Commit 9509b1c1 authored by David S. Miller's avatar David S. Miller

Merge branch 'ieee802154-next'

Phoebe Buckheister says:

====================
802154: some cleanups and fixes

This series adds some definitions for 802.15.4 header fields that were missing,
changes 6lowpan fragmentation to be aware of security headers and fixes
802.15.4 datagram socket sendmsg(), which was entirely incompliant to date.
Also a few minor changes to mac_cb handling, mark a single-use function static,
and correctly check for EMSGSIZE conditions during wpan_header_create.

Changes since v1:
  * rename mac_cb_alloc to mac_cb_init
  * catch all error cases of sendmsg() instead of only !conn && msg_name
  * redo 6lowpan fragmentation to not clone lower layer headers
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 9dbccc30 6ef0023a
...@@ -79,6 +79,15 @@ ...@@ -79,6 +79,15 @@
#define IEEE802154_SCF_KEY_SHORT_INDEX 2 #define IEEE802154_SCF_KEY_SHORT_INDEX 2
#define IEEE802154_SCF_KEY_HW_INDEX 3 #define IEEE802154_SCF_KEY_HW_INDEX 3
#define IEEE802154_SCF_SECLEVEL_NONE 0
#define IEEE802154_SCF_SECLEVEL_MIC32 1
#define IEEE802154_SCF_SECLEVEL_MIC64 2
#define IEEE802154_SCF_SECLEVEL_MIC128 3
#define IEEE802154_SCF_SECLEVEL_ENC 4
#define IEEE802154_SCF_SECLEVEL_ENC_MIC32 5
#define IEEE802154_SCF_SECLEVEL_ENC_MIC64 6
#define IEEE802154_SCF_SECLEVEL_ENC_MIC128 7
/* MAC footer size */ /* MAC footer size */
#define IEEE802154_MFR_SIZE 2 /* 2 octets */ #define IEEE802154_MFR_SIZE 2 /* 2 octets */
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#ifndef IEEE802154_NETDEVICE_H #ifndef IEEE802154_NETDEVICE_H
#define IEEE802154_NETDEVICE_H #define IEEE802154_NETDEVICE_H
#include <net/ieee802154.h>
#include <net/af_ieee802154.h> #include <net/af_ieee802154.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
...@@ -114,6 +115,34 @@ int ieee802154_hdr_pull(struct sk_buff *skb, struct ieee802154_hdr *hdr); ...@@ -114,6 +115,34 @@ int ieee802154_hdr_pull(struct sk_buff *skb, struct ieee802154_hdr *hdr);
int ieee802154_hdr_peek_addrs(const struct sk_buff *skb, int ieee802154_hdr_peek_addrs(const struct sk_buff *skb,
struct ieee802154_hdr *hdr); struct ieee802154_hdr *hdr);
/* parses the full 802.15.4 header a given skb and stores them into hdr,
* performing pan id decompression and length checks to be suitable for use in
* header_ops.parse
*/
int ieee802154_hdr_peek(const struct sk_buff *skb, struct ieee802154_hdr *hdr);
int ieee802154_max_payload(const struct ieee802154_hdr *hdr);
static inline int
ieee802154_sechdr_authtag_len(const struct ieee802154_sechdr *sec)
{
switch (sec->level) {
case IEEE802154_SCF_SECLEVEL_MIC32:
case IEEE802154_SCF_SECLEVEL_ENC_MIC32:
return 4;
case IEEE802154_SCF_SECLEVEL_MIC64:
case IEEE802154_SCF_SECLEVEL_ENC_MIC64:
return 8;
case IEEE802154_SCF_SECLEVEL_MIC128:
case IEEE802154_SCF_SECLEVEL_ENC_MIC128:
return 16;
case IEEE802154_SCF_SECLEVEL_NONE:
case IEEE802154_SCF_SECLEVEL_ENC:
default:
return 0;
}
}
static inline int ieee802154_hdr_length(struct sk_buff *skb) static inline int ieee802154_hdr_length(struct sk_buff *skb)
{ {
struct ieee802154_hdr hdr; struct ieee802154_hdr hdr;
...@@ -193,8 +222,9 @@ static inline void ieee802154_addr_to_sa(struct ieee802154_addr_sa *sa, ...@@ -193,8 +222,9 @@ static inline void ieee802154_addr_to_sa(struct ieee802154_addr_sa *sa,
*/ */
struct ieee802154_mac_cb { struct ieee802154_mac_cb {
u8 lqi; u8 lqi;
u8 flags; u8 type;
u8 seq; bool ackreq;
bool secen;
struct ieee802154_addr source; struct ieee802154_addr source;
struct ieee802154_addr dest; struct ieee802154_addr dest;
}; };
...@@ -204,24 +234,12 @@ static inline struct ieee802154_mac_cb *mac_cb(struct sk_buff *skb) ...@@ -204,24 +234,12 @@ static inline struct ieee802154_mac_cb *mac_cb(struct sk_buff *skb)
return (struct ieee802154_mac_cb *)skb->cb; return (struct ieee802154_mac_cb *)skb->cb;
} }
#define MAC_CB_FLAG_TYPEMASK ((1 << 3) - 1) static inline struct ieee802154_mac_cb *mac_cb_init(struct sk_buff *skb)
#define MAC_CB_FLAG_ACKREQ (1 << 3)
#define MAC_CB_FLAG_SECEN (1 << 4)
static inline bool mac_cb_is_ackreq(struct sk_buff *skb)
{ {
return mac_cb(skb)->flags & MAC_CB_FLAG_ACKREQ; BUILD_BUG_ON(sizeof(struct ieee802154_mac_cb) > sizeof(skb->cb));
}
static inline bool mac_cb_is_secen(struct sk_buff *skb) memset(skb->cb, 0, sizeof(struct ieee802154_mac_cb));
{ return mac_cb(skb);
return mac_cb(skb)->flags & MAC_CB_FLAG_SECEN;
}
static inline int mac_cb_type(struct sk_buff *skb)
{
return mac_cb(skb)->flags & MAC_CB_FLAG_TYPEMASK;
} }
#define IEEE802154_MAC_SCAN_ED 0 #define IEEE802154_MAC_SCAN_ED 0
......
...@@ -92,6 +92,7 @@ static int lowpan_header_create(struct sk_buff *skb, ...@@ -92,6 +92,7 @@ static int lowpan_header_create(struct sk_buff *skb,
const u8 *saddr = _saddr; const u8 *saddr = _saddr;
const u8 *daddr = _daddr; const u8 *daddr = _daddr;
struct ieee802154_addr sa, da; struct ieee802154_addr sa, da;
struct ieee802154_mac_cb *cb = mac_cb_init(skb);
/* TODO: /* TODO:
* if this package isn't ipv6 one, where should it be routed? * if this package isn't ipv6 one, where should it be routed?
...@@ -115,8 +116,7 @@ static int lowpan_header_create(struct sk_buff *skb, ...@@ -115,8 +116,7 @@ static int lowpan_header_create(struct sk_buff *skb,
* from MAC subif of the 'dev' and 'real_dev' network devices, but * from MAC subif of the 'dev' and 'real_dev' network devices, but
* this isn't implemented in mainline yet, so currently we assign 0xff * this isn't implemented in mainline yet, so currently we assign 0xff
*/ */
mac_cb(skb)->flags = IEEE802154_FC_TYPE_DATA; cb->type = IEEE802154_FC_TYPE_DATA;
mac_cb(skb)->seq = ieee802154_mlme_ops(dev)->get_dsn(dev);
/* prepare wpan address data */ /* prepare wpan address data */
sa.mode = IEEE802154_ADDR_LONG; sa.mode = IEEE802154_ADDR_LONG;
...@@ -135,11 +135,10 @@ static int lowpan_header_create(struct sk_buff *skb, ...@@ -135,11 +135,10 @@ static int lowpan_header_create(struct sk_buff *skb,
} else { } else {
da.mode = IEEE802154_ADDR_LONG; da.mode = IEEE802154_ADDR_LONG;
da.extended_addr = ieee802154_devaddr_from_raw(daddr); da.extended_addr = ieee802154_devaddr_from_raw(daddr);
/* request acknowledgment */
mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ;
} }
cb->ackreq = !lowpan_is_addr_broadcast(daddr);
return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev, return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev,
type, (void *)&da, (void *)&sa, 0); type, (void *)&da, (void *)&sa, 0);
} }
...@@ -221,139 +220,149 @@ static int lowpan_set_address(struct net_device *dev, void *p) ...@@ -221,139 +220,149 @@ static int lowpan_set_address(struct net_device *dev, void *p)
return 0; return 0;
} }
static int static struct sk_buff*
lowpan_fragment_xmit(struct sk_buff *skb, u8 *head, lowpan_alloc_frag(struct sk_buff *skb, int size,
int mlen, int plen, int offset, int type) const struct ieee802154_hdr *master_hdr)
{ {
struct net_device *real_dev = lowpan_dev_info(skb->dev)->real_dev;
struct sk_buff *frag; struct sk_buff *frag;
int hlen; int rc;
hlen = (type == LOWPAN_DISPATCH_FRAG1) ? frag = alloc_skb(real_dev->hard_header_len +
LOWPAN_FRAG1_HEAD_SIZE : LOWPAN_FRAGN_HEAD_SIZE; real_dev->needed_tailroom + size,
GFP_ATOMIC);
raw_dump_inline(__func__, "6lowpan fragment header", head, hlen); if (likely(frag)) {
frag->dev = real_dev;
frag->priority = skb->priority;
skb_reserve(frag, real_dev->hard_header_len);
skb_reset_network_header(frag);
*mac_cb(frag) = *mac_cb(skb);
rc = dev_hard_header(frag, real_dev, 0, &master_hdr->dest,
&master_hdr->source, size);
if (rc < 0) {
kfree_skb(frag);
return ERR_PTR(-rc);
}
} else {
frag = ERR_PTR(ENOMEM);
}
frag = netdev_alloc_skb(skb->dev, return frag;
hlen + mlen + plen + IEEE802154_MFR_SIZE); }
if (!frag)
return -ENOMEM;
frag->priority = skb->priority; static int
lowpan_xmit_fragment(struct sk_buff *skb, const struct ieee802154_hdr *wpan_hdr,
u8 *frag_hdr, int frag_hdrlen,
int offset, int len)
{
struct sk_buff *frag;
/* copy header, MFR and payload */ raw_dump_inline(__func__, " fragment header", frag_hdr, frag_hdrlen);
skb_put(frag, mlen);
skb_copy_to_linear_data(frag, skb_mac_header(skb), mlen);
skb_put(frag, hlen); frag = lowpan_alloc_frag(skb, frag_hdrlen + len, wpan_hdr);
skb_copy_to_linear_data_offset(frag, mlen, head, hlen); if (IS_ERR(frag))
return -PTR_ERR(frag);
skb_put(frag, plen); memcpy(skb_put(frag, frag_hdrlen), frag_hdr, frag_hdrlen);
skb_copy_to_linear_data_offset(frag, mlen + hlen, memcpy(skb_put(frag, len), skb_network_header(skb) + offset, len);
skb_network_header(skb) + offset, plen);
raw_dump_table(__func__, " raw fragment dump", frag->data, frag->len); raw_dump_table(__func__, " fragment dump", frag->data, frag->len);
return dev_queue_xmit(frag); return dev_queue_xmit(frag);
} }
static int static int
lowpan_skb_fragmentation(struct sk_buff *skb, struct net_device *dev) lowpan_xmit_fragmented(struct sk_buff *skb, struct net_device *dev,
const struct ieee802154_hdr *wpan_hdr)
{ {
int err; u16 dgram_size, dgram_offset;
u16 dgram_offset, dgram_size, payload_length, header_length, __be16 frag_tag;
lowpan_size, frag_plen, offset; u8 frag_hdr[5];
__be16 tag; int frag_cap, frag_len, payload_cap, rc;
u8 head[5]; int skb_unprocessed, skb_offset;
header_length = skb->mac_len;
payload_length = skb->len - header_length;
tag = lowpan_dev_info(dev)->fragment_tag++;
lowpan_size = skb_network_header_len(skb);
dgram_size = lowpan_uncompress_size(skb, &dgram_offset) - dgram_size = lowpan_uncompress_size(skb, &dgram_offset) -
header_length; skb->mac_len;
frag_tag = lowpan_dev_info(dev)->fragment_tag++;
/* first fragment header */ frag_hdr[0] = LOWPAN_DISPATCH_FRAG1 | ((dgram_size >> 8) & 0x07);
head[0] = LOWPAN_DISPATCH_FRAG1 | ((dgram_size >> 8) & 0x7); frag_hdr[1] = dgram_size & 0xff;
head[1] = dgram_size & 0xff; memcpy(frag_hdr + 2, &frag_tag, sizeof(frag_tag));
memcpy(head + 2, &tag, sizeof(tag));
/* calc the nearest payload length(divided to 8) for first fragment payload_cap = ieee802154_max_payload(wpan_hdr);
* which fits into a IEEE802154_MTU
*/
frag_plen = round_down(IEEE802154_MTU - header_length -
LOWPAN_FRAG1_HEAD_SIZE - lowpan_size -
IEEE802154_MFR_SIZE, 8);
err = lowpan_fragment_xmit(skb, head, header_length,
frag_plen + lowpan_size, 0,
LOWPAN_DISPATCH_FRAG1);
if (err) {
pr_debug("%s unable to send FRAG1 packet (tag: %d)",
__func__, tag);
goto exit;
}
offset = lowpan_size + frag_plen; frag_len = round_down(payload_cap - LOWPAN_FRAG1_HEAD_SIZE -
dgram_offset += frag_plen; skb_network_header_len(skb), 8);
/* next fragment header */ skb_offset = skb_network_header_len(skb);
head[0] &= ~LOWPAN_DISPATCH_FRAG1; skb_unprocessed = skb->len - skb->mac_len - skb_offset;
head[0] |= LOWPAN_DISPATCH_FRAGN;
frag_plen = round_down(IEEE802154_MTU - header_length - rc = lowpan_xmit_fragment(skb, wpan_hdr, frag_hdr,
LOWPAN_FRAGN_HEAD_SIZE - IEEE802154_MFR_SIZE, 8); LOWPAN_FRAG1_HEAD_SIZE, 0,
frag_len + skb_network_header_len(skb));
if (rc) {
pr_debug("%s unable to send FRAG1 packet (tag: %d)",
__func__, frag_tag);
goto err;
}
while (payload_length - offset > 0) { frag_hdr[0] &= ~LOWPAN_DISPATCH_FRAG1;
int len = frag_plen; frag_hdr[0] |= LOWPAN_DISPATCH_FRAGN;
frag_cap = round_down(payload_cap - LOWPAN_FRAGN_HEAD_SIZE, 8);
head[4] = dgram_offset >> 3; while (skb_unprocessed >= frag_cap) {
dgram_offset += frag_len;
skb_offset += frag_len;
skb_unprocessed -= frag_len;
frag_len = min(frag_cap, skb_unprocessed);
if (payload_length - offset < len) frag_hdr[4] = dgram_offset >> 3;
len = payload_length - offset;
err = lowpan_fragment_xmit(skb, head, header_length, len, rc = lowpan_xmit_fragment(skb, wpan_hdr, frag_hdr,
offset, LOWPAN_DISPATCH_FRAGN); LOWPAN_FRAGN_HEAD_SIZE, skb_offset,
if (err) { frag_len);
if (rc) {
pr_debug("%s unable to send a FRAGN packet. (tag: %d, offset: %d)\n", pr_debug("%s unable to send a FRAGN packet. (tag: %d, offset: %d)\n",
__func__, tag, offset); __func__, frag_tag, skb_offset);
goto exit; goto err;
} }
offset += len;
dgram_offset += len;
} }
exit: consume_skb(skb);
return err; return NET_XMIT_SUCCESS;
err:
kfree_skb(skb);
return rc;
} }
static netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *dev) static netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *dev)
{ {
int err = -1; struct ieee802154_hdr wpan_hdr;
int max_single;
pr_debug("package xmit\n"); pr_debug("package xmit\n");
skb->dev = lowpan_dev_info(dev)->real_dev; if (ieee802154_hdr_peek(skb, &wpan_hdr) < 0) {
if (skb->dev == NULL) { kfree_skb(skb);
pr_debug("ERROR: no real wpan device found\n"); return NET_XMIT_DROP;
goto error;
} }
/* Send directly if less than the MTU minus the 2 checksum bytes. */ max_single = ieee802154_max_payload(&wpan_hdr);
if (skb->len <= IEEE802154_MTU - IEEE802154_MFR_SIZE) {
err = dev_queue_xmit(skb); if (skb_tail_pointer(skb) - skb_network_header(skb) <= max_single) {
goto out; skb->dev = lowpan_dev_info(dev)->real_dev;
} return dev_queue_xmit(skb);
} else {
netdev_tx_t rc;
pr_debug("frame is too big, fragmentation is needed\n"); pr_debug("frame is too big, fragmentation is needed\n");
err = lowpan_skb_fragmentation(skb, dev); rc = lowpan_xmit_fragmented(skb, dev, &wpan_hdr);
error:
dev_kfree_skb(skb);
out:
if (err)
pr_debug("ERROR: xmit failed\n");
return (err < 0) ? NET_XMIT_DROP : err; return rc < 0 ? NET_XMIT_DROP : rc;
}
} }
static struct wpan_phy *lowpan_get_phy(const struct net_device *dev) static struct wpan_phy *lowpan_get_phy(const struct net_device *dev)
......
...@@ -45,6 +45,7 @@ struct dgram_sock { ...@@ -45,6 +45,7 @@ struct dgram_sock {
struct ieee802154_addr dst_addr; struct ieee802154_addr dst_addr;
unsigned int bound:1; unsigned int bound:1;
unsigned int connected:1;
unsigned int want_ack:1; unsigned int want_ack:1;
}; };
...@@ -73,10 +74,7 @@ static int dgram_init(struct sock *sk) ...@@ -73,10 +74,7 @@ static int dgram_init(struct sock *sk)
{ {
struct dgram_sock *ro = dgram_sk(sk); struct dgram_sock *ro = dgram_sk(sk);
ro->dst_addr.mode = IEEE802154_ADDR_LONG;
ro->dst_addr.pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST);
ro->want_ack = 1; ro->want_ack = 1;
memset(&ro->dst_addr.extended_addr, 0xff, IEEE802154_ADDR_LEN);
return 0; return 0;
} }
...@@ -183,6 +181,7 @@ static int dgram_connect(struct sock *sk, struct sockaddr *uaddr, ...@@ -183,6 +181,7 @@ static int dgram_connect(struct sock *sk, struct sockaddr *uaddr,
} }
ieee802154_addr_from_sa(&ro->dst_addr, &addr->addr); ieee802154_addr_from_sa(&ro->dst_addr, &addr->addr);
ro->connected = 1;
out: out:
release_sock(sk); release_sock(sk);
...@@ -194,10 +193,7 @@ static int dgram_disconnect(struct sock *sk, int flags) ...@@ -194,10 +193,7 @@ static int dgram_disconnect(struct sock *sk, int flags)
struct dgram_sock *ro = dgram_sk(sk); struct dgram_sock *ro = dgram_sk(sk);
lock_sock(sk); lock_sock(sk);
ro->connected = 0;
ro->dst_addr.mode = IEEE802154_ADDR_LONG;
memset(&ro->dst_addr.extended_addr, 0xff, IEEE802154_ADDR_LEN);
release_sock(sk); release_sock(sk);
return 0; return 0;
...@@ -209,7 +205,9 @@ static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -209,7 +205,9 @@ static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk,
struct net_device *dev; struct net_device *dev;
unsigned int mtu; unsigned int mtu;
struct sk_buff *skb; struct sk_buff *skb;
struct ieee802154_mac_cb *cb;
struct dgram_sock *ro = dgram_sk(sk); struct dgram_sock *ro = dgram_sk(sk);
struct ieee802154_addr dst_addr;
int hlen, tlen; int hlen, tlen;
int err; int err;
...@@ -218,6 +216,11 @@ static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -218,6 +216,11 @@ static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
if (!ro->connected && !msg->msg_name)
return -EDESTADDRREQ;
else if (ro->connected && msg->msg_name)
return -EISCONN;
if (!ro->bound) if (!ro->bound)
dev = dev_getfirstbyhwtype(sock_net(sk), ARPHRD_IEEE802154); dev = dev_getfirstbyhwtype(sock_net(sk), ARPHRD_IEEE802154);
else else
...@@ -249,18 +252,23 @@ static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -249,18 +252,23 @@ static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk,
skb_reset_network_header(skb); skb_reset_network_header(skb);
mac_cb(skb)->flags = IEEE802154_FC_TYPE_DATA; cb = mac_cb_init(skb);
if (ro->want_ack) cb->type = IEEE802154_FC_TYPE_DATA;
mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ; cb->ackreq = ro->want_ack;
mac_cb(skb)->seq = ieee802154_mlme_ops(dev)->get_dsn(dev); if (msg->msg_name) {
err = dev_hard_header(skb, dev, ETH_P_IEEE802154, &ro->dst_addr, DECLARE_SOCKADDR(struct sockaddr_ieee802154*, daddr, msg->msg_name);
ieee802154_addr_from_sa(&dst_addr, &daddr->addr);
} else {
dst_addr = ro->dst_addr;
}
err = dev_hard_header(skb, dev, ETH_P_IEEE802154, &dst_addr,
ro->bound ? &ro->src_addr : NULL, size); ro->bound ? &ro->src_addr : NULL, size);
if (err < 0) if (err < 0)
goto out_skb; goto out_skb;
skb_reset_mac_header(skb);
err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
if (err < 0) if (err < 0)
goto out_skb; goto out_skb;
......
...@@ -195,15 +195,16 @@ ieee802154_hdr_get_sechdr(const u8 *buf, struct ieee802154_sechdr *hdr) ...@@ -195,15 +195,16 @@ ieee802154_hdr_get_sechdr(const u8 *buf, struct ieee802154_sechdr *hdr)
return pos; return pos;
} }
static int ieee802154_sechdr_lengths[4] = {
[IEEE802154_SCF_KEY_IMPLICIT] = 5,
[IEEE802154_SCF_KEY_INDEX] = 6,
[IEEE802154_SCF_KEY_SHORT_INDEX] = 10,
[IEEE802154_SCF_KEY_HW_INDEX] = 14,
};
static int ieee802154_hdr_sechdr_len(u8 sc) static int ieee802154_hdr_sechdr_len(u8 sc)
{ {
switch (IEEE802154_SCF_KEY_ID_MODE(sc)) { return ieee802154_sechdr_lengths[IEEE802154_SCF_KEY_ID_MODE(sc)];
case IEEE802154_SCF_KEY_IMPLICIT: return 5;
case IEEE802154_SCF_KEY_INDEX: return 6;
case IEEE802154_SCF_KEY_SHORT_INDEX: return 10;
case IEEE802154_SCF_KEY_HW_INDEX: return 14;
default: return -EINVAL;
}
} }
static int ieee802154_hdr_minlen(const struct ieee802154_hdr *hdr) static int ieee802154_hdr_minlen(const struct ieee802154_hdr *hdr)
...@@ -285,3 +286,40 @@ ieee802154_hdr_peek_addrs(const struct sk_buff *skb, struct ieee802154_hdr *hdr) ...@@ -285,3 +286,40 @@ ieee802154_hdr_peek_addrs(const struct sk_buff *skb, struct ieee802154_hdr *hdr)
return pos; return pos;
} }
EXPORT_SYMBOL_GPL(ieee802154_hdr_peek_addrs); EXPORT_SYMBOL_GPL(ieee802154_hdr_peek_addrs);
int
ieee802154_hdr_peek(const struct sk_buff *skb, struct ieee802154_hdr *hdr)
{
const u8 *buf = skb_mac_header(skb);
int pos;
pos = ieee802154_hdr_peek_addrs(skb, hdr);
if (pos < 0)
return -EINVAL;
if (hdr->fc.security_enabled) {
u8 key_id_mode = IEEE802154_SCF_KEY_ID_MODE(*(buf + pos));
int want = pos + ieee802154_sechdr_lengths[key_id_mode];
if (buf + want > skb_tail_pointer(skb))
return -EINVAL;
pos += ieee802154_hdr_get_sechdr(buf + pos, &hdr->sec);
}
return pos;
}
EXPORT_SYMBOL_GPL(ieee802154_hdr_peek);
int ieee802154_max_payload(const struct ieee802154_hdr *hdr)
{
int hlen = ieee802154_hdr_minlen(hdr);
if (hdr->fc.security_enabled) {
hlen += ieee802154_sechdr_lengths[hdr->sec.key_id_mode] - 1;
hlen += ieee802154_sechdr_authtag_len(&hdr->sec);
}
return IEEE802154_MTU - hlen - IEEE802154_MFR_SIZE;
}
EXPORT_SYMBOL_GPL(ieee802154_max_payload);
...@@ -59,8 +59,6 @@ mac802154_subif_rx(struct ieee802154_dev *hw, struct sk_buff *skb, u8 lqi) ...@@ -59,8 +59,6 @@ mac802154_subif_rx(struct ieee802154_dev *hw, struct sk_buff *skb, u8 lqi)
skb->protocol = htons(ETH_P_IEEE802154); skb->protocol = htons(ETH_P_IEEE802154);
skb_reset_mac_header(skb); skb_reset_mac_header(skb);
BUILD_BUG_ON(sizeof(struct ieee802154_mac_cb) > sizeof(skb->cb));
if (!(priv->hw.flags & IEEE802154_HW_OMIT_CKSUM)) { if (!(priv->hw.flags & IEEE802154_HW_OMIT_CKSUM)) {
u16 crc; u16 crc;
......
...@@ -124,7 +124,7 @@ void mac802154_get_mac_params(struct net_device *dev, ...@@ -124,7 +124,7 @@ void mac802154_get_mac_params(struct net_device *dev,
mutex_unlock(&priv->hw->slaves_mtx); mutex_unlock(&priv->hw->slaves_mtx);
} }
int mac802154_wpan_open(struct net_device *dev) static int mac802154_wpan_open(struct net_device *dev)
{ {
int rc; int rc;
struct mac802154_sub_if_data *priv = netdev_priv(dev); struct mac802154_sub_if_data *priv = netdev_priv(dev);
...@@ -192,15 +192,17 @@ static int mac802154_header_create(struct sk_buff *skb, ...@@ -192,15 +192,17 @@ static int mac802154_header_create(struct sk_buff *skb,
{ {
struct ieee802154_hdr hdr; struct ieee802154_hdr hdr;
struct mac802154_sub_if_data *priv = netdev_priv(dev); struct mac802154_sub_if_data *priv = netdev_priv(dev);
struct ieee802154_mac_cb *cb = mac_cb(skb);
int hlen; int hlen;
if (!daddr) if (!daddr)
return -EINVAL; return -EINVAL;
memset(&hdr.fc, 0, sizeof(hdr.fc)); memset(&hdr.fc, 0, sizeof(hdr.fc));
hdr.fc.type = mac_cb_type(skb); hdr.fc.type = cb->type;
hdr.fc.security_enabled = mac_cb_is_secen(skb); hdr.fc.security_enabled = cb->secen;
hdr.fc.ack_request = mac_cb_is_ackreq(skb); hdr.fc.ack_request = cb->ackreq;
hdr.seq = ieee802154_mlme_ops(dev)->get_dsn(dev);
if (!saddr) { if (!saddr) {
spin_lock_bh(&priv->mib_lock); spin_lock_bh(&priv->mib_lock);
...@@ -231,7 +233,7 @@ static int mac802154_header_create(struct sk_buff *skb, ...@@ -231,7 +233,7 @@ static int mac802154_header_create(struct sk_buff *skb,
skb_reset_mac_header(skb); skb_reset_mac_header(skb);
skb->mac_len = hlen; skb->mac_len = hlen;
if (hlen + len + 2 > dev->mtu) if (len > ieee802154_max_payload(&hdr))
return -EMSGSIZE; return -EMSGSIZE;
return hlen; return hlen;
...@@ -391,12 +393,12 @@ mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb) ...@@ -391,12 +393,12 @@ mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb)
sdata->dev->stats.rx_packets++; sdata->dev->stats.rx_packets++;
sdata->dev->stats.rx_bytes += skb->len; sdata->dev->stats.rx_bytes += skb->len;
switch (mac_cb_type(skb)) { switch (mac_cb(skb)->type) {
case IEEE802154_FC_TYPE_DATA: case IEEE802154_FC_TYPE_DATA:
return mac802154_process_data(sdata->dev, skb); return mac802154_process_data(sdata->dev, skb);
default: default:
pr_warn("ieee802154: bad frame received (type = %d)\n", pr_warn("ieee802154: bad frame received (type = %d)\n",
mac_cb_type(skb)); mac_cb(skb)->type);
kfree_skb(skb); kfree_skb(skb);
return NET_RX_DROP; return NET_RX_DROP;
} }
...@@ -423,6 +425,7 @@ static int mac802154_parse_frame_start(struct sk_buff *skb) ...@@ -423,6 +425,7 @@ static int mac802154_parse_frame_start(struct sk_buff *skb)
{ {
int hlen; int hlen;
struct ieee802154_hdr hdr; struct ieee802154_hdr hdr;
struct ieee802154_mac_cb *cb = mac_cb_init(skb);
hlen = ieee802154_hdr_pull(skb, &hdr); hlen = ieee802154_hdr_pull(skb, &hdr);
if (hlen < 0) if (hlen < 0)
...@@ -433,18 +436,15 @@ static int mac802154_parse_frame_start(struct sk_buff *skb) ...@@ -433,18 +436,15 @@ static int mac802154_parse_frame_start(struct sk_buff *skb)
pr_debug("fc: %04x dsn: %02x\n", le16_to_cpup((__le16 *)&hdr.fc), pr_debug("fc: %04x dsn: %02x\n", le16_to_cpup((__le16 *)&hdr.fc),
hdr.seq); hdr.seq);
mac_cb(skb)->flags = hdr.fc.type; cb->type = hdr.fc.type;
cb->ackreq = hdr.fc.ack_request;
if (hdr.fc.ack_request) cb->secen = hdr.fc.security_enabled;
mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ;
if (hdr.fc.security_enabled)
mac_cb(skb)->flags |= MAC_CB_FLAG_SECEN;
mac802154_print_addr("destination", &hdr.dest); mac802154_print_addr("destination", &hdr.dest);
mac802154_print_addr("source", &hdr.source); mac802154_print_addr("source", &hdr.source);
mac_cb(skb)->source = hdr.source; cb->source = hdr.source;
mac_cb(skb)->dest = hdr.dest; cb->dest = hdr.dest;
if (hdr.fc.security_enabled) { if (hdr.fc.security_enabled) {
u64 key; u64 key;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment