2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include "afs/param.h"
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"
23 #ifdef RXK_LISTENER_ENV
25 * OS dependent part of kernel RX listener thread.
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.
36 * error code (such as EINTR) if not
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
43 int rxk_lastSocketError = 0;
44 int rxk_nSocketErrors = 0;
45 int rxk_nSignalsCleared = 0;
48 osi_NetReceive(osi_socket so, struct sockaddr_in *addr, struct iovec *dvec,
49 int nvecs, int *alength)
53 struct mbuf *maddr = NULL;
54 struct sockaddr_in *taddr;
55 struct iovec tmpvec[RX_MAXWVECS + 2];
57 BHV_PDATA(&bhv) = (void *)so;
59 memset(&tuio, 0, sizeof(tuio));
60 memset(&tmpvec, 0, sizeof(tmpvec));
62 tuio.uio_iov = tmpvec;
63 tuio.uio_iovcnt = nvecs;
65 tuio.uio_segflg = AFS_UIOSYS;
67 tuio.uio_resid = *alength;
71 if (nvecs > RX_MAXWVECS + 2) {
72 osi_Panic("Too many (%d) iovecs passed to osi_NetReceive\n", nvecs);
74 memcpy(tmpvec, (char *)dvec, (RX_MAXWVECS + 1) * sizeof(struct iovec));
75 code = soreceive(&bhv, &maddr, &tuio, NULL, NULL);
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.
84 uthread_t *ut = curuthread;
87 sigemptyset(&ut->ut_sig);
89 thread_interrupt_clear(UT_TO_KT(ut), 1);
91 rxk_nSignalsCleared++;
93 /* Clear the error before using the socket again. */
95 rxk_lastSocketError = code;
100 *alength = *alength - tuio.uio_resid;
102 memcpy((char *)addr, (char *)mtod(maddr, struct sockaddr_in *),
103 sizeof(struct sockaddr_in));
111 #else /* RXK_LISTENER_ENV */
113 static struct protosw parent_proto; /* udp proto switch */
116 * RX input, fast timer and initialization routines.
120 rxk_input(struct mbuf *am, struct ifnet *aif, struct ipsec *spec)
127 struct udpiphdr *tvu;
130 struct sockaddr_in taddr;
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);
142 hdr = (mtod(am, struct ip *))->ip_hl;
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));
150 ti = mtod(am, struct ip *); /* recompute, since m_pullup allocates new mbuf */
151 tu = (struct udphdr *)(((char *)ti) + (hdr << 2)); /* skip ip hdr */
153 ti = mtod(am, struct ip *);
154 tu = (struct udphdr *)(((char *)ti) + 20); /* skip basic ip hdr */
156 /* now read the port out */
160 for (tsp = rxk_ports, i = 0; i < MAXRXPORTS; i++) {
161 if (*tsp++ == port) {
162 /* checksum the packet */
164 ip_stripoptions(am, (struct mbuf *)0); /* get rid of anything we don't need */
165 tu = (struct udphdr *)(((char *)ti) + 20);
168 * Make mbuf data length reflect UDP length.
169 * If not enough data to reflect UDP length, drop.
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) {
178 m_adj(am, tlen - (int)ti->ip_len);
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. */
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 */
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.
212 data_len = ntohs(tu->uh_ulen);
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);
220 (*rxk_PacketArrivalProc) (phandle, &taddr,
221 rxk_portRocks[i], data_len);
229 /* if we get here, try to deliver packet to udp */
230 if (tproc = parent_proto.pr_input)
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.
246 /* do rx fasttimo processing here */
247 rxevent_RaiseEvents(&temp);
248 if (tproc = parent_proto.pr_fasttimo)
253 /* start intercepting basic calls */
257 struct protosw *tpro, *last;
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;
271 osi_Panic("inet:no udp");
273 #endif /* RXK_LISTENER_ENV */
276 * RX IP address routines.
279 static afs_uint32 myNetAddrs[ADDRSPERSITE];
280 static int myNetMTUs[ADDRSPERSITE];
281 static int myNetFlags[ADDRSPERSITE];
282 static int numMyNetAddrs = 0;
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.
289 rxi_MatchIfnet(struct hashbucket *h, caddr_t key, caddr_t arg1, caddr_t arg2)
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;
296 if ((ppaddr & ifa->ia_netmask) == ifa->ia_net) {
297 if ((ppaddr & ifa->ia_subnetmask) == ifa->ia_subnet) {
299 if (sin->sin_addr.s_addr == ppaddr) { /* ie, ME!!! */
301 *(struct in_ifaddr **)arg2 = ifa;
303 if (match_value < 3) {
304 *(struct in_ifaddr **)arg2 = ifa;
308 if (match_value < 2) {
309 *(struct in_ifaddr **)arg2 = ifa;
314 *(int *)arg1 = match_value;
320 rxi_FindIfnet(afs_uint32 addr, afs_uint32 * maskp)
324 struct in_ifaddr *ifad;
326 if (numMyNetAddrs == 0)
327 (void)rxi_GetIFInfo();
329 ppaddr = ntohl(addr);
330 ifad = (struct in_ifaddr *)&hashinfo_inaddr;
332 (void)hash_enum(&hashinfo_inaddr, rxi_MatchIfnet, HTF_INET,
333 (caddr_t) & ppaddr, (caddr_t) & match_value,
338 *maskp = ifad->ia_subnetmask;
345 rxi_EnumGetIfInfo(struct hashbucket *h, caddr_t key, caddr_t arg1,
348 int different = *(int *)arg1;
349 int i = *(int *)arg2;
350 struct in_ifaddr *iap = (struct in_ifaddr *)h;
355 if (i >= ADDRSPERSITE)
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;
365 *(int *)arg1 = different;
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);
373 *(int *)arg2 = i + 1;
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.
387 (void)hash_enum(&hashinfo_inaddr, rxi_EnumGetIfInfo, HTF_INET, NULL,
388 (caddr_t) & different, (caddr_t) & i);
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);
398 /* osi_NetSend - from the now defunct afs_osinet.c */
406 osi_NetSend(asocket, addr, dvec, nvec, asize, istack)
411 struct sockaddr_in *addr;
415 struct iovec tvecs[RX_MAXWVECS + 1];
422 memset(&tuio, 0, sizeof(tuio));
423 memset(&tvecs, 0, sizeof(tvecs));
425 if (nvec > RX_MAXWVECS + 1) {
426 osi_Panic("osi_NetSend: %d: Too many iovecs.\n", nvec);
428 memcpy((char *)tvecs, (char *)dvec, nvec * sizeof(struct iovec));
430 tuio.uio_iov = tvecs;
431 tuio.uio_iovcnt = nvec;
432 tuio.uio_segflg = UIO_SYSSPACE;
434 tuio.uio_sigpipe = 0;
439 for (i = 0, iovp = tvecs; i < nvec; i++, iovp++)
440 tuio.uio_resid += iovp->iov_len;
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);
447 BHV_PDATA(&bhv) = (void *)asocket;
448 code = sosend(&bhv, to, &tuio, 0, NULL);