diff options
Diffstat (limited to 'net/ipv6')
30 files changed, 3397 insertions, 228 deletions
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index 5728695b5449..4f7fe7270e37 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig | |||
@@ -201,6 +201,22 @@ config IPV6_TUNNEL | |||
201 | 201 | ||
202 | If unsure, say N. | 202 | If unsure, say N. |
203 | 203 | ||
204 | config IPV6_GRE | ||
205 | tristate "IPv6: GRE tunnel" | ||
206 | select IPV6_TUNNEL | ||
207 | ---help--- | ||
208 | Tunneling means encapsulating data of one protocol type within | ||
209 | another protocol and sending it over a channel that understands the | ||
210 | encapsulating protocol. This particular tunneling driver implements | ||
211 | GRE (Generic Routing Encapsulation) and at this time allows | ||
212 | encapsulating of IPv4 or IPv6 over existing IPv6 infrastructure. | ||
213 | This driver is useful if the other endpoint is a Cisco router: Cisco | ||
214 | likes GRE much better than the other Linux tunneling driver ("IP | ||
215 | tunneling" above). In addition, GRE allows multicast redistribution | ||
216 | through the tunnel. | ||
217 | |||
218 | Saying M here will produce a module called ip6_gre. If unsure, say N. | ||
219 | |||
204 | config IPV6_MULTIPLE_TABLES | 220 | config IPV6_MULTIPLE_TABLES |
205 | bool "IPv6: Multiple Routing Tables" | 221 | bool "IPv6: Multiple Routing Tables" |
206 | depends on EXPERIMENTAL | 222 | depends on EXPERIMENTAL |
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index 686934acfac1..b6d3f79151e2 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile | |||
@@ -36,6 +36,7 @@ obj-$(CONFIG_NETFILTER) += netfilter/ | |||
36 | 36 | ||
37 | obj-$(CONFIG_IPV6_SIT) += sit.o | 37 | obj-$(CONFIG_IPV6_SIT) += sit.o |
38 | obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o | 38 | obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o |
39 | obj-$(CONFIG_IPV6_GRE) += ip6_gre.o | ||
39 | 40 | ||
40 | obj-y += addrconf_core.o exthdrs_core.o | 41 | obj-y += addrconf_core.o exthdrs_core.o |
41 | 42 | ||
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 6bc85f7c31e3..719a828fb67f 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -127,8 +127,8 @@ static inline void addrconf_sysctl_unregister(struct inet6_dev *idev) | |||
127 | #endif | 127 | #endif |
128 | 128 | ||
129 | #ifdef CONFIG_IPV6_PRIVACY | 129 | #ifdef CONFIG_IPV6_PRIVACY |
130 | static int __ipv6_regen_rndid(struct inet6_dev *idev); | 130 | static void __ipv6_regen_rndid(struct inet6_dev *idev); |
131 | static int __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr); | 131 | static void __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr); |
132 | static void ipv6_regen_rndid(unsigned long data); | 132 | static void ipv6_regen_rndid(unsigned long data); |
133 | #endif | 133 | #endif |
134 | 134 | ||
@@ -852,16 +852,7 @@ retry: | |||
852 | } | 852 | } |
853 | in6_ifa_hold(ifp); | 853 | in6_ifa_hold(ifp); |
854 | memcpy(addr.s6_addr, ifp->addr.s6_addr, 8); | 854 | memcpy(addr.s6_addr, ifp->addr.s6_addr, 8); |
855 | if (__ipv6_try_regen_rndid(idev, tmpaddr) < 0) { | 855 | __ipv6_try_regen_rndid(idev, tmpaddr); |
856 | spin_unlock_bh(&ifp->lock); | ||
857 | write_unlock(&idev->lock); | ||
858 | pr_warn("%s: regeneration of randomized interface id failed\n", | ||
859 | __func__); | ||
860 | in6_ifa_put(ifp); | ||
861 | in6_dev_put(idev); | ||
862 | ret = -1; | ||
863 | goto out; | ||
864 | } | ||
865 | memcpy(&addr.s6_addr[8], idev->rndid, 8); | 856 | memcpy(&addr.s6_addr[8], idev->rndid, 8); |
866 | age = (now - ifp->tstamp) / HZ; | 857 | age = (now - ifp->tstamp) / HZ; |
867 | tmp_valid_lft = min_t(__u32, | 858 | tmp_valid_lft = min_t(__u32, |
@@ -1079,8 +1070,10 @@ static int ipv6_get_saddr_eval(struct net *net, | |||
1079 | break; | 1070 | break; |
1080 | case IPV6_SADDR_RULE_PREFIX: | 1071 | case IPV6_SADDR_RULE_PREFIX: |
1081 | /* Rule 8: Use longest matching prefix */ | 1072 | /* Rule 8: Use longest matching prefix */ |
1082 | score->matchlen = ret = ipv6_addr_diff(&score->ifa->addr, | 1073 | ret = ipv6_addr_diff(&score->ifa->addr, dst->addr); |
1083 | dst->addr); | 1074 | if (ret > score->ifa->prefix_len) |
1075 | ret = score->ifa->prefix_len; | ||
1076 | score->matchlen = ret; | ||
1084 | break; | 1077 | break; |
1085 | default: | 1078 | default: |
1086 | ret = 0; | 1079 | ret = 0; |
@@ -1093,7 +1086,7 @@ out: | |||
1093 | return ret; | 1086 | return ret; |
1094 | } | 1087 | } |
1095 | 1088 | ||
1096 | int ipv6_dev_get_saddr(struct net *net, struct net_device *dst_dev, | 1089 | int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev, |
1097 | const struct in6_addr *daddr, unsigned int prefs, | 1090 | const struct in6_addr *daddr, unsigned int prefs, |
1098 | struct in6_addr *saddr) | 1091 | struct in6_addr *saddr) |
1099 | { | 1092 | { |
@@ -1600,7 +1593,7 @@ static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev) | |||
1600 | 1593 | ||
1601 | #ifdef CONFIG_IPV6_PRIVACY | 1594 | #ifdef CONFIG_IPV6_PRIVACY |
1602 | /* (re)generation of randomized interface identifier (RFC 3041 3.2, 3.5) */ | 1595 | /* (re)generation of randomized interface identifier (RFC 3041 3.2, 3.5) */ |
1603 | static int __ipv6_regen_rndid(struct inet6_dev *idev) | 1596 | static void __ipv6_regen_rndid(struct inet6_dev *idev) |
1604 | { | 1597 | { |
1605 | regen: | 1598 | regen: |
1606 | get_random_bytes(idev->rndid, sizeof(idev->rndid)); | 1599 | get_random_bytes(idev->rndid, sizeof(idev->rndid)); |
@@ -1627,8 +1620,6 @@ regen: | |||
1627 | if ((idev->rndid[2]|idev->rndid[3]|idev->rndid[4]|idev->rndid[5]|idev->rndid[6]|idev->rndid[7]) == 0x00) | 1620 | if ((idev->rndid[2]|idev->rndid[3]|idev->rndid[4]|idev->rndid[5]|idev->rndid[6]|idev->rndid[7]) == 0x00) |
1628 | goto regen; | 1621 | goto regen; |
1629 | } | 1622 | } |
1630 | |||
1631 | return 0; | ||
1632 | } | 1623 | } |
1633 | 1624 | ||
1634 | static void ipv6_regen_rndid(unsigned long data) | 1625 | static void ipv6_regen_rndid(unsigned long data) |
@@ -1642,8 +1633,7 @@ static void ipv6_regen_rndid(unsigned long data) | |||
1642 | if (idev->dead) | 1633 | if (idev->dead) |
1643 | goto out; | 1634 | goto out; |
1644 | 1635 | ||
1645 | if (__ipv6_regen_rndid(idev) < 0) | 1636 | __ipv6_regen_rndid(idev); |
1646 | goto out; | ||
1647 | 1637 | ||
1648 | expires = jiffies + | 1638 | expires = jiffies + |
1649 | idev->cnf.temp_prefered_lft * HZ - | 1639 | idev->cnf.temp_prefered_lft * HZ - |
@@ -1664,13 +1654,10 @@ out: | |||
1664 | in6_dev_put(idev); | 1654 | in6_dev_put(idev); |
1665 | } | 1655 | } |
1666 | 1656 | ||
1667 | static int __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr) | 1657 | static void __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr) |
1668 | { | 1658 | { |
1669 | int ret = 0; | ||
1670 | |||
1671 | if (tmpaddr && memcmp(idev->rndid, &tmpaddr->s6_addr[8], 8) == 0) | 1659 | if (tmpaddr && memcmp(idev->rndid, &tmpaddr->s6_addr[8], 8) == 0) |
1672 | ret = __ipv6_regen_rndid(idev); | 1660 | __ipv6_regen_rndid(idev); |
1673 | return ret; | ||
1674 | } | 1661 | } |
1675 | #endif | 1662 | #endif |
1676 | 1663 | ||
@@ -1721,7 +1708,7 @@ static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx, | |||
1721 | if (table == NULL) | 1708 | if (table == NULL) |
1722 | return NULL; | 1709 | return NULL; |
1723 | 1710 | ||
1724 | write_lock_bh(&table->tb6_lock); | 1711 | read_lock_bh(&table->tb6_lock); |
1725 | fn = fib6_locate(&table->tb6_root, pfx, plen, NULL, 0); | 1712 | fn = fib6_locate(&table->tb6_root, pfx, plen, NULL, 0); |
1726 | if (!fn) | 1713 | if (!fn) |
1727 | goto out; | 1714 | goto out; |
@@ -1736,7 +1723,7 @@ static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx, | |||
1736 | break; | 1723 | break; |
1737 | } | 1724 | } |
1738 | out: | 1725 | out: |
1739 | write_unlock_bh(&table->tb6_lock); | 1726 | read_unlock_bh(&table->tb6_lock); |
1740 | return rt; | 1727 | return rt; |
1741 | } | 1728 | } |
1742 | 1729 | ||
@@ -3549,12 +3536,12 @@ static inline int inet6_ifaddr_msgsize(void) | |||
3549 | } | 3536 | } |
3550 | 3537 | ||
3551 | static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa, | 3538 | static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa, |
3552 | u32 pid, u32 seq, int event, unsigned int flags) | 3539 | u32 portid, u32 seq, int event, unsigned int flags) |
3553 | { | 3540 | { |
3554 | struct nlmsghdr *nlh; | 3541 | struct nlmsghdr *nlh; |
3555 | u32 preferred, valid; | 3542 | u32 preferred, valid; |
3556 | 3543 | ||
3557 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(struct ifaddrmsg), flags); | 3544 | nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct ifaddrmsg), flags); |
3558 | if (nlh == NULL) | 3545 | if (nlh == NULL) |
3559 | return -EMSGSIZE; | 3546 | return -EMSGSIZE; |
3560 | 3547 | ||
@@ -3592,7 +3579,7 @@ static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa, | |||
3592 | } | 3579 | } |
3593 | 3580 | ||
3594 | static int inet6_fill_ifmcaddr(struct sk_buff *skb, struct ifmcaddr6 *ifmca, | 3581 | static int inet6_fill_ifmcaddr(struct sk_buff *skb, struct ifmcaddr6 *ifmca, |
3595 | u32 pid, u32 seq, int event, u16 flags) | 3582 | u32 portid, u32 seq, int event, u16 flags) |
3596 | { | 3583 | { |
3597 | struct nlmsghdr *nlh; | 3584 | struct nlmsghdr *nlh; |
3598 | u8 scope = RT_SCOPE_UNIVERSE; | 3585 | u8 scope = RT_SCOPE_UNIVERSE; |
@@ -3601,7 +3588,7 @@ static int inet6_fill_ifmcaddr(struct sk_buff *skb, struct ifmcaddr6 *ifmca, | |||
3601 | if (ipv6_addr_scope(&ifmca->mca_addr) & IFA_SITE) | 3588 | if (ipv6_addr_scope(&ifmca->mca_addr) & IFA_SITE) |
3602 | scope = RT_SCOPE_SITE; | 3589 | scope = RT_SCOPE_SITE; |
3603 | 3590 | ||
3604 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(struct ifaddrmsg), flags); | 3591 | nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct ifaddrmsg), flags); |
3605 | if (nlh == NULL) | 3592 | if (nlh == NULL) |
3606 | return -EMSGSIZE; | 3593 | return -EMSGSIZE; |
3607 | 3594 | ||
@@ -3617,7 +3604,7 @@ static int inet6_fill_ifmcaddr(struct sk_buff *skb, struct ifmcaddr6 *ifmca, | |||
3617 | } | 3604 | } |
3618 | 3605 | ||
3619 | static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca, | 3606 | static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca, |
3620 | u32 pid, u32 seq, int event, unsigned int flags) | 3607 | u32 portid, u32 seq, int event, unsigned int flags) |
3621 | { | 3608 | { |
3622 | struct nlmsghdr *nlh; | 3609 | struct nlmsghdr *nlh; |
3623 | u8 scope = RT_SCOPE_UNIVERSE; | 3610 | u8 scope = RT_SCOPE_UNIVERSE; |
@@ -3626,7 +3613,7 @@ static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca, | |||
3626 | if (ipv6_addr_scope(&ifaca->aca_addr) & IFA_SITE) | 3613 | if (ipv6_addr_scope(&ifaca->aca_addr) & IFA_SITE) |
3627 | scope = RT_SCOPE_SITE; | 3614 | scope = RT_SCOPE_SITE; |
3628 | 3615 | ||
3629 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(struct ifaddrmsg), flags); | 3616 | nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct ifaddrmsg), flags); |
3630 | if (nlh == NULL) | 3617 | if (nlh == NULL) |
3631 | return -EMSGSIZE; | 3618 | return -EMSGSIZE; |
3632 | 3619 | ||
@@ -3667,7 +3654,7 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb, | |||
3667 | if (++ip_idx < s_ip_idx) | 3654 | if (++ip_idx < s_ip_idx) |
3668 | continue; | 3655 | continue; |
3669 | err = inet6_fill_ifaddr(skb, ifa, | 3656 | err = inet6_fill_ifaddr(skb, ifa, |
3670 | NETLINK_CB(cb->skb).pid, | 3657 | NETLINK_CB(cb->skb).portid, |
3671 | cb->nlh->nlmsg_seq, | 3658 | cb->nlh->nlmsg_seq, |
3672 | RTM_NEWADDR, | 3659 | RTM_NEWADDR, |
3673 | NLM_F_MULTI); | 3660 | NLM_F_MULTI); |
@@ -3683,7 +3670,7 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb, | |||
3683 | if (ip_idx < s_ip_idx) | 3670 | if (ip_idx < s_ip_idx) |
3684 | continue; | 3671 | continue; |
3685 | err = inet6_fill_ifmcaddr(skb, ifmca, | 3672 | err = inet6_fill_ifmcaddr(skb, ifmca, |
3686 | NETLINK_CB(cb->skb).pid, | 3673 | NETLINK_CB(cb->skb).portid, |
3687 | cb->nlh->nlmsg_seq, | 3674 | cb->nlh->nlmsg_seq, |
3688 | RTM_GETMULTICAST, | 3675 | RTM_GETMULTICAST, |
3689 | NLM_F_MULTI); | 3676 | NLM_F_MULTI); |
@@ -3698,7 +3685,7 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb, | |||
3698 | if (ip_idx < s_ip_idx) | 3685 | if (ip_idx < s_ip_idx) |
3699 | continue; | 3686 | continue; |
3700 | err = inet6_fill_ifacaddr(skb, ifaca, | 3687 | err = inet6_fill_ifacaddr(skb, ifaca, |
3701 | NETLINK_CB(cb->skb).pid, | 3688 | NETLINK_CB(cb->skb).portid, |
3702 | cb->nlh->nlmsg_seq, | 3689 | cb->nlh->nlmsg_seq, |
3703 | RTM_GETANYCAST, | 3690 | RTM_GETANYCAST, |
3704 | NLM_F_MULTI); | 3691 | NLM_F_MULTI); |
@@ -3820,7 +3807,7 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr *nlh, | |||
3820 | goto errout_ifa; | 3807 | goto errout_ifa; |
3821 | } | 3808 | } |
3822 | 3809 | ||
3823 | err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(in_skb).pid, | 3810 | err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(in_skb).portid, |
3824 | nlh->nlmsg_seq, RTM_NEWADDR, 0); | 3811 | nlh->nlmsg_seq, RTM_NEWADDR, 0); |
3825 | if (err < 0) { | 3812 | if (err < 0) { |
3826 | /* -EMSGSIZE implies BUG in inet6_ifaddr_msgsize() */ | 3813 | /* -EMSGSIZE implies BUG in inet6_ifaddr_msgsize() */ |
@@ -3828,7 +3815,7 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr *nlh, | |||
3828 | kfree_skb(skb); | 3815 | kfree_skb(skb); |
3829 | goto errout_ifa; | 3816 | goto errout_ifa; |
3830 | } | 3817 | } |
3831 | err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).pid); | 3818 | err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid); |
3832 | errout_ifa: | 3819 | errout_ifa: |
3833 | in6_ifa_put(ifa); | 3820 | in6_ifa_put(ifa); |
3834 | errout: | 3821 | errout: |
@@ -4030,14 +4017,14 @@ static int inet6_fill_link_af(struct sk_buff *skb, const struct net_device *dev) | |||
4030 | } | 4017 | } |
4031 | 4018 | ||
4032 | static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, | 4019 | static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, |
4033 | u32 pid, u32 seq, int event, unsigned int flags) | 4020 | u32 portid, u32 seq, int event, unsigned int flags) |
4034 | { | 4021 | { |
4035 | struct net_device *dev = idev->dev; | 4022 | struct net_device *dev = idev->dev; |
4036 | struct ifinfomsg *hdr; | 4023 | struct ifinfomsg *hdr; |
4037 | struct nlmsghdr *nlh; | 4024 | struct nlmsghdr *nlh; |
4038 | void *protoinfo; | 4025 | void *protoinfo; |
4039 | 4026 | ||
4040 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(*hdr), flags); | 4027 | nlh = nlmsg_put(skb, portid, seq, event, sizeof(*hdr), flags); |
4041 | if (nlh == NULL) | 4028 | if (nlh == NULL) |
4042 | return -EMSGSIZE; | 4029 | return -EMSGSIZE; |
4043 | 4030 | ||
@@ -4095,7 +4082,7 @@ static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | |||
4095 | if (!idev) | 4082 | if (!idev) |
4096 | goto cont; | 4083 | goto cont; |
4097 | if (inet6_fill_ifinfo(skb, idev, | 4084 | if (inet6_fill_ifinfo(skb, idev, |
4098 | NETLINK_CB(cb->skb).pid, | 4085 | NETLINK_CB(cb->skb).portid, |
4099 | cb->nlh->nlmsg_seq, | 4086 | cb->nlh->nlmsg_seq, |
4100 | RTM_NEWLINK, NLM_F_MULTI) <= 0) | 4087 | RTM_NEWLINK, NLM_F_MULTI) <= 0) |
4101 | goto out; | 4088 | goto out; |
@@ -4143,14 +4130,14 @@ static inline size_t inet6_prefix_nlmsg_size(void) | |||
4143 | } | 4130 | } |
4144 | 4131 | ||
4145 | static int inet6_fill_prefix(struct sk_buff *skb, struct inet6_dev *idev, | 4132 | static int inet6_fill_prefix(struct sk_buff *skb, struct inet6_dev *idev, |
4146 | struct prefix_info *pinfo, u32 pid, u32 seq, | 4133 | struct prefix_info *pinfo, u32 portid, u32 seq, |
4147 | int event, unsigned int flags) | 4134 | int event, unsigned int flags) |
4148 | { | 4135 | { |
4149 | struct prefixmsg *pmsg; | 4136 | struct prefixmsg *pmsg; |
4150 | struct nlmsghdr *nlh; | 4137 | struct nlmsghdr *nlh; |
4151 | struct prefix_cacheinfo ci; | 4138 | struct prefix_cacheinfo ci; |
4152 | 4139 | ||
4153 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(*pmsg), flags); | 4140 | nlh = nlmsg_put(skb, portid, seq, event, sizeof(*pmsg), flags); |
4154 | if (nlh == NULL) | 4141 | if (nlh == NULL) |
4155 | return -EMSGSIZE; | 4142 | return -EMSGSIZE; |
4156 | 4143 | ||
diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c index eb6a63632d3c..4be23da32b89 100644 --- a/net/ipv6/addrlabel.c +++ b/net/ipv6/addrlabel.c | |||
@@ -57,7 +57,7 @@ struct net *ip6addrlbl_net(const struct ip6addrlbl_entry *lbl) | |||
57 | } | 57 | } |
58 | 58 | ||
59 | /* | 59 | /* |
60 | * Default policy table (RFC3484 + extensions) | 60 | * Default policy table (RFC6724 + extensions) |
61 | * | 61 | * |
62 | * prefix addr_type label | 62 | * prefix addr_type label |
63 | * ------------------------------------------------------------------------- | 63 | * ------------------------------------------------------------------------- |
@@ -69,8 +69,12 @@ struct net *ip6addrlbl_net(const struct ip6addrlbl_entry *lbl) | |||
69 | * fc00::/7 N/A 5 ULA (RFC 4193) | 69 | * fc00::/7 N/A 5 ULA (RFC 4193) |
70 | * 2001::/32 N/A 6 Teredo (RFC 4380) | 70 | * 2001::/32 N/A 6 Teredo (RFC 4380) |
71 | * 2001:10::/28 N/A 7 ORCHID (RFC 4843) | 71 | * 2001:10::/28 N/A 7 ORCHID (RFC 4843) |
72 | * fec0::/10 N/A 11 Site-local | ||
73 | * (deprecated by RFC3879) | ||
74 | * 3ffe::/16 N/A 12 6bone | ||
72 | * | 75 | * |
73 | * Note: 0xffffffff is used if we do not have any policies. | 76 | * Note: 0xffffffff is used if we do not have any policies. |
77 | * Note: Labels for ULA and 6to4 are different from labels listed in RFC6724. | ||
74 | */ | 78 | */ |
75 | 79 | ||
76 | #define IPV6_ADDR_LABEL_DEFAULT 0xffffffffUL | 80 | #define IPV6_ADDR_LABEL_DEFAULT 0xffffffffUL |
@@ -88,10 +92,18 @@ static const __net_initdata struct ip6addrlbl_init_table | |||
88 | .prefix = &(struct in6_addr){{{ 0xfc }}}, | 92 | .prefix = &(struct in6_addr){{{ 0xfc }}}, |
89 | .prefixlen = 7, | 93 | .prefixlen = 7, |
90 | .label = 5, | 94 | .label = 5, |
95 | },{ /* fec0::/10 */ | ||
96 | .prefix = &(struct in6_addr){{{ 0xfe, 0xc0 }}}, | ||
97 | .prefixlen = 10, | ||
98 | .label = 11, | ||
91 | },{ /* 2002::/16 */ | 99 | },{ /* 2002::/16 */ |
92 | .prefix = &(struct in6_addr){{{ 0x20, 0x02 }}}, | 100 | .prefix = &(struct in6_addr){{{ 0x20, 0x02 }}}, |
93 | .prefixlen = 16, | 101 | .prefixlen = 16, |
94 | .label = 2, | 102 | .label = 2, |
103 | },{ /* 3ffe::/16 */ | ||
104 | .prefix = &(struct in6_addr){{{ 0x3f, 0xfe }}}, | ||
105 | .prefixlen = 16, | ||
106 | .label = 12, | ||
95 | },{ /* 2001::/32 */ | 107 | },{ /* 2001::/32 */ |
96 | .prefix = &(struct in6_addr){{{ 0x20, 0x01 }}}, | 108 | .prefix = &(struct in6_addr){{{ 0x20, 0x01 }}}, |
97 | .prefixlen = 32, | 109 | .prefixlen = 32, |
@@ -470,10 +482,10 @@ static void ip6addrlbl_putmsg(struct nlmsghdr *nlh, | |||
470 | static int ip6addrlbl_fill(struct sk_buff *skb, | 482 | static int ip6addrlbl_fill(struct sk_buff *skb, |
471 | struct ip6addrlbl_entry *p, | 483 | struct ip6addrlbl_entry *p, |
472 | u32 lseq, | 484 | u32 lseq, |
473 | u32 pid, u32 seq, int event, | 485 | u32 portid, u32 seq, int event, |
474 | unsigned int flags) | 486 | unsigned int flags) |
475 | { | 487 | { |
476 | struct nlmsghdr *nlh = nlmsg_put(skb, pid, seq, event, | 488 | struct nlmsghdr *nlh = nlmsg_put(skb, portid, seq, event, |
477 | sizeof(struct ifaddrlblmsg), flags); | 489 | sizeof(struct ifaddrlblmsg), flags); |
478 | if (!nlh) | 490 | if (!nlh) |
479 | return -EMSGSIZE; | 491 | return -EMSGSIZE; |
@@ -503,7 +515,7 @@ static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb) | |||
503 | net_eq(ip6addrlbl_net(p), net)) { | 515 | net_eq(ip6addrlbl_net(p), net)) { |
504 | if ((err = ip6addrlbl_fill(skb, p, | 516 | if ((err = ip6addrlbl_fill(skb, p, |
505 | ip6addrlbl_table.seq, | 517 | ip6addrlbl_table.seq, |
506 | NETLINK_CB(cb->skb).pid, | 518 | NETLINK_CB(cb->skb).portid, |
507 | cb->nlh->nlmsg_seq, | 519 | cb->nlh->nlmsg_seq, |
508 | RTM_NEWADDRLABEL, | 520 | RTM_NEWADDRLABEL, |
509 | NLM_F_MULTI)) <= 0) | 521 | NLM_F_MULTI)) <= 0) |
@@ -574,7 +586,7 @@ static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh, | |||
574 | } | 586 | } |
575 | 587 | ||
576 | err = ip6addrlbl_fill(skb, p, lseq, | 588 | err = ip6addrlbl_fill(skb, p, lseq, |
577 | NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, | 589 | NETLINK_CB(in_skb).portid, nlh->nlmsg_seq, |
578 | RTM_NEWADDRLABEL, 0); | 590 | RTM_NEWADDRLABEL, 0); |
579 | 591 | ||
580 | ip6addrlbl_put(p); | 592 | ip6addrlbl_put(p); |
@@ -585,7 +597,7 @@ static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh, | |||
585 | goto out; | 597 | goto out; |
586 | } | 598 | } |
587 | 599 | ||
588 | err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).pid); | 600 | err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid); |
589 | out: | 601 | out: |
590 | return err; | 602 | return err; |
591 | } | 603 | } |
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 9772fbd8a3f5..90bbefb57943 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/seq_file.h> | 22 | #include <linux/seq_file.h> |
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/export.h> | 24 | #include <linux/export.h> |
25 | #include <linux/pid_namespace.h> | ||
25 | 26 | ||
26 | #include <net/net_namespace.h> | 27 | #include <net/net_namespace.h> |
27 | #include <net/sock.h> | 28 | #include <net/sock.h> |
@@ -91,6 +92,8 @@ static struct ip6_flowlabel *fl_lookup(struct net *net, __be32 label) | |||
91 | static void fl_free(struct ip6_flowlabel *fl) | 92 | static void fl_free(struct ip6_flowlabel *fl) |
92 | { | 93 | { |
93 | if (fl) { | 94 | if (fl) { |
95 | if (fl->share == IPV6_FL_S_PROCESS) | ||
96 | put_pid(fl->owner.pid); | ||
94 | release_net(fl->fl_net); | 97 | release_net(fl->fl_net); |
95 | kfree(fl->opt); | 98 | kfree(fl->opt); |
96 | } | 99 | } |
@@ -394,10 +397,10 @@ fl_create(struct net *net, struct sock *sk, struct in6_flowlabel_req *freq, | |||
394 | case IPV6_FL_S_ANY: | 397 | case IPV6_FL_S_ANY: |
395 | break; | 398 | break; |
396 | case IPV6_FL_S_PROCESS: | 399 | case IPV6_FL_S_PROCESS: |
397 | fl->owner = current->pid; | 400 | fl->owner.pid = get_task_pid(current, PIDTYPE_PID); |
398 | break; | 401 | break; |
399 | case IPV6_FL_S_USER: | 402 | case IPV6_FL_S_USER: |
400 | fl->owner = current_euid(); | 403 | fl->owner.uid = current_euid(); |
401 | break; | 404 | break; |
402 | default: | 405 | default: |
403 | err = -EINVAL; | 406 | err = -EINVAL; |
@@ -561,7 +564,10 @@ recheck: | |||
561 | err = -EPERM; | 564 | err = -EPERM; |
562 | if (fl1->share == IPV6_FL_S_EXCL || | 565 | if (fl1->share == IPV6_FL_S_EXCL || |
563 | fl1->share != fl->share || | 566 | fl1->share != fl->share || |
564 | fl1->owner != fl->owner) | 567 | ((fl1->share == IPV6_FL_S_PROCESS) && |
568 | (fl1->owner.pid == fl->owner.pid)) || | ||
569 | ((fl1->share == IPV6_FL_S_USER) && | ||
570 | uid_eq(fl1->owner.uid, fl->owner.uid))) | ||
565 | goto release; | 571 | goto release; |
566 | 572 | ||
567 | err = -EINVAL; | 573 | err = -EINVAL; |
@@ -621,6 +627,7 @@ done: | |||
621 | 627 | ||
622 | struct ip6fl_iter_state { | 628 | struct ip6fl_iter_state { |
623 | struct seq_net_private p; | 629 | struct seq_net_private p; |
630 | struct pid_namespace *pid_ns; | ||
624 | int bucket; | 631 | int bucket; |
625 | }; | 632 | }; |
626 | 633 | ||
@@ -699,6 +706,7 @@ static void ip6fl_seq_stop(struct seq_file *seq, void *v) | |||
699 | 706 | ||
700 | static int ip6fl_seq_show(struct seq_file *seq, void *v) | 707 | static int ip6fl_seq_show(struct seq_file *seq, void *v) |
701 | { | 708 | { |
709 | struct ip6fl_iter_state *state = ip6fl_seq_private(seq); | ||
702 | if (v == SEQ_START_TOKEN) | 710 | if (v == SEQ_START_TOKEN) |
703 | seq_printf(seq, "%-5s %-1s %-6s %-6s %-6s %-8s %-32s %s\n", | 711 | seq_printf(seq, "%-5s %-1s %-6s %-6s %-6s %-8s %-32s %s\n", |
704 | "Label", "S", "Owner", "Users", "Linger", "Expires", "Dst", "Opt"); | 712 | "Label", "S", "Owner", "Users", "Linger", "Expires", "Dst", "Opt"); |
@@ -708,7 +716,11 @@ static int ip6fl_seq_show(struct seq_file *seq, void *v) | |||
708 | "%05X %-1d %-6d %-6d %-6ld %-8ld %pi6 %-4d\n", | 716 | "%05X %-1d %-6d %-6d %-6ld %-8ld %pi6 %-4d\n", |
709 | (unsigned int)ntohl(fl->label), | 717 | (unsigned int)ntohl(fl->label), |
710 | fl->share, | 718 | fl->share, |
711 | (int)fl->owner, | 719 | ((fl->share == IPV6_FL_S_PROCESS) ? |
720 | pid_nr_ns(fl->owner.pid, state->pid_ns) : | ||
721 | ((fl->share == IPV6_FL_S_USER) ? | ||
722 | from_kuid_munged(seq_user_ns(seq), fl->owner.uid) : | ||
723 | 0)), | ||
712 | atomic_read(&fl->users), | 724 | atomic_read(&fl->users), |
713 | fl->linger/HZ, | 725 | fl->linger/HZ, |
714 | (long)(fl->expires - jiffies)/HZ, | 726 | (long)(fl->expires - jiffies)/HZ, |
@@ -727,8 +739,29 @@ static const struct seq_operations ip6fl_seq_ops = { | |||
727 | 739 | ||
728 | static int ip6fl_seq_open(struct inode *inode, struct file *file) | 740 | static int ip6fl_seq_open(struct inode *inode, struct file *file) |
729 | { | 741 | { |
730 | return seq_open_net(inode, file, &ip6fl_seq_ops, | 742 | struct seq_file *seq; |
731 | sizeof(struct ip6fl_iter_state)); | 743 | struct ip6fl_iter_state *state; |
744 | int err; | ||
745 | |||
746 | err = seq_open_net(inode, file, &ip6fl_seq_ops, | ||
747 | sizeof(struct ip6fl_iter_state)); | ||
748 | |||
749 | if (!err) { | ||
750 | seq = file->private_data; | ||
751 | state = ip6fl_seq_private(seq); | ||
752 | rcu_read_lock(); | ||
753 | state->pid_ns = get_pid_ns(task_active_pid_ns(current)); | ||
754 | rcu_read_unlock(); | ||
755 | } | ||
756 | return err; | ||
757 | } | ||
758 | |||
759 | static int ip6fl_seq_release(struct inode *inode, struct file *file) | ||
760 | { | ||
761 | struct seq_file *seq = file->private_data; | ||
762 | struct ip6fl_iter_state *state = ip6fl_seq_private(seq); | ||
763 | put_pid_ns(state->pid_ns); | ||
764 | return seq_release_net(inode, file); | ||
732 | } | 765 | } |
733 | 766 | ||
734 | static const struct file_operations ip6fl_seq_fops = { | 767 | static const struct file_operations ip6fl_seq_fops = { |
@@ -736,7 +769,7 @@ static const struct file_operations ip6fl_seq_fops = { | |||
736 | .open = ip6fl_seq_open, | 769 | .open = ip6fl_seq_open, |
737 | .read = seq_read, | 770 | .read = seq_read, |
738 | .llseek = seq_lseek, | 771 | .llseek = seq_lseek, |
739 | .release = seq_release_net, | 772 | .release = ip6fl_seq_release, |
740 | }; | 773 | }; |
741 | 774 | ||
742 | static int __net_init ip6_flowlabel_proc_init(struct net *net) | 775 | static int __net_init ip6_flowlabel_proc_init(struct net *net) |
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c new file mode 100644 index 000000000000..424d11a4e7ff --- /dev/null +++ b/net/ipv6/ip6_gre.c | |||
@@ -0,0 +1,1792 @@ | |||
1 | /* | ||
2 | * GRE over IPv6 protocol decoder. | ||
3 | * | ||
4 | * Authors: Dmitry Kozlov (xeb@mail.ru) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
14 | |||
15 | #include <linux/capability.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/types.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/uaccess.h> | ||
21 | #include <linux/skbuff.h> | ||
22 | #include <linux/netdevice.h> | ||
23 | #include <linux/in.h> | ||
24 | #include <linux/tcp.h> | ||
25 | #include <linux/udp.h> | ||
26 | #include <linux/if_arp.h> | ||
27 | #include <linux/mroute.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/in6.h> | ||
30 | #include <linux/inetdevice.h> | ||
31 | #include <linux/igmp.h> | ||
32 | #include <linux/netfilter_ipv4.h> | ||
33 | #include <linux/etherdevice.h> | ||
34 | #include <linux/if_ether.h> | ||
35 | #include <linux/hash.h> | ||
36 | #include <linux/if_tunnel.h> | ||
37 | #include <linux/ip6_tunnel.h> | ||
38 | |||
39 | #include <net/sock.h> | ||
40 | #include <net/ip.h> | ||
41 | #include <net/icmp.h> | ||
42 | #include <net/protocol.h> | ||
43 | #include <net/addrconf.h> | ||
44 | #include <net/arp.h> | ||
45 | #include <net/checksum.h> | ||
46 | #include <net/dsfield.h> | ||
47 | #include <net/inet_ecn.h> | ||
48 | #include <net/xfrm.h> | ||
49 | #include <net/net_namespace.h> | ||
50 | #include <net/netns/generic.h> | ||
51 | #include <net/rtnetlink.h> | ||
52 | |||
53 | #include <net/ipv6.h> | ||
54 | #include <net/ip6_fib.h> | ||
55 | #include <net/ip6_route.h> | ||
56 | #include <net/ip6_tunnel.h> | ||
57 | |||
58 | |||
59 | #define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK) | ||
60 | #define IPV6_TCLASS_SHIFT 20 | ||
61 | |||
62 | #define HASH_SIZE_SHIFT 5 | ||
63 | #define HASH_SIZE (1 << HASH_SIZE_SHIFT) | ||
64 | |||
65 | static int ip6gre_net_id __read_mostly; | ||
66 | struct ip6gre_net { | ||
67 | struct ip6_tnl __rcu *tunnels[4][HASH_SIZE]; | ||
68 | |||
69 | struct net_device *fb_tunnel_dev; | ||
70 | }; | ||
71 | |||
72 | static struct rtnl_link_ops ip6gre_link_ops __read_mostly; | ||
73 | static int ip6gre_tunnel_init(struct net_device *dev); | ||
74 | static void ip6gre_tunnel_setup(struct net_device *dev); | ||
75 | static void ip6gre_tunnel_link(struct ip6gre_net *ign, struct ip6_tnl *t); | ||
76 | static void ip6gre_tnl_link_config(struct ip6_tnl *t, int set_mtu); | ||
77 | |||
78 | /* Tunnel hash table */ | ||
79 | |||
80 | /* | ||
81 | 4 hash tables: | ||
82 | |||
83 | 3: (remote,local) | ||
84 | 2: (remote,*) | ||
85 | 1: (*,local) | ||
86 | 0: (*,*) | ||
87 | |||
88 | We require exact key match i.e. if a key is present in packet | ||
89 | it will match only tunnel with the same key; if it is not present, | ||
90 | it will match only keyless tunnel. | ||
91 | |||
92 | All keysless packets, if not matched configured keyless tunnels | ||
93 | will match fallback tunnel. | ||
94 | */ | ||
95 | |||
96 | #define HASH_KEY(key) (((__force u32)key^((__force u32)key>>4))&(HASH_SIZE - 1)) | ||
97 | static u32 HASH_ADDR(const struct in6_addr *addr) | ||
98 | { | ||
99 | u32 hash = ipv6_addr_hash(addr); | ||
100 | |||
101 | return hash_32(hash, HASH_SIZE_SHIFT); | ||
102 | } | ||
103 | |||
104 | #define tunnels_r_l tunnels[3] | ||
105 | #define tunnels_r tunnels[2] | ||
106 | #define tunnels_l tunnels[1] | ||
107 | #define tunnels_wc tunnels[0] | ||
108 | /* | ||
109 | * Locking : hash tables are protected by RCU and RTNL | ||
110 | */ | ||
111 | |||
112 | #define for_each_ip_tunnel_rcu(start) \ | ||
113 | for (t = rcu_dereference(start); t; t = rcu_dereference(t->next)) | ||
114 | |||
115 | /* often modified stats are per cpu, other are shared (netdev->stats) */ | ||
116 | struct pcpu_tstats { | ||
117 | u64 rx_packets; | ||
118 | u64 rx_bytes; | ||
119 | u64 tx_packets; | ||
120 | u64 tx_bytes; | ||
121 | struct u64_stats_sync syncp; | ||
122 | }; | ||
123 | |||
124 | static struct rtnl_link_stats64 *ip6gre_get_stats64(struct net_device *dev, | ||
125 | struct rtnl_link_stats64 *tot) | ||
126 | { | ||
127 | int i; | ||
128 | |||
129 | for_each_possible_cpu(i) { | ||
130 | const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i); | ||
131 | u64 rx_packets, rx_bytes, tx_packets, tx_bytes; | ||
132 | unsigned int start; | ||
133 | |||
134 | do { | ||
135 | start = u64_stats_fetch_begin_bh(&tstats->syncp); | ||
136 | rx_packets = tstats->rx_packets; | ||
137 | tx_packets = tstats->tx_packets; | ||
138 | rx_bytes = tstats->rx_bytes; | ||
139 | tx_bytes = tstats->tx_bytes; | ||
140 | } while (u64_stats_fetch_retry_bh(&tstats->syncp, start)); | ||
141 | |||
142 | tot->rx_packets += rx_packets; | ||
143 | tot->tx_packets += tx_packets; | ||
144 | tot->rx_bytes += rx_bytes; | ||
145 | tot->tx_bytes += tx_bytes; | ||
146 | } | ||
147 | |||
148 | tot->multicast = dev->stats.multicast; | ||
149 | tot->rx_crc_errors = dev->stats.rx_crc_errors; | ||
150 | tot->rx_fifo_errors = dev->stats.rx_fifo_errors; | ||
151 | tot->rx_length_errors = dev->stats.rx_length_errors; | ||
152 | tot->rx_errors = dev->stats.rx_errors; | ||
153 | tot->tx_fifo_errors = dev->stats.tx_fifo_errors; | ||
154 | tot->tx_carrier_errors = dev->stats.tx_carrier_errors; | ||
155 | tot->tx_dropped = dev->stats.tx_dropped; | ||
156 | tot->tx_aborted_errors = dev->stats.tx_aborted_errors; | ||
157 | tot->tx_errors = dev->stats.tx_errors; | ||
158 | |||
159 | return tot; | ||
160 | } | ||
161 | |||
162 | /* Given src, dst and key, find appropriate for input tunnel. */ | ||
163 | |||
164 | static struct ip6_tnl *ip6gre_tunnel_lookup(struct net_device *dev, | ||
165 | const struct in6_addr *remote, const struct in6_addr *local, | ||
166 | __be32 key, __be16 gre_proto) | ||
167 | { | ||
168 | struct net *net = dev_net(dev); | ||
169 | int link = dev->ifindex; | ||
170 | unsigned int h0 = HASH_ADDR(remote); | ||
171 | unsigned int h1 = HASH_KEY(key); | ||
172 | struct ip6_tnl *t, *cand = NULL; | ||
173 | struct ip6gre_net *ign = net_generic(net, ip6gre_net_id); | ||
174 | int dev_type = (gre_proto == htons(ETH_P_TEB)) ? | ||
175 | ARPHRD_ETHER : ARPHRD_IP6GRE; | ||
176 | int score, cand_score = 4; | ||
177 | |||
178 | for_each_ip_tunnel_rcu(ign->tunnels_r_l[h0 ^ h1]) { | ||
179 | if (!ipv6_addr_equal(local, &t->parms.laddr) || | ||
180 | !ipv6_addr_equal(remote, &t->parms.raddr) || | ||
181 | key != t->parms.i_key || | ||
182 | !(t->dev->flags & IFF_UP)) | ||
183 | continue; | ||
184 | |||
185 | if (t->dev->type != ARPHRD_IP6GRE && | ||
186 | t->dev->type != dev_type) | ||
187 | continue; | ||
188 | |||
189 | score = 0; | ||
190 | if (t->parms.link != link) | ||
191 | score |= 1; | ||
192 | if (t->dev->type != dev_type) | ||
193 | score |= 2; | ||
194 | if (score == 0) | ||
195 | return t; | ||
196 | |||
197 | if (score < cand_score) { | ||
198 | cand = t; | ||
199 | cand_score = score; | ||
200 | } | ||
201 | } | ||
202 | |||
203 | for_each_ip_tunnel_rcu(ign->tunnels_r[h0 ^ h1]) { | ||
204 | if (!ipv6_addr_equal(remote, &t->parms.raddr) || | ||
205 | key != t->parms.i_key || | ||
206 | !(t->dev->flags & IFF_UP)) | ||
207 | continue; | ||
208 | |||
209 | if (t->dev->type != ARPHRD_IP6GRE && | ||
210 | t->dev->type != dev_type) | ||
211 | continue; | ||
212 | |||
213 | score = 0; | ||
214 | if (t->parms.link != link) | ||
215 | score |= 1; | ||
216 | if (t->dev->type != dev_type) | ||
217 | score |= 2; | ||
218 | if (score == 0) | ||
219 | return t; | ||
220 | |||
221 | if (score < cand_score) { | ||
222 | cand = t; | ||
223 | cand_score = score; | ||
224 | } | ||
225 | } | ||
226 | |||
227 | for_each_ip_tunnel_rcu(ign->tunnels_l[h1]) { | ||
228 | if ((!ipv6_addr_equal(local, &t->parms.laddr) && | ||
229 | (!ipv6_addr_equal(local, &t->parms.raddr) || | ||
230 | !ipv6_addr_is_multicast(local))) || | ||
231 | key != t->parms.i_key || | ||
232 | !(t->dev->flags & IFF_UP)) | ||
233 | continue; | ||
234 | |||
235 | if (t->dev->type != ARPHRD_IP6GRE && | ||
236 | t->dev->type != dev_type) | ||
237 | continue; | ||
238 | |||
239 | score = 0; | ||
240 | if (t->parms.link != link) | ||
241 | score |= 1; | ||
242 | if (t->dev->type != dev_type) | ||
243 | score |= 2; | ||
244 | if (score == 0) | ||
245 | return t; | ||
246 | |||
247 | if (score < cand_score) { | ||
248 | cand = t; | ||
249 | cand_score = score; | ||
250 | } | ||
251 | } | ||
252 | |||
253 | for_each_ip_tunnel_rcu(ign->tunnels_wc[h1]) { | ||
254 | if (t->parms.i_key != key || | ||
255 | !(t->dev->flags & IFF_UP)) | ||
256 | continue; | ||
257 | |||
258 | if (t->dev->type != ARPHRD_IP6GRE && | ||
259 | t->dev->type != dev_type) | ||
260 | continue; | ||
261 | |||
262 | score = 0; | ||
263 | if (t->parms.link != link) | ||
264 | score |= 1; | ||
265 | if (t->dev->type != dev_type) | ||
266 | score |= 2; | ||
267 | if (score == 0) | ||
268 | return t; | ||
269 | |||
270 | if (score < cand_score) { | ||
271 | cand = t; | ||
272 | cand_score = score; | ||
273 | } | ||
274 | } | ||
275 | |||
276 | if (cand != NULL) | ||
277 | return cand; | ||
278 | |||
279 | dev = ign->fb_tunnel_dev; | ||
280 | if (dev->flags & IFF_UP) | ||
281 | return netdev_priv(dev); | ||
282 | |||
283 | return NULL; | ||
284 | } | ||
285 | |||
286 | static struct ip6_tnl __rcu **__ip6gre_bucket(struct ip6gre_net *ign, | ||
287 | const struct __ip6_tnl_parm *p) | ||
288 | { | ||
289 | const struct in6_addr *remote = &p->raddr; | ||
290 | const struct in6_addr *local = &p->laddr; | ||
291 | unsigned int h = HASH_KEY(p->i_key); | ||
292 | int prio = 0; | ||
293 | |||
294 | if (!ipv6_addr_any(local)) | ||
295 | prio |= 1; | ||
296 | if (!ipv6_addr_any(remote) && !ipv6_addr_is_multicast(remote)) { | ||
297 | prio |= 2; | ||
298 | h ^= HASH_ADDR(remote); | ||
299 | } | ||
300 | |||
301 | return &ign->tunnels[prio][h]; | ||
302 | } | ||
303 | |||
304 | static inline struct ip6_tnl __rcu **ip6gre_bucket(struct ip6gre_net *ign, | ||
305 | const struct ip6_tnl *t) | ||
306 | { | ||
307 | return __ip6gre_bucket(ign, &t->parms); | ||
308 | } | ||
309 | |||
310 | static void ip6gre_tunnel_link(struct ip6gre_net *ign, struct ip6_tnl *t) | ||
311 | { | ||
312 | struct ip6_tnl __rcu **tp = ip6gre_bucket(ign, t); | ||
313 | |||
314 | rcu_assign_pointer(t->next, rtnl_dereference(*tp)); | ||
315 | rcu_assign_pointer(*tp, t); | ||
316 | } | ||
317 | |||
318 | static void ip6gre_tunnel_unlink(struct ip6gre_net *ign, struct ip6_tnl *t) | ||
319 | { | ||
320 | struct ip6_tnl __rcu **tp; | ||
321 | struct ip6_tnl *iter; | ||
322 | |||
323 | for (tp = ip6gre_bucket(ign, t); | ||
324 | (iter = rtnl_dereference(*tp)) != NULL; | ||
325 | tp = &iter->next) { | ||
326 | if (t == iter) { | ||
327 | rcu_assign_pointer(*tp, t->next); | ||
328 | break; | ||
329 | } | ||
330 | } | ||
331 | } | ||
332 | |||
333 | static struct ip6_tnl *ip6gre_tunnel_find(struct net *net, | ||
334 | const struct __ip6_tnl_parm *parms, | ||
335 | int type) | ||
336 | { | ||
337 | const struct in6_addr *remote = &parms->raddr; | ||
338 | const struct in6_addr *local = &parms->laddr; | ||
339 | __be32 key = parms->i_key; | ||
340 | int link = parms->link; | ||
341 | struct ip6_tnl *t; | ||
342 | struct ip6_tnl __rcu **tp; | ||
343 | struct ip6gre_net *ign = net_generic(net, ip6gre_net_id); | ||
344 | |||
345 | for (tp = __ip6gre_bucket(ign, parms); | ||
346 | (t = rtnl_dereference(*tp)) != NULL; | ||
347 | tp = &t->next) | ||
348 | if (ipv6_addr_equal(local, &t->parms.laddr) && | ||
349 | ipv6_addr_equal(remote, &t->parms.raddr) && | ||
350 | key == t->parms.i_key && | ||
351 | link == t->parms.link && | ||
352 | type == t->dev->type) | ||
353 | break; | ||
354 | |||
355 | return t; | ||
356 | } | ||
357 | |||
358 | static struct ip6_tnl *ip6gre_tunnel_locate(struct net *net, | ||
359 | const struct __ip6_tnl_parm *parms, int create) | ||
360 | { | ||
361 | struct ip6_tnl *t, *nt; | ||
362 | struct net_device *dev; | ||
363 | char name[IFNAMSIZ]; | ||
364 | struct ip6gre_net *ign = net_generic(net, ip6gre_net_id); | ||
365 | |||
366 | t = ip6gre_tunnel_find(net, parms, ARPHRD_IP6GRE); | ||
367 | if (t || !create) | ||
368 | return t; | ||
369 | |||
370 | if (parms->name[0]) | ||
371 | strlcpy(name, parms->name, IFNAMSIZ); | ||
372 | else | ||
373 | strcpy(name, "ip6gre%d"); | ||
374 | |||
375 | dev = alloc_netdev(sizeof(*t), name, ip6gre_tunnel_setup); | ||
376 | if (!dev) | ||
377 | return NULL; | ||
378 | |||
379 | dev_net_set(dev, net); | ||
380 | |||
381 | nt = netdev_priv(dev); | ||
382 | nt->parms = *parms; | ||
383 | dev->rtnl_link_ops = &ip6gre_link_ops; | ||
384 | |||
385 | nt->dev = dev; | ||
386 | ip6gre_tnl_link_config(nt, 1); | ||
387 | |||
388 | if (register_netdevice(dev) < 0) | ||
389 | goto failed_free; | ||
390 | |||
391 | /* Can use a lockless transmit, unless we generate output sequences */ | ||
392 | if (!(nt->parms.o_flags & GRE_SEQ)) | ||
393 | dev->features |= NETIF_F_LLTX; | ||
394 | |||
395 | dev_hold(dev); | ||
396 | ip6gre_tunnel_link(ign, nt); | ||
397 | return nt; | ||
398 | |||
399 | failed_free: | ||
400 | free_netdev(dev); | ||
401 | return NULL; | ||
402 | } | ||
403 | |||
404 | static void ip6gre_tunnel_uninit(struct net_device *dev) | ||
405 | { | ||
406 | struct net *net = dev_net(dev); | ||
407 | struct ip6gre_net *ign = net_generic(net, ip6gre_net_id); | ||
408 | |||
409 | ip6gre_tunnel_unlink(ign, netdev_priv(dev)); | ||
410 | dev_put(dev); | ||
411 | } | ||
412 | |||
413 | |||
414 | static void ip6gre_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | ||
415 | u8 type, u8 code, int offset, __be32 info) | ||
416 | { | ||
417 | const struct ipv6hdr *ipv6h = (const struct ipv6hdr *)skb->data; | ||
418 | __be16 *p = (__be16 *)(skb->data + offset); | ||
419 | int grehlen = offset + 4; | ||
420 | struct ip6_tnl *t; | ||
421 | __be16 flags; | ||
422 | |||
423 | flags = p[0]; | ||
424 | if (flags&(GRE_CSUM|GRE_KEY|GRE_SEQ|GRE_ROUTING|GRE_VERSION)) { | ||
425 | if (flags&(GRE_VERSION|GRE_ROUTING)) | ||
426 | return; | ||
427 | if (flags&GRE_KEY) { | ||
428 | grehlen += 4; | ||
429 | if (flags&GRE_CSUM) | ||
430 | grehlen += 4; | ||
431 | } | ||
432 | } | ||
433 | |||
434 | /* If only 8 bytes returned, keyed message will be dropped here */ | ||
435 | if (!pskb_may_pull(skb, grehlen)) | ||
436 | return; | ||
437 | ipv6h = (const struct ipv6hdr *)skb->data; | ||
438 | p = (__be16 *)(skb->data + offset); | ||
439 | |||
440 | rcu_read_lock(); | ||
441 | |||
442 | t = ip6gre_tunnel_lookup(skb->dev, &ipv6h->daddr, &ipv6h->saddr, | ||
443 | flags & GRE_KEY ? | ||
444 | *(((__be32 *)p) + (grehlen / 4) - 1) : 0, | ||
445 | p[1]); | ||
446 | if (t == NULL) | ||
447 | goto out; | ||
448 | |||
449 | switch (type) { | ||
450 | __u32 teli; | ||
451 | struct ipv6_tlv_tnl_enc_lim *tel; | ||
452 | __u32 mtu; | ||
453 | case ICMPV6_DEST_UNREACH: | ||
454 | net_warn_ratelimited("%s: Path to destination invalid or inactive!\n", | ||
455 | t->parms.name); | ||
456 | break; | ||
457 | case ICMPV6_TIME_EXCEED: | ||
458 | if (code == ICMPV6_EXC_HOPLIMIT) { | ||
459 | net_warn_ratelimited("%s: Too small hop limit or routing loop in tunnel!\n", | ||
460 | t->parms.name); | ||
461 | } | ||
462 | break; | ||
463 | case ICMPV6_PARAMPROB: | ||
464 | teli = 0; | ||
465 | if (code == ICMPV6_HDR_FIELD) | ||
466 | teli = ip6_tnl_parse_tlv_enc_lim(skb, skb->data); | ||
467 | |||
468 | if (teli && teli == info - 2) { | ||
469 | tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli]; | ||
470 | if (tel->encap_limit == 0) { | ||
471 | net_warn_ratelimited("%s: Too small encapsulation limit or routing loop in tunnel!\n", | ||
472 | t->parms.name); | ||
473 | } | ||
474 | } else { | ||
475 | net_warn_ratelimited("%s: Recipient unable to parse tunneled packet!\n", | ||
476 | t->parms.name); | ||
477 | } | ||
478 | break; | ||
479 | case ICMPV6_PKT_TOOBIG: | ||
480 | mtu = info - offset; | ||
481 | if (mtu < IPV6_MIN_MTU) | ||
482 | mtu = IPV6_MIN_MTU; | ||
483 | t->dev->mtu = mtu; | ||
484 | break; | ||
485 | } | ||
486 | |||
487 | if (time_before(jiffies, t->err_time + IP6TUNNEL_ERR_TIMEO)) | ||
488 | t->err_count++; | ||
489 | else | ||
490 | t->err_count = 1; | ||
491 | t->err_time = jiffies; | ||
492 | out: | ||
493 | rcu_read_unlock(); | ||
494 | } | ||
495 | |||
496 | static inline void ip6gre_ecn_decapsulate_ipv4(const struct ip6_tnl *t, | ||
497 | const struct ipv6hdr *ipv6h, struct sk_buff *skb) | ||
498 | { | ||
499 | __u8 dsfield = ipv6_get_dsfield(ipv6h) & ~INET_ECN_MASK; | ||
500 | |||
501 | if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY) | ||
502 | ipv4_change_dsfield(ip_hdr(skb), INET_ECN_MASK, dsfield); | ||
503 | |||
504 | if (INET_ECN_is_ce(dsfield)) | ||
505 | IP_ECN_set_ce(ip_hdr(skb)); | ||
506 | } | ||
507 | |||
508 | static inline void ip6gre_ecn_decapsulate_ipv6(const struct ip6_tnl *t, | ||
509 | const struct ipv6hdr *ipv6h, struct sk_buff *skb) | ||
510 | { | ||
511 | if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY) | ||
512 | ipv6_copy_dscp(ipv6_get_dsfield(ipv6h), ipv6_hdr(skb)); | ||
513 | |||
514 | if (INET_ECN_is_ce(ipv6_get_dsfield(ipv6h))) | ||
515 | IP6_ECN_set_ce(ipv6_hdr(skb)); | ||
516 | } | ||
517 | |||
518 | static int ip6gre_rcv(struct sk_buff *skb) | ||
519 | { | ||
520 | const struct ipv6hdr *ipv6h; | ||
521 | u8 *h; | ||
522 | __be16 flags; | ||
523 | __sum16 csum = 0; | ||
524 | __be32 key = 0; | ||
525 | u32 seqno = 0; | ||
526 | struct ip6_tnl *tunnel; | ||
527 | int offset = 4; | ||
528 | __be16 gre_proto; | ||
529 | |||
530 | if (!pskb_may_pull(skb, sizeof(struct in6_addr))) | ||
531 | goto drop_nolock; | ||
532 | |||
533 | ipv6h = ipv6_hdr(skb); | ||
534 | h = skb->data; | ||
535 | flags = *(__be16 *)h; | ||
536 | |||
537 | if (flags&(GRE_CSUM|GRE_KEY|GRE_ROUTING|GRE_SEQ|GRE_VERSION)) { | ||
538 | /* - Version must be 0. | ||
539 | - We do not support routing headers. | ||
540 | */ | ||
541 | if (flags&(GRE_VERSION|GRE_ROUTING)) | ||
542 | goto drop_nolock; | ||
543 | |||
544 | if (flags&GRE_CSUM) { | ||
545 | switch (skb->ip_summed) { | ||
546 | case CHECKSUM_COMPLETE: | ||
547 | csum = csum_fold(skb->csum); | ||
548 | if (!csum) | ||
549 | break; | ||
550 | /* fall through */ | ||
551 | case CHECKSUM_NONE: | ||
552 | skb->csum = 0; | ||
553 | csum = __skb_checksum_complete(skb); | ||
554 | skb->ip_summed = CHECKSUM_COMPLETE; | ||
555 | } | ||
556 | offset += 4; | ||
557 | } | ||
558 | if (flags&GRE_KEY) { | ||
559 | key = *(__be32 *)(h + offset); | ||
560 | offset += 4; | ||
561 | } | ||
562 | if (flags&GRE_SEQ) { | ||
563 | seqno = ntohl(*(__be32 *)(h + offset)); | ||
564 | offset += 4; | ||
565 | } | ||
566 | } | ||
567 | |||
568 | gre_proto = *(__be16 *)(h + 2); | ||
569 | |||
570 | rcu_read_lock(); | ||
571 | tunnel = ip6gre_tunnel_lookup(skb->dev, | ||
572 | &ipv6h->saddr, &ipv6h->daddr, key, | ||
573 | gre_proto); | ||
574 | if (tunnel) { | ||
575 | struct pcpu_tstats *tstats; | ||
576 | |||
577 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) | ||
578 | goto drop; | ||
579 | |||
580 | if (!ip6_tnl_rcv_ctl(tunnel, &ipv6h->daddr, &ipv6h->saddr)) { | ||
581 | tunnel->dev->stats.rx_dropped++; | ||
582 | goto drop; | ||
583 | } | ||
584 | |||
585 | secpath_reset(skb); | ||
586 | |||
587 | skb->protocol = gre_proto; | ||
588 | /* WCCP version 1 and 2 protocol decoding. | ||
589 | * - Change protocol to IP | ||
590 | * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header | ||
591 | */ | ||
592 | if (flags == 0 && gre_proto == htons(ETH_P_WCCP)) { | ||
593 | skb->protocol = htons(ETH_P_IP); | ||
594 | if ((*(h + offset) & 0xF0) != 0x40) | ||
595 | offset += 4; | ||
596 | } | ||
597 | |||
598 | skb->mac_header = skb->network_header; | ||
599 | __pskb_pull(skb, offset); | ||
600 | skb_postpull_rcsum(skb, skb_transport_header(skb), offset); | ||
601 | skb->pkt_type = PACKET_HOST; | ||
602 | |||
603 | if (((flags&GRE_CSUM) && csum) || | ||
604 | (!(flags&GRE_CSUM) && tunnel->parms.i_flags&GRE_CSUM)) { | ||
605 | tunnel->dev->stats.rx_crc_errors++; | ||
606 | tunnel->dev->stats.rx_errors++; | ||
607 | goto drop; | ||
608 | } | ||
609 | if (tunnel->parms.i_flags&GRE_SEQ) { | ||
610 | if (!(flags&GRE_SEQ) || | ||
611 | (tunnel->i_seqno && | ||
612 | (s32)(seqno - tunnel->i_seqno) < 0)) { | ||
613 | tunnel->dev->stats.rx_fifo_errors++; | ||
614 | tunnel->dev->stats.rx_errors++; | ||
615 | goto drop; | ||
616 | } | ||
617 | tunnel->i_seqno = seqno + 1; | ||
618 | } | ||
619 | |||
620 | /* Warning: All skb pointers will be invalidated! */ | ||
621 | if (tunnel->dev->type == ARPHRD_ETHER) { | ||
622 | if (!pskb_may_pull(skb, ETH_HLEN)) { | ||
623 | tunnel->dev->stats.rx_length_errors++; | ||
624 | tunnel->dev->stats.rx_errors++; | ||
625 | goto drop; | ||
626 | } | ||
627 | |||
628 | ipv6h = ipv6_hdr(skb); | ||
629 | skb->protocol = eth_type_trans(skb, tunnel->dev); | ||
630 | skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); | ||
631 | } | ||
632 | |||
633 | tstats = this_cpu_ptr(tunnel->dev->tstats); | ||
634 | u64_stats_update_begin(&tstats->syncp); | ||
635 | tstats->rx_packets++; | ||
636 | tstats->rx_bytes += skb->len; | ||
637 | u64_stats_update_end(&tstats->syncp); | ||
638 | |||
639 | __skb_tunnel_rx(skb, tunnel->dev); | ||
640 | |||
641 | skb_reset_network_header(skb); | ||
642 | if (skb->protocol == htons(ETH_P_IP)) | ||
643 | ip6gre_ecn_decapsulate_ipv4(tunnel, ipv6h, skb); | ||
644 | else if (skb->protocol == htons(ETH_P_IPV6)) | ||
645 | ip6gre_ecn_decapsulate_ipv6(tunnel, ipv6h, skb); | ||
646 | |||
647 | netif_rx(skb); | ||
648 | |||
649 | rcu_read_unlock(); | ||
650 | return 0; | ||
651 | } | ||
652 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); | ||
653 | |||
654 | drop: | ||
655 | rcu_read_unlock(); | ||
656 | drop_nolock: | ||
657 | kfree_skb(skb); | ||
658 | return 0; | ||
659 | } | ||
660 | |||
661 | struct ipv6_tel_txoption { | ||
662 | struct ipv6_txoptions ops; | ||
663 | __u8 dst_opt[8]; | ||
664 | }; | ||
665 | |||
666 | static void init_tel_txopt(struct ipv6_tel_txoption *opt, __u8 encap_limit) | ||
667 | { | ||
668 | memset(opt, 0, sizeof(struct ipv6_tel_txoption)); | ||
669 | |||
670 | opt->dst_opt[2] = IPV6_TLV_TNL_ENCAP_LIMIT; | ||
671 | opt->dst_opt[3] = 1; | ||
672 | opt->dst_opt[4] = encap_limit; | ||
673 | opt->dst_opt[5] = IPV6_TLV_PADN; | ||
674 | opt->dst_opt[6] = 1; | ||
675 | |||
676 | opt->ops.dst0opt = (struct ipv6_opt_hdr *) opt->dst_opt; | ||
677 | opt->ops.opt_nflen = 8; | ||
678 | } | ||
679 | |||
680 | static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb, | ||
681 | struct net_device *dev, | ||
682 | __u8 dsfield, | ||
683 | struct flowi6 *fl6, | ||
684 | int encap_limit, | ||
685 | __u32 *pmtu) | ||
686 | { | ||
687 | struct net *net = dev_net(dev); | ||
688 | struct ip6_tnl *tunnel = netdev_priv(dev); | ||
689 | struct net_device *tdev; /* Device to other host */ | ||
690 | struct ipv6hdr *ipv6h; /* Our new IP header */ | ||
691 | unsigned int max_headroom; /* The extra header space needed */ | ||
692 | int gre_hlen; | ||
693 | struct ipv6_tel_txoption opt; | ||
694 | int mtu; | ||
695 | struct dst_entry *dst = NULL, *ndst = NULL; | ||
696 | struct net_device_stats *stats = &tunnel->dev->stats; | ||
697 | int err = -1; | ||
698 | u8 proto; | ||
699 | int pkt_len; | ||
700 | struct sk_buff *new_skb; | ||
701 | |||
702 | if (dev->type == ARPHRD_ETHER) | ||
703 | IPCB(skb)->flags = 0; | ||
704 | |||
705 | if (dev->header_ops && dev->type == ARPHRD_IP6GRE) { | ||
706 | gre_hlen = 0; | ||
707 | ipv6h = (struct ipv6hdr *)skb->data; | ||
708 | fl6->daddr = ipv6h->daddr; | ||
709 | } else { | ||
710 | gre_hlen = tunnel->hlen; | ||
711 | fl6->daddr = tunnel->parms.raddr; | ||
712 | } | ||
713 | |||
714 | if (!fl6->flowi6_mark) | ||
715 | dst = ip6_tnl_dst_check(tunnel); | ||
716 | |||
717 | if (!dst) { | ||
718 | ndst = ip6_route_output(net, NULL, fl6); | ||
719 | |||
720 | if (ndst->error) | ||
721 | goto tx_err_link_failure; | ||
722 | ndst = xfrm_lookup(net, ndst, flowi6_to_flowi(fl6), NULL, 0); | ||
723 | if (IS_ERR(ndst)) { | ||
724 | err = PTR_ERR(ndst); | ||
725 | ndst = NULL; | ||
726 | goto tx_err_link_failure; | ||
727 | } | ||
728 | dst = ndst; | ||
729 | } | ||
730 | |||
731 | tdev = dst->dev; | ||
732 | |||
733 | if (tdev == dev) { | ||
734 | stats->collisions++; | ||
735 | net_warn_ratelimited("%s: Local routing loop detected!\n", | ||
736 | tunnel->parms.name); | ||
737 | goto tx_err_dst_release; | ||
738 | } | ||
739 | |||
740 | mtu = dst_mtu(dst) - sizeof(*ipv6h); | ||
741 | if (encap_limit >= 0) { | ||
742 | max_headroom += 8; | ||
743 | mtu -= 8; | ||
744 | } | ||
745 | if (mtu < IPV6_MIN_MTU) | ||
746 | mtu = IPV6_MIN_MTU; | ||
747 | if (skb_dst(skb)) | ||
748 | skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu); | ||
749 | if (skb->len > mtu) { | ||
750 | *pmtu = mtu; | ||
751 | err = -EMSGSIZE; | ||
752 | goto tx_err_dst_release; | ||
753 | } | ||
754 | |||
755 | if (tunnel->err_count > 0) { | ||
756 | if (time_before(jiffies, | ||
757 | tunnel->err_time + IP6TUNNEL_ERR_TIMEO)) { | ||
758 | tunnel->err_count--; | ||
759 | |||
760 | dst_link_failure(skb); | ||
761 | } else | ||
762 | tunnel->err_count = 0; | ||
763 | } | ||
764 | |||
765 | max_headroom = LL_RESERVED_SPACE(tdev) + gre_hlen + dst->header_len; | ||
766 | |||
767 | if (skb_headroom(skb) < max_headroom || skb_shared(skb) || | ||
768 | (skb_cloned(skb) && !skb_clone_writable(skb, 0))) { | ||
769 | new_skb = skb_realloc_headroom(skb, max_headroom); | ||
770 | if (max_headroom > dev->needed_headroom) | ||
771 | dev->needed_headroom = max_headroom; | ||
772 | if (!new_skb) | ||
773 | goto tx_err_dst_release; | ||
774 | |||
775 | if (skb->sk) | ||
776 | skb_set_owner_w(new_skb, skb->sk); | ||
777 | consume_skb(skb); | ||
778 | skb = new_skb; | ||
779 | } | ||
780 | |||
781 | skb_dst_drop(skb); | ||
782 | |||
783 | if (fl6->flowi6_mark) { | ||
784 | skb_dst_set(skb, dst); | ||
785 | ndst = NULL; | ||
786 | } else { | ||
787 | skb_dst_set_noref(skb, dst); | ||
788 | } | ||
789 | |||
790 | skb->transport_header = skb->network_header; | ||
791 | |||
792 | proto = NEXTHDR_GRE; | ||
793 | if (encap_limit >= 0) { | ||
794 | init_tel_txopt(&opt, encap_limit); | ||
795 | ipv6_push_nfrag_opts(skb, &opt.ops, &proto, NULL); | ||
796 | } | ||
797 | |||
798 | skb_push(skb, gre_hlen); | ||
799 | skb_reset_network_header(skb); | ||
800 | |||
801 | /* | ||
802 | * Push down and install the IP header. | ||
803 | */ | ||
804 | ipv6h = ipv6_hdr(skb); | ||
805 | *(__be32 *)ipv6h = fl6->flowlabel | htonl(0x60000000); | ||
806 | dsfield = INET_ECN_encapsulate(0, dsfield); | ||
807 | ipv6_change_dsfield(ipv6h, ~INET_ECN_MASK, dsfield); | ||
808 | ipv6h->hop_limit = tunnel->parms.hop_limit; | ||
809 | ipv6h->nexthdr = proto; | ||
810 | ipv6h->saddr = fl6->saddr; | ||
811 | ipv6h->daddr = fl6->daddr; | ||
812 | |||
813 | ((__be16 *)(ipv6h + 1))[0] = tunnel->parms.o_flags; | ||
814 | ((__be16 *)(ipv6h + 1))[1] = (dev->type == ARPHRD_ETHER) ? | ||
815 | htons(ETH_P_TEB) : skb->protocol; | ||
816 | |||
817 | if (tunnel->parms.o_flags&(GRE_KEY|GRE_CSUM|GRE_SEQ)) { | ||
818 | __be32 *ptr = (__be32 *)(((u8 *)ipv6h) + tunnel->hlen - 4); | ||
819 | |||
820 | if (tunnel->parms.o_flags&GRE_SEQ) { | ||
821 | ++tunnel->o_seqno; | ||
822 | *ptr = htonl(tunnel->o_seqno); | ||
823 | ptr--; | ||
824 | } | ||
825 | if (tunnel->parms.o_flags&GRE_KEY) { | ||
826 | *ptr = tunnel->parms.o_key; | ||
827 | ptr--; | ||
828 | } | ||
829 | if (tunnel->parms.o_flags&GRE_CSUM) { | ||
830 | *ptr = 0; | ||
831 | *(__sum16 *)ptr = ip_compute_csum((void *)(ipv6h+1), | ||
832 | skb->len - sizeof(struct ipv6hdr)); | ||
833 | } | ||
834 | } | ||
835 | |||
836 | nf_reset(skb); | ||
837 | pkt_len = skb->len; | ||
838 | err = ip6_local_out(skb); | ||
839 | |||
840 | if (net_xmit_eval(err) == 0) { | ||
841 | struct pcpu_tstats *tstats = this_cpu_ptr(tunnel->dev->tstats); | ||
842 | |||
843 | tstats->tx_bytes += pkt_len; | ||
844 | tstats->tx_packets++; | ||
845 | } else { | ||
846 | stats->tx_errors++; | ||
847 | stats->tx_aborted_errors++; | ||
848 | } | ||
849 | |||
850 | if (ndst) | ||
851 | ip6_tnl_dst_store(tunnel, ndst); | ||
852 | |||
853 | return 0; | ||
854 | tx_err_link_failure: | ||
855 | stats->tx_carrier_errors++; | ||
856 | dst_link_failure(skb); | ||
857 | tx_err_dst_release: | ||
858 | dst_release(ndst); | ||
859 | return err; | ||
860 | } | ||
861 | |||
862 | static inline int ip6gre_xmit_ipv4(struct sk_buff *skb, struct net_device *dev) | ||
863 | { | ||
864 | struct ip6_tnl *t = netdev_priv(dev); | ||
865 | const struct iphdr *iph = ip_hdr(skb); | ||
866 | int encap_limit = -1; | ||
867 | struct flowi6 fl6; | ||
868 | __u8 dsfield; | ||
869 | __u32 mtu; | ||
870 | int err; | ||
871 | |||
872 | if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) | ||
873 | encap_limit = t->parms.encap_limit; | ||
874 | |||
875 | memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6)); | ||
876 | fl6.flowi6_proto = IPPROTO_IPIP; | ||
877 | |||
878 | dsfield = ipv4_get_dsfield(iph); | ||
879 | |||
880 | if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS) | ||
881 | fl6.flowlabel |= htonl((__u32)iph->tos << IPV6_TCLASS_SHIFT) | ||
882 | & IPV6_TCLASS_MASK; | ||
883 | if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK) | ||
884 | fl6.flowi6_mark = skb->mark; | ||
885 | |||
886 | err = ip6gre_xmit2(skb, dev, dsfield, &fl6, encap_limit, &mtu); | ||
887 | if (err != 0) { | ||
888 | /* XXX: send ICMP error even if DF is not set. */ | ||
889 | if (err == -EMSGSIZE) | ||
890 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, | ||
891 | htonl(mtu)); | ||
892 | return -1; | ||
893 | } | ||
894 | |||
895 | return 0; | ||
896 | } | ||
897 | |||
898 | static inline int ip6gre_xmit_ipv6(struct sk_buff *skb, struct net_device *dev) | ||
899 | { | ||
900 | struct ip6_tnl *t = netdev_priv(dev); | ||
901 | struct ipv6hdr *ipv6h = ipv6_hdr(skb); | ||
902 | int encap_limit = -1; | ||
903 | __u16 offset; | ||
904 | struct flowi6 fl6; | ||
905 | __u8 dsfield; | ||
906 | __u32 mtu; | ||
907 | int err; | ||
908 | |||
909 | if (ipv6_addr_equal(&t->parms.raddr, &ipv6h->saddr)) | ||
910 | return -1; | ||
911 | |||
912 | offset = ip6_tnl_parse_tlv_enc_lim(skb, skb_network_header(skb)); | ||
913 | if (offset > 0) { | ||
914 | struct ipv6_tlv_tnl_enc_lim *tel; | ||
915 | tel = (struct ipv6_tlv_tnl_enc_lim *)&skb_network_header(skb)[offset]; | ||
916 | if (tel->encap_limit == 0) { | ||
917 | icmpv6_send(skb, ICMPV6_PARAMPROB, | ||
918 | ICMPV6_HDR_FIELD, offset + 2); | ||
919 | return -1; | ||
920 | } | ||
921 | encap_limit = tel->encap_limit - 1; | ||
922 | } else if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) | ||
923 | encap_limit = t->parms.encap_limit; | ||
924 | |||
925 | memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6)); | ||
926 | fl6.flowi6_proto = IPPROTO_IPV6; | ||
927 | |||
928 | dsfield = ipv6_get_dsfield(ipv6h); | ||
929 | if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS) | ||
930 | fl6.flowlabel |= (*(__be32 *) ipv6h & IPV6_TCLASS_MASK); | ||
931 | if (t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL) | ||
932 | fl6.flowlabel |= (*(__be32 *) ipv6h & IPV6_FLOWLABEL_MASK); | ||
933 | if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK) | ||
934 | fl6.flowi6_mark = skb->mark; | ||
935 | |||
936 | err = ip6gre_xmit2(skb, dev, dsfield, &fl6, encap_limit, &mtu); | ||
937 | if (err != 0) { | ||
938 | if (err == -EMSGSIZE) | ||
939 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); | ||
940 | return -1; | ||
941 | } | ||
942 | |||
943 | return 0; | ||
944 | } | ||
945 | |||
946 | /** | ||
947 | * ip6_tnl_addr_conflict - compare packet addresses to tunnel's own | ||
948 | * @t: the outgoing tunnel device | ||
949 | * @hdr: IPv6 header from the incoming packet | ||
950 | * | ||
951 | * Description: | ||
952 | * Avoid trivial tunneling loop by checking that tunnel exit-point | ||
953 | * doesn't match source of incoming packet. | ||
954 | * | ||
955 | * Return: | ||
956 | * 1 if conflict, | ||
957 | * 0 else | ||
958 | **/ | ||
959 | |||
960 | static inline bool ip6gre_tnl_addr_conflict(const struct ip6_tnl *t, | ||
961 | const struct ipv6hdr *hdr) | ||
962 | { | ||
963 | return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr); | ||
964 | } | ||
965 | |||
966 | static int ip6gre_xmit_other(struct sk_buff *skb, struct net_device *dev) | ||
967 | { | ||
968 | struct ip6_tnl *t = netdev_priv(dev); | ||
969 | int encap_limit = -1; | ||
970 | struct flowi6 fl6; | ||
971 | __u32 mtu; | ||
972 | int err; | ||
973 | |||
974 | if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) | ||
975 | encap_limit = t->parms.encap_limit; | ||
976 | |||
977 | memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6)); | ||
978 | fl6.flowi6_proto = skb->protocol; | ||
979 | |||
980 | err = ip6gre_xmit2(skb, dev, 0, &fl6, encap_limit, &mtu); | ||
981 | |||
982 | return err; | ||
983 | } | ||
984 | |||
985 | static netdev_tx_t ip6gre_tunnel_xmit(struct sk_buff *skb, | ||
986 | struct net_device *dev) | ||
987 | { | ||
988 | struct ip6_tnl *t = netdev_priv(dev); | ||
989 | struct net_device_stats *stats = &t->dev->stats; | ||
990 | int ret; | ||
991 | |||
992 | if (!ip6_tnl_xmit_ctl(t)) | ||
993 | return -1; | ||
994 | |||
995 | switch (skb->protocol) { | ||
996 | case htons(ETH_P_IP): | ||
997 | ret = ip6gre_xmit_ipv4(skb, dev); | ||
998 | break; | ||
999 | case htons(ETH_P_IPV6): | ||
1000 | ret = ip6gre_xmit_ipv6(skb, dev); | ||
1001 | break; | ||
1002 | default: | ||
1003 | ret = ip6gre_xmit_other(skb, dev); | ||
1004 | break; | ||
1005 | } | ||
1006 | |||
1007 | if (ret < 0) | ||
1008 | goto tx_err; | ||
1009 | |||
1010 | return NETDEV_TX_OK; | ||
1011 | |||
1012 | tx_err: | ||
1013 | stats->tx_errors++; | ||
1014 | stats->tx_dropped++; | ||
1015 | kfree_skb(skb); | ||
1016 | return NETDEV_TX_OK; | ||
1017 | } | ||
1018 | |||
1019 | static void ip6gre_tnl_link_config(struct ip6_tnl *t, int set_mtu) | ||
1020 | { | ||
1021 | struct net_device *dev = t->dev; | ||
1022 | struct __ip6_tnl_parm *p = &t->parms; | ||
1023 | struct flowi6 *fl6 = &t->fl.u.ip6; | ||
1024 | int addend = sizeof(struct ipv6hdr) + 4; | ||
1025 | |||
1026 | if (dev->type != ARPHRD_ETHER) { | ||
1027 | memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr)); | ||
1028 | memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr)); | ||
1029 | } | ||
1030 | |||
1031 | /* Set up flowi template */ | ||
1032 | fl6->saddr = p->laddr; | ||
1033 | fl6->daddr = p->raddr; | ||
1034 | fl6->flowi6_oif = p->link; | ||
1035 | fl6->flowlabel = 0; | ||
1036 | |||
1037 | if (!(p->flags&IP6_TNL_F_USE_ORIG_TCLASS)) | ||
1038 | fl6->flowlabel |= IPV6_TCLASS_MASK & p->flowinfo; | ||
1039 | if (!(p->flags&IP6_TNL_F_USE_ORIG_FLOWLABEL)) | ||
1040 | fl6->flowlabel |= IPV6_FLOWLABEL_MASK & p->flowinfo; | ||
1041 | |||
1042 | p->flags &= ~(IP6_TNL_F_CAP_XMIT|IP6_TNL_F_CAP_RCV|IP6_TNL_F_CAP_PER_PACKET); | ||
1043 | p->flags |= ip6_tnl_get_cap(t, &p->laddr, &p->raddr); | ||
1044 | |||
1045 | if (p->flags&IP6_TNL_F_CAP_XMIT && | ||
1046 | p->flags&IP6_TNL_F_CAP_RCV && dev->type != ARPHRD_ETHER) | ||
1047 | dev->flags |= IFF_POINTOPOINT; | ||
1048 | else | ||
1049 | dev->flags &= ~IFF_POINTOPOINT; | ||
1050 | |||
1051 | dev->iflink = p->link; | ||
1052 | |||
1053 | /* Precalculate GRE options length */ | ||
1054 | if (t->parms.o_flags&(GRE_CSUM|GRE_KEY|GRE_SEQ)) { | ||
1055 | if (t->parms.o_flags&GRE_CSUM) | ||
1056 | addend += 4; | ||
1057 | if (t->parms.o_flags&GRE_KEY) | ||
1058 | addend += 4; | ||
1059 | if (t->parms.o_flags&GRE_SEQ) | ||
1060 | addend += 4; | ||
1061 | } | ||
1062 | |||
1063 | if (p->flags & IP6_TNL_F_CAP_XMIT) { | ||
1064 | int strict = (ipv6_addr_type(&p->raddr) & | ||
1065 | (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL)); | ||
1066 | |||
1067 | struct rt6_info *rt = rt6_lookup(dev_net(dev), | ||
1068 | &p->raddr, &p->laddr, | ||
1069 | p->link, strict); | ||
1070 | |||
1071 | if (rt == NULL) | ||
1072 | return; | ||
1073 | |||
1074 | if (rt->dst.dev) { | ||
1075 | dev->hard_header_len = rt->dst.dev->hard_header_len + addend; | ||
1076 | |||
1077 | if (set_mtu) { | ||
1078 | dev->mtu = rt->dst.dev->mtu - addend; | ||
1079 | if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) | ||
1080 | dev->mtu -= 8; | ||
1081 | |||
1082 | if (dev->mtu < IPV6_MIN_MTU) | ||
1083 | dev->mtu = IPV6_MIN_MTU; | ||
1084 | } | ||
1085 | } | ||
1086 | dst_release(&rt->dst); | ||
1087 | } | ||
1088 | |||
1089 | t->hlen = addend; | ||
1090 | } | ||
1091 | |||
1092 | static int ip6gre_tnl_change(struct ip6_tnl *t, | ||
1093 | const struct __ip6_tnl_parm *p, int set_mtu) | ||
1094 | { | ||
1095 | t->parms.laddr = p->laddr; | ||
1096 | t->parms.raddr = p->raddr; | ||
1097 | t->parms.flags = p->flags; | ||
1098 | t->parms.hop_limit = p->hop_limit; | ||
1099 | t->parms.encap_limit = p->encap_limit; | ||
1100 | t->parms.flowinfo = p->flowinfo; | ||
1101 | t->parms.link = p->link; | ||
1102 | t->parms.proto = p->proto; | ||
1103 | t->parms.i_key = p->i_key; | ||
1104 | t->parms.o_key = p->o_key; | ||
1105 | t->parms.i_flags = p->i_flags; | ||
1106 | t->parms.o_flags = p->o_flags; | ||
1107 | ip6_tnl_dst_reset(t); | ||
1108 | ip6gre_tnl_link_config(t, set_mtu); | ||
1109 | return 0; | ||
1110 | } | ||
1111 | |||
1112 | static void ip6gre_tnl_parm_from_user(struct __ip6_tnl_parm *p, | ||
1113 | const struct ip6_tnl_parm2 *u) | ||
1114 | { | ||
1115 | p->laddr = u->laddr; | ||
1116 | p->raddr = u->raddr; | ||
1117 | p->flags = u->flags; | ||
1118 | p->hop_limit = u->hop_limit; | ||
1119 | p->encap_limit = u->encap_limit; | ||
1120 | p->flowinfo = u->flowinfo; | ||
1121 | p->link = u->link; | ||
1122 | p->i_key = u->i_key; | ||
1123 | p->o_key = u->o_key; | ||
1124 | p->i_flags = u->i_flags; | ||
1125 | p->o_flags = u->o_flags; | ||
1126 | memcpy(p->name, u->name, sizeof(u->name)); | ||
1127 | } | ||
1128 | |||
1129 | static void ip6gre_tnl_parm_to_user(struct ip6_tnl_parm2 *u, | ||
1130 | const struct __ip6_tnl_parm *p) | ||
1131 | { | ||
1132 | u->proto = IPPROTO_GRE; | ||
1133 | u->laddr = p->laddr; | ||
1134 | u->raddr = p->raddr; | ||
1135 | u->flags = p->flags; | ||
1136 | u->hop_limit = p->hop_limit; | ||
1137 | u->encap_limit = p->encap_limit; | ||
1138 | u->flowinfo = p->flowinfo; | ||
1139 | u->link = p->link; | ||
1140 | u->i_key = p->i_key; | ||
1141 | u->o_key = p->o_key; | ||
1142 | u->i_flags = p->i_flags; | ||
1143 | u->o_flags = p->o_flags; | ||
1144 | memcpy(u->name, p->name, sizeof(u->name)); | ||
1145 | } | ||
1146 | |||
1147 | static int ip6gre_tunnel_ioctl(struct net_device *dev, | ||
1148 | struct ifreq *ifr, int cmd) | ||
1149 | { | ||
1150 | int err = 0; | ||
1151 | struct ip6_tnl_parm2 p; | ||
1152 | struct __ip6_tnl_parm p1; | ||
1153 | struct ip6_tnl *t; | ||
1154 | struct net *net = dev_net(dev); | ||
1155 | struct ip6gre_net *ign = net_generic(net, ip6gre_net_id); | ||
1156 | |||
1157 | switch (cmd) { | ||
1158 | case SIOCGETTUNNEL: | ||
1159 | t = NULL; | ||
1160 | if (dev == ign->fb_tunnel_dev) { | ||
1161 | if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) { | ||
1162 | err = -EFAULT; | ||
1163 | break; | ||
1164 | } | ||
1165 | ip6gre_tnl_parm_from_user(&p1, &p); | ||
1166 | t = ip6gre_tunnel_locate(net, &p1, 0); | ||
1167 | } | ||
1168 | if (t == NULL) | ||
1169 | t = netdev_priv(dev); | ||
1170 | ip6gre_tnl_parm_to_user(&p, &t->parms); | ||
1171 | if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) | ||
1172 | err = -EFAULT; | ||
1173 | break; | ||
1174 | |||
1175 | case SIOCADDTUNNEL: | ||
1176 | case SIOCCHGTUNNEL: | ||
1177 | err = -EPERM; | ||
1178 | if (!capable(CAP_NET_ADMIN)) | ||
1179 | goto done; | ||
1180 | |||
1181 | err = -EFAULT; | ||
1182 | if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) | ||
1183 | goto done; | ||
1184 | |||
1185 | err = -EINVAL; | ||
1186 | if ((p.i_flags|p.o_flags)&(GRE_VERSION|GRE_ROUTING)) | ||
1187 | goto done; | ||
1188 | |||
1189 | if (!(p.i_flags&GRE_KEY)) | ||
1190 | p.i_key = 0; | ||
1191 | if (!(p.o_flags&GRE_KEY)) | ||
1192 | p.o_key = 0; | ||
1193 | |||
1194 | ip6gre_tnl_parm_from_user(&p1, &p); | ||
1195 | t = ip6gre_tunnel_locate(net, &p1, cmd == SIOCADDTUNNEL); | ||
1196 | |||
1197 | if (dev != ign->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) { | ||
1198 | if (t != NULL) { | ||
1199 | if (t->dev != dev) { | ||
1200 | err = -EEXIST; | ||
1201 | break; | ||
1202 | } | ||
1203 | } else { | ||
1204 | t = netdev_priv(dev); | ||
1205 | |||
1206 | ip6gre_tunnel_unlink(ign, t); | ||
1207 | synchronize_net(); | ||
1208 | ip6gre_tnl_change(t, &p1, 1); | ||
1209 | ip6gre_tunnel_link(ign, t); | ||
1210 | netdev_state_change(dev); | ||
1211 | } | ||
1212 | } | ||
1213 | |||
1214 | if (t) { | ||
1215 | err = 0; | ||
1216 | |||
1217 | ip6gre_tnl_parm_to_user(&p, &t->parms); | ||
1218 | if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) | ||
1219 | err = -EFAULT; | ||
1220 | } else | ||
1221 | err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT); | ||
1222 | break; | ||
1223 | |||
1224 | case SIOCDELTUNNEL: | ||
1225 | err = -EPERM; | ||
1226 | if (!capable(CAP_NET_ADMIN)) | ||
1227 | goto done; | ||
1228 | |||
1229 | if (dev == ign->fb_tunnel_dev) { | ||
1230 | err = -EFAULT; | ||
1231 | if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) | ||
1232 | goto done; | ||
1233 | err = -ENOENT; | ||
1234 | ip6gre_tnl_parm_from_user(&p1, &p); | ||
1235 | t = ip6gre_tunnel_locate(net, &p1, 0); | ||
1236 | if (t == NULL) | ||
1237 | goto done; | ||
1238 | err = -EPERM; | ||
1239 | if (t == netdev_priv(ign->fb_tunnel_dev)) | ||
1240 | goto done; | ||
1241 | dev = t->dev; | ||
1242 | } | ||
1243 | unregister_netdevice(dev); | ||
1244 | err = 0; | ||
1245 | break; | ||
1246 | |||
1247 | default: | ||
1248 | err = -EINVAL; | ||
1249 | } | ||
1250 | |||
1251 | done: | ||
1252 | return err; | ||
1253 | } | ||
1254 | |||
1255 | static int ip6gre_tunnel_change_mtu(struct net_device *dev, int new_mtu) | ||
1256 | { | ||
1257 | struct ip6_tnl *tunnel = netdev_priv(dev); | ||
1258 | if (new_mtu < 68 || | ||
1259 | new_mtu > 0xFFF8 - dev->hard_header_len - tunnel->hlen) | ||
1260 | return -EINVAL; | ||
1261 | dev->mtu = new_mtu; | ||
1262 | return 0; | ||
1263 | } | ||
1264 | |||
1265 | static int ip6gre_header(struct sk_buff *skb, struct net_device *dev, | ||
1266 | unsigned short type, | ||
1267 | const void *daddr, const void *saddr, unsigned int len) | ||
1268 | { | ||
1269 | struct ip6_tnl *t = netdev_priv(dev); | ||
1270 | struct ipv6hdr *ipv6h = (struct ipv6hdr *)skb_push(skb, t->hlen); | ||
1271 | __be16 *p = (__be16 *)(ipv6h+1); | ||
1272 | |||
1273 | *(__be32 *)ipv6h = t->fl.u.ip6.flowlabel | htonl(0x60000000); | ||
1274 | ipv6h->hop_limit = t->parms.hop_limit; | ||
1275 | ipv6h->nexthdr = NEXTHDR_GRE; | ||
1276 | ipv6h->saddr = t->parms.laddr; | ||
1277 | ipv6h->daddr = t->parms.raddr; | ||
1278 | |||
1279 | p[0] = t->parms.o_flags; | ||
1280 | p[1] = htons(type); | ||
1281 | |||
1282 | /* | ||
1283 | * Set the source hardware address. | ||
1284 | */ | ||
1285 | |||
1286 | if (saddr) | ||
1287 | memcpy(&ipv6h->saddr, saddr, sizeof(struct in6_addr)); | ||
1288 | if (daddr) | ||
1289 | memcpy(&ipv6h->daddr, daddr, sizeof(struct in6_addr)); | ||
1290 | if (!ipv6_addr_any(&ipv6h->daddr)) | ||
1291 | return t->hlen; | ||
1292 | |||
1293 | return -t->hlen; | ||
1294 | } | ||
1295 | |||
1296 | static int ip6gre_header_parse(const struct sk_buff *skb, unsigned char *haddr) | ||
1297 | { | ||
1298 | const struct ipv6hdr *ipv6h = (const struct ipv6hdr *)skb_mac_header(skb); | ||
1299 | memcpy(haddr, &ipv6h->saddr, sizeof(struct in6_addr)); | ||
1300 | return sizeof(struct in6_addr); | ||
1301 | } | ||
1302 | |||
1303 | static const struct header_ops ip6gre_header_ops = { | ||
1304 | .create = ip6gre_header, | ||
1305 | .parse = ip6gre_header_parse, | ||
1306 | }; | ||
1307 | |||
1308 | static const struct net_device_ops ip6gre_netdev_ops = { | ||
1309 | .ndo_init = ip6gre_tunnel_init, | ||
1310 | .ndo_uninit = ip6gre_tunnel_uninit, | ||
1311 | .ndo_start_xmit = ip6gre_tunnel_xmit, | ||
1312 | .ndo_do_ioctl = ip6gre_tunnel_ioctl, | ||
1313 | .ndo_change_mtu = ip6gre_tunnel_change_mtu, | ||
1314 | .ndo_get_stats64 = ip6gre_get_stats64, | ||
1315 | }; | ||
1316 | |||
1317 | static void ip6gre_dev_free(struct net_device *dev) | ||
1318 | { | ||
1319 | free_percpu(dev->tstats); | ||
1320 | free_netdev(dev); | ||
1321 | } | ||
1322 | |||
1323 | static void ip6gre_tunnel_setup(struct net_device *dev) | ||
1324 | { | ||
1325 | struct ip6_tnl *t; | ||
1326 | |||
1327 | dev->netdev_ops = &ip6gre_netdev_ops; | ||
1328 | dev->destructor = ip6gre_dev_free; | ||
1329 | |||
1330 | dev->type = ARPHRD_IP6GRE; | ||
1331 | dev->hard_header_len = LL_MAX_HEADER + sizeof(struct ipv6hdr) + 4; | ||
1332 | dev->mtu = ETH_DATA_LEN - sizeof(struct ipv6hdr) - 4; | ||
1333 | t = netdev_priv(dev); | ||
1334 | if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) | ||
1335 | dev->mtu -= 8; | ||
1336 | dev->flags |= IFF_NOARP; | ||
1337 | dev->iflink = 0; | ||
1338 | dev->addr_len = sizeof(struct in6_addr); | ||
1339 | dev->features |= NETIF_F_NETNS_LOCAL; | ||
1340 | dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; | ||
1341 | } | ||
1342 | |||
1343 | static int ip6gre_tunnel_init(struct net_device *dev) | ||
1344 | { | ||
1345 | struct ip6_tnl *tunnel; | ||
1346 | |||
1347 | tunnel = netdev_priv(dev); | ||
1348 | |||
1349 | tunnel->dev = dev; | ||
1350 | strcpy(tunnel->parms.name, dev->name); | ||
1351 | |||
1352 | memcpy(dev->dev_addr, &tunnel->parms.laddr, sizeof(struct in6_addr)); | ||
1353 | memcpy(dev->broadcast, &tunnel->parms.raddr, sizeof(struct in6_addr)); | ||
1354 | |||
1355 | if (ipv6_addr_any(&tunnel->parms.raddr)) | ||
1356 | dev->header_ops = &ip6gre_header_ops; | ||
1357 | |||
1358 | dev->tstats = alloc_percpu(struct pcpu_tstats); | ||
1359 | if (!dev->tstats) | ||
1360 | return -ENOMEM; | ||
1361 | |||
1362 | return 0; | ||
1363 | } | ||
1364 | |||
1365 | static void ip6gre_fb_tunnel_init(struct net_device *dev) | ||
1366 | { | ||
1367 | struct ip6_tnl *tunnel = netdev_priv(dev); | ||
1368 | |||
1369 | tunnel->dev = dev; | ||
1370 | strcpy(tunnel->parms.name, dev->name); | ||
1371 | |||
1372 | tunnel->hlen = sizeof(struct ipv6hdr) + 4; | ||
1373 | |||
1374 | dev_hold(dev); | ||
1375 | } | ||
1376 | |||
1377 | |||
1378 | static struct inet6_protocol ip6gre_protocol __read_mostly = { | ||
1379 | .handler = ip6gre_rcv, | ||
1380 | .err_handler = ip6gre_err, | ||
1381 | .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, | ||
1382 | }; | ||
1383 | |||
1384 | static void ip6gre_destroy_tunnels(struct ip6gre_net *ign, | ||
1385 | struct list_head *head) | ||
1386 | { | ||
1387 | int prio; | ||
1388 | |||
1389 | for (prio = 0; prio < 4; prio++) { | ||
1390 | int h; | ||
1391 | for (h = 0; h < HASH_SIZE; h++) { | ||
1392 | struct ip6_tnl *t; | ||
1393 | |||
1394 | t = rtnl_dereference(ign->tunnels[prio][h]); | ||
1395 | |||
1396 | while (t != NULL) { | ||
1397 | unregister_netdevice_queue(t->dev, head); | ||
1398 | t = rtnl_dereference(t->next); | ||
1399 | } | ||
1400 | } | ||
1401 | } | ||
1402 | } | ||
1403 | |||
1404 | static int __net_init ip6gre_init_net(struct net *net) | ||
1405 | { | ||
1406 | struct ip6gre_net *ign = net_generic(net, ip6gre_net_id); | ||
1407 | int err; | ||
1408 | |||
1409 | ign->fb_tunnel_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6gre0", | ||
1410 | ip6gre_tunnel_setup); | ||
1411 | if (!ign->fb_tunnel_dev) { | ||
1412 | err = -ENOMEM; | ||
1413 | goto err_alloc_dev; | ||
1414 | } | ||
1415 | dev_net_set(ign->fb_tunnel_dev, net); | ||
1416 | |||
1417 | ip6gre_fb_tunnel_init(ign->fb_tunnel_dev); | ||
1418 | ign->fb_tunnel_dev->rtnl_link_ops = &ip6gre_link_ops; | ||
1419 | |||
1420 | err = register_netdev(ign->fb_tunnel_dev); | ||
1421 | if (err) | ||
1422 | goto err_reg_dev; | ||
1423 | |||
1424 | rcu_assign_pointer(ign->tunnels_wc[0], | ||
1425 | netdev_priv(ign->fb_tunnel_dev)); | ||
1426 | return 0; | ||
1427 | |||
1428 | err_reg_dev: | ||
1429 | ip6gre_dev_free(ign->fb_tunnel_dev); | ||
1430 | err_alloc_dev: | ||
1431 | return err; | ||
1432 | } | ||
1433 | |||
1434 | static void __net_exit ip6gre_exit_net(struct net *net) | ||
1435 | { | ||
1436 | struct ip6gre_net *ign; | ||
1437 | LIST_HEAD(list); | ||
1438 | |||
1439 | ign = net_generic(net, ip6gre_net_id); | ||
1440 | rtnl_lock(); | ||
1441 | ip6gre_destroy_tunnels(ign, &list); | ||
1442 | unregister_netdevice_many(&list); | ||
1443 | rtnl_unlock(); | ||
1444 | } | ||
1445 | |||
1446 | static struct pernet_operations ip6gre_net_ops = { | ||
1447 | .init = ip6gre_init_net, | ||
1448 | .exit = ip6gre_exit_net, | ||
1449 | .id = &ip6gre_net_id, | ||
1450 | .size = sizeof(struct ip6gre_net), | ||
1451 | }; | ||
1452 | |||
1453 | static int ip6gre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[]) | ||
1454 | { | ||
1455 | __be16 flags; | ||
1456 | |||
1457 | if (!data) | ||
1458 | return 0; | ||
1459 | |||
1460 | flags = 0; | ||
1461 | if (data[IFLA_GRE_IFLAGS]) | ||
1462 | flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]); | ||
1463 | if (data[IFLA_GRE_OFLAGS]) | ||
1464 | flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]); | ||
1465 | if (flags & (GRE_VERSION|GRE_ROUTING)) | ||
1466 | return -EINVAL; | ||
1467 | |||
1468 | return 0; | ||
1469 | } | ||
1470 | |||
1471 | static int ip6gre_tap_validate(struct nlattr *tb[], struct nlattr *data[]) | ||
1472 | { | ||
1473 | struct in6_addr daddr; | ||
1474 | |||
1475 | if (tb[IFLA_ADDRESS]) { | ||
1476 | if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) | ||
1477 | return -EINVAL; | ||
1478 | if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) | ||
1479 | return -EADDRNOTAVAIL; | ||
1480 | } | ||
1481 | |||
1482 | if (!data) | ||
1483 | goto out; | ||
1484 | |||
1485 | if (data[IFLA_GRE_REMOTE]) { | ||
1486 | nla_memcpy(&daddr, data[IFLA_GRE_REMOTE], sizeof(struct in6_addr)); | ||
1487 | if (ipv6_addr_any(&daddr)) | ||
1488 | return -EINVAL; | ||
1489 | } | ||
1490 | |||
1491 | out: | ||
1492 | return ip6gre_tunnel_validate(tb, data); | ||
1493 | } | ||
1494 | |||
1495 | |||
1496 | static void ip6gre_netlink_parms(struct nlattr *data[], | ||
1497 | struct __ip6_tnl_parm *parms) | ||
1498 | { | ||
1499 | memset(parms, 0, sizeof(*parms)); | ||
1500 | |||
1501 | if (!data) | ||
1502 | return; | ||
1503 | |||
1504 | if (data[IFLA_GRE_LINK]) | ||
1505 | parms->link = nla_get_u32(data[IFLA_GRE_LINK]); | ||
1506 | |||
1507 | if (data[IFLA_GRE_IFLAGS]) | ||
1508 | parms->i_flags = nla_get_be16(data[IFLA_GRE_IFLAGS]); | ||
1509 | |||
1510 | if (data[IFLA_GRE_OFLAGS]) | ||
1511 | parms->o_flags = nla_get_be16(data[IFLA_GRE_OFLAGS]); | ||
1512 | |||
1513 | if (data[IFLA_GRE_IKEY]) | ||
1514 | parms->i_key = nla_get_be32(data[IFLA_GRE_IKEY]); | ||
1515 | |||
1516 | if (data[IFLA_GRE_OKEY]) | ||
1517 | parms->o_key = nla_get_be32(data[IFLA_GRE_OKEY]); | ||
1518 | |||
1519 | if (data[IFLA_GRE_LOCAL]) | ||
1520 | nla_memcpy(&parms->laddr, data[IFLA_GRE_LOCAL], sizeof(struct in6_addr)); | ||
1521 | |||
1522 | if (data[IFLA_GRE_REMOTE]) | ||
1523 | nla_memcpy(&parms->raddr, data[IFLA_GRE_REMOTE], sizeof(struct in6_addr)); | ||
1524 | |||
1525 | if (data[IFLA_GRE_TTL]) | ||
1526 | parms->hop_limit = nla_get_u8(data[IFLA_GRE_TTL]); | ||
1527 | |||
1528 | if (data[IFLA_GRE_ENCAP_LIMIT]) | ||
1529 | parms->encap_limit = nla_get_u8(data[IFLA_GRE_ENCAP_LIMIT]); | ||
1530 | |||
1531 | if (data[IFLA_GRE_FLOWINFO]) | ||
1532 | parms->flowinfo = nla_get_u32(data[IFLA_GRE_FLOWINFO]); | ||
1533 | |||
1534 | if (data[IFLA_GRE_FLAGS]) | ||
1535 | parms->flags = nla_get_u32(data[IFLA_GRE_FLAGS]); | ||
1536 | } | ||
1537 | |||
1538 | static int ip6gre_tap_init(struct net_device *dev) | ||
1539 | { | ||
1540 | struct ip6_tnl *tunnel; | ||
1541 | |||
1542 | tunnel = netdev_priv(dev); | ||
1543 | |||
1544 | tunnel->dev = dev; | ||
1545 | strcpy(tunnel->parms.name, dev->name); | ||
1546 | |||
1547 | ip6gre_tnl_link_config(tunnel, 1); | ||
1548 | |||
1549 | dev->tstats = alloc_percpu(struct pcpu_tstats); | ||
1550 | if (!dev->tstats) | ||
1551 | return -ENOMEM; | ||
1552 | |||
1553 | return 0; | ||
1554 | } | ||
1555 | |||
1556 | static const struct net_device_ops ip6gre_tap_netdev_ops = { | ||
1557 | .ndo_init = ip6gre_tap_init, | ||
1558 | .ndo_uninit = ip6gre_tunnel_uninit, | ||
1559 | .ndo_start_xmit = ip6gre_tunnel_xmit, | ||
1560 | .ndo_set_mac_address = eth_mac_addr, | ||
1561 | .ndo_validate_addr = eth_validate_addr, | ||
1562 | .ndo_change_mtu = ip6gre_tunnel_change_mtu, | ||
1563 | .ndo_get_stats64 = ip6gre_get_stats64, | ||
1564 | }; | ||
1565 | |||
1566 | static void ip6gre_tap_setup(struct net_device *dev) | ||
1567 | { | ||
1568 | |||
1569 | ether_setup(dev); | ||
1570 | |||
1571 | dev->netdev_ops = &ip6gre_tap_netdev_ops; | ||
1572 | dev->destructor = ip6gre_dev_free; | ||
1573 | |||
1574 | dev->iflink = 0; | ||
1575 | dev->features |= NETIF_F_NETNS_LOCAL; | ||
1576 | } | ||
1577 | |||
1578 | static int ip6gre_newlink(struct net *src_net, struct net_device *dev, | ||
1579 | struct nlattr *tb[], struct nlattr *data[]) | ||
1580 | { | ||
1581 | struct ip6_tnl *nt; | ||
1582 | struct net *net = dev_net(dev); | ||
1583 | struct ip6gre_net *ign = net_generic(net, ip6gre_net_id); | ||
1584 | int err; | ||
1585 | |||
1586 | nt = netdev_priv(dev); | ||
1587 | ip6gre_netlink_parms(data, &nt->parms); | ||
1588 | |||
1589 | if (ip6gre_tunnel_find(net, &nt->parms, dev->type)) | ||
1590 | return -EEXIST; | ||
1591 | |||
1592 | if (dev->type == ARPHRD_ETHER && !tb[IFLA_ADDRESS]) | ||
1593 | eth_hw_addr_random(dev); | ||
1594 | |||
1595 | nt->dev = dev; | ||
1596 | ip6gre_tnl_link_config(nt, !tb[IFLA_MTU]); | ||
1597 | |||
1598 | /* Can use a lockless transmit, unless we generate output sequences */ | ||
1599 | if (!(nt->parms.o_flags & GRE_SEQ)) | ||
1600 | dev->features |= NETIF_F_LLTX; | ||
1601 | |||
1602 | err = register_netdevice(dev); | ||
1603 | if (err) | ||
1604 | goto out; | ||
1605 | |||
1606 | dev_hold(dev); | ||
1607 | ip6gre_tunnel_link(ign, nt); | ||
1608 | |||
1609 | out: | ||
1610 | return err; | ||
1611 | } | ||
1612 | |||
1613 | static int ip6gre_changelink(struct net_device *dev, struct nlattr *tb[], | ||
1614 | struct nlattr *data[]) | ||
1615 | { | ||
1616 | struct ip6_tnl *t, *nt; | ||
1617 | struct net *net = dev_net(dev); | ||
1618 | struct ip6gre_net *ign = net_generic(net, ip6gre_net_id); | ||
1619 | struct __ip6_tnl_parm p; | ||
1620 | |||
1621 | if (dev == ign->fb_tunnel_dev) | ||
1622 | return -EINVAL; | ||
1623 | |||
1624 | nt = netdev_priv(dev); | ||
1625 | ip6gre_netlink_parms(data, &p); | ||
1626 | |||
1627 | t = ip6gre_tunnel_locate(net, &p, 0); | ||
1628 | |||
1629 | if (t) { | ||
1630 | if (t->dev != dev) | ||
1631 | return -EEXIST; | ||
1632 | } else { | ||
1633 | t = nt; | ||
1634 | |||
1635 | ip6gre_tunnel_unlink(ign, t); | ||
1636 | ip6gre_tnl_change(t, &p, !tb[IFLA_MTU]); | ||
1637 | ip6gre_tunnel_link(ign, t); | ||
1638 | netdev_state_change(dev); | ||
1639 | } | ||
1640 | |||
1641 | return 0; | ||
1642 | } | ||
1643 | |||
1644 | static size_t ip6gre_get_size(const struct net_device *dev) | ||
1645 | { | ||
1646 | return | ||
1647 | /* IFLA_GRE_LINK */ | ||
1648 | nla_total_size(4) + | ||
1649 | /* IFLA_GRE_IFLAGS */ | ||
1650 | nla_total_size(2) + | ||
1651 | /* IFLA_GRE_OFLAGS */ | ||
1652 | nla_total_size(2) + | ||
1653 | /* IFLA_GRE_IKEY */ | ||
1654 | nla_total_size(4) + | ||
1655 | /* IFLA_GRE_OKEY */ | ||
1656 | nla_total_size(4) + | ||
1657 | /* IFLA_GRE_LOCAL */ | ||
1658 | nla_total_size(4) + | ||
1659 | /* IFLA_GRE_REMOTE */ | ||
1660 | nla_total_size(4) + | ||
1661 | /* IFLA_GRE_TTL */ | ||
1662 | nla_total_size(1) + | ||
1663 | /* IFLA_GRE_TOS */ | ||
1664 | nla_total_size(1) + | ||
1665 | /* IFLA_GRE_ENCAP_LIMIT */ | ||
1666 | nla_total_size(1) + | ||
1667 | /* IFLA_GRE_FLOWINFO */ | ||
1668 | nla_total_size(4) + | ||
1669 | /* IFLA_GRE_FLAGS */ | ||
1670 | nla_total_size(4) + | ||
1671 | 0; | ||
1672 | } | ||
1673 | |||
1674 | static int ip6gre_fill_info(struct sk_buff *skb, const struct net_device *dev) | ||
1675 | { | ||
1676 | struct ip6_tnl *t = netdev_priv(dev); | ||
1677 | struct __ip6_tnl_parm *p = &t->parms; | ||
1678 | |||
1679 | if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) || | ||
1680 | nla_put_be16(skb, IFLA_GRE_IFLAGS, p->i_flags) || | ||
1681 | nla_put_be16(skb, IFLA_GRE_OFLAGS, p->o_flags) || | ||
1682 | nla_put_be32(skb, IFLA_GRE_IKEY, p->i_key) || | ||
1683 | nla_put_be32(skb, IFLA_GRE_OKEY, p->o_key) || | ||
1684 | nla_put(skb, IFLA_GRE_LOCAL, sizeof(struct in6_addr), &p->raddr) || | ||
1685 | nla_put(skb, IFLA_GRE_REMOTE, sizeof(struct in6_addr), &p->laddr) || | ||
1686 | nla_put_u8(skb, IFLA_GRE_TTL, p->hop_limit) || | ||
1687 | /*nla_put_u8(skb, IFLA_GRE_TOS, t->priority) ||*/ | ||
1688 | nla_put_u8(skb, IFLA_GRE_ENCAP_LIMIT, p->encap_limit) || | ||
1689 | nla_put_be32(skb, IFLA_GRE_FLOWINFO, p->flowinfo) || | ||
1690 | nla_put_u32(skb, IFLA_GRE_FLAGS, p->flags)) | ||
1691 | goto nla_put_failure; | ||
1692 | return 0; | ||
1693 | |||
1694 | nla_put_failure: | ||
1695 | return -EMSGSIZE; | ||
1696 | } | ||
1697 | |||
1698 | static const struct nla_policy ip6gre_policy[IFLA_GRE_MAX + 1] = { | ||
1699 | [IFLA_GRE_LINK] = { .type = NLA_U32 }, | ||
1700 | [IFLA_GRE_IFLAGS] = { .type = NLA_U16 }, | ||
1701 | [IFLA_GRE_OFLAGS] = { .type = NLA_U16 }, | ||
1702 | [IFLA_GRE_IKEY] = { .type = NLA_U32 }, | ||
1703 | [IFLA_GRE_OKEY] = { .type = NLA_U32 }, | ||
1704 | [IFLA_GRE_LOCAL] = { .len = FIELD_SIZEOF(struct ipv6hdr, saddr) }, | ||
1705 | [IFLA_GRE_REMOTE] = { .len = FIELD_SIZEOF(struct ipv6hdr, daddr) }, | ||
1706 | [IFLA_GRE_TTL] = { .type = NLA_U8 }, | ||
1707 | [IFLA_GRE_ENCAP_LIMIT] = { .type = NLA_U8 }, | ||
1708 | [IFLA_GRE_FLOWINFO] = { .type = NLA_U32 }, | ||
1709 | [IFLA_GRE_FLAGS] = { .type = NLA_U32 }, | ||
1710 | }; | ||
1711 | |||
1712 | static struct rtnl_link_ops ip6gre_link_ops __read_mostly = { | ||
1713 | .kind = "ip6gre", | ||
1714 | .maxtype = IFLA_GRE_MAX, | ||
1715 | .policy = ip6gre_policy, | ||
1716 | .priv_size = sizeof(struct ip6_tnl), | ||
1717 | .setup = ip6gre_tunnel_setup, | ||
1718 | .validate = ip6gre_tunnel_validate, | ||
1719 | .newlink = ip6gre_newlink, | ||
1720 | .changelink = ip6gre_changelink, | ||
1721 | .get_size = ip6gre_get_size, | ||
1722 | .fill_info = ip6gre_fill_info, | ||
1723 | }; | ||
1724 | |||
1725 | static struct rtnl_link_ops ip6gre_tap_ops __read_mostly = { | ||
1726 | .kind = "ip6gretap", | ||
1727 | .maxtype = IFLA_GRE_MAX, | ||
1728 | .policy = ip6gre_policy, | ||
1729 | .priv_size = sizeof(struct ip6_tnl), | ||
1730 | .setup = ip6gre_tap_setup, | ||
1731 | .validate = ip6gre_tap_validate, | ||
1732 | .newlink = ip6gre_newlink, | ||
1733 | .changelink = ip6gre_changelink, | ||
1734 | .get_size = ip6gre_get_size, | ||
1735 | .fill_info = ip6gre_fill_info, | ||
1736 | }; | ||
1737 | |||
1738 | /* | ||
1739 | * And now the modules code and kernel interface. | ||
1740 | */ | ||
1741 | |||
1742 | static int __init ip6gre_init(void) | ||
1743 | { | ||
1744 | int err; | ||
1745 | |||
1746 | pr_info("GRE over IPv6 tunneling driver\n"); | ||
1747 | |||
1748 | err = register_pernet_device(&ip6gre_net_ops); | ||
1749 | if (err < 0) | ||
1750 | return err; | ||
1751 | |||
1752 | err = inet6_add_protocol(&ip6gre_protocol, IPPROTO_GRE); | ||
1753 | if (err < 0) { | ||
1754 | pr_info("%s: can't add protocol\n", __func__); | ||
1755 | goto add_proto_failed; | ||
1756 | } | ||
1757 | |||
1758 | err = rtnl_link_register(&ip6gre_link_ops); | ||
1759 | if (err < 0) | ||
1760 | goto rtnl_link_failed; | ||
1761 | |||
1762 | err = rtnl_link_register(&ip6gre_tap_ops); | ||
1763 | if (err < 0) | ||
1764 | goto tap_ops_failed; | ||
1765 | |||
1766 | out: | ||
1767 | return err; | ||
1768 | |||
1769 | tap_ops_failed: | ||
1770 | rtnl_link_unregister(&ip6gre_link_ops); | ||
1771 | rtnl_link_failed: | ||
1772 | inet6_del_protocol(&ip6gre_protocol, IPPROTO_GRE); | ||
1773 | add_proto_failed: | ||
1774 | unregister_pernet_device(&ip6gre_net_ops); | ||
1775 | goto out; | ||
1776 | } | ||
1777 | |||
1778 | static void __exit ip6gre_fini(void) | ||
1779 | { | ||
1780 | rtnl_link_unregister(&ip6gre_tap_ops); | ||
1781 | rtnl_link_unregister(&ip6gre_link_ops); | ||
1782 | inet6_del_protocol(&ip6gre_protocol, IPPROTO_GRE); | ||
1783 | unregister_pernet_device(&ip6gre_net_ops); | ||
1784 | } | ||
1785 | |||
1786 | module_init(ip6gre_init); | ||
1787 | module_exit(ip6gre_fini); | ||
1788 | MODULE_LICENSE("GPL"); | ||
1789 | MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)"); | ||
1790 | MODULE_DESCRIPTION("GRE over IPv6 tunneling device"); | ||
1791 | MODULE_ALIAS_RTNL_LINK("ip6gre"); | ||
1792 | MODULE_ALIAS_NETDEV("ip6gre0"); | ||
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 5b2d63ed793e..3dd4a37488d5 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -123,16 +123,11 @@ static int ip6_finish_output2(struct sk_buff *skb) | |||
123 | skb->len); | 123 | skb->len); |
124 | } | 124 | } |
125 | 125 | ||
126 | rcu_read_lock(); | ||
127 | rt = (struct rt6_info *) dst; | 126 | rt = (struct rt6_info *) dst; |
128 | neigh = rt->n; | 127 | neigh = rt->n; |
129 | if (neigh) { | 128 | if (neigh) |
130 | int res = dst_neigh_output(dst, neigh, skb); | 129 | return dst_neigh_output(dst, neigh, skb); |
131 | 130 | ||
132 | rcu_read_unlock(); | ||
133 | return res; | ||
134 | } | ||
135 | rcu_read_unlock(); | ||
136 | IP6_INC_STATS_BH(dev_net(dst->dev), | 131 | IP6_INC_STATS_BH(dev_net(dst->dev), |
137 | ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); | 132 | ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); |
138 | kfree_skb(skb); | 133 | kfree_skb(skb); |
@@ -493,7 +488,8 @@ int ip6_forward(struct sk_buff *skb) | |||
493 | if (mtu < IPV6_MIN_MTU) | 488 | if (mtu < IPV6_MIN_MTU) |
494 | mtu = IPV6_MIN_MTU; | 489 | mtu = IPV6_MIN_MTU; |
495 | 490 | ||
496 | if (skb->len > mtu && !skb_is_gso(skb)) { | 491 | if ((!skb->local_df && skb->len > mtu && !skb_is_gso(skb)) || |
492 | (IP6CB(skb)->frag_max_size && IP6CB(skb)->frag_max_size > mtu)) { | ||
497 | /* Again, force OUTPUT device used as source address */ | 493 | /* Again, force OUTPUT device used as source address */ |
498 | skb->dev = dst->dev; | 494 | skb->dev = dst->dev; |
499 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); | 495 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
@@ -636,7 +632,9 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
636 | /* We must not fragment if the socket is set to force MTU discovery | 632 | /* We must not fragment if the socket is set to force MTU discovery |
637 | * or if the skb it not generated by a local socket. | 633 | * or if the skb it not generated by a local socket. |
638 | */ | 634 | */ |
639 | if (unlikely(!skb->local_df && skb->len > mtu)) { | 635 | if (unlikely(!skb->local_df && skb->len > mtu) || |
636 | (IP6CB(skb)->frag_max_size && | ||
637 | IP6CB(skb)->frag_max_size > mtu)) { | ||
640 | if (skb->sk && dst_allfrag(skb_dst(skb))) | 638 | if (skb->sk && dst_allfrag(skb_dst(skb))) |
641 | sk_nocaps_add(skb->sk, NETIF_F_GSO_MASK); | 639 | sk_nocaps_add(skb->sk, NETIF_F_GSO_MASK); |
642 | 640 | ||
@@ -980,7 +978,6 @@ static int ip6_dst_lookup_tail(struct sock *sk, | |||
980 | * dst entry and replace it instead with the | 978 | * dst entry and replace it instead with the |
981 | * dst entry of the nexthop router | 979 | * dst entry of the nexthop router |
982 | */ | 980 | */ |
983 | rcu_read_lock(); | ||
984 | rt = (struct rt6_info *) *dst; | 981 | rt = (struct rt6_info *) *dst; |
985 | n = rt->n; | 982 | n = rt->n; |
986 | if (n && !(n->nud_state & NUD_VALID)) { | 983 | if (n && !(n->nud_state & NUD_VALID)) { |
@@ -988,7 +985,6 @@ static int ip6_dst_lookup_tail(struct sock *sk, | |||
988 | struct flowi6 fl_gw6; | 985 | struct flowi6 fl_gw6; |
989 | int redirect; | 986 | int redirect; |
990 | 987 | ||
991 | rcu_read_unlock(); | ||
992 | ifp = ipv6_get_ifaddr(net, &fl6->saddr, | 988 | ifp = ipv6_get_ifaddr(net, &fl6->saddr, |
993 | (*dst)->dev, 1); | 989 | (*dst)->dev, 1); |
994 | 990 | ||
@@ -1008,8 +1004,6 @@ static int ip6_dst_lookup_tail(struct sock *sk, | |||
1008 | if ((err = (*dst)->error)) | 1004 | if ((err = (*dst)->error)) |
1009 | goto out_err_release; | 1005 | goto out_err_release; |
1010 | } | 1006 | } |
1011 | } else { | ||
1012 | rcu_read_unlock(); | ||
1013 | } | 1007 | } |
1014 | #endif | 1008 | #endif |
1015 | 1009 | ||
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 9a1d5fe6aef8..cb7e2ded6f08 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c | |||
@@ -126,7 +126,7 @@ static struct net_device_stats *ip6_get_stats(struct net_device *dev) | |||
126 | * Locking : hash tables are protected by RCU and RTNL | 126 | * Locking : hash tables are protected by RCU and RTNL |
127 | */ | 127 | */ |
128 | 128 | ||
129 | static inline struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t) | 129 | struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t) |
130 | { | 130 | { |
131 | struct dst_entry *dst = t->dst_cache; | 131 | struct dst_entry *dst = t->dst_cache; |
132 | 132 | ||
@@ -139,20 +139,23 @@ static inline struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t) | |||
139 | 139 | ||
140 | return dst; | 140 | return dst; |
141 | } | 141 | } |
142 | EXPORT_SYMBOL_GPL(ip6_tnl_dst_check); | ||
142 | 143 | ||
143 | static inline void ip6_tnl_dst_reset(struct ip6_tnl *t) | 144 | void ip6_tnl_dst_reset(struct ip6_tnl *t) |
144 | { | 145 | { |
145 | dst_release(t->dst_cache); | 146 | dst_release(t->dst_cache); |
146 | t->dst_cache = NULL; | 147 | t->dst_cache = NULL; |
147 | } | 148 | } |
149 | EXPORT_SYMBOL_GPL(ip6_tnl_dst_reset); | ||
148 | 150 | ||
149 | static inline void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst) | 151 | void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst) |
150 | { | 152 | { |
151 | struct rt6_info *rt = (struct rt6_info *) dst; | 153 | struct rt6_info *rt = (struct rt6_info *) dst; |
152 | t->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0; | 154 | t->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0; |
153 | dst_release(t->dst_cache); | 155 | dst_release(t->dst_cache); |
154 | t->dst_cache = dst; | 156 | t->dst_cache = dst; |
155 | } | 157 | } |
158 | EXPORT_SYMBOL_GPL(ip6_tnl_dst_store); | ||
156 | 159 | ||
157 | /** | 160 | /** |
158 | * ip6_tnl_lookup - fetch tunnel matching the end-point addresses | 161 | * ip6_tnl_lookup - fetch tunnel matching the end-point addresses |
@@ -200,7 +203,7 @@ ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_ | |||
200 | **/ | 203 | **/ |
201 | 204 | ||
202 | static struct ip6_tnl __rcu ** | 205 | static struct ip6_tnl __rcu ** |
203 | ip6_tnl_bucket(struct ip6_tnl_net *ip6n, const struct ip6_tnl_parm *p) | 206 | ip6_tnl_bucket(struct ip6_tnl_net *ip6n, const struct __ip6_tnl_parm *p) |
204 | { | 207 | { |
205 | const struct in6_addr *remote = &p->raddr; | 208 | const struct in6_addr *remote = &p->raddr; |
206 | const struct in6_addr *local = &p->laddr; | 209 | const struct in6_addr *local = &p->laddr; |
@@ -267,7 +270,7 @@ static void ip6_dev_free(struct net_device *dev) | |||
267 | * created tunnel or NULL | 270 | * created tunnel or NULL |
268 | **/ | 271 | **/ |
269 | 272 | ||
270 | static struct ip6_tnl *ip6_tnl_create(struct net *net, struct ip6_tnl_parm *p) | 273 | static struct ip6_tnl *ip6_tnl_create(struct net *net, struct __ip6_tnl_parm *p) |
271 | { | 274 | { |
272 | struct net_device *dev; | 275 | struct net_device *dev; |
273 | struct ip6_tnl *t; | 276 | struct ip6_tnl *t; |
@@ -322,7 +325,7 @@ failed: | |||
322 | **/ | 325 | **/ |
323 | 326 | ||
324 | static struct ip6_tnl *ip6_tnl_locate(struct net *net, | 327 | static struct ip6_tnl *ip6_tnl_locate(struct net *net, |
325 | struct ip6_tnl_parm *p, int create) | 328 | struct __ip6_tnl_parm *p, int create) |
326 | { | 329 | { |
327 | const struct in6_addr *remote = &p->raddr; | 330 | const struct in6_addr *remote = &p->raddr; |
328 | const struct in6_addr *local = &p->laddr; | 331 | const struct in6_addr *local = &p->laddr; |
@@ -374,8 +377,7 @@ ip6_tnl_dev_uninit(struct net_device *dev) | |||
374 | * else index to encapsulation limit | 377 | * else index to encapsulation limit |
375 | **/ | 378 | **/ |
376 | 379 | ||
377 | static __u16 | 380 | __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw) |
378 | parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw) | ||
379 | { | 381 | { |
380 | const struct ipv6hdr *ipv6h = (const struct ipv6hdr *) raw; | 382 | const struct ipv6hdr *ipv6h = (const struct ipv6hdr *) raw; |
381 | __u8 nexthdr = ipv6h->nexthdr; | 383 | __u8 nexthdr = ipv6h->nexthdr; |
@@ -425,6 +427,7 @@ parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw) | |||
425 | } | 427 | } |
426 | return 0; | 428 | return 0; |
427 | } | 429 | } |
430 | EXPORT_SYMBOL(ip6_tnl_parse_tlv_enc_lim); | ||
428 | 431 | ||
429 | /** | 432 | /** |
430 | * ip6_tnl_err - tunnel error handler | 433 | * ip6_tnl_err - tunnel error handler |
@@ -480,7 +483,7 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt, | |||
480 | case ICMPV6_PARAMPROB: | 483 | case ICMPV6_PARAMPROB: |
481 | teli = 0; | 484 | teli = 0; |
482 | if ((*code) == ICMPV6_HDR_FIELD) | 485 | if ((*code) == ICMPV6_HDR_FIELD) |
483 | teli = parse_tlv_tnl_enc_lim(skb, skb->data); | 486 | teli = ip6_tnl_parse_tlv_enc_lim(skb, skb->data); |
484 | 487 | ||
485 | if (teli && teli == *info - 2) { | 488 | if (teli && teli == *info - 2) { |
486 | tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli]; | 489 | tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli]; |
@@ -693,11 +696,11 @@ static void ip6ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t, | |||
693 | IP6_ECN_set_ce(ipv6_hdr(skb)); | 696 | IP6_ECN_set_ce(ipv6_hdr(skb)); |
694 | } | 697 | } |
695 | 698 | ||
696 | static __u32 ip6_tnl_get_cap(struct ip6_tnl *t, | 699 | __u32 ip6_tnl_get_cap(struct ip6_tnl *t, |
697 | const struct in6_addr *laddr, | 700 | const struct in6_addr *laddr, |
698 | const struct in6_addr *raddr) | 701 | const struct in6_addr *raddr) |
699 | { | 702 | { |
700 | struct ip6_tnl_parm *p = &t->parms; | 703 | struct __ip6_tnl_parm *p = &t->parms; |
701 | int ltype = ipv6_addr_type(laddr); | 704 | int ltype = ipv6_addr_type(laddr); |
702 | int rtype = ipv6_addr_type(raddr); | 705 | int rtype = ipv6_addr_type(raddr); |
703 | __u32 flags = 0; | 706 | __u32 flags = 0; |
@@ -715,13 +718,14 @@ static __u32 ip6_tnl_get_cap(struct ip6_tnl *t, | |||
715 | } | 718 | } |
716 | return flags; | 719 | return flags; |
717 | } | 720 | } |
721 | EXPORT_SYMBOL(ip6_tnl_get_cap); | ||
718 | 722 | ||
719 | /* called with rcu_read_lock() */ | 723 | /* called with rcu_read_lock() */ |
720 | static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t, | 724 | int ip6_tnl_rcv_ctl(struct ip6_tnl *t, |
721 | const struct in6_addr *laddr, | 725 | const struct in6_addr *laddr, |
722 | const struct in6_addr *raddr) | 726 | const struct in6_addr *raddr) |
723 | { | 727 | { |
724 | struct ip6_tnl_parm *p = &t->parms; | 728 | struct __ip6_tnl_parm *p = &t->parms; |
725 | int ret = 0; | 729 | int ret = 0; |
726 | struct net *net = dev_net(t->dev); | 730 | struct net *net = dev_net(t->dev); |
727 | 731 | ||
@@ -740,6 +744,7 @@ static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t, | |||
740 | } | 744 | } |
741 | return ret; | 745 | return ret; |
742 | } | 746 | } |
747 | EXPORT_SYMBOL_GPL(ip6_tnl_rcv_ctl); | ||
743 | 748 | ||
744 | /** | 749 | /** |
745 | * ip6_tnl_rcv - decapsulate IPv6 packet and retransmit it locally | 750 | * ip6_tnl_rcv - decapsulate IPv6 packet and retransmit it locally |
@@ -859,9 +864,9 @@ ip6_tnl_addr_conflict(const struct ip6_tnl *t, const struct ipv6hdr *hdr) | |||
859 | return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr); | 864 | return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr); |
860 | } | 865 | } |
861 | 866 | ||
862 | static inline int ip6_tnl_xmit_ctl(struct ip6_tnl *t) | 867 | int ip6_tnl_xmit_ctl(struct ip6_tnl *t) |
863 | { | 868 | { |
864 | struct ip6_tnl_parm *p = &t->parms; | 869 | struct __ip6_tnl_parm *p = &t->parms; |
865 | int ret = 0; | 870 | int ret = 0; |
866 | struct net *net = dev_net(t->dev); | 871 | struct net *net = dev_net(t->dev); |
867 | 872 | ||
@@ -885,6 +890,8 @@ static inline int ip6_tnl_xmit_ctl(struct ip6_tnl *t) | |||
885 | } | 890 | } |
886 | return ret; | 891 | return ret; |
887 | } | 892 | } |
893 | EXPORT_SYMBOL_GPL(ip6_tnl_xmit_ctl); | ||
894 | |||
888 | /** | 895 | /** |
889 | * ip6_tnl_xmit2 - encapsulate packet and send | 896 | * ip6_tnl_xmit2 - encapsulate packet and send |
890 | * @skb: the outgoing socket buffer | 897 | * @skb: the outgoing socket buffer |
@@ -1085,7 +1092,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1085 | !ip6_tnl_xmit_ctl(t) || ip6_tnl_addr_conflict(t, ipv6h)) | 1092 | !ip6_tnl_xmit_ctl(t) || ip6_tnl_addr_conflict(t, ipv6h)) |
1086 | return -1; | 1093 | return -1; |
1087 | 1094 | ||
1088 | offset = parse_tlv_tnl_enc_lim(skb, skb_network_header(skb)); | 1095 | offset = ip6_tnl_parse_tlv_enc_lim(skb, skb_network_header(skb)); |
1089 | if (offset > 0) { | 1096 | if (offset > 0) { |
1090 | struct ipv6_tlv_tnl_enc_lim *tel; | 1097 | struct ipv6_tlv_tnl_enc_lim *tel; |
1091 | tel = (struct ipv6_tlv_tnl_enc_lim *)&skb_network_header(skb)[offset]; | 1098 | tel = (struct ipv6_tlv_tnl_enc_lim *)&skb_network_header(skb)[offset]; |
@@ -1152,7 +1159,7 @@ tx_err: | |||
1152 | static void ip6_tnl_link_config(struct ip6_tnl *t) | 1159 | static void ip6_tnl_link_config(struct ip6_tnl *t) |
1153 | { | 1160 | { |
1154 | struct net_device *dev = t->dev; | 1161 | struct net_device *dev = t->dev; |
1155 | struct ip6_tnl_parm *p = &t->parms; | 1162 | struct __ip6_tnl_parm *p = &t->parms; |
1156 | struct flowi6 *fl6 = &t->fl.u.ip6; | 1163 | struct flowi6 *fl6 = &t->fl.u.ip6; |
1157 | 1164 | ||
1158 | memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr)); | 1165 | memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr)); |
@@ -1215,7 +1222,7 @@ static void ip6_tnl_link_config(struct ip6_tnl *t) | |||
1215 | **/ | 1222 | **/ |
1216 | 1223 | ||
1217 | static int | 1224 | static int |
1218 | ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p) | 1225 | ip6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p) |
1219 | { | 1226 | { |
1220 | t->parms.laddr = p->laddr; | 1227 | t->parms.laddr = p->laddr; |
1221 | t->parms.raddr = p->raddr; | 1228 | t->parms.raddr = p->raddr; |
@@ -1230,6 +1237,34 @@ ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p) | |||
1230 | return 0; | 1237 | return 0; |
1231 | } | 1238 | } |
1232 | 1239 | ||
1240 | static void | ||
1241 | ip6_tnl_parm_from_user(struct __ip6_tnl_parm *p, const struct ip6_tnl_parm *u) | ||
1242 | { | ||
1243 | p->laddr = u->laddr; | ||
1244 | p->raddr = u->raddr; | ||
1245 | p->flags = u->flags; | ||
1246 | p->hop_limit = u->hop_limit; | ||
1247 | p->encap_limit = u->encap_limit; | ||
1248 | p->flowinfo = u->flowinfo; | ||
1249 | p->link = u->link; | ||
1250 | p->proto = u->proto; | ||
1251 | memcpy(p->name, u->name, sizeof(u->name)); | ||
1252 | } | ||
1253 | |||
1254 | static void | ||
1255 | ip6_tnl_parm_to_user(struct ip6_tnl_parm *u, const struct __ip6_tnl_parm *p) | ||
1256 | { | ||
1257 | u->laddr = p->laddr; | ||
1258 | u->raddr = p->raddr; | ||
1259 | u->flags = p->flags; | ||
1260 | u->hop_limit = p->hop_limit; | ||
1261 | u->encap_limit = p->encap_limit; | ||
1262 | u->flowinfo = p->flowinfo; | ||
1263 | u->link = p->link; | ||
1264 | u->proto = p->proto; | ||
1265 | memcpy(u->name, p->name, sizeof(u->name)); | ||
1266 | } | ||
1267 | |||
1233 | /** | 1268 | /** |
1234 | * ip6_tnl_ioctl - configure ipv6 tunnels from userspace | 1269 | * ip6_tnl_ioctl - configure ipv6 tunnels from userspace |
1235 | * @dev: virtual device associated with tunnel | 1270 | * @dev: virtual device associated with tunnel |
@@ -1263,6 +1298,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |||
1263 | { | 1298 | { |
1264 | int err = 0; | 1299 | int err = 0; |
1265 | struct ip6_tnl_parm p; | 1300 | struct ip6_tnl_parm p; |
1301 | struct __ip6_tnl_parm p1; | ||
1266 | struct ip6_tnl *t = NULL; | 1302 | struct ip6_tnl *t = NULL; |
1267 | struct net *net = dev_net(dev); | 1303 | struct net *net = dev_net(dev); |
1268 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | 1304 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); |
@@ -1274,11 +1310,14 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |||
1274 | err = -EFAULT; | 1310 | err = -EFAULT; |
1275 | break; | 1311 | break; |
1276 | } | 1312 | } |
1277 | t = ip6_tnl_locate(net, &p, 0); | 1313 | ip6_tnl_parm_from_user(&p1, &p); |
1314 | t = ip6_tnl_locate(net, &p1, 0); | ||
1315 | } else { | ||
1316 | memset(&p, 0, sizeof(p)); | ||
1278 | } | 1317 | } |
1279 | if (t == NULL) | 1318 | if (t == NULL) |
1280 | t = netdev_priv(dev); | 1319 | t = netdev_priv(dev); |
1281 | memcpy(&p, &t->parms, sizeof (p)); | 1320 | ip6_tnl_parm_to_user(&p, &t->parms); |
1282 | if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof (p))) { | 1321 | if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof (p))) { |
1283 | err = -EFAULT; | 1322 | err = -EFAULT; |
1284 | } | 1323 | } |
@@ -1295,7 +1334,8 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |||
1295 | if (p.proto != IPPROTO_IPV6 && p.proto != IPPROTO_IPIP && | 1334 | if (p.proto != IPPROTO_IPV6 && p.proto != IPPROTO_IPIP && |
1296 | p.proto != 0) | 1335 | p.proto != 0) |
1297 | break; | 1336 | break; |
1298 | t = ip6_tnl_locate(net, &p, cmd == SIOCADDTUNNEL); | 1337 | ip6_tnl_parm_from_user(&p1, &p); |
1338 | t = ip6_tnl_locate(net, &p1, cmd == SIOCADDTUNNEL); | ||
1299 | if (dev != ip6n->fb_tnl_dev && cmd == SIOCCHGTUNNEL) { | 1339 | if (dev != ip6n->fb_tnl_dev && cmd == SIOCCHGTUNNEL) { |
1300 | if (t != NULL) { | 1340 | if (t != NULL) { |
1301 | if (t->dev != dev) { | 1341 | if (t->dev != dev) { |
@@ -1307,13 +1347,14 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |||
1307 | 1347 | ||
1308 | ip6_tnl_unlink(ip6n, t); | 1348 | ip6_tnl_unlink(ip6n, t); |
1309 | synchronize_net(); | 1349 | synchronize_net(); |
1310 | err = ip6_tnl_change(t, &p); | 1350 | err = ip6_tnl_change(t, &p1); |
1311 | ip6_tnl_link(ip6n, t); | 1351 | ip6_tnl_link(ip6n, t); |
1312 | netdev_state_change(dev); | 1352 | netdev_state_change(dev); |
1313 | } | 1353 | } |
1314 | if (t) { | 1354 | if (t) { |
1315 | err = 0; | 1355 | err = 0; |
1316 | if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof (p))) | 1356 | ip6_tnl_parm_to_user(&p, &t->parms); |
1357 | if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) | ||
1317 | err = -EFAULT; | 1358 | err = -EFAULT; |
1318 | 1359 | ||
1319 | } else | 1360 | } else |
@@ -1329,7 +1370,9 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |||
1329 | if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) | 1370 | if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) |
1330 | break; | 1371 | break; |
1331 | err = -ENOENT; | 1372 | err = -ENOENT; |
1332 | if ((t = ip6_tnl_locate(net, &p, 0)) == NULL) | 1373 | ip6_tnl_parm_from_user(&p1, &p); |
1374 | t = ip6_tnl_locate(net, &p1, 0); | ||
1375 | if (t == NULL) | ||
1333 | break; | 1376 | break; |
1334 | err = -EPERM; | 1377 | err = -EPERM; |
1335 | if (t->dev == ip6n->fb_tnl_dev) | 1378 | if (t->dev == ip6n->fb_tnl_dev) |
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 4532973f0dd4..08ea3f0b6e55 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c | |||
@@ -838,7 +838,7 @@ static void ip6mr_destroy_unres(struct mr6_table *mrt, struct mfc6_cache *c) | |||
838 | nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr)); | 838 | nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr)); |
839 | skb_trim(skb, nlh->nlmsg_len); | 839 | skb_trim(skb, nlh->nlmsg_len); |
840 | ((struct nlmsgerr *)NLMSG_DATA(nlh))->error = -ETIMEDOUT; | 840 | ((struct nlmsgerr *)NLMSG_DATA(nlh))->error = -ETIMEDOUT; |
841 | rtnl_unicast(skb, net, NETLINK_CB(skb).pid); | 841 | rtnl_unicast(skb, net, NETLINK_CB(skb).portid); |
842 | } else | 842 | } else |
843 | kfree_skb(skb); | 843 | kfree_skb(skb); |
844 | } | 844 | } |
@@ -1052,7 +1052,7 @@ static void ip6mr_cache_resolve(struct net *net, struct mr6_table *mrt, | |||
1052 | skb_trim(skb, nlh->nlmsg_len); | 1052 | skb_trim(skb, nlh->nlmsg_len); |
1053 | ((struct nlmsgerr *)NLMSG_DATA(nlh))->error = -EMSGSIZE; | 1053 | ((struct nlmsgerr *)NLMSG_DATA(nlh))->error = -EMSGSIZE; |
1054 | } | 1054 | } |
1055 | rtnl_unicast(skb, net, NETLINK_CB(skb).pid); | 1055 | rtnl_unicast(skb, net, NETLINK_CB(skb).portid); |
1056 | } else | 1056 | } else |
1057 | ip6_mr_forward(net, mrt, skb, c); | 1057 | ip6_mr_forward(net, mrt, skb, c); |
1058 | } | 1058 | } |
@@ -2202,12 +2202,12 @@ int ip6mr_get_route(struct net *net, | |||
2202 | } | 2202 | } |
2203 | 2203 | ||
2204 | static int ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb, | 2204 | static int ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb, |
2205 | u32 pid, u32 seq, struct mfc6_cache *c) | 2205 | u32 portid, u32 seq, struct mfc6_cache *c) |
2206 | { | 2206 | { |
2207 | struct nlmsghdr *nlh; | 2207 | struct nlmsghdr *nlh; |
2208 | struct rtmsg *rtm; | 2208 | struct rtmsg *rtm; |
2209 | 2209 | ||
2210 | nlh = nlmsg_put(skb, pid, seq, RTM_NEWROUTE, sizeof(*rtm), NLM_F_MULTI); | 2210 | nlh = nlmsg_put(skb, portid, seq, RTM_NEWROUTE, sizeof(*rtm), NLM_F_MULTI); |
2211 | if (nlh == NULL) | 2211 | if (nlh == NULL) |
2212 | return -EMSGSIZE; | 2212 | return -EMSGSIZE; |
2213 | 2213 | ||
@@ -2260,7 +2260,7 @@ static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb) | |||
2260 | if (e < s_e) | 2260 | if (e < s_e) |
2261 | goto next_entry; | 2261 | goto next_entry; |
2262 | if (ip6mr_fill_mroute(mrt, skb, | 2262 | if (ip6mr_fill_mroute(mrt, skb, |
2263 | NETLINK_CB(cb->skb).pid, | 2263 | NETLINK_CB(cb->skb).portid, |
2264 | cb->nlh->nlmsg_seq, | 2264 | cb->nlh->nlmsg_seq, |
2265 | mfc) < 0) | 2265 | mfc) < 0) |
2266 | goto done; | 2266 | goto done; |
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index db31561cc8df..429089cb073d 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c | |||
@@ -15,6 +15,7 @@ int ip6_route_me_harder(struct sk_buff *skb) | |||
15 | { | 15 | { |
16 | struct net *net = dev_net(skb_dst(skb)->dev); | 16 | struct net *net = dev_net(skb_dst(skb)->dev); |
17 | const struct ipv6hdr *iph = ipv6_hdr(skb); | 17 | const struct ipv6hdr *iph = ipv6_hdr(skb); |
18 | unsigned int hh_len; | ||
18 | struct dst_entry *dst; | 19 | struct dst_entry *dst; |
19 | struct flowi6 fl6 = { | 20 | struct flowi6 fl6 = { |
20 | .flowi6_oif = skb->sk ? skb->sk->sk_bound_dev_if : 0, | 21 | .flowi6_oif = skb->sk ? skb->sk->sk_bound_dev_if : 0, |
@@ -47,6 +48,13 @@ int ip6_route_me_harder(struct sk_buff *skb) | |||
47 | } | 48 | } |
48 | #endif | 49 | #endif |
49 | 50 | ||
51 | /* Change in oif may mean change in hh_len. */ | ||
52 | hh_len = skb_dst(skb)->dev->hard_header_len; | ||
53 | if (skb_headroom(skb) < hh_len && | ||
54 | pskb_expand_head(skb, HH_DATA_ALIGN(hh_len - skb_headroom(skb)), | ||
55 | 0, GFP_ATOMIC)) | ||
56 | return -1; | ||
57 | |||
50 | return 0; | 58 | return 0; |
51 | } | 59 | } |
52 | EXPORT_SYMBOL(ip6_route_me_harder); | 60 | EXPORT_SYMBOL(ip6_route_me_harder); |
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index 10135342799e..3b73254d7bf1 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig | |||
@@ -25,6 +25,18 @@ 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_NAT_IPV6 | ||
29 | tristate "IPv6 NAT" | ||
30 | depends on NF_CONNTRACK_IPV6 | ||
31 | depends on NETFILTER_ADVANCED | ||
32 | select NF_NAT | ||
33 | help | ||
34 | The IPv6 NAT option allows masquerading, port forwarding and other | ||
35 | forms of full Network Address Port Translation. It is controlled by | ||
36 | the `nat' table in ip6tables, see the man page for ip6tables(8). | ||
37 | |||
38 | To compile it as a module, choose M here. If unsure, say N. | ||
39 | |||
28 | config IP6_NF_IPTABLES | 40 | config IP6_NF_IPTABLES |
29 | tristate "IP6 tables support (required for filtering)" | 41 | tristate "IP6 tables support (required for filtering)" |
30 | depends on INET && IPV6 | 42 | depends on INET && IPV6 |
@@ -132,6 +144,48 @@ config IP6_NF_TARGET_HL | |||
132 | (e.g. when running oldconfig). It selects | 144 | (e.g. when running oldconfig). It selects |
133 | CONFIG_NETFILTER_XT_TARGET_HL. | 145 | CONFIG_NETFILTER_XT_TARGET_HL. |
134 | 146 | ||
147 | config IP6_NF_TARGET_MASQUERADE | ||
148 | tristate "MASQUERADE target support" | ||
149 | depends on NF_NAT_IPV6 | ||
150 | help | ||
151 | Masquerading is a special case of NAT: all outgoing connections are | ||
152 | changed to seem to come from a particular interface's address, and | ||
153 | if the interface goes down, those connections are lost. This is | ||
154 | only useful for dialup accounts with dynamic IP address (ie. your IP | ||
155 | address will be different on next dialup). | ||
156 | |||
157 | To compile it as a module, choose M here. If unsure, say N. | ||
158 | |||
159 | config IP6_NF_TARGET_NETMAP | ||
160 | tristate "NETMAP target support" | ||
161 | depends on NF_NAT_IPV6 | ||
162 | help | ||
163 | NETMAP is an implementation of static 1:1 NAT mapping of network | ||
164 | addresses. It maps the network address part, while keeping the host | ||
165 | address part intact. | ||
166 | |||
167 | To compile it as a module, choose M here. If unsure, say N. | ||
168 | |||
169 | config IP6_NF_TARGET_REDIRECT | ||
170 | tristate "REDIRECT target support" | ||
171 | depends on NF_NAT_IPV6 | ||
172 | help | ||
173 | REDIRECT is a special case of NAT: all incoming connections are | ||
174 | mapped onto the incoming interface's address, causing the packets to | ||
175 | come to the local machine instead of passing through. This is | ||
176 | useful for transparent proxies. | ||
177 | |||
178 | To compile it as a module, choose M here. If unsure, say N. | ||
179 | |||
180 | config IP6_NF_TARGET_NPT | ||
181 | tristate "NPT (Network Prefix translation) target support" | ||
182 | depends on NETFILTER_ADVANCED | ||
183 | help | ||
184 | This option adds the `SNPT' and `DNPT' target, which perform | ||
185 | stateless IPv6-to-IPv6 Network Prefix Translation per RFC 6296. | ||
186 | |||
187 | To compile it as a module, choose M here. If unsure, say N. | ||
188 | |||
135 | config IP6_NF_FILTER | 189 | config IP6_NF_FILTER |
136 | tristate "Packet filtering" | 190 | tristate "Packet filtering" |
137 | default m if NETFILTER_ADVANCED=n | 191 | default m if NETFILTER_ADVANCED=n |
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile index 534d3f216f7b..5752132ca159 100644 --- a/net/ipv6/netfilter/Makefile +++ b/net/ipv6/netfilter/Makefile | |||
@@ -8,6 +8,7 @@ obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o | |||
8 | obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o | 8 | obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o |
9 | obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o | 9 | obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o |
10 | obj-$(CONFIG_IP6_NF_SECURITY) += ip6table_security.o | 10 | obj-$(CONFIG_IP6_NF_SECURITY) += ip6table_security.o |
11 | obj-$(CONFIG_NF_NAT_IPV6) += ip6table_nat.o | ||
11 | 12 | ||
12 | # objects for l3 independent conntrack | 13 | # objects for l3 independent conntrack |
13 | nf_conntrack_ipv6-y := nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o | 14 | nf_conntrack_ipv6-y := nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o |
@@ -15,6 +16,9 @@ nf_conntrack_ipv6-y := nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o | |||
15 | # l3 independent conntrack | 16 | # l3 independent conntrack |
16 | obj-$(CONFIG_NF_CONNTRACK_IPV6) += nf_conntrack_ipv6.o nf_defrag_ipv6.o | 17 | obj-$(CONFIG_NF_CONNTRACK_IPV6) += nf_conntrack_ipv6.o nf_defrag_ipv6.o |
17 | 18 | ||
19 | nf_nat_ipv6-y := nf_nat_l3proto_ipv6.o nf_nat_proto_icmpv6.o | ||
20 | obj-$(CONFIG_NF_NAT_IPV6) += nf_nat_ipv6.o | ||
21 | |||
18 | # defrag | 22 | # defrag |
19 | 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 |
20 | obj-$(CONFIG_NF_DEFRAG_IPV6) += nf_defrag_ipv6.o | 24 | obj-$(CONFIG_NF_DEFRAG_IPV6) += nf_defrag_ipv6.o |
@@ -30,4 +34,8 @@ obj-$(CONFIG_IP6_NF_MATCH_RPFILTER) += ip6t_rpfilter.o | |||
30 | obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o | 34 | obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o |
31 | 35 | ||
32 | # targets | 36 | # targets |
37 | obj-$(CONFIG_IP6_NF_TARGET_MASQUERADE) += ip6t_MASQUERADE.o | ||
38 | obj-$(CONFIG_IP6_NF_TARGET_NETMAP) += ip6t_NETMAP.o | ||
39 | obj-$(CONFIG_IP6_NF_TARGET_NPT) += ip6t_NPT.o | ||
40 | obj-$(CONFIG_IP6_NF_TARGET_REDIRECT) += ip6t_REDIRECT.o | ||
33 | obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o | 41 | obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o |
diff --git a/net/ipv6/netfilter/ip6t_MASQUERADE.c b/net/ipv6/netfilter/ip6t_MASQUERADE.c new file mode 100644 index 000000000000..60e9053bab05 --- /dev/null +++ b/net/ipv6/netfilter/ip6t_MASQUERADE.c | |||
@@ -0,0 +1,135 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2011 Patrick McHardy <kaber@trash.net> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * Based on Rusty Russell's IPv6 MASQUERADE target. Development of IPv6 | ||
9 | * NAT funded by Astaro. | ||
10 | */ | ||
11 | |||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/netdevice.h> | ||
15 | #include <linux/ipv6.h> | ||
16 | #include <linux/netfilter.h> | ||
17 | #include <linux/netfilter_ipv6.h> | ||
18 | #include <linux/netfilter/x_tables.h> | ||
19 | #include <net/netfilter/nf_nat.h> | ||
20 | #include <net/addrconf.h> | ||
21 | #include <net/ipv6.h> | ||
22 | |||
23 | static unsigned int | ||
24 | masquerade_tg6(struct sk_buff *skb, const struct xt_action_param *par) | ||
25 | { | ||
26 | const struct nf_nat_range *range = par->targinfo; | ||
27 | enum ip_conntrack_info ctinfo; | ||
28 | struct in6_addr src; | ||
29 | struct nf_conn *ct; | ||
30 | struct nf_nat_range newrange; | ||
31 | |||
32 | ct = nf_ct_get(skb, &ctinfo); | ||
33 | NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED || | ||
34 | ctinfo == IP_CT_RELATED_REPLY)); | ||
35 | |||
36 | if (ipv6_dev_get_saddr(dev_net(par->out), par->out, | ||
37 | &ipv6_hdr(skb)->daddr, 0, &src) < 0) | ||
38 | return NF_DROP; | ||
39 | |||
40 | nfct_nat(ct)->masq_index = par->out->ifindex; | ||
41 | |||
42 | newrange.flags = range->flags | NF_NAT_RANGE_MAP_IPS; | ||
43 | newrange.min_addr.in6 = src; | ||
44 | newrange.max_addr.in6 = src; | ||
45 | newrange.min_proto = range->min_proto; | ||
46 | newrange.max_proto = range->max_proto; | ||
47 | |||
48 | return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC); | ||
49 | } | ||
50 | |||
51 | static int masquerade_tg6_checkentry(const struct xt_tgchk_param *par) | ||
52 | { | ||
53 | const struct nf_nat_range *range = par->targinfo; | ||
54 | |||
55 | if (range->flags & NF_NAT_RANGE_MAP_IPS) | ||
56 | return -EINVAL; | ||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | static int device_cmp(struct nf_conn *ct, void *ifindex) | ||
61 | { | ||
62 | const struct nf_conn_nat *nat = nfct_nat(ct); | ||
63 | |||
64 | if (!nat) | ||
65 | return 0; | ||
66 | if (nf_ct_l3num(ct) != NFPROTO_IPV6) | ||
67 | return 0; | ||
68 | return nat->masq_index == (int)(long)ifindex; | ||
69 | } | ||
70 | |||
71 | static int masq_device_event(struct notifier_block *this, | ||
72 | unsigned long event, void *ptr) | ||
73 | { | ||
74 | const struct net_device *dev = ptr; | ||
75 | struct net *net = dev_net(dev); | ||
76 | |||
77 | if (event == NETDEV_DOWN) | ||
78 | nf_ct_iterate_cleanup(net, device_cmp, | ||
79 | (void *)(long)dev->ifindex); | ||
80 | |||
81 | return NOTIFY_DONE; | ||
82 | } | ||
83 | |||
84 | static struct notifier_block masq_dev_notifier = { | ||
85 | .notifier_call = masq_device_event, | ||
86 | }; | ||
87 | |||
88 | static int masq_inet_event(struct notifier_block *this, | ||
89 | unsigned long event, void *ptr) | ||
90 | { | ||
91 | struct inet6_ifaddr *ifa = ptr; | ||
92 | |||
93 | return masq_device_event(this, event, ifa->idev->dev); | ||
94 | } | ||
95 | |||
96 | static struct notifier_block masq_inet_notifier = { | ||
97 | .notifier_call = masq_inet_event, | ||
98 | }; | ||
99 | |||
100 | static struct xt_target masquerade_tg6_reg __read_mostly = { | ||
101 | .name = "MASQUERADE", | ||
102 | .family = NFPROTO_IPV6, | ||
103 | .checkentry = masquerade_tg6_checkentry, | ||
104 | .target = masquerade_tg6, | ||
105 | .targetsize = sizeof(struct nf_nat_range), | ||
106 | .table = "nat", | ||
107 | .hooks = 1 << NF_INET_POST_ROUTING, | ||
108 | .me = THIS_MODULE, | ||
109 | }; | ||
110 | |||
111 | static int __init masquerade_tg6_init(void) | ||
112 | { | ||
113 | int err; | ||
114 | |||
115 | err = xt_register_target(&masquerade_tg6_reg); | ||
116 | if (err == 0) { | ||
117 | register_netdevice_notifier(&masq_dev_notifier); | ||
118 | register_inet6addr_notifier(&masq_inet_notifier); | ||
119 | } | ||
120 | |||
121 | return err; | ||
122 | } | ||
123 | static void __exit masquerade_tg6_exit(void) | ||
124 | { | ||
125 | unregister_inet6addr_notifier(&masq_inet_notifier); | ||
126 | unregister_netdevice_notifier(&masq_dev_notifier); | ||
127 | xt_unregister_target(&masquerade_tg6_reg); | ||
128 | } | ||
129 | |||
130 | module_init(masquerade_tg6_init); | ||
131 | module_exit(masquerade_tg6_exit); | ||
132 | |||
133 | MODULE_LICENSE("GPL"); | ||
134 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); | ||
135 | MODULE_DESCRIPTION("Xtables: automatic address SNAT"); | ||
diff --git a/net/ipv6/netfilter/ip6t_NETMAP.c b/net/ipv6/netfilter/ip6t_NETMAP.c new file mode 100644 index 000000000000..4f3bf360e50f --- /dev/null +++ b/net/ipv6/netfilter/ip6t_NETMAP.c | |||
@@ -0,0 +1,94 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2011 Patrick McHardy <kaber@trash.net> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * Based on Svenning Soerensen's IPv4 NETMAP target. Development of IPv6 | ||
9 | * NAT funded by Astaro. | ||
10 | */ | ||
11 | |||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/ipv6.h> | ||
15 | #include <linux/netfilter.h> | ||
16 | #include <linux/netfilter_ipv6.h> | ||
17 | #include <linux/netfilter/x_tables.h> | ||
18 | #include <net/netfilter/nf_nat.h> | ||
19 | |||
20 | static unsigned int | ||
21 | netmap_tg6(struct sk_buff *skb, const struct xt_action_param *par) | ||
22 | { | ||
23 | const struct nf_nat_range *range = par->targinfo; | ||
24 | struct nf_nat_range newrange; | ||
25 | struct nf_conn *ct; | ||
26 | enum ip_conntrack_info ctinfo; | ||
27 | union nf_inet_addr new_addr, netmask; | ||
28 | unsigned int i; | ||
29 | |||
30 | ct = nf_ct_get(skb, &ctinfo); | ||
31 | for (i = 0; i < ARRAY_SIZE(range->min_addr.ip6); i++) | ||
32 | netmask.ip6[i] = ~(range->min_addr.ip6[i] ^ | ||
33 | range->max_addr.ip6[i]); | ||
34 | |||
35 | if (par->hooknum == NF_INET_PRE_ROUTING || | ||
36 | par->hooknum == NF_INET_LOCAL_OUT) | ||
37 | new_addr.in6 = ipv6_hdr(skb)->daddr; | ||
38 | else | ||
39 | new_addr.in6 = ipv6_hdr(skb)->saddr; | ||
40 | |||
41 | for (i = 0; i < ARRAY_SIZE(new_addr.ip6); i++) { | ||
42 | new_addr.ip6[i] &= ~netmask.ip6[i]; | ||
43 | new_addr.ip6[i] |= range->min_addr.ip6[i] & | ||
44 | netmask.ip6[i]; | ||
45 | } | ||
46 | |||
47 | newrange.flags = range->flags | NF_NAT_RANGE_MAP_IPS; | ||
48 | newrange.min_addr = new_addr; | ||
49 | newrange.max_addr = new_addr; | ||
50 | newrange.min_proto = range->min_proto; | ||
51 | newrange.max_proto = range->max_proto; | ||
52 | |||
53 | return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(par->hooknum)); | ||
54 | } | ||
55 | |||
56 | static int netmap_tg6_checkentry(const struct xt_tgchk_param *par) | ||
57 | { | ||
58 | const struct nf_nat_range *range = par->targinfo; | ||
59 | |||
60 | if (!(range->flags & NF_NAT_RANGE_MAP_IPS)) | ||
61 | return -EINVAL; | ||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static struct xt_target netmap_tg6_reg __read_mostly = { | ||
66 | .name = "NETMAP", | ||
67 | .family = NFPROTO_IPV6, | ||
68 | .target = netmap_tg6, | ||
69 | .targetsize = sizeof(struct nf_nat_range), | ||
70 | .table = "nat", | ||
71 | .hooks = (1 << NF_INET_PRE_ROUTING) | | ||
72 | (1 << NF_INET_POST_ROUTING) | | ||
73 | (1 << NF_INET_LOCAL_OUT) | | ||
74 | (1 << NF_INET_LOCAL_IN), | ||
75 | .checkentry = netmap_tg6_checkentry, | ||
76 | .me = THIS_MODULE, | ||
77 | }; | ||
78 | |||
79 | static int __init netmap_tg6_init(void) | ||
80 | { | ||
81 | return xt_register_target(&netmap_tg6_reg); | ||
82 | } | ||
83 | |||
84 | static void netmap_tg6_exit(void) | ||
85 | { | ||
86 | xt_unregister_target(&netmap_tg6_reg); | ||
87 | } | ||
88 | |||
89 | module_init(netmap_tg6_init); | ||
90 | module_exit(netmap_tg6_exit); | ||
91 | |||
92 | MODULE_LICENSE("GPL"); | ||
93 | MODULE_DESCRIPTION("Xtables: 1:1 NAT mapping of IPv6 subnets"); | ||
94 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); | ||
diff --git a/net/ipv6/netfilter/ip6t_NPT.c b/net/ipv6/netfilter/ip6t_NPT.c new file mode 100644 index 000000000000..e9486915eff6 --- /dev/null +++ b/net/ipv6/netfilter/ip6t_NPT.c | |||
@@ -0,0 +1,165 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2011, 2012 Patrick McHardy <kaber@trash.net> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/module.h> | ||
10 | #include <linux/skbuff.h> | ||
11 | #include <linux/ipv6.h> | ||
12 | #include <linux/netfilter.h> | ||
13 | #include <linux/netfilter_ipv6.h> | ||
14 | #include <linux/netfilter_ipv6/ip6t_NPT.h> | ||
15 | #include <linux/netfilter/x_tables.h> | ||
16 | |||
17 | static __sum16 csum16_complement(__sum16 a) | ||
18 | { | ||
19 | return (__force __sum16)(0xffff - (__force u16)a); | ||
20 | } | ||
21 | |||
22 | static __sum16 csum16_add(__sum16 a, __sum16 b) | ||
23 | { | ||
24 | u16 sum; | ||
25 | |||
26 | sum = (__force u16)a + (__force u16)b; | ||
27 | sum += (__force u16)a < (__force u16)b; | ||
28 | return (__force __sum16)sum; | ||
29 | } | ||
30 | |||
31 | static __sum16 csum16_sub(__sum16 a, __sum16 b) | ||
32 | { | ||
33 | return csum16_add(a, csum16_complement(b)); | ||
34 | } | ||
35 | |||
36 | static int ip6t_npt_checkentry(const struct xt_tgchk_param *par) | ||
37 | { | ||
38 | struct ip6t_npt_tginfo *npt = par->targinfo; | ||
39 | __sum16 src_sum = 0, dst_sum = 0; | ||
40 | unsigned int i; | ||
41 | |||
42 | if (npt->src_pfx_len > 64 || npt->dst_pfx_len > 64) | ||
43 | return -EINVAL; | ||
44 | |||
45 | for (i = 0; i < ARRAY_SIZE(npt->src_pfx.in6.s6_addr16); i++) { | ||
46 | src_sum = csum16_add(src_sum, | ||
47 | (__force __sum16)npt->src_pfx.in6.s6_addr16[i]); | ||
48 | dst_sum = csum16_add(dst_sum, | ||
49 | (__force __sum16)npt->dst_pfx.in6.s6_addr16[i]); | ||
50 | } | ||
51 | |||
52 | npt->adjustment = csum16_sub(src_sum, dst_sum); | ||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | static bool ip6t_npt_map_pfx(const struct ip6t_npt_tginfo *npt, | ||
57 | struct in6_addr *addr) | ||
58 | { | ||
59 | unsigned int pfx_len; | ||
60 | unsigned int i, idx; | ||
61 | __be32 mask; | ||
62 | __sum16 sum; | ||
63 | |||
64 | pfx_len = max(npt->src_pfx_len, npt->dst_pfx_len); | ||
65 | for (i = 0; i < pfx_len; i += 32) { | ||
66 | if (pfx_len - i >= 32) | ||
67 | mask = 0; | ||
68 | else | ||
69 | mask = htonl(~((1 << (pfx_len - i)) - 1)); | ||
70 | |||
71 | idx = i / 32; | ||
72 | addr->s6_addr32[idx] &= mask; | ||
73 | addr->s6_addr32[idx] |= npt->dst_pfx.in6.s6_addr32[idx]; | ||
74 | } | ||
75 | |||
76 | if (pfx_len <= 48) | ||
77 | idx = 3; | ||
78 | else { | ||
79 | for (idx = 4; idx < ARRAY_SIZE(addr->s6_addr16); idx++) { | ||
80 | if ((__force __sum16)addr->s6_addr16[idx] != | ||
81 | CSUM_MANGLED_0) | ||
82 | break; | ||
83 | } | ||
84 | if (idx == ARRAY_SIZE(addr->s6_addr16)) | ||
85 | return false; | ||
86 | } | ||
87 | |||
88 | sum = csum16_add((__force __sum16)addr->s6_addr16[idx], | ||
89 | npt->adjustment); | ||
90 | if (sum == CSUM_MANGLED_0) | ||
91 | sum = 0; | ||
92 | *(__force __sum16 *)&addr->s6_addr16[idx] = sum; | ||
93 | |||
94 | return true; | ||
95 | } | ||
96 | |||
97 | static unsigned int | ||
98 | ip6t_snpt_tg(struct sk_buff *skb, const struct xt_action_param *par) | ||
99 | { | ||
100 | const struct ip6t_npt_tginfo *npt = par->targinfo; | ||
101 | |||
102 | if (!ip6t_npt_map_pfx(npt, &ipv6_hdr(skb)->saddr)) { | ||
103 | icmpv6_send(skb, ICMPV6_PARAMPROB, ICMPV6_HDR_FIELD, | ||
104 | offsetof(struct ipv6hdr, saddr)); | ||
105 | return NF_DROP; | ||
106 | } | ||
107 | return XT_CONTINUE; | ||
108 | } | ||
109 | |||
110 | static unsigned int | ||
111 | ip6t_dnpt_tg(struct sk_buff *skb, const struct xt_action_param *par) | ||
112 | { | ||
113 | const struct ip6t_npt_tginfo *npt = par->targinfo; | ||
114 | |||
115 | if (!ip6t_npt_map_pfx(npt, &ipv6_hdr(skb)->daddr)) { | ||
116 | icmpv6_send(skb, ICMPV6_PARAMPROB, ICMPV6_HDR_FIELD, | ||
117 | offsetof(struct ipv6hdr, daddr)); | ||
118 | return NF_DROP; | ||
119 | } | ||
120 | return XT_CONTINUE; | ||
121 | } | ||
122 | |||
123 | static struct xt_target ip6t_npt_target_reg[] __read_mostly = { | ||
124 | { | ||
125 | .name = "SNPT", | ||
126 | .target = ip6t_snpt_tg, | ||
127 | .targetsize = sizeof(struct ip6t_npt_tginfo), | ||
128 | .checkentry = ip6t_npt_checkentry, | ||
129 | .family = NFPROTO_IPV6, | ||
130 | .hooks = (1 << NF_INET_LOCAL_IN) | | ||
131 | (1 << NF_INET_POST_ROUTING), | ||
132 | .me = THIS_MODULE, | ||
133 | }, | ||
134 | { | ||
135 | .name = "DNPT", | ||
136 | .target = ip6t_dnpt_tg, | ||
137 | .targetsize = sizeof(struct ip6t_npt_tginfo), | ||
138 | .checkentry = ip6t_npt_checkentry, | ||
139 | .family = NFPROTO_IPV6, | ||
140 | .hooks = (1 << NF_INET_PRE_ROUTING) | | ||
141 | (1 << NF_INET_LOCAL_OUT), | ||
142 | .me = THIS_MODULE, | ||
143 | }, | ||
144 | }; | ||
145 | |||
146 | static int __init ip6t_npt_init(void) | ||
147 | { | ||
148 | return xt_register_targets(ip6t_npt_target_reg, | ||
149 | ARRAY_SIZE(ip6t_npt_target_reg)); | ||
150 | } | ||
151 | |||
152 | static void __exit ip6t_npt_exit(void) | ||
153 | { | ||
154 | xt_unregister_targets(ip6t_npt_target_reg, | ||
155 | ARRAY_SIZE(ip6t_npt_target_reg)); | ||
156 | } | ||
157 | |||
158 | module_init(ip6t_npt_init); | ||
159 | module_exit(ip6t_npt_exit); | ||
160 | |||
161 | MODULE_LICENSE("GPL"); | ||
162 | MODULE_DESCRIPTION("IPv6-to-IPv6 Network Prefix Translation (RFC 6296)"); | ||
163 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); | ||
164 | MODULE_ALIAS("ip6t_SNPT"); | ||
165 | MODULE_ALIAS("ip6t_DNPT"); | ||
diff --git a/net/ipv6/netfilter/ip6t_REDIRECT.c b/net/ipv6/netfilter/ip6t_REDIRECT.c new file mode 100644 index 000000000000..60497a3c6004 --- /dev/null +++ b/net/ipv6/netfilter/ip6t_REDIRECT.c | |||
@@ -0,0 +1,98 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2011 Patrick McHardy <kaber@trash.net> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * Based on Rusty Russell's IPv4 REDIRECT target. Development of IPv6 | ||
9 | * NAT funded by Astaro. | ||
10 | */ | ||
11 | |||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/netfilter.h> | ||
15 | #include <linux/netfilter_ipv6.h> | ||
16 | #include <linux/netfilter/x_tables.h> | ||
17 | #include <net/addrconf.h> | ||
18 | #include <net/netfilter/nf_nat.h> | ||
19 | |||
20 | static const struct in6_addr loopback_addr = IN6ADDR_LOOPBACK_INIT; | ||
21 | |||
22 | static unsigned int | ||
23 | redirect_tg6(struct sk_buff *skb, const struct xt_action_param *par) | ||
24 | { | ||
25 | const struct nf_nat_range *range = par->targinfo; | ||
26 | struct nf_nat_range newrange; | ||
27 | struct in6_addr newdst; | ||
28 | enum ip_conntrack_info ctinfo; | ||
29 | struct nf_conn *ct; | ||
30 | |||
31 | ct = nf_ct_get(skb, &ctinfo); | ||
32 | if (par->hooknum == NF_INET_LOCAL_OUT) | ||
33 | newdst = loopback_addr; | ||
34 | else { | ||
35 | struct inet6_dev *idev; | ||
36 | struct inet6_ifaddr *ifa; | ||
37 | bool addr = false; | ||
38 | |||
39 | rcu_read_lock(); | ||
40 | idev = __in6_dev_get(skb->dev); | ||
41 | if (idev != NULL) { | ||
42 | list_for_each_entry(ifa, &idev->addr_list, if_list) { | ||
43 | newdst = ifa->addr; | ||
44 | addr = true; | ||
45 | break; | ||
46 | } | ||
47 | } | ||
48 | rcu_read_unlock(); | ||
49 | |||
50 | if (!addr) | ||
51 | return NF_DROP; | ||
52 | } | ||
53 | |||
54 | newrange.flags = range->flags | NF_NAT_RANGE_MAP_IPS; | ||
55 | newrange.min_addr.in6 = newdst; | ||
56 | newrange.max_addr.in6 = newdst; | ||
57 | newrange.min_proto = range->min_proto; | ||
58 | newrange.max_proto = range->max_proto; | ||
59 | |||
60 | return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_DST); | ||
61 | } | ||
62 | |||
63 | static int redirect_tg6_checkentry(const struct xt_tgchk_param *par) | ||
64 | { | ||
65 | const struct nf_nat_range *range = par->targinfo; | ||
66 | |||
67 | if (range->flags & NF_NAT_RANGE_MAP_IPS) | ||
68 | return -EINVAL; | ||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | static struct xt_target redirect_tg6_reg __read_mostly = { | ||
73 | .name = "REDIRECT", | ||
74 | .family = NFPROTO_IPV6, | ||
75 | .checkentry = redirect_tg6_checkentry, | ||
76 | .target = redirect_tg6, | ||
77 | .targetsize = sizeof(struct nf_nat_range), | ||
78 | .table = "nat", | ||
79 | .hooks = (1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT), | ||
80 | .me = THIS_MODULE, | ||
81 | }; | ||
82 | |||
83 | static int __init redirect_tg6_init(void) | ||
84 | { | ||
85 | return xt_register_target(&redirect_tg6_reg); | ||
86 | } | ||
87 | |||
88 | static void __exit redirect_tg6_exit(void) | ||
89 | { | ||
90 | xt_unregister_target(&redirect_tg6_reg); | ||
91 | } | ||
92 | |||
93 | module_init(redirect_tg6_init); | ||
94 | module_exit(redirect_tg6_exit); | ||
95 | |||
96 | MODULE_LICENSE("GPL"); | ||
97 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); | ||
98 | MODULE_DESCRIPTION("Xtables: Connection redirection to localhost"); | ||
diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index 325e59a0224f..beb5777d2043 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c | |||
@@ -61,9 +61,7 @@ static int __net_init ip6table_filter_net_init(struct net *net) | |||
61 | net->ipv6.ip6table_filter = | 61 | net->ipv6.ip6table_filter = |
62 | ip6t_register_table(net, &packet_filter, repl); | 62 | ip6t_register_table(net, &packet_filter, repl); |
63 | kfree(repl); | 63 | kfree(repl); |
64 | if (IS_ERR(net->ipv6.ip6table_filter)) | 64 | return PTR_RET(net->ipv6.ip6table_filter); |
65 | return PTR_ERR(net->ipv6.ip6table_filter); | ||
66 | return 0; | ||
67 | } | 65 | } |
68 | 66 | ||
69 | static void __net_exit ip6table_filter_net_exit(struct net *net) | 67 | static void __net_exit ip6table_filter_net_exit(struct net *net) |
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index 4d782405f125..7431121b87de 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c | |||
@@ -97,9 +97,7 @@ static int __net_init ip6table_mangle_net_init(struct net *net) | |||
97 | net->ipv6.ip6table_mangle = | 97 | net->ipv6.ip6table_mangle = |
98 | ip6t_register_table(net, &packet_mangler, repl); | 98 | ip6t_register_table(net, &packet_mangler, repl); |
99 | kfree(repl); | 99 | kfree(repl); |
100 | if (IS_ERR(net->ipv6.ip6table_mangle)) | 100 | return PTR_RET(net->ipv6.ip6table_mangle); |
101 | return PTR_ERR(net->ipv6.ip6table_mangle); | ||
102 | return 0; | ||
103 | } | 101 | } |
104 | 102 | ||
105 | static void __net_exit ip6table_mangle_net_exit(struct net *net) | 103 | static void __net_exit ip6table_mangle_net_exit(struct net *net) |
diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c new file mode 100644 index 000000000000..e418bd6350a4 --- /dev/null +++ b/net/ipv6/netfilter/ip6table_nat.c | |||
@@ -0,0 +1,321 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2011 Patrick McHardy <kaber@trash.net> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * Based on Rusty Russell's IPv4 NAT code. Development of IPv6 NAT | ||
9 | * funded by Astaro. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/netfilter.h> | ||
14 | #include <linux/netfilter_ipv6.h> | ||
15 | #include <linux/netfilter_ipv6/ip6_tables.h> | ||
16 | #include <linux/ipv6.h> | ||
17 | #include <net/ipv6.h> | ||
18 | |||
19 | #include <net/netfilter/nf_nat.h> | ||
20 | #include <net/netfilter/nf_nat_core.h> | ||
21 | #include <net/netfilter/nf_nat_l3proto.h> | ||
22 | |||
23 | static const struct xt_table nf_nat_ipv6_table = { | ||
24 | .name = "nat", | ||
25 | .valid_hooks = (1 << NF_INET_PRE_ROUTING) | | ||
26 | (1 << NF_INET_POST_ROUTING) | | ||
27 | (1 << NF_INET_LOCAL_OUT) | | ||
28 | (1 << NF_INET_LOCAL_IN), | ||
29 | .me = THIS_MODULE, | ||
30 | .af = NFPROTO_IPV6, | ||
31 | }; | ||
32 | |||
33 | static unsigned int alloc_null_binding(struct nf_conn *ct, unsigned int hooknum) | ||
34 | { | ||
35 | /* Force range to this IP; let proto decide mapping for | ||
36 | * per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED). | ||
37 | */ | ||
38 | struct nf_nat_range range; | ||
39 | |||
40 | range.flags = 0; | ||
41 | pr_debug("Allocating NULL binding for %p (%pI6)\n", ct, | ||
42 | HOOK2MANIP(hooknum) == NF_NAT_MANIP_SRC ? | ||
43 | &ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip6 : | ||
44 | &ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip6); | ||
45 | |||
46 | return nf_nat_setup_info(ct, &range, HOOK2MANIP(hooknum)); | ||
47 | } | ||
48 | |||
49 | static unsigned int nf_nat_rule_find(struct sk_buff *skb, unsigned int hooknum, | ||
50 | const struct net_device *in, | ||
51 | const struct net_device *out, | ||
52 | struct nf_conn *ct) | ||
53 | { | ||
54 | struct net *net = nf_ct_net(ct); | ||
55 | unsigned int ret; | ||
56 | |||
57 | ret = ip6t_do_table(skb, hooknum, in, out, net->ipv6.ip6table_nat); | ||
58 | if (ret == NF_ACCEPT) { | ||
59 | if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum))) | ||
60 | ret = alloc_null_binding(ct, hooknum); | ||
61 | } | ||
62 | return ret; | ||
63 | } | ||
64 | |||
65 | static unsigned int | ||
66 | nf_nat_ipv6_fn(unsigned int hooknum, | ||
67 | struct sk_buff *skb, | ||
68 | const struct net_device *in, | ||
69 | const struct net_device *out, | ||
70 | int (*okfn)(struct sk_buff *)) | ||
71 | { | ||
72 | struct nf_conn *ct; | ||
73 | enum ip_conntrack_info ctinfo; | ||
74 | struct nf_conn_nat *nat; | ||
75 | enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum); | ||
76 | __be16 frag_off; | ||
77 | int hdrlen; | ||
78 | u8 nexthdr; | ||
79 | |||
80 | ct = nf_ct_get(skb, &ctinfo); | ||
81 | /* Can't track? It's not due to stress, or conntrack would | ||
82 | * have dropped it. Hence it's the user's responsibilty to | ||
83 | * packet filter it out, or implement conntrack/NAT for that | ||
84 | * protocol. 8) --RR | ||
85 | */ | ||
86 | if (!ct) | ||
87 | return NF_ACCEPT; | ||
88 | |||
89 | /* Don't try to NAT if this packet is not conntracked */ | ||
90 | if (nf_ct_is_untracked(ct)) | ||
91 | return NF_ACCEPT; | ||
92 | |||
93 | nat = nfct_nat(ct); | ||
94 | if (!nat) { | ||
95 | /* NAT module was loaded late. */ | ||
96 | if (nf_ct_is_confirmed(ct)) | ||
97 | return NF_ACCEPT; | ||
98 | nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC); | ||
99 | if (nat == NULL) { | ||
100 | pr_debug("failed to add NAT extension\n"); | ||
101 | return NF_ACCEPT; | ||
102 | } | ||
103 | } | ||
104 | |||
105 | switch (ctinfo) { | ||
106 | case IP_CT_RELATED: | ||
107 | case IP_CT_RELATED_REPLY: | ||
108 | nexthdr = ipv6_hdr(skb)->nexthdr; | ||
109 | hdrlen = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), | ||
110 | &nexthdr, &frag_off); | ||
111 | |||
112 | if (hdrlen >= 0 && nexthdr == IPPROTO_ICMPV6) { | ||
113 | if (!nf_nat_icmpv6_reply_translation(skb, ct, ctinfo, | ||
114 | hooknum, hdrlen)) | ||
115 | return NF_DROP; | ||
116 | else | ||
117 | return NF_ACCEPT; | ||
118 | } | ||
119 | /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */ | ||
120 | case IP_CT_NEW: | ||
121 | /* Seen it before? This can happen for loopback, retrans, | ||
122 | * or local packets. | ||
123 | */ | ||
124 | if (!nf_nat_initialized(ct, maniptype)) { | ||
125 | unsigned int ret; | ||
126 | |||
127 | ret = nf_nat_rule_find(skb, hooknum, in, out, ct); | ||
128 | if (ret != NF_ACCEPT) | ||
129 | return ret; | ||
130 | } else | ||
131 | pr_debug("Already setup manip %s for ct %p\n", | ||
132 | maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST", | ||
133 | ct); | ||
134 | break; | ||
135 | |||
136 | default: | ||
137 | /* ESTABLISHED */ | ||
138 | NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || | ||
139 | ctinfo == IP_CT_ESTABLISHED_REPLY); | ||
140 | } | ||
141 | |||
142 | return nf_nat_packet(ct, ctinfo, hooknum, skb); | ||
143 | } | ||
144 | |||
145 | static unsigned int | ||
146 | nf_nat_ipv6_in(unsigned int hooknum, | ||
147 | struct sk_buff *skb, | ||
148 | const struct net_device *in, | ||
149 | const struct net_device *out, | ||
150 | int (*okfn)(struct sk_buff *)) | ||
151 | { | ||
152 | unsigned int ret; | ||
153 | struct in6_addr daddr = ipv6_hdr(skb)->daddr; | ||
154 | |||
155 | ret = nf_nat_ipv6_fn(hooknum, skb, in, out, okfn); | ||
156 | if (ret != NF_DROP && ret != NF_STOLEN && | ||
157 | ipv6_addr_cmp(&daddr, &ipv6_hdr(skb)->daddr)) | ||
158 | skb_dst_drop(skb); | ||
159 | |||
160 | return ret; | ||
161 | } | ||
162 | |||
163 | static unsigned int | ||
164 | nf_nat_ipv6_out(unsigned int hooknum, | ||
165 | struct sk_buff *skb, | ||
166 | const struct net_device *in, | ||
167 | const struct net_device *out, | ||
168 | int (*okfn)(struct sk_buff *)) | ||
169 | { | ||
170 | #ifdef CONFIG_XFRM | ||
171 | const struct nf_conn *ct; | ||
172 | enum ip_conntrack_info ctinfo; | ||
173 | #endif | ||
174 | unsigned int ret; | ||
175 | |||
176 | /* root is playing with raw sockets. */ | ||
177 | if (skb->len < sizeof(struct ipv6hdr)) | ||
178 | return NF_ACCEPT; | ||
179 | |||
180 | ret = nf_nat_ipv6_fn(hooknum, skb, in, out, okfn); | ||
181 | #ifdef CONFIG_XFRM | ||
182 | if (ret != NF_DROP && ret != NF_STOLEN && | ||
183 | !(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && | ||
184 | (ct = nf_ct_get(skb, &ctinfo)) != NULL) { | ||
185 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
186 | |||
187 | if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, | ||
188 | &ct->tuplehash[!dir].tuple.dst.u3) || | ||
189 | (ct->tuplehash[dir].tuple.src.u.all != | ||
190 | ct->tuplehash[!dir].tuple.dst.u.all)) | ||
191 | if (nf_xfrm_me_harder(skb, AF_INET6) < 0) | ||
192 | ret = NF_DROP; | ||
193 | } | ||
194 | #endif | ||
195 | return ret; | ||
196 | } | ||
197 | |||
198 | static unsigned int | ||
199 | nf_nat_ipv6_local_fn(unsigned int hooknum, | ||
200 | struct sk_buff *skb, | ||
201 | const struct net_device *in, | ||
202 | const struct net_device *out, | ||
203 | int (*okfn)(struct sk_buff *)) | ||
204 | { | ||
205 | const struct nf_conn *ct; | ||
206 | enum ip_conntrack_info ctinfo; | ||
207 | unsigned int ret; | ||
208 | |||
209 | /* root is playing with raw sockets. */ | ||
210 | if (skb->len < sizeof(struct ipv6hdr)) | ||
211 | return NF_ACCEPT; | ||
212 | |||
213 | ret = nf_nat_ipv6_fn(hooknum, skb, in, out, okfn); | ||
214 | if (ret != NF_DROP && ret != NF_STOLEN && | ||
215 | (ct = nf_ct_get(skb, &ctinfo)) != NULL) { | ||
216 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
217 | |||
218 | if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, | ||
219 | &ct->tuplehash[!dir].tuple.src.u3)) { | ||
220 | if (ip6_route_me_harder(skb)) | ||
221 | ret = NF_DROP; | ||
222 | } | ||
223 | #ifdef CONFIG_XFRM | ||
224 | else if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && | ||
225 | ct->tuplehash[dir].tuple.dst.u.all != | ||
226 | ct->tuplehash[!dir].tuple.src.u.all) | ||
227 | if (nf_xfrm_me_harder(skb, AF_INET6)) | ||
228 | ret = NF_DROP; | ||
229 | #endif | ||
230 | } | ||
231 | return ret; | ||
232 | } | ||
233 | |||
234 | static struct nf_hook_ops nf_nat_ipv6_ops[] __read_mostly = { | ||
235 | /* Before packet filtering, change destination */ | ||
236 | { | ||
237 | .hook = nf_nat_ipv6_in, | ||
238 | .owner = THIS_MODULE, | ||
239 | .pf = NFPROTO_IPV6, | ||
240 | .hooknum = NF_INET_PRE_ROUTING, | ||
241 | .priority = NF_IP6_PRI_NAT_DST, | ||
242 | }, | ||
243 | /* After packet filtering, change source */ | ||
244 | { | ||
245 | .hook = nf_nat_ipv6_out, | ||
246 | .owner = THIS_MODULE, | ||
247 | .pf = NFPROTO_IPV6, | ||
248 | .hooknum = NF_INET_POST_ROUTING, | ||
249 | .priority = NF_IP6_PRI_NAT_SRC, | ||
250 | }, | ||
251 | /* Before packet filtering, change destination */ | ||
252 | { | ||
253 | .hook = nf_nat_ipv6_local_fn, | ||
254 | .owner = THIS_MODULE, | ||
255 | .pf = NFPROTO_IPV6, | ||
256 | .hooknum = NF_INET_LOCAL_OUT, | ||
257 | .priority = NF_IP6_PRI_NAT_DST, | ||
258 | }, | ||
259 | /* After packet filtering, change source */ | ||
260 | { | ||
261 | .hook = nf_nat_ipv6_fn, | ||
262 | .owner = THIS_MODULE, | ||
263 | .pf = NFPROTO_IPV6, | ||
264 | .hooknum = NF_INET_LOCAL_IN, | ||
265 | .priority = NF_IP6_PRI_NAT_SRC, | ||
266 | }, | ||
267 | }; | ||
268 | |||
269 | static int __net_init ip6table_nat_net_init(struct net *net) | ||
270 | { | ||
271 | struct ip6t_replace *repl; | ||
272 | |||
273 | repl = ip6t_alloc_initial_table(&nf_nat_ipv6_table); | ||
274 | if (repl == NULL) | ||
275 | return -ENOMEM; | ||
276 | net->ipv6.ip6table_nat = ip6t_register_table(net, &nf_nat_ipv6_table, repl); | ||
277 | kfree(repl); | ||
278 | if (IS_ERR(net->ipv6.ip6table_nat)) | ||
279 | return PTR_ERR(net->ipv6.ip6table_nat); | ||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | static void __net_exit ip6table_nat_net_exit(struct net *net) | ||
284 | { | ||
285 | ip6t_unregister_table(net, net->ipv6.ip6table_nat); | ||
286 | } | ||
287 | |||
288 | static struct pernet_operations ip6table_nat_net_ops = { | ||
289 | .init = ip6table_nat_net_init, | ||
290 | .exit = ip6table_nat_net_exit, | ||
291 | }; | ||
292 | |||
293 | static int __init ip6table_nat_init(void) | ||
294 | { | ||
295 | int err; | ||
296 | |||
297 | err = register_pernet_subsys(&ip6table_nat_net_ops); | ||
298 | if (err < 0) | ||
299 | goto err1; | ||
300 | |||
301 | err = nf_register_hooks(nf_nat_ipv6_ops, ARRAY_SIZE(nf_nat_ipv6_ops)); | ||
302 | if (err < 0) | ||
303 | goto err2; | ||
304 | return 0; | ||
305 | |||
306 | err2: | ||
307 | unregister_pernet_subsys(&ip6table_nat_net_ops); | ||
308 | err1: | ||
309 | return err; | ||
310 | } | ||
311 | |||
312 | static void __exit ip6table_nat_exit(void) | ||
313 | { | ||
314 | nf_unregister_hooks(nf_nat_ipv6_ops, ARRAY_SIZE(nf_nat_ipv6_ops)); | ||
315 | unregister_pernet_subsys(&ip6table_nat_net_ops); | ||
316 | } | ||
317 | |||
318 | module_init(ip6table_nat_init); | ||
319 | module_exit(ip6table_nat_exit); | ||
320 | |||
321 | MODULE_LICENSE("GPL"); | ||
diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c index 5b9926a011bd..60d1bddff7a0 100644 --- a/net/ipv6/netfilter/ip6table_raw.c +++ b/net/ipv6/netfilter/ip6table_raw.c | |||
@@ -40,9 +40,7 @@ static int __net_init ip6table_raw_net_init(struct net *net) | |||
40 | net->ipv6.ip6table_raw = | 40 | net->ipv6.ip6table_raw = |
41 | ip6t_register_table(net, &packet_raw, repl); | 41 | ip6t_register_table(net, &packet_raw, repl); |
42 | kfree(repl); | 42 | kfree(repl); |
43 | if (IS_ERR(net->ipv6.ip6table_raw)) | 43 | return PTR_RET(net->ipv6.ip6table_raw); |
44 | return PTR_ERR(net->ipv6.ip6table_raw); | ||
45 | return 0; | ||
46 | } | 44 | } |
47 | 45 | ||
48 | static void __net_exit ip6table_raw_net_exit(struct net *net) | 46 | static void __net_exit ip6table_raw_net_exit(struct net *net) |
diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c index 91aa2b4d83c9..db155351339c 100644 --- a/net/ipv6/netfilter/ip6table_security.c +++ b/net/ipv6/netfilter/ip6table_security.c | |||
@@ -58,10 +58,7 @@ static int __net_init ip6table_security_net_init(struct net *net) | |||
58 | net->ipv6.ip6table_security = | 58 | net->ipv6.ip6table_security = |
59 | ip6t_register_table(net, &security_table, repl); | 59 | ip6t_register_table(net, &security_table, repl); |
60 | kfree(repl); | 60 | kfree(repl); |
61 | if (IS_ERR(net->ipv6.ip6table_security)) | 61 | return PTR_RET(net->ipv6.ip6table_security); |
62 | return PTR_ERR(net->ipv6.ip6table_security); | ||
63 | |||
64 | return 0; | ||
65 | } | 62 | } |
66 | 63 | ||
67 | static void __net_exit ip6table_security_net_exit(struct net *net) | 64 | static void __net_exit ip6table_security_net_exit(struct net *net) |
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index 4794f96cf2e0..8860d23e61cf 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <net/netfilter/nf_conntrack_core.h> | 28 | #include <net/netfilter/nf_conntrack_core.h> |
29 | #include <net/netfilter/nf_conntrack_zones.h> | 29 | #include <net/netfilter/nf_conntrack_zones.h> |
30 | #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> | 30 | #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> |
31 | #include <net/netfilter/nf_nat_helper.h> | ||
31 | #include <net/netfilter/ipv6/nf_defrag_ipv6.h> | 32 | #include <net/netfilter/ipv6/nf_defrag_ipv6.h> |
32 | #include <net/netfilter/nf_log.h> | 33 | #include <net/netfilter/nf_log.h> |
33 | 34 | ||
@@ -64,82 +65,31 @@ static int ipv6_print_tuple(struct seq_file *s, | |||
64 | tuple->src.u3.ip6, tuple->dst.u3.ip6); | 65 | tuple->src.u3.ip6, tuple->dst.u3.ip6); |
65 | } | 66 | } |
66 | 67 | ||
67 | /* | ||
68 | * Based on ipv6_skip_exthdr() in net/ipv6/exthdr.c | ||
69 | * | ||
70 | * This function parses (probably truncated) exthdr set "hdr" | ||
71 | * of length "len". "nexthdrp" initially points to some place, | ||
72 | * where type of the first header can be found. | ||
73 | * | ||
74 | * It skips all well-known exthdrs, and returns pointer to the start | ||
75 | * of unparsable area i.e. the first header with unknown type. | ||
76 | * if success, *nexthdr is updated by type/protocol of this header. | ||
77 | * | ||
78 | * NOTES: - it may return pointer pointing beyond end of packet, | ||
79 | * if the last recognized header is truncated in the middle. | ||
80 | * - if packet is truncated, so that all parsed headers are skipped, | ||
81 | * it returns -1. | ||
82 | * - if packet is fragmented, return pointer of the fragment header. | ||
83 | * - ESP is unparsable for now and considered like | ||
84 | * normal payload protocol. | ||
85 | * - Note also special handling of AUTH header. Thanks to IPsec wizards. | ||
86 | */ | ||
87 | |||
88 | static int nf_ct_ipv6_skip_exthdr(const struct sk_buff *skb, int start, | ||
89 | u8 *nexthdrp, int len) | ||
90 | { | ||
91 | u8 nexthdr = *nexthdrp; | ||
92 | |||
93 | while (ipv6_ext_hdr(nexthdr)) { | ||
94 | struct ipv6_opt_hdr hdr; | ||
95 | int hdrlen; | ||
96 | |||
97 | if (len < (int)sizeof(struct ipv6_opt_hdr)) | ||
98 | return -1; | ||
99 | if (nexthdr == NEXTHDR_NONE) | ||
100 | break; | ||
101 | if (nexthdr == NEXTHDR_FRAGMENT) | ||
102 | break; | ||
103 | if (skb_copy_bits(skb, start, &hdr, sizeof(hdr))) | ||
104 | BUG(); | ||
105 | if (nexthdr == NEXTHDR_AUTH) | ||
106 | hdrlen = (hdr.hdrlen+2)<<2; | ||
107 | else | ||
108 | hdrlen = ipv6_optlen(&hdr); | ||
109 | |||
110 | nexthdr = hdr.nexthdr; | ||
111 | len -= hdrlen; | ||
112 | start += hdrlen; | ||
113 | } | ||
114 | |||
115 | *nexthdrp = nexthdr; | ||
116 | return start; | ||
117 | } | ||
118 | |||
119 | static int ipv6_get_l4proto(const struct sk_buff *skb, unsigned int nhoff, | 68 | static int ipv6_get_l4proto(const struct sk_buff *skb, unsigned int nhoff, |
120 | unsigned int *dataoff, u_int8_t *protonum) | 69 | unsigned int *dataoff, u_int8_t *protonum) |
121 | { | 70 | { |
122 | unsigned int extoff = nhoff + sizeof(struct ipv6hdr); | 71 | unsigned int extoff = nhoff + sizeof(struct ipv6hdr); |
123 | unsigned char pnum; | 72 | __be16 frag_off; |
124 | int protoff; | 73 | int protoff; |
74 | u8 nexthdr; | ||
125 | 75 | ||
126 | if (skb_copy_bits(skb, nhoff + offsetof(struct ipv6hdr, nexthdr), | 76 | if (skb_copy_bits(skb, nhoff + offsetof(struct ipv6hdr, nexthdr), |
127 | &pnum, sizeof(pnum)) != 0) { | 77 | &nexthdr, sizeof(nexthdr)) != 0) { |
128 | pr_debug("ip6_conntrack_core: can't get nexthdr\n"); | 78 | pr_debug("ip6_conntrack_core: can't get nexthdr\n"); |
129 | return -NF_ACCEPT; | 79 | return -NF_ACCEPT; |
130 | } | 80 | } |
131 | protoff = nf_ct_ipv6_skip_exthdr(skb, extoff, &pnum, skb->len - extoff); | 81 | protoff = ipv6_skip_exthdr(skb, extoff, &nexthdr, &frag_off); |
132 | /* | 82 | /* |
133 | * (protoff == skb->len) mean that the packet doesn't have no data | 83 | * (protoff == skb->len) mean that the packet doesn't have no data |
134 | * except of IPv6 & ext headers. but it's tracked anyway. - YK | 84 | * except of IPv6 & ext headers. but it's tracked anyway. - YK |
135 | */ | 85 | */ |
136 | if ((protoff < 0) || (protoff > skb->len)) { | 86 | if (protoff < 0 || (frag_off & htons(~0x7)) != 0) { |
137 | pr_debug("ip6_conntrack_core: can't find proto in pkt\n"); | 87 | pr_debug("ip6_conntrack_core: can't find proto in pkt\n"); |
138 | return -NF_ACCEPT; | 88 | return -NF_ACCEPT; |
139 | } | 89 | } |
140 | 90 | ||
141 | *dataoff = protoff; | 91 | *dataoff = protoff; |
142 | *protonum = pnum; | 92 | *protonum = nexthdr; |
143 | return NF_ACCEPT; | 93 | return NF_ACCEPT; |
144 | } | 94 | } |
145 | 95 | ||
@@ -153,10 +103,10 @@ static unsigned int ipv6_helper(unsigned int hooknum, | |||
153 | const struct nf_conn_help *help; | 103 | const struct nf_conn_help *help; |
154 | const struct nf_conntrack_helper *helper; | 104 | const struct nf_conntrack_helper *helper; |
155 | enum ip_conntrack_info ctinfo; | 105 | enum ip_conntrack_info ctinfo; |
156 | unsigned int ret, protoff; | 106 | unsigned int ret; |
157 | unsigned int extoff = (u8 *)(ipv6_hdr(skb) + 1) - skb->data; | 107 | __be16 frag_off; |
158 | unsigned char pnum = ipv6_hdr(skb)->nexthdr; | 108 | int protoff; |
159 | 109 | u8 nexthdr; | |
160 | 110 | ||
161 | /* This is where we call the helper: as the packet goes out. */ | 111 | /* This is where we call the helper: as the packet goes out. */ |
162 | ct = nf_ct_get(skb, &ctinfo); | 112 | ct = nf_ct_get(skb, &ctinfo); |
@@ -171,9 +121,10 @@ static unsigned int ipv6_helper(unsigned int hooknum, | |||
171 | if (!helper) | 121 | if (!helper) |
172 | return NF_ACCEPT; | 122 | return NF_ACCEPT; |
173 | 123 | ||
174 | protoff = nf_ct_ipv6_skip_exthdr(skb, extoff, &pnum, | 124 | nexthdr = ipv6_hdr(skb)->nexthdr; |
175 | skb->len - extoff); | 125 | protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr, |
176 | if (protoff > skb->len || pnum == NEXTHDR_FRAGMENT) { | 126 | &frag_off); |
127 | if (protoff < 0 || (frag_off & htons(~0x7)) != 0) { | ||
177 | pr_debug("proto header not found\n"); | 128 | pr_debug("proto header not found\n"); |
178 | return NF_ACCEPT; | 129 | return NF_ACCEPT; |
179 | } | 130 | } |
@@ -192,6 +143,36 @@ static unsigned int ipv6_confirm(unsigned int hooknum, | |||
192 | const struct net_device *out, | 143 | const struct net_device *out, |
193 | int (*okfn)(struct sk_buff *)) | 144 | int (*okfn)(struct sk_buff *)) |
194 | { | 145 | { |
146 | struct nf_conn *ct; | ||
147 | enum ip_conntrack_info ctinfo; | ||
148 | unsigned char pnum = ipv6_hdr(skb)->nexthdr; | ||
149 | int protoff; | ||
150 | __be16 frag_off; | ||
151 | |||
152 | ct = nf_ct_get(skb, &ctinfo); | ||
153 | if (!ct || ctinfo == IP_CT_RELATED_REPLY) | ||
154 | goto out; | ||
155 | |||
156 | protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &pnum, | ||
157 | &frag_off); | ||
158 | if (protoff < 0 || (frag_off & htons(~0x7)) != 0) { | ||
159 | pr_debug("proto header not found\n"); | ||
160 | goto out; | ||
161 | } | ||
162 | |||
163 | /* adjust seqs for loopback traffic only in outgoing direction */ | ||
164 | if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) && | ||
165 | !nf_is_loopback_packet(skb)) { | ||
166 | typeof(nf_nat_seq_adjust_hook) seq_adjust; | ||
167 | |||
168 | seq_adjust = rcu_dereference(nf_nat_seq_adjust_hook); | ||
169 | if (!seq_adjust || | ||
170 | !seq_adjust(skb, ct, ctinfo, protoff)) { | ||
171 | NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop); | ||
172 | return NF_DROP; | ||
173 | } | ||
174 | } | ||
175 | out: | ||
195 | /* We've seen it coming out the other side: confirm it */ | 176 | /* We've seen it coming out the other side: confirm it */ |
196 | return nf_conntrack_confirm(skb); | 177 | return nf_conntrack_confirm(skb); |
197 | } | 178 | } |
@@ -199,9 +180,14 @@ static unsigned int ipv6_confirm(unsigned int hooknum, | |||
199 | static unsigned int __ipv6_conntrack_in(struct net *net, | 180 | static unsigned int __ipv6_conntrack_in(struct net *net, |
200 | unsigned int hooknum, | 181 | unsigned int hooknum, |
201 | struct sk_buff *skb, | 182 | struct sk_buff *skb, |
183 | const struct net_device *in, | ||
184 | const struct net_device *out, | ||
202 | int (*okfn)(struct sk_buff *)) | 185 | int (*okfn)(struct sk_buff *)) |
203 | { | 186 | { |
204 | struct sk_buff *reasm = skb->nfct_reasm; | 187 | struct sk_buff *reasm = skb->nfct_reasm; |
188 | const struct nf_conn_help *help; | ||
189 | struct nf_conn *ct; | ||
190 | enum ip_conntrack_info ctinfo; | ||
205 | 191 | ||
206 | /* This packet is fragmented and has reassembled packet. */ | 192 | /* This packet is fragmented and has reassembled packet. */ |
207 | if (reasm) { | 193 | if (reasm) { |
@@ -213,6 +199,25 @@ static unsigned int __ipv6_conntrack_in(struct net *net, | |||
213 | if (ret != NF_ACCEPT) | 199 | if (ret != NF_ACCEPT) |
214 | return ret; | 200 | return ret; |
215 | } | 201 | } |
202 | |||
203 | /* Conntrack helpers need the entire reassembled packet in the | ||
204 | * POST_ROUTING hook. In case of unconfirmed connections NAT | ||
205 | * might reassign a helper, so the entire packet is also | ||
206 | * required. | ||
207 | */ | ||
208 | ct = nf_ct_get(reasm, &ctinfo); | ||
209 | if (ct != NULL && !nf_ct_is_untracked(ct)) { | ||
210 | help = nfct_help(ct); | ||
211 | if ((help && help->helper) || !nf_ct_is_confirmed(ct)) { | ||
212 | nf_conntrack_get_reasm(skb); | ||
213 | NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, reasm, | ||
214 | (struct net_device *)in, | ||
215 | (struct net_device *)out, | ||
216 | okfn, NF_IP6_PRI_CONNTRACK + 1); | ||
217 | return NF_DROP_ERR(-ECANCELED); | ||
218 | } | ||
219 | } | ||
220 | |||
216 | nf_conntrack_get(reasm->nfct); | 221 | nf_conntrack_get(reasm->nfct); |
217 | skb->nfct = reasm->nfct; | 222 | skb->nfct = reasm->nfct; |
218 | skb->nfctinfo = reasm->nfctinfo; | 223 | skb->nfctinfo = reasm->nfctinfo; |
@@ -228,7 +233,7 @@ static unsigned int ipv6_conntrack_in(unsigned int hooknum, | |||
228 | const struct net_device *out, | 233 | const struct net_device *out, |
229 | int (*okfn)(struct sk_buff *)) | 234 | int (*okfn)(struct sk_buff *)) |
230 | { | 235 | { |
231 | return __ipv6_conntrack_in(dev_net(in), hooknum, skb, okfn); | 236 | return __ipv6_conntrack_in(dev_net(in), hooknum, skb, in, out, okfn); |
232 | } | 237 | } |
233 | 238 | ||
234 | static unsigned int ipv6_conntrack_local(unsigned int hooknum, | 239 | static unsigned int ipv6_conntrack_local(unsigned int hooknum, |
@@ -242,7 +247,7 @@ static unsigned int ipv6_conntrack_local(unsigned int hooknum, | |||
242 | net_notice_ratelimited("ipv6_conntrack_local: packet too short\n"); | 247 | net_notice_ratelimited("ipv6_conntrack_local: packet too short\n"); |
243 | return NF_ACCEPT; | 248 | return NF_ACCEPT; |
244 | } | 249 | } |
245 | return __ipv6_conntrack_in(dev_net(out), hooknum, skb, okfn); | 250 | return __ipv6_conntrack_in(dev_net(out), hooknum, skb, in, out, okfn); |
246 | } | 251 | } |
247 | 252 | ||
248 | static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = { | 253 | static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = { |
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index c9c78c2e666b..f94fb3ac2a79 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c | |||
@@ -190,6 +190,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb, | |||
190 | const struct frag_hdr *fhdr, int nhoff) | 190 | const struct frag_hdr *fhdr, int nhoff) |
191 | { | 191 | { |
192 | struct sk_buff *prev, *next; | 192 | struct sk_buff *prev, *next; |
193 | unsigned int payload_len; | ||
193 | int offset, end; | 194 | int offset, end; |
194 | 195 | ||
195 | if (fq->q.last_in & INET_FRAG_COMPLETE) { | 196 | if (fq->q.last_in & INET_FRAG_COMPLETE) { |
@@ -197,8 +198,10 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb, | |||
197 | goto err; | 198 | goto err; |
198 | } | 199 | } |
199 | 200 | ||
201 | payload_len = ntohs(ipv6_hdr(skb)->payload_len); | ||
202 | |||
200 | offset = ntohs(fhdr->frag_off) & ~0x7; | 203 | offset = ntohs(fhdr->frag_off) & ~0x7; |
201 | end = offset + (ntohs(ipv6_hdr(skb)->payload_len) - | 204 | end = offset + (payload_len - |
202 | ((u8 *)(fhdr + 1) - (u8 *)(ipv6_hdr(skb) + 1))); | 205 | ((u8 *)(fhdr + 1) - (u8 *)(ipv6_hdr(skb) + 1))); |
203 | 206 | ||
204 | if ((unsigned int)end > IPV6_MAXPLEN) { | 207 | if ((unsigned int)end > IPV6_MAXPLEN) { |
@@ -307,6 +310,8 @@ found: | |||
307 | skb->dev = NULL; | 310 | skb->dev = NULL; |
308 | fq->q.stamp = skb->tstamp; | 311 | fq->q.stamp = skb->tstamp; |
309 | fq->q.meat += skb->len; | 312 | fq->q.meat += skb->len; |
313 | if (payload_len > fq->q.max_size) | ||
314 | fq->q.max_size = payload_len; | ||
310 | atomic_add(skb->truesize, &nf_init_frags.mem); | 315 | atomic_add(skb->truesize, &nf_init_frags.mem); |
311 | 316 | ||
312 | /* The first fragment. | 317 | /* The first fragment. |
@@ -412,10 +417,12 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev) | |||
412 | } | 417 | } |
413 | atomic_sub(head->truesize, &nf_init_frags.mem); | 418 | atomic_sub(head->truesize, &nf_init_frags.mem); |
414 | 419 | ||
420 | head->local_df = 1; | ||
415 | head->next = NULL; | 421 | head->next = NULL; |
416 | head->dev = dev; | 422 | head->dev = dev; |
417 | head->tstamp = fq->q.stamp; | 423 | head->tstamp = fq->q.stamp; |
418 | ipv6_hdr(head)->payload_len = htons(payload_len); | 424 | ipv6_hdr(head)->payload_len = htons(payload_len); |
425 | IP6CB(head)->frag_max_size = sizeof(struct ipv6hdr) + fq->q.max_size; | ||
419 | 426 | ||
420 | /* Yes, and fold redundant checksum back. 8) */ | 427 | /* Yes, and fold redundant checksum back. 8) */ |
421 | if (head->ip_summed == CHECKSUM_COMPLETE) | 428 | if (head->ip_summed == CHECKSUM_COMPLETE) |
@@ -592,6 +599,7 @@ void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb, | |||
592 | int (*okfn)(struct sk_buff *)) | 599 | int (*okfn)(struct sk_buff *)) |
593 | { | 600 | { |
594 | struct sk_buff *s, *s2; | 601 | struct sk_buff *s, *s2; |
602 | unsigned int ret = 0; | ||
595 | 603 | ||
596 | for (s = NFCT_FRAG6_CB(skb)->orig; s;) { | 604 | for (s = NFCT_FRAG6_CB(skb)->orig; s;) { |
597 | nf_conntrack_put_reasm(s->nfct_reasm); | 605 | nf_conntrack_put_reasm(s->nfct_reasm); |
@@ -601,8 +609,13 @@ void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb, | |||
601 | s2 = s->next; | 609 | s2 = s->next; |
602 | s->next = NULL; | 610 | s->next = NULL; |
603 | 611 | ||
604 | NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, s, in, out, okfn, | 612 | if (ret != -ECANCELED) |
605 | NF_IP6_PRI_CONNTRACK_DEFRAG + 1); | 613 | ret = NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, s, |
614 | in, out, okfn, | ||
615 | NF_IP6_PRI_CONNTRACK_DEFRAG + 1); | ||
616 | else | ||
617 | kfree_skb(s); | ||
618 | |||
606 | s = s2; | 619 | s = s2; |
607 | } | 620 | } |
608 | nf_conntrack_put_reasm(skb); | 621 | nf_conntrack_put_reasm(skb); |
diff --git a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c new file mode 100644 index 000000000000..abfe75a2e316 --- /dev/null +++ b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c | |||
@@ -0,0 +1,288 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2011 Patrick McHardy <kaber@trash.net> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * Development of IPv6 NAT funded by Astaro. | ||
9 | */ | ||
10 | #include <linux/types.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/skbuff.h> | ||
13 | #include <linux/ipv6.h> | ||
14 | #include <linux/netfilter.h> | ||
15 | #include <linux/netfilter_ipv6.h> | ||
16 | #include <net/secure_seq.h> | ||
17 | #include <net/checksum.h> | ||
18 | #include <net/ip6_checksum.h> | ||
19 | #include <net/ip6_route.h> | ||
20 | #include <net/ipv6.h> | ||
21 | |||
22 | #include <net/netfilter/nf_conntrack_core.h> | ||
23 | #include <net/netfilter/nf_conntrack.h> | ||
24 | #include <net/netfilter/nf_nat_core.h> | ||
25 | #include <net/netfilter/nf_nat_l3proto.h> | ||
26 | #include <net/netfilter/nf_nat_l4proto.h> | ||
27 | |||
28 | static const struct nf_nat_l3proto nf_nat_l3proto_ipv6; | ||
29 | |||
30 | #ifdef CONFIG_XFRM | ||
31 | static void nf_nat_ipv6_decode_session(struct sk_buff *skb, | ||
32 | const struct nf_conn *ct, | ||
33 | enum ip_conntrack_dir dir, | ||
34 | unsigned long statusbit, | ||
35 | struct flowi *fl) | ||
36 | { | ||
37 | const struct nf_conntrack_tuple *t = &ct->tuplehash[dir].tuple; | ||
38 | struct flowi6 *fl6 = &fl->u.ip6; | ||
39 | |||
40 | if (ct->status & statusbit) { | ||
41 | fl6->daddr = t->dst.u3.in6; | ||
42 | if (t->dst.protonum == IPPROTO_TCP || | ||
43 | t->dst.protonum == IPPROTO_UDP || | ||
44 | t->dst.protonum == IPPROTO_UDPLITE || | ||
45 | t->dst.protonum == IPPROTO_DCCP || | ||
46 | t->dst.protonum == IPPROTO_SCTP) | ||
47 | fl6->fl6_dport = t->dst.u.all; | ||
48 | } | ||
49 | |||
50 | statusbit ^= IPS_NAT_MASK; | ||
51 | |||
52 | if (ct->status & statusbit) { | ||
53 | fl6->saddr = t->src.u3.in6; | ||
54 | if (t->dst.protonum == IPPROTO_TCP || | ||
55 | t->dst.protonum == IPPROTO_UDP || | ||
56 | t->dst.protonum == IPPROTO_UDPLITE || | ||
57 | t->dst.protonum == IPPROTO_DCCP || | ||
58 | t->dst.protonum == IPPROTO_SCTP) | ||
59 | fl6->fl6_sport = t->src.u.all; | ||
60 | } | ||
61 | } | ||
62 | #endif | ||
63 | |||
64 | static bool nf_nat_ipv6_in_range(const struct nf_conntrack_tuple *t, | ||
65 | const struct nf_nat_range *range) | ||
66 | { | ||
67 | return ipv6_addr_cmp(&t->src.u3.in6, &range->min_addr.in6) >= 0 && | ||
68 | ipv6_addr_cmp(&t->src.u3.in6, &range->max_addr.in6) <= 0; | ||
69 | } | ||
70 | |||
71 | static u32 nf_nat_ipv6_secure_port(const struct nf_conntrack_tuple *t, | ||
72 | __be16 dport) | ||
73 | { | ||
74 | return secure_ipv6_port_ephemeral(t->src.u3.ip6, t->dst.u3.ip6, dport); | ||
75 | } | ||
76 | |||
77 | static bool nf_nat_ipv6_manip_pkt(struct sk_buff *skb, | ||
78 | unsigned int iphdroff, | ||
79 | const struct nf_nat_l4proto *l4proto, | ||
80 | const struct nf_conntrack_tuple *target, | ||
81 | enum nf_nat_manip_type maniptype) | ||
82 | { | ||
83 | struct ipv6hdr *ipv6h; | ||
84 | __be16 frag_off; | ||
85 | int hdroff; | ||
86 | u8 nexthdr; | ||
87 | |||
88 | if (!skb_make_writable(skb, iphdroff + sizeof(*ipv6h))) | ||
89 | return false; | ||
90 | |||
91 | ipv6h = (void *)skb->data + iphdroff; | ||
92 | nexthdr = ipv6h->nexthdr; | ||
93 | hdroff = ipv6_skip_exthdr(skb, iphdroff + sizeof(*ipv6h), | ||
94 | &nexthdr, &frag_off); | ||
95 | if (hdroff < 0) | ||
96 | goto manip_addr; | ||
97 | |||
98 | if ((frag_off & htons(~0x7)) == 0 && | ||
99 | !l4proto->manip_pkt(skb, &nf_nat_l3proto_ipv6, iphdroff, hdroff, | ||
100 | target, maniptype)) | ||
101 | return false; | ||
102 | manip_addr: | ||
103 | if (maniptype == NF_NAT_MANIP_SRC) | ||
104 | ipv6h->saddr = target->src.u3.in6; | ||
105 | else | ||
106 | ipv6h->daddr = target->dst.u3.in6; | ||
107 | |||
108 | return true; | ||
109 | } | ||
110 | |||
111 | static void nf_nat_ipv6_csum_update(struct sk_buff *skb, | ||
112 | unsigned int iphdroff, __sum16 *check, | ||
113 | const struct nf_conntrack_tuple *t, | ||
114 | enum nf_nat_manip_type maniptype) | ||
115 | { | ||
116 | const struct ipv6hdr *ipv6h = (struct ipv6hdr *)(skb->data + iphdroff); | ||
117 | const struct in6_addr *oldip, *newip; | ||
118 | |||
119 | if (maniptype == NF_NAT_MANIP_SRC) { | ||
120 | oldip = &ipv6h->saddr; | ||
121 | newip = &t->src.u3.in6; | ||
122 | } else { | ||
123 | oldip = &ipv6h->daddr; | ||
124 | newip = &t->dst.u3.in6; | ||
125 | } | ||
126 | inet_proto_csum_replace16(check, skb, oldip->s6_addr32, | ||
127 | newip->s6_addr32, 1); | ||
128 | } | ||
129 | |||
130 | static void nf_nat_ipv6_csum_recalc(struct sk_buff *skb, | ||
131 | u8 proto, void *data, __sum16 *check, | ||
132 | int datalen, int oldlen) | ||
133 | { | ||
134 | const struct ipv6hdr *ipv6h = ipv6_hdr(skb); | ||
135 | struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); | ||
136 | |||
137 | if (skb->ip_summed != CHECKSUM_PARTIAL) { | ||
138 | if (!(rt->rt6i_flags & RTF_LOCAL) && | ||
139 | (!skb->dev || skb->dev->features & NETIF_F_V6_CSUM)) { | ||
140 | skb->ip_summed = CHECKSUM_PARTIAL; | ||
141 | skb->csum_start = skb_headroom(skb) + | ||
142 | skb_network_offset(skb) + | ||
143 | (data - (void *)skb->data); | ||
144 | skb->csum_offset = (void *)check - data; | ||
145 | *check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, | ||
146 | datalen, proto, 0); | ||
147 | } else { | ||
148 | *check = 0; | ||
149 | *check = csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, | ||
150 | datalen, proto, | ||
151 | csum_partial(data, datalen, | ||
152 | 0)); | ||
153 | if (proto == IPPROTO_UDP && !*check) | ||
154 | *check = CSUM_MANGLED_0; | ||
155 | } | ||
156 | } else | ||
157 | inet_proto_csum_replace2(check, skb, | ||
158 | htons(oldlen), htons(datalen), 1); | ||
159 | } | ||
160 | |||
161 | static int nf_nat_ipv6_nlattr_to_range(struct nlattr *tb[], | ||
162 | struct nf_nat_range *range) | ||
163 | { | ||
164 | if (tb[CTA_NAT_V6_MINIP]) { | ||
165 | nla_memcpy(&range->min_addr.ip6, tb[CTA_NAT_V6_MINIP], | ||
166 | sizeof(struct in6_addr)); | ||
167 | range->flags |= NF_NAT_RANGE_MAP_IPS; | ||
168 | } | ||
169 | |||
170 | if (tb[CTA_NAT_V6_MAXIP]) | ||
171 | nla_memcpy(&range->max_addr.ip6, tb[CTA_NAT_V6_MAXIP], | ||
172 | sizeof(struct in6_addr)); | ||
173 | else | ||
174 | range->max_addr = range->min_addr; | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static const struct nf_nat_l3proto nf_nat_l3proto_ipv6 = { | ||
180 | .l3proto = NFPROTO_IPV6, | ||
181 | .secure_port = nf_nat_ipv6_secure_port, | ||
182 | .in_range = nf_nat_ipv6_in_range, | ||
183 | .manip_pkt = nf_nat_ipv6_manip_pkt, | ||
184 | .csum_update = nf_nat_ipv6_csum_update, | ||
185 | .csum_recalc = nf_nat_ipv6_csum_recalc, | ||
186 | .nlattr_to_range = nf_nat_ipv6_nlattr_to_range, | ||
187 | #ifdef CONFIG_XFRM | ||
188 | .decode_session = nf_nat_ipv6_decode_session, | ||
189 | #endif | ||
190 | }; | ||
191 | |||
192 | int nf_nat_icmpv6_reply_translation(struct sk_buff *skb, | ||
193 | struct nf_conn *ct, | ||
194 | enum ip_conntrack_info ctinfo, | ||
195 | unsigned int hooknum, | ||
196 | unsigned int hdrlen) | ||
197 | { | ||
198 | struct { | ||
199 | struct icmp6hdr icmp6; | ||
200 | struct ipv6hdr ip6; | ||
201 | } *inside; | ||
202 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
203 | enum nf_nat_manip_type manip = HOOK2MANIP(hooknum); | ||
204 | const struct nf_nat_l4proto *l4proto; | ||
205 | struct nf_conntrack_tuple target; | ||
206 | unsigned long statusbit; | ||
207 | |||
208 | NF_CT_ASSERT(ctinfo == IP_CT_RELATED || ctinfo == IP_CT_RELATED_REPLY); | ||
209 | |||
210 | if (!skb_make_writable(skb, hdrlen + sizeof(*inside))) | ||
211 | return 0; | ||
212 | if (nf_ip6_checksum(skb, hooknum, hdrlen, IPPROTO_ICMPV6)) | ||
213 | return 0; | ||
214 | |||
215 | inside = (void *)skb->data + hdrlen; | ||
216 | if (inside->icmp6.icmp6_type == NDISC_REDIRECT) { | ||
217 | if ((ct->status & IPS_NAT_DONE_MASK) != IPS_NAT_DONE_MASK) | ||
218 | return 0; | ||
219 | if (ct->status & IPS_NAT_MASK) | ||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | if (manip == NF_NAT_MANIP_SRC) | ||
224 | statusbit = IPS_SRC_NAT; | ||
225 | else | ||
226 | statusbit = IPS_DST_NAT; | ||
227 | |||
228 | /* Invert if this is reply direction */ | ||
229 | if (dir == IP_CT_DIR_REPLY) | ||
230 | statusbit ^= IPS_NAT_MASK; | ||
231 | |||
232 | if (!(ct->status & statusbit)) | ||
233 | return 1; | ||
234 | |||
235 | l4proto = __nf_nat_l4proto_find(NFPROTO_IPV6, inside->ip6.nexthdr); | ||
236 | if (!nf_nat_ipv6_manip_pkt(skb, hdrlen + sizeof(inside->icmp6), | ||
237 | l4proto, &ct->tuplehash[!dir].tuple, !manip)) | ||
238 | return 0; | ||
239 | |||
240 | if (skb->ip_summed != CHECKSUM_PARTIAL) { | ||
241 | struct ipv6hdr *ipv6h = ipv6_hdr(skb); | ||
242 | inside = (void *)skb->data + hdrlen; | ||
243 | inside->icmp6.icmp6_cksum = 0; | ||
244 | inside->icmp6.icmp6_cksum = | ||
245 | csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, | ||
246 | skb->len - hdrlen, IPPROTO_ICMPV6, | ||
247 | csum_partial(&inside->icmp6, | ||
248 | skb->len - hdrlen, 0)); | ||
249 | } | ||
250 | |||
251 | nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple); | ||
252 | l4proto = __nf_nat_l4proto_find(NFPROTO_IPV6, IPPROTO_ICMPV6); | ||
253 | if (!nf_nat_ipv6_manip_pkt(skb, 0, l4proto, &target, manip)) | ||
254 | return 0; | ||
255 | |||
256 | return 1; | ||
257 | } | ||
258 | EXPORT_SYMBOL_GPL(nf_nat_icmpv6_reply_translation); | ||
259 | |||
260 | static int __init nf_nat_l3proto_ipv6_init(void) | ||
261 | { | ||
262 | int err; | ||
263 | |||
264 | err = nf_nat_l4proto_register(NFPROTO_IPV6, &nf_nat_l4proto_icmpv6); | ||
265 | if (err < 0) | ||
266 | goto err1; | ||
267 | err = nf_nat_l3proto_register(&nf_nat_l3proto_ipv6); | ||
268 | if (err < 0) | ||
269 | goto err2; | ||
270 | return err; | ||
271 | |||
272 | err2: | ||
273 | nf_nat_l4proto_unregister(NFPROTO_IPV6, &nf_nat_l4proto_icmpv6); | ||
274 | err1: | ||
275 | return err; | ||
276 | } | ||
277 | |||
278 | static void __exit nf_nat_l3proto_ipv6_exit(void) | ||
279 | { | ||
280 | nf_nat_l3proto_unregister(&nf_nat_l3proto_ipv6); | ||
281 | nf_nat_l4proto_unregister(NFPROTO_IPV6, &nf_nat_l4proto_icmpv6); | ||
282 | } | ||
283 | |||
284 | MODULE_LICENSE("GPL"); | ||
285 | MODULE_ALIAS("nf-nat-" __stringify(AF_INET6)); | ||
286 | |||
287 | module_init(nf_nat_l3proto_ipv6_init); | ||
288 | module_exit(nf_nat_l3proto_ipv6_exit); | ||
diff --git a/net/ipv6/netfilter/nf_nat_proto_icmpv6.c b/net/ipv6/netfilter/nf_nat_proto_icmpv6.c new file mode 100644 index 000000000000..5d6da784305b --- /dev/null +++ b/net/ipv6/netfilter/nf_nat_proto_icmpv6.c | |||
@@ -0,0 +1,90 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2011 Patrick Mchardy <kaber@trash.net> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * Based on Rusty Russell's IPv4 ICMP NAT code. Development of IPv6 | ||
9 | * NAT funded by Astaro. | ||
10 | */ | ||
11 | |||
12 | #include <linux/types.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/icmpv6.h> | ||
15 | |||
16 | #include <linux/netfilter.h> | ||
17 | #include <net/netfilter/nf_nat.h> | ||
18 | #include <net/netfilter/nf_nat_core.h> | ||
19 | #include <net/netfilter/nf_nat_l3proto.h> | ||
20 | #include <net/netfilter/nf_nat_l4proto.h> | ||
21 | |||
22 | static bool | ||
23 | icmpv6_in_range(const struct nf_conntrack_tuple *tuple, | ||
24 | enum nf_nat_manip_type maniptype, | ||
25 | const union nf_conntrack_man_proto *min, | ||
26 | const union nf_conntrack_man_proto *max) | ||
27 | { | ||
28 | return ntohs(tuple->src.u.icmp.id) >= ntohs(min->icmp.id) && | ||
29 | ntohs(tuple->src.u.icmp.id) <= ntohs(max->icmp.id); | ||
30 | } | ||
31 | |||
32 | static void | ||
33 | icmpv6_unique_tuple(const struct nf_nat_l3proto *l3proto, | ||
34 | struct nf_conntrack_tuple *tuple, | ||
35 | const struct nf_nat_range *range, | ||
36 | enum nf_nat_manip_type maniptype, | ||
37 | const struct nf_conn *ct) | ||
38 | { | ||
39 | static u16 id; | ||
40 | unsigned int range_size; | ||
41 | unsigned int i; | ||
42 | |||
43 | range_size = ntohs(range->max_proto.icmp.id) - | ||
44 | ntohs(range->min_proto.icmp.id) + 1; | ||
45 | |||
46 | if (!(range->flags & NF_NAT_RANGE_PROTO_SPECIFIED)) | ||
47 | range_size = 0xffff; | ||
48 | |||
49 | for (i = 0; ; ++id) { | ||
50 | tuple->src.u.icmp.id = htons(ntohs(range->min_proto.icmp.id) + | ||
51 | (id % range_size)); | ||
52 | if (++i == range_size || !nf_nat_used_tuple(tuple, ct)) | ||
53 | return; | ||
54 | } | ||
55 | } | ||
56 | |||
57 | static bool | ||
58 | icmpv6_manip_pkt(struct sk_buff *skb, | ||
59 | const struct nf_nat_l3proto *l3proto, | ||
60 | unsigned int iphdroff, unsigned int hdroff, | ||
61 | const struct nf_conntrack_tuple *tuple, | ||
62 | enum nf_nat_manip_type maniptype) | ||
63 | { | ||
64 | struct icmp6hdr *hdr; | ||
65 | |||
66 | if (!skb_make_writable(skb, hdroff + sizeof(*hdr))) | ||
67 | return false; | ||
68 | |||
69 | hdr = (struct icmp6hdr *)(skb->data + hdroff); | ||
70 | l3proto->csum_update(skb, iphdroff, &hdr->icmp6_cksum, | ||
71 | tuple, maniptype); | ||
72 | if (hdr->icmp6_code == ICMPV6_ECHO_REQUEST || | ||
73 | hdr->icmp6_code == ICMPV6_ECHO_REPLY) { | ||
74 | inet_proto_csum_replace2(&hdr->icmp6_cksum, skb, | ||
75 | hdr->icmp6_identifier, | ||
76 | tuple->src.u.icmp.id, 0); | ||
77 | hdr->icmp6_identifier = tuple->src.u.icmp.id; | ||
78 | } | ||
79 | return true; | ||
80 | } | ||
81 | |||
82 | const struct nf_nat_l4proto nf_nat_l4proto_icmpv6 = { | ||
83 | .l4proto = IPPROTO_ICMPV6, | ||
84 | .manip_pkt = icmpv6_manip_pkt, | ||
85 | .in_range = icmpv6_in_range, | ||
86 | .unique_tuple = icmpv6_unique_tuple, | ||
87 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | ||
88 | .nlattr_to_range = nf_nat_l4proto_nlattr_to_range, | ||
89 | #endif | ||
90 | }; | ||
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index ef0579d5bca6..7af88ef01657 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -1251,7 +1251,8 @@ static void raw6_sock_seq_show(struct seq_file *seq, struct sock *sp, int i) | |||
1251 | sk_wmem_alloc_get(sp), | 1251 | sk_wmem_alloc_get(sp), |
1252 | sk_rmem_alloc_get(sp), | 1252 | sk_rmem_alloc_get(sp), |
1253 | 0, 0L, 0, | 1253 | 0, 0L, 0, |
1254 | sock_i_uid(sp), 0, | 1254 | from_kuid_munged(seq_user_ns(seq), sock_i_uid(sp)), |
1255 | 0, | ||
1255 | sock_i_ino(sp), | 1256 | sock_i_ino(sp), |
1256 | atomic_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_drops)); | 1257 | atomic_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_drops)); |
1257 | } | 1258 | } |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 8e80fd279100..83dafa528936 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -222,7 +222,7 @@ static const u32 ip6_template_metrics[RTAX_MAX] = { | |||
222 | [RTAX_HOPLIMIT - 1] = 255, | 222 | [RTAX_HOPLIMIT - 1] = 255, |
223 | }; | 223 | }; |
224 | 224 | ||
225 | static struct rt6_info ip6_null_entry_template = { | 225 | static const struct rt6_info ip6_null_entry_template = { |
226 | .dst = { | 226 | .dst = { |
227 | .__refcnt = ATOMIC_INIT(1), | 227 | .__refcnt = ATOMIC_INIT(1), |
228 | .__use = 1, | 228 | .__use = 1, |
@@ -242,7 +242,7 @@ static struct rt6_info ip6_null_entry_template = { | |||
242 | static int ip6_pkt_prohibit(struct sk_buff *skb); | 242 | static int ip6_pkt_prohibit(struct sk_buff *skb); |
243 | static int ip6_pkt_prohibit_out(struct sk_buff *skb); | 243 | static int ip6_pkt_prohibit_out(struct sk_buff *skb); |
244 | 244 | ||
245 | static struct rt6_info ip6_prohibit_entry_template = { | 245 | static const struct rt6_info ip6_prohibit_entry_template = { |
246 | .dst = { | 246 | .dst = { |
247 | .__refcnt = ATOMIC_INIT(1), | 247 | .__refcnt = ATOMIC_INIT(1), |
248 | .__use = 1, | 248 | .__use = 1, |
@@ -257,7 +257,7 @@ static struct rt6_info ip6_prohibit_entry_template = { | |||
257 | .rt6i_ref = ATOMIC_INIT(1), | 257 | .rt6i_ref = ATOMIC_INIT(1), |
258 | }; | 258 | }; |
259 | 259 | ||
260 | static struct rt6_info ip6_blk_hole_entry_template = { | 260 | static const struct rt6_info ip6_blk_hole_entry_template = { |
261 | .dst = { | 261 | .dst = { |
262 | .__refcnt = ATOMIC_INIT(1), | 262 | .__refcnt = ATOMIC_INIT(1), |
263 | .__use = 1, | 263 | .__use = 1, |
@@ -451,10 +451,9 @@ static void rt6_probe(struct rt6_info *rt) | |||
451 | * Router Reachability Probe MUST be rate-limited | 451 | * Router Reachability Probe MUST be rate-limited |
452 | * to no more than one per minute. | 452 | * to no more than one per minute. |
453 | */ | 453 | */ |
454 | rcu_read_lock(); | ||
455 | neigh = rt ? rt->n : NULL; | 454 | neigh = rt ? rt->n : NULL; |
456 | if (!neigh || (neigh->nud_state & NUD_VALID)) | 455 | if (!neigh || (neigh->nud_state & NUD_VALID)) |
457 | goto out; | 456 | return; |
458 | read_lock_bh(&neigh->lock); | 457 | read_lock_bh(&neigh->lock); |
459 | if (!(neigh->nud_state & NUD_VALID) && | 458 | if (!(neigh->nud_state & NUD_VALID) && |
460 | time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) { | 459 | time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) { |
@@ -470,8 +469,6 @@ static void rt6_probe(struct rt6_info *rt) | |||
470 | } else { | 469 | } else { |
471 | read_unlock_bh(&neigh->lock); | 470 | read_unlock_bh(&neigh->lock); |
472 | } | 471 | } |
473 | out: | ||
474 | rcu_read_unlock(); | ||
475 | } | 472 | } |
476 | #else | 473 | #else |
477 | static inline void rt6_probe(struct rt6_info *rt) | 474 | static inline void rt6_probe(struct rt6_info *rt) |
@@ -498,7 +495,6 @@ static inline int rt6_check_neigh(struct rt6_info *rt) | |||
498 | struct neighbour *neigh; | 495 | struct neighbour *neigh; |
499 | int m; | 496 | int m; |
500 | 497 | ||
501 | rcu_read_lock(); | ||
502 | neigh = rt->n; | 498 | neigh = rt->n; |
503 | if (rt->rt6i_flags & RTF_NONEXTHOP || | 499 | if (rt->rt6i_flags & RTF_NONEXTHOP || |
504 | !(rt->rt6i_flags & RTF_GATEWAY)) | 500 | !(rt->rt6i_flags & RTF_GATEWAY)) |
@@ -516,7 +512,6 @@ static inline int rt6_check_neigh(struct rt6_info *rt) | |||
516 | read_unlock_bh(&neigh->lock); | 512 | read_unlock_bh(&neigh->lock); |
517 | } else | 513 | } else |
518 | m = 0; | 514 | m = 0; |
519 | rcu_read_unlock(); | ||
520 | return m; | 515 | return m; |
521 | } | 516 | } |
522 | 517 | ||
@@ -965,7 +960,7 @@ struct dst_entry * ip6_route_output(struct net *net, const struct sock *sk, | |||
965 | { | 960 | { |
966 | int flags = 0; | 961 | int flags = 0; |
967 | 962 | ||
968 | fl6->flowi6_iif = net->loopback_dev->ifindex; | 963 | fl6->flowi6_iif = LOOPBACK_IFINDEX; |
969 | 964 | ||
970 | if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr)) | 965 | if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr)) |
971 | flags |= RT6_LOOKUP_F_IFACE; | 966 | flags |= RT6_LOOKUP_F_IFACE; |
@@ -1463,8 +1458,21 @@ int ip6_route_add(struct fib6_config *cfg) | |||
1463 | } | 1458 | } |
1464 | rt->dst.output = ip6_pkt_discard_out; | 1459 | rt->dst.output = ip6_pkt_discard_out; |
1465 | rt->dst.input = ip6_pkt_discard; | 1460 | rt->dst.input = ip6_pkt_discard; |
1466 | rt->dst.error = -ENETUNREACH; | ||
1467 | rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP; | 1461 | rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP; |
1462 | switch (cfg->fc_type) { | ||
1463 | case RTN_BLACKHOLE: | ||
1464 | rt->dst.error = -EINVAL; | ||
1465 | break; | ||
1466 | case RTN_PROHIBIT: | ||
1467 | rt->dst.error = -EACCES; | ||
1468 | break; | ||
1469 | case RTN_THROW: | ||
1470 | rt->dst.error = -EAGAIN; | ||
1471 | break; | ||
1472 | default: | ||
1473 | rt->dst.error = -ENETUNREACH; | ||
1474 | break; | ||
1475 | } | ||
1468 | goto install_route; | 1476 | goto install_route; |
1469 | } | 1477 | } |
1470 | 1478 | ||
@@ -1829,7 +1837,7 @@ static struct rt6_info *rt6_get_route_info(struct net *net, | |||
1829 | if (!table) | 1837 | if (!table) |
1830 | return NULL; | 1838 | return NULL; |
1831 | 1839 | ||
1832 | write_lock_bh(&table->tb6_lock); | 1840 | read_lock_bh(&table->tb6_lock); |
1833 | fn = fib6_locate(&table->tb6_root, prefix ,prefixlen, NULL, 0); | 1841 | fn = fib6_locate(&table->tb6_root, prefix ,prefixlen, NULL, 0); |
1834 | if (!fn) | 1842 | if (!fn) |
1835 | goto out; | 1843 | goto out; |
@@ -1845,7 +1853,7 @@ static struct rt6_info *rt6_get_route_info(struct net *net, | |||
1845 | break; | 1853 | break; |
1846 | } | 1854 | } |
1847 | out: | 1855 | out: |
1848 | write_unlock_bh(&table->tb6_lock); | 1856 | read_unlock_bh(&table->tb6_lock); |
1849 | return rt; | 1857 | return rt; |
1850 | } | 1858 | } |
1851 | 1859 | ||
@@ -1861,7 +1869,7 @@ static struct rt6_info *rt6_add_route_info(struct net *net, | |||
1861 | .fc_dst_len = prefixlen, | 1869 | .fc_dst_len = prefixlen, |
1862 | .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO | | 1870 | .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO | |
1863 | RTF_UP | RTF_PREF(pref), | 1871 | RTF_UP | RTF_PREF(pref), |
1864 | .fc_nlinfo.pid = 0, | 1872 | .fc_nlinfo.portid = 0, |
1865 | .fc_nlinfo.nlh = NULL, | 1873 | .fc_nlinfo.nlh = NULL, |
1866 | .fc_nlinfo.nl_net = net, | 1874 | .fc_nlinfo.nl_net = net, |
1867 | }; | 1875 | }; |
@@ -1888,7 +1896,7 @@ struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_dev | |||
1888 | if (!table) | 1896 | if (!table) |
1889 | return NULL; | 1897 | return NULL; |
1890 | 1898 | ||
1891 | write_lock_bh(&table->tb6_lock); | 1899 | read_lock_bh(&table->tb6_lock); |
1892 | for (rt = table->tb6_root.leaf; rt; rt=rt->dst.rt6_next) { | 1900 | for (rt = table->tb6_root.leaf; rt; rt=rt->dst.rt6_next) { |
1893 | if (dev == rt->dst.dev && | 1901 | if (dev == rt->dst.dev && |
1894 | ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) && | 1902 | ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) && |
@@ -1897,7 +1905,7 @@ struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_dev | |||
1897 | } | 1905 | } |
1898 | if (rt) | 1906 | if (rt) |
1899 | dst_hold(&rt->dst); | 1907 | dst_hold(&rt->dst); |
1900 | write_unlock_bh(&table->tb6_lock); | 1908 | read_unlock_bh(&table->tb6_lock); |
1901 | return rt; | 1909 | return rt; |
1902 | } | 1910 | } |
1903 | 1911 | ||
@@ -1911,7 +1919,7 @@ struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr, | |||
1911 | .fc_ifindex = dev->ifindex, | 1919 | .fc_ifindex = dev->ifindex, |
1912 | .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | | 1920 | .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | |
1913 | RTF_UP | RTF_EXPIRES | RTF_PREF(pref), | 1921 | RTF_UP | RTF_EXPIRES | RTF_PREF(pref), |
1914 | .fc_nlinfo.pid = 0, | 1922 | .fc_nlinfo.portid = 0, |
1915 | .fc_nlinfo.nlh = NULL, | 1923 | .fc_nlinfo.nlh = NULL, |
1916 | .fc_nlinfo.nl_net = dev_net(dev), | 1924 | .fc_nlinfo.nl_net = dev_net(dev), |
1917 | }; | 1925 | }; |
@@ -2261,14 +2269,18 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
2261 | cfg->fc_src_len = rtm->rtm_src_len; | 2269 | cfg->fc_src_len = rtm->rtm_src_len; |
2262 | cfg->fc_flags = RTF_UP; | 2270 | cfg->fc_flags = RTF_UP; |
2263 | cfg->fc_protocol = rtm->rtm_protocol; | 2271 | cfg->fc_protocol = rtm->rtm_protocol; |
2272 | cfg->fc_type = rtm->rtm_type; | ||
2264 | 2273 | ||
2265 | if (rtm->rtm_type == RTN_UNREACHABLE) | 2274 | if (rtm->rtm_type == RTN_UNREACHABLE || |
2275 | rtm->rtm_type == RTN_BLACKHOLE || | ||
2276 | rtm->rtm_type == RTN_PROHIBIT || | ||
2277 | rtm->rtm_type == RTN_THROW) | ||
2266 | cfg->fc_flags |= RTF_REJECT; | 2278 | cfg->fc_flags |= RTF_REJECT; |
2267 | 2279 | ||
2268 | if (rtm->rtm_type == RTN_LOCAL) | 2280 | if (rtm->rtm_type == RTN_LOCAL) |
2269 | cfg->fc_flags |= RTF_LOCAL; | 2281 | cfg->fc_flags |= RTF_LOCAL; |
2270 | 2282 | ||
2271 | cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid; | 2283 | cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid; |
2272 | cfg->fc_nlinfo.nlh = nlh; | 2284 | cfg->fc_nlinfo.nlh = nlh; |
2273 | cfg->fc_nlinfo.nl_net = sock_net(skb->sk); | 2285 | cfg->fc_nlinfo.nl_net = sock_net(skb->sk); |
2274 | 2286 | ||
@@ -2359,7 +2371,7 @@ static inline size_t rt6_nlmsg_size(void) | |||
2359 | static int rt6_fill_node(struct net *net, | 2371 | static int rt6_fill_node(struct net *net, |
2360 | struct sk_buff *skb, struct rt6_info *rt, | 2372 | struct sk_buff *skb, struct rt6_info *rt, |
2361 | struct in6_addr *dst, struct in6_addr *src, | 2373 | struct in6_addr *dst, struct in6_addr *src, |
2362 | int iif, int type, u32 pid, u32 seq, | 2374 | int iif, int type, u32 portid, u32 seq, |
2363 | int prefix, int nowait, unsigned int flags) | 2375 | int prefix, int nowait, unsigned int flags) |
2364 | { | 2376 | { |
2365 | struct rtmsg *rtm; | 2377 | struct rtmsg *rtm; |
@@ -2375,7 +2387,7 @@ static int rt6_fill_node(struct net *net, | |||
2375 | } | 2387 | } |
2376 | } | 2388 | } |
2377 | 2389 | ||
2378 | nlh = nlmsg_put(skb, pid, seq, type, sizeof(*rtm), flags); | 2390 | nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags); |
2379 | if (!nlh) | 2391 | if (!nlh) |
2380 | return -EMSGSIZE; | 2392 | return -EMSGSIZE; |
2381 | 2393 | ||
@@ -2391,8 +2403,22 @@ static int rt6_fill_node(struct net *net, | |||
2391 | rtm->rtm_table = table; | 2403 | rtm->rtm_table = table; |
2392 | if (nla_put_u32(skb, RTA_TABLE, table)) | 2404 | if (nla_put_u32(skb, RTA_TABLE, table)) |
2393 | goto nla_put_failure; | 2405 | goto nla_put_failure; |
2394 | if (rt->rt6i_flags & RTF_REJECT) | 2406 | if (rt->rt6i_flags & RTF_REJECT) { |
2395 | rtm->rtm_type = RTN_UNREACHABLE; | 2407 | switch (rt->dst.error) { |
2408 | case -EINVAL: | ||
2409 | rtm->rtm_type = RTN_BLACKHOLE; | ||
2410 | break; | ||
2411 | case -EACCES: | ||
2412 | rtm->rtm_type = RTN_PROHIBIT; | ||
2413 | break; | ||
2414 | case -EAGAIN: | ||
2415 | rtm->rtm_type = RTN_THROW; | ||
2416 | break; | ||
2417 | default: | ||
2418 | rtm->rtm_type = RTN_UNREACHABLE; | ||
2419 | break; | ||
2420 | } | ||
2421 | } | ||
2396 | else if (rt->rt6i_flags & RTF_LOCAL) | 2422 | else if (rt->rt6i_flags & RTF_LOCAL) |
2397 | rtm->rtm_type = RTN_LOCAL; | 2423 | rtm->rtm_type = RTN_LOCAL; |
2398 | else if (rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK)) | 2424 | else if (rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK)) |
@@ -2465,15 +2491,11 @@ static int rt6_fill_node(struct net *net, | |||
2465 | if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0) | 2491 | if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0) |
2466 | goto nla_put_failure; | 2492 | goto nla_put_failure; |
2467 | 2493 | ||
2468 | rcu_read_lock(); | ||
2469 | n = rt->n; | 2494 | n = rt->n; |
2470 | if (n) { | 2495 | if (n) { |
2471 | if (nla_put(skb, RTA_GATEWAY, 16, &n->primary_key) < 0) { | 2496 | if (nla_put(skb, RTA_GATEWAY, 16, &n->primary_key) < 0) |
2472 | rcu_read_unlock(); | ||
2473 | goto nla_put_failure; | 2497 | goto nla_put_failure; |
2474 | } | ||
2475 | } | 2498 | } |
2476 | rcu_read_unlock(); | ||
2477 | 2499 | ||
2478 | if (rt->dst.dev && | 2500 | if (rt->dst.dev && |
2479 | nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex)) | 2501 | nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex)) |
@@ -2506,7 +2528,7 @@ int rt6_dump_route(struct rt6_info *rt, void *p_arg) | |||
2506 | 2528 | ||
2507 | return rt6_fill_node(arg->net, | 2529 | return rt6_fill_node(arg->net, |
2508 | arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE, | 2530 | arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE, |
2509 | NETLINK_CB(arg->cb->skb).pid, arg->cb->nlh->nlmsg_seq, | 2531 | NETLINK_CB(arg->cb->skb).portid, arg->cb->nlh->nlmsg_seq, |
2510 | prefix, 0, NLM_F_MULTI); | 2532 | prefix, 0, NLM_F_MULTI); |
2511 | } | 2533 | } |
2512 | 2534 | ||
@@ -2586,14 +2608,14 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void | |||
2586 | skb_dst_set(skb, &rt->dst); | 2608 | skb_dst_set(skb, &rt->dst); |
2587 | 2609 | ||
2588 | err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif, | 2610 | err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif, |
2589 | RTM_NEWROUTE, NETLINK_CB(in_skb).pid, | 2611 | RTM_NEWROUTE, NETLINK_CB(in_skb).portid, |
2590 | nlh->nlmsg_seq, 0, 0, 0); | 2612 | nlh->nlmsg_seq, 0, 0, 0); |
2591 | if (err < 0) { | 2613 | if (err < 0) { |
2592 | kfree_skb(skb); | 2614 | kfree_skb(skb); |
2593 | goto errout; | 2615 | goto errout; |
2594 | } | 2616 | } |
2595 | 2617 | ||
2596 | err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).pid); | 2618 | err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid); |
2597 | errout: | 2619 | errout: |
2598 | return err; | 2620 | return err; |
2599 | } | 2621 | } |
@@ -2613,14 +2635,14 @@ void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info) | |||
2613 | goto errout; | 2635 | goto errout; |
2614 | 2636 | ||
2615 | err = rt6_fill_node(net, skb, rt, NULL, NULL, 0, | 2637 | err = rt6_fill_node(net, skb, rt, NULL, NULL, 0, |
2616 | event, info->pid, seq, 0, 0, 0); | 2638 | event, info->portid, seq, 0, 0, 0); |
2617 | if (err < 0) { | 2639 | if (err < 0) { |
2618 | /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */ | 2640 | /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */ |
2619 | WARN_ON(err == -EMSGSIZE); | 2641 | WARN_ON(err == -EMSGSIZE); |
2620 | kfree_skb(skb); | 2642 | kfree_skb(skb); |
2621 | goto errout; | 2643 | goto errout; |
2622 | } | 2644 | } |
2623 | rtnl_notify(skb, net, info->pid, RTNLGRP_IPV6_ROUTE, | 2645 | rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE, |
2624 | info->nlh, gfp_any()); | 2646 | info->nlh, gfp_any()); |
2625 | return; | 2647 | return; |
2626 | errout: | 2648 | errout: |
@@ -2675,14 +2697,12 @@ static int rt6_info_route(struct rt6_info *rt, void *p_arg) | |||
2675 | #else | 2697 | #else |
2676 | seq_puts(m, "00000000000000000000000000000000 00 "); | 2698 | seq_puts(m, "00000000000000000000000000000000 00 "); |
2677 | #endif | 2699 | #endif |
2678 | rcu_read_lock(); | ||
2679 | n = rt->n; | 2700 | n = rt->n; |
2680 | if (n) { | 2701 | if (n) { |
2681 | seq_printf(m, "%pi6", n->primary_key); | 2702 | seq_printf(m, "%pi6", n->primary_key); |
2682 | } else { | 2703 | } else { |
2683 | seq_puts(m, "00000000000000000000000000000000"); | 2704 | seq_puts(m, "00000000000000000000000000000000"); |
2684 | } | 2705 | } |
2685 | rcu_read_unlock(); | ||
2686 | seq_printf(m, " %08x %08x %08x %08x %8s\n", | 2706 | seq_printf(m, " %08x %08x %08x %08x %8s\n", |
2687 | rt->rt6i_metric, atomic_read(&rt->dst.__refcnt), | 2707 | rt->rt6i_metric, atomic_read(&rt->dst.__refcnt), |
2688 | rt->dst.__use, rt->rt6i_flags, | 2708 | rt->dst.__use, rt->rt6i_flags, |
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index bb46061c813a..182ab9a85d6c 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c | |||
@@ -190,6 +190,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
190 | ireq = inet_rsk(req); | 190 | ireq = inet_rsk(req); |
191 | ireq6 = inet6_rsk(req); | 191 | ireq6 = inet6_rsk(req); |
192 | treq = tcp_rsk(req); | 192 | treq = tcp_rsk(req); |
193 | treq->listener = NULL; | ||
193 | 194 | ||
194 | if (security_inet_conn_request(sk, skb, req)) | 195 | if (security_inet_conn_request(sk, skb, req)) |
195 | goto out_free; | 196 | goto out_free; |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index acd32e3f1b68..f3bfb8bbfdec 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -476,7 +476,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst, | |||
476 | if (!dst && (dst = inet6_csk_route_req(sk, fl6, req)) == NULL) | 476 | if (!dst && (dst = inet6_csk_route_req(sk, fl6, req)) == NULL) |
477 | goto done; | 477 | goto done; |
478 | 478 | ||
479 | skb = tcp_make_synack(sk, dst, req, rvp); | 479 | skb = tcp_make_synack(sk, dst, req, rvp, NULL); |
480 | 480 | ||
481 | if (skb) { | 481 | if (skb) { |
482 | __tcp_v6_send_check(skb, &treq->loc_addr, &treq->rmt_addr); | 482 | __tcp_v6_send_check(skb, &treq->loc_addr, &treq->rmt_addr); |
@@ -988,7 +988,7 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) | |||
988 | &ipv6_hdr(skb)->saddr, | 988 | &ipv6_hdr(skb)->saddr, |
989 | &ipv6_hdr(skb)->daddr, inet6_iif(skb)); | 989 | &ipv6_hdr(skb)->daddr, inet6_iif(skb)); |
990 | if (req) | 990 | if (req) |
991 | return tcp_check_req(sk, skb, req, prev); | 991 | return tcp_check_req(sk, skb, req, prev, false); |
992 | 992 | ||
993 | nsk = __inet6_lookup_established(sock_net(sk), &tcp_hashinfo, | 993 | nsk = __inet6_lookup_established(sock_net(sk), &tcp_hashinfo, |
994 | &ipv6_hdr(skb)->saddr, th->source, | 994 | &ipv6_hdr(skb)->saddr, th->source, |
@@ -1180,6 +1180,7 @@ have_isn: | |||
1180 | want_cookie) | 1180 | want_cookie) |
1181 | goto drop_and_free; | 1181 | goto drop_and_free; |
1182 | 1182 | ||
1183 | tcp_rsk(req)->listener = NULL; | ||
1183 | inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); | 1184 | inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); |
1184 | return 0; | 1185 | return 0; |
1185 | 1186 | ||
@@ -1829,7 +1830,7 @@ static void tcp_v6_destroy_sock(struct sock *sk) | |||
1829 | #ifdef CONFIG_PROC_FS | 1830 | #ifdef CONFIG_PROC_FS |
1830 | /* Proc filesystem TCPv6 sock list dumping. */ | 1831 | /* Proc filesystem TCPv6 sock list dumping. */ |
1831 | static void get_openreq6(struct seq_file *seq, | 1832 | static void get_openreq6(struct seq_file *seq, |
1832 | const struct sock *sk, struct request_sock *req, int i, int uid) | 1833 | const struct sock *sk, struct request_sock *req, int i, kuid_t uid) |
1833 | { | 1834 | { |
1834 | int ttd = req->expires - jiffies; | 1835 | int ttd = req->expires - jiffies; |
1835 | const struct in6_addr *src = &inet6_rsk(req)->loc_addr; | 1836 | const struct in6_addr *src = &inet6_rsk(req)->loc_addr; |
@@ -1853,7 +1854,7 @@ static void get_openreq6(struct seq_file *seq, | |||
1853 | 1, /* timers active (only the expire timer) */ | 1854 | 1, /* timers active (only the expire timer) */ |
1854 | jiffies_to_clock_t(ttd), | 1855 | jiffies_to_clock_t(ttd), |
1855 | req->retrans, | 1856 | req->retrans, |
1856 | uid, | 1857 | from_kuid_munged(seq_user_ns(seq), uid), |
1857 | 0, /* non standard timer */ | 1858 | 0, /* non standard timer */ |
1858 | 0, /* open_requests have no inode */ | 1859 | 0, /* open_requests have no inode */ |
1859 | 0, req); | 1860 | 0, req); |
@@ -1901,9 +1902,9 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i) | |||
1901 | tp->write_seq-tp->snd_una, | 1902 | tp->write_seq-tp->snd_una, |
1902 | (sp->sk_state == TCP_LISTEN) ? sp->sk_ack_backlog : (tp->rcv_nxt - tp->copied_seq), | 1903 | (sp->sk_state == TCP_LISTEN) ? sp->sk_ack_backlog : (tp->rcv_nxt - tp->copied_seq), |
1903 | timer_active, | 1904 | timer_active, |
1904 | jiffies_to_clock_t(timer_expires - jiffies), | 1905 | jiffies_delta_to_clock_t(timer_expires - jiffies), |
1905 | icsk->icsk_retransmits, | 1906 | icsk->icsk_retransmits, |
1906 | sock_i_uid(sp), | 1907 | from_kuid_munged(seq_user_ns(seq), sock_i_uid(sp)), |
1907 | icsk->icsk_probes_out, | 1908 | icsk->icsk_probes_out, |
1908 | sock_i_ino(sp), | 1909 | sock_i_ino(sp), |
1909 | atomic_read(&sp->sk_refcnt), sp, | 1910 | atomic_read(&sp->sk_refcnt), sp, |
@@ -1921,10 +1922,7 @@ static void get_timewait6_sock(struct seq_file *seq, | |||
1921 | const struct in6_addr *dest, *src; | 1922 | const struct in6_addr *dest, *src; |
1922 | __u16 destp, srcp; | 1923 | __u16 destp, srcp; |
1923 | const struct inet6_timewait_sock *tw6 = inet6_twsk((struct sock *)tw); | 1924 | const struct inet6_timewait_sock *tw6 = inet6_twsk((struct sock *)tw); |
1924 | int ttd = tw->tw_ttd - jiffies; | 1925 | long delta = tw->tw_ttd - jiffies; |
1925 | |||
1926 | if (ttd < 0) | ||
1927 | ttd = 0; | ||
1928 | 1926 | ||
1929 | dest = &tw6->tw_v6_daddr; | 1927 | dest = &tw6->tw_v6_daddr; |
1930 | src = &tw6->tw_v6_rcv_saddr; | 1928 | src = &tw6->tw_v6_rcv_saddr; |
@@ -1940,7 +1938,7 @@ static void get_timewait6_sock(struct seq_file *seq, | |||
1940 | dest->s6_addr32[0], dest->s6_addr32[1], | 1938 | dest->s6_addr32[0], dest->s6_addr32[1], |
1941 | dest->s6_addr32[2], dest->s6_addr32[3], destp, | 1939 | dest->s6_addr32[2], dest->s6_addr32[3], destp, |
1942 | tw->tw_substate, 0, 0, | 1940 | tw->tw_substate, 0, 0, |
1943 | 3, jiffies_to_clock_t(ttd), 0, 0, 0, 0, | 1941 | 3, jiffies_delta_to_clock_t(delta), 0, 0, 0, 0, |
1944 | atomic_read(&tw->tw_refcnt), tw); | 1942 | atomic_read(&tw->tw_refcnt), tw); |
1945 | } | 1943 | } |
1946 | 1944 | ||
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 07e2bfef6845..fc9997260a6b 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -1469,7 +1469,8 @@ static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket | |||
1469 | sk_wmem_alloc_get(sp), | 1469 | sk_wmem_alloc_get(sp), |
1470 | sk_rmem_alloc_get(sp), | 1470 | sk_rmem_alloc_get(sp), |
1471 | 0, 0L, 0, | 1471 | 0, 0L, 0, |
1472 | sock_i_uid(sp), 0, | 1472 | from_kuid_munged(seq_user_ns(seq), sock_i_uid(sp)), |
1473 | 0, | ||
1473 | sock_i_ino(sp), | 1474 | sock_i_ino(sp), |
1474 | atomic_read(&sp->sk_refcnt), sp, | 1475 | atomic_read(&sp->sk_refcnt), sp, |
1475 | atomic_read(&sp->sk_drops)); | 1476 | atomic_read(&sp->sk_drops)); |