On Tue, Jul 05, 2016 at 12:22:36PM +0200, Martin Pieuchot wrote:
> Fine, new diff doing that.
OK bluhm@
> Index: netinet6/ip6_input.c
> ===================================================================
> RCS file: /cvs/src/sys/netinet6/ip6_input.c,v
> retrieving revision 1.161
> diff -u -p -r1.161 ip6_input.c
> --- netinet6/ip6_input.c 5 Jul 2016 10:17:14 -0000 1.161
> +++ netinet6/ip6_input.c 5 Jul 2016 10:21:10 -0000
> @@ -122,6 +122,7 @@ struct ip6stat ip6stat;
> void ip6_init2(void *);
> int ip6_check_rh0hdr(struct mbuf *, int *);
>
> +int ip6_hbhchcheck(struct mbuf *, int *, int *, int *);
> int ip6_hopopts_input(u_int32_t *, u_int32_t *, struct mbuf **, int *);
> struct mbuf *ip6_pullexthdr(struct mbuf *, size_t, int);
>
> @@ -192,7 +193,6 @@ ip6_input(struct mbuf *m)
> struct ip6_hdr *ip6;
> int off, nest;
> u_int16_t src_scope, dst_scope;
> - u_int32_t plen, rtalert = ~0;
> int nxt, ours = 0;
> #if NPF > 0
> struct in6_addr odst;
> @@ -495,78 +495,15 @@ ip6_input(struct mbuf *m)
> }
>
> hbhcheck:
> - /*
> - * Process Hop-by-Hop options header if it's contained.
> - * 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);
> - off = sizeof(struct ip6_hdr);
> - if (ip6->ip6_nxt == IPPROTO_HOPOPTS) {
> - struct ip6_hbh *hbh;
> -
> - if (ip6_hopopts_input(&plen, &rtalert, &m, &off)) {
> - if_put(ifp);
> - return; /* m have already been freed */
> - }
> -
> - /* adjust pointer */
> - ip6 = mtod(m, struct ip6_hdr *);
> -
> - /*
> - * if the payload length field is 0 and the next header field
> - * indicates Hop-by-Hop Options header, then a Jumbo Payload
> - * option MUST be included.
> - */
> - if (ip6->ip6_plen == 0 && 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.ip6s_badoptions++;
> - icmp6_error(m, ICMP6_PARAM_PROB,
> - ICMP6_PARAMPROB_HEADER,
> - (caddr_t)&ip6->ip6_plen - (caddr_t)ip6);
> - if_put(ifp);
> - return;
> - }
> - IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr),
> - sizeof(struct ip6_hbh));
> - if (hbh == NULL) {
> - ip6stat.ip6s_tooshort++;
> - if_put(ifp);
> - return;
> - }
> - nxt = hbh->ip6h_nxt;
>
> - /*
> - * accept the packet if a router alert option is included
> - * and we act as an IPv6 router.
> - */
> - if (rtalert != ~0 && ip6_forwarding)
> - ours = 1;
> - } else
> - nxt = ip6->ip6_nxt;
> -
> - /*
> - * Check that the amount of data in the buffers
> - * is as at least much as the IPv6 header would have us expect.
> - * Trim mbufs if longer than we expect.
> - * Drop packet if shorter than we expect.
> - */
> - if (m->m_pkthdr.len - sizeof(struct ip6_hdr) < plen) {
> - ip6stat.ip6s_tooshort++;
> - goto bad;
> - }
> - if (m->m_pkthdr.len > sizeof(struct ip6_hdr) + plen) {
> - if (m->m_len == m->m_pkthdr.len) {
> - m->m_len = sizeof(struct ip6_hdr) + plen;
> - m->m_pkthdr.len = sizeof(struct ip6_hdr) + plen;
> - } else
> - m_adj(m, sizeof(struct ip6_hdr) + plen -
> m->m_pkthdr.len);
> + if (ip6_hbhchcheck(m, &off, &nxt, &ours)) {
> + if_put(ifp);
> + return; /* m have already been freed */
> }
>
> + /* adjust pointer */
> + ip6 = mtod(m, struct ip6_hdr *);
> +
> /*
> * Forward if desirable.
> */
> @@ -638,6 +575,89 @@ ip6_input(struct mbuf *m)
> bad:
> if_put(ifp);
> m_freem(m);
> +}
> +
> +int
> +ip6_hbhchcheck(struct mbuf *m, int *offp, int *nxtp, int *oursp)
> +{
> + struct ip6_hdr *ip6;
> + u_int32_t plen, rtalert = ~0;
> +
> + ip6 = mtod(m, struct ip6_hdr *);
> +
> + /*
> + * Process Hop-by-Hop options header if it's contained.
> + * 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);
> + *offp = sizeof(struct ip6_hdr);
> + if (ip6->ip6_nxt == IPPROTO_HOPOPTS) {
> + struct ip6_hbh *hbh;
> +
> + if (ip6_hopopts_input(&plen, &rtalert, &m, offp)) {
> + return (-1); /* m have already been freed */
> + }
> +
> + /* adjust pointer */
> + ip6 = mtod(m, struct ip6_hdr *);
> +
> + /*
> + * if the payload length field is 0 and the next header field
> + * indicates Hop-by-Hop Options header, then a Jumbo Payload
> + * option MUST be included.
> + */
> + if (ip6->ip6_plen == 0 && 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.ip6s_badoptions++;
> + icmp6_error(m, ICMP6_PARAM_PROB,
> + ICMP6_PARAMPROB_HEADER,
> + (caddr_t)&ip6->ip6_plen - (caddr_t)ip6);
> + return (-1);
> + }
> + IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr),
> + sizeof(struct ip6_hbh));
> + if (hbh == NULL) {
> + ip6stat.ip6s_tooshort++;
> + return (-1);
> + }
> + *nxtp = hbh->ip6h_nxt;
> +
> + /*
> + * accept the packet if a router alert option is included
> + * and we act as an IPv6 router.
> + */
> + if (rtalert != ~0 && ip6_forwarding)
> + *oursp = 1;
> + } else
> + *nxtp = ip6->ip6_nxt;
> +
> + /*
> + * Check that the amount of data in the buffers
> + * is as at least much as the IPv6 header would have us expect.
> + * Trim mbufs if longer than we expect.
> + * Drop packet if shorter than we expect.
> + */
> + if (m->m_pkthdr.len - sizeof(struct ip6_hdr) < plen) {
> + ip6stat.ip6s_tooshort++;
> + m_freem(m);
> + return (-1);
> + }
> + if (m->m_pkthdr.len > sizeof(struct ip6_hdr) + plen) {
> + if (m->m_len == m->m_pkthdr.len) {
> + m->m_len = sizeof(struct ip6_hdr) + plen;
> + m->m_pkthdr.len = sizeof(struct ip6_hdr) + plen;
> + } else {
> + m_adj(m,
> + sizeof(struct ip6_hdr) + plen - m->m_pkthdr.len);
> + }
> + }
> +
> + return (0);
> }
>
> /* scan packet for RH0 routing header. Mostly stolen from pf.c:pf_test() */