aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/ieee802154/af_ieee802154.h60
-rw-r--r--include/net/ieee802154/mac_def.h160
-rw-r--r--include/net/ieee802154/netdevice.h115
-rw-r--r--net/Kconfig1
-rw-r--r--net/Makefile1
-rw-r--r--net/ieee802154/Kconfig12
-rw-r--r--net/ieee802154/Makefile4
-rw-r--r--net/ieee802154/af802154.h36
-rw-r--r--net/ieee802154/af_ieee802154.c372
-rw-r--r--net/ieee802154/dgram.c394
-rw-r--r--net/ieee802154/raw.c254
11 files changed, 1409 insertions, 0 deletions
diff --git a/include/net/ieee802154/af_ieee802154.h b/include/net/ieee802154/af_ieee802154.h
new file mode 100644
index 000000000000..0d78605fb1a6
--- /dev/null
+++ b/include/net/ieee802154/af_ieee802154.h
@@ -0,0 +1,60 @@
1/*
2 * IEEE 802.15.4 inteface for userspace
3 *
4 * Copyright 2007, 2008 Siemens AG
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2
8 * as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Written by:
20 * Sergey Lapin <slapin@ossfans.org>
21 * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
22 */
23
24#ifndef _AF_IEEE802154_H
25#define _AF_IEEE802154_H
26
27#include <linux/socket.h> /* for sa_family_t */
28
29enum {
30 IEEE802154_ADDR_NONE = 0x0,
31 /* RESERVED = 0x01, */
32 IEEE802154_ADDR_SHORT = 0x2, /* 16-bit address + PANid */
33 IEEE802154_ADDR_LONG = 0x3, /* 64-bit address + PANid */
34};
35
36/* address length, octets */
37#define IEEE802154_ADDR_LEN 8
38
39struct ieee802154_addr {
40 int addr_type;
41 u16 pan_id;
42 union {
43 u8 hwaddr[IEEE802154_ADDR_LEN];
44 u16 short_addr;
45 };
46};
47
48#define IEEE802154_PANID_BROADCAST 0xffff
49#define IEEE802154_ADDR_BROADCAST 0xffff
50#define IEEE802154_ADDR_UNDEF 0xfffe
51
52struct sockaddr_ieee802154 {
53 sa_family_t family; /* AF_IEEE802154 */
54 struct ieee802154_addr addr;
55};
56
57/* master device */
58#define IEEE802154_SIOC_ADD_SLAVE (SIOCDEVPRIVATE + 0)
59
60#endif
diff --git a/include/net/ieee802154/mac_def.h b/include/net/ieee802154/mac_def.h
new file mode 100644
index 000000000000..8cb684635650
--- /dev/null
+++ b/include/net/ieee802154/mac_def.h
@@ -0,0 +1,160 @@
1/*
2 * IEEE802.15.4-2003 specification
3 *
4 * Copyright (C) 2007, 2008 Siemens AG
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2
8 * as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Written by:
20 * Pavel Smolenskiy <pavel.smolenskiy@gmail.com>
21 * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
22 * Maxim Osipov <maxim.osipov@siemens.com>
23 * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
24 */
25
26#ifndef IEEE802154_MAC_DEF_H
27#define IEEE802154_MAC_DEF_H
28
29#define IEEE802154_FC_TYPE_BEACON 0x0 /* Frame is beacon */
30#define IEEE802154_FC_TYPE_DATA 0x1 /* Frame is data */
31#define IEEE802154_FC_TYPE_ACK 0x2 /* Frame is acknowledgment */
32#define IEEE802154_FC_TYPE_MAC_CMD 0x3 /* Frame is MAC command */
33
34#define IEEE802154_FC_TYPE_SHIFT 0
35#define IEEE802154_FC_TYPE_MASK ((1 << 3) - 1)
36#define IEEE802154_FC_TYPE(x) ((x & IEEE802154_FC_TYPE_MASK) >> IEEE802154_FC_TYPE_SHIFT)
37#define IEEE802154_FC_SET_TYPE(v, x) do { \
38 v = (((v) & ~IEEE802154_FC_TYPE_MASK) | \
39 (((x) << IEEE802154_FC_TYPE_SHIFT) & IEEE802154_FC_TYPE_MASK)); \
40 } while (0)
41
42#define IEEE802154_FC_SECEN (1 << 3)
43#define IEEE802154_FC_FRPEND (1 << 4)
44#define IEEE802154_FC_ACK_REQ (1 << 5)
45#define IEEE802154_FC_INTRA_PAN (1 << 6)
46
47#define IEEE802154_FC_SAMODE_SHIFT 14
48#define IEEE802154_FC_SAMODE_MASK (3 << IEEE802154_FC_SAMODE_SHIFT)
49#define IEEE802154_FC_DAMODE_SHIFT 10
50#define IEEE802154_FC_DAMODE_MASK (3 << IEEE802154_FC_DAMODE_SHIFT)
51
52#define IEEE802154_FC_SAMODE(x) \
53 (((x) & IEEE802154_FC_SAMODE_MASK) >> IEEE802154_FC_SAMODE_SHIFT)
54
55#define IEEE802154_FC_DAMODE(x) \
56 (((x) & IEEE802154_FC_DAMODE_MASK) >> IEEE802154_FC_DAMODE_SHIFT)
57
58
59/* MAC's Command Frames Identifiers */
60#define IEEE802154_CMD_ASSOCIATION_REQ 0x01
61#define IEEE802154_CMD_ASSOCIATION_RESP 0x02
62#define IEEE802154_CMD_DISASSOCIATION_NOTIFY 0x03
63#define IEEE802154_CMD_DATA_REQ 0x04
64#define IEEE802154_CMD_PANID_CONFLICT_NOTIFY 0x05
65#define IEEE802154_CMD_ORPHAN_NOTIFY 0x06
66#define IEEE802154_CMD_BEACON_REQ 0x07
67#define IEEE802154_CMD_COORD_REALIGN_NOTIFY 0x08
68#define IEEE802154_CMD_GTS_REQ 0x09
69
70/*
71 * The return values of MAC operations
72 */
73enum {
74 /*
75 * The requested operation was completed successfully.
76 * For a transmission request, this value indicates
77 * a successful transmission.
78 */
79 IEEE802154_SUCCESS = 0x0,
80
81 /* The beacon was lost following a synchronization request. */
82 IEEE802154_BEACON_LOSS = 0xe0,
83 /*
84 * A transmission could not take place due to activity on the
85 * channel, i.e., the CSMA-CA mechanism has failed.
86 */
87 IEEE802154_CHNL_ACCESS_FAIL = 0xe1,
88 /* The GTS request has been denied by the PAN coordinator. */
89 IEEE802154_DENINED = 0xe2,
90 /* The attempt to disable the transceiver has failed. */
91 IEEE802154_DISABLE_TRX_FAIL = 0xe3,
92 /*
93 * The received frame induces a failed security check according to
94 * the security suite.
95 */
96 IEEE802154_FAILED_SECURITY_CHECK = 0xe4,
97 /*
98 * The frame resulting from secure processing has a length that is
99 * greater than aMACMaxFrameSize.
100 */
101 IEEE802154_FRAME_TOO_LONG = 0xe5,
102 /*
103 * The requested GTS transmission failed because the specified GTS
104 * either did not have a transmit GTS direction or was not defined.
105 */
106 IEEE802154_INVALID_GTS = 0xe6,
107 /*
108 * A request to purge an MSDU from the transaction queue was made using
109 * an MSDU handle that was not found in the transaction table.
110 */
111 IEEE802154_INVALID_HANDLE = 0xe7,
112 /* A parameter in the primitive is out of the valid range.*/
113 IEEE802154_INVALID_PARAMETER = 0xe8,
114 /* No acknowledgment was received after aMaxFrameRetries. */
115 IEEE802154_NO_ACK = 0xe9,
116 /* A scan operation failed to find any network beacons.*/
117 IEEE802154_NO_BEACON = 0xea,
118 /* No response data were available following a request. */
119 IEEE802154_NO_DATA = 0xeb,
120 /* The operation failed because a short address was not allocated. */
121 IEEE802154_NO_SHORT_ADDRESS = 0xec,
122 /*
123 * A receiver enable request was unsuccessful because it could not be
124 * completed within the CAP.
125 */
126 IEEE802154_OUT_OF_CAP = 0xed,
127 /*
128 * A PAN identifier conflict has been detected and communicated to the
129 * PAN coordinator.
130 */
131 IEEE802154_PANID_CONFLICT = 0xee,
132 /* A coordinator realignment command has been received. */
133 IEEE802154_REALIGMENT = 0xef,
134 /* The transaction has expired and its information discarded. */
135 IEEE802154_TRANSACTION_EXPIRED = 0xf0,
136 /* There is no capacity to store the transaction. */
137 IEEE802154_TRANSACTION_OVERFLOW = 0xf1,
138 /*
139 * The transceiver was in the transmitter enabled state when the
140 * receiver was requested to be enabled.
141 */
142 IEEE802154_TX_ACTIVE = 0xf2,
143 /* The appropriate key is not available in the ACL. */
144 IEEE802154_UNAVAILABLE_KEY = 0xf3,
145 /*
146 * A SET/GET request was issued with the identifier of a PIB attribute
147 * that is not supported.
148 */
149 IEEE802154_UNSUPPORTED_ATTR = 0xf4,
150 /*
151 * A request to perform a scan operation failed because the MLME was
152 * in the process of performing a previously initiated scan operation.
153 */
154 IEEE802154_SCAN_IN_PROGRESS = 0xfc,
155};
156
157
158#endif
159
160
diff --git a/include/net/ieee802154/netdevice.h b/include/net/ieee802154/netdevice.h
new file mode 100644
index 000000000000..e2506af3e7c8
--- /dev/null
+++ b/include/net/ieee802154/netdevice.h
@@ -0,0 +1,115 @@
1/*
2 * An interface between IEEE802.15.4 device and rest of the kernel.
3 *
4 * Copyright (C) 2007, 2008, 2009 Siemens AG
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2
8 * as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Written by:
20 * Pavel Smolenskiy <pavel.smolenskiy@gmail.com>
21 * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
22 * Maxim Osipov <maxim.osipov@siemens.com>
23 * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
24 */
25
26#ifndef IEEE802154_NETDEVICE_H
27#define IEEE802154_NETDEVICE_H
28
29/*
30 * A control block of skb passed between the ARPHRD_IEEE802154 device
31 * and other stack parts.
32 */
33struct ieee802154_mac_cb {
34 u8 lqi;
35 struct ieee802154_addr sa;
36 struct ieee802154_addr da;
37 u8 flags;
38 u8 seq;
39};
40
41static inline struct ieee802154_mac_cb *mac_cb(struct sk_buff *skb)
42{
43 return (struct ieee802154_mac_cb *)skb->cb;
44}
45
46#define MAC_CB_FLAG_TYPEMASK ((1 << 3) - 1)
47
48#define MAC_CB_FLAG_ACKREQ (1 << 3)
49#define MAC_CB_FLAG_SECEN (1 << 4)
50#define MAC_CB_FLAG_INTRAPAN (1 << 5)
51
52static inline int mac_cb_is_ackreq(struct sk_buff *skb)
53{
54 return mac_cb(skb)->flags & MAC_CB_FLAG_ACKREQ;
55}
56
57static inline int mac_cb_is_secen(struct sk_buff *skb)
58{
59 return mac_cb(skb)->flags & MAC_CB_FLAG_SECEN;
60}
61
62static inline int mac_cb_is_intrapan(struct sk_buff *skb)
63{
64 return mac_cb(skb)->flags & MAC_CB_FLAG_INTRAPAN;
65}
66
67static inline int mac_cb_type(struct sk_buff *skb)
68{
69 return mac_cb(skb)->flags & MAC_CB_FLAG_TYPEMASK;
70}
71
72#define IEEE802154_MAC_SCAN_ED 0
73#define IEEE802154_MAC_SCAN_ACTIVE 1
74#define IEEE802154_MAC_SCAN_PASSIVE 2
75#define IEEE802154_MAC_SCAN_ORPHAN 3
76
77/*
78 * This should be located at net_device->ml_priv
79 */
80struct ieee802154_mlme_ops {
81 int (*assoc_req)(struct net_device *dev,
82 struct ieee802154_addr *addr,
83 u8 channel, u8 cap);
84 int (*assoc_resp)(struct net_device *dev,
85 struct ieee802154_addr *addr,
86 u16 short_addr, u8 status);
87 int (*disassoc_req)(struct net_device *dev,
88 struct ieee802154_addr *addr,
89 u8 reason);
90 int (*start_req)(struct net_device *dev,
91 struct ieee802154_addr *addr,
92 u8 channel, u8 bcn_ord, u8 sf_ord,
93 u8 pan_coord, u8 blx, u8 coord_realign);
94 int (*scan_req)(struct net_device *dev,
95 u8 type, u32 channels, u8 duration);
96
97 /*
98 * FIXME: these should become the part of PIB/MIB interface.
99 * However we still don't have IB interface of any kind
100 */
101 u16 (*get_pan_id)(struct net_device *dev);
102 u16 (*get_short_addr)(struct net_device *dev);
103 u8 (*get_dsn)(struct net_device *dev);
104 u8 (*get_bsn)(struct net_device *dev);
105};
106
107static inline struct ieee802154_mlme_ops *ieee802154_mlme_ops(
108 struct net_device *dev)
109{
110 return dev->ml_priv;
111}
112
113#endif
114
115
diff --git a/net/Kconfig b/net/Kconfig
index c19f549c8e74..7051b9710675 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -179,6 +179,7 @@ source "net/lapb/Kconfig"
179source "net/econet/Kconfig" 179source "net/econet/Kconfig"
180source "net/wanrouter/Kconfig" 180source "net/wanrouter/Kconfig"
181source "net/phonet/Kconfig" 181source "net/phonet/Kconfig"
182source "net/ieee802154/Kconfig"
182source "net/sched/Kconfig" 183source "net/sched/Kconfig"
183source "net/dcb/Kconfig" 184source "net/dcb/Kconfig"
184 185
diff --git a/net/Makefile b/net/Makefile
index 9e00a55a901b..ba324aefda73 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -60,6 +60,7 @@ obj-$(CONFIG_NET_9P) += 9p/
60ifneq ($(CONFIG_DCB),) 60ifneq ($(CONFIG_DCB),)
61obj-y += dcb/ 61obj-y += dcb/
62endif 62endif
63obj-y += ieee802154/
63 64
64ifeq ($(CONFIG_NET),y) 65ifeq ($(CONFIG_NET),y)
65obj-$(CONFIG_SYSCTL) += sysctl_net.o 66obj-$(CONFIG_SYSCTL) += sysctl_net.o
diff --git a/net/ieee802154/Kconfig b/net/ieee802154/Kconfig
new file mode 100644
index 000000000000..1c1de97d264a
--- /dev/null
+++ b/net/ieee802154/Kconfig
@@ -0,0 +1,12 @@
1config IEEE802154
2 tristate "IEEE Std 802.15.4 Low-Rate Wireless Personal Area Networks support (EXPERIMENTAL)"
3 depends on EXPERIMENTAL
4 ---help---
5 IEEE Std 802.15.4 defines a low data rate, low power and low
6 complexity short range wireless personal area networks. It was
7 designed to organise networks of sensors, switches, etc automation
8 devices. Maximum allowed data rate is 250 kb/s and typical personal
9 operating space around 10m.
10
11 Say Y here to compile LR-WPAN support into the kernel or say M to
12 compile it as modules.
diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile
new file mode 100644
index 000000000000..7451c7cc8c8e
--- /dev/null
+++ b/net/ieee802154/Makefile
@@ -0,0 +1,4 @@
1obj-$(CONFIG_IEEE802154) += af_802154.o
2af_802154-y := af_ieee802154.o raw.o dgram.o
3
4ccflags-y += -Wall -DDEBUG
diff --git a/net/ieee802154/af802154.h b/net/ieee802154/af802154.h
new file mode 100644
index 000000000000..b1ec52537522
--- /dev/null
+++ b/net/ieee802154/af802154.h
@@ -0,0 +1,36 @@
1/*
2 * Internal interfaces for ieee 802.15.4 address family.
3 *
4 * Copyright 2007, 2008, 2009 Siemens AG
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2
8 * as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Written by:
20 * Sergey Lapin <slapin@ossfans.org>
21 * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
22 */
23
24#ifndef AF802154_H
25#define AF802154_H
26
27struct sk_buff;
28struct net_devce;
29extern struct proto ieee802154_raw_prot;
30extern struct proto ieee802154_dgram_prot;
31void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb);
32int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb);
33struct net_device *ieee802154_get_dev(struct net *net,
34 struct ieee802154_addr *addr);
35
36#endif
diff --git a/net/ieee802154/af_ieee802154.c b/net/ieee802154/af_ieee802154.c
new file mode 100644
index 000000000000..882a927cefae
--- /dev/null
+++ b/net/ieee802154/af_ieee802154.c
@@ -0,0 +1,372 @@
1/*
2 * IEEE802154.4 socket interface
3 *
4 * Copyright 2007, 2008 Siemens AG
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2
8 * as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Written by:
20 * Sergey Lapin <slapin@ossfans.org>
21 * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
22 */
23
24#include <linux/net.h>
25#include <linux/capability.h>
26#include <linux/module.h>
27#include <linux/if_arp.h>
28#include <linux/if.h>
29#include <linux/termios.h> /* For TIOCOUTQ/INQ */
30#include <linux/list.h>
31#include <net/datalink.h>
32#include <net/psnap.h>
33#include <net/sock.h>
34#include <net/tcp_states.h>
35#include <net/route.h>
36
37#include <net/ieee802154/af_ieee802154.h>
38#include <net/ieee802154/netdevice.h>
39
40#include "af802154.h"
41
42#define DBG_DUMP(data, len) { \
43 int i; \
44 pr_debug("function: %s: data: len %d:\n", __func__, len); \
45 for (i = 0; i < len; i++) {\
46 pr_debug("%02x: %02x\n", i, (data)[i]); \
47 } \
48}
49
50/*
51 * Utility function for families
52 */
53struct net_device *ieee802154_get_dev(struct net *net,
54 struct ieee802154_addr *addr)
55{
56 struct net_device *dev = NULL;
57 struct net_device *tmp;
58 u16 pan_id, short_addr;
59
60 switch (addr->addr_type) {
61 case IEEE802154_ADDR_LONG:
62 rtnl_lock();
63 dev = dev_getbyhwaddr(net, ARPHRD_IEEE802154, addr->hwaddr);
64 if (dev)
65 dev_hold(dev);
66 rtnl_unlock();
67 break;
68 case IEEE802154_ADDR_SHORT:
69 if (addr->pan_id == 0xffff ||
70 addr->short_addr == IEEE802154_ADDR_UNDEF ||
71 addr->short_addr == 0xffff)
72 break;
73
74 rtnl_lock();
75
76 for_each_netdev(net, tmp) {
77 if (tmp->type != ARPHRD_IEEE802154)
78 continue;
79
80 pan_id = ieee802154_mlme_ops(tmp)->get_pan_id(tmp);
81 short_addr =
82 ieee802154_mlme_ops(tmp)->get_short_addr(tmp);
83
84 if (pan_id == addr->pan_id &&
85 short_addr == addr->short_addr) {
86 dev = tmp;
87 dev_hold(dev);
88 break;
89 }
90 }
91
92 rtnl_unlock();
93 break;
94 default:
95 pr_warning("Unsupported ieee802154 address type: %d\n",
96 addr->addr_type);
97 break;
98 }
99
100 return dev;
101}
102
103static int ieee802154_sock_release(struct socket *sock)
104{
105 struct sock *sk = sock->sk;
106
107 if (sk) {
108 sock->sk = NULL;
109 sk->sk_prot->close(sk, 0);
110 }
111 return 0;
112}
113static int ieee802154_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
114 struct msghdr *msg, size_t len)
115{
116 struct sock *sk = sock->sk;
117
118 return sk->sk_prot->sendmsg(iocb, sk, msg, len);
119}
120
121static int ieee802154_sock_bind(struct socket *sock, struct sockaddr *uaddr,
122 int addr_len)
123{
124 struct sock *sk = sock->sk;
125
126 if (sk->sk_prot->bind)
127 return sk->sk_prot->bind(sk, uaddr, addr_len);
128
129 return sock_no_bind(sock, uaddr, addr_len);
130}
131
132static int ieee802154_sock_connect(struct socket *sock, struct sockaddr *uaddr,
133 int addr_len, int flags)
134{
135 struct sock *sk = sock->sk;
136
137 if (uaddr->sa_family == AF_UNSPEC)
138 return sk->sk_prot->disconnect(sk, flags);
139
140 return sk->sk_prot->connect(sk, uaddr, addr_len);
141}
142
143static int ieee802154_dev_ioctl(struct sock *sk, struct ifreq __user *arg,
144 unsigned int cmd)
145{
146 struct ifreq ifr;
147 int ret = -EINVAL;
148 struct net_device *dev;
149
150 if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
151 return -EFAULT;
152
153 ifr.ifr_name[IFNAMSIZ-1] = 0;
154
155 dev_load(sock_net(sk), ifr.ifr_name);
156 dev = dev_get_by_name(sock_net(sk), ifr.ifr_name);
157 if (dev->type == ARPHRD_IEEE802154 ||
158 dev->type == ARPHRD_IEEE802154_PHY)
159 ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, cmd);
160
161 if (!ret && copy_to_user(arg, &ifr, sizeof(struct ifreq)))
162 ret = -EFAULT;
163 dev_put(dev);
164
165 return ret;
166}
167
168static int ieee802154_sock_ioctl(struct socket *sock, unsigned int cmd,
169 unsigned long arg)
170{
171 struct sock *sk = sock->sk;
172
173 switch (cmd) {
174 case SIOCGSTAMP:
175 return sock_get_timestamp(sk, (struct timeval __user *)arg);
176 case SIOCGSTAMPNS:
177 return sock_get_timestampns(sk, (struct timespec __user *)arg);
178 case SIOCGIFADDR:
179 case SIOCSIFADDR:
180 return ieee802154_dev_ioctl(sk, (struct ifreq __user *)arg,
181 cmd);
182 default:
183 if (!sk->sk_prot->ioctl)
184 return -ENOIOCTLCMD;
185 return sk->sk_prot->ioctl(sk, cmd, arg);
186 }
187}
188
189static const struct proto_ops ieee802154_raw_ops = {
190 .family = PF_IEEE802154,
191 .owner = THIS_MODULE,
192 .release = ieee802154_sock_release,
193 .bind = ieee802154_sock_bind,
194 .connect = ieee802154_sock_connect,
195 .socketpair = sock_no_socketpair,
196 .accept = sock_no_accept,
197 .getname = sock_no_getname,
198 .poll = datagram_poll,
199 .ioctl = ieee802154_sock_ioctl,
200 .listen = sock_no_listen,
201 .shutdown = sock_no_shutdown,
202 .setsockopt = sock_common_setsockopt,
203 .getsockopt = sock_common_getsockopt,
204 .sendmsg = ieee802154_sock_sendmsg,
205 .recvmsg = sock_common_recvmsg,
206 .mmap = sock_no_mmap,
207 .sendpage = sock_no_sendpage,
208#ifdef CONFIG_COMPAT
209 .compat_setsockopt = compat_sock_common_setsockopt,
210 .compat_getsockopt = compat_sock_common_getsockopt,
211#endif
212};
213
214static const struct proto_ops ieee802154_dgram_ops = {
215 .family = PF_IEEE802154,
216 .owner = THIS_MODULE,
217 .release = ieee802154_sock_release,
218 .bind = ieee802154_sock_bind,
219 .connect = ieee802154_sock_connect,
220 .socketpair = sock_no_socketpair,
221 .accept = sock_no_accept,
222 .getname = sock_no_getname,
223 .poll = datagram_poll,
224 .ioctl = ieee802154_sock_ioctl,
225 .listen = sock_no_listen,
226 .shutdown = sock_no_shutdown,
227 .setsockopt = sock_common_setsockopt,
228 .getsockopt = sock_common_getsockopt,
229 .sendmsg = ieee802154_sock_sendmsg,
230 .recvmsg = sock_common_recvmsg,
231 .mmap = sock_no_mmap,
232 .sendpage = sock_no_sendpage,
233#ifdef CONFIG_COMPAT
234 .compat_setsockopt = compat_sock_common_setsockopt,
235 .compat_getsockopt = compat_sock_common_getsockopt,
236#endif
237};
238
239
240/*
241 * Create a socket. Initialise the socket, blank the addresses
242 * set the state.
243 */
244static int ieee802154_create(struct net *net, struct socket *sock,
245 int protocol)
246{
247 struct sock *sk;
248 int rc;
249 struct proto *proto;
250 const struct proto_ops *ops;
251
252 if (net != &init_net)
253 return -EAFNOSUPPORT;
254
255 switch (sock->type) {
256 case SOCK_RAW:
257 proto = &ieee802154_raw_prot;
258 ops = &ieee802154_raw_ops;
259 break;
260 case SOCK_DGRAM:
261 proto = &ieee802154_dgram_prot;
262 ops = &ieee802154_dgram_ops;
263 break;
264 default:
265 rc = -ESOCKTNOSUPPORT;
266 goto out;
267 }
268
269 rc = -ENOMEM;
270 sk = sk_alloc(net, PF_IEEE802154, GFP_KERNEL, proto);
271 if (!sk)
272 goto out;
273 rc = 0;
274
275 sock->ops = ops;
276
277 sock_init_data(sock, sk);
278 /* FIXME: sk->sk_destruct */
279 sk->sk_family = PF_IEEE802154;
280
281 /* Checksums on by default */
282 sock_set_flag(sk, SOCK_ZAPPED);
283
284 if (sk->sk_prot->hash)
285 sk->sk_prot->hash(sk);
286
287 if (sk->sk_prot->init) {
288 rc = sk->sk_prot->init(sk);
289 if (rc)
290 sk_common_release(sk);
291 }
292out:
293 return rc;
294}
295
296static struct net_proto_family ieee802154_family_ops = {
297 .family = PF_IEEE802154,
298 .create = ieee802154_create,
299 .owner = THIS_MODULE,
300};
301
302static int ieee802154_rcv(struct sk_buff *skb, struct net_device *dev,
303 struct packet_type *pt, struct net_device *orig_dev)
304{
305 DBG_DUMP(skb->data, skb->len);
306 if (!netif_running(dev))
307 return -ENODEV;
308 pr_debug("got frame, type %d, dev %p\n", dev->type, dev);
309
310 if (!net_eq(dev_net(dev), &init_net))
311 goto drop;
312
313 ieee802154_raw_deliver(dev, skb);
314
315 if (dev->type != ARPHRD_IEEE802154)
316 goto drop;
317
318 if (skb->pkt_type != PACKET_OTHERHOST)
319 return ieee802154_dgram_deliver(dev, skb);
320
321drop:
322 kfree_skb(skb);
323 return NET_RX_DROP;
324}
325
326
327static struct packet_type ieee802154_packet_type = {
328 .type = __constant_htons(ETH_P_IEEE802154),
329 .func = ieee802154_rcv,
330};
331
332static int __init af_ieee802154_init(void)
333{
334 int rc = -EINVAL;
335
336 rc = proto_register(&ieee802154_raw_prot, 1);
337 if (rc)
338 goto out;
339
340 rc = proto_register(&ieee802154_dgram_prot, 1);
341 if (rc)
342 goto err_dgram;
343
344 /* Tell SOCKET that we are alive */
345 rc = sock_register(&ieee802154_family_ops);
346 if (rc)
347 goto err_sock;
348 dev_add_pack(&ieee802154_packet_type);
349
350 rc = 0;
351 goto out;
352
353err_sock:
354 proto_unregister(&ieee802154_dgram_prot);
355err_dgram:
356 proto_unregister(&ieee802154_raw_prot);
357out:
358 return rc;
359}
360static void __exit af_ieee802154_remove(void)
361{
362 dev_remove_pack(&ieee802154_packet_type);
363 sock_unregister(PF_IEEE802154);
364 proto_unregister(&ieee802154_dgram_prot);
365 proto_unregister(&ieee802154_raw_prot);
366}
367
368module_init(af_ieee802154_init);
369module_exit(af_ieee802154_remove);
370
371MODULE_LICENSE("GPL");
372MODULE_ALIAS_NETPROTO(PF_IEEE802154);
diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c
new file mode 100644
index 000000000000..1f5ea11c2fdf
--- /dev/null
+++ b/net/ieee802154/dgram.c
@@ -0,0 +1,394 @@
1/*
2 * ZigBee socket interface
3 *
4 * Copyright 2007, 2008 Siemens AG
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2
8 * as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Written by:
20 * Sergey Lapin <slapin@ossfans.org>
21 * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
22 */
23
24#include <linux/net.h>
25#include <linux/module.h>
26#include <linux/if_arp.h>
27#include <linux/list.h>
28#include <net/sock.h>
29#include <net/ieee802154/af_ieee802154.h>
30#include <net/ieee802154/mac_def.h>
31#include <net/ieee802154/netdevice.h>
32
33#include <asm/ioctls.h>
34
35#include "af802154.h"
36
37static HLIST_HEAD(dgram_head);
38static DEFINE_RWLOCK(dgram_lock);
39
40struct dgram_sock {
41 struct sock sk;
42
43 int bound;
44 struct ieee802154_addr src_addr;
45 struct ieee802154_addr dst_addr;
46};
47
48static inline struct dgram_sock *dgram_sk(const struct sock *sk)
49{
50 return container_of(sk, struct dgram_sock, sk);
51}
52
53
54static void dgram_hash(struct sock *sk)
55{
56 write_lock_bh(&dgram_lock);
57 sk_add_node(sk, &dgram_head);
58 sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
59 write_unlock_bh(&dgram_lock);
60}
61
62static void dgram_unhash(struct sock *sk)
63{
64 write_lock_bh(&dgram_lock);
65 if (sk_del_node_init(sk))
66 sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
67 write_unlock_bh(&dgram_lock);
68}
69
70static int dgram_init(struct sock *sk)
71{
72 struct dgram_sock *ro = dgram_sk(sk);
73
74 ro->dst_addr.addr_type = IEEE802154_ADDR_LONG;
75 ro->dst_addr.pan_id = 0xffff;
76 memset(&ro->dst_addr.hwaddr, 0xff, sizeof(ro->dst_addr.hwaddr));
77 return 0;
78}
79
80static void dgram_close(struct sock *sk, long timeout)
81{
82 sk_common_release(sk);
83}
84
85static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len)
86{
87 struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr;
88 struct dgram_sock *ro = dgram_sk(sk);
89 int err = 0;
90 struct net_device *dev;
91
92 ro->bound = 0;
93
94 if (len < sizeof(*addr))
95 return -EINVAL;
96
97 if (addr->family != AF_IEEE802154)
98 return -EINVAL;
99
100 lock_sock(sk);
101
102 dev = ieee802154_get_dev(sock_net(sk), &addr->addr);
103 if (!dev) {
104 err = -ENODEV;
105 goto out;
106 }
107
108 if (dev->type != ARPHRD_IEEE802154) {
109 err = -ENODEV;
110 goto out_put;
111 }
112
113 memcpy(&ro->src_addr, &addr->addr, sizeof(struct ieee802154_addr));
114
115 ro->bound = 1;
116out_put:
117 dev_put(dev);
118out:
119 release_sock(sk);
120
121 return err;
122}
123
124static int dgram_ioctl(struct sock *sk, int cmd, unsigned long arg)
125{
126 switch (cmd) {
127 case SIOCOUTQ:
128 {
129 int amount = atomic_read(&sk->sk_wmem_alloc);
130 return put_user(amount, (int __user *)arg);
131 }
132
133 case SIOCINQ:
134 {
135 struct sk_buff *skb;
136 unsigned long amount;
137
138 amount = 0;
139 spin_lock_bh(&sk->sk_receive_queue.lock);
140 skb = skb_peek(&sk->sk_receive_queue);
141 if (skb != NULL) {
142 /*
143 * We will only return the amount
144 * of this packet since that is all
145 * that will be read.
146 */
147 /* FIXME: parse the header for more correct value */
148 amount = skb->len - (3+8+8);
149 }
150 spin_unlock_bh(&sk->sk_receive_queue.lock);
151 return put_user(amount, (int __user *)arg);
152 }
153
154 }
155 return -ENOIOCTLCMD;
156}
157
158/* FIXME: autobind */
159static int dgram_connect(struct sock *sk, struct sockaddr *uaddr,
160 int len)
161{
162 struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr;
163 struct dgram_sock *ro = dgram_sk(sk);
164 int err = 0;
165
166 if (len < sizeof(*addr))
167 return -EINVAL;
168
169 if (addr->family != AF_IEEE802154)
170 return -EINVAL;
171
172 lock_sock(sk);
173
174 if (!ro->bound) {
175 err = -ENETUNREACH;
176 goto out;
177 }
178
179 memcpy(&ro->dst_addr, &addr->addr, sizeof(struct ieee802154_addr));
180
181out:
182 release_sock(sk);
183 return err;
184}
185
186static int dgram_disconnect(struct sock *sk, int flags)
187{
188 struct dgram_sock *ro = dgram_sk(sk);
189
190 lock_sock(sk);
191
192 ro->dst_addr.addr_type = IEEE802154_ADDR_LONG;
193 memset(&ro->dst_addr.hwaddr, 0xff, sizeof(ro->dst_addr.hwaddr));
194
195 release_sock(sk);
196
197 return 0;
198}
199
200static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk,
201 struct msghdr *msg, size_t size)
202{
203 struct net_device *dev;
204 unsigned mtu;
205 struct sk_buff *skb;
206 struct dgram_sock *ro = dgram_sk(sk);
207 int err;
208
209 if (msg->msg_flags & MSG_OOB) {
210 pr_debug("msg->msg_flags = 0x%x\n", msg->msg_flags);
211 return -EOPNOTSUPP;
212 }
213
214 if (!ro->bound)
215 dev = dev_getfirstbyhwtype(sock_net(sk), ARPHRD_IEEE802154);
216 else
217 dev = ieee802154_get_dev(sock_net(sk), &ro->src_addr);
218
219 if (!dev) {
220 pr_debug("no dev\n");
221 err = -ENXIO;
222 goto out;
223 }
224 mtu = dev->mtu;
225 pr_debug("name = %s, mtu = %u\n", dev->name, mtu);
226
227 skb = sock_alloc_send_skb(sk, LL_ALLOCATED_SPACE(dev) + size,
228 msg->msg_flags & MSG_DONTWAIT,
229 &err);
230 if (!skb)
231 goto out_dev;
232
233 skb_reserve(skb, LL_RESERVED_SPACE(dev));
234
235 skb_reset_network_header(skb);
236
237 mac_cb(skb)->flags = IEEE802154_FC_TYPE_DATA | MAC_CB_FLAG_ACKREQ;
238 mac_cb(skb)->seq = ieee802154_mlme_ops(dev)->get_dsn(dev);
239 err = dev_hard_header(skb, dev, ETH_P_IEEE802154, &ro->dst_addr,
240 ro->bound ? &ro->src_addr : NULL, size);
241 if (err < 0)
242 goto out_skb;
243
244 skb_reset_mac_header(skb);
245
246 err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
247 if (err < 0)
248 goto out_skb;
249
250 if (size > mtu) {
251 pr_debug("size = %u, mtu = %u\n", size, mtu);
252 err = -EINVAL;
253 goto out_skb;
254 }
255
256 skb->dev = dev;
257 skb->sk = sk;
258 skb->protocol = htons(ETH_P_IEEE802154);
259
260 dev_put(dev);
261
262 err = dev_queue_xmit(skb);
263 if (err > 0)
264 err = net_xmit_errno(err);
265
266 return err ?: size;
267
268out_skb:
269 kfree_skb(skb);
270out_dev:
271 dev_put(dev);
272out:
273 return err;
274}
275
276static int dgram_recvmsg(struct kiocb *iocb, struct sock *sk,
277 struct msghdr *msg, size_t len, int noblock, int flags,
278 int *addr_len)
279{
280 size_t copied = 0;
281 int err = -EOPNOTSUPP;
282 struct sk_buff *skb;
283
284 skb = skb_recv_datagram(sk, flags, noblock, &err);
285 if (!skb)
286 goto out;
287
288 copied = skb->len;
289 if (len < copied) {
290 msg->msg_flags |= MSG_TRUNC;
291 copied = len;
292 }
293
294 /* FIXME: skip headers if necessary ?! */
295 err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
296 if (err)
297 goto done;
298
299 sock_recv_timestamp(msg, sk, skb);
300
301 if (flags & MSG_TRUNC)
302 copied = skb->len;
303done:
304 skb_free_datagram(sk, skb);
305out:
306 if (err)
307 return err;
308 return copied;
309}
310
311static int dgram_rcv_skb(struct sock *sk, struct sk_buff *skb)
312{
313 if (sock_queue_rcv_skb(sk, skb) < 0) {
314 atomic_inc(&sk->sk_drops);
315 kfree_skb(skb);
316 return NET_RX_DROP;
317 }
318
319 return NET_RX_SUCCESS;
320}
321
322static inline int ieee802154_match_sock(u8 *hw_addr, u16 pan_id,
323 u16 short_addr, struct dgram_sock *ro)
324{
325 if (!ro->bound)
326 return 1;
327
328 if (ro->src_addr.addr_type == IEEE802154_ADDR_LONG &&
329 !memcmp(ro->src_addr.hwaddr, hw_addr, IEEE802154_ADDR_LEN))
330 return 1;
331
332 if (ro->src_addr.addr_type == IEEE802154_ADDR_SHORT &&
333 pan_id == ro->src_addr.pan_id &&
334 short_addr == ro->src_addr.short_addr)
335 return 1;
336
337 return 0;
338}
339
340int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb)
341{
342 struct sock *sk, *prev = NULL;
343 struct hlist_node *node;
344 int ret = NET_RX_SUCCESS;
345 u16 pan_id, short_addr;
346
347 /* Data frame processing */
348 BUG_ON(dev->type != ARPHRD_IEEE802154);
349
350 pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
351 short_addr = ieee802154_mlme_ops(dev)->get_short_addr(dev);
352
353 read_lock(&dgram_lock);
354 sk_for_each(sk, node, &dgram_head) {
355 if (ieee802154_match_sock(dev->dev_addr, pan_id, short_addr,
356 dgram_sk(sk))) {
357 if (prev) {
358 struct sk_buff *clone;
359 clone = skb_clone(skb, GFP_ATOMIC);
360 if (clone)
361 dgram_rcv_skb(prev, clone);
362 }
363
364 prev = sk;
365 }
366 }
367
368 if (prev)
369 dgram_rcv_skb(prev, skb);
370 else {
371 kfree_skb(skb);
372 ret = NET_RX_DROP;
373 }
374 read_unlock(&dgram_lock);
375
376 return ret;
377}
378
379struct proto ieee802154_dgram_prot = {
380 .name = "IEEE-802.15.4-MAC",
381 .owner = THIS_MODULE,
382 .obj_size = sizeof(struct dgram_sock),
383 .init = dgram_init,
384 .close = dgram_close,
385 .bind = dgram_bind,
386 .sendmsg = dgram_sendmsg,
387 .recvmsg = dgram_recvmsg,
388 .hash = dgram_hash,
389 .unhash = dgram_unhash,
390 .connect = dgram_connect,
391 .disconnect = dgram_disconnect,
392 .ioctl = dgram_ioctl,
393};
394
diff --git a/net/ieee802154/raw.c b/net/ieee802154/raw.c
new file mode 100644
index 000000000000..8b892e060491
--- /dev/null
+++ b/net/ieee802154/raw.c
@@ -0,0 +1,254 @@
1/*
2 * Raw IEEE 802.15.4 sockets
3 *
4 * Copyright 2007, 2008 Siemens AG
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2
8 * as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Written by:
20 * Sergey Lapin <slapin@ossfans.org>
21 * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
22 */
23
24#include <linux/net.h>
25#include <linux/module.h>
26#include <linux/if_arp.h>
27#include <linux/list.h>
28#include <net/sock.h>
29#include <net/ieee802154/af_ieee802154.h>
30
31#include "af802154.h"
32
33static HLIST_HEAD(raw_head);
34static DEFINE_RWLOCK(raw_lock);
35
36static void raw_hash(struct sock *sk)
37{
38 write_lock_bh(&raw_lock);
39 sk_add_node(sk, &raw_head);
40 sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
41 write_unlock_bh(&raw_lock);
42}
43
44static void raw_unhash(struct sock *sk)
45{
46 write_lock_bh(&raw_lock);
47 if (sk_del_node_init(sk))
48 sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
49 write_unlock_bh(&raw_lock);
50}
51
52static void raw_close(struct sock *sk, long timeout)
53{
54 sk_common_release(sk);
55}
56
57static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int len)
58{
59 struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr;
60 int err = 0;
61 struct net_device *dev = NULL;
62
63 if (len < sizeof(*addr))
64 return -EINVAL;
65
66 if (addr->family != AF_IEEE802154)
67 return -EINVAL;
68
69 lock_sock(sk);
70
71 dev = ieee802154_get_dev(sock_net(sk), &addr->addr);
72 if (!dev) {
73 err = -ENODEV;
74 goto out;
75 }
76
77 if (dev->type != ARPHRD_IEEE802154_PHY &&
78 dev->type != ARPHRD_IEEE802154) {
79 err = -ENODEV;
80 goto out_put;
81 }
82
83 sk->sk_bound_dev_if = dev->ifindex;
84 sk_dst_reset(sk);
85
86out_put:
87 dev_put(dev);
88out:
89 release_sock(sk);
90
91 return err;
92}
93
94static int raw_connect(struct sock *sk, struct sockaddr *uaddr,
95 int addr_len)
96{
97 return -ENOTSUPP;
98}
99
100static int raw_disconnect(struct sock *sk, int flags)
101{
102 return 0;
103}
104
105static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
106 size_t size)
107{
108 struct net_device *dev;
109 unsigned mtu;
110 struct sk_buff *skb;
111 int err;
112
113 if (msg->msg_flags & MSG_OOB) {
114 pr_debug("msg->msg_flags = 0x%x\n", msg->msg_flags);
115 return -EOPNOTSUPP;
116 }
117
118 lock_sock(sk);
119 if (!sk->sk_bound_dev_if)
120 dev = dev_getfirstbyhwtype(sock_net(sk), ARPHRD_IEEE802154);
121 else
122 dev = dev_get_by_index(sock_net(sk), sk->sk_bound_dev_if);
123 release_sock(sk);
124
125 if (!dev) {
126 pr_debug("no dev\n");
127 err = -ENXIO;
128 goto out;
129 }
130
131 mtu = dev->mtu;
132 pr_debug("name = %s, mtu = %u\n", dev->name, mtu);
133
134 if (size > mtu) {
135 pr_debug("size = %u, mtu = %u\n", size, mtu);
136 err = -EINVAL;
137 goto out_dev;
138 }
139
140 skb = sock_alloc_send_skb(sk, LL_ALLOCATED_SPACE(dev) + size,
141 msg->msg_flags & MSG_DONTWAIT, &err);
142 if (!skb)
143 goto out_dev;
144
145 skb_reserve(skb, LL_RESERVED_SPACE(dev));
146
147 skb_reset_mac_header(skb);
148 skb_reset_network_header(skb);
149
150 err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
151 if (err < 0)
152 goto out_skb;
153
154 skb->dev = dev;
155 skb->sk = sk;
156 skb->protocol = htons(ETH_P_IEEE802154);
157
158 dev_put(dev);
159
160 err = dev_queue_xmit(skb);
161 if (err > 0)
162 err = net_xmit_errno(err);
163
164 return err ?: size;
165
166out_skb:
167 kfree_skb(skb);
168out_dev:
169 dev_put(dev);
170out:
171 return err;
172}
173
174static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
175 size_t len, int noblock, int flags, int *addr_len)
176{
177 size_t copied = 0;
178 int err = -EOPNOTSUPP;
179 struct sk_buff *skb;
180
181 skb = skb_recv_datagram(sk, flags, noblock, &err);
182 if (!skb)
183 goto out;
184
185 copied = skb->len;
186 if (len < copied) {
187 msg->msg_flags |= MSG_TRUNC;
188 copied = len;
189 }
190
191 err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
192 if (err)
193 goto done;
194
195 sock_recv_timestamp(msg, sk, skb);
196
197 if (flags & MSG_TRUNC)
198 copied = skb->len;
199done:
200 skb_free_datagram(sk, skb);
201out:
202 if (err)
203 return err;
204 return copied;
205}
206
207static int raw_rcv_skb(struct sock *sk, struct sk_buff *skb)
208{
209 if (sock_queue_rcv_skb(sk, skb) < 0) {
210 atomic_inc(&sk->sk_drops);
211 kfree_skb(skb);
212 return NET_RX_DROP;
213 }
214
215 return NET_RX_SUCCESS;
216}
217
218
219void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb)
220{
221 struct sock *sk;
222 struct hlist_node *node;
223
224 read_lock(&raw_lock);
225 sk_for_each(sk, node, &raw_head) {
226 bh_lock_sock(sk);
227 if (!sk->sk_bound_dev_if ||
228 sk->sk_bound_dev_if == dev->ifindex) {
229
230 struct sk_buff *clone;
231
232 clone = skb_clone(skb, GFP_ATOMIC);
233 if (clone)
234 raw_rcv_skb(sk, clone);
235 }
236 bh_unlock_sock(sk);
237 }
238 read_unlock(&raw_lock);
239}
240
241struct proto ieee802154_raw_prot = {
242 .name = "IEEE-802.15.4-RAW",
243 .owner = THIS_MODULE,
244 .obj_size = sizeof(struct sock),
245 .close = raw_close,
246 .bind = raw_bind,
247 .sendmsg = raw_sendmsg,
248 .recvmsg = raw_recvmsg,
249 .hash = raw_hash,
250 .unhash = raw_unhash,
251 .connect = raw_connect,
252 .disconnect = raw_disconnect,
253};
254