Merge tag 'usb-4.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
[deliverable/linux.git] / net / 6lowpan / iphc.c
index 8501dd532fe1c59f7ba7fc3fe608926fbe2d5f9a..79f1fa22509a350b35340897c1cb137357734713 100644 (file)
@@ -761,22 +761,75 @@ static const u8 lowpan_iphc_dam_to_sam_value[] = {
        [LOWPAN_IPHC_DAM_11] = LOWPAN_IPHC_SAM_11,
 };
 
-static u8 lowpan_compress_ctx_addr(u8 **hc_ptr, const struct in6_addr *ipaddr,
+static inline bool
+lowpan_iphc_compress_ctx_802154_lladdr(const struct in6_addr *ipaddr,
+                                      const struct lowpan_iphc_ctx *ctx,
+                                      const void *lladdr)
+{
+       const struct ieee802154_addr *addr = lladdr;
+       unsigned char extended_addr[EUI64_ADDR_LEN];
+       bool lladdr_compress = false;
+       struct in6_addr tmp = {};
+
+       switch (addr->mode) {
+       case IEEE802154_ADDR_LONG:
+               ieee802154_le64_to_be64(&extended_addr, &addr->extended_addr);
+               /* check for SAM/DAM = 11 */
+               memcpy(&tmp.s6_addr[8], &extended_addr, EUI64_ADDR_LEN);
+               /* second bit-flip (Universe/Local) is done according RFC2464 */
+               tmp.s6_addr[8] ^= 0x02;
+               /* context information are always used */
+               ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen);
+               if (ipv6_addr_equal(&tmp, ipaddr))
+                       lladdr_compress = true;
+               break;
+       case IEEE802154_ADDR_SHORT:
+               tmp.s6_addr[11] = 0xFF;
+               tmp.s6_addr[12] = 0xFE;
+               ieee802154_le16_to_be16(&tmp.s6_addr16[7],
+                                       &addr->short_addr);
+               /* context information are always used */
+               ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen);
+               if (ipv6_addr_equal(&tmp, ipaddr))
+                       lladdr_compress = true;
+               break;
+       default:
+               /* should never handled and filtered by 802154 6lowpan */
+               WARN_ON_ONCE(1);
+               break;
+       }
+
+       return lladdr_compress;
+}
+
+static u8 lowpan_compress_ctx_addr(u8 **hc_ptr, const struct net_device *dev,
+                                  const struct in6_addr *ipaddr,
                                   const struct lowpan_iphc_ctx *ctx,
                                   const unsigned char *lladdr, bool sam)
 {
        struct in6_addr tmp = {};
        u8 dam;
 
-       /* check for SAM/DAM = 11 */
-       memcpy(&tmp.s6_addr[8], lladdr, 8);
-       /* second bit-flip (Universe/Local) is done according RFC2464 */
-       tmp.s6_addr[8] ^= 0x02;
-       /* context information are always used */
-       ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen);
-       if (ipv6_addr_equal(&tmp, ipaddr)) {
-               dam = LOWPAN_IPHC_DAM_11;
-               goto out;
+       switch (lowpan_dev(dev)->lltype) {
+       case LOWPAN_LLTYPE_IEEE802154:
+               if (lowpan_iphc_compress_ctx_802154_lladdr(ipaddr, ctx,
+                                                          lladdr)) {
+                       dam = LOWPAN_IPHC_DAM_11;
+                       goto out;
+               }
+               break;
+       default:
+               /* check for SAM/DAM = 11 */
+               memcpy(&tmp.s6_addr[8], lladdr, EUI64_ADDR_LEN);
+               /* second bit-flip (Universe/Local) is done according RFC2464 */
+               tmp.s6_addr[8] ^= 0x02;
+               /* context information are always used */
+               ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen);
+               if (ipv6_addr_equal(&tmp, ipaddr)) {
+                       dam = LOWPAN_IPHC_DAM_11;
+                       goto out;
+               }
+               break;
        }
 
        memset(&tmp, 0, sizeof(tmp));
@@ -813,28 +866,85 @@ out:
                return dam;
 }
 
-static u8 lowpan_compress_addr_64(u8 **hc_ptr, const struct in6_addr *ipaddr,
+static inline bool
+lowpan_iphc_compress_802154_lladdr(const struct in6_addr *ipaddr,
+                                  const void *lladdr)
+{
+       const struct ieee802154_addr *addr = lladdr;
+       unsigned char extended_addr[EUI64_ADDR_LEN];
+       bool lladdr_compress = false;
+       struct in6_addr tmp = {};
+
+       switch (addr->mode) {
+       case IEEE802154_ADDR_LONG:
+               ieee802154_le64_to_be64(&extended_addr, &addr->extended_addr);
+               if (is_addr_mac_addr_based(ipaddr, extended_addr))
+                       lladdr_compress = true;
+               break;
+       case IEEE802154_ADDR_SHORT:
+               /* fe:80::ff:fe00:XXXX
+                *                \__/
+                *             short_addr
+                *
+                * Universe/Local bit is zero.
+                */
+               tmp.s6_addr[0] = 0xFE;
+               tmp.s6_addr[1] = 0x80;
+               tmp.s6_addr[11] = 0xFF;
+               tmp.s6_addr[12] = 0xFE;
+               ieee802154_le16_to_be16(&tmp.s6_addr16[7],
+                                       &addr->short_addr);
+               if (ipv6_addr_equal(&tmp, ipaddr))
+                       lladdr_compress = true;
+               break;
+       default:
+               /* should never handled and filtered by 802154 6lowpan */
+               WARN_ON_ONCE(1);
+               break;
+       }
+
+       return lladdr_compress;
+}
+
+static u8 lowpan_compress_addr_64(u8 **hc_ptr, const struct net_device *dev,
+                                 const struct in6_addr *ipaddr,
                                  const unsigned char *lladdr, bool sam)
 {
-       u8 dam = LOWPAN_IPHC_DAM_00;
+       u8 dam = LOWPAN_IPHC_DAM_01;
 
-       if (is_addr_mac_addr_based(ipaddr, lladdr)) {
-               dam = LOWPAN_IPHC_DAM_11; /* 0-bits */
-               pr_debug("address compression 0 bits\n");
-       } else if (lowpan_is_iid_16_bit_compressable(ipaddr)) {
+       switch (lowpan_dev(dev)->lltype) {
+       case LOWPAN_LLTYPE_IEEE802154:
+               if (lowpan_iphc_compress_802154_lladdr(ipaddr, lladdr)) {
+                       dam = LOWPAN_IPHC_DAM_11; /* 0-bits */
+                       pr_debug("address compression 0 bits\n");
+                       goto out;
+               }
+               break;
+       default:
+               if (is_addr_mac_addr_based(ipaddr, lladdr)) {
+                       dam = LOWPAN_IPHC_DAM_11; /* 0-bits */
+                       pr_debug("address compression 0 bits\n");
+                       goto out;
+               }
+               break;
+       }
+
+       if (lowpan_is_iid_16_bit_compressable(ipaddr)) {
                /* compress IID to 16 bits xxxx::XXXX */
                lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[7], 2);
                dam = LOWPAN_IPHC_DAM_10; /* 16-bits */
                raw_dump_inline(NULL, "Compressed ipv6 addr is (16 bits)",
                                *hc_ptr - 2, 2);
-       } else {
-               /* do not compress IID => xxxx::IID */
-               lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[4], 8);
-               dam = LOWPAN_IPHC_DAM_01; /* 64-bits */
-               raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)",
-                               *hc_ptr - 8, 8);
+               goto out;
        }
 
+       /* do not compress IID => xxxx::IID */
+       lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[4], 8);
+       raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)",
+                       *hc_ptr - 8, 8);
+
+out:
+
        if (sam)
                return lowpan_iphc_dam_to_sam_value[dam];
        else
@@ -1013,9 +1123,6 @@ int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
        iphc0 = LOWPAN_DISPATCH_IPHC;
        iphc1 = 0;
 
-       raw_dump_inline(__func__, "saddr", saddr, EUI64_ADDR_LEN);
-       raw_dump_inline(__func__, "daddr", daddr, EUI64_ADDR_LEN);
-
        raw_dump_table(__func__, "sending raw skb network uncompressed packet",
                       skb->data, skb->len);
 
@@ -1088,14 +1195,15 @@ int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
                iphc1 |= LOWPAN_IPHC_SAC;
        } else {
                if (sci) {
-                       iphc1 |= lowpan_compress_ctx_addr(&hc_ptr, &hdr->saddr,
+                       iphc1 |= lowpan_compress_ctx_addr(&hc_ptr, dev,
+                                                         &hdr->saddr,
                                                          &sci_entry, saddr,
                                                          true);
                        iphc1 |= LOWPAN_IPHC_SAC;
                } else {
                        if (ipv6_saddr_type & IPV6_ADDR_LINKLOCAL &&
                            lowpan_is_linklocal_zero_padded(hdr->saddr)) {
-                               iphc1 |= lowpan_compress_addr_64(&hc_ptr,
+                               iphc1 |= lowpan_compress_addr_64(&hc_ptr, dev,
                                                                 &hdr->saddr,
                                                                 saddr, true);
                                pr_debug("source address unicast link-local %pI6c iphc1 0x%02x\n",
@@ -1123,14 +1231,15 @@ int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
                }
        } else {
                if (dci) {
-                       iphc1 |= lowpan_compress_ctx_addr(&hc_ptr, &hdr->daddr,
+                       iphc1 |= lowpan_compress_ctx_addr(&hc_ptr, dev,
+                                                         &hdr->daddr,
                                                          &dci_entry, daddr,
                                                          false);
                        iphc1 |= LOWPAN_IPHC_DAC;
                } else {
                        if (ipv6_daddr_type & IPV6_ADDR_LINKLOCAL &&
                            lowpan_is_linklocal_zero_padded(hdr->daddr)) {
-                               iphc1 |= lowpan_compress_addr_64(&hc_ptr,
+                               iphc1 |= lowpan_compress_addr_64(&hc_ptr, dev,
                                                                 &hdr->daddr,
                                                                 daddr, false);
                                pr_debug("dest address unicast link-local %pI6c iphc1 0x%02x\n",
This page took 0.029764 seconds and 5 git commands to generate.