📄 main.c
字号:
/** * This file contains the major functions in WLAN * driver. It includes init, exit, open, close and main * thread etc.. */#include <linux/moduleparam.h>#include <linux/delay.h>#include <linux/freezer.h>#include <linux/etherdevice.h>#include <linux/netdevice.h>#include <linux/if_arp.h>#include <linux/kthread.h>#include <net/iw_handler.h>#include <net/ieee80211.h>#include "host.h"#include "decl.h"#include "dev.h"#include "wext.h"#include "debugfs.h"#include "assoc.h"#include "join.h"#define DRIVER_RELEASE_VERSION "323.p0"const char libertas_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION#ifdef DEBUG "-dbg"#endif "";/* Module parameters */unsigned int libertas_debug = 0;module_param(libertas_debug, int, 0644);EXPORT_SYMBOL_GPL(libertas_debug);#define WLAN_TX_PWR_DEFAULT 20 /*100mW */#define WLAN_TX_PWR_US_DEFAULT 20 /*100mW */#define WLAN_TX_PWR_JP_DEFAULT 16 /*50mW */#define WLAN_TX_PWR_FR_DEFAULT 20 /*100mW */#define WLAN_TX_PWR_EMEA_DEFAULT 20 /*100mW *//* Format { channel, frequency (MHz), maxtxpower } *//* band: 'B/G', region: USA FCC/Canada IC */static struct chan_freq_power channel_freq_power_US_BG[] = { {1, 2412, WLAN_TX_PWR_US_DEFAULT}, {2, 2417, WLAN_TX_PWR_US_DEFAULT}, {3, 2422, WLAN_TX_PWR_US_DEFAULT}, {4, 2427, WLAN_TX_PWR_US_DEFAULT}, {5, 2432, WLAN_TX_PWR_US_DEFAULT}, {6, 2437, WLAN_TX_PWR_US_DEFAULT}, {7, 2442, WLAN_TX_PWR_US_DEFAULT}, {8, 2447, WLAN_TX_PWR_US_DEFAULT}, {9, 2452, WLAN_TX_PWR_US_DEFAULT}, {10, 2457, WLAN_TX_PWR_US_DEFAULT}, {11, 2462, WLAN_TX_PWR_US_DEFAULT}};/* band: 'B/G', region: Europe ETSI */static struct chan_freq_power channel_freq_power_EU_BG[] = { {1, 2412, WLAN_TX_PWR_EMEA_DEFAULT}, {2, 2417, WLAN_TX_PWR_EMEA_DEFAULT}, {3, 2422, WLAN_TX_PWR_EMEA_DEFAULT}, {4, 2427, WLAN_TX_PWR_EMEA_DEFAULT}, {5, 2432, WLAN_TX_PWR_EMEA_DEFAULT}, {6, 2437, WLAN_TX_PWR_EMEA_DEFAULT}, {7, 2442, WLAN_TX_PWR_EMEA_DEFAULT}, {8, 2447, WLAN_TX_PWR_EMEA_DEFAULT}, {9, 2452, WLAN_TX_PWR_EMEA_DEFAULT}, {10, 2457, WLAN_TX_PWR_EMEA_DEFAULT}, {11, 2462, WLAN_TX_PWR_EMEA_DEFAULT}, {12, 2467, WLAN_TX_PWR_EMEA_DEFAULT}, {13, 2472, WLAN_TX_PWR_EMEA_DEFAULT}};/* band: 'B/G', region: Spain */static struct chan_freq_power channel_freq_power_SPN_BG[] = { {10, 2457, WLAN_TX_PWR_DEFAULT}, {11, 2462, WLAN_TX_PWR_DEFAULT}};/* band: 'B/G', region: France */static struct chan_freq_power channel_freq_power_FR_BG[] = { {10, 2457, WLAN_TX_PWR_FR_DEFAULT}, {11, 2462, WLAN_TX_PWR_FR_DEFAULT}, {12, 2467, WLAN_TX_PWR_FR_DEFAULT}, {13, 2472, WLAN_TX_PWR_FR_DEFAULT}};/* band: 'B/G', region: Japan */static struct chan_freq_power channel_freq_power_JPN_BG[] = { {1, 2412, WLAN_TX_PWR_JP_DEFAULT}, {2, 2417, WLAN_TX_PWR_JP_DEFAULT}, {3, 2422, WLAN_TX_PWR_JP_DEFAULT}, {4, 2427, WLAN_TX_PWR_JP_DEFAULT}, {5, 2432, WLAN_TX_PWR_JP_DEFAULT}, {6, 2437, WLAN_TX_PWR_JP_DEFAULT}, {7, 2442, WLAN_TX_PWR_JP_DEFAULT}, {8, 2447, WLAN_TX_PWR_JP_DEFAULT}, {9, 2452, WLAN_TX_PWR_JP_DEFAULT}, {10, 2457, WLAN_TX_PWR_JP_DEFAULT}, {11, 2462, WLAN_TX_PWR_JP_DEFAULT}, {12, 2467, WLAN_TX_PWR_JP_DEFAULT}, {13, 2472, WLAN_TX_PWR_JP_DEFAULT}, {14, 2484, WLAN_TX_PWR_JP_DEFAULT}};/** * the structure for channel, frequency and power */struct region_cfp_table { u8 region; struct chan_freq_power *cfp_BG; int cfp_no_BG;};/** * the structure for the mapping between region and CFP */static struct region_cfp_table region_cfp_table[] = { {0x10, /*US FCC */ channel_freq_power_US_BG, ARRAY_SIZE(channel_freq_power_US_BG), } , {0x20, /*CANADA IC */ channel_freq_power_US_BG, ARRAY_SIZE(channel_freq_power_US_BG), } , {0x30, /*EU*/ channel_freq_power_EU_BG, ARRAY_SIZE(channel_freq_power_EU_BG), } , {0x31, /*SPAIN*/ channel_freq_power_SPN_BG, ARRAY_SIZE(channel_freq_power_SPN_BG), } , {0x32, /*FRANCE*/ channel_freq_power_FR_BG, ARRAY_SIZE(channel_freq_power_FR_BG), } , {0x40, /*JAPAN*/ channel_freq_power_JPN_BG, ARRAY_SIZE(channel_freq_power_JPN_BG), } ,/*Add new region here */};/** * the table to keep region code */u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE] = { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 };/** * 802.11b/g supported bitrates (in 500Kb/s units) */u8 libertas_bg_rates[MAX_RATES] = { 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,0x00, 0x00 };/** * FW rate table. FW refers to rates by their index in this table, not by the * rate value itself. Values of 0x00 are * reserved positions. */static u8 fw_data_rates[MAX_RATES] = { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00};/** * @brief use index to get the data rate * * @param idx The index of data rate * @return data rate or 0 */u32 libertas_fw_index_to_data_rate(u8 idx){ if (idx >= sizeof(fw_data_rates)) idx = 0; return fw_data_rates[idx];}/** * @brief use rate to get the index * * @param rate data rate * @return index or 0 */u8 libertas_data_rate_to_fw_index(u32 rate){ u8 i; if (!rate) return 0; for (i = 0; i < sizeof(fw_data_rates); i++) { if (rate == fw_data_rates[i]) return i; } return 0;}/** * Attributes exported through sysfs *//** * @brief Get function for sysfs attribute anycast_mask */static ssize_t libertas_anycast_get(struct device * dev, struct device_attribute *attr, char * buf){ struct cmd_ds_mesh_access mesh_access; memset(&mesh_access, 0, sizeof(mesh_access)); libertas_prepare_and_send_command(to_net_dev(dev)->priv, CMD_MESH_ACCESS, CMD_ACT_MESH_GET_ANYCAST, CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access); return snprintf(buf, 12, "0x%X\n", le32_to_cpu(mesh_access.data[0]));}/** * @brief Set function for sysfs attribute anycast_mask */static ssize_t libertas_anycast_set(struct device * dev, struct device_attribute *attr, const char * buf, size_t count){ struct cmd_ds_mesh_access mesh_access; uint32_t datum; memset(&mesh_access, 0, sizeof(mesh_access)); sscanf(buf, "%x", &datum); mesh_access.data[0] = cpu_to_le32(datum); libertas_prepare_and_send_command((to_net_dev(dev))->priv, CMD_MESH_ACCESS, CMD_ACT_MESH_SET_ANYCAST, CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access); return strlen(buf);}int libertas_add_rtap(wlan_private *priv);void libertas_remove_rtap(wlan_private *priv);/** * Get function for sysfs attribute rtap */static ssize_t libertas_rtap_get(struct device * dev, struct device_attribute *attr, char * buf){ wlan_private *priv = (wlan_private *) (to_net_dev(dev))->priv; wlan_adapter *adapter = priv->adapter; return snprintf(buf, 5, "0x%X\n", adapter->monitormode);}/** * Set function for sysfs attribute rtap */static ssize_t libertas_rtap_set(struct device * dev, struct device_attribute *attr, const char * buf, size_t count){ int monitor_mode; wlan_private *priv = (wlan_private *) (to_net_dev(dev))->priv; wlan_adapter *adapter = priv->adapter; sscanf(buf, "%x", &monitor_mode); if (monitor_mode != WLAN_MONITOR_OFF) { if(adapter->monitormode == monitor_mode) return strlen(buf); if (adapter->monitormode == WLAN_MONITOR_OFF) { if (adapter->mode == IW_MODE_INFRA) libertas_send_deauthentication(priv); else if (adapter->mode == IW_MODE_ADHOC) libertas_stop_adhoc_network(priv); libertas_add_rtap(priv); } adapter->monitormode = monitor_mode; } else { if(adapter->monitormode == WLAN_MONITOR_OFF) return strlen(buf); adapter->monitormode = WLAN_MONITOR_OFF; libertas_remove_rtap(priv); netif_wake_queue(priv->dev); netif_wake_queue(priv->mesh_dev); } libertas_prepare_and_send_command(priv, CMD_802_11_MONITOR_MODE, CMD_ACT_SET, CMD_OPTION_WAITFORRSP, 0, &adapter->monitormode); return strlen(buf);}/** * libertas_rtap attribute to be exported per mshX interface * through sysfs (/sys/class/net/mshX/libertas-rtap) */static DEVICE_ATTR(libertas_rtap, 0644, libertas_rtap_get, libertas_rtap_set );/** * anycast_mask attribute to be exported per mshX interface * through sysfs (/sys/class/net/mshX/anycast_mask) */static DEVICE_ATTR(anycast_mask, 0644, libertas_anycast_get, libertas_anycast_set);static ssize_t libertas_autostart_enabled_get(struct device * dev, struct device_attribute *attr, char * buf){ struct cmd_ds_mesh_access mesh_access; memset(&mesh_access, 0, sizeof(mesh_access)); libertas_prepare_and_send_command(to_net_dev(dev)->priv, CMD_MESH_ACCESS, CMD_ACT_MESH_GET_AUTOSTART_ENABLED, CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access); return sprintf(buf, "%d\n", le32_to_cpu(mesh_access.data[0]));}static ssize_t libertas_autostart_enabled_set(struct device * dev, struct device_attribute *attr, const char * buf, size_t count){ struct cmd_ds_mesh_access mesh_access; uint32_t datum; wlan_private * priv = (to_net_dev(dev))->priv; int ret; memset(&mesh_access, 0, sizeof(mesh_access)); sscanf(buf, "%d", &datum); mesh_access.data[0] = cpu_to_le32(datum); ret = libertas_prepare_and_send_command(priv, CMD_MESH_ACCESS, CMD_ACT_MESH_SET_AUTOSTART_ENABLED, CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access); if (ret == 0) priv->mesh_autostart_enabled = datum ? 1 : 0; return strlen(buf);}static DEVICE_ATTR(autostart_enabled, 0644, libertas_autostart_enabled_get, libertas_autostart_enabled_set);static struct attribute *libertas_mesh_sysfs_entries[] = { &dev_attr_anycast_mask.attr, &dev_attr_autostart_enabled.attr, NULL,};static struct attribute_group libertas_mesh_attr_group = { .attrs = libertas_mesh_sysfs_entries,};/** * @brief Check if the device can be open and wait if necessary. * * @param dev A pointer to net_device structure * @return 0 * * For USB adapter, on some systems the device open handler will be * called before FW ready. Use the following flag check and wait * function to work around the issue. * */static int pre_open_check(struct net_device *dev){ wlan_private *priv = (wlan_private *) dev->priv; wlan_adapter *adapter = priv->adapter; int i = 0; while (!adapter->fw_ready && i < 20) { i++; msleep_interruptible(100); } if (!adapter->fw_ready) { lbs_pr_err("firmware not ready\n"); return -1; } return 0;}/** * @brief This function opens the device * * @param dev A pointer to net_device structure * @return 0 */static int libertas_dev_open(struct net_device *dev){ wlan_private *priv = (wlan_private *) dev->priv; wlan_adapter *adapter = priv->adapter; lbs_deb_enter(LBS_DEB_NET); priv->open = 1; if (adapter->connect_status == LIBERTAS_CONNECTED) { netif_carrier_on(priv->dev); if (priv->mesh_dev) netif_carrier_on(priv->mesh_dev); } else { netif_carrier_off(priv->dev); if (priv->mesh_dev) netif_carrier_off(priv->mesh_dev); } lbs_deb_leave(LBS_DEB_NET); return 0;}/** * @brief This function opens the mshX interface * * @param dev A pointer to net_device structure * @return 0 */static int libertas_mesh_open(struct net_device *dev){ wlan_private *priv = (wlan_private *) dev->priv ; if (pre_open_check(dev) == -1) return -1; priv->mesh_open = 1 ; netif_wake_queue(priv->mesh_dev); if (priv->infra_open == 0) return libertas_dev_open(priv->dev) ; return 0;}/** * @brief This function opens the ethX interface * * @param dev A pointer to net_device structure * @return 0 */static int libertas_open(struct net_device *dev){ wlan_private *priv = (wlan_private *) dev->priv ; if(pre_open_check(dev) == -1) return -1; priv->infra_open = 1 ; netif_wake_queue(priv->dev); if (priv->open == 0) return libertas_dev_open(priv->dev) ; return 0;}static int libertas_dev_close(struct net_device *dev){ wlan_private *priv = dev->priv; lbs_deb_enter(LBS_DEB_NET); netif_carrier_off(priv->dev); priv->open = 0; lbs_deb_leave(LBS_DEB_NET); return 0;}/** * @brief This function closes the mshX interface * * @param dev A pointer to net_device structure * @return 0 */static int libertas_mesh_close(struct net_device *dev){ wlan_private *priv = (wlan_private *) (dev->priv); priv->mesh_open = 0; netif_stop_queue(priv->mesh_dev); if (priv->infra_open == 0) return libertas_dev_close(dev); else return 0;}/** * @brief This function closes the ethX interface * * @param dev A pointer to net_device structure * @return 0 */static int libertas_close(struct net_device *dev){ wlan_private *priv = (wlan_private *) dev->priv; netif_stop_queue(dev); priv->infra_open = 0; if (priv->mesh_open == 0) return libertas_dev_close(dev); else return 0;}static int libertas_hard_start_xmit(struct sk_buff *skb, struct net_device *dev){ int ret = 0; wlan_private *priv = dev->priv; lbs_deb_enter(LBS_DEB_NET); if (priv->dnld_sent || priv->adapter->TxLockFlag) { priv->stats.tx_dropped++; goto done; } netif_stop_queue(priv->dev); if (priv->mesh_dev) netif_stop_queue(priv->mesh_dev); if (libertas_process_tx(priv, skb) == 0) dev->trans_start = jiffies;done: lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); return ret;}/** * @brief Mark mesh packets and handover them to libertas_hard_start_xmit * */static int libertas_mesh_pre_start_xmit(struct sk_buff *skb,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -