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