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"
17 #include "rx/rx_kcommon.h"
20 static struct protosw parent_proto; /* udp proto switch */
21 static void rxk_input(struct mbuf *am, int iphlen);
22 static void rxk_fasttimo(void);
24 /* start intercepting basic calls */
27 register struct protosw *tpro, *last;
31 last = inetdomain.dom_protoswNPROTOSW;
32 for (tpro = inetdomain.dom_protosw; tpro < last; tpro++)
33 if (tpro->pr_protocol == IPPROTO_UDP) {
34 /* force UDP checksumming on for AFS */
37 memcpy(&parent_proto, tpro, sizeof(parent_proto));
38 tpro->pr_input = rxk_input;
39 tpro->pr_fasttimo = rxk_fasttimo;
41 * don't bother with pr_drain and pr_ctlinput
42 * until we have something to do
47 osi_Panic("inet:no udp");
52 rxk_input(struct mbuf *am, int iphlen)
55 register unsigned short *tsp;
58 register struct ip *ti;
63 struct sockaddr_in taddr;
66 int data_len, comp_sum;
71 /* make sure we have base ip and udp headers in first mbuf */
72 if (iphlen > sizeof(struct ip)) {
73 ip_stripoptions(am, NULL, NULL);
74 iphlen = sizeof(struct ip);
77 if (am->m_len < sizeof(struct udpiphdr)) {
78 am = m_pullup(am, sizeof(struct udpiphdr));
85 ti = mtod(am, struct ip *);
86 /* skip basic ip hdr */
87 tu = (struct udphdr *)(((char *)ti) + sizeof(struct ip));
89 /* now read the port out */
93 for (tsp = rxk_ports, i = 0; i < MAXRXPORTS; i++) {
95 /* checksum the packet */
97 * Make mbuf data length reflect UDP length.
98 * If not enough data to reflect UDP length, drop.
100 tvu = (struct udpiphdr *)ti;
101 tlen = ntohs((u_short) tvu->ui_ulen);
102 if ((int)ti->ip_len != tlen) {
103 if (tlen > (int)ti->ip_len) {
108 m_adj(am, tlen - (int)ti->ip_len);
110 /* deliver packet to rx */
111 taddr.sin_family = AF_INET; /* compute source address */
112 taddr.sin_port = tu->uh_sport;
113 taddr.sin_addr.s_addr = ti->ip_src.s_addr;
114 taddr.sin_len = sizeof(taddr);
115 tvu = (struct udpiphdr *)ti; /* virtual udp structure, for cksum */
116 /* handle the checksum. Note that this code damages the actual ip
117 * header (replacing it with the virtual one, which is the same size),
118 * so we must ensure we get everything out we need, first */
119 if (tu->uh_sum != 0) {
120 /* if the checksum is there, always check it. It's crazy not
121 * to, unless you can really be sure that your
122 * underlying network (and interfaces and drivers and
123 * DMA hardware, etc!) is error-free. First, fill
124 * in entire virtual ip header. */
125 tvu->ui_i.fill[0] = 0;
126 tvu->ui_i.fill[1] = 0;
128 tvu->ui_len = tvu->ui_ulen;
129 tlen = ntohs((unsigned short)(tvu->ui_ulen));
130 if (in_cksum(am, sizeof(struct ip) + tlen)) {
131 /* checksum, including cksum field, doesn't come out 0, so
132 * this packet is bad */
140 * 28 is IP (20) + UDP (8) header. ulen includes
141 * udp header, and we *don't* tell RX about udp
142 * header either. So, we remove those 8 as well.
144 data_len = ntohs(tu->uh_ulen);
147 if (!(*rxk_GetPacketProc) (&phandle, data_len)) {
148 if (rx_mb_to_packet(am, m_freem, 28, data_len, phandle)) {
149 /* XXX should just increment counter here.. */
150 printf("rx: truncated UDP packet\n");
151 rxi_FreePacket(phandle);
153 (*rxk_PacketArrivalProc) (phandle, &taddr,
154 rxk_portRocks[i], data_len);
164 /* if we get here, try to deliver packet to udp */
165 if (tproc = parent_proto.pr_input)
166 (*tproc) (am, iphlen);
173 * UDP fast timer to raise events for all but Solaris and NCR.
174 * Called about 5 times per second (at unknown priority?). Must go to
175 * splnet or obtain global lock before touching anything significant.
183 /* do rx fasttimo processing here */
184 rxevent_RaiseEvents(&temp);
185 if (tproc = parent_proto.pr_fasttimo)
190 /* rx_NetSend - send asize bytes at adata from asocket to host at addr.
192 * Now, why do we allocate a new buffer when we could theoretically use the one
193 * pointed to by adata? Because PRU_SEND returns after queueing the message,
194 * not after sending it. If the sender changes the data after queueing it,
195 * we'd see the already-queued data change. One attempt to fix this without
196 * adding a copy would be to have this function wait until the datagram is
197 * sent; however this doesn't work well. In particular, if a host is down, and
198 * an ARP fails to that host, this packet will be queued until the ARP request
199 * comes back, which could be hours later. We can't block in this routine that
200 * long, since it prevents RPC timeouts from happening.
202 /* XXX In the brave new world, steal the data bufs out of the rx_packet iovec,
203 * and just queue those. XXX
206 /* set lock on sockbuf sb; can't call sblock since we're at interrupt level
210 register struct sockbuf *sb;
212 AFS_STATCNT(trysblock);
213 if (sb->sb_flags & SB_LOCK) {
214 return -1; /* can't lock socket */
216 sb->sb_flags |= SB_LOCK;
221 osi_NetSend(osi_socket asocket, struct sockaddr_in *addr, struct iovec *dvec,
222 int nvec, afs_int32 asize, int istack)
224 register struct mbuf *tm, *um;
225 register afs_int32 code;
227 struct mbuf *top = 0;
228 register struct mbuf *m, **mp;
236 AFS_STATCNT(osi_NetSend);
238 /* Actually, the Ultrix way is as good as any for us, so we don't bother with
239 * special mbufs any more. Used to think we could get away with not copying
240 * the data to the interface, but there's no way to tell the caller not to
241 * reuse the buffers after sending, so we lost out on that trick anyway */
246 tdata = dvec[i].iov_base;
247 tl = dvec[i].iov_len;
251 MGETHDR(m, M_DONTWAIT, MT_DATA);
258 m->m_pkthdr.rcvif = NULL;
260 MGET(m, M_DONTWAIT, MT_DATA);
262 /* can't get an mbuf, give up */
264 m_freem(top); /* free mbuf list we're building */
269 * WARNING: the `4 * MLEN' is somewhat dubious. It is better than
270 * `NBPG', which may have no relation to `CLBYTES'. Also, `CLBYTES'
271 * may be so large that we never use clusters, resulting in far
272 * too many mbufs being used. It is often better to briefly use
273 * a cluster, even if we are only using a portion of it. Since
274 * we are on the xmit side, it shouldn't end up sitting on a queue
275 * for a potentially unbounded time (except perhaps if we are talking
278 if (asize >= 4 * MLEN) { /* try to get cluster mbuf */
279 register struct mbuf *p;
281 /* different algorithms for getting cluster mbuf */
282 MCLGET(m, M_DONTWAIT);
283 if ((m->m_flags & M_EXT) == 0)
287 /* now compute usable size */
288 len = MIN(mlen, asize);
289 /* Should I look at MAPPED_MBUFS??? */
292 len = MIN(mlen, asize);
296 top->m_pkthdr.len += len;
297 tpa = mtod(m, caddr_t);
300 memcpy(tpa, tdata, rlen);
310 /* shouldn't come here! */
311 asize = 0; /* so we make progress toward completion */
314 tdata = dvec[i].iov_base;
315 tl = dvec[i].iov_len;
327 /* setup mbuf corresponding to destination address */
328 um = m_get(M_DONTWAIT, MT_SONAME);
331 m_freem(top); /* free mbuf chain */
332 /* if this were vfs40, we'd do sbunlock(asocket, &asocket->so_snd), but
333 * we don't do the locking at all for vfs40 systems */
337 memcpy(mtod(um, caddr_t), addr, sizeof(*addr));
338 um->m_len = sizeof(*addr);
339 /* note that udp_usrreq frees funny mbuf. We hold onto data, but mbuf
340 * around it is gone. we free address ourselves. */
341 haveGlock = ISAFS_GLOCK();
345 SOCKET_LOCK(asocket);
346 code = (*asocket->so_proto->pr_usrreq) (asocket, PRU_SEND, tm, um, 0);
347 SOCKET_UNLOCK(asocket);
357 #endif /* AFS_DUX40_ENV */