diff options
Diffstat (limited to 'net/ipv6')
41 files changed, 2253 insertions, 651 deletions
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index 11b13ea69db4..d92e5586783e 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig | |||
@@ -21,24 +21,6 @@ menuconfig IPV6 | |||
21 | 21 | ||
22 | if IPV6 | 22 | if IPV6 |
23 | 23 | ||
24 | config IPV6_PRIVACY | ||
25 | bool "IPv6: Privacy Extensions (RFC 3041) support" | ||
26 | ---help--- | ||
27 | Privacy Extensions for Stateless Address Autoconfiguration in IPv6 | ||
28 | support. With this option, additional periodically-altered | ||
29 | pseudo-random global-scope unicast address(es) will be assigned to | ||
30 | your interface(s). | ||
31 | |||
32 | We use our standard pseudo-random algorithm to generate the | ||
33 | randomized interface identifier, instead of one described in RFC 3041. | ||
34 | |||
35 | By default the kernel does not generate temporary addresses. | ||
36 | To use temporary addresses, do | ||
37 | |||
38 | echo 2 >/proc/sys/net/ipv6/conf/all/use_tempaddr | ||
39 | |||
40 | See <file:Documentation/networking/ip-sysctl.txt> for details. | ||
41 | |||
42 | config IPV6_ROUTER_PREF | 24 | config IPV6_ROUTER_PREF |
43 | bool "IPv6: Router Preference (RFC 4191) support" | 25 | bool "IPv6: Router Preference (RFC 4191) support" |
44 | ---help--- | 26 | ---help--- |
@@ -153,6 +135,17 @@ config INET6_XFRM_MODE_ROUTEOPTIMIZATION | |||
153 | ---help--- | 135 | ---help--- |
154 | Support for MIPv6 route optimization mode. | 136 | Support for MIPv6 route optimization mode. |
155 | 137 | ||
138 | config IPV6_VTI | ||
139 | tristate "Virtual (secure) IPv6: tunneling" | ||
140 | select IPV6_TUNNEL | ||
141 | depends on INET6_XFRM_MODE_TUNNEL | ||
142 | ---help--- | ||
143 | Tunneling means encapsulating data of one protocol type within | ||
144 | another protocol and sending it over a channel that understands the | ||
145 | encapsulating protocol. This can be used with xfrm mode tunnel to give | ||
146 | the notion of a secure tunnel for IPSEC and then use routing protocol | ||
147 | on top. | ||
148 | |||
156 | config IPV6_SIT | 149 | config IPV6_SIT |
157 | tristate "IPv6: IPv6-in-IPv4 tunnel (SIT driver)" | 150 | tristate "IPv6: IPv6-in-IPv4 tunnel (SIT driver)" |
158 | select INET_TUNNEL | 151 | select INET_TUNNEL |
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index 470a9c008e9b..17bb830872db 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile | |||
@@ -36,6 +36,7 @@ obj-$(CONFIG_INET6_XFRM_MODE_BEET) += xfrm6_mode_beet.o | |||
36 | obj-$(CONFIG_IPV6_MIP6) += mip6.o | 36 | obj-$(CONFIG_IPV6_MIP6) += mip6.o |
37 | obj-$(CONFIG_NETFILTER) += netfilter/ | 37 | obj-$(CONFIG_NETFILTER) += netfilter/ |
38 | 38 | ||
39 | obj-$(CONFIG_IPV6_VTI) += ip6_vti.o | ||
39 | obj-$(CONFIG_IPV6_SIT) += sit.o | 40 | obj-$(CONFIG_IPV6_SIT) += sit.o |
40 | obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o | 41 | obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o |
41 | obj-$(CONFIG_IPV6_GRE) += ip6_gre.o | 42 | obj-$(CONFIG_IPV6_GRE) += ip6_gre.o |
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index cd3fb301da38..542d09561ed6 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -83,11 +83,7 @@ | |||
83 | #include <linux/if_tunnel.h> | 83 | #include <linux/if_tunnel.h> |
84 | #include <linux/rtnetlink.h> | 84 | #include <linux/rtnetlink.h> |
85 | #include <linux/netconf.h> | 85 | #include <linux/netconf.h> |
86 | |||
87 | #ifdef CONFIG_IPV6_PRIVACY | ||
88 | #include <linux/random.h> | 86 | #include <linux/random.h> |
89 | #endif | ||
90 | |||
91 | #include <linux/uaccess.h> | 87 | #include <linux/uaccess.h> |
92 | #include <asm/unaligned.h> | 88 | #include <asm/unaligned.h> |
93 | 89 | ||
@@ -124,11 +120,9 @@ static inline void addrconf_sysctl_unregister(struct inet6_dev *idev) | |||
124 | } | 120 | } |
125 | #endif | 121 | #endif |
126 | 122 | ||
127 | #ifdef CONFIG_IPV6_PRIVACY | ||
128 | static void __ipv6_regen_rndid(struct inet6_dev *idev); | 123 | static void __ipv6_regen_rndid(struct inet6_dev *idev); |
129 | static void __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr); | 124 | static void __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr); |
130 | static void ipv6_regen_rndid(unsigned long data); | 125 | static void ipv6_regen_rndid(unsigned long data); |
131 | #endif | ||
132 | 126 | ||
133 | static int ipv6_generate_eui64(u8 *eui, struct net_device *dev); | 127 | static int ipv6_generate_eui64(u8 *eui, struct net_device *dev); |
134 | static int ipv6_count_addresses(struct inet6_dev *idev); | 128 | static int ipv6_count_addresses(struct inet6_dev *idev); |
@@ -183,13 +177,11 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = { | |||
183 | .rtr_solicits = MAX_RTR_SOLICITATIONS, | 177 | .rtr_solicits = MAX_RTR_SOLICITATIONS, |
184 | .rtr_solicit_interval = RTR_SOLICITATION_INTERVAL, | 178 | .rtr_solicit_interval = RTR_SOLICITATION_INTERVAL, |
185 | .rtr_solicit_delay = MAX_RTR_SOLICITATION_DELAY, | 179 | .rtr_solicit_delay = MAX_RTR_SOLICITATION_DELAY, |
186 | #ifdef CONFIG_IPV6_PRIVACY | ||
187 | .use_tempaddr = 0, | 180 | .use_tempaddr = 0, |
188 | .temp_valid_lft = TEMP_VALID_LIFETIME, | 181 | .temp_valid_lft = TEMP_VALID_LIFETIME, |
189 | .temp_prefered_lft = TEMP_PREFERRED_LIFETIME, | 182 | .temp_prefered_lft = TEMP_PREFERRED_LIFETIME, |
190 | .regen_max_retry = REGEN_MAX_RETRY, | 183 | .regen_max_retry = REGEN_MAX_RETRY, |
191 | .max_desync_factor = MAX_DESYNC_FACTOR, | 184 | .max_desync_factor = MAX_DESYNC_FACTOR, |
192 | #endif | ||
193 | .max_addresses = IPV6_MAX_ADDRESSES, | 185 | .max_addresses = IPV6_MAX_ADDRESSES, |
194 | .accept_ra_defrtr = 1, | 186 | .accept_ra_defrtr = 1, |
195 | .accept_ra_pinfo = 1, | 187 | .accept_ra_pinfo = 1, |
@@ -221,13 +213,11 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { | |||
221 | .rtr_solicits = MAX_RTR_SOLICITATIONS, | 213 | .rtr_solicits = MAX_RTR_SOLICITATIONS, |
222 | .rtr_solicit_interval = RTR_SOLICITATION_INTERVAL, | 214 | .rtr_solicit_interval = RTR_SOLICITATION_INTERVAL, |
223 | .rtr_solicit_delay = MAX_RTR_SOLICITATION_DELAY, | 215 | .rtr_solicit_delay = MAX_RTR_SOLICITATION_DELAY, |
224 | #ifdef CONFIG_IPV6_PRIVACY | ||
225 | .use_tempaddr = 0, | 216 | .use_tempaddr = 0, |
226 | .temp_valid_lft = TEMP_VALID_LIFETIME, | 217 | .temp_valid_lft = TEMP_VALID_LIFETIME, |
227 | .temp_prefered_lft = TEMP_PREFERRED_LIFETIME, | 218 | .temp_prefered_lft = TEMP_PREFERRED_LIFETIME, |
228 | .regen_max_retry = REGEN_MAX_RETRY, | 219 | .regen_max_retry = REGEN_MAX_RETRY, |
229 | .max_desync_factor = MAX_DESYNC_FACTOR, | 220 | .max_desync_factor = MAX_DESYNC_FACTOR, |
230 | #endif | ||
231 | .max_addresses = IPV6_MAX_ADDRESSES, | 221 | .max_addresses = IPV6_MAX_ADDRESSES, |
232 | .accept_ra_defrtr = 1, | 222 | .accept_ra_defrtr = 1, |
233 | .accept_ra_pinfo = 1, | 223 | .accept_ra_pinfo = 1, |
@@ -371,7 +361,6 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev) | |||
371 | } | 361 | } |
372 | #endif | 362 | #endif |
373 | 363 | ||
374 | #ifdef CONFIG_IPV6_PRIVACY | ||
375 | INIT_LIST_HEAD(&ndev->tempaddr_list); | 364 | INIT_LIST_HEAD(&ndev->tempaddr_list); |
376 | setup_timer(&ndev->regen_timer, ipv6_regen_rndid, (unsigned long)ndev); | 365 | setup_timer(&ndev->regen_timer, ipv6_regen_rndid, (unsigned long)ndev); |
377 | if ((dev->flags&IFF_LOOPBACK) || | 366 | if ((dev->flags&IFF_LOOPBACK) || |
@@ -384,7 +373,7 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev) | |||
384 | in6_dev_hold(ndev); | 373 | in6_dev_hold(ndev); |
385 | ipv6_regen_rndid((unsigned long) ndev); | 374 | ipv6_regen_rndid((unsigned long) ndev); |
386 | } | 375 | } |
387 | #endif | 376 | |
388 | ndev->token = in6addr_any; | 377 | ndev->token = in6addr_any; |
389 | 378 | ||
390 | if (netif_running(dev) && addrconf_qdisc_ok(dev)) | 379 | if (netif_running(dev) && addrconf_qdisc_ok(dev)) |
@@ -865,12 +854,10 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, | |||
865 | /* Add to inet6_dev unicast addr list. */ | 854 | /* Add to inet6_dev unicast addr list. */ |
866 | ipv6_link_dev_addr(idev, ifa); | 855 | ipv6_link_dev_addr(idev, ifa); |
867 | 856 | ||
868 | #ifdef CONFIG_IPV6_PRIVACY | ||
869 | if (ifa->flags&IFA_F_TEMPORARY) { | 857 | if (ifa->flags&IFA_F_TEMPORARY) { |
870 | list_add(&ifa->tmp_list, &idev->tempaddr_list); | 858 | list_add(&ifa->tmp_list, &idev->tempaddr_list); |
871 | in6_ifa_hold(ifa); | 859 | in6_ifa_hold(ifa); |
872 | } | 860 | } |
873 | #endif | ||
874 | 861 | ||
875 | in6_ifa_hold(ifa); | 862 | in6_ifa_hold(ifa); |
876 | write_unlock(&idev->lock); | 863 | write_unlock(&idev->lock); |
@@ -913,7 +900,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) | |||
913 | spin_unlock_bh(&addrconf_hash_lock); | 900 | spin_unlock_bh(&addrconf_hash_lock); |
914 | 901 | ||
915 | write_lock_bh(&idev->lock); | 902 | write_lock_bh(&idev->lock); |
916 | #ifdef CONFIG_IPV6_PRIVACY | 903 | |
917 | if (ifp->flags&IFA_F_TEMPORARY) { | 904 | if (ifp->flags&IFA_F_TEMPORARY) { |
918 | list_del(&ifp->tmp_list); | 905 | list_del(&ifp->tmp_list); |
919 | if (ifp->ifpub) { | 906 | if (ifp->ifpub) { |
@@ -922,7 +909,6 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) | |||
922 | } | 909 | } |
923 | __in6_ifa_put(ifp); | 910 | __in6_ifa_put(ifp); |
924 | } | 911 | } |
925 | #endif | ||
926 | 912 | ||
927 | list_for_each_entry_safe(ifa, ifn, &idev->addr_list, if_list) { | 913 | list_for_each_entry_safe(ifa, ifn, &idev->addr_list, if_list) { |
928 | if (ifa == ifp) { | 914 | if (ifa == ifp) { |
@@ -1013,7 +999,6 @@ out: | |||
1013 | in6_ifa_put(ifp); | 999 | in6_ifa_put(ifp); |
1014 | } | 1000 | } |
1015 | 1001 | ||
1016 | #ifdef CONFIG_IPV6_PRIVACY | ||
1017 | static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *ift) | 1002 | static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *ift) |
1018 | { | 1003 | { |
1019 | struct inet6_dev *idev = ifp->idev; | 1004 | struct inet6_dev *idev = ifp->idev; |
@@ -1116,7 +1101,6 @@ retry: | |||
1116 | out: | 1101 | out: |
1117 | return ret; | 1102 | return ret; |
1118 | } | 1103 | } |
1119 | #endif | ||
1120 | 1104 | ||
1121 | /* | 1105 | /* |
1122 | * Choose an appropriate source address (RFC3484) | 1106 | * Choose an appropriate source address (RFC3484) |
@@ -1131,9 +1115,7 @@ enum { | |||
1131 | #endif | 1115 | #endif |
1132 | IPV6_SADDR_RULE_OIF, | 1116 | IPV6_SADDR_RULE_OIF, |
1133 | IPV6_SADDR_RULE_LABEL, | 1117 | IPV6_SADDR_RULE_LABEL, |
1134 | #ifdef CONFIG_IPV6_PRIVACY | ||
1135 | IPV6_SADDR_RULE_PRIVACY, | 1118 | IPV6_SADDR_RULE_PRIVACY, |
1136 | #endif | ||
1137 | IPV6_SADDR_RULE_ORCHID, | 1119 | IPV6_SADDR_RULE_ORCHID, |
1138 | IPV6_SADDR_RULE_PREFIX, | 1120 | IPV6_SADDR_RULE_PREFIX, |
1139 | IPV6_SADDR_RULE_MAX | 1121 | IPV6_SADDR_RULE_MAX |
@@ -1247,7 +1229,6 @@ static int ipv6_get_saddr_eval(struct net *net, | |||
1247 | &score->ifa->addr, score->addr_type, | 1229 | &score->ifa->addr, score->addr_type, |
1248 | score->ifa->idev->dev->ifindex) == dst->label; | 1230 | score->ifa->idev->dev->ifindex) == dst->label; |
1249 | break; | 1231 | break; |
1250 | #ifdef CONFIG_IPV6_PRIVACY | ||
1251 | case IPV6_SADDR_RULE_PRIVACY: | 1232 | case IPV6_SADDR_RULE_PRIVACY: |
1252 | { | 1233 | { |
1253 | /* Rule 7: Prefer public address | 1234 | /* Rule 7: Prefer public address |
@@ -1259,7 +1240,6 @@ static int ipv6_get_saddr_eval(struct net *net, | |||
1259 | ret = (!(score->ifa->flags & IFA_F_TEMPORARY)) ^ preftmp; | 1240 | ret = (!(score->ifa->flags & IFA_F_TEMPORARY)) ^ preftmp; |
1260 | break; | 1241 | break; |
1261 | } | 1242 | } |
1262 | #endif | ||
1263 | case IPV6_SADDR_RULE_ORCHID: | 1243 | case IPV6_SADDR_RULE_ORCHID: |
1264 | /* Rule 8-: Prefer ORCHID vs ORCHID or | 1244 | /* Rule 8-: Prefer ORCHID vs ORCHID or |
1265 | * non-ORCHID vs non-ORCHID | 1245 | * non-ORCHID vs non-ORCHID |
@@ -1588,7 +1568,6 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp, int dad_failed) | |||
1588 | if (dad_failed) | 1568 | if (dad_failed) |
1589 | ipv6_ifa_notify(0, ifp); | 1569 | ipv6_ifa_notify(0, ifp); |
1590 | in6_ifa_put(ifp); | 1570 | in6_ifa_put(ifp); |
1591 | #ifdef CONFIG_IPV6_PRIVACY | ||
1592 | } else if (ifp->flags&IFA_F_TEMPORARY) { | 1571 | } else if (ifp->flags&IFA_F_TEMPORARY) { |
1593 | struct inet6_ifaddr *ifpub; | 1572 | struct inet6_ifaddr *ifpub; |
1594 | spin_lock_bh(&ifp->lock); | 1573 | spin_lock_bh(&ifp->lock); |
@@ -1602,7 +1581,6 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp, int dad_failed) | |||
1602 | spin_unlock_bh(&ifp->lock); | 1581 | spin_unlock_bh(&ifp->lock); |
1603 | } | 1582 | } |
1604 | ipv6_del_addr(ifp); | 1583 | ipv6_del_addr(ifp); |
1605 | #endif | ||
1606 | } else | 1584 | } else |
1607 | ipv6_del_addr(ifp); | 1585 | ipv6_del_addr(ifp); |
1608 | } | 1586 | } |
@@ -1851,7 +1829,6 @@ static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev) | |||
1851 | return err; | 1829 | return err; |
1852 | } | 1830 | } |
1853 | 1831 | ||
1854 | #ifdef CONFIG_IPV6_PRIVACY | ||
1855 | /* (re)generation of randomized interface identifier (RFC 3041 3.2, 3.5) */ | 1832 | /* (re)generation of randomized interface identifier (RFC 3041 3.2, 3.5) */ |
1856 | static void __ipv6_regen_rndid(struct inet6_dev *idev) | 1833 | static void __ipv6_regen_rndid(struct inet6_dev *idev) |
1857 | { | 1834 | { |
@@ -1919,7 +1896,6 @@ static void __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmp | |||
1919 | if (tmpaddr && memcmp(idev->rndid, &tmpaddr->s6_addr[8], 8) == 0) | 1896 | if (tmpaddr && memcmp(idev->rndid, &tmpaddr->s6_addr[8], 8) == 0) |
1920 | __ipv6_regen_rndid(idev); | 1897 | __ipv6_regen_rndid(idev); |
1921 | } | 1898 | } |
1922 | #endif | ||
1923 | 1899 | ||
1924 | /* | 1900 | /* |
1925 | * Add prefix route. | 1901 | * Add prefix route. |
@@ -2207,9 +2183,7 @@ ok: | |||
2207 | if (ifp) { | 2183 | if (ifp) { |
2208 | int flags; | 2184 | int flags; |
2209 | unsigned long now; | 2185 | unsigned long now; |
2210 | #ifdef CONFIG_IPV6_PRIVACY | ||
2211 | struct inet6_ifaddr *ift; | 2186 | struct inet6_ifaddr *ift; |
2212 | #endif | ||
2213 | u32 stored_lft; | 2187 | u32 stored_lft; |
2214 | 2188 | ||
2215 | /* update lifetime (RFC2462 5.5.3 e) */ | 2189 | /* update lifetime (RFC2462 5.5.3 e) */ |
@@ -2250,7 +2224,6 @@ ok: | |||
2250 | } else | 2224 | } else |
2251 | spin_unlock(&ifp->lock); | 2225 | spin_unlock(&ifp->lock); |
2252 | 2226 | ||
2253 | #ifdef CONFIG_IPV6_PRIVACY | ||
2254 | read_lock_bh(&in6_dev->lock); | 2227 | read_lock_bh(&in6_dev->lock); |
2255 | /* update all temporary addresses in the list */ | 2228 | /* update all temporary addresses in the list */ |
2256 | list_for_each_entry(ift, &in6_dev->tempaddr_list, | 2229 | list_for_each_entry(ift, &in6_dev->tempaddr_list, |
@@ -2315,7 +2288,7 @@ ok: | |||
2315 | } else { | 2288 | } else { |
2316 | read_unlock_bh(&in6_dev->lock); | 2289 | read_unlock_bh(&in6_dev->lock); |
2317 | } | 2290 | } |
2318 | #endif | 2291 | |
2319 | in6_ifa_put(ifp); | 2292 | in6_ifa_put(ifp); |
2320 | addrconf_verify(0); | 2293 | addrconf_verify(0); |
2321 | } | 2294 | } |
@@ -2995,7 +2968,6 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
2995 | if (!how) | 2968 | if (!how) |
2996 | idev->if_flags &= ~(IF_RS_SENT|IF_RA_RCVD|IF_READY); | 2969 | idev->if_flags &= ~(IF_RS_SENT|IF_RA_RCVD|IF_READY); |
2997 | 2970 | ||
2998 | #ifdef CONFIG_IPV6_PRIVACY | ||
2999 | if (how && del_timer(&idev->regen_timer)) | 2971 | if (how && del_timer(&idev->regen_timer)) |
3000 | in6_dev_put(idev); | 2972 | in6_dev_put(idev); |
3001 | 2973 | ||
@@ -3015,7 +2987,6 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
3015 | in6_ifa_put(ifa); | 2987 | in6_ifa_put(ifa); |
3016 | write_lock_bh(&idev->lock); | 2988 | write_lock_bh(&idev->lock); |
3017 | } | 2989 | } |
3018 | #endif | ||
3019 | 2990 | ||
3020 | while (!list_empty(&idev->addr_list)) { | 2991 | while (!list_empty(&idev->addr_list)) { |
3021 | ifa = list_first_entry(&idev->addr_list, | 2992 | ifa = list_first_entry(&idev->addr_list, |
@@ -3528,7 +3499,6 @@ restart: | |||
3528 | in6_ifa_put(ifp); | 3499 | in6_ifa_put(ifp); |
3529 | goto restart; | 3500 | goto restart; |
3530 | } | 3501 | } |
3531 | #ifdef CONFIG_IPV6_PRIVACY | ||
3532 | } else if ((ifp->flags&IFA_F_TEMPORARY) && | 3502 | } else if ((ifp->flags&IFA_F_TEMPORARY) && |
3533 | !(ifp->flags&IFA_F_TENTATIVE)) { | 3503 | !(ifp->flags&IFA_F_TENTATIVE)) { |
3534 | unsigned long regen_advance = ifp->idev->cnf.regen_max_retry * | 3504 | unsigned long regen_advance = ifp->idev->cnf.regen_max_retry * |
@@ -3556,7 +3526,6 @@ restart: | |||
3556 | } else if (time_before(ifp->tstamp + ifp->prefered_lft * HZ - regen_advance * HZ, next)) | 3526 | } else if (time_before(ifp->tstamp + ifp->prefered_lft * HZ - regen_advance * HZ, next)) |
3557 | next = ifp->tstamp + ifp->prefered_lft * HZ - regen_advance * HZ; | 3527 | next = ifp->tstamp + ifp->prefered_lft * HZ - regen_advance * HZ; |
3558 | spin_unlock(&ifp->lock); | 3528 | spin_unlock(&ifp->lock); |
3559 | #endif | ||
3560 | } else { | 3529 | } else { |
3561 | /* ifp->prefered_lft <= ifp->valid_lft */ | 3530 | /* ifp->prefered_lft <= ifp->valid_lft */ |
3562 | if (time_before(ifp->tstamp + ifp->prefered_lft * HZ, next)) | 3531 | if (time_before(ifp->tstamp + ifp->prefered_lft * HZ, next)) |
@@ -4128,13 +4097,11 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, | |||
4128 | jiffies_to_msecs(cnf->mldv1_unsolicited_report_interval); | 4097 | jiffies_to_msecs(cnf->mldv1_unsolicited_report_interval); |
4129 | array[DEVCONF_MLDV2_UNSOLICITED_REPORT_INTERVAL] = | 4098 | array[DEVCONF_MLDV2_UNSOLICITED_REPORT_INTERVAL] = |
4130 | jiffies_to_msecs(cnf->mldv2_unsolicited_report_interval); | 4099 | jiffies_to_msecs(cnf->mldv2_unsolicited_report_interval); |
4131 | #ifdef CONFIG_IPV6_PRIVACY | ||
4132 | array[DEVCONF_USE_TEMPADDR] = cnf->use_tempaddr; | 4100 | array[DEVCONF_USE_TEMPADDR] = cnf->use_tempaddr; |
4133 | array[DEVCONF_TEMP_VALID_LFT] = cnf->temp_valid_lft; | 4101 | array[DEVCONF_TEMP_VALID_LFT] = cnf->temp_valid_lft; |
4134 | array[DEVCONF_TEMP_PREFERED_LFT] = cnf->temp_prefered_lft; | 4102 | array[DEVCONF_TEMP_PREFERED_LFT] = cnf->temp_prefered_lft; |
4135 | array[DEVCONF_REGEN_MAX_RETRY] = cnf->regen_max_retry; | 4103 | array[DEVCONF_REGEN_MAX_RETRY] = cnf->regen_max_retry; |
4136 | array[DEVCONF_MAX_DESYNC_FACTOR] = cnf->max_desync_factor; | 4104 | array[DEVCONF_MAX_DESYNC_FACTOR] = cnf->max_desync_factor; |
4137 | #endif | ||
4138 | array[DEVCONF_MAX_ADDRESSES] = cnf->max_addresses; | 4105 | array[DEVCONF_MAX_ADDRESSES] = cnf->max_addresses; |
4139 | array[DEVCONF_ACCEPT_RA_DEFRTR] = cnf->accept_ra_defrtr; | 4106 | array[DEVCONF_ACCEPT_RA_DEFRTR] = cnf->accept_ra_defrtr; |
4140 | array[DEVCONF_ACCEPT_RA_PINFO] = cnf->accept_ra_pinfo; | 4107 | array[DEVCONF_ACCEPT_RA_PINFO] = cnf->accept_ra_pinfo; |
@@ -4828,7 +4795,6 @@ static struct addrconf_sysctl_table | |||
4828 | .mode = 0644, | 4795 | .mode = 0644, |
4829 | .proc_handler = proc_dointvec_ms_jiffies, | 4796 | .proc_handler = proc_dointvec_ms_jiffies, |
4830 | }, | 4797 | }, |
4831 | #ifdef CONFIG_IPV6_PRIVACY | ||
4832 | { | 4798 | { |
4833 | .procname = "use_tempaddr", | 4799 | .procname = "use_tempaddr", |
4834 | .data = &ipv6_devconf.use_tempaddr, | 4800 | .data = &ipv6_devconf.use_tempaddr, |
@@ -4864,7 +4830,6 @@ static struct addrconf_sysctl_table | |||
4864 | .mode = 0644, | 4830 | .mode = 0644, |
4865 | .proc_handler = proc_dointvec, | 4831 | .proc_handler = proc_dointvec, |
4866 | }, | 4832 | }, |
4867 | #endif | ||
4868 | { | 4833 | { |
4869 | .procname = "max_addresses", | 4834 | .procname = "max_addresses", |
4870 | .data = &ipv6_devconf.max_addresses, | 4835 | .data = &ipv6_devconf.max_addresses, |
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 7c96100b021e..6468bda1f2b9 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
@@ -110,11 +110,6 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol, | |||
110 | int try_loading_module = 0; | 110 | int try_loading_module = 0; |
111 | int err; | 111 | int err; |
112 | 112 | ||
113 | if (sock->type != SOCK_RAW && | ||
114 | sock->type != SOCK_DGRAM && | ||
115 | !inet_ehash_secret) | ||
116 | build_ehash_secret(); | ||
117 | |||
118 | /* Look for the requested type/protocol pair. */ | 113 | /* Look for the requested type/protocol pair. */ |
119 | lookup_protocol: | 114 | lookup_protocol: |
120 | err = -ESOCKTNOSUPPORT; | 115 | err = -ESOCKTNOSUPPORT; |
@@ -364,7 +359,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
364 | inet->inet_rcv_saddr = v4addr; | 359 | inet->inet_rcv_saddr = v4addr; |
365 | inet->inet_saddr = v4addr; | 360 | inet->inet_saddr = v4addr; |
366 | 361 | ||
367 | np->rcv_saddr = addr->sin6_addr; | 362 | sk->sk_v6_rcv_saddr = addr->sin6_addr; |
368 | 363 | ||
369 | if (!(addr_type & IPV6_ADDR_MULTICAST)) | 364 | if (!(addr_type & IPV6_ADDR_MULTICAST)) |
370 | np->saddr = addr->sin6_addr; | 365 | np->saddr = addr->sin6_addr; |
@@ -461,14 +456,14 @@ int inet6_getname(struct socket *sock, struct sockaddr *uaddr, | |||
461 | peer == 1) | 456 | peer == 1) |
462 | return -ENOTCONN; | 457 | return -ENOTCONN; |
463 | sin->sin6_port = inet->inet_dport; | 458 | sin->sin6_port = inet->inet_dport; |
464 | sin->sin6_addr = np->daddr; | 459 | sin->sin6_addr = sk->sk_v6_daddr; |
465 | if (np->sndflow) | 460 | if (np->sndflow) |
466 | sin->sin6_flowinfo = np->flow_label; | 461 | sin->sin6_flowinfo = np->flow_label; |
467 | } else { | 462 | } else { |
468 | if (ipv6_addr_any(&np->rcv_saddr)) | 463 | if (ipv6_addr_any(&sk->sk_v6_rcv_saddr)) |
469 | sin->sin6_addr = np->saddr; | 464 | sin->sin6_addr = np->saddr; |
470 | else | 465 | else |
471 | sin->sin6_addr = np->rcv_saddr; | 466 | sin->sin6_addr = sk->sk_v6_rcv_saddr; |
472 | 467 | ||
473 | sin->sin6_port = inet->inet_sport; | 468 | sin->sin6_port = inet->inet_sport; |
474 | } | 469 | } |
@@ -655,7 +650,7 @@ int inet6_sk_rebuild_header(struct sock *sk) | |||
655 | 650 | ||
656 | memset(&fl6, 0, sizeof(fl6)); | 651 | memset(&fl6, 0, sizeof(fl6)); |
657 | fl6.flowi6_proto = sk->sk_protocol; | 652 | fl6.flowi6_proto = sk->sk_protocol; |
658 | fl6.daddr = np->daddr; | 653 | fl6.daddr = sk->sk_v6_daddr; |
659 | fl6.saddr = np->saddr; | 654 | fl6.saddr = np->saddr; |
660 | fl6.flowlabel = np->flow_label; | 655 | fl6.flowlabel = np->flow_label; |
661 | fl6.flowi6_oif = sk->sk_bound_dev_if; | 656 | fl6.flowi6_oif = sk->sk_bound_dev_if; |
@@ -870,8 +865,6 @@ static int __init inet6_init(void) | |||
870 | if (err) | 865 | if (err) |
871 | goto out_sock_register_fail; | 866 | goto out_sock_register_fail; |
872 | 867 | ||
873 | tcpv6_prot.sysctl_mem = init_net.ipv4.sysctl_tcp_mem; | ||
874 | |||
875 | /* | 868 | /* |
876 | * ipngwg API draft makes clear that the correct semantics | 869 | * ipngwg API draft makes clear that the correct semantics |
877 | * for TCP and UDP is to consider one TCP and UDP instance | 870 | * for TCP and UDP is to consider one TCP and UDP instance |
@@ -1028,52 +1021,4 @@ out_unregister_tcp_proto: | |||
1028 | } | 1021 | } |
1029 | module_init(inet6_init); | 1022 | module_init(inet6_init); |
1030 | 1023 | ||
1031 | static void __exit inet6_exit(void) | ||
1032 | { | ||
1033 | if (disable_ipv6_mod) | ||
1034 | return; | ||
1035 | |||
1036 | /* First of all disallow new sockets creation. */ | ||
1037 | sock_unregister(PF_INET6); | ||
1038 | /* Disallow any further netlink messages */ | ||
1039 | rtnl_unregister_all(PF_INET6); | ||
1040 | |||
1041 | udpv6_exit(); | ||
1042 | udplitev6_exit(); | ||
1043 | tcpv6_exit(); | ||
1044 | |||
1045 | /* Cleanup code parts. */ | ||
1046 | ipv6_packet_cleanup(); | ||
1047 | ipv6_frag_exit(); | ||
1048 | ipv6_exthdrs_exit(); | ||
1049 | addrconf_cleanup(); | ||
1050 | ip6_flowlabel_cleanup(); | ||
1051 | ndisc_late_cleanup(); | ||
1052 | ip6_route_cleanup(); | ||
1053 | #ifdef CONFIG_PROC_FS | ||
1054 | |||
1055 | /* Cleanup code parts. */ | ||
1056 | if6_proc_exit(); | ||
1057 | ipv6_misc_proc_exit(); | ||
1058 | udplite6_proc_exit(); | ||
1059 | raw6_proc_exit(); | ||
1060 | #endif | ||
1061 | ipv6_netfilter_fini(); | ||
1062 | ipv6_stub = NULL; | ||
1063 | igmp6_cleanup(); | ||
1064 | ndisc_cleanup(); | ||
1065 | ip6_mr_cleanup(); | ||
1066 | icmpv6_cleanup(); | ||
1067 | rawv6_exit(); | ||
1068 | |||
1069 | unregister_pernet_subsys(&inet6_net_ops); | ||
1070 | proto_unregister(&rawv6_prot); | ||
1071 | proto_unregister(&udplitev6_prot); | ||
1072 | proto_unregister(&udpv6_prot); | ||
1073 | proto_unregister(&tcpv6_prot); | ||
1074 | |||
1075 | rcu_barrier(); /* Wait for completion of call_rcu()'s */ | ||
1076 | } | ||
1077 | module_exit(inet6_exit); | ||
1078 | |||
1079 | MODULE_ALIAS_NETPROTO(PF_INET6); | 1024 | MODULE_ALIAS_NETPROTO(PF_INET6); |
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 48b6bd2a9a14..a454b0ff57c7 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c | |||
@@ -107,16 +107,16 @@ ipv4_connected: | |||
107 | if (err) | 107 | if (err) |
108 | goto out; | 108 | goto out; |
109 | 109 | ||
110 | ipv6_addr_set_v4mapped(inet->inet_daddr, &np->daddr); | 110 | ipv6_addr_set_v4mapped(inet->inet_daddr, &sk->sk_v6_daddr); |
111 | 111 | ||
112 | if (ipv6_addr_any(&np->saddr) || | 112 | if (ipv6_addr_any(&np->saddr) || |
113 | ipv6_mapped_addr_any(&np->saddr)) | 113 | ipv6_mapped_addr_any(&np->saddr)) |
114 | ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr); | 114 | ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr); |
115 | 115 | ||
116 | if (ipv6_addr_any(&np->rcv_saddr) || | 116 | if (ipv6_addr_any(&sk->sk_v6_rcv_saddr) || |
117 | ipv6_mapped_addr_any(&np->rcv_saddr)) { | 117 | ipv6_mapped_addr_any(&sk->sk_v6_rcv_saddr)) { |
118 | ipv6_addr_set_v4mapped(inet->inet_rcv_saddr, | 118 | ipv6_addr_set_v4mapped(inet->inet_rcv_saddr, |
119 | &np->rcv_saddr); | 119 | &sk->sk_v6_rcv_saddr); |
120 | if (sk->sk_prot->rehash) | 120 | if (sk->sk_prot->rehash) |
121 | sk->sk_prot->rehash(sk); | 121 | sk->sk_prot->rehash(sk); |
122 | } | 122 | } |
@@ -145,7 +145,7 @@ ipv4_connected: | |||
145 | } | 145 | } |
146 | } | 146 | } |
147 | 147 | ||
148 | np->daddr = *daddr; | 148 | sk->sk_v6_daddr = *daddr; |
149 | np->flow_label = fl6.flowlabel; | 149 | np->flow_label = fl6.flowlabel; |
150 | 150 | ||
151 | inet->inet_dport = usin->sin6_port; | 151 | inet->inet_dport = usin->sin6_port; |
@@ -156,7 +156,7 @@ ipv4_connected: | |||
156 | */ | 156 | */ |
157 | 157 | ||
158 | fl6.flowi6_proto = sk->sk_protocol; | 158 | fl6.flowi6_proto = sk->sk_protocol; |
159 | fl6.daddr = np->daddr; | 159 | fl6.daddr = sk->sk_v6_daddr; |
160 | fl6.saddr = np->saddr; | 160 | fl6.saddr = np->saddr; |
161 | fl6.flowi6_oif = sk->sk_bound_dev_if; | 161 | fl6.flowi6_oif = sk->sk_bound_dev_if; |
162 | fl6.flowi6_mark = sk->sk_mark; | 162 | fl6.flowi6_mark = sk->sk_mark; |
@@ -183,16 +183,16 @@ ipv4_connected: | |||
183 | if (ipv6_addr_any(&np->saddr)) | 183 | if (ipv6_addr_any(&np->saddr)) |
184 | np->saddr = fl6.saddr; | 184 | np->saddr = fl6.saddr; |
185 | 185 | ||
186 | if (ipv6_addr_any(&np->rcv_saddr)) { | 186 | if (ipv6_addr_any(&sk->sk_v6_rcv_saddr)) { |
187 | np->rcv_saddr = fl6.saddr; | 187 | sk->sk_v6_rcv_saddr = fl6.saddr; |
188 | inet->inet_rcv_saddr = LOOPBACK4_IPV6; | 188 | inet->inet_rcv_saddr = LOOPBACK4_IPV6; |
189 | if (sk->sk_prot->rehash) | 189 | if (sk->sk_prot->rehash) |
190 | sk->sk_prot->rehash(sk); | 190 | sk->sk_prot->rehash(sk); |
191 | } | 191 | } |
192 | 192 | ||
193 | ip6_dst_store(sk, dst, | 193 | ip6_dst_store(sk, dst, |
194 | ipv6_addr_equal(&fl6.daddr, &np->daddr) ? | 194 | ipv6_addr_equal(&fl6.daddr, &sk->sk_v6_daddr) ? |
195 | &np->daddr : NULL, | 195 | &sk->sk_v6_daddr : NULL, |
196 | #ifdef CONFIG_IPV6_SUBTREES | 196 | #ifdef CONFIG_IPV6_SUBTREES |
197 | ipv6_addr_equal(&fl6.saddr, &np->saddr) ? | 197 | ipv6_addr_equal(&fl6.saddr, &np->saddr) ? |
198 | &np->saddr : | 198 | &np->saddr : |
@@ -883,11 +883,10 @@ EXPORT_SYMBOL_GPL(ip6_datagram_send_ctl); | |||
883 | void ip6_dgram_sock_seq_show(struct seq_file *seq, struct sock *sp, | 883 | void ip6_dgram_sock_seq_show(struct seq_file *seq, struct sock *sp, |
884 | __u16 srcp, __u16 destp, int bucket) | 884 | __u16 srcp, __u16 destp, int bucket) |
885 | { | 885 | { |
886 | struct ipv6_pinfo *np = inet6_sk(sp); | ||
887 | const struct in6_addr *dest, *src; | 886 | const struct in6_addr *dest, *src; |
888 | 887 | ||
889 | dest = &np->daddr; | 888 | dest = &sp->sk_v6_daddr; |
890 | src = &np->rcv_saddr; | 889 | src = &sp->sk_v6_rcv_saddr; |
891 | seq_printf(seq, | 890 | seq_printf(seq, |
892 | "%5d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " | 891 | "%5d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " |
893 | "%02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d\n", | 892 | "%02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d\n", |
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index e67e63f9858d..b8719df0366e 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c | |||
@@ -164,10 +164,9 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
164 | u8 *iv; | 164 | u8 *iv; |
165 | u8 *tail; | 165 | u8 *tail; |
166 | __be32 *seqhi; | 166 | __be32 *seqhi; |
167 | struct esp_data *esp = x->data; | ||
168 | 167 | ||
169 | /* skb is pure payload to encrypt */ | 168 | /* skb is pure payload to encrypt */ |
170 | aead = esp->aead; | 169 | aead = x->data; |
171 | alen = crypto_aead_authsize(aead); | 170 | alen = crypto_aead_authsize(aead); |
172 | 171 | ||
173 | tfclen = 0; | 172 | tfclen = 0; |
@@ -181,8 +180,6 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
181 | } | 180 | } |
182 | blksize = ALIGN(crypto_aead_blocksize(aead), 4); | 181 | blksize = ALIGN(crypto_aead_blocksize(aead), 4); |
183 | clen = ALIGN(skb->len + 2 + tfclen, blksize); | 182 | clen = ALIGN(skb->len + 2 + tfclen, blksize); |
184 | if (esp->padlen) | ||
185 | clen = ALIGN(clen, esp->padlen); | ||
186 | plen = clen - skb->len - tfclen; | 183 | plen = clen - skb->len - tfclen; |
187 | 184 | ||
188 | err = skb_cow_data(skb, tfclen + plen + alen, &trailer); | 185 | err = skb_cow_data(skb, tfclen + plen + alen, &trailer); |
@@ -271,8 +268,7 @@ error: | |||
271 | static int esp_input_done2(struct sk_buff *skb, int err) | 268 | static int esp_input_done2(struct sk_buff *skb, int err) |
272 | { | 269 | { |
273 | struct xfrm_state *x = xfrm_input_state(skb); | 270 | struct xfrm_state *x = xfrm_input_state(skb); |
274 | struct esp_data *esp = x->data; | 271 | struct crypto_aead *aead = x->data; |
275 | struct crypto_aead *aead = esp->aead; | ||
276 | int alen = crypto_aead_authsize(aead); | 272 | int alen = crypto_aead_authsize(aead); |
277 | int hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead); | 273 | int hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead); |
278 | int elen = skb->len - hlen; | 274 | int elen = skb->len - hlen; |
@@ -325,8 +321,7 @@ static void esp_input_done(struct crypto_async_request *base, int err) | |||
325 | static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) | 321 | static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) |
326 | { | 322 | { |
327 | struct ip_esp_hdr *esph; | 323 | struct ip_esp_hdr *esph; |
328 | struct esp_data *esp = x->data; | 324 | struct crypto_aead *aead = x->data; |
329 | struct crypto_aead *aead = esp->aead; | ||
330 | struct aead_request *req; | 325 | struct aead_request *req; |
331 | struct sk_buff *trailer; | 326 | struct sk_buff *trailer; |
332 | int elen = skb->len - sizeof(*esph) - crypto_aead_ivsize(aead); | 327 | int elen = skb->len - sizeof(*esph) - crypto_aead_ivsize(aead); |
@@ -414,9 +409,8 @@ out: | |||
414 | 409 | ||
415 | static u32 esp6_get_mtu(struct xfrm_state *x, int mtu) | 410 | static u32 esp6_get_mtu(struct xfrm_state *x, int mtu) |
416 | { | 411 | { |
417 | struct esp_data *esp = x->data; | 412 | struct crypto_aead *aead = x->data; |
418 | u32 blksize = ALIGN(crypto_aead_blocksize(esp->aead), 4); | 413 | u32 blksize = ALIGN(crypto_aead_blocksize(aead), 4); |
419 | u32 align = max_t(u32, blksize, esp->padlen); | ||
420 | unsigned int net_adj; | 414 | unsigned int net_adj; |
421 | 415 | ||
422 | if (x->props.mode != XFRM_MODE_TUNNEL) | 416 | if (x->props.mode != XFRM_MODE_TUNNEL) |
@@ -424,8 +418,8 @@ static u32 esp6_get_mtu(struct xfrm_state *x, int mtu) | |||
424 | else | 418 | else |
425 | net_adj = 0; | 419 | net_adj = 0; |
426 | 420 | ||
427 | return ((mtu - x->props.header_len - crypto_aead_authsize(esp->aead) - | 421 | return ((mtu - x->props.header_len - crypto_aead_authsize(aead) - |
428 | net_adj) & ~(align - 1)) + net_adj - 2; | 422 | net_adj) & ~(blksize - 1)) + net_adj - 2; |
429 | } | 423 | } |
430 | 424 | ||
431 | static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | 425 | static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, |
@@ -454,18 +448,16 @@ static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
454 | 448 | ||
455 | static void esp6_destroy(struct xfrm_state *x) | 449 | static void esp6_destroy(struct xfrm_state *x) |
456 | { | 450 | { |
457 | struct esp_data *esp = x->data; | 451 | struct crypto_aead *aead = x->data; |
458 | 452 | ||
459 | if (!esp) | 453 | if (!aead) |
460 | return; | 454 | return; |
461 | 455 | ||
462 | crypto_free_aead(esp->aead); | 456 | crypto_free_aead(aead); |
463 | kfree(esp); | ||
464 | } | 457 | } |
465 | 458 | ||
466 | static int esp_init_aead(struct xfrm_state *x) | 459 | static int esp_init_aead(struct xfrm_state *x) |
467 | { | 460 | { |
468 | struct esp_data *esp = x->data; | ||
469 | struct crypto_aead *aead; | 461 | struct crypto_aead *aead; |
470 | int err; | 462 | int err; |
471 | 463 | ||
@@ -474,7 +466,7 @@ static int esp_init_aead(struct xfrm_state *x) | |||
474 | if (IS_ERR(aead)) | 466 | if (IS_ERR(aead)) |
475 | goto error; | 467 | goto error; |
476 | 468 | ||
477 | esp->aead = aead; | 469 | x->data = aead; |
478 | 470 | ||
479 | err = crypto_aead_setkey(aead, x->aead->alg_key, | 471 | err = crypto_aead_setkey(aead, x->aead->alg_key, |
480 | (x->aead->alg_key_len + 7) / 8); | 472 | (x->aead->alg_key_len + 7) / 8); |
@@ -491,7 +483,6 @@ error: | |||
491 | 483 | ||
492 | static int esp_init_authenc(struct xfrm_state *x) | 484 | static int esp_init_authenc(struct xfrm_state *x) |
493 | { | 485 | { |
494 | struct esp_data *esp = x->data; | ||
495 | struct crypto_aead *aead; | 486 | struct crypto_aead *aead; |
496 | struct crypto_authenc_key_param *param; | 487 | struct crypto_authenc_key_param *param; |
497 | struct rtattr *rta; | 488 | struct rtattr *rta; |
@@ -526,7 +517,7 @@ static int esp_init_authenc(struct xfrm_state *x) | |||
526 | if (IS_ERR(aead)) | 517 | if (IS_ERR(aead)) |
527 | goto error; | 518 | goto error; |
528 | 519 | ||
529 | esp->aead = aead; | 520 | x->data = aead; |
530 | 521 | ||
531 | keylen = (x->aalg ? (x->aalg->alg_key_len + 7) / 8 : 0) + | 522 | keylen = (x->aalg ? (x->aalg->alg_key_len + 7) / 8 : 0) + |
532 | (x->ealg->alg_key_len + 7) / 8 + RTA_SPACE(sizeof(*param)); | 523 | (x->ealg->alg_key_len + 7) / 8 + RTA_SPACE(sizeof(*param)); |
@@ -581,7 +572,6 @@ error: | |||
581 | 572 | ||
582 | static int esp6_init_state(struct xfrm_state *x) | 573 | static int esp6_init_state(struct xfrm_state *x) |
583 | { | 574 | { |
584 | struct esp_data *esp; | ||
585 | struct crypto_aead *aead; | 575 | struct crypto_aead *aead; |
586 | u32 align; | 576 | u32 align; |
587 | int err; | 577 | int err; |
@@ -589,11 +579,7 @@ static int esp6_init_state(struct xfrm_state *x) | |||
589 | if (x->encap) | 579 | if (x->encap) |
590 | return -EINVAL; | 580 | return -EINVAL; |
591 | 581 | ||
592 | esp = kzalloc(sizeof(*esp), GFP_KERNEL); | 582 | x->data = NULL; |
593 | if (esp == NULL) | ||
594 | return -ENOMEM; | ||
595 | |||
596 | x->data = esp; | ||
597 | 583 | ||
598 | if (x->aead) | 584 | if (x->aead) |
599 | err = esp_init_aead(x); | 585 | err = esp_init_aead(x); |
@@ -603,9 +589,7 @@ static int esp6_init_state(struct xfrm_state *x) | |||
603 | if (err) | 589 | if (err) |
604 | goto error; | 590 | goto error; |
605 | 591 | ||
606 | aead = esp->aead; | 592 | aead = x->data; |
607 | |||
608 | esp->padlen = 0; | ||
609 | 593 | ||
610 | x->props.header_len = sizeof(struct ip_esp_hdr) + | 594 | x->props.header_len = sizeof(struct ip_esp_hdr) + |
611 | crypto_aead_ivsize(aead); | 595 | crypto_aead_ivsize(aead); |
@@ -625,9 +609,7 @@ static int esp6_init_state(struct xfrm_state *x) | |||
625 | } | 609 | } |
626 | 610 | ||
627 | align = ALIGN(crypto_aead_blocksize(aead), 4); | 611 | align = ALIGN(crypto_aead_blocksize(aead), 4); |
628 | if (esp->padlen) | 612 | x->props.trailer_len = align + 1 + crypto_aead_authsize(aead); |
629 | align = max_t(u32, align, esp->padlen); | ||
630 | x->props.trailer_len = align + 1 + crypto_aead_authsize(esp->aead); | ||
631 | 613 | ||
632 | error: | 614 | error: |
633 | return err; | 615 | return err; |
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index e4311cbc8b4e..77bb8afb141d 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c | |||
@@ -70,20 +70,20 @@ struct dst_entry *inet6_csk_route_req(struct sock *sk, | |||
70 | struct flowi6 *fl6, | 70 | struct flowi6 *fl6, |
71 | const struct request_sock *req) | 71 | const struct request_sock *req) |
72 | { | 72 | { |
73 | struct inet6_request_sock *treq = inet6_rsk(req); | 73 | struct inet_request_sock *ireq = inet_rsk(req); |
74 | struct ipv6_pinfo *np = inet6_sk(sk); | 74 | struct ipv6_pinfo *np = inet6_sk(sk); |
75 | struct in6_addr *final_p, final; | 75 | struct in6_addr *final_p, final; |
76 | struct dst_entry *dst; | 76 | struct dst_entry *dst; |
77 | 77 | ||
78 | memset(fl6, 0, sizeof(*fl6)); | 78 | memset(fl6, 0, sizeof(*fl6)); |
79 | fl6->flowi6_proto = IPPROTO_TCP; | 79 | fl6->flowi6_proto = IPPROTO_TCP; |
80 | fl6->daddr = treq->rmt_addr; | 80 | fl6->daddr = ireq->ir_v6_rmt_addr; |
81 | final_p = fl6_update_dst(fl6, np->opt, &final); | 81 | final_p = fl6_update_dst(fl6, np->opt, &final); |
82 | fl6->saddr = treq->loc_addr; | 82 | fl6->saddr = ireq->ir_v6_loc_addr; |
83 | fl6->flowi6_oif = treq->iif; | 83 | fl6->flowi6_oif = ireq->ir_iif; |
84 | fl6->flowi6_mark = sk->sk_mark; | 84 | fl6->flowi6_mark = sk->sk_mark; |
85 | fl6->fl6_dport = inet_rsk(req)->rmt_port; | 85 | fl6->fl6_dport = ireq->ir_rmt_port; |
86 | fl6->fl6_sport = inet_rsk(req)->loc_port; | 86 | fl6->fl6_sport = htons(ireq->ir_num); |
87 | security_req_classify_flow(req, flowi6_to_flowi(fl6)); | 87 | security_req_classify_flow(req, flowi6_to_flowi(fl6)); |
88 | 88 | ||
89 | dst = ip6_dst_lookup_flow(sk, fl6, final_p, false); | 89 | dst = ip6_dst_lookup_flow(sk, fl6, final_p, false); |
@@ -129,13 +129,13 @@ struct request_sock *inet6_csk_search_req(const struct sock *sk, | |||
129 | lopt->nr_table_entries)]; | 129 | lopt->nr_table_entries)]; |
130 | (req = *prev) != NULL; | 130 | (req = *prev) != NULL; |
131 | prev = &req->dl_next) { | 131 | prev = &req->dl_next) { |
132 | const struct inet6_request_sock *treq = inet6_rsk(req); | 132 | const struct inet_request_sock *ireq = inet_rsk(req); |
133 | 133 | ||
134 | if (inet_rsk(req)->rmt_port == rport && | 134 | if (ireq->ir_rmt_port == rport && |
135 | req->rsk_ops->family == AF_INET6 && | 135 | req->rsk_ops->family == AF_INET6 && |
136 | ipv6_addr_equal(&treq->rmt_addr, raddr) && | 136 | ipv6_addr_equal(&ireq->ir_v6_rmt_addr, raddr) && |
137 | ipv6_addr_equal(&treq->loc_addr, laddr) && | 137 | ipv6_addr_equal(&ireq->ir_v6_loc_addr, laddr) && |
138 | (!treq->iif || treq->iif == iif)) { | 138 | (!ireq->ir_iif || ireq->ir_iif == iif)) { |
139 | WARN_ON(req->sk != NULL); | 139 | WARN_ON(req->sk != NULL); |
140 | *prevp = prev; | 140 | *prevp = prev; |
141 | return req; | 141 | return req; |
@@ -153,8 +153,8 @@ void inet6_csk_reqsk_queue_hash_add(struct sock *sk, | |||
153 | { | 153 | { |
154 | struct inet_connection_sock *icsk = inet_csk(sk); | 154 | struct inet_connection_sock *icsk = inet_csk(sk); |
155 | struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt; | 155 | struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt; |
156 | const u32 h = inet6_synq_hash(&inet6_rsk(req)->rmt_addr, | 156 | const u32 h = inet6_synq_hash(&inet_rsk(req)->ir_v6_rmt_addr, |
157 | inet_rsk(req)->rmt_port, | 157 | inet_rsk(req)->ir_rmt_port, |
158 | lopt->hash_rnd, lopt->nr_table_entries); | 158 | lopt->hash_rnd, lopt->nr_table_entries); |
159 | 159 | ||
160 | reqsk_queue_hash_req(&icsk->icsk_accept_queue, h, req, timeout); | 160 | reqsk_queue_hash_req(&icsk->icsk_accept_queue, h, req, timeout); |
@@ -165,11 +165,10 @@ EXPORT_SYMBOL_GPL(inet6_csk_reqsk_queue_hash_add); | |||
165 | 165 | ||
166 | void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr) | 166 | void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr) |
167 | { | 167 | { |
168 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
169 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) uaddr; | 168 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) uaddr; |
170 | 169 | ||
171 | sin6->sin6_family = AF_INET6; | 170 | sin6->sin6_family = AF_INET6; |
172 | sin6->sin6_addr = np->daddr; | 171 | sin6->sin6_addr = sk->sk_v6_daddr; |
173 | sin6->sin6_port = inet_sk(sk)->inet_dport; | 172 | sin6->sin6_port = inet_sk(sk)->inet_dport; |
174 | /* We do not store received flowlabel for TCP */ | 173 | /* We do not store received flowlabel for TCP */ |
175 | sin6->sin6_flowinfo = 0; | 174 | sin6->sin6_flowinfo = 0; |
@@ -203,7 +202,7 @@ static struct dst_entry *inet6_csk_route_socket(struct sock *sk, | |||
203 | 202 | ||
204 | memset(fl6, 0, sizeof(*fl6)); | 203 | memset(fl6, 0, sizeof(*fl6)); |
205 | fl6->flowi6_proto = sk->sk_protocol; | 204 | fl6->flowi6_proto = sk->sk_protocol; |
206 | fl6->daddr = np->daddr; | 205 | fl6->daddr = sk->sk_v6_daddr; |
207 | fl6->saddr = np->saddr; | 206 | fl6->saddr = np->saddr; |
208 | fl6->flowlabel = np->flow_label; | 207 | fl6->flowlabel = np->flow_label; |
209 | IP6_ECN_flow_xmit(sk, fl6->flowlabel); | 208 | IP6_ECN_flow_xmit(sk, fl6->flowlabel); |
@@ -245,7 +244,7 @@ int inet6_csk_xmit(struct sk_buff *skb, struct flowi *fl_unused) | |||
245 | skb_dst_set_noref(skb, dst); | 244 | skb_dst_set_noref(skb, dst); |
246 | 245 | ||
247 | /* Restore final destination back after routing done */ | 246 | /* Restore final destination back after routing done */ |
248 | fl6.daddr = np->daddr; | 247 | fl6.daddr = sk->sk_v6_daddr; |
249 | 248 | ||
250 | res = ip6_xmit(sk, skb, &fl6, np->opt, np->tclass); | 249 | res = ip6_xmit(sk, skb, &fl6, np->opt, np->tclass); |
251 | rcu_read_unlock(); | 250 | rcu_read_unlock(); |
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index 066640e0ba8e..262e13c02ec2 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c | |||
@@ -23,6 +23,39 @@ | |||
23 | #include <net/secure_seq.h> | 23 | #include <net/secure_seq.h> |
24 | #include <net/ip.h> | 24 | #include <net/ip.h> |
25 | 25 | ||
26 | static unsigned int inet6_ehashfn(struct net *net, | ||
27 | const struct in6_addr *laddr, | ||
28 | const u16 lport, | ||
29 | const struct in6_addr *faddr, | ||
30 | const __be16 fport) | ||
31 | { | ||
32 | static u32 inet6_ehash_secret __read_mostly; | ||
33 | static u32 ipv6_hash_secret __read_mostly; | ||
34 | |||
35 | u32 lhash, fhash; | ||
36 | |||
37 | net_get_random_once(&inet6_ehash_secret, sizeof(inet6_ehash_secret)); | ||
38 | net_get_random_once(&ipv6_hash_secret, sizeof(ipv6_hash_secret)); | ||
39 | |||
40 | lhash = (__force u32)laddr->s6_addr32[3]; | ||
41 | fhash = __ipv6_addr_jhash(faddr, ipv6_hash_secret); | ||
42 | |||
43 | return __inet6_ehashfn(lhash, lport, fhash, fport, | ||
44 | inet6_ehash_secret + net_hash_mix(net)); | ||
45 | } | ||
46 | |||
47 | static int inet6_sk_ehashfn(const struct sock *sk) | ||
48 | { | ||
49 | const struct inet_sock *inet = inet_sk(sk); | ||
50 | const struct in6_addr *laddr = &sk->sk_v6_rcv_saddr; | ||
51 | const struct in6_addr *faddr = &sk->sk_v6_daddr; | ||
52 | const __u16 lport = inet->inet_num; | ||
53 | const __be16 fport = inet->inet_dport; | ||
54 | struct net *net = sock_net(sk); | ||
55 | |||
56 | return inet6_ehashfn(net, laddr, lport, faddr, fport); | ||
57 | } | ||
58 | |||
26 | int __inet6_hash(struct sock *sk, struct inet_timewait_sock *tw) | 59 | int __inet6_hash(struct sock *sk, struct inet_timewait_sock *tw) |
27 | { | 60 | { |
28 | struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; | 61 | struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; |
@@ -89,43 +122,22 @@ begin: | |||
89 | sk_nulls_for_each_rcu(sk, node, &head->chain) { | 122 | sk_nulls_for_each_rcu(sk, node, &head->chain) { |
90 | if (sk->sk_hash != hash) | 123 | if (sk->sk_hash != hash) |
91 | continue; | 124 | continue; |
92 | if (likely(INET6_MATCH(sk, net, saddr, daddr, ports, dif))) { | 125 | if (!INET6_MATCH(sk, net, saddr, daddr, ports, dif)) |
93 | if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) | ||
94 | goto begintw; | ||
95 | if (unlikely(!INET6_MATCH(sk, net, saddr, daddr, | ||
96 | ports, dif))) { | ||
97 | sock_put(sk); | ||
98 | goto begin; | ||
99 | } | ||
100 | goto out; | ||
101 | } | ||
102 | } | ||
103 | if (get_nulls_value(node) != slot) | ||
104 | goto begin; | ||
105 | |||
106 | begintw: | ||
107 | /* Must check for a TIME_WAIT'er before going to listener hash. */ | ||
108 | sk_nulls_for_each_rcu(sk, node, &head->twchain) { | ||
109 | if (sk->sk_hash != hash) | ||
110 | continue; | 126 | continue; |
111 | if (likely(INET6_TW_MATCH(sk, net, saddr, daddr, | 127 | if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) |
112 | ports, dif))) { | ||
113 | if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) { | ||
114 | sk = NULL; | ||
115 | goto out; | ||
116 | } | ||
117 | if (unlikely(!INET6_TW_MATCH(sk, net, saddr, daddr, | ||
118 | ports, dif))) { | ||
119 | inet_twsk_put(inet_twsk(sk)); | ||
120 | goto begintw; | ||
121 | } | ||
122 | goto out; | 128 | goto out; |
129 | |||
130 | if (unlikely(!INET6_MATCH(sk, net, saddr, daddr, ports, dif))) { | ||
131 | sock_gen_put(sk); | ||
132 | goto begin; | ||
123 | } | 133 | } |
134 | goto found; | ||
124 | } | 135 | } |
125 | if (get_nulls_value(node) != slot) | 136 | if (get_nulls_value(node) != slot) |
126 | goto begintw; | 137 | goto begin; |
127 | sk = NULL; | ||
128 | out: | 138 | out: |
139 | sk = NULL; | ||
140 | found: | ||
129 | rcu_read_unlock(); | 141 | rcu_read_unlock(); |
130 | return sk; | 142 | return sk; |
131 | } | 143 | } |
@@ -140,11 +152,10 @@ static inline int compute_score(struct sock *sk, struct net *net, | |||
140 | 152 | ||
141 | if (net_eq(sock_net(sk), net) && inet_sk(sk)->inet_num == hnum && | 153 | if (net_eq(sock_net(sk), net) && inet_sk(sk)->inet_num == hnum && |
142 | sk->sk_family == PF_INET6) { | 154 | sk->sk_family == PF_INET6) { |
143 | const struct ipv6_pinfo *np = inet6_sk(sk); | ||
144 | 155 | ||
145 | score = 1; | 156 | score = 1; |
146 | if (!ipv6_addr_any(&np->rcv_saddr)) { | 157 | if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr)) { |
147 | if (!ipv6_addr_equal(&np->rcv_saddr, daddr)) | 158 | if (!ipv6_addr_equal(&sk->sk_v6_rcv_saddr, daddr)) |
148 | return -1; | 159 | return -1; |
149 | score++; | 160 | score++; |
150 | } | 161 | } |
@@ -236,9 +247,8 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, | |||
236 | { | 247 | { |
237 | struct inet_hashinfo *hinfo = death_row->hashinfo; | 248 | struct inet_hashinfo *hinfo = death_row->hashinfo; |
238 | struct inet_sock *inet = inet_sk(sk); | 249 | struct inet_sock *inet = inet_sk(sk); |
239 | const struct ipv6_pinfo *np = inet6_sk(sk); | 250 | const struct in6_addr *daddr = &sk->sk_v6_rcv_saddr; |
240 | const struct in6_addr *daddr = &np->rcv_saddr; | 251 | const struct in6_addr *saddr = &sk->sk_v6_daddr; |
241 | const struct in6_addr *saddr = &np->daddr; | ||
242 | const int dif = sk->sk_bound_dev_if; | 252 | const int dif = sk->sk_bound_dev_if; |
243 | const __portpair ports = INET_COMBINED_PORTS(inet->inet_dport, lport); | 253 | const __portpair ports = INET_COMBINED_PORTS(inet->inet_dport, lport); |
244 | struct net *net = sock_net(sk); | 254 | struct net *net = sock_net(sk); |
@@ -248,38 +258,28 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, | |||
248 | spinlock_t *lock = inet_ehash_lockp(hinfo, hash); | 258 | spinlock_t *lock = inet_ehash_lockp(hinfo, hash); |
249 | struct sock *sk2; | 259 | struct sock *sk2; |
250 | const struct hlist_nulls_node *node; | 260 | const struct hlist_nulls_node *node; |
251 | struct inet_timewait_sock *tw; | 261 | struct inet_timewait_sock *tw = NULL; |
252 | int twrefcnt = 0; | 262 | int twrefcnt = 0; |
253 | 263 | ||
254 | spin_lock(lock); | 264 | spin_lock(lock); |
255 | 265 | ||
256 | /* Check TIME-WAIT sockets first. */ | ||
257 | sk_nulls_for_each(sk2, node, &head->twchain) { | ||
258 | if (sk2->sk_hash != hash) | ||
259 | continue; | ||
260 | |||
261 | if (likely(INET6_TW_MATCH(sk2, net, saddr, daddr, | ||
262 | ports, dif))) { | ||
263 | tw = inet_twsk(sk2); | ||
264 | if (twsk_unique(sk, sk2, twp)) | ||
265 | goto unique; | ||
266 | else | ||
267 | goto not_unique; | ||
268 | } | ||
269 | } | ||
270 | tw = NULL; | ||
271 | |||
272 | /* And established part... */ | ||
273 | sk_nulls_for_each(sk2, node, &head->chain) { | 266 | sk_nulls_for_each(sk2, node, &head->chain) { |
274 | if (sk2->sk_hash != hash) | 267 | if (sk2->sk_hash != hash) |
275 | continue; | 268 | continue; |
276 | if (likely(INET6_MATCH(sk2, net, saddr, daddr, ports, dif))) | 269 | |
270 | if (likely(INET6_MATCH(sk2, net, saddr, daddr, ports, dif))) { | ||
271 | if (sk2->sk_state == TCP_TIME_WAIT) { | ||
272 | tw = inet_twsk(sk2); | ||
273 | if (twsk_unique(sk, sk2, twp)) | ||
274 | break; | ||
275 | } | ||
277 | goto not_unique; | 276 | goto not_unique; |
277 | } | ||
278 | } | 278 | } |
279 | 279 | ||
280 | unique: | ||
281 | /* Must record num and sport now. Otherwise we will see | 280 | /* Must record num and sport now. Otherwise we will see |
282 | * in hash table socket with a funny identity. */ | 281 | * in hash table socket with a funny identity. |
282 | */ | ||
283 | inet->inet_num = lport; | 283 | inet->inet_num = lport; |
284 | inet->inet_sport = htons(lport); | 284 | inet->inet_sport = htons(lport); |
285 | sk->sk_hash = hash; | 285 | sk->sk_hash = hash; |
@@ -312,9 +312,9 @@ not_unique: | |||
312 | static inline u32 inet6_sk_port_offset(const struct sock *sk) | 312 | static inline u32 inet6_sk_port_offset(const struct sock *sk) |
313 | { | 313 | { |
314 | const struct inet_sock *inet = inet_sk(sk); | 314 | const struct inet_sock *inet = inet_sk(sk); |
315 | const struct ipv6_pinfo *np = inet6_sk(sk); | 315 | |
316 | return secure_ipv6_port_ephemeral(np->rcv_saddr.s6_addr32, | 316 | return secure_ipv6_port_ephemeral(sk->sk_v6_rcv_saddr.s6_addr32, |
317 | np->daddr.s6_addr32, | 317 | sk->sk_v6_daddr.s6_addr32, |
318 | inet->inet_dport); | 318 | inet->inet_dport); |
319 | } | 319 | } |
320 | 320 | ||
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 5bec666aba61..5550a8113a6d 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c | |||
@@ -1529,25 +1529,6 @@ static void fib6_clean_tree(struct net *net, struct fib6_node *root, | |||
1529 | fib6_walk(&c.w); | 1529 | fib6_walk(&c.w); |
1530 | } | 1530 | } |
1531 | 1531 | ||
1532 | void fib6_clean_all_ro(struct net *net, int (*func)(struct rt6_info *, void *arg), | ||
1533 | int prune, void *arg) | ||
1534 | { | ||
1535 | struct fib6_table *table; | ||
1536 | struct hlist_head *head; | ||
1537 | unsigned int h; | ||
1538 | |||
1539 | rcu_read_lock(); | ||
1540 | for (h = 0; h < FIB6_TABLE_HASHSZ; h++) { | ||
1541 | head = &net->ipv6.fib_table_hash[h]; | ||
1542 | hlist_for_each_entry_rcu(table, head, tb6_hlist) { | ||
1543 | read_lock_bh(&table->tb6_lock); | ||
1544 | fib6_clean_tree(net, &table->tb6_root, | ||
1545 | func, prune, arg); | ||
1546 | read_unlock_bh(&table->tb6_lock); | ||
1547 | } | ||
1548 | } | ||
1549 | rcu_read_unlock(); | ||
1550 | } | ||
1551 | void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *arg), | 1532 | void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *arg), |
1552 | int prune, void *arg) | 1533 | int prune, void *arg) |
1553 | { | 1534 | { |
@@ -1782,3 +1763,189 @@ void fib6_gc_cleanup(void) | |||
1782 | unregister_pernet_subsys(&fib6_net_ops); | 1763 | unregister_pernet_subsys(&fib6_net_ops); |
1783 | kmem_cache_destroy(fib6_node_kmem); | 1764 | kmem_cache_destroy(fib6_node_kmem); |
1784 | } | 1765 | } |
1766 | |||
1767 | #ifdef CONFIG_PROC_FS | ||
1768 | |||
1769 | struct ipv6_route_iter { | ||
1770 | struct seq_net_private p; | ||
1771 | struct fib6_walker_t w; | ||
1772 | loff_t skip; | ||
1773 | struct fib6_table *tbl; | ||
1774 | __u32 sernum; | ||
1775 | }; | ||
1776 | |||
1777 | static int ipv6_route_seq_show(struct seq_file *seq, void *v) | ||
1778 | { | ||
1779 | struct rt6_info *rt = v; | ||
1780 | struct ipv6_route_iter *iter = seq->private; | ||
1781 | |||
1782 | seq_printf(seq, "%pi6 %02x ", &rt->rt6i_dst.addr, rt->rt6i_dst.plen); | ||
1783 | |||
1784 | #ifdef CONFIG_IPV6_SUBTREES | ||
1785 | seq_printf(seq, "%pi6 %02x ", &rt->rt6i_src.addr, rt->rt6i_src.plen); | ||
1786 | #else | ||
1787 | seq_puts(seq, "00000000000000000000000000000000 00 "); | ||
1788 | #endif | ||
1789 | if (rt->rt6i_flags & RTF_GATEWAY) | ||
1790 | seq_printf(seq, "%pi6", &rt->rt6i_gateway); | ||
1791 | else | ||
1792 | seq_puts(seq, "00000000000000000000000000000000"); | ||
1793 | |||
1794 | seq_printf(seq, " %08x %08x %08x %08x %8s\n", | ||
1795 | rt->rt6i_metric, atomic_read(&rt->dst.__refcnt), | ||
1796 | rt->dst.__use, rt->rt6i_flags, | ||
1797 | rt->dst.dev ? rt->dst.dev->name : ""); | ||
1798 | iter->w.leaf = NULL; | ||
1799 | return 0; | ||
1800 | } | ||
1801 | |||
1802 | static int ipv6_route_yield(struct fib6_walker_t *w) | ||
1803 | { | ||
1804 | struct ipv6_route_iter *iter = w->args; | ||
1805 | |||
1806 | if (!iter->skip) | ||
1807 | return 1; | ||
1808 | |||
1809 | do { | ||
1810 | iter->w.leaf = iter->w.leaf->dst.rt6_next; | ||
1811 | iter->skip--; | ||
1812 | if (!iter->skip && iter->w.leaf) | ||
1813 | return 1; | ||
1814 | } while (iter->w.leaf); | ||
1815 | |||
1816 | return 0; | ||
1817 | } | ||
1818 | |||
1819 | static void ipv6_route_seq_setup_walk(struct ipv6_route_iter *iter) | ||
1820 | { | ||
1821 | memset(&iter->w, 0, sizeof(iter->w)); | ||
1822 | iter->w.func = ipv6_route_yield; | ||
1823 | iter->w.root = &iter->tbl->tb6_root; | ||
1824 | iter->w.state = FWS_INIT; | ||
1825 | iter->w.node = iter->w.root; | ||
1826 | iter->w.args = iter; | ||
1827 | iter->sernum = iter->w.root->fn_sernum; | ||
1828 | INIT_LIST_HEAD(&iter->w.lh); | ||
1829 | fib6_walker_link(&iter->w); | ||
1830 | } | ||
1831 | |||
1832 | static struct fib6_table *ipv6_route_seq_next_table(struct fib6_table *tbl, | ||
1833 | struct net *net) | ||
1834 | { | ||
1835 | unsigned int h; | ||
1836 | struct hlist_node *node; | ||
1837 | |||
1838 | if (tbl) { | ||
1839 | h = (tbl->tb6_id & (FIB6_TABLE_HASHSZ - 1)) + 1; | ||
1840 | node = rcu_dereference_bh(hlist_next_rcu(&tbl->tb6_hlist)); | ||
1841 | } else { | ||
1842 | h = 0; | ||
1843 | node = NULL; | ||
1844 | } | ||
1845 | |||
1846 | while (!node && h < FIB6_TABLE_HASHSZ) { | ||
1847 | node = rcu_dereference_bh( | ||
1848 | hlist_first_rcu(&net->ipv6.fib_table_hash[h++])); | ||
1849 | } | ||
1850 | return hlist_entry_safe(node, struct fib6_table, tb6_hlist); | ||
1851 | } | ||
1852 | |||
1853 | static void ipv6_route_check_sernum(struct ipv6_route_iter *iter) | ||
1854 | { | ||
1855 | if (iter->sernum != iter->w.root->fn_sernum) { | ||
1856 | iter->sernum = iter->w.root->fn_sernum; | ||
1857 | iter->w.state = FWS_INIT; | ||
1858 | iter->w.node = iter->w.root; | ||
1859 | WARN_ON(iter->w.skip); | ||
1860 | iter->w.skip = iter->w.count; | ||
1861 | } | ||
1862 | } | ||
1863 | |||
1864 | static void *ipv6_route_seq_next(struct seq_file *seq, void *v, loff_t *pos) | ||
1865 | { | ||
1866 | int r; | ||
1867 | struct rt6_info *n; | ||
1868 | struct net *net = seq_file_net(seq); | ||
1869 | struct ipv6_route_iter *iter = seq->private; | ||
1870 | |||
1871 | if (!v) | ||
1872 | goto iter_table; | ||
1873 | |||
1874 | n = ((struct rt6_info *)v)->dst.rt6_next; | ||
1875 | if (n) { | ||
1876 | ++*pos; | ||
1877 | return n; | ||
1878 | } | ||
1879 | |||
1880 | iter_table: | ||
1881 | ipv6_route_check_sernum(iter); | ||
1882 | read_lock(&iter->tbl->tb6_lock); | ||
1883 | r = fib6_walk_continue(&iter->w); | ||
1884 | read_unlock(&iter->tbl->tb6_lock); | ||
1885 | if (r > 0) { | ||
1886 | if (v) | ||
1887 | ++*pos; | ||
1888 | return iter->w.leaf; | ||
1889 | } else if (r < 0) { | ||
1890 | fib6_walker_unlink(&iter->w); | ||
1891 | return NULL; | ||
1892 | } | ||
1893 | fib6_walker_unlink(&iter->w); | ||
1894 | |||
1895 | iter->tbl = ipv6_route_seq_next_table(iter->tbl, net); | ||
1896 | if (!iter->tbl) | ||
1897 | return NULL; | ||
1898 | |||
1899 | ipv6_route_seq_setup_walk(iter); | ||
1900 | goto iter_table; | ||
1901 | } | ||
1902 | |||
1903 | static void *ipv6_route_seq_start(struct seq_file *seq, loff_t *pos) | ||
1904 | __acquires(RCU_BH) | ||
1905 | { | ||
1906 | struct net *net = seq_file_net(seq); | ||
1907 | struct ipv6_route_iter *iter = seq->private; | ||
1908 | |||
1909 | rcu_read_lock_bh(); | ||
1910 | iter->tbl = ipv6_route_seq_next_table(NULL, net); | ||
1911 | iter->skip = *pos; | ||
1912 | |||
1913 | if (iter->tbl) { | ||
1914 | ipv6_route_seq_setup_walk(iter); | ||
1915 | return ipv6_route_seq_next(seq, NULL, pos); | ||
1916 | } else { | ||
1917 | return NULL; | ||
1918 | } | ||
1919 | } | ||
1920 | |||
1921 | static bool ipv6_route_iter_active(struct ipv6_route_iter *iter) | ||
1922 | { | ||
1923 | struct fib6_walker_t *w = &iter->w; | ||
1924 | return w->node && !(w->state == FWS_U && w->node == w->root); | ||
1925 | } | ||
1926 | |||
1927 | static void ipv6_route_seq_stop(struct seq_file *seq, void *v) | ||
1928 | __releases(RCU_BH) | ||
1929 | { | ||
1930 | struct ipv6_route_iter *iter = seq->private; | ||
1931 | |||
1932 | if (ipv6_route_iter_active(iter)) | ||
1933 | fib6_walker_unlink(&iter->w); | ||
1934 | |||
1935 | rcu_read_unlock_bh(); | ||
1936 | } | ||
1937 | |||
1938 | static const struct seq_operations ipv6_route_seq_ops = { | ||
1939 | .start = ipv6_route_seq_start, | ||
1940 | .next = ipv6_route_seq_next, | ||
1941 | .stop = ipv6_route_seq_stop, | ||
1942 | .show = ipv6_route_seq_show | ||
1943 | }; | ||
1944 | |||
1945 | int ipv6_route_open(struct inode *inode, struct file *file) | ||
1946 | { | ||
1947 | return seq_open_net(inode, file, &ipv6_route_seq_ops, | ||
1948 | sizeof(struct ipv6_route_iter)); | ||
1949 | } | ||
1950 | |||
1951 | #endif /* CONFIG_PROC_FS */ | ||
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 46e88433ec7d..e7fb7106550f 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c | |||
@@ -41,7 +41,7 @@ | |||
41 | #define FL_MIN_LINGER 6 /* Minimal linger. It is set to 6sec specified | 41 | #define FL_MIN_LINGER 6 /* Minimal linger. It is set to 6sec specified |
42 | in old IPv6 RFC. Well, it was reasonable value. | 42 | in old IPv6 RFC. Well, it was reasonable value. |
43 | */ | 43 | */ |
44 | #define FL_MAX_LINGER 60 /* Maximal linger timeout */ | 44 | #define FL_MAX_LINGER 150 /* Maximal linger timeout */ |
45 | 45 | ||
46 | /* FL hash table */ | 46 | /* FL hash table */ |
47 | 47 | ||
@@ -345,6 +345,8 @@ static int fl6_renew(struct ip6_flowlabel *fl, unsigned long linger, unsigned lo | |||
345 | expires = check_linger(expires); | 345 | expires = check_linger(expires); |
346 | if (!expires) | 346 | if (!expires) |
347 | return -EPERM; | 347 | return -EPERM; |
348 | |||
349 | spin_lock_bh(&ip6_fl_lock); | ||
348 | fl->lastuse = jiffies; | 350 | fl->lastuse = jiffies; |
349 | if (time_before(fl->linger, linger)) | 351 | if (time_before(fl->linger, linger)) |
350 | fl->linger = linger; | 352 | fl->linger = linger; |
@@ -352,6 +354,8 @@ static int fl6_renew(struct ip6_flowlabel *fl, unsigned long linger, unsigned lo | |||
352 | expires = fl->linger; | 354 | expires = fl->linger; |
353 | if (time_before(fl->expires, fl->lastuse + expires)) | 355 | if (time_before(fl->expires, fl->lastuse + expires)) |
354 | fl->expires = fl->lastuse + expires; | 356 | fl->expires = fl->lastuse + expires; |
357 | spin_unlock_bh(&ip6_fl_lock); | ||
358 | |||
355 | return 0; | 359 | return 0; |
356 | } | 360 | } |
357 | 361 | ||
@@ -453,8 +457,10 @@ static int mem_check(struct sock *sk) | |||
453 | if (room > FL_MAX_SIZE - FL_MAX_PER_SOCK) | 457 | if (room > FL_MAX_SIZE - FL_MAX_PER_SOCK) |
454 | return 0; | 458 | return 0; |
455 | 459 | ||
460 | rcu_read_lock_bh(); | ||
456 | for_each_sk_fl_rcu(np, sfl) | 461 | for_each_sk_fl_rcu(np, sfl) |
457 | count++; | 462 | count++; |
463 | rcu_read_unlock_bh(); | ||
458 | 464 | ||
459 | if (room <= 0 || | 465 | if (room <= 0 || |
460 | ((count >= FL_MAX_PER_SOCK || | 466 | ((count >= FL_MAX_PER_SOCK || |
@@ -465,34 +471,6 @@ static int mem_check(struct sock *sk) | |||
465 | return 0; | 471 | return 0; |
466 | } | 472 | } |
467 | 473 | ||
468 | static bool ipv6_hdr_cmp(struct ipv6_opt_hdr *h1, struct ipv6_opt_hdr *h2) | ||
469 | { | ||
470 | if (h1 == h2) | ||
471 | return false; | ||
472 | if (h1 == NULL || h2 == NULL) | ||
473 | return true; | ||
474 | if (h1->hdrlen != h2->hdrlen) | ||
475 | return true; | ||
476 | return memcmp(h1+1, h2+1, ((h1->hdrlen+1)<<3) - sizeof(*h1)); | ||
477 | } | ||
478 | |||
479 | static bool ipv6_opt_cmp(struct ipv6_txoptions *o1, struct ipv6_txoptions *o2) | ||
480 | { | ||
481 | if (o1 == o2) | ||
482 | return false; | ||
483 | if (o1 == NULL || o2 == NULL) | ||
484 | return true; | ||
485 | if (o1->opt_nflen != o2->opt_nflen) | ||
486 | return true; | ||
487 | if (ipv6_hdr_cmp(o1->hopopt, o2->hopopt)) | ||
488 | return true; | ||
489 | if (ipv6_hdr_cmp(o1->dst0opt, o2->dst0opt)) | ||
490 | return true; | ||
491 | if (ipv6_hdr_cmp((struct ipv6_opt_hdr *)o1->srcrt, (struct ipv6_opt_hdr *)o2->srcrt)) | ||
492 | return true; | ||
493 | return false; | ||
494 | } | ||
495 | |||
496 | static inline void fl_link(struct ipv6_pinfo *np, struct ipv6_fl_socklist *sfl, | 474 | static inline void fl_link(struct ipv6_pinfo *np, struct ipv6_fl_socklist *sfl, |
497 | struct ip6_flowlabel *fl) | 475 | struct ip6_flowlabel *fl) |
498 | { | 476 | { |
@@ -503,6 +481,32 @@ static inline void fl_link(struct ipv6_pinfo *np, struct ipv6_fl_socklist *sfl, | |||
503 | spin_unlock_bh(&ip6_sk_fl_lock); | 481 | spin_unlock_bh(&ip6_sk_fl_lock); |
504 | } | 482 | } |
505 | 483 | ||
484 | int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq) | ||
485 | { | ||
486 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
487 | struct ipv6_fl_socklist *sfl; | ||
488 | |||
489 | rcu_read_lock_bh(); | ||
490 | |||
491 | for_each_sk_fl_rcu(np, sfl) { | ||
492 | if (sfl->fl->label == (np->flow_label & IPV6_FLOWLABEL_MASK)) { | ||
493 | spin_lock_bh(&ip6_fl_lock); | ||
494 | freq->flr_label = sfl->fl->label; | ||
495 | freq->flr_dst = sfl->fl->dst; | ||
496 | freq->flr_share = sfl->fl->share; | ||
497 | freq->flr_expires = (sfl->fl->expires - jiffies) / HZ; | ||
498 | freq->flr_linger = sfl->fl->linger / HZ; | ||
499 | |||
500 | spin_unlock_bh(&ip6_fl_lock); | ||
501 | rcu_read_unlock_bh(); | ||
502 | return 0; | ||
503 | } | ||
504 | } | ||
505 | rcu_read_unlock_bh(); | ||
506 | |||
507 | return -ENOENT; | ||
508 | } | ||
509 | |||
506 | int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) | 510 | int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) |
507 | { | 511 | { |
508 | int uninitialized_var(err); | 512 | int uninitialized_var(err); |
@@ -603,11 +607,6 @@ recheck: | |||
603 | uid_eq(fl1->owner.uid, fl->owner.uid))) | 607 | uid_eq(fl1->owner.uid, fl->owner.uid))) |
604 | goto release; | 608 | goto release; |
605 | 609 | ||
606 | err = -EINVAL; | ||
607 | if (!ipv6_addr_equal(&fl1->dst, &fl->dst) || | ||
608 | ipv6_opt_cmp(fl1->opt, fl->opt)) | ||
609 | goto release; | ||
610 | |||
611 | err = -ENOMEM; | 610 | err = -ENOMEM; |
612 | if (sfl1 == NULL) | 611 | if (sfl1 == NULL) |
613 | goto release; | 612 | goto release; |
diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c index d82de7228100..4b851692b1f6 100644 --- a/net/ipv6/ip6_offload.c +++ b/net/ipv6/ip6_offload.c | |||
@@ -66,7 +66,6 @@ static int ipv6_gso_send_check(struct sk_buff *skb) | |||
66 | __skb_pull(skb, sizeof(*ipv6h)); | 66 | __skb_pull(skb, sizeof(*ipv6h)); |
67 | err = -EPROTONOSUPPORT; | 67 | err = -EPROTONOSUPPORT; |
68 | 68 | ||
69 | rcu_read_lock(); | ||
70 | ops = rcu_dereference(inet6_offloads[ | 69 | ops = rcu_dereference(inet6_offloads[ |
71 | ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr)]); | 70 | ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr)]); |
72 | 71 | ||
@@ -74,7 +73,6 @@ static int ipv6_gso_send_check(struct sk_buff *skb) | |||
74 | skb_reset_transport_header(skb); | 73 | skb_reset_transport_header(skb); |
75 | err = ops->callbacks.gso_send_check(skb); | 74 | err = ops->callbacks.gso_send_check(skb); |
76 | } | 75 | } |
77 | rcu_read_unlock(); | ||
78 | 76 | ||
79 | out: | 77 | out: |
80 | return err; | 78 | return err; |
@@ -92,46 +90,58 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, | |||
92 | u8 *prevhdr; | 90 | u8 *prevhdr; |
93 | int offset = 0; | 91 | int offset = 0; |
94 | bool tunnel; | 92 | bool tunnel; |
93 | int nhoff; | ||
95 | 94 | ||
96 | if (unlikely(skb_shinfo(skb)->gso_type & | 95 | if (unlikely(skb_shinfo(skb)->gso_type & |
97 | ~(SKB_GSO_UDP | | 96 | ~(SKB_GSO_UDP | |
98 | SKB_GSO_DODGY | | 97 | SKB_GSO_DODGY | |
99 | SKB_GSO_TCP_ECN | | 98 | SKB_GSO_TCP_ECN | |
100 | SKB_GSO_GRE | | 99 | SKB_GSO_GRE | |
100 | SKB_GSO_IPIP | | ||
101 | SKB_GSO_SIT | | ||
101 | SKB_GSO_UDP_TUNNEL | | 102 | SKB_GSO_UDP_TUNNEL | |
102 | SKB_GSO_MPLS | | 103 | SKB_GSO_MPLS | |
103 | SKB_GSO_TCPV6 | | 104 | SKB_GSO_TCPV6 | |
104 | 0))) | 105 | 0))) |
105 | goto out; | 106 | goto out; |
106 | 107 | ||
108 | skb_reset_network_header(skb); | ||
109 | nhoff = skb_network_header(skb) - skb_mac_header(skb); | ||
107 | if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h)))) | 110 | if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h)))) |
108 | goto out; | 111 | goto out; |
109 | 112 | ||
110 | tunnel = skb->encapsulation; | 113 | tunnel = SKB_GSO_CB(skb)->encap_level > 0; |
114 | if (tunnel) | ||
115 | features = skb->dev->hw_enc_features & netif_skb_features(skb); | ||
116 | SKB_GSO_CB(skb)->encap_level += sizeof(*ipv6h); | ||
117 | |||
111 | ipv6h = ipv6_hdr(skb); | 118 | ipv6h = ipv6_hdr(skb); |
112 | __skb_pull(skb, sizeof(*ipv6h)); | 119 | __skb_pull(skb, sizeof(*ipv6h)); |
113 | segs = ERR_PTR(-EPROTONOSUPPORT); | 120 | segs = ERR_PTR(-EPROTONOSUPPORT); |
114 | 121 | ||
115 | proto = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr); | 122 | proto = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr); |
116 | rcu_read_lock(); | 123 | |
117 | ops = rcu_dereference(inet6_offloads[proto]); | 124 | ops = rcu_dereference(inet6_offloads[proto]); |
118 | if (likely(ops && ops->callbacks.gso_segment)) { | 125 | if (likely(ops && ops->callbacks.gso_segment)) { |
119 | skb_reset_transport_header(skb); | 126 | skb_reset_transport_header(skb); |
120 | segs = ops->callbacks.gso_segment(skb, features); | 127 | segs = ops->callbacks.gso_segment(skb, features); |
121 | } | 128 | } |
122 | rcu_read_unlock(); | ||
123 | 129 | ||
124 | if (IS_ERR(segs)) | 130 | if (IS_ERR(segs)) |
125 | goto out; | 131 | goto out; |
126 | 132 | ||
127 | for (skb = segs; skb; skb = skb->next) { | 133 | for (skb = segs; skb; skb = skb->next) { |
128 | ipv6h = ipv6_hdr(skb); | 134 | ipv6h = (struct ipv6hdr *)(skb_mac_header(skb) + nhoff); |
129 | ipv6h->payload_len = htons(skb->len - skb->mac_len - | 135 | ipv6h->payload_len = htons(skb->len - nhoff - sizeof(*ipv6h)); |
130 | sizeof(*ipv6h)); | 136 | if (tunnel) { |
137 | skb_reset_inner_headers(skb); | ||
138 | skb->encapsulation = 1; | ||
139 | } | ||
140 | skb->network_header = (u8 *)ipv6h - skb->head; | ||
141 | |||
131 | if (!tunnel && proto == IPPROTO_UDP) { | 142 | if (!tunnel && proto == IPPROTO_UDP) { |
132 | unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr); | 143 | unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr); |
133 | fptr = (struct frag_hdr *)(skb_network_header(skb) + | 144 | fptr = (struct frag_hdr *)((u8 *)ipv6h + unfrag_ip6hlen); |
134 | unfrag_ip6hlen); | ||
135 | fptr->frag_off = htons(offset); | 145 | fptr->frag_off = htons(offset); |
136 | if (skb->next != NULL) | 146 | if (skb->next != NULL) |
137 | fptr->frag_off |= htons(IP6_MF); | 147 | fptr->frag_off |= htons(IP6_MF); |
@@ -267,6 +277,13 @@ static struct packet_offload ipv6_packet_offload __read_mostly = { | |||
267 | }, | 277 | }, |
268 | }; | 278 | }; |
269 | 279 | ||
280 | static const struct net_offload sit_offload = { | ||
281 | .callbacks = { | ||
282 | .gso_send_check = ipv6_gso_send_check, | ||
283 | .gso_segment = ipv6_gso_segment, | ||
284 | }, | ||
285 | }; | ||
286 | |||
270 | static int __init ipv6_offload_init(void) | 287 | static int __init ipv6_offload_init(void) |
271 | { | 288 | { |
272 | 289 | ||
@@ -278,6 +295,9 @@ static int __init ipv6_offload_init(void) | |||
278 | pr_crit("%s: Cannot add EXTHDRS protocol offload\n", __func__); | 295 | pr_crit("%s: Cannot add EXTHDRS protocol offload\n", __func__); |
279 | 296 | ||
280 | dev_add_offload(&ipv6_packet_offload); | 297 | dev_add_offload(&ipv6_packet_offload); |
298 | |||
299 | inet_add_offload(&sit_offload, IPPROTO_IPV6); | ||
300 | |||
281 | return 0; | 301 | return 0; |
282 | } | 302 | } |
283 | 303 | ||
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 91fb4e8212f5..5e31a909a2b0 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -125,7 +125,8 @@ static int ip6_finish_output2(struct sk_buff *skb) | |||
125 | static int ip6_finish_output(struct sk_buff *skb) | 125 | static int ip6_finish_output(struct sk_buff *skb) |
126 | { | 126 | { |
127 | if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) || | 127 | if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) || |
128 | dst_allfrag(skb_dst(skb))) | 128 | dst_allfrag(skb_dst(skb)) || |
129 | (IP6CB(skb)->frag_max_size && skb->len > IP6CB(skb)->frag_max_size)) | ||
129 | return ip6_fragment(skb, ip6_finish_output2); | 130 | return ip6_fragment(skb, ip6_finish_output2); |
130 | else | 131 | else |
131 | return ip6_finish_output2(skb); | 132 | return ip6_finish_output2(skb); |
diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c new file mode 100644 index 000000000000..ed94ba61dda0 --- /dev/null +++ b/net/ipv6/ip6_vti.c | |||
@@ -0,0 +1,1056 @@ | |||
1 | /* | ||
2 | * IPv6 virtual tunneling interface | ||
3 | * | ||
4 | * Copyright (C) 2013 secunet Security Networks AG | ||
5 | * | ||
6 | * Author: | ||
7 | * Steffen Klassert <steffen.klassert@secunet.com> | ||
8 | * | ||
9 | * Based on: | ||
10 | * net/ipv6/ip6_tunnel.c | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version | ||
15 | * 2 of the License, or (at your option) any later version. | ||
16 | */ | ||
17 | |||
18 | #include <linux/module.h> | ||
19 | #include <linux/capability.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/types.h> | ||
22 | #include <linux/sockios.h> | ||
23 | #include <linux/icmp.h> | ||
24 | #include <linux/if.h> | ||
25 | #include <linux/in.h> | ||
26 | #include <linux/ip.h> | ||
27 | #include <linux/if_tunnel.h> | ||
28 | #include <linux/net.h> | ||
29 | #include <linux/in6.h> | ||
30 | #include <linux/netdevice.h> | ||
31 | #include <linux/if_arp.h> | ||
32 | #include <linux/icmpv6.h> | ||
33 | #include <linux/init.h> | ||
34 | #include <linux/route.h> | ||
35 | #include <linux/rtnetlink.h> | ||
36 | #include <linux/netfilter_ipv6.h> | ||
37 | #include <linux/slab.h> | ||
38 | #include <linux/hash.h> | ||
39 | |||
40 | #include <linux/uaccess.h> | ||
41 | #include <linux/atomic.h> | ||
42 | |||
43 | #include <net/icmp.h> | ||
44 | #include <net/ip.h> | ||
45 | #include <net/ip_tunnels.h> | ||
46 | #include <net/ipv6.h> | ||
47 | #include <net/ip6_route.h> | ||
48 | #include <net/addrconf.h> | ||
49 | #include <net/ip6_tunnel.h> | ||
50 | #include <net/xfrm.h> | ||
51 | #include <net/net_namespace.h> | ||
52 | #include <net/netns/generic.h> | ||
53 | |||
54 | #define HASH_SIZE_SHIFT 5 | ||
55 | #define HASH_SIZE (1 << HASH_SIZE_SHIFT) | ||
56 | |||
57 | static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2) | ||
58 | { | ||
59 | u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2); | ||
60 | |||
61 | return hash_32(hash, HASH_SIZE_SHIFT); | ||
62 | } | ||
63 | |||
64 | static int vti6_dev_init(struct net_device *dev); | ||
65 | static void vti6_dev_setup(struct net_device *dev); | ||
66 | static struct rtnl_link_ops vti6_link_ops __read_mostly; | ||
67 | |||
68 | static int vti6_net_id __read_mostly; | ||
69 | struct vti6_net { | ||
70 | /* the vti6 tunnel fallback device */ | ||
71 | struct net_device *fb_tnl_dev; | ||
72 | /* lists for storing tunnels in use */ | ||
73 | struct ip6_tnl __rcu *tnls_r_l[HASH_SIZE]; | ||
74 | struct ip6_tnl __rcu *tnls_wc[1]; | ||
75 | struct ip6_tnl __rcu **tnls[2]; | ||
76 | }; | ||
77 | |||
78 | static struct net_device_stats *vti6_get_stats(struct net_device *dev) | ||
79 | { | ||
80 | struct pcpu_tstats sum = { 0 }; | ||
81 | int i; | ||
82 | |||
83 | for_each_possible_cpu(i) { | ||
84 | const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i); | ||
85 | |||
86 | sum.rx_packets += tstats->rx_packets; | ||
87 | sum.rx_bytes += tstats->rx_bytes; | ||
88 | sum.tx_packets += tstats->tx_packets; | ||
89 | sum.tx_bytes += tstats->tx_bytes; | ||
90 | } | ||
91 | dev->stats.rx_packets = sum.rx_packets; | ||
92 | dev->stats.rx_bytes = sum.rx_bytes; | ||
93 | dev->stats.tx_packets = sum.tx_packets; | ||
94 | dev->stats.tx_bytes = sum.tx_bytes; | ||
95 | return &dev->stats; | ||
96 | } | ||
97 | |||
98 | #define for_each_vti6_tunnel_rcu(start) \ | ||
99 | for (t = rcu_dereference(start); t; t = rcu_dereference(t->next)) | ||
100 | |||
101 | /** | ||
102 | * vti6_tnl_lookup - fetch tunnel matching the end-point addresses | ||
103 | * @net: network namespace | ||
104 | * @remote: the address of the tunnel exit-point | ||
105 | * @local: the address of the tunnel entry-point | ||
106 | * | ||
107 | * Return: | ||
108 | * tunnel matching given end-points if found, | ||
109 | * else fallback tunnel if its device is up, | ||
110 | * else %NULL | ||
111 | **/ | ||
112 | static struct ip6_tnl * | ||
113 | vti6_tnl_lookup(struct net *net, const struct in6_addr *remote, | ||
114 | const struct in6_addr *local) | ||
115 | { | ||
116 | unsigned int hash = HASH(remote, local); | ||
117 | struct ip6_tnl *t; | ||
118 | struct vti6_net *ip6n = net_generic(net, vti6_net_id); | ||
119 | |||
120 | for_each_vti6_tunnel_rcu(ip6n->tnls_r_l[hash]) { | ||
121 | if (ipv6_addr_equal(local, &t->parms.laddr) && | ||
122 | ipv6_addr_equal(remote, &t->parms.raddr) && | ||
123 | (t->dev->flags & IFF_UP)) | ||
124 | return t; | ||
125 | } | ||
126 | t = rcu_dereference(ip6n->tnls_wc[0]); | ||
127 | if (t && (t->dev->flags & IFF_UP)) | ||
128 | return t; | ||
129 | |||
130 | return NULL; | ||
131 | } | ||
132 | |||
133 | /** | ||
134 | * vti6_tnl_bucket - get head of list matching given tunnel parameters | ||
135 | * @p: parameters containing tunnel end-points | ||
136 | * | ||
137 | * Description: | ||
138 | * vti6_tnl_bucket() returns the head of the list matching the | ||
139 | * &struct in6_addr entries laddr and raddr in @p. | ||
140 | * | ||
141 | * Return: head of IPv6 tunnel list | ||
142 | **/ | ||
143 | static struct ip6_tnl __rcu ** | ||
144 | vti6_tnl_bucket(struct vti6_net *ip6n, const struct __ip6_tnl_parm *p) | ||
145 | { | ||
146 | const struct in6_addr *remote = &p->raddr; | ||
147 | const struct in6_addr *local = &p->laddr; | ||
148 | unsigned int h = 0; | ||
149 | int prio = 0; | ||
150 | |||
151 | if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) { | ||
152 | prio = 1; | ||
153 | h = HASH(remote, local); | ||
154 | } | ||
155 | return &ip6n->tnls[prio][h]; | ||
156 | } | ||
157 | |||
158 | static void | ||
159 | vti6_tnl_link(struct vti6_net *ip6n, struct ip6_tnl *t) | ||
160 | { | ||
161 | struct ip6_tnl __rcu **tp = vti6_tnl_bucket(ip6n, &t->parms); | ||
162 | |||
163 | rcu_assign_pointer(t->next , rtnl_dereference(*tp)); | ||
164 | rcu_assign_pointer(*tp, t); | ||
165 | } | ||
166 | |||
167 | static void | ||
168 | vti6_tnl_unlink(struct vti6_net *ip6n, struct ip6_tnl *t) | ||
169 | { | ||
170 | struct ip6_tnl __rcu **tp; | ||
171 | struct ip6_tnl *iter; | ||
172 | |||
173 | for (tp = vti6_tnl_bucket(ip6n, &t->parms); | ||
174 | (iter = rtnl_dereference(*tp)) != NULL; | ||
175 | tp = &iter->next) { | ||
176 | if (t == iter) { | ||
177 | rcu_assign_pointer(*tp, t->next); | ||
178 | break; | ||
179 | } | ||
180 | } | ||
181 | } | ||
182 | |||
183 | static void vti6_dev_free(struct net_device *dev) | ||
184 | { | ||
185 | free_percpu(dev->tstats); | ||
186 | free_netdev(dev); | ||
187 | } | ||
188 | |||
189 | static int vti6_tnl_create2(struct net_device *dev) | ||
190 | { | ||
191 | struct ip6_tnl *t = netdev_priv(dev); | ||
192 | struct net *net = dev_net(dev); | ||
193 | struct vti6_net *ip6n = net_generic(net, vti6_net_id); | ||
194 | int err; | ||
195 | |||
196 | err = vti6_dev_init(dev); | ||
197 | if (err < 0) | ||
198 | goto out; | ||
199 | |||
200 | err = register_netdevice(dev); | ||
201 | if (err < 0) | ||
202 | goto out; | ||
203 | |||
204 | strcpy(t->parms.name, dev->name); | ||
205 | dev->rtnl_link_ops = &vti6_link_ops; | ||
206 | |||
207 | dev_hold(dev); | ||
208 | vti6_tnl_link(ip6n, t); | ||
209 | |||
210 | return 0; | ||
211 | |||
212 | out: | ||
213 | return err; | ||
214 | } | ||
215 | |||
216 | static struct ip6_tnl *vti6_tnl_create(struct net *net, struct __ip6_tnl_parm *p) | ||
217 | { | ||
218 | struct net_device *dev; | ||
219 | struct ip6_tnl *t; | ||
220 | char name[IFNAMSIZ]; | ||
221 | int err; | ||
222 | |||
223 | if (p->name[0]) | ||
224 | strlcpy(name, p->name, IFNAMSIZ); | ||
225 | else | ||
226 | sprintf(name, "ip6_vti%%d"); | ||
227 | |||
228 | dev = alloc_netdev(sizeof(*t), name, vti6_dev_setup); | ||
229 | if (dev == NULL) | ||
230 | goto failed; | ||
231 | |||
232 | dev_net_set(dev, net); | ||
233 | |||
234 | t = netdev_priv(dev); | ||
235 | t->parms = *p; | ||
236 | t->net = dev_net(dev); | ||
237 | |||
238 | err = vti6_tnl_create2(dev); | ||
239 | if (err < 0) | ||
240 | goto failed_free; | ||
241 | |||
242 | return t; | ||
243 | |||
244 | failed_free: | ||
245 | vti6_dev_free(dev); | ||
246 | failed: | ||
247 | return NULL; | ||
248 | } | ||
249 | |||
250 | /** | ||
251 | * vti6_locate - find or create tunnel matching given parameters | ||
252 | * @net: network namespace | ||
253 | * @p: tunnel parameters | ||
254 | * @create: != 0 if allowed to create new tunnel if no match found | ||
255 | * | ||
256 | * Description: | ||
257 | * vti6_locate() first tries to locate an existing tunnel | ||
258 | * based on @parms. If this is unsuccessful, but @create is set a new | ||
259 | * tunnel device is created and registered for use. | ||
260 | * | ||
261 | * Return: | ||
262 | * matching tunnel or NULL | ||
263 | **/ | ||
264 | static struct ip6_tnl *vti6_locate(struct net *net, struct __ip6_tnl_parm *p, | ||
265 | int create) | ||
266 | { | ||
267 | const struct in6_addr *remote = &p->raddr; | ||
268 | const struct in6_addr *local = &p->laddr; | ||
269 | struct ip6_tnl __rcu **tp; | ||
270 | struct ip6_tnl *t; | ||
271 | struct vti6_net *ip6n = net_generic(net, vti6_net_id); | ||
272 | |||
273 | for (tp = vti6_tnl_bucket(ip6n, p); | ||
274 | (t = rtnl_dereference(*tp)) != NULL; | ||
275 | tp = &t->next) { | ||
276 | if (ipv6_addr_equal(local, &t->parms.laddr) && | ||
277 | ipv6_addr_equal(remote, &t->parms.raddr)) | ||
278 | return t; | ||
279 | } | ||
280 | if (!create) | ||
281 | return NULL; | ||
282 | return vti6_tnl_create(net, p); | ||
283 | } | ||
284 | |||
285 | /** | ||
286 | * vti6_dev_uninit - tunnel device uninitializer | ||
287 | * @dev: the device to be destroyed | ||
288 | * | ||
289 | * Description: | ||
290 | * vti6_dev_uninit() removes tunnel from its list | ||
291 | **/ | ||
292 | static void vti6_dev_uninit(struct net_device *dev) | ||
293 | { | ||
294 | struct ip6_tnl *t = netdev_priv(dev); | ||
295 | struct net *net = dev_net(dev); | ||
296 | struct vti6_net *ip6n = net_generic(net, vti6_net_id); | ||
297 | |||
298 | if (dev == ip6n->fb_tnl_dev) | ||
299 | RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL); | ||
300 | else | ||
301 | vti6_tnl_unlink(ip6n, t); | ||
302 | ip6_tnl_dst_reset(t); | ||
303 | dev_put(dev); | ||
304 | } | ||
305 | |||
306 | static int vti6_rcv(struct sk_buff *skb) | ||
307 | { | ||
308 | struct ip6_tnl *t; | ||
309 | const struct ipv6hdr *ipv6h = ipv6_hdr(skb); | ||
310 | |||
311 | rcu_read_lock(); | ||
312 | |||
313 | if ((t = vti6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, | ||
314 | &ipv6h->daddr)) != NULL) { | ||
315 | struct pcpu_tstats *tstats; | ||
316 | |||
317 | if (t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) { | ||
318 | rcu_read_unlock(); | ||
319 | goto discard; | ||
320 | } | ||
321 | |||
322 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { | ||
323 | rcu_read_unlock(); | ||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | if (!ip6_tnl_rcv_ctl(t, &ipv6h->daddr, &ipv6h->saddr)) { | ||
328 | t->dev->stats.rx_dropped++; | ||
329 | rcu_read_unlock(); | ||
330 | goto discard; | ||
331 | } | ||
332 | |||
333 | tstats = this_cpu_ptr(t->dev->tstats); | ||
334 | tstats->rx_packets++; | ||
335 | tstats->rx_bytes += skb->len; | ||
336 | |||
337 | skb->mark = 0; | ||
338 | secpath_reset(skb); | ||
339 | skb->dev = t->dev; | ||
340 | |||
341 | rcu_read_unlock(); | ||
342 | return 0; | ||
343 | } | ||
344 | rcu_read_unlock(); | ||
345 | return 1; | ||
346 | |||
347 | discard: | ||
348 | kfree_skb(skb); | ||
349 | return 0; | ||
350 | } | ||
351 | |||
352 | /** | ||
353 | * vti6_addr_conflict - compare packet addresses to tunnel's own | ||
354 | * @t: the outgoing tunnel device | ||
355 | * @hdr: IPv6 header from the incoming packet | ||
356 | * | ||
357 | * Description: | ||
358 | * Avoid trivial tunneling loop by checking that tunnel exit-point | ||
359 | * doesn't match source of incoming packet. | ||
360 | * | ||
361 | * Return: | ||
362 | * 1 if conflict, | ||
363 | * 0 else | ||
364 | **/ | ||
365 | static inline bool | ||
366 | vti6_addr_conflict(const struct ip6_tnl *t, const struct ipv6hdr *hdr) | ||
367 | { | ||
368 | return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr); | ||
369 | } | ||
370 | |||
371 | /** | ||
372 | * vti6_xmit - send a packet | ||
373 | * @skb: the outgoing socket buffer | ||
374 | * @dev: the outgoing tunnel device | ||
375 | **/ | ||
376 | static int vti6_xmit(struct sk_buff *skb, struct net_device *dev) | ||
377 | { | ||
378 | struct net *net = dev_net(dev); | ||
379 | struct ip6_tnl *t = netdev_priv(dev); | ||
380 | struct net_device_stats *stats = &t->dev->stats; | ||
381 | struct dst_entry *dst = NULL, *ndst = NULL; | ||
382 | struct flowi6 fl6; | ||
383 | struct ipv6hdr *ipv6h = ipv6_hdr(skb); | ||
384 | struct net_device *tdev; | ||
385 | int err = -1; | ||
386 | |||
387 | if ((t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) || | ||
388 | !ip6_tnl_xmit_ctl(t) || vti6_addr_conflict(t, ipv6h)) | ||
389 | return err; | ||
390 | |||
391 | dst = ip6_tnl_dst_check(t); | ||
392 | if (!dst) { | ||
393 | memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6)); | ||
394 | |||
395 | ndst = ip6_route_output(net, NULL, &fl6); | ||
396 | |||
397 | if (ndst->error) | ||
398 | goto tx_err_link_failure; | ||
399 | ndst = xfrm_lookup(net, ndst, flowi6_to_flowi(&fl6), NULL, 0); | ||
400 | if (IS_ERR(ndst)) { | ||
401 | err = PTR_ERR(ndst); | ||
402 | ndst = NULL; | ||
403 | goto tx_err_link_failure; | ||
404 | } | ||
405 | dst = ndst; | ||
406 | } | ||
407 | |||
408 | if (!dst->xfrm || dst->xfrm->props.mode != XFRM_MODE_TUNNEL) | ||
409 | goto tx_err_link_failure; | ||
410 | |||
411 | tdev = dst->dev; | ||
412 | |||
413 | if (tdev == dev) { | ||
414 | stats->collisions++; | ||
415 | net_warn_ratelimited("%s: Local routing loop detected!\n", | ||
416 | t->parms.name); | ||
417 | goto tx_err_dst_release; | ||
418 | } | ||
419 | |||
420 | |||
421 | skb_dst_drop(skb); | ||
422 | skb_dst_set_noref(skb, dst); | ||
423 | |||
424 | ip6tunnel_xmit(skb, dev); | ||
425 | if (ndst) { | ||
426 | dev->mtu = dst_mtu(ndst); | ||
427 | ip6_tnl_dst_store(t, ndst); | ||
428 | } | ||
429 | |||
430 | return 0; | ||
431 | tx_err_link_failure: | ||
432 | stats->tx_carrier_errors++; | ||
433 | dst_link_failure(skb); | ||
434 | tx_err_dst_release: | ||
435 | dst_release(ndst); | ||
436 | return err; | ||
437 | } | ||
438 | |||
439 | static netdev_tx_t | ||
440 | vti6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) | ||
441 | { | ||
442 | struct ip6_tnl *t = netdev_priv(dev); | ||
443 | struct net_device_stats *stats = &t->dev->stats; | ||
444 | int ret; | ||
445 | |||
446 | switch (skb->protocol) { | ||
447 | case htons(ETH_P_IPV6): | ||
448 | ret = vti6_xmit(skb, dev); | ||
449 | break; | ||
450 | default: | ||
451 | goto tx_err; | ||
452 | } | ||
453 | |||
454 | if (ret < 0) | ||
455 | goto tx_err; | ||
456 | |||
457 | return NETDEV_TX_OK; | ||
458 | |||
459 | tx_err: | ||
460 | stats->tx_errors++; | ||
461 | stats->tx_dropped++; | ||
462 | kfree_skb(skb); | ||
463 | return NETDEV_TX_OK; | ||
464 | } | ||
465 | |||
466 | static void vti6_link_config(struct ip6_tnl *t) | ||
467 | { | ||
468 | struct dst_entry *dst; | ||
469 | struct net_device *dev = t->dev; | ||
470 | struct __ip6_tnl_parm *p = &t->parms; | ||
471 | struct flowi6 *fl6 = &t->fl.u.ip6; | ||
472 | |||
473 | memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr)); | ||
474 | memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr)); | ||
475 | |||
476 | /* Set up flowi template */ | ||
477 | fl6->saddr = p->laddr; | ||
478 | fl6->daddr = p->raddr; | ||
479 | fl6->flowi6_oif = p->link; | ||
480 | fl6->flowi6_mark = be32_to_cpu(p->i_key); | ||
481 | fl6->flowi6_proto = p->proto; | ||
482 | fl6->flowlabel = 0; | ||
483 | |||
484 | p->flags &= ~(IP6_TNL_F_CAP_XMIT | IP6_TNL_F_CAP_RCV | | ||
485 | IP6_TNL_F_CAP_PER_PACKET); | ||
486 | p->flags |= ip6_tnl_get_cap(t, &p->laddr, &p->raddr); | ||
487 | |||
488 | if (p->flags & IP6_TNL_F_CAP_XMIT && p->flags & IP6_TNL_F_CAP_RCV) | ||
489 | dev->flags |= IFF_POINTOPOINT; | ||
490 | else | ||
491 | dev->flags &= ~IFF_POINTOPOINT; | ||
492 | |||
493 | dev->iflink = p->link; | ||
494 | |||
495 | if (p->flags & IP6_TNL_F_CAP_XMIT) { | ||
496 | |||
497 | dst = ip6_route_output(dev_net(dev), NULL, fl6); | ||
498 | if (dst->error) | ||
499 | return; | ||
500 | |||
501 | dst = xfrm_lookup(dev_net(dev), dst, flowi6_to_flowi(fl6), | ||
502 | NULL, 0); | ||
503 | if (IS_ERR(dst)) | ||
504 | return; | ||
505 | |||
506 | if (dst->dev) { | ||
507 | dev->hard_header_len = dst->dev->hard_header_len; | ||
508 | |||
509 | dev->mtu = dst_mtu(dst); | ||
510 | |||
511 | if (dev->mtu < IPV6_MIN_MTU) | ||
512 | dev->mtu = IPV6_MIN_MTU; | ||
513 | } | ||
514 | dst_release(dst); | ||
515 | } | ||
516 | } | ||
517 | |||
518 | /** | ||
519 | * vti6_tnl_change - update the tunnel parameters | ||
520 | * @t: tunnel to be changed | ||
521 | * @p: tunnel configuration parameters | ||
522 | * | ||
523 | * Description: | ||
524 | * vti6_tnl_change() updates the tunnel parameters | ||
525 | **/ | ||
526 | static int | ||
527 | vti6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p) | ||
528 | { | ||
529 | t->parms.laddr = p->laddr; | ||
530 | t->parms.raddr = p->raddr; | ||
531 | t->parms.link = p->link; | ||
532 | t->parms.i_key = p->i_key; | ||
533 | t->parms.o_key = p->o_key; | ||
534 | t->parms.proto = p->proto; | ||
535 | ip6_tnl_dst_reset(t); | ||
536 | vti6_link_config(t); | ||
537 | return 0; | ||
538 | } | ||
539 | |||
540 | static int vti6_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p) | ||
541 | { | ||
542 | struct net *net = dev_net(t->dev); | ||
543 | struct vti6_net *ip6n = net_generic(net, vti6_net_id); | ||
544 | int err; | ||
545 | |||
546 | vti6_tnl_unlink(ip6n, t); | ||
547 | synchronize_net(); | ||
548 | err = vti6_tnl_change(t, p); | ||
549 | vti6_tnl_link(ip6n, t); | ||
550 | netdev_state_change(t->dev); | ||
551 | return err; | ||
552 | } | ||
553 | |||
554 | static void | ||
555 | vti6_parm_from_user(struct __ip6_tnl_parm *p, const struct ip6_tnl_parm2 *u) | ||
556 | { | ||
557 | p->laddr = u->laddr; | ||
558 | p->raddr = u->raddr; | ||
559 | p->link = u->link; | ||
560 | p->i_key = u->i_key; | ||
561 | p->o_key = u->o_key; | ||
562 | p->proto = u->proto; | ||
563 | |||
564 | memcpy(p->name, u->name, sizeof(u->name)); | ||
565 | } | ||
566 | |||
567 | static void | ||
568 | vti6_parm_to_user(struct ip6_tnl_parm2 *u, const struct __ip6_tnl_parm *p) | ||
569 | { | ||
570 | u->laddr = p->laddr; | ||
571 | u->raddr = p->raddr; | ||
572 | u->link = p->link; | ||
573 | u->i_key = p->i_key; | ||
574 | u->o_key = p->o_key; | ||
575 | u->proto = p->proto; | ||
576 | |||
577 | memcpy(u->name, p->name, sizeof(u->name)); | ||
578 | } | ||
579 | |||
580 | /** | ||
581 | * vti6_tnl_ioctl - configure vti6 tunnels from userspace | ||
582 | * @dev: virtual device associated with tunnel | ||
583 | * @ifr: parameters passed from userspace | ||
584 | * @cmd: command to be performed | ||
585 | * | ||
586 | * Description: | ||
587 | * vti6_ioctl() is used for managing vti6 tunnels | ||
588 | * from userspace. | ||
589 | * | ||
590 | * The possible commands are the following: | ||
591 | * %SIOCGETTUNNEL: get tunnel parameters for device | ||
592 | * %SIOCADDTUNNEL: add tunnel matching given tunnel parameters | ||
593 | * %SIOCCHGTUNNEL: change tunnel parameters to those given | ||
594 | * %SIOCDELTUNNEL: delete tunnel | ||
595 | * | ||
596 | * The fallback device "ip6_vti0", created during module | ||
597 | * initialization, can be used for creating other tunnel devices. | ||
598 | * | ||
599 | * Return: | ||
600 | * 0 on success, | ||
601 | * %-EFAULT if unable to copy data to or from userspace, | ||
602 | * %-EPERM if current process hasn't %CAP_NET_ADMIN set | ||
603 | * %-EINVAL if passed tunnel parameters are invalid, | ||
604 | * %-EEXIST if changing a tunnel's parameters would cause a conflict | ||
605 | * %-ENODEV if attempting to change or delete a nonexisting device | ||
606 | **/ | ||
607 | static int | ||
608 | vti6_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | ||
609 | { | ||
610 | int err = 0; | ||
611 | struct ip6_tnl_parm2 p; | ||
612 | struct __ip6_tnl_parm p1; | ||
613 | struct ip6_tnl *t = NULL; | ||
614 | struct net *net = dev_net(dev); | ||
615 | struct vti6_net *ip6n = net_generic(net, vti6_net_id); | ||
616 | |||
617 | switch (cmd) { | ||
618 | case SIOCGETTUNNEL: | ||
619 | if (dev == ip6n->fb_tnl_dev) { | ||
620 | if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) { | ||
621 | err = -EFAULT; | ||
622 | break; | ||
623 | } | ||
624 | vti6_parm_from_user(&p1, &p); | ||
625 | t = vti6_locate(net, &p1, 0); | ||
626 | } else { | ||
627 | memset(&p, 0, sizeof(p)); | ||
628 | } | ||
629 | if (t == NULL) | ||
630 | t = netdev_priv(dev); | ||
631 | vti6_parm_to_user(&p, &t->parms); | ||
632 | if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) | ||
633 | err = -EFAULT; | ||
634 | break; | ||
635 | case SIOCADDTUNNEL: | ||
636 | case SIOCCHGTUNNEL: | ||
637 | err = -EPERM; | ||
638 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) | ||
639 | break; | ||
640 | err = -EFAULT; | ||
641 | if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) | ||
642 | break; | ||
643 | err = -EINVAL; | ||
644 | if (p.proto != IPPROTO_IPV6 && p.proto != 0) | ||
645 | break; | ||
646 | vti6_parm_from_user(&p1, &p); | ||
647 | t = vti6_locate(net, &p1, cmd == SIOCADDTUNNEL); | ||
648 | if (dev != ip6n->fb_tnl_dev && cmd == SIOCCHGTUNNEL) { | ||
649 | if (t != NULL) { | ||
650 | if (t->dev != dev) { | ||
651 | err = -EEXIST; | ||
652 | break; | ||
653 | } | ||
654 | } else | ||
655 | t = netdev_priv(dev); | ||
656 | |||
657 | err = vti6_update(t, &p1); | ||
658 | } | ||
659 | if (t) { | ||
660 | err = 0; | ||
661 | vti6_parm_to_user(&p, &t->parms); | ||
662 | if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) | ||
663 | err = -EFAULT; | ||
664 | |||
665 | } else | ||
666 | err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT); | ||
667 | break; | ||
668 | case SIOCDELTUNNEL: | ||
669 | err = -EPERM; | ||
670 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) | ||
671 | break; | ||
672 | |||
673 | if (dev == ip6n->fb_tnl_dev) { | ||
674 | err = -EFAULT; | ||
675 | if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) | ||
676 | break; | ||
677 | err = -ENOENT; | ||
678 | vti6_parm_from_user(&p1, &p); | ||
679 | t = vti6_locate(net, &p1, 0); | ||
680 | if (t == NULL) | ||
681 | break; | ||
682 | err = -EPERM; | ||
683 | if (t->dev == ip6n->fb_tnl_dev) | ||
684 | break; | ||
685 | dev = t->dev; | ||
686 | } | ||
687 | err = 0; | ||
688 | unregister_netdevice(dev); | ||
689 | break; | ||
690 | default: | ||
691 | err = -EINVAL; | ||
692 | } | ||
693 | return err; | ||
694 | } | ||
695 | |||
696 | /** | ||
697 | * vti6_tnl_change_mtu - change mtu manually for tunnel device | ||
698 | * @dev: virtual device associated with tunnel | ||
699 | * @new_mtu: the new mtu | ||
700 | * | ||
701 | * Return: | ||
702 | * 0 on success, | ||
703 | * %-EINVAL if mtu too small | ||
704 | **/ | ||
705 | static int vti6_change_mtu(struct net_device *dev, int new_mtu) | ||
706 | { | ||
707 | if (new_mtu < IPV6_MIN_MTU) | ||
708 | return -EINVAL; | ||
709 | |||
710 | dev->mtu = new_mtu; | ||
711 | return 0; | ||
712 | } | ||
713 | |||
714 | static const struct net_device_ops vti6_netdev_ops = { | ||
715 | .ndo_uninit = vti6_dev_uninit, | ||
716 | .ndo_start_xmit = vti6_tnl_xmit, | ||
717 | .ndo_do_ioctl = vti6_ioctl, | ||
718 | .ndo_change_mtu = vti6_change_mtu, | ||
719 | .ndo_get_stats = vti6_get_stats, | ||
720 | }; | ||
721 | |||
722 | /** | ||
723 | * vti6_dev_setup - setup virtual tunnel device | ||
724 | * @dev: virtual device associated with tunnel | ||
725 | * | ||
726 | * Description: | ||
727 | * Initialize function pointers and device parameters | ||
728 | **/ | ||
729 | static void vti6_dev_setup(struct net_device *dev) | ||
730 | { | ||
731 | struct ip6_tnl *t; | ||
732 | |||
733 | dev->netdev_ops = &vti6_netdev_ops; | ||
734 | dev->destructor = vti6_dev_free; | ||
735 | |||
736 | dev->type = ARPHRD_TUNNEL6; | ||
737 | dev->hard_header_len = LL_MAX_HEADER + sizeof(struct ipv6hdr); | ||
738 | dev->mtu = ETH_DATA_LEN; | ||
739 | t = netdev_priv(dev); | ||
740 | dev->flags |= IFF_NOARP; | ||
741 | dev->addr_len = sizeof(struct in6_addr); | ||
742 | dev->features |= NETIF_F_NETNS_LOCAL; | ||
743 | dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; | ||
744 | } | ||
745 | |||
746 | /** | ||
747 | * vti6_dev_init_gen - general initializer for all tunnel devices | ||
748 | * @dev: virtual device associated with tunnel | ||
749 | **/ | ||
750 | static inline int vti6_dev_init_gen(struct net_device *dev) | ||
751 | { | ||
752 | struct ip6_tnl *t = netdev_priv(dev); | ||
753 | |||
754 | t->dev = dev; | ||
755 | t->net = dev_net(dev); | ||
756 | dev->tstats = alloc_percpu(struct pcpu_tstats); | ||
757 | if (!dev->tstats) | ||
758 | return -ENOMEM; | ||
759 | return 0; | ||
760 | } | ||
761 | |||
762 | /** | ||
763 | * vti6_dev_init - initializer for all non fallback tunnel devices | ||
764 | * @dev: virtual device associated with tunnel | ||
765 | **/ | ||
766 | static int vti6_dev_init(struct net_device *dev) | ||
767 | { | ||
768 | struct ip6_tnl *t = netdev_priv(dev); | ||
769 | int err = vti6_dev_init_gen(dev); | ||
770 | |||
771 | if (err) | ||
772 | return err; | ||
773 | vti6_link_config(t); | ||
774 | return 0; | ||
775 | } | ||
776 | |||
777 | /** | ||
778 | * vti6_fb_tnl_dev_init - initializer for fallback tunnel device | ||
779 | * @dev: fallback device | ||
780 | * | ||
781 | * Return: 0 | ||
782 | **/ | ||
783 | static int __net_init vti6_fb_tnl_dev_init(struct net_device *dev) | ||
784 | { | ||
785 | struct ip6_tnl *t = netdev_priv(dev); | ||
786 | struct net *net = dev_net(dev); | ||
787 | struct vti6_net *ip6n = net_generic(net, vti6_net_id); | ||
788 | int err = vti6_dev_init_gen(dev); | ||
789 | |||
790 | if (err) | ||
791 | return err; | ||
792 | |||
793 | t->parms.proto = IPPROTO_IPV6; | ||
794 | dev_hold(dev); | ||
795 | |||
796 | vti6_link_config(t); | ||
797 | |||
798 | rcu_assign_pointer(ip6n->tnls_wc[0], t); | ||
799 | return 0; | ||
800 | } | ||
801 | |||
802 | static int vti6_validate(struct nlattr *tb[], struct nlattr *data[]) | ||
803 | { | ||
804 | return 0; | ||
805 | } | ||
806 | |||
807 | static void vti6_netlink_parms(struct nlattr *data[], | ||
808 | struct __ip6_tnl_parm *parms) | ||
809 | { | ||
810 | memset(parms, 0, sizeof(*parms)); | ||
811 | |||
812 | if (!data) | ||
813 | return; | ||
814 | |||
815 | if (data[IFLA_VTI_LINK]) | ||
816 | parms->link = nla_get_u32(data[IFLA_VTI_LINK]); | ||
817 | |||
818 | if (data[IFLA_VTI_LOCAL]) | ||
819 | nla_memcpy(&parms->laddr, data[IFLA_VTI_LOCAL], | ||
820 | sizeof(struct in6_addr)); | ||
821 | |||
822 | if (data[IFLA_VTI_REMOTE]) | ||
823 | nla_memcpy(&parms->raddr, data[IFLA_VTI_REMOTE], | ||
824 | sizeof(struct in6_addr)); | ||
825 | |||
826 | if (data[IFLA_VTI_IKEY]) | ||
827 | parms->i_key = nla_get_be32(data[IFLA_VTI_IKEY]); | ||
828 | |||
829 | if (data[IFLA_VTI_OKEY]) | ||
830 | parms->o_key = nla_get_be32(data[IFLA_VTI_OKEY]); | ||
831 | } | ||
832 | |||
833 | static int vti6_newlink(struct net *src_net, struct net_device *dev, | ||
834 | struct nlattr *tb[], struct nlattr *data[]) | ||
835 | { | ||
836 | struct net *net = dev_net(dev); | ||
837 | struct ip6_tnl *nt; | ||
838 | |||
839 | nt = netdev_priv(dev); | ||
840 | vti6_netlink_parms(data, &nt->parms); | ||
841 | |||
842 | nt->parms.proto = IPPROTO_IPV6; | ||
843 | |||
844 | if (vti6_locate(net, &nt->parms, 0)) | ||
845 | return -EEXIST; | ||
846 | |||
847 | return vti6_tnl_create2(dev); | ||
848 | } | ||
849 | |||
850 | static int vti6_changelink(struct net_device *dev, struct nlattr *tb[], | ||
851 | struct nlattr *data[]) | ||
852 | { | ||
853 | struct ip6_tnl *t; | ||
854 | struct __ip6_tnl_parm p; | ||
855 | struct net *net = dev_net(dev); | ||
856 | struct vti6_net *ip6n = net_generic(net, vti6_net_id); | ||
857 | |||
858 | if (dev == ip6n->fb_tnl_dev) | ||
859 | return -EINVAL; | ||
860 | |||
861 | vti6_netlink_parms(data, &p); | ||
862 | |||
863 | t = vti6_locate(net, &p, 0); | ||
864 | |||
865 | if (t) { | ||
866 | if (t->dev != dev) | ||
867 | return -EEXIST; | ||
868 | } else | ||
869 | t = netdev_priv(dev); | ||
870 | |||
871 | return vti6_update(t, &p); | ||
872 | } | ||
873 | |||
874 | static size_t vti6_get_size(const struct net_device *dev) | ||
875 | { | ||
876 | return | ||
877 | /* IFLA_VTI_LINK */ | ||
878 | nla_total_size(4) + | ||
879 | /* IFLA_VTI_LOCAL */ | ||
880 | nla_total_size(sizeof(struct in6_addr)) + | ||
881 | /* IFLA_VTI_REMOTE */ | ||
882 | nla_total_size(sizeof(struct in6_addr)) + | ||
883 | /* IFLA_VTI_IKEY */ | ||
884 | nla_total_size(4) + | ||
885 | /* IFLA_VTI_OKEY */ | ||
886 | nla_total_size(4) + | ||
887 | 0; | ||
888 | } | ||
889 | |||
890 | static int vti6_fill_info(struct sk_buff *skb, const struct net_device *dev) | ||
891 | { | ||
892 | struct ip6_tnl *tunnel = netdev_priv(dev); | ||
893 | struct __ip6_tnl_parm *parm = &tunnel->parms; | ||
894 | |||
895 | if (nla_put_u32(skb, IFLA_VTI_LINK, parm->link) || | ||
896 | nla_put(skb, IFLA_VTI_LOCAL, sizeof(struct in6_addr), | ||
897 | &parm->laddr) || | ||
898 | nla_put(skb, IFLA_VTI_REMOTE, sizeof(struct in6_addr), | ||
899 | &parm->raddr) || | ||
900 | nla_put_be32(skb, IFLA_VTI_IKEY, parm->i_key) || | ||
901 | nla_put_be32(skb, IFLA_VTI_OKEY, parm->o_key)) | ||
902 | goto nla_put_failure; | ||
903 | return 0; | ||
904 | |||
905 | nla_put_failure: | ||
906 | return -EMSGSIZE; | ||
907 | } | ||
908 | |||
909 | static const struct nla_policy vti6_policy[IFLA_VTI_MAX + 1] = { | ||
910 | [IFLA_VTI_LINK] = { .type = NLA_U32 }, | ||
911 | [IFLA_VTI_LOCAL] = { .len = sizeof(struct in6_addr) }, | ||
912 | [IFLA_VTI_REMOTE] = { .len = sizeof(struct in6_addr) }, | ||
913 | [IFLA_VTI_IKEY] = { .type = NLA_U32 }, | ||
914 | [IFLA_VTI_OKEY] = { .type = NLA_U32 }, | ||
915 | }; | ||
916 | |||
917 | static struct rtnl_link_ops vti6_link_ops __read_mostly = { | ||
918 | .kind = "vti6", | ||
919 | .maxtype = IFLA_VTI_MAX, | ||
920 | .policy = vti6_policy, | ||
921 | .priv_size = sizeof(struct ip6_tnl), | ||
922 | .setup = vti6_dev_setup, | ||
923 | .validate = vti6_validate, | ||
924 | .newlink = vti6_newlink, | ||
925 | .changelink = vti6_changelink, | ||
926 | .get_size = vti6_get_size, | ||
927 | .fill_info = vti6_fill_info, | ||
928 | }; | ||
929 | |||
930 | static struct xfrm_tunnel_notifier vti6_handler __read_mostly = { | ||
931 | .handler = vti6_rcv, | ||
932 | .priority = 1, | ||
933 | }; | ||
934 | |||
935 | static void __net_exit vti6_destroy_tunnels(struct vti6_net *ip6n) | ||
936 | { | ||
937 | int h; | ||
938 | struct ip6_tnl *t; | ||
939 | LIST_HEAD(list); | ||
940 | |||
941 | for (h = 0; h < HASH_SIZE; h++) { | ||
942 | t = rtnl_dereference(ip6n->tnls_r_l[h]); | ||
943 | while (t != NULL) { | ||
944 | unregister_netdevice_queue(t->dev, &list); | ||
945 | t = rtnl_dereference(t->next); | ||
946 | } | ||
947 | } | ||
948 | |||
949 | t = rtnl_dereference(ip6n->tnls_wc[0]); | ||
950 | unregister_netdevice_queue(t->dev, &list); | ||
951 | unregister_netdevice_many(&list); | ||
952 | } | ||
953 | |||
954 | static int __net_init vti6_init_net(struct net *net) | ||
955 | { | ||
956 | struct vti6_net *ip6n = net_generic(net, vti6_net_id); | ||
957 | struct ip6_tnl *t = NULL; | ||
958 | int err; | ||
959 | |||
960 | ip6n->tnls[0] = ip6n->tnls_wc; | ||
961 | ip6n->tnls[1] = ip6n->tnls_r_l; | ||
962 | |||
963 | err = -ENOMEM; | ||
964 | ip6n->fb_tnl_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6_vti0", | ||
965 | vti6_dev_setup); | ||
966 | |||
967 | if (!ip6n->fb_tnl_dev) | ||
968 | goto err_alloc_dev; | ||
969 | dev_net_set(ip6n->fb_tnl_dev, net); | ||
970 | |||
971 | err = vti6_fb_tnl_dev_init(ip6n->fb_tnl_dev); | ||
972 | if (err < 0) | ||
973 | goto err_register; | ||
974 | |||
975 | err = register_netdev(ip6n->fb_tnl_dev); | ||
976 | if (err < 0) | ||
977 | goto err_register; | ||
978 | |||
979 | t = netdev_priv(ip6n->fb_tnl_dev); | ||
980 | |||
981 | strcpy(t->parms.name, ip6n->fb_tnl_dev->name); | ||
982 | return 0; | ||
983 | |||
984 | err_register: | ||
985 | vti6_dev_free(ip6n->fb_tnl_dev); | ||
986 | err_alloc_dev: | ||
987 | return err; | ||
988 | } | ||
989 | |||
990 | static void __net_exit vti6_exit_net(struct net *net) | ||
991 | { | ||
992 | struct vti6_net *ip6n = net_generic(net, vti6_net_id); | ||
993 | |||
994 | rtnl_lock(); | ||
995 | vti6_destroy_tunnels(ip6n); | ||
996 | rtnl_unlock(); | ||
997 | } | ||
998 | |||
999 | static struct pernet_operations vti6_net_ops = { | ||
1000 | .init = vti6_init_net, | ||
1001 | .exit = vti6_exit_net, | ||
1002 | .id = &vti6_net_id, | ||
1003 | .size = sizeof(struct vti6_net), | ||
1004 | }; | ||
1005 | |||
1006 | /** | ||
1007 | * vti6_tunnel_init - register protocol and reserve needed resources | ||
1008 | * | ||
1009 | * Return: 0 on success | ||
1010 | **/ | ||
1011 | static int __init vti6_tunnel_init(void) | ||
1012 | { | ||
1013 | int err; | ||
1014 | |||
1015 | err = register_pernet_device(&vti6_net_ops); | ||
1016 | if (err < 0) | ||
1017 | goto out_pernet; | ||
1018 | |||
1019 | err = xfrm6_mode_tunnel_input_register(&vti6_handler); | ||
1020 | if (err < 0) { | ||
1021 | pr_err("%s: can't register vti6\n", __func__); | ||
1022 | goto out; | ||
1023 | } | ||
1024 | err = rtnl_link_register(&vti6_link_ops); | ||
1025 | if (err < 0) | ||
1026 | goto rtnl_link_failed; | ||
1027 | |||
1028 | return 0; | ||
1029 | |||
1030 | rtnl_link_failed: | ||
1031 | xfrm6_mode_tunnel_input_deregister(&vti6_handler); | ||
1032 | out: | ||
1033 | unregister_pernet_device(&vti6_net_ops); | ||
1034 | out_pernet: | ||
1035 | return err; | ||
1036 | } | ||
1037 | |||
1038 | /** | ||
1039 | * vti6_tunnel_cleanup - free resources and unregister protocol | ||
1040 | **/ | ||
1041 | static void __exit vti6_tunnel_cleanup(void) | ||
1042 | { | ||
1043 | rtnl_link_unregister(&vti6_link_ops); | ||
1044 | if (xfrm6_mode_tunnel_input_deregister(&vti6_handler)) | ||
1045 | pr_info("%s: can't deregister vti6\n", __func__); | ||
1046 | |||
1047 | unregister_pernet_device(&vti6_net_ops); | ||
1048 | } | ||
1049 | |||
1050 | module_init(vti6_tunnel_init); | ||
1051 | module_exit(vti6_tunnel_cleanup); | ||
1052 | MODULE_LICENSE("GPL"); | ||
1053 | MODULE_ALIAS_RTNL_LINK("vti6"); | ||
1054 | MODULE_ALIAS_NETDEV("ip6_vti0"); | ||
1055 | MODULE_AUTHOR("Steffen Klassert"); | ||
1056 | MODULE_DESCRIPTION("IPv6 virtual tunnel interface"); | ||
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index d1e2e8ef29c5..1c6ce3119ff8 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
@@ -174,7 +174,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
174 | } | 174 | } |
175 | 175 | ||
176 | if (ipv6_only_sock(sk) || | 176 | if (ipv6_only_sock(sk) || |
177 | !ipv6_addr_v4mapped(&np->daddr)) { | 177 | !ipv6_addr_v4mapped(&sk->sk_v6_daddr)) { |
178 | retv = -EADDRNOTAVAIL; | 178 | retv = -EADDRNOTAVAIL; |
179 | break; | 179 | break; |
180 | } | 180 | } |
@@ -1011,7 +1011,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
1011 | struct in6_pktinfo src_info; | 1011 | struct in6_pktinfo src_info; |
1012 | src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif : | 1012 | src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif : |
1013 | np->sticky_pktinfo.ipi6_ifindex; | 1013 | np->sticky_pktinfo.ipi6_ifindex; |
1014 | src_info.ipi6_addr = np->mcast_oif ? np->daddr : np->sticky_pktinfo.ipi6_addr; | 1014 | src_info.ipi6_addr = np->mcast_oif ? sk->sk_v6_daddr : np->sticky_pktinfo.ipi6_addr; |
1015 | put_cmsg(&msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info); | 1015 | put_cmsg(&msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info); |
1016 | } | 1016 | } |
1017 | if (np->rxopt.bits.rxhlim) { | 1017 | if (np->rxopt.bits.rxhlim) { |
@@ -1026,7 +1026,8 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
1026 | struct in6_pktinfo src_info; | 1026 | struct in6_pktinfo src_info; |
1027 | src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif : | 1027 | src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif : |
1028 | np->sticky_pktinfo.ipi6_ifindex; | 1028 | np->sticky_pktinfo.ipi6_ifindex; |
1029 | src_info.ipi6_addr = np->mcast_oif ? np->daddr : np->sticky_pktinfo.ipi6_addr; | 1029 | src_info.ipi6_addr = np->mcast_oif ? sk->sk_v6_daddr : |
1030 | np->sticky_pktinfo.ipi6_addr; | ||
1030 | put_cmsg(&msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info); | 1031 | put_cmsg(&msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info); |
1031 | } | 1032 | } |
1032 | if (np->rxopt.bits.rxohlim) { | 1033 | if (np->rxopt.bits.rxohlim) { |
@@ -1211,6 +1212,34 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
1211 | val = np->sndflow; | 1212 | val = np->sndflow; |
1212 | break; | 1213 | break; |
1213 | 1214 | ||
1215 | case IPV6_FLOWLABEL_MGR: | ||
1216 | { | ||
1217 | struct in6_flowlabel_req freq; | ||
1218 | |||
1219 | if (len < sizeof(freq)) | ||
1220 | return -EINVAL; | ||
1221 | |||
1222 | if (copy_from_user(&freq, optval, sizeof(freq))) | ||
1223 | return -EFAULT; | ||
1224 | |||
1225 | if (freq.flr_action != IPV6_FL_A_GET) | ||
1226 | return -EINVAL; | ||
1227 | |||
1228 | len = sizeof(freq); | ||
1229 | memset(&freq, 0, sizeof(freq)); | ||
1230 | |||
1231 | val = ipv6_flowlabel_opt_get(sk, &freq); | ||
1232 | if (val < 0) | ||
1233 | return val; | ||
1234 | |||
1235 | if (put_user(len, optlen)) | ||
1236 | return -EFAULT; | ||
1237 | if (copy_to_user(optval, &freq, len)) | ||
1238 | return -EFAULT; | ||
1239 | |||
1240 | return 0; | ||
1241 | } | ||
1242 | |||
1214 | case IPV6_ADDR_PREFERENCES: | 1243 | case IPV6_ADDR_PREFERENCES: |
1215 | val = 0; | 1244 | val = 0; |
1216 | 1245 | ||
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index a7f842b29b67..7702f9e90a04 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig | |||
@@ -25,6 +25,19 @@ config NF_CONNTRACK_IPV6 | |||
25 | 25 | ||
26 | To compile it as a module, choose M here. If unsure, say N. | 26 | To compile it as a module, choose M here. If unsure, say N. |
27 | 27 | ||
28 | config NF_TABLES_IPV6 | ||
29 | depends on NF_TABLES | ||
30 | tristate "IPv6 nf_tables support" | ||
31 | |||
32 | config NFT_CHAIN_ROUTE_IPV6 | ||
33 | depends on NF_TABLES_IPV6 | ||
34 | tristate "IPv6 nf_tables route chain support" | ||
35 | |||
36 | config NFT_CHAIN_NAT_IPV6 | ||
37 | depends on NF_TABLES_IPV6 | ||
38 | depends on NF_NAT_IPV6 && NFT_NAT | ||
39 | tristate "IPv6 nf_tables nat chain support" | ||
40 | |||
28 | config IP6_NF_IPTABLES | 41 | config IP6_NF_IPTABLES |
29 | tristate "IP6 tables support (required for filtering)" | 42 | tristate "IP6 tables support (required for filtering)" |
30 | depends on INET && IPV6 | 43 | depends on INET && IPV6 |
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile index 2b53738f798c..d1b4928f34f7 100644 --- a/net/ipv6/netfilter/Makefile +++ b/net/ipv6/netfilter/Makefile | |||
@@ -23,6 +23,11 @@ obj-$(CONFIG_NF_NAT_IPV6) += nf_nat_ipv6.o | |||
23 | nf_defrag_ipv6-y := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o | 23 | nf_defrag_ipv6-y := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o |
24 | obj-$(CONFIG_NF_DEFRAG_IPV6) += nf_defrag_ipv6.o | 24 | obj-$(CONFIG_NF_DEFRAG_IPV6) += nf_defrag_ipv6.o |
25 | 25 | ||
26 | # nf_tables | ||
27 | obj-$(CONFIG_NF_TABLES_IPV6) += nf_tables_ipv6.o | ||
28 | obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV6) += nft_chain_route_ipv6.o | ||
29 | obj-$(CONFIG_NFT_CHAIN_NAT_IPV6) += nft_chain_nat_ipv6.o | ||
30 | |||
26 | # matches | 31 | # matches |
27 | obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o | 32 | obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o |
28 | obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o | 33 | obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o |
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index 56eef30ee5f6..da00a2ecde55 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c | |||
@@ -39,7 +39,7 @@ MODULE_DESCRIPTION("Xtables: packet \"rejection\" target for IPv6"); | |||
39 | MODULE_LICENSE("GPL"); | 39 | MODULE_LICENSE("GPL"); |
40 | 40 | ||
41 | /* Send RST reply */ | 41 | /* Send RST reply */ |
42 | static void send_reset(struct net *net, struct sk_buff *oldskb) | 42 | static void send_reset(struct net *net, struct sk_buff *oldskb, int hook) |
43 | { | 43 | { |
44 | struct sk_buff *nskb; | 44 | struct sk_buff *nskb; |
45 | struct tcphdr otcph, *tcph; | 45 | struct tcphdr otcph, *tcph; |
@@ -88,8 +88,7 @@ static void send_reset(struct net *net, struct sk_buff *oldskb) | |||
88 | } | 88 | } |
89 | 89 | ||
90 | /* Check checksum. */ | 90 | /* Check checksum. */ |
91 | if (csum_ipv6_magic(&oip6h->saddr, &oip6h->daddr, otcplen, IPPROTO_TCP, | 91 | if (nf_ip6_checksum(oldskb, hook, tcphoff, IPPROTO_TCP)) { |
92 | skb_checksum(oldskb, tcphoff, otcplen, 0))) { | ||
93 | pr_debug("TCP checksum is invalid\n"); | 92 | pr_debug("TCP checksum is invalid\n"); |
94 | return; | 93 | return; |
95 | } | 94 | } |
@@ -227,7 +226,7 @@ reject_tg6(struct sk_buff *skb, const struct xt_action_param *par) | |||
227 | /* Do nothing */ | 226 | /* Do nothing */ |
228 | break; | 227 | break; |
229 | case IP6T_TCP_RESET: | 228 | case IP6T_TCP_RESET: |
230 | send_reset(net, skb); | 229 | send_reset(net, skb, par->hooknum); |
231 | break; | 230 | break; |
232 | default: | 231 | default: |
233 | net_info_ratelimited("case %u not handled yet\n", reject->with); | 232 | net_info_ratelimited("case %u not handled yet\n", reject->with); |
diff --git a/net/ipv6/netfilter/ip6t_SYNPROXY.c b/net/ipv6/netfilter/ip6t_SYNPROXY.c index 2748b042da72..bf9f612c1bc2 100644 --- a/net/ipv6/netfilter/ip6t_SYNPROXY.c +++ b/net/ipv6/netfilter/ip6t_SYNPROXY.c | |||
@@ -312,7 +312,7 @@ synproxy_tg6(struct sk_buff *skb, const struct xt_action_param *par) | |||
312 | return XT_CONTINUE; | 312 | return XT_CONTINUE; |
313 | } | 313 | } |
314 | 314 | ||
315 | static unsigned int ipv6_synproxy_hook(unsigned int hooknum, | 315 | static unsigned int ipv6_synproxy_hook(const struct nf_hook_ops *ops, |
316 | struct sk_buff *skb, | 316 | struct sk_buff *skb, |
317 | const struct net_device *in, | 317 | const struct net_device *in, |
318 | const struct net_device *out, | 318 | const struct net_device *out, |
diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index 29b44b14c5ea..ca7f6c128086 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c | |||
@@ -32,13 +32,14 @@ static const struct xt_table packet_filter = { | |||
32 | 32 | ||
33 | /* The work comes in here from netfilter.c. */ | 33 | /* The work comes in here from netfilter.c. */ |
34 | static unsigned int | 34 | static unsigned int |
35 | ip6table_filter_hook(unsigned int hook, struct sk_buff *skb, | 35 | ip6table_filter_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, |
36 | const struct net_device *in, const struct net_device *out, | 36 | const struct net_device *in, const struct net_device *out, |
37 | int (*okfn)(struct sk_buff *)) | 37 | int (*okfn)(struct sk_buff *)) |
38 | { | 38 | { |
39 | const struct net *net = dev_net((in != NULL) ? in : out); | 39 | const struct net *net = dev_net((in != NULL) ? in : out); |
40 | 40 | ||
41 | return ip6t_do_table(skb, hook, in, out, net->ipv6.ip6table_filter); | 41 | return ip6t_do_table(skb, ops->hooknum, in, out, |
42 | net->ipv6.ip6table_filter); | ||
42 | } | 43 | } |
43 | 44 | ||
44 | static struct nf_hook_ops *filter_ops __read_mostly; | 45 | static struct nf_hook_ops *filter_ops __read_mostly; |
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index c705907ae6ab..307bbb782d14 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c | |||
@@ -76,17 +76,17 @@ ip6t_mangle_out(struct sk_buff *skb, const struct net_device *out) | |||
76 | 76 | ||
77 | /* The work comes in here from netfilter.c. */ | 77 | /* The work comes in here from netfilter.c. */ |
78 | static unsigned int | 78 | static unsigned int |
79 | ip6table_mangle_hook(unsigned int hook, struct sk_buff *skb, | 79 | ip6table_mangle_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, |
80 | const struct net_device *in, const struct net_device *out, | 80 | const struct net_device *in, const struct net_device *out, |
81 | int (*okfn)(struct sk_buff *)) | 81 | int (*okfn)(struct sk_buff *)) |
82 | { | 82 | { |
83 | if (hook == NF_INET_LOCAL_OUT) | 83 | if (ops->hooknum == NF_INET_LOCAL_OUT) |
84 | return ip6t_mangle_out(skb, out); | 84 | return ip6t_mangle_out(skb, out); |
85 | if (hook == NF_INET_POST_ROUTING) | 85 | if (ops->hooknum == NF_INET_POST_ROUTING) |
86 | return ip6t_do_table(skb, hook, in, out, | 86 | return ip6t_do_table(skb, ops->hooknum, in, out, |
87 | dev_net(out)->ipv6.ip6table_mangle); | 87 | dev_net(out)->ipv6.ip6table_mangle); |
88 | /* INPUT/FORWARD */ | 88 | /* INPUT/FORWARD */ |
89 | return ip6t_do_table(skb, hook, in, out, | 89 | return ip6t_do_table(skb, ops->hooknum, in, out, |
90 | dev_net(in)->ipv6.ip6table_mangle); | 90 | dev_net(in)->ipv6.ip6table_mangle); |
91 | } | 91 | } |
92 | 92 | ||
diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c index 9b076d2d3a7b..84c7f33d0cf8 100644 --- a/net/ipv6/netfilter/ip6table_nat.c +++ b/net/ipv6/netfilter/ip6table_nat.c | |||
@@ -63,7 +63,7 @@ static unsigned int nf_nat_rule_find(struct sk_buff *skb, unsigned int hooknum, | |||
63 | } | 63 | } |
64 | 64 | ||
65 | static unsigned int | 65 | static unsigned int |
66 | nf_nat_ipv6_fn(unsigned int hooknum, | 66 | nf_nat_ipv6_fn(const struct nf_hook_ops *ops, |
67 | struct sk_buff *skb, | 67 | struct sk_buff *skb, |
68 | const struct net_device *in, | 68 | const struct net_device *in, |
69 | const struct net_device *out, | 69 | const struct net_device *out, |
@@ -72,7 +72,7 @@ nf_nat_ipv6_fn(unsigned int hooknum, | |||
72 | struct nf_conn *ct; | 72 | struct nf_conn *ct; |
73 | enum ip_conntrack_info ctinfo; | 73 | enum ip_conntrack_info ctinfo; |
74 | struct nf_conn_nat *nat; | 74 | struct nf_conn_nat *nat; |
75 | enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum); | 75 | enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum); |
76 | __be16 frag_off; | 76 | __be16 frag_off; |
77 | int hdrlen; | 77 | int hdrlen; |
78 | u8 nexthdr; | 78 | u8 nexthdr; |
@@ -111,7 +111,8 @@ nf_nat_ipv6_fn(unsigned int hooknum, | |||
111 | 111 | ||
112 | if (hdrlen >= 0 && nexthdr == IPPROTO_ICMPV6) { | 112 | if (hdrlen >= 0 && nexthdr == IPPROTO_ICMPV6) { |
113 | if (!nf_nat_icmpv6_reply_translation(skb, ct, ctinfo, | 113 | if (!nf_nat_icmpv6_reply_translation(skb, ct, ctinfo, |
114 | hooknum, hdrlen)) | 114 | ops->hooknum, |
115 | hdrlen)) | ||
115 | return NF_DROP; | 116 | return NF_DROP; |
116 | else | 117 | else |
117 | return NF_ACCEPT; | 118 | return NF_ACCEPT; |
@@ -124,14 +125,14 @@ nf_nat_ipv6_fn(unsigned int hooknum, | |||
124 | if (!nf_nat_initialized(ct, maniptype)) { | 125 | if (!nf_nat_initialized(ct, maniptype)) { |
125 | unsigned int ret; | 126 | unsigned int ret; |
126 | 127 | ||
127 | ret = nf_nat_rule_find(skb, hooknum, in, out, ct); | 128 | ret = nf_nat_rule_find(skb, ops->hooknum, in, out, ct); |
128 | if (ret != NF_ACCEPT) | 129 | if (ret != NF_ACCEPT) |
129 | return ret; | 130 | return ret; |
130 | } else { | 131 | } else { |
131 | pr_debug("Already setup manip %s for ct %p\n", | 132 | pr_debug("Already setup manip %s for ct %p\n", |
132 | maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST", | 133 | maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST", |
133 | ct); | 134 | ct); |
134 | if (nf_nat_oif_changed(hooknum, ctinfo, nat, out)) | 135 | if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out)) |
135 | goto oif_changed; | 136 | goto oif_changed; |
136 | } | 137 | } |
137 | break; | 138 | break; |
@@ -140,11 +141,11 @@ nf_nat_ipv6_fn(unsigned int hooknum, | |||
140 | /* ESTABLISHED */ | 141 | /* ESTABLISHED */ |
141 | NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || | 142 | NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || |
142 | ctinfo == IP_CT_ESTABLISHED_REPLY); | 143 | ctinfo == IP_CT_ESTABLISHED_REPLY); |
143 | if (nf_nat_oif_changed(hooknum, ctinfo, nat, out)) | 144 | if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out)) |
144 | goto oif_changed; | 145 | goto oif_changed; |
145 | } | 146 | } |
146 | 147 | ||
147 | return nf_nat_packet(ct, ctinfo, hooknum, skb); | 148 | return nf_nat_packet(ct, ctinfo, ops->hooknum, skb); |
148 | 149 | ||
149 | oif_changed: | 150 | oif_changed: |
150 | nf_ct_kill_acct(ct, ctinfo, skb); | 151 | nf_ct_kill_acct(ct, ctinfo, skb); |
@@ -152,7 +153,7 @@ oif_changed: | |||
152 | } | 153 | } |
153 | 154 | ||
154 | static unsigned int | 155 | static unsigned int |
155 | nf_nat_ipv6_in(unsigned int hooknum, | 156 | nf_nat_ipv6_in(const struct nf_hook_ops *ops, |
156 | struct sk_buff *skb, | 157 | struct sk_buff *skb, |
157 | const struct net_device *in, | 158 | const struct net_device *in, |
158 | const struct net_device *out, | 159 | const struct net_device *out, |
@@ -161,7 +162,7 @@ nf_nat_ipv6_in(unsigned int hooknum, | |||
161 | unsigned int ret; | 162 | unsigned int ret; |
162 | struct in6_addr daddr = ipv6_hdr(skb)->daddr; | 163 | struct in6_addr daddr = ipv6_hdr(skb)->daddr; |
163 | 164 | ||
164 | ret = nf_nat_ipv6_fn(hooknum, skb, in, out, okfn); | 165 | ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn); |
165 | if (ret != NF_DROP && ret != NF_STOLEN && | 166 | if (ret != NF_DROP && ret != NF_STOLEN && |
166 | ipv6_addr_cmp(&daddr, &ipv6_hdr(skb)->daddr)) | 167 | ipv6_addr_cmp(&daddr, &ipv6_hdr(skb)->daddr)) |
167 | skb_dst_drop(skb); | 168 | skb_dst_drop(skb); |
@@ -170,7 +171,7 @@ nf_nat_ipv6_in(unsigned int hooknum, | |||
170 | } | 171 | } |
171 | 172 | ||
172 | static unsigned int | 173 | static unsigned int |
173 | nf_nat_ipv6_out(unsigned int hooknum, | 174 | nf_nat_ipv6_out(const struct nf_hook_ops *ops, |
174 | struct sk_buff *skb, | 175 | struct sk_buff *skb, |
175 | const struct net_device *in, | 176 | const struct net_device *in, |
176 | const struct net_device *out, | 177 | const struct net_device *out, |
@@ -187,7 +188,7 @@ nf_nat_ipv6_out(unsigned int hooknum, | |||
187 | if (skb->len < sizeof(struct ipv6hdr)) | 188 | if (skb->len < sizeof(struct ipv6hdr)) |
188 | return NF_ACCEPT; | 189 | return NF_ACCEPT; |
189 | 190 | ||
190 | ret = nf_nat_ipv6_fn(hooknum, skb, in, out, okfn); | 191 | ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn); |
191 | #ifdef CONFIG_XFRM | 192 | #ifdef CONFIG_XFRM |
192 | if (ret != NF_DROP && ret != NF_STOLEN && | 193 | if (ret != NF_DROP && ret != NF_STOLEN && |
193 | !(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && | 194 | !(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && |
@@ -209,7 +210,7 @@ nf_nat_ipv6_out(unsigned int hooknum, | |||
209 | } | 210 | } |
210 | 211 | ||
211 | static unsigned int | 212 | static unsigned int |
212 | nf_nat_ipv6_local_fn(unsigned int hooknum, | 213 | nf_nat_ipv6_local_fn(const struct nf_hook_ops *ops, |
213 | struct sk_buff *skb, | 214 | struct sk_buff *skb, |
214 | const struct net_device *in, | 215 | const struct net_device *in, |
215 | const struct net_device *out, | 216 | const struct net_device *out, |
@@ -224,7 +225,7 @@ nf_nat_ipv6_local_fn(unsigned int hooknum, | |||
224 | if (skb->len < sizeof(struct ipv6hdr)) | 225 | if (skb->len < sizeof(struct ipv6hdr)) |
225 | return NF_ACCEPT; | 226 | return NF_ACCEPT; |
226 | 227 | ||
227 | ret = nf_nat_ipv6_fn(hooknum, skb, in, out, okfn); | 228 | ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn); |
228 | if (ret != NF_DROP && ret != NF_STOLEN && | 229 | if (ret != NF_DROP && ret != NF_STOLEN && |
229 | (ct = nf_ct_get(skb, &ctinfo)) != NULL) { | 230 | (ct = nf_ct_get(skb, &ctinfo)) != NULL) { |
230 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | 231 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c index 9a626d86720f..5274740acecc 100644 --- a/net/ipv6/netfilter/ip6table_raw.c +++ b/net/ipv6/netfilter/ip6table_raw.c | |||
@@ -19,13 +19,14 @@ static const struct xt_table packet_raw = { | |||
19 | 19 | ||
20 | /* The work comes in here from netfilter.c. */ | 20 | /* The work comes in here from netfilter.c. */ |
21 | static unsigned int | 21 | static unsigned int |
22 | ip6table_raw_hook(unsigned int hook, struct sk_buff *skb, | 22 | ip6table_raw_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, |
23 | const struct net_device *in, const struct net_device *out, | 23 | const struct net_device *in, const struct net_device *out, |
24 | int (*okfn)(struct sk_buff *)) | 24 | int (*okfn)(struct sk_buff *)) |
25 | { | 25 | { |
26 | const struct net *net = dev_net((in != NULL) ? in : out); | 26 | const struct net *net = dev_net((in != NULL) ? in : out); |
27 | 27 | ||
28 | return ip6t_do_table(skb, hook, in, out, net->ipv6.ip6table_raw); | 28 | return ip6t_do_table(skb, ops->hooknum, in, out, |
29 | net->ipv6.ip6table_raw); | ||
29 | } | 30 | } |
30 | 31 | ||
31 | static struct nf_hook_ops *rawtable_ops __read_mostly; | 32 | static struct nf_hook_ops *rawtable_ops __read_mostly; |
diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c index ce88d1d7e525..ab3b0219ecfa 100644 --- a/net/ipv6/netfilter/ip6table_security.c +++ b/net/ipv6/netfilter/ip6table_security.c | |||
@@ -36,14 +36,15 @@ static const struct xt_table security_table = { | |||
36 | }; | 36 | }; |
37 | 37 | ||
38 | static unsigned int | 38 | static unsigned int |
39 | ip6table_security_hook(unsigned int hook, struct sk_buff *skb, | 39 | ip6table_security_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, |
40 | const struct net_device *in, | 40 | const struct net_device *in, |
41 | const struct net_device *out, | 41 | const struct net_device *out, |
42 | int (*okfn)(struct sk_buff *)) | 42 | int (*okfn)(struct sk_buff *)) |
43 | { | 43 | { |
44 | const struct net *net = dev_net((in != NULL) ? in : out); | 44 | const struct net *net = dev_net((in != NULL) ? in : out); |
45 | 45 | ||
46 | return ip6t_do_table(skb, hook, in, out, net->ipv6.ip6table_security); | 46 | return ip6t_do_table(skb, ops->hooknum, in, out, |
47 | net->ipv6.ip6table_security); | ||
47 | } | 48 | } |
48 | 49 | ||
49 | static struct nf_hook_ops *sectbl_ops __read_mostly; | 50 | static struct nf_hook_ops *sectbl_ops __read_mostly; |
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index d6e4dd8b58df..4cbc6b290dd5 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | |||
@@ -95,7 +95,7 @@ static int ipv6_get_l4proto(const struct sk_buff *skb, unsigned int nhoff, | |||
95 | return NF_ACCEPT; | 95 | return NF_ACCEPT; |
96 | } | 96 | } |
97 | 97 | ||
98 | static unsigned int ipv6_helper(unsigned int hooknum, | 98 | static unsigned int ipv6_helper(const struct nf_hook_ops *ops, |
99 | struct sk_buff *skb, | 99 | struct sk_buff *skb, |
100 | const struct net_device *in, | 100 | const struct net_device *in, |
101 | const struct net_device *out, | 101 | const struct net_device *out, |
@@ -133,7 +133,7 @@ static unsigned int ipv6_helper(unsigned int hooknum, | |||
133 | return helper->help(skb, protoff, ct, ctinfo); | 133 | return helper->help(skb, protoff, ct, ctinfo); |
134 | } | 134 | } |
135 | 135 | ||
136 | static unsigned int ipv6_confirm(unsigned int hooknum, | 136 | static unsigned int ipv6_confirm(const struct nf_hook_ops *ops, |
137 | struct sk_buff *skb, | 137 | struct sk_buff *skb, |
138 | const struct net_device *in, | 138 | const struct net_device *in, |
139 | const struct net_device *out, | 139 | const struct net_device *out, |
@@ -169,66 +169,16 @@ out: | |||
169 | return nf_conntrack_confirm(skb); | 169 | return nf_conntrack_confirm(skb); |
170 | } | 170 | } |
171 | 171 | ||
172 | static unsigned int __ipv6_conntrack_in(struct net *net, | 172 | static unsigned int ipv6_conntrack_in(const struct nf_hook_ops *ops, |
173 | unsigned int hooknum, | ||
174 | struct sk_buff *skb, | ||
175 | const struct net_device *in, | ||
176 | const struct net_device *out, | ||
177 | int (*okfn)(struct sk_buff *)) | ||
178 | { | ||
179 | struct sk_buff *reasm = skb->nfct_reasm; | ||
180 | const struct nf_conn_help *help; | ||
181 | struct nf_conn *ct; | ||
182 | enum ip_conntrack_info ctinfo; | ||
183 | |||
184 | /* This packet is fragmented and has reassembled packet. */ | ||
185 | if (reasm) { | ||
186 | /* Reassembled packet isn't parsed yet ? */ | ||
187 | if (!reasm->nfct) { | ||
188 | unsigned int ret; | ||
189 | |||
190 | ret = nf_conntrack_in(net, PF_INET6, hooknum, reasm); | ||
191 | if (ret != NF_ACCEPT) | ||
192 | return ret; | ||
193 | } | ||
194 | |||
195 | /* Conntrack helpers need the entire reassembled packet in the | ||
196 | * POST_ROUTING hook. In case of unconfirmed connections NAT | ||
197 | * might reassign a helper, so the entire packet is also | ||
198 | * required. | ||
199 | */ | ||
200 | ct = nf_ct_get(reasm, &ctinfo); | ||
201 | if (ct != NULL && !nf_ct_is_untracked(ct)) { | ||
202 | help = nfct_help(ct); | ||
203 | if ((help && help->helper) || !nf_ct_is_confirmed(ct)) { | ||
204 | nf_conntrack_get_reasm(reasm); | ||
205 | NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, reasm, | ||
206 | (struct net_device *)in, | ||
207 | (struct net_device *)out, | ||
208 | okfn, NF_IP6_PRI_CONNTRACK + 1); | ||
209 | return NF_DROP_ERR(-ECANCELED); | ||
210 | } | ||
211 | } | ||
212 | |||
213 | nf_conntrack_get(reasm->nfct); | ||
214 | skb->nfct = reasm->nfct; | ||
215 | skb->nfctinfo = reasm->nfctinfo; | ||
216 | return NF_ACCEPT; | ||
217 | } | ||
218 | |||
219 | return nf_conntrack_in(net, PF_INET6, hooknum, skb); | ||
220 | } | ||
221 | |||
222 | static unsigned int ipv6_conntrack_in(unsigned int hooknum, | ||
223 | struct sk_buff *skb, | 173 | struct sk_buff *skb, |
224 | const struct net_device *in, | 174 | const struct net_device *in, |
225 | const struct net_device *out, | 175 | const struct net_device *out, |
226 | int (*okfn)(struct sk_buff *)) | 176 | int (*okfn)(struct sk_buff *)) |
227 | { | 177 | { |
228 | return __ipv6_conntrack_in(dev_net(in), hooknum, skb, in, out, okfn); | 178 | return nf_conntrack_in(dev_net(in), PF_INET6, ops->hooknum, skb); |
229 | } | 179 | } |
230 | 180 | ||
231 | static unsigned int ipv6_conntrack_local(unsigned int hooknum, | 181 | static unsigned int ipv6_conntrack_local(const struct nf_hook_ops *ops, |
232 | struct sk_buff *skb, | 182 | struct sk_buff *skb, |
233 | const struct net_device *in, | 183 | const struct net_device *in, |
234 | const struct net_device *out, | 184 | const struct net_device *out, |
@@ -239,7 +189,7 @@ static unsigned int ipv6_conntrack_local(unsigned int hooknum, | |||
239 | net_notice_ratelimited("ipv6_conntrack_local: packet too short\n"); | 189 | net_notice_ratelimited("ipv6_conntrack_local: packet too short\n"); |
240 | return NF_ACCEPT; | 190 | return NF_ACCEPT; |
241 | } | 191 | } |
242 | return __ipv6_conntrack_in(dev_net(out), hooknum, skb, in, out, okfn); | 192 | return nf_conntrack_in(dev_net(out), PF_INET6, ops->hooknum, skb); |
243 | } | 193 | } |
244 | 194 | ||
245 | static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = { | 195 | static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = { |
@@ -297,9 +247,9 @@ ipv6_getorigdst(struct sock *sk, int optval, void __user *user, int *len) | |||
297 | struct nf_conntrack_tuple tuple = { .src.l3num = NFPROTO_IPV6 }; | 247 | struct nf_conntrack_tuple tuple = { .src.l3num = NFPROTO_IPV6 }; |
298 | struct nf_conn *ct; | 248 | struct nf_conn *ct; |
299 | 249 | ||
300 | tuple.src.u3.in6 = inet6->rcv_saddr; | 250 | tuple.src.u3.in6 = sk->sk_v6_rcv_saddr; |
301 | tuple.src.u.tcp.port = inet->inet_sport; | 251 | tuple.src.u.tcp.port = inet->inet_sport; |
302 | tuple.dst.u3.in6 = inet6->daddr; | 252 | tuple.dst.u3.in6 = sk->sk_v6_daddr; |
303 | tuple.dst.u.tcp.port = inet->inet_dport; | 253 | tuple.dst.u.tcp.port = inet->inet_dport; |
304 | tuple.dst.protonum = sk->sk_protocol; | 254 | tuple.dst.protonum = sk->sk_protocol; |
305 | 255 | ||
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index dffdc1a389c5..767ab8da8218 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c | |||
@@ -144,12 +144,24 @@ static inline u8 ip6_frag_ecn(const struct ipv6hdr *ipv6h) | |||
144 | return 1 << (ipv6_get_dsfield(ipv6h) & INET_ECN_MASK); | 144 | return 1 << (ipv6_get_dsfield(ipv6h) & INET_ECN_MASK); |
145 | } | 145 | } |
146 | 146 | ||
147 | static unsigned int nf_hash_frag(__be32 id, const struct in6_addr *saddr, | ||
148 | const struct in6_addr *daddr) | ||
149 | { | ||
150 | u32 c; | ||
151 | |||
152 | net_get_random_once(&nf_frags.rnd, sizeof(nf_frags.rnd)); | ||
153 | c = jhash_3words(ipv6_addr_hash(saddr), ipv6_addr_hash(daddr), | ||
154 | (__force u32)id, nf_frags.rnd); | ||
155 | return c & (INETFRAGS_HASHSZ - 1); | ||
156 | } | ||
157 | |||
158 | |||
147 | static unsigned int nf_hashfn(struct inet_frag_queue *q) | 159 | static unsigned int nf_hashfn(struct inet_frag_queue *q) |
148 | { | 160 | { |
149 | const struct frag_queue *nq; | 161 | const struct frag_queue *nq; |
150 | 162 | ||
151 | nq = container_of(q, struct frag_queue, q); | 163 | nq = container_of(q, struct frag_queue, q); |
152 | return inet6_hash_frag(nq->id, &nq->saddr, &nq->daddr, nf_frags.rnd); | 164 | return nf_hash_frag(nq->id, &nq->saddr, &nq->daddr); |
153 | } | 165 | } |
154 | 166 | ||
155 | static void nf_skb_free(struct sk_buff *skb) | 167 | static void nf_skb_free(struct sk_buff *skb) |
@@ -185,7 +197,7 @@ static inline struct frag_queue *fq_find(struct net *net, __be32 id, | |||
185 | arg.ecn = ecn; | 197 | arg.ecn = ecn; |
186 | 198 | ||
187 | read_lock_bh(&nf_frags.lock); | 199 | read_lock_bh(&nf_frags.lock); |
188 | hash = inet6_hash_frag(id, src, dst, nf_frags.rnd); | 200 | hash = nf_hash_frag(id, src, dst); |
189 | 201 | ||
190 | q = inet_frag_find(&net->nf_frag.frags, &nf_frags, &arg, hash); | 202 | q = inet_frag_find(&net->nf_frag.frags, &nf_frags, &arg, hash); |
191 | local_bh_enable(); | 203 | local_bh_enable(); |
@@ -621,31 +633,16 @@ ret_orig: | |||
621 | return skb; | 633 | return skb; |
622 | } | 634 | } |
623 | 635 | ||
624 | void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb, | 636 | void nf_ct_frag6_consume_orig(struct sk_buff *skb) |
625 | struct net_device *in, struct net_device *out, | ||
626 | int (*okfn)(struct sk_buff *)) | ||
627 | { | 637 | { |
628 | struct sk_buff *s, *s2; | 638 | struct sk_buff *s, *s2; |
629 | unsigned int ret = 0; | ||
630 | 639 | ||
631 | for (s = NFCT_FRAG6_CB(skb)->orig; s;) { | 640 | for (s = NFCT_FRAG6_CB(skb)->orig; s;) { |
632 | nf_conntrack_put_reasm(s->nfct_reasm); | ||
633 | nf_conntrack_get_reasm(skb); | ||
634 | s->nfct_reasm = skb; | ||
635 | |||
636 | s2 = s->next; | 641 | s2 = s->next; |
637 | s->next = NULL; | 642 | s->next = NULL; |
638 | 643 | consume_skb(s); | |
639 | if (ret != -ECANCELED) | ||
640 | ret = NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, s, | ||
641 | in, out, okfn, | ||
642 | NF_IP6_PRI_CONNTRACK_DEFRAG + 1); | ||
643 | else | ||
644 | kfree_skb(s); | ||
645 | |||
646 | s = s2; | 644 | s = s2; |
647 | } | 645 | } |
648 | nf_conntrack_put_reasm(skb); | ||
649 | } | 646 | } |
650 | 647 | ||
651 | static int nf_ct_net_init(struct net *net) | 648 | static int nf_ct_net_init(struct net *net) |
diff --git a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c index aacd121fe8c5..7b9a748c6bac 100644 --- a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c +++ b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c | |||
@@ -52,7 +52,7 @@ static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum, | |||
52 | 52 | ||
53 | } | 53 | } |
54 | 54 | ||
55 | static unsigned int ipv6_defrag(unsigned int hooknum, | 55 | static unsigned int ipv6_defrag(const struct nf_hook_ops *ops, |
56 | struct sk_buff *skb, | 56 | struct sk_buff *skb, |
57 | const struct net_device *in, | 57 | const struct net_device *in, |
58 | const struct net_device *out, | 58 | const struct net_device *out, |
@@ -66,7 +66,7 @@ static unsigned int ipv6_defrag(unsigned int hooknum, | |||
66 | return NF_ACCEPT; | 66 | return NF_ACCEPT; |
67 | #endif | 67 | #endif |
68 | 68 | ||
69 | reasm = nf_ct_frag6_gather(skb, nf_ct6_defrag_user(hooknum, skb)); | 69 | reasm = nf_ct_frag6_gather(skb, nf_ct6_defrag_user(ops->hooknum, skb)); |
70 | /* queued */ | 70 | /* queued */ |
71 | if (reasm == NULL) | 71 | if (reasm == NULL) |
72 | return NF_STOLEN; | 72 | return NF_STOLEN; |
@@ -75,8 +75,11 @@ static unsigned int ipv6_defrag(unsigned int hooknum, | |||
75 | if (reasm == skb) | 75 | if (reasm == skb) |
76 | return NF_ACCEPT; | 76 | return NF_ACCEPT; |
77 | 77 | ||
78 | nf_ct_frag6_output(hooknum, reasm, (struct net_device *)in, | 78 | nf_ct_frag6_consume_orig(reasm); |
79 | (struct net_device *)out, okfn); | 79 | |
80 | NF_HOOK_THRESH(NFPROTO_IPV6, ops->hooknum, reasm, | ||
81 | (struct net_device *) in, (struct net_device *) out, | ||
82 | okfn, NF_IP6_PRI_CONNTRACK_DEFRAG + 1); | ||
80 | 83 | ||
81 | return NF_STOLEN; | 84 | return NF_STOLEN; |
82 | } | 85 | } |
diff --git a/net/ipv6/netfilter/nf_tables_ipv6.c b/net/ipv6/netfilter/nf_tables_ipv6.c new file mode 100644 index 000000000000..d77db8a13505 --- /dev/null +++ b/net/ipv6/netfilter/nf_tables_ipv6.c | |||
@@ -0,0 +1,127 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2008 Patrick McHardy <kaber@trash.net> | ||
3 | * Copyright (c) 2012-2013 Pablo Neira Ayuso <pablo@netfilter.org> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * Development of this code funded by Astaro AG (http://www.astaro.com/) | ||
10 | */ | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/ipv6.h> | ||
15 | #include <linux/netfilter_ipv6.h> | ||
16 | #include <net/netfilter/nf_tables.h> | ||
17 | #include <net/netfilter/nf_tables_ipv6.h> | ||
18 | |||
19 | static unsigned int nft_ipv6_output(const struct nf_hook_ops *ops, | ||
20 | struct sk_buff *skb, | ||
21 | const struct net_device *in, | ||
22 | const struct net_device *out, | ||
23 | int (*okfn)(struct sk_buff *)) | ||
24 | { | ||
25 | struct nft_pktinfo pkt; | ||
26 | |||
27 | if (unlikely(skb->len < sizeof(struct ipv6hdr))) { | ||
28 | if (net_ratelimit()) | ||
29 | pr_info("nf_tables_ipv6: ignoring short SOCK_RAW " | ||
30 | "packet\n"); | ||
31 | return NF_ACCEPT; | ||
32 | } | ||
33 | if (nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out) < 0) | ||
34 | return NF_DROP; | ||
35 | |||
36 | return nft_do_chain_pktinfo(&pkt, ops); | ||
37 | } | ||
38 | |||
39 | static struct nft_af_info nft_af_ipv6 __read_mostly = { | ||
40 | .family = NFPROTO_IPV6, | ||
41 | .nhooks = NF_INET_NUMHOOKS, | ||
42 | .owner = THIS_MODULE, | ||
43 | .hooks = { | ||
44 | [NF_INET_LOCAL_OUT] = nft_ipv6_output, | ||
45 | }, | ||
46 | }; | ||
47 | |||
48 | static int nf_tables_ipv6_init_net(struct net *net) | ||
49 | { | ||
50 | net->nft.ipv6 = kmalloc(sizeof(struct nft_af_info), GFP_KERNEL); | ||
51 | if (net->nft.ipv6 == NULL) | ||
52 | return -ENOMEM; | ||
53 | |||
54 | memcpy(net->nft.ipv6, &nft_af_ipv6, sizeof(nft_af_ipv6)); | ||
55 | |||
56 | if (nft_register_afinfo(net, net->nft.ipv6) < 0) | ||
57 | goto err; | ||
58 | |||
59 | return 0; | ||
60 | err: | ||
61 | kfree(net->nft.ipv6); | ||
62 | return -ENOMEM; | ||
63 | } | ||
64 | |||
65 | static void nf_tables_ipv6_exit_net(struct net *net) | ||
66 | { | ||
67 | nft_unregister_afinfo(net->nft.ipv6); | ||
68 | kfree(net->nft.ipv6); | ||
69 | } | ||
70 | |||
71 | static struct pernet_operations nf_tables_ipv6_net_ops = { | ||
72 | .init = nf_tables_ipv6_init_net, | ||
73 | .exit = nf_tables_ipv6_exit_net, | ||
74 | }; | ||
75 | |||
76 | static unsigned int | ||
77 | nft_do_chain_ipv6(const struct nf_hook_ops *ops, | ||
78 | struct sk_buff *skb, | ||
79 | const struct net_device *in, | ||
80 | const struct net_device *out, | ||
81 | int (*okfn)(struct sk_buff *)) | ||
82 | { | ||
83 | struct nft_pktinfo pkt; | ||
84 | |||
85 | /* malformed packet, drop it */ | ||
86 | if (nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out) < 0) | ||
87 | return NF_DROP; | ||
88 | |||
89 | return nft_do_chain_pktinfo(&pkt, ops); | ||
90 | } | ||
91 | |||
92 | static struct nf_chain_type filter_ipv6 = { | ||
93 | .family = NFPROTO_IPV6, | ||
94 | .name = "filter", | ||
95 | .type = NFT_CHAIN_T_DEFAULT, | ||
96 | .hook_mask = (1 << NF_INET_LOCAL_IN) | | ||
97 | (1 << NF_INET_LOCAL_OUT) | | ||
98 | (1 << NF_INET_FORWARD) | | ||
99 | (1 << NF_INET_PRE_ROUTING) | | ||
100 | (1 << NF_INET_POST_ROUTING), | ||
101 | .fn = { | ||
102 | [NF_INET_LOCAL_IN] = nft_do_chain_ipv6, | ||
103 | [NF_INET_LOCAL_OUT] = nft_ipv6_output, | ||
104 | [NF_INET_FORWARD] = nft_do_chain_ipv6, | ||
105 | [NF_INET_PRE_ROUTING] = nft_do_chain_ipv6, | ||
106 | [NF_INET_POST_ROUTING] = nft_do_chain_ipv6, | ||
107 | }, | ||
108 | }; | ||
109 | |||
110 | static int __init nf_tables_ipv6_init(void) | ||
111 | { | ||
112 | nft_register_chain_type(&filter_ipv6); | ||
113 | return register_pernet_subsys(&nf_tables_ipv6_net_ops); | ||
114 | } | ||
115 | |||
116 | static void __exit nf_tables_ipv6_exit(void) | ||
117 | { | ||
118 | unregister_pernet_subsys(&nf_tables_ipv6_net_ops); | ||
119 | nft_unregister_chain_type(&filter_ipv6); | ||
120 | } | ||
121 | |||
122 | module_init(nf_tables_ipv6_init); | ||
123 | module_exit(nf_tables_ipv6_exit); | ||
124 | |||
125 | MODULE_LICENSE("GPL"); | ||
126 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); | ||
127 | MODULE_ALIAS_NFT_FAMILY(AF_INET6); | ||
diff --git a/net/ipv6/netfilter/nft_chain_nat_ipv6.c b/net/ipv6/netfilter/nft_chain_nat_ipv6.c new file mode 100644 index 000000000000..e86dcd70dc76 --- /dev/null +++ b/net/ipv6/netfilter/nft_chain_nat_ipv6.c | |||
@@ -0,0 +1,211 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2011 Patrick McHardy <kaber@trash.net> | ||
3 | * Copyright (c) 2012 Intel Corporation | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/list.h> | ||
14 | #include <linux/skbuff.h> | ||
15 | #include <linux/ip.h> | ||
16 | #include <linux/netfilter.h> | ||
17 | #include <linux/netfilter_ipv6.h> | ||
18 | #include <linux/netfilter/nf_tables.h> | ||
19 | #include <net/netfilter/nf_conntrack.h> | ||
20 | #include <net/netfilter/nf_nat.h> | ||
21 | #include <net/netfilter/nf_nat_core.h> | ||
22 | #include <net/netfilter/nf_tables.h> | ||
23 | #include <net/netfilter/nf_tables_ipv6.h> | ||
24 | #include <net/netfilter/nf_nat_l3proto.h> | ||
25 | #include <net/ipv6.h> | ||
26 | |||
27 | /* | ||
28 | * IPv6 NAT chains | ||
29 | */ | ||
30 | |||
31 | static unsigned int nf_nat_ipv6_fn(const struct nf_hook_ops *ops, | ||
32 | struct sk_buff *skb, | ||
33 | const struct net_device *in, | ||
34 | const struct net_device *out, | ||
35 | int (*okfn)(struct sk_buff *)) | ||
36 | { | ||
37 | enum ip_conntrack_info ctinfo; | ||
38 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | ||
39 | struct nf_conn_nat *nat; | ||
40 | enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum); | ||
41 | __be16 frag_off; | ||
42 | int hdrlen; | ||
43 | u8 nexthdr; | ||
44 | struct nft_pktinfo pkt; | ||
45 | unsigned int ret; | ||
46 | |||
47 | if (ct == NULL || nf_ct_is_untracked(ct)) | ||
48 | return NF_ACCEPT; | ||
49 | |||
50 | nat = nfct_nat(ct); | ||
51 | if (nat == NULL) { | ||
52 | /* Conntrack module was loaded late, can't add extension. */ | ||
53 | if (nf_ct_is_confirmed(ct)) | ||
54 | return NF_ACCEPT; | ||
55 | nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC); | ||
56 | if (nat == NULL) | ||
57 | return NF_ACCEPT; | ||
58 | } | ||
59 | |||
60 | switch (ctinfo) { | ||
61 | case IP_CT_RELATED: | ||
62 | case IP_CT_RELATED + IP_CT_IS_REPLY: | ||
63 | nexthdr = ipv6_hdr(skb)->nexthdr; | ||
64 | hdrlen = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), | ||
65 | &nexthdr, &frag_off); | ||
66 | |||
67 | if (hdrlen >= 0 && nexthdr == IPPROTO_ICMPV6) { | ||
68 | if (!nf_nat_icmpv6_reply_translation(skb, ct, ctinfo, | ||
69 | ops->hooknum, | ||
70 | hdrlen)) | ||
71 | return NF_DROP; | ||
72 | else | ||
73 | return NF_ACCEPT; | ||
74 | } | ||
75 | /* Fall through */ | ||
76 | case IP_CT_NEW: | ||
77 | if (nf_nat_initialized(ct, maniptype)) | ||
78 | break; | ||
79 | |||
80 | nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out); | ||
81 | |||
82 | ret = nft_do_chain_pktinfo(&pkt, ops); | ||
83 | if (ret != NF_ACCEPT) | ||
84 | return ret; | ||
85 | if (!nf_nat_initialized(ct, maniptype)) { | ||
86 | ret = nf_nat_alloc_null_binding(ct, ops->hooknum); | ||
87 | if (ret != NF_ACCEPT) | ||
88 | return ret; | ||
89 | } | ||
90 | default: | ||
91 | break; | ||
92 | } | ||
93 | |||
94 | return nf_nat_packet(ct, ctinfo, ops->hooknum, skb); | ||
95 | } | ||
96 | |||
97 | static unsigned int nf_nat_ipv6_prerouting(const struct nf_hook_ops *ops, | ||
98 | struct sk_buff *skb, | ||
99 | const struct net_device *in, | ||
100 | const struct net_device *out, | ||
101 | int (*okfn)(struct sk_buff *)) | ||
102 | { | ||
103 | struct in6_addr daddr = ipv6_hdr(skb)->daddr; | ||
104 | unsigned int ret; | ||
105 | |||
106 | ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn); | ||
107 | if (ret != NF_DROP && ret != NF_STOLEN && | ||
108 | ipv6_addr_cmp(&daddr, &ipv6_hdr(skb)->daddr)) | ||
109 | skb_dst_drop(skb); | ||
110 | |||
111 | return ret; | ||
112 | } | ||
113 | |||
114 | static unsigned int nf_nat_ipv6_postrouting(const struct nf_hook_ops *ops, | ||
115 | struct sk_buff *skb, | ||
116 | const struct net_device *in, | ||
117 | const struct net_device *out, | ||
118 | int (*okfn)(struct sk_buff *)) | ||
119 | { | ||
120 | enum ip_conntrack_info ctinfo __maybe_unused; | ||
121 | const struct nf_conn *ct __maybe_unused; | ||
122 | unsigned int ret; | ||
123 | |||
124 | ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn); | ||
125 | #ifdef CONFIG_XFRM | ||
126 | if (ret != NF_DROP && ret != NF_STOLEN && | ||
127 | !(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && | ||
128 | (ct = nf_ct_get(skb, &ctinfo)) != NULL) { | ||
129 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
130 | |||
131 | if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, | ||
132 | &ct->tuplehash[!dir].tuple.dst.u3) || | ||
133 | (ct->tuplehash[dir].tuple.src.u.all != | ||
134 | ct->tuplehash[!dir].tuple.dst.u.all)) | ||
135 | if (nf_xfrm_me_harder(skb, AF_INET6) < 0) | ||
136 | ret = NF_DROP; | ||
137 | } | ||
138 | #endif | ||
139 | return ret; | ||
140 | } | ||
141 | |||
142 | static unsigned int nf_nat_ipv6_output(const struct nf_hook_ops *ops, | ||
143 | struct sk_buff *skb, | ||
144 | const struct net_device *in, | ||
145 | const struct net_device *out, | ||
146 | int (*okfn)(struct sk_buff *)) | ||
147 | { | ||
148 | enum ip_conntrack_info ctinfo; | ||
149 | const struct nf_conn *ct; | ||
150 | unsigned int ret; | ||
151 | |||
152 | ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn); | ||
153 | if (ret != NF_DROP && ret != NF_STOLEN && | ||
154 | (ct = nf_ct_get(skb, &ctinfo)) != NULL) { | ||
155 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
156 | |||
157 | if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, | ||
158 | &ct->tuplehash[!dir].tuple.src.u3)) { | ||
159 | if (ip6_route_me_harder(skb)) | ||
160 | ret = NF_DROP; | ||
161 | } | ||
162 | #ifdef CONFIG_XFRM | ||
163 | else if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && | ||
164 | ct->tuplehash[dir].tuple.dst.u.all != | ||
165 | ct->tuplehash[!dir].tuple.src.u.all) | ||
166 | if (nf_xfrm_me_harder(skb, AF_INET6)) | ||
167 | ret = NF_DROP; | ||
168 | #endif | ||
169 | } | ||
170 | return ret; | ||
171 | } | ||
172 | |||
173 | static struct nf_chain_type nft_chain_nat_ipv6 = { | ||
174 | .family = NFPROTO_IPV6, | ||
175 | .name = "nat", | ||
176 | .type = NFT_CHAIN_T_NAT, | ||
177 | .hook_mask = (1 << NF_INET_PRE_ROUTING) | | ||
178 | (1 << NF_INET_POST_ROUTING) | | ||
179 | (1 << NF_INET_LOCAL_OUT) | | ||
180 | (1 << NF_INET_LOCAL_IN), | ||
181 | .fn = { | ||
182 | [NF_INET_PRE_ROUTING] = nf_nat_ipv6_prerouting, | ||
183 | [NF_INET_POST_ROUTING] = nf_nat_ipv6_postrouting, | ||
184 | [NF_INET_LOCAL_OUT] = nf_nat_ipv6_output, | ||
185 | [NF_INET_LOCAL_IN] = nf_nat_ipv6_fn, | ||
186 | }, | ||
187 | .me = THIS_MODULE, | ||
188 | }; | ||
189 | |||
190 | static int __init nft_chain_nat_ipv6_init(void) | ||
191 | { | ||
192 | int err; | ||
193 | |||
194 | err = nft_register_chain_type(&nft_chain_nat_ipv6); | ||
195 | if (err < 0) | ||
196 | return err; | ||
197 | |||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | static void __exit nft_chain_nat_ipv6_exit(void) | ||
202 | { | ||
203 | nft_unregister_chain_type(&nft_chain_nat_ipv6); | ||
204 | } | ||
205 | |||
206 | module_init(nft_chain_nat_ipv6_init); | ||
207 | module_exit(nft_chain_nat_ipv6_exit); | ||
208 | |||
209 | MODULE_LICENSE("GPL"); | ||
210 | MODULE_AUTHOR("Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>"); | ||
211 | MODULE_ALIAS_NFT_CHAIN(AF_INET6, "nat"); | ||
diff --git a/net/ipv6/netfilter/nft_chain_route_ipv6.c b/net/ipv6/netfilter/nft_chain_route_ipv6.c new file mode 100644 index 000000000000..3fe40f0456ad --- /dev/null +++ b/net/ipv6/netfilter/nft_chain_route_ipv6.c | |||
@@ -0,0 +1,88 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2008 Patrick McHardy <kaber@trash.net> | ||
3 | * Copyright (c) 2012 Pablo Neira Ayuso <pablo@netfilter.org> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * Development of this code funded by Astaro AG (http://www.astaro.com/) | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/list.h> | ||
15 | #include <linux/skbuff.h> | ||
16 | #include <linux/netlink.h> | ||
17 | #include <linux/netfilter.h> | ||
18 | #include <linux/netfilter_ipv6.h> | ||
19 | #include <linux/netfilter/nfnetlink.h> | ||
20 | #include <linux/netfilter/nf_tables.h> | ||
21 | #include <net/netfilter/nf_tables.h> | ||
22 | #include <net/netfilter/nf_tables_ipv6.h> | ||
23 | #include <net/route.h> | ||
24 | |||
25 | static unsigned int nf_route_table_hook(const struct nf_hook_ops *ops, | ||
26 | struct sk_buff *skb, | ||
27 | const struct net_device *in, | ||
28 | const struct net_device *out, | ||
29 | int (*okfn)(struct sk_buff *)) | ||
30 | { | ||
31 | unsigned int ret; | ||
32 | struct nft_pktinfo pkt; | ||
33 | struct in6_addr saddr, daddr; | ||
34 | u_int8_t hop_limit; | ||
35 | u32 mark, flowlabel; | ||
36 | |||
37 | /* malformed packet, drop it */ | ||
38 | if (nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out) < 0) | ||
39 | return NF_DROP; | ||
40 | |||
41 | /* save source/dest address, mark, hoplimit, flowlabel, priority */ | ||
42 | memcpy(&saddr, &ipv6_hdr(skb)->saddr, sizeof(saddr)); | ||
43 | memcpy(&daddr, &ipv6_hdr(skb)->daddr, sizeof(daddr)); | ||
44 | mark = skb->mark; | ||
45 | hop_limit = ipv6_hdr(skb)->hop_limit; | ||
46 | |||
47 | /* flowlabel and prio (includes version, which shouldn't change either */ | ||
48 | flowlabel = *((u32 *)ipv6_hdr(skb)); | ||
49 | |||
50 | ret = nft_do_chain_pktinfo(&pkt, ops); | ||
51 | if (ret != NF_DROP && ret != NF_QUEUE && | ||
52 | (memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr)) || | ||
53 | memcmp(&ipv6_hdr(skb)->daddr, &daddr, sizeof(daddr)) || | ||
54 | skb->mark != mark || | ||
55 | ipv6_hdr(skb)->hop_limit != hop_limit || | ||
56 | flowlabel != *((u_int32_t *)ipv6_hdr(skb)))) | ||
57 | return ip6_route_me_harder(skb) == 0 ? ret : NF_DROP; | ||
58 | |||
59 | return ret; | ||
60 | } | ||
61 | |||
62 | static struct nf_chain_type nft_chain_route_ipv6 = { | ||
63 | .family = NFPROTO_IPV6, | ||
64 | .name = "route", | ||
65 | .type = NFT_CHAIN_T_ROUTE, | ||
66 | .hook_mask = (1 << NF_INET_LOCAL_OUT), | ||
67 | .fn = { | ||
68 | [NF_INET_LOCAL_OUT] = nf_route_table_hook, | ||
69 | }, | ||
70 | .me = THIS_MODULE, | ||
71 | }; | ||
72 | |||
73 | static int __init nft_chain_route_init(void) | ||
74 | { | ||
75 | return nft_register_chain_type(&nft_chain_route_ipv6); | ||
76 | } | ||
77 | |||
78 | static void __exit nft_chain_route_exit(void) | ||
79 | { | ||
80 | nft_unregister_chain_type(&nft_chain_route_ipv6); | ||
81 | } | ||
82 | |||
83 | module_init(nft_chain_route_init); | ||
84 | module_exit(nft_chain_route_exit); | ||
85 | |||
86 | MODULE_LICENSE("GPL"); | ||
87 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); | ||
88 | MODULE_ALIAS_NFT_CHAIN(AF_INET6, "route"); | ||
diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c index 18f19df4189f..8815e31a87fe 100644 --- a/net/ipv6/ping.c +++ b/net/ipv6/ping.c | |||
@@ -116,7 +116,7 @@ int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
116 | } else { | 116 | } else { |
117 | if (sk->sk_state != TCP_ESTABLISHED) | 117 | if (sk->sk_state != TCP_ESTABLISHED) |
118 | return -EDESTADDRREQ; | 118 | return -EDESTADDRREQ; |
119 | daddr = &np->daddr; | 119 | daddr = &sk->sk_v6_daddr; |
120 | } | 120 | } |
121 | 121 | ||
122 | if (!iif) | 122 | if (!iif) |
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index a4ed2416399e..3c00842b0079 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -77,20 +77,19 @@ static struct sock *__raw_v6_lookup(struct net *net, struct sock *sk, | |||
77 | 77 | ||
78 | sk_for_each_from(sk) | 78 | sk_for_each_from(sk) |
79 | if (inet_sk(sk)->inet_num == num) { | 79 | if (inet_sk(sk)->inet_num == num) { |
80 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
81 | 80 | ||
82 | if (!net_eq(sock_net(sk), net)) | 81 | if (!net_eq(sock_net(sk), net)) |
83 | continue; | 82 | continue; |
84 | 83 | ||
85 | if (!ipv6_addr_any(&np->daddr) && | 84 | if (!ipv6_addr_any(&sk->sk_v6_daddr) && |
86 | !ipv6_addr_equal(&np->daddr, rmt_addr)) | 85 | !ipv6_addr_equal(&sk->sk_v6_daddr, rmt_addr)) |
87 | continue; | 86 | continue; |
88 | 87 | ||
89 | if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif) | 88 | if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif) |
90 | continue; | 89 | continue; |
91 | 90 | ||
92 | if (!ipv6_addr_any(&np->rcv_saddr)) { | 91 | if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr)) { |
93 | if (ipv6_addr_equal(&np->rcv_saddr, loc_addr)) | 92 | if (ipv6_addr_equal(&sk->sk_v6_rcv_saddr, loc_addr)) |
94 | goto found; | 93 | goto found; |
95 | if (is_multicast && | 94 | if (is_multicast && |
96 | inet6_mc_check(sk, loc_addr, rmt_addr)) | 95 | inet6_mc_check(sk, loc_addr, rmt_addr)) |
@@ -302,7 +301,7 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) | |||
302 | } | 301 | } |
303 | 302 | ||
304 | inet->inet_rcv_saddr = inet->inet_saddr = v4addr; | 303 | inet->inet_rcv_saddr = inet->inet_saddr = v4addr; |
305 | np->rcv_saddr = addr->sin6_addr; | 304 | sk->sk_v6_rcv_saddr = addr->sin6_addr; |
306 | if (!(addr_type & IPV6_ADDR_MULTICAST)) | 305 | if (!(addr_type & IPV6_ADDR_MULTICAST)) |
307 | np->saddr = addr->sin6_addr; | 306 | np->saddr = addr->sin6_addr; |
308 | err = 0; | 307 | err = 0; |
@@ -804,8 +803,8 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
804 | * sk->sk_dst_cache. | 803 | * sk->sk_dst_cache. |
805 | */ | 804 | */ |
806 | if (sk->sk_state == TCP_ESTABLISHED && | 805 | if (sk->sk_state == TCP_ESTABLISHED && |
807 | ipv6_addr_equal(daddr, &np->daddr)) | 806 | ipv6_addr_equal(daddr, &sk->sk_v6_daddr)) |
808 | daddr = &np->daddr; | 807 | daddr = &sk->sk_v6_daddr; |
809 | 808 | ||
810 | if (addr_len >= sizeof(struct sockaddr_in6) && | 809 | if (addr_len >= sizeof(struct sockaddr_in6) && |
811 | sin6->sin6_scope_id && | 810 | sin6->sin6_scope_id && |
@@ -816,7 +815,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
816 | return -EDESTADDRREQ; | 815 | return -EDESTADDRREQ; |
817 | 816 | ||
818 | proto = inet->inet_num; | 817 | proto = inet->inet_num; |
819 | daddr = &np->daddr; | 818 | daddr = &sk->sk_v6_daddr; |
820 | fl6.flowlabel = np->flow_label; | 819 | fl6.flowlabel = np->flow_label; |
821 | } | 820 | } |
822 | 821 | ||
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 1aeb473b2cc6..cc85a9ba5010 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c | |||
@@ -82,24 +82,24 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, | |||
82 | * callers should be careful not to use the hash value outside the ipfrag_lock | 82 | * callers should be careful not to use the hash value outside the ipfrag_lock |
83 | * as doing so could race with ipfrag_hash_rnd being recalculated. | 83 | * as doing so could race with ipfrag_hash_rnd being recalculated. |
84 | */ | 84 | */ |
85 | unsigned int inet6_hash_frag(__be32 id, const struct in6_addr *saddr, | 85 | static unsigned int inet6_hash_frag(__be32 id, const struct in6_addr *saddr, |
86 | const struct in6_addr *daddr, u32 rnd) | 86 | const struct in6_addr *daddr) |
87 | { | 87 | { |
88 | u32 c; | 88 | u32 c; |
89 | 89 | ||
90 | net_get_random_once(&ip6_frags.rnd, sizeof(ip6_frags.rnd)); | ||
90 | c = jhash_3words(ipv6_addr_hash(saddr), ipv6_addr_hash(daddr), | 91 | c = jhash_3words(ipv6_addr_hash(saddr), ipv6_addr_hash(daddr), |
91 | (__force u32)id, rnd); | 92 | (__force u32)id, ip6_frags.rnd); |
92 | 93 | ||
93 | return c & (INETFRAGS_HASHSZ - 1); | 94 | return c & (INETFRAGS_HASHSZ - 1); |
94 | } | 95 | } |
95 | EXPORT_SYMBOL_GPL(inet6_hash_frag); | ||
96 | 96 | ||
97 | static unsigned int ip6_hashfn(struct inet_frag_queue *q) | 97 | static unsigned int ip6_hashfn(struct inet_frag_queue *q) |
98 | { | 98 | { |
99 | struct frag_queue *fq; | 99 | struct frag_queue *fq; |
100 | 100 | ||
101 | fq = container_of(q, struct frag_queue, q); | 101 | fq = container_of(q, struct frag_queue, q); |
102 | return inet6_hash_frag(fq->id, &fq->saddr, &fq->daddr, ip6_frags.rnd); | 102 | return inet6_hash_frag(fq->id, &fq->saddr, &fq->daddr); |
103 | } | 103 | } |
104 | 104 | ||
105 | bool ip6_frag_match(struct inet_frag_queue *q, void *a) | 105 | bool ip6_frag_match(struct inet_frag_queue *q, void *a) |
@@ -193,7 +193,7 @@ fq_find(struct net *net, __be32 id, const struct in6_addr *src, | |||
193 | arg.ecn = ecn; | 193 | arg.ecn = ecn; |
194 | 194 | ||
195 | read_lock(&ip6_frags.lock); | 195 | read_lock(&ip6_frags.lock); |
196 | hash = inet6_hash_frag(id, src, dst, ip6_frags.rnd); | 196 | hash = inet6_hash_frag(id, src, dst); |
197 | 197 | ||
198 | q = inet_frag_find(&net->ipv6.frags, &ip6_frags, &arg, hash); | 198 | q = inet_frag_find(&net->ipv6.frags, &ip6_frags, &arg, hash); |
199 | if (IS_ERR_OR_NULL(q)) { | 199 | if (IS_ERR_OR_NULL(q)) { |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 04e17b3309fb..7faa9d5e1503 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -619,7 +619,7 @@ static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict, | |||
619 | goto out; | 619 | goto out; |
620 | 620 | ||
621 | m = rt6_score_route(rt, oif, strict); | 621 | m = rt6_score_route(rt, oif, strict); |
622 | if (m == RT6_NUD_FAIL_SOFT && !IS_ENABLED(CONFIG_IPV6_ROUTER_PREF)) { | 622 | if (m == RT6_NUD_FAIL_SOFT) { |
623 | match_do_rr = true; | 623 | match_do_rr = true; |
624 | m = 0; /* lowest valid score */ | 624 | m = 0; /* lowest valid score */ |
625 | } else if (m < 0) { | 625 | } else if (m < 0) { |
@@ -731,8 +731,11 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, | |||
731 | prefix = &prefix_buf; | 731 | prefix = &prefix_buf; |
732 | } | 732 | } |
733 | 733 | ||
734 | rt = rt6_get_route_info(net, prefix, rinfo->prefix_len, gwaddr, | 734 | if (rinfo->prefix_len == 0) |
735 | dev->ifindex); | 735 | rt = rt6_get_dflt_router(gwaddr, dev); |
736 | else | ||
737 | rt = rt6_get_route_info(net, prefix, rinfo->prefix_len, | ||
738 | gwaddr, dev->ifindex); | ||
736 | 739 | ||
737 | if (rt && !lifetime) { | 740 | if (rt && !lifetime) { |
738 | ip6_del_rt(rt); | 741 | ip6_del_rt(rt); |
@@ -871,11 +874,9 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, | |||
871 | rt = ip6_rt_copy(ort, daddr); | 874 | rt = ip6_rt_copy(ort, daddr); |
872 | 875 | ||
873 | if (rt) { | 876 | if (rt) { |
874 | if (!(rt->rt6i_flags & RTF_GATEWAY)) { | 877 | if (ort->rt6i_dst.plen != 128 && |
875 | if (ort->rt6i_dst.plen != 128 && | 878 | ipv6_addr_equal(&ort->rt6i_dst.addr, daddr)) |
876 | ipv6_addr_equal(&ort->rt6i_dst.addr, daddr)) | 879 | rt->rt6i_flags |= RTF_ANYCAST; |
877 | rt->rt6i_flags |= RTF_ANYCAST; | ||
878 | } | ||
879 | 880 | ||
880 | rt->rt6i_flags |= RTF_CACHE; | 881 | rt->rt6i_flags |= RTF_CACHE; |
881 | 882 | ||
@@ -1163,7 +1164,6 @@ void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu, | |||
1163 | memset(&fl6, 0, sizeof(fl6)); | 1164 | memset(&fl6, 0, sizeof(fl6)); |
1164 | fl6.flowi6_oif = oif; | 1165 | fl6.flowi6_oif = oif; |
1165 | fl6.flowi6_mark = mark; | 1166 | fl6.flowi6_mark = mark; |
1166 | fl6.flowi6_flags = 0; | ||
1167 | fl6.daddr = iph->daddr; | 1167 | fl6.daddr = iph->daddr; |
1168 | fl6.saddr = iph->saddr; | 1168 | fl6.saddr = iph->saddr; |
1169 | fl6.flowlabel = ip6_flowinfo(iph); | 1169 | fl6.flowlabel = ip6_flowinfo(iph); |
@@ -1262,7 +1262,6 @@ void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark) | |||
1262 | memset(&fl6, 0, sizeof(fl6)); | 1262 | memset(&fl6, 0, sizeof(fl6)); |
1263 | fl6.flowi6_oif = oif; | 1263 | fl6.flowi6_oif = oif; |
1264 | fl6.flowi6_mark = mark; | 1264 | fl6.flowi6_mark = mark; |
1265 | fl6.flowi6_flags = 0; | ||
1266 | fl6.daddr = iph->daddr; | 1265 | fl6.daddr = iph->daddr; |
1267 | fl6.saddr = iph->saddr; | 1266 | fl6.saddr = iph->saddr; |
1268 | fl6.flowlabel = ip6_flowinfo(iph); | 1267 | fl6.flowlabel = ip6_flowinfo(iph); |
@@ -1284,7 +1283,6 @@ void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif, | |||
1284 | memset(&fl6, 0, sizeof(fl6)); | 1283 | memset(&fl6, 0, sizeof(fl6)); |
1285 | fl6.flowi6_oif = oif; | 1284 | fl6.flowi6_oif = oif; |
1286 | fl6.flowi6_mark = mark; | 1285 | fl6.flowi6_mark = mark; |
1287 | fl6.flowi6_flags = 0; | ||
1288 | fl6.daddr = msg->dest; | 1286 | fl6.daddr = msg->dest; |
1289 | fl6.saddr = iph->daddr; | 1287 | fl6.saddr = iph->daddr; |
1290 | 1288 | ||
@@ -2831,56 +2829,12 @@ static int ip6_route_dev_notify(struct notifier_block *this, | |||
2831 | 2829 | ||
2832 | #ifdef CONFIG_PROC_FS | 2830 | #ifdef CONFIG_PROC_FS |
2833 | 2831 | ||
2834 | struct rt6_proc_arg | ||
2835 | { | ||
2836 | char *buffer; | ||
2837 | int offset; | ||
2838 | int length; | ||
2839 | int skip; | ||
2840 | int len; | ||
2841 | }; | ||
2842 | |||
2843 | static int rt6_info_route(struct rt6_info *rt, void *p_arg) | ||
2844 | { | ||
2845 | struct seq_file *m = p_arg; | ||
2846 | |||
2847 | seq_printf(m, "%pi6 %02x ", &rt->rt6i_dst.addr, rt->rt6i_dst.plen); | ||
2848 | |||
2849 | #ifdef CONFIG_IPV6_SUBTREES | ||
2850 | seq_printf(m, "%pi6 %02x ", &rt->rt6i_src.addr, rt->rt6i_src.plen); | ||
2851 | #else | ||
2852 | seq_puts(m, "00000000000000000000000000000000 00 "); | ||
2853 | #endif | ||
2854 | if (rt->rt6i_flags & RTF_GATEWAY) { | ||
2855 | seq_printf(m, "%pi6", &rt->rt6i_gateway); | ||
2856 | } else { | ||
2857 | seq_puts(m, "00000000000000000000000000000000"); | ||
2858 | } | ||
2859 | seq_printf(m, " %08x %08x %08x %08x %8s\n", | ||
2860 | rt->rt6i_metric, atomic_read(&rt->dst.__refcnt), | ||
2861 | rt->dst.__use, rt->rt6i_flags, | ||
2862 | rt->dst.dev ? rt->dst.dev->name : ""); | ||
2863 | return 0; | ||
2864 | } | ||
2865 | |||
2866 | static int ipv6_route_show(struct seq_file *m, void *v) | ||
2867 | { | ||
2868 | struct net *net = (struct net *)m->private; | ||
2869 | fib6_clean_all_ro(net, rt6_info_route, 0, m); | ||
2870 | return 0; | ||
2871 | } | ||
2872 | |||
2873 | static int ipv6_route_open(struct inode *inode, struct file *file) | ||
2874 | { | ||
2875 | return single_open_net(inode, file, ipv6_route_show); | ||
2876 | } | ||
2877 | |||
2878 | static const struct file_operations ipv6_route_proc_fops = { | 2832 | static const struct file_operations ipv6_route_proc_fops = { |
2879 | .owner = THIS_MODULE, | 2833 | .owner = THIS_MODULE, |
2880 | .open = ipv6_route_open, | 2834 | .open = ipv6_route_open, |
2881 | .read = seq_read, | 2835 | .read = seq_read, |
2882 | .llseek = seq_lseek, | 2836 | .llseek = seq_lseek, |
2883 | .release = single_release_net, | 2837 | .release = seq_release_net, |
2884 | }; | 2838 | }; |
2885 | 2839 | ||
2886 | static int rt6_stats_seq_show(struct seq_file *seq, void *v) | 2840 | static int rt6_stats_seq_show(struct seq_file *seq, void *v) |
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 19269453a8ea..3a9038dd818d 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
@@ -933,10 +933,9 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
933 | ttl = iph6->hop_limit; | 933 | ttl = iph6->hop_limit; |
934 | tos = INET_ECN_encapsulate(tos, ipv6_get_dsfield(iph6)); | 934 | tos = INET_ECN_encapsulate(tos, ipv6_get_dsfield(iph6)); |
935 | 935 | ||
936 | if (likely(!skb->encapsulation)) { | 936 | skb = iptunnel_handle_offloads(skb, false, SKB_GSO_SIT); |
937 | skb_reset_inner_headers(skb); | 937 | if (IS_ERR(skb)) |
938 | skb->encapsulation = 1; | 938 | goto out; |
939 | } | ||
940 | 939 | ||
941 | err = iptunnel_xmit(rt, skb, fl4.saddr, fl4.daddr, IPPROTO_IPV6, tos, | 940 | err = iptunnel_xmit(rt, skb, fl4.saddr, fl4.daddr, IPPROTO_IPV6, tos, |
942 | ttl, df, !net_eq(tunnel->net, dev_net(dev))); | 941 | ttl, df, !net_eq(tunnel->net, dev_net(dev))); |
@@ -946,8 +945,9 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
946 | tx_error_icmp: | 945 | tx_error_icmp: |
947 | dst_link_failure(skb); | 946 | dst_link_failure(skb); |
948 | tx_error: | 947 | tx_error: |
949 | dev->stats.tx_errors++; | ||
950 | dev_kfree_skb(skb); | 948 | dev_kfree_skb(skb); |
949 | out: | ||
950 | dev->stats.tx_errors++; | ||
951 | return NETDEV_TX_OK; | 951 | return NETDEV_TX_OK; |
952 | } | 952 | } |
953 | 953 | ||
@@ -956,13 +956,15 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) | |||
956 | struct ip_tunnel *tunnel = netdev_priv(dev); | 956 | struct ip_tunnel *tunnel = netdev_priv(dev); |
957 | const struct iphdr *tiph = &tunnel->parms.iph; | 957 | const struct iphdr *tiph = &tunnel->parms.iph; |
958 | 958 | ||
959 | if (likely(!skb->encapsulation)) { | 959 | skb = iptunnel_handle_offloads(skb, false, SKB_GSO_IPIP); |
960 | skb_reset_inner_headers(skb); | 960 | if (IS_ERR(skb)) |
961 | skb->encapsulation = 1; | 961 | goto out; |
962 | } | ||
963 | 962 | ||
964 | ip_tunnel_xmit(skb, dev, tiph, IPPROTO_IPIP); | 963 | ip_tunnel_xmit(skb, dev, tiph, IPPROTO_IPIP); |
965 | return NETDEV_TX_OK; | 964 | return NETDEV_TX_OK; |
965 | out: | ||
966 | dev->stats.tx_errors++; | ||
967 | return NETDEV_TX_OK; | ||
966 | } | 968 | } |
967 | 969 | ||
968 | static netdev_tx_t sit_tunnel_xmit(struct sk_buff *skb, | 970 | static netdev_tx_t sit_tunnel_xmit(struct sk_buff *skb, |
@@ -1292,6 +1294,12 @@ static void ipip6_dev_free(struct net_device *dev) | |||
1292 | free_netdev(dev); | 1294 | free_netdev(dev); |
1293 | } | 1295 | } |
1294 | 1296 | ||
1297 | #define SIT_FEATURES (NETIF_F_SG | \ | ||
1298 | NETIF_F_FRAGLIST | \ | ||
1299 | NETIF_F_HIGHDMA | \ | ||
1300 | NETIF_F_GSO_SOFTWARE | \ | ||
1301 | NETIF_F_HW_CSUM) | ||
1302 | |||
1295 | static void ipip6_tunnel_setup(struct net_device *dev) | 1303 | static void ipip6_tunnel_setup(struct net_device *dev) |
1296 | { | 1304 | { |
1297 | dev->netdev_ops = &ipip6_netdev_ops; | 1305 | dev->netdev_ops = &ipip6_netdev_ops; |
@@ -1305,6 +1313,8 @@ static void ipip6_tunnel_setup(struct net_device *dev) | |||
1305 | dev->iflink = 0; | 1313 | dev->iflink = 0; |
1306 | dev->addr_len = 4; | 1314 | dev->addr_len = 4; |
1307 | dev->features |= NETIF_F_LLTX; | 1315 | dev->features |= NETIF_F_LLTX; |
1316 | dev->features |= SIT_FEATURES; | ||
1317 | dev->hw_features |= SIT_FEATURES; | ||
1308 | } | 1318 | } |
1309 | 1319 | ||
1310 | static int ipip6_tunnel_init(struct net_device *dev) | 1320 | static int ipip6_tunnel_init(struct net_device *dev) |
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index bf63ac8a49b9..535a3ad262f1 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c | |||
@@ -24,26 +24,23 @@ | |||
24 | #define COOKIEBITS 24 /* Upper bits store count */ | 24 | #define COOKIEBITS 24 /* Upper bits store count */ |
25 | #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1) | 25 | #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1) |
26 | 26 | ||
27 | /* Table must be sorted. */ | 27 | static u32 syncookie6_secret[2][16-4+SHA_DIGEST_WORDS]; |
28 | |||
29 | /* RFC 2460, Section 8.3: | ||
30 | * [ipv6 tcp] MSS must be computed as the maximum packet size minus 60 [..] | ||
31 | * | ||
32 | * Due to IPV6_MIN_MTU=1280 the lowest possible MSS is 1220, which allows | ||
33 | * using higher values than ipv4 tcp syncookies. | ||
34 | * The other values are chosen based on ethernet (1500 and 9k MTU), plus | ||
35 | * one that accounts for common encap (PPPoe) overhead. Table must be sorted. | ||
36 | */ | ||
28 | static __u16 const msstab[] = { | 37 | static __u16 const msstab[] = { |
29 | 64, | 38 | 1280 - 60, /* IPV6_MIN_MTU - 60 */ |
30 | 512, | ||
31 | 536, | ||
32 | 1280 - 60, | ||
33 | 1480 - 60, | 39 | 1480 - 60, |
34 | 1500 - 60, | 40 | 1500 - 60, |
35 | 4460 - 60, | ||
36 | 9000 - 60, | 41 | 9000 - 60, |
37 | }; | 42 | }; |
38 | 43 | ||
39 | /* | ||
40 | * This (misnamed) value is the age of syncookie which is permitted. | ||
41 | * Its ideal value should be dependent on TCP_TIMEOUT_INIT and | ||
42 | * sysctl_tcp_retries1. It's a rather complicated formula (exponential | ||
43 | * backoff) to compute at runtime so it's currently hardcoded here. | ||
44 | */ | ||
45 | #define COUNTER_TRIES 4 | ||
46 | |||
47 | static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb, | 44 | static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb, |
48 | struct request_sock *req, | 45 | struct request_sock *req, |
49 | struct dst_entry *dst) | 46 | struct dst_entry *dst) |
@@ -66,14 +63,18 @@ static DEFINE_PER_CPU(__u32 [16 + 5 + SHA_WORKSPACE_WORDS], | |||
66 | static u32 cookie_hash(const struct in6_addr *saddr, const struct in6_addr *daddr, | 63 | static u32 cookie_hash(const struct in6_addr *saddr, const struct in6_addr *daddr, |
67 | __be16 sport, __be16 dport, u32 count, int c) | 64 | __be16 sport, __be16 dport, u32 count, int c) |
68 | { | 65 | { |
69 | __u32 *tmp = __get_cpu_var(ipv6_cookie_scratch); | 66 | __u32 *tmp; |
67 | |||
68 | net_get_random_once(syncookie6_secret, sizeof(syncookie6_secret)); | ||
69 | |||
70 | tmp = __get_cpu_var(ipv6_cookie_scratch); | ||
70 | 71 | ||
71 | /* | 72 | /* |
72 | * we have 320 bits of information to hash, copy in the remaining | 73 | * we have 320 bits of information to hash, copy in the remaining |
73 | * 192 bits required for sha_transform, from the syncookie_secret | 74 | * 192 bits required for sha_transform, from the syncookie6_secret |
74 | * and overwrite the digest with the secret | 75 | * and overwrite the digest with the secret |
75 | */ | 76 | */ |
76 | memcpy(tmp + 10, syncookie_secret[c], 44); | 77 | memcpy(tmp + 10, syncookie6_secret[c], 44); |
77 | memcpy(tmp, saddr, 16); | 78 | memcpy(tmp, saddr, 16); |
78 | memcpy(tmp + 4, daddr, 16); | 79 | memcpy(tmp + 4, daddr, 16); |
79 | tmp[8] = ((__force u32)sport << 16) + (__force u32)dport; | 80 | tmp[8] = ((__force u32)sport << 16) + (__force u32)dport; |
@@ -86,8 +87,9 @@ static u32 cookie_hash(const struct in6_addr *saddr, const struct in6_addr *dadd | |||
86 | static __u32 secure_tcp_syn_cookie(const struct in6_addr *saddr, | 87 | static __u32 secure_tcp_syn_cookie(const struct in6_addr *saddr, |
87 | const struct in6_addr *daddr, | 88 | const struct in6_addr *daddr, |
88 | __be16 sport, __be16 dport, __u32 sseq, | 89 | __be16 sport, __be16 dport, __u32 sseq, |
89 | __u32 count, __u32 data) | 90 | __u32 data) |
90 | { | 91 | { |
92 | u32 count = tcp_cookie_time(); | ||
91 | return (cookie_hash(saddr, daddr, sport, dport, 0, 0) + | 93 | return (cookie_hash(saddr, daddr, sport, dport, 0, 0) + |
92 | sseq + (count << COOKIEBITS) + | 94 | sseq + (count << COOKIEBITS) + |
93 | ((cookie_hash(saddr, daddr, sport, dport, count, 1) + data) | 95 | ((cookie_hash(saddr, daddr, sport, dport, count, 1) + data) |
@@ -96,15 +98,14 @@ static __u32 secure_tcp_syn_cookie(const struct in6_addr *saddr, | |||
96 | 98 | ||
97 | static __u32 check_tcp_syn_cookie(__u32 cookie, const struct in6_addr *saddr, | 99 | static __u32 check_tcp_syn_cookie(__u32 cookie, const struct in6_addr *saddr, |
98 | const struct in6_addr *daddr, __be16 sport, | 100 | const struct in6_addr *daddr, __be16 sport, |
99 | __be16 dport, __u32 sseq, __u32 count, | 101 | __be16 dport, __u32 sseq) |
100 | __u32 maxdiff) | ||
101 | { | 102 | { |
102 | __u32 diff; | 103 | __u32 diff, count = tcp_cookie_time(); |
103 | 104 | ||
104 | cookie -= cookie_hash(saddr, daddr, sport, dport, 0, 0) + sseq; | 105 | cookie -= cookie_hash(saddr, daddr, sport, dport, 0, 0) + sseq; |
105 | 106 | ||
106 | diff = (count - (cookie >> COOKIEBITS)) & ((__u32) -1 >> COOKIEBITS); | 107 | diff = (count - (cookie >> COOKIEBITS)) & ((__u32) -1 >> COOKIEBITS); |
107 | if (diff >= maxdiff) | 108 | if (diff >= MAX_SYNCOOKIE_AGE) |
108 | return (__u32)-1; | 109 | return (__u32)-1; |
109 | 110 | ||
110 | return (cookie - | 111 | return (cookie - |
@@ -125,8 +126,7 @@ u32 __cookie_v6_init_sequence(const struct ipv6hdr *iph, | |||
125 | *mssp = msstab[mssind]; | 126 | *mssp = msstab[mssind]; |
126 | 127 | ||
127 | return secure_tcp_syn_cookie(&iph->saddr, &iph->daddr, th->source, | 128 | return secure_tcp_syn_cookie(&iph->saddr, &iph->daddr, th->source, |
128 | th->dest, ntohl(th->seq), | 129 | th->dest, ntohl(th->seq), mssind); |
129 | jiffies / (HZ * 60), mssind); | ||
130 | } | 130 | } |
131 | EXPORT_SYMBOL_GPL(__cookie_v6_init_sequence); | 131 | EXPORT_SYMBOL_GPL(__cookie_v6_init_sequence); |
132 | 132 | ||
@@ -146,8 +146,7 @@ int __cookie_v6_check(const struct ipv6hdr *iph, const struct tcphdr *th, | |||
146 | { | 146 | { |
147 | __u32 seq = ntohl(th->seq) - 1; | 147 | __u32 seq = ntohl(th->seq) - 1; |
148 | __u32 mssind = check_tcp_syn_cookie(cookie, &iph->saddr, &iph->daddr, | 148 | __u32 mssind = check_tcp_syn_cookie(cookie, &iph->saddr, &iph->daddr, |
149 | th->source, th->dest, seq, | 149 | th->source, th->dest, seq); |
150 | jiffies / (HZ * 60), COUNTER_TRIES); | ||
151 | 150 | ||
152 | return mssind < ARRAY_SIZE(msstab) ? msstab[mssind] : 0; | 151 | return mssind < ARRAY_SIZE(msstab) ? msstab[mssind] : 0; |
153 | } | 152 | } |
@@ -157,7 +156,6 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
157 | { | 156 | { |
158 | struct tcp_options_received tcp_opt; | 157 | struct tcp_options_received tcp_opt; |
159 | struct inet_request_sock *ireq; | 158 | struct inet_request_sock *ireq; |
160 | struct inet6_request_sock *ireq6; | ||
161 | struct tcp_request_sock *treq; | 159 | struct tcp_request_sock *treq; |
162 | struct ipv6_pinfo *np = inet6_sk(sk); | 160 | struct ipv6_pinfo *np = inet6_sk(sk); |
163 | struct tcp_sock *tp = tcp_sk(sk); | 161 | struct tcp_sock *tp = tcp_sk(sk); |
@@ -194,7 +192,6 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
194 | goto out; | 192 | goto out; |
195 | 193 | ||
196 | ireq = inet_rsk(req); | 194 | ireq = inet_rsk(req); |
197 | ireq6 = inet6_rsk(req); | ||
198 | treq = tcp_rsk(req); | 195 | treq = tcp_rsk(req); |
199 | treq->listener = NULL; | 196 | treq->listener = NULL; |
200 | 197 | ||
@@ -202,22 +199,22 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
202 | goto out_free; | 199 | goto out_free; |
203 | 200 | ||
204 | req->mss = mss; | 201 | req->mss = mss; |
205 | ireq->rmt_port = th->source; | 202 | ireq->ir_rmt_port = th->source; |
206 | ireq->loc_port = th->dest; | 203 | ireq->ir_num = ntohs(th->dest); |
207 | ireq6->rmt_addr = ipv6_hdr(skb)->saddr; | 204 | ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr; |
208 | ireq6->loc_addr = ipv6_hdr(skb)->daddr; | 205 | ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr; |
209 | if (ipv6_opt_accepted(sk, skb) || | 206 | if (ipv6_opt_accepted(sk, skb) || |
210 | np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || | 207 | np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || |
211 | np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) { | 208 | np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) { |
212 | atomic_inc(&skb->users); | 209 | atomic_inc(&skb->users); |
213 | ireq6->pktopts = skb; | 210 | ireq->pktopts = skb; |
214 | } | 211 | } |
215 | 212 | ||
216 | ireq6->iif = sk->sk_bound_dev_if; | 213 | ireq->ir_iif = sk->sk_bound_dev_if; |
217 | /* So that link locals have meaning */ | 214 | /* So that link locals have meaning */ |
218 | if (!sk->sk_bound_dev_if && | 215 | if (!sk->sk_bound_dev_if && |
219 | ipv6_addr_type(&ireq6->rmt_addr) & IPV6_ADDR_LINKLOCAL) | 216 | ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL) |
220 | ireq6->iif = inet6_iif(skb); | 217 | ireq->ir_iif = inet6_iif(skb); |
221 | 218 | ||
222 | req->expires = 0UL; | 219 | req->expires = 0UL; |
223 | req->num_retrans = 0; | 220 | req->num_retrans = 0; |
@@ -241,12 +238,12 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
241 | struct flowi6 fl6; | 238 | struct flowi6 fl6; |
242 | memset(&fl6, 0, sizeof(fl6)); | 239 | memset(&fl6, 0, sizeof(fl6)); |
243 | fl6.flowi6_proto = IPPROTO_TCP; | 240 | fl6.flowi6_proto = IPPROTO_TCP; |
244 | fl6.daddr = ireq6->rmt_addr; | 241 | fl6.daddr = ireq->ir_v6_rmt_addr; |
245 | final_p = fl6_update_dst(&fl6, np->opt, &final); | 242 | final_p = fl6_update_dst(&fl6, np->opt, &final); |
246 | fl6.saddr = ireq6->loc_addr; | 243 | fl6.saddr = ireq->ir_v6_loc_addr; |
247 | fl6.flowi6_oif = sk->sk_bound_dev_if; | 244 | fl6.flowi6_oif = sk->sk_bound_dev_if; |
248 | fl6.flowi6_mark = sk->sk_mark; | 245 | fl6.flowi6_mark = sk->sk_mark; |
249 | fl6.fl6_dport = inet_rsk(req)->rmt_port; | 246 | fl6.fl6_dport = ireq->ir_rmt_port; |
250 | fl6.fl6_sport = inet_sk(sk)->inet_sport; | 247 | fl6.fl6_sport = inet_sk(sk)->inet_sport; |
251 | security_req_classify_flow(req, flowi6_to_flowi(&fl6)); | 248 | security_req_classify_flow(req, flowi6_to_flowi(&fl6)); |
252 | 249 | ||
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 5c71501fc917..0740f93a114a 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -192,13 +192,13 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
192 | } | 192 | } |
193 | 193 | ||
194 | if (tp->rx_opt.ts_recent_stamp && | 194 | if (tp->rx_opt.ts_recent_stamp && |
195 | !ipv6_addr_equal(&np->daddr, &usin->sin6_addr)) { | 195 | !ipv6_addr_equal(&sk->sk_v6_daddr, &usin->sin6_addr)) { |
196 | tp->rx_opt.ts_recent = 0; | 196 | tp->rx_opt.ts_recent = 0; |
197 | tp->rx_opt.ts_recent_stamp = 0; | 197 | tp->rx_opt.ts_recent_stamp = 0; |
198 | tp->write_seq = 0; | 198 | tp->write_seq = 0; |
199 | } | 199 | } |
200 | 200 | ||
201 | np->daddr = usin->sin6_addr; | 201 | sk->sk_v6_daddr = usin->sin6_addr; |
202 | np->flow_label = fl6.flowlabel; | 202 | np->flow_label = fl6.flowlabel; |
203 | 203 | ||
204 | /* | 204 | /* |
@@ -237,17 +237,17 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
237 | } else { | 237 | } else { |
238 | ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr); | 238 | ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr); |
239 | ipv6_addr_set_v4mapped(inet->inet_rcv_saddr, | 239 | ipv6_addr_set_v4mapped(inet->inet_rcv_saddr, |
240 | &np->rcv_saddr); | 240 | &sk->sk_v6_rcv_saddr); |
241 | } | 241 | } |
242 | 242 | ||
243 | return err; | 243 | return err; |
244 | } | 244 | } |
245 | 245 | ||
246 | if (!ipv6_addr_any(&np->rcv_saddr)) | 246 | if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr)) |
247 | saddr = &np->rcv_saddr; | 247 | saddr = &sk->sk_v6_rcv_saddr; |
248 | 248 | ||
249 | fl6.flowi6_proto = IPPROTO_TCP; | 249 | fl6.flowi6_proto = IPPROTO_TCP; |
250 | fl6.daddr = np->daddr; | 250 | fl6.daddr = sk->sk_v6_daddr; |
251 | fl6.saddr = saddr ? *saddr : np->saddr; | 251 | fl6.saddr = saddr ? *saddr : np->saddr; |
252 | fl6.flowi6_oif = sk->sk_bound_dev_if; | 252 | fl6.flowi6_oif = sk->sk_bound_dev_if; |
253 | fl6.flowi6_mark = sk->sk_mark; | 253 | fl6.flowi6_mark = sk->sk_mark; |
@@ -266,7 +266,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
266 | 266 | ||
267 | if (saddr == NULL) { | 267 | if (saddr == NULL) { |
268 | saddr = &fl6.saddr; | 268 | saddr = &fl6.saddr; |
269 | np->rcv_saddr = *saddr; | 269 | sk->sk_v6_rcv_saddr = *saddr; |
270 | } | 270 | } |
271 | 271 | ||
272 | /* set the source address */ | 272 | /* set the source address */ |
@@ -279,7 +279,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
279 | rt = (struct rt6_info *) dst; | 279 | rt = (struct rt6_info *) dst; |
280 | if (tcp_death_row.sysctl_tw_recycle && | 280 | if (tcp_death_row.sysctl_tw_recycle && |
281 | !tp->rx_opt.ts_recent_stamp && | 281 | !tp->rx_opt.ts_recent_stamp && |
282 | ipv6_addr_equal(&rt->rt6i_dst.addr, &np->daddr)) | 282 | ipv6_addr_equal(&rt->rt6i_dst.addr, &sk->sk_v6_daddr)) |
283 | tcp_fetch_timewait_stamp(sk, dst); | 283 | tcp_fetch_timewait_stamp(sk, dst); |
284 | 284 | ||
285 | icsk->icsk_ext_hdr_len = 0; | 285 | icsk->icsk_ext_hdr_len = 0; |
@@ -298,7 +298,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
298 | 298 | ||
299 | if (!tp->write_seq && likely(!tp->repair)) | 299 | if (!tp->write_seq && likely(!tp->repair)) |
300 | tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32, | 300 | tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32, |
301 | np->daddr.s6_addr32, | 301 | sk->sk_v6_daddr.s6_addr32, |
302 | inet->inet_sport, | 302 | inet->inet_sport, |
303 | inet->inet_dport); | 303 | inet->inet_dport); |
304 | 304 | ||
@@ -465,7 +465,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst, | |||
465 | struct request_sock *req, | 465 | struct request_sock *req, |
466 | u16 queue_mapping) | 466 | u16 queue_mapping) |
467 | { | 467 | { |
468 | struct inet6_request_sock *treq = inet6_rsk(req); | 468 | struct inet_request_sock *ireq = inet_rsk(req); |
469 | struct ipv6_pinfo *np = inet6_sk(sk); | 469 | struct ipv6_pinfo *np = inet6_sk(sk); |
470 | struct sk_buff * skb; | 470 | struct sk_buff * skb; |
471 | int err = -ENOMEM; | 471 | int err = -ENOMEM; |
@@ -477,9 +477,10 @@ static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst, | |||
477 | skb = tcp_make_synack(sk, dst, req, NULL); | 477 | skb = tcp_make_synack(sk, dst, req, NULL); |
478 | 478 | ||
479 | if (skb) { | 479 | if (skb) { |
480 | __tcp_v6_send_check(skb, &treq->loc_addr, &treq->rmt_addr); | 480 | __tcp_v6_send_check(skb, &ireq->ir_v6_loc_addr, |
481 | &ireq->ir_v6_rmt_addr); | ||
481 | 482 | ||
482 | fl6->daddr = treq->rmt_addr; | 483 | fl6->daddr = ireq->ir_v6_rmt_addr; |
483 | skb_set_queue_mapping(skb, queue_mapping); | 484 | skb_set_queue_mapping(skb, queue_mapping); |
484 | err = ip6_xmit(sk, skb, fl6, np->opt, np->tclass); | 485 | err = ip6_xmit(sk, skb, fl6, np->opt, np->tclass); |
485 | err = net_xmit_eval(err); | 486 | err = net_xmit_eval(err); |
@@ -502,7 +503,7 @@ static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req) | |||
502 | 503 | ||
503 | static void tcp_v6_reqsk_destructor(struct request_sock *req) | 504 | static void tcp_v6_reqsk_destructor(struct request_sock *req) |
504 | { | 505 | { |
505 | kfree_skb(inet6_rsk(req)->pktopts); | 506 | kfree_skb(inet_rsk(req)->pktopts); |
506 | } | 507 | } |
507 | 508 | ||
508 | #ifdef CONFIG_TCP_MD5SIG | 509 | #ifdef CONFIG_TCP_MD5SIG |
@@ -515,13 +516,13 @@ static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk, | |||
515 | static struct tcp_md5sig_key *tcp_v6_md5_lookup(struct sock *sk, | 516 | static struct tcp_md5sig_key *tcp_v6_md5_lookup(struct sock *sk, |
516 | struct sock *addr_sk) | 517 | struct sock *addr_sk) |
517 | { | 518 | { |
518 | return tcp_v6_md5_do_lookup(sk, &inet6_sk(addr_sk)->daddr); | 519 | return tcp_v6_md5_do_lookup(sk, &addr_sk->sk_v6_daddr); |
519 | } | 520 | } |
520 | 521 | ||
521 | static struct tcp_md5sig_key *tcp_v6_reqsk_md5_lookup(struct sock *sk, | 522 | static struct tcp_md5sig_key *tcp_v6_reqsk_md5_lookup(struct sock *sk, |
522 | struct request_sock *req) | 523 | struct request_sock *req) |
523 | { | 524 | { |
524 | return tcp_v6_md5_do_lookup(sk, &inet6_rsk(req)->rmt_addr); | 525 | return tcp_v6_md5_do_lookup(sk, &inet_rsk(req)->ir_v6_rmt_addr); |
525 | } | 526 | } |
526 | 527 | ||
527 | static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval, | 528 | static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval, |
@@ -621,10 +622,10 @@ static int tcp_v6_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key, | |||
621 | 622 | ||
622 | if (sk) { | 623 | if (sk) { |
623 | saddr = &inet6_sk(sk)->saddr; | 624 | saddr = &inet6_sk(sk)->saddr; |
624 | daddr = &inet6_sk(sk)->daddr; | 625 | daddr = &sk->sk_v6_daddr; |
625 | } else if (req) { | 626 | } else if (req) { |
626 | saddr = &inet6_rsk(req)->loc_addr; | 627 | saddr = &inet_rsk(req)->ir_v6_loc_addr; |
627 | daddr = &inet6_rsk(req)->rmt_addr; | 628 | daddr = &inet_rsk(req)->ir_v6_rmt_addr; |
628 | } else { | 629 | } else { |
629 | const struct ipv6hdr *ip6h = ipv6_hdr(skb); | 630 | const struct ipv6hdr *ip6h = ipv6_hdr(skb); |
630 | saddr = &ip6h->saddr; | 631 | saddr = &ip6h->saddr; |
@@ -949,7 +950,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
949 | { | 950 | { |
950 | struct tcp_options_received tmp_opt; | 951 | struct tcp_options_received tmp_opt; |
951 | struct request_sock *req; | 952 | struct request_sock *req; |
952 | struct inet6_request_sock *treq; | 953 | struct inet_request_sock *ireq; |
953 | struct ipv6_pinfo *np = inet6_sk(sk); | 954 | struct ipv6_pinfo *np = inet6_sk(sk); |
954 | struct tcp_sock *tp = tcp_sk(sk); | 955 | struct tcp_sock *tp = tcp_sk(sk); |
955 | __u32 isn = TCP_SKB_CB(skb)->when; | 956 | __u32 isn = TCP_SKB_CB(skb)->when; |
@@ -994,25 +995,25 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
994 | tmp_opt.tstamp_ok = tmp_opt.saw_tstamp; | 995 | tmp_opt.tstamp_ok = tmp_opt.saw_tstamp; |
995 | tcp_openreq_init(req, &tmp_opt, skb); | 996 | tcp_openreq_init(req, &tmp_opt, skb); |
996 | 997 | ||
997 | treq = inet6_rsk(req); | 998 | ireq = inet_rsk(req); |
998 | treq->rmt_addr = ipv6_hdr(skb)->saddr; | 999 | ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr; |
999 | treq->loc_addr = ipv6_hdr(skb)->daddr; | 1000 | ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr; |
1000 | if (!want_cookie || tmp_opt.tstamp_ok) | 1001 | if (!want_cookie || tmp_opt.tstamp_ok) |
1001 | TCP_ECN_create_request(req, skb, sock_net(sk)); | 1002 | TCP_ECN_create_request(req, skb, sock_net(sk)); |
1002 | 1003 | ||
1003 | treq->iif = sk->sk_bound_dev_if; | 1004 | ireq->ir_iif = sk->sk_bound_dev_if; |
1004 | 1005 | ||
1005 | /* So that link locals have meaning */ | 1006 | /* So that link locals have meaning */ |
1006 | if (!sk->sk_bound_dev_if && | 1007 | if (!sk->sk_bound_dev_if && |
1007 | ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL) | 1008 | ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL) |
1008 | treq->iif = inet6_iif(skb); | 1009 | ireq->ir_iif = inet6_iif(skb); |
1009 | 1010 | ||
1010 | if (!isn) { | 1011 | if (!isn) { |
1011 | if (ipv6_opt_accepted(sk, skb) || | 1012 | if (ipv6_opt_accepted(sk, skb) || |
1012 | np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || | 1013 | np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || |
1013 | np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) { | 1014 | np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) { |
1014 | atomic_inc(&skb->users); | 1015 | atomic_inc(&skb->users); |
1015 | treq->pktopts = skb; | 1016 | ireq->pktopts = skb; |
1016 | } | 1017 | } |
1017 | 1018 | ||
1018 | if (want_cookie) { | 1019 | if (want_cookie) { |
@@ -1051,7 +1052,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1051 | * to the moment of synflood. | 1052 | * to the moment of synflood. |
1052 | */ | 1053 | */ |
1053 | LIMIT_NETDEBUG(KERN_DEBUG "TCP: drop open request from %pI6/%u\n", | 1054 | LIMIT_NETDEBUG(KERN_DEBUG "TCP: drop open request from %pI6/%u\n", |
1054 | &treq->rmt_addr, ntohs(tcp_hdr(skb)->source)); | 1055 | &ireq->ir_v6_rmt_addr, ntohs(tcp_hdr(skb)->source)); |
1055 | goto drop_and_release; | 1056 | goto drop_and_release; |
1056 | } | 1057 | } |
1057 | 1058 | ||
@@ -1086,7 +1087,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
1086 | struct request_sock *req, | 1087 | struct request_sock *req, |
1087 | struct dst_entry *dst) | 1088 | struct dst_entry *dst) |
1088 | { | 1089 | { |
1089 | struct inet6_request_sock *treq; | 1090 | struct inet_request_sock *ireq; |
1090 | struct ipv6_pinfo *newnp, *np = inet6_sk(sk); | 1091 | struct ipv6_pinfo *newnp, *np = inet6_sk(sk); |
1091 | struct tcp6_sock *newtcp6sk; | 1092 | struct tcp6_sock *newtcp6sk; |
1092 | struct inet_sock *newinet; | 1093 | struct inet_sock *newinet; |
@@ -1116,11 +1117,11 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
1116 | 1117 | ||
1117 | memcpy(newnp, np, sizeof(struct ipv6_pinfo)); | 1118 | memcpy(newnp, np, sizeof(struct ipv6_pinfo)); |
1118 | 1119 | ||
1119 | ipv6_addr_set_v4mapped(newinet->inet_daddr, &newnp->daddr); | 1120 | ipv6_addr_set_v4mapped(newinet->inet_daddr, &newsk->sk_v6_daddr); |
1120 | 1121 | ||
1121 | ipv6_addr_set_v4mapped(newinet->inet_saddr, &newnp->saddr); | 1122 | ipv6_addr_set_v4mapped(newinet->inet_saddr, &newnp->saddr); |
1122 | 1123 | ||
1123 | newnp->rcv_saddr = newnp->saddr; | 1124 | newsk->sk_v6_rcv_saddr = newnp->saddr; |
1124 | 1125 | ||
1125 | inet_csk(newsk)->icsk_af_ops = &ipv6_mapped; | 1126 | inet_csk(newsk)->icsk_af_ops = &ipv6_mapped; |
1126 | newsk->sk_backlog_rcv = tcp_v4_do_rcv; | 1127 | newsk->sk_backlog_rcv = tcp_v4_do_rcv; |
@@ -1151,7 +1152,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
1151 | return newsk; | 1152 | return newsk; |
1152 | } | 1153 | } |
1153 | 1154 | ||
1154 | treq = inet6_rsk(req); | 1155 | ireq = inet_rsk(req); |
1155 | 1156 | ||
1156 | if (sk_acceptq_is_full(sk)) | 1157 | if (sk_acceptq_is_full(sk)) |
1157 | goto out_overflow; | 1158 | goto out_overflow; |
@@ -1185,10 +1186,10 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
1185 | 1186 | ||
1186 | memcpy(newnp, np, sizeof(struct ipv6_pinfo)); | 1187 | memcpy(newnp, np, sizeof(struct ipv6_pinfo)); |
1187 | 1188 | ||
1188 | newnp->daddr = treq->rmt_addr; | 1189 | newsk->sk_v6_daddr = ireq->ir_v6_rmt_addr; |
1189 | newnp->saddr = treq->loc_addr; | 1190 | newnp->saddr = ireq->ir_v6_loc_addr; |
1190 | newnp->rcv_saddr = treq->loc_addr; | 1191 | newsk->sk_v6_rcv_saddr = ireq->ir_v6_loc_addr; |
1191 | newsk->sk_bound_dev_if = treq->iif; | 1192 | newsk->sk_bound_dev_if = ireq->ir_iif; |
1192 | 1193 | ||
1193 | /* Now IPv6 options... | 1194 | /* Now IPv6 options... |
1194 | 1195 | ||
@@ -1203,11 +1204,11 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
1203 | 1204 | ||
1204 | /* Clone pktoptions received with SYN */ | 1205 | /* Clone pktoptions received with SYN */ |
1205 | newnp->pktoptions = NULL; | 1206 | newnp->pktoptions = NULL; |
1206 | if (treq->pktopts != NULL) { | 1207 | if (ireq->pktopts != NULL) { |
1207 | newnp->pktoptions = skb_clone(treq->pktopts, | 1208 | newnp->pktoptions = skb_clone(ireq->pktopts, |
1208 | sk_gfp_atomic(sk, GFP_ATOMIC)); | 1209 | sk_gfp_atomic(sk, GFP_ATOMIC)); |
1209 | consume_skb(treq->pktopts); | 1210 | consume_skb(ireq->pktopts); |
1210 | treq->pktopts = NULL; | 1211 | ireq->pktopts = NULL; |
1211 | if (newnp->pktoptions) | 1212 | if (newnp->pktoptions) |
1212 | skb_set_owner_r(newnp->pktoptions, newsk); | 1213 | skb_set_owner_r(newnp->pktoptions, newsk); |
1213 | } | 1214 | } |
@@ -1244,13 +1245,13 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
1244 | 1245 | ||
1245 | #ifdef CONFIG_TCP_MD5SIG | 1246 | #ifdef CONFIG_TCP_MD5SIG |
1246 | /* Copy over the MD5 key from the original socket */ | 1247 | /* Copy over the MD5 key from the original socket */ |
1247 | if ((key = tcp_v6_md5_do_lookup(sk, &newnp->daddr)) != NULL) { | 1248 | if ((key = tcp_v6_md5_do_lookup(sk, &newsk->sk_v6_daddr)) != NULL) { |
1248 | /* We're using one, so create a matching key | 1249 | /* We're using one, so create a matching key |
1249 | * on the newsk structure. If we fail to get | 1250 | * on the newsk structure. If we fail to get |
1250 | * memory, then we end up not copying the key | 1251 | * memory, then we end up not copying the key |
1251 | * across. Shucks. | 1252 | * across. Shucks. |
1252 | */ | 1253 | */ |
1253 | tcp_md5_do_add(newsk, (union tcp_md5_addr *)&newnp->daddr, | 1254 | tcp_md5_do_add(newsk, (union tcp_md5_addr *)&newsk->sk_v6_daddr, |
1254 | AF_INET6, key->key, key->keylen, | 1255 | AF_INET6, key->key, key->keylen, |
1255 | sk_gfp_atomic(sk, GFP_ATOMIC)); | 1256 | sk_gfp_atomic(sk, GFP_ATOMIC)); |
1256 | } | 1257 | } |
@@ -1722,8 +1723,8 @@ static void get_openreq6(struct seq_file *seq, | |||
1722 | const struct sock *sk, struct request_sock *req, int i, kuid_t uid) | 1723 | const struct sock *sk, struct request_sock *req, int i, kuid_t uid) |
1723 | { | 1724 | { |
1724 | int ttd = req->expires - jiffies; | 1725 | int ttd = req->expires - jiffies; |
1725 | const struct in6_addr *src = &inet6_rsk(req)->loc_addr; | 1726 | const struct in6_addr *src = &inet_rsk(req)->ir_v6_loc_addr; |
1726 | const struct in6_addr *dest = &inet6_rsk(req)->rmt_addr; | 1727 | const struct in6_addr *dest = &inet_rsk(req)->ir_v6_rmt_addr; |
1727 | 1728 | ||
1728 | if (ttd < 0) | 1729 | if (ttd < 0) |
1729 | ttd = 0; | 1730 | ttd = 0; |
@@ -1734,10 +1735,10 @@ static void get_openreq6(struct seq_file *seq, | |||
1734 | i, | 1735 | i, |
1735 | src->s6_addr32[0], src->s6_addr32[1], | 1736 | src->s6_addr32[0], src->s6_addr32[1], |
1736 | src->s6_addr32[2], src->s6_addr32[3], | 1737 | src->s6_addr32[2], src->s6_addr32[3], |
1737 | ntohs(inet_rsk(req)->loc_port), | 1738 | inet_rsk(req)->ir_num, |
1738 | dest->s6_addr32[0], dest->s6_addr32[1], | 1739 | dest->s6_addr32[0], dest->s6_addr32[1], |
1739 | dest->s6_addr32[2], dest->s6_addr32[3], | 1740 | dest->s6_addr32[2], dest->s6_addr32[3], |
1740 | ntohs(inet_rsk(req)->rmt_port), | 1741 | ntohs(inet_rsk(req)->ir_rmt_port), |
1741 | TCP_SYN_RECV, | 1742 | TCP_SYN_RECV, |
1742 | 0,0, /* could print option size, but that is af dependent. */ | 1743 | 0,0, /* could print option size, but that is af dependent. */ |
1743 | 1, /* timers active (only the expire timer) */ | 1744 | 1, /* timers active (only the expire timer) */ |
@@ -1758,10 +1759,9 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i) | |||
1758 | const struct inet_sock *inet = inet_sk(sp); | 1759 | const struct inet_sock *inet = inet_sk(sp); |
1759 | const struct tcp_sock *tp = tcp_sk(sp); | 1760 | const struct tcp_sock *tp = tcp_sk(sp); |
1760 | const struct inet_connection_sock *icsk = inet_csk(sp); | 1761 | const struct inet_connection_sock *icsk = inet_csk(sp); |
1761 | const struct ipv6_pinfo *np = inet6_sk(sp); | ||
1762 | 1762 | ||
1763 | dest = &np->daddr; | 1763 | dest = &sp->sk_v6_daddr; |
1764 | src = &np->rcv_saddr; | 1764 | src = &sp->sk_v6_rcv_saddr; |
1765 | destp = ntohs(inet->inet_dport); | 1765 | destp = ntohs(inet->inet_dport); |
1766 | srcp = ntohs(inet->inet_sport); | 1766 | srcp = ntohs(inet->inet_sport); |
1767 | 1767 | ||
@@ -1810,11 +1810,10 @@ static void get_timewait6_sock(struct seq_file *seq, | |||
1810 | { | 1810 | { |
1811 | const struct in6_addr *dest, *src; | 1811 | const struct in6_addr *dest, *src; |
1812 | __u16 destp, srcp; | 1812 | __u16 destp, srcp; |
1813 | const struct inet6_timewait_sock *tw6 = inet6_twsk((struct sock *)tw); | 1813 | s32 delta = tw->tw_ttd - inet_tw_time_stamp(); |
1814 | long delta = tw->tw_ttd - jiffies; | ||
1815 | 1814 | ||
1816 | dest = &tw6->tw_v6_daddr; | 1815 | dest = &tw->tw_v6_daddr; |
1817 | src = &tw6->tw_v6_rcv_saddr; | 1816 | src = &tw->tw_v6_rcv_saddr; |
1818 | destp = ntohs(tw->tw_dport); | 1817 | destp = ntohs(tw->tw_dport); |
1819 | srcp = ntohs(tw->tw_sport); | 1818 | srcp = ntohs(tw->tw_sport); |
1820 | 1819 | ||
@@ -1834,6 +1833,7 @@ static void get_timewait6_sock(struct seq_file *seq, | |||
1834 | static int tcp6_seq_show(struct seq_file *seq, void *v) | 1833 | static int tcp6_seq_show(struct seq_file *seq, void *v) |
1835 | { | 1834 | { |
1836 | struct tcp_iter_state *st; | 1835 | struct tcp_iter_state *st; |
1836 | struct sock *sk = v; | ||
1837 | 1837 | ||
1838 | if (v == SEQ_START_TOKEN) { | 1838 | if (v == SEQ_START_TOKEN) { |
1839 | seq_puts(seq, | 1839 | seq_puts(seq, |
@@ -1849,14 +1849,14 @@ static int tcp6_seq_show(struct seq_file *seq, void *v) | |||
1849 | switch (st->state) { | 1849 | switch (st->state) { |
1850 | case TCP_SEQ_STATE_LISTENING: | 1850 | case TCP_SEQ_STATE_LISTENING: |
1851 | case TCP_SEQ_STATE_ESTABLISHED: | 1851 | case TCP_SEQ_STATE_ESTABLISHED: |
1852 | get_tcp6_sock(seq, v, st->num); | 1852 | if (sk->sk_state == TCP_TIME_WAIT) |
1853 | get_timewait6_sock(seq, v, st->num); | ||
1854 | else | ||
1855 | get_tcp6_sock(seq, v, st->num); | ||
1853 | break; | 1856 | break; |
1854 | case TCP_SEQ_STATE_OPENREQ: | 1857 | case TCP_SEQ_STATE_OPENREQ: |
1855 | get_openreq6(seq, st->syn_wait_sk, v, st->num, st->uid); | 1858 | get_openreq6(seq, st->syn_wait_sk, v, st->num, st->uid); |
1856 | break; | 1859 | break; |
1857 | case TCP_SEQ_STATE_TIME_WAIT: | ||
1858 | get_timewait6_sock(seq, v, st->num); | ||
1859 | break; | ||
1860 | } | 1860 | } |
1861 | out: | 1861 | out: |
1862 | return 0; | 1862 | return 0; |
@@ -1929,6 +1929,7 @@ struct proto tcpv6_prot = { | |||
1929 | .memory_allocated = &tcp_memory_allocated, | 1929 | .memory_allocated = &tcp_memory_allocated, |
1930 | .memory_pressure = &tcp_memory_pressure, | 1930 | .memory_pressure = &tcp_memory_pressure, |
1931 | .orphan_count = &tcp_orphan_count, | 1931 | .orphan_count = &tcp_orphan_count, |
1932 | .sysctl_mem = sysctl_tcp_mem, | ||
1932 | .sysctl_wmem = sysctl_tcp_wmem, | 1933 | .sysctl_wmem = sysctl_tcp_wmem, |
1933 | .sysctl_rmem = sysctl_tcp_rmem, | 1934 | .sysctl_rmem = sysctl_tcp_rmem, |
1934 | .max_header = MAX_TCP_HEADER, | 1935 | .max_header = MAX_TCP_HEADER, |
diff --git a/net/ipv6/tcpv6_offload.c b/net/ipv6/tcpv6_offload.c index 2ec6bf6a0aa0..c1097c798900 100644 --- a/net/ipv6/tcpv6_offload.c +++ b/net/ipv6/tcpv6_offload.c | |||
@@ -83,7 +83,7 @@ static int tcp6_gro_complete(struct sk_buff *skb) | |||
83 | static const struct net_offload tcpv6_offload = { | 83 | static const struct net_offload tcpv6_offload = { |
84 | .callbacks = { | 84 | .callbacks = { |
85 | .gso_send_check = tcp_v6_gso_send_check, | 85 | .gso_send_check = tcp_v6_gso_send_check, |
86 | .gso_segment = tcp_tso_segment, | 86 | .gso_segment = tcp_gso_segment, |
87 | .gro_receive = tcp6_gro_receive, | 87 | .gro_receive = tcp6_gro_receive, |
88 | .gro_complete = tcp6_gro_complete, | 88 | .gro_complete = tcp6_gro_complete, |
89 | }, | 89 | }, |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 18786098fd41..f3893e897f72 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -53,22 +53,42 @@ | |||
53 | #include <trace/events/skb.h> | 53 | #include <trace/events/skb.h> |
54 | #include "udp_impl.h" | 54 | #include "udp_impl.h" |
55 | 55 | ||
56 | static unsigned int udp6_ehashfn(struct net *net, | ||
57 | const struct in6_addr *laddr, | ||
58 | const u16 lport, | ||
59 | const struct in6_addr *faddr, | ||
60 | const __be16 fport) | ||
61 | { | ||
62 | static u32 udp6_ehash_secret __read_mostly; | ||
63 | static u32 udp_ipv6_hash_secret __read_mostly; | ||
64 | |||
65 | u32 lhash, fhash; | ||
66 | |||
67 | net_get_random_once(&udp6_ehash_secret, | ||
68 | sizeof(udp6_ehash_secret)); | ||
69 | net_get_random_once(&udp_ipv6_hash_secret, | ||
70 | sizeof(udp_ipv6_hash_secret)); | ||
71 | |||
72 | lhash = (__force u32)laddr->s6_addr32[3]; | ||
73 | fhash = __ipv6_addr_jhash(faddr, udp_ipv6_hash_secret); | ||
74 | |||
75 | return __inet6_ehashfn(lhash, lport, fhash, fport, | ||
76 | udp_ipv6_hash_secret + net_hash_mix(net)); | ||
77 | } | ||
78 | |||
56 | int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) | 79 | int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) |
57 | { | 80 | { |
58 | const struct in6_addr *sk_rcv_saddr6 = &inet6_sk(sk)->rcv_saddr; | ||
59 | const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2); | 81 | const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2); |
60 | __be32 sk1_rcv_saddr = sk_rcv_saddr(sk); | ||
61 | __be32 sk2_rcv_saddr = sk_rcv_saddr(sk2); | ||
62 | int sk_ipv6only = ipv6_only_sock(sk); | 82 | int sk_ipv6only = ipv6_only_sock(sk); |
63 | int sk2_ipv6only = inet_v6_ipv6only(sk2); | 83 | int sk2_ipv6only = inet_v6_ipv6only(sk2); |
64 | int addr_type = ipv6_addr_type(sk_rcv_saddr6); | 84 | int addr_type = ipv6_addr_type(&sk->sk_v6_rcv_saddr); |
65 | int addr_type2 = sk2_rcv_saddr6 ? ipv6_addr_type(sk2_rcv_saddr6) : IPV6_ADDR_MAPPED; | 85 | int addr_type2 = sk2_rcv_saddr6 ? ipv6_addr_type(sk2_rcv_saddr6) : IPV6_ADDR_MAPPED; |
66 | 86 | ||
67 | /* if both are mapped, treat as IPv4 */ | 87 | /* if both are mapped, treat as IPv4 */ |
68 | if (addr_type == IPV6_ADDR_MAPPED && addr_type2 == IPV6_ADDR_MAPPED) | 88 | if (addr_type == IPV6_ADDR_MAPPED && addr_type2 == IPV6_ADDR_MAPPED) |
69 | return (!sk2_ipv6only && | 89 | return (!sk2_ipv6only && |
70 | (!sk1_rcv_saddr || !sk2_rcv_saddr || | 90 | (!sk->sk_rcv_saddr || !sk2->sk_rcv_saddr || |
71 | sk1_rcv_saddr == sk2_rcv_saddr)); | 91 | sk->sk_rcv_saddr == sk2->sk_rcv_saddr)); |
72 | 92 | ||
73 | if (addr_type2 == IPV6_ADDR_ANY && | 93 | if (addr_type2 == IPV6_ADDR_ANY && |
74 | !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED)) | 94 | !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED)) |
@@ -79,7 +99,7 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) | |||
79 | return 1; | 99 | return 1; |
80 | 100 | ||
81 | if (sk2_rcv_saddr6 && | 101 | if (sk2_rcv_saddr6 && |
82 | ipv6_addr_equal(sk_rcv_saddr6, sk2_rcv_saddr6)) | 102 | ipv6_addr_equal(&sk->sk_v6_rcv_saddr, sk2_rcv_saddr6)) |
83 | return 1; | 103 | return 1; |
84 | 104 | ||
85 | return 0; | 105 | return 0; |
@@ -107,7 +127,7 @@ int udp_v6_get_port(struct sock *sk, unsigned short snum) | |||
107 | unsigned int hash2_nulladdr = | 127 | unsigned int hash2_nulladdr = |
108 | udp6_portaddr_hash(sock_net(sk), &in6addr_any, snum); | 128 | udp6_portaddr_hash(sock_net(sk), &in6addr_any, snum); |
109 | unsigned int hash2_partial = | 129 | unsigned int hash2_partial = |
110 | udp6_portaddr_hash(sock_net(sk), &inet6_sk(sk)->rcv_saddr, 0); | 130 | udp6_portaddr_hash(sock_net(sk), &sk->sk_v6_rcv_saddr, 0); |
111 | 131 | ||
112 | /* precompute partial secondary hash */ | 132 | /* precompute partial secondary hash */ |
113 | udp_sk(sk)->udp_portaddr_hash = hash2_partial; | 133 | udp_sk(sk)->udp_portaddr_hash = hash2_partial; |
@@ -117,7 +137,7 @@ int udp_v6_get_port(struct sock *sk, unsigned short snum) | |||
117 | static void udp_v6_rehash(struct sock *sk) | 137 | static void udp_v6_rehash(struct sock *sk) |
118 | { | 138 | { |
119 | u16 new_hash = udp6_portaddr_hash(sock_net(sk), | 139 | u16 new_hash = udp6_portaddr_hash(sock_net(sk), |
120 | &inet6_sk(sk)->rcv_saddr, | 140 | &sk->sk_v6_rcv_saddr, |
121 | inet_sk(sk)->inet_num); | 141 | inet_sk(sk)->inet_num); |
122 | 142 | ||
123 | udp_lib_rehash(sk, new_hash); | 143 | udp_lib_rehash(sk, new_hash); |
@@ -133,7 +153,6 @@ static inline int compute_score(struct sock *sk, struct net *net, | |||
133 | 153 | ||
134 | if (net_eq(sock_net(sk), net) && udp_sk(sk)->udp_port_hash == hnum && | 154 | if (net_eq(sock_net(sk), net) && udp_sk(sk)->udp_port_hash == hnum && |
135 | sk->sk_family == PF_INET6) { | 155 | sk->sk_family == PF_INET6) { |
136 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
137 | struct inet_sock *inet = inet_sk(sk); | 156 | struct inet_sock *inet = inet_sk(sk); |
138 | 157 | ||
139 | score = 0; | 158 | score = 0; |
@@ -142,13 +161,13 @@ static inline int compute_score(struct sock *sk, struct net *net, | |||
142 | return -1; | 161 | return -1; |
143 | score++; | 162 | score++; |
144 | } | 163 | } |
145 | if (!ipv6_addr_any(&np->rcv_saddr)) { | 164 | if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr)) { |
146 | if (!ipv6_addr_equal(&np->rcv_saddr, daddr)) | 165 | if (!ipv6_addr_equal(&sk->sk_v6_rcv_saddr, daddr)) |
147 | return -1; | 166 | return -1; |
148 | score++; | 167 | score++; |
149 | } | 168 | } |
150 | if (!ipv6_addr_any(&np->daddr)) { | 169 | if (!ipv6_addr_any(&sk->sk_v6_daddr)) { |
151 | if (!ipv6_addr_equal(&np->daddr, saddr)) | 170 | if (!ipv6_addr_equal(&sk->sk_v6_daddr, saddr)) |
152 | return -1; | 171 | return -1; |
153 | score++; | 172 | score++; |
154 | } | 173 | } |
@@ -171,10 +190,9 @@ static inline int compute_score2(struct sock *sk, struct net *net, | |||
171 | 190 | ||
172 | if (net_eq(sock_net(sk), net) && udp_sk(sk)->udp_port_hash == hnum && | 191 | if (net_eq(sock_net(sk), net) && udp_sk(sk)->udp_port_hash == hnum && |
173 | sk->sk_family == PF_INET6) { | 192 | sk->sk_family == PF_INET6) { |
174 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
175 | struct inet_sock *inet = inet_sk(sk); | 193 | struct inet_sock *inet = inet_sk(sk); |
176 | 194 | ||
177 | if (!ipv6_addr_equal(&np->rcv_saddr, daddr)) | 195 | if (!ipv6_addr_equal(&sk->sk_v6_rcv_saddr, daddr)) |
178 | return -1; | 196 | return -1; |
179 | score = 0; | 197 | score = 0; |
180 | if (inet->inet_dport) { | 198 | if (inet->inet_dport) { |
@@ -182,8 +200,8 @@ static inline int compute_score2(struct sock *sk, struct net *net, | |||
182 | return -1; | 200 | return -1; |
183 | score++; | 201 | score++; |
184 | } | 202 | } |
185 | if (!ipv6_addr_any(&np->daddr)) { | 203 | if (!ipv6_addr_any(&sk->sk_v6_daddr)) { |
186 | if (!ipv6_addr_equal(&np->daddr, saddr)) | 204 | if (!ipv6_addr_equal(&sk->sk_v6_daddr, saddr)) |
187 | return -1; | 205 | return -1; |
188 | score++; | 206 | score++; |
189 | } | 207 | } |
@@ -219,8 +237,8 @@ begin: | |||
219 | badness = score; | 237 | badness = score; |
220 | reuseport = sk->sk_reuseport; | 238 | reuseport = sk->sk_reuseport; |
221 | if (reuseport) { | 239 | if (reuseport) { |
222 | hash = inet6_ehashfn(net, daddr, hnum, | 240 | hash = udp6_ehashfn(net, daddr, hnum, |
223 | saddr, sport); | 241 | saddr, sport); |
224 | matches = 1; | 242 | matches = 1; |
225 | } else if (score == SCORE2_MAX) | 243 | } else if (score == SCORE2_MAX) |
226 | goto exact_match; | 244 | goto exact_match; |
@@ -300,8 +318,8 @@ begin: | |||
300 | badness = score; | 318 | badness = score; |
301 | reuseport = sk->sk_reuseport; | 319 | reuseport = sk->sk_reuseport; |
302 | if (reuseport) { | 320 | if (reuseport) { |
303 | hash = inet6_ehashfn(net, daddr, hnum, | 321 | hash = udp6_ehashfn(net, daddr, hnum, |
304 | saddr, sport); | 322 | saddr, sport); |
305 | matches = 1; | 323 | matches = 1; |
306 | } | 324 | } |
307 | } else if (score == badness && reuseport) { | 325 | } else if (score == badness && reuseport) { |
@@ -551,8 +569,10 @@ static int __udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
551 | { | 569 | { |
552 | int rc; | 570 | int rc; |
553 | 571 | ||
554 | if (!ipv6_addr_any(&inet6_sk(sk)->daddr)) | 572 | if (!ipv6_addr_any(&sk->sk_v6_daddr)) { |
555 | sock_rps_save_rxhash(sk, skb); | 573 | sock_rps_save_rxhash(sk, skb); |
574 | sk_mark_napi_id(sk, skb); | ||
575 | } | ||
556 | 576 | ||
557 | rc = sock_queue_rcv_skb(sk, skb); | 577 | rc = sock_queue_rcv_skb(sk, skb); |
558 | if (rc < 0) { | 578 | if (rc < 0) { |
@@ -690,20 +710,19 @@ static struct sock *udp_v6_mcast_next(struct net *net, struct sock *sk, | |||
690 | 710 | ||
691 | if (udp_sk(s)->udp_port_hash == num && | 711 | if (udp_sk(s)->udp_port_hash == num && |
692 | s->sk_family == PF_INET6) { | 712 | s->sk_family == PF_INET6) { |
693 | struct ipv6_pinfo *np = inet6_sk(s); | ||
694 | if (inet->inet_dport) { | 713 | if (inet->inet_dport) { |
695 | if (inet->inet_dport != rmt_port) | 714 | if (inet->inet_dport != rmt_port) |
696 | continue; | 715 | continue; |
697 | } | 716 | } |
698 | if (!ipv6_addr_any(&np->daddr) && | 717 | if (!ipv6_addr_any(&sk->sk_v6_daddr) && |
699 | !ipv6_addr_equal(&np->daddr, rmt_addr)) | 718 | !ipv6_addr_equal(&sk->sk_v6_daddr, rmt_addr)) |
700 | continue; | 719 | continue; |
701 | 720 | ||
702 | if (s->sk_bound_dev_if && s->sk_bound_dev_if != dif) | 721 | if (s->sk_bound_dev_if && s->sk_bound_dev_if != dif) |
703 | continue; | 722 | continue; |
704 | 723 | ||
705 | if (!ipv6_addr_any(&np->rcv_saddr)) { | 724 | if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr)) { |
706 | if (!ipv6_addr_equal(&np->rcv_saddr, loc_addr)) | 725 | if (!ipv6_addr_equal(&sk->sk_v6_rcv_saddr, loc_addr)) |
707 | continue; | 726 | continue; |
708 | } | 727 | } |
709 | if (!inet6_mc_check(s, loc_addr, rmt_addr)) | 728 | if (!inet6_mc_check(s, loc_addr, rmt_addr)) |
@@ -846,7 +865,6 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, | |||
846 | if (sk != NULL) { | 865 | if (sk != NULL) { |
847 | int ret; | 866 | int ret; |
848 | 867 | ||
849 | sk_mark_napi_id(sk, skb); | ||
850 | ret = udpv6_queue_rcv_skb(sk, skb); | 868 | ret = udpv6_queue_rcv_skb(sk, skb); |
851 | sock_put(sk); | 869 | sock_put(sk); |
852 | 870 | ||
@@ -1064,7 +1082,7 @@ int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
1064 | } else if (!up->pending) { | 1082 | } else if (!up->pending) { |
1065 | if (sk->sk_state != TCP_ESTABLISHED) | 1083 | if (sk->sk_state != TCP_ESTABLISHED) |
1066 | return -EDESTADDRREQ; | 1084 | return -EDESTADDRREQ; |
1067 | daddr = &np->daddr; | 1085 | daddr = &sk->sk_v6_daddr; |
1068 | } else | 1086 | } else |
1069 | daddr = NULL; | 1087 | daddr = NULL; |
1070 | 1088 | ||
@@ -1134,8 +1152,8 @@ do_udp_sendmsg: | |||
1134 | * sk->sk_dst_cache. | 1152 | * sk->sk_dst_cache. |
1135 | */ | 1153 | */ |
1136 | if (sk->sk_state == TCP_ESTABLISHED && | 1154 | if (sk->sk_state == TCP_ESTABLISHED && |
1137 | ipv6_addr_equal(daddr, &np->daddr)) | 1155 | ipv6_addr_equal(daddr, &sk->sk_v6_daddr)) |
1138 | daddr = &np->daddr; | 1156 | daddr = &sk->sk_v6_daddr; |
1139 | 1157 | ||
1140 | if (addr_len >= sizeof(struct sockaddr_in6) && | 1158 | if (addr_len >= sizeof(struct sockaddr_in6) && |
1141 | sin6->sin6_scope_id && | 1159 | sin6->sin6_scope_id && |
@@ -1146,7 +1164,7 @@ do_udp_sendmsg: | |||
1146 | return -EDESTADDRREQ; | 1164 | return -EDESTADDRREQ; |
1147 | 1165 | ||
1148 | fl6.fl6_dport = inet->inet_dport; | 1166 | fl6.fl6_dport = inet->inet_dport; |
1149 | daddr = &np->daddr; | 1167 | daddr = &sk->sk_v6_daddr; |
1150 | fl6.flowlabel = np->flow_label; | 1168 | fl6.flowlabel = np->flow_label; |
1151 | connected = 1; | 1169 | connected = 1; |
1152 | } | 1170 | } |
@@ -1261,8 +1279,8 @@ do_append_data: | |||
1261 | if (dst) { | 1279 | if (dst) { |
1262 | if (connected) { | 1280 | if (connected) { |
1263 | ip6_dst_store(sk, dst, | 1281 | ip6_dst_store(sk, dst, |
1264 | ipv6_addr_equal(&fl6.daddr, &np->daddr) ? | 1282 | ipv6_addr_equal(&fl6.daddr, &sk->sk_v6_daddr) ? |
1265 | &np->daddr : NULL, | 1283 | &sk->sk_v6_daddr : NULL, |
1266 | #ifdef CONFIG_IPV6_SUBTREES | 1284 | #ifdef CONFIG_IPV6_SUBTREES |
1267 | ipv6_addr_equal(&fl6.saddr, &np->saddr) ? | 1285 | ipv6_addr_equal(&fl6.saddr, &np->saddr) ? |
1268 | &np->saddr : | 1286 | &np->saddr : |
diff --git a/net/ipv6/udp_impl.h b/net/ipv6/udp_impl.h index 4691ed50a928..c779c3c90b9d 100644 --- a/net/ipv6/udp_impl.h +++ b/net/ipv6/udp_impl.h | |||
@@ -7,33 +7,32 @@ | |||
7 | #include <net/inet_common.h> | 7 | #include <net/inet_common.h> |
8 | #include <net/transp_v6.h> | 8 | #include <net/transp_v6.h> |
9 | 9 | ||
10 | extern int __udp6_lib_rcv(struct sk_buff *, struct udp_table *, int ); | 10 | int __udp6_lib_rcv(struct sk_buff *, struct udp_table *, int); |
11 | extern void __udp6_lib_err(struct sk_buff *, struct inet6_skb_parm *, | 11 | void __udp6_lib_err(struct sk_buff *, struct inet6_skb_parm *, u8, u8, int, |
12 | u8 , u8 , int , __be32 , struct udp_table *); | 12 | __be32, struct udp_table *); |
13 | 13 | ||
14 | extern int udp_v6_get_port(struct sock *sk, unsigned short snum); | 14 | int udp_v6_get_port(struct sock *sk, unsigned short snum); |
15 | 15 | ||
16 | extern int udpv6_getsockopt(struct sock *sk, int level, int optname, | 16 | int udpv6_getsockopt(struct sock *sk, int level, int optname, |
17 | char __user *optval, int __user *optlen); | 17 | char __user *optval, int __user *optlen); |
18 | extern int udpv6_setsockopt(struct sock *sk, int level, int optname, | 18 | int udpv6_setsockopt(struct sock *sk, int level, int optname, |
19 | char __user *optval, unsigned int optlen); | 19 | char __user *optval, unsigned int optlen); |
20 | #ifdef CONFIG_COMPAT | 20 | #ifdef CONFIG_COMPAT |
21 | extern int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, | 21 | int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, |
22 | char __user *optval, unsigned int optlen); | 22 | char __user *optval, unsigned int optlen); |
23 | extern int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, | 23 | int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, |
24 | char __user *optval, int __user *optlen); | 24 | char __user *optval, int __user *optlen); |
25 | #endif | 25 | #endif |
26 | extern int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, | 26 | int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, |
27 | struct msghdr *msg, size_t len); | 27 | size_t len); |
28 | extern int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, | 28 | int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, |
29 | struct msghdr *msg, size_t len, | 29 | size_t len, int noblock, int flags, int *addr_len); |
30 | int noblock, int flags, int *addr_len); | 30 | int udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb); |
31 | extern int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb); | 31 | void udpv6_destroy_sock(struct sock *sk); |
32 | extern void udpv6_destroy_sock(struct sock *sk); | ||
33 | 32 | ||
34 | extern void udp_v6_clear_sk(struct sock *sk, int size); | 33 | void udp_v6_clear_sk(struct sock *sk, int size); |
35 | 34 | ||
36 | #ifdef CONFIG_PROC_FS | 35 | #ifdef CONFIG_PROC_FS |
37 | extern int udp6_seq_show(struct seq_file *seq, void *v); | 36 | int udp6_seq_show(struct seq_file *seq, void *v); |
38 | #endif | 37 | #endif |
39 | #endif /* _UDP6_IMPL_H */ | 38 | #endif /* _UDP6_IMPL_H */ |
diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c index 60559511bd9c..e7359f9eaa8d 100644 --- a/net/ipv6/udp_offload.c +++ b/net/ipv6/udp_offload.c | |||
@@ -64,6 +64,8 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, | |||
64 | SKB_GSO_DODGY | | 64 | SKB_GSO_DODGY | |
65 | SKB_GSO_UDP_TUNNEL | | 65 | SKB_GSO_UDP_TUNNEL | |
66 | SKB_GSO_GRE | | 66 | SKB_GSO_GRE | |
67 | SKB_GSO_IPIP | | ||
68 | SKB_GSO_SIT | | ||
67 | SKB_GSO_MPLS) || | 69 | SKB_GSO_MPLS) || |
68 | !(type & (SKB_GSO_UDP)))) | 70 | !(type & (SKB_GSO_UDP)))) |
69 | goto out; | 71 | goto out; |
@@ -88,7 +90,7 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, | |||
88 | 90 | ||
89 | /* Check if there is enough headroom to insert fragment header. */ | 91 | /* Check if there is enough headroom to insert fragment header. */ |
90 | tnl_hlen = skb_tnl_header_len(skb); | 92 | tnl_hlen = skb_tnl_header_len(skb); |
91 | if (skb_headroom(skb) < (tnl_hlen + frag_hdr_sz)) { | 93 | if (skb->mac_header < (tnl_hlen + frag_hdr_sz)) { |
92 | if (gso_pskb_expand_head(skb, tnl_hlen + frag_hdr_sz)) | 94 | if (gso_pskb_expand_head(skb, tnl_hlen + frag_hdr_sz)) |
93 | goto out; | 95 | goto out; |
94 | } | 96 | } |
diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c index 4770d515c2c8..cb04f7a16b5e 100644 --- a/net/ipv6/xfrm6_mode_tunnel.c +++ b/net/ipv6/xfrm6_mode_tunnel.c | |||
@@ -18,6 +18,65 @@ | |||
18 | #include <net/ipv6.h> | 18 | #include <net/ipv6.h> |
19 | #include <net/xfrm.h> | 19 | #include <net/xfrm.h> |
20 | 20 | ||
21 | /* Informational hook. The decap is still done here. */ | ||
22 | static struct xfrm_tunnel_notifier __rcu *rcv_notify_handlers __read_mostly; | ||
23 | static DEFINE_MUTEX(xfrm6_mode_tunnel_input_mutex); | ||
24 | |||
25 | int xfrm6_mode_tunnel_input_register(struct xfrm_tunnel_notifier *handler) | ||
26 | { | ||
27 | struct xfrm_tunnel_notifier __rcu **pprev; | ||
28 | struct xfrm_tunnel_notifier *t; | ||
29 | int ret = -EEXIST; | ||
30 | int priority = handler->priority; | ||
31 | |||
32 | mutex_lock(&xfrm6_mode_tunnel_input_mutex); | ||
33 | |||
34 | for (pprev = &rcv_notify_handlers; | ||
35 | (t = rcu_dereference_protected(*pprev, | ||
36 | lockdep_is_held(&xfrm6_mode_tunnel_input_mutex))) != NULL; | ||
37 | pprev = &t->next) { | ||
38 | if (t->priority > priority) | ||
39 | break; | ||
40 | if (t->priority == priority) | ||
41 | goto err; | ||
42 | |||
43 | } | ||
44 | |||
45 | handler->next = *pprev; | ||
46 | rcu_assign_pointer(*pprev, handler); | ||
47 | |||
48 | ret = 0; | ||
49 | |||
50 | err: | ||
51 | mutex_unlock(&xfrm6_mode_tunnel_input_mutex); | ||
52 | return ret; | ||
53 | } | ||
54 | EXPORT_SYMBOL_GPL(xfrm6_mode_tunnel_input_register); | ||
55 | |||
56 | int xfrm6_mode_tunnel_input_deregister(struct xfrm_tunnel_notifier *handler) | ||
57 | { | ||
58 | struct xfrm_tunnel_notifier __rcu **pprev; | ||
59 | struct xfrm_tunnel_notifier *t; | ||
60 | int ret = -ENOENT; | ||
61 | |||
62 | mutex_lock(&xfrm6_mode_tunnel_input_mutex); | ||
63 | for (pprev = &rcv_notify_handlers; | ||
64 | (t = rcu_dereference_protected(*pprev, | ||
65 | lockdep_is_held(&xfrm6_mode_tunnel_input_mutex))) != NULL; | ||
66 | pprev = &t->next) { | ||
67 | if (t == handler) { | ||
68 | *pprev = handler->next; | ||
69 | ret = 0; | ||
70 | break; | ||
71 | } | ||
72 | } | ||
73 | mutex_unlock(&xfrm6_mode_tunnel_input_mutex); | ||
74 | synchronize_net(); | ||
75 | |||
76 | return ret; | ||
77 | } | ||
78 | EXPORT_SYMBOL_GPL(xfrm6_mode_tunnel_input_deregister); | ||
79 | |||
21 | static inline void ipip6_ecn_decapsulate(struct sk_buff *skb) | 80 | static inline void ipip6_ecn_decapsulate(struct sk_buff *skb) |
22 | { | 81 | { |
23 | const struct ipv6hdr *outer_iph = ipv6_hdr(skb); | 82 | const struct ipv6hdr *outer_iph = ipv6_hdr(skb); |
@@ -63,8 +122,15 @@ static int xfrm6_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) | |||
63 | return 0; | 122 | return 0; |
64 | } | 123 | } |
65 | 124 | ||
125 | #define for_each_input_rcu(head, handler) \ | ||
126 | for (handler = rcu_dereference(head); \ | ||
127 | handler != NULL; \ | ||
128 | handler = rcu_dereference(handler->next)) | ||
129 | |||
130 | |||
66 | static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) | 131 | static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) |
67 | { | 132 | { |
133 | struct xfrm_tunnel_notifier *handler; | ||
68 | int err = -EINVAL; | 134 | int err = -EINVAL; |
69 | 135 | ||
70 | if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPV6) | 136 | if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPV6) |
@@ -72,6 +138,9 @@ static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) | |||
72 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) | 138 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) |
73 | goto out; | 139 | goto out; |
74 | 140 | ||
141 | for_each_input_rcu(rcv_notify_handlers, handler) | ||
142 | handler->handler(skb); | ||
143 | |||
75 | err = skb_unclone(skb, GFP_ATOMIC); | 144 | err = skb_unclone(skb, GFP_ATOMIC); |
76 | if (err) | 145 | if (err) |
77 | goto out; | 146 | goto out; |