Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: move br_nf_check_hbh_len to utils

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@gmail.com>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
Reviewed-by: Aaron Conole <aconole@redhat.com>
Signed-off-by: Florian Westphal <fw@strlen.de>

authored by

Xin Long and committed by
Florian Westphal
28e144cf 0b24bd71

+55 -54
+2
include/linux/netfilter_ipv6.h
··· 197 197 __sum16 nf_ip6_checksum(struct sk_buff *skb, unsigned int hook, 198 198 unsigned int dataoff, u_int8_t protocol); 199 199 200 + int nf_ip6_check_hbh_len(struct sk_buff *skb, u32 *plen); 201 + 200 202 int ipv6_netfilter_init(void); 201 203 void ipv6_netfilter_fini(void); 202 204
+1 -54
net/bridge/br_netfilter_ipv6.c
··· 40 40 #include <linux/sysctl.h> 41 41 #endif 42 42 43 - /* We only check the length. A bridge shouldn't do any hop-by-hop stuff 44 - * anyway 45 - */ 46 - static int br_nf_check_hbh_len(struct sk_buff *skb, u32 *plen) 47 - { 48 - int len, off = sizeof(struct ipv6hdr); 49 - unsigned char *nh; 50 - 51 - if (!pskb_may_pull(skb, off + 8)) 52 - return -1; 53 - nh = (unsigned char *)(ipv6_hdr(skb) + 1); 54 - len = (nh[1] + 1) << 3; 55 - 56 - if (!pskb_may_pull(skb, off + len)) 57 - return -1; 58 - nh = skb_network_header(skb); 59 - 60 - off += 2; 61 - len -= 2; 62 - while (len > 0) { 63 - int optlen; 64 - 65 - if (nh[off] == IPV6_TLV_PAD1) { 66 - off++; 67 - len--; 68 - continue; 69 - } 70 - if (len < 2) 71 - return -1; 72 - optlen = nh[off + 1] + 2; 73 - if (optlen > len) 74 - return -1; 75 - 76 - if (nh[off] == IPV6_TLV_JUMBO) { 77 - u32 pkt_len; 78 - 79 - if (nh[off + 1] != 4 || (off & 3) != 2) 80 - return -1; 81 - pkt_len = ntohl(*(__be32 *)(nh + off + 2)); 82 - if (pkt_len <= IPV6_MAXPLEN || 83 - ipv6_hdr(skb)->payload_len) 84 - return -1; 85 - if (pkt_len > skb->len - sizeof(struct ipv6hdr)) 86 - return -1; 87 - *plen = pkt_len; 88 - } 89 - off += optlen; 90 - len -= optlen; 91 - } 92 - 93 - return len ? -1 : 0; 94 - } 95 - 96 43 int br_validate_ipv6(struct net *net, struct sk_buff *skb) 97 44 { 98 45 const struct ipv6hdr *hdr; ··· 59 112 goto inhdr_error; 60 113 61 114 pkt_len = ntohs(hdr->payload_len); 62 - if (hdr->nexthdr == NEXTHDR_HOP && br_nf_check_hbh_len(skb, &pkt_len)) 115 + if (hdr->nexthdr == NEXTHDR_HOP && nf_ip6_check_hbh_len(skb, &pkt_len)) 63 116 goto drop; 64 117 65 118 if (pkt_len + ip6h_len > skb->len) {
+52
net/netfilter/utils.c
··· 215 215 } 216 216 return ret; 217 217 } 218 + 219 + /* Only get and check the lengths, not do any hop-by-hop stuff. */ 220 + int nf_ip6_check_hbh_len(struct sk_buff *skb, u32 *plen) 221 + { 222 + int len, off = sizeof(struct ipv6hdr); 223 + unsigned char *nh; 224 + 225 + if (!pskb_may_pull(skb, off + 8)) 226 + return -ENOMEM; 227 + nh = (unsigned char *)(ipv6_hdr(skb) + 1); 228 + len = (nh[1] + 1) << 3; 229 + 230 + if (!pskb_may_pull(skb, off + len)) 231 + return -ENOMEM; 232 + nh = skb_network_header(skb); 233 + 234 + off += 2; 235 + len -= 2; 236 + while (len > 0) { 237 + int optlen; 238 + 239 + if (nh[off] == IPV6_TLV_PAD1) { 240 + off++; 241 + len--; 242 + continue; 243 + } 244 + if (len < 2) 245 + return -EBADMSG; 246 + optlen = nh[off + 1] + 2; 247 + if (optlen > len) 248 + return -EBADMSG; 249 + 250 + if (nh[off] == IPV6_TLV_JUMBO) { 251 + u32 pkt_len; 252 + 253 + if (nh[off + 1] != 4 || (off & 3) != 2) 254 + return -EBADMSG; 255 + pkt_len = ntohl(*(__be32 *)(nh + off + 2)); 256 + if (pkt_len <= IPV6_MAXPLEN || 257 + ipv6_hdr(skb)->payload_len) 258 + return -EBADMSG; 259 + if (pkt_len > skb->len - sizeof(struct ipv6hdr)) 260 + return -EBADMSG; 261 + *plen = pkt_len; 262 + } 263 + off += optlen; 264 + len -= optlen; 265 + } 266 + 267 + return len ? -EBADMSG : 0; 268 + } 269 + EXPORT_SYMBOL_GPL(nf_ip6_check_hbh_len);