ieee802154: introduce wpan_dev_header_ops
The current header_ops callback structure of net device are used mostly from 802.15.4 upper-layers. Because this callback structure is a very generic one, which is also used by e.g. DGRAM AF_PACKET sockets, we can't make this callback structure 802.15.4 specific which is currently is. I saw the smallest "constraint" for calling this callback with dev_hard_header/dev_parse_header by AF_PACKET which assign a 8 byte array for address void pointers. Currently 802.15.4 specific protocols like af802154 and 6LoWPAN will assign the "struct ieee802154_addr" as these parameters which is greater than 8 bytes. The current callback implementation for header_ops.create assumes always a complete "struct ieee802154_addr" which AF_PACKET can't never handled and is greater than 8 bytes. For that reason we introduce now a "generic" create/parse header_ops callback which allows handling with intra-pan extended addresses only. This allows a small use-case with AF_PACKET to send "somehow" a valid dataframe over DGRAM. To keeping the current dev_hard_header behaviour we introduce a similar callback structure "wpan_dev_header_ops" which contains 802.15.4 specific upper-layer header creation functionality, which can be called by wpan_dev_hard_header. Signed-off-by: Alexander Aring <alex.aring@gmail.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
parent
a1da67b811
commit
838b83d63d
5 changed files with 118 additions and 27 deletions
|
@ -167,6 +167,26 @@ struct wpan_phy {
|
|||
char priv[0] __aligned(NETDEV_ALIGN);
|
||||
};
|
||||
|
||||
struct ieee802154_addr {
|
||||
u8 mode;
|
||||
__le16 pan_id;
|
||||
union {
|
||||
__le16 short_addr;
|
||||
__le64 extended_addr;
|
||||
};
|
||||
};
|
||||
|
||||
struct wpan_dev_header_ops {
|
||||
/* TODO create callback currently assumes ieee802154_mac_cb inside
|
||||
* skb->cb. This should be changed to give these information as
|
||||
* parameter.
|
||||
*/
|
||||
int (*create)(struct sk_buff *skb, struct net_device *dev,
|
||||
const struct ieee802154_addr *daddr,
|
||||
const struct ieee802154_addr *saddr,
|
||||
unsigned int len);
|
||||
};
|
||||
|
||||
struct wpan_dev {
|
||||
struct wpan_phy *wpan_phy;
|
||||
int iftype;
|
||||
|
@ -175,6 +195,8 @@ struct wpan_dev {
|
|||
struct list_head list;
|
||||
struct net_device *netdev;
|
||||
|
||||
const struct wpan_dev_header_ops *header_ops;
|
||||
|
||||
/* lowpan interface, set when the wpan_dev belongs to one lowpan_dev */
|
||||
struct net_device *lowpan_dev;
|
||||
|
||||
|
@ -205,6 +227,17 @@ struct wpan_dev {
|
|||
|
||||
#define to_phy(_dev) container_of(_dev, struct wpan_phy, dev)
|
||||
|
||||
static inline int
|
||||
wpan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,
|
||||
const struct ieee802154_addr *daddr,
|
||||
const struct ieee802154_addr *saddr,
|
||||
unsigned int len)
|
||||
{
|
||||
struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
|
||||
|
||||
return wpan_dev->header_ops->create(skb, dev, daddr, saddr, len);
|
||||
}
|
||||
|
||||
struct wpan_phy *
|
||||
wpan_phy_new(const struct cfg802154_ops *ops, size_t priv_size);
|
||||
static inline void wpan_phy_set_dev(struct wpan_phy *phy, struct device *dev)
|
||||
|
|
|
@ -50,15 +50,6 @@ struct ieee802154_sechdr {
|
|||
};
|
||||
};
|
||||
|
||||
struct ieee802154_addr {
|
||||
u8 mode;
|
||||
__le16 pan_id;
|
||||
union {
|
||||
__le16 short_addr;
|
||||
__le64 extended_addr;
|
||||
};
|
||||
};
|
||||
|
||||
struct ieee802154_hdr_fc {
|
||||
#if defined(__LITTLE_ENDIAN_BITFIELD)
|
||||
u16 type:3,
|
||||
|
|
|
@ -87,8 +87,8 @@ lowpan_alloc_frag(struct sk_buff *skb, int size,
|
|||
skb_reset_network_header(frag);
|
||||
*mac_cb(frag) = *mac_cb(skb);
|
||||
|
||||
rc = dev_hard_header(frag, wdev, 0, &master_hdr->dest,
|
||||
&master_hdr->source, size);
|
||||
rc = wpan_dev_hard_header(frag, wdev, &master_hdr->dest,
|
||||
&master_hdr->source, size);
|
||||
if (rc < 0) {
|
||||
kfree_skb(frag);
|
||||
return ERR_PTR(rc);
|
||||
|
@ -228,8 +228,8 @@ static int lowpan_header(struct sk_buff *skb, struct net_device *ldev,
|
|||
cb->ackreq = wpan_dev->ackreq;
|
||||
}
|
||||
|
||||
return dev_hard_header(skb, lowpan_dev_info(ldev)->wdev, ETH_P_IPV6,
|
||||
(void *)&da, (void *)&sa, 0);
|
||||
return wpan_dev_hard_header(skb, lowpan_dev_info(ldev)->wdev, &da, &sa,
|
||||
0);
|
||||
}
|
||||
|
||||
netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *ldev)
|
||||
|
|
|
@ -676,8 +676,8 @@ static int dgram_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
|
|||
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);
|
||||
err = wpan_dev_hard_header(skb, dev, &dst_addr,
|
||||
ro->bound ? &ro->src_addr : NULL, size);
|
||||
if (err < 0)
|
||||
goto out_skb;
|
||||
|
||||
|
|
|
@ -367,12 +367,11 @@ static int mac802154_set_header_security(struct ieee802154_sub_if_data *sdata,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int mac802154_header_create(struct sk_buff *skb,
|
||||
struct net_device *dev,
|
||||
unsigned short type,
|
||||
const void *daddr,
|
||||
const void *saddr,
|
||||
unsigned len)
|
||||
static int ieee802154_header_create(struct sk_buff *skb,
|
||||
struct net_device *dev,
|
||||
const struct ieee802154_addr *daddr,
|
||||
const struct ieee802154_addr *saddr,
|
||||
unsigned len)
|
||||
{
|
||||
struct ieee802154_hdr hdr;
|
||||
struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
|
||||
|
@ -423,24 +422,91 @@ static int mac802154_header_create(struct sk_buff *skb,
|
|||
return hlen;
|
||||
}
|
||||
|
||||
static const struct wpan_dev_header_ops ieee802154_header_ops = {
|
||||
.create = ieee802154_header_create,
|
||||
};
|
||||
|
||||
/* This header create functionality assumes a 8 byte array for
|
||||
* source and destination pointer at maximum. To adapt this for
|
||||
* the 802.15.4 dataframe header we use extended address handling
|
||||
* here only and intra pan connection. fc fields are mostly fallback
|
||||
* handling. For provide dev_hard_header for dgram sockets.
|
||||
*/
|
||||
static int mac802154_header_create(struct sk_buff *skb,
|
||||
struct net_device *dev,
|
||||
unsigned short type,
|
||||
const void *daddr,
|
||||
const void *saddr,
|
||||
unsigned len)
|
||||
{
|
||||
struct ieee802154_hdr hdr;
|
||||
struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
|
||||
struct wpan_dev *wpan_dev = &sdata->wpan_dev;
|
||||
struct ieee802154_mac_cb cb = { };
|
||||
int hlen;
|
||||
|
||||
if (!daddr)
|
||||
return -EINVAL;
|
||||
|
||||
memset(&hdr.fc, 0, sizeof(hdr.fc));
|
||||
hdr.fc.type = IEEE802154_FC_TYPE_DATA;
|
||||
hdr.fc.ack_request = wpan_dev->ackreq;
|
||||
hdr.seq = atomic_inc_return(&dev->ieee802154_ptr->dsn) & 0xFF;
|
||||
|
||||
/* TODO currently a workaround to give zero cb block to set
|
||||
* security parameters defaults according MIB.
|
||||
*/
|
||||
if (mac802154_set_header_security(sdata, &hdr, &cb) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
hdr.dest.pan_id = wpan_dev->pan_id;
|
||||
hdr.dest.mode = IEEE802154_ADDR_LONG;
|
||||
memcpy(&hdr.dest.extended_addr, daddr, IEEE802154_EXTENDED_ADDR_LEN);
|
||||
|
||||
hdr.source.pan_id = hdr.dest.pan_id;
|
||||
hdr.source.mode = IEEE802154_ADDR_LONG;
|
||||
|
||||
if (!saddr)
|
||||
hdr.source.extended_addr = wpan_dev->extended_addr;
|
||||
else
|
||||
memcpy(&hdr.source.extended_addr, saddr,
|
||||
IEEE802154_EXTENDED_ADDR_LEN);
|
||||
|
||||
hlen = ieee802154_hdr_push(skb, &hdr);
|
||||
if (hlen < 0)
|
||||
return -EINVAL;
|
||||
|
||||
skb_reset_mac_header(skb);
|
||||
skb->mac_len = hlen;
|
||||
|
||||
if (len > ieee802154_max_payload(&hdr))
|
||||
return -EMSGSIZE;
|
||||
|
||||
return hlen;
|
||||
}
|
||||
|
||||
static int
|
||||
mac802154_header_parse(const struct sk_buff *skb, unsigned char *haddr)
|
||||
{
|
||||
struct ieee802154_hdr hdr;
|
||||
struct ieee802154_addr *addr = (struct ieee802154_addr *)haddr;
|
||||
|
||||
if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0) {
|
||||
pr_debug("malformed packet\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
*addr = hdr.source;
|
||||
return sizeof(*addr);
|
||||
if (hdr.source.mode == IEEE802154_ADDR_LONG) {
|
||||
memcpy(haddr, &hdr.source.extended_addr,
|
||||
IEEE802154_EXTENDED_ADDR_LEN);
|
||||
return IEEE802154_EXTENDED_ADDR_LEN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct header_ops mac802154_header_ops = {
|
||||
.create = mac802154_header_create,
|
||||
.parse = mac802154_header_parse,
|
||||
static const struct header_ops mac802154_header_ops = {
|
||||
.create = mac802154_header_create,
|
||||
.parse = mac802154_header_parse,
|
||||
};
|
||||
|
||||
static const struct net_device_ops mac802154_wpan_ops = {
|
||||
|
@ -513,6 +579,7 @@ ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata,
|
|||
sdata->dev->netdev_ops = &mac802154_wpan_ops;
|
||||
sdata->dev->ml_priv = &mac802154_mlme_wpan;
|
||||
wpan_dev->promiscuous_mode = false;
|
||||
wpan_dev->header_ops = &ieee802154_header_ops;
|
||||
|
||||
mutex_init(&sdata->sec_mtx);
|
||||
|
||||
|
|
Loading…
Reference in a new issue