diff options
Diffstat (limited to 'net/ipv4/ip_options.c')
-rw-r--r-- | net/ipv4/ip_options.c | 57 |
1 files changed, 27 insertions, 30 deletions
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 2391b24e8251..c3118e1cd3bb 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c | |||
@@ -36,8 +36,8 @@ | |||
36 | * saddr is address of outgoing interface. | 36 | * saddr is address of outgoing interface. |
37 | */ | 37 | */ |
38 | 38 | ||
39 | void ip_options_build(struct sk_buff * skb, struct ip_options * opt, | 39 | void ip_options_build(struct sk_buff *skb, struct ip_options *opt, |
40 | __be32 daddr, struct rtable *rt, int is_frag) | 40 | __be32 daddr, struct rtable *rt, int is_frag) |
41 | { | 41 | { |
42 | unsigned char *iph = skb_network_header(skb); | 42 | unsigned char *iph = skb_network_header(skb); |
43 | 43 | ||
@@ -50,9 +50,9 @@ void ip_options_build(struct sk_buff * skb, struct ip_options * opt, | |||
50 | 50 | ||
51 | if (!is_frag) { | 51 | if (!is_frag) { |
52 | if (opt->rr_needaddr) | 52 | if (opt->rr_needaddr) |
53 | ip_rt_get_source(iph+opt->rr+iph[opt->rr+2]-5, rt); | 53 | ip_rt_get_source(iph+opt->rr+iph[opt->rr+2]-5, skb, rt); |
54 | if (opt->ts_needaddr) | 54 | if (opt->ts_needaddr) |
55 | ip_rt_get_source(iph+opt->ts+iph[opt->ts+2]-9, rt); | 55 | ip_rt_get_source(iph+opt->ts+iph[opt->ts+2]-9, skb, rt); |
56 | if (opt->ts_needtime) { | 56 | if (opt->ts_needtime) { |
57 | struct timespec tv; | 57 | struct timespec tv; |
58 | __be32 midtime; | 58 | __be32 midtime; |
@@ -83,9 +83,9 @@ void ip_options_build(struct sk_buff * skb, struct ip_options * opt, | |||
83 | * NOTE: dopt cannot point to skb. | 83 | * NOTE: dopt cannot point to skb. |
84 | */ | 84 | */ |
85 | 85 | ||
86 | int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb) | 86 | int ip_options_echo(struct ip_options *dopt, struct sk_buff *skb) |
87 | { | 87 | { |
88 | struct ip_options *sopt; | 88 | const struct ip_options *sopt; |
89 | unsigned char *sptr, *dptr; | 89 | unsigned char *sptr, *dptr; |
90 | int soffset, doffset; | 90 | int soffset, doffset; |
91 | int optlen; | 91 | int optlen; |
@@ -95,10 +95,8 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb) | |||
95 | 95 | ||
96 | sopt = &(IPCB(skb)->opt); | 96 | sopt = &(IPCB(skb)->opt); |
97 | 97 | ||
98 | if (sopt->optlen == 0) { | 98 | if (sopt->optlen == 0) |
99 | dopt->optlen = 0; | ||
100 | return 0; | 99 | return 0; |
101 | } | ||
102 | 100 | ||
103 | sptr = skb_network_header(skb); | 101 | sptr = skb_network_header(skb); |
104 | dptr = dopt->__data; | 102 | dptr = dopt->__data; |
@@ -157,7 +155,7 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb) | |||
157 | dopt->optlen += optlen; | 155 | dopt->optlen += optlen; |
158 | } | 156 | } |
159 | if (sopt->srr) { | 157 | if (sopt->srr) { |
160 | unsigned char * start = sptr+sopt->srr; | 158 | unsigned char *start = sptr+sopt->srr; |
161 | __be32 faddr; | 159 | __be32 faddr; |
162 | 160 | ||
163 | optlen = start[1]; | 161 | optlen = start[1]; |
@@ -499,19 +497,19 @@ void ip_options_undo(struct ip_options * opt) | |||
499 | } | 497 | } |
500 | } | 498 | } |
501 | 499 | ||
502 | static struct ip_options *ip_options_get_alloc(const int optlen) | 500 | static struct ip_options_rcu *ip_options_get_alloc(const int optlen) |
503 | { | 501 | { |
504 | return kzalloc(sizeof(struct ip_options) + ((optlen + 3) & ~3), | 502 | return kzalloc(sizeof(struct ip_options_rcu) + ((optlen + 3) & ~3), |
505 | GFP_KERNEL); | 503 | GFP_KERNEL); |
506 | } | 504 | } |
507 | 505 | ||
508 | static int ip_options_get_finish(struct net *net, struct ip_options **optp, | 506 | static int ip_options_get_finish(struct net *net, struct ip_options_rcu **optp, |
509 | struct ip_options *opt, int optlen) | 507 | struct ip_options_rcu *opt, int optlen) |
510 | { | 508 | { |
511 | while (optlen & 3) | 509 | while (optlen & 3) |
512 | opt->__data[optlen++] = IPOPT_END; | 510 | opt->opt.__data[optlen++] = IPOPT_END; |
513 | opt->optlen = optlen; | 511 | opt->opt.optlen = optlen; |
514 | if (optlen && ip_options_compile(net, opt, NULL)) { | 512 | if (optlen && ip_options_compile(net, &opt->opt, NULL)) { |
515 | kfree(opt); | 513 | kfree(opt); |
516 | return -EINVAL; | 514 | return -EINVAL; |
517 | } | 515 | } |
@@ -520,29 +518,29 @@ static int ip_options_get_finish(struct net *net, struct ip_options **optp, | |||
520 | return 0; | 518 | return 0; |
521 | } | 519 | } |
522 | 520 | ||
523 | int ip_options_get_from_user(struct net *net, struct ip_options **optp, | 521 | int ip_options_get_from_user(struct net *net, struct ip_options_rcu **optp, |
524 | unsigned char __user *data, int optlen) | 522 | unsigned char __user *data, int optlen) |
525 | { | 523 | { |
526 | struct ip_options *opt = ip_options_get_alloc(optlen); | 524 | struct ip_options_rcu *opt = ip_options_get_alloc(optlen); |
527 | 525 | ||
528 | if (!opt) | 526 | if (!opt) |
529 | return -ENOMEM; | 527 | return -ENOMEM; |
530 | if (optlen && copy_from_user(opt->__data, data, optlen)) { | 528 | if (optlen && copy_from_user(opt->opt.__data, data, optlen)) { |
531 | kfree(opt); | 529 | kfree(opt); |
532 | return -EFAULT; | 530 | return -EFAULT; |
533 | } | 531 | } |
534 | return ip_options_get_finish(net, optp, opt, optlen); | 532 | return ip_options_get_finish(net, optp, opt, optlen); |
535 | } | 533 | } |
536 | 534 | ||
537 | int ip_options_get(struct net *net, struct ip_options **optp, | 535 | int ip_options_get(struct net *net, struct ip_options_rcu **optp, |
538 | unsigned char *data, int optlen) | 536 | unsigned char *data, int optlen) |
539 | { | 537 | { |
540 | struct ip_options *opt = ip_options_get_alloc(optlen); | 538 | struct ip_options_rcu *opt = ip_options_get_alloc(optlen); |
541 | 539 | ||
542 | if (!opt) | 540 | if (!opt) |
543 | return -ENOMEM; | 541 | return -ENOMEM; |
544 | if (optlen) | 542 | if (optlen) |
545 | memcpy(opt->__data, data, optlen); | 543 | memcpy(opt->opt.__data, data, optlen); |
546 | return ip_options_get_finish(net, optp, opt, optlen); | 544 | return ip_options_get_finish(net, optp, opt, optlen); |
547 | } | 545 | } |
548 | 546 | ||
@@ -555,7 +553,7 @@ void ip_forward_options(struct sk_buff *skb) | |||
555 | 553 | ||
556 | if (opt->rr_needaddr) { | 554 | if (opt->rr_needaddr) { |
557 | optptr = (unsigned char *)raw + opt->rr; | 555 | optptr = (unsigned char *)raw + opt->rr; |
558 | ip_rt_get_source(&optptr[optptr[2]-5], rt); | 556 | ip_rt_get_source(&optptr[optptr[2]-5], skb, rt); |
559 | opt->is_changed = 1; | 557 | opt->is_changed = 1; |
560 | } | 558 | } |
561 | if (opt->srr_is_hit) { | 559 | if (opt->srr_is_hit) { |
@@ -569,19 +567,18 @@ void ip_forward_options(struct sk_buff *skb) | |||
569 | ) { | 567 | ) { |
570 | if (srrptr + 3 > srrspace) | 568 | if (srrptr + 3 > srrspace) |
571 | break; | 569 | break; |
572 | if (memcmp(&rt->rt_dst, &optptr[srrptr-1], 4) == 0) | 570 | if (memcmp(&ip_hdr(skb)->daddr, &optptr[srrptr-1], 4) == 0) |
573 | break; | 571 | break; |
574 | } | 572 | } |
575 | if (srrptr + 3 <= srrspace) { | 573 | if (srrptr + 3 <= srrspace) { |
576 | opt->is_changed = 1; | 574 | opt->is_changed = 1; |
577 | ip_rt_get_source(&optptr[srrptr-1], rt); | 575 | ip_rt_get_source(&optptr[srrptr-1], skb, rt); |
578 | ip_hdr(skb)->daddr = rt->rt_dst; | ||
579 | optptr[2] = srrptr+4; | 576 | optptr[2] = srrptr+4; |
580 | } else if (net_ratelimit()) | 577 | } else if (net_ratelimit()) |
581 | printk(KERN_CRIT "ip_forward(): Argh! Destination lost!\n"); | 578 | printk(KERN_CRIT "ip_forward(): Argh! Destination lost!\n"); |
582 | if (opt->ts_needaddr) { | 579 | if (opt->ts_needaddr) { |
583 | optptr = raw + opt->ts; | 580 | optptr = raw + opt->ts; |
584 | ip_rt_get_source(&optptr[optptr[2]-9], rt); | 581 | ip_rt_get_source(&optptr[optptr[2]-9], skb, rt); |
585 | opt->is_changed = 1; | 582 | opt->is_changed = 1; |
586 | } | 583 | } |
587 | } | 584 | } |
@@ -603,7 +600,7 @@ int ip_options_rcv_srr(struct sk_buff *skb) | |||
603 | unsigned long orefdst; | 600 | unsigned long orefdst; |
604 | int err; | 601 | int err; |
605 | 602 | ||
606 | if (!opt->srr || !rt) | 603 | if (!rt) |
607 | return 0; | 604 | return 0; |
608 | 605 | ||
609 | if (skb->pkt_type != PACKET_HOST) | 606 | if (skb->pkt_type != PACKET_HOST) |
@@ -637,7 +634,7 @@ int ip_options_rcv_srr(struct sk_buff *skb) | |||
637 | if (rt2->rt_type != RTN_LOCAL) | 634 | if (rt2->rt_type != RTN_LOCAL) |
638 | break; | 635 | break; |
639 | /* Superfast 8) loopback forward */ | 636 | /* Superfast 8) loopback forward */ |
640 | memcpy(&iph->daddr, &optptr[srrptr-1], 4); | 637 | iph->daddr = nexthop; |
641 | opt->is_changed = 1; | 638 | opt->is_changed = 1; |
642 | } | 639 | } |
643 | if (srrptr <= srrspace) { | 640 | if (srrptr <= srrspace) { |