freebsd-almost-working-client-20020216
[openafs.git] / src / rx / FBSD / rx_knet.c
1 /*
2 ****************************************************************************
3 *        Copyright IBM Corporation 1988, 1989 - All Rights Reserved        *
4 *        Copyright Transarc Corporation 1989 - All Rights Reserved         *
5 *                                                                          *
6 * Permission to use, copy, modify, and distribute this software and its    *
7 * documentation for any purpose and without fee is hereby granted,         *
8 * provided that the above copyright notice appear in all copies and        *
9 * that both that copyright notice and this permission notice appear in     *
10 * supporting documentation, and that the name of IBM not be used in        *
11 * advertising or publicity pertaining to distribution of the software      *
12 * without specific, written prior permission.                              *
13 *                                                                          *
14 * IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL *
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL IBM *
16 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY      *
17 * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER  *
18 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING   *
19 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.    *
20 ****************************************************************************
21 */
22
23 #include <afsconfig.h>
24 #include "../afs/param.h"
25
26 RCSID("$Header$");
27
28 #ifdef AFS_FBSD40_ENV
29 #include "../rx/rx_kcommon.h"
30
31
32 #ifdef RXK_LISTENER_ENV
33 int osi_NetReceive(asocket, addr, dvec, nvecs, alength)
34     struct socket *asocket;
35     struct sockaddr_in *addr;
36     struct iovec *dvec;
37     int nvecs;
38     int *alength;
39 {
40     struct uio u;
41     int i;
42     struct iovec iov[RX_MAXIOVECS];
43     struct sockaddr *sa;
44     int code;
45
46     int haveGlock = ISAFS_GLOCK();
47     /*AFS_STATCNT(osi_NetReceive);*/
48
49     if (nvecs > RX_MAXIOVECS) {
50         osi_Panic("osi_NetReceive: %d: Too many iovecs.\n", nvecs);
51     }
52
53     for (i = 0 ; i < nvecs ; i++) {
54         iov[i].iov_base = dvec[i].iov_base;
55         iov[i].iov_len = dvec[i].iov_len;
56     }
57
58     u.uio_iov=&iov[0];
59     u.uio_iovcnt=nvecs;
60     u.uio_offset=0;
61     u.uio_resid=*alength;
62     u.uio_segflg=UIO_SYSSPACE; 
63     u.uio_rw=UIO_READ;
64     u.uio_procp=NULL;  
65
66     if (haveGlock) { 
67         AFS_GUNLOCK();
68     }
69     code = soreceive(asocket, &sa, &u, NULL, NULL, NULL);
70 #if KNET_DEBUG
71     if (code) {
72         if (code == EINVAL)
73           Debugger("afs NetReceive busted");
74         else
75           printf("y");
76     }
77 #endif
78     if (haveGlock) {
79         AFS_GLOCK();
80     }
81     *alength=*alength-u.uio_resid;
82     if (sa) {
83        if (sa->sa_family == AF_INET) {
84           if (addr) *addr=*(struct sockaddr_in *)sa;
85        } else {
86           printf("Unknown socket family %d in NetReceive\n", sa->sa_family);
87        }
88     }
89     return code;
90 }
91
92 extern int rxk_ListenerPid;
93 void osi_StopListener(void)
94 {
95    struct proc *p;
96
97    soclose(rx_socket);
98    p=pfind(rxk_ListenerPid); 
99    if (p)
100        psignal(p, SIGUSR1);
101 }
102
103 int 
104 osi_NetSend(asocket, addr, dvec, nvecs, alength, istack)
105      register struct socket *asocket;
106      struct iovec *dvec;
107      int nvecs;
108      register afs_int32 alength;
109      struct sockaddr_in *addr;
110      int istack;
111 {
112     register afs_int32 code;
113     int s;
114     int len;
115     int i;
116     struct iovec iov[RX_MAXIOVECS];
117     char *tdata;
118     struct uio u;
119     int haveGlock = ISAFS_GLOCK();
120
121     AFS_STATCNT(osi_NetSend);
122     if (nvecs > RX_MAXIOVECS) {
123         osi_Panic("osi_NetSend: %d: Too many iovecs.\n", nvecs);
124     } 
125
126     for (i = 0 ; i < nvecs ; i++) {
127         iov[i].iov_base = dvec[i].iov_base; 
128         iov[i].iov_len = dvec[i].iov_len; 
129     } 
130
131     u.uio_iov=&iov[0];
132     u.uio_iovcnt=nvecs;
133     u.uio_offset=0;
134     u.uio_resid=alength;
135     u.uio_segflg=UIO_SYSSPACE;
136     u.uio_rw=UIO_WRITE;
137     u.uio_procp=NULL;
138
139     addr->sin_len=sizeof(struct sockaddr_in);
140
141     if (haveGlock) {
142         AFS_GUNLOCK();
143     }
144 #if KNET_DEBUG
145     printf("+");
146 #endif
147     code = sosend(asocket, addr, &u, NULL, NULL, 0, curproc);
148 #if KNET_DEBUG
149     if (code) {
150         if (code == EINVAL)
151           Debugger("afs NetSend busted");
152         else
153           printf("z");
154     }
155 #endif
156     if (haveGlock) {
157         AFS_GLOCK();
158     }
159     return code;
160 }
161 #else
162 /* This code *almost* works :( */
163 static struct protosw parent_proto;     /* udp proto switch */
164 static void rxk_input (struct mbuf *am, int iphlen);
165 static void rxk_fasttimo (void);
166
167 /* start intercepting basic calls */
168 rxk_init() {
169     register struct protosw *tpro, *last;
170     if (rxk_initDone) return 0;
171
172     last = inetdomain.dom_protoswNPROTOSW;
173     for (tpro = inetdomain.dom_protosw; tpro < last; tpro++)
174       if (tpro->pr_protocol == IPPROTO_UDP) {
175 #if 0 /* not exported */
176         /* force UDP checksumming on for AFS    */
177          extern int udpcksum;
178          udpcksum = 1;  
179 #endif
180           memcpy(&parent_proto, tpro, sizeof(parent_proto));
181           tpro->pr_input = rxk_input;
182           tpro->pr_fasttimo = rxk_fasttimo;
183           /*
184            * don't bother with pr_drain and pr_ctlinput
185            * until we have something to do
186            */
187           rxk_initDone = 1;
188           return 0;
189       }
190     osi_Panic("inet:no udp");
191 }
192
193
194 static void rxk_input (struct mbuf *am, int iphlen)
195 {
196     void (*tproc)();
197     register unsigned short *tsp;
198     int hdr;
199     struct udphdr *tu;
200     register struct ip *ti;
201     struct udpiphdr *tvu;
202     register int i;
203     char *phandle;
204     afs_int32 code;
205     struct sockaddr_in taddr;
206     int tlen;
207     short port;
208     int data_len, comp_sum;
209
210     SPLVAR;
211     NETPRI;
212
213     /* make sure we have base ip and udp headers in first mbuf */
214     if (iphlen > sizeof (struct ip)) {
215         ip_stripoptions(am, (struct mbuf *)0);
216         iphlen = sizeof (struct ip);
217     }
218
219     if (am->m_len < sizeof(struct udpiphdr)) {
220         am = m_pullup(am, sizeof(struct udpiphdr));
221         if (!am) {
222             USERPRI;
223             return;
224         }
225     }
226
227     ti = mtod(am, struct ip *);
228     /* skip basic ip hdr */
229     tu = (struct udphdr *)(((char *)ti) + sizeof(struct ip)); 
230     
231     /* now read the port out */
232     port = tu->uh_dport;
233
234     if (port) {
235         for(tsp=rxk_ports, i=0; i<MAXRXPORTS;i++) {
236             if (*tsp++ == port) {
237                 /* checksum the packet */
238                 /*
239                  * Make mbuf data length reflect UDP length.
240                  * If not enough data to reflect UDP length, drop.
241                  */
242                 tvu = (struct udpiphdr *)ti;
243                 tlen = ntohs((u_short)tvu->ui_ulen);
244                 if ((int)ti->ip_len != tlen) {
245                     if (tlen > (int)ti->ip_len) {
246                         m_free(am);
247                         USERPRI;
248                         return;
249                     }
250                     m_adj(am, tlen - (int)ti->ip_len);
251                 }
252                 /* deliver packet to rx */
253                 taddr.sin_family = AF_INET;         /* compute source address */
254                 taddr.sin_port = tu->uh_sport;
255                 taddr.sin_addr.s_addr = ti->ip_src.s_addr;
256                 taddr.sin_len = sizeof(taddr);
257                 tvu = (struct udpiphdr *) ti;   /* virtual udp structure, for cksum */
258                 /* handle the checksum.  Note that this code damages the actual ip
259                    header (replacing it with the virtual one, which is the same size),
260                    so we must ensure we get everything out we need, first */
261                 if ( tu->uh_sum != 0) {
262                         /* if the checksum is there, always check it. It's crazy not
263                          * to, unless you can really be sure that your
264                          * underlying network (and interfaces and drivers and
265                          * DMA hardware, etc!) is error-free. First, fill
266                          * in entire virtual ip header. */
267                         memset(tvu->ui_i.ih_x1, 0, 9);
268                         tvu->ui_len = tvu->ui_ulen;
269                         tlen = ntohs((unsigned short)(tvu->ui_ulen));
270                         if (in_cksum(am, sizeof(struct ip) + tlen)) {
271                             /* checksum, including cksum field, doesn't come out 0, so
272                                this packet is bad */
273                             m_freem(am);
274                             USERPRI;
275                             return;
276                         }
277                       }
278
279                 /*
280                  * 28 is IP (20) + UDP (8) header.  ulen includes
281                  * udp header, and we *don't* tell RX about udp
282                  * header either.  So, we remove those 8 as well.
283                  */
284                 data_len = ntohs(tu->uh_ulen);
285                 data_len -= 8;
286                 AFS_RXGLOCK();
287                 if (!(*rxk_GetPacketProc)(&phandle, data_len)) {
288                   if (rx_mb_to_packet(am, m_freem, 28, data_len, phandle)) {
289                     /* XXX should just increment counter here.. */
290                     printf("rx: truncated UDP packet\n");
291                     rxi_FreePacket(phandle);
292                   }
293                   else 
294                     (*rxk_PacketArrivalProc)(phandle, &taddr,
295                                              rxk_portRocks[i], data_len);
296                 }else m_freem(am);
297                 AFS_RXGUNLOCK();
298                 USERPRI;
299                 return;
300                 }
301             }
302         }
303
304     /* if we get here, try to deliver packet to udp */
305     if (tproc = parent_proto.pr_input) (*tproc)(am,iphlen);
306     USERPRI;
307     return;
308 }
309
310
311 /* 
312  * UDP fast timer to raise events for all but Solaris and NCR. 
313  * Called about 5 times per second (at unknown priority?).  Must go to
314  * splnet or obtain global lock before touching anything significant.
315  */
316 static void rxk_fasttimo (void)
317 {
318     void (*tproc)();
319     struct clock temp;
320
321     /* do rx fasttimo processing here */
322     rxevent_RaiseEvents(&temp);
323     if (tproc = parent_proto.pr_fasttimo) (*tproc)();
324 }
325
326 /* rx_NetSend - send asize bytes at adata from asocket to host at addr.
327  *
328  * Now, why do we allocate a new buffer when we could theoretically use the one
329  * pointed to by adata?  Because PRU_SEND returns after queueing the message,
330  * not after sending it.  If the sender changes the data after queueing it,
331  * we'd see the already-queued data change.  One attempt to fix this without
332  * adding a copy would be to have this function wait until the datagram is
333  * sent; however this doesn't work well.  In particular, if a host is down, and
334  * an ARP fails to that host, this packet will be queued until the ARP request
335  * comes back, which could be hours later.  We can't block in this routine that
336  * long, since it prevents RPC timeouts from happening.
337  */
338 /* XXX In the brave new world, steal the data bufs out of the rx_packet iovec,
339  * and just queue those.  XXX
340  */
341
342 /* set lock on sockbuf sb; can't call sblock since we're at interrupt level
343  * sometimes */
344 static trysblock(sb)    
345 register struct sockbuf *sb; {
346     AFS_STATCNT(trysblock);
347     if (sb->sb_flags & SB_LOCK){
348         return -1;  /* can't lock socket */
349     }
350     sb->sb_flags |= SB_LOCK;
351     return 0;
352 }
353
354 /* We only have to do all the mbuf management ourselves if we can be called at
355    interrupt time. in RXK_LISTENER_ENV, we can just call sosend() */
356 int 
357 osi_NetSend(asocket, addr, dvec, nvec, asize, istack)
358      register struct socket *asocket;
359      struct iovec *dvec;
360      int nvec;
361      register afs_int32 asize;
362      struct sockaddr_in *addr;
363      int istack;
364 {
365     register struct mbuf *tm, *um;
366     register afs_int32 code;
367     int s;
368     struct mbuf *top = 0;
369     register struct mbuf *m, **mp;
370     int len;
371     char *tdata;
372     caddr_t tpa;
373     int i,tl,rlen;
374     int mlen;
375     int haveGlock;
376 #if KNET_DEBUG
377     static int before=0;
378 #endif
379
380     AFS_STATCNT(osi_NetSend);
381 /* Actually, the Ultrix way is as good as any for us, so we don't bother with
382  * special mbufs any more.  Used to think we could get away with not copying
383  * the data to the interface, but there's no way to tell the caller not to
384  * reuse the buffers after sending, so we lost out on that trick anyway */
385     s = splnet();
386     if (trysblock(&asocket->so_snd)) {
387         splx(s);
388         return 1;
389     }
390     mp = &top;
391     i = 0;
392     tdata = dvec[i].iov_base;
393     tl = dvec[i].iov_len;
394     while (1) {
395         mlen = MLEN;
396         if (top == 0) {
397             MGETHDR(m, M_DONTWAIT, MT_DATA);
398             if (!m) {
399                 sbunlock(&asocket->so_snd);
400                 splx(s);
401                 return 1;
402             }
403             mlen = MHLEN;
404             m->m_pkthdr.len = 0;
405             m->m_pkthdr.rcvif = (struct ifnet *)0;
406         } else
407         MGET(m, M_DONTWAIT, MT_DATA);
408         if (!m) {
409             /* can't get an mbuf, give up */
410             if (top) m_freem(top);      /* free mbuf list we're building */
411                 sbunlock(&asocket->so_snd);
412             splx(s);
413             return 1;
414         }
415         /*
416          * WARNING: the `4 * MLEN' is somewhat dubious.  It is better than
417          * `NBPG', which may have no relation to `CLBYTES'.  Also, `CLBYTES'
418          * may be so large that we never use clusters, resulting in far
419          * too many mbufs being used.  It is often better to briefly use
420          * a cluster, even if we are only using a portion of it.  Since
421          * we are on the xmit side, it shouldn't end up sitting on a queue
422          * for a potentially unbounded time (except perhaps if we are talking
423          * to ourself).
424          */
425         if (asize >= 4 * MLEN) {        /* try to get cluster mbuf */
426             /* different algorithms for getting cluster mbuf */
427             MCLGET(m, M_DONTWAIT);
428             if ((m->m_flags & M_EXT) == 0)
429                 goto nopages;
430             mlen = MCLBYTES;
431
432             /* now compute usable size */
433             len = MIN(mlen, asize);
434 /* Should I look at MAPPED_MBUFS??? */
435         } else {
436 nopages:
437             len = MIN(mlen, asize);
438         }
439         m->m_len = 0;
440         *mp = m;        /* XXXX */
441         top->m_pkthdr.len += len;
442         tpa = mtod(m, caddr_t);
443         while (len) {
444           rlen = MIN(len, tl);
445           memcpy(tpa, tdata, rlen);
446           asize -= rlen;
447           len -= rlen;
448           tpa += rlen;
449           m->m_len += rlen;
450           tdata += rlen;
451           tl -= rlen;
452           if (tl <= 0) {
453             i++;
454             if (i > nvec) {
455               /* shouldn't come here! */
456               asize = 0;   /* so we make progress toward completion */
457               break;
458             }
459             tdata = dvec[i].iov_base;
460             tl = dvec[i].iov_len;
461           }
462         }
463         *mp = m;
464         mp = &m->m_next;
465         if (asize <= 0)
466           break;
467     }
468     tm = top;
469
470     tm->m_act = (struct mbuf *) 0;
471
472     /* setup mbuf corresponding to destination address */
473     um = m_get(M_DONTWAIT, MT_SONAME);
474     if (!um) {
475         if (top) m_freem(top);  /* free mbuf chain */
476         sbunlock(&asocket->so_snd);
477         splx(s);
478         return 1;
479     }
480     memcpy(mtod(um, caddr_t), addr, sizeof(*addr));
481     addr->sin_len = um->m_len = sizeof(*addr);
482     /* note that udp_usrreq frees funny mbuf.  We hold onto data, but mbuf
483      * around it is gone. */
484     /*    haveGlock = ISAFS_GLOCK();
485     if (haveGlock) {
486         AFS_GUNLOCK();
487         }  */
488     /* SOCKET_LOCK(asocket); */
489     /* code = (*asocket->so_proto->pr_usrreq)(asocket, PRU_SEND, tm, um, 0); */
490 #if KNET_DEBUG
491     if (before) Debugger("afs NetSend before");
492 #endif
493     code = (*asocket->so_proto->pr_usrreqs->pru_send)(asocket, 0, tm, 
494                                                       (struct sockaddr *) addr,
495                                                       um, &proc0);
496     /* SOCKET_UNLOCK(asocket); */
497     /* if (haveGlock) {
498         AFS_GLOCK();
499         } */
500     sbunlock(&asocket->so_snd);
501     splx(s);
502 #if KNET_DEBUG
503     if (code) {
504         if (code == EINVAL)
505           Debugger("afs NetSend busted");
506         else
507           printf("z");
508     }
509 #endif
510     return code;
511 }
512 #endif
513
514 #endif /* AFS_FBSD40_ENV */