mac802154: monitor device support
authoralex.bluesman.smirnov@gmail.com <alex.bluesman.smirnov@gmail.com>
Tue, 15 May 2012 20:50:29 +0000 (20:50 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 16 May 2012 19:17:08 +0000 (15:17 -0400)
Support for monitor device intended to capture all the network activity.
This interface could be used by networks sniffers and is already
supported by WireShark. That's a good test point to check that basic
MAC support works.

Signed-off-by: Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/if_arp.h
include/linux/nl802154.h
include/net/wpan-phy.h
net/mac802154/Makefile
net/mac802154/ieee802154_dev.c
net/mac802154/mac802154.h
net/mac802154/monitor.c [new file with mode: 0644]
net/mac802154/rx.c

index 3718acf40a09ba9aba3026524a3c099841a548f7..26cb3c2c5c7175668d26923977a2464ce4d2e02f 100644 (file)
@@ -87,6 +87,7 @@
 #define ARPHRD_IEEE80211_PRISM 802     /* IEEE 802.11 + Prism2 header  */
 #define ARPHRD_IEEE80211_RADIOTAP 803  /* IEEE 802.11 + radiotap header */
 #define ARPHRD_IEEE802154        804
+#define ARPHRD_IEEE802154_MONITOR 805  /* IEEE 802.15.4 network monitor */
 
 #define ARPHRD_PHONET  820             /* PhoNet media type            */
 #define ARPHRD_PHONET_PIPE 821         /* PhoNet pipe header           */
index 2015ad24810193013f53f9d4660e53f57c84656b..5a3db3aa5f17425587411e26ed1736cb92a6a5c4 100644 (file)
@@ -129,6 +129,20 @@ enum {
 
 enum {
        __IEEE802154_DEV_INVALID = -1,
+
+        /* TODO:
+        * Nowadays three device types supported by this stack at linux-zigbee
+        * project: WPAN = 0, MONITOR = 1 and SMAC = 2.
+        *
+        * Since this stack implementation exists many years, it's definitely
+        * bad idea to change the assigned values due to they are already used
+        * by third-party userspace software like: iz-tools, wireshark...
+        *
+        * Currently only monitor device is added and initialized by '1' for
+        * compatibility.
+        */
+       IEEE802154_DEV_MONITOR = 1,
+
        __IEEE802154_DEV_MAX,
 };
 
index efd6749e392b399117399afed88cd38f656c4135..b52bda8d13b183a953b88cb90700a1ee8cf08e23 100644 (file)
 #include <linux/mutex.h>
 #include <linux/bug.h>
 
+/* According to the IEEE 802.15.4 stadard the upper most significant bits of
+ * the 32-bit channel bitmaps shall be used as an integer value to specify 32
+ * possible channel pages. The lower 27 bits of the channel bit map shall be
+ * used as a bit mask to specify channel numbers within a channel page.
+ */
+#define WPAN_NUM_CHANNELS      27
+#define WPAN_NUM_PAGES         32
+
 struct wpan_phy {
        struct mutex pib_lock;
 
index 6b348b07a7656859de1487b29fbf24c952621cbb..ec1bd3fc1273026718c0ee5cb68278bdfb3da6b1 100644 (file)
@@ -1,2 +1,2 @@
 obj-$(CONFIG_MAC802154)        += mac802154.o
-mac802154-objs         := ieee802154_dev.o rx.o tx.o mac_cmd.o mib.o
+mac802154-objs         := ieee802154_dev.o rx.o tx.o mac_cmd.o mib.o monitor.o
index 9f36760b6c3a128d110dceb2f2524ef75aa50faf..e3edfb0661b0f2fdde02e0a84f14cb7f5f4700f3 100644 (file)
@@ -135,8 +135,11 @@ mac802154_add_iface(struct wpan_phy *phy, const char *name, int type)
        struct net_device *dev;
        int err = -ENOMEM;
 
-       /* No devices is currently added */
        switch (type) {
+       case IEEE802154_DEV_MONITOR:
+               dev = alloc_netdev(sizeof(struct mac802154_sub_if_data),
+                                  name, mac802154_monitor_setup);
+               break;
        default:
                dev = NULL;
                err = -EINVAL;
index 622752622c87d718886e7ea0d8f90e1a469843f8..789d9c948aec4855665d45fe5af436dc5c9c5af6 100644 (file)
@@ -90,11 +90,16 @@ struct mac802154_sub_if_data {
 
 #define MAC802154_MAX_XMIT_ATTEMPTS    3
 
+#define MAC802154_CHAN_NONE            (~(u8)0) /* No channel is assigned */
+
 extern struct ieee802154_reduced_mlme_ops mac802154_mlme_reduced;
 
 int mac802154_slave_open(struct net_device *dev);
 int mac802154_slave_close(struct net_device *dev);
 
+void mac802154_monitors_rx(struct mac802154_priv *priv, struct sk_buff *skb);
+void mac802154_monitor_setup(struct net_device *dev);
+
 netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb,
                         u8 page, u8 chan);
 
diff --git a/net/mac802154/monitor.c b/net/mac802154/monitor.c
new file mode 100644 (file)
index 0000000..434a26f
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2007, 2008, 2009 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:
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ * Sergey Lapin <slapin@ossfans.org>
+ * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
+ * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
+ */
+
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/crc-ccitt.h>
+
+#include <net/ieee802154.h>
+#include <net/mac802154.h>
+#include <net/netlink.h>
+#include <net/wpan-phy.h>
+#include <linux/nl802154.h>
+
+#include "mac802154.h"
+
+static netdev_tx_t mac802154_monitor_xmit(struct sk_buff *skb,
+                                         struct net_device *dev)
+{
+       struct mac802154_sub_if_data *priv;
+       u8 chan, page;
+
+       priv = netdev_priv(dev);
+
+       /* FIXME: locking */
+       chan = priv->hw->phy->current_channel;
+       page = priv->hw->phy->current_page;
+
+       if (chan == MAC802154_CHAN_NONE) /* not initialized */
+               return NETDEV_TX_OK;
+
+       if (WARN_ON(page >= WPAN_NUM_PAGES) ||
+           WARN_ON(chan >= WPAN_NUM_CHANNELS))
+               return NETDEV_TX_OK;
+
+       skb->skb_iif = dev->ifindex;
+       dev->stats.tx_packets++;
+       dev->stats.tx_bytes += skb->len;
+
+       return mac802154_tx(priv->hw, skb, page, chan);
+}
+
+
+void mac802154_monitors_rx(struct mac802154_priv *priv, struct sk_buff *skb)
+{
+       struct sk_buff *skb2;
+       struct mac802154_sub_if_data *sdata;
+       u16 crc = crc_ccitt(0, skb->data, skb->len);
+       u8 *data;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(sdata, &priv->slaves, list) {
+               if (sdata->type != IEEE802154_DEV_MONITOR)
+                       continue;
+
+               skb2 = skb_clone(skb, GFP_ATOMIC);
+               skb2->dev = sdata->dev;
+               skb2->pkt_type = PACKET_HOST;
+               data = skb_put(skb2, 2);
+               data[0] = crc & 0xff;
+               data[1] = crc >> 8;
+
+               netif_rx_ni(skb2);
+       }
+       rcu_read_unlock();
+}
+
+static const struct net_device_ops mac802154_monitor_ops = {
+       .ndo_open               = mac802154_slave_open,
+       .ndo_stop               = mac802154_slave_close,
+       .ndo_start_xmit         = mac802154_monitor_xmit,
+};
+
+void mac802154_monitor_setup(struct net_device *dev)
+{
+       struct mac802154_sub_if_data *priv;
+
+       dev->addr_len           = 0;
+       dev->hard_header_len    = 0;
+       dev->needed_tailroom    = 2; /* room for FCS */
+       dev->mtu                = IEEE802154_MTU;
+       dev->tx_queue_len       = 10;
+       dev->type               = ARPHRD_IEEE802154_MONITOR;
+       dev->flags              = IFF_NOARP | IFF_BROADCAST;
+       dev->watchdog_timeo     = 0;
+
+       dev->destructor         = free_netdev;
+       dev->netdev_ops         = &mac802154_monitor_ops;
+       dev->ml_priv            = &mac802154_mlme_reduced;
+
+       priv = netdev_priv(dev);
+       priv->type = IEEE802154_DEV_MONITOR;
+
+       priv->chan = MAC802154_CHAN_NONE; /* not initialized */
+       priv->page = 0;
+}
index d15738fae55179cc7f557f43923f9c543919359a..4a7d76d4f8bcf85ca8d087b50520df66043e69b8 100644 (file)
@@ -76,6 +76,7 @@ mac802154_subif_rx(struct ieee802154_dev *hw, struct sk_buff *skb, u8 lqi)
                skb_trim(skb, skb->len - 2); /* CRC */
        }
 
+       mac802154_monitors_rx(priv, skb);
 out:
        dev_kfree_skb(skb);
        return;