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