From patchwork Wed Nov 30 14:25:57 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: alex.bluesman.smirnov@gmail.com X-Patchwork-Id: 128512 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 60D6B1007D1 for ; Thu, 1 Dec 2011 00:26:24 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755718Ab1K3N0S (ORCPT ); Wed, 30 Nov 2011 08:26:18 -0500 Received: from mail-ey0-f174.google.com ([209.85.215.174]:33208 "EHLO mail-ey0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755012Ab1K3N0R (ORCPT ); Wed, 30 Nov 2011 08:26:17 -0500 Received: by eaak14 with SMTP id k14so664542eaa.19 for ; Wed, 30 Nov 2011 05:26:16 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; bh=OISef3vgLvGXvNTm2bGfwu0GpHjiKQLMm1tVyZAkIic=; b=gyvVeddXEUiskv4nu7PxVoh4POBRyq2/kEt3g7QbfZGPohYlPK0h7c3chrdEAgph0/ KrDSoL25pKqf8l0U0ZRoJoZtGFyUIH56keBna0qH4P3AZM66b3LdxwTtpgph7ApKJpy1 d3Pj5iiwDDaUMDvE9UwytBfOYviaMcHUd0BOk= Received: by 10.213.17.70 with SMTP id r6mr447424eba.100.1322659576371; Wed, 30 Nov 2011 05:26:16 -0800 (PST) Received: from localhost.localdomain ([91.213.169.4]) by mx.google.com with ESMTPS id d6sm6164692eec.10.2011.11.30.05.26.14 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 30 Nov 2011 05:26:15 -0800 (PST) From: Alexander Smirnov To: dbaryshkov@gmail.com Cc: linux-zigbee-devel@lists.sourceforge.net, netdev@vger.kernel.org, davem@davemloft.net, Alexander Smirnov Subject: [PATCH 08/12] [MAC802154] mac802154: MAC commands support Date: Wed, 30 Nov 2011 17:25:57 +0300 Message-Id: <1322663157-4022-1-git-send-email-alex.bluesman.smirnov@gmail.com> X-Mailer: git-send-email 1.7.2.3 In-Reply-To: <20111130141827.GA3739@avtobot.cybertron> References: <20111130141827.GA3739@avtobot.cybertron> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Support for MAC layer commands. Currently association and disassociation are implemented only. Signed-off-by: Alexander Smirnov --- 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 + * Dmitry Eremin-Solenikov + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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, +};