dux-rxk-init-is-void-20040808
[openafs.git] / src / rx / DUX / 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_DUX40_ENV
17 #include "rx/rx_kcommon.h"
18
19
20 static struct protosw parent_proto;     /* udp proto switch */
21 static void rxk_input(struct mbuf *am, int iphlen);
22 static void rxk_fasttimo(void);
23
24 /* start intercepting basic calls */
25 void
26 rxk_init()
27 {
28     register struct protosw *tpro, *last;
29     if (rxk_initDone)
30         return;
31
32     last = inetdomain.dom_protoswNPROTOSW;
33     for (tpro = inetdomain.dom_protosw; tpro < last; tpro++)
34         if (tpro->pr_protocol == IPPROTO_UDP) {
35             /* force UDP checksumming on for AFS    */
36             extern int udpcksum;
37             udpcksum = 1;
38             memcpy(&parent_proto, tpro, sizeof(parent_proto));
39             tpro->pr_input = rxk_input;
40             tpro->pr_fasttimo = rxk_fasttimo;
41             /*
42              * don't bother with pr_drain and pr_ctlinput
43              * until we have something to do
44              */
45             rxk_initDone = 1;
46             return;
47         }
48     osi_Panic("inet:no udp");
49 }
50
51
52 static void
53 rxk_input(struct mbuf *am, int iphlen)
54 {
55     void (*tproc) ();
56     register unsigned short *tsp;
57     int hdr;
58     struct udphdr *tu;
59     register struct ip *ti;
60     struct udpiphdr *tvu;
61     register int i;
62     char *phandle;
63     afs_int32 code;
64     struct sockaddr_in taddr;
65     int tlen;
66     short port;
67     int data_len, comp_sum;
68
69     SPLVAR;
70     NETPRI;
71
72     /* make sure we have base ip and udp headers in first mbuf */
73     if (iphlen > sizeof(struct ip)) {
74         ip_stripoptions(am, NULL, NULL);
75         iphlen = sizeof(struct ip);
76     }
77
78     if (am->m_len < sizeof(struct udpiphdr)) {
79         am = m_pullup(am, sizeof(struct udpiphdr));
80         if (!am) {
81             USERPRI;
82             return;
83         }
84     }
85
86     ti = mtod(am, struct ip *);
87     /* skip basic ip hdr */
88     tu = (struct udphdr *)(((char *)ti) + sizeof(struct ip));
89
90     /* now read the port out */
91     port = tu->uh_dport;
92
93     if (port) {
94         for (tsp = rxk_ports, i = 0; i < MAXRXPORTS; i++) {
95             if (*tsp++ == port) {
96                 /* checksum the packet */
97                 /*
98                  * Make mbuf data length reflect UDP length.
99                  * If not enough data to reflect UDP length, drop.
100                  */
101                 tvu = (struct udpiphdr *)ti;
102                 tlen = ntohs((u_short) tvu->ui_ulen);
103                 if ((int)ti->ip_len != tlen) {
104                     if (tlen > (int)ti->ip_len) {
105                         m_free(am);
106                         USERPRI;
107                         return;
108                     }
109                     m_adj(am, tlen - (int)ti->ip_len);
110                 }
111                 /* deliver packet to rx */
112                 taddr.sin_family = AF_INET;     /* compute source address */
113                 taddr.sin_port = tu->uh_sport;
114                 taddr.sin_addr.s_addr = ti->ip_src.s_addr;
115                 taddr.sin_len = sizeof(taddr);
116                 tvu = (struct udpiphdr *)ti;    /* virtual udp structure, for cksum */
117                 /* handle the checksum.  Note that this code damages the actual ip
118                  * header (replacing it with the virtual one, which is the same size),
119                  * so we must ensure we get everything out we need, first */
120                 if (tu->uh_sum != 0) {
121                     /* if the checksum is there, always check it. It's crazy not
122                      * to, unless you can really be sure that your
123                      * underlying network (and interfaces and drivers and
124                      * DMA hardware, etc!) is error-free. First, fill
125                      * in entire virtual ip header. */
126                     tvu->ui_i.fill[0] = 0;
127                     tvu->ui_i.fill[1] = 0;
128                     tvu->ui_x1 = 0;
129                     tvu->ui_len = tvu->ui_ulen;
130                     tlen = ntohs((unsigned short)(tvu->ui_ulen));
131                     if (in_cksum(am, sizeof(struct ip) + tlen)) {
132                         /* checksum, including cksum field, doesn't come out 0, so
133                          * this packet is bad */
134                         m_freem(am);
135                         USERPRI;
136                         return;
137                     }
138                 }
139
140                 /*
141                  * 28 is IP (20) + UDP (8) header.  ulen includes
142                  * udp header, and we *don't* tell RX about udp
143                  * header either.  So, we remove those 8 as well.
144                  */
145                 data_len = ntohs(tu->uh_ulen);
146                 data_len -= 8;
147                 AFS_RXGLOCK();
148                 if (!(*rxk_GetPacketProc) (&phandle, data_len)) {
149                     if (rx_mb_to_packet(am, m_freem, 28, data_len, phandle)) {
150                         /* XXX should just increment counter here.. */
151                         printf("rx: truncated UDP packet\n");
152                         rxi_FreePacket(phandle);
153                     } else
154                         (*rxk_PacketArrivalProc) (phandle, &taddr,
155                                                   rxk_portRocks[i], data_len);
156                 } else
157                     m_freem(am);
158                 AFS_RXGUNLOCK();
159                 USERPRI;
160                 return;
161             }
162         }
163     }
164
165     /* if we get here, try to deliver packet to udp */
166     if (tproc = parent_proto.pr_input)
167         (*tproc) (am, iphlen);
168     USERPRI;
169     return;
170 }
171
172
173 /* 
174  * UDP fast timer to raise events for all but Solaris and NCR. 
175  * Called about 5 times per second (at unknown priority?).  Must go to
176  * splnet or obtain global lock before touching anything significant.
177  */
178 static void
179 rxk_fasttimo(void)
180 {
181     void (*tproc) ();
182     struct clock temp;
183
184     /* do rx fasttimo processing here */
185     rxevent_RaiseEvents(&temp);
186     if (tproc = parent_proto.pr_fasttimo)
187         (*tproc) ();
188 }
189
190
191 /* rx_NetSend - send asize bytes at adata from asocket to host at addr.
192  *
193  * Now, why do we allocate a new buffer when we could theoretically use the one
194  * pointed to by adata?  Because PRU_SEND returns after queueing the message,
195  * not after sending it.  If the sender changes the data after queueing it,
196  * we'd see the already-queued data change.  One attempt to fix this without
197  * adding a copy would be to have this function wait until the datagram is
198  * sent; however this doesn't work well.  In particular, if a host is down, and
199  * an ARP fails to that host, this packet will be queued until the ARP request
200  * comes back, which could be hours later.  We can't block in this routine that
201  * long, since it prevents RPC timeouts from happening.
202  */
203 /* XXX In the brave new world, steal the data bufs out of the rx_packet iovec,
204  * and just queue those.  XXX
205  */
206
207 /* set lock on sockbuf sb; can't call sblock since we're at interrupt level
208  * sometimes */
209 static
210 trysblock(sb)
211      register struct sockbuf *sb;
212 {
213     AFS_STATCNT(trysblock);
214     if (sb->sb_flags & SB_LOCK) {
215         return -1;              /* can't lock socket */
216     }
217     sb->sb_flags |= SB_LOCK;
218     return 0;
219 }
220
221 int
222 osi_NetSend(osi_socket asocket, struct sockaddr_in *addr, struct iovec *dvec,
223             int nvec, afs_int32 asize, int istack)
224 {
225     register struct mbuf *tm, *um;
226     register afs_int32 code;
227     int s;
228     struct mbuf *top = 0;
229     register struct mbuf *m, **mp;
230     int len;
231     char *tdata;
232     caddr_t tpa;
233     int i, tl, rlen;
234     int mlen;
235     int haveGlock;
236
237     AFS_STATCNT(osi_NetSend);
238
239 /* Actually, the Ultrix way is as good as any for us, so we don't bother with
240  * special mbufs any more.  Used to think we could get away with not copying
241  * the data to the interface, but there's no way to tell the caller not to
242  * reuse the buffers after sending, so we lost out on that trick anyway */
243
244     s = splnet();
245     mp = &top;
246     i = 0;
247     tdata = dvec[i].iov_base;
248     tl = dvec[i].iov_len;
249     while (1) {
250         mlen = MLEN;
251         if (top == 0) {
252             MGETHDR(m, M_DONTWAIT, MT_DATA);
253             if (!m) {
254                 splx(s);
255                 return 1;
256             }
257             mlen = MHLEN;
258             m->m_pkthdr.len = 0;
259             m->m_pkthdr.rcvif = NULL;
260         } else
261             MGET(m, M_DONTWAIT, MT_DATA);
262         if (!m) {
263             /* can't get an mbuf, give up */
264             if (top)
265                 m_freem(top);   /* free mbuf list we're building */
266             splx(s);
267             return 1;
268         }
269         /*
270          * WARNING: the `4 * MLEN' is somewhat dubious.  It is better than
271          * `NBPG', which may have no relation to `CLBYTES'.  Also, `CLBYTES'
272          * may be so large that we never use clusters, resulting in far
273          * too many mbufs being used.  It is often better to briefly use
274          * a cluster, even if we are only using a portion of it.  Since
275          * we are on the xmit side, it shouldn't end up sitting on a queue
276          * for a potentially unbounded time (except perhaps if we are talking
277          * to ourself).
278          */
279         if (asize >= 4 * MLEN) {        /* try to get cluster mbuf */
280             register struct mbuf *p;
281
282             /* different algorithms for getting cluster mbuf */
283             MCLGET(m, M_DONTWAIT);
284             if ((m->m_flags & M_EXT) == 0)
285                 goto nopages;
286             mlen = MCLBYTES;
287
288             /* now compute usable size */
289             len = MIN(mlen, asize);
290 /* Should I look at MAPPED_MBUFS??? */
291         } else {
292           nopages:
293             len = MIN(mlen, asize);
294         }
295         m->m_len = 0;
296         *mp = m;                /* XXXX */
297         top->m_pkthdr.len += len;
298         tpa = mtod(m, caddr_t);
299         while (len) {
300             rlen = MIN(len, tl);
301             memcpy(tpa, tdata, rlen);
302             asize -= rlen;
303             len -= rlen;
304             tpa += rlen;
305             m->m_len += rlen;
306             tdata += rlen;
307             tl -= rlen;
308             if (tl <= 0) {
309                 i++;
310                 if (i > nvec) {
311                     /* shouldn't come here! */
312                     asize = 0;  /* so we make progress toward completion */
313                     break;
314                 }
315                 tdata = dvec[i].iov_base;
316                 tl = dvec[i].iov_len;
317             }
318         }
319         *mp = m;
320         mp = &m->m_next;
321         if (asize <= 0)
322             break;
323     }
324     tm = top;
325
326     tm->m_act = NULL;
327
328     /* setup mbuf corresponding to destination address */
329     um = m_get(M_DONTWAIT, MT_SONAME);
330     if (!um) {
331         if (top)
332             m_freem(top);       /* free mbuf chain */
333         /* if this were vfs40, we'd do sbunlock(asocket, &asocket->so_snd), but
334          * we don't do the locking at all for vfs40 systems */
335         splx(s);
336         return 1;
337     }
338     memcpy(mtod(um, caddr_t), addr, sizeof(*addr));
339     um->m_len = sizeof(*addr);
340     /* note that udp_usrreq frees funny mbuf.  We hold onto data, but mbuf
341      * around it is gone.  we free address ourselves.  */
342     haveGlock = ISAFS_GLOCK();
343     if (haveGlock) {
344         AFS_GUNLOCK();
345     }
346     SOCKET_LOCK(asocket);
347     code = (*asocket->so_proto->pr_usrreq) (asocket, PRU_SEND, tm, um, 0);
348     SOCKET_UNLOCK(asocket);
349     if (haveGlock) {
350         AFS_GLOCK();
351     }
352     splx(s);
353     m_free(um);
354
355     return code;
356 }
357
358 #endif /* AFS_DUX40_ENV */