Commit a47e8f5a authored by David S. Miller's avatar David S. Miller

Merge branch 'ieee802154-next'

Phoebe Buckheister says:

====================
802154: implement link-layer security

This patch series implements 802.15.4-2011 link layer security.

Patches 1 and 2 prepare for llsec by adding data structures to represent the
llsec PIB as specified in 802.15.4-2011. I've changed some structures from
their specification to be more sensible, since 802.15.4 specifies some
structures in not-exactly-useful ways. Nested lists are common, but not very
accessible for netlink methods, and not very fast to traverse when searching
for specific elements either.

Patch 3 implements backends for these structures in mac802154.

Patch 4 and 5 implement the encryption and decryption methods, split from patch
3 to ease review. The encryption and decryption methods are almost entirely
compliant with the specified outgoing/incoming frame procedures. Decryption
deviates from the specification slightly where the specification makes no
sense, i.e. encrypted frames with security level 0 may be sent, but must be
dropped an reception - but transforms for processing such frames are given a
few lines in the standard. I've opted to not drop these frames instead of not
implementing the transforms that wouldn't be used if they were dropped.

Patch 6 links the mac802154 llsec with the SoftMAC devices. This is mainly
init//fini code for llsec context, handling of security subheaders and calling
the encryption/decryption methods.

Patch 7 adds sockopts to 802.15.4 dgram sockets to modifiy outgoing security
parameters on a per-socket basis. Ideally, this would also be available for
sockets on 6lowpan devices, but I'm not sure how to do that nicely.

Patch 8 adds forwarders to the llsec configuration methods for netlink, patch
10 implements these netlink accessors. This is mainly mechanical.

Patch 11, implements a key tracking option for devices that previous patches
haven't, because I'm not entirely sure whether this is the best approach to the
problem. It performs reasonably well though, so I decided to include it as a
separate patch in this series instead of sending an RFC just for this one
option.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents e54740e6 f0f77dc6
...@@ -80,6 +80,22 @@ enum { ...@@ -80,6 +80,22 @@ enum {
IEEE802154_ATTR_FRAME_RETRIES, IEEE802154_ATTR_FRAME_RETRIES,
IEEE802154_ATTR_LLSEC_ENABLED,
IEEE802154_ATTR_LLSEC_SECLEVEL,
IEEE802154_ATTR_LLSEC_KEY_MODE,
IEEE802154_ATTR_LLSEC_KEY_SOURCE_SHORT,
IEEE802154_ATTR_LLSEC_KEY_SOURCE_EXTENDED,
IEEE802154_ATTR_LLSEC_KEY_ID,
IEEE802154_ATTR_LLSEC_FRAME_COUNTER,
IEEE802154_ATTR_LLSEC_KEY_BYTES,
IEEE802154_ATTR_LLSEC_KEY_USAGE_FRAME_TYPES,
IEEE802154_ATTR_LLSEC_KEY_USAGE_COMMANDS,
IEEE802154_ATTR_LLSEC_FRAME_TYPE,
IEEE802154_ATTR_LLSEC_CMD_FRAME_ID,
IEEE802154_ATTR_LLSEC_SECLEVELS,
IEEE802154_ATTR_LLSEC_DEV_OVERRIDE,
IEEE802154_ATTR_LLSEC_DEV_KEY_MODE,
__IEEE802154_ATTR_MAX, __IEEE802154_ATTR_MAX,
}; };
...@@ -134,6 +150,21 @@ enum { ...@@ -134,6 +150,21 @@ enum {
IEEE802154_SET_MACPARAMS, IEEE802154_SET_MACPARAMS,
IEEE802154_LLSEC_GETPARAMS,
IEEE802154_LLSEC_SETPARAMS,
IEEE802154_LLSEC_LIST_KEY,
IEEE802154_LLSEC_ADD_KEY,
IEEE802154_LLSEC_DEL_KEY,
IEEE802154_LLSEC_LIST_DEV,
IEEE802154_LLSEC_ADD_DEV,
IEEE802154_LLSEC_DEL_DEV,
IEEE802154_LLSEC_LIST_DEVKEY,
IEEE802154_LLSEC_ADD_DEVKEY,
IEEE802154_LLSEC_DEL_DEVKEY,
IEEE802154_LLSEC_LIST_SECLEVEL,
IEEE802154_LLSEC_ADD_SECLEVEL,
IEEE802154_LLSEC_DEL_SECLEVEL,
__IEEE802154_CMD_MAX, __IEEE802154_CMD_MAX,
}; };
......
...@@ -57,6 +57,14 @@ struct sockaddr_ieee802154 { ...@@ -57,6 +57,14 @@ struct sockaddr_ieee802154 {
/* get/setsockopt */ /* get/setsockopt */
#define SOL_IEEE802154 0 #define SOL_IEEE802154 0
#define WPAN_WANTACK 0 #define WPAN_WANTACK 0
#define WPAN_SECURITY 1
#define WPAN_SECURITY_LEVEL 2
#define WPAN_SECURITY_DEFAULT 0
#define WPAN_SECURITY_OFF 1
#define WPAN_SECURITY_ON 2
#define WPAN_SECURITY_LEVEL_DEFAULT (-1)
#endif #endif
...@@ -225,6 +225,9 @@ struct ieee802154_mac_cb { ...@@ -225,6 +225,9 @@ struct ieee802154_mac_cb {
u8 type; u8 type;
bool ackreq; bool ackreq;
bool secen; bool secen;
bool secen_override;
u8 seclevel;
bool seclevel_override;
struct ieee802154_addr source; struct ieee802154_addr source;
struct ieee802154_addr dest; struct ieee802154_addr dest;
}; };
...@@ -242,6 +245,89 @@ static inline struct ieee802154_mac_cb *mac_cb_init(struct sk_buff *skb) ...@@ -242,6 +245,89 @@ static inline struct ieee802154_mac_cb *mac_cb_init(struct sk_buff *skb)
return mac_cb(skb); return mac_cb(skb);
} }
#define IEEE802154_LLSEC_KEY_SIZE 16
struct ieee802154_llsec_key_id {
u8 mode;
u8 id;
union {
struct ieee802154_addr device_addr;
__le32 short_source;
__le64 extended_source;
};
};
struct ieee802154_llsec_key {
u8 frame_types;
u32 cmd_frame_ids;
u8 key[IEEE802154_LLSEC_KEY_SIZE];
};
struct ieee802154_llsec_key_entry {
struct list_head list;
struct ieee802154_llsec_key_id id;
struct ieee802154_llsec_key *key;
};
struct ieee802154_llsec_device_key {
struct list_head list;
struct ieee802154_llsec_key_id key_id;
u32 frame_counter;
};
enum {
IEEE802154_LLSEC_DEVKEY_IGNORE,
IEEE802154_LLSEC_DEVKEY_RESTRICT,
IEEE802154_LLSEC_DEVKEY_RECORD,
__IEEE802154_LLSEC_DEVKEY_MAX,
};
struct ieee802154_llsec_device {
struct list_head list;
__le16 pan_id;
__le16 short_addr;
__le64 hwaddr;
u32 frame_counter;
bool seclevel_exempt;
u8 key_mode;
struct list_head keys;
};
struct ieee802154_llsec_seclevel {
struct list_head list;
u8 frame_type;
u8 cmd_frame_id;
bool device_override;
u32 sec_levels;
};
struct ieee802154_llsec_params {
bool enabled;
__be32 frame_counter;
u8 out_level;
struct ieee802154_llsec_key_id out_key;
__le64 default_key_source;
__le16 pan_id;
__le64 hwaddr;
__le64 coord_hwaddr;
__le16 coord_shortaddr;
};
struct ieee802154_llsec_table {
struct list_head keys;
struct list_head devices;
struct list_head security_levels;
};
#define IEEE802154_MAC_SCAN_ED 0 #define IEEE802154_MAC_SCAN_ED 0
#define IEEE802154_MAC_SCAN_ACTIVE 1 #define IEEE802154_MAC_SCAN_ACTIVE 1
#define IEEE802154_MAC_SCAN_PASSIVE 2 #define IEEE802154_MAC_SCAN_PASSIVE 2
...@@ -260,6 +346,53 @@ struct ieee802154_mac_params { ...@@ -260,6 +346,53 @@ struct ieee802154_mac_params {
}; };
struct wpan_phy; struct wpan_phy;
enum {
IEEE802154_LLSEC_PARAM_ENABLED = 1 << 0,
IEEE802154_LLSEC_PARAM_FRAME_COUNTER = 1 << 1,
IEEE802154_LLSEC_PARAM_OUT_LEVEL = 1 << 2,
IEEE802154_LLSEC_PARAM_OUT_KEY = 1 << 3,
IEEE802154_LLSEC_PARAM_KEY_SOURCE = 1 << 4,
IEEE802154_LLSEC_PARAM_PAN_ID = 1 << 5,
IEEE802154_LLSEC_PARAM_HWADDR = 1 << 6,
IEEE802154_LLSEC_PARAM_COORD_HWADDR = 1 << 7,
IEEE802154_LLSEC_PARAM_COORD_SHORTADDR = 1 << 8,
};
struct ieee802154_llsec_ops {
int (*get_params)(struct net_device *dev,
struct ieee802154_llsec_params *params);
int (*set_params)(struct net_device *dev,
const struct ieee802154_llsec_params *params,
int changed);
int (*add_key)(struct net_device *dev,
const struct ieee802154_llsec_key_id *id,
const struct ieee802154_llsec_key *key);
int (*del_key)(struct net_device *dev,
const struct ieee802154_llsec_key_id *id);
int (*add_dev)(struct net_device *dev,
const struct ieee802154_llsec_device *llsec_dev);
int (*del_dev)(struct net_device *dev, __le64 dev_addr);
int (*add_devkey)(struct net_device *dev,
__le64 device_addr,
const struct ieee802154_llsec_device_key *key);
int (*del_devkey)(struct net_device *dev,
__le64 device_addr,
const struct ieee802154_llsec_device_key *key);
int (*add_seclevel)(struct net_device *dev,
const struct ieee802154_llsec_seclevel *sl);
int (*del_seclevel)(struct net_device *dev,
const struct ieee802154_llsec_seclevel *sl);
void (*lock_table)(struct net_device *dev);
void (*get_table)(struct net_device *dev,
struct ieee802154_llsec_table **t);
void (*unlock_table)(struct net_device *dev);
};
/* /*
* This should be located at net_device->ml_priv * This should be located at net_device->ml_priv
* *
...@@ -290,6 +423,8 @@ struct ieee802154_mlme_ops { ...@@ -290,6 +423,8 @@ struct ieee802154_mlme_ops {
void (*get_mac_params)(struct net_device *dev, void (*get_mac_params)(struct net_device *dev,
struct ieee802154_mac_params *params); struct ieee802154_mac_params *params);
struct ieee802154_llsec_ops *llsec;
/* The fields below are required. */ /* The fields below are required. */
struct wpan_phy *(*get_phy)(const struct net_device *dev); struct wpan_phy *(*get_phy)(const struct net_device *dev);
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
* Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
*/ */
#include <linux/capability.h>
#include <linux/net.h> #include <linux/net.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/if_arp.h> #include <linux/if_arp.h>
...@@ -47,6 +48,10 @@ struct dgram_sock { ...@@ -47,6 +48,10 @@ struct dgram_sock {
unsigned int bound:1; unsigned int bound:1;
unsigned int connected:1; unsigned int connected:1;
unsigned int want_ack:1; unsigned int want_ack:1;
unsigned int secen:1;
unsigned int secen_override:1;
unsigned int seclevel:3;
unsigned int seclevel_override:1;
}; };
static inline struct dgram_sock *dgram_sk(const struct sock *sk) static inline struct dgram_sock *dgram_sk(const struct sock *sk)
...@@ -264,6 +269,11 @@ static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -264,6 +269,11 @@ static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk,
dst_addr = ro->dst_addr; dst_addr = ro->dst_addr;
} }
cb->secen = ro->secen;
cb->secen_override = ro->secen_override;
cb->seclevel = ro->seclevel;
cb->seclevel_override = ro->seclevel_override;
err = dev_hard_header(skb, dev, ETH_P_IEEE802154, &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)
...@@ -427,6 +437,20 @@ static int dgram_getsockopt(struct sock *sk, int level, int optname, ...@@ -427,6 +437,20 @@ static int dgram_getsockopt(struct sock *sk, int level, int optname,
case WPAN_WANTACK: case WPAN_WANTACK:
val = ro->want_ack; val = ro->want_ack;
break; break;
case WPAN_SECURITY:
if (!ro->secen_override)
val = WPAN_SECURITY_DEFAULT;
else if (ro->secen)
val = WPAN_SECURITY_ON;
else
val = WPAN_SECURITY_OFF;
break;
case WPAN_SECURITY_LEVEL:
if (!ro->seclevel_override)
val = WPAN_SECURITY_LEVEL_DEFAULT;
else
val = ro->seclevel;
break;
default: default:
return -ENOPROTOOPT; return -ENOPROTOOPT;
} }
...@@ -442,6 +466,7 @@ static int dgram_setsockopt(struct sock *sk, int level, int optname, ...@@ -442,6 +466,7 @@ static int dgram_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, unsigned int optlen) char __user *optval, unsigned int optlen)
{ {
struct dgram_sock *ro = dgram_sk(sk); struct dgram_sock *ro = dgram_sk(sk);
struct net *net = sock_net(sk);
int val; int val;
int err = 0; int err = 0;
...@@ -457,6 +482,47 @@ static int dgram_setsockopt(struct sock *sk, int level, int optname, ...@@ -457,6 +482,47 @@ static int dgram_setsockopt(struct sock *sk, int level, int optname,
case WPAN_WANTACK: case WPAN_WANTACK:
ro->want_ack = !!val; ro->want_ack = !!val;
break; break;
case WPAN_SECURITY:
if (!ns_capable(net->user_ns, CAP_NET_ADMIN) &&
!ns_capable(net->user_ns, CAP_NET_RAW)) {
err = -EPERM;
break;
}
switch (val) {
case WPAN_SECURITY_DEFAULT:
ro->secen_override = 0;
break;
case WPAN_SECURITY_ON:
ro->secen_override = 1;
ro->secen = 1;
break;
case WPAN_SECURITY_OFF:
ro->secen_override = 1;
ro->secen = 0;
break;
default:
err = -EINVAL;
break;
}
break;
case WPAN_SECURITY_LEVEL:
if (!ns_capable(net->user_ns, CAP_NET_ADMIN) &&
!ns_capable(net->user_ns, CAP_NET_RAW)) {
err = -EPERM;
break;
}
if (val < WPAN_SECURITY_LEVEL_DEFAULT ||
val > IEEE802154_SCF_SECLEVEL_ENC_MIC128) {
err = -EINVAL;
} else if (val == WPAN_SECURITY_LEVEL_DEFAULT) {
ro->seclevel_override = 0;
} else {
ro->seclevel_override = 1;
ro->seclevel = val;
}
break;
default: default:
err = -ENOPROTOOPT; err = -ENOPROTOOPT;
break; break;
......
...@@ -68,4 +68,23 @@ int ieee802154_list_iface(struct sk_buff *skb, struct genl_info *info); ...@@ -68,4 +68,23 @@ int ieee802154_list_iface(struct sk_buff *skb, struct genl_info *info);
int ieee802154_dump_iface(struct sk_buff *skb, struct netlink_callback *cb); int ieee802154_dump_iface(struct sk_buff *skb, struct netlink_callback *cb);
int ieee802154_set_macparams(struct sk_buff *skb, struct genl_info *info); int ieee802154_set_macparams(struct sk_buff *skb, struct genl_info *info);
int ieee802154_llsec_getparams(struct sk_buff *skb, struct genl_info *info);
int ieee802154_llsec_setparams(struct sk_buff *skb, struct genl_info *info);
int ieee802154_llsec_add_key(struct sk_buff *skb, struct genl_info *info);
int ieee802154_llsec_del_key(struct sk_buff *skb, struct genl_info *info);
int ieee802154_llsec_dump_keys(struct sk_buff *skb,
struct netlink_callback *cb);
int ieee802154_llsec_add_dev(struct sk_buff *skb, struct genl_info *info);
int ieee802154_llsec_del_dev(struct sk_buff *skb, struct genl_info *info);
int ieee802154_llsec_dump_devs(struct sk_buff *skb,
struct netlink_callback *cb);
int ieee802154_llsec_add_devkey(struct sk_buff *skb, struct genl_info *info);
int ieee802154_llsec_del_devkey(struct sk_buff *skb, struct genl_info *info);
int ieee802154_llsec_dump_devkeys(struct sk_buff *skb,
struct netlink_callback *cb);
int ieee802154_llsec_add_seclevel(struct sk_buff *skb, struct genl_info *info);
int ieee802154_llsec_del_seclevel(struct sk_buff *skb, struct genl_info *info);
int ieee802154_llsec_dump_seclevels(struct sk_buff *skb,
struct netlink_callback *cb);
#endif #endif
...@@ -124,6 +124,26 @@ static const struct genl_ops ieee8021154_ops[] = { ...@@ -124,6 +124,26 @@ static const struct genl_ops ieee8021154_ops[] = {
IEEE802154_DUMP(IEEE802154_LIST_IFACE, ieee802154_list_iface, IEEE802154_DUMP(IEEE802154_LIST_IFACE, ieee802154_list_iface,
ieee802154_dump_iface), ieee802154_dump_iface),
IEEE802154_OP(IEEE802154_SET_MACPARAMS, ieee802154_set_macparams), IEEE802154_OP(IEEE802154_SET_MACPARAMS, ieee802154_set_macparams),
IEEE802154_OP(IEEE802154_LLSEC_GETPARAMS, ieee802154_llsec_getparams),
IEEE802154_OP(IEEE802154_LLSEC_SETPARAMS, ieee802154_llsec_setparams),
IEEE802154_DUMP(IEEE802154_LLSEC_LIST_KEY, NULL,
ieee802154_llsec_dump_keys),
IEEE802154_OP(IEEE802154_LLSEC_ADD_KEY, ieee802154_llsec_add_key),
IEEE802154_OP(IEEE802154_LLSEC_DEL_KEY, ieee802154_llsec_del_key),
IEEE802154_DUMP(IEEE802154_LLSEC_LIST_DEV, NULL,
ieee802154_llsec_dump_devs),
IEEE802154_OP(IEEE802154_LLSEC_ADD_DEV, ieee802154_llsec_add_dev),
IEEE802154_OP(IEEE802154_LLSEC_DEL_DEV, ieee802154_llsec_del_dev),
IEEE802154_DUMP(IEEE802154_LLSEC_LIST_DEVKEY, NULL,
ieee802154_llsec_dump_devkeys),
IEEE802154_OP(IEEE802154_LLSEC_ADD_DEVKEY, ieee802154_llsec_add_devkey),
IEEE802154_OP(IEEE802154_LLSEC_DEL_DEVKEY, ieee802154_llsec_del_devkey),
IEEE802154_DUMP(IEEE802154_LLSEC_LIST_SECLEVEL, NULL,
ieee802154_llsec_dump_seclevels),
IEEE802154_OP(IEEE802154_LLSEC_ADD_SECLEVEL,
ieee802154_llsec_add_seclevel),
IEEE802154_OP(IEEE802154_LLSEC_DEL_SECLEVEL,
ieee802154_llsec_del_seclevel),
}; };
static const struct genl_multicast_group ieee802154_mcgrps[] = { static const struct genl_multicast_group ieee802154_mcgrps[] = {
......
This diff is collapsed.
...@@ -62,5 +62,21 @@ const struct nla_policy ieee802154_policy[IEEE802154_ATTR_MAX + 1] = { ...@@ -62,5 +62,21 @@ const struct nla_policy ieee802154_policy[IEEE802154_ATTR_MAX + 1] = {
[IEEE802154_ATTR_CSMA_MAX_BE] = { .type = NLA_U8, }, [IEEE802154_ATTR_CSMA_MAX_BE] = { .type = NLA_U8, },
[IEEE802154_ATTR_FRAME_RETRIES] = { .type = NLA_S8, }, [IEEE802154_ATTR_FRAME_RETRIES] = { .type = NLA_S8, },
[IEEE802154_ATTR_LLSEC_ENABLED] = { .type = NLA_U8, },
[IEEE802154_ATTR_LLSEC_SECLEVEL] = { .type = NLA_U8, },
[IEEE802154_ATTR_LLSEC_KEY_MODE] = { .type = NLA_U8, },
[IEEE802154_ATTR_LLSEC_KEY_SOURCE_SHORT] = { .type = NLA_U32, },
[IEEE802154_ATTR_LLSEC_KEY_SOURCE_EXTENDED] = { .type = NLA_HW_ADDR, },
[IEEE802154_ATTR_LLSEC_KEY_ID] = { .type = NLA_U8, },
[IEEE802154_ATTR_LLSEC_FRAME_COUNTER] = { .type = NLA_U32 },
[IEEE802154_ATTR_LLSEC_KEY_BYTES] = { .len = 16, },
[IEEE802154_ATTR_LLSEC_KEY_USAGE_FRAME_TYPES] = { .type = NLA_U8, },
[IEEE802154_ATTR_LLSEC_KEY_USAGE_COMMANDS] = { .len = 258 / 8 },
[IEEE802154_ATTR_LLSEC_FRAME_TYPE] = { .type = NLA_U8, },
[IEEE802154_ATTR_LLSEC_CMD_FRAME_ID] = { .type = NLA_U8, },
[IEEE802154_ATTR_LLSEC_SECLEVELS] = { .type = NLA_U8, },
[IEEE802154_ATTR_LLSEC_DEV_OVERRIDE] = { .type = NLA_U8, },
[IEEE802154_ATTR_LLSEC_DEV_KEY_MODE] = { .type = NLA_U8, },
}; };
...@@ -2,6 +2,10 @@ config MAC802154 ...@@ -2,6 +2,10 @@ config MAC802154
tristate "Generic IEEE 802.15.4 Soft Networking Stack (mac802154)" tristate "Generic IEEE 802.15.4 Soft Networking Stack (mac802154)"
depends on IEEE802154 depends on IEEE802154
select CRC_CCITT select CRC_CCITT
select CRYPTO_AUTHENC
select CRYPTO_CCM
select CRYPTO_CTR
select CRYPTO_AES
---help--- ---help---
This option enables the hardware independent IEEE 802.15.4 This option enables the hardware independent IEEE 802.15.4
networking stack for SoftMAC devices (the ones implementing networking stack for SoftMAC devices (the ones implementing
......
obj-$(CONFIG_MAC802154) += mac802154.o obj-$(CONFIG_MAC802154) += mac802154.o
mac802154-objs := ieee802154_dev.o rx.o tx.o mac_cmd.o mib.o monitor.o wpan.o mac802154-objs := ieee802154_dev.o rx.o tx.o mac_cmd.o mib.o \
monitor.o wpan.o llsec.o
ccflags-y += -D__CHECK_ENDIAN__ ccflags-y += -D__CHECK_ENDIAN__
This diff is collapsed.
/*
* Copyright (C) 2014 Fraunhofer ITWM
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Written by:
* Phoebe Buckheister <phoebe.buckheister@itwm.fraunhofer.de>
*/
#ifndef MAC802154_LLSEC_H
#define MAC802154_LLSEC_H
#include <linux/slab.h>
#include <linux/hashtable.h>
#include <linux/crypto.h>
#include <linux/kref.h>
#include <linux/spinlock.h>
#include <net/af_ieee802154.h>
#include <net/ieee802154_netdev.h>
struct mac802154_llsec_key {
struct ieee802154_llsec_key key;
/* one tfm for each authsize (4/8/16) */
struct crypto_aead *tfm[3];
struct crypto_blkcipher *tfm0;
struct kref ref;
};
struct mac802154_llsec_device_key {
struct ieee802154_llsec_device_key devkey;
struct rcu_head rcu;
};
struct mac802154_llsec_device {
struct ieee802154_llsec_device dev;
struct hlist_node bucket_s;
struct hlist_node bucket_hw;
/* protects dev.frame_counter and the elements of dev.keys */
spinlock_t lock;
struct rcu_head rcu;
};
struct mac802154_llsec_seclevel {
struct ieee802154_llsec_seclevel level;
struct rcu_head rcu;
};
struct mac802154_llsec {
struct ieee802154_llsec_params params;
struct ieee802154_llsec_table table;
DECLARE_HASHTABLE(devices_short, 6);
DECLARE_HASHTABLE(devices_hw, 6);
/* protects params, all other fields are fine with RCU */
rwlock_t lock;
};
void mac802154_llsec_init(struct mac802154_llsec *sec);
void mac802154_llsec_destroy(struct mac802154_llsec *sec);
int mac802154_llsec_get_params(struct mac802154_llsec *sec,
struct ieee802154_llsec_params *params);
int mac802154_llsec_set_params(struct mac802154_llsec *sec,
const struct ieee802154_llsec_params *params,
int changed);
int mac802154_llsec_key_add(struct mac802154_llsec *sec,
const struct ieee802154_llsec_key_id *id,
const struct ieee802154_llsec_key *key);
int mac802154_llsec_key_del(struct mac802154_llsec *sec,
const struct ieee802154_llsec_key_id *key);
int mac802154_llsec_dev_add(struct mac802154_llsec *sec,
const struct ieee802154_llsec_device *dev);
int mac802154_llsec_dev_del(struct mac802154_llsec *sec,
__le64 device_addr);
int mac802154_llsec_devkey_add(struct mac802154_llsec *sec,
__le64 dev_addr,
const struct ieee802154_llsec_device_key *key);
int mac802154_llsec_devkey_del(struct mac802154_llsec *sec,
__le64 dev_addr,
const struct ieee802154_llsec_device_key *key);
int mac802154_llsec_seclevel_add(struct mac802154_llsec *sec,
const struct ieee802154_llsec_seclevel *sl);
int mac802154_llsec_seclevel_del(struct mac802154_llsec *sec,
const struct ieee802154_llsec_seclevel *sl);
int mac802154_llsec_encrypt(struct mac802154_llsec *sec, struct sk_buff *skb);
int mac802154_llsec_decrypt(struct mac802154_llsec *sec, struct sk_buff *skb);
#endif /* MAC802154_LLSEC_H */
...@@ -23,8 +23,12 @@ ...@@ -23,8 +23,12 @@
#ifndef MAC802154_H #ifndef MAC802154_H
#define MAC802154_H #define MAC802154_H
#include <linux/mutex.h>
#include <net/mac802154.h>
#include <net/ieee802154_netdev.h> #include <net/ieee802154_netdev.h>
#include "llsec.h"
/* mac802154 device private data */ /* mac802154 device private data */
struct mac802154_priv { struct mac802154_priv {
struct ieee802154_dev hw; struct ieee802154_dev hw;
...@@ -90,6 +94,13 @@ struct mac802154_sub_if_data { ...@@ -90,6 +94,13 @@ struct mac802154_sub_if_data {
u8 bsn; u8 bsn;
/* MAC DSN field */ /* MAC DSN field */
u8 dsn; u8 dsn;
/* protects sec from concurrent access by netlink. access by
* encrypt/decrypt/header_create safe without additional protection.
*/
struct mutex sec_mtx;
struct mac802154_llsec sec;
}; };
#define mac802154_to_priv(_hw) container_of(_hw, struct mac802154_priv, hw) #define mac802154_to_priv(_hw) container_of(_hw, struct mac802154_priv, hw)
...@@ -125,4 +136,37 @@ int mac802154_set_mac_params(struct net_device *dev, ...@@ -125,4 +136,37 @@ int mac802154_set_mac_params(struct net_device *dev,
void mac802154_get_mac_params(struct net_device *dev, void mac802154_get_mac_params(struct net_device *dev,
struct ieee802154_mac_params *params); struct ieee802154_mac_params *params);
int mac802154_get_params(struct net_device *dev,
struct ieee802154_llsec_params *params);
int mac802154_set_params(struct net_device *dev,
const struct ieee802154_llsec_params *params,
int changed);
int mac802154_add_key(struct net_device *dev,
const struct ieee802154_llsec_key_id *id,
const struct ieee802154_llsec_key *key);
int mac802154_del_key(struct net_device *dev,
const struct ieee802154_llsec_key_id *id);
int mac802154_add_dev(struct net_device *dev,
const struct ieee802154_llsec_device *llsec_dev);
int mac802154_del_dev(struct net_device *dev, __le64 dev_addr);
int mac802154_add_devkey(struct net_device *dev,
__le64 device_addr,
const struct ieee802154_llsec_device_key *key);
int mac802154_del_devkey(struct net_device *dev,
__le64 device_addr,
const struct ieee802154_llsec_device_key *key);
int mac802154_add_seclevel(struct net_device *dev,
const struct ieee802154_llsec_seclevel *sl);
int mac802154_del_seclevel(struct net_device *dev,
const struct ieee802154_llsec_seclevel *sl);
void mac802154_lock_table(struct net_device *dev);
void mac802154_get_table(struct net_device *dev,
struct ieee802154_llsec_table **t);
void mac802154_unlock_table(struct net_device *dev);
#endif /* MAC802154_H */ #endif /* MAC802154_H */
...@@ -40,6 +40,9 @@ static int mac802154_mlme_start_req(struct net_device *dev, ...@@ -40,6 +40,9 @@ static int mac802154_mlme_start_req(struct net_device *dev,
u8 pan_coord, u8 blx, u8 pan_coord, u8 blx,
u8 coord_realign) u8 coord_realign)
{ {
struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
int rc = 0;
BUG_ON(addr->mode != IEEE802154_ADDR_SHORT); BUG_ON(addr->mode != IEEE802154_ADDR_SHORT);
mac802154_dev_set_pan_id(dev, addr->pan_id); mac802154_dev_set_pan_id(dev, addr->pan_id);
...@@ -47,12 +50,31 @@ static int mac802154_mlme_start_req(struct net_device *dev, ...@@ -47,12 +50,31 @@ static int mac802154_mlme_start_req(struct net_device *dev,
mac802154_dev_set_ieee_addr(dev); mac802154_dev_set_ieee_addr(dev);
mac802154_dev_set_page_channel(dev, page, channel); mac802154_dev_set_page_channel(dev, page, channel);
if (ops->llsec) {
struct ieee802154_llsec_params params;
int changed = 0;
params.coord_shortaddr = addr->short_addr;
changed |= IEEE802154_LLSEC_PARAM_COORD_SHORTADDR;
params.pan_id = addr->pan_id;
changed |= IEEE802154_LLSEC_PARAM_PAN_ID;
params.hwaddr = ieee802154_devaddr_from_raw(dev->dev_addr);
changed |= IEEE802154_LLSEC_PARAM_HWADDR;
params.coord_hwaddr = params.hwaddr;
changed |= IEEE802154_LLSEC_PARAM_COORD_HWADDR;
rc = ops->llsec->set_params(dev, &params, changed);
}
/* FIXME: add validation for unused parameters to be sane /* FIXME: add validation for unused parameters to be sane
* for SoftMAC * for SoftMAC
*/ */
ieee802154_nl_start_confirm(dev, IEEE802154_SUCCESS); ieee802154_nl_start_confirm(dev, IEEE802154_SUCCESS);
return 0; return rc;
} }
static struct wpan_phy *mac802154_get_phy(const struct net_device *dev) static struct wpan_phy *mac802154_get_phy(const struct net_device *dev)
...@@ -64,6 +86,22 @@ static struct wpan_phy *mac802154_get_phy(const struct net_device *dev) ...@@ -64,6 +86,22 @@ static struct wpan_phy *mac802154_get_phy(const struct net_device *dev)
return to_phy(get_device(&priv->hw->phy->dev)); return to_phy(get_device(&priv->hw->phy->dev));
} }
static struct ieee802154_llsec_ops mac802154_llsec_ops = {
.get_params = mac802154_get_params,
.set_params = mac802154_set_params,
.add_key = mac802154_add_key,
.del_key = mac802154_del_key,
.add_dev = mac802154_add_dev,
.del_dev = mac802154_del_dev,
.add_devkey = mac802154_add_devkey,
.del_devkey = mac802154_del_devkey,
.add_seclevel = mac802154_add_seclevel,
.del_seclevel = mac802154_del_seclevel,
.lock_table = mac802154_lock_table,
.get_table = mac802154_get_table,
.unlock_table = mac802154_unlock_table,
};
struct ieee802154_reduced_mlme_ops mac802154_mlme_reduced = { struct ieee802154_reduced_mlme_ops mac802154_mlme_reduced = {
.get_phy = mac802154_get_phy, .get_phy = mac802154_get_phy,
}; };
...@@ -75,6 +113,8 @@ struct ieee802154_mlme_ops mac802154_mlme_wpan = { ...@@ -75,6 +113,8 @@ struct ieee802154_mlme_ops mac802154_mlme_wpan = {
.get_short_addr = mac802154_dev_get_short_addr, .get_short_addr = mac802154_dev_get_short_addr,
.get_dsn = mac802154_dev_get_dsn, .get_dsn = mac802154_dev_get_dsn,
.llsec = &mac802154_llsec_ops,
.set_mac_params = mac802154_set_mac_params, .set_mac_params = mac802154_set_mac_params,
.get_mac_params = mac802154_get_mac_params, .get_mac_params = mac802154_get_mac_params,
}; };
...@@ -213,3 +213,190 @@ void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan) ...@@ -213,3 +213,190 @@ void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan)
} else } else
mutex_unlock(&priv->hw->phy->pib_lock); mutex_unlock(&priv->hw->phy->pib_lock);
} }
int mac802154_get_params(struct net_device *dev,
struct ieee802154_llsec_params *params)
{
struct mac802154_sub_if_data *priv = netdev_priv(dev);
int res;
BUG_ON(dev->type != ARPHRD_IEEE802154);
mutex_lock(&priv->sec_mtx);
res = mac802154_llsec_get_params(&priv->sec, params);
mutex_unlock(&priv->sec_mtx);
return res;
}
int mac802154_set_params(struct net_device *dev,
const struct ieee802154_llsec_params *params,
int changed)
{
struct mac802154_sub_if_data *priv = netdev_priv(dev);
int res;
BUG_ON(dev->type != ARPHRD_IEEE802154);
mutex_lock(&priv->sec_mtx);
res = mac802154_llsec_set_params(&priv->sec, params, changed);
mutex_unlock(&priv->sec_mtx);
return res;
}
int mac802154_add_key(struct net_device *dev,
const struct ieee802154_llsec_key_id *id,
const struct ieee802154_llsec_key *key)
{
struct mac802154_sub_if_data *priv = netdev_priv(dev);
int res;
BUG_ON(dev->type != ARPHRD_IEEE802154);
mutex_lock(&priv->sec_mtx);
res = mac802154_llsec_key_add(&priv->sec, id, key);
mutex_unlock(&priv->sec_mtx);
return res;
}
int mac802154_del_key(struct net_device *dev,
const struct ieee802154_llsec_key_id *id)
{
struct mac802154_sub_if_data *priv = netdev_priv(dev);
int res;
BUG_ON(dev->type != ARPHRD_IEEE802154);
mutex_lock(&priv->sec_mtx);
res = mac802154_llsec_key_del(&priv->sec, id);
mutex_unlock(&priv->sec_mtx);
return res;
}
int mac802154_add_dev(struct net_device *dev,
const struct ieee802154_llsec_device *llsec_dev)
{
struct mac802154_sub_if_data *priv = netdev_priv(dev);
int res;
BUG_ON(dev->type != ARPHRD_IEEE802154);
mutex_lock(&priv->sec_mtx);
res = mac802154_llsec_dev_add(&priv->sec, llsec_dev);
mutex_unlock(&priv->sec_mtx);
return res;
}
int mac802154_del_dev(struct net_device *dev, __le64 dev_addr)
{
struct mac802154_sub_if_data *priv = netdev_priv(dev);
int res;
BUG_ON(dev->type != ARPHRD_IEEE802154);
mutex_lock(&priv->sec_mtx);
res = mac802154_llsec_dev_del(&priv->sec, dev_addr);
mutex_unlock(&priv->sec_mtx);
return res;
}
int mac802154_add_devkey(struct net_device *dev,
__le64 device_addr,
const struct ieee802154_llsec_device_key *key)
{
struct mac802154_sub_if_data *priv = netdev_priv(dev);
int res;
BUG_ON(dev->type != ARPHRD_IEEE802154);
mutex_lock(&priv->sec_mtx);
res = mac802154_llsec_devkey_add(&priv->sec, device_addr, key);
mutex_unlock(&priv->sec_mtx);
return res;
}
int mac802154_del_devkey(struct net_device *dev,
__le64 device_addr,
const struct ieee802154_llsec_device_key *key)
{
struct mac802154_sub_if_data *priv = netdev_priv(dev);
int res;
BUG_ON(dev->type != ARPHRD_IEEE802154);
mutex_lock(&priv->sec_mtx);
res = mac802154_llsec_devkey_del(&priv->sec, device_addr, key);
mutex_unlock(&priv->sec_mtx);
return res;
}
int mac802154_add_seclevel(struct net_device *dev,
const struct ieee802154_llsec_seclevel *sl)
{
struct mac802154_sub_if_data *priv = netdev_priv(dev);
int res;
BUG_ON(dev->type != ARPHRD_IEEE802154);
mutex_lock(&priv->sec_mtx);
res = mac802154_llsec_seclevel_add(&priv->sec, sl);
mutex_unlock(&priv->sec_mtx);
return res;
}
int mac802154_del_seclevel(struct net_device *dev,
const struct ieee802154_llsec_seclevel *sl)
{
struct mac802154_sub_if_data *priv = netdev_priv(dev);
int res;
BUG_ON(dev->type != ARPHRD_IEEE802154);
mutex_lock(&priv->sec_mtx);
res = mac802154_llsec_seclevel_del(&priv->sec, sl);
mutex_unlock(&priv->sec_mtx);
return res;
}
void mac802154_lock_table(struct net_device *dev)
{
struct mac802154_sub_if_data *priv = netdev_priv(dev);
BUG_ON(dev->type != ARPHRD_IEEE802154);
mutex_lock(&priv->sec_mtx);
}
void mac802154_get_table(struct net_device *dev,
struct ieee802154_llsec_table **t)
{
struct mac802154_sub_if_data *priv = netdev_priv(dev);
BUG_ON(dev->type != ARPHRD_IEEE802154);
*t = &priv->sec.table;
}
void mac802154_unlock_table(struct net_device *dev)
{
struct mac802154_sub_if_data *priv = netdev_priv(dev);
BUG_ON(dev->type != ARPHRD_IEEE802154);
mutex_unlock(&priv->sec_mtx);
}
...@@ -35,6 +35,28 @@ ...@@ -35,6 +35,28 @@
#include "mac802154.h" #include "mac802154.h"
static int mac802154_wpan_update_llsec(struct net_device *dev)
{
struct mac802154_sub_if_data *priv = netdev_priv(dev);
struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
int rc = 0;
if (ops->llsec) {
struct ieee802154_llsec_params params;
int changed = 0;
params.pan_id = priv->pan_id;
changed |= IEEE802154_LLSEC_PARAM_PAN_ID;
params.hwaddr = priv->extended_addr;
changed |= IEEE802154_LLSEC_PARAM_HWADDR;
rc = ops->llsec->set_params(dev, &params, changed);
}
return rc;
}
static int static int
mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{ {
...@@ -81,7 +103,7 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -81,7 +103,7 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
priv->pan_id = cpu_to_le16(sa->addr.pan_id); priv->pan_id = cpu_to_le16(sa->addr.pan_id);
priv->short_addr = cpu_to_le16(sa->addr.short_addr); priv->short_addr = cpu_to_le16(sa->addr.short_addr);
err = 0; err = mac802154_wpan_update_llsec(dev);
break; break;
} }
...@@ -99,7 +121,7 @@ static int mac802154_wpan_mac_addr(struct net_device *dev, void *p) ...@@ -99,7 +121,7 @@ static int mac802154_wpan_mac_addr(struct net_device *dev, void *p)
/* FIXME: validate addr */ /* FIXME: validate addr */
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
mac802154_dev_set_ieee_addr(dev); mac802154_dev_set_ieee_addr(dev);
return 0; return mac802154_wpan_update_llsec(dev);
} }
int mac802154_set_mac_params(struct net_device *dev, int mac802154_set_mac_params(struct net_device *dev,
...@@ -183,6 +205,38 @@ static int mac802154_wpan_open(struct net_device *dev) ...@@ -183,6 +205,38 @@ static int mac802154_wpan_open(struct net_device *dev)
return rc; return rc;
} }
static int mac802154_set_header_security(struct mac802154_sub_if_data *priv,
struct ieee802154_hdr *hdr,
const struct ieee802154_mac_cb *cb)
{
struct ieee802154_llsec_params params;
u8 level;
mac802154_llsec_get_params(&priv->sec, &params);
if (!params.enabled && cb->secen_override && cb->secen)
return -EINVAL;
if (!params.enabled ||
(cb->secen_override && !cb->secen) ||
!params.out_level)
return 0;
if (cb->seclevel_override && !cb->seclevel)
return -EINVAL;
level = cb->seclevel_override ? cb->seclevel : params.out_level;
hdr->fc.security_enabled = 1;
hdr->sec.level = level;
hdr->sec.key_id_mode = params.out_key.mode;
if (params.out_key.mode == IEEE802154_SCF_KEY_SHORT_INDEX)
hdr->sec.short_src = params.out_key.short_source;
else if (params.out_key.mode == IEEE802154_SCF_KEY_HW_INDEX)
hdr->sec.extended_src = params.out_key.extended_source;
hdr->sec.key_id = params.out_key.id;
return 0;
}
static int mac802154_header_create(struct sk_buff *skb, static int mac802154_header_create(struct sk_buff *skb,
struct net_device *dev, struct net_device *dev,
unsigned short type, unsigned short type,
...@@ -204,6 +258,9 @@ static int mac802154_header_create(struct sk_buff *skb, ...@@ -204,6 +258,9 @@ static int mac802154_header_create(struct sk_buff *skb,
hdr.fc.ack_request = cb->ackreq; hdr.fc.ack_request = cb->ackreq;
hdr.seq = ieee802154_mlme_ops(dev)->get_dsn(dev); hdr.seq = ieee802154_mlme_ops(dev)->get_dsn(dev);
if (mac802154_set_header_security(priv, &hdr, cb) < 0)
return -EINVAL;
if (!saddr) { if (!saddr) {
spin_lock_bh(&priv->mib_lock); spin_lock_bh(&priv->mib_lock);
...@@ -259,6 +316,7 @@ mac802154_wpan_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -259,6 +316,7 @@ mac802154_wpan_xmit(struct sk_buff *skb, struct net_device *dev)
{ {
struct mac802154_sub_if_data *priv; struct mac802154_sub_if_data *priv;
u8 chan, page; u8 chan, page;
int rc;
priv = netdev_priv(dev); priv = netdev_priv(dev);
...@@ -274,6 +332,13 @@ mac802154_wpan_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -274,6 +332,13 @@ mac802154_wpan_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
rc = mac802154_llsec_encrypt(&priv->sec, skb);
if (rc) {
pr_warn("encryption failed: %i\n", rc);
kfree_skb(skb);
return NETDEV_TX_OK;
}
skb->skb_iif = dev->ifindex; skb->skb_iif = dev->ifindex;
dev->stats.tx_packets++; dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len; dev->stats.tx_bytes += skb->len;
...@@ -294,6 +359,15 @@ static const struct net_device_ops mac802154_wpan_ops = { ...@@ -294,6 +359,15 @@ static const struct net_device_ops mac802154_wpan_ops = {
.ndo_set_mac_address = mac802154_wpan_mac_addr, .ndo_set_mac_address = mac802154_wpan_mac_addr,
}; };
static void mac802154_wpan_free(struct net_device *dev)
{
struct mac802154_sub_if_data *priv = netdev_priv(dev);
mac802154_llsec_destroy(&priv->sec);
free_netdev(dev);
}
void mac802154_wpan_setup(struct net_device *dev) void mac802154_wpan_setup(struct net_device *dev)
{ {
struct mac802154_sub_if_data *priv; struct mac802154_sub_if_data *priv;
...@@ -303,14 +377,14 @@ void mac802154_wpan_setup(struct net_device *dev) ...@@ -303,14 +377,14 @@ void mac802154_wpan_setup(struct net_device *dev)
dev->hard_header_len = MAC802154_FRAME_HARD_HEADER_LEN; dev->hard_header_len = MAC802154_FRAME_HARD_HEADER_LEN;
dev->header_ops = &mac802154_header_ops; dev->header_ops = &mac802154_header_ops;
dev->needed_tailroom = 2; /* FCS */ dev->needed_tailroom = 2 + 16; /* FCS + MIC */
dev->mtu = IEEE802154_MTU; dev->mtu = IEEE802154_MTU;
dev->tx_queue_len = 300; dev->tx_queue_len = 300;
dev->type = ARPHRD_IEEE802154; dev->type = ARPHRD_IEEE802154;
dev->flags = IFF_NOARP | IFF_BROADCAST; dev->flags = IFF_NOARP | IFF_BROADCAST;
dev->watchdog_timeo = 0; dev->watchdog_timeo = 0;
dev->destructor = free_netdev; dev->destructor = mac802154_wpan_free;
dev->netdev_ops = &mac802154_wpan_ops; dev->netdev_ops = &mac802154_wpan_ops;
dev->ml_priv = &mac802154_mlme_wpan; dev->ml_priv = &mac802154_mlme_wpan;
...@@ -321,6 +395,7 @@ void mac802154_wpan_setup(struct net_device *dev) ...@@ -321,6 +395,7 @@ void mac802154_wpan_setup(struct net_device *dev)
priv->page = 0; priv->page = 0;
spin_lock_init(&priv->mib_lock); spin_lock_init(&priv->mib_lock);
mutex_init(&priv->sec_mtx);
get_random_bytes(&priv->bsn, 1); get_random_bytes(&priv->bsn, 1);
get_random_bytes(&priv->dsn, 1); get_random_bytes(&priv->dsn, 1);
...@@ -333,6 +408,8 @@ void mac802154_wpan_setup(struct net_device *dev) ...@@ -333,6 +408,8 @@ void mac802154_wpan_setup(struct net_device *dev)
priv->pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST); priv->pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST);
priv->short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST); priv->short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
mac802154_llsec_init(&priv->sec);
} }
static int mac802154_process_data(struct net_device *dev, struct sk_buff *skb) static int mac802154_process_data(struct net_device *dev, struct sk_buff *skb)
...@@ -341,9 +418,11 @@ static int mac802154_process_data(struct net_device *dev, struct sk_buff *skb) ...@@ -341,9 +418,11 @@ static int mac802154_process_data(struct net_device *dev, struct sk_buff *skb)
} }
static int static int
mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb) mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb,
const struct ieee802154_hdr *hdr)
{ {
__le16 span, sshort; __le16 span, sshort;
int rc;
pr_debug("getting packet via slave interface %s\n", sdata->dev->name); pr_debug("getting packet via slave interface %s\n", sdata->dev->name);
...@@ -390,6 +469,12 @@ mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb) ...@@ -390,6 +469,12 @@ mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb)
skb->dev = sdata->dev; skb->dev = sdata->dev;
rc = mac802154_llsec_decrypt(&sdata->sec, skb);
if (rc) {
pr_debug("decryption failed: %i\n", rc);
return NET_RX_DROP;
}
sdata->dev->stats.rx_packets++; sdata->dev->stats.rx_packets++;
sdata->dev->stats.rx_bytes += skb->len; sdata->dev->stats.rx_bytes += skb->len;
...@@ -421,60 +506,58 @@ static void mac802154_print_addr(const char *name, ...@@ -421,60 +506,58 @@ static void mac802154_print_addr(const char *name,
} }
} }
static int mac802154_parse_frame_start(struct sk_buff *skb) static int mac802154_parse_frame_start(struct sk_buff *skb,
struct ieee802154_hdr *hdr)
{ {
int hlen; int hlen;
struct ieee802154_hdr hdr;
struct ieee802154_mac_cb *cb = mac_cb_init(skb); 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)
return -EINVAL; return -EINVAL;
skb->mac_len = hlen; skb->mac_len = hlen;
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);
cb->type = hdr.fc.type; cb->type = hdr->fc.type;
cb->ackreq = hdr.fc.ack_request; cb->ackreq = hdr->fc.ack_request;
cb->secen = hdr.fc.security_enabled; cb->secen = hdr->fc.security_enabled;
mac802154_print_addr("destination", &hdr.dest); mac802154_print_addr("destination", &hdr->dest);
mac802154_print_addr("source", &hdr.source); mac802154_print_addr("source", &hdr->source);
cb->source = hdr.source; cb->source = hdr->source;
cb->dest = hdr.dest; cb->dest = hdr->dest;
if (hdr.fc.security_enabled) { if (hdr->fc.security_enabled) {
u64 key; u64 key;
pr_debug("seclevel %i\n", hdr.sec.level); pr_debug("seclevel %i\n", hdr->sec.level);
switch (hdr.sec.key_id_mode) { switch (hdr->sec.key_id_mode) {
case IEEE802154_SCF_KEY_IMPLICIT: case IEEE802154_SCF_KEY_IMPLICIT:
pr_debug("implicit key\n"); pr_debug("implicit key\n");
break; break;
case IEEE802154_SCF_KEY_INDEX: case IEEE802154_SCF_KEY_INDEX:
pr_debug("key %02x\n", hdr.sec.key_id); pr_debug("key %02x\n", hdr->sec.key_id);
break; break;
case IEEE802154_SCF_KEY_SHORT_INDEX: case IEEE802154_SCF_KEY_SHORT_INDEX:
pr_debug("key %04x:%04x %02x\n", pr_debug("key %04x:%04x %02x\n",
le32_to_cpu(hdr.sec.short_src) >> 16, le32_to_cpu(hdr->sec.short_src) >> 16,
le32_to_cpu(hdr.sec.short_src) & 0xffff, le32_to_cpu(hdr->sec.short_src) & 0xffff,
hdr.sec.key_id); hdr->sec.key_id);
break; break;
case IEEE802154_SCF_KEY_HW_INDEX: case IEEE802154_SCF_KEY_HW_INDEX:
key = swab64((__force u64) hdr.sec.extended_src); key = swab64((__force u64) hdr->sec.extended_src);
pr_debug("key source %8phC %02x\n", &key, pr_debug("key source %8phC %02x\n", &key,
hdr.sec.key_id); hdr->sec.key_id);
break; break;
} }
return -EINVAL;
} }
return 0; return 0;
...@@ -485,8 +568,9 @@ void mac802154_wpans_rx(struct mac802154_priv *priv, struct sk_buff *skb) ...@@ -485,8 +568,9 @@ void mac802154_wpans_rx(struct mac802154_priv *priv, struct sk_buff *skb)
int ret; int ret;
struct sk_buff *sskb; struct sk_buff *sskb;
struct mac802154_sub_if_data *sdata; struct mac802154_sub_if_data *sdata;
struct ieee802154_hdr hdr;
ret = mac802154_parse_frame_start(skb); ret = mac802154_parse_frame_start(skb, &hdr);
if (ret) { if (ret) {
pr_debug("got invalid frame\n"); pr_debug("got invalid frame\n");
return; return;
...@@ -499,7 +583,7 @@ void mac802154_wpans_rx(struct mac802154_priv *priv, struct sk_buff *skb) ...@@ -499,7 +583,7 @@ void mac802154_wpans_rx(struct mac802154_priv *priv, struct sk_buff *skb)
sskb = skb_clone(skb, GFP_ATOMIC); sskb = skb_clone(skb, GFP_ATOMIC);
if (sskb) if (sskb)
mac802154_subif_frame(sdata, sskb); mac802154_subif_frame(sdata, sskb, &hdr);
} }
rcu_read_unlock(); rcu_read_unlock();
} }
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