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