summaryrefslogtreecommitdiffstats
path: root/net/mac802154/wpan.c
diff options
context:
space:
mode:
authorPhoebe Buckheister2014-03-14 21:24:01 +0100
committerDavid S. Miller2014-03-15 03:15:26 +0100
commite6278d92005e9d6e374f269b4ce39c908a68ad5d (patch)
tree4991dd3441843d55104c0fdba78cf36ed5d75034 /net/mac802154/wpan.c
parentieee802154: add header structs with endiannes and operations (diff)
downloadkernel-qcow2-linux-e6278d92005e9d6e374f269b4ce39c908a68ad5d.tar.gz
kernel-qcow2-linux-e6278d92005e9d6e374f269b4ce39c908a68ad5d.tar.xz
kernel-qcow2-linux-e6278d92005e9d6e374f269b4ce39c908a68ad5d.zip
mac802154: use header operations to create/parse headers
Use the operations on 802.15.4 header structs introduced in a previous patch to create and parse all headers in the mac802154 stack. This patch reduces code duplication between different parts of the mac802154 stack that needed information from headers, and also fixes a few bugs that seem to have gone unnoticed until now: * 802.15.4 dgram sockets would return a slightly incorrect value for the SIOCINQ ioctl * mac802154 would not drop frames with the "security enabled" bit set, even though it does not support security, in violation of the standard Signed-off-by: Phoebe Buckheister <phoebe.buckheister@itwm.fraunhofer.de> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/mac802154/wpan.c')
-rw-r--r--net/mac802154/wpan.c321
1 files changed, 83 insertions, 238 deletions
diff --git a/net/mac802154/wpan.c b/net/mac802154/wpan.c
index 43e886bb9073..051ed46ffca9 100644
--- a/net/mac802154/wpan.c
+++ b/net/mac802154/wpan.c
@@ -35,35 +35,6 @@
#include "mac802154.h"
-static inline int mac802154_fetch_skb_u8(struct sk_buff *skb, u8 *val)
-{
- if (unlikely(!pskb_may_pull(skb, 1)))
- return -EINVAL;
-
- *val = skb->data[0];
- skb_pull(skb, 1);
-
- return 0;
-}
-
-static inline int mac802154_fetch_skb_u16(struct sk_buff *skb, u16 *val)
-{
- if (unlikely(!pskb_may_pull(skb, 2)))
- return -EINVAL;
-
- *val = skb->data[0] | (skb->data[1] << 8);
- skb_pull(skb, 2);
-
- return 0;
-}
-
-static inline void mac802154_haddr_copy_swap(u8 *dest, const u8 *src)
-{
- int i;
- for (i = 0; i < IEEE802154_ADDR_LEN; i++)
- dest[IEEE802154_ADDR_LEN - i - 1] = src[i];
-}
-
static int
mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
@@ -134,25 +105,21 @@ static int mac802154_wpan_mac_addr(struct net_device *dev, void *p)
static int mac802154_header_create(struct sk_buff *skb,
struct net_device *dev,
unsigned short type,
- const void *_daddr,
- const void *_saddr,
+ const void *daddr,
+ const void *saddr,
unsigned len)
{
- const struct ieee802154_addr_sa *saddr = _saddr;
- const struct ieee802154_addr_sa *daddr = _daddr;
- struct ieee802154_addr_sa dev_addr;
+ struct ieee802154_hdr hdr;
struct mac802154_sub_if_data *priv = netdev_priv(dev);
- int pos = 2;
- u8 head[MAC802154_FRAME_HARD_HEADER_LEN];
- u16 fc;
+ int hlen;
if (!daddr)
return -EINVAL;
- head[pos++] = mac_cb(skb)->seq; /* DSN/BSN */
- fc = mac_cb_type(skb);
- if (mac_cb_is_ackreq(skb))
- fc |= IEEE802154_FC_ACK_REQ;
+ memset(&hdr.fc, 0, sizeof(hdr.fc));
+ hdr.fc.type = mac_cb_type(skb);
+ hdr.fc.security_enabled = mac_cb_is_secen(skb);
+ hdr.fc.ack_request = mac_cb_is_ackreq(skb);
if (!saddr) {
spin_lock_bh(&priv->mib_lock);
@@ -160,161 +127,45 @@ static int mac802154_header_create(struct sk_buff *skb,
if (priv->short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST) ||
priv->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) ||
priv->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST)) {
- dev_addr.addr_type = IEEE802154_ADDR_LONG;
- memcpy(dev_addr.hwaddr, dev->dev_addr,
- IEEE802154_ADDR_LEN);
+ hdr.source.mode = IEEE802154_ADDR_LONG;
+ hdr.source.extended_addr = priv->extended_addr;
} else {
- dev_addr.addr_type = IEEE802154_ADDR_SHORT;
- dev_addr.short_addr = le16_to_cpu(priv->short_addr);
+ hdr.source.mode = IEEE802154_ADDR_SHORT;
+ hdr.source.short_addr = priv->short_addr;
}
- dev_addr.pan_id = le16_to_cpu(priv->pan_id);
- saddr = &dev_addr;
+ hdr.source.pan_id = priv->pan_id;
spin_unlock_bh(&priv->mib_lock);
+ } else {
+ hdr.source = *(const struct ieee802154_addr *)saddr;
}
- 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;
- }
- }
-
- 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;
- }
+ hdr.dest = *(const struct ieee802154_addr *)daddr;
- 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;
- }
- }
-
- head[0] = fc;
- head[1] = fc >> 8;
+ hlen = ieee802154_hdr_push(skb, &hdr);
+ if (hlen < 0)
+ return -EINVAL;
- memcpy(skb_push(skb, pos), head, pos);
skb_reset_mac_header(skb);
- skb->mac_len = pos;
+ skb->mac_len = hlen;
- return pos;
+ return hlen;
}
static int
mac802154_header_parse(const struct sk_buff *skb, unsigned char *haddr)
{
- const u8 *hdr = skb_mac_header(skb);
- const u8 *tail = skb_tail_pointer(skb);
- struct ieee802154_addr_sa *addr = (struct ieee802154_addr_sa *)haddr;
- u16 fc;
- int da_type;
-
- if (hdr + 3 > tail)
- goto malformed;
-
- fc = hdr[0] | (hdr[1] << 8);
+ struct ieee802154_hdr hdr;
+ struct ieee802154_addr *addr = (struct ieee802154_addr *)haddr;
- hdr += 3;
-
- da_type = IEEE802154_FC_DAMODE(fc);
- addr->addr_type = IEEE802154_FC_SAMODE(fc);
-
- switch (da_type) {
- case IEEE802154_ADDR_NONE:
- if (fc & IEEE802154_FC_INTRA_PAN)
- goto malformed;
- break;
- case IEEE802154_ADDR_LONG:
- if (fc & IEEE802154_FC_INTRA_PAN) {
- if (hdr + 2 > tail)
- goto malformed;
- addr->pan_id = hdr[0] | (hdr[1] << 8);
- hdr += 2;
- }
-
- if (hdr + IEEE802154_ADDR_LEN > tail)
- goto malformed;
-
- hdr += IEEE802154_ADDR_LEN;
- break;
- case IEEE802154_ADDR_SHORT:
- if (fc & IEEE802154_FC_INTRA_PAN) {
- if (hdr + 2 > tail)
- goto malformed;
- addr->pan_id = hdr[0] | (hdr[1] << 8);
- hdr += 2;
- }
-
- if (hdr + 2 > tail)
- goto malformed;
-
- hdr += 2;
- break;
- default:
- goto malformed;
-
- }
-
- switch (addr->addr_type) {
- case IEEE802154_ADDR_NONE:
- break;
- case IEEE802154_ADDR_LONG:
- if (!(fc & IEEE802154_FC_INTRA_PAN)) {
- if (hdr + 2 > tail)
- goto malformed;
- addr->pan_id = hdr[0] | (hdr[1] << 8);
- hdr += 2;
- }
-
- if (hdr + IEEE802154_ADDR_LEN > tail)
- goto malformed;
-
- mac802154_haddr_copy_swap(addr->hwaddr, hdr);
- hdr += IEEE802154_ADDR_LEN;
- break;
- case IEEE802154_ADDR_SHORT:
- if (!(fc & IEEE802154_FC_INTRA_PAN)) {
- if (hdr + 2 > tail)
- goto malformed;
- addr->pan_id = hdr[0] | (hdr[1] << 8);
- hdr += 2;
- }
-
- if (hdr + 2 > tail)
- goto malformed;
-
- addr->short_addr = hdr[0] | (hdr[1] << 8);
- hdr += 2;
- break;
- default:
- goto malformed;
+ if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0) {
+ pr_debug("malformed packet\n");
+ return 0;
}
- return sizeof(struct ieee802154_addr_sa);
-
-malformed:
- pr_debug("malformed packet\n");
- return 0;
+ *addr = hdr.source;
+ return sizeof(*addr);
}
static netdev_tx_t
@@ -462,88 +313,82 @@ mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb)
}
}
-static int mac802154_parse_frame_start(struct sk_buff *skb)
+static void mac802154_print_addr(const char *name,
+ const struct ieee802154_addr *addr)
{
- u8 *head = skb->data;
- u16 fc;
-
- if (mac802154_fetch_skb_u16(skb, &fc) ||
- mac802154_fetch_skb_u8(skb, &(mac_cb(skb)->seq)))
- goto err;
+ if (addr->mode == IEEE802154_ADDR_NONE)
+ pr_debug("%s not present\n", name);
- pr_debug("fc: %04x dsn: %02x\n", fc, head[2]);
+ pr_debug("%s PAN ID: %04x\n", name, le16_to_cpu(addr->pan_id));
+ if (addr->mode == IEEE802154_ADDR_SHORT) {
+ pr_debug("%s is short: %04x\n", name,
+ le16_to_cpu(addr->short_addr));
+ } else {
+ u64 hw = swab64((__force u64) addr->extended_addr);
- mac_cb(skb)->flags = IEEE802154_FC_TYPE(fc);
- mac_cb(skb)->sa.addr_type = IEEE802154_FC_SAMODE(fc);
- mac_cb(skb)->da.addr_type = IEEE802154_FC_DAMODE(fc);
+ pr_debug("%s is hardware: %8phC\n", name, &hw);
+ }
+}
- if (fc & IEEE802154_FC_INTRA_PAN)
- mac_cb(skb)->flags |= MAC_CB_FLAG_INTRAPAN;
+static int mac802154_parse_frame_start(struct sk_buff *skb)
+{
+ struct ieee802154_hdr hdr;
+ int hlen;
- if (mac_cb(skb)->da.addr_type != IEEE802154_ADDR_NONE) {
- if (mac802154_fetch_skb_u16(skb, &(mac_cb(skb)->da.pan_id)))
- goto err;
+ hlen = ieee802154_hdr_pull(skb, &hdr);
+ if (hlen < 0)
+ return -EINVAL;
- /* source PAN id compression */
- if (mac_cb_is_intrapan(skb))
- mac_cb(skb)->sa.pan_id = mac_cb(skb)->da.pan_id;
+ skb->mac_len = hlen;
- pr_debug("dest PAN addr: %04x\n", mac_cb(skb)->da.pan_id);
+ pr_debug("fc: %04x dsn: %02x\n", le16_to_cpup((__le16 *)&hdr.fc),
+ hdr.seq);
- if (mac_cb(skb)->da.addr_type == IEEE802154_ADDR_SHORT) {
- u16 *da = &(mac_cb(skb)->da.short_addr);
+ mac_cb(skb)->flags = hdr.fc.type;
- if (mac802154_fetch_skb_u16(skb, da))
- goto err;
+ ieee802154_addr_to_sa(&mac_cb(skb)->sa, &hdr.source);
+ ieee802154_addr_to_sa(&mac_cb(skb)->da, &hdr.dest);
- pr_debug("destination address is short: %04x\n",
- mac_cb(skb)->da.short_addr);
- } else {
- if (!pskb_may_pull(skb, IEEE802154_ADDR_LEN))
- goto err;
+ if (hdr.fc.ack_request)
+ mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ;
+ if (hdr.fc.security_enabled)
+ mac_cb(skb)->flags |= MAC_CB_FLAG_SECEN;
- mac802154_haddr_copy_swap(mac_cb(skb)->da.hwaddr,
- skb->data);
- skb_pull(skb, IEEE802154_ADDR_LEN);
+ mac802154_print_addr("destination", &hdr.dest);
+ mac802154_print_addr("source", &hdr.source);
- pr_debug("destination address is hardware\n");
- }
- }
+ if (hdr.fc.security_enabled) {
+ u64 key;
- if (mac_cb(skb)->sa.addr_type != IEEE802154_ADDR_NONE) {
- /* non PAN-compression, fetch source address id */
- if (!(mac_cb_is_intrapan(skb))) {
- u16 *sa_pan = &(mac_cb(skb)->sa.pan_id);
+ pr_debug("seclevel %i\n", hdr.sec.level);
- if (mac802154_fetch_skb_u16(skb, sa_pan))
- goto err;
- }
-
- pr_debug("source PAN addr: %04x\n", mac_cb(skb)->da.pan_id);
-
- if (mac_cb(skb)->sa.addr_type == IEEE802154_ADDR_SHORT) {
- u16 *sa = &(mac_cb(skb)->sa.short_addr);
-
- if (mac802154_fetch_skb_u16(skb, sa))
- goto err;
+ switch (hdr.sec.key_id_mode) {
+ case IEEE802154_SCF_KEY_IMPLICIT:
+ pr_debug("implicit key\n");
+ break;
- pr_debug("source address is short: %04x\n",
- mac_cb(skb)->sa.short_addr);
- } else {
- if (!pskb_may_pull(skb, IEEE802154_ADDR_LEN))
- goto err;
+ case IEEE802154_SCF_KEY_INDEX:
+ pr_debug("key %02x\n", hdr.sec.key_id);
+ break;
- mac802154_haddr_copy_swap(mac_cb(skb)->sa.hwaddr,
- skb->data);
- skb_pull(skb, IEEE802154_ADDR_LEN);
+ case IEEE802154_SCF_KEY_SHORT_INDEX:
+ pr_debug("key %04x:%04x %02x\n",
+ le32_to_cpu(hdr.sec.short_src) >> 16,
+ le32_to_cpu(hdr.sec.short_src) & 0xffff,
+ hdr.sec.key_id);
+ break;
- pr_debug("source address is hardware\n");
+ case IEEE802154_SCF_KEY_HW_INDEX:
+ key = swab64((__force u64) hdr.sec.extended_src);
+ pr_debug("key source %8phC %02x\n", &key,
+ hdr.sec.key_id);
+ break;
}
+
+ return -EINVAL;
}
return 0;
-err:
- return -EINVAL;
}
void mac802154_wpans_rx(struct mac802154_priv *priv, struct sk_buff *skb)