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