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

ipv6: Move ipv6_find_hdr() out of Netfilter code.

Open vSwitch will soon also use ipv6_find_hdr() so this moves it
out of Netfilter-specific code into a more common location.

Signed-off-by: Jesse Gross <jesse@nicira.com>

+116 -116
-9
include/linux/netfilter_ipv6/ip6_tables.h
··· 47 47 (nexthdr == IPPROTO_DSTOPTS); 48 48 } 49 49 50 - enum { 51 - IP6T_FH_F_FRAG = (1 << 0), 52 - IP6T_FH_F_AUTH = (1 << 1), 53 - }; 54 - 55 - /* find specified header and get offset to it */ 56 - extern int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, 57 - int target, unsigned short *fragoff, int *fragflg); 58 - 59 50 #ifdef CONFIG_COMPAT 60 51 #include <net/compat.h> 61 52
+9
include/net/ipv6.h
··· 630 630 631 631 extern bool ipv6_ext_hdr(u8 nexthdr); 632 632 633 + enum { 634 + IP6_FH_F_FRAG = (1 << 0), 635 + IP6_FH_F_AUTH = (1 << 1), 636 + }; 637 + 638 + /* find specified header and get offset to it */ 639 + extern int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, 640 + int target, unsigned short *fragoff, int *fragflg); 641 + 633 642 extern int ipv6_find_tlv(struct sk_buff *skb, int offset, int type); 634 643 635 644 extern struct in6_addr *fl6_update_dst(struct flowi6 *fl6,
+103
net/ipv6/exthdrs_core.c
··· 111 111 return start; 112 112 } 113 113 EXPORT_SYMBOL(ipv6_skip_exthdr); 114 + 115 + /* 116 + * find the offset to specified header or the protocol number of last header 117 + * if target < 0. "last header" is transport protocol header, ESP, or 118 + * "No next header". 119 + * 120 + * Note that *offset is used as input/output parameter. an if it is not zero, 121 + * then it must be a valid offset to an inner IPv6 header. This can be used 122 + * to explore inner IPv6 header, eg. ICMPv6 error messages. 123 + * 124 + * If target header is found, its offset is set in *offset and return protocol 125 + * number. Otherwise, return -1. 126 + * 127 + * If the first fragment doesn't contain the final protocol header or 128 + * NEXTHDR_NONE it is considered invalid. 129 + * 130 + * Note that non-1st fragment is special case that "the protocol number 131 + * of last header" is "next header" field in Fragment header. In this case, 132 + * *offset is meaningless and fragment offset is stored in *fragoff if fragoff 133 + * isn't NULL. 134 + * 135 + * if flags is not NULL and it's a fragment, then the frag flag IP6_FH_F_FRAG 136 + * will be set. If it's an AH header, the IP6_FH_F_AUTH flag is set and 137 + * target < 0, then this function will stop at the AH header. 138 + */ 139 + int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, 140 + int target, unsigned short *fragoff, int *flags) 141 + { 142 + unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr); 143 + u8 nexthdr = ipv6_hdr(skb)->nexthdr; 144 + unsigned int len; 145 + 146 + if (fragoff) 147 + *fragoff = 0; 148 + 149 + if (*offset) { 150 + struct ipv6hdr _ip6, *ip6; 151 + 152 + ip6 = skb_header_pointer(skb, *offset, sizeof(_ip6), &_ip6); 153 + if (!ip6 || (ip6->version != 6)) { 154 + printk(KERN_ERR "IPv6 header not found\n"); 155 + return -EBADMSG; 156 + } 157 + start = *offset + sizeof(struct ipv6hdr); 158 + nexthdr = ip6->nexthdr; 159 + } 160 + len = skb->len - start; 161 + 162 + while (nexthdr != target) { 163 + struct ipv6_opt_hdr _hdr, *hp; 164 + unsigned int hdrlen; 165 + 166 + if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) { 167 + if (target < 0) 168 + break; 169 + return -ENOENT; 170 + } 171 + 172 + hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr); 173 + if (hp == NULL) 174 + return -EBADMSG; 175 + if (nexthdr == NEXTHDR_FRAGMENT) { 176 + unsigned short _frag_off; 177 + __be16 *fp; 178 + 179 + if (flags) /* Indicate that this is a fragment */ 180 + *flags |= IP6_FH_F_FRAG; 181 + fp = skb_header_pointer(skb, 182 + start+offsetof(struct frag_hdr, 183 + frag_off), 184 + sizeof(_frag_off), 185 + &_frag_off); 186 + if (fp == NULL) 187 + return -EBADMSG; 188 + 189 + _frag_off = ntohs(*fp) & ~0x7; 190 + if (_frag_off) { 191 + if (target < 0 && 192 + ((!ipv6_ext_hdr(hp->nexthdr)) || 193 + hp->nexthdr == NEXTHDR_NONE)) { 194 + if (fragoff) 195 + *fragoff = _frag_off; 196 + return hp->nexthdr; 197 + } 198 + return -ENOENT; 199 + } 200 + hdrlen = 8; 201 + } else if (nexthdr == NEXTHDR_AUTH) { 202 + if (flags && (*flags & IP6_FH_F_AUTH) && (target < 0)) 203 + break; 204 + hdrlen = (hp->hdrlen + 2) << 2; 205 + } else 206 + hdrlen = ipv6_optlen(hp); 207 + 208 + nexthdr = hp->nexthdr; 209 + len -= hdrlen; 210 + start += hdrlen; 211 + } 212 + 213 + *offset = start; 214 + return nexthdr; 215 + } 216 + EXPORT_SYMBOL(ipv6_find_hdr);
-103
net/ipv6/netfilter/ip6_tables.c
··· 2273 2273 unregister_pernet_subsys(&ip6_tables_net_ops); 2274 2274 } 2275 2275 2276 - /* 2277 - * find the offset to specified header or the protocol number of last header 2278 - * if target < 0. "last header" is transport protocol header, ESP, or 2279 - * "No next header". 2280 - * 2281 - * Note that *offset is used as input/output parameter. an if it is not zero, 2282 - * then it must be a valid offset to an inner IPv6 header. This can be used 2283 - * to explore inner IPv6 header, eg. ICMPv6 error messages. 2284 - * 2285 - * If target header is found, its offset is set in *offset and return protocol 2286 - * number. Otherwise, return -1. 2287 - * 2288 - * If the first fragment doesn't contain the final protocol header or 2289 - * NEXTHDR_NONE it is considered invalid. 2290 - * 2291 - * Note that non-1st fragment is special case that "the protocol number 2292 - * of last header" is "next header" field in Fragment header. In this case, 2293 - * *offset is meaningless and fragment offset is stored in *fragoff if fragoff 2294 - * isn't NULL. 2295 - * 2296 - * if flags is not NULL and it's a fragment, then the frag flag IP6T_FH_F_FRAG 2297 - * will be set. If it's an AH header, the IP6T_FH_F_AUTH flag is set and 2298 - * target < 0, then this function will stop at the AH header. 2299 - */ 2300 - int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, 2301 - int target, unsigned short *fragoff, int *flags) 2302 - { 2303 - unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr); 2304 - u8 nexthdr = ipv6_hdr(skb)->nexthdr; 2305 - unsigned int len; 2306 - 2307 - if (fragoff) 2308 - *fragoff = 0; 2309 - 2310 - if (*offset) { 2311 - struct ipv6hdr _ip6, *ip6; 2312 - 2313 - ip6 = skb_header_pointer(skb, *offset, sizeof(_ip6), &_ip6); 2314 - if (!ip6 || (ip6->version != 6)) { 2315 - printk(KERN_ERR "IPv6 header not found\n"); 2316 - return -EBADMSG; 2317 - } 2318 - start = *offset + sizeof(struct ipv6hdr); 2319 - nexthdr = ip6->nexthdr; 2320 - } 2321 - len = skb->len - start; 2322 - 2323 - while (nexthdr != target) { 2324 - struct ipv6_opt_hdr _hdr, *hp; 2325 - unsigned int hdrlen; 2326 - 2327 - if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) { 2328 - if (target < 0) 2329 - break; 2330 - return -ENOENT; 2331 - } 2332 - 2333 - hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr); 2334 - if (hp == NULL) 2335 - return -EBADMSG; 2336 - if (nexthdr == NEXTHDR_FRAGMENT) { 2337 - unsigned short _frag_off; 2338 - __be16 *fp; 2339 - 2340 - if (flags) /* Indicate that this is a fragment */ 2341 - *flags |= IP6T_FH_F_FRAG; 2342 - fp = skb_header_pointer(skb, 2343 - start+offsetof(struct frag_hdr, 2344 - frag_off), 2345 - sizeof(_frag_off), 2346 - &_frag_off); 2347 - if (fp == NULL) 2348 - return -EBADMSG; 2349 - 2350 - _frag_off = ntohs(*fp) & ~0x7; 2351 - if (_frag_off) { 2352 - if (target < 0 && 2353 - ((!ipv6_ext_hdr(hp->nexthdr)) || 2354 - hp->nexthdr == NEXTHDR_NONE)) { 2355 - if (fragoff) 2356 - *fragoff = _frag_off; 2357 - return hp->nexthdr; 2358 - } 2359 - return -ENOENT; 2360 - } 2361 - hdrlen = 8; 2362 - } else if (nexthdr == NEXTHDR_AUTH) { 2363 - if (flags && (*flags & IP6T_FH_F_AUTH) && (target < 0)) 2364 - break; 2365 - hdrlen = (hp->hdrlen + 2) << 2; 2366 - } else 2367 - hdrlen = ipv6_optlen(hp); 2368 - 2369 - nexthdr = hp->nexthdr; 2370 - len -= hdrlen; 2371 - start += hdrlen; 2372 - } 2373 - 2374 - *offset = start; 2375 - return nexthdr; 2376 - } 2377 - 2378 2276 EXPORT_SYMBOL(ip6t_register_table); 2379 2277 EXPORT_SYMBOL(ip6t_unregister_table); 2380 2278 EXPORT_SYMBOL(ip6t_do_table); 2381 - EXPORT_SYMBOL(ipv6_find_hdr); 2382 2279 2383 2280 module_init(ip6_tables_init); 2384 2281 module_exit(ip6_tables_fini);
+4 -4
net/netfilter/xt_HMARK.c
··· 167 167 const struct xt_hmark_info *info) 168 168 { 169 169 struct ipv6hdr *ip6, _ip6; 170 - int flag = IP6T_FH_F_AUTH; 170 + int flag = IP6_FH_F_AUTH; 171 171 unsigned int nhoff = 0; 172 172 u16 fragoff = 0; 173 173 int nexthdr; ··· 177 177 if (nexthdr < 0) 178 178 return 0; 179 179 /* No need to check for icmp errors on fragments */ 180 - if ((flag & IP6T_FH_F_FRAG) || (nexthdr != IPPROTO_ICMPV6)) 180 + if ((flag & IP6_FH_F_FRAG) || (nexthdr != IPPROTO_ICMPV6)) 181 181 goto noicmp; 182 182 /* Use inner header in case of ICMP errors */ 183 183 if (get_inner6_hdr(skb, &nhoff)) { ··· 185 185 if (ip6 == NULL) 186 186 return -1; 187 187 /* If AH present, use SPI like in ESP. */ 188 - flag = IP6T_FH_F_AUTH; 188 + flag = IP6_FH_F_AUTH; 189 189 nexthdr = ipv6_find_hdr(skb, &nhoff, -1, &fragoff, &flag); 190 190 if (nexthdr < 0) 191 191 return -1; ··· 201 201 if (t->proto == IPPROTO_ICMPV6) 202 202 return 0; 203 203 204 - if (flag & IP6T_FH_F_FRAG) 204 + if (flag & IP6_FH_F_FRAG) 205 205 return 0; 206 206 207 207 hmark_set_tuple_ports(skb, nhoff, t, info);