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;
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;
#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)
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);
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)
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);
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 = {
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);