Support for MAC layer commands. Currently association and
disassociation are implemented only.

Signed-off-by: Alexander Smirnov <alex.bluesman.smir...@gmail.com>
---
 net/mac802154/Makefile  |    2 +-
 net/mac802154/mac_cmd.c |  300 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 301 insertions(+), 1 deletions(-)
 create mode 100644 net/mac802154/mac_cmd.c

diff --git a/net/mac802154/Makefile b/net/mac802154/Makefile
index 875feb2..50e2569 100644
--- a/net/mac802154/Makefile
+++ b/net/mac802154/Makefile
@@ -1,2 +1,2 @@
 obj-$(CONFIG_MAC802154)        += mac802154.o
-mac802154-objs         := ieee802154_dev.o rx.o tx.o mib.o
+mac802154-objs         := ieee802154_dev.o rx.o tx.o mib.o mac_cmd.o
diff --git a/net/mac802154/mac_cmd.c b/net/mac802154/mac_cmd.c
new file mode 100644
index 0000000..0013358
--- /dev/null
+++ b/net/mac802154/mac_cmd.c
@@ -0,0 +1,300 @@
+/*
+ * MAC commands interface
+ *
+ * Copyright 2007, 2008 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Written by:
+ * Sergey Lapin <sla...@ossfans.org>
+ * Dmitry Eremin-Solenikov <dbarysh...@gmail.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <net/af_ieee802154.h>
+#include <net/mac802154.h>
+#include <net/ieee802154.h>
+#include <net/ieee802154_netdev.h>
+#include <net/nl802154.h>
+
+#include "mac802154.h"
+#include "mib.h"
+
+static int mac802154_cmd_assoc_req(struct sk_buff *skb)
+{
+       u8 cap;
+
+       if (skb->len != 2)
+               return -EINVAL;
+
+       if (skb->pkt_type != PACKET_HOST)
+               return 0;
+
+       if (mac_cb(skb)->sa.addr_type != IEEE802154_ADDR_LONG ||
+           mac_cb(skb)->sa.pan_id != IEEE802154_PANID_BROADCAST)
+               return -EINVAL;
+
+       /*
+        * FIXME: check that we allow incoming ASSOC requests
+        * by consulting MIB
+        */
+
+       cap = skb->data[1];
+
+       return ieee802154_nl_assoc_indic(skb->dev, &mac_cb(skb)->sa, cap);
+}
+
+static int mac802154_cmd_assoc_resp(struct sk_buff *skb)
+{
+       u8 status;
+       u16 short_addr;
+
+       if (skb->len != 4)
+               return -EINVAL;
+
+       if (skb->pkt_type != PACKET_HOST)
+               return 0;
+
+       if (mac_cb(skb)->sa.addr_type != IEEE802154_ADDR_LONG ||
+           mac_cb(skb)->sa.addr_type != IEEE802154_ADDR_LONG ||
+           !(mac_cb(skb)->flags & MAC_CB_FLAG_INTRAPAN))
+               return -EINVAL;
+
+       /* FIXME: check that we requested association ? */
+
+       status = skb->data[3];
+       short_addr = skb->data[1] | (skb->data[2] << 8);
+       pr_info("Received ASSOC-RESP status %x, addr %hx\n", status,
+                       short_addr);
+       if (status) {
+               mac802154_dev_set_short_addr(skb->dev,
+                               IEEE802154_ADDR_BROADCAST);
+               mac802154_dev_set_pan_id(skb->dev,
+                               IEEE802154_PANID_BROADCAST);
+       } else
+               mac802154_dev_set_short_addr(skb->dev, short_addr);
+
+       return ieee802154_nl_assoc_confirm(skb->dev, short_addr, status);
+}
+
+static int mac802154_cmd_disassoc_notify(struct sk_buff *skb)
+{
+       u8 reason;
+
+       if (skb->len != 2)
+               return -EINVAL;
+
+       if (skb->pkt_type != PACKET_HOST)
+               return 0;
+
+       if (mac_cb(skb)->sa.addr_type != IEEE802154_ADDR_LONG ||
+           (mac_cb(skb)->da.addr_type != IEEE802154_ADDR_LONG &&
+            mac_cb(skb)->da.addr_type != IEEE802154_ADDR_SHORT) ||
+           mac_cb(skb)->sa.pan_id != mac_cb(skb)->da.pan_id)
+               return -EINVAL;
+
+       reason = skb->data[1];
+
+       /* FIXME: checks if this was our coordinator and the disassoc us */
+       /* FIXME: if we device, one should receive ->da and not ->sa */
+       /* FIXME: the status should also help */
+
+       return ieee802154_nl_disassoc_indic(skb->dev, &mac_cb(skb)->sa,
+                       reason);
+}
+
+int mac802154_process_cmd(struct net_device *dev, struct sk_buff *skb)
+{
+       u8 cmd;
+
+       if (skb->len < 1) {
+               pr_warning("Uncomplete command frame!\n");
+               goto drop;
+       }
+
+       cmd = *(skb->data);
+       pr_debug("(%s): command %02x on device %s\n",
+                                       __func__, cmd, dev->name);
+
+       switch (cmd) {
+       case IEEE802154_CMD_ASSOCIATION_REQ:
+               mac802154_cmd_assoc_req(skb);
+               break;
+       case IEEE802154_CMD_ASSOCIATION_RESP:
+               mac802154_cmd_assoc_resp(skb);
+               break;
+       case IEEE802154_CMD_DISASSOCIATION_NOTIFY:
+               mac802154_cmd_disassoc_notify(skb);
+               break;
+       case IEEE802154_CMD_BEACON_REQ:
+       default:
+               pr_debug("(%s): frame type is not supported yet\n", __func__);
+               goto drop;
+       }
+
+
+       kfree_skb(skb);
+       return NET_RX_SUCCESS;
+
+drop:
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+static int mac802154_send_cmd(struct net_device *dev,
+               struct ieee802154_addr *addr, struct ieee802154_addr *saddr,
+               const u8 *buf, int len)
+{
+       struct sk_buff *skb;
+       int err;
+       int hlen = LL_RESERVED_SPACE(dev), tlen = dev->needed_tailroom;
+
+       BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+       skb = alloc_skb(hlen + tlen + len, GFP_KERNEL);
+       if (!skb)
+               return -ENOMEM;
+
+       skb_reserve(skb, hlen);
+
+       skb_reset_network_header(skb);
+
+       mac_cb(skb)->flags = IEEE802154_FC_TYPE_MAC_CMD | MAC_CB_FLAG_ACKREQ;
+       mac_cb(skb)->seq = ieee802154_mlme_ops(dev)->get_dsn(dev);
+       err = dev_hard_header(skb, dev, ETH_P_IEEE802154, addr, saddr, len);
+       if (err < 0) {
+               kfree_skb(skb);
+               return err;
+       }
+
+       skb_reset_mac_header(skb);
+       memcpy(skb_put(skb, len), buf, len);
+
+       skb->dev = dev;
+       skb->protocol = htons(ETH_P_IEEE802154);
+
+       return dev_queue_xmit(skb);
+}
+
+static int mac802154_mlme_assoc_req(struct net_device *dev,
+               struct ieee802154_addr *addr, u8 channel, u8 page, u8 cap)
+{
+       struct ieee802154_addr saddr;
+       u8 buf[2];
+       int pos = 0;
+
+       saddr.addr_type = IEEE802154_ADDR_LONG;
+       saddr.pan_id = IEEE802154_PANID_BROADCAST;
+       memcpy(saddr.hwaddr, dev->dev_addr, IEEE802154_ADDR_LEN);
+
+
+       /* FIXME: set PIB/MIB info */
+       mac802154_dev_set_pan_id(dev, addr->pan_id);
+       mac802154_dev_set_page_channel(dev, page, channel);
+       mac802154_dev_set_ieee_addr(dev);
+
+       buf[pos++] = IEEE802154_CMD_ASSOCIATION_REQ;
+       buf[pos++] = cap;
+
+       return mac802154_send_cmd(dev, addr, &saddr, buf, pos);
+}
+
+static int mac802154_mlme_assoc_resp(struct net_device *dev,
+               struct ieee802154_addr *addr, u16 short_addr, u8 status)
+{
+       struct ieee802154_addr saddr;
+       u8 buf[4];
+       int pos = 0;
+
+       saddr.addr_type = IEEE802154_ADDR_LONG;
+       saddr.pan_id = addr->pan_id;
+       memcpy(saddr.hwaddr, dev->dev_addr, IEEE802154_ADDR_LEN);
+
+       buf[pos++] = IEEE802154_CMD_ASSOCIATION_RESP;
+       buf[pos++] = short_addr;
+       buf[pos++] = short_addr >> 8;
+       buf[pos++] = status;
+
+       return mac802154_send_cmd(dev, addr, &saddr, buf, pos);
+}
+
+static int mac802154_mlme_disassoc_req(struct net_device *dev,
+               struct ieee802154_addr *addr, u8 reason)
+{
+       struct ieee802154_addr saddr;
+       u8 buf[2];
+       int pos = 0;
+       int ret;
+
+       saddr.addr_type = IEEE802154_ADDR_LONG;
+       saddr.pan_id = addr->pan_id;
+       memcpy(saddr.hwaddr, dev->dev_addr, IEEE802154_ADDR_LEN);
+
+       buf[pos++] = IEEE802154_CMD_DISASSOCIATION_NOTIFY;
+       buf[pos++] = reason;
+
+       ret = mac802154_send_cmd(dev, addr, &saddr, buf, pos);
+
+       /* FIXME: this should be after the ack receved */
+       mac802154_dev_set_pan_id(dev, 0xffff);
+       mac802154_dev_set_short_addr(dev, 0xffff);
+       ieee802154_nl_disassoc_confirm(dev, 0x00);
+
+       return ret;
+}
+
+static int mac802154_mlme_start_req(struct net_device *dev,
+                               struct ieee802154_addr *addr,
+                               u8 channel, u8 page,
+                               u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx,
+                               u8 coord_realign)
+{
+       BUG_ON(addr->addr_type != IEEE802154_ADDR_SHORT);
+
+       mac802154_dev_set_pan_id(dev, addr->pan_id);
+       mac802154_dev_set_short_addr(dev, addr->short_addr);
+       mac802154_dev_set_ieee_addr(dev);
+       mac802154_dev_set_page_channel(dev, page, channel);
+
+       /*
+        * FIXME: add validation for unused parameters to be sane
+        * for SoftMAC
+        */
+
+       if (pan_coord)
+               dev->priv_flags |= IFF_IEEE802154_COORD;
+       else
+               dev->priv_flags &= ~IFF_IEEE802154_COORD;
+
+       mac802154_dev_set_pan_coord(dev);
+       ieee802154_nl_start_confirm(dev, IEEE802154_SUCCESS);
+
+       return 0;
+}
+
+struct ieee802154_mlme_ops mac802154_mlme_wpan = {
+       .assoc_req = mac802154_mlme_assoc_req,
+       .assoc_resp = mac802154_mlme_assoc_resp,
+       .disassoc_req = mac802154_mlme_disassoc_req,
+       .start_req = mac802154_mlme_start_req,
+
+       .wpan_ops.get_phy = mac802154_get_phy,
+
+       .get_pan_id = mac802154_dev_get_pan_id,
+       .get_short_addr = mac802154_dev_get_short_addr,
+       .get_dsn = mac802154_dev_get_dsn,
+       .get_bsn = mac802154_dev_get_bsn,
+};
-- 
1.7.2.3


------------------------------------------------------------------------------
All the data continuously generated in your IT infrastructure 
contains a definitive record of customers, application performance, 
security threats, fraudulent activity, and more. Splunk takes this 
data and makes sense of it. IT sense. And common sense.
http://p.sf.net/sfu/splunk-novd2d
_______________________________________________
Linux-zigbee-devel mailing list
Linux-zigbee-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-zigbee-devel

Reply via email to