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