ieee802154: introduce wpan_dev_header_ops
authorAlexander Aring <alex.aring@gmail.com>
Fri, 18 Sep 2015 09:30:42 +0000 (11:30 +0200)
committerMarcel Holtmann <marcel@holtmann.org>
Tue, 22 Sep 2015 09:51:20 +0000 (11:51 +0200)
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>
include/net/cfg802154.h
include/net/ieee802154_netdev.h
net/ieee802154/6lowpan/tx.c
net/ieee802154/socket.c
net/mac802154/iface.c

index 76b1ffaea863600be09280cc4c2d168dc5bae41f..242273ccf34b1cf24120bf6dec423efd36f44813 100644 (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)
index 95a71bc113b3cd3f0c0163e99c6d2e48c19bdfea..aebb9d8d7a112ae6d78e1399f2578fd3431e458e 100644 (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,
index 54939d031ea5d21e348a3be36bc9e2ef7bcaa82f..6067e064a3fe2bcd78ca0a7b3e5996c6bc01d0af 100644 (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)
index b6eacf30ee7a619e10a682e7c3e5c2a5e9dfe408..be77f211ce87ff05954fec31bc2d736542d09e23 100644 (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;
 
index ed26952f9e143407723dca1ef45d8400424aca3e..8afe26d729710021c3707d815bdd2bebb994fc96 100644 (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);