Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet6/ip6_input.c
Show First 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | |||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include "opt_inet.h" | #include "opt_inet.h" | ||||
#include "opt_inet6.h" | #include "opt_inet6.h" | ||||
#include "opt_ipsec.h" | #include "opt_ipsec.h" | ||||
#include "opt_route.h" | #include "opt_route.h" | ||||
#include "opt_rss.h" | #include "opt_rss.h" | ||||
#include "opt_sctp.h" | |||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/hhook.h> | #include <sys/hhook.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/mbuf.h> | #include <sys/mbuf.h> | ||||
#include <sys/proc.h> | #include <sys/proc.h> | ||||
#include <sys/domain.h> | #include <sys/domain.h> | ||||
Show All 26 Lines | |||||
#include <net/if_llatbl.h> | #include <net/if_llatbl.h> | ||||
#ifdef INET | #ifdef INET | ||||
#include <netinet/ip.h> | #include <netinet/ip.h> | ||||
#include <netinet/ip_icmp.h> | #include <netinet/ip_icmp.h> | ||||
#endif /* INET */ | #endif /* INET */ | ||||
#include <netinet/ip6.h> | #include <netinet/ip6.h> | ||||
#include <netinet6/in6_var.h> | #include <netinet6/in6_var.h> | ||||
#include <netinet6/ip6_var.h> | #include <netinet6/ip6_var.h> | ||||
#include <netinet/ip_encap.h> | |||||
#include <netinet/in_pcb.h> | #include <netinet/in_pcb.h> | ||||
#include <netinet/icmp6.h> | #include <netinet/icmp6.h> | ||||
#include <netinet6/scope6_var.h> | #include <netinet6/scope6_var.h> | ||||
#include <netinet6/in6_ifattach.h> | #include <netinet6/in6_ifattach.h> | ||||
#include <netinet6/mld6_var.h> | #include <netinet6/mld6_var.h> | ||||
#include <netinet6/nd6.h> | #include <netinet6/nd6.h> | ||||
#include <netinet6/in6_rss.h> | #include <netinet6/in6_rss.h> | ||||
#ifdef SCTP | |||||
#include <netinet/sctp_pcb.h> | |||||
#include <netinet6/sctp6_var.h> | |||||
#endif | |||||
#include <netipsec/ipsec_support.h> | #include <netipsec/ipsec_support.h> | ||||
#include <netinet6/ip6protosw.h> | #include <netinet6/ip6protosw.h> | ||||
extern struct domain inet6domain; | ipproto_input_t *ip6_protox[IPPROTO_MAX] = { | ||||
[0 ... IPPROTO_MAX - 1] = rip6_input }; | |||||
ipproto_ctlinput_t *ip6_ctlprotox[IPPROTO_MAX] = { | |||||
[0 ... IPPROTO_MAX - 1] = rip6_ctlinput }; | |||||
melifaro: Probably worth asserting that `IPPROTO_MAX` is >= 256, just in case. | |||||
u_char ip6_protox[IPPROTO_MAX]; | |||||
VNET_DEFINE(struct in6_ifaddrhead, in6_ifaddrhead); | VNET_DEFINE(struct in6_ifaddrhead, in6_ifaddrhead); | ||||
VNET_DEFINE(struct in6_ifaddrlisthead *, in6_ifaddrhashtbl); | VNET_DEFINE(struct in6_ifaddrlisthead *, in6_ifaddrhashtbl); | ||||
VNET_DEFINE(u_long, in6_ifaddrhmask); | VNET_DEFINE(u_long, in6_ifaddrhmask); | ||||
static struct netisr_handler ip6_nh = { | static struct netisr_handler ip6_nh = { | ||||
.nh_name = "ip6", | .nh_name = "ip6", | ||||
.nh_handler = ip6_input, | .nh_handler = ip6_input, | ||||
.nh_proto = NETISR_IPV6, | .nh_proto = NETISR_IPV6, | ||||
▲ Show 20 Lines • Show All 126 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
} | } | ||||
VNET_SYSINIT(ip6_vnet_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH, | VNET_SYSINIT(ip6_vnet_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH, | ||||
ip6_vnet_init, NULL); | ip6_vnet_init, NULL); | ||||
static void | static void | ||||
ip6_init(void *arg __unused) | ip6_init(void *arg __unused) | ||||
{ | { | ||||
struct protosw *pr; | |||||
pr = pffindproto(PF_INET6, IPPROTO_RAW, SOCK_RAW); | |||||
KASSERT(pr, ("%s: PF_INET6 not found", __func__)); | |||||
/* Initialize the entire ip6_protox[] array to IPPROTO_RAW. */ | |||||
for (int i = 0; i < IPPROTO_MAX; i++) | |||||
ip6_protox[i] = pr - inet6sw; | |||||
/* | /* | ||||
* Cycle through IP protocols and put them into the appropriate place | * Register statically those protocols that are unlikely to ever go | ||||
* in ip6_protox[]. | * dynamic. | ||||
*/ | */ | ||||
for (pr = inet6domain.dom_protosw; | IP6PROTO_REGISTER(IPPROTO_ICMPV6, icmp6_input, rip6_ctlinput); | ||||
pr < inet6domain.dom_protoswNPROTOSW; pr++) | IP6PROTO_REGISTER(IPPROTO_DSTOPTS, dest6_input, NULL); | ||||
if (pr->pr_domain->dom_family == PF_INET6 && | IP6PROTO_REGISTER(IPPROTO_ROUTING, route6_input, NULL); | ||||
pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) { | IP6PROTO_REGISTER(IPPROTO_FRAGMENT, frag6_input, NULL); | ||||
/* Be careful to only index valid IP protocols. */ | IP6PROTO_REGISTER(IPPROTO_IPV4, encap6_input, NULL); | ||||
if (pr->pr_protocol < IPPROTO_MAX) | IP6PROTO_REGISTER(IPPROTO_IPV6, encap6_input, NULL); | ||||
ip6_protox[pr->pr_protocol] = pr - inet6sw; | IP6PROTO_REGISTER(IPPROTO_ETHERIP, encap6_input, NULL); | ||||
} | IP6PROTO_REGISTER(IPPROTO_GRE, encap6_input, NULL); | ||||
IP6PROTO_REGISTER(IPPROTO_PIM, encap6_input, NULL); | |||||
#ifdef SCTP /* XXX: has a loadable & static version */ | |||||
IP6PROTO_REGISTER(IPPROTO_SCTP, sctp6_input, sctp6_ctlinput); | |||||
Not Done Inline ActionsAny chance the static version can still be moved to sctp code? Or, at least, maybe in can be called as scp_init() or similar to avoid having sctp headers here? melifaro: Any chance the static version can still be moved to sctp code? Or, at least, maybe in can be… | |||||
#endif | |||||
netisr_register(&ip6_nh); | netisr_register(&ip6_nh); | ||||
#ifdef RSS | #ifdef RSS | ||||
netisr_register(&ip6_direct_nh); | netisr_register(&ip6_direct_nh); | ||||
#endif | #endif | ||||
} | } | ||||
SYSINIT(ip6_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, ip6_init, NULL); | SYSINIT(ip6_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, ip6_init, NULL); | ||||
/* | |||||
* The protocol to be inserted into ip6_protox[] must be already registered | |||||
* in inet6sw[], either statically or through pf_proto_register(). | |||||
*/ | |||||
int | int | ||||
ip6proto_register(short ip6proto) | ip6proto_register(uint8_t proto, ipproto_input_t input, ipproto_ctlinput_t ctl) | ||||
{ | { | ||||
struct protosw *pr; | |||||
/* Sanity checks. */ | MPASS(proto > 0); | ||||
if (ip6proto <= 0 || ip6proto >= IPPROTO_MAX) | |||||
return (EPROTONOSUPPORT); | |||||
/* | if (ip6_protox[proto] == rip6_input) { | ||||
* The protocol slot must not be occupied by another protocol | ip6_protox[proto] = input; | ||||
* already. An index pointing to IPPROTO_RAW is unused. | ip6_ctlprotox[proto] = ctl; | ||||
*/ | |||||
pr = pffindproto(PF_INET6, IPPROTO_RAW, SOCK_RAW); | |||||
if (pr == NULL) | |||||
return (EPFNOSUPPORT); | |||||
if (ip6_protox[ip6proto] != pr - inet6sw) /* IPPROTO_RAW */ | |||||
return (EEXIST); | |||||
/* | |||||
* Find the protocol position in inet6sw[] and set the index. | |||||
*/ | |||||
for (pr = inet6domain.dom_protosw; | |||||
pr < inet6domain.dom_protoswNPROTOSW; pr++) { | |||||
if (pr->pr_domain->dom_family == PF_INET6 && | |||||
pr->pr_protocol && pr->pr_protocol == ip6proto) { | |||||
ip6_protox[pr->pr_protocol] = pr - inet6sw; | |||||
return (0); | return (0); | ||||
} else | |||||
return (EEXIST); | |||||
} | } | ||||
} | |||||
return (EPROTONOSUPPORT); | |||||
} | |||||
int | int | ||||
ip6proto_unregister(short ip6proto) | ip6proto_unregister(uint8_t proto) | ||||
{ | { | ||||
struct protosw *pr; | |||||
/* Sanity checks. */ | MPASS(proto > 0); | ||||
if (ip6proto <= 0 || ip6proto >= IPPROTO_MAX) | |||||
return (EPROTONOSUPPORT); | |||||
/* Check if the protocol was indeed registered. */ | if (ip6_protox[proto] != rip6_input) { | ||||
pr = pffindproto(PF_INET6, IPPROTO_RAW, SOCK_RAW); | ip6_protox[proto] = rip6_input; | ||||
if (pr == NULL) | ip6_ctlprotox[proto] = rip6_ctlinput; | ||||
return (EPFNOSUPPORT); | |||||
if (ip6_protox[ip6proto] == pr - inet6sw) /* IPPROTO_RAW */ | |||||
return (ENOENT); | |||||
/* Reset the protocol slot to IPPROTO_RAW. */ | |||||
ip6_protox[ip6proto] = pr - inet6sw; | |||||
return (0); | return (0); | ||||
} else | |||||
return (ENOENT); | |||||
} | } | ||||
#ifdef VIMAGE | #ifdef VIMAGE | ||||
static void | static void | ||||
ip6_destroy(void *unused __unused) | ip6_destroy(void *unused __unused) | ||||
{ | { | ||||
struct ifaddr *ifa, *nifa; | struct ifaddr *ifa, *nifa; | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
▲ Show 20 Lines • Show All 161 Lines • ▼ Show 20 Lines | |||||
#if defined(IPSEC) || defined(IPSEC_SUPPORT) | #if defined(IPSEC) || defined(IPSEC_SUPPORT) | ||||
if (IPSEC_ENABLED(ipv6)) { | if (IPSEC_ENABLED(ipv6)) { | ||||
if (IPSEC_INPUT(ipv6, m, off, nxt) != 0) | if (IPSEC_INPUT(ipv6, m, off, nxt) != 0) | ||||
return; | return; | ||||
} | } | ||||
#endif /* IPSEC */ | #endif /* IPSEC */ | ||||
nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt); | nxt = ip6_protox[nxt](&m, &off, nxt); | ||||
} | } | ||||
return; | return; | ||||
bad: | bad: | ||||
m_freem(m); | m_freem(m); | ||||
} | } | ||||
#endif | #endif | ||||
void | void | ||||
▲ Show 20 Lines • Show All 393 Lines • ▼ Show 20 Lines | |||||
#if defined(IPSEC) || defined(IPSEC_SUPPORT) | #if defined(IPSEC) || defined(IPSEC_SUPPORT) | ||||
if (IPSEC_ENABLED(ipv6)) { | if (IPSEC_ENABLED(ipv6)) { | ||||
if (IPSEC_INPUT(ipv6, m, off, nxt) != 0) | if (IPSEC_INPUT(ipv6, m, off, nxt) != 0) | ||||
return; | return; | ||||
} | } | ||||
#endif /* IPSEC */ | #endif /* IPSEC */ | ||||
nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt); | nxt = ip6_protox[nxt](&m, &off, nxt); | ||||
} | } | ||||
return; | return; | ||||
bad: | bad: | ||||
in6_ifstat_inc(rcvif, ifs6_in_discard); | in6_ifstat_inc(rcvif, ifs6_in_discard); | ||||
if (m != NULL) | if (m != NULL) | ||||
m_freem(m); | m_freem(m); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 798 Lines • Show Last 20 Lines |
Probably worth asserting that IPPROTO_MAX is >= 256, just in case.