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:
Alexander Aring 2015-09-18 11:30:42 +02:00 committed by Marcel Holtmann
parent a1da67b811
commit 838b83d63d
5 changed files with 118 additions and 27 deletions

View file

@ -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)

View file

@ -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,

View file

@ -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)

View file

@ -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;

View file

@ -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);