]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - net/mac802154/iface.c
Merge remote-tracking branch 'arm-soc/for-next'
[karo-tx-linux.git] / net / mac802154 / iface.c
index ed26952f9e143407723dca1ef45d8400424aca3e..7079cd32a7ad201265cf730027dda07254e622aa 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,89 @@ 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;
+       ieee802154_be64_to_le64(&hdr.dest.extended_addr, daddr);
+
+       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
+               ieee802154_be64_to_le64(&hdr.source.extended_addr, saddr);
+
+       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) {
+               ieee802154_le64_to_be64(haddr, &hdr.source.extended_addr);
+               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 = {
@@ -471,9 +535,29 @@ static void ieee802154_if_setup(struct net_device *dev)
        dev->addr_len           = IEEE802154_EXTENDED_ADDR_LEN;
        memset(dev->broadcast, 0xff, IEEE802154_EXTENDED_ADDR_LEN);
 
-       dev->hard_header_len    = MAC802154_FRAME_HARD_HEADER_LEN;
-       dev->needed_tailroom    = 2 + 16; /* FCS + MIC */
-       dev->mtu                = IEEE802154_MTU;
+       /* Let hard_header_len set to IEEE802154_MIN_HEADER_LEN. AF_PACKET
+        * will not send frames without any payload, but ack frames
+        * has no payload, so substract one that we can send a 3 bytes
+        * frame. The xmit callback assumes at least a hard header where two
+        * bytes fc and sequence field are set.
+        */
+       dev->hard_header_len    = IEEE802154_MIN_HEADER_LEN - 1;
+       /* The auth_tag header is for security and places in private payload
+        * room of mac frame which stucks between payload and FCS field.
+        */
+       dev->needed_tailroom    = IEEE802154_MAX_AUTH_TAG_LEN +
+                                 IEEE802154_FCS_LEN;
+       /* The mtu size is the payload without mac header in this case.
+        * We have a dynamic length header with a minimum header length
+        * which is hard_header_len. In this case we let mtu to the size
+        * of maximum payload which is IEEE802154_MTU - IEEE802154_FCS_LEN -
+        * hard_header_len. The FCS which is set by hardware or ndo_start_xmit
+        * and the minimum mac header which can be evaluated inside driver
+        * layer. The rest of mac header will be part of payload if greater
+        * than hard_header_len.
+        */
+       dev->mtu                = IEEE802154_MTU - IEEE802154_FCS_LEN -
+                                 dev->hard_header_len;
        dev->tx_queue_len       = 300;
        dev->flags              = IFF_NOARP | IFF_BROADCAST;
 }
@@ -513,6 +597,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);
 
@@ -550,7 +635,8 @@ ieee802154_if_add(struct ieee802154_local *local, const char *name,
        if (!ndev)
                return ERR_PTR(-ENOMEM);
 
-       ndev->needed_headroom = local->hw.extra_tx_headroom;
+       ndev->needed_headroom = local->hw.extra_tx_headroom +
+                               IEEE802154_MAX_HEADER_LEN;
 
        ret = dev_alloc_name(ndev, ndev->name);
        if (ret < 0)