aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/uwb
diff options
context:
space:
mode:
authorReinette Chatre <reinette.chatre@intel.com>2008-09-17 11:34:16 -0400
committerDavid Vrabel <dv02@dv02pc01.europe.root.pri>2008-09-17 11:54:27 -0400
commitf51448543f8e4871f0539435fce42a14044f5652 (patch)
tree3e6f211771e2ac746029ee9bc9b21634f9457446 /drivers/uwb
parentde520b8bd5525d33e6a6f36b297836125736bd2a (diff)
uwb: add the WiMedia LLC Protocol stack
Add the generic code for the WiMedia Logical Link Control Protocol (WLP). This has been split into several patches for easier review. core (this patch): - everything else messages: - WLP message construction/decode wss: - Wireless Service Set support build-system: - Kconfig and Kbuild files Signed-off-by: David Vrabel <david.vrabel@csr.com>
Diffstat (limited to 'drivers/uwb')
-rw-r--r--drivers/uwb/wlp/driver.c43
-rw-r--r--drivers/uwb/wlp/eda.c449
-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
6 files changed, 2388 insertions, 0 deletions
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/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);