|
@@ -49,36 +49,178 @@
|
|
|
#include <linux/bitops.h>
|
|
|
#include <linux/if_arp.h>
|
|
|
#include <linux/netdevice.h>
|
|
|
+
|
|
|
#include <net/6lowpan.h>
|
|
|
#include <net/ipv6.h>
|
|
|
-#include <net/af_ieee802154.h>
|
|
|
+
|
|
|
+/* special link-layer handling */
|
|
|
+#include <net/mac802154.h>
|
|
|
|
|
|
#include "nhc.h"
|
|
|
|
|
|
+/* Values of fields within the IPHC encoding first byte */
|
|
|
+#define LOWPAN_IPHC_TF_MASK 0x18
|
|
|
+#define LOWPAN_IPHC_TF_00 0x00
|
|
|
+#define LOWPAN_IPHC_TF_01 0x08
|
|
|
+#define LOWPAN_IPHC_TF_10 0x10
|
|
|
+#define LOWPAN_IPHC_TF_11 0x18
|
|
|
+
|
|
|
+#define LOWPAN_IPHC_NH 0x04
|
|
|
+
|
|
|
+#define LOWPAN_IPHC_HLIM_MASK 0x03
|
|
|
+#define LOWPAN_IPHC_HLIM_00 0x00
|
|
|
+#define LOWPAN_IPHC_HLIM_01 0x01
|
|
|
+#define LOWPAN_IPHC_HLIM_10 0x02
|
|
|
+#define LOWPAN_IPHC_HLIM_11 0x03
|
|
|
+
|
|
|
+/* Values of fields within the IPHC encoding second byte */
|
|
|
+#define LOWPAN_IPHC_CID 0x80
|
|
|
+
|
|
|
+#define LOWPAN_IPHC_SAC 0x40
|
|
|
+
|
|
|
+#define LOWPAN_IPHC_SAM_MASK 0x30
|
|
|
+#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_M 0x08
|
|
|
+
|
|
|
+#define LOWPAN_IPHC_DAC 0x04
|
|
|
+
|
|
|
+#define LOWPAN_IPHC_DAM_MASK 0x03
|
|
|
+#define LOWPAN_IPHC_DAM_00 0x00
|
|
|
+#define LOWPAN_IPHC_DAM_01 0x01
|
|
|
+#define LOWPAN_IPHC_DAM_10 0x02
|
|
|
+#define LOWPAN_IPHC_DAM_11 0x03
|
|
|
+
|
|
|
+/* ipv6 address based on mac
|
|
|
+ * second bit-flip (Universe/Local) is done according RFC2464
|
|
|
+ */
|
|
|
+#define is_addr_mac_addr_based(a, m) \
|
|
|
+ ((((a)->s6_addr[8]) == (((m)[0]) ^ 0x02)) && \
|
|
|
+ (((a)->s6_addr[9]) == (m)[1]) && \
|
|
|
+ (((a)->s6_addr[10]) == (m)[2]) && \
|
|
|
+ (((a)->s6_addr[11]) == (m)[3]) && \
|
|
|
+ (((a)->s6_addr[12]) == (m)[4]) && \
|
|
|
+ (((a)->s6_addr[13]) == (m)[5]) && \
|
|
|
+ (((a)->s6_addr[14]) == (m)[6]) && \
|
|
|
+ (((a)->s6_addr[15]) == (m)[7]))
|
|
|
+
|
|
|
+/* check whether we can compress the IID to 16 bits,
|
|
|
+ * it's possible for unicast addresses with first 49 bits are zero only.
|
|
|
+ */
|
|
|
+#define lowpan_is_iid_16_bit_compressable(a) \
|
|
|
+ ((((a)->s6_addr16[4]) == 0) && \
|
|
|
+ (((a)->s6_addr[10]) == 0) && \
|
|
|
+ (((a)->s6_addr[11]) == 0xff) && \
|
|
|
+ (((a)->s6_addr[12]) == 0xfe) && \
|
|
|
+ (((a)->s6_addr[13]) == 0))
|
|
|
+
|
|
|
+/* check whether the 112-bit gid of the multicast address is mappable to: */
|
|
|
+
|
|
|
+/* 48 bits, FFXX::00XX:XXXX:XXXX */
|
|
|
+#define lowpan_is_mcast_addr_compressable48(a) \
|
|
|
+ ((((a)->s6_addr16[1]) == 0) && \
|
|
|
+ (((a)->s6_addr16[2]) == 0) && \
|
|
|
+ (((a)->s6_addr16[3]) == 0) && \
|
|
|
+ (((a)->s6_addr16[4]) == 0) && \
|
|
|
+ (((a)->s6_addr[10]) == 0))
|
|
|
+
|
|
|
+/* 32 bits, FFXX::00XX:XXXX */
|
|
|
+#define lowpan_is_mcast_addr_compressable32(a) \
|
|
|
+ ((((a)->s6_addr16[1]) == 0) && \
|
|
|
+ (((a)->s6_addr16[2]) == 0) && \
|
|
|
+ (((a)->s6_addr16[3]) == 0) && \
|
|
|
+ (((a)->s6_addr16[4]) == 0) && \
|
|
|
+ (((a)->s6_addr16[5]) == 0) && \
|
|
|
+ (((a)->s6_addr[12]) == 0))
|
|
|
+
|
|
|
+/* 8 bits, FF02::00XX */
|
|
|
+#define lowpan_is_mcast_addr_compressable8(a) \
|
|
|
+ ((((a)->s6_addr[1]) == 2) && \
|
|
|
+ (((a)->s6_addr16[1]) == 0) && \
|
|
|
+ (((a)->s6_addr16[2]) == 0) && \
|
|
|
+ (((a)->s6_addr16[3]) == 0) && \
|
|
|
+ (((a)->s6_addr16[4]) == 0) && \
|
|
|
+ (((a)->s6_addr16[5]) == 0) && \
|
|
|
+ (((a)->s6_addr16[6]) == 0) && \
|
|
|
+ (((a)->s6_addr[14]) == 0))
|
|
|
+
|
|
|
+static inline void iphc_uncompress_eui64_lladdr(struct in6_addr *ipaddr,
|
|
|
+ const void *lladdr)
|
|
|
+{
|
|
|
+ /* fe:80::XXXX:XXXX:XXXX:XXXX
|
|
|
+ * \_________________/
|
|
|
+ * hwaddr
|
|
|
+ */
|
|
|
+ ipaddr->s6_addr[0] = 0xFE;
|
|
|
+ ipaddr->s6_addr[1] = 0x80;
|
|
|
+ memcpy(&ipaddr->s6_addr[8], lladdr, EUI64_ADDR_LEN);
|
|
|
+ /* second bit-flip (Universe/Local)
|
|
|
+ * is done according RFC2464
|
|
|
+ */
|
|
|
+ ipaddr->s6_addr[8] ^= 0x02;
|
|
|
+}
|
|
|
+
|
|
|
+static inline void iphc_uncompress_802154_lladdr(struct in6_addr *ipaddr,
|
|
|
+ const void *lladdr)
|
|
|
+{
|
|
|
+ const struct ieee802154_addr *addr = lladdr;
|
|
|
+ u8 eui64[EUI64_ADDR_LEN] = { };
|
|
|
+
|
|
|
+ switch (addr->mode) {
|
|
|
+ case IEEE802154_ADDR_LONG:
|
|
|
+ ieee802154_le64_to_be64(eui64, &addr->extended_addr);
|
|
|
+ iphc_uncompress_eui64_lladdr(ipaddr, eui64);
|
|
|
+ break;
|
|
|
+ case IEEE802154_ADDR_SHORT:
|
|
|
+ /* fe:80::ff:fe00:XXXX
|
|
|
+ * \__/
|
|
|
+ * short_addr
|
|
|
+ *
|
|
|
+ * Universe/Local bit is zero.
|
|
|
+ */
|
|
|
+ ipaddr->s6_addr[0] = 0xFE;
|
|
|
+ ipaddr->s6_addr[1] = 0x80;
|
|
|
+ ipaddr->s6_addr[11] = 0xFF;
|
|
|
+ ipaddr->s6_addr[12] = 0xFE;
|
|
|
+ ieee802154_le16_to_be16(&ipaddr->s6_addr16[7],
|
|
|
+ &addr->short_addr);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ /* should never handled and filtered by 802154 6lowpan */
|
|
|
+ WARN_ON_ONCE(1);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/* Uncompress address function for source and
|
|
|
* destination address(non-multicast).
|
|
|
*
|
|
|
- * address_mode is sam value or dam value.
|
|
|
+ * address_mode is the masked value for sam or dam value
|
|
|
*/
|
|
|
-static int uncompress_addr(struct sk_buff *skb,
|
|
|
- struct in6_addr *ipaddr, const u8 address_mode,
|
|
|
- const u8 *lladdr, const u8 addr_type,
|
|
|
- const u8 addr_len)
|
|
|
+static int uncompress_addr(struct sk_buff *skb, const struct net_device *dev,
|
|
|
+ struct in6_addr *ipaddr, u8 address_mode,
|
|
|
+ const void *lladdr)
|
|
|
{
|
|
|
bool fail;
|
|
|
|
|
|
switch (address_mode) {
|
|
|
- case LOWPAN_IPHC_ADDR_00:
|
|
|
+ /* SAM and DAM are the same here */
|
|
|
+ case LOWPAN_IPHC_DAM_00:
|
|
|
/* for global link addresses */
|
|
|
fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16);
|
|
|
break;
|
|
|
- case LOWPAN_IPHC_ADDR_01:
|
|
|
+ case LOWPAN_IPHC_SAM_01:
|
|
|
+ case LOWPAN_IPHC_DAM_01:
|
|
|
/* fe:80::XXXX:XXXX:XXXX:XXXX */
|
|
|
ipaddr->s6_addr[0] = 0xFE;
|
|
|
ipaddr->s6_addr[1] = 0x80;
|
|
|
fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[8], 8);
|
|
|
break;
|
|
|
- case LOWPAN_IPHC_ADDR_02:
|
|
|
+ case LOWPAN_IPHC_SAM_10:
|
|
|
+ case LOWPAN_IPHC_DAM_10:
|
|
|
/* fe:80::ff:fe00:XXXX */
|
|
|
ipaddr->s6_addr[0] = 0xFE;
|
|
|
ipaddr->s6_addr[1] = 0x80;
|
|
@@ -86,38 +228,16 @@ static int uncompress_addr(struct sk_buff *skb,
|
|
|
ipaddr->s6_addr[12] = 0xFE;
|
|
|
fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[14], 2);
|
|
|
break;
|
|
|
- case LOWPAN_IPHC_ADDR_03:
|
|
|
+ case LOWPAN_IPHC_SAM_11:
|
|
|
+ case LOWPAN_IPHC_DAM_11:
|
|
|
fail = false;
|
|
|
- switch (addr_type) {
|
|
|
- case IEEE802154_ADDR_LONG:
|
|
|
- /* fe:80::XXXX:XXXX:XXXX:XXXX
|
|
|
- * \_________________/
|
|
|
- * hwaddr
|
|
|
- */
|
|
|
- ipaddr->s6_addr[0] = 0xFE;
|
|
|
- ipaddr->s6_addr[1] = 0x80;
|
|
|
- memcpy(&ipaddr->s6_addr[8], lladdr, addr_len);
|
|
|
- /* second bit-flip (Universe/Local)
|
|
|
- * is done according RFC2464
|
|
|
- */
|
|
|
- ipaddr->s6_addr[8] ^= 0x02;
|
|
|
- break;
|
|
|
- case IEEE802154_ADDR_SHORT:
|
|
|
- /* fe:80::ff:fe00:XXXX
|
|
|
- * \__/
|
|
|
- * short_addr
|
|
|
- *
|
|
|
- * Universe/Local bit is zero.
|
|
|
- */
|
|
|
- ipaddr->s6_addr[0] = 0xFE;
|
|
|
- ipaddr->s6_addr[1] = 0x80;
|
|
|
- ipaddr->s6_addr[11] = 0xFF;
|
|
|
- ipaddr->s6_addr[12] = 0xFE;
|
|
|
- ipaddr->s6_addr16[7] = htons(*((u16 *)lladdr));
|
|
|
+ switch (lowpan_priv(dev)->lltype) {
|
|
|
+ case LOWPAN_LLTYPE_IEEE802154:
|
|
|
+ iphc_uncompress_802154_lladdr(ipaddr, lladdr);
|
|
|
break;
|
|
|
default:
|
|
|
- pr_debug("Invalid addr_type set\n");
|
|
|
- return -EINVAL;
|
|
|
+ iphc_uncompress_eui64_lladdr(ipaddr, lladdr);
|
|
|
+ break;
|
|
|
}
|
|
|
break;
|
|
|
default:
|
|
@@ -141,24 +261,25 @@ static int uncompress_addr(struct sk_buff *skb,
|
|
|
*/
|
|
|
static int uncompress_context_based_src_addr(struct sk_buff *skb,
|
|
|
struct in6_addr *ipaddr,
|
|
|
- const u8 sam)
|
|
|
+ u8 address_mode)
|
|
|
{
|
|
|
- switch (sam) {
|
|
|
- case LOWPAN_IPHC_ADDR_00:
|
|
|
+ switch (address_mode) {
|
|
|
+ case LOWPAN_IPHC_SAM_00:
|
|
|
/* unspec address ::
|
|
|
* Do nothing, address is already ::
|
|
|
*/
|
|
|
break;
|
|
|
- case LOWPAN_IPHC_ADDR_01:
|
|
|
+ case LOWPAN_IPHC_SAM_01:
|
|
|
/* TODO */
|
|
|
- case LOWPAN_IPHC_ADDR_02:
|
|
|
+ case LOWPAN_IPHC_SAM_10:
|
|
|
/* TODO */
|
|
|
- case LOWPAN_IPHC_ADDR_03:
|
|
|
+ case LOWPAN_IPHC_SAM_11:
|
|
|
/* TODO */
|
|
|
- netdev_warn(skb->dev, "SAM value 0x%x not supported\n", sam);
|
|
|
+ netdev_warn(skb->dev, "SAM value 0x%x not supported\n",
|
|
|
+ address_mode);
|
|
|
return -EINVAL;
|
|
|
default:
|
|
|
- pr_debug("Invalid sam value: 0x%x\n", sam);
|
|
|
+ pr_debug("Invalid sam value: 0x%x\n", address_mode);
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
@@ -174,11 +295,11 @@ static int uncompress_context_based_src_addr(struct sk_buff *skb,
|
|
|
*/
|
|
|
static int lowpan_uncompress_multicast_daddr(struct sk_buff *skb,
|
|
|
struct in6_addr *ipaddr,
|
|
|
- const u8 dam)
|
|
|
+ u8 address_mode)
|
|
|
{
|
|
|
bool fail;
|
|
|
|
|
|
- switch (dam) {
|
|
|
+ switch (address_mode) {
|
|
|
case LOWPAN_IPHC_DAM_00:
|
|
|
/* 00: 128 bits. The full address
|
|
|
* is carried in-line.
|
|
@@ -210,7 +331,7 @@ static int lowpan_uncompress_multicast_daddr(struct sk_buff *skb,
|
|
|
fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[15], 1);
|
|
|
break;
|
|
|
default:
|
|
|
- pr_debug("DAM value has a wrong value: 0x%x\n", dam);
|
|
|
+ pr_debug("DAM value has a wrong value: 0x%x\n", address_mode);
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
@@ -225,77 +346,142 @@ static int lowpan_uncompress_multicast_daddr(struct sk_buff *skb,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/* TTL uncompression values */
|
|
|
-static const u8 lowpan_ttl_values[] = { 0, 1, 64, 255 };
|
|
|
-
|
|
|
-int
|
|
|
-lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
|
|
|
- const u8 *saddr, const u8 saddr_type,
|
|
|
- const u8 saddr_len, const u8 *daddr,
|
|
|
- const u8 daddr_type, const u8 daddr_len,
|
|
|
- u8 iphc0, u8 iphc1)
|
|
|
+/* get the ecn values from iphc tf format and set it to ipv6hdr */
|
|
|
+static inline void lowpan_iphc_tf_set_ecn(struct ipv6hdr *hdr, const u8 *tf)
|
|
|
{
|
|
|
- struct ipv6hdr hdr = {};
|
|
|
- u8 tmp, num_context = 0;
|
|
|
- int err;
|
|
|
+ /* get the two higher bits which is ecn */
|
|
|
+ u8 ecn = tf[0] & 0xc0;
|
|
|
|
|
|
- raw_dump_table(__func__, "raw skb data dump uncompressed",
|
|
|
- skb->data, skb->len);
|
|
|
+ /* ECN takes 0x30 in hdr->flow_lbl[0] */
|
|
|
+ hdr->flow_lbl[0] |= (ecn >> 2);
|
|
|
+}
|
|
|
|
|
|
- /* another if the CID flag is set */
|
|
|
- if (iphc1 & LOWPAN_IPHC_CID) {
|
|
|
- pr_debug("CID flag is set, increase header with one\n");
|
|
|
- if (lowpan_fetch_skb(skb, &num_context, sizeof(num_context)))
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
+/* get the dscp values from iphc tf format and set it to ipv6hdr */
|
|
|
+static inline void lowpan_iphc_tf_set_dscp(struct ipv6hdr *hdr, const u8 *tf)
|
|
|
+{
|
|
|
+ /* DSCP is at place after ECN */
|
|
|
+ u8 dscp = tf[0] & 0x3f;
|
|
|
|
|
|
- hdr.version = 6;
|
|
|
+ /* The four highest bits need to be set at hdr->priority */
|
|
|
+ hdr->priority |= ((dscp & 0x3c) >> 2);
|
|
|
+ /* The two lower bits is part of hdr->flow_lbl[0] */
|
|
|
+ hdr->flow_lbl[0] |= ((dscp & 0x03) << 6);
|
|
|
+}
|
|
|
|
|
|
- /* Traffic Class and Flow Label */
|
|
|
- switch ((iphc0 & LOWPAN_IPHC_TF) >> 3) {
|
|
|
- /* Traffic Class and FLow Label carried in-line
|
|
|
- * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes)
|
|
|
+/* get the flow label values from iphc tf format and set it to ipv6hdr */
|
|
|
+static inline void lowpan_iphc_tf_set_lbl(struct ipv6hdr *hdr, const u8 *lbl)
|
|
|
+{
|
|
|
+ /* flow label is always some array started with lower nibble of
|
|
|
+ * flow_lbl[0] and followed with two bytes afterwards. Inside inline
|
|
|
+ * data the flow_lbl position can be different, which will be handled
|
|
|
+ * by lbl pointer. E.g. case "01" vs "00" the traffic class is 8 bit
|
|
|
+ * shifted, the different lbl pointer will handle that.
|
|
|
+ *
|
|
|
+ * The flow label will started at lower nibble of flow_lbl[0], the
|
|
|
+ * higher nibbles are part of DSCP + ECN.
|
|
|
*/
|
|
|
- case 0: /* 00b */
|
|
|
- if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp)))
|
|
|
+ hdr->flow_lbl[0] |= lbl[0] & 0x0f;
|
|
|
+ memcpy(&hdr->flow_lbl[1], &lbl[1], 2);
|
|
|
+}
|
|
|
+
|
|
|
+/* lowpan_iphc_tf_decompress - decompress the traffic class.
|
|
|
+ * This function will return zero on success, a value lower than zero if
|
|
|
+ * failed.
|
|
|
+ */
|
|
|
+static int lowpan_iphc_tf_decompress(struct sk_buff *skb, struct ipv6hdr *hdr,
|
|
|
+ u8 val)
|
|
|
+{
|
|
|
+ u8 tf[4];
|
|
|
+
|
|
|
+ /* Traffic Class and Flow Label */
|
|
|
+ switch (val) {
|
|
|
+ case LOWPAN_IPHC_TF_00:
|
|
|
+ /* ECN + DSCP + 4-bit Pad + Flow Label (4 bytes) */
|
|
|
+ if (lowpan_fetch_skb(skb, tf, 4))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- memcpy(&hdr.flow_lbl, &skb->data[0], 3);
|
|
|
- skb_pull(skb, 3);
|
|
|
- hdr.priority = ((tmp >> 2) & 0x0f);
|
|
|
- hdr.flow_lbl[0] = ((tmp >> 2) & 0x30) | (tmp << 6) |
|
|
|
- (hdr.flow_lbl[0] & 0x0f);
|
|
|
+ /* 1 2 3
|
|
|
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
|
+ * |ECN| DSCP | rsv | Flow Label |
|
|
|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
|
+ */
|
|
|
+ lowpan_iphc_tf_set_ecn(hdr, tf);
|
|
|
+ lowpan_iphc_tf_set_dscp(hdr, tf);
|
|
|
+ lowpan_iphc_tf_set_lbl(hdr, &tf[1]);
|
|
|
break;
|
|
|
- /* Traffic class carried in-line
|
|
|
- * ECN + DSCP (1 byte), Flow Label is elided
|
|
|
- */
|
|
|
- case 2: /* 10b */
|
|
|
- if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp)))
|
|
|
+ case LOWPAN_IPHC_TF_01:
|
|
|
+ /* ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided. */
|
|
|
+ if (lowpan_fetch_skb(skb, tf, 3))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- hdr.priority = ((tmp >> 2) & 0x0f);
|
|
|
- hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30);
|
|
|
+ /* 1 2
|
|
|
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
|
|
|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
|
+ * |ECN|rsv| Flow Label |
|
|
|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
|
+ */
|
|
|
+ lowpan_iphc_tf_set_ecn(hdr, tf);
|
|
|
+ lowpan_iphc_tf_set_lbl(hdr, &tf[0]);
|
|
|
break;
|
|
|
- /* Flow Label carried in-line
|
|
|
- * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided
|
|
|
- */
|
|
|
- case 1: /* 01b */
|
|
|
- if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp)))
|
|
|
+ case LOWPAN_IPHC_TF_10:
|
|
|
+ /* ECN + DSCP (1 byte), Flow Label is elided. */
|
|
|
+ if (lowpan_fetch_skb(skb, tf, 1))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- hdr.flow_lbl[0] = (tmp & 0x0F) | ((tmp >> 2) & 0x30);
|
|
|
- memcpy(&hdr.flow_lbl[1], &skb->data[0], 2);
|
|
|
- skb_pull(skb, 2);
|
|
|
+ /* 0 1 2 3 4 5 6 7
|
|
|
+ * +-+-+-+-+-+-+-+-+
|
|
|
+ * |ECN| DSCP |
|
|
|
+ * +-+-+-+-+-+-+-+-+
|
|
|
+ */
|
|
|
+ lowpan_iphc_tf_set_ecn(hdr, tf);
|
|
|
+ lowpan_iphc_tf_set_dscp(hdr, tf);
|
|
|
break;
|
|
|
- /* Traffic Class and Flow Label are elided */
|
|
|
- case 3: /* 11b */
|
|
|
+ case LOWPAN_IPHC_TF_11:
|
|
|
+ /* Traffic Class and Flow Label are elided */
|
|
|
break;
|
|
|
default:
|
|
|
- break;
|
|
|
+ WARN_ON_ONCE(1);
|
|
|
+ return -EINVAL;
|
|
|
}
|
|
|
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* TTL uncompression values */
|
|
|
+static const u8 lowpan_ttl_values[] = {
|
|
|
+ [LOWPAN_IPHC_HLIM_01] = 1,
|
|
|
+ [LOWPAN_IPHC_HLIM_10] = 64,
|
|
|
+ [LOWPAN_IPHC_HLIM_11] = 255,
|
|
|
+};
|
|
|
+
|
|
|
+int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev,
|
|
|
+ const void *daddr, const void *saddr)
|
|
|
+{
|
|
|
+ struct ipv6hdr hdr = {};
|
|
|
+ u8 iphc0, iphc1;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ raw_dump_table(__func__, "raw skb data dump uncompressed",
|
|
|
+ skb->data, skb->len);
|
|
|
+
|
|
|
+ if (lowpan_fetch_skb(skb, &iphc0, sizeof(iphc0)) ||
|
|
|
+ lowpan_fetch_skb(skb, &iphc1, sizeof(iphc1)))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ /* another if the CID flag is set */
|
|
|
+ if (iphc1 & LOWPAN_IPHC_CID)
|
|
|
+ return -ENOTSUPP;
|
|
|
+
|
|
|
+ hdr.version = 6;
|
|
|
+
|
|
|
+ err = lowpan_iphc_tf_decompress(skb, &hdr,
|
|
|
+ iphc0 & LOWPAN_IPHC_TF_MASK);
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
+
|
|
|
/* Next Header */
|
|
|
- if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
|
|
|
+ if (!(iphc0 & LOWPAN_IPHC_NH)) {
|
|
|
/* Next header is carried inline */
|
|
|
if (lowpan_fetch_skb(skb, &hdr.nexthdr, sizeof(hdr.nexthdr)))
|
|
|
return -EINVAL;
|
|
@@ -305,35 +491,30 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
|
|
|
}
|
|
|
|
|
|
/* Hop Limit */
|
|
|
- if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I) {
|
|
|
- hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03];
|
|
|
+ if ((iphc0 & LOWPAN_IPHC_HLIM_MASK) != LOWPAN_IPHC_HLIM_00) {
|
|
|
+ hdr.hop_limit = lowpan_ttl_values[iphc0 & LOWPAN_IPHC_HLIM_MASK];
|
|
|
} else {
|
|
|
if (lowpan_fetch_skb(skb, &hdr.hop_limit,
|
|
|
sizeof(hdr.hop_limit)))
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- /* Extract SAM to the tmp variable */
|
|
|
- tmp = ((iphc1 & LOWPAN_IPHC_SAM) >> LOWPAN_IPHC_SAM_BIT) & 0x03;
|
|
|
-
|
|
|
if (iphc1 & LOWPAN_IPHC_SAC) {
|
|
|
/* Source address context based uncompression */
|
|
|
pr_debug("SAC bit is set. Handle context based source address.\n");
|
|
|
- err = uncompress_context_based_src_addr(skb, &hdr.saddr, tmp);
|
|
|
+ err = uncompress_context_based_src_addr(skb, &hdr.saddr,
|
|
|
+ iphc1 & LOWPAN_IPHC_SAM_MASK);
|
|
|
} else {
|
|
|
/* Source address uncompression */
|
|
|
pr_debug("source address stateless compression\n");
|
|
|
- err = uncompress_addr(skb, &hdr.saddr, tmp, saddr,
|
|
|
- saddr_type, saddr_len);
|
|
|
+ err = uncompress_addr(skb, dev, &hdr.saddr,
|
|
|
+ iphc1 & LOWPAN_IPHC_SAM_MASK, saddr);
|
|
|
}
|
|
|
|
|
|
/* Check on error of previous branch */
|
|
|
if (err)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- /* Extract DAM to the tmp variable */
|
|
|
- tmp = ((iphc1 & LOWPAN_IPHC_DAM_11) >> LOWPAN_IPHC_DAM_BIT) & 0x03;
|
|
|
-
|
|
|
/* check for Multicast Compression */
|
|
|
if (iphc1 & LOWPAN_IPHC_M) {
|
|
|
if (iphc1 & LOWPAN_IPHC_DAC) {
|
|
@@ -341,22 +522,22 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
|
|
|
/* TODO: implement this */
|
|
|
} else {
|
|
|
err = lowpan_uncompress_multicast_daddr(skb, &hdr.daddr,
|
|
|
- tmp);
|
|
|
+ iphc1 & LOWPAN_IPHC_DAM_MASK);
|
|
|
|
|
|
if (err)
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
} else {
|
|
|
- err = uncompress_addr(skb, &hdr.daddr, tmp, daddr,
|
|
|
- daddr_type, daddr_len);
|
|
|
+ err = uncompress_addr(skb, dev, &hdr.daddr,
|
|
|
+ iphc1 & LOWPAN_IPHC_DAM_MASK, daddr);
|
|
|
pr_debug("dest: stateless compression mode %d dest %pI6c\n",
|
|
|
- tmp, &hdr.daddr);
|
|
|
+ iphc1 & LOWPAN_IPHC_DAM_MASK, &hdr.daddr);
|
|
|
if (err)
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
/* Next header data uncompression */
|
|
|
- if (iphc0 & LOWPAN_IPHC_NH_C) {
|
|
|
+ if (iphc0 & LOWPAN_IPHC_NH) {
|
|
|
err = lowpan_nhc_do_uncompression(skb, dev, &hdr);
|
|
|
if (err < 0)
|
|
|
return err;
|
|
@@ -397,42 +578,176 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(lowpan_header_decompress);
|
|
|
|
|
|
-static u8 lowpan_compress_addr_64(u8 **hc_ptr, u8 shift,
|
|
|
- const struct in6_addr *ipaddr,
|
|
|
- const unsigned char *lladdr)
|
|
|
+static const u8 lowpan_iphc_dam_to_sam_value[] = {
|
|
|
+ [LOWPAN_IPHC_DAM_00] = LOWPAN_IPHC_SAM_00,
|
|
|
+ [LOWPAN_IPHC_DAM_01] = LOWPAN_IPHC_SAM_01,
|
|
|
+ [LOWPAN_IPHC_DAM_10] = LOWPAN_IPHC_SAM_10,
|
|
|
+ [LOWPAN_IPHC_DAM_11] = LOWPAN_IPHC_SAM_11,
|
|
|
+};
|
|
|
+
|
|
|
+static u8 lowpan_compress_addr_64(u8 **hc_ptr, const struct in6_addr *ipaddr,
|
|
|
+ const unsigned char *lladdr, bool sam)
|
|
|
{
|
|
|
- u8 val = 0;
|
|
|
+ u8 dam = LOWPAN_IPHC_DAM_00;
|
|
|
|
|
|
if (is_addr_mac_addr_based(ipaddr, lladdr)) {
|
|
|
- val = 3; /* 0-bits */
|
|
|
+ dam = LOWPAN_IPHC_DAM_11; /* 0-bits */
|
|
|
pr_debug("address compression 0 bits\n");
|
|
|
} else 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);
|
|
|
- val = 2; /* 16-bits */
|
|
|
+ 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);
|
|
|
- val = 1; /* 64-bits */
|
|
|
+ dam = LOWPAN_IPHC_DAM_01; /* 64-bits */
|
|
|
raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)",
|
|
|
*hc_ptr - 8, 8);
|
|
|
}
|
|
|
|
|
|
- return rol8(val, shift);
|
|
|
+ if (sam)
|
|
|
+ return lowpan_iphc_dam_to_sam_value[dam];
|
|
|
+ else
|
|
|
+ return dam;
|
|
|
}
|
|
|
|
|
|
-int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
|
|
|
- unsigned short type, const void *_daddr,
|
|
|
- const void *_saddr, unsigned int len)
|
|
|
+/* lowpan_iphc_get_tc - get the ECN + DCSP fields in hc format */
|
|
|
+static inline u8 lowpan_iphc_get_tc(const struct ipv6hdr *hdr)
|
|
|
{
|
|
|
- u8 tmp, iphc0, iphc1, *hc_ptr;
|
|
|
+ u8 dscp, ecn;
|
|
|
+
|
|
|
+ /* hdr->priority contains the higher bits of dscp, lower are part of
|
|
|
+ * flow_lbl[0]. Note ECN, DCSP is swapped in ipv6 hdr.
|
|
|
+ */
|
|
|
+ dscp = (hdr->priority << 2) | ((hdr->flow_lbl[0] & 0xc0) >> 6);
|
|
|
+ /* ECN is at the two lower bits from first nibble of flow_lbl[0] */
|
|
|
+ ecn = (hdr->flow_lbl[0] & 0x30);
|
|
|
+ /* for pretty debug output, also shift ecn to get the ecn value */
|
|
|
+ pr_debug("ecn 0x%02x dscp 0x%02x\n", ecn >> 4, dscp);
|
|
|
+ /* ECN is at 0x30 now, shift it to have ECN + DCSP */
|
|
|
+ return (ecn << 2) | dscp;
|
|
|
+}
|
|
|
+
|
|
|
+/* lowpan_iphc_is_flow_lbl_zero - check if flow label is zero */
|
|
|
+static inline bool lowpan_iphc_is_flow_lbl_zero(const struct ipv6hdr *hdr)
|
|
|
+{
|
|
|
+ return ((!(hdr->flow_lbl[0] & 0x0f)) &&
|
|
|
+ !hdr->flow_lbl[1] && !hdr->flow_lbl[2]);
|
|
|
+}
|
|
|
+
|
|
|
+/* lowpan_iphc_tf_compress - compress the traffic class which is set by
|
|
|
+ * ipv6hdr. Return the corresponding format identifier which is used.
|
|
|
+ */
|
|
|
+static u8 lowpan_iphc_tf_compress(u8 **hc_ptr, const struct ipv6hdr *hdr)
|
|
|
+{
|
|
|
+ /* get ecn dscp data in a byteformat as: ECN(hi) + DSCP(lo) */
|
|
|
+ u8 tc = lowpan_iphc_get_tc(hdr), tf[4], val;
|
|
|
+
|
|
|
+ /* printout the traffic class in hc format */
|
|
|
+ pr_debug("tc 0x%02x\n", tc);
|
|
|
+
|
|
|
+ if (lowpan_iphc_is_flow_lbl_zero(hdr)) {
|
|
|
+ if (!tc) {
|
|
|
+ /* 11: Traffic Class and Flow Label are elided. */
|
|
|
+ val = LOWPAN_IPHC_TF_11;
|
|
|
+ } else {
|
|
|
+ /* 10: ECN + DSCP (1 byte), Flow Label is elided.
|
|
|
+ *
|
|
|
+ * 0 1 2 3 4 5 6 7
|
|
|
+ * +-+-+-+-+-+-+-+-+
|
|
|
+ * |ECN| DSCP |
|
|
|
+ * +-+-+-+-+-+-+-+-+
|
|
|
+ */
|
|
|
+ lowpan_push_hc_data(hc_ptr, &tc, sizeof(tc));
|
|
|
+ val = LOWPAN_IPHC_TF_10;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ /* check if dscp is zero, it's after the first two bit */
|
|
|
+ if (!(tc & 0x3f)) {
|
|
|
+ /* 01: ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided
|
|
|
+ *
|
|
|
+ * 1 2
|
|
|
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
|
|
|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
|
+ * |ECN|rsv| Flow Label |
|
|
|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
|
+ */
|
|
|
+ memcpy(&tf[0], &hdr->flow_lbl[0], 3);
|
|
|
+ /* zero the highest 4-bits, contains DCSP + ECN */
|
|
|
+ tf[0] &= ~0xf0;
|
|
|
+ /* set ECN */
|
|
|
+ tf[0] |= (tc & 0xc0);
|
|
|
+
|
|
|
+ lowpan_push_hc_data(hc_ptr, tf, 3);
|
|
|
+ val = LOWPAN_IPHC_TF_01;
|
|
|
+ } else {
|
|
|
+ /* 00: ECN + DSCP + 4-bit Pad + Flow Label (4 bytes)
|
|
|
+ *
|
|
|
+ * 1 2 3
|
|
|
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
|
+ * |ECN| DSCP | rsv | Flow Label |
|
|
|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
|
+ */
|
|
|
+ memcpy(&tf[0], &tc, sizeof(tc));
|
|
|
+ /* highest nibble of flow_lbl[0] is part of DSCP + ECN
|
|
|
+ * which will be the 4-bit pad and will be filled with
|
|
|
+ * zeros afterwards.
|
|
|
+ */
|
|
|
+ memcpy(&tf[1], &hdr->flow_lbl[0], 3);
|
|
|
+ /* zero the 4-bit pad, which is reserved */
|
|
|
+ tf[1] &= ~0xf0;
|
|
|
+
|
|
|
+ lowpan_push_hc_data(hc_ptr, tf, 4);
|
|
|
+ val = LOWPAN_IPHC_TF_00;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return val;
|
|
|
+}
|
|
|
+
|
|
|
+static u8 lowpan_iphc_mcast_addr_compress(u8 **hc_ptr,
|
|
|
+ const struct in6_addr *ipaddr)
|
|
|
+{
|
|
|
+ u8 val;
|
|
|
+
|
|
|
+ if (lowpan_is_mcast_addr_compressable8(ipaddr)) {
|
|
|
+ pr_debug("compressed to 1 octet\n");
|
|
|
+ /* use last byte */
|
|
|
+ lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr[15], 1);
|
|
|
+ val = LOWPAN_IPHC_DAM_11;
|
|
|
+ } else if (lowpan_is_mcast_addr_compressable32(ipaddr)) {
|
|
|
+ pr_debug("compressed to 4 octets\n");
|
|
|
+ /* second byte + the last three */
|
|
|
+ lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr[1], 1);
|
|
|
+ lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr[13], 3);
|
|
|
+ val = LOWPAN_IPHC_DAM_10;
|
|
|
+ } else if (lowpan_is_mcast_addr_compressable48(ipaddr)) {
|
|
|
+ pr_debug("compressed to 6 octets\n");
|
|
|
+ /* second byte + the last five */
|
|
|
+ lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr[1], 1);
|
|
|
+ lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr[11], 5);
|
|
|
+ val = LOWPAN_IPHC_DAM_01;
|
|
|
+ } else {
|
|
|
+ pr_debug("using full address\n");
|
|
|
+ lowpan_push_hc_data(hc_ptr, ipaddr->s6_addr, 16);
|
|
|
+ val = LOWPAN_IPHC_DAM_00;
|
|
|
+ }
|
|
|
+
|
|
|
+ return val;
|
|
|
+}
|
|
|
+
|
|
|
+int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
|
|
|
+ const void *daddr, const void *saddr)
|
|
|
+{
|
|
|
+ u8 iphc0, iphc1, *hc_ptr;
|
|
|
struct ipv6hdr *hdr;
|
|
|
- u8 head[100] = {};
|
|
|
+ u8 head[LOWPAN_IPHC_MAX_HC_BUF_LEN] = {};
|
|
|
int ret, addr_type;
|
|
|
|
|
|
- if (type != ETH_P_IPV6)
|
|
|
+ if (skb->protocol != htons(ETH_P_IPV6))
|
|
|
return -EINVAL;
|
|
|
|
|
|
hdr = ipv6_hdr(skb);
|
|
@@ -456,63 +771,26 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
|
|
|
|
|
|
/* TODO: context lookup */
|
|
|
|
|
|
- raw_dump_inline(__func__, "saddr",
|
|
|
- (unsigned char *)_saddr, IEEE802154_ADDR_LEN);
|
|
|
- raw_dump_inline(__func__, "daddr",
|
|
|
- (unsigned char *)_daddr, IEEE802154_ADDR_LEN);
|
|
|
+ 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);
|
|
|
|
|
|
- /* 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
|
|
|
- */
|
|
|
-
|
|
|
- /* hc format of TC is ECN | DSCP , original one 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 */
|
|
|
- *hc_ptr = tmp;
|
|
|
- hc_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;
|
|
|
- *hc_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F);
|
|
|
- memcpy(hc_ptr + 1, &hdr->flow_lbl[1], 2);
|
|
|
- hc_ptr += 3;
|
|
|
- } else {
|
|
|
- /* compress nothing */
|
|
|
- memcpy(hc_ptr, hdr, 4);
|
|
|
- /* replace the top byte with new ECN | DSCP format */
|
|
|
- *hc_ptr = tmp;
|
|
|
- hc_ptr += 4;
|
|
|
- }
|
|
|
- }
|
|
|
+ /* Traffic Class, Flow Label compression */
|
|
|
+ iphc0 |= lowpan_iphc_tf_compress(&hc_ptr, hdr);
|
|
|
|
|
|
/* NOTE: payload length is always compressed */
|
|
|
|
|
|
/* Check if we provide the nhc format for nexthdr and compression
|
|
|
* functionality. If not nexthdr is handled inline and not compressed.
|
|
|
*/
|
|
|
- ret = lowpan_nhc_check_compression(skb, hdr, &hc_ptr, &iphc0);
|
|
|
- if (ret < 0)
|
|
|
- return ret;
|
|
|
+ ret = lowpan_nhc_check_compression(skb, hdr, &hc_ptr);
|
|
|
+ if (ret == -ENOENT)
|
|
|
+ lowpan_push_hc_data(&hc_ptr, &hdr->nexthdr,
|
|
|
+ sizeof(hdr->nexthdr));
|
|
|
+ else
|
|
|
+ iphc0 |= LOWPAN_IPHC_NH;
|
|
|
|
|
|
/* Hop limit
|
|
|
* if 1: compress, encoding is 01
|
|
@@ -522,13 +800,13 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
|
|
|
*/
|
|
|
switch (hdr->hop_limit) {
|
|
|
case 1:
|
|
|
- iphc0 |= LOWPAN_IPHC_TTL_1;
|
|
|
+ iphc0 |= LOWPAN_IPHC_HLIM_01;
|
|
|
break;
|
|
|
case 64:
|
|
|
- iphc0 |= LOWPAN_IPHC_TTL_64;
|
|
|
+ iphc0 |= LOWPAN_IPHC_HLIM_10;
|
|
|
break;
|
|
|
case 255:
|
|
|
- iphc0 |= LOWPAN_IPHC_TTL_255;
|
|
|
+ iphc0 |= LOWPAN_IPHC_HLIM_11;
|
|
|
break;
|
|
|
default:
|
|
|
lowpan_push_hc_data(&hc_ptr, &hdr->hop_limit,
|
|
@@ -542,9 +820,8 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
|
|
|
iphc1 |= LOWPAN_IPHC_SAC;
|
|
|
} else {
|
|
|
if (addr_type & IPV6_ADDR_LINKLOCAL) {
|
|
|
- iphc1 |= lowpan_compress_addr_64(&hc_ptr,
|
|
|
- LOWPAN_IPHC_SAM_BIT,
|
|
|
- &hdr->saddr, _saddr);
|
|
|
+ iphc1 |= lowpan_compress_addr_64(&hc_ptr, &hdr->saddr,
|
|
|
+ saddr, true);
|
|
|
pr_debug("source address unicast link-local %pI6c iphc1 0x%02x\n",
|
|
|
&hdr->saddr, iphc1);
|
|
|
} else {
|
|
@@ -558,38 +835,12 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
|
|
|
if (addr_type & IPV6_ADDR_MULTICAST) {
|
|
|
pr_debug("destination address is multicast: ");
|
|
|
iphc1 |= LOWPAN_IPHC_M;
|
|
|
- if (lowpan_is_mcast_addr_compressable8(&hdr->daddr)) {
|
|
|
- pr_debug("compressed to 1 octet\n");
|
|
|
- iphc1 |= LOWPAN_IPHC_DAM_11;
|
|
|
- /* use last byte */
|
|
|
- lowpan_push_hc_data(&hc_ptr,
|
|
|
- &hdr->daddr.s6_addr[15], 1);
|
|
|
- } else if (lowpan_is_mcast_addr_compressable32(&hdr->daddr)) {
|
|
|
- pr_debug("compressed to 4 octets\n");
|
|
|
- iphc1 |= LOWPAN_IPHC_DAM_10;
|
|
|
- /* second byte + the last three */
|
|
|
- lowpan_push_hc_data(&hc_ptr,
|
|
|
- &hdr->daddr.s6_addr[1], 1);
|
|
|
- lowpan_push_hc_data(&hc_ptr,
|
|
|
- &hdr->daddr.s6_addr[13], 3);
|
|
|
- } else if (lowpan_is_mcast_addr_compressable48(&hdr->daddr)) {
|
|
|
- pr_debug("compressed to 6 octets\n");
|
|
|
- iphc1 |= LOWPAN_IPHC_DAM_01;
|
|
|
- /* second byte + the last five */
|
|
|
- lowpan_push_hc_data(&hc_ptr,
|
|
|
- &hdr->daddr.s6_addr[1], 1);
|
|
|
- lowpan_push_hc_data(&hc_ptr,
|
|
|
- &hdr->daddr.s6_addr[11], 5);
|
|
|
- } else {
|
|
|
- pr_debug("using full address\n");
|
|
|
- iphc1 |= LOWPAN_IPHC_DAM_00;
|
|
|
- lowpan_push_hc_data(&hc_ptr, hdr->daddr.s6_addr, 16);
|
|
|
- }
|
|
|
+ iphc1 |= lowpan_iphc_mcast_addr_compress(&hc_ptr, &hdr->daddr);
|
|
|
} else {
|
|
|
if (addr_type & IPV6_ADDR_LINKLOCAL) {
|
|
|
/* TODO: context lookup */
|
|
|
- iphc1 |= lowpan_compress_addr_64(&hc_ptr,
|
|
|
- LOWPAN_IPHC_DAM_BIT, &hdr->daddr, _daddr);
|
|
|
+ iphc1 |= lowpan_compress_addr_64(&hc_ptr, &hdr->daddr,
|
|
|
+ daddr, false);
|
|
|
pr_debug("dest address unicast link-local %pI6c "
|
|
|
"iphc1 0x%02x\n", &hdr->daddr, iphc1);
|
|
|
} else {
|
|
@@ -599,7 +850,7 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
|
|
|
}
|
|
|
|
|
|
/* next header compression */
|
|
|
- if (iphc0 & LOWPAN_IPHC_NH_C) {
|
|
|
+ if (iphc0 & LOWPAN_IPHC_NH) {
|
|
|
ret = lowpan_nhc_do_compression(skb, hdr, &hc_ptr);
|
|
|
if (ret < 0)
|
|
|
return ret;
|