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