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