blob: 7f6a630bf26c47e4f2a5f13a5478d81f5cdcf346 [file] [log] [blame]
Reinette Chatref5144852008-09-17 16:34:16 +01001/*
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 */
Reinette Chatref5144852008-09-17 16:34:16 +010024#include <linux/wlp.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090025#include <linux/slab.h>
Reinette Chatref5144852008-09-17 16:34:16 +010026
David Vrabelbce83692008-12-22 18:22:50 +000027#include "wlp-internal.h"
Reinette Chatref5144852008-09-17 16:34:16 +010028
29static
30void wlp_neighbor_init(struct wlp_neighbor_e *neighbor)
31{
32 INIT_LIST_HEAD(&neighbor->wssid);
33}
34
35/**
36 * Create area for device information storage
37 *
38 * wlp->mutex must be held
39 */
40int __wlp_alloc_device_info(struct wlp *wlp)
41{
42 struct device *dev = &wlp->rc->uwb_dev.dev;
43 BUG_ON(wlp->dev_info != NULL);
44 wlp->dev_info = kzalloc(sizeof(struct wlp_device_info), GFP_KERNEL);
45 if (wlp->dev_info == NULL) {
46 dev_err(dev, "WLP: Unable to allocate memory for "
47 "device information.\n");
48 return -ENOMEM;
49 }
50 return 0;
51}
52
53
54/**
55 * Fill in device information using function provided by driver
56 *
57 * wlp->mutex must be held
58 */
59static
60void __wlp_fill_device_info(struct wlp *wlp)
61{
Reinette Chatref5144852008-09-17 16:34:16 +010062 wlp->fill_device_info(wlp, wlp->dev_info);
63}
64
65/**
66 * Setup device information
67 *
68 * Allocate area for device information and populate it.
69 *
70 * wlp->mutex must be held
71 */
72int __wlp_setup_device_info(struct wlp *wlp)
73{
74 int result;
75 struct device *dev = &wlp->rc->uwb_dev.dev;
76
77 result = __wlp_alloc_device_info(wlp);
78 if (result < 0) {
79 dev_err(dev, "WLP: Unable to allocate area for "
80 "device information.\n");
81 return result;
82 }
83 __wlp_fill_device_info(wlp);
84 return 0;
85}
86
87/**
88 * Remove information about neighbor stored temporarily
89 *
90 * Information learned during discovey should only be stored when the
91 * device enrolls in the neighbor's WSS. We do need to store this
92 * information temporarily in order to present it to the user.
93 *
94 * We are only interested in keeping neighbor WSS information if that
95 * neighbor is accepting enrollment.
96 *
97 * should be called with wlp->nbmutex held
98 */
99void wlp_remove_neighbor_tmp_info(struct wlp_neighbor_e *neighbor)
100{
101 struct wlp_wssid_e *wssid_e, *next;
102 u8 keep;
103 if (!list_empty(&neighbor->wssid)) {
104 list_for_each_entry_safe(wssid_e, next, &neighbor->wssid,
105 node) {
106 if (wssid_e->info != NULL) {
107 keep = wssid_e->info->accept_enroll;
108 kfree(wssid_e->info);
109 wssid_e->info = NULL;
110 if (!keep) {
111 list_del(&wssid_e->node);
112 kfree(wssid_e);
113 }
114 }
115 }
116 }
117 if (neighbor->info != NULL) {
118 kfree(neighbor->info);
119 neighbor->info = NULL;
120 }
121}
122
David Vrabelbce83692008-12-22 18:22:50 +0000123/*
Reinette Chatref5144852008-09-17 16:34:16 +0100124 * Populate WLP neighborhood cache with neighbor information
125 *
126 * A new neighbor is found. If it is discoverable then we add it to the
127 * neighborhood cache.
128 *
129 */
130static
131int wlp_add_neighbor(struct wlp *wlp, struct uwb_dev *dev)
132{
133 int result = 0;
134 int discoverable;
135 struct wlp_neighbor_e *neighbor;
136
David Vrabelbce83692008-12-22 18:22:50 +0000137 /*
Reinette Chatref5144852008-09-17 16:34:16 +0100138 * FIXME:
139 * Use contents of WLP IE found in beacon cache to determine if
140 * neighbor is discoverable.
141 * The device does not support WLP IE yet so this still needs to be
142 * done. Until then we assume all devices are discoverable.
143 */
144 discoverable = 1; /* will be changed when FIXME disappears */
145 if (discoverable) {
146 /* Add neighbor to cache for discovery */
147 neighbor = kzalloc(sizeof(*neighbor), GFP_KERNEL);
148 if (neighbor == NULL) {
149 dev_err(&dev->dev, "Unable to create memory for "
150 "new neighbor. \n");
151 result = -ENOMEM;
152 goto error_no_mem;
153 }
154 wlp_neighbor_init(neighbor);
155 uwb_dev_get(dev);
156 neighbor->uwb_dev = dev;
157 list_add(&neighbor->node, &wlp->neighbors);
158 }
159error_no_mem:
Reinette Chatref5144852008-09-17 16:34:16 +0100160 return result;
161}
162
163/**
164 * Remove one neighbor from cache
165 */
166static
167void __wlp_neighbor_release(struct wlp_neighbor_e *neighbor)
168{
169 struct wlp_wssid_e *wssid_e, *next_wssid_e;
170
171 list_for_each_entry_safe(wssid_e, next_wssid_e,
172 &neighbor->wssid, node) {
173 list_del(&wssid_e->node);
174 kfree(wssid_e);
175 }
176 uwb_dev_put(neighbor->uwb_dev);
177 list_del(&neighbor->node);
178 kfree(neighbor);
179}
180
181/**
182 * Clear entire neighborhood cache.
183 */
184static
185void __wlp_neighbors_release(struct wlp *wlp)
186{
187 struct wlp_neighbor_e *neighbor, *next;
188 if (list_empty(&wlp->neighbors))
189 return;
190 list_for_each_entry_safe(neighbor, next, &wlp->neighbors, node) {
191 __wlp_neighbor_release(neighbor);
192 }
193}
194
195static
196void wlp_neighbors_release(struct wlp *wlp)
197{
198 mutex_lock(&wlp->nbmutex);
199 __wlp_neighbors_release(wlp);
200 mutex_unlock(&wlp->nbmutex);
201}
202
203
204
205/**
206 * Send D1 message to neighbor, receive D2 message
207 *
208 * @neighbor: neighbor to which D1 message will be sent
209 * @wss: if not NULL, it is an enrollment request for this WSS
210 * @wssid: if wss not NULL, this is the wssid of the WSS in which we
211 * want to enroll
212 *
213 * A D1/D2 exchange is done for one of two reasons: discovery or
214 * enrollment. If done for discovery the D1 message is sent to the neighbor
215 * and the contents of the D2 response is stored in a temporary cache.
216 * If done for enrollment the @wss and @wssid are provided also. In this
217 * case the D1 message is sent to the neighbor, the D2 response is parsed
218 * for enrollment of the WSS with wssid.
219 *
220 * &wss->mutex is held
221 */
222static
223int wlp_d1d2_exchange(struct wlp *wlp, struct wlp_neighbor_e *neighbor,
224 struct wlp_wss *wss, struct wlp_uuid *wssid)
225{
226 int result;
227 struct device *dev = &wlp->rc->uwb_dev.dev;
228 DECLARE_COMPLETION_ONSTACK(completion);
229 struct wlp_session session;
230 struct sk_buff *skb;
231 struct wlp_frame_assoc *resp;
232 struct uwb_dev_addr *dev_addr = &neighbor->uwb_dev->dev_addr;
233
234 mutex_lock(&wlp->mutex);
235 if (!wlp_uuid_is_set(&wlp->uuid)) {
236 dev_err(dev, "WLP: UUID is not set. Set via sysfs to "
237 "proceed.\n");
238 result = -ENXIO;
239 goto out;
240 }
241 /* Send D1 association frame */
242 result = wlp_send_assoc_frame(wlp, wss, dev_addr, WLP_ASSOC_D1);
243 if (result < 0) {
244 dev_err(dev, "Unable to send D1 frame to neighbor "
245 "%02x:%02x (%d)\n", dev_addr->data[1],
246 dev_addr->data[0], result);
Reinette Chatref5144852008-09-17 16:34:16 +0100247 goto out;
248 }
249 /* Create session, wait for response */
250 session.exp_message = WLP_ASSOC_D2;
251 session.cb = wlp_session_cb;
252 session.cb_priv = &completion;
253 session.neighbor_addr = *dev_addr;
254 BUG_ON(wlp->session != NULL);
255 wlp->session = &session;
256 /* Wait for D2/F0 frame */
257 result = wait_for_completion_interruptible_timeout(&completion,
258 WLP_PER_MSG_TIMEOUT * HZ);
259 if (result == 0) {
260 result = -ETIMEDOUT;
261 dev_err(dev, "Timeout while sending D1 to neighbor "
262 "%02x:%02x.\n", dev_addr->data[1],
263 dev_addr->data[0]);
264 goto error_session;
265 }
266 if (result < 0) {
267 dev_err(dev, "Unable to discover/enroll neighbor %02x:%02x.\n",
268 dev_addr->data[1], dev_addr->data[0]);
269 goto error_session;
270 }
271 /* Parse message in session->data: it will be either D2 or F0 */
272 skb = session.data;
273 resp = (void *) skb->data;
Reinette Chatref5144852008-09-17 16:34:16 +0100274
275 if (resp->type == WLP_ASSOC_F0) {
276 result = wlp_parse_f0(wlp, skb);
277 if (result < 0)
278 dev_err(dev, "WLP: Unable to parse F0 from neighbor "
279 "%02x:%02x.\n", dev_addr->data[1],
280 dev_addr->data[0]);
281 result = -EINVAL;
282 goto error_resp_parse;
283 }
284 if (wss == NULL) {
285 /* Discovery */
286 result = wlp_parse_d2_frame_to_cache(wlp, skb, neighbor);
287 if (result < 0) {
288 dev_err(dev, "WLP: Unable to parse D2 message from "
289 "neighbor %02x:%02x for discovery.\n",
290 dev_addr->data[1], dev_addr->data[0]);
291 goto error_resp_parse;
292 }
293 } else {
294 /* Enrollment */
295 result = wlp_parse_d2_frame_to_enroll(wss, skb, neighbor,
296 wssid);
297 if (result < 0) {
298 dev_err(dev, "WLP: Unable to parse D2 message from "
299 "neighbor %02x:%02x for enrollment.\n",
300 dev_addr->data[1], dev_addr->data[0]);
301 goto error_resp_parse;
302 }
303 }
304error_resp_parse:
305 kfree_skb(skb);
306error_session:
307 wlp->session = NULL;
308out:
309 mutex_unlock(&wlp->mutex);
310 return result;
311}
312
313/**
314 * Enroll into WSS of provided WSSID by using neighbor as registrar
315 *
316 * &wss->mutex is held
317 */
318int wlp_enroll_neighbor(struct wlp *wlp, struct wlp_neighbor_e *neighbor,
319 struct wlp_wss *wss, struct wlp_uuid *wssid)
320{
321 int result = 0;
322 struct device *dev = &wlp->rc->uwb_dev.dev;
323 char buf[WLP_WSS_UUID_STRSIZE];
324 struct uwb_dev_addr *dev_addr = &neighbor->uwb_dev->dev_addr;
David Vrabelbce83692008-12-22 18:22:50 +0000325
Reinette Chatref5144852008-09-17 16:34:16 +0100326 wlp_wss_uuid_print(buf, sizeof(buf), wssid);
David Vrabelbce83692008-12-22 18:22:50 +0000327
Reinette Chatref5144852008-09-17 16:34:16 +0100328 result = wlp_d1d2_exchange(wlp, neighbor, wss, wssid);
329 if (result < 0) {
330 dev_err(dev, "WLP: D1/D2 message exchange for enrollment "
331 "failed. result = %d \n", result);
332 goto out;
333 }
334 if (wss->state != WLP_WSS_STATE_PART_ENROLLED) {
335 dev_err(dev, "WLP: Unable to enroll into WSS %s using "
336 "neighbor %02x:%02x. \n", buf,
337 dev_addr->data[1], dev_addr->data[0]);
338 result = -EINVAL;
339 goto out;
340 }
341 if (wss->secure_status == WLP_WSS_SECURE) {
342 dev_err(dev, "FIXME: need to complete secure enrollment.\n");
343 result = -EINVAL;
344 goto error;
345 } else {
346 wss->state = WLP_WSS_STATE_ENROLLED;
David Vrabelbce83692008-12-22 18:22:50 +0000347 dev_dbg(dev, "WLP: Success Enrollment into unsecure WSS "
348 "%s using neighbor %02x:%02x. \n",
349 buf, dev_addr->data[1], dev_addr->data[0]);
Reinette Chatref5144852008-09-17 16:34:16 +0100350 }
Reinette Chatref5144852008-09-17 16:34:16 +0100351out:
352 return result;
353error:
354 wlp_wss_reset(wss);
355 return result;
356}
357
358/**
359 * Discover WSS information of neighbor's active WSS
360 */
361static
362int wlp_discover_neighbor(struct wlp *wlp,
363 struct wlp_neighbor_e *neighbor)
364{
365 return wlp_d1d2_exchange(wlp, neighbor, NULL, NULL);
366}
367
368
369/**
370 * Each neighbor in the neighborhood cache is discoverable. Discover it.
371 *
372 * Discovery is done through sending of D1 association frame and parsing
373 * the D2 association frame response. Only wssid from D2 will be included
374 * in neighbor cache, rest is just displayed to user and forgotten.
375 *
376 * The discovery is not done in parallel. This is simple and enables us to
377 * maintain only one association context.
378 *
379 * The discovery of one neighbor does not affect the other, but if the
380 * discovery of a neighbor fails it is removed from the neighborhood cache.
381 */
382static
383int wlp_discover_all_neighbors(struct wlp *wlp)
384{
385 int result = 0;
386 struct device *dev = &wlp->rc->uwb_dev.dev;
387 struct wlp_neighbor_e *neighbor, *next;
388
389 list_for_each_entry_safe(neighbor, next, &wlp->neighbors, node) {
390 result = wlp_discover_neighbor(wlp, neighbor);
391 if (result < 0) {
392 dev_err(dev, "WLP: Unable to discover neighbor "
393 "%02x:%02x, removing from neighborhood. \n",
394 neighbor->uwb_dev->dev_addr.data[1],
395 neighbor->uwb_dev->dev_addr.data[0]);
396 __wlp_neighbor_release(neighbor);
397 }
398 }
399 return result;
400}
401
402static int wlp_add_neighbor_helper(struct device *dev, void *priv)
403{
404 struct wlp *wlp = priv;
405 struct uwb_dev *uwb_dev = to_uwb_dev(dev);
406
407 return wlp_add_neighbor(wlp, uwb_dev);
408}
409
410/**
411 * Discover WLP neighborhood
412 *
413 * Will send D1 association frame to all devices in beacon group that have
414 * discoverable bit set in WLP IE. D2 frames will be received, information
415 * displayed to user in @buf. Partial information (from D2 association
416 * frame) will be cached to assist with future association
417 * requests.
418 *
419 * The discovery of the WLP neighborhood is triggered by the user. This
420 * should occur infrequently and we thus free current cache and re-allocate
421 * memory if needed.
422 *
423 * If one neighbor fails during initial discovery (determining if it is a
424 * neighbor or not), we fail all - note that interaction with neighbor has
425 * not occured at this point so if a failure occurs we know something went wrong
426 * locally. We thus undo everything.
427 */
428ssize_t wlp_discover(struct wlp *wlp)
429{
430 int result = 0;
431 struct device *dev = &wlp->rc->uwb_dev.dev;
432
Reinette Chatref5144852008-09-17 16:34:16 +0100433 mutex_lock(&wlp->nbmutex);
434 /* Clear current neighborhood cache. */
435 __wlp_neighbors_release(wlp);
436 /* Determine which devices in neighborhood. Repopulate cache. */
437 result = uwb_dev_for_each(wlp->rc, wlp_add_neighbor_helper, wlp);
438 if (result < 0) {
439 /* May have partial neighbor information, release all. */
440 __wlp_neighbors_release(wlp);
441 goto error_dev_for_each;
442 }
443 /* Discover the properties of devices in neighborhood. */
444 result = wlp_discover_all_neighbors(wlp);
445 /* In case of failure we still print our partial results. */
446 if (result < 0) {
447 dev_err(dev, "Unable to fully discover neighborhood. \n");
448 result = 0;
449 }
450error_dev_for_each:
451 mutex_unlock(&wlp->nbmutex);
Reinette Chatref5144852008-09-17 16:34:16 +0100452 return result;
453}
454
455/**
456 * Handle events from UWB stack
457 *
458 * We handle events conservatively. If a neighbor goes off the air we
459 * remove it from the neighborhood. If an association process is in
460 * progress this function will block waiting for the nbmutex to become
461 * free. The association process will thus be allowed to complete before it
462 * is removed.
463 */
464static
465void wlp_uwb_notifs_cb(void *_wlp, struct uwb_dev *uwb_dev,
466 enum uwb_notifs event)
467{
468 struct wlp *wlp = _wlp;
469 struct device *dev = &wlp->rc->uwb_dev.dev;
470 struct wlp_neighbor_e *neighbor, *next;
471 int result;
472 switch (event) {
473 case UWB_NOTIF_ONAIR:
Reinette Chatref5144852008-09-17 16:34:16 +0100474 result = wlp_eda_create_node(&wlp->eda,
475 uwb_dev->mac_addr.data,
476 &uwb_dev->dev_addr);
477 if (result < 0)
478 dev_err(dev, "WLP: Unable to add new neighbor "
479 "%02x:%02x to EDA cache.\n",
480 uwb_dev->dev_addr.data[1],
481 uwb_dev->dev_addr.data[0]);
482 break;
483 case UWB_NOTIF_OFFAIR:
Reinette Chatref5144852008-09-17 16:34:16 +0100484 wlp_eda_rm_node(&wlp->eda, &uwb_dev->dev_addr);
485 mutex_lock(&wlp->nbmutex);
David Vrabelbce83692008-12-22 18:22:50 +0000486 list_for_each_entry_safe(neighbor, next, &wlp->neighbors, node) {
487 if (neighbor->uwb_dev == uwb_dev)
Reinette Chatref5144852008-09-17 16:34:16 +0100488 __wlp_neighbor_release(neighbor);
Reinette Chatref5144852008-09-17 16:34:16 +0100489 }
490 mutex_unlock(&wlp->nbmutex);
491 break;
492 default:
493 dev_err(dev, "don't know how to handle event %d from uwb\n",
494 event);
495 }
496}
497
David Vrabele8e15942008-11-17 16:16:51 +0000498static void wlp_channel_changed(struct uwb_pal *pal, int channel)
499{
500 struct wlp *wlp = container_of(pal, struct wlp, pal);
501
502 if (channel < 0)
503 netif_carrier_off(wlp->ndev);
504 else
505 netif_carrier_on(wlp->ndev);
506}
507
508int wlp_setup(struct wlp *wlp, struct uwb_rc *rc, struct net_device *ndev)
Reinette Chatref5144852008-09-17 16:34:16 +0100509{
Reinette Chatref5144852008-09-17 16:34:16 +0100510 int result;
511
Reinette Chatref5144852008-09-17 16:34:16 +0100512 BUG_ON(wlp->fill_device_info == NULL);
513 BUG_ON(wlp->xmit_frame == NULL);
514 BUG_ON(wlp->stop_queue == NULL);
515 BUG_ON(wlp->start_queue == NULL);
David Vrabelbce83692008-12-22 18:22:50 +0000516
Reinette Chatref5144852008-09-17 16:34:16 +0100517 wlp->rc = rc;
David Vrabele8e15942008-11-17 16:16:51 +0000518 wlp->ndev = ndev;
Reinette Chatref5144852008-09-17 16:34:16 +0100519 wlp_eda_init(&wlp->eda);/* Set up address cache */
520 wlp->uwb_notifs_handler.cb = wlp_uwb_notifs_cb;
521 wlp->uwb_notifs_handler.data = wlp;
522 uwb_notifs_register(rc, &wlp->uwb_notifs_handler);
523
524 uwb_pal_init(&wlp->pal);
David Vrabel6fae35f2008-11-17 15:53:42 +0000525 wlp->pal.rc = rc;
David Vrabele8e15942008-11-17 16:16:51 +0000526 wlp->pal.channel_changed = wlp_channel_changed;
David Vrabel6fae35f2008-11-17 15:53:42 +0000527 result = uwb_pal_register(&wlp->pal);
Reinette Chatref5144852008-09-17 16:34:16 +0100528 if (result < 0)
529 uwb_notifs_deregister(wlp->rc, &wlp->uwb_notifs_handler);
530
Reinette Chatref5144852008-09-17 16:34:16 +0100531 return result;
532}
533EXPORT_SYMBOL_GPL(wlp_setup);
534
535void wlp_remove(struct wlp *wlp)
536{
Reinette Chatref5144852008-09-17 16:34:16 +0100537 wlp_neighbors_release(wlp);
David Vrabel6fae35f2008-11-17 15:53:42 +0000538 uwb_pal_unregister(&wlp->pal);
Reinette Chatref5144852008-09-17 16:34:16 +0100539 uwb_notifs_deregister(wlp->rc, &wlp->uwb_notifs_handler);
540 wlp_eda_release(&wlp->eda);
541 mutex_lock(&wlp->mutex);
542 if (wlp->dev_info != NULL)
543 kfree(wlp->dev_info);
544 mutex_unlock(&wlp->mutex);
545 wlp->rc = NULL;
Reinette Chatref5144852008-09-17 16:34:16 +0100546}
547EXPORT_SYMBOL_GPL(wlp_remove);
548
549/**
550 * wlp_reset_all - reset the WLP hardware
551 * @wlp: the WLP device to reset.
552 *
553 * This schedules a full hardware reset of the WLP device. The radio
554 * controller and any other PALs will also be reset.
555 */
556void wlp_reset_all(struct wlp *wlp)
557{
558 uwb_rc_reset_all(wlp->rc);
559}
560EXPORT_SYMBOL_GPL(wlp_reset_all);