/* * --------------------------------------------------------------------------- * FILE: netdev.c * * PURPOSE: * This file provides the upper edge interface to the linux netdevice * and wireless extensions. * It is part of the porting exercise. * * Copyright (C) 2005-2010 by Cambridge Silicon Radio Ltd. * * Refer to LICENSE.txt included with this source code for details on * the license terms. * * --------------------------------------------------------------------------- */ /* * Porting Notes: * This file implements the data plane of the UniFi linux driver. * * All the Tx packets are passed to the HIP core lib, using the * unifi_send_signal() API. For EAPOL packets use the MLME-EAPOL.req * signal, for all other use the MLME-UNITDATA.req. The unifi_send_signal() * expects the wire-formatted (packed) signal. For convenience, in the OS * layer we only use the native (unpacked) signal structures. The HIP core lib * provides the write_pack() helper function to convert to the packed signal. * The packet is stored in the bulk data of the signal. We do not need to * allocate new memory to store the packet, because unifi_net_data_malloc() * is implemented to return a skb, which is the format of packet in Linux. * The HIP core lib frees the bulk data buffers, so we do not need to do * this in the OS layer. * * All the Rx packets are MLME-UNITDATA.ind signals, passed by the HIP core lib * in unifi_receive_event(). We do not need to allocate an skb and copy the * received packet because the HIP core lib has stored in memory allocated by * unifi_net_data_malloc(). Also, we can perform the 802.11 to Ethernet * translation in-place because we allocate the extra memory allocated in * unifi_net_data_malloc(). * * If possible, the porting exercise should appropriately implement * unifi_net_data_malloc() and unifi_net_data_free() to save copies between * network and driver buffers. */ #include <linux/types.h>#include <linux/etherdevice.h>#include <linux/mutex.h>#include <linux/semaphore.h>#include <linux/version.h>#include <linux/vmalloc.h>#include "csr_wifi_hip_unifi.h"#include "csr_wifi_hip_conversions.h"#include "unifi_priv.h"#include <net/pkt_sched.h> /* Wext handler is suported only if CSR_SUPPORT_WEXT is defined */#ifdef CSR_SUPPORT_WEXTextern struct iw_handler_def unifi_iw_handler_def;#endif /* CSR_SUPPORT_WEXT */static void check_ba_frame_age_timeout( unifi_priv_t *priv, netInterface_priv_t *interfacePriv, ba_session_rx_struct *ba_session);static void process_ba_frame(unifi_priv_t *priv, netInterface_priv_t *interfacePriv, ba_session_rx_struct *ba_session, frame_desc_struct *frame_desc);static void process_ba_complete(unifi_priv_t *priv, netInterface_priv_t *interfacePriv);static void process_ma_packet_error_ind(unifi_priv_t *priv, CSR_SIGNAL *signal, bulk_data_param_t *bulkdata);static void process_amsdu(unifi_priv_t *priv, CSR_SIGNAL *signal, bulk_data_param_t *bulkdata);static int uf_net_open(struct net_device *dev);static int uf_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);static int uf_net_stop(struct net_device *dev);static struct net_device_stats *uf_net_get_stats(struct net_device *dev);static u16 uf_net_select_queue(struct net_device *dev, struct sk_buff *skb);static netdev_tx_t uf_net_xmit(struct sk_buff *skb, struct net_device *dev);static void uf_set_multicast_list(struct net_device *dev); typedef int (*tx_signal_handler)(unifi_priv_t *priv, struct sk_buff *skb, const struct ethhdr *ehdr, CSR_PRIORITY priority); #ifdef CONFIG_NET_SCHED/* * Queueing Discipline Interface * Only used if kernel is configured with CONFIG_NET_SCHED */ /* * The driver uses the qdisc interface to buffer and control all * outgoing traffic. We create a root qdisc, register our qdisc operations * and later we create two subsiduary pfifo queues for the uncontrolled * and controlled ports. * * The network stack delivers all outgoing packets in our enqueue handler. * There, we classify the packet and decide whether to store it or drop it * (if the controlled port state is set to "discard"). * If the packet is enqueued, the network stack call our dequeue handler. * There, we decide whether we can send the packet, delay it or drop it * (the controlled port configuration might have changed meanwhile). * If a packet is dequeued, then the network stack calls our hard_start_xmit * handler where finally we send the packet. * * If the hard_start_xmit handler fails to send the packet, we return * NETDEV_TX_BUSY and the network stack call our requeue handler where * we put the packet back in the same queue in came from. * */ struct uf_sched_data{ /* Traffic Classifier TBD */ struct tcf_proto *filter_list; /* Our two queues */ struct Qdisc *queues[UNIFI_TRAFFIC_Q_MAX];}; struct uf_tx_packet_data { /* Queue the packet is stored in */ unifi_TrafficQueue queue; /* QoS Priority determined when enqueing packet */ CSR_PRIORITY priority; /* Debug */ unsigned long host_tag;}; #endif /* CONFIG_NET_SCHED */ static const struct net_device_ops uf_netdev_ops ={ .ndo_open = uf_net_open, .ndo_stop = uf_net_stop, .ndo_start_xmit = uf_net_xmit, .ndo_do_ioctl = uf_net_ioctl, .ndo_get_stats = uf_net_get_stats, /* called by /proc/net/dev */ .ndo_set_rx_mode = uf_set_multicast_list, .ndo_select_queue = uf_net_select_queue,}; static u8 oui_rfc1042[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 };static u8 oui_8021h[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 }; /* Callback for event logging to blocking clients */static void netdev_mlme_event_handler(ul_client_t *client, const u8 *sig_packed, int sig_len, const bulk_data_param_t *bulkdata, int dir); #ifdef CSR_SUPPORT_WEXT/* Declare netdev_notifier block which will contain the state change * handler callback function */static struct notifier_block uf_netdev_notifier;#endif /* * --------------------------------------------------------------------------- * uf_alloc_netdevice * * Allocate memory for the net_device and device private structs * for this interface. * Fill in the fields, but don't register the interface yet. * We need to configure the UniFi first. * * Arguments: * sdio_dev Pointer to SDIO context handle to use for all * SDIO ops. * bus_id A small number indicating the SDIO card position on the * bus. Typically this is the slot number, e.g. 0, 1 etc. * Valid values are 0 to MAX_UNIFI_DEVS-1. * * Returns: * Pointer to device private struct. * * Notes: * The net_device and device private structs are allocated together * and should be freed by freeing the net_device pointer. * --------------------------------------------------------------------------- */unifi_priv_t *uf_alloc_netdevice(CsrSdioFunction *sdio_dev, int bus_id){ struct net_device *dev; unifi_priv_t *priv; netInterface_priv_t *interfacePriv;#ifdef CSR_SUPPORT_WEXT int rc;#endif unsigned char i; /* loop index */ /* * Allocate netdevice struct, assign name template and * setup as an ethernet device. * The net_device and private structs are zeroed. Ether_setup() then * sets up ethernet handlers and values. * The RedHat 9 redhat-config-network tool doesn't recognise wlan* devices, * so use "eth*" (like other wireless extns drivers). */ dev = alloc_etherdev_mq(sizeof(unifi_priv_t) + sizeof(netInterface_priv_t), UNIFI_TRAFFIC_Q_MAX); if (dev == NULL) { return NULL; } /* Set up back pointer from priv to netdev */ interfacePriv = (netInterface_priv_t *)netdev_priv(dev); priv = (unifi_priv_t *)(interfacePriv + 1); interfacePriv->privPtr = priv; interfacePriv->InterfaceTag = 0; /* Initialize all supported netdev interface to be NULL */ for(i=0; i<CSR_WIFI_NUM_INTERFACES; i++) { priv->netdev[i] = NULL; priv->interfacePriv[i] = NULL; } priv->netdev[0] = dev; priv->interfacePriv[0] = interfacePriv; /* Setup / override net_device fields */ dev->netdev_ops = &uf_netdev_ops; #ifdef CSR_SUPPORT_WEXT dev->wireless_handlers = &unifi_iw_handler_def;#if IW_HANDLER_VERSION < 6 dev->get_wireless_stats = unifi_get_wireless_stats;#endif /* IW_HANDLER_VERSION */#endif /* CSR_SUPPORT_WEXT */ /* This gives us enough headroom to add the 802.11 header */ dev->needed_headroom = 32; /* Use bus_id as instance number */ priv->instance = bus_id; /* Store SDIO pointer to pass in the core */ priv->sdio = sdio_dev; sdio_dev->driverData = (void*)priv; /* Consider UniFi to be uninitialised */ priv->init_progress = UNIFI_INIT_NONE; priv->prev_queue = 0; /* * Initialise the clients structure array. * We do not need protection around ul_init_clients() because * the character device can not be used until uf_alloc_netdevice() * returns and Unifi_instances[bus_id]=priv is set, since unifi_open() * will return -ENODEV. */ ul_init_clients(priv); /* * Register a new ul client to send the multicast list signals. * Note: priv->instance must be set before calling this. */ priv->netdev_client = ul_register_client(priv, 0, netdev_mlme_event_handler); if (priv->netdev_client == NULL) { unifi_error(priv, "Failed to register a unifi client for background netdev processing\n"); free_netdev(priv->netdev[0]); return NULL; } unifi_trace(priv, UDBG2, "Netdev %p client (id:%d s:0x%X) is registered\n", dev, priv->netdev_client->client_id, priv->netdev_client->sender_id); priv->sta_wmm_capabilities = 0; #if (defined(CSR_WIFI_SECURITY_WAPI_ENABLE) && defined(CSR_SUPPORT_SME)) priv->wapi_multicast_filter = 0; priv->wapi_unicast_filter = 0; priv->wapi_unicast_queued_pkt_filter = 0;#ifdef CSR_WIFI_SECURITY_WAPI_QOSCTRL_MIC_WORKAROUND priv->isWapiConnection = FALSE;#endif#endif /* Enable all queues by default */ interfacePriv->queueEnabled[0] = 1; interfacePriv->queueEnabled[1] = 1; interfacePriv->queueEnabled[2] = 1; interfacePriv->queueEnabled[3] = 1; #ifdef CSR_SUPPORT_SME priv->allPeerDozing = 0;#endif /* * Initialise the OS private struct. */ /* * Instead of deciding in advance to use 11bg or 11a, we could do a more * clever scan on both radios. */ if (use_5g) { priv->if_index = CSR_INDEX_5G; unifi_info(priv, "Using the 802.11a radio\n"); } else { priv->if_index = CSR_INDEX_2G4; } /* Initialise bh thread structure */ priv->bh_thread.thread_task = NULL; priv->bh_thread.block_thread = 1; init_waitqueue_head(&priv->bh_thread.wakeup_q); priv->bh_thread.wakeup_flag = 0; sprintf(priv->bh_thread.name, "uf_bh_thread"); /* reset the connected state for the interface */ interfacePriv->connected = UnifiConnectedUnknown; /* -1 unknown, 0 no, 1 yes */ #ifdef USE_DRIVER_LOCK sema_init(&priv->lock, 1);#endif /* USE_DRIVER_LOCK */ spin_lock_init(&priv->send_signal_lock); spin_lock_init(&priv->m4_lock); sema_init(&priv->ba_mutex, 1); #if (defined(CSR_WIFI_SECURITY_WAPI_ENABLE) && defined(CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION)) spin_lock_init(&priv->wapi_lock);#endif #ifdef CSR_SUPPORT_SME spin_lock_init(&priv->staRecord_lock); spin_lock_init(&priv->tx_q_lock);#endif /* Create the Traffic Analysis workqueue */ priv->unifi_workqueue = create_singlethread_workqueue("unifi_workq"); if (priv->unifi_workqueue == NULL) { /* Deregister priv->netdev_client */ ul_deregister_client(priv->netdev_client); free_netdev(priv->netdev[0]); return NULL; } #ifdef CSR_SUPPORT_SME /* Create the Multicast Addresses list work structure */ INIT_WORK(&priv->multicast_list_task, uf_multicast_list_wq); /* Create m4 buffering work structure */ INIT_WORK(&interfacePriv->send_m4_ready_task, uf_send_m4_ready_wq); #if (defined(CSR_WIFI_SECURITY_WAPI_ENABLE) && defined(CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION)) /* Create work structure to buffer the WAPI data packets to be sent to SME for encryption */ INIT_WORK(&interfacePriv->send_pkt_to_encrypt, uf_send_pkt_to_encrypt);#endif#endif priv->ref_count = 1; priv->amp_client = NULL; priv->coredump_mode = 0; priv->ptest_mode = 0; priv->wol_suspend = FALSE; INIT_LIST_HEAD(&interfacePriv->rx_uncontrolled_list); INIT_LIST_HEAD(&interfacePriv->rx_controlled_list); sema_init(&priv->rx_q_sem, 1); #ifdef CSR_SUPPORT_WEXT interfacePriv->netdev_callback_registered = FALSE; interfacePriv->wait_netdev_change = FALSE; /* Register callback for netdevice state changes */ if ((rc = register_netdevice_notifier(&uf_netdev_notifier)) == 0) { interfacePriv->netdev_callback_registered = TRUE; } else { unifi_warning(priv, "Failed to register netdevice notifier : %d %p\n", rc, dev); }#endif /* CSR_SUPPORT_WEXT */ #ifdef CSR_WIFI_SPLIT_PATCH /* set it to some invalid value */ priv->pending_mode_set.common.destination = 0xaaaa;#endif return priv;} /* uf_alloc_netdevice() */ /* *--------------------------------------------------------------------------- * uf_alloc_netdevice_for_other_interfaces * * Allocate memory for the net_device and device private structs * for this interface. * Fill in the fields, but don't register the interface yet. * We need to configure the UniFi first. * * Arguments: * interfaceTag Interface number. * sdio_dev Pointer to SDIO context handle to use for all * SDIO ops. * bus_id A small number indicating the SDIO card position on the * bus. Typically this is the slot number, e.g. 0, 1 etc. * Valid values are 0 to MAX_UNIFI_DEVS-1. * * Returns: * Pointer to device private struct. * * Notes: * The device private structure contains the interfaceTag and pointer to the unifi_priv * structure created allocated by net_device od interface0. * The net_device and device private structs are allocated together * and should be freed by freeing the net_device pointer. * --------------------------------------------------------------------------- */u8uf_alloc_netdevice_for_other_interfaces(unifi_priv_t *priv, u16 interfaceTag){ struct net_device *dev; netInterface_priv_t *interfacePriv; /* * Allocate netdevice struct, assign name template and * setup as an ethernet device. * The net_device and private structs are zeroed. Ether_setup() then * sets up ethernet handlers and values. * The RedHat 9 redhat-config-network tool doesn't recognise wlan* devices, * so use "eth*" (like other wireless extns drivers). */ dev = alloc_etherdev_mq(sizeof(netInterface_priv_t), 1); if (dev == NULL) { return FALSE; } if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) { unifi_error(priv, "uf_alloc_netdevice_for_other_interfaces bad interfaceTag\n"); return FALSE; } /* Set up back pointer from priv to netdev */ interfacePriv = (netInterface_priv_t *)netdev_priv(dev); interfacePriv->privPtr = priv; interfacePriv->InterfaceTag = interfaceTag; priv->netdev[interfaceTag] = dev; priv->interfacePriv[interfacePriv->InterfaceTag] = interfacePriv; /* reset the connected state for the interface */ interfacePriv->connected = UnifiConnectedUnknown; /* -1 unknown, 0 no, 1 yes */ INIT_LIST_HEAD(&interfacePriv->rx_uncontrolled_list); INIT_LIST_HEAD(&interfacePriv->rx_controlled_list); /* Setup / override net_device fields */ dev->netdev_ops = &uf_netdev_ops; #ifdef CSR_SUPPORT_WEXT dev->wireless_handlers = &unifi_iw_handler_def;#if IW_HANDLER_VERSION < 6 dev->get_wireless_stats = unifi_get_wireless_stats;#endif /* IW_HANDLER_VERSION */#endif /* CSR_SUPPORT_WEXT */ return TRUE;} /* uf_alloc_netdevice() */ /* * --------------------------------------------------------------------------- * uf_free_netdevice * * Unregister the network device and free the memory allocated for it. * NB This includes the memory for the priv struct. * * Arguments: * priv Device private pointer. * * Returns: * None. * --------------------------------------------------------------------------- */intuf_free_netdevice(unifi_priv_t *priv){ int i; unsigned long flags; func_enter(); unifi_trace(priv, UDBG1, "uf_free_netdevice\n"); if (!priv) { return -EINVAL; } /* * Free any buffers used for holding firmware */ uf_release_firmware_files(priv); #if (defined CSR_SUPPORT_SME) && (defined CSR_SUPPORT_WEXT) if (priv->connection_config.mlmeAssociateReqInformationElements) { kfree(priv->connection_config.mlmeAssociateReqInformationElements); } priv->connection_config.mlmeAssociateReqInformationElements = NULL; priv->connection_config.mlmeAssociateReqInformationElementsLength = 0; Lines 1–500 of 3375. Load more
/* * --------------------------------------------------------------------------- * FILE: netdev.c * * PURPOSE: * This file provides the upper edge interface to the linux netdevice * and wireless extensions. * It is part of the porting exercise. * * Copyright (C) 2005-2010 by Cambridge Silicon Radio Ltd. * * Refer to LICENSE.txt included with this source code for details on * the license terms. * * --------------------------------------------------------------------------- */ /* * Porting Notes: * This file implements the data plane of the UniFi linux driver. * * All the Tx packets are passed to the HIP core lib, using the * unifi_send_signal() API. For EAPOL packets use the MLME-EAPOL.req * signal, for all other use the MLME-UNITDATA.req. The unifi_send_signal() * expects the wire-formatted (packed) signal. For convenience, in the OS * layer we only use the native (unpacked) signal structures. The HIP core lib * provides the write_pack() helper function to convert to the packed signal. * The packet is stored in the bulk data of the signal. We do not need to * allocate new memory to store the packet, because unifi_net_data_malloc() * is implemented to return a skb, which is the format of packet in Linux. * The HIP core lib frees the bulk data buffers, so we do not need to do * this in the OS layer. * * All the Rx packets are MLME-UNITDATA.ind signals, passed by the HIP core lib * in unifi_receive_event(). We do not need to allocate an skb and copy the * received packet because the HIP core lib has stored in memory allocated by * unifi_net_data_malloc(). Also, we can perform the 802.11 to Ethernet * translation in-place because we allocate the extra memory allocated in * unifi_net_data_malloc(). * * If possible, the porting exercise should appropriately implement * unifi_net_data_malloc() and unifi_net_data_free() to save copies between * network and driver buffers. */ #include <linux/types.h> #include <linux/etherdevice.h> #include <linux/mutex.h> #include <linux/semaphore.h> #include <linux/version.h> #include <linux/vmalloc.h> #include "csr_wifi_hip_unifi.h" #include "csr_wifi_hip_conversions.h" #include "unifi_priv.h" #include <net/pkt_sched.h> /* Wext handler is suported only if CSR_SUPPORT_WEXT is defined */ #ifdef CSR_SUPPORT_WEXT extern struct iw_handler_def unifi_iw_handler_def; #endif /* CSR_SUPPORT_WEXT */ static void check_ba_frame_age_timeout( unifi_priv_t *priv, netInterface_priv_t *interfacePriv, ba_session_rx_struct *ba_session); static void process_ba_frame(unifi_priv_t *priv, netInterface_priv_t *interfacePriv, ba_session_rx_struct *ba_session, frame_desc_struct *frame_desc); static void process_ba_complete(unifi_priv_t *priv, netInterface_priv_t *interfacePriv); static void process_ma_packet_error_ind(unifi_priv_t *priv, CSR_SIGNAL *signal, bulk_data_param_t *bulkdata); static void process_amsdu(unifi_priv_t *priv, CSR_SIGNAL *signal, bulk_data_param_t *bulkdata); static int uf_net_open(struct net_device *dev); static int uf_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int uf_net_stop(struct net_device *dev); static struct net_device_stats *uf_net_get_stats(struct net_device *dev); static u16 uf_net_select_queue(struct net_device *dev, struct sk_buff *skb); static netdev_tx_t uf_net_xmit(struct sk_buff *skb, struct net_device *dev); static void uf_set_multicast_list(struct net_device *dev); typedef int (*tx_signal_handler)(unifi_priv_t *priv, struct sk_buff *skb, const struct ethhdr *ehdr, CSR_PRIORITY priority); #ifdef CONFIG_NET_SCHED /* * Queueing Discipline Interface * Only used if kernel is configured with CONFIG_NET_SCHED */ /* * The driver uses the qdisc interface to buffer and control all * outgoing traffic. We create a root qdisc, register our qdisc operations * and later we create two subsiduary pfifo queues for the uncontrolled * and controlled ports. * * The network stack delivers all outgoing packets in our enqueue handler. * There, we classify the packet and decide whether to store it or drop it * (if the controlled port state is set to "discard"). * If the packet is enqueued, the network stack call our dequeue handler. * There, we decide whether we can send the packet, delay it or drop it * (the controlled port configuration might have changed meanwhile). * If a packet is dequeued, then the network stack calls our hard_start_xmit * handler where finally we send the packet. * * If the hard_start_xmit handler fails to send the packet, we return * NETDEV_TX_BUSY and the network stack call our requeue handler where * we put the packet back in the same queue in came from. * */ struct uf_sched_data { /* Traffic Classifier TBD */ struct tcf_proto *filter_list; /* Our two queues */ struct Qdisc *queues[UNIFI_TRAFFIC_Q_MAX]; }; struct uf_tx_packet_data { /* Queue the packet is stored in */ unifi_TrafficQueue queue; /* QoS Priority determined when enqueing packet */ CSR_PRIORITY priority; /* Debug */ unsigned long host_tag; }; #endif /* CONFIG_NET_SCHED */ static const struct net_device_ops uf_netdev_ops = { .ndo_open = uf_net_open, .ndo_stop = uf_net_stop, .ndo_start_xmit = uf_net_xmit, .ndo_do_ioctl = uf_net_ioctl, .ndo_get_stats = uf_net_get_stats, /* called by /proc/net/dev */ .ndo_set_rx_mode = uf_set_multicast_list, .ndo_select_queue = uf_net_select_queue, }; static u8 oui_rfc1042[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 }; static u8 oui_8021h[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 }; /* Callback for event logging to blocking clients */ static void netdev_mlme_event_handler(ul_client_t *client, const u8 *sig_packed, int sig_len, const bulk_data_param_t *bulkdata, int dir); #ifdef CSR_SUPPORT_WEXT /* Declare netdev_notifier block which will contain the state change * handler callback function */ static struct notifier_block uf_netdev_notifier; #endif /* * --------------------------------------------------------------------------- * uf_alloc_netdevice * * Allocate memory for the net_device and device private structs * for this interface. * Fill in the fields, but don't register the interface yet. * We need to configure the UniFi first. * * Arguments: * sdio_dev Pointer to SDIO context handle to use for all * SDIO ops. * bus_id A small number indicating the SDIO card position on the * bus. Typically this is the slot number, e.g. 0, 1 etc. * Valid values are 0 to MAX_UNIFI_DEVS-1. * * Returns: * Pointer to device private struct. * * Notes: * The net_device and device private structs are allocated together * and should be freed by freeing the net_device pointer. * --------------------------------------------------------------------------- */ unifi_priv_t * uf_alloc_netdevice(CsrSdioFunction *sdio_dev, int bus_id) { struct net_device *dev; unifi_priv_t *priv; netInterface_priv_t *interfacePriv; #ifdef CSR_SUPPORT_WEXT int rc; #endif unsigned char i; /* loop index */ /* * Allocate netdevice struct, assign name template and * setup as an ethernet device. * The net_device and private structs are zeroed. Ether_setup() then * sets up ethernet handlers and values. * The RedHat 9 redhat-config-network tool doesn't recognise wlan* devices, * so use "eth*" (like other wireless extns drivers). */ dev = alloc_etherdev_mq(sizeof(unifi_priv_t) + sizeof(netInterface_priv_t), UNIFI_TRAFFIC_Q_MAX); if (dev == NULL) { return NULL; } /* Set up back pointer from priv to netdev */ interfacePriv = (netInterface_priv_t *)netdev_priv(dev); priv = (unifi_priv_t *)(interfacePriv + 1); interfacePriv->privPtr = priv; interfacePriv->InterfaceTag = 0; /* Initialize all supported netdev interface to be NULL */ for(i=0; i<CSR_WIFI_NUM_INTERFACES; i++) { priv->netdev[i] = NULL; priv->interfacePriv[i] = NULL; } priv->netdev[0] = dev; priv->interfacePriv[0] = interfacePriv; /* Setup / override net_device fields */ dev->netdev_ops = &uf_netdev_ops; #ifdef CSR_SUPPORT_WEXT dev->wireless_handlers = &unifi_iw_handler_def; #if IW_HANDLER_VERSION < 6 dev->get_wireless_stats = unifi_get_wireless_stats; #endif /* IW_HANDLER_VERSION */ #endif /* CSR_SUPPORT_WEXT */ /* This gives us enough headroom to add the 802.11 header */ dev->needed_headroom = 32; /* Use bus_id as instance number */ priv->instance = bus_id; /* Store SDIO pointer to pass in the core */ priv->sdio = sdio_dev; sdio_dev->driverData = (void*)priv; /* Consider UniFi to be uninitialised */ priv->init_progress = UNIFI_INIT_NONE; priv->prev_queue = 0; /* * Initialise the clients structure array. * We do not need protection around ul_init_clients() because * the character device can not be used until uf_alloc_netdevice() * returns and Unifi_instances[bus_id]=priv is set, since unifi_open() * will return -ENODEV. */ ul_init_clients(priv); /* * Register a new ul client to send the multicast list signals. * Note: priv->instance must be set before calling this. */ priv->netdev_client = ul_register_client(priv, 0, netdev_mlme_event_handler); if (priv->netdev_client == NULL) { unifi_error(priv, "Failed to register a unifi client for background netdev processing\n"); free_netdev(priv->netdev[0]); return NULL; } unifi_trace(priv, UDBG2, "Netdev %p client (id:%d s:0x%X) is registered\n", dev, priv->netdev_client->client_id, priv->netdev_client->sender_id); priv->sta_wmm_capabilities = 0; #if (defined(CSR_WIFI_SECURITY_WAPI_ENABLE) && defined(CSR_SUPPORT_SME)) priv->wapi_multicast_filter = 0; priv->wapi_unicast_filter = 0; priv->wapi_unicast_queued_pkt_filter = 0; #ifdef CSR_WIFI_SECURITY_WAPI_QOSCTRL_MIC_WORKAROUND priv->isWapiConnection = FALSE; #endif #endif /* Enable all queues by default */ interfacePriv->queueEnabled[0] = 1; interfacePriv->queueEnabled[1] = 1; interfacePriv->queueEnabled[2] = 1; interfacePriv->queueEnabled[3] = 1; #ifdef CSR_SUPPORT_SME priv->allPeerDozing = 0; #endif /* * Initialise the OS private struct. */ /* * Instead of deciding in advance to use 11bg or 11a, we could do a more * clever scan on both radios. */ if (use_5g) { priv->if_index = CSR_INDEX_5G; unifi_info(priv, "Using the 802.11a radio\n"); } else { priv->if_index = CSR_INDEX_2G4; } /* Initialise bh thread structure */ priv->bh_thread.thread_task = NULL; priv->bh_thread.block_thread = 1; init_waitqueue_head(&priv->bh_thread.wakeup_q); priv->bh_thread.wakeup_flag = 0; sprintf(priv->bh_thread.name, "uf_bh_thread"); /* reset the connected state for the interface */ interfacePriv->connected = UnifiConnectedUnknown; /* -1 unknown, 0 no, 1 yes */ #ifdef USE_DRIVER_LOCK sema_init(&priv->lock, 1); #endif /* USE_DRIVER_LOCK */ spin_lock_init(&priv->send_signal_lock); spin_lock_init(&priv->m4_lock); sema_init(&priv->ba_mutex, 1); #if (defined(CSR_WIFI_SECURITY_WAPI_ENABLE) && defined(CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION)) spin_lock_init(&priv->wapi_lock); #endif #ifdef CSR_SUPPORT_SME spin_lock_init(&priv->staRecord_lock); spin_lock_init(&priv->tx_q_lock); #endif /* Create the Traffic Analysis workqueue */ priv->unifi_workqueue = create_singlethread_workqueue("unifi_workq"); if (priv->unifi_workqueue == NULL) { /* Deregister priv->netdev_client */ ul_deregister_client(priv->netdev_client); free_netdev(priv->netdev[0]); return NULL; } #ifdef CSR_SUPPORT_SME /* Create the Multicast Addresses list work structure */ INIT_WORK(&priv->multicast_list_task, uf_multicast_list_wq); /* Create m4 buffering work structure */ INIT_WORK(&interfacePriv->send_m4_ready_task, uf_send_m4_ready_wq); #if (defined(CSR_WIFI_SECURITY_WAPI_ENABLE) && defined(CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION)) /* Create work structure to buffer the WAPI data packets to be sent to SME for encryption */ INIT_WORK(&interfacePriv->send_pkt_to_encrypt, uf_send_pkt_to_encrypt); #endif #endif priv->ref_count = 1; priv->amp_client = NULL; priv->coredump_mode = 0; priv->ptest_mode = 0; priv->wol_suspend = FALSE; INIT_LIST_HEAD(&interfacePriv->rx_uncontrolled_list); INIT_LIST_HEAD(&interfacePriv->rx_controlled_list); sema_init(&priv->rx_q_sem, 1); #ifdef CSR_SUPPORT_WEXT interfacePriv->netdev_callback_registered = FALSE; interfacePriv->wait_netdev_change = FALSE; /* Register callback for netdevice state changes */ if ((rc = register_netdevice_notifier(&uf_netdev_notifier)) == 0) { interfacePriv->netdev_callback_registered = TRUE; } else { unifi_warning(priv, "Failed to register netdevice notifier : %d %p\n", rc, dev); } #endif /* CSR_SUPPORT_WEXT */ #ifdef CSR_WIFI_SPLIT_PATCH /* set it to some invalid value */ priv->pending_mode_set.common.destination = 0xaaaa; #endif return priv; } /* uf_alloc_netdevice() */ /* *--------------------------------------------------------------------------- * uf_alloc_netdevice_for_other_interfaces * * Allocate memory for the net_device and device private structs * for this interface. * Fill in the fields, but don't register the interface yet. * We need to configure the UniFi first. * * Arguments: * interfaceTag Interface number. * sdio_dev Pointer to SDIO context handle to use for all * SDIO ops. * bus_id A small number indicating the SDIO card position on the * bus. Typically this is the slot number, e.g. 0, 1 etc. * Valid values are 0 to MAX_UNIFI_DEVS-1. * * Returns: * Pointer to device private struct. * * Notes: * The device private structure contains the interfaceTag and pointer to the unifi_priv * structure created allocated by net_device od interface0. * The net_device and device private structs are allocated together * and should be freed by freeing the net_device pointer. * --------------------------------------------------------------------------- */ u8 uf_alloc_netdevice_for_other_interfaces(unifi_priv_t *priv, u16 interfaceTag) { struct net_device *dev; netInterface_priv_t *interfacePriv; /* * Allocate netdevice struct, assign name template and * setup as an ethernet device. * The net_device and private structs are zeroed. Ether_setup() then * sets up ethernet handlers and values. * The RedHat 9 redhat-config-network tool doesn't recognise wlan* devices, * so use "eth*" (like other wireless extns drivers). */ dev = alloc_etherdev_mq(sizeof(netInterface_priv_t), 1); if (dev == NULL) { return FALSE; } if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) { unifi_error(priv, "uf_alloc_netdevice_for_other_interfaces bad interfaceTag\n"); return FALSE; } /* Set up back pointer from priv to netdev */ interfacePriv = (netInterface_priv_t *)netdev_priv(dev); interfacePriv->privPtr = priv; interfacePriv->InterfaceTag = interfaceTag; priv->netdev[interfaceTag] = dev; priv->interfacePriv[interfacePriv->InterfaceTag] = interfacePriv; /* reset the connected state for the interface */ interfacePriv->connected = UnifiConnectedUnknown; /* -1 unknown, 0 no, 1 yes */ INIT_LIST_HEAD(&interfacePriv->rx_uncontrolled_list); INIT_LIST_HEAD(&interfacePriv->rx_controlled_list); /* Setup / override net_device fields */ dev->netdev_ops = &uf_netdev_ops; #ifdef CSR_SUPPORT_WEXT dev->wireless_handlers = &unifi_iw_handler_def; #if IW_HANDLER_VERSION < 6 dev->get_wireless_stats = unifi_get_wireless_stats; #endif /* IW_HANDLER_VERSION */ #endif /* CSR_SUPPORT_WEXT */ return TRUE; } /* uf_alloc_netdevice() */ /* * --------------------------------------------------------------------------- * uf_free_netdevice * * Unregister the network device and free the memory allocated for it. * NB This includes the memory for the priv struct. * * Arguments: * priv Device private pointer. * * Returns: * None. * --------------------------------------------------------------------------- */ int uf_free_netdevice(unifi_priv_t *priv) { int i; unsigned long flags; func_enter(); unifi_trace(priv, UDBG1, "uf_free_netdevice\n"); if (!priv) { return -EINVAL; } /* * Free any buffers used for holding firmware */ uf_release_firmware_files(priv); #if (defined CSR_SUPPORT_SME) && (defined CSR_SUPPORT_WEXT) if (priv->connection_config.mlmeAssociateReqInformationElements) { kfree(priv->connection_config.mlmeAssociateReqInformationElements); } priv->connection_config.mlmeAssociateReqInformationElements = NULL; priv->connection_config.mlmeAssociateReqInformationElementsLength = 0;