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