diff options
Diffstat (limited to 'net/ipv6/sit.c')
| -rw-r--r-- | net/ipv6/sit.c | 133 |
1 files changed, 25 insertions, 108 deletions
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 5a6fab95569f..32e871a6c25a 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
| @@ -222,15 +222,18 @@ __ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr) | |||
| 222 | 222 | ||
| 223 | } | 223 | } |
| 224 | 224 | ||
| 225 | static int ipip6_tunnel_get_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) | 225 | static int ipip6_tunnel_get_prl(struct ip_tunnel *t, |
| 226 | struct ip_tunnel_prl __user *a) | ||
| 226 | { | 227 | { |
| 227 | struct ip_tunnel_prl *kp; | 228 | struct ip_tunnel_prl kprl, *kp; |
| 228 | struct ip_tunnel_prl_entry *prl; | 229 | struct ip_tunnel_prl_entry *prl; |
| 229 | unsigned int cmax, c = 0, ca, len; | 230 | unsigned int cmax, c = 0, ca, len; |
| 230 | int ret = 0; | 231 | int ret = 0; |
| 231 | 232 | ||
| 232 | cmax = a->datalen / sizeof(*a); | 233 | if (copy_from_user(&kprl, a, sizeof(kprl))) |
| 233 | if (cmax > 1 && a->addr != htonl(INADDR_ANY)) | 234 | return -EFAULT; |
| 235 | cmax = kprl.datalen / sizeof(kprl); | ||
| 236 | if (cmax > 1 && kprl.addr != htonl(INADDR_ANY)) | ||
| 234 | cmax = 1; | 237 | cmax = 1; |
| 235 | 238 | ||
| 236 | /* For simple GET or for root users, | 239 | /* For simple GET or for root users, |
| @@ -261,26 +264,25 @@ static int ipip6_tunnel_get_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) | |||
| 261 | for (prl = t->prl; prl; prl = prl->next) { | 264 | for (prl = t->prl; prl; prl = prl->next) { |
| 262 | if (c > cmax) | 265 | if (c > cmax) |
| 263 | break; | 266 | break; |
| 264 | if (a->addr != htonl(INADDR_ANY) && prl->addr != a->addr) | 267 | if (kprl.addr != htonl(INADDR_ANY) && prl->addr != kprl.addr) |
| 265 | continue; | 268 | continue; |
| 266 | kp[c].addr = prl->addr; | 269 | kp[c].addr = prl->addr; |
| 267 | kp[c].flags = prl->flags; | 270 | kp[c].flags = prl->flags; |
| 268 | c++; | 271 | c++; |
| 269 | if (a->addr != htonl(INADDR_ANY)) | 272 | if (kprl.addr != htonl(INADDR_ANY)) |
| 270 | break; | 273 | break; |
| 271 | } | 274 | } |
| 272 | out: | 275 | out: |
| 273 | read_unlock(&ipip6_lock); | 276 | read_unlock(&ipip6_lock); |
| 274 | 277 | ||
| 275 | len = sizeof(*kp) * c; | 278 | len = sizeof(*kp) * c; |
| 276 | ret = len ? copy_to_user(a->data, kp, len) : 0; | 279 | ret = 0; |
| 280 | if ((len && copy_to_user(a + 1, kp, len)) || put_user(len, &a->datalen)) | ||
| 281 | ret = -EFAULT; | ||
| 277 | 282 | ||
| 278 | kfree(kp); | 283 | kfree(kp); |
| 279 | if (ret) | ||
| 280 | return -EFAULT; | ||
| 281 | 284 | ||
| 282 | a->datalen = len; | 285 | return ret; |
| 283 | return 0; | ||
| 284 | } | 286 | } |
| 285 | 287 | ||
| 286 | static int | 288 | static int |
| @@ -403,9 +405,8 @@ static void ipip6_tunnel_uninit(struct net_device *dev) | |||
| 403 | 405 | ||
| 404 | static int ipip6_err(struct sk_buff *skb, u32 info) | 406 | static int ipip6_err(struct sk_buff *skb, u32 info) |
| 405 | { | 407 | { |
| 406 | #ifndef I_WISH_WORLD_WERE_PERFECT | ||
| 407 | 408 | ||
| 408 | /* It is not :-( All the routers (except for Linux) return only | 409 | /* All the routers (except for Linux) return only |
| 409 | 8 bytes of packet payload. It means, that precise relaying of | 410 | 8 bytes of packet payload. It means, that precise relaying of |
| 410 | ICMP in the real Internet is absolutely infeasible. | 411 | ICMP in the real Internet is absolutely infeasible. |
| 411 | */ | 412 | */ |
| @@ -462,92 +463,6 @@ static int ipip6_err(struct sk_buff *skb, u32 info) | |||
| 462 | out: | 463 | out: |
| 463 | read_unlock(&ipip6_lock); | 464 | read_unlock(&ipip6_lock); |
| 464 | return err; | 465 | return err; |
| 465 | #else | ||
| 466 | struct iphdr *iph = (struct iphdr*)dp; | ||
| 467 | int hlen = iph->ihl<<2; | ||
| 468 | struct ipv6hdr *iph6; | ||
| 469 | const int type = icmp_hdr(skb)->type; | ||
| 470 | const int code = icmp_hdr(skb)->code; | ||
| 471 | int rel_type = 0; | ||
| 472 | int rel_code = 0; | ||
| 473 | int rel_info = 0; | ||
| 474 | struct sk_buff *skb2; | ||
| 475 | struct rt6_info *rt6i; | ||
| 476 | |||
| 477 | if (len < hlen + sizeof(struct ipv6hdr)) | ||
| 478 | return; | ||
| 479 | iph6 = (struct ipv6hdr*)(dp + hlen); | ||
| 480 | |||
| 481 | switch (type) { | ||
| 482 | default: | ||
| 483 | return; | ||
| 484 | case ICMP_PARAMETERPROB: | ||
| 485 | if (icmp_hdr(skb)->un.gateway < hlen) | ||
| 486 | return; | ||
| 487 | |||
| 488 | /* So... This guy found something strange INSIDE encapsulated | ||
| 489 | packet. Well, he is fool, but what can we do ? | ||
| 490 | */ | ||
| 491 | rel_type = ICMPV6_PARAMPROB; | ||
| 492 | rel_info = icmp_hdr(skb)->un.gateway - hlen; | ||
| 493 | break; | ||
| 494 | |||
| 495 | case ICMP_DEST_UNREACH: | ||
| 496 | switch (code) { | ||
| 497 | case ICMP_SR_FAILED: | ||
| 498 | case ICMP_PORT_UNREACH: | ||
| 499 | /* Impossible event. */ | ||
| 500 | return; | ||
| 501 | case ICMP_FRAG_NEEDED: | ||
| 502 | /* Too complicated case ... */ | ||
| 503 | return; | ||
| 504 | default: | ||
| 505 | /* All others are translated to HOST_UNREACH. | ||
| 506 | rfc2003 contains "deep thoughts" about NET_UNREACH, | ||
| 507 | I believe, it is just ether pollution. --ANK | ||
| 508 | */ | ||
| 509 | rel_type = ICMPV6_DEST_UNREACH; | ||
| 510 | rel_code = ICMPV6_ADDR_UNREACH; | ||
| 511 | break; | ||
| 512 | } | ||
| 513 | break; | ||
| 514 | case ICMP_TIME_EXCEEDED: | ||
| 515 | if (code != ICMP_EXC_TTL) | ||
| 516 | return; | ||
| 517 | rel_type = ICMPV6_TIME_EXCEED; | ||
| 518 | rel_code = ICMPV6_EXC_HOPLIMIT; | ||
| 519 | break; | ||
| 520 | } | ||
| 521 | |||
| 522 | /* Prepare fake skb to feed it to icmpv6_send */ | ||
| 523 | skb2 = skb_clone(skb, GFP_ATOMIC); | ||
| 524 | if (skb2 == NULL) | ||
| 525 | return 0; | ||
| 526 | dst_release(skb2->dst); | ||
| 527 | skb2->dst = NULL; | ||
| 528 | skb_pull(skb2, skb->data - (u8*)iph6); | ||
| 529 | skb_reset_network_header(skb2); | ||
| 530 | |||
| 531 | /* Try to guess incoming interface */ | ||
| 532 | rt6i = rt6_lookup(dev_net(skb->dev), &iph6->saddr, NULL, NULL, 0); | ||
| 533 | if (rt6i && rt6i->rt6i_dev) { | ||
| 534 | skb2->dev = rt6i->rt6i_dev; | ||
| 535 | |||
| 536 | rt6i = rt6_lookup(dev_net(skb->dev), | ||
| 537 | &iph6->daddr, &iph6->saddr, NULL, 0); | ||
| 538 | |||
| 539 | if (rt6i && rt6i->rt6i_dev && rt6i->rt6i_dev->type == ARPHRD_SIT) { | ||
| 540 | struct ip_tunnel *t = netdev_priv(rt6i->rt6i_dev); | ||
| 541 | if (rel_type == ICMPV6_TIME_EXCEED && t->parms.iph.ttl) { | ||
| 542 | rel_type = ICMPV6_DEST_UNREACH; | ||
| 543 | rel_code = ICMPV6_ADDR_UNREACH; | ||
| 544 | } | ||
| 545 | icmpv6_send(skb2, rel_type, rel_code, rel_info, skb2->dev); | ||
| 546 | } | ||
| 547 | } | ||
| 548 | kfree_skb(skb2); | ||
| 549 | return 0; | ||
| 550 | #endif | ||
| 551 | } | 466 | } |
| 552 | 467 | ||
| 553 | static inline void ipip6_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb) | 468 | static inline void ipip6_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb) |
| @@ -960,11 +875,20 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) | |||
| 960 | break; | 875 | break; |
| 961 | 876 | ||
| 962 | case SIOCGETPRL: | 877 | case SIOCGETPRL: |
| 878 | err = -EINVAL; | ||
| 879 | if (dev == sitn->fb_tunnel_dev) | ||
| 880 | goto done; | ||
| 881 | err = -ENOENT; | ||
| 882 | if (!(t = netdev_priv(dev))) | ||
| 883 | goto done; | ||
| 884 | err = ipip6_tunnel_get_prl(t, ifr->ifr_ifru.ifru_data); | ||
| 885 | break; | ||
| 886 | |||
| 963 | case SIOCADDPRL: | 887 | case SIOCADDPRL: |
| 964 | case SIOCDELPRL: | 888 | case SIOCDELPRL: |
| 965 | case SIOCCHGPRL: | 889 | case SIOCCHGPRL: |
| 966 | err = -EPERM; | 890 | err = -EPERM; |
| 967 | if (cmd != SIOCGETPRL && !capable(CAP_NET_ADMIN)) | 891 | if (!capable(CAP_NET_ADMIN)) |
| 968 | goto done; | 892 | goto done; |
| 969 | err = -EINVAL; | 893 | err = -EINVAL; |
| 970 | if (dev == sitn->fb_tunnel_dev) | 894 | if (dev == sitn->fb_tunnel_dev) |
| @@ -977,12 +901,6 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) | |||
| 977 | goto done; | 901 | goto done; |
| 978 | 902 | ||
| 979 | switch (cmd) { | 903 | switch (cmd) { |
| 980 | case SIOCGETPRL: | ||
| 981 | err = ipip6_tunnel_get_prl(t, &prl); | ||
| 982 | if (!err && copy_to_user(ifr->ifr_ifru.ifru_data, | ||
| 983 | &prl, sizeof(prl))) | ||
| 984 | err = -EFAULT; | ||
| 985 | break; | ||
| 986 | case SIOCDELPRL: | 904 | case SIOCDELPRL: |
| 987 | err = ipip6_tunnel_del_prl(t, &prl); | 905 | err = ipip6_tunnel_del_prl(t, &prl); |
| 988 | break; | 906 | break; |
| @@ -991,8 +909,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) | |||
| 991 | err = ipip6_tunnel_add_prl(t, &prl, cmd == SIOCCHGPRL); | 909 | err = ipip6_tunnel_add_prl(t, &prl, cmd == SIOCCHGPRL); |
| 992 | break; | 910 | break; |
| 993 | } | 911 | } |
| 994 | if (cmd != SIOCGETPRL) | 912 | netdev_state_change(dev); |
| 995 | netdev_state_change(dev); | ||
| 996 | break; | 913 | break; |
| 997 | 914 | ||
| 998 | default: | 915 | default: |
