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