Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet6/ip6_input.c
Show First 20 Lines • Show All 414 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
goto out; /* m have already been freed */ | goto out; /* m have already been freed */ | ||||
} | } | ||||
/* adjust pointer */ | /* adjust pointer */ | ||||
ip6 = mtod(m, struct ip6_hdr *); | ip6 = mtod(m, struct ip6_hdr *); | ||||
/* | /* | ||||
* if the payload length field is 0 and the next header field | * if the payload length field is 0 and the next header field indicates | ||||
* indicates Hop-by-Hop Options header, then a Jumbo Payload | * Hop-by-Hop Options header, then this must be a jumbo payload. We do | ||||
* option MUST be included. | * not support jumbo payloads, report an error to the sender. | ||||
*/ | */ | ||||
if (ip6->ip6_plen == 0 && *plen == 0) { | if (ip6->ip6_plen == 0) { | ||||
/* | |||||
* Note that if a valid jumbo payload option is | |||||
* contained, ip6_hopopts_input() must set a valid | |||||
* (non-zero) payload length to the variable plen. | |||||
*/ | |||||
IP6STAT_INC(ip6s_badoptions); | IP6STAT_INC(ip6s_badoptions); | ||||
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); | in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); | ||||
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr); | in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr); | ||||
icmp6_error(m, ICMP6_PARAM_PROB, | icmp6_error(m, ICMP6_PARAM_PROB, | ||||
ICMP6_PARAMPROB_HEADER, | ICMP6_PARAMPROB_HEADER, | ||||
(caddr_t)&ip6->ip6_plen - (caddr_t)ip6); | (caddr_t)&ip6->ip6_plen - (caddr_t)ip6); | ||||
goto out; | goto out; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 404 Lines • ▼ Show 20 Lines | if (!V_ip6_forwarding) { | ||||
IP6STAT_INC(ip6s_cantforward); | IP6STAT_INC(ip6s_cantforward); | ||||
goto bad; | goto bad; | ||||
} | } | ||||
hbhcheck: | hbhcheck: | ||||
/* | /* | ||||
* Process Hop-by-Hop options header if it's contained. | * Process Hop-by-Hop options header if it's contained. | ||||
* m may be modified in ip6_hopopts_input(). | * m may be modified in ip6_hopopts_input(). | ||||
* If a JumboPayload option is included, plen will also be modified. | |||||
*/ | */ | ||||
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; | ||||
▲ Show 20 Lines • Show All 101 Lines • ▼ Show 20 Lines | #endif /* IPSEC */ | ||||
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); | ||||
} | } | ||||
/* | /* | ||||
* Hop-by-Hop options header processing. If a valid jumbo payload option is | * Hop-by-Hop options header processing. If a jumbo payload option is present | ||||
* included, the real payload length will be stored in plenp. | * report an error. | ||||
* | * | ||||
* rtalertp - XXX: should be stored more smart way | * rtalertp - XXX: should be stored more smart way | ||||
*/ | */ | ||||
static int | static int | ||||
ip6_hopopts_input(u_int32_t *plenp, u_int32_t *rtalertp, | ip6_hopopts_input(u_int32_t *plenp, u_int32_t *rtalertp, | ||||
struct mbuf **mp, int *offp) | struct mbuf **mp, int *offp) | ||||
{ | { | ||||
struct mbuf *m = *mp; | struct mbuf *m = *mp; | ||||
Show All 21 Lines | #else | ||||
if (hbh == NULL) { | if (hbh == NULL) { | ||||
IP6STAT_INC(ip6s_tooshort); | IP6STAT_INC(ip6s_tooshort); | ||||
return -1; | return -1; | ||||
} | } | ||||
#endif | #endif | ||||
off += hbhlen; | off += hbhlen; | ||||
hbhlen -= sizeof(struct ip6_hbh); | hbhlen -= sizeof(struct ip6_hbh); | ||||
if (ip6_process_hopopts(m, (u_int8_t *)hbh + sizeof(struct ip6_hbh), | if (ip6_process_hopopts(m, (u_int8_t *)hbh + sizeof(struct ip6_hbh), | ||||
hbhlen, rtalertp, plenp) < 0) | hbhlen, rtalertp) < 0) | ||||
return (-1); | return (-1); | ||||
*offp = off; | *offp = off; | ||||
*mp = m; | *mp = m; | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Search header for all Hop-by-hop options and process each option. | * Search header for all Hop-by-hop options and process each option. | ||||
* This function is separate from ip6_hopopts_input() in order to | * This function is separate from ip6_hopopts_input() in order to | ||||
* handle a case where the sending node itself process its hop-by-hop | * handle a case where the sending node itself process its hop-by-hop | ||||
* options header. In such a case, the function is called from ip6_output(). | * options header. In such a case, the function is called from ip6_output(). | ||||
* | * | ||||
* The function assumes that hbh header is located right after the IPv6 header | * The function assumes that hbh header is located right after the IPv6 header | ||||
* (RFC2460 p7), opthead is pointer into data content in m, and opthead to | * (RFC2460 p7), opthead is pointer into data content in m, and opthead to | ||||
* opthead + hbhlen is located in contiguous memory region. | * opthead + hbhlen is located in contiguous memory region. | ||||
*/ | */ | ||||
int | int | ||||
ip6_process_hopopts(struct mbuf *m, u_int8_t *opthead, int hbhlen, | ip6_process_hopopts(struct mbuf *m, u_int8_t *opthead, int hbhlen, | ||||
u_int32_t *rtalertp, u_int32_t *plenp) | u_int32_t *rtalertp) | ||||
{ | { | ||||
struct ip6_hdr *ip6; | |||||
int optlen = 0; | int optlen = 0; | ||||
u_int8_t *opt = opthead; | u_int8_t *opt = opthead; | ||||
u_int16_t rtalert_val; | u_int16_t rtalert_val; | ||||
u_int32_t jumboplen; | |||||
const int erroff = sizeof(struct ip6_hdr) + sizeof(struct ip6_hbh); | const int erroff = sizeof(struct ip6_hdr) + sizeof(struct ip6_hbh); | ||||
for (; hbhlen > 0; hbhlen -= optlen, opt += optlen) { | for (; hbhlen > 0; hbhlen -= optlen, opt += optlen) { | ||||
switch (*opt) { | switch (*opt) { | ||||
case IP6OPT_PAD1: | case IP6OPT_PAD1: | ||||
optlen = 1; | optlen = 1; | ||||
break; | break; | ||||
case IP6OPT_PADN: | case IP6OPT_PADN: | ||||
Show All 16 Lines | case IP6OPT_ROUTER_ALERT: | ||||
erroff + opt + 1 - opthead); | erroff + opt + 1 - opthead); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
optlen = IP6OPT_RTALERT_LEN; | optlen = IP6OPT_RTALERT_LEN; | ||||
bcopy((caddr_t)(opt + 2), (caddr_t)&rtalert_val, 2); | bcopy((caddr_t)(opt + 2), (caddr_t)&rtalert_val, 2); | ||||
*rtalertp = ntohs(rtalert_val); | *rtalertp = ntohs(rtalert_val); | ||||
break; | break; | ||||
case IP6OPT_JUMBO: | case IP6OPT_JUMBO: | ||||
/* XXX may need check for alignment */ | /* We do not support the jumbo payload option */ | ||||
if (hbhlen < IP6OPT_JUMBO_LEN) { | |||||
IP6STAT_INC(ip6s_toosmall); | |||||
goto bad; | goto bad; | ||||
} | |||||
if (*(opt + 1) != IP6OPT_JUMBO_LEN - 2) { | |||||
/* XXX stat */ | |||||
icmp6_error(m, ICMP6_PARAM_PROB, | |||||
ICMP6_PARAMPROB_HEADER, | |||||
erroff + opt + 1 - opthead); | |||||
return (-1); | |||||
} | |||||
optlen = IP6OPT_JUMBO_LEN; | |||||
/* | |||||
* IPv6 packets that have non 0 payload length | |||||
* must not contain a jumbo payload option. | |||||
*/ | |||||
ip6 = mtod(m, struct ip6_hdr *); | |||||
if (ip6->ip6_plen) { | |||||
IP6STAT_INC(ip6s_badoptions); | |||||
icmp6_error(m, ICMP6_PARAM_PROB, | |||||
ICMP6_PARAMPROB_HEADER, | |||||
erroff + opt - opthead); | |||||
return (-1); | |||||
} | |||||
/* | |||||
* We may see jumbolen in unaligned location, so | |||||
* we'd need to perform bcopy(). | |||||
*/ | |||||
bcopy(opt + 2, &jumboplen, sizeof(jumboplen)); | |||||
jumboplen = (u_int32_t)htonl(jumboplen); | |||||
#if 1 | |||||
/* | |||||
* if there are multiple jumbo payload options, | |||||
* *plenp will be non-zero and the packet will be | |||||
* rejected. | |||||
* the behavior may need some debate in ipngwg - | |||||
* multiple options does not make sense, however, | |||||
* there's no explicit mention in specification. | |||||
*/ | |||||
if (*plenp != 0) { | |||||
IP6STAT_INC(ip6s_badoptions); | |||||
icmp6_error(m, ICMP6_PARAM_PROB, | |||||
ICMP6_PARAMPROB_HEADER, | |||||
erroff + opt + 2 - opthead); | |||||
return (-1); | |||||
} | |||||
#endif | |||||
/* | |||||
* jumbo payload length must be larger than 65535. | |||||
*/ | |||||
if (jumboplen <= IPV6_MAXPACKET) { | |||||
IP6STAT_INC(ip6s_badoptions); | |||||
icmp6_error(m, ICMP6_PARAM_PROB, | |||||
ICMP6_PARAMPROB_HEADER, | |||||
erroff + opt + 2 - opthead); | |||||
return (-1); | |||||
} | |||||
*plenp = jumboplen; | |||||
break; | |||||
default: /* unknown option */ | default: /* unknown option */ | ||||
if (hbhlen < IP6OPT_MINLEN) { | if (hbhlen < IP6OPT_MINLEN) { | ||||
IP6STAT_INC(ip6s_toosmall); | IP6STAT_INC(ip6s_toosmall); | ||||
goto bad; | goto bad; | ||||
} | } | ||||
optlen = ip6_unknown_opt(opt, m, | optlen = ip6_unknown_opt(opt, m, | ||||
erroff + opt - opthead); | erroff + opt - opthead); | ||||
if (optlen == -1) | if (optlen == -1) | ||||
▲ Show 20 Lines • Show All 306 Lines • ▼ Show 20 Lines | #else | ||||
hbh = mtod(ext, struct ip6_hbh *); | hbh = mtod(ext, struct ip6_hbh *); | ||||
hbhlen = (hbh->ip6h_len + 1) << 3; | hbhlen = (hbh->ip6h_len + 1) << 3; | ||||
if (hbhlen != ext->m_len) { | if (hbhlen != ext->m_len) { | ||||
m_freem(ext); | m_freem(ext); | ||||
IP6STAT_INC(ip6s_tooshort); | IP6STAT_INC(ip6s_tooshort); | ||||
return; | return; | ||||
} | } | ||||
#endif | #endif | ||||
/* | /* | ||||
* XXX: We copy the whole header even if a | * XXX: We copy the whole header even if a | ||||
* jumbo payload option is included, the option which | * jumbo payload option is included, the option which | ||||
* is to be removed before returning according to | * is to be removed before returning according to | ||||
* RFC2292. | * RFC2292. | ||||
* Note: this constraint is removed in RFC3542 | * Note: this constraint is removed in RFC3542 | ||||
*/ | */ | ||||
*mp = sbcreatecontrol((caddr_t)hbh, hbhlen, | *mp = sbcreatecontrol((caddr_t)hbh, hbhlen, | ||||
▲ Show 20 Lines • Show All 397 Lines • Show Last 20 Lines |