Annotation of src/sys/netinet/udp_usrreq.c, Revision 1.57
1.57 ! itojun 1: /* $NetBSD: udp_usrreq.c,v 1.56 2000/01/06 15:46:08 itojun Exp $ */
1.48 itojun 2:
3: /*
4: * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. Neither the name of the project nor the names of its contributors
16: * may be used to endorse or promote products derived from this software
17: * without specific prior written permission.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22: * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29: * SUCH DAMAGE.
30: */
1.14 cgd 31:
1.1 cgd 32: /*
1.44 thorpej 33: * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995
1.13 mycroft 34: * The Regents of the University of California. All rights reserved.
1.1 cgd 35: *
36: * Redistribution and use in source and binary forms, with or without
37: * modification, are permitted provided that the following conditions
38: * are met:
39: * 1. Redistributions of source code must retain the above copyright
40: * notice, this list of conditions and the following disclaimer.
41: * 2. Redistributions in binary form must reproduce the above copyright
42: * notice, this list of conditions and the following disclaimer in the
43: * documentation and/or other materials provided with the distribution.
44: * 3. All advertising materials mentioning features or use of this software
45: * must display the following acknowledgement:
46: * This product includes software developed by the University of
47: * California, Berkeley and its contributors.
48: * 4. Neither the name of the University nor the names of its contributors
49: * may be used to endorse or promote products derived from this software
50: * without specific prior written permission.
51: *
52: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62: * SUCH DAMAGE.
63: *
1.44 thorpej 64: * @(#)udp_usrreq.c 8.6 (Berkeley) 5/23/95
1.1 cgd 65: */
1.50 thorpej 66:
67: #include "opt_ipsec.h"
68:
1.38 ws 69: #include "ipkdb.h"
1.1 cgd 70:
1.5 mycroft 71: #include <sys/param.h>
72: #include <sys/malloc.h>
73: #include <sys/mbuf.h>
74: #include <sys/protosw.h>
75: #include <sys/socket.h>
76: #include <sys/socketvar.h>
1.13 mycroft 77: #include <sys/errno.h>
1.5 mycroft 78: #include <sys/stat.h>
1.27 christos 79: #include <sys/systm.h>
80: #include <sys/proc.h>
1.53 itojun 81: #include <sys/domain.h>
1.27 christos 82:
83: #include <vm/vm.h>
84: #include <sys/sysctl.h>
1.1 cgd 85:
1.5 mycroft 86: #include <net/if.h>
87: #include <net/route.h>
1.1 cgd 88:
1.5 mycroft 89: #include <netinet/in.h>
90: #include <netinet/in_systm.h>
1.15 cgd 91: #include <netinet/in_var.h>
1.5 mycroft 92: #include <netinet/ip.h>
93: #include <netinet/in_pcb.h>
94: #include <netinet/ip_var.h>
95: #include <netinet/ip_icmp.h>
96: #include <netinet/udp.h>
97: #include <netinet/udp_var.h>
1.1 cgd 98:
1.53 itojun 99: #ifdef INET6
100: #include <netinet/ip6.h>
101: #include <netinet/icmp6.h>
102: #include <netinet6/ip6_var.h>
103: #include <netinet6/in6_pcb.h>
104: #include <netinet6/udp6_var.h>
105: #endif
106:
107: #ifdef PULLDOWN_TEST
108: #ifndef INET6
109: /* always need ip6.h for IP6_EXTHDR_GET */
110: #include <netinet/ip6.h>
111: #endif
112: #endif
113:
1.27 christos 114: #include <machine/stdarg.h>
115:
1.48 itojun 116: #ifdef IPSEC
117: #include <netinet6/ipsec.h>
118: #include <netkey/key.h>
119: #include <netkey/key_debug.h>
120: #endif /*IPSEC*/
121:
1.8 mycroft 122: /*
123: * UDP protocol implementation.
124: * Per RFC 768, August, 1980.
125: */
126: #ifndef COMPAT_42
127: int udpcksum = 1;
128: #else
129: int udpcksum = 0; /* XXX */
130: #endif
131:
1.53 itojun 132: static void udp4_sendup __P((struct mbuf *, int, struct sockaddr *,
133: struct socket *));
134: static int udp4_realinput __P((struct sockaddr_in *, struct sockaddr_in *,
135: struct mbuf *, int));
136: #ifdef INET6
137: static void udp6_sendup __P((struct mbuf *, int, struct sockaddr *,
138: struct socket *));
139: static int in6_mcmatch __P((struct in6pcb *, struct in6_addr *,
140: struct ifnet *));
141: static int udp6_realinput __P((int, struct sockaddr_in6 *,
142: struct sockaddr_in6 *, struct mbuf *, int));
143: #endif
1.13 mycroft 144: static void udp_notify __P((struct inpcb *, int));
1.7 mycroft 145:
1.26 mycroft 146: #ifndef UDBHASHSIZE
147: #define UDBHASHSIZE 128
148: #endif
149: int udbhashsize = UDBHASHSIZE;
150:
1.7 mycroft 151: void
1.1 cgd 152: udp_init()
153: {
1.18 mycroft 154:
1.35 mycroft 155: in_pcbinit(&udbtable, udbhashsize, udbhashsize);
1.1 cgd 156: }
157:
1.56 itojun 158: #ifndef UDP6
1.7 mycroft 159: void
1.27 christos 160: #if __STDC__
161: udp_input(struct mbuf *m, ...)
162: #else
163: udp_input(m, va_alist)
164: struct mbuf *m;
165: va_dcl
166: #endif
1.1 cgd 167: {
1.53 itojun 168: va_list ap;
169: struct sockaddr_in src, dst;
170: struct ip *ip;
171: struct udphdr *uh;
172: int iphlen, proto;
173: int len;
174: int n;
175:
176: va_start(ap, m);
177: iphlen = va_arg(ap, int);
178: proto = va_arg(ap, int);
179: va_end(ap);
180:
181: udpstat.udps_ipackets++;
182:
183: #ifndef PULLDOWN_TEST
184: /*
185: * Strip IP options, if any; should skip this,
186: * make available to user, and use on returned packets,
187: * but we don't yet have a way to check the checksum
188: * with options still present.
189: */
190: if (iphlen > sizeof (struct ip)) {
191: ip_stripoptions(m, (struct mbuf *)0);
192: iphlen = sizeof(struct ip);
193: }
194: #else
195: /*
196: * we may enable the above code if we save and pass IPv4 options
197: * to the userland.
198: */
199: #endif
200:
201: /*
202: * Get IP and UDP header together in first mbuf.
203: */
204: ip = mtod(m, struct ip *);
205: #ifndef PULLDOWN_TEST
206: if (m->m_len < iphlen + sizeof(struct udphdr)) {
207: if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) {
208: udpstat.udps_hdrops++;
209: return;
210: }
211: ip = mtod(m, struct ip *);
212: }
213: uh = (struct udphdr *)((caddr_t)ip + iphlen);
214: #else
215: IP6_EXTHDR_GET(uh, struct udphdr *, m, iphlen, sizeof(struct udphdr));
216: if (uh == NULL) {
217: udpstat.udps_hdrops++;
218: return;
219: }
220: #endif
221:
1.57 ! itojun 222: /* destination port of 0 is illegal, based on RFC768. */
! 223: if (uh->uh_dport == 0)
! 224: goto bad;
! 225:
1.53 itojun 226: /*
227: * Make mbuf data length reflect UDP length.
228: * If not enough data to reflect UDP length, drop.
229: */
230: len = ntohs((u_int16_t)uh->uh_ulen);
231: if (ip->ip_len != iphlen + len) {
232: if (ip->ip_len < iphlen + len) {
233: udpstat.udps_badlen++;
234: goto bad;
235: }
236: m_adj(m, iphlen + len - ip->ip_len);
237: }
238:
239: /*
240: * Checksum extended UDP header and data.
241: */
242: if (uh->uh_sum) {
243: #ifndef PULLDOWN_TEST
244: struct ip save_ip;
245:
246: /*
247: * Save a copy of the IP header in case we want restore it
248: * for sending an ICMP error message in response.
249: */
250: save_ip = *ip;
251:
252: bzero(((struct ipovly *)ip)->ih_x1,
253: sizeof ((struct ipovly *)ip)->ih_x1);
254: ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
255: if (in_cksum(m, len + sizeof (struct ip)) != 0) {
256: udpstat.udps_badsum++;
257: m_freem(m);
258: return;
259: }
260:
261: *ip = save_ip;
262: #else
263: if (in4_cksum(m, IPPROTO_UDP, iphlen, len) != 0) {
264: udpstat.udps_badsum++;
265: m_freem(m);
266: return;
267: }
268: #endif
269: }
270:
271: /* construct source and dst sockaddrs. */
272: bzero(&src, sizeof(src));
273: src.sin_family = AF_INET;
274: src.sin_len = sizeof(struct sockaddr_in);
275: bcopy(&ip->ip_src, &src.sin_addr, sizeof(src.sin_addr));
276: src.sin_port = uh->uh_sport;
277: bzero(&dst, sizeof(dst));
278: dst.sin_family = AF_INET;
279: dst.sin_len = sizeof(struct sockaddr_in);
280: bcopy(&ip->ip_dst, &dst.sin_addr, sizeof(dst.sin_addr));
281: dst.sin_port = uh->uh_dport;
282:
283: n = udp4_realinput(&src, &dst, m, iphlen);
284: #ifdef INET6
285: if (IN_MULTICAST(ip->ip_dst.s_addr) || n == 0) {
286: struct sockaddr_in6 src6, dst6;
287:
288: bzero(&src6, sizeof(src6));
289: src6.sin6_family = AF_INET6;
290: src6.sin6_len = sizeof(struct sockaddr_in6);
291: src6.sin6_addr.s6_addr[10] = src6.sin6_addr.s6_addr[11] = 0xff;
292: bcopy(&ip->ip_src, &src6.sin6_addr.s6_addr[12],
293: sizeof(ip->ip_src));
294: src6.sin6_port = uh->uh_sport;
295: bzero(&dst6, sizeof(dst6));
296: dst6.sin6_family = AF_INET6;
297: dst6.sin6_len = sizeof(struct sockaddr_in6);
298: dst6.sin6_addr.s6_addr[10] = dst6.sin6_addr.s6_addr[11] = 0xff;
299: bcopy(&ip->ip_dst, &dst6.sin6_addr.s6_addr[12],
300: sizeof(ip->ip_dst));
301: dst6.sin6_port = uh->uh_dport;
302:
303: n += udp6_realinput(AF_INET, &src6, &dst6, m, iphlen);
304: }
305: #endif
306:
307: if (n == 0) {
308: udpstat.udps_noport++;
309: if (m->m_flags & (M_BCAST | M_MCAST)) {
310: udpstat.udps_noportbcast++;
311: goto bad;
312: }
313: #if NIPKDB > 0
314: if (checkipkdb(&ip->ip_src, uh->uh_sport, uh->uh_dport,
315: m, iphlen + sizeof(struct udphdr),
316: m->m_pkthdr.len - iphlen - sizeof(struct udphdr))) {
317: /*
318: * It was a debugger connect packet,
319: * just drop it now
320: */
321: goto bad;
322: }
323: #endif
324: icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0);
325: m = NULL;
326: }
327:
328: bad:
329: if (m)
330: m_freem(m);
331: }
332:
333: #ifdef INET6
334: int
335: udp6_input(mp, offp, proto)
336: struct mbuf **mp;
337: int *offp, proto;
338: {
339: struct mbuf *m = *mp;
340: int off = *offp;
341: struct sockaddr_in6 src, dst;
342: struct ip6_hdr *ip6;
343: struct udphdr *uh;
344: u_int32_t plen, ulen;
345:
346: #if defined(NFAITH) && 0 < NFAITH
347: if (m->m_pkthdr.rcvif) {
348: if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
349: /* send icmp6 host unreach? */
350: m_freem(m);
351: return IPPROTO_DONE;
352: }
353: }
354: #endif
355:
356: udp6stat.udp6s_ipackets++;
357:
358: #ifndef PULLDOWN_TEST
359: IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE);
360: #endif
361:
362: ip6 = mtod(m, struct ip6_hdr *);
363: /* check for jumbogram is done in ip6_input. we can trust pkthdr.len */
364: plen = m->m_pkthdr.len - off;
365: #ifndef PULLDOWN_TEST
366: uh = (struct udphdr *)((caddr_t)ip6 + off);
367: #else
368: IP6_EXTHDR_GET(uh, struct udphdr *, m, off, sizeof(struct udphdr));
369: if (uh == NULL) {
370: ip6stat.ip6s_tooshort++;
371: return IPPROTO_DONE;
372: }
373: #endif
374: ulen = ntohs((u_short)uh->uh_ulen);
375: if (ulen == 0 && plen > 0xffff)
376: ulen = plen;
377:
378: if (plen != ulen) {
379: udp6stat.udp6s_badlen++;
1.54 itojun 380: goto bad;
381: }
382:
1.57 ! itojun 383: /* destination port of 0 is illegal, based on RFC768. */
! 384: if (uh->uh_dport == 0)
! 385: goto bad;
! 386:
1.54 itojun 387: /* Be proactive about malicious use of IPv4 mapped address */
388: if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
389: IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) {
390: /* XXX stat */
1.53 itojun 391: goto bad;
392: }
393:
394: /*
395: * Checksum extended UDP header and data.
396: */
397: if (uh->uh_sum == 0)
398: udp6stat.udp6s_nosum++;
399: else if (in6_cksum(m, IPPROTO_UDP, off, ulen) != 0) {
400: udp6stat.udp6s_badsum++;
401: goto bad;
402: }
403:
404: /*
405: * Construct source and dst sockaddrs.
406: * Note that ifindex (s6_addr16[1]) is already filled.
407: */
408: bzero(&src, sizeof(src));
409: src.sin6_family = AF_INET6;
410: src.sin6_len = sizeof(struct sockaddr_in6);
411: bcopy(&ip6->ip6_src, &src.sin6_addr, sizeof(src.sin6_addr));
412: if (IN6_IS_SCOPE_LINKLOCAL(&src.sin6_addr))
413: src.sin6_addr.s6_addr16[1] = 0;
414: if (m->m_pkthdr.rcvif) {
415: if (IN6_IS_SCOPE_LINKLOCAL(&src.sin6_addr))
416: src.sin6_scope_id = m->m_pkthdr.rcvif->if_index;
417: else
418: src.sin6_scope_id = 0;
419: }
420: src.sin6_port = uh->uh_sport;
421: bzero(&dst, sizeof(dst));
422: dst.sin6_family = AF_INET6;
423: dst.sin6_len = sizeof(struct sockaddr_in6);
424: bcopy(&ip6->ip6_dst, &dst.sin6_addr, sizeof(dst.sin6_addr));
425: if (IN6_IS_SCOPE_LINKLOCAL(&dst.sin6_addr))
426: dst.sin6_addr.s6_addr16[1] = 0;
427: if (m->m_pkthdr.rcvif) {
428: if (IN6_IS_SCOPE_LINKLOCAL(&dst.sin6_addr))
429: dst.sin6_scope_id = m->m_pkthdr.rcvif->if_index;
430: else
431: dst.sin6_scope_id = 0;
432: }
433: dst.sin6_port = uh->uh_dport;
434:
435: if (udp6_realinput(AF_INET6, &src, &dst, m, off) == 0) {
436: udp6stat.udp6s_noport++;
437: if (m->m_flags & M_MCAST) {
438: udp6stat.udp6s_noportmcast++;
439: goto bad;
440: }
441: icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0);
442: m = NULL;
443: }
444:
445: bad:
446: if (m)
447: m_freem(m);
448: return IPPROTO_DONE;
449: }
450: #endif
451:
452: static void
453: udp4_sendup(m, off, src, so)
454: struct mbuf *m;
455: int off; /* offset of data portion */
456: struct sockaddr *src;
457: struct socket *so;
458: {
459: struct mbuf *opts = NULL;
460: struct mbuf *n;
461: struct inpcb *inp = NULL;
462: #ifdef INET6
463: struct in6pcb *in6p = NULL;
464: #endif
465:
466: if (!so)
467: return;
468: switch (so->so_proto->pr_domain->dom_family) {
469: case AF_INET:
470: inp = sotoinpcb(so);
471: break;
472: #ifdef INET6
473: case AF_INET6:
474: in6p = sotoin6pcb(so);
475: break;
476: #endif
477: default:
478: return;
479: }
480:
481: #ifdef IPSEC
482: /* check AH/ESP integrity. */
483: if (so != NULL && ipsec4_in_reject_so(m, so)) {
484: ipsecstat.in_polvio++;
485: return;
486: }
487: #endif /*IPSEC*/
488:
489: if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
490: if (inp && (inp->inp_flags & INP_CONTROLOPTS
491: || so->so_options & SO_TIMESTAMP)) {
492: struct ip *ip = mtod(n, struct ip *);
493: ip_savecontrol(inp, &opts, ip, n);
494: }
495:
496: m_adj(n, off);
497: if (sbappendaddr(&so->so_rcv, src, n,
498: opts) == 0) {
499: m_freem(n);
500: if (opts)
501: m_freem(opts);
502: } else
503: sorwakeup(so);
504: }
505: }
506:
507: #ifdef INET6
508: static void
509: udp6_sendup(m, off, src, so)
510: struct mbuf *m;
511: int off; /* offset of data portion */
512: struct sockaddr *src;
513: struct socket *so;
514: {
515: struct mbuf *opts = NULL;
516: struct mbuf *n;
517: struct in6pcb *in6p = NULL;
518:
519: if (!so)
520: return;
521: if (so->so_proto->pr_domain->dom_family != AF_INET6)
522: return;
523: in6p = sotoin6pcb(so);
524:
525: #ifdef IPSEC
526: /* check AH/ESP integrity. */
527: if (so != NULL && ipsec6_in_reject_so(m, so)) {
528: ipsec6stat.in_polvio++;
529: return;
530: }
531: #endif /*IPSEC*/
532:
533: if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
534: if (in6p && (in6p->in6p_flags & IN6P_CONTROLOPTS
535: || in6p->in6p_socket->so_options & SO_TIMESTAMP)) {
536: struct ip6_hdr *ip6 = mtod(n, struct ip6_hdr *);
537: ip6_savecontrol(in6p, &opts, ip6, n);
538: }
539:
540: m_adj(n, off);
541: if (sbappendaddr(&so->so_rcv, src, n, opts) == 0) {
542: m_freem(n);
543: if (opts)
544: m_freem(opts);
545: udp6stat.udp6s_fullsock++;
546: } else
547: sorwakeup(so);
548: }
549: }
550: #endif
551:
552: static int
553: udp4_realinput(src, dst, m, off)
554: struct sockaddr_in *src;
555: struct sockaddr_in *dst;
556: struct mbuf *m;
557: int off; /* offset of udphdr */
558: {
559: u_int16_t *sport, *dport;
560: int rcvcnt;
561: struct in_addr *src4, *dst4;
562: struct inpcb *inp;
563:
564: rcvcnt = 0;
565: off += sizeof(struct udphdr); /* now, offset of payload */
566:
567: if (src->sin_family != AF_INET || dst->sin_family != AF_INET)
568: goto bad;
569:
570: src4 = &src->sin_addr;
571: sport = &src->sin_port;
572: dst4 = &dst->sin_addr;
573: dport = &dst->sin_port;
574:
575: if (IN_MULTICAST(src4->s_addr) ||
576: in_broadcast(*dst4, m->m_pkthdr.rcvif)) {
577: struct inpcb *last;
578: /*
579: * Deliver a multicast or broadcast datagram to *all* sockets
580: * for which the local and remote addresses and ports match
581: * those of the incoming datagram. This allows more than
582: * one process to receive multi/broadcasts on the same port.
583: * (This really ought to be done for unicast datagrams as
584: * well, but that would cause problems with existing
585: * applications that open both address-specific sockets and
586: * a wildcard socket listening to the same port -- they would
587: * end up receiving duplicates of every unicast datagram.
588: * Those applications open the multiple sockets to overcome an
589: * inadequacy of the UDP socket interface, but for backwards
590: * compatibility we avoid the problem here rather than
591: * fixing the interface. Maybe 4.5BSD will remedy this?)
592: */
593:
594: /*
595: * KAME note: usually we drop udpiphdr from mbuf here.
596: * we need udpiphdr for iPsec processing so we do that later.
597: */
598: /*
599: * Locate pcb(s) for datagram.
600: */
601: for (inp = udbtable.inpt_queue.cqh_first;
602: inp != (struct inpcb *)&udbtable.inpt_queue;
603: inp = inp->inp_queue.cqe_next) {
604: if (inp->inp_lport != *dport)
605: continue;
606: if (!in_nullhost(inp->inp_laddr)) {
607: if (!in_hosteq(inp->inp_laddr, *dst4))
608: continue;
609: }
610: if (!in_nullhost(inp->inp_faddr)) {
611: if (!in_hosteq(inp->inp_faddr, *src4) ||
612: inp->inp_fport != *sport)
613: continue;
614: }
615:
616: last = inp;
617: udp4_sendup(m, off, (struct sockaddr *)src,
618: inp->inp_socket);
619: rcvcnt++;
620:
621: /*
622: * Don't look for additional matches if this one does
623: * not have either the SO_REUSEPORT or SO_REUSEADDR
624: * socket options set. This heuristic avoids searching
625: * through all pcbs in the common case of a non-shared
626: * port. It assumes that an application will never
627: * clear these options after setting them.
628: */
629: if ((inp->inp_socket->so_options &
630: (SO_REUSEPORT|SO_REUSEADDR)) == 0)
631: break;
632: }
633:
634: #if 0
635: if (last == NULL) {
636: /*
637: * No matching pcb found; discard datagram.
638: * (No need to send an ICMP Port Unreachable
639: * for a broadcast or multicast datgram.)
640: */
641: udpstat.udps_noport++;
642: udpstat.udps_noportbcast++;
643: goto bad;
644: }
645: #endif
646: } else {
647: /*
648: * Locate pcb for datagram.
649: */
650: inp = in_pcblookup_connect(&udbtable, *src4, *sport, *dst4, *dport);
651: if (inp == 0) {
652: ++udpstat.udps_pcbhashmiss;
653: inp = in_pcblookup_bind(&udbtable, *dst4, *dport);
654: if (inp == 0) {
655: #if 0
656: struct mbuf *n;
657:
658: udpstat.udps_noport++;
659: if (m->m_flags & (M_BCAST | M_MCAST)) {
660: udpstat.udps_noportbcast++;
661: goto bad;
662: }
663: #if NIPKDB > 0
664: if (checkipkdb(src4, *sport, *dport, m, off,
665: m->m_pkthdr.len - off)) {
666: /*
667: * It was a debugger connect packet,
668: * just drop it now
669: */
670: goto bad;
671: }
672: #endif
673: if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
674: icmp_error(n, ICMP_UNREACH,
675: ICMP_UNREACH_PORT, 0, 0);
676: }
677: #endif
678: return rcvcnt;
679: }
680: }
681:
682: udp4_sendup(m, off, (struct sockaddr *)src, inp->inp_socket);
683: rcvcnt++;
684: }
685:
686: bad:
687: return rcvcnt;
688: }
689:
690: #ifdef INET6
691: static int
692: in6_mcmatch(in6p, ia6, ifp)
693: struct in6pcb *in6p;
694: register struct in6_addr *ia6;
695: struct ifnet *ifp;
696: {
697: struct ip6_moptions *im6o = in6p->in6p_moptions;
698: struct in6_multi_mship *imm;
699:
700: if (im6o == NULL)
701: return 0;
702:
703: for (imm = im6o->im6o_memberships.lh_first; imm != NULL;
704: imm = imm->i6mm_chain.le_next) {
705: if ((ifp == NULL ||
706: imm->i6mm_maddr->in6m_ifp == ifp) &&
707: IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr,
708: ia6))
709: return 1;
710: }
711: return 0;
712: }
713:
714: static int
715: udp6_realinput(af, src, dst, m, off)
716: int af; /* af on packet */
717: struct sockaddr_in6 *src;
718: struct sockaddr_in6 *dst;
719: struct mbuf *m;
720: int off; /* offset of udphdr */
721: {
722: u_int16_t *sport, *dport;
723: int rcvcnt;
724: struct in6_addr *src6, *dst6;
725: struct in_addr *src4;
726: struct in6pcb *in6p;
727:
728: rcvcnt = 0;
729: off += sizeof(struct udphdr); /* now, offset of payload */
730:
731: if (af != AF_INET && af != AF_INET6)
732: goto bad;
733: if (src->sin6_family != AF_INET6 || dst->sin6_family != AF_INET6)
734: goto bad;
735:
736: src6 = &src->sin6_addr;
737: sport = &src->sin6_port;
738: dst6 = &dst->sin6_addr;
739: dport = &dst->sin6_port;
740: src4 = (struct in_addr *)&src->sin6_addr.s6_addr32[12];
741:
742: if (IN6_IS_ADDR_MULTICAST(dst6)
743: || (af == AF_INET && IN_MULTICAST(src4->s_addr))) {
744: struct in6pcb *last;
745: /*
746: * Deliver a multicast or broadcast datagram to *all* sockets
747: * for which the local and remote addresses and ports match
748: * those of the incoming datagram. This allows more than
749: * one process to receive multi/broadcasts on the same port.
750: * (This really ought to be done for unicast datagrams as
751: * well, but that would cause problems with existing
752: * applications that open both address-specific sockets and
753: * a wildcard socket listening to the same port -- they would
754: * end up receiving duplicates of every unicast datagram.
755: * Those applications open the multiple sockets to overcome an
756: * inadequacy of the UDP socket interface, but for backwards
757: * compatibility we avoid the problem here rather than
758: * fixing the interface. Maybe 4.5BSD will remedy this?)
759: */
760:
761: /*
762: * KAME note: usually we drop udpiphdr from mbuf here.
763: * we need udpiphdr for iPsec processing so we do that later.
764: */
765: /*
766: * Locate pcb(s) for datagram.
767: */
768: for (in6p = udb6.in6p_next; in6p != &udb6;
769: in6p = in6p->in6p_next) {
770: if (in6p->in6p_lport != *dport)
771: continue;
772: if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) {
773: if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, dst6)
774: && !in6_mcmatch(in6p, dst6, m->m_pkthdr.rcvif))
775: continue;
776: }
1.55 itojun 777: #ifndef INET6_BINDV6ONLY
778: else {
779: if (IN6_IS_ADDR_V4MAPPED(dst6)
780: && (in6p->in6p_flags & IN6P_BINDV6ONLY))
781: continue;
782: }
783: #endif
1.53 itojun 784: if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
785: if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, src6)
786: || in6p->in6p_fport != *sport)
787: continue;
788: }
1.55 itojun 789: #ifndef INET6_BINDV6ONLY
790: else {
791: if (IN6_IS_ADDR_V4MAPPED(src6)
792: && (in6p->in6p_flags & IN6P_BINDV6ONLY))
793: continue;
794: }
795: #endif
1.53 itojun 796:
797: last = in6p;
798: udp6_sendup(m, off, (struct sockaddr *)src,
799: in6p->in6p_socket);
800: rcvcnt++;
801:
802: /*
803: * Don't look for additional matches if this one does
804: * not have either the SO_REUSEPORT or SO_REUSEADDR
805: * socket options set. This heuristic avoids searching
806: * through all pcbs in the common case of a non-shared
807: * port. It assumes that an application will never
808: * clear these options after setting them.
809: */
810: if ((in6p->in6p_socket->so_options &
811: (SO_REUSEPORT|SO_REUSEADDR)) == 0)
812: break;
813: }
814:
815: #if 0
816: if (last == NULL) {
817: /*
818: * No matching pcb found; discard datagram.
819: * (No need to send an ICMP Port Unreachable
820: * for a broadcast or multicast datgram.)
821: */
822: switch (af) {
823: case AF_INET:
824: udpstat.udps_noport++;
825: udpstat.udps_noportbcast++;
826: break;
827: case AF_INET6:
828: udp6stat.udp6s_noport++;
829: udp6stat.udp6s_noportmcast++;
830: break;
831: }
832: goto bad;
833: }
834: #endif
835: } else {
836: /*
837: * Locate pcb for datagram.
838: */
839: in6p = in6_pcblookup_connect(&udb6, src6, *sport,
840: dst6, *dport, 0);
841: if (in6p == 0) {
842: ++udpstat.udps_pcbhashmiss;
843: in6p = in6_pcblookup_bind(&udb6, dst6, *dport, 0);
844: if (in6p == 0) {
845: #if 0
846: struct mbuf *n;
847: n = m_copy(m, 0, M_COPYALL);
848: switch (af) {
849: case AF_INET:
850: udpstat.udps_noport++;
851: if (m->m_flags & (M_BCAST | M_MCAST)) {
852: udpstat.udps_noportbcast++;
853: goto bad;
854: }
855: if (n != NULL)
856: icmp_error(n, ICMP_UNREACH,
857: ICMP_UNREACH_PORT, 0, 0);
858: break;
859: case AF_INET6:
860: udp6stat.udp6s_noport++;
861: if (m->m_flags & M_MCAST) {
862: udp6stat.udp6s_noportmcast++;
863: goto bad;
864: }
865: if (n != NULL)
866: icmp6_error(n, ICMP6_DST_UNREACH,
867: ICMP6_DST_UNREACH_NOPORT, 0);
868: break;
869: }
870: #endif
871:
872: return rcvcnt;
873: }
874: }
875:
876: udp6_sendup(m, off, (struct sockaddr *)src, in6p->in6p_socket);
877: rcvcnt++;
878: }
879:
880: bad:
881: return rcvcnt;
882: }
883: #endif
884:
1.56 itojun 885: #else /*UDP6*/
886:
1.53 itojun 887: void
888: #if __STDC__
889: udp_input(struct mbuf *m, ...)
890: #else
891: udp_input(m, va_alist)
892: struct mbuf *m;
893: va_dcl
894: #endif
895: {
1.48 itojun 896: int proto;
1.1 cgd 897: register struct ip *ip;
898: register struct udphdr *uh;
899: register struct inpcb *inp;
900: struct mbuf *opts = 0;
901: int len;
902: struct ip save_ip;
1.27 christos 903: int iphlen;
904: va_list ap;
1.34 mycroft 905: struct sockaddr_in udpsrc;
1.48 itojun 906: struct sockaddr *sa;
1.27 christos 907:
908: va_start(ap, m);
909: iphlen = va_arg(ap, int);
1.48 itojun 910: proto = va_arg(ap, int);
1.27 christos 911: va_end(ap);
1.1 cgd 912:
913: udpstat.udps_ipackets++;
914:
915: /*
916: * Strip IP options, if any; should skip this,
917: * make available to user, and use on returned packets,
918: * but we don't yet have a way to check the checksum
919: * with options still present.
920: */
921: if (iphlen > sizeof (struct ip)) {
922: ip_stripoptions(m, (struct mbuf *)0);
923: iphlen = sizeof(struct ip);
924: }
925:
926: /*
927: * Get IP and UDP header together in first mbuf.
928: */
929: ip = mtod(m, struct ip *);
930: if (m->m_len < iphlen + sizeof(struct udphdr)) {
931: if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) {
932: udpstat.udps_hdrops++;
933: return;
934: }
935: ip = mtod(m, struct ip *);
936: }
937: uh = (struct udphdr *)((caddr_t)ip + iphlen);
1.57 ! itojun 938:
! 939: /* destination port of 0 is illegal, based on RFC768. */
! 940: if (uh->uh_dport == 0)
! 941: goto bad;
1.1 cgd 942:
943: /*
944: * Make mbuf data length reflect UDP length.
945: * If not enough data to reflect UDP length, drop.
946: */
1.15 cgd 947: len = ntohs((u_int16_t)uh->uh_ulen);
1.47 mycroft 948: if (ip->ip_len != iphlen + len) {
949: if (ip->ip_len < iphlen + len) {
1.1 cgd 950: udpstat.udps_badlen++;
951: goto bad;
952: }
1.47 mycroft 953: m_adj(m, iphlen + len - ip->ip_len);
1.1 cgd 954: }
955: /*
956: * Save a copy of the IP header in case we want restore it
957: * for sending an ICMP error message in response.
958: */
959: save_ip = *ip;
960:
961: /*
962: * Checksum extended UDP header and data.
963: */
1.29 mrg 964: if (uh->uh_sum) {
1.25 cgd 965: bzero(((struct ipovly *)ip)->ih_x1,
966: sizeof ((struct ipovly *)ip)->ih_x1);
1.1 cgd 967: ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
1.46 mycroft 968: if (in_cksum(m, len + sizeof (struct ip)) != 0) {
1.1 cgd 969: udpstat.udps_badsum++;
970: m_freem(m);
971: return;
972: }
973: }
1.13 mycroft 974:
1.48 itojun 975: /*
976: * Construct sockaddr format source address.
977: */
978: udpsrc.sin_family = AF_INET;
979: udpsrc.sin_len = sizeof(struct sockaddr_in);
980: udpsrc.sin_addr = ip->ip_src;
981: udpsrc.sin_port = uh->uh_sport;
982: bzero((caddr_t)udpsrc.sin_zero, sizeof(udpsrc.sin_zero));
983:
1.16 mycroft 984: if (IN_MULTICAST(ip->ip_dst.s_addr) ||
1.13 mycroft 985: in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) {
1.40 thorpej 986: struct inpcb *last;
1.4 hpeyerl 987: /*
988: * Deliver a multicast or broadcast datagram to *all* sockets
989: * for which the local and remote addresses and ports match
990: * those of the incoming datagram. This allows more than
991: * one process to receive multi/broadcasts on the same port.
992: * (This really ought to be done for unicast datagrams as
993: * well, but that would cause problems with existing
994: * applications that open both address-specific sockets and
995: * a wildcard socket listening to the same port -- they would
996: * end up receiving duplicates of every unicast datagram.
997: * Those applications open the multiple sockets to overcome an
998: * inadequacy of the UDP socket interface, but for backwards
999: * compatibility we avoid the problem here rather than
1.13 mycroft 1000: * fixing the interface. Maybe 4.5BSD will remedy this?)
1.4 hpeyerl 1001: */
1.13 mycroft 1002:
1.48 itojun 1003: iphlen += sizeof(struct udphdr);
1.4 hpeyerl 1004: /*
1.48 itojun 1005: * KAME note: usually we drop udpiphdr from mbuf here.
1006: * we need udpiphdr for iPsec processing so we do that later.
1.4 hpeyerl 1007: */
1008: /*
1009: * Locate pcb(s) for datagram.
1010: * (Algorithm copied from raw_intr().)
1011: */
1012: last = NULL;
1.22 cgd 1013: for (inp = udbtable.inpt_queue.cqh_first;
1014: inp != (struct inpcb *)&udbtable.inpt_queue;
1015: inp = inp->inp_queue.cqe_next) {
1.4 hpeyerl 1016: if (inp->inp_lport != uh->uh_dport)
1017: continue;
1.34 mycroft 1018: if (!in_nullhost(inp->inp_laddr)) {
1019: if (!in_hosteq(inp->inp_laddr, ip->ip_dst))
1.4 hpeyerl 1020: continue;
1021: }
1.34 mycroft 1022: if (!in_nullhost(inp->inp_faddr)) {
1023: if (!in_hosteq(inp->inp_faddr, ip->ip_src) ||
1.4 hpeyerl 1024: inp->inp_fport != uh->uh_sport)
1025: continue;
1026: }
1027:
1028: if (last != NULL) {
1029: struct mbuf *n;
1030:
1.48 itojun 1031: #ifdef IPSEC
1032: /* check AH/ESP integrity. */
1033: if (last != NULL && ipsec4_in_reject(m, last)) {
1034: ipsecstat.in_polvio++;
1035: /* do not inject data to pcb */
1036: } else
1037: #endif /*IPSEC*/
1.4 hpeyerl 1038: if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
1.40 thorpej 1039: if (last->inp_flags & INP_CONTROLOPTS
1040: || last->inp_socket->so_options &
1041: SO_TIMESTAMP) {
1042: ip_savecontrol(last, &opts,
1043: ip, n);
1044: }
1.49 drochner 1045: m_adj(n, iphlen);
1.48 itojun 1046: sa = (struct sockaddr *)&udpsrc;
1.40 thorpej 1047: if (sbappendaddr(
1048: &last->inp_socket->so_rcv,
1.48 itojun 1049: sa, n, opts) == 0) {
1.4 hpeyerl 1050: m_freem(n);
1.40 thorpej 1051: if (opts)
1052: m_freem(opts);
1.13 mycroft 1053: } else
1.40 thorpej 1054: sorwakeup(last->inp_socket);
1055: opts = 0;
1.4 hpeyerl 1056: }
1057: }
1.40 thorpej 1058: last = inp;
1.4 hpeyerl 1059: /*
1.13 mycroft 1060: * Don't look for additional matches if this one does
1061: * not have either the SO_REUSEPORT or SO_REUSEADDR
1062: * socket options set. This heuristic avoids searching
1063: * through all pcbs in the common case of a non-shared
1064: * port. It * assumes that an application will never
1065: * clear these options after setting them.
1.4 hpeyerl 1066: */
1.40 thorpej 1067: if ((last->inp_socket->so_options &
1068: (SO_REUSEPORT|SO_REUSEADDR)) == 0)
1.4 hpeyerl 1069: break;
1070: }
1.6 mycroft 1071:
1.4 hpeyerl 1072: if (last == NULL) {
1073: /*
1074: * No matching pcb found; discard datagram.
1075: * (No need to send an ICMP Port Unreachable
1076: * for a broadcast or multicast datgram.)
1077: */
1.48 itojun 1078: udpstat.udps_noport++;
1.13 mycroft 1079: udpstat.udps_noportbcast++;
1.4 hpeyerl 1080: goto bad;
1081: }
1.48 itojun 1082: #ifdef IPSEC
1083: /* check AH/ESP integrity. */
1084: if (last != NULL && ipsec4_in_reject(m, last)) {
1085: ipsecstat.in_polvio++;
1086: goto bad;
1087: }
1088: #endif /*IPSEC*/
1.40 thorpej 1089: if (last->inp_flags & INP_CONTROLOPTS ||
1090: last->inp_socket->so_options & SO_TIMESTAMP)
1091: ip_savecontrol(last, &opts, ip, m);
1.49 drochner 1092: m->m_len -= iphlen;
1093: m->m_pkthdr.len -= iphlen;
1094: m->m_data += iphlen;
1.48 itojun 1095: sa = (struct sockaddr *)&udpsrc;
1096: if (sbappendaddr(&last->inp_socket->so_rcv, sa, m, opts) == 0) {
1.13 mycroft 1097: udpstat.udps_fullsock++;
1.4 hpeyerl 1098: goto bad;
1.13 mycroft 1099: }
1.40 thorpej 1100: sorwakeup(last->inp_socket);
1.4 hpeyerl 1101: return;
1102: }
1.1 cgd 1103: /*
1104: * Locate pcb for datagram.
1105: */
1.35 mycroft 1106: inp = in_pcblookup_connect(&udbtable, ip->ip_src, uh->uh_sport,
1.26 mycroft 1107: ip->ip_dst, uh->uh_dport);
1108: if (inp == 0) {
1109: ++udpstat.udps_pcbhashmiss;
1.35 mycroft 1110: inp = in_pcblookup_bind(&udbtable, ip->ip_dst, uh->uh_dport);
1.18 mycroft 1111: if (inp == 0) {
1112: udpstat.udps_noport++;
1113: if (m->m_flags & (M_BCAST | M_MCAST)) {
1114: udpstat.udps_noportbcast++;
1115: goto bad;
1116: }
1117: *ip = save_ip;
1.38 ws 1118: #if NIPKDB > 0
1119: if (checkipkdb(&ip->ip_src,
1120: uh->uh_sport,
1121: uh->uh_dport,
1122: m,
1123: iphlen + sizeof(struct udphdr),
1124: len - sizeof(struct udphdr)))
1.37 ws 1125: /* It was a debugger connect packet, just drop it now */
1126: goto bad;
1127: #endif
1.18 mycroft 1128: icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0);
1129: return;
1.13 mycroft 1130: }
1.1 cgd 1131: }
1.48 itojun 1132: #ifdef IPSEC
1133: if (inp != NULL && ipsec4_in_reject(m, inp)) {
1134: ipsecstat.in_polvio++;
1135: goto bad;
1136: }
1137: #endif /*IPSEC*/
1.1 cgd 1138:
1139: /*
1140: * Stuff source address and datagram in user buffer.
1141: */
1.40 thorpej 1142: if (inp->inp_flags & INP_CONTROLOPTS ||
1143: inp->inp_socket->so_options & SO_TIMESTAMP)
1144: ip_savecontrol(inp, &opts, ip, m);
1.1 cgd 1145: iphlen += sizeof(struct udphdr);
1146: m->m_len -= iphlen;
1147: m->m_pkthdr.len -= iphlen;
1148: m->m_data += iphlen;
1.48 itojun 1149: sa = (struct sockaddr *)&udpsrc;
1150: if (sbappendaddr(&inp->inp_socket->so_rcv, sa, m, opts) == 0) {
1.1 cgd 1151: udpstat.udps_fullsock++;
1152: goto bad;
1153: }
1154: sorwakeup(inp->inp_socket);
1155: return;
1156: bad:
1157: m_freem(m);
1158: if (opts)
1159: m_freem(opts);
1160: }
1.56 itojun 1161: #endif /*UDP6*/
1.1 cgd 1162:
1163: /*
1164: * Notify a udp user of an asynchronous error;
1165: * just wake up so that he can collect error status.
1166: */
1.7 mycroft 1167: static void
1.1 cgd 1168: udp_notify(inp, errno)
1169: register struct inpcb *inp;
1.7 mycroft 1170: int errno;
1.1 cgd 1171: {
1.34 mycroft 1172:
1.1 cgd 1173: inp->inp_socket->so_error = errno;
1174: sorwakeup(inp->inp_socket);
1175: sowwakeup(inp->inp_socket);
1176: }
1177:
1.27 christos 1178: void *
1179: udp_ctlinput(cmd, sa, v)
1.1 cgd 1180: int cmd;
1181: struct sockaddr *sa;
1.27 christos 1182: void *v;
1.1 cgd 1183: {
1.27 christos 1184: register struct ip *ip = v;
1.1 cgd 1185: register struct udphdr *uh;
1.21 mycroft 1186: extern int inetctlerrmap[];
1.18 mycroft 1187: void (*notify) __P((struct inpcb *, int)) = udp_notify;
1.21 mycroft 1188: int errno;
1.1 cgd 1189:
1.53 itojun 1190: if (sa->sa_family != AF_INET
1191: || sa->sa_len != sizeof(struct sockaddr_in))
1.51 itojun 1192: return NULL;
1.20 mycroft 1193: if ((unsigned)cmd >= PRC_NCMDS)
1.27 christos 1194: return NULL;
1.20 mycroft 1195: errno = inetctlerrmap[cmd];
1.18 mycroft 1196: if (PRC_IS_REDIRECT(cmd))
1.19 mycroft 1197: notify = in_rtchange, ip = 0;
1.18 mycroft 1198: else if (cmd == PRC_HOSTDEAD)
1.19 mycroft 1199: ip = 0;
1.23 cgd 1200: else if (errno == 0)
1.27 christos 1201: return NULL;
1.19 mycroft 1202: if (ip) {
1.1 cgd 1203: uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
1.34 mycroft 1204: in_pcbnotify(&udbtable, satosin(sa)->sin_addr, uh->uh_dport,
1205: ip->ip_src, uh->uh_sport, errno, notify);
1.53 itojun 1206:
1207: /* XXX mapped address case */
1.19 mycroft 1208: } else
1.34 mycroft 1209: in_pcbnotifyall(&udbtable, satosin(sa)->sin_addr, errno,
1210: notify);
1.27 christos 1211: return NULL;
1.1 cgd 1212: }
1213:
1.7 mycroft 1214: int
1.27 christos 1215: #if __STDC__
1216: udp_output(struct mbuf *m, ...)
1217: #else
1218: udp_output(m, va_alist)
1219: struct mbuf *m;
1220: va_dcl
1221: #endif
1222: {
1.1 cgd 1223: register struct inpcb *inp;
1224: register struct udpiphdr *ui;
1225: register int len = m->m_pkthdr.len;
1.31 mycroft 1226: int error = 0;
1.27 christos 1227: va_list ap;
1228:
1229: va_start(ap, m);
1230: inp = va_arg(ap, struct inpcb *);
1231: va_end(ap);
1.1 cgd 1232:
1233: /*
1234: * Calculate data length and get a mbuf
1235: * for UDP and IP headers.
1236: */
1.13 mycroft 1237: M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
1238: if (m == 0) {
1239: error = ENOBUFS;
1.39 thorpej 1240: goto release;
1241: }
1242:
1243: /*
1244: * Compute the packet length of the IP header, and
1245: * punt if the length looks bogus.
1246: */
1247: if ((len + sizeof(struct udpiphdr)) > IP_MAXPACKET) {
1248: error = EMSGSIZE;
1.13 mycroft 1249: goto release;
1250: }
1.1 cgd 1251:
1252: /*
1253: * Fill in mbuf with extended UDP header
1254: * and addresses and length put into network format.
1255: */
1256: ui = mtod(m, struct udpiphdr *);
1.25 cgd 1257: bzero(ui->ui_x1, sizeof ui->ui_x1);
1.1 cgd 1258: ui->ui_pr = IPPROTO_UDP;
1.15 cgd 1259: ui->ui_len = htons((u_int16_t)len + sizeof (struct udphdr));
1.1 cgd 1260: ui->ui_src = inp->inp_laddr;
1261: ui->ui_dst = inp->inp_faddr;
1262: ui->ui_sport = inp->inp_lport;
1263: ui->ui_dport = inp->inp_fport;
1264: ui->ui_ulen = ui->ui_len;
1265:
1266: /*
1267: * Stuff checksum and output datagram.
1268: */
1269: ui->ui_sum = 0;
1270: if (udpcksum) {
1271: if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
1272: ui->ui_sum = 0xffff;
1273: }
1274: ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
1275: ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl; /* XXX */
1276: ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */
1277: udpstat.udps_opackets++;
1.48 itojun 1278:
1279: #ifdef IPSEC
1280: m->m_pkthdr.rcvif = (struct ifnet *)inp->inp_socket;
1281: #endif /*IPSEC*/
1282:
1.31 mycroft 1283: return (ip_output(m, inp->inp_options, &inp->inp_route,
1.12 mycroft 1284: inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST),
1.31 mycroft 1285: inp->inp_moptions));
1.1 cgd 1286:
1287: release:
1288: m_freem(m);
1289: return (error);
1290: }
1291:
1.42 thorpej 1292: int udp_sendspace = 9216; /* really max datagram size */
1293: int udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
1.1 cgd 1294: /* 40 1K datagrams */
1295:
1296: /*ARGSUSED*/
1.7 mycroft 1297: int
1.31 mycroft 1298: udp_usrreq(so, req, m, nam, control, p)
1.1 cgd 1299: struct socket *so;
1300: int req;
1.31 mycroft 1301: struct mbuf *m, *nam, *control;
1.30 mycroft 1302: struct proc *p;
1.1 cgd 1303: {
1.31 mycroft 1304: register struct inpcb *inp;
1.1 cgd 1305: int s;
1.31 mycroft 1306: register int error = 0;
1.1 cgd 1307:
1308: if (req == PRU_CONTROL)
1.31 mycroft 1309: return (in_control(so, (long)m, (caddr_t)nam,
1.30 mycroft 1310: (struct ifnet *)control, p));
1.31 mycroft 1311:
1312: s = splsoftnet();
1313: inp = sotoinpcb(so);
1.32 mycroft 1314: #ifdef DIAGNOSTIC
1315: if (req != PRU_SEND && req != PRU_SENDOOB && control)
1316: panic("udp_usrreq: unexpected control mbuf");
1317: #endif
1.31 mycroft 1318: if (inp == 0 && req != PRU_ATTACH) {
1319: error = EINVAL;
1320: goto release;
1321: }
1322:
1.1 cgd 1323: /*
1324: * Note: need to block udp_input while changing
1325: * the udp pcb queue and/or pcb addresses.
1326: */
1327: switch (req) {
1328:
1329: case PRU_ATTACH:
1.31 mycroft 1330: if (inp != 0) {
1331: error = EISCONN;
1.1 cgd 1332: break;
1333: }
1.31 mycroft 1334: if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
1335: error = soreserve(so, udp_sendspace, udp_recvspace);
1336: if (error)
1337: break;
1338: }
1.18 mycroft 1339: error = in_pcballoc(so, &udbtable);
1.1 cgd 1340: if (error)
1341: break;
1.31 mycroft 1342: inp = sotoinpcb(so);
1343: inp->inp_ip.ip_ttl = ip_defttl;
1.48 itojun 1344: #ifdef IPSEC
1.53 itojun 1345: error = ipsec_init_policy(&inp->inp_sp);
1346: if (error != 0) {
1.52 itojun 1347: in_pcbdetach(inp);
1.53 itojun 1348: break;
1349: }
1.48 itojun 1350: #endif /*IPSEC*/
1.1 cgd 1351: break;
1352:
1353: case PRU_DETACH:
1.31 mycroft 1354: in_pcbdetach(inp);
1.1 cgd 1355: break;
1356:
1357: case PRU_BIND:
1.31 mycroft 1358: error = in_pcbbind(inp, nam, p);
1.1 cgd 1359: break;
1360:
1361: case PRU_LISTEN:
1362: error = EOPNOTSUPP;
1363: break;
1364:
1365: case PRU_CONNECT:
1.31 mycroft 1366: error = in_pcbconnect(inp, nam);
1367: if (error)
1.1 cgd 1368: break;
1.31 mycroft 1369: soisconnected(so);
1.1 cgd 1370: break;
1371:
1372: case PRU_CONNECT2:
1373: error = EOPNOTSUPP;
1374: break;
1375:
1376: case PRU_DISCONNECT:
1.31 mycroft 1377: /*soisdisconnected(so);*/
1378: so->so_state &= ~SS_ISCONNECTED; /* XXX */
1.1 cgd 1379: in_pcbdisconnect(inp);
1.34 mycroft 1380: inp->inp_laddr = zeroin_addr; /* XXX */
1.35 mycroft 1381: in_pcbstate(inp, INP_BOUND); /* XXX */
1.1 cgd 1382: break;
1383:
1384: case PRU_SHUTDOWN:
1385: socantsendmore(so);
1386: break;
1387:
1.31 mycroft 1388: case PRU_RCVD:
1389: error = EOPNOTSUPP;
1.1 cgd 1390: break;
1391:
1.31 mycroft 1392: case PRU_SEND:
1.32 mycroft 1393: if (control && control->m_len) {
1394: m_freem(control);
1395: m_freem(m);
1396: error = EINVAL;
1397: break;
1398: }
1.31 mycroft 1399: {
1.35 mycroft 1400: struct in_addr laddr; /* XXX */
1.1 cgd 1401:
1.31 mycroft 1402: if (nam) {
1.35 mycroft 1403: laddr = inp->inp_laddr; /* XXX */
1.31 mycroft 1404: if ((so->so_state & SS_ISCONNECTED) != 0) {
1405: error = EISCONN;
1.32 mycroft 1406: goto die;
1.31 mycroft 1407: }
1408: error = in_pcbconnect(inp, nam);
1.32 mycroft 1409: if (error) {
1410: die:
1411: m_freem(m);
1.31 mycroft 1412: break;
1.32 mycroft 1413: }
1.31 mycroft 1414: } else {
1415: if ((so->so_state & SS_ISCONNECTED) == 0) {
1416: error = ENOTCONN;
1.32 mycroft 1417: goto die;
1.31 mycroft 1418: }
1419: }
1.33 mycroft 1420: error = udp_output(m, inp);
1.31 mycroft 1421: if (nam) {
1422: in_pcbdisconnect(inp);
1.35 mycroft 1423: inp->inp_laddr = laddr; /* XXX */
1424: in_pcbstate(inp, INP_BOUND); /* XXX */
1.31 mycroft 1425: }
1426: }
1.1 cgd 1427: break;
1428:
1429: case PRU_SENSE:
1430: /*
1431: * stat: don't bother with a blocksize.
1432: */
1.31 mycroft 1433: splx(s);
1.1 cgd 1434: return (0);
1435:
1.31 mycroft 1436: case PRU_RCVOOB:
1437: error = EOPNOTSUPP;
1438: break;
1439:
1.1 cgd 1440: case PRU_SENDOOB:
1.32 mycroft 1441: m_freem(control);
1.31 mycroft 1442: m_freem(m);
1.1 cgd 1443: error = EOPNOTSUPP;
1444: break;
1445:
1.31 mycroft 1446: case PRU_SOCKADDR:
1447: in_setsockaddr(inp, nam);
1448: break;
1449:
1450: case PRU_PEERADDR:
1451: in_setpeeraddr(inp, nam);
1452: break;
1.1 cgd 1453:
1454: default:
1455: panic("udp_usrreq");
1456: }
1457:
1458: release:
1.31 mycroft 1459: splx(s);
1.1 cgd 1460: return (error);
1.13 mycroft 1461: }
1462:
1463: /*
1464: * Sysctl for udp variables.
1465: */
1.27 christos 1466: int
1.13 mycroft 1467: udp_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
1468: int *name;
1469: u_int namelen;
1470: void *oldp;
1471: size_t *oldlenp;
1472: void *newp;
1473: size_t newlen;
1474: {
1475: /* All sysctl names at this level are terminal. */
1476: if (namelen != 1)
1477: return (ENOTDIR);
1478:
1479: switch (name[0]) {
1480: case UDPCTL_CHECKSUM:
1481: return (sysctl_int(oldp, oldlenp, newp, newlen, &udpcksum));
1.42 thorpej 1482: case UDPCTL_SENDSPACE:
1483: return (sysctl_int(oldp, oldlenp, newp, newlen,
1484: &udp_sendspace));
1485: case UDPCTL_RECVSPACE:
1486: return (sysctl_int(oldp, oldlenp, newp, newlen,
1487: &udp_recvspace));
1.13 mycroft 1488: default:
1489: return (ENOPROTOOPT);
1490: }
1491: /* NOTREACHED */
1.1 cgd 1492: }
CVSweb <webmaster@jp.NetBSD.org>