diff options
Diffstat (limited to 'drivers/uwb/wlp/wlp-lc.c')
-rw-r--r-- | drivers/uwb/wlp/wlp-lc.c | 560 |
1 files changed, 0 insertions, 560 deletions
diff --git a/drivers/uwb/wlp/wlp-lc.c b/drivers/uwb/wlp/wlp-lc.c deleted file mode 100644 index 7f6a630bf26..00000000000 --- a/drivers/uwb/wlp/wlp-lc.c +++ /dev/null @@ -1,560 +0,0 @@ -/* - * WiMedia Logical Link Control Protocol (WLP) - * - * Copyright (C) 2005-2006 Intel Corporation - * Reinette Chatre <reinette.chatre@intel.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * - * FIXME: docs - */ -#include <linux/wlp.h> -#include <linux/slab.h> - -#include "wlp-internal.h" - -static -void wlp_neighbor_init(struct wlp_neighbor_e *neighbor) -{ - INIT_LIST_HEAD(&neighbor->wssid); -} - -/** - * Create area for device information storage - * - * wlp->mutex must be held - */ -int __wlp_alloc_device_info(struct wlp *wlp) -{ - struct device *dev = &wlp->rc->uwb_dev.dev; - BUG_ON(wlp->dev_info != NULL); - wlp->dev_info = kzalloc(sizeof(struct wlp_device_info), GFP_KERNEL); - if (wlp->dev_info == NULL) { - dev_err(dev, "WLP: Unable to allocate memory for " - "device information.\n"); - return -ENOMEM; - } - return 0; -} - - -/** - * Fill in device information using function provided by driver - * - * wlp->mutex must be held - */ -static -void __wlp_fill_device_info(struct wlp *wlp) -{ - wlp->fill_device_info(wlp, wlp->dev_info); -} - -/** - * Setup device information - * - * Allocate area for device information and populate it. - * - * wlp->mutex must be held - */ -int __wlp_setup_device_info(struct wlp *wlp) -{ - int result; - struct device *dev = &wlp->rc->uwb_dev.dev; - - result = __wlp_alloc_device_info(wlp); - if (result < 0) { - dev_err(dev, "WLP: Unable to allocate area for " - "device information.\n"); - return result; - } - __wlp_fill_device_info(wlp); - return 0; -} - -/** - * Remove information about neighbor stored temporarily - * - * Information learned during discovey should only be stored when the - * device enrolls in the neighbor's WSS. We do need to store this - * information temporarily in order to present it to the user. - * - * We are only interested in keeping neighbor WSS information if that - * neighbor is accepting enrollment. - * - * should be called with wlp->nbmutex held - */ -void wlp_remove_neighbor_tmp_info(struct wlp_neighbor_e *neighbor) -{ - struct wlp_wssid_e *wssid_e, *next; - u8 keep; - if (!list_empty(&neighbor->wssid)) { - list_for_each_entry_safe(wssid_e, next, &neighbor->wssid, - node) { - if (wssid_e->info != NULL) { - keep = wssid_e->info->accept_enroll; - kfree(wssid_e->info); - wssid_e->info = NULL; - if (!keep) { - list_del(&wssid_e->node); - kfree(wssid_e); - } - } - } - } - if (neighbor->info != NULL) { - kfree(neighbor->info); - neighbor->info = NULL; - } -} - -/* - * Populate WLP neighborhood cache with neighbor information - * - * A new neighbor is found. If it is discoverable then we add it to the - * neighborhood cache. - * - */ -static -int wlp_add_neighbor(struct wlp *wlp, struct uwb_dev *dev) -{ - int result = 0; - int discoverable; - struct wlp_neighbor_e *neighbor; - - /* - * FIXME: - * Use contents of WLP IE found in beacon cache to determine if - * neighbor is discoverable. - * The device does not support WLP IE yet so this still needs to be - * done. Until then we assume all devices are discoverable. - */ - discoverable = 1; /* will be changed when FIXME disappears */ - if (discoverable) { - /* Add neighbor to cache for discovery */ - neighbor = kzalloc(sizeof(*neighbor), GFP_KERNEL); - if (neighbor == NULL) { - dev_err(&dev->dev, "Unable to create memory for " - "new neighbor. \n"); - result = -ENOMEM; - goto error_no_mem; - } - wlp_neighbor_init(neighbor); - uwb_dev_get(dev); - neighbor->uwb_dev = dev; - list_add(&neighbor->node, &wlp->neighbors); - } -error_no_mem: - return result; -} - -/** - * Remove one neighbor from cache - */ -static -void __wlp_neighbor_release(struct wlp_neighbor_e *neighbor) -{ - struct wlp_wssid_e *wssid_e, *next_wssid_e; - - list_for_each_entry_safe(wssid_e, next_wssid_e, - &neighbor->wssid, node) { - list_del(&wssid_e->node); - kfree(wssid_e); - } - uwb_dev_put(neighbor->uwb_dev); - list_del(&neighbor->node); - kfree(neighbor); -} - -/** - * Clear entire neighborhood cache. - */ -static -void __wlp_neighbors_release(struct wlp *wlp) -{ - struct wlp_neighbor_e *neighbor, *next; - if (list_empty(&wlp->neighbors)) - return; - list_for_each_entry_safe(neighbor, next, &wlp->neighbors, node) { - __wlp_neighbor_release(neighbor); - } -} - -static -void wlp_neighbors_release(struct wlp *wlp) -{ - mutex_lock(&wlp->nbmutex); - __wlp_neighbors_release(wlp); - mutex_unlock(&wlp->nbmutex); -} - - - -/** - * Send D1 message to neighbor, receive D2 message - * - * @neighbor: neighbor to which D1 message will be sent - * @wss: if not NULL, it is an enrollment request for this WSS - * @wssid: if wss not NULL, this is the wssid of the WSS in which we - * want to enroll - * - * A D1/D2 exchange is done for one of two reasons: discovery or - * enrollment. If done for discovery the D1 message is sent to the neighbor - * and the contents of the D2 response is stored in a temporary cache. - * If done for enrollment the @wss and @wssid are provided also. In this - * case the D1 message is sent to the neighbor, the D2 response is parsed - * for enrollment of the WSS with wssid. - * - * &wss->mutex is held - */ -static -int wlp_d1d2_exchange(struct wlp *wlp, struct wlp_neighbor_e *neighbor, - struct wlp_wss *wss, struct wlp_uuid *wssid) -{ - int result; - struct device *dev = &wlp->rc->uwb_dev.dev; - DECLARE_COMPLETION_ONSTACK(completion); - struct wlp_session session; - struct sk_buff *skb; - struct wlp_frame_assoc *resp; - struct uwb_dev_addr *dev_addr = &neighbor->uwb_dev->dev_addr; - - mutex_lock(&wlp->mutex); - if (!wlp_uuid_is_set(&wlp->uuid)) { - dev_err(dev, "WLP: UUID is not set. Set via sysfs to " - "proceed.\n"); - result = -ENXIO; - goto out; - } - /* Send D1 association frame */ - result = wlp_send_assoc_frame(wlp, wss, dev_addr, WLP_ASSOC_D1); - if (result < 0) { - dev_err(dev, "Unable to send D1 frame to neighbor " - "%02x:%02x (%d)\n", dev_addr->data[1], - dev_addr->data[0], result); - goto out; - } - /* Create session, wait for response */ - session.exp_message = WLP_ASSOC_D2; - session.cb = wlp_session_cb; - session.cb_priv = &completion; - session.neighbor_addr = *dev_addr; - BUG_ON(wlp->session != NULL); - wlp->session = &session; - /* Wait for D2/F0 frame */ - result = wait_for_completion_interruptible_timeout(&completion, - WLP_PER_MSG_TIMEOUT * HZ); - if (result == 0) { - result = -ETIMEDOUT; - dev_err(dev, "Timeout while sending D1 to neighbor " - "%02x:%02x.\n", dev_addr->data[1], - dev_addr->data[0]); - goto error_session; - } - if (result < 0) { - dev_err(dev, "Unable to discover/enroll neighbor %02x:%02x.\n", - dev_addr->data[1], dev_addr->data[0]); - goto error_session; - } - /* Parse message in session->data: it will be either D2 or F0 */ - skb = session.data; - resp = (void *) skb->data; - - if (resp->type == WLP_ASSOC_F0) { - result = wlp_parse_f0(wlp, skb); - if (result < 0) - dev_err(dev, "WLP: Unable to parse F0 from neighbor " - "%02x:%02x.\n", dev_addr->data[1], - dev_addr->data[0]); - result = -EINVAL; - goto error_resp_parse; - } - if (wss == NULL) { - /* Discovery */ - result = wlp_parse_d2_frame_to_cache(wlp, skb, neighbor); - if (result < 0) { - dev_err(dev, "WLP: Unable to parse D2 message from " - "neighbor %02x:%02x for discovery.\n", - dev_addr->data[1], dev_addr->data[0]); - goto error_resp_parse; - } - } else { - /* Enrollment */ - result = wlp_parse_d2_frame_to_enroll(wss, skb, neighbor, - wssid); - if (result < 0) { - dev_err(dev, "WLP: Unable to parse D2 message from " - "neighbor %02x:%02x for enrollment.\n", - dev_addr->data[1], dev_addr->data[0]); - goto error_resp_parse; - } - } -error_resp_parse: - kfree_skb(skb); -error_session: - wlp->session = NULL; -out: - mutex_unlock(&wlp->mutex); - return result; -} - -/** - * Enroll into WSS of provided WSSID by using neighbor as registrar - * - * &wss->mutex is held - */ -int wlp_enroll_neighbor(struct wlp *wlp, struct wlp_neighbor_e *neighbor, - struct wlp_wss *wss, struct wlp_uuid *wssid) -{ - int result = 0; - struct device *dev = &wlp->rc->uwb_dev.dev; - char buf[WLP_WSS_UUID_STRSIZE]; - struct uwb_dev_addr *dev_addr = &neighbor->uwb_dev->dev_addr; - - wlp_wss_uuid_print(buf, sizeof(buf), wssid); - - result = wlp_d1d2_exchange(wlp, neighbor, wss, wssid); - if (result < 0) { - dev_err(dev, "WLP: D1/D2 message exchange for enrollment " - "failed. result = %d \n", result); - goto out; - } - if (wss->state != WLP_WSS_STATE_PART_ENROLLED) { - dev_err(dev, "WLP: Unable to enroll into WSS %s using " - "neighbor %02x:%02x. \n", buf, - dev_addr->data[1], dev_addr->data[0]); - result = -EINVAL; - goto out; - } - if (wss->secure_status == WLP_WSS_SECURE) { - dev_err(dev, "FIXME: need to complete secure enrollment.\n"); - result = -EINVAL; - goto error; - } else { - wss->state = WLP_WSS_STATE_ENROLLED; - dev_dbg(dev, "WLP: Success Enrollment into unsecure WSS " - "%s using neighbor %02x:%02x. \n", - buf, dev_addr->data[1], dev_addr->data[0]); - } -out: - return result; -error: - wlp_wss_reset(wss); - return result; -} - -/** - * Discover WSS information of neighbor's active WSS - */ -static -int wlp_discover_neighbor(struct wlp *wlp, - struct wlp_neighbor_e *neighbor) -{ - return wlp_d1d2_exchange(wlp, neighbor, NULL, NULL); -} - - -/** - * Each neighbor in the neighborhood cache is discoverable. Discover it. - * - * Discovery is done through sending of D1 association frame and parsing - * the D2 association frame response. Only wssid from D2 will be included - * in neighbor cache, rest is just displayed to user and forgotten. - * - * The discovery is not done in parallel. This is simple and enables us to - * maintain only one association context. - * - * The discovery of one neighbor does not affect the other, but if the - * discovery of a neighbor fails it is removed from the neighborhood cache. - */ -static -int wlp_discover_all_neighbors(struct wlp *wlp) -{ - int result = 0; - struct device *dev = &wlp->rc->uwb_dev.dev; - struct wlp_neighbor_e *neighbor, *next; - - list_for_each_entry_safe(neighbor, next, &wlp->neighbors, node) { - result = wlp_discover_neighbor(wlp, neighbor); - if (result < 0) { - dev_err(dev, "WLP: Unable to discover neighbor " - "%02x:%02x, removing from neighborhood. \n", - neighbor->uwb_dev->dev_addr.data[1], - neighbor->uwb_dev->dev_addr.data[0]); - __wlp_neighbor_release(neighbor); - } - } - return result; -} - -static int wlp_add_neighbor_helper(struct device *dev, void *priv) -{ - struct wlp *wlp = priv; - struct uwb_dev *uwb_dev = to_uwb_dev(dev); - - return wlp_add_neighbor(wlp, uwb_dev); -} - -/** - * Discover WLP neighborhood - * - * Will send D1 association frame to all devices in beacon group that have - * discoverable bit set in WLP IE. D2 frames will be received, information - * displayed to user in @buf. Partial information (from D2 association - * frame) will be cached to assist with future association - * requests. - * - * The discovery of the WLP neighborhood is triggered by the user. This - * should occur infrequently and we thus free current cache and re-allocate - * memory if needed. - * - * If one neighbor fails during initial discovery (determining if it is a - * neighbor or not), we fail all - note that interaction with neighbor has - * not occured at this point so if a failure occurs we know something went wrong - * locally. We thus undo everything. - */ -ssize_t wlp_discover(struct wlp *wlp) -{ - int result = 0; - struct device *dev = &wlp->rc->uwb_dev.dev; - - mutex_lock(&wlp->nbmutex); - /* Clear current neighborhood cache. */ - __wlp_neighbors_release(wlp); - /* Determine which devices in neighborhood. Repopulate cache. */ - result = uwb_dev_for_each(wlp->rc, wlp_add_neighbor_helper, wlp); - if (result < 0) { - /* May have partial neighbor information, release all. */ - __wlp_neighbors_release(wlp); - goto error_dev_for_each; - } - /* Discover the properties of devices in neighborhood. */ - result = wlp_discover_all_neighbors(wlp); - /* In case of failure we still print our partial results. */ - if (result < 0) { - dev_err(dev, "Unable to fully discover neighborhood. \n"); - result = 0; - } -error_dev_for_each: - mutex_unlock(&wlp->nbmutex); - return result; -} - -/** - * Handle events from UWB stack - * - * We handle events conservatively. If a neighbor goes off the air we - * remove it from the neighborhood. If an association process is in - * progress this function will block waiting for the nbmutex to become - * free. The association process will thus be allowed to complete before it - * is removed. - */ -static -void wlp_uwb_notifs_cb(void *_wlp, struct uwb_dev *uwb_dev, - enum uwb_notifs event) -{ - struct wlp *wlp = _wlp; - struct device *dev = &wlp->rc->uwb_dev.dev; - struct wlp_neighbor_e *neighbor, *next; - int result; - switch (event) { - case UWB_NOTIF_ONAIR: - result = wlp_eda_create_node(&wlp->eda, - uwb_dev->mac_addr.data, - &uwb_dev->dev_addr); - if (result < 0) - dev_err(dev, "WLP: Unable to add new neighbor " - "%02x:%02x to EDA cache.\n", - uwb_dev->dev_addr.data[1], - uwb_dev->dev_addr.data[0]); - break; - case UWB_NOTIF_OFFAIR: - wlp_eda_rm_node(&wlp->eda, &uwb_dev->dev_addr); - mutex_lock(&wlp->nbmutex); - list_for_each_entry_safe(neighbor, next, &wlp->neighbors, node) { - if (neighbor->uwb_dev == uwb_dev) - __wlp_neighbor_release(neighbor); - } - mutex_unlock(&wlp->nbmutex); - break; - default: - dev_err(dev, "don't know how to handle event %d from uwb\n", - event); - } -} - -static void wlp_channel_changed(struct uwb_pal *pal, int channel) -{ - struct wlp *wlp = container_of(pal, struct wlp, pal); - - if (channel < 0) - netif_carrier_off(wlp->ndev); - else - netif_carrier_on(wlp->ndev); -} - -int wlp_setup(struct wlp *wlp, struct uwb_rc *rc, struct net_device *ndev) -{ - int result; - - BUG_ON(wlp->fill_device_info == NULL); - BUG_ON(wlp->xmit_frame == NULL); - BUG_ON(wlp->stop_queue == NULL); - BUG_ON(wlp->start_queue == NULL); - - wlp->rc = rc; - wlp->ndev = ndev; - wlp_eda_init(&wlp->eda);/* Set up address cache */ - wlp->uwb_notifs_handler.cb = wlp_uwb_notifs_cb; - wlp->uwb_notifs_handler.data = wlp; - uwb_notifs_register(rc, &wlp->uwb_notifs_handler); - - uwb_pal_init(&wlp->pal); - wlp->pal.rc = rc; - wlp->pal.channel_changed = wlp_channel_changed; - result = uwb_pal_register(&wlp->pal); - if (result < 0) - uwb_notifs_deregister(wlp->rc, &wlp->uwb_notifs_handler); - - return result; -} -EXPORT_SYMBOL_GPL(wlp_setup); - -void wlp_remove(struct wlp *wlp) -{ - wlp_neighbors_release(wlp); - uwb_pal_unregister(&wlp->pal); - uwb_notifs_deregister(wlp->rc, &wlp->uwb_notifs_handler); - wlp_eda_release(&wlp->eda); - mutex_lock(&wlp->mutex); - if (wlp->dev_info != NULL) - kfree(wlp->dev_info); - mutex_unlock(&wlp->mutex); - wlp->rc = NULL; -} -EXPORT_SYMBOL_GPL(wlp_remove); - -/** - * wlp_reset_all - reset the WLP hardware - * @wlp: the WLP device to reset. - * - * This schedules a full hardware reset of the WLP device. The radio - * controller and any other PALs will also be reset. - */ -void wlp_reset_all(struct wlp *wlp) -{ - uwb_rc_reset_all(wlp->rc); -} -EXPORT_SYMBOL_GPL(wlp_reset_all); |