Module Name: src Committed By: tls Date: Sun Aug 10 06:56:30 UTC 2014
Modified Files: src/sys/netinet6 [tls-earlyentropy]: icmp6.c in6.c in6.h in6_gif.c in6_ifattach.c in6_pcb.c in6_pcb.h in6_proto.c in6_src.c in6_var.h ip6_flow.c ip6_forward.c ip6_input.c ip6_mroute.c ip6_output.c ip6_var.h ip6protosw.h mld6.c nd6.c nd6.h nd6_nbr.c nd6_rtr.c raw_ip6.c scope6.c udp6_usrreq.c udp6_var.h Log Message: Rebase. To generate a diff of this commit: cvs rdiff -u -r1.165 -r1.165.2.1 src/sys/netinet6/icmp6.c cvs rdiff -u -r1.169 -r1.169.2.1 src/sys/netinet6/in6.c cvs rdiff -u -r1.75 -r1.75.2.1 src/sys/netinet6/in6.h cvs rdiff -u -r1.59 -r1.59.10.1 src/sys/netinet6/in6_gif.c cvs rdiff -u -r1.89 -r1.89.2.1 src/sys/netinet6/in6_ifattach.c cvs rdiff -u -r1.124 -r1.124.2.1 src/sys/netinet6/in6_pcb.c cvs rdiff -u -r1.37 -r1.37.12.1 src/sys/netinet6/in6_pcb.h cvs rdiff -u -r1.100 -r1.100.2.1 src/sys/netinet6/in6_proto.c cvs rdiff -u -r1.53 -r1.53.12.1 src/sys/netinet6/in6_src.c cvs rdiff -u -r1.68 -r1.68.2.1 src/sys/netinet6/in6_var.h cvs rdiff -u -r1.22 -r1.22.2.1 src/sys/netinet6/ip6_flow.c cvs rdiff -u -r1.72 -r1.72.4.1 src/sys/netinet6/ip6_forward.c cvs rdiff -u -r1.145 -r1.145.2.1 src/sys/netinet6/ip6_input.c cvs rdiff -u -r1.106 -r1.106.2.1 src/sys/netinet6/ip6_mroute.c cvs rdiff -u -r1.155 -r1.155.2.1 src/sys/netinet6/ip6_output.c cvs rdiff -u -r1.59 -r1.59.12.1 src/sys/netinet6/ip6_var.h cvs rdiff -u -r1.21 -r1.21.54.1 src/sys/netinet6/ip6protosw.h cvs rdiff -u -r1.55 -r1.55.22.1 src/sys/netinet6/mld6.c cvs rdiff -u -r1.148 -r1.148.2.1 src/sys/netinet6/nd6.c cvs rdiff -u -r1.58 -r1.58.6.1 src/sys/netinet6/nd6.h cvs rdiff -u -r1.99 -r1.99.2.1 src/sys/netinet6/nd6_nbr.c cvs rdiff -u -r1.90 -r1.90.2.1 src/sys/netinet6/nd6_rtr.c cvs rdiff -u -r1.113 -r1.113.2.1 src/sys/netinet6/raw_ip6.c cvs rdiff -u -r1.8 -r1.8.36.1 src/sys/netinet6/scope6.c cvs rdiff -u -r1.93 -r1.93.2.1 src/sys/netinet6/udp6_usrreq.c cvs rdiff -u -r1.25 -r1.25.12.1 src/sys/netinet6/udp6_var.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/netinet6/icmp6.c diff -u src/sys/netinet6/icmp6.c:1.165 src/sys/netinet6/icmp6.c:1.165.2.1 --- src/sys/netinet6/icmp6.c:1.165 Tue Feb 25 18:30:12 2014 +++ src/sys/netinet6/icmp6.c Sun Aug 10 06:56:30 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: icmp6.c,v 1.165 2014/02/25 18:30:12 pooka Exp $ */ +/* $NetBSD: icmp6.c,v 1.165.2.1 2014/08/10 06:56:30 tls Exp $ */ /* $KAME: icmp6.c,v 1.217 2001/06/20 15:03:29 jinmei Exp $ */ /* @@ -62,14 +62,14 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: icmp6.c,v 1.165 2014/02/25 18:30:12 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: icmp6.c,v 1.165.2.1 2014/08/10 06:56:30 tls Exp $"); #include "opt_inet.h" #include "opt_ipsec.h" #include <sys/param.h> #include <sys/systm.h> -#include <sys/malloc.h> +#include <sys/kmem.h> #include <sys/mbuf.h> #include <sys/protosw.h> #include <sys/socket.h> @@ -253,10 +253,7 @@ icmp6_mtudisc_callback_register(void (*f return; } - mc = malloc(sizeof(*mc), M_PCB, M_NOWAIT); - if (mc == NULL) - panic("icmp6_mtudisc_callback_register"); - + mc = kmem_alloc(sizeof(*mc), KM_SLEEP); mc->mc_func = func; LIST_INSERT_HEAD(&icmp6_mtudisc_callbacks, mc, mc_list); } @@ -1135,8 +1132,8 @@ icmp6_mtudisc_update(struct ip6ctlparam rt->rt_rmx.rmx_mtu = mtu; } } - if (rt) { /* XXX: need braces to avoid conflict with else in RTFREE. */ - RTFREE(rt); + if (rt) { + rtfree(rt); } /* @@ -1717,7 +1714,7 @@ ni6_store_addrs(struct icmp6_nodeinfo *n struct icmp6_nodeinfo *nni6, struct ifnet *ifp0, int resid) { - struct ifnet *ifp = ifp0 ? ifp0 : TAILQ_FIRST(&ifnet); + struct ifnet *ifp = ifp0 ? ifp0 : IFNET_FIRST(); struct in6_ifaddr *ifa6; struct ifaddr *ifa; struct ifnet *ifp_dep = NULL; @@ -2191,7 +2188,7 @@ icmp6_redirect_input(struct mbuf *m, int "ICMP6 redirect rejected; no route " "with inet6 gateway found for redirect dst: %s\n", icmp6_redirect_diag(&src6, &reddst6, &redtgt6))); - RTFREE(rt); + rtfree(rt); goto bad; } @@ -2203,7 +2200,7 @@ icmp6_redirect_input(struct mbuf *m, int "%s\n", ip6_sprintf(gw6), icmp6_redirect_diag(&src6, &reddst6, &redtgt6))); - RTFREE(rt); + rtfree(rt); goto bad; } } else { @@ -2213,7 +2210,7 @@ icmp6_redirect_input(struct mbuf *m, int icmp6_redirect_diag(&src6, &reddst6, &redtgt6))); goto bad; } - RTFREE(rt); + rtfree(rt); rt = NULL; } if (IN6_IS_ADDR_MULTICAST(&reddst6)) { @@ -2319,7 +2316,8 @@ icmp6_redirect_input(struct mbuf *m, int sockaddr_in6_init(&sdst, &reddst6, 0, 0, 0); pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&sdst); #if defined(IPSEC) - key_sa_routechange((struct sockaddr *)&sdst); + if (ipsec_used) + key_sa_routechange((struct sockaddr *)&sdst); #endif } Index: src/sys/netinet6/in6.c diff -u src/sys/netinet6/in6.c:1.169 src/sys/netinet6/in6.c:1.169.2.1 --- src/sys/netinet6/in6.c:1.169 Wed Jan 15 10:52:11 2014 +++ src/sys/netinet6/in6.c Sun Aug 10 06:56:30 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: in6.c,v 1.169 2014/01/15 10:52:11 roy Exp $ */ +/* $NetBSD: in6.c,v 1.169.2.1 2014/08/10 06:56:30 tls Exp $ */ /* $KAME: in6.c,v 1.198 2001/07/18 09:12:38 itojun Exp $ */ /* @@ -62,7 +62,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.169 2014/01/15 10:52:11 roy Exp $"); +__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.169.2.1 2014/08/10 06:56:30 tls Exp $"); #include "opt_inet.h" #include "opt_compat_netbsd.h" @@ -139,7 +139,7 @@ const struct sockaddr_in6 sa6_any = {siz 0, 0, IN6ADDR_ANY_INIT, 0}; static int in6_lifaddr_ioctl(struct socket *, u_long, void *, - struct ifnet *, struct lwp *); + struct ifnet *); static int in6_ifinit(struct ifnet *, struct in6_ifaddr *, const struct sockaddr_in6 *, int); static void in6_unlink_ifa(struct in6_ifaddr *, struct ifnet *); @@ -360,8 +360,7 @@ in6_mask2len(struct in6_addr *mask, u_ch #define ia62ifa(ia6) (&((ia6)->ia_ifa)) static int -in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp, - lwp_t *l) +in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp) { struct in6_ifreq *ifr = (struct in6_ifreq *)data; struct in6_ifaddr *ia = NULL; @@ -385,7 +384,7 @@ in6_control1(struct socket *so, u_long c case SIOCSIFADDRPREF: if (ifp == NULL) return EINVAL; - return ifaddrpref_ioctl(so, cmd, data, ifp, l); + return ifaddrpref_ioctl(so, cmd, data, ifp); } if (ifp == NULL) @@ -428,7 +427,7 @@ in6_control1(struct socket *so, u_long c /* Privileged. */ /* FALLTHROUGH */ case SIOCGLIFADDR: - return in6_lifaddr_ioctl(so, cmd, data, ifp, l); + return in6_lifaddr_ioctl(so, cmd, data, ifp); } /* @@ -784,8 +783,7 @@ in6_control1(struct socket *so, u_long c } int -in6_control(struct socket *so, u_long cmd, void *data, struct ifnet *ifp, - struct lwp *l) +in6_control(struct socket *so, u_long cmd, void *data, struct ifnet *ifp) { int error, s; @@ -805,7 +803,7 @@ in6_control(struct socket *so, u_long cm case OSIOCAIFADDR_IN6: #endif case SIOCAIFADDR_IN6: - if (kauth_authorize_network(l->l_cred, + if (kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_SOCKET, KAUTH_REQ_NETWORK_SOCKET_SETPRIV, so, NULL, NULL)) @@ -814,7 +812,7 @@ in6_control(struct socket *so, u_long cm } s = splnet(); - error = in6_control1(so , cmd, data, ifp, l); + error = in6_control1(so , cmd, data, ifp); splx(s); return error; } @@ -1168,7 +1166,7 @@ in6_update_ifa1(struct ifnet *ifp, struc if (memcmp(&mltaddr.sin6_addr, &satocsin6(rt_getkey(rt))->sin6_addr, MLTMASK_LEN)) { - RTFREE(rt); + rtfree(rt); rt = NULL; } else if (rt->rt_ifp != ifp) { IN6_DPRINTF("%s: rt_ifp %p -> %p (%s) " @@ -1199,7 +1197,7 @@ in6_update_ifa1(struct ifnet *ifp, struc if (error) goto cleanup; } else { - RTFREE(rt); + rtfree(rt); } imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0); if (!imm) { @@ -1253,7 +1251,7 @@ in6_update_ifa1(struct ifnet *ifp, struc if (memcmp(&mltaddr.sin6_addr, &satocsin6(rt_getkey(rt))->sin6_addr, 32 / NBBY)) { - RTFREE(rt); + rtfree(rt); rt = NULL; } else if (rt->rt_ifp != ifp) { IN6_DPRINTF("%s: rt_ifp %p -> %p (%s) " @@ -1284,7 +1282,7 @@ in6_update_ifa1(struct ifnet *ifp, struc goto cleanup; #undef MLTMASK_LEN } else { - RTFREE(rt); + rtfree(rt); } imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0); if (!imm) { @@ -1333,7 +1331,8 @@ in6_update_ifa1(struct ifnet *ifp, struc mindelay; } } - nd6_dad_start(&ia->ia_ifa, dad_delay); + /* +1 ensures callout is always used */ + nd6_dad_start(&ia->ia_ifa, dad_delay + 1); } return error; @@ -1508,7 +1507,7 @@ in6_purgeif(struct ifnet *ifp) */ static int in6_lifaddr_ioctl(struct socket *so, u_long cmd, void *data, - struct ifnet *ifp, struct lwp *l) + struct ifnet *ifp) { struct in6_ifaddr *ia; struct if_laddrreq *iflr = (struct if_laddrreq *)data; @@ -1618,7 +1617,7 @@ in6_lifaddr_ioctl(struct socket *so, u_l ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; ifra.ifra_flags = iflr->flags & ~IFLR_PREFIX; - return in6_control(so, SIOCAIFADDR_IN6, &ifra, ifp, l); + return in6_control(so, SIOCAIFADDR_IN6, &ifra, ifp); } case SIOCGLIFADDR: case SIOCDLIFADDR: @@ -1729,7 +1728,7 @@ in6_lifaddr_ioctl(struct socket *so, u_l ia->ia_prefixmask.sin6_len); ifra.ifra_flags = ia->ia6_flags; - return in6_control(so, SIOCDIFADDR_IN6, &ifra, ifp, l); + return in6_control(so, SIOCDIFADDR_IN6, &ifra, ifp); } } } @@ -2157,15 +2156,17 @@ in6_if_link_up(struct ifnet *ifp) } if (ia->ia6_flags & IN6_IFF_TENTATIVE) { + int rand_delay; /* * The TENTATIVE flag was likely set by hand * beforehand, implicitly indicating the need for DAD. * We may be able to skip the random delay in this * case, but we impose delays just in case. */ - nd6_dad_start(ifa, - cprng_fast32() % - (MAX_RTR_SOLICITATION_DELAY * hz)); + rand_delay = cprng_fast32() % + (MAX_RTR_SOLICITATION_DELAY * hz); + /* +1 ensures callout is always used */ + nd6_dad_start(ifa, rand_delay + 1); } } @@ -2274,7 +2275,7 @@ in6_setmaxmtu(void) unsigned long maxmtu = 0; struct ifnet *ifp; - TAILQ_FOREACH(ifp, &ifnet, if_list) { + IFNET_FOREACH(ifp) { /* this function can be called during ifnet initialization */ if (!ifp->if_afdata[AF_INET6]) continue; Index: src/sys/netinet6/in6.h diff -u src/sys/netinet6/in6.h:1.75 src/sys/netinet6/in6.h:1.75.2.1 --- src/sys/netinet6/in6.h:1.75 Sat Oct 19 15:44:29 2013 +++ src/sys/netinet6/in6.h Sun Aug 10 06:56:30 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: in6.h,v 1.75 2013/10/19 15:44:29 christos Exp $ */ +/* $NetBSD: in6.h,v 1.75.2.1 2014/08/10 06:56:30 tls Exp $ */ /* $KAME: in6.h,v 1.83 2001/03/29 02:55:07 jinmei Exp $ */ /* @@ -403,9 +403,7 @@ extern const struct in6_addr in6addr_lin #define IPV6_CHECKSUM 26 /* int; checksum offset for raw socket */ #define IPV6_V6ONLY 27 /* bool; make AF_INET6 sockets v6 only */ -#if 1 /* IPSEC */ #define IPV6_IPSEC_POLICY 28 /* struct; get/set security policy */ -#endif #define IPV6_FAITH 29 /* bool; accept FAITH'ed connections */ /* new socket options introduced in RFC3542 */ @@ -573,11 +571,13 @@ struct ip6_mtuinfo { #define IPV6CTL_ANONPORTMAX 29 /* maximum ephemeral port */ #define IPV6CTL_LOWPORTMIN 30 /* minimum reserved port */ #define IPV6CTL_LOWPORTMAX 31 /* maximum reserved port */ -/* 32 to 38: reserved */ +/* 32 to 34: reserved */ +#define IPV6CTL_AUTO_LINKLOCAL 35 /* automatic link-local addr assign */ +/* 36 to 38: reserved */ #define IPV6CTL_USE_DEFAULTZONE 39 /* use default scope zone */ /* 40: reserved */ #define IPV6CTL_MAXFRAGS 41 /* max fragments */ -#define IPV6CTL_IFQ 42 /* ip6intrq node */ +#define IPV6CTL_IFQ 42 /* IPv6 packet input queue */ #define IPV6CTL_RTADV_MAXROUTES 43 /* maximum number of routes */ /* via router advertisement */ #define IPV6CTL_RTADV_NUMROUTES 44 /* current number of routes */ Index: src/sys/netinet6/in6_gif.c diff -u src/sys/netinet6/in6_gif.c:1.59 src/sys/netinet6/in6_gif.c:1.59.10.1 --- src/sys/netinet6/in6_gif.c:1.59 Fri Mar 1 18:25:58 2013 +++ src/sys/netinet6/in6_gif.c Sun Aug 10 06:56:30 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: in6_gif.c,v 1.59 2013/03/01 18:25:58 joerg Exp $ */ +/* $NetBSD: in6_gif.c,v 1.59.10.1 2014/08/10 06:56:30 tls Exp $ */ /* $KAME: in6_gif.c,v 1.62 2001/07/29 04:27:25 itojun Exp $ */ /* @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: in6_gif.c,v 1.59 2013/03/01 18:25:58 joerg Exp $"); +__KERNEL_RCSID(0, "$NetBSD: in6_gif.c,v 1.59.10.1 2014/08/10 06:56:30 tls Exp $"); #include "opt_inet.h" @@ -441,16 +441,20 @@ in6_gif_ctlinput(int cmd, const struct s PR_WRAP_CTLINPUT(in6_gif_ctlinput) PR_WRAP_CTLOUTPUT(rip6_ctloutput) -PR_WRAP_USRREQ(rip6_usrreq) #define in6_gif_ctlinput in6_gif_ctlinput_wrapper #define rip6_ctloutput rip6_ctloutput_wrapper -#define rip6_usrreq rip6_usrreq_wrapper extern struct domain inet6domain; -const struct ip6protosw in6_gif_protosw = -{ SOCK_RAW, &inet6domain, 0/* IPPROTO_IPV[46] */, PR_ATOMIC|PR_ADDR, - in6_gif_input, rip6_output, in6_gif_ctlinput, rip6_ctloutput, - rip6_usrreq, - 0, 0, 0, 0, + +const struct ip6protosw in6_gif_protosw = { + .pr_type = SOCK_RAW, + .pr_domain = &inet6domain, + .pr_protocol = 0 /* IPPROTO_IPV[46] */, + .pr_flags = PR_ATOMIC | PR_ADDR, + .pr_input = in6_gif_input, + .pr_output = rip6_output, + .pr_ctlinput = in6_gif_ctlinput, + .pr_ctloutput = rip6_ctloutput, + .pr_usrreqs = &rip6_usrreqs, }; Index: src/sys/netinet6/in6_ifattach.c diff -u src/sys/netinet6/in6_ifattach.c:1.89 src/sys/netinet6/in6_ifattach.c:1.89.2.1 --- src/sys/netinet6/in6_ifattach.c:1.89 Fri Oct 25 15:44:39 2013 +++ src/sys/netinet6/in6_ifattach.c Sun Aug 10 06:56:30 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: in6_ifattach.c,v 1.89 2013/10/25 15:44:39 martin Exp $ */ +/* $NetBSD: in6_ifattach.c,v 1.89.2.1 2014/08/10 06:56:30 tls Exp $ */ /* $KAME: in6_ifattach.c,v 1.124 2001/07/18 08:32:51 jinmei Exp $ */ /* @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: in6_ifattach.c,v 1.89 2013/10/25 15:44:39 martin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: in6_ifattach.c,v 1.89.2.1 2014/08/10 06:56:30 tls Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -473,7 +473,7 @@ get_ifid(struct ifnet *ifp0, struct ifne } /* next, try to get it from some other hardware interface */ - TAILQ_FOREACH(ifp, &ifnet, if_list) { + IFNET_FOREACH(ifp) { if (ifp == ifp0) continue; if (in6_get_hw_ifid(ifp, in6) != 0) @@ -754,6 +754,8 @@ in6_ifattach(struct ifnet *ifp, struct i #ifdef IFT_PFSYNC case IFT_PFSYNC: #endif + ND_IFINFO(ifp)->flags &= ~ND6_IFF_AUTO_LINKLOCAL; + ND_IFINFO(ifp)->flags |= ND6_IFF_IFDISABLED; return; } @@ -784,6 +786,7 @@ in6_ifattach(struct ifnet *ifp, struct i * linklocals for 6to4 interface, but there's no use and * it is rather harmful to have one. */ + ND_IFINFO(ifp)->flags &= ~ND6_IFF_AUTO_LINKLOCAL; return; #endif case IFT_CARP: @@ -817,7 +820,9 @@ in6_ifattach(struct ifnet *ifp, struct i /* * assign a link-local address, if there's none. */ - if (ip6_auto_linklocal) { + if (!(ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) && + ND_IFINFO(ifp)->flags & ND6_IFF_AUTO_LINKLOCAL) + { ia = in6ifa_ifpforlinklocal(ifp, 0); if (ia == NULL && in6_ifattach_linklocal(ifp, altifp) != 0) { printf("%s: cannot assign link-local address\n", @@ -962,7 +967,7 @@ in6_tmpaddrtimer(void *ignored_arg) ip6_temp_regen_advance) * hz, in6_tmpaddrtimer, NULL); memset(nullbuf, 0, sizeof(nullbuf)); - TAILQ_FOREACH(ifp, &ifnet, if_list) { + IFNET_FOREACH(ifp) { ndi = ND_IFINFO(ifp); if (memcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) != 0) { /* Index: src/sys/netinet6/in6_pcb.c diff -u src/sys/netinet6/in6_pcb.c:1.124 src/sys/netinet6/in6_pcb.c:1.124.2.1 --- src/sys/netinet6/in6_pcb.c:1.124 Sat Nov 23 14:20:22 2013 +++ src/sys/netinet6/in6_pcb.c Sun Aug 10 06:56:30 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: in6_pcb.c,v 1.124 2013/11/23 14:20:22 christos Exp $ */ +/* $NetBSD: in6_pcb.c,v 1.124.2.1 2014/08/10 06:56:30 tls Exp $ */ /* $KAME: in6_pcb.c,v 1.84 2001/02/08 18:02:08 itojun Exp $ */ /* @@ -62,7 +62,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: in6_pcb.c,v 1.124 2013/11/23 14:20:22 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: in6_pcb.c,v 1.124.2.1 2014/08/10 06:56:30 tls Exp $"); #include "opt_inet.h" #include "opt_ipsec.h" @@ -157,9 +157,6 @@ in6_pcballoc(struct socket *so, void *v) struct inpcbtable *table = v; struct in6pcb *in6p; int s; -#if defined(IPSEC) - int error; -#endif s = splnet(); in6p = pool_get(&in6pcb_pool, PR_NOWAIT); @@ -175,12 +172,14 @@ in6_pcballoc(struct socket *so, void *v) in6p->in6p_portalgo = PORTALGO_DEFAULT; in6p->in6p_bindportonsend = false; #if defined(IPSEC) - error = ipsec_init_pcbpolicy(so, &in6p->in6p_sp); - if (error != 0) { - s = splnet(); - pool_put(&in6pcb_pool, in6p); - splx(s); - return error; + if (ipsec_enabled) { + int error = ipsec_init_pcbpolicy(so, &in6p->in6p_sp); + if (error != 0) { + s = splnet(); + pool_put(&in6pcb_pool, in6p); + splx(s); + return error; + } } #endif /* IPSEC */ s = splnet(); @@ -567,7 +566,7 @@ in6_pcbconnect(void *v, struct mbuf *nam in6p->in6p_flowinfo |= (htonl(ip6_randomflowlabel()) & IPV6_FLOWLABEL_MASK); #if defined(IPSEC) - if (in6p->in6p_socket->so_type == SOCK_STREAM) + if (ipsec_enabled && in6p->in6p_socket->so_type == SOCK_STREAM) ipsec_pcbconn(in6p->in6p_sp); #endif return (0); @@ -581,7 +580,8 @@ in6_pcbdisconnect(struct in6pcb *in6p) in6_pcbstate(in6p, IN6P_BOUND); in6p->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK; #if defined(IPSEC) - ipsec_pcbdisconn(in6p->in6p_sp); + if (ipsec_enabled) + ipsec_pcbdisconn(in6p->in6p_sp); #endif if (in6p->in6p_socket->so_state & SS_NOFDREF) in6_pcbdetach(in6p); @@ -597,25 +597,30 @@ in6_pcbdetach(struct in6pcb *in6p) return; #if defined(IPSEC) - ipsec6_delete_pcbpolicy(in6p); -#endif /* IPSEC */ - so->so_pcb = 0; - if (in6p->in6p_options) + if (ipsec_enabled) + ipsec6_delete_pcbpolicy(in6p); +#endif + so->so_pcb = NULL; + + s = splnet(); + in6_pcbstate(in6p, IN6P_ATTACHED); + LIST_REMOVE(&in6p->in6p_head, inph_lhash); + TAILQ_REMOVE(&in6p->in6p_table->inpt_queue, &in6p->in6p_head, + inph_queue); + splx(s); + + if (in6p->in6p_options) { m_freem(in6p->in6p_options); + } if (in6p->in6p_outputopts != NULL) { ip6_clearpktopts(in6p->in6p_outputopts, -1); free(in6p->in6p_outputopts, M_IP6OPT); } rtcache_free(&in6p->in6p_route); + sofree(so); /* drops the socket's lock */ + ip6_freemoptions(in6p->in6p_moptions); - s = splnet(); - in6_pcbstate(in6p, IN6P_ATTACHED); - LIST_REMOVE(&in6p->in6p_head, inph_lhash); - TAILQ_REMOVE(&in6p->in6p_table->inpt_queue, &in6p->in6p_head, - inph_queue); pool_put(&in6pcb_pool, in6p); - splx(s); - sofree(so); /* drops the socket's lock */ mutex_enter(softnet_lock); /* reacquire it */ } Index: src/sys/netinet6/in6_pcb.h diff -u src/sys/netinet6/in6_pcb.h:1.37 src/sys/netinet6/in6_pcb.h:1.37.12.1 --- src/sys/netinet6/in6_pcb.h:1.37 Mon Jun 25 15:28:39 2012 +++ src/sys/netinet6/in6_pcb.h Sun Aug 10 06:56:30 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: in6_pcb.h,v 1.37 2012/06/25 15:28:39 christos Exp $ */ +/* $NetBSD: in6_pcb.h,v 1.37.12.1 2014/08/10 06:56:30 tls Exp $ */ /* $KAME: in6_pcb.h,v 1.45 2001/02/09 05:59:46 itojun Exp $ */ /* Index: src/sys/netinet6/in6_proto.c diff -u src/sys/netinet6/in6_proto.c:1.100 src/sys/netinet6/in6_proto.c:1.100.2.1 --- src/sys/netinet6/in6_proto.c:1.100 Thu Jan 2 18:29:01 2014 +++ src/sys/netinet6/in6_proto.c Sun Aug 10 06:56:30 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: in6_proto.c,v 1.100 2014/01/02 18:29:01 pooka Exp $ */ +/* $NetBSD: in6_proto.c,v 1.100.2.1 2014/08/10 06:56:30 tls Exp $ */ /* $KAME: in6_proto.c,v 1.66 2000/10/10 15:35:47 itojun Exp $ */ /* @@ -62,7 +62,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: in6_proto.c,v 1.100 2014/01/02 18:29:01 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: in6_proto.c,v 1.100.2.1 2014/08/10 06:56:30 tls Exp $"); #include "opt_gateway.h" #include "opt_inet.h" @@ -135,14 +135,6 @@ DOMAIN_DEFINE(inet6domain); /* forward d /* Wrappers to acquire kernel_lock. */ -PR_WRAP_USRREQ(rip6_usrreq) -PR_WRAP_USRREQ(udp6_usrreq) -PR_WRAP_USRREQ(tcp_usrreq) - -#define rip6_usrreq rip6_usrreq_wrapper -#define udp6_usrreq udp6_usrreq_wrapper -#define tcp_usrreq tcp_usrreq_wrapper - PR_WRAP_CTLINPUT(rip6_ctlinput) PR_WRAP_CTLINPUT(encap6_ctlinput) PR_WRAP_CTLINPUT(udp6_ctlinput) @@ -199,7 +191,7 @@ const struct ip6protosw inet6sw[] = { .pr_input = udp6_input, .pr_ctlinput = udp6_ctlinput, .pr_ctloutput = udp6_ctloutput, - .pr_usrreq = udp6_usrreq, + .pr_usrreqs = &udp6_usrreqs, .pr_init = udp6_init, }, { .pr_type = SOCK_STREAM, @@ -209,7 +201,7 @@ const struct ip6protosw inet6sw[] = { .pr_input = tcp6_input, .pr_ctlinput = tcp6_ctlinput, .pr_ctloutput = tcp_ctloutput, - .pr_usrreq = tcp_usrreq, + .pr_usrreqs = &tcp_usrreqs, .pr_init = tcp6_init, .pr_fasttimo = tcp_fasttimo, .pr_drain = tcp_drainstub, @@ -222,7 +214,7 @@ const struct ip6protosw inet6sw[] = { .pr_output = rip6_output, .pr_ctlinput = rip6_ctlinput, .pr_ctloutput = rip6_ctloutput, - .pr_usrreq = rip6_usrreq, + .pr_usrreqs = &rip6_usrreqs, }, #ifdef GATEWAY { .pr_domain = &inet6domain, @@ -239,7 +231,7 @@ const struct ip6protosw inet6sw[] = { .pr_output = rip6_output, .pr_ctlinput = rip6_ctlinput, .pr_ctloutput = icmp6_ctloutput, - .pr_usrreq = rip6_usrreq, + .pr_usrreqs = &rip6_usrreqs, .pr_init = icmp6_init, }, { .pr_type = SOCK_RAW, @@ -291,7 +283,7 @@ const struct ip6protosw inet6sw[] = { .pr_output = rip6_output, .pr_ctlinput = encap6_ctlinput, .pr_ctloutput = rip6_ctloutput, - .pr_usrreq = rip6_usrreq, + .pr_usrreqs = &rip6_usrreqs, .pr_init = encap_init, }, #endif @@ -303,7 +295,7 @@ const struct ip6protosw inet6sw[] = { .pr_output = rip6_output, .pr_ctlinput = encap6_ctlinput, .pr_ctloutput = rip6_ctloutput, - .pr_usrreq = rip6_usrreq, + .pr_usrreqs = &rip6_usrreqs, .pr_init = encap_init, }, #if NETHERIP > 0 @@ -315,7 +307,7 @@ const struct ip6protosw inet6sw[] = { .pr_output = rip6_output, .pr_ctlinput = rip6_ctlinput, .pr_ctloutput = rip6_ctloutput, - .pr_usrreq = rip6_usrreq, + .pr_usrreqs = &rip6_usrreqs, }, #endif #if NCARP > 0 @@ -326,7 +318,7 @@ const struct ip6protosw inet6sw[] = { .pr_input = carp6_proto_input, .pr_output = rip6_output, .pr_ctloutput = rip6_ctloutput, - .pr_usrreq = rip6_usrreq, + .pr_usrreqs = &rip6_usrreqs, }, #endif /* NCARP */ { .pr_type = SOCK_RAW, @@ -336,7 +328,7 @@ const struct ip6protosw inet6sw[] = { .pr_input = pim6_input, .pr_output = rip6_output, .pr_ctloutput = rip6_ctloutput, - .pr_usrreq = rip6_usrreq, + .pr_usrreqs = &rip6_usrreqs, .pr_init = pim6_init, }, /* raw wildcard */ @@ -346,7 +338,7 @@ const struct ip6protosw inet6sw[] = { .pr_input = rip6_input, .pr_output = rip6_output, .pr_ctloutput = rip6_ctloutput, - .pr_usrreq = rip6_usrreq, + .pr_usrreqs = &rip6_usrreqs, .pr_init = rip6_init, }, }; @@ -377,7 +369,7 @@ struct domain inet6domain = { .dom_rtoffset = offsetof(struct sockaddr_in6, sin6_addr) << 3, .dom_maxrtkey = sizeof(struct ip_pack6), .dom_ifattach = in6_domifattach, .dom_ifdetach = in6_domifdetach, - .dom_ifqueues = { &ip6intrq, NULL }, + .dom_ifqueues = { NULL, NULL }, .dom_link = { NULL }, .dom_mowner = MOWNER_INIT("",""), .dom_sa_cmpofs = offsetof(struct sockaddr_in6, sin6_addr), @@ -476,8 +468,3 @@ int icmp6_rediraccept = 1; /* accept an int icmp6_redirtimeout = 10 * 60; /* 10 minutes */ int icmp6errppslim = 100; /* 100pps */ int icmp6_nodeinfo = 1; /* enable/disable NI response */ - -/* UDP on IP6 parameters */ -int udp6_sendspace = 9216; /* really max datagram size */ -int udp6_recvspace = 40 * (1024 + sizeof(struct sockaddr_in6)); - /* 40 1K datagrams */ Index: src/sys/netinet6/in6_src.c diff -u src/sys/netinet6/in6_src.c:1.53 src/sys/netinet6/in6_src.c:1.53.12.1 --- src/sys/netinet6/in6_src.c:1.53 Mon Jun 25 15:28:39 2012 +++ src/sys/netinet6/in6_src.c Sun Aug 10 06:56:30 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: in6_src.c,v 1.53 2012/06/25 15:28:39 christos Exp $ */ +/* $NetBSD: in6_src.c,v 1.53.12.1 2014/08/10 06:56:30 tls Exp $ */ /* $KAME: in6_src.c,v 1.159 2005/10/19 01:40:32 t-momose Exp $ */ /* @@ -66,7 +66,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: in6_src.c,v 1.53 2012/06/25 15:28:39 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: in6_src.c,v 1.53.12.1 2014/08/10 06:56:30 tls Exp $"); #include "opt_inet.h" @@ -591,7 +591,7 @@ selectroute(struct sockaddr_in6 *dstsock /* If the caller specify the outgoing interface explicitly, use it. */ if (opts && (pi = opts->ip6po_pktinfo) != NULL && pi->ipi6_ifindex) { /* XXX boundary check is assumed to be already done. */ - ifp = ifindex2ifnet[pi->ipi6_ifindex]; + ifp = if_byindex(pi->ipi6_ifindex); if (ifp != NULL && (norouteok || retrt == NULL || IN6_IS_ADDR_MULTICAST(dst))) { Index: src/sys/netinet6/in6_var.h diff -u src/sys/netinet6/in6_var.h:1.68 src/sys/netinet6/in6_var.h:1.68.2.1 --- src/sys/netinet6/in6_var.h:1.68 Mon Jan 13 18:57:49 2014 +++ src/sys/netinet6/in6_var.h Sun Aug 10 06:56:30 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: in6_var.h,v 1.68 2014/01/13 18:57:49 roy Exp $ */ +/* $NetBSD: in6_var.h,v 1.68.2.1 2014/08/10 06:56:30 tls Exp $ */ /* $KAME: in6_var.h,v 1.81 2002/06/08 11:16:51 itojun Exp $ */ /* @@ -479,6 +479,11 @@ struct in6_rrenumreq { #endif #ifdef _KERNEL + +#include <net/pktqueue.h> + +extern pktqueue_t *ip6_pktq; + MALLOC_DECLARE(M_IP6OPT); extern struct in6_ifaddr *in6_ifaddr; @@ -489,7 +494,6 @@ do { \ ((struct in6_ifextra *)((ifp)->if_afdata[AF_INET6]))->in6_ifstat->tag++; \ } while (/*CONSTCOND*/ 0) -extern struct ifqueue ip6intrq; /* IP6 packet input queue */ extern const struct in6_addr zeroin6_addr; extern const u_char inet6ctlerrmap[]; extern unsigned long in6_maxmtu; @@ -676,8 +680,7 @@ struct in6_multi_mship *in6_joingroup(st int *, int); int in6_leavegroup(struct in6_multi_mship *); int in6_mask2len(struct in6_addr *, u_char *); -int in6_control(struct socket *, u_long, void *, struct ifnet *, - struct lwp *); +int in6_control(struct socket *, u_long, void *, struct ifnet *); int in6_update_ifa(struct ifnet *, struct in6_aliasreq *, struct in6_ifaddr *, int); void in6_purgeaddr(struct ifaddr *); Index: src/sys/netinet6/ip6_flow.c diff -u src/sys/netinet6/ip6_flow.c:1.22 src/sys/netinet6/ip6_flow.c:1.22.2.1 --- src/sys/netinet6/ip6_flow.c:1.22 Tue Apr 1 13:11:44 2014 +++ src/sys/netinet6/ip6_flow.c Sun Aug 10 06:56:30 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: ip6_flow.c,v 1.22 2014/04/01 13:11:44 pooka Exp $ */ +/* $NetBSD: ip6_flow.c,v 1.22.2.1 2014/08/10 06:56:30 tls Exp $ */ /*- * Copyright (c) 2007 The NetBSD Foundation, Inc. @@ -38,7 +38,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ip6_flow.c,v 1.22 2014/04/01 13:11:44 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip6_flow.c,v 1.22.2.1 2014/08/10 06:56:30 tls Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -308,13 +308,14 @@ ip6flow_fastforward(struct mbuf **mp) ip6f->ip6f_uses++; + KERNEL_LOCK(1, NULL); /* Send on its way - straight to the interface output routine. */ if ((error = (*rt->rt_ifp->if_output)(rt->rt_ifp, m, dst, rt)) != 0) { ip6f->ip6f_dropped++; } else { ip6f->ip6f_forwarded++; } - + KERNEL_UNLOCK_ONE(NULL); return 1; } Index: src/sys/netinet6/ip6_forward.c diff -u src/sys/netinet6/ip6_forward.c:1.72 src/sys/netinet6/ip6_forward.c:1.72.4.1 --- src/sys/netinet6/ip6_forward.c:1.72 Sat Jun 29 21:06:58 2013 +++ src/sys/netinet6/ip6_forward.c Sun Aug 10 06:56:30 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: ip6_forward.c,v 1.72 2013/06/29 21:06:58 rmind Exp $ */ +/* $NetBSD: ip6_forward.c,v 1.72.4.1 2014/08/10 06:56:30 tls Exp $ */ /* $KAME: ip6_forward.c,v 1.109 2002/09/11 08:10:17 sakane Exp $ */ /* @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ip6_forward.c,v 1.72 2013/06/29 21:06:58 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip6_forward.c,v 1.72.4.1 2014/08/10 06:56:30 tls Exp $"); #include "opt_gateway.h" #include "opt_ipsec.h" @@ -100,9 +100,8 @@ ip6_forward(struct mbuf *m, int srcrt) u_int32_t inzone, outzone; struct in6_addr src_in6, dst_in6; #ifdef IPSEC - struct secpolicy *sp = NULL; int needipsec = 0; - int s; + struct secpolicy *sp = NULL; #endif /* @@ -155,19 +154,21 @@ ip6_forward(struct mbuf *m, int srcrt) mcopy = m_copy(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN)); #ifdef IPSEC - /* Check the security policy (SP) for the packet */ + if (ipsec_used) { + /* Check the security policy (SP) for the packet */ - sp = ipsec6_check_policy(m,NULL,0,&needipsec,&error); - if (error != 0) { - /* - * Hack: -EINVAL is used to signal that a packet - * should be silently discarded. This is typically - * because we asked key management for an SA and - * it was delayed (e.g. kicked up to IKE). - */ - if (error == -EINVAL) - error = 0; - goto freecopy; + sp = ipsec6_check_policy(m, NULL, 0, &needipsec, &error); + if (error != 0) { + /* + * Hack: -EINVAL is used to signal that a packet + * should be silently discarded. This is typically + * because we asked key management for an SA and + * it was delayed (e.g. kicked up to IKE). + */ + if (error == -EINVAL) + error = 0; + goto freecopy; + } } #endif /* IPSEC */ @@ -261,8 +262,8 @@ ip6_forward(struct mbuf *m, int srcrt) * ipsec6_proces_packet will send the packet using ip6_output */ if (needipsec) { - s = splsoftnet(); - error = ipsec6_process_packet(m,sp->req); + int s = splsoftnet(); + error = ipsec6_process_packet(m, sp->req); splx(s); if (mcopy) goto freecopy; Index: src/sys/netinet6/ip6_input.c diff -u src/sys/netinet6/ip6_input.c:1.145 src/sys/netinet6/ip6_input.c:1.145.2.1 --- src/sys/netinet6/ip6_input.c:1.145 Tue Feb 25 18:30:12 2014 +++ src/sys/netinet6/ip6_input.c Sun Aug 10 06:56:30 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: ip6_input.c,v 1.145 2014/02/25 18:30:12 pooka Exp $ */ +/* $NetBSD: ip6_input.c,v 1.145.2.1 2014/08/10 06:56:30 tls Exp $ */ /* $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $ */ /* @@ -62,7 +62,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ip6_input.c,v 1.145 2014/02/25 18:30:12 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip6_input.c,v 1.145.2.1 2014/08/10 06:56:30 tls Exp $"); #include "opt_gateway.h" #include "opt_inet.h" @@ -90,13 +90,14 @@ __KERNEL_RCSID(0, "$NetBSD: ip6_input.c, #include <net/if_types.h> #include <net/if_dl.h> #include <net/route.h> -#include <net/netisr.h> +#include <net/pktqueue.h> #include <net/pfil.h> #include <netinet/in.h> #include <netinet/in_systm.h> #ifdef INET #include <netinet/ip.h> +#include <netinet/ip_var.h> #include <netinet/ip_icmp.h> #endif /* INET */ #include <netinet/ip6.h> @@ -135,9 +136,8 @@ __KERNEL_RCSID(0, "$NetBSD: ip6_input.c, extern struct domain inet6domain; u_char ip6_protox[IPPROTO_MAX]; -static int ip6qmaxlen = IFQ_MAXLEN; struct in6_ifaddr *in6_ifaddr; -struct ifqueue ip6intrq; +pktqueue_t *ip6_pktq __read_mostly; extern callout_t in6_tmpaddrtimer_ch; @@ -150,6 +150,7 @@ pfil_head_t *inet6_pfil_hook; percpu_t *ip6stat_percpu; static void ip6_init2(void *); +static void ip6intr(void *); static struct m_tag *ip6_setdstifaddr(struct mbuf *, const struct in6_ifaddr *); static int ip6_process_hopopts(struct mbuf *, u_int8_t *, int, u_int32_t *, @@ -178,7 +179,10 @@ ip6_init(void) if (pr->pr_domain->dom_family == PF_INET6 && pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) ip6_protox[pr->pr_protocol] = pr - inet6sw; - ip6intrq.ifq_maxlen = ip6qmaxlen; + + ip6_pktq = pktq_create(IFQ_MAXLEN, ip6intr, NULL); + KASSERT(ip6_pktq != NULL); + scope6_init(); addrsel_policy_init(); nd6_init(); @@ -215,28 +219,24 @@ ip6_init2(void *dummy) /* * IP6 input interrupt handling. Just pass the packet to ip6_input. */ -void -ip6intr(void) +static void +ip6intr(void *arg __unused) { - int s; struct mbuf *m; mutex_enter(softnet_lock); - KERNEL_LOCK(1, NULL); - for (;;) { - s = splnet(); - IF_DEQUEUE(&ip6intrq, m); - splx(s); - if (m == 0) - break; - /* drop the packet if IPv6 operation is disabled on the IF */ - if ((ND_IFINFO(m->m_pkthdr.rcvif)->flags & ND6_IFF_IFDISABLED)) { + while ((m = pktq_dequeue(ip6_pktq)) != NULL) { + const ifnet_t *ifp = m->m_pkthdr.rcvif; + + /* + * Drop the packet if IPv6 is disabled on the interface. + */ + if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)) { m_freem(m); - break; + continue; } ip6_input(m); } - KERNEL_UNLOCK_ONE(NULL); mutex_exit(softnet_lock); } @@ -257,12 +257,6 @@ ip6_input(struct mbuf *m) struct sockaddr dst; struct sockaddr_in6 dst6; } u; -#ifdef IPSEC - struct m_tag *mtag; - struct tdb_ident *tdbi; - struct secpolicy *sp; - int s, error; -#endif /* * make sure we don't have onion peering information into m_tag. @@ -345,7 +339,7 @@ ip6_input(struct mbuf *m) * not the decapsulated packet. */ #if defined(IPSEC) - if (!ipsec_indone(m)) + if (!ipsec_used || !ipsec_indone(m)) #else if (1) #endif @@ -753,45 +747,58 @@ ip6_input(struct mbuf *m) } #ifdef IPSEC - /* - * enforce IPsec policy checking if we are seeing last header. - * note that we do not visit this with protocols with pcb layer - * code - like udp/tcp/raw ip. - */ - if ((inet6sw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0) { - /* - * Check if the packet has already had IPsec processing - * done. If so, then just pass it along. This tag gets - * set during AH, ESP, etc. input handling, before the - * packet is returned to the ip input queue for delivery. - */ - mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL); - s = splsoftnet(); - if (mtag != NULL) { - tdbi = (struct tdb_ident *)(mtag + 1); - sp = ipsec_getpolicy(tdbi, IPSEC_DIR_INBOUND); - } else { - sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND, - IP_FORWARDING, &error); - } - if (sp != NULL) { + if (ipsec_used) { + struct m_tag *mtag; + struct tdb_ident *tdbi; + struct secpolicy *sp; + int s, error; + /* - * Check security policy against packet attributes. + * enforce IPsec policy checking if we are seeing last + * header. note that we do not visit this with + * protocols with pcb layer code - like udp/tcp/raw ip. */ - error = ipsec_in_reject(sp, m); - KEY_FREESP(&sp); - } else { - /* XXX error stat??? */ - error = EINVAL; - DPRINTF(("ip6_input: no SP, packet discarded\n"));/*XXX*/ + if ((inet6sw[ip_protox[nxt]].pr_flags + & PR_LASTHDR) != 0) { + /* + * Check if the packet has already had IPsec + * processing done. If so, then just pass it + * along. This tag gets set during AH, ESP, + * etc. input handling, before the packet is + * returned to the ip input queue for delivery. + */ + mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, + NULL); + s = splsoftnet(); + if (mtag != NULL) { + tdbi = (struct tdb_ident *)(mtag + 1); + sp = ipsec_getpolicy(tdbi, + IPSEC_DIR_INBOUND); + } else { + sp = ipsec_getpolicybyaddr(m, + IPSEC_DIR_INBOUND, IP_FORWARDING, + &error); + } + if (sp != NULL) { + /* + * Check security policy against packet + * attributes. + */ + error = ipsec_in_reject(sp, m); + KEY_FREESP(&sp); + } else { + /* XXX error stat??? */ + error = EINVAL; + DPRINTF(("ip6_input: no SP, packet" + " discarded\n"));/*XXX*/ + } + splx(s); + if (error) + goto bad; + } } - splx(s); - if (error) - goto bad; - } #endif /* IPSEC */ - nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt); } return; @@ -1847,6 +1854,15 @@ sysctl_net_inet6_ip6_setup(struct sysctl IPV6CTL_V6ONLY, CTL_EOL); sysctl_createv(clog, 0, NULL, NULL, CTLFLAG_PERMANENT|CTLFLAG_READWRITE, + CTLTYPE_INT, "auto_linklocal", + SYSCTL_DESCR("Default value of per-interface flag for " + "adding an IPv6 link-local address to " + "interfaces when attached"), + NULL, 0, &ip6_auto_linklocal, 0, + CTL_NET, PF_INET6, IPPROTO_IPV6, + IPV6CTL_AUTO_LINKLOCAL, CTL_EOL); + sysctl_createv(clog, 0, NULL, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "anonportmin", SYSCTL_DESCR("Lowest ephemeral port number to assign"), sysctl_net_inet_ip_ports, 0, &ip6_anonportmin, 0, Index: src/sys/netinet6/ip6_mroute.c diff -u src/sys/netinet6/ip6_mroute.c:1.106 src/sys/netinet6/ip6_mroute.c:1.106.2.1 --- src/sys/netinet6/ip6_mroute.c:1.106 Tue Feb 25 18:30:12 2014 +++ src/sys/netinet6/ip6_mroute.c Sun Aug 10 06:56:30 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: ip6_mroute.c,v 1.106 2014/02/25 18:30:12 pooka Exp $ */ +/* $NetBSD: ip6_mroute.c,v 1.106.2.1 2014/08/10 06:56:30 tls Exp $ */ /* $KAME: ip6_mroute.c,v 1.49 2001/07/25 09:21:18 jinmei Exp $ */ /* @@ -117,7 +117,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ip6_mroute.c,v 1.106 2014/02/25 18:30:12 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip6_mroute.c,v 1.106.2.1 2014/08/10 06:56:30 tls Exp $"); #include "opt_inet.h" #include "opt_mrouting.h" @@ -658,13 +658,7 @@ add_m6if(struct mif6ctl *mifcp) mifp = mif6table + mifcp->mif6c_mifi; if (mifp->m6_ifp) return EADDRINUSE; /* XXX: is it appropriate? */ - if (mifcp->mif6c_pifi == 0 || mifcp->mif6c_pifi >= if_indexlim) - return ENXIO; - /* - * XXX: some OSes can remove ifp and clear ifindex2ifnet[id] - * even for id between 0 and if_index. - */ - if ((ifp = ifindex2ifnet[mifcp->mif6c_pifi]) == NULL) + if (!mifcp->mif6c_pifi || (ifp = if_byindex(mifcp->mif6c_pifi)) == NULL) return ENXIO; if (mifcp->mif6c_flags & MIFF_REGISTER) { Index: src/sys/netinet6/ip6_output.c diff -u src/sys/netinet6/ip6_output.c:1.155 src/sys/netinet6/ip6_output.c:1.155.2.1 --- src/sys/netinet6/ip6_output.c:1.155 Thu Oct 3 20:27:55 2013 +++ src/sys/netinet6/ip6_output.c Sun Aug 10 06:56:30 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: ip6_output.c,v 1.155 2013/10/03 20:27:55 christos Exp $ */ +/* $NetBSD: ip6_output.c,v 1.155.2.1 2014/08/10 06:56:30 tls Exp $ */ /* $KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $ */ /* @@ -62,7 +62,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ip6_output.c,v 1.155 2013/10/03 20:27:55 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip6_output.c,v 1.155.2.1 2014/08/10 06:56:30 tls Exp $"); #include "opt_inet.h" #include "opt_inet6.h" @@ -181,7 +181,6 @@ ip6_output( int needipsec = 0; #ifdef IPSEC struct secpolicy *sp = NULL; - int s; #endif memset(&ip6route, 0, sizeof(ip6route)); @@ -241,20 +240,22 @@ ip6_output( if (exthdrs.ip6e_dest2) optlen += exthdrs.ip6e_dest2->m_len; #ifdef IPSEC - /* Check the security policy (SP) for the packet */ - - sp = ipsec6_check_policy(m,so,flags,&needipsec,&error); - if (error != 0) { - /* - * Hack: -EINVAL is used to signal that a packet - * should be silently discarded. This is typically - * because we asked key management for an SA and - * it was delayed (e.g. kicked up to IKE). - */ - if (error == -EINVAL) - error = 0; - goto freehdrs; - } + if (ipsec_used) { + /* Check the security policy (SP) for the packet */ + + sp = ipsec6_check_policy(m, so, flags, &needipsec, &error); + if (error != 0) { + /* + * Hack: -EINVAL is used to signal that a packet + * should be silently discarded. This is typically + * because we asked key management for an SA and + * it was delayed (e.g. kicked up to IKE). + */ + if (error == -EINVAL) + error = 0; + goto freehdrs; + } + } #endif /* IPSEC */ @@ -464,8 +465,8 @@ ip6_output( #ifdef IPSEC if (needipsec) { - s = splsoftnet(); - error = ipsec6_process_packet(m,sp->req); + int s = splsoftnet(); + error = ipsec6_process_packet(m, sp->req); /* * Preserve KAME behaviour: ENOENT can be returned @@ -480,8 +481,6 @@ ip6_output( } #endif /* IPSEC */ - - /* adjust pointer */ ip6 = mtod(m, struct ip6_hdr *); @@ -1652,9 +1651,13 @@ else \ #if defined(IPSEC) case IPV6_IPSEC_POLICY: - error = ipsec6_set_policy(in6p, optname, - sopt->sopt_data, sopt->sopt_size, kauth_cred_get()); - break; + if (ipsec_enabled) { + error = ipsec6_set_policy(in6p, optname, + sopt->sopt_data, sopt->sopt_size, + kauth_cred_get()); + break; + } + /*FALLTHROUGH*/ #endif /* IPSEC */ default: @@ -1841,17 +1844,20 @@ else \ #if defined(IPSEC) case IPV6_IPSEC_POLICY: - { - struct mbuf *m = NULL; - - /* XXX this will return EINVAL as sopt is empty */ - error = ipsec6_get_policy(in6p, sopt->sopt_data, - sopt->sopt_size, &m); - if (!error) - error = sockopt_setmbuf(sopt, m); + if (ipsec_used) { + struct mbuf *m = NULL; - break; - } + /* + * XXX: this will return EINVAL as sopt is + * empty + */ + error = ipsec6_get_policy(in6p, sopt->sopt_data, + sopt->sopt_size, &m); + if (!error) + error = sockopt_setmbuf(sopt, m); + break; + } + /*FALLTHROUGH*/ #endif /* IPSEC */ default: @@ -2277,11 +2283,10 @@ ip6_setmoptions(const struct sockopt *so break; if (ifindex != 0) { - if (if_indexlim <= ifindex || !ifindex2ifnet[ifindex]) { + if ((ifp = if_byindex(ifindex)) == NULL) { error = ENXIO; /* XXX EINVAL? */ break; } - ifp = ifindex2ifnet[ifindex]; if ((ifp->if_flags & IFF_MULTICAST) == 0) { error = EADDRNOTAVAIL; break; @@ -2379,12 +2384,10 @@ ip6_setmoptions(const struct sockopt *so /* * If the interface is specified, validate it. */ - if (if_indexlim <= mreq.ipv6mr_interface || - !ifindex2ifnet[mreq.ipv6mr_interface]) { + if ((ifp = if_byindex(mreq.ipv6mr_interface)) == NULL) { error = ENXIO; /* XXX EINVAL? */ break; } - ifp = ifindex2ifnet[mreq.ipv6mr_interface]; } /* @@ -2438,12 +2441,10 @@ ip6_setmoptions(const struct sockopt *so * to its ifnet structure. */ if (mreq.ipv6mr_interface != 0) { - if (if_indexlim <= mreq.ipv6mr_interface || - !ifindex2ifnet[mreq.ipv6mr_interface]) { + if ((ifp = if_byindex(mreq.ipv6mr_interface)) == NULL) { error = ENXIO; /* XXX EINVAL? */ break; } - ifp = ifindex2ifnet[mreq.ipv6mr_interface]; } else ifp = NULL; @@ -2737,12 +2738,9 @@ ip6_setpktopt(int optname, u_char *buf, return (EINVAL); } - /* validate the interface index if specified. */ - if (pktinfo->ipi6_ifindex >= if_indexlim) { - return (ENXIO); - } + /* Validate the interface index if specified. */ if (pktinfo->ipi6_ifindex) { - ifp = ifindex2ifnet[pktinfo->ipi6_ifindex]; + ifp = if_byindex(pktinfo->ipi6_ifindex); if (ifp == NULL) return (ENXIO); } Index: src/sys/netinet6/ip6_var.h diff -u src/sys/netinet6/ip6_var.h:1.59 src/sys/netinet6/ip6_var.h:1.59.12.1 --- src/sys/netinet6/ip6_var.h:1.59 Sat Jun 23 03:14:04 2012 +++ src/sys/netinet6/ip6_var.h Sun Aug 10 06:56:30 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: ip6_var.h,v 1.59 2012/06/23 03:14:04 christos Exp $ */ +/* $NetBSD: ip6_var.h,v 1.59.12.1 2014/08/10 06:56:30 tls Exp $ */ /* $KAME: ip6_var.h,v 1.33 2000/06/11 14:59:20 jinmei Exp $ */ /* @@ -312,11 +312,11 @@ extern int ip6_hashsize; /* size of has #endif struct in6pcb; +extern const struct pr_usrreqs rip6_usrreqs; int icmp6_ctloutput(int, struct socket *, struct sockopt *); void ip6_init(void); -void ip6intr(void); void ip6_input(struct mbuf *); const struct ip6aux *ip6_getdstifaddr(struct mbuf *); void ip6_freepcbopts(struct ip6_pktopts *); @@ -380,6 +380,7 @@ void *rip6_ctlinput(int, const struct so int rip6_ctloutput(int, struct socket *, struct sockopt *); int rip6_output(struct mbuf *, struct socket *, struct sockaddr_in6 *, struct mbuf *); +int rip6_attach(struct socket *, int); int rip6_usrreq(struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *, struct lwp *); Index: src/sys/netinet6/ip6protosw.h diff -u src/sys/netinet6/ip6protosw.h:1.21 src/sys/netinet6/ip6protosw.h:1.21.54.1 --- src/sys/netinet6/ip6protosw.h:1.21 Wed Aug 6 15:01:23 2008 +++ src/sys/netinet6/ip6protosw.h Sun Aug 10 06:56:30 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: ip6protosw.h,v 1.21 2008/08/06 15:01:23 plunky Exp $ */ +/* $NetBSD: ip6protosw.h,v 1.21.54.1 2014/08/10 06:56:30 tls Exp $ */ /* $KAME: ip6protosw.h,v 1.22 2001/02/08 18:02:08 itojun Exp $ */ /* @@ -129,9 +129,7 @@ struct ip6protosw { (int, struct socket *, struct sockopt *); /* user-protocol hook */ - int (*pr_usrreq) /* user request: see list below */ - (struct socket *, int, struct mbuf *, - struct mbuf *, struct mbuf *, struct lwp *); + const struct pr_usrreqs *pr_usrreqs; /* utility hooks */ void (*pr_init) /* initialization hook */ Index: src/sys/netinet6/mld6.c diff -u src/sys/netinet6/mld6.c:1.55 src/sys/netinet6/mld6.c:1.55.22.1 --- src/sys/netinet6/mld6.c:1.55 Sat Nov 19 22:51:29 2011 +++ src/sys/netinet6/mld6.c Sun Aug 10 06:56:30 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: mld6.c,v 1.55 2011/11/19 22:51:29 tls Exp $ */ +/* $NetBSD: mld6.c,v 1.55.22.1 2014/08/10 06:56:30 tls Exp $ */ /* $KAME: mld6.c,v 1.25 2001/01/16 14:14:18 itojun Exp $ */ /* @@ -102,7 +102,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: mld6.c,v 1.55 2011/11/19 22:51:29 tls Exp $"); +__KERNEL_RCSID(0, "$NetBSD: mld6.c,v 1.55.22.1 2014/08/10 06:56:30 tls Exp $"); #include "opt_inet.h" @@ -137,7 +137,7 @@ __KERNEL_RCSID(0, "$NetBSD: mld6.c,v 1.5 * This structure is used to keep track of in6_multi chains which belong to * deleted interface addresses. */ -static LIST_HEAD(, multi6_kludge) in6_mk; /* XXX BSS initialization */ +static LIST_HEAD(, multi6_kludge) in6_mk = LIST_HEAD_INITIALIZER(in6_mk); struct multi6_kludge { LIST_ENTRY(multi6_kludge) mk_entry; @@ -897,3 +897,152 @@ in6_purgemkludge(struct ifnet *ifp) LIST_REMOVE(mk, mk_entry); free(mk, M_IPMADDR); } + +static int +in6_mkludge_sysctl(SYSCTLFN_ARGS) +{ + struct multi6_kludge *mk; + struct in6_multi *in6m; + int error; + uint32_t tmp; + size_t written; + + if (namelen != 1) + return EINVAL; + + if (oldp == NULL) { + *oldlenp = 0; + LIST_FOREACH(mk, &in6_mk, mk_entry) { + if (mk->mk_ifp->if_index == name[0]) + continue; + LIST_FOREACH(in6m, &mk->mk_head, in6m_entry) { + *oldlenp += sizeof(struct in6_addr) + + sizeof(uint32_t); + } + } + return 0; + } + + error = 0; + written = 0; + LIST_FOREACH(mk, &in6_mk, mk_entry) { + if (mk->mk_ifp->if_index == name[0]) + continue; + LIST_FOREACH(in6m, &mk->mk_head, in6m_entry) { + if (written + sizeof(struct in6_addr) + + sizeof(uint32_t) > *oldlenp) + goto done; + error = sysctl_copyout(l, &in6m->in6m_addr, + oldp, sizeof(struct in6_addr)); + if (error) + goto done; + oldp = (char *)oldp + sizeof(struct in6_addr); + written += sizeof(struct in6_addr); + tmp = in6m->in6m_refcount; + error = sysctl_copyout(l, &tmp, oldp, sizeof(tmp)); + if (error) + goto done; + oldp = (char *)oldp + sizeof(tmp); + written += sizeof(tmp); + } + } + +done: + *oldlenp = written; + return error; +} + +static int +in6_multicast_sysctl(SYSCTLFN_ARGS) +{ + struct ifnet *ifp; + struct ifaddr *ifa; + struct in6_ifaddr *ifa6; + struct in6_multi *in6m; + uint32_t tmp; + int error; + size_t written; + + if (namelen != 1) + return EINVAL; + + ifp = if_byindex(name[0]); + if (ifp == NULL) + return ENODEV; + + if (oldp == NULL) { + *oldlenp = 0; + IFADDR_FOREACH(ifa, ifp) { + if (ifa->ifa_addr == NULL) + continue; + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + ifa6 = (struct in6_ifaddr *)ifa; + LIST_FOREACH(in6m, &ifa6->ia6_multiaddrs, in6m_entry) { + *oldlenp += 2 * sizeof(struct in6_addr) + + sizeof(uint32_t); + } + } + return 0; + } + + error = 0; + written = 0; + IFADDR_FOREACH(ifa, ifp) { + if (ifa->ifa_addr == NULL) + continue; + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + ifa6 = (struct in6_ifaddr *)ifa; + LIST_FOREACH(in6m, &ifa6->ia6_multiaddrs, in6m_entry) { + if (written + 2 * sizeof(struct in6_addr) + + sizeof(uint32_t) > *oldlenp) + goto done; + error = sysctl_copyout(l, &ifa6->ia_addr.sin6_addr, + oldp, sizeof(struct in6_addr)); + if (error) + goto done; + oldp = (char *)oldp + sizeof(struct in6_addr); + written += sizeof(struct in6_addr); + error = sysctl_copyout(l, &in6m->in6m_addr, + oldp, sizeof(struct in6_addr)); + if (error) + goto done; + oldp = (char *)oldp + sizeof(struct in6_addr); + written += sizeof(struct in6_addr); + tmp = in6m->in6m_refcount; + error = sysctl_copyout(l, &tmp, oldp, sizeof(tmp)); + if (error) + goto done; + oldp = (char *)oldp + sizeof(tmp); + written += sizeof(tmp); + } + } +done: + *oldlenp = written; + return error; +} + +SYSCTL_SETUP(sysctl_in6_mklude_setup, "sysctl net.inet6.multicast_kludge subtree setup") +{ + + sysctl_createv(clog, 0, NULL, NULL, + CTLFLAG_PERMANENT, + CTLTYPE_NODE, "inet6", NULL, + NULL, 0, NULL, 0, + CTL_NET, PF_INET6, CTL_EOL); + + sysctl_createv(clog, 0, NULL, NULL, + CTLFLAG_PERMANENT, + CTLTYPE_NODE, "multicast", + SYSCTL_DESCR("Multicast information"), + in6_multicast_sysctl, 0, NULL, 0, + CTL_NET, PF_INET6, CTL_CREATE, CTL_EOL); + + sysctl_createv(clog, 0, NULL, NULL, + CTLFLAG_PERMANENT, + CTLTYPE_NODE, "multicast_kludge", + SYSCTL_DESCR("multicast kludge information"), + in6_mkludge_sysctl, 0, NULL, 0, + CTL_NET, PF_INET6, CTL_CREATE, CTL_EOL); +} Index: src/sys/netinet6/nd6.c diff -u src/sys/netinet6/nd6.c:1.148 src/sys/netinet6/nd6.c:1.148.2.1 --- src/sys/netinet6/nd6.c:1.148 Thu Mar 20 13:34:35 2014 +++ src/sys/netinet6/nd6.c Sun Aug 10 06:56:30 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: nd6.c,v 1.148 2014/03/20 13:34:35 roy Exp $ */ +/* $NetBSD: nd6.c,v 1.148.2.1 2014/08/10 06:56:30 tls Exp $ */ /* $KAME: nd6.c,v 1.279 2002/06/08 11:16:51 itojun Exp $ */ /* @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.148 2014/03/20 13:34:35 roy Exp $"); +__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.148.2.1 2014/08/10 06:56:30 tls Exp $"); #include "opt_ipsec.h" @@ -66,6 +66,7 @@ __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.14 #include <netinet6/ip6_var.h> #include <netinet6/scope6_var.h> #include <netinet6/nd6.h> +#include <netinet6/in6_ifattach.h> #include <netinet/icmp6.h> #include <netinet6/icmp6_private.h> @@ -177,13 +178,24 @@ nd6_ifattach(struct ifnet *ifp) nd->basereachable = REACHABLE_TIME; nd->reachable = ND_COMPUTE_RTIME(nd->basereachable); nd->retrans = RETRANS_TIMER; - /* - * Note that the default value of ip6_accept_rtadv is 0. - * Because we do not set ND6_IFF_OVERRIDE_RTADV here, we won't - * accept RAs by default. - */ + nd->flags = ND6_IFF_PERFORMNUD | ND6_IFF_ACCEPT_RTADV; + /* A loopback interface always has ND6_IFF_AUTO_LINKLOCAL. + * A bridge interface should not have ND6_IFF_AUTO_LINKLOCAL + * because one of it's members should. */ + if ((ip6_auto_linklocal && ifp->if_type != IFT_BRIDGE) || + (ifp->if_flags & IFF_LOOPBACK)) + nd->flags |= ND6_IFF_AUTO_LINKLOCAL; + + /* A loopback interface does not need to accept RTADV. + * A bridge interface should not accept RTADV + * because one of it's members should. */ + if (ip6_accept_rtadv && + !(ifp->if_flags & IFF_LOOPBACK) && + !(ifp->if_type != IFT_BRIDGE)) + nd->flags |= ND6_IFF_ACCEPT_RTADV; + /* XXX: we cannot call nd6_setmtu since ifp is not fully initialized */ nd6_setmtu0(ifp, nd); @@ -835,7 +847,7 @@ nd6_lookup1(const struct in6_addr *addr6 * interface route. */ if (create) { - RTFREE(rt); + rtfree(rt); rt = NULL; } } @@ -1698,8 +1710,38 @@ nd6_ioctl(u_long cmd, void *data, struct ia->ia6_flags |= IN6_IFF_TENTATIVE; } } - } + if (ND.flags & ND6_IFF_AUTO_LINKLOCAL) { + if (!(ND_IFINFO(ifp)->flags & ND6_IFF_AUTO_LINKLOCAL)) { + /* auto_linklocal 0->1 transition */ + + ND_IFINFO(ifp)->flags |= ND6_IFF_AUTO_LINKLOCAL; + in6_ifattach(ifp, NULL); + } else if (!(ND.flags & ND6_IFF_IFDISABLED) && + ifp->if_flags & IFF_UP) + { + /* + * When the IF already has + * ND6_IFF_AUTO_LINKLOCAL, no link-local + * address is assigned, and IFF_UP, try to + * assign one. + */ + int haslinklocal = 0; + + IFADDR_FOREACH(ifa, ifp) { + if (ifa->ifa_addr->sa_family !=AF_INET6) + continue; + ia = (struct in6_ifaddr *)ifa; + if (IN6_IS_ADDR_LINKLOCAL(IA6_IN6(ia))){ + haslinklocal = 1; + break; + } + } + if (!haslinklocal) + in6_ifattach(ifp, NULL); + } + } + } ND_IFINFO(ifp)->flags = ND.flags; break; #undef ND @@ -2047,7 +2089,7 @@ nd6_slowtimo(void *ignored_arg) KERNEL_LOCK(1, NULL); callout_reset(&nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz, nd6_slowtimo, NULL); - TAILQ_FOREACH(ifp, &ifnet, if_list) { + IFNET_FOREACH(ifp) { nd6if = ND_IFINFO(ifp); if (nd6if->basereachable && /* already initialized */ (nd6if->recalctm -= ND6_SLOWTIMER_INTERVAL) <= 0) { @@ -2257,9 +2299,13 @@ nd6_output(struct ifnet *ifp, struct ifn goto bad; } + KERNEL_LOCK(1, NULL); if ((ifp->if_flags & IFF_LOOPBACK) != 0) - return (*ifp->if_output)(origifp, m, sin6tocsa(dst), rt); - return (*ifp->if_output)(ifp, m, sin6tocsa(dst), rt); + error = (*ifp->if_output)(origifp, m, sin6tocsa(dst), rt); + else + error = (*ifp->if_output)(ifp, m, sin6tocsa(dst), rt); + KERNEL_UNLOCK_ONE(NULL); + return error; bad: if (m != NULL) Index: src/sys/netinet6/nd6.h diff -u src/sys/netinet6/nd6.h:1.58 src/sys/netinet6/nd6.h:1.58.6.1 --- src/sys/netinet6/nd6.h:1.58 Tue May 21 08:37:27 2013 +++ src/sys/netinet6/nd6.h Sun Aug 10 06:56:30 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: nd6.h,v 1.58 2013/05/21 08:37:27 roy Exp $ */ +/* $NetBSD: nd6.h,v 1.58.6.1 2014/08/10 06:56:30 tls Exp $ */ /* $KAME: nd6.h,v 1.95 2002/06/08 11:31:06 itojun Exp $ */ /* @@ -93,6 +93,7 @@ struct nd_ifinfo { * DAD failure. (XXX: not ND-specific) */ #define ND6_IFF_OVERRIDE_RTADV 0x10 /* See "RTADV Key", below. */ +#define ND6_IFF_AUTO_LINKLOCAL 0x20 /* * RTADV Key Index: src/sys/netinet6/nd6_nbr.c diff -u src/sys/netinet6/nd6_nbr.c:1.99 src/sys/netinet6/nd6_nbr.c:1.99.2.1 --- src/sys/netinet6/nd6_nbr.c:1.99 Mon Jan 13 18:23:36 2014 +++ src/sys/netinet6/nd6_nbr.c Sun Aug 10 06:56:30 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: nd6_nbr.c,v 1.99 2014/01/13 18:23:36 roy Exp $ */ +/* $NetBSD: nd6_nbr.c,v 1.99.2.1 2014/08/10 06:56:30 tls Exp $ */ /* $KAME: nd6_nbr.c,v 1.61 2001/02/10 16:06:14 jinmei Exp $ */ /* @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v 1.99 2014/01/13 18:23:36 roy Exp $"); +__KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v 1.99.2.1 2014/08/10 06:56:30 tls Exp $"); #include "opt_inet.h" #include "opt_ipsec.h" @@ -1097,6 +1097,8 @@ nd6_newaddrmsg(struct ifaddr *ifa) /* * Start Duplicate Address Detection (DAD) for specified interface address. * + * Note that callout is used when xtick > 0 and not when xtick == 0. + * * xtick: minimum delay ticks for IFF_UP event */ void Index: src/sys/netinet6/nd6_rtr.c diff -u src/sys/netinet6/nd6_rtr.c:1.90 src/sys/netinet6/nd6_rtr.c:1.90.2.1 --- src/sys/netinet6/nd6_rtr.c:1.90 Sat Sep 14 21:08:35 2013 +++ src/sys/netinet6/nd6_rtr.c Sun Aug 10 06:56:30 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: nd6_rtr.c,v 1.90 2013/09/14 21:08:35 martin Exp $ */ +/* $NetBSD: nd6_rtr.c,v 1.90.2.1 2014/08/10 06:56:30 tls Exp $ */ /* $KAME: nd6_rtr.c,v 1.95 2001/02/07 08:09:47 itojun Exp $ */ /* @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: nd6_rtr.c,v 1.90 2013/09/14 21:08:35 martin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: nd6_rtr.c,v 1.90.2.1 2014/08/10 06:56:30 tls Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -915,8 +915,7 @@ purge_detached(struct ifnet *ifp) !LIST_EMPTY(&pr->ndpr_advrtrs))) continue; - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa_next) { - ifa_next = ifa->ifa_list.tqe_next; + IFADDR_FOREACH_SAFE(ifa, ifp, ifa_next) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; ia = (struct in6_ifaddr *)ifa; @@ -2162,19 +2161,15 @@ rt6_deleteroute(struct rtentry *rt, void int nd6_setdefaultiface(int ifindex) { + ifnet_t *ifp; int error = 0; - if (ifindex < 0 || if_indexlim <= ifindex) - return (EINVAL); - if (ifindex != 0 && !ifindex2ifnet[ifindex]) - return (EINVAL); - + if ((ifp = if_byindex(ifindex)) == NULL) { + return EINVAL; + } if (nd6_defifindex != ifindex) { nd6_defifindex = ifindex; - if (nd6_defifindex > 0) { - nd6_defifp = ifindex2ifnet[nd6_defifindex]; - } else - nd6_defifp = NULL; + nd6_defifp = nd6_defifindex > 0 ? ifp : NULL; /* * Our current implementation assumes one-to-one maping between Index: src/sys/netinet6/raw_ip6.c diff -u src/sys/netinet6/raw_ip6.c:1.113 src/sys/netinet6/raw_ip6.c:1.113.2.1 --- src/sys/netinet6/raw_ip6.c:1.113 Tue Feb 25 18:30:12 2014 +++ src/sys/netinet6/raw_ip6.c Sun Aug 10 06:56:30 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: raw_ip6.c,v 1.113 2014/02/25 18:30:12 pooka Exp $ */ +/* $NetBSD: raw_ip6.c,v 1.113.2.1 2014/08/10 06:56:30 tls Exp $ */ /* $KAME: raw_ip6.c,v 1.82 2001/07/23 18:57:56 jinmei Exp $ */ /* @@ -62,21 +62,20 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: raw_ip6.c,v 1.113 2014/02/25 18:30:12 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: raw_ip6.c,v 1.113.2.1 2014/08/10 06:56:30 tls Exp $"); #include "opt_ipsec.h" #include <sys/param.h> #include <sys/sysctl.h> -#include <sys/malloc.h> #include <sys/mbuf.h> #include <sys/socket.h> #include <sys/protosw.h> #include <sys/socketvar.h> -#include <sys/errno.h> #include <sys/systm.h> #include <sys/proc.h> #include <sys/kauth.h> +#include <sys/kmem.h> #include <net/if.h> #include <net/route.h> @@ -205,7 +204,7 @@ rip6_input(struct mbuf **mp, int *offp, /* * Check AH/ESP integrity */ - if (!ipsec6_in_reject(m,last)) + if (ipsec_used && !ipsec6_in_reject(m, last)) #endif /* IPSEC */ if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) { if (last->in6p_flags & IN6P_CONTROLOPTS) @@ -227,7 +226,7 @@ rip6_input(struct mbuf **mp, int *offp, last = in6p; } #ifdef IPSEC - if (last && ipsec6_in_reject(m, last)) { + if (ipsec_used && last && ipsec6_in_reject(m, last)) { m_freem(m); /* * XXX ipsec6_in_reject update stat if there is an error @@ -585,262 +584,380 @@ extern u_long rip6_sendspace; extern u_long rip6_recvspace; int -rip6_usrreq(struct socket *so, int req, struct mbuf *m, - struct mbuf *nam, struct mbuf *control, struct lwp *l) +rip6_attach(struct socket *so, int proto) { - struct in6pcb *in6p = sotoin6pcb(so); - int s; - int error = 0; + struct in6pcb *in6p; + int s, error; - if (req == PRU_CONTROL) - return in6_control(so, (u_long)m, (void *)nam, - (struct ifnet *)control, l); - - if (req == PRU_PURGEIF) { - mutex_enter(softnet_lock); - in6_pcbpurgeif0(&raw6cbtable, (struct ifnet *)control); - in6_purgeif((struct ifnet *)control); - in6_pcbpurgeif(&raw6cbtable, (struct ifnet *)control); - mutex_exit(softnet_lock); - return 0; - } - - switch (req) { - case PRU_ATTACH: - error = kauth_authorize_network(l->l_cred, - KAUTH_NETWORK_SOCKET, KAUTH_REQ_NETWORK_SOCKET_RAWSOCK, - KAUTH_ARG(AF_INET6), - KAUTH_ARG(SOCK_RAW), - KAUTH_ARG(so->so_proto->pr_protocol)); - sosetlock(so); - if (in6p != NULL) - panic("rip6_attach"); - if (error) { - break; - } - s = splsoftnet(); - error = soreserve(so, rip6_sendspace, rip6_recvspace); - if (error != 0) { - splx(s); - break; - } - if ((error = in6_pcballoc(so, &raw6cbtable)) != 0) { - splx(s); - break; - } - splx(s); - in6p = sotoin6pcb(so); - in6p->in6p_ip6.ip6_nxt = (long)nam; - in6p->in6p_cksum = -1; - - in6p->in6p_icmp6filt = malloc(sizeof(struct icmp6_filter), - M_PCB, M_NOWAIT); - if (in6p->in6p_icmp6filt == NULL) { - in6_pcbdetach(in6p); - error = ENOMEM; - break; - } - ICMP6_FILTER_SETPASSALL(in6p->in6p_icmp6filt); - break; + KASSERT(sotoin6pcb(so) == NULL); + sosetlock(so); - case PRU_DISCONNECT: - if ((so->so_state & SS_ISCONNECTED) == 0) { - error = ENOTCONN; - break; - } - in6p->in6p_faddr = in6addr_any; - so->so_state &= ~SS_ISCONNECTED; /* XXX */ - break; + error = kauth_authorize_network(curlwp->l_cred, + KAUTH_NETWORK_SOCKET, KAUTH_REQ_NETWORK_SOCKET_RAWSOCK, + KAUTH_ARG(AF_INET6), + KAUTH_ARG(SOCK_RAW), + KAUTH_ARG(so->so_proto->pr_protocol)); + if (error) { + return error; + } + s = splsoftnet(); + error = soreserve(so, rip6_sendspace, rip6_recvspace); + if (error) { + splx(s); + return error; + } + if ((error = in6_pcballoc(so, &raw6cbtable)) != 0) { + splx(s); + return error; + } + splx(s); + in6p = sotoin6pcb(so); + in6p->in6p_ip6.ip6_nxt = proto; + in6p->in6p_cksum = -1; - case PRU_ABORT: - soisdisconnected(so); - /* Fallthrough */ - case PRU_DETACH: - if (in6p == NULL) - panic("rip6_detach"); - if (so == ip6_mrouter) - ip6_mrouter_done(); - /* xxx: RSVP */ - if (in6p->in6p_icmp6filt != NULL) { - free(in6p->in6p_icmp6filt, M_PCB); - in6p->in6p_icmp6filt = NULL; - } + in6p->in6p_icmp6filt = kmem_alloc(sizeof(struct icmp6_filter), KM_SLEEP); + if (in6p->in6p_icmp6filt == NULL) { in6_pcbdetach(in6p); - break; + return ENOMEM; + } + ICMP6_FILTER_SETPASSALL(in6p->in6p_icmp6filt); + KASSERT(solocked(so)); + return error; +} - case PRU_BIND: - { - struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *); - struct ifaddr *ia = NULL; +static void +rip6_detach(struct socket *so) +{ + struct in6pcb *in6p = sotoin6pcb(so); - if (nam->m_len != sizeof(*addr)) { - error = EINVAL; - break; - } - if (TAILQ_EMPTY(&ifnet) || addr->sin6_family != AF_INET6) { - error = EADDRNOTAVAIL; - break; - } - if ((error = sa6_embedscope(addr, ip6_use_defzone)) != 0) - break; + KASSERT(solocked(so)); + KASSERT(in6p != NULL); - /* - * we don't support mapped address here, it would confuse - * users so reject it - */ - if (IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr)) { - error = EADDRNOTAVAIL; - break; - } - if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) && - (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0) { - error = EADDRNOTAVAIL; - break; - } - if (ia && ((struct in6_ifaddr *)ia)->ia6_flags & - (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY| - IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) { - error = EADDRNOTAVAIL; - break; - } - in6p->in6p_laddr = addr->sin6_addr; - break; - } + if (so == ip6_mrouter) { + ip6_mrouter_done(); + } + /* xxx: RSVP */ + if (in6p->in6p_icmp6filt != NULL) { + kmem_free(in6p->in6p_icmp6filt, sizeof(struct icmp6_filter)); + in6p->in6p_icmp6filt = NULL; + } + in6_pcbdetach(in6p); +} - case PRU_CONNECT: - { - struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *); - struct in6_addr *in6a = NULL; - struct ifnet *ifp = NULL; - int scope_ambiguous = 0; +static int +rip6_accept(struct socket *so, struct mbuf *nam) +{ + KASSERT(solocked(so)); - if (nam->m_len != sizeof(*addr)) { - error = EINVAL; - break; - } - if (TAILQ_EMPTY(&ifnet)) { - error = EADDRNOTAVAIL; - break; - } - if (addr->sin6_family != AF_INET6) { - error = EAFNOSUPPORT; - break; - } + return EOPNOTSUPP; +} - /* - * Application should provide a proper zone ID or the use of - * default zone IDs should be enabled. Unfortunately, some - * applications do not behave as it should, so we need a - * workaround. Even if an appropriate ID is not determined, - * we'll see if we can determine the outgoing interface. If we - * can, determine the zone ID based on the interface below. - */ - if (addr->sin6_scope_id == 0 && !ip6_use_defzone) - scope_ambiguous = 1; - if ((error = sa6_embedscope(addr, ip6_use_defzone)) != 0) - return error; +static int +rip6_bind(struct socket *so, struct mbuf *nam, struct lwp *l) +{ + struct in6pcb *in6p = sotoin6pcb(so); + struct sockaddr_in6 *addr; + struct ifaddr *ia = NULL; + int error = 0; - /* Source address selection. XXX: need pcblookup? */ - in6a = in6_selectsrc(addr, in6p->in6p_outputopts, - in6p->in6p_moptions, &in6p->in6p_route, - &in6p->in6p_laddr, &ifp, &error); - if (in6a == NULL) { - if (error == 0) - error = EADDRNOTAVAIL; - break; - } - /* XXX: see above */ - if (ifp && scope_ambiguous && - (error = in6_setscope(&addr->sin6_addr, ifp, NULL)) != 0) { - break; - } - in6p->in6p_laddr = *in6a; - in6p->in6p_faddr = addr->sin6_addr; - soisconnected(so); - break; + KASSERT(solocked(so)); + KASSERT(in6p != NULL); + KASSERT(nam != NULL); + + addr = mtod(nam, struct sockaddr_in6 *); + if (nam->m_len != sizeof(*addr)) + return EINVAL; + if (IFNET_EMPTY() || addr->sin6_family != AF_INET6) + return EADDRNOTAVAIL; + + if ((error = sa6_embedscope(addr, ip6_use_defzone)) != 0) + return error; + + /* + * we don't support mapped address here, it would confuse + * users so reject it + */ + if (IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr)) + return EADDRNOTAVAIL; + if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) && + (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0) + return EADDRNOTAVAIL; + if (ia && ((struct in6_ifaddr *)ia)->ia6_flags & + (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY| + IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) + return EADDRNOTAVAIL; + in6p->in6p_laddr = addr->sin6_addr; + return 0; +} + +static int +rip6_listen(struct socket *so, struct lwp *l) +{ + KASSERT(solocked(so)); + + return EOPNOTSUPP; +} + +static int +rip6_connect(struct socket *so, struct mbuf *nam, struct lwp *l) +{ + struct in6pcb *in6p = sotoin6pcb(so); + struct sockaddr_in6 *addr; + struct in6_addr *in6a = NULL; + struct ifnet *ifp = NULL; + int scope_ambiguous = 0; + int error = 0; + + KASSERT(solocked(so)); + KASSERT(in6p != NULL); + KASSERT(nam != NULL); + + addr = mtod(nam, struct sockaddr_in6 *); + + if (nam->m_len != sizeof(*addr)) + return EINVAL; + if (IFNET_EMPTY()) + return EADDRNOTAVAIL; + if (addr->sin6_family != AF_INET6) + return EAFNOSUPPORT; + + /* + * Application should provide a proper zone ID or the use of + * default zone IDs should be enabled. Unfortunately, some + * applications do not behave as it should, so we need a + * workaround. Even if an appropriate ID is not determined, + * we'll see if we can determine the outgoing interface. If we + * can, determine the zone ID based on the interface below. + */ + if (addr->sin6_scope_id == 0 && !ip6_use_defzone) + scope_ambiguous = 1; + if ((error = sa6_embedscope(addr, ip6_use_defzone)) != 0) + return error; + + /* Source address selection. XXX: need pcblookup? */ + in6a = in6_selectsrc(addr, in6p->in6p_outputopts, + in6p->in6p_moptions, &in6p->in6p_route, + &in6p->in6p_laddr, &ifp, &error); + if (in6a == NULL) { + if (error == 0) + return EADDRNOTAVAIL; + return error; + } + /* XXX: see above */ + if (ifp && scope_ambiguous && + (error = in6_setscope(&addr->sin6_addr, ifp, NULL)) != 0) { + return error; } + in6p->in6p_laddr = *in6a; + in6p->in6p_faddr = addr->sin6_addr; + soisconnected(so); + return error; +} - case PRU_CONNECT2: - error = EOPNOTSUPP; - break; +static int +rip6_connect2(struct socket *so, struct socket *so2) +{ + KASSERT(solocked(so)); + + return EOPNOTSUPP; +} + +static int +rip6_disconnect(struct socket *so) +{ + struct in6pcb *in6p = sotoin6pcb(so); + + KASSERT(solocked(so)); + KASSERT(in6p != NULL); + + if ((so->so_state & SS_ISCONNECTED) == 0) + return ENOTCONN; + + in6p->in6p_faddr = in6addr_any; + so->so_state &= ~SS_ISCONNECTED; /* XXX */ + return 0; +} + +static int +rip6_shutdown(struct socket *so) +{ + KASSERT(solocked(so)); /* * Mark the connection as being incapable of futther input. */ - case PRU_SHUTDOWN: - socantsendmore(so); - break; + socantsendmore(so); + return 0; +} + +static int +rip6_abort(struct socket *so) +{ + KASSERT(solocked(so)); + + soisdisconnected(so); + rip6_detach(so); + return 0; +} + +static int +rip6_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp) +{ + return in6_control(so, cmd, nam, ifp); +} + +static int +rip6_stat(struct socket *so, struct stat *ub) +{ + KASSERT(solocked(so)); + + /* stat: don't bother with a blocksize */ + return 0; +} + +static int +rip6_peeraddr(struct socket *so, struct mbuf *nam) +{ + KASSERT(solocked(so)); + KASSERT(sotoin6pcb(so) != NULL); + KASSERT(nam != NULL); + + in6_setpeeraddr(sotoin6pcb(so), nam); + return 0; +} + +static int +rip6_sockaddr(struct socket *so, struct mbuf *nam) +{ + KASSERT(solocked(so)); + KASSERT(sotoin6pcb(so) != NULL); + KASSERT(nam != NULL); + + in6_setsockaddr(sotoin6pcb(so), nam); + return 0; +} + +static int +rip6_rcvd(struct socket *so, int flags, struct lwp *l) +{ + KASSERT(solocked(so)); + + return EOPNOTSUPP; +} + +static int +rip6_recvoob(struct socket *so, struct mbuf *m, int flags) +{ + KASSERT(solocked(so)); + + return EOPNOTSUPP; +} + +static int +rip6_send(struct socket *so, struct mbuf *m, struct mbuf *nam, + struct mbuf *control, struct lwp *l) +{ + struct in6pcb *in6p = sotoin6pcb(so); + struct sockaddr_in6 tmp; + struct sockaddr_in6 *dst; + int error = 0; + + KASSERT(solocked(so)); + KASSERT(in6p != NULL); + KASSERT(m != NULL); + /* * Ship a packet out. The appropriate raw output * routine handles any messaging necessary. */ - case PRU_SEND: - { - struct sockaddr_in6 tmp; - struct sockaddr_in6 *dst; - - /* always copy sockaddr to avoid overwrites */ - if (so->so_state & SS_ISCONNECTED) { - if (nam) { - error = EISCONN; - break; - } - /* XXX */ - sockaddr_in6_init(&tmp, &in6p->in6p_faddr, 0, 0, 0); - dst = &tmp; - } else { - if (nam == NULL) { - error = ENOTCONN; - break; - } - if (nam->m_len != sizeof(tmp)) { - error = EINVAL; - break; - } - tmp = *mtod(nam, struct sockaddr_in6 *); - dst = &tmp; + /* always copy sockaddr to avoid overwrites */ + if (so->so_state & SS_ISCONNECTED) { + if (nam) { + error = EISCONN; + goto release; + } + /* XXX */ + sockaddr_in6_init(&tmp, &in6p->in6p_faddr, 0, 0, 0); + dst = &tmp; + } else { + if (nam == NULL) { + error = ENOTCONN; + goto release; + } + if (nam->m_len != sizeof(tmp)) { + error = EINVAL; + goto release; + } + + tmp = *mtod(nam, struct sockaddr_in6 *); + dst = &tmp; - if (dst->sin6_family != AF_INET6) { - error = EAFNOSUPPORT; - break; - } + if (dst->sin6_family != AF_INET6) { + error = EAFNOSUPPORT; + goto release; } - error = rip6_output(m, so, dst, control); - m = NULL; - break; } + error = rip6_output(m, so, dst, control); + m = NULL; - case PRU_SENSE: - /* - * stat: don't bother with a blocksize - */ - return 0; - /* - * Not supported. - */ - case PRU_RCVOOB: - case PRU_RCVD: - case PRU_LISTEN: - case PRU_ACCEPT: - case PRU_SENDOOB: - error = EOPNOTSUPP; - break; +release: + if (m) + m_freem(m); - case PRU_SOCKADDR: - in6_setsockaddr(in6p, nam); - break; + return error; +} - case PRU_PEERADDR: - in6_setpeeraddr(in6p, nam); - break; +static int +rip6_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control) +{ + KASSERT(solocked(so)); - default: - panic("rip6_usrreq"); - } - if (m != NULL) - m_freem(m); - return error; + if (m) + m_freem(m); + + return EOPNOTSUPP; +} + +static int +rip6_purgeif(struct socket *so, struct ifnet *ifp) +{ + + mutex_enter(softnet_lock); + in6_pcbpurgeif0(&raw6cbtable, ifp); + in6_purgeif(ifp); + in6_pcbpurgeif(&raw6cbtable, ifp); + mutex_exit(softnet_lock); + + return 0; +} + +int +rip6_usrreq(struct socket *so, int req, struct mbuf *m, + struct mbuf *nam, struct mbuf *control, struct lwp *l) +{ + + KASSERT(req != PRU_ACCEPT); + KASSERT(req != PRU_BIND); + KASSERT(req != PRU_LISTEN); + KASSERT(req != PRU_CONNECT); + KASSERT(req != PRU_CONNECT2); + KASSERT(req != PRU_DISCONNECT); + KASSERT(req != PRU_SHUTDOWN); + KASSERT(req != PRU_ABORT); + KASSERT(req != PRU_CONTROL); + KASSERT(req != PRU_SENSE); + KASSERT(req != PRU_PEERADDR); + KASSERT(req != PRU_SOCKADDR); + KASSERT(req != PRU_RCVD); + KASSERT(req != PRU_RCVOOB); + KASSERT(req != PRU_SEND); + KASSERT(req != PRU_PURGEIF); + KASSERT(req != PRU_SENDOOB); + + panic("rip6_usrreq"); + + return 0; } static int @@ -881,3 +998,48 @@ sysctl_net_inet6_raw6_setup(struct sysct CTL_NET, PF_INET6, IPPROTO_RAW, RAW6CTL_STATS, CTL_EOL); } + +PR_WRAP_USRREQS(rip6) +#define rip6_attach rip6_attach_wrapper +#define rip6_detach rip6_detach_wrapper +#define rip6_accept rip6_accept_wrapper +#define rip6_bind rip6_bind_wrapper +#define rip6_listen rip6_listen_wrapper +#define rip6_connect rip6_connect_wrapper +#define rip6_connect2 rip6_connect2_wrapper +#define rip6_disconnect rip6_disconnect_wrapper +#define rip6_shutdown rip6_shutdown_wrapper +#define rip6_abort rip6_abort_wrapper +#define rip6_ioctl rip6_ioctl_wrapper +#define rip6_stat rip6_stat_wrapper +#define rip6_peeraddr rip6_peeraddr_wrapper +#define rip6_sockaddr rip6_sockaddr_wrapper +#define rip6_rcvd rip6_rcvd_wrapper +#define rip6_recvoob rip6_recvoob_wrapper +#define rip6_send rip6_send_wrapper +#define rip6_sendoob rip6_sendoob_wrapper +#define rip6_purgeif rip6_purgeif_wrapper +#define rip6_usrreq rip6_usrreq_wrapper + +const struct pr_usrreqs rip6_usrreqs = { + .pr_attach = rip6_attach, + .pr_detach = rip6_detach, + .pr_accept = rip6_accept, + .pr_bind = rip6_bind, + .pr_listen = rip6_listen, + .pr_connect = rip6_connect, + .pr_connect2 = rip6_connect2, + .pr_disconnect = rip6_disconnect, + .pr_shutdown = rip6_shutdown, + .pr_abort = rip6_abort, + .pr_ioctl = rip6_ioctl, + .pr_stat = rip6_stat, + .pr_peeraddr = rip6_peeraddr, + .pr_sockaddr = rip6_sockaddr, + .pr_rcvd = rip6_rcvd, + .pr_recvoob = rip6_recvoob, + .pr_send = rip6_send, + .pr_sendoob = rip6_sendoob, + .pr_purgeif = rip6_purgeif, + .pr_generic = rip6_usrreq, +}; Index: src/sys/netinet6/scope6.c diff -u src/sys/netinet6/scope6.c:1.8 src/sys/netinet6/scope6.c:1.8.36.1 --- src/sys/netinet6/scope6.c:1.8 Fri Sep 11 22:06:29 2009 +++ src/sys/netinet6/scope6.c Sun Aug 10 06:56:30 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: scope6.c,v 1.8 2009/09/11 22:06:29 dyoung Exp $ */ +/* $NetBSD: scope6.c,v 1.8.36.1 2014/08/10 06:56:30 tls Exp $ */ /* $KAME$ */ /*- @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: scope6.c,v 1.8 2009/09/11 22:06:29 dyoung Exp $"); +__KERNEL_RCSID(0, "$NetBSD: scope6.c,v 1.8.36.1 2014/08/10 06:56:30 tls Exp $"); #include <sys/param.h> #include <sys/malloc.h> @@ -130,7 +130,7 @@ scope6_set(struct ifnet *ifp, const stru return (EINVAL); if (i == IPV6_ADDR_SCOPE_LINKLOCAL && - idlist->s6id_list[i] >= if_indexlim) { + !if_byindex(idlist->s6id_list[i])) { /* * XXX: theoretically, there should be no * relationship between link IDs and interface @@ -309,14 +309,8 @@ sa6_embedscope(struct sockaddr_in6 *sin6 * zone IDs assuming a one-to-one mapping between interfaces * and links. */ - if (if_indexlim <= zoneid) - return (ENXIO); -#ifdef __FreeBSD__ - ifp = ifnet_byindex(zoneid); -#else - ifp = ifindex2ifnet[zoneid]; -#endif - if (ifp == NULL) /* XXX: this can happen for some OS */ + ifp = if_byindex(zoneid); + if (ifp == NULL) return (ENXIO); /* XXX assignment to 16bit from 32bit variable */ @@ -363,14 +357,7 @@ sa6_recoverscope(struct sockaddr_in6 *si */ zoneid = ntohs(sin6->sin6_addr.s6_addr16[1]); if (zoneid) { - /* sanity check */ - if (/* zoneid < 0 || */ if_indexlim <= zoneid) - return (ENXIO); -#ifdef __FreeBSD__ - if (!ifnet_byindex(zoneid)) -#else - if (!ifindex2ifnet[zoneid]) -#endif + if (!if_byindex(zoneid)) return (ENXIO); sin6->sin6_addr.s6_addr16[1] = 0; sin6->sin6_scope_id = zoneid; Index: src/sys/netinet6/udp6_usrreq.c diff -u src/sys/netinet6/udp6_usrreq.c:1.93 src/sys/netinet6/udp6_usrreq.c:1.93.2.1 --- src/sys/netinet6/udp6_usrreq.c:1.93 Tue Feb 25 18:30:12 2014 +++ src/sys/netinet6/udp6_usrreq.c Sun Aug 10 06:56:30 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: udp6_usrreq.c,v 1.93 2014/02/25 18:30:12 pooka Exp $ */ +/* $NetBSD: udp6_usrreq.c,v 1.93.2.1 2014/08/10 06:56:30 tls Exp $ */ /* $KAME: udp6_usrreq.c,v 1.86 2001/05/27 17:33:00 itojun Exp $ */ /* @@ -62,18 +62,16 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: udp6_usrreq.c,v 1.93 2014/02/25 18:30:12 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: udp6_usrreq.c,v 1.93.2.1 2014/08/10 06:56:30 tls Exp $"); #include "opt_inet.h" +#include "opt_inet_csum.h" #include <sys/param.h> -#include <sys/malloc.h> #include <sys/mbuf.h> #include <sys/protosw.h> #include <sys/socket.h> #include <sys/socketvar.h> -#include <sys/errno.h> -#include <sys/stat.h> #include <sys/systm.h> #include <sys/proc.h> #include <sys/syslog.h> @@ -87,19 +85,23 @@ __KERNEL_RCSID(0, "$NetBSD: udp6_usrreq. #include <netinet/in.h> #include <netinet/in_var.h> #include <netinet/in_systm.h> +#include <netinet/in_offload.h> #include <netinet/ip.h> #include <netinet/ip_var.h> #include <netinet/in_pcb.h> #include <netinet/udp.h> #include <netinet/udp_var.h> +#include <netinet/udp_private.h> + #include <netinet/ip6.h> +#include <netinet/icmp6.h> #include <netinet6/ip6_var.h> +#include <netinet6/ip6_private.h> #include <netinet6/in6_pcb.h> -#include <netinet/icmp6.h> #include <netinet6/udp6_var.h> #include <netinet6/udp6_private.h> #include <netinet6/ip6protosw.h> -#include <netinet/in_offload.h> +#include <netinet6/scope6_var.h> #include "faith.h" #if defined(NFAITH) && NFAITH > 0 @@ -115,13 +117,38 @@ extern struct inpcbtable udbtable; percpu_t *udp6stat_percpu; +/* UDP on IP6 parameters */ +static int udp6_sendspace = 9216; /* really max datagram size */ +static int udp6_recvspace = 40 * (1024 + sizeof(struct sockaddr_in6)); + /* 40 1K datagrams */ + static void udp6_notify(struct in6pcb *, int); static void sysctl_net_inet6_udp6_setup(struct sysctllog **); +#ifdef UDP_CSUM_COUNTERS +#include <sys/device.h> +struct evcnt udp6_hwcsum_bad = EVCNT_INITIALIZER(EVCNT_TYPE_MISC, + NULL, "udp6", "hwcsum bad"); +struct evcnt udp6_hwcsum_ok = EVCNT_INITIALIZER(EVCNT_TYPE_MISC, + NULL, "udp6", "hwcsum ok"); +struct evcnt udp6_hwcsum_data = EVCNT_INITIALIZER(EVCNT_TYPE_MISC, + NULL, "udp6", "hwcsum data"); +struct evcnt udp6_swcsum = EVCNT_INITIALIZER(EVCNT_TYPE_MISC, + NULL, "udp6", "swcsum"); + +EVCNT_ATTACH_STATIC(udp6_hwcsum_bad); +EVCNT_ATTACH_STATIC(udp6_hwcsum_ok); +EVCNT_ATTACH_STATIC(udp6_hwcsum_data); +EVCNT_ATTACH_STATIC(udp6_swcsum); + +#define UDP_CSUM_COUNTER_INCR(ev) (ev)->ev_count++ +#else +#define UDP_CSUM_COUNTER_INCR(ev) /* nothing */ +#endif + void udp6_init(void) { - sysctl_net_inet6_udp6_setup(NULL); udp6stat_percpu = percpu_alloc(sizeof(uint64_t) * UDP6_NSTATS); @@ -298,18 +325,472 @@ end: return error; } +static void +udp6_sendup(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); + +#if defined(IPSEC) + /* check AH/ESP integrity. */ + if (ipsec_used && so != NULL && ipsec6_in_reject_so(m, so)) { + IPSEC6_STATINC(IPSEC_STAT_IN_POLVIO); + if ((n = m_copypacket(m, M_DONTWAIT)) != NULL) + icmp6_error(n, ICMP6_DST_UNREACH, + ICMP6_DST_UNREACH_ADMIN, 0); + return; + } +#endif /*IPSEC*/ + + if ((n = m_copypacket(m, M_DONTWAIT)) != NULL) { + if (in6p && (in6p->in6p_flags & IN6P_CONTROLOPTS +#ifdef SO_OTIMESTAMP + || in6p->in6p_socket->so_options & SO_OTIMESTAMP +#endif + || in6p->in6p_socket->so_options & SO_TIMESTAMP)) { + struct ip6_hdr *ip6 = mtod(n, struct ip6_hdr *); + ip6_savecontrol(in6p, &opts, ip6, n); + } -extern int udp6_sendspace; -extern int udp6_recvspace; + m_adj(n, off); + if (sbappendaddr(&so->so_rcv, src, n, opts) == 0) { + m_freem(n); + if (opts) + m_freem(opts); + so->so_rcv.sb_overflowed++; + UDP6_STATINC(UDP6_STAT_FULLSOCK); + } else + sorwakeup(so); + } +} int -udp6_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *addr6, - struct mbuf *control, struct lwp *l) +udp6_realinput(int af, struct sockaddr_in6 *src, struct sockaddr_in6 *dst, + struct mbuf *m, int off) +{ + u_int16_t sport, dport; + int rcvcnt; + struct in6_addr src6, *dst6; + const struct in_addr *dst4; + struct inpcb_hdr *inph; + 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; + if (sa6_recoverscope(src) != 0) { + /* XXX: should be impossible. */ + goto bad; + } + sport = src->sin6_port; + + dport = dst->sin6_port; + dst4 = (struct in_addr *)&dst->sin6_addr.s6_addr[12]; + dst6 = &dst->sin6_addr; + + if (IN6_IS_ADDR_MULTICAST(dst6) || + (af == AF_INET && IN_MULTICAST(dst4->s_addr))) { + /* + * 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: traditionally we dropped udpiphdr from mbuf here. + * we need udpiphdr for IPsec processing so we do that later. + */ + /* + * Locate pcb(s) for datagram. + */ + TAILQ_FOREACH(inph, &udbtable.inpt_queue, inph_queue) { + in6p = (struct in6pcb *)inph; + if (in6p->in6p_af != AF_INET6) + continue; + + if (in6p->in6p_lport != dport) + continue; + if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) { + if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, + dst6)) + continue; + } else { + if (IN6_IS_ADDR_V4MAPPED(dst6) && + (in6p->in6p_flags & IN6P_IPV6_V6ONLY)) + continue; + } + if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { + if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, + &src6) || in6p->in6p_fport != sport) + continue; + } else { + if (IN6_IS_ADDR_V4MAPPED(&src6) && + (in6p->in6p_flags & IN6P_IPV6_V6ONLY)) + continue; + } + + 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; + } + } else { + /* + * Locate pcb for datagram. + */ + in6p = in6_pcblookup_connect(&udbtable, &src6, sport, dst6, + dport, 0, 0); + if (in6p == 0) { + UDP_STATINC(UDP_STAT_PCBHASHMISS); + in6p = in6_pcblookup_bind(&udbtable, dst6, dport, 0); + if (in6p == 0) + return rcvcnt; + } + + udp6_sendup(m, off, (struct sockaddr *)src, in6p->in6p_socket); + rcvcnt++; + } + +bad: + return rcvcnt; +} + +int +udp6_input_checksum(struct mbuf *m, const struct udphdr *uh, int off, int len) +{ + + /* + * XXX it's better to record and check if this mbuf is + * already checked. + */ + + if (__predict_false((m->m_flags & M_LOOP) && !udp_do_loopback_cksum)) { + goto good; + } + if (uh->uh_sum == 0) { + UDP6_STATINC(UDP6_STAT_NOSUM); + goto bad; + } + + switch (m->m_pkthdr.csum_flags & + ((m->m_pkthdr.rcvif->if_csum_flags_rx & M_CSUM_UDPv6) | + M_CSUM_TCP_UDP_BAD | M_CSUM_DATA)) { + case M_CSUM_UDPv6|M_CSUM_TCP_UDP_BAD: + UDP_CSUM_COUNTER_INCR(&udp6_hwcsum_bad); + UDP6_STATINC(UDP6_STAT_BADSUM); + goto bad; + +#if 0 /* notyet */ + case M_CSUM_UDPv6|M_CSUM_DATA: +#endif + + case M_CSUM_UDPv6: + /* Checksum was okay. */ + UDP_CSUM_COUNTER_INCR(&udp6_hwcsum_ok); + break; + + default: + /* + * Need to compute it ourselves. Maybe skip checksum + * on loopback interfaces. + */ + UDP_CSUM_COUNTER_INCR(&udp6_swcsum); + if (in6_cksum(m, IPPROTO_UDP, off, len) != 0) { + UDP6_STATINC(UDP6_STAT_BADSUM); + goto bad; + } + } + +good: + return 0; +bad: + return -1; +} + +int +udp6_input(struct mbuf **mp, int *offp, int 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; + + ip6 = mtod(m, struct ip6_hdr *); + +#if defined(NFAITH) && 0 < NFAITH + if (faithprefix(&ip6->ip6_dst)) { + /* send icmp6 host unreach? */ + m_freem(m); + return IPPROTO_DONE; + } +#endif + + UDP6_STATINC(UDP6_STAT_IPACKETS); + + /* check for jumbogram is done in ip6_input. we can trust pkthdr.len */ + plen = m->m_pkthdr.len - off; + IP6_EXTHDR_GET(uh, struct udphdr *, m, off, sizeof(struct udphdr)); + if (uh == NULL) { + IP6_STATINC(IP6_STAT_TOOSHORT); + return IPPROTO_DONE; + } + KASSERT(UDP_HDR_ALIGNED_P(uh)); + ulen = ntohs((u_short)uh->uh_ulen); + /* + * RFC2675 section 4: jumbograms will have 0 in the UDP header field, + * iff payload length > 0xffff. + */ + if (ulen == 0 && plen > 0xffff) + ulen = plen; + + if (plen != ulen) { + UDP6_STATINC(UDP6_STAT_BADLEN); + goto bad; + } + + /* destination port of 0 is illegal, based on RFC768. */ + if (uh->uh_dport == 0) + goto bad; + + /* Be proactive about malicious use of IPv4 mapped address */ + if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || + IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { + /* XXX stat */ + goto bad; + } + + /* + * Checksum extended UDP header and data. Maybe skip checksum + * on loopback interfaces. + */ + if (udp6_input_checksum(m, uh, off, ulen)) + goto bad; + + /* + * Construct source and dst sockaddrs. + */ + memset(&src, 0, sizeof(src)); + src.sin6_family = AF_INET6; + src.sin6_len = sizeof(struct sockaddr_in6); + src.sin6_addr = ip6->ip6_src; + src.sin6_port = uh->uh_sport; + memset(&dst, 0, sizeof(dst)); + dst.sin6_family = AF_INET6; + dst.sin6_len = sizeof(struct sockaddr_in6); + dst.sin6_addr = ip6->ip6_dst; + dst.sin6_port = uh->uh_dport; + + if (udp6_realinput(AF_INET6, &src, &dst, m, off) == 0) { + if (m->m_flags & M_MCAST) { + UDP6_STATINC(UDP6_STAT_NOPORTMCAST); + goto bad; + } + UDP6_STATINC(UDP6_STAT_NOPORT); + icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0); + m = NULL; + } + +bad: + if (m) + m_freem(m); + return IPPROTO_DONE; +} + +static int +udp6_attach(struct socket *so, int proto) +{ + struct in6pcb *in6p; + int s, error; + + KASSERT(sotoin6pcb(so) == NULL); + sosetlock(so); + + /* + * MAPPED_ADDR implementation spec: + * Always attach for IPv6, and only when necessary for IPv4. + */ + s = splsoftnet(); + error = in6_pcballoc(so, &udbtable); + splx(s); + if (error) { + return error; + } + error = soreserve(so, udp6_sendspace, udp6_recvspace); + if (error) { + return error; + } + in6p = sotoin6pcb(so); + in6p->in6p_cksum = -1; /* just to be sure */ + + KASSERT(solocked(so)); + return 0; +} + +static void +udp6_detach(struct socket *so) +{ + struct in6pcb *in6p = sotoin6pcb(so); + int s; + + KASSERT(solocked(so)); + KASSERT(in6p != NULL); + + s = splsoftnet(); + in6_pcbdetach(in6p); + splx(s); +} + +static int +udp6_accept(struct socket *so, struct mbuf *nam) +{ + KASSERT(solocked(so)); + + return EOPNOTSUPP; +} + +static int +udp6_bind(struct socket *so, struct mbuf *nam, struct lwp *l) +{ + struct in6pcb *in6p = sotoin6pcb(so); + int error = 0; + int s; + + KASSERT(solocked(so)); + KASSERT(in6p != NULL); + + s = splsoftnet(); + error = in6_pcbbind(in6p, nam, l); + splx(s); + return error; +} + +static int +udp6_listen(struct socket *so, struct lwp *l) +{ + KASSERT(solocked(so)); + + return EOPNOTSUPP; +} + +static int +udp6_connect(struct socket *so, struct mbuf *nam, struct lwp *l) +{ + struct in6pcb *in6p = sotoin6pcb(so); + int error = 0; + int s; + + KASSERT(solocked(so)); + KASSERT(in6p != NULL); + + if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) + return EISCONN; + s = splsoftnet(); + error = in6_pcbconnect(in6p, nam, l); + splx(s); + if (error == 0) + soisconnected(so); + + return error; +} + +static int +udp6_connect2(struct socket *so, struct socket *so2) +{ + KASSERT(solocked(so)); + + return EOPNOTSUPP; +} + +static int +udp6_disconnect(struct socket *so) +{ + struct in6pcb *in6p = sotoin6pcb(so); + int s; + + KASSERT(solocked(so)); + KASSERT(in6p != NULL); + + if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) + return ENOTCONN; + + s = splsoftnet(); + in6_pcbdisconnect(in6p); + memset((void *)&in6p->in6p_laddr, 0, sizeof(in6p->in6p_laddr)); + splx(s); + + so->so_state &= ~SS_ISCONNECTED; /* XXX */ + in6_pcbstate(in6p, IN6P_BOUND); /* XXX */ + return 0; +} + +static int +udp6_shutdown(struct socket *so) { - struct in6pcb *in6p = sotoin6pcb(so); - int error = 0; - int s; + int s; + s = splsoftnet(); + socantsendmore(so); + splx(s); + + return 0; +} + +static int +udp6_abort(struct socket *so) +{ + int s; + + KASSERT(solocked(so)); + KASSERT(sotoin6pcb(so) != NULL); + + s = splsoftnet(); + soisdisconnected(so); + in6_pcbdetach(sotoin6pcb(so)); + splx(s); + + return 0; +} + +static int +udp6_ioctl(struct socket *so, u_long cmd, void *addr6, struct ifnet *ifp) +{ /* * MAPPED_ADDR implementation info: * Mapped addr support for PRU_CONTROL is not necessary. @@ -320,117 +801,133 @@ udp6_usrreq(struct socket *so, int req, * So AF_INET socket need to be used to control AF_INET addrs, * and AF_INET6 socket for AF_INET6 addrs. */ - if (req == PRU_CONTROL) - return in6_control(so, (u_long)m, (void *)addr6, - (struct ifnet *)control, l); - - if (req == PRU_PURGEIF) { - mutex_enter(softnet_lock); - in6_pcbpurgeif0(&udbtable, (struct ifnet *)control); - in6_purgeif((struct ifnet *)control); - in6_pcbpurgeif(&udbtable, (struct ifnet *)control); - mutex_exit(softnet_lock); - return 0; - } - - if (req == PRU_ATTACH) - sosetlock(so); - else if (in6p == NULL) { - error = EINVAL; - goto release; - } + return in6_control(so, cmd, addr6, ifp); +} - switch (req) { - case PRU_ATTACH: - /* - * MAPPED_ADDR implementation spec: - * Always attach for IPv6, - * and only when necessary for IPv4. - */ - if (in6p != NULL) { - error = EINVAL; - break; - } - s = splsoftnet(); - error = in6_pcballoc(so, &udbtable); - splx(s); - if (error) - break; - error = soreserve(so, udp6_sendspace, udp6_recvspace); - if (error) - break; - in6p = sotoin6pcb(so); - in6p->in6p_cksum = -1; /* just to be sure */ - break; +static int +udp6_stat(struct socket *so, struct stat *ub) +{ + KASSERT(solocked(so)); - case PRU_DETACH: - in6_pcbdetach(in6p); - break; + /* stat: don't bother with a blocksize */ + return 0; +} - case PRU_BIND: - s = splsoftnet(); - error = in6_pcbbind(in6p, addr6, l); - splx(s); - break; +static int +udp6_peeraddr(struct socket *so, struct mbuf *nam) +{ + KASSERT(solocked(so)); + KASSERT(sotoin6pcb(so) != NULL); + KASSERT(nam != NULL); - case PRU_CONNECT: - if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { - error = EISCONN; - break; - } - s = splsoftnet(); - error = in6_pcbconnect(in6p, addr6, l); - splx(s); - if (error == 0) - soisconnected(so); - break; + in6_setpeeraddr(sotoin6pcb(so), nam); + return 0; +} - case PRU_DISCONNECT: - if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { - error = ENOTCONN; - break; - } - s = splsoftnet(); - in6_pcbdisconnect(in6p); - memset((void *)&in6p->in6p_laddr, 0, sizeof(in6p->in6p_laddr)); - splx(s); - so->so_state &= ~SS_ISCONNECTED; /* XXX */ - in6_pcbstate(in6p, IN6P_BOUND); /* XXX */ - break; +static int +udp6_sockaddr(struct socket *so, struct mbuf *nam) +{ + KASSERT(solocked(so)); + KASSERT(sotoin6pcb(so) != NULL); + KASSERT(nam != NULL); - case PRU_SHUTDOWN: - socantsendmore(so); - break; + in6_setsockaddr(sotoin6pcb(so), nam); + return 0; +} - case PRU_SEND: - s = splsoftnet(); - error = udp6_output(in6p, m, addr6, control, l); - splx(s); - return error; +static int +udp6_rcvd(struct socket *so, int flags, struct lwp *l) +{ + KASSERT(solocked(so)); - case PRU_ABORT: - soisdisconnected(so); - in6_pcbdetach(in6p); - break; + return EOPNOTSUPP; +} - case PRU_SOCKADDR: - in6_setsockaddr(in6p, addr6); - break; +static int +udp6_recvoob(struct socket *so, struct mbuf *m, int flags) +{ + KASSERT(solocked(so)); - case PRU_PEERADDR: - in6_setpeeraddr(in6p, addr6); - break; + return EOPNOTSUPP; +} - case PRU_SENSE: - /* - * stat: don't bother with a blocksize - */ - return 0; +static int +udp6_send(struct socket *so, struct mbuf *m, struct mbuf *nam, + struct mbuf *control, struct lwp *l) +{ + struct in6pcb *in6p = sotoin6pcb(so); + int error = 0; + int s; + + KASSERT(solocked(so)); + KASSERT(in6p != NULL); + KASSERT(m != NULL); + + s = splsoftnet(); + error = udp6_output(in6p, m, nam, control, l); + splx(s); + + return error; +} + +static int +udp6_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control) +{ + KASSERT(solocked(so)); + + if (m) + m_freem(m); + if (control) + m_freem(control); + + return EOPNOTSUPP; +} + +static int +udp6_purgeif(struct socket *so, struct ifnet *ifp) +{ + + mutex_enter(softnet_lock); + in6_pcbpurgeif0(&udbtable, ifp); + in6_purgeif(ifp); + in6_pcbpurgeif(&udbtable, ifp); + mutex_exit(softnet_lock); - case PRU_LISTEN: - case PRU_CONNECT2: - case PRU_ACCEPT: - case PRU_SENDOOB: + return 0; +} + +int +udp6_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *addr6, + struct mbuf *control, struct lwp *l) +{ + int error = 0; + + KASSERT(req != PRU_ATTACH); + KASSERT(req != PRU_DETACH); + KASSERT(req != PRU_ACCEPT); + KASSERT(req != PRU_BIND); + KASSERT(req != PRU_LISTEN); + KASSERT(req != PRU_CONNECT); + KASSERT(req != PRU_CONNECT2); + KASSERT(req != PRU_DISCONNECT); + KASSERT(req != PRU_SHUTDOWN); + KASSERT(req != PRU_ABORT); + KASSERT(req != PRU_CONTROL); + KASSERT(req != PRU_SENSE); + KASSERT(req != PRU_PEERADDR); + KASSERT(req != PRU_SOCKADDR); + KASSERT(req != PRU_RCVD); + KASSERT(req != PRU_RCVOOB); + KASSERT(req != PRU_SEND); + KASSERT(req != PRU_SENDOOB); + KASSERT(req != PRU_PURGEIF); + + if (sotoin6pcb(so) == NULL) { + error = EINVAL; + goto release; + } + + switch (req) { case PRU_FASTTIMO: case PRU_SLOWTIMO: case PRU_PROTORCV: @@ -438,10 +935,6 @@ udp6_usrreq(struct socket *so, int req, error = EOPNOTSUPP; break; - case PRU_RCVD: - case PRU_RCVOOB: - return EOPNOTSUPP; /* do not free mbuf's */ - default: panic("udp6_usrreq"); } @@ -521,3 +1014,48 @@ udp6_statinc(u_int stat) KASSERT(stat < UDP6_NSTATS); UDP6_STATINC(stat); } + +PR_WRAP_USRREQS(udp6) +#define udp6_attach udp6_attach_wrapper +#define udp6_detach udp6_detach_wrapper +#define udp6_accept udp6_accept_wrapper +#define udp6_bind udp6_bind_wrapper +#define udp6_listen udp6_listen_wrapper +#define udp6_connect udp6_connect_wrapper +#define udp6_connect2 udp6_connect2_wrapper +#define udp6_disconnect udp6_disconnect_wrapper +#define udp6_shutdown udp6_shutdown_wrapper +#define udp6_abort udp6_abort_wrapper +#define udp6_ioctl udp6_ioctl_wrapper +#define udp6_stat udp6_stat_wrapper +#define udp6_peeraddr udp6_peeraddr_wrapper +#define udp6_sockaddr udp6_sockaddr_wrapper +#define udp6_rcvd udp6_rcvd_wrapper +#define udp6_recvoob udp6_recvoob_wrapper +#define udp6_send udp6_send_wrapper +#define udp6_sendoob udp6_sendoob_wrapper +#define udp6_purgeif udp6_purgeif_wrapper +#define udp6_usrreq udp6_usrreq_wrapper + +const struct pr_usrreqs udp6_usrreqs = { + .pr_attach = udp6_attach, + .pr_detach = udp6_detach, + .pr_accept = udp6_accept, + .pr_bind = udp6_bind, + .pr_listen = udp6_listen, + .pr_connect = udp6_connect, + .pr_connect2 = udp6_connect2, + .pr_disconnect = udp6_disconnect, + .pr_shutdown = udp6_shutdown, + .pr_abort = udp6_abort, + .pr_ioctl = udp6_ioctl, + .pr_stat = udp6_stat, + .pr_peeraddr = udp6_peeraddr, + .pr_sockaddr = udp6_sockaddr, + .pr_rcvd = udp6_rcvd, + .pr_recvoob = udp6_recvoob, + .pr_send = udp6_send, + .pr_sendoob = udp6_sendoob, + .pr_purgeif = udp6_purgeif, + .pr_generic = udp6_usrreq, +}; Index: src/sys/netinet6/udp6_var.h diff -u src/sys/netinet6/udp6_var.h:1.25 src/sys/netinet6/udp6_var.h:1.25.12.1 --- src/sys/netinet6/udp6_var.h:1.25 Fri Jun 22 14:54:35 2012 +++ src/sys/netinet6/udp6_var.h Sun Aug 10 06:56:30 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: udp6_var.h,v 1.25 2012/06/22 14:54:35 christos Exp $ */ +/* $NetBSD: udp6_var.h,v 1.25.12.1 2014/08/10 06:56:30 tls Exp $ */ /* $KAME: udp6_var.h,v 1.11 2000/06/05 00:14:31 itojun Exp $ */ /* @@ -99,6 +99,9 @@ } #ifdef _KERNEL + +extern const struct pr_usrreqs udp6_usrreqs; + void *udp6_ctlinput(int, const struct sockaddr *, void *); int udp6_ctloutput(int, struct socket *, struct sockopt *); void udp6_init(void); @@ -108,6 +111,9 @@ int udp6_output(struct in6pcb *, struct int udp6_sysctl(int *, u_int, void *, size_t *, void *, size_t); int udp6_usrreq(struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *, struct lwp *); +int udp6_realinput(int, struct sockaddr_in6 *, struct sockaddr_in6 *, + struct mbuf *, int); +int udp6_input_checksum(struct mbuf *, const struct udphdr *, int, int); void udp6_statinc(u_int); #endif /* _KERNEL */