diff options
| author | itojun <itojun@NetBSD.org> | 1999-12-13 15:17:17 +0000 |
|---|---|---|
| committer | itojun <itojun@NetBSD.org> | 1999-12-13 15:17:17 +0000 |
| commit | ea861f0183f07970865fa35737f2b42e49e3aba0 (patch) | |
| tree | 66276ba5ce54db63f1e39e0faf66b6d48a561f54 /sys/netinet | |
| parent | 1501f61891a7a207cce1aa417e23eb96889384b2 (diff) | |
sync IPv6 part with latest KAME tree. IPsec part is left unmodified
due to massive changes in KAME side.
- IPv6 output goes through nd6_output
- faith can capture IPv4 packets as well - you can run IPv4-to-IPv6 translator
using heavily modified DNS servers
- per-interface statistics (required for IPv6 MIB)
- interface autoconfig is revisited
- udp input handling has a big change for mapped address support.
- introduce in4_cksum() for non-overwriting checksumming
- introduce m_pulldown()
- neighbor discovery cleanups/improvements
- netinet/in.h strictly conforms to RFC2553 (no extra defs visible to userland)
- IFA_STATS is fixed a bit (not tested)
- and more more more.
TODO:
- cleanup os-independency #ifdef
- avoid rcvif dual use (for IPsec) to help ifdetach
(sorry for jumbo commit, I can't separate this any more...)
Diffstat (limited to 'sys/netinet')
| -rw-r--r-- | sys/netinet/in.h | 3 | ||||
| -rw-r--r-- | sys/netinet/in4_cksum.c | 7 | ||||
| -rw-r--r-- | sys/netinet/in_gif.c | 40 | ||||
| -rw-r--r-- | sys/netinet/in_pcb.c | 7 | ||||
| -rw-r--r-- | sys/netinet/in_proto.c | 10 | ||||
| -rw-r--r-- | sys/netinet/ip_ipip.c | 7 | ||||
| -rw-r--r-- | sys/netinet/ip_output.c | 47 | ||||
| -rw-r--r-- | sys/netinet/raw_ip.c | 10 | ||||
| -rw-r--r-- | sys/netinet/tcp_input.c | 57 | ||||
| -rw-r--r-- | sys/netinet/tcp_output.c | 22 | ||||
| -rw-r--r-- | sys/netinet/tcp_subr.c | 68 | ||||
| -rw-r--r-- | sys/netinet/tcp_usrreq.c | 20 | ||||
| -rw-r--r-- | sys/netinet/tcp_var.h | 5 | ||||
| -rw-r--r-- | sys/netinet/udp_usrreq.c | 770 |
14 files changed, 939 insertions, 134 deletions
diff --git a/sys/netinet/in.h b/sys/netinet/in.h index 37001266186..0afb9b43d0e 100644 --- a/sys/netinet/in.h +++ b/sys/netinet/in.h @@ -1,4 +1,4 @@ -/* $NetBSD: in.h,v 1.43 1999/11/20 00:37:59 thorpej Exp $ */ +/* $NetBSD: in.h,v 1.44 1999/12/13 15:17:19 itojun Exp $ */ /* * Copyright (c) 1982, 1986, 1990, 1993 @@ -376,6 +376,7 @@ extern struct in_addr zeroin_addr; int in_broadcast __P((struct in_addr, struct ifnet *)); int in_canforward __P((struct in_addr)); int in_cksum __P((struct mbuf *, int)); +int in4_cksum __P((struct mbuf *, u_int8_t, int, int)); int in_localaddr __P((struct in_addr)); void in_socktrim __P((struct sockaddr_in *)); diff --git a/sys/netinet/in4_cksum.c b/sys/netinet/in4_cksum.c index 95b3529f467..a535848fe9e 100644 --- a/sys/netinet/in4_cksum.c +++ b/sys/netinet/in4_cksum.c @@ -1,4 +1,4 @@ -/* $NetBSD: in4_cksum.c,v 1.1.2.1 1999/11/30 13:35:24 itojun Exp $ */ +/* $NetBSD: in4_cksum.c,v 1.2 1999/12/13 15:17:19 itojun Exp $ */ /* * Copyright (C) 1999 WIDE Project. @@ -67,11 +67,12 @@ #include <sys/param.h> #include <sys/mbuf.h> #include <sys/systm.h> +#include <sys/socket.h> +#include <net/route.h> #include <netinet/in.h> -#include <netinet/ip_var.h> - #include <netinet/in_systm.h> #include <netinet/ip.h> +#include <netinet/ip_var.h> /* * Checksum routine for Internet Protocol family headers (Portable Version). diff --git a/sys/netinet/in_gif.c b/sys/netinet/in_gif.c index b64d752c68b..8d47e1e0e6a 100644 --- a/sys/netinet/in_gif.c +++ b/sys/netinet/in_gif.c @@ -1,4 +1,4 @@ -/* $NetBSD: in_gif.c,v 1.6 1999/08/20 10:07:40 itojun Exp $ */ +/* $NetBSD: in_gif.c,v 1.7 1999/12/13 15:17:20 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -38,8 +38,10 @@ #endif #if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) #include "opt_inet.h" +#ifdef __NetBSD__ /*XXX*/ #include "opt_ipsec.h" #endif +#endif #include <sys/param.h> #include <sys/systm.h> @@ -47,6 +49,10 @@ #include <sys/sockio.h> #include <sys/mbuf.h> #include <sys/errno.h> +#ifdef __FreeBSD__ +#include <sys/kernel.h> +#include <sys/sysctl.h> +#endif #if !defined(__FreeBSD__) || __FreeBSD__ < 3 #include <sys/ioctl.h> #endif @@ -75,15 +81,19 @@ #include "gif.h" -#ifdef __NetBSD__ #include <machine/stdarg.h> -#endif + +#include <net/net_osdep.h> #if NGIF > 0 int ip_gif_ttl = GIF_TTL; #else int ip_gif_ttl = 0; #endif +#ifdef __FreeBSD__ +SYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_RW, + &ip_gif_ttl, 0, ""); +#endif int in_gif_output(ifp, family, m, rt) @@ -155,6 +165,10 @@ in_gif_output(ifp, family, m, rt) if (sin_dst->sin_addr.s_addr != INADDR_ANY) iphdr.ip_dst = sin_dst->sin_addr; else if (rt) { + if (family != AF_INET) { + m_freem(m); + return EINVAL; /*XXX*/ + } iphdr.ip_dst = ((struct sockaddr_in *) (rt->rt_gateway))->sin_addr; } else { @@ -216,20 +230,19 @@ in_gif_output(ifp, family, m, rt) } #ifdef IPSEC +#ifndef __OpenBSD__ /*KAME IPSEC*/ m->m_pkthdr.rcvif = NULL; +#endif #endif /*IPSEC*/ - error = ip_output(m, 0, &sc->gif_ro, 0, 0); +#ifndef __OpenBSD__ + error = ip_output(m, NULL, &sc->gif_ro, 0, NULL); +#else + error = ip_output(m, NULL, &sc->gif_ro, 0, NULL, NULL); +#endif return(error); } void -#ifndef __NetBSD__ -in_gif_input(m, off, proto) - struct mbuf *m; - int off; - int proto; -{ -#else /* __NetBSD__ */ #if __STDC__ in_gif_input(struct mbuf *m, ...) #else @@ -239,22 +252,17 @@ in_gif_input(m, va_alist) #endif { int off, proto; -#endif /* __NetBSD__ */ struct gif_softc *sc; struct ifnet *gifp = NULL; struct ip *ip; int i, af; -#ifdef __NetBSD__ va_list ap; -#endif /* __NetBSD__ */ u_int8_t otos; -#ifdef __NetBSD__ va_start(ap, m); off = va_arg(ap, int); proto = va_arg(ap, int); va_end(ap); -#endif /* __NetBSD__ */ ip = mtod(m, struct ip *); diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 7ccc39f6b8a..7de281f9e77 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -1,4 +1,4 @@ -/* $NetBSD: in_pcb.c,v 1.60 1999/07/09 22:57:17 thorpej Exp $ */ +/* $NetBSD: in_pcb.c,v 1.61 1999/12/13 15:17:20 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -507,11 +507,6 @@ in_pcbdetach(v) int s; #ifdef IPSEC - if (so->so_pcb) { - KEYDEBUG(KEYDEBUG_KEY_STAMP, - printf("DP call free SO=%p from in_pcbdetach\n", so)); - key_freeso(so); - } ipsec4_delete_pcbpolicy(inp); #endif /*IPSEC*/ so->so_pcb = 0; diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c index 5c7fbff5cc6..a8f6900f6c1 100644 --- a/sys/netinet/in_proto.c +++ b/sys/netinet/in_proto.c @@ -1,4 +1,4 @@ -/* $NetBSD: in_proto.c,v 1.33 1999/07/09 22:57:18 thorpej Exp $ */ +/* $NetBSD: in_proto.c,v 1.34 1999/12/13 15:17:20 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -195,14 +195,14 @@ struct protosw inetsw[] = { #endif /* IPSEC */ #if NGIF > 0 { SOCK_RAW, &inetdomain, IPPROTO_IPV4, PR_ATOMIC|PR_ADDR, - in_gif_input, 0, 0, 0, - 0, + in_gif_input, rip_output, 0, rip_ctloutput, + rip_usrreq, /*XXX*/ 0, 0, 0, 0, }, #ifdef INET6 { SOCK_RAW, &inetdomain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR, - in_gif_input, 0, 0, 0, - 0, + in_gif_input, rip_output, 0, rip_ctloutput, + rip_usrreq, /*XXX*/ 0, 0, 0, 0, }, #endif /* INET6 */ diff --git a/sys/netinet/ip_ipip.c b/sys/netinet/ip_ipip.c index 1be4fb2c1b0..c75c76d94fc 100644 --- a/sys/netinet/ip_ipip.c +++ b/sys/netinet/ip_ipip.c @@ -1,4 +1,4 @@ -/* $NetBSD: ip_ipip.c,v 1.7 1999/08/26 02:56:59 itojun Exp $ */ +/* $NetBSD: ip_ipip.c,v 1.8 1999/12/13 15:17:20 itojun Exp $ */ /*- * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -109,11 +109,12 @@ ipip_input(m, va_alist) #if NIPIP > 0 struct ipip_softc *sc; #endif - int hlen; + int hlen, proto; va_list ap; va_start(ap, m); hlen = va_arg(ap, int); + proto = va_arg(ap, int); va_end(ap); #if NIPIP > 0 @@ -163,7 +164,7 @@ ipip_input(m, va_alist) #endif /* MROUTING */ /* Last try: give it to raw IP. */ - rip_input(m); + rip_input(m, hlen, proto); } #if NIPIP > 0 diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index 74c71ce94e6..967eabd3b0c 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -1,4 +1,4 @@ -/* $NetBSD: ip_output.c,v 1.62 1999/07/09 22:57:19 thorpej Exp $ */ +/* $NetBSD: ip_output.c,v 1.63 1999/12/13 15:17:20 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -549,6 +549,19 @@ skip_ipsec: * If small enough for mtu of path, can just send directly. */ if ((u_int16_t)ip->ip_len <= mtu) { +#if IFA_STATS + /* + * search for the source address structure to + * maintain output statistics. + */ + bzero((caddr_t*) &src, sizeof(src)); + src.sin_family = AF_INET; + src.sin_addr.s_addr = ip->ip_src.s_addr; + src.sin_len = sizeof(src); + ia = ifatoia(ifa_ifwithladdr(sintosa(&src))); + if (ia) + ia->ia_ifa.ifa_data.ifad_outbytes += ntohs(ip->ip_len); +#endif HTONS(ip->ip_len); HTONS(ip->ip_off); ip->ip_sum = 0; @@ -659,10 +672,25 @@ sendorfree: for (m = m0; m; m = m0) { m0 = m->m_nextpkt; m->m_nextpkt = 0; - if (error == 0) + if (error == 0) { +#if IFA_STATS + /* + * search for the source address structure to + * maintain output statistics. + */ + bzero((caddr_t*) &src, sizeof(src)); + src.sin_family = AF_INET; + src.sin_addr.s_addr = ip->ip_src.s_addr; + src.sin_len = sizeof(src); + ia = ifatoia(ifa_ifwithladdr(sintosa(&src))); + if (ia) { + ia->ia_ifa.ifa_data.ifad_outbytes += + ntohs(ip->ip_len); + } +#endif error = (*ifp->if_output)(ifp, m, sintosa(dst), ro->ro_rt); - else + } else m_freem(m); } @@ -674,19 +702,6 @@ done: RTFREE(ro->ro_rt); ro->ro_rt = 0; } -#if IFA_STATS - if (error == 0) { - /* search for the source address structure to maintain output - * statistics. */ - bzero((caddr_t*) &src, sizeof(src)); - src.sin_family = AF_INET; - src.sin_addr.s_addr = ip->ip_src.s_addr; - src.sin_len = sizeof(src); - ia = ifatoia(ifa_ifwithladdr(sintosa(&src))); - if (ia) - ia->ia_ifa.ifa_data.ifad_outbytes += ntohs(ip->ip_len); - } -#endif #ifdef IPSEC if (sp != NULL) { diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index ed3854bf660..58c208eacc0 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -1,4 +1,4 @@ -/* $NetBSD: raw_ip.c,v 1.46 1999/09/13 12:15:55 itojun Exp $ */ +/* $NetBSD: raw_ip.c,v 1.47 1999/12/13 15:17:20 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -207,7 +207,8 @@ rip_input(m, va_alist) sorwakeup(last->inp_socket); } else { if (inetsw[ip_protox[ip->ip_p]].pr_input == rip_input) { - icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PROTOCOL,0,0); + icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PROTOCOL, + 0, 0); ipstat.ips_noproto++; ipstat.ips_delivered--; } else @@ -463,8 +464,11 @@ rip_usrreq(so, req, m, nam, control, p) inp = sotoinpcb(so); inp->inp_ip.ip_p = (long)nam; #ifdef IPSEC - if ((error = ipsec_init_policy(&inp->inp_sp)) != 0) + error = ipsec_init_policy(&inp->inp_sp); + if (error != 0) { in_pcbdetach(inp); + break; + } #endif /*IPSEC*/ break; diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 198ca0e1e38..ba03bd4a044 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -1,4 +1,4 @@ -/* $NetBSD: tcp_input.c,v 1.98 1999/12/11 09:55:14 itojun Exp $ */ +/* $NetBSD: tcp_input.c,v 1.99 1999/12/13 15:17:20 itojun Exp $ */ /* %%% portions-copyright-nrl-95 @@ -161,6 +161,13 @@ didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>. #include <netinet6/nd6.h> #endif +#ifdef PULLDOWN_TEST +#ifndef INET6 +/* always need ip6.h for IP6_EXTHDR_GET */ +#include <netinet/ip6.h> +#endif +#endif + #include <netinet/tcp.h> #include <netinet/tcp_fsm.h> #include <netinet/tcp_seq.h> @@ -589,6 +596,7 @@ tcp_input(m, va_alist) case 4: af = AF_INET; iphlen = sizeof(struct ip); +#ifndef PULLDOWN_TEST /* would like to get rid of this... */ if (toff > sizeof (struct ip)) { ip_stripoptions(m, (struct mbuf *)0); @@ -602,12 +610,22 @@ tcp_input(m, va_alist) } ip = mtod(m, struct ip *); th = (struct tcphdr *)(mtod(m, caddr_t) + toff); +#else + ip = mtod(m, struct ip *); + IP6_EXTHDR_GET(th, struct tcphdr *, m, toff, + sizeof(struct tcphdr)); + if (th == NULL) { + tcpstat.tcps_rcvshort++; + return; + } +#endif /* * Checksum extended TCP header and data. */ len = ip->ip_len; tlen = len - toff; +#ifndef PULLDOWN_TEST { struct ipovly *ipov; ipov = (struct ipovly *)ip; @@ -618,12 +636,19 @@ tcp_input(m, va_alist) tcpstat.tcps_rcvbadsum++; goto drop; } +#else + if (in4_cksum(m, IPPROTO_TCP, toff, tlen) != 0) { + tcpstat.tcps_rcvbadsum++; + goto drop; + } +#endif break; #ifdef INET6 case 6: ip = NULL; iphlen = sizeof(struct ip6_hdr); af = AF_INET6; +#ifndef PULLDOWN_TEST if (m->m_len < toff + sizeof(struct tcphdr)) { m = m_pullup(m, toff + sizeof(struct tcphdr)); /*XXX*/ if (m == NULL) { @@ -633,6 +658,15 @@ tcp_input(m, va_alist) } ip6 = mtod(m, struct ip6_hdr *); th = (struct tcphdr *)(mtod(m, caddr_t) + toff); +#else + ip6 = mtod(m, struct ip6_hdr *); + IP6_EXTHDR_GET(th, struct tcphdr *, m, toff, + sizeof(struct tcphdr)); + if (th == NULL) { + tcpstat.tcps_rcvshort++; + return; + } +#endif /* * Checksum extended TCP header and data. @@ -669,6 +703,7 @@ tcp_input(m, va_alist) */ if (off > sizeof (struct tcphdr)) { +#ifndef PULLDOWN_TEST if (m->m_len < toff + off) { if ((m = m_pullup(m, toff + off)) == 0) { tcpstat.tcps_rcvshort++; @@ -686,8 +721,19 @@ tcp_input(m, va_alist) } th = (struct tcphdr *)(mtod(m, caddr_t) + toff); } +#else + IP6_EXTHDR_GET(th, struct tcphdr *, m, toff, off); + if (th == NULL) { + tcpstat.tcps_rcvshort++; + return; + } + /* + * NOTE: ip/ip6 will not be affected by m_pulldown() + * (as they're before toff) and we don't need to update those. + */ +#endif optlen = off - sizeof (struct tcphdr); - optp = mtod(m, caddr_t) + toff + sizeof (struct tcphdr); + optp = ((caddr_t)th) + sizeof(struct tcphdr); /* * Do quick retrieval of timestamp options ("options * prediction?"). If timestamp is the only option and it's @@ -3384,7 +3430,7 @@ syn_cache_respond(sc, m) case AF_INET6: ip6->ip6_vfc = IPV6_VERSION; ip6->ip6_plen = htons(tlen - hlen); - ip6->ip6_hlim = ip6_defhlim; + /* ip6_hlim will be initialized afterwards */ /* XXX flowlabel? */ break; #endif @@ -3429,8 +3475,11 @@ syn_cache_respond(sc, m) break; #ifdef INET6 case AF_INET6: + ip6->ip6_hlim = in6_selecthlim(NULL, + ro->ro_rt ? ro->ro_rt->rt_ifp : NULL); + error = ip6_output(m, NULL /*XXX*/, (struct route_in6 *)ro, - 0, NULL); + 0, NULL, NULL); break; #endif default: diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c index 779859e5761..2f807b51bf2 100644 --- a/sys/netinet/tcp_output.c +++ b/sys/netinet/tcp_output.c @@ -1,4 +1,4 @@ -/* $NetBSD: tcp_output.c,v 1.52 1999/09/23 02:21:31 itojun Exp $ */ +/* $NetBSD: tcp_output.c,v 1.53 1999/12/13 15:17:20 itojun Exp $ */ /* %%% portions-copyright-nrl-95 @@ -946,8 +946,16 @@ send: #ifdef INET6 case AF_INET6: ip6->ip6_nxt = IPPROTO_TCP; - if (tp->t_in6pcb) - ip6->ip6_hlim = tp->t_in6pcb->in6p_ip6.ip6_hlim; + if (tp->t_in6pcb) { + /* + * we separately set hoplimit for every segment, since + * the user might want to change the value via + * setsockopt. Also, desired default hop limit might + * be changed via Neighbor Discovery. + */ + ip6->ip6_hlim = in6_selecthlim(tp->t_in6pcb, + ro->ro_rt ? ro->ro_rt->rt_ifp : NULL); + } /* ip6->ip6_flow = ??? */ /* ip6_plen will be filled in ip6_output(). */ break; @@ -1043,18 +1051,12 @@ send: { struct ip6_pktopts *opts; -#if BSD >= 43 if (tp->t_in6pcb) opts = tp->t_in6pcb->in6p_outputopts; else opts = NULL; error = ip6_output(m, opts, (struct route_in6 *)ro, - so->so_options & SO_DONTROUTE, 0); -#else - opts = NULL; - error = ip6_output(m, opts, (struct route_in6 *)ro, - so->so_options & SO_DONTROUTE); -#endif + so->so_options & SO_DONTROUTE, 0, NULL); break; } #endif diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 621fd14c390..a01849a07bb 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -1,4 +1,4 @@ -/* $NetBSD: tcp_subr.c,v 1.83 1999/12/12 19:51:49 ragge Exp $ */ +/* $NetBSD: tcp_subr.c,v 1.84 1999/12/13 15:17:20 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -439,13 +439,12 @@ tcp_respond(tp, template, m, th0, ack, seq, flags) th = (struct tcphdr *)(ip6 + 1); break; #endif - default: /*pacify gcc*/ - ip = NULL; -#ifdef INET6 - ip6 = NULL; +#if 0 + default: + /* noone will visit here */ + m_freem(m); + return EAFNOSUPPORT; #endif - th = NULL; - break; } flags = TH_ACK; } else { @@ -462,8 +461,7 @@ tcp_respond(tp, template, m, th0, ack, seq, flags) break; #endif default: - if (m) - m_freem(m); + m_freem(m); return EAFNOSUPPORT; } @@ -494,9 +492,6 @@ tcp_respond(tp, template, m, th0, ack, seq, flags) ip6->ip6_nxt = IPPROTO_TCP; break; #endif - default: /*pacify gcc*/ - th = NULL; - break; } *th = *th0; xchg(th->th_dport, th->th_sport, u_int16_t); @@ -540,7 +535,13 @@ tcp_respond(tp, template, m, th0, ack, seq, flags) th->th_sum = in6_cksum(m, IPPROTO_TCP, sizeof(struct ip6_hdr), tlen); ip6->ip6_plen = ntohs(tlen); - ip6->ip6_hlim = ip6_defhlim; + if (tp && tp->t_in6pcb) { + struct ifnet *oifp; + ro = (struct route *)&tp->t_in6pcb->in6p_route; + oifp = ro->ro_rt ? ro->ro_rt->rt_ifp : NULL; + ip6->ip6_hlim = in6_selecthlim(tp->t_in6pcb, oifp); + } else + ip6->ip6_hlim = ip6_defhlim; ip6->ip6_flow &= ~IPV6_FLOWINFO_MASK; if (ip6_auto_flowlabel) { ip6->ip6_flow |= @@ -658,7 +659,8 @@ tcp_respond(tp, template, m, th0, ack, seq, flags) break; #ifdef INET6 case AF_INET6: - error = ip6_output(m, NULL, (struct route_in6 *)ro, 0, NULL); + error = ip6_output(m, NULL, (struct route_in6 *)ro, 0, NULL, + NULL); break; #endif default: @@ -749,7 +751,9 @@ tcp_newtcpcb(family, aux) #ifdef INET6 else if (family == AF_INET6) { struct in6pcb *in6p = (struct in6pcb *)aux; - in6p->in6p_ip6.ip6_hlim = ip6_defhlim; + in6p->in6p_ip6.ip6_hlim = in6_selecthlim(in6p, + in6p->in6p_route.ro_rt ? in6p->in6p_route.ro_rt->rt_ifp + : NULL); in6p->in6p_ppcb = (caddr_t)tp; } #endif @@ -1048,12 +1052,10 @@ tcp6_notify(in6p, error) #if defined(INET6) && !defined(TCP6) void -tcp6_ctlinput(cmd, sa, ip6, m, off) +tcp6_ctlinput(cmd, sa, d) int cmd; struct sockaddr *sa; - register struct ip6_hdr *ip6; - struct mbuf *m; - int off; + void *d; { register struct tcphdr *thp; struct tcphdr th; @@ -1061,16 +1063,25 @@ tcp6_ctlinput(cmd, sa, ip6, m, off) int nmatch; extern struct in6_addr zeroin6_addr; /* netinet6/in6_pcb.c */ struct sockaddr_in6 sa6; + register struct ip6_hdr *ip6; + struct mbuf *m; + int off; if (sa->sa_family != AF_INET6 || sa->sa_len != sizeof(struct sockaddr_in6)) return; - if (cmd == PRC_QUENCH) + if ((unsigned)cmd >= PRC_NCMDS) + return; + else if (cmd == PRC_QUENCH) { + /* XXX there's no PRC_QUENCH in IPv6 */ notify = tcp6_quench; + } else if (PRC_IS_REDIRECT(cmd)) + notify = in6_rtchange, d = NULL; else if (cmd == PRC_MSGSIZE) - notify = tcp6_mtudisc; - else if (!PRC_IS_REDIRECT(cmd) && - ((unsigned)cmd > PRC_NCMDS || inet6ctlerrmap[cmd] == 0)) + notify = tcp6_mtudisc, d = NULL; + else if (cmd == PRC_HOSTDEAD) + d = NULL; + else if (inet6ctlerrmap[cmd] == 0) return; /* translate addresses into internal form */ @@ -1078,6 +1089,17 @@ tcp6_ctlinput(cmd, sa, ip6, m, off) if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr)) sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); + /* if the parameter is from icmp6, decode it. */ + if (d != NULL) { + struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d; + m = ip6cp->ip6c_m; + ip6 = ip6cp->ip6c_ip6; + off = ip6cp->ip6c_off; + } else { + m = NULL; + ip6 = NULL; + } + if (ip6) { /* * XXX: We assume that when ip6 is non NULL, diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index fbaa4e32ec2..deddd049ad0 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -1,4 +1,4 @@ -/* $NetBSD: tcp_usrreq.c,v 1.42 1999/07/09 22:57:23 thorpej Exp $ */ +/* $NetBSD: tcp_usrreq.c,v 1.43 1999/12/13 15:17:21 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -730,14 +730,20 @@ tcp_attach(so) return EAFNOSUPPORT; } #ifdef IPSEC - if (inp && (error = ipsec_init_policy(&inp->inp_sp)) != 0) { - in_pcbdetach(inp); - return (error); + if (inp) { + error = ipsec_init_policy(&inp->inp_sp); + if (error != 0) { + in_pcbdetach(inp); + return (error); + } } #ifdef INET6 - else if (in6p && (error = ipsec_init_policy(&in6p->in6p_sp)) != 0) { - in6_pcbdetach(in6p); - return (error); + else if (in6p) { + error = ipsec_init_policy(&in6p->in6p_sp); + if (error != 0) { + in6_pcbdetach(in6p); + return (error); + } } #endif #endif /*IPSEC*/ diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h index bdce32eec01..786eba3262f 100644 --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -1,4 +1,4 @@ -/* $NetBSD: tcp_var.h,v 1.70 1999/12/08 16:22:20 itojun Exp $ */ +/* $NetBSD: tcp_var.h,v 1.71 1999/12/13 15:17:21 itojun Exp $ */ /* %%% portions-copyright-nrl-98 @@ -621,8 +621,7 @@ void tcp_canceltimers __P((struct tcpcb *)); struct tcpcb * tcp_close __P((struct tcpcb *)); #if defined(INET6) && !defined(TCP6) -void tcp6_ctlinput __P((int, struct sockaddr *, struct ip6_hdr *, - struct mbuf *, int)); +void tcp6_ctlinput __P((int, struct sockaddr *, void *)); #endif void *tcp_ctlinput __P((int, struct sockaddr *, void *)); int tcp_ctloutput __P((int, struct socket *, int, int, struct mbuf **)); diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index 32296ddb215..4f532ea5239 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -1,4 +1,4 @@ -/* $NetBSD: udp_usrreq.c,v 1.52 1999/09/13 12:15:55 itojun Exp $ */ +/* $NetBSD: udp_usrreq.c,v 1.53 1999/12/13 15:17:21 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -68,14 +68,9 @@ #include "ipkdb.h" -/* XXX MAPPED_ADDR_ENABLED should be revisited */ - #include <sys/param.h> #include <sys/malloc.h> #include <sys/mbuf.h> -#ifdef MAPPED_ADDR_ENABLED -#include <sys/domain.h> -#endif /* MAPPED_ADDR_ENABLED */ #include <sys/protosw.h> #include <sys/socket.h> #include <sys/socketvar.h> @@ -83,6 +78,7 @@ #include <sys/stat.h> #include <sys/systm.h> #include <sys/proc.h> +#include <sys/domain.h> #include <vm/vm.h> #include <sys/sysctl.h> @@ -100,6 +96,21 @@ #include <netinet/udp.h> #include <netinet/udp_var.h> +#ifdef INET6 +#include <netinet/ip6.h> +#include <netinet/icmp6.h> +#include <netinet6/ip6_var.h> +#include <netinet6/in6_pcb.h> +#include <netinet6/udp6_var.h> +#endif + +#ifdef PULLDOWN_TEST +#ifndef INET6 +/* always need ip6.h for IP6_EXTHDR_GET */ +#include <netinet/ip6.h> +#endif +#endif + #include <machine/stdarg.h> #ifdef IPSEC @@ -118,6 +129,18 @@ int udpcksum = 1; int udpcksum = 0; /* XXX */ #endif +static void udp4_sendup __P((struct mbuf *, int, struct sockaddr *, + struct socket *)); +static int udp4_realinput __P((struct sockaddr_in *, struct sockaddr_in *, + struct mbuf *, int)); +#ifdef INET6 +static void udp6_sendup __P((struct mbuf *, int, struct sockaddr *, + struct socket *)); +static int in6_mcmatch __P((struct in6pcb *, struct in6_addr *, + struct ifnet *)); +static int udp6_realinput __P((int, struct sockaddr_in6 *, + struct sockaddr_in6 *, struct mbuf *, int)); +#endif static void udp_notify __P((struct inpcb *, int)); #ifndef UDBHASHSIZE @@ -141,6 +164,704 @@ udp_input(m, va_alist) va_dcl #endif { + va_list ap; + struct sockaddr_in src, dst; + struct ip *ip; + struct udphdr *uh; + int iphlen, proto; + int len; + int n; + + va_start(ap, m); + iphlen = va_arg(ap, int); + proto = va_arg(ap, int); + va_end(ap); + + udpstat.udps_ipackets++; + +#ifndef PULLDOWN_TEST + /* + * Strip IP options, if any; should skip this, + * make available to user, and use on returned packets, + * but we don't yet have a way to check the checksum + * with options still present. + */ + if (iphlen > sizeof (struct ip)) { + ip_stripoptions(m, (struct mbuf *)0); + iphlen = sizeof(struct ip); + } +#else + /* + * we may enable the above code if we save and pass IPv4 options + * to the userland. + */ +#endif + + /* + * Get IP and UDP header together in first mbuf. + */ + ip = mtod(m, struct ip *); +#ifndef PULLDOWN_TEST + if (m->m_len < iphlen + sizeof(struct udphdr)) { + if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) { + udpstat.udps_hdrops++; + return; + } + ip = mtod(m, struct ip *); + } + uh = (struct udphdr *)((caddr_t)ip + iphlen); +#else + IP6_EXTHDR_GET(uh, struct udphdr *, m, iphlen, sizeof(struct udphdr)); + if (uh == NULL) { + udpstat.udps_hdrops++; + return; + } +#endif + + /* + * Make mbuf data length reflect UDP length. + * If not enough data to reflect UDP length, drop. + */ + len = ntohs((u_int16_t)uh->uh_ulen); + if (ip->ip_len != iphlen + len) { + if (ip->ip_len < iphlen + len) { + udpstat.udps_badlen++; + goto bad; + } + m_adj(m, iphlen + len - ip->ip_len); + } + + /* + * Checksum extended UDP header and data. + */ + if (uh->uh_sum) { +#ifndef PULLDOWN_TEST + struct ip save_ip; + + /* + * Save a copy of the IP header in case we want restore it + * for sending an ICMP error message in response. + */ + save_ip = *ip; + + bzero(((struct ipovly *)ip)->ih_x1, + sizeof ((struct ipovly *)ip)->ih_x1); + ((struct ipovly *)ip)->ih_len = uh->uh_ulen; + if (in_cksum(m, len + sizeof (struct ip)) != 0) { + udpstat.udps_badsum++; + m_freem(m); + return; + } + + *ip = save_ip; +#else + if (in4_cksum(m, IPPROTO_UDP, iphlen, len) != 0) { + udpstat.udps_badsum++; + m_freem(m); + return; + } +#endif + } + + /* construct source and dst sockaddrs. */ + bzero(&src, sizeof(src)); + src.sin_family = AF_INET; + src.sin_len = sizeof(struct sockaddr_in); + bcopy(&ip->ip_src, &src.sin_addr, sizeof(src.sin_addr)); + src.sin_port = uh->uh_sport; + bzero(&dst, sizeof(dst)); + dst.sin_family = AF_INET; + dst.sin_len = sizeof(struct sockaddr_in); + bcopy(&ip->ip_dst, &dst.sin_addr, sizeof(dst.sin_addr)); + dst.sin_port = uh->uh_dport; + + n = udp4_realinput(&src, &dst, m, iphlen); +#ifdef INET6 + if (IN_MULTICAST(ip->ip_dst.s_addr) || n == 0) { + struct sockaddr_in6 src6, dst6; + + bzero(&src6, sizeof(src6)); + src6.sin6_family = AF_INET6; + src6.sin6_len = sizeof(struct sockaddr_in6); + src6.sin6_addr.s6_addr[10] = src6.sin6_addr.s6_addr[11] = 0xff; + bcopy(&ip->ip_src, &src6.sin6_addr.s6_addr[12], + sizeof(ip->ip_src)); + src6.sin6_port = uh->uh_sport; + bzero(&dst6, sizeof(dst6)); + dst6.sin6_family = AF_INET6; + dst6.sin6_len = sizeof(struct sockaddr_in6); + dst6.sin6_addr.s6_addr[10] = dst6.sin6_addr.s6_addr[11] = 0xff; + bcopy(&ip->ip_dst, &dst6.sin6_addr.s6_addr[12], + sizeof(ip->ip_dst)); + dst6.sin6_port = uh->uh_dport; + + n += udp6_realinput(AF_INET, &src6, &dst6, m, iphlen); + } +#endif + + if (n == 0) { + udpstat.udps_noport++; + if (m->m_flags & (M_BCAST | M_MCAST)) { + udpstat.udps_noportbcast++; + goto bad; + } +#if NIPKDB > 0 + if (checkipkdb(&ip->ip_src, uh->uh_sport, uh->uh_dport, + m, iphlen + sizeof(struct udphdr), + m->m_pkthdr.len - iphlen - sizeof(struct udphdr))) { + /* + * It was a debugger connect packet, + * just drop it now + */ + goto bad; + } +#endif + icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0); + m = NULL; + } + +bad: + if (m) + m_freem(m); +} + +#ifdef INET6 +int +udp6_input(mp, offp, proto) + struct mbuf **mp; + int *offp, proto; +{ + struct mbuf *m = *mp; + int off = *offp; + struct sockaddr_in6 src, dst; + struct ip6_hdr *ip6; + struct udphdr *uh; + u_int32_t plen, ulen; + +#if defined(NFAITH) && 0 < NFAITH + if (m->m_pkthdr.rcvif) { + if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) { + /* send icmp6 host unreach? */ + m_freem(m); + return IPPROTO_DONE; + } + } +#endif + + udp6stat.udp6s_ipackets++; + +#ifndef PULLDOWN_TEST + IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE); +#endif + + ip6 = mtod(m, struct ip6_hdr *); + /* check for jumbogram is done in ip6_input. we can trust pkthdr.len */ + plen = m->m_pkthdr.len - off; +#ifndef PULLDOWN_TEST + uh = (struct udphdr *)((caddr_t)ip6 + off); +#else + IP6_EXTHDR_GET(uh, struct udphdr *, m, off, sizeof(struct udphdr)); + if (uh == NULL) { + ip6stat.ip6s_tooshort++; + return IPPROTO_DONE; + } +#endif + ulen = ntohs((u_short)uh->uh_ulen); + if (ulen == 0 && plen > 0xffff) + ulen = plen; + + if (plen != ulen) { + udp6stat.udp6s_badlen++; + goto bad; + } + + /* + * Checksum extended UDP header and data. + */ + if (uh->uh_sum == 0) + udp6stat.udp6s_nosum++; + else if (in6_cksum(m, IPPROTO_UDP, off, ulen) != 0) { + udp6stat.udp6s_badsum++; + goto bad; + } + + /* + * Construct source and dst sockaddrs. + * Note that ifindex (s6_addr16[1]) is already filled. + */ + bzero(&src, sizeof(src)); + src.sin6_family = AF_INET6; + src.sin6_len = sizeof(struct sockaddr_in6); + bcopy(&ip6->ip6_src, &src.sin6_addr, sizeof(src.sin6_addr)); + if (IN6_IS_SCOPE_LINKLOCAL(&src.sin6_addr)) + src.sin6_addr.s6_addr16[1] = 0; + if (m->m_pkthdr.rcvif) { + if (IN6_IS_SCOPE_LINKLOCAL(&src.sin6_addr)) + src.sin6_scope_id = m->m_pkthdr.rcvif->if_index; + else + src.sin6_scope_id = 0; + } + src.sin6_port = uh->uh_sport; + bzero(&dst, sizeof(dst)); + dst.sin6_family = AF_INET6; + dst.sin6_len = sizeof(struct sockaddr_in6); + bcopy(&ip6->ip6_dst, &dst.sin6_addr, sizeof(dst.sin6_addr)); + if (IN6_IS_SCOPE_LINKLOCAL(&dst.sin6_addr)) + dst.sin6_addr.s6_addr16[1] = 0; + if (m->m_pkthdr.rcvif) { + if (IN6_IS_SCOPE_LINKLOCAL(&dst.sin6_addr)) + dst.sin6_scope_id = m->m_pkthdr.rcvif->if_index; + else + dst.sin6_scope_id = 0; + } + dst.sin6_port = uh->uh_dport; + + if (udp6_realinput(AF_INET6, &src, &dst, m, off) == 0) { + udp6stat.udp6s_noport++; + if (m->m_flags & M_MCAST) { + udp6stat.udp6s_noportmcast++; + goto bad; + } + icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0); + m = NULL; + } + +bad: + if (m) + m_freem(m); + return IPPROTO_DONE; +} +#endif + +static void +udp4_sendup(m, off, src, so) + struct mbuf *m; + int off; /* offset of data portion */ + struct sockaddr *src; + struct socket *so; +{ + struct mbuf *opts = NULL; + struct mbuf *n; + struct inpcb *inp = NULL; +#ifdef INET6 + struct in6pcb *in6p = NULL; +#endif + + if (!so) + return; + switch (so->so_proto->pr_domain->dom_family) { + case AF_INET: + inp = sotoinpcb(so); + break; +#ifdef INET6 + case AF_INET6: + in6p = sotoin6pcb(so); + break; +#endif + default: + return; + } + +#ifdef IPSEC + /* check AH/ESP integrity. */ + if (so != NULL && ipsec4_in_reject_so(m, so)) { + ipsecstat.in_polvio++; + return; + } +#endif /*IPSEC*/ + + if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { + if (inp && (inp->inp_flags & INP_CONTROLOPTS + || so->so_options & SO_TIMESTAMP)) { + struct ip *ip = mtod(n, struct ip *); + ip_savecontrol(inp, &opts, ip, n); + } + + m_adj(n, off); + if (sbappendaddr(&so->so_rcv, src, n, + opts) == 0) { + m_freem(n); + if (opts) + m_freem(opts); + } else + sorwakeup(so); + } +} + +#ifdef INET6 +static void +udp6_sendup(m, off, src, so) + struct mbuf *m; + int off; /* offset of data portion */ + struct sockaddr *src; + struct socket *so; +{ + struct mbuf *opts = NULL; + struct mbuf *n; + struct in6pcb *in6p = NULL; + + if (!so) + return; + if (so->so_proto->pr_domain->dom_family != AF_INET6) + return; + in6p = sotoin6pcb(so); + +#ifdef IPSEC + /* check AH/ESP integrity. */ + if (so != NULL && ipsec6_in_reject_so(m, so)) { + ipsec6stat.in_polvio++; + return; + } +#endif /*IPSEC*/ + + if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { + if (in6p && (in6p->in6p_flags & IN6P_CONTROLOPTS + || in6p->in6p_socket->so_options & SO_TIMESTAMP)) { + struct ip6_hdr *ip6 = mtod(n, struct ip6_hdr *); + ip6_savecontrol(in6p, &opts, ip6, n); + } + + m_adj(n, off); + if (sbappendaddr(&so->so_rcv, src, n, opts) == 0) { + m_freem(n); + if (opts) + m_freem(opts); + udp6stat.udp6s_fullsock++; + } else + sorwakeup(so); + } +} +#endif + +static int +udp4_realinput(src, dst, m, off) + struct sockaddr_in *src; + struct sockaddr_in *dst; + struct mbuf *m; + int off; /* offset of udphdr */ +{ + u_int16_t *sport, *dport; + int rcvcnt; + struct in_addr *src4, *dst4; + struct inpcb *inp; + + rcvcnt = 0; + off += sizeof(struct udphdr); /* now, offset of payload */ + + if (src->sin_family != AF_INET || dst->sin_family != AF_INET) + goto bad; + + src4 = &src->sin_addr; + sport = &src->sin_port; + dst4 = &dst->sin_addr; + dport = &dst->sin_port; + + if (IN_MULTICAST(src4->s_addr) || + in_broadcast(*dst4, m->m_pkthdr.rcvif)) { + struct inpcb *last; + /* + * Deliver a multicast or broadcast datagram to *all* sockets + * for which the local and remote addresses and ports match + * those of the incoming datagram. This allows more than + * one process to receive multi/broadcasts on the same port. + * (This really ought to be done for unicast datagrams as + * well, but that would cause problems with existing + * applications that open both address-specific sockets and + * a wildcard socket listening to the same port -- they would + * end up receiving duplicates of every unicast datagram. + * Those applications open the multiple sockets to overcome an + * inadequacy of the UDP socket interface, but for backwards + * compatibility we avoid the problem here rather than + * fixing the interface. Maybe 4.5BSD will remedy this?) + */ + + /* + * KAME note: usually we drop udpiphdr from mbuf here. + * we need udpiphdr for iPsec processing so we do that later. + */ + /* + * Locate pcb(s) for datagram. + */ + for (inp = udbtable.inpt_queue.cqh_first; + inp != (struct inpcb *)&udbtable.inpt_queue; + inp = inp->inp_queue.cqe_next) { + if (inp->inp_lport != *dport) + continue; + if (!in_nullhost(inp->inp_laddr)) { + if (!in_hosteq(inp->inp_laddr, *dst4)) + continue; + } + if (!in_nullhost(inp->inp_faddr)) { + if (!in_hosteq(inp->inp_faddr, *src4) || + inp->inp_fport != *sport) + continue; + } + + last = inp; + udp4_sendup(m, off, (struct sockaddr *)src, + inp->inp_socket); + rcvcnt++; + + /* + * Don't look for additional matches if this one does + * not have either the SO_REUSEPORT or SO_REUSEADDR + * socket options set. This heuristic avoids searching + * through all pcbs in the common case of a non-shared + * port. It assumes that an application will never + * clear these options after setting them. + */ + if ((inp->inp_socket->so_options & + (SO_REUSEPORT|SO_REUSEADDR)) == 0) + break; + } + +#if 0 + if (last == NULL) { + /* + * No matching pcb found; discard datagram. + * (No need to send an ICMP Port Unreachable + * for a broadcast or multicast datgram.) + */ + udpstat.udps_noport++; + udpstat.udps_noportbcast++; + goto bad; + } +#endif + } else { + /* + * Locate pcb for datagram. + */ + inp = in_pcblookup_connect(&udbtable, *src4, *sport, *dst4, *dport); + if (inp == 0) { + ++udpstat.udps_pcbhashmiss; + inp = in_pcblookup_bind(&udbtable, *dst4, *dport); + if (inp == 0) { +#if 0 + struct mbuf *n; + + udpstat.udps_noport++; + if (m->m_flags & (M_BCAST | M_MCAST)) { + udpstat.udps_noportbcast++; + goto bad; + } +#if NIPKDB > 0 + if (checkipkdb(src4, *sport, *dport, m, off, + m->m_pkthdr.len - off)) { + /* + * It was a debugger connect packet, + * just drop it now + */ + goto bad; + } +#endif + if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { + icmp_error(n, ICMP_UNREACH, + ICMP_UNREACH_PORT, 0, 0); + } +#endif + return rcvcnt; + } + } + + udp4_sendup(m, off, (struct sockaddr *)src, inp->inp_socket); + rcvcnt++; + } + +bad: + return rcvcnt; +} + +#ifdef INET6 +static int +in6_mcmatch(in6p, ia6, ifp) + struct in6pcb *in6p; + register struct in6_addr *ia6; + struct ifnet *ifp; +{ + struct ip6_moptions *im6o = in6p->in6p_moptions; + struct in6_multi_mship *imm; + + if (im6o == NULL) + return 0; + + for (imm = im6o->im6o_memberships.lh_first; imm != NULL; + imm = imm->i6mm_chain.le_next) { + if ((ifp == NULL || + imm->i6mm_maddr->in6m_ifp == ifp) && + IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr, + ia6)) + return 1; + } + return 0; +} + +static int +udp6_realinput(af, src, dst, m, off) + int af; /* af on packet */ + struct sockaddr_in6 *src; + struct sockaddr_in6 *dst; + struct mbuf *m; + int off; /* offset of udphdr */ +{ + u_int16_t *sport, *dport; + int rcvcnt; + struct in6_addr *src6, *dst6; + struct in_addr *src4; + struct in6pcb *in6p; + + rcvcnt = 0; + off += sizeof(struct udphdr); /* now, offset of payload */ + + if (af != AF_INET && af != AF_INET6) + goto bad; + if (src->sin6_family != AF_INET6 || dst->sin6_family != AF_INET6) + goto bad; + + src6 = &src->sin6_addr; + sport = &src->sin6_port; + dst6 = &dst->sin6_addr; + dport = &dst->sin6_port; + src4 = (struct in_addr *)&src->sin6_addr.s6_addr32[12]; + + if (IN6_IS_ADDR_MULTICAST(dst6) + || (af == AF_INET && IN_MULTICAST(src4->s_addr))) { + struct in6pcb *last; + /* + * Deliver a multicast or broadcast datagram to *all* sockets + * for which the local and remote addresses and ports match + * those of the incoming datagram. This allows more than + * one process to receive multi/broadcasts on the same port. + * (This really ought to be done for unicast datagrams as + * well, but that would cause problems with existing + * applications that open both address-specific sockets and + * a wildcard socket listening to the same port -- they would + * end up receiving duplicates of every unicast datagram. + * Those applications open the multiple sockets to overcome an + * inadequacy of the UDP socket interface, but for backwards + * compatibility we avoid the problem here rather than + * fixing the interface. Maybe 4.5BSD will remedy this?) + */ + + /* + * KAME note: usually we drop udpiphdr from mbuf here. + * we need udpiphdr for iPsec processing so we do that later. + */ + /* + * Locate pcb(s) for datagram. + */ + for (in6p = udb6.in6p_next; in6p != &udb6; + in6p = in6p->in6p_next) { + if (in6p->in6p_lport != *dport) + continue; + if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) { + if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, dst6) + && !in6_mcmatch(in6p, dst6, m->m_pkthdr.rcvif)) + continue; + } + if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { + if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, src6) + || in6p->in6p_fport != *sport) + continue; + } + + last = in6p; + udp6_sendup(m, off, (struct sockaddr *)src, + in6p->in6p_socket); + rcvcnt++; + + /* + * Don't look for additional matches if this one does + * not have either the SO_REUSEPORT or SO_REUSEADDR + * socket options set. This heuristic avoids searching + * through all pcbs in the common case of a non-shared + * port. It assumes that an application will never + * clear these options after setting them. + */ + if ((in6p->in6p_socket->so_options & + (SO_REUSEPORT|SO_REUSEADDR)) == 0) + break; + } + +#if 0 + if (last == NULL) { + /* + * No matching pcb found; discard datagram. + * (No need to send an ICMP Port Unreachable + * for a broadcast or multicast datgram.) + */ + switch (af) { + case AF_INET: + udpstat.udps_noport++; + udpstat.udps_noportbcast++; + break; + case AF_INET6: + udp6stat.udp6s_noport++; + udp6stat.udp6s_noportmcast++; + break; + } + goto bad; + } +#endif + } else { + /* + * Locate pcb for datagram. + */ + in6p = in6_pcblookup_connect(&udb6, src6, *sport, + dst6, *dport, 0); + if (in6p == 0) { + ++udpstat.udps_pcbhashmiss; + in6p = in6_pcblookup_bind(&udb6, dst6, *dport, 0); + if (in6p == 0) { +#if 0 + struct mbuf *n; + n = m_copy(m, 0, M_COPYALL); + switch (af) { + case AF_INET: + udpstat.udps_noport++; + if (m->m_flags & (M_BCAST | M_MCAST)) { + udpstat.udps_noportbcast++; + goto bad; + } + if (n != NULL) + icmp_error(n, ICMP_UNREACH, + ICMP_UNREACH_PORT, 0, 0); + break; + case AF_INET6: + udp6stat.udp6s_noport++; + if (m->m_flags & M_MCAST) { + udp6stat.udp6s_noportmcast++; + goto bad; + } + if (n != NULL) + icmp6_error(n, ICMP6_DST_UNREACH, + ICMP6_DST_UNREACH_NOPORT, 0); + break; + } +#endif + + return rcvcnt; + } + } + + udp6_sendup(m, off, (struct sockaddr *)src, in6p->in6p_socket); + rcvcnt++; + } + +bad: + return rcvcnt; +} +#endif + +#if 0 +void +#if __STDC__ +udp_input(struct mbuf *m, ...) +#else +udp_input(m, va_alist) + struct mbuf *m; + va_dcl +#endif +{ int proto; register struct ip *ip; register struct udphdr *uh; @@ -151,9 +872,6 @@ udp_input(m, va_alist) int iphlen; va_list ap; struct sockaddr_in udpsrc; -#ifdef MAPPED_ADDR_ENABLED - struct sockaddr_in6 mapped; -#endif struct sockaddr *sa; va_start(ap, m); @@ -291,14 +1009,6 @@ udp_input(m, va_alist) } m_adj(n, iphlen); sa = (struct sockaddr *)&udpsrc; -#ifdef MAPPED_ADDR_ENABLED - if (last->inp_socket->so_proto-> - pr_domain->dom_family == AF_INET6) { - in6_sin_2_v4mapsin6(&udpsrc, - &mapped); - sa = (struct sockaddr *)&mapped; - } -#endif /* MAPPED_ADDR_ENABLED */ if (sbappendaddr( &last->inp_socket->so_rcv, sa, n, opts) == 0) { @@ -348,13 +1058,6 @@ udp_input(m, va_alist) m->m_pkthdr.len -= iphlen; m->m_data += iphlen; sa = (struct sockaddr *)&udpsrc; -#ifdef MAPPED_ADDR_ENABLED - if (last->inp_socket->so_proto->pr_domain->dom_family == - AF_INET6) { - in6_sin_2_v4mapsin6(&udpsrc, &mapped); - sa = (struct sockaddr *)&mapped; - } -#endif /* MAPPED_ADDR_ENABLED */ if (sbappendaddr(&last->inp_socket->so_rcv, sa, m, opts) == 0) { udpstat.udps_fullsock++; goto bad; @@ -409,12 +1112,6 @@ udp_input(m, va_alist) m->m_pkthdr.len -= iphlen; m->m_data += iphlen; sa = (struct sockaddr *)&udpsrc; -#ifdef MAPPED_ADDR_ENABLED - if (inp->inp_socket->so_proto->pr_domain->dom_family == AF_INET6) { - in6_sin_2_v4mapsin6(&udpsrc, &mapped); - sa = (struct sockaddr *)&mapped; - } -#endif /* MAPPED_ADDR_ENABLED */ if (sbappendaddr(&inp->inp_socket->so_rcv, sa, m, opts) == 0) { udpstat.udps_fullsock++; goto bad; @@ -426,6 +1123,7 @@ bad: if (opts) m_freem(opts); } +#endif /* * Notify a udp user of an asynchronous error; @@ -454,8 +1152,8 @@ udp_ctlinput(cmd, sa, v) void (*notify) __P((struct inpcb *, int)) = udp_notify; int errno; - if (sa->sa_family != AF_INET || - sa->sa_len != sizeof(struct sockaddr_in)) + if (sa->sa_family != AF_INET + || sa->sa_len != sizeof(struct sockaddr_in)) return NULL; if ((unsigned)cmd >= PRC_NCMDS) return NULL; @@ -470,6 +1168,8 @@ udp_ctlinput(cmd, sa, v) uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); in_pcbnotify(&udbtable, satosin(sa)->sin_addr, uh->uh_dport, ip->ip_src, uh->uh_sport, errno, notify); + + /* XXX mapped address case */ } else in_pcbnotifyall(&udbtable, satosin(sa)->sin_addr, errno, notify); @@ -607,9 +1307,11 @@ udp_usrreq(so, req, m, nam, control, p) inp = sotoinpcb(so); inp->inp_ip.ip_ttl = ip_defttl; #ifdef IPSEC - inp = (struct inpcb *)so->so_pcb; - if ((error = ipsec_init_policy(&inp->inp_sp)) != 0) + error = ipsec_init_policy(&inp->inp_sp); + if (error != 0) { in_pcbdetach(inp); + break; + } #endif /*IPSEC*/ break; |
