forked from mirrors/linux
		
	ipv6 addrconf: Implemented enhanced DAD (RFC7527)
Implemented RFC7527 Enhanced DAD.
IPv6 duplicate address detection can fail if there is some temporary
loopback of Ethernet frames. RFC7527 solves this by including a random
nonce in the NS messages used for DAD, and if an NS is received with the
same nonce it is assumed to be a looped back DAD probe and is ignored.
RFC7527 is enabled by default. Can be disabled by setting both of
conf/{all,interface}/enhanced_dad to zero.
Signed-off-by: Erik Nordmark <nordmark@arista.com>
Signed-off-by: Bob Gilligan <gilligan@arista.com>
Reviewed-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
			
			
This commit is contained in:
		
							parent
							
								
									ce84c7c663
								
							
						
					
					
						commit
						adc176c547
					
				
					 8 changed files with 64 additions and 6 deletions
				
			
		| 
						 | 
					@ -1734,6 +1734,15 @@ drop_unsolicited_na - BOOLEAN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	By default this is turned off.
 | 
						By default this is turned off.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enhanced_dad - BOOLEAN
 | 
				
			||||||
 | 
						Include a nonce option in the IPv6 neighbor solicitation messages used for
 | 
				
			||||||
 | 
						duplicate address detection per RFC7527. A received DAD NS will only signal
 | 
				
			||||||
 | 
						a duplicate address if the nonce is different. This avoids any false
 | 
				
			||||||
 | 
						detection of duplicates due to loopback of the NS messages that we send.
 | 
				
			||||||
 | 
						The nonce option will be sent on an interface unless both of
 | 
				
			||||||
 | 
						conf/{all,interface}/enhanced_dad are set to FALSE.
 | 
				
			||||||
 | 
						Default: TRUE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
icmp/*:
 | 
					icmp/*:
 | 
				
			||||||
ratelimit - INTEGER
 | 
					ratelimit - INTEGER
 | 
				
			||||||
	Limit the maximal rates for sending ICMPv6 packets.
 | 
						Limit the maximal rates for sending ICMPv6 packets.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -68,6 +68,7 @@ struct ipv6_devconf {
 | 
				
			||||||
#ifdef CONFIG_IPV6_SEG6_HMAC
 | 
					#ifdef CONFIG_IPV6_SEG6_HMAC
 | 
				
			||||||
	__s32		seg6_require_hmac;
 | 
						__s32		seg6_require_hmac;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
						__u32		enhanced_dad;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct ctl_table_header *sysctl_header;
 | 
						struct ctl_table_header *sysctl_header;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -55,6 +55,7 @@ struct inet6_ifaddr {
 | 
				
			||||||
	__u8			stable_privacy_retry;
 | 
						__u8			stable_privacy_retry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	__u16			scope;
 | 
						__u16			scope;
 | 
				
			||||||
 | 
						__u64			dad_nonce;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned long		cstamp;	/* created timestamp */
 | 
						unsigned long		cstamp;	/* created timestamp */
 | 
				
			||||||
	unsigned long		tstamp; /* updated timestamp */
 | 
						unsigned long		tstamp; /* updated timestamp */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,6 +31,7 @@ enum {
 | 
				
			||||||
	ND_OPT_PREFIX_INFO = 3,		/* RFC2461 */
 | 
						ND_OPT_PREFIX_INFO = 3,		/* RFC2461 */
 | 
				
			||||||
	ND_OPT_REDIRECT_HDR = 4,	/* RFC2461 */
 | 
						ND_OPT_REDIRECT_HDR = 4,	/* RFC2461 */
 | 
				
			||||||
	ND_OPT_MTU = 5,			/* RFC2461 */
 | 
						ND_OPT_MTU = 5,			/* RFC2461 */
 | 
				
			||||||
 | 
						ND_OPT_NONCE = 14,              /* RFC7527 */
 | 
				
			||||||
	__ND_OPT_ARRAY_MAX,
 | 
						__ND_OPT_ARRAY_MAX,
 | 
				
			||||||
	ND_OPT_ROUTE_INFO = 24,		/* RFC4191 */
 | 
						ND_OPT_ROUTE_INFO = 24,		/* RFC4191 */
 | 
				
			||||||
	ND_OPT_RDNSS = 25,		/* RFC5006 */
 | 
						ND_OPT_RDNSS = 25,		/* RFC5006 */
 | 
				
			||||||
| 
						 | 
					@ -121,6 +122,7 @@ struct ndisc_options {
 | 
				
			||||||
#define nd_opts_pi_end			nd_opt_array[__ND_OPT_PREFIX_INFO_END]
 | 
					#define nd_opts_pi_end			nd_opt_array[__ND_OPT_PREFIX_INFO_END]
 | 
				
			||||||
#define nd_opts_rh			nd_opt_array[ND_OPT_REDIRECT_HDR]
 | 
					#define nd_opts_rh			nd_opt_array[ND_OPT_REDIRECT_HDR]
 | 
				
			||||||
#define nd_opts_mtu			nd_opt_array[ND_OPT_MTU]
 | 
					#define nd_opts_mtu			nd_opt_array[ND_OPT_MTU]
 | 
				
			||||||
 | 
					#define nd_opts_nonce			nd_opt_array[ND_OPT_NONCE]
 | 
				
			||||||
#define nd_802154_opts_src_lladdr	nd_802154_opt_array[ND_OPT_SOURCE_LL_ADDR]
 | 
					#define nd_802154_opts_src_lladdr	nd_802154_opt_array[ND_OPT_SOURCE_LL_ADDR]
 | 
				
			||||||
#define nd_802154_opts_tgt_lladdr	nd_802154_opt_array[ND_OPT_TARGET_LL_ADDR]
 | 
					#define nd_802154_opts_tgt_lladdr	nd_802154_opt_array[ND_OPT_TARGET_LL_ADDR]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -398,7 +400,8 @@ void ndisc_cleanup(void);
 | 
				
			||||||
int ndisc_rcv(struct sk_buff *skb);
 | 
					int ndisc_rcv(struct sk_buff *skb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
 | 
					void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
 | 
				
			||||||
		   const struct in6_addr *daddr, const struct in6_addr *saddr);
 | 
							   const struct in6_addr *daddr, const struct in6_addr *saddr,
 | 
				
			||||||
 | 
							   u64 nonce);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ndisc_send_rs(struct net_device *dev,
 | 
					void ndisc_send_rs(struct net_device *dev,
 | 
				
			||||||
		   const struct in6_addr *saddr, const struct in6_addr *daddr);
 | 
							   const struct in6_addr *saddr, const struct in6_addr *daddr);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -181,6 +181,7 @@ enum {
 | 
				
			||||||
	DEVCONF_RTR_SOLICIT_MAX_INTERVAL,
 | 
						DEVCONF_RTR_SOLICIT_MAX_INTERVAL,
 | 
				
			||||||
	DEVCONF_SEG6_ENABLED,
 | 
						DEVCONF_SEG6_ENABLED,
 | 
				
			||||||
	DEVCONF_SEG6_REQUIRE_HMAC,
 | 
						DEVCONF_SEG6_REQUIRE_HMAC,
 | 
				
			||||||
 | 
						DEVCONF_ENHANCED_DAD,
 | 
				
			||||||
	DEVCONF_MAX
 | 
						DEVCONF_MAX
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -242,6 +242,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
 | 
				
			||||||
#ifdef CONFIG_IPV6_SEG6_HMAC
 | 
					#ifdef CONFIG_IPV6_SEG6_HMAC
 | 
				
			||||||
	.seg6_require_hmac	= 0,
 | 
						.seg6_require_hmac	= 0,
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
						.enhanced_dad           = 1,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
 | 
					static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
 | 
				
			||||||
| 
						 | 
					@ -292,6 +293,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
 | 
				
			||||||
#ifdef CONFIG_IPV6_SEG6_HMAC
 | 
					#ifdef CONFIG_IPV6_SEG6_HMAC
 | 
				
			||||||
	.seg6_require_hmac	= 0,
 | 
						.seg6_require_hmac	= 0,
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
						.enhanced_dad           = 1,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Check if a valid qdisc is available */
 | 
					/* Check if a valid qdisc is available */
 | 
				
			||||||
| 
						 | 
					@ -3735,12 +3737,21 @@ static void addrconf_dad_kick(struct inet6_ifaddr *ifp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned long rand_num;
 | 
						unsigned long rand_num;
 | 
				
			||||||
	struct inet6_dev *idev = ifp->idev;
 | 
						struct inet6_dev *idev = ifp->idev;
 | 
				
			||||||
 | 
						u64 nonce;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ifp->flags & IFA_F_OPTIMISTIC)
 | 
						if (ifp->flags & IFA_F_OPTIMISTIC)
 | 
				
			||||||
		rand_num = 0;
 | 
							rand_num = 0;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		rand_num = prandom_u32() % (idev->cnf.rtr_solicit_delay ? : 1);
 | 
							rand_num = prandom_u32() % (idev->cnf.rtr_solicit_delay ? : 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						nonce = 0;
 | 
				
			||||||
 | 
						if (idev->cnf.enhanced_dad ||
 | 
				
			||||||
 | 
						    dev_net(idev->dev)->ipv6.devconf_all->enhanced_dad) {
 | 
				
			||||||
 | 
							do
 | 
				
			||||||
 | 
								get_random_bytes(&nonce, 6);
 | 
				
			||||||
 | 
							while (nonce == 0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ifp->dad_nonce = nonce;
 | 
				
			||||||
	ifp->dad_probes = idev->cnf.dad_transmits;
 | 
						ifp->dad_probes = idev->cnf.dad_transmits;
 | 
				
			||||||
	addrconf_mod_dad_work(ifp, rand_num);
 | 
						addrconf_mod_dad_work(ifp, rand_num);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -3918,7 +3929,8 @@ static void addrconf_dad_work(struct work_struct *w)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* send a neighbour solicitation for our addr */
 | 
						/* send a neighbour solicitation for our addr */
 | 
				
			||||||
	addrconf_addr_solict_mult(&ifp->addr, &mcaddr);
 | 
						addrconf_addr_solict_mult(&ifp->addr, &mcaddr);
 | 
				
			||||||
	ndisc_send_ns(ifp->idev->dev, &ifp->addr, &mcaddr, &in6addr_any);
 | 
						ndisc_send_ns(ifp->idev->dev, &ifp->addr, &mcaddr, &in6addr_any,
 | 
				
			||||||
 | 
							      ifp->dad_nonce);
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	in6_ifa_put(ifp);
 | 
						in6_ifa_put(ifp);
 | 
				
			||||||
	rtnl_unlock();
 | 
						rtnl_unlock();
 | 
				
			||||||
| 
						 | 
					@ -4962,6 +4974,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
 | 
				
			||||||
#ifdef CONFIG_IPV6_SEG6_HMAC
 | 
					#ifdef CONFIG_IPV6_SEG6_HMAC
 | 
				
			||||||
	array[DEVCONF_SEG6_REQUIRE_HMAC] = cnf->seg6_require_hmac;
 | 
						array[DEVCONF_SEG6_REQUIRE_HMAC] = cnf->seg6_require_hmac;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
						array[DEVCONF_ENHANCED_DAD] = cnf->enhanced_dad;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline size_t inet6_ifla6_size(void)
 | 
					static inline size_t inet6_ifla6_size(void)
 | 
				
			||||||
| 
						 | 
					@ -6069,6 +6082,13 @@ static const struct ctl_table addrconf_sysctl[] = {
 | 
				
			||||||
		.proc_handler	= proc_dointvec,
 | 
							.proc_handler	= proc_dointvec,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.procname       = "enhanced_dad",
 | 
				
			||||||
 | 
							.data           = &ipv6_devconf.enhanced_dad,
 | 
				
			||||||
 | 
							.maxlen         = sizeof(int),
 | 
				
			||||||
 | 
							.mode           = 0644,
 | 
				
			||||||
 | 
							.proc_handler   = proc_dointvec,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		/* sentinel */
 | 
							/* sentinel */
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -233,6 +233,7 @@ struct ndisc_options *ndisc_parse_options(const struct net_device *dev,
 | 
				
			||||||
		case ND_OPT_SOURCE_LL_ADDR:
 | 
							case ND_OPT_SOURCE_LL_ADDR:
 | 
				
			||||||
		case ND_OPT_TARGET_LL_ADDR:
 | 
							case ND_OPT_TARGET_LL_ADDR:
 | 
				
			||||||
		case ND_OPT_MTU:
 | 
							case ND_OPT_MTU:
 | 
				
			||||||
 | 
							case ND_OPT_NONCE:
 | 
				
			||||||
		case ND_OPT_REDIRECT_HDR:
 | 
							case ND_OPT_REDIRECT_HDR:
 | 
				
			||||||
			if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
 | 
								if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
 | 
				
			||||||
				ND_PRINTK(2, warn,
 | 
									ND_PRINTK(2, warn,
 | 
				
			||||||
| 
						 | 
					@ -568,7 +569,8 @@ static void ndisc_send_unsol_na(struct net_device *dev)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
 | 
					void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
 | 
				
			||||||
		   const struct in6_addr *daddr, const struct in6_addr *saddr)
 | 
							   const struct in6_addr *daddr, const struct in6_addr *saddr,
 | 
				
			||||||
 | 
							   u64 nonce)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct sk_buff *skb;
 | 
						struct sk_buff *skb;
 | 
				
			||||||
	struct in6_addr addr_buf;
 | 
						struct in6_addr addr_buf;
 | 
				
			||||||
| 
						 | 
					@ -588,6 +590,8 @@ void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
 | 
				
			||||||
	if (inc_opt)
 | 
						if (inc_opt)
 | 
				
			||||||
		optlen += ndisc_opt_addr_space(dev,
 | 
							optlen += ndisc_opt_addr_space(dev,
 | 
				
			||||||
					       NDISC_NEIGHBOUR_SOLICITATION);
 | 
										       NDISC_NEIGHBOUR_SOLICITATION);
 | 
				
			||||||
 | 
						if (nonce != 0)
 | 
				
			||||||
 | 
							optlen += 8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
 | 
						skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
 | 
				
			||||||
	if (!skb)
 | 
						if (!skb)
 | 
				
			||||||
| 
						 | 
					@ -605,6 +609,13 @@ void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
 | 
				
			||||||
		ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
 | 
							ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
 | 
				
			||||||
				       dev->dev_addr,
 | 
									       dev->dev_addr,
 | 
				
			||||||
				       NDISC_NEIGHBOUR_SOLICITATION);
 | 
									       NDISC_NEIGHBOUR_SOLICITATION);
 | 
				
			||||||
 | 
						if (nonce != 0) {
 | 
				
			||||||
 | 
							u8 *opt = skb_put(skb, 8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							opt[0] = ND_OPT_NONCE;
 | 
				
			||||||
 | 
							opt[1] = 8 >> 3;
 | 
				
			||||||
 | 
							memcpy(opt + 2, &nonce, 6);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ndisc_send_skb(skb, daddr, saddr);
 | 
						ndisc_send_skb(skb, daddr, saddr);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -693,12 +704,12 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
 | 
				
			||||||
				  "%s: trying to ucast probe in NUD_INVALID: %pI6\n",
 | 
									  "%s: trying to ucast probe in NUD_INVALID: %pI6\n",
 | 
				
			||||||
				  __func__, target);
 | 
									  __func__, target);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ndisc_send_ns(dev, target, target, saddr);
 | 
							ndisc_send_ns(dev, target, target, saddr, 0);
 | 
				
			||||||
	} else if ((probes -= NEIGH_VAR(neigh->parms, APP_PROBES)) < 0) {
 | 
						} else if ((probes -= NEIGH_VAR(neigh->parms, APP_PROBES)) < 0) {
 | 
				
			||||||
		neigh_app_ns(neigh);
 | 
							neigh_app_ns(neigh);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		addrconf_addr_solict_mult(target, &mcaddr);
 | 
							addrconf_addr_solict_mult(target, &mcaddr);
 | 
				
			||||||
		ndisc_send_ns(dev, target, &mcaddr, saddr);
 | 
							ndisc_send_ns(dev, target, &mcaddr, saddr, 0);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -742,6 +753,7 @@ static void ndisc_recv_ns(struct sk_buff *skb)
 | 
				
			||||||
	int dad = ipv6_addr_any(saddr);
 | 
						int dad = ipv6_addr_any(saddr);
 | 
				
			||||||
	bool inc;
 | 
						bool inc;
 | 
				
			||||||
	int is_router = -1;
 | 
						int is_router = -1;
 | 
				
			||||||
 | 
						u64 nonce = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (skb->len < sizeof(struct nd_msg)) {
 | 
						if (skb->len < sizeof(struct nd_msg)) {
 | 
				
			||||||
		ND_PRINTK(2, warn, "NS: packet too short\n");
 | 
							ND_PRINTK(2, warn, "NS: packet too short\n");
 | 
				
			||||||
| 
						 | 
					@ -786,6 +798,8 @@ static void ndisc_recv_ns(struct sk_buff *skb)
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (ndopts.nd_opts_nonce)
 | 
				
			||||||
 | 
							memcpy(&nonce, (u8 *)(ndopts.nd_opts_nonce + 1), 6);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inc = ipv6_addr_is_multicast(daddr);
 | 
						inc = ipv6_addr_is_multicast(daddr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -794,6 +808,15 @@ static void ndisc_recv_ns(struct sk_buff *skb)
 | 
				
			||||||
have_ifp:
 | 
					have_ifp:
 | 
				
			||||||
		if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) {
 | 
							if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) {
 | 
				
			||||||
			if (dad) {
 | 
								if (dad) {
 | 
				
			||||||
 | 
									if (nonce != 0 && ifp->dad_nonce == nonce) {
 | 
				
			||||||
 | 
										u8 *np = (u8 *)&nonce;
 | 
				
			||||||
 | 
										/* Matching nonce if looped back */
 | 
				
			||||||
 | 
										ND_PRINTK(2, notice,
 | 
				
			||||||
 | 
											  "%s: IPv6 DAD loopback for address %pI6c nonce %pM ignored\n",
 | 
				
			||||||
 | 
											  ifp->idev->dev->name,
 | 
				
			||||||
 | 
											  &ifp->addr, np);
 | 
				
			||||||
 | 
										goto out;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
				/*
 | 
									/*
 | 
				
			||||||
				 * We are colliding with another node
 | 
									 * We are colliding with another node
 | 
				
			||||||
				 * who is doing DAD
 | 
									 * who is doing DAD
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -527,7 +527,7 @@ static void rt6_probe_deferred(struct work_struct *w)
 | 
				
			||||||
		container_of(w, struct __rt6_probe_work, work);
 | 
							container_of(w, struct __rt6_probe_work, work);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	addrconf_addr_solict_mult(&work->target, &mcaddr);
 | 
						addrconf_addr_solict_mult(&work->target, &mcaddr);
 | 
				
			||||||
	ndisc_send_ns(work->dev, &work->target, &mcaddr, NULL);
 | 
						ndisc_send_ns(work->dev, &work->target, &mcaddr, NULL, 0);
 | 
				
			||||||
	dev_put(work->dev);
 | 
						dev_put(work->dev);
 | 
				
			||||||
	kfree(work);
 | 
						kfree(work);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue