diff options
| -rw-r--r-- | include/net/ndisc.h | 7 | ||||
| -rw-r--r-- | net/ipv6/ndisc.c | 17 | 
2 files changed, 24 insertions, 0 deletions
diff --git a/include/net/ndisc.h b/include/net/ndisc.h index 7af1ea89303..23b3a7c5878 100644 --- a/include/net/ndisc.h +++ b/include/net/ndisc.h @@ -78,6 +78,13 @@ struct ra_msg {  	__be32			retrans_timer;  }; +struct rd_msg { +	struct icmp6hdr icmph; +	struct in6_addr	target; +	struct in6_addr	dest; +	__u8		opt[0]; +}; +  struct nd_opt_hdr {  	__u8		nd_opt_type;  	__u8		nd_opt_len; diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index f2a007b7bde..6574175795d 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1314,6 +1314,12 @@ out:  static void ndisc_redirect_rcv(struct sk_buff *skb)  { +	u8 *hdr; +	struct ndisc_options ndopts; +	struct rd_msg *msg = (struct rd_msg *)skb_transport_header(skb); +	u32 ndoptlen = skb->tail - (skb->transport_header + +				    offsetof(struct rd_msg, opt)); +  #ifdef CONFIG_IPV6_NDISC_NODETYPE  	switch (skb->ndisc_nodetype) {  	case NDISC_NODETYPE_HOST: @@ -1330,6 +1336,17 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)  		return;  	} +	if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) +		return; + +	if (!ndopts.nd_opts_rh) +		return; + +	hdr = (u8 *)ndopts.nd_opts_rh; +	hdr += 8; +	if (!pskb_pull(skb, hdr - skb_transport_header(skb))) +		return; +  	icmpv6_notify(skb, NDISC_REDIRECT, 0, 0);  }  |