ieee802154: add definitions for link-layer security and header functions

When dealing with 802.15.4, one often has to know the maximum payload
size for a given packet. This depends on many factors, one of which is
whether or not a security header is present in the frame. These
definitions and functions provide an easy way for any upper layer to
calculate the maximum payload size for a packet. The first obvious user
for this is 6lowpan, which duplicates this calculation and gets it
partially wrong because it ignores security headers.

Signed-off-by: Phoebe Buckheister <phoebe.buckheister@itwm.fraunhofer.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Phoebe Buckheister
2014-05-14 17:43:06 +02:00
committed by David S. Miller
parent 9dbccc30f3
commit c3a6114f31
3 changed files with 83 additions and 7 deletions

View File

@@ -195,15 +195,16 @@ ieee802154_hdr_get_sechdr(const u8 *buf, struct ieee802154_sechdr *hdr)
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)
{
switch (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;
}
return ieee802154_sechdr_lengths[IEEE802154_SCF_KEY_ID_MODE(sc)];
}
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)
return pos;
}
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);