All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC][WIP] IEEE 802.15.4 implementation for Linux v1
@ 2009-06-01 14:54 ` Dmitry Eremin-Solenikov
  0 siblings, 0 replies; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-01 14:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: netdev, linux-wireless, slapin, maxim.osipov, dmitry.baryshkov,
	oliver.fendt

Hi,

As a part of research activities the Embedded Systems - Open Platform Group
from Siemens Corporate Technology we are working on adding support for
the IEEE 802.15.4 Wireless Personal Area Networks to the Linux. Our current
implementation is neither certified nor even feature complete. However
we'd like to present current state of our patchset to the Linux developers
community to gain comments, fixes, ideas, etc. This is not yet a pull request,
but more like an RFC.

The project page is available at http://apps.sourceforge.net/trac/linux-zigbee
with source code of kernel part available from git at
http://zigbee-linux.git.sourceforge.net, mirrored for convenience at
git://git.kernel.org/pub/scm/linux/kernel/git/lumag/lowpan.git

The source code for userspace utils is available from git at
http://linux-zigbee.git.sourceforge.net/

Changes since previous RFC:
  * Split the code into socket family, netlink interface and separate
    MAC 802.15.4 implementation.
  * Add a sample driver for devices implementing mac level of IEEE 802.15.4
    on their own.
  * Major cleanup of public interfaces.
  * Drop our CRC implementation and use a variant of CRC-ITU-T one
  * Add preliminary version of AT86RF231 Atmel chip driver

The following changes since commit 59a3759d0fe8d969888c741bb33f4946e4d3750d:
  Linus Torvalds (1):
        Linux 2.6.30-rc7

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/lumag/lowpan.git for-review-v1

Darren Salt (1):
      crc-itu-t: add bit-reversed calculation

Dmitry Eremin-Solenikov (9):
      Add constants for the ieee 802.15.4/ZigBee stack
      net: add IEEE 802.15.4 socket family implementation
      net: add NL802154 interface for configuration of 802.15.4 devices
      ieee802154: add simple HardMAC driver sample
      mac802154: add a software MAC 802.15.4 implementation
      ieee802154: add virtual loopback driver
      tty_io: export tty_class
      ieee802154: add serial dongle driver
      ieee802154: add at86rf230/rf231 spi driver

 drivers/Makefile                       |    1 +
 drivers/char/tty_io.c                  |    1 +
 drivers/ieee802154/Kconfig             |   42 ++
 drivers/ieee802154/Makefile            |    6 +
 drivers/ieee802154/at86rf230.c         |  971 +++++++++++++++++++++++++++++++
 drivers/ieee802154/fakehard.c          |  253 ++++++++
 drivers/ieee802154/fakelb.c            |  335 +++++++++++
 drivers/ieee802154/serial.c            |  999 ++++++++++++++++++++++++++++++++
 drivers/net/Kconfig                    |    2 +
 include/linux/crc-itu-t.h              |   10 +
 include/linux/if.h                     |    2 +
 include/linux/if_arp.h                 |    2 +
 include/linux/if_ether.h               |    2 +
 include/linux/socket.h                 |    6 +-
 include/linux/spi/at86rf230.h          |   32 +
 include/linux/tty.h                    |    3 +-
 include/net/ieee802154/af_ieee802154.h |   60 ++
 include/net/ieee802154/mac802154.h     |   79 +++
 include/net/ieee802154/mac_def.h       |  158 +++++
 include/net/ieee802154/netdevice.h     |   84 +++
 include/net/ieee802154/nl802154.h      |  165 ++++++
 lib/crc-itu-t.c                        |   18 +
 net/Kconfig                            |    2 +
 net/Makefile                           |    2 +
 net/core/dev.c                         |    6 +-
 net/core/sock.c                        |    3 +
 net/ieee802154/Kconfig                 |   12 +
 net/ieee802154/Makefile                |    5 +
 net/ieee802154/af802154.h              |   35 ++
 net/ieee802154/af_ieee802154.c         |  356 ++++++++++++
 net/ieee802154/dgram.c                 |  373 ++++++++++++
 net/ieee802154/netlink.c               |  485 ++++++++++++++++
 net/ieee802154/raw.c                   |  250 ++++++++
 net/mac802154/Kconfig                  |   13 +
 net/mac802154/Makefile                 |    5 +
 net/mac802154/beacon.c                 |  242 ++++++++
 net/mac802154/beacon.h                 |   48 ++
 net/mac802154/beacon_hash.c            |  103 ++++
 net/mac802154/beacon_hash.h            |   40 ++
 net/mac802154/dev.c                    |  843 +++++++++++++++++++++++++++
 net/mac802154/mac802154.h              |   64 ++
 net/mac802154/mac_cmd.c                |  325 +++++++++++
 net/mac802154/main.c                   |   96 +++
 net/mac802154/mdev.c                   |  283 +++++++++
 net/mac802154/mib.h                    |   32 +
 net/mac802154/pib.c                    |   87 +++
 net/mac802154/pib.h                    |   35 ++
 net/mac802154/scan.c                   |  215 +++++++
 48 files changed, 7187 insertions(+), 4 deletions(-)
 create mode 100644 drivers/ieee802154/Kconfig
 create mode 100644 drivers/ieee802154/Makefile
 create mode 100644 drivers/ieee802154/at86rf230.c
 create mode 100644 drivers/ieee802154/fakehard.c
 create mode 100644 drivers/ieee802154/fakelb.c
 create mode 100644 drivers/ieee802154/serial.c
 create mode 100644 include/linux/spi/at86rf230.h
 create mode 100644 include/net/ieee802154/af_ieee802154.h
 create mode 100644 include/net/ieee802154/mac802154.h
 create mode 100644 include/net/ieee802154/mac_def.h
 create mode 100644 include/net/ieee802154/netdevice.h
 create mode 100644 include/net/ieee802154/nl802154.h
 create mode 100644 net/ieee802154/Kconfig
 create mode 100644 net/ieee802154/Makefile
 create mode 100644 net/ieee802154/af802154.h
 create mode 100644 net/ieee802154/af_ieee802154.c
 create mode 100644 net/ieee802154/dgram.c
 create mode 100644 net/ieee802154/netlink.c
 create mode 100644 net/ieee802154/raw.c
 create mode 100644 net/mac802154/Kconfig
 create mode 100644 net/mac802154/Makefile
 create mode 100644 net/mac802154/beacon.c
 create mode 100644 net/mac802154/beacon.h
 create mode 100644 net/mac802154/beacon_hash.c
 create mode 100644 net/mac802154/beacon_hash.h
 create mode 100644 net/mac802154/dev.c
 create mode 100644 net/mac802154/mac802154.h
 create mode 100644 net/mac802154/mac_cmd.c
 create mode 100644 net/mac802154/main.c
 create mode 100644 net/mac802154/mdev.c
 create mode 100644 net/mac802154/mib.h
 create mode 100644 net/mac802154/pib.c
 create mode 100644 net/mac802154/pib.h
 create mode 100644 net/mac802154/scan.c

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [RFC][WIP] IEEE 802.15.4 implementation for Linux v1
@ 2009-06-01 14:54 ` Dmitry Eremin-Solenikov
  0 siblings, 0 replies; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-01 14:54 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	slapin-9cOl001CZnBAfugRpC6u6w,
	maxim.osipov-kv7WeFo6aLtBDgjK7y7TUQ,
	dmitry.baryshkov-kv7WeFo6aLtBDgjK7y7TUQ,
	oliver.fendt-kv7WeFo6aLtBDgjK7y7TUQ

Hi,

As a part of research activities the Embedded Systems - Open Platform Group
from Siemens Corporate Technology we are working on adding support for
the IEEE 802.15.4 Wireless Personal Area Networks to the Linux. Our current
implementation is neither certified nor even feature complete. However
we'd like to present current state of our patchset to the Linux developers
community to gain comments, fixes, ideas, etc. This is not yet a pull request,
but more like an RFC.

The project page is available at http://apps.sourceforge.net/trac/linux-zigbee
with source code of kernel part available from git at
http://zigbee-linux.git.sourceforge.net, mirrored for convenience at
git://git.kernel.org/pub/scm/linux/kernel/git/lumag/lowpan.git

The source code for userspace utils is available from git at
http://linux-zigbee.git.sourceforge.net/

Changes since previous RFC:
  * Split the code into socket family, netlink interface and separate
    MAC 802.15.4 implementation.
  * Add a sample driver for devices implementing mac level of IEEE 802.15.4
    on their own.
  * Major cleanup of public interfaces.
  * Drop our CRC implementation and use a variant of CRC-ITU-T one
  * Add preliminary version of AT86RF231 Atmel chip driver

The following changes since commit 59a3759d0fe8d969888c741bb33f4946e4d3750d:
  Linus Torvalds (1):
        Linux 2.6.30-rc7

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/lumag/lowpan.git for-review-v1

Darren Salt (1):
      crc-itu-t: add bit-reversed calculation

Dmitry Eremin-Solenikov (9):
      Add constants for the ieee 802.15.4/ZigBee stack
      net: add IEEE 802.15.4 socket family implementation
      net: add NL802154 interface for configuration of 802.15.4 devices
      ieee802154: add simple HardMAC driver sample
      mac802154: add a software MAC 802.15.4 implementation
      ieee802154: add virtual loopback driver
      tty_io: export tty_class
      ieee802154: add serial dongle driver
      ieee802154: add at86rf230/rf231 spi driver

 drivers/Makefile                       |    1 +
 drivers/char/tty_io.c                  |    1 +
 drivers/ieee802154/Kconfig             |   42 ++
 drivers/ieee802154/Makefile            |    6 +
 drivers/ieee802154/at86rf230.c         |  971 +++++++++++++++++++++++++++++++
 drivers/ieee802154/fakehard.c          |  253 ++++++++
 drivers/ieee802154/fakelb.c            |  335 +++++++++++
 drivers/ieee802154/serial.c            |  999 ++++++++++++++++++++++++++++++++
 drivers/net/Kconfig                    |    2 +
 include/linux/crc-itu-t.h              |   10 +
 include/linux/if.h                     |    2 +
 include/linux/if_arp.h                 |    2 +
 include/linux/if_ether.h               |    2 +
 include/linux/socket.h                 |    6 +-
 include/linux/spi/at86rf230.h          |   32 +
 include/linux/tty.h                    |    3 +-
 include/net/ieee802154/af_ieee802154.h |   60 ++
 include/net/ieee802154/mac802154.h     |   79 +++
 include/net/ieee802154/mac_def.h       |  158 +++++
 include/net/ieee802154/netdevice.h     |   84 +++
 include/net/ieee802154/nl802154.h      |  165 ++++++
 lib/crc-itu-t.c                        |   18 +
 net/Kconfig                            |    2 +
 net/Makefile                           |    2 +
 net/core/dev.c                         |    6 +-
 net/core/sock.c                        |    3 +
 net/ieee802154/Kconfig                 |   12 +
 net/ieee802154/Makefile                |    5 +
 net/ieee802154/af802154.h              |   35 ++
 net/ieee802154/af_ieee802154.c         |  356 ++++++++++++
 net/ieee802154/dgram.c                 |  373 ++++++++++++
 net/ieee802154/netlink.c               |  485 ++++++++++++++++
 net/ieee802154/raw.c                   |  250 ++++++++
 net/mac802154/Kconfig                  |   13 +
 net/mac802154/Makefile                 |    5 +
 net/mac802154/beacon.c                 |  242 ++++++++
 net/mac802154/beacon.h                 |   48 ++
 net/mac802154/beacon_hash.c            |  103 ++++
 net/mac802154/beacon_hash.h            |   40 ++
 net/mac802154/dev.c                    |  843 +++++++++++++++++++++++++++
 net/mac802154/mac802154.h              |   64 ++
 net/mac802154/mac_cmd.c                |  325 +++++++++++
 net/mac802154/main.c                   |   96 +++
 net/mac802154/mdev.c                   |  283 +++++++++
 net/mac802154/mib.h                    |   32 +
 net/mac802154/pib.c                    |   87 +++
 net/mac802154/pib.h                    |   35 ++
 net/mac802154/scan.c                   |  215 +++++++
 48 files changed, 7187 insertions(+), 4 deletions(-)
 create mode 100644 drivers/ieee802154/Kconfig
 create mode 100644 drivers/ieee802154/Makefile
 create mode 100644 drivers/ieee802154/at86rf230.c
 create mode 100644 drivers/ieee802154/fakehard.c
 create mode 100644 drivers/ieee802154/fakelb.c
 create mode 100644 drivers/ieee802154/serial.c
 create mode 100644 include/linux/spi/at86rf230.h
 create mode 100644 include/net/ieee802154/af_ieee802154.h
 create mode 100644 include/net/ieee802154/mac802154.h
 create mode 100644 include/net/ieee802154/mac_def.h
 create mode 100644 include/net/ieee802154/netdevice.h
 create mode 100644 include/net/ieee802154/nl802154.h
 create mode 100644 net/ieee802154/Kconfig
 create mode 100644 net/ieee802154/Makefile
 create mode 100644 net/ieee802154/af802154.h
 create mode 100644 net/ieee802154/af_ieee802154.c
 create mode 100644 net/ieee802154/dgram.c
 create mode 100644 net/ieee802154/netlink.c
 create mode 100644 net/ieee802154/raw.c
 create mode 100644 net/mac802154/Kconfig
 create mode 100644 net/mac802154/Makefile
 create mode 100644 net/mac802154/beacon.c
 create mode 100644 net/mac802154/beacon.h
 create mode 100644 net/mac802154/beacon_hash.c
 create mode 100644 net/mac802154/beacon_hash.h
 create mode 100644 net/mac802154/dev.c
 create mode 100644 net/mac802154/mac802154.h
 create mode 100644 net/mac802154/mac_cmd.c
 create mode 100644 net/mac802154/main.c
 create mode 100644 net/mac802154/mdev.c
 create mode 100644 net/mac802154/mib.h
 create mode 100644 net/mac802154/pib.c
 create mode 100644 net/mac802154/pib.h
 create mode 100644 net/mac802154/scan.c
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [PATCH 01/10] crc-itu-t: add bit-reversed calculation
  2009-06-01 14:54 ` Dmitry Eremin-Solenikov
  (?)
@ 2009-06-01 14:54 ` Dmitry Eremin-Solenikov
  2009-06-01 14:54   ` [PATCH 02/10] Add constants for the ieee 802.15.4/ZigBee stack Dmitry Eremin-Solenikov
  2009-06-04  0:05   ` [PATCH 01/10] crc-itu-t: add bit-reversed calculation Andrew Morton
  -1 siblings, 2 replies; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-01 14:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: netdev, linux-wireless, slapin, maxim.osipov, dmitry.baryshkov,
	oliver.fendt, Darren Salt

From: Darren Salt <linux@youmustbejoking.demon.co.uk>

Signed-off-by: Darren Salt <linux@youmustbejoking.demon.co.uk>
---
 include/linux/crc-itu-t.h |   10 ++++++++++
 lib/crc-itu-t.c           |   18 ++++++++++++++++++
 2 files changed, 28 insertions(+), 0 deletions(-)

diff --git a/include/linux/crc-itu-t.h b/include/linux/crc-itu-t.h
index 84920f3..7b2b7ba 100644
--- a/include/linux/crc-itu-t.h
+++ b/include/linux/crc-itu-t.h
@@ -6,6 +6,9 @@
  *   Poly  0x0x1021 (x^16 + x^12 + x^15 + 1)
  *   Init  0
  *
+ * The bit-reversed buffer variants may be non-standard, but some firmware
+ * loaders require them.
+ *
  * This source code is licensed under the GNU General Public License,
  * Version 2. See the file COPYING for more details.
  */
@@ -14,15 +17,22 @@
 #define CRC_ITU_T_H
 
 #include <linux/types.h>
+#include <linux/bitrev.h>
 
 extern u16 const crc_itu_t_table[256];
 
 extern u16 crc_itu_t(u16 crc, const u8 *buffer, size_t len);
+extern u16 crc_itu_t_bitreversed(u16 crc, const u8 *buffer, size_t len);
 
 static inline u16 crc_itu_t_byte(u16 crc, const u8 data)
 {
 	return (crc << 8) ^ crc_itu_t_table[((crc >> 8) ^ data) & 0xff];
 }
 
+static inline u16 crc_itu_t_bitreversed_byte(u16 crc, const u8 data)
+{
+	return (crc << 8) ^ crc_itu_t_table[((crc >> 8) ^ bitrev8(data)) & 0xff];
+}
+
 #endif /* CRC_ITU_T_H */
 
diff --git a/lib/crc-itu-t.c b/lib/crc-itu-t.c
index a63472b..5562fdd 100644
--- a/lib/crc-itu-t.c
+++ b/lib/crc-itu-t.c
@@ -64,6 +64,24 @@ u16 crc_itu_t(u16 crc, const u8 *buffer, size_t len)
 }
 EXPORT_SYMBOL(crc_itu_t);
 
+/**
+ * crc_itu_t_bitreversed - Compute the CRC-ITU-T for the data buffer;
+ * the buffer content is assumed to be bit-reversed
+ *
+ * @crc:     previous CRC value
+ * @buffer:  data pointer
+ * @len:     number of bytes in the buffer
+ *
+ * Returns the updated CRC value
+ */
+u16 crc_itu_t_bitreversed(u16 crc, const u8 *buffer, size_t len)
+{
+	while (len--)
+		crc = crc_itu_t_bitreversed_byte(crc, *buffer++);
+	return crc;
+}
+EXPORT_SYMBOL(crc_itu_t_bitreversed);
+
 MODULE_DESCRIPTION("CRC ITU-T V.41 calculations");
 MODULE_LICENSE("GPL");
 
-- 
1.6.2.4


^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [PATCH 02/10] Add constants for the ieee 802.15.4/ZigBee stack
  2009-06-01 14:54 ` [PATCH 01/10] crc-itu-t: add bit-reversed calculation Dmitry Eremin-Solenikov
@ 2009-06-01 14:54   ` Dmitry Eremin-Solenikov
  2009-06-01 14:54     ` [PATCH 03/10] net: add IEEE 802.15.4 socket family implementation Dmitry Eremin-Solenikov
  2009-06-04  0:05   ` [PATCH 01/10] crc-itu-t: add bit-reversed calculation Andrew Morton
  1 sibling, 1 reply; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-01 14:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: netdev, linux-wireless, slapin, maxim.osipov, dmitry.baryshkov,
	oliver.fendt, Dmitry Eremin-Solenikov

IEEE 802.15.4/ZigBee stack requires several constants to be defined/adjusted.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Signed-off-by: Sergey Lapin <slapin@ossfans.org>
---
 include/linux/if.h       |    2 ++
 include/linux/if_arp.h   |    2 ++
 include/linux/if_ether.h |    2 ++
 include/linux/socket.h   |    6 +++++-
 net/core/dev.c           |    6 ++++--
 net/core/sock.c          |    3 +++
 6 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/include/linux/if.h b/include/linux/if.h
index 1108f3e..3f574b8 100644
--- a/include/linux/if.h
+++ b/include/linux/if.h
@@ -68,6 +68,8 @@
 #define IFF_MASTER_ARPMON 0x100		/* bonding master, ARP mon in use */
 #define IFF_WAN_HDLC	0x200		/* WAN HDLC device		*/
 
+#define IFF_IEEE802154_COORD 0x100	/* IEEE802.15.4 PAN coordinator */
+
 #define IF_GET_IFACE	0x0001		/* for querying only */
 #define IF_GET_PROTO	0x0002
 
diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h
index 5ff8980..b554300 100644
--- a/include/linux/if_arp.h
+++ b/include/linux/if_arp.h
@@ -86,6 +86,8 @@
 #define ARPHRD_IEEE80211 801		/* IEEE 802.11			*/
 #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_PHY	  805
 
 #define ARPHRD_PHONET	820		/* PhoNet media type		*/
 #define ARPHRD_PHONET_PIPE 821		/* PhoNet pipe header		*/
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
index cfe4fe1..0a08e92 100644
--- a/include/linux/if_ether.h
+++ b/include/linux/if_ether.h
@@ -106,6 +106,8 @@
 #define ETH_P_DSA	0x001B		/* Distributed Switch Arch.	*/
 #define ETH_P_TRAILER	0x001C		/* Trailer switch tagging	*/
 #define ETH_P_PHONET	0x00F5		/* Nokia Phonet frames          */
+#define ETH_P_IEEE802154 0x00F6		/* IEEE802.15.4 frame		*/
+#define ETH_P_IEEE802154_MAC 0x00F7	/* IEEE802.15.4 MAC frame	*/
 
 /*
  *	This is an Ethernet frame header.
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 421afb4..09d792e 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -194,7 +194,9 @@ struct ucred {
 #define AF_RXRPC	33	/* RxRPC sockets 		*/
 #define AF_ISDN		34	/* mISDN sockets 		*/
 #define AF_PHONET	35	/* Phonet sockets		*/
-#define AF_MAX		36	/* For now.. */
+#define AF_IEEE802154	36	/* IEEE802154 sockets		*/
+#define AF_ZIGBEE	37	/* ZIGBEE sockets		*/
+#define AF_MAX		38	/* For now.. */
 
 /* Protocol families, same as address families. */
 #define PF_UNSPEC	AF_UNSPEC
@@ -233,6 +235,8 @@ struct ucred {
 #define PF_RXRPC	AF_RXRPC
 #define PF_ISDN		AF_ISDN
 #define PF_PHONET	AF_PHONET
+#define PF_IEEE802154	AF_IEEE802154
+#define PF_ZIGBEE	AF_ZIGBEE
 #define PF_MAX		AF_MAX
 
 /* Maximum queue length specifiable by listen.  */
diff --git a/net/core/dev.c b/net/core/dev.c
index e2e9e4a..4119dfc 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -268,7 +268,8 @@ static const unsigned short netdev_lock_type[] =
 	 ARPHRD_IRDA, ARPHRD_FCPP, ARPHRD_FCAL, ARPHRD_FCPL,
 	 ARPHRD_FCFABRIC, ARPHRD_IEEE802_TR, ARPHRD_IEEE80211,
 	 ARPHRD_IEEE80211_PRISM, ARPHRD_IEEE80211_RADIOTAP, ARPHRD_PHONET,
-	 ARPHRD_PHONET_PIPE, ARPHRD_VOID, ARPHRD_NONE};
+	 ARPHRD_PHONET_PIPE, ARPHRD_IEEE802154, ARPHRD_IEEE802154_PHY,
+	 ARPHRD_VOID, ARPHRD_NONE};
 
 static const char *netdev_lock_name[] =
 	{"_xmit_NETROM", "_xmit_ETHER", "_xmit_EETHER", "_xmit_AX25",
@@ -285,7 +286,8 @@ static const char *netdev_lock_name[] =
 	 "_xmit_IRDA", "_xmit_FCPP", "_xmit_FCAL", "_xmit_FCPL",
 	 "_xmit_FCFABRIC", "_xmit_IEEE802_TR", "_xmit_IEEE80211",
 	 "_xmit_IEEE80211_PRISM", "_xmit_IEEE80211_RADIOTAP", "_xmit_PHONET",
-	 "_xmit_PHONET_PIPE", "_xmit_VOID", "_xmit_NONE"};
+	 "_xmit_PHONET_PIPE", "_xmit_IEEE802154", "_xmit_IEEE802154_PHY",
+	 "_xmit_VOID", "_xmit_NONE"};
 
 static struct lock_class_key netdev_xmit_lock_key[ARRAY_SIZE(netdev_lock_type)];
 static struct lock_class_key netdev_addr_lock_key[ARRAY_SIZE(netdev_lock_type)];
diff --git a/net/core/sock.c b/net/core/sock.c
index 7dbf3ff..72d593b 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -155,6 +155,7 @@ static const char *af_family_key_strings[AF_MAX+1] = {
   "sk_lock-27"       , "sk_lock-28"          , "sk_lock-AF_CAN"      ,
   "sk_lock-AF_TIPC"  , "sk_lock-AF_BLUETOOTH", "sk_lock-IUCV"        ,
   "sk_lock-AF_RXRPC" , "sk_lock-AF_ISDN"     , "sk_lock-AF_PHONET"   ,
+  "sk_lock-AF_IEEE802154", "sk_lock-AF_ZIGBEE",
   "sk_lock-AF_MAX"
 };
 static const char *af_family_slock_key_strings[AF_MAX+1] = {
@@ -170,6 +171,7 @@ static const char *af_family_slock_key_strings[AF_MAX+1] = {
   "slock-27"       , "slock-28"          , "slock-AF_CAN"      ,
   "slock-AF_TIPC"  , "slock-AF_BLUETOOTH", "slock-AF_IUCV"     ,
   "slock-AF_RXRPC" , "slock-AF_ISDN"     , "slock-AF_PHONET"   ,
+  "slock-AF_IEEE802154", "slock-AF_ZIGBEE",
   "slock-AF_MAX"
 };
 static const char *af_family_clock_key_strings[AF_MAX+1] = {
@@ -185,6 +187,7 @@ static const char *af_family_clock_key_strings[AF_MAX+1] = {
   "clock-27"       , "clock-28"          , "clock-AF_CAN"      ,
   "clock-AF_TIPC"  , "clock-AF_BLUETOOTH", "clock-AF_IUCV"     ,
   "clock-AF_RXRPC" , "clock-AF_ISDN"     , "clock-AF_PHONET"   ,
+  "clock-AF_IEEE802154", "clock-AF_ZIGBEE",
   "clock-AF_MAX"
 };
 
-- 
1.6.2.4


^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [PATCH 03/10] net: add IEEE 802.15.4 socket family implementation
  2009-06-01 14:54   ` [PATCH 02/10] Add constants for the ieee 802.15.4/ZigBee stack Dmitry Eremin-Solenikov
@ 2009-06-01 14:54     ` Dmitry Eremin-Solenikov
  2009-06-01 14:54         ` Dmitry Eremin-Solenikov
  2009-06-04  0:32         ` Andrew Morton
  0 siblings, 2 replies; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-01 14:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: netdev, linux-wireless, slapin, maxim.osipov, dmitry.baryshkov,
	oliver.fendt, Dmitry Eremin-Solenikov

Add support for communication over IEEE 802.15.4 networks. This implementation
is neither certified nor complete, but aims to that goal. This commit contains
only the socket interface for communication over IEEE 802.15.4 networks.
One can either send RAW datagrams or use SOCK_DGRAM to encapsulate data
inside normal IEEE 802.15.4 packets.

Configuration interface, drivers and software MAC 802.15.4 implementation will
follow.

Initial implementation was done by Maxim Gorbachyov, Maxim Osipov and Pavel
Smolensky as a research project at Siemens AG. Later the stack was heavily
reworked to better suit the linux networking model, and is now maitained
as an open project partially sponsored by Siemens.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Signed-off-by: Sergey Lapin <slapin@ossfans.org>
---
 include/net/ieee802154/af_ieee802154.h |   60 +++++
 include/net/ieee802154/mac_def.h       |  158 ++++++++++++++
 include/net/ieee802154/netdevice.h     |   84 +++++++
 net/Kconfig                            |    1 +
 net/Makefile                           |    1 +
 net/ieee802154/Kconfig                 |   12 +
 net/ieee802154/Makefile                |    4 +
 net/ieee802154/af802154.h              |   35 +++
 net/ieee802154/af_ieee802154.c         |  356 ++++++++++++++++++++++++++++++
 net/ieee802154/dgram.c                 |  373 ++++++++++++++++++++++++++++++++
 net/ieee802154/raw.c                   |  250 +++++++++++++++++++++
 11 files changed, 1334 insertions(+), 0 deletions(-)
 create mode 100644 include/net/ieee802154/af_ieee802154.h
 create mode 100644 include/net/ieee802154/mac_def.h
 create mode 100644 include/net/ieee802154/netdevice.h
 create mode 100644 net/ieee802154/Kconfig
 create mode 100644 net/ieee802154/Makefile
 create mode 100644 net/ieee802154/af802154.h
 create mode 100644 net/ieee802154/af_ieee802154.c
 create mode 100644 net/ieee802154/dgram.c
 create mode 100644 net/ieee802154/raw.c

diff --git a/include/net/ieee802154/af_ieee802154.h b/include/net/ieee802154/af_ieee802154.h
new file mode 100644
index 0000000..874f1e7
--- /dev/null
+++ b/include/net/ieee802154/af_ieee802154.h
@@ -0,0 +1,60 @@
+/*
+ * IEEE 802.15.4 inteface for userspace
+ *
+ * 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 <sergey.lapin@siemens.com>
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ */
+
+#ifndef _AF_IEEE802154_H
+#define _AF_IEEE802154_H
+
+#include <linux/socket.h> /* for sa_family_t */
+
+enum {
+	IEEE802154_ADDR_NONE = 0x0,
+	/* RESERVED = 0x01, */
+	IEEE802154_ADDR_SHORT = 0x2, /* 16-bit address + PANid */
+	IEEE802154_ADDR_LONG = 0x3, /* 64-bit address + PANid */
+};
+
+/* address length, octets */
+#define IEEE802154_ADDR_LEN	8
+
+struct ieee802154_addr {
+	int addr_type;
+	u16 pan_id;
+	union {
+		u8 hwaddr[IEEE802154_ADDR_LEN];
+		u16 short_addr;
+	};
+};
+
+#define IEEE802154_PANID_BROADCAST	0xffff
+#define IEEE802154_ADDR_BROADCAST	0xffff
+#define IEEE802154_ADDR_UNDEF		0xfffe
+
+struct sockaddr_ieee802154 {
+	sa_family_t family; /* AF_IEEE802154 */
+	struct ieee802154_addr addr;
+};
+
+/* master device */
+#define IEEE802154_SIOC_ADD_SLAVE		(SIOCDEVPRIVATE + 0)
+
+#endif
diff --git a/include/net/ieee802154/mac_def.h b/include/net/ieee802154/mac_def.h
new file mode 100644
index 0000000..0d92393
--- /dev/null
+++ b/include/net/ieee802154/mac_def.h
@@ -0,0 +1,158 @@
+/*
+ * IEEE802.15.4-2003 specification
+ *
+ * Copyright (C) 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:
+ * Pavel Smolenskiy <pavel.smolenskiy@gmail.com>
+ * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
+ * Maxim Osipov <maxim.osipov@siemens.com>
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ */
+
+#ifndef IEEE802154_MAC_DEF_H
+#define IEEE802154_MAC_DEF_H
+
+#define IEEE802154_FC_TYPE_BEACON	0x0	/* Frame is beacon */
+#define	IEEE802154_FC_TYPE_DATA		0x1	/* Frame is data */
+#define IEEE802154_FC_TYPE_ACK		0x2	/* Frame is acknowledgment */
+#define IEEE802154_FC_TYPE_MAC_CMD	0x3	/* Frame is MAC command */
+
+#define IEEE802154_FC_TYPE_SHIFT		0
+#define IEEE802154_FC_TYPE_MASK		((1 << 3) - 1)
+#define IEEE802154_FC_TYPE(x)		((x & IEEE802154_FC_TYPE_MASK) >> IEEE802154_FC_TYPE_SHIFT)
+#define IEEE802154_FC_SET_TYPE(v, x)	do {v = (((v) & ~IEEE802154_FC_TYPE_MASK) | \
+						(((x) << IEEE802154_FC_TYPE_SHIFT) \
+						& IEEE802154_FC_TYPE_MASK)); } while (0)
+
+#define IEEE802154_FC_SECEN		(1 << 3)
+#define IEEE802154_FC_FRPEND		(1 << 4)
+#define IEEE802154_FC_ACK_REQ		(1 << 5)
+#define IEEE802154_FC_INTRA_PAN		(1 << 6)
+
+#define IEEE802154_FC_SAMODE_SHIFT	14
+#define IEEE802154_FC_SAMODE_MASK	(3 << IEEE802154_FC_SAMODE_SHIFT)
+#define IEEE802154_FC_DAMODE_SHIFT	10
+#define IEEE802154_FC_DAMODE_MASK	(3 << IEEE802154_FC_DAMODE_SHIFT)
+
+#define IEEE802154_FC_SAMODE(x)		\
+		(((x) & IEEE802154_FC_SAMODE_MASK) >> IEEE802154_FC_SAMODE_SHIFT)
+
+#define IEEE802154_FC_DAMODE(x)		\
+		(((x) & IEEE802154_FC_DAMODE_MASK) >> IEEE802154_FC_DAMODE_SHIFT)
+
+
+/* MAC's Command Frames Identifiers */
+#define IEEE802154_CMD_ASSOCIATION_REQ		0x01
+#define IEEE802154_CMD_ASSOCIATION_RESP		0x02
+#define IEEE802154_CMD_DISASSOCIATION_NOTIFY	0x03
+#define IEEE802154_CMD_DATA_REQ			0x04
+#define IEEE802154_CMD_PANID_CONFLICT_NOTIFY	0x05
+#define IEEE802154_CMD_ORPHAN_NOTIFY		0x06
+#define IEEE802154_CMD_BEACON_REQ		0x07
+#define IEEE802154_CMD_COORD_REALIGN_NOTIFY	0x08
+#define IEEE802154_CMD_GTS_REQ			0x09
+
+/*
+ * The return values of MAC operations
+ */
+enum {
+	/*
+	 * The requested operation was completed successfully. For a transmission
+	 * request, this value indicates a successful transmission.
+	 */
+	IEEE802154_SUCCESS = 0x0,
+
+	/* The beacon was lost following a synchronization request. */
+	IEEE802154_BEACON_LOSS = 0xe0,
+	/*
+	 * A transmission could not take place due to activity on the
+	 * channel, i.e., the CSMA-CA mechanism has failed.
+	 */
+	IEEE802154_CHNL_ACCESS_FAIL = 0xe1,
+	/* The GTS request has been denied by the PAN coordinator. */
+	IEEE802154_DENINED = 0xe2,
+	/* The attempt to disable the transceiver has failed. */
+	IEEE802154_DISABLE_TRX_FAIL = 0xe3,
+	/*
+	 * The received frame induces a failed security check according to
+	 * the security suite.
+	 */
+	IEEE802154_FAILED_SECURITY_CHECK = 0xe4,
+	/*
+	 * The frame resulting from secure processing has a length that is
+	 * greater than aMACMaxFrameSize.
+	 */
+	IEEE802154_FRAME_TOO_LONG = 0xe5,
+	/*
+	 * The requested GTS transmission failed because the specified GTS
+	 * either did not have a transmit GTS direction or was not defined.
+	 */
+	IEEE802154_INVALID_GTS = 0xe6,
+	/*
+	 * A request to purge an MSDU from the transaction queue was made using
+	 * an MSDU handle that was not found in the transaction table.
+	 */
+	IEEE802154_INVALID_HANDLE = 0xe7,
+	/* A parameter in the primitive is out of the valid range.*/
+	IEEE802154_INVALID_PARAMETER = 0xe8,
+	/* No acknowledgment was received after aMaxFrameRetries. */
+	IEEE802154_NO_ACK = 0xe9,
+	/* A scan operation failed to find any network beacons.*/
+	IEEE802154_NO_BEACON = 0xea,
+	/* No response data were available following a request. */
+	IEEE802154_NO_DATA = 0xeb,
+	/* The operation failed because a short address was not allocated. */
+	IEEE802154_NO_SHORT_ADDRESS = 0xec,
+	/*
+	 * A receiver enable request was unsuccessful because it could not be
+	 * completed within the CAP.
+	 */
+	IEEE802154_OUT_OF_CAP = 0xed,
+	/*
+	 * A PAN identifier conflict has been detected and communicated to the
+	 * PAN coordinator.
+	 */
+	IEEE802154_PANID_CONFLICT = 0xee,
+	/* A coordinator realignment command has been received. */
+	IEEE802154_REALIGMENT = 0xef,
+	/* The transaction has expired and its information discarded. */
+	IEEE802154_TRANSACTION_EXPIRED = 0xf0,
+	/* There is no capacity to store the transaction. */
+	IEEE802154_TRANSACTION_OVERFLOW = 0xf1,
+	/*
+	 * The transceiver was in the transmitter enabled state when the
+	 * receiver was requested to be enabled.
+	 */
+	IEEE802154_TX_ACTIVE = 0xf2,
+	/* The appropriate key is not available in the ACL. */
+	IEEE802154_UNAVAILABLE_KEY = 0xf3,
+	/*
+	 * A SET/GET request was issued with the identifier of a PIB attribute
+	 * that is not supported.
+	 */
+	IEEE802154_UNSUPPORTED_ATTR = 0xf4,
+	/*
+	 * A request to perform a scan operation failed because the MLME was
+	 * in the process of performing a previously initiated scan operation.
+	 */
+	IEEE802154_SCAN_IN_PROGRESS = 0xfc,
+};
+
+
+#endif
+
+
diff --git a/include/net/ieee802154/netdevice.h b/include/net/ieee802154/netdevice.h
new file mode 100644
index 0000000..42b66fb
--- /dev/null
+++ b/include/net/ieee802154/netdevice.h
@@ -0,0 +1,84 @@
+/*
+ * An interface between IEEE802.15.4 device and rest of the kernel.
+ *
+ * Copyright (C) 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:
+ * Pavel Smolenskiy <pavel.smolenskiy@gmail.com>
+ * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
+ * Maxim Osipov <maxim.osipov@siemens.com>
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ */
+
+#ifndef IEEE802154_NETDEVICE_H
+#define IEEE802154_NETDEVICE_H
+
+/*
+ * A control block of skb passed between the ARPHRD_IEEE802154 device
+ * and other stack parts.
+ */
+struct ieee802154_mac_cb {
+	u8 lqi;
+	struct ieee802154_addr sa;
+	struct ieee802154_addr da;
+	u8 flags;
+	u8 seq;
+};
+#define MAC_CB(skb)	((struct ieee802154_mac_cb *)(skb)->cb)
+
+#define MAC_CB_FLAG_TYPEMASK		((1 << 3) - 1)
+
+#define MAC_CB_FLAG_ACKREQ		(1 << 3)
+#define MAC_CB_FLAG_SECEN		(1 << 4)
+#define MAC_CB_FLAG_INTRAPAN		(1 << 5)
+
+#define MAC_CB_IS_ACKREQ(skb)		(MAC_CB(skb)->flags & MAC_CB_FLAG_ACKREQ)
+#define MAC_CB_IS_SECEN(skb)		(MAC_CB(skb)->flags & MAC_CB_FLAG_SECEN)
+#define MAC_CB_IS_INTRAPAN(skb)		(MAC_CB(skb)->flags & MAC_CB_FLAG_INTRAPAN)
+#define MAC_CB_TYPE(skb)		(MAC_CB(skb)->flags & MAC_CB_FLAG_TYPEMASK)
+
+#define IEEE802154_MAC_SCAN_ED		0
+#define IEEE802154_MAC_SCAN_ACTIVE	1
+#define IEEE802154_MAC_SCAN_PASSIVE	2
+#define IEEE802154_MAC_SCAN_ORPHAN	3
+
+/*
+ * This should be located at net_device->ml_priv
+ */
+struct ieee802154_mlme_ops {
+	int (*assoc_req)(struct net_device *dev, struct ieee802154_addr *addr, u8 channel, u8 cap);
+	int (*assoc_resp)(struct net_device *dev, struct ieee802154_addr *addr, u16 short_addr, u8 status);
+	int (*disassoc_req)(struct net_device *dev, struct ieee802154_addr *addr, u8 reason);
+	int (*start_req)(struct net_device *dev, struct ieee802154_addr *addr, u8 channel,
+			     u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx,
+			     u8 coord_realign);
+	int (*scan_req)(struct net_device *dev, u8 type, u32 channels, u8 duration);
+
+	/*
+	 * FIXME: these should become the part of PIB/MIB interface.
+	 * However we still don't have IB interface of any kind
+	 */
+	u16 (*get_pan_id)(struct net_device *dev);
+	u16 (*get_short_addr)(struct net_device *dev);
+	u8 (*get_dsn)(struct net_device *dev);
+	u8 (*get_bsn)(struct net_device *dev);
+};
+
+#define IEEE802154_MLME_OPS(dev)	((struct ieee802154_mlme_ops *) dev->ml_priv)
+
+#endif
+
+
diff --git a/net/Kconfig b/net/Kconfig
index c19f549..7051b97 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -179,6 +179,7 @@ source "net/lapb/Kconfig"
 source "net/econet/Kconfig"
 source "net/wanrouter/Kconfig"
 source "net/phonet/Kconfig"
+source "net/ieee802154/Kconfig"
 source "net/sched/Kconfig"
 source "net/dcb/Kconfig"
 
diff --git a/net/Makefile b/net/Makefile
index 9e00a55..ba324ae 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -60,6 +60,7 @@ obj-$(CONFIG_NET_9P)		+= 9p/
 ifneq ($(CONFIG_DCB),)
 obj-y				+= dcb/
 endif
+obj-y				+= ieee802154/
 
 ifeq ($(CONFIG_NET),y)
 obj-$(CONFIG_SYSCTL)		+= sysctl_net.o
diff --git a/net/ieee802154/Kconfig b/net/ieee802154/Kconfig
new file mode 100644
index 0000000..f540cd1
--- /dev/null
+++ b/net/ieee802154/Kconfig
@@ -0,0 +1,12 @@
+config IEEE802154
+	tristate "IEEE Std 802.15.4 Low-Rate Wireless Personal Area Networks support (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	---help---
+	  IEEE Std 802.15.4 defines a low data rate, low power and low complexity
+	  short range wireless personal area networks. It was designed to
+	  organise networks of sensors, switches, etc automation devices. Maximum
+	  allowed data rate is 250 kb/s and typical personal operating space
+	  around 10m.
+
+	  Say Y here to compile LR-WPAN support into the kernel or say M to
+	  compile it as modules.
diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile
new file mode 100644
index 0000000..cb88054
--- /dev/null
+++ b/net/ieee802154/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_IEEE802154) +=	af_802154.o
+af_802154-objs		:= af_ieee802154.o raw.o dgram.o
+
+EXTRA_CFLAGS += -Wall -DDEBUG
diff --git a/net/ieee802154/af802154.h b/net/ieee802154/af802154.h
new file mode 100644
index 0000000..3a96fb9
--- /dev/null
+++ b/net/ieee802154/af802154.h
@@ -0,0 +1,35 @@
+/*
+ * Internal interfaces for ieee 802.15.4 address family.
+ *
+ * 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:
+ * Sergey Lapin <sergey.lapin@siemens.com>
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ */
+
+#ifndef AF802154_H
+#define AF802154_H
+
+struct sk_buff;
+struct net_devce;
+extern struct proto ieee802154_raw_prot;
+extern struct proto ieee802154_dgram_prot;
+void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb);
+int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb);
+struct net_device *ieee802154_get_dev(struct net *net, struct ieee802154_addr *addr);
+
+#endif
diff --git a/net/ieee802154/af_ieee802154.c b/net/ieee802154/af_ieee802154.c
new file mode 100644
index 0000000..9e8284d
--- /dev/null
+++ b/net/ieee802154/af_ieee802154.c
@@ -0,0 +1,356 @@
+/*
+ * IEEE802154.4 socket 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 <sergey.lapin@siemens.com>
+ * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
+ */
+
+#include <linux/net.h>
+#include <linux/capability.h>
+#include <linux/module.h>
+#include <linux/if_arp.h>
+#include <linux/if.h>
+#include <linux/termios.h>	/* For TIOCOUTQ/INQ */
+#include <linux/list.h>
+#include <net/datalink.h>
+#include <net/psnap.h>
+#include <net/sock.h>
+#include <net/tcp_states.h>
+#include <net/route.h>
+
+#include <net/ieee802154/af_ieee802154.h>
+#include <net/ieee802154/netdevice.h>
+
+#include "af802154.h"
+
+#define DBG_DUMP(data, len) { \
+	int i; \
+	pr_debug("file %s: function: %s: data: len %d:\n", __FILE__, __func__, len); \
+	for (i = 0; i < len; i++) {\
+		pr_debug("%02x: %02x\n", i, (data)[i]); \
+	} \
+}
+
+/*
+ * Utility function for families
+ */
+struct net_device *ieee802154_get_dev(struct net *net, struct ieee802154_addr *addr)
+{
+	struct net_device *dev = NULL;
+
+	switch (addr->addr_type) {
+	case IEEE802154_ADDR_LONG:
+		rtnl_lock();
+		dev = dev_getbyhwaddr(net, ARPHRD_IEEE802154, addr->hwaddr);
+		if (dev)
+			dev_hold(dev);
+		rtnl_unlock();
+		break;
+	case IEEE802154_ADDR_SHORT:
+		if (addr->pan_id != 0xffff && addr->short_addr != IEEE802154_ADDR_UNDEF && addr->short_addr != 0xffff) {
+			struct net_device *tmp;
+
+			rtnl_lock();
+
+			for_each_netdev(net, tmp) {
+				if (tmp->type == ARPHRD_IEEE802154) {
+					if (IEEE802154_MLME_OPS(tmp)->get_pan_id(tmp) == addr->pan_id
+					  && IEEE802154_MLME_OPS(tmp)->get_short_addr(tmp) == addr->short_addr) {
+						dev = tmp;
+						dev_hold(dev);
+						break;
+					}
+				}
+			}
+
+			rtnl_unlock();
+		}
+		break;
+	default:
+		pr_warning("Unsupported ieee802154 address type: %d\n", addr->addr_type);
+		break;
+	}
+
+	return dev;
+}
+
+static int ieee802154_sock_release(struct socket *sock)
+{
+	struct sock *sk = sock->sk;
+
+	if (sk) {
+		sock->sk = NULL;
+		sk->sk_prot->close(sk, 0);
+	}
+	return 0;
+}
+static int ieee802154_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len)
+{
+	struct sock *sk = sock->sk;
+
+	return sk->sk_prot->sendmsg(iocb, sk, msg, len);
+}
+
+static int ieee802154_sock_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
+{
+	struct sock *sk = sock->sk;
+
+	if (sk->sk_prot->bind)
+		return sk->sk_prot->bind(sk, uaddr, addr_len);
+
+	return sock_no_bind(sock, uaddr, addr_len);
+}
+
+static int ieee802154_sock_connect(struct socket *sock, struct sockaddr *uaddr,
+			int addr_len, int flags)
+{
+	struct sock *sk = sock->sk;
+
+	if (uaddr->sa_family == AF_UNSPEC)
+		return sk->sk_prot->disconnect(sk, flags);
+
+	return sk->sk_prot->connect(sk, uaddr, addr_len);
+}
+
+static int ieee802154_dev_ioctl(struct sock *sk, struct ifreq __user *arg, unsigned int cmd)
+{
+	struct ifreq ifr;
+	int ret = -EINVAL;
+	struct net_device *dev;
+
+	if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
+		return -EFAULT;
+
+	ifr.ifr_name[IFNAMSIZ-1] = 0;
+
+	dev_load(sock_net(sk), ifr.ifr_name);
+	dev = dev_get_by_name(sock_net(sk), ifr.ifr_name);
+	if (dev->type == ARPHRD_IEEE802154 || dev->type == ARPHRD_IEEE802154_PHY)
+		ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, cmd);
+
+	if (!ret && copy_to_user(arg, &ifr, sizeof(struct ifreq)))
+		ret = -EFAULT;
+	dev_put(dev);
+
+	return ret;
+}
+
+static int ieee802154_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+	struct sock *sk = sock->sk;
+
+	switch (cmd) {
+	case SIOCGSTAMP:
+		return sock_get_timestamp(sk, (struct timeval __user *)arg);
+	case SIOCGSTAMPNS:
+		return sock_get_timestampns(sk, (struct timespec __user *)arg);
+	case SIOCGIFADDR:
+	case SIOCSIFADDR:
+		return ieee802154_dev_ioctl(sk, (struct ifreq __user *)arg, cmd);
+	default:
+		if (!sk->sk_prot->ioctl)
+			return -ENOIOCTLCMD;
+		return sk->sk_prot->ioctl(sk, cmd, arg);
+	}
+}
+
+static const struct proto_ops ieee802154_raw_ops = {
+	.family		   = PF_IEEE802154,
+	.owner		   = THIS_MODULE,
+	.release	   = ieee802154_sock_release,
+	.bind		   = ieee802154_sock_bind,
+	.connect	   = ieee802154_sock_connect,
+	.socketpair	   = sock_no_socketpair,
+	.accept		   = sock_no_accept,
+	.getname	   = sock_no_getname,
+	.poll		   = datagram_poll,
+	.ioctl		   = ieee802154_sock_ioctl,
+	.listen		   = sock_no_listen,
+	.shutdown	   = sock_no_shutdown,
+	.setsockopt	   = sock_common_setsockopt,
+	.getsockopt	   = sock_common_getsockopt,
+	.sendmsg	   = ieee802154_sock_sendmsg,
+	.recvmsg	   = sock_common_recvmsg,
+	.mmap		   = sock_no_mmap,
+	.sendpage	   = sock_no_sendpage,
+#ifdef CONFIG_COMPAT
+	.compat_setsockopt = compat_sock_common_setsockopt,
+	.compat_getsockopt = compat_sock_common_getsockopt,
+#endif
+};
+
+static const struct proto_ops ieee802154_dgram_ops = {
+	.family		   = PF_IEEE802154,
+	.owner		   = THIS_MODULE,
+	.release	   = ieee802154_sock_release,
+	.bind		   = ieee802154_sock_bind,
+	.connect	   = ieee802154_sock_connect,
+	.socketpair	   = sock_no_socketpair,
+	.accept		   = sock_no_accept,
+	.getname	   = sock_no_getname,
+	.poll		   = datagram_poll,
+	.ioctl		   = ieee802154_sock_ioctl,
+	.listen		   = sock_no_listen,
+	.shutdown	   = sock_no_shutdown,
+	.setsockopt	   = sock_common_setsockopt,
+	.getsockopt	   = sock_common_getsockopt,
+	.sendmsg	   = ieee802154_sock_sendmsg,
+	.recvmsg	   = sock_common_recvmsg,
+	.mmap		   = sock_no_mmap,
+	.sendpage	   = sock_no_sendpage,
+#ifdef CONFIG_COMPAT
+	.compat_setsockopt = compat_sock_common_setsockopt,
+	.compat_getsockopt = compat_sock_common_getsockopt,
+#endif
+};
+
+
+/*
+ * Create a socket. Initialise the socket, blank the addresses
+ * set the state.
+ */
+static int ieee802154_create(struct net *net, struct socket *sock, int protocol)
+{
+	struct sock *sk;
+	int rc;
+	struct proto *proto;
+	const struct proto_ops *ops;
+
+	/* FIXME: init_net */
+	if (net != &init_net)
+		return -EAFNOSUPPORT;
+
+	switch (sock->type) {
+	case SOCK_RAW:
+		proto = &ieee802154_raw_prot;
+		ops = &ieee802154_raw_ops;
+		break;
+	case SOCK_DGRAM:
+		proto = &ieee802154_dgram_prot;
+		ops = &ieee802154_dgram_ops;
+		break;
+	default:
+		rc = -ESOCKTNOSUPPORT;
+		goto out;
+	}
+
+	rc = -ENOMEM;
+	sk = sk_alloc(net, PF_IEEE802154, GFP_KERNEL, proto);
+	if (!sk)
+		goto out;
+	rc = 0;
+
+	sock->ops = ops;
+
+	sock_init_data(sock, sk);
+	/* FIXME: sk->sk_destruct */
+	sk->sk_family = PF_IEEE802154;
+
+	/* Checksums on by default */
+	sock_set_flag(sk, SOCK_ZAPPED);
+
+	if (sk->sk_prot->hash)
+		sk->sk_prot->hash(sk);
+
+	if (sk->sk_prot->init) {
+		rc = sk->sk_prot->init(sk);
+		if (rc)
+			sk_common_release(sk);
+	}
+out:
+	return rc;
+}
+
+static struct net_proto_family ieee802154_family_ops = {
+	.family		= PF_IEEE802154,
+	.create		= ieee802154_create,
+	.owner		= THIS_MODULE,
+};
+
+static int ieee802154_rcv(struct sk_buff *skb, struct net_device *dev,
+	struct packet_type *pt, struct net_device *orig_dev)
+{
+	DBG_DUMP(skb->data, skb->len);
+	if (!netif_running(dev))
+		return -ENODEV;
+	pr_debug("got frame, type %d, dev %p\n", dev->type, dev);
+	/* FIXME: init_net */
+	if (!net_eq(dev_net(dev), &init_net))
+		goto drop;
+
+	ieee802154_raw_deliver(dev, skb);
+
+	if (dev->type != ARPHRD_IEEE802154)
+		goto drop;
+
+	if (skb->pkt_type != PACKET_OTHERHOST)
+		return ieee802154_dgram_deliver(dev, skb);
+
+drop:
+	kfree_skb(skb);
+	return NET_RX_DROP;
+}
+
+
+static struct packet_type ieee802154_packet_type = {
+	.type = __constant_htons(ETH_P_IEEE802154),
+	.func = ieee802154_rcv,
+};
+
+static int __init af_ieee802154_init(void)
+{
+	int rc = -EINVAL;
+
+	rc = proto_register(&ieee802154_raw_prot, 1);
+	if (rc)
+		goto out;
+
+	rc = proto_register(&ieee802154_dgram_prot, 1);
+	if (rc)
+		goto err_dgram;
+
+	/* Tell SOCKET that we are alive */
+	rc = sock_register(&ieee802154_family_ops);
+	if (rc)
+		goto err_sock;
+	dev_add_pack(&ieee802154_packet_type);
+
+	rc = 0;
+	goto out;
+
+err_sock:
+	proto_unregister(&ieee802154_dgram_prot);
+err_dgram:
+	proto_unregister(&ieee802154_raw_prot);
+out:
+	return rc;
+}
+static void af_ieee802154_remove(void)
+{
+	dev_remove_pack(&ieee802154_packet_type);
+	sock_unregister(PF_IEEE802154);
+	proto_unregister(&ieee802154_dgram_prot);
+	proto_unregister(&ieee802154_raw_prot);
+}
+
+module_init(af_ieee802154_init);
+module_exit(af_ieee802154_remove);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_NETPROTO(PF_IEEE802154);
diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c
new file mode 100644
index 0000000..761709e
--- /dev/null
+++ b/net/ieee802154/dgram.c
@@ -0,0 +1,373 @@
+/*
+ * ZigBee socket 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 <sergey.lapin@siemens.com>
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ */
+
+#include <linux/net.h>
+#include <linux/module.h>
+#include <linux/if_arp.h>
+#include <linux/list.h>
+#include <net/sock.h>
+#include <net/ieee802154/af_ieee802154.h>
+#include <net/ieee802154/mac_def.h>
+#include <net/ieee802154/netdevice.h>
+
+#include <asm/ioctls.h>
+
+#include "af802154.h"
+
+static HLIST_HEAD(dgram_head);
+static DEFINE_RWLOCK(dgram_lock);
+
+struct dgram_sock {
+	struct sock sk;
+
+	int bound;
+	struct ieee802154_addr src_addr;
+	struct ieee802154_addr dst_addr;
+};
+
+static inline struct dgram_sock *dgram_sk(const struct sock *sk)
+{
+	return (struct dgram_sock *)sk;
+}
+
+
+static void dgram_hash(struct sock *sk)
+{
+	write_lock_bh(&dgram_lock);
+	sk_add_node(sk, &dgram_head);
+	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
+	write_unlock_bh(&dgram_lock);
+}
+
+static void dgram_unhash(struct sock *sk)
+{
+	write_lock_bh(&dgram_lock);
+	if (sk_del_node_init(sk))
+		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
+	write_unlock_bh(&dgram_lock);
+}
+
+static int dgram_init(struct sock *sk)
+{
+	struct dgram_sock *ro = dgram_sk(sk);
+
+	ro->dst_addr.addr_type = IEEE802154_ADDR_LONG;
+	ro->dst_addr.pan_id = 0xffff;
+	memset(&ro->dst_addr.hwaddr, 0xff, sizeof(ro->dst_addr.hwaddr));
+	return 0;
+}
+
+static void dgram_close(struct sock *sk, long timeout)
+{
+	sk_common_release(sk);
+}
+
+static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len)
+{
+	struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr;
+	struct dgram_sock *ro = dgram_sk(sk);
+	int err = 0;
+	struct net_device *dev;
+
+	ro->bound = 0;
+
+	if (len < sizeof(*addr))
+		return -EINVAL;
+
+	if (addr->family != AF_IEEE802154)
+		return -EINVAL;
+
+	lock_sock(sk);
+
+	dev = ieee802154_get_dev(sock_net(sk), &addr->addr);
+	if (!dev) {
+		err = -ENODEV;
+		goto out;
+	}
+
+	if (dev->type != ARPHRD_IEEE802154) {
+		err = -ENODEV;
+		goto out_put;
+	}
+
+	memcpy(&ro->src_addr, &addr->addr, sizeof(struct ieee802154_addr));
+
+	ro->bound = 1;
+out_put:
+	dev_put(dev);
+out:
+	release_sock(sk);
+
+	return err;
+}
+
+static int dgram_ioctl(struct sock *sk, int cmd, unsigned long arg)
+{
+	switch (cmd) {
+	case SIOCOUTQ:
+	{
+		int amount = atomic_read(&sk->sk_wmem_alloc);
+		return put_user(amount, (int __user *)arg);
+	}
+
+	case SIOCINQ:
+	{
+		struct sk_buff *skb;
+		unsigned long amount;
+
+		amount = 0;
+		spin_lock_bh(&sk->sk_receive_queue.lock);
+		skb = skb_peek(&sk->sk_receive_queue);
+		if (skb != NULL) {
+			/*
+			 * We will only return the amount
+			 * of this packet since that is all
+			 * that will be read.
+			 */
+			/* FIXME: parse the header for more correct value */
+			amount = skb->len - (3+8+8);
+		}
+		spin_unlock_bh(&sk->sk_receive_queue.lock);
+		return put_user(amount, (int __user *)arg);
+	}
+
+	}
+	return -ENOIOCTLCMD;
+}
+
+/* FIXME: autobind */
+static int dgram_connect(struct sock *sk, struct sockaddr *uaddr,
+			int len)
+{
+	struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr;
+	struct dgram_sock *ro = dgram_sk(sk);
+	int err = 0;
+
+	if (len < sizeof(*addr))
+		return -EINVAL;
+
+	if (addr->family != AF_IEEE802154)
+		return -EINVAL;
+
+	lock_sock(sk);
+
+	if (!ro->bound) {
+		err = -ENETUNREACH;
+		goto out;
+	}
+
+	memcpy(&ro->dst_addr, &addr->addr, sizeof(struct ieee802154_addr));
+
+out:
+	release_sock(sk);
+	return err;
+}
+
+static int dgram_disconnect(struct sock *sk, int flags)
+{
+	struct dgram_sock *ro = dgram_sk(sk);
+
+	lock_sock(sk);
+
+	ro->dst_addr.addr_type = IEEE802154_ADDR_LONG;
+	memset(&ro->dst_addr.hwaddr, 0xff, sizeof(ro->dst_addr.hwaddr));
+
+	release_sock(sk);
+
+	return 0;
+}
+
+static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+		       size_t size)
+{
+	struct net_device *dev;
+	unsigned mtu;
+	struct sk_buff *skb;
+	struct dgram_sock *ro = dgram_sk(sk);
+	int err;
+
+	if (msg->msg_flags & MSG_OOB) {
+		pr_debug("msg->msg_flags = 0x%x\n", msg->msg_flags);
+		return -EOPNOTSUPP;
+	}
+
+	if (!ro->bound)
+		dev = dev_getfirstbyhwtype(sock_net(sk), ARPHRD_IEEE802154);
+	else
+		dev = ieee802154_get_dev(sock_net(sk), &ro->src_addr);
+
+	if (!dev) {
+		pr_debug("no dev\n");
+		return -ENXIO;
+	}
+	mtu = dev->mtu;
+	pr_debug("name = %s, mtu = %u\n", dev->name, mtu);
+
+	skb = sock_alloc_send_skb(sk, LL_ALLOCATED_SPACE(dev) + size, msg->msg_flags & MSG_DONTWAIT,
+				  &err);
+	if (!skb) {
+		dev_put(dev);
+		return err;
+	}
+	skb_reserve(skb, LL_RESERVED_SPACE(dev));
+
+	skb_reset_network_header(skb);
+
+	MAC_CB(skb)->flags = IEEE802154_FC_TYPE_DATA | MAC_CB_FLAG_ACKREQ;
+	MAC_CB(skb)->seq = IEEE802154_MLME_OPS(dev)->get_dsn(dev);
+	err = dev_hard_header(skb, dev, ETH_P_IEEE802154, &ro->dst_addr, ro->bound ? &ro->src_addr : NULL, size);
+	if (err < 0) {
+		kfree_skb(skb);
+		dev_put(dev);
+		return err;
+	}
+
+	skb_reset_mac_header(skb);
+
+	err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
+	if (err < 0) {
+		kfree_skb(skb);
+		dev_put(dev);
+		return err;
+	}
+
+	if (size > mtu) {
+		pr_debug("size = %u, mtu = %u\n", size, mtu);
+		return -EINVAL;
+	}
+
+	skb->dev = dev;
+	skb->sk  = sk;
+	skb->protocol = htons(ETH_P_IEEE802154);
+
+	err = dev_queue_xmit(skb);
+
+	dev_put(dev);
+
+	if (err)
+		return err;
+
+	return size;
+}
+
+static int dgram_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+		       size_t len, int noblock, int flags, int *addr_len)
+{
+	size_t copied = 0;
+	int err = -EOPNOTSUPP;
+	struct sk_buff *skb;
+
+	skb = skb_recv_datagram(sk, flags, noblock, &err);
+	if (!skb)
+		goto out;
+
+	copied = skb->len;
+	if (len < copied) {
+		msg->msg_flags |= MSG_TRUNC;
+		copied = len;
+	}
+
+	/* FIXME: skip headers if necessary ?! */
+	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+	if (err)
+		goto done;
+
+	sock_recv_timestamp(msg, sk, skb);
+
+	if (flags & MSG_TRUNC)
+		copied = skb->len;
+done:
+	skb_free_datagram(sk, skb);
+out:
+	if (err)
+		return err;
+	return copied;
+}
+
+static int dgram_rcv_skb(struct sock *sk, struct sk_buff *skb)
+{
+	if (sock_queue_rcv_skb(sk, skb) < 0) {
+		atomic_inc(&sk->sk_drops);
+		kfree_skb(skb);
+		return NET_RX_DROP;
+	}
+
+	return NET_RX_SUCCESS;
+}
+
+int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb)
+{
+	struct sock *sk, *prev = NULL;
+	struct hlist_node *node;
+	int ret = NET_RX_SUCCESS;
+
+	/* Data frame processing */
+	BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+	read_lock(&dgram_lock);
+	sk_for_each(sk, node, &dgram_head) {
+		struct dgram_sock *ro = dgram_sk(sk);
+		if (!ro->bound ||
+		  (ro->src_addr.addr_type == IEEE802154_ADDR_LONG &&
+		     !memcmp(ro->src_addr.hwaddr, dev->dev_addr, IEEE802154_ADDR_LEN)) ||
+		  (ro->src_addr.addr_type == IEEE802154_ADDR_SHORT &&
+		     IEEE802154_MLME_OPS(dev)->get_pan_id(dev) == ro->src_addr.pan_id &&
+		     IEEE802154_MLME_OPS(dev)->get_short_addr(dev) == ro->src_addr.short_addr)) {
+			if (prev) {
+				struct sk_buff *clone;
+				clone = skb_clone(skb, GFP_ATOMIC);
+				if (clone)
+					dgram_rcv_skb(prev, clone);
+			}
+
+			prev = sk;
+		}
+	}
+
+	if (prev)
+		dgram_rcv_skb(prev, skb);
+	else {
+		kfree_skb(skb);
+		ret = NET_RX_DROP;
+	}
+	read_unlock(&dgram_lock);
+
+	return ret;
+}
+
+struct proto ieee802154_dgram_prot = {
+	.name		= "IEEE-802.15.4-MAC",
+	.owner		= THIS_MODULE,
+	.obj_size	= sizeof(struct dgram_sock),
+	.init		= dgram_init,
+	.close		= dgram_close,
+	.bind		= dgram_bind,
+	.sendmsg	= dgram_sendmsg,
+	.recvmsg	= dgram_recvmsg,
+	.hash		= dgram_hash,
+	.unhash		= dgram_unhash,
+	.connect	= dgram_connect,
+	.disconnect	= dgram_disconnect,
+	.ioctl		= dgram_ioctl,
+};
+
diff --git a/net/ieee802154/raw.c b/net/ieee802154/raw.c
new file mode 100644
index 0000000..678f196
--- /dev/null
+++ b/net/ieee802154/raw.c
@@ -0,0 +1,250 @@
+/*
+ * Raw IEEE 802.15.4 sockets
+ *
+ * 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 <sergey.lapin@siemens.com>
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ */
+
+#include <linux/net.h>
+#include <linux/module.h>
+#include <linux/if_arp.h>
+#include <linux/list.h>
+#include <net/sock.h>
+#include <net/ieee802154/af_ieee802154.h>
+
+#include "af802154.h"
+
+static HLIST_HEAD(raw_head);
+static DEFINE_RWLOCK(raw_lock);
+
+static void raw_hash(struct sock *sk)
+{
+	write_lock_bh(&raw_lock);
+	sk_add_node(sk, &raw_head);
+	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
+	write_unlock_bh(&raw_lock);
+}
+
+static void raw_unhash(struct sock *sk)
+{
+	write_lock_bh(&raw_lock);
+	if (sk_del_node_init(sk))
+		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
+	write_unlock_bh(&raw_lock);
+}
+
+static void raw_close(struct sock *sk, long timeout)
+{
+	sk_common_release(sk);
+}
+
+static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int len)
+{
+	struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr;
+	int err = 0;
+	struct net_device *dev = NULL;
+
+	if (len < sizeof(*addr))
+		return -EINVAL;
+
+	if (addr->family != AF_IEEE802154)
+		return -EINVAL;
+
+	lock_sock(sk);
+
+	dev = ieee802154_get_dev(sock_net(sk), &addr->addr);
+	if (!dev) {
+		err = -ENODEV;
+		goto out;
+	}
+
+	if (dev->type != ARPHRD_IEEE802154_PHY && dev->type != ARPHRD_IEEE802154) {
+		err = -ENODEV;
+		goto out_put;
+	}
+
+	sk->sk_bound_dev_if = dev->ifindex;
+	sk_dst_reset(sk);
+
+out_put:
+	dev_put(dev);
+out:
+	release_sock(sk);
+
+	return err;
+}
+
+static int raw_connect(struct sock *sk, struct sockaddr *uaddr,
+			int addr_len)
+{
+	return -ENOTSUPP;
+}
+
+static int raw_disconnect(struct sock *sk, int flags)
+{
+	return 0;
+}
+
+static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+		       size_t size)
+{
+	struct net_device *dev;
+	unsigned mtu;
+	struct sk_buff *skb;
+	int err;
+
+	if (msg->msg_flags & MSG_OOB) {
+		pr_debug("msg->msg_flags = 0x%x\n", msg->msg_flags);
+		return -EOPNOTSUPP;
+	}
+
+	lock_sock(sk);
+	if (!sk->sk_bound_dev_if)
+		dev = dev_getfirstbyhwtype(sock_net(sk), ARPHRD_IEEE802154_PHY);
+	else
+		dev = dev_get_by_index(sock_net(sk), sk->sk_bound_dev_if);
+	release_sock(sk);
+
+	if (!dev) {
+		pr_debug("no dev\n");
+		err = -ENXIO;
+		goto out;
+	}
+
+	mtu = dev->mtu;
+	pr_debug("name = %s, mtu = %u\n", dev->name, mtu);
+
+	if (size > mtu) {
+		pr_debug("size = %u, mtu = %u\n", size, mtu);
+		err = -EINVAL;
+		goto out_dev;
+	}
+
+	skb = sock_alloc_send_skb(sk, LL_ALLOCATED_SPACE(dev) + size, msg->msg_flags & MSG_DONTWAIT,
+				  &err);
+	if (!skb)
+		goto out_dev;
+
+	skb_reserve(skb, LL_RESERVED_SPACE(dev));
+
+	skb_reset_mac_header(skb);
+	skb_reset_network_header(skb);
+
+	err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
+	if (err < 0)
+		goto out_skb;
+
+	skb->dev = dev;
+	skb->sk  = sk;
+	skb->protocol = htons(ETH_P_IEEE802154);
+
+	err = dev_queue_xmit(skb);
+
+	dev_put(dev);
+
+	return size;
+
+out_skb:
+	kfree_skb(skb);
+out_dev:
+	dev_put(dev);
+out:
+	return err;
+}
+
+static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+		       size_t len, int noblock, int flags, int *addr_len)
+{
+	size_t copied = 0;
+	int err = -EOPNOTSUPP;
+	struct sk_buff *skb;
+
+	skb = skb_recv_datagram(sk, flags, noblock, &err);
+	if (!skb)
+		goto out;
+
+	copied = skb->len;
+	if (len < copied) {
+		msg->msg_flags |= MSG_TRUNC;
+		copied = len;
+	}
+
+	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+	if (err)
+		goto done;
+
+	sock_recv_timestamp(msg, sk, skb);
+
+	if (flags & MSG_TRUNC)
+		copied = skb->len;
+done:
+	skb_free_datagram(sk, skb);
+out:
+	if (err)
+		return err;
+	return copied;
+}
+
+static int raw_rcv_skb(struct sock *sk, struct sk_buff *skb)
+{
+	if (sock_queue_rcv_skb(sk, skb) < 0) {
+		atomic_inc(&sk->sk_drops);
+		kfree_skb(skb);
+		return NET_RX_DROP;
+	}
+
+	return NET_RX_SUCCESS;
+}
+
+
+void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb)
+{
+	struct sock *sk;
+	struct hlist_node *node;
+
+	read_lock(&raw_lock);
+	sk_for_each(sk, node, &raw_head) {
+		bh_lock_sock(sk);
+		if (!sk->sk_bound_dev_if || sk->sk_bound_dev_if == dev->ifindex) {
+
+			struct sk_buff *clone;
+
+			clone = skb_clone(skb, GFP_ATOMIC);
+			if (clone)
+				raw_rcv_skb(sk, clone);
+		}
+		bh_unlock_sock(sk);
+	}
+	read_unlock(&raw_lock);
+}
+
+struct proto ieee802154_raw_prot = {
+	.name		= "IEEE-802.15.4-RAW",
+	.owner		= THIS_MODULE,
+	.obj_size	= sizeof(struct sock),
+	.close		= raw_close,
+	.bind		= raw_bind,
+	.sendmsg	= raw_sendmsg,
+	.recvmsg	= raw_recvmsg,
+	.hash		= raw_hash,
+	.unhash		= raw_unhash,
+	.connect	= raw_connect,
+	.disconnect	= raw_disconnect,
+};
+
-- 
1.6.2.4


^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [PATCH 04/10] net: add NL802154 interface for configuration of 802.15.4 devices
@ 2009-06-01 14:54         ` Dmitry Eremin-Solenikov
  0 siblings, 0 replies; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-01 14:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: netdev, linux-wireless, slapin, maxim.osipov, dmitry.baryshkov,
	oliver.fendt, Dmitry Eremin-Solenikov

Add a netlink interface for configuration of IEEE 802.15.4 device. Also this
interface specifies events notification sent by devices towards higher layers.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Signed-off-by: Sergey Lapin <slapin@ossfans.org>
---
 include/net/ieee802154/nl802154.h |  165 +++++++++++++
 net/ieee802154/Makefile           |    3 +-
 net/ieee802154/netlink.c          |  485 +++++++++++++++++++++++++++++++++++++
 3 files changed, 652 insertions(+), 1 deletions(-)
 create mode 100644 include/net/ieee802154/nl802154.h
 create mode 100644 net/ieee802154/netlink.c

diff --git a/include/net/ieee802154/nl802154.h b/include/net/ieee802154/nl802154.h
new file mode 100644
index 0000000..27f6ee9
--- /dev/null
+++ b/include/net/ieee802154/nl802154.h
@@ -0,0 +1,165 @@
+/*
+ * ieee802154_nl.h
+ *
+ * Copyright (C) 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.
+ *
+ */
+
+#ifndef IEEE802154_NL_H
+#define IEEE802154_NL_H
+
+#define IEEE802154_NL_NAME "802.15.4 MAC"
+#define IEEE802154_MCAST_COORD_NAME "coordinator"
+#define IEEE802154_MCAST_BEACON_NAME "beacon"
+
+enum {
+	__IEEE802154_ATTR_INVALID,
+
+	IEEE802154_ATTR_DEV_NAME,
+	IEEE802154_ATTR_DEV_INDEX,
+
+	IEEE802154_ATTR_STATUS,
+
+	IEEE802154_ATTR_SHORT_ADDR,
+	IEEE802154_ATTR_HW_ADDR,
+	IEEE802154_ATTR_PAN_ID,
+
+	IEEE802154_ATTR_CHANNEL,
+
+	IEEE802154_ATTR_COORD_SHORT_ADDR,
+	IEEE802154_ATTR_COORD_HW_ADDR,
+	IEEE802154_ATTR_COORD_PAN_ID,
+
+	IEEE802154_ATTR_SRC_SHORT_ADDR,
+	IEEE802154_ATTR_SRC_HW_ADDR,
+	IEEE802154_ATTR_SRC_PAN_ID,
+
+	IEEE802154_ATTR_DEST_SHORT_ADDR,
+	IEEE802154_ATTR_DEST_HW_ADDR,
+	IEEE802154_ATTR_DEST_PAN_ID,
+
+	IEEE802154_ATTR_CAPABILITY, /* FIXME: this is association */
+	IEEE802154_ATTR_REASON,
+	IEEE802154_ATTR_SCAN_TYPE,
+	IEEE802154_ATTR_CHANNELS,
+	IEEE802154_ATTR_DURATION,
+	IEEE802154_ATTR_ED_LIST,
+	IEEE802154_ATTR_BCN_ORD,
+	IEEE802154_ATTR_SF_ORD,
+	IEEE802154_ATTR_PAN_COORD,
+	IEEE802154_ATTR_BAT_EXT,
+	IEEE802154_ATTR_COORD_REALIGN,
+	IEEE802154_ATTR_SEC,
+
+	__IEEE802154_ATTR_MAX,
+};
+
+#define IEEE802154_ATTR_MAX (__IEEE802154_ATTR_MAX - 1)
+#define NLA_HW_ADDR	NLA_U64
+#define NLA_GET_HW_ADDR(attr, addr) do { u64 _temp = nla_get_u64(attr); memcpy(addr, &_temp, 8); } while (0)
+#define NLA_PUT_HW_ADDR(msg, attr, addr) do { u64 _temp; memcpy(&_temp, addr, 8); NLA_PUT_U64(msg, attr, _temp); } while (0)
+
+#ifdef IEEE802154_NL_WANT_POLICY
+static struct nla_policy ieee802154_policy[IEEE802154_ATTR_MAX + 1] = {
+	[IEEE802154_ATTR_DEV_NAME] = { .type = NLA_STRING, },
+	[IEEE802154_ATTR_DEV_INDEX] = { .type = NLA_U32, },
+
+	[IEEE802154_ATTR_STATUS] = { .type = NLA_U8, },
+	[IEEE802154_ATTR_SHORT_ADDR] = { .type = NLA_U16, },
+	[IEEE802154_ATTR_HW_ADDR] = { .type = NLA_HW_ADDR, },
+	[IEEE802154_ATTR_PAN_ID] = { .type = NLA_U16, },
+	[IEEE802154_ATTR_CHANNEL] = { .type = NLA_U8, },
+	[IEEE802154_ATTR_COORD_SHORT_ADDR] = { .type = NLA_U16, },
+	[IEEE802154_ATTR_COORD_HW_ADDR] = { .type = NLA_HW_ADDR, },
+	[IEEE802154_ATTR_COORD_PAN_ID] = { .type = NLA_U16, },
+	[IEEE802154_ATTR_SRC_SHORT_ADDR] = { .type = NLA_U16, },
+	[IEEE802154_ATTR_SRC_HW_ADDR] = { .type = NLA_HW_ADDR, },
+	[IEEE802154_ATTR_SRC_PAN_ID] = { .type = NLA_U16, },
+	[IEEE802154_ATTR_DEST_SHORT_ADDR] = { .type = NLA_U16, },
+	[IEEE802154_ATTR_DEST_HW_ADDR] = { .type = NLA_HW_ADDR, },
+	[IEEE802154_ATTR_DEST_PAN_ID] = { .type = NLA_U16, },
+
+	[IEEE802154_ATTR_CAPABILITY] = { .type = NLA_U8, },
+	[IEEE802154_ATTR_REASON] = { .type = NLA_U8, },
+	[IEEE802154_ATTR_SCAN_TYPE] = { .type = NLA_U8, },
+	[IEEE802154_ATTR_CHANNELS] = { .type = NLA_U32, },
+	[IEEE802154_ATTR_DURATION] = { .type = NLA_U8, },
+#ifdef __KERNEL__
+	[IEEE802154_ATTR_ED_LIST] = { .len = 27 },
+#else
+	[IEEE802154_ATTR_ED_LIST] = { .minlen = 27, .maxlen = 27 },
+#endif
+};
+#endif
+
+/* commands */
+/* REQ should be responded with CONF
+ * and INDIC with RESP
+ */
+enum {
+	__IEEE802154_COMMAND_INVALID,
+
+	IEEE802154_ASSOCIATE_REQ,
+	IEEE802154_ASSOCIATE_CONF,
+	IEEE802154_DISASSOCIATE_REQ,
+	IEEE802154_DISASSOCIATE_CONF,
+	IEEE802154_GET_REQ,
+	IEEE802154_GET_CONF,
+/* 	IEEE802154_GTS_REQ, */
+/* 	IEEE802154_GTS_CONF, */
+	IEEE802154_RESET_REQ,
+	IEEE802154_RESET_CONF,
+/* 	IEEE802154_RX_ENABLE_REQ, */
+/* 	IEEE802154_RX_ENABLE_CONF, */
+	IEEE802154_SCAN_REQ,
+	IEEE802154_SCAN_CONF,
+	IEEE802154_SET_REQ,
+	IEEE802154_SET_CONF,
+	IEEE802154_START_REQ,
+	IEEE802154_START_CONF,
+	IEEE802154_SYNC_REQ,
+	IEEE802154_POLL_REQ,
+	IEEE802154_POLL_CONF,
+
+	IEEE802154_ASSOCIATE_INDIC,
+	IEEE802154_ASSOCIATE_RESP,
+	IEEE802154_DISASSOCIATE_INDIC,
+	IEEE802154_BEACON_NOTIFY_INDIC,
+/* 	IEEE802154_GTS_INDIC, */
+	IEEE802154_ORPHAN_INDIC,
+	IEEE802154_ORPHAN_RESP,
+	IEEE802154_COMM_STATUS_INDIC,
+	IEEE802154_SYNC_LOSS_INDIC,
+
+	__IEEE802154_CMD_MAX,
+};
+
+#define IEEE802154_CMD_MAX (__IEEE802154_CMD_MAX - 1)
+
+
+#ifdef __KERNEL__
+struct net_device;
+
+int ieee802154_nl_assoc_indic(struct net_device *dev, struct ieee802154_addr *addr, u8 cap);
+int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr, u8 status);
+int ieee802154_nl_disassoc_indic(struct net_device *dev, struct ieee802154_addr *addr, u8 reason);
+int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status);
+int ieee802154_nl_scan_confirm(struct net_device *dev, u8 status, u8 scan_type, u32 unscanned,
+		u8 *edl/*, struct list_head *pan_desc_list */);
+int ieee802154_nl_beacon_indic(struct net_device *dev, u16 panid, u16 coord_addr); /* TODO */
+#endif
+
+#endif
diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile
index cb88054..7c0b025 100644
--- a/net/ieee802154/Makefile
+++ b/net/ieee802154/Makefile
@@ -1,4 +1,5 @@
-obj-$(CONFIG_IEEE802154) +=	af_802154.o
+obj-$(CONFIG_IEEE802154) +=	nl802154.o af_802154.o
+nl802154-objs		:= netlink.o
 af_802154-objs		:= af_ieee802154.o raw.o dgram.o
 
 EXTRA_CFLAGS += -Wall -DDEBUG
diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c
new file mode 100644
index 0000000..eafdc4d
--- /dev/null
+++ b/net/ieee802154/netlink.c
@@ -0,0 +1,485 @@
+/*
+ * Netlink inteface for IEEE 802.15.4 stack
+ *
+ * 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 <sergey.lapin@siemens.com>
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/if_arp.h>
+#include <net/netlink.h>
+#include <net/genetlink.h>
+#include <linux/netdevice.h>
+#include <net/ieee802154/af_ieee802154.h>
+#define IEEE802154_NL_WANT_POLICY
+#include <net/ieee802154/nl802154.h>
+#include <net/ieee802154/netdevice.h>
+
+static unsigned int ieee802154_seq_num;
+
+static struct genl_family ieee802154_coordinator_family = {
+	.id		= GENL_ID_GENERATE,
+	.hdrsize	= 0,
+	.name		= IEEE802154_NL_NAME,
+	.version	= 1,
+	.maxattr	= IEEE802154_ATTR_MAX,
+};
+
+static struct genl_multicast_group ieee802154_coord_mcgrp = {
+	.name		= IEEE802154_MCAST_COORD_NAME,
+};
+
+static struct genl_multicast_group ieee802154_beacon_mcgrp = {
+	.name		= IEEE802154_MCAST_BEACON_NAME,
+};
+
+/* Requests to userspace */
+static struct sk_buff *ieee802154_nl_create(int flags, u8 req)
+{
+	void *hdr;
+	struct sk_buff *msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
+
+	if (!msg)
+		return NULL;
+
+	hdr = genlmsg_put(msg, 0, ieee802154_seq_num++, &ieee802154_coordinator_family, flags, req);
+	if (!hdr) {
+		nlmsg_free(msg);
+		return NULL;
+	}
+
+	return msg;
+}
+
+static int ieee802154_nl_finish(struct sk_buff *msg)
+{
+	void *hdr = genlmsg_data(NLMSG_DATA(msg->data)); /* XXX: nlh is right at the start of msg */
+
+	if (!genlmsg_end(msg, hdr))
+		goto out;
+
+	return genlmsg_multicast(msg, 0, ieee802154_coord_mcgrp.id, GFP_ATOMIC);
+out:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+static int ieee802154_nl_put_failure(struct sk_buff *msg)
+{
+	void *hdr = genlmsg_data(NLMSG_DATA(msg->data)); /* XXX: nlh is right at the start of msg */
+	genlmsg_cancel(msg, hdr);
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+int ieee802154_nl_assoc_indic(struct net_device *dev, struct ieee802154_addr *addr, u8 cap)
+{
+	struct sk_buff *msg;
+
+	pr_debug("%s\n", __func__);
+
+	msg = ieee802154_nl_create(/* flags*/ 0, IEEE802154_ASSOCIATE_INDIC);
+	if (!msg)
+		return -ENOBUFS;
+
+	NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
+	NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
+	NLA_PUT_HW_ADDR(msg, IEEE802154_ATTR_HW_ADDR, dev->dev_addr);
+
+	/* FIXME: check that we really received hw address */
+	NLA_PUT_HW_ADDR(msg, IEEE802154_ATTR_SRC_HW_ADDR, addr->hwaddr);
+
+	NLA_PUT_U8(msg, IEEE802154_ATTR_CAPABILITY, cap);
+
+	return ieee802154_nl_finish(msg);
+
+nla_put_failure:
+	return ieee802154_nl_put_failure(msg);
+}
+EXPORT_SYMBOL(ieee802154_nl_assoc_indic);
+
+int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr, u8 status)
+{
+	struct sk_buff *msg;
+
+	pr_debug("%s\n", __func__);
+
+	msg = ieee802154_nl_create(/* flags*/ 0, IEEE802154_ASSOCIATE_CONF);
+	if (!msg)
+		return -ENOBUFS;
+
+	NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
+	NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
+	NLA_PUT_HW_ADDR(msg, IEEE802154_ATTR_HW_ADDR, dev->dev_addr);
+
+	NLA_PUT_U16(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr);
+	NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
+
+	return ieee802154_nl_finish(msg);
+
+nla_put_failure:
+	return ieee802154_nl_put_failure(msg);
+}
+EXPORT_SYMBOL(ieee802154_nl_assoc_confirm);
+
+int ieee802154_nl_disassoc_indic(struct net_device *dev, struct ieee802154_addr *addr, u8 reason)
+{
+	struct sk_buff *msg;
+
+	pr_debug("%s\n", __func__);
+
+	msg = ieee802154_nl_create(/* flags*/ 0, IEEE802154_DISASSOCIATE_INDIC);
+	if (!msg)
+		return -ENOBUFS;
+
+	NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
+	NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
+	NLA_PUT_HW_ADDR(msg, IEEE802154_ATTR_HW_ADDR, dev->dev_addr);
+
+	if (addr->addr_type == IEEE802154_ADDR_LONG)
+		NLA_PUT_HW_ADDR(msg, IEEE802154_ATTR_SRC_HW_ADDR, addr->hwaddr);
+	else
+		NLA_PUT_U16(msg, IEEE802154_ATTR_SRC_SHORT_ADDR, addr->short_addr);
+
+	NLA_PUT_U8(msg, IEEE802154_ATTR_REASON, reason);
+
+	return ieee802154_nl_finish(msg);
+
+nla_put_failure:
+	return ieee802154_nl_put_failure(msg);
+}
+EXPORT_SYMBOL(ieee802154_nl_disassoc_indic);
+
+int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status)
+{
+	struct sk_buff *msg;
+
+	pr_debug("%s\n", __func__);
+
+	msg = ieee802154_nl_create(/* flags*/ 0, IEEE802154_DISASSOCIATE_CONF);
+	if (!msg)
+		return -ENOBUFS;
+
+	NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
+	NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
+	NLA_PUT_HW_ADDR(msg, IEEE802154_ATTR_HW_ADDR, dev->dev_addr);
+
+	NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
+
+	return ieee802154_nl_finish(msg);
+
+nla_put_failure:
+	return ieee802154_nl_put_failure(msg);
+}
+EXPORT_SYMBOL(ieee802154_nl_disassoc_confirm);
+
+int ieee802154_nl_beacon_indic(struct net_device *dev, u16 panid, u16 coord_addr) /* TODO */
+{
+	struct sk_buff *msg;
+
+	pr_debug("%s\n", __func__);
+
+	msg = ieee802154_nl_create(/* flags*/ 0, IEEE802154_BEACON_NOTIFY_INDIC);
+	if (!msg)
+		return -ENOBUFS;
+
+	NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
+	NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
+	NLA_PUT_HW_ADDR(msg, IEEE802154_ATTR_HW_ADDR, dev->dev_addr);
+	NLA_PUT_U16(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, coord_addr);
+	NLA_PUT_U16(msg, IEEE802154_ATTR_COORD_PAN_ID, panid);
+
+	return ieee802154_nl_finish(msg);
+
+nla_put_failure:
+	return ieee802154_nl_put_failure(msg);
+}
+EXPORT_SYMBOL(ieee802154_nl_beacon_indic);
+
+int ieee802154_nl_scan_confirm(struct net_device *dev, u8 status, u8 scan_type, u32 unscanned,
+		u8 *edl/* , struct list_head *pan_desc_list */)
+{
+	struct sk_buff *msg;
+
+	pr_debug("%s\n", __func__);
+
+	msg = ieee802154_nl_create(/* flags*/ 0, IEEE802154_SCAN_CONF);
+	if (!msg)
+		return -ENOBUFS;
+
+	NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
+	NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
+	NLA_PUT_HW_ADDR(msg, IEEE802154_ATTR_HW_ADDR, dev->dev_addr);
+
+	NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
+	NLA_PUT_U8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type);
+	NLA_PUT_U32(msg, IEEE802154_ATTR_CHANNELS, unscanned);
+
+	if (edl)
+		NLA_PUT(msg, IEEE802154_ATTR_ED_LIST, 27, edl);
+
+	return ieee802154_nl_finish(msg);
+
+nla_put_failure:
+	return ieee802154_nl_put_failure(msg);
+}
+EXPORT_SYMBOL(ieee802154_nl_scan_confirm);
+
+/* Requests from userspace */
+static struct net_device *ieee802154_nl_get_dev(struct genl_info *info)
+{
+	struct net_device *dev;
+
+	if (info->attrs[IEEE802154_ATTR_DEV_NAME]) {
+		char name[IFNAMSIZ + 1];
+		nla_strlcpy(name, info->attrs[IEEE802154_ATTR_DEV_NAME], sizeof(name));
+		dev = dev_get_by_name(&init_net, name);
+	} else if (info->attrs[IEEE802154_ATTR_DEV_INDEX])
+		dev = dev_get_by_index(&init_net, nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX]));
+	else
+		return NULL;
+
+	if (dev->type != ARPHRD_IEEE802154) {
+		dev_put(dev);
+		return NULL;
+	}
+
+	return dev;
+}
+
+static int ieee802154_associate_req(struct sk_buff *skb, struct genl_info *info)
+{
+	struct net_device *dev;
+	struct ieee802154_addr addr;
+	int ret = -EINVAL;
+
+	if (!info->attrs[IEEE802154_ATTR_CHANNEL]
+	 || !info->attrs[IEEE802154_ATTR_COORD_PAN_ID]
+	 || (!info->attrs[IEEE802154_ATTR_COORD_HW_ADDR] && !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR])
+	 || !info->attrs[IEEE802154_ATTR_CAPABILITY])
+		return -EINVAL;
+
+	dev = ieee802154_nl_get_dev(info);
+	if (!dev)
+		return -ENODEV;
+
+	if (info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]) {
+		addr.addr_type = IEEE802154_ADDR_LONG;
+		NLA_GET_HW_ADDR(info->attrs[IEEE802154_ATTR_COORD_HW_ADDR], addr.hwaddr);
+	} else {
+		addr.addr_type = IEEE802154_ADDR_SHORT;
+		addr.short_addr = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
+	}
+	addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
+
+	ret = IEEE802154_MLME_OPS(dev)->assoc_req(dev, &addr,
+			nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]),
+			nla_get_u8(info->attrs[IEEE802154_ATTR_CAPABILITY]));
+
+	dev_put(dev);
+	return ret;
+}
+
+static int ieee802154_associate_resp(struct sk_buff *skb, struct genl_info *info)
+{
+	struct net_device *dev;
+	struct ieee802154_addr addr;
+	int ret = -EINVAL;
+
+	if (!info->attrs[IEEE802154_ATTR_STATUS]
+	 || !info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]
+	 || !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR])
+		return -EINVAL;
+
+	dev = ieee802154_nl_get_dev(info);
+	if (!dev)
+		return -ENODEV;
+
+	addr.addr_type = IEEE802154_ADDR_LONG;
+	NLA_GET_HW_ADDR(info->attrs[IEEE802154_ATTR_DEST_HW_ADDR], addr.hwaddr);
+	addr.pan_id = IEEE802154_MLME_OPS(dev)->get_pan_id(dev);
+
+
+	ret = IEEE802154_MLME_OPS(dev)->assoc_resp(dev, &addr,
+			nla_get_u16(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]),
+			nla_get_u8(info->attrs[IEEE802154_ATTR_STATUS]));
+
+	dev_put(dev);
+	return ret;
+}
+
+static int ieee802154_disassociate_req(struct sk_buff *skb, struct genl_info *info)
+{
+	struct net_device *dev;
+	struct ieee802154_addr addr;
+	int ret = -EINVAL;
+
+	if ((!info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] && !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR])
+	 || !info->attrs[IEEE802154_ATTR_REASON])
+		return -EINVAL;
+
+	dev = ieee802154_nl_get_dev(info);
+	if (!dev)
+		return -ENODEV;
+
+	if (info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]) {
+		addr.addr_type = IEEE802154_ADDR_LONG;
+		NLA_GET_HW_ADDR(info->attrs[IEEE802154_ATTR_DEST_HW_ADDR], addr.hwaddr);
+	} else {
+		addr.addr_type = IEEE802154_ADDR_SHORT;
+		addr.short_addr = nla_get_u16(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]);
+	}
+	addr.pan_id = IEEE802154_MLME_OPS(dev)->get_pan_id(dev);
+
+	ret = IEEE802154_MLME_OPS(dev)->disassoc_req(dev, &addr,
+			nla_get_u8(info->attrs[IEEE802154_ATTR_REASON]));
+
+	dev_put(dev);
+	return ret;
+}
+
+/*
+ * PANid, channel, beacon_order = 15, superframe_order = 15,
+ * PAN_coordinator, battery_life_extension = 0,
+ * coord_realignment = 0, security_enable = 0
+*/
+static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
+{
+	struct net_device *dev;
+	struct ieee802154_addr addr;
+
+	u8 channel, bcn_ord, sf_ord;
+	int pan_coord, blx, coord_realign;
+	int ret;
+
+	if (!info->attrs[IEEE802154_ATTR_COORD_PAN_ID]
+	 || !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]
+	 || !info->attrs[IEEE802154_ATTR_CHANNEL]
+	 || !info->attrs[IEEE802154_ATTR_BCN_ORD]
+	 || !info->attrs[IEEE802154_ATTR_SF_ORD]
+	 || !info->attrs[IEEE802154_ATTR_PAN_COORD]
+	 || !info->attrs[IEEE802154_ATTR_BAT_EXT]
+	 || !info->attrs[IEEE802154_ATTR_COORD_REALIGN]
+	 )
+		return -EINVAL;
+
+	dev = ieee802154_nl_get_dev(info);
+	if (!dev)
+		return -ENODEV;
+
+	addr.addr_type = IEEE802154_ADDR_SHORT;
+	addr.short_addr = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
+	addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
+
+	channel = nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]);
+	bcn_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_BCN_ORD]);
+	sf_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_SF_ORD]);
+	pan_coord = nla_get_u8(info->attrs[IEEE802154_ATTR_PAN_COORD]);
+	blx = nla_get_u8(info->attrs[IEEE802154_ATTR_BAT_EXT]);
+	coord_realign = nla_get_u8(info->attrs[IEEE802154_ATTR_COORD_REALIGN]);
+
+	ret = IEEE802154_MLME_OPS(dev)->start_req(dev, &addr, channel, bcn_ord, sf_ord,
+		pan_coord, blx, coord_realign);
+
+	dev_put(dev);
+	return ret;
+}
+
+static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info)
+{
+	struct net_device *dev;
+	int ret;
+	u8 type;
+	u32 channels;
+	u8 duration;
+
+	if (!info->attrs[IEEE802154_ATTR_SCAN_TYPE]
+	 || !info->attrs[IEEE802154_ATTR_CHANNELS]
+	 || !info->attrs[IEEE802154_ATTR_DURATION])
+		return -EINVAL;
+
+	dev = ieee802154_nl_get_dev(info);
+	if (!dev)
+		return -ENODEV;
+
+	type = nla_get_u8(info->attrs[IEEE802154_ATTR_SCAN_TYPE]);
+	channels = nla_get_u32(info->attrs[IEEE802154_ATTR_CHANNELS]);
+	duration = nla_get_u8(info->attrs[IEEE802154_ATTR_DURATION]);
+
+	ret = IEEE802154_MLME_OPS(dev)->scan_req(dev, type, channels, duration);
+
+	dev_put(dev);
+	return ret;
+}
+
+#define IEEE802154_OP(_cmd, _func)			\
+	{						\
+		.cmd	= _cmd,				\
+		.policy	= ieee802154_policy,		\
+		.doit	= _func,			\
+		.dumpit	= NULL,				\
+		.flags	= GENL_ADMIN_PERM,		\
+	}
+
+static struct genl_ops ieee802154_coordinator_ops[] = {
+	IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req),
+	IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp),
+	IEEE802154_OP(IEEE802154_DISASSOCIATE_REQ, ieee802154_disassociate_req),
+	IEEE802154_OP(IEEE802154_SCAN_REQ, ieee802154_scan_req),
+	IEEE802154_OP(IEEE802154_START_REQ, ieee802154_start_req),
+};
+
+static int __init ieee802154_nl_init(void)
+{
+	int rc;
+	int i;
+
+	rc = genl_register_family(&ieee802154_coordinator_family);
+	if (rc)
+		goto fail;
+
+	rc = genl_register_mc_group(&ieee802154_coordinator_family, &ieee802154_coord_mcgrp);
+	if (rc)
+		goto fail;
+
+	rc = genl_register_mc_group(&ieee802154_coordinator_family, &ieee802154_beacon_mcgrp);
+	if (rc)
+		goto fail;
+
+
+	for (i = 0; i < ARRAY_SIZE(ieee802154_coordinator_ops); i++) {
+		rc = genl_register_ops(&ieee802154_coordinator_family, &ieee802154_coordinator_ops[i]);
+		if (rc)
+			goto fail;
+	}
+
+	return 0;
+
+fail:
+	genl_unregister_family(&ieee802154_coordinator_family);
+	return rc;
+}
+module_init(ieee802154_nl_init);
+
+static void __exit ieee802154_nl_exit(void)
+{
+	genl_unregister_family(&ieee802154_coordinator_family);
+}
+module_exit(ieee802154_nl_exit);
+
-- 
1.6.2.4


^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [PATCH 04/10] net: add NL802154 interface for configuration of 802.15.4 devices
@ 2009-06-01 14:54         ` Dmitry Eremin-Solenikov
  0 siblings, 0 replies; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-01 14:54 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	slapin-9cOl001CZnBAfugRpC6u6w,
	maxim.osipov-kv7WeFo6aLtBDgjK7y7TUQ,
	dmitry.baryshkov-kv7WeFo6aLtBDgjK7y7TUQ,
	oliver.fendt-kv7WeFo6aLtBDgjK7y7TUQ, Dmitry Eremin-Solenikov

Add a netlink interface for configuration of IEEE 802.15.4 device. Also this
interface specifies events notification sent by devices towards higher layers.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Sergey Lapin <slapin-9cOl001CZnBAfugRpC6u6w@public.gmane.org>
---
 include/net/ieee802154/nl802154.h |  165 +++++++++++++
 net/ieee802154/Makefile           |    3 +-
 net/ieee802154/netlink.c          |  485 +++++++++++++++++++++++++++++++++++++
 3 files changed, 652 insertions(+), 1 deletions(-)
 create mode 100644 include/net/ieee802154/nl802154.h
 create mode 100644 net/ieee802154/netlink.c

diff --git a/include/net/ieee802154/nl802154.h b/include/net/ieee802154/nl802154.h
new file mode 100644
index 0000000..27f6ee9
--- /dev/null
+++ b/include/net/ieee802154/nl802154.h
@@ -0,0 +1,165 @@
+/*
+ * ieee802154_nl.h
+ *
+ * Copyright (C) 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.
+ *
+ */
+
+#ifndef IEEE802154_NL_H
+#define IEEE802154_NL_H
+
+#define IEEE802154_NL_NAME "802.15.4 MAC"
+#define IEEE802154_MCAST_COORD_NAME "coordinator"
+#define IEEE802154_MCAST_BEACON_NAME "beacon"
+
+enum {
+	__IEEE802154_ATTR_INVALID,
+
+	IEEE802154_ATTR_DEV_NAME,
+	IEEE802154_ATTR_DEV_INDEX,
+
+	IEEE802154_ATTR_STATUS,
+
+	IEEE802154_ATTR_SHORT_ADDR,
+	IEEE802154_ATTR_HW_ADDR,
+	IEEE802154_ATTR_PAN_ID,
+
+	IEEE802154_ATTR_CHANNEL,
+
+	IEEE802154_ATTR_COORD_SHORT_ADDR,
+	IEEE802154_ATTR_COORD_HW_ADDR,
+	IEEE802154_ATTR_COORD_PAN_ID,
+
+	IEEE802154_ATTR_SRC_SHORT_ADDR,
+	IEEE802154_ATTR_SRC_HW_ADDR,
+	IEEE802154_ATTR_SRC_PAN_ID,
+
+	IEEE802154_ATTR_DEST_SHORT_ADDR,
+	IEEE802154_ATTR_DEST_HW_ADDR,
+	IEEE802154_ATTR_DEST_PAN_ID,
+
+	IEEE802154_ATTR_CAPABILITY, /* FIXME: this is association */
+	IEEE802154_ATTR_REASON,
+	IEEE802154_ATTR_SCAN_TYPE,
+	IEEE802154_ATTR_CHANNELS,
+	IEEE802154_ATTR_DURATION,
+	IEEE802154_ATTR_ED_LIST,
+	IEEE802154_ATTR_BCN_ORD,
+	IEEE802154_ATTR_SF_ORD,
+	IEEE802154_ATTR_PAN_COORD,
+	IEEE802154_ATTR_BAT_EXT,
+	IEEE802154_ATTR_COORD_REALIGN,
+	IEEE802154_ATTR_SEC,
+
+	__IEEE802154_ATTR_MAX,
+};
+
+#define IEEE802154_ATTR_MAX (__IEEE802154_ATTR_MAX - 1)
+#define NLA_HW_ADDR	NLA_U64
+#define NLA_GET_HW_ADDR(attr, addr) do { u64 _temp = nla_get_u64(attr); memcpy(addr, &_temp, 8); } while (0)
+#define NLA_PUT_HW_ADDR(msg, attr, addr) do { u64 _temp; memcpy(&_temp, addr, 8); NLA_PUT_U64(msg, attr, _temp); } while (0)
+
+#ifdef IEEE802154_NL_WANT_POLICY
+static struct nla_policy ieee802154_policy[IEEE802154_ATTR_MAX + 1] = {
+	[IEEE802154_ATTR_DEV_NAME] = { .type = NLA_STRING, },
+	[IEEE802154_ATTR_DEV_INDEX] = { .type = NLA_U32, },
+
+	[IEEE802154_ATTR_STATUS] = { .type = NLA_U8, },
+	[IEEE802154_ATTR_SHORT_ADDR] = { .type = NLA_U16, },
+	[IEEE802154_ATTR_HW_ADDR] = { .type = NLA_HW_ADDR, },
+	[IEEE802154_ATTR_PAN_ID] = { .type = NLA_U16, },
+	[IEEE802154_ATTR_CHANNEL] = { .type = NLA_U8, },
+	[IEEE802154_ATTR_COORD_SHORT_ADDR] = { .type = NLA_U16, },
+	[IEEE802154_ATTR_COORD_HW_ADDR] = { .type = NLA_HW_ADDR, },
+	[IEEE802154_ATTR_COORD_PAN_ID] = { .type = NLA_U16, },
+	[IEEE802154_ATTR_SRC_SHORT_ADDR] = { .type = NLA_U16, },
+	[IEEE802154_ATTR_SRC_HW_ADDR] = { .type = NLA_HW_ADDR, },
+	[IEEE802154_ATTR_SRC_PAN_ID] = { .type = NLA_U16, },
+	[IEEE802154_ATTR_DEST_SHORT_ADDR] = { .type = NLA_U16, },
+	[IEEE802154_ATTR_DEST_HW_ADDR] = { .type = NLA_HW_ADDR, },
+	[IEEE802154_ATTR_DEST_PAN_ID] = { .type = NLA_U16, },
+
+	[IEEE802154_ATTR_CAPABILITY] = { .type = NLA_U8, },
+	[IEEE802154_ATTR_REASON] = { .type = NLA_U8, },
+	[IEEE802154_ATTR_SCAN_TYPE] = { .type = NLA_U8, },
+	[IEEE802154_ATTR_CHANNELS] = { .type = NLA_U32, },
+	[IEEE802154_ATTR_DURATION] = { .type = NLA_U8, },
+#ifdef __KERNEL__
+	[IEEE802154_ATTR_ED_LIST] = { .len = 27 },
+#else
+	[IEEE802154_ATTR_ED_LIST] = { .minlen = 27, .maxlen = 27 },
+#endif
+};
+#endif
+
+/* commands */
+/* REQ should be responded with CONF
+ * and INDIC with RESP
+ */
+enum {
+	__IEEE802154_COMMAND_INVALID,
+
+	IEEE802154_ASSOCIATE_REQ,
+	IEEE802154_ASSOCIATE_CONF,
+	IEEE802154_DISASSOCIATE_REQ,
+	IEEE802154_DISASSOCIATE_CONF,
+	IEEE802154_GET_REQ,
+	IEEE802154_GET_CONF,
+/* 	IEEE802154_GTS_REQ, */
+/* 	IEEE802154_GTS_CONF, */
+	IEEE802154_RESET_REQ,
+	IEEE802154_RESET_CONF,
+/* 	IEEE802154_RX_ENABLE_REQ, */
+/* 	IEEE802154_RX_ENABLE_CONF, */
+	IEEE802154_SCAN_REQ,
+	IEEE802154_SCAN_CONF,
+	IEEE802154_SET_REQ,
+	IEEE802154_SET_CONF,
+	IEEE802154_START_REQ,
+	IEEE802154_START_CONF,
+	IEEE802154_SYNC_REQ,
+	IEEE802154_POLL_REQ,
+	IEEE802154_POLL_CONF,
+
+	IEEE802154_ASSOCIATE_INDIC,
+	IEEE802154_ASSOCIATE_RESP,
+	IEEE802154_DISASSOCIATE_INDIC,
+	IEEE802154_BEACON_NOTIFY_INDIC,
+/* 	IEEE802154_GTS_INDIC, */
+	IEEE802154_ORPHAN_INDIC,
+	IEEE802154_ORPHAN_RESP,
+	IEEE802154_COMM_STATUS_INDIC,
+	IEEE802154_SYNC_LOSS_INDIC,
+
+	__IEEE802154_CMD_MAX,
+};
+
+#define IEEE802154_CMD_MAX (__IEEE802154_CMD_MAX - 1)
+
+
+#ifdef __KERNEL__
+struct net_device;
+
+int ieee802154_nl_assoc_indic(struct net_device *dev, struct ieee802154_addr *addr, u8 cap);
+int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr, u8 status);
+int ieee802154_nl_disassoc_indic(struct net_device *dev, struct ieee802154_addr *addr, u8 reason);
+int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status);
+int ieee802154_nl_scan_confirm(struct net_device *dev, u8 status, u8 scan_type, u32 unscanned,
+		u8 *edl/*, struct list_head *pan_desc_list */);
+int ieee802154_nl_beacon_indic(struct net_device *dev, u16 panid, u16 coord_addr); /* TODO */
+#endif
+
+#endif
diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile
index cb88054..7c0b025 100644
--- a/net/ieee802154/Makefile
+++ b/net/ieee802154/Makefile
@@ -1,4 +1,5 @@
-obj-$(CONFIG_IEEE802154) +=	af_802154.o
+obj-$(CONFIG_IEEE802154) +=	nl802154.o af_802154.o
+nl802154-objs		:= netlink.o
 af_802154-objs		:= af_ieee802154.o raw.o dgram.o
 
 EXTRA_CFLAGS += -Wall -DDEBUG
diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c
new file mode 100644
index 0000000..eafdc4d
--- /dev/null
+++ b/net/ieee802154/netlink.c
@@ -0,0 +1,485 @@
+/*
+ * Netlink inteface for IEEE 802.15.4 stack
+ *
+ * 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 <sergey.lapin-kv7WeFo6aLtBDgjK7y7TUQ@public.gmane.org>
+ * Dmitry Eremin-Solenikov <dbaryshkov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/if_arp.h>
+#include <net/netlink.h>
+#include <net/genetlink.h>
+#include <linux/netdevice.h>
+#include <net/ieee802154/af_ieee802154.h>
+#define IEEE802154_NL_WANT_POLICY
+#include <net/ieee802154/nl802154.h>
+#include <net/ieee802154/netdevice.h>
+
+static unsigned int ieee802154_seq_num;
+
+static struct genl_family ieee802154_coordinator_family = {
+	.id		= GENL_ID_GENERATE,
+	.hdrsize	= 0,
+	.name		= IEEE802154_NL_NAME,
+	.version	= 1,
+	.maxattr	= IEEE802154_ATTR_MAX,
+};
+
+static struct genl_multicast_group ieee802154_coord_mcgrp = {
+	.name		= IEEE802154_MCAST_COORD_NAME,
+};
+
+static struct genl_multicast_group ieee802154_beacon_mcgrp = {
+	.name		= IEEE802154_MCAST_BEACON_NAME,
+};
+
+/* Requests to userspace */
+static struct sk_buff *ieee802154_nl_create(int flags, u8 req)
+{
+	void *hdr;
+	struct sk_buff *msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
+
+	if (!msg)
+		return NULL;
+
+	hdr = genlmsg_put(msg, 0, ieee802154_seq_num++, &ieee802154_coordinator_family, flags, req);
+	if (!hdr) {
+		nlmsg_free(msg);
+		return NULL;
+	}
+
+	return msg;
+}
+
+static int ieee802154_nl_finish(struct sk_buff *msg)
+{
+	void *hdr = genlmsg_data(NLMSG_DATA(msg->data)); /* XXX: nlh is right at the start of msg */
+
+	if (!genlmsg_end(msg, hdr))
+		goto out;
+
+	return genlmsg_multicast(msg, 0, ieee802154_coord_mcgrp.id, GFP_ATOMIC);
+out:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+static int ieee802154_nl_put_failure(struct sk_buff *msg)
+{
+	void *hdr = genlmsg_data(NLMSG_DATA(msg->data)); /* XXX: nlh is right at the start of msg */
+	genlmsg_cancel(msg, hdr);
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+int ieee802154_nl_assoc_indic(struct net_device *dev, struct ieee802154_addr *addr, u8 cap)
+{
+	struct sk_buff *msg;
+
+	pr_debug("%s\n", __func__);
+
+	msg = ieee802154_nl_create(/* flags*/ 0, IEEE802154_ASSOCIATE_INDIC);
+	if (!msg)
+		return -ENOBUFS;
+
+	NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
+	NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
+	NLA_PUT_HW_ADDR(msg, IEEE802154_ATTR_HW_ADDR, dev->dev_addr);
+
+	/* FIXME: check that we really received hw address */
+	NLA_PUT_HW_ADDR(msg, IEEE802154_ATTR_SRC_HW_ADDR, addr->hwaddr);
+
+	NLA_PUT_U8(msg, IEEE802154_ATTR_CAPABILITY, cap);
+
+	return ieee802154_nl_finish(msg);
+
+nla_put_failure:
+	return ieee802154_nl_put_failure(msg);
+}
+EXPORT_SYMBOL(ieee802154_nl_assoc_indic);
+
+int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr, u8 status)
+{
+	struct sk_buff *msg;
+
+	pr_debug("%s\n", __func__);
+
+	msg = ieee802154_nl_create(/* flags*/ 0, IEEE802154_ASSOCIATE_CONF);
+	if (!msg)
+		return -ENOBUFS;
+
+	NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
+	NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
+	NLA_PUT_HW_ADDR(msg, IEEE802154_ATTR_HW_ADDR, dev->dev_addr);
+
+	NLA_PUT_U16(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr);
+	NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
+
+	return ieee802154_nl_finish(msg);
+
+nla_put_failure:
+	return ieee802154_nl_put_failure(msg);
+}
+EXPORT_SYMBOL(ieee802154_nl_assoc_confirm);
+
+int ieee802154_nl_disassoc_indic(struct net_device *dev, struct ieee802154_addr *addr, u8 reason)
+{
+	struct sk_buff *msg;
+
+	pr_debug("%s\n", __func__);
+
+	msg = ieee802154_nl_create(/* flags*/ 0, IEEE802154_DISASSOCIATE_INDIC);
+	if (!msg)
+		return -ENOBUFS;
+
+	NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
+	NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
+	NLA_PUT_HW_ADDR(msg, IEEE802154_ATTR_HW_ADDR, dev->dev_addr);
+
+	if (addr->addr_type == IEEE802154_ADDR_LONG)
+		NLA_PUT_HW_ADDR(msg, IEEE802154_ATTR_SRC_HW_ADDR, addr->hwaddr);
+	else
+		NLA_PUT_U16(msg, IEEE802154_ATTR_SRC_SHORT_ADDR, addr->short_addr);
+
+	NLA_PUT_U8(msg, IEEE802154_ATTR_REASON, reason);
+
+	return ieee802154_nl_finish(msg);
+
+nla_put_failure:
+	return ieee802154_nl_put_failure(msg);
+}
+EXPORT_SYMBOL(ieee802154_nl_disassoc_indic);
+
+int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status)
+{
+	struct sk_buff *msg;
+
+	pr_debug("%s\n", __func__);
+
+	msg = ieee802154_nl_create(/* flags*/ 0, IEEE802154_DISASSOCIATE_CONF);
+	if (!msg)
+		return -ENOBUFS;
+
+	NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
+	NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
+	NLA_PUT_HW_ADDR(msg, IEEE802154_ATTR_HW_ADDR, dev->dev_addr);
+
+	NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
+
+	return ieee802154_nl_finish(msg);
+
+nla_put_failure:
+	return ieee802154_nl_put_failure(msg);
+}
+EXPORT_SYMBOL(ieee802154_nl_disassoc_confirm);
+
+int ieee802154_nl_beacon_indic(struct net_device *dev, u16 panid, u16 coord_addr) /* TODO */
+{
+	struct sk_buff *msg;
+
+	pr_debug("%s\n", __func__);
+
+	msg = ieee802154_nl_create(/* flags*/ 0, IEEE802154_BEACON_NOTIFY_INDIC);
+	if (!msg)
+		return -ENOBUFS;
+
+	NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
+	NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
+	NLA_PUT_HW_ADDR(msg, IEEE802154_ATTR_HW_ADDR, dev->dev_addr);
+	NLA_PUT_U16(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, coord_addr);
+	NLA_PUT_U16(msg, IEEE802154_ATTR_COORD_PAN_ID, panid);
+
+	return ieee802154_nl_finish(msg);
+
+nla_put_failure:
+	return ieee802154_nl_put_failure(msg);
+}
+EXPORT_SYMBOL(ieee802154_nl_beacon_indic);
+
+int ieee802154_nl_scan_confirm(struct net_device *dev, u8 status, u8 scan_type, u32 unscanned,
+		u8 *edl/* , struct list_head *pan_desc_list */)
+{
+	struct sk_buff *msg;
+
+	pr_debug("%s\n", __func__);
+
+	msg = ieee802154_nl_create(/* flags*/ 0, IEEE802154_SCAN_CONF);
+	if (!msg)
+		return -ENOBUFS;
+
+	NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
+	NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
+	NLA_PUT_HW_ADDR(msg, IEEE802154_ATTR_HW_ADDR, dev->dev_addr);
+
+	NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
+	NLA_PUT_U8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type);
+	NLA_PUT_U32(msg, IEEE802154_ATTR_CHANNELS, unscanned);
+
+	if (edl)
+		NLA_PUT(msg, IEEE802154_ATTR_ED_LIST, 27, edl);
+
+	return ieee802154_nl_finish(msg);
+
+nla_put_failure:
+	return ieee802154_nl_put_failure(msg);
+}
+EXPORT_SYMBOL(ieee802154_nl_scan_confirm);
+
+/* Requests from userspace */
+static struct net_device *ieee802154_nl_get_dev(struct genl_info *info)
+{
+	struct net_device *dev;
+
+	if (info->attrs[IEEE802154_ATTR_DEV_NAME]) {
+		char name[IFNAMSIZ + 1];
+		nla_strlcpy(name, info->attrs[IEEE802154_ATTR_DEV_NAME], sizeof(name));
+		dev = dev_get_by_name(&init_net, name);
+	} else if (info->attrs[IEEE802154_ATTR_DEV_INDEX])
+		dev = dev_get_by_index(&init_net, nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX]));
+	else
+		return NULL;
+
+	if (dev->type != ARPHRD_IEEE802154) {
+		dev_put(dev);
+		return NULL;
+	}
+
+	return dev;
+}
+
+static int ieee802154_associate_req(struct sk_buff *skb, struct genl_info *info)
+{
+	struct net_device *dev;
+	struct ieee802154_addr addr;
+	int ret = -EINVAL;
+
+	if (!info->attrs[IEEE802154_ATTR_CHANNEL]
+	 || !info->attrs[IEEE802154_ATTR_COORD_PAN_ID]
+	 || (!info->attrs[IEEE802154_ATTR_COORD_HW_ADDR] && !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR])
+	 || !info->attrs[IEEE802154_ATTR_CAPABILITY])
+		return -EINVAL;
+
+	dev = ieee802154_nl_get_dev(info);
+	if (!dev)
+		return -ENODEV;
+
+	if (info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]) {
+		addr.addr_type = IEEE802154_ADDR_LONG;
+		NLA_GET_HW_ADDR(info->attrs[IEEE802154_ATTR_COORD_HW_ADDR], addr.hwaddr);
+	} else {
+		addr.addr_type = IEEE802154_ADDR_SHORT;
+		addr.short_addr = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
+	}
+	addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
+
+	ret = IEEE802154_MLME_OPS(dev)->assoc_req(dev, &addr,
+			nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]),
+			nla_get_u8(info->attrs[IEEE802154_ATTR_CAPABILITY]));
+
+	dev_put(dev);
+	return ret;
+}
+
+static int ieee802154_associate_resp(struct sk_buff *skb, struct genl_info *info)
+{
+	struct net_device *dev;
+	struct ieee802154_addr addr;
+	int ret = -EINVAL;
+
+	if (!info->attrs[IEEE802154_ATTR_STATUS]
+	 || !info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]
+	 || !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR])
+		return -EINVAL;
+
+	dev = ieee802154_nl_get_dev(info);
+	if (!dev)
+		return -ENODEV;
+
+	addr.addr_type = IEEE802154_ADDR_LONG;
+	NLA_GET_HW_ADDR(info->attrs[IEEE802154_ATTR_DEST_HW_ADDR], addr.hwaddr);
+	addr.pan_id = IEEE802154_MLME_OPS(dev)->get_pan_id(dev);
+
+
+	ret = IEEE802154_MLME_OPS(dev)->assoc_resp(dev, &addr,
+			nla_get_u16(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]),
+			nla_get_u8(info->attrs[IEEE802154_ATTR_STATUS]));
+
+	dev_put(dev);
+	return ret;
+}
+
+static int ieee802154_disassociate_req(struct sk_buff *skb, struct genl_info *info)
+{
+	struct net_device *dev;
+	struct ieee802154_addr addr;
+	int ret = -EINVAL;
+
+	if ((!info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] && !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR])
+	 || !info->attrs[IEEE802154_ATTR_REASON])
+		return -EINVAL;
+
+	dev = ieee802154_nl_get_dev(info);
+	if (!dev)
+		return -ENODEV;
+
+	if (info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]) {
+		addr.addr_type = IEEE802154_ADDR_LONG;
+		NLA_GET_HW_ADDR(info->attrs[IEEE802154_ATTR_DEST_HW_ADDR], addr.hwaddr);
+	} else {
+		addr.addr_type = IEEE802154_ADDR_SHORT;
+		addr.short_addr = nla_get_u16(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]);
+	}
+	addr.pan_id = IEEE802154_MLME_OPS(dev)->get_pan_id(dev);
+
+	ret = IEEE802154_MLME_OPS(dev)->disassoc_req(dev, &addr,
+			nla_get_u8(info->attrs[IEEE802154_ATTR_REASON]));
+
+	dev_put(dev);
+	return ret;
+}
+
+/*
+ * PANid, channel, beacon_order = 15, superframe_order = 15,
+ * PAN_coordinator, battery_life_extension = 0,
+ * coord_realignment = 0, security_enable = 0
+*/
+static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
+{
+	struct net_device *dev;
+	struct ieee802154_addr addr;
+
+	u8 channel, bcn_ord, sf_ord;
+	int pan_coord, blx, coord_realign;
+	int ret;
+
+	if (!info->attrs[IEEE802154_ATTR_COORD_PAN_ID]
+	 || !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]
+	 || !info->attrs[IEEE802154_ATTR_CHANNEL]
+	 || !info->attrs[IEEE802154_ATTR_BCN_ORD]
+	 || !info->attrs[IEEE802154_ATTR_SF_ORD]
+	 || !info->attrs[IEEE802154_ATTR_PAN_COORD]
+	 || !info->attrs[IEEE802154_ATTR_BAT_EXT]
+	 || !info->attrs[IEEE802154_ATTR_COORD_REALIGN]
+	 )
+		return -EINVAL;
+
+	dev = ieee802154_nl_get_dev(info);
+	if (!dev)
+		return -ENODEV;
+
+	addr.addr_type = IEEE802154_ADDR_SHORT;
+	addr.short_addr = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
+	addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
+
+	channel = nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]);
+	bcn_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_BCN_ORD]);
+	sf_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_SF_ORD]);
+	pan_coord = nla_get_u8(info->attrs[IEEE802154_ATTR_PAN_COORD]);
+	blx = nla_get_u8(info->attrs[IEEE802154_ATTR_BAT_EXT]);
+	coord_realign = nla_get_u8(info->attrs[IEEE802154_ATTR_COORD_REALIGN]);
+
+	ret = IEEE802154_MLME_OPS(dev)->start_req(dev, &addr, channel, bcn_ord, sf_ord,
+		pan_coord, blx, coord_realign);
+
+	dev_put(dev);
+	return ret;
+}
+
+static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info)
+{
+	struct net_device *dev;
+	int ret;
+	u8 type;
+	u32 channels;
+	u8 duration;
+
+	if (!info->attrs[IEEE802154_ATTR_SCAN_TYPE]
+	 || !info->attrs[IEEE802154_ATTR_CHANNELS]
+	 || !info->attrs[IEEE802154_ATTR_DURATION])
+		return -EINVAL;
+
+	dev = ieee802154_nl_get_dev(info);
+	if (!dev)
+		return -ENODEV;
+
+	type = nla_get_u8(info->attrs[IEEE802154_ATTR_SCAN_TYPE]);
+	channels = nla_get_u32(info->attrs[IEEE802154_ATTR_CHANNELS]);
+	duration = nla_get_u8(info->attrs[IEEE802154_ATTR_DURATION]);
+
+	ret = IEEE802154_MLME_OPS(dev)->scan_req(dev, type, channels, duration);
+
+	dev_put(dev);
+	return ret;
+}
+
+#define IEEE802154_OP(_cmd, _func)			\
+	{						\
+		.cmd	= _cmd,				\
+		.policy	= ieee802154_policy,		\
+		.doit	= _func,			\
+		.dumpit	= NULL,				\
+		.flags	= GENL_ADMIN_PERM,		\
+	}
+
+static struct genl_ops ieee802154_coordinator_ops[] = {
+	IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req),
+	IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp),
+	IEEE802154_OP(IEEE802154_DISASSOCIATE_REQ, ieee802154_disassociate_req),
+	IEEE802154_OP(IEEE802154_SCAN_REQ, ieee802154_scan_req),
+	IEEE802154_OP(IEEE802154_START_REQ, ieee802154_start_req),
+};
+
+static int __init ieee802154_nl_init(void)
+{
+	int rc;
+	int i;
+
+	rc = genl_register_family(&ieee802154_coordinator_family);
+	if (rc)
+		goto fail;
+
+	rc = genl_register_mc_group(&ieee802154_coordinator_family, &ieee802154_coord_mcgrp);
+	if (rc)
+		goto fail;
+
+	rc = genl_register_mc_group(&ieee802154_coordinator_family, &ieee802154_beacon_mcgrp);
+	if (rc)
+		goto fail;
+
+
+	for (i = 0; i < ARRAY_SIZE(ieee802154_coordinator_ops); i++) {
+		rc = genl_register_ops(&ieee802154_coordinator_family, &ieee802154_coordinator_ops[i]);
+		if (rc)
+			goto fail;
+	}
+
+	return 0;
+
+fail:
+	genl_unregister_family(&ieee802154_coordinator_family);
+	return rc;
+}
+module_init(ieee802154_nl_init);
+
+static void __exit ieee802154_nl_exit(void)
+{
+	genl_unregister_family(&ieee802154_coordinator_family);
+}
+module_exit(ieee802154_nl_exit);
+
-- 
1.6.2.4

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [PATCH 05/10] ieee802154: add simple HardMAC driver sample
  2009-06-01 14:54         ` Dmitry Eremin-Solenikov
  (?)
@ 2009-06-01 14:54         ` Dmitry Eremin-Solenikov
  2009-06-01 14:54           ` [PATCH 06/10] mac802154: add a software MAC 802.15.4 implementation Dmitry Eremin-Solenikov
  -1 siblings, 1 reply; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-01 14:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: netdev, linux-wireless, slapin, maxim.osipov, dmitry.baryshkov,
	oliver.fendt, Dmitry Eremin-Solenikov

fakehard is a really simple driver implementing only necessary
callbacks and serves the role of an example of driver for HardMAC
IEEE 802.15.4 device.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Signed-off-by: Sergey Lapin <slapin@ossfans.org>
---
 drivers/Makefile              |    1 +
 drivers/ieee802154/Kconfig    |   23 ++++
 drivers/ieee802154/Makefile   |    3 +
 drivers/ieee802154/fakehard.c |  253 +++++++++++++++++++++++++++++++++++++++++
 drivers/net/Kconfig           |    2 +
 5 files changed, 282 insertions(+), 0 deletions(-)
 create mode 100644 drivers/ieee802154/Kconfig
 create mode 100644 drivers/ieee802154/Makefile
 create mode 100644 drivers/ieee802154/fakehard.c

diff --git a/drivers/Makefile b/drivers/Makefile
index 1266ead..9e7d4e5 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -107,3 +107,4 @@ obj-$(CONFIG_SSB)		+= ssb/
 obj-$(CONFIG_VIRTIO)		+= virtio/
 obj-$(CONFIG_STAGING)		+= staging/
 obj-y				+= platform/
+obj-y				+= ieee802154/
diff --git a/drivers/ieee802154/Kconfig b/drivers/ieee802154/Kconfig
new file mode 100644
index 0000000..8610620
--- /dev/null
+++ b/drivers/ieee802154/Kconfig
@@ -0,0 +1,23 @@
+menuconfig IEEE802154_DRIVERS
+	bool "IEEE 802.15.4 drivers"
+	depends on NETDEVICES && IEEE802154
+	default y
+	---help---
+	  Say Y here to get to see options for IEEE 802.15.4 Low-Rate
+	  Wireless Personal Area Network device drivers. This option alone
+	  does not add any kernel code.
+
+	  If you say N, all options in this submenu will be skipped and disabled.
+
+config IEEE802154_FAKEHARD
+	tristate "Fake LR-WPAN driver with several interconnected devices"
+	depends on  IEEE802154_DRIVERS
+	---help---
+	  Say Y here to enable the fake driver that serves as an example
+          of HardMAC device driver.
+
+          This driver can also be built as a module. To do so say M here.
+	  The module will be called 'fakehard'.
+
+endif
+
diff --git a/drivers/ieee802154/Makefile b/drivers/ieee802154/Makefile
new file mode 100644
index 0000000..e0e8e1a
--- /dev/null
+++ b/drivers/ieee802154/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_IEEE802154_FAKEHARD) += fakehard.o
+
+EXTRA_CFLAGS += -DDEBUG -DCONFIG_FFD
diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c
new file mode 100644
index 0000000..e4c08ea
--- /dev/null
+++ b/drivers/ieee802154/fakehard.c
@@ -0,0 +1,253 @@
+/*
+ * Sample driver for HardMAC IEEE 802.15.4 devices
+ *
+ * Copyright (C) 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 <dmitry.baryshkov@siemens.com>
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+
+#include <net/ieee802154/af_ieee802154.h>
+#include <net/ieee802154/netdevice.h>
+
+static u16 fake_get_pan_id(struct net_device *dev)
+{
+	BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+	return 0xeba1;
+}
+
+static u16 fake_get_short_addr(struct net_device *dev)
+{
+	BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+	return 0x1;
+}
+
+static u8 fake_get_dsn(struct net_device *dev)
+{
+	BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+	return 0x00; /* DSN are implemented in HW, so return just 0 */
+}
+
+static u8 fake_get_bsn(struct net_device *dev)
+{
+	BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+	return 0x00; /* BSN are implemented in HW, so return just 0 */
+}
+
+static int fake_assoc_req(struct net_device *dev, struct ieee802154_addr *addr, u8 channel, u8 cap)
+{
+	return 0;
+}
+
+static int fake_assoc_resp(struct net_device *dev, struct ieee802154_addr *addr, u16 short_addr, u8 status)
+{
+	return 0;
+}
+
+static int fake_disassoc_req(struct net_device *dev, struct ieee802154_addr *addr, u8 reason)
+{
+	return 0;
+}
+
+static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr,
+				u8 channel,
+				u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx,
+				u8 coord_realign)
+{
+	return 0;
+}
+
+static int fake_scan_req(struct net_device *dev, u8 type, u32 channels, u8 duration)
+{
+	return 0;
+}
+
+static struct ieee802154_mlme_ops fake_mlme = {
+	.assoc_req = fake_assoc_req,
+	.assoc_resp = fake_assoc_resp,
+	.disassoc_req = fake_disassoc_req,
+	.start_req = fake_start_req,
+	.scan_req = fake_scan_req,
+
+	.get_pan_id = fake_get_pan_id,
+	.get_short_addr = fake_get_short_addr,
+	.get_dsn = fake_get_dsn,
+	.get_bsn = fake_get_bsn,
+};
+
+static int ieee802154_fake_open(struct net_device *dev)
+{
+	netif_start_queue(dev);
+	return 0;
+}
+
+static int ieee802154_fake_close(struct net_device *dev)
+{
+	netif_stop_queue(dev);
+	return 0;
+}
+
+static int ieee802154_fake_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	skb->iif = dev->ifindex;
+	skb->dev = dev;
+	dev->stats.tx_packets++;
+	dev->stats.tx_bytes += skb->len;
+
+	dev->trans_start = jiffies;
+
+	/* FIXME: do hardware work here ... */
+
+	return 0;
+}
+
+
+static int ieee802154_fake_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct sockaddr_ieee802154 *sa = (struct sockaddr_ieee802154 *)&ifr->ifr_addr;
+	u16 pan_id, short_addr;
+
+	switch (cmd) {
+	case SIOCGIFADDR:
+		/* FIXME: fixed here, get from device IRL */
+		pan_id = fake_get_pan_id(dev);
+		short_addr = fake_get_short_addr(dev);
+		if (pan_id == IEEE802154_PANID_BROADCAST || short_addr == IEEE802154_ADDR_BROADCAST)
+			return -EADDRNOTAVAIL;
+
+		sa->family = AF_IEEE802154;
+		sa->addr.addr_type = IEEE802154_ADDR_SHORT;
+		sa->addr.pan_id = pan_id;
+		sa->addr.short_addr = short_addr;
+		return 0;
+	}
+	return -ENOIOCTLCMD;
+}
+
+static int ieee802154_fake_mac_addr(struct net_device *dev, void *p)
+{
+	return -EBUSY; /* HW address is built into the device */
+}
+
+static const struct net_device_ops fake_ops = {
+	.ndo_open		= ieee802154_fake_open,
+	.ndo_stop		= ieee802154_fake_close,
+	.ndo_start_xmit		= ieee802154_fake_xmit,
+	.ndo_do_ioctl		= ieee802154_fake_ioctl,
+	.ndo_set_mac_address	= ieee802154_fake_mac_addr,
+};
+
+
+static void ieee802154_fake_setup(struct net_device *dev)
+{
+	dev->addr_len		= IEEE802154_ADDR_LEN;
+	memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN);
+	dev->features		= NETIF_F_NO_CSUM;
+	dev->needed_tailroom	= 2; /* FCS */
+	dev->mtu		= 127;
+	dev->tx_queue_len	= 10;
+	dev->type		= ARPHRD_IEEE802154;
+	dev->flags		= IFF_NOARP | IFF_BROADCAST;
+	dev->watchdog_timeo	= 0;
+}
+
+
+static int __devinit ieee802154fake_probe(struct platform_device *pdev)
+{
+	struct net_device *dev = alloc_netdev(0, "hardwpan%d", ieee802154_fake_setup);
+	int err;
+
+	if (!dev)
+		return -ENOMEM;
+
+	memcpy(dev->dev_addr, "\xba\xbe\xca\xfe\xde\xad\xbe\xef", dev->addr_len);
+	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+
+	dev->netdev_ops = &fake_ops;
+	dev->ml_priv = &fake_mlme;
+
+	/*
+	 * If the name is a format string the caller wants us to do a
+	 * name allocation.
+	 */
+	if (strchr(dev->name, '%')) {
+		err = dev_alloc_name(dev, dev->name);
+		if (err < 0)
+			goto out;
+	}
+
+	SET_NETDEV_DEV(dev, &pdev->dev);
+
+	platform_set_drvdata(pdev, dev);
+
+	err = register_netdevice(dev);
+	if (err < 0)
+		goto out;
+
+
+	dev_info(&pdev->dev, "Added ieee802154 HardMAC hardware\n");
+	return 0;
+
+out:
+	unregister_netdev(dev);
+	return err;
+}
+
+static int __devexit ieee802154fake_remove(struct platform_device *pdev)
+{
+	struct net_device *dev = platform_get_drvdata(pdev);
+	unregister_netdev(dev);
+	free_netdev(dev);
+	return 0;
+}
+
+static struct platform_device *ieee802154fake_dev;
+
+static struct platform_driver ieee802154fake_driver = {
+	.probe = ieee802154fake_probe,
+	.remove = __devexit_p(ieee802154fake_remove),
+	.driver = {
+			.name = "ieee802154hardmac",
+			.owner = THIS_MODULE,
+	},
+};
+
+static __init int fake_init(void)
+{
+	ieee802154fake_dev = platform_device_register_simple("ieee802154hardmac", -1, NULL, 0);
+	return platform_driver_register(&ieee802154fake_driver);
+}
+
+static __exit void fake_exit(void)
+{
+	platform_driver_unregister(&ieee802154fake_driver);
+	platform_device_unregister(ieee802154fake_dev);
+}
+
+module_init(fake_init);
+module_exit(fake_exit);
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 214a92d..ec8cf21 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2704,6 +2704,8 @@ source "drivers/net/wan/Kconfig"
 
 source "drivers/atm/Kconfig"
 
+source "drivers/ieee802154/Kconfig"
+
 source "drivers/s390/net/Kconfig"
 
 config XEN_NETDEV_FRONTEND
-- 
1.6.2.4


^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [PATCH 06/10] mac802154: add a software MAC 802.15.4 implementation
  2009-06-01 14:54         ` [PATCH 05/10] ieee802154: add simple HardMAC driver sample Dmitry Eremin-Solenikov
@ 2009-06-01 14:54           ` Dmitry Eremin-Solenikov
  2009-06-01 14:54               ` Dmitry Eremin-Solenikov
  2009-06-05 12:24               ` Pavel Machek
  0 siblings, 2 replies; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-01 14:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: netdev, linux-wireless, slapin, maxim.osipov, dmitry.baryshkov,
	oliver.fendt, Dmitry Eremin-Solenikov

Some of available devices are just dump radios implementing IEEE 802.15.4
PHY layer. This commit adds a common library that acts like an intermediate
layer between our socket family and drivers for those dumb devices.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Signed-off-by: Sergey Lapin <slapin@ossfans.org>
---
 include/net/ieee802154/mac802154.h |   79 ++++
 net/Kconfig                        |    1 +
 net/Makefile                       |    1 +
 net/mac802154/Kconfig              |   13 +
 net/mac802154/Makefile             |    5 +
 net/mac802154/beacon.c             |  242 +++++++++++
 net/mac802154/beacon.h             |   48 ++
 net/mac802154/beacon_hash.c        |  103 +++++
 net/mac802154/beacon_hash.h        |   40 ++
 net/mac802154/dev.c                |  843 ++++++++++++++++++++++++++++++++++++
 net/mac802154/mac802154.h          |   64 +++
 net/mac802154/mac_cmd.c            |  325 ++++++++++++++
 net/mac802154/main.c               |   96 ++++
 net/mac802154/mdev.c               |  283 ++++++++++++
 net/mac802154/mib.h                |   32 ++
 net/mac802154/pib.c                |   87 ++++
 net/mac802154/pib.h                |   35 ++
 net/mac802154/scan.c               |  215 +++++++++
 18 files changed, 2512 insertions(+), 0 deletions(-)
 create mode 100644 include/net/ieee802154/mac802154.h
 create mode 100644 net/mac802154/Kconfig
 create mode 100644 net/mac802154/Makefile
 create mode 100644 net/mac802154/beacon.c
 create mode 100644 net/mac802154/beacon.h
 create mode 100644 net/mac802154/beacon_hash.c
 create mode 100644 net/mac802154/beacon_hash.h
 create mode 100644 net/mac802154/dev.c
 create mode 100644 net/mac802154/mac802154.h
 create mode 100644 net/mac802154/mac_cmd.c
 create mode 100644 net/mac802154/main.c
 create mode 100644 net/mac802154/mdev.c
 create mode 100644 net/mac802154/mib.h
 create mode 100644 net/mac802154/pib.c
 create mode 100644 net/mac802154/pib.h
 create mode 100644 net/mac802154/scan.c

diff --git a/include/net/ieee802154/mac802154.h b/include/net/ieee802154/mac802154.h
new file mode 100644
index 0000000..68e48d0
--- /dev/null
+++ b/include/net/ieee802154/mac802154.h
@@ -0,0 +1,79 @@
+/*
+ * IEEE802.15.4-2003 specification
+ *
+ * Copyright (C) 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:
+ */
+#ifndef IEEE802154_MAC802154_H
+#define IEEE802154_MAC802154_H
+
+/* FIXME: this can be merged with const.h ? */
+typedef enum {
+	PHY_BUSY = 0, /* cca */
+	PHY_BUSY_RX, /* state */
+	PHY_BUSY_TX, /* state */
+	PHY_FORCE_TRX_OFF,
+	PHY_IDLE, /* cca */
+	PHY_INVALID_PARAMETER, /* pib get/set */
+	PHY_RX_ON, /* state */
+	PHY_SUCCESS, /* ed */
+	PHY_TRX_OFF, /* cca, ed, state */
+	PHY_TX_ON, /* cca, ed, state */
+	PHY_UNSUPPORTED_ATTRIBUTE, /* pib get/set */
+	PHY_READ_ONLY, /* pib get/set */
+
+	PHY_INVAL = -1, /* all */
+	PHY_ERROR = -2, /* all */
+} phy_status_t;
+
+struct ieee802154_dev {
+	const char *name;
+	int	extra_tx_headroom; /* headroom to reserve for tx skb */
+	void	*priv;		/* driver-specific data */
+	u32	channel_mask;
+	u8	current_channel;
+	u32 flags; /* Flags for device to set */
+	struct device *parent;
+	struct net_device *netdev; /* mwpanX device */
+};
+
+/* Checksum is in hardware and is omitted from packet */
+#define IEEE802154_FLAGS_OMIT_CKSUM	(1 << 0)
+
+struct sk_buff;
+
+struct ieee802154_ops {
+	struct module	*owner;
+	phy_status_t (*tx)(struct ieee802154_dev *dev, struct sk_buff *skb);
+	phy_status_t (*cca)(struct ieee802154_dev *dev);
+	phy_status_t (*ed)(struct ieee802154_dev *dev, u8 *level);
+	phy_status_t (*set_trx_state)(struct ieee802154_dev *dev, phy_status_t state);
+	phy_status_t (*set_channel)(struct ieee802154_dev *dev, int channel);
+	/* FIXME: PIB get/set ??? */
+};
+
+struct ieee802154_dev *ieee802154_alloc_device(void);
+int ieee802154_register_device(struct ieee802154_dev *dev, struct ieee802154_ops *ops);
+void ieee802154_unregister_device(struct ieee802154_dev *dev);
+void ieee802154_free_device(struct ieee802154_dev *dev);
+
+int __deprecated ieee802154_add_slave(struct ieee802154_dev *hw, const u8 *addr);
+
+void ieee802154_rx(struct ieee802154_dev *dev, struct sk_buff *skb, u8 lqi);
+void ieee802154_rx_irqsafe(struct ieee802154_dev *dev, struct sk_buff *skb, u8 lqi);
+#endif
+
diff --git a/net/Kconfig b/net/Kconfig
index 7051b97..b42d325 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -180,6 +180,7 @@ source "net/econet/Kconfig"
 source "net/wanrouter/Kconfig"
 source "net/phonet/Kconfig"
 source "net/ieee802154/Kconfig"
+source "net/mac802154/Kconfig"
 source "net/sched/Kconfig"
 source "net/dcb/Kconfig"
 
diff --git a/net/Makefile b/net/Makefile
index ba324ae..81115f6 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -61,6 +61,7 @@ ifneq ($(CONFIG_DCB),)
 obj-y				+= dcb/
 endif
 obj-y				+= ieee802154/
+obj-y				+= mac802154/
 
 ifeq ($(CONFIG_NET),y)
 obj-$(CONFIG_SYSCTL)		+= sysctl_net.o
diff --git a/net/mac802154/Kconfig b/net/mac802154/Kconfig
new file mode 100644
index 0000000..4f0333a
--- /dev/null
+++ b/net/mac802154/Kconfig
@@ -0,0 +1,13 @@
+config MAC802154
+	tristate "Generic IEEE 802.15.4 Soft Networking Stack (mac802154)"
+	depends on IEEE802154 && EXPERIMENTAL
+	select CRC_ITU_T
+	---help---
+	  This option enables the hardware independent IEEE 802.15.4
+	  networking stack for SoftMAC devices (the ones implementing
+	  only PHY level of IEEE 802.15.4 standard).
+
+	  If you plan to use HardMAC IEEE 802.15.4 devices, you can
+          say N here. Alternatievly you can say M to compile it as
+	  module.
+
diff --git a/net/mac802154/Makefile b/net/mac802154/Makefile
new file mode 100644
index 0000000..253ae18
--- /dev/null
+++ b/net/mac802154/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_MAC802154) +=	mac802154.o
+mac802154-objs		:= main.o mdev.o pib.o dev.o mac_cmd.o scan.o \
+			beacon.o beacon_hash.o
+
+EXTRA_CFLAGS += -Wall -DDEBUG
diff --git a/net/mac802154/beacon.c b/net/mac802154/beacon.c
new file mode 100644
index 0000000..cb7cec3
--- /dev/null
+++ b/net/mac802154/beacon.c
@@ -0,0 +1,242 @@
+/*
+ * MAC beacon 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 <sergey.lapin@siemens.com>
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/if_arp.h>
+#include <linux/list.h>
+
+#include <net/ieee802154/af_ieee802154.h>
+#include <net/ieee802154/nl802154.h>
+#include <net/ieee802154/mac802154.h>
+#include <net/ieee802154/mac_def.h>
+#include <net/ieee802154/netdevice.h>
+
+#include "mac802154.h"
+#include "beacon.h"
+
+/* Beacon frame format per specification is the followinf:
+ * Standard MAC frame header:
+ * FC (2) SEQ (1)
+ * Addressing (4-20)
+ * Beacon fields:
+ * <Superframe specification> (2)
+ * <GTS> (?)
+ * <Pending address> (?)
+ * <Beacon payload> (?)
+ * FCS (2)
+ *
+ * Superframe specification:
+ * bit   Value
+ * 15    Association permit
+ * 14    PAN coordinator
+ * 13    Reserved
+ * 12    Battery life extension
+ * 8-11  Final CAP slot
+ * 4-7   Superframe order
+ * 0-3   Beacon order
+ *
+ * GTS:
+ * <GTS specification> (1)
+ * <GTS directions> (0-1)
+ * <GTS list> (?)
+ *
+ * Pending address:
+ * <Pending address specification> (1)
+ * <Pending address list (?)
+ *
+ * GTS specification:
+ * bit   Value
+ * 7     GTS permit
+ * 3-6   Reserved
+ * 0-2   GTS descriptor count
+ *
+ * Pending address specification:
+ * bit   Value
+ * 7     Reserved
+ * 4-6   Number of extended addresses pendinf
+ * 3     Reserved
+ * 0-2   Number of short addresses pending
+ * */
+
+#define IEEE802154_BEACON_SF_BO_BEACONLESS	(15 << 0)
+#define IEEE802154_BEACON_SF_SO(x)		((x & 0xf) << 4)
+#define IEEE802154_BEACON_SF_SO_INACTIVE		IEEE802154_BEACON_SF_SO(15)
+#define IEEE802154_BEACON_SF_PANCOORD		(1 << 14)
+#define IEEE802154_BEACON_SF_CANASSOC		(1 << 15)
+#define IEEE802154_BEACON_GTS_COUNT(x)		(x << 0)
+#define IEEE802154_BEACON_GTS_PERMIT		(1 << 7)
+#define IEEE802154_BEACON_PA_SHORT(x)		((x & 7) << 0)
+#define IEEE802154_BEACON_PA_LONG(x)		((x & 7) << 4)
+
+/* Flags parameter */
+#define IEEE802154_BEACON_FLAG_PANCOORD		(1 << 0)
+#define IEEE802154_BEACON_FLAG_CANASSOC		(1 << 1)
+#define IEEE802154_BEACON_FLAG_GTSPERMIT		(1 << 2)
+
+struct ieee802154_address_list {
+	struct list_head list;
+	struct ieee802154_addr addr;
+};
+/*
+ * @dev device
+ * @addr destination address
+ * @saddr source address
+ * @buf beacon payload
+ * @len beacon payload size
+ * @pan_coord - if we're PAN coordinator while sending this frame
+ * @gts_permit - wheather we allow GTS requests
+ * @al address list to be provided in beacon
+ *
+ * TODO:
+ * For a beacon frame, the sequence number field shall specify a BSN.
+ * Each coordinator shall store its current
+ * BSN value in the MAC PIB attribute macBSN and initialize it to a random value.
+ * The algorithm for choosing a random number is out of the scope
+ * of this standard. The coordinator shall copy the value of the macBSN
+ * attribute into the sequence number field of a beacon frame,
+ * each time one is generated, and shall then increment macBSN by one.
+ *
+*/
+
+
+int ieee802154_send_beacon(struct net_device *dev, struct ieee802154_addr *saddr,
+		u16 pan_id, const u8 *buf, int len,
+		int flags, struct list_head *al)
+{
+	struct sk_buff *skb;
+	int err;
+	u16 sf;
+	u8 gts;
+	u8 pa_spec;
+	int addr16_cnt;
+	int addr64_cnt;
+	struct ieee802154_addr addr;
+
+	BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+	skb = alloc_skb(LL_ALLOCATED_SPACE(dev) + len, GFP_ATOMIC);
+	if (!skb)
+		return -ENOMEM;
+
+	skb_reserve(skb, LL_RESERVED_SPACE(dev));
+
+	skb_reset_network_header(skb);
+
+	MAC_CB(skb)->flags = IEEE802154_FC_TYPE_BEACON;
+	MAC_CB(skb)->seq = IEEE802154_MLME_OPS(dev)->get_bsn(dev);
+
+	addr.addr_type = IEEE802154_ADDR_NONE;
+	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);
+
+	/* Superframe */
+	sf = IEEE802154_BEACON_SF_BO_BEACONLESS;
+	sf |= IEEE802154_BEACON_SF_SO_INACTIVE;
+	if (flags & IEEE802154_BEACON_FLAG_PANCOORD)
+		sf |= IEEE802154_BEACON_SF_PANCOORD;
+
+	if (flags & IEEE802154_BEACON_FLAG_CANASSOC)
+		sf |= IEEE802154_BEACON_SF_CANASSOC;
+	memcpy(skb_put(skb,  sizeof(sf)), &sf, sizeof(sf));
+
+	/* TODO GTS */
+	gts = 0;
+
+	if (flags & IEEE802154_BEACON_FLAG_GTSPERMIT)
+		gts |= IEEE802154_BEACON_GTS_PERMIT;
+	memcpy(skb_put(skb, sizeof(gts)), &gts, sizeof(gts));
+
+	/* FIXME pending address */
+	addr16_cnt = 0;
+	addr64_cnt = 0;
+
+	pa_spec = IEEE802154_BEACON_PA_LONG(addr64_cnt) | IEEE802154_BEACON_PA_SHORT(addr16_cnt);
+	memcpy(skb_put(skb, sizeof(pa_spec)), &pa_spec, sizeof(pa_spec));
+
+	memcpy(skb_put(skb, len), buf, len);
+
+	skb->dev = dev;
+	skb->protocol = htons(ETH_P_IEEE802154);
+
+	return dev_queue_xmit(skb);
+}
+
+/* at entry to this function we need skb->data to point to start
+ * of beacon field and MAC frame already parsed into MAC_CB */
+
+int parse_beacon_frame(struct sk_buff *skb, u8 *buf,
+		int *flags, struct list_head *al)
+{
+	int offt = 0;
+	u8 gts_spec;
+	u8 pa_spec;
+	struct ieee802154_pandsc *pd;
+	u16 sf = skb->data[0] + (skb->data[1] << 8);
+
+	pd = kzalloc(sizeof(struct ieee802154_pandsc), GFP_KERNEL);
+
+	/* Filling-up pre-parsed values */
+	pd->lqi = MAC_CB(skb)->lqi;
+	pd->sf = sf;
+	/* FIXME: make sure we do it right */
+	memcpy(&pd->addr, &MAC_CB(skb)->da, sizeof(struct ieee802154_addr));
+
+	/* Supplying our nitifiers with data */
+	ieee802154_slave_event(skb->dev, IEEE802154_NOTIFIER_BEACON, pd);
+	ieee802154_nl_beacon_indic(skb->dev, pd->addr.pan_id, pd->addr.short_addr);
+	/* FIXME: We don't cache PAN descriptors yet */
+	kfree(pd);
+
+	offt += 2;
+	gts_spec = skb->data[offt++];
+	/* FIXME !!! */
+	if ((gts_spec & 7) != 0) {
+		pr_debug("We still don't parse GTS part properly");
+		return -ENOTSUPP;
+	}
+	pa_spec = skb->data[offt++];
+	/* FIXME !!! */
+	if (pa_spec != 0) {
+		pr_debug("We still don't parse PA part properly");
+		return -ENOTSUPP;
+	}
+
+	*flags = 0;
+
+	if (sf & IEEE802154_BEACON_SF_PANCOORD)
+		*flags |= IEEE802154_BEACON_FLAG_PANCOORD;
+
+	if (sf & IEEE802154_BEACON_SF_CANASSOC)
+		*flags |= IEEE802154_BEACON_FLAG_CANASSOC;
+	BUG_ON(skb->len - offt < 0);
+	/* FIXME */
+	if (buf && (skb->len - offt > 0))
+		memcpy(buf, skb->data + offt, skb->len - offt);
+	return 0;
+}
+
diff --git a/net/mac802154/beacon.h b/net/mac802154/beacon.h
new file mode 100644
index 0000000..0fedc93
--- /dev/null
+++ b/net/mac802154/beacon.h
@@ -0,0 +1,48 @@
+/*
+ * beacon.h
+ *
+ * Copyright (C) 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:
+ * Pavel Smolenskiy <pavel.smolenskiy@gmail.com>
+ * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
+ */
+
+#ifndef IEEE802154_BEACON_H
+#define IEEE802154_BEACON_H
+
+/* Per spec; optimizations are needed */
+struct ieee802154_pandsc {
+	struct list_head	list;
+	struct ieee802154_addr	addr; /* Contains panid */
+	int			channel;
+	u16			sf;
+	bool			gts_permit;
+	u8			lqi;
+/* FIXME: Aging of stored PAN descriptors is not decided yet,
+ * because no PAN descriptor storage is implemented yet */
+	u32			timestamp;
+};
+
+int parse_beacon_frame(struct sk_buff *skb, u8 * buf,
+		int *flags, struct list_head *al);
+
+int ieee802154_send_beacon(struct net_device *dev, struct ieee802154_addr *saddr,
+		u16 pan_id, const u8 *buf, int len,
+		int flags, struct list_head *al);
+
+#endif /* IEEE802154_BEACON_H */
+
diff --git a/net/mac802154/beacon_hash.c b/net/mac802154/beacon_hash.c
new file mode 100644
index 0000000..90ea801
--- /dev/null
+++ b/net/mac802154/beacon_hash.c
@@ -0,0 +1,103 @@
+/*
+ * MAC beacon hash storage
+ *
+ * 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 <sergey.lapin@siemens.com>
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ */
+
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+
+#include <net/ieee802154/af_ieee802154.h>
+
+#include "beacon_hash.h"
+
+static struct hlist_head beacon_hash[IEEE802154_BEACON_HTABLE_SIZE];
+static DEFINE_RWLOCK(beacon_hash_lock);
+
+static int beacon_hashfn(struct ieee802154_addr *coord_addr, u16 pan_addr)
+{
+	return pan_addr % IEEE802154_BEACON_HTABLE_SIZE;
+}
+
+static void __beacon_add_node(struct ieee802154_addr *coord_addr, u16 pan_addr)
+{
+	struct beacon_node *node = kzalloc(sizeof(struct beacon_node), GFP_KERNEL);
+	struct hlist_head *list = &beacon_hash[beacon_hashfn(coord_addr, pan_addr)];
+	memcpy(&node->coord_addr, coord_addr, sizeof(struct ieee802154_addr));
+	node->pan_addr = pan_addr;
+	INIT_HLIST_NODE(&node->list);
+	hlist_add_head(&node->list, list);
+}
+
+struct beacon_node *ieee802154_beacon_find_pan(struct ieee802154_addr *coord_addr,
+						u16 pan_addr)
+{
+	struct hlist_head *list;
+	struct hlist_node *tmp;
+	list = &beacon_hash[beacon_hashfn(coord_addr, pan_addr)];
+	if (hlist_empty(list))
+		return NULL;
+	hlist_for_each(tmp, list) {
+		struct beacon_node *entry = hlist_entry(tmp, struct beacon_node, list);
+		if (entry->pan_addr == pan_addr)
+			return entry;
+	}
+	return NULL;
+}
+
+void ieee802154_beacon_hash_add(struct ieee802154_addr *coord_addr)
+{
+	if (!ieee802154_beacon_find_pan(coord_addr, coord_addr->pan_id)) {
+		write_lock(&beacon_hash_lock);
+		__beacon_add_node(coord_addr, coord_addr->pan_id);
+		write_unlock(&beacon_hash_lock);
+	}
+}
+
+void ieee802154_beacon_hash_del(struct ieee802154_addr *coord_addr)
+{
+	struct beacon_node *entry = ieee802154_beacon_find_pan(coord_addr,
+								coord_addr->pan_id);
+	if (!entry)
+		return;
+	write_lock(&beacon_hash_lock);
+	hlist_del(&entry->list);
+	write_unlock(&beacon_hash_lock);
+	kfree(entry);
+}
+
+void ieee802154_beacon_hash_dump(void)
+{
+	int i;
+	struct hlist_node *tmp;
+	pr_debug("beacon hash dump begin\n");
+	read_lock(&beacon_hash_lock);
+	for (i = 0; i < IEEE802154_BEACON_HTABLE_SIZE; i++) {
+		struct beacon_node *entry;
+		hlist_for_each(tmp, &beacon_hash[i]) {
+			entry = hlist_entry(tmp, struct beacon_node, list);
+			pr_debug("PAN: %d\n", entry->pan_addr);
+		}
+	}
+	read_unlock(&beacon_hash_lock);
+	pr_debug("beacon hash dump end\n");
+}
+
diff --git a/net/mac802154/beacon_hash.h b/net/mac802154/beacon_hash.h
new file mode 100644
index 0000000..db8457c
--- /dev/null
+++ b/net/mac802154/beacon_hash.h
@@ -0,0 +1,40 @@
+/*
+ * MAC beacon hash storage
+ *
+ * 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 <sergey.lapin@siemens.com>
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ */
+
+#ifndef IEEE802154_BEACON_HASH_H
+#define IEEE802154_BEACON_HASH_H
+
+#define IEEE802154_BEACON_HTABLE_SIZE 256
+
+struct beacon_node {
+	struct hlist_node list;
+	struct ieee802154_addr coord_addr;
+	u16 pan_addr;
+};
+struct beacon_node *ieee802154_beacon_find_pan(struct ieee802154_addr *coord_addr,
+			u16 pan_addr);
+void ieee802154_beacon_hash_add(struct ieee802154_addr *coord_addr);
+void ieee802154_beacon_hash_del(struct ieee802154_addr *coord_addr);
+void ieee802154_beacon_hash_dump(void);
+#endif
+
diff --git a/net/mac802154/dev.c b/net/mac802154/dev.c
new file mode 100644
index 0000000..4e3f70f
--- /dev/null
+++ b/net/mac802154/dev.c
@@ -0,0 +1,843 @@
+/*
+ * 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:
+ * Sergey Lapin <sergey.lapin@siemens.com>
+ * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
+ */
+
+#include <linux/net.h>
+#include <linux/capability.h>
+#include <linux/module.h>
+#include <linux/if_arp.h>
+#include <linux/termios.h>	/* For TIOCOUTQ/INQ */
+#include <linux/notifier.h>
+#include <linux/random.h>
+#include <linux/crc-itu-t.h>
+#include <net/datalink.h>
+#include <net/psnap.h>
+#include <net/sock.h>
+#include <net/tcp_states.h>
+#include <net/route.h>
+
+#include <net/ieee802154/af_ieee802154.h>
+#include <net/ieee802154/mac802154.h>
+#include <net/ieee802154/netdevice.h>
+#include <net/ieee802154/mac_def.h>
+
+#include "mac802154.h"
+#include "beacon.h"
+#include "beacon_hash.h"
+#include "mib.h"
+
+struct ieee802154_netdev_priv {
+	struct list_head list;
+	struct ieee802154_priv *hw;
+	struct net_device *dev;
+
+	__le16 pan_id;
+	__le16 short_addr;
+
+	u8 chan;
+
+	/* MAC BSN field */
+	u8 bsn;
+	/* MAC BSN field */
+	u8 dsn;
+
+	/* This one is used to provide notifications */
+	struct blocking_notifier_head events;
+};
+
+static int ieee802154_net_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ieee802154_netdev_priv *priv;
+	priv = netdev_priv(dev);
+
+	if (!(priv->hw->hw.flags & IEEE802154_FLAGS_OMIT_CKSUM)) {
+		u16 crc = bitrev16(crc_itu_t_bitreversed(0, skb->data, skb->len));
+		u8 *data = skb_put(skb, 2);
+		data[0] = crc & 0xff;
+		data[1] = crc >> 8;
+	}
+
+	PHY_CB(skb)->chan = priv->chan;
+
+	skb->iif = dev->ifindex;
+	skb->dev = priv->hw->hw.netdev;
+	dev->stats.tx_packets++;
+	dev->stats.tx_bytes += skb->len;
+
+	dev->trans_start = jiffies;
+	dev_queue_xmit(skb);
+
+	return 0;
+}
+
+static int ieee802154_slave_open(struct net_device *dev)
+{
+	struct ieee802154_netdev_priv *priv;
+	priv = netdev_priv(dev);
+	netif_start_queue(dev);
+	return 0;
+}
+
+static int ieee802154_slave_close(struct net_device *dev)
+{
+	struct ieee802154_netdev_priv *priv;
+	dev->priv_flags &= ~IFF_IEEE802154_COORD;
+	netif_stop_queue(dev);
+	priv = netdev_priv(dev);
+	netif_stop_queue(dev);
+	return 0;
+}
+
+
+static int ieee802154_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct ieee802154_netdev_priv *priv = netdev_priv(dev);
+	struct sockaddr_ieee802154 *sa = (struct sockaddr_ieee802154 *)&ifr->ifr_addr;
+	switch (cmd) {
+	case SIOCGIFADDR:
+		if (priv->pan_id == IEEE802154_PANID_BROADCAST || priv->short_addr == IEEE802154_ADDR_BROADCAST)
+			return -EADDRNOTAVAIL;
+
+		sa->family = AF_IEEE802154;
+		sa->addr.addr_type = IEEE802154_ADDR_SHORT;
+		sa->addr.pan_id = priv->pan_id;
+		sa->addr.short_addr = priv->short_addr;
+		return 0;
+	case SIOCSIFADDR:
+		dev_warn(&dev->dev, "Using DEBUGing ioctl SIOCSIFADDR isn't recommened!\n");
+		if (sa->family != AF_IEEE802154 || sa->addr.addr_type != IEEE802154_ADDR_SHORT ||
+			sa->addr.pan_id == IEEE802154_PANID_BROADCAST || sa->addr.short_addr == IEEE802154_ADDR_BROADCAST || sa->addr.short_addr == IEEE802154_ADDR_UNDEF)
+			return -EINVAL;
+
+		priv->pan_id = sa->addr.pan_id;
+		priv->short_addr = sa->addr.short_addr;
+		return 0;
+	}
+	return -ENOIOCTLCMD;
+}
+
+static int ieee802154_slave_mac_addr(struct net_device *dev, void *p)
+{
+	struct sockaddr *addr = p;
+
+	if (netif_running(dev))
+		return -EBUSY;
+	/* FIXME: validate addr */
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+	return 0;
+}
+
+static int ieee802154_header_create(struct sk_buff *skb, struct net_device *dev,
+			   unsigned short type, const void *_daddr,
+			   const void *_saddr, unsigned len)
+{
+	u8 head[24] = {};
+	int pos = 0;
+
+	u16 fc;
+	const struct ieee802154_addr *saddr = _saddr;
+	const struct ieee802154_addr *daddr = _daddr;
+	struct ieee802154_addr dev_addr;
+	struct ieee802154_netdev_priv *priv = netdev_priv(dev);
+
+	fc = MAC_CB_TYPE(skb);
+	if (MAC_CB_IS_ACKREQ(skb))
+		fc |= IEEE802154_FC_ACK_REQ;
+
+	pos = 2;
+
+	head[pos++] = MAC_CB(skb)->seq; /* DSN/BSN */
+
+	if (!daddr)
+		return -EINVAL;
+
+	if (!saddr) {
+		if (priv->short_addr == IEEE802154_ADDR_BROADCAST || priv->short_addr == IEEE802154_ADDR_UNDEF || priv->pan_id == IEEE802154_PANID_BROADCAST) {
+			dev_addr.addr_type = IEEE802154_ADDR_LONG;
+			memcpy(dev_addr.hwaddr, dev->dev_addr, IEEE802154_ADDR_LEN);
+		} else {
+			dev_addr.addr_type = IEEE802154_ADDR_SHORT;
+			dev_addr.short_addr = priv->short_addr;
+		}
+
+		dev_addr.pan_id = priv->pan_id;
+		saddr = &dev_addr;
+	}
+
+	if (daddr->addr_type != IEEE802154_ADDR_NONE) {
+		fc |= (daddr->addr_type << IEEE802154_FC_DAMODE_SHIFT);
+
+		head[pos++] = daddr->pan_id & 0xff;
+		head[pos++] = daddr->pan_id >> 8;
+
+		if (daddr->addr_type == IEEE802154_ADDR_SHORT) {
+			head[pos++] = daddr->short_addr & 0xff;
+			head[pos++] = daddr->short_addr >> 8;
+		} else {
+			memcpy(head + pos, daddr->hwaddr, IEEE802154_ADDR_LEN);
+			pos += IEEE802154_ADDR_LEN;
+		}
+	}
+
+	if (saddr->addr_type != IEEE802154_ADDR_NONE) {
+		fc |= (saddr->addr_type << IEEE802154_FC_SAMODE_SHIFT);
+
+		if ((saddr->pan_id == daddr->pan_id) && (saddr->pan_id != IEEE802154_PANID_BROADCAST))
+			fc |= IEEE802154_FC_INTRA_PAN; /* PANID compression/ intra PAN */
+		else {
+			head[pos++] = saddr->pan_id & 0xff;
+			head[pos++] = saddr->pan_id >> 8;
+		}
+
+		if (saddr->addr_type == IEEE802154_ADDR_SHORT) {
+			head[pos++] = saddr->short_addr & 0xff;
+			head[pos++] = saddr->short_addr >> 8;
+		} else {
+			memcpy(head + pos, saddr->hwaddr, IEEE802154_ADDR_LEN);
+			pos += IEEE802154_ADDR_LEN;
+		}
+	}
+
+	head[0] = fc;
+	head[1] = fc >> 8;
+
+	memcpy(skb_push(skb, pos), head, pos);
+
+	return pos;
+}
+
+static int ieee802154_header_parse(const struct sk_buff *skb, unsigned char *haddr)
+{
+	const u8 *hdr = skb_mac_header(skb), *tail = skb_tail_pointer(skb);
+	struct ieee802154_addr *addr = (struct ieee802154_addr *)haddr;
+	u16 fc;
+	int da_type;
+
+	if (hdr + 3 > tail)
+		goto malformed;
+
+	fc = hdr[0] | (hdr[1] << 8);
+
+	hdr += 3;
+
+	da_type = IEEE802154_FC_DAMODE(fc);
+	addr->addr_type = IEEE802154_FC_SAMODE(fc);
+
+	switch (da_type) {
+	case IEEE802154_ADDR_NONE:
+		if (fc & IEEE802154_FC_INTRA_PAN)
+			goto malformed;
+		break;
+
+	case IEEE802154_ADDR_LONG:
+		if (hdr + 2 > tail)
+			goto malformed;
+		if (fc & IEEE802154_FC_INTRA_PAN) {
+			addr->pan_id = hdr[0] | (hdr[1] << 8);
+			hdr += 2;
+		}
+
+		if (hdr + IEEE802154_ADDR_LEN > tail)
+			goto malformed;
+		hdr += IEEE802154_ADDR_LEN;
+		break;
+
+	case IEEE802154_ADDR_SHORT:
+		if (hdr + 2 > tail)
+			goto malformed;
+		if (fc & IEEE802154_FC_INTRA_PAN) {
+			addr->pan_id = hdr[0] | (hdr[1] << 8);
+			hdr += 2;
+		}
+
+		if (hdr + 2 > tail)
+			goto malformed;
+		hdr += 2;
+		break;
+
+	default:
+		goto malformed;
+
+	}
+
+	switch (addr->addr_type) {
+	case IEEE802154_ADDR_NONE:
+		break;
+
+	case IEEE802154_ADDR_LONG:
+		if (hdr + 2 > tail)
+			goto malformed;
+		if (!(fc & IEEE802154_FC_INTRA_PAN)) {
+			addr->pan_id = hdr[0] | (hdr[1] << 8);
+			hdr += 2;
+		}
+
+		if (hdr + IEEE802154_ADDR_LEN > tail)
+			goto malformed;
+		memcpy(addr->hwaddr, hdr, IEEE802154_ADDR_LEN);
+		hdr += IEEE802154_ADDR_LEN;
+		break;
+
+	case IEEE802154_ADDR_SHORT:
+		if (hdr + 2 > tail)
+			goto malformed;
+		if (!(fc & IEEE802154_FC_INTRA_PAN)) {
+			addr->pan_id = hdr[0] | (hdr[1] << 8);
+			hdr += 2;
+		}
+
+		if (hdr + 2 > tail)
+			goto malformed;
+		addr->short_addr = hdr[0] | (hdr[1] << 8);
+		hdr += 2;
+		break;
+
+	default:
+		goto malformed;
+
+	}
+
+	return sizeof(struct ieee802154_addr);
+
+malformed:
+	pr_debug("malformed packet\n");
+	return 0;
+}
+
+static struct header_ops ieee802154_header_ops = {
+	.create		= ieee802154_header_create,
+	.parse		= ieee802154_header_parse,
+};
+
+static void ieee802154_netdev_setup(struct net_device *dev)
+{
+	dev->addr_len		= IEEE802154_ADDR_LEN;
+	memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN);
+	dev->features		= NETIF_F_NO_CSUM;
+	dev->hard_header_len	= 2 + 1 + 20 + 14;
+	dev->header_ops		= &ieee802154_header_ops;
+	dev->needed_tailroom	= 2; /* FCS */
+	dev->mtu		= 127;
+	dev->tx_queue_len	= 10;
+	dev->type		= ARPHRD_IEEE802154;
+	dev->flags		= IFF_NOARP | IFF_BROADCAST;
+	dev->watchdog_timeo	= 0;
+}
+
+static const struct net_device_ops ieee802154_slave_ops = {
+	.ndo_open		= ieee802154_slave_open,
+	.ndo_stop		= ieee802154_slave_close,
+	.ndo_start_xmit		= ieee802154_net_xmit,
+	.ndo_do_ioctl		= ieee802154_slave_ioctl,
+	.ndo_set_mac_address	= ieee802154_slave_mac_addr,
+};
+
+int ieee802154_add_slave(struct ieee802154_dev *hw, const u8 *addr)
+{
+	struct net_device *dev;
+	struct ieee802154_netdev_priv *priv;
+	struct ieee802154_priv *ipriv = ieee802154_to_priv(hw);
+	int err;
+
+	ASSERT_RTNL();
+
+	dev = alloc_netdev(sizeof(struct ieee802154_netdev_priv),
+			"wpan%d", ieee802154_netdev_setup);
+	if (!dev) {
+		printk(KERN_ERR "Failure to initialize IEEE802154 device\n");
+		return -ENOMEM;
+	}
+	priv = netdev_priv(dev);
+	priv->dev = dev;
+	priv->hw = ipriv;
+
+	get_random_bytes(&priv->bsn, 1);
+	get_random_bytes(&priv->dsn, 1);
+
+	BLOCKING_INIT_NOTIFIER_HEAD(&priv->events);
+	memcpy(dev->dev_addr, addr, dev->addr_len);
+	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+	dev->priv_flags = IFF_SLAVE_INACTIVE;
+	dev->netdev_ops = &ieee802154_slave_ops;
+	dev->ml_priv = &mac802154_mlme;
+
+	priv->pan_id = IEEE802154_PANID_BROADCAST;
+	priv->short_addr = IEEE802154_ADDR_BROADCAST;
+
+	dev_hold(ipriv->hw.netdev);
+
+	dev->needed_headroom = ipriv->hw.extra_tx_headroom;
+
+	spin_lock(&ipriv->slaves_lock);
+	list_add_tail(&priv->list, &ipriv->slaves);
+	spin_unlock(&ipriv->slaves_lock);
+	/*
+	 * If the name is a format string the caller wants us to do a
+	 * name allocation.
+	 */
+	if (strchr(dev->name, '%')) {
+		err = dev_alloc_name(dev, dev->name);
+		if (err < 0)
+			goto out;
+	}
+
+	SET_NETDEV_DEV(dev, &ipriv->hw.netdev->dev);
+
+	err = register_netdevice(dev);
+	if (err < 0)
+		goto out;
+
+	return dev->ifindex;
+out:
+	return err;
+}
+EXPORT_SYMBOL(ieee802154_add_slave);
+
+static void __ieee802154_del_slave(struct ieee802154_netdev_priv *ndp)
+{
+	struct net_device *dev = ndp->dev;
+	dev_put(ndp->hw->hw.netdev);
+	unregister_netdev(ndp->dev);
+
+	spin_lock(&ndp->hw->slaves_lock);
+	list_del(&ndp->list);
+	spin_unlock(&ndp->hw->slaves_lock);
+
+	free_netdev(dev);
+}
+
+void ieee802154_drop_slaves(struct ieee802154_dev *hw)
+{
+	struct ieee802154_priv *priv = ieee802154_to_priv(hw);
+	struct ieee802154_netdev_priv *ndp, *next;
+
+	spin_lock(&priv->slaves_lock);
+	list_for_each_entry_safe(ndp, next, &priv->slaves, list) {
+		spin_unlock(&priv->slaves_lock);
+		__ieee802154_del_slave(ndp);
+		spin_lock(&priv->slaves_lock);
+	}
+	spin_unlock(&priv->slaves_lock);
+}
+
+static int ieee802154_send_ack(struct sk_buff *skb)
+{
+	u16 fc = IEEE802154_FC_TYPE_ACK;
+	u8 *data;
+	struct sk_buff *ackskb;
+
+	BUG_ON(!skb || !skb->dev);
+	BUG_ON(!MAC_CB_IS_ACKREQ(skb));
+
+	ackskb = alloc_skb(LL_ALLOCATED_SPACE(skb->dev) + 3, GFP_ATOMIC);
+
+	skb_reserve(ackskb, LL_RESERVED_SPACE(skb->dev));
+
+	skb_reset_network_header(ackskb);
+
+	data = skb_push(ackskb, 3);
+	data[0] = fc & 0xff;
+	data[1] = (fc >> 8) & 0xff;
+	data[2] = MAC_CB(skb)->seq;
+
+	skb_reset_mac_header(ackskb);
+
+	ackskb->dev = skb->dev;
+	pr_debug("ACK frame to %s device\n", skb->dev->name);
+	ackskb->protocol = htons(ETH_P_IEEE802154);
+	/* FIXME */
+
+	return dev_queue_xmit(ackskb);
+}
+
+static int ieee802154_process_beacon(struct net_device *dev, struct sk_buff *skb)
+{
+	int flags;
+	int ret;
+	ret = parse_beacon_frame(skb, NULL, &flags, NULL);
+
+	/* Here we have cb->sa = coordinator address, and PAN address */
+
+	if (ret < 0) {
+		ret = NET_RX_DROP;
+		goto fail;
+	}
+	dev_dbg(&dev->dev, "got beacon from pan %d\n", MAC_CB(skb)->sa.pan_id);
+	ieee802154_beacon_hash_add(&MAC_CB(skb)->sa);
+	ieee802154_beacon_hash_dump();
+	ret = NET_RX_SUCCESS;
+fail:
+	kfree_skb(skb);
+	return ret;
+}
+
+static int ieee802154_process_ack(struct net_device *dev, struct sk_buff *skb)
+{
+	pr_debug("got ACK for SEQ=%d\n", MAC_CB(skb)->seq);
+
+	kfree_skb(skb);
+	return NET_RX_SUCCESS;
+}
+
+static int ieee802154_process_data(struct net_device *dev, struct sk_buff *skb)
+{
+	return netif_rx(skb);
+}
+
+static int ieee802154_subif_frame(struct ieee802154_netdev_priv *ndp, struct sk_buff *skb)
+{
+	pr_debug("%s Getting packet via slave interface %s\n",
+				__func__, ndp->dev->name);
+
+	switch (MAC_CB(skb)->da.addr_type) {
+	case IEEE802154_ADDR_NONE:
+		if (MAC_CB(skb)->sa.addr_type != IEEE802154_ADDR_NONE)
+			/* FIXME: check if we are PAN coordinator :) */
+			skb->pkt_type = PACKET_OTHERHOST;
+		else
+			/* ACK comes with both addresses empty */
+			skb->pkt_type = PACKET_HOST;
+		break;
+	case IEEE802154_ADDR_LONG:
+		if (MAC_CB(skb)->da.pan_id != ndp->pan_id && MAC_CB(skb)->da.pan_id != IEEE802154_PANID_BROADCAST)
+			skb->pkt_type = PACKET_OTHERHOST;
+		else if (!memcmp(MAC_CB(skb)->da.hwaddr, ndp->dev->dev_addr, IEEE802154_ADDR_LEN))
+			skb->pkt_type = PACKET_HOST;
+		else if (!memcmp(MAC_CB(skb)->da.hwaddr, ndp->dev->broadcast, IEEE802154_ADDR_LEN))
+			/* FIXME: is this correct? */
+			skb->pkt_type = PACKET_BROADCAST;
+		else
+			skb->pkt_type = PACKET_OTHERHOST;
+		break;
+	case IEEE802154_ADDR_SHORT:
+		if (MAC_CB(skb)->da.pan_id != ndp->pan_id && MAC_CB(skb)->da.pan_id != IEEE802154_PANID_BROADCAST)
+			skb->pkt_type = PACKET_OTHERHOST;
+		else if (MAC_CB(skb)->da.short_addr == ndp->short_addr)
+			skb->pkt_type = PACKET_HOST;
+		else if (MAC_CB(skb)->da.short_addr == IEEE802154_ADDR_BROADCAST)
+			skb->pkt_type = PACKET_BROADCAST;
+		else
+			skb->pkt_type = PACKET_OTHERHOST;
+		break;
+	}
+
+	skb->dev = ndp->dev;
+
+	if (MAC_CB_IS_ACKREQ(skb))
+		ieee802154_send_ack(skb);
+
+	switch (MAC_CB_TYPE(skb)) {
+	case IEEE802154_FC_TYPE_BEACON:
+		return ieee802154_process_beacon(ndp->dev, skb);
+	case IEEE802154_FC_TYPE_ACK:
+		return ieee802154_process_ack(ndp->dev, skb);
+	case IEEE802154_FC_TYPE_MAC_CMD:
+		return ieee802154_process_cmd(ndp->dev, skb);
+	case IEEE802154_FC_TYPE_DATA:
+		return ieee802154_process_data(ndp->dev, skb);
+	default:
+		pr_warning("ieee802154: Bad frame received (type = %d)\n", MAC_CB_TYPE(skb));
+		kfree_skb(skb);
+		return NET_RX_DROP;
+	}
+}
+
+static u8 fetch_skb_u8(struct sk_buff *skb)
+{
+	u8 ret;
+
+	BUG_ON(skb->len < 1);
+
+	ret = skb->data[0];
+	skb_pull(skb, 1);
+
+	return ret;
+}
+
+static u16 fetch_skb_u16(struct sk_buff *skb)
+{
+	u16 ret;
+
+	BUG_ON(skb->len < 2);
+
+	ret = skb->data[0] + (skb->data[1] * 256);
+	skb_pull(skb, 2);
+	return ret;
+}
+
+static void fetch_skb_u64(struct sk_buff *skb, void *data)
+{
+	BUG_ON(skb->len < IEEE802154_ADDR_LEN);
+
+	memcpy(data, skb->data, IEEE802154_ADDR_LEN);
+	skb_pull(skb, IEEE802154_ADDR_LEN);
+}
+
+#define IEEE802154_FETCH_U8(skb, var)		\
+	do {					\
+		if (skb->len < 1)		\
+			goto exit_error;	\
+		var = fetch_skb_u8(skb);	\
+	} while (0)
+
+#define IEEE802154_FETCH_U16(skb, var)		\
+	do {					\
+		if (skb->len < 2)		\
+			goto exit_error;	\
+		var = fetch_skb_u16(skb);	\
+	} while (0)
+
+#define IEEE802154_FETCH_U64(skb, var)			\
+	do {						\
+		if (skb->len < IEEE802154_ADDR_LEN)	\
+			goto exit_error;		\
+		fetch_skb_u64(skb, &var);		\
+	} while (0)
+
+static int parse_frame_start(struct sk_buff *skb)
+{
+	u8 *head = skb->data;
+	u16 fc;
+
+	if (skb->len < 3) {
+		pr_debug("frame size %d bytes is too short\n", skb->len);
+		return -EINVAL;
+	}
+
+	IEEE802154_FETCH_U16(skb, fc);
+	IEEE802154_FETCH_U8(skb, MAC_CB(skb)->seq);
+
+	pr_debug("%s: %04x dsn%02x\n", __func__, fc, head[2]);
+
+	MAC_CB(skb)->flags = IEEE802154_FC_TYPE(fc);
+
+	if (fc & IEEE802154_FC_ACK_REQ) {
+		pr_debug("%s(): ACKNOWLEDGE required\n", __func__);
+		MAC_CB(skb)->flags |= MAC_CB_FLAG_ACKREQ;
+	}
+
+	if (fc & IEEE802154_FC_SECEN)
+		MAC_CB(skb)->flags |= MAC_CB_FLAG_SECEN;
+
+	if (fc & IEEE802154_FC_INTRA_PAN)
+		MAC_CB(skb)->flags |= MAC_CB_FLAG_INTRAPAN;
+
+	/* TODO */
+	if (MAC_CB_IS_SECEN(skb)) {
+		pr_info("security support is not implemented\n");
+		return -EINVAL;
+	}
+
+	MAC_CB(skb)->sa.addr_type = IEEE802154_FC_SAMODE(fc);
+	if (MAC_CB(skb)->sa.addr_type == IEEE802154_ADDR_NONE)
+		pr_debug("%s(): src addr_type is NONE\n", __func__);
+
+	MAC_CB(skb)->da.addr_type = IEEE802154_FC_DAMODE(fc);
+	if (MAC_CB(skb)->da.addr_type == IEEE802154_ADDR_NONE)
+		pr_debug("%s(): dst addr_type is NONE\n", __func__);
+
+	if (IEEE802154_FC_TYPE(fc) == IEEE802154_FC_TYPE_ACK) {
+		/* ACK can only have NONE-type addresses */
+		if (MAC_CB(skb)->sa.addr_type != IEEE802154_ADDR_NONE ||
+		    MAC_CB(skb)->da.addr_type != IEEE802154_ADDR_NONE)
+			return -EINVAL;
+	}
+
+	if (MAC_CB(skb)->da.addr_type != IEEE802154_ADDR_NONE) {
+		IEEE802154_FETCH_U16(skb, MAC_CB(skb)->da.pan_id);
+
+		if (MAC_CB_IS_INTRAPAN(skb)) { /* ! panid compress */
+			pr_debug("%s(): src IEEE802154_FC_INTRA_PAN\n", __func__);
+			MAC_CB(skb)->sa.pan_id = MAC_CB(skb)->da.pan_id;
+			pr_debug("%s(): src PAN address %04x\n",
+					__func__, MAC_CB(skb)->sa.pan_id);
+		}
+
+		pr_debug("%s(): dst PAN address %04x\n",
+				__func__, MAC_CB(skb)->da.pan_id);
+
+		if (MAC_CB(skb)->da.addr_type == IEEE802154_ADDR_SHORT) {
+			IEEE802154_FETCH_U16(skb, MAC_CB(skb)->da.short_addr);
+			pr_debug("%s(): dst SHORT address %04x\n",
+					__func__, MAC_CB(skb)->da.short_addr);
+
+		} else {
+			IEEE802154_FETCH_U64(skb, MAC_CB(skb)->da.hwaddr);
+			pr_debug("%s(): dst hardware addr\n", __func__);
+		}
+	}
+
+	if (MAC_CB(skb)->sa.addr_type != IEEE802154_ADDR_NONE) {
+		pr_debug("%s(): got src non-NONE address\n", __func__);
+		if (!(MAC_CB_IS_INTRAPAN(skb))) { /* ! panid compress */
+			IEEE802154_FETCH_U16(skb, MAC_CB(skb)->sa.pan_id);
+			pr_debug("%s(): src IEEE802154_FC_INTRA_PAN\n", __func__);
+		}
+
+		if (MAC_CB(skb)->sa.addr_type == IEEE802154_ADDR_SHORT) {
+			IEEE802154_FETCH_U16(skb, MAC_CB(skb)->sa.short_addr);
+			pr_debug("%s(): src IEEE802154_ADDR_SHORT\n", __func__);
+		} else {
+			IEEE802154_FETCH_U64(skb, MAC_CB(skb)->sa.hwaddr);
+			pr_debug("%s(): src hardware addr\n", __func__);
+		}
+	}
+
+	return 0;
+
+exit_error:
+	return -EINVAL;
+}
+
+void ieee802154_subif_rx(struct ieee802154_dev *hw, struct sk_buff *skb)
+{
+	struct ieee802154_priv *priv = ieee802154_to_priv(hw);
+	struct ieee802154_netdev_priv *ndp, *prev = NULL;
+	int ret;
+
+	BUILD_BUG_ON(sizeof(struct ieee802154_mac_cb) > sizeof(skb->cb));
+	pr_debug("%s()\n", __func__);
+
+	ret = parse_frame_start(skb); /* 3 bytes pulled after this */
+	if (ret) {
+		pr_debug("%s(): Got invalid frame\n", __func__);
+		goto out;
+	}
+
+	if (!(priv->hw.flags & IEEE802154_FLAGS_OMIT_CKSUM)) {
+		if (skb->len < 2) {
+			pr_debug("%s(): Got invalid frame\n", __func__);
+			goto out;
+		}
+		/* FIXME: check CRC if necessary */
+		skb_trim(skb, skb->len - 2); /* CRC */
+	}
+
+	pr_debug("%s() frame %d\n", __func__, MAC_CB_TYPE(skb));
+
+	spin_lock(&priv->slaves_lock);
+	list_for_each_entry(ndp, &priv->slaves, list)
+	{
+		if (prev) {
+			struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
+			if (skb2)
+				ieee802154_subif_frame(prev, skb2);
+		}
+
+		prev = ndp;
+	}
+
+	if (prev)
+		ieee802154_subif_frame(prev, skb);
+	else
+		kfree_skb(skb);
+	spin_unlock(&priv->slaves_lock);
+
+	return;
+
+out:
+	kfree_skb(skb);
+	return;
+}
+
+u16 ieee802154_dev_get_pan_id(struct net_device *dev)
+{
+	struct ieee802154_netdev_priv *priv = netdev_priv(dev);
+
+	BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+	return priv->pan_id;
+}
+
+u16 ieee802154_dev_get_short_addr(struct net_device *dev)
+{
+	struct ieee802154_netdev_priv *priv = netdev_priv(dev);
+
+	BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+	return priv->short_addr;
+}
+
+void ieee802154_dev_set_pan_id(struct net_device *dev, u16 val)
+{
+	struct ieee802154_netdev_priv *priv = netdev_priv(dev);
+
+	BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+	priv->pan_id = val;
+}
+void ieee802154_dev_set_short_addr(struct net_device *dev, u16 val)
+{
+	struct ieee802154_netdev_priv *priv = netdev_priv(dev);
+
+	BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+	priv->short_addr = val;
+}
+void ieee802154_dev_set_channel(struct net_device *dev, u8 val)
+{
+	struct ieee802154_netdev_priv *priv = netdev_priv(dev);
+
+	BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+	priv->chan = val;
+}
+
+u8 ieee802154_dev_get_dsn(struct net_device *dev)
+{
+	struct ieee802154_netdev_priv *priv = netdev_priv(dev);
+
+	BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+	return priv->dsn++;
+}
+
+u8 ieee802154_dev_get_bsn(struct net_device *dev)
+{
+	struct ieee802154_netdev_priv *priv = netdev_priv(dev);
+
+	BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+	return priv->bsn++;
+}
+
+int ieee802154_slave_register_notifier(struct net_device *dev, struct notifier_block *nb)
+{
+	struct ieee802154_netdev_priv *priv = netdev_priv(dev);
+	return blocking_notifier_chain_register(&priv->events, nb);
+}
+int ieee802154_slave_unregister_notifier(struct net_device *dev, struct notifier_block *nb)
+{
+	struct ieee802154_netdev_priv *priv = netdev_priv(dev);
+	return blocking_notifier_chain_unregister(&priv->events, nb);
+}
+int ieee802154_slave_event(struct net_device *dev, int event, void *data)
+{
+	struct ieee802154_netdev_priv *priv = netdev_priv(dev);
+	return blocking_notifier_call_chain(&priv->events, event, data);
+}
+
+struct ieee802154_priv *ieee802154_slave_get_priv(struct net_device *dev)
+{
+	struct ieee802154_netdev_priv *priv = netdev_priv(dev);
+	BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+	return priv->hw;
+}
diff --git a/net/mac802154/mac802154.h b/net/mac802154/mac802154.h
new file mode 100644
index 0000000..2f346cd
--- /dev/null
+++ b/net/mac802154/mac802154.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 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:
+ * Pavel Smolenskiy <pavel.smolenskiy@gmail.com>
+ * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ */
+#ifndef MAC802154_H
+#define MAC802154_H
+
+struct ieee802154_priv {
+	struct ieee802154_dev	hw;
+	struct ieee802154_ops	*ops;
+	struct list_head	slaves;
+	spinlock_t		slaves_lock;
+	/* This one is used for scanning and other
+	 * jobs not to be interfered with serial driver */
+	struct workqueue_struct	*dev_workqueue;
+};
+
+#define ieee802154_to_priv(_hw)	container_of(_hw, struct ieee802154_priv, hw)
+
+void ieee802154_drop_slaves(struct ieee802154_dev *hw);
+
+void ieee802154_subif_rx(struct ieee802154_dev *hw, struct sk_buff *skb);
+
+struct ieee802154_phy_cb {
+	u8 lqi;
+	u8 chan;
+};
+
+#define PHY_CB(skb)	((struct ieee802154_phy_cb *)(skb)->cb)
+
+extern struct ieee802154_mlme_ops mac802154_mlme;
+
+int ieee802154_mlme_scan_req(struct net_device *dev, u8 type, u32 channels, u8 duration);
+
+int ieee802154_process_cmd(struct net_device *dev, struct sk_buff *skb);
+int ieee802154_send_beacon_req(struct net_device *dev);
+
+struct ieee802154_priv *ieee802154_slave_get_priv(struct net_device *dev);
+
+/* FIXME: this interface should be rethought ! */
+struct notifier_block;
+int ieee802154_slave_register_notifier(struct net_device *dev, struct notifier_block *nb);
+int ieee802154_slave_unregister_notifier(struct net_device *dev, struct notifier_block *nb);
+int ieee802154_slave_event(struct net_device *dev, int event, void *data);
+#define IEEE802154_NOTIFIER_BEACON		0x0
+
+#endif
diff --git a/net/mac802154/mac_cmd.c b/net/mac802154/mac_cmd.c
new file mode 100644
index 0000000..0be38fb
--- /dev/null
+++ b/net/mac802154/mac_cmd.c
@@ -0,0 +1,325 @@
+/*
+ * 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 <sergey.lapin@siemens.com>
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <net/ieee802154/af_ieee802154.h>
+#include <net/ieee802154/mac802154.h>
+#include <net/ieee802154/mac_def.h>
+#include <net/ieee802154/netdevice.h>
+#include <net/ieee802154/nl802154.h>
+
+#include "mac802154.h"
+#include "beacon.h"
+#include "mib.h"
+
+static int ieee802154_cmd_beacon_req(struct sk_buff *skb)
+{
+	struct ieee802154_addr saddr; /* jeez */
+	int flags = 0;
+	if (skb->len != 1)
+		return -EINVAL;
+
+	if (skb->pkt_type != PACKET_HOST)
+		return 0;
+
+	/* Checking if we're really PAN coordinator
+	 * before sending beacons */
+	if (!(skb->dev->priv_flags & IFF_IEEE802154_COORD))
+		return 0;
+
+	if (MAC_CB(skb)->sa.addr_type != IEEE802154_ADDR_NONE ||
+	    MAC_CB(skb)->da.addr_type != IEEE802154_ADDR_SHORT ||
+	    MAC_CB(skb)->da.pan_id != IEEE802154_PANID_BROADCAST ||
+	    MAC_CB(skb)->da.short_addr != IEEE802154_ADDR_BROADCAST)
+		return -EINVAL;
+
+
+	/* 7 bytes of MHR and 1 byte of command frame identifier
+	 * We have no information in this command to proceed with.
+	 * we need to submit beacon as answer to this. */
+
+	return ieee802154_send_beacon(skb->dev, &saddr, IEEE802154_MLME_OPS(skb->dev)->get_pan_id(skb->dev),
+			NULL, 0, flags, NULL);
+}
+
+static int ieee802154_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 ieee802154_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) {
+		ieee802154_dev_set_short_addr(skb->dev, IEEE802154_ADDR_BROADCAST);
+		ieee802154_dev_set_pan_id(skb->dev, IEEE802154_PANID_BROADCAST);
+	} else
+		ieee802154_dev_set_short_addr(skb->dev, short_addr);
+
+	return ieee802154_nl_assoc_confirm(skb->dev, short_addr, status);
+}
+
+static int ieee802154_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 ieee802154_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("Command %02x on device %s\n", cmd, dev->name);
+
+	switch (cmd) {
+	case IEEE802154_CMD_ASSOCIATION_REQ:
+		ieee802154_cmd_assoc_req(skb);
+		break;
+	case IEEE802154_CMD_ASSOCIATION_RESP:
+		ieee802154_cmd_assoc_resp(skb);
+		break;
+	case IEEE802154_CMD_DISASSOCIATION_NOTIFY:
+		ieee802154_cmd_disassoc_notify(skb);
+		break;
+	case IEEE802154_CMD_BEACON_REQ:
+		ieee802154_cmd_beacon_req(skb);
+		break;
+	default:
+		pr_debug("Frame type is not supported yet\n");
+		goto drop;
+	}
+
+
+	kfree_skb(skb);
+	return NET_RX_SUCCESS;
+
+drop:
+	kfree_skb(skb);
+	return NET_RX_DROP;
+}
+
+static int ieee802154_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;
+
+	BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+	skb = alloc_skb(LL_ALLOCATED_SPACE(dev) + len, GFP_KERNEL);
+	if (!skb)
+		return -ENOMEM;
+
+	skb_reserve(skb, LL_RESERVED_SPACE(dev));
+
+	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);
+}
+
+int ieee802154_send_beacon_req(struct net_device *dev)
+{
+	struct ieee802154_addr addr;
+	struct ieee802154_addr saddr;
+	u8 cmd = IEEE802154_CMD_BEACON_REQ;
+	addr.addr_type = IEEE802154_ADDR_SHORT;
+	addr.short_addr = IEEE802154_ADDR_BROADCAST;
+	addr.pan_id = IEEE802154_PANID_BROADCAST;
+	saddr.addr_type = IEEE802154_ADDR_NONE;
+	return ieee802154_send_cmd(dev, &addr, &saddr, &cmd, 1);
+}
+
+
+static int ieee802154_mlme_assoc_req(struct net_device *dev, struct ieee802154_addr *addr, u8 channel, 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 */
+	ieee802154_dev_set_pan_id(dev, addr->pan_id);
+	ieee802154_dev_set_channel(dev, channel);
+
+	buf[pos++] = IEEE802154_CMD_ASSOCIATION_REQ;
+	buf[pos++] = cap;
+
+	return ieee802154_send_cmd(dev, addr, &saddr, buf, pos);
+}
+
+static int ieee802154_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 ieee802154_send_cmd(dev, addr, &saddr, buf, pos);
+}
+
+static int ieee802154_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 = ieee802154_send_cmd(dev, addr, &saddr, buf, pos);
+
+	/* FIXME: this should be after the ack receved */
+	ieee802154_dev_set_pan_id(dev, 0xffff);
+	ieee802154_dev_set_short_addr(dev, 0xffff);
+	ieee802154_nl_disassoc_confirm(dev, 0x00);
+
+	return ret;
+}
+
+static int ieee802154_mlme_start_req(struct net_device *dev, struct ieee802154_addr *addr,
+				u8 channel,
+				u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx,
+				u8 coord_realign)
+{
+	BUG_ON(addr->addr_type != IEEE802154_ADDR_SHORT);
+
+	ieee802154_dev_set_pan_id(dev, addr->pan_id);
+	ieee802154_dev_set_short_addr(dev, addr->short_addr);
+	ieee802154_dev_set_channel(dev, 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;
+
+	return 0;
+}
+
+struct ieee802154_mlme_ops mac802154_mlme = {
+	.assoc_req = ieee802154_mlme_assoc_req,
+	.assoc_resp = ieee802154_mlme_assoc_resp,
+	.disassoc_req = ieee802154_mlme_disassoc_req,
+	.start_req = ieee802154_mlme_start_req,
+	.scan_req = ieee802154_mlme_scan_req,
+
+	.get_pan_id = ieee802154_dev_get_pan_id,
+	.get_short_addr = ieee802154_dev_get_short_addr,
+	.get_dsn = ieee802154_dev_get_dsn,
+	.get_bsn = ieee802154_dev_get_bsn,
+};
+
diff --git a/net/mac802154/main.c b/net/mac802154/main.c
new file mode 100644
index 0000000..1dbace4
--- /dev/null
+++ b/net/mac802154/main.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 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:
+ * Pavel Smolenskiy <pavel.smolenskiy@gmail.com>
+ * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/workqueue.h>
+#include <linux/netdevice.h>
+
+#include <net/ieee802154/mac802154.h>
+
+#include "mac802154.h"
+
+static void __ieee802154_rx_prepare(struct ieee802154_dev *dev, struct sk_buff *skb, u8 lqi)
+{
+	struct ieee802154_priv *priv = ieee802154_to_priv(dev);
+
+	BUG_ON(!skb);
+
+	PHY_CB(skb)->lqi = lqi;
+
+	skb->dev = priv->hw.netdev;
+
+	skb->iif = skb->dev->ifindex;
+
+	skb->protocol = htons(ETH_P_IEEE802154);
+
+	skb_reset_mac_header(skb);
+}
+
+void ieee802154_rx(struct ieee802154_dev *dev, struct sk_buff *skb, u8 lqi)
+{
+	struct sk_buff *skb2;
+
+	__ieee802154_rx_prepare(dev, skb, lqi);
+
+	skb2 = skb_clone(skb, GFP_KERNEL);
+	netif_rx(skb2);
+
+	ieee802154_subif_rx(dev, skb);
+}
+EXPORT_SYMBOL(ieee802154_rx);
+
+struct rx_work {
+	struct sk_buff *skb;
+	struct work_struct work;
+	struct ieee802154_dev *dev;
+};
+
+static void ieee802154_rx_worker(struct work_struct *work)
+{
+	struct rx_work *rw = container_of(work, struct rx_work, work);
+	struct sk_buff *skb = rw->skb;
+
+	struct sk_buff *skb2 = skb_clone(skb, GFP_KERNEL);
+	netif_rx(skb2);
+
+	ieee802154_subif_rx(rw->dev, skb);
+	kfree(rw);
+}
+
+void ieee802154_rx_irqsafe(struct ieee802154_dev *dev, struct sk_buff *skb, u8 lqi)
+{
+	struct ieee802154_priv *priv = ieee802154_to_priv(dev);
+	struct rx_work *work = kzalloc(sizeof(struct rx_work), GFP_ATOMIC);
+
+	if (!work)
+		return;
+
+	__ieee802154_rx_prepare(dev, skb, lqi);
+
+	INIT_WORK(&work->work, ieee802154_rx_worker);
+	work->skb = skb;
+	work->dev = dev;
+
+	queue_work(priv->dev_workqueue, &work->work);
+}
+EXPORT_SYMBOL(ieee802154_rx_irqsafe);
diff --git a/net/mac802154/mdev.c b/net/mac802154/mdev.c
new file mode 100644
index 0000000..3bebe22
--- /dev/null
+++ b/net/mac802154/mdev.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+
+#include <net/ieee802154/af_ieee802154.h>
+#include <net/ieee802154/mac802154.h>
+
+#include "mac802154.h"
+
+struct xmit_work {
+	struct sk_buff *skb;
+	struct work_struct work;
+	struct ieee802154_priv *priv;
+};
+
+static void ieee802154_xmit_worker(struct work_struct *work)
+{
+	struct xmit_work *xw = container_of(work, struct xmit_work, work);
+	phy_status_t res;
+
+	if (xw->priv->hw.current_channel != PHY_CB(xw->skb)->chan) {
+		res = xw->priv->ops->set_channel(&xw->priv->hw, PHY_CB(xw->skb)->chan);
+		if (res != PHY_SUCCESS) {
+			pr_debug("set_channel failed\n");
+			goto out;
+		}
+	}
+
+	res = xw->priv->ops->cca(&xw->priv->hw);
+	if (res != PHY_IDLE) {
+		pr_debug("CCA failed\n");
+		goto out;
+	}
+
+	res = xw->priv->ops->set_trx_state(&xw->priv->hw, PHY_TX_ON);
+	if (res != PHY_SUCCESS && res != PHY_TX_ON) {
+		pr_debug("set_trx_state returned %d\n", res);
+		goto out;
+	}
+
+	res = xw->priv->ops->tx(&xw->priv->hw, xw->skb);
+
+out:
+	/* FIXME: result processing and/or requeue!!! */
+	dev_kfree_skb(xw->skb);
+
+	xw->priv->ops->set_trx_state(&xw->priv->hw, PHY_RX_ON);
+	kfree(xw);
+}
+
+static int ieee802154_master_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ieee802154_priv *priv = netdev_priv(dev);
+	struct xmit_work *work;
+
+	if (skb_cow_head(skb, priv->hw.extra_tx_headroom)) {
+		dev_kfree_skb(skb);
+		return NETDEV_TX_OK;
+	}
+
+	work = kzalloc(sizeof(struct xmit_work), GFP_ATOMIC);
+	if (!work)
+		return NETDEV_TX_BUSY;
+
+	INIT_WORK(&work->work, ieee802154_xmit_worker);
+	work->skb = skb;
+	work->priv = priv;
+
+	queue_work(priv->dev_workqueue, &work->work);
+
+	return NETDEV_TX_OK;
+}
+
+static int ieee802154_master_open(struct net_device *dev)
+{
+	struct ieee802154_priv *priv;
+	phy_status_t status;
+	priv = netdev_priv(dev);
+	if (!priv) {
+		pr_debug("%s:%s: unable to get master private data\n",
+				__FILE__, __func__);
+		return -ENODEV;
+	}
+	status = priv->ops->set_trx_state(&priv->hw, PHY_RX_ON);
+	if (status != PHY_SUCCESS) {
+		pr_debug("set_trx_state returned %d\n", status);
+		return -EBUSY;
+	}
+
+	netif_start_queue(dev);
+	return 0;
+}
+
+static int ieee802154_master_close(struct net_device *dev)
+{
+	struct ieee802154_priv *priv;
+	netif_stop_queue(dev);
+	priv = netdev_priv(dev);
+
+	priv->ops->set_trx_state(&priv->hw, PHY_FORCE_TRX_OFF);
+	return 0;
+}
+static int ieee802154_master_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct ieee802154_priv *priv = netdev_priv(dev);
+	switch (cmd) {
+	case IEEE802154_SIOC_ADD_SLAVE:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		return ieee802154_add_slave(&priv->hw, (u8 *) &ifr->ifr_hwaddr.sa_data);
+	}
+	return -ENOIOCTLCMD;
+}
+
+static void ieee802154_netdev_setup_master(struct net_device *dev)
+{
+	dev->addr_len		= 0;
+	memset(dev->broadcast, 0xff, dev->addr_len);
+	dev->features		= NETIF_F_NO_CSUM;
+	dev->hard_header_len	= 0;
+	dev->mtu		= 127;
+	dev->tx_queue_len	= 0;
+	dev->type		= ARPHRD_IEEE802154_PHY;
+	dev->flags		= IFF_NOARP | IFF_BROADCAST;
+	dev->watchdog_timeo	= 0;
+}
+static ssize_t ieee802154_netdev_show(const struct device *dev,
+			   struct device_attribute *attr, char *buf,
+			   ssize_t (*format)(const struct net_device *, char *))
+{
+	struct net_device *netdev = to_net_dev(dev);
+	ssize_t ret = -EINVAL;
+
+	if (netdev->reg_state <= NETREG_REGISTERED)
+		ret = (*format)(netdev, buf);
+
+	return ret;
+}
+#define MASTER_SHOW(field, format_string)				\
+static ssize_t format_##field(const struct net_device *dev, char *buf)	\
+{									\
+	struct ieee802154_priv *priv = netdev_priv(dev);		\
+	return sprintf(buf, format_string, priv->hw.field);		\
+}									\
+static ssize_t show_##field(struct device *dev,				\
+			    struct device_attribute *attr, char *buf)	\
+{									\
+	return ieee802154_netdev_show(dev, attr, buf, format_##field);	\
+}									\
+static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL)
+
+static const char fmt_long_hex[] = "%#lx\n";
+static const char fmt_hex[] = "%#x\n";
+static const char fmt_dec[] = "%d\n";
+
+MASTER_SHOW(current_channel, fmt_dec);
+MASTER_SHOW(channel_mask, fmt_hex);
+
+static struct attribute *pmib_attrs[] = {
+	&dev_attr_current_channel.attr,
+	&dev_attr_channel_mask.attr,
+	NULL
+};
+
+static struct attribute_group pmib_group = {
+	.name  = "pib",
+	.attrs  = pmib_attrs,
+};
+
+static const struct net_device_ops ieee802154_master_ops = {
+	.ndo_open		= ieee802154_master_open,
+	.ndo_stop		= ieee802154_master_close,
+	.ndo_start_xmit		= ieee802154_master_hard_start_xmit,
+	.ndo_do_ioctl		= ieee802154_master_ioctl,
+};
+
+static int ieee802154_register_netdev_master(struct ieee802154_priv *priv)
+{
+	struct net_device *dev = priv->hw.netdev;
+
+	dev->netdev_ops = &ieee802154_master_ops;
+	dev->needed_headroom = priv->hw.extra_tx_headroom;
+	SET_NETDEV_DEV(dev, priv->hw.parent);
+
+	dev->sysfs_groups[1] = &pmib_group;
+
+	register_netdev(dev);
+
+	return 0;
+}
+
+struct ieee802154_dev *ieee802154_alloc_device(void)
+{
+	struct net_device *dev;
+	struct ieee802154_priv *priv;
+
+	dev = alloc_netdev(sizeof(struct ieee802154_priv),
+			"mwpan%d", ieee802154_netdev_setup_master);
+	if (!dev) {
+		printk(KERN_ERR "Failure to initialize master IEEE802154 device\n");
+		return NULL;
+	}
+	priv = netdev_priv(dev);
+	priv->hw.netdev = dev;
+
+	INIT_LIST_HEAD(&priv->slaves);
+	spin_lock_init(&priv->slaves_lock);
+	return &priv->hw;
+}
+EXPORT_SYMBOL(ieee802154_alloc_device);
+
+void ieee802154_free_device(struct ieee802154_dev *hw)
+{
+	struct ieee802154_priv *priv = ieee802154_to_priv(hw);
+
+	BUG_ON(!list_empty(&priv->slaves));
+	BUG_ON(!priv->hw.netdev);
+
+	free_netdev(priv->hw.netdev);
+}
+EXPORT_SYMBOL(ieee802154_free_device);
+
+int ieee802154_register_device(struct ieee802154_dev *dev, struct ieee802154_ops *ops)
+{
+	struct ieee802154_priv *priv = ieee802154_to_priv(dev);
+	int rc;
+
+	if (!try_module_get(ops->owner))
+		return -EFAULT;
+
+	BUG_ON(!dev || !dev->name);
+	BUG_ON(!ops || !ops->tx || !ops->cca || !ops->ed || !ops->set_trx_state);
+
+	priv->ops = ops;
+	rc = ieee802154_register_netdev_master(priv);
+	if (rc < 0)
+		goto out;
+	priv->dev_workqueue = create_singlethread_workqueue(priv->hw.netdev->name);
+	if (!priv->dev_workqueue)
+		goto out_wq;
+
+	return 0;
+
+out_wq:
+	unregister_netdev(priv->hw.netdev);
+out:
+	return rc;
+}
+EXPORT_SYMBOL(ieee802154_register_device);
+
+void ieee802154_unregister_device(struct ieee802154_dev *dev)
+{
+	struct ieee802154_priv *priv = ieee802154_to_priv(dev);
+
+	ieee802154_drop_slaves(dev);
+	unregister_netdev(priv->hw.netdev);
+	flush_workqueue(priv->dev_workqueue);
+	destroy_workqueue(priv->dev_workqueue);
+	module_put(priv->ops->owner);
+}
+EXPORT_SYMBOL(ieee802154_unregister_device);
+
+MODULE_DESCRIPTION("IEEE 802.15.4 implementation");
+MODULE_LICENSE("GPL v2");
+
diff --git a/net/mac802154/mib.h b/net/mac802154/mib.h
new file mode 100644
index 0000000..57bf03f
--- /dev/null
+++ b/net/mac802154/mib.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 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.
+ *
+ */
+
+#ifndef MIB802154_H
+#define MIB802154_H
+
+/* FIXME: should be dropped in favour of generic MIB API */
+u8 ieee802154_dev_get_dsn(struct net_device *dev);
+u8 ieee802154_dev_get_bsn(struct net_device *dev);
+u16 ieee802154_dev_get_pan_id(struct net_device *dev);
+u16 ieee802154_dev_get_short_addr(struct net_device *dev);
+void ieee802154_dev_set_pan_id(struct net_device *dev, u16 val);
+void ieee802154_dev_set_short_addr(struct net_device *dev, u16 val);
+void ieee802154_dev_set_channel(struct net_device *dev, u8 chan);
+
+
+#endif
diff --git a/net/mac802154/pib.c b/net/mac802154/pib.c
new file mode 100644
index 0000000..29fc75e
--- /dev/null
+++ b/net/mac802154/pib.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <net/ieee802154/mac802154.h>
+
+#include "mac802154.h"
+#include "pib.h"
+
+int ieee802154_pib_set(struct ieee802154_dev *hw, struct ieee802154_pib *pib)
+{
+	int ret;
+	struct ieee802154_priv *priv = ieee802154_to_priv(hw);
+	BUG_ON(!hw);
+	BUG_ON(!pib);
+	switch (pib->type) {
+	case IEEE802154_PIB_CURCHAN:
+#warning this should go via usual workqueue!!!
+		/* Our internal mask is inverted
+		 * 0 = channel is available
+		 * 1 = channel is unavailable
+		 * this saves initialization */
+		if (hw->channel_mask & (1 << (pib->val - 1)))
+			return -EINVAL;
+		ret = priv->ops->set_channel(hw, pib->val);
+		if (ret == PHY_ERROR)
+			return -EINVAL; /* FIXME */
+		hw->current_channel =  pib->val;
+		break;
+	case IEEE802154_PIB_CHANSUPP:
+		hw->channel_mask = ~(pib->val);
+		break;
+	case IEEE802154_PIB_TRPWR:
+		/* TODO */
+		break;
+	case IEEE802154_PIB_CCAMODE:
+		/* TODO */
+		break;
+	default:
+		pr_debug("Unknown PIB type value\n");
+		return -ENOTSUPP;
+	}
+	return 0;
+}
+
+int ieee802154_pib_get(struct ieee802154_dev *hw, struct ieee802154_pib *pib)
+{
+	BUG_ON(!hw);
+	BUG_ON(!pib);
+	switch (pib->type) {
+	case IEEE802154_PIB_CURCHAN:
+		pib->val = hw->current_channel;
+		break;
+	case IEEE802154_PIB_CHANSUPP:
+		pib->val = ~(hw->channel_mask);
+		break;
+	case IEEE802154_PIB_TRPWR:
+		pib->val = 0;
+		break;
+	case IEEE802154_PIB_CCAMODE:
+		pib->val = 0;
+		break;
+	default:
+		pr_debug("Unknown PIB type value\n");
+		return -ENOTSUPP;
+	}
+	return 0;
+}
+
diff --git a/net/mac802154/pib.h b/net/mac802154/pib.h
new file mode 100644
index 0000000..6593fa1
--- /dev/null
+++ b/net/mac802154/pib.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 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.
+ *
+ */
+
+#ifndef PIB802154_H
+#define PIB802154_H
+
+struct ieee802154_pib {
+	int type;
+	u32 val;
+};
+
+#define IEEE802154_PIB_CURCHAN	0 /* Current channel, u8 6.1.2 */
+#define IEEE802154_PIB_CHANSUPP	1 /* Channel mask, u32 6.1.2 */
+#define IEEE802154_PIB_TRPWR	2 /* Transmit power, u8 6.4.2  */
+#define IEEE802154_PIB_CCAMODE	3 /* CCA mode, u8 6.7.9 */
+
+int ieee802154_pib_set(struct ieee802154_dev *hw, struct ieee802154_pib *pib);
+int ieee802154_pib_get(struct ieee802154_dev *hw, struct ieee802154_pib *pib);
+
+#endif
diff --git a/net/mac802154/scan.c b/net/mac802154/scan.c
new file mode 100644
index 0000000..89e0c9f
--- /dev/null
+++ b/net/mac802154/scan.c
@@ -0,0 +1,215 @@
+/*
+ * scan.c
+ *
+ * Description: MAC scan helper functions.
+ *
+ * Copyright (C) 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:
+ * Pavel Smolenskiy <pavel.smolenskiy@gmail.com>
+ * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
+ */
+#include <linux/net.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+
+#include <net/ieee802154/af_ieee802154.h>
+#include <net/ieee802154/mac802154.h>
+#include <net/ieee802154/nl802154.h>
+#include <net/ieee802154/mac_def.h>
+#include <net/ieee802154/netdevice.h>
+
+#include "mac802154.h"
+#include "beacon.h"
+
+/*
+ * ED scan is periodic issuing of ed device function
+ * on evry permitted channel, so it is virtually PHY-only scan */
+
+struct scan_work {
+	struct work_struct work;
+
+	int (*scan_ch)(struct scan_work *work, int channel, u8 duration);
+	struct net_device *dev;
+
+	u8 edl[27];
+
+	u8 type;
+	u32 channels;
+	u8 duration;
+};
+
+static int scan_ed(struct scan_work *work, int channel, u8 duration)
+{
+	int ret;
+	struct ieee802154_priv *hw = ieee802154_slave_get_priv(work->dev);
+	pr_debug("ed scan channel %d duration %d\n", channel, duration);
+	ret = hw->ops->ed(&hw->hw, &work->edl[channel]);
+	pr_debug("ed scan channel %d value %d\n", channel, work->edl[channel]);
+	return ret;
+}
+
+struct scan_data {
+	struct notifier_block nb;
+	struct list_head scan_head;
+};
+
+static int beacon_notifier(struct notifier_block *p,
+		unsigned long event, void *data)
+{
+	struct ieee802154_pandsc *pd = data;
+	struct scan_data *sd = container_of(p, struct scan_data, nb);
+	switch (event) {
+	case IEEE802154_NOTIFIER_BEACON:
+		/* TODO: add item to list here */
+		pr_debug("got a beacon frame addr_type %d pan_id %d\n",
+				pd->addr.addr_type, pd->addr.pan_id);
+		break;
+	}
+	return 0;
+}
+
+
+static int scan_passive(struct scan_work *work, int channel, u8 duration)
+{
+	unsigned long j;
+	struct scan_data *data = kzalloc(sizeof(struct scan_data), GFP_KERNEL);
+	pr_debug("passive scan channel %d duration %d\n", channel, duration);
+	data->nb.notifier_call = beacon_notifier;
+	ieee802154_slave_register_notifier(work->dev, &data->nb);
+	/* Hope 2 msecs will be enough for scan */
+	j = msecs_to_jiffies(2);
+	while (j > 0)
+		j = schedule_timeout(j);
+
+	ieee802154_slave_unregister_notifier(work->dev, &data->nb);
+	kfree(data);
+	return PHY_SUCCESS;
+}
+
+/* Active scan is periodic submission of beacon request
+ * and waiting for beacons which is useful for collecting LWPAN information */
+static int scan_active(struct scan_work *work, int channel, u8 duration)
+{
+	int ret;
+	pr_debug("active scan channel %d duration %d\n", channel, duration);
+	ret = ieee802154_send_beacon_req(work->dev);
+	if (ret < 0)
+		return PHY_ERROR;
+	return scan_passive(work, channel, duration);
+}
+
+static int scan_orphan(struct scan_work *work, int channel, u8 duration)
+{
+	pr_debug("orphan scan channel %d duration %d\n", channel, duration);
+	return 0;
+}
+
+static void scanner(struct work_struct *work)
+{
+	struct scan_work *sw = container_of(work, struct scan_work, work);
+	struct ieee802154_priv *hw = ieee802154_slave_get_priv(sw->dev);
+	int i;
+	phy_status_t ret;
+
+	for (i = 0; i < 27; i++) {
+		if (!(sw->channels & (1 << i)))
+			continue;
+
+		ret = hw->ops->set_channel(&hw->hw,  i);
+		if (ret != PHY_SUCCESS)
+			goto exit_error;
+
+		ret = sw->scan_ch(sw, i, sw->duration);
+		if (ret != PHY_SUCCESS)
+			goto exit_error;
+
+		sw->channels &= ~(1 << i);
+	}
+
+	ieee802154_nl_scan_confirm(sw->dev, IEEE802154_SUCCESS, sw->type, sw->channels,
+			sw->edl/*, NULL */);
+
+	kfree(sw);
+
+	return;
+
+exit_error:
+	ieee802154_nl_scan_confirm(sw->dev, IEEE802154_INVALID_PARAMETER, sw->type, sw->channels,
+			NULL/*, NULL */);
+	kfree(sw);
+	return;
+}
+
+/*
+ * Alloc ed_detect list for ED scan.
+ *
+ * @param mac current mac pointer
+ * @param type type of the scan to be performed
+ * @param channels 32-bit mask of requested to scan channels
+ * @param duration scan duration, see ieee802.15.4-2003.pdf, page 145.
+ * @return 0 if request is ok, errno otherwise.
+ */
+int ieee802154_mlme_scan_req(struct net_device *dev, u8 type, u32 channels, u8 duration)
+{
+	struct ieee802154_priv *hw = ieee802154_slave_get_priv(dev);
+	struct scan_work *work;
+
+	pr_debug("%s()\n", __func__);
+
+	if (duration > 14)
+		goto inval;
+	if (channels & hw->hw.channel_mask)
+		goto inval;
+
+	work = kzalloc(sizeof(struct scan_work), GFP_KERNEL);
+	if (!work)
+		goto inval;
+
+	work->dev = dev;
+	work->channels = channels;
+	work->duration = duration;
+	work->type = type;
+
+	switch (type) {
+	case IEEE802154_MAC_SCAN_ED:
+		work->scan_ch = scan_ed;
+		break;
+	case IEEE802154_MAC_SCAN_ACTIVE:
+		work->scan_ch = scan_active;
+		break;
+	case IEEE802154_MAC_SCAN_PASSIVE:
+		work->scan_ch = scan_passive;
+		break;
+	case IEEE802154_MAC_SCAN_ORPHAN:
+		work->scan_ch = scan_orphan;
+		break;
+	default:
+		pr_debug("%s(): invalid type %d\n", __func__, type);
+		goto inval;
+	}
+
+	INIT_WORK(&work->work, scanner);
+	queue_work(hw->dev_workqueue, &work->work);
+
+	return 0;
+
+inval:
+	ieee802154_nl_scan_confirm(dev, IEEE802154_INVALID_PARAMETER, type, channels,
+			NULL/*, NULL */);
+	return -EINVAL;
+}
+
-- 
1.6.2.4


^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [PATCH 07/10] ieee802154: add virtual loopback driver
@ 2009-06-01 14:54               ` Dmitry Eremin-Solenikov
  0 siblings, 0 replies; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-01 14:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: netdev, linux-wireless, slapin, maxim.osipov, dmitry.baryshkov,
	oliver.fendt, Dmitry Eremin-Solenikov

fakelb is a virtual loopback driver implementing one or several
interconnected radios. Packets from the radio are either sent
back to the node (if no other fake radio are registered) or to
all other fake radio.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Signed-off-by: Sergey Lapin <slapin@ossfans.org>
---
 drivers/ieee802154/Kconfig  |   11 ++
 drivers/ieee802154/Makefile |    1 +
 drivers/ieee802154/fakelb.c |  335 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 347 insertions(+), 0 deletions(-)
 create mode 100644 drivers/ieee802154/fakelb.c

diff --git a/drivers/ieee802154/Kconfig b/drivers/ieee802154/Kconfig
index 8610620..d1799e3 100644
--- a/drivers/ieee802154/Kconfig
+++ b/drivers/ieee802154/Kconfig
@@ -19,5 +19,16 @@ config IEEE802154_FAKEHARD
           This driver can also be built as a module. To do so say M here.
 	  The module will be called 'fakehard'.
 
+
+if IEEE802154_DRIVERS && MAC802154
+config IEEE802154_FAKELB
+	tristate "Fake LR-WPAN driver with several interconnected devices"
+	---help---
+	  Say Y here to enable the fake driver that can emulate a net
+          of several interconnected radio devices.
+
+          This driver can also be built as a module. To do so say M here.
+	  The module will be called 'fakelb'.
+
 endif
 
diff --git a/drivers/ieee802154/Makefile b/drivers/ieee802154/Makefile
index e0e8e1a..2bd7bdf 100644
--- a/drivers/ieee802154/Makefile
+++ b/drivers/ieee802154/Makefile
@@ -1,3 +1,4 @@
 obj-$(CONFIG_IEEE802154_FAKEHARD) += fakehard.o
+obj-$(CONFIG_IEEE802154_FAKELB) += fakelb.o
 
 EXTRA_CFLAGS += -DDEBUG -DCONFIG_FFD
diff --git a/drivers/ieee802154/fakelb.c b/drivers/ieee802154/fakelb.c
new file mode 100644
index 0000000..7c00f07
--- /dev/null
+++ b/drivers/ieee802154/fakelb.c
@@ -0,0 +1,335 @@
+/*
+ * Loopback IEEE 802.15.4 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 <sergey.lapin@siemens.com>
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ */
+
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/platform_device.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/spinlock.h>
+#include <net/ieee802154/mac802154.h>
+
+struct fake_dev_priv {
+	struct ieee802154_dev *dev;
+	phy_status_t cur_state, pend_state;
+
+	struct list_head list;
+	struct fake_priv *fake;
+};
+
+struct fake_priv {
+	struct list_head list;
+	rwlock_t lock;
+};
+
+static int is_transmitting(struct ieee802154_dev *dev)
+{
+	return 0;
+}
+
+static int is_receiving(struct ieee802154_dev *dev)
+{
+	return 0;
+}
+
+static phy_status_t
+hw_ed(struct ieee802154_dev *dev, u8 *level)
+{
+	pr_debug("%s\n", __func__);
+	might_sleep();
+	BUG_ON(!level);
+	*level = 0xbe;
+	return PHY_SUCCESS;
+}
+
+static phy_status_t
+hw_cca(struct ieee802154_dev *dev)
+{
+	pr_debug("%s\n", __func__);
+	might_sleep();
+	return PHY_IDLE;
+}
+
+static phy_status_t
+hw_state(struct ieee802154_dev *dev, phy_status_t state)
+{
+	struct fake_dev_priv *priv = dev->priv;
+	pr_debug("%s %d %d\n", __func__, priv->cur_state, state);
+	might_sleep();
+	if (state != PHY_TRX_OFF && state != PHY_RX_ON && state != PHY_TX_ON && state != PHY_FORCE_TRX_OFF)
+		return PHY_INVAL;
+	else if (state == PHY_FORCE_TRX_OFF) {
+		priv->cur_state = PHY_TRX_OFF;
+		return PHY_SUCCESS;
+	} else if (priv->cur_state == state)
+		return state;
+	else if ((state == PHY_TRX_OFF || state == PHY_RX_ON) && is_transmitting(dev)) {
+		priv->pend_state = state;
+		return PHY_BUSY_TX;
+	} else if ((state == PHY_TRX_OFF || state == PHY_TX_ON) && is_receiving(dev)) {
+		priv->pend_state = state;
+		return PHY_BUSY_RX;
+	} else {
+		priv->cur_state = state;
+		return PHY_SUCCESS;
+	}
+}
+
+static phy_status_t
+hw_channel(struct ieee802154_dev *dev, int channel)
+{
+	pr_debug("%s %d\n", __func__, channel);
+	might_sleep();
+	dev->current_channel = channel;
+	return PHY_SUCCESS;
+}
+
+static void
+hw_deliver(struct fake_dev_priv *priv, struct sk_buff *skb)
+{
+	struct sk_buff *newskb;
+
+	newskb = pskb_copy(skb, GFP_ATOMIC);
+
+	ieee802154_rx_irqsafe(priv->dev, newskb, 0xcc);
+}
+
+static int
+hw_tx(struct ieee802154_dev *dev, struct sk_buff *skb)
+{
+	struct fake_dev_priv *priv = dev->priv;
+	struct fake_priv *fake = priv->fake;
+
+	might_sleep();
+
+	read_lock_bh(&fake->lock);
+	if (priv->list.next == priv->list.prev) {
+		/* we are the only one device */
+		hw_deliver(priv, skb);
+	} else {
+		struct fake_dev_priv *dp;
+		list_for_each_entry(dp, &priv->fake->list, list)
+			if (dp != priv && dp->dev->current_channel == priv->dev->current_channel)
+				hw_deliver(dp, skb);
+	}
+	read_unlock_bh(&fake->lock);
+
+	return PHY_SUCCESS;
+}
+
+static struct ieee802154_ops fake_ops = {
+	.owner = THIS_MODULE,
+	.tx = hw_tx,
+	.ed = hw_ed,
+	.cca = hw_cca,
+	.set_trx_state = hw_state,
+	.set_channel = hw_channel,
+};
+
+static int ieee802154fake_add_priv(struct device *dev, struct fake_priv *fake, const u8 *macaddr)
+{
+	struct fake_dev_priv *priv;
+	int err = -ENOMEM;
+
+	priv = kzalloc(sizeof(struct fake_dev_priv), GFP_KERNEL);
+	if (!priv)
+		goto err_alloc;
+
+	INIT_LIST_HEAD(&priv->list);
+
+	priv->dev = ieee802154_alloc_device();
+	if (!priv->dev)
+		goto err_alloc_dev;
+	priv->dev->name = "IEEE 802.15.4 fake";
+	priv->dev->priv = priv;
+	priv->dev->parent = dev;
+	priv->fake = fake;
+
+	err = ieee802154_register_device(priv->dev, &fake_ops);
+	if (err)
+		goto err_reg;
+	rtnl_lock();
+	err = ieee802154_add_slave(priv->dev, macaddr);
+	rtnl_unlock();
+	if (err < 0)
+		goto err_slave;
+
+	write_lock_bh(&fake->lock);
+	list_add_tail(&priv->list, &fake->list);
+	write_unlock_bh(&fake->lock);
+
+	return 0;
+
+err_slave:
+	ieee802154_unregister_device(priv->dev);
+err_reg:
+	ieee802154_free_device(priv->dev);
+err_alloc_dev:
+	kfree(priv);
+err_alloc:
+	return err;
+}
+
+static void ieee802154fake_del_priv(struct fake_dev_priv *priv)
+{
+	write_lock_bh(&priv->fake->lock);
+	list_del(&priv->list);
+	write_unlock_bh(&priv->fake->lock);
+
+	ieee802154_unregister_device(priv->dev);
+	ieee802154_free_device(priv->dev);
+	kfree(priv);
+}
+
+static ssize_t
+adddev_store(struct device *dev, struct device_attribute *attr,
+	const char *buf, size_t n)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct fake_priv *priv = platform_get_drvdata(pdev);
+	char hw[8] = {};
+	int i, j, ch, err;
+
+	for (i = 0, j = 0; i < 16 && j < n; j++) {
+		ch = buf[j];
+		switch (buf[j]) {
+		default:
+			return -EINVAL;
+		case '0'...'9':
+			ch -= '0';
+			break;
+		case 'A'...'F':
+			ch -= 'A' - 10;
+			break;
+		case 'a'...'f':
+			ch -= 'a' - 10;
+			break;
+		case ':':
+		case '.':
+			continue;
+		}
+		if (i % 2)
+			hw[i/2] = (hw[i/2] & 0xf0) | ch;
+		else
+			hw[i/2] = ch << 4;
+		i++;
+	}
+	if (i != 16)
+		return -EINVAL;
+	err = ieee802154fake_add_priv(dev, priv, hw);
+	if (err)
+		return err;
+	return n;
+}
+
+static DEVICE_ATTR(adddev, 0200, NULL, adddev_store);
+
+static struct attribute *fake_attrs[] = {
+	&dev_attr_adddev.attr,
+	NULL,
+};
+
+static struct attribute_group fake_group = {
+	.name	= NULL /* fake */,
+	.attrs	= fake_attrs,
+};
+
+
+static int __devinit ieee802154fake_probe(struct platform_device *pdev)
+{
+	struct fake_priv *priv;
+	struct fake_dev_priv *dp;
+
+	int err = -ENOMEM;
+	priv = kzalloc(sizeof(struct fake_priv), GFP_KERNEL);
+	if (!priv)
+		goto err_alloc;
+
+	INIT_LIST_HEAD(&priv->list);
+	rwlock_init(&priv->lock);
+
+	err = sysfs_create_group(&pdev->dev.kobj, &fake_group);
+	if (err)
+		goto err_grp;
+
+	err = ieee802154fake_add_priv(&pdev->dev, priv, "\xde\xad\xbe\xaf\xca\xfe\xba\xbe");
+	if (err < 0)
+		goto err_slave;
+
+/*	err = ieee802154fake_add_priv(priv, "\x67\x45\x23\x01\x67\x45\x23\x01");
+	if (err < 0)
+		goto err_slave;*/
+
+	platform_set_drvdata(pdev, priv);
+	dev_info(&pdev->dev, "Added ieee802154 hardware\n");
+	return 0;
+
+err_slave:
+	list_for_each_entry(dp, &priv->list, list)
+		ieee802154fake_del_priv(dp);
+	sysfs_remove_group(&pdev->dev.kobj, &fake_group);
+err_grp:
+	kfree(priv);
+err_alloc:
+	return err;
+}
+
+static int __devexit ieee802154fake_remove(struct platform_device *pdev)
+{
+	struct fake_priv *priv = platform_get_drvdata(pdev);
+	struct fake_dev_priv *dp, *temp;
+
+	list_for_each_entry_safe(dp, temp, &priv->list, list)
+		ieee802154fake_del_priv(dp);
+	sysfs_remove_group(&pdev->dev.kobj, &fake_group);
+	kfree(priv);
+	return 0;
+}
+
+static struct platform_device *ieee802154fake_dev;
+
+static struct platform_driver ieee802154fake_driver = {
+	.probe = ieee802154fake_probe,
+	.remove = __devexit_p(ieee802154fake_remove),
+	.driver = {
+			.name = "ieee802154fakelb",
+			.owner = THIS_MODULE,
+	},
+};
+
+static __init int fake_init(void)
+{
+	ieee802154fake_dev = platform_device_register_simple("ieee802154fakelb", -1, NULL, 0);
+	return platform_driver_register(&ieee802154fake_driver);
+}
+
+static __exit void fake_exit(void)
+{
+	platform_driver_unregister(&ieee802154fake_driver);
+	platform_device_unregister(ieee802154fake_dev);
+}
+
+module_init(fake_init);
+module_exit(fake_exit);
+MODULE_LICENSE("GPL");
+
-- 
1.6.2.4


^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [PATCH 07/10] ieee802154: add virtual loopback driver
@ 2009-06-01 14:54               ` Dmitry Eremin-Solenikov
  0 siblings, 0 replies; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-01 14:54 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	slapin-9cOl001CZnBAfugRpC6u6w,
	maxim.osipov-kv7WeFo6aLtBDgjK7y7TUQ,
	dmitry.baryshkov-kv7WeFo6aLtBDgjK7y7TUQ,
	oliver.fendt-kv7WeFo6aLtBDgjK7y7TUQ, Dmitry Eremin-Solenikov

fakelb is a virtual loopback driver implementing one or several
interconnected radios. Packets from the radio are either sent
back to the node (if no other fake radio are registered) or to
all other fake radio.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Sergey Lapin <slapin-9cOl001CZnBAfugRpC6u6w@public.gmane.org>
---
 drivers/ieee802154/Kconfig  |   11 ++
 drivers/ieee802154/Makefile |    1 +
 drivers/ieee802154/fakelb.c |  335 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 347 insertions(+), 0 deletions(-)
 create mode 100644 drivers/ieee802154/fakelb.c

diff --git a/drivers/ieee802154/Kconfig b/drivers/ieee802154/Kconfig
index 8610620..d1799e3 100644
--- a/drivers/ieee802154/Kconfig
+++ b/drivers/ieee802154/Kconfig
@@ -19,5 +19,16 @@ config IEEE802154_FAKEHARD
           This driver can also be built as a module. To do so say M here.
 	  The module will be called 'fakehard'.
 
+
+if IEEE802154_DRIVERS && MAC802154
+config IEEE802154_FAKELB
+	tristate "Fake LR-WPAN driver with several interconnected devices"
+	---help---
+	  Say Y here to enable the fake driver that can emulate a net
+          of several interconnected radio devices.
+
+          This driver can also be built as a module. To do so say M here.
+	  The module will be called 'fakelb'.
+
 endif
 
diff --git a/drivers/ieee802154/Makefile b/drivers/ieee802154/Makefile
index e0e8e1a..2bd7bdf 100644
--- a/drivers/ieee802154/Makefile
+++ b/drivers/ieee802154/Makefile
@@ -1,3 +1,4 @@
 obj-$(CONFIG_IEEE802154_FAKEHARD) += fakehard.o
+obj-$(CONFIG_IEEE802154_FAKELB) += fakelb.o
 
 EXTRA_CFLAGS += -DDEBUG -DCONFIG_FFD
diff --git a/drivers/ieee802154/fakelb.c b/drivers/ieee802154/fakelb.c
new file mode 100644
index 0000000..7c00f07
--- /dev/null
+++ b/drivers/ieee802154/fakelb.c
@@ -0,0 +1,335 @@
+/*
+ * Loopback IEEE 802.15.4 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 <sergey.lapin-kv7WeFo6aLtBDgjK7y7TUQ@public.gmane.org>
+ * Dmitry Eremin-Solenikov <dbaryshkov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+ */
+
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/platform_device.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/spinlock.h>
+#include <net/ieee802154/mac802154.h>
+
+struct fake_dev_priv {
+	struct ieee802154_dev *dev;
+	phy_status_t cur_state, pend_state;
+
+	struct list_head list;
+	struct fake_priv *fake;
+};
+
+struct fake_priv {
+	struct list_head list;
+	rwlock_t lock;
+};
+
+static int is_transmitting(struct ieee802154_dev *dev)
+{
+	return 0;
+}
+
+static int is_receiving(struct ieee802154_dev *dev)
+{
+	return 0;
+}
+
+static phy_status_t
+hw_ed(struct ieee802154_dev *dev, u8 *level)
+{
+	pr_debug("%s\n", __func__);
+	might_sleep();
+	BUG_ON(!level);
+	*level = 0xbe;
+	return PHY_SUCCESS;
+}
+
+static phy_status_t
+hw_cca(struct ieee802154_dev *dev)
+{
+	pr_debug("%s\n", __func__);
+	might_sleep();
+	return PHY_IDLE;
+}
+
+static phy_status_t
+hw_state(struct ieee802154_dev *dev, phy_status_t state)
+{
+	struct fake_dev_priv *priv = dev->priv;
+	pr_debug("%s %d %d\n", __func__, priv->cur_state, state);
+	might_sleep();
+	if (state != PHY_TRX_OFF && state != PHY_RX_ON && state != PHY_TX_ON && state != PHY_FORCE_TRX_OFF)
+		return PHY_INVAL;
+	else if (state == PHY_FORCE_TRX_OFF) {
+		priv->cur_state = PHY_TRX_OFF;
+		return PHY_SUCCESS;
+	} else if (priv->cur_state == state)
+		return state;
+	else if ((state == PHY_TRX_OFF || state == PHY_RX_ON) && is_transmitting(dev)) {
+		priv->pend_state = state;
+		return PHY_BUSY_TX;
+	} else if ((state == PHY_TRX_OFF || state == PHY_TX_ON) && is_receiving(dev)) {
+		priv->pend_state = state;
+		return PHY_BUSY_RX;
+	} else {
+		priv->cur_state = state;
+		return PHY_SUCCESS;
+	}
+}
+
+static phy_status_t
+hw_channel(struct ieee802154_dev *dev, int channel)
+{
+	pr_debug("%s %d\n", __func__, channel);
+	might_sleep();
+	dev->current_channel = channel;
+	return PHY_SUCCESS;
+}
+
+static void
+hw_deliver(struct fake_dev_priv *priv, struct sk_buff *skb)
+{
+	struct sk_buff *newskb;
+
+	newskb = pskb_copy(skb, GFP_ATOMIC);
+
+	ieee802154_rx_irqsafe(priv->dev, newskb, 0xcc);
+}
+
+static int
+hw_tx(struct ieee802154_dev *dev, struct sk_buff *skb)
+{
+	struct fake_dev_priv *priv = dev->priv;
+	struct fake_priv *fake = priv->fake;
+
+	might_sleep();
+
+	read_lock_bh(&fake->lock);
+	if (priv->list.next == priv->list.prev) {
+		/* we are the only one device */
+		hw_deliver(priv, skb);
+	} else {
+		struct fake_dev_priv *dp;
+		list_for_each_entry(dp, &priv->fake->list, list)
+			if (dp != priv && dp->dev->current_channel == priv->dev->current_channel)
+				hw_deliver(dp, skb);
+	}
+	read_unlock_bh(&fake->lock);
+
+	return PHY_SUCCESS;
+}
+
+static struct ieee802154_ops fake_ops = {
+	.owner = THIS_MODULE,
+	.tx = hw_tx,
+	.ed = hw_ed,
+	.cca = hw_cca,
+	.set_trx_state = hw_state,
+	.set_channel = hw_channel,
+};
+
+static int ieee802154fake_add_priv(struct device *dev, struct fake_priv *fake, const u8 *macaddr)
+{
+	struct fake_dev_priv *priv;
+	int err = -ENOMEM;
+
+	priv = kzalloc(sizeof(struct fake_dev_priv), GFP_KERNEL);
+	if (!priv)
+		goto err_alloc;
+
+	INIT_LIST_HEAD(&priv->list);
+
+	priv->dev = ieee802154_alloc_device();
+	if (!priv->dev)
+		goto err_alloc_dev;
+	priv->dev->name = "IEEE 802.15.4 fake";
+	priv->dev->priv = priv;
+	priv->dev->parent = dev;
+	priv->fake = fake;
+
+	err = ieee802154_register_device(priv->dev, &fake_ops);
+	if (err)
+		goto err_reg;
+	rtnl_lock();
+	err = ieee802154_add_slave(priv->dev, macaddr);
+	rtnl_unlock();
+	if (err < 0)
+		goto err_slave;
+
+	write_lock_bh(&fake->lock);
+	list_add_tail(&priv->list, &fake->list);
+	write_unlock_bh(&fake->lock);
+
+	return 0;
+
+err_slave:
+	ieee802154_unregister_device(priv->dev);
+err_reg:
+	ieee802154_free_device(priv->dev);
+err_alloc_dev:
+	kfree(priv);
+err_alloc:
+	return err;
+}
+
+static void ieee802154fake_del_priv(struct fake_dev_priv *priv)
+{
+	write_lock_bh(&priv->fake->lock);
+	list_del(&priv->list);
+	write_unlock_bh(&priv->fake->lock);
+
+	ieee802154_unregister_device(priv->dev);
+	ieee802154_free_device(priv->dev);
+	kfree(priv);
+}
+
+static ssize_t
+adddev_store(struct device *dev, struct device_attribute *attr,
+	const char *buf, size_t n)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct fake_priv *priv = platform_get_drvdata(pdev);
+	char hw[8] = {};
+	int i, j, ch, err;
+
+	for (i = 0, j = 0; i < 16 && j < n; j++) {
+		ch = buf[j];
+		switch (buf[j]) {
+		default:
+			return -EINVAL;
+		case '0'...'9':
+			ch -= '0';
+			break;
+		case 'A'...'F':
+			ch -= 'A' - 10;
+			break;
+		case 'a'...'f':
+			ch -= 'a' - 10;
+			break;
+		case ':':
+		case '.':
+			continue;
+		}
+		if (i % 2)
+			hw[i/2] = (hw[i/2] & 0xf0) | ch;
+		else
+			hw[i/2] = ch << 4;
+		i++;
+	}
+	if (i != 16)
+		return -EINVAL;
+	err = ieee802154fake_add_priv(dev, priv, hw);
+	if (err)
+		return err;
+	return n;
+}
+
+static DEVICE_ATTR(adddev, 0200, NULL, adddev_store);
+
+static struct attribute *fake_attrs[] = {
+	&dev_attr_adddev.attr,
+	NULL,
+};
+
+static struct attribute_group fake_group = {
+	.name	= NULL /* fake */,
+	.attrs	= fake_attrs,
+};
+
+
+static int __devinit ieee802154fake_probe(struct platform_device *pdev)
+{
+	struct fake_priv *priv;
+	struct fake_dev_priv *dp;
+
+	int err = -ENOMEM;
+	priv = kzalloc(sizeof(struct fake_priv), GFP_KERNEL);
+	if (!priv)
+		goto err_alloc;
+
+	INIT_LIST_HEAD(&priv->list);
+	rwlock_init(&priv->lock);
+
+	err = sysfs_create_group(&pdev->dev.kobj, &fake_group);
+	if (err)
+		goto err_grp;
+
+	err = ieee802154fake_add_priv(&pdev->dev, priv, "\xde\xad\xbe\xaf\xca\xfe\xba\xbe");
+	if (err < 0)
+		goto err_slave;
+
+/*	err = ieee802154fake_add_priv(priv, "\x67\x45\x23\x01\x67\x45\x23\x01");
+	if (err < 0)
+		goto err_slave;*/
+
+	platform_set_drvdata(pdev, priv);
+	dev_info(&pdev->dev, "Added ieee802154 hardware\n");
+	return 0;
+
+err_slave:
+	list_for_each_entry(dp, &priv->list, list)
+		ieee802154fake_del_priv(dp);
+	sysfs_remove_group(&pdev->dev.kobj, &fake_group);
+err_grp:
+	kfree(priv);
+err_alloc:
+	return err;
+}
+
+static int __devexit ieee802154fake_remove(struct platform_device *pdev)
+{
+	struct fake_priv *priv = platform_get_drvdata(pdev);
+	struct fake_dev_priv *dp, *temp;
+
+	list_for_each_entry_safe(dp, temp, &priv->list, list)
+		ieee802154fake_del_priv(dp);
+	sysfs_remove_group(&pdev->dev.kobj, &fake_group);
+	kfree(priv);
+	return 0;
+}
+
+static struct platform_device *ieee802154fake_dev;
+
+static struct platform_driver ieee802154fake_driver = {
+	.probe = ieee802154fake_probe,
+	.remove = __devexit_p(ieee802154fake_remove),
+	.driver = {
+			.name = "ieee802154fakelb",
+			.owner = THIS_MODULE,
+	},
+};
+
+static __init int fake_init(void)
+{
+	ieee802154fake_dev = platform_device_register_simple("ieee802154fakelb", -1, NULL, 0);
+	return platform_driver_register(&ieee802154fake_driver);
+}
+
+static __exit void fake_exit(void)
+{
+	platform_driver_unregister(&ieee802154fake_driver);
+	platform_device_unregister(ieee802154fake_dev);
+}
+
+module_init(fake_init);
+module_exit(fake_exit);
+MODULE_LICENSE("GPL");
+
-- 
1.6.2.4

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [PATCH 08/10] tty_io: export tty_class
@ 2009-06-01 14:54                 ` Dmitry Eremin-Solenikov
  0 siblings, 0 replies; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-01 14:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: netdev, linux-wireless, slapin, maxim.osipov, dmitry.baryshkov,
	oliver.fendt, Dmitry Eremin-Solenikov

Currently tty_class in a public variable in the tty_io.c
Export it to the modules to allow some usefull tricks.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Signed-off-by: Sergey Lapin <slapin@ossfans.org>
---
 drivers/char/tty_io.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 66b99a2..4b12d03 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -2809,6 +2809,7 @@ int tty_put_char(struct tty_struct *tty, unsigned char ch)
 EXPORT_SYMBOL_GPL(tty_put_char);
 
 struct class *tty_class;
+EXPORT_SYMBOL(tty_class);
 
 /**
  *	tty_register_device - register a tty device
-- 
1.6.2.4


^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [PATCH 08/10] tty_io: export tty_class
@ 2009-06-01 14:54                 ` Dmitry Eremin-Solenikov
  0 siblings, 0 replies; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-01 14:54 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	slapin-9cOl001CZnBAfugRpC6u6w,
	maxim.osipov-kv7WeFo6aLtBDgjK7y7TUQ,
	dmitry.baryshkov-kv7WeFo6aLtBDgjK7y7TUQ,
	oliver.fendt-kv7WeFo6aLtBDgjK7y7TUQ, Dmitry Eremin-Solenikov

Currently tty_class in a public variable in the tty_io.c
Export it to the modules to allow some usefull tricks.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Sergey Lapin <slapin-9cOl001CZnBAfugRpC6u6w@public.gmane.org>
---
 drivers/char/tty_io.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 66b99a2..4b12d03 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -2809,6 +2809,7 @@ int tty_put_char(struct tty_struct *tty, unsigned char ch)
 EXPORT_SYMBOL_GPL(tty_put_char);
 
 struct class *tty_class;
+EXPORT_SYMBOL(tty_class);
 
 /**
  *	tty_register_device - register a tty device
-- 
1.6.2.4

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [PATCH 09/10] ieee802154: add serial dongle driver
@ 2009-06-01 14:54                   ` Dmitry Eremin-Solenikov
  0 siblings, 0 replies; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-01 14:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: netdev, linux-wireless, slapin, maxim.osipov, dmitry.baryshkov,
	oliver.fendt, Dmitry Eremin-Solenikov

Add a tty ldisc supporting IEEE 802.15.4 over serial line. Currently
the only protocol implemented/device supported is our firmware for
Freescale 13192 evaluation boards.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Signed-off-by: Sergey Lapin <slapin@ossfans.org>
---
 drivers/ieee802154/Kconfig  |    3 +
 drivers/ieee802154/Makefile |    1 +
 drivers/ieee802154/serial.c |  999 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/tty.h         |    3 +-
 4 files changed, 1005 insertions(+), 1 deletions(-)
 create mode 100644 drivers/ieee802154/serial.c

diff --git a/drivers/ieee802154/Kconfig b/drivers/ieee802154/Kconfig
index d1799e3..0e65572 100644
--- a/drivers/ieee802154/Kconfig
+++ b/drivers/ieee802154/Kconfig
@@ -30,5 +30,8 @@ config IEEE802154_FAKELB
           This driver can also be built as a module. To do so say M here.
 	  The module will be called 'fakelb'.
 
+config IEEE802154_SERIAL
+	tristate "Simple LR-WPAN UART driver"
+
 endif
 
diff --git a/drivers/ieee802154/Makefile b/drivers/ieee802154/Makefile
index 2bd7bdf..ca41e99 100644
--- a/drivers/ieee802154/Makefile
+++ b/drivers/ieee802154/Makefile
@@ -1,4 +1,5 @@
 obj-$(CONFIG_IEEE802154_FAKEHARD) += fakehard.o
 obj-$(CONFIG_IEEE802154_FAKELB) += fakelb.o
+obj-$(CONFIG_IEEE802154_SERIAL) += serial.o
 
 EXTRA_CFLAGS += -DDEBUG -DCONFIG_FFD
diff --git a/drivers/ieee802154/serial.c b/drivers/ieee802154/serial.c
new file mode 100644
index 0000000..5c452dd
--- /dev/null
+++ b/drivers/ieee802154/serial.c
@@ -0,0 +1,999 @@
+/*
+ * ZigBee TTY line discipline.
+ *
+ * Provides interface between ZigBee stack and IEEE 802.15.4 compatible
+ * firmware over serial line. Communication protocol is described below.
+ *
+ * Copyright (C) 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:
+ * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
+ * Maxim Osipov <maxim.osipov@siemens.com>
+ * Sergey Lapin <sergey.lapin@siemens.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/completion.h>
+#include <linux/tty.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <net/ieee802154/mac802154.h>
+
+
+/* NOTE: be sure to use here the same values as in the firmware */
+#define START_BYTE1	'z'
+#define START_BYTE2	'b'
+#define MAX_DATA_SIZE	127
+
+#define IDLE_MODE	0x00
+#define RX_MODE		0x02
+#define TX_MODE		0x03
+#define FORCE_TRX_OFF	0xF0
+
+#define STATUS_SUCCESS	0
+#define STATUS_RX_ON	1
+#define STATUS_TX_ON	2
+#define STATUS_TRX_OFF	3
+#define STATUS_IDLE	4
+#define STATUS_BUSY	5
+#define STATUS_BUSY_RX	6
+#define STATUS_BUSY_TX	7
+#define STATUS_ERR	8
+
+/* We re-use PPP ioctl for our purposes */
+#define	PPPIOCGUNIT	_IOR('t', 86, int)	/* get ppp unit number */
+
+/*
+ * The following messages are used to control ZigBee firmware.
+ * All communication has request/response format,
+ * except of asynchronous incoming data stream (DATA_RECV_* messages).
+ */
+enum {
+	NO_ID			= 0, /* means no pending id */
+
+	/* Driver to Firmware */
+	CMD_OPEN		= 0x01, /* u8 id */
+	CMD_CLOSE		= 0x02, /* u8 id */
+	CMD_SET_CHANNEL		= 0x04, /* u8 id, u8 channel */
+	CMD_ED			= 0x05, /* u8 id */
+	CMD_CCA			= 0x06, /* u8 id */
+	CMD_SET_STATE		= 0x07, /* u8 id, u8 flag */
+	DATA_XMIT_BLOCK		= 0x09, /* u8 id, u8 len, u8 data[len] */
+	DATA_XMIT_STREAM	= 0x0a, /* u8 id, u8 c */
+	RESP_RECV_BLOCK		= 0x0b, /* u8 id, u8 status */
+	RESP_RECV_STREAM	= 0x0c, /* u8 id, u8 status */
+
+	/* Firmware to Driver */
+	RESP_OPEN		= 0x81, /* u8 id, u8 status */
+	RESP_CLOSE		= 0x82, /* u8 id, u8 status */
+	RESP_SET_CHANNEL 	= 0x84, /* u8 id, u8 status */
+	RESP_ED			= 0x85, /* u8 id, u8 status, u8 level */
+	RESP_CCA		= 0x86, /* u8 id, u8 status */
+	RESP_SET_STATE		= 0x87, /* u8 id, u8 status */
+	RESP_XMIT_BLOCK		= 0x89, /* u8 id, u8 status */
+	RESP_XMIT_STREAM	= 0x8a, /* u8 id, u8 status */
+	DATA_RECV_BLOCK		= 0x8b, /* u8 id, u8 lq, u8 len, u8 data[len] */
+	DATA_RECV_STREAM	= 0x8c  /* u8 id, u8 c */
+};
+
+enum {
+	STATE_WAIT_START1,
+	STATE_WAIT_START2,
+	STATE_WAIT_COMMAND,
+	STATE_WAIT_PARAM1,
+	STATE_WAIT_PARAM2,
+	STATE_WAIT_DATA
+};
+
+struct zb_device {
+	/* Relative devices */
+	struct tty_struct	*tty;
+	struct ieee802154_dev	*dev;
+
+	/* locks the ldisc for the command */
+	struct mutex		mutex;
+
+	/* command completition */
+	wait_queue_head_t	wq;
+	phy_status_t		status;
+	u8			ed;
+
+	/* Internal state */
+	struct completion	open_done;
+	unsigned char		opened;
+	u8			pending_id;
+	unsigned int		pending_size;
+	u8			*pending_data;
+	/* FIXME: WE NEED LOCKING!!! */
+
+	/* Command (rx) processing */
+	int			state;
+	unsigned char		id;
+	unsigned char		param1;
+	unsigned char		param2;
+	unsigned char		index;
+	unsigned char		data[MAX_DATA_SIZE];
+};
+
+/*****************************************************************************
+ * ZigBee serial device protocol handling
+ *****************************************************************************/
+static int _open_dev(struct zb_device *zbdev);
+
+static int
+_send_pending_data(struct zb_device *zbdev)
+{
+	unsigned int j;
+	struct tty_struct *tty;
+
+	BUG_ON(!zbdev);
+	tty = zbdev->tty;
+	if (!tty)
+		return -ENODEV;
+
+	zbdev->status = PHY_INVAL;
+
+	/* Debug info */
+	printk(KERN_INFO "%lu %s, %d bytes:", jiffies, __func__, zbdev->pending_size);
+	for (j = 0; j < zbdev->pending_size; ++j)
+		printk(KERN_CONT " 0x%02X", zbdev->pending_data[j]);
+	printk(KERN_CONT "\n");
+
+	if (tty->driver->ops->write(tty, zbdev->pending_data, zbdev->pending_size) != zbdev->pending_size) {
+		printk(KERN_ERR "%s: device write failed\n", __func__);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+send_cmd(struct zb_device *zbdev, u8 id)
+{
+	u8 len = 0, buf[4];	/* 4 because of 2 start bytes, id and optional extra */
+
+	/* Check arguments */
+	BUG_ON(!zbdev);
+
+	if (!zbdev->opened) {
+		if (!_open_dev(zbdev))
+			return -EAGAIN;
+	}
+
+	pr_debug("%s(): id = %u\n", __func__, id);
+	if (zbdev->pending_size) {
+		printk(KERN_ERR "%s(): cmd is already pending, id = %u\n",
+			__func__, zbdev->pending_id);
+		BUG();
+	}
+
+	/* Prepare a message */
+	buf[len++] = START_BYTE1;
+	buf[len++] = START_BYTE2;
+	buf[len++] = id;
+
+	zbdev->pending_id = id;
+	zbdev->pending_size = len;
+	zbdev->pending_data = kzalloc(zbdev->pending_size, GFP_KERNEL);
+	if (!zbdev->pending_data) {
+		printk(KERN_ERR "%s(): unable to allocate memory\n", __func__);
+		zbdev->pending_id = 0;
+		zbdev->pending_size = 0;
+		return -ENOMEM;
+	}
+	memcpy(zbdev->pending_data, buf, len);
+
+	return _send_pending_data(zbdev);
+}
+
+static int
+send_cmd2(struct zb_device *zbdev, u8 id, u8 extra)
+{
+	u8 len = 0, buf[4];	/* 4 because of 2 start bytes, id and optional extra */
+
+	/* Check arguments */
+	BUG_ON(!zbdev);
+
+	if (!zbdev->opened) {
+		if (!_open_dev(zbdev))
+			return -EAGAIN;
+	}
+
+	pr_debug("%s(): id = %u\n", __func__, id);
+	if (zbdev->pending_size) {
+		printk(KERN_ERR "%s(): cmd is already pending, id = %u\n",
+			__func__, zbdev->pending_id);
+		BUG();
+	}
+
+	/* Prepare a message */
+	buf[len++] = START_BYTE1;
+	buf[len++] = START_BYTE2;
+	buf[len++] = id;
+	buf[len++] = extra;
+
+	zbdev->pending_id = id;
+	zbdev->pending_size = len;
+	zbdev->pending_data = kzalloc(zbdev->pending_size, GFP_KERNEL);
+	if (!zbdev->pending_data) {
+		printk(KERN_ERR "%s(): unable to allocate memory\n", __func__);
+		zbdev->pending_id = 0;
+		zbdev->pending_size = 0;
+		return -ENOMEM;
+	}
+	memcpy(zbdev->pending_data, buf, len);
+
+	return _send_pending_data(zbdev);
+}
+
+static int
+send_block(struct zb_device *zbdev, u8 len, u8 *data)
+{
+	u8 i = 0, buf[4];	/* 4 because of 2 start bytes, id and len */
+
+	/* Check arguments */
+	BUG_ON(!zbdev);
+
+	if (!zbdev->opened) {
+		if (!_open_dev(zbdev))
+			return -EAGAIN;
+	}
+
+	pr_debug("%s(): id = %u\n", __func__, DATA_XMIT_BLOCK);
+	if (zbdev->pending_size) {
+		printk(KERN_ERR "%s(): cmd is already pending, id = %u\n",
+			__func__, zbdev->pending_id);
+		BUG();
+	}
+
+	/* Prepare a message */
+	buf[i++] = START_BYTE1;
+	buf[i++] = START_BYTE2;
+	buf[i++] = DATA_XMIT_BLOCK;
+	buf[i++] = len;
+
+	zbdev->pending_id = DATA_XMIT_BLOCK;
+	zbdev->pending_size = i + len;
+	zbdev->pending_data = kzalloc(zbdev->pending_size, GFP_KERNEL);
+	if (!zbdev->pending_data) {
+		printk(KERN_ERR "%s(): unable to allocate memory\n", __func__);
+		zbdev->pending_id = 0;
+		zbdev->pending_size = 0;
+		return -ENOMEM;
+	}
+	memcpy(zbdev->pending_data, buf, i);
+	memcpy(zbdev->pending_data + i, data, len);
+
+	return _send_pending_data(zbdev);
+}
+
+static void
+cleanup(struct zb_device *zbdev)
+{
+	zbdev->state = STATE_WAIT_START1;
+	zbdev->id = 0;
+	zbdev->param1 = 0;
+	zbdev->param2 = 0;
+	zbdev->index = 0;
+}
+
+static int
+is_command(unsigned char c)
+{
+	switch (c) {
+	/* ids we can get here: */
+	case RESP_OPEN:
+	case RESP_CLOSE:
+	case RESP_SET_CHANNEL:
+	case RESP_ED:
+	case RESP_CCA:
+	case RESP_SET_STATE:
+	case RESP_XMIT_BLOCK:
+	case RESP_XMIT_STREAM:
+	case DATA_RECV_BLOCK:
+	case DATA_RECV_STREAM:
+		return 1;
+	}
+	return 0;
+}
+
+static int
+_match_pending_id(struct zb_device *zbdev)
+{
+	return ((CMD_OPEN == zbdev->pending_id && RESP_OPEN == zbdev->id)
+		|| (CMD_CLOSE == zbdev->pending_id && RESP_CLOSE == zbdev->id)
+		|| (CMD_SET_CHANNEL == zbdev->pending_id && RESP_SET_CHANNEL == zbdev->id)
+		|| (CMD_ED == zbdev->pending_id && RESP_ED == zbdev->id)
+		|| (CMD_CCA == zbdev->pending_id && RESP_CCA == zbdev->id)
+		|| (CMD_SET_STATE == zbdev->pending_id && RESP_SET_STATE == zbdev->id)
+		|| (DATA_XMIT_BLOCK == zbdev->pending_id && RESP_XMIT_BLOCK == zbdev->id)
+		|| (DATA_XMIT_STREAM == zbdev->pending_id && RESP_XMIT_STREAM == zbdev->id)
+		|| DATA_RECV_BLOCK == zbdev->id
+		|| DATA_RECV_STREAM == zbdev->id);
+}
+
+static void serial_net_rx(struct zb_device *zbdev)
+{
+	/* zbdev->param1 is LQI
+	 * zbdev->param2 is length of data
+	 * zbdev->data is data itself
+	 */
+	struct sk_buff *skb;
+	skb = alloc_skb(zbdev->param2, GFP_ATOMIC);
+	skb_put(skb, zbdev->param2);
+	skb_copy_to_linear_data(skb, zbdev->data, zbdev->param2);
+	ieee802154_rx_irqsafe(zbdev->dev, skb, zbdev->param1);
+}
+
+static void
+process_command(struct zb_device *zbdev)
+{
+	/* Command processing */
+	if (!_match_pending_id(zbdev))
+		return;
+
+	if (RESP_OPEN == zbdev->id && STATUS_SUCCESS == zbdev->param1) {
+		zbdev->opened = 1;
+		pr_debug("Opened device\n");
+		complete(&zbdev->open_done);
+		/* Input is not processed during output, so
+		 * using completion is not possible during output.
+		 * so we need to handle open as any other command
+		 * and hope for best
+		 */
+		return;
+	}
+
+	if (!zbdev->opened)
+		return;
+
+	zbdev->pending_id = 0;
+	kfree(zbdev->pending_data);
+	zbdev->pending_data = NULL;
+	zbdev->pending_size = 0;
+	if (zbdev->id != DATA_RECV_BLOCK)
+		switch (zbdev->param1) {
+		case STATUS_SUCCESS:
+			zbdev->status = PHY_SUCCESS;
+			break;
+		case STATUS_RX_ON:
+			zbdev->status = PHY_RX_ON;
+			break;
+		case STATUS_TX_ON:
+			zbdev->status = PHY_TX_ON;
+			break;
+		case STATUS_TRX_OFF:
+			zbdev->status = PHY_TRX_OFF;
+			break;
+		case STATUS_BUSY:
+			zbdev->status = PHY_BUSY;
+			break;
+		case STATUS_IDLE:
+			zbdev->status = PHY_IDLE;
+			break;
+		case STATUS_BUSY_RX:
+			zbdev->status = PHY_BUSY_RX;
+			break;
+		case STATUS_BUSY_TX:
+			zbdev->status = PHY_BUSY_TX;
+			break;
+		default:
+			printk(KERN_ERR "%s: bad status received from firmware: %u\n",
+				__func__, zbdev->param1);
+			zbdev->status = PHY_ERROR;
+			break;
+		}
+
+	switch (zbdev->id) {
+	case RESP_ED:
+		zbdev->ed = zbdev->param2;
+		break;
+	case DATA_RECV_BLOCK:
+		pr_debug("Received block, lqi %02x, len %02x\n", zbdev->param1, zbdev->param2);
+		/* zbdev->param1 is LQ, zbdev->param2 is length */
+		serial_net_rx(zbdev);
+		break;
+	case DATA_RECV_STREAM:
+		/* TODO: update firmware to use this */
+		break;
+	}
+
+	wake_up(&zbdev->wq);
+}
+
+static void
+process_char(struct zb_device *zbdev, unsigned char c)
+{
+	/* Data processing */
+	pr_debug("Char: %d (0x%02x)\n", c, c);
+	switch (zbdev->state) {
+	case STATE_WAIT_START1:
+		if (START_BYTE1 == c)
+			zbdev->state = STATE_WAIT_START2;
+		break;
+
+	case STATE_WAIT_START2:
+		if (START_BYTE2 == c)
+			zbdev->state = STATE_WAIT_COMMAND;
+		else
+			cleanup(zbdev);
+		break;
+
+	case STATE_WAIT_COMMAND:
+		if (is_command(c)) {
+			zbdev->id = c;
+			zbdev->state = STATE_WAIT_PARAM1;
+		} else {
+			cleanup(zbdev);
+			printk(KERN_ERR "%s, unexpected command id: %x\n", __func__, c);
+		}
+		break;
+
+	case STATE_WAIT_PARAM1:
+		zbdev->param1 = c;
+		if ((RESP_ED == zbdev->id) || (DATA_RECV_BLOCK == zbdev->id))
+			zbdev->state = STATE_WAIT_PARAM2;
+		else {
+			process_command(zbdev);
+			cleanup(zbdev);
+		}
+		break;
+
+	case STATE_WAIT_PARAM2:
+		zbdev->param2 = c;
+		if (RESP_ED == zbdev->id) {
+			process_command(zbdev);
+			cleanup(zbdev);
+		} else if (DATA_RECV_BLOCK == zbdev->id)
+			zbdev->state = STATE_WAIT_DATA;
+		else
+			cleanup(zbdev);
+		break;
+
+	case STATE_WAIT_DATA:
+		if (zbdev->index < sizeof(zbdev->data)) {
+			zbdev->data[zbdev->index] = c;
+			zbdev->index++;
+			/* Pending data is received, param2 is length for DATA_RECV_BLOCK */
+			if (zbdev->index == zbdev->param2) {
+				process_command(zbdev);
+				cleanup(zbdev);
+			}
+		} else {
+			printk(KERN_ERR "%s(): data size is greater "
+				"than buffer available\n", __func__);
+			cleanup(zbdev);
+		}
+		break;
+
+	default:
+		cleanup(zbdev);
+	}
+}
+
+/*****************************************************************************
+ * Device operations for IEEE 802.15.4 PHY side interface ZigBee stack
+ *****************************************************************************/
+
+static int _open_dev(struct zb_device *zbdev)
+{
+	int retries;
+	u8 len = 0, buf[4];	/* 4 because of 2 start bytes, id and optional extra */
+
+	/* Check arguments */
+	BUG_ON(!zbdev);
+	if (zbdev->opened)
+		return 1;
+
+	pr_debug("%s()\n", __func__);
+	if (zbdev->pending_size) {
+		printk(KERN_ERR "%s(): cmd is already pending, id = %u\n",
+			__func__, zbdev->pending_id);
+		BUG();
+	}
+
+	/* Prepare a message */
+	buf[len++] = START_BYTE1;
+	buf[len++] = START_BYTE2;
+	buf[len++] = CMD_OPEN;
+
+	zbdev->pending_id = CMD_OPEN;
+	zbdev->pending_size = len;
+	zbdev->pending_data = kzalloc(zbdev->pending_size, GFP_KERNEL);
+	if (!zbdev->pending_data) {
+		printk(KERN_ERR "%s(): unable to allocate memory\n", __func__);
+		zbdev->pending_id = 0;
+		zbdev->pending_size = 0;
+		return -ENOMEM;
+	}
+	memcpy(zbdev->pending_data, buf, len);
+
+	retries = 5;
+	while (!zbdev->opened && retries) {
+		if (_send_pending_data(zbdev) != 0)
+			return 0;
+
+		/* 3 second before retransmission */
+		wait_for_completion_interruptible_timeout(&zbdev->open_done, msecs_to_jiffies(1000));
+		--retries;
+	}
+
+	zbdev->pending_id = 0;
+	kfree(zbdev->pending_data);
+	zbdev->pending_data = NULL;
+	zbdev->pending_size = 0;
+
+	if (zbdev->opened) {
+		printk(KERN_INFO "Opened connection to device\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+/* Valid channels: 1-16 */
+static phy_status_t
+ieee802154_serial_set_channel(struct ieee802154_dev *dev, int channel)
+{
+	struct zb_device *zbdev;
+	phy_status_t ret;
+
+	pr_debug("%s\n", __func__);
+
+	zbdev = dev->priv;
+	if (NULL == zbdev) {
+		printk(KERN_ERR "%s: wrong phy\n", __func__);
+		return PHY_INVAL;
+	}
+
+	if (mutex_lock_interruptible(&zbdev->mutex))
+		return PHY_ERROR;
+	/* Our channels are actually from 11 to 26
+	 * We have IEEE802.15.4 channel no from 0 to 26.
+	 * channels 0-10 are not valid for us */
+	BUG_ON(channel < 11 || channel > 26);
+	/* ...  but our crappy firmware numbers channels from 1 to 16
+	 * which is a mystery. We suould enforce that using PIB API
+	 * but additional checking here won't kill, and gcc will
+	 * optimize this stuff anyway. */
+	BUG_ON((channel - 10) < 1 && (channel - 10) > 16);
+
+	if (send_cmd2(zbdev, CMD_SET_CHANNEL, channel - 10) != 0) {
+		ret = PHY_ERROR;
+		goto out;
+	}
+
+	if (wait_event_interruptible_timeout(zbdev->wq, zbdev->status != PHY_INVAL, msecs_to_jiffies(1000)) > 0)
+		ret = zbdev->status;
+	else
+		ret = PHY_ERROR;
+
+	if (ret == PHY_SUCCESS)
+		zbdev->dev->current_channel = channel;
+out:
+	mutex_unlock(&zbdev->mutex);
+	pr_debug("%s end\n", __func__);
+	return ret;
+}
+
+static phy_status_t
+ieee802154_serial_ed(struct ieee802154_dev *dev, u8 *level)
+{
+	struct zb_device *zbdev;
+	phy_status_t ret;
+
+	pr_debug("%s\n", __func__);
+
+	zbdev = dev->priv;
+	if (NULL == zbdev) {
+		printk(KERN_ERR "%s: wrong phy\n", __func__);
+		return PHY_INVAL;
+	}
+
+	if (mutex_lock_interruptible(&zbdev->mutex))
+		return PHY_ERROR;
+
+#if 0
+	if (send_cmd(zbdev, CMD_ED) != 0) {
+		ret = PHY_ERROR;
+		goto out;
+	}
+
+	if (wait_event_interruptible_timeout(zbdev->wq, zbdev->status != PHY_INVAL, msecs_to_jiffies(1000)) > 0) {
+		*level = zbdev->ed;
+		ret = zbdev->status;
+	} else
+		ret = PHY_ERROR;
+out:
+#else
+	/* Lets suppose we have energy on all channels
+	 * till we fix something regarding hardware or driver */
+	*level = 0xbe;
+	ret = PHY_SUCCESS;
+#endif
+	mutex_unlock(&zbdev->mutex);
+	pr_debug("%s end\n", __func__);
+	return ret;
+}
+
+static phy_status_t
+ieee802154_serial_cca(struct ieee802154_dev *dev)
+{
+	struct zb_device *zbdev;
+	phy_status_t ret;
+
+	pr_debug("%s\n", __func__);
+
+	zbdev = dev->priv;
+	if (NULL == zbdev) {
+		printk(KERN_ERR "%s: wrong phy\n", __func__);
+		return PHY_INVAL;
+	}
+
+	if (mutex_lock_interruptible(&zbdev->mutex))
+		return PHY_ERROR;
+
+	if (send_cmd(zbdev, CMD_CCA) != 0) {
+		ret = PHY_ERROR;
+		goto out;
+	}
+
+	if (wait_event_interruptible_timeout(zbdev->wq, zbdev->status != PHY_INVAL, msecs_to_jiffies(1000)) > 0)
+		ret = zbdev->status;
+	else
+		ret = PHY_ERROR;
+out:
+	mutex_unlock(&zbdev->mutex);
+	pr_debug("%s end\n", __func__);
+	return ret;
+}
+
+static phy_status_t
+ieee802154_serial_set_state(struct ieee802154_dev *dev, phy_status_t state)
+{
+	struct zb_device *zbdev;
+	unsigned char flag;
+	phy_status_t ret;
+
+	pr_debug("%s %d\n", __func__, state);
+
+	zbdev = dev->priv;
+	if (NULL == zbdev) {
+		printk(KERN_ERR "%s: wrong phy\n", __func__);
+		return PHY_INVAL;
+	}
+
+	if (mutex_lock_interruptible(&zbdev->mutex))
+		return PHY_ERROR;
+
+	switch (state) {
+	case PHY_RX_ON:
+		flag = RX_MODE;
+		break;
+	case PHY_TX_ON:
+		flag = TX_MODE;
+		break;
+	case PHY_TRX_OFF:
+		flag = IDLE_MODE;
+		break;
+	case PHY_FORCE_TRX_OFF:
+		flag = FORCE_TRX_OFF;
+		break;
+	default:
+		ret = PHY_INVAL;
+		goto out;
+	}
+
+	if (send_cmd2(zbdev, CMD_SET_STATE, flag) != 0) {
+		ret = PHY_ERROR;
+		goto out;
+	}
+
+	if (wait_event_interruptible_timeout(zbdev->wq, zbdev->status != PHY_INVAL, msecs_to_jiffies(1000)) > 0)
+		ret = zbdev->status;
+	else
+		ret = PHY_ERROR;
+out:
+	mutex_unlock(&zbdev->mutex);
+	pr_debug("%s end\n", __func__);
+	return ret;
+}
+
+static phy_status_t
+ieee802154_serial_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
+{
+	struct zb_device *zbdev;
+	phy_status_t ret;
+
+	pr_debug("%s\n", __func__);
+
+	zbdev = dev->priv;
+	if (NULL == zbdev) {
+		printk(KERN_ERR "%s: wrong phy\n", __func__);
+		return PHY_INVAL;
+	}
+
+	if (mutex_lock_interruptible(&zbdev->mutex))
+		return PHY_ERROR;
+
+	if (send_block(zbdev, skb->len, skb->data) != 0) {
+		ret = PHY_ERROR;
+		goto out;
+	}
+
+	if (wait_event_interruptible_timeout(zbdev->wq, zbdev->status != PHY_INVAL, msecs_to_jiffies(1000)) > 0)
+		ret = zbdev->status;
+	else
+		ret = PHY_ERROR;
+out:
+
+	mutex_unlock(&zbdev->mutex);
+	pr_debug("%s end\n", __func__);
+	return ret;
+}
+
+/*****************************************************************************
+ * Line discipline interface for IEEE 802.15.4 serial device
+ *****************************************************************************/
+
+static struct ieee802154_ops serial_ops = {
+	.owner = THIS_MODULE,
+	.tx = ieee802154_serial_xmit,
+	.ed = ieee802154_serial_ed,
+	.cca = ieee802154_serial_cca,
+	.set_trx_state = ieee802154_serial_set_state,
+	.set_channel	= ieee802154_serial_set_channel,
+};
+
+static int dev_minor_match(struct device *dev, void *data)
+{
+	int *minor = data;
+	return MINOR(dev->devt) == *minor;
+}
+
+/*
+ * Called when a tty is put into ZB line discipline. Called in process context.
+ * Returns 0 on success.
+ */
+static int
+ieee802154_tty_open(struct tty_struct *tty)
+{
+	struct zb_device *zbdev = tty->disc_data;
+	int err;
+	int minor;
+
+	pr_debug("Openning ldisc\n");
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	if (zbdev)
+		return -EBUSY;
+
+	/* Allocate device structure */
+	zbdev = kzalloc(sizeof(struct zb_device), GFP_KERNEL);
+	if (NULL == zbdev) {
+		printk(KERN_ERR "%s: can't allocate zb_device structure.\n", __func__);
+		return -ENOMEM;
+	}
+	mutex_init(&zbdev->mutex);
+	init_completion(&zbdev->open_done);
+	init_waitqueue_head(&zbdev->wq);
+
+	zbdev->dev = ieee802154_alloc_device();
+	if (!zbdev->dev) {
+		err = -ENOMEM;
+		goto out_free_zb;
+	}
+
+	zbdev->dev->name		= "serialdev";
+	zbdev->dev->priv		= zbdev;
+	zbdev->dev->extra_tx_headroom	= 0;
+	zbdev->dev->channel_mask	= 0x7ff;
+	zbdev->dev->current_channel	= 11; /* it's 1st channel of 2.4 Ghz space */
+	zbdev->dev->flags		= IEEE802154_FLAGS_OMIT_CKSUM;
+
+	minor = tty->index + tty->driver->minor_start;
+	zbdev->dev->parent = class_find_device(tty_class, NULL, &minor, dev_minor_match);
+
+	zbdev->tty = tty;
+	cleanup(zbdev);
+
+	tty->disc_data = zbdev;
+	tty->receive_room = MAX_DATA_SIZE;
+	tty->low_latency = 1;
+
+	/* FIXME: why is this needed. Note don't use ldisc_ref here as the
+	   open path is before the ldisc is referencable */
+
+	if (tty->ldisc.ops->flush_buffer)
+		tty->ldisc.ops->flush_buffer(tty);
+	tty_driver_flush_buffer(tty);
+
+	err = ieee802154_register_device(zbdev->dev, &serial_ops);
+	/* we put it only after it has a chance to be get by network core */
+	if (zbdev->dev->parent)
+		put_device(zbdev->dev->parent);
+	if (err) {
+		printk(KERN_ERR "%s: device register failed\n", __func__);
+		goto out_free;
+	}
+
+	return 0;
+
+	ieee802154_unregister_device(zbdev->dev);
+
+out_free:
+	tty->disc_data = NULL;
+
+	ieee802154_free_device(zbdev->dev);
+out_free_zb:
+	kfree(zbdev);
+
+	return err;
+}
+
+/*
+ * Called when the tty is put into another line discipline or it hangs up. We
+ * have to wait for any cpu currently executing in any of the other zb_tty_*
+ * routines to finish before we can call zb_tty_close and free the
+ * zb_serial_dev struct. This routine must be called from process context, not
+ * interrupt or softirq context.
+ */
+static void
+ieee802154_tty_close(struct tty_struct *tty)
+{
+	struct zb_device *zbdev;
+
+	zbdev = tty->disc_data;
+	if (NULL == zbdev) {
+		printk(KERN_WARNING "%s: match is not found\n", __func__);
+		return;
+	}
+
+	tty->disc_data = NULL;
+	zbdev->tty = NULL;
+
+	ieee802154_unregister_device(zbdev->dev);
+
+	tty_ldisc_flush(tty);
+	tty_driver_flush_buffer(tty);
+
+	ieee802154_free_device(zbdev->dev);
+	kfree(zbdev);
+}
+
+/*
+ * Called on tty hangup in process context.
+ */
+static int
+ieee802154_tty_hangup(struct tty_struct *tty)
+{
+	ieee802154_tty_close(tty);
+	return 0;
+}
+
+/*
+ * Called in process context only. May be re-entered by multiple ioctl calling threads.
+ */
+static int
+ieee802154_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct zb_device *zbdev;
+	struct ifreq ifr;
+	int err;
+	void __user *argp = (void __user *) arg;
+
+	pr_debug("cmd = 0x%x\n", cmd);
+	memset(&ifr, 0, sizeof(ifr));
+
+	zbdev = tty->disc_data;
+	if (NULL == zbdev) {
+		pr_debug("match is not found\n");
+		return -EINVAL;
+	}
+
+
+	switch (cmd) {
+	case PPPIOCGUNIT:
+		/* TODO: some error checking */
+		BUG_ON(!zbdev->dev->netdev);
+		err = -EFAULT;
+		if (copy_to_user(argp, zbdev->dev->netdev->name, strlen(zbdev->dev->netdev->name)))
+			break;
+		err = 0;
+		break;
+	default:
+		pr_debug("Unknown ioctl cmd: %u\n", cmd);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+
+/*
+ * This can now be called from hard interrupt level as well
+ * as soft interrupt level or mainline.
+ */
+static void
+ieee802154_tty_receive(struct tty_struct *tty, const unsigned char *buf, char *cflags, int count)
+{
+	struct zb_device *zbdev;
+	int i;
+
+	/* Debug info */
+	printk(KERN_INFO "%lu %s, received %d bytes:", jiffies, __func__, count);
+	for (i = 0; i < count; ++i)
+		printk(KERN_CONT " 0x%02X", buf[i]);
+	printk(KERN_CONT "\n");
+
+	/* Actual processing */
+	zbdev = tty->disc_data;
+	if (NULL == zbdev) {
+		printk(KERN_ERR "%s(): record for tty is not found\n", __func__);
+		return;
+	}
+	for (i = 0; i < count; ++i)
+		process_char(zbdev, buf[i]);
+#if 0
+	if (tty->driver->flush_chars)
+		tty->driver->flush_chars(tty);
+#endif
+	tty_unthrottle(tty);
+}
+
+/*
+ * Line discipline device structure
+ */
+static struct tty_ldisc_ops ieee802154_ldisc = {
+	.owner  = THIS_MODULE,
+	.magic	= TTY_LDISC_MAGIC,
+	.name	= "ieee802154-ldisc",
+	.open	= ieee802154_tty_open,
+	.close	= ieee802154_tty_close,
+	.hangup	= ieee802154_tty_hangup,
+	.receive_buf = ieee802154_tty_receive,
+	.ioctl	= ieee802154_tty_ioctl,
+};
+
+/*****************************************************************************
+ * Module service routinues
+ *****************************************************************************/
+
+static int __init ieee802154_serial_init(void)
+{
+	printk(KERN_INFO "Initializing ZigBee TTY interface\n");
+
+	if (tty_register_ldisc(N_IEEE802154, &ieee802154_ldisc) != 0) {
+		printk(KERN_ERR "%s: line discipline register failed\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void __exit ieee802154_serial_cleanup(void)
+{
+	if (tty_unregister_ldisc(N_IEEE802154) != 0)
+		printk(KERN_CRIT "failed to unregister ZigBee line discipline.\n");
+}
+
+module_init(ieee802154_serial_init);
+module_exit(ieee802154_serial_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_LDISC(N_IEEE802154);
+
diff --git a/include/linux/tty.h b/include/linux/tty.h
index fc39db9..f533beb 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -23,7 +23,7 @@
  */
 #define NR_UNIX98_PTY_DEFAULT	4096      /* Default maximum for Unix98 ptys */
 #define NR_UNIX98_PTY_MAX	(1 << MINORBITS) /* Absolute limit */
-#define NR_LDISCS		19
+#define NR_LDISCS		20
 
 /* line disciplines */
 #define N_TTY		0
@@ -46,6 +46,7 @@
 #define N_GIGASET_M101	16	/* Siemens Gigaset M101 serial DECT adapter */
 #define N_SLCAN		17	/* Serial / USB serial CAN Adaptors */
 #define N_PPS		18	/* Pulse per Second */
+#define N_IEEE802154	19	/* Serial / USB serial IEEE802154.4 devices */
 
 /*
  * This character is the same as _POSIX_VDISABLE: it cannot be used as
-- 
1.6.2.4


^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [PATCH 09/10] ieee802154: add serial dongle driver
@ 2009-06-01 14:54                   ` Dmitry Eremin-Solenikov
  0 siblings, 0 replies; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-01 14:54 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	slapin-9cOl001CZnBAfugRpC6u6w,
	maxim.osipov-kv7WeFo6aLtBDgjK7y7TUQ,
	dmitry.baryshkov-kv7WeFo6aLtBDgjK7y7TUQ,
	oliver.fendt-kv7WeFo6aLtBDgjK7y7TUQ, Dmitry Eremin-Solenikov

Add a tty ldisc supporting IEEE 802.15.4 over serial line. Currently
the only protocol implemented/device supported is our firmware for
Freescale 13192 evaluation boards.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Sergey Lapin <slapin-9cOl001CZnBAfugRpC6u6w@public.gmane.org>
---
 drivers/ieee802154/Kconfig  |    3 +
 drivers/ieee802154/Makefile |    1 +
 drivers/ieee802154/serial.c |  999 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/tty.h         |    3 +-
 4 files changed, 1005 insertions(+), 1 deletions(-)
 create mode 100644 drivers/ieee802154/serial.c

diff --git a/drivers/ieee802154/Kconfig b/drivers/ieee802154/Kconfig
index d1799e3..0e65572 100644
--- a/drivers/ieee802154/Kconfig
+++ b/drivers/ieee802154/Kconfig
@@ -30,5 +30,8 @@ config IEEE802154_FAKELB
           This driver can also be built as a module. To do so say M here.
 	  The module will be called 'fakelb'.
 
+config IEEE802154_SERIAL
+	tristate "Simple LR-WPAN UART driver"
+
 endif
 
diff --git a/drivers/ieee802154/Makefile b/drivers/ieee802154/Makefile
index 2bd7bdf..ca41e99 100644
--- a/drivers/ieee802154/Makefile
+++ b/drivers/ieee802154/Makefile
@@ -1,4 +1,5 @@
 obj-$(CONFIG_IEEE802154_FAKEHARD) += fakehard.o
 obj-$(CONFIG_IEEE802154_FAKELB) += fakelb.o
+obj-$(CONFIG_IEEE802154_SERIAL) += serial.o
 
 EXTRA_CFLAGS += -DDEBUG -DCONFIG_FFD
diff --git a/drivers/ieee802154/serial.c b/drivers/ieee802154/serial.c
new file mode 100644
index 0000000..5c452dd
--- /dev/null
+++ b/drivers/ieee802154/serial.c
@@ -0,0 +1,999 @@
+/*
+ * ZigBee TTY line discipline.
+ *
+ * Provides interface between ZigBee stack and IEEE 802.15.4 compatible
+ * firmware over serial line. Communication protocol is described below.
+ *
+ * Copyright (C) 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:
+ * Maxim Gorbachyov <maxim.gorbachev-kv7WeFo6aLtBDgjK7y7TUQ@public.gmane.org>
+ * Maxim Osipov <maxim.osipov-kv7WeFo6aLtBDgjK7y7TUQ@public.gmane.org>
+ * Sergey Lapin <sergey.lapin-kv7WeFo6aLtBDgjK7y7TUQ@public.gmane.org>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/completion.h>
+#include <linux/tty.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <net/ieee802154/mac802154.h>
+
+
+/* NOTE: be sure to use here the same values as in the firmware */
+#define START_BYTE1	'z'
+#define START_BYTE2	'b'
+#define MAX_DATA_SIZE	127
+
+#define IDLE_MODE	0x00
+#define RX_MODE		0x02
+#define TX_MODE		0x03
+#define FORCE_TRX_OFF	0xF0
+
+#define STATUS_SUCCESS	0
+#define STATUS_RX_ON	1
+#define STATUS_TX_ON	2
+#define STATUS_TRX_OFF	3
+#define STATUS_IDLE	4
+#define STATUS_BUSY	5
+#define STATUS_BUSY_RX	6
+#define STATUS_BUSY_TX	7
+#define STATUS_ERR	8
+
+/* We re-use PPP ioctl for our purposes */
+#define	PPPIOCGUNIT	_IOR('t', 86, int)	/* get ppp unit number */
+
+/*
+ * The following messages are used to control ZigBee firmware.
+ * All communication has request/response format,
+ * except of asynchronous incoming data stream (DATA_RECV_* messages).
+ */
+enum {
+	NO_ID			= 0, /* means no pending id */
+
+	/* Driver to Firmware */
+	CMD_OPEN		= 0x01, /* u8 id */
+	CMD_CLOSE		= 0x02, /* u8 id */
+	CMD_SET_CHANNEL		= 0x04, /* u8 id, u8 channel */
+	CMD_ED			= 0x05, /* u8 id */
+	CMD_CCA			= 0x06, /* u8 id */
+	CMD_SET_STATE		= 0x07, /* u8 id, u8 flag */
+	DATA_XMIT_BLOCK		= 0x09, /* u8 id, u8 len, u8 data[len] */
+	DATA_XMIT_STREAM	= 0x0a, /* u8 id, u8 c */
+	RESP_RECV_BLOCK		= 0x0b, /* u8 id, u8 status */
+	RESP_RECV_STREAM	= 0x0c, /* u8 id, u8 status */
+
+	/* Firmware to Driver */
+	RESP_OPEN		= 0x81, /* u8 id, u8 status */
+	RESP_CLOSE		= 0x82, /* u8 id, u8 status */
+	RESP_SET_CHANNEL 	= 0x84, /* u8 id, u8 status */
+	RESP_ED			= 0x85, /* u8 id, u8 status, u8 level */
+	RESP_CCA		= 0x86, /* u8 id, u8 status */
+	RESP_SET_STATE		= 0x87, /* u8 id, u8 status */
+	RESP_XMIT_BLOCK		= 0x89, /* u8 id, u8 status */
+	RESP_XMIT_STREAM	= 0x8a, /* u8 id, u8 status */
+	DATA_RECV_BLOCK		= 0x8b, /* u8 id, u8 lq, u8 len, u8 data[len] */
+	DATA_RECV_STREAM	= 0x8c  /* u8 id, u8 c */
+};
+
+enum {
+	STATE_WAIT_START1,
+	STATE_WAIT_START2,
+	STATE_WAIT_COMMAND,
+	STATE_WAIT_PARAM1,
+	STATE_WAIT_PARAM2,
+	STATE_WAIT_DATA
+};
+
+struct zb_device {
+	/* Relative devices */
+	struct tty_struct	*tty;
+	struct ieee802154_dev	*dev;
+
+	/* locks the ldisc for the command */
+	struct mutex		mutex;
+
+	/* command completition */
+	wait_queue_head_t	wq;
+	phy_status_t		status;
+	u8			ed;
+
+	/* Internal state */
+	struct completion	open_done;
+	unsigned char		opened;
+	u8			pending_id;
+	unsigned int		pending_size;
+	u8			*pending_data;
+	/* FIXME: WE NEED LOCKING!!! */
+
+	/* Command (rx) processing */
+	int			state;
+	unsigned char		id;
+	unsigned char		param1;
+	unsigned char		param2;
+	unsigned char		index;
+	unsigned char		data[MAX_DATA_SIZE];
+};
+
+/*****************************************************************************
+ * ZigBee serial device protocol handling
+ *****************************************************************************/
+static int _open_dev(struct zb_device *zbdev);
+
+static int
+_send_pending_data(struct zb_device *zbdev)
+{
+	unsigned int j;
+	struct tty_struct *tty;
+
+	BUG_ON(!zbdev);
+	tty = zbdev->tty;
+	if (!tty)
+		return -ENODEV;
+
+	zbdev->status = PHY_INVAL;
+
+	/* Debug info */
+	printk(KERN_INFO "%lu %s, %d bytes:", jiffies, __func__, zbdev->pending_size);
+	for (j = 0; j < zbdev->pending_size; ++j)
+		printk(KERN_CONT " 0x%02X", zbdev->pending_data[j]);
+	printk(KERN_CONT "\n");
+
+	if (tty->driver->ops->write(tty, zbdev->pending_data, zbdev->pending_size) != zbdev->pending_size) {
+		printk(KERN_ERR "%s: device write failed\n", __func__);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+send_cmd(struct zb_device *zbdev, u8 id)
+{
+	u8 len = 0, buf[4];	/* 4 because of 2 start bytes, id and optional extra */
+
+	/* Check arguments */
+	BUG_ON(!zbdev);
+
+	if (!zbdev->opened) {
+		if (!_open_dev(zbdev))
+			return -EAGAIN;
+	}
+
+	pr_debug("%s(): id = %u\n", __func__, id);
+	if (zbdev->pending_size) {
+		printk(KERN_ERR "%s(): cmd is already pending, id = %u\n",
+			__func__, zbdev->pending_id);
+		BUG();
+	}
+
+	/* Prepare a message */
+	buf[len++] = START_BYTE1;
+	buf[len++] = START_BYTE2;
+	buf[len++] = id;
+
+	zbdev->pending_id = id;
+	zbdev->pending_size = len;
+	zbdev->pending_data = kzalloc(zbdev->pending_size, GFP_KERNEL);
+	if (!zbdev->pending_data) {
+		printk(KERN_ERR "%s(): unable to allocate memory\n", __func__);
+		zbdev->pending_id = 0;
+		zbdev->pending_size = 0;
+		return -ENOMEM;
+	}
+	memcpy(zbdev->pending_data, buf, len);
+
+	return _send_pending_data(zbdev);
+}
+
+static int
+send_cmd2(struct zb_device *zbdev, u8 id, u8 extra)
+{
+	u8 len = 0, buf[4];	/* 4 because of 2 start bytes, id and optional extra */
+
+	/* Check arguments */
+	BUG_ON(!zbdev);
+
+	if (!zbdev->opened) {
+		if (!_open_dev(zbdev))
+			return -EAGAIN;
+	}
+
+	pr_debug("%s(): id = %u\n", __func__, id);
+	if (zbdev->pending_size) {
+		printk(KERN_ERR "%s(): cmd is already pending, id = %u\n",
+			__func__, zbdev->pending_id);
+		BUG();
+	}
+
+	/* Prepare a message */
+	buf[len++] = START_BYTE1;
+	buf[len++] = START_BYTE2;
+	buf[len++] = id;
+	buf[len++] = extra;
+
+	zbdev->pending_id = id;
+	zbdev->pending_size = len;
+	zbdev->pending_data = kzalloc(zbdev->pending_size, GFP_KERNEL);
+	if (!zbdev->pending_data) {
+		printk(KERN_ERR "%s(): unable to allocate memory\n", __func__);
+		zbdev->pending_id = 0;
+		zbdev->pending_size = 0;
+		return -ENOMEM;
+	}
+	memcpy(zbdev->pending_data, buf, len);
+
+	return _send_pending_data(zbdev);
+}
+
+static int
+send_block(struct zb_device *zbdev, u8 len, u8 *data)
+{
+	u8 i = 0, buf[4];	/* 4 because of 2 start bytes, id and len */
+
+	/* Check arguments */
+	BUG_ON(!zbdev);
+
+	if (!zbdev->opened) {
+		if (!_open_dev(zbdev))
+			return -EAGAIN;
+	}
+
+	pr_debug("%s(): id = %u\n", __func__, DATA_XMIT_BLOCK);
+	if (zbdev->pending_size) {
+		printk(KERN_ERR "%s(): cmd is already pending, id = %u\n",
+			__func__, zbdev->pending_id);
+		BUG();
+	}
+
+	/* Prepare a message */
+	buf[i++] = START_BYTE1;
+	buf[i++] = START_BYTE2;
+	buf[i++] = DATA_XMIT_BLOCK;
+	buf[i++] = len;
+
+	zbdev->pending_id = DATA_XMIT_BLOCK;
+	zbdev->pending_size = i + len;
+	zbdev->pending_data = kzalloc(zbdev->pending_size, GFP_KERNEL);
+	if (!zbdev->pending_data) {
+		printk(KERN_ERR "%s(): unable to allocate memory\n", __func__);
+		zbdev->pending_id = 0;
+		zbdev->pending_size = 0;
+		return -ENOMEM;
+	}
+	memcpy(zbdev->pending_data, buf, i);
+	memcpy(zbdev->pending_data + i, data, len);
+
+	return _send_pending_data(zbdev);
+}
+
+static void
+cleanup(struct zb_device *zbdev)
+{
+	zbdev->state = STATE_WAIT_START1;
+	zbdev->id = 0;
+	zbdev->param1 = 0;
+	zbdev->param2 = 0;
+	zbdev->index = 0;
+}
+
+static int
+is_command(unsigned char c)
+{
+	switch (c) {
+	/* ids we can get here: */
+	case RESP_OPEN:
+	case RESP_CLOSE:
+	case RESP_SET_CHANNEL:
+	case RESP_ED:
+	case RESP_CCA:
+	case RESP_SET_STATE:
+	case RESP_XMIT_BLOCK:
+	case RESP_XMIT_STREAM:
+	case DATA_RECV_BLOCK:
+	case DATA_RECV_STREAM:
+		return 1;
+	}
+	return 0;
+}
+
+static int
+_match_pending_id(struct zb_device *zbdev)
+{
+	return ((CMD_OPEN == zbdev->pending_id && RESP_OPEN == zbdev->id)
+		|| (CMD_CLOSE == zbdev->pending_id && RESP_CLOSE == zbdev->id)
+		|| (CMD_SET_CHANNEL == zbdev->pending_id && RESP_SET_CHANNEL == zbdev->id)
+		|| (CMD_ED == zbdev->pending_id && RESP_ED == zbdev->id)
+		|| (CMD_CCA == zbdev->pending_id && RESP_CCA == zbdev->id)
+		|| (CMD_SET_STATE == zbdev->pending_id && RESP_SET_STATE == zbdev->id)
+		|| (DATA_XMIT_BLOCK == zbdev->pending_id && RESP_XMIT_BLOCK == zbdev->id)
+		|| (DATA_XMIT_STREAM == zbdev->pending_id && RESP_XMIT_STREAM == zbdev->id)
+		|| DATA_RECV_BLOCK == zbdev->id
+		|| DATA_RECV_STREAM == zbdev->id);
+}
+
+static void serial_net_rx(struct zb_device *zbdev)
+{
+	/* zbdev->param1 is LQI
+	 * zbdev->param2 is length of data
+	 * zbdev->data is data itself
+	 */
+	struct sk_buff *skb;
+	skb = alloc_skb(zbdev->param2, GFP_ATOMIC);
+	skb_put(skb, zbdev->param2);
+	skb_copy_to_linear_data(skb, zbdev->data, zbdev->param2);
+	ieee802154_rx_irqsafe(zbdev->dev, skb, zbdev->param1);
+}
+
+static void
+process_command(struct zb_device *zbdev)
+{
+	/* Command processing */
+	if (!_match_pending_id(zbdev))
+		return;
+
+	if (RESP_OPEN == zbdev->id && STATUS_SUCCESS == zbdev->param1) {
+		zbdev->opened = 1;
+		pr_debug("Opened device\n");
+		complete(&zbdev->open_done);
+		/* Input is not processed during output, so
+		 * using completion is not possible during output.
+		 * so we need to handle open as any other command
+		 * and hope for best
+		 */
+		return;
+	}
+
+	if (!zbdev->opened)
+		return;
+
+	zbdev->pending_id = 0;
+	kfree(zbdev->pending_data);
+	zbdev->pending_data = NULL;
+	zbdev->pending_size = 0;
+	if (zbdev->id != DATA_RECV_BLOCK)
+		switch (zbdev->param1) {
+		case STATUS_SUCCESS:
+			zbdev->status = PHY_SUCCESS;
+			break;
+		case STATUS_RX_ON:
+			zbdev->status = PHY_RX_ON;
+			break;
+		case STATUS_TX_ON:
+			zbdev->status = PHY_TX_ON;
+			break;
+		case STATUS_TRX_OFF:
+			zbdev->status = PHY_TRX_OFF;
+			break;
+		case STATUS_BUSY:
+			zbdev->status = PHY_BUSY;
+			break;
+		case STATUS_IDLE:
+			zbdev->status = PHY_IDLE;
+			break;
+		case STATUS_BUSY_RX:
+			zbdev->status = PHY_BUSY_RX;
+			break;
+		case STATUS_BUSY_TX:
+			zbdev->status = PHY_BUSY_TX;
+			break;
+		default:
+			printk(KERN_ERR "%s: bad status received from firmware: %u\n",
+				__func__, zbdev->param1);
+			zbdev->status = PHY_ERROR;
+			break;
+		}
+
+	switch (zbdev->id) {
+	case RESP_ED:
+		zbdev->ed = zbdev->param2;
+		break;
+	case DATA_RECV_BLOCK:
+		pr_debug("Received block, lqi %02x, len %02x\n", zbdev->param1, zbdev->param2);
+		/* zbdev->param1 is LQ, zbdev->param2 is length */
+		serial_net_rx(zbdev);
+		break;
+	case DATA_RECV_STREAM:
+		/* TODO: update firmware to use this */
+		break;
+	}
+
+	wake_up(&zbdev->wq);
+}
+
+static void
+process_char(struct zb_device *zbdev, unsigned char c)
+{
+	/* Data processing */
+	pr_debug("Char: %d (0x%02x)\n", c, c);
+	switch (zbdev->state) {
+	case STATE_WAIT_START1:
+		if (START_BYTE1 == c)
+			zbdev->state = STATE_WAIT_START2;
+		break;
+
+	case STATE_WAIT_START2:
+		if (START_BYTE2 == c)
+			zbdev->state = STATE_WAIT_COMMAND;
+		else
+			cleanup(zbdev);
+		break;
+
+	case STATE_WAIT_COMMAND:
+		if (is_command(c)) {
+			zbdev->id = c;
+			zbdev->state = STATE_WAIT_PARAM1;
+		} else {
+			cleanup(zbdev);
+			printk(KERN_ERR "%s, unexpected command id: %x\n", __func__, c);
+		}
+		break;
+
+	case STATE_WAIT_PARAM1:
+		zbdev->param1 = c;
+		if ((RESP_ED == zbdev->id) || (DATA_RECV_BLOCK == zbdev->id))
+			zbdev->state = STATE_WAIT_PARAM2;
+		else {
+			process_command(zbdev);
+			cleanup(zbdev);
+		}
+		break;
+
+	case STATE_WAIT_PARAM2:
+		zbdev->param2 = c;
+		if (RESP_ED == zbdev->id) {
+			process_command(zbdev);
+			cleanup(zbdev);
+		} else if (DATA_RECV_BLOCK == zbdev->id)
+			zbdev->state = STATE_WAIT_DATA;
+		else
+			cleanup(zbdev);
+		break;
+
+	case STATE_WAIT_DATA:
+		if (zbdev->index < sizeof(zbdev->data)) {
+			zbdev->data[zbdev->index] = c;
+			zbdev->index++;
+			/* Pending data is received, param2 is length for DATA_RECV_BLOCK */
+			if (zbdev->index == zbdev->param2) {
+				process_command(zbdev);
+				cleanup(zbdev);
+			}
+		} else {
+			printk(KERN_ERR "%s(): data size is greater "
+				"than buffer available\n", __func__);
+			cleanup(zbdev);
+		}
+		break;
+
+	default:
+		cleanup(zbdev);
+	}
+}
+
+/*****************************************************************************
+ * Device operations for IEEE 802.15.4 PHY side interface ZigBee stack
+ *****************************************************************************/
+
+static int _open_dev(struct zb_device *zbdev)
+{
+	int retries;
+	u8 len = 0, buf[4];	/* 4 because of 2 start bytes, id and optional extra */
+
+	/* Check arguments */
+	BUG_ON(!zbdev);
+	if (zbdev->opened)
+		return 1;
+
+	pr_debug("%s()\n", __func__);
+	if (zbdev->pending_size) {
+		printk(KERN_ERR "%s(): cmd is already pending, id = %u\n",
+			__func__, zbdev->pending_id);
+		BUG();
+	}
+
+	/* Prepare a message */
+	buf[len++] = START_BYTE1;
+	buf[len++] = START_BYTE2;
+	buf[len++] = CMD_OPEN;
+
+	zbdev->pending_id = CMD_OPEN;
+	zbdev->pending_size = len;
+	zbdev->pending_data = kzalloc(zbdev->pending_size, GFP_KERNEL);
+	if (!zbdev->pending_data) {
+		printk(KERN_ERR "%s(): unable to allocate memory\n", __func__);
+		zbdev->pending_id = 0;
+		zbdev->pending_size = 0;
+		return -ENOMEM;
+	}
+	memcpy(zbdev->pending_data, buf, len);
+
+	retries = 5;
+	while (!zbdev->opened && retries) {
+		if (_send_pending_data(zbdev) != 0)
+			return 0;
+
+		/* 3 second before retransmission */
+		wait_for_completion_interruptible_timeout(&zbdev->open_done, msecs_to_jiffies(1000));
+		--retries;
+	}
+
+	zbdev->pending_id = 0;
+	kfree(zbdev->pending_data);
+	zbdev->pending_data = NULL;
+	zbdev->pending_size = 0;
+
+	if (zbdev->opened) {
+		printk(KERN_INFO "Opened connection to device\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+/* Valid channels: 1-16 */
+static phy_status_t
+ieee802154_serial_set_channel(struct ieee802154_dev *dev, int channel)
+{
+	struct zb_device *zbdev;
+	phy_status_t ret;
+
+	pr_debug("%s\n", __func__);
+
+	zbdev = dev->priv;
+	if (NULL == zbdev) {
+		printk(KERN_ERR "%s: wrong phy\n", __func__);
+		return PHY_INVAL;
+	}
+
+	if (mutex_lock_interruptible(&zbdev->mutex))
+		return PHY_ERROR;
+	/* Our channels are actually from 11 to 26
+	 * We have IEEE802.15.4 channel no from 0 to 26.
+	 * channels 0-10 are not valid for us */
+	BUG_ON(channel < 11 || channel > 26);
+	/* ...  but our crappy firmware numbers channels from 1 to 16
+	 * which is a mystery. We suould enforce that using PIB API
+	 * but additional checking here won't kill, and gcc will
+	 * optimize this stuff anyway. */
+	BUG_ON((channel - 10) < 1 && (channel - 10) > 16);
+
+	if (send_cmd2(zbdev, CMD_SET_CHANNEL, channel - 10) != 0) {
+		ret = PHY_ERROR;
+		goto out;
+	}
+
+	if (wait_event_interruptible_timeout(zbdev->wq, zbdev->status != PHY_INVAL, msecs_to_jiffies(1000)) > 0)
+		ret = zbdev->status;
+	else
+		ret = PHY_ERROR;
+
+	if (ret == PHY_SUCCESS)
+		zbdev->dev->current_channel = channel;
+out:
+	mutex_unlock(&zbdev->mutex);
+	pr_debug("%s end\n", __func__);
+	return ret;
+}
+
+static phy_status_t
+ieee802154_serial_ed(struct ieee802154_dev *dev, u8 *level)
+{
+	struct zb_device *zbdev;
+	phy_status_t ret;
+
+	pr_debug("%s\n", __func__);
+
+	zbdev = dev->priv;
+	if (NULL == zbdev) {
+		printk(KERN_ERR "%s: wrong phy\n", __func__);
+		return PHY_INVAL;
+	}
+
+	if (mutex_lock_interruptible(&zbdev->mutex))
+		return PHY_ERROR;
+
+#if 0
+	if (send_cmd(zbdev, CMD_ED) != 0) {
+		ret = PHY_ERROR;
+		goto out;
+	}
+
+	if (wait_event_interruptible_timeout(zbdev->wq, zbdev->status != PHY_INVAL, msecs_to_jiffies(1000)) > 0) {
+		*level = zbdev->ed;
+		ret = zbdev->status;
+	} else
+		ret = PHY_ERROR;
+out:
+#else
+	/* Lets suppose we have energy on all channels
+	 * till we fix something regarding hardware or driver */
+	*level = 0xbe;
+	ret = PHY_SUCCESS;
+#endif
+	mutex_unlock(&zbdev->mutex);
+	pr_debug("%s end\n", __func__);
+	return ret;
+}
+
+static phy_status_t
+ieee802154_serial_cca(struct ieee802154_dev *dev)
+{
+	struct zb_device *zbdev;
+	phy_status_t ret;
+
+	pr_debug("%s\n", __func__);
+
+	zbdev = dev->priv;
+	if (NULL == zbdev) {
+		printk(KERN_ERR "%s: wrong phy\n", __func__);
+		return PHY_INVAL;
+	}
+
+	if (mutex_lock_interruptible(&zbdev->mutex))
+		return PHY_ERROR;
+
+	if (send_cmd(zbdev, CMD_CCA) != 0) {
+		ret = PHY_ERROR;
+		goto out;
+	}
+
+	if (wait_event_interruptible_timeout(zbdev->wq, zbdev->status != PHY_INVAL, msecs_to_jiffies(1000)) > 0)
+		ret = zbdev->status;
+	else
+		ret = PHY_ERROR;
+out:
+	mutex_unlock(&zbdev->mutex);
+	pr_debug("%s end\n", __func__);
+	return ret;
+}
+
+static phy_status_t
+ieee802154_serial_set_state(struct ieee802154_dev *dev, phy_status_t state)
+{
+	struct zb_device *zbdev;
+	unsigned char flag;
+	phy_status_t ret;
+
+	pr_debug("%s %d\n", __func__, state);
+
+	zbdev = dev->priv;
+	if (NULL == zbdev) {
+		printk(KERN_ERR "%s: wrong phy\n", __func__);
+		return PHY_INVAL;
+	}
+
+	if (mutex_lock_interruptible(&zbdev->mutex))
+		return PHY_ERROR;
+
+	switch (state) {
+	case PHY_RX_ON:
+		flag = RX_MODE;
+		break;
+	case PHY_TX_ON:
+		flag = TX_MODE;
+		break;
+	case PHY_TRX_OFF:
+		flag = IDLE_MODE;
+		break;
+	case PHY_FORCE_TRX_OFF:
+		flag = FORCE_TRX_OFF;
+		break;
+	default:
+		ret = PHY_INVAL;
+		goto out;
+	}
+
+	if (send_cmd2(zbdev, CMD_SET_STATE, flag) != 0) {
+		ret = PHY_ERROR;
+		goto out;
+	}
+
+	if (wait_event_interruptible_timeout(zbdev->wq, zbdev->status != PHY_INVAL, msecs_to_jiffies(1000)) > 0)
+		ret = zbdev->status;
+	else
+		ret = PHY_ERROR;
+out:
+	mutex_unlock(&zbdev->mutex);
+	pr_debug("%s end\n", __func__);
+	return ret;
+}
+
+static phy_status_t
+ieee802154_serial_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
+{
+	struct zb_device *zbdev;
+	phy_status_t ret;
+
+	pr_debug("%s\n", __func__);
+
+	zbdev = dev->priv;
+	if (NULL == zbdev) {
+		printk(KERN_ERR "%s: wrong phy\n", __func__);
+		return PHY_INVAL;
+	}
+
+	if (mutex_lock_interruptible(&zbdev->mutex))
+		return PHY_ERROR;
+
+	if (send_block(zbdev, skb->len, skb->data) != 0) {
+		ret = PHY_ERROR;
+		goto out;
+	}
+
+	if (wait_event_interruptible_timeout(zbdev->wq, zbdev->status != PHY_INVAL, msecs_to_jiffies(1000)) > 0)
+		ret = zbdev->status;
+	else
+		ret = PHY_ERROR;
+out:
+
+	mutex_unlock(&zbdev->mutex);
+	pr_debug("%s end\n", __func__);
+	return ret;
+}
+
+/*****************************************************************************
+ * Line discipline interface for IEEE 802.15.4 serial device
+ *****************************************************************************/
+
+static struct ieee802154_ops serial_ops = {
+	.owner = THIS_MODULE,
+	.tx = ieee802154_serial_xmit,
+	.ed = ieee802154_serial_ed,
+	.cca = ieee802154_serial_cca,
+	.set_trx_state = ieee802154_serial_set_state,
+	.set_channel	= ieee802154_serial_set_channel,
+};
+
+static int dev_minor_match(struct device *dev, void *data)
+{
+	int *minor = data;
+	return MINOR(dev->devt) == *minor;
+}
+
+/*
+ * Called when a tty is put into ZB line discipline. Called in process context.
+ * Returns 0 on success.
+ */
+static int
+ieee802154_tty_open(struct tty_struct *tty)
+{
+	struct zb_device *zbdev = tty->disc_data;
+	int err;
+	int minor;
+
+	pr_debug("Openning ldisc\n");
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	if (zbdev)
+		return -EBUSY;
+
+	/* Allocate device structure */
+	zbdev = kzalloc(sizeof(struct zb_device), GFP_KERNEL);
+	if (NULL == zbdev) {
+		printk(KERN_ERR "%s: can't allocate zb_device structure.\n", __func__);
+		return -ENOMEM;
+	}
+	mutex_init(&zbdev->mutex);
+	init_completion(&zbdev->open_done);
+	init_waitqueue_head(&zbdev->wq);
+
+	zbdev->dev = ieee802154_alloc_device();
+	if (!zbdev->dev) {
+		err = -ENOMEM;
+		goto out_free_zb;
+	}
+
+	zbdev->dev->name		= "serialdev";
+	zbdev->dev->priv		= zbdev;
+	zbdev->dev->extra_tx_headroom	= 0;
+	zbdev->dev->channel_mask	= 0x7ff;
+	zbdev->dev->current_channel	= 11; /* it's 1st channel of 2.4 Ghz space */
+	zbdev->dev->flags		= IEEE802154_FLAGS_OMIT_CKSUM;
+
+	minor = tty->index + tty->driver->minor_start;
+	zbdev->dev->parent = class_find_device(tty_class, NULL, &minor, dev_minor_match);
+
+	zbdev->tty = tty;
+	cleanup(zbdev);
+
+	tty->disc_data = zbdev;
+	tty->receive_room = MAX_DATA_SIZE;
+	tty->low_latency = 1;
+
+	/* FIXME: why is this needed. Note don't use ldisc_ref here as the
+	   open path is before the ldisc is referencable */
+
+	if (tty->ldisc.ops->flush_buffer)
+		tty->ldisc.ops->flush_buffer(tty);
+	tty_driver_flush_buffer(tty);
+
+	err = ieee802154_register_device(zbdev->dev, &serial_ops);
+	/* we put it only after it has a chance to be get by network core */
+	if (zbdev->dev->parent)
+		put_device(zbdev->dev->parent);
+	if (err) {
+		printk(KERN_ERR "%s: device register failed\n", __func__);
+		goto out_free;
+	}
+
+	return 0;
+
+	ieee802154_unregister_device(zbdev->dev);
+
+out_free:
+	tty->disc_data = NULL;
+
+	ieee802154_free_device(zbdev->dev);
+out_free_zb:
+	kfree(zbdev);
+
+	return err;
+}
+
+/*
+ * Called when the tty is put into another line discipline or it hangs up. We
+ * have to wait for any cpu currently executing in any of the other zb_tty_*
+ * routines to finish before we can call zb_tty_close and free the
+ * zb_serial_dev struct. This routine must be called from process context, not
+ * interrupt or softirq context.
+ */
+static void
+ieee802154_tty_close(struct tty_struct *tty)
+{
+	struct zb_device *zbdev;
+
+	zbdev = tty->disc_data;
+	if (NULL == zbdev) {
+		printk(KERN_WARNING "%s: match is not found\n", __func__);
+		return;
+	}
+
+	tty->disc_data = NULL;
+	zbdev->tty = NULL;
+
+	ieee802154_unregister_device(zbdev->dev);
+
+	tty_ldisc_flush(tty);
+	tty_driver_flush_buffer(tty);
+
+	ieee802154_free_device(zbdev->dev);
+	kfree(zbdev);
+}
+
+/*
+ * Called on tty hangup in process context.
+ */
+static int
+ieee802154_tty_hangup(struct tty_struct *tty)
+{
+	ieee802154_tty_close(tty);
+	return 0;
+}
+
+/*
+ * Called in process context only. May be re-entered by multiple ioctl calling threads.
+ */
+static int
+ieee802154_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct zb_device *zbdev;
+	struct ifreq ifr;
+	int err;
+	void __user *argp = (void __user *) arg;
+
+	pr_debug("cmd = 0x%x\n", cmd);
+	memset(&ifr, 0, sizeof(ifr));
+
+	zbdev = tty->disc_data;
+	if (NULL == zbdev) {
+		pr_debug("match is not found\n");
+		return -EINVAL;
+	}
+
+
+	switch (cmd) {
+	case PPPIOCGUNIT:
+		/* TODO: some error checking */
+		BUG_ON(!zbdev->dev->netdev);
+		err = -EFAULT;
+		if (copy_to_user(argp, zbdev->dev->netdev->name, strlen(zbdev->dev->netdev->name)))
+			break;
+		err = 0;
+		break;
+	default:
+		pr_debug("Unknown ioctl cmd: %u\n", cmd);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+
+/*
+ * This can now be called from hard interrupt level as well
+ * as soft interrupt level or mainline.
+ */
+static void
+ieee802154_tty_receive(struct tty_struct *tty, const unsigned char *buf, char *cflags, int count)
+{
+	struct zb_device *zbdev;
+	int i;
+
+	/* Debug info */
+	printk(KERN_INFO "%lu %s, received %d bytes:", jiffies, __func__, count);
+	for (i = 0; i < count; ++i)
+		printk(KERN_CONT " 0x%02X", buf[i]);
+	printk(KERN_CONT "\n");
+
+	/* Actual processing */
+	zbdev = tty->disc_data;
+	if (NULL == zbdev) {
+		printk(KERN_ERR "%s(): record for tty is not found\n", __func__);
+		return;
+	}
+	for (i = 0; i < count; ++i)
+		process_char(zbdev, buf[i]);
+#if 0
+	if (tty->driver->flush_chars)
+		tty->driver->flush_chars(tty);
+#endif
+	tty_unthrottle(tty);
+}
+
+/*
+ * Line discipline device structure
+ */
+static struct tty_ldisc_ops ieee802154_ldisc = {
+	.owner  = THIS_MODULE,
+	.magic	= TTY_LDISC_MAGIC,
+	.name	= "ieee802154-ldisc",
+	.open	= ieee802154_tty_open,
+	.close	= ieee802154_tty_close,
+	.hangup	= ieee802154_tty_hangup,
+	.receive_buf = ieee802154_tty_receive,
+	.ioctl	= ieee802154_tty_ioctl,
+};
+
+/*****************************************************************************
+ * Module service routinues
+ *****************************************************************************/
+
+static int __init ieee802154_serial_init(void)
+{
+	printk(KERN_INFO "Initializing ZigBee TTY interface\n");
+
+	if (tty_register_ldisc(N_IEEE802154, &ieee802154_ldisc) != 0) {
+		printk(KERN_ERR "%s: line discipline register failed\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void __exit ieee802154_serial_cleanup(void)
+{
+	if (tty_unregister_ldisc(N_IEEE802154) != 0)
+		printk(KERN_CRIT "failed to unregister ZigBee line discipline.\n");
+}
+
+module_init(ieee802154_serial_init);
+module_exit(ieee802154_serial_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_LDISC(N_IEEE802154);
+
diff --git a/include/linux/tty.h b/include/linux/tty.h
index fc39db9..f533beb 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -23,7 +23,7 @@
  */
 #define NR_UNIX98_PTY_DEFAULT	4096      /* Default maximum for Unix98 ptys */
 #define NR_UNIX98_PTY_MAX	(1 << MINORBITS) /* Absolute limit */
-#define NR_LDISCS		19
+#define NR_LDISCS		20
 
 /* line disciplines */
 #define N_TTY		0
@@ -46,6 +46,7 @@
 #define N_GIGASET_M101	16	/* Siemens Gigaset M101 serial DECT adapter */
 #define N_SLCAN		17	/* Serial / USB serial CAN Adaptors */
 #define N_PPS		18	/* Pulse per Second */
+#define N_IEEE802154	19	/* Serial / USB serial IEEE802154.4 devices */
 
 /*
  * This character is the same as _POSIX_VDISABLE: it cannot be used as
-- 
1.6.2.4

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [PATCH 10/10] ieee802154: add at86rf230/rf231 spi driver
@ 2009-06-01 14:54                     ` Dmitry Eremin-Solenikov
  0 siblings, 0 replies; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-01 14:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: netdev, linux-wireless, slapin, maxim.osipov, dmitry.baryshkov,
	oliver.fendt, Dmitry Eremin-Solenikov

Add a driver handling AT86RF230/RF231 line of chips. Only basic
features are currently implemented (no extended mode operation, etc.)
Also the RF230 chip is not really supported yet.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Signed-off-by: Sergey Lapin <slapin@ossfans.org>
---
 drivers/ieee802154/Kconfig     |    5 +
 drivers/ieee802154/Makefile    |    1 +
 drivers/ieee802154/at86rf230.c |  971 ++++++++++++++++++++++++++++++++++++++++
 include/linux/spi/at86rf230.h  |   32 ++
 4 files changed, 1009 insertions(+), 0 deletions(-)
 create mode 100644 drivers/ieee802154/at86rf230.c
 create mode 100644 include/linux/spi/at86rf230.h

diff --git a/drivers/ieee802154/Kconfig b/drivers/ieee802154/Kconfig
index 0e65572..eff0423 100644
--- a/drivers/ieee802154/Kconfig
+++ b/drivers/ieee802154/Kconfig
@@ -33,5 +33,10 @@ config IEEE802154_FAKELB
 config IEEE802154_SERIAL
 	tristate "Simple LR-WPAN UART driver"
 
+config IEEE802154_AT86RF230
+	tristate "AT86RF230 transceiver driver"
+	depends on SPI
+
+
 endif
 
diff --git a/drivers/ieee802154/Makefile b/drivers/ieee802154/Makefile
index ca41e99..76237f3 100644
--- a/drivers/ieee802154/Makefile
+++ b/drivers/ieee802154/Makefile
@@ -1,5 +1,6 @@
 obj-$(CONFIG_IEEE802154_FAKEHARD) += fakehard.o
 obj-$(CONFIG_IEEE802154_FAKELB) += fakelb.o
 obj-$(CONFIG_IEEE802154_SERIAL) += serial.o
+obj-$(CONFIG_IEEE802154_AT86RF230) += at86rf230.o
 
 EXTRA_CFLAGS += -DDEBUG -DCONFIG_FFD
diff --git a/drivers/ieee802154/at86rf230.c b/drivers/ieee802154/at86rf230.c
new file mode 100644
index 0000000..a4ead47
--- /dev/null
+++ b/drivers/ieee802154/at86rf230.c
@@ -0,0 +1,971 @@
+#undef AT86RF230_OLDFW_HACK
+/*
+ * AT86RF230/RF231 driver
+ *
+ * Copyright (C) 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 <dmitry.baryshkov@siemens.com>
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/spinlock.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/at86rf230.h>
+#include <linux/rtnetlink.h> /* FIXME: hack for slave instantiation */
+
+#include <net/ieee802154/mac802154.h>
+
+struct at86rf230_local {
+	struct spi_device *spi;
+	int rstn, slp_tr, dig2;
+
+	u8 part;
+	u8 vers;
+
+	u8 buf[2];
+	struct mutex bmux;
+
+	struct work_struct irqwork;
+	struct completion tx_complete;
+
+	struct ieee802154_dev *dev;
+
+	spinlock_t lock;
+	unsigned irq_disabled:1; /* P: lock */
+	unsigned is_tx:1; /* P: lock */
+};
+
+#define	RG_TRX_STATUS	(0x01)
+#define	SR_TRX_STATUS		0x01, 0x1f, 0
+#define	SR_RESERVED_01_3	0x01, 0x20, 5
+#define	SR_CCA_STATUS		0x01, 0x40, 6
+#define	SR_CCA_DONE		0x01, 0x80, 7
+#define	RG_TRX_STATE	(0x02)
+#define	SR_TRX_CMD		0x02, 0x1f, 0
+#define	SR_TRAC_STATUS		0x02, 0xe0, 5
+#define	RG_TRX_CTRL_0	(0x03)
+#define	SR_CLKM_CTRL		0x03, 0x07, 0
+#define	SR_CLKM_SHA_SEL		0x03, 0x08, 3
+#define	SR_PAD_IO_CLKM		0x03, 0x30, 4
+#define	SR_PAD_IO		0x03, 0xc0, 6
+#define	RG_TRX_CTRL_1	(0x04)
+#define	SR_IRQ_POLARITY		0x04, 0x01, 0
+#define	SR_IRQ_MASK_MODE	0x04, 0x02, 1
+#define	SR_SPI_CMD_MODE		0x04, 0x0c, 2
+#define	SR_RX_BL_CTRL		0x04, 0x10, 4
+#define	SR_TX_AUTO_CRC_ON	0x04, 0x20, 5
+#define	SR_IRQ_2_EXT_EN		0x04, 0x40, 6
+#define	SR_PA_EXT_EN		0x04, 0x80, 7
+#define	RG_PHY_TX_PWR	(0x05)
+#define	SR_TX_PWR		0x05, 0x0f, 0
+#define	SR_PA_LT		0x05, 0x30, 4
+#define	SR_PA_BUF_LT		0x05, 0xc0, 6
+#define	RG_PHY_RSSI	(0x06)
+#define	SR_RSSI			0x06, 0x1f, 0
+#define	SR_RND_VALUE		0x06, 0x60, 5
+#define	SR_RX_CRC_VALID		0x06, 0x80, 7
+#define	RG_PHY_ED_LEVEL	(0x07)
+#define	SR_ED_LEVEL		0x07, 0xff, 0
+#define	RG_PHY_CC_CCA	(0x08)
+#define	SR_CHANNEL		0x08, 0x1f, 0
+#define	SR_CCA_MODE		0x08, 0x60, 5
+#define	SR_CCA_REQUEST		0x08, 0x80, 7
+#define	RG_CCA_THRES	(0x09)
+#define	SR_CCA_ED_THRES		0x09, 0x0f, 0
+#define	SR_RESERVED_09_1	0x09, 0xf0, 4
+#define	RG_RX_CTRL	(0x0a)
+#define	SR_PDT_THRES		0x0a, 0x0f, 0
+#define	SR_RESERVED_0a_1	0x0a, 0xf0, 4
+#define	RG_SFD_VALUE	(0x0b)
+#define	SR_SFD_VALUE		0x0b, 0xff, 0
+#define	RG_TRX_CTRL_2	(0x0c)
+#define	SR_OQPSK_DATA_RATE	0x0c, 0x03, 0
+#define	SR_RESERVED_0c_2	0x0c, 0x7c, 2
+#define	SR_RX_SAFE_MODE		0x0c, 0x80, 7
+#define	RG_ANT_DIV	(0x0d)
+#define	SR_ANT_CTRL		0x0d, 0x03, 0
+#define	SR_ANT_EXT_SW_EN	0x0d, 0x04, 2
+#define	SR_ANT_DIV_EN		0x0d, 0x08, 3
+#define	SR_RESERVED_0d_2	0x0d, 0x70, 4
+#define	SR_ANT_SEL		0x0d, 0x80, 7
+#define	RG_IRQ_MASK	(0x0e)
+#define	SR_IRQ_MASK		0x0e, 0xff, 0
+#define	RG_IRQ_STATUS	(0x0f)
+#define	SR_IRQ_0_PLL_LOCK	0x0f, 0x01, 0
+#define	SR_IRQ_1_PLL_UNLOCK	0x0f, 0x02, 1
+#define	SR_IRQ_2_RX_START	0x0f, 0x04, 2
+#define	SR_IRQ_3_TRX_END	0x0f, 0x08, 3
+#define	SR_IRQ_4_CCA_ED_DONE	0x0f, 0x10, 4
+#define	SR_IRQ_5_AMI		0x0f, 0x20, 5
+#define	SR_IRQ_6_TRX_UR		0x0f, 0x40, 6
+#define	SR_IRQ_7_BAT_LOW	0x0f, 0x80, 7
+#define	RG_VREG_CTRL	(0x10)
+#define	SR_RESERVED_10_6	0x10, 0x03, 0
+#define	SR_DVDD_OK		0x10, 0x04, 2
+#define	SR_DVREG_EXT		0x10, 0x08, 3
+#define	SR_RESERVED_10_3	0x10, 0x30, 4
+#define	SR_AVDD_OK		0x10, 0x40, 6
+#define	SR_AVREG_EXT		0x10, 0x80, 7
+#define	RG_BATMON	(0x11)
+#define	SR_BATMON_VTH		0x11, 0x0f, 0
+#define	SR_BATMON_HR		0x11, 0x10, 4
+#define	SR_BATMON_OK		0x11, 0x20, 5
+#define	SR_RESERVED_11_1	0x11, 0xc0, 6
+#define	RG_XOSC_CTRL	(0x12)
+#define	SR_XTAL_TRIM		0x12, 0x0f, 0
+#define	SR_XTAL_MODE		0x12, 0xf0, 4
+#define	RG_RX_SYN	(0x15)
+#define	SR_RX_PDT_LEVEL		0x15, 0x0f, 0
+#define	SR_RESERVED_15_2	0x15, 0x70, 4
+#define	SR_RX_PDT_DIS		0x15, 0x80, 7
+#define	RG_XAH_CTRL_1	(0x17)
+#define	SR_RESERVED_17_8	0x17, 0x01, 0
+#define	SR_AACK_PROM_MODE	0x17, 0x02, 1
+#define	SR_AACK_ACK_TIME	0x17, 0x04, 2
+#define	SR_RESERVED_17_5	0x17, 0x08, 3
+#define	SR_AACK_UPLD_RES_FT	0x17, 0x10, 4
+#define	SR_AACK_FLTR_RES_FT	0x17, 0x20, 5
+#define	SR_RESERVED_17_2	0x17, 0x40, 6
+#define	SR_RESERVED_17_1	0x17, 0x80, 7
+#define	RG_FTN_CTRL	(0x18)
+#define	SR_RESERVED_18_2	0x18, 0x7f, 0
+#define	SR_FTN_START		0x18, 0x80, 7
+#define	RG_PLL_CF	(0x1a)
+#define	SR_RESERVED_1a_2	0x1a, 0x7f, 0
+#define	SR_PLL_CF_START		0x1a, 0x80, 7
+#define	RG_PLL_DCU	(0x1b)
+#define	SR_RESERVED_1b_3	0x1b, 0x3f, 0
+#define	SR_RESERVED_1b_2	0x1b, 0x40, 6
+#define	SR_PLL_DCU_START	0x1b, 0x80, 7
+#define	RG_PART_NUM	(0x1c)
+#define	SR_PART_NUM		0x1c, 0xff, 0
+#define	RG_VERSION_NUM	(0x1d)
+#define	SR_VERSION_NUM		0x1d, 0xff, 0
+#define	RG_MAN_ID_0	(0x1e)
+#define	SR_MAN_ID_0		0x1e, 0xff, 0
+#define	RG_MAN_ID_1	(0x1f)
+#define	SR_MAN_ID_1		0x1f, 0xff, 0
+#define	RG_SHORT_ADDR_0	(0x20)
+#define	SR_SHORT_ADDR_0		0x20, 0xff, 0
+#define	RG_SHORT_ADDR_1	(0x21)
+#define	SR_SHORT_ADDR_1		0x21, 0xff, 0
+#define	RG_PAN_ID_0	(0x22)
+#define	SR_PAN_ID_0		0x22, 0xff, 0
+#define	RG_PAN_ID_1	(0x23)
+#define	SR_PAN_ID_1		0x23, 0xff, 0
+#define	RG_IEEE_ADDR_0	(0x24)
+#define	SR_IEEE_ADDR_0		0x24, 0xff, 0
+#define	RG_IEEE_ADDR_1	(0x25)
+#define	SR_IEEE_ADDR_1		0x25, 0xff, 0
+#define	RG_IEEE_ADDR_2	(0x26)
+#define	SR_IEEE_ADDR_2		0x26, 0xff, 0
+#define	RG_IEEE_ADDR_3	(0x27)
+#define	SR_IEEE_ADDR_3		0x27, 0xff, 0
+#define	RG_IEEE_ADDR_4	(0x28)
+#define	SR_IEEE_ADDR_4		0x28, 0xff, 0
+#define	RG_IEEE_ADDR_5	(0x29)
+#define	SR_IEEE_ADDR_5		0x29, 0xff, 0
+#define	RG_IEEE_ADDR_6	(0x2a)
+#define	SR_IEEE_ADDR_6		0x2a, 0xff, 0
+#define	RG_IEEE_ADDR_7	(0x2b)
+#define	SR_IEEE_ADDR_7		0x2b, 0xff, 0
+#define	RG_XAH_CTRL_0	(0x2c)
+#define	SR_SLOTTED_OPERATION	0x2c, 0x01, 0
+#define	SR_MAX_CSMA_RETRIES	0x2c, 0x0e, 1
+#define	SR_MAX_FRAME_RETRIES	0x2c, 0xf0, 4
+#define	RG_CSMA_SEED_0	(0x2d)
+#define	SR_CSMA_SEED_0		0x2d, 0xff, 0
+#define	RG_CSMA_SEED_1	(0x2e)
+#define	SR_CSMA_SEED_1		0x2e, 0x07, 0
+#define	SR_AACK_I_AM_COORD	0x2e, 0x08, 3
+#define	SR_AACK_DIS_ACK		0x2e, 0x10, 4
+#define	SR_AACK_SET_PD		0x2e, 0x20, 5
+#define	SR_AACK_FVN_MODE	0x2e, 0xc0, 6
+#define	RG_CSMA_BE	(0x2f)
+#define	SR_MIN_BE		0x2f, 0x0f, 0
+#define	SR_MAX_BE		0x2f, 0xf0, 4
+
+#define CMD_REG		0x80
+#define CMD_REG_MASK	0x3f
+#define CMD_WRITE	0x40
+#define CMD_FB		0x20
+
+#define IRQ_BAT_LOW	(1 << 7)
+#define IRQ_TRX_UR	(1 << 6)
+#define IRQ_AMI		(1 << 5)
+#define IRQ_CCA_ED	(1 << 4)
+#define IRQ_TRX_END	(1 << 3)
+#define IRQ_RX_START	(1 << 2)
+#define IRQ_PLL_UNL	(1 << 1)
+#define IRQ_PLL_LOCK	(1 << 0)
+
+#define STATE_P_ON		0x00	/* BUSY */
+#define STATE_BUSY_RX		0x01
+#define STATE_BUSY_TX		0x02
+#define STATE_FORCE_TRX_OFF	0x03
+#define STATE_FORCE_TX_ON	0x04	/* IDLE */
+/* 0x05 */				/* INVALID_PARAMETER */
+#define STATE_RX_ON		0x06
+/* 0x07 */				/* SUCCESS */
+#define STATE_TRX_OFF		0x08
+#define STATE_TX_ON		0x09
+/* 0x0a - 0x0e */			/* 0x0a - UNSUPPORTED_ATTRIBUTE */
+#define STATE_SLEEP		0x0F
+#define STATE_BUSY_RX_AACK	0x11
+#define STATE_BUSY_TX_ARET	0x12
+#define STATE_BUSY_RX_AACK_ON	0x16
+#define STATE_BUSY_TX_ARET_ON	0x19
+#define STATE_RX_ON_NOCLK	0x1C
+#define STATE_RX_AACK_ON_NOCLK	0x1D
+#define STATE_BUSY_RX_AACK_NOCLK 0x1E
+#define STATE_TRANSITION_IN_PROGRESS 0x1F
+
+static int
+__at86rf230_write(struct at86rf230_local *lp, u8 addr, u8 data)
+{
+	u8 *buf = lp->buf;
+	int status;
+	struct spi_message msg;
+	struct spi_transfer xfer = {
+		.len		= 2,
+		.tx_buf		= buf,
+	};
+
+	buf[0] = (addr & CMD_REG_MASK) | CMD_REG | CMD_WRITE;
+	buf[1] = data;
+	dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
+	dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+
+	status = spi_sync(lp->spi, &msg);
+	dev_vdbg(&lp->spi->dev, "status = %d\n", status);
+	if (msg.status)
+		status = msg.status;
+	dev_vdbg(&lp->spi->dev, "status = %d\n", status);
+	dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
+	dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
+
+	return status;
+}
+
+static int
+__at86rf230_read_subreg(struct at86rf230_local *lp, u8 addr, u8 mask, int shift, u8* data)
+{
+	u8 *buf = lp->buf;
+	int status;
+	struct spi_message msg;
+	struct spi_transfer xfer = {
+		.len		= 2,
+		.tx_buf		= buf,
+		.rx_buf		= buf,
+	};
+
+	buf[0] = (addr & CMD_REG_MASK) | CMD_REG;
+	buf[1] = 0xff;
+	dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+
+	status = spi_sync(lp->spi, &msg);
+	dev_vdbg(&lp->spi->dev, "status = %d\n", status);
+	if (msg.status)
+		status = msg.status;
+	dev_vdbg(&lp->spi->dev, "status = %d\n", status);
+	dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
+	dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
+
+	if (status == 0)
+		*data = buf[1];
+
+	return status;
+}
+
+static int
+at86rf230_read_subreg(struct at86rf230_local *lp, u8 addr, u8 mask, int shift, u8* data)
+{
+	int status;
+
+	mutex_lock(&lp->bmux);
+	status = __at86rf230_read_subreg(lp, addr, mask, shift, data);
+	mutex_unlock(&lp->bmux);
+
+	return status;
+}
+
+static int
+at86rf230_write_subreg(struct at86rf230_local *lp, u8 addr, u8 mask, int shift, u8 data)
+{
+	int status;
+	u8 val;
+
+	mutex_lock(&lp->bmux);
+	status = __at86rf230_read_subreg(lp, addr, 0xff, 0, &val);
+	if (status)
+		goto out;
+
+	val &= ~mask;
+	val |= (data << shift) & mask;
+
+	status = __at86rf230_write(lp, addr, val);
+out:
+	mutex_unlock(&lp->bmux);
+
+	return status;
+}
+
+static int
+at86rf230_write_fbuf(struct at86rf230_local *lp, u8 *data, u8 len)
+{
+	u8 *buf = lp->buf;
+	int status;
+	struct spi_message msg;
+	struct spi_transfer xfer_head = {
+		.len		= 2,
+		.tx_buf		= buf,
+
+	};
+	struct spi_transfer xfer_buf = {
+		.len		= len,
+		.tx_buf		= data,
+	};
+
+	mutex_lock(&lp->bmux);
+	buf[0] = CMD_WRITE | CMD_FB;
+	buf[1] = len;
+
+	dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
+	dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer_head, &msg);
+	spi_message_add_tail(&xfer_buf, &msg);
+
+	status = spi_sync(lp->spi, &msg);
+	dev_vdbg(&lp->spi->dev, "status = %d\n", status);
+	if (msg.status)
+		status = msg.status;
+	dev_vdbg(&lp->spi->dev, "status = %d\n", status);
+	dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
+	dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
+
+	mutex_unlock(&lp->bmux);
+	return status;
+}
+
+static int
+at86rf230_read_fbuf(struct at86rf230_local *lp, u8 *data, u8 *len, u8 *lqi)
+{
+	u8 *buf = lp->buf;
+	int status;
+	struct spi_message msg;
+	struct spi_transfer xfer_head = {
+		.len		= 2,
+		.tx_buf		= buf,
+		.rx_buf		= buf,
+
+	};
+	struct spi_transfer xfer_buf = {
+		.len		= *len,
+		.rx_buf		= data,
+	};
+
+	mutex_lock(&lp->bmux);
+	buf[0] = CMD_FB;
+	buf[1] = 0x00;
+
+	dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
+	dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer_head, &msg);
+	spi_message_add_tail(&xfer_buf, &msg);
+
+	status = spi_sync(lp->spi, &msg);
+	dev_vdbg(&lp->spi->dev, "status = %d\n", status);
+	if (msg.status)
+		status = msg.status;
+	dev_vdbg(&lp->spi->dev, "status = %d\n", status);
+	dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
+	dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
+
+	if (!status) {
+		if (lqi && *len > lp->buf[1])
+			*lqi = data[lp->buf[1]];
+
+		*len = lp->buf[1];
+	}
+
+	mutex_unlock(&lp->bmux);
+
+	return status;
+}
+
+static phy_status_t
+at86rf230_ed(struct ieee802154_dev *dev, u8 *level)
+{
+	pr_debug("%s\n", __func__);
+	might_sleep();
+	BUG_ON(!level);
+	*level = 0xbe;
+	return PHY_SUCCESS;
+}
+
+static phy_status_t
+at86rf230_cca(struct ieee802154_dev *dev)
+{
+	pr_debug("%s\n", __func__);
+	might_sleep();
+	return PHY_IDLE;
+}
+
+static phy_status_t
+at86rf230_state(struct ieee802154_dev *dev, phy_status_t state)
+{
+	struct at86rf230_local *lp = dev->priv;
+	int rc;
+	u8 val;
+
+	pr_debug("%s %d\n", __func__/*, priv->cur_state*/, state);
+	might_sleep();
+
+	if (state != PHY_TRX_OFF && state != PHY_RX_ON && state != PHY_TX_ON && state != PHY_FORCE_TRX_OFF)
+		return PHY_INVAL;
+
+	do {
+		rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &val);
+		if (rc)
+			goto err;
+		pr_debug("%s val1 = %x\n", __func__, val);
+	} while (val == STATE_TRANSITION_IN_PROGRESS);
+
+	if (val == state)
+		goto out;
+
+	/* FIXME: handle all non-standard states here!!! */
+
+	/* state is equal to phy states */
+	rc = at86rf230_write_subreg(lp, SR_TRX_CMD, state);
+	if (rc)
+		goto err;
+
+	do {
+		rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &val);
+		if (rc)
+			goto err;
+		pr_debug("%s val2 = %x\n", __func__, val);
+	} while (val == STATE_TRANSITION_IN_PROGRESS);
+
+	if (val == state)
+		val = PHY_SUCCESS;
+
+out:
+	return val;
+
+err:
+	pr_err("%s error: %d\n", __func__, rc);
+	return PHY_ERROR;
+}
+
+static phy_status_t
+at86rf230_channel(struct ieee802154_dev *dev, int channel)
+{
+	struct at86rf230_local *lp = dev->priv;
+	int rc;
+
+	pr_debug("%s %d\n", __func__, channel);
+	might_sleep();
+
+	BUG_ON(channel < 11);
+	BUG_ON(channel > 26);
+
+	rc = at86rf230_write_subreg(lp, SR_CHANNEL, channel);
+	msleep(1); /* Wait for PLL */
+	dev->current_channel = channel;
+
+	return PHY_SUCCESS;
+}
+
+static int
+at86rf230_tx(struct ieee802154_dev *dev, struct sk_buff *skb)
+{
+	char *data;
+	struct at86rf230_local *lp = dev->priv;
+	int rc;
+	unsigned long flags;
+
+	pr_debug("%s\n", __func__);
+
+	might_sleep();
+
+#ifdef AT86RF230_OLDFW_HACK
+	data = skb_push(skb, 2);
+	data[0] = 0x7e;
+	data[1] = 0xff;
+#else
+	data = skb_push(skb, 0); /* FIXME: find a better way */
+#endif
+
+	spin_lock_irqsave(&lp->lock, flags);
+	BUG_ON(lp->is_tx);
+	lp->is_tx = 1;
+	INIT_COMPLETION(lp->tx_complete);
+	spin_unlock_irqrestore(&lp->lock, flags);
+
+	rc = at86rf230_write_fbuf(lp, data, skb->len);
+	if (rc)
+		goto err;
+
+	if (gpio_is_valid(lp->slp_tr)) {
+		gpio_set_value(lp->slp_tr, 1);
+	} else {
+		rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_BUSY_TX);
+		if (rc)
+			goto err;
+	}
+
+	rc = wait_for_completion_interruptible(&lp->tx_complete);
+
+	gpio_set_value(lp->slp_tr, 0);
+
+	if (rc < 0)
+		goto err;
+
+	return PHY_SUCCESS;
+err:
+	spin_lock_irqsave(&lp->lock, flags);
+	lp->is_tx = 0;
+	spin_unlock_irqrestore(&lp->lock, flags);
+
+	return PHY_ERROR;
+}
+
+static int at86rf230_rx(struct at86rf230_local *lp)
+{
+	u8 len = 128;
+	u8 lqi = 0;
+	int rc;
+	struct sk_buff *skb;
+
+	skb = alloc_skb(len, GFP_KERNEL);
+	if (!skb)
+		return -ENOMEM;
+
+	rc = at86rf230_read_fbuf(lp, skb_put(skb, len), &len, &lqi);
+	if (len < 2) {
+		kfree_skb(skb);
+		return -EINVAL;
+	}
+
+	skb_trim(skb, len-2); /* We do not put CRC into the frame */
+
+	if (len < 2) {
+		kfree_skb(skb);
+		return -EINVAL;
+	}
+
+#ifdef AT86RF230_OLDFW_HACK
+	skb_pull(skb, 2);
+#endif
+	ieee802154_rx_irqsafe(lp->dev, skb, lqi);
+
+	dev_dbg(&lp->spi->dev, "READ_FBUF: %d %d %x\n", rc, len, lqi);
+
+	return 0;
+}
+
+static struct ieee802154_ops at86rf230_ops = {
+	.owner = THIS_MODULE,
+	.tx = at86rf230_tx,
+	.ed = at86rf230_ed,
+	.cca = at86rf230_cca,
+	.set_trx_state = at86rf230_state,
+	.set_channel = at86rf230_channel,
+};
+
+static int at86rf230_register(struct at86rf230_local *lp)
+{
+	int rc = -ENOMEM;
+
+	lp->dev = ieee802154_alloc_device();
+	if (!lp->dev)
+		goto err_alloc;
+
+	lp->dev->name = dev_name(&lp->spi->dev);
+	lp->dev->priv = lp;
+	lp->dev->parent = &lp->spi->dev;
+#ifdef AT86RF230_OLDFW_HACK
+	lp->dev->extra_tx_headroom = 2;
+#else
+	lp->dev->extra_tx_headroom = 0;
+#endif
+	lp->dev->channel_mask = 0x7ff; /* We do support only 2.4 Ghz */
+	lp->dev->flags = IEEE802154_FLAGS_OMIT_CKSUM;
+
+	rc = ieee802154_register_device(lp->dev, &at86rf230_ops);
+	if (rc)
+		goto err_register;
+
+	/* FIXME: remove this after we have proper support for slave instantiation from iz tool */
+	rtnl_lock();
+	rc = ieee802154_add_slave(lp->dev, "\xde\xad\xbe\xaf\xca\xfe\xba\xbe");
+	rtnl_unlock();
+	if (rc < 0)
+		goto err_slave;
+
+	return 0;
+
+err_slave:
+	ieee802154_unregister_device(lp->dev);
+err_register:
+	ieee802154_free_device(lp->dev);
+err_alloc:
+	return rc;
+}
+
+static void at86rf230_unregister(struct at86rf230_local *lp)
+{
+	ieee802154_unregister_device(lp->dev);
+	ieee802154_free_device(lp->dev);
+}
+
+static void at86rf230_irqwork(struct work_struct *work)
+{
+	struct at86rf230_local *lp = container_of(work, struct at86rf230_local, irqwork);
+	u8 status = 0, val;
+	int rc;
+	unsigned long flags;
+
+	dev_dbg(&lp->spi->dev, "IRQ Worker\n");
+
+	do {
+		rc = at86rf230_read_subreg(lp, RG_IRQ_STATUS, 0xff, 0, &val);
+		status |= val;
+		dev_dbg(&lp->spi->dev, "IRQ Status: %02x\n", status);
+
+		status &= ~IRQ_PLL_LOCK; /* ignore */
+		status &= ~IRQ_RX_START; /* ignore */
+		status &= ~IRQ_AMI; /* ignore */
+		status &= ~IRQ_TRX_UR; /* FIXME: possibly handle ???*/
+
+		if (status & IRQ_TRX_END) {
+			status &= ~IRQ_TRX_END;
+			spin_lock_irqsave(&lp->lock, flags);
+			if (lp->is_tx) {
+				lp->is_tx = 0;
+				spin_unlock_irqrestore(&lp->lock, flags);
+				complete(&lp->tx_complete);
+			} else {
+				spin_unlock_irqrestore(&lp->lock, flags);
+				at86rf230_rx(lp);
+			}
+		}
+
+	} while (status != 0);
+
+	spin_lock_irqsave(&lp->lock, flags);
+	if (lp->irq_disabled) {
+		lp->irq_disabled = 0;
+		enable_irq(lp->spi->irq);
+	}
+	spin_unlock_irqrestore(&lp->lock, flags);
+}
+
+static irqreturn_t at86rf230_isr(int irq, void *data)
+{
+	struct at86rf230_local *lp = data;
+
+	dev_dbg(&lp->spi->dev, "IRQ!\n");
+
+	spin_lock(&lp->lock);
+	if (!lp->irq_disabled) {
+		disable_irq_nosync(irq);
+		lp->irq_disabled = 1;
+	}
+	spin_unlock(&lp->lock);
+
+	schedule_work(&lp->irqwork);
+
+	return IRQ_HANDLED;
+}
+
+
+static int at86rf230_hw_init(struct at86rf230_local *lp)
+{
+	u8 status;
+	int rc;
+
+	rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status);
+	if (rc)
+		return rc;
+
+	dev_info(&lp->spi->dev, "Status: %02x\n", status);
+	if (status == STATE_P_ON) {
+		rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_TRX_OFF);
+		if (rc)
+			return rc;
+		msleep(1);
+		rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status);
+		if (rc)
+			return rc;
+		dev_info(&lp->spi->dev, "Status: %02x\n", status);
+	}
+
+	rc = at86rf230_write_subreg(lp, SR_IRQ_MASK,
+			/*IRQ_TRX_UR | IRQ_CCA_ED | IRQ_TRX_END | IRQ_PLL_UNL | IRQ_PLL_LOCK*/ 0xff);
+	if (rc)
+		return rc;
+
+	rc = at86rf230_write_subreg(lp, SR_CLKM_SHA_SEL, 0x00); /* CLKM changes are applied immediately */
+	if (rc)
+		return rc;
+
+	rc = at86rf230_write_subreg(lp, SR_CLKM_CTRL, 0x00); /* Turn CLKM Off */
+	if (rc)
+		return rc;
+
+	msleep(100);
+
+	rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_TX_ON);
+	if (rc)
+		return rc;
+	msleep(1);
+
+	rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status);
+	if (rc)
+		return rc;
+	dev_info(&lp->spi->dev, "Status: %02x\n", status);
+
+	rc = at86rf230_read_subreg(lp, SR_DVDD_OK, &status);
+	if (rc)
+		return rc;
+	if (!status) {
+		dev_err(&lp->spi->dev, "DVDD error\n");
+		return -EINVAL;
+	}
+
+	rc = at86rf230_read_subreg(lp, SR_AVDD_OK, &status);
+	if (rc)
+		return rc;
+	if (!status) {
+		dev_err(&lp->spi->dev, "AVDD error\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int at86rf230_suspend(struct spi_device *spi, pm_message_t message)
+{
+	return 0;
+}
+
+static int at86rf230_resume(struct spi_device *spi)
+{
+	return 0;
+}
+
+static int __devinit at86rf230_probe(struct spi_device *spi)
+{
+	struct at86rf230_local *lp = kzalloc(sizeof *lp, GFP_KERNEL);
+	u8 man_id_0, man_id_1;
+	int rc;
+	const char *chip;
+	int supported = 0;
+	struct at86rf230_platform_data *pdata = spi->dev.platform_data;
+
+	if (!lp)
+		return -ENOMEM;
+
+	if (!pdata) {
+		dev_err(&spi->dev, "no platform_data\n");
+		rc = -EINVAL;
+		goto err;
+	}
+
+	if (!spi->irq) {
+		dev_err(&spi->dev, "no IRQ specified\n");
+		rc = -EINVAL;
+		goto err;
+	}
+
+	lp->spi = spi;
+
+	lp->rstn = pdata->rstn;
+	lp->slp_tr = pdata->slp_tr;
+	lp->dig2 = pdata->dig2;
+
+	mutex_init(&lp->bmux);
+	INIT_WORK(&lp->irqwork, at86rf230_irqwork);
+	spin_lock_init(&lp->lock);
+	init_completion(&lp->tx_complete);
+
+	spi_set_drvdata(spi, lp);
+
+	rc = gpio_request(lp->rstn, "rstn");
+	if (rc)
+		goto err_rstn;
+
+	if (gpio_is_valid(lp->slp_tr)) {
+		rc = gpio_request(lp->slp_tr, "slp_tr");
+		if (rc)
+			goto err_slp_tr;
+	}
+
+	rc = gpio_direction_output(lp->rstn, 1);
+	if (rc)
+		goto err_gpio_dir;
+
+	if (gpio_is_valid(lp->slp_tr)) {
+		rc = gpio_direction_output(lp->slp_tr, 0);
+		if (rc)
+			goto err_gpio_dir;
+	}
+
+	/* Reset */
+	msleep(1);
+	gpio_set_value(lp->rstn, 0);
+	msleep(1);
+	gpio_set_value(lp->rstn, 1);
+	msleep(1);
+
+	rc = at86rf230_read_subreg(lp, SR_MAN_ID_0, &man_id_0);
+	if (rc)
+		goto err_gpio_dir;
+	rc = at86rf230_read_subreg(lp, SR_MAN_ID_1, &man_id_1);
+	if (rc)
+		goto err_gpio_dir;
+
+	if (man_id_1 != 0x00 || man_id_0 != 0x1f) {
+		dev_err(&spi->dev, "Non-Atmel device found (MAN_ID %02x %02x)\n", man_id_1, man_id_0);
+		rc = -EINVAL;
+		goto err_gpio_dir;
+	}
+
+	rc = at86rf230_read_subreg(lp, SR_PART_NUM, &lp->part);
+	if (rc)
+		goto err_gpio_dir;
+
+	rc = at86rf230_read_subreg(lp, SR_VERSION_NUM, &lp->vers);
+	if (rc)
+		goto err_gpio_dir;
+
+	switch (lp->part) {
+	case 2:
+		chip = "at86rf230";
+		/* supported = 1;  FIXME: should be easy to support; */
+		break;
+	case 3:
+		chip = "at86rf231";
+		supported = 1;
+		break;
+	default:
+		chip = "UNKNOWN";
+		break;
+	}
+
+	dev_info(&spi->dev, "Detected %s chip version %d\n", chip, lp->vers);
+	if (!supported) {
+		rc = -ENOTSUPP;
+		goto err_gpio_dir;
+	}
+
+	rc = at86rf230_hw_init(lp);
+	if (rc)
+		goto err_gpio_dir;
+
+	rc = request_irq(spi->irq, at86rf230_isr, IRQF_SHARED, dev_name(&spi->dev), lp);
+	if (rc)
+		goto err_gpio_dir;
+
+	dev_dbg(&spi->dev, "registered at86rf230\n");
+
+	rc = at86rf230_register(lp);
+	if (rc)
+		goto err_irq;
+
+	return rc;
+
+	at86rf230_unregister(lp);
+err_irq:
+	free_irq(spi->irq, lp);
+	flush_work(&lp->irqwork);
+err_gpio_dir:
+	if (gpio_is_valid(lp->slp_tr))
+		gpio_free(lp->slp_tr);
+err_slp_tr:
+	gpio_free(lp->rstn);
+err_rstn:
+err:
+	spi_set_drvdata(spi, NULL);
+	mutex_destroy(&lp->bmux);
+	kfree(lp);
+	return rc;
+}
+
+static int __devexit at86rf230_remove(struct spi_device *spi)
+{
+	struct at86rf230_local *lp = spi_get_drvdata(spi);
+
+	at86rf230_unregister(lp);
+
+	free_irq(spi->irq, lp);
+	flush_work(&lp->irqwork);
+
+	if (gpio_is_valid(lp->slp_tr))
+		gpio_free(lp->slp_tr);
+	gpio_free(lp->rstn);
+
+	spi_set_drvdata(spi, NULL);
+	mutex_destroy(&lp->bmux);
+	kfree(lp);
+
+	dev_dbg(&spi->dev, "unregistered at86rf230\n");
+	return 0;
+}
+
+static struct spi_driver at86rf230_driver = {
+	.driver = {
+		.name	= "at86rf230",
+		.owner	= THIS_MODULE,
+	},
+	.probe      = at86rf230_probe,
+	.remove     = __devexit_p(at86rf230_remove),
+	.suspend    = at86rf230_suspend,
+	.resume     = at86rf230_resume,
+};
+
+static int __init at86rf230_init(void)
+{
+	return spi_register_driver(&at86rf230_driver);
+}
+module_init(at86rf230_init);
+
+static void __exit at86rf230_exit(void)
+{
+	spi_unregister_driver(&at86rf230_driver);
+}
+module_exit(at86rf230_exit);
+
+MODULE_DESCRIPTION("AT86RF230 Transceiver Driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/include/linux/spi/at86rf230.h b/include/linux/spi/at86rf230.h
new file mode 100644
index 0000000..aa8e250
--- /dev/null
+++ b/include/linux/spi/at86rf230.h
@@ -0,0 +1,32 @@
+/*
+ * AT86RF230/RF231 driver
+ *
+ * Copyright (C) 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 <dmitry.baryshkov@siemens.com>
+ */
+#ifndef AT86RF230_H
+#define AT86RF230_H
+
+struct at86rf230_platform_data {
+	int rstn;
+	int slp_tr;
+	int dig2;
+};
+
+#endif
+
-- 
1.6.2.4


^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [PATCH 10/10] ieee802154: add at86rf230/rf231 spi driver
@ 2009-06-01 14:54                     ` Dmitry Eremin-Solenikov
  0 siblings, 0 replies; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-01 14:54 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	slapin-9cOl001CZnBAfugRpC6u6w,
	maxim.osipov-kv7WeFo6aLtBDgjK7y7TUQ,
	dmitry.baryshkov-kv7WeFo6aLtBDgjK7y7TUQ,
	oliver.fendt-kv7WeFo6aLtBDgjK7y7TUQ, Dmitry Eremin-Solenikov

Add a driver handling AT86RF230/RF231 line of chips. Only basic
features are currently implemented (no extended mode operation, etc.)
Also the RF230 chip is not really supported yet.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Sergey Lapin <slapin-9cOl001CZnBAfugRpC6u6w@public.gmane.org>
---
 drivers/ieee802154/Kconfig     |    5 +
 drivers/ieee802154/Makefile    |    1 +
 drivers/ieee802154/at86rf230.c |  971 ++++++++++++++++++++++++++++++++++++++++
 include/linux/spi/at86rf230.h  |   32 ++
 4 files changed, 1009 insertions(+), 0 deletions(-)
 create mode 100644 drivers/ieee802154/at86rf230.c
 create mode 100644 include/linux/spi/at86rf230.h

diff --git a/drivers/ieee802154/Kconfig b/drivers/ieee802154/Kconfig
index 0e65572..eff0423 100644
--- a/drivers/ieee802154/Kconfig
+++ b/drivers/ieee802154/Kconfig
@@ -33,5 +33,10 @@ config IEEE802154_FAKELB
 config IEEE802154_SERIAL
 	tristate "Simple LR-WPAN UART driver"
 
+config IEEE802154_AT86RF230
+	tristate "AT86RF230 transceiver driver"
+	depends on SPI
+
+
 endif
 
diff --git a/drivers/ieee802154/Makefile b/drivers/ieee802154/Makefile
index ca41e99..76237f3 100644
--- a/drivers/ieee802154/Makefile
+++ b/drivers/ieee802154/Makefile
@@ -1,5 +1,6 @@
 obj-$(CONFIG_IEEE802154_FAKEHARD) += fakehard.o
 obj-$(CONFIG_IEEE802154_FAKELB) += fakelb.o
 obj-$(CONFIG_IEEE802154_SERIAL) += serial.o
+obj-$(CONFIG_IEEE802154_AT86RF230) += at86rf230.o
 
 EXTRA_CFLAGS += -DDEBUG -DCONFIG_FFD
diff --git a/drivers/ieee802154/at86rf230.c b/drivers/ieee802154/at86rf230.c
new file mode 100644
index 0000000..a4ead47
--- /dev/null
+++ b/drivers/ieee802154/at86rf230.c
@@ -0,0 +1,971 @@
+#undef AT86RF230_OLDFW_HACK
+/*
+ * AT86RF230/RF231 driver
+ *
+ * Copyright (C) 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 <dmitry.baryshkov-kv7WeFo6aLtBDgjK7y7TUQ@public.gmane.org>
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/spinlock.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/at86rf230.h>
+#include <linux/rtnetlink.h> /* FIXME: hack for slave instantiation */
+
+#include <net/ieee802154/mac802154.h>
+
+struct at86rf230_local {
+	struct spi_device *spi;
+	int rstn, slp_tr, dig2;
+
+	u8 part;
+	u8 vers;
+
+	u8 buf[2];
+	struct mutex bmux;
+
+	struct work_struct irqwork;
+	struct completion tx_complete;
+
+	struct ieee802154_dev *dev;
+
+	spinlock_t lock;
+	unsigned irq_disabled:1; /* P: lock */
+	unsigned is_tx:1; /* P: lock */
+};
+
+#define	RG_TRX_STATUS	(0x01)
+#define	SR_TRX_STATUS		0x01, 0x1f, 0
+#define	SR_RESERVED_01_3	0x01, 0x20, 5
+#define	SR_CCA_STATUS		0x01, 0x40, 6
+#define	SR_CCA_DONE		0x01, 0x80, 7
+#define	RG_TRX_STATE	(0x02)
+#define	SR_TRX_CMD		0x02, 0x1f, 0
+#define	SR_TRAC_STATUS		0x02, 0xe0, 5
+#define	RG_TRX_CTRL_0	(0x03)
+#define	SR_CLKM_CTRL		0x03, 0x07, 0
+#define	SR_CLKM_SHA_SEL		0x03, 0x08, 3
+#define	SR_PAD_IO_CLKM		0x03, 0x30, 4
+#define	SR_PAD_IO		0x03, 0xc0, 6
+#define	RG_TRX_CTRL_1	(0x04)
+#define	SR_IRQ_POLARITY		0x04, 0x01, 0
+#define	SR_IRQ_MASK_MODE	0x04, 0x02, 1
+#define	SR_SPI_CMD_MODE		0x04, 0x0c, 2
+#define	SR_RX_BL_CTRL		0x04, 0x10, 4
+#define	SR_TX_AUTO_CRC_ON	0x04, 0x20, 5
+#define	SR_IRQ_2_EXT_EN		0x04, 0x40, 6
+#define	SR_PA_EXT_EN		0x04, 0x80, 7
+#define	RG_PHY_TX_PWR	(0x05)
+#define	SR_TX_PWR		0x05, 0x0f, 0
+#define	SR_PA_LT		0x05, 0x30, 4
+#define	SR_PA_BUF_LT		0x05, 0xc0, 6
+#define	RG_PHY_RSSI	(0x06)
+#define	SR_RSSI			0x06, 0x1f, 0
+#define	SR_RND_VALUE		0x06, 0x60, 5
+#define	SR_RX_CRC_VALID		0x06, 0x80, 7
+#define	RG_PHY_ED_LEVEL	(0x07)
+#define	SR_ED_LEVEL		0x07, 0xff, 0
+#define	RG_PHY_CC_CCA	(0x08)
+#define	SR_CHANNEL		0x08, 0x1f, 0
+#define	SR_CCA_MODE		0x08, 0x60, 5
+#define	SR_CCA_REQUEST		0x08, 0x80, 7
+#define	RG_CCA_THRES	(0x09)
+#define	SR_CCA_ED_THRES		0x09, 0x0f, 0
+#define	SR_RESERVED_09_1	0x09, 0xf0, 4
+#define	RG_RX_CTRL	(0x0a)
+#define	SR_PDT_THRES		0x0a, 0x0f, 0
+#define	SR_RESERVED_0a_1	0x0a, 0xf0, 4
+#define	RG_SFD_VALUE	(0x0b)
+#define	SR_SFD_VALUE		0x0b, 0xff, 0
+#define	RG_TRX_CTRL_2	(0x0c)
+#define	SR_OQPSK_DATA_RATE	0x0c, 0x03, 0
+#define	SR_RESERVED_0c_2	0x0c, 0x7c, 2
+#define	SR_RX_SAFE_MODE		0x0c, 0x80, 7
+#define	RG_ANT_DIV	(0x0d)
+#define	SR_ANT_CTRL		0x0d, 0x03, 0
+#define	SR_ANT_EXT_SW_EN	0x0d, 0x04, 2
+#define	SR_ANT_DIV_EN		0x0d, 0x08, 3
+#define	SR_RESERVED_0d_2	0x0d, 0x70, 4
+#define	SR_ANT_SEL		0x0d, 0x80, 7
+#define	RG_IRQ_MASK	(0x0e)
+#define	SR_IRQ_MASK		0x0e, 0xff, 0
+#define	RG_IRQ_STATUS	(0x0f)
+#define	SR_IRQ_0_PLL_LOCK	0x0f, 0x01, 0
+#define	SR_IRQ_1_PLL_UNLOCK	0x0f, 0x02, 1
+#define	SR_IRQ_2_RX_START	0x0f, 0x04, 2
+#define	SR_IRQ_3_TRX_END	0x0f, 0x08, 3
+#define	SR_IRQ_4_CCA_ED_DONE	0x0f, 0x10, 4
+#define	SR_IRQ_5_AMI		0x0f, 0x20, 5
+#define	SR_IRQ_6_TRX_UR		0x0f, 0x40, 6
+#define	SR_IRQ_7_BAT_LOW	0x0f, 0x80, 7
+#define	RG_VREG_CTRL	(0x10)
+#define	SR_RESERVED_10_6	0x10, 0x03, 0
+#define	SR_DVDD_OK		0x10, 0x04, 2
+#define	SR_DVREG_EXT		0x10, 0x08, 3
+#define	SR_RESERVED_10_3	0x10, 0x30, 4
+#define	SR_AVDD_OK		0x10, 0x40, 6
+#define	SR_AVREG_EXT		0x10, 0x80, 7
+#define	RG_BATMON	(0x11)
+#define	SR_BATMON_VTH		0x11, 0x0f, 0
+#define	SR_BATMON_HR		0x11, 0x10, 4
+#define	SR_BATMON_OK		0x11, 0x20, 5
+#define	SR_RESERVED_11_1	0x11, 0xc0, 6
+#define	RG_XOSC_CTRL	(0x12)
+#define	SR_XTAL_TRIM		0x12, 0x0f, 0
+#define	SR_XTAL_MODE		0x12, 0xf0, 4
+#define	RG_RX_SYN	(0x15)
+#define	SR_RX_PDT_LEVEL		0x15, 0x0f, 0
+#define	SR_RESERVED_15_2	0x15, 0x70, 4
+#define	SR_RX_PDT_DIS		0x15, 0x80, 7
+#define	RG_XAH_CTRL_1	(0x17)
+#define	SR_RESERVED_17_8	0x17, 0x01, 0
+#define	SR_AACK_PROM_MODE	0x17, 0x02, 1
+#define	SR_AACK_ACK_TIME	0x17, 0x04, 2
+#define	SR_RESERVED_17_5	0x17, 0x08, 3
+#define	SR_AACK_UPLD_RES_FT	0x17, 0x10, 4
+#define	SR_AACK_FLTR_RES_FT	0x17, 0x20, 5
+#define	SR_RESERVED_17_2	0x17, 0x40, 6
+#define	SR_RESERVED_17_1	0x17, 0x80, 7
+#define	RG_FTN_CTRL	(0x18)
+#define	SR_RESERVED_18_2	0x18, 0x7f, 0
+#define	SR_FTN_START		0x18, 0x80, 7
+#define	RG_PLL_CF	(0x1a)
+#define	SR_RESERVED_1a_2	0x1a, 0x7f, 0
+#define	SR_PLL_CF_START		0x1a, 0x80, 7
+#define	RG_PLL_DCU	(0x1b)
+#define	SR_RESERVED_1b_3	0x1b, 0x3f, 0
+#define	SR_RESERVED_1b_2	0x1b, 0x40, 6
+#define	SR_PLL_DCU_START	0x1b, 0x80, 7
+#define	RG_PART_NUM	(0x1c)
+#define	SR_PART_NUM		0x1c, 0xff, 0
+#define	RG_VERSION_NUM	(0x1d)
+#define	SR_VERSION_NUM		0x1d, 0xff, 0
+#define	RG_MAN_ID_0	(0x1e)
+#define	SR_MAN_ID_0		0x1e, 0xff, 0
+#define	RG_MAN_ID_1	(0x1f)
+#define	SR_MAN_ID_1		0x1f, 0xff, 0
+#define	RG_SHORT_ADDR_0	(0x20)
+#define	SR_SHORT_ADDR_0		0x20, 0xff, 0
+#define	RG_SHORT_ADDR_1	(0x21)
+#define	SR_SHORT_ADDR_1		0x21, 0xff, 0
+#define	RG_PAN_ID_0	(0x22)
+#define	SR_PAN_ID_0		0x22, 0xff, 0
+#define	RG_PAN_ID_1	(0x23)
+#define	SR_PAN_ID_1		0x23, 0xff, 0
+#define	RG_IEEE_ADDR_0	(0x24)
+#define	SR_IEEE_ADDR_0		0x24, 0xff, 0
+#define	RG_IEEE_ADDR_1	(0x25)
+#define	SR_IEEE_ADDR_1		0x25, 0xff, 0
+#define	RG_IEEE_ADDR_2	(0x26)
+#define	SR_IEEE_ADDR_2		0x26, 0xff, 0
+#define	RG_IEEE_ADDR_3	(0x27)
+#define	SR_IEEE_ADDR_3		0x27, 0xff, 0
+#define	RG_IEEE_ADDR_4	(0x28)
+#define	SR_IEEE_ADDR_4		0x28, 0xff, 0
+#define	RG_IEEE_ADDR_5	(0x29)
+#define	SR_IEEE_ADDR_5		0x29, 0xff, 0
+#define	RG_IEEE_ADDR_6	(0x2a)
+#define	SR_IEEE_ADDR_6		0x2a, 0xff, 0
+#define	RG_IEEE_ADDR_7	(0x2b)
+#define	SR_IEEE_ADDR_7		0x2b, 0xff, 0
+#define	RG_XAH_CTRL_0	(0x2c)
+#define	SR_SLOTTED_OPERATION	0x2c, 0x01, 0
+#define	SR_MAX_CSMA_RETRIES	0x2c, 0x0e, 1
+#define	SR_MAX_FRAME_RETRIES	0x2c, 0xf0, 4
+#define	RG_CSMA_SEED_0	(0x2d)
+#define	SR_CSMA_SEED_0		0x2d, 0xff, 0
+#define	RG_CSMA_SEED_1	(0x2e)
+#define	SR_CSMA_SEED_1		0x2e, 0x07, 0
+#define	SR_AACK_I_AM_COORD	0x2e, 0x08, 3
+#define	SR_AACK_DIS_ACK		0x2e, 0x10, 4
+#define	SR_AACK_SET_PD		0x2e, 0x20, 5
+#define	SR_AACK_FVN_MODE	0x2e, 0xc0, 6
+#define	RG_CSMA_BE	(0x2f)
+#define	SR_MIN_BE		0x2f, 0x0f, 0
+#define	SR_MAX_BE		0x2f, 0xf0, 4
+
+#define CMD_REG		0x80
+#define CMD_REG_MASK	0x3f
+#define CMD_WRITE	0x40
+#define CMD_FB		0x20
+
+#define IRQ_BAT_LOW	(1 << 7)
+#define IRQ_TRX_UR	(1 << 6)
+#define IRQ_AMI		(1 << 5)
+#define IRQ_CCA_ED	(1 << 4)
+#define IRQ_TRX_END	(1 << 3)
+#define IRQ_RX_START	(1 << 2)
+#define IRQ_PLL_UNL	(1 << 1)
+#define IRQ_PLL_LOCK	(1 << 0)
+
+#define STATE_P_ON		0x00	/* BUSY */
+#define STATE_BUSY_RX		0x01
+#define STATE_BUSY_TX		0x02
+#define STATE_FORCE_TRX_OFF	0x03
+#define STATE_FORCE_TX_ON	0x04	/* IDLE */
+/* 0x05 */				/* INVALID_PARAMETER */
+#define STATE_RX_ON		0x06
+/* 0x07 */				/* SUCCESS */
+#define STATE_TRX_OFF		0x08
+#define STATE_TX_ON		0x09
+/* 0x0a - 0x0e */			/* 0x0a - UNSUPPORTED_ATTRIBUTE */
+#define STATE_SLEEP		0x0F
+#define STATE_BUSY_RX_AACK	0x11
+#define STATE_BUSY_TX_ARET	0x12
+#define STATE_BUSY_RX_AACK_ON	0x16
+#define STATE_BUSY_TX_ARET_ON	0x19
+#define STATE_RX_ON_NOCLK	0x1C
+#define STATE_RX_AACK_ON_NOCLK	0x1D
+#define STATE_BUSY_RX_AACK_NOCLK 0x1E
+#define STATE_TRANSITION_IN_PROGRESS 0x1F
+
+static int
+__at86rf230_write(struct at86rf230_local *lp, u8 addr, u8 data)
+{
+	u8 *buf = lp->buf;
+	int status;
+	struct spi_message msg;
+	struct spi_transfer xfer = {
+		.len		= 2,
+		.tx_buf		= buf,
+	};
+
+	buf[0] = (addr & CMD_REG_MASK) | CMD_REG | CMD_WRITE;
+	buf[1] = data;
+	dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
+	dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+
+	status = spi_sync(lp->spi, &msg);
+	dev_vdbg(&lp->spi->dev, "status = %d\n", status);
+	if (msg.status)
+		status = msg.status;
+	dev_vdbg(&lp->spi->dev, "status = %d\n", status);
+	dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
+	dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
+
+	return status;
+}
+
+static int
+__at86rf230_read_subreg(struct at86rf230_local *lp, u8 addr, u8 mask, int shift, u8* data)
+{
+	u8 *buf = lp->buf;
+	int status;
+	struct spi_message msg;
+	struct spi_transfer xfer = {
+		.len		= 2,
+		.tx_buf		= buf,
+		.rx_buf		= buf,
+	};
+
+	buf[0] = (addr & CMD_REG_MASK) | CMD_REG;
+	buf[1] = 0xff;
+	dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+
+	status = spi_sync(lp->spi, &msg);
+	dev_vdbg(&lp->spi->dev, "status = %d\n", status);
+	if (msg.status)
+		status = msg.status;
+	dev_vdbg(&lp->spi->dev, "status = %d\n", status);
+	dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
+	dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
+
+	if (status == 0)
+		*data = buf[1];
+
+	return status;
+}
+
+static int
+at86rf230_read_subreg(struct at86rf230_local *lp, u8 addr, u8 mask, int shift, u8* data)
+{
+	int status;
+
+	mutex_lock(&lp->bmux);
+	status = __at86rf230_read_subreg(lp, addr, mask, shift, data);
+	mutex_unlock(&lp->bmux);
+
+	return status;
+}
+
+static int
+at86rf230_write_subreg(struct at86rf230_local *lp, u8 addr, u8 mask, int shift, u8 data)
+{
+	int status;
+	u8 val;
+
+	mutex_lock(&lp->bmux);
+	status = __at86rf230_read_subreg(lp, addr, 0xff, 0, &val);
+	if (status)
+		goto out;
+
+	val &= ~mask;
+	val |= (data << shift) & mask;
+
+	status = __at86rf230_write(lp, addr, val);
+out:
+	mutex_unlock(&lp->bmux);
+
+	return status;
+}
+
+static int
+at86rf230_write_fbuf(struct at86rf230_local *lp, u8 *data, u8 len)
+{
+	u8 *buf = lp->buf;
+	int status;
+	struct spi_message msg;
+	struct spi_transfer xfer_head = {
+		.len		= 2,
+		.tx_buf		= buf,
+
+	};
+	struct spi_transfer xfer_buf = {
+		.len		= len,
+		.tx_buf		= data,
+	};
+
+	mutex_lock(&lp->bmux);
+	buf[0] = CMD_WRITE | CMD_FB;
+	buf[1] = len;
+
+	dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
+	dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer_head, &msg);
+	spi_message_add_tail(&xfer_buf, &msg);
+
+	status = spi_sync(lp->spi, &msg);
+	dev_vdbg(&lp->spi->dev, "status = %d\n", status);
+	if (msg.status)
+		status = msg.status;
+	dev_vdbg(&lp->spi->dev, "status = %d\n", status);
+	dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
+	dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
+
+	mutex_unlock(&lp->bmux);
+	return status;
+}
+
+static int
+at86rf230_read_fbuf(struct at86rf230_local *lp, u8 *data, u8 *len, u8 *lqi)
+{
+	u8 *buf = lp->buf;
+	int status;
+	struct spi_message msg;
+	struct spi_transfer xfer_head = {
+		.len		= 2,
+		.tx_buf		= buf,
+		.rx_buf		= buf,
+
+	};
+	struct spi_transfer xfer_buf = {
+		.len		= *len,
+		.rx_buf		= data,
+	};
+
+	mutex_lock(&lp->bmux);
+	buf[0] = CMD_FB;
+	buf[1] = 0x00;
+
+	dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
+	dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer_head, &msg);
+	spi_message_add_tail(&xfer_buf, &msg);
+
+	status = spi_sync(lp->spi, &msg);
+	dev_vdbg(&lp->spi->dev, "status = %d\n", status);
+	if (msg.status)
+		status = msg.status;
+	dev_vdbg(&lp->spi->dev, "status = %d\n", status);
+	dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
+	dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
+
+	if (!status) {
+		if (lqi && *len > lp->buf[1])
+			*lqi = data[lp->buf[1]];
+
+		*len = lp->buf[1];
+	}
+
+	mutex_unlock(&lp->bmux);
+
+	return status;
+}
+
+static phy_status_t
+at86rf230_ed(struct ieee802154_dev *dev, u8 *level)
+{
+	pr_debug("%s\n", __func__);
+	might_sleep();
+	BUG_ON(!level);
+	*level = 0xbe;
+	return PHY_SUCCESS;
+}
+
+static phy_status_t
+at86rf230_cca(struct ieee802154_dev *dev)
+{
+	pr_debug("%s\n", __func__);
+	might_sleep();
+	return PHY_IDLE;
+}
+
+static phy_status_t
+at86rf230_state(struct ieee802154_dev *dev, phy_status_t state)
+{
+	struct at86rf230_local *lp = dev->priv;
+	int rc;
+	u8 val;
+
+	pr_debug("%s %d\n", __func__/*, priv->cur_state*/, state);
+	might_sleep();
+
+	if (state != PHY_TRX_OFF && state != PHY_RX_ON && state != PHY_TX_ON && state != PHY_FORCE_TRX_OFF)
+		return PHY_INVAL;
+
+	do {
+		rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &val);
+		if (rc)
+			goto err;
+		pr_debug("%s val1 = %x\n", __func__, val);
+	} while (val == STATE_TRANSITION_IN_PROGRESS);
+
+	if (val == state)
+		goto out;
+
+	/* FIXME: handle all non-standard states here!!! */
+
+	/* state is equal to phy states */
+	rc = at86rf230_write_subreg(lp, SR_TRX_CMD, state);
+	if (rc)
+		goto err;
+
+	do {
+		rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &val);
+		if (rc)
+			goto err;
+		pr_debug("%s val2 = %x\n", __func__, val);
+	} while (val == STATE_TRANSITION_IN_PROGRESS);
+
+	if (val == state)
+		val = PHY_SUCCESS;
+
+out:
+	return val;
+
+err:
+	pr_err("%s error: %d\n", __func__, rc);
+	return PHY_ERROR;
+}
+
+static phy_status_t
+at86rf230_channel(struct ieee802154_dev *dev, int channel)
+{
+	struct at86rf230_local *lp = dev->priv;
+	int rc;
+
+	pr_debug("%s %d\n", __func__, channel);
+	might_sleep();
+
+	BUG_ON(channel < 11);
+	BUG_ON(channel > 26);
+
+	rc = at86rf230_write_subreg(lp, SR_CHANNEL, channel);
+	msleep(1); /* Wait for PLL */
+	dev->current_channel = channel;
+
+	return PHY_SUCCESS;
+}
+
+static int
+at86rf230_tx(struct ieee802154_dev *dev, struct sk_buff *skb)
+{
+	char *data;
+	struct at86rf230_local *lp = dev->priv;
+	int rc;
+	unsigned long flags;
+
+	pr_debug("%s\n", __func__);
+
+	might_sleep();
+
+#ifdef AT86RF230_OLDFW_HACK
+	data = skb_push(skb, 2);
+	data[0] = 0x7e;
+	data[1] = 0xff;
+#else
+	data = skb_push(skb, 0); /* FIXME: find a better way */
+#endif
+
+	spin_lock_irqsave(&lp->lock, flags);
+	BUG_ON(lp->is_tx);
+	lp->is_tx = 1;
+	INIT_COMPLETION(lp->tx_complete);
+	spin_unlock_irqrestore(&lp->lock, flags);
+
+	rc = at86rf230_write_fbuf(lp, data, skb->len);
+	if (rc)
+		goto err;
+
+	if (gpio_is_valid(lp->slp_tr)) {
+		gpio_set_value(lp->slp_tr, 1);
+	} else {
+		rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_BUSY_TX);
+		if (rc)
+			goto err;
+	}
+
+	rc = wait_for_completion_interruptible(&lp->tx_complete);
+
+	gpio_set_value(lp->slp_tr, 0);
+
+	if (rc < 0)
+		goto err;
+
+	return PHY_SUCCESS;
+err:
+	spin_lock_irqsave(&lp->lock, flags);
+	lp->is_tx = 0;
+	spin_unlock_irqrestore(&lp->lock, flags);
+
+	return PHY_ERROR;
+}
+
+static int at86rf230_rx(struct at86rf230_local *lp)
+{
+	u8 len = 128;
+	u8 lqi = 0;
+	int rc;
+	struct sk_buff *skb;
+
+	skb = alloc_skb(len, GFP_KERNEL);
+	if (!skb)
+		return -ENOMEM;
+
+	rc = at86rf230_read_fbuf(lp, skb_put(skb, len), &len, &lqi);
+	if (len < 2) {
+		kfree_skb(skb);
+		return -EINVAL;
+	}
+
+	skb_trim(skb, len-2); /* We do not put CRC into the frame */
+
+	if (len < 2) {
+		kfree_skb(skb);
+		return -EINVAL;
+	}
+
+#ifdef AT86RF230_OLDFW_HACK
+	skb_pull(skb, 2);
+#endif
+	ieee802154_rx_irqsafe(lp->dev, skb, lqi);
+
+	dev_dbg(&lp->spi->dev, "READ_FBUF: %d %d %x\n", rc, len, lqi);
+
+	return 0;
+}
+
+static struct ieee802154_ops at86rf230_ops = {
+	.owner = THIS_MODULE,
+	.tx = at86rf230_tx,
+	.ed = at86rf230_ed,
+	.cca = at86rf230_cca,
+	.set_trx_state = at86rf230_state,
+	.set_channel = at86rf230_channel,
+};
+
+static int at86rf230_register(struct at86rf230_local *lp)
+{
+	int rc = -ENOMEM;
+
+	lp->dev = ieee802154_alloc_device();
+	if (!lp->dev)
+		goto err_alloc;
+
+	lp->dev->name = dev_name(&lp->spi->dev);
+	lp->dev->priv = lp;
+	lp->dev->parent = &lp->spi->dev;
+#ifdef AT86RF230_OLDFW_HACK
+	lp->dev->extra_tx_headroom = 2;
+#else
+	lp->dev->extra_tx_headroom = 0;
+#endif
+	lp->dev->channel_mask = 0x7ff; /* We do support only 2.4 Ghz */
+	lp->dev->flags = IEEE802154_FLAGS_OMIT_CKSUM;
+
+	rc = ieee802154_register_device(lp->dev, &at86rf230_ops);
+	if (rc)
+		goto err_register;
+
+	/* FIXME: remove this after we have proper support for slave instantiation from iz tool */
+	rtnl_lock();
+	rc = ieee802154_add_slave(lp->dev, "\xde\xad\xbe\xaf\xca\xfe\xba\xbe");
+	rtnl_unlock();
+	if (rc < 0)
+		goto err_slave;
+
+	return 0;
+
+err_slave:
+	ieee802154_unregister_device(lp->dev);
+err_register:
+	ieee802154_free_device(lp->dev);
+err_alloc:
+	return rc;
+}
+
+static void at86rf230_unregister(struct at86rf230_local *lp)
+{
+	ieee802154_unregister_device(lp->dev);
+	ieee802154_free_device(lp->dev);
+}
+
+static void at86rf230_irqwork(struct work_struct *work)
+{
+	struct at86rf230_local *lp = container_of(work, struct at86rf230_local, irqwork);
+	u8 status = 0, val;
+	int rc;
+	unsigned long flags;
+
+	dev_dbg(&lp->spi->dev, "IRQ Worker\n");
+
+	do {
+		rc = at86rf230_read_subreg(lp, RG_IRQ_STATUS, 0xff, 0, &val);
+		status |= val;
+		dev_dbg(&lp->spi->dev, "IRQ Status: %02x\n", status);
+
+		status &= ~IRQ_PLL_LOCK; /* ignore */
+		status &= ~IRQ_RX_START; /* ignore */
+		status &= ~IRQ_AMI; /* ignore */
+		status &= ~IRQ_TRX_UR; /* FIXME: possibly handle ???*/
+
+		if (status & IRQ_TRX_END) {
+			status &= ~IRQ_TRX_END;
+			spin_lock_irqsave(&lp->lock, flags);
+			if (lp->is_tx) {
+				lp->is_tx = 0;
+				spin_unlock_irqrestore(&lp->lock, flags);
+				complete(&lp->tx_complete);
+			} else {
+				spin_unlock_irqrestore(&lp->lock, flags);
+				at86rf230_rx(lp);
+			}
+		}
+
+	} while (status != 0);
+
+	spin_lock_irqsave(&lp->lock, flags);
+	if (lp->irq_disabled) {
+		lp->irq_disabled = 0;
+		enable_irq(lp->spi->irq);
+	}
+	spin_unlock_irqrestore(&lp->lock, flags);
+}
+
+static irqreturn_t at86rf230_isr(int irq, void *data)
+{
+	struct at86rf230_local *lp = data;
+
+	dev_dbg(&lp->spi->dev, "IRQ!\n");
+
+	spin_lock(&lp->lock);
+	if (!lp->irq_disabled) {
+		disable_irq_nosync(irq);
+		lp->irq_disabled = 1;
+	}
+	spin_unlock(&lp->lock);
+
+	schedule_work(&lp->irqwork);
+
+	return IRQ_HANDLED;
+}
+
+
+static int at86rf230_hw_init(struct at86rf230_local *lp)
+{
+	u8 status;
+	int rc;
+
+	rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status);
+	if (rc)
+		return rc;
+
+	dev_info(&lp->spi->dev, "Status: %02x\n", status);
+	if (status == STATE_P_ON) {
+		rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_TRX_OFF);
+		if (rc)
+			return rc;
+		msleep(1);
+		rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status);
+		if (rc)
+			return rc;
+		dev_info(&lp->spi->dev, "Status: %02x\n", status);
+	}
+
+	rc = at86rf230_write_subreg(lp, SR_IRQ_MASK,
+			/*IRQ_TRX_UR | IRQ_CCA_ED | IRQ_TRX_END | IRQ_PLL_UNL | IRQ_PLL_LOCK*/ 0xff);
+	if (rc)
+		return rc;
+
+	rc = at86rf230_write_subreg(lp, SR_CLKM_SHA_SEL, 0x00); /* CLKM changes are applied immediately */
+	if (rc)
+		return rc;
+
+	rc = at86rf230_write_subreg(lp, SR_CLKM_CTRL, 0x00); /* Turn CLKM Off */
+	if (rc)
+		return rc;
+
+	msleep(100);
+
+	rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_TX_ON);
+	if (rc)
+		return rc;
+	msleep(1);
+
+	rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status);
+	if (rc)
+		return rc;
+	dev_info(&lp->spi->dev, "Status: %02x\n", status);
+
+	rc = at86rf230_read_subreg(lp, SR_DVDD_OK, &status);
+	if (rc)
+		return rc;
+	if (!status) {
+		dev_err(&lp->spi->dev, "DVDD error\n");
+		return -EINVAL;
+	}
+
+	rc = at86rf230_read_subreg(lp, SR_AVDD_OK, &status);
+	if (rc)
+		return rc;
+	if (!status) {
+		dev_err(&lp->spi->dev, "AVDD error\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int at86rf230_suspend(struct spi_device *spi, pm_message_t message)
+{
+	return 0;
+}
+
+static int at86rf230_resume(struct spi_device *spi)
+{
+	return 0;
+}
+
+static int __devinit at86rf230_probe(struct spi_device *spi)
+{
+	struct at86rf230_local *lp = kzalloc(sizeof *lp, GFP_KERNEL);
+	u8 man_id_0, man_id_1;
+	int rc;
+	const char *chip;
+	int supported = 0;
+	struct at86rf230_platform_data *pdata = spi->dev.platform_data;
+
+	if (!lp)
+		return -ENOMEM;
+
+	if (!pdata) {
+		dev_err(&spi->dev, "no platform_data\n");
+		rc = -EINVAL;
+		goto err;
+	}
+
+	if (!spi->irq) {
+		dev_err(&spi->dev, "no IRQ specified\n");
+		rc = -EINVAL;
+		goto err;
+	}
+
+	lp->spi = spi;
+
+	lp->rstn = pdata->rstn;
+	lp->slp_tr = pdata->slp_tr;
+	lp->dig2 = pdata->dig2;
+
+	mutex_init(&lp->bmux);
+	INIT_WORK(&lp->irqwork, at86rf230_irqwork);
+	spin_lock_init(&lp->lock);
+	init_completion(&lp->tx_complete);
+
+	spi_set_drvdata(spi, lp);
+
+	rc = gpio_request(lp->rstn, "rstn");
+	if (rc)
+		goto err_rstn;
+
+	if (gpio_is_valid(lp->slp_tr)) {
+		rc = gpio_request(lp->slp_tr, "slp_tr");
+		if (rc)
+			goto err_slp_tr;
+	}
+
+	rc = gpio_direction_output(lp->rstn, 1);
+	if (rc)
+		goto err_gpio_dir;
+
+	if (gpio_is_valid(lp->slp_tr)) {
+		rc = gpio_direction_output(lp->slp_tr, 0);
+		if (rc)
+			goto err_gpio_dir;
+	}
+
+	/* Reset */
+	msleep(1);
+	gpio_set_value(lp->rstn, 0);
+	msleep(1);
+	gpio_set_value(lp->rstn, 1);
+	msleep(1);
+
+	rc = at86rf230_read_subreg(lp, SR_MAN_ID_0, &man_id_0);
+	if (rc)
+		goto err_gpio_dir;
+	rc = at86rf230_read_subreg(lp, SR_MAN_ID_1, &man_id_1);
+	if (rc)
+		goto err_gpio_dir;
+
+	if (man_id_1 != 0x00 || man_id_0 != 0x1f) {
+		dev_err(&spi->dev, "Non-Atmel device found (MAN_ID %02x %02x)\n", man_id_1, man_id_0);
+		rc = -EINVAL;
+		goto err_gpio_dir;
+	}
+
+	rc = at86rf230_read_subreg(lp, SR_PART_NUM, &lp->part);
+	if (rc)
+		goto err_gpio_dir;
+
+	rc = at86rf230_read_subreg(lp, SR_VERSION_NUM, &lp->vers);
+	if (rc)
+		goto err_gpio_dir;
+
+	switch (lp->part) {
+	case 2:
+		chip = "at86rf230";
+		/* supported = 1;  FIXME: should be easy to support; */
+		break;
+	case 3:
+		chip = "at86rf231";
+		supported = 1;
+		break;
+	default:
+		chip = "UNKNOWN";
+		break;
+	}
+
+	dev_info(&spi->dev, "Detected %s chip version %d\n", chip, lp->vers);
+	if (!supported) {
+		rc = -ENOTSUPP;
+		goto err_gpio_dir;
+	}
+
+	rc = at86rf230_hw_init(lp);
+	if (rc)
+		goto err_gpio_dir;
+
+	rc = request_irq(spi->irq, at86rf230_isr, IRQF_SHARED, dev_name(&spi->dev), lp);
+	if (rc)
+		goto err_gpio_dir;
+
+	dev_dbg(&spi->dev, "registered at86rf230\n");
+
+	rc = at86rf230_register(lp);
+	if (rc)
+		goto err_irq;
+
+	return rc;
+
+	at86rf230_unregister(lp);
+err_irq:
+	free_irq(spi->irq, lp);
+	flush_work(&lp->irqwork);
+err_gpio_dir:
+	if (gpio_is_valid(lp->slp_tr))
+		gpio_free(lp->slp_tr);
+err_slp_tr:
+	gpio_free(lp->rstn);
+err_rstn:
+err:
+	spi_set_drvdata(spi, NULL);
+	mutex_destroy(&lp->bmux);
+	kfree(lp);
+	return rc;
+}
+
+static int __devexit at86rf230_remove(struct spi_device *spi)
+{
+	struct at86rf230_local *lp = spi_get_drvdata(spi);
+
+	at86rf230_unregister(lp);
+
+	free_irq(spi->irq, lp);
+	flush_work(&lp->irqwork);
+
+	if (gpio_is_valid(lp->slp_tr))
+		gpio_free(lp->slp_tr);
+	gpio_free(lp->rstn);
+
+	spi_set_drvdata(spi, NULL);
+	mutex_destroy(&lp->bmux);
+	kfree(lp);
+
+	dev_dbg(&spi->dev, "unregistered at86rf230\n");
+	return 0;
+}
+
+static struct spi_driver at86rf230_driver = {
+	.driver = {
+		.name	= "at86rf230",
+		.owner	= THIS_MODULE,
+	},
+	.probe      = at86rf230_probe,
+	.remove     = __devexit_p(at86rf230_remove),
+	.suspend    = at86rf230_suspend,
+	.resume     = at86rf230_resume,
+};
+
+static int __init at86rf230_init(void)
+{
+	return spi_register_driver(&at86rf230_driver);
+}
+module_init(at86rf230_init);
+
+static void __exit at86rf230_exit(void)
+{
+	spi_unregister_driver(&at86rf230_driver);
+}
+module_exit(at86rf230_exit);
+
+MODULE_DESCRIPTION("AT86RF230 Transceiver Driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/include/linux/spi/at86rf230.h b/include/linux/spi/at86rf230.h
new file mode 100644
index 0000000..aa8e250
--- /dev/null
+++ b/include/linux/spi/at86rf230.h
@@ -0,0 +1,32 @@
+/*
+ * AT86RF230/RF231 driver
+ *
+ * Copyright (C) 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 <dmitry.baryshkov-kv7WeFo6aLtBDgjK7y7TUQ@public.gmane.org>
+ */
+#ifndef AT86RF230_H
+#define AT86RF230_H
+
+struct at86rf230_platform_data {
+	int rstn;
+	int slp_tr;
+	int dig2;
+};
+
+#endif
+
-- 
1.6.2.4

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* Re: [PATCH 08/10] tty_io: export tty_class
@ 2009-06-01 15:07                   ` Alan Cox
  0 siblings, 0 replies; 75+ messages in thread
From: Alan Cox @ 2009-06-01 15:07 UTC (permalink / raw)
  To: Dmitry Eremin-Solenikov
  Cc: linux-kernel, netdev, linux-wireless, slapin, maxim.osipov,
	dmitry.baryshkov, oliver.fendt, Dmitry Eremin-Solenikov

On Mon,  1 Jun 2009 18:54:49 +0400
Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> wrote:

> Currently tty_class in a public variable in the tty_io.c
> Export it to the modules to allow some usefull tricks.

Thats exactly why it isn't exported. We don't want "tricks".


^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 08/10] tty_io: export tty_class
@ 2009-06-01 15:07                   ` Alan Cox
  0 siblings, 0 replies; 75+ messages in thread
From: Alan Cox @ 2009-06-01 15:07 UTC (permalink / raw)
  To: Dmitry Eremin-Solenikov
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	slapin-9cOl001CZnBAfugRpC6u6w,
	maxim.osipov-kv7WeFo6aLtBDgjK7y7TUQ,
	dmitry.baryshkov-kv7WeFo6aLtBDgjK7y7TUQ,
	oliver.fendt-kv7WeFo6aLtBDgjK7y7TUQ, Dmitry Eremin-Solenikov

On Mon,  1 Jun 2009 18:54:49 +0400
Dmitry Eremin-Solenikov <dbaryshkov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:

> Currently tty_class in a public variable in the tty_io.c
> Export it to the modules to allow some usefull tricks.

Thats exactly why it isn't exported. We don't want "tricks".

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 08/10] tty_io: export tty_class
  2009-06-01 15:07                   ` Alan Cox
  (?)
@ 2009-06-01 15:10                   ` Dmitry Eremin-Solenikov
  2009-06-01 15:34                     ` Alan Cox
  -1 siblings, 1 reply; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-01 15:10 UTC (permalink / raw)
  To: Alan Cox
  Cc: linux-kernel, netdev, linux-wireless, slapin, maxim.osipov,
	dmitry.baryshkov, oliver.fendt

2009/6/1 Alan Cox <alan@lxorguk.ukuu.org.uk>:
> On Mon,  1 Jun 2009 18:54:49 +0400
> Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> wrote:
>
>> Currently tty_class in a public variable in the tty_io.c
>> Export it to the modules to allow some usefull tricks.
>
> Thats exactly why it isn't exported. We don't want "tricks".

I'd like to find a struct device corresponding to the struct tty_struct
from the ldisc .open call. What would be the best way for me to do this?
I used class_find_device finding the device with matching minor. Will it be
acceptable, if I just move this code into tty_* file and export it as
to modules?


-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 09/10] ieee802154: add serial dongle driver
@ 2009-06-01 15:27                     ` Alan Cox
  0 siblings, 0 replies; 75+ messages in thread
From: Alan Cox @ 2009-06-01 15:27 UTC (permalink / raw)
  To: Dmitry Eremin-Solenikov
  Cc: linux-kernel, netdev, linux-wireless, slapin, maxim.osipov,
	dmitry.baryshkov, oliver.fendt, Dmitry Eremin-Solenikov

> +	zbdev->pending_data = kzalloc(zbdev->pending_size, GFP_KERNEL);
> +	if (!zbdev->pending_data) {
> +		printk(KERN_ERR "%s(): unable to allocate memory\n", __func__);
> +		zbdev->pending_id = 0;
> +		zbdev->pending_size = 0;
> +		return -ENOMEM;
> +	}
> +	memcpy(zbdev->pending_data, buf, len);
> +
> +	return _send_pending_data(zbdev);

Where do you check that the tty has enough space ?


> +	case STATE_WAIT_COMMAND:
> +		if (is_command(c)) {
> +			zbdev->id = c;
> +			zbdev->state = STATE_WAIT_PARAM1;
> +		} else {
> +			cleanup(zbdev);
> +			printk(KERN_ERR "%s, unexpected command id: %x\n", __func__, c);

In all these ERR cases what stops a remote device from having fun spewing
garbage at you and filling the log ?

>
> +	 * channels 0-10 are not valid for us */
> +	BUG_ON(channel < 11 || channel > 26);
> +	/* ...  but our crappy firmware numbers channels from 1 to 16
> +	 * which is a mystery. We suould enforce that using PIB API
> +	 * but additional checking here won't kill, and gcc will
> +	 * optimize this stuff anyway. */
> +	BUG_ON((channel - 10) < 1 && (channel - 10) > 16);

Shouldn't be driver specific hacks in the ldisc surely - or is the ldisc
only applicable to a specific single bit of hardware ?

> + minor = tty->index + tty->driver->minor_start;
> +	zbdev->dev->parent = class_find_device(tty_class, NULL, &minor, dev_minor_match);
> +

That sort of thing shouldn't be buried in the depths of a driver. I'm not
entirely averse to that sort of thing but it belongs in a helper in the
tty layer.

> +	zbdev->tty = tty;

Refcounting ?

> +	cleanup(zbdev);
> +
> +	tty->disc_data = zbdev;
> +	tty->receive_room = MAX_DATA_SIZE;
> +	tty->low_latency = 1;

You can't go around mashing driver internal values - many drivers don't
support low_latency mode and this will make them crash.

> +
> +	/* FIXME: why is this needed. Note don't use ldisc_ref here as the
> +	   open path is before the ldisc is referencable */
> +

[Because otherwise after a SET_LDISC there may be bits from the old stuff
 left over - this one will go away as I finish the ldisc switching
 rewrite that is in the ttydev tree]

> +/*
> + * Called when the tty is put into another line discipline or it hangs up. We
> + * have to wait for any cpu currently executing in any of the other zb_tty_*
> + * routines to finish before we can call zb_tty_close and free the
> + * zb_serial_dev struct. This routine must be called from process context, not
> + * interrupt or softirq context.
> + */
> +static void
> +ieee802154_tty_close(struct tty_struct *tty)
> +{
> +	struct zb_device *zbdev;
> +
> +	zbdev = tty->disc_data;
> +	if (NULL == zbdev) {
> +		printk(KERN_WARNING "%s: match is not found\n", __func__);
> +		return;
> +	}
> +
> +	tty->disc_data = NULL;
> +	zbdev->tty = NULL;

Again you want a refcount on these I suspect. You may actually be safe
anyway but it would be cleaner to take/drop refs.



> +static int
> +ieee802154_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
> +{
> +	struct zb_device *zbdev;
> +	struct ifreq ifr;
> +	int err;
> +	void __user *argp = (void __user *) arg;
> +
> +	pr_debug("cmd = 0x%x\n", cmd);
> +	memset(&ifr, 0, sizeof(ifr));
> +
> +	zbdev = tty->disc_data;
> +	if (NULL == zbdev) {
> +		pr_debug("match is not found\n");
> +		return -EINVAL;
> +	}

If that is NULL it's a serious bug so WARN on it I think

> +	default:
> +		pr_debug("Unknown ioctl cmd: %u\n", cmd);
> +		return -EINVAL;

This will break default ioctl processing. You probably want to call into
some of the generic handlers at this point depending upon your hardware.
Either way -EINVAL is wrong.

> +	}
> +	return 0;

Unreachable

> +static void
> +ieee802154_tty_receive(struct tty_struct *tty, const unsigned char *buf, char *cflags, int count)
> +{
> +	struct zb_device *zbdev;
> +	int i;
> +
> +	/* Debug info */
> +	printk(KERN_INFO "%lu %s, received %d bytes:", jiffies, __func__, count);
> +	for (i = 0; i < count; ++i)
> +		printk(KERN_CONT " 0x%02X", buf[i]);
> +	printk(KERN_CONT "\n");

I don't think the above is meant to be there....


^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 09/10] ieee802154: add serial dongle driver
@ 2009-06-01 15:27                     ` Alan Cox
  0 siblings, 0 replies; 75+ messages in thread
From: Alan Cox @ 2009-06-01 15:27 UTC (permalink / raw)
  To: Dmitry Eremin-Solenikov
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	slapin-9cOl001CZnBAfugRpC6u6w,
	maxim.osipov-kv7WeFo6aLtBDgjK7y7TUQ,
	dmitry.baryshkov-kv7WeFo6aLtBDgjK7y7TUQ,
	oliver.fendt-kv7WeFo6aLtBDgjK7y7TUQ, Dmitry Eremin-Solenikov

> +	zbdev->pending_data = kzalloc(zbdev->pending_size, GFP_KERNEL);
> +	if (!zbdev->pending_data) {
> +		printk(KERN_ERR "%s(): unable to allocate memory\n", __func__);
> +		zbdev->pending_id = 0;
> +		zbdev->pending_size = 0;
> +		return -ENOMEM;
> +	}
> +	memcpy(zbdev->pending_data, buf, len);
> +
> +	return _send_pending_data(zbdev);

Where do you check that the tty has enough space ?


> +	case STATE_WAIT_COMMAND:
> +		if (is_command(c)) {
> +			zbdev->id = c;
> +			zbdev->state = STATE_WAIT_PARAM1;
> +		} else {
> +			cleanup(zbdev);
> +			printk(KERN_ERR "%s, unexpected command id: %x\n", __func__, c);

In all these ERR cases what stops a remote device from having fun spewing
garbage at you and filling the log ?

>
> +	 * channels 0-10 are not valid for us */
> +	BUG_ON(channel < 11 || channel > 26);
> +	/* ...  but our crappy firmware numbers channels from 1 to 16
> +	 * which is a mystery. We suould enforce that using PIB API
> +	 * but additional checking here won't kill, and gcc will
> +	 * optimize this stuff anyway. */
> +	BUG_ON((channel - 10) < 1 && (channel - 10) > 16);

Shouldn't be driver specific hacks in the ldisc surely - or is the ldisc
only applicable to a specific single bit of hardware ?

> + minor = tty->index + tty->driver->minor_start;
> +	zbdev->dev->parent = class_find_device(tty_class, NULL, &minor, dev_minor_match);
> +

That sort of thing shouldn't be buried in the depths of a driver. I'm not
entirely averse to that sort of thing but it belongs in a helper in the
tty layer.

> +	zbdev->tty = tty;

Refcounting ?

> +	cleanup(zbdev);
> +
> +	tty->disc_data = zbdev;
> +	tty->receive_room = MAX_DATA_SIZE;
> +	tty->low_latency = 1;

You can't go around mashing driver internal values - many drivers don't
support low_latency mode and this will make them crash.

> +
> +	/* FIXME: why is this needed. Note don't use ldisc_ref here as the
> +	   open path is before the ldisc is referencable */
> +

[Because otherwise after a SET_LDISC there may be bits from the old stuff
 left over - this one will go away as I finish the ldisc switching
 rewrite that is in the ttydev tree]

> +/*
> + * Called when the tty is put into another line discipline or it hangs up. We
> + * have to wait for any cpu currently executing in any of the other zb_tty_*
> + * routines to finish before we can call zb_tty_close and free the
> + * zb_serial_dev struct. This routine must be called from process context, not
> + * interrupt or softirq context.
> + */
> +static void
> +ieee802154_tty_close(struct tty_struct *tty)
> +{
> +	struct zb_device *zbdev;
> +
> +	zbdev = tty->disc_data;
> +	if (NULL == zbdev) {
> +		printk(KERN_WARNING "%s: match is not found\n", __func__);
> +		return;
> +	}
> +
> +	tty->disc_data = NULL;
> +	zbdev->tty = NULL;

Again you want a refcount on these I suspect. You may actually be safe
anyway but it would be cleaner to take/drop refs.



> +static int
> +ieee802154_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
> +{
> +	struct zb_device *zbdev;
> +	struct ifreq ifr;
> +	int err;
> +	void __user *argp = (void __user *) arg;
> +
> +	pr_debug("cmd = 0x%x\n", cmd);
> +	memset(&ifr, 0, sizeof(ifr));
> +
> +	zbdev = tty->disc_data;
> +	if (NULL == zbdev) {
> +		pr_debug("match is not found\n");
> +		return -EINVAL;
> +	}

If that is NULL it's a serious bug so WARN on it I think

> +	default:
> +		pr_debug("Unknown ioctl cmd: %u\n", cmd);
> +		return -EINVAL;

This will break default ioctl processing. You probably want to call into
some of the generic handlers at this point depending upon your hardware.
Either way -EINVAL is wrong.

> +	}
> +	return 0;

Unreachable

> +static void
> +ieee802154_tty_receive(struct tty_struct *tty, const unsigned char *buf, char *cflags, int count)
> +{
> +	struct zb_device *zbdev;
> +	int i;
> +
> +	/* Debug info */
> +	printk(KERN_INFO "%lu %s, received %d bytes:", jiffies, __func__, count);
> +	for (i = 0; i < count; ++i)
> +		printk(KERN_CONT " 0x%02X", buf[i]);
> +	printk(KERN_CONT "\n");

I don't think the above is meant to be there....

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 08/10] tty_io: export tty_class
  2009-06-01 15:10                   ` Dmitry Eremin-Solenikov
@ 2009-06-01 15:34                     ` Alan Cox
  2009-06-02 14:22                         ` Dmitry Eremin-Solenikov
  0 siblings, 1 reply; 75+ messages in thread
From: Alan Cox @ 2009-06-01 15:34 UTC (permalink / raw)
  To: Dmitry Eremin-Solenikov
  Cc: linux-kernel, netdev, linux-wireless, slapin, maxim.osipov,
	dmitry.baryshkov, oliver.fendt

> I used class_find_device finding the device with matching minor. Will it be
> acceptable, if I just move this code into tty_* file and export it as
> to modules?

Yes - create a proper tty helper function for doing the job and document
what it does. That way if the tty layer is changed it is obvious that
this code also needs considering.

Alan

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 10/10] ieee802154: add at86rf230/rf231 spi driver
@ 2009-06-01 16:21                       ` Gábor Stefanik
  0 siblings, 0 replies; 75+ messages in thread
From: Gábor Stefanik @ 2009-06-01 16:21 UTC (permalink / raw)
  To: Dmitry Eremin-Solenikov
  Cc: linux-kernel, netdev, linux-wireless, slapin, maxim.osipov,
	dmitry.baryshkov, oliver.fendt

On Mon, Jun 1, 2009 at 4:54 PM, Dmitry Eremin-Solenikov
<dbaryshkov@gmail.com> wrote:
> Add a driver handling AT86RF230/RF231 line of chips. Only basic
> features are currently implemented (no extended mode operation, etc.)
> Also the RF230 chip is not really supported yet.
>
> Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
> Signed-off-by: Sergey Lapin <slapin@ossfans.org>
> ---
>  drivers/ieee802154/Kconfig     |    5 +
>  drivers/ieee802154/Makefile    |    1 +
>  drivers/ieee802154/at86rf230.c |  971 ++++++++++++++++++++++++++++++++++++++++

Shouldn't this go into drivers/net/ieee802154 instead?

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 10/10] ieee802154: add at86rf230/rf231 spi driver
@ 2009-06-01 16:21                       ` Gábor Stefanik
  0 siblings, 0 replies; 75+ messages in thread
From: Gábor Stefanik @ 2009-06-01 16:21 UTC (permalink / raw)
  To: Dmitry Eremin-Solenikov
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	slapin-9cOl001CZnBAfugRpC6u6w,
	maxim.osipov-kv7WeFo6aLtBDgjK7y7TUQ,
	dmitry.baryshkov-kv7WeFo6aLtBDgjK7y7TUQ,
	oliver.fendt-kv7WeFo6aLtBDgjK7y7TUQ

On Mon, Jun 1, 2009 at 4:54 PM, Dmitry Eremin-Solenikov
<dbaryshkov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> Add a driver handling AT86RF230/RF231 line of chips. Only basic
> features are currently implemented (no extended mode operation, etc.)
> Also the RF230 chip is not really supported yet.
>
> Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> Signed-off-by: Sergey Lapin <slapin-9cOl001CZnBAfugRpC6u6w@public.gmane.org>
> ---
>  drivers/ieee802154/Kconfig     |    5 +
>  drivers/ieee802154/Makefile    |    1 +
>  drivers/ieee802154/at86rf230.c |  971 ++++++++++++++++++++++++++++++++++++++++

Shouldn't this go into drivers/net/ieee802154 instead?
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 09/10] ieee802154: add serial dongle driver
  2009-06-01 15:27                     ` Alan Cox
  (?)
@ 2009-06-01 20:29                     ` Dmitry Eremin-Solenikov
  2009-06-01 21:52                         ` Alan Cox
  -1 siblings, 1 reply; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-01 20:29 UTC (permalink / raw)
  To: Alan Cox
  Cc: linux-kernel, netdev, linux-wireless, slapin, maxim.osipov,
	dmitry.baryshkov, oliver.fendt

Thanks for the review, Alan,

On Mon, Jun 01, 2009 at 04:27:32PM +0100, Alan Cox wrote:
> > +	zbdev->pending_data = kzalloc(zbdev->pending_size, GFP_KERNEL);
> > +	if (!zbdev->pending_data) {
> > +		printk(KERN_ERR "%s(): unable to allocate memory\n", __func__);
> > +		zbdev->pending_id = 0;
> > +		zbdev->pending_size = 0;
> > +		return -ENOMEM;
> > +	}
> > +	memcpy(zbdev->pending_data, buf, len);
> > +
> > +	return _send_pending_data(zbdev);
> 
> Where do you check that the tty has enough space ?

Basically that means checking for ->write result, doesn't it?

> 
> 
> > +	case STATE_WAIT_COMMAND:
> > +		if (is_command(c)) {
> > +			zbdev->id = c;
> > +			zbdev->state = STATE_WAIT_PARAM1;
> > +		} else {
> > +			cleanup(zbdev);
> > +			printk(KERN_ERR "%s, unexpected command id: %x\n", __func__, c);
> 
> In all these ERR cases what stops a remote device from having fun spewing
> garbage at you and filling the log ?

And what stops your precious IDE controller from spewing garbage and
filling the log? Nothing I think. I'll lower the priority of the
messages though.

> > +	 * channels 0-10 are not valid for us */
> > +	BUG_ON(channel < 11 || channel > 26);
> > +	/* ...  but our crappy firmware numbers channels from 1 to 16
> > +	 * which is a mystery. We suould enforce that using PIB API
> > +	 * but additional checking here won't kill, and gcc will
> > +	 * optimize this stuff anyway. */
> > +	BUG_ON((channel - 10) < 1 && (channel - 10) > 16);
> 
> Shouldn't be driver specific hacks in the ldisc surely - or is the ldisc
> only applicable to a specific single bit of hardware ?

Currently it's applicable to only one (well, two) type of evkits from
FreeScale flashed with pretty much specific firmware. For other evkits
one have to write firmware on his own. Unlike bluetooth there is no
standard for such communication over serial proto. Also if there will be
any RS-232 device which implements IEEE 802.15.4 PHY layer and doesn't
follow this protocol, we can extend the ldisc to be more like hci-uart:
a multiplexor of protocols.

> > + minor = tty->index + tty->driver->minor_start;
> > +	zbdev->dev->parent = class_find_device(tty_class, NULL, &minor, dev_minor_match);
> > +
> 
> That sort of thing shouldn't be buried in the depths of a driver. I'm not
> entirely averse to that sort of thing but it belongs in a helper in the
> tty layer.

Fine with me. I'll move this into helper in tty layer.

> > +	zbdev->tty = tty;
> 
> Refcounting ?

Sample code? SLIP, hci-uart, ppp don't do it.

> > +	cleanup(zbdev);
> > +
> > +	tty->disc_data = zbdev;
> > +	tty->receive_room = MAX_DATA_SIZE;
> > +	tty->low_latency = 1;
> 
> You can't go around mashing driver internal values - many drivers don't
> support low_latency mode and this will make them crash.

C&P from drivers/bluetooth/hci-ldisc.c, around line 466. We had problems
working with low-latency unset.

> > +/*
> > + * Called when the tty is put into another line discipline or it hangs up. We
> > + * have to wait for any cpu currently executing in any of the other zb_tty_*
> > + * routines to finish before we can call zb_tty_close and free the
> > + * zb_serial_dev struct. This routine must be called from process context, not
> > + * interrupt or softirq context.
> > + */
> > +static void
> > +ieee802154_tty_close(struct tty_struct *tty)
> > +{
> > +	struct zb_device *zbdev;
> > +
> > +	zbdev = tty->disc_data;
> > +	if (NULL == zbdev) {
> > +		printk(KERN_WARNING "%s: match is not found\n", __func__);
> > +		return;
> > +	}
> > +
> > +	tty->disc_data = NULL;
> > +	zbdev->tty = NULL;
> 
> Again you want a refcount on these I suspect. You may actually be safe
> anyway but it would be cleaner to take/drop refs.

See above. Didn't see refounting in any of ldiscs checked.
That's not a 'no, I won't do it', but rather 'wait, all those are also
buggy ?!'

> > +static int
> > +ieee802154_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
> > +{
> > +	struct zb_device *zbdev;
> > +	struct ifreq ifr;
> > +	int err;
> > +	void __user *argp = (void __user *) arg;
> > +
> > +	pr_debug("cmd = 0x%x\n", cmd);
> > +	memset(&ifr, 0, sizeof(ifr));
> > +
> > +	zbdev = tty->disc_data;
> > +	if (NULL == zbdev) {
> > +		pr_debug("match is not found\n");
> > +		return -EINVAL;
> > +	}
> 
> If that is NULL it's a serious bug so WARN on it I think

I tend to agree.


> > +	default:
> > +		pr_debug("Unknown ioctl cmd: %u\n", cmd);
> > +		return -EINVAL;
> 
> This will break default ioctl processing. You probably want to call into
> some of the generic handlers at this point depending upon your hardware.
> Either way -EINVAL is wrong.


n_tty_ioctl_helper ?

> > +static void
> > +ieee802154_tty_receive(struct tty_struct *tty, const unsigned char *buf, char *cflags, int count)
> > +{
> > +	struct zb_device *zbdev;
> > +	int i;
> > +
> > +	/* Debug info */
> > +	printk(KERN_INFO "%lu %s, received %d bytes:", jiffies, __func__, count);
> > +	for (i = 0; i < count; ++i)
> > +		printk(KERN_CONT " 0x%02X", buf[i]);
> > +	printk(KERN_CONT "\n");
> 
> I don't think the above is meant to be there....

In final version, it will go away.

-- 
With best wishes
Dmitry


^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 10/10] ieee802154: add at86rf230/rf231 spi driver
@ 2009-06-01 20:33                         ` Dmitry Eremin-Solenikov
  0 siblings, 0 replies; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-01 20:33 UTC (permalink / raw)
  To: Gábor Stefanik
  Cc: linux-kernel, netdev, linux-wireless, slapin, maxim.osipov,
	dmitry.baryshkov, oliver.fendt

On Mon, Jun 01, 2009 at 06:21:37PM +0200, Gábor Stefanik wrote:
> On Mon, Jun 1, 2009 at 4:54 PM, Dmitry Eremin-Solenikov
> <dbaryshkov@gmail.com> wrote:
> > Add a driver handling AT86RF230/RF231 line of chips. Only basic
> > features are currently implemented (no extended mode operation, etc.)
> > Also the RF230 chip is not really supported yet.
> >
> > Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
> > Signed-off-by: Sergey Lapin <slapin@ossfans.org>
> > ---
> >  drivers/ieee802154/Kconfig     |    5 +
> >  drivers/ieee802154/Makefile    |    1 +
> >  drivers/ieee802154/at86rf230.c |  971 ++++++++++++++++++++++++++++++++++++++++
> 
> Shouldn't this go into drivers/net/ieee802154 instead?

I thought about drivers/net as about ip (well, more or less) network
drivers. We have drivers/atm or drivers/bluetooth (and bluetooth is
802.15.1...). So we've used just drivers/ieee802154. If you say so,
we will move to drivers/net.

-- 
With best wishes
Dmitry


^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 10/10] ieee802154: add at86rf230/rf231 spi driver
@ 2009-06-01 20:33                         ` Dmitry Eremin-Solenikov
  0 siblings, 0 replies; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-01 20:33 UTC (permalink / raw)
  To: Gábor Stefanik
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	slapin-9cOl001CZnBAfugRpC6u6w,
	maxim.osipov-kv7WeFo6aLtBDgjK7y7TUQ,
	dmitry.baryshkov-kv7WeFo6aLtBDgjK7y7TUQ,
	oliver.fendt-kv7WeFo6aLtBDgjK7y7TUQ

On Mon, Jun 01, 2009 at 06:21:37PM +0200, Gábor Stefanik wrote:
> On Mon, Jun 1, 2009 at 4:54 PM, Dmitry Eremin-Solenikov
> <dbaryshkov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> > Add a driver handling AT86RF230/RF231 line of chips. Only basic
> > features are currently implemented (no extended mode operation, etc.)
> > Also the RF230 chip is not really supported yet.
> >
> > Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> > Signed-off-by: Sergey Lapin <slapin-9cOl001CZnBAfugRpC6u6w@public.gmane.org>
> > ---
> >  drivers/ieee802154/Kconfig     |    5 +
> >  drivers/ieee802154/Makefile    |    1 +
> >  drivers/ieee802154/at86rf230.c |  971 ++++++++++++++++++++++++++++++++++++++++
> 
> Shouldn't this go into drivers/net/ieee802154 instead?

I thought about drivers/net as about ip (well, more or less) network
drivers. We have drivers/atm or drivers/bluetooth (and bluetooth is
802.15.1...). So we've used just drivers/ieee802154. If you say so,
we will move to drivers/net.

-- 
With best wishes
Dmitry

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 09/10] ieee802154: add serial dongle driver
@ 2009-06-01 21:52                         ` Alan Cox
  0 siblings, 0 replies; 75+ messages in thread
From: Alan Cox @ 2009-06-01 21:52 UTC (permalink / raw)
  To: Dmitry Eremin-Solenikov
  Cc: linux-kernel, netdev, linux-wireless, slapin, maxim.osipov,
	dmitry.baryshkov, oliver.fendt

> > > +	return _send_pending_data(zbdev);
> > 
> > Where do you check that the tty has enough space ?
> 
> Basically that means checking for ->write result, doesn't it?

You should check write_room before writing if you want some control - you
can also then respect internal flow control via the wakeup mechanism.

Something like:
                /* Wait for space */
                while ((space = tty_write_room(tty)) < len) {
                        if (file->f_flags & O_NONBLOCK) {
                                err = -EAGAIN;
                                break;
                        }
                        interruptible_sleep_on(&tty->write_wait);
                        if (signal_pending(current)) {
                                err = -EINTR;
                                break;
                        }
                }
                /* Shove the entire frame down */
                tty->ops->write(tty, data, len);
 
> > In all these ERR cases what stops a remote device from having fun spewing
> > garbage at you and filling the log ?
> 
> And what stops your precious IDE controller from spewing garbage and
> filling the log? Nothing I think. I'll lower the priority of the
> messages though.

The fact the drive is entirely under my control and not potentially being
spewed at from a hostile network. Also the fact that it takes about 30
seconds to spank a misbehaving drive and reset it. The network laye
generally uses time checks (search for ratelimit()).

> any RS-232 device which implements IEEE 802.15.4 PHY layer and doesn't
> follow this protocol, we can extend the ldisc to be more like hci-uart:
> a multiplexor of protocols.

Ok

> > > +	zbdev->tty = tty;
> > 
> > Refcounting ?
> 
> Sample code? SLIP, hci-uart, ppp don't do it.

No I'm still running around clobbering them all - and slip needed a
partial rewrite first.

	zbdev->tty = tty_kref_get(tty);

	tty_kref_put(foo);

> > You can't go around mashing driver internal values - many drivers don't
> > support low_latency mode and this will make them crash.
> 
> C&P from drivers/bluetooth/hci-ldisc.c, around line 466. We had problems
> working with low-latency unset.

The bluetooth one needs killing too. I will do that tomorrow ...

How many releases ago - the entire tty buffering layer has been rewritten
over time. tty->low_latency requires driver specific support that most
don't have. Also as of 2.6.30rc you'll get debug spew if you misuse it.

If you still need it we need to know why.


> That's not a 'no, I won't do it', but rather 'wait, all those are also
> buggy ?!'

The tty layer has a lot of "yes, those are also buggy" - which is why I'm
currently half way through systematically brutalising it.


> > > +	default:
> > > +		pr_debug("Unknown ioctl cmd: %u\n", cmd);
> > > +		return -EINVAL;
> > 
> > This will break default ioctl processing. You probably want to call into
> > some of the generic handlers at this point depending upon your hardware.
> > Either way -EINVAL is wrong.
> 
> 
> n_tty_ioctl_helper ?

That depends what you need. tty_mode_ioctl() gives you all the mode
stuff, n_tty_ioctl_helper adds things like software flow management which
don't actually look relevant to your ldisc ?

Any other queries let me know, and if the tty->low_latency is still
needed let me know and we'll figure out why between us, as it should not
be.

Alan

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 09/10] ieee802154: add serial dongle driver
@ 2009-06-01 21:52                         ` Alan Cox
  0 siblings, 0 replies; 75+ messages in thread
From: Alan Cox @ 2009-06-01 21:52 UTC (permalink / raw)
  To: Dmitry Eremin-Solenikov
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	slapin-9cOl001CZnBAfugRpC6u6w,
	maxim.osipov-kv7WeFo6aLtBDgjK7y7TUQ,
	dmitry.baryshkov-kv7WeFo6aLtBDgjK7y7TUQ,
	oliver.fendt-kv7WeFo6aLtBDgjK7y7TUQ

> > > +	return _send_pending_data(zbdev);
> > 
> > Where do you check that the tty has enough space ?
> 
> Basically that means checking for ->write result, doesn't it?

You should check write_room before writing if you want some control - you
can also then respect internal flow control via the wakeup mechanism.

Something like:
                /* Wait for space */
                while ((space = tty_write_room(tty)) < len) {
                        if (file->f_flags & O_NONBLOCK) {
                                err = -EAGAIN;
                                break;
                        }
                        interruptible_sleep_on(&tty->write_wait);
                        if (signal_pending(current)) {
                                err = -EINTR;
                                break;
                        }
                }
                /* Shove the entire frame down */
                tty->ops->write(tty, data, len);
 
> > In all these ERR cases what stops a remote device from having fun spewing
> > garbage at you and filling the log ?
> 
> And what stops your precious IDE controller from spewing garbage and
> filling the log? Nothing I think. I'll lower the priority of the
> messages though.

The fact the drive is entirely under my control and not potentially being
spewed at from a hostile network. Also the fact that it takes about 30
seconds to spank a misbehaving drive and reset it. The network laye
generally uses time checks (search for ratelimit()).

> any RS-232 device which implements IEEE 802.15.4 PHY layer and doesn't
> follow this protocol, we can extend the ldisc to be more like hci-uart:
> a multiplexor of protocols.

Ok

> > > +	zbdev->tty = tty;
> > 
> > Refcounting ?
> 
> Sample code? SLIP, hci-uart, ppp don't do it.

No I'm still running around clobbering them all - and slip needed a
partial rewrite first.

	zbdev->tty = tty_kref_get(tty);

	tty_kref_put(foo);

> > You can't go around mashing driver internal values - many drivers don't
> > support low_latency mode and this will make them crash.
> 
> C&P from drivers/bluetooth/hci-ldisc.c, around line 466. We had problems
> working with low-latency unset.

The bluetooth one needs killing too. I will do that tomorrow ...

How many releases ago - the entire tty buffering layer has been rewritten
over time. tty->low_latency requires driver specific support that most
don't have. Also as of 2.6.30rc you'll get debug spew if you misuse it.

If you still need it we need to know why.


> That's not a 'no, I won't do it', but rather 'wait, all those are also
> buggy ?!'

The tty layer has a lot of "yes, those are also buggy" - which is why I'm
currently half way through systematically brutalising it.


> > > +	default:
> > > +		pr_debug("Unknown ioctl cmd: %u\n", cmd);
> > > +		return -EINVAL;
> > 
> > This will break default ioctl processing. You probably want to call into
> > some of the generic handlers at this point depending upon your hardware.
> > Either way -EINVAL is wrong.
> 
> 
> n_tty_ioctl_helper ?

That depends what you need. tty_mode_ioctl() gives you all the mode
stuff, n_tty_ioctl_helper adds things like software flow management which
don't actually look relevant to your ldisc ?

Any other queries let me know, and if the tty->low_latency is still
needed let me know and we'll figure out why between us, as it should not
be.

Alan
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 10/10] ieee802154: add at86rf230/rf231 spi driver
@ 2009-06-02  8:10                           ` Holger Schurig
  0 siblings, 0 replies; 75+ messages in thread
From: Holger Schurig @ 2009-06-02  8:10 UTC (permalink / raw)
  To: linux-wireless
  Cc: Dmitry Eremin-Solenikov, Gábor Stefanik, linux-kernel,
	netdev, slapin, maxim.osipov, dmitry.baryshkov, oliver.fendt

> I thought about drivers/net as about ip (well, more or less)
> network drivers. We have drivers/atm or drivers/bluetooth (and
> bluetooth is 802.15.1...).

I actually like that this is drivers/bluetooth and not 
drivers/ieee802151. Would you consider drivers/zigbee instead of 
drivers/ieee802154 ???

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 10/10] ieee802154: add at86rf230/rf231 spi driver
@ 2009-06-02  8:10                           ` Holger Schurig
  0 siblings, 0 replies; 75+ messages in thread
From: Holger Schurig @ 2009-06-02  8:10 UTC (permalink / raw)
  To: linux-wireless-u79uwXL29TY76Z2rM5mHXA
  Cc: Dmitry Eremin-Solenikov, Gábor Stefanik,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA, slapin-9cOl001CZnBAfugRpC6u6w,
	maxim.osipov-kv7WeFo6aLtBDgjK7y7TUQ,
	dmitry.baryshkov-kv7WeFo6aLtBDgjK7y7TUQ,
	oliver.fendt-kv7WeFo6aLtBDgjK7y7TUQ

> I thought about drivers/net as about ip (well, more or less)
> network drivers. We have drivers/atm or drivers/bluetooth (and
> bluetooth is 802.15.1...).

I actually like that this is drivers/bluetooth and not 
drivers/ieee802151. Would you consider drivers/zigbee instead of 
drivers/ieee802154 ???
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 10/10] ieee802154: add at86rf230/rf231 spi driver
@ 2009-06-02  8:21                             ` Marcel Holtmann
  0 siblings, 0 replies; 75+ messages in thread
From: Marcel Holtmann @ 2009-06-02  8:21 UTC (permalink / raw)
  To: Holger Schurig
  Cc: linux-wireless, Dmitry Eremin-Solenikov, Gábor Stefanik,
	linux-kernel, netdev, slapin, maxim.osipov, dmitry.baryshkov,
	oliver.fendt

Hi Holger,

> > I thought about drivers/net as about ip (well, more or less)
> > network drivers. We have drivers/atm or drivers/bluetooth (and
> > bluetooth is 802.15.1...).
> 
> I actually like that this is drivers/bluetooth and not 
> drivers/ieee802151. Would you consider drivers/zigbee instead of 
> drivers/ieee802154 ???

I fully agree here.

Please use "zigbee" instead of "ieee*" names since that can become messy
and confusing. I know that in theory the IEEE part of ZigBee is more
low-level radio and could be used by non-ZigBee devices, but that is not
gonna happen anyway. Especially with Bluetooth Low Energy pushing into
the turf of ZigBee. So please use proper names and not confuse people
with IEEE numbers ;)

Regards

Marcel



^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 10/10] ieee802154: add at86rf230/rf231 spi driver
@ 2009-06-02  8:21                             ` Marcel Holtmann
  0 siblings, 0 replies; 75+ messages in thread
From: Marcel Holtmann @ 2009-06-02  8:21 UTC (permalink / raw)
  To: Holger Schurig
  Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA, Dmitry Eremin-Solenikov,
	Gábor Stefanik, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA, slapin-9cOl001CZnBAfugRpC6u6w,
	maxim.osipov-kv7WeFo6aLtBDgjK7y7TUQ,
	dmitry.baryshkov-kv7WeFo6aLtBDgjK7y7TUQ,
	oliver.fendt-kv7WeFo6aLtBDgjK7y7TUQ

Hi Holger,

> > I thought about drivers/net as about ip (well, more or less)
> > network drivers. We have drivers/atm or drivers/bluetooth (and
> > bluetooth is 802.15.1...).
> 
> I actually like that this is drivers/bluetooth and not 
> drivers/ieee802151. Would you consider drivers/zigbee instead of 
> drivers/ieee802154 ???

I fully agree here.

Please use "zigbee" instead of "ieee*" names since that can become messy
and confusing. I know that in theory the IEEE part of ZigBee is more
low-level radio and could be used by non-ZigBee devices, but that is not
gonna happen anyway. Especially with Bluetooth Low Energy pushing into
the turf of ZigBee. So please use proper names and not confuse people
with IEEE numbers ;)

Regards

Marcel


--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Ответ: [PATCH 10/10] ieee802154: add at86rf230/rf231 spi driver
@ 2009-06-02  8:29                               ` Dmitry Eremin-Solenikov
  0 siblings, 0 replies; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-02  8:29 UTC (permalink / raw)
  To: Marcel Holtmann
  Cc: Holger Schurig, linux-wireless, Gábor Stefanik,
	linux-kernel, netdev, slapin, maxim.osipov, dmitry.baryshkov,
	oliver.fendt

2009/6/2, Marcel Holtmann <marcel@holtmann.org>:
> Hi Holger,
>
>> > I thought about drivers/net as about ip (well, more or less)
>> > network drivers. We have drivers/atm or drivers/bluetooth (and
>> > bluetooth is 802.15.1...).
>>
>> I actually like that this is drivers/bluetooth and not
>> drivers/ieee802151. Would you consider drivers/zigbee instead of
>> drivers/ieee802154 ???
>
> I fully agree here.
>
> Please use "zigbee" instead of "ieee*" names since that can become messy
> and confusing. I know that in theory the IEEE part of ZigBee is more
> low-level radio and could be used by non-ZigBee devices, but that is not
> gonna happen anyway. Especially with Bluetooth Low Energy pushing into
> the turf of ZigBee. So please use proper names and not confuse people
> with IEEE numbers ;)

This gonna happen, as we are most probably going to implement 6lowpan
on top of our stack. 6lowpan is a way to encapsulate IPv6 frames into
IEEE 802.15.4 and has nothing in common with ZigBee. Moreover
ZigBee is a trademark with strict rules upon it's usage. Our lawyers are
currently investigating if it's possible to use this name in projects like
Linux kernel which are open-source, non-related to any project but
OTOH can be encapsulated in any commercial project.

IEEE 802.15.4 is a term like IEEE 802.11. We do have mac80211,
we have had (until recently) ieee80211 dir, so why bother?

For Bluetooth naming directories 'bluetooth' is logical, as 802.15.1
standard is a less known name, doesn't incorporate latest changes
from Bluetooth, etc.

-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Ответ: [PATCH 10/10] ieee802154: add at86rf230/rf231 spi driver
@ 2009-06-02  8:29                               ` Dmitry Eremin-Solenikov
  0 siblings, 0 replies; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-02  8:29 UTC (permalink / raw)
  To: Marcel Holtmann
  Cc: Holger Schurig, linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	Gábor Stefanik, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA, slapin-9cOl001CZnBAfugRpC6u6w,
	maxim.osipov-kv7WeFo6aLtBDgjK7y7TUQ,
	dmitry.baryshkov-kv7WeFo6aLtBDgjK7y7TUQ,
	oliver.fendt-kv7WeFo6aLtBDgjK7y7TUQ

2009/6/2, Marcel Holtmann <marcel-kz+m5ild9QBg9hUCZPvPmw@public.gmane.org>:
> Hi Holger,
>
>> > I thought about drivers/net as about ip (well, more or less)
>> > network drivers. We have drivers/atm or drivers/bluetooth (and
>> > bluetooth is 802.15.1...).
>>
>> I actually like that this is drivers/bluetooth and not
>> drivers/ieee802151. Would you consider drivers/zigbee instead of
>> drivers/ieee802154 ???
>
> I fully agree here.
>
> Please use "zigbee" instead of "ieee*" names since that can become messy
> and confusing. I know that in theory the IEEE part of ZigBee is more
> low-level radio and could be used by non-ZigBee devices, but that is not
> gonna happen anyway. Especially with Bluetooth Low Energy pushing into
> the turf of ZigBee. So please use proper names and not confuse people
> with IEEE numbers ;)

This gonna happen, as we are most probably going to implement 6lowpan
on top of our stack. 6lowpan is a way to encapsulate IPv6 frames into
IEEE 802.15.4 and has nothing in common with ZigBee. Moreover
ZigBee is a trademark with strict rules upon it's usage. Our lawyers are
currently investigating if it's possible to use this name in projects like
Linux kernel which are open-source, non-related to any project but
OTOH can be encapsulated in any commercial project.

IEEE 802.15.4 is a term like IEEE 802.11. We do have mac80211,
we have had (until recently) ieee80211 dir, so why bother?

For Bluetooth naming directories 'bluetooth' is logical, as 802.15.1
standard is a less known name, doesn't incorporate latest changes
from Bluetooth, etc.

-- 
With best wishes
Dmitry
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: Ответ: [PATCH 10/10] ieee802154: add at86rf230/rf231 spi driver
  2009-06-02  8:29                               ` Dmitry Eremin-Solenikov
  (?)
@ 2009-06-02  8:36                               ` Marcel Holtmann
  2009-06-02  8:46                                 ` Florian Fainelli
                                                   ` (2 more replies)
  -1 siblings, 3 replies; 75+ messages in thread
From: Marcel Holtmann @ 2009-06-02  8:36 UTC (permalink / raw)
  To: Dmitry Eremin-Solenikov
  Cc: Holger Schurig, linux-wireless, Gábor Stefanik,
	linux-kernel, netdev, slapin, maxim.osipov, dmitry.baryshkov,
	oliver.fendt

Hi Dmitry,

> >> > I thought about drivers/net as about ip (well, more or less)
> >> > network drivers. We have drivers/atm or drivers/bluetooth (and
> >> > bluetooth is 802.15.1...).
> >>
> >> I actually like that this is drivers/bluetooth and not
> >> drivers/ieee802151. Would you consider drivers/zigbee instead of
> >> drivers/ieee802154 ???
> >
> > I fully agree here.
> >
> > Please use "zigbee" instead of "ieee*" names since that can become messy
> > and confusing. I know that in theory the IEEE part of ZigBee is more
> > low-level radio and could be used by non-ZigBee devices, but that is not
> > gonna happen anyway. Especially with Bluetooth Low Energy pushing into
> > the turf of ZigBee. So please use proper names and not confuse people
> > with IEEE numbers ;)
> 
> This gonna happen, as we are most probably going to implement 6lowpan
> on top of our stack. 6lowpan is a way to encapsulate IPv6 frames into
> IEEE 802.15.4 and has nothing in common with ZigBee. Moreover
> ZigBee is a trademark with strict rules upon it's usage. Our lawyers are
> currently investigating if it's possible to use this name in projects like
> Linux kernel which are open-source, non-related to any project but
> OTOH can be encapsulated in any commercial project.
> 
> IEEE 802.15.4 is a term like IEEE 802.11. We do have mac80211,
> we have had (until recently) ieee80211 dir, so why bother?
> 
> For Bluetooth naming directories 'bluetooth' is logical, as 802.15.1
> standard is a less known name, doesn't incorporate latest changes
> from Bluetooth, etc.

and so is IEEE 802.15.4 hence we propose using "zigbee" here. Using the
mac80211 has historical reasons and 802.11 is a known name and even used
on product marketing material. IEEE 802.15.4 is not. We are also using
the term "wimax" and not its IEEE numbering.

Regards

Marcel



^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: Ответ: [PATCH 10/10] ieee802154: add at86rf230/rf231 spi driver
  2009-06-02  8:36                               ` Marcel Holtmann
@ 2009-06-02  8:46                                 ` Florian Fainelli
  2009-06-02  8:49                                 ` Maxim Osipov
  2009-06-02  8:52                                   ` Sergey Lapin
  2 siblings, 0 replies; 75+ messages in thread
From: Florian Fainelli @ 2009-06-02  8:46 UTC (permalink / raw)
  To: Marcel Holtmann
  Cc: Dmitry Eremin-Solenikov, Holger Schurig, linux-wireless,
	Gábor Stefanik, linux-kernel, netdev, slapin, maxim.osipov,
	dmitry.baryshkov, oliver.fendt

Le Tuesday 02 June 2009 10:36:49 Marcel Holtmann, vous avez écrit :
> Hi Dmitry,
>
> > >> > I thought about drivers/net as about ip (well, more or less)
> > >> > network drivers. We have drivers/atm or drivers/bluetooth (and
> > >> > bluetooth is 802.15.1...).
> > >>
> > >> I actually like that this is drivers/bluetooth and not
> > >> drivers/ieee802151. Would you consider drivers/zigbee instead of
> > >> drivers/ieee802154 ???
> > >
> > > I fully agree here.
> > >
> > > Please use "zigbee" instead of "ieee*" names since that can become
> > > messy and confusing. I know that in theory the IEEE part of ZigBee is
> > > more low-level radio and could be used by non-ZigBee devices, but that
> > > is not gonna happen anyway. Especially with Bluetooth Low Energy
> > > pushing into the turf of ZigBee. So please use proper names and not
> > > confuse people with IEEE numbers ;)
> >
> > This gonna happen, as we are most probably going to implement 6lowpan
> > on top of our stack. 6lowpan is a way to encapsulate IPv6 frames into
> > IEEE 802.15.4 and has nothing in common with ZigBee. Moreover
> > ZigBee is a trademark with strict rules upon it's usage. Our lawyers are
> > currently investigating if it's possible to use this name in projects
> > like Linux kernel which are open-source, non-related to any project but
> > OTOH can be encapsulated in any commercial project.
> >
> > IEEE 802.15.4 is a term like IEEE 802.11. We do have mac80211,
> > we have had (until recently) ieee80211 dir, so why bother?
> >
> > For Bluetooth naming directories 'bluetooth' is logical, as 802.15.1
> > standard is a less known name, doesn't incorporate latest changes
> > from Bluetooth, etc.
>
> and so is IEEE 802.15.4 hence we propose using "zigbee" here. Using the
> mac80211 has historical reasons and 802.11 is a known name and even used
> on product marketing material. IEEE 802.15.4 is not. We are also using
> the term "wimax" and not its IEEE numbering.

Because you have an IEEE 802.15.4 PHY/MAC chip does not mean you want to do 
ZigBee on top of it and Dmitry explained that well. I would stick with the 
ieee802154 name here for that reason. If your drivers go in ZigBee, it means 
that your hardware implements parts of the ZigBee profiles, and that is not 
the case here.

The current Bluetooth implementation in the kernel deserves its name since 
drivers are implementing the HCI Bluetooth profile (maybe others as well), 
that is not plain IEEE 802.15.1.
-- 
Best regards, Florian Fainelli
Email : florian@openwrt.org
http://openwrt.org
-------------------------------

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: Ответ: [PATCH 10/10] ieee802154: add at86rf230/rf231 spi driver
  2009-06-02  8:36                               ` Marcel Holtmann
  2009-06-02  8:46                                 ` Florian Fainelli
@ 2009-06-02  8:49                                 ` Maxim Osipov
  2009-06-02  9:15                                     ` Holger Schurig
  2009-06-02  9:29                                   ` ?????: " Jonathan Cameron
  2009-06-02  8:52                                   ` Sergey Lapin
  2 siblings, 2 replies; 75+ messages in thread
From: Maxim Osipov @ 2009-06-02  8:49 UTC (permalink / raw)
  To: Marcel Holtmann
  Cc: Dmitry Eremin-Solenikov, Holger Schurig, linux-wireless,
	Gábor Stefanik, linux-kernel, netdev, slapin, maxim.osipov,
	dmitry.baryshkov, oliver.fendt

Hi Marcel,

On Tue, Jun 2, 2009 at 12:36 PM, Marcel Holtmann <marcel@holtmann.org> wrote:
>> For Bluetooth naming directories 'bluetooth' is logical, as 802.15.1
>> standard is a less known name, doesn't incorporate latest changes
>> from Bluetooth, etc.
>
> and so is IEEE 802.15.4 hence we propose using "zigbee" here. Using the
> mac80211 has historical reasons and 802.11 is a known name and even used
> on product marketing material. IEEE 802.15.4 is not. We are also using
> the term "wimax" and not its IEEE numbering.

Actually, ieee802154 is better in this case, because as Dmitry
mentioned, an entire family of standards is implemented on the top of
it, including:

- ZigBee
- 6LoWPAN
- ISA100.11a
- WirelessHART
 - and probably something I don't know about

All of them (once implemented) will use ieee802.15.4 drivers. It is
better to avoid future confusion and use correct terminology from the
very beginning.

Kind regards,
Maxim

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: Ответ: [PATCH 10/10] ieee802154: add at86rf230/rf231 spi driver
@ 2009-06-02  8:52                                   ` Sergey Lapin
  0 siblings, 0 replies; 75+ messages in thread
From: Sergey Lapin @ 2009-06-02  8:52 UTC (permalink / raw)
  To: Marcel Holtmann
  Cc: Dmitry Eremin-Solenikov, Holger Schurig, linux-wireless,
	Gábor Stefanik, linux-kernel, netdev, maxim.osipov,
	dmitry.baryshkov, oliver.fendt

On Tue, Jun 02, 2009 at 10:36:49AM +0200, Marcel Holtmann wrote:
> > This gonna happen, as we are most probably going to implement 6lowpan
> > on top of our stack. 6lowpan is a way to encapsulate IPv6 frames into
> > IEEE 802.15.4 and has nothing in common with ZigBee. Moreover
> > ZigBee is a trademark with strict rules upon it's usage. Our lawyers are
> > currently investigating if it's possible to use this name in projects like
> > Linux kernel which are open-source, non-related to any project but
> > OTOH can be encapsulated in any commercial project.
> > 
> > IEEE 802.15.4 is a term like IEEE 802.11. We do have mac80211,
> > we have had (until recently) ieee80211 dir, so why bother?
> > 
> > For Bluetooth naming directories 'bluetooth' is logical, as 802.15.1
> > standard is a less known name, doesn't incorporate latest changes
> > from Bluetooth, etc.
> 
> and so is IEEE 802.15.4 hence we propose using "zigbee" here. Using the
> mac80211 has historical reasons and 802.11 is a known name and even used
> on product marketing material. IEEE 802.15.4 is not. We are also using
> the term "wimax" and not its IEEE numbering.

That WILL add confusion. Because of the following:
1. IEEE 802.15.4 is layer under ZigBee. ZigBee is implemented on top of
IEEE 802.15.4, like UDP is implemented on top of IP.
2. There are hardware implementations of the following sorts:
a) Simple radio (IEEE 802.15.4 PHY).
b) IEEE 802.15.4 MAC
c) ZigBee, or other high level protocols (well, actually I don't know of
any others than ZigBee at this level, but that doesn't mean they don't
exist).

Using this stack we can implement both a) and b). With addition of
ZigBee layers, it might be possible to implement c), too. For things
like 6lowpan, only a) and b) are useful. If you call this all ZigBee,
it will add confusion and artifical limitation. Not to mention, not
true. And just for cosmetic measures. That will be a lot of trouble and
no practical gain from that.

References:
RFC-4919
RFC-4944

All the best,
S.


^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: Ответ: [PATCH 10/10] ieee802154: add at86rf230/rf231 spi driver
@ 2009-06-02  8:52                                   ` Sergey Lapin
  0 siblings, 0 replies; 75+ messages in thread
From: Sergey Lapin @ 2009-06-02  8:52 UTC (permalink / raw)
  To: Marcel Holtmann
  Cc: Dmitry Eremin-Solenikov, Holger Schurig,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA, Gábor Stefanik,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	maxim.osipov-kv7WeFo6aLtBDgjK7y7TUQ,
	dmitry.baryshkov-kv7WeFo6aLtBDgjK7y7TUQ,
	oliver.fendt-kv7WeFo6aLtBDgjK7y7TUQ

On Tue, Jun 02, 2009 at 10:36:49AM +0200, Marcel Holtmann wrote:
> > This gonna happen, as we are most probably going to implement 6lowpan
> > on top of our stack. 6lowpan is a way to encapsulate IPv6 frames into
> > IEEE 802.15.4 and has nothing in common with ZigBee. Moreover
> > ZigBee is a trademark with strict rules upon it's usage. Our lawyers are
> > currently investigating if it's possible to use this name in projects like
> > Linux kernel which are open-source, non-related to any project but
> > OTOH can be encapsulated in any commercial project.
> > 
> > IEEE 802.15.4 is a term like IEEE 802.11. We do have mac80211,
> > we have had (until recently) ieee80211 dir, so why bother?
> > 
> > For Bluetooth naming directories 'bluetooth' is logical, as 802.15.1
> > standard is a less known name, doesn't incorporate latest changes
> > from Bluetooth, etc.
> 
> and so is IEEE 802.15.4 hence we propose using "zigbee" here. Using the
> mac80211 has historical reasons and 802.11 is a known name and even used
> on product marketing material. IEEE 802.15.4 is not. We are also using
> the term "wimax" and not its IEEE numbering.

That WILL add confusion. Because of the following:
1. IEEE 802.15.4 is layer under ZigBee. ZigBee is implemented on top of
IEEE 802.15.4, like UDP is implemented on top of IP.
2. There are hardware implementations of the following sorts:
a) Simple radio (IEEE 802.15.4 PHY).
b) IEEE 802.15.4 MAC
c) ZigBee, or other high level protocols (well, actually I don't know of
any others than ZigBee at this level, but that doesn't mean they don't
exist).

Using this stack we can implement both a) and b). With addition of
ZigBee layers, it might be possible to implement c), too. For things
like 6lowpan, only a) and b) are useful. If you call this all ZigBee,
it will add confusion and artifical limitation. Not to mention, not
true. And just for cosmetic measures. That will be a lot of trouble and
no practical gain from that.

References:
RFC-4919
RFC-4944

All the best,
S.

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: Ответ: [PATCH 10/10] ieee802154: add at86rf230/rf231 spi driver
@ 2009-06-02  9:15                                     ` Holger Schurig
  0 siblings, 0 replies; 75+ messages in thread
From: Holger Schurig @ 2009-06-02  9:15 UTC (permalink / raw)
  To: maxim
  Cc: Marcel Holtmann, Dmitry Eremin-Solenikov, linux-wireless,
	Gábor Stefanik, linux-kernel, netdev, slapin, maxim.osipov,
	dmitry.baryshkov, oliver.fendt

> - ZigBee
> - 6LoWPAN
> - ISA100.11a
> - WirelessHART
>  - and probably something I don't know about

You now convinced at least me :-)

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: Ответ: [PATCH 10/10] ieee802154: add at86rf230/rf231 spi driver
@ 2009-06-02  9:15                                     ` Holger Schurig
  0 siblings, 0 replies; 75+ messages in thread
From: Holger Schurig @ 2009-06-02  9:15 UTC (permalink / raw)
  To: maxim-OiolBBqRjXA
  Cc: Marcel Holtmann, Dmitry Eremin-Solenikov,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA, Gábor Stefanik,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA, slapin-9cOl001CZnBAfugRpC6u6w,
	maxim.osipov-kv7WeFo6aLtBDgjK7y7TUQ,
	dmitry.baryshkov-kv7WeFo6aLtBDgjK7y7TUQ,
	oliver.fendt-kv7WeFo6aLtBDgjK7y7TUQ

> - ZigBee
> - 6LoWPAN
> - ISA100.11a
> - WirelessHART
>  - and probably something I don't know about

You now convinced at least me :-)
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: ?????: [PATCH 10/10] ieee802154: add at86rf230/rf231 spi driver
  2009-06-02  8:49                                 ` Maxim Osipov
  2009-06-02  9:15                                     ` Holger Schurig
@ 2009-06-02  9:29                                   ` Jonathan Cameron
  2009-06-02 11:42                                       ` Dmitry Eremin-Solenikov
  1 sibling, 1 reply; 75+ messages in thread
From: Jonathan Cameron @ 2009-06-02  9:29 UTC (permalink / raw)
  To: maxim
  Cc: Marcel Holtmann, Dmitry Eremin-Solenikov, Holger Schurig,
	linux-wireless, Gábor Stefanik, linux-kernel, netdev,
	slapin, maxim.osipov, dmitry.baryshkov, oliver.fendt

Maxim Osipov wrote:
> Hi Marcel,
> 
> On Tue, Jun 2, 2009 at 12:36 PM, Marcel Holtmann <marcel@holtmann.org> wrote:
>>> For Bluetooth naming directories 'bluetooth' is logical, as 802.15.1
>>> standard is a less known name, doesn't incorporate latest changes
>>> from Bluetooth, etc.
>> and so is IEEE 802.15.4 hence we propose using "zigbee" here. Using the
>> mac80211 has historical reasons and 802.11 is a known name and even used
>> on product marketing material. IEEE 802.15.4 is not. We are also using
>> the term "wimax" and not its IEEE numbering.
> 
> Actually, ieee802154 is better in this case, because as Dmitry
> mentioned, an entire family of standards is implemented on the top of
> it, including:
> 
> - ZigBee
> - 6LoWPAN
> - ISA100.11a
> - WirelessHART
>  - and probably something I don't know about
I'll tack on tosmac (the tinyos protocol).
The platforms I support have out of kernel support for a cc2420 (802.15.4) radio
using that protocol. In the embedded sensors field it seems to be
pretty common to use linux nodes as gateways to systems running various realtime
/ light weight OSes.

As Maxim stated there are a lot of protocols out there.

Thank you to Dmitry and co for your work on this project, I'll be following
your progress with interest (and when I have a sec adding support for the cc2420
if no one else does it first ;)

---
Jonathan Cameron

 

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: ?????: [PATCH 10/10] ieee802154: add at86rf230/rf231 spi driver
@ 2009-06-02 11:42                                       ` Dmitry Eremin-Solenikov
  0 siblings, 0 replies; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-02 11:42 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: maxim, Marcel Holtmann, Holger Schurig, linux-wireless,
	Gábor Stefanik, linux-kernel, netdev, slapin, maxim.osipov,
	dmitry.baryshkov, oliver.fendt

2009/6/2 Jonathan Cameron <jic23@cam.ac.uk>:
> Thank you to Dmitry and co for your work on this project, I'll be following
> your progress with interest (and when I have a sec adding support for the cc2420
> if no one else does it first ;)

We will be waiting with interest for these patches. We don't have the cc2420 hw
at hand, so we won't work on support for it in the foreseeble (1-3
moths :)) time.

-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: ?????: [PATCH 10/10] ieee802154: add at86rf230/rf231 spi driver
@ 2009-06-02 11:42                                       ` Dmitry Eremin-Solenikov
  0 siblings, 0 replies; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-02 11:42 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: maxim-OiolBBqRjXA, Marcel Holtmann, Holger Schurig,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA, Gábor Stefanik,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA, slapin-9cOl001CZnBAfugRpC6u6w,
	maxim.osipov-kv7WeFo6aLtBDgjK7y7TUQ,
	dmitry.baryshkov-kv7WeFo6aLtBDgjK7y7TUQ,
	oliver.fendt-kv7WeFo6aLtBDgjK7y7TUQ

2009/6/2 Jonathan Cameron <jic23-KWPb1pKIrIJaa/9Udqfwiw@public.gmane.org>:
> Thank you to Dmitry and co for your work on this project, I'll be following
> your progress with interest (and when I have a sec adding support for the cc2420
> if no one else does it first ;)

We will be waiting with interest for these patches. We don't have the cc2420 hw
at hand, so we won't work on support for it in the foreseeble (1-3
moths :)) time.

-- 
With best wishes
Dmitry
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 08/10] tty_io: export tty_class
@ 2009-06-02 14:22                         ` Dmitry Eremin-Solenikov
  0 siblings, 0 replies; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-02 14:22 UTC (permalink / raw)
  To: Alan Cox
  Cc: linux-kernel, netdev, linux-wireless, slapin, maxim.osipov,
	dmitry.baryshkov, oliver.fendt

On Mon, Jun 01, 2009 at 04:34:18PM +0100, Alan Cox wrote:
> > I used class_find_device finding the device with matching minor. Will it be
> > acceptable, if I just move this code into tty_* file and export it as
> > to modules?
> 
> Yes - create a proper tty helper function for doing the job and document
> what it does. That way if the tty layer is changed it is obvious that
> this code also needs considering.

Is this suitable:

>From bea1f7dd279119a1aa60556ff0441e31c92876aa Mon Sep 17 00:00:00 2001
From: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Date: Tue, 2 Jun 2009 06:31:35 +0400
Subject: [PATCH] tty_io: add an API to get device corresponding to tty_struct

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
---
 drivers/char/tty_io.c |   13 +++++++++++++
 include/linux/tty.h   |    1 +
 2 files changed, 14 insertions(+), 0 deletions(-)

diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 66b99a2..04d6c9a 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -3026,6 +3026,19 @@ dev_t tty_devnum(struct tty_struct *tty)
 }
 EXPORT_SYMBOL(tty_devnum);
 
+static int dev_match_devt(struct device *dev, void *data)
+{
+	dev_t *devt = data;
+	return dev->devt == *devt;
+}
+
+struct device *tty_get_device(struct tty_struct *tty)
+{
+	dev_t devt = tty_devnum(tty);
+	return class_find_device(tty_class, NULL, &devt, dev_match_devt);
+}
+EXPORT_SYMBOL(tty_get_device);
+
 void proc_clear_tty(struct task_struct *p)
 {
 	unsigned long flags;
diff --git a/include/linux/tty.h b/include/linux/tty.h
index fc39db9..d17ba1e 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -413,6 +413,7 @@ extern int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
 			unsigned int cmd, unsigned long arg);
 extern int tty_perform_flush(struct tty_struct *tty, unsigned long arg);
 extern dev_t tty_devnum(struct tty_struct *tty);
+struct device *tty_get_device(struct tty_struct *tty);
 extern void proc_clear_tty(struct task_struct *p);
 extern struct tty_struct *get_current_tty(void);
 extern void tty_default_fops(struct file_operations *fops);
-- 
1.6.3.1

-- 
With best wishes
Dmitry


^ permalink raw reply related	[flat|nested] 75+ messages in thread

* Re: [PATCH 08/10] tty_io: export tty_class
@ 2009-06-02 14:22                         ` Dmitry Eremin-Solenikov
  0 siblings, 0 replies; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-02 14:22 UTC (permalink / raw)
  To: Alan Cox
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	slapin-9cOl001CZnBAfugRpC6u6w,
	maxim.osipov-kv7WeFo6aLtBDgjK7y7TUQ,
	dmitry.baryshkov-kv7WeFo6aLtBDgjK7y7TUQ,
	oliver.fendt-kv7WeFo6aLtBDgjK7y7TUQ

On Mon, Jun 01, 2009 at 04:34:18PM +0100, Alan Cox wrote:
> > I used class_find_device finding the device with matching minor. Will it be
> > acceptable, if I just move this code into tty_* file and export it as
> > to modules?
> 
> Yes - create a proper tty helper function for doing the job and document
> what it does. That way if the tty layer is changed it is obvious that
> this code also needs considering.

Is this suitable:

>From bea1f7dd279119a1aa60556ff0441e31c92876aa Mon Sep 17 00:00:00 2001
From: Dmitry Eremin-Solenikov <dbaryshkov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Date: Tue, 2 Jun 2009 06:31:35 +0400
Subject: [PATCH] tty_io: add an API to get device corresponding to tty_struct

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 drivers/char/tty_io.c |   13 +++++++++++++
 include/linux/tty.h   |    1 +
 2 files changed, 14 insertions(+), 0 deletions(-)

diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 66b99a2..04d6c9a 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -3026,6 +3026,19 @@ dev_t tty_devnum(struct tty_struct *tty)
 }
 EXPORT_SYMBOL(tty_devnum);
 
+static int dev_match_devt(struct device *dev, void *data)
+{
+	dev_t *devt = data;
+	return dev->devt == *devt;
+}
+
+struct device *tty_get_device(struct tty_struct *tty)
+{
+	dev_t devt = tty_devnum(tty);
+	return class_find_device(tty_class, NULL, &devt, dev_match_devt);
+}
+EXPORT_SYMBOL(tty_get_device);
+
 void proc_clear_tty(struct task_struct *p)
 {
 	unsigned long flags;
diff --git a/include/linux/tty.h b/include/linux/tty.h
index fc39db9..d17ba1e 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -413,6 +413,7 @@ extern int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
 			unsigned int cmd, unsigned long arg);
 extern int tty_perform_flush(struct tty_struct *tty, unsigned long arg);
 extern dev_t tty_devnum(struct tty_struct *tty);
+struct device *tty_get_device(struct tty_struct *tty);
 extern void proc_clear_tty(struct task_struct *p);
 extern struct tty_struct *get_current_tty(void);
 extern void tty_default_fops(struct file_operations *fops);
-- 
1.6.3.1

-- 
With best wishes
Dmitry

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* Re: [PATCH 08/10] tty_io: export tty_class
  2009-06-02 14:22                         ` Dmitry Eremin-Solenikov
  (?)
@ 2009-06-02 14:35                         ` Alan Cox
  -1 siblings, 0 replies; 75+ messages in thread
From: Alan Cox @ 2009-06-02 14:35 UTC (permalink / raw)
  To: Dmitry Eremin-Solenikov
  Cc: linux-kernel, netdev, linux-wireless, slapin, maxim.osipov,
	dmitry.baryshkov, oliver.fendt

> > Yes - create a proper tty helper function for doing the job and document
> > what it does. That way if the tty layer is changed it is obvious that
> > this code also needs considering.
> 
> Is this suitable:

Perfect - add the needed documentation to the public function and submit
it for merging.

Alan

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 09/10] ieee802154: add serial dongle driver
@ 2009-06-02 14:43                           ` Sergey Lapin
  0 siblings, 0 replies; 75+ messages in thread
From: Sergey Lapin @ 2009-06-02 14:43 UTC (permalink / raw)
  To: Alan Cox
  Cc: Dmitry Eremin-Solenikov, linux-kernel, netdev, linux-wireless,
	maxim.osipov, dmitry.baryshkov, oliver.fendt

> > C&P from drivers/bluetooth/hci-ldisc.c, around line 466. We had problems
> > working with low-latency unset.
> 
> The bluetooth one needs killing too. I will do that tomorrow ...
> 
> How many releases ago - the entire tty buffering layer has been rewritten
> over time. tty->low_latency requires driver specific support that most
> don't have. Also as of 2.6.30rc you'll get debug spew if you misuse it.
> 
> If you still need it we need to know why.

As we're tested it here, we don't need tty->low_latency anymore.
So that can go away. Thanks!


^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 09/10] ieee802154: add serial dongle driver
@ 2009-06-02 14:43                           ` Sergey Lapin
  0 siblings, 0 replies; 75+ messages in thread
From: Sergey Lapin @ 2009-06-02 14:43 UTC (permalink / raw)
  To: Alan Cox
  Cc: Dmitry Eremin-Solenikov, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	maxim.osipov-kv7WeFo6aLtBDgjK7y7TUQ,
	dmitry.baryshkov-kv7WeFo6aLtBDgjK7y7TUQ,
	oliver.fendt-kv7WeFo6aLtBDgjK7y7TUQ

> > C&P from drivers/bluetooth/hci-ldisc.c, around line 466. We had problems
> > working with low-latency unset.
> 
> The bluetooth one needs killing too. I will do that tomorrow ...
> 
> How many releases ago - the entire tty buffering layer has been rewritten
> over time. tty->low_latency requires driver specific support that most
> don't have. Also as of 2.6.30rc you'll get debug spew if you misuse it.
> 
> If you still need it we need to know why.

As we're tested it here, we don't need tty->low_latency anymore.
So that can go away. Thanks!

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 01/10] crc-itu-t: add bit-reversed calculation
  2009-06-01 14:54 ` [PATCH 01/10] crc-itu-t: add bit-reversed calculation Dmitry Eremin-Solenikov
  2009-06-01 14:54   ` [PATCH 02/10] Add constants for the ieee 802.15.4/ZigBee stack Dmitry Eremin-Solenikov
@ 2009-06-04  0:05   ` Andrew Morton
  1 sibling, 0 replies; 75+ messages in thread
From: Andrew Morton @ 2009-06-04  0:05 UTC (permalink / raw)
  To: Dmitry Eremin-Solenikov
  Cc: linux-kernel, netdev, linux-wireless, slapin, maxim.osipov,
	dmitry.baryshkov, oliver.fendt, linux

On Mon,  1 Jun 2009 18:54:42 +0400
Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> wrote:

> From: Darren Salt <linux@youmustbejoking.demon.co.uk>
> 
> ..
>
>  static inline u16 crc_itu_t_byte(u16 crc, const u8 data)
>  {
>  	return (crc << 8) ^ crc_itu_t_table[((crc >> 8) ^ data) & 0xff];
>  }
>  
> +static inline u16 crc_itu_t_bitreversed_byte(u16 crc, const u8 data)
> +{
> +	return (crc << 8) ^ crc_itu_t_table[((crc >> 8) ^ bitrev8(data)) & 0xff];
> +}

I suspect that inlining these was a mistake, but one which we make often.

>  #endif /* CRC_ITU_T_H */
>  
> diff --git a/lib/crc-itu-t.c b/lib/crc-itu-t.c
> index a63472b..5562fdd 100644
> --- a/lib/crc-itu-t.c
> +++ b/lib/crc-itu-t.c
> @@ -64,6 +64,24 @@ u16 crc_itu_t(u16 crc, const u8 *buffer, size_t len)
>  }
>  EXPORT_SYMBOL(crc_itu_t);
>  
> +/**
> + * crc_itu_t_bitreversed - Compute the CRC-ITU-T for the data buffer;
> + * the buffer content is assumed to be bit-reversed

kerneldoc doesn't support the breaking of this information across
multiple lines.  It'll need to be done as a single 120-column line.


> + * @crc:     previous CRC value
> + * @buffer:  data pointer
> + * @len:     number of bytes in the buffer
> + *
> + * Returns the updated CRC value
> + */
> +u16 crc_itu_t_bitreversed(u16 crc, const u8 *buffer, size_t len)
> +{
> +	while (len--)
> +		crc = crc_itu_t_bitreversed_byte(crc, *buffer++);
> +	return crc;
> +}
> +EXPORT_SYMBOL(crc_itu_t_bitreversed);


^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 03/10] net: add IEEE 802.15.4 socket family implementation
@ 2009-06-04  0:32         ` Andrew Morton
  0 siblings, 0 replies; 75+ messages in thread
From: Andrew Morton @ 2009-06-04  0:32 UTC (permalink / raw)
  To: Dmitry Eremin-Solenikov
  Cc: linux-kernel, netdev, linux-wireless, slapin, maxim.osipov,
	dmitry.baryshkov, oliver.fendt, dbaryshkov

On Mon,  1 Jun 2009 18:54:44 +0400
Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> wrote:

> Add support for communication over IEEE 802.15.4 networks. This implementation
> is neither certified nor complete, but aims to that goal. This commit contains
> only the socket interface for communication over IEEE 802.15.4 networks.
> One can either send RAW datagrams or use SOCK_DGRAM to encapsulate data
> inside normal IEEE 802.15.4 packets.
> 
> Configuration interface, drivers and software MAC 802.15.4 implementation will
> follow.
> 
> Initial implementation was done by Maxim Gorbachyov, Maxim Osipov and Pavel
> Smolensky as a research project at Siemens AG. Later the stack was heavily
> reworked to better suit the linux networking model, and is now maitained
> as an open project partially sponsored by Siemens.
> 

Some drive-by nitpicking, and I saw a bug...

> ...
>
> +#define MAC_CB(skb)	((struct ieee802154_mac_cb *)(skb)->cb)

At present this macro can be passed a variable of any type at all.

It would be better to implement this as a (probably inlined) C
function, so the compiler can check that it was indeed passed a `struct
sk_buff *' (or whatever type it's supposed to be).

And regular C functions are typically in lower case..


I have a feeling that this unnecessary macro pattern is used in other
places in networking, and there's an argument that new code should copy
the old code.  It's not a terribly good argument, IMO - the defeating
of type-safety does rather suck.

> +#define MAC_CB_FLAG_TYPEMASK		((1 << 3) - 1)
> +
> +#define MAC_CB_FLAG_ACKREQ		(1 << 3)
> +#define MAC_CB_FLAG_SECEN		(1 << 4)
> +#define MAC_CB_FLAG_INTRAPAN		(1 << 5)
> +
> +#define MAC_CB_IS_ACKREQ(skb)		(MAC_CB(skb)->flags & MAC_CB_FLAG_ACKREQ)
> +#define MAC_CB_IS_SECEN(skb)		(MAC_CB(skb)->flags & MAC_CB_FLAG_SECEN)
> +#define MAC_CB_IS_INTRAPAN(skb)		(MAC_CB(skb)->flags & MAC_CB_FLAG_INTRAPAN)
> +#define MAC_CB_TYPE(skb)		(MAC_CB(skb)->flags & MAC_CB_FLAG_TYPEMASK)

These didn't need to be implemented as macros either.

> +#define IEEE802154_MAC_SCAN_ED		0
> +#define IEEE802154_MAC_SCAN_ACTIVE	1
> +#define IEEE802154_MAC_SCAN_PASSIVE	2
> +#define IEEE802154_MAC_SCAN_ORPHAN	3
> +
> +/*
> + * This should be located at net_device->ml_priv
> + */
> +struct ieee802154_mlme_ops {
> +	int (*assoc_req)(struct net_device *dev, struct ieee802154_addr *addr, u8 channel, u8 cap);
> +	int (*assoc_resp)(struct net_device *dev, struct ieee802154_addr *addr, u16 short_addr, u8 status);
> +	int (*disassoc_req)(struct net_device *dev, struct ieee802154_addr *addr, u8 reason);
> +	int (*start_req)(struct net_device *dev, struct ieee802154_addr *addr, u8 channel,
> +			     u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx,
> +			     u8 coord_realign);
> +	int (*scan_req)(struct net_device *dev, u8 type, u32 channels, u8 duration);
> +
> +	/*
> +	 * FIXME: these should become the part of PIB/MIB interface.
> +	 * However we still don't have IB interface of any kind
> +	 */
> +	u16 (*get_pan_id)(struct net_device *dev);
> +	u16 (*get_short_addr)(struct net_device *dev);
> +	u8 (*get_dsn)(struct net_device *dev);
> +	u8 (*get_bsn)(struct net_device *dev);
> +};
> +
> +#define IEEE802154_MLME_OPS(dev)	((struct ieee802154_mlme_ops *) dev->ml_priv)

Nor did this.

>
> ...
>
> +	int i; \
> +	pr_debug("file %s: function: %s: data: len %d:\n", __FILE__, __func__, len); \
> +	for (i = 0; i < len; i++) {\
> +		pr_debug("%02x: %02x\n", i, (data)[i]); \
> +	} \
> +}

Could perhaps use lib/hexdump.c

Will do weird things if passed a pointer whcih has type other than char*.

> +/*
> + * Utility function for families
> + */
> +struct net_device *ieee802154_get_dev(struct net *net, struct ieee802154_addr *addr)
> +{
> +	struct net_device *dev = NULL;
> +
> +	switch (addr->addr_type) {
> +	case IEEE802154_ADDR_LONG:
> +		rtnl_lock();
> +		dev = dev_getbyhwaddr(net, ARPHRD_IEEE802154, addr->hwaddr);
> +		if (dev)
> +			dev_hold(dev);
> +		rtnl_unlock();
> +		break;
> +	case IEEE802154_ADDR_SHORT:
> +		if (addr->pan_id != 0xffff && addr->short_addr != IEEE802154_ADDR_UNDEF && addr->short_addr != 0xffff) {
> +			struct net_device *tmp;
> +
> +			rtnl_lock();
> +
> +			for_each_netdev(net, tmp) {
> +				if (tmp->type == ARPHRD_IEEE802154) {
> +					if (IEEE802154_MLME_OPS(tmp)->get_pan_id(tmp) == addr->pan_id
> +					  && IEEE802154_MLME_OPS(tmp)->get_short_addr(tmp) == addr->short_addr) {

You must use very wide xterms :(

> +						dev = tmp;
> +						dev_hold(dev);
> +						break;
> +					}
> +				}
> +			}
> +
> +			rtnl_unlock();
> +		}
> +		break;
> +	default:
> +		pr_warning("Unsupported ieee802154 address type: %d\n", addr->addr_type);
> +		break;
> +	}
> +
> +	return dev;
> +}
> +
>
> ...
>
> +static int ieee802154_create(struct net *net, struct socket *sock, int protocol)
> +{
> +	struct sock *sk;
> +	int rc;
> +	struct proto *proto;
> +	const struct proto_ops *ops;
> +
> +	/* FIXME: init_net */
> +	if (net != &init_net)
> +		return -EAFNOSUPPORT;

yeah, I was going to ask about that.  What's the problem here?

> +	switch (sock->type) {
> +	case SOCK_RAW:
> +		proto = &ieee802154_raw_prot;
> +		ops = &ieee802154_raw_ops;
> +		break;
> +	case SOCK_DGRAM:
> +		proto = &ieee802154_dgram_prot;
> +		ops = &ieee802154_dgram_ops;
> +		break;
> +	default:
> +		rc = -ESOCKTNOSUPPORT;
> +		goto out;
> +	}
> +
> +	rc = -ENOMEM;
> +	sk = sk_alloc(net, PF_IEEE802154, GFP_KERNEL, proto);
> +	if (!sk)
> +		goto out;
> +	rc = 0;
> +
> +	sock->ops = ops;
> +
> +	sock_init_data(sock, sk);
> +	/* FIXME: sk->sk_destruct */

?

> +	sk->sk_family = PF_IEEE802154;
> +
> +	/* Checksums on by default */
> +	sock_set_flag(sk, SOCK_ZAPPED);
> +
> +	if (sk->sk_prot->hash)
> +		sk->sk_prot->hash(sk);
> +
> +	if (sk->sk_prot->init) {
> +		rc = sk->sk_prot->init(sk);
> +		if (rc)
> +			sk_common_release(sk);
> +	}
> +out:
> +	return rc;
> +}
> +
>
> ...
>
> +static void af_ieee802154_remove(void)

Could be __exit, althugh __exit doesn't do much (it used to be
implemented on UML and might still be).

> +{
> +	dev_remove_pack(&ieee802154_packet_type);
> +	sock_unregister(PF_IEEE802154);
> +	proto_unregister(&ieee802154_dgram_prot);
> +	proto_unregister(&ieee802154_raw_prot);
> +}
> +
> +module_init(af_ieee802154_init);
> +module_exit(af_ieee802154_remove);
>
> ...
>
> +static inline struct dgram_sock *dgram_sk(const struct sock *sk)
> +{
> +	return (struct dgram_sock *)sk;

Better to use container_of() - it's clearer and doesn't assume that
dgram_sock.sk is the first member.

> +}
>
> ...
>
> +static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len)
> +{
> +	struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr;

sigh, more casting.  Often these things can be done in ways which are
nicer to the C type system.

> +	struct dgram_sock *ro = dgram_sk(sk);
> +	int err = 0;
> +	struct net_device *dev;
> +
> +	ro->bound = 0;
> +
> +	if (len < sizeof(*addr))
> +		return -EINVAL;
> +
> +	if (addr->family != AF_IEEE802154)
> +		return -EINVAL;
> +
> +	lock_sock(sk);
> +
> +	dev = ieee802154_get_dev(sock_net(sk), &addr->addr);
> +	if (!dev) {
> +		err = -ENODEV;
> +		goto out;
> +	}
> +
> +	if (dev->type != ARPHRD_IEEE802154) {
> +		err = -ENODEV;
> +		goto out_put;
> +	}
> +
> +	memcpy(&ro->src_addr, &addr->addr, sizeof(struct ieee802154_addr));
> +
> +	ro->bound = 1;
> +out_put:
> +	dev_put(dev);
> +out:
> +	release_sock(sk);
> +
> +	return err;
> +}
> +
>
> ...
>
> +static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
> +		       size_t size)
> +{
> +	struct net_device *dev;
> +	unsigned mtu;
> +	struct sk_buff *skb;
> +	struct dgram_sock *ro = dgram_sk(sk);
> +	int err;
> +
> +	if (msg->msg_flags & MSG_OOB) {
> +		pr_debug("msg->msg_flags = 0x%x\n", msg->msg_flags);
> +		return -EOPNOTSUPP;
> +	}
> +
> +	if (!ro->bound)
> +		dev = dev_getfirstbyhwtype(sock_net(sk), ARPHRD_IEEE802154);
> +	else
> +		dev = ieee802154_get_dev(sock_net(sk), &ro->src_addr);
> +
> +	if (!dev) {
> +		pr_debug("no dev\n");
> +		return -ENXIO;
> +	}
> +	mtu = dev->mtu;
> +	pr_debug("name = %s, mtu = %u\n", dev->name, mtu);
> +
> +	skb = sock_alloc_send_skb(sk, LL_ALLOCATED_SPACE(dev) + size, msg->msg_flags & MSG_DONTWAIT,
> +				  &err);
> +	if (!skb) {
> +		dev_put(dev);
> +		return err;
> +	}
> +	skb_reserve(skb, LL_RESERVED_SPACE(dev));
> +
> +	skb_reset_network_header(skb);
> +
> +	MAC_CB(skb)->flags = IEEE802154_FC_TYPE_DATA | MAC_CB_FLAG_ACKREQ;
> +	MAC_CB(skb)->seq = IEEE802154_MLME_OPS(dev)->get_dsn(dev);
> +	err = dev_hard_header(skb, dev, ETH_P_IEEE802154, &ro->dst_addr, ro->bound ? &ro->src_addr : NULL, size);
> +	if (err < 0) {
> +		kfree_skb(skb);
> +		dev_put(dev);
> +		return err;
> +	}
> +
> +	skb_reset_mac_header(skb);
> +
> +	err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
> +	if (err < 0) {
> +		kfree_skb(skb);
> +		dev_put(dev);
> +		return err;
> +	}

It would be better to convert this function (and any similar
occurences) to the `goto foo;' unwinding approach.  The
multiple-return-statements-per-C-function is not a favoured approach. 
It leads to code duplication and it leads to bugs.

> +	if (size > mtu) {
> +		pr_debug("size = %u, mtu = %u\n", size, mtu);
> +		return -EINVAL;

See, a bug.

> +	}
> +
> +	skb->dev = dev;
> +	skb->sk  = sk;
> +	skb->protocol = htons(ETH_P_IEEE802154);
> +
> +	err = dev_queue_xmit(skb);
> +
> +	dev_put(dev);
> +
> +	if (err)
> +		return err;
> +
> +	return size;
> +}
> +
>
> ...
>
> +struct proto ieee802154_dgram_prot = {

I suspect this could/should be const.

> +	.name		= "IEEE-802.15.4-MAC",
> +	.owner		= THIS_MODULE,
> +	.obj_size	= sizeof(struct dgram_sock),
> +	.init		= dgram_init,
> +	.close		= dgram_close,
> +	.bind		= dgram_bind,
> +	.sendmsg	= dgram_sendmsg,
> +	.recvmsg	= dgram_recvmsg,
> +	.hash		= dgram_hash,
> +	.unhash		= dgram_unhash,
> +	.connect	= dgram_connect,
> +	.disconnect	= dgram_disconnect,
> +	.ioctl		= dgram_ioctl,
> +};
> +
>
> ...
>
> +struct proto ieee802154_raw_prot = {

const?

>
> ...
>


^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 03/10] net: add IEEE 802.15.4 socket family implementation
@ 2009-06-04  0:32         ` Andrew Morton
  0 siblings, 0 replies; 75+ messages in thread
From: Andrew Morton @ 2009-06-04  0:32 UTC (permalink / raw)
  To: Dmitry Eremin-Solenikov
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	slapin-9cOl001CZnBAfugRpC6u6w,
	maxim.osipov-kv7WeFo6aLtBDgjK7y7TUQ,
	dmitry.baryshkov-kv7WeFo6aLtBDgjK7y7TUQ,
	oliver.fendt-kv7WeFo6aLtBDgjK7y7TUQ,
	dbaryshkov-Re5JQEeQqe8AvxtiuMwx3w

On Mon,  1 Jun 2009 18:54:44 +0400
Dmitry Eremin-Solenikov <dbaryshkov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:

> Add support for communication over IEEE 802.15.4 networks. This implementation
> is neither certified nor complete, but aims to that goal. This commit contains
> only the socket interface for communication over IEEE 802.15.4 networks.
> One can either send RAW datagrams or use SOCK_DGRAM to encapsulate data
> inside normal IEEE 802.15.4 packets.
> 
> Configuration interface, drivers and software MAC 802.15.4 implementation will
> follow.
> 
> Initial implementation was done by Maxim Gorbachyov, Maxim Osipov and Pavel
> Smolensky as a research project at Siemens AG. Later the stack was heavily
> reworked to better suit the linux networking model, and is now maitained
> as an open project partially sponsored by Siemens.
> 

Some drive-by nitpicking, and I saw a bug...

> ...
>
> +#define MAC_CB(skb)	((struct ieee802154_mac_cb *)(skb)->cb)

At present this macro can be passed a variable of any type at all.

It would be better to implement this as a (probably inlined) C
function, so the compiler can check that it was indeed passed a `struct
sk_buff *' (or whatever type it's supposed to be).

And regular C functions are typically in lower case..


I have a feeling that this unnecessary macro pattern is used in other
places in networking, and there's an argument that new code should copy
the old code.  It's not a terribly good argument, IMO - the defeating
of type-safety does rather suck.

> +#define MAC_CB_FLAG_TYPEMASK		((1 << 3) - 1)
> +
> +#define MAC_CB_FLAG_ACKREQ		(1 << 3)
> +#define MAC_CB_FLAG_SECEN		(1 << 4)
> +#define MAC_CB_FLAG_INTRAPAN		(1 << 5)
> +
> +#define MAC_CB_IS_ACKREQ(skb)		(MAC_CB(skb)->flags & MAC_CB_FLAG_ACKREQ)
> +#define MAC_CB_IS_SECEN(skb)		(MAC_CB(skb)->flags & MAC_CB_FLAG_SECEN)
> +#define MAC_CB_IS_INTRAPAN(skb)		(MAC_CB(skb)->flags & MAC_CB_FLAG_INTRAPAN)
> +#define MAC_CB_TYPE(skb)		(MAC_CB(skb)->flags & MAC_CB_FLAG_TYPEMASK)

These didn't need to be implemented as macros either.

> +#define IEEE802154_MAC_SCAN_ED		0
> +#define IEEE802154_MAC_SCAN_ACTIVE	1
> +#define IEEE802154_MAC_SCAN_PASSIVE	2
> +#define IEEE802154_MAC_SCAN_ORPHAN	3
> +
> +/*
> + * This should be located at net_device->ml_priv
> + */
> +struct ieee802154_mlme_ops {
> +	int (*assoc_req)(struct net_device *dev, struct ieee802154_addr *addr, u8 channel, u8 cap);
> +	int (*assoc_resp)(struct net_device *dev, struct ieee802154_addr *addr, u16 short_addr, u8 status);
> +	int (*disassoc_req)(struct net_device *dev, struct ieee802154_addr *addr, u8 reason);
> +	int (*start_req)(struct net_device *dev, struct ieee802154_addr *addr, u8 channel,
> +			     u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx,
> +			     u8 coord_realign);
> +	int (*scan_req)(struct net_device *dev, u8 type, u32 channels, u8 duration);
> +
> +	/*
> +	 * FIXME: these should become the part of PIB/MIB interface.
> +	 * However we still don't have IB interface of any kind
> +	 */
> +	u16 (*get_pan_id)(struct net_device *dev);
> +	u16 (*get_short_addr)(struct net_device *dev);
> +	u8 (*get_dsn)(struct net_device *dev);
> +	u8 (*get_bsn)(struct net_device *dev);
> +};
> +
> +#define IEEE802154_MLME_OPS(dev)	((struct ieee802154_mlme_ops *) dev->ml_priv)

Nor did this.

>
> ...
>
> +	int i; \
> +	pr_debug("file %s: function: %s: data: len %d:\n", __FILE__, __func__, len); \
> +	for (i = 0; i < len; i++) {\
> +		pr_debug("%02x: %02x\n", i, (data)[i]); \
> +	} \
> +}

Could perhaps use lib/hexdump.c

Will do weird things if passed a pointer whcih has type other than char*.

> +/*
> + * Utility function for families
> + */
> +struct net_device *ieee802154_get_dev(struct net *net, struct ieee802154_addr *addr)
> +{
> +	struct net_device *dev = NULL;
> +
> +	switch (addr->addr_type) {
> +	case IEEE802154_ADDR_LONG:
> +		rtnl_lock();
> +		dev = dev_getbyhwaddr(net, ARPHRD_IEEE802154, addr->hwaddr);
> +		if (dev)
> +			dev_hold(dev);
> +		rtnl_unlock();
> +		break;
> +	case IEEE802154_ADDR_SHORT:
> +		if (addr->pan_id != 0xffff && addr->short_addr != IEEE802154_ADDR_UNDEF && addr->short_addr != 0xffff) {
> +			struct net_device *tmp;
> +
> +			rtnl_lock();
> +
> +			for_each_netdev(net, tmp) {
> +				if (tmp->type == ARPHRD_IEEE802154) {
> +					if (IEEE802154_MLME_OPS(tmp)->get_pan_id(tmp) == addr->pan_id
> +					  && IEEE802154_MLME_OPS(tmp)->get_short_addr(tmp) == addr->short_addr) {

You must use very wide xterms :(

> +						dev = tmp;
> +						dev_hold(dev);
> +						break;
> +					}
> +				}
> +			}
> +
> +			rtnl_unlock();
> +		}
> +		break;
> +	default:
> +		pr_warning("Unsupported ieee802154 address type: %d\n", addr->addr_type);
> +		break;
> +	}
> +
> +	return dev;
> +}
> +
>
> ...
>
> +static int ieee802154_create(struct net *net, struct socket *sock, int protocol)
> +{
> +	struct sock *sk;
> +	int rc;
> +	struct proto *proto;
> +	const struct proto_ops *ops;
> +
> +	/* FIXME: init_net */
> +	if (net != &init_net)
> +		return -EAFNOSUPPORT;

yeah, I was going to ask about that.  What's the problem here?

> +	switch (sock->type) {
> +	case SOCK_RAW:
> +		proto = &ieee802154_raw_prot;
> +		ops = &ieee802154_raw_ops;
> +		break;
> +	case SOCK_DGRAM:
> +		proto = &ieee802154_dgram_prot;
> +		ops = &ieee802154_dgram_ops;
> +		break;
> +	default:
> +		rc = -ESOCKTNOSUPPORT;
> +		goto out;
> +	}
> +
> +	rc = -ENOMEM;
> +	sk = sk_alloc(net, PF_IEEE802154, GFP_KERNEL, proto);
> +	if (!sk)
> +		goto out;
> +	rc = 0;
> +
> +	sock->ops = ops;
> +
> +	sock_init_data(sock, sk);
> +	/* FIXME: sk->sk_destruct */

?

> +	sk->sk_family = PF_IEEE802154;
> +
> +	/* Checksums on by default */
> +	sock_set_flag(sk, SOCK_ZAPPED);
> +
> +	if (sk->sk_prot->hash)
> +		sk->sk_prot->hash(sk);
> +
> +	if (sk->sk_prot->init) {
> +		rc = sk->sk_prot->init(sk);
> +		if (rc)
> +			sk_common_release(sk);
> +	}
> +out:
> +	return rc;
> +}
> +
>
> ...
>
> +static void af_ieee802154_remove(void)

Could be __exit, althugh __exit doesn't do much (it used to be
implemented on UML and might still be).

> +{
> +	dev_remove_pack(&ieee802154_packet_type);
> +	sock_unregister(PF_IEEE802154);
> +	proto_unregister(&ieee802154_dgram_prot);
> +	proto_unregister(&ieee802154_raw_prot);
> +}
> +
> +module_init(af_ieee802154_init);
> +module_exit(af_ieee802154_remove);
>
> ...
>
> +static inline struct dgram_sock *dgram_sk(const struct sock *sk)
> +{
> +	return (struct dgram_sock *)sk;

Better to use container_of() - it's clearer and doesn't assume that
dgram_sock.sk is the first member.

> +}
>
> ...
>
> +static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len)
> +{
> +	struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr;

sigh, more casting.  Often these things can be done in ways which are
nicer to the C type system.

> +	struct dgram_sock *ro = dgram_sk(sk);
> +	int err = 0;
> +	struct net_device *dev;
> +
> +	ro->bound = 0;
> +
> +	if (len < sizeof(*addr))
> +		return -EINVAL;
> +
> +	if (addr->family != AF_IEEE802154)
> +		return -EINVAL;
> +
> +	lock_sock(sk);
> +
> +	dev = ieee802154_get_dev(sock_net(sk), &addr->addr);
> +	if (!dev) {
> +		err = -ENODEV;
> +		goto out;
> +	}
> +
> +	if (dev->type != ARPHRD_IEEE802154) {
> +		err = -ENODEV;
> +		goto out_put;
> +	}
> +
> +	memcpy(&ro->src_addr, &addr->addr, sizeof(struct ieee802154_addr));
> +
> +	ro->bound = 1;
> +out_put:
> +	dev_put(dev);
> +out:
> +	release_sock(sk);
> +
> +	return err;
> +}
> +
>
> ...
>
> +static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
> +		       size_t size)
> +{
> +	struct net_device *dev;
> +	unsigned mtu;
> +	struct sk_buff *skb;
> +	struct dgram_sock *ro = dgram_sk(sk);
> +	int err;
> +
> +	if (msg->msg_flags & MSG_OOB) {
> +		pr_debug("msg->msg_flags = 0x%x\n", msg->msg_flags);
> +		return -EOPNOTSUPP;
> +	}
> +
> +	if (!ro->bound)
> +		dev = dev_getfirstbyhwtype(sock_net(sk), ARPHRD_IEEE802154);
> +	else
> +		dev = ieee802154_get_dev(sock_net(sk), &ro->src_addr);
> +
> +	if (!dev) {
> +		pr_debug("no dev\n");
> +		return -ENXIO;
> +	}
> +	mtu = dev->mtu;
> +	pr_debug("name = %s, mtu = %u\n", dev->name, mtu);
> +
> +	skb = sock_alloc_send_skb(sk, LL_ALLOCATED_SPACE(dev) + size, msg->msg_flags & MSG_DONTWAIT,
> +				  &err);
> +	if (!skb) {
> +		dev_put(dev);
> +		return err;
> +	}
> +	skb_reserve(skb, LL_RESERVED_SPACE(dev));
> +
> +	skb_reset_network_header(skb);
> +
> +	MAC_CB(skb)->flags = IEEE802154_FC_TYPE_DATA | MAC_CB_FLAG_ACKREQ;
> +	MAC_CB(skb)->seq = IEEE802154_MLME_OPS(dev)->get_dsn(dev);
> +	err = dev_hard_header(skb, dev, ETH_P_IEEE802154, &ro->dst_addr, ro->bound ? &ro->src_addr : NULL, size);
> +	if (err < 0) {
> +		kfree_skb(skb);
> +		dev_put(dev);
> +		return err;
> +	}
> +
> +	skb_reset_mac_header(skb);
> +
> +	err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
> +	if (err < 0) {
> +		kfree_skb(skb);
> +		dev_put(dev);
> +		return err;
> +	}

It would be better to convert this function (and any similar
occurences) to the `goto foo;' unwinding approach.  The
multiple-return-statements-per-C-function is not a favoured approach. 
It leads to code duplication and it leads to bugs.

> +	if (size > mtu) {
> +		pr_debug("size = %u, mtu = %u\n", size, mtu);
> +		return -EINVAL;

See, a bug.

> +	}
> +
> +	skb->dev = dev;
> +	skb->sk  = sk;
> +	skb->protocol = htons(ETH_P_IEEE802154);
> +
> +	err = dev_queue_xmit(skb);
> +
> +	dev_put(dev);
> +
> +	if (err)
> +		return err;
> +
> +	return size;
> +}
> +
>
> ...
>
> +struct proto ieee802154_dgram_prot = {

I suspect this could/should be const.

> +	.name		= "IEEE-802.15.4-MAC",
> +	.owner		= THIS_MODULE,
> +	.obj_size	= sizeof(struct dgram_sock),
> +	.init		= dgram_init,
> +	.close		= dgram_close,
> +	.bind		= dgram_bind,
> +	.sendmsg	= dgram_sendmsg,
> +	.recvmsg	= dgram_recvmsg,
> +	.hash		= dgram_hash,
> +	.unhash		= dgram_unhash,
> +	.connect	= dgram_connect,
> +	.disconnect	= dgram_disconnect,
> +	.ioctl		= dgram_ioctl,
> +};
> +
>
> ...
>
> +struct proto ieee802154_raw_prot = {

const?

>
> ...
>

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 03/10] net: add IEEE 802.15.4 socket family implementation
@ 2009-06-04 11:16           ` Dmitry Eremin-Solenikov
  0 siblings, 0 replies; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-04 11:16 UTC (permalink / raw)
  To: Andrew Morton
  Cc: linux-kernel, netdev, linux-wireless, slapin, maxim.osipov,
	dmitry.baryshkov, oliver.fendt

On Wed, Jun 03, 2009 at 05:32:14PM -0700, Andrew Morton wrote:
> On Mon,  1 Jun 2009 18:54:44 +0400
> Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> wrote:
> 
> > Add support for communication over IEEE 802.15.4 networks. This implementation
> > is neither certified nor complete, but aims to that goal. This commit contains
> > only the socket interface for communication over IEEE 802.15.4 networks.
> > One can either send RAW datagrams or use SOCK_DGRAM to encapsulate data
> > inside normal IEEE 802.15.4 packets.
> > 
> > Configuration interface, drivers and software MAC 802.15.4 implementation will
> > follow.
> > 
> > Initial implementation was done by Maxim Gorbachyov, Maxim Osipov and Pavel
> > Smolensky as a research project at Siemens AG. Later the stack was heavily
> > reworked to better suit the linux networking model, and is now maitained
> > as an open project partially sponsored by Siemens.
> > 
> 
> Some drive-by nitpicking, and I saw a bug...
> 
> > +	switch (addr->addr_type) {
> > +	case IEEE802154_ADDR_LONG:
> > +		rtnl_lock();
> > +		dev = dev_getbyhwaddr(net, ARPHRD_IEEE802154, addr->hwaddr);
> > +		if (dev)
> > +			dev_hold(dev);
> > +		rtnl_unlock();
> > +		break;
> > +	case IEEE802154_ADDR_SHORT:
> > +		if (addr->pan_id != 0xffff && addr->short_addr != IEEE802154_ADDR_UNDEF && addr->short_addr != 0xffff) {
> > +			struct net_device *tmp;
> > +
> > +			rtnl_lock();
> > +
> > +			for_each_netdev(net, tmp) {
> > +				if (tmp->type == ARPHRD_IEEE802154) {
> > +					if (IEEE802154_MLME_OPS(tmp)->get_pan_id(tmp) == addr->pan_id
> > +					  && IEEE802154_MLME_OPS(tmp)->get_short_addr(tmp) == addr->short_addr) {
> 
> You must use very wide xterms :(

~120 chars in width :)  We prefer to have a single code line split between
several screen lines, rather than split it manually in some weird places
just to justify width of 80 chars.

> 
> > +						dev = tmp;
> > +						dev_hold(dev);
> > +						break;
> > +					}
> > +				}
> > +			}
> > +
> > +			rtnl_unlock();
> > +		}
> > +		break;
> > +	default:
> > +		pr_warning("Unsupported ieee802154 address type: %d\n", addr->addr_type);
> > +		break;
> > +	}
> > +
> > +	return dev;
> > +}
> > +
> >
> > ...
> >
> > +static int ieee802154_create(struct net *net, struct socket *sock, int protocol)
> > +{
> > +	struct sock *sk;
> > +	int rc;
> > +	struct proto *proto;
> > +	const struct proto_ops *ops;
> > +
> > +	/* FIXME: init_net */
> > +	if (net != &init_net)
> > +		return -EAFNOSUPPORT;
> 
> yeah, I was going to ask about that.  What's the problem here?

The FIXME was dedicated to the fact that I didn't understand what is
this. The code fragment is c&p from lots of examples of similar code
(check can, appletalk, etc. for example)

> > +	switch (sock->type) {
> > +	case SOCK_RAW:
> > +		proto = &ieee802154_raw_prot;
> > +		ops = &ieee802154_raw_ops;
> > +		break;
> > +	case SOCK_DGRAM:
> > +		proto = &ieee802154_dgram_prot;
> > +		ops = &ieee802154_dgram_ops;
> > +		break;
> > +	default:
> > +		rc = -ESOCKTNOSUPPORT;
> > +		goto out;
> > +	}
> > +
> > +	rc = -ENOMEM;
> > +	sk = sk_alloc(net, PF_IEEE802154, GFP_KERNEL, proto);
> > +	if (!sk)
> > +		goto out;
> > +	rc = 0;
> > +
> > +	sock->ops = ops;
> > +
> > +	sock_init_data(sock, sk);
> > +	/* FIXME: sk->sk_destruct */
> 
> ?

Oh... I nearly forgot about this. When writing this code, I examined
several existing address families. Usually (but not always) the sk_destruct
callback will purge sk_receive_queue and sk_write_queue. However I
didn't understand why and in which case should these queues (or others)
be purged. Could please one clarify this?

> > ...
> >
> > +static void af_ieee802154_remove(void)
> 
> Could be __exit, althugh __exit doesn't do much (it used to be
> implemented on UML and might still be).

Added. BTW: I thought, that __exit functions aren't added to (or are
stripped from) the final vmlinux image. Am I wrong?

> >
> > +static inline struct dgram_sock *dgram_sk(const struct sock *sk)
> > +{
> > +	return (struct dgram_sock *)sk;
> 
> Better to use container_of() - it's clearer and doesn't assume that
> dgram_sock.sk is the first member.

Fixed.

> > +}
> >
> > ...
> >
> > +static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len)
> > +{
> > +	struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr;
> 
> sigh, more casting.  Often these things can be done in ways which are
> nicer to the C type system.

Unfortunately sockaddr things can't be done in a more clean way IMO.

> > +	struct dgram_sock *ro = dgram_sk(sk);
> > +	int err = 0;
> > +	struct net_device *dev;
> > +
> > +	ro->bound = 0;
> > +

> > ...
> >
> > +struct proto ieee802154_dgram_prot = {
> 
> I suspect this could/should be const.

No. proto_register changes the passed protocol struct during
registration.

> 
> > +	.name		= "IEEE-802.15.4-MAC",
> > +	.owner		= THIS_MODULE,
> > +	.obj_size	= sizeof(struct dgram_sock),
> > +	.init		= dgram_init,
> > +	.close		= dgram_close,
> > +	.bind		= dgram_bind,
> > +	.sendmsg	= dgram_sendmsg,
> > +	.recvmsg	= dgram_recvmsg,
> > +	.hash		= dgram_hash,
> > +	.unhash		= dgram_unhash,
> > +	.connect	= dgram_connect,
> > +	.disconnect	= dgram_disconnect,
> > +	.ioctl		= dgram_ioctl,
> > +};
> > +

-- 
With best wishes
Dmitry


^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 03/10] net: add IEEE 802.15.4 socket family implementation
@ 2009-06-04 11:16           ` Dmitry Eremin-Solenikov
  0 siblings, 0 replies; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-04 11:16 UTC (permalink / raw)
  To: Andrew Morton
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	slapin-9cOl001CZnBAfugRpC6u6w,
	maxim.osipov-kv7WeFo6aLtBDgjK7y7TUQ,
	dmitry.baryshkov-kv7WeFo6aLtBDgjK7y7TUQ,
	oliver.fendt-kv7WeFo6aLtBDgjK7y7TUQ

On Wed, Jun 03, 2009 at 05:32:14PM -0700, Andrew Morton wrote:
> On Mon,  1 Jun 2009 18:54:44 +0400
> Dmitry Eremin-Solenikov <dbaryshkov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> 
> > Add support for communication over IEEE 802.15.4 networks. This implementation
> > is neither certified nor complete, but aims to that goal. This commit contains
> > only the socket interface for communication over IEEE 802.15.4 networks.
> > One can either send RAW datagrams or use SOCK_DGRAM to encapsulate data
> > inside normal IEEE 802.15.4 packets.
> > 
> > Configuration interface, drivers and software MAC 802.15.4 implementation will
> > follow.
> > 
> > Initial implementation was done by Maxim Gorbachyov, Maxim Osipov and Pavel
> > Smolensky as a research project at Siemens AG. Later the stack was heavily
> > reworked to better suit the linux networking model, and is now maitained
> > as an open project partially sponsored by Siemens.
> > 
> 
> Some drive-by nitpicking, and I saw a bug...
> 
> > +	switch (addr->addr_type) {
> > +	case IEEE802154_ADDR_LONG:
> > +		rtnl_lock();
> > +		dev = dev_getbyhwaddr(net, ARPHRD_IEEE802154, addr->hwaddr);
> > +		if (dev)
> > +			dev_hold(dev);
> > +		rtnl_unlock();
> > +		break;
> > +	case IEEE802154_ADDR_SHORT:
> > +		if (addr->pan_id != 0xffff && addr->short_addr != IEEE802154_ADDR_UNDEF && addr->short_addr != 0xffff) {
> > +			struct net_device *tmp;
> > +
> > +			rtnl_lock();
> > +
> > +			for_each_netdev(net, tmp) {
> > +				if (tmp->type == ARPHRD_IEEE802154) {
> > +					if (IEEE802154_MLME_OPS(tmp)->get_pan_id(tmp) == addr->pan_id
> > +					  && IEEE802154_MLME_OPS(tmp)->get_short_addr(tmp) == addr->short_addr) {
> 
> You must use very wide xterms :(

~120 chars in width :)  We prefer to have a single code line split between
several screen lines, rather than split it manually in some weird places
just to justify width of 80 chars.

> 
> > +						dev = tmp;
> > +						dev_hold(dev);
> > +						break;
> > +					}
> > +				}
> > +			}
> > +
> > +			rtnl_unlock();
> > +		}
> > +		break;
> > +	default:
> > +		pr_warning("Unsupported ieee802154 address type: %d\n", addr->addr_type);
> > +		break;
> > +	}
> > +
> > +	return dev;
> > +}
> > +
> >
> > ...
> >
> > +static int ieee802154_create(struct net *net, struct socket *sock, int protocol)
> > +{
> > +	struct sock *sk;
> > +	int rc;
> > +	struct proto *proto;
> > +	const struct proto_ops *ops;
> > +
> > +	/* FIXME: init_net */
> > +	if (net != &init_net)
> > +		return -EAFNOSUPPORT;
> 
> yeah, I was going to ask about that.  What's the problem here?

The FIXME was dedicated to the fact that I didn't understand what is
this. The code fragment is c&p from lots of examples of similar code
(check can, appletalk, etc. for example)

> > +	switch (sock->type) {
> > +	case SOCK_RAW:
> > +		proto = &ieee802154_raw_prot;
> > +		ops = &ieee802154_raw_ops;
> > +		break;
> > +	case SOCK_DGRAM:
> > +		proto = &ieee802154_dgram_prot;
> > +		ops = &ieee802154_dgram_ops;
> > +		break;
> > +	default:
> > +		rc = -ESOCKTNOSUPPORT;
> > +		goto out;
> > +	}
> > +
> > +	rc = -ENOMEM;
> > +	sk = sk_alloc(net, PF_IEEE802154, GFP_KERNEL, proto);
> > +	if (!sk)
> > +		goto out;
> > +	rc = 0;
> > +
> > +	sock->ops = ops;
> > +
> > +	sock_init_data(sock, sk);
> > +	/* FIXME: sk->sk_destruct */
> 
> ?

Oh... I nearly forgot about this. When writing this code, I examined
several existing address families. Usually (but not always) the sk_destruct
callback will purge sk_receive_queue and sk_write_queue. However I
didn't understand why and in which case should these queues (or others)
be purged. Could please one clarify this?

> > ...
> >
> > +static void af_ieee802154_remove(void)
> 
> Could be __exit, althugh __exit doesn't do much (it used to be
> implemented on UML and might still be).

Added. BTW: I thought, that __exit functions aren't added to (or are
stripped from) the final vmlinux image. Am I wrong?

> >
> > +static inline struct dgram_sock *dgram_sk(const struct sock *sk)
> > +{
> > +	return (struct dgram_sock *)sk;
> 
> Better to use container_of() - it's clearer and doesn't assume that
> dgram_sock.sk is the first member.

Fixed.

> > +}
> >
> > ...
> >
> > +static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len)
> > +{
> > +	struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr;
> 
> sigh, more casting.  Often these things can be done in ways which are
> nicer to the C type system.

Unfortunately sockaddr things can't be done in a more clean way IMO.

> > +	struct dgram_sock *ro = dgram_sk(sk);
> > +	int err = 0;
> > +	struct net_device *dev;
> > +
> > +	ro->bound = 0;
> > +

> > ...
> >
> > +struct proto ieee802154_dgram_prot = {
> 
> I suspect this could/should be const.

No. proto_register changes the passed protocol struct during
registration.

> 
> > +	.name		= "IEEE-802.15.4-MAC",
> > +	.owner		= THIS_MODULE,
> > +	.obj_size	= sizeof(struct dgram_sock),
> > +	.init		= dgram_init,
> > +	.close		= dgram_close,
> > +	.bind		= dgram_bind,
> > +	.sendmsg	= dgram_sendmsg,
> > +	.recvmsg	= dgram_recvmsg,
> > +	.hash		= dgram_hash,
> > +	.unhash		= dgram_unhash,
> > +	.connect	= dgram_connect,
> > +	.disconnect	= dgram_disconnect,
> > +	.ioctl		= dgram_ioctl,
> > +};
> > +

-- 
With best wishes
Dmitry

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 03/10] net: add IEEE 802.15.4 socket family implementation
@ 2009-06-04 13:46             ` John W. Linville
  0 siblings, 0 replies; 75+ messages in thread
From: John W. Linville @ 2009-06-04 13:46 UTC (permalink / raw)
  To: Dmitry Eremin-Solenikov
  Cc: Andrew Morton, linux-kernel, netdev, linux-wireless, slapin,
	maxim.osipov, dmitry.baryshkov, oliver.fendt

On Thu, Jun 04, 2009 at 03:16:34PM +0400, Dmitry Eremin-Solenikov wrote:
> On Wed, Jun 03, 2009 at 05:32:14PM -0700, Andrew Morton wrote:
> > On Mon,  1 Jun 2009 18:54:44 +0400
> > Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> wrote:

> > > +	switch (addr->addr_type) {
> > > +	case IEEE802154_ADDR_LONG:
> > > +		rtnl_lock();
> > > +		dev = dev_getbyhwaddr(net, ARPHRD_IEEE802154, addr->hwaddr);
> > > +		if (dev)
> > > +			dev_hold(dev);
> > > +		rtnl_unlock();
> > > +		break;
> > > +	case IEEE802154_ADDR_SHORT:
> > > +		if (addr->pan_id != 0xffff && addr->short_addr != IEEE802154_ADDR_UNDEF && addr->short_addr != 0xffff) {
> > > +			struct net_device *tmp;
> > > +
> > > +			rtnl_lock();
> > > +
> > > +			for_each_netdev(net, tmp) {
> > > +				if (tmp->type == ARPHRD_IEEE802154) {
> > > +					if (IEEE802154_MLME_OPS(tmp)->get_pan_id(tmp) == addr->pan_id
> > > +					  && IEEE802154_MLME_OPS(tmp)->get_short_addr(tmp) == addr->short_addr) {
> > 
> > You must use very wide xterms :(
> 
> ~120 chars in width :)  We prefer to have a single code line split between
> several screen lines, rather than split it manually in some weird places
> just to justify width of 80 chars.

Hopefully you realize that many find this difficult to read -- I just
can't spread my eyes far enough to comprehend the lines.

80 chars is not a hard limit, but it is a good goal.  120 is too wide.

John
-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 03/10] net: add IEEE 802.15.4 socket family implementation
@ 2009-06-04 13:46             ` John W. Linville
  0 siblings, 0 replies; 75+ messages in thread
From: John W. Linville @ 2009-06-04 13:46 UTC (permalink / raw)
  To: Dmitry Eremin-Solenikov
  Cc: Andrew Morton, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	slapin-9cOl001CZnBAfugRpC6u6w,
	maxim.osipov-kv7WeFo6aLtBDgjK7y7TUQ,
	dmitry.baryshkov-kv7WeFo6aLtBDgjK7y7TUQ,
	oliver.fendt-kv7WeFo6aLtBDgjK7y7TUQ

On Thu, Jun 04, 2009 at 03:16:34PM +0400, Dmitry Eremin-Solenikov wrote:
> On Wed, Jun 03, 2009 at 05:32:14PM -0700, Andrew Morton wrote:
> > On Mon,  1 Jun 2009 18:54:44 +0400
> > Dmitry Eremin-Solenikov <dbaryshkov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:

> > > +	switch (addr->addr_type) {
> > > +	case IEEE802154_ADDR_LONG:
> > > +		rtnl_lock();
> > > +		dev = dev_getbyhwaddr(net, ARPHRD_IEEE802154, addr->hwaddr);
> > > +		if (dev)
> > > +			dev_hold(dev);
> > > +		rtnl_unlock();
> > > +		break;
> > > +	case IEEE802154_ADDR_SHORT:
> > > +		if (addr->pan_id != 0xffff && addr->short_addr != IEEE802154_ADDR_UNDEF && addr->short_addr != 0xffff) {
> > > +			struct net_device *tmp;
> > > +
> > > +			rtnl_lock();
> > > +
> > > +			for_each_netdev(net, tmp) {
> > > +				if (tmp->type == ARPHRD_IEEE802154) {
> > > +					if (IEEE802154_MLME_OPS(tmp)->get_pan_id(tmp) == addr->pan_id
> > > +					  && IEEE802154_MLME_OPS(tmp)->get_short_addr(tmp) == addr->short_addr) {
> > 
> > You must use very wide xterms :(
> 
> ~120 chars in width :)  We prefer to have a single code line split between
> several screen lines, rather than split it manually in some weird places
> just to justify width of 80 chars.

Hopefully you realize that many find this difficult to read -- I just
can't spread my eyes far enough to comprehend the lines.

80 chars is not a hard limit, but it is a good goal.  120 is too wide.

John
-- 
John W. Linville		Someday the world will need a hero, and you
linville-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org			might be all we have.  Be ready.
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 03/10] net: add IEEE 802.15.4 socket family implementation
@ 2009-06-04 14:10               ` Dmitry Eremin-Solenikov
  0 siblings, 0 replies; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-04 14:10 UTC (permalink / raw)
  To: John W. Linville
  Cc: Andrew Morton, linux-kernel, netdev, linux-wireless, slapin,
	maxim.osipov, dmitry.baryshkov, oliver.fendt

2009/6/4 John W. Linville <linville@tuxdriver.com>:
> On Thu, Jun 04, 2009 at 03:16:34PM +0400, Dmitry Eremin-Solenikov wrote:
>> On Wed, Jun 03, 2009 at 05:32:14PM -0700, Andrew Morton wrote:
>> > On Mon,  1 Jun 2009 18:54:44 +0400
>> > Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> wrote:
>
>> > > + switch (addr->addr_type) {
>> > > + case IEEE802154_ADDR_LONG:
>> > > +         rtnl_lock();
>> > > +         dev = dev_getbyhwaddr(net, ARPHRD_IEEE802154, addr->hwaddr);
>> > > +         if (dev)
>> > > +                 dev_hold(dev);
>> > > +         rtnl_unlock();
>> > > +         break;
>> > > + case IEEE802154_ADDR_SHORT:
>> > > +         if (addr->pan_id != 0xffff && addr->short_addr != IEEE802154_ADDR_UNDEF && addr->short_addr != 0xffff) {
>> > > +                 struct net_device *tmp;
>> > > +
>> > > +                 rtnl_lock();
>> > > +
>> > > +                 for_each_netdev(net, tmp) {
>> > > +                         if (tmp->type == ARPHRD_IEEE802154) {
>> > > +                                 if (IEEE802154_MLME_OPS(tmp)->get_pan_id(tmp) == addr->pan_id
>> > > +                                   && IEEE802154_MLME_OPS(tmp)->get_short_addr(tmp) == addr->short_addr) {
>> >
>> > You must use very wide xterms :(
>>
>> ~120 chars in width :)  We prefer to have a single code line split between
>> several screen lines, rather than split it manually in some weird places
>> just to justify width of 80 chars.
>
> Hopefully you realize that many find this difficult to read -- I just
> can't spread my eyes far enough to comprehend the lines.
>
> 80 chars is not a hard limit, but it is a good goal.  120 is too wide.

We do try to fit the lines into 80 chars, but when that seems logical.
I strongly dislike breaking comparations between lines.

-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 03/10] net: add IEEE 802.15.4 socket family implementation
@ 2009-06-04 14:10               ` Dmitry Eremin-Solenikov
  0 siblings, 0 replies; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-04 14:10 UTC (permalink / raw)
  To: John W. Linville
  Cc: Andrew Morton, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	slapin-9cOl001CZnBAfugRpC6u6w,
	maxim.osipov-kv7WeFo6aLtBDgjK7y7TUQ,
	dmitry.baryshkov-kv7WeFo6aLtBDgjK7y7TUQ,
	oliver.fendt-kv7WeFo6aLtBDgjK7y7TUQ

2009/6/4 John W. Linville <linville-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org>:
> On Thu, Jun 04, 2009 at 03:16:34PM +0400, Dmitry Eremin-Solenikov wrote:
>> On Wed, Jun 03, 2009 at 05:32:14PM -0700, Andrew Morton wrote:
>> > On Mon,  1 Jun 2009 18:54:44 +0400
>> > Dmitry Eremin-Solenikov <dbaryshkov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>
>> > > + switch (addr->addr_type) {
>> > > + case IEEE802154_ADDR_LONG:
>> > > +         rtnl_lock();
>> > > +         dev = dev_getbyhwaddr(net, ARPHRD_IEEE802154, addr->hwaddr);
>> > > +         if (dev)
>> > > +                 dev_hold(dev);
>> > > +         rtnl_unlock();
>> > > +         break;
>> > > + case IEEE802154_ADDR_SHORT:
>> > > +         if (addr->pan_id != 0xffff && addr->short_addr != IEEE802154_ADDR_UNDEF && addr->short_addr != 0xffff) {
>> > > +                 struct net_device *tmp;
>> > > +
>> > > +                 rtnl_lock();
>> > > +
>> > > +                 for_each_netdev(net, tmp) {
>> > > +                         if (tmp->type == ARPHRD_IEEE802154) {
>> > > +                                 if (IEEE802154_MLME_OPS(tmp)->get_pan_id(tmp) == addr->pan_id
>> > > +                                   && IEEE802154_MLME_OPS(tmp)->get_short_addr(tmp) == addr->short_addr) {
>> >
>> > You must use very wide xterms :(
>>
>> ~120 chars in width :)  We prefer to have a single code line split between
>> several screen lines, rather than split it manually in some weird places
>> just to justify width of 80 chars.
>
> Hopefully you realize that many find this difficult to read -- I just
> can't spread my eyes far enough to comprehend the lines.
>
> 80 chars is not a hard limit, but it is a good goal.  120 is too wide.

We do try to fit the lines into 80 chars, but when that seems logical.
I strongly dislike breaking comparations between lines.

-- 
With best wishes
Dmitry
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 03/10] net: add IEEE 802.15.4 socket family implementation
@ 2009-06-04 14:15                 ` Johannes Berg
  0 siblings, 0 replies; 75+ messages in thread
From: Johannes Berg @ 2009-06-04 14:15 UTC (permalink / raw)
  To: Dmitry Eremin-Solenikov
  Cc: John W. Linville, Andrew Morton, linux-kernel, netdev,
	linux-wireless, slapin, maxim.osipov, dmitry.baryshkov,
	oliver.fendt

[-- Attachment #1: Type: text/plain, Size: 610 bytes --]

On Thu, 2009-06-04 at 18:10 +0400, Dmitry Eremin-Solenikov wrote:

> We do try to fit the lines into 80 chars, but when that seems logical.
> I strongly dislike breaking comparations between lines.

There are a whole bunch of improvements possible at this particular
spot:

switch (X) {
case Y:
	if (A) {
		...
	}
	break;
...
}

can be written as

switch (X) {
case Y:
	if (!A)
		break;
	...
	break;
}


and 

for (...) {
	if (A) {
		...
		break;
	}
}

can be written as

for (...) {
	if (!A)
		continue;
	...
	break;
}

etc.

Show some creativity!

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 03/10] net: add IEEE 802.15.4 socket family implementation
@ 2009-06-04 14:15                 ` Johannes Berg
  0 siblings, 0 replies; 75+ messages in thread
From: Johannes Berg @ 2009-06-04 14:15 UTC (permalink / raw)
  To: Dmitry Eremin-Solenikov
  Cc: John W. Linville, Andrew Morton,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	slapin-9cOl001CZnBAfugRpC6u6w,
	maxim.osipov-kv7WeFo6aLtBDgjK7y7TUQ,
	dmitry.baryshkov-kv7WeFo6aLtBDgjK7y7TUQ,
	oliver.fendt-kv7WeFo6aLtBDgjK7y7TUQ

[-- Attachment #1: Type: text/plain, Size: 610 bytes --]

On Thu, 2009-06-04 at 18:10 +0400, Dmitry Eremin-Solenikov wrote:

> We do try to fit the lines into 80 chars, but when that seems logical.
> I strongly dislike breaking comparations between lines.

There are a whole bunch of improvements possible at this particular
spot:

switch (X) {
case Y:
	if (A) {
		...
	}
	break;
...
}

can be written as

switch (X) {
case Y:
	if (!A)
		break;
	...
	break;
}


and 

for (...) {
	if (A) {
		...
		break;
	}
}

can be written as

for (...) {
	if (!A)
		continue;
	...
	break;
}

etc.

Show some creativity!

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [RFC][WIP] IEEE 802.15.4 implementation for Linux v1
  2009-06-01 14:54 ` Dmitry Eremin-Solenikov
  (?)
  (?)
@ 2009-06-05  4:03 ` Jon Smirl
  2009-06-05  4:49     ` Dmitry Eremin-Solenikov
  -1 siblings, 1 reply; 75+ messages in thread
From: Jon Smirl @ 2009-06-05  4:03 UTC (permalink / raw)
  To: Dmitry Eremin-Solenikov
  Cc: linux-kernel, netdev, linux-wireless, slapin, maxim.osipov,
	dmitry.baryshkov, oliver.fendt

On Mon, Jun 1, 2009 at 10:54 AM, Dmitry
Eremin-Solenikov<dbaryshkov@gmail.com> wrote:
> Hi,
>
> As a part of research activities the Embedded Systems - Open Platform Group
> from Siemens Corporate Technology we are working on adding support for
> the IEEE 802.15.4 Wireless Personal Area Networks to the Linux. Our current
> implementation is neither certified nor even feature complete. However
> we'd like to present current state of our patchset to the Linux developers
> community to gain comments, fixes, ideas, etc. This is not yet a pull request,
> but more like an RFC.

Does this stack work with the Atmel USB version of at86rf230?
ATAVRRZUSBSTICK, http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4396

It's not so simple to plug in the at86rf230 using SPI. Supporting USB
sticks lets you develop on a desktop PC.

freaklabs.org is using ATAVRRZUSBSTICK


>
> The project page is available at http://apps.sourceforge.net/trac/linux-zigbee
> with source code of kernel part available from git at
> http://zigbee-linux.git.sourceforge.net, mirrored for convenience at
> git://git.kernel.org/pub/scm/linux/kernel/git/lumag/lowpan.git
>
> The source code for userspace utils is available from git at
> http://linux-zigbee.git.sourceforge.net/
>
> Changes since previous RFC:
>  * Split the code into socket family, netlink interface and separate
>    MAC 802.15.4 implementation.
>  * Add a sample driver for devices implementing mac level of IEEE 802.15.4
>    on their own.
>  * Major cleanup of public interfaces.
>  * Drop our CRC implementation and use a variant of CRC-ITU-T one
>  * Add preliminary version of AT86RF231 Atmel chip driver
>
> The following changes since commit 59a3759d0fe8d969888c741bb33f4946e4d3750d:
>  Linus Torvalds (1):
>        Linux 2.6.30-rc7
>
> are available in the git repository at:
>
>  git://git.kernel.org/pub/scm/linux/kernel/git/lumag/lowpan.git for-review-v1
>
> Darren Salt (1):
>      crc-itu-t: add bit-reversed calculation
>
> Dmitry Eremin-Solenikov (9):
>      Add constants for the ieee 802.15.4/ZigBee stack
>      net: add IEEE 802.15.4 socket family implementation
>      net: add NL802154 interface for configuration of 802.15.4 devices
>      ieee802154: add simple HardMAC driver sample
>      mac802154: add a software MAC 802.15.4 implementation
>      ieee802154: add virtual loopback driver
>      tty_io: export tty_class
>      ieee802154: add serial dongle driver
>      ieee802154: add at86rf230/rf231 spi driver
>
>  drivers/Makefile                       |    1 +
>  drivers/char/tty_io.c                  |    1 +
>  drivers/ieee802154/Kconfig             |   42 ++
>  drivers/ieee802154/Makefile            |    6 +
>  drivers/ieee802154/at86rf230.c         |  971 +++++++++++++++++++++++++++++++
>  drivers/ieee802154/fakehard.c          |  253 ++++++++
>  drivers/ieee802154/fakelb.c            |  335 +++++++++++
>  drivers/ieee802154/serial.c            |  999 ++++++++++++++++++++++++++++++++
>  drivers/net/Kconfig                    |    2 +
>  include/linux/crc-itu-t.h              |   10 +
>  include/linux/if.h                     |    2 +
>  include/linux/if_arp.h                 |    2 +
>  include/linux/if_ether.h               |    2 +
>  include/linux/socket.h                 |    6 +-
>  include/linux/spi/at86rf230.h          |   32 +
>  include/linux/tty.h                    |    3 +-
>  include/net/ieee802154/af_ieee802154.h |   60 ++
>  include/net/ieee802154/mac802154.h     |   79 +++
>  include/net/ieee802154/mac_def.h       |  158 +++++
>  include/net/ieee802154/netdevice.h     |   84 +++
>  include/net/ieee802154/nl802154.h      |  165 ++++++
>  lib/crc-itu-t.c                        |   18 +
>  net/Kconfig                            |    2 +
>  net/Makefile                           |    2 +
>  net/core/dev.c                         |    6 +-
>  net/core/sock.c                        |    3 +
>  net/ieee802154/Kconfig                 |   12 +
>  net/ieee802154/Makefile                |    5 +
>  net/ieee802154/af802154.h              |   35 ++
>  net/ieee802154/af_ieee802154.c         |  356 ++++++++++++
>  net/ieee802154/dgram.c                 |  373 ++++++++++++
>  net/ieee802154/netlink.c               |  485 ++++++++++++++++
>  net/ieee802154/raw.c                   |  250 ++++++++
>  net/mac802154/Kconfig                  |   13 +
>  net/mac802154/Makefile                 |    5 +
>  net/mac802154/beacon.c                 |  242 ++++++++
>  net/mac802154/beacon.h                 |   48 ++
>  net/mac802154/beacon_hash.c            |  103 ++++
>  net/mac802154/beacon_hash.h            |   40 ++
>  net/mac802154/dev.c                    |  843 +++++++++++++++++++++++++++
>  net/mac802154/mac802154.h              |   64 ++
>  net/mac802154/mac_cmd.c                |  325 +++++++++++
>  net/mac802154/main.c                   |   96 +++
>  net/mac802154/mdev.c                   |  283 +++++++++
>  net/mac802154/mib.h                    |   32 +
>  net/mac802154/pib.c                    |   87 +++
>  net/mac802154/pib.h                    |   35 ++
>  net/mac802154/scan.c                   |  215 +++++++
>  48 files changed, 7187 insertions(+), 4 deletions(-)
>  create mode 100644 drivers/ieee802154/Kconfig
>  create mode 100644 drivers/ieee802154/Makefile
>  create mode 100644 drivers/ieee802154/at86rf230.c
>  create mode 100644 drivers/ieee802154/fakehard.c
>  create mode 100644 drivers/ieee802154/fakelb.c
>  create mode 100644 drivers/ieee802154/serial.c
>  create mode 100644 include/linux/spi/at86rf230.h
>  create mode 100644 include/net/ieee802154/af_ieee802154.h
>  create mode 100644 include/net/ieee802154/mac802154.h
>  create mode 100644 include/net/ieee802154/mac_def.h
>  create mode 100644 include/net/ieee802154/netdevice.h
>  create mode 100644 include/net/ieee802154/nl802154.h
>  create mode 100644 net/ieee802154/Kconfig
>  create mode 100644 net/ieee802154/Makefile
>  create mode 100644 net/ieee802154/af802154.h
>  create mode 100644 net/ieee802154/af_ieee802154.c
>  create mode 100644 net/ieee802154/dgram.c
>  create mode 100644 net/ieee802154/netlink.c
>  create mode 100644 net/ieee802154/raw.c
>  create mode 100644 net/mac802154/Kconfig
>  create mode 100644 net/mac802154/Makefile
>  create mode 100644 net/mac802154/beacon.c
>  create mode 100644 net/mac802154/beacon.h
>  create mode 100644 net/mac802154/beacon_hash.c
>  create mode 100644 net/mac802154/beacon_hash.h
>  create mode 100644 net/mac802154/dev.c
>  create mode 100644 net/mac802154/mac802154.h
>  create mode 100644 net/mac802154/mac_cmd.c
>  create mode 100644 net/mac802154/main.c
>  create mode 100644 net/mac802154/mdev.c
>  create mode 100644 net/mac802154/mib.h
>  create mode 100644 net/mac802154/pib.c
>  create mode 100644 net/mac802154/pib.h
>  create mode 100644 net/mac802154/scan.c
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
>



-- 
Jon Smirl
jonsmirl@gmail.com

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [RFC][WIP] IEEE 802.15.4 implementation for Linux v1
@ 2009-06-05  4:49     ` Dmitry Eremin-Solenikov
  0 siblings, 0 replies; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-05  4:49 UTC (permalink / raw)
  To: Jon Smirl
  Cc: linux-kernel, netdev, linux-wireless, slapin, maxim.osipov,
	dmitry.baryshkov, oliver.fendt

2009/6/5 Jon Smirl <jonsmirl@gmail.com>:
> On Mon, Jun 1, 2009 at 10:54 AM, Dmitry
> Eremin-Solenikov<dbaryshkov@gmail.com> wrote:
>> Hi,
>>
>> As a part of research activities the Embedded Systems - Open Platform Group
>> from Siemens Corporate Technology we are working on adding support for
>> the IEEE 802.15.4 Wireless Personal Area Networks to the Linux. Our current
>> implementation is neither certified nor even feature complete. However
>> we'd like to present current state of our patchset to the Linux developers
>> community to gain comments, fixes, ideas, etc. This is not yet a pull request,
>> but more like an RFC.
>
> Does this stack work with the Atmel USB version of at86rf230?
> ATAVRRZUSBSTICK, http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4396

No, we do not support Atmel USB sticks, nor we do not have plans for
adding support
for it in the foreseable feature. However if the onboard ATmega can be
programmed to
provide usb-serial interface, one can use/adapt our serial discipline
driver to control it.
One will still have to write firmware for the on-stick ATmega chip.

Or you can add support for any existing interface that is provided by
RazorUSB card by yourself.
We tried to make mac802154 drivers easy to implement.

> It's not so simple to plug in the at86rf230 using SPI. Supporting USB
> sticks lets you develop on a desktop PC.

Hmm. One can solder (e.g.) the FTDI 2232 together with AT86RF230/231
and use that combo
instead of RazorUSB sticks.

> freaklabs.org is using ATAVRRZUSBSTICK

I'll look for the interface they are using to control sticks and check
how easy will it be to
write a driver for it.
-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [RFC][WIP] IEEE 802.15.4 implementation for Linux v1
@ 2009-06-05  4:49     ` Dmitry Eremin-Solenikov
  0 siblings, 0 replies; 75+ messages in thread
From: Dmitry Eremin-Solenikov @ 2009-06-05  4:49 UTC (permalink / raw)
  To: Jon Smirl
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	slapin-9cOl001CZnBAfugRpC6u6w,
	maxim.osipov-kv7WeFo6aLtBDgjK7y7TUQ,
	dmitry.baryshkov-kv7WeFo6aLtBDgjK7y7TUQ,
	oliver.fendt-kv7WeFo6aLtBDgjK7y7TUQ

2009/6/5 Jon Smirl <jonsmirl-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>:
> On Mon, Jun 1, 2009 at 10:54 AM, Dmitry
> Eremin-Solenikov<dbaryshkov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>> Hi,
>>
>> As a part of research activities the Embedded Systems - Open Platform Group
>> from Siemens Corporate Technology we are working on adding support for
>> the IEEE 802.15.4 Wireless Personal Area Networks to the Linux. Our current
>> implementation is neither certified nor even feature complete. However
>> we'd like to present current state of our patchset to the Linux developers
>> community to gain comments, fixes, ideas, etc. This is not yet a pull request,
>> but more like an RFC.
>
> Does this stack work with the Atmel USB version of at86rf230?
> ATAVRRZUSBSTICK, http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4396

No, we do not support Atmel USB sticks, nor we do not have plans for
adding support
for it in the foreseable feature. However if the onboard ATmega can be
programmed to
provide usb-serial interface, one can use/adapt our serial discipline
driver to control it.
One will still have to write firmware for the on-stick ATmega chip.

Or you can add support for any existing interface that is provided by
RazorUSB card by yourself.
We tried to make mac802154 drivers easy to implement.

> It's not so simple to plug in the at86rf230 using SPI. Supporting USB
> sticks lets you develop on a desktop PC.

Hmm. One can solder (e.g.) the FTDI 2232 together with AT86RF230/231
and use that combo
instead of RazorUSB sticks.

> freaklabs.org is using ATAVRRZUSBSTICK

I'll look for the interface they are using to control sticks and check
how easy will it be to
write a driver for it.
-- 
With best wishes
Dmitry
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 06/10] mac802154: add a software MAC 802.15.4 implementation
@ 2009-06-05 12:24               ` Pavel Machek
  0 siblings, 0 replies; 75+ messages in thread
From: Pavel Machek @ 2009-06-05 12:24 UTC (permalink / raw)
  To: Dmitry Eremin-Solenikov
  Cc: linux-kernel, netdev, linux-wireless, slapin, maxim.osipov,
	dmitry.baryshkov, oliver.fendt

On Mon 2009-06-01 18:54:47, Dmitry Eremin-Solenikov wrote:
> Some of available devices are just dump radios implementing IEEE 802.15.4
> PHY layer. This commit adds a common library that acts like an intermediate
> layer between our socket family and drivers for those dumb devices.
> 
> Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
> Signed-off-by: Sergey Lapin <slapin@ossfans.org>
> ---
>  include/net/ieee802154/mac802154.h |   79 ++++

Could we get some name that is not alphabet soup? Is 'zigbee'
trademarked so heavily that it can't be used? Maybe 'wpan'?
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [PATCH 06/10] mac802154: add a software MAC 802.15.4 implementation
@ 2009-06-05 12:24               ` Pavel Machek
  0 siblings, 0 replies; 75+ messages in thread
From: Pavel Machek @ 2009-06-05 12:24 UTC (permalink / raw)
  To: Dmitry Eremin-Solenikov
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	slapin-9cOl001CZnBAfugRpC6u6w,
	maxim.osipov-kv7WeFo6aLtBDgjK7y7TUQ,
	dmitry.baryshkov-kv7WeFo6aLtBDgjK7y7TUQ,
	oliver.fendt-kv7WeFo6aLtBDgjK7y7TUQ

On Mon 2009-06-01 18:54:47, Dmitry Eremin-Solenikov wrote:
> Some of available devices are just dump radios implementing IEEE 802.15.4
> PHY layer. This commit adds a common library that acts like an intermediate
> layer between our socket family and drivers for those dumb devices.
> 
> Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> Signed-off-by: Sergey Lapin <slapin-9cOl001CZnBAfugRpC6u6w@public.gmane.org>
> ---
>  include/net/ieee802154/mac802154.h |   79 ++++

Could we get some name that is not alphabet soup? Is 'zigbee'
trademarked so heavily that it can't be used? Maybe 'wpan'?
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [RFC][WIP] IEEE 802.15.4 implementation for Linux v1
@ 2009-06-05 12:58       ` Jon Smirl
  0 siblings, 0 replies; 75+ messages in thread
From: Jon Smirl @ 2009-06-05 12:58 UTC (permalink / raw)
  To: Dmitry Eremin-Solenikov
  Cc: linux-kernel, netdev, linux-wireless, slapin, maxim.osipov,
	dmitry.baryshkov, oliver.fendt

On Fri, Jun 5, 2009 at 12:49 AM, Dmitry
Eremin-Solenikov<dbaryshkov@gmail.com> wrote:
> 2009/6/5 Jon Smirl <jonsmirl@gmail.com>:
>> On Mon, Jun 1, 2009 at 10:54 AM, Dmitry
>> Eremin-Solenikov<dbaryshkov@gmail.com> wrote:
>>> Hi,
>>>
>>> As a part of research activities the Embedded Systems - Open Platform Group
>>> from Siemens Corporate Technology we are working on adding support for
>>> the IEEE 802.15.4 Wireless Personal Area Networks to the Linux. Our current
>>> implementation is neither certified nor even feature complete. However
>>> we'd like to present current state of our patchset to the Linux developers
>>> community to gain comments, fixes, ideas, etc. This is not yet a pull request,
>>> but more like an RFC.
>>
>> Does this stack work with the Atmel USB version of at86rf230?
>> ATAVRRZUSBSTICK, http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4396
>
> No, we do not support Atmel USB sticks, nor we do not have plans for
> adding support
> for it in the foreseable feature. However if the onboard ATmega can be
> programmed to
> provide usb-serial interface, one can use/adapt our serial discipline
> driver to control it.
> One will still have to write firmware for the on-stick ATmega chip.
>
> Or you can add support for any existing interface that is provided by
> RazorUSB card by yourself.
> We tried to make mac802154 drivers easy to implement.
>
>> It's not so simple to plug in the at86rf230 using SPI. Supporting USB
>> sticks lets you develop on a desktop PC.
>
> Hmm. One can solder (e.g.) the FTDI 2232 together with AT86RF230/231
> and use that combo
> instead of RazorUSB sticks.

Everything is there on USB stick. Interface, Zigbee chip, antenna, power, etc..
And they are cheap $40.

>
>> freaklabs.org is using ATAVRRZUSBSTICK
>
> I'll look for the interface they are using to control sticks and check
> how easy will it be to
> write a driver for it.

For development purposes you don't want to download the stack into the
USB stick, you just want to use USB as a transparent pass-through to
the Zigbee chip.

I have a Raven kit ordered, it will be here next week.


> --
> With best wishes
> Dmitry
>



-- 
Jon Smirl
jonsmirl@gmail.com

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [RFC][WIP] IEEE 802.15.4 implementation for Linux v1
@ 2009-06-05 12:58       ` Jon Smirl
  0 siblings, 0 replies; 75+ messages in thread
From: Jon Smirl @ 2009-06-05 12:58 UTC (permalink / raw)
  To: Dmitry Eremin-Solenikov
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	slapin-9cOl001CZnBAfugRpC6u6w,
	maxim.osipov-kv7WeFo6aLtBDgjK7y7TUQ,
	dmitry.baryshkov-kv7WeFo6aLtBDgjK7y7TUQ,
	oliver.fendt-kv7WeFo6aLtBDgjK7y7TUQ

On Fri, Jun 5, 2009 at 12:49 AM, Dmitry
Eremin-Solenikov<dbaryshkov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> 2009/6/5 Jon Smirl <jonsmirl-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>:
>> On Mon, Jun 1, 2009 at 10:54 AM, Dmitry
>> Eremin-Solenikov<dbaryshkov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>>> Hi,
>>>
>>> As a part of research activities the Embedded Systems - Open Platform Group
>>> from Siemens Corporate Technology we are working on adding support for
>>> the IEEE 802.15.4 Wireless Personal Area Networks to the Linux. Our current
>>> implementation is neither certified nor even feature complete. However
>>> we'd like to present current state of our patchset to the Linux developers
>>> community to gain comments, fixes, ideas, etc. This is not yet a pull request,
>>> but more like an RFC.
>>
>> Does this stack work with the Atmel USB version of at86rf230?
>> ATAVRRZUSBSTICK, http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4396
>
> No, we do not support Atmel USB sticks, nor we do not have plans for
> adding support
> for it in the foreseable feature. However if the onboard ATmega can be
> programmed to
> provide usb-serial interface, one can use/adapt our serial discipline
> driver to control it.
> One will still have to write firmware for the on-stick ATmega chip.
>
> Or you can add support for any existing interface that is provided by
> RazorUSB card by yourself.
> We tried to make mac802154 drivers easy to implement.
>
>> It's not so simple to plug in the at86rf230 using SPI. Supporting USB
>> sticks lets you develop on a desktop PC.
>
> Hmm. One can solder (e.g.) the FTDI 2232 together with AT86RF230/231
> and use that combo
> instead of RazorUSB sticks.

Everything is there on USB stick. Interface, Zigbee chip, antenna, power, etc..
And they are cheap $40.

>
>> freaklabs.org is using ATAVRRZUSBSTICK
>
> I'll look for the interface they are using to control sticks and check
> how easy will it be to
> write a driver for it.

For development purposes you don't want to download the stack into the
USB stick, you just want to use USB as a transparent pass-through to
the Zigbee chip.

I have a Raven kit ordered, it will be here next week.


> --
> With best wishes
> Dmitry
>



-- 
Jon Smirl
jonsmirl-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [RFC][WIP] IEEE 802.15.4 implementation for Linux v1
  2009-06-01 14:54 ` Dmitry Eremin-Solenikov
                   ` (2 preceding siblings ...)
  (?)
@ 2009-06-13  3:21 ` Jon Smirl
  2009-06-13  5:37     ` Maxim Osipov
  2009-06-21  6:40     ` Pavel Machek
  -1 siblings, 2 replies; 75+ messages in thread
From: Jon Smirl @ 2009-06-13  3:21 UTC (permalink / raw)
  To: Dmitry Eremin-Solenikov
  Cc: linux-kernel, netdev, linux-wireless, slapin, maxim.osipov,
	dmitry.baryshkov, oliver.fendt

On Mon, Jun 1, 2009 at 10:54 AM, Dmitry
Eremin-Solenikov<dbaryshkov@gmail.com> wrote:
> Hi,
>
> As a part of research activities the Embedded Systems - Open Platform Group
> from Siemens Corporate Technology we are working on adding support for
> the IEEE 802.15.4 Wireless Personal Area Networks to the Linux. Our current
> implementation is neither certified nor even feature complete. However
> we'd like to present current state of our patchset to the Linux developers
> community to gain comments, fixes, ideas, etc. This is not yet a pull request,
> but more like an RFC.
>
> The project page is available at http://apps.sourceforge.net/trac/linux-zigbee
> with source code of kernel part available from git at
> http://zigbee-linux.git.sourceforge.net, mirrored for convenience at
> git://git.kernel.org/pub/scm/linux/kernel/git/lumag/lowpan.git
>
> The source code for userspace utils is available from git at
> http://linux-zigbee.git.sourceforge.net/

The Zigbee alliance requires a minimum of $3,500/yr from any company
making a product based on the spec. How are you going to reconcile
this requirement with the GPL? They exempt non-commercial users but
the GPL doesn't allow code to be free for one purpose and pay for
another.

"The ZigBee Specification is available to individuals, companies and
institutions free of charge for all non-commercial purposes (including
university research, technical evaluation, and development of
non-commercial software, tools, or documentation). For ease of use,
clearly marked errata have been incorporated into this document. These
errata may not have been subjected to an Intellectual Property review,
and as such, may contain undeclared Necessary Claims. No part of this
specification may be used in development of a product for sale without
becoming a member of ZigBee Alliance. Copyright © ZigBee Alliance,
Inc. (2005). All rights Reserved. This information within this
document is the property of the ZigBee Alliance and its use and
disclosure are restricted.Elements of ZigBee Alliance specifications
may be subject to third party intellectual property rights, including
without limitation, patent, copyright or trademark rights (such a
third party may or may not be a member of ZigBee). ZigBee is not
responsible and shall not be held responsible in any manner for
identifying or failing to identify any or all such third party
intellectual property rights. This document and the information
contained herein are provided on an “AS IS” basis and ZigBee DISCLAIMS
ALL WARRANTIES EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO (A)
ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE
ANY RIGHTS OF THIRD PARTIES (INCLUDING WITH-OUT LIMITATION ANY
INTELLECTUAL PROPERTY RIGHTS INCLUDING PATENT, COPYRIGHT OR TRADEMARK
RIGHTS) OR (B) ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
A PARTICULAR PURPOSE, TITLE OR NON-INFRINGEMENT. IN NO EVENT WILL
ZIGBEE BE LIABLE FOR ANY LOSS OF PROF-ITS, LOSS OF BUSINESS, LOSS OF
USE OF DATA, INTERRUPTION OF BUSINESS, OR FOR ANY OTHER DIRECT,
INDIRECT, SPECIAL OR EXEMPLARY, INCIDENTIAL, PUNITIVE OR CONSEQUENTIAL
DAMAGES OF ANY KIND, IN CONTRACT OR IN TORT, IN CONNECTION WITH THIS
DOCUMENT OR THE INFORMATION CONTAINED HEREIN, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH LOSS OR DAMAGE. All Company, brand and product
names may be trademarks that are the sole property of their respective
owners. <P>The above notice and this paragraph must be included on all
copies of this document that are made. ZigBee Alliance, Inc.2400
Camino Ramon, Suite 375San Ramon, CA 94583"

-- 
Jon Smirl
jonsmirl@gmail.com

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [RFC][WIP] IEEE 802.15.4 implementation for Linux v1
@ 2009-06-13  5:37     ` Maxim Osipov
  0 siblings, 0 replies; 75+ messages in thread
From: Maxim Osipov @ 2009-06-13  5:37 UTC (permalink / raw)
  To: Jon Smirl
  Cc: Dmitry Eremin-Solenikov, linux-kernel, netdev, linux-wireless,
	slapin, maxim.osipov, dmitry.baryshkov, oliver.fendt

On Sat, Jun 13, 2009 at 7:21 AM, Jon Smirl<jonsmirl@gmail.com> wrote:
> On Mon, Jun 1, 2009 at 10:54 AM, Dmitry
> Eremin-Solenikov<dbaryshkov@gmail.com> wrote:
>> Hi,
>>
>> As a part of research activities the Embedded Systems - Open Platform Group
>> from Siemens Corporate Technology we are working on adding support for
>> the IEEE 802.15.4 Wireless Personal Area Networks to the Linux. Our current
>> implementation is neither certified nor even feature complete. However
>> we'd like to present current state of our patchset to the Linux developers
>> community to gain comments, fixes, ideas, etc. This is not yet a pull request,
>> but more like an RFC.
>>
>
> The Zigbee alliance requires a minimum of $3,500/yr from any company
> making a product based on the spec. How are you going to reconcile
> this requirement with the GPL? They exempt non-commercial users but
> the GPL doesn't allow code to be free for one purpose and pay for
> another.
>

For now, we do not release any ZigBee implementation. BTW - could you
refer to particular clause of GPL, which doesn't allow user to pay for
code?

Regards,
Maxim

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [RFC][WIP] IEEE 802.15.4 implementation for Linux v1
@ 2009-06-13  5:37     ` Maxim Osipov
  0 siblings, 0 replies; 75+ messages in thread
From: Maxim Osipov @ 2009-06-13  5:37 UTC (permalink / raw)
  To: Jon Smirl
  Cc: Dmitry Eremin-Solenikov, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	slapin-9cOl001CZnBAfugRpC6u6w,
	maxim.osipov-kv7WeFo6aLtBDgjK7y7TUQ,
	dmitry.baryshkov-kv7WeFo6aLtBDgjK7y7TUQ,
	oliver.fendt-kv7WeFo6aLtBDgjK7y7TUQ

On Sat, Jun 13, 2009 at 7:21 AM, Jon Smirl<jonsmirl-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> On Mon, Jun 1, 2009 at 10:54 AM, Dmitry
> Eremin-Solenikov<dbaryshkov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>> Hi,
>>
>> As a part of research activities the Embedded Systems - Open Platform Group
>> from Siemens Corporate Technology we are working on adding support for
>> the IEEE 802.15.4 Wireless Personal Area Networks to the Linux. Our current
>> implementation is neither certified nor even feature complete. However
>> we'd like to present current state of our patchset to the Linux developers
>> community to gain comments, fixes, ideas, etc. This is not yet a pull request,
>> but more like an RFC.
>>
>
> The Zigbee alliance requires a minimum of $3,500/yr from any company
> making a product based on the spec. How are you going to reconcile
> this requirement with the GPL? They exempt non-commercial users but
> the GPL doesn't allow code to be free for one purpose and pay for
> another.
>

For now, we do not release any ZigBee implementation. BTW - could you
refer to particular clause of GPL, which doesn't allow user to pay for
code?

Regards,
Maxim
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [RFC][WIP] IEEE 802.15.4 implementation for Linux v1
  2009-06-13  5:37     ` Maxim Osipov
  (?)
@ 2009-06-13 12:39     ` Jon Smirl
  -1 siblings, 0 replies; 75+ messages in thread
From: Jon Smirl @ 2009-06-13 12:39 UTC (permalink / raw)
  To: maxim
  Cc: Dmitry Eremin-Solenikov, linux-kernel, netdev, linux-wireless,
	slapin, maxim.osipov, dmitry.baryshkov, oliver.fendt

On Sat, Jun 13, 2009 at 1:37 AM, Maxim Osipov<maxim.osipov@gmail.com> wrote:
> On Sat, Jun 13, 2009 at 7:21 AM, Jon Smirl<jonsmirl@gmail.com> wrote:
>> On Mon, Jun 1, 2009 at 10:54 AM, Dmitry
>> Eremin-Solenikov<dbaryshkov@gmail.com> wrote:
>>> Hi,
>>>
>>> As a part of research activities the Embedded Systems - Open Platform Group
>>> from Siemens Corporate Technology we are working on adding support for
>>> the IEEE 802.15.4 Wireless Personal Area Networks to the Linux. Our current
>>> implementation is neither certified nor even feature complete. However
>>> we'd like to present current state of our patchset to the Linux developers
>>> community to gain comments, fixes, ideas, etc. This is not yet a pull request,
>>> but more like an RFC.
>>>
>>
>> The Zigbee alliance requires a minimum of $3,500/yr from any company
>> making a product based on the spec. How are you going to reconcile
>> this requirement with the GPL? They exempt non-commercial users but
>> the GPL doesn't allow code to be free for one purpose and pay for
>> another.
>>
>
> For now, we do not release any ZigBee implementation. BTW - could you
> refer to particular clause of GPL, which doesn't allow user to pay for
> code?

    b) You must cause any work that you distribute or publish, that in
    whole or in part contains or is derived from the Program or any
    part thereof, to be licensed as a whole at no charge to all third
    parties under the terms of this License.

You can charge a duplication fee when you do the copying. It is fine
to charge for things like support or the hardware that comes with the
software.


>
> Regards,
> Maxim
>



-- 
Jon Smirl
jonsmirl@gmail.com

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [RFC][WIP] IEEE 802.15.4 implementation for Linux v1
@ 2009-06-21  6:40     ` Pavel Machek
  0 siblings, 0 replies; 75+ messages in thread
From: Pavel Machek @ 2009-06-21  6:40 UTC (permalink / raw)
  To: Jon Smirl
  Cc: Dmitry Eremin-Solenikov, linux-kernel, netdev, linux-wireless,
	slapin, maxim.osipov, dmitry.baryshkov, oliver.fendt

On Fri 2009-06-12 23:21:34, Jon Smirl wrote:
> On Mon, Jun 1, 2009 at 10:54 AM, Dmitry
> Eremin-Solenikov<dbaryshkov@gmail.com> wrote:
> > Hi,
> >
> > As a part of research activities the Embedded Systems - Open Platform Group
> > from Siemens Corporate Technology we are working on adding support for
> > the IEEE 802.15.4 Wireless Personal Area Networks to the Linux. Our current
> > implementation is neither certified nor even feature complete. However
> > we'd like to present current state of our patchset to the Linux developers
> > community to gain comments, fixes, ideas, etc. This is not yet a pull request,
> > but more like an RFC.
> >
> > The project page is available at http://apps.sourceforge.net/trac/linux-zigbee
> > with source code of kernel part available from git at
> > http://zigbee-linux.git.sourceforge.net, mirrored for convenience at
> > git://git.kernel.org/pub/scm/linux/kernel/git/lumag/lowpan.git
> >
> > The source code for userspace utils is available from git at
> > http://linux-zigbee.git.sourceforge.net/
> 
> The Zigbee alliance requires a minimum of $3,500/yr from any company
> making a product based on the spec. How are you going to reconcile
> this requirement with the GPL? They exempt non-commercial users but
> the GPL doesn't allow code to be free for one purpose and pay for
> another.
> 
> "The ZigBee Specification is available to individuals, companies and
> institutions free of charge for all non-commercial purposes (including
> university research, technical evaluation, and development of
> non-commercial software, tools, or documentation). For ease of use,
> clearly marked errata have been incorporated into this document. These
> errata may not have been subjected to an Intellectual Property review,
> and as such, may contain undeclared Necessary Claims. No part of this
> specification may be used in development of a product for sale without
> becoming a member of ZigBee Alliance. Copyright ? ZigBee Alliance,

Confusing legaleese, and probably void, too. If you can get hard copy
of that book, and make sure your implementation is not derived work of
that book, you are safe -- w.r.t. copyright. Someone would have to
research the patents, or just move out of US.
								Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [RFC][WIP] IEEE 802.15.4 implementation for Linux v1
@ 2009-06-21  6:40     ` Pavel Machek
  0 siblings, 0 replies; 75+ messages in thread
From: Pavel Machek @ 2009-06-21  6:40 UTC (permalink / raw)
  To: Jon Smirl
  Cc: Dmitry Eremin-Solenikov, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	slapin-9cOl001CZnBAfugRpC6u6w,
	maxim.osipov-kv7WeFo6aLtBDgjK7y7TUQ,
	dmitry.baryshkov-kv7WeFo6aLtBDgjK7y7TUQ,
	oliver.fendt-kv7WeFo6aLtBDgjK7y7TUQ

On Fri 2009-06-12 23:21:34, Jon Smirl wrote:
> On Mon, Jun 1, 2009 at 10:54 AM, Dmitry
> Eremin-Solenikov<dbaryshkov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> > Hi,
> >
> > As a part of research activities the Embedded Systems - Open Platform Group
> > from Siemens Corporate Technology we are working on adding support for
> > the IEEE 802.15.4 Wireless Personal Area Networks to the Linux. Our current
> > implementation is neither certified nor even feature complete. However
> > we'd like to present current state of our patchset to the Linux developers
> > community to gain comments, fixes, ideas, etc. This is not yet a pull request,
> > but more like an RFC.
> >
> > The project page is available at http://apps.sourceforge.net/trac/linux-zigbee
> > with source code of kernel part available from git at
> > http://zigbee-linux.git.sourceforge.net, mirrored for convenience at
> > git://git.kernel.org/pub/scm/linux/kernel/git/lumag/lowpan.git
> >
> > The source code for userspace utils is available from git at
> > http://linux-zigbee.git.sourceforge.net/
> 
> The Zigbee alliance requires a minimum of $3,500/yr from any company
> making a product based on the spec. How are you going to reconcile
> this requirement with the GPL? They exempt non-commercial users but
> the GPL doesn't allow code to be free for one purpose and pay for
> another.
> 
> "The ZigBee Specification is available to individuals, companies and
> institutions free of charge for all non-commercial purposes (including
> university research, technical evaluation, and development of
> non-commercial software, tools, or documentation). For ease of use,
> clearly marked errata have been incorporated into this document. These
> errata may not have been subjected to an Intellectual Property review,
> and as such, may contain undeclared Necessary Claims. No part of this
> specification may be used in development of a product for sale without
> becoming a member of ZigBee Alliance. Copyright ? ZigBee Alliance,

Confusing legaleese, and probably void, too. If you can get hard copy
of that book, and make sure your implementation is not derived work of
that book, you are safe -- w.r.t. copyright. Someone would have to
research the patents, or just move out of US.
								Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 75+ messages in thread

end of thread, other threads:[~2009-06-21  6:45 UTC | newest]

Thread overview: 75+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-06-01 14:54 [RFC][WIP] IEEE 802.15.4 implementation for Linux v1 Dmitry Eremin-Solenikov
2009-06-01 14:54 ` Dmitry Eremin-Solenikov
2009-06-01 14:54 ` [PATCH 01/10] crc-itu-t: add bit-reversed calculation Dmitry Eremin-Solenikov
2009-06-01 14:54   ` [PATCH 02/10] Add constants for the ieee 802.15.4/ZigBee stack Dmitry Eremin-Solenikov
2009-06-01 14:54     ` [PATCH 03/10] net: add IEEE 802.15.4 socket family implementation Dmitry Eremin-Solenikov
2009-06-01 14:54       ` [PATCH 04/10] net: add NL802154 interface for configuration of 802.15.4 devices Dmitry Eremin-Solenikov
2009-06-01 14:54         ` Dmitry Eremin-Solenikov
2009-06-01 14:54         ` [PATCH 05/10] ieee802154: add simple HardMAC driver sample Dmitry Eremin-Solenikov
2009-06-01 14:54           ` [PATCH 06/10] mac802154: add a software MAC 802.15.4 implementation Dmitry Eremin-Solenikov
2009-06-01 14:54             ` [PATCH 07/10] ieee802154: add virtual loopback driver Dmitry Eremin-Solenikov
2009-06-01 14:54               ` Dmitry Eremin-Solenikov
2009-06-01 14:54               ` [PATCH 08/10] tty_io: export tty_class Dmitry Eremin-Solenikov
2009-06-01 14:54                 ` Dmitry Eremin-Solenikov
2009-06-01 14:54                 ` [PATCH 09/10] ieee802154: add serial dongle driver Dmitry Eremin-Solenikov
2009-06-01 14:54                   ` Dmitry Eremin-Solenikov
2009-06-01 14:54                   ` [PATCH 10/10] ieee802154: add at86rf230/rf231 spi driver Dmitry Eremin-Solenikov
2009-06-01 14:54                     ` Dmitry Eremin-Solenikov
2009-06-01 16:21                     ` Gábor Stefanik
2009-06-01 16:21                       ` Gábor Stefanik
2009-06-01 20:33                       ` Dmitry Eremin-Solenikov
2009-06-01 20:33                         ` Dmitry Eremin-Solenikov
2009-06-02  8:10                         ` Holger Schurig
2009-06-02  8:10                           ` Holger Schurig
2009-06-02  8:21                           ` Marcel Holtmann
2009-06-02  8:21                             ` Marcel Holtmann
2009-06-02  8:29                             ` Ответ: " Dmitry Eremin-Solenikov
2009-06-02  8:29                               ` Dmitry Eremin-Solenikov
2009-06-02  8:36                               ` Marcel Holtmann
2009-06-02  8:46                                 ` Florian Fainelli
2009-06-02  8:49                                 ` Maxim Osipov
2009-06-02  9:15                                   ` Holger Schurig
2009-06-02  9:15                                     ` Holger Schurig
2009-06-02  9:29                                   ` ?????: " Jonathan Cameron
2009-06-02 11:42                                     ` Dmitry Eremin-Solenikov
2009-06-02 11:42                                       ` Dmitry Eremin-Solenikov
2009-06-02  8:52                                 ` Ответ: " Sergey Lapin
2009-06-02  8:52                                   ` Sergey Lapin
2009-06-01 15:27                   ` [PATCH 09/10] ieee802154: add serial dongle driver Alan Cox
2009-06-01 15:27                     ` Alan Cox
2009-06-01 20:29                     ` Dmitry Eremin-Solenikov
2009-06-01 21:52                       ` Alan Cox
2009-06-01 21:52                         ` Alan Cox
2009-06-02 14:43                         ` Sergey Lapin
2009-06-02 14:43                           ` Sergey Lapin
2009-06-01 15:07                 ` [PATCH 08/10] tty_io: export tty_class Alan Cox
2009-06-01 15:07                   ` Alan Cox
2009-06-01 15:10                   ` Dmitry Eremin-Solenikov
2009-06-01 15:34                     ` Alan Cox
2009-06-02 14:22                       ` Dmitry Eremin-Solenikov
2009-06-02 14:22                         ` Dmitry Eremin-Solenikov
2009-06-02 14:35                         ` Alan Cox
2009-06-05 12:24             ` [PATCH 06/10] mac802154: add a software MAC 802.15.4 implementation Pavel Machek
2009-06-05 12:24               ` Pavel Machek
2009-06-04  0:32       ` [PATCH 03/10] net: add IEEE 802.15.4 socket family implementation Andrew Morton
2009-06-04  0:32         ` Andrew Morton
2009-06-04 11:16         ` Dmitry Eremin-Solenikov
2009-06-04 11:16           ` Dmitry Eremin-Solenikov
2009-06-04 13:46           ` John W. Linville
2009-06-04 13:46             ` John W. Linville
2009-06-04 14:10             ` Dmitry Eremin-Solenikov
2009-06-04 14:10               ` Dmitry Eremin-Solenikov
2009-06-04 14:15               ` Johannes Berg
2009-06-04 14:15                 ` Johannes Berg
2009-06-04  0:05   ` [PATCH 01/10] crc-itu-t: add bit-reversed calculation Andrew Morton
2009-06-05  4:03 ` [RFC][WIP] IEEE 802.15.4 implementation for Linux v1 Jon Smirl
2009-06-05  4:49   ` Dmitry Eremin-Solenikov
2009-06-05  4:49     ` Dmitry Eremin-Solenikov
2009-06-05 12:58     ` Jon Smirl
2009-06-05 12:58       ` Jon Smirl
2009-06-13  3:21 ` Jon Smirl
2009-06-13  5:37   ` Maxim Osipov
2009-06-13  5:37     ` Maxim Osipov
2009-06-13 12:39     ` Jon Smirl
2009-06-21  6:40   ` Pavel Machek
2009-06-21  6:40     ` Pavel Machek

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.