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 "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];
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);
50 for (i = 0 ; i < nvecs ; i++) {
51 iov[i].iov_base = dvec[i].iov_base;
52 iov[i].iov_len = dvec[i].iov_len;
59 u.uio_segflg=UIO_SYSSPACE;
66 code = soreceive(asocket, &sa, &u, NULL, NULL, NULL);
70 Debugger("afs NetReceive busted");
78 *alength=*alength-u.uio_resid;
80 if (sa->sa_family == AF_INET) {
81 if (addr) *addr=*(struct sockaddr_in *)sa;
83 printf("Unknown socket family %d in NetReceive\n", sa->sa_family);
89 extern int rxk_ListenerPid;
90 void osi_StopListener(void)
95 p=pfind(rxk_ListenerPid);
101 osi_NetSend(osi_socket asocket, struct sockaddr_in *addr,
102 struct iovec *dvec, int nvecs, afs_int32 alength, int istack)
104 register afs_int32 code;
108 struct iovec iov[RX_MAXIOVECS];
111 int haveGlock = ISAFS_GLOCK();
113 AFS_STATCNT(osi_NetSend);
114 if (nvecs > RX_MAXIOVECS) {
115 osi_Panic("osi_NetSend: %d: Too many iovecs.\n", nvecs);
118 for (i = 0 ; i < nvecs ; i++) {
119 iov[i].iov_base = dvec[i].iov_base;
120 iov[i].iov_len = dvec[i].iov_len;
127 u.uio_segflg=UIO_SYSSPACE;
131 addr->sin_len=sizeof(struct sockaddr_in);
139 code = sosend(asocket, addr, &u, NULL, NULL, 0, curproc);
143 Debugger("afs NetSend busted");
154 /* This code *almost* works :( */
155 static struct protosw parent_proto; /* udp proto switch */
156 static void rxk_input (struct mbuf *am, int iphlen);
157 static void rxk_fasttimo (void);
159 /* start intercepting basic calls */
161 register struct protosw *tpro, *last;
162 if (rxk_initDone) return 0;
164 last = inetdomain.dom_protoswNPROTOSW;
165 for (tpro = inetdomain.dom_protosw; tpro < last; tpro++)
166 if (tpro->pr_protocol == IPPROTO_UDP) {
167 #if 0 /* not exported */
168 /* force UDP checksumming on for AFS */
172 memcpy(&parent_proto, tpro, sizeof(parent_proto));
173 tpro->pr_input = rxk_input;
174 tpro->pr_fasttimo = rxk_fasttimo;
176 * don't bother with pr_drain and pr_ctlinput
177 * until we have something to do
182 osi_Panic("inet:no udp");
186 static void rxk_input (struct mbuf *am, int iphlen)
189 register unsigned short *tsp;
192 register struct ip *ti;
193 struct udpiphdr *tvu;
197 struct sockaddr_in taddr;
200 int data_len, comp_sum;
205 /* make sure we have base ip and udp headers in first mbuf */
206 if (iphlen > sizeof (struct ip)) {
207 ip_stripoptions(am, NULL);
208 iphlen = sizeof (struct ip);
211 if (am->m_len < sizeof(struct udpiphdr)) {
212 am = m_pullup(am, sizeof(struct udpiphdr));
219 ti = mtod(am, struct ip *);
220 /* skip basic ip hdr */
221 tu = (struct udphdr *)(((char *)ti) + sizeof(struct ip));
223 /* now read the port out */
227 for(tsp=rxk_ports, i=0; i<MAXRXPORTS;i++) {
228 if (*tsp++ == port) {
229 /* checksum the packet */
231 * Make mbuf data length reflect UDP length.
232 * If not enough data to reflect UDP length, drop.
234 tvu = (struct udpiphdr *)ti;
235 tlen = ntohs((u_short)tvu->ui_ulen);
236 if ((int)ti->ip_len != tlen) {
237 if (tlen > (int)ti->ip_len) {
242 m_adj(am, tlen - (int)ti->ip_len);
244 /* deliver packet to rx */
245 taddr.sin_family = AF_INET; /* compute source address */
246 taddr.sin_port = tu->uh_sport;
247 taddr.sin_addr.s_addr = ti->ip_src.s_addr;
248 taddr.sin_len = sizeof(taddr);
249 tvu = (struct udpiphdr *) ti; /* virtual udp structure, for cksum */
250 /* handle the checksum. Note that this code damages the actual ip
251 header (replacing it with the virtual one, which is the same size),
252 so we must ensure we get everything out we need, first */
253 if ( tu->uh_sum != 0) {
254 /* if the checksum is there, always check it. It's crazy not
255 * to, unless you can really be sure that your
256 * underlying network (and interfaces and drivers and
257 * DMA hardware, etc!) is error-free. First, fill
258 * in entire virtual ip header. */
259 memset(tvu->ui_i.ih_x1, 0, 9);
260 tvu->ui_len = tvu->ui_ulen;
261 tlen = ntohs((unsigned short)(tvu->ui_ulen));
262 if (in_cksum(am, sizeof(struct ip) + tlen)) {
263 /* checksum, including cksum field, doesn't come out 0, so
264 this packet is bad */
272 * 28 is IP (20) + UDP (8) header. ulen includes
273 * udp header, and we *don't* tell RX about udp
274 * header either. So, we remove those 8 as well.
276 data_len = ntohs(tu->uh_ulen);
279 if (!(*rxk_GetPacketProc)(&phandle, data_len)) {
280 if (rx_mb_to_packet(am, m_freem, 28, data_len, phandle)) {
281 /* XXX should just increment counter here.. */
282 printf("rx: truncated UDP packet\n");
283 rxi_FreePacket(phandle);
286 (*rxk_PacketArrivalProc)(phandle, &taddr,
287 rxk_portRocks[i], data_len);
296 /* if we get here, try to deliver packet to udp */
297 if (tproc = parent_proto.pr_input) (*tproc)(am,iphlen);
304 * UDP fast timer to raise events for all but Solaris and NCR.
305 * Called about 5 times per second (at unknown priority?). Must go to
306 * splnet or obtain global lock before touching anything significant.
308 static void rxk_fasttimo (void)
313 /* do rx fasttimo processing here */
314 rxevent_RaiseEvents(&temp);
315 if (tproc = parent_proto.pr_fasttimo) (*tproc)();
318 /* rx_NetSend - send asize bytes at adata from asocket to host at addr.
320 * Now, why do we allocate a new buffer when we could theoretically use the one
321 * pointed to by adata? Because PRU_SEND returns after queueing the message,
322 * not after sending it. If the sender changes the data after queueing it,
323 * we'd see the already-queued data change. One attempt to fix this without
324 * adding a copy would be to have this function wait until the datagram is
325 * sent; however this doesn't work well. In particular, if a host is down, and
326 * an ARP fails to that host, this packet will be queued until the ARP request
327 * comes back, which could be hours later. We can't block in this routine that
328 * long, since it prevents RPC timeouts from happening.
330 /* XXX In the brave new world, steal the data bufs out of the rx_packet iovec,
331 * and just queue those. XXX
334 /* set lock on sockbuf sb; can't call sblock since we're at interrupt level
337 register struct sockbuf *sb; {
338 AFS_STATCNT(trysblock);
339 if (sb->sb_flags & SB_LOCK){
340 return -1; /* can't lock socket */
342 sb->sb_flags |= SB_LOCK;
346 /* We only have to do all the mbuf management ourselves if we can be called at
347 interrupt time. in RXK_LISTENER_ENV, we can just call sosend() */
349 osi_NetSend(osi_socket asocket, struct sockaddr_in *addr,
350 struct iovec *dvec, int nvec, afs_int32 asize, int istack)
352 register struct mbuf *tm, *um;
353 register afs_int32 code;
355 struct mbuf *top = 0;
356 register struct mbuf *m, **mp;
367 AFS_STATCNT(osi_NetSend);
368 /* Actually, the Ultrix way is as good as any for us, so we don't bother with
369 * special mbufs any more. Used to think we could get away with not copying
370 * the data to the interface, but there's no way to tell the caller not to
371 * reuse the buffers after sending, so we lost out on that trick anyway */
373 if (trysblock(&asocket->so_snd)) {
379 tdata = dvec[i].iov_base;
380 tl = dvec[i].iov_len;
384 MGETHDR(m, M_DONTWAIT, MT_DATA);
386 sbunlock(&asocket->so_snd);
392 m->m_pkthdr.rcvif = NULL;
394 MGET(m, M_DONTWAIT, MT_DATA);
396 /* can't get an mbuf, give up */
397 if (top) m_freem(top); /* free mbuf list we're building */
398 sbunlock(&asocket->so_snd);
403 * WARNING: the `4 * MLEN' is somewhat dubious. It is better than
404 * `NBPG', which may have no relation to `CLBYTES'. Also, `CLBYTES'
405 * may be so large that we never use clusters, resulting in far
406 * too many mbufs being used. It is often better to briefly use
407 * a cluster, even if we are only using a portion of it. Since
408 * we are on the xmit side, it shouldn't end up sitting on a queue
409 * for a potentially unbounded time (except perhaps if we are talking
412 if (asize >= 4 * MLEN) { /* try to get cluster mbuf */
413 /* different algorithms for getting cluster mbuf */
414 MCLGET(m, M_DONTWAIT);
415 if ((m->m_flags & M_EXT) == 0)
419 /* now compute usable size */
420 len = MIN(mlen, asize);
421 /* Should I look at MAPPED_MBUFS??? */
424 len = MIN(mlen, asize);
428 top->m_pkthdr.len += len;
429 tpa = mtod(m, caddr_t);
432 memcpy(tpa, tdata, rlen);
442 /* shouldn't come here! */
443 asize = 0; /* so we make progress toward completion */
446 tdata = dvec[i].iov_base;
447 tl = dvec[i].iov_len;
459 /* setup mbuf corresponding to destination address */
460 um = m_get(M_DONTWAIT, MT_SONAME);
462 if (top) m_freem(top); /* free mbuf chain */
463 sbunlock(&asocket->so_snd);
467 memcpy(mtod(um, caddr_t), addr, sizeof(*addr));
468 addr->sin_len = um->m_len = sizeof(*addr);
469 /* note that udp_usrreq frees funny mbuf. We hold onto data, but mbuf
470 * around it is gone. */
471 /* haveGlock = ISAFS_GLOCK();
475 /* SOCKET_LOCK(asocket); */
476 /* code = (*asocket->so_proto->pr_usrreq)(asocket, PRU_SEND, tm, um, 0); */
478 if (before) Debugger("afs NetSend before");
480 code = (*asocket->so_proto->pr_usrreqs->pru_send)(asocket, 0, tm,
481 (struct sockaddr *) addr,
483 /* SOCKET_UNLOCK(asocket); */
487 sbunlock(&asocket->so_snd);
492 Debugger("afs NetSend busted");
501 #endif /* AFS_FBSD40_ENV */