diff options
Diffstat (limited to 'net/ipv4/ip_options.c')
-rw-r--r-- | net/ipv4/ip_options.c | 63 |
1 files changed, 27 insertions, 36 deletions
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 4d315158fd3c..d107543d3f81 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c | |||
@@ -45,7 +45,6 @@ void ip_options_build(struct sk_buff * skb, struct ip_options * opt, | |||
45 | memcpy(&(IPCB(skb)->opt), opt, sizeof(struct ip_options)); | 45 | memcpy(&(IPCB(skb)->opt), opt, sizeof(struct ip_options)); |
46 | memcpy(iph+sizeof(struct iphdr), opt->__data, opt->optlen); | 46 | memcpy(iph+sizeof(struct iphdr), opt->__data, opt->optlen); |
47 | opt = &(IPCB(skb)->opt); | 47 | opt = &(IPCB(skb)->opt); |
48 | opt->is_data = 0; | ||
49 | 48 | ||
50 | if (opt->srr) | 49 | if (opt->srr) |
51 | memcpy(iph+opt->srr+iph[opt->srr+1]-4, &daddr, 4); | 50 | memcpy(iph+opt->srr+iph[opt->srr+1]-4, &daddr, 4); |
@@ -95,8 +94,6 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb) | |||
95 | 94 | ||
96 | memset(dopt, 0, sizeof(struct ip_options)); | 95 | memset(dopt, 0, sizeof(struct ip_options)); |
97 | 96 | ||
98 | dopt->is_data = 1; | ||
99 | |||
100 | sopt = &(IPCB(skb)->opt); | 97 | sopt = &(IPCB(skb)->opt); |
101 | 98 | ||
102 | if (sopt->optlen == 0) { | 99 | if (sopt->optlen == 0) { |
@@ -107,10 +104,7 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb) | |||
107 | sptr = skb_network_header(skb); | 104 | sptr = skb_network_header(skb); |
108 | dptr = dopt->__data; | 105 | dptr = dopt->__data; |
109 | 106 | ||
110 | if (skb->dst) | 107 | daddr = skb->rtable->rt_spec_dst; |
111 | daddr = ((struct rtable*)skb->dst)->rt_spec_dst; | ||
112 | else | ||
113 | daddr = ip_hdr(skb)->daddr; | ||
114 | 108 | ||
115 | if (sopt->rr) { | 109 | if (sopt->rr) { |
116 | optlen = sptr[sopt->rr+1]; | 110 | optlen = sptr[sopt->rr+1]; |
@@ -151,7 +145,7 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb) | |||
151 | __be32 addr; | 145 | __be32 addr; |
152 | 146 | ||
153 | memcpy(&addr, sptr+soffset-1, 4); | 147 | memcpy(&addr, sptr+soffset-1, 4); |
154 | if (inet_addr_type(&init_net, addr) != RTN_LOCAL) { | 148 | if (inet_addr_type(dev_net(skb->dst->dev), addr) != RTN_LOCAL) { |
155 | dopt->ts_needtime = 1; | 149 | dopt->ts_needtime = 1; |
156 | soffset += 8; | 150 | soffset += 8; |
157 | } | 151 | } |
@@ -254,26 +248,22 @@ void ip_options_fragment(struct sk_buff * skb) | |||
254 | * If opt == NULL, then skb->data should point to IP header. | 248 | * If opt == NULL, then skb->data should point to IP header. |
255 | */ | 249 | */ |
256 | 250 | ||
257 | int ip_options_compile(struct ip_options * opt, struct sk_buff * skb) | 251 | int ip_options_compile(struct net *net, |
252 | struct ip_options * opt, struct sk_buff * skb) | ||
258 | { | 253 | { |
259 | int l; | 254 | int l; |
260 | unsigned char * iph; | 255 | unsigned char * iph; |
261 | unsigned char * optptr; | 256 | unsigned char * optptr; |
262 | int optlen; | 257 | int optlen; |
263 | unsigned char * pp_ptr = NULL; | 258 | unsigned char * pp_ptr = NULL; |
264 | struct rtable *rt = skb ? (struct rtable*)skb->dst : NULL; | 259 | struct rtable *rt = NULL; |
265 | 260 | ||
266 | if (!opt) { | 261 | if (skb != NULL) { |
267 | opt = &(IPCB(skb)->opt); | 262 | rt = skb->rtable; |
268 | iph = skb_network_header(skb); | 263 | optptr = (unsigned char *)&(ip_hdr(skb)[1]); |
269 | opt->optlen = ((struct iphdr *)iph)->ihl*4 - sizeof(struct iphdr); | 264 | } else |
270 | optptr = iph + sizeof(struct iphdr); | 265 | optptr = opt->__data; |
271 | opt->is_data = 0; | 266 | iph = optptr - sizeof(struct iphdr); |
272 | } else { | ||
273 | optptr = opt->is_data ? opt->__data : | ||
274 | (unsigned char *)&(ip_hdr(skb)[1]); | ||
275 | iph = optptr - sizeof(struct iphdr); | ||
276 | } | ||
277 | 267 | ||
278 | for (l = opt->optlen; l > 0; ) { | 268 | for (l = opt->optlen; l > 0; ) { |
279 | switch (*optptr) { | 269 | switch (*optptr) { |
@@ -400,7 +390,7 @@ int ip_options_compile(struct ip_options * opt, struct sk_buff * skb) | |||
400 | { | 390 | { |
401 | __be32 addr; | 391 | __be32 addr; |
402 | memcpy(&addr, &optptr[optptr[2]-1], 4); | 392 | memcpy(&addr, &optptr[optptr[2]-1], 4); |
403 | if (inet_addr_type(&init_net, addr) == RTN_UNICAST) | 393 | if (inet_addr_type(net, addr) == RTN_UNICAST) |
404 | break; | 394 | break; |
405 | if (skb) | 395 | if (skb) |
406 | timeptr = (__be32*)&optptr[optptr[2]+3]; | 396 | timeptr = (__be32*)&optptr[optptr[2]+3]; |
@@ -517,14 +507,13 @@ static struct ip_options *ip_options_get_alloc(const int optlen) | |||
517 | GFP_KERNEL); | 507 | GFP_KERNEL); |
518 | } | 508 | } |
519 | 509 | ||
520 | static int ip_options_get_finish(struct ip_options **optp, | 510 | static int ip_options_get_finish(struct net *net, struct ip_options **optp, |
521 | struct ip_options *opt, int optlen) | 511 | struct ip_options *opt, int optlen) |
522 | { | 512 | { |
523 | while (optlen & 3) | 513 | while (optlen & 3) |
524 | opt->__data[optlen++] = IPOPT_END; | 514 | opt->__data[optlen++] = IPOPT_END; |
525 | opt->optlen = optlen; | 515 | opt->optlen = optlen; |
526 | opt->is_data = 1; | 516 | if (optlen && ip_options_compile(net, opt, NULL)) { |
527 | if (optlen && ip_options_compile(opt, NULL)) { | ||
528 | kfree(opt); | 517 | kfree(opt); |
529 | return -EINVAL; | 518 | return -EINVAL; |
530 | } | 519 | } |
@@ -533,7 +522,8 @@ static int ip_options_get_finish(struct ip_options **optp, | |||
533 | return 0; | 522 | return 0; |
534 | } | 523 | } |
535 | 524 | ||
536 | int ip_options_get_from_user(struct ip_options **optp, unsigned char __user *data, int optlen) | 525 | int ip_options_get_from_user(struct net *net, struct ip_options **optp, |
526 | unsigned char __user *data, int optlen) | ||
537 | { | 527 | { |
538 | struct ip_options *opt = ip_options_get_alloc(optlen); | 528 | struct ip_options *opt = ip_options_get_alloc(optlen); |
539 | 529 | ||
@@ -543,10 +533,11 @@ int ip_options_get_from_user(struct ip_options **optp, unsigned char __user *dat | |||
543 | kfree(opt); | 533 | kfree(opt); |
544 | return -EFAULT; | 534 | return -EFAULT; |
545 | } | 535 | } |
546 | return ip_options_get_finish(optp, opt, optlen); | 536 | return ip_options_get_finish(net, optp, opt, optlen); |
547 | } | 537 | } |
548 | 538 | ||
549 | int ip_options_get(struct ip_options **optp, unsigned char *data, int optlen) | 539 | int ip_options_get(struct net *net, struct ip_options **optp, |
540 | unsigned char *data, int optlen) | ||
550 | { | 541 | { |
551 | struct ip_options *opt = ip_options_get_alloc(optlen); | 542 | struct ip_options *opt = ip_options_get_alloc(optlen); |
552 | 543 | ||
@@ -554,14 +545,14 @@ int ip_options_get(struct ip_options **optp, unsigned char *data, int optlen) | |||
554 | return -ENOMEM; | 545 | return -ENOMEM; |
555 | if (optlen) | 546 | if (optlen) |
556 | memcpy(opt->__data, data, optlen); | 547 | memcpy(opt->__data, data, optlen); |
557 | return ip_options_get_finish(optp, opt, optlen); | 548 | return ip_options_get_finish(net, optp, opt, optlen); |
558 | } | 549 | } |
559 | 550 | ||
560 | void ip_forward_options(struct sk_buff *skb) | 551 | void ip_forward_options(struct sk_buff *skb) |
561 | { | 552 | { |
562 | struct ip_options * opt = &(IPCB(skb)->opt); | 553 | struct ip_options * opt = &(IPCB(skb)->opt); |
563 | unsigned char * optptr; | 554 | unsigned char * optptr; |
564 | struct rtable *rt = (struct rtable*)skb->dst; | 555 | struct rtable *rt = skb->rtable; |
565 | unsigned char *raw = skb_network_header(skb); | 556 | unsigned char *raw = skb_network_header(skb); |
566 | 557 | ||
567 | if (opt->rr_needaddr) { | 558 | if (opt->rr_needaddr) { |
@@ -609,7 +600,7 @@ int ip_options_rcv_srr(struct sk_buff *skb) | |||
609 | __be32 nexthop; | 600 | __be32 nexthop; |
610 | struct iphdr *iph = ip_hdr(skb); | 601 | struct iphdr *iph = ip_hdr(skb); |
611 | unsigned char *optptr = skb_network_header(skb) + opt->srr; | 602 | unsigned char *optptr = skb_network_header(skb) + opt->srr; |
612 | struct rtable *rt = (struct rtable*)skb->dst; | 603 | struct rtable *rt = skb->rtable; |
613 | struct rtable *rt2; | 604 | struct rtable *rt2; |
614 | int err; | 605 | int err; |
615 | 606 | ||
@@ -634,13 +625,13 @@ int ip_options_rcv_srr(struct sk_buff *skb) | |||
634 | } | 625 | } |
635 | memcpy(&nexthop, &optptr[srrptr-1], 4); | 626 | memcpy(&nexthop, &optptr[srrptr-1], 4); |
636 | 627 | ||
637 | rt = (struct rtable*)skb->dst; | 628 | rt = skb->rtable; |
638 | skb->dst = NULL; | 629 | skb->rtable = NULL; |
639 | err = ip_route_input(skb, nexthop, iph->saddr, iph->tos, skb->dev); | 630 | err = ip_route_input(skb, nexthop, iph->saddr, iph->tos, skb->dev); |
640 | rt2 = (struct rtable*)skb->dst; | 631 | rt2 = skb->rtable; |
641 | if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) { | 632 | if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) { |
642 | ip_rt_put(rt2); | 633 | ip_rt_put(rt2); |
643 | skb->dst = &rt->u.dst; | 634 | skb->rtable = rt; |
644 | return -EINVAL; | 635 | return -EINVAL; |
645 | } | 636 | } |
646 | ip_rt_put(rt); | 637 | ip_rt_put(rt); |