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