aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/exthdrs.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/exthdrs.c')
-rw-r--r--net/ipv6/exthdrs.c233
1 files changed, 213 insertions, 20 deletions
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 86dac106873b..88c96b10684c 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -43,9 +43,54 @@
43#include <net/ndisc.h> 43#include <net/ndisc.h>
44#include <net/ip6_route.h> 44#include <net/ip6_route.h>
45#include <net/addrconf.h> 45#include <net/addrconf.h>
46#ifdef CONFIG_IPV6_MIP6
47#include <net/xfrm.h>
48#endif
46 49
47#include <asm/uaccess.h> 50#include <asm/uaccess.h>
48 51
52int ipv6_find_tlv(struct sk_buff *skb, int offset, int type)
53{
54 int packet_len = skb->tail - skb->nh.raw;
55 struct ipv6_opt_hdr *hdr;
56 int len;
57
58 if (offset + 2 > packet_len)
59 goto bad;
60 hdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
61 len = ((hdr->hdrlen + 1) << 3);
62
63 if (offset + len > packet_len)
64 goto bad;
65
66 offset += 2;
67 len -= 2;
68
69 while (len > 0) {
70 int opttype = skb->nh.raw[offset];
71 int optlen;
72
73 if (opttype == type)
74 return offset;
75
76 switch (opttype) {
77 case IPV6_TLV_PAD0:
78 optlen = 1;
79 break;
80 default:
81 optlen = skb->nh.raw[offset + 1] + 2;
82 if (optlen > len)
83 goto bad;
84 break;
85 }
86 offset += optlen;
87 len -= optlen;
88 }
89 /* not_found */
90 bad:
91 return -1;
92}
93
49/* 94/*
50 * Parsing tlv encoded headers. 95 * Parsing tlv encoded headers.
51 * 96 *
@@ -56,7 +101,7 @@
56 101
57struct tlvtype_proc { 102struct tlvtype_proc {
58 int type; 103 int type;
59 int (*func)(struct sk_buff *skb, int offset); 104 int (*func)(struct sk_buff **skbp, int offset);
60}; 105};
61 106
62/********************* 107/*********************
@@ -65,8 +110,10 @@ struct tlvtype_proc {
65 110
66/* An unknown option is detected, decide what to do */ 111/* An unknown option is detected, decide what to do */
67 112
68static int ip6_tlvopt_unknown(struct sk_buff *skb, int optoff) 113static int ip6_tlvopt_unknown(struct sk_buff **skbp, int optoff)
69{ 114{
115 struct sk_buff *skb = *skbp;
116
70 switch ((skb->nh.raw[optoff] & 0xC0) >> 6) { 117 switch ((skb->nh.raw[optoff] & 0xC0) >> 6) {
71 case 0: /* ignore */ 118 case 0: /* ignore */
72 return 1; 119 return 1;
@@ -91,8 +138,9 @@ static int ip6_tlvopt_unknown(struct sk_buff *skb, int optoff)
91 138
92/* Parse tlv encoded option header (hop-by-hop or destination) */ 139/* Parse tlv encoded option header (hop-by-hop or destination) */
93 140
94static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb) 141static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff **skbp)
95{ 142{
143 struct sk_buff *skb = *skbp;
96 struct tlvtype_proc *curr; 144 struct tlvtype_proc *curr;
97 int off = skb->h.raw - skb->nh.raw; 145 int off = skb->h.raw - skb->nh.raw;
98 int len = ((skb->h.raw[1]+1)<<3); 146 int len = ((skb->h.raw[1]+1)<<3);
@@ -122,13 +170,13 @@ static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb)
122 /* type specific length/alignment 170 /* type specific length/alignment
123 checks will be performed in the 171 checks will be performed in the
124 func(). */ 172 func(). */
125 if (curr->func(skb, off) == 0) 173 if (curr->func(skbp, off) == 0)
126 return 0; 174 return 0;
127 break; 175 break;
128 } 176 }
129 } 177 }
130 if (curr->type < 0) { 178 if (curr->type < 0) {
131 if (ip6_tlvopt_unknown(skb, off) == 0) 179 if (ip6_tlvopt_unknown(skbp, off) == 0)
132 return 0; 180 return 0;
133 } 181 }
134 break; 182 break;
@@ -147,8 +195,85 @@ bad:
147 Destination options header. 195 Destination options header.
148 *****************************/ 196 *****************************/
149 197
198#ifdef CONFIG_IPV6_MIP6
199static int ipv6_dest_hao(struct sk_buff **skbp, int optoff)
200{
201 struct sk_buff *skb = *skbp;
202 struct ipv6_destopt_hao *hao;
203 struct inet6_skb_parm *opt = IP6CB(skb);
204 struct ipv6hdr *ipv6h = (struct ipv6hdr *)skb->nh.raw;
205 struct in6_addr tmp_addr;
206 int ret;
207
208 if (opt->dsthao) {
209 LIMIT_NETDEBUG(KERN_DEBUG "hao duplicated\n");
210 goto discard;
211 }
212 opt->dsthao = opt->dst1;
213 opt->dst1 = 0;
214
215 hao = (struct ipv6_destopt_hao *)(skb->nh.raw + optoff);
216
217 if (hao->length != 16) {
218 LIMIT_NETDEBUG(
219 KERN_DEBUG "hao invalid option length = %d\n", hao->length);
220 goto discard;
221 }
222
223 if (!(ipv6_addr_type(&hao->addr) & IPV6_ADDR_UNICAST)) {
224 LIMIT_NETDEBUG(
225 KERN_DEBUG "hao is not an unicast addr: " NIP6_FMT "\n", NIP6(hao->addr));
226 goto discard;
227 }
228
229 ret = xfrm6_input_addr(skb, (xfrm_address_t *)&ipv6h->daddr,
230 (xfrm_address_t *)&hao->addr, IPPROTO_DSTOPTS);
231 if (unlikely(ret < 0))
232 goto discard;
233
234 if (skb_cloned(skb)) {
235 struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
236 struct inet6_skb_parm *opt2;
237
238 if (skb2 == NULL)
239 goto discard;
240
241 opt2 = IP6CB(skb2);
242 memcpy(opt2, opt, sizeof(*opt2));
243
244 kfree_skb(skb);
245
246 /* update all variable using below by copied skbuff */
247 *skbp = skb = skb2;
248 hao = (struct ipv6_destopt_hao *)(skb2->nh.raw + optoff);
249 ipv6h = (struct ipv6hdr *)skb2->nh.raw;
250 }
251
252 if (skb->ip_summed == CHECKSUM_COMPLETE)
253 skb->ip_summed = CHECKSUM_NONE;
254
255 ipv6_addr_copy(&tmp_addr, &ipv6h->saddr);
256 ipv6_addr_copy(&ipv6h->saddr, &hao->addr);
257 ipv6_addr_copy(&hao->addr, &tmp_addr);
258
259 if (skb->tstamp.off_sec == 0)
260 __net_timestamp(skb);
261
262 return 1;
263
264 discard:
265 kfree_skb(skb);
266 return 0;
267}
268#endif
269
150static struct tlvtype_proc tlvprocdestopt_lst[] = { 270static struct tlvtype_proc tlvprocdestopt_lst[] = {
151 /* No destination options are defined now */ 271#ifdef CONFIG_IPV6_MIP6
272 {
273 .type = IPV6_TLV_HAO,
274 .func = ipv6_dest_hao,
275 },
276#endif
152 {-1, NULL} 277 {-1, NULL}
153}; 278};
154 279
@@ -156,6 +281,9 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp)
156{ 281{
157 struct sk_buff *skb = *skbp; 282 struct sk_buff *skb = *skbp;
158 struct inet6_skb_parm *opt = IP6CB(skb); 283 struct inet6_skb_parm *opt = IP6CB(skb);
284#ifdef CONFIG_IPV6_MIP6
285 __u16 dstbuf;
286#endif
159 287
160 if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) || 288 if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
161 !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) { 289 !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
@@ -166,10 +294,19 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp)
166 294
167 opt->lastopt = skb->h.raw - skb->nh.raw; 295 opt->lastopt = skb->h.raw - skb->nh.raw;
168 opt->dst1 = skb->h.raw - skb->nh.raw; 296 opt->dst1 = skb->h.raw - skb->nh.raw;
297#ifdef CONFIG_IPV6_MIP6
298 dstbuf = opt->dst1;
299#endif
169 300
170 if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) { 301 if (ip6_parse_tlv(tlvprocdestopt_lst, skbp)) {
302 skb = *skbp;
171 skb->h.raw += ((skb->h.raw[1]+1)<<3); 303 skb->h.raw += ((skb->h.raw[1]+1)<<3);
304 opt = IP6CB(skb);
305#ifdef CONFIG_IPV6_MIP6
306 opt->nhoff = dstbuf;
307#else
172 opt->nhoff = opt->dst1; 308 opt->nhoff = opt->dst1;
309#endif
173 return 1; 310 return 1;
174 } 311 }
175 312
@@ -219,7 +356,7 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)
219{ 356{
220 struct sk_buff *skb = *skbp; 357 struct sk_buff *skb = *skbp;
221 struct inet6_skb_parm *opt = IP6CB(skb); 358 struct inet6_skb_parm *opt = IP6CB(skb);
222 struct in6_addr *addr; 359 struct in6_addr *addr = NULL;
223 struct in6_addr daddr; 360 struct in6_addr daddr;
224 int n, i; 361 int n, i;
225 362
@@ -244,6 +381,23 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)
244 381
245looped_back: 382looped_back:
246 if (hdr->segments_left == 0) { 383 if (hdr->segments_left == 0) {
384 switch (hdr->type) {
385#ifdef CONFIG_IPV6_MIP6
386 case IPV6_SRCRT_TYPE_2:
387 /* Silently discard type 2 header unless it was
388 * processed by own
389 */
390 if (!addr) {
391 IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
392 kfree_skb(skb);
393 return -1;
394 }
395 break;
396#endif
397 default:
398 break;
399 }
400
247 opt->lastopt = skb->h.raw - skb->nh.raw; 401 opt->lastopt = skb->h.raw - skb->nh.raw;
248 opt->srcrt = skb->h.raw - skb->nh.raw; 402 opt->srcrt = skb->h.raw - skb->nh.raw;
249 skb->h.raw += (hdr->hdrlen + 1) << 3; 403 skb->h.raw += (hdr->hdrlen + 1) << 3;
@@ -253,17 +407,29 @@ looped_back:
253 return 1; 407 return 1;
254 } 408 }
255 409
256 if (hdr->type != IPV6_SRCRT_TYPE_0) { 410 switch (hdr->type) {
411 case IPV6_SRCRT_TYPE_0:
412 if (hdr->hdrlen & 0x01) {
413 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
414 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->hdrlen) - skb->nh.raw);
415 return -1;
416 }
417 break;
418#ifdef CONFIG_IPV6_MIP6
419 case IPV6_SRCRT_TYPE_2:
420 /* Silently discard invalid RTH type 2 */
421 if (hdr->hdrlen != 2 || hdr->segments_left != 1) {
422 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
423 kfree_skb(skb);
424 return -1;
425 }
426 break;
427#endif
428 default:
257 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); 429 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
258 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw); 430 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw);
259 return -1; 431 return -1;
260 } 432 }
261
262 if (hdr->hdrlen & 0x01) {
263 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
264 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->hdrlen) - skb->nh.raw);
265 return -1;
266 }
267 433
268 /* 434 /*
269 * This is the routing header forwarding algorithm from 435 * This is the routing header forwarding algorithm from
@@ -294,7 +460,7 @@ looped_back:
294 hdr = (struct ipv6_rt_hdr *) skb2->h.raw; 460 hdr = (struct ipv6_rt_hdr *) skb2->h.raw;
295 } 461 }
296 462
297 if (skb->ip_summed == CHECKSUM_HW) 463 if (skb->ip_summed == CHECKSUM_COMPLETE)
298 skb->ip_summed = CHECKSUM_NONE; 464 skb->ip_summed = CHECKSUM_NONE;
299 465
300 i = n - --hdr->segments_left; 466 i = n - --hdr->segments_left;
@@ -303,6 +469,27 @@ looped_back:
303 addr = rthdr->addr; 469 addr = rthdr->addr;
304 addr += i - 1; 470 addr += i - 1;
305 471
472 switch (hdr->type) {
473#ifdef CONFIG_IPV6_MIP6
474 case IPV6_SRCRT_TYPE_2:
475 if (xfrm6_input_addr(skb, (xfrm_address_t *)addr,
476 (xfrm_address_t *)&skb->nh.ipv6h->saddr,
477 IPPROTO_ROUTING) < 0) {
478 IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
479 kfree_skb(skb);
480 return -1;
481 }
482 if (!ipv6_chk_home_addr(addr)) {
483 IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
484 kfree_skb(skb);
485 return -1;
486 }
487 break;
488#endif
489 default:
490 break;
491 }
492
306 if (ipv6_addr_is_multicast(addr)) { 493 if (ipv6_addr_is_multicast(addr)) {
307 IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); 494 IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
308 kfree_skb(skb); 495 kfree_skb(skb);
@@ -421,8 +608,10 @@ EXPORT_SYMBOL_GPL(ipv6_invert_rthdr);
421 608
422/* Router Alert as of RFC 2711 */ 609/* Router Alert as of RFC 2711 */
423 610
424static int ipv6_hop_ra(struct sk_buff *skb, int optoff) 611static int ipv6_hop_ra(struct sk_buff **skbp, int optoff)
425{ 612{
613 struct sk_buff *skb = *skbp;
614
426 if (skb->nh.raw[optoff+1] == 2) { 615 if (skb->nh.raw[optoff+1] == 2) {
427 IP6CB(skb)->ra = optoff; 616 IP6CB(skb)->ra = optoff;
428 return 1; 617 return 1;
@@ -435,8 +624,9 @@ static int ipv6_hop_ra(struct sk_buff *skb, int optoff)
435 624
436/* Jumbo payload */ 625/* Jumbo payload */
437 626
438static int ipv6_hop_jumbo(struct sk_buff *skb, int optoff) 627static int ipv6_hop_jumbo(struct sk_buff **skbp, int optoff)
439{ 628{
629 struct sk_buff *skb = *skbp;
440 u32 pkt_len; 630 u32 pkt_len;
441 631
442 if (skb->nh.raw[optoff+1] != 4 || (optoff&3) != 2) { 632 if (skb->nh.raw[optoff+1] != 4 || (optoff&3) != 2) {
@@ -485,8 +675,9 @@ static struct tlvtype_proc tlvprochopopt_lst[] = {
485 { -1, } 675 { -1, }
486}; 676};
487 677
488int ipv6_parse_hopopts(struct sk_buff *skb) 678int ipv6_parse_hopopts(struct sk_buff **skbp)
489{ 679{
680 struct sk_buff *skb = *skbp;
490 struct inet6_skb_parm *opt = IP6CB(skb); 681 struct inet6_skb_parm *opt = IP6CB(skb);
491 682
492 /* 683 /*
@@ -502,8 +693,10 @@ int ipv6_parse_hopopts(struct sk_buff *skb)
502 } 693 }
503 694
504 opt->hop = sizeof(struct ipv6hdr); 695 opt->hop = sizeof(struct ipv6hdr);
505 if (ip6_parse_tlv(tlvprochopopt_lst, skb)) { 696 if (ip6_parse_tlv(tlvprochopopt_lst, skbp)) {
697 skb = *skbp;
506 skb->h.raw += (skb->h.raw[1]+1)<<3; 698 skb->h.raw += (skb->h.raw[1]+1)<<3;
699 opt = IP6CB(skb);
507 opt->nhoff = sizeof(struct ipv6hdr); 700 opt->nhoff = sizeof(struct ipv6hdr);
508 return 1; 701 return 1;
509 } 702 }