diff options
Diffstat (limited to 'net/ipv6/exthdrs.c')
| -rw-r--r-- | net/ipv6/exthdrs.c | 266 |
1 files changed, 231 insertions, 35 deletions
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index a18d4256372c..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 | ||
| 52 | int 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 | ||
| 57 | struct tlvtype_proc { | 102 | struct 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 | ||
| 68 | static int ip6_tlvopt_unknown(struct sk_buff *skb, int optoff) | 113 | static 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 | ||
| 94 | static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb) | 141 | static 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 | ||
| 199 | static 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 | |||
| 150 | static struct tlvtype_proc tlvprocdestopt_lst[] = { | 270 | static 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 | ||
| @@ -179,7 +316,7 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp) | |||
| 179 | 316 | ||
| 180 | static struct inet6_protocol destopt_protocol = { | 317 | static struct inet6_protocol destopt_protocol = { |
| 181 | .handler = ipv6_destopt_rcv, | 318 | .handler = ipv6_destopt_rcv, |
| 182 | .flags = INET6_PROTO_NOPOLICY, | 319 | .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR, |
| 183 | }; | 320 | }; |
| 184 | 321 | ||
| 185 | void __init ipv6_destopt_init(void) | 322 | void __init ipv6_destopt_init(void) |
| @@ -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 | ||
| 245 | looped_back: | 382 | looped_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); |
| @@ -340,7 +527,7 @@ looped_back: | |||
| 340 | 527 | ||
| 341 | static struct inet6_protocol rthdr_protocol = { | 528 | static struct inet6_protocol rthdr_protocol = { |
| 342 | .handler = ipv6_rthdr_rcv, | 529 | .handler = ipv6_rthdr_rcv, |
| 343 | .flags = INET6_PROTO_NOPOLICY, | 530 | .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR, |
| 344 | }; | 531 | }; |
| 345 | 532 | ||
| 346 | void __init ipv6_rthdr_init(void) | 533 | void __init ipv6_rthdr_init(void) |
| @@ -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 | ||
| 424 | static int ipv6_hop_ra(struct sk_buff *skb, int optoff) | 611 | static 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 | ||
| 438 | static int ipv6_hop_jumbo(struct sk_buff *skb, int optoff) | 627 | static 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 | ||
| 488 | int ipv6_parse_hopopts(struct sk_buff *skb) | 678 | int 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 | } |
| @@ -635,14 +828,17 @@ ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt, | |||
| 635 | struct ipv6_txoptions *opt2; | 828 | struct ipv6_txoptions *opt2; |
| 636 | int err; | 829 | int err; |
| 637 | 830 | ||
| 638 | if (newtype != IPV6_HOPOPTS && opt->hopopt) | 831 | if (opt) { |
| 639 | tot_len += CMSG_ALIGN(ipv6_optlen(opt->hopopt)); | 832 | if (newtype != IPV6_HOPOPTS && opt->hopopt) |
| 640 | if (newtype != IPV6_RTHDRDSTOPTS && opt->dst0opt) | 833 | tot_len += CMSG_ALIGN(ipv6_optlen(opt->hopopt)); |
| 641 | tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst0opt)); | 834 | if (newtype != IPV6_RTHDRDSTOPTS && opt->dst0opt) |
| 642 | if (newtype != IPV6_RTHDR && opt->srcrt) | 835 | tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst0opt)); |
| 643 | tot_len += CMSG_ALIGN(ipv6_optlen(opt->srcrt)); | 836 | if (newtype != IPV6_RTHDR && opt->srcrt) |
| 644 | if (newtype != IPV6_DSTOPTS && opt->dst1opt) | 837 | tot_len += CMSG_ALIGN(ipv6_optlen(opt->srcrt)); |
| 645 | tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst1opt)); | 838 | if (newtype != IPV6_DSTOPTS && opt->dst1opt) |
| 839 | tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst1opt)); | ||
| 840 | } | ||
| 841 | |||
| 646 | if (newopt && newoptlen) | 842 | if (newopt && newoptlen) |
| 647 | tot_len += CMSG_ALIGN(newoptlen); | 843 | tot_len += CMSG_ALIGN(newoptlen); |
| 648 | 844 | ||
| @@ -659,25 +855,25 @@ ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt, | |||
| 659 | opt2->tot_len = tot_len; | 855 | opt2->tot_len = tot_len; |
| 660 | p = (char *)(opt2 + 1); | 856 | p = (char *)(opt2 + 1); |
| 661 | 857 | ||
| 662 | err = ipv6_renew_option(opt->hopopt, newopt, newoptlen, | 858 | err = ipv6_renew_option(opt ? opt->hopopt : NULL, newopt, newoptlen, |
| 663 | newtype != IPV6_HOPOPTS, | 859 | newtype != IPV6_HOPOPTS, |
| 664 | &opt2->hopopt, &p); | 860 | &opt2->hopopt, &p); |
| 665 | if (err) | 861 | if (err) |
| 666 | goto out; | 862 | goto out; |
| 667 | 863 | ||
| 668 | err = ipv6_renew_option(opt->dst0opt, newopt, newoptlen, | 864 | err = ipv6_renew_option(opt ? opt->dst0opt : NULL, newopt, newoptlen, |
| 669 | newtype != IPV6_RTHDRDSTOPTS, | 865 | newtype != IPV6_RTHDRDSTOPTS, |
| 670 | &opt2->dst0opt, &p); | 866 | &opt2->dst0opt, &p); |
| 671 | if (err) | 867 | if (err) |
| 672 | goto out; | 868 | goto out; |
| 673 | 869 | ||
| 674 | err = ipv6_renew_option(opt->srcrt, newopt, newoptlen, | 870 | err = ipv6_renew_option(opt ? opt->srcrt : NULL, newopt, newoptlen, |
| 675 | newtype != IPV6_RTHDR, | 871 | newtype != IPV6_RTHDR, |
| 676 | (struct ipv6_opt_hdr **)opt2->srcrt, &p); | 872 | (struct ipv6_opt_hdr **)&opt2->srcrt, &p); |
| 677 | if (err) | 873 | if (err) |
| 678 | goto out; | 874 | goto out; |
| 679 | 875 | ||
| 680 | err = ipv6_renew_option(opt->dst1opt, newopt, newoptlen, | 876 | err = ipv6_renew_option(opt ? opt->dst1opt : NULL, newopt, newoptlen, |
| 681 | newtype != IPV6_DSTOPTS, | 877 | newtype != IPV6_DSTOPTS, |
| 682 | &opt2->dst1opt, &p); | 878 | &opt2->dst1opt, &p); |
| 683 | if (err) | 879 | if (err) |
