30dd0ddf89f5d65ad33b12f063d6f9b433987f91
[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(osi_socket asocket, struct sockaddr_in *addr,
213             struct iovec *dvec, int nvec, afs_int32 asize, int istack)
214 {
215     register struct mbuf *tm, *um;
216     register afs_int32 code;
217     int s;
218     struct mbuf *top = 0;
219     register struct mbuf *m, **mp;
220     int len;
221     char *tdata;
222     caddr_t tpa;
223     int i,tl,rlen;
224     int mlen;
225     int haveGlock;
226
227     AFS_STATCNT(osi_NetSend);
228
229 /* Actually, the Ultrix way is as good as any for us, so we don't bother with
230  * special mbufs any more.  Used to think we could get away with not copying
231  * the data to the interface, but there's no way to tell the caller not to
232  * reuse the buffers after sending, so we lost out on that trick anyway */
233
234     s = splnet();
235     mp = &top;
236     i = 0;
237     tdata = dvec[i].iov_base;
238     tl = dvec[i].iov_len;
239     while (1) {
240         mlen = MLEN;
241         if (top == 0) {
242             MGETHDR(m, M_DONTWAIT, MT_DATA);
243             if (!m) {
244                 splx(s);
245                 return 1;
246             }
247             mlen = MHLEN;
248             m->m_pkthdr.len = 0;
249             m->m_pkthdr.rcvif = NULL;
250         } else
251         MGET(m, M_DONTWAIT, MT_DATA);
252         if (!m) {
253             /* can't get an mbuf, give up */
254             if (top) m_freem(top);      /* free mbuf list we're building */
255             splx(s);
256             return 1;
257         }
258         /*
259          * WARNING: the `4 * MLEN' is somewhat dubious.  It is better than
260          * `NBPG', which may have no relation to `CLBYTES'.  Also, `CLBYTES'
261          * may be so large that we never use clusters, resulting in far
262          * too many mbufs being used.  It is often better to briefly use
263          * a cluster, even if we are only using a portion of it.  Since
264          * we are on the xmit side, it shouldn't end up sitting on a queue
265          * for a potentially unbounded time (except perhaps if we are talking
266          * to ourself).
267          */
268         if (asize >= 4 * MLEN) {        /* try to get cluster mbuf */
269             register struct mbuf *p;
270
271             /* different algorithms for getting cluster mbuf */
272             MCLGET(m, M_DONTWAIT);
273             if ((m->m_flags & M_EXT) == 0)
274                 goto nopages;
275             mlen = MCLBYTES;
276
277             /* now compute usable size */
278             len = MIN(mlen, asize);
279 /* Should I look at MAPPED_MBUFS??? */
280         } else {
281 nopages:
282             len = MIN(mlen, asize);
283         }
284         m->m_len = 0;
285         *mp = m;        /* XXXX */
286         top->m_pkthdr.len += len;
287         tpa = mtod(m, caddr_t);
288         while (len) {
289           rlen = MIN(len, tl);
290           memcpy(tpa, tdata, rlen);
291           asize -= rlen;
292           len -= rlen;
293           tpa += rlen;
294           m->m_len += rlen;
295           tdata += rlen;
296           tl -= rlen;
297           if (tl <= 0) {
298             i++;
299             if (i > nvec) {
300               /* shouldn't come here! */
301               asize = 0;   /* so we make progress toward completion */
302               break;
303             }
304             tdata = dvec[i].iov_base;
305             tl = dvec[i].iov_len;
306           }
307         }
308         *mp = m;
309         mp = &m->m_next;
310         if (asize <= 0)
311           break;
312     }
313     tm = top;
314
315     tm->m_act = NULL;
316
317     /* setup mbuf corresponding to destination address */
318     um = m_get(M_DONTWAIT, MT_SONAME);
319     if (!um) {
320         if (top) m_freem(top);  /* free mbuf chain */
321         /* if this were vfs40, we'd do sbunlock(asocket, &asocket->so_snd), but
322            we don't do the locking at all for vfs40 systems */
323         splx(s);
324         return 1;
325     }
326     memcpy(mtod(um, caddr_t), addr, sizeof(*addr));
327     um->m_len = sizeof(*addr);
328     /* note that udp_usrreq frees funny mbuf.  We hold onto data, but mbuf
329      * around it is gone.  we free address ourselves.  */
330     haveGlock = ISAFS_GLOCK();
331     if (haveGlock) {
332         AFS_GUNLOCK();
333     }
334     SOCKET_LOCK(asocket);
335     code = (*asocket->so_proto->pr_usrreq)(asocket, PRU_SEND, tm, um, 0);
336     SOCKET_UNLOCK(asocket);
337     if (haveGlock) {
338         AFS_GLOCK();
339     }
340     splx(s);
341     m_free(um);
342
343     return code;
344 }
345
346 #endif /* AFS_DUX40_ENV */