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 <sys/malloc.h>
15 #include "rx/rx_kcommon.h"
17 #ifdef RXK_LISTENER_ENV
19 osi_NetReceive(osi_socket asocket, struct sockaddr_in *addr,
20 struct iovec *dvec, int nvecs, int *alength)
24 struct iovec iov[RX_MAXIOVECS];
25 struct sockaddr *sa = NULL;
28 int haveGlock = ISAFS_GLOCK();
30 memset(&u, 0, sizeof(u));
31 memset(&iov, 0, sizeof(iov));
33 /*AFS_STATCNT(osi_NetReceive); */
35 if (nvecs > RX_MAXIOVECS)
36 osi_Panic("osi_NetReceive: %d: Too many iovecs.\n", nvecs);
38 for (i = 0; i < nvecs; i++)
44 u.uio_resid = *alength;
45 u.uio_segflg = UIO_SYSSPACE;
51 code = soreceive(asocket, &sa, &u, NULL, NULL, NULL);
58 Debugger("afs NetReceive busted");
65 *alength -= u.uio_resid;
67 if (sa->sa_family == AF_INET) {
69 *addr = *(struct sockaddr_in *)sa;
71 printf("Unknown socket family %d in NetReceive\n", sa->sa_family);
77 extern int rxk_ListenerPid;
79 osi_StopListener(void)
81 struct sockaddr_in taddr;
88 * Have to drop global lock to safely do this.
89 * soclose() is currently protected by Giant,
90 * but pfind and psignal are MPSAFE.
92 int haveGlock = ISAFS_GLOCK();
95 soshutdown(rx_socket, SHUT_RDWR);
96 p = pfind(rxk_ListenerPid);
98 afs_warn("osi_StopListener: rxk_ListenerPid %u\n", rxk_ListenerPid);
99 #if (__FreeBSD_version >= 900044)
100 kern_psignal(p, SIGUSR1);
106 afs_warn("osi_StopListener: rxk_Listener not found (pid %u)\n",
109 /* Avoid destroying socket until osi_NetReceive has
110 * had a chance to clean up. Otherwise we can't restart. */
111 bzero(&taddr, sizeof(taddr));
112 taddr.sin_len = sizeof(struct sockaddr_in);
113 taddr.sin_family = AF_INET;
114 taddr.sin_port = rx_port;
115 taddr.sin_addr.s_addr = htonl(0x7f000001); /* no place like localhost */
116 bzero(&dvec, sizeof(dvec));
119 /* afs_osi_Sleep requires the GLOCK */
121 while(rxk_ListenerPid) {
122 afs_warn("waiting for rxk_ListenerPid to die\n");
123 osi_NetSend(rx_socket, &taddr, &dvec, 1, 1, 0);
124 afs_osi_Sleep(&rxk_ListenerPid);
127 /* in theory, we are now the only people doing anything with rx_socket */
135 osi_NetSend(osi_socket asocket, struct sockaddr_in *addr, struct iovec *dvec,
136 int nvecs, afs_int32 alength, int istack)
140 struct iovec iov[RX_MAXIOVECS];
142 int haveGlock = ISAFS_GLOCK();
144 memset(&u, 0, sizeof(u));
145 memset(&iov, 0, sizeof(iov));
147 AFS_STATCNT(osi_NetSend);
148 if (nvecs > RX_MAXIOVECS)
149 osi_Panic("osi_NetSend: %d: Too many iovecs.\n", nvecs);
151 for (i = 0; i < nvecs; i++)
155 u.uio_iovcnt = nvecs;
157 u.uio_resid = alength;
158 u.uio_segflg = UIO_SYSSPACE;
159 u.uio_rw = UIO_WRITE;
162 addr->sin_len = sizeof(struct sockaddr_in);
170 sosend(asocket, (struct sockaddr *)addr, &u, NULL, NULL, 0,
175 Debugger("afs NetSend busted");
185 /* This code *almost* works :( */
186 static struct protosw parent_proto; /* udp proto switch */
187 static void rxk_input(struct mbuf *am, int iphlen);
188 static void rxk_fasttimo(void);
190 /* start intercepting basic calls */
193 struct protosw *tpro, *last;
197 last = inetdomain.dom_protoswNPROTOSW;
198 for (tpro = inetdomain.dom_protosw; tpro < last; tpro++)
199 if (tpro->pr_protocol == IPPROTO_UDP) {
200 memcpy(&parent_proto, tpro, sizeof(parent_proto));
201 tpro->pr_input = rxk_input;
202 tpro->pr_fasttimo = rxk_fasttimo;
204 * don't bother with pr_drain and pr_ctlinput
205 * until we have something to do
210 osi_Panic("inet:no udp");
215 rxk_input(struct mbuf *am, int iphlen)
222 struct udpiphdr *tvu;
226 struct sockaddr_in taddr;
229 int data_len, comp_sum;
234 /* make sure we have base ip and udp headers in first mbuf */
235 if (iphlen > sizeof(struct ip)) {
236 ip_stripoptions(am, NULL);
237 iphlen = sizeof(struct ip);
240 if (am->m_len < sizeof(struct udpiphdr)) {
241 am = m_pullup(am, sizeof(struct udpiphdr));
248 ti = mtod(am, struct ip *);
249 /* skip basic ip hdr */
250 tu = (struct udphdr *)(((char *)ti) + sizeof(struct ip));
252 /* now read the port out */
256 for (tsp = rxk_ports, i = 0; i < MAXRXPORTS; i++) {
257 if (*tsp++ == port) {
258 /* checksum the packet */
260 * Make mbuf data length reflect UDP length.
261 * If not enough data to reflect UDP length, drop.
263 tvu = (struct udpiphdr *)ti;
264 tlen = ntohs((u_short) tvu->ui_ulen);
265 if ((int)ti->ip_len != tlen) {
266 if (tlen > (int)ti->ip_len) {
271 m_adj(am, tlen - (int)ti->ip_len);
273 /* deliver packet to rx */
274 taddr.sin_family = AF_INET; /* compute source address */
275 taddr.sin_port = tu->uh_sport;
276 taddr.sin_addr.s_addr = ti->ip_src.s_addr;
277 taddr.sin_len = sizeof(taddr);
278 tvu = (struct udpiphdr *)ti; /* virtual udp structure, for cksum */
279 /* handle the checksum. Note that this code damages the actual ip
280 * header (replacing it with the virtual one, which is the same size),
281 * so we must ensure we get everything out we need, first */
282 if (tu->uh_sum != 0) {
283 /* if the checksum is there, always check it. It's crazy not
284 * to, unless you can really be sure that your
285 * underlying network (and interfaces and drivers and
286 * DMA hardware, etc!) is error-free. First, fill
287 * in entire virtual ip header. */
288 memset(tvu->ui_i.ih_x1, 0, 9);
289 tvu->ui_len = tvu->ui_ulen;
290 tlen = ntohs((unsigned short)(tvu->ui_ulen));
291 if (in_cksum(am, sizeof(struct ip) + tlen)) {
292 /* checksum, including cksum field, doesn't come out 0, so
293 * this packet is bad */
301 * 28 is IP (20) + UDP (8) header. ulen includes
302 * udp header, and we *don't* tell RX about udp
303 * header either. So, we remove those 8 as well.
305 data_len = ntohs(tu->uh_ulen);
307 if (!(*rxk_GetPacketProc) (&phandle, data_len)) {
308 if (rx_mb_to_packet(am, m_freem, 28, data_len, phandle)) {
309 /* XXX should just increment counter here.. */
310 printf("rx: truncated UDP packet\n");
311 rxi_FreePacket(phandle);
313 (*rxk_PacketArrivalProc) (phandle, &taddr,
314 rxk_portRocks[i], data_len);
323 /* if we get here, try to deliver packet to udp */
324 if (tproc = parent_proto.pr_input)
325 (*tproc) (am, iphlen);
332 * UDP fast timer to raise events for all but Solaris and NCR.
333 * Called about 5 times per second (at unknown priority?). Must go to
334 * splnet or obtain global lock before touching anything significant.
342 /* do rx fasttimo processing here */
343 rxevent_RaiseEvents(&temp);
344 if (tproc = parent_proto.pr_fasttimo)
348 /* rx_NetSend - send asize bytes at adata from asocket to host at addr.
350 * Now, why do we allocate a new buffer when we could theoretically use the one
351 * pointed to by adata? Because PRU_SEND returns after queueing the message,
352 * not after sending it. If the sender changes the data after queueing it,
353 * we'd see the already-queued data change. One attempt to fix this without
354 * adding a copy would be to have this function wait until the datagram is
355 * sent; however this doesn't work well. In particular, if a host is down, and
356 * an ARP fails to that host, this packet will be queued until the ARP request
357 * comes back, which could be hours later. We can't block in this routine that
358 * long, since it prevents RPC timeouts from happening.
360 /* XXX In the brave new world, steal the data bufs out of the rx_packet iovec,
361 * and just queue those. XXX
364 /* set lock on sockbuf sb; can't call sblock since we're at interrupt level
370 AFS_STATCNT(trysblock);
371 if (sb->sb_flags & SB_LOCK) {
372 return -1; /* can't lock socket */
374 sb->sb_flags |= SB_LOCK;
378 /* We only have to do all the mbuf management ourselves if we can be called at
379 interrupt time. in RXK_LISTENER_ENV, we can just call sosend() */
381 osi_NetSend(osi_socket asocket, struct sockaddr_in *addr, struct iovec *dvec,
382 int nvec, afs_int32 asize, int istack)
384 struct mbuf *tm, *um;
387 struct mbuf *top = 0;
388 struct mbuf *m, **mp;
396 static int before = 0;
399 AFS_STATCNT(osi_NetSend);
400 /* Actually, the Ultrix way is as good as any for us, so we don't bother with
401 * special mbufs any more. Used to think we could get away with not copying
402 * the data to the interface, but there's no way to tell the caller not to
403 * reuse the buffers after sending, so we lost out on that trick anyway */
405 if (trysblock(&asocket->so_snd)) {
411 tdata = dvec[i].iov_base;
412 tl = dvec[i].iov_len;
416 MGETHDR(m, M_DONTWAIT, MT_DATA);
418 sbunlock(&asocket->so_snd);
424 m->m_pkthdr.rcvif = NULL;
426 MGET(m, M_DONTWAIT, MT_DATA);
428 /* can't get an mbuf, give up */
430 m_freem(top); /* free mbuf list we're building */
431 sbunlock(&asocket->so_snd);
436 * WARNING: the `4 * MLEN' is somewhat dubious. It is better than
437 * `NBPG', which may have no relation to `CLBYTES'. Also, `CLBYTES'
438 * may be so large that we never use clusters, resulting in far
439 * too many mbufs being used. It is often better to briefly use
440 * a cluster, even if we are only using a portion of it. Since
441 * we are on the xmit side, it shouldn't end up sitting on a queue
442 * for a potentially unbounded time (except perhaps if we are talking
445 if (asize >= 4 * MLEN) { /* try to get cluster mbuf */
446 /* different algorithms for getting cluster mbuf */
447 MCLGET(m, M_DONTWAIT);
448 if ((m->m_flags & M_EXT) == 0)
452 /* now compute usable size */
453 len = MIN(mlen, asize);
454 /* Should I look at MAPPED_MBUFS??? */
457 len = MIN(mlen, asize);
461 top->m_pkthdr.len += len;
462 tpa = mtod(m, caddr_t);
465 memcpy(tpa, tdata, rlen);
475 /* shouldn't come here! */
476 asize = 0; /* so we make progress toward completion */
479 tdata = dvec[i].iov_base;
480 tl = dvec[i].iov_len;
492 /* setup mbuf corresponding to destination address */
493 um = m_get(M_DONTWAIT, MT_SONAME);
496 m_freem(top); /* free mbuf chain */
497 sbunlock(&asocket->so_snd);
501 memcpy(mtod(um, caddr_t), addr, sizeof(*addr));
502 addr->sin_len = um->m_len = sizeof(*addr);
503 /* note that udp_usrreq frees funny mbuf. We hold onto data, but mbuf
504 * around it is gone. */
505 /* haveGlock = ISAFS_GLOCK();
509 /* SOCKET_LOCK(asocket); */
510 /* code = (*asocket->so_proto->pr_usrreq)(asocket, PRU_SEND, tm, um, 0); */
513 Debugger("afs NetSend before");
516 (*asocket->so_proto->pr_usrreqs->pru_send) (asocket, 0, tm,
519 /* SOCKET_UNLOCK(asocket); */
523 sbunlock(&asocket->so_snd);
528 Debugger("afs NetSend busted");