summaryrefslogtreecommitdiff
path: root/sys/netinet
diff options
context:
space:
mode:
authoritojun <itojun@NetBSD.org>1999-12-13 15:17:17 +0000
committeritojun <itojun@NetBSD.org>1999-12-13 15:17:17 +0000
commitea861f0183f07970865fa35737f2b42e49e3aba0 (patch)
tree66276ba5ce54db63f1e39e0faf66b6d48a561f54 /sys/netinet
parent1501f61891a7a207cce1aa417e23eb96889384b2 (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.h3
-rw-r--r--sys/netinet/in4_cksum.c7
-rw-r--r--sys/netinet/in_gif.c40
-rw-r--r--sys/netinet/in_pcb.c7
-rw-r--r--sys/netinet/in_proto.c10
-rw-r--r--sys/netinet/ip_ipip.c7
-rw-r--r--sys/netinet/ip_output.c47
-rw-r--r--sys/netinet/raw_ip.c10
-rw-r--r--sys/netinet/tcp_input.c57
-rw-r--r--sys/netinet/tcp_output.c22
-rw-r--r--sys/netinet/tcp_subr.c68
-rw-r--r--sys/netinet/tcp_usrreq.c20
-rw-r--r--sys/netinet/tcp_var.h5
-rw-r--r--sys/netinet/udp_usrreq.c770
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;