2 ****************************************************************************
3 * Copyright IBM Corporation 1988, 1989 - All Rights Reserved *
4 * Copyright Transarc Corporation 1989 - All Rights Reserved *
6 * Permission to use, copy, modify, and distribute this software and its *
7 * documentation for any purpose and without fee is hereby granted, *
8 * provided that the above copyright notice appear in all copies and *
9 * that both that copyright notice and this permission notice appear in *
10 * supporting documentation, and that the name of IBM not be used in *
11 * advertising or publicity pertaining to distribution of the software *
12 * without specific, written prior permission. *
14 * IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL *
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL IBM *
16 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY *
17 * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER *
18 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING *
19 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
20 ****************************************************************************
23 #include <afsconfig.h>
24 #include "afs/param.h"
29 #include <sys/malloc.h>
30 #include "rx/rx_kcommon.h"
32 #ifdef RXK_LISTENER_ENV
33 int osi_NetReceive(osi_socket so, struct sockaddr_in *addr, struct iovec *dvec,
34 int nvecs, int *alength)
36 struct socket *asocket = (struct socket *)so;
39 struct iovec iov[RX_MAXIOVECS];
40 struct sockaddr *sa = NULL;
43 int haveGlock = ISAFS_GLOCK();
44 /*AFS_STATCNT(osi_NetReceive);*/
46 if (nvecs > RX_MAXIOVECS)
47 osi_Panic("osi_NetReceive: %d: Too many iovecs.\n", nvecs);
49 for (i = 0 ; i < nvecs ; i++)
55 u.uio_resid = *alength;
56 u.uio_segflg = UIO_SYSSPACE;
62 code = soreceive(asocket, &sa, &u, NULL, NULL, NULL);
69 Debugger("afs NetReceive busted");
76 *alength -= u.uio_resid;
78 if (sa->sa_family == AF_INET) {
80 *addr = *(struct sockaddr_in *) sa;
82 printf("Unknown socket family %d in NetReceive\n", sa->sa_family);
88 extern int rxk_ListenerPid;
89 void osi_StopListener(void)
94 p = pfind(rxk_ListenerPid);
100 osi_NetSend(osi_socket asocket, struct sockaddr_in *addr,
101 struct iovec *dvec, int nvecs, afs_int32 alength, int istack)
103 register afs_int32 code;
105 struct iovec iov[RX_MAXIOVECS];
107 int haveGlock = ISAFS_GLOCK();
109 AFS_STATCNT(osi_NetSend);
110 if (nvecs > RX_MAXIOVECS)
111 osi_Panic("osi_NetSend: %d: Too many iovecs.\n", nvecs);
113 for (i = 0 ; i < nvecs ; i++)
117 u.uio_iovcnt = nvecs;
119 u.uio_resid = alength;
120 u.uio_segflg = UIO_SYSSPACE;
121 u.uio_rw = UIO_WRITE;
124 addr->sin_len = sizeof(struct sockaddr_in);
131 code = sosend(asocket, (struct sockaddr *) addr, &u, NULL, NULL, 0, curproc);
135 Debugger("afs NetSend busted");
145 /* This code *almost* works :( */
146 static struct protosw parent_proto; /* udp proto switch */
147 static void rxk_input (struct mbuf *am, int iphlen);
148 static void rxk_fasttimo (void);
150 /* start intercepting basic calls */
152 register struct protosw *tpro, *last;
153 if (rxk_initDone) return 0;
155 last = inetdomain.dom_protoswNPROTOSW;
156 for (tpro = inetdomain.dom_protosw; tpro < last; tpro++)
157 if (tpro->pr_protocol == IPPROTO_UDP) {
158 #if 0 /* not exported */
159 /* force UDP checksumming on for AFS */
163 memcpy(&parent_proto, tpro, sizeof(parent_proto));
164 tpro->pr_input = rxk_input;
165 tpro->pr_fasttimo = rxk_fasttimo;
167 * don't bother with pr_drain and pr_ctlinput
168 * until we have something to do
173 osi_Panic("inet:no udp");
177 static void rxk_input (struct mbuf *am, int iphlen)
180 register unsigned short *tsp;
183 register struct ip *ti;
184 struct udpiphdr *tvu;
188 struct sockaddr_in taddr;
191 int data_len, comp_sum;
196 /* make sure we have base ip and udp headers in first mbuf */
197 if (iphlen > sizeof (struct ip)) {
198 ip_stripoptions(am, NULL);
199 iphlen = sizeof (struct ip);
202 if (am->m_len < sizeof(struct udpiphdr)) {
203 am = m_pullup(am, sizeof(struct udpiphdr));
210 ti = mtod(am, struct ip *);
211 /* skip basic ip hdr */
212 tu = (struct udphdr *)(((char *)ti) + sizeof(struct ip));
214 /* now read the port out */
218 for(tsp=rxk_ports, i=0; i<MAXRXPORTS;i++) {
219 if (*tsp++ == port) {
220 /* checksum the packet */
222 * Make mbuf data length reflect UDP length.
223 * If not enough data to reflect UDP length, drop.
225 tvu = (struct udpiphdr *)ti;
226 tlen = ntohs((u_short)tvu->ui_ulen);
227 if ((int)ti->ip_len != tlen) {
228 if (tlen > (int)ti->ip_len) {
233 m_adj(am, tlen - (int)ti->ip_len);
235 /* deliver packet to rx */
236 taddr.sin_family = AF_INET; /* compute source address */
237 taddr.sin_port = tu->uh_sport;
238 taddr.sin_addr.s_addr = ti->ip_src.s_addr;
239 taddr.sin_len = sizeof(taddr);
240 tvu = (struct udpiphdr *) ti; /* virtual udp structure, for cksum */
241 /* handle the checksum. Note that this code damages the actual ip
242 header (replacing it with the virtual one, which is the same size),
243 so we must ensure we get everything out we need, first */
244 if ( tu->uh_sum != 0) {
245 /* if the checksum is there, always check it. It's crazy not
246 * to, unless you can really be sure that your
247 * underlying network (and interfaces and drivers and
248 * DMA hardware, etc!) is error-free. First, fill
249 * in entire virtual ip header. */
250 memset(tvu->ui_i.ih_x1, 0, 9);
251 tvu->ui_len = tvu->ui_ulen;
252 tlen = ntohs((unsigned short)(tvu->ui_ulen));
253 if (in_cksum(am, sizeof(struct ip) + tlen)) {
254 /* checksum, including cksum field, doesn't come out 0, so
255 this packet is bad */
263 * 28 is IP (20) + UDP (8) header. ulen includes
264 * udp header, and we *don't* tell RX about udp
265 * header either. So, we remove those 8 as well.
267 data_len = ntohs(tu->uh_ulen);
270 if (!(*rxk_GetPacketProc)(&phandle, data_len)) {
271 if (rx_mb_to_packet(am, m_freem, 28, data_len, phandle)) {
272 /* XXX should just increment counter here.. */
273 printf("rx: truncated UDP packet\n");
274 rxi_FreePacket(phandle);
277 (*rxk_PacketArrivalProc)(phandle, &taddr,
278 rxk_portRocks[i], data_len);
287 /* if we get here, try to deliver packet to udp */
288 if (tproc = parent_proto.pr_input) (*tproc)(am,iphlen);
295 * UDP fast timer to raise events for all but Solaris and NCR.
296 * Called about 5 times per second (at unknown priority?). Must go to
297 * splnet or obtain global lock before touching anything significant.
299 static void rxk_fasttimo (void)
304 /* do rx fasttimo processing here */
305 rxevent_RaiseEvents(&temp);
306 if (tproc = parent_proto.pr_fasttimo) (*tproc)();
309 /* rx_NetSend - send asize bytes at adata from asocket to host at addr.
311 * Now, why do we allocate a new buffer when we could theoretically use the one
312 * pointed to by adata? Because PRU_SEND returns after queueing the message,
313 * not after sending it. If the sender changes the data after queueing it,
314 * we'd see the already-queued data change. One attempt to fix this without
315 * adding a copy would be to have this function wait until the datagram is
316 * sent; however this doesn't work well. In particular, if a host is down, and
317 * an ARP fails to that host, this packet will be queued until the ARP request
318 * comes back, which could be hours later. We can't block in this routine that
319 * long, since it prevents RPC timeouts from happening.
321 /* XXX In the brave new world, steal the data bufs out of the rx_packet iovec,
322 * and just queue those. XXX
325 /* set lock on sockbuf sb; can't call sblock since we're at interrupt level
328 register struct sockbuf *sb; {
329 AFS_STATCNT(trysblock);
330 if (sb->sb_flags & SB_LOCK){
331 return -1; /* can't lock socket */
333 sb->sb_flags |= SB_LOCK;
337 /* We only have to do all the mbuf management ourselves if we can be called at
338 interrupt time. in RXK_LISTENER_ENV, we can just call sosend() */
340 osi_NetSend(osi_socket asocket, struct sockaddr_in *addr,
341 struct iovec *dvec, int nvec, afs_int32 asize, int istack)
343 register struct mbuf *tm, *um;
344 register afs_int32 code;
346 struct mbuf *top = 0;
347 register struct mbuf *m, **mp;
358 AFS_STATCNT(osi_NetSend);
359 /* Actually, the Ultrix way is as good as any for us, so we don't bother with
360 * special mbufs any more. Used to think we could get away with not copying
361 * the data to the interface, but there's no way to tell the caller not to
362 * reuse the buffers after sending, so we lost out on that trick anyway */
364 if (trysblock(&asocket->so_snd)) {
370 tdata = dvec[i].iov_base;
371 tl = dvec[i].iov_len;
375 MGETHDR(m, M_DONTWAIT, MT_DATA);
377 sbunlock(&asocket->so_snd);
383 m->m_pkthdr.rcvif = NULL;
385 MGET(m, M_DONTWAIT, MT_DATA);
387 /* can't get an mbuf, give up */
388 if (top) m_freem(top); /* free mbuf list we're building */
389 sbunlock(&asocket->so_snd);
394 * WARNING: the `4 * MLEN' is somewhat dubious. It is better than
395 * `NBPG', which may have no relation to `CLBYTES'. Also, `CLBYTES'
396 * may be so large that we never use clusters, resulting in far
397 * too many mbufs being used. It is often better to briefly use
398 * a cluster, even if we are only using a portion of it. Since
399 * we are on the xmit side, it shouldn't end up sitting on a queue
400 * for a potentially unbounded time (except perhaps if we are talking
403 if (asize >= 4 * MLEN) { /* try to get cluster mbuf */
404 /* different algorithms for getting cluster mbuf */
405 MCLGET(m, M_DONTWAIT);
406 if ((m->m_flags & M_EXT) == 0)
410 /* now compute usable size */
411 len = MIN(mlen, asize);
412 /* Should I look at MAPPED_MBUFS??? */
415 len = MIN(mlen, asize);
419 top->m_pkthdr.len += len;
420 tpa = mtod(m, caddr_t);
423 memcpy(tpa, tdata, rlen);
433 /* shouldn't come here! */
434 asize = 0; /* so we make progress toward completion */
437 tdata = dvec[i].iov_base;
438 tl = dvec[i].iov_len;
450 /* setup mbuf corresponding to destination address */
451 um = m_get(M_DONTWAIT, MT_SONAME);
453 if (top) m_freem(top); /* free mbuf chain */
454 sbunlock(&asocket->so_snd);
458 memcpy(mtod(um, caddr_t), addr, sizeof(*addr));
459 addr->sin_len = um->m_len = sizeof(*addr);
460 /* note that udp_usrreq frees funny mbuf. We hold onto data, but mbuf
461 * around it is gone. */
462 /* haveGlock = ISAFS_GLOCK();
466 /* SOCKET_LOCK(asocket); */
467 /* code = (*asocket->so_proto->pr_usrreq)(asocket, PRU_SEND, tm, um, 0); */
469 if (before) Debugger("afs NetSend before");
471 code = (*asocket->so_proto->pr_usrreqs->pru_send)(asocket, 0, tm,
472 (struct sockaddr *) addr,
474 /* SOCKET_UNLOCK(asocket); */
478 sbunlock(&asocket->so_snd);
483 Debugger("afs NetSend busted");
492 #endif /* AFS_FBSD40_ENV */