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 "../afs/param.h"
12 #include "../rx/rx_kcommon.h"
15 static struct protosw parent_proto; /* udp proto switch */
16 static void rxk_input (struct mbuf *am, int iphlen);
17 static void rxk_fasttimo (void);
19 /* start intercepting basic calls */
21 register struct protosw *tpro, *last;
22 if (rxk_initDone) return 0;
24 last = inetdomain.dom_protoswNPROTOSW;
25 for (tpro = inetdomain.dom_protosw; tpro < last; tpro++)
26 if (tpro->pr_protocol == IPPROTO_UDP) {
27 /* force UDP checksumming on for AFS */
30 bcopy(tpro, &parent_proto, sizeof(parent_proto));
31 tpro->pr_input = rxk_input;
32 tpro->pr_fasttimo = rxk_fasttimo;
34 * don't bother with pr_drain and pr_ctlinput
35 * until we have something to do
40 osi_Panic("inet:no udp");
44 static void rxk_input (struct mbuf *am, int iphlen)
47 register unsigned short *tsp;
50 register struct ip *ti;
55 struct sockaddr_in taddr;
58 int data_len, comp_sum;
63 /* make sure we have base ip and udp headers in first mbuf */
64 if (iphlen > sizeof (struct ip)) {
65 ip_stripoptions(am, (struct mbuf *)0, (struct ipoption *)0);
66 iphlen = sizeof (struct ip);
69 if (am->m_len < sizeof(struct udpiphdr)) {
70 am = m_pullup(am, sizeof(struct udpiphdr));
77 ti = mtod(am, struct ip *);
78 /* skip basic ip hdr */
79 tu = (struct udphdr *)(((char *)ti) + sizeof(struct ip));
81 /* now read the port out */
85 for(tsp=rxk_ports, i=0; i<MAXRXPORTS;i++) {
87 /* checksum the packet */
89 * Make mbuf data length reflect UDP length.
90 * If not enough data to reflect UDP length, drop.
92 tvu = (struct udpiphdr *)ti;
93 tlen = ntohs((u_short)tvu->ui_ulen);
94 if ((int)ti->ip_len != tlen) {
95 if (tlen > (int)ti->ip_len) {
100 m_adj(am, tlen - (int)ti->ip_len);
102 /* deliver packet to rx */
103 taddr.sin_family = AF_INET; /* compute source address */
104 taddr.sin_port = tu->uh_sport;
105 taddr.sin_addr.s_addr = ti->ip_src.s_addr;
106 taddr.sin_len = sizeof(taddr);
107 tvu = (struct udpiphdr *) ti; /* virtual udp structure, for cksum */
108 /* handle the checksum. Note that this code damages the actual ip
109 header (replacing it with the virtual one, which is the same size),
110 so we must ensure we get everything out we need, first */
111 if ( tu->uh_sum != 0) {
112 /* if the checksum is there, always check it. It's crazy not
113 * to, unless you can really be sure that your
114 * underlying network (and interfaces and drivers and
115 * DMA hardware, etc!) is error-free. First, fill
116 * in entire virtual ip header. */
117 tvu->ui_i.fill[0] = 0;
118 tvu->ui_i.fill[1] = 0;
120 tvu->ui_len = tvu->ui_ulen;
121 tlen = ntohs((unsigned short)(tvu->ui_ulen));
122 if (in_cksum(am, sizeof(struct ip) + tlen)) {
123 /* checksum, including cksum field, doesn't come out 0, so
124 this packet is bad */
132 * 28 is IP (20) + UDP (8) header. ulen includes
133 * udp header, and we *don't* tell RX about udp
134 * header either. So, we remove those 8 as well.
136 data_len = ntohs(tu->uh_ulen);
139 if (!(*rxk_GetPacketProc)(&phandle, data_len)) {
140 if (rx_mb_to_packet(am, m_freem, 28, data_len, phandle)) {
141 /* XXX should just increment counter here.. */
142 printf("rx: truncated UDP packet\n");
143 rxi_FreePacket(phandle);
146 (*rxk_PacketArrivalProc)(phandle, &taddr,
147 rxk_portRocks[i], data_len);
156 /* if we get here, try to deliver packet to udp */
157 if (tproc = parent_proto.pr_input) (*tproc)(am,iphlen);
164 * UDP fast timer to raise events for all but Solaris and NCR.
165 * Called about 5 times per second (at unknown priority?). Must go to
166 * splnet or obtain global lock before touching anything significant.
168 static void rxk_fasttimo (void)
173 /* do rx fasttimo processing here */
174 rxevent_RaiseEvents(&temp);
175 if (tproc = parent_proto.pr_fasttimo) (*tproc)();
179 /* rx_NetSend - send asize bytes at adata from asocket to host at addr.
181 * Now, why do we allocate a new buffer when we could theoretically use the one
182 * pointed to by adata? Because PRU_SEND returns after queueing the message,
183 * not after sending it. If the sender changes the data after queueing it,
184 * we'd see the already-queued data change. One attempt to fix this without
185 * adding a copy would be to have this function wait until the datagram is
186 * sent; however this doesn't work well. In particular, if a host is down, and
187 * an ARP fails to that host, this packet will be queued until the ARP request
188 * comes back, which could be hours later. We can't block in this routine that
189 * long, since it prevents RPC timeouts from happening.
191 /* XXX In the brave new world, steal the data bufs out of the rx_packet iovec,
192 * and just queue those. XXX
195 /* set lock on sockbuf sb; can't call sblock since we're at interrupt level
198 register struct sockbuf *sb; {
199 AFS_STATCNT(trysblock);
200 if (sb->sb_flags & SB_LOCK){
201 return -1; /* can't lock socket */
203 sb->sb_flags |= SB_LOCK;
208 osi_NetSend(asocket, addr, dvec, nvec, asize, istack)
209 register struct socket *asocket;
212 register afs_int32 asize;
213 struct sockaddr_in *addr;
216 register struct mbuf *tm, *um;
217 register afs_int32 code;
219 struct mbuf *top = 0;
220 register struct mbuf *m, **mp;
228 AFS_STATCNT(osi_NetSend);
230 /* Actually, the Ultrix way is as good as any for us, so we don't bother with
231 * special mbufs any more. Used to think we could get away with not copying
232 * the data to the interface, but there's no way to tell the caller not to
233 * reuse the buffers after sending, so we lost out on that trick anyway */
238 tdata = dvec[i].iov_base;
239 tl = dvec[i].iov_len;
243 MGETHDR(m, M_DONTWAIT, MT_DATA);
250 m->m_pkthdr.rcvif = (struct ifnet *)0;
252 MGET(m, M_DONTWAIT, MT_DATA);
254 /* can't get an mbuf, give up */
255 if (top) m_freem(top); /* free mbuf list we're building */
260 * WARNING: the `4 * MLEN' is somewhat dubious. It is better than
261 * `NBPG', which may have no relation to `CLBYTES'. Also, `CLBYTES'
262 * may be so large that we never use clusters, resulting in far
263 * too many mbufs being used. It is often better to briefly use
264 * a cluster, even if we are only using a portion of it. Since
265 * we are on the xmit side, it shouldn't end up sitting on a queue
266 * for a potentially unbounded time (except perhaps if we are talking
269 if (asize >= 4 * MLEN) { /* try to get cluster mbuf */
270 register struct mbuf *p;
272 /* different algorithms for getting cluster mbuf */
273 MCLGET(m, M_DONTWAIT);
274 if ((m->m_flags & M_EXT) == 0)
278 /* now compute usable size */
279 len = MIN(mlen, asize);
280 /* Should I look at MAPPED_MBUFS??? */
283 len = MIN(mlen, asize);
287 top->m_pkthdr.len += len;
288 tpa = mtod(m, caddr_t);
291 bcopy(tdata, tpa, rlen);
301 /* shouldn't come here! */
302 asize = 0; /* so we make progress toward completion */
305 tdata = dvec[i].iov_base;
306 tl = dvec[i].iov_len;
316 tm->m_act = (struct mbuf *) 0;
318 /* setup mbuf corresponding to destination address */
319 um = m_get(M_DONTWAIT, MT_SONAME);
321 if (top) m_freem(top); /* free mbuf chain */
322 /* if this were vfs40, we'd do sbunlock(asocket, &asocket->so_snd), but
323 we don't do the locking at all for vfs40 systems */
327 bcopy(addr, mtod(um, caddr_t), sizeof(*addr));
328 um->m_len = sizeof(*addr);
329 /* note that udp_usrreq frees funny mbuf. We hold onto data, but mbuf
330 * around it is gone. we free address ourselves. */
331 haveGlock = ISAFS_GLOCK();
335 SOCKET_LOCK(asocket);
336 code = (*asocket->so_proto->pr_usrreq)(asocket, PRU_SEND, tm, um, 0);
337 SOCKET_UNLOCK(asocket);
347 #endif /* AFS_DUX40_ENV */