Commit f8f626754ebeca613cf1af2e6f890cfde0e74d5b
1 parent
c061853381
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
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>
Showing 5 changed files with 116 additions and 116 deletions Side-by-side Diff
include/linux/netfilter_ipv6/ip6_tables.h
... | ... | @@ -47,15 +47,6 @@ |
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 |
include/net/ipv6.h
... | ... | @@ -630,6 +630,15 @@ |
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, |
net/ipv6/exthdrs_core.c
... | ... | @@ -111,4 +111,107 @@ |
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); |
net/ipv6/netfilter/ip6_tables.c
... | ... | @@ -2273,112 +2273,9 @@ |
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); |
net/netfilter/xt_HMARK.c
... | ... | @@ -167,7 +167,7 @@ |
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,7 +177,7 @@ |
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,7 +185,7 @@ |
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,7 +201,7 @@ |
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); |