Patchwork [08/12,MAC802154] mac802154: MAC commands support

login
register
mail settings
Submitter alex.bluesman.smirnov@gmail.com
Date Nov. 30, 2011, 2:25 p.m.
Message ID <1322663157-4022-1-git-send-email-alex.bluesman.smirnov@gmail.com>
Download mbox | patch
Permalink /patch/128512/
State RFC
Delegated to: David Miller
Headers show

Comments

alex.bluesman.smirnov@gmail.com - Nov. 30, 2011, 2:25 p.m.
Support for MAC layer commands. Currently association and
disassociation are implemented only.

Signed-off-by: Alexander Smirnov <alex.bluesman.smirnov@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

Patch

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 <slapin@ossfans.org>
+ * Dmitry Eremin-Solenikov <dbaryshkov@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,
+};