Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[firefly-linux-kernel-4.4.55.git] / net / ieee802154 / 6lowpan.c
index 276971ba3ade5dd998d576a8a49b9fb0f6262550..55e1fd5b3e56d4ede22c2a05a6f72cc3b4bffa44 100644 (file)
@@ -104,7 +104,7 @@ static const u8 lowpan_llprefix[] = {0xfe, 0x80};
 struct lowpan_dev_info {
        struct net_device       *real_dev; /* real WPAN device ptr */
        struct mutex            dev_list_mtx; /* mutex for list ops */
-       unsigned short fragment_tag;
+       unsigned short          fragment_tag;
 };
 
 struct lowpan_dev_record {
@@ -284,6 +284,9 @@ lowpan_compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb)
        /* checksum is always inline */
        memcpy(*hc06_ptr, &uh->check, 2);
        *hc06_ptr += 2;
+
+       /* skip the UDP header */
+       skb_pull(skb, sizeof(struct udphdr));
 }
 
 static inline int lowpan_fetch_skb_u8(struct sk_buff *skb, u8 *val)
@@ -309,9 +312,8 @@ static inline int lowpan_fetch_skb_u16(struct sk_buff *skb, u16 *val)
 }
 
 static int
-lowpan_uncompress_udp_header(struct sk_buff *skb)
+lowpan_uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh)
 {
-       struct udphdr *uh = udp_hdr(skb);
        u8 tmp;
 
        if (!uh)
@@ -358,6 +360,14 @@ lowpan_uncompress_udp_header(struct sk_buff *skb)
                /* copy checksum */
                memcpy(&uh->check, &skb->data[0], 2);
                skb_pull(skb, 2);
+
+               /*
+                * UDP lenght needs to be infered from the lower layers
+                * here, we obtain the hint from the remaining size of the
+                * frame
+                */
+               uh->len = htons(skb->len + sizeof(struct udphdr));
+               pr_debug("uncompressed UDP length: src = %d", uh->len);
        } else {
                pr_debug("ERROR: unsupported NH format\n");
                goto err;
@@ -592,7 +602,7 @@ static int lowpan_header_create(struct sk_buff *skb,
                        da.short_addr = IEEE802154_ADDR_BROADCAST;
                } else {
                        da.addr_type = IEEE802154_ADDR_LONG;
-                       memcpy(&(da.hwaddr), daddr, 8);
+                       memcpy(&(da.hwaddr), daddr, IEEE802154_ADDR_LEN);
 
                        /* request acknowledgment */
                        mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ;
@@ -944,8 +954,31 @@ lowpan_process_data(struct sk_buff *skb)
 
        /* UDP data uncompression */
        if (iphc0 & LOWPAN_IPHC_NH_C) {
-               if (lowpan_uncompress_udp_header(skb))
+               struct udphdr uh;
+               struct sk_buff *new;
+               if (lowpan_uncompress_udp_header(skb, &uh))
                        goto drop;
+
+               /*
+                * replace the compressed UDP head by the uncompressed UDP
+                * header
+                */
+               new = skb_copy_expand(skb, sizeof(struct udphdr),
+                                     skb_tailroom(skb), GFP_ATOMIC);
+               kfree_skb(skb);
+
+               if (!new)
+                       return -ENOMEM;
+
+               skb = new;
+
+               skb_push(skb, sizeof(struct udphdr));
+               skb_reset_transport_header(skb);
+               skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr));
+
+               lowpan_raw_dump_table(__func__, "raw UDP header dump",
+                                     (u8 *)&uh, sizeof(uh));
+
                hdr.nexthdr = UIP_PROTO_UDP;
        }
 
@@ -1106,10 +1139,10 @@ static netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *dev)
 error:
        dev_kfree_skb(skb);
 out:
-       if (err < 0)
+       if (err)
                pr_debug("ERROR: xmit failed\n");
 
-       return (err < 0 ? NETDEV_TX_BUSY : NETDEV_TX_OK);
+       return (err < 0) ? NET_XMIT_DROP : err;
 }
 
 static struct wpan_phy *lowpan_get_phy(const struct net_device *dev)