Annotation of src/sys/netinet/udp_usrreq.c, Revision 1.3
1.1 cgd 1: /*
2: * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. All advertising materials mentioning features or use of this software
14: * must display the following acknowledgement:
15: * This product includes software developed by the University of
16: * California, Berkeley and its contributors.
17: * 4. Neither the name of the University nor the names of its contributors
18: * may be used to endorse or promote products derived from this software
19: * without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31: * SUCH DAMAGE.
32: *
1.2 cgd 33: * from: @(#)udp_usrreq.c 7.20 (Berkeley) 4/20/91
1.3 ! cgd 34: * $Id: udp_usrreq.c,v 1.2 1993/05/18 18:20:23 cgd Exp $
1.1 cgd 35: */
36:
37: #include "param.h"
38: #include "malloc.h"
39: #include "mbuf.h"
40: #include "protosw.h"
41: #include "socket.h"
42: #include "socketvar.h"
43: #include "stat.h"
44:
45: #include "../net/if.h"
46: #include "../net/route.h"
47:
48: #include "in.h"
49: #include "in_systm.h"
50: #include "ip.h"
51: #include "in_pcb.h"
52: #include "ip_var.h"
53: #include "ip_icmp.h"
54: #include "udp.h"
55: #include "udp_var.h"
56:
57: struct inpcb *udp_last_inpcb = &udb;
58:
59: /*
60: * UDP protocol implementation.
61: * Per RFC 768, August, 1980.
62: */
63: udp_init()
64: {
65:
66: udb.inp_next = udb.inp_prev = &udb;
67: }
68:
69: #ifndef COMPAT_42
70: int udpcksum = 1;
71: #else
72: int udpcksum = 0; /* XXX */
73: #endif
74: int udp_ttl = UDP_TTL;
75:
76: struct sockaddr_in udp_in = { sizeof(udp_in), AF_INET };
77:
78: udp_input(m, iphlen)
79: register struct mbuf *m;
80: int iphlen;
81: {
82: register struct ip *ip;
83: register struct udphdr *uh;
84: register struct inpcb *inp;
85: struct mbuf *opts = 0;
86: int len;
87: struct ip save_ip;
88:
89: udpstat.udps_ipackets++;
90:
91: /*
92: * Strip IP options, if any; should skip this,
93: * make available to user, and use on returned packets,
94: * but we don't yet have a way to check the checksum
95: * with options still present.
96: */
97: if (iphlen > sizeof (struct ip)) {
98: ip_stripoptions(m, (struct mbuf *)0);
99: iphlen = sizeof(struct ip);
100: }
101:
102: /*
103: * Get IP and UDP header together in first mbuf.
104: */
105: ip = mtod(m, struct ip *);
106: if (m->m_len < iphlen + sizeof(struct udphdr)) {
107: if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) {
108: udpstat.udps_hdrops++;
109: return;
110: }
111: ip = mtod(m, struct ip *);
112: }
113: uh = (struct udphdr *)((caddr_t)ip + iphlen);
114:
115: /*
116: * Make mbuf data length reflect UDP length.
117: * If not enough data to reflect UDP length, drop.
118: */
119: len = ntohs((u_short)uh->uh_ulen);
120: if (ip->ip_len != len) {
121: if (len > ip->ip_len) {
122: udpstat.udps_badlen++;
123: goto bad;
124: }
125: m_adj(m, len - ip->ip_len);
126: /* ip->ip_len = len; */
127: }
128: /*
129: * Save a copy of the IP header in case we want restore it
130: * for sending an ICMP error message in response.
131: */
132: save_ip = *ip;
133:
134: /*
135: * Checksum extended UDP header and data.
136: */
137: if (udpcksum && uh->uh_sum) {
138: ((struct ipovly *)ip)->ih_next = 0;
139: ((struct ipovly *)ip)->ih_prev = 0;
140: ((struct ipovly *)ip)->ih_x1 = 0;
141: ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
142: if (uh->uh_sum = in_cksum(m, len + sizeof (struct ip))) {
143: udpstat.udps_badsum++;
144: m_freem(m);
145: return;
146: }
147: }
148:
149: /*
150: * Locate pcb for datagram.
151: */
152: inp = udp_last_inpcb;
153: if (inp->inp_lport != uh->uh_dport ||
154: inp->inp_fport != uh->uh_sport ||
155: inp->inp_faddr.s_addr != ip->ip_src.s_addr ||
156: inp->inp_laddr.s_addr != ip->ip_dst.s_addr) {
157: inp = in_pcblookup(&udb, ip->ip_src, uh->uh_sport,
158: ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD);
159: if (inp)
160: udp_last_inpcb = inp;
161: udpstat.udpps_pcbcachemiss++;
162: }
163: if (inp == 0) {
164: /* don't send ICMP response for broadcast packet */
165: udpstat.udps_noport++;
166: if (m->m_flags & M_BCAST) {
167: udpstat.udps_noportbcast++;
168: goto bad;
169: }
170: *ip = save_ip;
171: ip->ip_len += iphlen;
172: icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT);
173: return;
174: }
175:
176: /*
177: * Construct sockaddr format source address.
178: * Stuff source address and datagram in user buffer.
179: */
180: udp_in.sin_port = uh->uh_sport;
181: udp_in.sin_addr = ip->ip_src;
182: if (inp->inp_flags & INP_CONTROLOPTS) {
183: struct mbuf **mp = &opts;
184: struct mbuf *udp_saveopt();
185:
186: if (inp->inp_flags & INP_RECVDSTADDR) {
187: *mp = udp_saveopt((caddr_t) &ip->ip_dst,
188: sizeof(struct in_addr), IP_RECVDSTADDR);
189: if (*mp)
190: mp = &(*mp)->m_next;
191: }
192: #ifdef notyet
193: /* options were tossed above */
194: if (inp->inp_flags & INP_RECVOPTS) {
195: *mp = udp_saveopt((caddr_t) opts_deleted_above,
196: sizeof(struct in_addr), IP_RECVOPTS);
197: if (*mp)
198: mp = &(*mp)->m_next;
199: }
200: /* ip_srcroute doesn't do what we want here, need to fix */
201: if (inp->inp_flags & INP_RECVRETOPTS) {
202: *mp = udp_saveopt((caddr_t) ip_srcroute(),
203: sizeof(struct in_addr), IP_RECVRETOPTS);
204: if (*mp)
205: mp = &(*mp)->m_next;
206: }
207: #endif
208: }
209: iphlen += sizeof(struct udphdr);
210: m->m_len -= iphlen;
211: m->m_pkthdr.len -= iphlen;
212: m->m_data += iphlen;
213: if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in,
214: m, opts) == 0) {
215: udpstat.udps_fullsock++;
216: goto bad;
217: }
218: sorwakeup(inp->inp_socket);
219: return;
220: bad:
221: m_freem(m);
222: if (opts)
223: m_freem(opts);
224: }
225:
226: /*
227: * Create a "control" mbuf containing the specified data
228: * with the specified type for presentation with a datagram.
229: */
230: struct mbuf *
231: udp_saveopt(p, size, type)
232: caddr_t p;
233: register int size;
234: int type;
235: {
236: register struct cmsghdr *cp;
237: struct mbuf *m;
238:
239: if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL)
240: return ((struct mbuf *) NULL);
241: cp = (struct cmsghdr *) mtod(m, struct cmsghdr *);
242: bcopy(p, (caddr_t)(cp + 1), size);
243: size += sizeof(*cp);
244: m->m_len = size;
245: cp->cmsg_len = size;
246: cp->cmsg_level = IPPROTO_IP;
247: cp->cmsg_type = type;
248: return (m);
249: }
250:
251: /*
252: * Notify a udp user of an asynchronous error;
253: * just wake up so that he can collect error status.
254: */
255: udp_notify(inp, errno)
256: register struct inpcb *inp;
257: {
258:
259: inp->inp_socket->so_error = errno;
260: sorwakeup(inp->inp_socket);
261: sowwakeup(inp->inp_socket);
262: }
263:
264: udp_ctlinput(cmd, sa, ip)
265: int cmd;
266: struct sockaddr *sa;
267: register struct ip *ip;
268: {
269: register struct udphdr *uh;
270: extern struct in_addr zeroin_addr;
271: extern u_char inetctlerrmap[];
272:
273: if ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0)
274: return;
275: if (ip) {
276: uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
277: in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport,
278: cmd, udp_notify);
279: } else
280: in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify);
281: }
282:
283: udp_output(inp, m, addr, control)
284: register struct inpcb *inp;
285: register struct mbuf *m;
286: struct mbuf *addr, *control;
287: {
288: register struct udpiphdr *ui;
289: register int len = m->m_pkthdr.len;
290: struct in_addr laddr;
291: int s, error = 0;
292:
293: if (control)
294: m_freem(control); /* XXX */
295:
296: if (addr) {
297: laddr = inp->inp_laddr;
298: if (inp->inp_faddr.s_addr != INADDR_ANY) {
299: error = EISCONN;
300: goto release;
301: }
302: /*
303: * Must block input while temporarily connected.
304: */
305: s = splnet();
306: error = in_pcbconnect(inp, addr);
307: if (error) {
308: splx(s);
309: goto release;
310: }
311: } else {
312: if (inp->inp_faddr.s_addr == INADDR_ANY) {
313: error = ENOTCONN;
314: goto release;
315: }
316: }
317: /*
318: * Calculate data length and get a mbuf
319: * for UDP and IP headers.
320: */
321: M_PREPEND(m, sizeof(struct udpiphdr), M_WAIT);
322:
323: /*
324: * Fill in mbuf with extended UDP header
325: * and addresses and length put into network format.
326: */
327: ui = mtod(m, struct udpiphdr *);
328: ui->ui_next = ui->ui_prev = 0;
329: ui->ui_x1 = 0;
330: ui->ui_pr = IPPROTO_UDP;
331: ui->ui_len = htons((u_short)len + sizeof (struct udphdr));
332: ui->ui_src = inp->inp_laddr;
333: ui->ui_dst = inp->inp_faddr;
334: ui->ui_sport = inp->inp_lport;
335: ui->ui_dport = inp->inp_fport;
336: ui->ui_ulen = ui->ui_len;
337:
338: /*
339: * Stuff checksum and output datagram.
340: */
341: ui->ui_sum = 0;
342: if (udpcksum) {
343: if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
344: ui->ui_sum = 0xffff;
345: }
346: ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
347: ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl; /* XXX */
348: ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */
349: udpstat.udps_opackets++;
350: error = ip_output(m, inp->inp_options, &inp->inp_route,
351: inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST));
352:
353: if (addr) {
354: in_pcbdisconnect(inp);
355: inp->inp_laddr = laddr;
356: splx(s);
357: }
358: return (error);
359:
360: release:
361: m_freem(m);
362: return (error);
363: }
364:
365: u_long udp_sendspace = 9216; /* really max datagram size */
366: u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
367: /* 40 1K datagrams */
368:
369: /*ARGSUSED*/
370: udp_usrreq(so, req, m, addr, control)
371: struct socket *so;
372: int req;
373: struct mbuf *m, *addr, *control;
374: {
375: struct inpcb *inp = sotoinpcb(so);
376: int error = 0;
377: int s;
378:
379: if (req == PRU_CONTROL)
380: return (in_control(so, (int)m, (caddr_t)addr,
381: (struct ifnet *)control));
382: if (inp == NULL && req != PRU_ATTACH) {
383: error = EINVAL;
384: goto release;
385: }
386: /*
387: * Note: need to block udp_input while changing
388: * the udp pcb queue and/or pcb addresses.
389: */
390: switch (req) {
391:
392: case PRU_ATTACH:
393: if (inp != NULL) {
394: error = EINVAL;
395: break;
396: }
397: s = splnet();
398: error = in_pcballoc(so, &udb);
399: splx(s);
400: if (error)
401: break;
402: error = soreserve(so, udp_sendspace, udp_recvspace);
403: if (error)
404: break;
405: ((struct inpcb *) so->so_pcb)->inp_ip.ip_ttl = udp_ttl;
406: break;
407:
408: case PRU_DETACH:
409: udp_detach(inp);
410: break;
411:
412: case PRU_BIND:
413: s = splnet();
414: error = in_pcbbind(inp, addr);
415: splx(s);
416: break;
417:
418: case PRU_LISTEN:
419: error = EOPNOTSUPP;
420: break;
421:
422: case PRU_CONNECT:
423: if (inp->inp_faddr.s_addr != INADDR_ANY) {
424: error = EISCONN;
425: break;
426: }
427: s = splnet();
428: error = in_pcbconnect(inp, addr);
429: splx(s);
430: if (error == 0)
431: soisconnected(so);
432: break;
433:
434: case PRU_CONNECT2:
435: error = EOPNOTSUPP;
436: break;
437:
438: case PRU_ACCEPT:
439: error = EOPNOTSUPP;
440: break;
441:
442: case PRU_DISCONNECT:
443: if (inp->inp_faddr.s_addr == INADDR_ANY) {
444: error = ENOTCONN;
445: break;
446: }
447: s = splnet();
448: in_pcbdisconnect(inp);
449: inp->inp_laddr.s_addr = INADDR_ANY;
450: splx(s);
451: so->so_state &= ~SS_ISCONNECTED; /* XXX */
452: break;
453:
454: case PRU_SHUTDOWN:
455: socantsendmore(so);
456: break;
457:
458: case PRU_SEND:
459: return (udp_output(inp, m, addr, control));
460:
461: case PRU_ABORT:
462: soisdisconnected(so);
463: udp_detach(inp);
464: break;
465:
466: case PRU_SOCKADDR:
467: in_setsockaddr(inp, addr);
468: break;
469:
470: case PRU_PEERADDR:
471: in_setpeeraddr(inp, addr);
472: break;
473:
474: case PRU_SENSE:
475: /*
476: * stat: don't bother with a blocksize.
477: */
478: return (0);
479:
480: case PRU_SENDOOB:
481: case PRU_FASTTIMO:
482: case PRU_SLOWTIMO:
483: case PRU_PROTORCV:
484: case PRU_PROTOSEND:
485: error = EOPNOTSUPP;
486: break;
487:
488: case PRU_RCVD:
489: case PRU_RCVOOB:
490: return (EOPNOTSUPP); /* do not free mbuf's */
491:
492: default:
493: panic("udp_usrreq");
494: }
495:
496: release:
497: if (control) {
498: printf("udp control data unexpectedly retained\n");
499: m_freem(control);
500: }
501: if (m)
502: m_freem(m);
503: return (error);
504: }
505:
506: udp_detach(inp)
507: struct inpcb *inp;
508: {
509: int s = splnet();
510:
511: if (inp == udp_last_inpcb)
512: udp_last_inpcb = &udb;
513: in_pcbdetach(inp);
514: splx(s);
515: }
CVSweb <webmaster@jp.NetBSD.org>