diff options
Diffstat (limited to 'net/ipv6')
54 files changed, 2755 insertions, 1903 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 324fac3b6c16..498b927f68be 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -98,7 +98,11 @@ | |||
98 | #endif | 98 | #endif |
99 | 99 | ||
100 | #define INFINITY_LIFE_TIME 0xFFFFFFFF | 100 | #define INFINITY_LIFE_TIME 0xFFFFFFFF |
101 | #define TIME_DELTA(a, b) ((unsigned long)((long)(a) - (long)(b))) | 101 | |
102 | static inline u32 cstamp_delta(unsigned long cstamp) | ||
103 | { | ||
104 | return (cstamp - INITIAL_JIFFIES) * 100UL / HZ; | ||
105 | } | ||
102 | 106 | ||
103 | #define ADDRCONF_TIMER_FUZZ_MINUS (HZ > 50 ? HZ/50 : 1) | 107 | #define ADDRCONF_TIMER_FUZZ_MINUS (HZ > 50 ? HZ/50 : 1) |
104 | #define ADDRCONF_TIMER_FUZZ (HZ / 4) | 108 | #define ADDRCONF_TIMER_FUZZ (HZ / 4) |
@@ -243,7 +247,7 @@ static inline bool addrconf_qdisc_ok(const struct net_device *dev) | |||
243 | /* Check if a route is valid prefix route */ | 247 | /* Check if a route is valid prefix route */ |
244 | static inline int addrconf_is_prefix_route(const struct rt6_info *rt) | 248 | static inline int addrconf_is_prefix_route(const struct rt6_info *rt) |
245 | { | 249 | { |
246 | return ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0); | 250 | return (rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0; |
247 | } | 251 | } |
248 | 252 | ||
249 | static void addrconf_del_timer(struct inet6_ifaddr *ifp) | 253 | static void addrconf_del_timer(struct inet6_ifaddr *ifp) |
@@ -285,19 +289,19 @@ static int snmp6_alloc_dev(struct inet6_dev *idev) | |||
285 | sizeof(struct ipstats_mib), | 289 | sizeof(struct ipstats_mib), |
286 | __alignof__(struct ipstats_mib)) < 0) | 290 | __alignof__(struct ipstats_mib)) < 0) |
287 | goto err_ip; | 291 | goto err_ip; |
288 | if (snmp_mib_init((void __percpu **)idev->stats.icmpv6, | 292 | idev->stats.icmpv6dev = kzalloc(sizeof(struct icmpv6_mib_device), |
289 | sizeof(struct icmpv6_mib), | 293 | GFP_KERNEL); |
290 | __alignof__(struct icmpv6_mib)) < 0) | 294 | if (!idev->stats.icmpv6dev) |
291 | goto err_icmp; | 295 | goto err_icmp; |
292 | if (snmp_mib_init((void __percpu **)idev->stats.icmpv6msg, | 296 | idev->stats.icmpv6msgdev = kzalloc(sizeof(struct icmpv6msg_mib_device), |
293 | sizeof(struct icmpv6msg_mib), | 297 | GFP_KERNEL); |
294 | __alignof__(struct icmpv6msg_mib)) < 0) | 298 | if (!idev->stats.icmpv6msgdev) |
295 | goto err_icmpmsg; | 299 | goto err_icmpmsg; |
296 | 300 | ||
297 | return 0; | 301 | return 0; |
298 | 302 | ||
299 | err_icmpmsg: | 303 | err_icmpmsg: |
300 | snmp_mib_free((void __percpu **)idev->stats.icmpv6); | 304 | kfree(idev->stats.icmpv6dev); |
301 | err_icmp: | 305 | err_icmp: |
302 | snmp_mib_free((void __percpu **)idev->stats.ipv6); | 306 | snmp_mib_free((void __percpu **)idev->stats.ipv6); |
303 | err_ip: | 307 | err_ip: |
@@ -306,19 +310,13 @@ err_ip: | |||
306 | 310 | ||
307 | static void snmp6_free_dev(struct inet6_dev *idev) | 311 | static void snmp6_free_dev(struct inet6_dev *idev) |
308 | { | 312 | { |
309 | snmp_mib_free((void __percpu **)idev->stats.icmpv6msg); | 313 | kfree(idev->stats.icmpv6msgdev); |
310 | snmp_mib_free((void __percpu **)idev->stats.icmpv6); | 314 | kfree(idev->stats.icmpv6dev); |
311 | snmp_mib_free((void __percpu **)idev->stats.ipv6); | 315 | snmp_mib_free((void __percpu **)idev->stats.ipv6); |
312 | } | 316 | } |
313 | 317 | ||
314 | /* Nobody refers to this device, we may destroy it. */ | 318 | /* Nobody refers to this device, we may destroy it. */ |
315 | 319 | ||
316 | static void in6_dev_finish_destroy_rcu(struct rcu_head *head) | ||
317 | { | ||
318 | struct inet6_dev *idev = container_of(head, struct inet6_dev, rcu); | ||
319 | kfree(idev); | ||
320 | } | ||
321 | |||
322 | void in6_dev_finish_destroy(struct inet6_dev *idev) | 320 | void in6_dev_finish_destroy(struct inet6_dev *idev) |
323 | { | 321 | { |
324 | struct net_device *dev = idev->dev; | 322 | struct net_device *dev = idev->dev; |
@@ -335,7 +333,7 @@ void in6_dev_finish_destroy(struct inet6_dev *idev) | |||
335 | return; | 333 | return; |
336 | } | 334 | } |
337 | snmp6_free_dev(idev); | 335 | snmp6_free_dev(idev); |
338 | call_rcu(&idev->rcu, in6_dev_finish_destroy_rcu); | 336 | kfree_rcu(idev, rcu); |
339 | } | 337 | } |
340 | 338 | ||
341 | EXPORT_SYMBOL(in6_dev_finish_destroy); | 339 | EXPORT_SYMBOL(in6_dev_finish_destroy); |
@@ -416,9 +414,6 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) | |||
416 | dev->type == ARPHRD_TUNNEL6 || | 414 | dev->type == ARPHRD_TUNNEL6 || |
417 | dev->type == ARPHRD_SIT || | 415 | dev->type == ARPHRD_SIT || |
418 | dev->type == ARPHRD_NONE) { | 416 | dev->type == ARPHRD_NONE) { |
419 | printk(KERN_INFO | ||
420 | "%s: Disabled Privacy Extensions\n", | ||
421 | dev->name); | ||
422 | ndev->cnf.use_tempaddr = -1; | 417 | ndev->cnf.use_tempaddr = -1; |
423 | } else { | 418 | } else { |
424 | in6_dev_hold(ndev); | 419 | in6_dev_hold(ndev); |
@@ -534,12 +529,6 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old) | |||
534 | } | 529 | } |
535 | #endif | 530 | #endif |
536 | 531 | ||
537 | static void inet6_ifa_finish_destroy_rcu(struct rcu_head *head) | ||
538 | { | ||
539 | struct inet6_ifaddr *ifp = container_of(head, struct inet6_ifaddr, rcu); | ||
540 | kfree(ifp); | ||
541 | } | ||
542 | |||
543 | /* Nobody refers to this ifaddr, destroy it */ | 532 | /* Nobody refers to this ifaddr, destroy it */ |
544 | void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp) | 533 | void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp) |
545 | { | 534 | { |
@@ -560,7 +549,7 @@ void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp) | |||
560 | } | 549 | } |
561 | dst_release(&ifp->rt->dst); | 550 | dst_release(&ifp->rt->dst); |
562 | 551 | ||
563 | call_rcu(&ifp->rcu, inet6_ifa_finish_destroy_rcu); | 552 | kfree_rcu(ifp, rcu); |
564 | } | 553 | } |
565 | 554 | ||
566 | static void | 555 | static void |
@@ -717,12 +706,9 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) | |||
717 | struct inet6_ifaddr *ifa, *ifn; | 706 | struct inet6_ifaddr *ifa, *ifn; |
718 | struct inet6_dev *idev = ifp->idev; | 707 | struct inet6_dev *idev = ifp->idev; |
719 | int state; | 708 | int state; |
720 | int hash; | ||
721 | int deleted = 0, onlink = 0; | 709 | int deleted = 0, onlink = 0; |
722 | unsigned long expires = jiffies; | 710 | unsigned long expires = jiffies; |
723 | 711 | ||
724 | hash = ipv6_addr_hash(&ifp->addr); | ||
725 | |||
726 | spin_lock_bh(&ifp->state_lock); | 712 | spin_lock_bh(&ifp->state_lock); |
727 | state = ifp->state; | 713 | state = ifp->state; |
728 | ifp->state = INET6_IFADDR_STATE_DEAD; | 714 | ifp->state = INET6_IFADDR_STATE_DEAD; |
@@ -827,6 +813,8 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) | |||
827 | dst_release(&rt->dst); | 813 | dst_release(&rt->dst); |
828 | } | 814 | } |
829 | 815 | ||
816 | /* clean up prefsrc entries */ | ||
817 | rt6_remove_prefsrc(ifp); | ||
830 | out: | 818 | out: |
831 | in6_ifa_put(ifp); | 819 | in6_ifa_put(ifp); |
832 | } | 820 | } |
@@ -836,7 +824,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i | |||
836 | { | 824 | { |
837 | struct inet6_dev *idev = ifp->idev; | 825 | struct inet6_dev *idev = ifp->idev; |
838 | struct in6_addr addr, *tmpaddr; | 826 | struct in6_addr addr, *tmpaddr; |
839 | unsigned long tmp_prefered_lft, tmp_valid_lft, tmp_cstamp, tmp_tstamp; | 827 | unsigned long tmp_prefered_lft, tmp_valid_lft, tmp_cstamp, tmp_tstamp, age; |
840 | unsigned long regen_advance; | 828 | unsigned long regen_advance; |
841 | int tmp_plen; | 829 | int tmp_plen; |
842 | int ret = 0; | 830 | int ret = 0; |
@@ -886,12 +874,13 @@ retry: | |||
886 | goto out; | 874 | goto out; |
887 | } | 875 | } |
888 | memcpy(&addr.s6_addr[8], idev->rndid, 8); | 876 | memcpy(&addr.s6_addr[8], idev->rndid, 8); |
877 | age = (jiffies - ifp->tstamp) / HZ; | ||
889 | tmp_valid_lft = min_t(__u32, | 878 | tmp_valid_lft = min_t(__u32, |
890 | ifp->valid_lft, | 879 | ifp->valid_lft, |
891 | idev->cnf.temp_valid_lft); | 880 | idev->cnf.temp_valid_lft + age); |
892 | tmp_prefered_lft = min_t(__u32, | 881 | tmp_prefered_lft = min_t(__u32, |
893 | ifp->prefered_lft, | 882 | ifp->prefered_lft, |
894 | idev->cnf.temp_prefered_lft - | 883 | idev->cnf.temp_prefered_lft + age - |
895 | idev->cnf.max_desync_factor); | 884 | idev->cnf.max_desync_factor); |
896 | tmp_plen = ifp->prefix_len; | 885 | tmp_plen = ifp->prefix_len; |
897 | max_addresses = idev->cnf.max_addresses; | 886 | max_addresses = idev->cnf.max_addresses; |
@@ -1085,7 +1074,7 @@ static int ipv6_get_saddr_eval(struct net *net, | |||
1085 | case IPV6_SADDR_RULE_PRIVACY: | 1074 | case IPV6_SADDR_RULE_PRIVACY: |
1086 | { | 1075 | { |
1087 | /* Rule 7: Prefer public address | 1076 | /* Rule 7: Prefer public address |
1088 | * Note: prefer temprary address if use_tempaddr >= 2 | 1077 | * Note: prefer temporary address if use_tempaddr >= 2 |
1089 | */ | 1078 | */ |
1090 | int preftmp = dst->prefs & (IPV6_PREFER_SRC_PUBLIC|IPV6_PREFER_SRC_TMP) ? | 1079 | int preftmp = dst->prefs & (IPV6_PREFER_SRC_PUBLIC|IPV6_PREFER_SRC_TMP) ? |
1091 | !!(dst->prefs & IPV6_PREFER_SRC_TMP) : | 1080 | !!(dst->prefs & IPV6_PREFER_SRC_TMP) : |
@@ -1282,7 +1271,7 @@ static int ipv6_count_addresses(struct inet6_dev *idev) | |||
1282 | return cnt; | 1271 | return cnt; |
1283 | } | 1272 | } |
1284 | 1273 | ||
1285 | int ipv6_chk_addr(struct net *net, struct in6_addr *addr, | 1274 | int ipv6_chk_addr(struct net *net, const struct in6_addr *addr, |
1286 | struct net_device *dev, int strict) | 1275 | struct net_device *dev, int strict) |
1287 | { | 1276 | { |
1288 | struct inet6_ifaddr *ifp; | 1277 | struct inet6_ifaddr *ifp; |
@@ -1325,7 +1314,7 @@ static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr, | |||
1325 | return false; | 1314 | return false; |
1326 | } | 1315 | } |
1327 | 1316 | ||
1328 | int ipv6_chk_prefix(struct in6_addr *addr, struct net_device *dev) | 1317 | int ipv6_chk_prefix(const struct in6_addr *addr, struct net_device *dev) |
1329 | { | 1318 | { |
1330 | struct inet6_dev *idev; | 1319 | struct inet6_dev *idev; |
1331 | struct inet6_ifaddr *ifa; | 1320 | struct inet6_ifaddr *ifa; |
@@ -1426,8 +1415,10 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp) | |||
1426 | { | 1415 | { |
1427 | struct inet6_dev *idev = ifp->idev; | 1416 | struct inet6_dev *idev = ifp->idev; |
1428 | 1417 | ||
1429 | if (addrconf_dad_end(ifp)) | 1418 | if (addrconf_dad_end(ifp)) { |
1419 | in6_ifa_put(ifp); | ||
1430 | return; | 1420 | return; |
1421 | } | ||
1431 | 1422 | ||
1432 | if (net_ratelimit()) | 1423 | if (net_ratelimit()) |
1433 | printk(KERN_INFO "%s: IPv6 duplicate address %pI6c detected!\n", | 1424 | printk(KERN_INFO "%s: IPv6 duplicate address %pI6c detected!\n", |
@@ -1454,7 +1445,7 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp) | |||
1454 | 1445 | ||
1455 | /* Join to solicited addr multicast group. */ | 1446 | /* Join to solicited addr multicast group. */ |
1456 | 1447 | ||
1457 | void addrconf_join_solict(struct net_device *dev, struct in6_addr *addr) | 1448 | void addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr) |
1458 | { | 1449 | { |
1459 | struct in6_addr maddr; | 1450 | struct in6_addr maddr; |
1460 | 1451 | ||
@@ -1465,7 +1456,7 @@ void addrconf_join_solict(struct net_device *dev, struct in6_addr *addr) | |||
1465 | ipv6_dev_mc_inc(dev, &maddr); | 1456 | ipv6_dev_mc_inc(dev, &maddr); |
1466 | } | 1457 | } |
1467 | 1458 | ||
1468 | void addrconf_leave_solict(struct inet6_dev *idev, struct in6_addr *addr) | 1459 | void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr) |
1469 | { | 1460 | { |
1470 | struct in6_addr maddr; | 1461 | struct in6_addr maddr; |
1471 | 1462 | ||
@@ -1544,7 +1535,7 @@ static int addrconf_ifid_infiniband(u8 *eui, struct net_device *dev) | |||
1544 | return 0; | 1535 | return 0; |
1545 | } | 1536 | } |
1546 | 1537 | ||
1547 | int __ipv6_isatap_ifid(u8 *eui, __be32 addr) | 1538 | static int __ipv6_isatap_ifid(u8 *eui, __be32 addr) |
1548 | { | 1539 | { |
1549 | if (addr == 0) | 1540 | if (addr == 0) |
1550 | return -1; | 1541 | return -1; |
@@ -1560,7 +1551,6 @@ int __ipv6_isatap_ifid(u8 *eui, __be32 addr) | |||
1560 | memcpy(eui + 4, &addr, 4); | 1551 | memcpy(eui + 4, &addr, 4); |
1561 | return 0; | 1552 | return 0; |
1562 | } | 1553 | } |
1563 | EXPORT_SYMBOL(__ipv6_isatap_ifid); | ||
1564 | 1554 | ||
1565 | static int addrconf_ifid_sit(u8 *eui, struct net_device *dev) | 1555 | static int addrconf_ifid_sit(u8 *eui, struct net_device *dev) |
1566 | { | 1556 | { |
@@ -1968,7 +1958,7 @@ ok: | |||
1968 | * to the stored lifetime since we'll | 1958 | * to the stored lifetime since we'll |
1969 | * be updating the timestamp below, | 1959 | * be updating the timestamp below, |
1970 | * else we'll set it back to the | 1960 | * else we'll set it back to the |
1971 | * minumum. | 1961 | * minimum. |
1972 | */ | 1962 | */ |
1973 | if (prefered_lft != ifp->prefered_lft) { | 1963 | if (prefered_lft != ifp->prefered_lft) { |
1974 | valid_lft = stored_lft; | 1964 | valid_lft = stored_lft; |
@@ -2022,10 +2012,11 @@ ok: | |||
2022 | ipv6_ifa_notify(0, ift); | 2012 | ipv6_ifa_notify(0, ift); |
2023 | } | 2013 | } |
2024 | 2014 | ||
2025 | if (create && in6_dev->cnf.use_tempaddr > 0) { | 2015 | if ((create || list_empty(&in6_dev->tempaddr_list)) && in6_dev->cnf.use_tempaddr > 0) { |
2026 | /* | 2016 | /* |
2027 | * When a new public address is created as described in [ADDRCONF], | 2017 | * When a new public address is created as described in [ADDRCONF], |
2028 | * also create a new temporary address. | 2018 | * also create a new temporary address. Also create a temporary |
2019 | * address if it's enabled but no temporary address currently exists. | ||
2029 | */ | 2020 | */ |
2030 | read_unlock_bh(&in6_dev->lock); | 2021 | read_unlock_bh(&in6_dev->lock); |
2031 | ipv6_create_tempaddr(ifp, NULL); | 2022 | ipv6_create_tempaddr(ifp, NULL); |
@@ -2110,7 +2101,7 @@ err_exit: | |||
2110 | /* | 2101 | /* |
2111 | * Manual configuration of address on an interface | 2102 | * Manual configuration of address on an interface |
2112 | */ | 2103 | */ |
2113 | static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx, | 2104 | static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *pfx, |
2114 | unsigned int plen, __u8 ifa_flags, __u32 prefered_lft, | 2105 | unsigned int plen, __u8 ifa_flags, __u32 prefered_lft, |
2115 | __u32 valid_lft) | 2106 | __u32 valid_lft) |
2116 | { | 2107 | { |
@@ -2184,7 +2175,7 @@ static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx, | |||
2184 | return PTR_ERR(ifp); | 2175 | return PTR_ERR(ifp); |
2185 | } | 2176 | } |
2186 | 2177 | ||
2187 | static int inet6_addr_del(struct net *net, int ifindex, struct in6_addr *pfx, | 2178 | static int inet6_addr_del(struct net *net, int ifindex, const struct in6_addr *pfx, |
2188 | unsigned int plen) | 2179 | unsigned int plen) |
2189 | { | 2180 | { |
2190 | struct inet6_ifaddr *ifp; | 2181 | struct inet6_ifaddr *ifp; |
@@ -2347,7 +2338,7 @@ static void init_loopback(struct net_device *dev) | |||
2347 | add_addr(idev, &in6addr_loopback, 128, IFA_HOST); | 2338 | add_addr(idev, &in6addr_loopback, 128, IFA_HOST); |
2348 | } | 2339 | } |
2349 | 2340 | ||
2350 | static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr) | 2341 | static void addrconf_add_linklocal(struct inet6_dev *idev, const struct in6_addr *addr) |
2351 | { | 2342 | { |
2352 | struct inet6_ifaddr * ifp; | 2343 | struct inet6_ifaddr * ifp; |
2353 | u32 addr_flags = IFA_F_PERMANENT; | 2344 | u32 addr_flags = IFA_F_PERMANENT; |
@@ -2657,8 +2648,7 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
2657 | struct net *net = dev_net(dev); | 2648 | struct net *net = dev_net(dev); |
2658 | struct inet6_dev *idev; | 2649 | struct inet6_dev *idev; |
2659 | struct inet6_ifaddr *ifa; | 2650 | struct inet6_ifaddr *ifa; |
2660 | LIST_HEAD(keep_list); | 2651 | int state, i; |
2661 | int state; | ||
2662 | 2652 | ||
2663 | ASSERT_RTNL(); | 2653 | ASSERT_RTNL(); |
2664 | 2654 | ||
@@ -2684,6 +2674,23 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
2684 | 2674 | ||
2685 | } | 2675 | } |
2686 | 2676 | ||
2677 | /* Step 2: clear hash table */ | ||
2678 | for (i = 0; i < IN6_ADDR_HSIZE; i++) { | ||
2679 | struct hlist_head *h = &inet6_addr_lst[i]; | ||
2680 | struct hlist_node *n; | ||
2681 | |||
2682 | spin_lock_bh(&addrconf_hash_lock); | ||
2683 | restart: | ||
2684 | hlist_for_each_entry_rcu(ifa, n, h, addr_lst) { | ||
2685 | if (ifa->idev == idev) { | ||
2686 | hlist_del_init_rcu(&ifa->addr_lst); | ||
2687 | addrconf_del_timer(ifa); | ||
2688 | goto restart; | ||
2689 | } | ||
2690 | } | ||
2691 | spin_unlock_bh(&addrconf_hash_lock); | ||
2692 | } | ||
2693 | |||
2687 | write_lock_bh(&idev->lock); | 2694 | write_lock_bh(&idev->lock); |
2688 | 2695 | ||
2689 | /* Step 2: clear flags for stateless addrconf */ | 2696 | /* Step 2: clear flags for stateless addrconf */ |
@@ -2717,61 +2724,24 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
2717 | struct inet6_ifaddr, if_list); | 2724 | struct inet6_ifaddr, if_list); |
2718 | addrconf_del_timer(ifa); | 2725 | addrconf_del_timer(ifa); |
2719 | 2726 | ||
2720 | /* If just doing link down, and address is permanent | 2727 | list_del(&ifa->if_list); |
2721 | and not link-local, then retain it. */ | ||
2722 | if (!how && | ||
2723 | (ifa->flags&IFA_F_PERMANENT) && | ||
2724 | !(ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) { | ||
2725 | list_move_tail(&ifa->if_list, &keep_list); | ||
2726 | |||
2727 | /* If not doing DAD on this address, just keep it. */ | ||
2728 | if ((dev->flags&(IFF_NOARP|IFF_LOOPBACK)) || | ||
2729 | idev->cnf.accept_dad <= 0 || | ||
2730 | (ifa->flags & IFA_F_NODAD)) | ||
2731 | continue; | ||
2732 | |||
2733 | /* If it was tentative already, no need to notify */ | ||
2734 | if (ifa->flags & IFA_F_TENTATIVE) | ||
2735 | continue; | ||
2736 | 2728 | ||
2737 | /* Flag it for later restoration when link comes up */ | 2729 | write_unlock_bh(&idev->lock); |
2738 | ifa->flags |= IFA_F_TENTATIVE; | ||
2739 | ifa->state = INET6_IFADDR_STATE_DAD; | ||
2740 | |||
2741 | write_unlock_bh(&idev->lock); | ||
2742 | |||
2743 | in6_ifa_hold(ifa); | ||
2744 | } else { | ||
2745 | list_del(&ifa->if_list); | ||
2746 | |||
2747 | /* clear hash table */ | ||
2748 | spin_lock_bh(&addrconf_hash_lock); | ||
2749 | hlist_del_init_rcu(&ifa->addr_lst); | ||
2750 | spin_unlock_bh(&addrconf_hash_lock); | ||
2751 | 2730 | ||
2752 | write_unlock_bh(&idev->lock); | 2731 | spin_lock_bh(&ifa->state_lock); |
2753 | spin_lock_bh(&ifa->state_lock); | 2732 | state = ifa->state; |
2754 | state = ifa->state; | 2733 | ifa->state = INET6_IFADDR_STATE_DEAD; |
2755 | ifa->state = INET6_IFADDR_STATE_DEAD; | 2734 | spin_unlock_bh(&ifa->state_lock); |
2756 | spin_unlock_bh(&ifa->state_lock); | ||
2757 | 2735 | ||
2758 | if (state == INET6_IFADDR_STATE_DEAD) | 2736 | if (state != INET6_IFADDR_STATE_DEAD) { |
2759 | goto put_ifa; | 2737 | __ipv6_ifa_notify(RTM_DELADDR, ifa); |
2738 | atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa); | ||
2760 | } | 2739 | } |
2761 | |||
2762 | __ipv6_ifa_notify(RTM_DELADDR, ifa); | ||
2763 | if (ifa->state == INET6_IFADDR_STATE_DEAD) | ||
2764 | atomic_notifier_call_chain(&inet6addr_chain, | ||
2765 | NETDEV_DOWN, ifa); | ||
2766 | |||
2767 | put_ifa: | ||
2768 | in6_ifa_put(ifa); | 2740 | in6_ifa_put(ifa); |
2769 | 2741 | ||
2770 | write_lock_bh(&idev->lock); | 2742 | write_lock_bh(&idev->lock); |
2771 | } | 2743 | } |
2772 | 2744 | ||
2773 | list_splice(&keep_list, &idev->addr_list); | ||
2774 | |||
2775 | write_unlock_bh(&idev->lock); | 2745 | write_unlock_bh(&idev->lock); |
2776 | 2746 | ||
2777 | /* Step 5: Discard multicast list */ | 2747 | /* Step 5: Discard multicast list */ |
@@ -2964,7 +2934,8 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp) | |||
2964 | start sending router solicitations. | 2934 | start sending router solicitations. |
2965 | */ | 2935 | */ |
2966 | 2936 | ||
2967 | if (ifp->idev->cnf.forwarding == 0 && | 2937 | if ((ifp->idev->cnf.forwarding == 0 || |
2938 | ifp->idev->cnf.forwarding == 2) && | ||
2968 | ifp->idev->cnf.rtr_solicits > 0 && | 2939 | ifp->idev->cnf.rtr_solicits > 0 && |
2969 | (dev->flags&IFF_LOOPBACK) == 0 && | 2940 | (dev->flags&IFF_LOOPBACK) == 0 && |
2970 | (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) { | 2941 | (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) { |
@@ -3138,7 +3109,7 @@ void if6_proc_exit(void) | |||
3138 | 3109 | ||
3139 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 3110 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) |
3140 | /* Check if address is a home address configured on any interface. */ | 3111 | /* Check if address is a home address configured on any interface. */ |
3141 | int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr) | 3112 | int ipv6_chk_home_addr(struct net *net, const struct in6_addr *addr) |
3142 | { | 3113 | { |
3143 | int ret = 0; | 3114 | int ret = 0; |
3144 | struct inet6_ifaddr *ifp = NULL; | 3115 | struct inet6_ifaddr *ifp = NULL; |
@@ -3448,10 +3419,8 @@ static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp, | |||
3448 | { | 3419 | { |
3449 | struct ifa_cacheinfo ci; | 3420 | struct ifa_cacheinfo ci; |
3450 | 3421 | ||
3451 | ci.cstamp = (u32)(TIME_DELTA(cstamp, INITIAL_JIFFIES) / HZ * 100 | 3422 | ci.cstamp = cstamp_delta(cstamp); |
3452 | + TIME_DELTA(cstamp, INITIAL_JIFFIES) % HZ * 100 / HZ); | 3423 | ci.tstamp = cstamp_delta(tstamp); |
3453 | ci.tstamp = (u32)(TIME_DELTA(tstamp, INITIAL_JIFFIES) / HZ * 100 | ||
3454 | + TIME_DELTA(tstamp, INITIAL_JIFFIES) % HZ * 100 / HZ); | ||
3455 | ci.ifa_prefered = preferred; | 3424 | ci.ifa_prefered = preferred; |
3456 | ci.ifa_valid = valid; | 3425 | ci.ifa_valid = valid; |
3457 | 3426 | ||
@@ -3802,8 +3771,10 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, | |||
3802 | array[DEVCONF_AUTOCONF] = cnf->autoconf; | 3771 | array[DEVCONF_AUTOCONF] = cnf->autoconf; |
3803 | array[DEVCONF_DAD_TRANSMITS] = cnf->dad_transmits; | 3772 | array[DEVCONF_DAD_TRANSMITS] = cnf->dad_transmits; |
3804 | array[DEVCONF_RTR_SOLICITS] = cnf->rtr_solicits; | 3773 | array[DEVCONF_RTR_SOLICITS] = cnf->rtr_solicits; |
3805 | array[DEVCONF_RTR_SOLICIT_INTERVAL] = cnf->rtr_solicit_interval; | 3774 | array[DEVCONF_RTR_SOLICIT_INTERVAL] = |
3806 | array[DEVCONF_RTR_SOLICIT_DELAY] = cnf->rtr_solicit_delay; | 3775 | jiffies_to_msecs(cnf->rtr_solicit_interval); |
3776 | array[DEVCONF_RTR_SOLICIT_DELAY] = | ||
3777 | jiffies_to_msecs(cnf->rtr_solicit_delay); | ||
3807 | array[DEVCONF_FORCE_MLD_VERSION] = cnf->force_mld_version; | 3778 | array[DEVCONF_FORCE_MLD_VERSION] = cnf->force_mld_version; |
3808 | #ifdef CONFIG_IPV6_PRIVACY | 3779 | #ifdef CONFIG_IPV6_PRIVACY |
3809 | array[DEVCONF_USE_TEMPADDR] = cnf->use_tempaddr; | 3780 | array[DEVCONF_USE_TEMPADDR] = cnf->use_tempaddr; |
@@ -3817,7 +3788,8 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, | |||
3817 | array[DEVCONF_ACCEPT_RA_PINFO] = cnf->accept_ra_pinfo; | 3788 | array[DEVCONF_ACCEPT_RA_PINFO] = cnf->accept_ra_pinfo; |
3818 | #ifdef CONFIG_IPV6_ROUTER_PREF | 3789 | #ifdef CONFIG_IPV6_ROUTER_PREF |
3819 | array[DEVCONF_ACCEPT_RA_RTR_PREF] = cnf->accept_ra_rtr_pref; | 3790 | array[DEVCONF_ACCEPT_RA_RTR_PREF] = cnf->accept_ra_rtr_pref; |
3820 | array[DEVCONF_RTR_PROBE_INTERVAL] = cnf->rtr_probe_interval; | 3791 | array[DEVCONF_RTR_PROBE_INTERVAL] = |
3792 | jiffies_to_msecs(cnf->rtr_probe_interval); | ||
3821 | #ifdef CONFIG_IPV6_ROUTE_INFO | 3793 | #ifdef CONFIG_IPV6_ROUTE_INFO |
3822 | array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = cnf->accept_ra_rt_info_max_plen; | 3794 | array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = cnf->accept_ra_rt_info_max_plen; |
3823 | #endif | 3795 | #endif |
@@ -3835,6 +3807,15 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, | |||
3835 | array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao; | 3807 | array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao; |
3836 | } | 3808 | } |
3837 | 3809 | ||
3810 | static inline size_t inet6_ifla6_size(void) | ||
3811 | { | ||
3812 | return nla_total_size(4) /* IFLA_INET6_FLAGS */ | ||
3813 | + nla_total_size(sizeof(struct ifla_cacheinfo)) | ||
3814 | + nla_total_size(DEVCONF_MAX * 4) /* IFLA_INET6_CONF */ | ||
3815 | + nla_total_size(IPSTATS_MIB_MAX * 8) /* IFLA_INET6_STATS */ | ||
3816 | + nla_total_size(ICMP6_MIB_MAX * 8); /* IFLA_INET6_ICMP6STATS */ | ||
3817 | } | ||
3818 | |||
3838 | static inline size_t inet6_if_nlmsg_size(void) | 3819 | static inline size_t inet6_if_nlmsg_size(void) |
3839 | { | 3820 | { |
3840 | return NLMSG_ALIGN(sizeof(struct ifinfomsg)) | 3821 | return NLMSG_ALIGN(sizeof(struct ifinfomsg)) |
@@ -3842,16 +3823,10 @@ static inline size_t inet6_if_nlmsg_size(void) | |||
3842 | + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */ | 3823 | + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */ |
3843 | + nla_total_size(4) /* IFLA_MTU */ | 3824 | + nla_total_size(4) /* IFLA_MTU */ |
3844 | + nla_total_size(4) /* IFLA_LINK */ | 3825 | + nla_total_size(4) /* IFLA_LINK */ |
3845 | + nla_total_size( /* IFLA_PROTINFO */ | 3826 | + nla_total_size(inet6_ifla6_size()); /* IFLA_PROTINFO */ |
3846 | nla_total_size(4) /* IFLA_INET6_FLAGS */ | ||
3847 | + nla_total_size(sizeof(struct ifla_cacheinfo)) | ||
3848 | + nla_total_size(DEVCONF_MAX * 4) /* IFLA_INET6_CONF */ | ||
3849 | + nla_total_size(IPSTATS_MIB_MAX * 8) /* IFLA_INET6_STATS */ | ||
3850 | + nla_total_size(ICMP6_MIB_MAX * 8) /* IFLA_INET6_ICMP6STATS */ | ||
3851 | ); | ||
3852 | } | 3827 | } |
3853 | 3828 | ||
3854 | static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib, | 3829 | static inline void __snmp6_fill_statsdev(u64 *stats, atomic_long_t *mib, |
3855 | int items, int bytes) | 3830 | int items, int bytes) |
3856 | { | 3831 | { |
3857 | int i; | 3832 | int i; |
@@ -3861,7 +3836,7 @@ static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib, | |||
3861 | /* Use put_unaligned() because stats may not be aligned for u64. */ | 3836 | /* Use put_unaligned() because stats may not be aligned for u64. */ |
3862 | put_unaligned(items, &stats[0]); | 3837 | put_unaligned(items, &stats[0]); |
3863 | for (i = 1; i < items; i++) | 3838 | for (i = 1; i < items; i++) |
3864 | put_unaligned(snmp_fold_field(mib, i), &stats[i]); | 3839 | put_unaligned(atomic_long_read(&mib[i]), &stats[i]); |
3865 | 3840 | ||
3866 | memset(&stats[items], 0, pad); | 3841 | memset(&stats[items], 0, pad); |
3867 | } | 3842 | } |
@@ -3890,20 +3865,75 @@ static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype, | |||
3890 | IPSTATS_MIB_MAX, bytes, offsetof(struct ipstats_mib, syncp)); | 3865 | IPSTATS_MIB_MAX, bytes, offsetof(struct ipstats_mib, syncp)); |
3891 | break; | 3866 | break; |
3892 | case IFLA_INET6_ICMP6STATS: | 3867 | case IFLA_INET6_ICMP6STATS: |
3893 | __snmp6_fill_stats(stats, (void __percpu **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes); | 3868 | __snmp6_fill_statsdev(stats, idev->stats.icmpv6dev->mibs, ICMP6_MIB_MAX, bytes); |
3894 | break; | 3869 | break; |
3895 | } | 3870 | } |
3896 | } | 3871 | } |
3897 | 3872 | ||
3873 | static int inet6_fill_ifla6_attrs(struct sk_buff *skb, struct inet6_dev *idev) | ||
3874 | { | ||
3875 | struct nlattr *nla; | ||
3876 | struct ifla_cacheinfo ci; | ||
3877 | |||
3878 | NLA_PUT_U32(skb, IFLA_INET6_FLAGS, idev->if_flags); | ||
3879 | |||
3880 | ci.max_reasm_len = IPV6_MAXPLEN; | ||
3881 | ci.tstamp = cstamp_delta(idev->tstamp); | ||
3882 | ci.reachable_time = jiffies_to_msecs(idev->nd_parms->reachable_time); | ||
3883 | ci.retrans_time = jiffies_to_msecs(idev->nd_parms->retrans_time); | ||
3884 | NLA_PUT(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci); | ||
3885 | |||
3886 | nla = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32)); | ||
3887 | if (nla == NULL) | ||
3888 | goto nla_put_failure; | ||
3889 | ipv6_store_devconf(&idev->cnf, nla_data(nla), nla_len(nla)); | ||
3890 | |||
3891 | /* XXX - MC not implemented */ | ||
3892 | |||
3893 | nla = nla_reserve(skb, IFLA_INET6_STATS, IPSTATS_MIB_MAX * sizeof(u64)); | ||
3894 | if (nla == NULL) | ||
3895 | goto nla_put_failure; | ||
3896 | snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_STATS, nla_len(nla)); | ||
3897 | |||
3898 | nla = nla_reserve(skb, IFLA_INET6_ICMP6STATS, ICMP6_MIB_MAX * sizeof(u64)); | ||
3899 | if (nla == NULL) | ||
3900 | goto nla_put_failure; | ||
3901 | snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_ICMP6STATS, nla_len(nla)); | ||
3902 | |||
3903 | return 0; | ||
3904 | |||
3905 | nla_put_failure: | ||
3906 | return -EMSGSIZE; | ||
3907 | } | ||
3908 | |||
3909 | static size_t inet6_get_link_af_size(const struct net_device *dev) | ||
3910 | { | ||
3911 | if (!__in6_dev_get(dev)) | ||
3912 | return 0; | ||
3913 | |||
3914 | return inet6_ifla6_size(); | ||
3915 | } | ||
3916 | |||
3917 | static int inet6_fill_link_af(struct sk_buff *skb, const struct net_device *dev) | ||
3918 | { | ||
3919 | struct inet6_dev *idev = __in6_dev_get(dev); | ||
3920 | |||
3921 | if (!idev) | ||
3922 | return -ENODATA; | ||
3923 | |||
3924 | if (inet6_fill_ifla6_attrs(skb, idev) < 0) | ||
3925 | return -EMSGSIZE; | ||
3926 | |||
3927 | return 0; | ||
3928 | } | ||
3929 | |||
3898 | static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, | 3930 | static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, |
3899 | u32 pid, u32 seq, int event, unsigned int flags) | 3931 | u32 pid, u32 seq, int event, unsigned int flags) |
3900 | { | 3932 | { |
3901 | struct net_device *dev = idev->dev; | 3933 | struct net_device *dev = idev->dev; |
3902 | struct nlattr *nla; | ||
3903 | struct ifinfomsg *hdr; | 3934 | struct ifinfomsg *hdr; |
3904 | struct nlmsghdr *nlh; | 3935 | struct nlmsghdr *nlh; |
3905 | void *protoinfo; | 3936 | void *protoinfo; |
3906 | struct ifla_cacheinfo ci; | ||
3907 | 3937 | ||
3908 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(*hdr), flags); | 3938 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(*hdr), flags); |
3909 | if (nlh == NULL) | 3939 | if (nlh == NULL) |
@@ -3930,31 +3960,8 @@ static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, | |||
3930 | if (protoinfo == NULL) | 3960 | if (protoinfo == NULL) |
3931 | goto nla_put_failure; | 3961 | goto nla_put_failure; |
3932 | 3962 | ||
3933 | NLA_PUT_U32(skb, IFLA_INET6_FLAGS, idev->if_flags); | 3963 | if (inet6_fill_ifla6_attrs(skb, idev) < 0) |
3934 | |||
3935 | ci.max_reasm_len = IPV6_MAXPLEN; | ||
3936 | ci.tstamp = (__u32)(TIME_DELTA(idev->tstamp, INITIAL_JIFFIES) / HZ * 100 | ||
3937 | + TIME_DELTA(idev->tstamp, INITIAL_JIFFIES) % HZ * 100 / HZ); | ||
3938 | ci.reachable_time = idev->nd_parms->reachable_time; | ||
3939 | ci.retrans_time = idev->nd_parms->retrans_time; | ||
3940 | NLA_PUT(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci); | ||
3941 | |||
3942 | nla = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32)); | ||
3943 | if (nla == NULL) | ||
3944 | goto nla_put_failure; | ||
3945 | ipv6_store_devconf(&idev->cnf, nla_data(nla), nla_len(nla)); | ||
3946 | |||
3947 | /* XXX - MC not implemented */ | ||
3948 | |||
3949 | nla = nla_reserve(skb, IFLA_INET6_STATS, IPSTATS_MIB_MAX * sizeof(u64)); | ||
3950 | if (nla == NULL) | ||
3951 | goto nla_put_failure; | ||
3952 | snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_STATS, nla_len(nla)); | ||
3953 | |||
3954 | nla = nla_reserve(skb, IFLA_INET6_ICMP6STATS, ICMP6_MIB_MAX * sizeof(u64)); | ||
3955 | if (nla == NULL) | ||
3956 | goto nla_put_failure; | 3964 | goto nla_put_failure; |
3957 | snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_ICMP6STATS, nla_len(nla)); | ||
3958 | 3965 | ||
3959 | nla_nest_end(skb, protoinfo); | 3966 | nla_nest_end(skb, protoinfo); |
3960 | return nlmsg_end(skb, nlh); | 3967 | return nlmsg_end(skb, nlh); |
@@ -4021,11 +4028,11 @@ void inet6_ifinfo_notify(int event, struct inet6_dev *idev) | |||
4021 | kfree_skb(skb); | 4028 | kfree_skb(skb); |
4022 | goto errout; | 4029 | goto errout; |
4023 | } | 4030 | } |
4024 | rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC); | 4031 | rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFINFO, NULL, GFP_ATOMIC); |
4025 | return; | 4032 | return; |
4026 | errout: | 4033 | errout: |
4027 | if (err < 0) | 4034 | if (err < 0) |
4028 | rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err); | 4035 | rtnl_set_sk_err(net, RTNLGRP_IPV6_IFINFO, err); |
4029 | } | 4036 | } |
4030 | 4037 | ||
4031 | static inline size_t inet6_prefix_nlmsg_size(void) | 4038 | static inline size_t inet6_prefix_nlmsg_size(void) |
@@ -4122,8 +4129,7 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) | |||
4122 | addrconf_leave_solict(ifp->idev, &ifp->addr); | 4129 | addrconf_leave_solict(ifp->idev, &ifp->addr); |
4123 | dst_hold(&ifp->rt->dst); | 4130 | dst_hold(&ifp->rt->dst); |
4124 | 4131 | ||
4125 | if (ifp->state == INET6_IFADDR_STATE_DEAD && | 4132 | if (ip6_del_rt(ifp->rt)) |
4126 | ip6_del_rt(ifp->rt)) | ||
4127 | dst_free(&ifp->rt->dst); | 4133 | dst_free(&ifp->rt->dst); |
4128 | break; | 4134 | break; |
4129 | } | 4135 | } |
@@ -4521,7 +4527,7 @@ static void __addrconf_sysctl_unregister(struct ipv6_devconf *p) | |||
4521 | 4527 | ||
4522 | t = p->sysctl; | 4528 | t = p->sysctl; |
4523 | p->sysctl = NULL; | 4529 | p->sysctl = NULL; |
4524 | unregister_sysctl_table(t->sysctl_header); | 4530 | unregister_net_sysctl_table(t->sysctl_header); |
4525 | kfree(t->dev_name); | 4531 | kfree(t->dev_name); |
4526 | kfree(t); | 4532 | kfree(t); |
4527 | } | 4533 | } |
@@ -4625,6 +4631,12 @@ int unregister_inet6addr_notifier(struct notifier_block *nb) | |||
4625 | } | 4631 | } |
4626 | EXPORT_SYMBOL(unregister_inet6addr_notifier); | 4632 | EXPORT_SYMBOL(unregister_inet6addr_notifier); |
4627 | 4633 | ||
4634 | static struct rtnl_af_ops inet6_ops = { | ||
4635 | .family = AF_INET6, | ||
4636 | .fill_link_af = inet6_fill_link_af, | ||
4637 | .get_link_af_size = inet6_get_link_af_size, | ||
4638 | }; | ||
4639 | |||
4628 | /* | 4640 | /* |
4629 | * Init / cleanup code | 4641 | * Init / cleanup code |
4630 | */ | 4642 | */ |
@@ -4676,6 +4688,10 @@ int __init addrconf_init(void) | |||
4676 | 4688 | ||
4677 | addrconf_verify(0); | 4689 | addrconf_verify(0); |
4678 | 4690 | ||
4691 | err = rtnl_af_register(&inet6_ops); | ||
4692 | if (err < 0) | ||
4693 | goto errout_af; | ||
4694 | |||
4679 | err = __rtnl_register(PF_INET6, RTM_GETLINK, NULL, inet6_dump_ifinfo); | 4695 | err = __rtnl_register(PF_INET6, RTM_GETLINK, NULL, inet6_dump_ifinfo); |
4680 | if (err < 0) | 4696 | if (err < 0) |
4681 | goto errout; | 4697 | goto errout; |
@@ -4691,6 +4707,8 @@ int __init addrconf_init(void) | |||
4691 | 4707 | ||
4692 | return 0; | 4708 | return 0; |
4693 | errout: | 4709 | errout: |
4710 | rtnl_af_unregister(&inet6_ops); | ||
4711 | errout_af: | ||
4694 | unregister_netdevice_notifier(&ipv6_dev_notf); | 4712 | unregister_netdevice_notifier(&ipv6_dev_notf); |
4695 | errlo: | 4713 | errlo: |
4696 | unregister_pernet_subsys(&addrconf_ops); | 4714 | unregister_pernet_subsys(&addrconf_ops); |
@@ -4711,6 +4729,8 @@ void addrconf_cleanup(void) | |||
4711 | 4729 | ||
4712 | rtnl_lock(); | 4730 | rtnl_lock(); |
4713 | 4731 | ||
4732 | __rtnl_af_unregister(&inet6_ops); | ||
4733 | |||
4714 | /* clean dev list */ | 4734 | /* clean dev list */ |
4715 | for_each_netdev(&init_net, dev) { | 4735 | for_each_netdev(&init_net, dev) { |
4716 | if (__in6_dev_get(dev) == NULL) | 4736 | if (__in6_dev_get(dev) == NULL) |
diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c index 8175f802651b..c8993e5a337c 100644 --- a/net/ipv6/addrlabel.c +++ b/net/ipv6/addrlabel.c | |||
@@ -518,10 +518,9 @@ static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb) | |||
518 | 518 | ||
519 | static inline int ip6addrlbl_msgsize(void) | 519 | static inline int ip6addrlbl_msgsize(void) |
520 | { | 520 | { |
521 | return (NLMSG_ALIGN(sizeof(struct ifaddrlblmsg)) | 521 | return NLMSG_ALIGN(sizeof(struct ifaddrlblmsg)) |
522 | + nla_total_size(16) /* IFAL_ADDRESS */ | 522 | + nla_total_size(16) /* IFAL_ADDRESS */ |
523 | + nla_total_size(4) /* IFAL_LABEL */ | 523 | + nla_total_size(4); /* IFAL_LABEL */ |
524 | ); | ||
525 | } | 524 | } |
526 | 525 | ||
527 | static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh, | 526 | static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh, |
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 56b9bf2516f4..3b5669a2582d 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
@@ -272,6 +272,10 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
272 | 272 | ||
273 | if (addr_len < SIN6_LEN_RFC2133) | 273 | if (addr_len < SIN6_LEN_RFC2133) |
274 | return -EINVAL; | 274 | return -EINVAL; |
275 | |||
276 | if (addr->sin6_family != AF_INET6) | ||
277 | return -EAFNOSUPPORT; | ||
278 | |||
275 | addr_type = ipv6_addr_type(&addr->sin6_addr); | 279 | addr_type = ipv6_addr_type(&addr->sin6_addr); |
276 | if ((addr_type & IPV6_ADDR_MULTICAST) && sock->type == SOCK_STREAM) | 280 | if ((addr_type & IPV6_ADDR_MULTICAST) && sock->type == SOCK_STREAM) |
277 | return -EINVAL; | 281 | return -EINVAL; |
@@ -300,7 +304,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
300 | goto out; | 304 | goto out; |
301 | } | 305 | } |
302 | 306 | ||
303 | /* Reproduce AF_INET checks to make the bindings consitant */ | 307 | /* Reproduce AF_INET checks to make the bindings consistent */ |
304 | v4addr = addr->sin6_addr.s6_addr32[3]; | 308 | v4addr = addr->sin6_addr.s6_addr32[3]; |
305 | chk_addr_ret = inet_addr_type(net, v4addr); | 309 | chk_addr_ret = inet_addr_type(net, v4addr); |
306 | if (!sysctl_ip_nonlocal_bind && | 310 | if (!sysctl_ip_nonlocal_bind && |
@@ -343,7 +347,8 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
343 | */ | 347 | */ |
344 | v4addr = LOOPBACK4_IPV6; | 348 | v4addr = LOOPBACK4_IPV6; |
345 | if (!(addr_type & IPV6_ADDR_MULTICAST)) { | 349 | if (!(addr_type & IPV6_ADDR_MULTICAST)) { |
346 | if (!ipv6_chk_addr(net, &addr->sin6_addr, | 350 | if (!inet->transparent && |
351 | !ipv6_chk_addr(net, &addr->sin6_addr, | ||
347 | dev, 0)) { | 352 | dev, 0)) { |
348 | err = -EADDRNOTAVAIL; | 353 | err = -EADDRNOTAVAIL; |
349 | goto out_unlock; | 354 | goto out_unlock; |
@@ -467,7 +472,7 @@ int inet6_getname(struct socket *sock, struct sockaddr *uaddr, | |||
467 | if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) | 472 | if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) |
468 | sin->sin6_scope_id = sk->sk_bound_dev_if; | 473 | sin->sin6_scope_id = sk->sk_bound_dev_if; |
469 | *uaddr_len = sizeof(*sin); | 474 | *uaddr_len = sizeof(*sin); |
470 | return(0); | 475 | return 0; |
471 | } | 476 | } |
472 | 477 | ||
473 | EXPORT_SYMBOL(inet6_getname); | 478 | EXPORT_SYMBOL(inet6_getname); |
@@ -488,7 +493,7 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
488 | case SIOCADDRT: | 493 | case SIOCADDRT: |
489 | case SIOCDELRT: | 494 | case SIOCDELRT: |
490 | 495 | ||
491 | return(ipv6_route_ioctl(net, cmd, (void __user *)arg)); | 496 | return ipv6_route_ioctl(net, cmd, (void __user *)arg); |
492 | 497 | ||
493 | case SIOCSIFADDR: | 498 | case SIOCSIFADDR: |
494 | return addrconf_add_ifaddr(net, (void __user *) arg); | 499 | return addrconf_add_ifaddr(net, (void __user *) arg); |
@@ -502,7 +507,7 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
502 | return sk->sk_prot->ioctl(sk, cmd, arg); | 507 | return sk->sk_prot->ioctl(sk, cmd, arg); |
503 | } | 508 | } |
504 | /*NOTREACHED*/ | 509 | /*NOTREACHED*/ |
505 | return(0); | 510 | return 0; |
506 | } | 511 | } |
507 | 512 | ||
508 | EXPORT_SYMBOL(inet6_ioctl); | 513 | EXPORT_SYMBOL(inet6_ioctl); |
@@ -643,41 +648,34 @@ EXPORT_SYMBOL(inet6_unregister_protosw); | |||
643 | 648 | ||
644 | int inet6_sk_rebuild_header(struct sock *sk) | 649 | int inet6_sk_rebuild_header(struct sock *sk) |
645 | { | 650 | { |
646 | int err; | ||
647 | struct dst_entry *dst; | ||
648 | struct ipv6_pinfo *np = inet6_sk(sk); | 651 | struct ipv6_pinfo *np = inet6_sk(sk); |
652 | struct dst_entry *dst; | ||
649 | 653 | ||
650 | dst = __sk_dst_check(sk, np->dst_cookie); | 654 | dst = __sk_dst_check(sk, np->dst_cookie); |
651 | 655 | ||
652 | if (dst == NULL) { | 656 | if (dst == NULL) { |
653 | struct inet_sock *inet = inet_sk(sk); | 657 | struct inet_sock *inet = inet_sk(sk); |
654 | struct in6_addr *final_p, final; | 658 | struct in6_addr *final_p, final; |
655 | struct flowi fl; | 659 | struct flowi6 fl6; |
656 | 660 | ||
657 | memset(&fl, 0, sizeof(fl)); | 661 | memset(&fl6, 0, sizeof(fl6)); |
658 | fl.proto = sk->sk_protocol; | 662 | fl6.flowi6_proto = sk->sk_protocol; |
659 | ipv6_addr_copy(&fl.fl6_dst, &np->daddr); | 663 | ipv6_addr_copy(&fl6.daddr, &np->daddr); |
660 | ipv6_addr_copy(&fl.fl6_src, &np->saddr); | 664 | ipv6_addr_copy(&fl6.saddr, &np->saddr); |
661 | fl.fl6_flowlabel = np->flow_label; | 665 | fl6.flowlabel = np->flow_label; |
662 | fl.oif = sk->sk_bound_dev_if; | 666 | fl6.flowi6_oif = sk->sk_bound_dev_if; |
663 | fl.mark = sk->sk_mark; | 667 | fl6.flowi6_mark = sk->sk_mark; |
664 | fl.fl_ip_dport = inet->inet_dport; | 668 | fl6.fl6_dport = inet->inet_dport; |
665 | fl.fl_ip_sport = inet->inet_sport; | 669 | fl6.fl6_sport = inet->inet_sport; |
666 | security_sk_classify_flow(sk, &fl); | 670 | security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); |
667 | 671 | ||
668 | final_p = fl6_update_dst(&fl, np->opt, &final); | 672 | final_p = fl6_update_dst(&fl6, np->opt, &final); |
669 | 673 | ||
670 | err = ip6_dst_lookup(sk, &dst, &fl); | 674 | dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false); |
671 | if (err) { | 675 | if (IS_ERR(dst)) { |
672 | sk->sk_route_caps = 0; | 676 | sk->sk_route_caps = 0; |
673 | return err; | 677 | sk->sk_err_soft = -PTR_ERR(dst); |
674 | } | 678 | return PTR_ERR(dst); |
675 | if (final_p) | ||
676 | ipv6_addr_copy(&fl.fl6_dst, final_p); | ||
677 | |||
678 | if ((err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0) { | ||
679 | sk->sk_err_soft = -err; | ||
680 | return err; | ||
681 | } | 679 | } |
682 | 680 | ||
683 | __ip6_dst_store(sk, dst, NULL, NULL); | 681 | __ip6_dst_store(sk, dst, NULL, NULL); |
@@ -746,7 +744,7 @@ static int ipv6_gso_pull_exthdrs(struct sk_buff *skb, int proto) | |||
746 | 744 | ||
747 | static int ipv6_gso_send_check(struct sk_buff *skb) | 745 | static int ipv6_gso_send_check(struct sk_buff *skb) |
748 | { | 746 | { |
749 | struct ipv6hdr *ipv6h; | 747 | const struct ipv6hdr *ipv6h; |
750 | const struct inet6_protocol *ops; | 748 | const struct inet6_protocol *ops; |
751 | int err = -EINVAL; | 749 | int err = -EINVAL; |
752 | 750 | ||
@@ -771,7 +769,7 @@ out: | |||
771 | return err; | 769 | return err; |
772 | } | 770 | } |
773 | 771 | ||
774 | static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features) | 772 | static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, u32 features) |
775 | { | 773 | { |
776 | struct sk_buff *segs = ERR_PTR(-EINVAL); | 774 | struct sk_buff *segs = ERR_PTR(-EINVAL); |
777 | struct ipv6hdr *ipv6h; | 775 | struct ipv6hdr *ipv6h; |
@@ -809,7 +807,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features) | |||
809 | } | 807 | } |
810 | rcu_read_unlock(); | 808 | rcu_read_unlock(); |
811 | 809 | ||
812 | if (unlikely(IS_ERR(segs))) | 810 | if (IS_ERR(segs)) |
813 | goto out; | 811 | goto out; |
814 | 812 | ||
815 | for (skb = segs; skb; skb = skb->next) { | 813 | for (skb = segs; skb; skb = skb->next) { |
@@ -1119,7 +1117,7 @@ static int __init inet6_init(void) | |||
1119 | /* | 1117 | /* |
1120 | * ipngwg API draft makes clear that the correct semantics | 1118 | * ipngwg API draft makes clear that the correct semantics |
1121 | * for TCP and UDP is to consider one TCP and UDP instance | 1119 | * for TCP and UDP is to consider one TCP and UDP instance |
1122 | * in a host availiable by both INET and INET6 APIs and | 1120 | * in a host available by both INET and INET6 APIs and |
1123 | * able to communicate via both network protocols. | 1121 | * able to communicate via both network protocols. |
1124 | */ | 1122 | */ |
1125 | 1123 | ||
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index ee82d4ef26ce..2195ae651923 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c | |||
@@ -409,7 +409,7 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
409 | 409 | ||
410 | ah->reserved = 0; | 410 | ah->reserved = 0; |
411 | ah->spi = x->id.spi; | 411 | ah->spi = x->id.spi; |
412 | ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output); | 412 | ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.low); |
413 | 413 | ||
414 | sg_init_table(sg, nfrags); | 414 | sg_init_table(sg, nfrags); |
415 | skb_to_sgvec(skb, sg, 0, skb->len); | 415 | skb_to_sgvec(skb, sg, 0, skb->len); |
@@ -538,14 +538,16 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
538 | if (!pskb_may_pull(skb, ah_hlen)) | 538 | if (!pskb_may_pull(skb, ah_hlen)) |
539 | goto out; | 539 | goto out; |
540 | 540 | ||
541 | ip6h = ipv6_hdr(skb); | ||
542 | |||
543 | skb_push(skb, hdr_len); | ||
544 | 541 | ||
545 | if ((err = skb_cow_data(skb, 0, &trailer)) < 0) | 542 | if ((err = skb_cow_data(skb, 0, &trailer)) < 0) |
546 | goto out; | 543 | goto out; |
547 | nfrags = err; | 544 | nfrags = err; |
548 | 545 | ||
546 | ah = (struct ip_auth_hdr *)skb->data; | ||
547 | ip6h = ipv6_hdr(skb); | ||
548 | |||
549 | skb_push(skb, hdr_len); | ||
550 | |||
549 | work_iph = ah_alloc_tmp(ahash, nfrags, hdr_len + ahp->icv_trunc_len); | 551 | work_iph = ah_alloc_tmp(ahash, nfrags, hdr_len + ahp->icv_trunc_len); |
550 | if (!work_iph) | 552 | if (!work_iph) |
551 | goto out; | 553 | goto out; |
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index 0e5e943446f0..674255f5e6b7 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c | |||
@@ -44,7 +44,7 @@ | |||
44 | 44 | ||
45 | #include <net/checksum.h> | 45 | #include <net/checksum.h> |
46 | 46 | ||
47 | static int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr); | 47 | static int ipv6_dev_ac_dec(struct net_device *dev, const struct in6_addr *addr); |
48 | 48 | ||
49 | /* Big ac list lock for all the sockets */ | 49 | /* Big ac list lock for all the sockets */ |
50 | static DEFINE_RWLOCK(ipv6_sk_ac_lock); | 50 | static DEFINE_RWLOCK(ipv6_sk_ac_lock); |
@@ -54,7 +54,7 @@ static DEFINE_RWLOCK(ipv6_sk_ac_lock); | |||
54 | * socket join an anycast group | 54 | * socket join an anycast group |
55 | */ | 55 | */ |
56 | 56 | ||
57 | int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr) | 57 | int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr) |
58 | { | 58 | { |
59 | struct ipv6_pinfo *np = inet6_sk(sk); | 59 | struct ipv6_pinfo *np = inet6_sk(sk); |
60 | struct net_device *dev = NULL; | 60 | struct net_device *dev = NULL; |
@@ -145,7 +145,7 @@ error: | |||
145 | /* | 145 | /* |
146 | * socket leave an anycast group | 146 | * socket leave an anycast group |
147 | */ | 147 | */ |
148 | int ipv6_sock_ac_drop(struct sock *sk, int ifindex, struct in6_addr *addr) | 148 | int ipv6_sock_ac_drop(struct sock *sk, int ifindex, const struct in6_addr *addr) |
149 | { | 149 | { |
150 | struct ipv6_pinfo *np = inet6_sk(sk); | 150 | struct ipv6_pinfo *np = inet6_sk(sk); |
151 | struct net_device *dev; | 151 | struct net_device *dev; |
@@ -252,7 +252,7 @@ static void aca_put(struct ifacaddr6 *ac) | |||
252 | /* | 252 | /* |
253 | * device anycast group inc (add if not found) | 253 | * device anycast group inc (add if not found) |
254 | */ | 254 | */ |
255 | int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr) | 255 | int ipv6_dev_ac_inc(struct net_device *dev, const struct in6_addr *addr) |
256 | { | 256 | { |
257 | struct ifacaddr6 *aca; | 257 | struct ifacaddr6 *aca; |
258 | struct inet6_dev *idev; | 258 | struct inet6_dev *idev; |
@@ -324,7 +324,7 @@ out: | |||
324 | /* | 324 | /* |
325 | * device anycast group decrement | 325 | * device anycast group decrement |
326 | */ | 326 | */ |
327 | int __ipv6_dev_ac_dec(struct inet6_dev *idev, struct in6_addr *addr) | 327 | int __ipv6_dev_ac_dec(struct inet6_dev *idev, const struct in6_addr *addr) |
328 | { | 328 | { |
329 | struct ifacaddr6 *aca, *prev_aca; | 329 | struct ifacaddr6 *aca, *prev_aca; |
330 | 330 | ||
@@ -358,7 +358,7 @@ int __ipv6_dev_ac_dec(struct inet6_dev *idev, struct in6_addr *addr) | |||
358 | } | 358 | } |
359 | 359 | ||
360 | /* called with rcu_read_lock() */ | 360 | /* called with rcu_read_lock() */ |
361 | static int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr) | 361 | static int ipv6_dev_ac_dec(struct net_device *dev, const struct in6_addr *addr) |
362 | { | 362 | { |
363 | struct inet6_dev *idev = __in6_dev_get(dev); | 363 | struct inet6_dev *idev = __in6_dev_get(dev); |
364 | 364 | ||
@@ -371,7 +371,7 @@ static int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr) | |||
371 | * check if the interface has this anycast address | 371 | * check if the interface has this anycast address |
372 | * called with rcu_read_lock() | 372 | * called with rcu_read_lock() |
373 | */ | 373 | */ |
374 | static int ipv6_chk_acast_dev(struct net_device *dev, struct in6_addr *addr) | 374 | static int ipv6_chk_acast_dev(struct net_device *dev, const struct in6_addr *addr) |
375 | { | 375 | { |
376 | struct inet6_dev *idev; | 376 | struct inet6_dev *idev; |
377 | struct ifacaddr6 *aca; | 377 | struct ifacaddr6 *aca; |
@@ -392,7 +392,7 @@ static int ipv6_chk_acast_dev(struct net_device *dev, struct in6_addr *addr) | |||
392 | * check if given interface (or any, if dev==0) has this anycast address | 392 | * check if given interface (or any, if dev==0) has this anycast address |
393 | */ | 393 | */ |
394 | int ipv6_chk_acast_addr(struct net *net, struct net_device *dev, | 394 | int ipv6_chk_acast_addr(struct net *net, struct net_device *dev, |
395 | struct in6_addr *addr) | 395 | const struct in6_addr *addr) |
396 | { | 396 | { |
397 | int found = 0; | 397 | int found = 0; |
398 | 398 | ||
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index ef371aa01ac5..16560336eb72 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c | |||
@@ -40,7 +40,7 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | |||
40 | struct ipv6_pinfo *np = inet6_sk(sk); | 40 | struct ipv6_pinfo *np = inet6_sk(sk); |
41 | struct in6_addr *daddr, *final_p, final; | 41 | struct in6_addr *daddr, *final_p, final; |
42 | struct dst_entry *dst; | 42 | struct dst_entry *dst; |
43 | struct flowi fl; | 43 | struct flowi6 fl6; |
44 | struct ip6_flowlabel *flowlabel = NULL; | 44 | struct ip6_flowlabel *flowlabel = NULL; |
45 | struct ipv6_txoptions *opt; | 45 | struct ipv6_txoptions *opt; |
46 | int addr_type; | 46 | int addr_type; |
@@ -59,11 +59,11 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | |||
59 | if (usin->sin6_family != AF_INET6) | 59 | if (usin->sin6_family != AF_INET6) |
60 | return -EAFNOSUPPORT; | 60 | return -EAFNOSUPPORT; |
61 | 61 | ||
62 | memset(&fl, 0, sizeof(fl)); | 62 | memset(&fl6, 0, sizeof(fl6)); |
63 | if (np->sndflow) { | 63 | if (np->sndflow) { |
64 | fl.fl6_flowlabel = usin->sin6_flowinfo&IPV6_FLOWINFO_MASK; | 64 | fl6.flowlabel = usin->sin6_flowinfo&IPV6_FLOWINFO_MASK; |
65 | if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) { | 65 | if (fl6.flowlabel&IPV6_FLOWLABEL_MASK) { |
66 | flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel); | 66 | flowlabel = fl6_sock_lookup(sk, fl6.flowlabel); |
67 | if (flowlabel == NULL) | 67 | if (flowlabel == NULL) |
68 | return -EINVAL; | 68 | return -EINVAL; |
69 | ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst); | 69 | ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst); |
@@ -137,7 +137,7 @@ ipv4_connected: | |||
137 | } | 137 | } |
138 | 138 | ||
139 | ipv6_addr_copy(&np->daddr, daddr); | 139 | ipv6_addr_copy(&np->daddr, daddr); |
140 | np->flow_label = fl.fl6_flowlabel; | 140 | np->flow_label = fl6.flowlabel; |
141 | 141 | ||
142 | inet->inet_dport = usin->sin6_port; | 142 | inet->inet_dport = usin->sin6_port; |
143 | 143 | ||
@@ -146,53 +146,46 @@ ipv4_connected: | |||
146 | * destination cache for it. | 146 | * destination cache for it. |
147 | */ | 147 | */ |
148 | 148 | ||
149 | fl.proto = sk->sk_protocol; | 149 | fl6.flowi6_proto = sk->sk_protocol; |
150 | ipv6_addr_copy(&fl.fl6_dst, &np->daddr); | 150 | ipv6_addr_copy(&fl6.daddr, &np->daddr); |
151 | ipv6_addr_copy(&fl.fl6_src, &np->saddr); | 151 | ipv6_addr_copy(&fl6.saddr, &np->saddr); |
152 | fl.oif = sk->sk_bound_dev_if; | 152 | fl6.flowi6_oif = sk->sk_bound_dev_if; |
153 | fl.mark = sk->sk_mark; | 153 | fl6.flowi6_mark = sk->sk_mark; |
154 | fl.fl_ip_dport = inet->inet_dport; | 154 | fl6.fl6_dport = inet->inet_dport; |
155 | fl.fl_ip_sport = inet->inet_sport; | 155 | fl6.fl6_sport = inet->inet_sport; |
156 | 156 | ||
157 | if (!fl.oif && (addr_type&IPV6_ADDR_MULTICAST)) | 157 | if (!fl6.flowi6_oif && (addr_type&IPV6_ADDR_MULTICAST)) |
158 | fl.oif = np->mcast_oif; | 158 | fl6.flowi6_oif = np->mcast_oif; |
159 | 159 | ||
160 | security_sk_classify_flow(sk, &fl); | 160 | security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); |
161 | 161 | ||
162 | opt = flowlabel ? flowlabel->opt : np->opt; | 162 | opt = flowlabel ? flowlabel->opt : np->opt; |
163 | final_p = fl6_update_dst(&fl, opt, &final); | 163 | final_p = fl6_update_dst(&fl6, opt, &final); |
164 | 164 | ||
165 | err = ip6_dst_lookup(sk, &dst, &fl); | 165 | dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true); |
166 | if (err) | 166 | err = 0; |
167 | if (IS_ERR(dst)) { | ||
168 | err = PTR_ERR(dst); | ||
167 | goto out; | 169 | goto out; |
168 | if (final_p) | ||
169 | ipv6_addr_copy(&fl.fl6_dst, final_p); | ||
170 | |||
171 | err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT); | ||
172 | if (err < 0) { | ||
173 | if (err == -EREMOTE) | ||
174 | err = ip6_dst_blackhole(sk, &dst, &fl); | ||
175 | if (err < 0) | ||
176 | goto out; | ||
177 | } | 170 | } |
178 | 171 | ||
179 | /* source address lookup done in ip6_dst_lookup */ | 172 | /* source address lookup done in ip6_dst_lookup */ |
180 | 173 | ||
181 | if (ipv6_addr_any(&np->saddr)) | 174 | if (ipv6_addr_any(&np->saddr)) |
182 | ipv6_addr_copy(&np->saddr, &fl.fl6_src); | 175 | ipv6_addr_copy(&np->saddr, &fl6.saddr); |
183 | 176 | ||
184 | if (ipv6_addr_any(&np->rcv_saddr)) { | 177 | if (ipv6_addr_any(&np->rcv_saddr)) { |
185 | ipv6_addr_copy(&np->rcv_saddr, &fl.fl6_src); | 178 | ipv6_addr_copy(&np->rcv_saddr, &fl6.saddr); |
186 | inet->inet_rcv_saddr = LOOPBACK4_IPV6; | 179 | inet->inet_rcv_saddr = LOOPBACK4_IPV6; |
187 | if (sk->sk_prot->rehash) | 180 | if (sk->sk_prot->rehash) |
188 | sk->sk_prot->rehash(sk); | 181 | sk->sk_prot->rehash(sk); |
189 | } | 182 | } |
190 | 183 | ||
191 | ip6_dst_store(sk, dst, | 184 | ip6_dst_store(sk, dst, |
192 | ipv6_addr_equal(&fl.fl6_dst, &np->daddr) ? | 185 | ipv6_addr_equal(&fl6.daddr, &np->daddr) ? |
193 | &np->daddr : NULL, | 186 | &np->daddr : NULL, |
194 | #ifdef CONFIG_IPV6_SUBTREES | 187 | #ifdef CONFIG_IPV6_SUBTREES |
195 | ipv6_addr_equal(&fl.fl6_src, &np->saddr) ? | 188 | ipv6_addr_equal(&fl6.saddr, &np->saddr) ? |
196 | &np->saddr : | 189 | &np->saddr : |
197 | #endif | 190 | #endif |
198 | NULL); | 191 | NULL); |
@@ -238,7 +231,7 @@ void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, | |||
238 | kfree_skb(skb); | 231 | kfree_skb(skb); |
239 | } | 232 | } |
240 | 233 | ||
241 | void ipv6_local_error(struct sock *sk, int err, struct flowi *fl, u32 info) | 234 | void ipv6_local_error(struct sock *sk, int err, struct flowi6 *fl6, u32 info) |
242 | { | 235 | { |
243 | struct ipv6_pinfo *np = inet6_sk(sk); | 236 | struct ipv6_pinfo *np = inet6_sk(sk); |
244 | struct sock_exterr_skb *serr; | 237 | struct sock_exterr_skb *serr; |
@@ -257,7 +250,7 @@ void ipv6_local_error(struct sock *sk, int err, struct flowi *fl, u32 info) | |||
257 | skb_put(skb, sizeof(struct ipv6hdr)); | 250 | skb_put(skb, sizeof(struct ipv6hdr)); |
258 | skb_reset_network_header(skb); | 251 | skb_reset_network_header(skb); |
259 | iph = ipv6_hdr(skb); | 252 | iph = ipv6_hdr(skb); |
260 | ipv6_addr_copy(&iph->daddr, &fl->fl6_dst); | 253 | ipv6_addr_copy(&iph->daddr, &fl6->daddr); |
261 | 254 | ||
262 | serr = SKB_EXT_ERR(skb); | 255 | serr = SKB_EXT_ERR(skb); |
263 | serr->ee.ee_errno = err; | 256 | serr->ee.ee_errno = err; |
@@ -268,7 +261,7 @@ void ipv6_local_error(struct sock *sk, int err, struct flowi *fl, u32 info) | |||
268 | serr->ee.ee_info = info; | 261 | serr->ee.ee_info = info; |
269 | serr->ee.ee_data = 0; | 262 | serr->ee.ee_data = 0; |
270 | serr->addr_offset = (u8 *)&iph->daddr - skb_network_header(skb); | 263 | serr->addr_offset = (u8 *)&iph->daddr - skb_network_header(skb); |
271 | serr->port = fl->fl_ip_dport; | 264 | serr->port = fl6->fl6_dport; |
272 | 265 | ||
273 | __skb_pull(skb, skb_tail_pointer(skb) - skb->data); | 266 | __skb_pull(skb, skb_tail_pointer(skb) - skb->data); |
274 | skb_reset_transport_header(skb); | 267 | skb_reset_transport_header(skb); |
@@ -277,7 +270,7 @@ void ipv6_local_error(struct sock *sk, int err, struct flowi *fl, u32 info) | |||
277 | kfree_skb(skb); | 270 | kfree_skb(skb); |
278 | } | 271 | } |
279 | 272 | ||
280 | void ipv6_local_rxpmtu(struct sock *sk, struct flowi *fl, u32 mtu) | 273 | void ipv6_local_rxpmtu(struct sock *sk, struct flowi6 *fl6, u32 mtu) |
281 | { | 274 | { |
282 | struct ipv6_pinfo *np = inet6_sk(sk); | 275 | struct ipv6_pinfo *np = inet6_sk(sk); |
283 | struct ipv6hdr *iph; | 276 | struct ipv6hdr *iph; |
@@ -294,7 +287,7 @@ void ipv6_local_rxpmtu(struct sock *sk, struct flowi *fl, u32 mtu) | |||
294 | skb_put(skb, sizeof(struct ipv6hdr)); | 287 | skb_put(skb, sizeof(struct ipv6hdr)); |
295 | skb_reset_network_header(skb); | 288 | skb_reset_network_header(skb); |
296 | iph = ipv6_hdr(skb); | 289 | iph = ipv6_hdr(skb); |
297 | ipv6_addr_copy(&iph->daddr, &fl->fl6_dst); | 290 | ipv6_addr_copy(&iph->daddr, &fl6->daddr); |
298 | 291 | ||
299 | mtu_info = IP6CBMTU(skb); | 292 | mtu_info = IP6CBMTU(skb); |
300 | if (!mtu_info) { | 293 | if (!mtu_info) { |
@@ -306,7 +299,7 @@ void ipv6_local_rxpmtu(struct sock *sk, struct flowi *fl, u32 mtu) | |||
306 | mtu_info->ip6m_addr.sin6_family = AF_INET6; | 299 | mtu_info->ip6m_addr.sin6_family = AF_INET6; |
307 | mtu_info->ip6m_addr.sin6_port = 0; | 300 | mtu_info->ip6m_addr.sin6_port = 0; |
308 | mtu_info->ip6m_addr.sin6_flowinfo = 0; | 301 | mtu_info->ip6m_addr.sin6_flowinfo = 0; |
309 | mtu_info->ip6m_addr.sin6_scope_id = fl->oif; | 302 | mtu_info->ip6m_addr.sin6_scope_id = fl6->flowi6_oif; |
310 | ipv6_addr_copy(&mtu_info->ip6m_addr.sin6_addr, &ipv6_hdr(skb)->daddr); | 303 | ipv6_addr_copy(&mtu_info->ip6m_addr.sin6_addr, &ipv6_hdr(skb)->daddr); |
311 | 304 | ||
312 | __skb_pull(skb, skb_tail_pointer(skb) - skb->data); | 305 | __skb_pull(skb, skb_tail_pointer(skb) - skb->data); |
@@ -577,11 +570,30 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb) | |||
577 | u8 *ptr = nh + opt->dst1; | 570 | u8 *ptr = nh + opt->dst1; |
578 | put_cmsg(msg, SOL_IPV6, IPV6_2292DSTOPTS, (ptr[1]+1)<<3, ptr); | 571 | put_cmsg(msg, SOL_IPV6, IPV6_2292DSTOPTS, (ptr[1]+1)<<3, ptr); |
579 | } | 572 | } |
573 | if (np->rxopt.bits.rxorigdstaddr) { | ||
574 | struct sockaddr_in6 sin6; | ||
575 | u16 *ports = (u16 *) skb_transport_header(skb); | ||
576 | |||
577 | if (skb_transport_offset(skb) + 4 <= skb->len) { | ||
578 | /* All current transport protocols have the port numbers in the | ||
579 | * first four bytes of the transport header and this function is | ||
580 | * written with this assumption in mind. | ||
581 | */ | ||
582 | |||
583 | sin6.sin6_family = AF_INET6; | ||
584 | ipv6_addr_copy(&sin6.sin6_addr, &ipv6_hdr(skb)->daddr); | ||
585 | sin6.sin6_port = ports[1]; | ||
586 | sin6.sin6_flowinfo = 0; | ||
587 | sin6.sin6_scope_id = 0; | ||
588 | |||
589 | put_cmsg(msg, SOL_IPV6, IPV6_ORIGDSTADDR, sizeof(sin6), &sin6); | ||
590 | } | ||
591 | } | ||
580 | return 0; | 592 | return 0; |
581 | } | 593 | } |
582 | 594 | ||
583 | int datagram_send_ctl(struct net *net, | 595 | int datagram_send_ctl(struct net *net, |
584 | struct msghdr *msg, struct flowi *fl, | 596 | struct msghdr *msg, struct flowi6 *fl6, |
585 | struct ipv6_txoptions *opt, | 597 | struct ipv6_txoptions *opt, |
586 | int *hlimit, int *tclass, int *dontfrag) | 598 | int *hlimit, int *tclass, int *dontfrag) |
587 | { | 599 | { |
@@ -617,16 +629,17 @@ int datagram_send_ctl(struct net *net, | |||
617 | src_info = (struct in6_pktinfo *)CMSG_DATA(cmsg); | 629 | src_info = (struct in6_pktinfo *)CMSG_DATA(cmsg); |
618 | 630 | ||
619 | if (src_info->ipi6_ifindex) { | 631 | if (src_info->ipi6_ifindex) { |
620 | if (fl->oif && src_info->ipi6_ifindex != fl->oif) | 632 | if (fl6->flowi6_oif && |
633 | src_info->ipi6_ifindex != fl6->flowi6_oif) | ||
621 | return -EINVAL; | 634 | return -EINVAL; |
622 | fl->oif = src_info->ipi6_ifindex; | 635 | fl6->flowi6_oif = src_info->ipi6_ifindex; |
623 | } | 636 | } |
624 | 637 | ||
625 | addr_type = __ipv6_addr_type(&src_info->ipi6_addr); | 638 | addr_type = __ipv6_addr_type(&src_info->ipi6_addr); |
626 | 639 | ||
627 | rcu_read_lock(); | 640 | rcu_read_lock(); |
628 | if (fl->oif) { | 641 | if (fl6->flowi6_oif) { |
629 | dev = dev_get_by_index_rcu(net, fl->oif); | 642 | dev = dev_get_by_index_rcu(net, fl6->flowi6_oif); |
630 | if (!dev) { | 643 | if (!dev) { |
631 | rcu_read_unlock(); | 644 | rcu_read_unlock(); |
632 | return -ENODEV; | 645 | return -ENODEV; |
@@ -642,7 +655,7 @@ int datagram_send_ctl(struct net *net, | |||
642 | strict ? dev : NULL, 0)) | 655 | strict ? dev : NULL, 0)) |
643 | err = -EINVAL; | 656 | err = -EINVAL; |
644 | else | 657 | else |
645 | ipv6_addr_copy(&fl->fl6_src, &src_info->ipi6_addr); | 658 | ipv6_addr_copy(&fl6->saddr, &src_info->ipi6_addr); |
646 | } | 659 | } |
647 | 660 | ||
648 | rcu_read_unlock(); | 661 | rcu_read_unlock(); |
@@ -659,13 +672,13 @@ int datagram_send_ctl(struct net *net, | |||
659 | goto exit_f; | 672 | goto exit_f; |
660 | } | 673 | } |
661 | 674 | ||
662 | if (fl->fl6_flowlabel&IPV6_FLOWINFO_MASK) { | 675 | if (fl6->flowlabel&IPV6_FLOWINFO_MASK) { |
663 | if ((fl->fl6_flowlabel^*(__be32 *)CMSG_DATA(cmsg))&~IPV6_FLOWINFO_MASK) { | 676 | if ((fl6->flowlabel^*(__be32 *)CMSG_DATA(cmsg))&~IPV6_FLOWINFO_MASK) { |
664 | err = -EINVAL; | 677 | err = -EINVAL; |
665 | goto exit_f; | 678 | goto exit_f; |
666 | } | 679 | } |
667 | } | 680 | } |
668 | fl->fl6_flowlabel = IPV6_FLOWINFO_MASK & *(__be32 *)CMSG_DATA(cmsg); | 681 | fl6->flowlabel = IPV6_FLOWINFO_MASK & *(__be32 *)CMSG_DATA(cmsg); |
669 | break; | 682 | break; |
670 | 683 | ||
671 | case IPV6_2292HOPOPTS: | 684 | case IPV6_2292HOPOPTS: |
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index ee9b93bdd6a2..1ac7938dd9ec 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c | |||
@@ -49,19 +49,25 @@ struct esp_skb_cb { | |||
49 | 49 | ||
50 | #define ESP_SKB_CB(__skb) ((struct esp_skb_cb *)&((__skb)->cb[0])) | 50 | #define ESP_SKB_CB(__skb) ((struct esp_skb_cb *)&((__skb)->cb[0])) |
51 | 51 | ||
52 | static u32 esp6_get_mtu(struct xfrm_state *x, int mtu); | ||
53 | |||
52 | /* | 54 | /* |
53 | * Allocate an AEAD request structure with extra space for SG and IV. | 55 | * Allocate an AEAD request structure with extra space for SG and IV. |
54 | * | 56 | * |
55 | * For alignment considerations the IV is placed at the front, followed | 57 | * For alignment considerations the upper 32 bits of the sequence number are |
56 | * by the request and finally the SG list. | 58 | * placed at the front, if present. Followed by the IV, the request and finally |
59 | * the SG list. | ||
57 | * | 60 | * |
58 | * TODO: Use spare space in skb for this where possible. | 61 | * TODO: Use spare space in skb for this where possible. |
59 | */ | 62 | */ |
60 | static void *esp_alloc_tmp(struct crypto_aead *aead, int nfrags) | 63 | static void *esp_alloc_tmp(struct crypto_aead *aead, int nfrags, int seqihlen) |
61 | { | 64 | { |
62 | unsigned int len; | 65 | unsigned int len; |
63 | 66 | ||
64 | len = crypto_aead_ivsize(aead); | 67 | len = seqihlen; |
68 | |||
69 | len += crypto_aead_ivsize(aead); | ||
70 | |||
65 | if (len) { | 71 | if (len) { |
66 | len += crypto_aead_alignmask(aead) & | 72 | len += crypto_aead_alignmask(aead) & |
67 | ~(crypto_tfm_ctx_alignment() - 1); | 73 | ~(crypto_tfm_ctx_alignment() - 1); |
@@ -76,10 +82,16 @@ static void *esp_alloc_tmp(struct crypto_aead *aead, int nfrags) | |||
76 | return kmalloc(len, GFP_ATOMIC); | 82 | return kmalloc(len, GFP_ATOMIC); |
77 | } | 83 | } |
78 | 84 | ||
79 | static inline u8 *esp_tmp_iv(struct crypto_aead *aead, void *tmp) | 85 | static inline __be32 *esp_tmp_seqhi(void *tmp) |
86 | { | ||
87 | return PTR_ALIGN((__be32 *)tmp, __alignof__(__be32)); | ||
88 | } | ||
89 | |||
90 | static inline u8 *esp_tmp_iv(struct crypto_aead *aead, void *tmp, int seqhilen) | ||
80 | { | 91 | { |
81 | return crypto_aead_ivsize(aead) ? | 92 | return crypto_aead_ivsize(aead) ? |
82 | PTR_ALIGN((u8 *)tmp, crypto_aead_alignmask(aead) + 1) : tmp; | 93 | PTR_ALIGN((u8 *)tmp + seqhilen, |
94 | crypto_aead_alignmask(aead) + 1) : tmp + seqhilen; | ||
83 | } | 95 | } |
84 | 96 | ||
85 | static inline struct aead_givcrypt_request *esp_tmp_givreq( | 97 | static inline struct aead_givcrypt_request *esp_tmp_givreq( |
@@ -140,47 +152,76 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
140 | int blksize; | 152 | int blksize; |
141 | int clen; | 153 | int clen; |
142 | int alen; | 154 | int alen; |
155 | int plen; | ||
156 | int tfclen; | ||
143 | int nfrags; | 157 | int nfrags; |
158 | int assoclen; | ||
159 | int sglists; | ||
160 | int seqhilen; | ||
144 | u8 *iv; | 161 | u8 *iv; |
145 | u8 *tail; | 162 | u8 *tail; |
163 | __be32 *seqhi; | ||
146 | struct esp_data *esp = x->data; | 164 | struct esp_data *esp = x->data; |
147 | 165 | ||
148 | /* skb is pure payload to encrypt */ | 166 | /* skb is pure payload to encrypt */ |
149 | err = -ENOMEM; | 167 | err = -ENOMEM; |
150 | 168 | ||
151 | /* Round to block size */ | ||
152 | clen = skb->len; | ||
153 | |||
154 | aead = esp->aead; | 169 | aead = esp->aead; |
155 | alen = crypto_aead_authsize(aead); | 170 | alen = crypto_aead_authsize(aead); |
156 | 171 | ||
172 | tfclen = 0; | ||
173 | if (x->tfcpad) { | ||
174 | struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb); | ||
175 | u32 padto; | ||
176 | |||
177 | padto = min(x->tfcpad, esp6_get_mtu(x, dst->child_mtu_cached)); | ||
178 | if (skb->len < padto) | ||
179 | tfclen = padto - skb->len; | ||
180 | } | ||
157 | blksize = ALIGN(crypto_aead_blocksize(aead), 4); | 181 | blksize = ALIGN(crypto_aead_blocksize(aead), 4); |
158 | clen = ALIGN(clen + 2, blksize); | 182 | clen = ALIGN(skb->len + 2 + tfclen, blksize); |
159 | if (esp->padlen) | 183 | if (esp->padlen) |
160 | clen = ALIGN(clen, esp->padlen); | 184 | clen = ALIGN(clen, esp->padlen); |
185 | plen = clen - skb->len - tfclen; | ||
161 | 186 | ||
162 | if ((err = skb_cow_data(skb, clen - skb->len + alen, &trailer)) < 0) | 187 | err = skb_cow_data(skb, tfclen + plen + alen, &trailer); |
188 | if (err < 0) | ||
163 | goto error; | 189 | goto error; |
164 | nfrags = err; | 190 | nfrags = err; |
165 | 191 | ||
166 | tmp = esp_alloc_tmp(aead, nfrags + 1); | 192 | assoclen = sizeof(*esph); |
193 | sglists = 1; | ||
194 | seqhilen = 0; | ||
195 | |||
196 | if (x->props.flags & XFRM_STATE_ESN) { | ||
197 | sglists += 2; | ||
198 | seqhilen += sizeof(__be32); | ||
199 | assoclen += seqhilen; | ||
200 | } | ||
201 | |||
202 | tmp = esp_alloc_tmp(aead, nfrags + sglists, seqhilen); | ||
167 | if (!tmp) | 203 | if (!tmp) |
168 | goto error; | 204 | goto error; |
169 | 205 | ||
170 | iv = esp_tmp_iv(aead, tmp); | 206 | seqhi = esp_tmp_seqhi(tmp); |
207 | iv = esp_tmp_iv(aead, tmp, seqhilen); | ||
171 | req = esp_tmp_givreq(aead, iv); | 208 | req = esp_tmp_givreq(aead, iv); |
172 | asg = esp_givreq_sg(aead, req); | 209 | asg = esp_givreq_sg(aead, req); |
173 | sg = asg + 1; | 210 | sg = asg + sglists; |
174 | 211 | ||
175 | /* Fill padding... */ | 212 | /* Fill padding... */ |
176 | tail = skb_tail_pointer(trailer); | 213 | tail = skb_tail_pointer(trailer); |
214 | if (tfclen) { | ||
215 | memset(tail, 0, tfclen); | ||
216 | tail += tfclen; | ||
217 | } | ||
177 | do { | 218 | do { |
178 | int i; | 219 | int i; |
179 | for (i=0; i<clen-skb->len - 2; i++) | 220 | for (i = 0; i < plen - 2; i++) |
180 | tail[i] = i + 1; | 221 | tail[i] = i + 1; |
181 | } while (0); | 222 | } while (0); |
182 | tail[clen-skb->len - 2] = (clen - skb->len) - 2; | 223 | tail[plen - 2] = plen - 2; |
183 | tail[clen - skb->len - 1] = *skb_mac_header(skb); | 224 | tail[plen - 1] = *skb_mac_header(skb); |
184 | pskb_put(skb, trailer, clen - skb->len + alen); | 225 | pskb_put(skb, trailer, clen - skb->len + alen); |
185 | 226 | ||
186 | skb_push(skb, -skb_network_offset(skb)); | 227 | skb_push(skb, -skb_network_offset(skb)); |
@@ -188,19 +229,27 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
188 | *skb_mac_header(skb) = IPPROTO_ESP; | 229 | *skb_mac_header(skb) = IPPROTO_ESP; |
189 | 230 | ||
190 | esph->spi = x->id.spi; | 231 | esph->spi = x->id.spi; |
191 | esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output); | 232 | esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.low); |
192 | 233 | ||
193 | sg_init_table(sg, nfrags); | 234 | sg_init_table(sg, nfrags); |
194 | skb_to_sgvec(skb, sg, | 235 | skb_to_sgvec(skb, sg, |
195 | esph->enc_data + crypto_aead_ivsize(aead) - skb->data, | 236 | esph->enc_data + crypto_aead_ivsize(aead) - skb->data, |
196 | clen + alen); | 237 | clen + alen); |
197 | sg_init_one(asg, esph, sizeof(*esph)); | 238 | |
239 | if ((x->props.flags & XFRM_STATE_ESN)) { | ||
240 | sg_init_table(asg, 3); | ||
241 | sg_set_buf(asg, &esph->spi, sizeof(__be32)); | ||
242 | *seqhi = htonl(XFRM_SKB_CB(skb)->seq.output.hi); | ||
243 | sg_set_buf(asg + 1, seqhi, seqhilen); | ||
244 | sg_set_buf(asg + 2, &esph->seq_no, sizeof(__be32)); | ||
245 | } else | ||
246 | sg_init_one(asg, esph, sizeof(*esph)); | ||
198 | 247 | ||
199 | aead_givcrypt_set_callback(req, 0, esp_output_done, skb); | 248 | aead_givcrypt_set_callback(req, 0, esp_output_done, skb); |
200 | aead_givcrypt_set_crypt(req, sg, sg, clen, iv); | 249 | aead_givcrypt_set_crypt(req, sg, sg, clen, iv); |
201 | aead_givcrypt_set_assoc(req, asg, sizeof(*esph)); | 250 | aead_givcrypt_set_assoc(req, asg, assoclen); |
202 | aead_givcrypt_set_giv(req, esph->enc_data, | 251 | aead_givcrypt_set_giv(req, esph->enc_data, |
203 | XFRM_SKB_CB(skb)->seq.output); | 252 | XFRM_SKB_CB(skb)->seq.output.low); |
204 | 253 | ||
205 | ESP_SKB_CB(skb)->tmp = tmp; | 254 | ESP_SKB_CB(skb)->tmp = tmp; |
206 | err = crypto_aead_givencrypt(req); | 255 | err = crypto_aead_givencrypt(req); |
@@ -276,8 +325,12 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
276 | struct sk_buff *trailer; | 325 | struct sk_buff *trailer; |
277 | int elen = skb->len - sizeof(*esph) - crypto_aead_ivsize(aead); | 326 | int elen = skb->len - sizeof(*esph) - crypto_aead_ivsize(aead); |
278 | int nfrags; | 327 | int nfrags; |
328 | int assoclen; | ||
329 | int sglists; | ||
330 | int seqhilen; | ||
279 | int ret = 0; | 331 | int ret = 0; |
280 | void *tmp; | 332 | void *tmp; |
333 | __be32 *seqhi; | ||
281 | u8 *iv; | 334 | u8 *iv; |
282 | struct scatterlist *sg; | 335 | struct scatterlist *sg; |
283 | struct scatterlist *asg; | 336 | struct scatterlist *asg; |
@@ -298,15 +351,27 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
298 | } | 351 | } |
299 | 352 | ||
300 | ret = -ENOMEM; | 353 | ret = -ENOMEM; |
301 | tmp = esp_alloc_tmp(aead, nfrags + 1); | 354 | |
355 | assoclen = sizeof(*esph); | ||
356 | sglists = 1; | ||
357 | seqhilen = 0; | ||
358 | |||
359 | if (x->props.flags & XFRM_STATE_ESN) { | ||
360 | sglists += 2; | ||
361 | seqhilen += sizeof(__be32); | ||
362 | assoclen += seqhilen; | ||
363 | } | ||
364 | |||
365 | tmp = esp_alloc_tmp(aead, nfrags + sglists, seqhilen); | ||
302 | if (!tmp) | 366 | if (!tmp) |
303 | goto out; | 367 | goto out; |
304 | 368 | ||
305 | ESP_SKB_CB(skb)->tmp = tmp; | 369 | ESP_SKB_CB(skb)->tmp = tmp; |
306 | iv = esp_tmp_iv(aead, tmp); | 370 | seqhi = esp_tmp_seqhi(tmp); |
371 | iv = esp_tmp_iv(aead, tmp, seqhilen); | ||
307 | req = esp_tmp_req(aead, iv); | 372 | req = esp_tmp_req(aead, iv); |
308 | asg = esp_req_sg(aead, req); | 373 | asg = esp_req_sg(aead, req); |
309 | sg = asg + 1; | 374 | sg = asg + sglists; |
310 | 375 | ||
311 | skb->ip_summed = CHECKSUM_NONE; | 376 | skb->ip_summed = CHECKSUM_NONE; |
312 | 377 | ||
@@ -317,11 +382,19 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
317 | 382 | ||
318 | sg_init_table(sg, nfrags); | 383 | sg_init_table(sg, nfrags); |
319 | skb_to_sgvec(skb, sg, sizeof(*esph) + crypto_aead_ivsize(aead), elen); | 384 | skb_to_sgvec(skb, sg, sizeof(*esph) + crypto_aead_ivsize(aead), elen); |
320 | sg_init_one(asg, esph, sizeof(*esph)); | 385 | |
386 | if ((x->props.flags & XFRM_STATE_ESN)) { | ||
387 | sg_init_table(asg, 3); | ||
388 | sg_set_buf(asg, &esph->spi, sizeof(__be32)); | ||
389 | *seqhi = XFRM_SKB_CB(skb)->seq.input.hi; | ||
390 | sg_set_buf(asg + 1, seqhi, seqhilen); | ||
391 | sg_set_buf(asg + 2, &esph->seq_no, sizeof(__be32)); | ||
392 | } else | ||
393 | sg_init_one(asg, esph, sizeof(*esph)); | ||
321 | 394 | ||
322 | aead_request_set_callback(req, 0, esp_input_done, skb); | 395 | aead_request_set_callback(req, 0, esp_input_done, skb); |
323 | aead_request_set_crypt(req, sg, sg, elen, iv); | 396 | aead_request_set_crypt(req, sg, sg, elen, iv); |
324 | aead_request_set_assoc(req, asg, sizeof(*esph)); | 397 | aead_request_set_assoc(req, asg, assoclen); |
325 | 398 | ||
326 | ret = crypto_aead_decrypt(req); | 399 | ret = crypto_aead_decrypt(req); |
327 | if (ret == -EINPROGRESS) | 400 | if (ret == -EINPROGRESS) |
@@ -357,7 +430,7 @@ static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
357 | u8 type, u8 code, int offset, __be32 info) | 430 | u8 type, u8 code, int offset, __be32 info) |
358 | { | 431 | { |
359 | struct net *net = dev_net(skb->dev); | 432 | struct net *net = dev_net(skb->dev); |
360 | struct ipv6hdr *iph = (struct ipv6hdr*)skb->data; | 433 | const struct ipv6hdr *iph = (const struct ipv6hdr *)skb->data; |
361 | struct ip_esp_hdr *esph = (struct ip_esp_hdr *)(skb->data + offset); | 434 | struct ip_esp_hdr *esph = (struct ip_esp_hdr *)(skb->data + offset); |
362 | struct xfrm_state *x; | 435 | struct xfrm_state *x; |
363 | 436 | ||
@@ -365,7 +438,8 @@ static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
365 | type != ICMPV6_PKT_TOOBIG) | 438 | type != ICMPV6_PKT_TOOBIG) |
366 | return; | 439 | return; |
367 | 440 | ||
368 | x = xfrm_state_lookup(net, skb->mark, (xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET6); | 441 | x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr, |
442 | esph->spi, IPPROTO_ESP, AF_INET6); | ||
369 | if (!x) | 443 | if (!x) |
370 | return; | 444 | return; |
371 | printk(KERN_DEBUG "pmtu discovery on SA ESP/%08x/%pI6\n", | 445 | printk(KERN_DEBUG "pmtu discovery on SA ESP/%08x/%pI6\n", |
@@ -427,10 +501,20 @@ static int esp_init_authenc(struct xfrm_state *x) | |||
427 | goto error; | 501 | goto error; |
428 | 502 | ||
429 | err = -ENAMETOOLONG; | 503 | err = -ENAMETOOLONG; |
430 | if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, "authenc(%s,%s)", | 504 | |
431 | x->aalg ? x->aalg->alg_name : "digest_null", | 505 | if ((x->props.flags & XFRM_STATE_ESN)) { |
432 | x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME) | 506 | if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, |
433 | goto error; | 507 | "authencesn(%s,%s)", |
508 | x->aalg ? x->aalg->alg_name : "digest_null", | ||
509 | x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME) | ||
510 | goto error; | ||
511 | } else { | ||
512 | if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, | ||
513 | "authenc(%s,%s)", | ||
514 | x->aalg ? x->aalg->alg_name : "digest_null", | ||
515 | x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME) | ||
516 | goto error; | ||
517 | } | ||
434 | 518 | ||
435 | aead = crypto_alloc_aead(authenc_name, 0, 0); | 519 | aead = crypto_alloc_aead(authenc_name, 0, 0); |
436 | err = PTR_ERR(aead); | 520 | err = PTR_ERR(aead); |
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 262f105d23b9..79a485e8a700 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c | |||
@@ -876,22 +876,22 @@ struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space, | |||
876 | * fl6_update_dst - update flowi destination address with info given | 876 | * fl6_update_dst - update flowi destination address with info given |
877 | * by srcrt option, if any. | 877 | * by srcrt option, if any. |
878 | * | 878 | * |
879 | * @fl: flowi for which fl6_dst is to be updated | 879 | * @fl6: flowi6 for which daddr is to be updated |
880 | * @opt: struct ipv6_txoptions in which to look for srcrt opt | 880 | * @opt: struct ipv6_txoptions in which to look for srcrt opt |
881 | * @orig: copy of original fl6_dst address if modified | 881 | * @orig: copy of original daddr address if modified |
882 | * | 882 | * |
883 | * Returns NULL if no txoptions or no srcrt, otherwise returns orig | 883 | * Returns NULL if no txoptions or no srcrt, otherwise returns orig |
884 | * and initial value of fl->fl6_dst set in orig | 884 | * and initial value of fl6->daddr set in orig |
885 | */ | 885 | */ |
886 | struct in6_addr *fl6_update_dst(struct flowi *fl, | 886 | struct in6_addr *fl6_update_dst(struct flowi6 *fl6, |
887 | const struct ipv6_txoptions *opt, | 887 | const struct ipv6_txoptions *opt, |
888 | struct in6_addr *orig) | 888 | struct in6_addr *orig) |
889 | { | 889 | { |
890 | if (!opt || !opt->srcrt) | 890 | if (!opt || !opt->srcrt) |
891 | return NULL; | 891 | return NULL; |
892 | 892 | ||
893 | ipv6_addr_copy(orig, &fl->fl6_dst); | 893 | ipv6_addr_copy(orig, &fl6->daddr); |
894 | ipv6_addr_copy(&fl->fl6_dst, ((struct rt0_hdr *)opt->srcrt)->addr); | 894 | ipv6_addr_copy(&fl6->daddr, ((struct rt0_hdr *)opt->srcrt)->addr); |
895 | return orig; | 895 | return orig; |
896 | } | 896 | } |
897 | 897 | ||
diff --git a/net/ipv6/exthdrs_core.c b/net/ipv6/exthdrs_core.c index e1caa5d526c2..14ed0a955b56 100644 --- a/net/ipv6/exthdrs_core.c +++ b/net/ipv6/exthdrs_core.c | |||
@@ -13,12 +13,12 @@ int ipv6_ext_hdr(u8 nexthdr) | |||
13 | /* | 13 | /* |
14 | * find out if nexthdr is an extension header or a protocol | 14 | * find out if nexthdr is an extension header or a protocol |
15 | */ | 15 | */ |
16 | return ( (nexthdr == NEXTHDR_HOP) || | 16 | return (nexthdr == NEXTHDR_HOP) || |
17 | (nexthdr == NEXTHDR_ROUTING) || | 17 | (nexthdr == NEXTHDR_ROUTING) || |
18 | (nexthdr == NEXTHDR_FRAGMENT) || | 18 | (nexthdr == NEXTHDR_FRAGMENT) || |
19 | (nexthdr == NEXTHDR_AUTH) || | 19 | (nexthdr == NEXTHDR_AUTH) || |
20 | (nexthdr == NEXTHDR_NONE) || | 20 | (nexthdr == NEXTHDR_NONE) || |
21 | (nexthdr == NEXTHDR_DEST) ); | 21 | (nexthdr == NEXTHDR_DEST); |
22 | } | 22 | } |
23 | 23 | ||
24 | /* | 24 | /* |
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index b1108ede18e1..34d244df907d 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c | |||
@@ -29,16 +29,16 @@ struct fib6_rule | |||
29 | u8 tclass; | 29 | u8 tclass; |
30 | }; | 30 | }; |
31 | 31 | ||
32 | struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl, | 32 | struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6, |
33 | int flags, pol_lookup_t lookup) | 33 | int flags, pol_lookup_t lookup) |
34 | { | 34 | { |
35 | struct fib_lookup_arg arg = { | 35 | struct fib_lookup_arg arg = { |
36 | .lookup_ptr = lookup, | 36 | .lookup_ptr = lookup, |
37 | .flags = FIB_LOOKUP_NOREF, | ||
37 | }; | 38 | }; |
38 | 39 | ||
39 | fib_rules_lookup(net->ipv6.fib6_rules_ops, fl, flags, &arg); | 40 | fib_rules_lookup(net->ipv6.fib6_rules_ops, |
40 | if (arg.rule) | 41 | flowi6_to_flowi(fl6), flags, &arg); |
41 | fib_rule_put(arg.rule); | ||
42 | 42 | ||
43 | if (arg.result) | 43 | if (arg.result) |
44 | return arg.result; | 44 | return arg.result; |
@@ -50,6 +50,7 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl, | |||
50 | static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, | 50 | static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, |
51 | int flags, struct fib_lookup_arg *arg) | 51 | int flags, struct fib_lookup_arg *arg) |
52 | { | 52 | { |
53 | struct flowi6 *flp6 = &flp->u.ip6; | ||
53 | struct rt6_info *rt = NULL; | 54 | struct rt6_info *rt = NULL; |
54 | struct fib6_table *table; | 55 | struct fib6_table *table; |
55 | struct net *net = rule->fr_net; | 56 | struct net *net = rule->fr_net; |
@@ -72,7 +73,7 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, | |||
72 | 73 | ||
73 | table = fib6_get_table(net, rule->table); | 74 | table = fib6_get_table(net, rule->table); |
74 | if (table) | 75 | if (table) |
75 | rt = lookup(net, table, flp, flags); | 76 | rt = lookup(net, table, flp6, flags); |
76 | 77 | ||
77 | if (rt != net->ipv6.ip6_null_entry) { | 78 | if (rt != net->ipv6.ip6_null_entry) { |
78 | struct fib6_rule *r = (struct fib6_rule *)rule; | 79 | struct fib6_rule *r = (struct fib6_rule *)rule; |
@@ -87,14 +88,14 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, | |||
87 | 88 | ||
88 | if (ipv6_dev_get_saddr(net, | 89 | if (ipv6_dev_get_saddr(net, |
89 | ip6_dst_idev(&rt->dst)->dev, | 90 | ip6_dst_idev(&rt->dst)->dev, |
90 | &flp->fl6_dst, | 91 | &flp6->daddr, |
91 | rt6_flags2srcprefs(flags), | 92 | rt6_flags2srcprefs(flags), |
92 | &saddr)) | 93 | &saddr)) |
93 | goto again; | 94 | goto again; |
94 | if (!ipv6_prefix_equal(&saddr, &r->src.addr, | 95 | if (!ipv6_prefix_equal(&saddr, &r->src.addr, |
95 | r->src.plen)) | 96 | r->src.plen)) |
96 | goto again; | 97 | goto again; |
97 | ipv6_addr_copy(&flp->fl6_src, &saddr); | 98 | ipv6_addr_copy(&flp6->saddr, &saddr); |
98 | } | 99 | } |
99 | goto out; | 100 | goto out; |
100 | } | 101 | } |
@@ -114,9 +115,10 @@ out: | |||
114 | static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) | 115 | static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) |
115 | { | 116 | { |
116 | struct fib6_rule *r = (struct fib6_rule *) rule; | 117 | struct fib6_rule *r = (struct fib6_rule *) rule; |
118 | struct flowi6 *fl6 = &fl->u.ip6; | ||
117 | 119 | ||
118 | if (r->dst.plen && | 120 | if (r->dst.plen && |
119 | !ipv6_prefix_equal(&fl->fl6_dst, &r->dst.addr, r->dst.plen)) | 121 | !ipv6_prefix_equal(&fl6->daddr, &r->dst.addr, r->dst.plen)) |
120 | return 0; | 122 | return 0; |
121 | 123 | ||
122 | /* | 124 | /* |
@@ -126,14 +128,14 @@ static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) | |||
126 | */ | 128 | */ |
127 | if (r->src.plen) { | 129 | if (r->src.plen) { |
128 | if (flags & RT6_LOOKUP_F_HAS_SADDR) { | 130 | if (flags & RT6_LOOKUP_F_HAS_SADDR) { |
129 | if (!ipv6_prefix_equal(&fl->fl6_src, &r->src.addr, | 131 | if (!ipv6_prefix_equal(&fl6->saddr, &r->src.addr, |
130 | r->src.plen)) | 132 | r->src.plen)) |
131 | return 0; | 133 | return 0; |
132 | } else if (!(r->common.flags & FIB_RULE_FIND_SADDR)) | 134 | } else if (!(r->common.flags & FIB_RULE_FIND_SADDR)) |
133 | return 0; | 135 | return 0; |
134 | } | 136 | } |
135 | 137 | ||
136 | if (r->tclass && r->tclass != ((ntohl(fl->fl6_flowlabel) >> 20) & 0xff)) | 138 | if (r->tclass && r->tclass != ((ntohl(fl6->flowlabel) >> 20) & 0xff)) |
137 | return 0; | 139 | return 0; |
138 | 140 | ||
139 | return 1; | 141 | return 1; |
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 03e62f94ff8e..11900417b1cc 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c | |||
@@ -157,32 +157,32 @@ static int is_ineligible(struct sk_buff *skb) | |||
157 | /* | 157 | /* |
158 | * Check the ICMP output rate limit | 158 | * Check the ICMP output rate limit |
159 | */ | 159 | */ |
160 | static inline int icmpv6_xrlim_allow(struct sock *sk, u8 type, | 160 | static inline bool icmpv6_xrlim_allow(struct sock *sk, u8 type, |
161 | struct flowi *fl) | 161 | struct flowi6 *fl6) |
162 | { | 162 | { |
163 | struct dst_entry *dst; | 163 | struct dst_entry *dst; |
164 | struct net *net = sock_net(sk); | 164 | struct net *net = sock_net(sk); |
165 | int res = 0; | 165 | bool res = false; |
166 | 166 | ||
167 | /* Informational messages are not limited. */ | 167 | /* Informational messages are not limited. */ |
168 | if (type & ICMPV6_INFOMSG_MASK) | 168 | if (type & ICMPV6_INFOMSG_MASK) |
169 | return 1; | 169 | return true; |
170 | 170 | ||
171 | /* Do not limit pmtu discovery, it would break it. */ | 171 | /* Do not limit pmtu discovery, it would break it. */ |
172 | if (type == ICMPV6_PKT_TOOBIG) | 172 | if (type == ICMPV6_PKT_TOOBIG) |
173 | return 1; | 173 | return true; |
174 | 174 | ||
175 | /* | 175 | /* |
176 | * Look up the output route. | 176 | * Look up the output route. |
177 | * XXX: perhaps the expire for routing entries cloned by | 177 | * XXX: perhaps the expire for routing entries cloned by |
178 | * this lookup should be more aggressive (not longer than timeout). | 178 | * this lookup should be more aggressive (not longer than timeout). |
179 | */ | 179 | */ |
180 | dst = ip6_route_output(net, sk, fl); | 180 | dst = ip6_route_output(net, sk, fl6); |
181 | if (dst->error) { | 181 | if (dst->error) { |
182 | IP6_INC_STATS(net, ip6_dst_idev(dst), | 182 | IP6_INC_STATS(net, ip6_dst_idev(dst), |
183 | IPSTATS_MIB_OUTNOROUTES); | 183 | IPSTATS_MIB_OUTNOROUTES); |
184 | } else if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) { | 184 | } else if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) { |
185 | res = 1; | 185 | res = true; |
186 | } else { | 186 | } else { |
187 | struct rt6_info *rt = (struct rt6_info *)dst; | 187 | struct rt6_info *rt = (struct rt6_info *)dst; |
188 | int tmo = net->ipv6.sysctl.icmpv6_time; | 188 | int tmo = net->ipv6.sysctl.icmpv6_time; |
@@ -191,7 +191,9 @@ static inline int icmpv6_xrlim_allow(struct sock *sk, u8 type, | |||
191 | if (rt->rt6i_dst.plen < 128) | 191 | if (rt->rt6i_dst.plen < 128) |
192 | tmo >>= ((128 - rt->rt6i_dst.plen)>>5); | 192 | tmo >>= ((128 - rt->rt6i_dst.plen)>>5); |
193 | 193 | ||
194 | res = xrlim_allow(dst, tmo); | 194 | if (!rt->rt6i_peer) |
195 | rt6_bind_peer(rt, 1); | ||
196 | res = inet_peer_xrlim_allow(rt->rt6i_peer, tmo); | ||
195 | } | 197 | } |
196 | dst_release(dst); | 198 | dst_release(dst); |
197 | return res; | 199 | return res; |
@@ -215,7 +217,7 @@ static __inline__ int opt_unrec(struct sk_buff *skb, __u32 offset) | |||
215 | return (*op & 0xC0) == 0x80; | 217 | return (*op & 0xC0) == 0x80; |
216 | } | 218 | } |
217 | 219 | ||
218 | static int icmpv6_push_pending_frames(struct sock *sk, struct flowi *fl, struct icmp6hdr *thdr, int len) | 220 | static int icmpv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6, struct icmp6hdr *thdr, int len) |
219 | { | 221 | { |
220 | struct sk_buff *skb; | 222 | struct sk_buff *skb; |
221 | struct icmp6hdr *icmp6h; | 223 | struct icmp6hdr *icmp6h; |
@@ -231,9 +233,9 @@ static int icmpv6_push_pending_frames(struct sock *sk, struct flowi *fl, struct | |||
231 | if (skb_queue_len(&sk->sk_write_queue) == 1) { | 233 | if (skb_queue_len(&sk->sk_write_queue) == 1) { |
232 | skb->csum = csum_partial(icmp6h, | 234 | skb->csum = csum_partial(icmp6h, |
233 | sizeof(struct icmp6hdr), skb->csum); | 235 | sizeof(struct icmp6hdr), skb->csum); |
234 | icmp6h->icmp6_cksum = csum_ipv6_magic(&fl->fl6_src, | 236 | icmp6h->icmp6_cksum = csum_ipv6_magic(&fl6->saddr, |
235 | &fl->fl6_dst, | 237 | &fl6->daddr, |
236 | len, fl->proto, | 238 | len, fl6->flowi6_proto, |
237 | skb->csum); | 239 | skb->csum); |
238 | } else { | 240 | } else { |
239 | __wsum tmp_csum = 0; | 241 | __wsum tmp_csum = 0; |
@@ -244,9 +246,9 @@ static int icmpv6_push_pending_frames(struct sock *sk, struct flowi *fl, struct | |||
244 | 246 | ||
245 | tmp_csum = csum_partial(icmp6h, | 247 | tmp_csum = csum_partial(icmp6h, |
246 | sizeof(struct icmp6hdr), tmp_csum); | 248 | sizeof(struct icmp6hdr), tmp_csum); |
247 | icmp6h->icmp6_cksum = csum_ipv6_magic(&fl->fl6_src, | 249 | icmp6h->icmp6_cksum = csum_ipv6_magic(&fl6->saddr, |
248 | &fl->fl6_dst, | 250 | &fl6->daddr, |
249 | len, fl->proto, | 251 | len, fl6->flowi6_proto, |
250 | tmp_csum); | 252 | tmp_csum); |
251 | } | 253 | } |
252 | ip6_push_pending_frames(sk); | 254 | ip6_push_pending_frames(sk); |
@@ -298,6 +300,68 @@ static void mip6_addr_swap(struct sk_buff *skb) | |||
298 | static inline void mip6_addr_swap(struct sk_buff *skb) {} | 300 | static inline void mip6_addr_swap(struct sk_buff *skb) {} |
299 | #endif | 301 | #endif |
300 | 302 | ||
303 | static struct dst_entry *icmpv6_route_lookup(struct net *net, struct sk_buff *skb, | ||
304 | struct sock *sk, struct flowi6 *fl6) | ||
305 | { | ||
306 | struct dst_entry *dst, *dst2; | ||
307 | struct flowi6 fl2; | ||
308 | int err; | ||
309 | |||
310 | err = ip6_dst_lookup(sk, &dst, fl6); | ||
311 | if (err) | ||
312 | return ERR_PTR(err); | ||
313 | |||
314 | /* | ||
315 | * We won't send icmp if the destination is known | ||
316 | * anycast. | ||
317 | */ | ||
318 | if (((struct rt6_info *)dst)->rt6i_flags & RTF_ANYCAST) { | ||
319 | LIMIT_NETDEBUG(KERN_DEBUG "icmpv6_send: acast source\n"); | ||
320 | dst_release(dst); | ||
321 | return ERR_PTR(-EINVAL); | ||
322 | } | ||
323 | |||
324 | /* No need to clone since we're just using its address. */ | ||
325 | dst2 = dst; | ||
326 | |||
327 | dst = xfrm_lookup(net, dst, flowi6_to_flowi(fl6), sk, 0); | ||
328 | if (!IS_ERR(dst)) { | ||
329 | if (dst != dst2) | ||
330 | return dst; | ||
331 | } else { | ||
332 | if (PTR_ERR(dst) == -EPERM) | ||
333 | dst = NULL; | ||
334 | else | ||
335 | return dst; | ||
336 | } | ||
337 | |||
338 | err = xfrm_decode_session_reverse(skb, flowi6_to_flowi(&fl2), AF_INET6); | ||
339 | if (err) | ||
340 | goto relookup_failed; | ||
341 | |||
342 | err = ip6_dst_lookup(sk, &dst2, &fl2); | ||
343 | if (err) | ||
344 | goto relookup_failed; | ||
345 | |||
346 | dst2 = xfrm_lookup(net, dst2, flowi6_to_flowi(&fl2), sk, XFRM_LOOKUP_ICMP); | ||
347 | if (!IS_ERR(dst2)) { | ||
348 | dst_release(dst); | ||
349 | dst = dst2; | ||
350 | } else { | ||
351 | err = PTR_ERR(dst2); | ||
352 | if (err == -EPERM) { | ||
353 | dst_release(dst); | ||
354 | return dst2; | ||
355 | } else | ||
356 | goto relookup_failed; | ||
357 | } | ||
358 | |||
359 | relookup_failed: | ||
360 | if (dst) | ||
361 | return dst; | ||
362 | return ERR_PTR(err); | ||
363 | } | ||
364 | |||
301 | /* | 365 | /* |
302 | * Send an ICMP message in response to a packet in error | 366 | * Send an ICMP message in response to a packet in error |
303 | */ | 367 | */ |
@@ -308,12 +372,10 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) | |||
308 | struct ipv6hdr *hdr = ipv6_hdr(skb); | 372 | struct ipv6hdr *hdr = ipv6_hdr(skb); |
309 | struct sock *sk; | 373 | struct sock *sk; |
310 | struct ipv6_pinfo *np; | 374 | struct ipv6_pinfo *np; |
311 | struct in6_addr *saddr = NULL; | 375 | const struct in6_addr *saddr = NULL; |
312 | struct dst_entry *dst; | 376 | struct dst_entry *dst; |
313 | struct dst_entry *dst2; | ||
314 | struct icmp6hdr tmp_hdr; | 377 | struct icmp6hdr tmp_hdr; |
315 | struct flowi fl; | 378 | struct flowi6 fl6; |
316 | struct flowi fl2; | ||
317 | struct icmpv6_msg msg; | 379 | struct icmpv6_msg msg; |
318 | int iif = 0; | 380 | int iif = 0; |
319 | int addr_type = 0; | 381 | int addr_type = 0; |
@@ -380,22 +442,22 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) | |||
380 | 442 | ||
381 | mip6_addr_swap(skb); | 443 | mip6_addr_swap(skb); |
382 | 444 | ||
383 | memset(&fl, 0, sizeof(fl)); | 445 | memset(&fl6, 0, sizeof(fl6)); |
384 | fl.proto = IPPROTO_ICMPV6; | 446 | fl6.flowi6_proto = IPPROTO_ICMPV6; |
385 | ipv6_addr_copy(&fl.fl6_dst, &hdr->saddr); | 447 | ipv6_addr_copy(&fl6.daddr, &hdr->saddr); |
386 | if (saddr) | 448 | if (saddr) |
387 | ipv6_addr_copy(&fl.fl6_src, saddr); | 449 | ipv6_addr_copy(&fl6.saddr, saddr); |
388 | fl.oif = iif; | 450 | fl6.flowi6_oif = iif; |
389 | fl.fl_icmp_type = type; | 451 | fl6.fl6_icmp_type = type; |
390 | fl.fl_icmp_code = code; | 452 | fl6.fl6_icmp_code = code; |
391 | security_skb_classify_flow(skb, &fl); | 453 | security_skb_classify_flow(skb, flowi6_to_flowi(&fl6)); |
392 | 454 | ||
393 | sk = icmpv6_xmit_lock(net); | 455 | sk = icmpv6_xmit_lock(net); |
394 | if (sk == NULL) | 456 | if (sk == NULL) |
395 | return; | 457 | return; |
396 | np = inet6_sk(sk); | 458 | np = inet6_sk(sk); |
397 | 459 | ||
398 | if (!icmpv6_xrlim_allow(sk, type, &fl)) | 460 | if (!icmpv6_xrlim_allow(sk, type, &fl6)) |
399 | goto out; | 461 | goto out; |
400 | 462 | ||
401 | tmp_hdr.icmp6_type = type; | 463 | tmp_hdr.icmp6_type = type; |
@@ -403,61 +465,14 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) | |||
403 | tmp_hdr.icmp6_cksum = 0; | 465 | tmp_hdr.icmp6_cksum = 0; |
404 | tmp_hdr.icmp6_pointer = htonl(info); | 466 | tmp_hdr.icmp6_pointer = htonl(info); |
405 | 467 | ||
406 | if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) | 468 | if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) |
407 | fl.oif = np->mcast_oif; | 469 | fl6.flowi6_oif = np->mcast_oif; |
408 | 470 | ||
409 | err = ip6_dst_lookup(sk, &dst, &fl); | 471 | dst = icmpv6_route_lookup(net, skb, sk, &fl6); |
410 | if (err) | 472 | if (IS_ERR(dst)) |
411 | goto out; | 473 | goto out; |
412 | 474 | ||
413 | /* | 475 | if (ipv6_addr_is_multicast(&fl6.daddr)) |
414 | * We won't send icmp if the destination is known | ||
415 | * anycast. | ||
416 | */ | ||
417 | if (((struct rt6_info *)dst)->rt6i_flags & RTF_ANYCAST) { | ||
418 | LIMIT_NETDEBUG(KERN_DEBUG "icmpv6_send: acast source\n"); | ||
419 | goto out_dst_release; | ||
420 | } | ||
421 | |||
422 | /* No need to clone since we're just using its address. */ | ||
423 | dst2 = dst; | ||
424 | |||
425 | err = xfrm_lookup(net, &dst, &fl, sk, 0); | ||
426 | switch (err) { | ||
427 | case 0: | ||
428 | if (dst != dst2) | ||
429 | goto route_done; | ||
430 | break; | ||
431 | case -EPERM: | ||
432 | dst = NULL; | ||
433 | break; | ||
434 | default: | ||
435 | goto out; | ||
436 | } | ||
437 | |||
438 | if (xfrm_decode_session_reverse(skb, &fl2, AF_INET6)) | ||
439 | goto relookup_failed; | ||
440 | |||
441 | if (ip6_dst_lookup(sk, &dst2, &fl2)) | ||
442 | goto relookup_failed; | ||
443 | |||
444 | err = xfrm_lookup(net, &dst2, &fl2, sk, XFRM_LOOKUP_ICMP); | ||
445 | switch (err) { | ||
446 | case 0: | ||
447 | dst_release(dst); | ||
448 | dst = dst2; | ||
449 | break; | ||
450 | case -EPERM: | ||
451 | goto out_dst_release; | ||
452 | default: | ||
453 | relookup_failed: | ||
454 | if (!dst) | ||
455 | goto out; | ||
456 | break; | ||
457 | } | ||
458 | |||
459 | route_done: | ||
460 | if (ipv6_addr_is_multicast(&fl.fl6_dst)) | ||
461 | hlimit = np->mcast_hops; | 476 | hlimit = np->mcast_hops; |
462 | else | 477 | else |
463 | hlimit = np->hop_limit; | 478 | hlimit = np->hop_limit; |
@@ -480,14 +495,14 @@ route_done: | |||
480 | err = ip6_append_data(sk, icmpv6_getfrag, &msg, | 495 | err = ip6_append_data(sk, icmpv6_getfrag, &msg, |
481 | len + sizeof(struct icmp6hdr), | 496 | len + sizeof(struct icmp6hdr), |
482 | sizeof(struct icmp6hdr), hlimit, | 497 | sizeof(struct icmp6hdr), hlimit, |
483 | np->tclass, NULL, &fl, (struct rt6_info*)dst, | 498 | np->tclass, NULL, &fl6, (struct rt6_info*)dst, |
484 | MSG_DONTWAIT, np->dontfrag); | 499 | MSG_DONTWAIT, np->dontfrag); |
485 | if (err) { | 500 | if (err) { |
486 | ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTERRORS); | 501 | ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTERRORS); |
487 | ip6_flush_pending_frames(sk); | 502 | ip6_flush_pending_frames(sk); |
488 | goto out_put; | 503 | goto out_put; |
489 | } | 504 | } |
490 | err = icmpv6_push_pending_frames(sk, &fl, &tmp_hdr, len + sizeof(struct icmp6hdr)); | 505 | err = icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr, len + sizeof(struct icmp6hdr)); |
491 | 506 | ||
492 | out_put: | 507 | out_put: |
493 | if (likely(idev != NULL)) | 508 | if (likely(idev != NULL)) |
@@ -506,10 +521,10 @@ static void icmpv6_echo_reply(struct sk_buff *skb) | |||
506 | struct sock *sk; | 521 | struct sock *sk; |
507 | struct inet6_dev *idev; | 522 | struct inet6_dev *idev; |
508 | struct ipv6_pinfo *np; | 523 | struct ipv6_pinfo *np; |
509 | struct in6_addr *saddr = NULL; | 524 | const struct in6_addr *saddr = NULL; |
510 | struct icmp6hdr *icmph = icmp6_hdr(skb); | 525 | struct icmp6hdr *icmph = icmp6_hdr(skb); |
511 | struct icmp6hdr tmp_hdr; | 526 | struct icmp6hdr tmp_hdr; |
512 | struct flowi fl; | 527 | struct flowi6 fl6; |
513 | struct icmpv6_msg msg; | 528 | struct icmpv6_msg msg; |
514 | struct dst_entry *dst; | 529 | struct dst_entry *dst; |
515 | int err = 0; | 530 | int err = 0; |
@@ -523,30 +538,31 @@ static void icmpv6_echo_reply(struct sk_buff *skb) | |||
523 | memcpy(&tmp_hdr, icmph, sizeof(tmp_hdr)); | 538 | memcpy(&tmp_hdr, icmph, sizeof(tmp_hdr)); |
524 | tmp_hdr.icmp6_type = ICMPV6_ECHO_REPLY; | 539 | tmp_hdr.icmp6_type = ICMPV6_ECHO_REPLY; |
525 | 540 | ||
526 | memset(&fl, 0, sizeof(fl)); | 541 | memset(&fl6, 0, sizeof(fl6)); |
527 | fl.proto = IPPROTO_ICMPV6; | 542 | fl6.flowi6_proto = IPPROTO_ICMPV6; |
528 | ipv6_addr_copy(&fl.fl6_dst, &ipv6_hdr(skb)->saddr); | 543 | ipv6_addr_copy(&fl6.daddr, &ipv6_hdr(skb)->saddr); |
529 | if (saddr) | 544 | if (saddr) |
530 | ipv6_addr_copy(&fl.fl6_src, saddr); | 545 | ipv6_addr_copy(&fl6.saddr, saddr); |
531 | fl.oif = skb->dev->ifindex; | 546 | fl6.flowi6_oif = skb->dev->ifindex; |
532 | fl.fl_icmp_type = ICMPV6_ECHO_REPLY; | 547 | fl6.fl6_icmp_type = ICMPV6_ECHO_REPLY; |
533 | security_skb_classify_flow(skb, &fl); | 548 | security_skb_classify_flow(skb, flowi6_to_flowi(&fl6)); |
534 | 549 | ||
535 | sk = icmpv6_xmit_lock(net); | 550 | sk = icmpv6_xmit_lock(net); |
536 | if (sk == NULL) | 551 | if (sk == NULL) |
537 | return; | 552 | return; |
538 | np = inet6_sk(sk); | 553 | np = inet6_sk(sk); |
539 | 554 | ||
540 | if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) | 555 | if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) |
541 | fl.oif = np->mcast_oif; | 556 | fl6.flowi6_oif = np->mcast_oif; |
542 | 557 | ||
543 | err = ip6_dst_lookup(sk, &dst, &fl); | 558 | err = ip6_dst_lookup(sk, &dst, &fl6); |
544 | if (err) | 559 | if (err) |
545 | goto out; | 560 | goto out; |
546 | if ((err = xfrm_lookup(net, &dst, &fl, sk, 0)) < 0) | 561 | dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), sk, 0); |
562 | if (IS_ERR(dst)) | ||
547 | goto out; | 563 | goto out; |
548 | 564 | ||
549 | if (ipv6_addr_is_multicast(&fl.fl6_dst)) | 565 | if (ipv6_addr_is_multicast(&fl6.daddr)) |
550 | hlimit = np->mcast_hops; | 566 | hlimit = np->mcast_hops; |
551 | else | 567 | else |
552 | hlimit = np->hop_limit; | 568 | hlimit = np->hop_limit; |
@@ -560,7 +576,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb) | |||
560 | msg.type = ICMPV6_ECHO_REPLY; | 576 | msg.type = ICMPV6_ECHO_REPLY; |
561 | 577 | ||
562 | err = ip6_append_data(sk, icmpv6_getfrag, &msg, skb->len + sizeof(struct icmp6hdr), | 578 | err = ip6_append_data(sk, icmpv6_getfrag, &msg, skb->len + sizeof(struct icmp6hdr), |
563 | sizeof(struct icmp6hdr), hlimit, np->tclass, NULL, &fl, | 579 | sizeof(struct icmp6hdr), hlimit, np->tclass, NULL, &fl6, |
564 | (struct rt6_info*)dst, MSG_DONTWAIT, | 580 | (struct rt6_info*)dst, MSG_DONTWAIT, |
565 | np->dontfrag); | 581 | np->dontfrag); |
566 | 582 | ||
@@ -569,7 +585,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb) | |||
569 | ip6_flush_pending_frames(sk); | 585 | ip6_flush_pending_frames(sk); |
570 | goto out_put; | 586 | goto out_put; |
571 | } | 587 | } |
572 | err = icmpv6_push_pending_frames(sk, &fl, &tmp_hdr, skb->len + sizeof(struct icmp6hdr)); | 588 | err = icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr, skb->len + sizeof(struct icmp6hdr)); |
573 | 589 | ||
574 | out_put: | 590 | out_put: |
575 | if (likely(idev != NULL)) | 591 | if (likely(idev != NULL)) |
@@ -629,8 +645,8 @@ static int icmpv6_rcv(struct sk_buff *skb) | |||
629 | { | 645 | { |
630 | struct net_device *dev = skb->dev; | 646 | struct net_device *dev = skb->dev; |
631 | struct inet6_dev *idev = __in6_dev_get(dev); | 647 | struct inet6_dev *idev = __in6_dev_get(dev); |
632 | struct in6_addr *saddr, *daddr; | 648 | const struct in6_addr *saddr, *daddr; |
633 | struct ipv6hdr *orig_hdr; | 649 | const struct ipv6hdr *orig_hdr; |
634 | struct icmp6hdr *hdr; | 650 | struct icmp6hdr *hdr; |
635 | u8 type; | 651 | u8 type; |
636 | 652 | ||
@@ -768,20 +784,20 @@ drop_no_count: | |||
768 | return 0; | 784 | return 0; |
769 | } | 785 | } |
770 | 786 | ||
771 | void icmpv6_flow_init(struct sock *sk, struct flowi *fl, | 787 | void icmpv6_flow_init(struct sock *sk, struct flowi6 *fl6, |
772 | u8 type, | 788 | u8 type, |
773 | const struct in6_addr *saddr, | 789 | const struct in6_addr *saddr, |
774 | const struct in6_addr *daddr, | 790 | const struct in6_addr *daddr, |
775 | int oif) | 791 | int oif) |
776 | { | 792 | { |
777 | memset(fl, 0, sizeof(*fl)); | 793 | memset(fl6, 0, sizeof(*fl6)); |
778 | ipv6_addr_copy(&fl->fl6_src, saddr); | 794 | ipv6_addr_copy(&fl6->saddr, saddr); |
779 | ipv6_addr_copy(&fl->fl6_dst, daddr); | 795 | ipv6_addr_copy(&fl6->daddr, daddr); |
780 | fl->proto = IPPROTO_ICMPV6; | 796 | fl6->flowi6_proto = IPPROTO_ICMPV6; |
781 | fl->fl_icmp_type = type; | 797 | fl6->fl6_icmp_type = type; |
782 | fl->fl_icmp_code = 0; | 798 | fl6->fl6_icmp_code = 0; |
783 | fl->oif = oif; | 799 | fl6->flowi6_oif = oif; |
784 | security_sk_classify_flow(sk, fl); | 800 | security_sk_classify_flow(sk, flowi6_to_flowi(fl6)); |
785 | } | 801 | } |
786 | 802 | ||
787 | /* | 803 | /* |
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index 8a1628023bd1..8a58e8cf6646 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c | |||
@@ -54,24 +54,49 @@ int inet6_csk_bind_conflict(const struct sock *sk, | |||
54 | 54 | ||
55 | EXPORT_SYMBOL_GPL(inet6_csk_bind_conflict); | 55 | EXPORT_SYMBOL_GPL(inet6_csk_bind_conflict); |
56 | 56 | ||
57 | struct dst_entry *inet6_csk_route_req(struct sock *sk, | ||
58 | const struct request_sock *req) | ||
59 | { | ||
60 | struct inet6_request_sock *treq = inet6_rsk(req); | ||
61 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
62 | struct in6_addr *final_p, final; | ||
63 | struct dst_entry *dst; | ||
64 | struct flowi6 fl6; | ||
65 | |||
66 | memset(&fl6, 0, sizeof(fl6)); | ||
67 | fl6.flowi6_proto = IPPROTO_TCP; | ||
68 | ipv6_addr_copy(&fl6.daddr, &treq->rmt_addr); | ||
69 | final_p = fl6_update_dst(&fl6, np->opt, &final); | ||
70 | ipv6_addr_copy(&fl6.saddr, &treq->loc_addr); | ||
71 | fl6.flowi6_oif = sk->sk_bound_dev_if; | ||
72 | fl6.flowi6_mark = sk->sk_mark; | ||
73 | fl6.fl6_dport = inet_rsk(req)->rmt_port; | ||
74 | fl6.fl6_sport = inet_rsk(req)->loc_port; | ||
75 | security_req_classify_flow(req, flowi6_to_flowi(&fl6)); | ||
76 | |||
77 | dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false); | ||
78 | if (IS_ERR(dst)) | ||
79 | return NULL; | ||
80 | |||
81 | return dst; | ||
82 | } | ||
83 | |||
57 | /* | 84 | /* |
58 | * request_sock (formerly open request) hash tables. | 85 | * request_sock (formerly open request) hash tables. |
59 | */ | 86 | */ |
60 | static u32 inet6_synq_hash(const struct in6_addr *raddr, const __be16 rport, | 87 | static u32 inet6_synq_hash(const struct in6_addr *raddr, const __be16 rport, |
61 | const u32 rnd, const u16 synq_hsize) | 88 | const u32 rnd, const u16 synq_hsize) |
62 | { | 89 | { |
63 | u32 a = (__force u32)raddr->s6_addr32[0]; | 90 | u32 c; |
64 | u32 b = (__force u32)raddr->s6_addr32[1]; | ||
65 | u32 c = (__force u32)raddr->s6_addr32[2]; | ||
66 | 91 | ||
67 | a += JHASH_GOLDEN_RATIO; | 92 | c = jhash_3words((__force u32)raddr->s6_addr32[0], |
68 | b += JHASH_GOLDEN_RATIO; | 93 | (__force u32)raddr->s6_addr32[1], |
69 | c += rnd; | 94 | (__force u32)raddr->s6_addr32[2], |
70 | __jhash_mix(a, b, c); | 95 | rnd); |
71 | 96 | ||
72 | a += (__force u32)raddr->s6_addr32[3]; | 97 | c = jhash_2words((__force u32)raddr->s6_addr32[3], |
73 | b += (__force u32)rport; | 98 | (__force u32)rport, |
74 | __jhash_mix(a, b, c); | 99 | c); |
75 | 100 | ||
76 | return c & (synq_hsize - 1); | 101 | return c & (synq_hsize - 1); |
77 | } | 102 | } |
@@ -178,47 +203,39 @@ struct dst_entry *__inet6_csk_dst_check(struct sock *sk, u32 cookie) | |||
178 | return dst; | 203 | return dst; |
179 | } | 204 | } |
180 | 205 | ||
181 | int inet6_csk_xmit(struct sk_buff *skb) | 206 | int inet6_csk_xmit(struct sk_buff *skb, struct flowi *fl_unused) |
182 | { | 207 | { |
183 | struct sock *sk = skb->sk; | 208 | struct sock *sk = skb->sk; |
184 | struct inet_sock *inet = inet_sk(sk); | 209 | struct inet_sock *inet = inet_sk(sk); |
185 | struct ipv6_pinfo *np = inet6_sk(sk); | 210 | struct ipv6_pinfo *np = inet6_sk(sk); |
186 | struct flowi fl; | 211 | struct flowi6 fl6; |
187 | struct dst_entry *dst; | 212 | struct dst_entry *dst; |
188 | struct in6_addr *final_p, final; | 213 | struct in6_addr *final_p, final; |
189 | 214 | ||
190 | memset(&fl, 0, sizeof(fl)); | 215 | memset(&fl6, 0, sizeof(fl6)); |
191 | fl.proto = sk->sk_protocol; | 216 | fl6.flowi6_proto = sk->sk_protocol; |
192 | ipv6_addr_copy(&fl.fl6_dst, &np->daddr); | 217 | ipv6_addr_copy(&fl6.daddr, &np->daddr); |
193 | ipv6_addr_copy(&fl.fl6_src, &np->saddr); | 218 | ipv6_addr_copy(&fl6.saddr, &np->saddr); |
194 | fl.fl6_flowlabel = np->flow_label; | 219 | fl6.flowlabel = np->flow_label; |
195 | IP6_ECN_flow_xmit(sk, fl.fl6_flowlabel); | 220 | IP6_ECN_flow_xmit(sk, fl6.flowlabel); |
196 | fl.oif = sk->sk_bound_dev_if; | 221 | fl6.flowi6_oif = sk->sk_bound_dev_if; |
197 | fl.mark = sk->sk_mark; | 222 | fl6.flowi6_mark = sk->sk_mark; |
198 | fl.fl_ip_sport = inet->inet_sport; | 223 | fl6.fl6_sport = inet->inet_sport; |
199 | fl.fl_ip_dport = inet->inet_dport; | 224 | fl6.fl6_dport = inet->inet_dport; |
200 | security_sk_classify_flow(sk, &fl); | 225 | security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); |
201 | 226 | ||
202 | final_p = fl6_update_dst(&fl, np->opt, &final); | 227 | final_p = fl6_update_dst(&fl6, np->opt, &final); |
203 | 228 | ||
204 | dst = __inet6_csk_dst_check(sk, np->dst_cookie); | 229 | dst = __inet6_csk_dst_check(sk, np->dst_cookie); |
205 | 230 | ||
206 | if (dst == NULL) { | 231 | if (dst == NULL) { |
207 | int err = ip6_dst_lookup(sk, &dst, &fl); | 232 | dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false); |
208 | |||
209 | if (err) { | ||
210 | sk->sk_err_soft = -err; | ||
211 | kfree_skb(skb); | ||
212 | return err; | ||
213 | } | ||
214 | |||
215 | if (final_p) | ||
216 | ipv6_addr_copy(&fl.fl6_dst, final_p); | ||
217 | 233 | ||
218 | if ((err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0) { | 234 | if (IS_ERR(dst)) { |
235 | sk->sk_err_soft = -PTR_ERR(dst); | ||
219 | sk->sk_route_caps = 0; | 236 | sk->sk_route_caps = 0; |
220 | kfree_skb(skb); | 237 | kfree_skb(skb); |
221 | return err; | 238 | return PTR_ERR(dst); |
222 | } | 239 | } |
223 | 240 | ||
224 | __inet6_csk_dst_store(sk, dst, NULL, NULL); | 241 | __inet6_csk_dst_store(sk, dst, NULL, NULL); |
@@ -227,9 +244,9 @@ int inet6_csk_xmit(struct sk_buff *skb) | |||
227 | skb_dst_set(skb, dst_clone(dst)); | 244 | skb_dst_set(skb, dst_clone(dst)); |
228 | 245 | ||
229 | /* Restore final destination back after routing done */ | 246 | /* Restore final destination back after routing done */ |
230 | ipv6_addr_copy(&fl.fl6_dst, &np->daddr); | 247 | ipv6_addr_copy(&fl6.daddr, &np->daddr); |
231 | 248 | ||
232 | return ip6_xmit(sk, skb, &fl, np->opt); | 249 | return ip6_xmit(sk, skb, &fl6, np->opt); |
233 | } | 250 | } |
234 | 251 | ||
235 | EXPORT_SYMBOL_GPL(inet6_csk_xmit); | 252 | EXPORT_SYMBOL_GPL(inet6_csk_xmit); |
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index 633a6c266136..b53197233709 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c | |||
@@ -124,7 +124,7 @@ out: | |||
124 | } | 124 | } |
125 | EXPORT_SYMBOL(__inet6_lookup_established); | 125 | EXPORT_SYMBOL(__inet6_lookup_established); |
126 | 126 | ||
127 | static int inline compute_score(struct sock *sk, struct net *net, | 127 | static inline int compute_score(struct sock *sk, struct net *net, |
128 | const unsigned short hnum, | 128 | const unsigned short hnum, |
129 | const struct in6_addr *daddr, | 129 | const struct in6_addr *daddr, |
130 | const int dif) | 130 | const int dif) |
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index b6a585909d35..4076a0b14b20 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c | |||
@@ -134,9 +134,9 @@ static __inline__ u32 fib6_new_sernum(void) | |||
134 | # define BITOP_BE32_SWIZZLE 0 | 134 | # define BITOP_BE32_SWIZZLE 0 |
135 | #endif | 135 | #endif |
136 | 136 | ||
137 | static __inline__ __be32 addr_bit_set(void *token, int fn_bit) | 137 | static __inline__ __be32 addr_bit_set(const void *token, int fn_bit) |
138 | { | 138 | { |
139 | __be32 *addr = token; | 139 | const __be32 *addr = token; |
140 | /* | 140 | /* |
141 | * Here, | 141 | * Here, |
142 | * 1 << ((~fn_bit ^ BITOP_BE32_SWIZZLE) & 0x1f) | 142 | * 1 << ((~fn_bit ^ BITOP_BE32_SWIZZLE) & 0x1f) |
@@ -260,10 +260,10 @@ struct fib6_table *fib6_get_table(struct net *net, u32 id) | |||
260 | return net->ipv6.fib6_main_tbl; | 260 | return net->ipv6.fib6_main_tbl; |
261 | } | 261 | } |
262 | 262 | ||
263 | struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl, | 263 | struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6, |
264 | int flags, pol_lookup_t lookup) | 264 | int flags, pol_lookup_t lookup) |
265 | { | 265 | { |
266 | return (struct dst_entry *) lookup(net, net->ipv6.fib6_main_tbl, fl, flags); | 266 | return (struct dst_entry *) lookup(net, net->ipv6.fib6_main_tbl, fl6, flags); |
267 | } | 267 | } |
268 | 268 | ||
269 | static void __net_init fib6_tables_init(struct net *net) | 269 | static void __net_init fib6_tables_init(struct net *net) |
@@ -394,10 +394,11 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) | |||
394 | arg.net = net; | 394 | arg.net = net; |
395 | w->args = &arg; | 395 | w->args = &arg; |
396 | 396 | ||
397 | rcu_read_lock(); | ||
397 | for (h = s_h; h < FIB6_TABLE_HASHSZ; h++, s_e = 0) { | 398 | for (h = s_h; h < FIB6_TABLE_HASHSZ; h++, s_e = 0) { |
398 | e = 0; | 399 | e = 0; |
399 | head = &net->ipv6.fib_table_hash[h]; | 400 | head = &net->ipv6.fib_table_hash[h]; |
400 | hlist_for_each_entry(tb, node, head, tb6_hlist) { | 401 | hlist_for_each_entry_rcu(tb, node, head, tb6_hlist) { |
401 | if (e < s_e) | 402 | if (e < s_e) |
402 | goto next; | 403 | goto next; |
403 | res = fib6_dump_table(tb, skb, cb); | 404 | res = fib6_dump_table(tb, skb, cb); |
@@ -408,6 +409,7 @@ next: | |||
408 | } | 409 | } |
409 | } | 410 | } |
410 | out: | 411 | out: |
412 | rcu_read_unlock(); | ||
411 | cb->args[1] = e; | 413 | cb->args[1] = e; |
412 | cb->args[0] = h; | 414 | cb->args[0] = h; |
413 | 415 | ||
@@ -822,7 +824,7 @@ st_failure: | |||
822 | 824 | ||
823 | struct lookup_args { | 825 | struct lookup_args { |
824 | int offset; /* key offset on rt6_info */ | 826 | int offset; /* key offset on rt6_info */ |
825 | struct in6_addr *addr; /* search key */ | 827 | const struct in6_addr *addr; /* search key */ |
826 | }; | 828 | }; |
827 | 829 | ||
828 | static struct fib6_node * fib6_lookup_1(struct fib6_node *root, | 830 | static struct fib6_node * fib6_lookup_1(struct fib6_node *root, |
@@ -881,8 +883,8 @@ static struct fib6_node * fib6_lookup_1(struct fib6_node *root, | |||
881 | return NULL; | 883 | return NULL; |
882 | } | 884 | } |
883 | 885 | ||
884 | struct fib6_node * fib6_lookup(struct fib6_node *root, struct in6_addr *daddr, | 886 | struct fib6_node * fib6_lookup(struct fib6_node *root, const struct in6_addr *daddr, |
885 | struct in6_addr *saddr) | 887 | const struct in6_addr *saddr) |
886 | { | 888 | { |
887 | struct fib6_node *fn; | 889 | struct fib6_node *fn; |
888 | struct lookup_args args[] = { | 890 | struct lookup_args args[] = { |
@@ -916,7 +918,7 @@ struct fib6_node * fib6_lookup(struct fib6_node *root, struct in6_addr *daddr, | |||
916 | 918 | ||
917 | 919 | ||
918 | static struct fib6_node * fib6_locate_1(struct fib6_node *root, | 920 | static struct fib6_node * fib6_locate_1(struct fib6_node *root, |
919 | struct in6_addr *addr, | 921 | const struct in6_addr *addr, |
920 | int plen, int offset) | 922 | int plen, int offset) |
921 | { | 923 | { |
922 | struct fib6_node *fn; | 924 | struct fib6_node *fn; |
@@ -946,8 +948,8 @@ static struct fib6_node * fib6_locate_1(struct fib6_node *root, | |||
946 | } | 948 | } |
947 | 949 | ||
948 | struct fib6_node * fib6_locate(struct fib6_node *root, | 950 | struct fib6_node * fib6_locate(struct fib6_node *root, |
949 | struct in6_addr *daddr, int dst_len, | 951 | const struct in6_addr *daddr, int dst_len, |
950 | struct in6_addr *saddr, int src_len) | 952 | const struct in6_addr *saddr, int src_len) |
951 | { | 953 | { |
952 | struct fib6_node *fn; | 954 | struct fib6_node *fn; |
953 | 955 | ||
@@ -1500,15 +1502,18 @@ static void fib6_gc_timer_cb(unsigned long arg) | |||
1500 | 1502 | ||
1501 | static int __net_init fib6_net_init(struct net *net) | 1503 | static int __net_init fib6_net_init(struct net *net) |
1502 | { | 1504 | { |
1505 | size_t size = sizeof(struct hlist_head) * FIB6_TABLE_HASHSZ; | ||
1506 | |||
1503 | setup_timer(&net->ipv6.ip6_fib_timer, fib6_gc_timer_cb, (unsigned long)net); | 1507 | setup_timer(&net->ipv6.ip6_fib_timer, fib6_gc_timer_cb, (unsigned long)net); |
1504 | 1508 | ||
1505 | net->ipv6.rt6_stats = kzalloc(sizeof(*net->ipv6.rt6_stats), GFP_KERNEL); | 1509 | net->ipv6.rt6_stats = kzalloc(sizeof(*net->ipv6.rt6_stats), GFP_KERNEL); |
1506 | if (!net->ipv6.rt6_stats) | 1510 | if (!net->ipv6.rt6_stats) |
1507 | goto out_timer; | 1511 | goto out_timer; |
1508 | 1512 | ||
1509 | net->ipv6.fib_table_hash = kcalloc(FIB6_TABLE_HASHSZ, | 1513 | /* Avoid false sharing : Use at least a full cache line */ |
1510 | sizeof(*net->ipv6.fib_table_hash), | 1514 | size = max_t(size_t, size, L1_CACHE_BYTES); |
1511 | GFP_KERNEL); | 1515 | |
1516 | net->ipv6.fib_table_hash = kzalloc(size, GFP_KERNEL); | ||
1512 | if (!net->ipv6.fib_table_hash) | 1517 | if (!net->ipv6.fib_table_hash) |
1513 | goto out_rt6_stats; | 1518 | goto out_rt6_stats; |
1514 | 1519 | ||
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 13654686aeab..f3caf1b8d572 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c | |||
@@ -342,7 +342,7 @@ fl_create(struct net *net, struct in6_flowlabel_req *freq, char __user *optval, | |||
342 | 342 | ||
343 | if (olen > 0) { | 343 | if (olen > 0) { |
344 | struct msghdr msg; | 344 | struct msghdr msg; |
345 | struct flowi flowi; | 345 | struct flowi6 flowi6; |
346 | int junk; | 346 | int junk; |
347 | 347 | ||
348 | err = -ENOMEM; | 348 | err = -ENOMEM; |
@@ -358,9 +358,9 @@ fl_create(struct net *net, struct in6_flowlabel_req *freq, char __user *optval, | |||
358 | 358 | ||
359 | msg.msg_controllen = olen; | 359 | msg.msg_controllen = olen; |
360 | msg.msg_control = (void*)(fl->opt+1); | 360 | msg.msg_control = (void*)(fl->opt+1); |
361 | flowi.oif = 0; | 361 | memset(&flowi6, 0, sizeof(flowi6)); |
362 | 362 | ||
363 | err = datagram_send_ctl(net, &msg, &flowi, fl->opt, &junk, | 363 | err = datagram_send_ctl(net, &msg, &flowi6, fl->opt, &junk, |
364 | &junk, &junk); | 364 | &junk, &junk); |
365 | if (err) | 365 | if (err) |
366 | goto done; | 366 | goto done; |
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index a83e9209cecc..027c7ff6f1e5 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c | |||
@@ -57,7 +57,7 @@ inline int ip6_rcv_finish( struct sk_buff *skb) | |||
57 | 57 | ||
58 | int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) | 58 | int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) |
59 | { | 59 | { |
60 | struct ipv6hdr *hdr; | 60 | const struct ipv6hdr *hdr; |
61 | u32 pkt_len; | 61 | u32 pkt_len; |
62 | struct inet6_dev *idev; | 62 | struct inet6_dev *idev; |
63 | struct net *net = dev_net(skb->dev); | 63 | struct net *net = dev_net(skb->dev); |
@@ -186,7 +186,7 @@ resubmit: | |||
186 | int ret; | 186 | int ret; |
187 | 187 | ||
188 | if (ipprot->flags & INET6_PROTO_FINAL) { | 188 | if (ipprot->flags & INET6_PROTO_FINAL) { |
189 | struct ipv6hdr *hdr; | 189 | const struct ipv6hdr *hdr; |
190 | 190 | ||
191 | /* Free reference early: we don't need it any more, | 191 | /* Free reference early: we don't need it any more, |
192 | and it may hold ip_conntrack module loaded | 192 | and it may hold ip_conntrack module loaded |
@@ -242,7 +242,7 @@ int ip6_input(struct sk_buff *skb) | |||
242 | 242 | ||
243 | int ip6_mc_input(struct sk_buff *skb) | 243 | int ip6_mc_input(struct sk_buff *skb) |
244 | { | 244 | { |
245 | struct ipv6hdr *hdr; | 245 | const struct ipv6hdr *hdr; |
246 | int deliver; | 246 | int deliver; |
247 | 247 | ||
248 | IP6_UPD_PO_STATS_BH(dev_net(skb_dst(skb)->dev), | 248 | IP6_UPD_PO_STATS_BH(dev_net(skb_dst(skb)->dev), |
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 980912ed7a38..9d4b165837d6 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -56,7 +56,7 @@ | |||
56 | #include <net/checksum.h> | 56 | #include <net/checksum.h> |
57 | #include <linux/mroute6.h> | 57 | #include <linux/mroute6.h> |
58 | 58 | ||
59 | static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)); | 59 | int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)); |
60 | 60 | ||
61 | int __ip6_local_out(struct sk_buff *skb) | 61 | int __ip6_local_out(struct sk_buff *skb) |
62 | { | 62 | { |
@@ -145,14 +145,6 @@ static int ip6_finish_output2(struct sk_buff *skb) | |||
145 | return -EINVAL; | 145 | return -EINVAL; |
146 | } | 146 | } |
147 | 147 | ||
148 | static inline int ip6_skb_dst_mtu(struct sk_buff *skb) | ||
149 | { | ||
150 | struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL; | ||
151 | |||
152 | return (np && np->pmtudisc == IPV6_PMTUDISC_PROBE) ? | ||
153 | skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb)); | ||
154 | } | ||
155 | |||
156 | static int ip6_finish_output(struct sk_buff *skb) | 148 | static int ip6_finish_output(struct sk_buff *skb) |
157 | { | 149 | { |
158 | if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) || | 150 | if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) || |
@@ -182,15 +174,15 @@ int ip6_output(struct sk_buff *skb) | |||
182 | * xmit an sk_buff (used by TCP, SCTP and DCCP) | 174 | * xmit an sk_buff (used by TCP, SCTP and DCCP) |
183 | */ | 175 | */ |
184 | 176 | ||
185 | int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, | 177 | int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, |
186 | struct ipv6_txoptions *opt) | 178 | struct ipv6_txoptions *opt) |
187 | { | 179 | { |
188 | struct net *net = sock_net(sk); | 180 | struct net *net = sock_net(sk); |
189 | struct ipv6_pinfo *np = inet6_sk(sk); | 181 | struct ipv6_pinfo *np = inet6_sk(sk); |
190 | struct in6_addr *first_hop = &fl->fl6_dst; | 182 | struct in6_addr *first_hop = &fl6->daddr; |
191 | struct dst_entry *dst = skb_dst(skb); | 183 | struct dst_entry *dst = skb_dst(skb); |
192 | struct ipv6hdr *hdr; | 184 | struct ipv6hdr *hdr; |
193 | u8 proto = fl->proto; | 185 | u8 proto = fl6->flowi6_proto; |
194 | int seg_len = skb->len; | 186 | int seg_len = skb->len; |
195 | int hlimit = -1; | 187 | int hlimit = -1; |
196 | int tclass = 0; | 188 | int tclass = 0; |
@@ -238,13 +230,13 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, | |||
238 | if (hlimit < 0) | 230 | if (hlimit < 0) |
239 | hlimit = ip6_dst_hoplimit(dst); | 231 | hlimit = ip6_dst_hoplimit(dst); |
240 | 232 | ||
241 | *(__be32 *)hdr = htonl(0x60000000 | (tclass << 20)) | fl->fl6_flowlabel; | 233 | *(__be32 *)hdr = htonl(0x60000000 | (tclass << 20)) | fl6->flowlabel; |
242 | 234 | ||
243 | hdr->payload_len = htons(seg_len); | 235 | hdr->payload_len = htons(seg_len); |
244 | hdr->nexthdr = proto; | 236 | hdr->nexthdr = proto; |
245 | hdr->hop_limit = hlimit; | 237 | hdr->hop_limit = hlimit; |
246 | 238 | ||
247 | ipv6_addr_copy(&hdr->saddr, &fl->fl6_src); | 239 | ipv6_addr_copy(&hdr->saddr, &fl6->saddr); |
248 | ipv6_addr_copy(&hdr->daddr, first_hop); | 240 | ipv6_addr_copy(&hdr->daddr, first_hop); |
249 | 241 | ||
250 | skb->priority = sk->sk_priority; | 242 | skb->priority = sk->sk_priority; |
@@ -282,13 +274,10 @@ int ip6_nd_hdr(struct sock *sk, struct sk_buff *skb, struct net_device *dev, | |||
282 | { | 274 | { |
283 | struct ipv6_pinfo *np = inet6_sk(sk); | 275 | struct ipv6_pinfo *np = inet6_sk(sk); |
284 | struct ipv6hdr *hdr; | 276 | struct ipv6hdr *hdr; |
285 | int totlen; | ||
286 | 277 | ||
287 | skb->protocol = htons(ETH_P_IPV6); | 278 | skb->protocol = htons(ETH_P_IPV6); |
288 | skb->dev = dev; | 279 | skb->dev = dev; |
289 | 280 | ||
290 | totlen = len + sizeof(struct ipv6hdr); | ||
291 | |||
292 | skb_reset_network_header(skb); | 281 | skb_reset_network_header(skb); |
293 | skb_put(skb, sizeof(struct ipv6hdr)); | 282 | skb_put(skb, sizeof(struct ipv6hdr)); |
294 | hdr = ipv6_hdr(skb); | 283 | hdr = ipv6_hdr(skb); |
@@ -409,6 +398,9 @@ int ip6_forward(struct sk_buff *skb) | |||
409 | goto drop; | 398 | goto drop; |
410 | } | 399 | } |
411 | 400 | ||
401 | if (skb->pkt_type != PACKET_HOST) | ||
402 | goto drop; | ||
403 | |||
412 | skb_forward_csum(skb); | 404 | skb_forward_csum(skb); |
413 | 405 | ||
414 | /* | 406 | /* |
@@ -484,10 +476,13 @@ int ip6_forward(struct sk_buff *skb) | |||
484 | else | 476 | else |
485 | target = &hdr->daddr; | 477 | target = &hdr->daddr; |
486 | 478 | ||
479 | if (!rt->rt6i_peer) | ||
480 | rt6_bind_peer(rt, 1); | ||
481 | |||
487 | /* Limit redirects both by destination (here) | 482 | /* Limit redirects both by destination (here) |
488 | and by source (inside ndisc_send_redirect) | 483 | and by source (inside ndisc_send_redirect) |
489 | */ | 484 | */ |
490 | if (xrlim_allow(dst, 1*HZ)) | 485 | if (inet_peer_xrlim_allow(rt->rt6i_peer, 1*HZ)) |
491 | ndisc_send_redirect(skb, n, target); | 486 | ndisc_send_redirect(skb, n, target); |
492 | } else { | 487 | } else { |
493 | int addrtype = ipv6_addr_type(&hdr->saddr); | 488 | int addrtype = ipv6_addr_type(&hdr->saddr); |
@@ -601,7 +596,7 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) | |||
601 | return offset; | 596 | return offset; |
602 | } | 597 | } |
603 | 598 | ||
604 | static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | 599 | int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) |
605 | { | 600 | { |
606 | struct sk_buff *frag; | 601 | struct sk_buff *frag; |
607 | struct rt6_info *rt = (struct rt6_info*)skb_dst(skb); | 602 | struct rt6_info *rt = (struct rt6_info*)skb_dst(skb); |
@@ -637,7 +632,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
637 | } | 632 | } |
638 | mtu -= hlen + sizeof(struct frag_hdr); | 633 | mtu -= hlen + sizeof(struct frag_hdr); |
639 | 634 | ||
640 | if (skb_has_frags(skb)) { | 635 | if (skb_has_frag_list(skb)) { |
641 | int first_len = skb_pagelen(skb); | 636 | int first_len = skb_pagelen(skb); |
642 | struct sk_buff *frag2; | 637 | struct sk_buff *frag2; |
643 | 638 | ||
@@ -784,7 +779,7 @@ slow_path: | |||
784 | /* IF: it doesn't fit, use 'mtu' - the data space left */ | 779 | /* IF: it doesn't fit, use 'mtu' - the data space left */ |
785 | if (len > mtu) | 780 | if (len > mtu) |
786 | len = mtu; | 781 | len = mtu; |
787 | /* IF: we are not sending upto and including the packet end | 782 | /* IF: we are not sending up to and including the packet end |
788 | then align the next start on an eight byte boundary */ | 783 | then align the next start on an eight byte boundary */ |
789 | if (len < left) { | 784 | if (len < left) { |
790 | len &= ~7; | 785 | len &= ~7; |
@@ -874,17 +869,17 @@ fail: | |||
874 | return err; | 869 | return err; |
875 | } | 870 | } |
876 | 871 | ||
877 | static inline int ip6_rt_check(struct rt6key *rt_key, | 872 | static inline int ip6_rt_check(const struct rt6key *rt_key, |
878 | struct in6_addr *fl_addr, | 873 | const struct in6_addr *fl_addr, |
879 | struct in6_addr *addr_cache) | 874 | const struct in6_addr *addr_cache) |
880 | { | 875 | { |
881 | return ((rt_key->plen != 128 || !ipv6_addr_equal(fl_addr, &rt_key->addr)) && | 876 | return (rt_key->plen != 128 || !ipv6_addr_equal(fl_addr, &rt_key->addr)) && |
882 | (addr_cache == NULL || !ipv6_addr_equal(fl_addr, addr_cache))); | 877 | (addr_cache == NULL || !ipv6_addr_equal(fl_addr, addr_cache)); |
883 | } | 878 | } |
884 | 879 | ||
885 | static struct dst_entry *ip6_sk_dst_check(struct sock *sk, | 880 | static struct dst_entry *ip6_sk_dst_check(struct sock *sk, |
886 | struct dst_entry *dst, | 881 | struct dst_entry *dst, |
887 | struct flowi *fl) | 882 | const struct flowi6 *fl6) |
888 | { | 883 | { |
889 | struct ipv6_pinfo *np = inet6_sk(sk); | 884 | struct ipv6_pinfo *np = inet6_sk(sk); |
890 | struct rt6_info *rt = (struct rt6_info *)dst; | 885 | struct rt6_info *rt = (struct rt6_info *)dst; |
@@ -909,11 +904,11 @@ static struct dst_entry *ip6_sk_dst_check(struct sock *sk, | |||
909 | * sockets. | 904 | * sockets. |
910 | * 2. oif also should be the same. | 905 | * 2. oif also should be the same. |
911 | */ | 906 | */ |
912 | if (ip6_rt_check(&rt->rt6i_dst, &fl->fl6_dst, np->daddr_cache) || | 907 | if (ip6_rt_check(&rt->rt6i_dst, &fl6->daddr, np->daddr_cache) || |
913 | #ifdef CONFIG_IPV6_SUBTREES | 908 | #ifdef CONFIG_IPV6_SUBTREES |
914 | ip6_rt_check(&rt->rt6i_src, &fl->fl6_src, np->saddr_cache) || | 909 | ip6_rt_check(&rt->rt6i_src, &fl6->saddr, np->saddr_cache) || |
915 | #endif | 910 | #endif |
916 | (fl->oif && fl->oif != dst->dev->ifindex)) { | 911 | (fl6->flowi6_oif && fl6->flowi6_oif != dst->dev->ifindex)) { |
917 | dst_release(dst); | 912 | dst_release(dst); |
918 | dst = NULL; | 913 | dst = NULL; |
919 | } | 914 | } |
@@ -923,22 +918,22 @@ out: | |||
923 | } | 918 | } |
924 | 919 | ||
925 | static int ip6_dst_lookup_tail(struct sock *sk, | 920 | static int ip6_dst_lookup_tail(struct sock *sk, |
926 | struct dst_entry **dst, struct flowi *fl) | 921 | struct dst_entry **dst, struct flowi6 *fl6) |
927 | { | 922 | { |
928 | int err; | 923 | int err; |
929 | struct net *net = sock_net(sk); | 924 | struct net *net = sock_net(sk); |
930 | 925 | ||
931 | if (*dst == NULL) | 926 | if (*dst == NULL) |
932 | *dst = ip6_route_output(net, sk, fl); | 927 | *dst = ip6_route_output(net, sk, fl6); |
933 | 928 | ||
934 | if ((err = (*dst)->error)) | 929 | if ((err = (*dst)->error)) |
935 | goto out_err_release; | 930 | goto out_err_release; |
936 | 931 | ||
937 | if (ipv6_addr_any(&fl->fl6_src)) { | 932 | if (ipv6_addr_any(&fl6->saddr)) { |
938 | err = ipv6_dev_get_saddr(net, ip6_dst_idev(*dst)->dev, | 933 | struct rt6_info *rt = (struct rt6_info *) *dst; |
939 | &fl->fl6_dst, | 934 | err = ip6_route_get_saddr(net, rt, &fl6->daddr, |
940 | sk ? inet6_sk(sk)->srcprefs : 0, | 935 | sk ? inet6_sk(sk)->srcprefs : 0, |
941 | &fl->fl6_src); | 936 | &fl6->saddr); |
942 | if (err) | 937 | if (err) |
943 | goto out_err_release; | 938 | goto out_err_release; |
944 | } | 939 | } |
@@ -954,10 +949,10 @@ static int ip6_dst_lookup_tail(struct sock *sk, | |||
954 | */ | 949 | */ |
955 | if ((*dst)->neighbour && !((*dst)->neighbour->nud_state & NUD_VALID)) { | 950 | if ((*dst)->neighbour && !((*dst)->neighbour->nud_state & NUD_VALID)) { |
956 | struct inet6_ifaddr *ifp; | 951 | struct inet6_ifaddr *ifp; |
957 | struct flowi fl_gw; | 952 | struct flowi6 fl_gw6; |
958 | int redirect; | 953 | int redirect; |
959 | 954 | ||
960 | ifp = ipv6_get_ifaddr(net, &fl->fl6_src, | 955 | ifp = ipv6_get_ifaddr(net, &fl6->saddr, |
961 | (*dst)->dev, 1); | 956 | (*dst)->dev, 1); |
962 | 957 | ||
963 | redirect = (ifp && ifp->flags & IFA_F_OPTIMISTIC); | 958 | redirect = (ifp && ifp->flags & IFA_F_OPTIMISTIC); |
@@ -970,9 +965,9 @@ static int ip6_dst_lookup_tail(struct sock *sk, | |||
970 | * default router instead | 965 | * default router instead |
971 | */ | 966 | */ |
972 | dst_release(*dst); | 967 | dst_release(*dst); |
973 | memcpy(&fl_gw, fl, sizeof(struct flowi)); | 968 | memcpy(&fl_gw6, fl6, sizeof(struct flowi6)); |
974 | memset(&fl_gw.fl6_dst, 0, sizeof(struct in6_addr)); | 969 | memset(&fl_gw6.daddr, 0, sizeof(struct in6_addr)); |
975 | *dst = ip6_route_output(net, sk, &fl_gw); | 970 | *dst = ip6_route_output(net, sk, &fl_gw6); |
976 | if ((err = (*dst)->error)) | 971 | if ((err = (*dst)->error)) |
977 | goto out_err_release; | 972 | goto out_err_release; |
978 | } | 973 | } |
@@ -993,43 +988,85 @@ out_err_release: | |||
993 | * ip6_dst_lookup - perform route lookup on flow | 988 | * ip6_dst_lookup - perform route lookup on flow |
994 | * @sk: socket which provides route info | 989 | * @sk: socket which provides route info |
995 | * @dst: pointer to dst_entry * for result | 990 | * @dst: pointer to dst_entry * for result |
996 | * @fl: flow to lookup | 991 | * @fl6: flow to lookup |
997 | * | 992 | * |
998 | * This function performs a route lookup on the given flow. | 993 | * This function performs a route lookup on the given flow. |
999 | * | 994 | * |
1000 | * It returns zero on success, or a standard errno code on error. | 995 | * It returns zero on success, or a standard errno code on error. |
1001 | */ | 996 | */ |
1002 | int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl) | 997 | int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi6 *fl6) |
1003 | { | 998 | { |
1004 | *dst = NULL; | 999 | *dst = NULL; |
1005 | return ip6_dst_lookup_tail(sk, dst, fl); | 1000 | return ip6_dst_lookup_tail(sk, dst, fl6); |
1006 | } | 1001 | } |
1007 | EXPORT_SYMBOL_GPL(ip6_dst_lookup); | 1002 | EXPORT_SYMBOL_GPL(ip6_dst_lookup); |
1008 | 1003 | ||
1009 | /** | 1004 | /** |
1010 | * ip6_sk_dst_lookup - perform socket cached route lookup on flow | 1005 | * ip6_dst_lookup_flow - perform route lookup on flow with ipsec |
1006 | * @sk: socket which provides route info | ||
1007 | * @fl6: flow to lookup | ||
1008 | * @final_dst: final destination address for ipsec lookup | ||
1009 | * @can_sleep: we are in a sleepable context | ||
1010 | * | ||
1011 | * This function performs a route lookup on the given flow. | ||
1012 | * | ||
1013 | * It returns a valid dst pointer on success, or a pointer encoded | ||
1014 | * error code. | ||
1015 | */ | ||
1016 | struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, | ||
1017 | const struct in6_addr *final_dst, | ||
1018 | bool can_sleep) | ||
1019 | { | ||
1020 | struct dst_entry *dst = NULL; | ||
1021 | int err; | ||
1022 | |||
1023 | err = ip6_dst_lookup_tail(sk, &dst, fl6); | ||
1024 | if (err) | ||
1025 | return ERR_PTR(err); | ||
1026 | if (final_dst) | ||
1027 | ipv6_addr_copy(&fl6->daddr, final_dst); | ||
1028 | if (can_sleep) | ||
1029 | fl6->flowi6_flags |= FLOWI_FLAG_CAN_SLEEP; | ||
1030 | |||
1031 | return xfrm_lookup(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0); | ||
1032 | } | ||
1033 | EXPORT_SYMBOL_GPL(ip6_dst_lookup_flow); | ||
1034 | |||
1035 | /** | ||
1036 | * ip6_sk_dst_lookup_flow - perform socket cached route lookup on flow | ||
1011 | * @sk: socket which provides the dst cache and route info | 1037 | * @sk: socket which provides the dst cache and route info |
1012 | * @dst: pointer to dst_entry * for result | 1038 | * @fl6: flow to lookup |
1013 | * @fl: flow to lookup | 1039 | * @final_dst: final destination address for ipsec lookup |
1040 | * @can_sleep: we are in a sleepable context | ||
1014 | * | 1041 | * |
1015 | * This function performs a route lookup on the given flow with the | 1042 | * This function performs a route lookup on the given flow with the |
1016 | * possibility of using the cached route in the socket if it is valid. | 1043 | * possibility of using the cached route in the socket if it is valid. |
1017 | * It will take the socket dst lock when operating on the dst cache. | 1044 | * It will take the socket dst lock when operating on the dst cache. |
1018 | * As a result, this function can only be used in process context. | 1045 | * As a result, this function can only be used in process context. |
1019 | * | 1046 | * |
1020 | * It returns zero on success, or a standard errno code on error. | 1047 | * It returns a valid dst pointer on success, or a pointer encoded |
1048 | * error code. | ||
1021 | */ | 1049 | */ |
1022 | int ip6_sk_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl) | 1050 | struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, |
1051 | const struct in6_addr *final_dst, | ||
1052 | bool can_sleep) | ||
1023 | { | 1053 | { |
1024 | *dst = NULL; | 1054 | struct dst_entry *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie); |
1025 | if (sk) { | 1055 | int err; |
1026 | *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie); | 1056 | |
1027 | *dst = ip6_sk_dst_check(sk, *dst, fl); | 1057 | dst = ip6_sk_dst_check(sk, dst, fl6); |
1028 | } | ||
1029 | 1058 | ||
1030 | return ip6_dst_lookup_tail(sk, dst, fl); | 1059 | err = ip6_dst_lookup_tail(sk, &dst, fl6); |
1060 | if (err) | ||
1061 | return ERR_PTR(err); | ||
1062 | if (final_dst) | ||
1063 | ipv6_addr_copy(&fl6->daddr, final_dst); | ||
1064 | if (can_sleep) | ||
1065 | fl6->flowi6_flags |= FLOWI_FLAG_CAN_SLEEP; | ||
1066 | |||
1067 | return xfrm_lookup(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0); | ||
1031 | } | 1068 | } |
1032 | EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup); | 1069 | EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow); |
1033 | 1070 | ||
1034 | static inline int ip6_ufo_append_data(struct sock *sk, | 1071 | static inline int ip6_ufo_append_data(struct sock *sk, |
1035 | int getfrag(void *from, char *to, int offset, int len, | 1072 | int getfrag(void *from, char *to, int offset, int len, |
@@ -1066,7 +1103,6 @@ static inline int ip6_ufo_append_data(struct sock *sk, | |||
1066 | 1103 | ||
1067 | skb->ip_summed = CHECKSUM_PARTIAL; | 1104 | skb->ip_summed = CHECKSUM_PARTIAL; |
1068 | skb->csum = 0; | 1105 | skb->csum = 0; |
1069 | sk->sk_sndmsg_off = 0; | ||
1070 | } | 1106 | } |
1071 | 1107 | ||
1072 | err = skb_append_datato_frags(sk,skb, getfrag, from, | 1108 | err = skb_append_datato_frags(sk,skb, getfrag, from, |
@@ -1109,11 +1145,12 @@ static inline struct ipv6_rt_hdr *ip6_rthdr_dup(struct ipv6_rt_hdr *src, | |||
1109 | int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | 1145 | int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, |
1110 | int offset, int len, int odd, struct sk_buff *skb), | 1146 | int offset, int len, int odd, struct sk_buff *skb), |
1111 | void *from, int length, int transhdrlen, | 1147 | void *from, int length, int transhdrlen, |
1112 | int hlimit, int tclass, struct ipv6_txoptions *opt, struct flowi *fl, | 1148 | int hlimit, int tclass, struct ipv6_txoptions *opt, struct flowi6 *fl6, |
1113 | struct rt6_info *rt, unsigned int flags, int dontfrag) | 1149 | struct rt6_info *rt, unsigned int flags, int dontfrag) |
1114 | { | 1150 | { |
1115 | struct inet_sock *inet = inet_sk(sk); | 1151 | struct inet_sock *inet = inet_sk(sk); |
1116 | struct ipv6_pinfo *np = inet6_sk(sk); | 1152 | struct ipv6_pinfo *np = inet6_sk(sk); |
1153 | struct inet_cork *cork; | ||
1117 | struct sk_buff *skb; | 1154 | struct sk_buff *skb; |
1118 | unsigned int maxfraglen, fragheaderlen; | 1155 | unsigned int maxfraglen, fragheaderlen; |
1119 | int exthdrlen; | 1156 | int exthdrlen; |
@@ -1123,9 +1160,11 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
1123 | int err; | 1160 | int err; |
1124 | int offset = 0; | 1161 | int offset = 0; |
1125 | int csummode = CHECKSUM_NONE; | 1162 | int csummode = CHECKSUM_NONE; |
1163 | __u8 tx_flags = 0; | ||
1126 | 1164 | ||
1127 | if (flags&MSG_PROBE) | 1165 | if (flags&MSG_PROBE) |
1128 | return 0; | 1166 | return 0; |
1167 | cork = &inet->cork.base; | ||
1129 | if (skb_queue_empty(&sk->sk_write_queue)) { | 1168 | if (skb_queue_empty(&sk->sk_write_queue)) { |
1130 | /* | 1169 | /* |
1131 | * setup for corking | 1170 | * setup for corking |
@@ -1165,8 +1204,8 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
1165 | /* need source address above miyazawa*/ | 1204 | /* need source address above miyazawa*/ |
1166 | } | 1205 | } |
1167 | dst_hold(&rt->dst); | 1206 | dst_hold(&rt->dst); |
1168 | inet->cork.dst = &rt->dst; | 1207 | cork->dst = &rt->dst; |
1169 | inet->cork.fl = *fl; | 1208 | inet->cork.fl.u.ip6 = *fl6; |
1170 | np->cork.hop_limit = hlimit; | 1209 | np->cork.hop_limit = hlimit; |
1171 | np->cork.tclass = tclass; | 1210 | np->cork.tclass = tclass; |
1172 | mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ? | 1211 | mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ? |
@@ -1175,10 +1214,10 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
1175 | if (np->frag_size) | 1214 | if (np->frag_size) |
1176 | mtu = np->frag_size; | 1215 | mtu = np->frag_size; |
1177 | } | 1216 | } |
1178 | inet->cork.fragsize = mtu; | 1217 | cork->fragsize = mtu; |
1179 | if (dst_allfrag(rt->dst.path)) | 1218 | if (dst_allfrag(rt->dst.path)) |
1180 | inet->cork.flags |= IPCORK_ALLFRAG; | 1219 | cork->flags |= IPCORK_ALLFRAG; |
1181 | inet->cork.length = 0; | 1220 | cork->length = 0; |
1182 | sk->sk_sndmsg_page = NULL; | 1221 | sk->sk_sndmsg_page = NULL; |
1183 | sk->sk_sndmsg_off = 0; | 1222 | sk->sk_sndmsg_off = 0; |
1184 | exthdrlen = rt->dst.header_len + (opt ? opt->opt_flen : 0) - | 1223 | exthdrlen = rt->dst.header_len + (opt ? opt->opt_flen : 0) - |
@@ -1186,12 +1225,12 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
1186 | length += exthdrlen; | 1225 | length += exthdrlen; |
1187 | transhdrlen += exthdrlen; | 1226 | transhdrlen += exthdrlen; |
1188 | } else { | 1227 | } else { |
1189 | rt = (struct rt6_info *)inet->cork.dst; | 1228 | rt = (struct rt6_info *)cork->dst; |
1190 | fl = &inet->cork.fl; | 1229 | fl6 = &inet->cork.fl.u.ip6; |
1191 | opt = np->cork.opt; | 1230 | opt = np->cork.opt; |
1192 | transhdrlen = 0; | 1231 | transhdrlen = 0; |
1193 | exthdrlen = 0; | 1232 | exthdrlen = 0; |
1194 | mtu = inet->cork.fragsize; | 1233 | mtu = cork->fragsize; |
1195 | } | 1234 | } |
1196 | 1235 | ||
1197 | hh_len = LL_RESERVED_SPACE(rt->dst.dev); | 1236 | hh_len = LL_RESERVED_SPACE(rt->dst.dev); |
@@ -1201,12 +1240,19 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
1201 | maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - sizeof(struct frag_hdr); | 1240 | maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - sizeof(struct frag_hdr); |
1202 | 1241 | ||
1203 | if (mtu <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN) { | 1242 | if (mtu <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN) { |
1204 | if (inet->cork.length + length > sizeof(struct ipv6hdr) + IPV6_MAXPLEN - fragheaderlen) { | 1243 | if (cork->length + length > sizeof(struct ipv6hdr) + IPV6_MAXPLEN - fragheaderlen) { |
1205 | ipv6_local_error(sk, EMSGSIZE, fl, mtu-exthdrlen); | 1244 | ipv6_local_error(sk, EMSGSIZE, fl6, mtu-exthdrlen); |
1206 | return -EMSGSIZE; | 1245 | return -EMSGSIZE; |
1207 | } | 1246 | } |
1208 | } | 1247 | } |
1209 | 1248 | ||
1249 | /* For UDP, check if TX timestamp is enabled */ | ||
1250 | if (sk->sk_type == SOCK_DGRAM) { | ||
1251 | err = sock_tx_timestamp(sk, &tx_flags); | ||
1252 | if (err) | ||
1253 | goto error; | ||
1254 | } | ||
1255 | |||
1210 | /* | 1256 | /* |
1211 | * Let's try using as much space as possible. | 1257 | * Let's try using as much space as possible. |
1212 | * Use MTU if total length of the message fits into the MTU. | 1258 | * Use MTU if total length of the message fits into the MTU. |
@@ -1223,11 +1269,11 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
1223 | * --yoshfuji | 1269 | * --yoshfuji |
1224 | */ | 1270 | */ |
1225 | 1271 | ||
1226 | inet->cork.length += length; | 1272 | cork->length += length; |
1227 | if (length > mtu) { | 1273 | if (length > mtu) { |
1228 | int proto = sk->sk_protocol; | 1274 | int proto = sk->sk_protocol; |
1229 | if (dontfrag && (proto == IPPROTO_UDP || proto == IPPROTO_RAW)){ | 1275 | if (dontfrag && (proto == IPPROTO_UDP || proto == IPPROTO_RAW)){ |
1230 | ipv6_local_rxpmtu(sk, fl, mtu-exthdrlen); | 1276 | ipv6_local_rxpmtu(sk, fl6, mtu-exthdrlen); |
1231 | return -EMSGSIZE; | 1277 | return -EMSGSIZE; |
1232 | } | 1278 | } |
1233 | 1279 | ||
@@ -1248,7 +1294,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
1248 | 1294 | ||
1249 | while (length > 0) { | 1295 | while (length > 0) { |
1250 | /* Check if the remaining data fits into current packet. */ | 1296 | /* Check if the remaining data fits into current packet. */ |
1251 | copy = (inet->cork.length <= mtu && !(inet->cork.flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - skb->len; | 1297 | copy = (cork->length <= mtu && !(cork->flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - skb->len; |
1252 | if (copy < length) | 1298 | if (copy < length) |
1253 | copy = maxfraglen - skb->len; | 1299 | copy = maxfraglen - skb->len; |
1254 | 1300 | ||
@@ -1273,7 +1319,7 @@ alloc_new_skb: | |||
1273 | * we know we need more fragment(s). | 1319 | * we know we need more fragment(s). |
1274 | */ | 1320 | */ |
1275 | datalen = length + fraggap; | 1321 | datalen = length + fraggap; |
1276 | if (datalen > (inet->cork.length <= mtu && !(inet->cork.flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - fragheaderlen) | 1322 | if (datalen > (cork->length <= mtu && !(cork->flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - fragheaderlen) |
1277 | datalen = maxfraglen - fragheaderlen; | 1323 | datalen = maxfraglen - fragheaderlen; |
1278 | 1324 | ||
1279 | fraglen = datalen + fragheaderlen; | 1325 | fraglen = datalen + fragheaderlen; |
@@ -1311,6 +1357,12 @@ alloc_new_skb: | |||
1311 | sk->sk_allocation); | 1357 | sk->sk_allocation); |
1312 | if (unlikely(skb == NULL)) | 1358 | if (unlikely(skb == NULL)) |
1313 | err = -ENOBUFS; | 1359 | err = -ENOBUFS; |
1360 | else { | ||
1361 | /* Only the initial fragment | ||
1362 | * is time stamped. | ||
1363 | */ | ||
1364 | tx_flags = 0; | ||
1365 | } | ||
1314 | } | 1366 | } |
1315 | if (skb == NULL) | 1367 | if (skb == NULL) |
1316 | goto error; | 1368 | goto error; |
@@ -1322,6 +1374,9 @@ alloc_new_skb: | |||
1322 | /* reserve for fragmentation */ | 1374 | /* reserve for fragmentation */ |
1323 | skb_reserve(skb, hh_len+sizeof(struct frag_hdr)); | 1375 | skb_reserve(skb, hh_len+sizeof(struct frag_hdr)); |
1324 | 1376 | ||
1377 | if (sk->sk_type == SOCK_DGRAM) | ||
1378 | skb_shinfo(skb)->tx_flags = tx_flags; | ||
1379 | |||
1325 | /* | 1380 | /* |
1326 | * Find where to start putting bytes | 1381 | * Find where to start putting bytes |
1327 | */ | 1382 | */ |
@@ -1428,7 +1483,7 @@ alloc_new_skb: | |||
1428 | } | 1483 | } |
1429 | return 0; | 1484 | return 0; |
1430 | error: | 1485 | error: |
1431 | inet->cork.length -= length; | 1486 | cork->length -= length; |
1432 | IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); | 1487 | IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); |
1433 | return err; | 1488 | return err; |
1434 | } | 1489 | } |
@@ -1444,10 +1499,10 @@ static void ip6_cork_release(struct inet_sock *inet, struct ipv6_pinfo *np) | |||
1444 | np->cork.opt = NULL; | 1499 | np->cork.opt = NULL; |
1445 | } | 1500 | } |
1446 | 1501 | ||
1447 | if (inet->cork.dst) { | 1502 | if (inet->cork.base.dst) { |
1448 | dst_release(inet->cork.dst); | 1503 | dst_release(inet->cork.base.dst); |
1449 | inet->cork.dst = NULL; | 1504 | inet->cork.base.dst = NULL; |
1450 | inet->cork.flags &= ~IPCORK_ALLFRAG; | 1505 | inet->cork.base.flags &= ~IPCORK_ALLFRAG; |
1451 | } | 1506 | } |
1452 | memset(&inet->cork.fl, 0, sizeof(inet->cork.fl)); | 1507 | memset(&inet->cork.fl, 0, sizeof(inet->cork.fl)); |
1453 | } | 1508 | } |
@@ -1462,9 +1517,9 @@ int ip6_push_pending_frames(struct sock *sk) | |||
1462 | struct net *net = sock_net(sk); | 1517 | struct net *net = sock_net(sk); |
1463 | struct ipv6hdr *hdr; | 1518 | struct ipv6hdr *hdr; |
1464 | struct ipv6_txoptions *opt = np->cork.opt; | 1519 | struct ipv6_txoptions *opt = np->cork.opt; |
1465 | struct rt6_info *rt = (struct rt6_info *)inet->cork.dst; | 1520 | struct rt6_info *rt = (struct rt6_info *)inet->cork.base.dst; |
1466 | struct flowi *fl = &inet->cork.fl; | 1521 | struct flowi6 *fl6 = &inet->cork.fl.u.ip6; |
1467 | unsigned char proto = fl->proto; | 1522 | unsigned char proto = fl6->flowi6_proto; |
1468 | int err = 0; | 1523 | int err = 0; |
1469 | 1524 | ||
1470 | if ((skb = __skb_dequeue(&sk->sk_write_queue)) == NULL) | 1525 | if ((skb = __skb_dequeue(&sk->sk_write_queue)) == NULL) |
@@ -1489,7 +1544,7 @@ int ip6_push_pending_frames(struct sock *sk) | |||
1489 | if (np->pmtudisc < IPV6_PMTUDISC_DO) | 1544 | if (np->pmtudisc < IPV6_PMTUDISC_DO) |
1490 | skb->local_df = 1; | 1545 | skb->local_df = 1; |
1491 | 1546 | ||
1492 | ipv6_addr_copy(final_dst, &fl->fl6_dst); | 1547 | ipv6_addr_copy(final_dst, &fl6->daddr); |
1493 | __skb_pull(skb, skb_network_header_len(skb)); | 1548 | __skb_pull(skb, skb_network_header_len(skb)); |
1494 | if (opt && opt->opt_flen) | 1549 | if (opt && opt->opt_flen) |
1495 | ipv6_push_frag_opts(skb, opt, &proto); | 1550 | ipv6_push_frag_opts(skb, opt, &proto); |
@@ -1500,12 +1555,12 @@ int ip6_push_pending_frames(struct sock *sk) | |||
1500 | skb_reset_network_header(skb); | 1555 | skb_reset_network_header(skb); |
1501 | hdr = ipv6_hdr(skb); | 1556 | hdr = ipv6_hdr(skb); |
1502 | 1557 | ||
1503 | *(__be32*)hdr = fl->fl6_flowlabel | | 1558 | *(__be32*)hdr = fl6->flowlabel | |
1504 | htonl(0x60000000 | ((int)np->cork.tclass << 20)); | 1559 | htonl(0x60000000 | ((int)np->cork.tclass << 20)); |
1505 | 1560 | ||
1506 | hdr->hop_limit = np->cork.hop_limit; | 1561 | hdr->hop_limit = np->cork.hop_limit; |
1507 | hdr->nexthdr = proto; | 1562 | hdr->nexthdr = proto; |
1508 | ipv6_addr_copy(&hdr->saddr, &fl->fl6_src); | 1563 | ipv6_addr_copy(&hdr->saddr, &fl6->saddr); |
1509 | ipv6_addr_copy(&hdr->daddr, final_dst); | 1564 | ipv6_addr_copy(&hdr->daddr, final_dst); |
1510 | 1565 | ||
1511 | skb->priority = sk->sk_priority; | 1566 | skb->priority = sk->sk_priority; |
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 0fd027f3f47e..36c2842a86b2 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c | |||
@@ -57,8 +57,7 @@ | |||
57 | MODULE_AUTHOR("Ville Nuorvala"); | 57 | MODULE_AUTHOR("Ville Nuorvala"); |
58 | MODULE_DESCRIPTION("IPv6 tunneling device"); | 58 | MODULE_DESCRIPTION("IPv6 tunneling device"); |
59 | MODULE_LICENSE("GPL"); | 59 | MODULE_LICENSE("GPL"); |
60 | 60 | MODULE_ALIAS_NETDEV("ip6tnl0"); | |
61 | #define IPV6_TLV_TEL_DST_SIZE 8 | ||
62 | 61 | ||
63 | #ifdef IP6_TNL_DEBUG | 62 | #ifdef IP6_TNL_DEBUG |
64 | #define IP6_TNL_TRACE(x...) printk(KERN_DEBUG "%s:" x "\n", __func__) | 63 | #define IP6_TNL_TRACE(x...) printk(KERN_DEBUG "%s:" x "\n", __func__) |
@@ -75,7 +74,7 @@ MODULE_LICENSE("GPL"); | |||
75 | (addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \ | 74 | (addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \ |
76 | (HASH_SIZE - 1)) | 75 | (HASH_SIZE - 1)) |
77 | 76 | ||
78 | static void ip6_tnl_dev_init(struct net_device *dev); | 77 | static int ip6_tnl_dev_init(struct net_device *dev); |
79 | static void ip6_tnl_dev_setup(struct net_device *dev); | 78 | static void ip6_tnl_dev_setup(struct net_device *dev); |
80 | 79 | ||
81 | static int ip6_tnl_net_id __read_mostly; | 80 | static int ip6_tnl_net_id __read_mostly; |
@@ -83,15 +82,42 @@ struct ip6_tnl_net { | |||
83 | /* the IPv6 tunnel fallback device */ | 82 | /* the IPv6 tunnel fallback device */ |
84 | struct net_device *fb_tnl_dev; | 83 | struct net_device *fb_tnl_dev; |
85 | /* lists for storing tunnels in use */ | 84 | /* lists for storing tunnels in use */ |
86 | struct ip6_tnl *tnls_r_l[HASH_SIZE]; | 85 | struct ip6_tnl __rcu *tnls_r_l[HASH_SIZE]; |
87 | struct ip6_tnl *tnls_wc[1]; | 86 | struct ip6_tnl __rcu *tnls_wc[1]; |
88 | struct ip6_tnl **tnls[2]; | 87 | struct ip6_tnl __rcu **tnls[2]; |
88 | }; | ||
89 | |||
90 | /* often modified stats are per cpu, other are shared (netdev->stats) */ | ||
91 | struct pcpu_tstats { | ||
92 | unsigned long rx_packets; | ||
93 | unsigned long rx_bytes; | ||
94 | unsigned long tx_packets; | ||
95 | unsigned long tx_bytes; | ||
89 | }; | 96 | }; |
90 | 97 | ||
98 | static struct net_device_stats *ip6_get_stats(struct net_device *dev) | ||
99 | { | ||
100 | struct pcpu_tstats sum = { 0 }; | ||
101 | int i; | ||
102 | |||
103 | for_each_possible_cpu(i) { | ||
104 | const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i); | ||
105 | |||
106 | sum.rx_packets += tstats->rx_packets; | ||
107 | sum.rx_bytes += tstats->rx_bytes; | ||
108 | sum.tx_packets += tstats->tx_packets; | ||
109 | sum.tx_bytes += tstats->tx_bytes; | ||
110 | } | ||
111 | dev->stats.rx_packets = sum.rx_packets; | ||
112 | dev->stats.rx_bytes = sum.rx_bytes; | ||
113 | dev->stats.tx_packets = sum.tx_packets; | ||
114 | dev->stats.tx_bytes = sum.tx_bytes; | ||
115 | return &dev->stats; | ||
116 | } | ||
117 | |||
91 | /* | 118 | /* |
92 | * Locking : hash tables are protected by RCU and a spinlock | 119 | * Locking : hash tables are protected by RCU and RTNL |
93 | */ | 120 | */ |
94 | static DEFINE_SPINLOCK(ip6_tnl_lock); | ||
95 | 121 | ||
96 | static inline struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t) | 122 | static inline struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t) |
97 | { | 123 | { |
@@ -136,10 +162,10 @@ static inline void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst) | |||
136 | for (t = rcu_dereference(start); t; t = rcu_dereference(t->next)) | 162 | for (t = rcu_dereference(start); t; t = rcu_dereference(t->next)) |
137 | 163 | ||
138 | static struct ip6_tnl * | 164 | static struct ip6_tnl * |
139 | ip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local) | 165 | ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_addr *local) |
140 | { | 166 | { |
141 | unsigned h0 = HASH(remote); | 167 | unsigned int h0 = HASH(remote); |
142 | unsigned h1 = HASH(local); | 168 | unsigned int h1 = HASH(local); |
143 | struct ip6_tnl *t; | 169 | struct ip6_tnl *t; |
144 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | 170 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); |
145 | 171 | ||
@@ -167,11 +193,11 @@ ip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local) | |||
167 | * Return: head of IPv6 tunnel list | 193 | * Return: head of IPv6 tunnel list |
168 | **/ | 194 | **/ |
169 | 195 | ||
170 | static struct ip6_tnl ** | 196 | static struct ip6_tnl __rcu ** |
171 | ip6_tnl_bucket(struct ip6_tnl_net *ip6n, struct ip6_tnl_parm *p) | 197 | ip6_tnl_bucket(struct ip6_tnl_net *ip6n, const struct ip6_tnl_parm *p) |
172 | { | 198 | { |
173 | struct in6_addr *remote = &p->raddr; | 199 | const struct in6_addr *remote = &p->raddr; |
174 | struct in6_addr *local = &p->laddr; | 200 | const struct in6_addr *local = &p->laddr; |
175 | unsigned h = 0; | 201 | unsigned h = 0; |
176 | int prio = 0; | 202 | int prio = 0; |
177 | 203 | ||
@@ -190,12 +216,10 @@ ip6_tnl_bucket(struct ip6_tnl_net *ip6n, struct ip6_tnl_parm *p) | |||
190 | static void | 216 | static void |
191 | ip6_tnl_link(struct ip6_tnl_net *ip6n, struct ip6_tnl *t) | 217 | ip6_tnl_link(struct ip6_tnl_net *ip6n, struct ip6_tnl *t) |
192 | { | 218 | { |
193 | struct ip6_tnl **tp = ip6_tnl_bucket(ip6n, &t->parms); | 219 | struct ip6_tnl __rcu **tp = ip6_tnl_bucket(ip6n, &t->parms); |
194 | 220 | ||
195 | spin_lock_bh(&ip6_tnl_lock); | 221 | rcu_assign_pointer(t->next , rtnl_dereference(*tp)); |
196 | t->next = *tp; | ||
197 | rcu_assign_pointer(*tp, t); | 222 | rcu_assign_pointer(*tp, t); |
198 | spin_unlock_bh(&ip6_tnl_lock); | ||
199 | } | 223 | } |
200 | 224 | ||
201 | /** | 225 | /** |
@@ -206,18 +230,25 @@ ip6_tnl_link(struct ip6_tnl_net *ip6n, struct ip6_tnl *t) | |||
206 | static void | 230 | static void |
207 | ip6_tnl_unlink(struct ip6_tnl_net *ip6n, struct ip6_tnl *t) | 231 | ip6_tnl_unlink(struct ip6_tnl_net *ip6n, struct ip6_tnl *t) |
208 | { | 232 | { |
209 | struct ip6_tnl **tp; | 233 | struct ip6_tnl __rcu **tp; |
210 | 234 | struct ip6_tnl *iter; | |
211 | for (tp = ip6_tnl_bucket(ip6n, &t->parms); *tp; tp = &(*tp)->next) { | 235 | |
212 | if (t == *tp) { | 236 | for (tp = ip6_tnl_bucket(ip6n, &t->parms); |
213 | spin_lock_bh(&ip6_tnl_lock); | 237 | (iter = rtnl_dereference(*tp)) != NULL; |
214 | *tp = t->next; | 238 | tp = &iter->next) { |
215 | spin_unlock_bh(&ip6_tnl_lock); | 239 | if (t == iter) { |
240 | rcu_assign_pointer(*tp, t->next); | ||
216 | break; | 241 | break; |
217 | } | 242 | } |
218 | } | 243 | } |
219 | } | 244 | } |
220 | 245 | ||
246 | static void ip6_dev_free(struct net_device *dev) | ||
247 | { | ||
248 | free_percpu(dev->tstats); | ||
249 | free_netdev(dev); | ||
250 | } | ||
251 | |||
221 | /** | 252 | /** |
222 | * ip6_tnl_create() - create a new tunnel | 253 | * ip6_tnl_create() - create a new tunnel |
223 | * @p: tunnel parameters | 254 | * @p: tunnel parameters |
@@ -249,14 +280,11 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct ip6_tnl_parm *p) | |||
249 | 280 | ||
250 | dev_net_set(dev, net); | 281 | dev_net_set(dev, net); |
251 | 282 | ||
252 | if (strchr(name, '%')) { | ||
253 | if (dev_alloc_name(dev, name) < 0) | ||
254 | goto failed_free; | ||
255 | } | ||
256 | |||
257 | t = netdev_priv(dev); | 283 | t = netdev_priv(dev); |
258 | t->parms = *p; | 284 | t->parms = *p; |
259 | ip6_tnl_dev_init(dev); | 285 | err = ip6_tnl_dev_init(dev); |
286 | if (err < 0) | ||
287 | goto failed_free; | ||
260 | 288 | ||
261 | if ((err = register_netdevice(dev)) < 0) | 289 | if ((err = register_netdevice(dev)) < 0) |
262 | goto failed_free; | 290 | goto failed_free; |
@@ -266,7 +294,7 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct ip6_tnl_parm *p) | |||
266 | return t; | 294 | return t; |
267 | 295 | ||
268 | failed_free: | 296 | failed_free: |
269 | free_netdev(dev); | 297 | ip6_dev_free(dev); |
270 | failed: | 298 | failed: |
271 | return NULL; | 299 | return NULL; |
272 | } | 300 | } |
@@ -288,12 +316,15 @@ failed: | |||
288 | static struct ip6_tnl *ip6_tnl_locate(struct net *net, | 316 | static struct ip6_tnl *ip6_tnl_locate(struct net *net, |
289 | struct ip6_tnl_parm *p, int create) | 317 | struct ip6_tnl_parm *p, int create) |
290 | { | 318 | { |
291 | struct in6_addr *remote = &p->raddr; | 319 | const struct in6_addr *remote = &p->raddr; |
292 | struct in6_addr *local = &p->laddr; | 320 | const struct in6_addr *local = &p->laddr; |
321 | struct ip6_tnl __rcu **tp; | ||
293 | struct ip6_tnl *t; | 322 | struct ip6_tnl *t; |
294 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | 323 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); |
295 | 324 | ||
296 | for (t = *ip6_tnl_bucket(ip6n, p); t; t = t->next) { | 325 | for (tp = ip6_tnl_bucket(ip6n, p); |
326 | (t = rtnl_dereference(*tp)) != NULL; | ||
327 | tp = &t->next) { | ||
297 | if (ipv6_addr_equal(local, &t->parms.laddr) && | 328 | if (ipv6_addr_equal(local, &t->parms.laddr) && |
298 | ipv6_addr_equal(remote, &t->parms.raddr)) | 329 | ipv6_addr_equal(remote, &t->parms.raddr)) |
299 | return t; | 330 | return t; |
@@ -318,13 +349,10 @@ ip6_tnl_dev_uninit(struct net_device *dev) | |||
318 | struct net *net = dev_net(dev); | 349 | struct net *net = dev_net(dev); |
319 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | 350 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); |
320 | 351 | ||
321 | if (dev == ip6n->fb_tnl_dev) { | 352 | if (dev == ip6n->fb_tnl_dev) |
322 | spin_lock_bh(&ip6_tnl_lock); | 353 | rcu_assign_pointer(ip6n->tnls_wc[0], NULL); |
323 | ip6n->tnls_wc[0] = NULL; | 354 | else |
324 | spin_unlock_bh(&ip6_tnl_lock); | ||
325 | } else { | ||
326 | ip6_tnl_unlink(ip6n, t); | 355 | ip6_tnl_unlink(ip6n, t); |
327 | } | ||
328 | ip6_tnl_dst_reset(t); | 356 | ip6_tnl_dst_reset(t); |
329 | dev_put(dev); | 357 | dev_put(dev); |
330 | } | 358 | } |
@@ -341,7 +369,7 @@ ip6_tnl_dev_uninit(struct net_device *dev) | |||
341 | static __u16 | 369 | static __u16 |
342 | parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw) | 370 | parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw) |
343 | { | 371 | { |
344 | struct ipv6hdr *ipv6h = (struct ipv6hdr *) raw; | 372 | const struct ipv6hdr *ipv6h = (const struct ipv6hdr *) raw; |
345 | __u8 nexthdr = ipv6h->nexthdr; | 373 | __u8 nexthdr = ipv6h->nexthdr; |
346 | __u16 off = sizeof (*ipv6h); | 374 | __u16 off = sizeof (*ipv6h); |
347 | 375 | ||
@@ -402,7 +430,7 @@ static int | |||
402 | ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt, | 430 | ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt, |
403 | u8 *type, u8 *code, int *msg, __u32 *info, int offset) | 431 | u8 *type, u8 *code, int *msg, __u32 *info, int offset) |
404 | { | 432 | { |
405 | struct ipv6hdr *ipv6h = (struct ipv6hdr *) skb->data; | 433 | const struct ipv6hdr *ipv6h = (const struct ipv6hdr *) skb->data; |
406 | struct ip6_tnl *t; | 434 | struct ip6_tnl *t; |
407 | int rel_msg = 0; | 435 | int rel_msg = 0; |
408 | u8 rel_type = ICMPV6_DEST_UNREACH; | 436 | u8 rel_type = ICMPV6_DEST_UNREACH; |
@@ -502,9 +530,9 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
502 | __u32 rel_info = ntohl(info); | 530 | __u32 rel_info = ntohl(info); |
503 | int err; | 531 | int err; |
504 | struct sk_buff *skb2; | 532 | struct sk_buff *skb2; |
505 | struct iphdr *eiph; | 533 | const struct iphdr *eiph; |
506 | struct flowi fl; | ||
507 | struct rtable *rt; | 534 | struct rtable *rt; |
535 | struct flowi4 fl4; | ||
508 | 536 | ||
509 | err = ip6_tnl_err(skb, IPPROTO_IPIP, opt, &rel_type, &rel_code, | 537 | err = ip6_tnl_err(skb, IPPROTO_IPIP, opt, &rel_type, &rel_code, |
510 | &rel_msg, &rel_info, offset); | 538 | &rel_msg, &rel_info, offset); |
@@ -545,11 +573,11 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
545 | eiph = ip_hdr(skb2); | 573 | eiph = ip_hdr(skb2); |
546 | 574 | ||
547 | /* Try to guess incoming interface */ | 575 | /* Try to guess incoming interface */ |
548 | memset(&fl, 0, sizeof(fl)); | 576 | rt = ip_route_output_ports(dev_net(skb->dev), &fl4, NULL, |
549 | fl.fl4_dst = eiph->saddr; | 577 | eiph->saddr, 0, |
550 | fl.fl4_tos = RT_TOS(eiph->tos); | 578 | 0, 0, |
551 | fl.proto = IPPROTO_IPIP; | 579 | IPPROTO_IPIP, RT_TOS(eiph->tos), 0); |
552 | if (ip_route_output_key(dev_net(skb->dev), &rt, &fl)) | 580 | if (IS_ERR(rt)) |
553 | goto out; | 581 | goto out; |
554 | 582 | ||
555 | skb2->dev = rt->dst.dev; | 583 | skb2->dev = rt->dst.dev; |
@@ -558,15 +586,18 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
558 | if (rt->rt_flags & RTCF_LOCAL) { | 586 | if (rt->rt_flags & RTCF_LOCAL) { |
559 | ip_rt_put(rt); | 587 | ip_rt_put(rt); |
560 | rt = NULL; | 588 | rt = NULL; |
561 | fl.fl4_dst = eiph->daddr; | 589 | rt = ip_route_output_ports(dev_net(skb->dev), &fl4, NULL, |
562 | fl.fl4_src = eiph->saddr; | 590 | eiph->daddr, eiph->saddr, |
563 | fl.fl4_tos = eiph->tos; | 591 | 0, 0, |
564 | if (ip_route_output_key(dev_net(skb->dev), &rt, &fl) || | 592 | IPPROTO_IPIP, |
593 | RT_TOS(eiph->tos), 0); | ||
594 | if (IS_ERR(rt) || | ||
565 | rt->dst.dev->type != ARPHRD_TUNNEL) { | 595 | rt->dst.dev->type != ARPHRD_TUNNEL) { |
566 | ip_rt_put(rt); | 596 | if (!IS_ERR(rt)) |
597 | ip_rt_put(rt); | ||
567 | goto out; | 598 | goto out; |
568 | } | 599 | } |
569 | skb_dst_set(skb2, (struct dst_entry *)rt); | 600 | skb_dst_set(skb2, &rt->dst); |
570 | } else { | 601 | } else { |
571 | ip_rt_put(rt); | 602 | ip_rt_put(rt); |
572 | if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos, | 603 | if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos, |
@@ -634,8 +665,8 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
634 | return 0; | 665 | return 0; |
635 | } | 666 | } |
636 | 667 | ||
637 | static void ip4ip6_dscp_ecn_decapsulate(struct ip6_tnl *t, | 668 | static void ip4ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t, |
638 | struct ipv6hdr *ipv6h, | 669 | const struct ipv6hdr *ipv6h, |
639 | struct sk_buff *skb) | 670 | struct sk_buff *skb) |
640 | { | 671 | { |
641 | __u8 dsfield = ipv6_get_dsfield(ipv6h) & ~INET_ECN_MASK; | 672 | __u8 dsfield = ipv6_get_dsfield(ipv6h) & ~INET_ECN_MASK; |
@@ -647,8 +678,8 @@ static void ip4ip6_dscp_ecn_decapsulate(struct ip6_tnl *t, | |||
647 | IP_ECN_set_ce(ip_hdr(skb)); | 678 | IP_ECN_set_ce(ip_hdr(skb)); |
648 | } | 679 | } |
649 | 680 | ||
650 | static void ip6ip6_dscp_ecn_decapsulate(struct ip6_tnl *t, | 681 | static void ip6ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t, |
651 | struct ipv6hdr *ipv6h, | 682 | const struct ipv6hdr *ipv6h, |
652 | struct sk_buff *skb) | 683 | struct sk_buff *skb) |
653 | { | 684 | { |
654 | if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY) | 685 | if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY) |
@@ -691,17 +722,19 @@ static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t) | |||
691 | 722 | ||
692 | static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol, | 723 | static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol, |
693 | __u8 ipproto, | 724 | __u8 ipproto, |
694 | void (*dscp_ecn_decapsulate)(struct ip6_tnl *t, | 725 | void (*dscp_ecn_decapsulate)(const struct ip6_tnl *t, |
695 | struct ipv6hdr *ipv6h, | 726 | const struct ipv6hdr *ipv6h, |
696 | struct sk_buff *skb)) | 727 | struct sk_buff *skb)) |
697 | { | 728 | { |
698 | struct ip6_tnl *t; | 729 | struct ip6_tnl *t; |
699 | struct ipv6hdr *ipv6h = ipv6_hdr(skb); | 730 | const struct ipv6hdr *ipv6h = ipv6_hdr(skb); |
700 | 731 | ||
701 | rcu_read_lock(); | 732 | rcu_read_lock(); |
702 | 733 | ||
703 | if ((t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, | 734 | if ((t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, |
704 | &ipv6h->daddr)) != NULL) { | 735 | &ipv6h->daddr)) != NULL) { |
736 | struct pcpu_tstats *tstats; | ||
737 | |||
705 | if (t->parms.proto != ipproto && t->parms.proto != 0) { | 738 | if (t->parms.proto != ipproto && t->parms.proto != 0) { |
706 | rcu_read_unlock(); | 739 | rcu_read_unlock(); |
707 | goto discard; | 740 | goto discard; |
@@ -724,10 +757,16 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol, | |||
724 | skb->pkt_type = PACKET_HOST; | 757 | skb->pkt_type = PACKET_HOST; |
725 | memset(skb->cb, 0, sizeof(struct inet6_skb_parm)); | 758 | memset(skb->cb, 0, sizeof(struct inet6_skb_parm)); |
726 | 759 | ||
727 | skb_tunnel_rx(skb, t->dev); | 760 | tstats = this_cpu_ptr(t->dev->tstats); |
761 | tstats->rx_packets++; | ||
762 | tstats->rx_bytes += skb->len; | ||
763 | |||
764 | __skb_tunnel_rx(skb, t->dev); | ||
728 | 765 | ||
729 | dscp_ecn_decapsulate(t, ipv6h, skb); | 766 | dscp_ecn_decapsulate(t, ipv6h, skb); |
767 | |||
730 | netif_rx(skb); | 768 | netif_rx(skb); |
769 | |||
731 | rcu_read_unlock(); | 770 | rcu_read_unlock(); |
732 | return 0; | 771 | return 0; |
733 | } | 772 | } |
@@ -785,7 +824,7 @@ static void init_tel_txopt(struct ipv6_tel_txoption *opt, __u8 encap_limit) | |||
785 | **/ | 824 | **/ |
786 | 825 | ||
787 | static inline int | 826 | static inline int |
788 | ip6_tnl_addr_conflict(struct ip6_tnl *t, struct ipv6hdr *hdr) | 827 | ip6_tnl_addr_conflict(const struct ip6_tnl *t, const struct ipv6hdr *hdr) |
789 | { | 828 | { |
790 | return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr); | 829 | return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr); |
791 | } | 830 | } |
@@ -841,7 +880,7 @@ static inline int ip6_tnl_xmit_ctl(struct ip6_tnl *t) | |||
841 | static int ip6_tnl_xmit2(struct sk_buff *skb, | 880 | static int ip6_tnl_xmit2(struct sk_buff *skb, |
842 | struct net_device *dev, | 881 | struct net_device *dev, |
843 | __u8 dsfield, | 882 | __u8 dsfield, |
844 | struct flowi *fl, | 883 | struct flowi6 *fl6, |
845 | int encap_limit, | 884 | int encap_limit, |
846 | __u32 *pmtu) | 885 | __u32 *pmtu) |
847 | { | 886 | { |
@@ -861,10 +900,16 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, | |||
861 | if ((dst = ip6_tnl_dst_check(t)) != NULL) | 900 | if ((dst = ip6_tnl_dst_check(t)) != NULL) |
862 | dst_hold(dst); | 901 | dst_hold(dst); |
863 | else { | 902 | else { |
864 | dst = ip6_route_output(net, NULL, fl); | 903 | dst = ip6_route_output(net, NULL, fl6); |
865 | 904 | ||
866 | if (dst->error || xfrm_lookup(net, &dst, fl, NULL, 0) < 0) | 905 | if (dst->error) |
906 | goto tx_err_link_failure; | ||
907 | dst = xfrm_lookup(net, dst, flowi6_to_flowi(fl6), NULL, 0); | ||
908 | if (IS_ERR(dst)) { | ||
909 | err = PTR_ERR(dst); | ||
910 | dst = NULL; | ||
867 | goto tx_err_link_failure; | 911 | goto tx_err_link_failure; |
912 | } | ||
868 | } | 913 | } |
869 | 914 | ||
870 | tdev = dst->dev; | 915 | tdev = dst->dev; |
@@ -914,7 +959,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, | |||
914 | 959 | ||
915 | skb->transport_header = skb->network_header; | 960 | skb->transport_header = skb->network_header; |
916 | 961 | ||
917 | proto = fl->proto; | 962 | proto = fl6->flowi6_proto; |
918 | if (encap_limit >= 0) { | 963 | if (encap_limit >= 0) { |
919 | init_tel_txopt(&opt, encap_limit); | 964 | init_tel_txopt(&opt, encap_limit); |
920 | ipv6_push_nfrag_opts(skb, &opt.ops, &proto, NULL); | 965 | ipv6_push_nfrag_opts(skb, &opt.ops, &proto, NULL); |
@@ -922,20 +967,22 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, | |||
922 | skb_push(skb, sizeof(struct ipv6hdr)); | 967 | skb_push(skb, sizeof(struct ipv6hdr)); |
923 | skb_reset_network_header(skb); | 968 | skb_reset_network_header(skb); |
924 | ipv6h = ipv6_hdr(skb); | 969 | ipv6h = ipv6_hdr(skb); |
925 | *(__be32*)ipv6h = fl->fl6_flowlabel | htonl(0x60000000); | 970 | *(__be32*)ipv6h = fl6->flowlabel | htonl(0x60000000); |
926 | dsfield = INET_ECN_encapsulate(0, dsfield); | 971 | dsfield = INET_ECN_encapsulate(0, dsfield); |
927 | ipv6_change_dsfield(ipv6h, ~INET_ECN_MASK, dsfield); | 972 | ipv6_change_dsfield(ipv6h, ~INET_ECN_MASK, dsfield); |
928 | ipv6h->hop_limit = t->parms.hop_limit; | 973 | ipv6h->hop_limit = t->parms.hop_limit; |
929 | ipv6h->nexthdr = proto; | 974 | ipv6h->nexthdr = proto; |
930 | ipv6_addr_copy(&ipv6h->saddr, &fl->fl6_src); | 975 | ipv6_addr_copy(&ipv6h->saddr, &fl6->saddr); |
931 | ipv6_addr_copy(&ipv6h->daddr, &fl->fl6_dst); | 976 | ipv6_addr_copy(&ipv6h->daddr, &fl6->daddr); |
932 | nf_reset(skb); | 977 | nf_reset(skb); |
933 | pkt_len = skb->len; | 978 | pkt_len = skb->len; |
934 | err = ip6_local_out(skb); | 979 | err = ip6_local_out(skb); |
935 | 980 | ||
936 | if (net_xmit_eval(err) == 0) { | 981 | if (net_xmit_eval(err) == 0) { |
937 | stats->tx_bytes += pkt_len; | 982 | struct pcpu_tstats *tstats = this_cpu_ptr(t->dev->tstats); |
938 | stats->tx_packets++; | 983 | |
984 | tstats->tx_bytes += pkt_len; | ||
985 | tstats->tx_packets++; | ||
939 | } else { | 986 | } else { |
940 | stats->tx_errors++; | 987 | stats->tx_errors++; |
941 | stats->tx_aborted_errors++; | 988 | stats->tx_aborted_errors++; |
@@ -954,9 +1001,9 @@ static inline int | |||
954 | ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) | 1001 | ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) |
955 | { | 1002 | { |
956 | struct ip6_tnl *t = netdev_priv(dev); | 1003 | struct ip6_tnl *t = netdev_priv(dev); |
957 | struct iphdr *iph = ip_hdr(skb); | 1004 | const struct iphdr *iph = ip_hdr(skb); |
958 | int encap_limit = -1; | 1005 | int encap_limit = -1; |
959 | struct flowi fl; | 1006 | struct flowi6 fl6; |
960 | __u8 dsfield; | 1007 | __u8 dsfield; |
961 | __u32 mtu; | 1008 | __u32 mtu; |
962 | int err; | 1009 | int err; |
@@ -968,16 +1015,16 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) | |||
968 | if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) | 1015 | if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) |
969 | encap_limit = t->parms.encap_limit; | 1016 | encap_limit = t->parms.encap_limit; |
970 | 1017 | ||
971 | memcpy(&fl, &t->fl, sizeof (fl)); | 1018 | memcpy(&fl6, &t->fl.u.ip6, sizeof (fl6)); |
972 | fl.proto = IPPROTO_IPIP; | 1019 | fl6.flowi6_proto = IPPROTO_IPIP; |
973 | 1020 | ||
974 | dsfield = ipv4_get_dsfield(iph); | 1021 | dsfield = ipv4_get_dsfield(iph); |
975 | 1022 | ||
976 | if ((t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)) | 1023 | if ((t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)) |
977 | fl.fl6_flowlabel |= htonl((__u32)iph->tos << IPV6_TCLASS_SHIFT) | 1024 | fl6.flowlabel |= htonl((__u32)iph->tos << IPV6_TCLASS_SHIFT) |
978 | & IPV6_TCLASS_MASK; | 1025 | & IPV6_TCLASS_MASK; |
979 | 1026 | ||
980 | err = ip6_tnl_xmit2(skb, dev, dsfield, &fl, encap_limit, &mtu); | 1027 | err = ip6_tnl_xmit2(skb, dev, dsfield, &fl6, encap_limit, &mtu); |
981 | if (err != 0) { | 1028 | if (err != 0) { |
982 | /* XXX: send ICMP error even if DF is not set. */ | 1029 | /* XXX: send ICMP error even if DF is not set. */ |
983 | if (err == -EMSGSIZE) | 1030 | if (err == -EMSGSIZE) |
@@ -996,7 +1043,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) | |||
996 | struct ipv6hdr *ipv6h = ipv6_hdr(skb); | 1043 | struct ipv6hdr *ipv6h = ipv6_hdr(skb); |
997 | int encap_limit = -1; | 1044 | int encap_limit = -1; |
998 | __u16 offset; | 1045 | __u16 offset; |
999 | struct flowi fl; | 1046 | struct flowi6 fl6; |
1000 | __u8 dsfield; | 1047 | __u8 dsfield; |
1001 | __u32 mtu; | 1048 | __u32 mtu; |
1002 | int err; | 1049 | int err; |
@@ -1018,16 +1065,16 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1018 | } else if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) | 1065 | } else if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) |
1019 | encap_limit = t->parms.encap_limit; | 1066 | encap_limit = t->parms.encap_limit; |
1020 | 1067 | ||
1021 | memcpy(&fl, &t->fl, sizeof (fl)); | 1068 | memcpy(&fl6, &t->fl.u.ip6, sizeof (fl6)); |
1022 | fl.proto = IPPROTO_IPV6; | 1069 | fl6.flowi6_proto = IPPROTO_IPV6; |
1023 | 1070 | ||
1024 | dsfield = ipv6_get_dsfield(ipv6h); | 1071 | dsfield = ipv6_get_dsfield(ipv6h); |
1025 | if ((t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)) | 1072 | if ((t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)) |
1026 | fl.fl6_flowlabel |= (*(__be32 *) ipv6h & IPV6_TCLASS_MASK); | 1073 | fl6.flowlabel |= (*(__be32 *) ipv6h & IPV6_TCLASS_MASK); |
1027 | if ((t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL)) | 1074 | if ((t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL)) |
1028 | fl.fl6_flowlabel |= (*(__be32 *) ipv6h & IPV6_FLOWLABEL_MASK); | 1075 | fl6.flowlabel |= (*(__be32 *) ipv6h & IPV6_FLOWLABEL_MASK); |
1029 | 1076 | ||
1030 | err = ip6_tnl_xmit2(skb, dev, dsfield, &fl, encap_limit, &mtu); | 1077 | err = ip6_tnl_xmit2(skb, dev, dsfield, &fl6, encap_limit, &mtu); |
1031 | if (err != 0) { | 1078 | if (err != 0) { |
1032 | if (err == -EMSGSIZE) | 1079 | if (err == -EMSGSIZE) |
1033 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); | 1080 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
@@ -1090,21 +1137,21 @@ static void ip6_tnl_link_config(struct ip6_tnl *t) | |||
1090 | { | 1137 | { |
1091 | struct net_device *dev = t->dev; | 1138 | struct net_device *dev = t->dev; |
1092 | struct ip6_tnl_parm *p = &t->parms; | 1139 | struct ip6_tnl_parm *p = &t->parms; |
1093 | struct flowi *fl = &t->fl; | 1140 | struct flowi6 *fl6 = &t->fl.u.ip6; |
1094 | 1141 | ||
1095 | memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr)); | 1142 | memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr)); |
1096 | memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr)); | 1143 | memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr)); |
1097 | 1144 | ||
1098 | /* Set up flowi template */ | 1145 | /* Set up flowi template */ |
1099 | ipv6_addr_copy(&fl->fl6_src, &p->laddr); | 1146 | ipv6_addr_copy(&fl6->saddr, &p->laddr); |
1100 | ipv6_addr_copy(&fl->fl6_dst, &p->raddr); | 1147 | ipv6_addr_copy(&fl6->daddr, &p->raddr); |
1101 | fl->oif = p->link; | 1148 | fl6->flowi6_oif = p->link; |
1102 | fl->fl6_flowlabel = 0; | 1149 | fl6->flowlabel = 0; |
1103 | 1150 | ||
1104 | if (!(p->flags&IP6_TNL_F_USE_ORIG_TCLASS)) | 1151 | if (!(p->flags&IP6_TNL_F_USE_ORIG_TCLASS)) |
1105 | fl->fl6_flowlabel |= IPV6_TCLASS_MASK & p->flowinfo; | 1152 | fl6->flowlabel |= IPV6_TCLASS_MASK & p->flowinfo; |
1106 | if (!(p->flags&IP6_TNL_F_USE_ORIG_FLOWLABEL)) | 1153 | if (!(p->flags&IP6_TNL_F_USE_ORIG_FLOWLABEL)) |
1107 | fl->fl6_flowlabel |= IPV6_FLOWLABEL_MASK & p->flowinfo; | 1154 | fl6->flowlabel |= IPV6_FLOWLABEL_MASK & p->flowinfo; |
1108 | 1155 | ||
1109 | ip6_tnl_set_cap(t); | 1156 | ip6_tnl_set_cap(t); |
1110 | 1157 | ||
@@ -1131,6 +1178,8 @@ static void ip6_tnl_link_config(struct ip6_tnl *t) | |||
1131 | sizeof (struct ipv6hdr); | 1178 | sizeof (struct ipv6hdr); |
1132 | 1179 | ||
1133 | dev->mtu = rt->rt6i_dev->mtu - sizeof (struct ipv6hdr); | 1180 | dev->mtu = rt->rt6i_dev->mtu - sizeof (struct ipv6hdr); |
1181 | if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) | ||
1182 | dev->mtu-=8; | ||
1134 | 1183 | ||
1135 | if (dev->mtu < IPV6_MIN_MTU) | 1184 | if (dev->mtu < IPV6_MIN_MTU) |
1136 | dev->mtu = IPV6_MIN_MTU; | 1185 | dev->mtu = IPV6_MIN_MTU; |
@@ -1240,6 +1289,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |||
1240 | t = netdev_priv(dev); | 1289 | t = netdev_priv(dev); |
1241 | 1290 | ||
1242 | ip6_tnl_unlink(ip6n, t); | 1291 | ip6_tnl_unlink(ip6n, t); |
1292 | synchronize_net(); | ||
1243 | err = ip6_tnl_change(t, &p); | 1293 | err = ip6_tnl_change(t, &p); |
1244 | ip6_tnl_link(ip6n, t); | 1294 | ip6_tnl_link(ip6n, t); |
1245 | netdev_state_change(dev); | 1295 | netdev_state_change(dev); |
@@ -1300,12 +1350,14 @@ ip6_tnl_change_mtu(struct net_device *dev, int new_mtu) | |||
1300 | 1350 | ||
1301 | 1351 | ||
1302 | static const struct net_device_ops ip6_tnl_netdev_ops = { | 1352 | static const struct net_device_ops ip6_tnl_netdev_ops = { |
1303 | .ndo_uninit = ip6_tnl_dev_uninit, | 1353 | .ndo_uninit = ip6_tnl_dev_uninit, |
1304 | .ndo_start_xmit = ip6_tnl_xmit, | 1354 | .ndo_start_xmit = ip6_tnl_xmit, |
1305 | .ndo_do_ioctl = ip6_tnl_ioctl, | 1355 | .ndo_do_ioctl = ip6_tnl_ioctl, |
1306 | .ndo_change_mtu = ip6_tnl_change_mtu, | 1356 | .ndo_change_mtu = ip6_tnl_change_mtu, |
1357 | .ndo_get_stats = ip6_get_stats, | ||
1307 | }; | 1358 | }; |
1308 | 1359 | ||
1360 | |||
1309 | /** | 1361 | /** |
1310 | * ip6_tnl_dev_setup - setup virtual tunnel device | 1362 | * ip6_tnl_dev_setup - setup virtual tunnel device |
1311 | * @dev: virtual device associated with tunnel | 1363 | * @dev: virtual device associated with tunnel |
@@ -1316,15 +1368,21 @@ static const struct net_device_ops ip6_tnl_netdev_ops = { | |||
1316 | 1368 | ||
1317 | static void ip6_tnl_dev_setup(struct net_device *dev) | 1369 | static void ip6_tnl_dev_setup(struct net_device *dev) |
1318 | { | 1370 | { |
1371 | struct ip6_tnl *t; | ||
1372 | |||
1319 | dev->netdev_ops = &ip6_tnl_netdev_ops; | 1373 | dev->netdev_ops = &ip6_tnl_netdev_ops; |
1320 | dev->destructor = free_netdev; | 1374 | dev->destructor = ip6_dev_free; |
1321 | 1375 | ||
1322 | dev->type = ARPHRD_TUNNEL6; | 1376 | dev->type = ARPHRD_TUNNEL6; |
1323 | dev->hard_header_len = LL_MAX_HEADER + sizeof (struct ipv6hdr); | 1377 | dev->hard_header_len = LL_MAX_HEADER + sizeof (struct ipv6hdr); |
1324 | dev->mtu = ETH_DATA_LEN - sizeof (struct ipv6hdr); | 1378 | dev->mtu = ETH_DATA_LEN - sizeof (struct ipv6hdr); |
1379 | t = netdev_priv(dev); | ||
1380 | if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) | ||
1381 | dev->mtu-=8; | ||
1325 | dev->flags |= IFF_NOARP; | 1382 | dev->flags |= IFF_NOARP; |
1326 | dev->addr_len = sizeof(struct in6_addr); | 1383 | dev->addr_len = sizeof(struct in6_addr); |
1327 | dev->features |= NETIF_F_NETNS_LOCAL; | 1384 | dev->features |= NETIF_F_NETNS_LOCAL; |
1385 | dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; | ||
1328 | } | 1386 | } |
1329 | 1387 | ||
1330 | 1388 | ||
@@ -1333,12 +1391,17 @@ static void ip6_tnl_dev_setup(struct net_device *dev) | |||
1333 | * @dev: virtual device associated with tunnel | 1391 | * @dev: virtual device associated with tunnel |
1334 | **/ | 1392 | **/ |
1335 | 1393 | ||
1336 | static inline void | 1394 | static inline int |
1337 | ip6_tnl_dev_init_gen(struct net_device *dev) | 1395 | ip6_tnl_dev_init_gen(struct net_device *dev) |
1338 | { | 1396 | { |
1339 | struct ip6_tnl *t = netdev_priv(dev); | 1397 | struct ip6_tnl *t = netdev_priv(dev); |
1398 | |||
1340 | t->dev = dev; | 1399 | t->dev = dev; |
1341 | strcpy(t->parms.name, dev->name); | 1400 | strcpy(t->parms.name, dev->name); |
1401 | dev->tstats = alloc_percpu(struct pcpu_tstats); | ||
1402 | if (!dev->tstats) | ||
1403 | return -ENOMEM; | ||
1404 | return 0; | ||
1342 | } | 1405 | } |
1343 | 1406 | ||
1344 | /** | 1407 | /** |
@@ -1346,11 +1409,15 @@ ip6_tnl_dev_init_gen(struct net_device *dev) | |||
1346 | * @dev: virtual device associated with tunnel | 1409 | * @dev: virtual device associated with tunnel |
1347 | **/ | 1410 | **/ |
1348 | 1411 | ||
1349 | static void ip6_tnl_dev_init(struct net_device *dev) | 1412 | static int ip6_tnl_dev_init(struct net_device *dev) |
1350 | { | 1413 | { |
1351 | struct ip6_tnl *t = netdev_priv(dev); | 1414 | struct ip6_tnl *t = netdev_priv(dev); |
1352 | ip6_tnl_dev_init_gen(dev); | 1415 | int err = ip6_tnl_dev_init_gen(dev); |
1416 | |||
1417 | if (err) | ||
1418 | return err; | ||
1353 | ip6_tnl_link_config(t); | 1419 | ip6_tnl_link_config(t); |
1420 | return 0; | ||
1354 | } | 1421 | } |
1355 | 1422 | ||
1356 | /** | 1423 | /** |
@@ -1360,25 +1427,29 @@ static void ip6_tnl_dev_init(struct net_device *dev) | |||
1360 | * Return: 0 | 1427 | * Return: 0 |
1361 | **/ | 1428 | **/ |
1362 | 1429 | ||
1363 | static void __net_init ip6_fb_tnl_dev_init(struct net_device *dev) | 1430 | static int __net_init ip6_fb_tnl_dev_init(struct net_device *dev) |
1364 | { | 1431 | { |
1365 | struct ip6_tnl *t = netdev_priv(dev); | 1432 | struct ip6_tnl *t = netdev_priv(dev); |
1366 | struct net *net = dev_net(dev); | 1433 | struct net *net = dev_net(dev); |
1367 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | 1434 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); |
1435 | int err = ip6_tnl_dev_init_gen(dev); | ||
1436 | |||
1437 | if (err) | ||
1438 | return err; | ||
1368 | 1439 | ||
1369 | ip6_tnl_dev_init_gen(dev); | ||
1370 | t->parms.proto = IPPROTO_IPV6; | 1440 | t->parms.proto = IPPROTO_IPV6; |
1371 | dev_hold(dev); | 1441 | dev_hold(dev); |
1372 | ip6n->tnls_wc[0] = t; | 1442 | rcu_assign_pointer(ip6n->tnls_wc[0], t); |
1443 | return 0; | ||
1373 | } | 1444 | } |
1374 | 1445 | ||
1375 | static struct xfrm6_tunnel ip4ip6_handler = { | 1446 | static struct xfrm6_tunnel ip4ip6_handler __read_mostly = { |
1376 | .handler = ip4ip6_rcv, | 1447 | .handler = ip4ip6_rcv, |
1377 | .err_handler = ip4ip6_err, | 1448 | .err_handler = ip4ip6_err, |
1378 | .priority = 1, | 1449 | .priority = 1, |
1379 | }; | 1450 | }; |
1380 | 1451 | ||
1381 | static struct xfrm6_tunnel ip6ip6_handler = { | 1452 | static struct xfrm6_tunnel ip6ip6_handler __read_mostly = { |
1382 | .handler = ip6ip6_rcv, | 1453 | .handler = ip6ip6_rcv, |
1383 | .err_handler = ip6ip6_err, | 1454 | .err_handler = ip6ip6_err, |
1384 | .priority = 1, | 1455 | .priority = 1, |
@@ -1391,14 +1462,14 @@ static void __net_exit ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n) | |||
1391 | LIST_HEAD(list); | 1462 | LIST_HEAD(list); |
1392 | 1463 | ||
1393 | for (h = 0; h < HASH_SIZE; h++) { | 1464 | for (h = 0; h < HASH_SIZE; h++) { |
1394 | t = ip6n->tnls_r_l[h]; | 1465 | t = rtnl_dereference(ip6n->tnls_r_l[h]); |
1395 | while (t != NULL) { | 1466 | while (t != NULL) { |
1396 | unregister_netdevice_queue(t->dev, &list); | 1467 | unregister_netdevice_queue(t->dev, &list); |
1397 | t = t->next; | 1468 | t = rtnl_dereference(t->next); |
1398 | } | 1469 | } |
1399 | } | 1470 | } |
1400 | 1471 | ||
1401 | t = ip6n->tnls_wc[0]; | 1472 | t = rtnl_dereference(ip6n->tnls_wc[0]); |
1402 | unregister_netdevice_queue(t->dev, &list); | 1473 | unregister_netdevice_queue(t->dev, &list); |
1403 | unregister_netdevice_many(&list); | 1474 | unregister_netdevice_many(&list); |
1404 | } | 1475 | } |
@@ -1419,7 +1490,9 @@ static int __net_init ip6_tnl_init_net(struct net *net) | |||
1419 | goto err_alloc_dev; | 1490 | goto err_alloc_dev; |
1420 | dev_net_set(ip6n->fb_tnl_dev, net); | 1491 | dev_net_set(ip6n->fb_tnl_dev, net); |
1421 | 1492 | ||
1422 | ip6_fb_tnl_dev_init(ip6n->fb_tnl_dev); | 1493 | err = ip6_fb_tnl_dev_init(ip6n->fb_tnl_dev); |
1494 | if (err < 0) | ||
1495 | goto err_register; | ||
1423 | 1496 | ||
1424 | err = register_netdev(ip6n->fb_tnl_dev); | 1497 | err = register_netdev(ip6n->fb_tnl_dev); |
1425 | if (err < 0) | 1498 | if (err < 0) |
@@ -1427,7 +1500,7 @@ static int __net_init ip6_tnl_init_net(struct net *net) | |||
1427 | return 0; | 1500 | return 0; |
1428 | 1501 | ||
1429 | err_register: | 1502 | err_register: |
1430 | free_netdev(ip6n->fb_tnl_dev); | 1503 | ip6_dev_free(ip6n->fb_tnl_dev); |
1431 | err_alloc_dev: | 1504 | err_alloc_dev: |
1432 | return err; | 1505 | return err; |
1433 | } | 1506 | } |
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 66078dad7fe8..82a809901f8e 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/seq_file.h> | 34 | #include <linux/seq_file.h> |
35 | #include <linux/init.h> | 35 | #include <linux/init.h> |
36 | #include <linux/slab.h> | 36 | #include <linux/slab.h> |
37 | #include <linux/compat.h> | ||
37 | #include <net/protocol.h> | 38 | #include <net/protocol.h> |
38 | #include <linux/skbuff.h> | 39 | #include <linux/skbuff.h> |
39 | #include <net/sock.h> | 40 | #include <net/sock.h> |
@@ -134,14 +135,15 @@ static struct mr6_table *ip6mr_get_table(struct net *net, u32 id) | |||
134 | return NULL; | 135 | return NULL; |
135 | } | 136 | } |
136 | 137 | ||
137 | static int ip6mr_fib_lookup(struct net *net, struct flowi *flp, | 138 | static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6, |
138 | struct mr6_table **mrt) | 139 | struct mr6_table **mrt) |
139 | { | 140 | { |
140 | struct ip6mr_result res; | 141 | struct ip6mr_result res; |
141 | struct fib_lookup_arg arg = { .result = &res, }; | 142 | struct fib_lookup_arg arg = { .result = &res, }; |
142 | int err; | 143 | int err; |
143 | 144 | ||
144 | err = fib_rules_lookup(net->ipv6.mr6_rules_ops, flp, 0, &arg); | 145 | err = fib_rules_lookup(net->ipv6.mr6_rules_ops, |
146 | flowi6_to_flowi(flp6), 0, &arg); | ||
145 | if (err < 0) | 147 | if (err < 0) |
146 | return err; | 148 | return err; |
147 | *mrt = res.mrt; | 149 | *mrt = res.mrt; |
@@ -269,7 +271,7 @@ static struct mr6_table *ip6mr_get_table(struct net *net, u32 id) | |||
269 | return net->ipv6.mrt6; | 271 | return net->ipv6.mrt6; |
270 | } | 272 | } |
271 | 273 | ||
272 | static int ip6mr_fib_lookup(struct net *net, struct flowi *flp, | 274 | static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6, |
273 | struct mr6_table **mrt) | 275 | struct mr6_table **mrt) |
274 | { | 276 | { |
275 | *mrt = net->ipv6.mrt6; | 277 | *mrt = net->ipv6.mrt6; |
@@ -616,9 +618,9 @@ static int pim6_rcv(struct sk_buff *skb) | |||
616 | struct net_device *reg_dev = NULL; | 618 | struct net_device *reg_dev = NULL; |
617 | struct net *net = dev_net(skb->dev); | 619 | struct net *net = dev_net(skb->dev); |
618 | struct mr6_table *mrt; | 620 | struct mr6_table *mrt; |
619 | struct flowi fl = { | 621 | struct flowi6 fl6 = { |
620 | .iif = skb->dev->ifindex, | 622 | .flowi6_iif = skb->dev->ifindex, |
621 | .mark = skb->mark, | 623 | .flowi6_mark = skb->mark, |
622 | }; | 624 | }; |
623 | int reg_vif_num; | 625 | int reg_vif_num; |
624 | 626 | ||
@@ -643,7 +645,7 @@ static int pim6_rcv(struct sk_buff *skb) | |||
643 | ntohs(encap->payload_len) + sizeof(*pim) > skb->len) | 645 | ntohs(encap->payload_len) + sizeof(*pim) > skb->len) |
644 | goto drop; | 646 | goto drop; |
645 | 647 | ||
646 | if (ip6mr_fib_lookup(net, &fl, &mrt) < 0) | 648 | if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0) |
647 | goto drop; | 649 | goto drop; |
648 | reg_vif_num = mrt->mroute_reg_vif_num; | 650 | reg_vif_num = mrt->mroute_reg_vif_num; |
649 | 651 | ||
@@ -661,12 +663,13 @@ static int pim6_rcv(struct sk_buff *skb) | |||
661 | skb_pull(skb, (u8 *)encap - skb->data); | 663 | skb_pull(skb, (u8 *)encap - skb->data); |
662 | skb_reset_network_header(skb); | 664 | skb_reset_network_header(skb); |
663 | skb->protocol = htons(ETH_P_IPV6); | 665 | skb->protocol = htons(ETH_P_IPV6); |
664 | skb->ip_summed = 0; | 666 | skb->ip_summed = CHECKSUM_NONE; |
665 | skb->pkt_type = PACKET_HOST; | 667 | skb->pkt_type = PACKET_HOST; |
666 | 668 | ||
667 | skb_tunnel_rx(skb, reg_dev); | 669 | skb_tunnel_rx(skb, reg_dev); |
668 | 670 | ||
669 | netif_rx(skb); | 671 | netif_rx(skb); |
672 | |||
670 | dev_put(reg_dev); | 673 | dev_put(reg_dev); |
671 | return 0; | 674 | return 0; |
672 | drop: | 675 | drop: |
@@ -685,14 +688,14 @@ static netdev_tx_t reg_vif_xmit(struct sk_buff *skb, | |||
685 | { | 688 | { |
686 | struct net *net = dev_net(dev); | 689 | struct net *net = dev_net(dev); |
687 | struct mr6_table *mrt; | 690 | struct mr6_table *mrt; |
688 | struct flowi fl = { | 691 | struct flowi6 fl6 = { |
689 | .oif = dev->ifindex, | 692 | .flowi6_oif = dev->ifindex, |
690 | .iif = skb->skb_iif, | 693 | .flowi6_iif = skb->skb_iif, |
691 | .mark = skb->mark, | 694 | .flowi6_mark = skb->mark, |
692 | }; | 695 | }; |
693 | int err; | 696 | int err; |
694 | 697 | ||
695 | err = ip6mr_fib_lookup(net, &fl, &mrt); | 698 | err = ip6mr_fib_lookup(net, &fl6, &mrt); |
696 | if (err < 0) | 699 | if (err < 0) |
697 | return err; | 700 | return err; |
698 | 701 | ||
@@ -986,8 +989,8 @@ static int mif6_add(struct net *net, struct mr6_table *mrt, | |||
986 | } | 989 | } |
987 | 990 | ||
988 | static struct mfc6_cache *ip6mr_cache_find(struct mr6_table *mrt, | 991 | static struct mfc6_cache *ip6mr_cache_find(struct mr6_table *mrt, |
989 | struct in6_addr *origin, | 992 | const struct in6_addr *origin, |
990 | struct in6_addr *mcastgrp) | 993 | const struct in6_addr *mcastgrp) |
991 | { | 994 | { |
992 | int line = MFC6_HASH(mcastgrp, origin); | 995 | int line = MFC6_HASH(mcastgrp, origin); |
993 | struct mfc6_cache *c; | 996 | struct mfc6_cache *c; |
@@ -1037,7 +1040,6 @@ static void ip6mr_cache_resolve(struct net *net, struct mr6_table *mrt, | |||
1037 | 1040 | ||
1038 | while((skb = __skb_dequeue(&uc->mfc_un.unres.unresolved))) { | 1041 | while((skb = __skb_dequeue(&uc->mfc_un.unres.unresolved))) { |
1039 | if (ipv6_hdr(skb)->version == 0) { | 1042 | if (ipv6_hdr(skb)->version == 0) { |
1040 | int err; | ||
1041 | struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr)); | 1043 | struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr)); |
1042 | 1044 | ||
1043 | if (__ip6mr_fill_mroute(mrt, skb, c, NLMSG_DATA(nlh)) > 0) { | 1045 | if (__ip6mr_fill_mroute(mrt, skb, c, NLMSG_DATA(nlh)) > 0) { |
@@ -1048,7 +1050,7 @@ static void ip6mr_cache_resolve(struct net *net, struct mr6_table *mrt, | |||
1048 | skb_trim(skb, nlh->nlmsg_len); | 1050 | skb_trim(skb, nlh->nlmsg_len); |
1049 | ((struct nlmsgerr *)NLMSG_DATA(nlh))->error = -EMSGSIZE; | 1051 | ((struct nlmsgerr *)NLMSG_DATA(nlh))->error = -EMSGSIZE; |
1050 | } | 1052 | } |
1051 | err = rtnl_unicast(skb, net, NETLINK_CB(skb).pid); | 1053 | rtnl_unicast(skb, net, NETLINK_CB(skb).pid); |
1052 | } else | 1054 | } else |
1053 | ip6_mr_forward(net, mrt, skb, c); | 1055 | ip6_mr_forward(net, mrt, skb, c); |
1054 | } | 1056 | } |
@@ -1546,13 +1548,13 @@ int ip6mr_sk_done(struct sock *sk) | |||
1546 | struct sock *mroute6_socket(struct net *net, struct sk_buff *skb) | 1548 | struct sock *mroute6_socket(struct net *net, struct sk_buff *skb) |
1547 | { | 1549 | { |
1548 | struct mr6_table *mrt; | 1550 | struct mr6_table *mrt; |
1549 | struct flowi fl = { | 1551 | struct flowi6 fl6 = { |
1550 | .iif = skb->skb_iif, | 1552 | .flowi6_iif = skb->skb_iif, |
1551 | .oif = skb->dev->ifindex, | 1553 | .flowi6_oif = skb->dev->ifindex, |
1552 | .mark = skb->mark, | 1554 | .flowi6_mark = skb->mark, |
1553 | }; | 1555 | }; |
1554 | 1556 | ||
1555 | if (ip6mr_fib_lookup(net, &fl, &mrt) < 0) | 1557 | if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0) |
1556 | return NULL; | 1558 | return NULL; |
1557 | 1559 | ||
1558 | return mrt->mroute6_sk; | 1560 | return mrt->mroute6_sk; |
@@ -1803,6 +1805,80 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg) | |||
1803 | } | 1805 | } |
1804 | } | 1806 | } |
1805 | 1807 | ||
1808 | #ifdef CONFIG_COMPAT | ||
1809 | struct compat_sioc_sg_req6 { | ||
1810 | struct sockaddr_in6 src; | ||
1811 | struct sockaddr_in6 grp; | ||
1812 | compat_ulong_t pktcnt; | ||
1813 | compat_ulong_t bytecnt; | ||
1814 | compat_ulong_t wrong_if; | ||
1815 | }; | ||
1816 | |||
1817 | struct compat_sioc_mif_req6 { | ||
1818 | mifi_t mifi; | ||
1819 | compat_ulong_t icount; | ||
1820 | compat_ulong_t ocount; | ||
1821 | compat_ulong_t ibytes; | ||
1822 | compat_ulong_t obytes; | ||
1823 | }; | ||
1824 | |||
1825 | int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg) | ||
1826 | { | ||
1827 | struct compat_sioc_sg_req6 sr; | ||
1828 | struct compat_sioc_mif_req6 vr; | ||
1829 | struct mif_device *vif; | ||
1830 | struct mfc6_cache *c; | ||
1831 | struct net *net = sock_net(sk); | ||
1832 | struct mr6_table *mrt; | ||
1833 | |||
1834 | mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT); | ||
1835 | if (mrt == NULL) | ||
1836 | return -ENOENT; | ||
1837 | |||
1838 | switch (cmd) { | ||
1839 | case SIOCGETMIFCNT_IN6: | ||
1840 | if (copy_from_user(&vr, arg, sizeof(vr))) | ||
1841 | return -EFAULT; | ||
1842 | if (vr.mifi >= mrt->maxvif) | ||
1843 | return -EINVAL; | ||
1844 | read_lock(&mrt_lock); | ||
1845 | vif = &mrt->vif6_table[vr.mifi]; | ||
1846 | if (MIF_EXISTS(mrt, vr.mifi)) { | ||
1847 | vr.icount = vif->pkt_in; | ||
1848 | vr.ocount = vif->pkt_out; | ||
1849 | vr.ibytes = vif->bytes_in; | ||
1850 | vr.obytes = vif->bytes_out; | ||
1851 | read_unlock(&mrt_lock); | ||
1852 | |||
1853 | if (copy_to_user(arg, &vr, sizeof(vr))) | ||
1854 | return -EFAULT; | ||
1855 | return 0; | ||
1856 | } | ||
1857 | read_unlock(&mrt_lock); | ||
1858 | return -EADDRNOTAVAIL; | ||
1859 | case SIOCGETSGCNT_IN6: | ||
1860 | if (copy_from_user(&sr, arg, sizeof(sr))) | ||
1861 | return -EFAULT; | ||
1862 | |||
1863 | read_lock(&mrt_lock); | ||
1864 | c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr); | ||
1865 | if (c) { | ||
1866 | sr.pktcnt = c->mfc_un.res.pkt; | ||
1867 | sr.bytecnt = c->mfc_un.res.bytes; | ||
1868 | sr.wrong_if = c->mfc_un.res.wrong_if; | ||
1869 | read_unlock(&mrt_lock); | ||
1870 | |||
1871 | if (copy_to_user(arg, &sr, sizeof(sr))) | ||
1872 | return -EFAULT; | ||
1873 | return 0; | ||
1874 | } | ||
1875 | read_unlock(&mrt_lock); | ||
1876 | return -EADDRNOTAVAIL; | ||
1877 | default: | ||
1878 | return -ENOIOCTLCMD; | ||
1879 | } | ||
1880 | } | ||
1881 | #endif | ||
1806 | 1882 | ||
1807 | static inline int ip6mr_forward2_finish(struct sk_buff *skb) | 1883 | static inline int ip6mr_forward2_finish(struct sk_buff *skb) |
1808 | { | 1884 | { |
@@ -1822,7 +1898,7 @@ static int ip6mr_forward2(struct net *net, struct mr6_table *mrt, | |||
1822 | struct mif_device *vif = &mrt->vif6_table[vifi]; | 1898 | struct mif_device *vif = &mrt->vif6_table[vifi]; |
1823 | struct net_device *dev; | 1899 | struct net_device *dev; |
1824 | struct dst_entry *dst; | 1900 | struct dst_entry *dst; |
1825 | struct flowi fl; | 1901 | struct flowi6 fl6; |
1826 | 1902 | ||
1827 | if (vif->dev == NULL) | 1903 | if (vif->dev == NULL) |
1828 | goto out_free; | 1904 | goto out_free; |
@@ -1840,14 +1916,12 @@ static int ip6mr_forward2(struct net *net, struct mr6_table *mrt, | |||
1840 | 1916 | ||
1841 | ipv6h = ipv6_hdr(skb); | 1917 | ipv6h = ipv6_hdr(skb); |
1842 | 1918 | ||
1843 | fl = (struct flowi) { | 1919 | fl6 = (struct flowi6) { |
1844 | .oif = vif->link, | 1920 | .flowi6_oif = vif->link, |
1845 | .nl_u = { .ip6_u = | 1921 | .daddr = ipv6h->daddr, |
1846 | { .daddr = ipv6h->daddr, } | ||
1847 | } | ||
1848 | }; | 1922 | }; |
1849 | 1923 | ||
1850 | dst = ip6_route_output(net, NULL, &fl); | 1924 | dst = ip6_route_output(net, NULL, &fl6); |
1851 | if (!dst) | 1925 | if (!dst) |
1852 | goto out_free; | 1926 | goto out_free; |
1853 | 1927 | ||
@@ -1970,13 +2044,13 @@ int ip6_mr_input(struct sk_buff *skb) | |||
1970 | struct mfc6_cache *cache; | 2044 | struct mfc6_cache *cache; |
1971 | struct net *net = dev_net(skb->dev); | 2045 | struct net *net = dev_net(skb->dev); |
1972 | struct mr6_table *mrt; | 2046 | struct mr6_table *mrt; |
1973 | struct flowi fl = { | 2047 | struct flowi6 fl6 = { |
1974 | .iif = skb->dev->ifindex, | 2048 | .flowi6_iif = skb->dev->ifindex, |
1975 | .mark = skb->mark, | 2049 | .flowi6_mark = skb->mark, |
1976 | }; | 2050 | }; |
1977 | int err; | 2051 | int err; |
1978 | 2052 | ||
1979 | err = ip6mr_fib_lookup(net, &fl, &mrt); | 2053 | err = ip6mr_fib_lookup(net, &fl6, &mrt); |
1980 | if (err < 0) | 2054 | if (err < 0) |
1981 | return err; | 2055 | return err; |
1982 | 2056 | ||
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index 85cccd6ed0b7..bba658d9a03c 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c | |||
@@ -55,7 +55,7 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
55 | { | 55 | { |
56 | struct net *net = dev_net(skb->dev); | 56 | struct net *net = dev_net(skb->dev); |
57 | __be32 spi; | 57 | __be32 spi; |
58 | struct ipv6hdr *iph = (struct ipv6hdr*)skb->data; | 58 | const struct ipv6hdr *iph = (const struct ipv6hdr *)skb->data; |
59 | struct ip_comp_hdr *ipcomph = | 59 | struct ip_comp_hdr *ipcomph = |
60 | (struct ip_comp_hdr *)(skb->data + offset); | 60 | (struct ip_comp_hdr *)(skb->data + offset); |
61 | struct xfrm_state *x; | 61 | struct xfrm_state *x; |
@@ -64,7 +64,8 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
64 | return; | 64 | return; |
65 | 65 | ||
66 | spi = htonl(ntohs(ipcomph->cpi)); | 66 | spi = htonl(ntohs(ipcomph->cpi)); |
67 | x = xfrm_state_lookup(net, skb->mark, (xfrm_address_t *)&iph->daddr, spi, IPPROTO_COMP, AF_INET6); | 67 | x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr, |
68 | spi, IPPROTO_COMP, AF_INET6); | ||
68 | if (!x) | 69 | if (!x) |
69 | return; | 70 | return; |
70 | 71 | ||
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index a7f66bc8f0b0..9cb191ecaba8 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
@@ -342,6 +342,25 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
342 | retv = 0; | 342 | retv = 0; |
343 | break; | 343 | break; |
344 | 344 | ||
345 | case IPV6_TRANSPARENT: | ||
346 | if (!capable(CAP_NET_ADMIN)) { | ||
347 | retv = -EPERM; | ||
348 | break; | ||
349 | } | ||
350 | if (optlen < sizeof(int)) | ||
351 | goto e_inval; | ||
352 | /* we don't have a separate transparent bit for IPV6 we use the one in the IPv4 socket */ | ||
353 | inet_sk(sk)->transparent = valbool; | ||
354 | retv = 0; | ||
355 | break; | ||
356 | |||
357 | case IPV6_RECVORIGDSTADDR: | ||
358 | if (optlen < sizeof(int)) | ||
359 | goto e_inval; | ||
360 | np->rxopt.bits.rxorigdstaddr = valbool; | ||
361 | retv = 0; | ||
362 | break; | ||
363 | |||
345 | case IPV6_HOPOPTS: | 364 | case IPV6_HOPOPTS: |
346 | case IPV6_RTHDRDSTOPTS: | 365 | case IPV6_RTHDRDSTOPTS: |
347 | case IPV6_RTHDR: | 366 | case IPV6_RTHDR: |
@@ -425,12 +444,12 @@ sticky_done: | |||
425 | { | 444 | { |
426 | struct ipv6_txoptions *opt = NULL; | 445 | struct ipv6_txoptions *opt = NULL; |
427 | struct msghdr msg; | 446 | struct msghdr msg; |
428 | struct flowi fl; | 447 | struct flowi6 fl6; |
429 | int junk; | 448 | int junk; |
430 | 449 | ||
431 | fl.fl6_flowlabel = 0; | 450 | memset(&fl6, 0, sizeof(fl6)); |
432 | fl.oif = sk->sk_bound_dev_if; | 451 | fl6.flowi6_oif = sk->sk_bound_dev_if; |
433 | fl.mark = sk->sk_mark; | 452 | fl6.flowi6_mark = sk->sk_mark; |
434 | 453 | ||
435 | if (optlen == 0) | 454 | if (optlen == 0) |
436 | goto update; | 455 | goto update; |
@@ -456,7 +475,7 @@ sticky_done: | |||
456 | msg.msg_controllen = optlen; | 475 | msg.msg_controllen = optlen; |
457 | msg.msg_control = (void*)(opt+1); | 476 | msg.msg_control = (void*)(opt+1); |
458 | 477 | ||
459 | retv = datagram_send_ctl(net, &msg, &fl, opt, &junk, &junk, | 478 | retv = datagram_send_ctl(net, &msg, &fl6, opt, &junk, &junk, |
460 | &junk); | 479 | &junk); |
461 | if (retv) | 480 | if (retv) |
462 | goto done; | 481 | goto done; |
@@ -1104,6 +1123,14 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
1104 | break; | 1123 | break; |
1105 | } | 1124 | } |
1106 | 1125 | ||
1126 | case IPV6_TRANSPARENT: | ||
1127 | val = inet_sk(sk)->transparent; | ||
1128 | break; | ||
1129 | |||
1130 | case IPV6_RECVORIGDSTADDR: | ||
1131 | val = np->rxopt.bits.rxorigdstaddr; | ||
1132 | break; | ||
1133 | |||
1107 | case IPV6_UNICAST_HOPS: | 1134 | case IPV6_UNICAST_HOPS: |
1108 | case IPV6_MULTICAST_HOPS: | 1135 | case IPV6_MULTICAST_HOPS: |
1109 | { | 1136 | { |
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index d1444b95ad7e..3e6ebcdb4779 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c | |||
@@ -82,7 +82,7 @@ static void *__mld2_query_bugs[] __attribute__((__unused__)) = { | |||
82 | static struct in6_addr mld2_all_mcr = MLD2_ALL_MCR_INIT; | 82 | static struct in6_addr mld2_all_mcr = MLD2_ALL_MCR_INIT; |
83 | 83 | ||
84 | /* Big mc list lock for all the sockets */ | 84 | /* Big mc list lock for all the sockets */ |
85 | static DEFINE_RWLOCK(ipv6_sk_mc_lock); | 85 | static DEFINE_SPINLOCK(ipv6_sk_mc_lock); |
86 | 86 | ||
87 | static void igmp6_join_group(struct ifmcaddr6 *ma); | 87 | static void igmp6_join_group(struct ifmcaddr6 *ma); |
88 | static void igmp6_leave_group(struct ifmcaddr6 *ma); | 88 | static void igmp6_leave_group(struct ifmcaddr6 *ma); |
@@ -92,16 +92,16 @@ static void mld_gq_timer_expire(unsigned long data); | |||
92 | static void mld_ifc_timer_expire(unsigned long data); | 92 | static void mld_ifc_timer_expire(unsigned long data); |
93 | static void mld_ifc_event(struct inet6_dev *idev); | 93 | static void mld_ifc_event(struct inet6_dev *idev); |
94 | static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *pmc); | 94 | static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *pmc); |
95 | static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *addr); | 95 | static void mld_del_delrec(struct inet6_dev *idev, const struct in6_addr *addr); |
96 | static void mld_clear_delrec(struct inet6_dev *idev); | 96 | static void mld_clear_delrec(struct inet6_dev *idev); |
97 | static int sf_setstate(struct ifmcaddr6 *pmc); | 97 | static int sf_setstate(struct ifmcaddr6 *pmc); |
98 | static void sf_markstate(struct ifmcaddr6 *pmc); | 98 | static void sf_markstate(struct ifmcaddr6 *pmc); |
99 | static void ip6_mc_clear_src(struct ifmcaddr6 *pmc); | 99 | static void ip6_mc_clear_src(struct ifmcaddr6 *pmc); |
100 | static int ip6_mc_del_src(struct inet6_dev *idev, struct in6_addr *pmca, | 100 | static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *pmca, |
101 | int sfmode, int sfcount, struct in6_addr *psfsrc, | 101 | int sfmode, int sfcount, const struct in6_addr *psfsrc, |
102 | int delta); | 102 | int delta); |
103 | static int ip6_mc_add_src(struct inet6_dev *idev, struct in6_addr *pmca, | 103 | static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca, |
104 | int sfmode, int sfcount, struct in6_addr *psfsrc, | 104 | int sfmode, int sfcount, const struct in6_addr *psfsrc, |
105 | int delta); | 105 | int delta); |
106 | static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml, | 106 | static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml, |
107 | struct inet6_dev *idev); | 107 | struct inet6_dev *idev); |
@@ -123,6 +123,11 @@ int sysctl_mld_max_msf __read_mostly = IPV6_MLD_MAX_MSF; | |||
123 | * socket join on multicast group | 123 | * socket join on multicast group |
124 | */ | 124 | */ |
125 | 125 | ||
126 | #define for_each_pmc_rcu(np, pmc) \ | ||
127 | for (pmc = rcu_dereference(np->ipv6_mc_list); \ | ||
128 | pmc != NULL; \ | ||
129 | pmc = rcu_dereference(pmc->next)) | ||
130 | |||
126 | int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr) | 131 | int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr) |
127 | { | 132 | { |
128 | struct net_device *dev = NULL; | 133 | struct net_device *dev = NULL; |
@@ -134,15 +139,15 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
134 | if (!ipv6_addr_is_multicast(addr)) | 139 | if (!ipv6_addr_is_multicast(addr)) |
135 | return -EINVAL; | 140 | return -EINVAL; |
136 | 141 | ||
137 | read_lock_bh(&ipv6_sk_mc_lock); | 142 | rcu_read_lock(); |
138 | for (mc_lst=np->ipv6_mc_list; mc_lst; mc_lst=mc_lst->next) { | 143 | for_each_pmc_rcu(np, mc_lst) { |
139 | if ((ifindex == 0 || mc_lst->ifindex == ifindex) && | 144 | if ((ifindex == 0 || mc_lst->ifindex == ifindex) && |
140 | ipv6_addr_equal(&mc_lst->addr, addr)) { | 145 | ipv6_addr_equal(&mc_lst->addr, addr)) { |
141 | read_unlock_bh(&ipv6_sk_mc_lock); | 146 | rcu_read_unlock(); |
142 | return -EADDRINUSE; | 147 | return -EADDRINUSE; |
143 | } | 148 | } |
144 | } | 149 | } |
145 | read_unlock_bh(&ipv6_sk_mc_lock); | 150 | rcu_read_unlock(); |
146 | 151 | ||
147 | mc_lst = sock_kmalloc(sk, sizeof(struct ipv6_mc_socklist), GFP_KERNEL); | 152 | mc_lst = sock_kmalloc(sk, sizeof(struct ipv6_mc_socklist), GFP_KERNEL); |
148 | 153 | ||
@@ -186,10 +191,10 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
186 | return err; | 191 | return err; |
187 | } | 192 | } |
188 | 193 | ||
189 | write_lock_bh(&ipv6_sk_mc_lock); | 194 | spin_lock(&ipv6_sk_mc_lock); |
190 | mc_lst->next = np->ipv6_mc_list; | 195 | mc_lst->next = np->ipv6_mc_list; |
191 | np->ipv6_mc_list = mc_lst; | 196 | rcu_assign_pointer(np->ipv6_mc_list, mc_lst); |
192 | write_unlock_bh(&ipv6_sk_mc_lock); | 197 | spin_unlock(&ipv6_sk_mc_lock); |
193 | 198 | ||
194 | rcu_read_unlock(); | 199 | rcu_read_unlock(); |
195 | 200 | ||
@@ -202,17 +207,21 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
202 | int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr) | 207 | int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr) |
203 | { | 208 | { |
204 | struct ipv6_pinfo *np = inet6_sk(sk); | 209 | struct ipv6_pinfo *np = inet6_sk(sk); |
205 | struct ipv6_mc_socklist *mc_lst, **lnk; | 210 | struct ipv6_mc_socklist *mc_lst; |
211 | struct ipv6_mc_socklist __rcu **lnk; | ||
206 | struct net *net = sock_net(sk); | 212 | struct net *net = sock_net(sk); |
207 | 213 | ||
208 | write_lock_bh(&ipv6_sk_mc_lock); | 214 | spin_lock(&ipv6_sk_mc_lock); |
209 | for (lnk = &np->ipv6_mc_list; (mc_lst = *lnk) !=NULL ; lnk = &mc_lst->next) { | 215 | for (lnk = &np->ipv6_mc_list; |
216 | (mc_lst = rcu_dereference_protected(*lnk, | ||
217 | lockdep_is_held(&ipv6_sk_mc_lock))) !=NULL ; | ||
218 | lnk = &mc_lst->next) { | ||
210 | if ((ifindex == 0 || mc_lst->ifindex == ifindex) && | 219 | if ((ifindex == 0 || mc_lst->ifindex == ifindex) && |
211 | ipv6_addr_equal(&mc_lst->addr, addr)) { | 220 | ipv6_addr_equal(&mc_lst->addr, addr)) { |
212 | struct net_device *dev; | 221 | struct net_device *dev; |
213 | 222 | ||
214 | *lnk = mc_lst->next; | 223 | *lnk = mc_lst->next; |
215 | write_unlock_bh(&ipv6_sk_mc_lock); | 224 | spin_unlock(&ipv6_sk_mc_lock); |
216 | 225 | ||
217 | rcu_read_lock(); | 226 | rcu_read_lock(); |
218 | dev = dev_get_by_index_rcu(net, mc_lst->ifindex); | 227 | dev = dev_get_by_index_rcu(net, mc_lst->ifindex); |
@@ -225,18 +234,19 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
225 | } else | 234 | } else |
226 | (void) ip6_mc_leave_src(sk, mc_lst, NULL); | 235 | (void) ip6_mc_leave_src(sk, mc_lst, NULL); |
227 | rcu_read_unlock(); | 236 | rcu_read_unlock(); |
228 | sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); | 237 | atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc); |
238 | kfree_rcu(mc_lst, rcu); | ||
229 | return 0; | 239 | return 0; |
230 | } | 240 | } |
231 | } | 241 | } |
232 | write_unlock_bh(&ipv6_sk_mc_lock); | 242 | spin_unlock(&ipv6_sk_mc_lock); |
233 | 243 | ||
234 | return -EADDRNOTAVAIL; | 244 | return -EADDRNOTAVAIL; |
235 | } | 245 | } |
236 | 246 | ||
237 | /* called with rcu_read_lock() */ | 247 | /* called with rcu_read_lock() */ |
238 | static struct inet6_dev *ip6_mc_find_dev_rcu(struct net *net, | 248 | static struct inet6_dev *ip6_mc_find_dev_rcu(struct net *net, |
239 | struct in6_addr *group, | 249 | const struct in6_addr *group, |
240 | int ifindex) | 250 | int ifindex) |
241 | { | 251 | { |
242 | struct net_device *dev = NULL; | 252 | struct net_device *dev = NULL; |
@@ -257,7 +267,7 @@ static struct inet6_dev *ip6_mc_find_dev_rcu(struct net *net, | |||
257 | return NULL; | 267 | return NULL; |
258 | idev = __in6_dev_get(dev); | 268 | idev = __in6_dev_get(dev); |
259 | if (!idev) | 269 | if (!idev) |
260 | return NULL;; | 270 | return NULL; |
261 | read_lock_bh(&idev->lock); | 271 | read_lock_bh(&idev->lock); |
262 | if (idev->dead) { | 272 | if (idev->dead) { |
263 | read_unlock_bh(&idev->lock); | 273 | read_unlock_bh(&idev->lock); |
@@ -272,12 +282,13 @@ void ipv6_sock_mc_close(struct sock *sk) | |||
272 | struct ipv6_mc_socklist *mc_lst; | 282 | struct ipv6_mc_socklist *mc_lst; |
273 | struct net *net = sock_net(sk); | 283 | struct net *net = sock_net(sk); |
274 | 284 | ||
275 | write_lock_bh(&ipv6_sk_mc_lock); | 285 | spin_lock(&ipv6_sk_mc_lock); |
276 | while ((mc_lst = np->ipv6_mc_list) != NULL) { | 286 | while ((mc_lst = rcu_dereference_protected(np->ipv6_mc_list, |
287 | lockdep_is_held(&ipv6_sk_mc_lock))) != NULL) { | ||
277 | struct net_device *dev; | 288 | struct net_device *dev; |
278 | 289 | ||
279 | np->ipv6_mc_list = mc_lst->next; | 290 | np->ipv6_mc_list = mc_lst->next; |
280 | write_unlock_bh(&ipv6_sk_mc_lock); | 291 | spin_unlock(&ipv6_sk_mc_lock); |
281 | 292 | ||
282 | rcu_read_lock(); | 293 | rcu_read_lock(); |
283 | dev = dev_get_by_index_rcu(net, mc_lst->ifindex); | 294 | dev = dev_get_by_index_rcu(net, mc_lst->ifindex); |
@@ -290,11 +301,13 @@ void ipv6_sock_mc_close(struct sock *sk) | |||
290 | } else | 301 | } else |
291 | (void) ip6_mc_leave_src(sk, mc_lst, NULL); | 302 | (void) ip6_mc_leave_src(sk, mc_lst, NULL); |
292 | rcu_read_unlock(); | 303 | rcu_read_unlock(); |
293 | sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); | ||
294 | 304 | ||
295 | write_lock_bh(&ipv6_sk_mc_lock); | 305 | atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc); |
306 | kfree_rcu(mc_lst, rcu); | ||
307 | |||
308 | spin_lock(&ipv6_sk_mc_lock); | ||
296 | } | 309 | } |
297 | write_unlock_bh(&ipv6_sk_mc_lock); | 310 | spin_unlock(&ipv6_sk_mc_lock); |
298 | } | 311 | } |
299 | 312 | ||
300 | int ip6_mc_source(int add, int omode, struct sock *sk, | 313 | int ip6_mc_source(int add, int omode, struct sock *sk, |
@@ -302,7 +315,6 @@ int ip6_mc_source(int add, int omode, struct sock *sk, | |||
302 | { | 315 | { |
303 | struct in6_addr *source, *group; | 316 | struct in6_addr *source, *group; |
304 | struct ipv6_mc_socklist *pmc; | 317 | struct ipv6_mc_socklist *pmc; |
305 | struct net_device *dev; | ||
306 | struct inet6_dev *idev; | 318 | struct inet6_dev *idev; |
307 | struct ipv6_pinfo *inet6 = inet6_sk(sk); | 319 | struct ipv6_pinfo *inet6 = inet6_sk(sk); |
308 | struct ip6_sf_socklist *psl; | 320 | struct ip6_sf_socklist *psl; |
@@ -324,12 +336,10 @@ int ip6_mc_source(int add, int omode, struct sock *sk, | |||
324 | rcu_read_unlock(); | 336 | rcu_read_unlock(); |
325 | return -ENODEV; | 337 | return -ENODEV; |
326 | } | 338 | } |
327 | dev = idev->dev; | ||
328 | 339 | ||
329 | err = -EADDRNOTAVAIL; | 340 | err = -EADDRNOTAVAIL; |
330 | 341 | ||
331 | read_lock(&ipv6_sk_mc_lock); | 342 | for_each_pmc_rcu(inet6, pmc) { |
332 | for (pmc=inet6->ipv6_mc_list; pmc; pmc=pmc->next) { | ||
333 | if (pgsr->gsr_interface && pmc->ifindex != pgsr->gsr_interface) | 343 | if (pgsr->gsr_interface && pmc->ifindex != pgsr->gsr_interface) |
334 | continue; | 344 | continue; |
335 | if (ipv6_addr_equal(&pmc->addr, group)) | 345 | if (ipv6_addr_equal(&pmc->addr, group)) |
@@ -428,7 +438,6 @@ int ip6_mc_source(int add, int omode, struct sock *sk, | |||
428 | done: | 438 | done: |
429 | if (pmclocked) | 439 | if (pmclocked) |
430 | write_unlock(&pmc->sflock); | 440 | write_unlock(&pmc->sflock); |
431 | read_unlock(&ipv6_sk_mc_lock); | ||
432 | read_unlock_bh(&idev->lock); | 441 | read_unlock_bh(&idev->lock); |
433 | rcu_read_unlock(); | 442 | rcu_read_unlock(); |
434 | if (leavegroup) | 443 | if (leavegroup) |
@@ -438,9 +447,8 @@ done: | |||
438 | 447 | ||
439 | int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf) | 448 | int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf) |
440 | { | 449 | { |
441 | struct in6_addr *group; | 450 | const struct in6_addr *group; |
442 | struct ipv6_mc_socklist *pmc; | 451 | struct ipv6_mc_socklist *pmc; |
443 | struct net_device *dev; | ||
444 | struct inet6_dev *idev; | 452 | struct inet6_dev *idev; |
445 | struct ipv6_pinfo *inet6 = inet6_sk(sk); | 453 | struct ipv6_pinfo *inet6 = inet6_sk(sk); |
446 | struct ip6_sf_socklist *newpsl, *psl; | 454 | struct ip6_sf_socklist *newpsl, *psl; |
@@ -463,17 +471,15 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf) | |||
463 | rcu_read_unlock(); | 471 | rcu_read_unlock(); |
464 | return -ENODEV; | 472 | return -ENODEV; |
465 | } | 473 | } |
466 | dev = idev->dev; | ||
467 | 474 | ||
468 | err = 0; | 475 | err = 0; |
469 | read_lock(&ipv6_sk_mc_lock); | ||
470 | 476 | ||
471 | if (gsf->gf_fmode == MCAST_INCLUDE && gsf->gf_numsrc == 0) { | 477 | if (gsf->gf_fmode == MCAST_INCLUDE && gsf->gf_numsrc == 0) { |
472 | leavegroup = 1; | 478 | leavegroup = 1; |
473 | goto done; | 479 | goto done; |
474 | } | 480 | } |
475 | 481 | ||
476 | for (pmc=inet6->ipv6_mc_list; pmc; pmc=pmc->next) { | 482 | for_each_pmc_rcu(inet6, pmc) { |
477 | if (pmc->ifindex != gsf->gf_interface) | 483 | if (pmc->ifindex != gsf->gf_interface) |
478 | continue; | 484 | continue; |
479 | if (ipv6_addr_equal(&pmc->addr, group)) | 485 | if (ipv6_addr_equal(&pmc->addr, group)) |
@@ -521,7 +527,6 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf) | |||
521 | write_unlock(&pmc->sflock); | 527 | write_unlock(&pmc->sflock); |
522 | err = 0; | 528 | err = 0; |
523 | done: | 529 | done: |
524 | read_unlock(&ipv6_sk_mc_lock); | ||
525 | read_unlock_bh(&idev->lock); | 530 | read_unlock_bh(&idev->lock); |
526 | rcu_read_unlock(); | 531 | rcu_read_unlock(); |
527 | if (leavegroup) | 532 | if (leavegroup) |
@@ -533,10 +538,9 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf, | |||
533 | struct group_filter __user *optval, int __user *optlen) | 538 | struct group_filter __user *optval, int __user *optlen) |
534 | { | 539 | { |
535 | int err, i, count, copycount; | 540 | int err, i, count, copycount; |
536 | struct in6_addr *group; | 541 | const struct in6_addr *group; |
537 | struct ipv6_mc_socklist *pmc; | 542 | struct ipv6_mc_socklist *pmc; |
538 | struct inet6_dev *idev; | 543 | struct inet6_dev *idev; |
539 | struct net_device *dev; | ||
540 | struct ipv6_pinfo *inet6 = inet6_sk(sk); | 544 | struct ipv6_pinfo *inet6 = inet6_sk(sk); |
541 | struct ip6_sf_socklist *psl; | 545 | struct ip6_sf_socklist *psl; |
542 | struct net *net = sock_net(sk); | 546 | struct net *net = sock_net(sk); |
@@ -553,7 +557,6 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf, | |||
553 | rcu_read_unlock(); | 557 | rcu_read_unlock(); |
554 | return -ENODEV; | 558 | return -ENODEV; |
555 | } | 559 | } |
556 | dev = idev->dev; | ||
557 | 560 | ||
558 | err = -EADDRNOTAVAIL; | 561 | err = -EADDRNOTAVAIL; |
559 | /* | 562 | /* |
@@ -562,7 +565,7 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf, | |||
562 | * so reading the list is safe. | 565 | * so reading the list is safe. |
563 | */ | 566 | */ |
564 | 567 | ||
565 | for (pmc=inet6->ipv6_mc_list; pmc; pmc=pmc->next) { | 568 | for_each_pmc_rcu(inet6, pmc) { |
566 | if (pmc->ifindex != gsf->gf_interface) | 569 | if (pmc->ifindex != gsf->gf_interface) |
567 | continue; | 570 | continue; |
568 | if (ipv6_addr_equal(group, &pmc->addr)) | 571 | if (ipv6_addr_equal(group, &pmc->addr)) |
@@ -612,13 +615,13 @@ int inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr, | |||
612 | struct ip6_sf_socklist *psl; | 615 | struct ip6_sf_socklist *psl; |
613 | int rv = 1; | 616 | int rv = 1; |
614 | 617 | ||
615 | read_lock(&ipv6_sk_mc_lock); | 618 | rcu_read_lock(); |
616 | for (mc = np->ipv6_mc_list; mc; mc = mc->next) { | 619 | for_each_pmc_rcu(np, mc) { |
617 | if (ipv6_addr_equal(&mc->addr, mc_addr)) | 620 | if (ipv6_addr_equal(&mc->addr, mc_addr)) |
618 | break; | 621 | break; |
619 | } | 622 | } |
620 | if (!mc) { | 623 | if (!mc) { |
621 | read_unlock(&ipv6_sk_mc_lock); | 624 | rcu_read_unlock(); |
622 | return 1; | 625 | return 1; |
623 | } | 626 | } |
624 | read_lock(&mc->sflock); | 627 | read_lock(&mc->sflock); |
@@ -638,7 +641,7 @@ int inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr, | |||
638 | rv = 0; | 641 | rv = 0; |
639 | } | 642 | } |
640 | read_unlock(&mc->sflock); | 643 | read_unlock(&mc->sflock); |
641 | read_unlock(&ipv6_sk_mc_lock); | 644 | rcu_read_unlock(); |
642 | 645 | ||
643 | return rv; | 646 | return rv; |
644 | } | 647 | } |
@@ -745,7 +748,7 @@ static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im) | |||
745 | spin_unlock_bh(&idev->mc_lock); | 748 | spin_unlock_bh(&idev->mc_lock); |
746 | } | 749 | } |
747 | 750 | ||
748 | static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *pmca) | 751 | static void mld_del_delrec(struct inet6_dev *idev, const struct in6_addr *pmca) |
749 | { | 752 | { |
750 | struct ifmcaddr6 *pmc, *pmc_prev; | 753 | struct ifmcaddr6 *pmc, *pmc_prev; |
751 | struct ip6_sf_list *psf, *psf_next; | 754 | struct ip6_sf_list *psf, *psf_next; |
@@ -1045,7 +1048,7 @@ static void igmp6_group_queried(struct ifmcaddr6 *ma, unsigned long resptime) | |||
1045 | 1048 | ||
1046 | /* mark EXCLUDE-mode sources */ | 1049 | /* mark EXCLUDE-mode sources */ |
1047 | static int mld_xmarksources(struct ifmcaddr6 *pmc, int nsrcs, | 1050 | static int mld_xmarksources(struct ifmcaddr6 *pmc, int nsrcs, |
1048 | struct in6_addr *srcs) | 1051 | const struct in6_addr *srcs) |
1049 | { | 1052 | { |
1050 | struct ip6_sf_list *psf; | 1053 | struct ip6_sf_list *psf; |
1051 | int i, scount; | 1054 | int i, scount; |
@@ -1073,7 +1076,7 @@ static int mld_xmarksources(struct ifmcaddr6 *pmc, int nsrcs, | |||
1073 | } | 1076 | } |
1074 | 1077 | ||
1075 | static int mld_marksources(struct ifmcaddr6 *pmc, int nsrcs, | 1078 | static int mld_marksources(struct ifmcaddr6 *pmc, int nsrcs, |
1076 | struct in6_addr *srcs) | 1079 | const struct in6_addr *srcs) |
1077 | { | 1080 | { |
1078 | struct ip6_sf_list *psf; | 1081 | struct ip6_sf_list *psf; |
1079 | int i, scount; | 1082 | int i, scount; |
@@ -1108,7 +1111,7 @@ int igmp6_event_query(struct sk_buff *skb) | |||
1108 | { | 1111 | { |
1109 | struct mld2_query *mlh2 = NULL; | 1112 | struct mld2_query *mlh2 = NULL; |
1110 | struct ifmcaddr6 *ma; | 1113 | struct ifmcaddr6 *ma; |
1111 | struct in6_addr *group; | 1114 | const struct in6_addr *group; |
1112 | unsigned long max_delay; | 1115 | unsigned long max_delay; |
1113 | struct inet6_dev *idev; | 1116 | struct inet6_dev *idev; |
1114 | struct mld_msg *mld; | 1117 | struct mld_msg *mld; |
@@ -1389,7 +1392,7 @@ static void mld_sendpack(struct sk_buff *skb) | |||
1389 | struct inet6_dev *idev; | 1392 | struct inet6_dev *idev; |
1390 | struct net *net = dev_net(skb->dev); | 1393 | struct net *net = dev_net(skb->dev); |
1391 | int err; | 1394 | int err; |
1392 | struct flowi fl; | 1395 | struct flowi6 fl6; |
1393 | struct dst_entry *dst; | 1396 | struct dst_entry *dst; |
1394 | 1397 | ||
1395 | rcu_read_lock(); | 1398 | rcu_read_lock(); |
@@ -1412,11 +1415,16 @@ static void mld_sendpack(struct sk_buff *skb) | |||
1412 | goto err_out; | 1415 | goto err_out; |
1413 | } | 1416 | } |
1414 | 1417 | ||
1415 | icmpv6_flow_init(net->ipv6.igmp_sk, &fl, ICMPV6_MLD2_REPORT, | 1418 | icmpv6_flow_init(net->ipv6.igmp_sk, &fl6, ICMPV6_MLD2_REPORT, |
1416 | &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, | 1419 | &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, |
1417 | skb->dev->ifindex); | 1420 | skb->dev->ifindex); |
1418 | 1421 | ||
1419 | err = xfrm_lookup(net, &dst, &fl, NULL, 0); | 1422 | dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0); |
1423 | err = 0; | ||
1424 | if (IS_ERR(dst)) { | ||
1425 | err = PTR_ERR(dst); | ||
1426 | dst = NULL; | ||
1427 | } | ||
1420 | skb_dst_set(skb, dst); | 1428 | skb_dst_set(skb, dst); |
1421 | if (err) | 1429 | if (err) |
1422 | goto err_out; | 1430 | goto err_out; |
@@ -1719,7 +1727,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) | |||
1719 | u8 ra[8] = { IPPROTO_ICMPV6, 0, | 1727 | u8 ra[8] = { IPPROTO_ICMPV6, 0, |
1720 | IPV6_TLV_ROUTERALERT, 2, 0, 0, | 1728 | IPV6_TLV_ROUTERALERT, 2, 0, 0, |
1721 | IPV6_TLV_PADN, 0 }; | 1729 | IPV6_TLV_PADN, 0 }; |
1722 | struct flowi fl; | 1730 | struct flowi6 fl6; |
1723 | struct dst_entry *dst; | 1731 | struct dst_entry *dst; |
1724 | 1732 | ||
1725 | if (type == ICMPV6_MGM_REDUCTION) | 1733 | if (type == ICMPV6_MGM_REDUCTION) |
@@ -1779,13 +1787,15 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) | |||
1779 | goto err_out; | 1787 | goto err_out; |
1780 | } | 1788 | } |
1781 | 1789 | ||
1782 | icmpv6_flow_init(sk, &fl, type, | 1790 | icmpv6_flow_init(sk, &fl6, type, |
1783 | &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, | 1791 | &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, |
1784 | skb->dev->ifindex); | 1792 | skb->dev->ifindex); |
1785 | 1793 | ||
1786 | err = xfrm_lookup(net, &dst, &fl, NULL, 0); | 1794 | dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0); |
1787 | if (err) | 1795 | if (IS_ERR(dst)) { |
1796 | err = PTR_ERR(dst); | ||
1788 | goto err_out; | 1797 | goto err_out; |
1798 | } | ||
1789 | 1799 | ||
1790 | skb_dst_set(skb, dst); | 1800 | skb_dst_set(skb, dst); |
1791 | err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev, | 1801 | err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev, |
@@ -1807,7 +1817,7 @@ err_out: | |||
1807 | } | 1817 | } |
1808 | 1818 | ||
1809 | static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode, | 1819 | static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode, |
1810 | struct in6_addr *psfsrc) | 1820 | const struct in6_addr *psfsrc) |
1811 | { | 1821 | { |
1812 | struct ip6_sf_list *psf, *psf_prev; | 1822 | struct ip6_sf_list *psf, *psf_prev; |
1813 | int rv = 0; | 1823 | int rv = 0; |
@@ -1843,8 +1853,8 @@ static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode, | |||
1843 | return rv; | 1853 | return rv; |
1844 | } | 1854 | } |
1845 | 1855 | ||
1846 | static int ip6_mc_del_src(struct inet6_dev *idev, struct in6_addr *pmca, | 1856 | static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *pmca, |
1847 | int sfmode, int sfcount, struct in6_addr *psfsrc, | 1857 | int sfmode, int sfcount, const struct in6_addr *psfsrc, |
1848 | int delta) | 1858 | int delta) |
1849 | { | 1859 | { |
1850 | struct ifmcaddr6 *pmc; | 1860 | struct ifmcaddr6 *pmc; |
@@ -1904,7 +1914,7 @@ static int ip6_mc_del_src(struct inet6_dev *idev, struct in6_addr *pmca, | |||
1904 | * Add multicast single-source filter to the interface list | 1914 | * Add multicast single-source filter to the interface list |
1905 | */ | 1915 | */ |
1906 | static int ip6_mc_add1_src(struct ifmcaddr6 *pmc, int sfmode, | 1916 | static int ip6_mc_add1_src(struct ifmcaddr6 *pmc, int sfmode, |
1907 | struct in6_addr *psfsrc, int delta) | 1917 | const struct in6_addr *psfsrc, int delta) |
1908 | { | 1918 | { |
1909 | struct ip6_sf_list *psf, *psf_prev; | 1919 | struct ip6_sf_list *psf, *psf_prev; |
1910 | 1920 | ||
@@ -2007,8 +2017,8 @@ static int sf_setstate(struct ifmcaddr6 *pmc) | |||
2007 | /* | 2017 | /* |
2008 | * Add multicast source filter list to the interface list | 2018 | * Add multicast source filter list to the interface list |
2009 | */ | 2019 | */ |
2010 | static int ip6_mc_add_src(struct inet6_dev *idev, struct in6_addr *pmca, | 2020 | static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca, |
2011 | int sfmode, int sfcount, struct in6_addr *psfsrc, | 2021 | int sfmode, int sfcount, const struct in6_addr *psfsrc, |
2012 | int delta) | 2022 | int delta) |
2013 | { | 2023 | { |
2014 | struct ifmcaddr6 *pmc; | 2024 | struct ifmcaddr6 *pmc; |
diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c index d6e9599d0705..43242e6e6103 100644 --- a/net/ipv6/mip6.c +++ b/net/ipv6/mip6.c | |||
@@ -126,7 +126,7 @@ static struct mip6_report_rate_limiter mip6_report_rl = { | |||
126 | 126 | ||
127 | static int mip6_destopt_input(struct xfrm_state *x, struct sk_buff *skb) | 127 | static int mip6_destopt_input(struct xfrm_state *x, struct sk_buff *skb) |
128 | { | 128 | { |
129 | struct ipv6hdr *iph = ipv6_hdr(skb); | 129 | const struct ipv6hdr *iph = ipv6_hdr(skb); |
130 | struct ipv6_destopt_hdr *destopt = (struct ipv6_destopt_hdr *)skb->data; | 130 | struct ipv6_destopt_hdr *destopt = (struct ipv6_destopt_hdr *)skb->data; |
131 | int err = destopt->nexthdr; | 131 | int err = destopt->nexthdr; |
132 | 132 | ||
@@ -181,8 +181,8 @@ static int mip6_destopt_output(struct xfrm_state *x, struct sk_buff *skb) | |||
181 | } | 181 | } |
182 | 182 | ||
183 | static inline int mip6_report_rl_allow(struct timeval *stamp, | 183 | static inline int mip6_report_rl_allow(struct timeval *stamp, |
184 | struct in6_addr *dst, | 184 | const struct in6_addr *dst, |
185 | struct in6_addr *src, int iif) | 185 | const struct in6_addr *src, int iif) |
186 | { | 186 | { |
187 | int allow = 0; | 187 | int allow = 0; |
188 | 188 | ||
@@ -203,18 +203,20 @@ static inline int mip6_report_rl_allow(struct timeval *stamp, | |||
203 | return allow; | 203 | return allow; |
204 | } | 204 | } |
205 | 205 | ||
206 | static int mip6_destopt_reject(struct xfrm_state *x, struct sk_buff *skb, struct flowi *fl) | 206 | static int mip6_destopt_reject(struct xfrm_state *x, struct sk_buff *skb, |
207 | const struct flowi *fl) | ||
207 | { | 208 | { |
208 | struct net *net = xs_net(x); | 209 | struct net *net = xs_net(x); |
209 | struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb; | 210 | struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb; |
211 | const struct flowi6 *fl6 = &fl->u.ip6; | ||
210 | struct ipv6_destopt_hao *hao = NULL; | 212 | struct ipv6_destopt_hao *hao = NULL; |
211 | struct xfrm_selector sel; | 213 | struct xfrm_selector sel; |
212 | int offset; | 214 | int offset; |
213 | struct timeval stamp; | 215 | struct timeval stamp; |
214 | int err = 0; | 216 | int err = 0; |
215 | 217 | ||
216 | if (unlikely(fl->proto == IPPROTO_MH && | 218 | if (unlikely(fl6->flowi6_proto == IPPROTO_MH && |
217 | fl->fl_mh_type <= IP6_MH_TYPE_MAX)) | 219 | fl6->fl6_mh_type <= IP6_MH_TYPE_MAX)) |
218 | goto out; | 220 | goto out; |
219 | 221 | ||
220 | if (likely(opt->dsthao)) { | 222 | if (likely(opt->dsthao)) { |
@@ -239,14 +241,14 @@ static int mip6_destopt_reject(struct xfrm_state *x, struct sk_buff *skb, struct | |||
239 | sizeof(sel.saddr)); | 241 | sizeof(sel.saddr)); |
240 | sel.prefixlen_s = 128; | 242 | sel.prefixlen_s = 128; |
241 | sel.family = AF_INET6; | 243 | sel.family = AF_INET6; |
242 | sel.proto = fl->proto; | 244 | sel.proto = fl6->flowi6_proto; |
243 | sel.dport = xfrm_flowi_dport(fl); | 245 | sel.dport = xfrm_flowi_dport(fl, &fl6->uli); |
244 | if (sel.dport) | 246 | if (sel.dport) |
245 | sel.dport_mask = htons(~0); | 247 | sel.dport_mask = htons(~0); |
246 | sel.sport = xfrm_flowi_sport(fl); | 248 | sel.sport = xfrm_flowi_sport(fl, &fl6->uli); |
247 | if (sel.sport) | 249 | if (sel.sport) |
248 | sel.sport_mask = htons(~0); | 250 | sel.sport_mask = htons(~0); |
249 | sel.ifindex = fl->oif; | 251 | sel.ifindex = fl6->flowi6_oif; |
250 | 252 | ||
251 | err = km_report(net, IPPROTO_DSTOPTS, &sel, | 253 | err = km_report(net, IPPROTO_DSTOPTS, &sel, |
252 | (hao ? (xfrm_address_t *)&hao->addr : NULL)); | 254 | (hao ? (xfrm_address_t *)&hao->addr : NULL)); |
@@ -347,7 +349,7 @@ static const struct xfrm_type mip6_destopt_type = | |||
347 | 349 | ||
348 | static int mip6_rthdr_input(struct xfrm_state *x, struct sk_buff *skb) | 350 | static int mip6_rthdr_input(struct xfrm_state *x, struct sk_buff *skb) |
349 | { | 351 | { |
350 | struct ipv6hdr *iph = ipv6_hdr(skb); | 352 | const struct ipv6hdr *iph = ipv6_hdr(skb); |
351 | struct rt2_hdr *rt2 = (struct rt2_hdr *)skb->data; | 353 | struct rt2_hdr *rt2 = (struct rt2_hdr *)skb->data; |
352 | int err = rt2->rt_hdr.nexthdr; | 354 | int err = rt2->rt_hdr.nexthdr; |
353 | 355 | ||
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 58841c4ae947..7596f071d308 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
@@ -91,7 +91,9 @@ | |||
91 | #include <linux/netfilter.h> | 91 | #include <linux/netfilter.h> |
92 | #include <linux/netfilter_ipv6.h> | 92 | #include <linux/netfilter_ipv6.h> |
93 | 93 | ||
94 | static u32 ndisc_hash(const void *pkey, const struct net_device *dev); | 94 | static u32 ndisc_hash(const void *pkey, |
95 | const struct net_device *dev, | ||
96 | __u32 rnd); | ||
95 | static int ndisc_constructor(struct neighbour *neigh); | 97 | static int ndisc_constructor(struct neighbour *neigh); |
96 | static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb); | 98 | static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb); |
97 | static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb); | 99 | static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb); |
@@ -139,18 +141,18 @@ struct neigh_table nd_tbl = { | |||
139 | .proxy_redo = pndisc_redo, | 141 | .proxy_redo = pndisc_redo, |
140 | .id = "ndisc_cache", | 142 | .id = "ndisc_cache", |
141 | .parms = { | 143 | .parms = { |
142 | .tbl = &nd_tbl, | 144 | .tbl = &nd_tbl, |
143 | .base_reachable_time = 30 * HZ, | 145 | .base_reachable_time = ND_REACHABLE_TIME, |
144 | .retrans_time = 1 * HZ, | 146 | .retrans_time = ND_RETRANS_TIMER, |
145 | .gc_staletime = 60 * HZ, | 147 | .gc_staletime = 60 * HZ, |
146 | .reachable_time = 30 * HZ, | 148 | .reachable_time = ND_REACHABLE_TIME, |
147 | .delay_probe_time = 5 * HZ, | 149 | .delay_probe_time = 5 * HZ, |
148 | .queue_len = 3, | 150 | .queue_len = 3, |
149 | .ucast_probes = 3, | 151 | .ucast_probes = 3, |
150 | .mcast_probes = 3, | 152 | .mcast_probes = 3, |
151 | .anycast_delay = 1 * HZ, | 153 | .anycast_delay = 1 * HZ, |
152 | .proxy_delay = (8 * HZ) / 10, | 154 | .proxy_delay = (8 * HZ) / 10, |
153 | .proxy_qlen = 64, | 155 | .proxy_qlen = 64, |
154 | }, | 156 | }, |
155 | .gc_interval = 30 * HZ, | 157 | .gc_interval = 30 * HZ, |
156 | .gc_thresh1 = 128, | 158 | .gc_thresh1 = 128, |
@@ -228,12 +230,12 @@ static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur, | |||
228 | do { | 230 | do { |
229 | cur = ((void *)cur) + (cur->nd_opt_len << 3); | 231 | cur = ((void *)cur) + (cur->nd_opt_len << 3); |
230 | } while(cur < end && cur->nd_opt_type != type); | 232 | } while(cur < end && cur->nd_opt_type != type); |
231 | return (cur <= end && cur->nd_opt_type == type ? cur : NULL); | 233 | return cur <= end && cur->nd_opt_type == type ? cur : NULL; |
232 | } | 234 | } |
233 | 235 | ||
234 | static inline int ndisc_is_useropt(struct nd_opt_hdr *opt) | 236 | static inline int ndisc_is_useropt(struct nd_opt_hdr *opt) |
235 | { | 237 | { |
236 | return (opt->nd_opt_type == ND_OPT_RDNSS); | 238 | return opt->nd_opt_type == ND_OPT_RDNSS; |
237 | } | 239 | } |
238 | 240 | ||
239 | static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur, | 241 | static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur, |
@@ -244,7 +246,7 @@ static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur, | |||
244 | do { | 246 | do { |
245 | cur = ((void *)cur) + (cur->nd_opt_len << 3); | 247 | cur = ((void *)cur) + (cur->nd_opt_len << 3); |
246 | } while(cur < end && !ndisc_is_useropt(cur)); | 248 | } while(cur < end && !ndisc_is_useropt(cur)); |
247 | return (cur <= end && ndisc_is_useropt(cur) ? cur : NULL); | 249 | return cur <= end && ndisc_is_useropt(cur) ? cur : NULL; |
248 | } | 250 | } |
249 | 251 | ||
250 | static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, | 252 | static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, |
@@ -319,10 +321,10 @@ static inline u8 *ndisc_opt_addr_data(struct nd_opt_hdr *p, | |||
319 | int prepad = ndisc_addr_option_pad(dev->type); | 321 | int prepad = ndisc_addr_option_pad(dev->type); |
320 | if (lladdrlen != NDISC_OPT_SPACE(dev->addr_len + prepad)) | 322 | if (lladdrlen != NDISC_OPT_SPACE(dev->addr_len + prepad)) |
321 | return NULL; | 323 | return NULL; |
322 | return (lladdr + prepad); | 324 | return lladdr + prepad; |
323 | } | 325 | } |
324 | 326 | ||
325 | int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int dir) | 327 | int ndisc_mc_map(const struct in6_addr *addr, char *buf, struct net_device *dev, int dir) |
326 | { | 328 | { |
327 | switch (dev->type) { | 329 | switch (dev->type) { |
328 | case ARPHRD_ETHER: | 330 | case ARPHRD_ETHER: |
@@ -339,6 +341,8 @@ int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int d | |||
339 | case ARPHRD_INFINIBAND: | 341 | case ARPHRD_INFINIBAND: |
340 | ipv6_ib_mc_map(addr, dev->broadcast, buf); | 342 | ipv6_ib_mc_map(addr, dev->broadcast, buf); |
341 | return 0; | 343 | return 0; |
344 | case ARPHRD_IPGRE: | ||
345 | return ipv6_ipgre_mc_map(addr, dev->broadcast, buf); | ||
342 | default: | 346 | default: |
343 | if (dir) { | 347 | if (dir) { |
344 | memcpy(buf, dev->broadcast, dev->addr_len); | 348 | memcpy(buf, dev->broadcast, dev->addr_len); |
@@ -350,7 +354,9 @@ int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int d | |||
350 | 354 | ||
351 | EXPORT_SYMBOL(ndisc_mc_map); | 355 | EXPORT_SYMBOL(ndisc_mc_map); |
352 | 356 | ||
353 | static u32 ndisc_hash(const void *pkey, const struct net_device *dev) | 357 | static u32 ndisc_hash(const void *pkey, |
358 | const struct net_device *dev, | ||
359 | __u32 hash_rnd) | ||
354 | { | 360 | { |
355 | const u32 *p32 = pkey; | 361 | const u32 *p32 = pkey; |
356 | u32 addr_hash, i; | 362 | u32 addr_hash, i; |
@@ -359,7 +365,7 @@ static u32 ndisc_hash(const void *pkey, const struct net_device *dev) | |||
359 | for (i = 0; i < (sizeof(struct in6_addr) / sizeof(u32)); i++) | 365 | for (i = 0; i < (sizeof(struct in6_addr) / sizeof(u32)); i++) |
360 | addr_hash ^= *p32++; | 366 | addr_hash ^= *p32++; |
361 | 367 | ||
362 | return jhash_2words(addr_hash, dev->ifindex, nd_tbl.hash_rnd); | 368 | return jhash_2words(addr_hash, dev->ifindex, hash_rnd); |
363 | } | 369 | } |
364 | 370 | ||
365 | static int ndisc_constructor(struct neighbour *neigh) | 371 | static int ndisc_constructor(struct neighbour *neigh) |
@@ -507,7 +513,7 @@ void ndisc_send_skb(struct sk_buff *skb, | |||
507 | const struct in6_addr *saddr, | 513 | const struct in6_addr *saddr, |
508 | struct icmp6hdr *icmp6h) | 514 | struct icmp6hdr *icmp6h) |
509 | { | 515 | { |
510 | struct flowi fl; | 516 | struct flowi6 fl6; |
511 | struct dst_entry *dst; | 517 | struct dst_entry *dst; |
512 | struct net *net = dev_net(dev); | 518 | struct net *net = dev_net(dev); |
513 | struct sock *sk = net->ipv6.ndisc_sk; | 519 | struct sock *sk = net->ipv6.ndisc_sk; |
@@ -517,7 +523,7 @@ void ndisc_send_skb(struct sk_buff *skb, | |||
517 | 523 | ||
518 | type = icmp6h->icmp6_type; | 524 | type = icmp6h->icmp6_type; |
519 | 525 | ||
520 | icmpv6_flow_init(sk, &fl, type, saddr, daddr, dev->ifindex); | 526 | icmpv6_flow_init(sk, &fl6, type, saddr, daddr, dev->ifindex); |
521 | 527 | ||
522 | dst = icmp6_dst_alloc(dev, neigh, daddr); | 528 | dst = icmp6_dst_alloc(dev, neigh, daddr); |
523 | if (!dst) { | 529 | if (!dst) { |
@@ -525,8 +531,8 @@ void ndisc_send_skb(struct sk_buff *skb, | |||
525 | return; | 531 | return; |
526 | } | 532 | } |
527 | 533 | ||
528 | err = xfrm_lookup(net, &dst, &fl, NULL, 0); | 534 | dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0); |
529 | if (err < 0) { | 535 | if (IS_ERR(dst)) { |
530 | kfree_skb(skb); | 536 | kfree_skb(skb); |
531 | return; | 537 | return; |
532 | } | 538 | } |
@@ -605,6 +611,29 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, | |||
605 | inc_opt ? ND_OPT_TARGET_LL_ADDR : 0); | 611 | inc_opt ? ND_OPT_TARGET_LL_ADDR : 0); |
606 | } | 612 | } |
607 | 613 | ||
614 | static void ndisc_send_unsol_na(struct net_device *dev) | ||
615 | { | ||
616 | struct inet6_dev *idev; | ||
617 | struct inet6_ifaddr *ifa; | ||
618 | struct in6_addr mcaddr; | ||
619 | |||
620 | idev = in6_dev_get(dev); | ||
621 | if (!idev) | ||
622 | return; | ||
623 | |||
624 | read_lock_bh(&idev->lock); | ||
625 | list_for_each_entry(ifa, &idev->addr_list, if_list) { | ||
626 | addrconf_addr_solict_mult(&ifa->addr, &mcaddr); | ||
627 | ndisc_send_na(dev, NULL, &mcaddr, &ifa->addr, | ||
628 | /*router=*/ !!idev->cnf.forwarding, | ||
629 | /*solicited=*/ false, /*override=*/ true, | ||
630 | /*inc_opt=*/ true); | ||
631 | } | ||
632 | read_unlock_bh(&idev->lock); | ||
633 | |||
634 | in6_dev_put(idev); | ||
635 | } | ||
636 | |||
608 | void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, | 637 | void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, |
609 | const struct in6_addr *solicit, | 638 | const struct in6_addr *solicit, |
610 | const struct in6_addr *daddr, const struct in6_addr *saddr) | 639 | const struct in6_addr *daddr, const struct in6_addr *saddr) |
@@ -719,8 +748,8 @@ static int pndisc_is_router(const void *pkey, | |||
719 | static void ndisc_recv_ns(struct sk_buff *skb) | 748 | static void ndisc_recv_ns(struct sk_buff *skb) |
720 | { | 749 | { |
721 | struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb); | 750 | struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb); |
722 | struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; | 751 | const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; |
723 | struct in6_addr *daddr = &ipv6_hdr(skb)->daddr; | 752 | const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr; |
724 | u8 *lladdr = NULL; | 753 | u8 *lladdr = NULL; |
725 | u32 ndoptlen = skb->tail - (skb->transport_header + | 754 | u32 ndoptlen = skb->tail - (skb->transport_header + |
726 | offsetof(struct nd_msg, opt)); | 755 | offsetof(struct nd_msg, opt)); |
@@ -895,8 +924,8 @@ out: | |||
895 | static void ndisc_recv_na(struct sk_buff *skb) | 924 | static void ndisc_recv_na(struct sk_buff *skb) |
896 | { | 925 | { |
897 | struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb); | 926 | struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb); |
898 | struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; | 927 | const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; |
899 | struct in6_addr *daddr = &ipv6_hdr(skb)->daddr; | 928 | const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr; |
900 | u8 *lladdr = NULL; | 929 | u8 *lladdr = NULL; |
901 | u32 ndoptlen = skb->tail - (skb->transport_header + | 930 | u32 ndoptlen = skb->tail - (skb->transport_header + |
902 | offsetof(struct nd_msg, opt)); | 931 | offsetof(struct nd_msg, opt)); |
@@ -939,9 +968,10 @@ static void ndisc_recv_na(struct sk_buff *skb) | |||
939 | } | 968 | } |
940 | ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1); | 969 | ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1); |
941 | if (ifp) { | 970 | if (ifp) { |
942 | if (ifp->flags & IFA_F_TENTATIVE) { | 971 | if (skb->pkt_type != PACKET_LOOPBACK |
943 | addrconf_dad_failure(ifp); | 972 | && (ifp->flags & IFA_F_TENTATIVE)) { |
944 | return; | 973 | addrconf_dad_failure(ifp); |
974 | return; | ||
945 | } | 975 | } |
946 | /* What should we make now? The advertisement | 976 | /* What should we make now? The advertisement |
947 | is invalid, but ndisc specs say nothing | 977 | is invalid, but ndisc specs say nothing |
@@ -1008,7 +1038,7 @@ static void ndisc_recv_rs(struct sk_buff *skb) | |||
1008 | unsigned long ndoptlen = skb->len - sizeof(*rs_msg); | 1038 | unsigned long ndoptlen = skb->len - sizeof(*rs_msg); |
1009 | struct neighbour *neigh; | 1039 | struct neighbour *neigh; |
1010 | struct inet6_dev *idev; | 1040 | struct inet6_dev *idev; |
1011 | struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; | 1041 | const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; |
1012 | struct ndisc_options ndopts; | 1042 | struct ndisc_options ndopts; |
1013 | u8 *lladdr = NULL; | 1043 | u8 *lladdr = NULL; |
1014 | 1044 | ||
@@ -1105,6 +1135,18 @@ errout: | |||
1105 | rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err); | 1135 | rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err); |
1106 | } | 1136 | } |
1107 | 1137 | ||
1138 | static inline int accept_ra(struct inet6_dev *in6_dev) | ||
1139 | { | ||
1140 | /* | ||
1141 | * If forwarding is enabled, RA are not accepted unless the special | ||
1142 | * hybrid mode (accept_ra=2) is enabled. | ||
1143 | */ | ||
1144 | if (in6_dev->cnf.forwarding && in6_dev->cnf.accept_ra < 2) | ||
1145 | return 0; | ||
1146 | |||
1147 | return in6_dev->cnf.accept_ra; | ||
1148 | } | ||
1149 | |||
1108 | static void ndisc_router_discovery(struct sk_buff *skb) | 1150 | static void ndisc_router_discovery(struct sk_buff *skb) |
1109 | { | 1151 | { |
1110 | struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb); | 1152 | struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb); |
@@ -1158,8 +1200,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
1158 | return; | 1200 | return; |
1159 | } | 1201 | } |
1160 | 1202 | ||
1161 | /* skip route and link configuration on routers */ | 1203 | if (!accept_ra(in6_dev)) |
1162 | if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra) | ||
1163 | goto skip_linkparms; | 1204 | goto skip_linkparms; |
1164 | 1205 | ||
1165 | #ifdef CONFIG_IPV6_NDISC_NODETYPE | 1206 | #ifdef CONFIG_IPV6_NDISC_NODETYPE |
@@ -1244,7 +1285,8 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
1244 | if (ra_msg->icmph.icmp6_hop_limit) { | 1285 | if (ra_msg->icmph.icmp6_hop_limit) { |
1245 | in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit; | 1286 | in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit; |
1246 | if (rt) | 1287 | if (rt) |
1247 | rt->dst.metrics[RTAX_HOPLIMIT-1] = ra_msg->icmph.icmp6_hop_limit; | 1288 | dst_metric_set(&rt->dst, RTAX_HOPLIMIT, |
1289 | ra_msg->icmph.icmp6_hop_limit); | ||
1248 | } | 1290 | } |
1249 | 1291 | ||
1250 | skip_defrtr: | 1292 | skip_defrtr: |
@@ -1309,8 +1351,7 @@ skip_linkparms: | |||
1309 | NEIGH_UPDATE_F_ISROUTER); | 1351 | NEIGH_UPDATE_F_ISROUTER); |
1310 | } | 1352 | } |
1311 | 1353 | ||
1312 | /* skip route and link configuration on routers */ | 1354 | if (!accept_ra(in6_dev)) |
1313 | if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra) | ||
1314 | goto out; | 1355 | goto out; |
1315 | 1356 | ||
1316 | #ifdef CONFIG_IPV6_ROUTE_INFO | 1357 | #ifdef CONFIG_IPV6_ROUTE_INFO |
@@ -1363,7 +1404,7 @@ skip_linkparms: | |||
1363 | in6_dev->cnf.mtu6 = mtu; | 1404 | in6_dev->cnf.mtu6 = mtu; |
1364 | 1405 | ||
1365 | if (rt) | 1406 | if (rt) |
1366 | rt->dst.metrics[RTAX_MTU-1] = mtu; | 1407 | dst_metric_set(&rt->dst, RTAX_MTU, mtu); |
1367 | 1408 | ||
1368 | rt6_mtu_change(skb->dev, mtu); | 1409 | rt6_mtu_change(skb->dev, mtu); |
1369 | } | 1410 | } |
@@ -1394,8 +1435,8 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) | |||
1394 | { | 1435 | { |
1395 | struct inet6_dev *in6_dev; | 1436 | struct inet6_dev *in6_dev; |
1396 | struct icmp6hdr *icmph; | 1437 | struct icmp6hdr *icmph; |
1397 | struct in6_addr *dest; | 1438 | const struct in6_addr *dest; |
1398 | struct in6_addr *target; /* new first hop to destination */ | 1439 | const struct in6_addr *target; /* new first hop to destination */ |
1399 | struct neighbour *neigh; | 1440 | struct neighbour *neigh; |
1400 | int on_link = 0; | 1441 | int on_link = 0; |
1401 | struct ndisc_options ndopts; | 1442 | struct ndisc_options ndopts; |
@@ -1428,7 +1469,7 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) | |||
1428 | } | 1469 | } |
1429 | 1470 | ||
1430 | icmph = icmp6_hdr(skb); | 1471 | icmph = icmp6_hdr(skb); |
1431 | target = (struct in6_addr *) (icmph + 1); | 1472 | target = (const struct in6_addr *) (icmph + 1); |
1432 | dest = target + 1; | 1473 | dest = target + 1; |
1433 | 1474 | ||
1434 | if (ipv6_addr_is_multicast(dest)) { | 1475 | if (ipv6_addr_is_multicast(dest)) { |
@@ -1500,7 +1541,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, | |||
1500 | struct rt6_info *rt; | 1541 | struct rt6_info *rt; |
1501 | struct dst_entry *dst; | 1542 | struct dst_entry *dst; |
1502 | struct inet6_dev *idev; | 1543 | struct inet6_dev *idev; |
1503 | struct flowi fl; | 1544 | struct flowi6 fl6; |
1504 | u8 *opt; | 1545 | u8 *opt; |
1505 | int rd_len; | 1546 | int rd_len; |
1506 | int err; | 1547 | int err; |
@@ -1520,15 +1561,15 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, | |||
1520 | return; | 1561 | return; |
1521 | } | 1562 | } |
1522 | 1563 | ||
1523 | icmpv6_flow_init(sk, &fl, NDISC_REDIRECT, | 1564 | icmpv6_flow_init(sk, &fl6, NDISC_REDIRECT, |
1524 | &saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex); | 1565 | &saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex); |
1525 | 1566 | ||
1526 | dst = ip6_route_output(net, NULL, &fl); | 1567 | dst = ip6_route_output(net, NULL, &fl6); |
1527 | if (dst == NULL) | 1568 | if (dst == NULL) |
1528 | return; | 1569 | return; |
1529 | 1570 | ||
1530 | err = xfrm_lookup(net, &dst, &fl, NULL, 0); | 1571 | dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0); |
1531 | if (err) | 1572 | if (IS_ERR(dst)) |
1532 | return; | 1573 | return; |
1533 | 1574 | ||
1534 | rt = (struct rt6_info *) dst; | 1575 | rt = (struct rt6_info *) dst; |
@@ -1538,7 +1579,9 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, | |||
1538 | "ICMPv6 Redirect: destination is not a neighbour.\n"); | 1579 | "ICMPv6 Redirect: destination is not a neighbour.\n"); |
1539 | goto release; | 1580 | goto release; |
1540 | } | 1581 | } |
1541 | if (!xrlim_allow(dst, 1*HZ)) | 1582 | if (!rt->rt6i_peer) |
1583 | rt6_bind_peer(rt, 1); | ||
1584 | if (inet_peer_xrlim_allow(rt->rt6i_peer, 1*HZ)) | ||
1542 | goto release; | 1585 | goto release; |
1543 | 1586 | ||
1544 | if (dev->addr_len) { | 1587 | if (dev->addr_len) { |
@@ -1703,6 +1746,9 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, | |||
1703 | neigh_ifdown(&nd_tbl, dev); | 1746 | neigh_ifdown(&nd_tbl, dev); |
1704 | fib6_run_gc(~0UL, net); | 1747 | fib6_run_gc(~0UL, net); |
1705 | break; | 1748 | break; |
1749 | case NETDEV_NOTIFY_PEERS: | ||
1750 | ndisc_send_unsol_na(dev); | ||
1751 | break; | ||
1706 | default: | 1752 | default: |
1707 | break; | 1753 | break; |
1708 | } | 1754 | } |
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index 7155b2451d7c..30fcee465448 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c | |||
@@ -13,18 +13,16 @@ | |||
13 | int ip6_route_me_harder(struct sk_buff *skb) | 13 | int ip6_route_me_harder(struct sk_buff *skb) |
14 | { | 14 | { |
15 | struct net *net = dev_net(skb_dst(skb)->dev); | 15 | struct net *net = dev_net(skb_dst(skb)->dev); |
16 | struct ipv6hdr *iph = ipv6_hdr(skb); | 16 | const struct ipv6hdr *iph = ipv6_hdr(skb); |
17 | struct dst_entry *dst; | 17 | struct dst_entry *dst; |
18 | struct flowi fl = { | 18 | struct flowi6 fl6 = { |
19 | .oif = skb->sk ? skb->sk->sk_bound_dev_if : 0, | 19 | .flowi6_oif = skb->sk ? skb->sk->sk_bound_dev_if : 0, |
20 | .mark = skb->mark, | 20 | .flowi6_mark = skb->mark, |
21 | .nl_u = | 21 | .daddr = iph->daddr, |
22 | { .ip6_u = | 22 | .saddr = iph->saddr, |
23 | { .daddr = iph->daddr, | ||
24 | .saddr = iph->saddr, } }, | ||
25 | }; | 23 | }; |
26 | 24 | ||
27 | dst = ip6_route_output(net, skb->sk, &fl); | 25 | dst = ip6_route_output(net, skb->sk, &fl6); |
28 | if (dst->error) { | 26 | if (dst->error) { |
29 | IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); | 27 | IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); |
30 | LIMIT_NETDEBUG(KERN_DEBUG "ip6_route_me_harder: No more route.\n"); | 28 | LIMIT_NETDEBUG(KERN_DEBUG "ip6_route_me_harder: No more route.\n"); |
@@ -39,9 +37,10 @@ int ip6_route_me_harder(struct sk_buff *skb) | |||
39 | 37 | ||
40 | #ifdef CONFIG_XFRM | 38 | #ifdef CONFIG_XFRM |
41 | if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && | 39 | if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && |
42 | xfrm_decode_session(skb, &fl, AF_INET6) == 0) { | 40 | xfrm_decode_session(skb, flowi6_to_flowi(&fl6), AF_INET6) == 0) { |
43 | skb_dst_set(skb, NULL); | 41 | skb_dst_set(skb, NULL); |
44 | if (xfrm_lookup(net, &dst, &fl, skb->sk, 0)) | 42 | dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), skb->sk, 0); |
43 | if (IS_ERR(dst)) | ||
45 | return -1; | 44 | return -1; |
46 | skb_dst_set(skb, dst); | 45 | skb_dst_set(skb, dst); |
47 | } | 46 | } |
@@ -68,7 +67,7 @@ static void nf_ip6_saveroute(const struct sk_buff *skb, | |||
68 | struct ip6_rt_info *rt_info = nf_queue_entry_reroute(entry); | 67 | struct ip6_rt_info *rt_info = nf_queue_entry_reroute(entry); |
69 | 68 | ||
70 | if (entry->hook == NF_INET_LOCAL_OUT) { | 69 | if (entry->hook == NF_INET_LOCAL_OUT) { |
71 | struct ipv6hdr *iph = ipv6_hdr(skb); | 70 | const struct ipv6hdr *iph = ipv6_hdr(skb); |
72 | 71 | ||
73 | rt_info->daddr = iph->daddr; | 72 | rt_info->daddr = iph->daddr; |
74 | rt_info->saddr = iph->saddr; | 73 | rt_info->saddr = iph->saddr; |
@@ -82,7 +81,7 @@ static int nf_ip6_reroute(struct sk_buff *skb, | |||
82 | struct ip6_rt_info *rt_info = nf_queue_entry_reroute(entry); | 81 | struct ip6_rt_info *rt_info = nf_queue_entry_reroute(entry); |
83 | 82 | ||
84 | if (entry->hook == NF_INET_LOCAL_OUT) { | 83 | if (entry->hook == NF_INET_LOCAL_OUT) { |
85 | struct ipv6hdr *iph = ipv6_hdr(skb); | 84 | const struct ipv6hdr *iph = ipv6_hdr(skb); |
86 | if (!ipv6_addr_equal(&iph->daddr, &rt_info->daddr) || | 85 | if (!ipv6_addr_equal(&iph->daddr, &rt_info->daddr) || |
87 | !ipv6_addr_equal(&iph->saddr, &rt_info->saddr) || | 86 | !ipv6_addr_equal(&iph->saddr, &rt_info->saddr) || |
88 | skb->mark != rt_info->mark) | 87 | skb->mark != rt_info->mark) |
@@ -91,16 +90,25 @@ static int nf_ip6_reroute(struct sk_buff *skb, | |||
91 | return 0; | 90 | return 0; |
92 | } | 91 | } |
93 | 92 | ||
94 | static int nf_ip6_route(struct dst_entry **dst, struct flowi *fl) | 93 | static int nf_ip6_route(struct net *net, struct dst_entry **dst, |
94 | struct flowi *fl, bool strict) | ||
95 | { | 95 | { |
96 | *dst = ip6_route_output(&init_net, NULL, fl); | 96 | static const struct ipv6_pinfo fake_pinfo; |
97 | static const struct inet_sock fake_sk = { | ||
98 | /* makes ip6_route_output set RT6_LOOKUP_F_IFACE: */ | ||
99 | .sk.sk_bound_dev_if = 1, | ||
100 | .pinet6 = (struct ipv6_pinfo *) &fake_pinfo, | ||
101 | }; | ||
102 | const void *sk = strict ? &fake_sk : NULL; | ||
103 | |||
104 | *dst = ip6_route_output(net, sk, &fl->u.ip6); | ||
97 | return (*dst)->error; | 105 | return (*dst)->error; |
98 | } | 106 | } |
99 | 107 | ||
100 | __sum16 nf_ip6_checksum(struct sk_buff *skb, unsigned int hook, | 108 | __sum16 nf_ip6_checksum(struct sk_buff *skb, unsigned int hook, |
101 | unsigned int dataoff, u_int8_t protocol) | 109 | unsigned int dataoff, u_int8_t protocol) |
102 | { | 110 | { |
103 | struct ipv6hdr *ip6h = ipv6_hdr(skb); | 111 | const struct ipv6hdr *ip6h = ipv6_hdr(skb); |
104 | __sum16 csum = 0; | 112 | __sum16 csum = 0; |
105 | 113 | ||
106 | switch (skb->ip_summed) { | 114 | switch (skb->ip_summed) { |
@@ -134,7 +142,7 @@ static __sum16 nf_ip6_checksum_partial(struct sk_buff *skb, unsigned int hook, | |||
134 | unsigned int dataoff, unsigned int len, | 142 | unsigned int dataoff, unsigned int len, |
135 | u_int8_t protocol) | 143 | u_int8_t protocol) |
136 | { | 144 | { |
137 | struct ipv6hdr *ip6h = ipv6_hdr(skb); | 145 | const struct ipv6hdr *ip6h = ipv6_hdr(skb); |
138 | __wsum hsum; | 146 | __wsum hsum; |
139 | __sum16 csum = 0; | 147 | __sum16 csum = 0; |
140 | 148 | ||
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index 29d643bcafa4..448464844a25 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig | |||
@@ -5,10 +5,15 @@ | |||
5 | menu "IPv6: Netfilter Configuration" | 5 | menu "IPv6: Netfilter Configuration" |
6 | depends on INET && IPV6 && NETFILTER | 6 | depends on INET && IPV6 && NETFILTER |
7 | 7 | ||
8 | config NF_DEFRAG_IPV6 | ||
9 | tristate | ||
10 | default n | ||
11 | |||
8 | config NF_CONNTRACK_IPV6 | 12 | config NF_CONNTRACK_IPV6 |
9 | tristate "IPv6 connection tracking support" | 13 | tristate "IPv6 connection tracking support" |
10 | depends on INET && IPV6 && NF_CONNTRACK | 14 | depends on INET && IPV6 && NF_CONNTRACK |
11 | default m if NETFILTER_ADVANCED=n | 15 | default m if NETFILTER_ADVANCED=n |
16 | select NF_DEFRAG_IPV6 | ||
12 | ---help--- | 17 | ---help--- |
13 | Connection tracking keeps a record of what packets have passed | 18 | Connection tracking keeps a record of what packets have passed |
14 | through your machine, in order to figure out how they are related | 19 | through your machine, in order to figure out how they are related |
@@ -132,10 +137,10 @@ config IP6_NF_MATCH_RT | |||
132 | # The targets | 137 | # The targets |
133 | config IP6_NF_TARGET_HL | 138 | config IP6_NF_TARGET_HL |
134 | tristate '"HL" hoplimit target support' | 139 | tristate '"HL" hoplimit target support' |
135 | depends on NETFILTER_ADVANCED | 140 | depends on NETFILTER_ADVANCED && IP6_NF_MANGLE |
136 | select NETFILTER_XT_TARGET_HL | 141 | select NETFILTER_XT_TARGET_HL |
137 | ---help--- | 142 | ---help--- |
138 | This is a backwards-compat option for the user's convenience | 143 | This is a backwards-compatible option for the user's convenience |
139 | (e.g. when running oldconfig). It selects | 144 | (e.g. when running oldconfig). It selects |
140 | CONFIG_NETFILTER_XT_TARGET_HL. | 145 | CONFIG_NETFILTER_XT_TARGET_HL. |
141 | 146 | ||
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile index aafbba30c899..abfee91ce816 100644 --- a/net/ipv6/netfilter/Makefile +++ b/net/ipv6/netfilter/Makefile | |||
@@ -11,10 +11,14 @@ obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o | |||
11 | obj-$(CONFIG_IP6_NF_SECURITY) += ip6table_security.o | 11 | obj-$(CONFIG_IP6_NF_SECURITY) += ip6table_security.o |
12 | 12 | ||
13 | # objects for l3 independent conntrack | 13 | # objects for l3 independent conntrack |
14 | nf_conntrack_ipv6-objs := nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o nf_conntrack_reasm.o | 14 | nf_conntrack_ipv6-y := nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o |
15 | 15 | ||
16 | # l3 independent conntrack | 16 | # l3 independent conntrack |
17 | obj-$(CONFIG_NF_CONNTRACK_IPV6) += nf_conntrack_ipv6.o | 17 | obj-$(CONFIG_NF_CONNTRACK_IPV6) += nf_conntrack_ipv6.o nf_defrag_ipv6.o |
18 | |||
19 | # defrag | ||
20 | nf_defrag_ipv6-y := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o | ||
21 | obj-$(CONFIG_NF_DEFRAG_IPV6) += nf_defrag_ipv6.o | ||
18 | 22 | ||
19 | # matches | 23 | # matches |
20 | obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o | 24 | obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o |
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index 413ab0754e1f..249394863284 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c | |||
@@ -204,7 +204,8 @@ ipq_build_packet_message(struct nf_queue_entry *entry, int *errp) | |||
204 | else | 204 | else |
205 | pmsg->outdev_name[0] = '\0'; | 205 | pmsg->outdev_name[0] = '\0'; |
206 | 206 | ||
207 | if (entry->indev && entry->skb->dev) { | 207 | if (entry->indev && entry->skb->dev && |
208 | entry->skb->mac_header != entry->skb->network_header) { | ||
208 | pmsg->hw_type = entry->skb->dev->type; | 209 | pmsg->hw_type = entry->skb->dev->type; |
209 | pmsg->hw_addrlen = dev_parse_header(entry->skb, pmsg->hw_addr); | 210 | pmsg->hw_addrlen = dev_parse_header(entry->skb, pmsg->hw_addr); |
210 | } | 211 | } |
@@ -403,7 +404,8 @@ ipq_dev_drop(int ifindex) | |||
403 | static inline void | 404 | static inline void |
404 | __ipq_rcv_skb(struct sk_buff *skb) | 405 | __ipq_rcv_skb(struct sk_buff *skb) |
405 | { | 406 | { |
406 | int status, type, pid, flags, nlmsglen, skblen; | 407 | int status, type, pid, flags; |
408 | unsigned int nlmsglen, skblen; | ||
407 | struct nlmsghdr *nlh; | 409 | struct nlmsghdr *nlh; |
408 | 410 | ||
409 | skblen = skb->len; | 411 | skblen = skb->len; |
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 8e754be92c24..94874b0bdcdc 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
@@ -82,13 +82,13 @@ EXPORT_SYMBOL_GPL(ip6t_alloc_initial_table); | |||
82 | int | 82 | int |
83 | ip6t_ext_hdr(u8 nexthdr) | 83 | ip6t_ext_hdr(u8 nexthdr) |
84 | { | 84 | { |
85 | return ( (nexthdr == IPPROTO_HOPOPTS) || | 85 | return (nexthdr == IPPROTO_HOPOPTS) || |
86 | (nexthdr == IPPROTO_ROUTING) || | 86 | (nexthdr == IPPROTO_ROUTING) || |
87 | (nexthdr == IPPROTO_FRAGMENT) || | 87 | (nexthdr == IPPROTO_FRAGMENT) || |
88 | (nexthdr == IPPROTO_ESP) || | 88 | (nexthdr == IPPROTO_ESP) || |
89 | (nexthdr == IPPROTO_AH) || | 89 | (nexthdr == IPPROTO_AH) || |
90 | (nexthdr == IPPROTO_NONE) || | 90 | (nexthdr == IPPROTO_NONE) || |
91 | (nexthdr == IPPROTO_DSTOPTS) ); | 91 | (nexthdr == IPPROTO_DSTOPTS); |
92 | } | 92 | } |
93 | 93 | ||
94 | /* Returns whether matches rule or not. */ | 94 | /* Returns whether matches rule or not. */ |
@@ -215,7 +215,7 @@ static inline bool unconditional(const struct ip6t_ip6 *ipv6) | |||
215 | return memcmp(ipv6, &uncond, sizeof(uncond)) == 0; | 215 | return memcmp(ipv6, &uncond, sizeof(uncond)) == 0; |
216 | } | 216 | } |
217 | 217 | ||
218 | static inline const struct ip6t_entry_target * | 218 | static inline const struct xt_entry_target * |
219 | ip6t_get_target_c(const struct ip6t_entry *e) | 219 | ip6t_get_target_c(const struct ip6t_entry *e) |
220 | { | 220 | { |
221 | return ip6t_get_target((struct ip6t_entry *)e); | 221 | return ip6t_get_target((struct ip6t_entry *)e); |
@@ -260,9 +260,9 @@ get_chainname_rulenum(const struct ip6t_entry *s, const struct ip6t_entry *e, | |||
260 | const char *hookname, const char **chainname, | 260 | const char *hookname, const char **chainname, |
261 | const char **comment, unsigned int *rulenum) | 261 | const char **comment, unsigned int *rulenum) |
262 | { | 262 | { |
263 | const struct ip6t_standard_target *t = (void *)ip6t_get_target_c(s); | 263 | const struct xt_standard_target *t = (void *)ip6t_get_target_c(s); |
264 | 264 | ||
265 | if (strcmp(t->target.u.kernel.target->name, IP6T_ERROR_TARGET) == 0) { | 265 | if (strcmp(t->target.u.kernel.target->name, XT_ERROR_TARGET) == 0) { |
266 | /* Head of user chain: ERROR target with chainname */ | 266 | /* Head of user chain: ERROR target with chainname */ |
267 | *chainname = t->target.data; | 267 | *chainname = t->target.data; |
268 | (*rulenum) = 0; | 268 | (*rulenum) = 0; |
@@ -271,7 +271,7 @@ get_chainname_rulenum(const struct ip6t_entry *s, const struct ip6t_entry *e, | |||
271 | 271 | ||
272 | if (s->target_offset == sizeof(struct ip6t_entry) && | 272 | if (s->target_offset == sizeof(struct ip6t_entry) && |
273 | strcmp(t->target.u.kernel.target->name, | 273 | strcmp(t->target.u.kernel.target->name, |
274 | IP6T_STANDARD_TARGET) == 0 && | 274 | XT_STANDARD_TARGET) == 0 && |
275 | t->verdict < 0 && | 275 | t->verdict < 0 && |
276 | unconditional(&s->ipv6)) { | 276 | unconditional(&s->ipv6)) { |
277 | /* Tail of chains: STANDARD target (return/policy) */ | 277 | /* Tail of chains: STANDARD target (return/policy) */ |
@@ -340,6 +340,7 @@ ip6t_do_table(struct sk_buff *skb, | |||
340 | unsigned int *stackptr, origptr, cpu; | 340 | unsigned int *stackptr, origptr, cpu; |
341 | const struct xt_table_info *private; | 341 | const struct xt_table_info *private; |
342 | struct xt_action_param acpar; | 342 | struct xt_action_param acpar; |
343 | unsigned int addend; | ||
343 | 344 | ||
344 | /* Initialization */ | 345 | /* Initialization */ |
345 | indev = in ? in->name : nulldevname; | 346 | indev = in ? in->name : nulldevname; |
@@ -358,7 +359,8 @@ ip6t_do_table(struct sk_buff *skb, | |||
358 | 359 | ||
359 | IP_NF_ASSERT(table->valid_hooks & (1 << hook)); | 360 | IP_NF_ASSERT(table->valid_hooks & (1 << hook)); |
360 | 361 | ||
361 | xt_info_rdlock_bh(); | 362 | local_bh_disable(); |
363 | addend = xt_write_recseq_begin(); | ||
362 | private = table->private; | 364 | private = table->private; |
363 | cpu = smp_processor_id(); | 365 | cpu = smp_processor_id(); |
364 | table_base = private->entries[cpu]; | 366 | table_base = private->entries[cpu]; |
@@ -369,7 +371,7 @@ ip6t_do_table(struct sk_buff *skb, | |||
369 | e = get_entry(table_base, private->hook_entry[hook]); | 371 | e = get_entry(table_base, private->hook_entry[hook]); |
370 | 372 | ||
371 | do { | 373 | do { |
372 | const struct ip6t_entry_target *t; | 374 | const struct xt_entry_target *t; |
373 | const struct xt_entry_match *ematch; | 375 | const struct xt_entry_match *ematch; |
374 | 376 | ||
375 | IP_NF_ASSERT(e); | 377 | IP_NF_ASSERT(e); |
@@ -403,14 +405,14 @@ ip6t_do_table(struct sk_buff *skb, | |||
403 | if (!t->u.kernel.target->target) { | 405 | if (!t->u.kernel.target->target) { |
404 | int v; | 406 | int v; |
405 | 407 | ||
406 | v = ((struct ip6t_standard_target *)t)->verdict; | 408 | v = ((struct xt_standard_target *)t)->verdict; |
407 | if (v < 0) { | 409 | if (v < 0) { |
408 | /* Pop from stack? */ | 410 | /* Pop from stack? */ |
409 | if (v != IP6T_RETURN) { | 411 | if (v != XT_RETURN) { |
410 | verdict = (unsigned)(-v) - 1; | 412 | verdict = (unsigned)(-v) - 1; |
411 | break; | 413 | break; |
412 | } | 414 | } |
413 | if (*stackptr == 0) | 415 | if (*stackptr <= origptr) |
414 | e = get_entry(table_base, | 416 | e = get_entry(table_base, |
415 | private->underflow[hook]); | 417 | private->underflow[hook]); |
416 | else | 418 | else |
@@ -434,16 +436,18 @@ ip6t_do_table(struct sk_buff *skb, | |||
434 | acpar.targinfo = t->data; | 436 | acpar.targinfo = t->data; |
435 | 437 | ||
436 | verdict = t->u.kernel.target->target(skb, &acpar); | 438 | verdict = t->u.kernel.target->target(skb, &acpar); |
437 | if (verdict == IP6T_CONTINUE) | 439 | if (verdict == XT_CONTINUE) |
438 | e = ip6t_next_entry(e); | 440 | e = ip6t_next_entry(e); |
439 | else | 441 | else |
440 | /* Verdict */ | 442 | /* Verdict */ |
441 | break; | 443 | break; |
442 | } while (!acpar.hotdrop); | 444 | } while (!acpar.hotdrop); |
443 | 445 | ||
444 | xt_info_rdunlock_bh(); | ||
445 | *stackptr = origptr; | 446 | *stackptr = origptr; |
446 | 447 | ||
448 | xt_write_recseq_end(addend); | ||
449 | local_bh_enable(); | ||
450 | |||
447 | #ifdef DEBUG_ALLOW_ALL | 451 | #ifdef DEBUG_ALLOW_ALL |
448 | return NF_ACCEPT; | 452 | return NF_ACCEPT; |
449 | #else | 453 | #else |
@@ -474,7 +478,7 @@ mark_source_chains(const struct xt_table_info *newinfo, | |||
474 | e->counters.pcnt = pos; | 478 | e->counters.pcnt = pos; |
475 | 479 | ||
476 | for (;;) { | 480 | for (;;) { |
477 | const struct ip6t_standard_target *t | 481 | const struct xt_standard_target *t |
478 | = (void *)ip6t_get_target_c(e); | 482 | = (void *)ip6t_get_target_c(e); |
479 | int visited = e->comefrom & (1 << hook); | 483 | int visited = e->comefrom & (1 << hook); |
480 | 484 | ||
@@ -488,13 +492,13 @@ mark_source_chains(const struct xt_table_info *newinfo, | |||
488 | /* Unconditional return/END. */ | 492 | /* Unconditional return/END. */ |
489 | if ((e->target_offset == sizeof(struct ip6t_entry) && | 493 | if ((e->target_offset == sizeof(struct ip6t_entry) && |
490 | (strcmp(t->target.u.user.name, | 494 | (strcmp(t->target.u.user.name, |
491 | IP6T_STANDARD_TARGET) == 0) && | 495 | XT_STANDARD_TARGET) == 0) && |
492 | t->verdict < 0 && | 496 | t->verdict < 0 && |
493 | unconditional(&e->ipv6)) || visited) { | 497 | unconditional(&e->ipv6)) || visited) { |
494 | unsigned int oldpos, size; | 498 | unsigned int oldpos, size; |
495 | 499 | ||
496 | if ((strcmp(t->target.u.user.name, | 500 | if ((strcmp(t->target.u.user.name, |
497 | IP6T_STANDARD_TARGET) == 0) && | 501 | XT_STANDARD_TARGET) == 0) && |
498 | t->verdict < -NF_MAX_VERDICT - 1) { | 502 | t->verdict < -NF_MAX_VERDICT - 1) { |
499 | duprintf("mark_source_chains: bad " | 503 | duprintf("mark_source_chains: bad " |
500 | "negative verdict (%i)\n", | 504 | "negative verdict (%i)\n", |
@@ -537,7 +541,7 @@ mark_source_chains(const struct xt_table_info *newinfo, | |||
537 | int newpos = t->verdict; | 541 | int newpos = t->verdict; |
538 | 542 | ||
539 | if (strcmp(t->target.u.user.name, | 543 | if (strcmp(t->target.u.user.name, |
540 | IP6T_STANDARD_TARGET) == 0 && | 544 | XT_STANDARD_TARGET) == 0 && |
541 | newpos >= 0) { | 545 | newpos >= 0) { |
542 | if (newpos > newinfo->size - | 546 | if (newpos > newinfo->size - |
543 | sizeof(struct ip6t_entry)) { | 547 | sizeof(struct ip6t_entry)) { |
@@ -565,7 +569,7 @@ mark_source_chains(const struct xt_table_info *newinfo, | |||
565 | return 1; | 569 | return 1; |
566 | } | 570 | } |
567 | 571 | ||
568 | static void cleanup_match(struct ip6t_entry_match *m, struct net *net) | 572 | static void cleanup_match(struct xt_entry_match *m, struct net *net) |
569 | { | 573 | { |
570 | struct xt_mtdtor_param par; | 574 | struct xt_mtdtor_param par; |
571 | 575 | ||
@@ -581,14 +585,14 @@ static void cleanup_match(struct ip6t_entry_match *m, struct net *net) | |||
581 | static int | 585 | static int |
582 | check_entry(const struct ip6t_entry *e, const char *name) | 586 | check_entry(const struct ip6t_entry *e, const char *name) |
583 | { | 587 | { |
584 | const struct ip6t_entry_target *t; | 588 | const struct xt_entry_target *t; |
585 | 589 | ||
586 | if (!ip6_checkentry(&e->ipv6)) { | 590 | if (!ip6_checkentry(&e->ipv6)) { |
587 | duprintf("ip_tables: ip check failed %p %s.\n", e, name); | 591 | duprintf("ip_tables: ip check failed %p %s.\n", e, name); |
588 | return -EINVAL; | 592 | return -EINVAL; |
589 | } | 593 | } |
590 | 594 | ||
591 | if (e->target_offset + sizeof(struct ip6t_entry_target) > | 595 | if (e->target_offset + sizeof(struct xt_entry_target) > |
592 | e->next_offset) | 596 | e->next_offset) |
593 | return -EINVAL; | 597 | return -EINVAL; |
594 | 598 | ||
@@ -599,7 +603,7 @@ check_entry(const struct ip6t_entry *e, const char *name) | |||
599 | return 0; | 603 | return 0; |
600 | } | 604 | } |
601 | 605 | ||
602 | static int check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par) | 606 | static int check_match(struct xt_entry_match *m, struct xt_mtchk_param *par) |
603 | { | 607 | { |
604 | const struct ip6t_ip6 *ipv6 = par->entryinfo; | 608 | const struct ip6t_ip6 *ipv6 = par->entryinfo; |
605 | int ret; | 609 | int ret; |
@@ -618,7 +622,7 @@ static int check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par) | |||
618 | } | 622 | } |
619 | 623 | ||
620 | static int | 624 | static int |
621 | find_check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par) | 625 | find_check_match(struct xt_entry_match *m, struct xt_mtchk_param *par) |
622 | { | 626 | { |
623 | struct xt_match *match; | 627 | struct xt_match *match; |
624 | int ret; | 628 | int ret; |
@@ -643,7 +647,7 @@ err: | |||
643 | 647 | ||
644 | static int check_target(struct ip6t_entry *e, struct net *net, const char *name) | 648 | static int check_target(struct ip6t_entry *e, struct net *net, const char *name) |
645 | { | 649 | { |
646 | struct ip6t_entry_target *t = ip6t_get_target(e); | 650 | struct xt_entry_target *t = ip6t_get_target(e); |
647 | struct xt_tgchk_param par = { | 651 | struct xt_tgchk_param par = { |
648 | .net = net, | 652 | .net = net, |
649 | .table = name, | 653 | .table = name, |
@@ -670,7 +674,7 @@ static int | |||
670 | find_check_entry(struct ip6t_entry *e, struct net *net, const char *name, | 674 | find_check_entry(struct ip6t_entry *e, struct net *net, const char *name, |
671 | unsigned int size) | 675 | unsigned int size) |
672 | { | 676 | { |
673 | struct ip6t_entry_target *t; | 677 | struct xt_entry_target *t; |
674 | struct xt_target *target; | 678 | struct xt_target *target; |
675 | int ret; | 679 | int ret; |
676 | unsigned int j; | 680 | unsigned int j; |
@@ -721,7 +725,7 @@ find_check_entry(struct ip6t_entry *e, struct net *net, const char *name, | |||
721 | 725 | ||
722 | static bool check_underflow(const struct ip6t_entry *e) | 726 | static bool check_underflow(const struct ip6t_entry *e) |
723 | { | 727 | { |
724 | const struct ip6t_entry_target *t; | 728 | const struct xt_entry_target *t; |
725 | unsigned int verdict; | 729 | unsigned int verdict; |
726 | 730 | ||
727 | if (!unconditional(&e->ipv6)) | 731 | if (!unconditional(&e->ipv6)) |
@@ -729,7 +733,7 @@ static bool check_underflow(const struct ip6t_entry *e) | |||
729 | t = ip6t_get_target_c(e); | 733 | t = ip6t_get_target_c(e); |
730 | if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0) | 734 | if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0) |
731 | return false; | 735 | return false; |
732 | verdict = ((struct ip6t_standard_target *)t)->verdict; | 736 | verdict = ((struct xt_standard_target *)t)->verdict; |
733 | verdict = -verdict - 1; | 737 | verdict = -verdict - 1; |
734 | return verdict == NF_DROP || verdict == NF_ACCEPT; | 738 | return verdict == NF_DROP || verdict == NF_ACCEPT; |
735 | } | 739 | } |
@@ -752,7 +756,7 @@ check_entry_size_and_hooks(struct ip6t_entry *e, | |||
752 | } | 756 | } |
753 | 757 | ||
754 | if (e->next_offset | 758 | if (e->next_offset |
755 | < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) { | 759 | < sizeof(struct ip6t_entry) + sizeof(struct xt_entry_target)) { |
756 | duprintf("checking: element %p size %u\n", | 760 | duprintf("checking: element %p size %u\n", |
757 | e, e->next_offset); | 761 | e, e->next_offset); |
758 | return -EINVAL; | 762 | return -EINVAL; |
@@ -784,7 +788,7 @@ check_entry_size_and_hooks(struct ip6t_entry *e, | |||
784 | static void cleanup_entry(struct ip6t_entry *e, struct net *net) | 788 | static void cleanup_entry(struct ip6t_entry *e, struct net *net) |
785 | { | 789 | { |
786 | struct xt_tgdtor_param par; | 790 | struct xt_tgdtor_param par; |
787 | struct ip6t_entry_target *t; | 791 | struct xt_entry_target *t; |
788 | struct xt_entry_match *ematch; | 792 | struct xt_entry_match *ematch; |
789 | 793 | ||
790 | /* Cleanup all matches */ | 794 | /* Cleanup all matches */ |
@@ -897,42 +901,25 @@ get_counters(const struct xt_table_info *t, | |||
897 | struct ip6t_entry *iter; | 901 | struct ip6t_entry *iter; |
898 | unsigned int cpu; | 902 | unsigned int cpu; |
899 | unsigned int i; | 903 | unsigned int i; |
900 | unsigned int curcpu = get_cpu(); | ||
901 | |||
902 | /* Instead of clearing (by a previous call to memset()) | ||
903 | * the counters and using adds, we set the counters | ||
904 | * with data used by 'current' CPU | ||
905 | * | ||
906 | * Bottom half has to be disabled to prevent deadlock | ||
907 | * if new softirq were to run and call ipt_do_table | ||
908 | */ | ||
909 | local_bh_disable(); | ||
910 | i = 0; | ||
911 | xt_entry_foreach(iter, t->entries[curcpu], t->size) { | ||
912 | SET_COUNTER(counters[i], iter->counters.bcnt, | ||
913 | iter->counters.pcnt); | ||
914 | ++i; | ||
915 | } | ||
916 | local_bh_enable(); | ||
917 | /* Processing counters from other cpus, we can let bottom half enabled, | ||
918 | * (preemption is disabled) | ||
919 | */ | ||
920 | 904 | ||
921 | for_each_possible_cpu(cpu) { | 905 | for_each_possible_cpu(cpu) { |
922 | if (cpu == curcpu) | 906 | seqcount_t *s = &per_cpu(xt_recseq, cpu); |
923 | continue; | 907 | |
924 | i = 0; | 908 | i = 0; |
925 | local_bh_disable(); | ||
926 | xt_info_wrlock(cpu); | ||
927 | xt_entry_foreach(iter, t->entries[cpu], t->size) { | 909 | xt_entry_foreach(iter, t->entries[cpu], t->size) { |
928 | ADD_COUNTER(counters[i], iter->counters.bcnt, | 910 | u64 bcnt, pcnt; |
929 | iter->counters.pcnt); | 911 | unsigned int start; |
912 | |||
913 | do { | ||
914 | start = read_seqcount_begin(s); | ||
915 | bcnt = iter->counters.bcnt; | ||
916 | pcnt = iter->counters.pcnt; | ||
917 | } while (read_seqcount_retry(s, start)); | ||
918 | |||
919 | ADD_COUNTER(counters[i], bcnt, pcnt); | ||
930 | ++i; | 920 | ++i; |
931 | } | 921 | } |
932 | xt_info_wrunlock(cpu); | ||
933 | local_bh_enable(); | ||
934 | } | 922 | } |
935 | put_cpu(); | ||
936 | } | 923 | } |
937 | 924 | ||
938 | static struct xt_counters *alloc_counters(const struct xt_table *table) | 925 | static struct xt_counters *alloc_counters(const struct xt_table *table) |
@@ -945,7 +932,7 @@ static struct xt_counters *alloc_counters(const struct xt_table *table) | |||
945 | (other than comefrom, which userspace doesn't care | 932 | (other than comefrom, which userspace doesn't care |
946 | about). */ | 933 | about). */ |
947 | countersize = sizeof(struct xt_counters) * private->number; | 934 | countersize = sizeof(struct xt_counters) * private->number; |
948 | counters = vmalloc(countersize); | 935 | counters = vzalloc(countersize); |
949 | 936 | ||
950 | if (counters == NULL) | 937 | if (counters == NULL) |
951 | return ERR_PTR(-ENOMEM); | 938 | return ERR_PTR(-ENOMEM); |
@@ -985,8 +972,8 @@ copy_entries_to_user(unsigned int total_size, | |||
985 | /* ... then go back and fix counters and names */ | 972 | /* ... then go back and fix counters and names */ |
986 | for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){ | 973 | for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){ |
987 | unsigned int i; | 974 | unsigned int i; |
988 | const struct ip6t_entry_match *m; | 975 | const struct xt_entry_match *m; |
989 | const struct ip6t_entry_target *t; | 976 | const struct xt_entry_target *t; |
990 | 977 | ||
991 | e = (struct ip6t_entry *)(loc_cpu_entry + off); | 978 | e = (struct ip6t_entry *)(loc_cpu_entry + off); |
992 | if (copy_to_user(userptr + off | 979 | if (copy_to_user(userptr + off |
@@ -1003,7 +990,7 @@ copy_entries_to_user(unsigned int total_size, | |||
1003 | m = (void *)e + i; | 990 | m = (void *)e + i; |
1004 | 991 | ||
1005 | if (copy_to_user(userptr + off + i | 992 | if (copy_to_user(userptr + off + i |
1006 | + offsetof(struct ip6t_entry_match, | 993 | + offsetof(struct xt_entry_match, |
1007 | u.user.name), | 994 | u.user.name), |
1008 | m->u.kernel.match->name, | 995 | m->u.kernel.match->name, |
1009 | strlen(m->u.kernel.match->name)+1) | 996 | strlen(m->u.kernel.match->name)+1) |
@@ -1015,7 +1002,7 @@ copy_entries_to_user(unsigned int total_size, | |||
1015 | 1002 | ||
1016 | t = ip6t_get_target_c(e); | 1003 | t = ip6t_get_target_c(e); |
1017 | if (copy_to_user(userptr + off + e->target_offset | 1004 | if (copy_to_user(userptr + off + e->target_offset |
1018 | + offsetof(struct ip6t_entry_target, | 1005 | + offsetof(struct xt_entry_target, |
1019 | u.user.name), | 1006 | u.user.name), |
1020 | t->u.kernel.target->name, | 1007 | t->u.kernel.target->name, |
1021 | strlen(t->u.kernel.target->name)+1) != 0) { | 1008 | strlen(t->u.kernel.target->name)+1) != 0) { |
@@ -1053,7 +1040,7 @@ static int compat_calc_entry(const struct ip6t_entry *e, | |||
1053 | const void *base, struct xt_table_info *newinfo) | 1040 | const void *base, struct xt_table_info *newinfo) |
1054 | { | 1041 | { |
1055 | const struct xt_entry_match *ematch; | 1042 | const struct xt_entry_match *ematch; |
1056 | const struct ip6t_entry_target *t; | 1043 | const struct xt_entry_target *t; |
1057 | unsigned int entry_offset; | 1044 | unsigned int entry_offset; |
1058 | int off, i, ret; | 1045 | int off, i, ret; |
1059 | 1046 | ||
@@ -1093,6 +1080,7 @@ static int compat_table_info(const struct xt_table_info *info, | |||
1093 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); | 1080 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); |
1094 | newinfo->initial_entries = 0; | 1081 | newinfo->initial_entries = 0; |
1095 | loc_cpu_entry = info->entries[raw_smp_processor_id()]; | 1082 | loc_cpu_entry = info->entries[raw_smp_processor_id()]; |
1083 | xt_compat_init_offsets(AF_INET6, info->number); | ||
1096 | xt_entry_foreach(iter, loc_cpu_entry, info->size) { | 1084 | xt_entry_foreach(iter, loc_cpu_entry, info->size) { |
1097 | ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo); | 1085 | ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo); |
1098 | if (ret != 0) | 1086 | if (ret != 0) |
@@ -1105,7 +1093,7 @@ static int compat_table_info(const struct xt_table_info *info, | |||
1105 | static int get_info(struct net *net, void __user *user, | 1093 | static int get_info(struct net *net, void __user *user, |
1106 | const int *len, int compat) | 1094 | const int *len, int compat) |
1107 | { | 1095 | { |
1108 | char name[IP6T_TABLE_MAXNAMELEN]; | 1096 | char name[XT_TABLE_MAXNAMELEN]; |
1109 | struct xt_table *t; | 1097 | struct xt_table *t; |
1110 | int ret; | 1098 | int ret; |
1111 | 1099 | ||
@@ -1118,7 +1106,7 @@ static int get_info(struct net *net, void __user *user, | |||
1118 | if (copy_from_user(name, user, sizeof(name)) != 0) | 1106 | if (copy_from_user(name, user, sizeof(name)) != 0) |
1119 | return -EFAULT; | 1107 | return -EFAULT; |
1120 | 1108 | ||
1121 | name[IP6T_TABLE_MAXNAMELEN-1] = '\0'; | 1109 | name[XT_TABLE_MAXNAMELEN-1] = '\0'; |
1122 | #ifdef CONFIG_COMPAT | 1110 | #ifdef CONFIG_COMPAT |
1123 | if (compat) | 1111 | if (compat) |
1124 | xt_compat_lock(AF_INET6); | 1112 | xt_compat_lock(AF_INET6); |
@@ -1137,6 +1125,7 @@ static int get_info(struct net *net, void __user *user, | |||
1137 | private = &tmp; | 1125 | private = &tmp; |
1138 | } | 1126 | } |
1139 | #endif | 1127 | #endif |
1128 | memset(&info, 0, sizeof(info)); | ||
1140 | info.valid_hooks = t->valid_hooks; | 1129 | info.valid_hooks = t->valid_hooks; |
1141 | memcpy(info.hook_entry, private->hook_entry, | 1130 | memcpy(info.hook_entry, private->hook_entry, |
1142 | sizeof(info.hook_entry)); | 1131 | sizeof(info.hook_entry)); |
@@ -1215,7 +1204,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, | |||
1215 | struct ip6t_entry *iter; | 1204 | struct ip6t_entry *iter; |
1216 | 1205 | ||
1217 | ret = 0; | 1206 | ret = 0; |
1218 | counters = vmalloc(num_counters * sizeof(struct xt_counters)); | 1207 | counters = vzalloc(num_counters * sizeof(struct xt_counters)); |
1219 | if (!counters) { | 1208 | if (!counters) { |
1220 | ret = -ENOMEM; | 1209 | ret = -ENOMEM; |
1221 | goto out; | 1210 | goto out; |
@@ -1290,6 +1279,7 @@ do_replace(struct net *net, const void __user *user, unsigned int len) | |||
1290 | /* overflow check */ | 1279 | /* overflow check */ |
1291 | if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters)) | 1280 | if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters)) |
1292 | return -ENOMEM; | 1281 | return -ENOMEM; |
1282 | tmp.name[sizeof(tmp.name)-1] = 0; | ||
1293 | 1283 | ||
1294 | newinfo = xt_alloc_table_info(tmp.size); | 1284 | newinfo = xt_alloc_table_info(tmp.size); |
1295 | if (!newinfo) | 1285 | if (!newinfo) |
@@ -1339,6 +1329,7 @@ do_add_counters(struct net *net, const void __user *user, unsigned int len, | |||
1339 | int ret = 0; | 1329 | int ret = 0; |
1340 | const void *loc_cpu_entry; | 1330 | const void *loc_cpu_entry; |
1341 | struct ip6t_entry *iter; | 1331 | struct ip6t_entry *iter; |
1332 | unsigned int addend; | ||
1342 | #ifdef CONFIG_COMPAT | 1333 | #ifdef CONFIG_COMPAT |
1343 | struct compat_xt_counters_info compat_tmp; | 1334 | struct compat_xt_counters_info compat_tmp; |
1344 | 1335 | ||
@@ -1395,13 +1386,13 @@ do_add_counters(struct net *net, const void __user *user, unsigned int len, | |||
1395 | i = 0; | 1386 | i = 0; |
1396 | /* Choose the copy that is on our node */ | 1387 | /* Choose the copy that is on our node */ |
1397 | curcpu = smp_processor_id(); | 1388 | curcpu = smp_processor_id(); |
1398 | xt_info_wrlock(curcpu); | 1389 | addend = xt_write_recseq_begin(); |
1399 | loc_cpu_entry = private->entries[curcpu]; | 1390 | loc_cpu_entry = private->entries[curcpu]; |
1400 | xt_entry_foreach(iter, loc_cpu_entry, private->size) { | 1391 | xt_entry_foreach(iter, loc_cpu_entry, private->size) { |
1401 | ADD_COUNTER(iter->counters, paddc[i].bcnt, paddc[i].pcnt); | 1392 | ADD_COUNTER(iter->counters, paddc[i].bcnt, paddc[i].pcnt); |
1402 | ++i; | 1393 | ++i; |
1403 | } | 1394 | } |
1404 | xt_info_wrunlock(curcpu); | 1395 | xt_write_recseq_end(addend); |
1405 | 1396 | ||
1406 | unlock_up_free: | 1397 | unlock_up_free: |
1407 | local_bh_enable(); | 1398 | local_bh_enable(); |
@@ -1415,14 +1406,14 @@ do_add_counters(struct net *net, const void __user *user, unsigned int len, | |||
1415 | 1406 | ||
1416 | #ifdef CONFIG_COMPAT | 1407 | #ifdef CONFIG_COMPAT |
1417 | struct compat_ip6t_replace { | 1408 | struct compat_ip6t_replace { |
1418 | char name[IP6T_TABLE_MAXNAMELEN]; | 1409 | char name[XT_TABLE_MAXNAMELEN]; |
1419 | u32 valid_hooks; | 1410 | u32 valid_hooks; |
1420 | u32 num_entries; | 1411 | u32 num_entries; |
1421 | u32 size; | 1412 | u32 size; |
1422 | u32 hook_entry[NF_INET_NUMHOOKS]; | 1413 | u32 hook_entry[NF_INET_NUMHOOKS]; |
1423 | u32 underflow[NF_INET_NUMHOOKS]; | 1414 | u32 underflow[NF_INET_NUMHOOKS]; |
1424 | u32 num_counters; | 1415 | u32 num_counters; |
1425 | compat_uptr_t counters; /* struct ip6t_counters * */ | 1416 | compat_uptr_t counters; /* struct xt_counters * */ |
1426 | struct compat_ip6t_entry entries[0]; | 1417 | struct compat_ip6t_entry entries[0]; |
1427 | }; | 1418 | }; |
1428 | 1419 | ||
@@ -1431,7 +1422,7 @@ compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr, | |||
1431 | unsigned int *size, struct xt_counters *counters, | 1422 | unsigned int *size, struct xt_counters *counters, |
1432 | unsigned int i) | 1423 | unsigned int i) |
1433 | { | 1424 | { |
1434 | struct ip6t_entry_target *t; | 1425 | struct xt_entry_target *t; |
1435 | struct compat_ip6t_entry __user *ce; | 1426 | struct compat_ip6t_entry __user *ce; |
1436 | u_int16_t target_offset, next_offset; | 1427 | u_int16_t target_offset, next_offset; |
1437 | compat_uint_t origsize; | 1428 | compat_uint_t origsize; |
@@ -1466,7 +1457,7 @@ compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr, | |||
1466 | } | 1457 | } |
1467 | 1458 | ||
1468 | static int | 1459 | static int |
1469 | compat_find_calc_match(struct ip6t_entry_match *m, | 1460 | compat_find_calc_match(struct xt_entry_match *m, |
1470 | const char *name, | 1461 | const char *name, |
1471 | const struct ip6t_ip6 *ipv6, | 1462 | const struct ip6t_ip6 *ipv6, |
1472 | unsigned int hookmask, | 1463 | unsigned int hookmask, |
@@ -1488,7 +1479,7 @@ compat_find_calc_match(struct ip6t_entry_match *m, | |||
1488 | 1479 | ||
1489 | static void compat_release_entry(struct compat_ip6t_entry *e) | 1480 | static void compat_release_entry(struct compat_ip6t_entry *e) |
1490 | { | 1481 | { |
1491 | struct ip6t_entry_target *t; | 1482 | struct xt_entry_target *t; |
1492 | struct xt_entry_match *ematch; | 1483 | struct xt_entry_match *ematch; |
1493 | 1484 | ||
1494 | /* Cleanup all matches */ | 1485 | /* Cleanup all matches */ |
@@ -1509,7 +1500,7 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, | |||
1509 | const char *name) | 1500 | const char *name) |
1510 | { | 1501 | { |
1511 | struct xt_entry_match *ematch; | 1502 | struct xt_entry_match *ematch; |
1512 | struct ip6t_entry_target *t; | 1503 | struct xt_entry_target *t; |
1513 | struct xt_target *target; | 1504 | struct xt_target *target; |
1514 | unsigned int entry_offset; | 1505 | unsigned int entry_offset; |
1515 | unsigned int j; | 1506 | unsigned int j; |
@@ -1591,8 +1582,7 @@ compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr, | |||
1591 | unsigned int *size, const char *name, | 1582 | unsigned int *size, const char *name, |
1592 | struct xt_table_info *newinfo, unsigned char *base) | 1583 | struct xt_table_info *newinfo, unsigned char *base) |
1593 | { | 1584 | { |
1594 | struct ip6t_entry_target *t; | 1585 | struct xt_entry_target *t; |
1595 | struct xt_target *target; | ||
1596 | struct ip6t_entry *de; | 1586 | struct ip6t_entry *de; |
1597 | unsigned int origsize; | 1587 | unsigned int origsize; |
1598 | int ret, h; | 1588 | int ret, h; |
@@ -1614,7 +1604,6 @@ compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr, | |||
1614 | } | 1604 | } |
1615 | de->target_offset = e->target_offset - (origsize - *size); | 1605 | de->target_offset = e->target_offset - (origsize - *size); |
1616 | t = compat_ip6t_get_target(e); | 1606 | t = compat_ip6t_get_target(e); |
1617 | target = t->u.kernel.target; | ||
1618 | xt_compat_target_from_user(t, dstptr, size); | 1607 | xt_compat_target_from_user(t, dstptr, size); |
1619 | 1608 | ||
1620 | de->next_offset = e->next_offset - (origsize - *size); | 1609 | de->next_offset = e->next_offset - (origsize - *size); |
@@ -1695,6 +1684,7 @@ translate_compat_table(struct net *net, | |||
1695 | duprintf("translate_compat_table: size %u\n", info->size); | 1684 | duprintf("translate_compat_table: size %u\n", info->size); |
1696 | j = 0; | 1685 | j = 0; |
1697 | xt_compat_lock(AF_INET6); | 1686 | xt_compat_lock(AF_INET6); |
1687 | xt_compat_init_offsets(AF_INET6, number); | ||
1698 | /* Walk through entries, checking offsets. */ | 1688 | /* Walk through entries, checking offsets. */ |
1699 | xt_entry_foreach(iter0, entry0, total_size) { | 1689 | xt_entry_foreach(iter0, entry0, total_size) { |
1700 | ret = check_compat_entry_size_and_hooks(iter0, info, &size, | 1690 | ret = check_compat_entry_size_and_hooks(iter0, info, &size, |
@@ -1836,6 +1826,7 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len) | |||
1836 | return -ENOMEM; | 1826 | return -ENOMEM; |
1837 | if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters)) | 1827 | if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters)) |
1838 | return -ENOMEM; | 1828 | return -ENOMEM; |
1829 | tmp.name[sizeof(tmp.name)-1] = 0; | ||
1839 | 1830 | ||
1840 | newinfo = xt_alloc_table_info(tmp.size); | 1831 | newinfo = xt_alloc_table_info(tmp.size); |
1841 | if (!newinfo) | 1832 | if (!newinfo) |
@@ -1899,7 +1890,7 @@ compat_do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, | |||
1899 | } | 1890 | } |
1900 | 1891 | ||
1901 | struct compat_ip6t_get_entries { | 1892 | struct compat_ip6t_get_entries { |
1902 | char name[IP6T_TABLE_MAXNAMELEN]; | 1893 | char name[XT_TABLE_MAXNAMELEN]; |
1903 | compat_uint_t size; | 1894 | compat_uint_t size; |
1904 | struct compat_ip6t_entry entrytable[0]; | 1895 | struct compat_ip6t_entry entrytable[0]; |
1905 | }; | 1896 | }; |
@@ -2054,7 +2045,7 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) | |||
2054 | 2045 | ||
2055 | case IP6T_SO_GET_REVISION_MATCH: | 2046 | case IP6T_SO_GET_REVISION_MATCH: |
2056 | case IP6T_SO_GET_REVISION_TARGET: { | 2047 | case IP6T_SO_GET_REVISION_TARGET: { |
2057 | struct ip6t_get_revision rev; | 2048 | struct xt_get_revision rev; |
2058 | int target; | 2049 | int target; |
2059 | 2050 | ||
2060 | if (*len != sizeof(rev)) { | 2051 | if (*len != sizeof(rev)) { |
@@ -2065,6 +2056,7 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) | |||
2065 | ret = -EFAULT; | 2056 | ret = -EFAULT; |
2066 | break; | 2057 | break; |
2067 | } | 2058 | } |
2059 | rev.name[sizeof(rev.name)-1] = 0; | ||
2068 | 2060 | ||
2069 | if (cmd == IP6T_SO_GET_REVISION_TARGET) | 2061 | if (cmd == IP6T_SO_GET_REVISION_TARGET) |
2070 | target = 1; | 2062 | target = 1; |
@@ -2191,7 +2183,7 @@ static int icmp6_checkentry(const struct xt_mtchk_param *par) | |||
2191 | /* The built-in targets: standard (NULL) and error. */ | 2183 | /* The built-in targets: standard (NULL) and error. */ |
2192 | static struct xt_target ip6t_builtin_tg[] __read_mostly = { | 2184 | static struct xt_target ip6t_builtin_tg[] __read_mostly = { |
2193 | { | 2185 | { |
2194 | .name = IP6T_STANDARD_TARGET, | 2186 | .name = XT_STANDARD_TARGET, |
2195 | .targetsize = sizeof(int), | 2187 | .targetsize = sizeof(int), |
2196 | .family = NFPROTO_IPV6, | 2188 | .family = NFPROTO_IPV6, |
2197 | #ifdef CONFIG_COMPAT | 2189 | #ifdef CONFIG_COMPAT |
@@ -2201,9 +2193,9 @@ static struct xt_target ip6t_builtin_tg[] __read_mostly = { | |||
2201 | #endif | 2193 | #endif |
2202 | }, | 2194 | }, |
2203 | { | 2195 | { |
2204 | .name = IP6T_ERROR_TARGET, | 2196 | .name = XT_ERROR_TARGET, |
2205 | .target = ip6t_error, | 2197 | .target = ip6t_error, |
2206 | .targetsize = IP6T_FUNCTION_MAXNAMELEN, | 2198 | .targetsize = XT_FUNCTION_MAXNAMELEN, |
2207 | .family = NFPROTO_IPV6, | 2199 | .family = NFPROTO_IPV6, |
2208 | }, | 2200 | }, |
2209 | }; | 2201 | }; |
@@ -2259,7 +2251,7 @@ static int __init ip6_tables_init(void) | |||
2259 | if (ret < 0) | 2251 | if (ret < 0) |
2260 | goto err1; | 2252 | goto err1; |
2261 | 2253 | ||
2262 | /* Noone else will be downing sem now, so we won't sleep */ | 2254 | /* No one else will be downing sem now, so we won't sleep */ |
2263 | ret = xt_register_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg)); | 2255 | ret = xt_register_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg)); |
2264 | if (ret < 0) | 2256 | if (ret < 0) |
2265 | goto err2; | 2257 | goto err2; |
diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c index 0a07ae7b933f..e6af8d72f26b 100644 --- a/net/ipv6/netfilter/ip6t_LOG.c +++ b/net/ipv6/netfilter/ip6t_LOG.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/netfilter/x_tables.h> | 23 | #include <linux/netfilter/x_tables.h> |
24 | #include <linux/netfilter_ipv6/ip6_tables.h> | 24 | #include <linux/netfilter_ipv6/ip6_tables.h> |
25 | #include <net/netfilter/nf_log.h> | 25 | #include <net/netfilter/nf_log.h> |
26 | #include <net/netfilter/xt_log.h> | ||
26 | 27 | ||
27 | MODULE_AUTHOR("Jan Rekorajski <baggins@pld.org.pl>"); | 28 | MODULE_AUTHOR("Jan Rekorajski <baggins@pld.org.pl>"); |
28 | MODULE_DESCRIPTION("Xtables: IPv6 packet logging to syslog"); | 29 | MODULE_DESCRIPTION("Xtables: IPv6 packet logging to syslog"); |
@@ -32,11 +33,9 @@ struct in_device; | |||
32 | #include <net/route.h> | 33 | #include <net/route.h> |
33 | #include <linux/netfilter_ipv6/ip6t_LOG.h> | 34 | #include <linux/netfilter_ipv6/ip6t_LOG.h> |
34 | 35 | ||
35 | /* Use lock to serialize, so printks don't overlap */ | ||
36 | static DEFINE_SPINLOCK(log_lock); | ||
37 | |||
38 | /* One level of recursion won't kill us */ | 36 | /* One level of recursion won't kill us */ |
39 | static void dump_packet(const struct nf_loginfo *info, | 37 | static void dump_packet(struct sbuff *m, |
38 | const struct nf_loginfo *info, | ||
40 | const struct sk_buff *skb, unsigned int ip6hoff, | 39 | const struct sk_buff *skb, unsigned int ip6hoff, |
41 | int recurse) | 40 | int recurse) |
42 | { | 41 | { |
@@ -55,15 +54,15 @@ static void dump_packet(const struct nf_loginfo *info, | |||
55 | 54 | ||
56 | ih = skb_header_pointer(skb, ip6hoff, sizeof(_ip6h), &_ip6h); | 55 | ih = skb_header_pointer(skb, ip6hoff, sizeof(_ip6h), &_ip6h); |
57 | if (ih == NULL) { | 56 | if (ih == NULL) { |
58 | printk("TRUNCATED"); | 57 | sb_add(m, "TRUNCATED"); |
59 | return; | 58 | return; |
60 | } | 59 | } |
61 | 60 | ||
62 | /* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000 " */ | 61 | /* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000 " */ |
63 | printk("SRC=%pI6 DST=%pI6 ", &ih->saddr, &ih->daddr); | 62 | sb_add(m, "SRC=%pI6 DST=%pI6 ", &ih->saddr, &ih->daddr); |
64 | 63 | ||
65 | /* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */ | 64 | /* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */ |
66 | printk("LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ", | 65 | sb_add(m, "LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ", |
67 | ntohs(ih->payload_len) + sizeof(struct ipv6hdr), | 66 | ntohs(ih->payload_len) + sizeof(struct ipv6hdr), |
68 | (ntohl(*(__be32 *)ih) & 0x0ff00000) >> 20, | 67 | (ntohl(*(__be32 *)ih) & 0x0ff00000) >> 20, |
69 | ih->hop_limit, | 68 | ih->hop_limit, |
@@ -78,35 +77,35 @@ static void dump_packet(const struct nf_loginfo *info, | |||
78 | 77 | ||
79 | hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); | 78 | hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); |
80 | if (hp == NULL) { | 79 | if (hp == NULL) { |
81 | printk("TRUNCATED"); | 80 | sb_add(m, "TRUNCATED"); |
82 | return; | 81 | return; |
83 | } | 82 | } |
84 | 83 | ||
85 | /* Max length: 48 "OPT (...) " */ | 84 | /* Max length: 48 "OPT (...) " */ |
86 | if (logflags & IP6T_LOG_IPOPT) | 85 | if (logflags & IP6T_LOG_IPOPT) |
87 | printk("OPT ( "); | 86 | sb_add(m, "OPT ( "); |
88 | 87 | ||
89 | switch (currenthdr) { | 88 | switch (currenthdr) { |
90 | case IPPROTO_FRAGMENT: { | 89 | case IPPROTO_FRAGMENT: { |
91 | struct frag_hdr _fhdr; | 90 | struct frag_hdr _fhdr; |
92 | const struct frag_hdr *fh; | 91 | const struct frag_hdr *fh; |
93 | 92 | ||
94 | printk("FRAG:"); | 93 | sb_add(m, "FRAG:"); |
95 | fh = skb_header_pointer(skb, ptr, sizeof(_fhdr), | 94 | fh = skb_header_pointer(skb, ptr, sizeof(_fhdr), |
96 | &_fhdr); | 95 | &_fhdr); |
97 | if (fh == NULL) { | 96 | if (fh == NULL) { |
98 | printk("TRUNCATED "); | 97 | sb_add(m, "TRUNCATED "); |
99 | return; | 98 | return; |
100 | } | 99 | } |
101 | 100 | ||
102 | /* Max length: 6 "65535 " */ | 101 | /* Max length: 6 "65535 " */ |
103 | printk("%u ", ntohs(fh->frag_off) & 0xFFF8); | 102 | sb_add(m, "%u ", ntohs(fh->frag_off) & 0xFFF8); |
104 | 103 | ||
105 | /* Max length: 11 "INCOMPLETE " */ | 104 | /* Max length: 11 "INCOMPLETE " */ |
106 | if (fh->frag_off & htons(0x0001)) | 105 | if (fh->frag_off & htons(0x0001)) |
107 | printk("INCOMPLETE "); | 106 | sb_add(m, "INCOMPLETE "); |
108 | 107 | ||
109 | printk("ID:%08x ", ntohl(fh->identification)); | 108 | sb_add(m, "ID:%08x ", ntohl(fh->identification)); |
110 | 109 | ||
111 | if (ntohs(fh->frag_off) & 0xFFF8) | 110 | if (ntohs(fh->frag_off) & 0xFFF8) |
112 | fragment = 1; | 111 | fragment = 1; |
@@ -120,7 +119,7 @@ static void dump_packet(const struct nf_loginfo *info, | |||
120 | case IPPROTO_HOPOPTS: | 119 | case IPPROTO_HOPOPTS: |
121 | if (fragment) { | 120 | if (fragment) { |
122 | if (logflags & IP6T_LOG_IPOPT) | 121 | if (logflags & IP6T_LOG_IPOPT) |
123 | printk(")"); | 122 | sb_add(m, ")"); |
124 | return; | 123 | return; |
125 | } | 124 | } |
126 | hdrlen = ipv6_optlen(hp); | 125 | hdrlen = ipv6_optlen(hp); |
@@ -132,10 +131,10 @@ static void dump_packet(const struct nf_loginfo *info, | |||
132 | const struct ip_auth_hdr *ah; | 131 | const struct ip_auth_hdr *ah; |
133 | 132 | ||
134 | /* Max length: 3 "AH " */ | 133 | /* Max length: 3 "AH " */ |
135 | printk("AH "); | 134 | sb_add(m, "AH "); |
136 | 135 | ||
137 | if (fragment) { | 136 | if (fragment) { |
138 | printk(")"); | 137 | sb_add(m, ")"); |
139 | return; | 138 | return; |
140 | } | 139 | } |
141 | 140 | ||
@@ -146,13 +145,13 @@ static void dump_packet(const struct nf_loginfo *info, | |||
146 | * Max length: 26 "INCOMPLETE [65535 | 145 | * Max length: 26 "INCOMPLETE [65535 |
147 | * bytes] )" | 146 | * bytes] )" |
148 | */ | 147 | */ |
149 | printk("INCOMPLETE [%u bytes] )", | 148 | sb_add(m, "INCOMPLETE [%u bytes] )", |
150 | skb->len - ptr); | 149 | skb->len - ptr); |
151 | return; | 150 | return; |
152 | } | 151 | } |
153 | 152 | ||
154 | /* Length: 15 "SPI=0xF1234567 */ | 153 | /* Length: 15 "SPI=0xF1234567 */ |
155 | printk("SPI=0x%x ", ntohl(ah->spi)); | 154 | sb_add(m, "SPI=0x%x ", ntohl(ah->spi)); |
156 | 155 | ||
157 | } | 156 | } |
158 | 157 | ||
@@ -164,10 +163,10 @@ static void dump_packet(const struct nf_loginfo *info, | |||
164 | const struct ip_esp_hdr *eh; | 163 | const struct ip_esp_hdr *eh; |
165 | 164 | ||
166 | /* Max length: 4 "ESP " */ | 165 | /* Max length: 4 "ESP " */ |
167 | printk("ESP "); | 166 | sb_add(m, "ESP "); |
168 | 167 | ||
169 | if (fragment) { | 168 | if (fragment) { |
170 | printk(")"); | 169 | sb_add(m, ")"); |
171 | return; | 170 | return; |
172 | } | 171 | } |
173 | 172 | ||
@@ -177,23 +176,23 @@ static void dump_packet(const struct nf_loginfo *info, | |||
177 | eh = skb_header_pointer(skb, ptr, sizeof(_esph), | 176 | eh = skb_header_pointer(skb, ptr, sizeof(_esph), |
178 | &_esph); | 177 | &_esph); |
179 | if (eh == NULL) { | 178 | if (eh == NULL) { |
180 | printk("INCOMPLETE [%u bytes] )", | 179 | sb_add(m, "INCOMPLETE [%u bytes] )", |
181 | skb->len - ptr); | 180 | skb->len - ptr); |
182 | return; | 181 | return; |
183 | } | 182 | } |
184 | 183 | ||
185 | /* Length: 16 "SPI=0xF1234567 )" */ | 184 | /* Length: 16 "SPI=0xF1234567 )" */ |
186 | printk("SPI=0x%x )", ntohl(eh->spi) ); | 185 | sb_add(m, "SPI=0x%x )", ntohl(eh->spi) ); |
187 | 186 | ||
188 | } | 187 | } |
189 | return; | 188 | return; |
190 | default: | 189 | default: |
191 | /* Max length: 20 "Unknown Ext Hdr 255" */ | 190 | /* Max length: 20 "Unknown Ext Hdr 255" */ |
192 | printk("Unknown Ext Hdr %u", currenthdr); | 191 | sb_add(m, "Unknown Ext Hdr %u", currenthdr); |
193 | return; | 192 | return; |
194 | } | 193 | } |
195 | if (logflags & IP6T_LOG_IPOPT) | 194 | if (logflags & IP6T_LOG_IPOPT) |
196 | printk(") "); | 195 | sb_add(m, ") "); |
197 | 196 | ||
198 | currenthdr = hp->nexthdr; | 197 | currenthdr = hp->nexthdr; |
199 | ptr += hdrlen; | 198 | ptr += hdrlen; |
@@ -205,7 +204,7 @@ static void dump_packet(const struct nf_loginfo *info, | |||
205 | const struct tcphdr *th; | 204 | const struct tcphdr *th; |
206 | 205 | ||
207 | /* Max length: 10 "PROTO=TCP " */ | 206 | /* Max length: 10 "PROTO=TCP " */ |
208 | printk("PROTO=TCP "); | 207 | sb_add(m, "PROTO=TCP "); |
209 | 208 | ||
210 | if (fragment) | 209 | if (fragment) |
211 | break; | 210 | break; |
@@ -213,40 +212,40 @@ static void dump_packet(const struct nf_loginfo *info, | |||
213 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | 212 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ |
214 | th = skb_header_pointer(skb, ptr, sizeof(_tcph), &_tcph); | 213 | th = skb_header_pointer(skb, ptr, sizeof(_tcph), &_tcph); |
215 | if (th == NULL) { | 214 | if (th == NULL) { |
216 | printk("INCOMPLETE [%u bytes] ", skb->len - ptr); | 215 | sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - ptr); |
217 | return; | 216 | return; |
218 | } | 217 | } |
219 | 218 | ||
220 | /* Max length: 20 "SPT=65535 DPT=65535 " */ | 219 | /* Max length: 20 "SPT=65535 DPT=65535 " */ |
221 | printk("SPT=%u DPT=%u ", | 220 | sb_add(m, "SPT=%u DPT=%u ", |
222 | ntohs(th->source), ntohs(th->dest)); | 221 | ntohs(th->source), ntohs(th->dest)); |
223 | /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */ | 222 | /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */ |
224 | if (logflags & IP6T_LOG_TCPSEQ) | 223 | if (logflags & IP6T_LOG_TCPSEQ) |
225 | printk("SEQ=%u ACK=%u ", | 224 | sb_add(m, "SEQ=%u ACK=%u ", |
226 | ntohl(th->seq), ntohl(th->ack_seq)); | 225 | ntohl(th->seq), ntohl(th->ack_seq)); |
227 | /* Max length: 13 "WINDOW=65535 " */ | 226 | /* Max length: 13 "WINDOW=65535 " */ |
228 | printk("WINDOW=%u ", ntohs(th->window)); | 227 | sb_add(m, "WINDOW=%u ", ntohs(th->window)); |
229 | /* Max length: 9 "RES=0x3C " */ | 228 | /* Max length: 9 "RES=0x3C " */ |
230 | printk("RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22)); | 229 | sb_add(m, "RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22)); |
231 | /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */ | 230 | /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */ |
232 | if (th->cwr) | 231 | if (th->cwr) |
233 | printk("CWR "); | 232 | sb_add(m, "CWR "); |
234 | if (th->ece) | 233 | if (th->ece) |
235 | printk("ECE "); | 234 | sb_add(m, "ECE "); |
236 | if (th->urg) | 235 | if (th->urg) |
237 | printk("URG "); | 236 | sb_add(m, "URG "); |
238 | if (th->ack) | 237 | if (th->ack) |
239 | printk("ACK "); | 238 | sb_add(m, "ACK "); |
240 | if (th->psh) | 239 | if (th->psh) |
241 | printk("PSH "); | 240 | sb_add(m, "PSH "); |
242 | if (th->rst) | 241 | if (th->rst) |
243 | printk("RST "); | 242 | sb_add(m, "RST "); |
244 | if (th->syn) | 243 | if (th->syn) |
245 | printk("SYN "); | 244 | sb_add(m, "SYN "); |
246 | if (th->fin) | 245 | if (th->fin) |
247 | printk("FIN "); | 246 | sb_add(m, "FIN "); |
248 | /* Max length: 11 "URGP=65535 " */ | 247 | /* Max length: 11 "URGP=65535 " */ |
249 | printk("URGP=%u ", ntohs(th->urg_ptr)); | 248 | sb_add(m, "URGP=%u ", ntohs(th->urg_ptr)); |
250 | 249 | ||
251 | if ((logflags & IP6T_LOG_TCPOPT) && | 250 | if ((logflags & IP6T_LOG_TCPOPT) && |
252 | th->doff * 4 > sizeof(struct tcphdr)) { | 251 | th->doff * 4 > sizeof(struct tcphdr)) { |
@@ -260,15 +259,15 @@ static void dump_packet(const struct nf_loginfo *info, | |||
260 | ptr + sizeof(struct tcphdr), | 259 | ptr + sizeof(struct tcphdr), |
261 | optsize, _opt); | 260 | optsize, _opt); |
262 | if (op == NULL) { | 261 | if (op == NULL) { |
263 | printk("OPT (TRUNCATED)"); | 262 | sb_add(m, "OPT (TRUNCATED)"); |
264 | return; | 263 | return; |
265 | } | 264 | } |
266 | 265 | ||
267 | /* Max length: 127 "OPT (" 15*4*2chars ") " */ | 266 | /* Max length: 127 "OPT (" 15*4*2chars ") " */ |
268 | printk("OPT ("); | 267 | sb_add(m, "OPT ("); |
269 | for (i =0; i < optsize; i++) | 268 | for (i =0; i < optsize; i++) |
270 | printk("%02X", op[i]); | 269 | sb_add(m, "%02X", op[i]); |
271 | printk(") "); | 270 | sb_add(m, ") "); |
272 | } | 271 | } |
273 | break; | 272 | break; |
274 | } | 273 | } |
@@ -279,9 +278,9 @@ static void dump_packet(const struct nf_loginfo *info, | |||
279 | 278 | ||
280 | if (currenthdr == IPPROTO_UDP) | 279 | if (currenthdr == IPPROTO_UDP) |
281 | /* Max length: 10 "PROTO=UDP " */ | 280 | /* Max length: 10 "PROTO=UDP " */ |
282 | printk("PROTO=UDP " ); | 281 | sb_add(m, "PROTO=UDP " ); |
283 | else /* Max length: 14 "PROTO=UDPLITE " */ | 282 | else /* Max length: 14 "PROTO=UDPLITE " */ |
284 | printk("PROTO=UDPLITE "); | 283 | sb_add(m, "PROTO=UDPLITE "); |
285 | 284 | ||
286 | if (fragment) | 285 | if (fragment) |
287 | break; | 286 | break; |
@@ -289,12 +288,12 @@ static void dump_packet(const struct nf_loginfo *info, | |||
289 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | 288 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ |
290 | uh = skb_header_pointer(skb, ptr, sizeof(_udph), &_udph); | 289 | uh = skb_header_pointer(skb, ptr, sizeof(_udph), &_udph); |
291 | if (uh == NULL) { | 290 | if (uh == NULL) { |
292 | printk("INCOMPLETE [%u bytes] ", skb->len - ptr); | 291 | sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - ptr); |
293 | return; | 292 | return; |
294 | } | 293 | } |
295 | 294 | ||
296 | /* Max length: 20 "SPT=65535 DPT=65535 " */ | 295 | /* Max length: 20 "SPT=65535 DPT=65535 " */ |
297 | printk("SPT=%u DPT=%u LEN=%u ", | 296 | sb_add(m, "SPT=%u DPT=%u LEN=%u ", |
298 | ntohs(uh->source), ntohs(uh->dest), | 297 | ntohs(uh->source), ntohs(uh->dest), |
299 | ntohs(uh->len)); | 298 | ntohs(uh->len)); |
300 | break; | 299 | break; |
@@ -304,7 +303,7 @@ static void dump_packet(const struct nf_loginfo *info, | |||
304 | const struct icmp6hdr *ic; | 303 | const struct icmp6hdr *ic; |
305 | 304 | ||
306 | /* Max length: 13 "PROTO=ICMPv6 " */ | 305 | /* Max length: 13 "PROTO=ICMPv6 " */ |
307 | printk("PROTO=ICMPv6 "); | 306 | sb_add(m, "PROTO=ICMPv6 "); |
308 | 307 | ||
309 | if (fragment) | 308 | if (fragment) |
310 | break; | 309 | break; |
@@ -312,18 +311,18 @@ static void dump_packet(const struct nf_loginfo *info, | |||
312 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | 311 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ |
313 | ic = skb_header_pointer(skb, ptr, sizeof(_icmp6h), &_icmp6h); | 312 | ic = skb_header_pointer(skb, ptr, sizeof(_icmp6h), &_icmp6h); |
314 | if (ic == NULL) { | 313 | if (ic == NULL) { |
315 | printk("INCOMPLETE [%u bytes] ", skb->len - ptr); | 314 | sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - ptr); |
316 | return; | 315 | return; |
317 | } | 316 | } |
318 | 317 | ||
319 | /* Max length: 18 "TYPE=255 CODE=255 " */ | 318 | /* Max length: 18 "TYPE=255 CODE=255 " */ |
320 | printk("TYPE=%u CODE=%u ", ic->icmp6_type, ic->icmp6_code); | 319 | sb_add(m, "TYPE=%u CODE=%u ", ic->icmp6_type, ic->icmp6_code); |
321 | 320 | ||
322 | switch (ic->icmp6_type) { | 321 | switch (ic->icmp6_type) { |
323 | case ICMPV6_ECHO_REQUEST: | 322 | case ICMPV6_ECHO_REQUEST: |
324 | case ICMPV6_ECHO_REPLY: | 323 | case ICMPV6_ECHO_REPLY: |
325 | /* Max length: 19 "ID=65535 SEQ=65535 " */ | 324 | /* Max length: 19 "ID=65535 SEQ=65535 " */ |
326 | printk("ID=%u SEQ=%u ", | 325 | sb_add(m, "ID=%u SEQ=%u ", |
327 | ntohs(ic->icmp6_identifier), | 326 | ntohs(ic->icmp6_identifier), |
328 | ntohs(ic->icmp6_sequence)); | 327 | ntohs(ic->icmp6_sequence)); |
329 | break; | 328 | break; |
@@ -334,35 +333,35 @@ static void dump_packet(const struct nf_loginfo *info, | |||
334 | 333 | ||
335 | case ICMPV6_PARAMPROB: | 334 | case ICMPV6_PARAMPROB: |
336 | /* Max length: 17 "POINTER=ffffffff " */ | 335 | /* Max length: 17 "POINTER=ffffffff " */ |
337 | printk("POINTER=%08x ", ntohl(ic->icmp6_pointer)); | 336 | sb_add(m, "POINTER=%08x ", ntohl(ic->icmp6_pointer)); |
338 | /* Fall through */ | 337 | /* Fall through */ |
339 | case ICMPV6_DEST_UNREACH: | 338 | case ICMPV6_DEST_UNREACH: |
340 | case ICMPV6_PKT_TOOBIG: | 339 | case ICMPV6_PKT_TOOBIG: |
341 | case ICMPV6_TIME_EXCEED: | 340 | case ICMPV6_TIME_EXCEED: |
342 | /* Max length: 3+maxlen */ | 341 | /* Max length: 3+maxlen */ |
343 | if (recurse) { | 342 | if (recurse) { |
344 | printk("["); | 343 | sb_add(m, "["); |
345 | dump_packet(info, skb, ptr + sizeof(_icmp6h), | 344 | dump_packet(m, info, skb, |
346 | 0); | 345 | ptr + sizeof(_icmp6h), 0); |
347 | printk("] "); | 346 | sb_add(m, "] "); |
348 | } | 347 | } |
349 | 348 | ||
350 | /* Max length: 10 "MTU=65535 " */ | 349 | /* Max length: 10 "MTU=65535 " */ |
351 | if (ic->icmp6_type == ICMPV6_PKT_TOOBIG) | 350 | if (ic->icmp6_type == ICMPV6_PKT_TOOBIG) |
352 | printk("MTU=%u ", ntohl(ic->icmp6_mtu)); | 351 | sb_add(m, "MTU=%u ", ntohl(ic->icmp6_mtu)); |
353 | } | 352 | } |
354 | break; | 353 | break; |
355 | } | 354 | } |
356 | /* Max length: 10 "PROTO=255 " */ | 355 | /* Max length: 10 "PROTO=255 " */ |
357 | default: | 356 | default: |
358 | printk("PROTO=%u ", currenthdr); | 357 | sb_add(m, "PROTO=%u ", currenthdr); |
359 | } | 358 | } |
360 | 359 | ||
361 | /* Max length: 15 "UID=4294967295 " */ | 360 | /* Max length: 15 "UID=4294967295 " */ |
362 | if ((logflags & IP6T_LOG_UID) && recurse && skb->sk) { | 361 | if ((logflags & IP6T_LOG_UID) && recurse && skb->sk) { |
363 | read_lock_bh(&skb->sk->sk_callback_lock); | 362 | read_lock_bh(&skb->sk->sk_callback_lock); |
364 | if (skb->sk->sk_socket && skb->sk->sk_socket->file) | 363 | if (skb->sk->sk_socket && skb->sk->sk_socket->file) |
365 | printk("UID=%u GID=%u ", | 364 | sb_add(m, "UID=%u GID=%u ", |
366 | skb->sk->sk_socket->file->f_cred->fsuid, | 365 | skb->sk->sk_socket->file->f_cred->fsuid, |
367 | skb->sk->sk_socket->file->f_cred->fsgid); | 366 | skb->sk->sk_socket->file->f_cred->fsgid); |
368 | read_unlock_bh(&skb->sk->sk_callback_lock); | 367 | read_unlock_bh(&skb->sk->sk_callback_lock); |
@@ -370,10 +369,11 @@ static void dump_packet(const struct nf_loginfo *info, | |||
370 | 369 | ||
371 | /* Max length: 16 "MARK=0xFFFFFFFF " */ | 370 | /* Max length: 16 "MARK=0xFFFFFFFF " */ |
372 | if (!recurse && skb->mark) | 371 | if (!recurse && skb->mark) |
373 | printk("MARK=0x%x ", skb->mark); | 372 | sb_add(m, "MARK=0x%x ", skb->mark); |
374 | } | 373 | } |
375 | 374 | ||
376 | static void dump_mac_header(const struct nf_loginfo *info, | 375 | static void dump_mac_header(struct sbuff *m, |
376 | const struct nf_loginfo *info, | ||
377 | const struct sk_buff *skb) | 377 | const struct sk_buff *skb) |
378 | { | 378 | { |
379 | struct net_device *dev = skb->dev; | 379 | struct net_device *dev = skb->dev; |
@@ -387,7 +387,7 @@ static void dump_mac_header(const struct nf_loginfo *info, | |||
387 | 387 | ||
388 | switch (dev->type) { | 388 | switch (dev->type) { |
389 | case ARPHRD_ETHER: | 389 | case ARPHRD_ETHER: |
390 | printk("MACSRC=%pM MACDST=%pM MACPROTO=%04x ", | 390 | sb_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ", |
391 | eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, | 391 | eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, |
392 | ntohs(eth_hdr(skb)->h_proto)); | 392 | ntohs(eth_hdr(skb)->h_proto)); |
393 | return; | 393 | return; |
@@ -396,7 +396,7 @@ static void dump_mac_header(const struct nf_loginfo *info, | |||
396 | } | 396 | } |
397 | 397 | ||
398 | fallback: | 398 | fallback: |
399 | printk("MAC="); | 399 | sb_add(m, "MAC="); |
400 | if (dev->hard_header_len && | 400 | if (dev->hard_header_len && |
401 | skb->mac_header != skb->network_header) { | 401 | skb->mac_header != skb->network_header) { |
402 | const unsigned char *p = skb_mac_header(skb); | 402 | const unsigned char *p = skb_mac_header(skb); |
@@ -408,19 +408,19 @@ fallback: | |||
408 | p = NULL; | 408 | p = NULL; |
409 | 409 | ||
410 | if (p != NULL) { | 410 | if (p != NULL) { |
411 | printk("%02x", *p++); | 411 | sb_add(m, "%02x", *p++); |
412 | for (i = 1; i < len; i++) | 412 | for (i = 1; i < len; i++) |
413 | printk(":%02x", p[i]); | 413 | sb_add(m, ":%02x", *p++); |
414 | } | 414 | } |
415 | printk(" "); | 415 | sb_add(m, " "); |
416 | 416 | ||
417 | if (dev->type == ARPHRD_SIT) { | 417 | if (dev->type == ARPHRD_SIT) { |
418 | const struct iphdr *iph = | 418 | const struct iphdr *iph = |
419 | (struct iphdr *)skb_mac_header(skb); | 419 | (struct iphdr *)skb_mac_header(skb); |
420 | printk("TUNNEL=%pI4->%pI4 ", &iph->saddr, &iph->daddr); | 420 | sb_add(m, "TUNNEL=%pI4->%pI4 ", &iph->saddr, &iph->daddr); |
421 | } | 421 | } |
422 | } else | 422 | } else |
423 | printk(" "); | 423 | sb_add(m, " "); |
424 | } | 424 | } |
425 | 425 | ||
426 | static struct nf_loginfo default_loginfo = { | 426 | static struct nf_loginfo default_loginfo = { |
@@ -442,22 +442,22 @@ ip6t_log_packet(u_int8_t pf, | |||
442 | const struct nf_loginfo *loginfo, | 442 | const struct nf_loginfo *loginfo, |
443 | const char *prefix) | 443 | const char *prefix) |
444 | { | 444 | { |
445 | struct sbuff *m = sb_open(); | ||
446 | |||
445 | if (!loginfo) | 447 | if (!loginfo) |
446 | loginfo = &default_loginfo; | 448 | loginfo = &default_loginfo; |
447 | 449 | ||
448 | spin_lock_bh(&log_lock); | 450 | sb_add(m, "<%d>%sIN=%s OUT=%s ", loginfo->u.log.level, |
449 | printk("<%d>%sIN=%s OUT=%s ", loginfo->u.log.level, | 451 | prefix, |
450 | prefix, | 452 | in ? in->name : "", |
451 | in ? in->name : "", | 453 | out ? out->name : ""); |
452 | out ? out->name : ""); | 454 | |
455 | if (in != NULL) | ||
456 | dump_mac_header(m, loginfo, skb); | ||
453 | 457 | ||
454 | /* MAC logging for input path only. */ | 458 | dump_packet(m, loginfo, skb, skb_network_offset(skb), 1); |
455 | if (in && !out) | ||
456 | dump_mac_header(loginfo, skb); | ||
457 | 459 | ||
458 | dump_packet(loginfo, skb, skb_network_offset(skb), 1); | 460 | sb_close(m); |
459 | printk("\n"); | ||
460 | spin_unlock_bh(&log_lock); | ||
461 | } | 461 | } |
462 | 462 | ||
463 | static unsigned int | 463 | static unsigned int |
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index 2933396e0281..a5a4c5dd5396 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c | |||
@@ -45,9 +45,11 @@ static void send_reset(struct net *net, struct sk_buff *oldskb) | |||
45 | int tcphoff, needs_ack; | 45 | int tcphoff, needs_ack; |
46 | const struct ipv6hdr *oip6h = ipv6_hdr(oldskb); | 46 | const struct ipv6hdr *oip6h = ipv6_hdr(oldskb); |
47 | struct ipv6hdr *ip6h; | 47 | struct ipv6hdr *ip6h; |
48 | #define DEFAULT_TOS_VALUE 0x0U | ||
49 | const __u8 tclass = DEFAULT_TOS_VALUE; | ||
48 | struct dst_entry *dst = NULL; | 50 | struct dst_entry *dst = NULL; |
49 | u8 proto; | 51 | u8 proto; |
50 | struct flowi fl; | 52 | struct flowi6 fl6; |
51 | 53 | ||
52 | if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) || | 54 | if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) || |
53 | (!(ipv6_addr_type(&oip6h->daddr) & IPV6_ADDR_UNICAST))) { | 55 | (!(ipv6_addr_type(&oip6h->daddr) & IPV6_ADDR_UNICAST))) { |
@@ -89,19 +91,20 @@ static void send_reset(struct net *net, struct sk_buff *oldskb) | |||
89 | return; | 91 | return; |
90 | } | 92 | } |
91 | 93 | ||
92 | memset(&fl, 0, sizeof(fl)); | 94 | memset(&fl6, 0, sizeof(fl6)); |
93 | fl.proto = IPPROTO_TCP; | 95 | fl6.flowi6_proto = IPPROTO_TCP; |
94 | ipv6_addr_copy(&fl.fl6_src, &oip6h->daddr); | 96 | ipv6_addr_copy(&fl6.saddr, &oip6h->daddr); |
95 | ipv6_addr_copy(&fl.fl6_dst, &oip6h->saddr); | 97 | ipv6_addr_copy(&fl6.daddr, &oip6h->saddr); |
96 | fl.fl_ip_sport = otcph.dest; | 98 | fl6.fl6_sport = otcph.dest; |
97 | fl.fl_ip_dport = otcph.source; | 99 | fl6.fl6_dport = otcph.source; |
98 | security_skb_classify_flow(oldskb, &fl); | 100 | security_skb_classify_flow(oldskb, flowi6_to_flowi(&fl6)); |
99 | dst = ip6_route_output(net, NULL, &fl); | 101 | dst = ip6_route_output(net, NULL, &fl6); |
100 | if (dst == NULL || dst->error) { | 102 | if (dst == NULL || dst->error) { |
101 | dst_release(dst); | 103 | dst_release(dst); |
102 | return; | 104 | return; |
103 | } | 105 | } |
104 | if (xfrm_lookup(net, &dst, &fl, NULL, 0)) | 106 | dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0); |
107 | if (IS_ERR(dst)) | ||
105 | return; | 108 | return; |
106 | 109 | ||
107 | hh_len = (dst->dev->hard_header_len + 15)&~15; | 110 | hh_len = (dst->dev->hard_header_len + 15)&~15; |
@@ -123,8 +126,8 @@ static void send_reset(struct net *net, struct sk_buff *oldskb) | |||
123 | skb_put(nskb, sizeof(struct ipv6hdr)); | 126 | skb_put(nskb, sizeof(struct ipv6hdr)); |
124 | skb_reset_network_header(nskb); | 127 | skb_reset_network_header(nskb); |
125 | ip6h = ipv6_hdr(nskb); | 128 | ip6h = ipv6_hdr(nskb); |
126 | ip6h->version = 6; | 129 | *(__be32 *)ip6h = htonl(0x60000000 | (tclass << 20)); |
127 | ip6h->hop_limit = dst_metric(dst, RTAX_HOPLIMIT); | 130 | ip6h->hop_limit = ip6_dst_hoplimit(dst); |
128 | ip6h->nexthdr = IPPROTO_TCP; | 131 | ip6h->nexthdr = IPPROTO_TCP; |
129 | ipv6_addr_copy(&ip6h->saddr, &oip6h->daddr); | 132 | ipv6_addr_copy(&ip6h->saddr, &oip6h->daddr); |
130 | ipv6_addr_copy(&ip6h->daddr, &oip6h->saddr); | 133 | ipv6_addr_copy(&ip6h->daddr, &oip6h->saddr); |
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index 679a0a3b7b3c..00d19173db7e 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c | |||
@@ -64,7 +64,8 @@ ip6t_mangle_out(struct sk_buff *skb, const struct net_device *out) | |||
64 | (memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr)) || | 64 | (memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr)) || |
65 | memcmp(&ipv6_hdr(skb)->daddr, &daddr, sizeof(daddr)) || | 65 | memcmp(&ipv6_hdr(skb)->daddr, &daddr, sizeof(daddr)) || |
66 | skb->mark != mark || | 66 | skb->mark != mark || |
67 | ipv6_hdr(skb)->hop_limit != hop_limit)) | 67 | ipv6_hdr(skb)->hop_limit != hop_limit || |
68 | flowlabel != *((u_int32_t *)ipv6_hdr(skb)))) | ||
68 | return ip6_route_me_harder(skb) == 0 ? ret : NF_DROP; | 69 | return ip6_route_me_harder(skb) == 0 ? ret : NF_DROP; |
69 | 70 | ||
70 | return ret; | 71 | return ret; |
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index ff43461704be..4111050a9fc5 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | |||
@@ -16,7 +16,6 @@ | |||
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/skbuff.h> | 17 | #include <linux/skbuff.h> |
18 | #include <linux/icmp.h> | 18 | #include <linux/icmp.h> |
19 | #include <linux/sysctl.h> | ||
20 | #include <net/ipv6.h> | 19 | #include <net/ipv6.h> |
21 | #include <net/inet_frag.h> | 20 | #include <net/inet_frag.h> |
22 | 21 | ||
@@ -29,6 +28,7 @@ | |||
29 | #include <net/netfilter/nf_conntrack_core.h> | 28 | #include <net/netfilter/nf_conntrack_core.h> |
30 | #include <net/netfilter/nf_conntrack_zones.h> | 29 | #include <net/netfilter/nf_conntrack_zones.h> |
31 | #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> | 30 | #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> |
31 | #include <net/netfilter/ipv6/nf_defrag_ipv6.h> | ||
32 | #include <net/netfilter/nf_log.h> | 32 | #include <net/netfilter/nf_log.h> |
33 | 33 | ||
34 | static bool ipv6_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff, | 34 | static bool ipv6_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff, |
@@ -160,7 +160,7 @@ static unsigned int ipv6_confirm(unsigned int hooknum, | |||
160 | 160 | ||
161 | /* This is where we call the helper: as the packet goes out. */ | 161 | /* This is where we call the helper: as the packet goes out. */ |
162 | ct = nf_ct_get(skb, &ctinfo); | 162 | ct = nf_ct_get(skb, &ctinfo); |
163 | if (!ct || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY) | 163 | if (!ct || ctinfo == IP_CT_RELATED_REPLY) |
164 | goto out; | 164 | goto out; |
165 | 165 | ||
166 | help = nfct_help(ct); | 166 | help = nfct_help(ct); |
@@ -189,53 +189,6 @@ out: | |||
189 | return nf_conntrack_confirm(skb); | 189 | return nf_conntrack_confirm(skb); |
190 | } | 190 | } |
191 | 191 | ||
192 | static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum, | ||
193 | struct sk_buff *skb) | ||
194 | { | ||
195 | u16 zone = NF_CT_DEFAULT_ZONE; | ||
196 | |||
197 | if (skb->nfct) | ||
198 | zone = nf_ct_zone((struct nf_conn *)skb->nfct); | ||
199 | |||
200 | #ifdef CONFIG_BRIDGE_NETFILTER | ||
201 | if (skb->nf_bridge && | ||
202 | skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING) | ||
203 | return IP6_DEFRAG_CONNTRACK_BRIDGE_IN + zone; | ||
204 | #endif | ||
205 | if (hooknum == NF_INET_PRE_ROUTING) | ||
206 | return IP6_DEFRAG_CONNTRACK_IN + zone; | ||
207 | else | ||
208 | return IP6_DEFRAG_CONNTRACK_OUT + zone; | ||
209 | |||
210 | } | ||
211 | |||
212 | static unsigned int ipv6_defrag(unsigned int hooknum, | ||
213 | struct sk_buff *skb, | ||
214 | const struct net_device *in, | ||
215 | const struct net_device *out, | ||
216 | int (*okfn)(struct sk_buff *)) | ||
217 | { | ||
218 | struct sk_buff *reasm; | ||
219 | |||
220 | /* Previously seen (loopback)? */ | ||
221 | if (skb->nfct && !nf_ct_is_template((struct nf_conn *)skb->nfct)) | ||
222 | return NF_ACCEPT; | ||
223 | |||
224 | reasm = nf_ct_frag6_gather(skb, nf_ct6_defrag_user(hooknum, skb)); | ||
225 | /* queued */ | ||
226 | if (reasm == NULL) | ||
227 | return NF_STOLEN; | ||
228 | |||
229 | /* error occured or not fragmented */ | ||
230 | if (reasm == skb) | ||
231 | return NF_ACCEPT; | ||
232 | |||
233 | nf_ct_frag6_output(hooknum, reasm, (struct net_device *)in, | ||
234 | (struct net_device *)out, okfn); | ||
235 | |||
236 | return NF_STOLEN; | ||
237 | } | ||
238 | |||
239 | static unsigned int __ipv6_conntrack_in(struct net *net, | 192 | static unsigned int __ipv6_conntrack_in(struct net *net, |
240 | unsigned int hooknum, | 193 | unsigned int hooknum, |
241 | struct sk_buff *skb, | 194 | struct sk_buff *skb, |
@@ -288,13 +241,6 @@ static unsigned int ipv6_conntrack_local(unsigned int hooknum, | |||
288 | 241 | ||
289 | static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = { | 242 | static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = { |
290 | { | 243 | { |
291 | .hook = ipv6_defrag, | ||
292 | .owner = THIS_MODULE, | ||
293 | .pf = NFPROTO_IPV6, | ||
294 | .hooknum = NF_INET_PRE_ROUTING, | ||
295 | .priority = NF_IP6_PRI_CONNTRACK_DEFRAG, | ||
296 | }, | ||
297 | { | ||
298 | .hook = ipv6_conntrack_in, | 244 | .hook = ipv6_conntrack_in, |
299 | .owner = THIS_MODULE, | 245 | .owner = THIS_MODULE, |
300 | .pf = NFPROTO_IPV6, | 246 | .pf = NFPROTO_IPV6, |
@@ -309,13 +255,6 @@ static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = { | |||
309 | .priority = NF_IP6_PRI_CONNTRACK, | 255 | .priority = NF_IP6_PRI_CONNTRACK, |
310 | }, | 256 | }, |
311 | { | 257 | { |
312 | .hook = ipv6_defrag, | ||
313 | .owner = THIS_MODULE, | ||
314 | .pf = NFPROTO_IPV6, | ||
315 | .hooknum = NF_INET_LOCAL_OUT, | ||
316 | .priority = NF_IP6_PRI_CONNTRACK_DEFRAG, | ||
317 | }, | ||
318 | { | ||
319 | .hook = ipv6_confirm, | 258 | .hook = ipv6_confirm, |
320 | .owner = THIS_MODULE, | 259 | .owner = THIS_MODULE, |
321 | .pf = NFPROTO_IPV6, | 260 | .pf = NFPROTO_IPV6, |
@@ -387,10 +326,6 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 __read_mostly = { | |||
387 | .nlattr_to_tuple = ipv6_nlattr_to_tuple, | 326 | .nlattr_to_tuple = ipv6_nlattr_to_tuple, |
388 | .nla_policy = ipv6_nla_policy, | 327 | .nla_policy = ipv6_nla_policy, |
389 | #endif | 328 | #endif |
390 | #ifdef CONFIG_SYSCTL | ||
391 | .ctl_table_path = nf_net_netfilter_sysctl_path, | ||
392 | .ctl_table = nf_ct_ipv6_sysctl_table, | ||
393 | #endif | ||
394 | .me = THIS_MODULE, | 329 | .me = THIS_MODULE, |
395 | }; | 330 | }; |
396 | 331 | ||
@@ -403,16 +338,12 @@ static int __init nf_conntrack_l3proto_ipv6_init(void) | |||
403 | int ret = 0; | 338 | int ret = 0; |
404 | 339 | ||
405 | need_conntrack(); | 340 | need_conntrack(); |
341 | nf_defrag_ipv6_enable(); | ||
406 | 342 | ||
407 | ret = nf_ct_frag6_init(); | ||
408 | if (ret < 0) { | ||
409 | pr_err("nf_conntrack_ipv6: can't initialize frag6.\n"); | ||
410 | return ret; | ||
411 | } | ||
412 | ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_tcp6); | 343 | ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_tcp6); |
413 | if (ret < 0) { | 344 | if (ret < 0) { |
414 | pr_err("nf_conntrack_ipv6: can't register tcp.\n"); | 345 | pr_err("nf_conntrack_ipv6: can't register tcp.\n"); |
415 | goto cleanup_frag6; | 346 | return ret; |
416 | } | 347 | } |
417 | 348 | ||
418 | ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_udp6); | 349 | ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_udp6); |
@@ -450,8 +381,6 @@ static int __init nf_conntrack_l3proto_ipv6_init(void) | |||
450 | nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp6); | 381 | nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp6); |
451 | cleanup_tcp: | 382 | cleanup_tcp: |
452 | nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp6); | 383 | nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp6); |
453 | cleanup_frag6: | ||
454 | nf_ct_frag6_cleanup(); | ||
455 | return ret; | 384 | return ret; |
456 | } | 385 | } |
457 | 386 | ||
@@ -463,7 +392,6 @@ static void __exit nf_conntrack_l3proto_ipv6_fini(void) | |||
463 | nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_icmpv6); | 392 | nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_icmpv6); |
464 | nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp6); | 393 | nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp6); |
465 | nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp6); | 394 | nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp6); |
466 | nf_ct_frag6_cleanup(); | ||
467 | } | 395 | } |
468 | 396 | ||
469 | module_init(nf_conntrack_l3proto_ipv6_init); | 397 | module_init(nf_conntrack_l3proto_ipv6_init); |
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index 1df3c8b6bf47..7c05e7eacbc6 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | |||
@@ -177,7 +177,7 @@ icmpv6_error_message(struct net *net, struct nf_conn *tmpl, | |||
177 | /* Update skb to refer to this connection */ | 177 | /* Update skb to refer to this connection */ |
178 | skb->nfct = &nf_ct_tuplehash_to_ctrack(h)->ct_general; | 178 | skb->nfct = &nf_ct_tuplehash_to_ctrack(h)->ct_general; |
179 | skb->nfctinfo = *ctinfo; | 179 | skb->nfctinfo = *ctinfo; |
180 | return -NF_ACCEPT; | 180 | return NF_ACCEPT; |
181 | } | 181 | } |
182 | 182 | ||
183 | static int | 183 | static int |
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 578f3c1a16db..085727263812 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include <linux/netfilter_ipv6.h> | 45 | #include <linux/netfilter_ipv6.h> |
46 | #include <linux/kernel.h> | 46 | #include <linux/kernel.h> |
47 | #include <linux/module.h> | 47 | #include <linux/module.h> |
48 | #include <net/netfilter/ipv6/nf_defrag_ipv6.h> | ||
48 | 49 | ||
49 | 50 | ||
50 | struct nf_ct_frag6_skb_cb | 51 | struct nf_ct_frag6_skb_cb |
@@ -73,7 +74,7 @@ static struct inet_frags nf_frags; | |||
73 | static struct netns_frags nf_init_frags; | 74 | static struct netns_frags nf_init_frags; |
74 | 75 | ||
75 | #ifdef CONFIG_SYSCTL | 76 | #ifdef CONFIG_SYSCTL |
76 | struct ctl_table nf_ct_ipv6_sysctl_table[] = { | 77 | static struct ctl_table nf_ct_frag6_sysctl_table[] = { |
77 | { | 78 | { |
78 | .procname = "nf_conntrack_frag6_timeout", | 79 | .procname = "nf_conntrack_frag6_timeout", |
79 | .data = &nf_init_frags.timeout, | 80 | .data = &nf_init_frags.timeout, |
@@ -97,6 +98,8 @@ struct ctl_table nf_ct_ipv6_sysctl_table[] = { | |||
97 | }, | 98 | }, |
98 | { } | 99 | { } |
99 | }; | 100 | }; |
101 | |||
102 | static struct ctl_table_header *nf_ct_frag6_sysctl_header; | ||
100 | #endif | 103 | #endif |
101 | 104 | ||
102 | static unsigned int nf_hashfn(struct inet_frag_queue *q) | 105 | static unsigned int nf_hashfn(struct inet_frag_queue *q) |
@@ -284,7 +287,7 @@ found: | |||
284 | 287 | ||
285 | /* Check for overlap with preceding fragment. */ | 288 | /* Check for overlap with preceding fragment. */ |
286 | if (prev && | 289 | if (prev && |
287 | (NFCT_FRAG6_CB(prev)->offset + prev->len) - offset > 0) | 290 | (NFCT_FRAG6_CB(prev)->offset + prev->len) > offset) |
288 | goto discard_fq; | 291 | goto discard_fq; |
289 | 292 | ||
290 | /* Look for overlap with succeeding segment. */ | 293 | /* Look for overlap with succeeding segment. */ |
@@ -363,7 +366,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev) | |||
363 | /* If the first fragment is fragmented itself, we split | 366 | /* If the first fragment is fragmented itself, we split |
364 | * it to two chunks: the first with data and paged part | 367 | * it to two chunks: the first with data and paged part |
365 | * and the second, holding only fragments. */ | 368 | * and the second, holding only fragments. */ |
366 | if (skb_has_frags(head)) { | 369 | if (skb_has_frag_list(head)) { |
367 | struct sk_buff *clone; | 370 | struct sk_buff *clone; |
368 | int i, plen = 0; | 371 | int i, plen = 0; |
369 | 372 | ||
@@ -623,11 +626,24 @@ int nf_ct_frag6_init(void) | |||
623 | inet_frags_init_net(&nf_init_frags); | 626 | inet_frags_init_net(&nf_init_frags); |
624 | inet_frags_init(&nf_frags); | 627 | inet_frags_init(&nf_frags); |
625 | 628 | ||
629 | #ifdef CONFIG_SYSCTL | ||
630 | nf_ct_frag6_sysctl_header = register_sysctl_paths(nf_net_netfilter_sysctl_path, | ||
631 | nf_ct_frag6_sysctl_table); | ||
632 | if (!nf_ct_frag6_sysctl_header) { | ||
633 | inet_frags_fini(&nf_frags); | ||
634 | return -ENOMEM; | ||
635 | } | ||
636 | #endif | ||
637 | |||
626 | return 0; | 638 | return 0; |
627 | } | 639 | } |
628 | 640 | ||
629 | void nf_ct_frag6_cleanup(void) | 641 | void nf_ct_frag6_cleanup(void) |
630 | { | 642 | { |
643 | #ifdef CONFIG_SYSCTL | ||
644 | unregister_sysctl_table(nf_ct_frag6_sysctl_header); | ||
645 | nf_ct_frag6_sysctl_header = NULL; | ||
646 | #endif | ||
631 | inet_frags_fini(&nf_frags); | 647 | inet_frags_fini(&nf_frags); |
632 | 648 | ||
633 | nf_init_frags.low_thresh = 0; | 649 | nf_init_frags.low_thresh = 0; |
diff --git a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c new file mode 100644 index 000000000000..cdd6d045e42e --- /dev/null +++ b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c | |||
@@ -0,0 +1,137 @@ | |||
1 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
2 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/types.h> | ||
10 | #include <linux/ipv6.h> | ||
11 | #include <linux/in6.h> | ||
12 | #include <linux/netfilter.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/skbuff.h> | ||
15 | #include <linux/icmp.h> | ||
16 | #include <linux/sysctl.h> | ||
17 | #include <net/ipv6.h> | ||
18 | #include <net/inet_frag.h> | ||
19 | |||
20 | #include <linux/netfilter_ipv6.h> | ||
21 | #include <linux/netfilter_bridge.h> | ||
22 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | ||
23 | #include <net/netfilter/nf_conntrack.h> | ||
24 | #include <net/netfilter/nf_conntrack_helper.h> | ||
25 | #include <net/netfilter/nf_conntrack_l4proto.h> | ||
26 | #include <net/netfilter/nf_conntrack_l3proto.h> | ||
27 | #include <net/netfilter/nf_conntrack_core.h> | ||
28 | #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> | ||
29 | #endif | ||
30 | #include <net/netfilter/nf_conntrack_zones.h> | ||
31 | #include <net/netfilter/ipv6/nf_defrag_ipv6.h> | ||
32 | |||
33 | static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum, | ||
34 | struct sk_buff *skb) | ||
35 | { | ||
36 | u16 zone = NF_CT_DEFAULT_ZONE; | ||
37 | |||
38 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | ||
39 | if (skb->nfct) | ||
40 | zone = nf_ct_zone((struct nf_conn *)skb->nfct); | ||
41 | #endif | ||
42 | |||
43 | #ifdef CONFIG_BRIDGE_NETFILTER | ||
44 | if (skb->nf_bridge && | ||
45 | skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING) | ||
46 | return IP6_DEFRAG_CONNTRACK_BRIDGE_IN + zone; | ||
47 | #endif | ||
48 | if (hooknum == NF_INET_PRE_ROUTING) | ||
49 | return IP6_DEFRAG_CONNTRACK_IN + zone; | ||
50 | else | ||
51 | return IP6_DEFRAG_CONNTRACK_OUT + zone; | ||
52 | |||
53 | } | ||
54 | |||
55 | static unsigned int ipv6_defrag(unsigned int hooknum, | ||
56 | struct sk_buff *skb, | ||
57 | const struct net_device *in, | ||
58 | const struct net_device *out, | ||
59 | int (*okfn)(struct sk_buff *)) | ||
60 | { | ||
61 | struct sk_buff *reasm; | ||
62 | |||
63 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | ||
64 | /* Previously seen (loopback)? */ | ||
65 | if (skb->nfct && !nf_ct_is_template((struct nf_conn *)skb->nfct)) | ||
66 | return NF_ACCEPT; | ||
67 | #endif | ||
68 | |||
69 | reasm = nf_ct_frag6_gather(skb, nf_ct6_defrag_user(hooknum, skb)); | ||
70 | /* queued */ | ||
71 | if (reasm == NULL) | ||
72 | return NF_STOLEN; | ||
73 | |||
74 | /* error occurred or not fragmented */ | ||
75 | if (reasm == skb) | ||
76 | return NF_ACCEPT; | ||
77 | |||
78 | nf_ct_frag6_output(hooknum, reasm, (struct net_device *)in, | ||
79 | (struct net_device *)out, okfn); | ||
80 | |||
81 | return NF_STOLEN; | ||
82 | } | ||
83 | |||
84 | static struct nf_hook_ops ipv6_defrag_ops[] = { | ||
85 | { | ||
86 | .hook = ipv6_defrag, | ||
87 | .owner = THIS_MODULE, | ||
88 | .pf = NFPROTO_IPV6, | ||
89 | .hooknum = NF_INET_PRE_ROUTING, | ||
90 | .priority = NF_IP6_PRI_CONNTRACK_DEFRAG, | ||
91 | }, | ||
92 | { | ||
93 | .hook = ipv6_defrag, | ||
94 | .owner = THIS_MODULE, | ||
95 | .pf = NFPROTO_IPV6, | ||
96 | .hooknum = NF_INET_LOCAL_OUT, | ||
97 | .priority = NF_IP6_PRI_CONNTRACK_DEFRAG, | ||
98 | }, | ||
99 | }; | ||
100 | |||
101 | static int __init nf_defrag_init(void) | ||
102 | { | ||
103 | int ret = 0; | ||
104 | |||
105 | ret = nf_ct_frag6_init(); | ||
106 | if (ret < 0) { | ||
107 | pr_err("nf_defrag_ipv6: can't initialize frag6.\n"); | ||
108 | return ret; | ||
109 | } | ||
110 | ret = nf_register_hooks(ipv6_defrag_ops, ARRAY_SIZE(ipv6_defrag_ops)); | ||
111 | if (ret < 0) { | ||
112 | pr_err("nf_defrag_ipv6: can't register hooks\n"); | ||
113 | goto cleanup_frag6; | ||
114 | } | ||
115 | return ret; | ||
116 | |||
117 | cleanup_frag6: | ||
118 | nf_ct_frag6_cleanup(); | ||
119 | return ret; | ||
120 | |||
121 | } | ||
122 | |||
123 | static void __exit nf_defrag_fini(void) | ||
124 | { | ||
125 | nf_unregister_hooks(ipv6_defrag_ops, ARRAY_SIZE(ipv6_defrag_ops)); | ||
126 | nf_ct_frag6_cleanup(); | ||
127 | } | ||
128 | |||
129 | void nf_defrag_ipv6_enable(void) | ||
130 | { | ||
131 | } | ||
132 | EXPORT_SYMBOL_GPL(nf_defrag_ipv6_enable); | ||
133 | |||
134 | module_init(nf_defrag_init); | ||
135 | module_exit(nf_defrag_fini); | ||
136 | |||
137 | MODULE_LICENSE("GPL"); | ||
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index d082eaeefa25..18ff5df7ec02 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c | |||
@@ -126,6 +126,8 @@ static const struct snmp_mib snmp6_udp6_list[] = { | |||
126 | SNMP_MIB_ITEM("Udp6NoPorts", UDP_MIB_NOPORTS), | 126 | SNMP_MIB_ITEM("Udp6NoPorts", UDP_MIB_NOPORTS), |
127 | SNMP_MIB_ITEM("Udp6InErrors", UDP_MIB_INERRORS), | 127 | SNMP_MIB_ITEM("Udp6InErrors", UDP_MIB_INERRORS), |
128 | SNMP_MIB_ITEM("Udp6OutDatagrams", UDP_MIB_OUTDATAGRAMS), | 128 | SNMP_MIB_ITEM("Udp6OutDatagrams", UDP_MIB_OUTDATAGRAMS), |
129 | SNMP_MIB_ITEM("Udp6RcvbufErrors", UDP_MIB_RCVBUFERRORS), | ||
130 | SNMP_MIB_ITEM("Udp6SndbufErrors", UDP_MIB_SNDBUFERRORS), | ||
129 | SNMP_MIB_SENTINEL | 131 | SNMP_MIB_SENTINEL |
130 | }; | 132 | }; |
131 | 133 | ||
@@ -134,10 +136,16 @@ static const struct snmp_mib snmp6_udplite6_list[] = { | |||
134 | SNMP_MIB_ITEM("UdpLite6NoPorts", UDP_MIB_NOPORTS), | 136 | SNMP_MIB_ITEM("UdpLite6NoPorts", UDP_MIB_NOPORTS), |
135 | SNMP_MIB_ITEM("UdpLite6InErrors", UDP_MIB_INERRORS), | 137 | SNMP_MIB_ITEM("UdpLite6InErrors", UDP_MIB_INERRORS), |
136 | SNMP_MIB_ITEM("UdpLite6OutDatagrams", UDP_MIB_OUTDATAGRAMS), | 138 | SNMP_MIB_ITEM("UdpLite6OutDatagrams", UDP_MIB_OUTDATAGRAMS), |
139 | SNMP_MIB_ITEM("UdpLite6RcvbufErrors", UDP_MIB_RCVBUFERRORS), | ||
140 | SNMP_MIB_ITEM("UdpLite6SndbufErrors", UDP_MIB_SNDBUFERRORS), | ||
137 | SNMP_MIB_SENTINEL | 141 | SNMP_MIB_SENTINEL |
138 | }; | 142 | }; |
139 | 143 | ||
140 | static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void __percpu **mib) | 144 | /* can be called either with percpu mib (pcpumib != NULL), |
145 | * or shared one (smib != NULL) | ||
146 | */ | ||
147 | static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void __percpu **pcpumib, | ||
148 | atomic_long_t *smib) | ||
141 | { | 149 | { |
142 | char name[32]; | 150 | char name[32]; |
143 | int i; | 151 | int i; |
@@ -154,14 +162,14 @@ static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void __percpu **mib) | |||
154 | snprintf(name, sizeof(name), "Icmp6%s%s", | 162 | snprintf(name, sizeof(name), "Icmp6%s%s", |
155 | i & 0x100 ? "Out" : "In", p); | 163 | i & 0x100 ? "Out" : "In", p); |
156 | seq_printf(seq, "%-32s\t%lu\n", name, | 164 | seq_printf(seq, "%-32s\t%lu\n", name, |
157 | snmp_fold_field(mib, i)); | 165 | pcpumib ? snmp_fold_field(pcpumib, i) : atomic_long_read(smib + i)); |
158 | } | 166 | } |
159 | 167 | ||
160 | /* print by number (nonzero only) - ICMPMsgStat format */ | 168 | /* print by number (nonzero only) - ICMPMsgStat format */ |
161 | for (i = 0; i < ICMP6MSG_MIB_MAX; i++) { | 169 | for (i = 0; i < ICMP6MSG_MIB_MAX; i++) { |
162 | unsigned long val; | 170 | unsigned long val; |
163 | 171 | ||
164 | val = snmp_fold_field(mib, i); | 172 | val = pcpumib ? snmp_fold_field(pcpumib, i) : atomic_long_read(smib + i); |
165 | if (!val) | 173 | if (!val) |
166 | continue; | 174 | continue; |
167 | snprintf(name, sizeof(name), "Icmp6%sType%u", | 175 | snprintf(name, sizeof(name), "Icmp6%sType%u", |
@@ -170,14 +178,22 @@ static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void __percpu **mib) | |||
170 | } | 178 | } |
171 | } | 179 | } |
172 | 180 | ||
173 | static void snmp6_seq_show_item(struct seq_file *seq, void __percpu **mib, | 181 | /* can be called either with percpu mib (pcpumib != NULL), |
182 | * or shared one (smib != NULL) | ||
183 | */ | ||
184 | static void snmp6_seq_show_item(struct seq_file *seq, void __percpu **pcpumib, | ||
185 | atomic_long_t *smib, | ||
174 | const struct snmp_mib *itemlist) | 186 | const struct snmp_mib *itemlist) |
175 | { | 187 | { |
176 | int i; | 188 | int i; |
189 | unsigned long val; | ||
177 | 190 | ||
178 | for (i = 0; itemlist[i].name; i++) | 191 | for (i = 0; itemlist[i].name; i++) { |
179 | seq_printf(seq, "%-32s\t%lu\n", itemlist[i].name, | 192 | val = pcpumib ? |
180 | snmp_fold_field(mib, itemlist[i].entry)); | 193 | snmp_fold_field(pcpumib, itemlist[i].entry) : |
194 | atomic_long_read(smib + itemlist[i].entry); | ||
195 | seq_printf(seq, "%-32s\t%lu\n", itemlist[i].name, val); | ||
196 | } | ||
181 | } | 197 | } |
182 | 198 | ||
183 | static void snmp6_seq_show_item64(struct seq_file *seq, void __percpu **mib, | 199 | static void snmp6_seq_show_item64(struct seq_file *seq, void __percpu **mib, |
@@ -197,13 +213,13 @@ static int snmp6_seq_show(struct seq_file *seq, void *v) | |||
197 | snmp6_seq_show_item64(seq, (void __percpu **)net->mib.ipv6_statistics, | 213 | snmp6_seq_show_item64(seq, (void __percpu **)net->mib.ipv6_statistics, |
198 | snmp6_ipstats_list, offsetof(struct ipstats_mib, syncp)); | 214 | snmp6_ipstats_list, offsetof(struct ipstats_mib, syncp)); |
199 | snmp6_seq_show_item(seq, (void __percpu **)net->mib.icmpv6_statistics, | 215 | snmp6_seq_show_item(seq, (void __percpu **)net->mib.icmpv6_statistics, |
200 | snmp6_icmp6_list); | 216 | NULL, snmp6_icmp6_list); |
201 | snmp6_seq_show_icmpv6msg(seq, | 217 | snmp6_seq_show_icmpv6msg(seq, |
202 | (void __percpu **)net->mib.icmpv6msg_statistics); | 218 | (void __percpu **)net->mib.icmpv6msg_statistics, NULL); |
203 | snmp6_seq_show_item(seq, (void __percpu **)net->mib.udp_stats_in6, | 219 | snmp6_seq_show_item(seq, (void __percpu **)net->mib.udp_stats_in6, |
204 | snmp6_udp6_list); | 220 | NULL, snmp6_udp6_list); |
205 | snmp6_seq_show_item(seq, (void __percpu **)net->mib.udplite_stats_in6, | 221 | snmp6_seq_show_item(seq, (void __percpu **)net->mib.udplite_stats_in6, |
206 | snmp6_udplite6_list); | 222 | NULL, snmp6_udplite6_list); |
207 | return 0; | 223 | return 0; |
208 | } | 224 | } |
209 | 225 | ||
@@ -225,11 +241,11 @@ static int snmp6_dev_seq_show(struct seq_file *seq, void *v) | |||
225 | struct inet6_dev *idev = (struct inet6_dev *)seq->private; | 241 | struct inet6_dev *idev = (struct inet6_dev *)seq->private; |
226 | 242 | ||
227 | seq_printf(seq, "%-32s\t%u\n", "ifIndex", idev->dev->ifindex); | 243 | seq_printf(seq, "%-32s\t%u\n", "ifIndex", idev->dev->ifindex); |
228 | snmp6_seq_show_item(seq, (void __percpu **)idev->stats.ipv6, | 244 | snmp6_seq_show_item(seq, (void __percpu **)idev->stats.ipv6, NULL, |
229 | snmp6_ipstats_list); | 245 | snmp6_ipstats_list); |
230 | snmp6_seq_show_item(seq, (void __percpu **)idev->stats.icmpv6, | 246 | snmp6_seq_show_item(seq, NULL, idev->stats.icmpv6dev->mibs, |
231 | snmp6_icmp6_list); | 247 | snmp6_icmp6_list); |
232 | snmp6_seq_show_icmpv6msg(seq, (void __percpu **)idev->stats.icmpv6msg); | 248 | snmp6_seq_show_icmpv6msg(seq, NULL, idev->stats.icmpv6msgdev->mibs); |
233 | return 0; | 249 | return 0; |
234 | } | 250 | } |
235 | 251 | ||
diff --git a/net/ipv6/protocol.c b/net/ipv6/protocol.c index 1fa3468f0f32..9a7978fdc02a 100644 --- a/net/ipv6/protocol.c +++ b/net/ipv6/protocol.c | |||
@@ -25,28 +25,15 @@ | |||
25 | #include <linux/spinlock.h> | 25 | #include <linux/spinlock.h> |
26 | #include <net/protocol.h> | 26 | #include <net/protocol.h> |
27 | 27 | ||
28 | const struct inet6_protocol *inet6_protos[MAX_INET_PROTOS]; | 28 | const struct inet6_protocol __rcu *inet6_protos[MAX_INET_PROTOS] __read_mostly; |
29 | static DEFINE_SPINLOCK(inet6_proto_lock); | ||
30 | |||
31 | 29 | ||
32 | int inet6_add_protocol(const struct inet6_protocol *prot, unsigned char protocol) | 30 | int inet6_add_protocol(const struct inet6_protocol *prot, unsigned char protocol) |
33 | { | 31 | { |
34 | int ret, hash = protocol & (MAX_INET_PROTOS - 1); | 32 | int hash = protocol & (MAX_INET_PROTOS - 1); |
35 | |||
36 | spin_lock_bh(&inet6_proto_lock); | ||
37 | |||
38 | if (inet6_protos[hash]) { | ||
39 | ret = -1; | ||
40 | } else { | ||
41 | inet6_protos[hash] = prot; | ||
42 | ret = 0; | ||
43 | } | ||
44 | |||
45 | spin_unlock_bh(&inet6_proto_lock); | ||
46 | 33 | ||
47 | return ret; | 34 | return !cmpxchg((const struct inet6_protocol **)&inet6_protos[hash], |
35 | NULL, prot) ? 0 : -1; | ||
48 | } | 36 | } |
49 | |||
50 | EXPORT_SYMBOL(inet6_add_protocol); | 37 | EXPORT_SYMBOL(inet6_add_protocol); |
51 | 38 | ||
52 | /* | 39 | /* |
@@ -57,20 +44,11 @@ int inet6_del_protocol(const struct inet6_protocol *prot, unsigned char protocol | |||
57 | { | 44 | { |
58 | int ret, hash = protocol & (MAX_INET_PROTOS - 1); | 45 | int ret, hash = protocol & (MAX_INET_PROTOS - 1); |
59 | 46 | ||
60 | spin_lock_bh(&inet6_proto_lock); | 47 | ret = (cmpxchg((const struct inet6_protocol **)&inet6_protos[hash], |
61 | 48 | prot, NULL) == prot) ? 0 : -1; | |
62 | if (inet6_protos[hash] != prot) { | ||
63 | ret = -1; | ||
64 | } else { | ||
65 | inet6_protos[hash] = NULL; | ||
66 | ret = 0; | ||
67 | } | ||
68 | |||
69 | spin_unlock_bh(&inet6_proto_lock); | ||
70 | 49 | ||
71 | synchronize_net(); | 50 | synchronize_net(); |
72 | 51 | ||
73 | return ret; | 52 | return ret; |
74 | } | 53 | } |
75 | |||
76 | EXPORT_SYMBOL(inet6_del_protocol); | 54 | EXPORT_SYMBOL(inet6_del_protocol); |
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index e677937a07fc..cc7313b8f7ea 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/netfilter.h> | 31 | #include <linux/netfilter.h> |
32 | #include <linux/netfilter_ipv6.h> | 32 | #include <linux/netfilter_ipv6.h> |
33 | #include <linux/skbuff.h> | 33 | #include <linux/skbuff.h> |
34 | #include <linux/compat.h> | ||
34 | #include <asm/uaccess.h> | 35 | #include <asm/uaccess.h> |
35 | #include <asm/ioctls.h> | 36 | #include <asm/ioctls.h> |
36 | 37 | ||
@@ -66,8 +67,8 @@ static struct raw_hashinfo raw_v6_hashinfo = { | |||
66 | }; | 67 | }; |
67 | 68 | ||
68 | static struct sock *__raw_v6_lookup(struct net *net, struct sock *sk, | 69 | static struct sock *__raw_v6_lookup(struct net *net, struct sock *sk, |
69 | unsigned short num, struct in6_addr *loc_addr, | 70 | unsigned short num, const struct in6_addr *loc_addr, |
70 | struct in6_addr *rmt_addr, int dif) | 71 | const struct in6_addr *rmt_addr, int dif) |
71 | { | 72 | { |
72 | struct hlist_node *node; | 73 | struct hlist_node *node; |
73 | int is_multicast = ipv6_addr_is_multicast(loc_addr); | 74 | int is_multicast = ipv6_addr_is_multicast(loc_addr); |
@@ -123,18 +124,18 @@ static __inline__ int icmpv6_filter(struct sock *sk, struct sk_buff *skb) | |||
123 | } | 124 | } |
124 | 125 | ||
125 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 126 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) |
126 | static int (*mh_filter)(struct sock *sock, struct sk_buff *skb); | 127 | typedef int mh_filter_t(struct sock *sock, struct sk_buff *skb); |
127 | 128 | ||
128 | int rawv6_mh_filter_register(int (*filter)(struct sock *sock, | 129 | static mh_filter_t __rcu *mh_filter __read_mostly; |
129 | struct sk_buff *skb)) | 130 | |
131 | int rawv6_mh_filter_register(mh_filter_t filter) | ||
130 | { | 132 | { |
131 | rcu_assign_pointer(mh_filter, filter); | 133 | rcu_assign_pointer(mh_filter, filter); |
132 | return 0; | 134 | return 0; |
133 | } | 135 | } |
134 | EXPORT_SYMBOL(rawv6_mh_filter_register); | 136 | EXPORT_SYMBOL(rawv6_mh_filter_register); |
135 | 137 | ||
136 | int rawv6_mh_filter_unregister(int (*filter)(struct sock *sock, | 138 | int rawv6_mh_filter_unregister(mh_filter_t filter) |
137 | struct sk_buff *skb)) | ||
138 | { | 139 | { |
139 | rcu_assign_pointer(mh_filter, NULL); | 140 | rcu_assign_pointer(mh_filter, NULL); |
140 | synchronize_rcu(); | 141 | synchronize_rcu(); |
@@ -153,8 +154,8 @@ EXPORT_SYMBOL(rawv6_mh_filter_unregister); | |||
153 | */ | 154 | */ |
154 | static int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) | 155 | static int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) |
155 | { | 156 | { |
156 | struct in6_addr *saddr; | 157 | const struct in6_addr *saddr; |
157 | struct in6_addr *daddr; | 158 | const struct in6_addr *daddr; |
158 | struct sock *sk; | 159 | struct sock *sk; |
159 | int delivered = 0; | 160 | int delivered = 0; |
160 | __u8 hash; | 161 | __u8 hash; |
@@ -192,10 +193,10 @@ static int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) | |||
192 | * policy is placed in rawv6_rcv() because it is | 193 | * policy is placed in rawv6_rcv() because it is |
193 | * required for each socket. | 194 | * required for each socket. |
194 | */ | 195 | */ |
195 | int (*filter)(struct sock *sock, struct sk_buff *skb); | 196 | mh_filter_t *filter; |
196 | 197 | ||
197 | filter = rcu_dereference(mh_filter); | 198 | filter = rcu_dereference(mh_filter); |
198 | filtered = filter ? filter(sk, skb) : 0; | 199 | filtered = filter ? (*filter)(sk, skb) : 0; |
199 | break; | 200 | break; |
200 | } | 201 | } |
201 | #endif | 202 | #endif |
@@ -347,7 +348,7 @@ void raw6_icmp_error(struct sk_buff *skb, int nexthdr, | |||
347 | { | 348 | { |
348 | struct sock *sk; | 349 | struct sock *sk; |
349 | int hash; | 350 | int hash; |
350 | struct in6_addr *saddr, *daddr; | 351 | const struct in6_addr *saddr, *daddr; |
351 | struct net *net; | 352 | struct net *net; |
352 | 353 | ||
353 | hash = nexthdr & (RAW_HTABLE_SIZE - 1); | 354 | hash = nexthdr & (RAW_HTABLE_SIZE - 1); |
@@ -356,7 +357,7 @@ void raw6_icmp_error(struct sk_buff *skb, int nexthdr, | |||
356 | sk = sk_head(&raw_v6_hashinfo.ht[hash]); | 357 | sk = sk_head(&raw_v6_hashinfo.ht[hash]); |
357 | if (sk != NULL) { | 358 | if (sk != NULL) { |
358 | /* Note: ipv6_hdr(skb) != skb->data */ | 359 | /* Note: ipv6_hdr(skb) != skb->data */ |
359 | struct ipv6hdr *ip6h = (struct ipv6hdr *)skb->data; | 360 | const struct ipv6hdr *ip6h = (const struct ipv6hdr *)skb->data; |
360 | saddr = &ip6h->saddr; | 361 | saddr = &ip6h->saddr; |
361 | daddr = &ip6h->daddr; | 362 | daddr = &ip6h->daddr; |
362 | net = dev_net(skb->dev); | 363 | net = dev_net(skb->dev); |
@@ -373,7 +374,7 @@ void raw6_icmp_error(struct sk_buff *skb, int nexthdr, | |||
373 | 374 | ||
374 | static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb) | 375 | static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb) |
375 | { | 376 | { |
376 | if ((raw6_sk(sk)->checksum || sk->sk_filter) && | 377 | if ((raw6_sk(sk)->checksum || rcu_dereference_raw(sk->sk_filter)) && |
377 | skb_checksum_complete(skb)) { | 378 | skb_checksum_complete(skb)) { |
378 | atomic_inc(&sk->sk_drops); | 379 | atomic_inc(&sk->sk_drops); |
379 | kfree_skb(skb); | 380 | kfree_skb(skb); |
@@ -523,7 +524,7 @@ csum_copy_err: | |||
523 | goto out; | 524 | goto out; |
524 | } | 525 | } |
525 | 526 | ||
526 | static int rawv6_push_pending_frames(struct sock *sk, struct flowi *fl, | 527 | static int rawv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6, |
527 | struct raw6_sock *rp) | 528 | struct raw6_sock *rp) |
528 | { | 529 | { |
529 | struct sk_buff *skb; | 530 | struct sk_buff *skb; |
@@ -541,8 +542,8 @@ static int rawv6_push_pending_frames(struct sock *sk, struct flowi *fl, | |||
541 | goto out; | 542 | goto out; |
542 | 543 | ||
543 | offset = rp->offset; | 544 | offset = rp->offset; |
544 | total_len = inet_sk(sk)->cork.length - (skb_network_header(skb) - | 545 | total_len = inet_sk(sk)->cork.base.length - (skb_network_header(skb) - |
545 | skb->data); | 546 | skb->data); |
546 | if (offset >= total_len - 1) { | 547 | if (offset >= total_len - 1) { |
547 | err = -EINVAL; | 548 | err = -EINVAL; |
548 | ip6_flush_pending_frames(sk); | 549 | ip6_flush_pending_frames(sk); |
@@ -585,11 +586,10 @@ static int rawv6_push_pending_frames(struct sock *sk, struct flowi *fl, | |||
585 | if (unlikely(csum)) | 586 | if (unlikely(csum)) |
586 | tmp_csum = csum_sub(tmp_csum, csum_unfold(csum)); | 587 | tmp_csum = csum_sub(tmp_csum, csum_unfold(csum)); |
587 | 588 | ||
588 | csum = csum_ipv6_magic(&fl->fl6_src, | 589 | csum = csum_ipv6_magic(&fl6->saddr, &fl6->daddr, |
589 | &fl->fl6_dst, | 590 | total_len, fl6->flowi6_proto, tmp_csum); |
590 | total_len, fl->proto, tmp_csum); | ||
591 | 591 | ||
592 | if (csum == 0 && fl->proto == IPPROTO_UDP) | 592 | if (csum == 0 && fl6->flowi6_proto == IPPROTO_UDP) |
593 | csum = CSUM_MANGLED_0; | 593 | csum = CSUM_MANGLED_0; |
594 | 594 | ||
595 | if (skb_store_bits(skb, offset, &csum, 2)) | 595 | if (skb_store_bits(skb, offset, &csum, 2)) |
@@ -602,7 +602,7 @@ out: | |||
602 | } | 602 | } |
603 | 603 | ||
604 | static int rawv6_send_hdrinc(struct sock *sk, void *from, int length, | 604 | static int rawv6_send_hdrinc(struct sock *sk, void *from, int length, |
605 | struct flowi *fl, struct dst_entry **dstp, | 605 | struct flowi6 *fl6, struct dst_entry **dstp, |
606 | unsigned int flags) | 606 | unsigned int flags) |
607 | { | 607 | { |
608 | struct ipv6_pinfo *np = inet6_sk(sk); | 608 | struct ipv6_pinfo *np = inet6_sk(sk); |
@@ -612,7 +612,7 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length, | |||
612 | struct rt6_info *rt = (struct rt6_info *)*dstp; | 612 | struct rt6_info *rt = (struct rt6_info *)*dstp; |
613 | 613 | ||
614 | if (length > rt->dst.dev->mtu) { | 614 | if (length > rt->dst.dev->mtu) { |
615 | ipv6_local_error(sk, EMSGSIZE, fl, rt->dst.dev->mtu); | 615 | ipv6_local_error(sk, EMSGSIZE, fl6, rt->dst.dev->mtu); |
616 | return -EMSGSIZE; | 616 | return -EMSGSIZE; |
617 | } | 617 | } |
618 | if (flags&MSG_PROBE) | 618 | if (flags&MSG_PROBE) |
@@ -661,7 +661,7 @@ error: | |||
661 | return err; | 661 | return err; |
662 | } | 662 | } |
663 | 663 | ||
664 | static int rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | 664 | static int rawv6_probe_proto_opt(struct flowi6 *fl6, struct msghdr *msg) |
665 | { | 665 | { |
666 | struct iovec *iov; | 666 | struct iovec *iov; |
667 | u8 __user *type = NULL; | 667 | u8 __user *type = NULL; |
@@ -678,7 +678,7 @@ static int rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | |||
678 | if (!iov) | 678 | if (!iov) |
679 | continue; | 679 | continue; |
680 | 680 | ||
681 | switch (fl->proto) { | 681 | switch (fl6->flowi6_proto) { |
682 | case IPPROTO_ICMPV6: | 682 | case IPPROTO_ICMPV6: |
683 | /* check if one-byte field is readable or not. */ | 683 | /* check if one-byte field is readable or not. */ |
684 | if (iov->iov_base && iov->iov_len < 1) | 684 | if (iov->iov_base && iov->iov_len < 1) |
@@ -693,8 +693,8 @@ static int rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | |||
693 | code = iov->iov_base; | 693 | code = iov->iov_base; |
694 | 694 | ||
695 | if (type && code) { | 695 | if (type && code) { |
696 | if (get_user(fl->fl_icmp_type, type) || | 696 | if (get_user(fl6->fl6_icmp_type, type) || |
697 | get_user(fl->fl_icmp_code, code)) | 697 | get_user(fl6->fl6_icmp_code, code)) |
698 | return -EFAULT; | 698 | return -EFAULT; |
699 | probed = 1; | 699 | probed = 1; |
700 | } | 700 | } |
@@ -705,7 +705,7 @@ static int rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | |||
705 | /* check if type field is readable or not. */ | 705 | /* check if type field is readable or not. */ |
706 | if (iov->iov_len > 2 - len) { | 706 | if (iov->iov_len > 2 - len) { |
707 | u8 __user *p = iov->iov_base; | 707 | u8 __user *p = iov->iov_base; |
708 | if (get_user(fl->fl_mh_type, &p[2 - len])) | 708 | if (get_user(fl6->fl6_mh_type, &p[2 - len])) |
709 | return -EFAULT; | 709 | return -EFAULT; |
710 | probed = 1; | 710 | probed = 1; |
711 | } else | 711 | } else |
@@ -734,7 +734,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
734 | struct ipv6_txoptions *opt = NULL; | 734 | struct ipv6_txoptions *opt = NULL; |
735 | struct ip6_flowlabel *flowlabel = NULL; | 735 | struct ip6_flowlabel *flowlabel = NULL; |
736 | struct dst_entry *dst = NULL; | 736 | struct dst_entry *dst = NULL; |
737 | struct flowi fl; | 737 | struct flowi6 fl6; |
738 | int addr_len = msg->msg_namelen; | 738 | int addr_len = msg->msg_namelen; |
739 | int hlimit = -1; | 739 | int hlimit = -1; |
740 | int tclass = -1; | 740 | int tclass = -1; |
@@ -755,16 +755,16 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
755 | /* | 755 | /* |
756 | * Get and verify the address. | 756 | * Get and verify the address. |
757 | */ | 757 | */ |
758 | memset(&fl, 0, sizeof(fl)); | 758 | memset(&fl6, 0, sizeof(fl6)); |
759 | 759 | ||
760 | fl.mark = sk->sk_mark; | 760 | fl6.flowi6_mark = sk->sk_mark; |
761 | 761 | ||
762 | if (sin6) { | 762 | if (sin6) { |
763 | if (addr_len < SIN6_LEN_RFC2133) | 763 | if (addr_len < SIN6_LEN_RFC2133) |
764 | return -EINVAL; | 764 | return -EINVAL; |
765 | 765 | ||
766 | if (sin6->sin6_family && sin6->sin6_family != AF_INET6) | 766 | if (sin6->sin6_family && sin6->sin6_family != AF_INET6) |
767 | return(-EAFNOSUPPORT); | 767 | return -EAFNOSUPPORT; |
768 | 768 | ||
769 | /* port is the proto value [0..255] carried in nexthdr */ | 769 | /* port is the proto value [0..255] carried in nexthdr */ |
770 | proto = ntohs(sin6->sin6_port); | 770 | proto = ntohs(sin6->sin6_port); |
@@ -772,16 +772,16 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
772 | if (!proto) | 772 | if (!proto) |
773 | proto = inet->inet_num; | 773 | proto = inet->inet_num; |
774 | else if (proto != inet->inet_num) | 774 | else if (proto != inet->inet_num) |
775 | return(-EINVAL); | 775 | return -EINVAL; |
776 | 776 | ||
777 | if (proto > 255) | 777 | if (proto > 255) |
778 | return(-EINVAL); | 778 | return -EINVAL; |
779 | 779 | ||
780 | daddr = &sin6->sin6_addr; | 780 | daddr = &sin6->sin6_addr; |
781 | if (np->sndflow) { | 781 | if (np->sndflow) { |
782 | fl.fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK; | 782 | fl6.flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK; |
783 | if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) { | 783 | if (fl6.flowlabel&IPV6_FLOWLABEL_MASK) { |
784 | flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel); | 784 | flowlabel = fl6_sock_lookup(sk, fl6.flowlabel); |
785 | if (flowlabel == NULL) | 785 | if (flowlabel == NULL) |
786 | return -EINVAL; | 786 | return -EINVAL; |
787 | daddr = &flowlabel->dst; | 787 | daddr = &flowlabel->dst; |
@@ -799,32 +799,32 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
799 | if (addr_len >= sizeof(struct sockaddr_in6) && | 799 | if (addr_len >= sizeof(struct sockaddr_in6) && |
800 | sin6->sin6_scope_id && | 800 | sin6->sin6_scope_id && |
801 | ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL) | 801 | ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL) |
802 | fl.oif = sin6->sin6_scope_id; | 802 | fl6.flowi6_oif = sin6->sin6_scope_id; |
803 | } else { | 803 | } else { |
804 | if (sk->sk_state != TCP_ESTABLISHED) | 804 | if (sk->sk_state != TCP_ESTABLISHED) |
805 | return -EDESTADDRREQ; | 805 | return -EDESTADDRREQ; |
806 | 806 | ||
807 | proto = inet->inet_num; | 807 | proto = inet->inet_num; |
808 | daddr = &np->daddr; | 808 | daddr = &np->daddr; |
809 | fl.fl6_flowlabel = np->flow_label; | 809 | fl6.flowlabel = np->flow_label; |
810 | } | 810 | } |
811 | 811 | ||
812 | if (fl.oif == 0) | 812 | if (fl6.flowi6_oif == 0) |
813 | fl.oif = sk->sk_bound_dev_if; | 813 | fl6.flowi6_oif = sk->sk_bound_dev_if; |
814 | 814 | ||
815 | if (msg->msg_controllen) { | 815 | if (msg->msg_controllen) { |
816 | opt = &opt_space; | 816 | opt = &opt_space; |
817 | memset(opt, 0, sizeof(struct ipv6_txoptions)); | 817 | memset(opt, 0, sizeof(struct ipv6_txoptions)); |
818 | opt->tot_len = sizeof(struct ipv6_txoptions); | 818 | opt->tot_len = sizeof(struct ipv6_txoptions); |
819 | 819 | ||
820 | err = datagram_send_ctl(sock_net(sk), msg, &fl, opt, &hlimit, | 820 | err = datagram_send_ctl(sock_net(sk), msg, &fl6, opt, &hlimit, |
821 | &tclass, &dontfrag); | 821 | &tclass, &dontfrag); |
822 | if (err < 0) { | 822 | if (err < 0) { |
823 | fl6_sock_release(flowlabel); | 823 | fl6_sock_release(flowlabel); |
824 | return err; | 824 | return err; |
825 | } | 825 | } |
826 | if ((fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) { | 826 | if ((fl6.flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) { |
827 | flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel); | 827 | flowlabel = fl6_sock_lookup(sk, fl6.flowlabel); |
828 | if (flowlabel == NULL) | 828 | if (flowlabel == NULL) |
829 | return -EINVAL; | 829 | return -EINVAL; |
830 | } | 830 | } |
@@ -837,40 +837,31 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
837 | opt = fl6_merge_options(&opt_space, flowlabel, opt); | 837 | opt = fl6_merge_options(&opt_space, flowlabel, opt); |
838 | opt = ipv6_fixup_options(&opt_space, opt); | 838 | opt = ipv6_fixup_options(&opt_space, opt); |
839 | 839 | ||
840 | fl.proto = proto; | 840 | fl6.flowi6_proto = proto; |
841 | err = rawv6_probe_proto_opt(&fl, msg); | 841 | err = rawv6_probe_proto_opt(&fl6, msg); |
842 | if (err) | 842 | if (err) |
843 | goto out; | 843 | goto out; |
844 | 844 | ||
845 | if (!ipv6_addr_any(daddr)) | 845 | if (!ipv6_addr_any(daddr)) |
846 | ipv6_addr_copy(&fl.fl6_dst, daddr); | 846 | ipv6_addr_copy(&fl6.daddr, daddr); |
847 | else | 847 | else |
848 | fl.fl6_dst.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */ | 848 | fl6.daddr.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */ |
849 | if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr)) | 849 | if (ipv6_addr_any(&fl6.saddr) && !ipv6_addr_any(&np->saddr)) |
850 | ipv6_addr_copy(&fl.fl6_src, &np->saddr); | 850 | ipv6_addr_copy(&fl6.saddr, &np->saddr); |
851 | 851 | ||
852 | final_p = fl6_update_dst(&fl, opt, &final); | 852 | final_p = fl6_update_dst(&fl6, opt, &final); |
853 | 853 | ||
854 | if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) | 854 | if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) |
855 | fl.oif = np->mcast_oif; | 855 | fl6.flowi6_oif = np->mcast_oif; |
856 | security_sk_classify_flow(sk, &fl); | 856 | security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); |
857 | 857 | ||
858 | err = ip6_dst_lookup(sk, &dst, &fl); | 858 | dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true); |
859 | if (err) | 859 | if (IS_ERR(dst)) { |
860 | err = PTR_ERR(dst); | ||
860 | goto out; | 861 | goto out; |
861 | if (final_p) | ||
862 | ipv6_addr_copy(&fl.fl6_dst, final_p); | ||
863 | |||
864 | err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT); | ||
865 | if (err < 0) { | ||
866 | if (err == -EREMOTE) | ||
867 | err = ip6_dst_blackhole(sk, &dst, &fl); | ||
868 | if (err < 0) | ||
869 | goto out; | ||
870 | } | 862 | } |
871 | |||
872 | if (hlimit < 0) { | 863 | if (hlimit < 0) { |
873 | if (ipv6_addr_is_multicast(&fl.fl6_dst)) | 864 | if (ipv6_addr_is_multicast(&fl6.daddr)) |
874 | hlimit = np->mcast_hops; | 865 | hlimit = np->mcast_hops; |
875 | else | 866 | else |
876 | hlimit = np->hop_limit; | 867 | hlimit = np->hop_limit; |
@@ -889,17 +880,17 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
889 | 880 | ||
890 | back_from_confirm: | 881 | back_from_confirm: |
891 | if (inet->hdrincl) | 882 | if (inet->hdrincl) |
892 | err = rawv6_send_hdrinc(sk, msg->msg_iov, len, &fl, &dst, msg->msg_flags); | 883 | err = rawv6_send_hdrinc(sk, msg->msg_iov, len, &fl6, &dst, msg->msg_flags); |
893 | else { | 884 | else { |
894 | lock_sock(sk); | 885 | lock_sock(sk); |
895 | err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, | 886 | err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, |
896 | len, 0, hlimit, tclass, opt, &fl, (struct rt6_info*)dst, | 887 | len, 0, hlimit, tclass, opt, &fl6, (struct rt6_info*)dst, |
897 | msg->msg_flags, dontfrag); | 888 | msg->msg_flags, dontfrag); |
898 | 889 | ||
899 | if (err) | 890 | if (err) |
900 | ip6_flush_pending_frames(sk); | 891 | ip6_flush_pending_frames(sk); |
901 | else if (!(msg->msg_flags & MSG_MORE)) | 892 | else if (!(msg->msg_flags & MSG_MORE)) |
902 | err = rawv6_push_pending_frames(sk, &fl, rp); | 893 | err = rawv6_push_pending_frames(sk, &fl6, rp); |
903 | release_sock(sk); | 894 | release_sock(sk); |
904 | } | 895 | } |
905 | done: | 896 | done: |
@@ -985,7 +976,7 @@ static int do_rawv6_setsockopt(struct sock *sk, int level, int optname, | |||
985 | /* You may get strange result with a positive odd offset; | 976 | /* You may get strange result with a positive odd offset; |
986 | RFC2292bis agrees with me. */ | 977 | RFC2292bis agrees with me. */ |
987 | if (val > 0 && (val&1)) | 978 | if (val > 0 && (val&1)) |
988 | return(-EINVAL); | 979 | return -EINVAL; |
989 | if (val < 0) { | 980 | if (val < 0) { |
990 | rp->checksum = 0; | 981 | rp->checksum = 0; |
991 | } else { | 982 | } else { |
@@ -997,7 +988,7 @@ static int do_rawv6_setsockopt(struct sock *sk, int level, int optname, | |||
997 | break; | 988 | break; |
998 | 989 | ||
999 | default: | 990 | default: |
1000 | return(-ENOPROTOOPT); | 991 | return -ENOPROTOOPT; |
1001 | } | 992 | } |
1002 | } | 993 | } |
1003 | 994 | ||
@@ -1157,6 +1148,23 @@ static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg) | |||
1157 | } | 1148 | } |
1158 | } | 1149 | } |
1159 | 1150 | ||
1151 | #ifdef CONFIG_COMPAT | ||
1152 | static int compat_rawv6_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg) | ||
1153 | { | ||
1154 | switch (cmd) { | ||
1155 | case SIOCOUTQ: | ||
1156 | case SIOCINQ: | ||
1157 | return -ENOIOCTLCMD; | ||
1158 | default: | ||
1159 | #ifdef CONFIG_IPV6_MROUTE | ||
1160 | return ip6mr_compat_ioctl(sk, cmd, compat_ptr(arg)); | ||
1161 | #else | ||
1162 | return -ENOIOCTLCMD; | ||
1163 | #endif | ||
1164 | } | ||
1165 | } | ||
1166 | #endif | ||
1167 | |||
1160 | static void rawv6_close(struct sock *sk, long timeout) | 1168 | static void rawv6_close(struct sock *sk, long timeout) |
1161 | { | 1169 | { |
1162 | if (inet_sk(sk)->inet_num == IPPROTO_RAW) | 1170 | if (inet_sk(sk)->inet_num == IPPROTO_RAW) |
@@ -1190,7 +1198,7 @@ static int rawv6_init_sk(struct sock *sk) | |||
1190 | default: | 1198 | default: |
1191 | break; | 1199 | break; |
1192 | } | 1200 | } |
1193 | return(0); | 1201 | return 0; |
1194 | } | 1202 | } |
1195 | 1203 | ||
1196 | struct proto rawv6_prot = { | 1204 | struct proto rawv6_prot = { |
@@ -1215,6 +1223,7 @@ struct proto rawv6_prot = { | |||
1215 | #ifdef CONFIG_COMPAT | 1223 | #ifdef CONFIG_COMPAT |
1216 | .compat_setsockopt = compat_rawv6_setsockopt, | 1224 | .compat_setsockopt = compat_rawv6_setsockopt, |
1217 | .compat_getsockopt = compat_rawv6_getsockopt, | 1225 | .compat_getsockopt = compat_rawv6_getsockopt, |
1226 | .compat_ioctl = compat_rawv6_ioctl, | ||
1218 | #endif | 1227 | #endif |
1219 | }; | 1228 | }; |
1220 | 1229 | ||
@@ -1222,7 +1231,7 @@ struct proto rawv6_prot = { | |||
1222 | static void raw6_sock_seq_show(struct seq_file *seq, struct sock *sp, int i) | 1231 | static void raw6_sock_seq_show(struct seq_file *seq, struct sock *sp, int i) |
1223 | { | 1232 | { |
1224 | struct ipv6_pinfo *np = inet6_sk(sp); | 1233 | struct ipv6_pinfo *np = inet6_sk(sp); |
1225 | struct in6_addr *dest, *src; | 1234 | const struct in6_addr *dest, *src; |
1226 | __u16 destp, srcp; | 1235 | __u16 destp, srcp; |
1227 | 1236 | ||
1228 | dest = &np->daddr; | 1237 | dest = &np->daddr; |
@@ -1231,7 +1240,7 @@ static void raw6_sock_seq_show(struct seq_file *seq, struct sock *sp, int i) | |||
1231 | srcp = inet_sk(sp)->inet_num; | 1240 | srcp = inet_sk(sp)->inet_num; |
1232 | seq_printf(seq, | 1241 | seq_printf(seq, |
1233 | "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " | 1242 | "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " |
1234 | "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n", | 1243 | "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %pK %d\n", |
1235 | i, | 1244 | i, |
1236 | src->s6_addr32[0], src->s6_addr32[1], | 1245 | src->s6_addr32[0], src->s6_addr32[1], |
1237 | src->s6_addr32[2], src->s6_addr32[3], srcp, | 1246 | src->s6_addr32[2], src->s6_addr32[3], srcp, |
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 64cfef1b0a4c..7b954e2539d0 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c | |||
@@ -104,26 +104,22 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, | |||
104 | unsigned int inet6_hash_frag(__be32 id, const struct in6_addr *saddr, | 104 | unsigned int inet6_hash_frag(__be32 id, const struct in6_addr *saddr, |
105 | const struct in6_addr *daddr, u32 rnd) | 105 | const struct in6_addr *daddr, u32 rnd) |
106 | { | 106 | { |
107 | u32 a, b, c; | 107 | u32 c; |
108 | 108 | ||
109 | a = (__force u32)saddr->s6_addr32[0]; | 109 | c = jhash_3words((__force u32)saddr->s6_addr32[0], |
110 | b = (__force u32)saddr->s6_addr32[1]; | 110 | (__force u32)saddr->s6_addr32[1], |
111 | c = (__force u32)saddr->s6_addr32[2]; | 111 | (__force u32)saddr->s6_addr32[2], |
112 | rnd); | ||
112 | 113 | ||
113 | a += JHASH_GOLDEN_RATIO; | 114 | c = jhash_3words((__force u32)saddr->s6_addr32[3], |
114 | b += JHASH_GOLDEN_RATIO; | 115 | (__force u32)daddr->s6_addr32[0], |
115 | c += rnd; | 116 | (__force u32)daddr->s6_addr32[1], |
116 | __jhash_mix(a, b, c); | 117 | c); |
117 | 118 | ||
118 | a += (__force u32)saddr->s6_addr32[3]; | 119 | c = jhash_3words((__force u32)daddr->s6_addr32[2], |
119 | b += (__force u32)daddr->s6_addr32[0]; | 120 | (__force u32)daddr->s6_addr32[3], |
120 | c += (__force u32)daddr->s6_addr32[1]; | 121 | (__force u32)id, |
121 | __jhash_mix(a, b, c); | 122 | c); |
122 | |||
123 | a += (__force u32)daddr->s6_addr32[2]; | ||
124 | b += (__force u32)daddr->s6_addr32[3]; | ||
125 | c += (__force u32)id; | ||
126 | __jhash_mix(a, b, c); | ||
127 | 123 | ||
128 | return c & (INETFRAGS_HASHSZ - 1); | 124 | return c & (INETFRAGS_HASHSZ - 1); |
129 | } | 125 | } |
@@ -228,7 +224,7 @@ out: | |||
228 | } | 224 | } |
229 | 225 | ||
230 | static __inline__ struct frag_queue * | 226 | static __inline__ struct frag_queue * |
231 | fq_find(struct net *net, __be32 id, struct in6_addr *src, struct in6_addr *dst) | 227 | fq_find(struct net *net, __be32 id, const struct in6_addr *src, const struct in6_addr *dst) |
232 | { | 228 | { |
233 | struct inet_frag_queue *q; | 229 | struct inet_frag_queue *q; |
234 | struct ip6_create_arg arg; | 230 | struct ip6_create_arg arg; |
@@ -349,7 +345,7 @@ found: | |||
349 | 345 | ||
350 | /* Check for overlap with preceding fragment. */ | 346 | /* Check for overlap with preceding fragment. */ |
351 | if (prev && | 347 | if (prev && |
352 | (FRAG6_CB(prev)->offset + prev->len) - offset > 0) | 348 | (FRAG6_CB(prev)->offset + prev->len) > offset) |
353 | goto discard_fq; | 349 | goto discard_fq; |
354 | 350 | ||
355 | /* Look for overlap with succeeding segment. */ | 351 | /* Look for overlap with succeeding segment. */ |
@@ -458,7 +454,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, | |||
458 | /* If the first fragment is fragmented itself, we split | 454 | /* If the first fragment is fragmented itself, we split |
459 | * it to two chunks: the first with data and paged part | 455 | * it to two chunks: the first with data and paged part |
460 | * and the second, holding only fragments. */ | 456 | * and the second, holding only fragments. */ |
461 | if (skb_has_frags(head)) { | 457 | if (skb_has_frag_list(head)) { |
462 | struct sk_buff *clone; | 458 | struct sk_buff *clone; |
463 | int i, plen = 0; | 459 | int i, plen = 0; |
464 | 460 | ||
@@ -539,7 +535,7 @@ static int ipv6_frag_rcv(struct sk_buff *skb) | |||
539 | { | 535 | { |
540 | struct frag_hdr *fhdr; | 536 | struct frag_hdr *fhdr; |
541 | struct frag_queue *fq; | 537 | struct frag_queue *fq; |
542 | struct ipv6hdr *hdr = ipv6_hdr(skb); | 538 | const struct ipv6hdr *hdr = ipv6_hdr(skb); |
543 | struct net *net = dev_net(skb_dst(skb)->dev); | 539 | struct net *net = dev_net(skb_dst(skb)->dev); |
544 | 540 | ||
545 | IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMREQDS); | 541 | IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMREQDS); |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index a275c6e1e25c..0ef1f086feb8 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -72,10 +72,10 @@ | |||
72 | #define RT6_TRACE(x...) do { ; } while (0) | 72 | #define RT6_TRACE(x...) do { ; } while (0) |
73 | #endif | 73 | #endif |
74 | 74 | ||
75 | #define CLONE_OFFLINK_ROUTE 0 | ||
76 | |||
77 | static struct rt6_info * ip6_rt_copy(struct rt6_info *ort); | 75 | static struct rt6_info * ip6_rt_copy(struct rt6_info *ort); |
78 | static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie); | 76 | static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie); |
77 | static unsigned int ip6_default_advmss(const struct dst_entry *dst); | ||
78 | static unsigned int ip6_default_mtu(const struct dst_entry *dst); | ||
79 | static struct dst_entry *ip6_negative_advice(struct dst_entry *); | 79 | static struct dst_entry *ip6_negative_advice(struct dst_entry *); |
80 | static void ip6_dst_destroy(struct dst_entry *); | 80 | static void ip6_dst_destroy(struct dst_entry *); |
81 | static void ip6_dst_ifdown(struct dst_entry *, | 81 | static void ip6_dst_ifdown(struct dst_entry *, |
@@ -89,40 +89,89 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu); | |||
89 | 89 | ||
90 | #ifdef CONFIG_IPV6_ROUTE_INFO | 90 | #ifdef CONFIG_IPV6_ROUTE_INFO |
91 | static struct rt6_info *rt6_add_route_info(struct net *net, | 91 | static struct rt6_info *rt6_add_route_info(struct net *net, |
92 | struct in6_addr *prefix, int prefixlen, | 92 | const struct in6_addr *prefix, int prefixlen, |
93 | struct in6_addr *gwaddr, int ifindex, | 93 | const struct in6_addr *gwaddr, int ifindex, |
94 | unsigned pref); | 94 | unsigned pref); |
95 | static struct rt6_info *rt6_get_route_info(struct net *net, | 95 | static struct rt6_info *rt6_get_route_info(struct net *net, |
96 | struct in6_addr *prefix, int prefixlen, | 96 | const struct in6_addr *prefix, int prefixlen, |
97 | struct in6_addr *gwaddr, int ifindex); | 97 | const struct in6_addr *gwaddr, int ifindex); |
98 | #endif | 98 | #endif |
99 | 99 | ||
100 | static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old) | ||
101 | { | ||
102 | struct rt6_info *rt = (struct rt6_info *) dst; | ||
103 | struct inet_peer *peer; | ||
104 | u32 *p = NULL; | ||
105 | |||
106 | if (!rt->rt6i_peer) | ||
107 | rt6_bind_peer(rt, 1); | ||
108 | |||
109 | peer = rt->rt6i_peer; | ||
110 | if (peer) { | ||
111 | u32 *old_p = __DST_METRICS_PTR(old); | ||
112 | unsigned long prev, new; | ||
113 | |||
114 | p = peer->metrics; | ||
115 | if (inet_metrics_new(peer)) | ||
116 | memcpy(p, old_p, sizeof(u32) * RTAX_MAX); | ||
117 | |||
118 | new = (unsigned long) p; | ||
119 | prev = cmpxchg(&dst->_metrics, old, new); | ||
120 | |||
121 | if (prev != old) { | ||
122 | p = __DST_METRICS_PTR(prev); | ||
123 | if (prev & DST_METRICS_READ_ONLY) | ||
124 | p = NULL; | ||
125 | } | ||
126 | } | ||
127 | return p; | ||
128 | } | ||
129 | |||
100 | static struct dst_ops ip6_dst_ops_template = { | 130 | static struct dst_ops ip6_dst_ops_template = { |
101 | .family = AF_INET6, | 131 | .family = AF_INET6, |
102 | .protocol = cpu_to_be16(ETH_P_IPV6), | 132 | .protocol = cpu_to_be16(ETH_P_IPV6), |
103 | .gc = ip6_dst_gc, | 133 | .gc = ip6_dst_gc, |
104 | .gc_thresh = 1024, | 134 | .gc_thresh = 1024, |
105 | .check = ip6_dst_check, | 135 | .check = ip6_dst_check, |
136 | .default_advmss = ip6_default_advmss, | ||
137 | .default_mtu = ip6_default_mtu, | ||
138 | .cow_metrics = ipv6_cow_metrics, | ||
106 | .destroy = ip6_dst_destroy, | 139 | .destroy = ip6_dst_destroy, |
107 | .ifdown = ip6_dst_ifdown, | 140 | .ifdown = ip6_dst_ifdown, |
108 | .negative_advice = ip6_negative_advice, | 141 | .negative_advice = ip6_negative_advice, |
109 | .link_failure = ip6_link_failure, | 142 | .link_failure = ip6_link_failure, |
110 | .update_pmtu = ip6_rt_update_pmtu, | 143 | .update_pmtu = ip6_rt_update_pmtu, |
111 | .local_out = __ip6_local_out, | 144 | .local_out = __ip6_local_out, |
112 | .entries = ATOMIC_INIT(0), | ||
113 | }; | 145 | }; |
114 | 146 | ||
147 | static unsigned int ip6_blackhole_default_mtu(const struct dst_entry *dst) | ||
148 | { | ||
149 | return 0; | ||
150 | } | ||
151 | |||
115 | static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu) | 152 | static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu) |
116 | { | 153 | { |
117 | } | 154 | } |
118 | 155 | ||
156 | static u32 *ip6_rt_blackhole_cow_metrics(struct dst_entry *dst, | ||
157 | unsigned long old) | ||
158 | { | ||
159 | return NULL; | ||
160 | } | ||
161 | |||
119 | static struct dst_ops ip6_dst_blackhole_ops = { | 162 | static struct dst_ops ip6_dst_blackhole_ops = { |
120 | .family = AF_INET6, | 163 | .family = AF_INET6, |
121 | .protocol = cpu_to_be16(ETH_P_IPV6), | 164 | .protocol = cpu_to_be16(ETH_P_IPV6), |
122 | .destroy = ip6_dst_destroy, | 165 | .destroy = ip6_dst_destroy, |
123 | .check = ip6_dst_check, | 166 | .check = ip6_dst_check, |
167 | .default_mtu = ip6_blackhole_default_mtu, | ||
168 | .default_advmss = ip6_default_advmss, | ||
124 | .update_pmtu = ip6_rt_blackhole_update_pmtu, | 169 | .update_pmtu = ip6_rt_blackhole_update_pmtu, |
125 | .entries = ATOMIC_INIT(0), | 170 | .cow_metrics = ip6_rt_blackhole_cow_metrics, |
171 | }; | ||
172 | |||
173 | static const u32 ip6_template_metrics[RTAX_MAX] = { | ||
174 | [RTAX_HOPLIMIT - 1] = 255, | ||
126 | }; | 175 | }; |
127 | 176 | ||
128 | static struct rt6_info ip6_null_entry_template = { | 177 | static struct rt6_info ip6_null_entry_template = { |
@@ -131,7 +180,6 @@ static struct rt6_info ip6_null_entry_template = { | |||
131 | .__use = 1, | 180 | .__use = 1, |
132 | .obsolete = -1, | 181 | .obsolete = -1, |
133 | .error = -ENETUNREACH, | 182 | .error = -ENETUNREACH, |
134 | .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, | ||
135 | .input = ip6_pkt_discard, | 183 | .input = ip6_pkt_discard, |
136 | .output = ip6_pkt_discard_out, | 184 | .output = ip6_pkt_discard_out, |
137 | }, | 185 | }, |
@@ -152,7 +200,6 @@ static struct rt6_info ip6_prohibit_entry_template = { | |||
152 | .__use = 1, | 200 | .__use = 1, |
153 | .obsolete = -1, | 201 | .obsolete = -1, |
154 | .error = -EACCES, | 202 | .error = -EACCES, |
155 | .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, | ||
156 | .input = ip6_pkt_prohibit, | 203 | .input = ip6_pkt_prohibit, |
157 | .output = ip6_pkt_prohibit_out, | 204 | .output = ip6_pkt_prohibit_out, |
158 | }, | 205 | }, |
@@ -168,7 +215,6 @@ static struct rt6_info ip6_blk_hole_entry_template = { | |||
168 | .__use = 1, | 215 | .__use = 1, |
169 | .obsolete = -1, | 216 | .obsolete = -1, |
170 | .error = -EINVAL, | 217 | .error = -EINVAL, |
171 | .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, | ||
172 | .input = dst_discard, | 218 | .input = dst_discard, |
173 | .output = dst_discard, | 219 | .output = dst_discard, |
174 | }, | 220 | }, |
@@ -181,20 +227,49 @@ static struct rt6_info ip6_blk_hole_entry_template = { | |||
181 | #endif | 227 | #endif |
182 | 228 | ||
183 | /* allocate dst with ip6_dst_ops */ | 229 | /* allocate dst with ip6_dst_ops */ |
184 | static inline struct rt6_info *ip6_dst_alloc(struct dst_ops *ops) | 230 | static inline struct rt6_info *ip6_dst_alloc(struct dst_ops *ops, |
231 | struct net_device *dev, | ||
232 | int flags) | ||
185 | { | 233 | { |
186 | return (struct rt6_info *)dst_alloc(ops); | 234 | struct rt6_info *rt = dst_alloc(ops, dev, 0, 0, flags); |
235 | |||
236 | memset(&rt->rt6i_table, 0, sizeof(*rt) - sizeof(struct dst_entry)); | ||
237 | |||
238 | return rt; | ||
187 | } | 239 | } |
188 | 240 | ||
189 | static void ip6_dst_destroy(struct dst_entry *dst) | 241 | static void ip6_dst_destroy(struct dst_entry *dst) |
190 | { | 242 | { |
191 | struct rt6_info *rt = (struct rt6_info *)dst; | 243 | struct rt6_info *rt = (struct rt6_info *)dst; |
192 | struct inet6_dev *idev = rt->rt6i_idev; | 244 | struct inet6_dev *idev = rt->rt6i_idev; |
245 | struct inet_peer *peer = rt->rt6i_peer; | ||
193 | 246 | ||
194 | if (idev != NULL) { | 247 | if (idev != NULL) { |
195 | rt->rt6i_idev = NULL; | 248 | rt->rt6i_idev = NULL; |
196 | in6_dev_put(idev); | 249 | in6_dev_put(idev); |
197 | } | 250 | } |
251 | if (peer) { | ||
252 | rt->rt6i_peer = NULL; | ||
253 | inet_putpeer(peer); | ||
254 | } | ||
255 | } | ||
256 | |||
257 | static atomic_t __rt6_peer_genid = ATOMIC_INIT(0); | ||
258 | |||
259 | static u32 rt6_peer_genid(void) | ||
260 | { | ||
261 | return atomic_read(&__rt6_peer_genid); | ||
262 | } | ||
263 | |||
264 | void rt6_bind_peer(struct rt6_info *rt, int create) | ||
265 | { | ||
266 | struct inet_peer *peer; | ||
267 | |||
268 | peer = inet_getpeer_v6(&rt->rt6i_dst.addr, create); | ||
269 | if (peer && cmpxchg(&rt->rt6i_peer, NULL, peer) != NULL) | ||
270 | inet_putpeer(peer); | ||
271 | else | ||
272 | rt->rt6i_peer_genid = rt6_peer_genid(); | ||
198 | } | 273 | } |
199 | 274 | ||
200 | static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, | 275 | static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, |
@@ -217,14 +292,14 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, | |||
217 | 292 | ||
218 | static __inline__ int rt6_check_expired(const struct rt6_info *rt) | 293 | static __inline__ int rt6_check_expired(const struct rt6_info *rt) |
219 | { | 294 | { |
220 | return (rt->rt6i_flags & RTF_EXPIRES && | 295 | return (rt->rt6i_flags & RTF_EXPIRES) && |
221 | time_after(jiffies, rt->rt6i_expires)); | 296 | time_after(jiffies, rt->rt6i_expires); |
222 | } | 297 | } |
223 | 298 | ||
224 | static inline int rt6_need_strict(struct in6_addr *daddr) | 299 | static inline int rt6_need_strict(const struct in6_addr *daddr) |
225 | { | 300 | { |
226 | return (ipv6_addr_type(daddr) & | 301 | return ipv6_addr_type(daddr) & |
227 | (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK)); | 302 | (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK); |
228 | } | 303 | } |
229 | 304 | ||
230 | /* | 305 | /* |
@@ -233,7 +308,7 @@ static inline int rt6_need_strict(struct in6_addr *daddr) | |||
233 | 308 | ||
234 | static inline struct rt6_info *rt6_device_match(struct net *net, | 309 | static inline struct rt6_info *rt6_device_match(struct net *net, |
235 | struct rt6_info *rt, | 310 | struct rt6_info *rt, |
236 | struct in6_addr *saddr, | 311 | const struct in6_addr *saddr, |
237 | int oif, | 312 | int oif, |
238 | int flags) | 313 | int flags) |
239 | { | 314 | { |
@@ -440,12 +515,12 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict) | |||
440 | __func__, match); | 515 | __func__, match); |
441 | 516 | ||
442 | net = dev_net(rt0->rt6i_dev); | 517 | net = dev_net(rt0->rt6i_dev); |
443 | return (match ? match : net->ipv6.ip6_null_entry); | 518 | return match ? match : net->ipv6.ip6_null_entry; |
444 | } | 519 | } |
445 | 520 | ||
446 | #ifdef CONFIG_IPV6_ROUTE_INFO | 521 | #ifdef CONFIG_IPV6_ROUTE_INFO |
447 | int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, | 522 | int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, |
448 | struct in6_addr *gwaddr) | 523 | const struct in6_addr *gwaddr) |
449 | { | 524 | { |
450 | struct net *net = dev_net(dev); | 525 | struct net *net = dev_net(dev); |
451 | struct route_info *rinfo = (struct route_info *) opt; | 526 | struct route_info *rinfo = (struct route_info *) opt; |
@@ -537,17 +612,17 @@ do { \ | |||
537 | 612 | ||
538 | static struct rt6_info *ip6_pol_route_lookup(struct net *net, | 613 | static struct rt6_info *ip6_pol_route_lookup(struct net *net, |
539 | struct fib6_table *table, | 614 | struct fib6_table *table, |
540 | struct flowi *fl, int flags) | 615 | struct flowi6 *fl6, int flags) |
541 | { | 616 | { |
542 | struct fib6_node *fn; | 617 | struct fib6_node *fn; |
543 | struct rt6_info *rt; | 618 | struct rt6_info *rt; |
544 | 619 | ||
545 | read_lock_bh(&table->tb6_lock); | 620 | read_lock_bh(&table->tb6_lock); |
546 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); | 621 | fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr); |
547 | restart: | 622 | restart: |
548 | rt = fn->leaf; | 623 | rt = fn->leaf; |
549 | rt = rt6_device_match(net, rt, &fl->fl6_src, fl->oif, flags); | 624 | rt = rt6_device_match(net, rt, &fl6->saddr, fl6->flowi6_oif, flags); |
550 | BACKTRACK(net, &fl->fl6_src); | 625 | BACKTRACK(net, &fl6->saddr); |
551 | out: | 626 | out: |
552 | dst_use(&rt->dst, jiffies); | 627 | dst_use(&rt->dst, jiffies); |
553 | read_unlock_bh(&table->tb6_lock); | 628 | read_unlock_bh(&table->tb6_lock); |
@@ -558,23 +633,19 @@ out: | |||
558 | struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr, | 633 | struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr, |
559 | const struct in6_addr *saddr, int oif, int strict) | 634 | const struct in6_addr *saddr, int oif, int strict) |
560 | { | 635 | { |
561 | struct flowi fl = { | 636 | struct flowi6 fl6 = { |
562 | .oif = oif, | 637 | .flowi6_oif = oif, |
563 | .nl_u = { | 638 | .daddr = *daddr, |
564 | .ip6_u = { | ||
565 | .daddr = *daddr, | ||
566 | }, | ||
567 | }, | ||
568 | }; | 639 | }; |
569 | struct dst_entry *dst; | 640 | struct dst_entry *dst; |
570 | int flags = strict ? RT6_LOOKUP_F_IFACE : 0; | 641 | int flags = strict ? RT6_LOOKUP_F_IFACE : 0; |
571 | 642 | ||
572 | if (saddr) { | 643 | if (saddr) { |
573 | memcpy(&fl.fl6_src, saddr, sizeof(*saddr)); | 644 | memcpy(&fl6.saddr, saddr, sizeof(*saddr)); |
574 | flags |= RT6_LOOKUP_F_HAS_SADDR; | 645 | flags |= RT6_LOOKUP_F_HAS_SADDR; |
575 | } | 646 | } |
576 | 647 | ||
577 | dst = fib6_rule_lookup(net, &fl, flags, ip6_pol_route_lookup); | 648 | dst = fib6_rule_lookup(net, &fl6, flags, ip6_pol_route_lookup); |
578 | if (dst->error == 0) | 649 | if (dst->error == 0) |
579 | return (struct rt6_info *) dst; | 650 | return (struct rt6_info *) dst; |
580 | 651 | ||
@@ -612,8 +683,8 @@ int ip6_ins_rt(struct rt6_info *rt) | |||
612 | return __ip6_ins_rt(rt, &info); | 683 | return __ip6_ins_rt(rt, &info); |
613 | } | 684 | } |
614 | 685 | ||
615 | static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *daddr, | 686 | static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, const struct in6_addr *daddr, |
616 | struct in6_addr *saddr) | 687 | const struct in6_addr *saddr) |
617 | { | 688 | { |
618 | struct rt6_info *rt; | 689 | struct rt6_info *rt; |
619 | 690 | ||
@@ -681,7 +752,7 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *dad | |||
681 | return rt; | 752 | return rt; |
682 | } | 753 | } |
683 | 754 | ||
684 | static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *daddr) | 755 | static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, const struct in6_addr *daddr) |
685 | { | 756 | { |
686 | struct rt6_info *rt = ip6_rt_copy(ort); | 757 | struct rt6_info *rt = ip6_rt_copy(ort); |
687 | if (rt) { | 758 | if (rt) { |
@@ -695,7 +766,7 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *d | |||
695 | } | 766 | } |
696 | 767 | ||
697 | static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int oif, | 768 | static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int oif, |
698 | struct flowi *fl, int flags) | 769 | struct flowi6 *fl6, int flags) |
699 | { | 770 | { |
700 | struct fib6_node *fn; | 771 | struct fib6_node *fn; |
701 | struct rt6_info *rt, *nrt; | 772 | struct rt6_info *rt, *nrt; |
@@ -710,12 +781,12 @@ relookup: | |||
710 | read_lock_bh(&table->tb6_lock); | 781 | read_lock_bh(&table->tb6_lock); |
711 | 782 | ||
712 | restart_2: | 783 | restart_2: |
713 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); | 784 | fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr); |
714 | 785 | ||
715 | restart: | 786 | restart: |
716 | rt = rt6_select(fn, oif, strict | reachable); | 787 | rt = rt6_select(fn, oif, strict | reachable); |
717 | 788 | ||
718 | BACKTRACK(net, &fl->fl6_src); | 789 | BACKTRACK(net, &fl6->saddr); |
719 | if (rt == net->ipv6.ip6_null_entry || | 790 | if (rt == net->ipv6.ip6_null_entry || |
720 | rt->rt6i_flags & RTF_CACHE) | 791 | rt->rt6i_flags & RTF_CACHE) |
721 | goto out; | 792 | goto out; |
@@ -724,14 +795,11 @@ restart: | |||
724 | read_unlock_bh(&table->tb6_lock); | 795 | read_unlock_bh(&table->tb6_lock); |
725 | 796 | ||
726 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) | 797 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) |
727 | nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src); | 798 | nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr); |
728 | else { | 799 | else if (!(rt->dst.flags & DST_HOST)) |
729 | #if CLONE_OFFLINK_ROUTE | 800 | nrt = rt6_alloc_clone(rt, &fl6->daddr); |
730 | nrt = rt6_alloc_clone(rt, &fl->fl6_dst); | 801 | else |
731 | #else | ||
732 | goto out2; | 802 | goto out2; |
733 | #endif | ||
734 | } | ||
735 | 803 | ||
736 | dst_release(&rt->dst); | 804 | dst_release(&rt->dst); |
737 | rt = nrt ? : net->ipv6.ip6_null_entry; | 805 | rt = nrt ? : net->ipv6.ip6_null_entry; |
@@ -768,78 +836,71 @@ out2: | |||
768 | } | 836 | } |
769 | 837 | ||
770 | static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table, | 838 | static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table, |
771 | struct flowi *fl, int flags) | 839 | struct flowi6 *fl6, int flags) |
772 | { | 840 | { |
773 | return ip6_pol_route(net, table, fl->iif, fl, flags); | 841 | return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, flags); |
774 | } | 842 | } |
775 | 843 | ||
776 | void ip6_route_input(struct sk_buff *skb) | 844 | void ip6_route_input(struct sk_buff *skb) |
777 | { | 845 | { |
778 | struct ipv6hdr *iph = ipv6_hdr(skb); | 846 | const struct ipv6hdr *iph = ipv6_hdr(skb); |
779 | struct net *net = dev_net(skb->dev); | 847 | struct net *net = dev_net(skb->dev); |
780 | int flags = RT6_LOOKUP_F_HAS_SADDR; | 848 | int flags = RT6_LOOKUP_F_HAS_SADDR; |
781 | struct flowi fl = { | 849 | struct flowi6 fl6 = { |
782 | .iif = skb->dev->ifindex, | 850 | .flowi6_iif = skb->dev->ifindex, |
783 | .nl_u = { | 851 | .daddr = iph->daddr, |
784 | .ip6_u = { | 852 | .saddr = iph->saddr, |
785 | .daddr = iph->daddr, | 853 | .flowlabel = (* (__be32 *) iph)&IPV6_FLOWINFO_MASK, |
786 | .saddr = iph->saddr, | 854 | .flowi6_mark = skb->mark, |
787 | .flowlabel = (* (__be32 *) iph)&IPV6_FLOWINFO_MASK, | 855 | .flowi6_proto = iph->nexthdr, |
788 | }, | ||
789 | }, | ||
790 | .mark = skb->mark, | ||
791 | .proto = iph->nexthdr, | ||
792 | }; | 856 | }; |
793 | 857 | ||
794 | if (rt6_need_strict(&iph->daddr) && skb->dev->type != ARPHRD_PIMREG) | 858 | if (rt6_need_strict(&iph->daddr) && skb->dev->type != ARPHRD_PIMREG) |
795 | flags |= RT6_LOOKUP_F_IFACE; | 859 | flags |= RT6_LOOKUP_F_IFACE; |
796 | 860 | ||
797 | skb_dst_set(skb, fib6_rule_lookup(net, &fl, flags, ip6_pol_route_input)); | 861 | skb_dst_set(skb, fib6_rule_lookup(net, &fl6, flags, ip6_pol_route_input)); |
798 | } | 862 | } |
799 | 863 | ||
800 | static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table, | 864 | static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table, |
801 | struct flowi *fl, int flags) | 865 | struct flowi6 *fl6, int flags) |
802 | { | 866 | { |
803 | return ip6_pol_route(net, table, fl->oif, fl, flags); | 867 | return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags); |
804 | } | 868 | } |
805 | 869 | ||
806 | struct dst_entry * ip6_route_output(struct net *net, struct sock *sk, | 870 | struct dst_entry * ip6_route_output(struct net *net, const struct sock *sk, |
807 | struct flowi *fl) | 871 | struct flowi6 *fl6) |
808 | { | 872 | { |
809 | int flags = 0; | 873 | int flags = 0; |
810 | 874 | ||
811 | if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl->fl6_dst)) | 875 | if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr)) |
812 | flags |= RT6_LOOKUP_F_IFACE; | 876 | flags |= RT6_LOOKUP_F_IFACE; |
813 | 877 | ||
814 | if (!ipv6_addr_any(&fl->fl6_src)) | 878 | if (!ipv6_addr_any(&fl6->saddr)) |
815 | flags |= RT6_LOOKUP_F_HAS_SADDR; | 879 | flags |= RT6_LOOKUP_F_HAS_SADDR; |
816 | else if (sk) | 880 | else if (sk) |
817 | flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs); | 881 | flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs); |
818 | 882 | ||
819 | return fib6_rule_lookup(net, fl, flags, ip6_pol_route_output); | 883 | return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_output); |
820 | } | 884 | } |
821 | 885 | ||
822 | EXPORT_SYMBOL(ip6_route_output); | 886 | EXPORT_SYMBOL(ip6_route_output); |
823 | 887 | ||
824 | int ip6_dst_blackhole(struct sock *sk, struct dst_entry **dstp, struct flowi *fl) | 888 | struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig) |
825 | { | 889 | { |
826 | struct rt6_info *ort = (struct rt6_info *) *dstp; | 890 | struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig; |
827 | struct rt6_info *rt = (struct rt6_info *) | ||
828 | dst_alloc(&ip6_dst_blackhole_ops); | ||
829 | struct dst_entry *new = NULL; | 891 | struct dst_entry *new = NULL; |
830 | 892 | ||
893 | rt = dst_alloc(&ip6_dst_blackhole_ops, ort->dst.dev, 1, 0, 0); | ||
831 | if (rt) { | 894 | if (rt) { |
895 | memset(&rt->rt6i_table, 0, sizeof(*rt) - sizeof(struct dst_entry)); | ||
896 | |||
832 | new = &rt->dst; | 897 | new = &rt->dst; |
833 | 898 | ||
834 | atomic_set(&new->__refcnt, 1); | ||
835 | new->__use = 1; | 899 | new->__use = 1; |
836 | new->input = dst_discard; | 900 | new->input = dst_discard; |
837 | new->output = dst_discard; | 901 | new->output = dst_discard; |
838 | 902 | ||
839 | memcpy(new->metrics, ort->dst.metrics, RTAX_MAX*sizeof(u32)); | 903 | dst_copy_metrics(new, &ort->dst); |
840 | new->dev = ort->dst.dev; | ||
841 | if (new->dev) | ||
842 | dev_hold(new->dev); | ||
843 | rt->rt6i_idev = ort->rt6i_idev; | 904 | rt->rt6i_idev = ort->rt6i_idev; |
844 | if (rt->rt6i_idev) | 905 | if (rt->rt6i_idev) |
845 | in6_dev_hold(rt->rt6i_idev); | 906 | in6_dev_hold(rt->rt6i_idev); |
@@ -857,11 +918,9 @@ int ip6_dst_blackhole(struct sock *sk, struct dst_entry **dstp, struct flowi *fl | |||
857 | dst_free(new); | 918 | dst_free(new); |
858 | } | 919 | } |
859 | 920 | ||
860 | dst_release(*dstp); | 921 | dst_release(dst_orig); |
861 | *dstp = new; | 922 | return new ? new : ERR_PTR(-ENOMEM); |
862 | return (new ? 0 : -ENOMEM); | ||
863 | } | 923 | } |
864 | EXPORT_SYMBOL_GPL(ip6_dst_blackhole); | ||
865 | 924 | ||
866 | /* | 925 | /* |
867 | * Destination cache support functions | 926 | * Destination cache support functions |
@@ -873,9 +932,14 @@ static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie) | |||
873 | 932 | ||
874 | rt = (struct rt6_info *) dst; | 933 | rt = (struct rt6_info *) dst; |
875 | 934 | ||
876 | if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie)) | 935 | if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie)) { |
936 | if (rt->rt6i_peer_genid != rt6_peer_genid()) { | ||
937 | if (!rt->rt6i_peer) | ||
938 | rt6_bind_peer(rt, 0); | ||
939 | rt->rt6i_peer_genid = rt6_peer_genid(); | ||
940 | } | ||
877 | return dst; | 941 | return dst; |
878 | 942 | } | |
879 | return NULL; | 943 | return NULL; |
880 | } | 944 | } |
881 | 945 | ||
@@ -920,18 +984,21 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu) | |||
920 | if (mtu < dst_mtu(dst) && rt6->rt6i_dst.plen == 128) { | 984 | if (mtu < dst_mtu(dst) && rt6->rt6i_dst.plen == 128) { |
921 | rt6->rt6i_flags |= RTF_MODIFIED; | 985 | rt6->rt6i_flags |= RTF_MODIFIED; |
922 | if (mtu < IPV6_MIN_MTU) { | 986 | if (mtu < IPV6_MIN_MTU) { |
987 | u32 features = dst_metric(dst, RTAX_FEATURES); | ||
923 | mtu = IPV6_MIN_MTU; | 988 | mtu = IPV6_MIN_MTU; |
924 | dst->metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG; | 989 | features |= RTAX_FEATURE_ALLFRAG; |
990 | dst_metric_set(dst, RTAX_FEATURES, features); | ||
925 | } | 991 | } |
926 | dst->metrics[RTAX_MTU-1] = mtu; | 992 | dst_metric_set(dst, RTAX_MTU, mtu); |
927 | call_netevent_notifiers(NETEVENT_PMTU_UPDATE, dst); | ||
928 | } | 993 | } |
929 | } | 994 | } |
930 | 995 | ||
931 | static int ipv6_get_mtu(struct net_device *dev); | 996 | static unsigned int ip6_default_advmss(const struct dst_entry *dst) |
932 | |||
933 | static inline unsigned int ipv6_advmss(struct net *net, unsigned int mtu) | ||
934 | { | 997 | { |
998 | struct net_device *dev = dst->dev; | ||
999 | unsigned int mtu = dst_mtu(dst); | ||
1000 | struct net *net = dev_net(dev); | ||
1001 | |||
935 | mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr); | 1002 | mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr); |
936 | 1003 | ||
937 | if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss) | 1004 | if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss) |
@@ -948,6 +1015,20 @@ static inline unsigned int ipv6_advmss(struct net *net, unsigned int mtu) | |||
948 | return mtu; | 1015 | return mtu; |
949 | } | 1016 | } |
950 | 1017 | ||
1018 | static unsigned int ip6_default_mtu(const struct dst_entry *dst) | ||
1019 | { | ||
1020 | unsigned int mtu = IPV6_MIN_MTU; | ||
1021 | struct inet6_dev *idev; | ||
1022 | |||
1023 | rcu_read_lock(); | ||
1024 | idev = __in6_dev_get(dst->dev); | ||
1025 | if (idev) | ||
1026 | mtu = idev->cnf.mtu6; | ||
1027 | rcu_read_unlock(); | ||
1028 | |||
1029 | return mtu; | ||
1030 | } | ||
1031 | |||
951 | static struct dst_entry *icmp6_dst_gc_list; | 1032 | static struct dst_entry *icmp6_dst_gc_list; |
952 | static DEFINE_SPINLOCK(icmp6_dst_lock); | 1033 | static DEFINE_SPINLOCK(icmp6_dst_lock); |
953 | 1034 | ||
@@ -962,13 +1043,12 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, | |||
962 | if (unlikely(idev == NULL)) | 1043 | if (unlikely(idev == NULL)) |
963 | return NULL; | 1044 | return NULL; |
964 | 1045 | ||
965 | rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops); | 1046 | rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, dev, 0); |
966 | if (unlikely(rt == NULL)) { | 1047 | if (unlikely(rt == NULL)) { |
967 | in6_dev_put(idev); | 1048 | in6_dev_put(idev); |
968 | goto out; | 1049 | goto out; |
969 | } | 1050 | } |
970 | 1051 | ||
971 | dev_hold(dev); | ||
972 | if (neigh) | 1052 | if (neigh) |
973 | neigh_hold(neigh); | 1053 | neigh_hold(neigh); |
974 | else { | 1054 | else { |
@@ -977,23 +1057,12 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, | |||
977 | neigh = NULL; | 1057 | neigh = NULL; |
978 | } | 1058 | } |
979 | 1059 | ||
980 | rt->rt6i_dev = dev; | ||
981 | rt->rt6i_idev = idev; | 1060 | rt->rt6i_idev = idev; |
982 | rt->rt6i_nexthop = neigh; | 1061 | rt->rt6i_nexthop = neigh; |
983 | atomic_set(&rt->dst.__refcnt, 1); | 1062 | atomic_set(&rt->dst.__refcnt, 1); |
984 | rt->dst.metrics[RTAX_HOPLIMIT-1] = 255; | 1063 | dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 255); |
985 | rt->dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev); | ||
986 | rt->dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->dst)); | ||
987 | rt->dst.output = ip6_output; | 1064 | rt->dst.output = ip6_output; |
988 | 1065 | ||
989 | #if 0 /* there's no chance to use these for ndisc */ | ||
990 | rt->dst.flags = ipv6_addr_type(addr) & IPV6_ADDR_UNICAST | ||
991 | ? DST_HOST | ||
992 | : 0; | ||
993 | ipv6_addr_copy(&rt->rt6i_dst.addr, addr); | ||
994 | rt->rt6i_dst.plen = 128; | ||
995 | #endif | ||
996 | |||
997 | spin_lock_bh(&icmp6_dst_lock); | 1066 | spin_lock_bh(&icmp6_dst_lock); |
998 | rt->dst.next = icmp6_dst_gc_list; | 1067 | rt->dst.next = icmp6_dst_gc_list; |
999 | icmp6_dst_gc_list = &rt->dst; | 1068 | icmp6_dst_gc_list = &rt->dst; |
@@ -1007,11 +1076,9 @@ out: | |||
1007 | 1076 | ||
1008 | int icmp6_dst_gc(void) | 1077 | int icmp6_dst_gc(void) |
1009 | { | 1078 | { |
1010 | struct dst_entry *dst, *next, **pprev; | 1079 | struct dst_entry *dst, **pprev; |
1011 | int more = 0; | 1080 | int more = 0; |
1012 | 1081 | ||
1013 | next = NULL; | ||
1014 | |||
1015 | spin_lock_bh(&icmp6_dst_lock); | 1082 | spin_lock_bh(&icmp6_dst_lock); |
1016 | pprev = &icmp6_dst_gc_list; | 1083 | pprev = &icmp6_dst_gc_list; |
1017 | 1084 | ||
@@ -1058,19 +1125,22 @@ static int ip6_dst_gc(struct dst_ops *ops) | |||
1058 | int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity; | 1125 | int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity; |
1059 | int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout; | 1126 | int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout; |
1060 | unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc; | 1127 | unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc; |
1128 | int entries; | ||
1061 | 1129 | ||
1130 | entries = dst_entries_get_fast(ops); | ||
1062 | if (time_after(rt_last_gc + rt_min_interval, now) && | 1131 | if (time_after(rt_last_gc + rt_min_interval, now) && |
1063 | atomic_read(&ops->entries) <= rt_max_size) | 1132 | entries <= rt_max_size) |
1064 | goto out; | 1133 | goto out; |
1065 | 1134 | ||
1066 | net->ipv6.ip6_rt_gc_expire++; | 1135 | net->ipv6.ip6_rt_gc_expire++; |
1067 | fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net); | 1136 | fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net); |
1068 | net->ipv6.ip6_rt_last_gc = now; | 1137 | net->ipv6.ip6_rt_last_gc = now; |
1069 | if (atomic_read(&ops->entries) < ops->gc_thresh) | 1138 | entries = dst_entries_get_slow(ops); |
1139 | if (entries < ops->gc_thresh) | ||
1070 | net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1; | 1140 | net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1; |
1071 | out: | 1141 | out: |
1072 | net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity; | 1142 | net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity; |
1073 | return (atomic_read(&ops->entries) > rt_max_size); | 1143 | return entries > rt_max_size; |
1074 | } | 1144 | } |
1075 | 1145 | ||
1076 | /* Clean host part of a prefix. Not necessary in radix tree, | 1146 | /* Clean host part of a prefix. Not necessary in radix tree, |
@@ -1079,23 +1149,10 @@ out: | |||
1079 | Remove it only when all the things will work! | 1149 | Remove it only when all the things will work! |
1080 | */ | 1150 | */ |
1081 | 1151 | ||
1082 | static int ipv6_get_mtu(struct net_device *dev) | ||
1083 | { | ||
1084 | int mtu = IPV6_MIN_MTU; | ||
1085 | struct inet6_dev *idev; | ||
1086 | |||
1087 | rcu_read_lock(); | ||
1088 | idev = __in6_dev_get(dev); | ||
1089 | if (idev) | ||
1090 | mtu = idev->cnf.mtu6; | ||
1091 | rcu_read_unlock(); | ||
1092 | return mtu; | ||
1093 | } | ||
1094 | |||
1095 | int ip6_dst_hoplimit(struct dst_entry *dst) | 1152 | int ip6_dst_hoplimit(struct dst_entry *dst) |
1096 | { | 1153 | { |
1097 | int hoplimit = dst_metric(dst, RTAX_HOPLIMIT); | 1154 | int hoplimit = dst_metric_raw(dst, RTAX_HOPLIMIT); |
1098 | if (hoplimit < 0) { | 1155 | if (hoplimit == 0) { |
1099 | struct net_device *dev = dst->dev; | 1156 | struct net_device *dev = dst->dev; |
1100 | struct inet6_dev *idev; | 1157 | struct inet6_dev *idev; |
1101 | 1158 | ||
@@ -1109,6 +1166,7 @@ int ip6_dst_hoplimit(struct dst_entry *dst) | |||
1109 | } | 1166 | } |
1110 | return hoplimit; | 1167 | return hoplimit; |
1111 | } | 1168 | } |
1169 | EXPORT_SYMBOL(ip6_dst_hoplimit); | ||
1112 | 1170 | ||
1113 | /* | 1171 | /* |
1114 | * | 1172 | * |
@@ -1149,7 +1207,7 @@ int ip6_route_add(struct fib6_config *cfg) | |||
1149 | goto out; | 1207 | goto out; |
1150 | } | 1208 | } |
1151 | 1209 | ||
1152 | rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops); | 1210 | rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, NULL, DST_NOCOUNT); |
1153 | 1211 | ||
1154 | if (rt == NULL) { | 1212 | if (rt == NULL) { |
1155 | err = -ENOMEM; | 1213 | err = -ENOMEM; |
@@ -1169,6 +1227,8 @@ int ip6_route_add(struct fib6_config *cfg) | |||
1169 | 1227 | ||
1170 | if (addr_type & IPV6_ADDR_MULTICAST) | 1228 | if (addr_type & IPV6_ADDR_MULTICAST) |
1171 | rt->dst.input = ip6_mc_input; | 1229 | rt->dst.input = ip6_mc_input; |
1230 | else if (cfg->fc_flags & RTF_LOCAL) | ||
1231 | rt->dst.input = ip6_input; | ||
1172 | else | 1232 | else |
1173 | rt->dst.input = ip6_forward; | 1233 | rt->dst.input = ip6_forward; |
1174 | 1234 | ||
@@ -1177,7 +1237,7 @@ int ip6_route_add(struct fib6_config *cfg) | |||
1177 | ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len); | 1237 | ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len); |
1178 | rt->rt6i_dst.plen = cfg->fc_dst_len; | 1238 | rt->rt6i_dst.plen = cfg->fc_dst_len; |
1179 | if (rt->rt6i_dst.plen == 128) | 1239 | if (rt->rt6i_dst.plen == 128) |
1180 | rt->dst.flags = DST_HOST; | 1240 | rt->dst.flags |= DST_HOST; |
1181 | 1241 | ||
1182 | #ifdef CONFIG_IPV6_SUBTREES | 1242 | #ifdef CONFIG_IPV6_SUBTREES |
1183 | ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len); | 1243 | ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len); |
@@ -1190,7 +1250,8 @@ int ip6_route_add(struct fib6_config *cfg) | |||
1190 | they would result in kernel looping; promote them to reject routes | 1250 | they would result in kernel looping; promote them to reject routes |
1191 | */ | 1251 | */ |
1192 | if ((cfg->fc_flags & RTF_REJECT) || | 1252 | if ((cfg->fc_flags & RTF_REJECT) || |
1193 | (dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK))) { | 1253 | (dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK) |
1254 | && !(cfg->fc_flags&RTF_LOCAL))) { | ||
1194 | /* hold loopback dev/idev if we haven't done so. */ | 1255 | /* hold loopback dev/idev if we haven't done so. */ |
1195 | if (dev != net->loopback_dev) { | 1256 | if (dev != net->loopback_dev) { |
1196 | if (dev) { | 1257 | if (dev) { |
@@ -1213,7 +1274,7 @@ int ip6_route_add(struct fib6_config *cfg) | |||
1213 | } | 1274 | } |
1214 | 1275 | ||
1215 | if (cfg->fc_flags & RTF_GATEWAY) { | 1276 | if (cfg->fc_flags & RTF_GATEWAY) { |
1216 | struct in6_addr *gw_addr; | 1277 | const struct in6_addr *gw_addr; |
1217 | int gwa_type; | 1278 | int gwa_type; |
1218 | 1279 | ||
1219 | gw_addr = &cfg->fc_gateway; | 1280 | gw_addr = &cfg->fc_gateway; |
@@ -1266,6 +1327,16 @@ int ip6_route_add(struct fib6_config *cfg) | |||
1266 | if (dev == NULL) | 1327 | if (dev == NULL) |
1267 | goto out; | 1328 | goto out; |
1268 | 1329 | ||
1330 | if (!ipv6_addr_any(&cfg->fc_prefsrc)) { | ||
1331 | if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) { | ||
1332 | err = -EINVAL; | ||
1333 | goto out; | ||
1334 | } | ||
1335 | ipv6_addr_copy(&rt->rt6i_prefsrc.addr, &cfg->fc_prefsrc); | ||
1336 | rt->rt6i_prefsrc.plen = 128; | ||
1337 | } else | ||
1338 | rt->rt6i_prefsrc.plen = 0; | ||
1339 | |||
1269 | if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) { | 1340 | if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) { |
1270 | rt->rt6i_nexthop = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev); | 1341 | rt->rt6i_nexthop = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev); |
1271 | if (IS_ERR(rt->rt6i_nexthop)) { | 1342 | if (IS_ERR(rt->rt6i_nexthop)) { |
@@ -1291,17 +1362,11 @@ install_route: | |||
1291 | goto out; | 1362 | goto out; |
1292 | } | 1363 | } |
1293 | 1364 | ||
1294 | rt->dst.metrics[type - 1] = nla_get_u32(nla); | 1365 | dst_metric_set(&rt->dst, type, nla_get_u32(nla)); |
1295 | } | 1366 | } |
1296 | } | 1367 | } |
1297 | } | 1368 | } |
1298 | 1369 | ||
1299 | if (dst_metric(&rt->dst, RTAX_HOPLIMIT) == 0) | ||
1300 | rt->dst.metrics[RTAX_HOPLIMIT-1] = -1; | ||
1301 | if (!dst_mtu(&rt->dst)) | ||
1302 | rt->dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(dev); | ||
1303 | if (!dst_metric(&rt->dst, RTAX_ADVMSS)) | ||
1304 | rt->dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->dst)); | ||
1305 | rt->dst.dev = dev; | 1370 | rt->dst.dev = dev; |
1306 | rt->rt6i_idev = idev; | 1371 | rt->rt6i_idev = idev; |
1307 | rt->rt6i_table = table; | 1372 | rt->rt6i_table = table; |
@@ -1391,16 +1456,16 @@ static int ip6_route_del(struct fib6_config *cfg) | |||
1391 | * Handle redirects | 1456 | * Handle redirects |
1392 | */ | 1457 | */ |
1393 | struct ip6rd_flowi { | 1458 | struct ip6rd_flowi { |
1394 | struct flowi fl; | 1459 | struct flowi6 fl6; |
1395 | struct in6_addr gateway; | 1460 | struct in6_addr gateway; |
1396 | }; | 1461 | }; |
1397 | 1462 | ||
1398 | static struct rt6_info *__ip6_route_redirect(struct net *net, | 1463 | static struct rt6_info *__ip6_route_redirect(struct net *net, |
1399 | struct fib6_table *table, | 1464 | struct fib6_table *table, |
1400 | struct flowi *fl, | 1465 | struct flowi6 *fl6, |
1401 | int flags) | 1466 | int flags) |
1402 | { | 1467 | { |
1403 | struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl; | 1468 | struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6; |
1404 | struct rt6_info *rt; | 1469 | struct rt6_info *rt; |
1405 | struct fib6_node *fn; | 1470 | struct fib6_node *fn; |
1406 | 1471 | ||
@@ -1416,7 +1481,7 @@ static struct rt6_info *__ip6_route_redirect(struct net *net, | |||
1416 | */ | 1481 | */ |
1417 | 1482 | ||
1418 | read_lock_bh(&table->tb6_lock); | 1483 | read_lock_bh(&table->tb6_lock); |
1419 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); | 1484 | fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr); |
1420 | restart: | 1485 | restart: |
1421 | for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) { | 1486 | for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) { |
1422 | /* | 1487 | /* |
@@ -1431,7 +1496,7 @@ restart: | |||
1431 | continue; | 1496 | continue; |
1432 | if (!(rt->rt6i_flags & RTF_GATEWAY)) | 1497 | if (!(rt->rt6i_flags & RTF_GATEWAY)) |
1433 | continue; | 1498 | continue; |
1434 | if (fl->oif != rt->rt6i_dev->ifindex) | 1499 | if (fl6->flowi6_oif != rt->rt6i_dev->ifindex) |
1435 | continue; | 1500 | continue; |
1436 | if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway)) | 1501 | if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway)) |
1437 | continue; | 1502 | continue; |
@@ -1440,7 +1505,7 @@ restart: | |||
1440 | 1505 | ||
1441 | if (!rt) | 1506 | if (!rt) |
1442 | rt = net->ipv6.ip6_null_entry; | 1507 | rt = net->ipv6.ip6_null_entry; |
1443 | BACKTRACK(net, &fl->fl6_src); | 1508 | BACKTRACK(net, &fl6->saddr); |
1444 | out: | 1509 | out: |
1445 | dst_hold(&rt->dst); | 1510 | dst_hold(&rt->dst); |
1446 | 1511 | ||
@@ -1449,22 +1514,18 @@ out: | |||
1449 | return rt; | 1514 | return rt; |
1450 | }; | 1515 | }; |
1451 | 1516 | ||
1452 | static struct rt6_info *ip6_route_redirect(struct in6_addr *dest, | 1517 | static struct rt6_info *ip6_route_redirect(const struct in6_addr *dest, |
1453 | struct in6_addr *src, | 1518 | const struct in6_addr *src, |
1454 | struct in6_addr *gateway, | 1519 | const struct in6_addr *gateway, |
1455 | struct net_device *dev) | 1520 | struct net_device *dev) |
1456 | { | 1521 | { |
1457 | int flags = RT6_LOOKUP_F_HAS_SADDR; | 1522 | int flags = RT6_LOOKUP_F_HAS_SADDR; |
1458 | struct net *net = dev_net(dev); | 1523 | struct net *net = dev_net(dev); |
1459 | struct ip6rd_flowi rdfl = { | 1524 | struct ip6rd_flowi rdfl = { |
1460 | .fl = { | 1525 | .fl6 = { |
1461 | .oif = dev->ifindex, | 1526 | .flowi6_oif = dev->ifindex, |
1462 | .nl_u = { | 1527 | .daddr = *dest, |
1463 | .ip6_u = { | 1528 | .saddr = *src, |
1464 | .daddr = *dest, | ||
1465 | .saddr = *src, | ||
1466 | }, | ||
1467 | }, | ||
1468 | }, | 1529 | }, |
1469 | }; | 1530 | }; |
1470 | 1531 | ||
@@ -1473,12 +1534,12 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest, | |||
1473 | if (rt6_need_strict(dest)) | 1534 | if (rt6_need_strict(dest)) |
1474 | flags |= RT6_LOOKUP_F_IFACE; | 1535 | flags |= RT6_LOOKUP_F_IFACE; |
1475 | 1536 | ||
1476 | return (struct rt6_info *)fib6_rule_lookup(net, (struct flowi *)&rdfl, | 1537 | return (struct rt6_info *)fib6_rule_lookup(net, &rdfl.fl6, |
1477 | flags, __ip6_route_redirect); | 1538 | flags, __ip6_route_redirect); |
1478 | } | 1539 | } |
1479 | 1540 | ||
1480 | void rt6_redirect(struct in6_addr *dest, struct in6_addr *src, | 1541 | void rt6_redirect(const struct in6_addr *dest, const struct in6_addr *src, |
1481 | struct in6_addr *saddr, | 1542 | const struct in6_addr *saddr, |
1482 | struct neighbour *neigh, u8 *lladdr, int on_link) | 1543 | struct neighbour *neigh, u8 *lladdr, int on_link) |
1483 | { | 1544 | { |
1484 | struct rt6_info *rt, *nrt = NULL; | 1545 | struct rt6_info *rt, *nrt = NULL; |
@@ -1530,10 +1591,6 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *src, | |||
1530 | 1591 | ||
1531 | ipv6_addr_copy(&nrt->rt6i_gateway, (struct in6_addr*)neigh->primary_key); | 1592 | ipv6_addr_copy(&nrt->rt6i_gateway, (struct in6_addr*)neigh->primary_key); |
1532 | nrt->rt6i_nexthop = neigh_clone(neigh); | 1593 | nrt->rt6i_nexthop = neigh_clone(neigh); |
1533 | /* Reset pmtu, it may be better */ | ||
1534 | nrt->dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(neigh->dev); | ||
1535 | nrt->dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dev_net(neigh->dev), | ||
1536 | dst_mtu(&nrt->dst)); | ||
1537 | 1594 | ||
1538 | if (ip6_ins_rt(nrt)) | 1595 | if (ip6_ins_rt(nrt)) |
1539 | goto out; | 1596 | goto out; |
@@ -1556,16 +1613,21 @@ out: | |||
1556 | * i.e. Path MTU discovery | 1613 | * i.e. Path MTU discovery |
1557 | */ | 1614 | */ |
1558 | 1615 | ||
1559 | static void rt6_do_pmtu_disc(struct in6_addr *daddr, struct in6_addr *saddr, | 1616 | static void rt6_do_pmtu_disc(const struct in6_addr *daddr, const struct in6_addr *saddr, |
1560 | struct net *net, u32 pmtu, int ifindex) | 1617 | struct net *net, u32 pmtu, int ifindex) |
1561 | { | 1618 | { |
1562 | struct rt6_info *rt, *nrt; | 1619 | struct rt6_info *rt, *nrt; |
1563 | int allfrag = 0; | 1620 | int allfrag = 0; |
1564 | 1621 | again: | |
1565 | rt = rt6_lookup(net, daddr, saddr, ifindex, 0); | 1622 | rt = rt6_lookup(net, daddr, saddr, ifindex, 0); |
1566 | if (rt == NULL) | 1623 | if (rt == NULL) |
1567 | return; | 1624 | return; |
1568 | 1625 | ||
1626 | if (rt6_check_expired(rt)) { | ||
1627 | ip6_del_rt(rt); | ||
1628 | goto again; | ||
1629 | } | ||
1630 | |||
1569 | if (pmtu >= dst_mtu(&rt->dst)) | 1631 | if (pmtu >= dst_mtu(&rt->dst)) |
1570 | goto out; | 1632 | goto out; |
1571 | 1633 | ||
@@ -1592,9 +1654,12 @@ static void rt6_do_pmtu_disc(struct in6_addr *daddr, struct in6_addr *saddr, | |||
1592 | would return automatically. | 1654 | would return automatically. |
1593 | */ | 1655 | */ |
1594 | if (rt->rt6i_flags & RTF_CACHE) { | 1656 | if (rt->rt6i_flags & RTF_CACHE) { |
1595 | rt->dst.metrics[RTAX_MTU-1] = pmtu; | 1657 | dst_metric_set(&rt->dst, RTAX_MTU, pmtu); |
1596 | if (allfrag) | 1658 | if (allfrag) { |
1597 | rt->dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG; | 1659 | u32 features = dst_metric(&rt->dst, RTAX_FEATURES); |
1660 | features |= RTAX_FEATURE_ALLFRAG; | ||
1661 | dst_metric_set(&rt->dst, RTAX_FEATURES, features); | ||
1662 | } | ||
1598 | dst_set_expires(&rt->dst, net->ipv6.sysctl.ip6_rt_mtu_expires); | 1663 | dst_set_expires(&rt->dst, net->ipv6.sysctl.ip6_rt_mtu_expires); |
1599 | rt->rt6i_flags |= RTF_MODIFIED|RTF_EXPIRES; | 1664 | rt->rt6i_flags |= RTF_MODIFIED|RTF_EXPIRES; |
1600 | goto out; | 1665 | goto out; |
@@ -1611,9 +1676,12 @@ static void rt6_do_pmtu_disc(struct in6_addr *daddr, struct in6_addr *saddr, | |||
1611 | nrt = rt6_alloc_clone(rt, daddr); | 1676 | nrt = rt6_alloc_clone(rt, daddr); |
1612 | 1677 | ||
1613 | if (nrt) { | 1678 | if (nrt) { |
1614 | nrt->dst.metrics[RTAX_MTU-1] = pmtu; | 1679 | dst_metric_set(&nrt->dst, RTAX_MTU, pmtu); |
1615 | if (allfrag) | 1680 | if (allfrag) { |
1616 | nrt->dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG; | 1681 | u32 features = dst_metric(&nrt->dst, RTAX_FEATURES); |
1682 | features |= RTAX_FEATURE_ALLFRAG; | ||
1683 | dst_metric_set(&nrt->dst, RTAX_FEATURES, features); | ||
1684 | } | ||
1617 | 1685 | ||
1618 | /* According to RFC 1981, detecting PMTU increase shouldn't be | 1686 | /* According to RFC 1981, detecting PMTU increase shouldn't be |
1619 | * happened within 5 mins, the recommended timer is 10 mins. | 1687 | * happened within 5 mins, the recommended timer is 10 mins. |
@@ -1630,7 +1698,7 @@ out: | |||
1630 | dst_release(&rt->dst); | 1698 | dst_release(&rt->dst); |
1631 | } | 1699 | } |
1632 | 1700 | ||
1633 | void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr, | 1701 | void rt6_pmtu_discovery(const struct in6_addr *daddr, const struct in6_addr *saddr, |
1634 | struct net_device *dev, u32 pmtu) | 1702 | struct net_device *dev, u32 pmtu) |
1635 | { | 1703 | { |
1636 | struct net *net = dev_net(dev); | 1704 | struct net *net = dev_net(dev); |
@@ -1658,17 +1726,15 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr, | |||
1658 | static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) | 1726 | static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) |
1659 | { | 1727 | { |
1660 | struct net *net = dev_net(ort->rt6i_dev); | 1728 | struct net *net = dev_net(ort->rt6i_dev); |
1661 | struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops); | 1729 | struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, |
1730 | ort->dst.dev, 0); | ||
1662 | 1731 | ||
1663 | if (rt) { | 1732 | if (rt) { |
1664 | rt->dst.input = ort->dst.input; | 1733 | rt->dst.input = ort->dst.input; |
1665 | rt->dst.output = ort->dst.output; | 1734 | rt->dst.output = ort->dst.output; |
1666 | 1735 | ||
1667 | memcpy(rt->dst.metrics, ort->dst.metrics, RTAX_MAX*sizeof(u32)); | 1736 | dst_copy_metrics(&rt->dst, &ort->dst); |
1668 | rt->dst.error = ort->dst.error; | 1737 | rt->dst.error = ort->dst.error; |
1669 | rt->dst.dev = ort->dst.dev; | ||
1670 | if (rt->dst.dev) | ||
1671 | dev_hold(rt->dst.dev); | ||
1672 | rt->rt6i_idev = ort->rt6i_idev; | 1738 | rt->rt6i_idev = ort->rt6i_idev; |
1673 | if (rt->rt6i_idev) | 1739 | if (rt->rt6i_idev) |
1674 | in6_dev_hold(rt->rt6i_idev); | 1740 | in6_dev_hold(rt->rt6i_idev); |
@@ -1683,6 +1749,7 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) | |||
1683 | #ifdef CONFIG_IPV6_SUBTREES | 1749 | #ifdef CONFIG_IPV6_SUBTREES |
1684 | memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key)); | 1750 | memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key)); |
1685 | #endif | 1751 | #endif |
1752 | memcpy(&rt->rt6i_prefsrc, &ort->rt6i_prefsrc, sizeof(struct rt6key)); | ||
1686 | rt->rt6i_table = ort->rt6i_table; | 1753 | rt->rt6i_table = ort->rt6i_table; |
1687 | } | 1754 | } |
1688 | return rt; | 1755 | return rt; |
@@ -1690,8 +1757,8 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) | |||
1690 | 1757 | ||
1691 | #ifdef CONFIG_IPV6_ROUTE_INFO | 1758 | #ifdef CONFIG_IPV6_ROUTE_INFO |
1692 | static struct rt6_info *rt6_get_route_info(struct net *net, | 1759 | static struct rt6_info *rt6_get_route_info(struct net *net, |
1693 | struct in6_addr *prefix, int prefixlen, | 1760 | const struct in6_addr *prefix, int prefixlen, |
1694 | struct in6_addr *gwaddr, int ifindex) | 1761 | const struct in6_addr *gwaddr, int ifindex) |
1695 | { | 1762 | { |
1696 | struct fib6_node *fn; | 1763 | struct fib6_node *fn; |
1697 | struct rt6_info *rt = NULL; | 1764 | struct rt6_info *rt = NULL; |
@@ -1722,8 +1789,8 @@ out: | |||
1722 | } | 1789 | } |
1723 | 1790 | ||
1724 | static struct rt6_info *rt6_add_route_info(struct net *net, | 1791 | static struct rt6_info *rt6_add_route_info(struct net *net, |
1725 | struct in6_addr *prefix, int prefixlen, | 1792 | const struct in6_addr *prefix, int prefixlen, |
1726 | struct in6_addr *gwaddr, int ifindex, | 1793 | const struct in6_addr *gwaddr, int ifindex, |
1727 | unsigned pref) | 1794 | unsigned pref) |
1728 | { | 1795 | { |
1729 | struct fib6_config cfg = { | 1796 | struct fib6_config cfg = { |
@@ -1751,7 +1818,7 @@ static struct rt6_info *rt6_add_route_info(struct net *net, | |||
1751 | } | 1818 | } |
1752 | #endif | 1819 | #endif |
1753 | 1820 | ||
1754 | struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *dev) | 1821 | struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_device *dev) |
1755 | { | 1822 | { |
1756 | struct rt6_info *rt; | 1823 | struct rt6_info *rt; |
1757 | struct fib6_table *table; | 1824 | struct fib6_table *table; |
@@ -1773,7 +1840,7 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d | |||
1773 | return rt; | 1840 | return rt; |
1774 | } | 1841 | } |
1775 | 1842 | ||
1776 | struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr, | 1843 | struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr, |
1777 | struct net_device *dev, | 1844 | struct net_device *dev, |
1778 | unsigned int pref) | 1845 | unsigned int pref) |
1779 | { | 1846 | { |
@@ -1938,23 +2005,23 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, | |||
1938 | int anycast) | 2005 | int anycast) |
1939 | { | 2006 | { |
1940 | struct net *net = dev_net(idev->dev); | 2007 | struct net *net = dev_net(idev->dev); |
1941 | struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops); | 2008 | struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, |
2009 | net->loopback_dev, 0); | ||
1942 | struct neighbour *neigh; | 2010 | struct neighbour *neigh; |
1943 | 2011 | ||
1944 | if (rt == NULL) | 2012 | if (rt == NULL) { |
2013 | if (net_ratelimit()) | ||
2014 | pr_warning("IPv6: Maximum number of routes reached," | ||
2015 | " consider increasing route/max_size.\n"); | ||
1945 | return ERR_PTR(-ENOMEM); | 2016 | return ERR_PTR(-ENOMEM); |
2017 | } | ||
1946 | 2018 | ||
1947 | dev_hold(net->loopback_dev); | ||
1948 | in6_dev_hold(idev); | 2019 | in6_dev_hold(idev); |
1949 | 2020 | ||
1950 | rt->dst.flags = DST_HOST; | 2021 | rt->dst.flags |= DST_HOST; |
1951 | rt->dst.input = ip6_input; | 2022 | rt->dst.input = ip6_input; |
1952 | rt->dst.output = ip6_output; | 2023 | rt->dst.output = ip6_output; |
1953 | rt->rt6i_dev = net->loopback_dev; | ||
1954 | rt->rt6i_idev = idev; | 2024 | rt->rt6i_idev = idev; |
1955 | rt->dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev); | ||
1956 | rt->dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->dst)); | ||
1957 | rt->dst.metrics[RTAX_HOPLIMIT-1] = -1; | ||
1958 | rt->dst.obsolete = -1; | 2025 | rt->dst.obsolete = -1; |
1959 | 2026 | ||
1960 | rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP; | 2027 | rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP; |
@@ -1966,12 +2033,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, | |||
1966 | if (IS_ERR(neigh)) { | 2033 | if (IS_ERR(neigh)) { |
1967 | dst_free(&rt->dst); | 2034 | dst_free(&rt->dst); |
1968 | 2035 | ||
1969 | /* We are casting this because that is the return | 2036 | return ERR_CAST(neigh); |
1970 | * value type. But an errno encoded pointer is the | ||
1971 | * same regardless of the underlying pointer type, | ||
1972 | * and that's what we are returning. So this is OK. | ||
1973 | */ | ||
1974 | return (struct rt6_info *) neigh; | ||
1975 | } | 2037 | } |
1976 | rt->rt6i_nexthop = neigh; | 2038 | rt->rt6i_nexthop = neigh; |
1977 | 2039 | ||
@@ -1984,6 +2046,55 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, | |||
1984 | return rt; | 2046 | return rt; |
1985 | } | 2047 | } |
1986 | 2048 | ||
2049 | int ip6_route_get_saddr(struct net *net, | ||
2050 | struct rt6_info *rt, | ||
2051 | const struct in6_addr *daddr, | ||
2052 | unsigned int prefs, | ||
2053 | struct in6_addr *saddr) | ||
2054 | { | ||
2055 | struct inet6_dev *idev = ip6_dst_idev((struct dst_entry*)rt); | ||
2056 | int err = 0; | ||
2057 | if (rt->rt6i_prefsrc.plen) | ||
2058 | ipv6_addr_copy(saddr, &rt->rt6i_prefsrc.addr); | ||
2059 | else | ||
2060 | err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL, | ||
2061 | daddr, prefs, saddr); | ||
2062 | return err; | ||
2063 | } | ||
2064 | |||
2065 | /* remove deleted ip from prefsrc entries */ | ||
2066 | struct arg_dev_net_ip { | ||
2067 | struct net_device *dev; | ||
2068 | struct net *net; | ||
2069 | struct in6_addr *addr; | ||
2070 | }; | ||
2071 | |||
2072 | static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg) | ||
2073 | { | ||
2074 | struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev; | ||
2075 | struct net *net = ((struct arg_dev_net_ip *)arg)->net; | ||
2076 | struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr; | ||
2077 | |||
2078 | if (((void *)rt->rt6i_dev == dev || dev == NULL) && | ||
2079 | rt != net->ipv6.ip6_null_entry && | ||
2080 | ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) { | ||
2081 | /* remove prefsrc entry */ | ||
2082 | rt->rt6i_prefsrc.plen = 0; | ||
2083 | } | ||
2084 | return 0; | ||
2085 | } | ||
2086 | |||
2087 | void rt6_remove_prefsrc(struct inet6_ifaddr *ifp) | ||
2088 | { | ||
2089 | struct net *net = dev_net(ifp->idev->dev); | ||
2090 | struct arg_dev_net_ip adni = { | ||
2091 | .dev = ifp->idev->dev, | ||
2092 | .net = net, | ||
2093 | .addr = &ifp->addr, | ||
2094 | }; | ||
2095 | fib6_clean_all(net, fib6_remove_prefsrc, 0, &adni); | ||
2096 | } | ||
2097 | |||
1987 | struct arg_dev_net { | 2098 | struct arg_dev_net { |
1988 | struct net_device *dev; | 2099 | struct net_device *dev; |
1989 | struct net *net; | 2100 | struct net *net; |
@@ -1991,11 +2102,11 @@ struct arg_dev_net { | |||
1991 | 2102 | ||
1992 | static int fib6_ifdown(struct rt6_info *rt, void *arg) | 2103 | static int fib6_ifdown(struct rt6_info *rt, void *arg) |
1993 | { | 2104 | { |
1994 | struct net_device *dev = ((struct arg_dev_net *)arg)->dev; | 2105 | const struct arg_dev_net *adn = arg; |
1995 | struct net *net = ((struct arg_dev_net *)arg)->net; | 2106 | const struct net_device *dev = adn->dev; |
1996 | 2107 | ||
1997 | if (((void *)rt->rt6i_dev == dev || dev == NULL) && | 2108 | if ((rt->rt6i_dev == dev || dev == NULL) && |
1998 | rt != net->ipv6.ip6_null_entry) { | 2109 | rt != adn->net->ipv6.ip6_null_entry) { |
1999 | RT6_TRACE("deleted by ifdown %p\n", rt); | 2110 | RT6_TRACE("deleted by ifdown %p\n", rt); |
2000 | return -1; | 2111 | return -1; |
2001 | } | 2112 | } |
@@ -2023,7 +2134,6 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg) | |||
2023 | { | 2134 | { |
2024 | struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg; | 2135 | struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg; |
2025 | struct inet6_dev *idev; | 2136 | struct inet6_dev *idev; |
2026 | struct net *net = dev_net(arg->dev); | ||
2027 | 2137 | ||
2028 | /* In IPv6 pmtu discovery is not optional, | 2138 | /* In IPv6 pmtu discovery is not optional, |
2029 | so that RTAX_MTU lock cannot disable it. | 2139 | so that RTAX_MTU lock cannot disable it. |
@@ -2054,8 +2164,7 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg) | |||
2054 | (dst_mtu(&rt->dst) >= arg->mtu || | 2164 | (dst_mtu(&rt->dst) >= arg->mtu || |
2055 | (dst_mtu(&rt->dst) < arg->mtu && | 2165 | (dst_mtu(&rt->dst) < arg->mtu && |
2056 | dst_mtu(&rt->dst) == idev->cnf.mtu6))) { | 2166 | dst_mtu(&rt->dst) == idev->cnf.mtu6))) { |
2057 | rt->dst.metrics[RTAX_MTU-1] = arg->mtu; | 2167 | dst_metric_set(&rt->dst, RTAX_MTU, arg->mtu); |
2058 | rt->dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, arg->mtu); | ||
2059 | } | 2168 | } |
2060 | return 0; | 2169 | return 0; |
2061 | } | 2170 | } |
@@ -2102,6 +2211,9 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
2102 | if (rtm->rtm_type == RTN_UNREACHABLE) | 2211 | if (rtm->rtm_type == RTN_UNREACHABLE) |
2103 | cfg->fc_flags |= RTF_REJECT; | 2212 | cfg->fc_flags |= RTF_REJECT; |
2104 | 2213 | ||
2214 | if (rtm->rtm_type == RTN_LOCAL) | ||
2215 | cfg->fc_flags |= RTF_LOCAL; | ||
2216 | |||
2105 | cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid; | 2217 | cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid; |
2106 | cfg->fc_nlinfo.nlh = nlh; | 2218 | cfg->fc_nlinfo.nlh = nlh; |
2107 | cfg->fc_nlinfo.nl_net = sock_net(skb->sk); | 2219 | cfg->fc_nlinfo.nl_net = sock_net(skb->sk); |
@@ -2129,6 +2241,9 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
2129 | nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen); | 2241 | nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen); |
2130 | } | 2242 | } |
2131 | 2243 | ||
2244 | if (tb[RTA_PREFSRC]) | ||
2245 | nla_memcpy(&cfg->fc_prefsrc, tb[RTA_PREFSRC], 16); | ||
2246 | |||
2132 | if (tb[RTA_OIF]) | 2247 | if (tb[RTA_OIF]) |
2133 | cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]); | 2248 | cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]); |
2134 | 2249 | ||
@@ -2222,6 +2337,8 @@ static int rt6_fill_node(struct net *net, | |||
2222 | NLA_PUT_U32(skb, RTA_TABLE, table); | 2337 | NLA_PUT_U32(skb, RTA_TABLE, table); |
2223 | if (rt->rt6i_flags&RTF_REJECT) | 2338 | if (rt->rt6i_flags&RTF_REJECT) |
2224 | rtm->rtm_type = RTN_UNREACHABLE; | 2339 | rtm->rtm_type = RTN_UNREACHABLE; |
2340 | else if (rt->rt6i_flags&RTF_LOCAL) | ||
2341 | rtm->rtm_type = RTN_LOCAL; | ||
2225 | else if (rt->rt6i_dev && (rt->rt6i_dev->flags&IFF_LOOPBACK)) | 2342 | else if (rt->rt6i_dev && (rt->rt6i_dev->flags&IFF_LOOPBACK)) |
2226 | rtm->rtm_type = RTN_LOCAL; | 2343 | rtm->rtm_type = RTN_LOCAL; |
2227 | else | 2344 | else |
@@ -2269,14 +2386,18 @@ static int rt6_fill_node(struct net *net, | |||
2269 | #endif | 2386 | #endif |
2270 | NLA_PUT_U32(skb, RTA_IIF, iif); | 2387 | NLA_PUT_U32(skb, RTA_IIF, iif); |
2271 | } else if (dst) { | 2388 | } else if (dst) { |
2272 | struct inet6_dev *idev = ip6_dst_idev(&rt->dst); | ||
2273 | struct in6_addr saddr_buf; | 2389 | struct in6_addr saddr_buf; |
2274 | if (ipv6_dev_get_saddr(net, idev ? idev->dev : NULL, | 2390 | if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0) |
2275 | dst, 0, &saddr_buf) == 0) | ||
2276 | NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); | 2391 | NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); |
2277 | } | 2392 | } |
2278 | 2393 | ||
2279 | if (rtnetlink_put_metrics(skb, rt->dst.metrics) < 0) | 2394 | if (rt->rt6i_prefsrc.plen) { |
2395 | struct in6_addr saddr_buf; | ||
2396 | ipv6_addr_copy(&saddr_buf, &rt->rt6i_prefsrc.addr); | ||
2397 | NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); | ||
2398 | } | ||
2399 | |||
2400 | if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0) | ||
2280 | goto nla_put_failure; | 2401 | goto nla_put_failure; |
2281 | 2402 | ||
2282 | if (rt->dst.neighbour) | 2403 | if (rt->dst.neighbour) |
@@ -2329,7 +2450,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void | |||
2329 | struct rt6_info *rt; | 2450 | struct rt6_info *rt; |
2330 | struct sk_buff *skb; | 2451 | struct sk_buff *skb; |
2331 | struct rtmsg *rtm; | 2452 | struct rtmsg *rtm; |
2332 | struct flowi fl; | 2453 | struct flowi6 fl6; |
2333 | int err, iif = 0; | 2454 | int err, iif = 0; |
2334 | 2455 | ||
2335 | err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy); | 2456 | err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy); |
@@ -2337,27 +2458,27 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void | |||
2337 | goto errout; | 2458 | goto errout; |
2338 | 2459 | ||
2339 | err = -EINVAL; | 2460 | err = -EINVAL; |
2340 | memset(&fl, 0, sizeof(fl)); | 2461 | memset(&fl6, 0, sizeof(fl6)); |
2341 | 2462 | ||
2342 | if (tb[RTA_SRC]) { | 2463 | if (tb[RTA_SRC]) { |
2343 | if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr)) | 2464 | if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr)) |
2344 | goto errout; | 2465 | goto errout; |
2345 | 2466 | ||
2346 | ipv6_addr_copy(&fl.fl6_src, nla_data(tb[RTA_SRC])); | 2467 | ipv6_addr_copy(&fl6.saddr, nla_data(tb[RTA_SRC])); |
2347 | } | 2468 | } |
2348 | 2469 | ||
2349 | if (tb[RTA_DST]) { | 2470 | if (tb[RTA_DST]) { |
2350 | if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr)) | 2471 | if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr)) |
2351 | goto errout; | 2472 | goto errout; |
2352 | 2473 | ||
2353 | ipv6_addr_copy(&fl.fl6_dst, nla_data(tb[RTA_DST])); | 2474 | ipv6_addr_copy(&fl6.daddr, nla_data(tb[RTA_DST])); |
2354 | } | 2475 | } |
2355 | 2476 | ||
2356 | if (tb[RTA_IIF]) | 2477 | if (tb[RTA_IIF]) |
2357 | iif = nla_get_u32(tb[RTA_IIF]); | 2478 | iif = nla_get_u32(tb[RTA_IIF]); |
2358 | 2479 | ||
2359 | if (tb[RTA_OIF]) | 2480 | if (tb[RTA_OIF]) |
2360 | fl.oif = nla_get_u32(tb[RTA_OIF]); | 2481 | fl6.flowi6_oif = nla_get_u32(tb[RTA_OIF]); |
2361 | 2482 | ||
2362 | if (iif) { | 2483 | if (iif) { |
2363 | struct net_device *dev; | 2484 | struct net_device *dev; |
@@ -2380,10 +2501,10 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void | |||
2380 | skb_reset_mac_header(skb); | 2501 | skb_reset_mac_header(skb); |
2381 | skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr)); | 2502 | skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr)); |
2382 | 2503 | ||
2383 | rt = (struct rt6_info*) ip6_route_output(net, NULL, &fl); | 2504 | rt = (struct rt6_info*) ip6_route_output(net, NULL, &fl6); |
2384 | skb_dst_set(skb, &rt->dst); | 2505 | skb_dst_set(skb, &rt->dst); |
2385 | 2506 | ||
2386 | err = rt6_fill_node(net, skb, rt, &fl.fl6_dst, &fl.fl6_src, iif, | 2507 | err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif, |
2387 | RTM_NEWROUTE, NETLINK_CB(in_skb).pid, | 2508 | RTM_NEWROUTE, NETLINK_CB(in_skb).pid, |
2388 | nlh->nlmsg_seq, 0, 0, 0); | 2509 | nlh->nlmsg_seq, 0, 0, 0); |
2389 | if (err < 0) { | 2510 | if (err < 0) { |
@@ -2452,8 +2573,6 @@ static int ip6_route_dev_notify(struct notifier_block *this, | |||
2452 | 2573 | ||
2453 | #ifdef CONFIG_PROC_FS | 2574 | #ifdef CONFIG_PROC_FS |
2454 | 2575 | ||
2455 | #define RT6_INFO_LEN (32 + 4 + 32 + 4 + 32 + 40 + 5 + 1) | ||
2456 | |||
2457 | struct rt6_proc_arg | 2576 | struct rt6_proc_arg |
2458 | { | 2577 | { |
2459 | char *buffer; | 2578 | char *buffer; |
@@ -2516,7 +2635,7 @@ static int rt6_stats_seq_show(struct seq_file *seq, void *v) | |||
2516 | net->ipv6.rt6_stats->fib_rt_alloc, | 2635 | net->ipv6.rt6_stats->fib_rt_alloc, |
2517 | net->ipv6.rt6_stats->fib_rt_entries, | 2636 | net->ipv6.rt6_stats->fib_rt_entries, |
2518 | net->ipv6.rt6_stats->fib_rt_cache, | 2637 | net->ipv6.rt6_stats->fib_rt_cache, |
2519 | atomic_read(&net->ipv6.ip6_dst_ops.entries), | 2638 | dst_entries_get_slow(&net->ipv6.ip6_dst_ops), |
2520 | net->ipv6.rt6_stats->fib_discarded_routes); | 2639 | net->ipv6.rt6_stats->fib_discarded_routes); |
2521 | 2640 | ||
2522 | return 0; | 2641 | return 0; |
@@ -2542,14 +2661,16 @@ static | |||
2542 | int ipv6_sysctl_rtcache_flush(ctl_table *ctl, int write, | 2661 | int ipv6_sysctl_rtcache_flush(ctl_table *ctl, int write, |
2543 | void __user *buffer, size_t *lenp, loff_t *ppos) | 2662 | void __user *buffer, size_t *lenp, loff_t *ppos) |
2544 | { | 2663 | { |
2545 | struct net *net = current->nsproxy->net_ns; | 2664 | struct net *net; |
2546 | int delay = net->ipv6.sysctl.flush_delay; | 2665 | int delay; |
2547 | if (write) { | 2666 | if (!write) |
2548 | proc_dointvec(ctl, write, buffer, lenp, ppos); | ||
2549 | fib6_run_gc(delay <= 0 ? ~0UL : (unsigned long)delay, net); | ||
2550 | return 0; | ||
2551 | } else | ||
2552 | return -EINVAL; | 2667 | return -EINVAL; |
2668 | |||
2669 | net = (struct net *)ctl->extra1; | ||
2670 | delay = net->ipv6.sysctl.flush_delay; | ||
2671 | proc_dointvec(ctl, write, buffer, lenp, ppos); | ||
2672 | fib6_run_gc(delay <= 0 ? ~0UL : (unsigned long)delay, net); | ||
2673 | return 0; | ||
2553 | } | 2674 | } |
2554 | 2675 | ||
2555 | ctl_table ipv6_route_table_template[] = { | 2676 | ctl_table ipv6_route_table_template[] = { |
@@ -2636,6 +2757,7 @@ struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net) | |||
2636 | 2757 | ||
2637 | if (table) { | 2758 | if (table) { |
2638 | table[0].data = &net->ipv6.sysctl.flush_delay; | 2759 | table[0].data = &net->ipv6.sysctl.flush_delay; |
2760 | table[0].extra1 = net; | ||
2639 | table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh; | 2761 | table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh; |
2640 | table[2].data = &net->ipv6.sysctl.ip6_rt_max_size; | 2762 | table[2].data = &net->ipv6.sysctl.ip6_rt_max_size; |
2641 | table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval; | 2763 | table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval; |
@@ -2658,14 +2780,19 @@ static int __net_init ip6_route_net_init(struct net *net) | |||
2658 | memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template, | 2780 | memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template, |
2659 | sizeof(net->ipv6.ip6_dst_ops)); | 2781 | sizeof(net->ipv6.ip6_dst_ops)); |
2660 | 2782 | ||
2783 | if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0) | ||
2784 | goto out_ip6_dst_ops; | ||
2785 | |||
2661 | net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template, | 2786 | net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template, |
2662 | sizeof(*net->ipv6.ip6_null_entry), | 2787 | sizeof(*net->ipv6.ip6_null_entry), |
2663 | GFP_KERNEL); | 2788 | GFP_KERNEL); |
2664 | if (!net->ipv6.ip6_null_entry) | 2789 | if (!net->ipv6.ip6_null_entry) |
2665 | goto out_ip6_dst_ops; | 2790 | goto out_ip6_dst_entries; |
2666 | net->ipv6.ip6_null_entry->dst.path = | 2791 | net->ipv6.ip6_null_entry->dst.path = |
2667 | (struct dst_entry *)net->ipv6.ip6_null_entry; | 2792 | (struct dst_entry *)net->ipv6.ip6_null_entry; |
2668 | net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops; | 2793 | net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops; |
2794 | dst_init_metrics(&net->ipv6.ip6_null_entry->dst, | ||
2795 | ip6_template_metrics, true); | ||
2669 | 2796 | ||
2670 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | 2797 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES |
2671 | net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, | 2798 | net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, |
@@ -2676,6 +2803,8 @@ static int __net_init ip6_route_net_init(struct net *net) | |||
2676 | net->ipv6.ip6_prohibit_entry->dst.path = | 2803 | net->ipv6.ip6_prohibit_entry->dst.path = |
2677 | (struct dst_entry *)net->ipv6.ip6_prohibit_entry; | 2804 | (struct dst_entry *)net->ipv6.ip6_prohibit_entry; |
2678 | net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops; | 2805 | net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops; |
2806 | dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst, | ||
2807 | ip6_template_metrics, true); | ||
2679 | 2808 | ||
2680 | net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template, | 2809 | net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template, |
2681 | sizeof(*net->ipv6.ip6_blk_hole_entry), | 2810 | sizeof(*net->ipv6.ip6_blk_hole_entry), |
@@ -2685,6 +2814,8 @@ static int __net_init ip6_route_net_init(struct net *net) | |||
2685 | net->ipv6.ip6_blk_hole_entry->dst.path = | 2814 | net->ipv6.ip6_blk_hole_entry->dst.path = |
2686 | (struct dst_entry *)net->ipv6.ip6_blk_hole_entry; | 2815 | (struct dst_entry *)net->ipv6.ip6_blk_hole_entry; |
2687 | net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops; | 2816 | net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops; |
2817 | dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst, | ||
2818 | ip6_template_metrics, true); | ||
2688 | #endif | 2819 | #endif |
2689 | 2820 | ||
2690 | net->ipv6.sysctl.flush_delay = 0; | 2821 | net->ipv6.sysctl.flush_delay = 0; |
@@ -2712,6 +2843,8 @@ out_ip6_prohibit_entry: | |||
2712 | out_ip6_null_entry: | 2843 | out_ip6_null_entry: |
2713 | kfree(net->ipv6.ip6_null_entry); | 2844 | kfree(net->ipv6.ip6_null_entry); |
2714 | #endif | 2845 | #endif |
2846 | out_ip6_dst_entries: | ||
2847 | dst_entries_destroy(&net->ipv6.ip6_dst_ops); | ||
2715 | out_ip6_dst_ops: | 2848 | out_ip6_dst_ops: |
2716 | goto out; | 2849 | goto out; |
2717 | } | 2850 | } |
@@ -2727,6 +2860,7 @@ static void __net_exit ip6_route_net_exit(struct net *net) | |||
2727 | kfree(net->ipv6.ip6_prohibit_entry); | 2860 | kfree(net->ipv6.ip6_prohibit_entry); |
2728 | kfree(net->ipv6.ip6_blk_hole_entry); | 2861 | kfree(net->ipv6.ip6_blk_hole_entry); |
2729 | #endif | 2862 | #endif |
2863 | dst_entries_destroy(&net->ipv6.ip6_dst_ops); | ||
2730 | } | 2864 | } |
2731 | 2865 | ||
2732 | static struct pernet_operations ip6_route_net_ops = { | 2866 | static struct pernet_operations ip6_route_net_ops = { |
@@ -2750,10 +2884,14 @@ int __init ip6_route_init(void) | |||
2750 | if (!ip6_dst_ops_template.kmem_cachep) | 2884 | if (!ip6_dst_ops_template.kmem_cachep) |
2751 | goto out; | 2885 | goto out; |
2752 | 2886 | ||
2753 | ret = register_pernet_subsys(&ip6_route_net_ops); | 2887 | ret = dst_entries_init(&ip6_dst_blackhole_ops); |
2754 | if (ret) | 2888 | if (ret) |
2755 | goto out_kmem_cache; | 2889 | goto out_kmem_cache; |
2756 | 2890 | ||
2891 | ret = register_pernet_subsys(&ip6_route_net_ops); | ||
2892 | if (ret) | ||
2893 | goto out_dst_entries; | ||
2894 | |||
2757 | ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep; | 2895 | ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep; |
2758 | 2896 | ||
2759 | /* Registering of the loopback is done before this portion of code, | 2897 | /* Registering of the loopback is done before this portion of code, |
@@ -2800,6 +2938,8 @@ out_fib6_init: | |||
2800 | fib6_gc_cleanup(); | 2938 | fib6_gc_cleanup(); |
2801 | out_register_subsys: | 2939 | out_register_subsys: |
2802 | unregister_pernet_subsys(&ip6_route_net_ops); | 2940 | unregister_pernet_subsys(&ip6_route_net_ops); |
2941 | out_dst_entries: | ||
2942 | dst_entries_destroy(&ip6_dst_blackhole_ops); | ||
2803 | out_kmem_cache: | 2943 | out_kmem_cache: |
2804 | kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep); | 2944 | kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep); |
2805 | goto out; | 2945 | goto out; |
@@ -2812,5 +2952,6 @@ void ip6_route_cleanup(void) | |||
2812 | xfrm6_fini(); | 2952 | xfrm6_fini(); |
2813 | fib6_gc_cleanup(); | 2953 | fib6_gc_cleanup(); |
2814 | unregister_pernet_subsys(&ip6_route_net_ops); | 2954 | unregister_pernet_subsys(&ip6_route_net_ops); |
2955 | dst_entries_destroy(&ip6_dst_blackhole_ops); | ||
2815 | kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep); | 2956 | kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep); |
2816 | } | 2957 | } |
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 4699cd3c3118..1cca5761aea9 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
@@ -63,36 +63,63 @@ | |||
63 | #define HASH_SIZE 16 | 63 | #define HASH_SIZE 16 |
64 | #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) | 64 | #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) |
65 | 65 | ||
66 | static void ipip6_tunnel_init(struct net_device *dev); | 66 | static int ipip6_tunnel_init(struct net_device *dev); |
67 | static void ipip6_tunnel_setup(struct net_device *dev); | 67 | static void ipip6_tunnel_setup(struct net_device *dev); |
68 | static void ipip6_dev_free(struct net_device *dev); | ||
68 | 69 | ||
69 | static int sit_net_id __read_mostly; | 70 | static int sit_net_id __read_mostly; |
70 | struct sit_net { | 71 | struct sit_net { |
71 | struct ip_tunnel *tunnels_r_l[HASH_SIZE]; | 72 | struct ip_tunnel __rcu *tunnels_r_l[HASH_SIZE]; |
72 | struct ip_tunnel *tunnels_r[HASH_SIZE]; | 73 | struct ip_tunnel __rcu *tunnels_r[HASH_SIZE]; |
73 | struct ip_tunnel *tunnels_l[HASH_SIZE]; | 74 | struct ip_tunnel __rcu *tunnels_l[HASH_SIZE]; |
74 | struct ip_tunnel *tunnels_wc[1]; | 75 | struct ip_tunnel __rcu *tunnels_wc[1]; |
75 | struct ip_tunnel **tunnels[4]; | 76 | struct ip_tunnel __rcu **tunnels[4]; |
76 | 77 | ||
77 | struct net_device *fb_tunnel_dev; | 78 | struct net_device *fb_tunnel_dev; |
78 | }; | 79 | }; |
79 | 80 | ||
80 | /* | 81 | /* |
81 | * Locking : hash tables are protected by RCU and a spinlock | 82 | * Locking : hash tables are protected by RCU and RTNL |
82 | */ | 83 | */ |
83 | static DEFINE_SPINLOCK(ipip6_lock); | ||
84 | 84 | ||
85 | #define for_each_ip_tunnel_rcu(start) \ | 85 | #define for_each_ip_tunnel_rcu(start) \ |
86 | for (t = rcu_dereference(start); t; t = rcu_dereference(t->next)) | 86 | for (t = rcu_dereference(start); t; t = rcu_dereference(t->next)) |
87 | 87 | ||
88 | /* often modified stats are per cpu, other are shared (netdev->stats) */ | ||
89 | struct pcpu_tstats { | ||
90 | unsigned long rx_packets; | ||
91 | unsigned long rx_bytes; | ||
92 | unsigned long tx_packets; | ||
93 | unsigned long tx_bytes; | ||
94 | }; | ||
95 | |||
96 | static struct net_device_stats *ipip6_get_stats(struct net_device *dev) | ||
97 | { | ||
98 | struct pcpu_tstats sum = { 0 }; | ||
99 | int i; | ||
100 | |||
101 | for_each_possible_cpu(i) { | ||
102 | const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i); | ||
103 | |||
104 | sum.rx_packets += tstats->rx_packets; | ||
105 | sum.rx_bytes += tstats->rx_bytes; | ||
106 | sum.tx_packets += tstats->tx_packets; | ||
107 | sum.tx_bytes += tstats->tx_bytes; | ||
108 | } | ||
109 | dev->stats.rx_packets = sum.rx_packets; | ||
110 | dev->stats.rx_bytes = sum.rx_bytes; | ||
111 | dev->stats.tx_packets = sum.tx_packets; | ||
112 | dev->stats.tx_bytes = sum.tx_bytes; | ||
113 | return &dev->stats; | ||
114 | } | ||
88 | /* | 115 | /* |
89 | * Must be invoked with rcu_read_lock | 116 | * Must be invoked with rcu_read_lock |
90 | */ | 117 | */ |
91 | static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, | 118 | static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, |
92 | struct net_device *dev, __be32 remote, __be32 local) | 119 | struct net_device *dev, __be32 remote, __be32 local) |
93 | { | 120 | { |
94 | unsigned h0 = HASH(remote); | 121 | unsigned int h0 = HASH(remote); |
95 | unsigned h1 = HASH(local); | 122 | unsigned int h1 = HASH(local); |
96 | struct ip_tunnel *t; | 123 | struct ip_tunnel *t; |
97 | struct sit_net *sitn = net_generic(net, sit_net_id); | 124 | struct sit_net *sitn = net_generic(net, sit_net_id); |
98 | 125 | ||
@@ -121,12 +148,12 @@ static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, | |||
121 | return NULL; | 148 | return NULL; |
122 | } | 149 | } |
123 | 150 | ||
124 | static struct ip_tunnel **__ipip6_bucket(struct sit_net *sitn, | 151 | static struct ip_tunnel __rcu **__ipip6_bucket(struct sit_net *sitn, |
125 | struct ip_tunnel_parm *parms) | 152 | struct ip_tunnel_parm *parms) |
126 | { | 153 | { |
127 | __be32 remote = parms->iph.daddr; | 154 | __be32 remote = parms->iph.daddr; |
128 | __be32 local = parms->iph.saddr; | 155 | __be32 local = parms->iph.saddr; |
129 | unsigned h = 0; | 156 | unsigned int h = 0; |
130 | int prio = 0; | 157 | int prio = 0; |
131 | 158 | ||
132 | if (remote) { | 159 | if (remote) { |
@@ -140,7 +167,7 @@ static struct ip_tunnel **__ipip6_bucket(struct sit_net *sitn, | |||
140 | return &sitn->tunnels[prio][h]; | 167 | return &sitn->tunnels[prio][h]; |
141 | } | 168 | } |
142 | 169 | ||
143 | static inline struct ip_tunnel **ipip6_bucket(struct sit_net *sitn, | 170 | static inline struct ip_tunnel __rcu **ipip6_bucket(struct sit_net *sitn, |
144 | struct ip_tunnel *t) | 171 | struct ip_tunnel *t) |
145 | { | 172 | { |
146 | return __ipip6_bucket(sitn, &t->parms); | 173 | return __ipip6_bucket(sitn, &t->parms); |
@@ -148,13 +175,14 @@ static inline struct ip_tunnel **ipip6_bucket(struct sit_net *sitn, | |||
148 | 175 | ||
149 | static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t) | 176 | static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t) |
150 | { | 177 | { |
151 | struct ip_tunnel **tp; | 178 | struct ip_tunnel __rcu **tp; |
152 | 179 | struct ip_tunnel *iter; | |
153 | for (tp = ipip6_bucket(sitn, t); *tp; tp = &(*tp)->next) { | 180 | |
154 | if (t == *tp) { | 181 | for (tp = ipip6_bucket(sitn, t); |
155 | spin_lock_bh(&ipip6_lock); | 182 | (iter = rtnl_dereference(*tp)) != NULL; |
156 | *tp = t->next; | 183 | tp = &iter->next) { |
157 | spin_unlock_bh(&ipip6_lock); | 184 | if (t == iter) { |
185 | rcu_assign_pointer(*tp, t->next); | ||
158 | break; | 186 | break; |
159 | } | 187 | } |
160 | } | 188 | } |
@@ -162,12 +190,10 @@ static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t) | |||
162 | 190 | ||
163 | static void ipip6_tunnel_link(struct sit_net *sitn, struct ip_tunnel *t) | 191 | static void ipip6_tunnel_link(struct sit_net *sitn, struct ip_tunnel *t) |
164 | { | 192 | { |
165 | struct ip_tunnel **tp = ipip6_bucket(sitn, t); | 193 | struct ip_tunnel __rcu **tp = ipip6_bucket(sitn, t); |
166 | 194 | ||
167 | spin_lock_bh(&ipip6_lock); | 195 | rcu_assign_pointer(t->next, rtnl_dereference(*tp)); |
168 | t->next = *tp; | ||
169 | rcu_assign_pointer(*tp, t); | 196 | rcu_assign_pointer(*tp, t); |
170 | spin_unlock_bh(&ipip6_lock); | ||
171 | } | 197 | } |
172 | 198 | ||
173 | static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn) | 199 | static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn) |
@@ -187,17 +213,20 @@ static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn) | |||
187 | #endif | 213 | #endif |
188 | } | 214 | } |
189 | 215 | ||
190 | static struct ip_tunnel * ipip6_tunnel_locate(struct net *net, | 216 | static struct ip_tunnel *ipip6_tunnel_locate(struct net *net, |
191 | struct ip_tunnel_parm *parms, int create) | 217 | struct ip_tunnel_parm *parms, int create) |
192 | { | 218 | { |
193 | __be32 remote = parms->iph.daddr; | 219 | __be32 remote = parms->iph.daddr; |
194 | __be32 local = parms->iph.saddr; | 220 | __be32 local = parms->iph.saddr; |
195 | struct ip_tunnel *t, **tp, *nt; | 221 | struct ip_tunnel *t, *nt; |
222 | struct ip_tunnel __rcu **tp; | ||
196 | struct net_device *dev; | 223 | struct net_device *dev; |
197 | char name[IFNAMSIZ]; | 224 | char name[IFNAMSIZ]; |
198 | struct sit_net *sitn = net_generic(net, sit_net_id); | 225 | struct sit_net *sitn = net_generic(net, sit_net_id); |
199 | 226 | ||
200 | for (tp = __ipip6_bucket(sitn, parms); (t = *tp) != NULL; tp = &t->next) { | 227 | for (tp = __ipip6_bucket(sitn, parms); |
228 | (t = rtnl_dereference(*tp)) != NULL; | ||
229 | tp = &t->next) { | ||
201 | if (local == t->parms.iph.saddr && | 230 | if (local == t->parms.iph.saddr && |
202 | remote == t->parms.iph.daddr && | 231 | remote == t->parms.iph.daddr && |
203 | parms->link == t->parms.link) { | 232 | parms->link == t->parms.link) { |
@@ -213,7 +242,7 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct net *net, | |||
213 | if (parms->name[0]) | 242 | if (parms->name[0]) |
214 | strlcpy(name, parms->name, IFNAMSIZ); | 243 | strlcpy(name, parms->name, IFNAMSIZ); |
215 | else | 244 | else |
216 | sprintf(name, "sit%%d"); | 245 | strcpy(name, "sit%d"); |
217 | 246 | ||
218 | dev = alloc_netdev(sizeof(*t), name, ipip6_tunnel_setup); | 247 | dev = alloc_netdev(sizeof(*t), name, ipip6_tunnel_setup); |
219 | if (dev == NULL) | 248 | if (dev == NULL) |
@@ -221,15 +250,11 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct net *net, | |||
221 | 250 | ||
222 | dev_net_set(dev, net); | 251 | dev_net_set(dev, net); |
223 | 252 | ||
224 | if (strchr(name, '%')) { | ||
225 | if (dev_alloc_name(dev, name) < 0) | ||
226 | goto failed_free; | ||
227 | } | ||
228 | |||
229 | nt = netdev_priv(dev); | 253 | nt = netdev_priv(dev); |
230 | 254 | ||
231 | nt->parms = *parms; | 255 | nt->parms = *parms; |
232 | ipip6_tunnel_init(dev); | 256 | if (ipip6_tunnel_init(dev) < 0) |
257 | goto failed_free; | ||
233 | ipip6_tunnel_clone_6rd(dev, sitn); | 258 | ipip6_tunnel_clone_6rd(dev, sitn); |
234 | 259 | ||
235 | if (parms->i_flags & SIT_ISATAP) | 260 | if (parms->i_flags & SIT_ISATAP) |
@@ -244,7 +269,7 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct net *net, | |||
244 | return nt; | 269 | return nt; |
245 | 270 | ||
246 | failed_free: | 271 | failed_free: |
247 | free_netdev(dev); | 272 | ipip6_dev_free(dev); |
248 | failed: | 273 | failed: |
249 | return NULL; | 274 | return NULL; |
250 | } | 275 | } |
@@ -340,7 +365,7 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg) | |||
340 | 365 | ||
341 | ASSERT_RTNL(); | 366 | ASSERT_RTNL(); |
342 | 367 | ||
343 | for (p = t->prl; p; p = p->next) { | 368 | for (p = rtnl_dereference(t->prl); p; p = rtnl_dereference(p->next)) { |
344 | if (p->addr == a->addr) { | 369 | if (p->addr == a->addr) { |
345 | if (chg) { | 370 | if (chg) { |
346 | p->flags = a->flags; | 371 | p->flags = a->flags; |
@@ -371,18 +396,13 @@ out: | |||
371 | return err; | 396 | return err; |
372 | } | 397 | } |
373 | 398 | ||
374 | static void prl_entry_destroy_rcu(struct rcu_head *head) | ||
375 | { | ||
376 | kfree(container_of(head, struct ip_tunnel_prl_entry, rcu_head)); | ||
377 | } | ||
378 | |||
379 | static void prl_list_destroy_rcu(struct rcu_head *head) | 399 | static void prl_list_destroy_rcu(struct rcu_head *head) |
380 | { | 400 | { |
381 | struct ip_tunnel_prl_entry *p, *n; | 401 | struct ip_tunnel_prl_entry *p, *n; |
382 | 402 | ||
383 | p = container_of(head, struct ip_tunnel_prl_entry, rcu_head); | 403 | p = container_of(head, struct ip_tunnel_prl_entry, rcu_head); |
384 | do { | 404 | do { |
385 | n = p->next; | 405 | n = rcu_dereference_protected(p->next, 1); |
386 | kfree(p); | 406 | kfree(p); |
387 | p = n; | 407 | p = n; |
388 | } while (p); | 408 | } while (p); |
@@ -391,26 +411,28 @@ static void prl_list_destroy_rcu(struct rcu_head *head) | |||
391 | static int | 411 | static int |
392 | ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) | 412 | ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) |
393 | { | 413 | { |
394 | struct ip_tunnel_prl_entry *x, **p; | 414 | struct ip_tunnel_prl_entry *x; |
415 | struct ip_tunnel_prl_entry __rcu **p; | ||
395 | int err = 0; | 416 | int err = 0; |
396 | 417 | ||
397 | ASSERT_RTNL(); | 418 | ASSERT_RTNL(); |
398 | 419 | ||
399 | if (a && a->addr != htonl(INADDR_ANY)) { | 420 | if (a && a->addr != htonl(INADDR_ANY)) { |
400 | for (p = &t->prl; *p; p = &(*p)->next) { | 421 | for (p = &t->prl; |
401 | if ((*p)->addr == a->addr) { | 422 | (x = rtnl_dereference(*p)) != NULL; |
402 | x = *p; | 423 | p = &x->next) { |
424 | if (x->addr == a->addr) { | ||
403 | *p = x->next; | 425 | *p = x->next; |
404 | call_rcu(&x->rcu_head, prl_entry_destroy_rcu); | 426 | kfree_rcu(x, rcu_head); |
405 | t->prl_count--; | 427 | t->prl_count--; |
406 | goto out; | 428 | goto out; |
407 | } | 429 | } |
408 | } | 430 | } |
409 | err = -ENXIO; | 431 | err = -ENXIO; |
410 | } else { | 432 | } else { |
411 | if (t->prl) { | 433 | x = rtnl_dereference(t->prl); |
434 | if (x) { | ||
412 | t->prl_count = 0; | 435 | t->prl_count = 0; |
413 | x = t->prl; | ||
414 | call_rcu(&x->rcu_head, prl_list_destroy_rcu); | 436 | call_rcu(&x->rcu_head, prl_list_destroy_rcu); |
415 | t->prl = NULL; | 437 | t->prl = NULL; |
416 | } | 438 | } |
@@ -420,7 +442,7 @@ out: | |||
420 | } | 442 | } |
421 | 443 | ||
422 | static int | 444 | static int |
423 | isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t) | 445 | isatap_chksrc(struct sk_buff *skb, const struct iphdr *iph, struct ip_tunnel *t) |
424 | { | 446 | { |
425 | struct ip_tunnel_prl_entry *p; | 447 | struct ip_tunnel_prl_entry *p; |
426 | int ok = 1; | 448 | int ok = 1; |
@@ -433,7 +455,8 @@ isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t) | |||
433 | else | 455 | else |
434 | skb->ndisc_nodetype = NDISC_NODETYPE_NODEFAULT; | 456 | skb->ndisc_nodetype = NDISC_NODETYPE_NODEFAULT; |
435 | } else { | 457 | } else { |
436 | struct in6_addr *addr6 = &ipv6_hdr(skb)->saddr; | 458 | const struct in6_addr *addr6 = &ipv6_hdr(skb)->saddr; |
459 | |||
437 | if (ipv6_addr_is_isatap(addr6) && | 460 | if (ipv6_addr_is_isatap(addr6) && |
438 | (addr6->s6_addr32[3] == iph->saddr) && | 461 | (addr6->s6_addr32[3] == iph->saddr) && |
439 | ipv6_chk_prefix(addr6, t->dev)) | 462 | ipv6_chk_prefix(addr6, t->dev)) |
@@ -451,15 +474,12 @@ static void ipip6_tunnel_uninit(struct net_device *dev) | |||
451 | struct sit_net *sitn = net_generic(net, sit_net_id); | 474 | struct sit_net *sitn = net_generic(net, sit_net_id); |
452 | 475 | ||
453 | if (dev == sitn->fb_tunnel_dev) { | 476 | if (dev == sitn->fb_tunnel_dev) { |
454 | spin_lock_bh(&ipip6_lock); | 477 | rcu_assign_pointer(sitn->tunnels_wc[0], NULL); |
455 | sitn->tunnels_wc[0] = NULL; | ||
456 | spin_unlock_bh(&ipip6_lock); | ||
457 | dev_put(dev); | ||
458 | } else { | 478 | } else { |
459 | ipip6_tunnel_unlink(sitn, netdev_priv(dev)); | 479 | ipip6_tunnel_unlink(sitn, netdev_priv(dev)); |
460 | ipip6_tunnel_del_prl(netdev_priv(dev), NULL); | 480 | ipip6_tunnel_del_prl(netdev_priv(dev), NULL); |
461 | dev_put(dev); | ||
462 | } | 481 | } |
482 | dev_put(dev); | ||
463 | } | 483 | } |
464 | 484 | ||
465 | 485 | ||
@@ -470,7 +490,7 @@ static int ipip6_err(struct sk_buff *skb, u32 info) | |||
470 | 8 bytes of packet payload. It means, that precise relaying of | 490 | 8 bytes of packet payload. It means, that precise relaying of |
471 | ICMP in the real Internet is absolutely infeasible. | 491 | ICMP in the real Internet is absolutely infeasible. |
472 | */ | 492 | */ |
473 | struct iphdr *iph = (struct iphdr*)skb->data; | 493 | const struct iphdr *iph = (const struct iphdr *)skb->data; |
474 | const int type = icmp_hdr(skb)->type; | 494 | const int type = icmp_hdr(skb)->type; |
475 | const int code = icmp_hdr(skb)->code; | 495 | const int code = icmp_hdr(skb)->code; |
476 | struct ip_tunnel *t; | 496 | struct ip_tunnel *t; |
@@ -528,7 +548,7 @@ out: | |||
528 | return err; | 548 | return err; |
529 | } | 549 | } |
530 | 550 | ||
531 | static inline void ipip6_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb) | 551 | static inline void ipip6_ecn_decapsulate(const struct iphdr *iph, struct sk_buff *skb) |
532 | { | 552 | { |
533 | if (INET_ECN_is_ce(iph->tos)) | 553 | if (INET_ECN_is_ce(iph->tos)) |
534 | IP6_ECN_set_ce(ipv6_hdr(skb)); | 554 | IP6_ECN_set_ce(ipv6_hdr(skb)); |
@@ -536,7 +556,7 @@ static inline void ipip6_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb) | |||
536 | 556 | ||
537 | static int ipip6_rcv(struct sk_buff *skb) | 557 | static int ipip6_rcv(struct sk_buff *skb) |
538 | { | 558 | { |
539 | struct iphdr *iph; | 559 | const struct iphdr *iph; |
540 | struct ip_tunnel *tunnel; | 560 | struct ip_tunnel *tunnel; |
541 | 561 | ||
542 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) | 562 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) |
@@ -548,6 +568,8 @@ static int ipip6_rcv(struct sk_buff *skb) | |||
548 | tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev, | 568 | tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev, |
549 | iph->saddr, iph->daddr); | 569 | iph->saddr, iph->daddr); |
550 | if (tunnel != NULL) { | 570 | if (tunnel != NULL) { |
571 | struct pcpu_tstats *tstats; | ||
572 | |||
551 | secpath_reset(skb); | 573 | secpath_reset(skb); |
552 | skb->mac_header = skb->network_header; | 574 | skb->mac_header = skb->network_header; |
553 | skb_reset_network_header(skb); | 575 | skb_reset_network_header(skb); |
@@ -563,16 +585,23 @@ static int ipip6_rcv(struct sk_buff *skb) | |||
563 | return 0; | 585 | return 0; |
564 | } | 586 | } |
565 | 587 | ||
566 | skb_tunnel_rx(skb, tunnel->dev); | 588 | tstats = this_cpu_ptr(tunnel->dev->tstats); |
589 | tstats->rx_packets++; | ||
590 | tstats->rx_bytes += skb->len; | ||
591 | |||
592 | __skb_tunnel_rx(skb, tunnel->dev); | ||
567 | 593 | ||
568 | ipip6_ecn_decapsulate(iph, skb); | 594 | ipip6_ecn_decapsulate(iph, skb); |
595 | |||
569 | netif_rx(skb); | 596 | netif_rx(skb); |
597 | |||
570 | rcu_read_unlock(); | 598 | rcu_read_unlock(); |
571 | return 0; | 599 | return 0; |
572 | } | 600 | } |
573 | 601 | ||
574 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); | 602 | /* no tunnel matched, let upstream know, ipsec may handle it */ |
575 | rcu_read_unlock(); | 603 | rcu_read_unlock(); |
604 | return 1; | ||
576 | out: | 605 | out: |
577 | kfree_skb(skb); | 606 | kfree_skb(skb); |
578 | return 0; | 607 | return 0; |
@@ -583,14 +612,14 @@ out: | |||
583 | * comes from 6rd / 6to4 (RFC 3056) addr space. | 612 | * comes from 6rd / 6to4 (RFC 3056) addr space. |
584 | */ | 613 | */ |
585 | static inline | 614 | static inline |
586 | __be32 try_6rd(struct in6_addr *v6dst, struct ip_tunnel *tunnel) | 615 | __be32 try_6rd(const struct in6_addr *v6dst, struct ip_tunnel *tunnel) |
587 | { | 616 | { |
588 | __be32 dst = 0; | 617 | __be32 dst = 0; |
589 | 618 | ||
590 | #ifdef CONFIG_IPV6_SIT_6RD | 619 | #ifdef CONFIG_IPV6_SIT_6RD |
591 | if (ipv6_prefix_equal(v6dst, &tunnel->ip6rd.prefix, | 620 | if (ipv6_prefix_equal(v6dst, &tunnel->ip6rd.prefix, |
592 | tunnel->ip6rd.prefixlen)) { | 621 | tunnel->ip6rd.prefixlen)) { |
593 | unsigned pbw0, pbi0; | 622 | unsigned int pbw0, pbi0; |
594 | int pbi1; | 623 | int pbi1; |
595 | u32 d; | 624 | u32 d; |
596 | 625 | ||
@@ -625,19 +654,19 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
625 | struct net_device *dev) | 654 | struct net_device *dev) |
626 | { | 655 | { |
627 | struct ip_tunnel *tunnel = netdev_priv(dev); | 656 | struct ip_tunnel *tunnel = netdev_priv(dev); |
628 | struct net_device_stats *stats = &dev->stats; | 657 | struct pcpu_tstats *tstats; |
629 | struct netdev_queue *txq = netdev_get_tx_queue(dev, 0); | 658 | const struct iphdr *tiph = &tunnel->parms.iph; |
630 | struct iphdr *tiph = &tunnel->parms.iph; | 659 | const struct ipv6hdr *iph6 = ipv6_hdr(skb); |
631 | struct ipv6hdr *iph6 = ipv6_hdr(skb); | ||
632 | u8 tos = tunnel->parms.iph.tos; | 660 | u8 tos = tunnel->parms.iph.tos; |
633 | __be16 df = tiph->frag_off; | 661 | __be16 df = tiph->frag_off; |
634 | struct rtable *rt; /* Route to the other host */ | 662 | struct rtable *rt; /* Route to the other host */ |
635 | struct net_device *tdev; /* Device to other host */ | 663 | struct net_device *tdev; /* Device to other host */ |
636 | struct iphdr *iph; /* Our new IP header */ | 664 | struct iphdr *iph; /* Our new IP header */ |
637 | unsigned int max_headroom; /* The extra header space needed */ | 665 | unsigned int max_headroom; /* The extra header space needed */ |
638 | __be32 dst = tiph->daddr; | 666 | __be32 dst = tiph->daddr; |
667 | struct flowi4 fl4; | ||
639 | int mtu; | 668 | int mtu; |
640 | struct in6_addr *addr6; | 669 | const struct in6_addr *addr6; |
641 | int addr_type; | 670 | int addr_type; |
642 | 671 | ||
643 | if (skb->protocol != htons(ETH_P_IPV6)) | 672 | if (skb->protocol != htons(ETH_P_IPV6)) |
@@ -656,7 +685,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
656 | goto tx_error; | 685 | goto tx_error; |
657 | } | 686 | } |
658 | 687 | ||
659 | addr6 = (struct in6_addr*)&neigh->primary_key; | 688 | addr6 = (const struct in6_addr*)&neigh->primary_key; |
660 | addr_type = ipv6_addr_type(addr6); | 689 | addr_type = ipv6_addr_type(addr6); |
661 | 690 | ||
662 | if ((addr_type & IPV6_ADDR_UNICAST) && | 691 | if ((addr_type & IPV6_ADDR_UNICAST) && |
@@ -681,7 +710,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
681 | goto tx_error; | 710 | goto tx_error; |
682 | } | 711 | } |
683 | 712 | ||
684 | addr6 = (struct in6_addr*)&neigh->primary_key; | 713 | addr6 = (const struct in6_addr*)&neigh->primary_key; |
685 | addr_type = ipv6_addr_type(addr6); | 714 | addr_type = ipv6_addr_type(addr6); |
686 | 715 | ||
687 | if (addr_type == IPV6_ADDR_ANY) { | 716 | if (addr_type == IPV6_ADDR_ANY) { |
@@ -695,28 +724,25 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
695 | dst = addr6->s6_addr32[3]; | 724 | dst = addr6->s6_addr32[3]; |
696 | } | 725 | } |
697 | 726 | ||
698 | { | 727 | rt = ip_route_output_ports(dev_net(dev), &fl4, NULL, |
699 | struct flowi fl = { .nl_u = { .ip4_u = | 728 | dst, tiph->saddr, |
700 | { .daddr = dst, | 729 | 0, 0, |
701 | .saddr = tiph->saddr, | 730 | IPPROTO_IPV6, RT_TOS(tos), |
702 | .tos = RT_TOS(tos) } }, | 731 | tunnel->parms.link); |
703 | .oif = tunnel->parms.link, | 732 | if (IS_ERR(rt)) { |
704 | .proto = IPPROTO_IPV6 }; | 733 | dev->stats.tx_carrier_errors++; |
705 | if (ip_route_output_key(dev_net(dev), &rt, &fl)) { | 734 | goto tx_error_icmp; |
706 | stats->tx_carrier_errors++; | ||
707 | goto tx_error_icmp; | ||
708 | } | ||
709 | } | 735 | } |
710 | if (rt->rt_type != RTN_UNICAST) { | 736 | if (rt->rt_type != RTN_UNICAST) { |
711 | ip_rt_put(rt); | 737 | ip_rt_put(rt); |
712 | stats->tx_carrier_errors++; | 738 | dev->stats.tx_carrier_errors++; |
713 | goto tx_error_icmp; | 739 | goto tx_error_icmp; |
714 | } | 740 | } |
715 | tdev = rt->dst.dev; | 741 | tdev = rt->dst.dev; |
716 | 742 | ||
717 | if (tdev == dev) { | 743 | if (tdev == dev) { |
718 | ip_rt_put(rt); | 744 | ip_rt_put(rt); |
719 | stats->collisions++; | 745 | dev->stats.collisions++; |
720 | goto tx_error; | 746 | goto tx_error; |
721 | } | 747 | } |
722 | 748 | ||
@@ -724,7 +750,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
724 | mtu = dst_mtu(&rt->dst) - sizeof(struct iphdr); | 750 | mtu = dst_mtu(&rt->dst) - sizeof(struct iphdr); |
725 | 751 | ||
726 | if (mtu < 68) { | 752 | if (mtu < 68) { |
727 | stats->collisions++; | 753 | dev->stats.collisions++; |
728 | ip_rt_put(rt); | 754 | ip_rt_put(rt); |
729 | goto tx_error; | 755 | goto tx_error; |
730 | } | 756 | } |
@@ -763,7 +789,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
763 | struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom); | 789 | struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom); |
764 | if (!new_skb) { | 790 | if (!new_skb) { |
765 | ip_rt_put(rt); | 791 | ip_rt_put(rt); |
766 | txq->tx_dropped++; | 792 | dev->stats.tx_dropped++; |
767 | dev_kfree_skb(skb); | 793 | dev_kfree_skb(skb); |
768 | return NETDEV_TX_OK; | 794 | return NETDEV_TX_OK; |
769 | } | 795 | } |
@@ -792,21 +818,21 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
792 | iph->frag_off = df; | 818 | iph->frag_off = df; |
793 | iph->protocol = IPPROTO_IPV6; | 819 | iph->protocol = IPPROTO_IPV6; |
794 | iph->tos = INET_ECN_encapsulate(tos, ipv6_get_dsfield(iph6)); | 820 | iph->tos = INET_ECN_encapsulate(tos, ipv6_get_dsfield(iph6)); |
795 | iph->daddr = rt->rt_dst; | 821 | iph->daddr = fl4.daddr; |
796 | iph->saddr = rt->rt_src; | 822 | iph->saddr = fl4.saddr; |
797 | 823 | ||
798 | if ((iph->ttl = tiph->ttl) == 0) | 824 | if ((iph->ttl = tiph->ttl) == 0) |
799 | iph->ttl = iph6->hop_limit; | 825 | iph->ttl = iph6->hop_limit; |
800 | 826 | ||
801 | nf_reset(skb); | 827 | nf_reset(skb); |
802 | 828 | tstats = this_cpu_ptr(dev->tstats); | |
803 | IPTUNNEL_XMIT(); | 829 | __IPTUNNEL_XMIT(tstats, &dev->stats); |
804 | return NETDEV_TX_OK; | 830 | return NETDEV_TX_OK; |
805 | 831 | ||
806 | tx_error_icmp: | 832 | tx_error_icmp: |
807 | dst_link_failure(skb); | 833 | dst_link_failure(skb); |
808 | tx_error: | 834 | tx_error: |
809 | stats->tx_errors++; | 835 | dev->stats.tx_errors++; |
810 | dev_kfree_skb(skb); | 836 | dev_kfree_skb(skb); |
811 | return NETDEV_TX_OK; | 837 | return NETDEV_TX_OK; |
812 | } | 838 | } |
@@ -815,20 +841,21 @@ static void ipip6_tunnel_bind_dev(struct net_device *dev) | |||
815 | { | 841 | { |
816 | struct net_device *tdev = NULL; | 842 | struct net_device *tdev = NULL; |
817 | struct ip_tunnel *tunnel; | 843 | struct ip_tunnel *tunnel; |
818 | struct iphdr *iph; | 844 | const struct iphdr *iph; |
845 | struct flowi4 fl4; | ||
819 | 846 | ||
820 | tunnel = netdev_priv(dev); | 847 | tunnel = netdev_priv(dev); |
821 | iph = &tunnel->parms.iph; | 848 | iph = &tunnel->parms.iph; |
822 | 849 | ||
823 | if (iph->daddr) { | 850 | if (iph->daddr) { |
824 | struct flowi fl = { .nl_u = { .ip4_u = | 851 | struct rtable *rt = ip_route_output_ports(dev_net(dev), &fl4, NULL, |
825 | { .daddr = iph->daddr, | 852 | iph->daddr, iph->saddr, |
826 | .saddr = iph->saddr, | 853 | 0, 0, |
827 | .tos = RT_TOS(iph->tos) } }, | 854 | IPPROTO_IPV6, |
828 | .oif = tunnel->parms.link, | 855 | RT_TOS(iph->tos), |
829 | .proto = IPPROTO_IPV6 }; | 856 | tunnel->parms.link); |
830 | struct rtable *rt; | 857 | |
831 | if (!ip_route_output_key(dev_net(dev), &rt, &fl)) { | 858 | if (!IS_ERR(rt)) { |
832 | tdev = rt->dst.dev; | 859 | tdev = rt->dst.dev; |
833 | ip_rt_put(rt); | 860 | ip_rt_put(rt); |
834 | } | 861 | } |
@@ -929,6 +956,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) | |||
929 | } | 956 | } |
930 | t = netdev_priv(dev); | 957 | t = netdev_priv(dev); |
931 | ipip6_tunnel_unlink(sitn, t); | 958 | ipip6_tunnel_unlink(sitn, t); |
959 | synchronize_net(); | ||
932 | t->parms.iph.saddr = p.iph.saddr; | 960 | t->parms.iph.saddr = p.iph.saddr; |
933 | t->parms.iph.daddr = p.iph.daddr; | 961 | t->parms.iph.daddr = p.iph.daddr; |
934 | memcpy(dev->dev_addr, &p.iph.saddr, 4); | 962 | memcpy(dev->dev_addr, &p.iph.saddr, 4); |
@@ -1083,12 +1111,19 @@ static const struct net_device_ops ipip6_netdev_ops = { | |||
1083 | .ndo_start_xmit = ipip6_tunnel_xmit, | 1111 | .ndo_start_xmit = ipip6_tunnel_xmit, |
1084 | .ndo_do_ioctl = ipip6_tunnel_ioctl, | 1112 | .ndo_do_ioctl = ipip6_tunnel_ioctl, |
1085 | .ndo_change_mtu = ipip6_tunnel_change_mtu, | 1113 | .ndo_change_mtu = ipip6_tunnel_change_mtu, |
1114 | .ndo_get_stats = ipip6_get_stats, | ||
1086 | }; | 1115 | }; |
1087 | 1116 | ||
1117 | static void ipip6_dev_free(struct net_device *dev) | ||
1118 | { | ||
1119 | free_percpu(dev->tstats); | ||
1120 | free_netdev(dev); | ||
1121 | } | ||
1122 | |||
1088 | static void ipip6_tunnel_setup(struct net_device *dev) | 1123 | static void ipip6_tunnel_setup(struct net_device *dev) |
1089 | { | 1124 | { |
1090 | dev->netdev_ops = &ipip6_netdev_ops; | 1125 | dev->netdev_ops = &ipip6_netdev_ops; |
1091 | dev->destructor = free_netdev; | 1126 | dev->destructor = ipip6_dev_free; |
1092 | 1127 | ||
1093 | dev->type = ARPHRD_SIT; | 1128 | dev->type = ARPHRD_SIT; |
1094 | dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr); | 1129 | dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr); |
@@ -1098,9 +1133,10 @@ static void ipip6_tunnel_setup(struct net_device *dev) | |||
1098 | dev->iflink = 0; | 1133 | dev->iflink = 0; |
1099 | dev->addr_len = 4; | 1134 | dev->addr_len = 4; |
1100 | dev->features |= NETIF_F_NETNS_LOCAL; | 1135 | dev->features |= NETIF_F_NETNS_LOCAL; |
1136 | dev->features |= NETIF_F_LLTX; | ||
1101 | } | 1137 | } |
1102 | 1138 | ||
1103 | static void ipip6_tunnel_init(struct net_device *dev) | 1139 | static int ipip6_tunnel_init(struct net_device *dev) |
1104 | { | 1140 | { |
1105 | struct ip_tunnel *tunnel = netdev_priv(dev); | 1141 | struct ip_tunnel *tunnel = netdev_priv(dev); |
1106 | 1142 | ||
@@ -1111,9 +1147,14 @@ static void ipip6_tunnel_init(struct net_device *dev) | |||
1111 | memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4); | 1147 | memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4); |
1112 | 1148 | ||
1113 | ipip6_tunnel_bind_dev(dev); | 1149 | ipip6_tunnel_bind_dev(dev); |
1150 | dev->tstats = alloc_percpu(struct pcpu_tstats); | ||
1151 | if (!dev->tstats) | ||
1152 | return -ENOMEM; | ||
1153 | |||
1154 | return 0; | ||
1114 | } | 1155 | } |
1115 | 1156 | ||
1116 | static void __net_init ipip6_fb_tunnel_init(struct net_device *dev) | 1157 | static int __net_init ipip6_fb_tunnel_init(struct net_device *dev) |
1117 | { | 1158 | { |
1118 | struct ip_tunnel *tunnel = netdev_priv(dev); | 1159 | struct ip_tunnel *tunnel = netdev_priv(dev); |
1119 | struct iphdr *iph = &tunnel->parms.iph; | 1160 | struct iphdr *iph = &tunnel->parms.iph; |
@@ -1128,11 +1169,15 @@ static void __net_init ipip6_fb_tunnel_init(struct net_device *dev) | |||
1128 | iph->ihl = 5; | 1169 | iph->ihl = 5; |
1129 | iph->ttl = 64; | 1170 | iph->ttl = 64; |
1130 | 1171 | ||
1172 | dev->tstats = alloc_percpu(struct pcpu_tstats); | ||
1173 | if (!dev->tstats) | ||
1174 | return -ENOMEM; | ||
1131 | dev_hold(dev); | 1175 | dev_hold(dev); |
1132 | sitn->tunnels_wc[0] = tunnel; | 1176 | rcu_assign_pointer(sitn->tunnels_wc[0], tunnel); |
1177 | return 0; | ||
1133 | } | 1178 | } |
1134 | 1179 | ||
1135 | static struct xfrm_tunnel sit_handler = { | 1180 | static struct xfrm_tunnel sit_handler __read_mostly = { |
1136 | .handler = ipip6_rcv, | 1181 | .handler = ipip6_rcv, |
1137 | .err_handler = ipip6_err, | 1182 | .err_handler = ipip6_err, |
1138 | .priority = 1, | 1183 | .priority = 1, |
@@ -1145,11 +1190,12 @@ static void __net_exit sit_destroy_tunnels(struct sit_net *sitn, struct list_hea | |||
1145 | for (prio = 1; prio < 4; prio++) { | 1190 | for (prio = 1; prio < 4; prio++) { |
1146 | int h; | 1191 | int h; |
1147 | for (h = 0; h < HASH_SIZE; h++) { | 1192 | for (h = 0; h < HASH_SIZE; h++) { |
1148 | struct ip_tunnel *t = sitn->tunnels[prio][h]; | 1193 | struct ip_tunnel *t; |
1149 | 1194 | ||
1195 | t = rtnl_dereference(sitn->tunnels[prio][h]); | ||
1150 | while (t != NULL) { | 1196 | while (t != NULL) { |
1151 | unregister_netdevice_queue(t->dev, head); | 1197 | unregister_netdevice_queue(t->dev, head); |
1152 | t = t->next; | 1198 | t = rtnl_dereference(t->next); |
1153 | } | 1199 | } |
1154 | } | 1200 | } |
1155 | } | 1201 | } |
@@ -1173,7 +1219,10 @@ static int __net_init sit_init_net(struct net *net) | |||
1173 | } | 1219 | } |
1174 | dev_net_set(sitn->fb_tunnel_dev, net); | 1220 | dev_net_set(sitn->fb_tunnel_dev, net); |
1175 | 1221 | ||
1176 | ipip6_fb_tunnel_init(sitn->fb_tunnel_dev); | 1222 | err = ipip6_fb_tunnel_init(sitn->fb_tunnel_dev); |
1223 | if (err) | ||
1224 | goto err_dev_free; | ||
1225 | |||
1177 | ipip6_tunnel_clone_6rd(sitn->fb_tunnel_dev, sitn); | 1226 | ipip6_tunnel_clone_6rd(sitn->fb_tunnel_dev, sitn); |
1178 | 1227 | ||
1179 | if ((err = register_netdev(sitn->fb_tunnel_dev))) | 1228 | if ((err = register_netdev(sitn->fb_tunnel_dev))) |
@@ -1183,7 +1232,8 @@ static int __net_init sit_init_net(struct net *net) | |||
1183 | 1232 | ||
1184 | err_reg_dev: | 1233 | err_reg_dev: |
1185 | dev_put(sitn->fb_tunnel_dev); | 1234 | dev_put(sitn->fb_tunnel_dev); |
1186 | free_netdev(sitn->fb_tunnel_dev); | 1235 | err_dev_free: |
1236 | ipip6_dev_free(sitn->fb_tunnel_dev); | ||
1187 | err_alloc_dev: | 1237 | err_alloc_dev: |
1188 | return err; | 1238 | return err; |
1189 | } | 1239 | } |
@@ -1235,4 +1285,4 @@ static int __init sit_init(void) | |||
1235 | module_init(sit_init); | 1285 | module_init(sit_init); |
1236 | module_exit(sit_cleanup); | 1286 | module_exit(sit_cleanup); |
1237 | MODULE_LICENSE("GPL"); | 1287 | MODULE_LICENSE("GPL"); |
1238 | MODULE_ALIAS("sit0"); | 1288 | MODULE_ALIAS_NETDEV("sit0"); |
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 09fd34f0dbf2..8b9644a8b697 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c | |||
@@ -66,7 +66,7 @@ static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb, | |||
66 | static DEFINE_PER_CPU(__u32 [16 + 5 + SHA_WORKSPACE_WORDS], | 66 | static DEFINE_PER_CPU(__u32 [16 + 5 + SHA_WORKSPACE_WORDS], |
67 | ipv6_cookie_scratch); | 67 | ipv6_cookie_scratch); |
68 | 68 | ||
69 | static u32 cookie_hash(struct in6_addr *saddr, struct in6_addr *daddr, | 69 | static u32 cookie_hash(const struct in6_addr *saddr, const struct in6_addr *daddr, |
70 | __be16 sport, __be16 dport, u32 count, int c) | 70 | __be16 sport, __be16 dport, u32 count, int c) |
71 | { | 71 | { |
72 | __u32 *tmp = __get_cpu_var(ipv6_cookie_scratch); | 72 | __u32 *tmp = __get_cpu_var(ipv6_cookie_scratch); |
@@ -86,7 +86,8 @@ static u32 cookie_hash(struct in6_addr *saddr, struct in6_addr *daddr, | |||
86 | return tmp[17]; | 86 | return tmp[17]; |
87 | } | 87 | } |
88 | 88 | ||
89 | static __u32 secure_tcp_syn_cookie(struct in6_addr *saddr, struct in6_addr *daddr, | 89 | static __u32 secure_tcp_syn_cookie(const struct in6_addr *saddr, |
90 | const struct in6_addr *daddr, | ||
90 | __be16 sport, __be16 dport, __u32 sseq, | 91 | __be16 sport, __be16 dport, __u32 sseq, |
91 | __u32 count, __u32 data) | 92 | __u32 count, __u32 data) |
92 | { | 93 | { |
@@ -96,8 +97,8 @@ static __u32 secure_tcp_syn_cookie(struct in6_addr *saddr, struct in6_addr *dadd | |||
96 | & COOKIEMASK)); | 97 | & COOKIEMASK)); |
97 | } | 98 | } |
98 | 99 | ||
99 | static __u32 check_tcp_syn_cookie(__u32 cookie, struct in6_addr *saddr, | 100 | static __u32 check_tcp_syn_cookie(__u32 cookie, const struct in6_addr *saddr, |
100 | struct in6_addr *daddr, __be16 sport, | 101 | const struct in6_addr *daddr, __be16 sport, |
101 | __be16 dport, __u32 sseq, __u32 count, | 102 | __be16 dport, __u32 sseq, __u32 count, |
102 | __u32 maxdiff) | 103 | __u32 maxdiff) |
103 | { | 104 | { |
@@ -116,7 +117,7 @@ static __u32 check_tcp_syn_cookie(__u32 cookie, struct in6_addr *saddr, | |||
116 | 117 | ||
117 | __u32 cookie_v6_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp) | 118 | __u32 cookie_v6_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp) |
118 | { | 119 | { |
119 | struct ipv6hdr *iph = ipv6_hdr(skb); | 120 | const struct ipv6hdr *iph = ipv6_hdr(skb); |
120 | const struct tcphdr *th = tcp_hdr(skb); | 121 | const struct tcphdr *th = tcp_hdr(skb); |
121 | int mssind; | 122 | int mssind; |
122 | const __u16 mss = *mssp; | 123 | const __u16 mss = *mssp; |
@@ -138,7 +139,7 @@ __u32 cookie_v6_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp) | |||
138 | 139 | ||
139 | static inline int cookie_check(struct sk_buff *skb, __u32 cookie) | 140 | static inline int cookie_check(struct sk_buff *skb, __u32 cookie) |
140 | { | 141 | { |
141 | struct ipv6hdr *iph = ipv6_hdr(skb); | 142 | const struct ipv6hdr *iph = ipv6_hdr(skb); |
142 | const struct tcphdr *th = tcp_hdr(skb); | 143 | const struct tcphdr *th = tcp_hdr(skb); |
143 | __u32 seq = ntohl(th->seq) - 1; | 144 | __u32 seq = ntohl(th->seq) - 1; |
144 | __u32 mssind = check_tcp_syn_cookie(cookie, &iph->saddr, &iph->daddr, | 145 | __u32 mssind = check_tcp_syn_cookie(cookie, &iph->saddr, &iph->daddr, |
@@ -232,23 +233,20 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
232 | */ | 233 | */ |
233 | { | 234 | { |
234 | struct in6_addr *final_p, final; | 235 | struct in6_addr *final_p, final; |
235 | struct flowi fl; | 236 | struct flowi6 fl6; |
236 | memset(&fl, 0, sizeof(fl)); | 237 | memset(&fl6, 0, sizeof(fl6)); |
237 | fl.proto = IPPROTO_TCP; | 238 | fl6.flowi6_proto = IPPROTO_TCP; |
238 | ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr); | 239 | ipv6_addr_copy(&fl6.daddr, &ireq6->rmt_addr); |
239 | final_p = fl6_update_dst(&fl, np->opt, &final); | 240 | final_p = fl6_update_dst(&fl6, np->opt, &final); |
240 | ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr); | 241 | ipv6_addr_copy(&fl6.saddr, &ireq6->loc_addr); |
241 | fl.oif = sk->sk_bound_dev_if; | 242 | fl6.flowi6_oif = sk->sk_bound_dev_if; |
242 | fl.mark = sk->sk_mark; | 243 | fl6.flowi6_mark = sk->sk_mark; |
243 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; | 244 | fl6.fl6_dport = inet_rsk(req)->rmt_port; |
244 | fl.fl_ip_sport = inet_sk(sk)->inet_sport; | 245 | fl6.fl6_sport = inet_sk(sk)->inet_sport; |
245 | security_req_classify_flow(req, &fl); | 246 | security_req_classify_flow(req, flowi6_to_flowi(&fl6)); |
246 | if (ip6_dst_lookup(sk, &dst, &fl)) | 247 | |
247 | goto out_free; | 248 | dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false); |
248 | 249 | if (IS_ERR(dst)) | |
249 | if (final_p) | ||
250 | ipv6_addr_copy(&fl.fl6_dst, final_p); | ||
251 | if ((xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0) | ||
252 | goto out_free; | 250 | goto out_free; |
253 | } | 251 | } |
254 | 252 | ||
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c index fa1d8f4e0051..6dcf5e7d661b 100644 --- a/net/ipv6/sysctl_net_ipv6.c +++ b/net/ipv6/sysctl_net_ipv6.c | |||
@@ -15,6 +15,18 @@ | |||
15 | #include <net/addrconf.h> | 15 | #include <net/addrconf.h> |
16 | #include <net/inet_frag.h> | 16 | #include <net/inet_frag.h> |
17 | 17 | ||
18 | static struct ctl_table empty[1]; | ||
19 | |||
20 | static ctl_table ipv6_static_skeleton[] = { | ||
21 | { | ||
22 | .procname = "neigh", | ||
23 | .maxlen = 0, | ||
24 | .mode = 0555, | ||
25 | .child = empty, | ||
26 | }, | ||
27 | { } | ||
28 | }; | ||
29 | |||
18 | static ctl_table ipv6_table_template[] = { | 30 | static ctl_table ipv6_table_template[] = { |
19 | { | 31 | { |
20 | .procname = "route", | 32 | .procname = "route", |
@@ -152,8 +164,7 @@ static struct ctl_table_header *ip6_base; | |||
152 | 164 | ||
153 | int ipv6_static_sysctl_register(void) | 165 | int ipv6_static_sysctl_register(void) |
154 | { | 166 | { |
155 | static struct ctl_table empty[1]; | 167 | ip6_base = register_sysctl_paths(net_ipv6_ctl_path, ipv6_static_skeleton); |
156 | ip6_base = register_sysctl_paths(net_ipv6_ctl_path, empty); | ||
157 | if (ip6_base == NULL) | 168 | if (ip6_base == NULL) |
158 | return -ENOMEM; | 169 | return -ENOMEM; |
159 | return 0; | 170 | return 0; |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index fe6d40418c0b..87551ca568cd 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -76,8 +76,8 @@ static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, | |||
76 | 76 | ||
77 | static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); | 77 | static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); |
78 | static void __tcp_v6_send_check(struct sk_buff *skb, | 78 | static void __tcp_v6_send_check(struct sk_buff *skb, |
79 | struct in6_addr *saddr, | 79 | const struct in6_addr *saddr, |
80 | struct in6_addr *daddr); | 80 | const struct in6_addr *daddr); |
81 | 81 | ||
82 | static const struct inet_connection_sock_af_ops ipv6_mapped; | 82 | static const struct inet_connection_sock_af_ops ipv6_mapped; |
83 | static const struct inet_connection_sock_af_ops ipv6_specific; | 83 | static const struct inet_connection_sock_af_ops ipv6_specific; |
@@ -86,7 +86,7 @@ static const struct tcp_sock_af_ops tcp_sock_ipv6_specific; | |||
86 | static const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific; | 86 | static const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific; |
87 | #else | 87 | #else |
88 | static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk, | 88 | static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk, |
89 | struct in6_addr *addr) | 89 | const struct in6_addr *addr) |
90 | { | 90 | { |
91 | return NULL; | 91 | return NULL; |
92 | } | 92 | } |
@@ -106,8 +106,8 @@ static void tcp_v6_hash(struct sock *sk) | |||
106 | } | 106 | } |
107 | 107 | ||
108 | static __inline__ __sum16 tcp_v6_check(int len, | 108 | static __inline__ __sum16 tcp_v6_check(int len, |
109 | struct in6_addr *saddr, | 109 | const struct in6_addr *saddr, |
110 | struct in6_addr *daddr, | 110 | const struct in6_addr *daddr, |
111 | __wsum base) | 111 | __wsum base) |
112 | { | 112 | { |
113 | return csum_ipv6_magic(saddr, daddr, len, IPPROTO_TCP, base); | 113 | return csum_ipv6_magic(saddr, daddr, len, IPPROTO_TCP, base); |
@@ -130,7 +130,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
130 | struct ipv6_pinfo *np = inet6_sk(sk); | 130 | struct ipv6_pinfo *np = inet6_sk(sk); |
131 | struct tcp_sock *tp = tcp_sk(sk); | 131 | struct tcp_sock *tp = tcp_sk(sk); |
132 | struct in6_addr *saddr = NULL, *final_p, final; | 132 | struct in6_addr *saddr = NULL, *final_p, final; |
133 | struct flowi fl; | 133 | struct rt6_info *rt; |
134 | struct flowi6 fl6; | ||
134 | struct dst_entry *dst; | 135 | struct dst_entry *dst; |
135 | int addr_type; | 136 | int addr_type; |
136 | int err; | 137 | int err; |
@@ -139,16 +140,16 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
139 | return -EINVAL; | 140 | return -EINVAL; |
140 | 141 | ||
141 | if (usin->sin6_family != AF_INET6) | 142 | if (usin->sin6_family != AF_INET6) |
142 | return(-EAFNOSUPPORT); | 143 | return -EAFNOSUPPORT; |
143 | 144 | ||
144 | memset(&fl, 0, sizeof(fl)); | 145 | memset(&fl6, 0, sizeof(fl6)); |
145 | 146 | ||
146 | if (np->sndflow) { | 147 | if (np->sndflow) { |
147 | fl.fl6_flowlabel = usin->sin6_flowinfo&IPV6_FLOWINFO_MASK; | 148 | fl6.flowlabel = usin->sin6_flowinfo&IPV6_FLOWINFO_MASK; |
148 | IP6_ECN_flow_init(fl.fl6_flowlabel); | 149 | IP6_ECN_flow_init(fl6.flowlabel); |
149 | if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) { | 150 | if (fl6.flowlabel&IPV6_FLOWLABEL_MASK) { |
150 | struct ip6_flowlabel *flowlabel; | 151 | struct ip6_flowlabel *flowlabel; |
151 | flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel); | 152 | flowlabel = fl6_sock_lookup(sk, fl6.flowlabel); |
152 | if (flowlabel == NULL) | 153 | if (flowlabel == NULL) |
153 | return -EINVAL; | 154 | return -EINVAL; |
154 | ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst); | 155 | ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst); |
@@ -194,7 +195,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
194 | } | 195 | } |
195 | 196 | ||
196 | ipv6_addr_copy(&np->daddr, &usin->sin6_addr); | 197 | ipv6_addr_copy(&np->daddr, &usin->sin6_addr); |
197 | np->flow_label = fl.fl6_flowlabel; | 198 | np->flow_label = fl6.flowlabel; |
198 | 199 | ||
199 | /* | 200 | /* |
200 | * TCP over IPv4 | 201 | * TCP over IPv4 |
@@ -241,35 +242,27 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
241 | if (!ipv6_addr_any(&np->rcv_saddr)) | 242 | if (!ipv6_addr_any(&np->rcv_saddr)) |
242 | saddr = &np->rcv_saddr; | 243 | saddr = &np->rcv_saddr; |
243 | 244 | ||
244 | fl.proto = IPPROTO_TCP; | 245 | fl6.flowi6_proto = IPPROTO_TCP; |
245 | ipv6_addr_copy(&fl.fl6_dst, &np->daddr); | 246 | ipv6_addr_copy(&fl6.daddr, &np->daddr); |
246 | ipv6_addr_copy(&fl.fl6_src, | 247 | ipv6_addr_copy(&fl6.saddr, |
247 | (saddr ? saddr : &np->saddr)); | 248 | (saddr ? saddr : &np->saddr)); |
248 | fl.oif = sk->sk_bound_dev_if; | 249 | fl6.flowi6_oif = sk->sk_bound_dev_if; |
249 | fl.mark = sk->sk_mark; | 250 | fl6.flowi6_mark = sk->sk_mark; |
250 | fl.fl_ip_dport = usin->sin6_port; | 251 | fl6.fl6_dport = usin->sin6_port; |
251 | fl.fl_ip_sport = inet->inet_sport; | 252 | fl6.fl6_sport = inet->inet_sport; |
252 | 253 | ||
253 | final_p = fl6_update_dst(&fl, np->opt, &final); | 254 | final_p = fl6_update_dst(&fl6, np->opt, &final); |
254 | 255 | ||
255 | security_sk_classify_flow(sk, &fl); | 256 | security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); |
256 | 257 | ||
257 | err = ip6_dst_lookup(sk, &dst, &fl); | 258 | dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true); |
258 | if (err) | 259 | if (IS_ERR(dst)) { |
260 | err = PTR_ERR(dst); | ||
259 | goto failure; | 261 | goto failure; |
260 | if (final_p) | ||
261 | ipv6_addr_copy(&fl.fl6_dst, final_p); | ||
262 | |||
263 | err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT); | ||
264 | if (err < 0) { | ||
265 | if (err == -EREMOTE) | ||
266 | err = ip6_dst_blackhole(sk, &dst, &fl); | ||
267 | if (err < 0) | ||
268 | goto failure; | ||
269 | } | 262 | } |
270 | 263 | ||
271 | if (saddr == NULL) { | 264 | if (saddr == NULL) { |
272 | saddr = &fl.fl6_src; | 265 | saddr = &fl6.saddr; |
273 | ipv6_addr_copy(&np->rcv_saddr, saddr); | 266 | ipv6_addr_copy(&np->rcv_saddr, saddr); |
274 | } | 267 | } |
275 | 268 | ||
@@ -280,6 +273,26 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
280 | sk->sk_gso_type = SKB_GSO_TCPV6; | 273 | sk->sk_gso_type = SKB_GSO_TCPV6; |
281 | __ip6_dst_store(sk, dst, NULL, NULL); | 274 | __ip6_dst_store(sk, dst, NULL, NULL); |
282 | 275 | ||
276 | rt = (struct rt6_info *) dst; | ||
277 | if (tcp_death_row.sysctl_tw_recycle && | ||
278 | !tp->rx_opt.ts_recent_stamp && | ||
279 | ipv6_addr_equal(&rt->rt6i_dst.addr, &np->daddr)) { | ||
280 | struct inet_peer *peer = rt6_get_peer(rt); | ||
281 | /* | ||
282 | * VJ's idea. We save last timestamp seen from | ||
283 | * the destination in peer table, when entering state | ||
284 | * TIME-WAIT * and initialize rx_opt.ts_recent from it, | ||
285 | * when trying new connection. | ||
286 | */ | ||
287 | if (peer) { | ||
288 | inet_peer_refcheck(peer); | ||
289 | if ((u32)get_seconds() - peer->tcp_ts_stamp <= TCP_PAWS_MSL) { | ||
290 | tp->rx_opt.ts_recent_stamp = peer->tcp_ts_stamp; | ||
291 | tp->rx_opt.ts_recent = peer->tcp_ts; | ||
292 | } | ||
293 | } | ||
294 | } | ||
295 | |||
283 | icsk->icsk_ext_hdr_len = 0; | 296 | icsk->icsk_ext_hdr_len = 0; |
284 | if (np->opt) | 297 | if (np->opt) |
285 | icsk->icsk_ext_hdr_len = (np->opt->opt_flen + | 298 | icsk->icsk_ext_hdr_len = (np->opt->opt_flen + |
@@ -318,7 +331,7 @@ failure: | |||
318 | static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | 331 | static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, |
319 | u8 type, u8 code, int offset, __be32 info) | 332 | u8 type, u8 code, int offset, __be32 info) |
320 | { | 333 | { |
321 | struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data; | 334 | const struct ipv6hdr *hdr = (const struct ipv6hdr*)skb->data; |
322 | const struct tcphdr *th = (struct tcphdr *)(skb->data+offset); | 335 | const struct tcphdr *th = (struct tcphdr *)(skb->data+offset); |
323 | struct ipv6_pinfo *np; | 336 | struct ipv6_pinfo *np; |
324 | struct sock *sk; | 337 | struct sock *sk; |
@@ -364,7 +377,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
364 | np = inet6_sk(sk); | 377 | np = inet6_sk(sk); |
365 | 378 | ||
366 | if (type == ICMPV6_PKT_TOOBIG) { | 379 | if (type == ICMPV6_PKT_TOOBIG) { |
367 | struct dst_entry *dst = NULL; | 380 | struct dst_entry *dst; |
368 | 381 | ||
369 | if (sock_owned_by_user(sk)) | 382 | if (sock_owned_by_user(sk)) |
370 | goto out; | 383 | goto out; |
@@ -376,29 +389,25 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
376 | 389 | ||
377 | if (dst == NULL) { | 390 | if (dst == NULL) { |
378 | struct inet_sock *inet = inet_sk(sk); | 391 | struct inet_sock *inet = inet_sk(sk); |
379 | struct flowi fl; | 392 | struct flowi6 fl6; |
380 | 393 | ||
381 | /* BUGGG_FUTURE: Again, it is not clear how | 394 | /* BUGGG_FUTURE: Again, it is not clear how |
382 | to handle rthdr case. Ignore this complexity | 395 | to handle rthdr case. Ignore this complexity |
383 | for now. | 396 | for now. |
384 | */ | 397 | */ |
385 | memset(&fl, 0, sizeof(fl)); | 398 | memset(&fl6, 0, sizeof(fl6)); |
386 | fl.proto = IPPROTO_TCP; | 399 | fl6.flowi6_proto = IPPROTO_TCP; |
387 | ipv6_addr_copy(&fl.fl6_dst, &np->daddr); | 400 | ipv6_addr_copy(&fl6.daddr, &np->daddr); |
388 | ipv6_addr_copy(&fl.fl6_src, &np->saddr); | 401 | ipv6_addr_copy(&fl6.saddr, &np->saddr); |
389 | fl.oif = sk->sk_bound_dev_if; | 402 | fl6.flowi6_oif = sk->sk_bound_dev_if; |
390 | fl.mark = sk->sk_mark; | 403 | fl6.flowi6_mark = sk->sk_mark; |
391 | fl.fl_ip_dport = inet->inet_dport; | 404 | fl6.fl6_dport = inet->inet_dport; |
392 | fl.fl_ip_sport = inet->inet_sport; | 405 | fl6.fl6_sport = inet->inet_sport; |
393 | security_skb_classify_flow(skb, &fl); | 406 | security_skb_classify_flow(skb, flowi6_to_flowi(&fl6)); |
394 | 407 | ||
395 | if ((err = ip6_dst_lookup(sk, &dst, &fl))) { | 408 | dst = ip6_dst_lookup_flow(sk, &fl6, NULL, false); |
396 | sk->sk_err_soft = -err; | 409 | if (IS_ERR(dst)) { |
397 | goto out; | 410 | sk->sk_err_soft = -PTR_ERR(dst); |
398 | } | ||
399 | |||
400 | if ((err = xfrm_lookup(net, &dst, &fl, sk, 0)) < 0) { | ||
401 | sk->sk_err_soft = -err; | ||
402 | goto out; | 411 | goto out; |
403 | } | 412 | } |
404 | 413 | ||
@@ -473,38 +482,37 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req, | |||
473 | struct sk_buff * skb; | 482 | struct sk_buff * skb; |
474 | struct ipv6_txoptions *opt = NULL; | 483 | struct ipv6_txoptions *opt = NULL; |
475 | struct in6_addr * final_p, final; | 484 | struct in6_addr * final_p, final; |
476 | struct flowi fl; | 485 | struct flowi6 fl6; |
477 | struct dst_entry *dst; | 486 | struct dst_entry *dst; |
478 | int err = -1; | 487 | int err; |
479 | 488 | ||
480 | memset(&fl, 0, sizeof(fl)); | 489 | memset(&fl6, 0, sizeof(fl6)); |
481 | fl.proto = IPPROTO_TCP; | 490 | fl6.flowi6_proto = IPPROTO_TCP; |
482 | ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr); | 491 | ipv6_addr_copy(&fl6.daddr, &treq->rmt_addr); |
483 | ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr); | 492 | ipv6_addr_copy(&fl6.saddr, &treq->loc_addr); |
484 | fl.fl6_flowlabel = 0; | 493 | fl6.flowlabel = 0; |
485 | fl.oif = treq->iif; | 494 | fl6.flowi6_oif = treq->iif; |
486 | fl.mark = sk->sk_mark; | 495 | fl6.flowi6_mark = sk->sk_mark; |
487 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; | 496 | fl6.fl6_dport = inet_rsk(req)->rmt_port; |
488 | fl.fl_ip_sport = inet_rsk(req)->loc_port; | 497 | fl6.fl6_sport = inet_rsk(req)->loc_port; |
489 | security_req_classify_flow(req, &fl); | 498 | security_req_classify_flow(req, flowi6_to_flowi(&fl6)); |
490 | 499 | ||
491 | opt = np->opt; | 500 | opt = np->opt; |
492 | final_p = fl6_update_dst(&fl, opt, &final); | 501 | final_p = fl6_update_dst(&fl6, opt, &final); |
493 | 502 | ||
494 | err = ip6_dst_lookup(sk, &dst, &fl); | 503 | dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false); |
495 | if (err) | 504 | if (IS_ERR(dst)) { |
496 | goto done; | 505 | err = PTR_ERR(dst); |
497 | if (final_p) | 506 | dst = NULL; |
498 | ipv6_addr_copy(&fl.fl6_dst, final_p); | ||
499 | if ((err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0) | ||
500 | goto done; | 507 | goto done; |
501 | 508 | } | |
502 | skb = tcp_make_synack(sk, dst, req, rvp); | 509 | skb = tcp_make_synack(sk, dst, req, rvp); |
510 | err = -ENOMEM; | ||
503 | if (skb) { | 511 | if (skb) { |
504 | __tcp_v6_send_check(skb, &treq->loc_addr, &treq->rmt_addr); | 512 | __tcp_v6_send_check(skb, &treq->loc_addr, &treq->rmt_addr); |
505 | 513 | ||
506 | ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr); | 514 | ipv6_addr_copy(&fl6.daddr, &treq->rmt_addr); |
507 | err = ip6_xmit(sk, skb, &fl, opt); | 515 | err = ip6_xmit(sk, skb, &fl6, opt); |
508 | err = net_xmit_eval(err); | 516 | err = net_xmit_eval(err); |
509 | } | 517 | } |
510 | 518 | ||
@@ -543,7 +551,7 @@ static void tcp_v6_reqsk_destructor(struct request_sock *req) | |||
543 | 551 | ||
544 | #ifdef CONFIG_TCP_MD5SIG | 552 | #ifdef CONFIG_TCP_MD5SIG |
545 | static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk, | 553 | static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk, |
546 | struct in6_addr *addr) | 554 | const struct in6_addr *addr) |
547 | { | 555 | { |
548 | struct tcp_sock *tp = tcp_sk(sk); | 556 | struct tcp_sock *tp = tcp_sk(sk); |
549 | int i; | 557 | int i; |
@@ -572,7 +580,7 @@ static struct tcp_md5sig_key *tcp_v6_reqsk_md5_lookup(struct sock *sk, | |||
572 | return tcp_v6_md5_do_lookup(sk, &inet6_rsk(req)->rmt_addr); | 580 | return tcp_v6_md5_do_lookup(sk, &inet6_rsk(req)->rmt_addr); |
573 | } | 581 | } |
574 | 582 | ||
575 | static int tcp_v6_md5_do_add(struct sock *sk, struct in6_addr *peer, | 583 | static int tcp_v6_md5_do_add(struct sock *sk, const struct in6_addr *peer, |
576 | char *newkey, u8 newkeylen) | 584 | char *newkey, u8 newkeylen) |
577 | { | 585 | { |
578 | /* Add key to the list */ | 586 | /* Add key to the list */ |
@@ -637,7 +645,7 @@ static int tcp_v6_md5_add_func(struct sock *sk, struct sock *addr_sk, | |||
637 | newkey, newkeylen); | 645 | newkey, newkeylen); |
638 | } | 646 | } |
639 | 647 | ||
640 | static int tcp_v6_md5_do_del(struct sock *sk, struct in6_addr *peer) | 648 | static int tcp_v6_md5_do_del(struct sock *sk, const struct in6_addr *peer) |
641 | { | 649 | { |
642 | struct tcp_sock *tp = tcp_sk(sk); | 650 | struct tcp_sock *tp = tcp_sk(sk); |
643 | int i; | 651 | int i; |
@@ -745,8 +753,8 @@ static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval, | |||
745 | } | 753 | } |
746 | 754 | ||
747 | static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp, | 755 | static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp, |
748 | struct in6_addr *daddr, | 756 | const struct in6_addr *daddr, |
749 | struct in6_addr *saddr, int nbytes) | 757 | const struct in6_addr *saddr, int nbytes) |
750 | { | 758 | { |
751 | struct tcp6_pseudohdr *bp; | 759 | struct tcp6_pseudohdr *bp; |
752 | struct scatterlist sg; | 760 | struct scatterlist sg; |
@@ -763,7 +771,7 @@ static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp, | |||
763 | } | 771 | } |
764 | 772 | ||
765 | static int tcp_v6_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key, | 773 | static int tcp_v6_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key, |
766 | struct in6_addr *daddr, struct in6_addr *saddr, | 774 | const struct in6_addr *daddr, struct in6_addr *saddr, |
767 | struct tcphdr *th) | 775 | struct tcphdr *th) |
768 | { | 776 | { |
769 | struct tcp_md5sig_pool *hp; | 777 | struct tcp_md5sig_pool *hp; |
@@ -799,7 +807,7 @@ static int tcp_v6_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key, | |||
799 | struct sock *sk, struct request_sock *req, | 807 | struct sock *sk, struct request_sock *req, |
800 | struct sk_buff *skb) | 808 | struct sk_buff *skb) |
801 | { | 809 | { |
802 | struct in6_addr *saddr, *daddr; | 810 | const struct in6_addr *saddr, *daddr; |
803 | struct tcp_md5sig_pool *hp; | 811 | struct tcp_md5sig_pool *hp; |
804 | struct hash_desc *desc; | 812 | struct hash_desc *desc; |
805 | struct tcphdr *th = tcp_hdr(skb); | 813 | struct tcphdr *th = tcp_hdr(skb); |
@@ -811,7 +819,7 @@ static int tcp_v6_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key, | |||
811 | saddr = &inet6_rsk(req)->loc_addr; | 819 | saddr = &inet6_rsk(req)->loc_addr; |
812 | daddr = &inet6_rsk(req)->rmt_addr; | 820 | daddr = &inet6_rsk(req)->rmt_addr; |
813 | } else { | 821 | } else { |
814 | struct ipv6hdr *ip6h = ipv6_hdr(skb); | 822 | const struct ipv6hdr *ip6h = ipv6_hdr(skb); |
815 | saddr = &ip6h->saddr; | 823 | saddr = &ip6h->saddr; |
816 | daddr = &ip6h->daddr; | 824 | daddr = &ip6h->daddr; |
817 | } | 825 | } |
@@ -849,7 +857,7 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) | |||
849 | { | 857 | { |
850 | __u8 *hash_location = NULL; | 858 | __u8 *hash_location = NULL; |
851 | struct tcp_md5sig_key *hash_expected; | 859 | struct tcp_md5sig_key *hash_expected; |
852 | struct ipv6hdr *ip6h = ipv6_hdr(skb); | 860 | const struct ipv6hdr *ip6h = ipv6_hdr(skb); |
853 | struct tcphdr *th = tcp_hdr(skb); | 861 | struct tcphdr *th = tcp_hdr(skb); |
854 | int genhash; | 862 | int genhash; |
855 | u8 newhash[16]; | 863 | u8 newhash[16]; |
@@ -906,14 +914,8 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { | |||
906 | }; | 914 | }; |
907 | #endif | 915 | #endif |
908 | 916 | ||
909 | static struct timewait_sock_ops tcp6_timewait_sock_ops = { | ||
910 | .twsk_obj_size = sizeof(struct tcp6_timewait_sock), | ||
911 | .twsk_unique = tcp_twsk_unique, | ||
912 | .twsk_destructor= tcp_twsk_destructor, | ||
913 | }; | ||
914 | |||
915 | static void __tcp_v6_send_check(struct sk_buff *skb, | 917 | static void __tcp_v6_send_check(struct sk_buff *skb, |
916 | struct in6_addr *saddr, struct in6_addr *daddr) | 918 | const struct in6_addr *saddr, const struct in6_addr *daddr) |
917 | { | 919 | { |
918 | struct tcphdr *th = tcp_hdr(skb); | 920 | struct tcphdr *th = tcp_hdr(skb); |
919 | 921 | ||
@@ -937,7 +939,7 @@ static void tcp_v6_send_check(struct sock *sk, struct sk_buff *skb) | |||
937 | 939 | ||
938 | static int tcp_v6_gso_send_check(struct sk_buff *skb) | 940 | static int tcp_v6_gso_send_check(struct sk_buff *skb) |
939 | { | 941 | { |
940 | struct ipv6hdr *ipv6h; | 942 | const struct ipv6hdr *ipv6h; |
941 | struct tcphdr *th; | 943 | struct tcphdr *th; |
942 | 944 | ||
943 | if (!pskb_may_pull(skb, sizeof(*th))) | 945 | if (!pskb_may_pull(skb, sizeof(*th))) |
@@ -955,7 +957,7 @@ static int tcp_v6_gso_send_check(struct sk_buff *skb) | |||
955 | static struct sk_buff **tcp6_gro_receive(struct sk_buff **head, | 957 | static struct sk_buff **tcp6_gro_receive(struct sk_buff **head, |
956 | struct sk_buff *skb) | 958 | struct sk_buff *skb) |
957 | { | 959 | { |
958 | struct ipv6hdr *iph = skb_gro_network_header(skb); | 960 | const struct ipv6hdr *iph = skb_gro_network_header(skb); |
959 | 961 | ||
960 | switch (skb->ip_summed) { | 962 | switch (skb->ip_summed) { |
961 | case CHECKSUM_COMPLETE: | 963 | case CHECKSUM_COMPLETE: |
@@ -976,7 +978,7 @@ static struct sk_buff **tcp6_gro_receive(struct sk_buff **head, | |||
976 | 978 | ||
977 | static int tcp6_gro_complete(struct sk_buff *skb) | 979 | static int tcp6_gro_complete(struct sk_buff *skb) |
978 | { | 980 | { |
979 | struct ipv6hdr *iph = ipv6_hdr(skb); | 981 | const struct ipv6hdr *iph = ipv6_hdr(skb); |
980 | struct tcphdr *th = tcp_hdr(skb); | 982 | struct tcphdr *th = tcp_hdr(skb); |
981 | 983 | ||
982 | th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb), | 984 | th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb), |
@@ -991,7 +993,7 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, | |||
991 | { | 993 | { |
992 | struct tcphdr *th = tcp_hdr(skb), *t1; | 994 | struct tcphdr *th = tcp_hdr(skb), *t1; |
993 | struct sk_buff *buff; | 995 | struct sk_buff *buff; |
994 | struct flowi fl; | 996 | struct flowi6 fl6; |
995 | struct net *net = dev_net(skb_dst(skb)->dev); | 997 | struct net *net = dev_net(skb_dst(skb)->dev); |
996 | struct sock *ctl_sk = net->ipv6.tcp_sk; | 998 | struct sock *ctl_sk = net->ipv6.tcp_sk; |
997 | unsigned int tot_len = sizeof(struct tcphdr); | 999 | unsigned int tot_len = sizeof(struct tcphdr); |
@@ -1045,34 +1047,33 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, | |||
1045 | } | 1047 | } |
1046 | #endif | 1048 | #endif |
1047 | 1049 | ||
1048 | memset(&fl, 0, sizeof(fl)); | 1050 | memset(&fl6, 0, sizeof(fl6)); |
1049 | ipv6_addr_copy(&fl.fl6_dst, &ipv6_hdr(skb)->saddr); | 1051 | ipv6_addr_copy(&fl6.daddr, &ipv6_hdr(skb)->saddr); |
1050 | ipv6_addr_copy(&fl.fl6_src, &ipv6_hdr(skb)->daddr); | 1052 | ipv6_addr_copy(&fl6.saddr, &ipv6_hdr(skb)->daddr); |
1051 | 1053 | ||
1052 | buff->ip_summed = CHECKSUM_PARTIAL; | 1054 | buff->ip_summed = CHECKSUM_PARTIAL; |
1053 | buff->csum = 0; | 1055 | buff->csum = 0; |
1054 | 1056 | ||
1055 | __tcp_v6_send_check(buff, &fl.fl6_src, &fl.fl6_dst); | 1057 | __tcp_v6_send_check(buff, &fl6.saddr, &fl6.daddr); |
1056 | 1058 | ||
1057 | fl.proto = IPPROTO_TCP; | 1059 | fl6.flowi6_proto = IPPROTO_TCP; |
1058 | fl.oif = inet6_iif(skb); | 1060 | fl6.flowi6_oif = inet6_iif(skb); |
1059 | fl.fl_ip_dport = t1->dest; | 1061 | fl6.fl6_dport = t1->dest; |
1060 | fl.fl_ip_sport = t1->source; | 1062 | fl6.fl6_sport = t1->source; |
1061 | security_skb_classify_flow(skb, &fl); | 1063 | security_skb_classify_flow(skb, flowi6_to_flowi(&fl6)); |
1062 | 1064 | ||
1063 | /* Pass a socket to ip6_dst_lookup either it is for RST | 1065 | /* Pass a socket to ip6_dst_lookup either it is for RST |
1064 | * Underlying function will use this to retrieve the network | 1066 | * Underlying function will use this to retrieve the network |
1065 | * namespace | 1067 | * namespace |
1066 | */ | 1068 | */ |
1067 | if (!ip6_dst_lookup(ctl_sk, &dst, &fl)) { | 1069 | dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL, false); |
1068 | if (xfrm_lookup(net, &dst, &fl, NULL, 0) >= 0) { | 1070 | if (!IS_ERR(dst)) { |
1069 | skb_dst_set(buff, dst); | 1071 | skb_dst_set(buff, dst); |
1070 | ip6_xmit(ctl_sk, buff, &fl, NULL); | 1072 | ip6_xmit(ctl_sk, buff, &fl6, NULL); |
1071 | TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); | 1073 | TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); |
1072 | if (rst) | 1074 | if (rst) |
1073 | TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS); | 1075 | TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS); |
1074 | return; | 1076 | return; |
1075 | } | ||
1076 | } | 1077 | } |
1077 | 1078 | ||
1078 | kfree_skb(buff); | 1079 | kfree_skb(buff); |
@@ -1176,6 +1177,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1176 | struct ipv6_pinfo *np = inet6_sk(sk); | 1177 | struct ipv6_pinfo *np = inet6_sk(sk); |
1177 | struct tcp_sock *tp = tcp_sk(sk); | 1178 | struct tcp_sock *tp = tcp_sk(sk); |
1178 | __u32 isn = TCP_SKB_CB(skb)->when; | 1179 | __u32 isn = TCP_SKB_CB(skb)->when; |
1180 | struct dst_entry *dst = NULL; | ||
1179 | #ifdef CONFIG_SYN_COOKIES | 1181 | #ifdef CONFIG_SYN_COOKIES |
1180 | int want_cookie = 0; | 1182 | int want_cookie = 0; |
1181 | #else | 1183 | #else |
@@ -1273,6 +1275,8 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1273 | TCP_ECN_create_request(req, tcp_hdr(skb)); | 1275 | TCP_ECN_create_request(req, tcp_hdr(skb)); |
1274 | 1276 | ||
1275 | if (!isn) { | 1277 | if (!isn) { |
1278 | struct inet_peer *peer = NULL; | ||
1279 | |||
1276 | if (ipv6_opt_accepted(sk, skb) || | 1280 | if (ipv6_opt_accepted(sk, skb) || |
1277 | np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || | 1281 | np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || |
1278 | np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) { | 1282 | np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) { |
@@ -1285,13 +1289,57 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1285 | if (!sk->sk_bound_dev_if && | 1289 | if (!sk->sk_bound_dev_if && |
1286 | ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL) | 1290 | ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL) |
1287 | treq->iif = inet6_iif(skb); | 1291 | treq->iif = inet6_iif(skb); |
1288 | if (!want_cookie) { | 1292 | |
1289 | isn = tcp_v6_init_sequence(skb); | 1293 | if (want_cookie) { |
1290 | } else { | ||
1291 | isn = cookie_v6_init_sequence(sk, skb, &req->mss); | 1294 | isn = cookie_v6_init_sequence(sk, skb, &req->mss); |
1292 | req->cookie_ts = tmp_opt.tstamp_ok; | 1295 | req->cookie_ts = tmp_opt.tstamp_ok; |
1296 | goto have_isn; | ||
1297 | } | ||
1298 | |||
1299 | /* VJ's idea. We save last timestamp seen | ||
1300 | * from the destination in peer table, when entering | ||
1301 | * state TIME-WAIT, and check against it before | ||
1302 | * accepting new connection request. | ||
1303 | * | ||
1304 | * If "isn" is not zero, this request hit alive | ||
1305 | * timewait bucket, so that all the necessary checks | ||
1306 | * are made in the function processing timewait state. | ||
1307 | */ | ||
1308 | if (tmp_opt.saw_tstamp && | ||
1309 | tcp_death_row.sysctl_tw_recycle && | ||
1310 | (dst = inet6_csk_route_req(sk, req)) != NULL && | ||
1311 | (peer = rt6_get_peer((struct rt6_info *)dst)) != NULL && | ||
1312 | ipv6_addr_equal((struct in6_addr *)peer->daddr.addr.a6, | ||
1313 | &treq->rmt_addr)) { | ||
1314 | inet_peer_refcheck(peer); | ||
1315 | if ((u32)get_seconds() - peer->tcp_ts_stamp < TCP_PAWS_MSL && | ||
1316 | (s32)(peer->tcp_ts - req->ts_recent) > | ||
1317 | TCP_PAWS_WINDOW) { | ||
1318 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED); | ||
1319 | goto drop_and_release; | ||
1320 | } | ||
1293 | } | 1321 | } |
1322 | /* Kill the following clause, if you dislike this way. */ | ||
1323 | else if (!sysctl_tcp_syncookies && | ||
1324 | (sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) < | ||
1325 | (sysctl_max_syn_backlog >> 2)) && | ||
1326 | (!peer || !peer->tcp_ts_stamp) && | ||
1327 | (!dst || !dst_metric(dst, RTAX_RTT))) { | ||
1328 | /* Without syncookies last quarter of | ||
1329 | * backlog is filled with destinations, | ||
1330 | * proven to be alive. | ||
1331 | * It means that we continue to communicate | ||
1332 | * to destinations, already remembered | ||
1333 | * to the moment of synflood. | ||
1334 | */ | ||
1335 | LIMIT_NETDEBUG(KERN_DEBUG "TCP: drop open request from %pI6/%u\n", | ||
1336 | &treq->rmt_addr, ntohs(tcp_hdr(skb)->source)); | ||
1337 | goto drop_and_release; | ||
1338 | } | ||
1339 | |||
1340 | isn = tcp_v6_init_sequence(skb); | ||
1294 | } | 1341 | } |
1342 | have_isn: | ||
1295 | tcp_rsk(req)->snt_isn = isn; | 1343 | tcp_rsk(req)->snt_isn = isn; |
1296 | 1344 | ||
1297 | security_inet_conn_request(sk, skb, req); | 1345 | security_inet_conn_request(sk, skb, req); |
@@ -1304,6 +1352,8 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1304 | inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); | 1352 | inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); |
1305 | return 0; | 1353 | return 0; |
1306 | 1354 | ||
1355 | drop_and_release: | ||
1356 | dst_release(dst); | ||
1307 | drop_and_free: | 1357 | drop_and_free: |
1308 | reqsk_free(req); | 1358 | reqsk_free(req); |
1309 | drop: | 1359 | drop: |
@@ -1382,34 +1432,15 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
1382 | if (sk_acceptq_is_full(sk)) | 1432 | if (sk_acceptq_is_full(sk)) |
1383 | goto out_overflow; | 1433 | goto out_overflow; |
1384 | 1434 | ||
1385 | if (dst == NULL) { | 1435 | if (!dst) { |
1386 | struct in6_addr *final_p, final; | 1436 | dst = inet6_csk_route_req(sk, req); |
1387 | struct flowi fl; | 1437 | if (!dst) |
1388 | |||
1389 | memset(&fl, 0, sizeof(fl)); | ||
1390 | fl.proto = IPPROTO_TCP; | ||
1391 | ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr); | ||
1392 | final_p = fl6_update_dst(&fl, opt, &final); | ||
1393 | ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr); | ||
1394 | fl.oif = sk->sk_bound_dev_if; | ||
1395 | fl.mark = sk->sk_mark; | ||
1396 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; | ||
1397 | fl.fl_ip_sport = inet_rsk(req)->loc_port; | ||
1398 | security_req_classify_flow(req, &fl); | ||
1399 | |||
1400 | if (ip6_dst_lookup(sk, &dst, &fl)) | ||
1401 | goto out; | ||
1402 | |||
1403 | if (final_p) | ||
1404 | ipv6_addr_copy(&fl.fl6_dst, final_p); | ||
1405 | |||
1406 | if ((xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0) | ||
1407 | goto out; | 1438 | goto out; |
1408 | } | 1439 | } |
1409 | 1440 | ||
1410 | newsk = tcp_create_openreq_child(sk, req, skb); | 1441 | newsk = tcp_create_openreq_child(sk, req, skb); |
1411 | if (newsk == NULL) | 1442 | if (newsk == NULL) |
1412 | goto out; | 1443 | goto out_nonewsk; |
1413 | 1444 | ||
1414 | /* | 1445 | /* |
1415 | * No need to charge this sock to the relevant IPv6 refcnt debug socks | 1446 | * No need to charge this sock to the relevant IPv6 refcnt debug socks |
@@ -1438,7 +1469,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
1438 | 1469 | ||
1439 | First: no IPv4 options. | 1470 | First: no IPv4 options. |
1440 | */ | 1471 | */ |
1441 | newinet->opt = NULL; | 1472 | newinet->inet_opt = NULL; |
1442 | newnp->ipv6_fl_list = NULL; | 1473 | newnp->ipv6_fl_list = NULL; |
1443 | 1474 | ||
1444 | /* Clone RX bits */ | 1475 | /* Clone RX bits */ |
@@ -1476,7 +1507,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
1476 | 1507 | ||
1477 | tcp_mtup_init(newsk); | 1508 | tcp_mtup_init(newsk); |
1478 | tcp_sync_mss(newsk, dst_mtu(dst)); | 1509 | tcp_sync_mss(newsk, dst_mtu(dst)); |
1479 | newtp->advmss = dst_metric(dst, RTAX_ADVMSS); | 1510 | newtp->advmss = dst_metric_advmss(dst); |
1480 | tcp_initialize_rcv_mss(newsk); | 1511 | tcp_initialize_rcv_mss(newsk); |
1481 | 1512 | ||
1482 | newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6; | 1513 | newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6; |
@@ -1497,18 +1528,22 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
1497 | } | 1528 | } |
1498 | #endif | 1529 | #endif |
1499 | 1530 | ||
1531 | if (__inet_inherit_port(sk, newsk) < 0) { | ||
1532 | sock_put(newsk); | ||
1533 | goto out; | ||
1534 | } | ||
1500 | __inet6_hash(newsk, NULL); | 1535 | __inet6_hash(newsk, NULL); |
1501 | __inet_inherit_port(sk, newsk); | ||
1502 | 1536 | ||
1503 | return newsk; | 1537 | return newsk; |
1504 | 1538 | ||
1505 | out_overflow: | 1539 | out_overflow: |
1506 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); | 1540 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); |
1507 | out: | 1541 | out_nonewsk: |
1508 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); | ||
1509 | if (opt && opt != np->opt) | 1542 | if (opt && opt != np->opt) |
1510 | sock_kfree_s(sk, opt, opt->tot_len); | 1543 | sock_kfree_s(sk, opt, opt->tot_len); |
1511 | dst_release(dst); | 1544 | dst_release(dst); |
1545 | out: | ||
1546 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); | ||
1512 | return NULL; | 1547 | return NULL; |
1513 | } | 1548 | } |
1514 | 1549 | ||
@@ -1587,10 +1622,9 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
1587 | opt_skb = skb_clone(skb, GFP_ATOMIC); | 1622 | opt_skb = skb_clone(skb, GFP_ATOMIC); |
1588 | 1623 | ||
1589 | if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */ | 1624 | if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */ |
1590 | TCP_CHECK_TIMER(sk); | 1625 | sock_rps_save_rxhash(sk, skb->rxhash); |
1591 | if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) | 1626 | if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) |
1592 | goto reset; | 1627 | goto reset; |
1593 | TCP_CHECK_TIMER(sk); | ||
1594 | if (opt_skb) | 1628 | if (opt_skb) |
1595 | goto ipv6_pktoptions; | 1629 | goto ipv6_pktoptions; |
1596 | return 0; | 1630 | return 0; |
@@ -1610,18 +1644,18 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
1610 | * the new socket.. | 1644 | * the new socket.. |
1611 | */ | 1645 | */ |
1612 | if(nsk != sk) { | 1646 | if(nsk != sk) { |
1647 | sock_rps_save_rxhash(nsk, skb->rxhash); | ||
1613 | if (tcp_child_process(sk, nsk, skb)) | 1648 | if (tcp_child_process(sk, nsk, skb)) |
1614 | goto reset; | 1649 | goto reset; |
1615 | if (opt_skb) | 1650 | if (opt_skb) |
1616 | __kfree_skb(opt_skb); | 1651 | __kfree_skb(opt_skb); |
1617 | return 0; | 1652 | return 0; |
1618 | } | 1653 | } |
1619 | } | 1654 | } else |
1655 | sock_rps_save_rxhash(sk, skb->rxhash); | ||
1620 | 1656 | ||
1621 | TCP_CHECK_TIMER(sk); | ||
1622 | if (tcp_rcv_state_process(sk, skb, tcp_hdr(skb), skb->len)) | 1657 | if (tcp_rcv_state_process(sk, skb, tcp_hdr(skb), skb->len)) |
1623 | goto reset; | 1658 | goto reset; |
1624 | TCP_CHECK_TIMER(sk); | ||
1625 | if (opt_skb) | 1659 | if (opt_skb) |
1626 | goto ipv6_pktoptions; | 1660 | goto ipv6_pktoptions; |
1627 | return 0; | 1661 | return 0; |
@@ -1669,7 +1703,7 @@ ipv6_pktoptions: | |||
1669 | static int tcp_v6_rcv(struct sk_buff *skb) | 1703 | static int tcp_v6_rcv(struct sk_buff *skb) |
1670 | { | 1704 | { |
1671 | struct tcphdr *th; | 1705 | struct tcphdr *th; |
1672 | struct ipv6hdr *hdr; | 1706 | const struct ipv6hdr *hdr; |
1673 | struct sock *sk; | 1707 | struct sock *sk; |
1674 | int ret; | 1708 | int ret; |
1675 | struct net *net = dev_net(skb->dev); | 1709 | struct net *net = dev_net(skb->dev); |
@@ -1814,19 +1848,51 @@ do_time_wait: | |||
1814 | goto discard_it; | 1848 | goto discard_it; |
1815 | } | 1849 | } |
1816 | 1850 | ||
1817 | static int tcp_v6_remember_stamp(struct sock *sk) | 1851 | static struct inet_peer *tcp_v6_get_peer(struct sock *sk, bool *release_it) |
1818 | { | 1852 | { |
1819 | /* Alas, not yet... */ | 1853 | struct rt6_info *rt = (struct rt6_info *) __sk_dst_get(sk); |
1820 | return 0; | 1854 | struct ipv6_pinfo *np = inet6_sk(sk); |
1855 | struct inet_peer *peer; | ||
1856 | |||
1857 | if (!rt || | ||
1858 | !ipv6_addr_equal(&np->daddr, &rt->rt6i_dst.addr)) { | ||
1859 | peer = inet_getpeer_v6(&np->daddr, 1); | ||
1860 | *release_it = true; | ||
1861 | } else { | ||
1862 | if (!rt->rt6i_peer) | ||
1863 | rt6_bind_peer(rt, 1); | ||
1864 | peer = rt->rt6i_peer; | ||
1865 | *release_it = false; | ||
1866 | } | ||
1867 | |||
1868 | return peer; | ||
1869 | } | ||
1870 | |||
1871 | static void *tcp_v6_tw_get_peer(struct sock *sk) | ||
1872 | { | ||
1873 | struct inet6_timewait_sock *tw6 = inet6_twsk(sk); | ||
1874 | struct inet_timewait_sock *tw = inet_twsk(sk); | ||
1875 | |||
1876 | if (tw->tw_family == AF_INET) | ||
1877 | return tcp_v4_tw_get_peer(sk); | ||
1878 | |||
1879 | return inet_getpeer_v6(&tw6->tw_v6_daddr, 1); | ||
1821 | } | 1880 | } |
1822 | 1881 | ||
1882 | static struct timewait_sock_ops tcp6_timewait_sock_ops = { | ||
1883 | .twsk_obj_size = sizeof(struct tcp6_timewait_sock), | ||
1884 | .twsk_unique = tcp_twsk_unique, | ||
1885 | .twsk_destructor= tcp_twsk_destructor, | ||
1886 | .twsk_getpeer = tcp_v6_tw_get_peer, | ||
1887 | }; | ||
1888 | |||
1823 | static const struct inet_connection_sock_af_ops ipv6_specific = { | 1889 | static const struct inet_connection_sock_af_ops ipv6_specific = { |
1824 | .queue_xmit = inet6_csk_xmit, | 1890 | .queue_xmit = inet6_csk_xmit, |
1825 | .send_check = tcp_v6_send_check, | 1891 | .send_check = tcp_v6_send_check, |
1826 | .rebuild_header = inet6_sk_rebuild_header, | 1892 | .rebuild_header = inet6_sk_rebuild_header, |
1827 | .conn_request = tcp_v6_conn_request, | 1893 | .conn_request = tcp_v6_conn_request, |
1828 | .syn_recv_sock = tcp_v6_syn_recv_sock, | 1894 | .syn_recv_sock = tcp_v6_syn_recv_sock, |
1829 | .remember_stamp = tcp_v6_remember_stamp, | 1895 | .get_peer = tcp_v6_get_peer, |
1830 | .net_header_len = sizeof(struct ipv6hdr), | 1896 | .net_header_len = sizeof(struct ipv6hdr), |
1831 | .setsockopt = ipv6_setsockopt, | 1897 | .setsockopt = ipv6_setsockopt, |
1832 | .getsockopt = ipv6_getsockopt, | 1898 | .getsockopt = ipv6_getsockopt, |
@@ -1858,7 +1924,7 @@ static const struct inet_connection_sock_af_ops ipv6_mapped = { | |||
1858 | .rebuild_header = inet_sk_rebuild_header, | 1924 | .rebuild_header = inet_sk_rebuild_header, |
1859 | .conn_request = tcp_v6_conn_request, | 1925 | .conn_request = tcp_v6_conn_request, |
1860 | .syn_recv_sock = tcp_v6_syn_recv_sock, | 1926 | .syn_recv_sock = tcp_v6_syn_recv_sock, |
1861 | .remember_stamp = tcp_v4_remember_stamp, | 1927 | .get_peer = tcp_v4_get_peer, |
1862 | .net_header_len = sizeof(struct iphdr), | 1928 | .net_header_len = sizeof(struct iphdr), |
1863 | .setsockopt = ipv6_setsockopt, | 1929 | .setsockopt = ipv6_setsockopt, |
1864 | .getsockopt = ipv6_getsockopt, | 1930 | .getsockopt = ipv6_getsockopt, |
@@ -1963,15 +2029,15 @@ static void get_openreq6(struct seq_file *seq, | |||
1963 | struct sock *sk, struct request_sock *req, int i, int uid) | 2029 | struct sock *sk, struct request_sock *req, int i, int uid) |
1964 | { | 2030 | { |
1965 | int ttd = req->expires - jiffies; | 2031 | int ttd = req->expires - jiffies; |
1966 | struct in6_addr *src = &inet6_rsk(req)->loc_addr; | 2032 | const struct in6_addr *src = &inet6_rsk(req)->loc_addr; |
1967 | struct in6_addr *dest = &inet6_rsk(req)->rmt_addr; | 2033 | const struct in6_addr *dest = &inet6_rsk(req)->rmt_addr; |
1968 | 2034 | ||
1969 | if (ttd < 0) | 2035 | if (ttd < 0) |
1970 | ttd = 0; | 2036 | ttd = 0; |
1971 | 2037 | ||
1972 | seq_printf(seq, | 2038 | seq_printf(seq, |
1973 | "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " | 2039 | "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " |
1974 | "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n", | 2040 | "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK\n", |
1975 | i, | 2041 | i, |
1976 | src->s6_addr32[0], src->s6_addr32[1], | 2042 | src->s6_addr32[0], src->s6_addr32[1], |
1977 | src->s6_addr32[2], src->s6_addr32[3], | 2043 | src->s6_addr32[2], src->s6_addr32[3], |
@@ -1992,7 +2058,7 @@ static void get_openreq6(struct seq_file *seq, | |||
1992 | 2058 | ||
1993 | static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i) | 2059 | static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i) |
1994 | { | 2060 | { |
1995 | struct in6_addr *dest, *src; | 2061 | const struct in6_addr *dest, *src; |
1996 | __u16 destp, srcp; | 2062 | __u16 destp, srcp; |
1997 | int timer_active; | 2063 | int timer_active; |
1998 | unsigned long timer_expires; | 2064 | unsigned long timer_expires; |
@@ -2022,7 +2088,7 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i) | |||
2022 | 2088 | ||
2023 | seq_printf(seq, | 2089 | seq_printf(seq, |
2024 | "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " | 2090 | "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " |
2025 | "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %lu %lu %u %u %d\n", | 2091 | "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %pK %lu %lu %u %u %d\n", |
2026 | i, | 2092 | i, |
2027 | src->s6_addr32[0], src->s6_addr32[1], | 2093 | src->s6_addr32[0], src->s6_addr32[1], |
2028 | src->s6_addr32[2], src->s6_addr32[3], srcp, | 2094 | src->s6_addr32[2], src->s6_addr32[3], srcp, |
@@ -2049,7 +2115,7 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i) | |||
2049 | static void get_timewait6_sock(struct seq_file *seq, | 2115 | static void get_timewait6_sock(struct seq_file *seq, |
2050 | struct inet_timewait_sock *tw, int i) | 2116 | struct inet_timewait_sock *tw, int i) |
2051 | { | 2117 | { |
2052 | struct in6_addr *dest, *src; | 2118 | const struct in6_addr *dest, *src; |
2053 | __u16 destp, srcp; | 2119 | __u16 destp, srcp; |
2054 | struct inet6_timewait_sock *tw6 = inet6_twsk((struct sock *)tw); | 2120 | struct inet6_timewait_sock *tw6 = inet6_twsk((struct sock *)tw); |
2055 | int ttd = tw->tw_ttd - jiffies; | 2121 | int ttd = tw->tw_ttd - jiffies; |
@@ -2064,7 +2130,7 @@ static void get_timewait6_sock(struct seq_file *seq, | |||
2064 | 2130 | ||
2065 | seq_printf(seq, | 2131 | seq_printf(seq, |
2066 | "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " | 2132 | "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " |
2067 | "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n", | 2133 | "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK\n", |
2068 | i, | 2134 | i, |
2069 | src->s6_addr32[0], src->s6_addr32[1], | 2135 | src->s6_addr32[0], src->s6_addr32[1], |
2070 | src->s6_addr32[2], src->s6_addr32[3], srcp, | 2136 | src->s6_addr32[2], src->s6_addr32[3], srcp, |
diff --git a/net/ipv6/tunnel6.c b/net/ipv6/tunnel6.c index fc3c86a47452..4f3cec12aa85 100644 --- a/net/ipv6/tunnel6.c +++ b/net/ipv6/tunnel6.c | |||
@@ -30,28 +30,31 @@ | |||
30 | #include <net/protocol.h> | 30 | #include <net/protocol.h> |
31 | #include <net/xfrm.h> | 31 | #include <net/xfrm.h> |
32 | 32 | ||
33 | static struct xfrm6_tunnel *tunnel6_handlers; | 33 | static struct xfrm6_tunnel __rcu *tunnel6_handlers __read_mostly; |
34 | static struct xfrm6_tunnel *tunnel46_handlers; | 34 | static struct xfrm6_tunnel __rcu *tunnel46_handlers __read_mostly; |
35 | static DEFINE_MUTEX(tunnel6_mutex); | 35 | static DEFINE_MUTEX(tunnel6_mutex); |
36 | 36 | ||
37 | int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family) | 37 | int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family) |
38 | { | 38 | { |
39 | struct xfrm6_tunnel **pprev; | 39 | struct xfrm6_tunnel __rcu **pprev; |
40 | struct xfrm6_tunnel *t; | ||
40 | int ret = -EEXIST; | 41 | int ret = -EEXIST; |
41 | int priority = handler->priority; | 42 | int priority = handler->priority; |
42 | 43 | ||
43 | mutex_lock(&tunnel6_mutex); | 44 | mutex_lock(&tunnel6_mutex); |
44 | 45 | ||
45 | for (pprev = (family == AF_INET6) ? &tunnel6_handlers : &tunnel46_handlers; | 46 | for (pprev = (family == AF_INET6) ? &tunnel6_handlers : &tunnel46_handlers; |
46 | *pprev; pprev = &(*pprev)->next) { | 47 | (t = rcu_dereference_protected(*pprev, |
47 | if ((*pprev)->priority > priority) | 48 | lockdep_is_held(&tunnel6_mutex))) != NULL; |
49 | pprev = &t->next) { | ||
50 | if (t->priority > priority) | ||
48 | break; | 51 | break; |
49 | if ((*pprev)->priority == priority) | 52 | if (t->priority == priority) |
50 | goto err; | 53 | goto err; |
51 | } | 54 | } |
52 | 55 | ||
53 | handler->next = *pprev; | 56 | handler->next = *pprev; |
54 | *pprev = handler; | 57 | rcu_assign_pointer(*pprev, handler); |
55 | 58 | ||
56 | ret = 0; | 59 | ret = 0; |
57 | 60 | ||
@@ -65,14 +68,17 @@ EXPORT_SYMBOL(xfrm6_tunnel_register); | |||
65 | 68 | ||
66 | int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family) | 69 | int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family) |
67 | { | 70 | { |
68 | struct xfrm6_tunnel **pprev; | 71 | struct xfrm6_tunnel __rcu **pprev; |
72 | struct xfrm6_tunnel *t; | ||
69 | int ret = -ENOENT; | 73 | int ret = -ENOENT; |
70 | 74 | ||
71 | mutex_lock(&tunnel6_mutex); | 75 | mutex_lock(&tunnel6_mutex); |
72 | 76 | ||
73 | for (pprev = (family == AF_INET6) ? &tunnel6_handlers : &tunnel46_handlers; | 77 | for (pprev = (family == AF_INET6) ? &tunnel6_handlers : &tunnel46_handlers; |
74 | *pprev; pprev = &(*pprev)->next) { | 78 | (t = rcu_dereference_protected(*pprev, |
75 | if (*pprev == handler) { | 79 | lockdep_is_held(&tunnel6_mutex))) != NULL; |
80 | pprev = &t->next) { | ||
81 | if (t == handler) { | ||
76 | *pprev = handler->next; | 82 | *pprev = handler->next; |
77 | ret = 0; | 83 | ret = 0; |
78 | break; | 84 | break; |
@@ -88,6 +94,11 @@ int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family) | |||
88 | 94 | ||
89 | EXPORT_SYMBOL(xfrm6_tunnel_deregister); | 95 | EXPORT_SYMBOL(xfrm6_tunnel_deregister); |
90 | 96 | ||
97 | #define for_each_tunnel_rcu(head, handler) \ | ||
98 | for (handler = rcu_dereference(head); \ | ||
99 | handler != NULL; \ | ||
100 | handler = rcu_dereference(handler->next)) \ | ||
101 | |||
91 | static int tunnel6_rcv(struct sk_buff *skb) | 102 | static int tunnel6_rcv(struct sk_buff *skb) |
92 | { | 103 | { |
93 | struct xfrm6_tunnel *handler; | 104 | struct xfrm6_tunnel *handler; |
@@ -95,7 +106,7 @@ static int tunnel6_rcv(struct sk_buff *skb) | |||
95 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) | 106 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) |
96 | goto drop; | 107 | goto drop; |
97 | 108 | ||
98 | for (handler = tunnel6_handlers; handler; handler = handler->next) | 109 | for_each_tunnel_rcu(tunnel6_handlers, handler) |
99 | if (!handler->handler(skb)) | 110 | if (!handler->handler(skb)) |
100 | return 0; | 111 | return 0; |
101 | 112 | ||
@@ -113,7 +124,7 @@ static int tunnel46_rcv(struct sk_buff *skb) | |||
113 | if (!pskb_may_pull(skb, sizeof(struct iphdr))) | 124 | if (!pskb_may_pull(skb, sizeof(struct iphdr))) |
114 | goto drop; | 125 | goto drop; |
115 | 126 | ||
116 | for (handler = tunnel46_handlers; handler; handler = handler->next) | 127 | for_each_tunnel_rcu(tunnel46_handlers, handler) |
117 | if (!handler->handler(skb)) | 128 | if (!handler->handler(skb)) |
118 | return 0; | 129 | return 0; |
119 | 130 | ||
@@ -129,7 +140,7 @@ static void tunnel6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
129 | { | 140 | { |
130 | struct xfrm6_tunnel *handler; | 141 | struct xfrm6_tunnel *handler; |
131 | 142 | ||
132 | for (handler = tunnel6_handlers; handler; handler = handler->next) | 143 | for_each_tunnel_rcu(tunnel6_handlers, handler) |
133 | if (!handler->err_handler(skb, opt, type, code, offset, info)) | 144 | if (!handler->err_handler(skb, opt, type, code, offset, info)) |
134 | break; | 145 | break; |
135 | } | 146 | } |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 5acb3560ff15..328985c40883 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -54,8 +54,8 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) | |||
54 | { | 54 | { |
55 | const struct in6_addr *sk_rcv_saddr6 = &inet6_sk(sk)->rcv_saddr; | 55 | const struct in6_addr *sk_rcv_saddr6 = &inet6_sk(sk)->rcv_saddr; |
56 | const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2); | 56 | const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2); |
57 | __be32 sk1_rcv_saddr = inet_sk(sk)->inet_rcv_saddr; | 57 | __be32 sk1_rcv_saddr = sk_rcv_saddr(sk); |
58 | __be32 sk2_rcv_saddr = inet_rcv_saddr(sk2); | 58 | __be32 sk2_rcv_saddr = sk_rcv_saddr(sk2); |
59 | int sk_ipv6only = ipv6_only_sock(sk); | 59 | int sk_ipv6only = ipv6_only_sock(sk); |
60 | int sk2_ipv6only = inet_v6_ipv6only(sk2); | 60 | int sk2_ipv6only = inet_v6_ipv6only(sk2); |
61 | int addr_type = ipv6_addr_type(sk_rcv_saddr6); | 61 | int addr_type = ipv6_addr_type(sk_rcv_saddr6); |
@@ -122,8 +122,8 @@ static void udp_v6_rehash(struct sock *sk) | |||
122 | 122 | ||
123 | static inline int compute_score(struct sock *sk, struct net *net, | 123 | static inline int compute_score(struct sock *sk, struct net *net, |
124 | unsigned short hnum, | 124 | unsigned short hnum, |
125 | struct in6_addr *saddr, __be16 sport, | 125 | const struct in6_addr *saddr, __be16 sport, |
126 | struct in6_addr *daddr, __be16 dport, | 126 | const struct in6_addr *daddr, __be16 dport, |
127 | int dif) | 127 | int dif) |
128 | { | 128 | { |
129 | int score = -1; | 129 | int score = -1; |
@@ -227,7 +227,7 @@ begin: | |||
227 | 227 | ||
228 | if (result) { | 228 | if (result) { |
229 | exact_match: | 229 | exact_match: |
230 | if (unlikely(!atomic_inc_not_zero(&result->sk_refcnt))) | 230 | if (unlikely(!atomic_inc_not_zero_hint(&result->sk_refcnt, 2))) |
231 | result = NULL; | 231 | result = NULL; |
232 | else if (unlikely(compute_score2(result, net, saddr, sport, | 232 | else if (unlikely(compute_score2(result, net, saddr, sport, |
233 | daddr, hnum, dif) < badness)) { | 233 | daddr, hnum, dif) < badness)) { |
@@ -239,8 +239,8 @@ exact_match: | |||
239 | } | 239 | } |
240 | 240 | ||
241 | static struct sock *__udp6_lib_lookup(struct net *net, | 241 | static struct sock *__udp6_lib_lookup(struct net *net, |
242 | struct in6_addr *saddr, __be16 sport, | 242 | const struct in6_addr *saddr, __be16 sport, |
243 | struct in6_addr *daddr, __be16 dport, | 243 | const struct in6_addr *daddr, __be16 dport, |
244 | int dif, struct udp_table *udptable) | 244 | int dif, struct udp_table *udptable) |
245 | { | 245 | { |
246 | struct sock *sk, *result; | 246 | struct sock *sk, *result; |
@@ -294,7 +294,7 @@ begin: | |||
294 | goto begin; | 294 | goto begin; |
295 | 295 | ||
296 | if (result) { | 296 | if (result) { |
297 | if (unlikely(!atomic_inc_not_zero(&result->sk_refcnt))) | 297 | if (unlikely(!atomic_inc_not_zero_hint(&result->sk_refcnt, 2))) |
298 | result = NULL; | 298 | result = NULL; |
299 | else if (unlikely(compute_score(result, net, hnum, saddr, sport, | 299 | else if (unlikely(compute_score(result, net, hnum, saddr, sport, |
300 | daddr, dport, dif) < badness)) { | 300 | daddr, dport, dif) < badness)) { |
@@ -311,7 +311,7 @@ static struct sock *__udp6_lib_lookup_skb(struct sk_buff *skb, | |||
311 | struct udp_table *udptable) | 311 | struct udp_table *udptable) |
312 | { | 312 | { |
313 | struct sock *sk; | 313 | struct sock *sk; |
314 | struct ipv6hdr *iph = ipv6_hdr(skb); | 314 | const struct ipv6hdr *iph = ipv6_hdr(skb); |
315 | 315 | ||
316 | if (unlikely(sk = skb_steal_sock(skb))) | 316 | if (unlikely(sk = skb_steal_sock(skb))) |
317 | return sk; | 317 | return sk; |
@@ -320,6 +320,14 @@ static struct sock *__udp6_lib_lookup_skb(struct sk_buff *skb, | |||
320 | udptable); | 320 | udptable); |
321 | } | 321 | } |
322 | 322 | ||
323 | struct sock *udp6_lib_lookup(struct net *net, const struct in6_addr *saddr, __be16 sport, | ||
324 | const struct in6_addr *daddr, __be16 dport, int dif) | ||
325 | { | ||
326 | return __udp6_lib_lookup(net, saddr, sport, daddr, dport, dif, &udp_table); | ||
327 | } | ||
328 | EXPORT_SYMBOL_GPL(udp6_lib_lookup); | ||
329 | |||
330 | |||
323 | /* | 331 | /* |
324 | * This should be easy, if there is something there we | 332 | * This should be easy, if there is something there we |
325 | * return it, otherwise we block. | 333 | * return it, otherwise we block. |
@@ -445,8 +453,11 @@ csum_copy_err: | |||
445 | } | 453 | } |
446 | unlock_sock_fast(sk, slow); | 454 | unlock_sock_fast(sk, slow); |
447 | 455 | ||
448 | if (flags & MSG_DONTWAIT) | 456 | if (noblock) |
449 | return -EAGAIN; | 457 | return -EAGAIN; |
458 | |||
459 | /* starting over for a new packet */ | ||
460 | msg->msg_flags &= ~MSG_TRUNC; | ||
450 | goto try_again; | 461 | goto try_again; |
451 | } | 462 | } |
452 | 463 | ||
@@ -455,9 +466,9 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
455 | struct udp_table *udptable) | 466 | struct udp_table *udptable) |
456 | { | 467 | { |
457 | struct ipv6_pinfo *np; | 468 | struct ipv6_pinfo *np; |
458 | struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data; | 469 | const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data; |
459 | struct in6_addr *saddr = &hdr->saddr; | 470 | const struct in6_addr *saddr = &hdr->saddr; |
460 | struct in6_addr *daddr = &hdr->daddr; | 471 | const struct in6_addr *daddr = &hdr->daddr; |
461 | struct udphdr *uh = (struct udphdr*)(skb->data+offset); | 472 | struct udphdr *uh = (struct udphdr*)(skb->data+offset); |
462 | struct sock *sk; | 473 | struct sock *sk; |
463 | int err; | 474 | int err; |
@@ -497,6 +508,9 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | |||
497 | int rc; | 508 | int rc; |
498 | int is_udplite = IS_UDPLITE(sk); | 509 | int is_udplite = IS_UDPLITE(sk); |
499 | 510 | ||
511 | if (!ipv6_addr_any(&inet6_sk(sk)->daddr)) | ||
512 | sock_rps_save_rxhash(sk, skb->rxhash); | ||
513 | |||
500 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) | 514 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) |
501 | goto drop; | 515 | goto drop; |
502 | 516 | ||
@@ -519,7 +533,7 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | |||
519 | } | 533 | } |
520 | } | 534 | } |
521 | 535 | ||
522 | if (sk->sk_filter) { | 536 | if (rcu_dereference_raw(sk->sk_filter)) { |
523 | if (udp_lib_checksum_complete(skb)) | 537 | if (udp_lib_checksum_complete(skb)) |
524 | goto drop; | 538 | goto drop; |
525 | } | 539 | } |
@@ -542,8 +556,8 @@ drop_no_sk_drops_inc: | |||
542 | } | 556 | } |
543 | 557 | ||
544 | static struct sock *udp_v6_mcast_next(struct net *net, struct sock *sk, | 558 | static struct sock *udp_v6_mcast_next(struct net *net, struct sock *sk, |
545 | __be16 loc_port, struct in6_addr *loc_addr, | 559 | __be16 loc_port, const struct in6_addr *loc_addr, |
546 | __be16 rmt_port, struct in6_addr *rmt_addr, | 560 | __be16 rmt_port, const struct in6_addr *rmt_addr, |
547 | int dif) | 561 | int dif) |
548 | { | 562 | { |
549 | struct hlist_nulls_node *node; | 563 | struct hlist_nulls_node *node; |
@@ -594,7 +608,7 @@ static void flush_stack(struct sock **stack, unsigned int count, | |||
594 | 608 | ||
595 | sk = stack[i]; | 609 | sk = stack[i]; |
596 | if (skb1) { | 610 | if (skb1) { |
597 | if (sk_rcvqueues_full(sk, skb)) { | 611 | if (sk_rcvqueues_full(sk, skb1)) { |
598 | kfree_skb(skb1); | 612 | kfree_skb(skb1); |
599 | goto drop; | 613 | goto drop; |
600 | } | 614 | } |
@@ -622,7 +636,7 @@ drop: | |||
622 | * so we don't need to lock the hashes. | 636 | * so we don't need to lock the hashes. |
623 | */ | 637 | */ |
624 | static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb, | 638 | static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb, |
625 | struct in6_addr *saddr, struct in6_addr *daddr, | 639 | const struct in6_addr *saddr, const struct in6_addr *daddr, |
626 | struct udp_table *udptable) | 640 | struct udp_table *udptable) |
627 | { | 641 | { |
628 | struct sock *sk, *stack[256 / sizeof(struct sock *)]; | 642 | struct sock *sk, *stack[256 / sizeof(struct sock *)]; |
@@ -705,7 +719,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, | |||
705 | struct net *net = dev_net(skb->dev); | 719 | struct net *net = dev_net(skb->dev); |
706 | struct sock *sk; | 720 | struct sock *sk; |
707 | struct udphdr *uh; | 721 | struct udphdr *uh; |
708 | struct in6_addr *saddr, *daddr; | 722 | const struct in6_addr *saddr, *daddr; |
709 | u32 ulen = 0; | 723 | u32 ulen = 0; |
710 | 724 | ||
711 | if (!pskb_may_pull(skb, sizeof(struct udphdr))) | 725 | if (!pskb_may_pull(skb, sizeof(struct udphdr))) |
@@ -878,7 +892,7 @@ static int udp_v6_push_pending_frames(struct sock *sk) | |||
878 | struct udphdr *uh; | 892 | struct udphdr *uh; |
879 | struct udp_sock *up = udp_sk(sk); | 893 | struct udp_sock *up = udp_sk(sk); |
880 | struct inet_sock *inet = inet_sk(sk); | 894 | struct inet_sock *inet = inet_sk(sk); |
881 | struct flowi *fl = &inet->cork.fl; | 895 | struct flowi6 *fl6 = &inet->cork.fl.u.ip6; |
882 | int err = 0; | 896 | int err = 0; |
883 | int is_udplite = IS_UDPLITE(sk); | 897 | int is_udplite = IS_UDPLITE(sk); |
884 | __wsum csum = 0; | 898 | __wsum csum = 0; |
@@ -891,23 +905,23 @@ static int udp_v6_push_pending_frames(struct sock *sk) | |||
891 | * Create a UDP header | 905 | * Create a UDP header |
892 | */ | 906 | */ |
893 | uh = udp_hdr(skb); | 907 | uh = udp_hdr(skb); |
894 | uh->source = fl->fl_ip_sport; | 908 | uh->source = fl6->fl6_sport; |
895 | uh->dest = fl->fl_ip_dport; | 909 | uh->dest = fl6->fl6_dport; |
896 | uh->len = htons(up->len); | 910 | uh->len = htons(up->len); |
897 | uh->check = 0; | 911 | uh->check = 0; |
898 | 912 | ||
899 | if (is_udplite) | 913 | if (is_udplite) |
900 | csum = udplite_csum_outgoing(sk, skb); | 914 | csum = udplite_csum_outgoing(sk, skb); |
901 | else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ | 915 | else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ |
902 | udp6_hwcsum_outgoing(sk, skb, &fl->fl6_src, &fl->fl6_dst, | 916 | udp6_hwcsum_outgoing(sk, skb, &fl6->saddr, &fl6->daddr, |
903 | up->len); | 917 | up->len); |
904 | goto send; | 918 | goto send; |
905 | } else | 919 | } else |
906 | csum = udp_csum_outgoing(sk, skb); | 920 | csum = udp_csum_outgoing(sk, skb); |
907 | 921 | ||
908 | /* add protocol-dependent pseudo-header */ | 922 | /* add protocol-dependent pseudo-header */ |
909 | uh->check = csum_ipv6_magic(&fl->fl6_src, &fl->fl6_dst, | 923 | uh->check = csum_ipv6_magic(&fl6->saddr, &fl6->daddr, |
910 | up->len, fl->proto, csum ); | 924 | up->len, fl6->flowi6_proto, csum); |
911 | if (uh->check == 0) | 925 | if (uh->check == 0) |
912 | uh->check = CSUM_MANGLED_0; | 926 | uh->check = CSUM_MANGLED_0; |
913 | 927 | ||
@@ -939,7 +953,7 @@ int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
939 | struct in6_addr *daddr, *final_p, final; | 953 | struct in6_addr *daddr, *final_p, final; |
940 | struct ipv6_txoptions *opt = NULL; | 954 | struct ipv6_txoptions *opt = NULL; |
941 | struct ip6_flowlabel *flowlabel = NULL; | 955 | struct ip6_flowlabel *flowlabel = NULL; |
942 | struct flowi fl; | 956 | struct flowi6 fl6; |
943 | struct dst_entry *dst; | 957 | struct dst_entry *dst; |
944 | int addr_len = msg->msg_namelen; | 958 | int addr_len = msg->msg_namelen; |
945 | int ulen = len; | 959 | int ulen = len; |
@@ -1022,19 +1036,19 @@ do_udp_sendmsg: | |||
1022 | } | 1036 | } |
1023 | ulen += sizeof(struct udphdr); | 1037 | ulen += sizeof(struct udphdr); |
1024 | 1038 | ||
1025 | memset(&fl, 0, sizeof(fl)); | 1039 | memset(&fl6, 0, sizeof(fl6)); |
1026 | 1040 | ||
1027 | if (sin6) { | 1041 | if (sin6) { |
1028 | if (sin6->sin6_port == 0) | 1042 | if (sin6->sin6_port == 0) |
1029 | return -EINVAL; | 1043 | return -EINVAL; |
1030 | 1044 | ||
1031 | fl.fl_ip_dport = sin6->sin6_port; | 1045 | fl6.fl6_dport = sin6->sin6_port; |
1032 | daddr = &sin6->sin6_addr; | 1046 | daddr = &sin6->sin6_addr; |
1033 | 1047 | ||
1034 | if (np->sndflow) { | 1048 | if (np->sndflow) { |
1035 | fl.fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK; | 1049 | fl6.flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK; |
1036 | if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) { | 1050 | if (fl6.flowlabel&IPV6_FLOWLABEL_MASK) { |
1037 | flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel); | 1051 | flowlabel = fl6_sock_lookup(sk, fl6.flowlabel); |
1038 | if (flowlabel == NULL) | 1052 | if (flowlabel == NULL) |
1039 | return -EINVAL; | 1053 | return -EINVAL; |
1040 | daddr = &flowlabel->dst; | 1054 | daddr = &flowlabel->dst; |
@@ -1052,38 +1066,38 @@ do_udp_sendmsg: | |||
1052 | if (addr_len >= sizeof(struct sockaddr_in6) && | 1066 | if (addr_len >= sizeof(struct sockaddr_in6) && |
1053 | sin6->sin6_scope_id && | 1067 | sin6->sin6_scope_id && |
1054 | ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL) | 1068 | ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL) |
1055 | fl.oif = sin6->sin6_scope_id; | 1069 | fl6.flowi6_oif = sin6->sin6_scope_id; |
1056 | } else { | 1070 | } else { |
1057 | if (sk->sk_state != TCP_ESTABLISHED) | 1071 | if (sk->sk_state != TCP_ESTABLISHED) |
1058 | return -EDESTADDRREQ; | 1072 | return -EDESTADDRREQ; |
1059 | 1073 | ||
1060 | fl.fl_ip_dport = inet->inet_dport; | 1074 | fl6.fl6_dport = inet->inet_dport; |
1061 | daddr = &np->daddr; | 1075 | daddr = &np->daddr; |
1062 | fl.fl6_flowlabel = np->flow_label; | 1076 | fl6.flowlabel = np->flow_label; |
1063 | connected = 1; | 1077 | connected = 1; |
1064 | } | 1078 | } |
1065 | 1079 | ||
1066 | if (!fl.oif) | 1080 | if (!fl6.flowi6_oif) |
1067 | fl.oif = sk->sk_bound_dev_if; | 1081 | fl6.flowi6_oif = sk->sk_bound_dev_if; |
1068 | 1082 | ||
1069 | if (!fl.oif) | 1083 | if (!fl6.flowi6_oif) |
1070 | fl.oif = np->sticky_pktinfo.ipi6_ifindex; | 1084 | fl6.flowi6_oif = np->sticky_pktinfo.ipi6_ifindex; |
1071 | 1085 | ||
1072 | fl.mark = sk->sk_mark; | 1086 | fl6.flowi6_mark = sk->sk_mark; |
1073 | 1087 | ||
1074 | if (msg->msg_controllen) { | 1088 | if (msg->msg_controllen) { |
1075 | opt = &opt_space; | 1089 | opt = &opt_space; |
1076 | memset(opt, 0, sizeof(struct ipv6_txoptions)); | 1090 | memset(opt, 0, sizeof(struct ipv6_txoptions)); |
1077 | opt->tot_len = sizeof(*opt); | 1091 | opt->tot_len = sizeof(*opt); |
1078 | 1092 | ||
1079 | err = datagram_send_ctl(sock_net(sk), msg, &fl, opt, &hlimit, | 1093 | err = datagram_send_ctl(sock_net(sk), msg, &fl6, opt, &hlimit, |
1080 | &tclass, &dontfrag); | 1094 | &tclass, &dontfrag); |
1081 | if (err < 0) { | 1095 | if (err < 0) { |
1082 | fl6_sock_release(flowlabel); | 1096 | fl6_sock_release(flowlabel); |
1083 | return err; | 1097 | return err; |
1084 | } | 1098 | } |
1085 | if ((fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) { | 1099 | if ((fl6.flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) { |
1086 | flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel); | 1100 | flowlabel = fl6_sock_lookup(sk, fl6.flowlabel); |
1087 | if (flowlabel == NULL) | 1101 | if (flowlabel == NULL) |
1088 | return -EINVAL; | 1102 | return -EINVAL; |
1089 | } | 1103 | } |
@@ -1097,42 +1111,35 @@ do_udp_sendmsg: | |||
1097 | opt = fl6_merge_options(&opt_space, flowlabel, opt); | 1111 | opt = fl6_merge_options(&opt_space, flowlabel, opt); |
1098 | opt = ipv6_fixup_options(&opt_space, opt); | 1112 | opt = ipv6_fixup_options(&opt_space, opt); |
1099 | 1113 | ||
1100 | fl.proto = sk->sk_protocol; | 1114 | fl6.flowi6_proto = sk->sk_protocol; |
1101 | if (!ipv6_addr_any(daddr)) | 1115 | if (!ipv6_addr_any(daddr)) |
1102 | ipv6_addr_copy(&fl.fl6_dst, daddr); | 1116 | ipv6_addr_copy(&fl6.daddr, daddr); |
1103 | else | 1117 | else |
1104 | fl.fl6_dst.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */ | 1118 | fl6.daddr.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */ |
1105 | if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr)) | 1119 | if (ipv6_addr_any(&fl6.saddr) && !ipv6_addr_any(&np->saddr)) |
1106 | ipv6_addr_copy(&fl.fl6_src, &np->saddr); | 1120 | ipv6_addr_copy(&fl6.saddr, &np->saddr); |
1107 | fl.fl_ip_sport = inet->inet_sport; | 1121 | fl6.fl6_sport = inet->inet_sport; |
1108 | 1122 | ||
1109 | final_p = fl6_update_dst(&fl, opt, &final); | 1123 | final_p = fl6_update_dst(&fl6, opt, &final); |
1110 | if (final_p) | 1124 | if (final_p) |
1111 | connected = 0; | 1125 | connected = 0; |
1112 | 1126 | ||
1113 | if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) { | 1127 | if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) { |
1114 | fl.oif = np->mcast_oif; | 1128 | fl6.flowi6_oif = np->mcast_oif; |
1115 | connected = 0; | 1129 | connected = 0; |
1116 | } | 1130 | } |
1117 | 1131 | ||
1118 | security_sk_classify_flow(sk, &fl); | 1132 | security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); |
1119 | 1133 | ||
1120 | err = ip6_sk_dst_lookup(sk, &dst, &fl); | 1134 | dst = ip6_sk_dst_lookup_flow(sk, &fl6, final_p, true); |
1121 | if (err) | 1135 | if (IS_ERR(dst)) { |
1136 | err = PTR_ERR(dst); | ||
1137 | dst = NULL; | ||
1122 | goto out; | 1138 | goto out; |
1123 | if (final_p) | ||
1124 | ipv6_addr_copy(&fl.fl6_dst, final_p); | ||
1125 | |||
1126 | err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT); | ||
1127 | if (err < 0) { | ||
1128 | if (err == -EREMOTE) | ||
1129 | err = ip6_dst_blackhole(sk, &dst, &fl); | ||
1130 | if (err < 0) | ||
1131 | goto out; | ||
1132 | } | 1139 | } |
1133 | 1140 | ||
1134 | if (hlimit < 0) { | 1141 | if (hlimit < 0) { |
1135 | if (ipv6_addr_is_multicast(&fl.fl6_dst)) | 1142 | if (ipv6_addr_is_multicast(&fl6.daddr)) |
1136 | hlimit = np->mcast_hops; | 1143 | hlimit = np->mcast_hops; |
1137 | else | 1144 | else |
1138 | hlimit = np->hop_limit; | 1145 | hlimit = np->hop_limit; |
@@ -1167,7 +1174,7 @@ do_append_data: | |||
1167 | up->len += ulen; | 1174 | up->len += ulen; |
1168 | getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; | 1175 | getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; |
1169 | err = ip6_append_data(sk, getfrag, msg->msg_iov, ulen, | 1176 | err = ip6_append_data(sk, getfrag, msg->msg_iov, ulen, |
1170 | sizeof(struct udphdr), hlimit, tclass, opt, &fl, | 1177 | sizeof(struct udphdr), hlimit, tclass, opt, &fl6, |
1171 | (struct rt6_info*)dst, | 1178 | (struct rt6_info*)dst, |
1172 | corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags, dontfrag); | 1179 | corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags, dontfrag); |
1173 | if (err) | 1180 | if (err) |
@@ -1180,10 +1187,10 @@ do_append_data: | |||
1180 | if (dst) { | 1187 | if (dst) { |
1181 | if (connected) { | 1188 | if (connected) { |
1182 | ip6_dst_store(sk, dst, | 1189 | ip6_dst_store(sk, dst, |
1183 | ipv6_addr_equal(&fl.fl6_dst, &np->daddr) ? | 1190 | ipv6_addr_equal(&fl6.daddr, &np->daddr) ? |
1184 | &np->daddr : NULL, | 1191 | &np->daddr : NULL, |
1185 | #ifdef CONFIG_IPV6_SUBTREES | 1192 | #ifdef CONFIG_IPV6_SUBTREES |
1186 | ipv6_addr_equal(&fl.fl6_src, &np->saddr) ? | 1193 | ipv6_addr_equal(&fl6.saddr, &np->saddr) ? |
1187 | &np->saddr : | 1194 | &np->saddr : |
1188 | #endif | 1195 | #endif |
1189 | NULL); | 1196 | NULL); |
@@ -1274,7 +1281,7 @@ int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, | |||
1274 | 1281 | ||
1275 | static int udp6_ufo_send_check(struct sk_buff *skb) | 1282 | static int udp6_ufo_send_check(struct sk_buff *skb) |
1276 | { | 1283 | { |
1277 | struct ipv6hdr *ipv6h; | 1284 | const struct ipv6hdr *ipv6h; |
1278 | struct udphdr *uh; | 1285 | struct udphdr *uh; |
1279 | 1286 | ||
1280 | if (!pskb_may_pull(skb, sizeof(*uh))) | 1287 | if (!pskb_may_pull(skb, sizeof(*uh))) |
@@ -1291,7 +1298,7 @@ static int udp6_ufo_send_check(struct sk_buff *skb) | |||
1291 | return 0; | 1298 | return 0; |
1292 | } | 1299 | } |
1293 | 1300 | ||
1294 | static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, int features) | 1301 | static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, u32 features) |
1295 | { | 1302 | { |
1296 | struct sk_buff *segs = ERR_PTR(-EINVAL); | 1303 | struct sk_buff *segs = ERR_PTR(-EINVAL); |
1297 | unsigned int mss; | 1304 | unsigned int mss; |
@@ -1324,14 +1331,14 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, int features) | |||
1324 | /* Do software UFO. Complete and fill in the UDP checksum as HW cannot | 1331 | /* Do software UFO. Complete and fill in the UDP checksum as HW cannot |
1325 | * do checksum of UDP packets sent as multiple IP fragments. | 1332 | * do checksum of UDP packets sent as multiple IP fragments. |
1326 | */ | 1333 | */ |
1327 | offset = skb->csum_start - skb_headroom(skb); | 1334 | offset = skb_checksum_start_offset(skb); |
1328 | csum = skb_checksum(skb, offset, skb->len- offset, 0); | 1335 | csum = skb_checksum(skb, offset, skb->len- offset, 0); |
1329 | offset += skb->csum_offset; | 1336 | offset += skb->csum_offset; |
1330 | *(__sum16 *)(skb->data + offset) = csum_fold(csum); | 1337 | *(__sum16 *)(skb->data + offset) = csum_fold(csum); |
1331 | skb->ip_summed = CHECKSUM_NONE; | 1338 | skb->ip_summed = CHECKSUM_NONE; |
1332 | 1339 | ||
1333 | /* Check if there is enough headroom to insert fragment header. */ | 1340 | /* Check if there is enough headroom to insert fragment header. */ |
1334 | if ((skb_headroom(skb) < frag_hdr_sz) && | 1341 | if ((skb_mac_header(skb) < skb->head + frag_hdr_sz) && |
1335 | pskb_expand_head(skb, frag_hdr_sz, 0, GFP_ATOMIC)) | 1342 | pskb_expand_head(skb, frag_hdr_sz, 0, GFP_ATOMIC)) |
1336 | goto out; | 1343 | goto out; |
1337 | 1344 | ||
@@ -1378,7 +1385,7 @@ static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket | |||
1378 | { | 1385 | { |
1379 | struct inet_sock *inet = inet_sk(sp); | 1386 | struct inet_sock *inet = inet_sk(sp); |
1380 | struct ipv6_pinfo *np = inet6_sk(sp); | 1387 | struct ipv6_pinfo *np = inet6_sk(sp); |
1381 | struct in6_addr *dest, *src; | 1388 | const struct in6_addr *dest, *src; |
1382 | __u16 destp, srcp; | 1389 | __u16 destp, srcp; |
1383 | 1390 | ||
1384 | dest = &np->daddr; | 1391 | dest = &np->daddr; |
@@ -1387,7 +1394,7 @@ static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket | |||
1387 | srcp = ntohs(inet->inet_sport); | 1394 | srcp = ntohs(inet->inet_sport); |
1388 | seq_printf(seq, | 1395 | seq_printf(seq, |
1389 | "%5d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " | 1396 | "%5d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " |
1390 | "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n", | 1397 | "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %pK %d\n", |
1391 | bucket, | 1398 | bucket, |
1392 | src->s6_addr32[0], src->s6_addr32[1], | 1399 | src->s6_addr32[0], src->s6_addr32[1], |
1393 | src->s6_addr32[2], src->s6_addr32[3], srcp, | 1400 | src->s6_addr32[2], src->s6_addr32[3], srcp, |
@@ -1469,6 +1476,7 @@ struct proto udpv6_prot = { | |||
1469 | .compat_setsockopt = compat_udpv6_setsockopt, | 1476 | .compat_setsockopt = compat_udpv6_setsockopt, |
1470 | .compat_getsockopt = compat_udpv6_getsockopt, | 1477 | .compat_getsockopt = compat_udpv6_getsockopt, |
1471 | #endif | 1478 | #endif |
1479 | .clear_sk = sk_prot_clear_portaddr_nulls, | ||
1472 | }; | 1480 | }; |
1473 | 1481 | ||
1474 | static struct inet_protosw udpv6_protosw = { | 1482 | static struct inet_protosw udpv6_protosw = { |
diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c index 5f48fadc27f7..986c4de5292e 100644 --- a/net/ipv6/udplite.c +++ b/net/ipv6/udplite.c | |||
@@ -55,6 +55,7 @@ struct proto udplitev6_prot = { | |||
55 | .compat_setsockopt = compat_udpv6_setsockopt, | 55 | .compat_setsockopt = compat_udpv6_setsockopt, |
56 | .compat_getsockopt = compat_udpv6_getsockopt, | 56 | .compat_getsockopt = compat_udpv6_getsockopt, |
57 | #endif | 57 | #endif |
58 | .clear_sk = sk_prot_clear_portaddr_nulls, | ||
58 | }; | 59 | }; |
59 | 60 | ||
60 | static struct inet_protosw udplite6_protosw = { | 61 | static struct inet_protosw udplite6_protosw = { |
diff --git a/net/ipv6/xfrm6_mode_beet.c b/net/ipv6/xfrm6_mode_beet.c index bbd48b101bae..3437d7d4eed6 100644 --- a/net/ipv6/xfrm6_mode_beet.c +++ b/net/ipv6/xfrm6_mode_beet.c | |||
@@ -41,10 +41,8 @@ static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb) | |||
41 | { | 41 | { |
42 | struct ipv6hdr *top_iph; | 42 | struct ipv6hdr *top_iph; |
43 | struct ip_beet_phdr *ph; | 43 | struct ip_beet_phdr *ph; |
44 | struct iphdr *iphv4; | ||
45 | int optlen, hdr_len; | 44 | int optlen, hdr_len; |
46 | 45 | ||
47 | iphv4 = ip_hdr(skb); | ||
48 | hdr_len = 0; | 46 | hdr_len = 0; |
49 | optlen = XFRM_MODE_SKB_CB(skb)->optlen; | 47 | optlen = XFRM_MODE_SKB_CB(skb)->optlen; |
50 | if (unlikely(optlen)) | 48 | if (unlikely(optlen)) |
diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c index b809812c8d30..4d6edff0498f 100644 --- a/net/ipv6/xfrm6_mode_tunnel.c +++ b/net/ipv6/xfrm6_mode_tunnel.c | |||
@@ -14,12 +14,13 @@ | |||
14 | #include <net/dsfield.h> | 14 | #include <net/dsfield.h> |
15 | #include <net/dst.h> | 15 | #include <net/dst.h> |
16 | #include <net/inet_ecn.h> | 16 | #include <net/inet_ecn.h> |
17 | #include <net/ip6_route.h> | ||
17 | #include <net/ipv6.h> | 18 | #include <net/ipv6.h> |
18 | #include <net/xfrm.h> | 19 | #include <net/xfrm.h> |
19 | 20 | ||
20 | static inline void ipip6_ecn_decapsulate(struct sk_buff *skb) | 21 | static inline void ipip6_ecn_decapsulate(struct sk_buff *skb) |
21 | { | 22 | { |
22 | struct ipv6hdr *outer_iph = ipv6_hdr(skb); | 23 | const struct ipv6hdr *outer_iph = ipv6_hdr(skb); |
23 | struct ipv6hdr *inner_iph = ipipv6_hdr(skb); | 24 | struct ipv6hdr *inner_iph = ipipv6_hdr(skb); |
24 | 25 | ||
25 | if (INET_ECN_is_ce(ipv6_get_dsfield(outer_iph))) | 26 | if (INET_ECN_is_ce(ipv6_get_dsfield(outer_iph))) |
@@ -53,9 +54,9 @@ static int xfrm6_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) | |||
53 | if (x->props.flags & XFRM_STATE_NOECN) | 54 | if (x->props.flags & XFRM_STATE_NOECN) |
54 | dsfield &= ~INET_ECN_MASK; | 55 | dsfield &= ~INET_ECN_MASK; |
55 | ipv6_change_dsfield(top_iph, 0, dsfield); | 56 | ipv6_change_dsfield(top_iph, 0, dsfield); |
56 | top_iph->hop_limit = dst_metric(dst->child, RTAX_HOPLIMIT); | 57 | top_iph->hop_limit = ip6_dst_hoplimit(dst->child); |
57 | ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr); | 58 | ipv6_addr_copy(&top_iph->saddr, (const struct in6_addr *)&x->props.saddr); |
58 | ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr); | 59 | ipv6_addr_copy(&top_iph->daddr, (const struct in6_addr *)&x->id.daddr); |
59 | return 0; | 60 | return 0; |
60 | } | 61 | } |
61 | 62 | ||
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index 6434bd5ce088..49a91c5f5623 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/netfilter_ipv6.h> | 17 | #include <linux/netfilter_ipv6.h> |
18 | #include <net/dst.h> | 18 | #include <net/dst.h> |
19 | #include <net/ipv6.h> | 19 | #include <net/ipv6.h> |
20 | #include <net/ip6_route.h> | ||
20 | #include <net/xfrm.h> | 21 | #include <net/xfrm.h> |
21 | 22 | ||
22 | int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb, | 23 | int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb, |
@@ -78,7 +79,7 @@ int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb) | |||
78 | } | 79 | } |
79 | EXPORT_SYMBOL(xfrm6_prepare_output); | 80 | EXPORT_SYMBOL(xfrm6_prepare_output); |
80 | 81 | ||
81 | static int xfrm6_output_finish(struct sk_buff *skb) | 82 | int xfrm6_output_finish(struct sk_buff *skb) |
82 | { | 83 | { |
83 | #ifdef CONFIG_NETFILTER | 84 | #ifdef CONFIG_NETFILTER |
84 | IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED; | 85 | IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED; |
@@ -88,8 +89,21 @@ static int xfrm6_output_finish(struct sk_buff *skb) | |||
88 | return xfrm_output(skb); | 89 | return xfrm_output(skb); |
89 | } | 90 | } |
90 | 91 | ||
92 | static int __xfrm6_output(struct sk_buff *skb) | ||
93 | { | ||
94 | struct dst_entry *dst = skb_dst(skb); | ||
95 | struct xfrm_state *x = dst->xfrm; | ||
96 | |||
97 | if ((x && x->props.mode == XFRM_MODE_TUNNEL) && | ||
98 | ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) || | ||
99 | dst_allfrag(skb_dst(skb)))) { | ||
100 | return ip6_fragment(skb, x->outer_mode->afinfo->output_finish); | ||
101 | } | ||
102 | return x->outer_mode->afinfo->output_finish(skb); | ||
103 | } | ||
104 | |||
91 | int xfrm6_output(struct sk_buff *skb) | 105 | int xfrm6_output(struct sk_buff *skb) |
92 | { | 106 | { |
93 | return NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL, | 107 | return NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL, |
94 | skb_dst(skb)->dev, xfrm6_output_finish); | 108 | skb_dst(skb)->dev, __xfrm6_output); |
95 | } | 109 | } |
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 6baeabbbca82..d879f7efbd10 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c | |||
@@ -27,18 +27,19 @@ | |||
27 | static struct xfrm_policy_afinfo xfrm6_policy_afinfo; | 27 | static struct xfrm_policy_afinfo xfrm6_policy_afinfo; |
28 | 28 | ||
29 | static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, | 29 | static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, |
30 | xfrm_address_t *saddr, | 30 | const xfrm_address_t *saddr, |
31 | xfrm_address_t *daddr) | 31 | const xfrm_address_t *daddr) |
32 | { | 32 | { |
33 | struct flowi fl = {}; | 33 | struct flowi6 fl6; |
34 | struct dst_entry *dst; | 34 | struct dst_entry *dst; |
35 | int err; | 35 | int err; |
36 | 36 | ||
37 | memcpy(&fl.fl6_dst, daddr, sizeof(fl.fl6_dst)); | 37 | memset(&fl6, 0, sizeof(fl6)); |
38 | memcpy(&fl6.daddr, daddr, sizeof(fl6.daddr)); | ||
38 | if (saddr) | 39 | if (saddr) |
39 | memcpy(&fl.fl6_src, saddr, sizeof(fl.fl6_src)); | 40 | memcpy(&fl6.saddr, saddr, sizeof(fl6.saddr)); |
40 | 41 | ||
41 | dst = ip6_route_output(net, NULL, &fl); | 42 | dst = ip6_route_output(net, NULL, &fl6); |
42 | 43 | ||
43 | err = dst->error; | 44 | err = dst->error; |
44 | if (dst->error) { | 45 | if (dst->error) { |
@@ -67,7 +68,7 @@ static int xfrm6_get_saddr(struct net *net, | |||
67 | return 0; | 68 | return 0; |
68 | } | 69 | } |
69 | 70 | ||
70 | static int xfrm6_get_tos(struct flowi *fl) | 71 | static int xfrm6_get_tos(const struct flowi *fl) |
71 | { | 72 | { |
72 | return 0; | 73 | return 0; |
73 | } | 74 | } |
@@ -87,7 +88,7 @@ static int xfrm6_init_path(struct xfrm_dst *path, struct dst_entry *dst, | |||
87 | } | 88 | } |
88 | 89 | ||
89 | static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, | 90 | static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, |
90 | struct flowi *fl) | 91 | const struct flowi *fl) |
91 | { | 92 | { |
92 | struct rt6_info *rt = (struct rt6_info*)xdst->route; | 93 | struct rt6_info *rt = (struct rt6_info*)xdst->route; |
93 | 94 | ||
@@ -98,6 +99,10 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, | |||
98 | if (!xdst->u.rt6.rt6i_idev) | 99 | if (!xdst->u.rt6.rt6i_idev) |
99 | return -ENODEV; | 100 | return -ENODEV; |
100 | 101 | ||
102 | xdst->u.rt6.rt6i_peer = rt->rt6i_peer; | ||
103 | if (rt->rt6i_peer) | ||
104 | atomic_inc(&rt->rt6i_peer->refcnt); | ||
105 | |||
101 | /* Sheit... I remember I did this right. Apparently, | 106 | /* Sheit... I remember I did this right. Apparently, |
102 | * it was magically lost, so this code needs audit */ | 107 | * it was magically lost, so this code needs audit */ |
103 | xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTF_ANYCAST | | 108 | xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTF_ANYCAST | |
@@ -116,18 +121,19 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, | |||
116 | static inline void | 121 | static inline void |
117 | _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse) | 122 | _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse) |
118 | { | 123 | { |
124 | struct flowi6 *fl6 = &fl->u.ip6; | ||
119 | int onlyproto = 0; | 125 | int onlyproto = 0; |
120 | u16 offset = skb_network_header_len(skb); | 126 | u16 offset = skb_network_header_len(skb); |
121 | struct ipv6hdr *hdr = ipv6_hdr(skb); | 127 | const struct ipv6hdr *hdr = ipv6_hdr(skb); |
122 | struct ipv6_opt_hdr *exthdr; | 128 | struct ipv6_opt_hdr *exthdr; |
123 | const unsigned char *nh = skb_network_header(skb); | 129 | const unsigned char *nh = skb_network_header(skb); |
124 | u8 nexthdr = nh[IP6CB(skb)->nhoff]; | 130 | u8 nexthdr = nh[IP6CB(skb)->nhoff]; |
125 | 131 | ||
126 | memset(fl, 0, sizeof(struct flowi)); | 132 | memset(fl6, 0, sizeof(struct flowi6)); |
127 | fl->mark = skb->mark; | 133 | fl6->flowi6_mark = skb->mark; |
128 | 134 | ||
129 | ipv6_addr_copy(&fl->fl6_dst, reverse ? &hdr->saddr : &hdr->daddr); | 135 | ipv6_addr_copy(&fl6->daddr, reverse ? &hdr->saddr : &hdr->daddr); |
130 | ipv6_addr_copy(&fl->fl6_src, reverse ? &hdr->daddr : &hdr->saddr); | 136 | ipv6_addr_copy(&fl6->saddr, reverse ? &hdr->daddr : &hdr->saddr); |
131 | 137 | ||
132 | while (nh + offset + 1 < skb->data || | 138 | while (nh + offset + 1 < skb->data || |
133 | pskb_may_pull(skb, nh + offset + 1 - skb->data)) { | 139 | pskb_may_pull(skb, nh + offset + 1 - skb->data)) { |
@@ -154,20 +160,20 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse) | |||
154 | pskb_may_pull(skb, nh + offset + 4 - skb->data))) { | 160 | pskb_may_pull(skb, nh + offset + 4 - skb->data))) { |
155 | __be16 *ports = (__be16 *)exthdr; | 161 | __be16 *ports = (__be16 *)exthdr; |
156 | 162 | ||
157 | fl->fl_ip_sport = ports[!!reverse]; | 163 | fl6->fl6_sport = ports[!!reverse]; |
158 | fl->fl_ip_dport = ports[!reverse]; | 164 | fl6->fl6_dport = ports[!reverse]; |
159 | } | 165 | } |
160 | fl->proto = nexthdr; | 166 | fl6->flowi6_proto = nexthdr; |
161 | return; | 167 | return; |
162 | 168 | ||
163 | case IPPROTO_ICMPV6: | 169 | case IPPROTO_ICMPV6: |
164 | if (!onlyproto && pskb_may_pull(skb, nh + offset + 2 - skb->data)) { | 170 | if (!onlyproto && pskb_may_pull(skb, nh + offset + 2 - skb->data)) { |
165 | u8 *icmp = (u8 *)exthdr; | 171 | u8 *icmp = (u8 *)exthdr; |
166 | 172 | ||
167 | fl->fl_icmp_type = icmp[0]; | 173 | fl6->fl6_icmp_type = icmp[0]; |
168 | fl->fl_icmp_code = icmp[1]; | 174 | fl6->fl6_icmp_code = icmp[1]; |
169 | } | 175 | } |
170 | fl->proto = nexthdr; | 176 | fl6->flowi6_proto = nexthdr; |
171 | return; | 177 | return; |
172 | 178 | ||
173 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 179 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) |
@@ -176,9 +182,9 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse) | |||
176 | struct ip6_mh *mh; | 182 | struct ip6_mh *mh; |
177 | mh = (struct ip6_mh *)exthdr; | 183 | mh = (struct ip6_mh *)exthdr; |
178 | 184 | ||
179 | fl->fl_mh_type = mh->ip6mh_type; | 185 | fl6->fl6_mh_type = mh->ip6mh_type; |
180 | } | 186 | } |
181 | fl->proto = nexthdr; | 187 | fl6->flowi6_proto = nexthdr; |
182 | return; | 188 | return; |
183 | #endif | 189 | #endif |
184 | 190 | ||
@@ -187,8 +193,8 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse) | |||
187 | case IPPROTO_ESP: | 193 | case IPPROTO_ESP: |
188 | case IPPROTO_COMP: | 194 | case IPPROTO_COMP: |
189 | default: | 195 | default: |
190 | fl->fl_ipsec_spi = 0; | 196 | fl6->fl6_ipsec_spi = 0; |
191 | fl->proto = nexthdr; | 197 | fl6->flowi6_proto = nexthdr; |
192 | return; | 198 | return; |
193 | } | 199 | } |
194 | } | 200 | } |
@@ -199,7 +205,7 @@ static inline int xfrm6_garbage_collect(struct dst_ops *ops) | |||
199 | struct net *net = container_of(ops, struct net, xfrm.xfrm6_dst_ops); | 205 | struct net *net = container_of(ops, struct net, xfrm.xfrm6_dst_ops); |
200 | 206 | ||
201 | xfrm6_policy_afinfo.garbage_collect(net); | 207 | xfrm6_policy_afinfo.garbage_collect(net); |
202 | return (atomic_read(&ops->entries) > ops->gc_thresh * 2); | 208 | return dst_entries_get_fast(ops) > ops->gc_thresh * 2; |
203 | } | 209 | } |
204 | 210 | ||
205 | static void xfrm6_update_pmtu(struct dst_entry *dst, u32 mtu) | 211 | static void xfrm6_update_pmtu(struct dst_entry *dst, u32 mtu) |
@@ -216,6 +222,9 @@ static void xfrm6_dst_destroy(struct dst_entry *dst) | |||
216 | 222 | ||
217 | if (likely(xdst->u.rt6.rt6i_idev)) | 223 | if (likely(xdst->u.rt6.rt6i_idev)) |
218 | in6_dev_put(xdst->u.rt6.rt6i_idev); | 224 | in6_dev_put(xdst->u.rt6.rt6i_idev); |
225 | dst_destroy_metrics_generic(dst); | ||
226 | if (likely(xdst->u.rt6.rt6i_peer)) | ||
227 | inet_putpeer(xdst->u.rt6.rt6i_peer); | ||
219 | xfrm_dst_destroy(xdst); | 228 | xfrm_dst_destroy(xdst); |
220 | } | 229 | } |
221 | 230 | ||
@@ -251,11 +260,11 @@ static struct dst_ops xfrm6_dst_ops = { | |||
251 | .protocol = cpu_to_be16(ETH_P_IPV6), | 260 | .protocol = cpu_to_be16(ETH_P_IPV6), |
252 | .gc = xfrm6_garbage_collect, | 261 | .gc = xfrm6_garbage_collect, |
253 | .update_pmtu = xfrm6_update_pmtu, | 262 | .update_pmtu = xfrm6_update_pmtu, |
263 | .cow_metrics = dst_cow_metrics_generic, | ||
254 | .destroy = xfrm6_dst_destroy, | 264 | .destroy = xfrm6_dst_destroy, |
255 | .ifdown = xfrm6_dst_ifdown, | 265 | .ifdown = xfrm6_dst_ifdown, |
256 | .local_out = __ip6_local_out, | 266 | .local_out = __ip6_local_out, |
257 | .gc_thresh = 1024, | 267 | .gc_thresh = 1024, |
258 | .entries = ATOMIC_INIT(0), | ||
259 | }; | 268 | }; |
260 | 269 | ||
261 | static struct xfrm_policy_afinfo xfrm6_policy_afinfo = { | 270 | static struct xfrm_policy_afinfo xfrm6_policy_afinfo = { |
@@ -267,6 +276,7 @@ static struct xfrm_policy_afinfo xfrm6_policy_afinfo = { | |||
267 | .get_tos = xfrm6_get_tos, | 276 | .get_tos = xfrm6_get_tos, |
268 | .init_path = xfrm6_init_path, | 277 | .init_path = xfrm6_init_path, |
269 | .fill_dst = xfrm6_fill_dst, | 278 | .fill_dst = xfrm6_fill_dst, |
279 | .blackhole_route = ip6_blackhole_route, | ||
270 | }; | 280 | }; |
271 | 281 | ||
272 | static int __init xfrm6_policy_init(void) | 282 | static int __init xfrm6_policy_init(void) |
@@ -312,11 +322,13 @@ int __init xfrm6_init(void) | |||
312 | */ | 322 | */ |
313 | gc_thresh = FIB6_TABLE_HASHSZ * 8; | 323 | gc_thresh = FIB6_TABLE_HASHSZ * 8; |
314 | xfrm6_dst_ops.gc_thresh = (gc_thresh < 1024) ? 1024 : gc_thresh; | 324 | xfrm6_dst_ops.gc_thresh = (gc_thresh < 1024) ? 1024 : gc_thresh; |
325 | dst_entries_init(&xfrm6_dst_ops); | ||
315 | 326 | ||
316 | ret = xfrm6_policy_init(); | 327 | ret = xfrm6_policy_init(); |
317 | if (ret) | 328 | if (ret) { |
329 | dst_entries_destroy(&xfrm6_dst_ops); | ||
318 | goto out; | 330 | goto out; |
319 | 331 | } | |
320 | ret = xfrm6_state_init(); | 332 | ret = xfrm6_state_init(); |
321 | if (ret) | 333 | if (ret) |
322 | goto out_policy; | 334 | goto out_policy; |
@@ -341,4 +353,5 @@ void xfrm6_fini(void) | |||
341 | //xfrm6_input_fini(); | 353 | //xfrm6_input_fini(); |
342 | xfrm6_policy_fini(); | 354 | xfrm6_policy_fini(); |
343 | xfrm6_state_fini(); | 355 | xfrm6_state_fini(); |
356 | dst_entries_destroy(&xfrm6_dst_ops); | ||
344 | } | 357 | } |
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c index a67575d472a3..248f0b2a7ee9 100644 --- a/net/ipv6/xfrm6_state.c +++ b/net/ipv6/xfrm6_state.c | |||
@@ -20,26 +20,28 @@ | |||
20 | #include <net/addrconf.h> | 20 | #include <net/addrconf.h> |
21 | 21 | ||
22 | static void | 22 | static void |
23 | __xfrm6_init_tempsel(struct xfrm_selector *sel, struct flowi *fl) | 23 | __xfrm6_init_tempsel(struct xfrm_selector *sel, const struct flowi *fl) |
24 | { | 24 | { |
25 | const struct flowi6 *fl6 = &fl->u.ip6; | ||
26 | |||
25 | /* Initialize temporary selector matching only | 27 | /* Initialize temporary selector matching only |
26 | * to current session. */ | 28 | * to current session. */ |
27 | ipv6_addr_copy((struct in6_addr *)&sel->daddr, &fl->fl6_dst); | 29 | ipv6_addr_copy((struct in6_addr *)&sel->daddr, &fl6->daddr); |
28 | ipv6_addr_copy((struct in6_addr *)&sel->saddr, &fl->fl6_src); | 30 | ipv6_addr_copy((struct in6_addr *)&sel->saddr, &fl6->saddr); |
29 | sel->dport = xfrm_flowi_dport(fl); | 31 | sel->dport = xfrm_flowi_dport(fl, &fl6->uli); |
30 | sel->dport_mask = htons(0xffff); | 32 | sel->dport_mask = htons(0xffff); |
31 | sel->sport = xfrm_flowi_sport(fl); | 33 | sel->sport = xfrm_flowi_sport(fl, &fl6->uli); |
32 | sel->sport_mask = htons(0xffff); | 34 | sel->sport_mask = htons(0xffff); |
33 | sel->family = AF_INET6; | 35 | sel->family = AF_INET6; |
34 | sel->prefixlen_d = 128; | 36 | sel->prefixlen_d = 128; |
35 | sel->prefixlen_s = 128; | 37 | sel->prefixlen_s = 128; |
36 | sel->proto = fl->proto; | 38 | sel->proto = fl6->flowi6_proto; |
37 | sel->ifindex = fl->oif; | 39 | sel->ifindex = fl6->flowi6_oif; |
38 | } | 40 | } |
39 | 41 | ||
40 | static void | 42 | static void |
41 | xfrm6_init_temprop(struct xfrm_state *x, struct xfrm_tmpl *tmpl, | 43 | xfrm6_init_temprop(struct xfrm_state *x, const struct xfrm_tmpl *tmpl, |
42 | xfrm_address_t *daddr, xfrm_address_t *saddr) | 44 | const xfrm_address_t *daddr, const xfrm_address_t *saddr) |
43 | { | 45 | { |
44 | x->id = tmpl->id; | 46 | x->id = tmpl->id; |
45 | if (ipv6_addr_any((struct in6_addr*)&x->id.daddr)) | 47 | if (ipv6_addr_any((struct in6_addr*)&x->id.daddr)) |
@@ -176,6 +178,7 @@ static struct xfrm_state_afinfo xfrm6_state_afinfo = { | |||
176 | .tmpl_sort = __xfrm6_tmpl_sort, | 178 | .tmpl_sort = __xfrm6_tmpl_sort, |
177 | .state_sort = __xfrm6_state_sort, | 179 | .state_sort = __xfrm6_state_sort, |
178 | .output = xfrm6_output, | 180 | .output = xfrm6_output, |
181 | .output_finish = xfrm6_output_finish, | ||
179 | .extract_input = xfrm6_extract_input, | 182 | .extract_input = xfrm6_extract_input, |
180 | .extract_output = xfrm6_extract_output, | 183 | .extract_output = xfrm6_extract_output, |
181 | .transport_finish = xfrm6_transport_finish, | 184 | .transport_finish = xfrm6_transport_finish, |
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index 2ce3a8278f26..4fe1db12d2a3 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c | |||
@@ -68,7 +68,7 @@ static DEFINE_SPINLOCK(xfrm6_tunnel_spi_lock); | |||
68 | 68 | ||
69 | static struct kmem_cache *xfrm6_tunnel_spi_kmem __read_mostly; | 69 | static struct kmem_cache *xfrm6_tunnel_spi_kmem __read_mostly; |
70 | 70 | ||
71 | static inline unsigned xfrm6_tunnel_spi_hash_byaddr(xfrm_address_t *addr) | 71 | static inline unsigned xfrm6_tunnel_spi_hash_byaddr(const xfrm_address_t *addr) |
72 | { | 72 | { |
73 | unsigned h; | 73 | unsigned h; |
74 | 74 | ||
@@ -85,7 +85,7 @@ static inline unsigned xfrm6_tunnel_spi_hash_byspi(u32 spi) | |||
85 | return spi % XFRM6_TUNNEL_SPI_BYSPI_HSIZE; | 85 | return spi % XFRM6_TUNNEL_SPI_BYSPI_HSIZE; |
86 | } | 86 | } |
87 | 87 | ||
88 | static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(struct net *net, xfrm_address_t *saddr) | 88 | static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(struct net *net, const xfrm_address_t *saddr) |
89 | { | 89 | { |
90 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); | 90 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); |
91 | struct xfrm6_tunnel_spi *x6spi; | 91 | struct xfrm6_tunnel_spi *x6spi; |
@@ -101,7 +101,7 @@ static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(struct net *net, xfrm_ | |||
101 | return NULL; | 101 | return NULL; |
102 | } | 102 | } |
103 | 103 | ||
104 | __be32 xfrm6_tunnel_spi_lookup(struct net *net, xfrm_address_t *saddr) | 104 | __be32 xfrm6_tunnel_spi_lookup(struct net *net, const xfrm_address_t *saddr) |
105 | { | 105 | { |
106 | struct xfrm6_tunnel_spi *x6spi; | 106 | struct xfrm6_tunnel_spi *x6spi; |
107 | u32 spi; | 107 | u32 spi; |
@@ -199,7 +199,7 @@ static void x6spi_destroy_rcu(struct rcu_head *head) | |||
199 | container_of(head, struct xfrm6_tunnel_spi, rcu_head)); | 199 | container_of(head, struct xfrm6_tunnel_spi, rcu_head)); |
200 | } | 200 | } |
201 | 201 | ||
202 | void xfrm6_tunnel_free_spi(struct net *net, xfrm_address_t *saddr) | 202 | static void xfrm6_tunnel_free_spi(struct net *net, xfrm_address_t *saddr) |
203 | { | 203 | { |
204 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); | 204 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); |
205 | struct xfrm6_tunnel_spi *x6spi; | 205 | struct xfrm6_tunnel_spi *x6spi; |
@@ -223,8 +223,6 @@ void xfrm6_tunnel_free_spi(struct net *net, xfrm_address_t *saddr) | |||
223 | spin_unlock_bh(&xfrm6_tunnel_spi_lock); | 223 | spin_unlock_bh(&xfrm6_tunnel_spi_lock); |
224 | } | 224 | } |
225 | 225 | ||
226 | EXPORT_SYMBOL(xfrm6_tunnel_free_spi); | ||
227 | |||
228 | static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) | 226 | static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) |
229 | { | 227 | { |
230 | skb_push(skb, -skb_network_offset(skb)); | 228 | skb_push(skb, -skb_network_offset(skb)); |
@@ -239,11 +237,11 @@ static int xfrm6_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) | |||
239 | static int xfrm6_tunnel_rcv(struct sk_buff *skb) | 237 | static int xfrm6_tunnel_rcv(struct sk_buff *skb) |
240 | { | 238 | { |
241 | struct net *net = dev_net(skb->dev); | 239 | struct net *net = dev_net(skb->dev); |
242 | struct ipv6hdr *iph = ipv6_hdr(skb); | 240 | const struct ipv6hdr *iph = ipv6_hdr(skb); |
243 | __be32 spi; | 241 | __be32 spi; |
244 | 242 | ||
245 | spi = xfrm6_tunnel_spi_lookup(net, (xfrm_address_t *)&iph->saddr); | 243 | spi = xfrm6_tunnel_spi_lookup(net, (const xfrm_address_t *)&iph->saddr); |
246 | return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi) > 0 ? : 0; | 244 | return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi); |
247 | } | 245 | } |
248 | 246 | ||
249 | static int xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | 247 | static int xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt, |
@@ -317,13 +315,13 @@ static const struct xfrm_type xfrm6_tunnel_type = { | |||
317 | .output = xfrm6_tunnel_output, | 315 | .output = xfrm6_tunnel_output, |
318 | }; | 316 | }; |
319 | 317 | ||
320 | static struct xfrm6_tunnel xfrm6_tunnel_handler = { | 318 | static struct xfrm6_tunnel xfrm6_tunnel_handler __read_mostly = { |
321 | .handler = xfrm6_tunnel_rcv, | 319 | .handler = xfrm6_tunnel_rcv, |
322 | .err_handler = xfrm6_tunnel_err, | 320 | .err_handler = xfrm6_tunnel_err, |
323 | .priority = 2, | 321 | .priority = 2, |
324 | }; | 322 | }; |
325 | 323 | ||
326 | static struct xfrm6_tunnel xfrm46_tunnel_handler = { | 324 | static struct xfrm6_tunnel xfrm46_tunnel_handler __read_mostly = { |
327 | .handler = xfrm6_tunnel_rcv, | 325 | .handler = xfrm6_tunnel_rcv, |
328 | .err_handler = xfrm6_tunnel_err, | 326 | .err_handler = xfrm6_tunnel_err, |
329 | .priority = 2, | 327 | .priority = 2, |