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"
16 #include "../rx/rx_kcommon.h"
19 static struct protosw parent_proto; /* udp proto switch */
20 static void rxk_input (struct mbuf *am, int iphlen);
21 static void rxk_fasttimo (void);
23 /* start intercepting basic calls */
25 register struct protosw *tpro, *last;
26 if (rxk_initDone) return 0;
28 last = inetdomain.dom_protoswNPROTOSW;
29 for (tpro = inetdomain.dom_protosw; tpro < last; tpro++)
30 if (tpro->pr_protocol == IPPROTO_UDP) {
31 /* force UDP checksumming on for AFS */
34 bcopy(tpro, &parent_proto, sizeof(parent_proto));
35 tpro->pr_input = rxk_input;
36 tpro->pr_fasttimo = rxk_fasttimo;
38 * don't bother with pr_drain and pr_ctlinput
39 * until we have something to do
44 osi_Panic("inet:no udp");
48 static void rxk_input (struct mbuf *am, int iphlen)
51 register unsigned short *tsp;
54 register struct ip *ti;
59 struct sockaddr_in taddr;
62 int data_len, comp_sum;
67 /* make sure we have base ip and udp headers in first mbuf */
68 if (iphlen > sizeof (struct ip)) {
69 ip_stripoptions(am, (struct mbuf *)0, (struct ipoption *)0);
70 iphlen = sizeof (struct ip);
73 if (am->m_len < sizeof(struct udpiphdr)) {
74 am = m_pullup(am, sizeof(struct udpiphdr));
81 ti = mtod(am, struct ip *);
82 /* skip basic ip hdr */
83 tu = (struct udphdr *)(((char *)ti) + sizeof(struct ip));
85 /* now read the port out */
89 for(tsp=rxk_ports, i=0; i<MAXRXPORTS;i++) {
91 /* checksum the packet */
93 * Make mbuf data length reflect UDP length.
94 * If not enough data to reflect UDP length, drop.
96 tvu = (struct udpiphdr *)ti;
97 tlen = ntohs((u_short)tvu->ui_ulen);
98 if ((int)ti->ip_len != tlen) {
99 if (tlen > (int)ti->ip_len) {
104 m_adj(am, tlen - (int)ti->ip_len);
106 /* deliver packet to rx */
107 taddr.sin_family = AF_INET; /* compute source address */
108 taddr.sin_port = tu->uh_sport;
109 taddr.sin_addr.s_addr = ti->ip_src.s_addr;
110 taddr.sin_len = sizeof(taddr);
111 tvu = (struct udpiphdr *) ti; /* virtual udp structure, for cksum */
112 /* handle the checksum. Note that this code damages the actual ip
113 header (replacing it with the virtual one, which is the same size),
114 so we must ensure we get everything out we need, first */
115 if ( tu->uh_sum != 0) {
116 /* if the checksum is there, always check it. It's crazy not
117 * to, unless you can really be sure that your
118 * underlying network (and interfaces and drivers and
119 * DMA hardware, etc!) is error-free. First, fill
120 * in entire virtual ip header. */
121 tvu->ui_i.fill[0] = 0;
122 tvu->ui_i.fill[1] = 0;
124 tvu->ui_len = tvu->ui_ulen;
125 tlen = ntohs((unsigned short)(tvu->ui_ulen));
126 if (in_cksum(am, sizeof(struct ip) + tlen)) {
127 /* checksum, including cksum field, doesn't come out 0, so
128 this packet is bad */
136 * 28 is IP (20) + UDP (8) header. ulen includes
137 * udp header, and we *don't* tell RX about udp
138 * header either. So, we remove those 8 as well.
140 data_len = ntohs(tu->uh_ulen);
143 if (!(*rxk_GetPacketProc)(&phandle, data_len)) {
144 if (rx_mb_to_packet(am, m_freem, 28, data_len, phandle)) {
145 /* XXX should just increment counter here.. */
146 printf("rx: truncated UDP packet\n");
147 rxi_FreePacket(phandle);
150 (*rxk_PacketArrivalProc)(phandle, &taddr,
151 rxk_portRocks[i], data_len);
160 /* if we get here, try to deliver packet to udp */
161 if (tproc = parent_proto.pr_input) (*tproc)(am,iphlen);
168 * UDP fast timer to raise events for all but Solaris and NCR.
169 * Called about 5 times per second (at unknown priority?). Must go to
170 * splnet or obtain global lock before touching anything significant.
172 static void rxk_fasttimo (void)
177 /* do rx fasttimo processing here */
178 rxevent_RaiseEvents(&temp);
179 if (tproc = parent_proto.pr_fasttimo) (*tproc)();
183 /* rx_NetSend - send asize bytes at adata from asocket to host at addr.
185 * Now, why do we allocate a new buffer when we could theoretically use the one
186 * pointed to by adata? Because PRU_SEND returns after queueing the message,
187 * not after sending it. If the sender changes the data after queueing it,
188 * we'd see the already-queued data change. One attempt to fix this without
189 * adding a copy would be to have this function wait until the datagram is
190 * sent; however this doesn't work well. In particular, if a host is down, and
191 * an ARP fails to that host, this packet will be queued until the ARP request
192 * comes back, which could be hours later. We can't block in this routine that
193 * long, since it prevents RPC timeouts from happening.
195 /* XXX In the brave new world, steal the data bufs out of the rx_packet iovec,
196 * and just queue those. XXX
199 /* set lock on sockbuf sb; can't call sblock since we're at interrupt level
202 register struct sockbuf *sb; {
203 AFS_STATCNT(trysblock);
204 if (sb->sb_flags & SB_LOCK){
205 return -1; /* can't lock socket */
207 sb->sb_flags |= SB_LOCK;
212 osi_NetSend(asocket, addr, dvec, nvec, asize, istack)
213 register struct socket *asocket;
216 register afs_int32 asize;
217 struct sockaddr_in *addr;
220 register struct mbuf *tm, *um;
221 register afs_int32 code;
223 struct mbuf *top = 0;
224 register struct mbuf *m, **mp;
232 AFS_STATCNT(osi_NetSend);
234 /* Actually, the Ultrix way is as good as any for us, so we don't bother with
235 * special mbufs any more. Used to think we could get away with not copying
236 * the data to the interface, but there's no way to tell the caller not to
237 * reuse the buffers after sending, so we lost out on that trick anyway */
242 tdata = dvec[i].iov_base;
243 tl = dvec[i].iov_len;
247 MGETHDR(m, M_DONTWAIT, MT_DATA);
254 m->m_pkthdr.rcvif = (struct ifnet *)0;
256 MGET(m, M_DONTWAIT, MT_DATA);
258 /* can't get an mbuf, give up */
259 if (top) m_freem(top); /* free mbuf list we're building */
264 * WARNING: the `4 * MLEN' is somewhat dubious. It is better than
265 * `NBPG', which may have no relation to `CLBYTES'. Also, `CLBYTES'
266 * may be so large that we never use clusters, resulting in far
267 * too many mbufs being used. It is often better to briefly use
268 * a cluster, even if we are only using a portion of it. Since
269 * we are on the xmit side, it shouldn't end up sitting on a queue
270 * for a potentially unbounded time (except perhaps if we are talking
273 if (asize >= 4 * MLEN) { /* try to get cluster mbuf */
274 register struct mbuf *p;
276 /* different algorithms for getting cluster mbuf */
277 MCLGET(m, M_DONTWAIT);
278 if ((m->m_flags & M_EXT) == 0)
282 /* now compute usable size */
283 len = MIN(mlen, asize);
284 /* Should I look at MAPPED_MBUFS??? */
287 len = MIN(mlen, asize);
291 top->m_pkthdr.len += len;
292 tpa = mtod(m, caddr_t);
295 bcopy(tdata, tpa, rlen);
305 /* shouldn't come here! */
306 asize = 0; /* so we make progress toward completion */
309 tdata = dvec[i].iov_base;
310 tl = dvec[i].iov_len;
320 tm->m_act = (struct mbuf *) 0;
322 /* setup mbuf corresponding to destination address */
323 um = m_get(M_DONTWAIT, MT_SONAME);
325 if (top) m_freem(top); /* free mbuf chain */
326 /* if this were vfs40, we'd do sbunlock(asocket, &asocket->so_snd), but
327 we don't do the locking at all for vfs40 systems */
331 bcopy(addr, mtod(um, caddr_t), sizeof(*addr));
332 um->m_len = sizeof(*addr);
333 /* note that udp_usrreq frees funny mbuf. We hold onto data, but mbuf
334 * around it is gone. we free address ourselves. */
335 haveGlock = ISAFS_GLOCK();
339 SOCKET_LOCK(asocket);
340 code = (*asocket->so_proto->pr_usrreq)(asocket, PRU_SEND, tm, um, 0);
341 SOCKET_UNLOCK(asocket);
351 #endif /* AFS_DUX40_ENV */