aboutsummaryrefslogtreecommitdiff
path: root/net/ipv6
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/Kconfig10
-rw-r--r--net/ipv6/Makefile5
-rw-r--r--net/ipv6/addrconf.c240
-rw-r--r--net/ipv6/af_inet6.c88
-rw-r--r--net/ipv6/ah6.c34
-rw-r--r--net/ipv6/datagram.c63
-rw-r--r--net/ipv6/esp6.c52
-rw-r--r--net/ipv6/exthdrs.c118
-rw-r--r--net/ipv6/fib6_rules.c39
-rw-r--r--net/ipv6/icmp.c48
-rw-r--r--net/ipv6/ip6_fib.c4
-rw-r--r--net/ipv6/ip6_input.c18
-rw-r--r--net/ipv6/ip6_output.c187
-rw-r--r--net/ipv6/ip6_tunnel.c643
-rw-r--r--net/ipv6/ipcomp6.c16
-rw-r--r--net/ipv6/ipv6_sockglue.c46
-rw-r--r--net/ipv6/ipv6_syms.c36
-rw-r--r--net/ipv6/mcast.c46
-rw-r--r--net/ipv6/mip6.c62
-rw-r--r--net/ipv6/ndisc.c435
-rw-r--r--net/ipv6/netfilter.c8
-rw-r--r--net/ipv6/netfilter/ip6_queue.c28
-rw-r--r--net/ipv6/netfilter/ip6_tables.c17
-rw-r--r--net/ipv6/netfilter/ip6t_HL.c2
-rw-r--r--net/ipv6/netfilter/ip6t_LOG.c21
-rw-r--r--net/ipv6/netfilter/ip6t_REJECT.c11
-rw-r--r--net/ipv6/netfilter/ip6t_eui64.c8
-rw-r--r--net/ipv6/netfilter/ip6t_hl.c2
-rw-r--r--net/ipv6/netfilter/ip6t_ipv6header.c2
-rw-r--r--net/ipv6/netfilter/ip6table_filter.c2
-rw-r--r--net/ipv6/netfilter/ip6table_mangle.c18
-rw-r--r--net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c30
-rw-r--r--net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c7
-rw-r--r--net/ipv6/netfilter/nf_conntrack_reasm.c59
-rw-r--r--net/ipv6/proc.c61
-rw-r--r--net/ipv6/protocol.c4
-rw-r--r--net/ipv6/raw.c52
-rw-r--r--net/ipv6/reassembly.c62
-rw-r--r--net/ipv6/route.c24
-rw-r--r--net/ipv6/sit.c58
-rw-r--r--net/ipv6/tcp_ipv6.c120
-rw-r--r--net/ipv6/udp.c123
-rw-r--r--net/ipv6/udplite.c2
-rw-r--r--net/ipv6/xfrm6_input.c18
-rw-r--r--net/ipv6/xfrm6_mode_beet.c27
-rw-r--r--net/ipv6/xfrm6_mode_ro.c7
-rw-r--r--net/ipv6/xfrm6_mode_transport.c20
-rw-r--r--net/ipv6/xfrm6_mode_tunnel.c36
-rw-r--r--net/ipv6/xfrm6_output.c6
-rw-r--r--net/ipv6/xfrm6_policy.c25
-rw-r--r--net/ipv6/xfrm6_tunnel.c2
51 files changed, 1742 insertions, 1310 deletions
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index 79682efb14b..8e5d54f23b4 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -57,6 +57,16 @@ config IPV6_ROUTE_INFO
If unsure, say N.
+config IPV6_OPTIMISTIC_DAD
+ bool "IPv6: Enable RFC 4429 Optimistic DAD (EXPERIMENTAL)"
+ depends on IPV6 && EXPERIMENTAL
+ ---help---
+ This is experimental support for optimistic Duplicate
+ Address Detection. It allows for autoconfigured addresses
+ to be used more quickly.
+
+ If unsure, say N.
+
config INET6_AH
tristate "IPv6: AH transformation"
depends on IPV6
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index d460017bb35..bb33309044c 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile
@@ -7,14 +7,15 @@ obj-$(CONFIG_IPV6) += ipv6.o
ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \
route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o udplite.o \
raw.o protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
- exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \
- ip6_flowlabel.o ipv6_syms.o inet6_connection_sock.o
+ exthdrs.o sysctl_net_ipv6.o datagram.o \
+ ip6_flowlabel.o inet6_connection_sock.o
ipv6-$(CONFIG_XFRM) += xfrm6_policy.o xfrm6_state.o xfrm6_input.o \
xfrm6_output.o
ipv6-$(CONFIG_NETFILTER) += netfilter.o
ipv6-$(CONFIG_IPV6_MULTIPLE_TABLES) += fib6_rules.o
ipv6-$(CONFIG_IPV6_MIP6) += mip6.o
+ipv6-$(CONFIG_PROC_FS) += proc.o
ipv6-objs += $(ipv6-y)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 452a82ce479..e04e4937350 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -81,6 +81,7 @@
#endif
#include <asm/uaccess.h>
+#include <asm/unaligned.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
@@ -208,9 +209,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
};
/* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
-#if 0
const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
-#endif
const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
static void addrconf_del_timer(struct inet6_ifaddr *ifp)
@@ -246,6 +245,37 @@ static void addrconf_mod_timer(struct inet6_ifaddr *ifp,
add_timer(&ifp->timer);
}
+static int snmp6_alloc_dev(struct inet6_dev *idev)
+{
+ int err = -ENOMEM;
+
+ if (!idev || !idev->dev)
+ return -EINVAL;
+
+ if (snmp_mib_init((void **)idev->stats.ipv6,
+ sizeof(struct ipstats_mib),
+ __alignof__(struct ipstats_mib)) < 0)
+ goto err_ip;
+ if (snmp_mib_init((void **)idev->stats.icmpv6,
+ sizeof(struct icmpv6_mib),
+ __alignof__(struct icmpv6_mib)) < 0)
+ goto err_icmp;
+
+ return 0;
+
+err_icmp:
+ snmp_mib_free((void **)idev->stats.ipv6);
+err_ip:
+ return err;
+}
+
+static int snmp6_free_dev(struct inet6_dev *idev)
+{
+ snmp_mib_free((void **)idev->stats.icmpv6);
+ snmp_mib_free((void **)idev->stats.ipv6);
+ return 0;
+}
+
/* Nobody refers to this device, we may destroy it. */
static void in6_dev_finish_destroy_rcu(struct rcu_head *head)
@@ -271,6 +301,8 @@ void in6_dev_finish_destroy(struct inet6_dev *idev)
call_rcu(&idev->rcu, in6_dev_finish_destroy_rcu);
}
+EXPORT_SYMBOL(in6_dev_finish_destroy);
+
static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
{
struct inet6_dev *ndev;
@@ -528,6 +560,16 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
ifa->rt = rt;
+ /*
+ * part one of RFC 4429, section 3.3
+ * We should not configure an address as
+ * optimistic if we do not yet know the link
+ * layer address of our nexhop router
+ */
+
+ if (rt->rt6i_nexthop == NULL)
+ ifa->flags &= ~IFA_F_OPTIMISTIC;
+
ifa->idev = idev;
in6_dev_hold(idev);
/* For caller */
@@ -704,6 +746,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i
int tmp_plen;
int ret = 0;
int max_addresses;
+ u32 addr_flags;
write_lock(&idev->lock);
if (ift) {
@@ -761,10 +804,17 @@ retry:
spin_unlock_bh(&ifp->lock);
write_unlock(&idev->lock);
+
+ addr_flags = IFA_F_TEMPORARY;
+ /* set in addrconf_prefix_rcv() */
+ if (ifp->flags & IFA_F_OPTIMISTIC)
+ addr_flags |= IFA_F_OPTIMISTIC;
+
ift = !max_addresses ||
ipv6_count_addresses(idev) < max_addresses ?
ipv6_add_addr(idev, &addr, tmp_plen,
- ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK, IFA_F_TEMPORARY) : NULL;
+ ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK,
+ addr_flags) : NULL;
if (!ift || IS_ERR(ift)) {
in6_ifa_put(ifp);
in6_dev_put(idev);
@@ -896,13 +946,14 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
* - Tentative Address (RFC2462 section 5.4)
* - A tentative address is not considered
* "assigned to an interface" in the traditional
- * sense.
+ * sense, unless it is also flagged as optimistic.
* - Candidate Source Address (section 4)
* - In any case, anycast addresses, multicast
* addresses, and the unspecified address MUST
* NOT be included in a candidate set.
*/
- if (ifa->flags & IFA_F_TENTATIVE)
+ if ((ifa->flags & IFA_F_TENTATIVE) &&
+ (!(ifa->flags & IFA_F_OPTIMISTIC)))
continue;
if (unlikely(score.addr_type == IPV6_ADDR_ANY ||
score.addr_type & IPV6_ADDR_MULTICAST)) {
@@ -961,15 +1012,17 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
}
}
- /* Rule 3: Avoid deprecated address */
+ /* Rule 3: Avoid deprecated and optimistic addresses */
if (hiscore.rule < 3) {
if (ipv6_saddr_preferred(hiscore.addr_type) ||
- !(ifa_result->flags & IFA_F_DEPRECATED))
+ (((ifa_result->flags &
+ (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)) == 0)))
hiscore.attrs |= IPV6_SADDR_SCORE_PREFERRED;
hiscore.rule++;
}
if (ipv6_saddr_preferred(score.addr_type) ||
- !(ifa->flags & IFA_F_DEPRECATED)) {
+ (((ifa_result->flags &
+ (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)) == 0))) {
score.attrs |= IPV6_SADDR_SCORE_PREFERRED;
if (!(hiscore.attrs & IPV6_SADDR_SCORE_PREFERRED)) {
score.rule = 3;
@@ -1107,8 +1160,10 @@ int ipv6_get_saddr(struct dst_entry *dst,
return ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL, daddr, saddr);
}
+EXPORT_SYMBOL(ipv6_get_saddr);
-int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr)
+int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,
+ unsigned char banned_flags)
{
struct inet6_dev *idev;
int err = -EADDRNOTAVAIL;
@@ -1119,7 +1174,7 @@ int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr)
read_lock_bh(&idev->lock);
for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
- if (ifp->scope == IFA_LINK && !(ifp->flags&IFA_F_TENTATIVE)) {
+ if (ifp->scope == IFA_LINK && !(ifp->flags & banned_flags)) {
ipv6_addr_copy(addr, &ifp->addr);
err = 0;
break;
@@ -1161,6 +1216,8 @@ int ipv6_chk_addr(struct in6_addr *addr, struct net_device *dev, int strict)
return ifp != NULL;
}
+EXPORT_SYMBOL(ipv6_chk_addr);
+
static
int ipv6_chk_same_addr(const struct in6_addr *addr, struct net_device *dev)
{
@@ -1669,6 +1726,13 @@ ok:
if (ifp == NULL && valid_lft) {
int max_addresses = in6_dev->cnf.max_addresses;
+ u32 addr_flags = 0;
+
+#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
+ if (in6_dev->cnf.optimistic_dad &&
+ !ipv6_devconf.forwarding)
+ addr_flags = IFA_F_OPTIMISTIC;
+#endif
/* Do not allow to create too much of autoconfigured
* addresses; this would be too easy way to crash kernel.
@@ -1676,7 +1740,8 @@ ok:
if (!max_addresses ||
ipv6_count_addresses(in6_dev) < max_addresses)
ifp = ipv6_add_addr(in6_dev, &addr, pinfo->prefix_len,
- addr_type&IPV6_ADDR_SCOPE_MASK, 0);
+ addr_type&IPV6_ADDR_SCOPE_MASK,
+ addr_flags);
if (!ifp || IS_ERR(ifp)) {
in6_dev_put(in6_dev);
@@ -1884,6 +1949,11 @@ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen,
addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev,
jiffies_to_clock_t(valid_lft * HZ), flags);
+ /*
+ * Note that section 3.1 of RFC 4429 indicates
+ * that the Optimistic flag should not be set for
+ * manually configured addresses
+ */
addrconf_dad_start(ifp, 0);
in6_ifa_put(ifp);
addrconf_verify(0);
@@ -2060,8 +2130,16 @@ static void init_loopback(struct net_device *dev)
static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr)
{
struct inet6_ifaddr * ifp;
+ u32 addr_flags = IFA_F_PERMANENT;
+
+#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
+ if (idev->cnf.optimistic_dad &&
+ !ipv6_devconf.forwarding)
+ addr_flags |= IFA_F_OPTIMISTIC;
+#endif
- ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, IFA_F_PERMANENT);
+
+ ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, addr_flags);
if (!IS_ERR(ifp)) {
addrconf_prefix_route(&ifp->addr, ifp->prefix_len, idev->dev, 0, 0);
addrconf_dad_start(ifp, 0);
@@ -2129,7 +2207,7 @@ ipv6_inherit_linklocal(struct inet6_dev *idev, struct net_device *link_dev)
{
struct in6_addr lladdr;
- if (!ipv6_get_lladdr(link_dev, &lladdr)) {
+ if (!ipv6_get_lladdr(link_dev, &lladdr, IFA_F_TENTATIVE)) {
addrconf_add_linklocal(idev, &lladdr);
return 0;
}
@@ -2240,7 +2318,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
default:
addrconf_dev_config(dev);
break;
- };
+ }
if (idev) {
if (run_pending)
addrconf_dad_run(idev);
@@ -2293,7 +2371,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
}
#endif
break;
- };
+ }
return NOTIFY_OK;
}
@@ -2474,7 +2552,11 @@ static void addrconf_dad_kick(struct inet6_ifaddr *ifp)
unsigned long rand_num;
struct inet6_dev *idev = ifp->idev;
- rand_num = net_random() % (idev->cnf.rtr_solicit_delay ? : 1);
+ if (ifp->flags & IFA_F_OPTIMISTIC)
+ rand_num = 0;
+ else
+ rand_num = net_random() % (idev->cnf.rtr_solicit_delay ? : 1);
+
ifp->probes = idev->cnf.dad_transmits;
addrconf_mod_timer(ifp, AC_DAD, rand_num);
}
@@ -2496,7 +2578,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)
if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||
!(ifp->flags&IFA_F_TENTATIVE) ||
ifp->flags & IFA_F_NODAD) {
- ifp->flags &= ~IFA_F_TENTATIVE;
+ ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC);
spin_unlock_bh(&ifp->lock);
read_unlock_bh(&idev->lock);
@@ -2516,6 +2598,14 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)
addrconf_dad_stop(ifp);
return;
}
+
+ /*
+ * Optimistic nodes can start receiving
+ * Frames right away
+ */
+ if(ifp->flags & IFA_F_OPTIMISTIC)
+ ip6_ins_rt(ifp->rt);
+
addrconf_dad_kick(ifp);
spin_unlock_bh(&ifp->lock);
out:
@@ -2540,7 +2630,7 @@ static void addrconf_dad_timer(unsigned long data)
* DAD was successful
*/
- ifp->flags &= ~IFA_F_TENTATIVE;
+ ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC);
spin_unlock_bh(&ifp->lock);
read_unlock_bh(&idev->lock);
@@ -3164,7 +3254,6 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
s_idx = cb->args[0];
s_ip_idx = ip_idx = cb->args[1];
- read_lock(&dev_base_lock);
for (dev = dev_base, idx = 0; dev; dev = dev->next, idx++) {
if (idx < s_idx)
@@ -3226,7 +3315,6 @@ done:
read_unlock_bh(&idev->lock);
in6_dev_put(idev);
}
- read_unlock(&dev_base_lock);
cb->args[0] = idx;
cb->args[1] = ip_idx;
return skb->len;
@@ -3359,6 +3447,9 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
#endif
array[DEVCONF_PROXY_NDP] = cnf->proxy_ndp;
array[DEVCONF_ACCEPT_SOURCE_ROUTE] = cnf->accept_source_route;
+#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
+ array[DEVCONF_OPTIMISTIC_DAD] = cnf->optimistic_dad;
+#endif
}
static inline size_t inet6_if_nlmsg_size(void)
@@ -3372,14 +3463,44 @@ static inline size_t inet6_if_nlmsg_size(void)
nla_total_size(4) /* IFLA_INET6_FLAGS */
+ nla_total_size(sizeof(struct ifla_cacheinfo))
+ nla_total_size(DEVCONF_MAX * 4) /* IFLA_INET6_CONF */
+ + nla_total_size(IPSTATS_MIB_MAX * 8) /* IFLA_INET6_STATS */
+ + nla_total_size(ICMP6_MIB_MAX * 8) /* IFLA_INET6_ICMP6STATS */
);
}
+static inline void __snmp6_fill_stats(u64 *stats, void **mib, int items,
+ int bytes)
+{
+ int i;
+ int pad = bytes - sizeof(u64) * items;
+ BUG_ON(pad < 0);
+
+ /* Use put_unaligned() because stats may not be aligned for u64. */
+ put_unaligned(items, &stats[0]);
+ for (i = 1; i < items; i++)
+ put_unaligned(snmp_fold_field(mib, i), &stats[i]);
+
+ memset(&stats[items], 0, pad);
+}
+
+static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype,
+ int bytes)
+{
+ switch(attrtype) {
+ case IFLA_INET6_STATS:
+ __snmp6_fill_stats(stats, (void **)idev->stats.ipv6, IPSTATS_MIB_MAX, bytes);
+ break;
+ case IFLA_INET6_ICMP6STATS:
+ __snmp6_fill_stats(stats, (void **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes);
+ break;
+ }
+}
+
static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,
u32 pid, u32 seq, int event, unsigned int flags)
{
struct net_device *dev = idev->dev;
- struct nlattr *conf;
+ struct nlattr *nla;
struct ifinfomsg *hdr;
struct nlmsghdr *nlh;
void *protoinfo;
@@ -3419,12 +3540,22 @@ static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,
ci.retrans_time = idev->nd_parms->retrans_time;
NLA_PUT(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci);
- conf = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32));
- if (conf == NULL)
+ nla = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32));
+ if (nla == NULL)
goto nla_put_failure;
- ipv6_store_devconf(&idev->cnf, nla_data(conf), nla_len(conf));
+ ipv6_store_devconf(&idev->cnf, nla_data(nla), nla_len(nla));
- /* XXX - Statistics/MC not implemented */
+ /* XXX - MC not implemented */
+
+ nla = nla_reserve(skb, IFLA_INET6_STATS, IPSTATS_MIB_MAX * sizeof(u64));
+ if (nla == NULL)
+ goto nla_put_failure;
+ snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_STATS, nla_len(nla));
+
+ nla = nla_reserve(skb, IFLA_INET6_ICMP6STATS, ICMP6_MIB_MAX * sizeof(u64));
+ if (nla == NULL)
+ goto nla_put_failure;
+ snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_ICMP6STATS, nla_len(nla));
nla_nest_end(skb, protoinfo);
return nlmsg_end(skb, nlh);
@@ -3550,30 +3681,20 @@ errout:
rtnl_set_sk_err(RTNLGRP_IPV6_PREFIX, err);
}
-static struct rtnetlink_link inet6_rtnetlink_table[RTM_NR_MSGTYPES] = {
- [RTM_GETLINK - RTM_BASE] = { .dumpit = inet6_dump_ifinfo, },
- [RTM_NEWADDR - RTM_BASE] = { .doit = inet6_rtm_newaddr, },
- [RTM_DELADDR - RTM_BASE] = { .doit = inet6_rtm_deladdr, },
- [RTM_GETADDR - RTM_BASE] = { .doit = inet6_rtm_getaddr,
- .dumpit = inet6_dump_ifaddr, },
- [RTM_GETMULTICAST - RTM_BASE] = { .dumpit = inet6_dump_ifmcaddr, },
- [RTM_GETANYCAST - RTM_BASE] = { .dumpit = inet6_dump_ifacaddr, },
- [RTM_NEWROUTE - RTM_BASE] = { .doit = inet6_rtm_newroute, },
- [RTM_DELROUTE - RTM_BASE] = { .doit = inet6_rtm_delroute, },
- [RTM_GETROUTE - RTM_BASE] = { .doit = inet6_rtm_getroute,
- .dumpit = inet6_dump_fib, },
-#ifdef CONFIG_IPV6_MULTIPLE_TABLES
- [RTM_GETRULE - RTM_BASE] = { .dumpit = fib6_rules_dump, },
-#endif
-};
-
static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
{
inet6_ifa_notify(event ? : RTM_NEWADDR, ifp);
switch (event) {
case RTM_NEWADDR:
- ip6_ins_rt(ifp->rt);
+ /*
+ * If the address was optimistic
+ * we inserted the route at the start of
+ * our DAD process, so we don't need
+ * to do it again
+ */
+ if (!(ifp->rt->rt6i_node))
+ ip6_ins_rt(ifp->rt);
if (ifp->idev->cnf.forwarding)
addrconf_join_anycast(ifp);
break;
@@ -3894,6 +4015,17 @@ static struct addrconf_sysctl_table
.mode = 0644,
.proc_handler = &proc_dointvec,
},
+#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "optimistic_dad",
+ .data = &ipv6_devconf.optimistic_dad,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+
+ },
+#endif
{
.ctl_name = 0, /* sentinel */
}
@@ -4021,11 +4153,15 @@ int register_inet6addr_notifier(struct notifier_block *nb)
return atomic_notifier_chain_register(&inet6addr_chain, nb);
}
+EXPORT_SYMBOL(register_inet6addr_notifier);
+
int unregister_inet6addr_notifier(struct notifier_block *nb)
{
return atomic_notifier_chain_unregister(&inet6addr_chain,nb);
}
+EXPORT_SYMBOL(unregister_inet6addr_notifier);
+
/*
* Init / cleanup code
*/
@@ -4064,7 +4200,18 @@ int __init addrconf_init(void)
register_netdevice_notifier(&ipv6_dev_notf);
addrconf_verify(0);
- rtnetlink_links[PF_INET6] = inet6_rtnetlink_table;
+
+ err = __rtnl_register(PF_INET6, RTM_GETLINK, NULL, inet6_dump_ifinfo);
+ if (err < 0)
+ goto errout;
+
+ /* Only the first call to __rtnl_register can fail */
+ __rtnl_register(PF_INET6, RTM_NEWADDR, inet6_rtm_newaddr, NULL);
+ __rtnl_register(PF_INET6, RTM_DELADDR, inet6_rtm_deladdr, NULL);
+ __rtnl_register(PF_INET6, RTM_GETADDR, inet6_rtm_getaddr, inet6_dump_ifaddr);
+ __rtnl_register(PF_INET6, RTM_GETMULTICAST, NULL, inet6_dump_ifmcaddr);
+ __rtnl_register(PF_INET6, RTM_GETANYCAST, NULL, inet6_dump_ifacaddr);
+
#ifdef CONFIG_SYSCTL
addrconf_sysctl.sysctl_header =
register_sysctl_table(addrconf_sysctl.addrconf_root_dir);
@@ -4072,6 +4219,10 @@ int __init addrconf_init(void)
#endif
return 0;
+errout:
+ unregister_netdevice_notifier(&ipv6_dev_notf);
+
+ return err;
}
void __exit addrconf_cleanup(void)
@@ -4083,7 +4234,6 @@ void __exit addrconf_cleanup(void)
unregister_netdevice_notifier(&ipv6_dev_notf);
- rtnetlink_links[PF_INET6] = NULL;
#ifdef CONFIG_SYSCTL
addrconf_sysctl_unregister(&ipv6_devconf_dflt);
addrconf_sysctl_unregister(&ipv6_devconf);
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 5cac14a5c77..18cb928c8d9 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -98,6 +98,11 @@ static int inet6_create(struct socket *sock, int protocol)
int try_loading_module = 0;
int err;
+ if (sock->type != SOCK_RAW &&
+ sock->type != SOCK_DGRAM &&
+ !inet_ehash_secret)
+ build_ehash_secret();
+
/* Look for the requested type/protocol pair. */
answer = NULL;
lookup_protocol:
@@ -349,6 +354,8 @@ out:
return err;
}
+EXPORT_SYMBOL(inet6_bind);
+
int inet6_release(struct socket *sock)
{
struct sock *sk = sock->sk;
@@ -365,6 +372,8 @@ int inet6_release(struct socket *sock)
return inet_release(sock);
}
+EXPORT_SYMBOL(inet6_release);
+
int inet6_destroy_sock(struct sock *sk)
{
struct ipv6_pinfo *np = inet6_sk(sk);
@@ -428,6 +437,8 @@ int inet6_getname(struct socket *sock, struct sockaddr *uaddr,
return(0);
}
+EXPORT_SYMBOL(inet6_getname);
+
int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
struct sock *sk = sock->sk;
@@ -437,6 +448,9 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case SIOCGSTAMP:
return sock_get_timestamp(sk, (struct timeval __user *)arg);
+ case SIOCGSTAMPNS:
+ return sock_get_timestampns(sk, (struct timespec __user *)arg);
+
case SIOCADDRT:
case SIOCDELRT:
@@ -457,6 +471,8 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
return(0);
}
+EXPORT_SYMBOL(inet6_ioctl);
+
const struct proto_ops inet6_stream_ops = {
.family = PF_INET6,
.owner = THIS_MODULE,
@@ -603,6 +619,8 @@ out_illegal:
goto out;
}
+EXPORT_SYMBOL(inet6_register_protosw);
+
void
inet6_unregister_protosw(struct inet_protosw *p)
{
@@ -619,6 +637,8 @@ inet6_unregister_protosw(struct inet_protosw *p)
}
}
+EXPORT_SYMBOL(inet6_unregister_protosw);
+
int inet6_sk_rebuild_header(struct sock *sk)
{
int err;
@@ -678,7 +698,8 @@ int ipv6_opt_accepted(struct sock *sk, struct sk_buff *skb)
if (np->rxopt.all) {
if ((opt->hop && (np->rxopt.bits.hopopts ||
np->rxopt.bits.ohopopts)) ||
- ((IPV6_FLOWINFO_MASK & *(__be32*)skb->nh.raw) &&
+ ((IPV6_FLOWINFO_MASK &
+ *(__be32 *)skb_network_header(skb)) &&
np->rxopt.bits.rxflow) ||
(opt->srcrt && (np->rxopt.bits.srcrt ||
np->rxopt.bits.osrcrt)) ||
@@ -691,61 +712,28 @@ int ipv6_opt_accepted(struct sock *sk, struct sk_buff *skb)
EXPORT_SYMBOL_GPL(ipv6_opt_accepted);
-int
-snmp6_mib_init(void *ptr[2], size_t mibsize, size_t mibalign)
-{
- if (ptr == NULL)
- return -EINVAL;
-
- ptr[0] = __alloc_percpu(mibsize);
- if (!ptr[0])
- goto err0;
-
- ptr[1] = __alloc_percpu(mibsize);
- if (!ptr[1])
- goto err1;
-
- return 0;
-
-err1:
- free_percpu(ptr[0]);
- ptr[0] = NULL;
-err0:
- return -ENOMEM;
-}
-
-void
-snmp6_mib_free(void *ptr[2])
-{
- if (ptr == NULL)
- return;
- free_percpu(ptr[0]);
- free_percpu(ptr[1]);
- ptr[0] = ptr[1] = NULL;
-}
-
static int __init init_ipv6_mibs(void)
{
- if (snmp6_mib_init((void **)ipv6_statistics, sizeof (struct ipstats_mib),
- __alignof__(struct ipstats_mib)) < 0)
+ if (snmp_mib_init((void **)ipv6_statistics, sizeof (struct ipstats_mib),
+ __alignof__(struct ipstats_mib)) < 0)
goto err_ip_mib;
- if (snmp6_mib_init((void **)icmpv6_statistics, sizeof (struct icmpv6_mib),
- __alignof__(struct icmpv6_mib)) < 0)
+ if (snmp_mib_init((void **)icmpv6_statistics, sizeof (struct icmpv6_mib),
+ __alignof__(struct icmpv6_mib)) < 0)
goto err_icmp_mib;
- if (snmp6_mib_init((void **)udp_stats_in6, sizeof (struct udp_mib),
- __alignof__(struct udp_mib)) < 0)
+ if (snmp_mib_init((void **)udp_stats_in6, sizeof (struct udp_mib),
+ __alignof__(struct udp_mib)) < 0)
goto err_udp_mib;
- if (snmp6_mib_init((void **)udplite_stats_in6, sizeof (struct udp_mib),
- __alignof__(struct udp_mib)) < 0)
+ if (snmp_mib_init((void **)udplite_stats_in6, sizeof (struct udp_mib),
+ __alignof__(struct udp_mib)) < 0)
goto err_udplite_mib;
return 0;
err_udplite_mib:
- snmp6_mib_free((void **)udp_stats_in6);
+ snmp_mib_free((void **)udp_stats_in6);
err_udp_mib:
- snmp6_mib_free((void **)icmpv6_statistics);
+ snmp_mib_free((void **)icmpv6_statistics);
err_icmp_mib:
- snmp6_mib_free((void **)ipv6_statistics);
+ snmp_mib_free((void **)ipv6_statistics);
err_ip_mib:
return -ENOMEM;
@@ -753,10 +741,10 @@ err_ip_mib:
static void cleanup_ipv6_mibs(void)