[NET]: Introduce and use print_mac() and DECLARE_MAC_BUF()
[deliverable/linux.git] / drivers / net / wireless / libertas / main.c
index b4e2cd19c3bce72981526eb6b2603f1929e4007e..5ead08312e1e48b4443ec9cd3fe830dc1288afdd 100644 (file)
@@ -21,8 +21,9 @@
 #include "wext.h"
 #include "debugfs.h"
 #include "assoc.h"
+#include "join.h"
 
-#define DRIVER_RELEASE_VERSION "322.p1"
+#define DRIVER_RELEASE_VERSION "323.p0"
 const char libertas_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION
 #ifdef  DEBUG
     "-dbg"
@@ -122,28 +123,28 @@ struct region_cfp_table {
 static struct region_cfp_table region_cfp_table[] = {
        {0x10,                  /*US FCC */
         channel_freq_power_US_BG,
-        sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power),
+        ARRAY_SIZE(channel_freq_power_US_BG),
         }
        ,
        {0x20,                  /*CANADA IC */
         channel_freq_power_US_BG,
-        sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power),
+        ARRAY_SIZE(channel_freq_power_US_BG),
         }
        ,
        {0x30, /*EU*/ channel_freq_power_EU_BG,
-        sizeof(channel_freq_power_EU_BG) / sizeof(struct chan_freq_power),
+        ARRAY_SIZE(channel_freq_power_EU_BG),
         }
        ,
        {0x31, /*SPAIN*/ channel_freq_power_SPN_BG,
-        sizeof(channel_freq_power_SPN_BG) / sizeof(struct chan_freq_power),
+        ARRAY_SIZE(channel_freq_power_SPN_BG),
         }
        ,
        {0x32, /*FRANCE*/ channel_freq_power_FR_BG,
-        sizeof(channel_freq_power_FR_BG) / sizeof(struct chan_freq_power),
+        ARRAY_SIZE(channel_freq_power_FR_BG),
         }
        ,
        {0x40, /*JAPAN*/ channel_freq_power_JPN_BG,
-        sizeof(channel_freq_power_JPN_BG) / sizeof(struct chan_freq_power),
+        ARRAY_SIZE(channel_freq_power_JPN_BG),
         }
        ,
 /*Add new region here */
@@ -246,12 +247,121 @@ static ssize_t libertas_anycast_set(struct device * dev,
        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.
  *
@@ -431,6 +541,10 @@ static int libertas_mesh_pre_start_xmit(struct sk_buff *skb,
        int ret;
 
        lbs_deb_enter(LBS_DEB_MESH);
+       if(priv->adapter->monitormode != WLAN_MONITOR_OFF) {
+               netif_stop_queue(dev);
+               return -EOPNOTSUPP;
+       }
 
        SET_MESH_FRAME(skb);
 
@@ -445,10 +559,16 @@ static int libertas_mesh_pre_start_xmit(struct sk_buff *skb,
  */
 static int libertas_pre_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
+       wlan_private *priv = dev->priv;
        int ret;
 
        lbs_deb_enter(LBS_DEB_NET);
 
+       if(priv->adapter->monitormode != WLAN_MONITOR_OFF) {
+               netif_stop_queue(dev);
+               return -EOPNOTSUPP;
+       }
+
        UNSET_MESH_FRAME(skb);
 
        ret = libertas_hard_start_xmit(skb, dev);
@@ -468,7 +588,7 @@ static void libertas_tx_timeout(struct net_device *dev)
        dev->trans_start = jiffies;
 
        if (priv->adapter->currenttxskb) {
-               if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
+               if (priv->adapter->monitormode != WLAN_MONITOR_OFF) {
                        /* If we are here, we have not received feedback from
                           the previous packet.  Assume TX_FAIL and move on. */
                        priv->adapter->eventcause = 0x01000000;
@@ -512,9 +632,9 @@ static int libertas_set_mac_address(struct net_device *dev, void *addr)
        memset(adapter->current_addr, 0, ETH_ALEN);
 
        /* dev->dev_addr is 8 bytes */
-       lbs_dbg_hex("dev->dev_addr:", dev->dev_addr, ETH_ALEN);
+       lbs_deb_hex(LBS_DEB_NET, "dev->dev_addr", dev->dev_addr, ETH_ALEN);
 
-       lbs_dbg_hex("addr:", phwaddr->sa_data, ETH_ALEN);
+       lbs_deb_hex(LBS_DEB_NET, "addr", phwaddr->sa_data, ETH_ALEN);
        memcpy(adapter->current_addr, phwaddr->sa_data, ETH_ALEN);
 
        ret = libertas_prepare_and_send_command(priv, CMD_802_11_MAC_ADDRESS,
@@ -527,7 +647,7 @@ static int libertas_set_mac_address(struct net_device *dev, void *addr)
                goto done;
        }
 
-       lbs_dbg_hex("adapter->macaddr:", adapter->current_addr, ETH_ALEN);
+       lbs_deb_hex(LBS_DEB_NET, "adapter->macaddr", adapter->current_addr, ETH_ALEN);
        memcpy(dev->dev_addr, adapter->current_addr, ETH_ALEN);
        if (priv->mesh_dev)
                memcpy(priv->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN);
@@ -557,6 +677,7 @@ static void libertas_set_multicast_list(struct net_device *dev)
        wlan_private *priv = dev->priv;
        wlan_adapter *adapter = priv->adapter;
        int oldpacketfilter;
+       DECLARE_MAC_BUF(mac);
 
        lbs_deb_enter(LBS_DEB_NET);
 
@@ -603,14 +724,9 @@ static void libertas_set_multicast_list(struct net_device *dev)
                                       dev->mc_count);
 
                                for (i = 0; i < dev->mc_count; i++) {
-                                       lbs_deb_net("Multicast address %d:"
-                                              MAC_FMT "\n", i,
-                                              adapter->multicastlist[i][0],
-                                              adapter->multicastlist[i][1],
-                                              adapter->multicastlist[i][2],
-                                              adapter->multicastlist[i][3],
-                                              adapter->multicastlist[i][4],
-                                              adapter->multicastlist[i][5]);
+                                       lbs_deb_net("Multicast address %d:%s\n",
+                                              i, print_mac(mac,
+                                              adapter->multicastlist[i]));
                                }
                                /* send multicast addresses to firmware */
                                libertas_prepare_and_send_command(priv,
@@ -648,6 +764,7 @@ static int libertas_thread(void *data)
 
        init_waitqueue_entry(&wait, current);
 
+       set_freezable();
        for (;;) {
                lbs_deb_thread( "main-thread 111: intcounter=%d "
                       "currenttxskb=%p dnld_sent=%d\n",
@@ -670,7 +787,6 @@ static int libertas_thread(void *data)
                } else
                        spin_unlock_irq(&adapter->driver_lock);
 
-
                lbs_deb_thread(
                       "main-thread 222 (waking up): intcounter=%d currenttxskb=%p "
                       "dnld_sent=%d\n", adapter->intcounter,
@@ -805,21 +921,14 @@ static int libertas_thread(void *data)
  *  @param priv    A pointer to wlan_private structure
  *  @return       0 or -1
  */
-static int wlan_setup_station_hw(wlan_private * priv)
+static int wlan_setup_firmware(wlan_private * priv)
 {
        int ret = -1;
        wlan_adapter *adapter = priv->adapter;
+       struct cmd_ds_mesh_access mesh_access;
 
        lbs_deb_enter(LBS_DEB_FW);
 
-       ret = priv->hw_prog_firmware(priv);
-
-       if (ret) {
-               lbs_deb_fw("bootloader in invalid state\n");
-               ret = -1;
-               goto done;
-       }
-
        /*
         * Read MAC address from HW
         */
@@ -845,14 +954,31 @@ static int wlan_setup_station_hw(wlan_private * priv)
                goto done;
        }
 
+       /* Disable mesh autostart */
+       if (priv->mesh_dev) {
+               memset(&mesh_access, 0, sizeof(mesh_access));
+               mesh_access.data[0] = cpu_to_le32(0);
+               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) {
+                       ret = -1;
+                       goto done;
+               }
+               priv->mesh_autostart_enabled = 0;
+       }
+
+       /* Set the boot2 version in firmware */
+       ret = libertas_prepare_and_send_command(priv, CMD_SET_BOOT2_VER,
+                                   0, CMD_OPTION_WAITFORRSP, 0, NULL);
+
        ret = 0;
 done:
        lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
        return ret;
 }
 
-static void command_timer_fn(unsigned long data);
-
 /**
  *  This function handles the timeout of command sending.
  *  It will re-send the same command again.
@@ -894,181 +1020,99 @@ static void command_timer_fn(unsigned long data)
        return;
 }
 
-static void libertas_free_adapter(wlan_private * priv)
+static int libertas_init_adapter(wlan_private * priv)
 {
        wlan_adapter *adapter = priv->adapter;
-
-       if (!adapter) {
-               lbs_deb_fw("why double free adapter?\n");
-               return;
-       }
-
-       lbs_deb_fw("free command buffer\n");
-       libertas_free_cmd_buffer(priv);
-
-       lbs_deb_fw("free command_timer\n");
-       del_timer(&adapter->command_timer);
-
-       lbs_deb_fw("free scan results table\n");
-       kfree(adapter->networks);
-       adapter->networks = NULL;
-
-       /* Free the adapter object itself */
-       lbs_deb_fw("free adapter\n");
-       kfree(adapter);
-       priv->adapter = NULL;
-}
-
-static int wlan_allocate_adapter(wlan_private * priv)
-{
        size_t bufsize;
-       wlan_adapter *adapter = priv->adapter;
+       int i, ret = 0;
 
        /* Allocate buffer to store the BSSID list */
        bufsize = MAX_NETWORK_COUNT * sizeof(struct bss_descriptor);
        adapter->networks = kzalloc(bufsize, GFP_KERNEL);
        if (!adapter->networks) {
                lbs_pr_err("Out of memory allocating beacons\n");
-               libertas_free_adapter(priv);
-               return -ENOMEM;
+               ret = -1;
+               goto out;
        }
 
-       /* Allocate the command buffers */
-       libertas_allocate_cmd_buffer(priv);
+       /* Initialize scan result lists */
+       INIT_LIST_HEAD(&adapter->network_free_list);
+       INIT_LIST_HEAD(&adapter->network_list);
+       for (i = 0; i < MAX_NETWORK_COUNT; i++) {
+               list_add_tail(&adapter->networks[i].list,
+                             &adapter->network_free_list);
+       }
 
-       memset(&adapter->libertas_ps_confirm_sleep, 0, sizeof(struct PS_CMD_ConfirmSleep));
        adapter->libertas_ps_confirm_sleep.seqnum = cpu_to_le16(++adapter->seqnum);
        adapter->libertas_ps_confirm_sleep.command =
            cpu_to_le16(CMD_802_11_PS_MODE);
        adapter->libertas_ps_confirm_sleep.size =
            cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep));
-       adapter->libertas_ps_confirm_sleep.result = 0;
        adapter->libertas_ps_confirm_sleep.action =
            cpu_to_le16(CMD_SUBCMD_SLEEP_CONFIRMED);
 
-       return 0;
-}
-
-static void wlan_init_adapter(wlan_private * priv)
-{
-       wlan_adapter *adapter = priv->adapter;
-       int i;
-
-       adapter->scanprobes = 0;
-
-       adapter->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR;
-       adapter->data_avg_factor = DEFAULT_DATA_AVG_FACTOR;
-
-       /* ATIM params */
-       adapter->atimwindow = 0;
-
-       adapter->connect_status = LIBERTAS_DISCONNECTED;
        memset(adapter->current_addr, 0xff, ETH_ALEN);
 
-       /* scan type */
-       adapter->scantype = CMD_SCAN_TYPE_ACTIVE;
-
-       /* scan mode */
-       adapter->scanmode = CMD_BSS_TYPE_ANY;
-
-       /* 802.11 specific */
-       adapter->secinfo.wep_enabled = 0;
-       for (i = 0; i < sizeof(adapter->wep_keys) / sizeof(adapter->wep_keys[0]);
-            i++)
-               memset(&adapter->wep_keys[i], 0, sizeof(struct enc_key));
-       adapter->wep_tx_keyidx = 0;
+       adapter->connect_status = LIBERTAS_DISCONNECTED;
        adapter->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
        adapter->mode = IW_MODE_INFRA;
-
-       adapter->pending_assoc_req = NULL;
-       adapter->in_progress_assoc_req = NULL;
-
-       /* Initialize scan result lists */
-       INIT_LIST_HEAD(&adapter->network_free_list);
-       INIT_LIST_HEAD(&adapter->network_list);
-       for (i = 0; i < MAX_NETWORK_COUNT; i++) {
-               list_add_tail(&adapter->networks[i].list,
-                             &adapter->network_free_list);
-       }
-
-       mutex_init(&adapter->lock);
-
-       adapter->prescan = 1;
-
-       memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams));
        adapter->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL;
-
-       /* PnP and power profile */
-       adapter->surpriseremoved = 0;
-
-       adapter->currentpacketfilter =
-           CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
-
+       adapter->currentpacketfilter = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
        adapter->radioon = RADIO_ON;
-       adapter->txantenna = RF_ANTENNA_2;
-       adapter->rxantenna = RF_ANTENNA_AUTO;
-
        adapter->auto_rate = 1;
-       adapter->cur_rate = 0;
-       adapter->adhoc_grate_enabled = 0;
-
-       adapter->beaconperiod = MRVDRV_BEACON_INTERVAL;
-
-       // set default capabilities
        adapter->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
-
        adapter->psmode = WLAN802_11POWERMODECAM;
-       adapter->multipledtim = MRVDRV_DEFAULT_MULTIPLE_DTIM;
-
-       adapter->listeninterval = MRVDRV_DEFAULT_LISTEN_INTERVAL;
-
        adapter->psstate = PS_STATE_FULL_POWER;
-       adapter->needtowakeup = 0;
-       adapter->locallisteninterval = 0;       /* default value in firmware will be used */
 
-       adapter->intcounter = 0;
-
-       adapter->currenttxskb = NULL;
-       adapter->pkttxctrl = 0;
+       mutex_init(&adapter->lock);
 
        memset(&adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*));
        adapter->tx_queue_idx = 0;
        spin_lock_init(&adapter->txqueue_lock);
 
-       return;
-}
+       setup_timer(&adapter->command_timer, command_timer_fn,
+                   (unsigned long)priv);
 
-static int libertas_init_fw(wlan_private * priv)
-{
-       int ret = -1;
-       wlan_adapter *adapter = priv->adapter;
+       INIT_LIST_HEAD(&adapter->cmdfreeq);
+       INIT_LIST_HEAD(&adapter->cmdpendingq);
 
-       lbs_deb_enter(LBS_DEB_FW);
+       spin_lock_init(&adapter->driver_lock);
+       init_waitqueue_head(&adapter->cmd_pending);
+       adapter->nr_cmd_pending = 0;
 
-       /* Allocate adapter structure */
-       if ((ret = wlan_allocate_adapter(priv)) != 0)
-               goto done;
+       /* Allocate the command buffers */
+       if (libertas_allocate_cmd_buffer(priv)) {
+               lbs_pr_err("Out of memory allocating command buffers\n");
+               ret = -1;
+       }
 
-       /* init adapter structure */
-       wlan_init_adapter(priv);
+out:
+       return ret;
+}
 
-       /* init timer etc. */
-       setup_timer(&adapter->command_timer, command_timer_fn,
-                       (unsigned long)priv);
+static void libertas_free_adapter(wlan_private * priv)
+{
+       wlan_adapter *adapter = priv->adapter;
 
-       /* download fimrware etc. */
-       if ((ret = wlan_setup_station_hw(priv)) != 0) {
-               del_timer_sync(&adapter->command_timer);
-               goto done;
+       if (!adapter) {
+               lbs_deb_fw("why double free adapter?\n");
+               return;
        }
 
-       /* init 802.11d */
-       libertas_init_11d(priv);
+       lbs_deb_fw("free command buffer\n");
+       libertas_free_cmd_buffer(priv);
 
-       ret = 0;
-done:
-       lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
-       return ret;
+       lbs_deb_fw("free command_timer\n");
+       del_timer(&adapter->command_timer);
+
+       lbs_deb_fw("free scan results table\n");
+       kfree(adapter->networks);
+       adapter->networks = NULL;
+
+       /* Free the adapter object itself */
+       lbs_deb_fw("free adapter\n");
+       kfree(adapter);
+       priv->adapter = NULL;
 }
 
 /**
@@ -1088,7 +1132,7 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev)
        /* Allocate an Ethernet device and register it */
        if (!(dev = alloc_etherdev(sizeof(wlan_private)))) {
                lbs_pr_err("init ethX device failed\n");
-               return NULL;
+               goto done;
        }
        priv = dev->priv;
 
@@ -1098,12 +1142,16 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev)
                goto err_kzalloc;
        }
 
+       if (libertas_init_adapter(priv)) {
+               lbs_pr_err("failed to initialize adapter structure.\n");
+               goto err_init_adapter;
+       }
+
        priv->dev = dev;
        priv->card = card;
        priv->mesh_open = 0;
        priv->infra_open = 0;
-
-       SET_MODULE_OWNER(dev);
+       priv->hotplug_device = dmdev;
 
        /* Setup the OS Interface to our functions */
        dev->open = libertas_open;
@@ -1124,83 +1172,144 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev)
 
        SET_NETDEV_DEV(dev, dmdev);
 
-       INIT_LIST_HEAD(&priv->adapter->cmdfreeq);
-       INIT_LIST_HEAD(&priv->adapter->cmdpendingq);
+       priv->rtap_net_dev = NULL;
+       if (device_create_file(dmdev, &dev_attr_libertas_rtap))
+               goto err_init_adapter;
+
+       lbs_deb_thread("Starting main thread...\n");
+       init_waitqueue_head(&priv->waitq);
+       priv->main_thread = kthread_run(libertas_thread, dev, "libertas_main");
+       if (IS_ERR(priv->main_thread)) {
+               lbs_deb_thread("Error creating main thread.\n");
+               goto err_kthread_run;
+       }
+
+       priv->work_thread = create_singlethread_workqueue("libertas_worker");
+       INIT_DELAYED_WORK(&priv->assoc_work, libertas_association_worker);
+       INIT_DELAYED_WORK(&priv->scan_work, libertas_scan_worker);
+       INIT_WORK(&priv->sync_channel, libertas_sync_channel);
 
-       spin_lock_init(&priv->adapter->driver_lock);
-       init_waitqueue_head(&priv->adapter->cmd_pending);
-       priv->adapter->nr_cmd_pending = 0;
        goto done;
 
+err_kthread_run:
+       device_remove_file(dmdev, &dev_attr_libertas_rtap);
+
+err_init_adapter:
+       libertas_free_adapter(priv);
+
 err_kzalloc:
        free_netdev(dev);
        priv = NULL;
+
 done:
        lbs_deb_leave_args(LBS_DEB_NET, "priv %p", priv);
        return priv;
 }
 EXPORT_SYMBOL_GPL(libertas_add_card);
 
-int libertas_activate_card(wlan_private *priv)
+
+int libertas_remove_card(wlan_private *priv)
 {
+       wlan_adapter *adapter = priv->adapter;
        struct net_device *dev = priv->dev;
-       int ret = -1;
+       union iwreq_data wrqu;
 
        lbs_deb_enter(LBS_DEB_MAIN);
 
-       lbs_deb_thread("Starting main thread...\n");
-       init_waitqueue_head(&priv->waitq);
-       priv->main_thread = kthread_run(libertas_thread, dev, "libertas_main");
-       if (IS_ERR(priv->main_thread)) {
-               lbs_deb_thread("Error creating main thread.\n");
-               goto done;
-       }
+       libertas_remove_rtap(priv);
 
-       priv->assoc_thread =
-               create_singlethread_workqueue("libertas_assoc");
-       INIT_DELAYED_WORK(&priv->assoc_work, libertas_association_worker);
-       INIT_WORK(&priv->sync_channel, libertas_sync_channel);
+       dev = priv->dev;
+       device_remove_file(priv->hotplug_device, &dev_attr_libertas_rtap);
 
-       /*
-        * Register the device. Fillup the private data structure with
-        * relevant information from the card and request for the required
-        * IRQ.
-        */
-       if (priv->hw_register_dev(priv) < 0) {
-               lbs_pr_err("failed to register WLAN device\n");
-               goto err_registerdev;
-       }
+       cancel_delayed_work(&priv->scan_work);
+       cancel_delayed_work(&priv->assoc_work);
+       destroy_workqueue(priv->work_thread);
 
-       /* init FW and HW */
-       if (libertas_init_fw(priv)) {
-               lbs_pr_err("firmware init failed\n");
-               goto err_registerdev;
+       if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) {
+               adapter->psmode = WLAN802_11POWERMODECAM;
+               libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
        }
 
+       memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN);
+       wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+       wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
+
+       /* Stop the thread servicing the interrupts */
+       adapter->surpriseremoved = 1;
+       kthread_stop(priv->main_thread);
+
+       libertas_free_adapter(priv);
+
+       priv->dev = NULL;
+       free_netdev(dev);
+
+       lbs_deb_leave(LBS_DEB_MAIN);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(libertas_remove_card);
+
+
+int libertas_start_card(wlan_private *priv)
+{
+       struct net_device *dev = priv->dev;
+       int ret = -1;
+
+       lbs_deb_enter(LBS_DEB_MAIN);
+
+       /* poke the firmware */
+       ret = wlan_setup_firmware(priv);
+       if (ret)
+               goto done;
+
+       /* init 802.11d */
+       libertas_init_11d(priv);
+
        if (register_netdev(dev)) {
                lbs_pr_err("cannot register ethX device\n");
-               goto err_init_fw;
+               goto done;
        }
 
-       lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name);
-
        libertas_debugfs_init_one(priv, dev);
 
+       lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name);
+
        ret = 0;
-       goto done;
 
-err_init_fw:
-       priv->hw_unregister_dev(priv);
-err_registerdev:
-       destroy_workqueue(priv->assoc_thread);
-       /* Stop the thread servicing the interrupts */
-       wake_up_interruptible(&priv->waitq);
-       kthread_stop(priv->main_thread);
 done:
-       lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
+       lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(libertas_start_card);
+
+
+int libertas_stop_card(wlan_private *priv)
+{
+       struct net_device *dev = priv->dev;
+       int ret = -1;
+       struct cmd_ctrl_node *cmdnode;
+       unsigned long flags;
+
+       lbs_deb_enter(LBS_DEB_MAIN);
+
+       netif_stop_queue(priv->dev);
+       netif_carrier_off(priv->dev);
+
+       libertas_debugfs_remove_one(priv);
+
+       /* Flush pending command nodes */
+       spin_lock_irqsave(&priv->adapter->driver_lock, flags);
+       list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) {
+               cmdnode->cmdwaitqwoken = 1;
+               wake_up_interruptible(&cmdnode->cmdwait_q);
+       }
+       spin_unlock_irqrestore(&priv->adapter->driver_lock, flags);
+
+       unregister_netdev(dev);
+
+       lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
        return ret;
 }
-EXPORT_SYMBOL_GPL(libertas_activate_card);
+EXPORT_SYMBOL_GPL(libertas_stop_card);
 
 
 /**
@@ -1225,8 +1334,6 @@ int libertas_add_mesh(wlan_private *priv, struct device *dev)
        mesh_dev->priv = priv;
        priv->mesh_dev = mesh_dev;
 
-       SET_MODULE_OWNER(mesh_dev);
-
        mesh_dev->open = libertas_mesh_open;
        mesh_dev->hard_start_xmit = libertas_mesh_pre_start_xmit;
        mesh_dev->stop = libertas_mesh_close;
@@ -1250,7 +1357,7 @@ int libertas_add_mesh(wlan_private *priv, struct device *dev)
                goto err_free;
        }
 
-       ret = device_create_file(&(mesh_dev->dev), &dev_attr_anycast_mask);
+       ret = sysfs_create_group(&(mesh_dev->dev.kobj), &libertas_mesh_attr_group);
        if (ret)
                goto err_unregister;
 
@@ -1270,86 +1377,12 @@ done:
 }
 EXPORT_SYMBOL_GPL(libertas_add_mesh);
 
-static void wake_pending_cmdnodes(wlan_private *priv)
-{
-       struct cmd_ctrl_node *cmdnode;
-       unsigned long flags;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       spin_lock_irqsave(&priv->adapter->driver_lock, flags);
-       list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) {
-               cmdnode->cmdwaitqwoken = 1;
-               wake_up_interruptible(&cmdnode->cmdwait_q);
-       }
-       spin_unlock_irqrestore(&priv->adapter->driver_lock, flags);
-}
-
-
-int libertas_remove_card(wlan_private *priv)
-{
-       wlan_adapter *adapter;
-       struct net_device *dev;
-       union iwreq_data wrqu;
-
-       lbs_deb_enter(LBS_DEB_NET);
-
-       if (!priv)
-               goto out;
-
-       adapter = priv->adapter;
-
-       if (!adapter)
-               goto out;
-
-       dev = priv->dev;
-
-       netif_stop_queue(priv->dev);
-       netif_carrier_off(priv->dev);
-
-       wake_pending_cmdnodes(priv);
-
-       unregister_netdev(dev);
-
-       cancel_delayed_work(&priv->assoc_work);
-       destroy_workqueue(priv->assoc_thread);
-
-       if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) {
-               adapter->psmode = WLAN802_11POWERMODECAM;
-               libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
-       }
-
-       memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN);
-       wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-       wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
-
-       adapter->surpriseremoved = 1;
-
-       /* Stop the thread servicing the interrupts */
-       kthread_stop(priv->main_thread);
-
-       libertas_debugfs_remove_one(priv);
-
-       lbs_deb_net("free adapter\n");
-       libertas_free_adapter(priv);
-
-       lbs_deb_net("unregister finish\n");
-
-       priv->dev = NULL;
-       free_netdev(dev);
-
-out:
-       lbs_deb_leave(LBS_DEB_NET);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(libertas_remove_card);
-
 
 void libertas_remove_mesh(wlan_private *priv)
 {
        struct net_device *mesh_dev;
 
-       lbs_deb_enter(LBS_DEB_NET);
+       lbs_deb_enter(LBS_DEB_MAIN);
 
        if (!priv)
                goto out;
@@ -1359,14 +1392,14 @@ void libertas_remove_mesh(wlan_private *priv)
        netif_stop_queue(mesh_dev);
        netif_carrier_off(priv->mesh_dev);
 
-       device_remove_file(&(mesh_dev->dev), &dev_attr_anycast_mask);
+       sysfs_remove_group(&(mesh_dev->dev.kobj), &libertas_mesh_attr_group);
        unregister_netdev(mesh_dev);
 
        priv->mesh_dev = NULL ;
        free_netdev(mesh_dev);
 
 out:
-       lbs_deb_leave(LBS_DEB_NET);
+       lbs_deb_leave(LBS_DEB_MAIN);
 }
 EXPORT_SYMBOL_GPL(libertas_remove_mesh);
 
@@ -1385,7 +1418,7 @@ struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band, int *c
 
        lbs_deb_enter(LBS_DEB_MAIN);
 
-       end = sizeof(region_cfp_table)/sizeof(struct region_cfp_table);
+       end = ARRAY_SIZE(region_cfp_table);
 
        for (i = 0; i < end ; i++) {
                lbs_deb_main("region_cfp_table[i].region=%d\n",
@@ -1498,6 +1531,81 @@ static void libertas_exit_module(void)
        lbs_deb_leave(LBS_DEB_MAIN);
 }
 
+/*
+ * rtap interface support fuctions
+ */
+
+static int libertas_rtap_open(struct net_device *dev)
+{
+        netif_carrier_off(dev);
+        netif_stop_queue(dev);
+        return 0;
+}
+
+static int libertas_rtap_stop(struct net_device *dev)
+{
+        return 0;
+}
+
+static int libertas_rtap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+        netif_stop_queue(dev);
+        return -EOPNOTSUPP;
+}
+
+static struct net_device_stats *libertas_rtap_get_stats(struct net_device *dev)
+{
+       wlan_private *priv = dev->priv;
+       return &priv->ieee->stats;
+}
+
+
+void libertas_remove_rtap(wlan_private *priv)
+{
+       if (priv->rtap_net_dev == NULL)
+               return;
+       unregister_netdev(priv->rtap_net_dev);
+       free_ieee80211(priv->rtap_net_dev);
+       priv->rtap_net_dev = NULL;
+}
+
+int libertas_add_rtap(wlan_private *priv)
+{
+       int rc = 0;
+
+       if (priv->rtap_net_dev)
+               return -EPERM;
+
+       priv->rtap_net_dev = alloc_ieee80211(0);
+       if (priv->rtap_net_dev == NULL)
+               return -ENOMEM;
+
+
+       priv->ieee = netdev_priv(priv->rtap_net_dev);
+
+       strcpy(priv->rtap_net_dev->name, "rtap%d");
+
+       priv->rtap_net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
+       priv->rtap_net_dev->open = libertas_rtap_open;
+       priv->rtap_net_dev->stop = libertas_rtap_stop;
+       priv->rtap_net_dev->get_stats = libertas_rtap_get_stats;
+       priv->rtap_net_dev->hard_start_xmit = libertas_rtap_hard_start_xmit;
+       priv->rtap_net_dev->set_multicast_list = libertas_set_multicast_list;
+       priv->rtap_net_dev->priv = priv;
+
+       priv->ieee->iw_mode = IW_MODE_MONITOR;
+
+       rc = register_netdev(priv->rtap_net_dev);
+       if (rc) {
+               free_ieee80211(priv->rtap_net_dev);
+               priv->rtap_net_dev = NULL;
+               return rc;
+       }
+
+       return 0;
+}
+
+
 module_init(libertas_init_module);
 module_exit(libertas_exit_module);
 
This page took 0.037671 seconds and 5 git commands to generate.