aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/uwb/wlp
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/uwb/wlp')
-rw-r--r--drivers/uwb/wlp/Makefile10
-rw-r--r--drivers/uwb/wlp/driver.c43
-rw-r--r--drivers/uwb/wlp/eda.c449
-rw-r--r--drivers/uwb/wlp/messages.c1946
-rw-r--r--drivers/uwb/wlp/sysfs.c709
-rw-r--r--drivers/uwb/wlp/txrx.c374
-rw-r--r--drivers/uwb/wlp/wlp-internal.h228
-rw-r--r--drivers/uwb/wlp/wlp-lc.c585
-rw-r--r--drivers/uwb/wlp/wss-lc.c1055
9 files changed, 5399 insertions, 0 deletions
diff --git a/drivers/uwb/wlp/Makefile b/drivers/uwb/wlp/Makefile
new file mode 100644
index 000000000000..c72c11db5b1b
--- /dev/null
+++ b/drivers/uwb/wlp/Makefile
@@ -0,0 +1,10 @@
1obj-$(CONFIG_UWB_WLP) := wlp.o
2
3wlp-objs := \
4 driver.o \
5 eda.o \
6 messages.o \
7 sysfs.o \
8 txrx.o \
9 wlp-lc.o \
10 wss-lc.o
diff --git a/drivers/uwb/wlp/driver.c b/drivers/uwb/wlp/driver.c
new file mode 100644
index 000000000000..cb8d699b6a67
--- /dev/null
+++ b/drivers/uwb/wlp/driver.c
@@ -0,0 +1,43 @@
1/*
2 * WiMedia Logical Link Control Protocol (WLP)
3 *
4 * Copyright (C) 2007 Intel Corporation
5 * Reinette Chatre <reinette.chatre@intel.com>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License version
9 * 2 as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301, USA.
20 *
21 *
22 * Life cycle of WLP substack
23 *
24 * FIXME: Docs
25 */
26
27#include <linux/module.h>
28
29static int __init wlp_subsys_init(void)
30{
31 return 0;
32}
33module_init(wlp_subsys_init);
34
35static void __exit wlp_subsys_exit(void)
36{
37 return;
38}
39module_exit(wlp_subsys_exit);
40
41MODULE_AUTHOR("Reinette Chatre <reinette.chatre@intel.com>");
42MODULE_DESCRIPTION("WiMedia Logical Link Control Protocol (WLP)");
43MODULE_LICENSE("GPL");
diff --git a/drivers/uwb/wlp/eda.c b/drivers/uwb/wlp/eda.c
new file mode 100644
index 000000000000..cdfe8dfc4340
--- /dev/null
+++ b/drivers/uwb/wlp/eda.c
@@ -0,0 +1,449 @@
1/*
2 * WUSB Wire Adapter: WLP interface
3 * Ethernet to device address cache
4 *
5 * Copyright (C) 2005-2006 Intel Corporation
6 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version
10 * 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA.
21 *
22 *
23 * We need to be able to map ethernet addresses to device addresses
24 * and back because there is not explicit relationship between the eth
25 * addresses used in the ETH frames and the device addresses (no, it
26 * would not have been simpler to force as ETH address the MBOA MAC
27 * address...no, not at all :).
28 *
29 * A device has one MBOA MAC address and one device address. It is possible
30 * for a device to have more than one virtual MAC address (although a
31 * virtual address can be the same as the MBOA MAC address). The device
32 * address is guaranteed to be unique among the devices in the extended
33 * beacon group (see ECMA 17.1.1). We thus use the device address as index
34 * to this cache. We do allow searching based on virtual address as this
35 * is how Ethernet frames will be addressed.
36 *
37 * We need to support virtual EUI-48. Although, right now the virtual
38 * EUI-48 will always be the same as the MAC SAP address. The EDA cache
39 * entry thus contains a MAC SAP address as well as the virtual address
40 * (used to map the network stack address to a neighbor). When we move
41 * to support more than one virtual MAC on a host then this organization
42 * will have to change. Perhaps a neighbor has a list of WSSs, each with a
43 * tag and virtual EUI-48.
44 *
45 * On data transmission
46 * it is used to determine if the neighbor is connected and what WSS it
47 * belongs to. With this we know what tag to add to the WLP frame. Storing
48 * the WSS in the EDA cache may be overkill because we only support one
49 * WSS. Hopefully we will support more than one WSS at some point.
50 * On data reception it is used to determine the WSS based on
51 * the tag and address of the transmitting neighbor.
52 */
53
54#define D_LOCAL 5
55#include <linux/netdevice.h>
56#include <linux/uwb/debug.h>
57#include <linux/etherdevice.h>
58#include <linux/wlp.h>
59#include "wlp-internal.h"
60
61
62/* FIXME: cache is not purged, only on device close */
63
64/* FIXME: does not scale, change to dynamic array */
65
66/*
67 * Initialize the EDA cache
68 *
69 * @returns 0 if ok, < 0 errno code on error
70 *
71 * Call when the interface is being brought up
72 *
73 * NOTE: Keep it as a separate function as the implementation will
74 * change and be more complex.
75 */
76void wlp_eda_init(struct wlp_eda *eda)
77{
78 INIT_LIST_HEAD(&eda->cache);
79 spin_lock_init(&eda->lock);
80}
81
82/*
83 * Release the EDA cache
84 *
85 * @returns 0 if ok, < 0 errno code on error
86 *
87 * Called when the interface is brought down
88 */
89void wlp_eda_release(struct wlp_eda *eda)
90{
91 unsigned long flags;
92 struct wlp_eda_node *itr, *next;
93
94 spin_lock_irqsave(&eda->lock, flags);
95 list_for_each_entry_safe(itr, next, &eda->cache, list_node) {
96 list_del(&itr->list_node);
97 kfree(itr);
98 }
99 spin_unlock_irqrestore(&eda->lock, flags);
100}
101
102/*
103 * Add an address mapping
104 *
105 * @returns 0 if ok, < 0 errno code on error
106 *
107 * An address mapping is initially created when the neighbor device is seen
108 * for the first time (it is "onair"). At this time the neighbor is not
109 * connected or associated with a WSS so we only populate the Ethernet and
110 * Device address fields.
111 *
112 */
113int wlp_eda_create_node(struct wlp_eda *eda,
114 const unsigned char eth_addr[ETH_ALEN],
115 const struct uwb_dev_addr *dev_addr)
116{
117 int result = 0;
118 struct wlp_eda_node *itr;
119 unsigned long flags;
120
121 BUG_ON(dev_addr == NULL || eth_addr == NULL);
122 spin_lock_irqsave(&eda->lock, flags);
123 list_for_each_entry(itr, &eda->cache, list_node) {
124 if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
125 printk(KERN_ERR "EDA cache already contains entry "
126 "for neighbor %02x:%02x\n",
127 dev_addr->data[1], dev_addr->data[0]);
128 result = -EEXIST;
129 goto out_unlock;
130 }
131 }
132 itr = kzalloc(sizeof(*itr), GFP_ATOMIC);
133 if (itr != NULL) {
134 memcpy(itr->eth_addr, eth_addr, sizeof(itr->eth_addr));
135 itr->dev_addr = *dev_addr;
136 list_add(&itr->list_node, &eda->cache);
137 } else
138 result = -ENOMEM;
139out_unlock:
140 spin_unlock_irqrestore(&eda->lock, flags);
141 return result;
142}
143
144/*
145 * Remove entry from EDA cache
146 *
147 * This is done when the device goes off air.
148 */
149void wlp_eda_rm_node(struct wlp_eda *eda, const struct uwb_dev_addr *dev_addr)
150{
151 struct wlp_eda_node *itr, *next;
152 unsigned long flags;
153
154 spin_lock_irqsave(&eda->lock, flags);
155 list_for_each_entry_safe(itr, next, &eda->cache, list_node) {
156 if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
157 list_del(&itr->list_node);
158 kfree(itr);
159 break;
160 }
161 }
162 spin_unlock_irqrestore(&eda->lock, flags);
163}
164
165/*
166 * Update an address mapping
167 *
168 * @returns 0 if ok, < 0 errno code on error
169 */
170int wlp_eda_update_node(struct wlp_eda *eda,
171 const struct uwb_dev_addr *dev_addr,
172 struct wlp_wss *wss,
173 const unsigned char virt_addr[ETH_ALEN],
174 const u8 tag, const enum wlp_wss_connect state)
175{
176 int result = -ENOENT;
177 struct wlp_eda_node *itr;
178 unsigned long flags;
179
180 spin_lock_irqsave(&eda->lock, flags);
181 list_for_each_entry(itr, &eda->cache, list_node) {
182 if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
183 /* Found it, update it */
184 itr->wss = wss;
185 memcpy(itr->virt_addr, virt_addr,
186 sizeof(itr->virt_addr));
187 itr->tag = tag;
188 itr->state = state;
189 result = 0;
190 goto out_unlock;
191 }
192 }
193 /* Not found */
194out_unlock:
195 spin_unlock_irqrestore(&eda->lock, flags);
196 return result;
197}
198
199/*
200 * Update only state field of an address mapping
201 *
202 * @returns 0 if ok, < 0 errno code on error
203 */
204int wlp_eda_update_node_state(struct wlp_eda *eda,
205 const struct uwb_dev_addr *dev_addr,
206 const enum wlp_wss_connect state)
207{
208 int result = -ENOENT;
209 struct wlp_eda_node *itr;
210 unsigned long flags;
211
212 spin_lock_irqsave(&eda->lock, flags);
213 list_for_each_entry(itr, &eda->cache, list_node) {
214 if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
215 /* Found it, update it */
216 itr->state = state;
217 result = 0;
218 goto out_unlock;
219 }
220 }
221 /* Not found */
222out_unlock:
223 spin_unlock_irqrestore(&eda->lock, flags);
224 return result;
225}
226
227/*
228 * Return contents of EDA cache entry
229 *
230 * @dev_addr: index to EDA cache
231 * @eda_entry: pointer to where contents of EDA cache will be copied
232 */
233int wlp_copy_eda_node(struct wlp_eda *eda, struct uwb_dev_addr *dev_addr,
234 struct wlp_eda_node *eda_entry)
235{
236 int result = -ENOENT;
237 struct wlp_eda_node *itr;
238 unsigned long flags;
239
240 spin_lock_irqsave(&eda->lock, flags);
241 list_for_each_entry(itr, &eda->cache, list_node) {
242 if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
243 *eda_entry = *itr;
244 result = 0;
245 goto out_unlock;
246 }
247 }
248 /* Not found */
249out_unlock:
250 spin_unlock_irqrestore(&eda->lock, flags);
251 return result;
252}
253
254/*
255 * Execute function for every element in the cache
256 *
257 * @function: function to execute on element of cache (must be atomic)
258 * @priv: private data of function
259 * @returns: result of first function that failed, or last function
260 * executed if no function failed.
261 *
262 * Stop executing when function returns error for any element in cache.
263 *
264 * IMPORTANT: We are using a spinlock here: the function executed on each
265 * element has to be atomic.
266 */
267int wlp_eda_for_each(struct wlp_eda *eda, wlp_eda_for_each_f function,
268 void *priv)
269{
270 int result = 0;
271 struct wlp *wlp = container_of(eda, struct wlp, eda);
272 struct wlp_eda_node *entry;
273 unsigned long flags;
274
275 spin_lock_irqsave(&eda->lock, flags);
276 list_for_each_entry(entry, &eda->cache, list_node) {
277 result = (*function)(wlp, entry, priv);
278 if (result < 0)
279 break;
280 }
281 spin_unlock_irqrestore(&eda->lock, flags);
282 return result;
283}
284
285/*
286 * Execute function for single element in the cache (return dev addr)
287 *
288 * @virt_addr: index into EDA cache used to determine which element to
289 * execute the function on
290 * @dev_addr: device address of element in cache will be returned using
291 * @dev_addr
292 * @function: function to execute on element of cache (must be atomic)
293 * @priv: private data of function
294 * @returns: result of function
295 *
296 * IMPORTANT: We are using a spinlock here: the function executed on the
297 * element has to be atomic.
298 */
299int wlp_eda_for_virtual(struct wlp_eda *eda,
300 const unsigned char virt_addr[ETH_ALEN],
301 struct uwb_dev_addr *dev_addr,
302 wlp_eda_for_each_f function,
303 void *priv)
304{
305 int result = 0;
306 struct wlp *wlp = container_of(eda, struct wlp, eda);
307 struct device *dev = &wlp->rc->uwb_dev.dev;
308 struct wlp_eda_node *itr;
309 unsigned long flags;
310 int found = 0;
311
312 spin_lock_irqsave(&eda->lock, flags);
313 list_for_each_entry(itr, &eda->cache, list_node) {
314 if (!memcmp(itr->virt_addr, virt_addr,
315 sizeof(itr->virt_addr))) {
316 d_printf(6, dev, "EDA: looking for "
317 "%02x:%02x:%02x:%02x:%02x:%02x hit %02x:%02x "
318 "wss %p tag 0x%02x state %u\n",
319 virt_addr[0], virt_addr[1],
320 virt_addr[2], virt_addr[3],
321 virt_addr[4], virt_addr[5],
322 itr->dev_addr.data[1],
323 itr->dev_addr.data[0], itr->wss,
324 itr->tag, itr->state);
325 result = (*function)(wlp, itr, priv);
326 *dev_addr = itr->dev_addr;
327 found = 1;
328 break;
329 } else
330 d_printf(6, dev, "EDA: looking for "
331 "%02x:%02x:%02x:%02x:%02x:%02x "
332 "against "
333 "%02x:%02x:%02x:%02x:%02x:%02x miss\n",
334 virt_addr[0], virt_addr[1],
335 virt_addr[2], virt_addr[3],
336 virt_addr[4], virt_addr[5],
337 itr->virt_addr[0], itr->virt_addr[1],
338 itr->virt_addr[2], itr->virt_addr[3],
339 itr->virt_addr[4], itr->virt_addr[5]);
340 }
341 if (!found) {
342 if (printk_ratelimit())
343 dev_err(dev, "EDA: Eth addr %02x:%02x:%02x"
344 ":%02x:%02x:%02x not found.\n",
345 virt_addr[0], virt_addr[1],
346 virt_addr[2], virt_addr[3],
347 virt_addr[4], virt_addr[5]);
348 result = -ENODEV;
349 }
350 spin_unlock_irqrestore(&eda->lock, flags);
351 return result;
352}
353
354static const char *__wlp_wss_connect_state[] = { "WLP_WSS_UNCONNECTED",
355 "WLP_WSS_CONNECTED",
356 "WLP_WSS_CONNECT_FAILED",
357};
358
359static const char *wlp_wss_connect_state_str(unsigned id)
360{
361 if (id >= ARRAY_SIZE(__wlp_wss_connect_state))
362 return "unknown WSS connection state";
363 return __wlp_wss_connect_state[id];
364}
365
366/*
367 * View EDA cache from user space
368 *
369 * A debugging feature to give user visibility into the EDA cache. Also
370 * used to display members of WSS to user (called from wlp_wss_members_show())
371 */
372ssize_t wlp_eda_show(struct wlp *wlp, char *buf)
373{
374 ssize_t result = 0;
375 struct wlp_eda_node *entry;
376 unsigned long flags;
377 struct wlp_eda *eda = &wlp->eda;
378 spin_lock_irqsave(&eda->lock, flags);
379 result = scnprintf(buf, PAGE_SIZE, "#eth_addr dev_addr wss_ptr "
380 "tag state virt_addr\n");
381 list_for_each_entry(entry, &eda->cache, list_node) {
382 result += scnprintf(buf + result, PAGE_SIZE - result,
383 "%02x:%02x:%02x:%02x:%02x:%02x %02x:%02x "
384 "%p 0x%02x %s "
385 "%02x:%02x:%02x:%02x:%02x:%02x\n",
386 entry->eth_addr[0], entry->eth_addr[1],
387 entry->eth_addr[2], entry->eth_addr[3],
388 entry->eth_addr[4], entry->eth_addr[5],
389 entry->dev_addr.data[1],
390 entry->dev_addr.data[0], entry->wss,
391 entry->tag,
392 wlp_wss_connect_state_str(entry->state),
393 entry->virt_addr[0], entry->virt_addr[1],
394 entry->virt_addr[2], entry->virt_addr[3],
395 entry->virt_addr[4], entry->virt_addr[5]);
396 if (result >= PAGE_SIZE)
397 break;
398 }
399 spin_unlock_irqrestore(&eda->lock, flags);
400 return result;
401}
402EXPORT_SYMBOL_GPL(wlp_eda_show);
403
404/*
405 * Add new EDA cache entry based on user input in sysfs
406 *
407 * Should only be used for debugging.
408 *
409 * The WSS is assumed to be the only WSS supported. This needs to be
410 * redesigned when we support more than one WSS.
411 */
412ssize_t wlp_eda_store(struct wlp *wlp, const char *buf, size_t size)
413{
414 ssize_t result;
415 struct wlp_eda *eda = &wlp->eda;
416 u8 eth_addr[6];
417 struct uwb_dev_addr dev_addr;
418 u8 tag;
419 unsigned state;
420
421 result = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx "
422 "%02hhx:%02hhx %02hhx %u\n",
423 &eth_addr[0], &eth_addr[1],
424 &eth_addr[2], &eth_addr[3],
425 &eth_addr[4], &eth_addr[5],
426 &dev_addr.data[1], &dev_addr.data[0], &tag, &state);
427 switch (result) {
428 case 6: /* no dev addr specified -- remove entry NOT IMPLEMENTED */
429 /*result = wlp_eda_rm(eda, eth_addr, &dev_addr);*/
430 result = -ENOSYS;
431 break;
432 case 10:
433 state = state >= 1 ? 1 : 0;
434 result = wlp_eda_create_node(eda, eth_addr, &dev_addr);
435 if (result < 0 && result != -EEXIST)
436 goto error;
437 /* Set virtual addr to be same as MAC */
438 result = wlp_eda_update_node(eda, &dev_addr, &wlp->wss,
439 eth_addr, tag, state);
440 if (result < 0)
441 goto error;
442 break;
443 default: /* bad format */
444 result = -EINVAL;
445 }
446error:
447 return result < 0 ? result : size;
448}
449EXPORT_SYMBOL_GPL(wlp_eda_store);
diff --git a/drivers/uwb/wlp/messages.c b/drivers/uwb/wlp/messages.c
new file mode 100644
index 000000000000..a64cb8241713
--- /dev/null
+++ b/drivers/uwb/wlp/messages.c
@@ -0,0 +1,1946 @@
1/*
2 * WiMedia Logical Link Control Protocol (WLP)
3 * Message construction and parsing
4 *
5 * Copyright (C) 2007 Intel Corporation
6 * Reinette Chatre <reinette.chatre@intel.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version
10 * 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA.
21 *
22 *
23 * FIXME: docs
24 */
25
26#include <linux/wlp.h>
27#define D_LOCAL 6
28#include <linux/uwb/debug.h>
29#include "wlp-internal.h"
30
31static
32const char *__wlp_assoc_frame[] = {
33 [WLP_ASSOC_D1] = "WLP_ASSOC_D1",
34 [WLP_ASSOC_D2] = "WLP_ASSOC_D2",
35 [WLP_ASSOC_M1] = "WLP_ASSOC_M1",
36 [WLP_ASSOC_M2] = "WLP_ASSOC_M2",
37 [WLP_ASSOC_M3] = "WLP_ASSOC_M3",
38 [WLP_ASSOC_M4] = "WLP_ASSOC_M4",
39 [WLP_ASSOC_M5] = "WLP_ASSOC_M5",
40 [WLP_ASSOC_M6] = "WLP_ASSOC_M6",
41 [WLP_ASSOC_M7] = "WLP_ASSOC_M7",
42 [WLP_ASSOC_M8] = "WLP_ASSOC_M8",
43 [WLP_ASSOC_F0] = "WLP_ASSOC_F0",
44 [WLP_ASSOC_E1] = "WLP_ASSOC_E1",
45 [WLP_ASSOC_E2] = "WLP_ASSOC_E2",
46 [WLP_ASSOC_C1] = "WLP_ASSOC_C1",
47 [WLP_ASSOC_C2] = "WLP_ASSOC_C2",
48 [WLP_ASSOC_C3] = "WLP_ASSOC_C3",
49 [WLP_ASSOC_C4] = "WLP_ASSOC_C4",
50};
51
52static const char *wlp_assoc_frame_str(unsigned id)
53{
54 if (id >= ARRAY_SIZE(__wlp_assoc_frame))
55 return "unknown association frame";
56 return __wlp_assoc_frame[id];
57}
58
59static const char *__wlp_assc_error[] = {
60 "none",
61 "Authenticator Failure",
62 "Rogue activity suspected",
63 "Device busy",
64 "Setup Locked",
65 "Registrar not ready",
66 "Invalid WSS selection",
67 "Message timeout",
68 "Enrollment session timeout",
69 "Device password invalid",
70 "Unsupported version",
71 "Internal error",
72 "Undefined error",
73 "Numeric comparison failure",
74 "Waiting for user input",
75};
76
77static const char *wlp_assc_error_str(unsigned id)
78{
79 if (id >= ARRAY_SIZE(__wlp_assc_error))
80 return "unknown WLP association error";
81 return __wlp_assc_error[id];
82}
83
84static inline void wlp_set_attr_hdr(struct wlp_attr_hdr *hdr, unsigned type,
85 size_t len)
86{
87 hdr->type = cpu_to_le16(type);
88 hdr->length = cpu_to_le16(len);
89}
90
91/*
92 * Populate fields of a constant sized attribute
93 *
94 * @returns: total size of attribute including size of new value
95 *
96 * We have two instances of this function (wlp_pset and wlp_set): one takes
97 * the value as a parameter, the other takes a pointer to the value as
98 * parameter. They thus only differ in how the value is assigned to the
99 * attribute.
100 *
101 * We use sizeof(*attr) - sizeof(struct wlp_attr_hdr) instead of
102 * sizeof(type) to be able to use this same code for the structures that
103 * contain 8bit enum values and be able to deal with pointer types.
104 */
105#define wlp_set(type, type_code, name) \
106static size_t wlp_set_##name(struct wlp_attr_##name *attr, type value) \
107{ \
108 d_fnstart(6, NULL, "(attribute %p)\n", attr); \
109 wlp_set_attr_hdr(&attr->hdr, type_code, \
110 sizeof(*attr) - sizeof(struct wlp_attr_hdr)); \
111 attr->name = value; \
112 d_dump(6, NULL, attr, sizeof(*attr)); \
113 d_fnend(6, NULL, "(attribute %p)\n", attr); \
114 return sizeof(*attr); \
115}
116
117#define wlp_pset(type, type_code, name) \
118static size_t wlp_set_##name(struct wlp_attr_##name *attr, type value) \
119{ \
120 d_fnstart(6, NULL, "(attribute %p)\n", attr); \
121 wlp_set_attr_hdr(&attr->hdr, type_code, \
122 sizeof(*attr) - sizeof(struct wlp_attr_hdr)); \
123 attr->name = *value; \
124 d_dump(6, NULL, attr, sizeof(*attr)); \
125 d_fnend(6, NULL, "(attribute %p)\n", attr); \
126 return sizeof(*attr); \
127}
128
129/**
130 * Populate fields of a variable attribute
131 *
132 * @returns: total size of attribute including size of new value
133 *
134 * Provided with a pointer to the memory area reserved for the
135 * attribute structure, the field is populated with the value. The
136 * reserved memory has to contain enough space for the value.
137 */
138#define wlp_vset(type, type_code, name) \
139static size_t wlp_set_##name(struct wlp_attr_##name *attr, type value, \
140 size_t len) \
141{ \
142 d_fnstart(6, NULL, "(attribute %p)\n", attr); \
143 wlp_set_attr_hdr(&attr->hdr, type_code, len); \
144 memcpy(attr->name, value, len); \
145 d_dump(6, NULL, attr, sizeof(*attr) + len); \
146 d_fnend(6, NULL, "(attribute %p)\n", attr); \
147 return sizeof(*attr) + len; \
148}
149
150wlp_vset(char *, WLP_ATTR_DEV_NAME, dev_name)
151wlp_vset(char *, WLP_ATTR_MANUF, manufacturer)
152wlp_set(enum wlp_assoc_type, WLP_ATTR_MSG_TYPE, msg_type)
153wlp_vset(char *, WLP_ATTR_MODEL_NAME, model_name)
154wlp_vset(char *, WLP_ATTR_MODEL_NR, model_nr)
155wlp_vset(char *, WLP_ATTR_SERIAL, serial)
156wlp_vset(char *, WLP_ATTR_WSS_NAME, wss_name)
157wlp_pset(struct wlp_uuid *, WLP_ATTR_UUID_E, uuid_e)
158wlp_pset(struct wlp_uuid *, WLP_ATTR_UUID_R, uuid_r)
159wlp_pset(struct wlp_uuid *, WLP_ATTR_WSSID, wssid)
160wlp_pset(struct wlp_dev_type *, WLP_ATTR_PRI_DEV_TYPE, prim_dev_type)
161/*wlp_pset(struct wlp_dev_type *, WLP_ATTR_SEC_DEV_TYPE, sec_dev_type)*/
162wlp_set(u8, WLP_ATTR_WLP_VER, version)
163wlp_set(enum wlp_assc_error, WLP_ATTR_WLP_ASSC_ERR, wlp_assc_err)
164wlp_set(enum wlp_wss_sel_mthd, WLP_ATTR_WSS_SEL_MTHD, wss_sel_mthd)
165wlp_set(u8, WLP_ATTR_ACC_ENRL, accept_enrl)
166wlp_set(u8, WLP_ATTR_WSS_SEC_STAT, wss_sec_status)
167wlp_pset(struct uwb_mac_addr *, WLP_ATTR_WSS_BCAST, wss_bcast)
168wlp_pset(struct wlp_nonce *, WLP_ATTR_ENRL_NONCE, enonce)
169wlp_pset(struct wlp_nonce *, WLP_ATTR_REG_NONCE, rnonce)
170wlp_set(u8, WLP_ATTR_WSS_TAG, wss_tag)
171wlp_pset(struct uwb_mac_addr *, WLP_ATTR_WSS_VIRT, wss_virt)
172
173/**
174 * Fill in the WSS information attributes
175 *
176 * We currently only support one WSS, and this is assumed in this function
177 * that can populate only one WSS information attribute.
178 */
179static size_t wlp_set_wss_info(struct wlp_attr_wss_info *attr,
180 struct wlp_wss *wss)
181{
182 size_t datalen;
183 void *ptr = attr->wss_info;
184 size_t used = sizeof(*attr);
185 d_fnstart(6, NULL, "(attribute %p)\n", attr);
186 datalen = sizeof(struct wlp_wss_info) + strlen(wss->name);
187 wlp_set_attr_hdr(&attr->hdr, WLP_ATTR_WSS_INFO, datalen);
188 used = wlp_set_wssid(ptr, &wss->wssid);
189 used += wlp_set_wss_name(ptr + used, wss->name, strlen(wss->name));
190 used += wlp_set_accept_enrl(ptr + used, wss->accept_enroll);
191 used += wlp_set_wss_sec_status(ptr + used, wss->secure_status);
192 used += wlp_set_wss_bcast(ptr + used, &wss->bcast);
193 d_dump(6, NULL, attr, sizeof(*attr) + datalen);
194 d_fnend(6, NULL, "(attribute %p, used %d)\n",
195 attr, (int)(sizeof(*attr) + used));
196 return sizeof(*attr) + used;
197}
198
199/**
200 * Verify attribute header
201 *
202 * @hdr: Pointer to attribute header that will be verified.
203 * @type: Expected attribute type.
204 * @len: Expected length of attribute value (excluding header).
205 *
206 * Most attribute values have a known length even when they do have a
207 * length field. This knowledge can be used via this function to verify
208 * that the length field matches the expected value.
209 */
210static int wlp_check_attr_hdr(struct wlp *wlp, struct wlp_attr_hdr *hdr,
211 enum wlp_attr_type type, unsigned len)
212{
213 struct device *dev = &wlp->rc->uwb_dev.dev;
214
215 if (le16_to_cpu(hdr->type) != type) {
216 dev_err(dev, "WLP: unexpected header type. Expected "
217 "%u, got %u.\n", type, le16_to_cpu(hdr->type));
218 return -EINVAL;
219 }
220 if (le16_to_cpu(hdr->length) != len) {
221 dev_err(dev, "WLP: unexpected length in header. Expected "
222 "%u, got %u.\n", len, le16_to_cpu(hdr->length));
223 return -EINVAL;
224 }
225 return 0;
226}
227
228/**
229 * Check if header of WSS information attribute valid
230 *
231 * @returns: length of WSS attributes (value of length attribute field) if
232 * valid WSS information attribute found
233 * -ENODATA if no WSS information attribute found
234 * -EIO other error occured
235 *
236 * The WSS information attribute is optional. The function will be provided
237 * with a pointer to data that could _potentially_ be a WSS information
238 * attribute. If a valid WSS information attribute is found it will return
239 * 0, if no WSS information attribute is found it will return -ENODATA, and
240 * another error will be returned if it is a WSS information attribute, but
241 * some parsing failure occured.
242 */
243static int wlp_check_wss_info_attr_hdr(struct wlp *wlp,
244 struct wlp_attr_hdr *hdr, size_t buflen)
245{
246 struct device *dev = &wlp->rc->uwb_dev.dev;
247 size_t len;
248 int result = 0;
249
250 if (buflen < sizeof(*hdr)) {
251 dev_err(dev, "WLP: Not enough space in buffer to parse"
252 " WSS information attribute header.\n");
253 result = -EIO;
254 goto out;
255 }
256 if (le16_to_cpu(hdr->type) != WLP_ATTR_WSS_INFO) {
257 /* WSS information is optional */
258 result = -ENODATA;
259 goto out;
260 }
261 len = le16_to_cpu(hdr->length);
262 if (buflen < sizeof(*hdr) + len) {
263 dev_err(dev, "WLP: Not enough space in buffer to parse "
264 "variable data. Got %d, expected %d.\n",
265 (int)buflen, (int)(sizeof(*hdr) + len));
266 result = -EIO;
267 goto out;
268 }
269 result = len;
270out:
271 return result;
272}
273
274
275/**
276 * Get value of attribute from fixed size attribute field.
277 *
278 * @attr: Pointer to attribute field.
279 * @value: Pointer to variable in which attribute value will be placed.
280 * @buflen: Size of buffer in which attribute field (including header)
281 * can be found.
282 * @returns: Amount of given buffer consumed by parsing for this attribute.
283 *
284 * The size and type of the value is known by the type of the attribute.
285 */
286#define wlp_get(type, type_code, name) \
287ssize_t wlp_get_##name(struct wlp *wlp, struct wlp_attr_##name *attr, \
288 type *value, ssize_t buflen) \
289{ \
290 struct device *dev = &wlp->rc->uwb_dev.dev; \
291 if (buflen < 0) \
292 return -EINVAL; \
293 if (buflen < sizeof(*attr)) { \
294 dev_err(dev, "WLP: Not enough space in buffer to parse" \
295 " attribute field. Need %d, received %zu\n", \
296 (int)sizeof(*attr), buflen); \
297 return -EIO; \
298 } \
299 if (wlp_check_attr_hdr(wlp, &attr->hdr, type_code, \
300 sizeof(attr->name)) < 0) { \
301 dev_err(dev, "WLP: Header verification failed. \n"); \
302 return -EINVAL; \
303 } \
304 *value = attr->name; \
305 return sizeof(*attr); \
306}
307
308#define wlp_get_sparse(type, type_code, name) \
309 static wlp_get(type, type_code, name)
310
311/**
312 * Get value of attribute from variable sized attribute field.
313 *
314 * @max: The maximum size of this attribute. This value is dictated by
315 * the maximum value from the WLP specification.
316 *
317 * @attr: Pointer to attribute field.
318 * @value: Pointer to variable that will contain the value. The memory
319 * must already have been allocated for this value.
320 * @buflen: Size of buffer in which attribute field (including header)
321 * can be found.
322 * @returns: Amount of given bufferconsumed by parsing for this attribute.
323 */
324#define wlp_vget(type_val, type_code, name, max) \
325static ssize_t wlp_get_##name(struct wlp *wlp, \
326 struct wlp_attr_##name *attr, \
327 type_val *value, ssize_t buflen) \
328{ \
329 struct device *dev = &wlp->rc->uwb_dev.dev; \
330 size_t len; \
331 if (buflen < 0) \
332 return -EINVAL; \
333 if (buflen < sizeof(*attr)) { \
334 dev_err(dev, "WLP: Not enough space in buffer to parse" \
335 " header.\n"); \
336 return -EIO; \
337 } \
338 if (le16_to_cpu(attr->hdr.type) != type_code) { \
339 dev_err(dev, "WLP: Unexpected attribute type. Got %u, " \
340 "expected %u.\n", le16_to_cpu(attr->hdr.type), \
341 type_code); \
342 return -EINVAL; \
343 } \
344 len = le16_to_cpu(attr->hdr.length); \
345 if (len > max) { \
346 dev_err(dev, "WLP: Attribute larger than maximum " \
347 "allowed. Received %zu, max is %d.\n", len, \
348 (int)max); \
349 return -EFBIG; \
350 } \
351 if (buflen < sizeof(*attr) + len) { \
352 dev_err(dev, "WLP: Not enough space in buffer to parse "\
353 "variable data.\n"); \
354 return -EIO; \
355 } \
356 memcpy(value, (void *) attr + sizeof(*attr), len); \
357 return sizeof(*attr) + len; \
358}
359
360wlp_get(u8, WLP_ATTR_WLP_VER, version)
361wlp_get_sparse(enum wlp_wss_sel_mthd, WLP_ATTR_WSS_SEL_MTHD, wss_sel_mthd)
362wlp_get_sparse(struct wlp_dev_type, WLP_ATTR_PRI_DEV_TYPE, prim_dev_type)
363wlp_get_sparse(enum wlp_assc_error, WLP_ATTR_WLP_ASSC_ERR, wlp_assc_err)
364wlp_get_sparse(struct wlp_uuid, WLP_ATTR_UUID_E, uuid_e)
365wlp_get_sparse(struct wlp_uuid, WLP_ATTR_UUID_R, uuid_r)
366wlp_get(struct wlp_uuid, WLP_ATTR_WSSID, wssid)
367wlp_get_sparse(u8, WLP_ATTR_ACC_ENRL, accept_enrl)
368wlp_get_sparse(u8, WLP_ATTR_WSS_SEC_STAT, wss_sec_status)
369wlp_get_sparse(struct uwb_mac_addr, WLP_ATTR_WSS_BCAST, wss_bcast)
370wlp_get_sparse(u8, WLP_ATTR_WSS_TAG, wss_tag)
371wlp_get_sparse(struct uwb_mac_addr, WLP_ATTR_WSS_VIRT, wss_virt)
372wlp_get_sparse(struct wlp_nonce, WLP_ATTR_ENRL_NONCE, enonce)
373wlp_get_sparse(struct wlp_nonce, WLP_ATTR_REG_NONCE, rnonce)
374
375/* The buffers for the device info attributes can be found in the
376 * wlp_device_info struct. These buffers contain one byte more than the
377 * max allowed by the spec - this is done to be able to add the
378 * terminating \0 for user display. This terminating byte is not required
379 * in the actual attribute field (because it has a length field) so the
380 * maximum allowed for this value is one less than its size in the
381 * structure.
382 */
383wlp_vget(char, WLP_ATTR_WSS_NAME, wss_name,
384 FIELD_SIZEOF(struct wlp_wss, name) - 1)
385wlp_vget(char, WLP_ATTR_DEV_NAME, dev_name,
386 FIELD_SIZEOF(struct wlp_device_info, name) - 1)
387wlp_vget(char, WLP_ATTR_MANUF, manufacturer,
388 FIELD_SIZEOF(struct wlp_device_info, manufacturer) - 1)
389wlp_vget(char, WLP_ATTR_MODEL_NAME, model_name,
390 FIELD_SIZEOF(struct wlp_device_info, model_name) - 1)
391wlp_vget(char, WLP_ATTR_MODEL_NR, model_nr,
392 FIELD_SIZEOF(struct wlp_device_info, model_nr) - 1)
393wlp_vget(char, WLP_ATTR_SERIAL, serial,
394 FIELD_SIZEOF(struct wlp_device_info, serial) - 1)
395
396/**
397 * Retrieve WSS Name, Accept enroll, Secure status, Broadcast from WSS info
398 *
399 * @attr: pointer to WSS name attribute in WSS information attribute field
400 * @info: structure that will be populated with data from WSS information
401 * field (WSS name, Accept enroll, secure status, broadcast address)
402 * @buflen: size of buffer
403 *
404 * Although the WSSID attribute forms part of the WSS info attribute it is
405 * retrieved separately and stored in a different location.
406 */
407static ssize_t wlp_get_wss_info_attrs(struct wlp *wlp,
408 struct wlp_attr_hdr *attr,
409 struct wlp_wss_tmp_info *info,
410 ssize_t buflen)
411{
412 struct device *dev = &wlp->rc->uwb_dev.dev;
413 void *ptr = attr;
414 size_t used = 0;
415 ssize_t result = -EINVAL;
416
417 d_printf(6, dev, "WLP: WSS info: Retrieving WSS name\n");
418 result = wlp_get_wss_name(wlp, ptr, info->name, buflen);
419 if (result < 0) {
420 dev_err(dev, "WLP: unable to obtain WSS name from "
421 "WSS info in D2 message.\n");
422 goto error_parse;
423 }
424 used += result;
425 d_printf(6, dev, "WLP: WSS info: Retrieving accept enroll\n");
426 result = wlp_get_accept_enrl(wlp, ptr + used, &info->accept_enroll,
427 buflen - used);
428 if (result < 0) {
429 dev_err(dev, "WLP: unable to obtain accepting "
430 "enrollment from WSS info in D2 message.\n");
431 goto error_parse;
432 }
433 if (info->accept_enroll != 0 && info->accept_enroll != 1) {
434 dev_err(dev, "WLP: invalid value for accepting "
435 "enrollment in D2 message.\n");
436 result = -EINVAL;
437 goto error_parse;
438 }
439 used += result;
440 d_printf(6, dev, "WLP: WSS info: Retrieving secure status\n");
441 result = wlp_get_wss_sec_status(wlp, ptr + used, &info->sec_status,
442 buflen - used);
443 if (result < 0) {
444 dev_err(dev, "WLP: unable to obtain secure "
445 "status from WSS info in D2 message.\n");
446 goto error_parse;
447 }
448 if (info->sec_status != 0 && info->sec_status != 1) {
449 dev_err(dev, "WLP: invalid value for secure "
450 "status in D2 message.\n");
451 result = -EINVAL;
452 goto error_parse;
453 }
454 used += result;
455 d_printf(6, dev, "WLP: WSS info: Retrieving broadcast\n");
456 result = wlp_get_wss_bcast(wlp, ptr + used, &info->bcast,
457 buflen - used);
458 if (result < 0) {
459 dev_err(dev, "WLP: unable to obtain broadcast "
460 "address from WSS info in D2 message.\n");
461 goto error_parse;
462 }
463 used += result;
464 result = used;
465error_parse:
466 return result;
467}
468
469/**
470 * Create a new WSSID entry for the neighbor, allocate temporary storage
471 *
472 * Each neighbor can have many WSS active. We maintain a list of WSSIDs
473 * advertised by neighbor. During discovery we also cache information about
474 * these WSS in temporary storage.
475 *
476 * The temporary storage will be removed after it has been used (eg.
477 * displayed to user), the wssid element will be removed from the list when
478 * the neighbor is rediscovered or when it disappears.
479 */
480static struct wlp_wssid_e *wlp_create_wssid_e(struct wlp *wlp,
481 struct wlp_neighbor_e *neighbor)
482{
483 struct device *dev = &wlp->rc->uwb_dev.dev;
484 struct wlp_wssid_e *wssid_e;
485
486 wssid_e = kzalloc(sizeof(*wssid_e), GFP_KERNEL);
487 if (wssid_e == NULL) {
488 dev_err(dev, "WLP: unable to allocate memory "
489 "for WSS information.\n");
490 goto error_alloc;
491 }
492 wssid_e->info = kzalloc(sizeof(struct wlp_wss_tmp_info), GFP_KERNEL);
493 if (wssid_e->info == NULL) {
494 dev_err(dev, "WLP: unable to allocate memory "
495 "for temporary WSS information.\n");
496 kfree(wssid_e);
497 wssid_e = NULL;
498 goto error_alloc;
499 }
500 list_add(&wssid_e->node, &neighbor->wssid);
501error_alloc:
502 return wssid_e;
503}
504
505/**
506 * Parse WSS information attribute
507 *
508 * @attr: pointer to WSS information attribute header
509 * @buflen: size of buffer in which WSS information attribute appears
510 * @wssid: will place wssid from WSS info attribute in this location
511 * @wss_info: will place other information from WSS information attribute
512 * in this location
513 *
514 * memory for @wssid and @wss_info must be allocated when calling this
515 */
516static ssize_t wlp_get_wss_info(struct wlp *wlp, struct wlp_attr_wss_info *attr,
517 size_t buflen, struct wlp_uuid *wssid,
518 struct wlp_wss_tmp_info *wss_info)
519{
520 struct device *dev = &wlp->rc->uwb_dev.dev;
521 ssize_t result;
522 size_t len;
523 size_t used = 0;
524 void *ptr;
525
526 result = wlp_check_wss_info_attr_hdr(wlp, (struct wlp_attr_hdr *)attr,
527 buflen);
528 if (result < 0)
529 goto out;
530 len = result;
531 used = sizeof(*attr);
532 ptr = attr;
533 d_printf(6, dev, "WLP: WSS info: Retrieving WSSID\n");
534 result = wlp_get_wssid(wlp, ptr + used, wssid, buflen - used);
535 if (result < 0) {
536 dev_err(dev, "WLP: unable to obtain WSSID from WSS info.\n");
537 goto out;
538 }
539 used += result;
540 result = wlp_get_wss_info_attrs(wlp, ptr + used, wss_info,
541 buflen - used);
542 if (result < 0) {
543 dev_err(dev, "WLP: unable to obtain WSS information "
544 "from WSS information attributes. \n");
545 goto out;
546 }
547 used += result;
548 if (len + sizeof(*attr) != used) {
549 dev_err(dev, "WLP: Amount of data parsed does not "
550 "match length field. Parsed %zu, length "
551 "field %zu. \n", used, len);
552 result = -EINVAL;
553 goto out;
554 }
555 result = used;
556 d_printf(6, dev, "WLP: Successfully parsed WLP information "
557 "attribute. used %zu bytes\n", used);
558out:
559 return result;
560}
561
562/**
563 * Retrieve WSS info from association frame
564 *
565 * @attr: pointer to WSS information attribute
566 * @neighbor: ptr to neighbor being discovered, NULL if enrollment in
567 * progress
568 * @wss: ptr to WSS being enrolled in, NULL if discovery in progress
569 * @buflen: size of buffer in which WSS information appears
570 *
571 * The WSS information attribute appears in the D2 association message.
572 * This message is used in two ways: to discover all neighbors or to enroll
573 * into a WSS activated by a neighbor. During discovery we only want to
574 * store the WSS info in a cache, to be deleted right after it has been
575 * used (eg. displayed to the user). During enrollment we store the WSS
576 * information for the lifetime of enrollment.
577 *
578 * During discovery we are interested in all WSS information, during
579 * enrollment we are only interested in the WSS being enrolled in. Even so,
580 * when in enrollment we keep parsing the message after finding the WSS of
581 * interest, this simplifies the calling routine in that it can be sure
582 * that all WSS information attributes have been parsed out of the message.
583 *
584 * Association frame is process with nbmutex held. The list access is safe.
585 */
586static ssize_t wlp_get_all_wss_info(struct wlp *wlp,
587 struct wlp_attr_wss_info *attr,
588 struct wlp_neighbor_e *neighbor,
589 struct wlp_wss *wss, ssize_t buflen)
590{
591 struct device *dev = &wlp->rc->uwb_dev.dev;
592 size_t used = 0;
593 ssize_t result = -EINVAL;
594 struct wlp_attr_wss_info *cur;
595 struct wlp_uuid wssid;
596 struct wlp_wss_tmp_info wss_info;
597 unsigned enroll; /* 0 - discovery to cache, 1 - enrollment */
598 struct wlp_wssid_e *wssid_e;
599 char buf[WLP_WSS_UUID_STRSIZE];
600
601 d_fnstart(6, dev, "wlp %p, attr %p, neighbor %p, wss %p, buflen %d \n",
602 wlp, attr, neighbor, wss, (int)buflen);
603 if (buflen < 0)
604 goto out;
605
606 if (neighbor != NULL && wss == NULL)
607 enroll = 0; /* discovery */
608 else if (wss != NULL && neighbor == NULL)
609 enroll = 1; /* enrollment */
610 else
611 goto out;
612
613 cur = attr;
614 while (buflen - used > 0) {
615 memset(&wss_info, 0, sizeof(wss_info));
616 cur = (void *)cur + used;
617 result = wlp_get_wss_info(wlp, cur, buflen - used, &wssid,
618 &wss_info);
619 if (result == -ENODATA) {
620 result = used;
621 goto out;
622 } else if (result < 0) {
623 dev_err(dev, "WLP: Unable to parse WSS information "
624 "from WSS information attribute. \n");
625 result = -EINVAL;
626 goto error_parse;
627 }
628 if (enroll && !memcmp(&wssid, &wss->wssid, sizeof(wssid))) {
629 if (wss_info.accept_enroll != 1) {
630 dev_err(dev, "WLP: Requested WSS does "
631 "not accept enrollment.\n");
632 result = -EINVAL;
633 goto out;
634 }
635 memcpy(wss->name, wss_info.name, sizeof(wss->name));
636 wss->bcast = wss_info.bcast;
637 wss->secure_status = wss_info.sec_status;
638 wss->accept_enroll = wss_info.accept_enroll;
639 wss->state = WLP_WSS_STATE_PART_ENROLLED;
640 wlp_wss_uuid_print(buf, sizeof(buf), &wssid);
641 d_printf(2, dev, "WLP: Found WSS %s. Enrolling.\n",
642 buf);
643 } else {
644 wssid_e = wlp_create_wssid_e(wlp, neighbor);
645 if (wssid_e == NULL) {
646 dev_err(dev, "WLP: Cannot create new WSSID "
647 "entry for neighbor %02x:%02x.\n",
648 neighbor->uwb_dev->dev_addr.data[1],
649 neighbor->uwb_dev->dev_addr.data[0]);
650 result = -ENOMEM;
651 goto out;
652 }
653 wssid_e->wssid = wssid;
654 *wssid_e->info = wss_info;
655 }
656 used += result;
657 }
658 result = used;
659error_parse:
660 if (result < 0 && !enroll) /* this was a discovery */
661 wlp_remove_neighbor_tmp_info(neighbor);
662out:
663 d_fnend(6, dev, "wlp %p, attr %p, neighbor %p, wss %p, buflen %d, "
664 "result %d \n", wlp, attr, neighbor, wss, (int)buflen,
665 (int)result);
666 return result;
667
668}
669
670/**
671 * Parse WSS information attributes into cache for discovery
672 *
673 * @attr: the first WSS information attribute in message
674 * @neighbor: the neighbor whose cache will be populated
675 * @buflen: size of the input buffer
676 */
677static ssize_t wlp_get_wss_info_to_cache(struct wlp *wlp,
678 struct wlp_attr_wss_info *attr,
679 struct wlp_neighbor_e *neighbor,
680 ssize_t buflen)
681{
682 return wlp_get_all_wss_info(wlp, attr, neighbor, NULL, buflen);
683}
684
685/**
686 * Parse WSS information attributes into WSS struct for enrollment
687 *
688 * @attr: the first WSS information attribute in message
689 * @wss: the WSS that will be enrolled
690 * @buflen: size of the input buffer
691 */
692static ssize_t wlp_get_wss_info_to_enroll(struct wlp *wlp,
693 struct wlp_attr_wss_info *attr,
694 struct wlp_wss *wss, ssize_t buflen)
695{
696 return wlp_get_all_wss_info(wlp, attr, NULL, wss, buflen);
697}
698
699/**
700 * Construct a D1 association frame
701 *
702 * We use the radio control functions to determine the values of the device
703 * properties. These are of variable length and the total space needed is
704 * tallied first before we start constructing the message. The radio
705 * control functions return strings that are terminated with \0. This
706 * character should not be included in the message (there is a length field
707 * accompanying it in the attribute).
708 */
709static int wlp_build_assoc_d1(struct wlp *wlp, struct wlp_wss *wss,
710 struct sk_buff **skb)
711{
712
713 struct device *dev = &wlp->rc->uwb_dev.dev;
714 int result = 0;
715 struct wlp_device_info *info;
716 size_t used = 0;
717 struct wlp_frame_assoc *_d1;
718 struct sk_buff *_skb;
719 void *d1_itr;
720
721 d_fnstart(6, dev, "wlp %p\n", wlp);
722 if (wlp->dev_info == NULL) {
723 result = __wlp_setup_device_info(wlp);
724 if (result < 0) {
725 dev_err(dev, "WLP: Unable to setup device "
726 "information for D1 message.\n");
727 goto error;
728 }
729 }
730 info = wlp->dev_info;
731 d_printf(6, dev, "Local properties:\n"
732 "Device name (%d bytes): %s\n"
733 "Model name (%d bytes): %s\n"
734 "Manufacturer (%d bytes): %s\n"
735 "Model number (%d bytes): %s\n"
736 "Serial number (%d bytes): %s\n"
737 "Primary device type: \n"
738 " Category: %d \n"
739 " OUI: %02x:%02x:%02x \n"
740 " OUI Subdivision: %u \n",
741 (int)strlen(info->name), info->name,
742 (int)strlen(info->model_name), info->model_name,
743 (int)strlen(info->manufacturer), info->manufacturer,
744 (int)strlen(info->model_nr), info->model_nr,
745 (int)strlen(info->serial), info->serial,
746 info->prim_dev_type.category,
747 info->prim_dev_type.OUI[0], info->prim_dev_type.OUI[1],
748 info->prim_dev_type.OUI[2], info->prim_dev_type.OUIsubdiv);
749 _skb = dev_alloc_skb(sizeof(*_d1)
750 + sizeof(struct wlp_attr_uuid_e)
751 + sizeof(struct wlp_attr_wss_sel_mthd)
752 + sizeof(struct wlp_attr_dev_name)
753 + strlen(info->name)
754 + sizeof(struct wlp_attr_manufacturer)
755 + strlen(info->manufacturer)
756 + sizeof(struct wlp_attr_model_name)
757 + strlen(info->model_name)
758 + sizeof(struct wlp_attr_model_nr)
759 + strlen(info->model_nr)
760 + sizeof(struct wlp_attr_serial)
761 + strlen(info->serial)
762 + sizeof(struct wlp_attr_prim_dev_type)
763 + sizeof(struct wlp_attr_wlp_assc_err));
764 if (_skb == NULL) {
765 dev_err(dev, "WLP: Cannot allocate memory for association "
766 "message.\n");
767 result = -ENOMEM;
768 goto error;
769 }
770 _d1 = (void *) _skb->data;
771 d_printf(6, dev, "D1 starts at %p \n", _d1);
772 _d1->hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID);
773 _d1->hdr.type = WLP_FRAME_ASSOCIATION;
774 _d1->type = WLP_ASSOC_D1;
775
776 wlp_set_version(&_d1->version, WLP_VERSION);
777 wlp_set_msg_type(&_d1->msg_type, WLP_ASSOC_D1);
778 d1_itr = _d1->attr;
779 used = wlp_set_uuid_e(d1_itr, &wlp->uuid);
780 used += wlp_set_wss_sel_mthd(d1_itr + used, WLP_WSS_REG_SELECT);
781 used += wlp_set_dev_name(d1_itr + used, info->name,
782 strlen(info->name));
783 used += wlp_set_manufacturer(d1_itr + used, info->manufacturer,
784 strlen(info->manufacturer));
785 used += wlp_set_model_name(d1_itr + used, info->model_name,
786 strlen(info->model_name));
787 used += wlp_set_model_nr(d1_itr + used, info->model_nr,
788 strlen(info->model_nr));
789 used += wlp_set_serial(d1_itr + used, info->serial,
790 strlen(info->serial));
791 used += wlp_set_prim_dev_type(d1_itr + used, &info->prim_dev_type);
792 used += wlp_set_wlp_assc_err(d1_itr + used, WLP_ASSOC_ERROR_NONE);
793 skb_put(_skb, sizeof(*_d1) + used);
794 d_printf(6, dev, "D1 message:\n");
795 d_dump(6, dev, _d1, sizeof(*_d1)
796 + sizeof(struct wlp_attr_uuid_e)
797 + sizeof(struct wlp_attr_wss_sel_mthd)
798 + sizeof(struct wlp_attr_dev_name)
799 + strlen(info->name)
800 + sizeof(struct wlp_attr_manufacturer)
801 + strlen(info->manufacturer)
802 + sizeof(struct wlp_attr_model_name)
803 + strlen(info->model_name)
804 + sizeof(struct wlp_attr_model_nr)
805 + strlen(info->model_nr)
806 + sizeof(struct wlp_attr_serial)
807 + strlen(info->serial)
808 + sizeof(struct wlp_attr_prim_dev_type)
809 + sizeof(struct wlp_attr_wlp_assc_err));
810 *skb = _skb;
811error:
812 d_fnend(6, dev, "wlp %p, result = %d\n", wlp, result);
813 return result;
814}
815
816/**
817 * Construct a D2 association frame
818 *
819 * We use the radio control functions to determine the values of the device
820 * properties. These are of variable length and the total space needed is
821 * tallied first before we start constructing the message. The radio
822 * control functions return strings that are terminated with \0. This
823 * character should not be included in the message (there is a length field
824 * accompanying it in the attribute).
825 */
826static
827int wlp_build_assoc_d2(struct wlp *wlp, struct wlp_wss *wss,
828 struct sk_buff **skb, struct wlp_uuid *uuid_e)
829{
830
831 struct device *dev = &wlp->rc->uwb_dev.dev;
832 int result = 0;
833 struct wlp_device_info *info;
834 size_t used = 0;
835 struct wlp_frame_assoc *_d2;
836 struct sk_buff *_skb;
837 void *d2_itr;
838 size_t mem_needed;
839
840 d_fnstart(6, dev, "wlp %p\n", wlp);
841 if (wlp->dev_info == NULL) {
842 result = __wlp_setup_device_info(wlp);
843 if (result < 0) {
844 dev_err(dev, "WLP: Unable to setup device "
845 "information for D2 message.\n");
846 goto error;
847 }
848 }
849 info = wlp->dev_info;
850 d_printf(6, dev, "Local properties:\n"
851 "Device name (%d bytes): %s\n"
852 "Model name (%d bytes): %s\n"
853 "Manufacturer (%d bytes): %s\n"
854 "Model number (%d bytes): %s\n"
855 "Serial number (%d bytes): %s\n"
856 "Primary device type: \n"
857 " Category: %d \n"
858 " OUI: %02x:%02x:%02x \n"
859 " OUI Subdivision: %u \n",
860 (int)strlen(info->name), info->name,
861 (int)strlen(info->model_name), info->model_name,
862 (int)strlen(info->manufacturer), info->manufacturer,
863 (int)strlen(info->model_nr), info->model_nr,
864 (int)strlen(info->serial), info->serial,
865 info->prim_dev_type.category,
866 info->prim_dev_type.OUI[0], info->prim_dev_type.OUI[1],
867 info->prim_dev_type.OUI[2], info->prim_dev_type.OUIsubdiv);
868 mem_needed = sizeof(*_d2)
869 + sizeof(struct wlp_attr_uuid_e)
870 + sizeof(struct wlp_attr_uuid_r)
871 + sizeof(struct wlp_attr_dev_name)
872 + strlen(info->name)
873 + sizeof(struct wlp_attr_manufacturer)
874 + strlen(info->manufacturer)
875 + sizeof(struct wlp_attr_model_name)
876 + strlen(info->model_name)
877 + sizeof(struct wlp_attr_model_nr)
878 + strlen(info->model_nr)
879 + sizeof(struct wlp_attr_serial)
880 + strlen(info->serial)
881 + sizeof(struct wlp_attr_prim_dev_type)
882 + sizeof(struct wlp_attr_wlp_assc_err);
883 if (wlp->wss.state >= WLP_WSS_STATE_ACTIVE)
884 mem_needed += sizeof(struct wlp_attr_wss_info)
885 + sizeof(struct wlp_wss_info)
886 + strlen(wlp->wss.name);
887 _skb = dev_alloc_skb(mem_needed);
888 if (_skb == NULL) {
889 dev_err(dev, "WLP: Cannot allocate memory for association "
890 "message.\n");
891 result = -ENOMEM;
892 goto error;
893 }
894 _d2 = (void *) _skb->data;
895 d_printf(6, dev, "D2 starts at %p \n", _d2);
896 _d2->hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID);
897 _d2->hdr.type = WLP_FRAME_ASSOCIATION;
898 _d2->type = WLP_ASSOC_D2;
899
900 wlp_set_version(&_d2->version, WLP_VERSION);
901 wlp_set_msg_type(&_d2->msg_type, WLP_ASSOC_D2);
902 d2_itr = _d2->attr;
903 used = wlp_set_uuid_e(d2_itr, uuid_e);
904 used += wlp_set_uuid_r(d2_itr + used, &wlp->uuid);
905 if (wlp->wss.state >= WLP_WSS_STATE_ACTIVE)
906 used += wlp_set_wss_info(d2_itr + used, &wlp->wss);
907 used += wlp_set_dev_name(d2_itr + used, info->name,
908 strlen(info->name));
909 used += wlp_set_manufacturer(d2_itr + used, info->manufacturer,
910 strlen(info->manufacturer));
911 used += wlp_set_model_name(d2_itr + used, info->model_name,
912 strlen(info->model_name));
913 used += wlp_set_model_nr(d2_itr + used, info->model_nr,
914 strlen(info->model_nr));
915 used += wlp_set_serial(d2_itr + used, info->serial,
916 strlen(info->serial));
917 used += wlp_set_prim_dev_type(d2_itr + used, &info->prim_dev_type);
918 used += wlp_set_wlp_assc_err(d2_itr + used, WLP_ASSOC_ERROR_NONE);
919 skb_put(_skb, sizeof(*_d2) + used);
920 d_printf(6, dev, "D2 message:\n");
921 d_dump(6, dev, _d2, mem_needed);
922 *skb = _skb;
923error:
924 d_fnend(6, dev, "wlp %p, result = %d\n", wlp, result);
925 return result;
926}
927
928/**
929 * Allocate memory for and populate fields of F0 association frame
930 *
931 * Currently (while focusing on unsecure enrollment) we ignore the
932 * nonce's that could be placed in the message. Only the error field is
933 * populated by the value provided by the caller.
934 */
935static
936int wlp_build_assoc_f0(struct wlp *wlp, struct sk_buff **skb,
937 enum wlp_assc_error error)
938{
939 struct device *dev = &wlp->rc->uwb_dev.dev;
940 int result = -ENOMEM;
941 struct {
942 struct wlp_frame_assoc f0_hdr;
943 struct wlp_attr_enonce enonce;
944 struct wlp_attr_rnonce rnonce;
945 struct wlp_attr_wlp_assc_err assc_err;
946 } *f0;
947 struct sk_buff *_skb;
948 struct wlp_nonce tmp;
949
950 d_fnstart(6, dev, "wlp %p\n", wlp);
951 _skb = dev_alloc_skb(sizeof(*f0));
952 if (_skb == NULL) {
953 dev_err(dev, "WLP: Unable to allocate memory for F0 "
954 "association frame. \n");
955 goto error_alloc;
956 }
957 f0 = (void *) _skb->data;
958 d_printf(6, dev, "F0 starts at %p \n", f0);
959 f0->f0_hdr.hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID);
960 f0->f0_hdr.hdr.type = WLP_FRAME_ASSOCIATION;
961 f0->f0_hdr.type = WLP_ASSOC_F0;
962 wlp_set_version(&f0->f0_hdr.version, WLP_VERSION);
963 wlp_set_msg_type(&f0->f0_hdr.msg_type, WLP_ASSOC_F0);
964 memset(&tmp, 0, sizeof(tmp));
965 wlp_set_enonce(&f0->enonce, &tmp);
966 wlp_set_rnonce(&f0->rnonce, &tmp);
967 wlp_set_wlp_assc_err(&f0->assc_err, error);
968 skb_put(_skb, sizeof(*f0));
969 *skb = _skb;
970 result = 0;
971error_alloc:
972 d_fnend(6, dev, "wlp %p, result %d \n", wlp, result);
973 return result;
974}
975
976/**
977 * Parse F0 frame
978 *
979 * We just retrieve the values and print it as an error to the user.
980 * Calling function already knows an error occured (F0 indicates error), so
981 * we just parse the content as debug for higher layers.
982 */
983int wlp_parse_f0(struct wlp *wlp, struct sk_buff *skb)
984{
985 struct device *dev = &wlp->rc->uwb_dev.dev;
986 struct wlp_frame_assoc *f0 = (void *) skb->data;
987 void *ptr = skb->data;
988 size_t len = skb->len;
989 size_t used;
990 ssize_t result;
991 struct wlp_nonce enonce, rnonce;
992 enum wlp_assc_error assc_err;
993 char enonce_buf[WLP_WSS_NONCE_STRSIZE];
994 char rnonce_buf[WLP_WSS_NONCE_STRSIZE];
995
996 used = sizeof(*f0);
997 result = wlp_get_enonce(wlp, ptr + used, &enonce, len - used);
998 if (result < 0) {
999 dev_err(dev, "WLP: unable to obtain Enrollee nonce "
1000 "attribute from F0 message.\n");
1001 goto error_parse;
1002 }
1003 used += result;
1004 result = wlp_get_rnonce(wlp, ptr + used, &rnonce, len - used);
1005 if (result < 0) {
1006 dev_err(dev, "WLP: unable to obtain Registrar nonce "
1007 "attribute from F0 message.\n");
1008 goto error_parse;
1009 }
1010 used += result;
1011 result = wlp_get_wlp_assc_err(wlp, ptr + used, &assc_err, len - used);
1012 if (result < 0) {
1013 dev_err(dev, "WLP: unable to obtain WLP Association error "
1014 "attribute from F0 message.\n");
1015 goto error_parse;
1016 }
1017 wlp_wss_nonce_print(enonce_buf, sizeof(enonce_buf), &enonce);
1018 wlp_wss_nonce_print(rnonce_buf, sizeof(rnonce_buf), &rnonce);
1019 dev_err(dev, "WLP: Received F0 error frame from neighbor. Enrollee "
1020 "nonce: %s, Registrar nonce: %s, WLP Association error: %s.\n",
1021 enonce_buf, rnonce_buf, wlp_assc_error_str(assc_err));
1022 result = 0;
1023error_parse:
1024 return result;
1025}
1026
1027/**
1028 * Retrieve variable device information from association message
1029 *
1030 * The device information parsed is not required in any message. This
1031 * routine will thus not fail if an attribute is not present.
1032 * The attributes are expected in a certain order, even if all are not
1033 * present. The "attribute type" value is used to ensure the attributes
1034 * are parsed in the correct order.
1035 *
1036 * If an error is encountered during parsing the function will return an
1037 * error code, when this happens the given device_info structure may be
1038 * partially filled.
1039 */
1040static
1041int wlp_get_variable_info(struct wlp *wlp, void *data,
1042 struct wlp_device_info *dev_info, ssize_t len)
1043{
1044 struct device *dev = &wlp->rc->uwb_dev.dev;
1045 size_t used = 0;
1046 struct wlp_attr_hdr *hdr;
1047 ssize_t result = 0;
1048 unsigned last = 0;
1049
1050 while (len - used > 0) {
1051 if (len - used < sizeof(*hdr)) {
1052 dev_err(dev, "WLP: Partial data in frame, cannot "
1053 "parse. \n");
1054 goto error_parse;
1055 }
1056 hdr = data + used;
1057 switch (le16_to_cpu(hdr->type)) {
1058 case WLP_ATTR_MANUF:
1059 if (last >= WLP_ATTR_MANUF) {
1060 dev_err(dev, "WLP: Incorrect order of "
1061 "attribute values in D1 msg.\n");
1062 goto error_parse;
1063 }
1064 result = wlp_get_manufacturer(wlp, data + used,
1065 dev_info->manufacturer,
1066 len - used);
1067 if (result < 0) {
1068 dev_err(dev, "WLP: Unable to obtain "
1069 "Manufacturer attribute from D1 "
1070 "message.\n");
1071 goto error_parse;
1072 }
1073 last = WLP_ATTR_MANUF;
1074 used += result;
1075 break;
1076 case WLP_ATTR_MODEL_NAME:
1077 if (last >= WLP_ATTR_MODEL_NAME) {
1078 dev_err(dev, "WLP: Incorrect order of "
1079 "attribute values in D1 msg.\n");
1080 goto error_parse;
1081 }
1082 result = wlp_get_model_name(wlp, data + used,
1083 dev_info->model_name,
1084 len - used);
1085 if (result < 0) {
1086 dev_err(dev, "WLP: Unable to obtain Model "
1087 "name attribute from D1 message.\n");
1088 goto error_parse;
1089 }
1090 last = WLP_ATTR_MODEL_NAME;
1091 used += result;
1092 break;
1093 case WLP_ATTR_MODEL_NR:
1094 if (last >= WLP_ATTR_MODEL_NR) {
1095 dev_err(dev, "WLP: Incorrect order of "
1096 "attribute values in D1 msg.\n");
1097 goto error_parse;
1098 }
1099 result = wlp_get_model_nr(wlp, data + used,
1100 dev_info->model_nr,
1101 len - used);
1102 if (result < 0) {
1103 dev_err(dev, "WLP: Unable to obtain Model "
1104 "number attribute from D1 message.\n");
1105 goto error_parse;
1106 }
1107 last = WLP_ATTR_MODEL_NR;
1108 used += result;
1109 break;
1110 case WLP_ATTR_SERIAL:
1111 if (last >= WLP_ATTR_SERIAL) {
1112 dev_err(dev, "WLP: Incorrect order of "
1113 "attribute values in D1 msg.\n");
1114 goto error_parse;
1115 }
1116 result = wlp_get_serial(wlp, data + used,
1117 dev_info->serial, len - used);
1118 if (result < 0) {
1119 dev_err(dev, "WLP: Unable to obtain Serial "
1120 "number attribute from D1 message.\n");
1121 goto error_parse;
1122 }
1123 last = WLP_ATTR_SERIAL;
1124 used += result;
1125 break;
1126 case WLP_ATTR_PRI_DEV_TYPE:
1127 if (last >= WLP_ATTR_PRI_DEV_TYPE) {
1128 dev_err(dev, "WLP: Incorrect order of "
1129 "attribute values in D1 msg.\n");
1130 goto error_parse;
1131 }
1132 result = wlp_get_prim_dev_type(wlp, data + used,
1133 &dev_info->prim_dev_type,
1134 len - used);
1135 if (result < 0) {
1136 dev_err(dev, "WLP: Unable to obtain Primary "
1137 "device type attribute from D1 "
1138 "message.\n");
1139 goto error_parse;
1140 }
1141 dev_info->prim_dev_type.category =
1142 le16_to_cpu(dev_info->prim_dev_type.category);
1143 dev_info->prim_dev_type.subID =
1144 le16_to_cpu(dev_info->prim_dev_type.subID);
1145 last = WLP_ATTR_PRI_DEV_TYPE;
1146 used += result;
1147 break;
1148 default:
1149 /* This is not variable device information. */
1150 goto out;
1151 break;
1152 }
1153 }
1154out:
1155 return used;
1156error_parse:
1157 return -EINVAL;
1158}
1159
1160/**
1161 * Parse incoming D1 frame, populate attribute values
1162 *
1163 * Caller provides pointers to memory already allocated for attributes
1164 * expected in the D1 frame. These variables will be populated.
1165 */
1166static
1167int wlp_parse_d1_frame(struct wlp *wlp, struct sk_buff *skb,
1168 struct wlp_uuid *uuid_e,
1169 enum wlp_wss_sel_mthd *sel_mthd,
1170 struct wlp_device_info *dev_info,
1171 enum wlp_assc_error *assc_err)
1172{
1173 struct device *dev = &wlp->rc->uwb_dev.dev;
1174 struct wlp_frame_assoc *d1 = (void *) skb->data;
1175 void *ptr = skb->data;
1176 size_t len = skb->len;
1177 size_t used;
1178 ssize_t result;
1179
1180 used = sizeof(*d1);
1181 result = wlp_get_uuid_e(wlp, ptr + used, uuid_e, len - used);
1182 if (result < 0) {
1183 dev_err(dev, "WLP: unable to obtain UUID-E attribute from D1 "
1184 "message.\n");
1185 goto error_parse;
1186 }
1187 used += result;
1188 result = wlp_get_wss_sel_mthd(wlp, ptr + used, sel_mthd, len - used);
1189 if (result < 0) {
1190 dev_err(dev, "WLP: unable to obtain WSS selection method "
1191 "from D1 message.\n");
1192 goto error_parse;
1193 }
1194 used += result;
1195 result = wlp_get_dev_name(wlp, ptr + used, dev_info->name,
1196 len - used);
1197 if (result < 0) {
1198 dev_err(dev, "WLP: unable to obtain Device Name from D1 "
1199 "message.\n");
1200 goto error_parse;
1201 }
1202 used += result;
1203 result = wlp_get_variable_info(wlp, ptr + used, dev_info, len - used);
1204 if (result < 0) {
1205 dev_err(dev, "WLP: unable to obtain Device Information from "
1206 "D1 message.\n");
1207 goto error_parse;
1208 }
1209 used += result;
1210 result = wlp_get_wlp_assc_err(wlp, ptr + used, assc_err, len - used);
1211 if (result < 0) {
1212 dev_err(dev, "WLP: unable to obtain WLP Association Error "
1213 "Information from D1 message.\n");
1214 goto error_parse;
1215 }
1216 result = 0;
1217error_parse:
1218 return result;
1219}
1220/**
1221 * Handle incoming D1 frame
1222 *
1223 * The frame has already been verified to contain an Association header with
1224 * the correct version number. Parse the incoming frame, construct and send
1225 * a D2 frame in response.
1226 *
1227 * It is not clear what to do with most fields in the incoming D1 frame. We
1228 * retrieve and discard the information here for now.
1229 */
1230void wlp_handle_d1_frame(struct work_struct *ws)
1231{
1232 struct wlp_assoc_frame_ctx *frame_ctx = container_of(ws,
1233 struct wlp_assoc_frame_ctx,
1234 ws);
1235 struct wlp *wlp = frame_ctx->wlp;
1236 struct wlp_wss *wss = &wlp->wss;
1237 struct sk_buff *skb = frame_ctx->skb;
1238 struct uwb_dev_addr *src = &frame_ctx->src;
1239 int result;
1240 struct device *dev = &wlp->rc->uwb_dev.dev;
1241 struct wlp_uuid uuid_e;
1242 enum wlp_wss_sel_mthd sel_mthd = 0;
1243 struct wlp_device_info dev_info;
1244 enum wlp_assc_error assc_err;
1245 char uuid[WLP_WSS_UUID_STRSIZE];
1246 struct sk_buff *resp = NULL;
1247
1248 /* Parse D1 frame */
1249 d_fnstart(6, dev, "WLP: handle D1 frame. wlp = %p, skb = %p\n",
1250 wlp, skb);
1251 mutex_lock(&wss->mutex);
1252 mutex_lock(&wlp->mutex); /* to access wlp->uuid */
1253 memset(&dev_info, 0, sizeof(dev_info));
1254 result = wlp_parse_d1_frame(wlp, skb, &uuid_e, &sel_mthd, &dev_info,
1255 &assc_err);
1256 if (result < 0) {
1257 dev_err(dev, "WLP: Unable to parse incoming D1 frame.\n");
1258 kfree_skb(skb);
1259 goto out;
1260 }
1261 wlp_wss_uuid_print(uuid, sizeof(uuid), &uuid_e);
1262 d_printf(6, dev, "From D1 frame:\n"
1263 "UUID-E: %s\n"
1264 "Selection method: %d\n"
1265 "Device name (%d bytes): %s\n"
1266 "Model name (%d bytes): %s\n"
1267 "Manufacturer (%d bytes): %s\n"
1268 "Model number (%d bytes): %s\n"
1269 "Serial number (%d bytes): %s\n"
1270 "Primary device type: \n"
1271 " Category: %d \n"
1272 " OUI: %02x:%02x:%02x \n"
1273 " OUI Subdivision: %u \n",
1274 uuid, sel_mthd,
1275 (int)strlen(dev_info.name), dev_info.name,
1276 (int)strlen(dev_info.model_name), dev_info.model_name,
1277 (int)strlen(dev_info.manufacturer), dev_info.manufacturer,
1278 (int)strlen(dev_info.model_nr), dev_info.model_nr,
1279 (int)strlen(dev_info.serial), dev_info.serial,
1280 dev_info.prim_dev_type.category,
1281 dev_info.prim_dev_type.OUI[0],
1282 dev_info.prim_dev_type.OUI[1],
1283 dev_info.prim_dev_type.OUI[2],
1284 dev_info.prim_dev_type.OUIsubdiv);
1285
1286 kfree_skb(skb);
1287 if (!wlp_uuid_is_set(&wlp->uuid)) {
1288 dev_err(dev, "WLP: UUID is not set. Set via sysfs to "
1289 "proceed. Respong to D1 message with error F0.\n");
1290 result = wlp_build_assoc_f0(wlp, &resp,
1291 WLP_ASSOC_ERROR_NOT_READY);
1292 if (result < 0) {
1293 dev_err(dev, "WLP: Unable to construct F0 message.\n");
1294 goto out;
1295 }
1296 } else {
1297 /* Construct D2 frame */
1298 result = wlp_build_assoc_d2(wlp, wss, &resp, &uuid_e);
1299 if (result < 0) {
1300 dev_err(dev, "WLP: Unable to construct D2 message.\n");
1301 goto out;
1302 }
1303 }
1304 /* Send D2 frame */
1305 BUG_ON(wlp->xmit_frame == NULL);
1306 result = wlp->xmit_frame(wlp, resp, src);
1307 if (result < 0) {
1308 dev_err(dev, "WLP: Unable to transmit D2 association "
1309 "message: %d\n", result);
1310 if (result == -ENXIO)
1311 dev_err(dev, "WLP: Is network interface up? \n");
1312 /* We could try again ... */
1313 dev_kfree_skb_any(resp); /* we need to free if tx fails */
1314 }
1315out:
1316 kfree(frame_ctx);
1317 mutex_unlock(&wlp->mutex);
1318 mutex_unlock(&wss->mutex);
1319 d_fnend(6, dev, "WLP: handle D1 frame. wlp = %p\n", wlp);
1320}
1321
1322/**
1323 * Parse incoming D2 frame, create and populate temporary cache
1324 *
1325 * @skb: socket buffer in which D2 frame can be found
1326 * @neighbor: the neighbor that sent the D2 frame
1327 *
1328 * Will allocate memory for temporary storage of information learned during
1329 * discovery.
1330 */
1331int wlp_parse_d2_frame_to_cache(struct wlp *wlp, struct sk_buff *skb,
1332 struct wlp_neighbor_e *neighbor)
1333{
1334 struct device *dev = &wlp->rc->uwb_dev.dev;
1335 struct wlp_frame_assoc *d2 = (void *) skb->data;
1336 void *ptr = skb->data;
1337 size_t len = skb->len;
1338 size_t used;
1339 ssize_t result;
1340 struct wlp_uuid uuid_e;
1341 struct wlp_device_info *nb_info;
1342 enum wlp_assc_error assc_err;
1343
1344 used = sizeof(*d2);
1345 result = wlp_get_uuid_e(wlp, ptr + used, &uuid_e, len - used);
1346 if (result < 0) {
1347 dev_err(dev, "WLP: unable to obtain UUID-E attribute from D2 "
1348 "message.\n");
1349 goto error_parse;
1350 }
1351 if (memcmp(&uuid_e, &wlp->uuid, sizeof(uuid_e))) {
1352 dev_err(dev, "WLP: UUID-E in incoming D2 does not match "
1353 "local UUID sent in D1. \n");
1354 goto error_parse;
1355 }
1356 used += result;
1357 result = wlp_get_uuid_r(wlp, ptr + used, &neighbor->uuid, len - used);
1358 if (result < 0) {
1359 dev_err(dev, "WLP: unable to obtain UUID-R attribute from D2 "
1360 "message.\n");
1361 goto error_parse;
1362 }
1363 used += result;
1364 result = wlp_get_wss_info_to_cache(wlp, ptr + used, neighbor,
1365 len - used);
1366 if (result < 0) {
1367 dev_err(dev, "WLP: unable to obtain WSS information "
1368 "from D2 message.\n");
1369 goto error_parse;
1370 }
1371 used += result;
1372 neighbor->info = kzalloc(sizeof(struct wlp_device_info), GFP_KERNEL);
1373 if (neighbor->info == NULL) {
1374 dev_err(dev, "WLP: cannot allocate memory to store device "
1375 "info.\n");
1376 result = -ENOMEM;
1377 goto error_parse;
1378 }
1379 nb_info = neighbor->info;
1380 result = wlp_get_dev_name(wlp, ptr + used, nb_info->name,
1381 len - used);
1382 if (result < 0) {
1383 dev_err(dev, "WLP: unable to obtain Device Name from D2 "
1384 "message.\n");
1385 goto error_parse;
1386 }
1387 used += result;
1388 result = wlp_get_variable_info(wlp, ptr + used, nb_info, len - used);
1389 if (result < 0) {
1390 dev_err(dev, "WLP: unable to obtain Device Information from "
1391 "D2 message.\n");
1392 goto error_parse;
1393 }
1394 used += result;
1395 result = wlp_get_wlp_assc_err(wlp, ptr + used, &assc_err, len - used);
1396 if (result < 0) {
1397 dev_err(dev, "WLP: unable to obtain WLP Association Error "
1398 "Information from D2 message.\n");
1399 goto error_parse;
1400 }
1401 if (assc_err != WLP_ASSOC_ERROR_NONE) {
1402 dev_err(dev, "WLP: neighbor device returned association "
1403 "error %d\n", assc_err);
1404 result = -EINVAL;
1405 goto error_parse;
1406 }
1407 result = 0;
1408error_parse:
1409 if (result < 0)
1410 wlp_remove_neighbor_tmp_info(neighbor);
1411 return result;
1412}
1413
1414/**
1415 * Parse incoming D2 frame, populate attribute values of WSS bein enrolled in
1416 *
1417 * @wss: our WSS that will be enrolled
1418 * @skb: socket buffer in which D2 frame can be found
1419 * @neighbor: the neighbor that sent the D2 frame
1420 * @wssid: the wssid of the WSS in which we want to enroll
1421 *
1422 * Forms part of enrollment sequence. We are trying to enroll in WSS with
1423 * @wssid by using @neighbor as registrar. A D1 message was sent to
1424 * @neighbor and now we need to parse the D2 response. The neighbor's
1425 * response is searched for the requested WSS and if found (and it accepts
1426 * enrollment), we store the information.
1427 */
1428int wlp_parse_d2_frame_to_enroll(struct wlp_wss *wss, struct sk_buff *skb,
1429 struct wlp_neighbor_e *neighbor,
1430 struct wlp_uuid *wssid)
1431{
1432 struct wlp *wlp = container_of(wss, struct wlp, wss);
1433 struct device *dev = &wlp->rc->uwb_dev.dev;
1434 void *ptr = skb->data;
1435 size_t len = skb->len;
1436 size_t used;
1437 ssize_t result;
1438 struct wlp_uuid uuid_e;
1439 struct wlp_uuid uuid_r;
1440 struct wlp_device_info nb_info;
1441 enum wlp_assc_error assc_err;
1442 char uuid_bufA[WLP_WSS_UUID_STRSIZE];
1443 char uuid_bufB[WLP_WSS_UUID_STRSIZE];
1444
1445 used = sizeof(struct wlp_frame_assoc);
1446 result = wlp_get_uuid_e(wlp, ptr + used, &uuid_e, len - used);
1447 if (result < 0) {
1448 dev_err(dev, "WLP: unable to obtain UUID-E attribute from D2 "
1449 "message.\n");
1450 goto error_parse;
1451 }
1452 if (memcmp(&uuid_e, &wlp->uuid, sizeof(uuid_e))) {
1453 dev_err(dev, "WLP: UUID-E in incoming D2 does not match "
1454 "local UUID sent in D1. \n");
1455 goto error_parse;
1456 }
1457 used += result;
1458 result = wlp_get_uuid_r(wlp, ptr + used, &uuid_r, len - used);
1459 if (result < 0) {
1460 dev_err(dev, "WLP: unable to obtain UUID-R attribute from D2 "
1461 "message.\n");
1462 goto error_parse;
1463 }
1464 if (memcmp(&uuid_r, &neighbor->uuid, sizeof(uuid_r))) {
1465 wlp_wss_uuid_print(uuid_bufA, sizeof(uuid_bufA),
1466 &neighbor->uuid);
1467 wlp_wss_uuid_print(uuid_bufB, sizeof(uuid_bufB), &uuid_r);
1468 dev_err(dev, "WLP: UUID of neighbor does not match UUID "
1469 "learned during discovery. Originally discovered: %s, "
1470 "now from D2 message: %s\n", uuid_bufA, uuid_bufB);
1471 result = -EINVAL;
1472 goto error_parse;
1473 }
1474 used += result;
1475 wss->wssid = *wssid;
1476 result = wlp_get_wss_info_to_enroll(wlp, ptr + used, wss, len - used);
1477 if (result < 0) {
1478 dev_err(dev, "WLP: unable to obtain WSS information "
1479 "from D2 message.\n");
1480 goto error_parse;
1481 }
1482 if (wss->state != WLP_WSS_STATE_PART_ENROLLED) {
1483 dev_err(dev, "WLP: D2 message did not contain information "
1484 "for successful enrollment. \n");
1485 result = -EINVAL;
1486 goto error_parse;
1487 }
1488 used += result;
1489 /* Place device information on stack to continue parsing of message */
1490 result = wlp_get_dev_name(wlp, ptr + used, nb_info.name,
1491 len - used);
1492 if (result < 0) {
1493 dev_err(dev, "WLP: unable to obtain Device Name from D2 "
1494 "message.\n");
1495 goto error_parse;
1496 }
1497 used += result;
1498 result = wlp_get_variable_info(wlp, ptr + used, &nb_info, len - used);
1499 if (result < 0) {
1500 dev_err(dev, "WLP: unable to obtain Device Information from "
1501 "D2 message.\n");
1502 goto error_parse;
1503 }
1504 used += result;
1505 result = wlp_get_wlp_assc_err(wlp, ptr + used, &assc_err, len - used);
1506 if (result < 0) {
1507 dev_err(dev, "WLP: unable to obtain WLP Association Error "
1508 "Information from D2 message.\n");
1509 goto error_parse;
1510 }
1511 if (assc_err != WLP_ASSOC_ERROR_NONE) {
1512 dev_err(dev, "WLP: neighbor device returned association "
1513 "error %d\n", assc_err);
1514 if (wss->state == WLP_WSS_STATE_PART_ENROLLED) {
1515 dev_err(dev, "WLP: Enrolled in WSS (should not "
1516 "happen according to spec). Undoing. \n");
1517 wlp_wss_reset(wss);
1518 }
1519 result = -EINVAL;
1520 goto error_parse;
1521 }
1522 result = 0;
1523error_parse:
1524 return result;
1525}
1526
1527/**
1528 * Parse C3/C4 frame into provided variables
1529 *
1530 * @wssid: will point to copy of wssid retrieved from C3/C4 frame
1531 * @tag: will point to copy of tag retrieved from C3/C4 frame
1532 * @virt_addr: will point to copy of virtual address retrieved from C3/C4
1533 * frame.
1534 *
1535 * Calling function has to allocate memory for these values.
1536 *
1537 * skb contains a valid C3/C4 frame, return the individual fields of this
1538 * frame in the provided variables.
1539 */
1540int wlp_parse_c3c4_frame(struct wlp *wlp, struct sk_buff *skb,
1541 struct wlp_uuid *wssid, u8 *tag,
1542 struct uwb_mac_addr *virt_addr)
1543{
1544 struct device *dev = &wlp->rc->uwb_dev.dev;
1545 int result;
1546 void *ptr = skb->data;
1547 size_t len = skb->len;
1548 size_t used;
1549 char buf[WLP_WSS_UUID_STRSIZE];
1550 struct wlp_frame_assoc *assoc = ptr;
1551
1552 d_fnstart(6, dev, "wlp %p, skb %p \n", wlp, skb);
1553 used = sizeof(*assoc);
1554 result = wlp_get_wssid(wlp, ptr + used, wssid, len - used);
1555 if (result < 0) {
1556 dev_err(dev, "WLP: unable to obtain WSSID attribute from "
1557 "%s message.\n", wlp_assoc_frame_str(assoc->type));
1558 goto error_parse;
1559 }
1560 used += result;
1561 result = wlp_get_wss_tag(wlp, ptr + used, tag, len - used);
1562 if (result < 0) {
1563 dev_err(dev, "WLP: unable to obtain WSS tag attribute from "
1564 "%s message.\n", wlp_assoc_frame_str(assoc->type));
1565 goto error_parse;
1566 }
1567 used += result;
1568 result = wlp_get_wss_virt(wlp, ptr + used, virt_addr, len - used);
1569 if (result < 0) {
1570 dev_err(dev, "WLP: unable to obtain WSS virtual address "
1571 "attribute from %s message.\n",
1572 wlp_assoc_frame_str(assoc->type));
1573 goto error_parse;
1574 }
1575 wlp_wss_uuid_print(buf, sizeof(buf), wssid);
1576 d_printf(6, dev, "WLP: parsed: WSSID %s, tag 0x%02x, virt "
1577 "%02x:%02x:%02x:%02x:%02x:%02x \n", buf, *tag,
1578 virt_addr->data[0], virt_addr->data[1], virt_addr->data[2],
1579 virt_addr->data[3], virt_addr->data[4], virt_addr->data[5]);
1580
1581error_parse:
1582 d_fnend(6, dev, "wlp %p, skb %p, result = %d \n", wlp, skb, result);
1583 return result;
1584}
1585
1586/**
1587 * Allocate memory for and populate fields of C1 or C2 association frame
1588 *
1589 * The C1 and C2 association frames appear identical - except for the type.
1590 */
1591static
1592int wlp_build_assoc_c1c2(struct wlp *wlp, struct wlp_wss *wss,
1593 struct sk_buff **skb, enum wlp_assoc_type type)
1594{
1595 struct device *dev = &wlp->rc->uwb_dev.dev;
1596 int result = -ENOMEM;
1597 struct {
1598 struct wlp_frame_assoc c_hdr;
1599 struct wlp_attr_wssid wssid;
1600 } *c;
1601 struct sk_buff *_skb;
1602
1603 d_fnstart(6, dev, "wlp %p, wss %p \n", wlp, wss);
1604 _skb = dev_alloc_skb(sizeof(*c));
1605 if (_skb == NULL) {
1606 dev_err(dev, "WLP: Unable to allocate memory for C1/C2 "
1607 "association frame. \n");
1608 goto error_alloc;
1609 }
1610 c = (void *) _skb->data;
1611 d_printf(6, dev, "C1/C2 starts at %p \n", c);
1612 c->c_hdr.hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID);
1613 c->c_hdr.hdr.type = WLP_FRAME_ASSOCIATION;
1614 c->c_hdr.type = type;
1615 wlp_set_version(&c->c_hdr.version, WLP_VERSION);
1616 wlp_set_msg_type(&c->c_hdr.msg_type, type);
1617 wlp_set_wssid(&c->wssid, &wss->wssid);
1618 skb_put(_skb, sizeof(*c));
1619 d_printf(6, dev, "C1/C2 message:\n");
1620 d_dump(6, dev, c, sizeof(*c));
1621 *skb = _skb;
1622 result = 0;
1623error_alloc:
1624 d_fnend(6, dev, "wlp %p, wss %p, result %d \n", wlp, wss, result);
1625 return result;
1626}
1627
1628
1629static
1630int wlp_build_assoc_c1(struct wlp *wlp, struct wlp_wss *wss,
1631 struct sk_buff **skb)
1632{
1633 return wlp_build_assoc_c1c2(wlp, wss, skb, WLP_ASSOC_C1);
1634}
1635
1636static
1637int wlp_build_assoc_c2(struct wlp *wlp, struct wlp_wss *wss,
1638 struct sk_buff **skb)
1639{
1640 return wlp_build_assoc_c1c2(wlp, wss, skb, WLP_ASSOC_C2);
1641}
1642
1643
1644/**
1645 * Allocate memory for and populate fields of C3 or C4 association frame
1646 *
1647 * The C3 and C4 association frames appear identical - except for the type.
1648 */
1649static
1650int wlp_build_assoc_c3c4(struct wlp *wlp, struct wlp_wss *wss,
1651 struct sk_buff **skb, enum wlp_assoc_type type)
1652{
1653 struct device *dev = &wlp->rc->uwb_dev.dev;
1654 int result = -ENOMEM;
1655 struct {
1656 struct wlp_frame_assoc c_hdr;
1657 struct wlp_attr_wssid wssid;
1658 struct wlp_attr_wss_tag wss_tag;
1659 struct wlp_attr_wss_virt wss_virt;
1660 } *c;
1661 struct sk_buff *_skb;
1662
1663 d_fnstart(6, dev, "wlp %p, wss %p \n", wlp, wss);
1664 _skb = dev_alloc_skb(sizeof(*c));
1665 if (_skb == NULL) {
1666 dev_err(dev, "WLP: Unable to allocate memory for C3/C4 "
1667 "association frame. \n");
1668 goto error_alloc;
1669 }
1670 c = (void *) _skb->data;
1671 d_printf(6, dev, "C3/C4 starts at %p \n", c);
1672 c->c_hdr.hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID);
1673 c->c_hdr.hdr.type = WLP_FRAME_ASSOCIATION;
1674 c->c_hdr.type = type;
1675 wlp_set_version(&c->c_hdr.version, WLP_VERSION);
1676 wlp_set_msg_type(&c->c_hdr.msg_type, type);
1677 wlp_set_wssid(&c->wssid, &wss->wssid);
1678 wlp_set_wss_tag(&c->wss_tag, wss->tag);
1679 wlp_set_wss_virt(&c->wss_virt, &wss->virtual_addr);
1680 skb_put(_skb, sizeof(*c));
1681 d_printf(6, dev, "C3/C4 message:\n");
1682 d_dump(6, dev, c, sizeof(*c));
1683 *skb = _skb;
1684 result = 0;
1685error_alloc:
1686 d_fnend(6, dev, "wlp %p, wss %p, result %d \n", wlp, wss, result);
1687 return result;
1688}
1689
1690static
1691int wlp_build_assoc_c3(struct wlp *wlp, struct wlp_wss *wss,
1692 struct sk_buff **skb)
1693{
1694 return wlp_build_assoc_c3c4(wlp, wss, skb, WLP_ASSOC_C3);
1695}
1696
1697static
1698int wlp_build_assoc_c4(struct wlp *wlp, struct wlp_wss *wss,
1699 struct sk_buff **skb)
1700{
1701 return wlp_build_assoc_c3c4(wlp, wss, skb, WLP_ASSOC_C4);
1702}
1703
1704
1705#define wlp_send_assoc(type, id) \
1706static int wlp_send_assoc_##type(struct wlp *wlp, struct wlp_wss *wss, \
1707 struct uwb_dev_addr *dev_addr) \
1708{ \
1709 struct device *dev = &wlp->rc->uwb_dev.dev; \
1710 int result; \
1711 struct sk_buff *skb = NULL; \
1712 d_fnstart(6, dev, "wlp %p, wss %p, neighbor: %02x:%02x\n", \
1713 wlp, wss, dev_addr->data[1], dev_addr->data[0]); \
1714 d_printf(6, dev, "WLP: Constructing %s frame. \n", \
1715 wlp_assoc_frame_str(id)); \
1716 /* Build the frame */ \
1717 result = wlp_build_assoc_##type(wlp, wss, &skb); \
1718 if (result < 0) { \
1719 dev_err(dev, "WLP: Unable to construct %s association " \
1720 "frame: %d\n", wlp_assoc_frame_str(id), result);\
1721 goto error_build_assoc; \
1722 } \
1723 /* Send the frame */ \
1724 d_printf(6, dev, "Transmitting %s frame to %02x:%02x \n", \
1725 wlp_assoc_frame_str(id), \
1726 dev_addr->data[1], dev_addr->data[0]); \
1727 BUG_ON(wlp->xmit_frame == NULL); \
1728 result = wlp->xmit_frame(wlp, skb, dev_addr); \
1729 if (result < 0) { \
1730 dev_err(dev, "WLP: Unable to transmit %s association " \
1731 "message: %d\n", wlp_assoc_frame_str(id), \
1732 result); \
1733 if (result == -ENXIO) \
1734 dev_err(dev, "WLP: Is network interface " \
1735 "up? \n"); \
1736 goto error_xmit; \
1737 } \
1738 return 0; \
1739error_xmit: \
1740 /* We could try again ... */ \
1741 dev_kfree_skb_any(skb);/*we need to free if tx fails*/ \
1742error_build_assoc: \
1743 d_fnend(6, dev, "wlp %p, wss %p, neighbor: %02x:%02x\n", \
1744 wlp, wss, dev_addr->data[1], dev_addr->data[0]); \
1745 return result; \
1746}
1747
1748wlp_send_assoc(d1, WLP_ASSOC_D1)
1749wlp_send_assoc(c1, WLP_ASSOC_C1)
1750wlp_send_assoc(c3, WLP_ASSOC_C3)
1751
1752int wlp_send_assoc_frame(struct wlp *wlp, struct wlp_wss *wss,
1753 struct uwb_dev_addr *dev_addr,
1754 enum wlp_assoc_type type)
1755{
1756 int result = 0;
1757 struct device *dev = &wlp->rc->uwb_dev.dev;
1758 switch (type) {
1759 case WLP_ASSOC_D1:
1760 result = wlp_send_assoc_d1(wlp, wss, dev_addr);
1761 break;
1762 case WLP_ASSOC_C1:
1763 result = wlp_send_assoc_c1(wlp, wss, dev_addr);
1764 break;
1765 case WLP_ASSOC_C3:
1766 result = wlp_send_assoc_c3(wlp, wss, dev_addr);
1767 break;
1768 default:
1769 dev_err(dev, "WLP: Received request to send unknown "
1770 "association message.\n");
1771 result = -EINVAL;
1772 break;
1773 }
1774 return result;
1775}
1776
1777/**
1778 * Handle incoming C1 frame
1779 *
1780 * The frame has already been verified to contain an Association header with
1781 * the correct version number. Parse the incoming frame, construct and send
1782 * a C2 frame in response.
1783 */
1784void wlp_handle_c1_frame(struct work_struct *ws)
1785{
1786 struct wlp_assoc_frame_ctx *frame_ctx = container_of(ws,
1787 struct wlp_assoc_frame_ctx,
1788 ws);
1789 struct wlp *wlp = frame_ctx->wlp;
1790 struct wlp_wss *wss = &wlp->wss;
1791 struct device *dev = &wlp->rc->uwb_dev.dev;
1792 struct wlp_frame_assoc *c1 = (void *) frame_ctx->skb->data;
1793 unsigned int len = frame_ctx->skb->len;
1794 struct uwb_dev_addr *src = &frame_ctx->src;
1795 int result;
1796 struct wlp_uuid wssid;
1797 char buf[WLP_WSS_UUID_STRSIZE];
1798 struct sk_buff *resp = NULL;
1799
1800 /* Parse C1 frame */
1801 d_fnstart(6, dev, "WLP: handle C1 frame. wlp = %p, c1 = %p\n",
1802 wlp, c1);
1803 mutex_lock(&wss->mutex);
1804 result = wlp_get_wssid(wlp, (void *)c1 + sizeof(*c1), &wssid,
1805 len - sizeof(*c1));
1806 if (result < 0) {
1807 dev_err(dev, "WLP: unable to obtain WSSID from C1 frame.\n");
1808 goto out;
1809 }
1810 wlp_wss_uuid_print(buf, sizeof(buf), &wssid);
1811 d_printf(6, dev, "Received C1 frame with WSSID %s \n", buf);
1812 if (!memcmp(&wssid, &wss->wssid, sizeof(wssid))
1813 && wss->state == WLP_WSS_STATE_ACTIVE) {
1814 d_printf(6, dev, "WSSID from C1 frame is known locally "
1815 "and is active\n");
1816 /* Construct C2 frame */
1817 result = wlp_build_assoc_c2(wlp, wss, &resp);
1818 if (result < 0) {
1819 dev_err(dev, "WLP: Unable to construct C2 message.\n");
1820 goto out;
1821 }
1822 } else {
1823 d_printf(6, dev, "WSSID from C1 frame is not known locally "
1824 "or is not active\n");
1825 /* Construct F0 frame */
1826 result = wlp_build_assoc_f0(wlp, &resp, WLP_ASSOC_ERROR_INV);
1827 if (result < 0) {
1828 dev_err(dev, "WLP: Unable to construct F0 message.\n");
1829 goto out;
1830 }
1831 }
1832 /* Send C2 frame */
1833 d_printf(6, dev, "Transmitting response (C2/F0) frame to %02x:%02x \n",
1834 src->data[1], src->data[0]);
1835 BUG_ON(wlp->xmit_frame == NULL);
1836 result = wlp->xmit_frame(wlp, resp, src);
1837 if (result < 0) {
1838 dev_err(dev, "WLP: Unable to transmit response association "
1839 "message: %d\n", result);
1840 if (result == -ENXIO)
1841 dev_err(dev, "WLP: Is network interface up? \n");
1842 /* We could try again ... */
1843 dev_kfree_skb_any(resp); /* we need to free if tx fails */
1844 }
1845out:
1846 kfree_skb(frame_ctx->skb);
1847 kfree(frame_ctx);
1848 mutex_unlock(&wss->mutex);
1849 d_fnend(6, dev, "WLP: handle C1 frame. wlp = %p\n", wlp);
1850}
1851
1852/**
1853 * Handle incoming C3 frame
1854 *
1855 * The frame has already been verified to contain an Association header with
1856 * the correct version number. Parse the incoming frame, construct and send
1857 * a C4 frame in response. If the C3 frame identifies a WSS that is locally
1858 * active then we connect to this neighbor (add it to our EDA cache).
1859 */
1860void wlp_handle_c3_frame(struct work_struct *ws)
1861{
1862 struct wlp_assoc_frame_ctx *frame_ctx = container_of(ws,
1863 struct wlp_assoc_frame_ctx,
1864 ws);
1865 struct wlp *wlp = frame_ctx->wlp;
1866 struct wlp_wss *wss = &wlp->wss;
1867 struct device *dev = &wlp->rc->uwb_dev.dev;
1868 struct sk_buff *skb = frame_ctx->skb;
1869 struct uwb_dev_addr *src = &frame_ctx->src;
1870 int result;
1871 char buf[WLP_WSS_UUID_STRSIZE];
1872 struct sk_buff *resp = NULL;
1873 struct wlp_uuid wssid;
1874 u8 tag;
1875 struct uwb_mac_addr virt_addr;
1876
1877 /* Parse C3 frame */
1878 d_fnstart(6, dev, "WLP: handle C3 frame. wlp = %p, skb = %p\n",
1879 wlp, skb);
1880 mutex_lock(&wss->mutex);
1881 result = wlp_parse_c3c4_frame(wlp, skb, &wssid, &tag, &virt_addr);
1882 if (result < 0) {
1883 dev_err(dev, "WLP: unable to obtain values from C3 frame.\n");
1884 goto out;
1885 }
1886 wlp_wss_uuid_print(buf, sizeof(buf), &wssid);
1887 d_printf(6, dev, "Received C3 frame with WSSID %s \n", buf);
1888 if (!memcmp(&wssid, &wss->wssid, sizeof(wssid))
1889 && wss->state >= WLP_WSS_STATE_ACTIVE) {
1890 d_printf(6, dev, "WSSID from C3 frame is known locally "
1891 "and is active\n");
1892 result = wlp_eda_update_node(&wlp->eda, src, wss,
1893 (void *) virt_addr.data, tag,
1894 WLP_WSS_CONNECTED);
1895 if (result < 0) {
1896 dev_err(dev, "WLP: Unable to update EDA cache "
1897 "with new connected neighbor information.\n");
1898 result = wlp_build_assoc_f0(wlp, &resp,
1899 WLP_ASSOC_ERROR_INT);
1900 if (result < 0) {
1901 dev_err(dev, "WLP: Unable to construct F0 "
1902 "message.\n");
1903 goto out;
1904 }
1905 } else {
1906 wss->state = WLP_WSS_STATE_CONNECTED;
1907 /* Construct C4 frame */
1908 result = wlp_build_assoc_c4(wlp, wss, &resp);
1909 if (result < 0) {
1910 dev_err(dev, "WLP: Unable to construct C4 "
1911 "message.\n");
1912 goto out;
1913 }
1914 }
1915 } else {
1916 d_printf(6, dev, "WSSID from C3 frame is not known locally "
1917 "or is not active\n");
1918 /* Construct F0 frame */
1919 result = wlp_build_assoc_f0(wlp, &resp, WLP_ASSOC_ERROR_INV);
1920 if (result < 0) {
1921 dev_err(dev, "WLP: Unable to construct F0 message.\n");
1922 goto out;
1923 }
1924 }
1925 /* Send C4 frame */
1926 d_printf(6, dev, "Transmitting response (C4/F0) frame to %02x:%02x \n",
1927 src->data[1], src->data[0]);
1928 BUG_ON(wlp->xmit_frame == NULL);
1929 result = wlp->xmit_frame(wlp, resp, src);
1930 if (result < 0) {
1931 dev_err(dev, "WLP: Unable to transmit response association "
1932 "message: %d\n", result);
1933 if (result == -ENXIO)
1934 dev_err(dev, "WLP: Is network interface up? \n");
1935 /* We could try again ... */
1936 dev_kfree_skb_any(resp); /* we need to free if tx fails */
1937 }
1938out:
1939 kfree_skb(frame_ctx->skb);
1940 kfree(frame_ctx);
1941 mutex_unlock(&wss->mutex);
1942 d_fnend(6, dev, "WLP: handle C3 frame. wlp = %p, skb = %p\n",
1943 wlp, skb);
1944}
1945
1946
diff --git a/drivers/uwb/wlp/sysfs.c b/drivers/uwb/wlp/sysfs.c
new file mode 100644
index 000000000000..1bb9b1f97d47
--- /dev/null
+++ b/drivers/uwb/wlp/sysfs.c
@@ -0,0 +1,709 @@
1/*
2 * WiMedia Logical Link Control Protocol (WLP)
3 * sysfs functions
4 *
5 * Copyright (C) 2007 Intel Corporation
6 * Reinette Chatre <reinette.chatre@intel.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version
10 * 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA.
21 *
22 *
23 * FIXME: Docs
24 *
25 */
26
27#include <linux/wlp.h>
28#include "wlp-internal.h"
29
30static
31size_t wlp_wss_wssid_e_print(char *buf, size_t bufsize,
32 struct wlp_wssid_e *wssid_e)
33{
34 size_t used = 0;
35 used += scnprintf(buf, bufsize, " WSS: ");
36 used += wlp_wss_uuid_print(buf + used, bufsize - used,
37 &wssid_e->wssid);
38
39 if (wssid_e->info != NULL) {
40 used += scnprintf(buf + used, bufsize - used, " ");
41 used += uwb_mac_addr_print(buf + used, bufsize - used,
42 &wssid_e->info->bcast);
43 used += scnprintf(buf + used, bufsize - used, " %u %u %s\n",
44 wssid_e->info->accept_enroll,
45 wssid_e->info->sec_status,
46 wssid_e->info->name);
47 }
48 return used;
49}
50
51/**
52 * Print out information learned from neighbor discovery
53 *
54 * Some fields being printed may not be included in the device discovery
55 * information (it is not mandatory). We are thus careful how the
56 * information is printed to ensure it is clear to the user what field is
57 * being referenced.
58 * The information being printed is for one time use - temporary storage is
59 * cleaned after it is printed.
60 *
61 * Ideally sysfs output should be on one line. The information printed here
62 * contain a few strings so it will be hard to parse if they are all
63 * printed on the same line - without agreeing on a standard field
64 * separator.
65 */
66static
67ssize_t wlp_wss_neighborhood_print_remove(struct wlp *wlp, char *buf,
68 size_t bufsize)
69{
70 size_t used = 0;
71 struct wlp_neighbor_e *neighb;
72 struct wlp_wssid_e *wssid_e;
73
74 mutex_lock(&wlp->nbmutex);
75 used = scnprintf(buf, bufsize, "#Neighbor information\n"
76 "#uuid dev_addr\n"
77 "# Device Name:\n# Model Name:\n# Manufacturer:\n"
78 "# Model Nr:\n# Serial:\n"
79 "# Pri Dev type: CategoryID OUI OUISubdiv "
80 "SubcategoryID\n"
81 "# WSS: WSSID WSS_name accept_enroll sec_status "
82 "bcast\n"
83 "# WSS: WSSID WSS_name accept_enroll sec_status "
84 "bcast\n\n");
85 list_for_each_entry(neighb, &wlp->neighbors, node) {
86 if (bufsize - used <= 0)
87 goto out;
88 used += wlp_wss_uuid_print(buf + used, bufsize - used,
89 &neighb->uuid);
90 buf[used++] = ' ';
91 used += uwb_dev_addr_print(buf + used, bufsize - used,
92 &neighb->uwb_dev->dev_addr);
93 if (neighb->info != NULL)
94 used += scnprintf(buf + used, bufsize - used,
95 "\n Device Name: %s\n"
96 " Model Name: %s\n"
97 " Manufacturer:%s \n"
98 " Model Nr: %s\n"
99 " Serial: %s\n"
100 " Pri Dev type: "
101 "%u %02x:%02x:%02x %u %u\n",
102 neighb->info->name,
103 neighb->info->model_name,
104 neighb->info->manufacturer,
105 neighb->info->model_nr,
106 neighb->info->serial,
107 neighb->info->prim_dev_type.category,
108 neighb->info->prim_dev_type.OUI[0],
109 neighb->info->prim_dev_type.OUI[1],
110 neighb->info->prim_dev_type.OUI[2],
111 neighb->info->prim_dev_type.OUIsubdiv,
112 neighb->info->prim_dev_type.subID);
113 list_for_each_entry(wssid_e, &neighb->wssid, node) {
114 used += wlp_wss_wssid_e_print(buf + used,
115 bufsize - used,
116 wssid_e);
117 }
118 buf[used++] = '\n';
119 wlp_remove_neighbor_tmp_info(neighb);
120 }
121
122
123out:
124 mutex_unlock(&wlp->nbmutex);
125 return used;
126}
127
128
129/**
130 * Show properties of all WSS in neighborhood.
131 *
132 * Will trigger a complete discovery of WSS activated by this device and
133 * its neighbors.
134 */
135ssize_t wlp_neighborhood_show(struct wlp *wlp, char *buf)
136{
137 wlp_discover(wlp);
138 return wlp_wss_neighborhood_print_remove(wlp, buf, PAGE_SIZE);
139}
140EXPORT_SYMBOL_GPL(wlp_neighborhood_show);
141
142static
143ssize_t __wlp_wss_properties_show(struct wlp_wss *wss, char *buf,
144 size_t bufsize)
145{
146 ssize_t result;
147
148 result = wlp_wss_uuid_print(buf, bufsize, &wss->wssid);
149 result += scnprintf(buf + result, bufsize - result, " ");
150 result += uwb_mac_addr_print(buf + result, bufsize - result,
151 &wss->bcast);
152 result += scnprintf(buf + result, bufsize - result,
153 " 0x%02x %u ", wss->hash, wss->secure_status);
154 result += wlp_wss_key_print(buf + result, bufsize - result,
155 wss->master_key);
156 result += scnprintf(buf + result, bufsize - result, " 0x%02x ",
157 wss->tag);
158 result += uwb_mac_addr_print(buf + result, bufsize - result,
159 &wss->virtual_addr);
160 result += scnprintf(buf + result, bufsize - result, " %s", wss->name);
161 result += scnprintf(buf + result, bufsize - result,
162 "\n\n#WSSID\n#WSS broadcast address\n"
163 "#WSS hash\n#WSS secure status\n"
164 "#WSS master key\n#WSS local tag\n"
165 "#WSS local virtual EUI-48\n#WSS name\n");
166 return result;
167}
168
169/**
170 * Show which WSS is activated.
171 */
172ssize_t wlp_wss_activate_show(struct wlp_wss *wss, char *buf)
173{
174 int result = 0;
175
176 if (mutex_lock_interruptible(&wss->mutex))
177 goto out;
178 if (wss->state >= WLP_WSS_STATE_ACTIVE)
179 result = __wlp_wss_properties_show(wss, buf, PAGE_SIZE);
180 else
181 result = scnprintf(buf, PAGE_SIZE, "No local WSS active.\n");
182 result += scnprintf(buf + result, PAGE_SIZE - result,
183 "\n\n"
184 "# echo WSSID SECURE_STATUS ACCEPT_ENROLLMENT "
185 "NAME #create new WSS\n"
186 "# echo WSSID [DEV ADDR] #enroll in and activate "
187 "existing WSS, can request registrar\n"
188 "#\n"
189 "# WSSID is a 16 byte hex array. Eg. 12 A3 3B ... \n"
190 "# SECURE_STATUS 0 - unsecure, 1 - secure (default)\n"
191 "# ACCEPT_ENROLLMENT 0 - no, 1 - yes (default)\n"
192 "# NAME is the text string identifying the WSS\n"
193 "# DEV ADDR is the device address of neighbor "
194 "that should be registrar. Eg. 32:AB\n");
195
196 mutex_unlock(&wss->mutex);
197out:
198 return result;
199
200}
201EXPORT_SYMBOL_GPL(wlp_wss_activate_show);
202
203/**
204 * Create/activate a new WSS or enroll/activate in neighboring WSS
205 *
206 * The user can provide the WSSID of a WSS in which it wants to enroll.
207 * Only the WSSID is necessary if the WSS have been discovered before. If
208 * the WSS has not been discovered before, or the user wants to use a
209 * particular neighbor as its registrar, then the user can also provide a
210 * device address or the neighbor that will be used as registrar.
211 *
212 * A new WSS is created when the user provides a WSSID, secure status, and
213 * WSS name.
214 */
215ssize_t wlp_wss_activate_store(struct wlp_wss *wss,
216 const char *buf, size_t size)
217{
218 ssize_t result = -EINVAL;
219 struct wlp_uuid wssid;
220 struct uwb_dev_addr dev;
221 struct uwb_dev_addr bcast = {.data = {0xff, 0xff} };
222 char name[65];
223 unsigned sec_status, accept;
224 memset(name, 0, sizeof(name));
225 result = sscanf(buf, "%02hhx %02hhx %02hhx %02hhx "
226 "%02hhx %02hhx %02hhx %02hhx "
227 "%02hhx %02hhx %02hhx %02hhx "
228 "%02hhx %02hhx %02hhx %02hhx "
229 "%02hhx:%02hhx",
230 &wssid.data[0] , &wssid.data[1],
231 &wssid.data[2] , &wssid.data[3],
232 &wssid.data[4] , &wssid.data[5],
233 &wssid.data[6] , &wssid.data[7],
234 &wssid.data[8] , &wssid.data[9],
235 &wssid.data[10], &wssid.data[11],
236 &wssid.data[12], &wssid.data[13],
237 &wssid.data[14], &wssid.data[15],
238 &dev.data[1], &dev.data[0]);
239 if (result == 16 || result == 17) {
240 result = sscanf(buf, "%02hhx %02hhx %02hhx %02hhx "
241 "%02hhx %02hhx %02hhx %02hhx "
242 "%02hhx %02hhx %02hhx %02hhx "
243 "%02hhx %02hhx %02hhx %02hhx "
244 "%u %u %64c",
245 &wssid.data[0] , &wssid.data[1],
246 &wssid.data[2] , &wssid.data[3],
247 &wssid.data[4] , &wssid.data[5],
248 &wssid.data[6] , &wssid.data[7],
249 &wssid.data[8] , &wssid.data[9],
250 &wssid.data[10], &wssid.data[11],
251 &wssid.data[12], &wssid.data[13],
252 &wssid.data[14], &wssid.data[15],
253 &sec_status, &accept, name);
254 if (result == 16)
255 result = wlp_wss_enroll_activate(wss, &wssid, &bcast);
256 else if (result == 19) {
257 sec_status = sec_status == 0 ? 0 : 1;
258 accept = accept == 0 ? 0 : 1;
259 /* We read name using %c, so the newline needs to be
260 * removed */
261 if (strlen(name) != sizeof(name) - 1)
262 name[strlen(name) - 1] = '\0';
263 result = wlp_wss_create_activate(wss, &wssid, name,
264 sec_status, accept);
265 } else
266 result = -EINVAL;
267 } else if (result == 18)
268 result = wlp_wss_enroll_activate(wss, &wssid, &dev);
269 else
270 result = -EINVAL;
271 return result < 0 ? result : size;
272}
273EXPORT_SYMBOL_GPL(wlp_wss_activate_store);
274
275/**
276 * Show the UUID of this host
277 */
278ssize_t wlp_uuid_show(struct wlp *wlp, char *buf)
279{
280 ssize_t result = 0;
281
282 mutex_lock(&wlp->mutex);
283 result = wlp_wss_uuid_print(buf, PAGE_SIZE, &wlp->uuid);
284 buf[result++] = '\n';
285 mutex_unlock(&wlp->mutex);
286 return result;
287}
288EXPORT_SYMBOL_GPL(wlp_uuid_show);
289
290/**
291 * Store a new UUID for this host
292 *
293 * According to the spec this should be encoded as an octet string in the
294 * order the octets are shown in string representation in RFC 4122 (WLP
295 * 0.99 [Table 6])
296 *
297 * We do not check value provided by user.
298 */
299ssize_t wlp_uuid_store(struct wlp *wlp, const char *buf, size_t size)
300{
301 ssize_t result;
302 struct wlp_uuid uuid;
303
304 mutex_lock(&wlp->mutex);
305 result = sscanf(buf, "%02hhx %02hhx %02hhx %02hhx "
306 "%02hhx %02hhx %02hhx %02hhx "
307 "%02hhx %02hhx %02hhx %02hhx "
308 "%02hhx %02hhx %02hhx %02hhx ",
309 &uuid.data[0] , &uuid.data[1],
310 &uuid.data[2] , &uuid.data[3],
311 &uuid.data[4] , &uuid.data[5],
312 &uuid.data[6] , &uuid.data[7],
313 &uuid.data[8] , &uuid.data[9],
314 &uuid.data[10], &uuid.data[11],
315 &uuid.data[12], &uuid.data[13],
316 &uuid.data[14], &uuid.data[15]);
317 if (result != 16) {
318 result = -EINVAL;
319 goto error;
320 }
321 wlp->uuid = uuid;
322error:
323 mutex_unlock(&wlp->mutex);
324 return result < 0 ? result : size;
325}
326EXPORT_SYMBOL_GPL(wlp_uuid_store);
327
328/**
329 * Show contents of members of device information structure
330 */
331#define wlp_dev_info_show(type) \
332ssize_t wlp_dev_##type##_show(struct wlp *wlp, char *buf) \
333{ \
334 ssize_t result = 0; \
335 mutex_lock(&wlp->mutex); \
336 if (wlp->dev_info == NULL) { \
337 result = __wlp_setup_device_info(wlp); \
338 if (result < 0) \
339 goto out; \
340 } \
341 result = scnprintf(buf, PAGE_SIZE, "%s\n", wlp->dev_info->type);\
342out: \
343 mutex_unlock(&wlp->mutex); \
344 return result; \
345} \
346EXPORT_SYMBOL_GPL(wlp_dev_##type##_show);
347
348wlp_dev_info_show(name)
349wlp_dev_info_show(model_name)
350wlp_dev_info_show(model_nr)
351wlp_dev_info_show(manufacturer)
352wlp_dev_info_show(serial)
353
354/**
355 * Store contents of members of device information structure
356 */
357#define wlp_dev_info_store(type, len) \
358ssize_t wlp_dev_##type##_store(struct wlp *wlp, const char *buf, size_t size)\
359{ \
360 ssize_t result; \
361 char format[10]; \
362 mutex_lock(&wlp->mutex); \
363 if (wlp->dev_info == NULL) { \
364 result = __wlp_alloc_device_info(wlp); \
365 if (result < 0) \
366 goto out; \
367 } \
368 memset(wlp->dev_info->type, 0, sizeof(wlp->dev_info->type)); \
369 sprintf(format, "%%%uc", len); \
370 result = sscanf(buf, format, wlp->dev_info->type); \
371out: \
372 mutex_unlock(&wlp->mutex); \
373 return result < 0 ? result : size; \
374} \
375EXPORT_SYMBOL_GPL(wlp_dev_##type##_store);
376
377wlp_dev_info_store(name, 32)
378wlp_dev_info_store(manufacturer, 64)
379wlp_dev_info_store(model_name, 32)
380wlp_dev_info_store(model_nr, 32)
381wlp_dev_info_store(serial, 32)
382
383static
384const char *__wlp_dev_category[] = {
385 [WLP_DEV_CAT_COMPUTER] = "Computer",
386 [WLP_DEV_CAT_INPUT] = "Input device",
387 [WLP_DEV_CAT_PRINT_SCAN_FAX_COPIER] = "Printer, scanner, FAX, or "
388 "Copier",
389 [WLP_DEV_CAT_CAMERA] = "Camera",
390 [WLP_DEV_CAT_STORAGE] = "Storage Network",
391 [WLP_DEV_CAT_INFRASTRUCTURE] = "Infrastructure",
392 [WLP_DEV_CAT_DISPLAY] = "Display",
393 [WLP_DEV_CAT_MULTIM] = "Multimedia device",
394 [WLP_DEV_CAT_GAMING] = "Gaming device",
395 [WLP_DEV_CAT_TELEPHONE] = "Telephone",
396 [WLP_DEV_CAT_OTHER] = "Other",
397};
398
399static
400const char *wlp_dev_category_str(unsigned cat)
401{
402 if ((cat >= WLP_DEV_CAT_COMPUTER && cat <= WLP_DEV_CAT_TELEPHONE)
403 || cat == WLP_DEV_CAT_OTHER)
404 return __wlp_dev_category[cat];
405 return "unknown category";
406}
407
408ssize_t wlp_dev_prim_category_show(struct wlp *wlp, char *buf)
409{
410 ssize_t result = 0;
411 mutex_lock(&wlp->mutex);
412 if (wlp->dev_info == NULL) {
413 result = __wlp_setup_device_info(wlp);
414 if (result < 0)
415 goto out;
416 }
417 result = scnprintf(buf, PAGE_SIZE, "%s\n",
418 wlp_dev_category_str(wlp->dev_info->prim_dev_type.category));
419out:
420 mutex_unlock(&wlp->mutex);
421 return result;
422}
423EXPORT_SYMBOL_GPL(wlp_dev_prim_category_show);
424
425ssize_t wlp_dev_prim_category_store(struct wlp *wlp, const char *buf,
426 size_t size)
427{
428 ssize_t result;
429 u16 cat;
430 mutex_lock(&wlp->mutex);
431 if (wlp->dev_info == NULL) {
432 result = __wlp_alloc_device_info(wlp);
433 if (result < 0)
434 goto out;
435 }
436 result = sscanf(buf, "%hu", &cat);
437 if ((cat >= WLP_DEV_CAT_COMPUTER && cat <= WLP_DEV_CAT_TELEPHONE)
438 || cat == WLP_DEV_CAT_OTHER)
439 wlp->dev_info->prim_dev_type.category = cat;
440 else
441 result = -EINVAL;
442out:
443 mutex_unlock(&wlp->mutex);
444 return result < 0 ? result : size;
445}
446EXPORT_SYMBOL_GPL(wlp_dev_prim_category_store);
447
448ssize_t wlp_dev_prim_OUI_show(struct wlp *wlp, char *buf)
449{
450 ssize_t result = 0;
451 mutex_lock(&wlp->mutex);
452 if (wlp->dev_info == NULL) {
453 result = __wlp_setup_device_info(wlp);
454 if (result < 0)
455 goto out;
456 }
457 result = scnprintf(buf, PAGE_SIZE, "%02x:%02x:%02x\n",
458 wlp->dev_info->prim_dev_type.OUI[0],
459 wlp->dev_info->prim_dev_type.OUI[1],
460 wlp->dev_info->prim_dev_type.OUI[2]);
461out:
462 mutex_unlock(&wlp->mutex);
463 return result;
464}
465EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_show);
466
467ssize_t wlp_dev_prim_OUI_store(struct wlp *wlp, const char *buf, size_t size)
468{
469 ssize_t result;
470 u8 OUI[3];
471 mutex_lock(&wlp->mutex);
472 if (wlp->dev_info == NULL) {
473 result = __wlp_alloc_device_info(wlp);
474 if (result < 0)
475 goto out;
476 }
477 result = sscanf(buf, "%hhx:%hhx:%hhx",
478 &OUI[0], &OUI[1], &OUI[2]);
479 if (result != 3) {
480 result = -EINVAL;
481 goto out;
482 } else
483 memcpy(wlp->dev_info->prim_dev_type.OUI, OUI, sizeof(OUI));
484out:
485 mutex_unlock(&wlp->mutex);
486 return result < 0 ? result : size;
487}
488EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_store);
489
490
491ssize_t wlp_dev_prim_OUI_sub_show(struct wlp *wlp, char *buf)
492{
493 ssize_t result = 0;
494 mutex_lock(&wlp->mutex);
495 if (wlp->dev_info == NULL) {
496 result = __wlp_setup_device_info(wlp);
497 if (result < 0)
498 goto out;
499 }
500 result = scnprintf(buf, PAGE_SIZE, "%u\n",
501 wlp->dev_info->prim_dev_type.OUIsubdiv);
502out:
503 mutex_unlock(&wlp->mutex);
504 return result;
505}
506EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_sub_show);
507
508ssize_t wlp_dev_prim_OUI_sub_store(struct wlp *wlp, const char *buf,
509 size_t size)
510{
511 ssize_t result;
512 unsigned sub;
513 u8 max_sub = ~0;
514 mutex_lock(&wlp->mutex);
515 if (wlp->dev_info == NULL) {
516 result = __wlp_alloc_device_info(wlp);
517 if (result < 0)
518 goto out;
519 }
520 result = sscanf(buf, "%u", &sub);
521 if (sub <= max_sub)
522 wlp->dev_info->prim_dev_type.OUIsubdiv = sub;
523 else
524 result = -EINVAL;
525out:
526 mutex_unlock(&wlp->mutex);
527 return result < 0 ? result : size;
528}
529EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_sub_store);
530
531ssize_t wlp_dev_prim_subcat_show(struct wlp *wlp, char *buf)
532{
533 ssize_t result = 0;
534 mutex_lock(&wlp->mutex);
535 if (wlp->dev_info == NULL) {
536 result = __wlp_setup_device_info(wlp);
537 if (result < 0)
538 goto out;
539 }
540 result = scnprintf(buf, PAGE_SIZE, "%u\n",
541 wlp->dev_info->prim_dev_type.subID);
542out:
543 mutex_unlock(&wlp->mutex);
544 return result;
545}
546EXPORT_SYMBOL_GPL(wlp_dev_prim_subcat_show);
547
548ssize_t wlp_dev_prim_subcat_store(struct wlp *wlp, const char *buf,
549 size_t size)
550{
551 ssize_t result;
552 unsigned sub;
553 __le16 max_sub = ~0;
554 mutex_lock(&wlp->mutex);
555 if (wlp->dev_info == NULL) {
556 result = __wlp_alloc_device_info(wlp);
557 if (result < 0)
558 goto out;
559 }
560 result = sscanf(buf, "%u", &sub);
561 if (sub <= max_sub)
562 wlp->dev_info->prim_dev_type.subID = sub;
563 else
564 result = -EINVAL;
565out:
566 mutex_unlock(&wlp->mutex);
567 return result < 0 ? result : size;
568}
569EXPORT_SYMBOL_GPL(wlp_dev_prim_subcat_store);
570
571/**
572 * Subsystem implementation for interaction with individual WSS via sysfs
573 *
574 * Followed instructions for subsystem in Documentation/filesystems/sysfs.txt
575 */
576
577#define kobj_to_wlp_wss(obj) container_of(obj, struct wlp_wss, kobj)
578#define attr_to_wlp_wss_attr(_attr) \
579 container_of(_attr, struct wlp_wss_attribute, attr)
580
581/**
582 * Sysfs subsystem: forward read calls
583 *
584 * Sysfs operation for forwarding read call to the show method of the
585 * attribute owner
586 */
587static
588ssize_t wlp_wss_attr_show(struct kobject *kobj, struct attribute *attr,
589 char *buf)
590{
591 struct wlp_wss_attribute *wss_attr = attr_to_wlp_wss_attr(attr);
592 struct wlp_wss *wss = kobj_to_wlp_wss(kobj);
593 ssize_t ret = -EIO;
594
595 if (wss_attr->show)
596 ret = wss_attr->show(wss, buf);
597 return ret;
598}
599/**
600 * Sysfs subsystem: forward write calls
601 *
602 * Sysfs operation for forwarding write call to the store method of the
603 * attribute owner
604 */
605static
606ssize_t wlp_wss_attr_store(struct kobject *kobj, struct attribute *attr,
607 const char *buf, size_t count)
608{
609 struct wlp_wss_attribute *wss_attr = attr_to_wlp_wss_attr(attr);
610 struct wlp_wss *wss = kobj_to_wlp_wss(kobj);
611 ssize_t ret = -EIO;
612
613 if (wss_attr->store)
614 ret = wss_attr->store(wss, buf, count);
615 return ret;
616}
617
618static
619struct sysfs_ops wss_sysfs_ops = {
620 .show = wlp_wss_attr_show,
621 .store = wlp_wss_attr_store,
622};
623
624struct kobj_type wss_ktype = {
625 .release = wlp_wss_release,
626 .sysfs_ops = &wss_sysfs_ops,
627};
628
629
630/**
631 * Sysfs files for individual WSS
632 */
633
634/**
635 * Print static properties of this WSS
636 *
637 * The name of a WSS may not be null teminated. It's max size is 64 bytes
638 * so we copy it to a larger array just to make sure we print sane data.
639 */
640static ssize_t wlp_wss_properties_show(struct wlp_wss *wss, char *buf)
641{
642 int result = 0;
643
644 if (mutex_lock_interruptible(&wss->mutex))
645 goto out;
646 result = __wlp_wss_properties_show(wss, buf, PAGE_SIZE);
647 mutex_unlock(&wss->mutex);
648out:
649 return result;
650}
651WSS_ATTR(properties, S_IRUGO, wlp_wss_properties_show, NULL);
652
653/**
654 * Print all connected members of this WSS
655 * The EDA cache contains all members of WSS neighborhood.
656 */
657static ssize_t wlp_wss_members_show(struct wlp_wss *wss, char *buf)
658{
659 struct wlp *wlp = container_of(wss, struct wlp, wss);
660 return wlp_eda_show(wlp, buf);
661}
662WSS_ATTR(members, S_IRUGO, wlp_wss_members_show, NULL);
663
664static
665const char *__wlp_strstate[] = {
666 "none",
667 "partially enrolled",
668 "enrolled",
669 "active",
670 "connected",
671};
672
673static const char *wlp_wss_strstate(unsigned state)
674{
675 if (state >= ARRAY_SIZE(__wlp_strstate))
676 return "unknown state";
677 return __wlp_strstate[state];
678}
679
680/*
681 * Print current state of this WSS
682 */
683static ssize_t wlp_wss_state_show(struct wlp_wss *wss, char *buf)
684{
685 int result = 0;
686
687 if (mutex_lock_interruptible(&wss->mutex))
688 goto out;
689 result = scnprintf(buf, PAGE_SIZE, "%s\n",
690 wlp_wss_strstate(wss->state));
691 mutex_unlock(&wss->mutex);
692out:
693 return result;
694}
695WSS_ATTR(state, S_IRUGO, wlp_wss_state_show, NULL);
696
697
698static
699struct attribute *wss_attrs[] = {
700 &wss_attr_properties.attr,
701 &wss_attr_members.attr,
702 &wss_attr_state.attr,
703 NULL,
704};
705
706struct attribute_group wss_attr_group = {
707 .name = NULL, /* we want them in the same directory */
708 .attrs = wss_attrs,
709};
diff --git a/drivers/uwb/wlp/txrx.c b/drivers/uwb/wlp/txrx.c
new file mode 100644
index 000000000000..c701bd1a2887
--- /dev/null
+++ b/drivers/uwb/wlp/txrx.c
@@ -0,0 +1,374 @@
1/*
2 * WiMedia Logical Link Control Protocol (WLP)
3 * Message exchange infrastructure
4 *
5 * Copyright (C) 2007 Intel Corporation
6 * Reinette Chatre <reinette.chatre@intel.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version
10 * 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA.
21 *
22 *
23 * FIXME: Docs
24 *
25 */
26
27#include <linux/etherdevice.h>
28#include <linux/wlp.h>
29#define D_LOCAL 5
30#include <linux/uwb/debug.h>
31#include "wlp-internal.h"
32
33
34/**
35 * Direct incoming association msg to correct parsing routine
36 *
37 * We only expect D1, E1, C1, C3 messages as new. All other incoming
38 * association messages should form part of an established session that is
39 * handled elsewhere.
40 * The handling of these messages often require calling sleeping functions
41 * - this cannot be done in interrupt context. We use the kernel's
42 * workqueue to handle these messages.
43 */
44static
45void wlp_direct_assoc_frame(struct wlp *wlp, struct sk_buff *skb,
46 struct uwb_dev_addr *src)
47{
48 struct device *dev = &wlp->rc->uwb_dev.dev;
49 struct wlp_frame_assoc *assoc = (void *) skb->data;
50 struct wlp_assoc_frame_ctx *frame_ctx;
51 d_fnstart(5, dev, "wlp %p, skb %p\n", wlp, skb);
52 frame_ctx = kmalloc(sizeof(*frame_ctx), GFP_ATOMIC);
53 if (frame_ctx == NULL) {
54 dev_err(dev, "WLP: Unable to allocate memory for association "
55 "frame handling.\n");
56 kfree_skb(skb);
57 goto out;
58 }
59 frame_ctx->wlp = wlp;
60 frame_ctx->skb = skb;
61 frame_ctx->src = *src;
62 switch (assoc->type) {
63 case WLP_ASSOC_D1:
64 d_printf(5, dev, "Received a D1 frame.\n");
65 INIT_WORK(&frame_ctx->ws, wlp_handle_d1_frame);
66 schedule_work(&frame_ctx->ws);
67 break;
68 case WLP_ASSOC_E1:
69 d_printf(5, dev, "Received a E1 frame. FIXME?\n");
70 kfree_skb(skb); /* Temporary until we handle it */
71 kfree(frame_ctx); /* Temporary until we handle it */
72 break;
73 case WLP_ASSOC_C1:
74 d_printf(5, dev, "Received a C1 frame.\n");
75 INIT_WORK(&frame_ctx->ws, wlp_handle_c1_frame);
76 schedule_work(&frame_ctx->ws);
77 break;
78 case WLP_ASSOC_C3:
79 d_printf(5, dev, "Received a C3 frame.\n");
80 INIT_WORK(&frame_ctx->ws, wlp_handle_c3_frame);
81 schedule_work(&frame_ctx->ws);
82 break;
83 default:
84 dev_err(dev, "Received unexpected association frame. "
85 "Type = %d \n", assoc->type);
86 kfree_skb(skb);
87 kfree(frame_ctx);
88 break;
89 }
90out:
91 d_fnend(5, dev, "wlp %p\n", wlp);
92}
93
94/**
95 * Process incoming association frame
96 *
97 * Although it could be possible to deal with some incoming association
98 * messages without creating a new session we are keeping things simple. We
99 * do not accept new association messages if there is a session in progress
100 * and the messages do not belong to that session.
101 *
102 * If an association message arrives that causes the creation of a session
103 * (WLP_ASSOC_E1) while we are in the process of creating a session then we
104 * rely on the neighbor mutex to protect the data. That is, the new session
105 * will not be started until the previous is completed.
106 */
107static
108void wlp_receive_assoc_frame(struct wlp *wlp, struct sk_buff *skb,
109 struct uwb_dev_addr *src)
110{
111 struct device *dev = &wlp->rc->uwb_dev.dev;
112 struct wlp_frame_assoc *assoc = (void *) skb->data;
113 struct wlp_session *session = wlp->session;
114 u8 version;
115 d_fnstart(5, dev, "wlp %p, skb %p\n", wlp, skb);
116
117 if (wlp_get_version(wlp, &assoc->version, &version,
118 sizeof(assoc->version)) < 0)
119 goto error;
120 if (version != WLP_VERSION) {
121 dev_err(dev, "Unsupported WLP version in association "
122 "message.\n");
123 goto error;
124 }
125 if (session != NULL) {
126 /* Function that created this session is still holding the
127 * &wlp->mutex to protect this session. */
128 if (assoc->type == session->exp_message ||
129 assoc->type == WLP_ASSOC_F0) {
130 if (!memcmp(&session->neighbor_addr, src,
131 sizeof(*src))) {
132 session->data = skb;
133 (session->cb)(wlp);
134 } else {
135 dev_err(dev, "Received expected message from "
136 "unexpected source. Expected message "
137 "%d or F0 from %02x:%02x, but received "
138 "it from %02x:%02x. Dropping.\n",
139 session->exp_message,
140 session->neighbor_addr.data[1],
141 session->neighbor_addr.data[0],
142 src->data[1], src->data[0]);
143 goto error;
144 }
145 } else {
146 dev_err(dev, "Association already in progress. "
147 "Dropping.\n");
148 goto error;
149 }
150 } else {
151 wlp_direct_assoc_frame(wlp, skb, src);
152 }
153 d_fnend(5, dev, "wlp %p\n", wlp);
154 return;
155error:
156 kfree_skb(skb);
157 d_fnend(5, dev, "wlp %p\n", wlp);
158}
159
160/**
161 * Verify incoming frame is from connected neighbor, prep to pass to WLP client
162 *
163 * Verification proceeds according to WLP 0.99 [7.3.1]. The source address
164 * is used to determine which neighbor is sending the frame and the WSS tag
165 * is used to know to which WSS the frame belongs (we only support one WSS
166 * so this test is straight forward).
167 * With the WSS found we need to ensure that we are connected before
168 * allowing the exchange of data frames.
169 */
170static
171int wlp_verify_prep_rx_frame(struct wlp *wlp, struct sk_buff *skb,
172 struct uwb_dev_addr *src)
173{
174 struct device *dev = &wlp->rc->uwb_dev.dev;
175 int result = -EINVAL;
176 struct wlp_eda_node eda_entry;
177 struct wlp_frame_std_abbrv_hdr *hdr = (void *) skb->data;
178
179 d_fnstart(6, dev, "wlp %p, skb %p \n", wlp, skb);
180 /*verify*/
181 result = wlp_copy_eda_node(&wlp->eda, src, &eda_entry);
182 if (result < 0) {
183 if (printk_ratelimit())
184 dev_err(dev, "WLP: Incoming frame is from unknown "
185 "neighbor %02x:%02x.\n", src->data[1],
186 src->data[0]);
187 goto out;
188 }
189 if (hdr->tag != eda_entry.tag) {
190 if (printk_ratelimit())
191 dev_err(dev, "WLP: Tag of incoming frame from "
192 "%02x:%02x does not match expected tag. "
193 "Received 0x%02x, expected 0x%02x. \n",
194 src->data[1], src->data[0], hdr->tag,
195 eda_entry.tag);
196 result = -EINVAL;
197 goto out;
198 }
199 if (eda_entry.state != WLP_WSS_CONNECTED) {
200 if (printk_ratelimit())
201 dev_err(dev, "WLP: Incoming frame from "
202 "%02x:%02x does is not from connected WSS.\n",
203 src->data[1], src->data[0]);
204 result = -EINVAL;
205 goto out;
206 }
207 /*prep*/
208 skb_pull(skb, sizeof(*hdr));
209out:
210 d_fnend(6, dev, "wlp %p, skb %p, result = %d \n", wlp, skb, result);
211 return result;
212}
213
214/**
215 * Receive a WLP frame from device
216 *
217 * @returns: 1 if calling function should free the skb
218 * 0 if it successfully handled skb and freed it
219 * 0 if error occured, will free skb in this case
220 */
221int wlp_receive_frame(struct device *dev, struct wlp *wlp, struct sk_buff *skb,
222 struct uwb_dev_addr *src)
223{
224 unsigned len = skb->len;
225 void *ptr = skb->data;
226 struct wlp_frame_hdr *hdr;
227 int result = 0;
228
229 d_fnstart(6, dev, "skb (%p), len (%u)\n", skb, len);
230 if (len < sizeof(*hdr)) {
231 dev_err(dev, "Not enough data to parse WLP header.\n");
232 result = -EINVAL;
233 goto out;
234 }
235 hdr = ptr;
236 d_dump(6, dev, hdr, sizeof(*hdr));
237 if (le16_to_cpu(hdr->mux_hdr) != WLP_PROTOCOL_ID) {
238 dev_err(dev, "Not a WLP frame type.\n");
239 result = -EINVAL;
240 goto out;
241 }
242 switch (hdr->type) {
243 case WLP_FRAME_STANDARD:
244 if (len < sizeof(struct wlp_frame_std_abbrv_hdr)) {
245 dev_err(dev, "Not enough data to parse Standard "
246 "WLP header.\n");
247 goto out;
248 }
249 result = wlp_verify_prep_rx_frame(wlp, skb, src);
250 if (result < 0) {
251 if (printk_ratelimit())
252 dev_err(dev, "WLP: Verification of frame "
253 "from neighbor %02x:%02x failed.\n",
254 src->data[1], src->data[0]);
255 goto out;
256 }
257 result = 1;
258 break;
259 case WLP_FRAME_ABBREVIATED:
260 dev_err(dev, "Abbreviated frame received. FIXME?\n");
261 kfree_skb(skb);
262 break;
263 case WLP_FRAME_CONTROL:
264 dev_err(dev, "Control frame received. FIXME?\n");
265 kfree_skb(skb);
266 break;
267 case WLP_FRAME_ASSOCIATION:
268 if (len < sizeof(struct wlp_frame_assoc)) {
269 dev_err(dev, "Not enough data to parse Association "
270 "WLP header.\n");
271 goto out;
272 }
273 d_printf(5, dev, "Association frame received.\n");
274 wlp_receive_assoc_frame(wlp, skb, src);
275 break;
276 default:
277 dev_err(dev, "Invalid frame received.\n");
278 result = -EINVAL;
279 break;
280 }
281out:
282 if (result < 0) {
283 kfree_skb(skb);
284 result = 0;
285 }
286 d_fnend(6, dev, "skb (%p)\n", skb);
287 return result;
288}
289EXPORT_SYMBOL_GPL(wlp_receive_frame);
290
291
292/**
293 * Verify frame from network stack, prepare for further transmission
294 *
295 * @skb: the socket buffer that needs to be prepared for transmission (it
296 * is in need of a WLP header). If this is a broadcast frame we take
297 * over the entire transmission.
298 * If it is a unicast the WSS connection should already be established
299 * and transmission will be done by the calling function.
300 * @dst: On return this will contain the device address to which the
301 * frame is destined.
302 * @returns: 0 on success no tx : WLP header sucessfully applied to skb buffer,
303 * calling function can proceed with tx
304 * 1 on success with tx : WLP will take over transmission of this
305 * frame
306 * <0 on error
307 *
308 * The network stack (WLP client) is attempting to transmit a frame. We can
309 * only transmit data if a local WSS is at least active (connection will be
310 * done here if this is a broadcast frame and neighbor also has the WSS
311 * active).
312 *
313 * The frame can be either broadcast or unicast. Broadcast in a WSS is
314 * supported via multicast, but we don't support multicast yet (until
315 * devices start to support MAB IEs). If a broadcast frame needs to be
316 * transmitted it is treated as a unicast frame to each neighbor. In this
317 * case the WLP takes over transmission of the skb and returns 1
318 * to the caller to indicate so. Also, in this case, if a neighbor has the
319 * same WSS activated but is not connected then the WSS connection will be
320 * done at this time. The neighbor's virtual address will be learned at
321 * this time.
322 *
323 * The destination address in a unicast frame is the virtual address of the
324 * neighbor. This address only becomes known when a WSS connection is
325 * established. We thus rely on a broadcast frame to trigger the setup of
326 * WSS connections to all neighbors before we are able to send unicast
327 * frames to them. This seems reasonable as IP would usually use ARP first
328 * before any unicast frames are sent.
329 *
330 * If we are already connected to the neighbor (neighbor's virtual address
331 * is known) we just prepare the WLP header and the caller will continue to
332 * send the frame.
333 *
334 * A failure in this function usually indicates something that cannot be
335 * fixed automatically. So, if this function fails (@return < 0) the calling
336 * function should not retry to send the frame as it will very likely keep
337 * failing.
338 *
339 */
340int wlp_prepare_tx_frame(struct device *dev, struct wlp *wlp,
341 struct sk_buff *skb, struct uwb_dev_addr *dst)
342{
343 int result = -EINVAL;
344 struct ethhdr *eth_hdr = (void *) skb->data;
345
346 d_fnstart(6, dev, "wlp (%p), skb (%p) \n", wlp, skb);
347 if (is_broadcast_ether_addr(eth_hdr->h_dest)) {
348 d_printf(6, dev, "WLP: handling broadcast frame. \n");
349 result = wlp_eda_for_each(&wlp->eda, wlp_wss_send_copy, skb);
350 if (result < 0) {
351 if (printk_ratelimit())
352 dev_err(dev, "Unable to handle broadcast "
353 "frame from WLP client.\n");
354 goto out;
355 }
356 dev_kfree_skb_irq(skb);
357 result = 1;
358 /* Frame will be transmitted by WLP. */
359 } else {
360 d_printf(6, dev, "WLP: handling unicast frame. \n");
361 result = wlp_eda_for_virtual(&wlp->eda, eth_hdr->h_dest, dst,
362 wlp_wss_prep_hdr, skb);
363 if (unlikely(result < 0)) {
364 if (printk_ratelimit())
365 dev_err(dev, "Unable to prepare "
366 "skb for transmission. \n");
367 goto out;
368 }
369 }
370out:
371 d_fnend(6, dev, "wlp (%p), skb (%p). result = %d \n", wlp, skb, result);
372 return result;
373}
374EXPORT_SYMBOL_GPL(wlp_prepare_tx_frame);
diff --git a/drivers/uwb/wlp/wlp-internal.h b/drivers/uwb/wlp/wlp-internal.h
new file mode 100644
index 000000000000..1c94fabfb1a7
--- /dev/null
+++ b/drivers/uwb/wlp/wlp-internal.h
@@ -0,0 +1,228 @@
1/*
2 * WiMedia Logical Link Control Protocol (WLP)
3 * Internal API
4 *
5 * Copyright (C) 2007 Intel Corporation
6 * Reinette Chatre <reinette.chatre@intel.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version
10 * 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA.
21 *
22 */
23
24#ifndef __WLP_INTERNAL_H__
25#define __WLP_INTERNAL_H__
26
27/**
28 * State of WSS connection
29 *
30 * A device needs to connect to a neighbor in an activated WSS before data
31 * can be transmitted. The spec also distinguishes between a new connection
32 * attempt and a connection attempt after previous connection attempts. The
33 * state WLP_WSS_CONNECT_FAILED is used for this scenario. See WLP 0.99
34 * [7.2.6]
35 */
36enum wlp_wss_connect {
37 WLP_WSS_UNCONNECTED = 0,
38 WLP_WSS_CONNECTED,
39 WLP_WSS_CONNECT_FAILED,
40};
41
42extern struct kobj_type wss_ktype;
43extern struct attribute_group wss_attr_group;
44
45extern int uwb_rc_ie_add(struct uwb_rc *, const struct uwb_ie_hdr *, size_t);
46extern int uwb_rc_ie_rm(struct uwb_rc *, enum uwb_ie);
47
48
49/* This should be changed to a dynamic array where entries are sorted
50 * by eth_addr and search is done in a binary form
51 *
52 * Although thinking twice about it: this technologie's maximum reach
53 * is 10 meters...unless you want to pack too much stuff in around
54 * your radio controller/WLP device, the list will probably not be
55 * too big.
56 *
57 * In any case, there is probably some data structure in the kernel
58 * than we could reused for that already.
59 *
60 * The below structure is really just good while we support one WSS per
61 * host.
62 */
63struct wlp_eda_node {
64 struct list_head list_node;
65 unsigned char eth_addr[ETH_ALEN];
66 struct uwb_dev_addr dev_addr;
67 struct wlp_wss *wss;
68 unsigned char virt_addr[ETH_ALEN];
69 u8 tag;
70 enum wlp_wss_connect state;
71};
72
73typedef int (*wlp_eda_for_each_f)(struct wlp *, struct wlp_eda_node *, void *);
74
75extern void wlp_eda_init(struct wlp_eda *);
76extern void wlp_eda_release(struct wlp_eda *);
77extern int wlp_eda_create_node(struct wlp_eda *,
78 const unsigned char eth_addr[ETH_ALEN],
79 const struct uwb_dev_addr *);
80extern void wlp_eda_rm_node(struct wlp_eda *, const struct uwb_dev_addr *);
81extern int wlp_eda_update_node(struct wlp_eda *,
82 const struct uwb_dev_addr *,
83 struct wlp_wss *,
84 const unsigned char virt_addr[ETH_ALEN],
85 const u8, const enum wlp_wss_connect);
86extern int wlp_eda_update_node_state(struct wlp_eda *,
87 const struct uwb_dev_addr *,
88 const enum wlp_wss_connect);
89
90extern int wlp_copy_eda_node(struct wlp_eda *, struct uwb_dev_addr *,
91 struct wlp_eda_node *);
92extern int wlp_eda_for_each(struct wlp_eda *, wlp_eda_for_each_f , void *);
93extern int wlp_eda_for_virtual(struct wlp_eda *,
94 const unsigned char eth_addr[ETH_ALEN],
95 struct uwb_dev_addr *,
96 wlp_eda_for_each_f , void *);
97
98
99extern void wlp_remove_neighbor_tmp_info(struct wlp_neighbor_e *);
100
101extern size_t wlp_wss_key_print(char *, size_t, u8 *);
102
103/* Function called when no more references to WSS exists */
104extern void wlp_wss_release(struct kobject *);
105
106extern void wlp_wss_reset(struct wlp_wss *);
107extern int wlp_wss_create_activate(struct wlp_wss *, struct wlp_uuid *,
108 char *, unsigned, unsigned);
109extern int wlp_wss_enroll_activate(struct wlp_wss *, struct wlp_uuid *,
110 struct uwb_dev_addr *);
111extern ssize_t wlp_discover(struct wlp *);
112
113extern int wlp_enroll_neighbor(struct wlp *, struct wlp_neighbor_e *,
114 struct wlp_wss *, struct wlp_uuid *);
115extern int wlp_wss_is_active(struct wlp *, struct wlp_wss *,
116 struct uwb_dev_addr *);
117
118struct wlp_assoc_conn_ctx {
119 struct work_struct ws;
120 struct wlp *wlp;
121 struct sk_buff *skb;
122 struct wlp_eda_node eda_entry;
123};
124
125
126extern int wlp_wss_connect_prep(struct wlp *, struct wlp_eda_node *, void *);
127extern int wlp_wss_send_copy(struct wlp *, struct wlp_eda_node *, void *);
128
129
130/* Message handling */
131struct wlp_assoc_frame_ctx {
132 struct work_struct ws;
133 struct wlp *wlp;
134 struct sk_buff *skb;
135 struct uwb_dev_addr src;
136};
137
138extern int wlp_wss_prep_hdr(struct wlp *, struct wlp_eda_node *, void *);
139extern void wlp_handle_d1_frame(struct work_struct *);
140extern int wlp_parse_d2_frame_to_cache(struct wlp *, struct sk_buff *,
141 struct wlp_neighbor_e *);
142extern int wlp_parse_d2_frame_to_enroll(struct wlp_wss *, struct sk_buff *,
143 struct wlp_neighbor_e *,
144 struct wlp_uuid *);
145extern void wlp_handle_c1_frame(struct work_struct *);
146extern void wlp_handle_c3_frame(struct work_struct *);
147extern int wlp_parse_c3c4_frame(struct wlp *, struct sk_buff *,
148 struct wlp_uuid *, u8 *,
149 struct uwb_mac_addr *);
150extern int wlp_parse_f0(struct wlp *, struct sk_buff *);
151extern int wlp_send_assoc_frame(struct wlp *, struct wlp_wss *,
152 struct uwb_dev_addr *, enum wlp_assoc_type);
153extern ssize_t wlp_get_version(struct wlp *, struct wlp_attr_version *,
154 u8 *, ssize_t);
155extern ssize_t wlp_get_wssid(struct wlp *, struct wlp_attr_wssid *,
156 struct wlp_uuid *, ssize_t);
157extern int __wlp_alloc_device_info(struct wlp *);
158extern int __wlp_setup_device_info(struct wlp *);
159
160extern struct wlp_wss_attribute wss_attribute_properties;
161extern struct wlp_wss_attribute wss_attribute_members;
162extern struct wlp_wss_attribute wss_attribute_state;
163
164static inline
165size_t wlp_wss_uuid_print(char *buf, size_t bufsize, struct wlp_uuid *uuid)
166{
167 size_t result;
168
169 result = scnprintf(buf, bufsize,
170 "%02x:%02x:%02x:%02x:%02x:%02x:"
171 "%02x:%02x:%02x:%02x:%02x:%02x:"
172 "%02x:%02x:%02x:%02x",
173 uuid->data[0], uuid->data[1],
174 uuid->data[2], uuid->data[3],
175 uuid->data[4], uuid->data[5],
176 uuid->data[6], uuid->data[7],
177 uuid->data[8], uuid->data[9],
178 uuid->data[10], uuid->data[11],
179 uuid->data[12], uuid->data[13],
180 uuid->data[14], uuid->data[15]);
181 return result;
182}
183
184/**
185 * FIXME: How should a nonce be displayed?
186 */
187static inline
188size_t wlp_wss_nonce_print(char *buf, size_t bufsize, struct wlp_nonce *nonce)
189{
190 size_t result;
191
192 result = scnprintf(buf, bufsize,
193 "%02x %02x %02x %02x %02x %02x "
194 "%02x %02x %02x %02x %02x %02x "
195 "%02x %02x %02x %02x",
196 nonce->data[0], nonce->data[1],
197 nonce->data[2], nonce->data[3],
198 nonce->data[4], nonce->data[5],
199 nonce->data[6], nonce->data[7],
200 nonce->data[8], nonce->data[9],
201 nonce->data[10], nonce->data[11],
202 nonce->data[12], nonce->data[13],
203 nonce->data[14], nonce->data[15]);
204 return result;
205}
206
207
208static inline
209void wlp_session_cb(struct wlp *wlp)
210{
211 struct completion *completion = wlp->session->cb_priv;
212 complete(completion);
213}
214
215static inline
216int wlp_uuid_is_set(struct wlp_uuid *uuid)
217{
218 struct wlp_uuid zero_uuid = { .data = { 0x00, 0x00, 0x00, 0x00,
219 0x00, 0x00, 0x00, 0x00,
220 0x00, 0x00, 0x00, 0x00,
221 0x00, 0x00, 0x00, 0x00} };
222
223 if (!memcmp(uuid, &zero_uuid, sizeof(*uuid)))
224 return 0;
225 return 1;
226}
227
228#endif /* __WLP_INTERNAL_H__ */
diff --git a/drivers/uwb/wlp/wlp-lc.c b/drivers/uwb/wlp/wlp-lc.c
new file mode 100644
index 000000000000..0799402e73fb
--- /dev/null
+++ b/drivers/uwb/wlp/wlp-lc.c
@@ -0,0 +1,585 @@
1/*
2 * WiMedia Logical Link Control Protocol (WLP)
3 *
4 * Copyright (C) 2005-2006 Intel Corporation
5 * Reinette Chatre <reinette.chatre@intel.com>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License version
9 * 2 as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301, USA.
20 *
21 *
22 * FIXME: docs
23 */
24
25#include <linux/wlp.h>
26#define D_LOCAL 6
27#include <linux/uwb/debug.h>
28#include "wlp-internal.h"
29
30
31static
32void wlp_neighbor_init(struct wlp_neighbor_e *neighbor)
33{
34 INIT_LIST_HEAD(&neighbor->wssid);
35}
36
37/**
38 * Create area for device information storage
39 *
40 * wlp->mutex must be held
41 */
42int __wlp_alloc_device_info(struct wlp *wlp)
43{
44 struct device *dev = &wlp->rc->uwb_dev.dev;
45 BUG_ON(wlp->dev_info != NULL);
46 wlp->dev_info = kzalloc(sizeof(struct wlp_device_info), GFP_KERNEL);
47 if (wlp->dev_info == NULL) {
48 dev_err(dev, "WLP: Unable to allocate memory for "
49 "device information.\n");
50 return -ENOMEM;
51 }
52 return 0;
53}
54
55
56/**
57 * Fill in device information using function provided by driver
58 *
59 * wlp->mutex must be held
60 */
61static
62void __wlp_fill_device_info(struct wlp *wlp)
63{
64 struct device *dev = &wlp->rc->uwb_dev.dev;
65
66 BUG_ON(wlp->fill_device_info == NULL);
67 d_printf(6, dev, "Retrieving device information "
68 "from device driver.\n");
69 wlp->fill_device_info(wlp, wlp->dev_info);
70}
71
72/**
73 * Setup device information
74 *
75 * Allocate area for device information and populate it.
76 *
77 * wlp->mutex must be held
78 */
79int __wlp_setup_device_info(struct wlp *wlp)
80{
81 int result;
82 struct device *dev = &wlp->rc->uwb_dev.dev;
83
84 result = __wlp_alloc_device_info(wlp);
85 if (result < 0) {
86 dev_err(dev, "WLP: Unable to allocate area for "
87 "device information.\n");
88 return result;
89 }
90 __wlp_fill_device_info(wlp);
91 return 0;
92}
93
94/**
95 * Remove information about neighbor stored temporarily
96 *
97 * Information learned during discovey should only be stored when the
98 * device enrolls in the neighbor's WSS. We do need to store this
99 * information temporarily in order to present it to the user.
100 *
101 * We are only interested in keeping neighbor WSS information if that
102 * neighbor is accepting enrollment.
103 *
104 * should be called with wlp->nbmutex held
105 */
106void wlp_remove_neighbor_tmp_info(struct wlp_neighbor_e *neighbor)
107{
108 struct wlp_wssid_e *wssid_e, *next;
109 u8 keep;
110 if (!list_empty(&neighbor->wssid)) {
111 list_for_each_entry_safe(wssid_e, next, &neighbor->wssid,
112 node) {
113 if (wssid_e->info != NULL) {
114 keep = wssid_e->info->accept_enroll;
115 kfree(wssid_e->info);
116 wssid_e->info = NULL;
117 if (!keep) {
118 list_del(&wssid_e->node);
119 kfree(wssid_e);
120 }
121 }
122 }
123 }
124 if (neighbor->info != NULL) {
125 kfree(neighbor->info);
126 neighbor->info = NULL;
127 }
128}
129
130/**
131 * Populate WLP neighborhood cache with neighbor information
132 *
133 * A new neighbor is found. If it is discoverable then we add it to the
134 * neighborhood cache.
135 *
136 */
137static
138int wlp_add_neighbor(struct wlp *wlp, struct uwb_dev *dev)
139{
140 int result = 0;
141 int discoverable;
142 struct wlp_neighbor_e *neighbor;
143
144 d_fnstart(6, &dev->dev, "uwb %p \n", dev);
145 d_printf(6, &dev->dev, "Found neighbor device %02x:%02x \n",
146 dev->dev_addr.data[1], dev->dev_addr.data[0]);
147 /**
148 * FIXME:
149 * Use contents of WLP IE found in beacon cache to determine if
150 * neighbor is discoverable.
151 * The device does not support WLP IE yet so this still needs to be
152 * done. Until then we assume all devices are discoverable.
153 */
154 discoverable = 1; /* will be changed when FIXME disappears */
155 if (discoverable) {
156 /* Add neighbor to cache for discovery */
157 neighbor = kzalloc(sizeof(*neighbor), GFP_KERNEL);
158 if (neighbor == NULL) {
159 dev_err(&dev->dev, "Unable to create memory for "
160 "new neighbor. \n");
161 result = -ENOMEM;
162 goto error_no_mem;
163 }
164 wlp_neighbor_init(neighbor);
165 uwb_dev_get(dev);
166 neighbor->uwb_dev = dev;
167 list_add(&neighbor->node, &wlp->neighbors);
168 }
169error_no_mem:
170 d_fnend(6, &dev->dev, "uwb %p, result = %d \n", dev, result);
171 return result;
172}
173
174/**
175 * Remove one neighbor from cache
176 */
177static
178void __wlp_neighbor_release(struct wlp_neighbor_e *neighbor)
179{
180 struct wlp_wssid_e *wssid_e, *next_wssid_e;
181
182 list_for_each_entry_safe(wssid_e, next_wssid_e,
183 &neighbor->wssid, node) {
184 list_del(&wssid_e->node);
185 kfree(wssid_e);
186 }
187 uwb_dev_put(neighbor->uwb_dev);
188 list_del(&neighbor->node);
189 kfree(neighbor);
190}
191
192/**
193 * Clear entire neighborhood cache.
194 */
195static
196void __wlp_neighbors_release(struct wlp *wlp)
197{
198 struct wlp_neighbor_e *neighbor, *next;
199 if (list_empty(&wlp->neighbors))
200 return;
201 list_for_each_entry_safe(neighbor, next, &wlp->neighbors, node) {
202 __wlp_neighbor_release(neighbor);
203 }
204}
205
206static
207void wlp_neighbors_release(struct wlp *wlp)
208{
209 mutex_lock(&wlp->nbmutex);
210 __wlp_neighbors_release(wlp);
211 mutex_unlock(&wlp->nbmutex);
212}
213
214
215
216/**
217 * Send D1 message to neighbor, receive D2 message
218 *
219 * @neighbor: neighbor to which D1 message will be sent
220 * @wss: if not NULL, it is an enrollment request for this WSS
221 * @wssid: if wss not NULL, this is the wssid of the WSS in which we
222 * want to enroll
223 *
224 * A D1/D2 exchange is done for one of two reasons: discovery or
225 * enrollment. If done for discovery the D1 message is sent to the neighbor
226 * and the contents of the D2 response is stored in a temporary cache.
227 * If done for enrollment the @wss and @wssid are provided also. In this
228 * case the D1 message is sent to the neighbor, the D2 response is parsed
229 * for enrollment of the WSS with wssid.
230 *
231 * &wss->mutex is held
232 */
233static
234int wlp_d1d2_exchange(struct wlp *wlp, struct wlp_neighbor_e *neighbor,
235 struct wlp_wss *wss, struct wlp_uuid *wssid)
236{
237 int result;
238 struct device *dev = &wlp->rc->uwb_dev.dev;
239 DECLARE_COMPLETION_ONSTACK(completion);
240 struct wlp_session session;
241 struct sk_buff *skb;
242 struct wlp_frame_assoc *resp;
243 struct uwb_dev_addr *dev_addr = &neighbor->uwb_dev->dev_addr;
244
245 mutex_lock(&wlp->mutex);
246 if (!wlp_uuid_is_set(&wlp->uuid)) {
247 dev_err(dev, "WLP: UUID is not set. Set via sysfs to "
248 "proceed.\n");
249 result = -ENXIO;
250 goto out;
251 }
252 /* Send D1 association frame */
253 result = wlp_send_assoc_frame(wlp, wss, dev_addr, WLP_ASSOC_D1);
254 if (result < 0) {
255 dev_err(dev, "Unable to send D1 frame to neighbor "
256 "%02x:%02x (%d)\n", dev_addr->data[1],
257 dev_addr->data[0], result);
258 d_printf(6, dev, "Add placeholders into buffer next to "
259 "neighbor information we have (dev address).\n");
260 goto out;
261 }
262 /* Create session, wait for response */
263 session.exp_message = WLP_ASSOC_D2;
264 session.cb = wlp_session_cb;
265 session.cb_priv = &completion;
266 session.neighbor_addr = *dev_addr;
267 BUG_ON(wlp->session != NULL);
268 wlp->session = &session;
269 /* Wait for D2/F0 frame */
270 result = wait_for_completion_interruptible_timeout(&completion,
271 WLP_PER_MSG_TIMEOUT * HZ);
272 if (result == 0) {
273 result = -ETIMEDOUT;
274 dev_err(dev, "Timeout while sending D1 to neighbor "
275 "%02x:%02x.\n", dev_addr->data[1],
276 dev_addr->data[0]);
277 goto error_session;
278 }
279 if (result < 0) {
280 dev_err(dev, "Unable to discover/enroll neighbor %02x:%02x.\n",
281 dev_addr->data[1], dev_addr->data[0]);
282 goto error_session;
283 }
284 /* Parse message in session->data: it will be either D2 or F0 */
285 skb = session.data;
286 resp = (void *) skb->data;
287 d_printf(6, dev, "Received response to D1 frame. \n");
288 d_dump(6, dev, skb->data, skb->len > 72 ? 72 : skb->len);
289
290 if (resp->type == WLP_ASSOC_F0) {
291 result = wlp_parse_f0(wlp, skb);
292 if (result < 0)
293 dev_err(dev, "WLP: Unable to parse F0 from neighbor "
294 "%02x:%02x.\n", dev_addr->data[1],
295 dev_addr->data[0]);
296 result = -EINVAL;
297 goto error_resp_parse;
298 }
299 if (wss == NULL) {
300 /* Discovery */
301 result = wlp_parse_d2_frame_to_cache(wlp, skb, neighbor);
302 if (result < 0) {
303 dev_err(dev, "WLP: Unable to parse D2 message from "
304 "neighbor %02x:%02x for discovery.\n",
305 dev_addr->data[1], dev_addr->data[0]);
306 goto error_resp_parse;
307 }
308 } else {
309 /* Enrollment */
310 result = wlp_parse_d2_frame_to_enroll(wss, skb, neighbor,
311 wssid);
312 if (result < 0) {
313 dev_err(dev, "WLP: Unable to parse D2 message from "
314 "neighbor %02x:%02x for enrollment.\n",
315 dev_addr->data[1], dev_addr->data[0]);
316 goto error_resp_parse;
317 }
318 }
319error_resp_parse:
320 kfree_skb(skb);
321error_session:
322 wlp->session = NULL;
323out:
324 mutex_unlock(&wlp->mutex);
325 return result;
326}
327
328/**
329 * Enroll into WSS of provided WSSID by using neighbor as registrar
330 *
331 * &wss->mutex is held
332 */
333int wlp_enroll_neighbor(struct wlp *wlp, struct wlp_neighbor_e *neighbor,
334 struct wlp_wss *wss, struct wlp_uuid *wssid)
335{
336 int result = 0;
337 struct device *dev = &wlp->rc->uwb_dev.dev;
338 char buf[WLP_WSS_UUID_STRSIZE];
339 struct uwb_dev_addr *dev_addr = &neighbor->uwb_dev->dev_addr;
340 wlp_wss_uuid_print(buf, sizeof(buf), wssid);
341 d_fnstart(6, dev, "wlp %p, neighbor %p, wss %p, wssid %p (%s)\n",
342 wlp, neighbor, wss, wssid, buf);
343 d_printf(6, dev, "Complete me.\n");
344 result = wlp_d1d2_exchange(wlp, neighbor, wss, wssid);
345 if (result < 0) {
346 dev_err(dev, "WLP: D1/D2 message exchange for enrollment "
347 "failed. result = %d \n", result);
348 goto out;
349 }
350 if (wss->state != WLP_WSS_STATE_PART_ENROLLED) {
351 dev_err(dev, "WLP: Unable to enroll into WSS %s using "
352 "neighbor %02x:%02x. \n", buf,
353 dev_addr->data[1], dev_addr->data[0]);
354 result = -EINVAL;
355 goto out;
356 }
357 if (wss->secure_status == WLP_WSS_SECURE) {
358 dev_err(dev, "FIXME: need to complete secure enrollment.\n");
359 result = -EINVAL;
360 goto error;
361 } else {
362 wss->state = WLP_WSS_STATE_ENROLLED;
363 d_printf(2, dev, "WLP: Success Enrollment into unsecure WSS "
364 "%s using neighbor %02x:%02x. \n", buf,
365 dev_addr->data[1], dev_addr->data[0]);
366 }
367
368 d_fnend(6, dev, "wlp %p, neighbor %p, wss %p, wssid %p (%s)\n",
369 wlp, neighbor, wss, wssid, buf);
370out:
371 return result;
372error:
373 wlp_wss_reset(wss);
374 return result;
375}
376
377/**
378 * Discover WSS information of neighbor's active WSS
379 */
380static
381int wlp_discover_neighbor(struct wlp *wlp,
382 struct wlp_neighbor_e *neighbor)
383{
384 return wlp_d1d2_exchange(wlp, neighbor, NULL, NULL);
385}
386
387
388/**
389 * Each neighbor in the neighborhood cache is discoverable. Discover it.
390 *
391 * Discovery is done through sending of D1 association frame and parsing
392 * the D2 association frame response. Only wssid from D2 will be included
393 * in neighbor cache, rest is just displayed to user and forgotten.
394 *
395 * The discovery is not done in parallel. This is simple and enables us to
396 * maintain only one association context.
397 *
398 * The discovery of one neighbor does not affect the other, but if the
399 * discovery of a neighbor fails it is removed from the neighborhood cache.
400 */
401static
402int wlp_discover_all_neighbors(struct wlp *wlp)
403{
404 int result = 0;
405 struct device *dev = &wlp->rc->uwb_dev.dev;
406 struct wlp_neighbor_e *neighbor, *next;
407
408 list_for_each_entry_safe(neighbor, next, &wlp->neighbors, node) {
409 result = wlp_discover_neighbor(wlp, neighbor);
410 if (result < 0) {
411 dev_err(dev, "WLP: Unable to discover neighbor "
412 "%02x:%02x, removing from neighborhood. \n",
413 neighbor->uwb_dev->dev_addr.data[1],
414 neighbor->uwb_dev->dev_addr.data[0]);
415 __wlp_neighbor_release(neighbor);
416 }
417 }
418 return result;
419}
420
421static int wlp_add_neighbor_helper(struct device *dev, void *priv)
422{
423 struct wlp *wlp = priv;
424 struct uwb_dev *uwb_dev = to_uwb_dev(dev);
425
426 return wlp_add_neighbor(wlp, uwb_dev);
427}
428
429/**
430 * Discover WLP neighborhood
431 *
432 * Will send D1 association frame to all devices in beacon group that have
433 * discoverable bit set in WLP IE. D2 frames will be received, information
434 * displayed to user in @buf. Partial information (from D2 association
435 * frame) will be cached to assist with future association
436 * requests.
437 *
438 * The discovery of the WLP neighborhood is triggered by the user. This
439 * should occur infrequently and we thus free current cache and re-allocate
440 * memory if needed.
441 *
442 * If one neighbor fails during initial discovery (determining if it is a
443 * neighbor or not), we fail all - note that interaction with neighbor has
444 * not occured at this point so if a failure occurs we know something went wrong
445 * locally. We thus undo everything.
446 */
447ssize_t wlp_discover(struct wlp *wlp)
448{
449 int result = 0;
450 struct device *dev = &wlp->rc->uwb_dev.dev;
451
452 d_fnstart(6, dev, "wlp %p \n", wlp);
453 mutex_lock(&wlp->nbmutex);
454 /* Clear current neighborhood cache. */
455 __wlp_neighbors_release(wlp);
456 /* Determine which devices in neighborhood. Repopulate cache. */
457 result = uwb_dev_for_each(wlp->rc, wlp_add_neighbor_helper, wlp);
458 if (result < 0) {
459 /* May have partial neighbor information, release all. */
460 __wlp_neighbors_release(wlp);
461 goto error_dev_for_each;
462 }
463 /* Discover the properties of devices in neighborhood. */
464 result = wlp_discover_all_neighbors(wlp);
465 /* In case of failure we still print our partial results. */
466 if (result < 0) {
467 dev_err(dev, "Unable to fully discover neighborhood. \n");
468 result = 0;
469 }
470error_dev_for_each:
471 mutex_unlock(&wlp->nbmutex);
472 d_fnend(6, dev, "wlp %p \n", wlp);
473 return result;
474}
475
476/**
477 * Handle events from UWB stack
478 *
479 * We handle events conservatively. If a neighbor goes off the air we
480 * remove it from the neighborhood. If an association process is in
481 * progress this function will block waiting for the nbmutex to become
482 * free. The association process will thus be allowed to complete before it
483 * is removed.
484 */
485static
486void wlp_uwb_notifs_cb(void *_wlp, struct uwb_dev *uwb_dev,
487 enum uwb_notifs event)
488{
489 struct wlp *wlp = _wlp;
490 struct device *dev = &wlp->rc->uwb_dev.dev;
491 struct wlp_neighbor_e *neighbor, *next;
492 int result;
493 switch (event) {
494 case UWB_NOTIF_ONAIR:
495 d_printf(6, dev, "UWB device %02x:%02x is onair\n",
496 uwb_dev->dev_addr.data[1],
497 uwb_dev->dev_addr.data[0]);
498 result = wlp_eda_create_node(&wlp->eda,
499 uwb_dev->mac_addr.data,
500 &uwb_dev->dev_addr);
501 if (result < 0)
502 dev_err(dev, "WLP: Unable to add new neighbor "
503 "%02x:%02x to EDA cache.\n",
504 uwb_dev->dev_addr.data[1],
505 uwb_dev->dev_addr.data[0]);
506 break;
507 case UWB_NOTIF_OFFAIR:
508 d_printf(6, dev, "UWB device %02x:%02x is offair\n",
509 uwb_dev->dev_addr.data[1],
510 uwb_dev->dev_addr.data[0]);
511 wlp_eda_rm_node(&wlp->eda, &uwb_dev->dev_addr);
512 mutex_lock(&wlp->nbmutex);
513 list_for_each_entry_safe(neighbor, next, &wlp->neighbors,
514 node) {
515 if (neighbor->uwb_dev == uwb_dev) {
516 d_printf(6, dev, "Removing device from "
517 "neighborhood.\n");
518 __wlp_neighbor_release(neighbor);
519 }
520 }
521 mutex_unlock(&wlp->nbmutex);
522 break;
523 default:
524 dev_err(dev, "don't know how to handle event %d from uwb\n",
525 event);
526 }
527}
528
529int wlp_setup(struct wlp *wlp, struct uwb_rc *rc)
530{
531 struct device *dev = &rc->uwb_dev.dev;
532 int result;
533
534 d_fnstart(6, dev, "wlp %p\n", wlp);
535 BUG_ON(wlp->fill_device_info == NULL);
536 BUG_ON(wlp->xmit_frame == NULL);
537 BUG_ON(wlp->stop_queue == NULL);
538 BUG_ON(wlp->start_queue == NULL);
539 wlp->rc = rc;
540 wlp_eda_init(&wlp->eda);/* Set up address cache */
541 wlp->uwb_notifs_handler.cb = wlp_uwb_notifs_cb;
542 wlp->uwb_notifs_handler.data = wlp;
543 uwb_notifs_register(rc, &wlp->uwb_notifs_handler);
544
545 uwb_pal_init(&wlp->pal);
546 result = uwb_pal_register(rc, &wlp->pal);
547 if (result < 0)
548 uwb_notifs_deregister(wlp->rc, &wlp->uwb_notifs_handler);
549
550 d_fnend(6, dev, "wlp %p, result = %d\n", wlp, result);
551 return result;
552}
553EXPORT_SYMBOL_GPL(wlp_setup);
554
555void wlp_remove(struct wlp *wlp)
556{
557 struct device *dev = &wlp->rc->uwb_dev.dev;
558 d_fnstart(6, dev, "wlp %p\n", wlp);
559 wlp_neighbors_release(wlp);
560 uwb_pal_unregister(wlp->rc, &wlp->pal);
561 uwb_notifs_deregister(wlp->rc, &wlp->uwb_notifs_handler);
562 wlp_eda_release(&wlp->eda);
563 mutex_lock(&wlp->mutex);
564 if (wlp->dev_info != NULL)
565 kfree(wlp->dev_info);
566 mutex_unlock(&wlp->mutex);
567 wlp->rc = NULL;
568 /* We have to use NULL here because this function can be called
569 * when the device disappeared. */
570 d_fnend(6, NULL, "wlp %p\n", wlp);
571}
572EXPORT_SYMBOL_GPL(wlp_remove);
573
574/**
575 * wlp_reset_all - reset the WLP hardware
576 * @wlp: the WLP device to reset.
577 *
578 * This schedules a full hardware reset of the WLP device. The radio
579 * controller and any other PALs will also be reset.
580 */
581void wlp_reset_all(struct wlp *wlp)
582{
583 uwb_rc_reset_all(wlp->rc);
584}
585EXPORT_SYMBOL_GPL(wlp_reset_all);
diff --git a/drivers/uwb/wlp/wss-lc.c b/drivers/uwb/wlp/wss-lc.c
new file mode 100644
index 000000000000..96b18c9bd6e9
--- /dev/null
+++ b/drivers/uwb/wlp/wss-lc.c
@@ -0,0 +1,1055 @@
1/*
2 * WiMedia Logical Link Control Protocol (WLP)
3 *
4 * Copyright (C) 2007 Intel Corporation
5 * Reinette Chatre <reinette.chatre@intel.com>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License version
9 * 2 as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301, USA.
20 *
21 *
22 * Implementation of the WLP association protocol.
23 *
24 * FIXME: Docs
25 *
26 * A UWB network interface will configure a WSS through wlp_wss_setup() after
27 * the interface has been assigned a MAC address, typically after
28 * "ifconfig" has been called. When the interface goes down it should call
29 * wlp_wss_remove().
30 *
31 * When the WSS is ready for use the user interacts via sysfs to create,
32 * discover, and activate WSS.
33 *
34 * wlp_wss_enroll_activate()
35 *
36 * wlp_wss_create_activate()
37 * wlp_wss_set_wssid_hash()
38 * wlp_wss_comp_wssid_hash()
39 * wlp_wss_sel_bcast_addr()
40 * wlp_wss_sysfs_add()
41 *
42 * Called when no more references to WSS exist:
43 * wlp_wss_release()
44 * wlp_wss_reset()
45 */
46
47#include <linux/etherdevice.h> /* for is_valid_ether_addr */
48#include <linux/skbuff.h>
49#include <linux/wlp.h>
50#define D_LOCAL 5
51#include <linux/uwb/debug.h>
52#include "wlp-internal.h"
53
54
55size_t wlp_wss_key_print(char *buf, size_t bufsize, u8 *key)
56{
57 size_t result;
58
59 result = scnprintf(buf, bufsize,
60 "%02x %02x %02x %02x %02x %02x "
61 "%02x %02x %02x %02x %02x %02x "
62 "%02x %02x %02x %02x",
63 key[0], key[1], key[2], key[3],
64 key[4], key[5], key[6], key[7],
65 key[8], key[9], key[10], key[11],
66 key[12], key[13], key[14], key[15]);
67 return result;
68}
69
70/**
71 * Compute WSSID hash
72 * WLP Draft 0.99 [7.2.1]
73 *
74 * The WSSID hash for a WSSID is the result of an octet-wise exclusive-OR
75 * of all octets in the WSSID.
76 */
77static
78u8 wlp_wss_comp_wssid_hash(struct wlp_uuid *wssid)
79{
80 return wssid->data[0] ^ wssid->data[1] ^ wssid->data[2]
81 ^ wssid->data[3] ^ wssid->data[4] ^ wssid->data[5]
82 ^ wssid->data[6] ^ wssid->data[7] ^ wssid->data[8]
83 ^ wssid->data[9] ^ wssid->data[10] ^ wssid->data[11]
84 ^ wssid->data[12] ^ wssid->data[13] ^ wssid->data[14]
85 ^ wssid->data[15];
86}
87
88/**
89 * Select a multicast EUI-48 for the WSS broadcast address.
90 * WLP Draft 0.99 [7.2.1]
91 *
92 * Selected based on the WiMedia Alliance OUI, 00-13-88, within the WLP
93 * range, [01-13-88-00-01-00, 01-13-88-00-01-FF] inclusive.
94 *
95 * This address is currently hardcoded.
96 * FIXME?
97 */
98static
99struct uwb_mac_addr wlp_wss_sel_bcast_addr(struct wlp_wss *wss)
100{
101 struct uwb_mac_addr bcast = {
102 .data = { 0x01, 0x13, 0x88, 0x00, 0x01, 0x00 }
103 };
104 return bcast;
105}
106
107/**
108 * Clear the contents of the WSS structure - all except kobj, mutex, virtual
109 *
110 * We do not want to reinitialize - the internal kobj should not change as
111 * it still points to the parent received during setup. The mutex should
112 * remain also. We thus just reset values individually.
113 * The virutal address assigned to WSS will remain the same for the
114 * lifetime of the WSS. We only reset the fields that can change during its
115 * lifetime.
116 */
117void wlp_wss_reset(struct wlp_wss *wss)
118{
119 struct wlp *wlp = container_of(wss, struct wlp, wss);
120 struct device *dev = &wlp->rc->uwb_dev.dev;
121 d_fnstart(5, dev, "wss (%p) \n", wss);
122 memset(&wss->wssid, 0, sizeof(wss->wssid));
123 wss->hash = 0;
124 memset(&wss->name[0], 0, sizeof(wss->name));
125 memset(&wss->bcast, 0, sizeof(wss->bcast));
126 wss->secure_status = WLP_WSS_UNSECURE;
127 memset(&wss->master_key[0], 0, sizeof(wss->master_key));
128 wss->tag = 0;
129 wss->state = WLP_WSS_STATE_NONE;
130 d_fnend(5, dev, "wss (%p) \n", wss);
131}
132
133/**
134 * Create sysfs infrastructure for WSS
135 *
136 * The WSS is configured to have the interface as parent (see wlp_wss_setup())
137 * a new sysfs directory that includes wssid as its name is created in the
138 * interface's sysfs directory. The group of files interacting with WSS are
139 * created also.
140 */
141static
142int wlp_wss_sysfs_add(struct wlp_wss *wss, char *wssid_str)
143{
144 struct wlp *wlp = container_of(wss, struct wlp, wss);
145 struct device *dev = &wlp->rc->uwb_dev.dev;
146 int result;
147
148 d_fnstart(5, dev, "wss (%p), wssid: %s\n", wss, wssid_str);
149 result = kobject_set_name(&wss->kobj, "wss-%s", wssid_str);
150 if (result < 0)
151 return result;
152 wss->kobj.ktype = &wss_ktype;
153 result = kobject_init_and_add(&wss->kobj,
154 &wss_ktype, wss->kobj.parent, "wlp");
155 if (result < 0) {
156 dev_err(dev, "WLP: Cannot register WSS kobject.\n");
157 goto error_kobject_register;
158 }
159 result = sysfs_create_group(&wss->kobj, &wss_attr_group);
160 if (result < 0) {
161 dev_err(dev, "WLP: Cannot register WSS attributes: %d\n",
162 result);
163 goto error_sysfs_create_group;
164 }
165 d_fnend(5, dev, "Completed. result = %d \n", result);
166 return 0;
167error_sysfs_create_group:
168
169 kobject_put(&wss->kobj); /* will free name if needed */
170 return result;
171error_kobject_register:
172 kfree(wss->kobj.name);
173 wss->kobj.name = NULL;
174 wss->kobj.ktype = NULL;
175 return result;
176}
177
178
179/**
180 * Release WSS
181 *
182 * No more references exist to this WSS. We should undo everything that was
183 * done in wlp_wss_create_activate() except removing the group. The group
184 * is not removed because an object can be unregistered before the group is
185 * created. We also undo any additional operations on the WSS after this
186 * (addition of members).
187 *
188 * If memory was allocated for the kobject's name then it will
189 * be freed by the kobject system during this time.
190 *
191 * The EDA cache is removed and reinitilized when the WSS is removed. We
192 * thus loose knowledge of members of this WSS at that time and need not do
193 * it here.
194 */
195void wlp_wss_release(struct kobject *kobj)
196{
197 struct wlp_wss *wss = container_of(kobj, struct wlp_wss, kobj);
198
199 wlp_wss_reset(wss);
200}
201
202/**
203 * Enroll into a WSS using provided neighbor as registrar
204 *
205 * First search the neighborhood information to learn which neighbor is
206 * referred to, next proceed with enrollment.
207 *
208 * &wss->mutex is held
209 */
210static
211int wlp_wss_enroll_target(struct wlp_wss *wss, struct wlp_uuid *wssid,
212 struct uwb_dev_addr *dest)
213{
214 struct wlp *wlp = container_of(wss, struct wlp, wss);
215 struct device *dev = &wlp->rc->uwb_dev.dev;
216 struct wlp_neighbor_e *neighbor;
217 char buf[WLP_WSS_UUID_STRSIZE];
218 int result = -ENXIO;
219 struct uwb_dev_addr *dev_addr;
220
221 wlp_wss_uuid_print(buf, sizeof(buf), wssid);
222 d_fnstart(5, dev, "wss %p, wssid %s, registrar %02x:%02x \n",
223 wss, buf, dest->data[1], dest->data[0]);
224 mutex_lock(&wlp->nbmutex);
225 list_for_each_entry(neighbor, &wlp->neighbors, node) {
226 dev_addr = &neighbor->uwb_dev->dev_addr;
227 if (!memcmp(dest, dev_addr, sizeof(*dest))) {
228 d_printf(5, dev, "Neighbor %02x:%02x is valid, "
229 "enrolling. \n",
230 dev_addr->data[1], dev_addr->data[0]);
231 result = wlp_enroll_neighbor(wlp, neighbor, wss,
232 wssid);
233 break;
234 }
235 }
236 if (result == -ENXIO)
237 dev_err(dev, "WLP: Cannot find neighbor %02x:%02x. \n",
238 dest->data[1], dest->data[0]);
239 mutex_unlock(&wlp->nbmutex);
240 d_fnend(5, dev, "wss %p, wssid %s, registrar %02x:%02x, result %d \n",
241 wss, buf, dest->data[1], dest->data[0], result);
242 return result;
243}
244
245/**
246 * Enroll into a WSS previously discovered
247 *
248 * User provides WSSID of WSS, search for neighbor that has this WSS
249 * activated and attempt to enroll.
250 *
251 * &wss->mutex is held
252 */
253static
254int wlp_wss_enroll_discovered(struct wlp_wss *wss, struct wlp_uuid *wssid)
255{
256 struct wlp *wlp = container_of(wss, struct wlp, wss);
257 struct device *dev = &wlp->rc->uwb_dev.dev;
258 struct wlp_neighbor_e *neighbor;
259 struct wlp_wssid_e *wssid_e;
260 char buf[WLP_WSS_UUID_STRSIZE];
261 int result = -ENXIO;
262
263 wlp_wss_uuid_print(buf, sizeof(buf), wssid);
264 d_fnstart(5, dev, "wss %p, wssid %s \n", wss, buf);
265 mutex_lock(&wlp->nbmutex);
266 list_for_each_entry(neighbor, &wlp->neighbors, node) {
267 list_for_each_entry(wssid_e, &neighbor->wssid, node) {
268 if (!memcmp(wssid, &wssid_e->wssid, sizeof(*wssid))) {
269 d_printf(5, dev, "Found WSSID %s in neighbor "
270 "%02x:%02x cache. \n", buf,
271 neighbor->uwb_dev->dev_addr.data[1],
272 neighbor->uwb_dev->dev_addr.data[0]);
273 result = wlp_enroll_neighbor(wlp, neighbor,
274 wss, wssid);
275 if (result == 0) /* enrollment success */
276 goto out;
277 break;
278 }
279 }
280 }
281out:
282 if (result == -ENXIO)
283 dev_err(dev, "WLP: Cannot find WSSID %s in cache. \n", buf);
284 mutex_unlock(&wlp->nbmutex);
285 d_fnend(5, dev, "wss %p, wssid %s, result %d \n", wss, buf, result);
286 return result;
287}
288
289/**
290 * Enroll into WSS with provided WSSID, registrar may be provided
291 *
292 * @wss: out WSS that will be enrolled
293 * @wssid: wssid of neighboring WSS that we want to enroll in
294 * @devaddr: registrar can be specified, will be broadcast (ff:ff) if any
295 * neighbor can be used as registrar.
296 *
297 * &wss->mutex is held
298 */
299static
300int wlp_wss_enroll(struct wlp_wss *wss, struct wlp_uuid *wssid,
301 struct uwb_dev_addr *devaddr)
302{
303 int result;
304 struct wlp *wlp = container_of(wss, struct wlp, wss);
305 struct device *dev = &wlp->rc->uwb_dev.dev;
306 char buf[WLP_WSS_UUID_STRSIZE];
307 struct uwb_dev_addr bcast = {.data = {0xff, 0xff} };
308
309 wlp_wss_uuid_print(buf, sizeof(buf), wssid);
310 if (wss->state != WLP_WSS_STATE_NONE) {
311 dev_err(dev, "WLP: Already enrolled in WSS %s.\n", buf);
312 result = -EEXIST;
313 goto error;
314 }
315 if (!memcmp(&bcast, devaddr, sizeof(bcast))) {
316 d_printf(5, dev, "Request to enroll in discovered WSS "
317 "with WSSID %s \n", buf);
318 result = wlp_wss_enroll_discovered(wss, wssid);
319 } else {
320 d_printf(5, dev, "Request to enroll in WSSID %s with "
321 "registrar %02x:%02x\n", buf, devaddr->data[1],
322 devaddr->data[0]);
323 result = wlp_wss_enroll_target(wss, wssid, devaddr);
324 }
325 if (result < 0) {
326 dev_err(dev, "WLP: Unable to enroll into WSS %s, result %d \n",
327 buf, result);
328 goto error;
329 }
330 d_printf(2, dev, "Successfully enrolled into WSS %s \n", buf);
331 result = wlp_wss_sysfs_add(wss, buf);
332 if (result < 0) {
333 dev_err(dev, "WLP: Unable to set up sysfs for WSS kobject.\n");
334 wlp_wss_reset(wss);
335 }
336error:
337 return result;
338
339}
340
341/**
342 * Activate given WSS
343 *
344 * Prior to activation a WSS must be enrolled. To activate a WSS a device
345 * includes the WSS hash in the WLP IE in its beacon in each superframe.
346 * WLP 0.99 [7.2.5].
347 *
348 * The WSS tag is also computed at this time. We only support one activated
349 * WSS so we can use the hash as a tag - there will never be a conflict.
350 *
351 * We currently only support one activated WSS so only one WSS hash is
352 * included in the WLP IE.
353 */
354static
355int wlp_wss_activate(struct wlp_wss *wss)
356{
357 struct wlp *wlp = container_of(wss, struct wlp, wss);
358 struct device *dev = &wlp->rc->uwb_dev.dev;
359 struct uwb_rc *uwb_rc = wlp->rc;
360 int result;
361 struct {
362 struct wlp_ie wlp_ie;
363 u8 hash; /* only include one hash */
364 } ie_data;
365
366 d_fnstart(5, dev, "Activating WSS %p. \n", wss);
367 BUG_ON(wss->state != WLP_WSS_STATE_ENROLLED);
368 wss->hash = wlp_wss_comp_wssid_hash(&wss->wssid);
369 wss->tag = wss->hash;
370 memset(&ie_data, 0, sizeof(ie_data));
371 ie_data.wlp_ie.hdr.element_id = UWB_IE_WLP;
372 ie_data.wlp_ie.hdr.length = sizeof(ie_data) - sizeof(struct uwb_ie_hdr);
373 wlp_ie_set_hash_length(&ie_data.wlp_ie, sizeof(ie_data.hash));
374 ie_data.hash = wss->hash;
375 result = uwb_rc_ie_add(uwb_rc, &ie_data.wlp_ie.hdr,
376 sizeof(ie_data));
377 if (result < 0) {
378 dev_err(dev, "WLP: Unable to add WLP IE to beacon. "
379 "result = %d.\n", result);
380 goto error_wlp_ie;
381 }
382 wss->state = WLP_WSS_STATE_ACTIVE;
383 result = 0;
384error_wlp_ie:
385 d_fnend(5, dev, "Activating WSS %p, result = %d \n", wss, result);
386 return result;
387}
388
389/**
390 * Enroll in and activate WSS identified by provided WSSID
391 *
392 * The neighborhood cache should contain a list of all neighbors and the
393 * WSS they have activated. Based on that cache we search which neighbor we
394 * can perform the association process with. The user also has option to
395 * specify which neighbor it prefers as registrar.
396 * Successful enrollment is followed by activation.
397 * Successful activation will create the sysfs directory containing
398 * specific information regarding this WSS.
399 */
400int wlp_wss_enroll_activate(struct wlp_wss *wss, struct wlp_uuid *wssid,
401 struct uwb_dev_addr *devaddr)
402{
403 struct wlp *wlp = container_of(wss, struct wlp, wss);
404 struct device *dev = &wlp->rc->uwb_dev.dev;
405 int result = 0;
406 char buf[WLP_WSS_UUID_STRSIZE];
407
408 d_fnstart(5, dev, "Enrollment and activation requested. \n");
409 mutex_lock(&wss->mutex);
410 result = wlp_wss_enroll(wss, wssid, devaddr);
411 if (result < 0) {
412 wlp_wss_uuid_print(buf, sizeof(buf), &wss->wssid);
413 dev_err(dev, "WLP: Enrollment into WSS %s failed.\n", buf);
414 goto error_enroll;
415 }
416 result = wlp_wss_activate(wss);
417 if (result < 0) {
418 dev_err(dev, "WLP: Unable to activate WSS. Undoing enrollment "
419 "result = %d \n", result);
420 /* Undo enrollment */
421 wlp_wss_reset(wss);
422 goto error_activate;
423 }
424error_activate:
425error_enroll:
426 mutex_unlock(&wss->mutex);
427 d_fnend(5, dev, "Completed. result = %d \n", result);
428 return result;
429}
430
431/**
432 * Create, enroll, and activate a new WSS
433 *
434 * @wssid: new wssid provided by user
435 * @name: WSS name requested by used.
436 * @sec_status: security status requested by user
437 *
438 * A user requested the creation of a new WSS. All operations are done
439 * locally. The new WSS will be stored locally, the hash will be included
440 * in the WLP IE, and the sysfs infrastructure for this WSS will be
441 * created.
442 */
443int wlp_wss_create_activate(struct wlp_wss *wss, struct wlp_uuid *wssid,
444 char *name, unsigned sec_status, unsigned accept)
445{
446 struct wlp *wlp = container_of(wss, struct wlp, wss);
447 struct device *dev = &wlp->rc->uwb_dev.dev;
448 int result = 0;
449 char buf[WLP_WSS_UUID_STRSIZE];
450 d_fnstart(5, dev, "Request to create new WSS.\n");
451 result = wlp_wss_uuid_print(buf, sizeof(buf), wssid);
452 d_printf(5, dev, "Request to create WSS: WSSID=%s, name=%s, "
453 "sec_status=%u, accepting enrollment=%u \n",
454 buf, name, sec_status, accept);
455 if (!mutex_trylock(&wss->mutex)) {
456 dev_err(dev, "WLP: WLP association session in progress.\n");
457 return -EBUSY;
458 }
459 if (wss->state != WLP_WSS_STATE_NONE) {
460 dev_err(dev, "WLP: WSS already exists. Not creating new.\n");
461 result = -EEXIST;
462 goto out;
463 }
464 if (wss->kobj.parent == NULL) {
465 dev_err(dev, "WLP: WSS parent not ready. Is network interface "
466 "up?\n");
467 result = -ENXIO;
468 goto out;
469 }
470 if (sec_status == WLP_WSS_SECURE) {
471 dev_err(dev, "WLP: FIXME Creation of secure WSS not "
472 "supported yet.\n");
473 result = -EINVAL;
474 goto out;
475 }
476 wss->wssid = *wssid;
477 memcpy(wss->name, name, sizeof(wss->name));
478 wss->bcast = wlp_wss_sel_bcast_addr(wss);
479 wss->secure_status = sec_status;
480 wss->accept_enroll = accept;
481 /*wss->virtual_addr is initialized in call to wlp_wss_setup*/
482 /* sysfs infrastructure */
483 result = wlp_wss_sysfs_add(wss, buf);
484 if (result < 0) {
485 dev_err(dev, "Cannot set up sysfs for WSS kobject.\n");
486 wlp_wss_reset(wss);
487 goto out;
488 } else
489 result = 0;
490 wss->state = WLP_WSS_STATE_ENROLLED;
491 result = wlp_wss_activate(wss);
492 if (result < 0) {
493 dev_err(dev, "WLP: Unable to activate WSS. Undoing "
494 "enrollment\n");
495 wlp_wss_reset(wss);
496 goto out;
497 }
498 result = 0;
499out:
500 mutex_unlock(&wss->mutex);
501 d_fnend(5, dev, "Completed. result = %d \n", result);
502 return result;
503}
504
505/**
506 * Determine if neighbor has WSS activated
507 *
508 * @returns: 1 if neighbor has WSS activated, zero otherwise
509 *
510 * This can be done in two ways:
511 * - send a C1 frame, parse C2/F0 response
512 * - examine the WLP IE sent by the neighbor
513 *
514 * The WLP IE is not fully supported in hardware so we use the C1/C2 frame
515 * exchange to determine if a WSS is activated. Using the WLP IE should be
516 * faster and should be used when it becomes possible.
517 */
518int wlp_wss_is_active(struct wlp *wlp, struct wlp_wss *wss,
519 struct uwb_dev_addr *dev_addr)
520{
521 int result = 0;
522 struct device *dev = &wlp->rc->uwb_dev.dev;
523 char buf[WLP_WSS_UUID_STRSIZE];
524 DECLARE_COMPLETION_ONSTACK(completion);
525 struct wlp_session session;
526 struct sk_buff *skb;
527 struct wlp_frame_assoc *resp;
528 struct wlp_uuid wssid;
529
530 wlp_wss_uuid_print(buf, sizeof(buf), &wss->wssid);
531 d_fnstart(5, dev, "wlp %p, wss %p (wssid %s), neighbor %02x:%02x \n",
532 wlp, wss, buf, dev_addr->data[1], dev_addr->data[0]);
533 mutex_lock(&wlp->mutex);
534 /* Send C1 association frame */
535 result = wlp_send_assoc_frame(wlp, wss, dev_addr, WLP_ASSOC_C1);
536 if (result < 0) {
537 dev_err(dev, "Unable to send C1 frame to neighbor "
538 "%02x:%02x (%d)\n", dev_addr->data[1],
539 dev_addr->data[0], result);
540 result = 0;
541 goto out;
542 }
543 /* Create session, wait for response */
544 session.exp_message = WLP_ASSOC_C2;
545 session.cb = wlp_session_cb;
546 session.cb_priv = &completion;
547 session.neighbor_addr = *dev_addr;
548 BUG_ON(wlp->session != NULL);
549 wlp->session = &session;
550 /* Wait for C2/F0 frame */
551 result = wait_for_completion_interruptible_timeout(&completion,
552 WLP_PER_MSG_TIMEOUT * HZ);
553 if (result == 0) {
554 dev_err(dev, "Timeout while sending C1 to neighbor "
555 "%02x:%02x.\n", dev_addr->data[1],
556 dev_addr->data[0]);
557 goto out;
558 }
559 if (result < 0) {
560 dev_err(dev, "Unable to send C1 to neighbor %02x:%02x.\n",
561 dev_addr->data[1], dev_addr->data[0]);
562 result = 0;
563 goto out;
564 }
565 /* Parse message in session->data: it will be either C2 or F0 */
566 skb = session.data;
567 resp = (void *) skb->data;
568 d_printf(5, dev, "Received response to C1 frame. \n");
569 d_dump(5, dev, skb->data, skb->len > 72 ? 72 : skb->len);
570 if (resp->type == WLP_ASSOC_F0) {
571 result = wlp_parse_f0(wlp, skb);
572 if (result < 0)
573 dev_err(dev, "WLP: unable to parse incoming F0 "
574 "frame from neighbor %02x:%02x.\n",
575 dev_addr->data[1], dev_addr->data[0]);
576 result = 0;
577 goto error_resp_parse;
578 }
579 /* WLP version and message type fields have already been parsed */
580 result = wlp_get_wssid(wlp, (void *)resp + sizeof(*resp), &wssid,
581 skb->len - sizeof(*resp));
582 if (result < 0) {
583 dev_err(dev, "WLP: unable to obtain WSSID from C2 frame.\n");
584 result = 0;
585 goto error_resp_parse;
586 }
587 if (!memcmp(&wssid, &wss->wssid, sizeof(wssid))) {
588 d_printf(5, dev, "WSSID in C2 frame matches local "
589 "active WSS.\n");
590 result = 1;
591 } else {
592 dev_err(dev, "WLP: Received a C2 frame without matching "
593 "WSSID.\n");
594 result = 0;
595 }
596error_resp_parse:
597 kfree_skb(skb);
598out:
599 wlp->session = NULL;
600 mutex_unlock(&wlp->mutex);
601 d_fnend(5, dev, "wlp %p, wss %p (wssid %s), neighbor %02x:%02x \n",
602 wlp, wss, buf, dev_addr->data[1], dev_addr->data[0]);
603 return result;
604}
605
606/**
607 * Activate connection with neighbor by updating EDA cache
608 *
609 * @wss: local WSS to which neighbor wants to connect
610 * @dev_addr: neighbor's address
611 * @wssid: neighbor's WSSID - must be same as our WSS's WSSID
612 * @tag: neighbor's WSS tag used to identify frames transmitted by it
613 * @virt_addr: neighbor's virtual EUI-48
614 */
615static
616int wlp_wss_activate_connection(struct wlp *wlp, struct wlp_wss *wss,
617 struct uwb_dev_addr *dev_addr,
618 struct wlp_uuid *wssid, u8 *tag,
619 struct uwb_mac_addr *virt_addr)
620{
621 struct device *dev = &wlp->rc->uwb_dev.dev;
622 int result = 0;
623 char buf[WLP_WSS_UUID_STRSIZE];
624 wlp_wss_uuid_print(buf, sizeof(buf), wssid);
625 d_fnstart(5, dev, "wlp %p, wss %p, wssid %s, tag %u, virtual "
626 "%02x:%02x:%02x:%02x:%02x:%02x \n", wlp, wss, buf, *tag,
627 virt_addr->data[0], virt_addr->data[1], virt_addr->data[2],
628 virt_addr->data[3], virt_addr->data[4], virt_addr->data[5]);
629
630 if (!memcmp(wssid, &wss->wssid, sizeof(*wssid))) {
631 d_printf(5, dev, "WSSID from neighbor frame matches local "
632 "active WSS.\n");
633 /* Update EDA cache */
634 result = wlp_eda_update_node(&wlp->eda, dev_addr, wss,
635 (void *) virt_addr->data, *tag,
636 WLP_WSS_CONNECTED);
637 if (result < 0)
638 dev_err(dev, "WLP: Unable to update EDA cache "
639 "with new connected neighbor information.\n");
640 } else {
641 dev_err(dev, "WLP: Neighbor does not have matching "
642 "WSSID.\n");
643 result = -EINVAL;
644 }
645
646 d_fnend(5, dev, "wlp %p, wss %p, wssid %s, tag %u, virtual "
647 "%02x:%02x:%02x:%02x:%02x:%02x, result = %d \n",
648 wlp, wss, buf, *tag,
649 virt_addr->data[0], virt_addr->data[1], virt_addr->data[2],
650 virt_addr->data[3], virt_addr->data[4], virt_addr->data[5],
651 result);
652
653 return result;
654}
655
656/**
657 * Connect to WSS neighbor
658 *
659 * Use C3/C4 exchange to determine if neighbor has WSS activated and
660 * retrieve the WSS tag and virtual EUI-48 of the neighbor.
661 */
662static
663int wlp_wss_connect_neighbor(struct wlp *wlp, struct wlp_wss *wss,
664 struct uwb_dev_addr *dev_addr)
665{
666 int result;
667 struct device *dev = &wlp->rc->uwb_dev.dev;
668 char buf[WLP_WSS_UUID_STRSIZE];
669 struct wlp_uuid wssid;
670 u8 tag;
671 struct uwb_mac_addr virt_addr;
672 DECLARE_COMPLETION_ONSTACK(completion);
673 struct wlp_session session;
674 struct wlp_frame_assoc *resp;
675 struct sk_buff *skb;
676
677 wlp_wss_uuid_print(buf, sizeof(buf), &wss->wssid);
678 d_fnstart(5, dev, "wlp %p, wss %p (wssid %s), neighbor %02x:%02x \n",
679 wlp, wss, buf, dev_addr->data[1], dev_addr->data[0]);
680 mutex_lock(&wlp->mutex);
681 /* Send C3 association frame */
682 result = wlp_send_assoc_frame(wlp, wss, dev_addr, WLP_ASSOC_C3);
683 if (result < 0) {
684 dev_err(dev, "Unable to send C3 frame to neighbor "
685 "%02x:%02x (%d)\n", dev_addr->data[1],
686 dev_addr->data[0], result);
687 goto out;
688 }
689 /* Create session, wait for response */
690 session.exp_message = WLP_ASSOC_C4;
691 session.cb = wlp_session_cb;
692 session.cb_priv = &completion;
693 session.neighbor_addr = *dev_addr;
694 BUG_ON(wlp->session != NULL);
695 wlp->session = &session;
696 /* Wait for C4/F0 frame */
697 result = wait_for_completion_interruptible_timeout(&completion,
698 WLP_PER_MSG_TIMEOUT * HZ);
699 if (result == 0) {
700 dev_err(dev, "Timeout while sending C3 to neighbor "
701 "%02x:%02x.\n", dev_addr->data[1],
702 dev_addr->data[0]);
703 result = -ETIMEDOUT;
704 goto out;
705 }
706 if (result < 0) {
707 dev_err(dev, "Unable to send C3 to neighbor %02x:%02x.\n",
708 dev_addr->data[1], dev_addr->data[0]);
709 goto out;
710 }
711 /* Parse message in session->data: it will be either C4 or F0 */
712 skb = session.data;
713 resp = (void *) skb->data;
714 d_printf(5, dev, "Received response to C3 frame. \n");
715 d_dump(5, dev, skb->data, skb->len > 72 ? 72 : skb->len);
716 if (resp->type == WLP_ASSOC_F0) {
717 result = wlp_parse_f0(wlp, skb);
718 if (result < 0)
719 dev_err(dev, "WLP: unable to parse incoming F0 "
720 "frame from neighbor %02x:%02x.\n",
721 dev_addr->data[1], dev_addr->data[0]);
722 result = -EINVAL;
723 goto error_resp_parse;
724 }
725 result = wlp_parse_c3c4_frame(wlp, skb, &wssid, &tag, &virt_addr);
726 if (result < 0) {
727 dev_err(dev, "WLP: Unable to parse C4 frame from neighbor.\n");
728 goto error_resp_parse;
729 }
730 result = wlp_wss_activate_connection(wlp, wss, dev_addr, &wssid, &tag,
731 &virt_addr);
732 if (result < 0) {
733 dev_err(dev, "WLP: Unable to activate connection to "
734 "neighbor %02x:%02x.\n", dev_addr->data[1],
735 dev_addr->data[0]);
736 goto error_resp_parse;
737 }
738error_resp_parse:
739 kfree_skb(skb);
740out:
741 /* Record that we unsuccessfully tried to connect to this neighbor */
742 if (result < 0)
743 wlp_eda_update_node_state(&wlp->eda, dev_addr,
744 WLP_WSS_CONNECT_FAILED);
745 wlp->session = NULL;
746 mutex_unlock(&wlp->mutex);
747 d_fnend(5, dev, "wlp %p, wss %p (wssid %s), neighbor %02x:%02x \n",
748 wlp, wss, buf, dev_addr->data[1], dev_addr->data[0]);
749 return result;
750}
751
752/**
753 * Connect to neighbor with common WSS, send pending frame
754 *
755 * This function is scheduled when a frame is destined to a neighbor with
756 * which we do not have a connection. A copy of the EDA cache entry is
757 * provided - not the actual cache entry (because it is protected by a
758 * spinlock).
759 *
760 * First determine if neighbor has the same WSS activated, connect if it
761 * does. The C3/C4 exchange is dual purpose to determine if neighbor has
762 * WSS activated and proceed with the connection.
763 *
764 * The frame that triggered the connection setup is sent after connection
765 * setup.
766 *
767 * network queue is stopped - we need to restart when done
768 *
769 */
770static
771void wlp_wss_connect_send(struct work_struct *ws)
772{
773 struct wlp_assoc_conn_ctx *conn_ctx = container_of(ws,
774 struct wlp_assoc_conn_ctx,
775 ws);
776 struct wlp *wlp = conn_ctx->wlp;
777 struct sk_buff *skb = conn_ctx->skb;
778 struct wlp_eda_node *eda_entry = &conn_ctx->eda_entry;
779 struct uwb_dev_addr *dev_addr = &eda_entry->dev_addr;
780 struct wlp_wss *wss = &wlp->wss;
781 int result;
782 struct device *dev = &wlp->rc->uwb_dev.dev;
783 char buf[WLP_WSS_UUID_STRSIZE];
784
785 mutex_lock(&wss->mutex);
786 wlp_wss_uuid_print(buf, sizeof(buf), &wss->wssid);
787 d_fnstart(5, dev, "wlp %p, wss %p (wssid %s), neighbor %02x:%02x \n",
788 wlp, wss, buf, dev_addr->data[1], dev_addr->data[0]);
789 if (wss->state < WLP_WSS_STATE_ACTIVE) {
790 if (printk_ratelimit())
791 dev_err(dev, "WLP: Attempting to connect with "
792 "WSS that is not active or connected.\n");
793 dev_kfree_skb(skb);
794 goto out;
795 }
796 /* Establish connection - send C3 rcv C4 */
797 result = wlp_wss_connect_neighbor(wlp, wss, dev_addr);
798 if (result < 0) {
799 if (printk_ratelimit())
800 dev_err(dev, "WLP: Unable to establish connection "
801 "with neighbor %02x:%02x.\n",
802 dev_addr->data[1], dev_addr->data[0]);
803 dev_kfree_skb(skb);
804 goto out;
805 }
806 /* EDA entry changed, update the local copy being used */
807 result = wlp_copy_eda_node(&wlp->eda, dev_addr, eda_entry);
808 if (result < 0) {
809 if (printk_ratelimit())
810 dev_err(dev, "WLP: Cannot find EDA entry for "
811 "neighbor %02x:%02x \n",
812 dev_addr->data[1], dev_addr->data[0]);
813 }
814 result = wlp_wss_prep_hdr(wlp, eda_entry, skb);
815 if (result < 0) {
816 if (printk_ratelimit())
817 dev_err(dev, "WLP: Unable to prepare frame header for "
818 "transmission (neighbor %02x:%02x). \n",
819 dev_addr->data[1], dev_addr->data[0]);
820 dev_kfree_skb(skb);
821 goto out;
822 }
823 BUG_ON(wlp->xmit_frame == NULL);
824 result = wlp->xmit_frame(wlp, skb, dev_addr);
825 if (result < 0) {
826 if (printk_ratelimit())
827 dev_err(dev, "WLP: Unable to transmit frame: %d\n",
828 result);
829 if (result == -ENXIO)
830 dev_err(dev, "WLP: Is network interface up? \n");
831 /* We could try again ... */
832 dev_kfree_skb(skb);/*we need to free if tx fails */
833 }
834out:
835 kfree(conn_ctx);
836 BUG_ON(wlp->start_queue == NULL);
837 wlp->start_queue(wlp);
838 mutex_unlock(&wss->mutex);
839 d_fnend(5, dev, "wlp %p, wss %p (wssid %s)\n", wlp, wss, buf);
840}
841
842/**
843 * Add WLP header to outgoing skb
844 *
845 * @eda_entry: pointer to neighbor's entry in the EDA cache
846 * @_skb: skb containing data destined to the neighbor
847 */
848int wlp_wss_prep_hdr(struct wlp *wlp, struct wlp_eda_node *eda_entry,
849 void *_skb)
850{
851 struct device *dev = &wlp->rc->uwb_dev.dev;
852 int result = 0;
853 unsigned char *eth_addr = eda_entry->eth_addr;
854 struct uwb_dev_addr *dev_addr = &eda_entry->dev_addr;
855 struct sk_buff *skb = _skb;
856 struct wlp_frame_std_abbrv_hdr *std_hdr;
857
858 d_fnstart(6, dev, "wlp %p \n", wlp);
859 if (eda_entry->state == WLP_WSS_CONNECTED) {
860 /* Add WLP header */
861 BUG_ON(skb_headroom(skb) < sizeof(*std_hdr));
862 std_hdr = (void *) __skb_push(skb, sizeof(*std_hdr));
863 std_hdr->hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID);
864 std_hdr->hdr.type = WLP_FRAME_STANDARD;
865 std_hdr->tag = eda_entry->wss->tag;
866 } else {
867 if (printk_ratelimit())
868 dev_err(dev, "WLP: Destination neighbor (Ethernet: "
869 "%02x:%02x:%02x:%02x:%02x:%02x, Dev: "
870 "%02x:%02x) is not connected. \n", eth_addr[0],
871 eth_addr[1], eth_addr[2], eth_addr[3],
872 eth_addr[4], eth_addr[5], dev_addr->data[1],
873 dev_addr->data[0]);
874 result = -EINVAL;
875 }
876 d_fnend(6, dev, "wlp %p \n", wlp);
877 return result;
878}
879
880
881/**
882 * Prepare skb for neighbor: connect if not already and prep WLP header
883 *
884 * This function is called in interrupt context, but it needs to sleep. We
885 * temporarily stop the net queue to establish the WLP connection.
886 * Setup of the WLP connection and restart of queue is scheduled
887 * on the default work queue.
888 *
889 * run with eda->lock held (spinlock)
890 */
891int wlp_wss_connect_prep(struct wlp *wlp, struct wlp_eda_node *eda_entry,
892 void *_skb)
893{
894 int result = 0;
895 struct device *dev = &wlp->rc->uwb_dev.dev;
896 struct uwb_dev_addr *dev_addr = &eda_entry->dev_addr;
897 unsigned char *eth_addr = eda_entry->eth_addr;
898 struct sk_buff *skb = _skb;
899 struct wlp_assoc_conn_ctx *conn_ctx;
900
901 d_fnstart(5, dev, "wlp %p\n", wlp);
902 d_printf(5, dev, "To neighbor %02x:%02x with eth "
903 "%02x:%02x:%02x:%02x:%02x:%02x\n", dev_addr->data[1],
904 dev_addr->data[0], eth_addr[0], eth_addr[1], eth_addr[2],
905 eth_addr[3], eth_addr[4], eth_addr[5]);
906 if (eda_entry->state == WLP_WSS_UNCONNECTED) {
907 /* We don't want any more packets while we set up connection */
908 BUG_ON(wlp->stop_queue == NULL);
909 wlp->stop_queue(wlp);
910 conn_ctx = kmalloc(sizeof(*conn_ctx), GFP_ATOMIC);
911 if (conn_ctx == NULL) {
912 if (printk_ratelimit())
913 dev_err(dev, "WLP: Unable to allocate memory "
914 "for connection handling.\n");
915 result = -ENOMEM;
916 goto out;
917 }
918 conn_ctx->wlp = wlp;
919 conn_ctx->skb = skb;
920 conn_ctx->eda_entry = *eda_entry;
921 INIT_WORK(&conn_ctx->ws, wlp_wss_connect_send);
922 schedule_work(&conn_ctx->ws);
923 result = 1;
924 } else if (eda_entry->state == WLP_WSS_CONNECT_FAILED) {
925 /* Previous connection attempts failed, don't retry - see
926 * conditions for connection in WLP 0.99 [7.6.2] */
927 if (printk_ratelimit())
928 dev_err(dev, "Could not connect to neighbor "
929 "previously. Not retrying. \n");
930 result = -ENONET;
931 goto out;
932 } else { /* eda_entry->state == WLP_WSS_CONNECTED */
933 d_printf(5, dev, "Neighbor is connected, preparing frame.\n");
934 result = wlp_wss_prep_hdr(wlp, eda_entry, skb);
935 }
936out:
937 d_fnend(5, dev, "wlp %p, result = %d \n", wlp, result);
938 return result;
939}
940
941/**
942 * Emulate broadcast: copy skb, send copy to neighbor (connect if not already)
943 *
944 * We need to copy skbs in the case where we emulate broadcast through
945 * unicast. We copy instead of clone because we are modifying the data of
946 * the frame after copying ... clones share data so we cannot emulate
947 * broadcast using clones.
948 *
949 * run with eda->lock held (spinlock)
950 */
951int wlp_wss_send_copy(struct wlp *wlp, struct wlp_eda_node *eda_entry,
952 void *_skb)
953{
954 int result = -ENOMEM;
955 struct device *dev = &wlp->rc->uwb_dev.dev;
956 struct sk_buff *skb = _skb;
957 struct sk_buff *copy;
958 struct uwb_dev_addr *dev_addr = &eda_entry->dev_addr;
959
960 d_fnstart(5, dev, "to neighbor %02x:%02x, skb (%p) \n",
961 dev_addr->data[1], dev_addr->data[0], skb);
962 copy = skb_copy(skb, GFP_ATOMIC);
963 if (copy == NULL) {
964 if (printk_ratelimit())
965 dev_err(dev, "WLP: Unable to copy skb for "
966 "transmission.\n");
967 goto out;
968 }
969 result = wlp_wss_connect_prep(wlp, eda_entry, copy);
970 if (result < 0) {
971 if (printk_ratelimit())
972 dev_err(dev, "WLP: Unable to connect/send skb "
973 "to neighbor.\n");
974 dev_kfree_skb_irq(copy);
975 goto out;
976 } else if (result == 1)
977 /* Frame will be transmitted separately */
978 goto out;
979 BUG_ON(wlp->xmit_frame == NULL);
980 result = wlp->xmit_frame(wlp, copy, dev_addr);
981 if (result < 0) {
982 if (printk_ratelimit())
983 dev_err(dev, "WLP: Unable to transmit frame: %d\n",
984 result);
985 if ((result == -ENXIO) && printk_ratelimit())
986 dev_err(dev, "WLP: Is network interface up? \n");
987 /* We could try again ... */
988 dev_kfree_skb_irq(copy);/*we need to free if tx fails */
989 }
990out:
991 d_fnend(5, dev, "to neighbor %02x:%02x \n", dev_addr->data[1],
992 dev_addr->data[0]);
993 return result;
994}
995
996
997/**
998 * Setup WSS
999 *
1000 * Should be called by network driver after the interface has been given a
1001 * MAC address.
1002 */
1003int wlp_wss_setup(struct net_device *net_dev, struct wlp_wss *wss)
1004{
1005 struct wlp *wlp = container_of(wss, struct wlp, wss);
1006 struct device *dev = &wlp->rc->uwb_dev.dev;
1007 int result = 0;
1008 d_fnstart(5, dev, "wss (%p) \n", wss);
1009 mutex_lock(&wss->mutex);
1010 wss->kobj.parent = &net_dev->dev.kobj;
1011 if (!is_valid_ether_addr(net_dev->dev_addr)) {
1012 dev_err(dev, "WLP: Invalid MAC address. Cannot use for"
1013 "virtual.\n");
1014 result = -EINVAL;
1015 goto out;
1016 }
1017 memcpy(wss->virtual_addr.data, net_dev->dev_addr,
1018 sizeof(wss->virtual_addr.data));
1019out:
1020 mutex_unlock(&wss->mutex);
1021 d_fnend(5, dev, "wss (%p) \n", wss);
1022 return result;
1023}
1024EXPORT_SYMBOL_GPL(wlp_wss_setup);
1025
1026/**
1027 * Remove WSS
1028 *
1029 * Called by client that configured WSS through wlp_wss_setup(). This
1030 * function is called when client no longer needs WSS, eg. client shuts
1031 * down.
1032 *
1033 * We remove the WLP IE from the beacon before initiating local cleanup.
1034 */
1035void wlp_wss_remove(struct wlp_wss *wss)
1036{
1037 struct wlp *wlp = container_of(wss, struct wlp, wss);
1038 struct device *dev = &wlp->rc->uwb_dev.dev;
1039 d_fnstart(5, dev, "wss (%p) \n", wss);
1040 mutex_lock(&wss->mutex);
1041 if (wss->state == WLP_WSS_STATE_ACTIVE)
1042 uwb_rc_ie_rm(wlp->rc, UWB_IE_WLP);
1043 if (wss->state != WLP_WSS_STATE_NONE) {
1044 sysfs_remove_group(&wss->kobj, &wss_attr_group);
1045 kobject_put(&wss->kobj);
1046 }
1047 wss->kobj.parent = NULL;
1048 memset(&wss->virtual_addr, 0, sizeof(wss->virtual_addr));
1049 /* Cleanup EDA cache */
1050 wlp_eda_release(&wlp->eda);
1051 wlp_eda_init(&wlp->eda);
1052 mutex_unlock(&wss->mutex);
1053 d_fnend(5, dev, "wss (%p) \n", wss);
1054}
1055EXPORT_SYMBOL_GPL(wlp_wss_remove);