IRIX: Remove pre-65 code
[openafs.git] / src / rx / IRIX / 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
14 #include "rx/rx_kcommon.h"
15 #include "rx/rx_packet.h"
16 #include "h/tcp-param.h"
17 /* This must be loaded after proc.h to avoid macro collision with a variable*/
18 #include "netinet/udp_var.h"
19
20
21
22
23 #ifdef RXK_LISTENER_ENV
24 /* osi_NetReceive
25  * OS dependent part of kernel RX listener thread.
26  *
27  * Arguments:
28  *      so      socket to receive on, typically rx_socket
29  *      from    pointer to a sockaddr_in. 
30  *      iov     array of iovecs to fill in.
31  *      iovcnt  how many iovecs there are.
32  *      lengthp IN/OUT in: total space available in iovecs. out: size of read.
33  *
34  * Return
35  * 0 if successful
36  * error code (such as EINTR) if not
37  *
38  * Environment
39  *      Note that the maximum number of iovecs is 2 + RX_MAXWVECS. This is
40  *      so we have a little space to look for packets larger than 
41  *      rx_maxReceiveSize.
42  */
43 int rxk_lastSocketError = 0;
44 int rxk_nSocketErrors = 0;
45 int rxk_nSignalsCleared = 0;
46
47 int
48 osi_NetReceive(osi_socket so, struct sockaddr_in *addr, struct iovec *dvec,
49                int nvecs, int *alength)
50 {
51     struct uio tuio;
52     int code;
53     struct mbuf *maddr = NULL;
54     struct sockaddr_in *taddr;
55     struct iovec tmpvec[RX_MAXWVECS + 2];
56     bhv_desc_t bhv;
57     BHV_PDATA(&bhv) = (void *)so;
58
59     memset(&tuio, 0, sizeof(tuio));
60     memset(&tmpvec, 0, sizeof(tmpvec));
61
62     tuio.uio_iov = tmpvec;
63     tuio.uio_iovcnt = nvecs;
64     tuio.uio_offset = 0;
65     tuio.uio_segflg = AFS_UIOSYS;
66     tuio.uio_fmode = 0;
67     tuio.uio_resid = *alength;
68     tuio.uio_pio = 0;
69     tuio.uio_pbuf = 0;
70
71     if (nvecs > RX_MAXWVECS + 2) {
72         osi_Panic("Too many (%d) iovecs passed to osi_NetReceive\n", nvecs);
73     }
74     memcpy(tmpvec, (char *)dvec, (RX_MAXWVECS + 1) * sizeof(struct iovec));
75     code = soreceive(&bhv, &maddr, &tuio, NULL, NULL);
76
77     if (code) {
78         /* Clear the error before using the socket again. I've tried being nice
79          * and blocking SIGKILL and SIGSTOP from the kernel, but they get
80          * delivered anyway. So, time to be crude and just clear the signals
81          * pending on this thread.
82          */
83         if (code == EINTR) {
84             uthread_t *ut = curuthread;
85             int s;
86             s = ut_lock(ut);
87             sigemptyset(&ut->ut_sig);
88             ut->ut_cursig = 0;
89             thread_interrupt_clear(UT_TO_KT(ut), 1);
90             ut_unlock(ut, s);
91             rxk_nSignalsCleared++;
92         }
93         /* Clear the error before using the socket again. */
94         so->so_error = 0;
95         rxk_lastSocketError = code;
96         rxk_nSocketErrors++;
97         if (maddr)
98             m_freem(maddr);
99     } else {
100         *alength = *alength - tuio.uio_resid;
101         if (maddr) {
102             memcpy((char *)addr, (char *)mtod(maddr, struct sockaddr_in *),
103                    sizeof(struct sockaddr_in));
104             m_freem(maddr);
105         } else {
106             return -1;
107         }
108     }
109     return code;
110 }
111 #else /* RXK_LISTENER_ENV */
112
113 static struct protosw parent_proto;     /* udp proto switch */
114
115 /*
116  * RX input, fast timer and initialization routines. 
117  */
118
119 static void
120 rxk_input(struct mbuf *am, struct ifnet *aif, struct ipsec *spec)
121 {
122     void (*tproc) ();
123     unsigned short *tsp;
124     int hdr;
125     struct udphdr *tu;
126     struct ip *ti;
127     struct udpiphdr *tvu;
128     int i;
129     char *phandle;
130     struct sockaddr_in taddr;
131     int tlen;
132     short port;
133     int data_len;
134
135     /* make sure we have base ip and udp headers in first mbuf */
136     if (am->m_off > MMAXOFF || am->m_len < 28) {
137         am = m_pullup(am, 28);
138         if (!am)
139             return;
140     }
141
142     hdr = (mtod(am, struct ip *))->ip_hl;
143     if (hdr > 5) {
144         /* pull up more, the IP hdr is bigger than usual */
145         if (am->m_len < (8 + (hdr << 2))) {
146             am = m_pullup(am, 8 + (hdr << 2));
147             if (!am)
148                 return;
149         }
150         ti = mtod(am, struct ip *);     /* recompute, since m_pullup allocates new mbuf */
151         tu = (struct udphdr *)(((char *)ti) + (hdr << 2));      /* skip ip hdr */
152     } else {
153         ti = mtod(am, struct ip *);
154         tu = (struct udphdr *)(((char *)ti) + 20);      /* skip basic ip hdr */
155     }
156     /* now read the port out */
157     port = tu->uh_dport;
158
159     if (port) {
160         for (tsp = rxk_ports, i = 0; i < MAXRXPORTS; i++) {
161             if (*tsp++ == port) {
162                 /* checksum the packet */
163                 if (hdr > 5) {
164                     ip_stripoptions(am, (struct mbuf *)0);      /* get rid of anything we don't need */
165                     tu = (struct udphdr *)(((char *)ti) + 20);
166                 }
167                 /*
168                  * Make mbuf data length reflect UDP length.
169                  * If not enough data to reflect UDP length, drop.
170                  */
171                 tvu = (struct udpiphdr *)ti;
172                 tlen = ntohs((u_short) tvu->ui_ulen);
173                 if ((int)ti->ip_len != tlen) {
174                     if (tlen > (int)ti->ip_len) {
175                         m_free(am);
176                         return;
177                     }
178                     m_adj(am, tlen - (int)ti->ip_len);
179                 }
180                 /* deliver packet to rx */
181                 taddr.sin_family = AF_INET;     /* compute source address */
182                 taddr.sin_port = tu->uh_sport;
183                 taddr.sin_addr.s_addr = ti->ip_src.s_addr;
184                 /* handle the checksum.  Note that this code damages the actual ip
185                  * header (replacing it with the virtual one, which is the same size),
186                  * so we must ensure we get everything out we need, first */
187                 if (tu->uh_sum != 0) {
188                     /* if the checksum is there, always check it. It's crazy not
189                      * to, unless you can really be sure that your
190                      * underlying network (and interfaces and drivers and
191                      * DMA hardware, etc!) is error-free. First, fill
192                      * in entire virtual ip header. */
193                     tvu->ui_next = 0;
194                     tvu->ui_prev = 0;
195                     tvu->ui_x1 = 0;
196                     tvu->ui_len = tvu->ui_ulen;
197                     tlen = ntohs((unsigned short)(tvu->ui_ulen));
198                     if ((!(am->m_flags & M_CKSUMMED))
199                         && in_cksum(am, sizeof(struct ip) + tlen)) {
200                         /* checksum, including cksum field, doesn't come out 0, so
201                          * this packet is bad */
202                         m_freem(am);
203                         return;
204                     }
205                 }
206
207                 /*
208                  * 28 is IP (20) + UDP (8) header.  ulen includes
209                  * udp header, and we *don't* tell RX about udp
210                  * header either.  So, we remove those 8 as well.
211                  */
212                 data_len = ntohs(tu->uh_ulen);
213                 data_len -= 8;
214                 if (!(*rxk_GetPacketProc) (&phandle, data_len)) {
215                     if (rx_mb_to_packet(am, m_freem, 28, data_len, phandle)) {
216                         /* XXX should just increment counter here.. */
217                         printf("rx: truncated UDP packet\n");
218                         rxi_FreePacket(phandle);
219                     } else
220                         (*rxk_PacketArrivalProc) (phandle, &taddr,
221                                                   rxk_portRocks[i], data_len);
222                 } else
223                     m_freem(am);
224                 return;
225             }
226         }
227     }
228
229     /* if we get here, try to deliver packet to udp */
230     if (tproc = parent_proto.pr_input)
231         (*tproc) (am, aif);
232     return;
233 }
234
235 /* 
236  * UDP fast timer to raise events for all but Solaris and NCR. 
237  * Called about 5 times per second (at unknown priority?).  Must go to
238  * splnet or obtain global lock before touching anything significant.
239  */
240 static void
241 rxk_fasttimo(void)
242 {
243     int (*tproc) ();
244     struct clock temp;
245
246     /* do rx fasttimo processing here */
247     rxevent_RaiseEvents(&temp);
248     if (tproc = parent_proto.pr_fasttimo)
249         (*tproc) ();
250 }
251
252
253 /* start intercepting basic calls */
254 void
255 rxk_init(void)
256 {
257     struct protosw *tpro, *last;
258     if (rxk_initDone)
259         return;
260
261     last = inetdomain.dom_protoswNPROTOSW;
262     for (tpro = inetdomain.dom_protosw; tpro < last; tpro++) {
263         if (tpro->pr_protocol == IPPROTO_UDP) {
264             memcpy(&parent_proto, tpro, sizeof(parent_proto));
265             tpro->pr_input = rxk_input;
266             tpro->pr_fasttimo = rxk_fasttimo;
267             rxk_initDone = 1;
268             return;
269         }
270     }
271     osi_Panic("inet:no udp");
272 }
273 #endif /* RXK_LISTENER_ENV */
274
275 /*
276  * RX IP address routines.
277  */
278
279 static afs_uint32 myNetAddrs[ADDRSPERSITE];
280 static int myNetMTUs[ADDRSPERSITE];
281 static int myNetFlags[ADDRSPERSITE];
282 static int numMyNetAddrs = 0;
283
284 /* This version doesn't even begin to handle iterative requests, but then
285  * we don't yet use them anyway. Fix this when rxi_InitPeerParams is changed
286  * to find a true maximum.
287  */
288 static int
289 rxi_MatchIfnet(struct hashbucket *h, caddr_t key, caddr_t arg1, caddr_t arg2)
290 {
291     afs_uint32 ppaddr = *(afs_uint32 *) key;
292     int match_value = *(int *)arg1;
293     struct in_ifaddr *ifa = (struct in_ifaddr *)h;
294     struct sockaddr_in *sin;
295
296     if ((ppaddr & ifa->ia_netmask) == ifa->ia_net) {
297         if ((ppaddr & ifa->ia_subnetmask) == ifa->ia_subnet) {
298             sin = IA_SIN(ifa);
299             if (sin->sin_addr.s_addr == ppaddr) {       /* ie, ME!!!  */
300                 match_value = 4;
301                 *(struct in_ifaddr **)arg2 = ifa;
302             }
303             if (match_value < 3) {
304                 *(struct in_ifaddr **)arg2 = ifa;
305                 match_value = 3;
306             }
307         } else {
308             if (match_value < 2) {
309                 *(struct in_ifaddr **)arg2 = ifa;
310                 match_value = 2;
311             }
312         }
313     }
314     *(int *)arg1 = match_value;
315     return 0;
316 }
317
318
319 struct ifnet *
320 rxi_FindIfnet(afs_uint32 addr, afs_uint32 * maskp)
321 {
322     afs_uint32 ppaddr;
323     int match_value = 0;
324     struct in_ifaddr *ifad;
325
326     if (numMyNetAddrs == 0)
327         (void)rxi_GetIFInfo();
328
329     ppaddr = ntohl(addr);
330     ifad = (struct in_ifaddr *)&hashinfo_inaddr;
331
332     (void)hash_enum(&hashinfo_inaddr, rxi_MatchIfnet, HTF_INET,
333                     (caddr_t) & ppaddr, (caddr_t) & match_value,
334                     (caddr_t) & ifad);
335
336     if (match_value) {
337         if (maskp)
338             *maskp = ifad->ia_subnetmask;
339         return ifad->ia_ifp;
340     } else
341         return NULL;
342 }
343
344 static int
345 rxi_EnumGetIfInfo(struct hashbucket *h, caddr_t key, caddr_t arg1,
346                   caddr_t arg2)
347 {
348     int different = *(int *)arg1;
349     int i = *(int *)arg2;
350     struct in_ifaddr *iap = (struct in_ifaddr *)h;
351     struct ifnet *ifnp;
352     afs_uint32 ifinaddr;
353     afs_uint32 rxmtu;
354
355     if (i >= ADDRSPERSITE)
356         return 0;
357
358     ifnp = iap->ia_ifp;
359     rxmtu = (ifnp->if_mtu - RX_IPUDP_SIZE);
360     ifinaddr = ntohl(iap->ia_addr.sin_addr.s_addr);
361     if (myNetAddrs[i] != ifinaddr) {
362         myNetAddrs[i] = ifinaddr;
363         myNetMTUs[i] = rxmtu;
364         different++;
365         *(int *)arg1 = different;
366     }
367     rxmtu = rxmtu * rxi_nRecvFrags + ((rxi_nRecvFrags - 1) * UDP_HDR_SIZE);
368     if (!rx_IsLoopbackAddr(ifinaddr) && (rxmtu > rx_maxReceiveSize)) {
369         rx_maxReceiveSize = MIN(RX_MAX_PACKET_SIZE, rxmtu);
370         rx_maxReceiveSize = MIN(rx_maxReceiveSize, rx_maxReceiveSizeUser);
371     }
372
373     *(int *)arg2 = i + 1;
374     return 0;
375 }
376
377 int
378 rxi_GetIFInfo()
379 {
380     int i = 0;
381     int different = 0;
382
383     /* SGI 6.2 does not have a pointer from the ifnet to the list of
384      * of addresses (if_addrlist). So it's more efficient to run the
385      * in_ifaddr list and use the back pointers to the ifnet struct's.
386      */
387     (void)hash_enum(&hashinfo_inaddr, rxi_EnumGetIfInfo, HTF_INET, NULL,
388                     (caddr_t) & different, (caddr_t) & i);
389
390     rx_maxJumboRecvSize =
391         RX_HEADER_SIZE + rxi_nDgramPackets * RX_JUMBOBUFFERSIZE +
392         (rxi_nDgramPackets - 1) * RX_JUMBOHEADERSIZE;
393     rx_maxJumboRecvSize = MAX(rx_maxJumboRecvSize, rx_maxReceiveSize);
394
395     return different;
396 }
397
398 /* osi_NetSend - from the now defunct afs_osinet.c */
399 #ifdef DEBUG
400 #undef DEBUG
401 #endif
402 #ifdef MP
403 #define _MP_NETLOCKS
404 #endif
405
406 osi_NetSend(asocket, addr, dvec, nvec, asize, istack)
407      osi_socket *asocket;
408      struct iovec *dvec;
409      int nvec;
410      afs_int32 asize;
411      struct sockaddr_in *addr;
412      int istack;
413 {
414     int code;
415     struct iovec tvecs[RX_MAXWVECS + 1];
416     struct iovec *iovp;
417     struct uio tuio;
418     struct mbuf *to;
419     int i;
420     bhv_desc_t bhv;
421
422     memset(&tuio, 0, sizeof(tuio));
423     memset(&tvecs, 0, sizeof(tvecs));
424
425     if (nvec > RX_MAXWVECS + 1) {
426         osi_Panic("osi_NetSend: %d: Too many iovecs.\n", nvec);
427     }
428     memcpy((char *)tvecs, (char *)dvec, nvec * sizeof(struct iovec));
429
430     tuio.uio_iov = tvecs;
431     tuio.uio_iovcnt = nvec;
432     tuio.uio_segflg = UIO_SYSSPACE;
433     tuio.uio_offset = 0;
434     tuio.uio_sigpipe = 0;
435     tuio.uio_pio = 0;
436     tuio.uio_pbuf = 0;
437
438     tuio.uio_resid = 0;
439     for (i = 0, iovp = tvecs; i < nvec; i++, iovp++)
440         tuio.uio_resid += iovp->iov_len;
441
442
443     to = m_get(M_WAIT, MT_SONAME);
444     to->m_len = sizeof(struct sockaddr_in);
445     memcpy(mtod(to, caddr_t), (char *)addr, to->m_len);
446
447     BHV_PDATA(&bhv) = (void *)asocket;
448     code = sosend(&bhv, to, &tuio, 0, NULL);
449
450     m_freem(to);
451     return code;
452 }