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: David S. Miller <davem@davemloft.net>
This commit is contained in:
Коммит
a47e8f5ad8
|
@ -80,6 +80,22 @@ enum {
|
|||
|
||||
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,
|
||||
};
|
||||
|
||||
|
@ -134,6 +150,21 @@ enum {
|
|||
|
||||
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,
|
||||
};
|
||||
|
||||
|
|
|
@ -57,6 +57,14 @@ struct sockaddr_ieee802154 {
|
|||
/* get/setsockopt */
|
||||
#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
|
||||
|
|
|
@ -225,6 +225,9 @@ struct ieee802154_mac_cb {
|
|||
u8 type;
|
||||
bool ackreq;
|
||||
bool secen;
|
||||
bool secen_override;
|
||||
u8 seclevel;
|
||||
bool seclevel_override;
|
||||
struct ieee802154_addr source;
|
||||
struct ieee802154_addr dest;
|
||||
};
|
||||
|
@ -242,6 +245,89 @@ static inline struct ieee802154_mac_cb *mac_cb_init(struct sk_buff *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_ACTIVE 1
|
||||
#define IEEE802154_MAC_SCAN_PASSIVE 2
|
||||
|
@ -260,6 +346,53 @@ struct ieee802154_mac_params {
|
|||
};
|
||||
|
||||
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
|
||||
*
|
||||
|
@ -290,6 +423,8 @@ struct ieee802154_mlme_ops {
|
|||
void (*get_mac_params)(struct net_device *dev,
|
||||
struct ieee802154_mac_params *params);
|
||||
|
||||
struct ieee802154_llsec_ops *llsec;
|
||||
|
||||
/* The fields below are required. */
|
||||
|
||||
struct wpan_phy *(*get_phy)(const struct net_device *dev);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
* Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
|
||||
*/
|
||||
|
||||
#include <linux/capability.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/if_arp.h>
|
||||
|
@ -47,6 +48,10 @@ struct dgram_sock {
|
|||
unsigned int bound:1;
|
||||
unsigned int connected: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)
|
||||
|
@ -264,6 +269,11 @@ static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk,
|
|||
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,
|
||||
ro->bound ? &ro->src_addr : NULL, size);
|
||||
if (err < 0)
|
||||
|
@ -427,6 +437,20 @@ static int dgram_getsockopt(struct sock *sk, int level, int optname,
|
|||
case WPAN_WANTACK:
|
||||
val = ro->want_ack;
|
||||
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:
|
||||
return -ENOPROTOOPT;
|
||||
}
|
||||
|
@ -442,6 +466,7 @@ static int dgram_setsockopt(struct sock *sk, int level, int optname,
|
|||
char __user *optval, unsigned int optlen)
|
||||
{
|
||||
struct dgram_sock *ro = dgram_sk(sk);
|
||||
struct net *net = sock_net(sk);
|
||||
int val;
|
||||
int err = 0;
|
||||
|
||||
|
@ -457,6 +482,47 @@ static int dgram_setsockopt(struct sock *sk, int level, int optname,
|
|||
case WPAN_WANTACK:
|
||||
ro->want_ack = !!val;
|
||||
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:
|
||||
err = -ENOPROTOOPT;
|
||||
break;
|
||||
|
|
|
@ -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_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
|
||||
|
|
|
@ -124,6 +124,26 @@ static const struct genl_ops ieee8021154_ops[] = {
|
|||
IEEE802154_DUMP(IEEE802154_LIST_IFACE, ieee802154_list_iface,
|
||||
ieee802154_dump_iface),
|
||||
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[] = {
|
||||
|
|
|
@ -715,3 +715,810 @@ out:
|
|||
dev_put(dev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
ieee802154_llsec_parse_key_id(struct genl_info *info,
|
||||
struct ieee802154_llsec_key_id *desc)
|
||||
{
|
||||
memset(desc, 0, sizeof(*desc));
|
||||
|
||||
if (!info->attrs[IEEE802154_ATTR_LLSEC_KEY_MODE])
|
||||
return -EINVAL;
|
||||
|
||||
desc->mode = nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_KEY_MODE]);
|
||||
|
||||
if (desc->mode == IEEE802154_SCF_KEY_IMPLICIT) {
|
||||
if (!info->attrs[IEEE802154_ATTR_PAN_ID] &&
|
||||
!(info->attrs[IEEE802154_ATTR_SHORT_ADDR] ||
|
||||
info->attrs[IEEE802154_ATTR_HW_ADDR]))
|
||||
return -EINVAL;
|
||||
|
||||
desc->device_addr.pan_id = nla_get_shortaddr(info->attrs[IEEE802154_ATTR_PAN_ID]);
|
||||
|
||||
if (info->attrs[IEEE802154_ATTR_SHORT_ADDR]) {
|
||||
desc->device_addr.mode = IEEE802154_ADDR_SHORT;
|
||||
desc->device_addr.short_addr = nla_get_shortaddr(info->attrs[IEEE802154_ATTR_SHORT_ADDR]);
|
||||
} else {
|
||||
desc->device_addr.mode = IEEE802154_ADDR_LONG;
|
||||
desc->device_addr.extended_addr = nla_get_hwaddr(info->attrs[IEEE802154_ATTR_HW_ADDR]);
|
||||
}
|
||||
}
|
||||
|
||||
if (desc->mode != IEEE802154_SCF_KEY_IMPLICIT &&
|
||||
!info->attrs[IEEE802154_ATTR_LLSEC_KEY_ID])
|
||||
return -EINVAL;
|
||||
|
||||
if (desc->mode == IEEE802154_SCF_KEY_SHORT_INDEX &&
|
||||
!info->attrs[IEEE802154_ATTR_LLSEC_KEY_SOURCE_SHORT])
|
||||
return -EINVAL;
|
||||
|
||||
if (desc->mode == IEEE802154_SCF_KEY_HW_INDEX &&
|
||||
!info->attrs[IEEE802154_ATTR_LLSEC_KEY_SOURCE_EXTENDED])
|
||||
return -EINVAL;
|
||||
|
||||
if (desc->mode != IEEE802154_SCF_KEY_IMPLICIT)
|
||||
desc->id = nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_KEY_ID]);
|
||||
|
||||
switch (desc->mode) {
|
||||
case IEEE802154_SCF_KEY_SHORT_INDEX:
|
||||
{
|
||||
u32 source = nla_get_u32(info->attrs[IEEE802154_ATTR_LLSEC_KEY_SOURCE_SHORT]);
|
||||
desc->short_source = cpu_to_le32(source);
|
||||
break;
|
||||
}
|
||||
case IEEE802154_SCF_KEY_HW_INDEX:
|
||||
desc->extended_source = nla_get_hwaddr(info->attrs[IEEE802154_ATTR_LLSEC_KEY_SOURCE_EXTENDED]);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ieee802154_llsec_fill_key_id(struct sk_buff *msg,
|
||||
const struct ieee802154_llsec_key_id *desc)
|
||||
{
|
||||
if (nla_put_u8(msg, IEEE802154_ATTR_LLSEC_KEY_MODE, desc->mode))
|
||||
return -EMSGSIZE;
|
||||
|
||||
if (desc->mode == IEEE802154_SCF_KEY_IMPLICIT) {
|
||||
if (nla_put_shortaddr(msg, IEEE802154_ATTR_PAN_ID,
|
||||
desc->device_addr.pan_id))
|
||||
return -EMSGSIZE;
|
||||
|
||||
if (desc->device_addr.mode == IEEE802154_ADDR_SHORT &&
|
||||
nla_put_shortaddr(msg, IEEE802154_ATTR_SHORT_ADDR,
|
||||
desc->device_addr.short_addr))
|
||||
return -EMSGSIZE;
|
||||
|
||||
if (desc->device_addr.mode == IEEE802154_ADDR_LONG &&
|
||||
nla_put_hwaddr(msg, IEEE802154_ATTR_HW_ADDR,
|
||||
desc->device_addr.extended_addr))
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
if (desc->mode != IEEE802154_SCF_KEY_IMPLICIT &&
|
||||
nla_put_u8(msg, IEEE802154_ATTR_LLSEC_KEY_ID, desc->id))
|
||||
return -EMSGSIZE;
|
||||
|
||||
if (desc->mode == IEEE802154_SCF_KEY_SHORT_INDEX &&
|
||||
nla_put_u32(msg, IEEE802154_ATTR_LLSEC_KEY_SOURCE_SHORT,
|
||||
le32_to_cpu(desc->short_source)))
|
||||
return -EMSGSIZE;
|
||||
|
||||
if (desc->mode == IEEE802154_SCF_KEY_HW_INDEX &&
|
||||
nla_put_hwaddr(msg, IEEE802154_ATTR_LLSEC_KEY_SOURCE_EXTENDED,
|
||||
desc->extended_source))
|
||||
return -EMSGSIZE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ieee802154_llsec_getparams(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct sk_buff *msg;
|
||||
struct net_device *dev = NULL;
|
||||
int rc = -ENOBUFS;
|
||||
struct ieee802154_mlme_ops *ops;
|
||||
void *hdr;
|
||||
struct ieee802154_llsec_params params;
|
||||
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
dev = ieee802154_nl_get_dev(info);
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
ops = ieee802154_mlme_ops(dev);
|
||||
if (!ops->llsec)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
if (!msg)
|
||||
goto out_dev;
|
||||
|
||||
hdr = genlmsg_put(msg, 0, info->snd_seq, &nl802154_family, 0,
|
||||
IEEE802154_LLSEC_GETPARAMS);
|
||||
if (!hdr)
|
||||
goto out_free;
|
||||
|
||||
rc = ops->llsec->get_params(dev, ¶ms);
|
||||
if (rc < 0)
|
||||
goto out_free;
|
||||
|
||||
if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
|
||||
nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
|
||||
nla_put_u8(msg, IEEE802154_ATTR_LLSEC_ENABLED, params.enabled) ||
|
||||
nla_put_u8(msg, IEEE802154_ATTR_LLSEC_SECLEVEL, params.out_level) ||
|
||||
nla_put_u32(msg, IEEE802154_ATTR_LLSEC_FRAME_COUNTER,
|
||||
be32_to_cpu(params.frame_counter)) ||
|
||||
ieee802154_llsec_fill_key_id(msg, ¶ms.out_key))
|
||||
goto out_free;
|
||||
|
||||
dev_put(dev);
|
||||
|
||||
return ieee802154_nl_reply(msg, info);
|
||||
out_free:
|
||||
nlmsg_free(msg);
|
||||
out_dev:
|
||||
dev_put(dev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int ieee802154_llsec_setparams(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct net_device *dev = NULL;
|
||||
int rc = -EINVAL;
|
||||
struct ieee802154_mlme_ops *ops;
|
||||
struct ieee802154_llsec_params params;
|
||||
int changed = 0;
|
||||
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
dev = ieee802154_nl_get_dev(info);
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
if (!info->attrs[IEEE802154_ATTR_LLSEC_ENABLED] &&
|
||||
!info->attrs[IEEE802154_ATTR_LLSEC_KEY_MODE] &&
|
||||
!info->attrs[IEEE802154_ATTR_LLSEC_SECLEVEL])
|
||||
goto out;
|
||||
|
||||
ops = ieee802154_mlme_ops(dev);
|
||||
if (!ops->llsec) {
|
||||
rc = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (info->attrs[IEEE802154_ATTR_LLSEC_SECLEVEL] &&
|
||||
nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_SECLEVEL]) > 7)
|
||||
goto out;
|
||||
|
||||
if (info->attrs[IEEE802154_ATTR_LLSEC_ENABLED]) {
|
||||
params.enabled = nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_ENABLED]);
|
||||
changed |= IEEE802154_LLSEC_PARAM_ENABLED;
|
||||
}
|
||||
|
||||
if (info->attrs[IEEE802154_ATTR_LLSEC_KEY_MODE]) {
|
||||
if (ieee802154_llsec_parse_key_id(info, ¶ms.out_key))
|
||||
goto out;
|
||||
|
||||
changed |= IEEE802154_LLSEC_PARAM_OUT_KEY;
|
||||
}
|
||||
|
||||
if (info->attrs[IEEE802154_ATTR_LLSEC_SECLEVEL]) {
|
||||
params.out_level = nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_SECLEVEL]);
|
||||
changed |= IEEE802154_LLSEC_PARAM_OUT_LEVEL;
|
||||
}
|
||||
|
||||
if (info->attrs[IEEE802154_ATTR_LLSEC_FRAME_COUNTER]) {
|
||||
u32 fc = nla_get_u32(info->attrs[IEEE802154_ATTR_LLSEC_FRAME_COUNTER]);
|
||||
|
||||
params.frame_counter = cpu_to_be32(fc);
|
||||
changed |= IEEE802154_LLSEC_PARAM_FRAME_COUNTER;
|
||||
}
|
||||
|
||||
rc = ops->llsec->set_params(dev, ¶ms, changed);
|
||||
|
||||
dev_put(dev);
|
||||
|
||||
return rc;
|
||||
out:
|
||||
dev_put(dev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct llsec_dump_data {
|
||||
struct sk_buff *skb;
|
||||
int s_idx, s_idx2;
|
||||
int portid;
|
||||
int nlmsg_seq;
|
||||
struct net_device *dev;
|
||||
struct ieee802154_mlme_ops *ops;
|
||||
struct ieee802154_llsec_table *table;
|
||||
};
|
||||
|
||||
static int
|
||||
ieee802154_llsec_dump_table(struct sk_buff *skb, struct netlink_callback *cb,
|
||||
int (*step)(struct llsec_dump_data*))
|
||||
{
|
||||
struct net *net = sock_net(skb->sk);
|
||||
struct net_device *dev;
|
||||
struct llsec_dump_data data;
|
||||
int idx = 0;
|
||||
int first_dev = cb->args[0];
|
||||
int rc;
|
||||
|
||||
for_each_netdev(net, dev) {
|
||||
if (idx < first_dev || dev->type != ARPHRD_IEEE802154)
|
||||
goto skip;
|
||||
|
||||
data.ops = ieee802154_mlme_ops(dev);
|
||||
if (!data.ops->llsec)
|
||||
goto skip;
|
||||
|
||||
data.skb = skb;
|
||||
data.s_idx = cb->args[1];
|
||||
data.s_idx2 = cb->args[2];
|
||||
data.dev = dev;
|
||||
data.portid = NETLINK_CB(cb->skb).portid;
|
||||
data.nlmsg_seq = cb->nlh->nlmsg_seq;
|
||||
|
||||
data.ops->llsec->lock_table(dev);
|
||||
data.ops->llsec->get_table(data.dev, &data.table);
|
||||
rc = step(&data);
|
||||
data.ops->llsec->unlock_table(dev);
|
||||
|
||||
if (rc < 0)
|
||||
break;
|
||||
|
||||
skip:
|
||||
idx++;
|
||||
}
|
||||
cb->args[0] = idx;
|
||||
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
static int
|
||||
ieee802154_nl_llsec_change(struct sk_buff *skb, struct genl_info *info,
|
||||
int (*fn)(struct net_device*, struct genl_info*))
|
||||
{
|
||||
struct net_device *dev = NULL;
|
||||
int rc = -EINVAL;
|
||||
|
||||
dev = ieee802154_nl_get_dev(info);
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
if (!ieee802154_mlme_ops(dev)->llsec)
|
||||
rc = -EOPNOTSUPP;
|
||||
else
|
||||
rc = fn(dev, info);
|
||||
|
||||
dev_put(dev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
ieee802154_llsec_parse_key(struct genl_info *info,
|
||||
struct ieee802154_llsec_key *key)
|
||||
{
|
||||
u8 frames;
|
||||
u32 commands[256 / 32];
|
||||
|
||||
memset(key, 0, sizeof(*key));
|
||||
|
||||
if (!info->attrs[IEEE802154_ATTR_LLSEC_KEY_USAGE_FRAME_TYPES] ||
|
||||
!info->attrs[IEEE802154_ATTR_LLSEC_KEY_BYTES])
|
||||
return -EINVAL;
|
||||
|
||||
frames = nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_KEY_USAGE_FRAME_TYPES]);
|
||||
if ((frames & BIT(IEEE802154_FC_TYPE_MAC_CMD)) &&
|
||||
!info->attrs[IEEE802154_ATTR_LLSEC_KEY_USAGE_COMMANDS])
|
||||
return -EINVAL;
|
||||
|
||||
if (info->attrs[IEEE802154_ATTR_LLSEC_KEY_USAGE_COMMANDS]) {
|
||||
nla_memcpy(commands,
|
||||
info->attrs[IEEE802154_ATTR_LLSEC_KEY_USAGE_COMMANDS],
|
||||
256 / 8);
|
||||
|
||||
if (commands[0] || commands[1] || commands[2] || commands[3] ||
|
||||
commands[4] || commands[5] || commands[6] ||
|
||||
commands[7] >= BIT(IEEE802154_CMD_GTS_REQ + 1))
|
||||
return -EINVAL;
|
||||
|
||||
key->cmd_frame_ids = commands[7];
|
||||
}
|
||||
|
||||
key->frame_types = frames;
|
||||
|
||||
nla_memcpy(key->key, info->attrs[IEEE802154_ATTR_LLSEC_KEY_BYTES],
|
||||
IEEE802154_LLSEC_KEY_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int llsec_add_key(struct net_device *dev, struct genl_info *info)
|
||||
{
|
||||
struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
|
||||
struct ieee802154_llsec_key key;
|
||||
struct ieee802154_llsec_key_id id;
|
||||
|
||||
if (ieee802154_llsec_parse_key(info, &key) ||
|
||||
ieee802154_llsec_parse_key_id(info, &id))
|
||||
return -EINVAL;
|
||||
|
||||
return ops->llsec->add_key(dev, &id, &key);
|
||||
}
|
||||
|
||||
int ieee802154_llsec_add_key(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
if ((info->nlhdr->nlmsg_flags & (NLM_F_CREATE | NLM_F_EXCL)) !=
|
||||
(NLM_F_CREATE | NLM_F_EXCL))
|
||||
return -EINVAL;
|
||||
|
||||
return ieee802154_nl_llsec_change(skb, info, llsec_add_key);
|
||||
}
|
||||
|
||||
static int llsec_remove_key(struct net_device *dev, struct genl_info *info)
|
||||
{
|
||||
struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
|
||||
struct ieee802154_llsec_key_id id;
|
||||
|
||||
if (ieee802154_llsec_parse_key_id(info, &id))
|
||||
return -EINVAL;
|
||||
|
||||
return ops->llsec->del_key(dev, &id);
|
||||
}
|
||||
|
||||
int ieee802154_llsec_del_key(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
return ieee802154_nl_llsec_change(skb, info, llsec_remove_key);
|
||||
}
|
||||
|
||||
static int
|
||||
ieee802154_nl_fill_key(struct sk_buff *msg, u32 portid, u32 seq,
|
||||
const struct ieee802154_llsec_key_entry *key,
|
||||
const struct net_device *dev)
|
||||
{
|
||||
void *hdr;
|
||||
u32 commands[256 / 32];
|
||||
|
||||
hdr = genlmsg_put(msg, 0, seq, &nl802154_family, NLM_F_MULTI,
|
||||
IEEE802154_LLSEC_LIST_KEY);
|
||||
if (!hdr)
|
||||
goto out;
|
||||
|
||||
if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
|
||||
nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
|
||||
ieee802154_llsec_fill_key_id(msg, &key->id) ||
|
||||
nla_put_u8(msg, IEEE802154_ATTR_LLSEC_KEY_USAGE_FRAME_TYPES,
|
||||
key->key->frame_types))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (key->key->frame_types & BIT(IEEE802154_FC_TYPE_MAC_CMD)) {
|
||||
memset(commands, 0, sizeof(commands));
|
||||
commands[7] = key->key->cmd_frame_ids;
|
||||
if (nla_put(msg, IEEE802154_ATTR_LLSEC_KEY_USAGE_COMMANDS,
|
||||
sizeof(commands), commands))
|
||||
goto nla_put_failure;
|
||||
}
|
||||
|
||||
if (nla_put(msg, IEEE802154_ATTR_LLSEC_KEY_BYTES,
|
||||
IEEE802154_LLSEC_KEY_SIZE, key->key->key))
|
||||
goto nla_put_failure;
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
genlmsg_cancel(msg, hdr);
|
||||
out:
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
static int llsec_iter_keys(struct llsec_dump_data *data)
|
||||
{
|
||||
struct ieee802154_llsec_key_entry *pos;
|
||||
int rc = 0, idx = 0;
|
||||
|
||||
list_for_each_entry(pos, &data->table->keys, list) {
|
||||
if (idx++ < data->s_idx)
|
||||
continue;
|
||||
|
||||
if (ieee802154_nl_fill_key(data->skb, data->portid,
|
||||
data->nlmsg_seq, pos, data->dev)) {
|
||||
rc = -EMSGSIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
data->s_idx++;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int ieee802154_llsec_dump_keys(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
return ieee802154_llsec_dump_table(skb, cb, llsec_iter_keys);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
llsec_parse_dev(struct genl_info *info,
|
||||
struct ieee802154_llsec_device *dev)
|
||||
{
|
||||
memset(dev, 0, sizeof(*dev));
|
||||
|
||||
if (!info->attrs[IEEE802154_ATTR_LLSEC_FRAME_COUNTER] ||
|
||||
!info->attrs[IEEE802154_ATTR_HW_ADDR] ||
|
||||
!info->attrs[IEEE802154_ATTR_LLSEC_DEV_OVERRIDE] ||
|
||||
!info->attrs[IEEE802154_ATTR_LLSEC_DEV_KEY_MODE] ||
|
||||
(!!info->attrs[IEEE802154_ATTR_PAN_ID] !=
|
||||
!!info->attrs[IEEE802154_ATTR_SHORT_ADDR]))
|
||||
return -EINVAL;
|
||||
|
||||
if (info->attrs[IEEE802154_ATTR_PAN_ID]) {
|
||||
dev->pan_id = nla_get_shortaddr(info->attrs[IEEE802154_ATTR_PAN_ID]);
|
||||
dev->short_addr = nla_get_shortaddr(info->attrs[IEEE802154_ATTR_SHORT_ADDR]);
|
||||
} else {
|
||||
dev->short_addr = cpu_to_le16(IEEE802154_ADDR_UNDEF);
|
||||
}
|
||||
|
||||
dev->hwaddr = nla_get_hwaddr(info->attrs[IEEE802154_ATTR_HW_ADDR]);
|
||||
dev->frame_counter = nla_get_u32(info->attrs[IEEE802154_ATTR_LLSEC_FRAME_COUNTER]);
|
||||
dev->seclevel_exempt = !!nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_DEV_OVERRIDE]);
|
||||
dev->key_mode = nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_DEV_KEY_MODE]);
|
||||
|
||||
if (dev->key_mode >= __IEEE802154_LLSEC_DEVKEY_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int llsec_add_dev(struct net_device *dev, struct genl_info *info)
|
||||
{
|
||||
struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
|
||||
struct ieee802154_llsec_device desc;
|
||||
|
||||
if (llsec_parse_dev(info, &desc))
|
||||
return -EINVAL;
|
||||
|
||||
return ops->llsec->add_dev(dev, &desc);
|
||||
}
|
||||
|
||||
int ieee802154_llsec_add_dev(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
if ((info->nlhdr->nlmsg_flags & (NLM_F_CREATE | NLM_F_EXCL)) !=
|
||||
(NLM_F_CREATE | NLM_F_EXCL))
|
||||
return -EINVAL;
|
||||
|
||||
return ieee802154_nl_llsec_change(skb, info, llsec_add_dev);
|
||||
}
|
||||
|
||||
static int llsec_del_dev(struct net_device *dev, struct genl_info *info)
|
||||
{
|
||||
struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
|
||||
__le64 devaddr;
|
||||
|
||||
if (!info->attrs[IEEE802154_ATTR_HW_ADDR])
|
||||
return -EINVAL;
|
||||
|
||||
devaddr = nla_get_hwaddr(info->attrs[IEEE802154_ATTR_HW_ADDR]);
|
||||
|
||||
return ops->llsec->del_dev(dev, devaddr);
|
||||
}
|
||||
|
||||
int ieee802154_llsec_del_dev(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
return ieee802154_nl_llsec_change(skb, info, llsec_del_dev);
|
||||
}
|
||||
|
||||
static int
|
||||
ieee802154_nl_fill_dev(struct sk_buff *msg, u32 portid, u32 seq,
|
||||
const struct ieee802154_llsec_device *desc,
|
||||
const struct net_device *dev)
|
||||
{
|
||||
void *hdr;
|
||||
|
||||
hdr = genlmsg_put(msg, 0, seq, &nl802154_family, NLM_F_MULTI,
|
||||
IEEE802154_LLSEC_LIST_DEV);
|
||||
if (!hdr)
|
||||
goto out;
|
||||
|
||||
if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
|
||||
nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
|
||||
nla_put_shortaddr(msg, IEEE802154_ATTR_PAN_ID, desc->pan_id) ||
|
||||
nla_put_shortaddr(msg, IEEE802154_ATTR_SHORT_ADDR,
|
||||
desc->short_addr) ||
|
||||
nla_put_hwaddr(msg, IEEE802154_ATTR_HW_ADDR, desc->hwaddr) ||
|
||||
nla_put_u32(msg, IEEE802154_ATTR_LLSEC_FRAME_COUNTER,
|
||||
desc->frame_counter) ||
|
||||
nla_put_u8(msg, IEEE802154_ATTR_LLSEC_DEV_OVERRIDE,
|
||||
desc->seclevel_exempt) ||
|
||||
nla_put_u8(msg, IEEE802154_ATTR_LLSEC_DEV_KEY_MODE, desc->key_mode))
|
||||
goto nla_put_failure;
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
genlmsg_cancel(msg, hdr);
|
||||
out:
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
static int llsec_iter_devs(struct llsec_dump_data *data)
|
||||
{
|
||||
struct ieee802154_llsec_device *pos;
|
||||
int rc = 0, idx = 0;
|
||||
|
||||
list_for_each_entry(pos, &data->table->devices, list) {
|
||||
if (idx++ < data->s_idx)
|
||||
continue;
|
||||
|
||||
if (ieee802154_nl_fill_dev(data->skb, data->portid,
|
||||
data->nlmsg_seq, pos, data->dev)) {
|
||||
rc = -EMSGSIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
data->s_idx++;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int ieee802154_llsec_dump_devs(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
return ieee802154_llsec_dump_table(skb, cb, llsec_iter_devs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int llsec_add_devkey(struct net_device *dev, struct genl_info *info)
|
||||
{
|
||||
struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
|
||||
struct ieee802154_llsec_device_key key;
|
||||
__le64 devaddr;
|
||||
|
||||
if (!info->attrs[IEEE802154_ATTR_LLSEC_FRAME_COUNTER] ||
|
||||
!info->attrs[IEEE802154_ATTR_HW_ADDR] ||
|
||||
ieee802154_llsec_parse_key_id(info, &key.key_id))
|
||||
return -EINVAL;
|
||||
|
||||
devaddr = nla_get_hwaddr(info->attrs[IEEE802154_ATTR_HW_ADDR]);
|
||||
key.frame_counter = nla_get_u32(info->attrs[IEEE802154_ATTR_LLSEC_FRAME_COUNTER]);
|
||||
|
||||
return ops->llsec->add_devkey(dev, devaddr, &key);
|
||||
}
|
||||
|
||||
int ieee802154_llsec_add_devkey(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
if ((info->nlhdr->nlmsg_flags & (NLM_F_CREATE | NLM_F_EXCL)) !=
|
||||
(NLM_F_CREATE | NLM_F_EXCL))
|
||||
return -EINVAL;
|
||||
|
||||
return ieee802154_nl_llsec_change(skb, info, llsec_add_devkey);
|
||||
}
|
||||
|
||||
static int llsec_del_devkey(struct net_device *dev, struct genl_info *info)
|
||||
{
|
||||
struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
|
||||
struct ieee802154_llsec_device_key key;
|
||||
__le64 devaddr;
|
||||
|
||||
if (!info->attrs[IEEE802154_ATTR_HW_ADDR] ||
|
||||
ieee802154_llsec_parse_key_id(info, &key.key_id))
|
||||
return -EINVAL;
|
||||
|
||||
devaddr = nla_get_hwaddr(info->attrs[IEEE802154_ATTR_HW_ADDR]);
|
||||
|
||||
return ops->llsec->del_devkey(dev, devaddr, &key);
|
||||
}
|
||||
|
||||
int ieee802154_llsec_del_devkey(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
return ieee802154_nl_llsec_change(skb, info, llsec_del_devkey);
|
||||
}
|
||||
|
||||
static int
|
||||
ieee802154_nl_fill_devkey(struct sk_buff *msg, u32 portid, u32 seq,
|
||||
__le64 devaddr,
|
||||
const struct ieee802154_llsec_device_key *devkey,
|
||||
const struct net_device *dev)
|
||||
{
|
||||
void *hdr;
|
||||
|
||||
hdr = genlmsg_put(msg, 0, seq, &nl802154_family, NLM_F_MULTI,
|
||||
IEEE802154_LLSEC_LIST_DEVKEY);
|
||||
if (!hdr)
|
||||
goto out;
|
||||
|
||||
if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
|
||||
nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
|
||||
nla_put_hwaddr(msg, IEEE802154_ATTR_HW_ADDR, devaddr) ||
|
||||
nla_put_u32(msg, IEEE802154_ATTR_LLSEC_FRAME_COUNTER,
|
||||
devkey->frame_counter) ||
|
||||
ieee802154_llsec_fill_key_id(msg, &devkey->key_id))
|
||||
goto nla_put_failure;
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
genlmsg_cancel(msg, hdr);
|
||||
out:
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
static int llsec_iter_devkeys(struct llsec_dump_data *data)
|
||||
{
|
||||
struct ieee802154_llsec_device *dpos;
|
||||
struct ieee802154_llsec_device_key *kpos;
|
||||
int rc = 0, idx = 0, idx2;
|
||||
|
||||
list_for_each_entry(dpos, &data->table->devices, list) {
|
||||
if (idx++ < data->s_idx)
|
||||
continue;
|
||||
|
||||
idx2 = 0;
|
||||
|
||||
list_for_each_entry(kpos, &dpos->keys, list) {
|
||||
if (idx2++ < data->s_idx2)
|
||||
continue;
|
||||
|
||||
if (ieee802154_nl_fill_devkey(data->skb, data->portid,
|
||||
data->nlmsg_seq,
|
||||
dpos->hwaddr, kpos,
|
||||
data->dev)) {
|
||||
return rc = -EMSGSIZE;
|
||||
}
|
||||
|
||||
data->s_idx2++;
|
||||
}
|
||||
|
||||
data->s_idx++;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int ieee802154_llsec_dump_devkeys(struct sk_buff *skb,
|
||||
struct netlink_callback *cb)
|
||||
{
|
||||
return ieee802154_llsec_dump_table(skb, cb, llsec_iter_devkeys);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
llsec_parse_seclevel(struct genl_info *info,
|
||||
struct ieee802154_llsec_seclevel *sl)
|
||||
{
|
||||
memset(sl, 0, sizeof(*sl));
|
||||
|
||||
if (!info->attrs[IEEE802154_ATTR_LLSEC_FRAME_TYPE] ||
|
||||
!info->attrs[IEEE802154_ATTR_LLSEC_SECLEVELS] ||
|
||||
!info->attrs[IEEE802154_ATTR_LLSEC_DEV_OVERRIDE])
|
||||
return -EINVAL;
|
||||
|
||||
sl->frame_type = nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_FRAME_TYPE]);
|
||||
if (sl->frame_type == IEEE802154_FC_TYPE_MAC_CMD) {
|
||||
if (!info->attrs[IEEE802154_ATTR_LLSEC_CMD_FRAME_ID])
|
||||
return -EINVAL;
|
||||
|
||||
sl->cmd_frame_id = nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_CMD_FRAME_ID]);
|
||||
}
|
||||
|
||||
sl->sec_levels = nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_SECLEVELS]);
|
||||
sl->device_override = nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_DEV_OVERRIDE]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int llsec_add_seclevel(struct net_device *dev, struct genl_info *info)
|
||||
{
|
||||
struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
|
||||
struct ieee802154_llsec_seclevel sl;
|
||||
|
||||
if (llsec_parse_seclevel(info, &sl))
|
||||
return -EINVAL;
|
||||
|
||||
return ops->llsec->add_seclevel(dev, &sl);
|
||||
}
|
||||
|
||||
int ieee802154_llsec_add_seclevel(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
if ((info->nlhdr->nlmsg_flags & (NLM_F_CREATE | NLM_F_EXCL)) !=
|
||||
(NLM_F_CREATE | NLM_F_EXCL))
|
||||
return -EINVAL;
|
||||
|
||||
return ieee802154_nl_llsec_change(skb, info, llsec_add_seclevel);
|
||||
}
|
||||
|
||||
static int llsec_del_seclevel(struct net_device *dev, struct genl_info *info)
|
||||
{
|
||||
struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
|
||||
struct ieee802154_llsec_seclevel sl;
|
||||
|
||||
if (llsec_parse_seclevel(info, &sl))
|
||||
return -EINVAL;
|
||||
|
||||
return ops->llsec->del_seclevel(dev, &sl);
|
||||
}
|
||||
|
||||
int ieee802154_llsec_del_seclevel(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
return ieee802154_nl_llsec_change(skb, info, llsec_del_seclevel);
|
||||
}
|
||||
|
||||
static int
|
||||
ieee802154_nl_fill_seclevel(struct sk_buff *msg, u32 portid, u32 seq,
|
||||
const struct ieee802154_llsec_seclevel *sl,
|
||||
const struct net_device *dev)
|
||||
{
|
||||
void *hdr;
|
||||
|
||||
hdr = genlmsg_put(msg, 0, seq, &nl802154_family, NLM_F_MULTI,
|
||||
IEEE802154_LLSEC_LIST_SECLEVEL);
|
||||
if (!hdr)
|
||||
goto out;
|
||||
|
||||
if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
|
||||
nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
|
||||
nla_put_u8(msg, IEEE802154_ATTR_LLSEC_FRAME_TYPE, sl->frame_type) ||
|
||||
nla_put_u8(msg, IEEE802154_ATTR_LLSEC_SECLEVELS, sl->sec_levels) ||
|
||||
nla_put_u8(msg, IEEE802154_ATTR_LLSEC_DEV_OVERRIDE,
|
||||
sl->device_override))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (sl->frame_type == IEEE802154_FC_TYPE_MAC_CMD &&
|
||||
nla_put_u8(msg, IEEE802154_ATTR_LLSEC_CMD_FRAME_ID,
|
||||
sl->cmd_frame_id))
|
||||
goto nla_put_failure;
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
genlmsg_cancel(msg, hdr);
|
||||
out:
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
static int llsec_iter_seclevels(struct llsec_dump_data *data)
|
||||
{
|
||||
struct ieee802154_llsec_seclevel *pos;
|
||||
int rc = 0, idx = 0;
|
||||
|
||||
list_for_each_entry(pos, &data->table->security_levels, list) {
|
||||
if (idx++ < data->s_idx)
|
||||
continue;
|
||||
|
||||
if (ieee802154_nl_fill_seclevel(data->skb, data->portid,
|
||||
data->nlmsg_seq, pos,
|
||||
data->dev)) {
|
||||
rc = -EMSGSIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
data->s_idx++;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int ieee802154_llsec_dump_seclevels(struct sk_buff *skb,
|
||||
struct netlink_callback *cb)
|
||||
{
|
||||
return ieee802154_llsec_dump_table(skb, cb, llsec_iter_seclevels);
|
||||
}
|
||||
|
|
|
@ -62,5 +62,21 @@ const struct nla_policy ieee802154_policy[IEEE802154_ATTR_MAX + 1] = {
|
|||
[IEEE802154_ATTR_CSMA_MAX_BE] = { .type = NLA_U8, },
|
||||
|
||||
[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
|
|||
tristate "Generic IEEE 802.15.4 Soft Networking Stack (mac802154)"
|
||||
depends on IEEE802154
|
||||
select CRC_CCITT
|
||||
select CRYPTO_AUTHENC
|
||||
select CRYPTO_CCM
|
||||
select CRYPTO_CTR
|
||||
select CRYPTO_AES
|
||||
---help---
|
||||
This option enables the hardware independent IEEE 802.15.4
|
||||
networking stack for SoftMAC devices (the ones implementing
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
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__
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* 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 @@
|
|||
#ifndef MAC802154_H
|
||||
#define MAC802154_H
|
||||
|
||||
#include <linux/mutex.h>
|
||||
#include <net/mac802154.h>
|
||||
#include <net/ieee802154_netdev.h>
|
||||
|
||||
#include "llsec.h"
|
||||
|
||||
/* mac802154 device private data */
|
||||
struct mac802154_priv {
|
||||
struct ieee802154_dev hw;
|
||||
|
@ -90,6 +94,13 @@ struct mac802154_sub_if_data {
|
|||
u8 bsn;
|
||||
/* MAC DSN field */
|
||||
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)
|
||||
|
@ -125,4 +136,37 @@ int mac802154_set_mac_params(struct net_device *dev,
|
|||
void mac802154_get_mac_params(struct net_device *dev,
|
||||
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 */
|
||||
|
|
|
@ -40,6 +40,9 @@ static int mac802154_mlme_start_req(struct net_device *dev,
|
|||
u8 pan_coord, u8 blx,
|
||||
u8 coord_realign)
|
||||
{
|
||||
struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
|
||||
int rc = 0;
|
||||
|
||||
BUG_ON(addr->mode != IEEE802154_ADDR_SHORT);
|
||||
|
||||
mac802154_dev_set_pan_id(dev, addr->pan_id);
|
||||
|
@ -47,12 +50,31 @@ static int mac802154_mlme_start_req(struct net_device *dev,
|
|||
mac802154_dev_set_ieee_addr(dev);
|
||||
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, ¶ms, changed);
|
||||
}
|
||||
|
||||
/* FIXME: add validation for unused parameters to be sane
|
||||
* for SoftMAC
|
||||
*/
|
||||
ieee802154_nl_start_confirm(dev, IEEE802154_SUCCESS);
|
||||
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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 = {
|
||||
.get_phy = mac802154_get_phy,
|
||||
};
|
||||
|
@ -75,6 +113,8 @@ struct ieee802154_mlme_ops mac802154_mlme_wpan = {
|
|||
.get_short_addr = mac802154_dev_get_short_addr,
|
||||
.get_dsn = mac802154_dev_get_dsn,
|
||||
|
||||
.llsec = &mac802154_llsec_ops,
|
||||
|
||||
.set_mac_params = mac802154_set_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)
|
|||
} else
|
||||
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 @@
|
|||
|
||||
#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, ¶ms, changed);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
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->short_addr = cpu_to_le16(sa->addr.short_addr);
|
||||
|
||||
err = 0;
|
||||
err = mac802154_wpan_update_llsec(dev);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -99,7 +121,7 @@ static int mac802154_wpan_mac_addr(struct net_device *dev, void *p)
|
|||
/* FIXME: validate addr */
|
||||
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
|
||||
mac802154_dev_set_ieee_addr(dev);
|
||||
return 0;
|
||||
return mac802154_wpan_update_llsec(dev);
|
||||
}
|
||||
|
||||
int mac802154_set_mac_params(struct net_device *dev,
|
||||
|
@ -183,6 +205,38 @@ out:
|
|||
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, ¶ms);
|
||||
|
||||
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,
|
||||
struct net_device *dev,
|
||||
unsigned short type,
|
||||
|
@ -204,6 +258,9 @@ static int mac802154_header_create(struct sk_buff *skb,
|
|||
hdr.fc.ack_request = cb->ackreq;
|
||||
hdr.seq = ieee802154_mlme_ops(dev)->get_dsn(dev);
|
||||
|
||||
if (mac802154_set_header_security(priv, &hdr, cb) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (!saddr) {
|
||||
spin_lock_bh(&priv->mib_lock);
|
||||
|
||||
|
@ -259,6 +316,7 @@ mac802154_wpan_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
{
|
||||
struct mac802154_sub_if_data *priv;
|
||||
u8 chan, page;
|
||||
int rc;
|
||||
|
||||
priv = netdev_priv(dev);
|
||||
|
||||
|
@ -274,6 +332,13 @@ mac802154_wpan_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
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;
|
||||
dev->stats.tx_packets++;
|
||||
dev->stats.tx_bytes += skb->len;
|
||||
|
@ -294,6 +359,15 @@ static const struct net_device_ops mac802154_wpan_ops = {
|
|||
.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)
|
||||
{
|
||||
struct mac802154_sub_if_data *priv;
|
||||
|
@ -303,14 +377,14 @@ void mac802154_wpan_setup(struct net_device *dev)
|
|||
|
||||
dev->hard_header_len = MAC802154_FRAME_HARD_HEADER_LEN;
|
||||
dev->header_ops = &mac802154_header_ops;
|
||||
dev->needed_tailroom = 2; /* FCS */
|
||||
dev->needed_tailroom = 2 + 16; /* FCS + MIC */
|
||||
dev->mtu = IEEE802154_MTU;
|
||||
dev->tx_queue_len = 300;
|
||||
dev->type = ARPHRD_IEEE802154;
|
||||
dev->flags = IFF_NOARP | IFF_BROADCAST;
|
||||
dev->watchdog_timeo = 0;
|
||||
|
||||
dev->destructor = free_netdev;
|
||||
dev->destructor = mac802154_wpan_free;
|
||||
dev->netdev_ops = &mac802154_wpan_ops;
|
||||
dev->ml_priv = &mac802154_mlme_wpan;
|
||||
|
||||
|
@ -321,6 +395,7 @@ void mac802154_wpan_setup(struct net_device *dev)
|
|||
priv->page = 0;
|
||||
|
||||
spin_lock_init(&priv->mib_lock);
|
||||
mutex_init(&priv->sec_mtx);
|
||||
|
||||
get_random_bytes(&priv->bsn, 1);
|
||||
get_random_bytes(&priv->dsn, 1);
|
||||
|
@ -333,6 +408,8 @@ void mac802154_wpan_setup(struct net_device *dev)
|
|||
|
||||
priv->pan_id = cpu_to_le16(IEEE802154_PANID_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)
|
||||
|
@ -341,9 +418,11 @@ static int mac802154_process_data(struct net_device *dev, struct sk_buff *skb)
|
|||
}
|
||||
|
||||
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;
|
||||
int rc;
|
||||
|
||||
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)
|
|||
|
||||
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_bytes += skb->len;
|
||||
|
||||
|
@ -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;
|
||||
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)
|
||||
return -EINVAL;
|
||||
|
||||
skb->mac_len = hlen;
|
||||
|
||||
pr_debug("fc: %04x dsn: %02x\n", le16_to_cpup((__le16 *)&hdr.fc),
|
||||
hdr.seq);
|
||||
pr_debug("fc: %04x dsn: %02x\n", le16_to_cpup((__le16 *)&hdr->fc),
|
||||
hdr->seq);
|
||||
|
||||
cb->type = hdr.fc.type;
|
||||
cb->ackreq = hdr.fc.ack_request;
|
||||
cb->secen = hdr.fc.security_enabled;
|
||||
cb->type = hdr->fc.type;
|
||||
cb->ackreq = hdr->fc.ack_request;
|
||||
cb->secen = hdr->fc.security_enabled;
|
||||
|
||||
mac802154_print_addr("destination", &hdr.dest);
|
||||
mac802154_print_addr("source", &hdr.source);
|
||||
mac802154_print_addr("destination", &hdr->dest);
|
||||
mac802154_print_addr("source", &hdr->source);
|
||||
|
||||
cb->source = hdr.source;
|
||||
cb->dest = hdr.dest;
|
||||
cb->source = hdr->source;
|
||||
cb->dest = hdr->dest;
|
||||
|
||||
if (hdr.fc.security_enabled) {
|
||||
if (hdr->fc.security_enabled) {
|
||||
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:
|
||||
pr_debug("implicit key\n");
|
||||
break;
|
||||
|
||||
case IEEE802154_SCF_KEY_INDEX:
|
||||
pr_debug("key %02x\n", hdr.sec.key_id);
|
||||
pr_debug("key %02x\n", hdr->sec.key_id);
|
||||
break;
|
||||
|
||||
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);
|
||||
le32_to_cpu(hdr->sec.short_src) >> 16,
|
||||
le32_to_cpu(hdr->sec.short_src) & 0xffff,
|
||||
hdr->sec.key_id);
|
||||
break;
|
||||
|
||||
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,
|
||||
hdr.sec.key_id);
|
||||
hdr->sec.key_id);
|
||||
break;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -485,8 +568,9 @@ void mac802154_wpans_rx(struct mac802154_priv *priv, struct sk_buff *skb)
|
|||
int ret;
|
||||
struct sk_buff *sskb;
|
||||
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) {
|
||||
pr_debug("got invalid frame\n");
|
||||
return;
|
||||
|
@ -499,7 +583,7 @@ void mac802154_wpans_rx(struct mac802154_priv *priv, struct sk_buff *skb)
|
|||
|
||||
sskb = skb_clone(skb, GFP_ATOMIC);
|
||||
if (sskb)
|
||||
mac802154_subif_frame(sdata, sskb);
|
||||
mac802154_subif_frame(sdata, sskb, &hdr);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче