blob: 83bb8a73d23c0f056b10a8c9061997a7b98e02a9 [file] [log] [blame]
Sergey Lapin9ec76712009-06-08 12:18:48 +00001/*
2 * An interface between IEEE802.15.4 device and rest of the kernel.
3 *
alex.bluesman.smirnov@gmail.com74a02fc2012-05-15 20:50:23 +00004 * Copyright (C) 2007-2012 Siemens AG
Sergey Lapin9ec76712009-06-08 12:18:48 +00005 *
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 *
Sergey Lapin9ec76712009-06-08 12:18:48 +000015 * Written by:
16 * Pavel Smolenskiy <pavel.smolenskiy@gmail.com>
17 * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
18 * Maxim Osipov <maxim.osipov@siemens.com>
19 * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
alex.bluesman.smirnov@gmail.com74a02fc2012-05-15 20:50:23 +000020 * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
Sergey Lapin9ec76712009-06-08 12:18:48 +000021 */
22
23#ifndef IEEE802154_NETDEVICE_H
24#define IEEE802154_NETDEVICE_H
25
alex.bluesman.smirnov@gmail.com1cd829c2012-05-15 20:50:21 +000026#include <net/af_ieee802154.h>
Phoebe Buckheister94b4f6c2014-03-14 21:24:00 +010027#include <linux/netdevice.h>
28#include <linux/skbuff.h>
Alexander Aring4ca24ac2014-10-25 09:41:04 +020029#include <linux/ieee802154.h>
Phoebe Buckheister94b4f6c2014-03-14 21:24:00 +010030
31struct ieee802154_sechdr {
32#if defined(__LITTLE_ENDIAN_BITFIELD)
33 u8 level:3,
34 key_id_mode:2,
35 reserved:3;
36#elif defined(__BIG_ENDIAN_BITFIELD)
37 u8 reserved:3,
38 key_id_mode:2,
39 level:3;
40#else
41#error "Please fix <asm/byteorder.h>"
42#endif
43 u8 key_id;
44 __le32 frame_counter;
45 union {
46 __le32 short_src;
47 __le64 extended_src;
48 };
49};
alex.bluesman.smirnov@gmail.com1cd829c2012-05-15 20:50:21 +000050
Phoebe Buckheister46ef0eb2014-03-14 21:23:58 +010051struct ieee802154_addr {
52 u8 mode;
53 __le16 pan_id;
54 union {
55 __le16 short_addr;
56 __le64 extended_addr;
57 };
58};
59
Phoebe Buckheister94b4f6c2014-03-14 21:24:00 +010060struct ieee802154_hdr_fc {
61#if defined(__LITTLE_ENDIAN_BITFIELD)
62 u16 type:3,
63 security_enabled:1,
64 frame_pending:1,
65 ack_request:1,
66 intra_pan:1,
67 reserved:3,
68 dest_addr_mode:2,
69 version:2,
70 source_addr_mode:2;
71#elif defined(__BIG_ENDIAN_BITFIELD)
72 u16 reserved:1,
73 intra_pan:1,
74 ack_request:1,
75 frame_pending:1,
76 security_enabled:1,
77 type:3,
78 source_addr_mode:2,
79 version:2,
80 dest_addr_mode:2,
81 reserved2:2;
82#else
83#error "Please fix <asm/byteorder.h>"
84#endif
85};
86
87struct ieee802154_hdr {
88 struct ieee802154_hdr_fc fc;
89 u8 seq;
90 struct ieee802154_addr source;
91 struct ieee802154_addr dest;
92 struct ieee802154_sechdr sec;
93};
94
95/* pushes hdr onto the skb. fields of hdr->fc that can be calculated from
96 * the contents of hdr will be, and the actual value of those bits in
97 * hdr->fc will be ignored. this includes the INTRA_PAN bit and the frame
98 * version, if SECEN is set.
99 */
100int ieee802154_hdr_push(struct sk_buff *skb, const struct ieee802154_hdr *hdr);
101
102/* pulls the entire 802.15.4 header off of the skb, including the security
103 * header, and performs pan id decompression
104 */
105int ieee802154_hdr_pull(struct sk_buff *skb, struct ieee802154_hdr *hdr);
106
107/* parses the frame control, sequence number of address fields in a given skb
108 * and stores them into hdr, performing pan id decompression and length checks
109 * to be suitable for use in header_ops.parse
110 */
111int ieee802154_hdr_peek_addrs(const struct sk_buff *skb,
112 struct ieee802154_hdr *hdr);
113
Phoebe Buckheisterc3a61142014-05-14 17:43:06 +0200114/* parses the full 802.15.4 header a given skb and stores them into hdr,
115 * performing pan id decompression and length checks to be suitable for use in
116 * header_ops.parse
117 */
118int ieee802154_hdr_peek(const struct sk_buff *skb, struct ieee802154_hdr *hdr);
119
120int ieee802154_max_payload(const struct ieee802154_hdr *hdr);
121
122static inline int
123ieee802154_sechdr_authtag_len(const struct ieee802154_sechdr *sec)
124{
125 switch (sec->level) {
126 case IEEE802154_SCF_SECLEVEL_MIC32:
127 case IEEE802154_SCF_SECLEVEL_ENC_MIC32:
128 return 4;
129 case IEEE802154_SCF_SECLEVEL_MIC64:
130 case IEEE802154_SCF_SECLEVEL_ENC_MIC64:
131 return 8;
132 case IEEE802154_SCF_SECLEVEL_MIC128:
133 case IEEE802154_SCF_SECLEVEL_ENC_MIC128:
134 return 16;
135 case IEEE802154_SCF_SECLEVEL_NONE:
136 case IEEE802154_SCF_SECLEVEL_ENC:
137 default:
138 return 0;
139 }
140}
141
Phoebe Buckheister94b4f6c2014-03-14 21:24:00 +0100142static inline int ieee802154_hdr_length(struct sk_buff *skb)
143{
144 struct ieee802154_hdr hdr;
145 int len = ieee802154_hdr_pull(skb, &hdr);
146
147 if (len > 0)
148 skb_push(skb, len);
149
150 return len;
151}
152
Phoebe Buckheister46ef0eb2014-03-14 21:23:58 +0100153static inline bool ieee802154_addr_equal(const struct ieee802154_addr *a1,
154 const struct ieee802154_addr *a2)
155{
156 if (a1->pan_id != a2->pan_id || a1->mode != a2->mode)
157 return false;
158
159 if ((a1->mode == IEEE802154_ADDR_LONG &&
160 a1->extended_addr != a2->extended_addr) ||
161 (a1->mode == IEEE802154_ADDR_SHORT &&
162 a1->short_addr != a2->short_addr))
163 return false;
164
165 return true;
166}
167
168static inline __le64 ieee802154_devaddr_from_raw(const void *raw)
169{
170 u64 temp;
171
172 memcpy(&temp, raw, IEEE802154_ADDR_LEN);
173 return (__force __le64)swab64(temp);
174}
175
176static inline void ieee802154_devaddr_to_raw(void *raw, __le64 addr)
177{
178 u64 temp = swab64((__force u64)addr);
179
180 memcpy(raw, &temp, IEEE802154_ADDR_LEN);
181}
182
183static inline void ieee802154_addr_from_sa(struct ieee802154_addr *a,
184 const struct ieee802154_addr_sa *sa)
185{
186 a->mode = sa->addr_type;
187 a->pan_id = cpu_to_le16(sa->pan_id);
188
189 switch (a->mode) {
190 case IEEE802154_ADDR_SHORT:
191 a->short_addr = cpu_to_le16(sa->short_addr);
192 break;
193 case IEEE802154_ADDR_LONG:
194 a->extended_addr = ieee802154_devaddr_from_raw(sa->hwaddr);
195 break;
196 }
197}
198
199static inline void ieee802154_addr_to_sa(struct ieee802154_addr_sa *sa,
200 const struct ieee802154_addr *a)
201{
202 sa->addr_type = a->mode;
203 sa->pan_id = le16_to_cpu(a->pan_id);
204
205 switch (a->mode) {
206 case IEEE802154_ADDR_SHORT:
207 sa->short_addr = le16_to_cpu(a->short_addr);
208 break;
209 case IEEE802154_ADDR_LONG:
210 ieee802154_devaddr_to_raw(sa->hwaddr, a->extended_addr);
211 break;
212 }
213}
214
Sergey Lapin9ec76712009-06-08 12:18:48 +0000215/*
216 * A control block of skb passed between the ARPHRD_IEEE802154 device
217 * and other stack parts.
218 */
219struct ieee802154_mac_cb {
220 u8 lqi;
Phoebe Buckheister32edc402014-05-14 17:43:08 +0200221 u8 type;
222 bool ackreq;
223 bool secen;
Phoebe Buckheisterf30be4d2014-05-16 17:46:40 +0200224 bool secen_override;
225 u8 seclevel;
226 bool seclevel_override;
Phoebe Buckheisterae531b92014-03-14 21:24:02 +0100227 struct ieee802154_addr source;
228 struct ieee802154_addr dest;
Sergey Lapin9ec76712009-06-08 12:18:48 +0000229};
230
231static inline struct ieee802154_mac_cb *mac_cb(struct sk_buff *skb)
232{
233 return (struct ieee802154_mac_cb *)skb->cb;
234}
235
Phoebe Buckheister32edc402014-05-14 17:43:08 +0200236static inline struct ieee802154_mac_cb *mac_cb_init(struct sk_buff *skb)
Sergey Lapin9ec76712009-06-08 12:18:48 +0000237{
Phoebe Buckheister32edc402014-05-14 17:43:08 +0200238 BUILD_BUG_ON(sizeof(struct ieee802154_mac_cb) > sizeof(skb->cb));
Sergey Lapin9ec76712009-06-08 12:18:48 +0000239
Phoebe Buckheister32edc402014-05-14 17:43:08 +0200240 memset(skb->cb, 0, sizeof(struct ieee802154_mac_cb));
241 return mac_cb(skb);
Sergey Lapin9ec76712009-06-08 12:18:48 +0000242}
243
Phoebe Buckheisterdc207592014-05-16 17:46:35 +0200244#define IEEE802154_LLSEC_KEY_SIZE 16
245
246struct ieee802154_llsec_key_id {
247 u8 mode;
248 u8 id;
249 union {
250 struct ieee802154_addr device_addr;
251 __le32 short_source;
252 __le64 extended_source;
253 };
254};
255
256struct ieee802154_llsec_key {
257 u8 frame_types;
258 u32 cmd_frame_ids;
259 u8 key[IEEE802154_LLSEC_KEY_SIZE];
260};
261
262struct ieee802154_llsec_key_entry {
263 struct list_head list;
264
265 struct ieee802154_llsec_key_id id;
266 struct ieee802154_llsec_key *key;
267};
268
269struct ieee802154_llsec_device_key {
270 struct list_head list;
271
272 struct ieee802154_llsec_key_id key_id;
273 u32 frame_counter;
274};
275
276enum {
277 IEEE802154_LLSEC_DEVKEY_IGNORE,
278 IEEE802154_LLSEC_DEVKEY_RESTRICT,
Phoebe Buckheisterf0f77dc2014-05-16 17:46:45 +0200279 IEEE802154_LLSEC_DEVKEY_RECORD,
Phoebe Buckheisterdc207592014-05-16 17:46:35 +0200280
281 __IEEE802154_LLSEC_DEVKEY_MAX,
282};
283
284struct ieee802154_llsec_device {
285 struct list_head list;
286
287 __le16 pan_id;
288 __le16 short_addr;
289 __le64 hwaddr;
290 u32 frame_counter;
291 bool seclevel_exempt;
292
293 u8 key_mode;
294 struct list_head keys;
295};
296
297struct ieee802154_llsec_seclevel {
298 struct list_head list;
299
300 u8 frame_type;
301 u8 cmd_frame_id;
302 bool device_override;
303 u32 sec_levels;
304};
305
306struct ieee802154_llsec_params {
307 bool enabled;
308
309 __be32 frame_counter;
310 u8 out_level;
311 struct ieee802154_llsec_key_id out_key;
312
313 __le64 default_key_source;
314
315 __le16 pan_id;
316 __le64 hwaddr;
317 __le64 coord_hwaddr;
318 __le16 coord_shortaddr;
319};
320
321struct ieee802154_llsec_table {
322 struct list_head keys;
323 struct list_head devices;
324 struct list_head security_levels;
325};
326
Sergey Lapin9ec76712009-06-08 12:18:48 +0000327#define IEEE802154_MAC_SCAN_ED 0
328#define IEEE802154_MAC_SCAN_ACTIVE 1
329#define IEEE802154_MAC_SCAN_PASSIVE 2
330#define IEEE802154_MAC_SCAN_ORPHAN 3
331
Phoebe Buckheistere462ded2014-03-31 21:37:46 +0200332struct ieee802154_mac_params {
333 s8 transmit_power;
334 u8 min_be;
335 u8 max_be;
336 u8 csma_retries;
337 s8 frame_retries;
338
339 bool lbt;
340 u8 cca_mode;
341 s32 cca_ed_level;
342};
343
Dmitry Eremin-Solenikov42723442009-11-04 17:53:23 +0300344struct wpan_phy;
Phoebe Buckheisterdc207592014-05-16 17:46:35 +0200345
346enum {
347 IEEE802154_LLSEC_PARAM_ENABLED = 1 << 0,
348 IEEE802154_LLSEC_PARAM_FRAME_COUNTER = 1 << 1,
349 IEEE802154_LLSEC_PARAM_OUT_LEVEL = 1 << 2,
350 IEEE802154_LLSEC_PARAM_OUT_KEY = 1 << 3,
351 IEEE802154_LLSEC_PARAM_KEY_SOURCE = 1 << 4,
352 IEEE802154_LLSEC_PARAM_PAN_ID = 1 << 5,
353 IEEE802154_LLSEC_PARAM_HWADDR = 1 << 6,
354 IEEE802154_LLSEC_PARAM_COORD_HWADDR = 1 << 7,
355 IEEE802154_LLSEC_PARAM_COORD_SHORTADDR = 1 << 8,
356};
357
Phoebe Buckheister29e02372014-05-16 17:46:42 +0200358struct ieee802154_llsec_ops {
359 int (*get_params)(struct net_device *dev,
360 struct ieee802154_llsec_params *params);
361 int (*set_params)(struct net_device *dev,
362 const struct ieee802154_llsec_params *params,
363 int changed);
364
365 int (*add_key)(struct net_device *dev,
366 const struct ieee802154_llsec_key_id *id,
367 const struct ieee802154_llsec_key *key);
368 int (*del_key)(struct net_device *dev,
369 const struct ieee802154_llsec_key_id *id);
370
371 int (*add_dev)(struct net_device *dev,
372 const struct ieee802154_llsec_device *llsec_dev);
373 int (*del_dev)(struct net_device *dev, __le64 dev_addr);
374
375 int (*add_devkey)(struct net_device *dev,
376 __le64 device_addr,
377 const struct ieee802154_llsec_device_key *key);
378 int (*del_devkey)(struct net_device *dev,
379 __le64 device_addr,
380 const struct ieee802154_llsec_device_key *key);
381
382 int (*add_seclevel)(struct net_device *dev,
383 const struct ieee802154_llsec_seclevel *sl);
384 int (*del_seclevel)(struct net_device *dev,
385 const struct ieee802154_llsec_seclevel *sl);
386
387 void (*lock_table)(struct net_device *dev);
388 void (*get_table)(struct net_device *dev,
389 struct ieee802154_llsec_table **t);
390 void (*unlock_table)(struct net_device *dev);
391};
Sergey Lapin9ec76712009-06-08 12:18:48 +0000392/*
393 * This should be located at net_device->ml_priv
Dmitry Eremin-Solenikov42723442009-11-04 17:53:23 +0300394 *
395 * get_phy should increment the reference counting on returned phy.
396 * Use wpan_wpy_put to put that reference.
Sergey Lapin9ec76712009-06-08 12:18:48 +0000397 */
398struct ieee802154_mlme_ops {
Werner Almesberger56aa0912013-04-04 06:32:35 +0000399 /* The following fields are optional (can be NULL). */
400
Sergey Lapin9ec76712009-06-08 12:18:48 +0000401 int (*assoc_req)(struct net_device *dev,
Phoebe Buckheisterae531b92014-03-14 21:24:02 +0100402 struct ieee802154_addr *addr,
Dmitry Eremin-Solenikov16eea492009-08-19 19:32:24 +0400403 u8 channel, u8 page, u8 cap);
Sergey Lapin9ec76712009-06-08 12:18:48 +0000404 int (*assoc_resp)(struct net_device *dev,
Phoebe Buckheisterae531b92014-03-14 21:24:02 +0100405 struct ieee802154_addr *addr,
Phoebe Buckheisterb70ab2e2014-03-14 21:23:59 +0100406 __le16 short_addr, u8 status);
Sergey Lapin9ec76712009-06-08 12:18:48 +0000407 int (*disassoc_req)(struct net_device *dev,
Phoebe Buckheisterae531b92014-03-14 21:24:02 +0100408 struct ieee802154_addr *addr,
Sergey Lapin9ec76712009-06-08 12:18:48 +0000409 u8 reason);
410 int (*start_req)(struct net_device *dev,
Phoebe Buckheisterae531b92014-03-14 21:24:02 +0100411 struct ieee802154_addr *addr,
Dmitry Eremin-Solenikov16eea492009-08-19 19:32:24 +0400412 u8 channel, u8 page, u8 bcn_ord, u8 sf_ord,
Sergey Lapin9ec76712009-06-08 12:18:48 +0000413 u8 pan_coord, u8 blx, u8 coord_realign);
414 int (*scan_req)(struct net_device *dev,
Dmitry Eremin-Solenikov16eea492009-08-19 19:32:24 +0400415 u8 type, u32 channels, u8 page, u8 duration);
Sergey Lapin9ec76712009-06-08 12:18:48 +0000416
Phoebe Buckheistere462ded2014-03-31 21:37:46 +0200417 int (*set_mac_params)(struct net_device *dev,
418 const struct ieee802154_mac_params *params);
419 void (*get_mac_params)(struct net_device *dev,
420 struct ieee802154_mac_params *params);
421
Phoebe Buckheister29e02372014-05-16 17:46:42 +0200422 struct ieee802154_llsec_ops *llsec;
423
Werner Almesberger56aa0912013-04-04 06:32:35 +0000424 /* The fields below are required. */
425
Sergey Lapin9ec76712009-06-08 12:18:48 +0000426 /*
427 * FIXME: these should become the part of PIB/MIB interface.
428 * However we still don't have IB interface of any kind
429 */
Phoebe Buckheisterb70ab2e2014-03-14 21:23:59 +0100430 __le16 (*get_pan_id)(const struct net_device *dev);
431 __le16 (*get_short_addr)(const struct net_device *dev);
Dmitry Eremin-Solenikova9966b52009-10-02 19:05:00 +0400432 u8 (*get_dsn)(const struct net_device *dev);
Sergey Lapin9ec76712009-06-08 12:18:48 +0000433};
434
alex.bluesman.smirnov@gmail.com74a02fc2012-05-15 20:50:23 +0000435static inline struct ieee802154_mlme_ops *
436ieee802154_mlme_ops(const struct net_device *dev)
437{
438 return dev->ml_priv;
439}
440
441static inline struct ieee802154_reduced_mlme_ops *
442ieee802154_reduced_mlme_ops(const struct net_device *dev)
Sergey Lapin9ec76712009-06-08 12:18:48 +0000443{
444 return dev->ml_priv;
445}
446
447#endif