Current snapshot of my 6lowpan port. Receive doesn't work.

Hook lowpan into the system
---
 drivers/ieee802154/serial.c |    7 
 include/linux/nl802154.h    |    1 
 net/mac802154/6lowpan.c     |  948 +++++++++++++++++++++++++++++++++++++++++++
 net/mac802154/6lowpan.h     |   81 ++++
 net/mac802154/Kconfig       |    6 
 net/mac802154/Makefile      |    6 
 net/mac802154/mac802154.h   |   17 +
 net/mac802154/main.c        |    5 
 net/mac802154/wpan.c        |  118 ++---
 9 files changed, 1122 insertions(+), 67 deletions(-)
 create mode 100644 net/mac802154/6lowpan.c
 create mode 100644 net/mac802154/6lowpan.h

diff --git a/drivers/ieee802154/serial.c b/drivers/ieee802154/serial.c
index 037963b..811b21e 100644
--- a/drivers/ieee802154/serial.c
+++ b/drivers/ieee802154/serial.c
@@ -31,6 +31,7 @@
 #include <linux/tty.h>
 #include <linux/skbuff.h>
 #include <linux/sched.h>
+#include <net/ipv6.h>
 #include <net/mac802154.h>
 #include <net/wpan-phy.h>
 
@@ -351,8 +352,10 @@ static void serial_net_rx(struct zb_device *zbdev)
         * zbdev->data is data itself
         */
        struct sk_buff *skb;
-       skb = alloc_skb(zbdev->param2, GFP_ATOMIC);
-       skb_put(skb, zbdev->param2);
+
+       /* leave room for 6lowpan expansion */
+       skb = alloc_skb(zbdev->param2 + sizeof(struct ipv6hdr), GFP_ATOMIC);
+       skb_push(skb, zbdev->param2);
        skb_copy_to_linear_data(skb, zbdev->data, zbdev->param2);
        ieee802154_rx_irqsafe(zbdev->dev, skb, zbdev->param1);
 }
diff --git a/include/linux/nl802154.h b/include/linux/nl802154.h
index a379fc7..72c686c 100644
--- a/include/linux/nl802154.h
+++ b/include/linux/nl802154.h
@@ -129,6 +129,7 @@ enum {
        IEEE802154_DEV_WPAN,
        IEEE802154_DEV_MONITOR,
        IEEE802154_DEV_SMAC,
+       IEEE802154_DEV_6LOWPAN,
        __IEEE802154_DEV_MAX,
 };
 
diff --git a/net/mac802154/6lowpan.c b/net/mac802154/6lowpan.c
new file mode 100644
index 0000000..51ccfb7
--- /dev/null
+++ b/net/mac802154/6lowpan.c
@@ -0,0 +1,948 @@
+/*
+ * 6lowpan - IPv6 compression on 802.15.4
+ *
+ * Copyright 2010, Jon Smirl <[email protected]>
+ * This code is derived from Contiki - http://www.sics.se/contiki
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/if_arp.h>
+#include <linux/netdevice.h>
+#include <linux/nl802154.h>
+#include <net/ipv6.h>
+#include <net/mac802154.h>
+
+#include "mac802154.h"
+#include "6lowpan.h"
+
+#define UIP_802154_SHORTADDR_LEN 2
+
+#define UIP_PROTO_UDP   17
+#define UIP_IPH_LEN    40
+#define UIP_FRAGH_LEN  8
+
+#define is_addr_mac_addr_based(a, m) \
+  ((((a)->in6_u.u6_addr8[8])  == (((m)[0]) ^ 0x02)) &&   \
+   (((a)->in6_u.u6_addr8[9])  == (m)[1]) &&            \
+   (((a)->in6_u.u6_addr8[10]) == (m)[2]) &&            \
+   (((a)->in6_u.u6_addr8[11]) == (m)[3]) &&            \
+   (((a)->in6_u.u6_addr8[12]) == (m)[4]) &&            \
+   (((a)->in6_u.u6_addr8[13]) == (m)[5]) &&            \
+   (((a)->in6_u.u6_addr8[14]) == (m)[6]) &&            \
+   (((a)->in6_u.u6_addr8[15]) == (m)[7]))
+
+/**
+ * \brief Is IPv6 address a the unspecified address
+ * a is of type ipaddr_t
+ */
+#define is_addr_unspecified(a)               \
+  ((((a)->in6_u.u6_addr16[0]) == 0) &&                       \
+   (((a)->in6_u.u6_addr16[1]) == 0) &&                       \
+   (((a)->in6_u.u6_addr16[2]) == 0) &&                       \
+   (((a)->in6_u.u6_addr16[3]) == 0) &&                       \
+   (((a)->in6_u.u6_addr16[4]) == 0) &&                       \
+   (((a)->in6_u.u6_addr16[5]) == 0) &&                       \
+   (((a)->in6_u.u6_addr16[6]) == 0) &&                       \
+   (((a)->in6_u.u6_addr16[7]) == 0))
+
+#define ipaddr_prefixcmp(addr1, addr2, length) (memcmp(addr1, addr2, 
length>>3) == 0)
+
+/**
+ * \brief is addr (a) a link local unicast address, see RFC3513
+ *  i.e. is (a) on prefix FE80::/10
+ *  a is of type ipaddr_t*
+ */
+#define is_addr_link_local(a) \
+  ((((a)->in6_u.u6_addr8[0]) == 0xFE) && \
+  (((a)->in6_u.u6_addr8[1]) == 0x80))
+
+/**
+ * \brief check whether we can compress the IID in
+ * address 'a' to 16 bits.
+ * This is used for unicast addresses only, and is true
+ * if first 49 bits of IID are 0
+ */
+#define lowpan_is_iid_16_bit_compressable(a) \
+  ((((a)->in6_u.u6_addr16[4]) == 0) &&                       \
+   (((a)->in6_u.u6_addr16[5]) == 0) &&                       \
+   (((a)->in6_u.u6_addr16[6]) == 0) &&                       \
+   ((((a)->in6_u.u6_addr8[14]) & 0x80) == 0))
+
+/**
+ * \brief is address a multicast address, see RFC 3513
+ * a is of type ipaddr_t*
+ * */
+#define is_addr_mcast(a)                    \
+  (((a)->in6_u.u6_addr8[0]) == 0xFF)
+
+
+/**
+ * \brief check whether the 112-bit group-id of the
+ * multicast address is mappable to a 9-bit group-id
+ * It is true if the group is the all nodes or all
+ * routers group.
+*/
+#define lowpan_is_mcast_addr_compressable(a) \
+  ((((a)->in6_u.u6_addr16[1]) == 0) &&                       \
+   (((a)->in6_u.u6_addr16[2]) == 0) &&                       \
+   (((a)->in6_u.u6_addr16[3]) == 0) &&                       \
+   (((a)->in6_u.u6_addr16[4]) == 0) &&                       \
+   (((a)->in6_u.u6_addr16[5]) == 0) &&                       \
+   (((a)->in6_u.u6_addr16[6]) == 0) &&                       \
+   (((a)->in6_u.u6_addr8[14]) == 0) &&                       \
+   ((((a)->in6_u.u6_addr8[15]) == 1) || (((a)->in6_u.u6_addr8[15]) == 2)))
+
+/* FFXX::00XX:XXXX:XXXX */
+#define lowpan_is_mcast_addr_compressable48(a) \
+  ((((a)->in6_u.u6_addr16[1]) == 0) &&                       \
+   (((a)->in6_u.u6_addr16[2]) == 0) &&                       \
+   (((a)->in6_u.u6_addr16[3]) == 0) &&                       \
+   (((a)->in6_u.u6_addr16[4]) == 0) &&                       \
+   (((a)->in6_u.u6_addr8[10]) == 0))
+
+/* FFXX::00XX:XXXX */
+#define lowpan_is_mcast_addr_compressable32(a) \
+  ((((a)->in6_u.u6_addr16[1]) == 0) &&                       \
+   (((a)->in6_u.u6_addr16[2]) == 0) &&                       \
+   (((a)->in6_u.u6_addr16[3]) == 0) &&                       \
+   (((a)->in6_u.u6_addr16[4]) == 0) &&                       \
+   (((a)->in6_u.u6_addr16[5]) == 0) &&                       \
+   (((a)->in6_u.u6_addr8[12]) == 0))
+
+/* FF02::00XX */
+#define lowpan_is_mcast_addr_compressable8(a) \
+  ((((a)->in6_u.u6_addr8[1]) == 2) &&                        \
+   (((a)->in6_u.u6_addr16[1]) == 0) &&                       \
+   (((a)->in6_u.u6_addr16[2]) == 0) &&                       \
+   (((a)->in6_u.u6_addr16[3]) == 0) &&                       \
+   (((a)->in6_u.u6_addr16[4]) == 0) &&                       \
+   (((a)->in6_u.u6_addr16[5]) == 0) &&                       \
+   (((a)->in6_u.u6_addr16[6]) == 0) &&                       \
+   (((a)->in6_u.u6_addr8[14]) == 0))
+
+/* TTL uncompression values */
+static const u8 ttl_values[] = {0, 1, 64, 255};
+
+/* Uncompression of linklocal */
+/*   0 -> 16 bytes from packet  */
+/*   1 -> 2 bytes from prefix - bunch of zeroes and 8 from packet */
+/*   2 -> 2 bytes from prefix - zeroes + 2 from packet */
+/*   3 -> 2 bytes from prefix - infer 8 bytes from lladdr */
+/*   NOTE: => the uncompress function does change 0xf to 0x10 */
+/*   NOTE: 0x00 => no-autoconfig => unspecified */
+const u8 unc_llconf[] = {0x0f,0x28,0x22,0x20};
+
+/* Uncompression of ctx-based */
+/*   0 -> 0 bits from packet [unspecified / reserved] */
+/*   1 -> 8 bytes from prefix - bunch of zeroes and 8 from packet */
+/*   2 -> 8 bytes from prefix - zeroes + 2 from packet */
+/*   3 -> 8 bytes from prefix - infer 8 bytes from lladdr */
+const u8 unc_ctxconf[] = {0x00,0x88,0x82,0x80};
+
+/* Uncompression of ctx-based */
+/*   0 -> 0 bits from packet  */
+/*   1 -> 2 bytes from prefix - bunch of zeroes 5 from packet */
+/*   2 -> 2 bytes from prefix - zeroes + 3 from packet */
+/*   3 -> 2 bytes from prefix - infer 1 bytes from lladdr */
+const u8 unc_mxconf[] = {0x0f, 0x25, 0x23, 0x21};
+
+/* Link local prefix */
+const u8 llprefix[] = {0xfe, 0x80};
+
+/**
+ * \brief An address context for IPHC address compression
+ * each context can have upto 8 bytes
+ */
+struct lowpan_addr_context {
+       u8 used; /* possibly use as prefix-length */
+       u8 number;
+       u8 prefix[8];
+};
+
+#define LOWPAN_CONF_MAX_ADDR_CONTEXTS 8
+static struct lowpan_addr_context 
+addr_contexts[LOWPAN_CONF_MAX_ADDR_CONTEXTS];
+
+/** \brief find the context corresponding to prefix ipaddr */
+static struct lowpan_addr_context*
+addr_context_lookup_by_prefix(const struct in6_addr *ipaddr) 
+{
+       int i;
+       for(i = 0; i < LOWPAN_CONF_MAX_ADDR_CONTEXTS; i++) {
+               if((addr_contexts[i].used == 1) &&
+                   ipaddr_prefixcmp(&addr_contexts[i].prefix, 
ipaddr->in6_u.u6_addr8, 64))
+                       return &addr_contexts[i];
+       }
+       return NULL;
+}
+
+/** \brief find the context with the given number */
+static struct lowpan_addr_context*
+addr_context_lookup_by_number(u8 number) 
+{
+       int i;
+       for(i = 0; i < LOWPAN_CONF_MAX_ADDR_CONTEXTS; i++) {
+               if((addr_contexts[i].used == 1) &&
+                   addr_contexts[i].number == number)
+                       return &addr_contexts[i];
+       }
+       return NULL;
+}
+
+static u8
+compress_addr_64(u8 **hc06_ptr, u8 bitpos, const struct in6_addr *ipaddr, 
const unsigned char lladdr[IEEE802154_ALEN]) 
+{
+       if (is_addr_mac_addr_based(ipaddr, lladdr)) {
+
+               return 3 << bitpos; /* 0-bits */
+
+       } else if (lowpan_is_iid_16_bit_compressable(ipaddr)) {
+
+               /* compress IID to 16 bits xxxx::XXXX */
+               memcpy(*hc06_ptr, &ipaddr->in6_u.u6_addr16[7], 2);
+               *hc06_ptr += 2;
+               return 2 << bitpos; /* 16-bits */
+       }
+       /* do not compress IID => xxxx::IID */
+       memcpy(*hc06_ptr, &ipaddr->in6_u.u6_addr16[4], 8);
+       *hc06_ptr += 8;
+       return 1 << bitpos; /* 64-bits */
+}
+
+/*---------------------------------------------------------------------------*/
+void
+uip_ds6_set_addr_iid(struct in6_addr *ipaddr, unsigned char 
lladdr[IEEE802154_ALEN])
+{
+       memcpy(&ipaddr->in6_u.u6_addr8[8], lladdr, IEEE802154_ALEN);
+       ipaddr->in6_u.u6_addr8[8] ^= 0x02;
+}
+
+/*-------------------------------------------------------------------- */
+/* Uncompress addresses based on a prefix and a postfix with zeroes in
+ * between. If the postfix is zero in length it will use the link address
+ * to configure the IP address (autoconf style).
+ * pref_post_count takes a byte where the first nibble specify prefix count
+ * and the second postfix count (NOTE: 15/0xf => 16 bytes copy).
+ */
+static void
+uncompress_addr(struct sk_buff *skb, struct in6_addr *ipaddr, u8 const 
prefix[], u8 pref_post_count, unsigned char lladdr[IEEE802154_ALEN]) 
+{
+       int tmp;
+       u8 prefcount = pref_post_count >> 4;
+       u8 postcount = pref_post_count & 0x0f;
+
+       /* full nibble 15 => 16 */
+       prefcount = prefcount == 15 ? 16 : prefcount;
+       postcount = postcount == 15 ? 16 : postcount;
+
+       printk("lladdr ");
+       if (lladdr)
+               for (tmp = 0; tmp < 8; tmp++)
+                       printk("%02x ", lladdr[tmp]);
+       printk("\nUncompressing %d + %d => ", prefcount, postcount);
+
+       if (prefcount > 0) {
+               memcpy(ipaddr, prefix, prefcount);
+       }
+       if (prefcount + postcount < 16) {
+               memset(&ipaddr->in6_u.u6_addr8[prefcount], 0, 16 - (prefcount + 
postcount));
+       }
+       if (postcount > 0) {
+               memcpy(&ipaddr->in6_u.u6_addr8[16 - postcount], skb->data, 
postcount);
+               skb_pull(skb, postcount);
+       } else if (prefcount > 0){
+               /* no IID based configuration if no prefix and no data => 
unspec */
+               uip_ds6_set_addr_iid(ipaddr, lladdr);
+       }
+
+       for (tmp = 0; tmp < 16; tmp++)
+               printk("%02x ", ipaddr->in6_u.u6_addr8[tmp]);
+       printk("\n");
+}
+
+
+
+static u8 fetch_skb_u8(struct sk_buff *skb)
+{
+       u8 ret;
+
+       BUG_ON(skb->len < 1);
+
+       ret = skb->data[0];
+       skb_pull(skb, 1);
+
+       return ret;
+}
+
+static u16 fetch_skb_u16(struct sk_buff *skb)
+{
+       u16 ret;
+
+       BUG_ON(skb->len < 2);
+
+       ret = skb->data[0] + (skb->data[1] * 256);
+       skb_pull(skb, 2);
+       return ret;
+}
+
+static void fetch_skb_u64(struct sk_buff *skb, u8 *dest)
+{
+       int i;
+
+       BUG_ON(skb->len < IEEE802154_ALEN);
+
+       for (i = 0; i < IEEE802154_ALEN; i++)
+               dest[IEEE802154_ALEN - i - 1] = skb->data[i];
+       skb_pull(skb, IEEE802154_ALEN);
+}
+
+static int lowpan_process_data(struct net_device *dev, struct sk_buff *skb, 
unsigned char _saddr[IEEE802154_ALEN], unsigned char _daddr[IEEE802154_ALEN])
+{
+       struct ipv6hdr hdr;
+       u8 tmp, iphc0, iphc1, num_context = 0;
+       struct lowpan_addr_context *context = NULL;
+
+       printk("JDS - %s\n", __func__);
+
+       /* at least two byte will be used for the encoding */
+
+       iphc0 = fetch_skb_u8(skb);
+       iphc1 = fetch_skb_u8(skb);
+       printk("iphc0 %02x iphc1 %02x\n", iphc0, iphc1);
+
+       /* another if the CID flag is set */
+       if(iphc1 & LOWPAN_IPHC_CID) {
+               printk("IPHC: CID flag set - increase header with one\n");
+               num_context = fetch_skb_u8(skb);
+       }
+
+       /* Traffic class and flow label */
+       hdr.version = 6;
+       if ((iphc0 & LOWPAN_IPHC_FL_C) == 0) {
+               /* Flow label are carried inline */
+               if ((iphc0 & LOWPAN_IPHC_TC_C) == 0) {
+                       /* Traffic class is carried inline */
+                       tmp = fetch_skb_u8(skb);
+                       memcpy(&hdr.flow_lbl, &skb->data[0], 3);
+                       skb_pull(skb, 3);
+
+                       /* hc06 format of tc is ECN | DSCP , original is DSCP | 
ECN */
+                       /* set version, pick highest DSCP bits and set in vtc */
+                       hdr.priority = ((tmp >> 2) & 0x0f);
+                       /* ECN rolled down two steps + lowest DSCP bits at top 
two bits */
+                       hdr.flow_lbl[0] = ((tmp >> 2) & 0x30) | (tmp << 6) | 
(hdr.flow_lbl[0] & 0x0f);
+               } else {
+                       /* Traffic class is compressed (set version and no TC)*/
+                       /* highest flow label bits + ECN bits */
+                       tmp = fetch_skb_u8(skb);
+                       hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 
0x30);
+                       memcpy(&hdr.flow_lbl[1], &skb->data[0], 2);
+                       skb_pull(skb, 2);
+               }
+       } else {
+               /* Version is always 6! */
+               /* Version and flow label are compressed */
+               if ((iphc0 & LOWPAN_IPHC_TC_C) == 0) {
+                       /* Traffic class is inline */
+                       tmp = fetch_skb_u8(skb);
+                       hdr.priority = ((tmp >> 2) & 0x0f);
+                       hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 
0x30);
+                       hdr.flow_lbl[1] = 0;
+                       hdr.flow_lbl[2] = 0;
+               } else {
+                       /* Traffic class is compressed */
+                       hdr.priority = 0;
+                       hdr.flow_lbl[0] = 0;
+                       hdr.flow_lbl[1] = 0;
+                       hdr.flow_lbl[2] = 0;
+               }
+       }
+
+       /* Next Header */
+       if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
+               /* Next header is carried inline */
+               hdr.nexthdr = fetch_skb_u8(skb);
+               printk("IPHC: next header inline: %02x\n", hdr.nexthdr);
+       }
+
+       /* Hop limit */
+       if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I) {
+               hdr.hop_limit = ttl_values[iphc0 & 0x03];
+       } else {
+               hdr.hop_limit = fetch_skb_u8(skb);
+       }
+
+       /* put the source address compression mode SAM in the tmp var */
+       tmp = ((iphc1 & LOWPAN_IPHC_SAM_11) >> LOWPAN_IPHC_SAM_BIT) & 0x03;
+
+       /* context based compression */
+       if (iphc1 & LOWPAN_IPHC_SAC) {
+               u8 sci = (iphc1 & LOWPAN_IPHC_CID) ? num_context >> 4 : 0;
+printk("iphc1 & LOWPAN_IPHC_SAC\n");
+
+               /* Source address */
+               if((iphc1 & LOWPAN_IPHC_SAM_11) != LOWPAN_IPHC_SAM_00) {
+                       context = addr_context_lookup_by_number(sci);
+printk("context %p sci %d\n", context, sci);
+                       if(context == NULL) {
+                               printk("sicslowpan uncompress_hdr: error 
context not found\n");
+                               return -ENXIO;
+                       } else {
+                               printk("IPHC: found compressed source context 
for sci = %d\n", sci);
+                       }
+                       uncompress_addr(skb, &hdr.saddr, context->prefix, 
unc_ctxconf[tmp], skb->data);
+               } else {
+printk("LOWPAN_IPHC_SAM == 0\n");
+               uncompress_addr(skb, &hdr.saddr, llprefix, unc_ctxconf[tmp], 
_saddr);
+               }
+       } else {
+               /* no compression and link local */
+               uncompress_addr(skb, &hdr.saddr, llprefix, unc_llconf[tmp], 
skb->data);
+       }
+
+       /* Destination address */
+       /* put the destination address compression mode into tmp */
+       tmp = ((iphc1 & LOWPAN_IPHC_DAM_11) >> LOWPAN_IPHC_DAM_BIT) & 0x03;
+
+       /* multicast compression */
+       if (iphc1 & LOWPAN_IPHC_M) {
+               /* context based multicast compression */
+               if (iphc1 & LOWPAN_IPHC_DAC) {
+                       /* TODO: implement this */
+               } else {
+                       /* non-context based multicast compression - */
+                       /* DAM_00: 128 bits  */
+                       /* DAM_01:  48 bits FFXX::00XX:XXXX:XXXX */
+                       /* DAM_10:  32 bits FFXX::00XX:XXXX */
+                       /* DAM_11:   8 bits FF02::00XX */
+                       u8 prefix[] = {0xff, 0x02};
+                       if (tmp > 0 && tmp < 3) {
+                               prefix[1] = fetch_skb_u8(skb);;
+                       }
+
+                       uncompress_addr(skb, &hdr.daddr, prefix, 
unc_mxconf[tmp], NULL);
+               }
+       } else {
+               /* no multicast */
+               /* Context based */
+               if(iphc1 & LOWPAN_IPHC_DAC) {
+                       u8 dci = (iphc1 & LOWPAN_IPHC_CID) ? num_context & 0x0f 
: 0;
+                       context = addr_context_lookup_by_number(dci);
+
+                       /* all valid cases below need the context! */
+                       if (context == NULL) {
+                               printk("sicslowpan uncompress_hdr: error 
context not found\n");
+                               return -ENXIO;
+                       }
+                       uncompress_addr(skb, &hdr.daddr, context->prefix, 
unc_ctxconf[tmp], skb->data);
+               } else {
+                       /* not context based => link local M = 0, DAC = 0 - 
same as SAC */
+                       uncompress_addr(skb, &hdr.daddr, llprefix, 
unc_llconf[tmp], skb->data);
+               }
+       }
+       printk("Check 1\n");
+#if 0
+       uncomp_hdr_len += UIP_IPH_LEN;
+
+       /* Next header processing - continued */
+       if ((iphc0 & LOWPAN_IPHC_NH_C)) {
+               /* The next header is compressed, NHC is following */
+               if ((*hc06_ptr & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) {
+                       u8 checksum_compressed;
+
+                       hdr.proto = UIP_PROTO_UDP;
+                       checksum_compressed = *hc06_ptr & 
LOWPAN_NHC_UDP_CHECKSUMC;
+                       printk("IPHC: Incoming header value: %i\n", *hc06_ptr);
+
+                       switch(*hc06_ptr & LOWPAN_NHC_UDP_CS_P_11) {
+                       case LOWPAN_NHC_UDP_CS_P_00:
+                               /* 1 byte for NHC, 4 byte for ports, 2 bytes 
chksum */
+                               memcpy(&LOWPAN_UDP_BUF->srcport, hc06_ptr + 1, 
2);
+                               memcpy(&LOWPAN_UDP_BUF->destport, hc06_ptr + 3, 
2);
+                               printk("IPHC: Uncompressed UDP ports (ptr+5): 
%x, %x\n",
+                               htons(LOWPAN_UDP_BUF->srcport), 
htons(LOWPAN_UDP_BUF->destport));
+                               hc06_ptr += 5;
+                               break;
+
+                       case LOWPAN_NHC_UDP_CS_P_01:
+                               /* 1 byte for NHC + source 16bit inline, dest = 
0xF0 + 8 bit inline */
+                               printk("IPHC: Decompressing destination\n");
+                               memcpy(&LOWPAN_UDP_BUF->srcport, hc06_ptr + 1, 
2);
+                               LOWPAN_UDP_BUF->destport = 
htons(LOWPAN_UDP_8_BIT_PORT_MIN + (*(hc06_ptr + 3)));
+                               printk("IPHC: Uncompressed UDP ports (ptr+4): 
%x, %x\n",
+                               htons(LOWPAN_UDP_BUF->srcport), 
htons(LOWPAN_UDP_BUF->destport));
+                               hc06_ptr += 4;
+                               break;
+
+                       case LOWPAN_NHC_UDP_CS_P_10:
+                               /* 1 byte for NHC + source = 0xF0 + 8bit 
inline, dest = 16 bit inline*/
+                               printk("IPHC: Decompressing source\n");
+                               LOWPAN_UDP_BUF->srcport = 
htons(LOWPAN_UDP_8_BIT_PORT_MIN +
+                               (*(hc06_ptr + 1)));
+                               memcpy(&LOWPAN_UDP_BUF->destport, hc06_ptr + 2, 
2);
+                               printk("IPHC: Uncompressed UDP ports (ptr+4): 
%x, %x\n",
+                               htons(LOWPAN_UDP_BUF->srcport), 
htons(LOWPAN_UDP_BUF->destport));
+                               hc06_ptr += 4;
+                               break;
+
+                       case LOWPAN_NHC_UDP_CS_P_11:
+                               /* 1 byte for NHC, 1 byte for ports */
+                               LOWPAN_UDP_BUF->srcport = 
htons(LOWPAN_UDP_4_BIT_PORT_MIN +
+                               (*(hc06_ptr + 1) >> 4));
+                               LOWPAN_UDP_BUF->destport = 
htons(LOWPAN_UDP_4_BIT_PORT_MIN +
+                               ((*(hc06_ptr + 1)) & 0x0F));
+                               printk("IPHC: Uncompressed UDP ports (ptr+2): 
%x, %x\n",
+                               htons(LOWPAN_UDP_BUF->srcport), 
htons(LOWPAN_UDP_BUF->destport));
+                               hc06_ptr += 2;
+                               break;
+
+                       default:
+                               printk("sicslowpan uncompress_hdr: error 
unsupported UDP compression\n");
+                               return;
+                       }
+                       if(!checksum_compressed) { /* has_checksum, default  */
+                               memcpy(&LOWPAN_UDP_BUF->udpchksum, hc06_ptr, 2);
+                               hc06_ptr += 2;
+                               printk("IPHC: sicslowpan uncompress_hdr: 
checksum included\n");
+                       } else {
+                               printk("IPHC: sicslowpan uncompress_hdr: 
checksum *NOT* included\n");
+                       }
+                       uncomp_hdr_len += UIP_UDPH_LEN;
+               }
+#ifdef LOWPAN_NH_COMPRESSOR
+               else {
+                       hc06_ptr += LOWPAN_NH_COMPRESSOR.uncompress(hc06_ptr, 
sicslowpan_buf, &uncomp_hdr_len);
+               }
+#endif
+       }
+
+       rime_hdr_len = hc06_ptr - rime_ptr;
+#endif
+
+       /* IP length field. */
+//     if(ip_len == 0) {
+               /* This is not a fragmented packet */
+               hdr.payload_len = htons(skb->len);
+//     } else {
+               /* This is a 1st fragment */
+               //hdr.payload_len = ip_len - UIP_IPH_LEN;
+//     }
+#if 0
+       /* length field in UDP header */
+       if(hdr.nexthdr == UIP_PROTO_UDP) {
+               memcpy(&LOWPAN_UDP_BUF->udplen, &hdr.payload_len[0], 2);
+       }
+#endif
+
+       memcpy(skb_push(skb, sizeof(hdr)), &hdr, sizeof(hdr));
+
+       skb->protocol = htons(ETH_P_IPV6);
+       skb->pkt_type = PACKET_HOST;
+
+       if (in_interrupt())
+               return netif_rx(skb);
+       else
+               return netif_rx_ni(skb);
+
+       printk("Version %d\n", hdr.version);
+       printk("Length %d\n", ntohs(hdr.payload_len));
+       printk("nexthdr %02x\n", hdr.nexthdr);
+       printk("hop_limit %d\n", hdr.hop_limit);
+
+       printk("Check 2\n");
+       for (tmp = 0; tmp < sizeof(hdr); tmp++)
+               printk("%02x ", ((u8 *)&hdr)[tmp]);
+       printk("\n");
+
+       printk("Check 3\n");
+
+       if (in_interrupt())
+               return netif_rx(skb);
+       else
+               return netif_rx_ni(skb);
+
+       //kfree_skb(skb);
+       return 0;
+}
+
+static int lowpan_header_parse(const struct sk_buff *skb,
+               unsigned char *haddr)
+{
+       printk("JDS - %s\n", __func__);
+       return mac802154_header_parse(skb, haddr);
+}
+
+static int lowpan_header_create(struct sk_buff *skb,
+                          struct net_device *dev,
+                          unsigned short type, const void *_daddr,
+                          const void *_saddr, unsigned len)
+{
+       u8 tmp, iphc0, iphc1, *hc06_ptr;
+       struct ipv6hdr* hdr;
+       struct lowpan_addr_context *context;
+       const u8 *saddr = _saddr;
+       const u8 *daddr = _daddr;
+       u8 head[100] = {};
+       u8 daddr_buf[IEEE802154_ALEN];
+
+       printk("JDS - %s\n", __func__);
+       if (type != ETH_P_IPV6)
+               return mac802154_header_create(skb, dev, type, _daddr, _saddr, 
skb->len);
+
+       hdr = ipv6_hdr(skb);
+       hc06_ptr = head + 2;
+
+       for (tmp = 0; tmp < 100; tmp++)
+               printk("%02x ", skb_network_header(skb)[tmp]);
+       printk("\n");
+
+       printk("Version %d\n", hdr->version);
+       printk("Length %d\n", ntohs(hdr->payload_len));
+       printk("nexthdr %02x\n", hdr->nexthdr);
+       printk("hop_limit %d\n", hdr->hop_limit);
+
+       printk("_saddr %p _daddr %p\n", _saddr, _daddr);
+
+       if (!saddr)
+               saddr = dev->dev_addr;
+       printk("saddr ");
+       for (tmp = 0; tmp < 8; tmp++)
+               printk("%02x:", saddr[tmp]);
+       printk("\n");
+
+       /*
+        * As we copy some bit-length fields, in the IPHC encoding bytes,
+        * we sometimes use |=
+        * If the field is 0, and the current bit value in memory is 1,
+        * this does not work. We therefore reset the IPHC encoding here
+        */
+
+       iphc0 = LOWPAN_DISPATCH_IPHC;
+       iphc1 = 0;
+
+       /*
+        * Address handling needs to be made first since it might
+        * cause an extra byte with [ SCI | DCI ]
+        *
+        */
+
+       printk("scontext %p\n", addr_context_lookup_by_prefix(&hdr->saddr));
+       printk("dcontext %p\n", addr_context_lookup_by_prefix(&hdr->daddr));
+
+
+       /* check if dest context exists (for allocating third byte) */
+       /* TODO: fix this so that it remembers the looked up values for
+        * avoiding two lookups - or set the lookup values immediately 
+        */
+       if (addr_context_lookup_by_prefix(&hdr->daddr) != NULL ||
+           addr_context_lookup_by_prefix(&hdr->saddr) != NULL) {
+               /* set context flag and increase hc06_ptr */
+               printk("IPHC: compressing dest or src ipaddr - setting CID\n");
+               iphc1 |= LOWPAN_IPHC_CID;
+               hc06_ptr++;
+       }
+
+       if ((addr_context_lookup_by_prefix(&hdr->daddr) && (memcmp(daddr, 
saddr, IEEE802154_ALEN) == 0))) {
+               memcpy(&daddr_buf, &hdr->daddr.in6_u.u6_addr8[8], 
IEEE802154_ALEN);
+               daddr_buf[0] &= 0xFD;
+               daddr = &daddr_buf[0];
+       }
+
+       printk("daddr ");
+       for (tmp = 0; tmp < 8; tmp++)
+               printk("%02x:", daddr[tmp]);
+       printk("\n");
+
+
+       /*
+        * Traffic class, flow label
+        * If flow label is 0, compress it. If traffic class is 0, compress it
+        * We have to process both in the same time as the offset of traffic 
class
+        * depends on the presence of version and flow label
+        */
+
+       /* hc06 format of tc is ECN | DSCP , original is DSCP | ECN */
+       tmp = (hdr->priority << 4) | (hdr->flow_lbl[0] >> 4);
+       tmp = ((tmp & 0x03) << 6) | (tmp >> 2);
+
+       if(((hdr->flow_lbl[0] & 0x0F) == 0) &&
+           (hdr->flow_lbl[1] == 0) && (hdr->flow_lbl[2] == 0)) {
+               /* flow label can be compressed */
+               iphc0 |= LOWPAN_IPHC_FL_C;
+               if((hdr->priority == 0) &&
+                   ((hdr->flow_lbl[0] & 0xF0) == 0)) {
+                       /* compress (elide) all */
+                       iphc0 |= LOWPAN_IPHC_TC_C;
+               } else {
+                       /* compress only the flow label */
+                       *hc06_ptr = tmp;
+                       hc06_ptr += 1;
+               }
+       } else {
+               /* Flow label cannot be compressed */
+               if((hdr->priority == 0) &&
+                   ((hdr->flow_lbl[0] & 0xF0) == 0)) {
+                       /* compress only traffic class */
+                       iphc0 |= LOWPAN_IPHC_TC_C;
+                       *hc06_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F);
+                       memcpy(hc06_ptr + 1, &hdr->flow_lbl[1], 2);
+                       hc06_ptr += 3;
+               } else {
+                       /* compress nothing */
+                       memcpy(hc06_ptr, &hdr, 4);
+                       /* but replace the top byte with the new ECN | DSCP 
format*/
+                       *hc06_ptr = tmp;
+                       hc06_ptr += 4;
+               }
+       }
+
+       /* Note that the payload length is always compressed */
+
+       /* Next header. We compress it if UDP */
+       if(hdr->nexthdr == UIP_PROTO_UDP) {
+               iphc0 |= LOWPAN_IPHC_NH_C;
+       }
+#if 0
+       if(LOWPAN_NH_COMPRESSOR.is_compressable(hdr->proto)) {
+               iphc0 |= LOWPAN_IPHC_NH_C;
+       }
+#endif
+       if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
+               *hc06_ptr = hdr->nexthdr;
+               hc06_ptr += 1;
+       }
+
+       /*
+       * Hop limit
+       * if 1: compress, encoding is 01
+       * if 64: compress, encoding is 10
+       * if 255: compress, encoding is 11
+       * else do not compress
+       */
+       switch(hdr->hop_limit) {
+       case 1:
+               iphc0 |= LOWPAN_IPHC_TTL_1;
+               break;
+       case 64:
+               iphc0 |= LOWPAN_IPHC_TTL_64;
+               break;
+       case 255:
+               iphc0 |= LOWPAN_IPHC_TTL_255;
+               break;
+       default:
+               *hc06_ptr = hdr->hop_limit;
+               hc06_ptr += 1;
+               break;
+       }
+
+       /* source address - cannot be multicast */
+       if (is_addr_unspecified(&hdr->saddr)) {
+               printk("IPHC: compressing unspecified - setting SAC\n");
+               iphc1 |= LOWPAN_IPHC_SAC;
+               iphc1 |= LOWPAN_IPHC_SAM_00;
+       } else if ((context = addr_context_lookup_by_prefix(&hdr->saddr)) != 
NULL) {
+               /* elide the prefix - indicate by CID and set context + SAC */
+               printk("IPHC: compressing src with context - setting CID & SAC 
ctx: %d\n",
+                  context->number);
+               iphc1 |= LOWPAN_IPHC_CID | LOWPAN_IPHC_SAC;
+               head[2] |= context->number << 4;
+
+               /* compession compare with this nodes address (source) */
+               iphc1 |= compress_addr_64(&hc06_ptr, LOWPAN_IPHC_SAM_BIT,
+                                     &hdr->saddr, saddr);
+       /* No context found for this address */
+       } else if (is_addr_link_local(&hdr->saddr)) {
+               iphc1 |= compress_addr_64(&hc06_ptr, LOWPAN_IPHC_SAM_BIT,
+                                     &hdr->saddr, saddr);
+       } else {
+               /* send the full address => SAC = 0, SAM = 00 */
+               iphc1 |= LOWPAN_IPHC_SAM_00; /* 128-bits */
+               memcpy(hc06_ptr, &hdr->saddr.in6_u.u6_addr16[0], 16);
+               hc06_ptr += 16;
+       }
+
+       /* dest address*/
+       if (is_addr_mcast(&hdr->daddr)) {
+               /* Address is multicast, try to compress */
+               iphc1 |= LOWPAN_IPHC_M;
+               if (lowpan_is_mcast_addr_compressable8(&hdr->daddr)) {
+                       iphc1 |= LOWPAN_IPHC_DAM_11;
+                       /* use last byte */
+                       *hc06_ptr = hdr->daddr.in6_u.u6_addr8[15];
+                       hc06_ptr += 1;
+               } else if (lowpan_is_mcast_addr_compressable32(&hdr->daddr)) {
+                       iphc1 |= LOWPAN_IPHC_DAM_10;
+                       /* second byte + the last three */
+                       *hc06_ptr = hdr->daddr.in6_u.u6_addr8[1];
+                       memcpy(hc06_ptr + 1, &hdr->daddr.in6_u.u6_addr8[13], 3);
+                       hc06_ptr += 4;
+               } else if (lowpan_is_mcast_addr_compressable48(&hdr->daddr)) {
+                       iphc1 |= LOWPAN_IPHC_DAM_01;
+                       /* second byte + the last five */
+                       *hc06_ptr = hdr->daddr.in6_u.u6_addr8[1];
+                       memcpy(hc06_ptr + 1, &hdr->daddr.in6_u.u6_addr8[11], 5);
+                       hc06_ptr += 6;
+               } else {
+                       iphc1 |= LOWPAN_IPHC_DAM_00;
+                       /* full address */
+                       memcpy(hc06_ptr, &hdr->daddr.in6_u.u6_addr8[0], 16);
+                       hc06_ptr += 16;
+               }
+       } else {
+               /* Address is unicast, try to compress */
+               if((context = addr_context_lookup_by_prefix(&hdr->daddr)) != 
NULL) {
+                       /* elide the prefix */
+                       iphc1 |= LOWPAN_IPHC_CID | LOWPAN_IPHC_DAC;
+                       head[2] |= context->number;
+
+                       printk("IPHC: compressing dest with context - setting 
CID & DAC ctx: %d\n",
+                          context->number);
+
+                       /* compession compare with link adress (destination) */
+                       iphc1 |= compress_addr_64(&hc06_ptr, 
LOWPAN_IPHC_DAM_BIT,
+                              &hdr->daddr, daddr);
+               /* No context found for this address */
+               } else if(is_addr_link_local(&hdr->daddr)) {
+                       iphc1 |= compress_addr_64(&hc06_ptr, 
LOWPAN_IPHC_DAM_BIT,
+                              &hdr->daddr, daddr);
+               } else {
+                       /* send the full address */
+                       iphc1 |= LOWPAN_IPHC_DAM_00; /* 128-bits */
+                       memcpy(hc06_ptr, &hdr->daddr.in6_u.u6_addr16[0], 16);
+                       hc06_ptr += 16;
+               }
+       }
+
+#ifdef UIP_CONF_UDP
+       /* UDP header compression */
+       if(UIP_IP_BUF->proto == UIP_PROTO_UDP) {
+               prink("IPHC: Uncompressed UDP ports on send side: %x, %x\n",
+                   htons(UIP_UDP_BUF->srcport), htons(UIP_UDP_BUF->destport));
+               /* Mask out the last 4 bits can be used as a mask */
+               if(((htons(UIP_UDP_BUF->srcport) & 0xfff0) == 
LOWPAN_UDP_4_BIT_PORT_MIN) &&
+                   ((htons(UIP_UDP_BUF->destport) & 0xfff0) == 
LOWPAN_UDP_4_BIT_PORT_MIN)) {
+                       /* we can compress 12 bits of both source and dest */
+                       *hc06_ptr = LOWPAN_NHC_UDP_CS_P_11;
+                       prink("IPHC: remove 12 b of both source & dest with 
prefix 0xFOB\n");
+                       *(hc06_ptr + 1) =
+                               (u8_t)((htons(UIP_UDP_BUF->srcport) -
+                                       LOWPAN_UDP_4_BIT_PORT_MIN) << 4) +
+                               (u8_t)((htons(UIP_UDP_BUF->destport) -
+                                       LOWPAN_UDP_4_BIT_PORT_MIN));
+                       hc06_ptr += 2;
+               } else if((htons(UIP_UDP_BUF->destport) & 0xff00) == 
LOWPAN_UDP_8_BIT_PORT_MIN) {
+                       /* we can compress 8 bits of dest, leave source. */
+                       *hc06_ptr = LOWPAN_NHC_UDP_CS_P_01;
+                       prink("IPHC: leave source, remove 8 bits of dest with 
prefix 0xF0\n");
+                       memcpy(hc06_ptr + 1, &UIP_UDP_BUF->srcport, 2);
+                       *(hc06_ptr + 3) =
+                               (u8_t)((htons(UIP_UDP_BUF->destport) -
+                                       LOWPAN_UDP_8_BIT_PORT_MIN));
+                       hc06_ptr += 4;
+               } else if((htons(UIP_UDP_BUF->srcport) & 0xff00) == 
LOWPAN_UDP_8_BIT_PORT_MIN) {
+                       /* we can compress 8 bits of src, leave dest. Copy 
compressed port */
+                       *hc06_ptr = LOWPAN_NHC_UDP_CS_P_10;
+                       prink("IPHC: remove 8 bits of source with prefix 0xF0, 
leave dest. hch: %i\n", *hc06_ptr);
+                       *(hc06_ptr + 1) =
+                               (u8_t)((htons(UIP_UDP_BUF->srcport) -
+                                       LOWPAN_UDP_8_BIT_PORT_MIN));
+                       memcpy(hc06_ptr + 2, &UIP_UDP_BUF->destport, 2);
+                       hc06_ptr += 4;
+               } else {
+                       /* we cannot compress. Copy uncompressed ports, full 
checksum  */
+                       *hc06_ptr = LOWPAN_NHC_UDP_CS_P_00;
+                       prink("IPHC: cannot compress headers\n");
+                       memcpy(hc06_ptr + 1, &UIP_UDP_BUF->srcport, 4);
+                       hc06_ptr += 5;
+               }
+               /* always inline the checksum  */
+               if (1) {
+                       memcpy(hc06_ptr, &UIP_UDP_BUF->udpchksum, 2);
+                       hc06_ptr += 2;
+               }
+               uncomp_hdr_len += UIP_UDPH_LEN;
+       }
+#endif /*UIP_CONF_UDP*/
+
+#ifdef LOWPAN_NH_COMPRESSOR
+       /* if nothing to compress just return zero  */
+       hc06_ptr += LOWPAN_NH_COMPRESSOR.compress(hc06_ptr, &uncomp_hdr_len);
+#endif
+
+       head[0] = iphc0;
+       head[1] = iphc1;
+
+       skb_pull(skb, sizeof(struct ipv6hdr));
+       memcpy(skb_push(skb, hc06_ptr - head), head, hc06_ptr - head);
+
+       printk("JDS - exit - %ld\n", hc06_ptr - head);
+
+       return mac802154_header_create(skb, dev, type, daddr, saddr, skb->len);
+}
+
+static netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       printk("JDS - %s\n", __func__);
+       return mac802154_wpan_xmit(skb, dev);
+}
+
+static int lowpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+       printk("JDS - %s\n", __func__);
+       return mac802154_wpan_ioctl(dev, ifr, cmd);
+}
+
+
+static int lowpan_mac_addr(struct net_device *dev, void *p)
+{
+       printk("JDS - %s\n", __func__);
+       return mac802154_wpan_mac_addr(dev, p);
+}
+
+static struct header_ops lowpan_header_ops = {
+       .create         = lowpan_header_create,
+       .parse          = lowpan_header_parse,
+};
+
+static const struct net_device_ops lowpan_ops = {
+       .ndo_open               = mac802154_slave_open,
+       .ndo_stop               = mac802154_slave_close,
+       .ndo_start_xmit         = lowpan_xmit,
+       .ndo_do_ioctl           = lowpan_ioctl,
+       .ndo_set_mac_address    = lowpan_mac_addr,
+};
+
+void lowpan_setup(struct net_device *dev)
+{
+       struct mac802154_sub_if_data *priv;
+
+       printk("JDS - %s\n", __func__);
+       mac802154_wpan_setup(dev);
+
+       dev->hard_header_len    = 2 + 1 + 20 + 14;
+       dev->header_ops         = &lowpan_header_ops;
+       dev->mtu                = 1280;
+
+       dev->netdev_ops         = &lowpan_ops;
+
+       priv = netdev_priv(dev);
+       priv->chain = lowpan_process_data;
+
+       addr_contexts[0].used = 1;
+       addr_contexts[0].number = 0;
+       addr_contexts[0].prefix[0] = 0xaa; 
+       addr_contexts[0].prefix[1] = 0xaa;
+}
+
diff --git a/net/mac802154/6lowpan.h b/net/mac802154/6lowpan.h
new file mode 100644
index 0000000..50eb5e9
--- /dev/null
+++ b/net/mac802154/6lowpan.h
@@ -0,0 +1,81 @@
+/*
+ * 6lowpan - IPv6 compression on 802.15.4
+ *
+ * Copyright 2010, Jon Smirl <[email protected]>
+ * This code is derived from Contiki - http://www.sics.se/contiki
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+void lowpan_setup(struct net_device *dev);
+
+#define LOWPAN_DISPATCH_IPV6                    0x41 /* 01000001 = 65 */
+#define LOWPAN_DISPATCH_HC1                     0x42 /* 01000010 = 66 */
+#define LOWPAN_DISPATCH_IPHC                    0x60 /* 011xxxxx = ... */
+#define LOWPAN_DISPATCH_FRAG1                   0xc0 /* 11000xxx */
+#define LOWPAN_DISPATCH_FRAGN                   0xe0 /* 11100xxx */
+
+/**
+ * \name IPHC encoding
+ * @{
+ */
+/*
+ * Values of fields within the IPHC encoding first byte
+ * (C stands for compressed and I for inline)
+ */
+#define LOWPAN_IPHC_FL_C                        0x10
+#define LOWPAN_IPHC_TC_C                        0x08
+#define LOWPAN_IPHC_NH_C                        0x04
+#define LOWPAN_IPHC_TTL_1                       0x01
+#define LOWPAN_IPHC_TTL_64                      0x02
+#define LOWPAN_IPHC_TTL_255                     0x03
+#define LOWPAN_IPHC_TTL_I                       0x00
+
+
+/* Values of fields within the IPHC encoding second byte */
+#define LOWPAN_IPHC_CID                         0x80
+
+#define LOWPAN_IPHC_SAC                         0x40
+#define LOWPAN_IPHC_SAM_00                      0x00
+#define LOWPAN_IPHC_SAM_01                      0x10
+#define LOWPAN_IPHC_SAM_10                      0x20
+#define LOWPAN_IPHC_SAM_11                      0x30
+
+#define LOWPAN_IPHC_SAM_BIT                     4
+
+#define LOWPAN_IPHC_M                           0x08
+#define LOWPAN_IPHC_DAC                         0x04
+#define LOWPAN_IPHC_DAM_00                      0x00
+#define LOWPAN_IPHC_DAM_01                      0x01
+#define LOWPAN_IPHC_DAM_10                      0x02
+#define LOWPAN_IPHC_DAM_11                      0x03
+
+#define LOWPAN_IPHC_DAM_BIT                     0
+
+/**
+ * \name LOWPAN_UDP encoding (works together with IPHC)
+ * @{
+ */
+#define LOWPAN_NHC_UDP_MASK                     0xF8
+#define LOWPAN_NHC_UDP_ID                       0xF0
+#define LOWPAN_NHC_UDP_CHECKSUMC                0x04
+#define LOWPAN_NHC_UDP_CHECKSUMI                0x00
+/* values for port compression, _with checksum_ ie bit 5 set to 0 */
+#define LOWPAN_NHC_UDP_CS_P_00  0xF0 /* all inline */
+#define LOWPAN_NHC_UDP_CS_P_01  0xF1 /* source 16bit inline, dest = 0xF0 + 8 
bit inline */
+#define LOWPAN_NHC_UDP_CS_P_10  0xF2 /* source = 0xF0 + 8bit inline, dest = 16 
bit inline */
+#define LOWPAN_NHC_UDP_CS_P_11  0xF3 /* source & dest = 0xF0B + 4bit inline */
+/** @} */
+
+
diff --git a/net/mac802154/Kconfig b/net/mac802154/Kconfig
index 61a3287..a5f49f1 100644
--- a/net/mac802154/Kconfig
+++ b/net/mac802154/Kconfig
@@ -15,3 +15,9 @@ config MAC802154
          say N here. Alternatievly you can say M to compile it as
          module.
 
+config 6LOWPAN
+       bool "6lowpan support over IEEE 802.15.4"
+       depends on MAC802154
+       ---help---
+         IPv6 compression over IEEE 802.15.4.
+         The support will be added to mac802154 module
diff --git a/net/mac802154/Makefile b/net/mac802154/Makefile
index 790b97f..f9e034b 100644
--- a/net/mac802154/Makefile
+++ b/net/mac802154/Makefile
@@ -1,5 +1,9 @@
 obj-$(CONFIG_MAC802154) +=     mac802154.o
-mac802154-objs         := rx.o tx.o main.o monitor.o wpan.o mac_cmd.o scan.o 
mib.o \
+mac802154-y            := rx.o tx.o main.o monitor.o wpan.o mac_cmd.o scan.o 
mib.o \
                        beacon.o beacon_hash.o smac.o
+mac802154-$(CONFIG_6LOWPAN) += 6lowpan.o
+
+mac802154-objs                 := $(mac802154-y)
+
 
 EXTRA_CFLAGS += -Wall -DDEBUG
diff --git a/net/mac802154/mac802154.h b/net/mac802154/mac802154.h
index ef1d776..7bcb8ee 100644
--- a/net/mac802154/mac802154.h
+++ b/net/mac802154/mac802154.h
@@ -69,12 +69,17 @@ struct mac802154_wpan_mib {
        u8 dsn;
 };
 
+typedef int (*process_data_chain)(struct net_device *dev, struct sk_buff *skb, 
+               unsigned char _saddr[IEEE802154_ALEN], unsigned char 
_daddr[IEEE802154_ALEN]);
+
 struct mac802154_sub_if_data {
        struct list_head list; /* the ieee802154_priv->slaves list */
 
        struct mac802154_priv *hw;
        struct net_device *dev;
 
+       process_data_chain chain;
+
        int type;
 
        spinlock_t mib_lock;
@@ -122,4 +127,16 @@ int mac802154_slave_close(struct net_device *dev);
 
 netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb,
                u8 page, u8 chan);
+
+int mac802154_header_create(struct sk_buff *skb,
+                          struct net_device *dev,
+                          unsigned short type, const void *_daddr,
+                          const void *_saddr, unsigned len);
+int mac802154_wpan_mac_addr(struct net_device *dev, void *p);
+int mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr,
+               int cmd);
+netdev_tx_t mac802154_wpan_xmit(struct sk_buff *skb, struct net_device *dev);
+int mac802154_header_parse(const struct sk_buff *skb,
+               unsigned char *haddr);
+
 #endif
diff --git a/net/mac802154/main.c b/net/mac802154/main.c
index 957098e..73460f9 100644
--- a/net/mac802154/main.c
+++ b/net/mac802154/main.c
@@ -27,6 +27,7 @@
 
 #include "mac802154.h"
 #include "mib.h"
+#include "6lowpan.h"
 
 int mac802154_slave_open(struct net_device *dev)
 {
@@ -139,6 +140,10 @@ static struct net_device *mac802154_add_iface(struct 
wpan_phy *phy,
                dev = alloc_netdev(sizeof(struct mac802154_sub_if_data),
                                name, mac802154_wpan_setup);
                break;
+       case IEEE802154_DEV_6LOWPAN:
+               dev = alloc_netdev(sizeof(struct mac802154_sub_if_data),
+                               name, lowpan_setup);
+               break;
        case IEEE802154_DEV_MONITOR:
                dev = alloc_netdev(sizeof(struct mac802154_sub_if_data),
                                name, mac802154_monitor_setup);
diff --git a/net/mac802154/wpan.c b/net/mac802154/wpan.c
index d4d1b7f..542a805 100644
--- a/net/mac802154/wpan.c
+++ b/net/mac802154/wpan.c
@@ -39,7 +39,18 @@
 #include "mac802154.h"
 #include "mib.h"
 
-static netdev_tx_t mac802154_wpan_xmit(struct sk_buff *skb, struct net_device 
*dev)
+#define is_addr_broadcast(a)   \
+  ((((a)[0]) == 0xFF) &&       \
+   (((a)[1]) == 0xFF) &&       \
+   (((a)[2]) == 0xFF) &&       \
+   (((a)[3]) == 0xFF) &&       \
+   (((a)[4]) == 0xFF) &&       \
+   (((a)[5]) == 0xFF) &&       \
+   (((a)[6]) == 0xFF) &&       \
+   (((a)[7]) == 0xFF))
+
+
+netdev_tx_t mac802154_wpan_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct mac802154_sub_if_data *priv;
        u8 chan, page;
@@ -64,7 +75,7 @@ static netdev_tx_t mac802154_wpan_xmit(struct sk_buff *skb, 
struct net_device *d
        return mac802154_tx(priv->hw, skb, page, chan);
 }
 
-static int mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr,
+int mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr,
                int cmd)
 {
        struct mac802154_sub_if_data *priv = netdev_priv(dev);
@@ -110,7 +121,7 @@ static int mac802154_wpan_ioctl(struct net_device *dev, 
struct ifreq *ifr,
        return err;
 }
 
-static int mac802154_wpan_mac_addr(struct net_device *dev, void *p)
+int mac802154_wpan_mac_addr(struct net_device *dev, void *p)
 {
        struct sockaddr *addr = p;
 
@@ -129,7 +140,7 @@ static void mac802154_haddr_copy_swap(u8 *dest, const u8 
*src)
                dest[IEEE802154_ADDR_LEN - i - 1] = src[i];
 }
 
-static int mac802154_header_create(struct sk_buff *skb,
+int mac802154_header_create(struct sk_buff *skb,
                           struct net_device *dev,
                           unsigned short type, const void *_daddr,
                           const void *_saddr, unsigned len)
@@ -138,76 +149,44 @@ static int mac802154_header_create(struct sk_buff *skb,
        int pos = 0;
 
        u16 fc;
-       const struct ieee802154_addr *saddr = _saddr;
-       const struct ieee802154_addr *daddr = _daddr;
-       struct ieee802154_addr dev_addr;
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
+       const u8 *saddr = _saddr;
+       const u8 *daddr = _daddr;
 
-       fc = mac_cb_type(skb);
+       fc = IEEE802154_FC_TYPE_DATA;
        if (mac_cb_is_ackreq(skb))
                fc |= IEEE802154_FC_ACK_REQ;
 
-       pos = 2;
+       pos = 2; /* leave room for fc */
 
        head[pos++] = mac_cb(skb)->seq; /* DSN/BSN */
 
        if (!daddr)
                return -EINVAL;
 
-       if (!saddr) {
-               spin_lock_bh(&priv->mib_lock);
-               if (priv->short_addr == IEEE802154_ADDR_BROADCAST ||
-                   priv->short_addr == IEEE802154_ADDR_UNDEF ||
-                   priv->pan_id == IEEE802154_PANID_BROADCAST) {
-                       dev_addr.addr_type = IEEE802154_ADDR_LONG;
-                       memcpy(dev_addr.hwaddr, dev->dev_addr,
-                                       IEEE802154_ADDR_LEN);
-               } else {
-                       dev_addr.addr_type = IEEE802154_ADDR_SHORT;
-                       dev_addr.short_addr = priv->short_addr;
-               }
-
-               dev_addr.pan_id = priv->pan_id;
-               saddr = &dev_addr;
-
-               spin_unlock_bh(&priv->mib_lock);
-       }
-
-       if (daddr->addr_type != IEEE802154_ADDR_NONE) {
-               fc |= (daddr->addr_type << IEEE802154_FC_DAMODE_SHIFT);
-
-               head[pos++] = daddr->pan_id & 0xff;
-               head[pos++] = daddr->pan_id >> 8;
-
-               if (daddr->addr_type == IEEE802154_ADDR_SHORT) {
-                       head[pos++] = daddr->short_addr & 0xff;
-                       head[pos++] = daddr->short_addr >> 8;
-               } else {
-                       mac802154_haddr_copy_swap(head + pos, daddr->hwaddr);
-                       pos += IEEE802154_ADDR_LEN;
-               }
+       /* force long address mode */
+       if(!_saddr)
+               saddr = dev->dev_addr;
+
+       /* panid*/
+       head[pos++] = 0xCD;
+       head[pos++] = 0xAB;
+       
+       if (is_addr_broadcast(daddr)) {
+               fc |= (IEEE802154_ADDR_SHORT << IEEE802154_FC_DAMODE_SHIFT);
+               head[pos++] = 0xff;
+               head[pos++] = 0xff;
+       } else {
+               /* force long for contiki */
+               fc |= (IEEE802154_ADDR_LONG << IEEE802154_FC_DAMODE_SHIFT);
+               mac802154_haddr_copy_swap(head + pos, daddr);
+               pos += IEEE802154_ADDR_LEN;
        }
 
-       if (saddr->addr_type != IEEE802154_ADDR_NONE) {
-               fc |= (saddr->addr_type << IEEE802154_FC_SAMODE_SHIFT);
-
-               if ((saddr->pan_id == daddr->pan_id) &&
-                   (saddr->pan_id != IEEE802154_PANID_BROADCAST))
-                       /* PANID compression/ intra PAN */
-                       fc |= IEEE802154_FC_INTRA_PAN;
-               else {
-                       head[pos++] = saddr->pan_id & 0xff;
-                       head[pos++] = saddr->pan_id >> 8;
-               }
+       fc |= (IEEE802154_ADDR_LONG << IEEE802154_FC_SAMODE_SHIFT);
+       fc |= IEEE802154_FC_INTRA_PAN;
 
-               if (saddr->addr_type == IEEE802154_ADDR_SHORT) {
-                       head[pos++] = saddr->short_addr & 0xff;
-                       head[pos++] = saddr->short_addr >> 8;
-               } else {
-                       mac802154_haddr_copy_swap(head + pos, saddr->hwaddr);
-                       pos += IEEE802154_ADDR_LEN;
-               }
-       }
+       mac802154_haddr_copy_swap(head + pos, saddr);
+       pos += IEEE802154_ADDR_LEN;          
 
        head[0] = fc;
        head[1] = fc >> 8;
@@ -217,7 +196,7 @@ static int mac802154_header_create(struct sk_buff *skb,
        return pos;
 }
 
-static int mac802154_header_parse(const struct sk_buff *skb,
+int mac802154_header_parse(const struct sk_buff *skb,
                unsigned char *haddr)
 {
        const u8 *hdr = skb_mac_header(skb), *tail = skb_tail_pointer(skb);
@@ -374,6 +353,13 @@ static int mac802154_process_ack(struct net_device *dev, 
struct sk_buff *skb)
 
 static int mac802154_process_data(struct net_device *dev, struct sk_buff *skb)
 {
+       struct mac802154_sub_if_data *priv = netdev_priv(dev);
+
+       printk("JDS - %s\n", __func__);
+
+       if (priv->chain)
+               return priv->chain(dev, skb, mac_cb(skb)->sa.hwaddr, 
mac_cb(skb)->da.hwaddr);
+
        if (in_interrupt())
                return netif_rx(skb);
        else
@@ -411,11 +397,15 @@ static int mac802154_subif_frame(struct 
mac802154_sub_if_data *sdata,
                if (mac_cb(skb)->da.pan_id != sdata->pan_id &&
                    mac_cb(skb)->da.pan_id != IEEE802154_PANID_BROADCAST)
                        skb->pkt_type = PACKET_OTHERHOST;
-               else if (mac_cb(skb)->da.short_addr == sdata->short_addr)
-                       skb->pkt_type = PACKET_HOST;
+               /* check if it's broadcast before host */
+               /* otherwise if we've set our address to 0xffff we */
+               /* incorrectly id broadcasts as host */
+               /* should probably get pushed up stream */
                else if (mac_cb(skb)->da.short_addr ==
                                        IEEE802154_ADDR_BROADCAST)
                        skb->pkt_type = PACKET_BROADCAST;
+               else if (mac_cb(skb)->da.short_addr == sdata->short_addr)
+                       skb->pkt_type = PACKET_HOST;
                else
                        skb->pkt_type = PACKET_OTHERHOST;
                break;


------------------------------------------------------------------------------
Sell apps to millions through the Intel(R) Atom(Tm) Developer Program
Be part of this innovative community and reach millions of netbook users 
worldwide. Take advantage of special opportunities to increase revenue and 
speed time-to-market. Join now, and jumpstart your future.
http://p.sf.net/sfu/intel-atom-d2d
_______________________________________________
Linux-zigbee-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/linux-zigbee-devel

Reply via email to