[PATCH] libertas: move channel changing into association framework
authorDan Williams <dcbw@redhat.com>
Fri, 25 May 2007 20:46:33 +0000 (16:46 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 11 Jun 2007 18:28:42 +0000 (14:28 -0400)
Handle channel changes through the deferred association framework
rather than directly.  Fixes errors when setting channels along
with other parameters like mode and SSID.

Signed-off-by: Dan Williams <dcbw@redhat.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/libertas/assoc.c
drivers/net/wireless/libertas/dev.h
drivers/net/wireless/libertas/fw.c
drivers/net/wireless/libertas/join.c
drivers/net/wireless/libertas/wext.c

index 4bc128fa58489636e6c4302ef3dea3d8f5ac8750..3f2dfaf879c57ab2de5d7384c4df44c0701211cd 100644 (file)
@@ -22,6 +22,10 @@ static int assoc_helper_essid(wlan_private *priv,
 
        lbs_deb_enter(LBS_DEB_ASSOC);
 
+       /* FIXME: take channel into account when picking SSIDs if a channel
+        * is set.
+        */
+
        lbs_deb_assoc("New SSID requested: %s\n", assoc_req->ssid.ssid);
        if (assoc_req->mode == IW_MODE_INFRA) {
                if (adapter->prescan) {
@@ -158,6 +162,69 @@ done:
 }
 
 
+static int update_channel(wlan_private * priv)
+{
+       /* the channel in f/w could be out of sync, get the current channel */
+       return libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
+                                   cmd_opt_802_11_rf_channel_get,
+                                   cmd_option_waitforrsp, 0, NULL);
+}
+
+static int assoc_helper_channel(wlan_private *priv,
+                                struct assoc_request * assoc_req)
+{
+       wlan_adapter *adapter = priv->adapter;
+       int ret = 0;
+
+       lbs_deb_enter(LBS_DEB_ASSOC);
+
+       ret = update_channel(priv);
+       if (ret < 0) {
+               lbs_deb_assoc("ASSOC: channel: error getting channel.");
+       }
+
+       if (assoc_req->channel == adapter->curbssparams.channel)
+               goto done;
+
+       lbs_deb_assoc("ASSOC: channel: %d -> %d\n",
+              adapter->curbssparams.channel, assoc_req->channel);
+
+       ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
+                               cmd_opt_802_11_rf_channel_set,
+                               cmd_option_waitforrsp, 0, &assoc_req->channel);
+       if (ret < 0) {
+               lbs_deb_assoc("ASSOC: channel: error setting channel.");
+       }
+
+       ret = update_channel(priv);
+       if (ret < 0) {
+               lbs_deb_assoc("ASSOC: channel: error getting channel.");
+       }
+
+       if (assoc_req->channel != adapter->curbssparams.channel) {
+               lbs_deb_assoc("ASSOC: channel: failed to update channel to %d",
+                             assoc_req->channel);
+               goto done;
+       }
+
+       if (   assoc_req->secinfo.wep_enabled
+           &&   (assoc_req->wep_keys[0].len
+              || assoc_req->wep_keys[1].len
+              || assoc_req->wep_keys[2].len
+              || assoc_req->wep_keys[3].len)) {
+               /* Make sure WEP keys are re-sent to firmware */
+               set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
+       }
+
+       /* Must restart/rejoin adhoc networks after channel change */
+       set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
+
+done:
+       lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
+       return ret;
+}
+
+
 static int assoc_helper_wep_keys(wlan_private *priv,
                                  struct assoc_request * assoc_req)
 {
@@ -334,6 +401,11 @@ static int should_stop_adhoc(wlan_adapter *adapter,
                        return 1;
        }
 
+       if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
+               if (assoc_req->channel != adapter->curbssparams.channel)
+                       return 1;
+       }
+
        return 0;
 }
 
@@ -423,6 +495,15 @@ lbs_deb_assoc("ASSOC(:%d) mode: ret = %d\n", __LINE__, ret);
                }
        }
 
+       if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
+               ret = assoc_helper_channel(priv, assoc_req);
+               if (ret) {
+                       lbs_deb_assoc("ASSOC(:%d) channel: ret = %d\n",
+                                     __LINE__, ret);
+                       goto out;
+               }
+       }
+
        if (   test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)
            || test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) {
                ret = assoc_helper_wep_keys(priv, assoc_req);
index 41d8a4cdd43b143e0ccfaf0a6340d6f4d2a06c7e..4ca60d9323b403dabf5229417921316edc8665ac 100644 (file)
@@ -287,7 +287,6 @@ struct _wlan_adapter {
        u32 txantenna;
        u32 rxantenna;
 
-       u8 adhocchannel;
        u32 fragthsd;
        u32 rtsthsd;
 
index 56b272d62a865f1b9771e16f01f8d197be9b288e..2e535ef7e8038b755ca29c0f6d1a4fea2e07836b 100644 (file)
@@ -220,8 +220,6 @@ static void wlan_init_adapter(wlan_private * priv)
        memset(&adapter->capinfo, 0, sizeof(adapter->capinfo));
        adapter->capinfo.shortpreamble = SHORT_PREAMBLE_ALLOWED;
 
-       adapter->adhocchannel = DEFAULT_AD_HOC_CHANNEL;
-
        adapter->psmode = wlan802_11powermodecam;
        adapter->multipledtim = MRVDRV_DEFAULT_MULTIPLE_DTIM;
 
index c9111b8770678b75b097002e12d46554d5bf492d..a11ce3a6f6110d0ed5561eb21d6afd8636f4928d 100644 (file)
@@ -158,7 +158,6 @@ int libertas_start_adhoc_network(wlan_private * priv, struct WLAN_802_11_SSID *a
 
        libertas_set_radio_control(priv);
 
-       lbs_deb_join("Adhoc channel = %d\n", adapter->adhocchannel);
        lbs_deb_join("curbssparams.channel = %d\n",
               adapter->curbssparams.channel);
        lbs_deb_join("curbssparams.band = %d\n", adapter->curbssparams.band);
@@ -513,15 +512,13 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
        adhs->phyparamset.dsparamset.elementid = DS_PARA_IE_ID;
        adhs->phyparamset.dsparamset.len = DS_PARA_IE_LEN;
 
-       WARN_ON(!adapter->adhocchannel);
+       WARN_ON(!adapter->curbssparams.channel);
 
        lbs_deb_join("ADHOC_S_CMD: Creating ADHOC on channel %d\n",
-              adapter->adhocchannel);
-
-       adapter->curbssparams.channel = adapter->adhocchannel;
+              adapter->curbssparams.channel);
 
-       pbssdesc->channel = adapter->adhocchannel;
-       adhs->phyparamset.dsparamset.currentchan = adapter->adhocchannel;
+       pbssdesc->channel = adapter->curbssparams.channel;
+       adhs->phyparamset.dsparamset.currentchan = adapter->curbssparams.channel;
 
        memcpy(&pbssdesc->phyparamset,
               &adhs->phyparamset, sizeof(union ieeetypes_phyparamset));
@@ -909,7 +906,7 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
        wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
 
        lbs_deb_join("ADHOC_RESP: - Joined/Started Ad Hoc\n");
-       lbs_deb_join("ADHOC_RESP: channel = %d\n", adapter->adhocchannel);
+       lbs_deb_join("ADHOC_RESP: channel = %d\n", adapter->curbssparams.channel);
        lbs_deb_join("ADHOC_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n",
               padhocresult->BSSID[0], padhocresult->BSSID[1],
               padhocresult->BSSID[2], padhocresult->BSSID[3],
index 518371a76c3650dfb939b1109dedfb9c0f35ff33..40dd08018b49657264af3cb8f312f3d041d3922c 100644 (file)
@@ -157,103 +157,6 @@ static struct chan_freq_power *find_cfp_by_band_and_freq(wlan_adapter * adapter,
        return cfp;
 }
 
-static int updatecurrentchannel(wlan_private * priv)
-{
-       int ret;
-
-       /*
-        ** the channel in f/w could be out of sync, get the current channel
-        */
-       ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
-                                   cmd_opt_802_11_rf_channel_get,
-                                   cmd_option_waitforrsp, 0, NULL);
-
-       lbs_deb_wext("current channel %d\n",
-              priv->adapter->curbssparams.channel);
-
-       return ret;
-}
-
-static int setcurrentchannel(wlan_private * priv, int channel)
-{
-       lbs_deb_wext("set channel %d\n", channel);
-
-       /*
-        **  Current channel is not set to adhocchannel requested, set channel
-        */
-       return (libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
-                                     cmd_opt_802_11_rf_channel_set,
-                                     cmd_option_waitforrsp, 0, &channel));
-}
-
-static int changeadhocchannel(wlan_private * priv, int channel)
-{
-       int ret = 0;
-       struct WLAN_802_11_SSID curadhocssid;
-       struct bss_descriptor * join_bss = NULL;
-       wlan_adapter *adapter = priv->adapter;
-
-       adapter->adhocchannel = channel;
-
-       updatecurrentchannel(priv);
-
-       if (adapter->curbssparams.channel == adapter->adhocchannel) {
-               /* adhocchannel is set to the current channel already */
-               goto out;
-       }
-
-       lbs_deb_wext("updating channel from %d to %d\n",
-              adapter->curbssparams.channel, adapter->adhocchannel);
-
-       setcurrentchannel(priv, adapter->adhocchannel);
-
-       updatecurrentchannel(priv);
-
-       if (adapter->curbssparams.channel != adapter->adhocchannel) {
-               lbs_deb_wext("failed to updated channel to %d, channel = %d\n",
-                      adapter->adhocchannel, adapter->curbssparams.channel);
-               ret = -1;
-               goto out;
-       }
-
-       if (adapter->connect_status != libertas_connected)
-               goto out;
-
-       lbs_deb_wext("channel changed while in IBSS\n");
-
-       /* Copy the current ssid */
-       memcpy(&curadhocssid, &adapter->curbssparams.ssid,
-              sizeof(struct WLAN_802_11_SSID));
-
-       /* Exit Adhoc mode */
-       lbs_deb_wext("in changeadhocchannel(): sending Adhoc stop\n");
-       ret = libertas_stop_adhoc_network(priv);
-       if (ret)
-               goto out;
-
-       /* Scan for the network, do not save previous results.  Stale
-        *   scan data will cause us to join a non-existant adhoc network
-        */
-       libertas_send_specific_SSID_scan(priv, &curadhocssid, 1);
-
-       /* find out the BSSID that matches the current SSID */
-       join_bss = libertas_find_SSID_in_list(adapter, &curadhocssid, NULL,
-                          IW_MODE_ADHOC);
-
-       if (join_bss) {
-               lbs_deb_wext("SSID found in list, so join\n");
-               libertas_join_adhoc_network(priv, join_bss);
-       } else {
-               lbs_deb_wext("SSID not found in list, "
-                      "creating AdHoc with SSID '%s'\n",
-                      curadhocssid.ssid);
-               libertas_start_adhoc_network(priv, &curadhocssid);
-       }
-
-out:
-       lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
-       return ret;
-}
 
 /**
  *  @brief Set Radio On/OFF
@@ -1228,82 +1131,59 @@ out:
 static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info,
                  struct iw_freq *fwrq, char *extra)
 {
-       int ret = 0;
+       int ret = -EINVAL;
        wlan_private *priv = dev->priv;
        wlan_adapter *adapter = priv->adapter;
-       int rc = -EINPROGRESS;  /* Call commit handler */
        struct chan_freq_power *cfp;
+       struct assoc_request * assoc_req;
 
        lbs_deb_enter(LBS_DEB_WEXT);
 
-       /*
-        * If setting by frequency, convert to a channel
-        */
-       if (fwrq->e == 1) {
+       mutex_lock(&adapter->lock);
+       assoc_req = wlan_get_association_request(adapter);
+       if (!assoc_req) {
+               ret = -ENOMEM;
+               goto out;
+       }
 
+       /* If setting by frequency, convert to a channel */
+       if (fwrq->e == 1) {
                long f = fwrq->m / 100000;
-               int c = 0;
 
                cfp = find_cfp_by_band_and_freq(adapter, 0, f);
                if (!cfp) {
                        lbs_deb_wext("invalid freq %ld\n", f);
-                       return -EINVAL;
+                       goto out;
                }
 
-               c = (int)cfp->channel;
-
-               if (c < 0)
-                       return -EINVAL;
-
                fwrq->e = 0;
-               fwrq->m = c;
+               fwrq->m = (int) cfp->channel;
        }
 
-       /*
-        * Setting by channel number
-        */
+       /* Setting by channel number */
        if (fwrq->m > 1000 || fwrq->e > 0) {
-               rc = -EOPNOTSUPP;
-       } else {
-               int channel = fwrq->m;
+               goto out;
+       }
 
-               cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, channel);
-               if (!cfp) {
-                       rc = -EINVAL;
-               } else {
-                       if (adapter->mode == IW_MODE_ADHOC) {
-                               rc = changeadhocchannel(priv, channel);
-                               /*  If station is WEP enabled, send the
-                                *  command to set WEP in firmware
-                                */
-                               if (adapter->secinfo.wep_enabled) {
-                                       lbs_deb_wext("set_freq: WEP enabled\n");
-                                       ret = libertas_prepare_and_send_command(priv,
-                                                                   cmd_802_11_set_wep,
-                                                                   cmd_act_add,
-                                                                   cmd_option_waitforrsp,
-                                                                   0,
-                                                                   NULL);
-
-                                       if (ret) {
-                                               rc = ret;
-                                               goto out;
-                                       }
-
-                                       adapter->currentpacketfilter |=
-                                           cmd_act_mac_wep_enable;
-
-                                       libertas_set_mac_packet_filter(priv);
-                               }
-                       } else {
-                               rc = -EOPNOTSUPP;
-                       }
-               }
+       cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, fwrq->m);
+       if (!cfp) {
+               goto out;
        }
 
+       assoc_req->channel = fwrq->m;
+       ret = 0;
+
 out:
-       lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", rc);
-       return rc;
+       if (ret == 0) {
+               set_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags);
+               wlan_postpone_association_work(priv);
+       } else {
+               wlan_cancel_association_work(priv);
+       }
+       mutex_unlock(&adapter->lock);
+
+       lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+       return ret;
 }
 
 /**