Xin Long <lucien.xin@xxxxxxxxx> writes: > Rename br_nf_check_hbh_len() to nf_ip6_check_hbh_len() and move it > to netfilter utils, so that it can be used by other modules, like > ovs and tc. > > Signed-off-by: Xin Long <lucien.xin@xxxxxxxxx> > --- Reviewed-by: Aaron Conole <aconole@xxxxxxxxxx> > include/linux/netfilter_ipv6.h | 2 ++ > net/bridge/br_netfilter_ipv6.c | 57 +--------------------------------- > net/netfilter/utils.c | 54 ++++++++++++++++++++++++++++++++ > 3 files changed, 57 insertions(+), 56 deletions(-) > > diff --git a/include/linux/netfilter_ipv6.h b/include/linux/netfilter_ipv6.h > index 48314ade1506..7834c0be2831 100644 > --- a/include/linux/netfilter_ipv6.h > +++ b/include/linux/netfilter_ipv6.h > @@ -197,6 +197,8 @@ static inline int nf_cookie_v6_check(const struct ipv6hdr *iph, > __sum16 nf_ip6_checksum(struct sk_buff *skb, unsigned int hook, > unsigned int dataoff, u_int8_t protocol); > > +int nf_ip6_check_hbh_len(struct sk_buff *skb, u32 *plen); > + > int ipv6_netfilter_init(void); > void ipv6_netfilter_fini(void); > > diff --git a/net/bridge/br_netfilter_ipv6.c b/net/bridge/br_netfilter_ipv6.c > index 07289e4f3213..550039dfc31a 100644 > --- a/net/bridge/br_netfilter_ipv6.c > +++ b/net/bridge/br_netfilter_ipv6.c > @@ -40,61 +40,6 @@ > #include <linux/sysctl.h> > #endif > > -/* We only check the length. A bridge shouldn't do any hop-by-hop stuff > - * anyway > - */ > -static int br_nf_check_hbh_len(struct sk_buff *skb, u32 *plen) > -{ > - int len, off = sizeof(struct ipv6hdr); > - unsigned char *nh; > - u32 pkt_len = 0; > - > - if (!pskb_may_pull(skb, off + 8)) > - return -1; > - nh = (u8 *)(ipv6_hdr(skb) + 1); > - len = (nh[1] + 1) << 3; > - > - if (!pskb_may_pull(skb, off + len)) > - return -1; > - nh = skb_network_header(skb); > - > - off += 2; > - len -= 2; > - while (len > 0) { > - int optlen; > - > - if (nh[off] == IPV6_TLV_PAD1) { > - off++; > - len--; > - continue; > - } > - if (len < 2) > - return -1; > - optlen = nh[off + 1] + 2; > - if (optlen > len) > - return -1; > - > - if (nh[off] == IPV6_TLV_JUMBO) { > - if (nh[off + 1] != 4 || (off & 3) != 2) > - return -1; > - pkt_len = ntohl(*(__be32 *)(nh + off + 2)); > - if (pkt_len <= IPV6_MAXPLEN || > - ipv6_hdr(skb)->payload_len) > - return -1; > - if (pkt_len > skb->len - sizeof(struct ipv6hdr)) > - return -1; > - } > - off += optlen; > - len -= optlen; > - } > - if (len) > - return -1; > - > - if (pkt_len) > - *plen = pkt_len; > - return 0; > -} > - > int br_validate_ipv6(struct net *net, struct sk_buff *skb) > { > const struct ipv6hdr *hdr; > @@ -114,7 +59,7 @@ int br_validate_ipv6(struct net *net, struct sk_buff *skb) > goto inhdr_error; > > pkt_len = ntohs(hdr->payload_len); > - if (hdr->nexthdr == NEXTHDR_HOP && br_nf_check_hbh_len(skb, &pkt_len)) > + if (hdr->nexthdr == NEXTHDR_HOP && nf_ip6_check_hbh_len(skb, &pkt_len)) > goto drop; > > if (pkt_len + ip6h_len > skb->len) { > diff --git a/net/netfilter/utils.c b/net/netfilter/utils.c > index 2182d361e273..04f4bd661774 100644 > --- a/net/netfilter/utils.c > +++ b/net/netfilter/utils.c > @@ -215,3 +215,57 @@ int nf_reroute(struct sk_buff *skb, struct nf_queue_entry *entry) > } > return ret; > } > + > +/* Only get and check the lengths, not do any hop-by-hop stuff. */ > +int nf_ip6_check_hbh_len(struct sk_buff *skb, u32 *plen) > +{ > + int len, off = sizeof(struct ipv6hdr); > + unsigned char *nh; > + u32 pkt_len = 0; > + > + if (!pskb_may_pull(skb, off + 8)) > + return -ENOMEM; > + nh = (u8 *)(ipv6_hdr(skb) + 1); > + len = (nh[1] + 1) << 3; > + > + if (!pskb_may_pull(skb, off + len)) > + return -ENOMEM; > + nh = skb_network_header(skb); > + > + off += 2; > + len -= 2; > + while (len > 0) { > + int optlen; > + > + if (nh[off] == IPV6_TLV_PAD1) { > + off++; > + len--; > + continue; > + } > + if (len < 2) > + return -EBADMSG; > + optlen = nh[off + 1] + 2; > + if (optlen > len) > + return -EBADMSG; > + > + if (nh[off] == IPV6_TLV_JUMBO) { > + if (nh[off + 1] != 4 || (off & 3) != 2) > + return -EBADMSG; > + pkt_len = ntohl(*(__be32 *)(nh + off + 2)); > + if (pkt_len <= IPV6_MAXPLEN || > + ipv6_hdr(skb)->payload_len) > + return -EBADMSG; > + if (pkt_len > skb->len - sizeof(struct ipv6hdr)) > + return -EBADMSG; > + } > + off += optlen; > + len -= optlen; > + } > + if (len) > + return -EBADMSG; > + > + if (pkt_len) > + *plen = pkt_len; > + return 0; > +} > +EXPORT_SYMBOL_GPL(nf_ip6_check_hbh_len);