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