hello...
In mainline kernel there is support for two radios at86rf230 and mrf24j40. And
cc2420 radio support is there in outside tree. I am implementing the driver for
cc2520 radio. I will complete it soon...

The attached documents are patches for implementing the RFC6775. Please check
the patches and give me suggestions if any changes are required. I did not
submit these patches to the ipv6 linux community. After any suggestions from
linux-zigbee-devel i will submit my patches to ipv6-linux community.

Regards,
Bhadram
-------------------------------------------------------------------------------------------------------------------------------

This e-mail is for the sole use of the intended recipient(s) and may
contain confidential and privileged information. If you are not the
intended recipient, please contact the sender by reply e-mail and destroy
all copies and the original message. Any unauthorized review, use,
disclosure, dissemination, forwarding, printing or copying of this email
is strictly prohibited and appropriate legal action will be taken.
-------------------------------------------------------------------------------------------------------------------------------

--- a/net/ipv6/ndisc.c	2013-09-14 19:37:01.000000000 +0530
+++ b/net/ipv6/ndisc.c	2013-09-23 16:30:12.000000000 +0530
@@ -61,6 +61,8 @@
 #include <net/addrconf.h>
 #include <net/icmp.h>
 
+#include <net/af_ieee802154.h>   //ieee802154 address family header
+
 #include <net/netlink.h>
 #include <linux/rtnetlink.h>
 
@@ -164,6 +166,35 @@
 		memset(opt, 0, space);
 }
 
+static void ndisc_fill_tllao_option(struct sk_buff *skb,int type,void *addr)
+{	
+	int data_len = skb->dev->addr_len;
+
+	u8 *opt = (u8 *)skb_put(skb,data_len+2);
+
+	opt[0] = type;
+	opt[1] = data_len>>3;	//FIXME: It should represent in 8octets=1 format
+                              //but we are having 10octets : SO HOW WE CAN REPRESENT ?
+	memcpy(opt+2,addr,data_len);		
+	
+	return;
+}
+
+static void ndisc_fill_aro_option(struct sk_buff *skb,int type,struct aro_option *aro)
+{
+	int space = ndisc_opt_addr_space(skb->dev);
+	
+	struct aro_option *opt = (struct aro_option *)skb_put(skb,space);
+	if (sizeof(*opt) != sizeof(*aro))	{
+		ND_PRINTK(2,warn,"ARO : error in handling ARO option\n");
+		return;
+	}
+	
+	*opt = *aro;	
+
+	return;
+}
+
 static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur,
 					    struct nd_opt_hdr *end)
 {
@@ -234,6 +265,20 @@
 				ndopts->nd_opts_ri = nd_opt;
 			break;
 #endif
+		/*RFC6775 options for 6lowpan*/		
+		case ND_OPT_ARO:		
+			if (!ndopts->nd_opts_aro)
+				ndopts->nd_opts_aro = nd_opt;
+			break;
+		case ND_OPT_6CO:		
+			if (!ndopts->nd_opts_6co)
+				ndopts->nd_opts_6co = nd_opt;
+			break;
+		case ND_OPT_ABRO:		
+			if (!ndopts->nd_opts_abro)
+				ndopts->nd_opts_abro = nd_opt;
+			break;
+
 		default:
 			if (ndisc_is_useropt(nd_opt)) {
 				ndopts->nd_useropts_end = nd_opt;
@@ -465,7 +510,8 @@
 static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
 			  const struct in6_addr *daddr,
 			  const struct in6_addr *solicited_addr,
-			  bool router, bool solicited, bool override, bool inc_opt)
+			  bool router, bool solicited, bool override, bool inc_opt,
+			  struct aro_option *aro)
 {
 	struct sk_buff *skb;
 	struct in6_addr tmpaddr;
@@ -492,8 +538,13 @@
 
 	if (!dev->addr_len)
 		inc_opt = 0;
-	if (inc_opt)
+	
+	
+	if (inc_opt) {
 		optlen += ndisc_opt_addr_space(dev);
+		if (dev->addr_len == IEEE802154_ADDR_LEN) 			
+			optlen += IEEE802154_ADDR_LEN;
+	}
 
 	skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
 	if (!skb)
@@ -509,12 +560,16 @@
 		},
 		.target = *solicited_addr,
 	};
-
-	if (inc_opt)
-		ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR,
+	
+	if (inc_opt) {
+		if (dev->type == ARPHRD_IEEE802154) {
+			ndisc_fill_tllao_option(skb,ND_OPT_TARGET_LL_ADDR,
+					dev->dev_addr);
+			ndisc_fill_aro_option(skb,ND_OPT_ARO,aro);	//FIXME: how to get the aro option structure
+		} else 
+			ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR,
 				       dev->dev_addr);
-
-
+	}
 	ndisc_send_skb(skb, daddr, src_addr);
 }
 
@@ -532,7 +587,7 @@
 		ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &ifa->addr,
 			      /*router=*/ !!idev->cnf.forwarding,
 			      /*solicited=*/ false, /*override=*/ true,
-			      /*inc_opt=*/ true);
+			      /*inc_opt=*/ true,NULL);
 	}
 	read_unlock_bh(&idev->lock);
 
@@ -704,6 +759,8 @@
 	bool inc;
 	int is_router = -1;
 
+	struct aro_option *aro;
+
 	if (skb->len < sizeof(struct nd_msg)) {
 		ND_PRINTK(2, warn, "NS: packet too short\n");
 		return;
@@ -748,6 +805,41 @@
 		}
 	}
 
+	/* Handling of ARO option according to RFC6775*/
+	if (dev->type == ARPHRD_IEEE802154) {
+		if (ndopts.nd_opts_aro) {
+			//TODO : check the status field should be zero otherwise discard it
+               		memcpy(&aro->status,(u8 *)(ndopts.nd_opts_aro+1),sizeof(aro->status));
+			memcpy(&aro->reg_lifetime,(u16 *)(ndopts.nd_opts_aro+3),sizeof(aro->reg_lifetime));
+			memcpy(aro->eui_64,(u8 *)(ndopts.nd_opts_aro+4),8);
+
+			if (aro->status == 0) {
+				ND_PRINTK(2,warn,"ARO: invalid status option must be discard the packet\n");	
+				return ;
+			}                
+			/*lookup in the neighbour table i.e NC */
+               		neigh = neigh_lookup(&nd_tbl,saddr,dev);
+
+               		if (neigh) {
+                    		if (memcmp(neigh->ha,aro->eui_64,8)) {
+                         		//FIXME:update registration life time
+                         		aro->status = 0;
+                    		} else
+                         		aro->status  = 1;
+               		} else {
+                    		neigh = neigh_create(&nd_tbl,saddr,dev);
+                    		if (neigh) {
+                         		neigh_update(neigh,aro->eui_64,NUD_STALE,0);
+					//TODO : update registration life time
+                         		aro->status = 0;
+                    		}
+               		}
+		}
+	} 
+
+	if (dev->type == ARPHRD_IEEE802154)
+		ndisc_send_na(dev,neigh,daddr,&msg->target,idev->cnf.forwarding,true,false,true,aro);
+	
 	inc = ipv6_addr_is_multicast(daddr);
 
 	ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
@@ -783,7 +875,6 @@
 			/* XXX: count this drop? */
 			return;
 		}
-
 		if (ipv6_chk_acast_addr(net, dev, &msg->target) ||
 		    (idev->cnf.forwarding &&
 		     (net->ipv6.devconf_all->proxy_ndp || idev->cnf.proxy_ndp) &&
@@ -813,7 +904,7 @@
 
 	if (dad) {
 		ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &msg->target,
-			      !!is_router, false, (ifp != NULL), true);
+			      !!is_router, false, (ifp != NULL), true,NULL);
 		goto out;
 	}
 
@@ -835,7 +926,7 @@
 	if (neigh || !dev->header_ops) {
 		ndisc_send_na(dev, neigh, saddr, &msg->target,
 			      !!is_router,
-			      true, (ifp != NULL && inc), inc);
+			      true, (ifp != NULL && inc), inc,NULL);
 		if (neigh)
 			neigh_release(neigh);
 	}
@@ -1009,6 +1100,114 @@
 	return;
 }
 
+static void ndisc_recv_dar(struct sk_buff *skb)
+{
+	struct darc_msg *msg = (struct darc_msg *)skb_transport_header(skb);//icmpv6 header pointer
+	const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;		//source ipv6 address
+	const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;		//destination ipv6 address
+	const struct in6_addr *reg_addr = &msg->reg_addr;
+
+	struct inet6_dev *idev;			//ipv6 specific information					
+	
+	struct neighbour *neigh;
+	
+	struct net_device *dev = skb->dev;	//netdevice ieee802154 interface
+	
+	/*Network Device is not related to Ieee802.15.4 device */
+	if (dev->type != ARPHRD_IEEE802154)	
+		return ;
+
+	/* if skb is too short */
+	if (skb->len < sizeof(struct darc_msg))
+		return ;
+		
+	idev = in6_dev_get(skb->dev);
+	if (!idev) {
+		ND_PRINTK(1, err, "DAR: can't find in6 device\n");
+		return;
+	}
+	/* dont accept DAR if you are not router mode*/
+	if (!idev->cnf.forwarding)			
+		return ;
+
+	/* registered address should not be multicast address : RFC6775 */
+	if (ipv6_addr_is_multicast(reg_addr)) {
+		ND_PRINTK(2,warn,"DAR : registered address is multicast\n");
+		return;
+	}
+	
+	/*status in the DAR must be zero */
+	if (msg->status != 0)
+		return;	
+	
+	/*lookup in the neighbour table i.e NC */
+	neigh = neigh_lookup(&nd_tbl,reg_addr,dev);
+
+	if (neigh) {
+		if (memcmp(neigh->ha,msg->eui_64,8) == 0) { 
+			//FIXME:update registration life time
+			msg->status = 0;		
+		}
+		else 
+			msg->status  = 1;
+	}
+ 	else {
+		neigh = neigh_create(&nd_tbl,reg_addr,dev);
+		if (neigh) {
+			neigh_update(neigh,msg->eui_64,NUD_STALE,0);
+			msg->status = 0;
+		}
+	}
+	ndisc_send_dac(dev,neigh,saddr,daddr,msg);
+}
+
+static void ndisc_recv_dac(struct sk_buff *skb)
+{
+	struct inet6_dev *idev;
+	struct net_device *dev=skb->dev;
+	
+	idev = in6_dev_get(skb->dev);
+	if (!idev) {
+		ND_PRINTK(1, err, "DAC: can't find in6 device\n");
+		return;
+	}
+	/* dont accept DAC if you are in router mode*/
+	if (idev->cnf.forwarding)			
+		return ;
+	
+	if (dev->type != ARPHRD_IEEE802154)
+		return;
+		
+}
+void ndisc_send_dac(struct net_device *dev,struct neighbour *neigh,
+						const struct in6_addr *daddr,const struct in6_addr *src_addr,
+						struct darc_msg *rmsg)
+{
+	struct sk_buff *skb;
+	struct darc_msg *cmsg;
+	
+	if (daddr == NULL) {
+		ND_PRINTK(2,warn,"DAC: Undefined destination address\n");
+		return ;
+	}
+
+	/* allocation of socket buffer */
+	skb = ndisc_alloc_skb(dev,sizeof(*cmsg));
+	if (!skb)
+		return ;
+
+	cmsg = (struct darc_msg *)skb_put(skb,sizeof(*cmsg));
+
+	*cmsg = (struct darc_msg) *rmsg;
+	*cmsg = (struct darc_msg) {
+			.icmph = { 
+				.icmp6_type = NDISC_DUPLICATE_ADDRESS_CONFIRMATION,
+			},
+	};
+
+	/*sending the packet */
+	ndisc_send_skb(skb,daddr,src_addr);
+}
 static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
 {
 	struct icmp6hdr *icmp6h = (struct icmp6hdr *)skb_transport_header(ra);
@@ -1564,6 +1763,14 @@
 	case NDISC_REDIRECT:
 		ndisc_redirect_rcv(skb);
 		break;
+	/*Two more ICMP messages according to RFC6775*/
+	case NDISC_DUPLICATE_ADDRESS_REQUEST:
+		ndisc_recv_dar(skb);		
+		break;	
+	
+	case NDISC_DUPLICATE_ADDRESS_CONFIRMATION:
+		ndisc_recv_dac(skb);
+		break;
 	}
 
 	return 0;
--- a/include/net/ndisc.h	2013-09-14 19:37:01.000000000 +0530
+++ b/include/net/ndisc.h	2013-09-23 16:14:01.000000000 +0530
@@ -11,6 +11,10 @@
 #define NDISC_NEIGHBOUR_ADVERTISEMENT	136
 #define NDISC_REDIRECT			137
 
+/* RFC6775 lowpan ND */
+#define NDISC_DUPLICATE_ADDRESS_REQUEST		157
+#define NDISC_DUPLICATE_ADDRESS_CONFIRMATION 	158
+
 /*
  * Router type: cross-layer information from link-layer to
  * IPv6 layer reported by certain link types (e.g., RFC4214).
@@ -35,6 +39,12 @@
 	ND_OPT_ROUTE_INFO = 24,		/* RFC4191 */
 	ND_OPT_RDNSS = 25,		/* RFC5006 */
 	ND_OPT_DNSSL = 31,		/* RFC6106 */
+
+
+ 	ND_OPT_ARO = 33,				/* RFC6775 */
+      	ND_OPT_6CO = 34,				/* RFC6775 */
+      	ND_OPT_ABRO = 35,				/* RFC6775 */
+
 	__ND_OPT_MAX
 };
 
@@ -85,20 +95,46 @@
 	__u8		opt[0];
 };
 
+/* RFC6775 Duplicate address registration message */
+struct darc_msg {
+	struct icmp6hdr icmph;
+	__u8 status;
+	__u8 reserved;
+	__u16 reg_life_time;
+	__u8 eui_64[8];
+	struct in6_addr reg_addr;
+};
+
+
 struct nd_opt_hdr {
 	__u8		nd_opt_type;
 	__u8		nd_opt_len;
 } __packed;
 
+struct aro_option {
+	struct nd_opt_hdr aro;
+	__u8 status;
+	__u16 reserved;
+	__u16 reg_lifetime;
+	__u8 eui_64[8];
+};
+
 /* ND options */
 struct ndisc_options {
 	struct nd_opt_hdr *nd_opt_array[__ND_OPT_ARRAY_MAX];
+	
+	/* lowpan options header fields RFC6775*/
+	struct nd_opt_hdr *nd_opts_aro;
+	struct nd_opt_hdr *nd_opts_6co;
+	struct nd_opt_hdr *nd_opts_abro;
+	
 #ifdef CONFIG_IPV6_ROUTE_INFO
 	struct nd_opt_hdr *nd_opts_ri;
 	struct nd_opt_hdr *nd_opts_ri_end;
 #endif
 	struct nd_opt_hdr *nd_useropts;
 	struct nd_opt_hdr *nd_useropts_end;
+
 };
 
 #define nd_opts_src_lladdr	nd_opt_array[ND_OPT_SOURCE_LL_ADDR]
@@ -190,7 +226,9 @@
 }
 
 extern int			ndisc_init(void);
+extern int			ndisc_late_init(void);
 
+extern void			ndisc_late_cleanup(void);
 extern void			ndisc_cleanup(void);
 
 extern int			ndisc_rcv(struct sk_buff *skb);
@@ -204,10 +242,22 @@
 extern void			ndisc_send_rs(struct net_device *dev,
 					      const struct in6_addr *saddr,
 					      const struct in6_addr *daddr);
+/*extern void			ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
+					      const struct in6_addr *daddr,
+					      const struct in6_addr *solicited_addr,
+					      bool router, bool solicited, bool override,
+					      bool inc_opt);*/
 
 extern void			ndisc_send_redirect(struct sk_buff *skb,
 						    const struct in6_addr *target);
 
+/*sending DAC : RFC6775 */
+extern void 			ndisc_send_dac(struct net_device *dev,
+						struct neighbour *neigh,
+                              			const struct in6_addr *daddr,
+						const struct in6_addr *src_addr,
+                              			struct darc_msg *rmsg);
+
 extern int			ndisc_mc_map(const struct in6_addr *addr, char *buf,
 					     struct net_device *dev, int dir);
 
------------------------------------------------------------------------------
LIMITED TIME SALE - Full Year of Microsoft Training For Just $49.99!
1,500+ hours of tutorials including VisualStudio 2012, Windows 8, SharePoint
2013, SQL 2012, MVC 4, more. BEST VALUE: New Multi-Library Power Pack includes
Mobile, Cloud, Java, and UX Design. Lowest price ever! Ends 9/20/13. 
http://pubads.g.doubleclick.net/gampad/clk?id=58041151&iu=/4140/ostg.clktrk
_______________________________________________
Linux-zigbee-devel mailing list
Linux-zigbee-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-zigbee-devel

Reply via email to