Changeset View
Standalone View
sys/netinet6/ip6_input.c
Show First 20 Lines • Show All 138 Lines • ▼ Show 20 Lines | #ifdef RSS | ||||
.nh_m2cpuid = rss_soft_m2cpuid_v6, | .nh_m2cpuid = rss_soft_m2cpuid_v6, | ||||
.nh_policy = NETISR_POLICY_CPU, | .nh_policy = NETISR_POLICY_CPU, | ||||
.nh_dispatch = NETISR_DISPATCH_HYBRID, | .nh_dispatch = NETISR_DISPATCH_HYBRID, | ||||
#else | #else | ||||
.nh_policy = NETISR_POLICY_FLOW, | .nh_policy = NETISR_POLICY_FLOW, | ||||
#endif | #endif | ||||
}; | }; | ||||
#ifdef RSS | |||||
static struct netisr_handler ip6_direct_nh = { | |||||
.nh_name = "ip6_direct", | |||||
.nh_handler = ip6_direct_input, | |||||
.nh_proto = NETISR_IPV6_DIRECT, | |||||
.nh_m2cpuid = rss_soft_m2cpuid_v6, | |||||
.nh_policy = NETISR_POLICY_CPU, | |||||
.nh_dispatch = NETISR_DISPATCH_HYBRID, | |||||
}; | |||||
#endif | |||||
VNET_DECLARE(struct callout, in6_tmpaddrtimer_ch); | VNET_DECLARE(struct callout, in6_tmpaddrtimer_ch); | ||||
#define V_in6_tmpaddrtimer_ch VNET(in6_tmpaddrtimer_ch) | #define V_in6_tmpaddrtimer_ch VNET(in6_tmpaddrtimer_ch) | ||||
VNET_DEFINE(struct pfil_head, inet6_pfil_hook); | VNET_DEFINE(struct pfil_head, inet6_pfil_hook); | ||||
VNET_PCPUSTAT_DEFINE(struct ip6stat, ip6stat); | VNET_PCPUSTAT_DEFINE(struct ip6stat, ip6stat); | ||||
VNET_PCPUSTAT_SYSINIT(ip6stat); | VNET_PCPUSTAT_SYSINIT(ip6stat); | ||||
#ifdef VIMAGE | #ifdef VIMAGE | ||||
▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | for (pr = inet6domain.dom_protosw; | ||||
if (pr->pr_domain->dom_family == PF_INET6 && | if (pr->pr_domain->dom_family == PF_INET6 && | ||||
pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) { | pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) { | ||||
/* Be careful to only index valid IP protocols. */ | /* Be careful to only index valid IP protocols. */ | ||||
if (pr->pr_protocol < IPPROTO_MAX) | if (pr->pr_protocol < IPPROTO_MAX) | ||||
ip6_protox[pr->pr_protocol] = pr - inet6sw; | ip6_protox[pr->pr_protocol] = pr - inet6sw; | ||||
} | } | ||||
netisr_register(&ip6_nh); | netisr_register(&ip6_nh); | ||||
#ifdef RSS | |||||
netisr_register(&ip6_direct_nh); | |||||
#endif | |||||
} | } | ||||
/* | /* | ||||
* The protocol to be inserted into ip6_protox[] must be already registered | * The protocol to be inserted into ip6_protox[] must be already registered | ||||
* in inet6sw[], either statically or through pf_proto_register(). | * in inet6sw[], either statically or through pf_proto_register(). | ||||
*/ | */ | ||||
int | int | ||||
ip6proto_register(short ip6proto) | ip6proto_register(short ip6proto) | ||||
▲ Show 20 Lines • Show All 165 Lines • ▼ Show 20 Lines | #endif | ||||
} | } | ||||
return (0); | return (0); | ||||
out: | out: | ||||
return (1); | return (1); | ||||
} | } | ||||
#ifdef RSS | |||||
/* | |||||
* IPv6 direct input routine. | |||||
* | |||||
* This is called when reinjecting completed fragments where | |||||
* all of the previous checking and book-keeping has been done. | |||||
*/ | |||||
void | void | ||||
ip6_direct_input(struct mbuf *m) | |||||
{ | |||||
int off, nxt; | |||||
int nest; | |||||
struct m_tag *mtag; | |||||
struct ip6_direct_ctx *ip6dc; | |||||
mtag = m_tag_locate(m, MTAG_ABI_IPV6, IPV6_TAG_DIRECT, NULL); | |||||
KASSERT(mtag != NULL, ("Reinjected packet w/o direct ctx tag!")); | |||||
btw: I'm wondering whether it is a better choice to replace these error handling codes with a… | |||||
Not Done Inline Actionsok, so what about for direct-dispatch v6 that isn't fragment related? eg, IPSEC tunnel decap, GRE or IPIP tunnel decap, etc? Would there be a hop-by-hop parsing mbuf tag in that instance? Maybe we should handle that case by just assuming it's a fully formed v6 packet that we're not doing incremental parsing and to just reinject it? Would that even work? adrian: ok, so what about for direct-dispatch v6 that isn't fragment related? eg, IPSEC tunnel decap… | |||||
Not Done Inline ActionsI'm not pretty familiar with these things. But by reading their codes, I think they are something different from fragment. Take GRE as an example: When a GRE packet is received, gre_input will be called: struct protosw in6_gre_protosw = { ...... .pr_protocol = IPPROTO_GRE, ...... .pr_input = gre_input, ...... }; int gre_input(struct mbuf **mp, int *offp, int proto) { ...... gh = (struct grehdr *)mtodo(m, *offp); ...... hlen = 2 * sizeof(uint16_t); if (flags & GRE_FLAGS_CP) { ...... hlen += 2 * sizeof(uint16_t); ...... } ...... switch (ntohs(gh->gre_proto)) { ...... case ETHERTYPE_IP: isr = NETISR_IP; af = AF_INET; break; case ETHERTYPE_IPV6: isr = NETISR_IPV6; af = AF_INET6; break; default: goto drop; } m_adj(m, *offp + hlen); ...... if ((ifp->if_flags & IFF_MONITOR) != 0) m_freem(m); else netisr_dispatch(isr, m); ...... } When the GRE parsing is done, the GRE header will be trimmed. And the rest is a new ip or ip6 packet. And gre_input() will and should dispatch it to ip_input() or ip6_input(). btw: I'm not pretty familiar with these things. But by reading their codes, I think they are… | |||||
ip6dc = (struct ip6_direct_ctx *)(mtag + 1); | |||||
nxt = ip6dc->ip6dc_nxt; | |||||
off = ip6dc->ip6dc_off; | |||||
nest = 0; | |||||
m_tag_delete(m, mtag); | |||||
while (nxt != IPPROTO_DONE) { | |||||
if (V_ip6_hdrnestlimit && (++nest > V_ip6_hdrnestlimit)) { | |||||
IP6STAT_INC(ip6s_toomanyhdr); | |||||
goto bad; | |||||
} | |||||
/* | |||||
* protection against faulty packet - there should be | |||||
* more sanity checks in header chain processing. | |||||
*/ | |||||
if (m->m_pkthdr.len < off) { | |||||
IP6STAT_INC(ip6s_tooshort); | |||||
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); | |||||
goto bad; | |||||
} | |||||
#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 (ip6_ipsec_input(m, nxt)) | |||||
goto bad; | |||||
#endif /* IPSEC */ | |||||
nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt); | |||||
} | |||||
return; | |||||
bad: | |||||
m_freem(m); | |||||
} | |||||
#endif | |||||
void | |||||
ip6_input(struct mbuf *m) | ip6_input(struct mbuf *m) | ||||
{ | { | ||||
struct in6_addr odst; | struct in6_addr odst; | ||||
struct ip6_hdr *ip6; | struct ip6_hdr *ip6; | ||||
struct in6_ifaddr *ia; | struct in6_ifaddr *ia; | ||||
u_int32_t plen; | u_int32_t plen; | ||||
u_int32_t rtalert = ~0; | u_int32_t rtalert = ~0; | ||||
int off = sizeof(struct ip6_hdr), nest; | int off = sizeof(struct ip6_hdr), nest; | ||||
▲ Show 20 Lines • Show All 293 Lines • ▼ Show 20 Lines | passin: | ||||
plen = (u_int32_t)ntohs(ip6->ip6_plen); | plen = (u_int32_t)ntohs(ip6->ip6_plen); | ||||
if (ip6->ip6_nxt == IPPROTO_HOPOPTS) { | if (ip6->ip6_nxt == IPPROTO_HOPOPTS) { | ||||
if (ip6_input_hbh(m, &plen, &rtalert, &off, &nxt, &ours) != 0) | if (ip6_input_hbh(m, &plen, &rtalert, &off, &nxt, &ours) != 0) | ||||
return; | return; | ||||
} else | } else | ||||
nxt = ip6->ip6_nxt; | nxt = ip6->ip6_nxt; | ||||
/* | /* | ||||
* Use mbuf flags to propagate Router Alert option to | |||||
* ICMPv6 layer, as hop-by-hop options have been stripped. | |||||
*/ | |||||
if (rtalert != ~0) | |||||
Not Done Inline ActionsPreviously, M_RTALERT_MLD will be set only when this is an ICMPV6 packet. btw: Previously, M_RTALERT_MLD will be set only when this is an ICMPV6 packet.
Now it is always set. | |||||
m->m_flags |= M_RTALERT_MLD; | |||||
/* | |||||
* Check that the amount of data in the buffers | * Check that the amount of data in the buffers | ||||
* is as at least much as the IPv6 header would have us expect. | * is as at least much as the IPv6 header would have us expect. | ||||
* Trim mbufs if longer than we expect. | * Trim mbufs if longer than we expect. | ||||
* Drop packet if shorter than we expect. | * Drop packet if shorter than we expect. | ||||
*/ | */ | ||||
if (m->m_pkthdr.len - sizeof(struct ip6_hdr) < plen) { | if (m->m_pkthdr.len - sizeof(struct ip6_hdr) < plen) { | ||||
IP6STAT_INC(ip6s_tooshort); | IP6STAT_INC(ip6s_tooshort); | ||||
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); | in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); | ||||
▲ Show 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | #ifdef IPSEC | ||||
/* | /* | ||||
* enforce IPsec policy checking if we are seeing last header. | * enforce IPsec policy checking if we are seeing last header. | ||||
* note that we do not visit this with protocols with pcb layer | * note that we do not visit this with protocols with pcb layer | ||||
* code - like udp/tcp/raw ip. | * code - like udp/tcp/raw ip. | ||||
*/ | */ | ||||
if (ip6_ipsec_input(m, nxt)) | if (ip6_ipsec_input(m, nxt)) | ||||
goto bad; | goto bad; | ||||
#endif /* IPSEC */ | #endif /* IPSEC */ | ||||
/* | |||||
* Use mbuf flags to propagate Router Alert option to | |||||
* ICMPv6 layer, as hop-by-hop options have been stripped. | |||||
*/ | |||||
if (nxt == IPPROTO_ICMPV6 && rtalert != ~0) | |||||
m->m_flags |= M_RTALERT_MLD; | |||||
nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt); | nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt); | ||||
} | } | ||||
return; | return; | ||||
bad: | bad: | ||||
m_freem(m); | m_freem(m); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 813 Lines • Show Last 20 Lines |
I'm wondering whether it is a better choice to replace these error handling codes with a KASSERT().