pull-prototypes-to-head-20020821
[openafs.git] / src / rx / AIX / 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_AIX41_ENV
16 #include "../rx/rx_kcommon.h"
17
18 static struct protosw parent_proto;     /* udp proto switch */
19
20 static void rxk_input(am, hlen)
21 register struct mbuf *am; {
22     register unsigned short *tsp;
23     int hdr;
24     struct udphdr *tu;
25     register struct ip *ti;
26     struct udpiphdr *tvu;
27     register int i;
28     char *phandle;
29     long code;
30     struct sockaddr_in taddr;
31     int tlen;
32     short port;
33     int data_len, comp_sum;
34     /* make sure we have base ip and udp headers in first mbuf */
35     if (M_HASCL(am) || am->m_len < 28) {
36         am = m_pullup(am, 28);
37         if (!am) return;
38     }
39     hdr = (mtod(am, struct ip *))->ip_hl;
40     if (hdr > 5) {
41         /* pull up more, the IP hdr is bigger than usual */
42         if (am->m_len < (8 + (hdr<<2))) {
43             am = m_pullup(am, 8+(hdr<<2));
44             if (!am) return;
45         }
46         ti = mtod(am, struct ip *); /* recompute, since m_pullup allocates new mbuf */
47         tu = (struct udphdr *)(((char *)ti) + (hdr<<2)); /* skip ip hdr */
48     } else {
49         ti = mtod(am, struct ip *);
50         tu = (struct udphdr *)(((char *)ti) + 20);      /* skip basic ip hdr */
51     }
52     
53     /* now read the port out */
54     port = tu->uh_dport;
55     if (port) {
56         for(tsp=rxk_ports, i=0; i<MAXRXPORTS;i++) {
57             if (*tsp++ == port) {
58                 rxk_kpork(am);
59                 return;
60             }
61         }
62     }
63     /* if we get here, try to deliver packet to udp */
64     if (parent_proto.pr_input)
65         udp_input(am, hlen);
66 }
67
68 /*
69  * the AIX version is complicated by the fact that the internet protocols
70  * are in a separate kernel extension, and they are unwilling to export their
71  * symbols to us.  We can get there indirectly, however.
72  */
73 #include <net/netisr.h>
74 static struct ifqueue rxk_q;                    /* RXKluge queue        */
75 static struct arpcom rxk_bogosity;
76
77 /* rxk_kpork -  send pkt over to netwerk kporc for processing */
78 rxk_kpork(m)
79 register struct mbuf *m; 
80 {
81     find_input_type(0xdead, m, &rxk_bogosity, 0);
82 }
83
84 /*
85  * AIX 4.3.3 changed the type of the second argument to
86  * ip_stripoptions().  The ip_stripoptions() prototype is in
87  * <netinet/proto_inet.h>.  This header file also acquired a guard
88  * macro, _PROTO_INET_H_, at the same time.  So we test for the guard
89  * macro to see which type we need to use for the second argument to
90  * ip_stripoptions().
91  *
92  * This way we don't have to introduce a port just to compile AFS on AIX
93  * 4.3.3.
94  */
95
96 #if defined(_PROTO_INET_H_)     /* AIX 4.3.3 and presumably later */
97 #define STRIP_ARG2_TYPE unsigned long
98 #else                           /* AIX 4.3.2 and earlier */
99 #define STRIP_ARG2_TYPE struct mbuf *
100 #endif
101
102 void ip_stripoptions(struct mbuf *m, STRIP_ARG2_TYPE mopt)
103 {
104         struct ip *ip = mtod(m, struct ip *);
105         register int i;
106         register caddr_t opts;
107         int olen;
108
109         olen = (ip->ip_hl<<2) - sizeof (struct ip);
110         opts = (caddr_t)(ip + 1);
111         i = m->m_len - (sizeof (struct ip) + olen);
112         memcpy(opts, opts  + olen, (unsigned)i);
113         m->m_len -= olen;
114         if (m->m_flags & M_PKTHDR)
115                 m->m_pkthdr.len -= olen;
116         ip->ip_hl = sizeof(struct ip) >> 2;
117 }
118
119 /* rxk_RX_input -       RX pkt input process */
120 rxk_RX_input(am)
121 register struct mbuf *am; {
122     register unsigned short *tsp;
123     int hdr;
124     struct udphdr *tu;
125     register struct ip *ti;
126     struct udpiphdr *tvu;
127     register int i;
128     char *phandle;
129     long code;
130     struct sockaddr_in taddr;
131     int tlen;
132     short port;
133     int data_len, comp_sum;
134
135     hdr = (ti = mtod(am, struct ip *))->ip_hl;
136     if (hdr > 5) {
137         ip_stripoptions(am, 0); /* get rid of anything we don't need */
138     }
139     tu = (struct udphdr *)(((char *)ti) + 20);
140     /*
141      * Make mbuf data length reflect UDP length.
142      * If not enough data to reflect UDP length, drop.
143      */
144     tvu = (struct udpiphdr *)ti;
145     tlen = ntohs((u_short)tvu->ui_ulen);
146     if ((int)ti->ip_len != tlen) {
147         if (tlen > (int)ti->ip_len) {
148             m_free(am);
149             return;
150         }
151         m_adj(am, tlen - (int)ti->ip_len);
152     }
153     /* deliver packet to rx */
154     taddr.sin_family = AF_INET;     /* compute source address */
155     taddr.sin_port = tu->uh_sport;
156     taddr.sin_addr.s_addr = ti->ip_src.s_addr;
157     /* handle the checksum.  Note that this code damages the actual ip
158        header (replacing it with the virtual one, which is the same size),
159        so we must ensure we get everything out we need, first */
160     if ( tu->uh_sum != 0) {
161         /* if the checksum is there, always check it. It's crazy not
162          * to, unless you can really be sure that your
163          * underlying network (and interfaces and drivers and
164          * DMA hardware, etc!) is error-free. First, fill
165          * in entire virtual ip header. */
166         tvu->ui_next = 0;
167         tvu->ui_prev = 0;
168         tvu->ui_x1 = 0;
169         tvu->ui_len = tvu->ui_ulen;
170         am->m_flags |= M_PKTHDR;
171         am->m_pkthdr.len = tlen;
172         if (in_cksum(am, sizeof(struct ip) + tlen)) {
173             /* checksum, including cksum field, doesn't come out 0, so
174                this packet is bad */
175             m_freem(am);
176             return;
177         }
178     }
179
180     /*
181      * 28 is IP (20) + UDP (8) header.  ulen includes
182      * udp header, and we *don't* tell RX about udp
183      * header either.  So, we remove those 8 as well.
184      */
185     data_len = ntohs(tu->uh_ulen);
186     data_len -= 8;
187     if (!(*rxk_GetPacketProc)(&phandle, data_len)) {
188         if (rx_mb_to_packet(am, m_freem, 28, data_len, phandle)) {
189             /* XXX should just increment counter here.. */
190             printf("rx: truncated UDP packet\n");
191             rxi_FreePacket(phandle);
192         } else 
193             (*rxk_PacketArrivalProc)(phandle, &taddr, rx_socket, data_len);
194     } else
195         m_freem(am);
196 }
197
198 /* rxk_isr - RX Kluge Input Service Routine */
199 static rxk_isr() {
200     register struct mbuf *m;
201     IFQ_LOCK_DECL();    /* silly macro has trailing ';'.  Sigh. */
202     while (1) {
203         IF_DEQUEUE(&rxk_q, m);
204         if (!m) return;
205         rxk_RX_input(m);
206     }
207 }
208
209 /* 
210  * UDP fast timer to raise events for all but Solaris and NCR. 
211  * Called about 5 times per second (at unknown priority?).  Must go to
212  * splnet or obtain global lock before touching anything significant.
213  */
214 static void rxk_fasttimo (void)
215 {
216     int (*tproc)();
217     struct clock temp;
218
219     /* do rx fasttimo processing here */
220     rxevent_RaiseEvents(&temp);
221     if (tproc = parent_proto.pr_fasttimo) (*tproc)();
222 }
223
224
225 void rxk_init(void)
226 {
227     register struct protosw *pr;
228     extern struct protosw *pffindproto();
229
230     if (!rxk_initDone &&
231         (pr = pffindproto(AF_INET, IPPROTO_UDP, SOCK_DGRAM))) {
232         parent_proto = *pr;
233
234         pr->pr_input    = rxk_input;
235         pr->pr_fasttimo = rxk_fasttimo;
236
237
238         /*
239          * don't bother with pr_drain and pr_ctlinput
240          * until we have something to do
241          */
242         rxk_q.ifq_maxlen = 128;         /* obligatory XXX       */
243         /* add pseudo pkt types as haque to get back onto net kproc */
244         if (!add_input_type(0xdead, NET_KPROC, rxk_isr, &rxk_q, NETISR_MAX-1))
245                 rxk_initDone = 1;
246     }
247
248     if (!rxk_initDone) {
249         printf("\nAFS: no INTERNET protocol support found\n");
250     }
251 }
252
253
254
255 void shutdown_rxkernel(void)
256 {
257     register struct protosw *pr;
258     register int i;
259     extern struct protosw *pffindproto();
260
261     if (rxk_initDone && (pr = pffindproto(AF_INET, IPPROTO_UDP, SOCK_DGRAM))) {
262         *pr = parent_proto;
263
264         rxk_initDone = 0;
265         for (i=0; i<MAXRXPORTS;i++) {
266             if (rxk_ports[i]) {
267                 rxk_ports[i] = 0;
268                 soclose((struct socket *)rxk_portRocks[i]);
269                 rxk_portRocks[i] = NULL;
270             }
271         }
272     }
273 }
274
275
276 /* osi_NetSend - send asize bytes at adata from asocket to host at addr.
277  *
278  * Now, why do we allocate a new buffer when we could theoretically use the one
279  * pointed to by adata?  Because PRU_SEND returns after queueing the message,
280  * not after sending it.  If the sender changes the data after queueing it,
281  * we'd see the already-queued data change.  One attempt to fix this without
282  * adding a copy would be to have this function wait until the datagram is
283  * sent; however this doesn't work well.  In particular, if a host is down, and
284  * an ARP fails to that host, this packet will be queued until the ARP request
285  * comes back, which could be hours later.  We can't block in this routine that
286  * long, since it prevents RPC timeouts from happening.
287  */
288 /* XXX In the brave new world, steal the data bufs out of the rx_packet iovec,
289  * and just queue those.  XXX
290  */
291
292 osi_NetSend(asocket, addr, dvec, nvec, asize, istack)
293 register struct socket *asocket;
294 struct iovec *dvec;
295 int nvec;
296 register afs_int32 asize;
297 struct sockaddr_in *addr;
298 int istack;
299 {
300     register struct mbuf *tm, *um;
301     register afs_int32 code;
302     struct mbuf *top = 0;
303     register struct mbuf *m, **mp;
304     int len, mlen;
305     char *tdata;
306     caddr_t tpa;
307     int i,tl,rlen;
308
309     AFS_STATCNT(osi_NetSend);
310 #ifndef AFS_AIX41_ENV
311     /*
312      * VRMIX has a version of sun's mclgetx() that works correctly with
313      * respect to mcopy(), so we can just dummy up the entire packet as
314      * an mbuf cluster, and pass it to the IP output routine (which will
315      * most likely have to frag it, but since mclgetx() has been fixed,
316      * will work ok).  The only problem is that we have to wait until
317      * m_free() has been called on the cluster, to guarantee that we
318      * do not muck with it until it has gone out.  We also must refrain
319      * from inadvertantly touching a piece of data that falls within the
320      * same cache line as any portion of the packet, if we have been lucky
321      * enough to be DMA-ing directly out from it.
322      * Certain IBM architects assure me that the rios is fast enough
323      * that the cost of the extra copy, as opposed to trying to
324      * DMA directly from the packet is barely worth my while,
325      * but I have a hard time accepting this.
326      *
327      * We can only use this code once we are passed in an indication of
328      * whether we are being called `process-synchronously' or not.
329      *
330      * of course, the packet must be pinned, which is currently true,
331      * but in future may not be.
332      */
333 #endif
334     mp = &top;
335     i = 0;
336     tdata = dvec[0].iov_base;
337     tl = dvec[0].iov_len;
338
339     while (1) {
340         if (!top) {
341             MGETHDR(m, M_DONTWAIT, MT_DATA);
342             mlen = MHLEN;
343         } else {
344             MGET(m, M_DONTWAIT, MT_DATA);
345             mlen = MLEN;
346         }
347         if (!m) {
348            /* can't get an mbuf, give up */
349            if (top)
350               m_freem(top);     /* free mbuf list we're building */
351            return 1;
352         }
353         if (!top) {
354            m->m_flags |= M_PKTHDR; /* XXX - temp */
355            m->m_pkthdr.len = 0;
356            m->m_pkthdr.rcvif = NULL;
357         }
358
359             /*
360              * WARNING: the `4 * MLEN' is somewhat dubious.  It is better than
361              * `NBPG', which may have no relation to `CLBYTES'.  Also,
362              * `CLBYTES' may be so large that we never use clusters,
363              * resulting in far too many mbufs being used.  It is often
364              * better to briefly use a cluster, even if we are only using a
365              * portion of it.  Since we are on the xmit side, it shouldn't
366              * end up sitting on a queue for a potentially unbounded time
367              * (except perhaps if we are talking to ourself).
368              */
369             if (asize >= (MHLEN + 3*MLEN)) {
370                 MCLGET(m,M_DONTWAIT);
371             }
372             /* now compute usable size */
373             if (M_HASCL(m)) {
374                 len = MIN(m->m_ext.ext_size, asize);
375             } else {
376                 len = MIN(mlen, asize);
377             }
378
379         tpa = mtod(m, caddr_t);
380         *mp = m;
381         mp = &m->m_next;
382         m->m_len = 0;
383         while (len) {
384           rlen = MIN(len, tl);
385           memcpy(tpa, tdata, rlen);
386           asize -= rlen;
387           len -= rlen;
388           tpa += rlen;
389           m->m_len += rlen;
390           top->m_pkthdr.len += rlen;
391           tdata += rlen;
392           tl -= rlen;
393           if (tl <= 0) {
394             i++;
395             if (i > nvec) {
396               /* shouldn't come here! */
397               asize = 0;   /* so we make progress toward completion */
398               break;
399             }
400             tdata = dvec[i].iov_base;
401             tl = dvec[i].iov_len;
402           }
403         }
404
405         if (asize <= 0)
406           break;
407         }
408         tm = top;
409
410         tm->m_act = NULL;
411
412         /* setup mbuf corresponding to destination address */
413         MGETHDR(um, M_DONTWAIT, MT_SONAME);
414         if (!um) {
415             if (top)
416                 m_freem(top);   /* free mbuf chain */
417             return 1;
418         }
419         memcpy(mtod(um, caddr_t), addr, sizeof(*addr));
420         um->m_len = sizeof(*addr);
421         um->m_pkthdr.len = sizeof(*addr);
422         um->m_flags |= M_PKTHDR;
423
424     SOCKET_LOCK(asocket);
425     code = (*asocket->so_proto->pr_usrreq)(asocket, PRU_SEND, tm, um, 0);
426     SOCKET_UNLOCK(asocket);
427     m_free(um);
428
429     return code;
430 }
431
432
433
434 #endif /* AFS_AIX41_ENV */