Return-path: Received: from casper.infradead.org ([85.118.1.10]:48661 "EHLO casper.infradead.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754035Ab0AYPVQ (ORCPT ); Mon, 25 Jan 2010 10:21:16 -0500 Subject: Re: [PATCH 10/10] [RFC, v4] libertas: cfg80211 support From: Samuel Ortiz Reply-To: Samuel Ortiz To: Holger Schurig Cc: John Linville , linux-wireless@vger.kernel.org, Dan Williams In-Reply-To: <20091202142955.107139811@gmail.com> References: <20091202142555.654873300@gmail.com> <20091202142955.107139811@gmail.com> Content-Type: text/plain; charset="UTF-8" Date: Mon, 25 Jan 2010 16:20:54 +0100 Message-ID: <1264432854.2250.17.camel@caravaggio> Mime-Version: 1.0 Sender: linux-wireless-owner@vger.kernel.org List-ID: Hi Holger, I just got a hold on a 8688 card, and I tested your patch. IMO this should be upstreamed, I only have a few minor comments: On Wed, 2009-12-02 at 15:26 +0100, Holger Schurig wrote: > * "iw wlan0 connect SSID" doesn't work, you HAVE to specify the BSSID > of an access-point: "iw wlan0 connect SSID 00:11:22:33:44:55". And > the AP has to be in cfg80211's BSS list. I really think that's ok. The typical driver+wpa_s+NM configuration will populate the cfg80211 list prior to association. I'm going to send a patch to apply on top of this one for supporting connection when sme->bssid is NULL. This way we can support iw wlan0 connect SSID provided that we have somehow populated the cfg80211 scan list. > +static void lbs_scan_worker(struct work_struct *work) > +{ > + struct lbs_private *priv = > + container_of(work, struct lbs_private, scan_work.work); > + struct cmd_ds_802_11_scan *scan_cmd; > + u8 *tlv; /* pointer into our current, growing TLV storage area */ > + int last_channel; > + int running, carrier; > + > + lbs_deb_enter(LBS_DEB_SCAN); > + > + scan_cmd = kzalloc(LBS_SCAN_MAX_CMD_SIZE, GFP_KERNEL); > + if (scan_cmd == NULL) > + goto out_no_scan_cmd; > + > + /* prepare fixed part of scan command */ > + scan_cmd->bsstype = CMD_BSS_TYPE_ANY; > + > + /* stop network while we're away from our main channel */ > + running = !netif_queue_stopped(priv->dev); > + carrier = netif_carrier_ok(priv->dev); > + if (running) > + netif_stop_queue(priv->dev); > + if (carrier) > + netif_carrier_off(priv->dev); Stopping the tx queue is fine, but turning the carrier signal off is not. > +static int lbs_cfg_scan(struct wiphy *wiphy, > + struct net_device *dev, > + struct cfg80211_scan_request *request) > +{ > + struct lbs_private *priv = wiphy_priv(wiphy); > + int ret = 0; > + > + lbs_deb_enter(LBS_DEB_CFG80211); > + > + if (priv->scan_req || delayed_work_pending(&priv->scan_work)) { > + /* old scan request not yet processed */ > + ret = -EAGAIN; > + goto out; > + } > + > + lbs_deb_scan("scan: ssids %d, channels %d, ie_len %d\n", > + request->n_ssids, request->n_channels, request->ie_len); > + > + priv->scan_channel = 0; > + queue_delayed_work(priv->work_thread, &priv->scan_work, > + msecs_to_jiffies(50)); > + > + if (priv->surpriseremoved) > + ret = -EIO; > + > + priv->scan_req = request; A couple of questions here: - What is this 50ms delay for ? - Why dont you set the scan_request pointer prior to scheduling the scanning work ? Again, I think this should make it to wireless-testing soon so that people can start using it. Cheers, Samuel. > + out: > + lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); > + return ret; > +} > + > + > + > + > +/*************************************************************************** > + * Events > + */ > + > +void lbs_send_disconnect_notification(struct lbs_private *priv) > +{ > + lbs_deb_enter(LBS_DEB_CFG80211); > + > + cfg80211_disconnected(priv->dev, > + 0, > + NULL, 0, > + GFP_KERNEL); > + > + lbs_deb_leave(LBS_DEB_CFG80211); > +} > + > +void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event) > +{ > + lbs_deb_enter(LBS_DEB_CFG80211); > + > + cfg80211_michael_mic_failure(priv->dev, > + priv->assoc_bss, > + event == MACREG_INT_CODE_MIC_ERR_MULTICAST ? > + NL80211_KEYTYPE_GROUP : > + NL80211_KEYTYPE_PAIRWISE, > + -1, > + NULL, > + GFP_KERNEL); > + > + lbs_deb_leave(LBS_DEB_CFG80211); > +} > + > + > + > + > +/*************************************************************************** > + * Connect/disconnect > + */ > + > + > +/* > + * This removes all WEP keys > + */ > +static int lbs_remove_wep_keys(struct lbs_private *priv) > +{ > + struct cmd_ds_802_11_set_wep cmd; > + int ret; > + > + lbs_deb_enter(LBS_DEB_CFG80211); > + > + memset(&cmd, 0, sizeof(cmd)); > + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); > + cmd.keyindex = cpu_to_le16(priv->wep_tx_key); > + cmd.action = cpu_to_le16(CMD_ACT_REMOVE); > + > + ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd); > + > + lbs_deb_leave(LBS_DEB_CFG80211); > + return ret; > +} > + > +/* > + * Set WEP keys > + */ > +static int lbs_set_wep_keys(struct lbs_private *priv) > +{ > + struct cmd_ds_802_11_set_wep cmd; > + int i; > + int ret; > + > + lbs_deb_enter(LBS_DEB_CFG80211); > + > + /* > + * command 13 00 > + * size 50 00 > + * sequence xx xx > + * result 00 00 > + * action 02 00 ACT_ADD > + * transmit key 00 00 > + * type for key 1 01 WEP40 > + * type for key 2 00 > + * type for key 3 00 > + * type for key 4 00 > + * key 1 39 39 39 39 39 00 00 00 > + * 00 00 00 00 00 00 00 00 > + * key 2 00 00 00 00 00 00 00 00 > + * 00 00 00 00 00 00 00 00 > + * key 3 00 00 00 00 00 00 00 00 > + * 00 00 00 00 00 00 00 00 > + * key 4 00 00 00 00 00 00 00 00 > + */ > + if (priv->wep_key_len[0] || priv->wep_key_len[1] || > + priv->wep_key_len[2] || priv->wep_key_len[3]) { > + /* Only set wep keys if we have at least one of them */ > + memset(&cmd, 0, sizeof(cmd)); > + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); > + cmd.keyindex = cpu_to_le16(priv->wep_tx_key); > + cmd.action = cpu_to_le16(CMD_ACT_ADD); > + > + for (i = 0; i < 4; i++) { > + switch (priv->wep_key_len[i]) { > + case WLAN_KEY_LEN_WEP40: > + cmd.keytype[i] = CMD_TYPE_WEP_40_BIT; > + break; > + case WLAN_KEY_LEN_WEP104: > + cmd.keytype[i] = CMD_TYPE_WEP_104_BIT; > + break; > + default: > + cmd.keytype[i] = 0; > + break; > + } > + memcpy(cmd.keymaterial[i], priv->wep_key[i], > + priv->wep_key_len[i]); > + } > + > + ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd); > + } else { > + /* Otherwise remove all wep keys */ > + ret = lbs_remove_wep_keys(priv); > + } > + > + lbs_deb_leave(LBS_DEB_CFG80211); > + return ret; > +} > + > + > +/* > + * Enable/Disable RSN status > + */ > +static int lbs_enable_rsn(struct lbs_private *priv, int enable) > +{ > + struct cmd_ds_802_11_enable_rsn cmd; > + int ret; > + > + lbs_deb_enter_args(LBS_DEB_CFG80211, "%d", enable); > + > + /* > + * cmd 2f 00 > + * size 0c 00 > + * sequence xx xx > + * result 00 00 > + * action 01 00 ACT_SET > + * enable 01 00 > + */ > + memset(&cmd, 0, sizeof(cmd)); > + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); > + cmd.action = cpu_to_le16(CMD_ACT_SET); > + cmd.enable = cpu_to_le16(enable); > + > + ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd); > + > + lbs_deb_leave(LBS_DEB_CFG80211); > + return ret; > +} > + > + > +/* > + * Set WPA/WPA key material > + */ > + > +/* like "struct cmd_ds_802_11_key_material", but with cmd_header. Once we > + * get rid of WEXT, this should go into host.h */ > + > +struct cmd_key_material { > + struct cmd_header hdr; > + > + __le16 action; > + struct MrvlIEtype_keyParamSet param; > +} __attribute__ ((packed)); > + > +static int lbs_set_key_material(struct lbs_private *priv, > + int key_type, > + int key_info, > + u8 *key, u16 key_len) > +{ > + struct cmd_key_material cmd; > + int ret; > + > + lbs_deb_enter(LBS_DEB_CFG80211); > + > + /* > + * Example for WPA (TKIP): > + * > + * cmd 5e 00 > + * size 34 00 > + * sequence xx xx > + * result 00 00 > + * action 01 00 > + * TLV type 00 01 key param > + * length 00 26 > + * key type 01 00 TKIP > + * key info 06 00 UNICAST | ENABLED > + * key len 20 00 > + * key 32 bytes > + */ > + memset(&cmd, 0, sizeof(cmd)); > + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); > + cmd.action = cpu_to_le16(CMD_ACT_SET); > + cmd.param.type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL); > + cmd.param.length = cpu_to_le16(sizeof(cmd.param) - 4); > + cmd.param.keytypeid = cpu_to_le16(key_type); > + cmd.param.keyinfo = cpu_to_le16(key_info); > + cmd.param.keylen = cpu_to_le16(key_len); > + if (key && key_len) > + memcpy(cmd.param.key, key, key_len); > + > + ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd); > + > + lbs_deb_leave(LBS_DEB_CFG80211); > + return ret; > +} > + > + > +/* > + * Sets the auth type (open, shared, etc) in the firmware. That > + * we use CMD_802_11_AUTHENTICATE is misleading, this firmware > + * command doesn't send an authentication frame at all, it just > + * stores the auth_type. > + */ > +static int lbs_set_authtype(struct lbs_private *priv, > + struct cfg80211_connect_params *sme) > +{ > + struct cmd_ds_802_11_authenticate cmd; > + int ret; > + > + lbs_deb_enter_args(LBS_DEB_CFG80211, "%d", sme->auth_type); > + > + /* > + * cmd 11 00 > + * size 19 00 > + * sequence xx xx > + * result 00 00 > + * BSS id 00 13 19 80 da 30 > + * auth type 00 > + * reserved 00 00 00 00 00 00 00 00 00 00 > + */ > + memset(&cmd, 0, sizeof(cmd)); > + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); > + if (sme->bssid) > + memcpy(cmd.bssid, sme->bssid, ETH_ALEN); > + /* convert auth_type */ > + ret = lbs_auth_to_authtype(sme->auth_type); > + if (ret < 0) > + goto done; > + > + cmd.authtype = ret; > + ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd); > + > + done: > + lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); > + return ret; > +} > + > + > +/* > + * Create association request > + */ > +#define LBS_ASSOC_MAX_CMD_SIZE \ > + (sizeof(struct cmd_ds_802_11_associate) \ > + - 512 /* cmd_ds_802_11_associate.iebuf */ \ > + + LBS_MAX_SSID_TLV_SIZE \ > + + LBS_MAX_CHANNEL_TLV_SIZE \ > + + LBS_MAX_CF_PARAM_TLV_SIZE \ > + + LBS_MAX_AUTH_TYPE_TLV_SIZE \ > + + LBS_MAX_WPA_TLV_SIZE) > + > +static int lbs_associate(struct lbs_private *priv, > + struct cfg80211_bss *bss, > + struct cfg80211_connect_params *sme) > +{ > + struct cmd_ds_802_11_associate_response *resp; > + struct cmd_ds_802_11_associate *cmd = kzalloc(LBS_ASSOC_MAX_CMD_SIZE, > + GFP_KERNEL); > + const u8 *ssid_eid; > + size_t len, resp_ie_len; > + int status; > + int ret; > + u8 *pos = &(cmd->iebuf[0]); > + > + lbs_deb_enter(LBS_DEB_CFG80211); > + > + if (!cmd) { > + ret = -ENOMEM; > + goto done; > + } > + > + /* > + * cmd 50 00 > + * length 34 00 > + * sequence xx xx > + * result 00 00 > + * BSS id 00 13 19 80 da 30 > + * capabilities 11 00 > + * listen interval 0a 00 > + * beacon interval 00 00 > + * DTIM period 00 > + * TLVs xx (up to 512 bytes) > + */ > + cmd->hdr.command = cpu_to_le16(CMD_802_11_ASSOCIATE); > + > + /* Fill in static fields */ > + memcpy(cmd->bssid, bss->bssid, ETH_ALEN); > + cmd->listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL); > + cmd->capability = cpu_to_le16(bss->capability); > + > + /* add SSID TLV */ > + ssid_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SSID); > + if (ssid_eid) > + pos += lbs_add_ssid_tlv(pos, ssid_eid + 2, ssid_eid[1]); > + else > + lbs_deb_assoc("no SSID\n"); > + > + /* add DS param TLV */ > + if (bss->channel) > + pos += lbs_add_channel_tlv(pos, bss->channel->hw_value); > + else > + lbs_deb_assoc("no channel\n"); > + > + /* add (empty) CF param TLV */ > + pos += lbs_add_cf_param_tlv(pos); > + > + /* add rates TLV */ > + pos += lbs_add_common_rates_tlv(pos, bss); > + > + /* add auth type TLV */ > + if (priv->fwrelease >= 0x09000000) > + pos += lbs_add_auth_type_tlv(pos, sme->auth_type); > + > + /* add WPA/WPA2 TLV */ > + if (sme->ie && sme->ie_len) > + pos += lbs_add_wpa_tlv(pos, sme->ie, sme->ie_len); > + > + len = (sizeof(*cmd) - sizeof(cmd->iebuf)) + > + (u16)(pos - (u8 *) &cmd->iebuf); > + cmd->hdr.size = cpu_to_le16(len); > + > + /* store for later use */ > + memcpy(priv->assoc_bss, bss->bssid, ETH_ALEN); > + > + ret = lbs_cmd_with_response(priv, CMD_802_11_ASSOCIATE, cmd); > + if (ret) > + goto done; > + > + > + /* generate connect message to cfg80211 */ > + > + resp = (void *) cmd; /* recast for easier field access */ > + status = le16_to_cpu(resp->statuscode); > + > + /* Convert statis code of old firmware */ > + if (priv->fwrelease < 0x09000000) > + switch (status) { > + case 0: > + break; > + case 1: > + lbs_deb_assoc("invalid association parameters\n"); > + status = WLAN_STATUS_CAPS_UNSUPPORTED; > + break; > + case 2: > + lbs_deb_assoc("timer expired while waiting for AP\n"); > + status = WLAN_STATUS_AUTH_TIMEOUT; > + break; > + case 3: > + lbs_deb_assoc("association refused by AP\n"); > + status = WLAN_STATUS_ASSOC_DENIED_UNSPEC; > + break; > + case 4: > + lbs_deb_assoc("authentication refused by AP\n"); > + status = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; > + break; > + default: > + lbs_deb_assoc("association failure %d\n", status); > + status = WLAN_STATUS_UNSPECIFIED_FAILURE; > + } > + > + lbs_deb_assoc("status %d, capability 0x%04x\n", status, > + le16_to_cpu(resp->capability)); > + > + resp_ie_len = le16_to_cpu(resp->hdr.size) > + - sizeof(resp->hdr) > + - 6; > + cfg80211_connect_result(priv->dev, > + priv->assoc_bss, > + sme->ie, sme->ie_len, > + resp->iebuf, resp_ie_len, > + status, > + GFP_KERNEL); > + > + if (status == 0) { > + /* TODO: get rid of priv->connect_status */ > + priv->connect_status = LBS_CONNECTED; > + netif_carrier_on(priv->dev); > + if (!priv->tx_pending_len) > + netif_tx_wake_all_queues(priv->dev); > + } > + > + > +done: > + lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); > + return ret; > +} > + > + > + > +static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev, > + struct cfg80211_connect_params *sme) > +{ > + struct lbs_private *priv = wiphy_priv(wiphy); > + struct cfg80211_bss *bss = NULL; > + int ret = 0; > + u8 preamble = RADIO_PREAMBLE_SHORT; > + > + lbs_deb_enter(LBS_DEB_CFG80211); > + > + if (sme->bssid) { > + bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid, > + sme->ssid, sme->ssid_len, > + WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); > + } else { > + /* > + * Here we have an impedance mismatch. The firmware command > + * CMD_802_11_ASSOCIATE always needs a BSSID, it cannot > + * connect otherwise. However, for the connect-API of > + * cfg80211 the bssid is purely optional. We don't get one, > + * except the user specifies one on the "iw" command line. > + * > + * If we don't got one, we could initiate a scan and look > + * for the best matching cfg80211_bss entry. > + * > + * Or, better yet, net/wireless/sme.c get's rewritten into > + * something more generally useful. > + */ > + lbs_pr_err("TODO: no BSS specified\n"); > + ret = -ENOTSUPP; > + goto done; > + } > + > + > + if (!bss) { > + lbs_pr_err("assicate: bss %pM not in scan results\n", > + sme->bssid); > + ret = -ENOENT; > + goto done; > + } > + lbs_deb_assoc("trying %pM", sme->bssid); > + lbs_deb_assoc("cipher 0x%x, key index %d, key len %d\n", > + sme->crypto.cipher_group, > + sme->key_idx, sme->key_len); > + > + /* As this is a new connection, clear locally stored WEP keys */ > + priv->wep_tx_key = 0; > + memset(priv->wep_key, 0, sizeof(priv->wep_key)); > + memset(priv->wep_key_len, 0, sizeof(priv->wep_key_len)); > + > + /* set/remove WEP keys */ > + switch (sme->crypto.cipher_group) { > + case WLAN_CIPHER_SUITE_WEP40: > + case WLAN_CIPHER_SUITE_WEP104: > + /* Store provided WEP keys in priv-> */ > + priv->wep_tx_key = sme->key_idx; > + priv->wep_key_len[sme->key_idx] = sme->key_len; > + memcpy(priv->wep_key[sme->key_idx], sme->key, sme->key_len); > + /* Set WEP keys and WEP mode */ > + lbs_set_wep_keys(priv); > + priv->mac_control |= CMD_ACT_MAC_WEP_ENABLE; > + lbs_set_mac_control(priv); > + /* No RSN mode for WEP */ > + lbs_enable_rsn(priv, 0); > + break; > + case 0: /* there's no WLAN_CIPHER_SUITE_NONE definition */ > + /* > + * If we don't have no WEP, no WPA and no WPA2, > + * we remove all keys like in the WPA/WPA2 setup, > + * we just don't set RSN. > + * > + * Therefore: fall-throught > + */ > + case WLAN_CIPHER_SUITE_TKIP: > + case WLAN_CIPHER_SUITE_CCMP: > + /* Remove WEP keys and WEP mode */ > + lbs_remove_wep_keys(priv); > + priv->mac_control &= ~CMD_ACT_MAC_WEP_ENABLE; > + lbs_set_mac_control(priv); > + > + /* clear the WPA/WPA2 keys */ > + lbs_set_key_material(priv, > + KEY_TYPE_ID_WEP, /* doesn't matter */ > + KEY_INFO_WPA_UNICAST, > + NULL, 0); > + lbs_set_key_material(priv, > + KEY_TYPE_ID_WEP, /* doesn't matter */ > + KEY_INFO_WPA_MCAST, > + NULL, 0); > + /* RSN mode for WPA/WPA2 */ > + lbs_enable_rsn(priv, sme->crypto.cipher_group != 0); > + break; > + default: > + lbs_pr_err("unsupported cipher group 0x%x\n", > + sme->crypto.cipher_group); > + ret = -ENOTSUPP; > + goto done; > + } > + > + lbs_set_authtype(priv, sme); > + lbs_set_radio(priv, preamble, 1); > + > + /* Do the actual association */ > + lbs_associate(priv, bss, sme); > + > + done: > + if (bss) > + cfg80211_put_bss(bss); > + lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); > + return ret; > +} > + > + > + > + > +/* callback from lbs_cfg_disconnect() */ > +static int lbs_cfg_ret_disconnect(struct lbs_private *priv, unsigned long dummy, > + struct cmd_header *resp) > +{ > + lbs_deb_enter(LBS_DEB_CFG80211); > + > + cfg80211_disconnected(priv->dev, > + priv->disassoc_reason, > + NULL, 0, /* TODO? */ > + GFP_KERNEL); > + > + /* TODO: get rid of priv->connect_status */ > + priv->connect_status = LBS_CONNECTED; > + > + lbs_deb_leave(LBS_DEB_CFG80211); > + return 0; > +} > + > + > +static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev, > + u16 reason_code) > +{ > + struct lbs_private *priv = wiphy_priv(wiphy); > + struct cmd_ds_802_11_deauthenticate cmd; > > - lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d", chan->center_freq, channel_type); > + lbs_deb_enter_args(LBS_DEB_CFG80211, "reason_code %d", reason_code); > > - if (channel_type != NL80211_CHAN_NO_HT) > + /* store for lbs_cfg_ret_disconnect() */ > + priv->disassoc_reason = reason_code; > + > + memset(&cmd, 0, sizeof(cmd)); > + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); > + /* Mildly ugly to use a locally store my own BSSID ... */ > + memcpy(cmd.macaddr, &priv->assoc_bss, ETH_ALEN); > + cmd.reasoncode = cpu_to_le16(reason_code); > + > + __lbs_cmd_async(priv, CMD_802_11_DEAUTHENTICATE, > + &cmd.hdr, sizeof(cmd), > + lbs_cfg_ret_disconnect, 0); > + > + return 0; > +} > + > + > +static int lbs_cfg_set_default_key(struct wiphy *wiphy, > + struct net_device *netdev, > + u8 key_index) > +{ > + struct lbs_private *priv = wiphy_priv(wiphy); > + > + lbs_deb_enter(LBS_DEB_CFG80211); > + > + if (key_index != priv->wep_tx_key) { > + lbs_deb_assoc("set_default_key: to %d\n", key_index); > + priv->wep_tx_key = key_index; > + lbs_set_wep_keys(priv); > + } > + > + return 0; > +} > + > + > +static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev, > + u8 idx, const u8 *mac_addr, > + struct key_params *params) > +{ > + struct lbs_private *priv = wiphy_priv(wiphy); > + u16 key_info; > + u16 key_type; > + int ret = 0; > + > + lbs_deb_enter(LBS_DEB_CFG80211); > + > + lbs_deb_assoc("add_key: cipher 0x%x, mac_addr %pM\n", > + params->cipher, mac_addr); > + lbs_deb_assoc("add_key: key index %d, key len %d\n", > + idx, params->key_len); > + if (params->key_len) > + lbs_deb_hex(LBS_DEB_CFG80211, "KEY", > + params->key, params->key_len); > + > + lbs_deb_assoc("add_key: seq len %d\n", params->seq_len); > + if (params->seq_len) > + lbs_deb_hex(LBS_DEB_CFG80211, "SEQ", > + params->seq, params->seq_len); > + > + switch (params->cipher) { > + case WLAN_CIPHER_SUITE_WEP40: > + case WLAN_CIPHER_SUITE_WEP104: > + /* actually compare if something has changed ... */ > + if ((priv->wep_key_len[idx] != params->key_len) || > + memcmp(priv->wep_key[idx], > + params->key, params->key_len) != 0) { > + priv->wep_key_len[idx] = params->key_len; > + memcpy(priv->wep_key[idx], > + params->key, params->key_len); > + lbs_set_wep_keys(priv); > + } > + break; > + case WLAN_CIPHER_SUITE_TKIP: > + case WLAN_CIPHER_SUITE_CCMP: > + key_info = KEY_INFO_WPA_ENABLED | ((idx == 0) > + ? KEY_INFO_WPA_UNICAST > + : KEY_INFO_WPA_MCAST); > + key_type = (params->cipher == WLAN_CIPHER_SUITE_TKIP) > + ? KEY_TYPE_ID_TKIP > + : KEY_TYPE_ID_AES; > + lbs_set_key_material(priv, > + key_type, > + key_info, > + params->key, params->key_len); > + break; > + default: > + lbs_pr_err("unhandled cipher 0x%x\n", params->cipher); > + ret = -ENOTSUPP; > + break; > + } > + > + return ret; > +} > + > + > +static int lbs_cfg_del_key(struct wiphy *wiphy, struct net_device *netdev, > + u8 key_index, const u8 *mac_addr) > +{ > + > + lbs_deb_enter(LBS_DEB_CFG80211); > + > + lbs_deb_assoc("del_key: key_idx %d, mac_addr %pM\n", > + key_index, mac_addr); > + > +#ifdef TODO > + struct lbs_private *priv = wiphy_priv(wiphy); > + /* > + * I think can keep this a NO-OP, because: > + > + * - we clear all keys whenever we do lbs_cfg_connect() anyway > + * - neither "iw" nor "wpa_supplicant" won't call this during > + * an ongoing connection > + * - TODO: but I have to check if this is still true when > + * I set the AP to periodic re-keying > + * - we've not kzallec() something when we've added a key at > + * lbs_cfg_connect() or lbs_cfg_add_key(). > + * > + * This causes lbs_cfg_del_key() only called at disconnect time, > + * where we'd just waste time deleting a key that is not going > + * to be used anyway. > + */ > + if (key_index < 3 && priv->wep_key_len[key_index]) { > + priv->wep_key_len[key_index] = 0; > + lbs_set_wep_keys(priv); > + } > +#endif > + > + return 0; > +} > + > + > + > +/*************************************************************************** > + * Monitor mode > + */ > + > +/* like "struct cmd_ds_802_11_monitor_mode", but with cmd_header. Once we > + * get rid of WEXT, this should go into host.h */ > +struct cmd_monitor_mode { > + struct cmd_header hdr; > + > + __le16 action; > + __le16 mode; > +} __attribute__ ((packed)); > + > +static int lbs_enable_monitor_mode(struct lbs_private *priv, int mode) > +{ > + struct cmd_monitor_mode cmd; > + int ret; > + > + lbs_deb_enter(LBS_DEB_CFG80211); > + > + /* > + * cmd 98 00 > + * size 0c 00 > + * sequence xx xx > + * result 00 00 > + * action 01 00 ACT_SET > + * enable 01 00 > + */ > + memset(&cmd, 0, sizeof(cmd)); > + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); > + cmd.action = cpu_to_le16(CMD_ACT_SET); > + cmd.mode = cpu_to_le16(mode); > + > + ret = lbs_cmd_with_response(priv, CMD_802_11_MONITOR_MODE, &cmd); > + > + if (ret == 0) > + priv->dev->type = ARPHRD_IEEE80211_RADIOTAP; > + else > + priv->dev->type = ARPHRD_ETHER; > + > + lbs_deb_leave(LBS_DEB_CFG80211); > + return ret; > +} > + > + > + > + > + > + > +/*************************************************************************** > + * Get station > + */ > + > +/* > + * Returns the signal or 0 in case of an error. > + */ > + > +/* like "struct cmd_ds_802_11_rssi", but with cmd_header. Once we get rid > + * of WEXT, this should go into host.h */ > +struct cmd_rssi { > + struct cmd_header hdr; > + > + __le16 n_or_snr; > + __le16 nf; > + __le16 avg_snr; > + __le16 avg_nf; > +} __attribute__ ((packed)); > + > +static int lbs_get_signal(struct lbs_private *priv, s8 *signal, s8 *noise) > +{ > + struct cmd_rssi cmd; > + int ret; > + > + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); > + cmd.n_or_snr = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR); > + ret = lbs_cmd_with_response(priv, CMD_802_11_RSSI, &cmd); > + > + if (ret == 0) { > + *signal = CAL_RSSI(le16_to_cpu(cmd.n_or_snr), > + le16_to_cpu(cmd.nf)); > + *noise = CAL_NF(le16_to_cpu(cmd.nf)); > + } > + return ret; > +} > + > + > +static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev, > + u8 *mac, struct station_info *sinfo) > +{ > + struct lbs_private *priv = wiphy_priv(wiphy); > + s8 signal, noise; > + int ret; > + size_t i; > + > + lbs_deb_enter(LBS_DEB_CFG80211); > + > + sinfo->filled |= STATION_INFO_TX_BYTES | > + STATION_INFO_TX_PACKETS | > + STATION_INFO_RX_BYTES | > + STATION_INFO_RX_PACKETS; > + sinfo->tx_bytes = priv->dev->stats.tx_bytes; > + sinfo->tx_packets = priv->dev->stats.tx_packets; > + sinfo->rx_bytes = priv->dev->stats.rx_bytes; > + sinfo->rx_packets = priv->dev->stats.rx_packets; > + > + /* Get current RSSI */ > + ret = lbs_get_signal(priv, &signal, &noise); > + if (ret == 0) { > + sinfo->signal = signal; > + sinfo->filled |= STATION_INFO_SIGNAL; > + } > + > + /* Convert priv->cur_rate from hw_value to NL80211 value */ > + for (i = 0; i < ARRAY_SIZE(lbs_rates); i++) { > + if (priv->cur_rate == lbs_rates[i].hw_value) { > + sinfo->txrate.legacy = lbs_rates[i].bitrate; > + sinfo->filled |= STATION_INFO_TX_BITRATE; > + break; > + } > + } > + > + return 0; > +} > + > + > + > + > +/*************************************************************************** > + * "Site survey", here just current channel and noise level > + */ > + > +static int lbs_get_survey(struct wiphy *wiphy, struct net_device *dev, > + int idx, struct survey_info *survey) > +{ > + struct lbs_private *priv = wiphy_priv(wiphy); > + s8 signal, noise; > + int ret; > + > + if (idx != 0) > + ret = -ENOENT; > + > + lbs_deb_enter(LBS_DEB_CFG80211); > + > + survey->channel = ieee80211_get_channel(wiphy, > + ieee80211_channel_to_frequency(priv->channel)); > + > + ret = lbs_get_signal(priv, &signal, &noise); > + if (ret == 0) { > + survey->filled = SURVEY_INFO_NOISE_DBM; > + survey->noise = noise; > + } > + > + lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); > + return ret; > +} > + > + > + > + > +/*************************************************************************** > + * Change interface > + */ > + > +static int lbs_change_intf(struct wiphy *wiphy, struct net_device *dev, > + enum nl80211_iftype type, u32 *flags, > + struct vif_params *params) > +{ > + struct lbs_private *priv = wiphy_priv(wiphy); > + int ret = 0; > + > + lbs_deb_enter(LBS_DEB_CFG80211); > + > + switch (type) { > + case NL80211_IFTYPE_MONITOR: > + ret = lbs_enable_monitor_mode(priv, 1); > + break; > + case NL80211_IFTYPE_STATION: > + if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) > + ret = lbs_enable_monitor_mode(priv, 0); > + if (!ret) > + ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 1); > + break; > + case NL80211_IFTYPE_ADHOC: > + if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) > + ret = lbs_enable_monitor_mode(priv, 0); > + if (!ret) > + ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 2); > + break; > + default: > + ret = -ENOTSUPP; > + } > + > + if (!ret) > + priv->wdev->iftype = type; > + > + lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); > + return ret; > +} > + > + > + > +/*************************************************************************** > + * IBSS (Ad-Hoc) > + */ > + > +/* The firmware needs the following bits masked out of the beacon-derived > + * capability field when associating/joining to a BSS: > + * 9 (QoS), 11 (APSD), 12 (unused), 14 (unused), 15 (unused) > + */ > +#define CAPINFO_MASK (~(0xda00)) > + > + > +static void lbs_join_post(struct lbs_private *priv, > + struct cfg80211_ibss_params *params, > + u8 *bssid, u16 capability) > +{ > + u8 fake_ie[2 + IEEE80211_MAX_SSID_LEN + /* ssid */ > + 2 + 4 + /* basic rates */ > + 2 + 1 + /* DS parameter */ > + 2 + 2 + /* atim */ > + 2 + 8]; /* extended rates */ > + u8 *fake = fake_ie; > + > + lbs_deb_enter(LBS_DEB_CFG80211); > + > + /* > + * For cfg80211_inform_bss, we'll need a fake IE, as we can't get > + * the real IE from the firmware. So we fabricate a fake IE based on > + * what the firmware actually sends (sniffed with wireshark). > + */ > + /* Fake SSID IE */ > + *fake++ = WLAN_EID_SSID; > + *fake++ = params->ssid_len; > + memcpy(fake, params->ssid, params->ssid_len); > + fake += params->ssid_len; > + /* Fake supported basic rates IE */ > + *fake++ = WLAN_EID_SUPP_RATES; > + *fake++ = 4; > + *fake++ = 0x82; > + *fake++ = 0x84; > + *fake++ = 0x8b; > + *fake++ = 0x96; > + /* Fake DS channel IE */ > + *fake++ = WLAN_EID_DS_PARAMS; > + *fake++ = 1; > + *fake++ = params->channel->hw_value; > + /* Fake IBSS params IE */ > + *fake++ = WLAN_EID_IBSS_PARAMS; > + *fake++ = 2; > + *fake++ = 0; /* ATIM=0 */ > + *fake++ = 0; > + /* Fake extended rates IE, TODO: don't add this for 802.11b only, > + * but I don't know how this could be checked */ > + *fake++ = WLAN_EID_EXT_SUPP_RATES; > + *fake++ = 8; > + *fake++ = 0x0c; > + *fake++ = 0x12; > + *fake++ = 0x18; > + *fake++ = 0x24; > + *fake++ = 0x30; > + *fake++ = 0x48; > + *fake++ = 0x60; > + *fake++ = 0x6c; > + lbs_deb_hex(LBS_DEB_CFG80211, "IE", fake_ie, fake - fake_ie); > + > + cfg80211_inform_bss(priv->wdev->wiphy, > + params->channel, > + bssid, > + 0, > + capability, > + params->beacon_interval, > + fake_ie, fake - fake_ie, > + 0, GFP_KERNEL); > + cfg80211_ibss_joined(priv->dev, bssid, GFP_KERNEL); > + > + /* TODO: consider doing this at MACREG_INT_CODE_LINK_SENSED time */ > + priv->connect_status = LBS_CONNECTED; > + netif_carrier_on(priv->dev); > + if (!priv->tx_pending_len) > + netif_wake_queue(priv->dev); > + > + lbs_deb_leave(LBS_DEB_CFG80211); > +} > + > +static int lbs_ibss_join_existing(struct lbs_private *priv, > + struct cfg80211_ibss_params *params, > + struct cfg80211_bss *bss) > +{ > + const u8 *rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES); > + struct cmd_ds_802_11_ad_hoc_join cmd; > + u8 preamble = RADIO_PREAMBLE_SHORT; > + int ret = 0; > + > + lbs_deb_enter(LBS_DEB_CFG80211); > + > + /* TODO: set preamble based on scan result */ > + ret = lbs_set_radio(priv, preamble, 1); > + if (ret) > + goto out; > + > + /* > + * Example CMD_802_11_AD_HOC_JOIN command: > + * > + * command 2c 00 CMD_802_11_AD_HOC_JOIN > + * size 65 00 > + * sequence xx xx > + * result 00 00 > + * bssid 02 27 27 97 2f 96 > + * ssid 49 42 53 53 00 00 00 00 > + * 00 00 00 00 00 00 00 00 > + * 00 00 00 00 00 00 00 00 > + * 00 00 00 00 00 00 00 00 > + * type 02 CMD_BSS_TYPE_IBSS > + * beacon period 64 00 > + * dtim period 00 > + * timestamp 00 00 00 00 00 00 00 00 > + * localtime 00 00 00 00 00 00 00 00 > + * IE DS 03 > + * IE DS len 01 > + * IE DS channel 01 > + * reserveed 00 00 00 00 > + * IE IBSS 06 > + * IE IBSS len 02 > + * IE IBSS atim 00 00 > + * reserved 00 00 00 00 > + * capability 02 00 > + * rates 82 84 8b 96 0c 12 18 24 30 48 60 6c 00 > + * fail timeout ff 00 > + * probe delay 00 00 > + */ > + memset(&cmd, 0, sizeof(cmd)); > + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); > + > + memcpy(cmd.bss.bssid, bss->bssid, ETH_ALEN); > + memcpy(cmd.bss.ssid, params->ssid, params->ssid_len); > + cmd.bss.type = CMD_BSS_TYPE_IBSS; > + cmd.bss.beaconperiod = cpu_to_le16(params->beacon_interval); > + cmd.bss.ds.header.id = WLAN_EID_DS_PARAMS; > + cmd.bss.ds.header.len = 1; > + cmd.bss.ds.channel = params->channel->hw_value; > + cmd.bss.ibss.header.id = WLAN_EID_IBSS_PARAMS; > + cmd.bss.ibss.header.len = 2; > + cmd.bss.ibss.atimwindow = 0; > + cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK); > + > + /* set rates to the intersection of our rates and the rates in the > + bss */ > + if (!rates_eid) { > + lbs_add_rates(cmd.bss.rates); > + } else { > + int hw, i; > + u8 rates_max = rates_eid[1]; > + u8 *rates = cmd.bss.rates; > + for (hw = 0; hw < ARRAY_SIZE(lbs_rates); hw++) { > + u8 hw_rate = lbs_rates[hw].bitrate / 5; > + for (i = 0; i < rates_max; i++) { > + if (hw_rate == (rates_eid[i+2] & 0x7f)) { > + u8 rate = rates_eid[i+2]; > + if (rate == 0x02 || rate == 0x04 || > + rate == 0x0b || rate == 0x16) > + rate |= 0x80; > + *rates++ = rate; > + } > + } > + } > + } > + > + /* Only v8 and below support setting this */ > + if (MRVL_FW_MAJOR_REV(priv->fwrelease) <= 8) { > + cmd.failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT); > + cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); > + } > + ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd); > + if (ret) > + goto out; > + > + /* > + * This is a sample response to CMD_802_11_AD_HOC_JOIN: > + * > + * response 2c 80 > + * size 09 00 > + * sequence xx xx > + * result 00 00 > + * reserved 00 > + */ > + lbs_join_post(priv, params, bss->bssid, bss->capability); > + > + out: > + lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); > + return ret; > +} > + > + > + > +static int lbs_ibss_start_new(struct lbs_private *priv, > + struct cfg80211_ibss_params *params) > +{ > + struct cmd_ds_802_11_ad_hoc_start cmd; > + struct cmd_ds_802_11_ad_hoc_result *resp = > + (struct cmd_ds_802_11_ad_hoc_result *) &cmd; > + u8 preamble = RADIO_PREAMBLE_SHORT; > + int ret = 0; > + u16 capability; > + > + lbs_deb_enter(LBS_DEB_CFG80211); > + > + ret = lbs_set_radio(priv, preamble, 1); > + if (ret) > + goto out; > + > + /* > + * Example CMD_802_11_AD_HOC_START command: > + * > + * command 2b 00 CMD_802_11_AD_HOC_START > + * size b1 00 > + * sequence xx xx > + * result 00 00 > + * ssid 54 45 53 54 00 00 00 00 > + * 00 00 00 00 00 00 00 00 > + * 00 00 00 00 00 00 00 00 > + * 00 00 00 00 00 00 00 00 > + * bss type 02 > + * beacon period 64 00 > + * dtim period 00 > + * IE IBSS 06 > + * IE IBSS len 02 > + * IE IBSS atim 00 00 > + * reserved 00 00 00 00 > + * IE DS 03 > + * IE DS len 01 > + * IE DS channel 01 > + * reserved 00 00 00 00 > + * probe delay 00 00 > + * capability 02 00 > + * rates 82 84 8b 96 (basic rates with have bit 7 set) > + * 0c 12 18 24 30 48 60 6c > + * padding 100 bytes > + */ > + memset(&cmd, 0, sizeof(cmd)); > + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); > + memcpy(cmd.ssid, params->ssid, params->ssid_len); > + cmd.bsstype = CMD_BSS_TYPE_IBSS; > + cmd.beaconperiod = cpu_to_le16(params->beacon_interval); > + cmd.ibss.header.id = WLAN_EID_IBSS_PARAMS; > + cmd.ibss.header.len = 2; > + cmd.ibss.atimwindow = 0; > + cmd.ds.header.id = WLAN_EID_DS_PARAMS; > + cmd.ds.header.len = 1; > + cmd.ds.channel = params->channel->hw_value; > + /* Only v8 and below support setting probe delay */ > + if (MRVL_FW_MAJOR_REV(priv->fwrelease) <= 8) > + cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); > + /* TODO: mix in WLAN_CAPABILITY_PRIVACY */ > + capability = cpu_to_le16(WLAN_CAPABILITY_IBSS); > + cmd.capability = cpu_to_le16(capability); > + lbs_add_rates(cmd.rates); > + > + > + ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_START, &cmd); > + if (ret) > + goto out; > + > + /* > + * This is a sample response to CMD_802_11_AD_HOC_JOIN: > + * > + * response 2b 80 > + * size 14 00 > + * sequence xx xx > + * result 00 00 > + * reserved 00 > + * bssid 02 2b 7b 0f 86 0e > + */ > + lbs_join_post(priv, params, resp->bssid, capability); > + > + out: > + lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); > + return ret; > +} > + > + > +static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev, > + struct cfg80211_ibss_params *params) > +{ > + struct lbs_private *priv = wiphy_priv(wiphy); > + int ret = 0; > + struct cfg80211_bss *bss; > + DECLARE_SSID_BUF(ssid_buf); > + > + lbs_deb_enter(LBS_DEB_CFG80211); > + > + if (!params->channel) { > + ret = -ENOTSUPP; > + goto out; > + } > + > + ret = lbs_set_channel(priv, params->channel->hw_value); > + if (ret) > goto out; > > - ret = lbs_set_channel(priv, chan->hw_value); > + /* Search if someone is beaconing. This assumes that the > + * bss list is populated already */ > + bss = cfg80211_get_bss(wiphy, params->channel, params->bssid, > + params->ssid, params->ssid_len, > + WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS); > + > + if (bss) { > + ret = lbs_ibss_join_existing(priv, params, bss); > + cfg80211_put_bss(bss); > + } else > + ret = lbs_ibss_start_new(priv, params); > + > > out: > lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); > @@ -97,10 +1919,45 @@ static int lbs_cfg_set_channel(struct wi > } > > > +static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev) > +{ > + struct lbs_private *priv = wiphy_priv(wiphy); > + struct cmd_ds_802_11_ad_hoc_stop cmd; > + int ret = 0; > + > + lbs_deb_enter(LBS_DEB_CFG80211); > + > + memset(&cmd, 0, sizeof(cmd)); > + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); > + ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_STOP, &cmd); > + > + /* TODO: consider doing this at MACREG_INT_CODE_ADHOC_BCN_LOST time */ > + lbs_mac_event_disconnected(priv); > + > + lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); > + return ret; > +} > + > + > > > +/*************************************************************************** > + * Initialization > + */ > + > static struct cfg80211_ops lbs_cfg80211_ops = { > .set_channel = lbs_cfg_set_channel, > + .scan = lbs_cfg_scan, > + .connect = lbs_cfg_connect, > + .disconnect = lbs_cfg_disconnect, > + .add_key = lbs_cfg_add_key, > + .del_key = lbs_cfg_del_key, > + .set_default_key = lbs_cfg_set_default_key, > + .get_station = lbs_cfg_get_station, > + .dump_survey = lbs_get_survey, > + .change_virtual_intf = lbs_change_intf, > + .join_ibss = lbs_join_ibss, > + .leave_ibss = lbs_leave_ibss, > }; > > > @@ -140,6 +1997,36 @@ struct wireless_dev *lbs_cfg_alloc(struc > } > > > +static void lbs_cfg_set_regulatory_hint(struct lbs_private *priv) > +{ > + struct region_code_mapping { > + const char *cn; > + int code; > + }; > + > + /* Section 5.17.2 */ > + static struct region_code_mapping regmap[] = { > + {"US ", 0x10}, /* US FCC */ > + {"CA ", 0x20}, /* Canada */ > + {"EU ", 0x30}, /* ETSI */ > + {"ES ", 0x31}, /* Spain */ > + {"FR ", 0x32}, /* France */ > + {"JP ", 0x40}, /* Japan */ > + }; > + size_t i; > + > + lbs_deb_enter(LBS_DEB_CFG80211); > + > + for (i = 0; i < ARRAY_SIZE(regmap); i++) > + if (regmap[i].code == priv->regioncode) { > + regulatory_hint(priv->wdev->wiphy, regmap[i].cn); > + break; > + } > + > + lbs_deb_leave(LBS_DEB_CFG80211); > +} > + > + > /* > * This function get's called after lbs_setup_firmware() determined the > * firmware capabities. So we can setup the wiphy according to our > @@ -155,10 +2042,12 @@ int lbs_cfg_register(struct lbs_private > wdev->wiphy->max_scan_ssids = 1; > wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; > > - /* TODO: BIT(NL80211_IFTYPE_ADHOC); */ > - wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); > + wdev->wiphy->interface_modes = > + BIT(NL80211_IFTYPE_STATION) | > + BIT(NL80211_IFTYPE_ADHOC); > + if (lbs_rtap_supported(priv)) > + wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); > > - /* TODO: honor priv->regioncode */ > wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &lbs_band_2ghz; > > /* > @@ -176,11 +2065,22 @@ int lbs_cfg_register(struct lbs_private > if (ret) > lbs_pr_err("cannot register network device\n"); > > + INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker); > + > + lbs_cfg_set_regulatory_hint(priv); > + > lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); > return ret; > } > > > +void lbs_scan_deinit(struct lbs_private *priv) > +{ > + lbs_deb_enter(LBS_DEB_CFG80211); > + cancel_delayed_work_sync(&priv->scan_work); > +} > + > + > void lbs_cfg_free(struct lbs_private *priv) > { > struct wireless_dev *wdev = priv->wdev; > --- linux-wl.orig/drivers/net/wireless/libertas/dev.h > +++ linux-wl/drivers/net/wireless/libertas/dev.h > @@ -7,8 +7,8 @@ > #define _LBS_DEV_H_ > > #include "mesh.h" > -#include "scan.h" > -#include "assoc.h" > +#include "defs.h" > +#include "host.h" > > > > @@ -29,13 +29,15 @@ struct lbs_private { > /* Basic networking */ > struct net_device *dev; > u32 connect_status; > - int infra_open; > struct work_struct mcast_work; > u32 nr_of_multicastmacaddr; > u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN]; > > /* CFG80211 */ > struct wireless_dev *wdev; > + struct cfg80211_scan_request *scan_req; > + u8 assoc_bss[ETH_ALEN]; > + u8 disassoc_reason; > > /* Mesh */ > struct net_device *mesh_dev; /* Virtual device */ > @@ -48,10 +50,6 @@ struct lbs_private { > u8 mesh_ssid_len; > #endif > > - /* Monitor mode */ > - struct net_device *rtap_net_dev; > - u32 monitormode; > - > /* Debugfs */ > struct dentry *debugfs_dir; > struct dentry *debugfs_debug; > @@ -127,13 +125,9 @@ struct lbs_private { > struct workqueue_struct *work_thread; > > /** Encryption stuff */ > - struct lbs_802_11_security secinfo; > - struct enc_key wpa_mcast_key; > - struct enc_key wpa_unicast_key; > - u8 wpa_ie[MAX_WPA_IE_LEN]; > - u8 wpa_ie_len; > - u16 wep_tx_keyidx; > - struct enc_key wep_keys[4]; > + u8 wep_tx_key; > + u8 wep_key[4][WLAN_KEY_LEN_WEP104]; > + u8 wep_key_len[4]; > > /* Wake On LAN */ > uint32_t wol_criteria; > @@ -154,6 +148,7 @@ struct lbs_private { > /* NIC/link operation characteristics */ > u16 mac_control; > u8 radio_on; > + u8 cur_rate; > u8 channel; > s16 txpower_cur; > s16 txpower_min; > @@ -162,42 +157,6 @@ struct lbs_private { > /** Scanning */ > struct delayed_work scan_work; > int scan_channel; > - /* remember which channel was scanned last, != 0 if currently scanning */ > - u8 scan_ssid[IEEE80211_MAX_SSID_LEN + 1]; > - u8 scan_ssid_len; > - > - /* Associating */ > - struct delayed_work assoc_work; > - struct current_bss_params curbssparams; > - u8 mode; > - struct list_head network_list; > - struct list_head network_free_list; > - struct bss_descriptor *networks; > - struct assoc_request * pending_assoc_req; > - struct assoc_request * in_progress_assoc_req; > - uint16_t enablehwauto; > - > - /* ADHOC */ > - u16 beacon_period; > - u8 beacon_enable; > - u8 adhoccreate; > - > - /* WEXT */ > - char name[DEV_NAME_LEN]; > - u8 nodename[16]; > - struct iw_statistics wstats; > - u8 cur_rate; > -#define MAX_REGION_CHANNEL_NUM 2 > - struct region_channel region_channel[MAX_REGION_CHANNEL_NUM]; > - > - /** Requested Signal Strength*/ > - u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG]; > - u16 NF[MAX_TYPE_B][MAX_TYPE_AVG]; > - u8 RSSI[MAX_TYPE_B][MAX_TYPE_AVG]; > - u8 rawSNR[DEFAULT_DATA_AVG_FACTOR]; > - u8 rawNF[DEFAULT_DATA_AVG_FACTOR]; > - u16 nextSNRNF; > - u16 numSNRNF; > }; > > extern struct cmd_confirm_sleep confirm_sleep; > --- linux-wl.orig/drivers/net/wireless/libertas/cmd.c > +++ linux-wl/drivers/net/wireless/libertas/cmd.c > @@ -6,13 +6,8 @@ > #include > #include > > -#include "host.h" > #include "decl.h" > -#include "defs.h" > -#include "dev.h" > -#include "assoc.h" > -#include "wext.h" > -#include "scan.h" > +#include "cfg.h" > #include "cmd.h" > > > @@ -174,11 +169,6 @@ int lbs_update_hw_spec(struct lbs_privat > if (priv->mesh_dev) > memcpy(priv->mesh_dev->dev_addr, priv->current_addr, ETH_ALEN); > > - if (lbs_set_regiontable(priv, priv->regioncode, 0)) { > - ret = -1; > - goto out; > - } > - > out: > lbs_deb_leave(LBS_DEB_CMD); > return ret; > @@ -1302,6 +1292,15 @@ int lbs_execute_next_command(struct lbs_ > * check if in power save mode, if yes, put the device back > * to PS mode > */ > +#ifdef TODO > + /* > + * This was the old code for libertas+wext. Someone that > + * understands this beast should re-code it in a sane way. > + * > + * I actually don't understand why this is related to WPA > + * and to connection status, shouldn't powering should be > + * independ of such things? > + */ > if ((priv->psmode != LBS802_11POWERMODECAM) && > (priv->psstate == PS_STATE_FULL_POWER) && > ((priv->connect_status == LBS_CONNECTED) || > @@ -1323,6 +1322,7 @@ int lbs_execute_next_command(struct lbs_ > lbs_ps_sleep(priv, 0); > } > } > +#endif > } > > ret = 0; > --- linux-wl.orig/drivers/net/wireless/libertas/cmdresp.c > +++ linux-wl/drivers/net/wireless/libertas/cmdresp.c > @@ -4,18 +4,11 @@ > */ > #include > #include > -#include > -#include > #include > -#include > +#include > > -#include "host.h" > -#include "decl.h" > +#include "cfg.h" > #include "cmd.h" > -#include "defs.h" > -#include "dev.h" > -#include "assoc.h" > -#include "wext.h" > > /** > * @brief This function handles disconnect event. it > @@ -48,23 +41,8 @@ void lbs_mac_event_disconnected(struct l > priv->currenttxskb = NULL; > priv->tx_pending_len = 0; > > - /* reset SNR/NF/RSSI values */ > - memset(priv->SNR, 0x00, sizeof(priv->SNR)); > - memset(priv->NF, 0x00, sizeof(priv->NF)); > - memset(priv->RSSI, 0x00, sizeof(priv->RSSI)); > - memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR)); > - memset(priv->rawNF, 0x00, sizeof(priv->rawNF)); > - priv->nextSNRNF = 0; > - priv->numSNRNF = 0; > priv->connect_status = LBS_DISCONNECTED; > > - /* Clear out associated SSID and BSSID since connection is > - * no longer valid. > - */ > - memset(&priv->curbssparams.bssid, 0, ETH_ALEN); > - memset(&priv->curbssparams.ssid, 0, IEEE80211_MAX_SSID_LEN); > - priv->curbssparams.ssid_len = 0; > - > if (priv->psstate != PS_STATE_FULL_POWER) { > /* make firmware to exit PS mode */ > lbs_deb_cmd("disconnected, so exit PS mode\n"); > @@ -265,7 +243,7 @@ int lbs_process_command_response(struct > * ad-hoc mode. It takes place in > * lbs_execute_next_command(). > */ > - if (priv->mode == IW_MODE_ADHOC && > + if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR && > action == CMD_SUBCMD_ENTER_PS) > priv->psmode = LBS802_11POWERMODECAM; > } else if (action == CMD_SUBCMD_ENTER_PS) { > --- linux-wl.orig/drivers/net/wireless/libertas/main.c > +++ linux-wl/drivers/net/wireless/libertas/main.c > @@ -11,19 +11,13 @@ > #include > #include > #include > -#include > -#include > -#include > #include > > #include "host.h" > #include "decl.h" > #include "dev.h" > -#include "wext.h" > #include "cfg.h" > #include "debugfs.h" > -#include "scan.h" > -#include "assoc.h" > #include "cmd.h" > > #define DRIVER_RELEASE_VERSION "323.p0" > @@ -95,72 +89,6 @@ u8 lbs_data_rate_to_fw_index(u32 rate) > } > > > -static int lbs_add_rtap(struct lbs_private *priv); > -static void lbs_remove_rtap(struct lbs_private *priv); > - > - > -/** > - * Get function for sysfs attribute rtap > - */ > -static ssize_t lbs_rtap_get(struct device *dev, > - struct device_attribute *attr, char * buf) > -{ > - struct lbs_private *priv = to_net_dev(dev)->ml_priv; > - return snprintf(buf, 5, "0x%X\n", priv->monitormode); > -} > - > -/** > - * Set function for sysfs attribute rtap > - */ > -static ssize_t lbs_rtap_set(struct device *dev, > - struct device_attribute *attr, const char * buf, size_t count) > -{ > - int monitor_mode; > - struct lbs_private *priv = to_net_dev(dev)->ml_priv; > - > - sscanf(buf, "%x", &monitor_mode); > - if (monitor_mode) { > - if (priv->monitormode == monitor_mode) > - return strlen(buf); > - if (!priv->monitormode) { > - if (priv->infra_open || lbs_mesh_open(priv)) > - return -EBUSY; > - if (priv->mode == IW_MODE_INFRA) > - lbs_cmd_80211_deauthenticate(priv, > - priv->curbssparams.bssid, > - WLAN_REASON_DEAUTH_LEAVING); > - else if (priv->mode == IW_MODE_ADHOC) > - lbs_adhoc_stop(priv); > - lbs_add_rtap(priv); > - } > - priv->monitormode = monitor_mode; > - } else { > - if (!priv->monitormode) > - return strlen(buf); > - priv->monitormode = 0; > - lbs_remove_rtap(priv); > - > - if (priv->currenttxskb) { > - dev_kfree_skb_any(priv->currenttxskb); > - priv->currenttxskb = NULL; > - } > - > - /* Wake queues, command thread, etc. */ > - lbs_host_to_card_done(priv); > - } > - > - lbs_prepare_and_send_command(priv, > - CMD_802_11_MONITOR_MODE, CMD_ACT_SET, > - CMD_OPTION_WAITFORRSP, 0, &priv->monitormode); > - return strlen(buf); > -} > - > -/** > - * lbs_rtap attribute to be exported per ethX interface > - * through sysfs (/sys/class/net/ethX/lbs_rtap) > - */ > -static DEVICE_ATTR(lbs_rtap, 0644, lbs_rtap_get, lbs_rtap_set ); > - > /** > * @brief This function opens the ethX interface > * > @@ -176,13 +104,6 @@ static int lbs_dev_open(struct net_devic > > spin_lock_irq(&priv->driver_lock); > > - if (priv->monitormode) { > - ret = -EBUSY; > - goto out; > - } > - > - priv->infra_open = 1; > - > if (priv->connect_status == LBS_CONNECTED) > netif_carrier_on(dev); > else > @@ -190,7 +111,6 @@ static int lbs_dev_open(struct net_devic > > if (!priv->tx_pending_len) > netif_wake_queue(dev); > - out: > > spin_unlock_irq(&priv->driver_lock); > lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); > @@ -210,7 +130,6 @@ static int lbs_eth_stop(struct net_devic > lbs_deb_enter(LBS_DEB_NET); > > spin_lock_irq(&priv->driver_lock); > - priv->infra_open = 0; > netif_stop_queue(dev); > spin_unlock_irq(&priv->driver_lock); > > @@ -808,37 +727,16 @@ int lbs_exit_auto_deep_sleep(struct lbs_ > > static int lbs_init_adapter(struct lbs_private *priv) > { > - size_t bufsize; > - int i, ret = 0; > + int ret; > > lbs_deb_enter(LBS_DEB_MAIN); > > - /* Allocate buffer to store the BSSID list */ > - bufsize = MAX_NETWORK_COUNT * sizeof(struct bss_descriptor); > - priv->networks = kzalloc(bufsize, GFP_KERNEL); > - if (!priv->networks) { > - lbs_pr_err("Out of memory allocating beacons\n"); > - ret = -1; > - goto out; > - } > - > - /* Initialize scan result lists */ > - INIT_LIST_HEAD(&priv->network_free_list); > - INIT_LIST_HEAD(&priv->network_list); > - for (i = 0; i < MAX_NETWORK_COUNT; i++) { > - list_add_tail(&priv->networks[i].list, > - &priv->network_free_list); > - } > - > memset(priv->current_addr, 0xff, ETH_ALEN); > > priv->connect_status = LBS_DISCONNECTED; > - priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; > - priv->mode = IW_MODE_INFRA; > priv->channel = DEFAULT_AD_HOC_CHANNEL; > priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; > priv->radio_on = 1; > - priv->enablehwauto = 1; > priv->psmode = LBS802_11POWERMODECAM; > priv->psstate = PS_STATE_FULL_POWER; > priv->is_deep_sleep = 0; > @@ -891,8 +789,6 @@ static void lbs_free_adapter(struct lbs_ > kfifo_free(priv->event_fifo); > del_timer(&priv->command_timer); > del_timer(&priv->auto_deepsleep_timer); > - kfree(priv->networks); > - priv->networks = NULL; > > lbs_deb_leave(LBS_DEB_MAIN); > } > @@ -929,7 +825,7 @@ struct lbs_private *lbs_add_card(void *c > lbs_pr_err("cfg80211 init failed\n"); > goto done; > } > - /* TODO? */ > + > wdev->iftype = NL80211_IFTYPE_STATION; > priv = wdev_priv(wdev); > priv->wdev = wdev; > @@ -939,7 +835,6 @@ struct lbs_private *lbs_add_card(void *c > goto err_wdev; > } > > - //TODO? dev = alloc_netdev_mq(0, "wlan%d", ether_setup, IWM_TX_QUEUES); > dev = alloc_netdev(0, "wlan%d", ether_setup); > if (!dev) { > dev_err(dmdev, "no memory for network device instance\n"); > @@ -955,20 +850,10 @@ struct lbs_private *lbs_add_card(void *c > dev->netdev_ops = &lbs_netdev_ops; > dev->watchdog_timeo = 5 * HZ; > dev->ethtool_ops = &lbs_ethtool_ops; > -#ifdef WIRELESS_EXT > - dev->wireless_handlers = &lbs_handler_def; > -#endif > dev->flags |= IFF_BROADCAST | IFF_MULTICAST; > > - > - // TODO: kzalloc + iwm_init_default_profile(iwm, iwm->umac_profile); ?? > - > - > priv->card = card; > - priv->infra_open = 0; > - > > - priv->rtap_net_dev = NULL; > strcpy(dev->name, "wlan%d"); > > lbs_deb_thread("Starting main thread...\n"); > @@ -980,8 +865,6 @@ struct lbs_private *lbs_add_card(void *c > } > > priv->work_thread = create_singlethread_workqueue("lbs_worker"); > - INIT_DELAYED_WORK(&priv->assoc_work, lbs_association_worker); > - INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker); > INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker); > > priv->wol_criteria = 0xffffffff; > @@ -1014,12 +897,10 @@ void lbs_remove_card(struct lbs_private > lbs_deb_enter(LBS_DEB_MAIN); > > lbs_remove_mesh(priv); > - lbs_remove_rtap(priv); > + lbs_scan_deinit(priv); > > dev = priv->dev; > > - cancel_delayed_work_sync(&priv->scan_work); > - cancel_delayed_work_sync(&priv->assoc_work); > cancel_work_sync(&priv->mcast_work); > > /* worker thread destruction blocks on the in-flight command which > @@ -1056,7 +937,7 @@ void lbs_remove_card(struct lbs_private > EXPORT_SYMBOL_GPL(lbs_remove_card); > > > -static int lbs_rtap_supported(struct lbs_private *priv) > +int lbs_rtap_supported(struct lbs_private *priv) > { > if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) > return 1; > @@ -1088,16 +969,6 @@ int lbs_start_card(struct lbs_private *p > > lbs_init_mesh(priv); > > - /* > - * While rtap isn't related to mesh, only mesh-enabled > - * firmware implements the rtap functionality via > - * CMD_802_11_MONITOR_MODE. > - */ > - if (lbs_rtap_supported(priv)) { > - if (device_create_file(&dev->dev, &dev_attr_lbs_rtap)) > - lbs_pr_err("cannot register lbs_rtap attribute\n"); > - } > - > lbs_debugfs_init_one(priv, dev); > > lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name); > @@ -1129,9 +1000,6 @@ void lbs_stop_card(struct lbs_private *p > lbs_debugfs_remove_one(priv); > lbs_deinit_mesh(priv); > > - if (lbs_rtap_supported(priv)) > - device_remove_file(&dev->dev, &dev_attr_lbs_rtap); > - > /* Delete the timeout of the currently processing command */ > del_timer_sync(&priv->command_timer); > del_timer_sync(&priv->auto_deepsleep_timer); > @@ -1218,87 +1086,6 @@ static void __exit lbs_exit_module(void) > lbs_deb_leave(LBS_DEB_MAIN); > } > > -/* > - * rtap interface support fuctions > - */ > - > -static int lbs_rtap_open(struct net_device *dev) > -{ > - /* Yes, _stop_ the queue. Because we don't support injection */ > - lbs_deb_enter(LBS_DEB_MAIN); > - netif_carrier_off(dev); > - netif_stop_queue(dev); > - lbs_deb_leave(LBS_DEB_LEAVE); > - return 0; > -} > - > -static int lbs_rtap_stop(struct net_device *dev) > -{ > - lbs_deb_enter(LBS_DEB_MAIN); > - lbs_deb_leave(LBS_DEB_MAIN); > - return 0; > -} > - > -static netdev_tx_t lbs_rtap_hard_start_xmit(struct sk_buff *skb, > - struct net_device *dev) > -{ > - netif_stop_queue(dev); > - return NETDEV_TX_BUSY; > -} > - > -static void lbs_remove_rtap(struct lbs_private *priv) > -{ > - lbs_deb_enter(LBS_DEB_MAIN); > - if (priv->rtap_net_dev == NULL) > - goto out; > - unregister_netdev(priv->rtap_net_dev); > - free_netdev(priv->rtap_net_dev); > - priv->rtap_net_dev = NULL; > -out: > - lbs_deb_leave(LBS_DEB_MAIN); > -} > - > -static const struct net_device_ops rtap_netdev_ops = { > - .ndo_open = lbs_rtap_open, > - .ndo_stop = lbs_rtap_stop, > - .ndo_start_xmit = lbs_rtap_hard_start_xmit, > -}; > - > -static int lbs_add_rtap(struct lbs_private *priv) > -{ > - int ret = 0; > - struct net_device *rtap_dev; > - > - lbs_deb_enter(LBS_DEB_MAIN); > - if (priv->rtap_net_dev) { > - ret = -EPERM; > - goto out; > - } > - > - rtap_dev = alloc_netdev(0, "rtap%d", ether_setup); > - if (rtap_dev == NULL) { > - ret = -ENOMEM; > - goto out; > - } > - > - memcpy(rtap_dev->dev_addr, priv->current_addr, ETH_ALEN); > - rtap_dev->type = ARPHRD_IEEE80211_RADIOTAP; > - rtap_dev->netdev_ops = &rtap_netdev_ops; > - rtap_dev->ml_priv = priv; > - SET_NETDEV_DEV(rtap_dev, priv->dev->dev.parent); > - > - ret = register_netdev(rtap_dev); > - if (ret) { > - free_netdev(rtap_dev); > - goto out; > - } > - priv->rtap_net_dev = rtap_dev; > - > -out: > - lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); > - return ret; > -} > - > module_init(lbs_init_module); > module_exit(lbs_exit_module); > > --- linux-wl.orig/drivers/net/wireless/libertas/debugfs.c > +++ linux-wl/drivers/net/wireless/libertas/debugfs.c > @@ -1,17 +1,12 @@ > -#include > #include > #include > #include > #include > #include > -#include > -#include > > -#include "dev.h" > #include "decl.h" > -#include "host.h" > -#include "debugfs.h" > #include "cmd.h" > +#include "debugfs.h" > > static struct dentry *lbs_dir; > static char *szStates[] = { > @@ -60,50 +55,6 @@ static ssize_t lbs_dev_info(struct file > } > > > -static ssize_t lbs_getscantable(struct file *file, char __user *userbuf, > - size_t count, loff_t *ppos) > -{ > - struct lbs_private *priv = file->private_data; > - size_t pos = 0; > - int numscansdone = 0, res; > - unsigned long addr = get_zeroed_page(GFP_KERNEL); > - char *buf = (char *)addr; > - DECLARE_SSID_BUF(ssid); > - struct bss_descriptor * iter_bss; > - if (!buf) > - return -ENOMEM; > - > - pos += snprintf(buf+pos, len-pos, > - "# | ch | rssi | bssid | cap | Qual | SSID \n"); > - > - mutex_lock(&priv->lock); > - list_for_each_entry (iter_bss, &priv->network_list, list) { > - u16 ibss = (iter_bss->capability & WLAN_CAPABILITY_IBSS); > - u16 privacy = (iter_bss->capability & WLAN_CAPABILITY_PRIVACY); > - u16 spectrum_mgmt = (iter_bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT); > - > - pos += snprintf(buf+pos, len-pos, "%02u| %03d | %04d | %pM |", > - numscansdone, iter_bss->channel, iter_bss->rssi, > - iter_bss->bssid); > - pos += snprintf(buf+pos, len-pos, " %04x-", iter_bss->capability); > - pos += snprintf(buf+pos, len-pos, "%c%c%c |", > - ibss ? 'A' : 'I', privacy ? 'P' : ' ', > - spectrum_mgmt ? 'S' : ' '); > - pos += snprintf(buf+pos, len-pos, " %04d |", SCAN_RSSI(iter_bss->rssi)); > - pos += snprintf(buf+pos, len-pos, " %s\n", > - print_ssid(ssid, iter_bss->ssid, > - iter_bss->ssid_len)); > - > - numscansdone++; > - } > - mutex_unlock(&priv->lock); > - > - res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); > - > - free_page(addr); > - return res; > -} > - > static ssize_t lbs_sleepparams_write(struct file *file, > const char __user *user_buf, size_t count, > loff_t *ppos) > @@ -722,8 +673,6 @@ struct lbs_debugfs_files { > > static const struct lbs_debugfs_files debugfs_files[] = { > { "info", 0444, FOPS(lbs_dev_info, write_file_dummy), }, > - { "getscantable", 0444, FOPS(lbs_getscantable, > - write_file_dummy), }, > { "sleepparams", 0644, FOPS(lbs_sleepparams_read, > lbs_sleepparams_write), }, > }; > --- linux-wl.orig/drivers/net/wireless/libertas/ethtool.c > +++ linux-wl/drivers/net/wireless/libertas/ethtool.c > @@ -2,13 +2,8 @@ > #include > #include > > -#include "host.h" > #include "decl.h" > -#include "defs.h" > -#include "dev.h" > -#include "wext.h" > #include "cmd.h" > -#include "mesh.h" > > > static void lbs_ethtool_get_drvinfo(struct net_device *dev, > --- linux-wl.orig/drivers/net/wireless/libertas/rx.c > +++ linux-wl/drivers/net/wireless/libertas/rx.c > @@ -3,12 +3,13 @@ > */ > #include > #include > +#include > > +#include "defs.h" > #include "host.h" > #include "radiotap.h" > #include "decl.h" > #include "dev.h" > -#include "wext.h" > > struct eth803hdr { > u8 dest_addr[6]; > @@ -38,99 +39,6 @@ static int process_rxed_802_11_packet(st > struct sk_buff *skb); > > /** > - * @brief This function computes the avgSNR . > - * > - * @param priv A pointer to struct lbs_private structure > - * @return avgSNR > - */ > -static u8 lbs_getavgsnr(struct lbs_private *priv) > -{ > - u8 i; > - u16 temp = 0; > - if (priv->numSNRNF == 0) > - return 0; > - for (i = 0; i < priv->numSNRNF; i++) > - temp += priv->rawSNR[i]; > - return (u8) (temp / priv->numSNRNF); > - > -} > - > -/** > - * @brief This function computes the AvgNF > - * > - * @param priv A pointer to struct lbs_private structure > - * @return AvgNF > - */ > -static u8 lbs_getavgnf(struct lbs_private *priv) > -{ > - u8 i; > - u16 temp = 0; > - if (priv->numSNRNF == 0) > - return 0; > - for (i = 0; i < priv->numSNRNF; i++) > - temp += priv->rawNF[i]; > - return (u8) (temp / priv->numSNRNF); > - > -} > - > -/** > - * @brief This function save the raw SNR/NF to our internel buffer > - * > - * @param priv A pointer to struct lbs_private structure > - * @param prxpd A pointer to rxpd structure of received packet > - * @return n/a > - */ > -static void lbs_save_rawSNRNF(struct lbs_private *priv, struct rxpd *p_rx_pd) > -{ > - if (priv->numSNRNF < DEFAULT_DATA_AVG_FACTOR) > - priv->numSNRNF++; > - priv->rawSNR[priv->nextSNRNF] = p_rx_pd->snr; > - priv->rawNF[priv->nextSNRNF] = p_rx_pd->nf; > - priv->nextSNRNF++; > - if (priv->nextSNRNF >= DEFAULT_DATA_AVG_FACTOR) > - priv->nextSNRNF = 0; > - return; > -} > - > -/** > - * @brief This function computes the RSSI in received packet. > - * > - * @param priv A pointer to struct lbs_private structure > - * @param prxpd A pointer to rxpd structure of received packet > - * @return n/a > - */ > -static void lbs_compute_rssi(struct lbs_private *priv, struct rxpd *p_rx_pd) > -{ > - > - lbs_deb_enter(LBS_DEB_RX); > - > - lbs_deb_rx("rxpd: SNR %d, NF %d\n", p_rx_pd->snr, p_rx_pd->nf); > - lbs_deb_rx("before computing SNR: SNR-avg = %d, NF-avg = %d\n", > - priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE, > - priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE); > - > - priv->SNR[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->snr; > - priv->NF[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->nf; > - lbs_save_rawSNRNF(priv, p_rx_pd); > - > - priv->SNR[TYPE_RXPD][TYPE_AVG] = lbs_getavgsnr(priv) * AVG_SCALE; > - priv->NF[TYPE_RXPD][TYPE_AVG] = lbs_getavgnf(priv) * AVG_SCALE; > - lbs_deb_rx("after computing SNR: SNR-avg = %d, NF-avg = %d\n", > - priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE, > - priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE); > - > - priv->RSSI[TYPE_RXPD][TYPE_NOAVG] = > - CAL_RSSI(priv->SNR[TYPE_RXPD][TYPE_NOAVG], > - priv->NF[TYPE_RXPD][TYPE_NOAVG]); > - > - priv->RSSI[TYPE_RXPD][TYPE_AVG] = > - CAL_RSSI(priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE, > - priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE); > - > - lbs_deb_leave(LBS_DEB_RX); > -} > - > -/** > * @brief This function processes received packet and forwards it > * to kernel/upper layer > * > @@ -154,7 +62,7 @@ int lbs_process_rxed_packet(struct lbs_p > > skb->ip_summed = CHECKSUM_NONE; > > - if (priv->monitormode) > + if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) > return process_rxed_802_11_packet(priv, skb); > > p_rx_pd = (struct rxpd *) skb->data; > @@ -225,13 +133,7 @@ int lbs_process_rxed_packet(struct lbs_p > */ > skb_pull(skb, hdrchop); > > - /* Take the data rate from the rxpd structure > - * only if the rate is auto > - */ > - if (priv->enablehwauto) > - priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate); > - > - lbs_compute_rssi(priv, p_rx_pd); > + priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate); > > lbs_deb_rx("rx data: size of actual packet %d\n", skb->len); > dev->stats.rx_bytes += skb->len; > @@ -353,20 +255,18 @@ static int process_rxed_802_11_packet(st > pradiotap_hdr = (void *)skb_push(skb, sizeof(struct rx_radiotap_hdr)); > memcpy(pradiotap_hdr, &radiotap_hdr, sizeof(struct rx_radiotap_hdr)); > > - /* Take the data rate from the rxpd structure > - * only if the rate is auto > - */ > - if (priv->enablehwauto) > - priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate); > - > - lbs_compute_rssi(priv, prxpd); > + priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate); > > lbs_deb_rx("rx data: size of actual packet %d\n", skb->len); > dev->stats.rx_bytes += skb->len; > dev->stats.rx_packets++; > > - skb->protocol = eth_type_trans(skb, priv->rtap_net_dev); > - netif_rx(skb); > + skb->protocol = eth_type_trans(skb, priv->dev); > + > + if (in_interrupt()) > + netif_rx(skb); > + else > + netif_rx_ni(skb); > > ret = 0; > > --- linux-wl.orig/drivers/net/wireless/libertas/tx.c > +++ linux-wl/drivers/net/wireless/libertas/tx.c > @@ -4,13 +4,13 @@ > #include > #include > #include > +#include > > #include "host.h" > #include "radiotap.h" > #include "decl.h" > #include "defs.h" > #include "dev.h" > -#include "wext.h" > > /** > * @brief This function converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE > @@ -111,7 +111,7 @@ netdev_tx_t lbs_hard_start_xmit(struct s > p802x_hdr = skb->data; > pkt_len = skb->len; > > - if (dev == priv->rtap_net_dev) { > + if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) { > struct tx_radiotap_hdr *rtap_hdr = (void *)skb->data; > > /* set txpd fields from the radiotap header */ > @@ -149,7 +149,7 @@ netdev_tx_t lbs_hard_start_xmit(struct s > > dev->trans_start = jiffies; > > - if (priv->monitormode) { > + if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) { > /* Keep the skb to echo it back once Tx feedback is > received from FW */ > skb_orphan(skb); > @@ -160,6 +160,7 @@ netdev_tx_t lbs_hard_start_xmit(struct s > free: > dev_kfree_skb_any(skb); > } > + > unlock: > spin_unlock_irqrestore(&priv->driver_lock, flags); > wake_up(&priv->waitq); > @@ -181,7 +182,8 @@ void lbs_send_tx_feedback(struct lbs_pri > { > struct tx_radiotap_hdr *radiotap_hdr; > > - if (!priv->monitormode || priv->currenttxskb == NULL) > + if (!priv->wdev->iftype == NL80211_IFTYPE_MONITOR || > + priv->currenttxskb == NULL) > return; > > radiotap_hdr = (struct tx_radiotap_hdr *)priv->currenttxskb->data; > @@ -190,7 +192,7 @@ void lbs_send_tx_feedback(struct lbs_pri > (1 + priv->txretrycount - try_count) : 0; > > priv->currenttxskb->protocol = eth_type_trans(priv->currenttxskb, > - priv->rtap_net_dev); > + priv->dev); > netif_rx(priv->currenttxskb); > > priv->currenttxskb = NULL; > --- linux-wl.orig/drivers/net/wireless/libertas/assoc.h > +++ /dev/null > @@ -1,155 +0,0 @@ > -/* Copyright (C) 2006, Red Hat, Inc. */ > - > -#ifndef _LBS_ASSOC_H_ > -#define _LBS_ASSOC_H_ > - > - > -#include "defs.h" > -#include "host.h" > - > - > -struct lbs_private; > - > -/* > - * In theory, the IE is limited to the IE length, 255, > - * but in practice 64 bytes are enough. > - */ > -#define MAX_WPA_IE_LEN 64 > - > - > - > -struct lbs_802_11_security { > - u8 WPAenabled; > - u8 WPA2enabled; > - u8 wep_enabled; > - u8 auth_mode; > - u32 key_mgmt; > -}; > - > -/** Current Basic Service Set State Structure */ > -struct current_bss_params { > - /** bssid */ > - u8 bssid[ETH_ALEN]; > - /** ssid */ > - u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; > - u8 ssid_len; > - > - /** band */ > - u8 band; > - /** channel is directly in priv->channel */ > - /** zero-terminated array of supported data rates */ > - u8 rates[MAX_RATES + 1]; > -}; > - > -/** > - * @brief Structure used to store information for each beacon/probe response > - */ > -struct bss_descriptor { > - u8 bssid[ETH_ALEN]; > - > - u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; > - u8 ssid_len; > - > - u16 capability; > - u32 rssi; > - u32 channel; > - u16 beaconperiod; > - __le16 atimwindow; > - > - /* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */ > - u8 mode; > - > - /* zero-terminated array of supported data rates */ > - u8 rates[MAX_RATES + 1]; > - > - unsigned long last_scanned; > - > - union ieee_phy_param_set phy; > - union ieee_ss_param_set ss; > - > - u8 wpa_ie[MAX_WPA_IE_LEN]; > - size_t wpa_ie_len; > - u8 rsn_ie[MAX_WPA_IE_LEN]; > - size_t rsn_ie_len; > - > - u8 mesh; > - > - struct list_head list; > -}; > - > -/** Association request > - * > - * Encapsulates all the options that describe a specific assocation request > - * or configuration of the wireless card's radio, mode, and security settings. > - */ > -struct assoc_request { > -#define ASSOC_FLAG_SSID 1 > -#define ASSOC_FLAG_CHANNEL 2 > -#define ASSOC_FLAG_BAND 3 > -#define ASSOC_FLAG_MODE 4 > -#define ASSOC_FLAG_BSSID 5 > -#define ASSOC_FLAG_WEP_KEYS 6 > -#define ASSOC_FLAG_WEP_TX_KEYIDX 7 > -#define ASSOC_FLAG_WPA_MCAST_KEY 8 > -#define ASSOC_FLAG_WPA_UCAST_KEY 9 > -#define ASSOC_FLAG_SECINFO 10 > -#define ASSOC_FLAG_WPA_IE 11 > - unsigned long flags; > - > - u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; > - u8 ssid_len; > - u8 channel; > - u8 band; > - u8 mode; > - u8 bssid[ETH_ALEN] __attribute__ ((aligned (2))); > - > - /** WEP keys */ > - struct enc_key wep_keys[4]; > - u16 wep_tx_keyidx; > - > - /** WPA keys */ > - struct enc_key wpa_mcast_key; > - struct enc_key wpa_unicast_key; > - > - struct lbs_802_11_security secinfo; > - > - /** WPA Information Elements*/ > - u8 wpa_ie[MAX_WPA_IE_LEN]; > - u8 wpa_ie_len; > - > - /* BSS to associate with for infrastructure of Ad-Hoc join */ > - struct bss_descriptor bss; > -}; > - > - > -extern u8 lbs_bg_rates[MAX_RATES]; > - > -void lbs_association_worker(struct work_struct *work); > -struct assoc_request *lbs_get_association_request(struct lbs_private *priv); > - > -int lbs_adhoc_stop(struct lbs_private *priv); > - > -int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, > - u8 bssid[ETH_ALEN], u16 reason); > - > -int lbs_cmd_802_11_rssi(struct lbs_private *priv, > - struct cmd_ds_command *cmd); > -int lbs_ret_802_11_rssi(struct lbs_private *priv, > - struct cmd_ds_command *resp); > - > -int lbs_cmd_bcn_ctrl(struct lbs_private *priv, > - struct cmd_ds_command *cmd, > - u16 cmd_action); > -int lbs_ret_802_11_bcn_ctrl(struct lbs_private *priv, > - struct cmd_ds_command *resp); > - > -int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action, > - struct assoc_request *assoc); > - > -int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action, > - uint16_t *enable); > - > -int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action, > - struct assoc_request *assoc); > - > -#endif /* _LBS_ASSOC_H */ > --- linux-wl.orig/drivers/net/wireless/libertas/assoc.c > +++ /dev/null > @@ -1,2239 +0,0 @@ > -/* Copyright (C) 2006, Red Hat, Inc. */ > - > -#include > -#include > -#include > -#include > -#include > - > -#include "assoc.h" > -#include "decl.h" > -#include "host.h" > -#include "scan.h" > -#include "cmd.h" > - > -static const u8 bssid_any[ETH_ALEN] __attribute__ ((aligned (2))) = > - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; > -static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) = > - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; > - > -/* The firmware needs the following bits masked out of the beacon-derived > - * capability field when associating/joining to a BSS: > - * 9 (QoS), 11 (APSD), 12 (unused), 14 (unused), 15 (unused) > - */ > -#define CAPINFO_MASK (~(0xda00)) > - > -/** > - * 802.11b/g supported bitrates (in 500Kb/s units) > - */ > -u8 lbs_bg_rates[MAX_RATES] = > - { 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c, > -0x00, 0x00 }; > - > - > -/** > - * @brief This function finds common rates between rates and card rates. > - * > - * It will fill common rates in rates as output if found. > - * > - * NOTE: Setting the MSB of the basic rates need to be taken > - * care, either before or after calling this function > - * > - * @param priv A pointer to struct lbs_private structure > - * @param rates the buffer which keeps input and output > - * @param rates_size the size of rates buffer; new size of buffer on return, > - * which will be less than or equal to original rates_size > - * > - * @return 0 on success, or -1 on error > - */ > -static int get_common_rates(struct lbs_private *priv, > - u8 *rates, > - u16 *rates_size) > -{ > - int i, j; > - u8 intersection[MAX_RATES]; > - u16 intersection_size; > - u16 num_rates = 0; > - > - intersection_size = min_t(u16, *rates_size, ARRAY_SIZE(intersection)); > - > - /* Allow each rate from 'rates' that is supported by the hardware */ > - for (i = 0; i < ARRAY_SIZE(lbs_bg_rates) && lbs_bg_rates[i]; i++) { > - for (j = 0; j < intersection_size && rates[j]; j++) { > - if (rates[j] == lbs_bg_rates[i]) > - intersection[num_rates++] = rates[j]; > - } > - } > - > - lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size); > - lbs_deb_hex(LBS_DEB_JOIN, "card rates ", lbs_bg_rates, > - ARRAY_SIZE(lbs_bg_rates)); > - lbs_deb_hex(LBS_DEB_JOIN, "common rates", intersection, num_rates); > - lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate); > - > - if (!priv->enablehwauto) { > - for (i = 0; i < num_rates; i++) { > - if (intersection[i] == priv->cur_rate) > - goto done; > - } > - lbs_pr_alert("Previously set fixed data rate %#x isn't " > - "compatible with the network.\n", priv->cur_rate); > - return -1; > - } > - > -done: > - memset(rates, 0, *rates_size); > - *rates_size = num_rates; > - memcpy(rates, intersection, num_rates); > - return 0; > -} > - > - > -/** > - * @brief Sets the MSB on basic rates as the firmware requires > - * > - * Scan through an array and set the MSB for basic data rates. > - * > - * @param rates buffer of data rates > - * @param len size of buffer > - */ > -static void lbs_set_basic_rate_flags(u8 *rates, size_t len) > -{ > - int i; > - > - for (i = 0; i < len; i++) { > - if (rates[i] == 0x02 || rates[i] == 0x04 || > - rates[i] == 0x0b || rates[i] == 0x16) > - rates[i] |= 0x80; > - } > -} > - > - > -static u8 iw_auth_to_ieee_auth(u8 auth) > -{ > - if (auth == IW_AUTH_ALG_OPEN_SYSTEM) > - return 0x00; > - else if (auth == IW_AUTH_ALG_SHARED_KEY) > - return 0x01; > - else if (auth == IW_AUTH_ALG_LEAP) > - return 0x80; > - > - lbs_deb_join("%s: invalid auth alg 0x%X\n", __func__, auth); > - return 0; > -} > - > -/** > - * @brief This function prepares the authenticate command. AUTHENTICATE only > - * sets the authentication suite for future associations, as the firmware > - * handles authentication internally during the ASSOCIATE command. > - * > - * @param priv A pointer to struct lbs_private structure > - * @param bssid The peer BSSID with which to authenticate > - * @param auth The authentication mode to use (from wireless.h) > - * > - * @return 0 or -1 > - */ > -static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth) > -{ > - struct cmd_ds_802_11_authenticate cmd; > - int ret = -1; > - > - lbs_deb_enter(LBS_DEB_JOIN); > - > - cmd.hdr.size = cpu_to_le16(sizeof(cmd)); > - memcpy(cmd.bssid, bssid, ETH_ALEN); > - > - cmd.authtype = iw_auth_to_ieee_auth(auth); > - > - lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n", bssid, cmd.authtype); > - > - ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd); > - > - lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); > - return ret; > -} > - > - > -int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action, > - struct assoc_request *assoc) > -{ > - struct cmd_ds_802_11_set_wep cmd; > - int ret = 0; > - > - lbs_deb_enter(LBS_DEB_CMD); > - > - memset(&cmd, 0, sizeof(cmd)); > - cmd.hdr.command = cpu_to_le16(CMD_802_11_SET_WEP); > - cmd.hdr.size = cpu_to_le16(sizeof(cmd)); > - > - cmd.action = cpu_to_le16(cmd_action); > - > - if (cmd_action == CMD_ACT_ADD) { > - int i; > - > - /* default tx key index */ > - cmd.keyindex = cpu_to_le16(assoc->wep_tx_keyidx & > - CMD_WEP_KEY_INDEX_MASK); > - > - /* Copy key types and material to host command structure */ > - for (i = 0; i < 4; i++) { > - struct enc_key *pkey = &assoc->wep_keys[i]; > - > - switch (pkey->len) { > - case KEY_LEN_WEP_40: > - cmd.keytype[i] = CMD_TYPE_WEP_40_BIT; > - memmove(cmd.keymaterial[i], pkey->key, pkey->len); > - lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i); > - break; > - case KEY_LEN_WEP_104: > - cmd.keytype[i] = CMD_TYPE_WEP_104_BIT; > - memmove(cmd.keymaterial[i], pkey->key, pkey->len); > - lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i); > - break; > - case 0: > - break; > - default: > - lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n", > - i, pkey->len); > - ret = -1; > - goto done; > - break; > - } > - } > - } else if (cmd_action == CMD_ACT_REMOVE) { > - /* ACT_REMOVE clears _all_ WEP keys */ > - > - /* default tx key index */ > - cmd.keyindex = cpu_to_le16(priv->wep_tx_keyidx & > - CMD_WEP_KEY_INDEX_MASK); > - lbs_deb_cmd("SET_WEP: remove key %d\n", priv->wep_tx_keyidx); > - } > - > - ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd); > -done: > - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); > - return ret; > -} > - > -int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action, > - uint16_t *enable) > -{ > - struct cmd_ds_802_11_enable_rsn cmd; > - int ret; > - > - lbs_deb_enter(LBS_DEB_CMD); > - > - cmd.hdr.size = cpu_to_le16(sizeof(cmd)); > - cmd.action = cpu_to_le16(cmd_action); > - > - if (cmd_action == CMD_ACT_GET) > - cmd.enable = 0; > - else { > - if (*enable) > - cmd.enable = cpu_to_le16(CMD_ENABLE_RSN); > - else > - cmd.enable = cpu_to_le16(CMD_DISABLE_RSN); > - lbs_deb_cmd("ENABLE_RSN: %d\n", *enable); > - } > - > - ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd); > - if (!ret && cmd_action == CMD_ACT_GET) > - *enable = le16_to_cpu(cmd.enable); > - > - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); > - return ret; > -} > - > -static void set_one_wpa_key(struct MrvlIEtype_keyParamSet *keyparam, > - struct enc_key *key) > -{ > - lbs_deb_enter(LBS_DEB_CMD); > - > - if (key->flags & KEY_INFO_WPA_ENABLED) > - keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED); > - if (key->flags & KEY_INFO_WPA_UNICAST) > - keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST); > - if (key->flags & KEY_INFO_WPA_MCAST) > - keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST); > - > - keyparam->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL); > - keyparam->keytypeid = cpu_to_le16(key->type); > - keyparam->keylen = cpu_to_le16(key->len); > - memcpy(keyparam->key, key->key, key->len); > - > - /* Length field doesn't include the {type,length} header */ > - keyparam->length = cpu_to_le16(sizeof(*keyparam) - 4); > - lbs_deb_leave(LBS_DEB_CMD); > -} > - > -int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action, > - struct assoc_request *assoc) > -{ > - struct cmd_ds_802_11_key_material cmd; > - int ret = 0; > - int index = 0; > - > - lbs_deb_enter(LBS_DEB_CMD); > - > - cmd.action = cpu_to_le16(cmd_action); > - cmd.hdr.size = cpu_to_le16(sizeof(cmd)); > - > - if (cmd_action == CMD_ACT_GET) { > - cmd.hdr.size = cpu_to_le16(sizeof(struct cmd_header) + 2); > - } else { > - memset(cmd.keyParamSet, 0, sizeof(cmd.keyParamSet)); > - > - if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc->flags)) { > - set_one_wpa_key(&cmd.keyParamSet[index], > - &assoc->wpa_unicast_key); > - index++; > - } > - > - if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc->flags)) { > - set_one_wpa_key(&cmd.keyParamSet[index], > - &assoc->wpa_mcast_key); > - index++; > - } > - > - /* The common header and as many keys as we included */ > - cmd.hdr.size = cpu_to_le16(offsetof(typeof(cmd), > - keyParamSet[index])); > - } > - ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd); > - /* Copy the returned key to driver private data */ > - if (!ret && cmd_action == CMD_ACT_GET) { > - void *buf_ptr = cmd.keyParamSet; > - void *resp_end = &(&cmd)[1]; > - > - while (buf_ptr < resp_end) { > - struct MrvlIEtype_keyParamSet *keyparam = buf_ptr; > - struct enc_key *key; > - uint16_t param_set_len = le16_to_cpu(keyparam->length); > - uint16_t key_len = le16_to_cpu(keyparam->keylen); > - uint16_t key_flags = le16_to_cpu(keyparam->keyinfo); > - uint16_t key_type = le16_to_cpu(keyparam->keytypeid); > - void *end; > - > - end = (void *)keyparam + sizeof(keyparam->type) > - + sizeof(keyparam->length) + param_set_len; > - > - /* Make sure we don't access past the end of the IEs */ > - if (end > resp_end) > - break; > - > - if (key_flags & KEY_INFO_WPA_UNICAST) > - key = &priv->wpa_unicast_key; > - else if (key_flags & KEY_INFO_WPA_MCAST) > - key = &priv->wpa_mcast_key; > - else > - break; > - > - /* Copy returned key into driver */ > - memset(key, 0, sizeof(struct enc_key)); > - if (key_len > sizeof(key->key)) > - break; > - key->type = key_type; > - key->flags = key_flags; > - key->len = key_len; > - memcpy(key->key, keyparam->key, key->len); > - > - buf_ptr = end + 1; > - } > - } > - > - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); > - return ret; > -} > - > -static __le16 lbs_rate_to_fw_bitmap(int rate, int lower_rates_ok) > -{ > -/* Bit Rate > -* 15:13 Reserved > -* 12 54 Mbps > -* 11 48 Mbps > -* 10 36 Mbps > -* 9 24 Mbps > -* 8 18 Mbps > -* 7 12 Mbps > -* 6 9 Mbps > -* 5 6 Mbps > -* 4 Reserved > -* 3 11 Mbps > -* 2 5.5 Mbps > -* 1 2 Mbps > -* 0 1 Mbps > -**/ > - > - uint16_t ratemask; > - int i = lbs_data_rate_to_fw_index(rate); > - if (lower_rates_ok) > - ratemask = (0x1fef >> (12 - i)); > - else > - ratemask = (1 << i); > - return cpu_to_le16(ratemask); > -} > - > -int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv, > - uint16_t cmd_action) > -{ > - struct cmd_ds_802_11_rate_adapt_rateset cmd; > - int ret; > - > - lbs_deb_enter(LBS_DEB_CMD); > - > - if (!priv->cur_rate && !priv->enablehwauto) > - return -EINVAL; > - > - cmd.hdr.size = cpu_to_le16(sizeof(cmd)); > - > - cmd.action = cpu_to_le16(cmd_action); > - cmd.enablehwauto = cpu_to_le16(priv->enablehwauto); > - cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto); > - ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, &cmd); > - if (!ret && cmd_action == CMD_ACT_GET) > - priv->enablehwauto = le16_to_cpu(cmd.enablehwauto); > - > - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); > - return ret; > -} > - > -/** > - * @brief Set the data rate > - * > - * @param priv A pointer to struct lbs_private structure > - * @param rate The desired data rate, or 0 to clear a locked rate > - * > - * @return 0 on success, error on failure > - */ > -int lbs_set_data_rate(struct lbs_private *priv, u8 rate) > -{ > - struct cmd_ds_802_11_data_rate cmd; > - int ret = 0; > - > - lbs_deb_enter(LBS_DEB_CMD); > - > - memset(&cmd, 0, sizeof(cmd)); > - cmd.hdr.size = cpu_to_le16(sizeof(cmd)); > - > - if (rate > 0) { > - cmd.action = cpu_to_le16(CMD_ACT_SET_TX_FIX_RATE); > - cmd.rates[0] = lbs_data_rate_to_fw_index(rate); > - if (cmd.rates[0] == 0) { > - lbs_deb_cmd("DATA_RATE: invalid requested rate of" > - " 0x%02X\n", rate); > - ret = 0; > - goto out; > - } > - lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n", cmd.rates[0]); > - } else { > - cmd.action = cpu_to_le16(CMD_ACT_SET_TX_AUTO); > - lbs_deb_cmd("DATA_RATE: setting auto\n"); > - } > - > - ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd); > - if (ret) > - goto out; > - > - lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof(cmd)); > - > - /* FIXME: get actual rates FW can do if this command actually returns > - * all data rates supported. > - */ > - priv->cur_rate = lbs_fw_index_to_data_rate(cmd.rates[0]); > - lbs_deb_cmd("DATA_RATE: current rate is 0x%02x\n", priv->cur_rate); > - > -out: > - lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); > - return ret; > -} > - > - > -int lbs_cmd_802_11_rssi(struct lbs_private *priv, > - struct cmd_ds_command *cmd) > -{ > - > - lbs_deb_enter(LBS_DEB_CMD); > - cmd->command = cpu_to_le16(CMD_802_11_RSSI); > - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + > - sizeof(struct cmd_header)); > - cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR); > - > - /* reset Beacon SNR/NF/RSSI values */ > - priv->SNR[TYPE_BEACON][TYPE_NOAVG] = 0; > - priv->SNR[TYPE_BEACON][TYPE_AVG] = 0; > - priv->NF[TYPE_BEACON][TYPE_NOAVG] = 0; > - priv->NF[TYPE_BEACON][TYPE_AVG] = 0; > - priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0; > - priv->RSSI[TYPE_BEACON][TYPE_AVG] = 0; > - > - lbs_deb_leave(LBS_DEB_CMD); > - return 0; > -} > - > -int lbs_ret_802_11_rssi(struct lbs_private *priv, > - struct cmd_ds_command *resp) > -{ > - struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp; > - > - lbs_deb_enter(LBS_DEB_CMD); > - > - /* store the non average value */ > - priv->SNR[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->SNR); > - priv->NF[TYPE_BEACON][TYPE_NOAVG] = > - get_unaligned_le16(&rssirsp->noisefloor); > - > - priv->SNR[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgSNR); > - priv->NF[TYPE_BEACON][TYPE_AVG] = > - get_unaligned_le16(&rssirsp->avgnoisefloor); > - > - priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = > - CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG], > - priv->NF[TYPE_BEACON][TYPE_NOAVG]); > - > - priv->RSSI[TYPE_BEACON][TYPE_AVG] = > - CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE, > - priv->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE); > - > - lbs_deb_cmd("RSSI: beacon %d, avg %d\n", > - priv->RSSI[TYPE_BEACON][TYPE_NOAVG], > - priv->RSSI[TYPE_BEACON][TYPE_AVG]); > - > - lbs_deb_leave(LBS_DEB_CMD); > - return 0; > -} > - > - > -int lbs_cmd_bcn_ctrl(struct lbs_private *priv, > - struct cmd_ds_command *cmd, > - u16 cmd_action) > -{ > - struct cmd_ds_802_11_beacon_control > - *bcn_ctrl = &cmd->params.bcn_ctrl; > - > - lbs_deb_enter(LBS_DEB_CMD); > - cmd->size = > - cpu_to_le16(sizeof(struct cmd_ds_802_11_beacon_control) > - + sizeof(struct cmd_header)); > - cmd->command = cpu_to_le16(CMD_802_11_BEACON_CTRL); > - > - bcn_ctrl->action = cpu_to_le16(cmd_action); > - bcn_ctrl->beacon_enable = cpu_to_le16(priv->beacon_enable); > - bcn_ctrl->beacon_period = cpu_to_le16(priv->beacon_period); > - > - lbs_deb_leave(LBS_DEB_CMD); > - return 0; > -} > - > -int lbs_ret_802_11_bcn_ctrl(struct lbs_private *priv, > - struct cmd_ds_command *resp) > -{ > - struct cmd_ds_802_11_beacon_control *bcn_ctrl = > - &resp->params.bcn_ctrl; > - > - lbs_deb_enter(LBS_DEB_CMD); > - > - if (bcn_ctrl->action == CMD_ACT_GET) { > - priv->beacon_enable = (u8) le16_to_cpu(bcn_ctrl->beacon_enable); > - priv->beacon_period = le16_to_cpu(bcn_ctrl->beacon_period); > - } > - > - lbs_deb_enter(LBS_DEB_CMD); > - return 0; > -} > - > - > - > -static int lbs_assoc_post(struct lbs_private *priv, > - struct cmd_ds_802_11_associate_response *resp) > -{ > - int ret = 0; > - union iwreq_data wrqu; > - struct bss_descriptor *bss; > - u16 status_code; > - > - lbs_deb_enter(LBS_DEB_ASSOC); > - > - if (!priv->in_progress_assoc_req) { > - lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n"); > - ret = -1; > - goto done; > - } > - bss = &priv->in_progress_assoc_req->bss; > - > - /* > - * Older FW versions map the IEEE 802.11 Status Code in the association > - * response to the following values returned in resp->statuscode: > - * > - * IEEE Status Code Marvell Status Code > - * 0 -> 0x0000 ASSOC_RESULT_SUCCESS > - * 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED > - * 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED > - * 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED > - * 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED > - * others -> 0x0003 ASSOC_RESULT_REFUSED > - * > - * Other response codes: > - * 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused) > - * 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for > - * association response from the AP) > - */ > - > - status_code = le16_to_cpu(resp->statuscode); > - if (priv->fwrelease < 0x09000000) { > - switch (status_code) { > - case 0x00: > - break; > - case 0x01: > - lbs_deb_assoc("ASSOC_RESP: invalid parameters\n"); > - break; > - case 0x02: > - lbs_deb_assoc("ASSOC_RESP: internal timer " > - "expired while waiting for the AP\n"); > - break; > - case 0x03: > - lbs_deb_assoc("ASSOC_RESP: association " > - "refused by AP\n"); > - break; > - case 0x04: > - lbs_deb_assoc("ASSOC_RESP: authentication " > - "refused by AP\n"); > - break; > - default: > - lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x " > - " unknown\n", status_code); > - break; > - } > - } else { > - /* v9+ returns the AP's association response */ > - lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x\n", status_code); > - } > - > - if (status_code) { > - lbs_mac_event_disconnected(priv); > - ret = -1; > - goto done; > - } > - > - lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP", > - (void *) (resp + sizeof (resp->hdr)), > - le16_to_cpu(resp->hdr.size) - sizeof (resp->hdr)); > - > - /* Send a Media Connected event, according to the Spec */ > - priv->connect_status = LBS_CONNECTED; > - > - /* Update current SSID and BSSID */ > - memcpy(&priv->curbssparams.ssid, &bss->ssid, IEEE80211_MAX_SSID_LEN); > - priv->curbssparams.ssid_len = bss->ssid_len; > - memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN); > - > - priv->SNR[TYPE_RXPD][TYPE_AVG] = 0; > - priv->NF[TYPE_RXPD][TYPE_AVG] = 0; > - > - memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR)); > - memset(priv->rawNF, 0x00, sizeof(priv->rawNF)); > - priv->nextSNRNF = 0; > - priv->numSNRNF = 0; > - > - netif_carrier_on(priv->dev); > - if (!priv->tx_pending_len) > - netif_wake_queue(priv->dev); > - > - memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); > - wrqu.ap_addr.sa_family = ARPHRD_ETHER; > - wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); > - > -done: > - lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); > - return ret; > -} > - > -/** > - * @brief This function prepares an association-class command. > - * > - * @param priv A pointer to struct lbs_private structure > - * @param assoc_req The association request describing the BSS to associate > - * or reassociate with > - * @param command The actual command, either CMD_802_11_ASSOCIATE or > - * CMD_802_11_REASSOCIATE > - * > - * @return 0 or -1 > - */ > -static int lbs_associate(struct lbs_private *priv, > - struct assoc_request *assoc_req, > - u16 command) > -{ > - struct cmd_ds_802_11_associate cmd; > - int ret = 0; > - struct bss_descriptor *bss = &assoc_req->bss; > - u8 *pos = &(cmd.iebuf[0]); > - u16 tmpcap, tmplen, tmpauth; > - struct mrvl_ie_ssid_param_set *ssid; > - struct mrvl_ie_ds_param_set *ds; > - struct mrvl_ie_cf_param_set *cf; > - struct mrvl_ie_rates_param_set *rates; > - struct mrvl_ie_rsn_param_set *rsn; > - struct mrvl_ie_auth_type *auth; > - > - lbs_deb_enter(LBS_DEB_ASSOC); > - > - BUG_ON((command != CMD_802_11_ASSOCIATE) && > - (command != CMD_802_11_REASSOCIATE)); > - > - memset(&cmd, 0, sizeof(cmd)); > - cmd.hdr.command = cpu_to_le16(command); > - > - /* Fill in static fields */ > - memcpy(cmd.bssid, bss->bssid, ETH_ALEN); > - cmd.listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL); > - > - /* Capability info */ > - tmpcap = (bss->capability & CAPINFO_MASK); > - if (bss->mode == IW_MODE_INFRA) > - tmpcap |= WLAN_CAPABILITY_ESS; > - cmd.capability = cpu_to_le16(tmpcap); > - lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap); > - > - /* SSID */ > - ssid = (struct mrvl_ie_ssid_param_set *) pos; > - ssid->header.type = cpu_to_le16(TLV_TYPE_SSID); > - tmplen = bss->ssid_len; > - ssid->header.len = cpu_to_le16(tmplen); > - memcpy(ssid->ssid, bss->ssid, tmplen); > - pos += sizeof(ssid->header) + tmplen; > - > - ds = (struct mrvl_ie_ds_param_set *) pos; > - ds->header.type = cpu_to_le16(TLV_TYPE_PHY_DS); > - ds->header.len = cpu_to_le16(1); > - ds->channel = bss->phy.ds.channel; > - pos += sizeof(ds->header) + 1; > - > - cf = (struct mrvl_ie_cf_param_set *) pos; > - cf->header.type = cpu_to_le16(TLV_TYPE_CF); > - tmplen = sizeof(*cf) - sizeof (cf->header); > - cf->header.len = cpu_to_le16(tmplen); > - /* IE payload should be zeroed, firmware fills it in for us */ > - pos += sizeof(*cf); > - > - rates = (struct mrvl_ie_rates_param_set *) pos; > - rates->header.type = cpu_to_le16(TLV_TYPE_RATES); > - tmplen = min_t(u16, ARRAY_SIZE(bss->rates), MAX_RATES); > - memcpy(&rates->rates, &bss->rates, tmplen); > - if (get_common_rates(priv, rates->rates, &tmplen)) { > - ret = -1; > - goto done; > - } > - pos += sizeof(rates->header) + tmplen; > - rates->header.len = cpu_to_le16(tmplen); > - lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen); > - > - /* Copy the infra. association rates into Current BSS state structure */ > - memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); > - memcpy(&priv->curbssparams.rates, &rates->rates, tmplen); > - > - /* Set MSB on basic rates as the firmware requires, but _after_ > - * copying to current bss rates. > - */ > - lbs_set_basic_rate_flags(rates->rates, tmplen); > - > - /* Firmware v9+ indicate authentication suites as a TLV */ > - if (priv->fwrelease >= 0x09000000) { > - auth = (struct mrvl_ie_auth_type *) pos; > - auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE); > - auth->header.len = cpu_to_le16(2); > - tmpauth = iw_auth_to_ieee_auth(priv->secinfo.auth_mode); > - auth->auth = cpu_to_le16(tmpauth); > - pos += sizeof(auth->header) + 2; > - > - lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n", > - bss->bssid, priv->secinfo.auth_mode); > - } > - > - /* WPA/WPA2 IEs */ > - if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) { > - rsn = (struct mrvl_ie_rsn_param_set *) pos; > - /* WPA_IE or WPA2_IE */ > - rsn->header.type = cpu_to_le16((u16) assoc_req->wpa_ie[0]); > - tmplen = (u16) assoc_req->wpa_ie[1]; > - rsn->header.len = cpu_to_le16(tmplen); > - memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen); > - lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: WPA/RSN IE", (u8 *) rsn, > - sizeof(rsn->header) + tmplen); > - pos += sizeof(rsn->header) + tmplen; > - } > - > - cmd.hdr.size = cpu_to_le16((sizeof(cmd) - sizeof(cmd.iebuf)) + > - (u16)(pos - (u8 *) &cmd.iebuf)); > - > - /* update curbssparams */ > - priv->channel = bss->phy.ds.channel; > - > - ret = lbs_cmd_with_response(priv, command, &cmd); > - if (ret == 0) { > - ret = lbs_assoc_post(priv, > - (struct cmd_ds_802_11_associate_response *) &cmd); > - } > - > -done: > - lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); > - return ret; > -} > - > -/** > - * @brief Associate to a specific BSS discovered in a scan > - * > - * @param priv A pointer to struct lbs_private structure > - * @param assoc_req The association request describing the BSS to associate with > - * > - * @return 0-success, otherwise fail > - */ > -static int lbs_try_associate(struct lbs_private *priv, > - struct assoc_request *assoc_req) > -{ > - int ret; > - u8 preamble = RADIO_PREAMBLE_LONG; > - > - lbs_deb_enter(LBS_DEB_ASSOC); > - > - /* FW v9 and higher indicate authentication suites as a TLV in the > - * association command, not as a separate authentication command. > - */ > - if (priv->fwrelease < 0x09000000) { > - ret = lbs_set_authentication(priv, assoc_req->bss.bssid, > - priv->secinfo.auth_mode); > - if (ret) > - goto out; > - } > - > - /* Use short preamble only when both the BSS and firmware support it */ > - if (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE) > - preamble = RADIO_PREAMBLE_SHORT; > - > - ret = lbs_set_radio(priv, preamble, 1); > - if (ret) > - goto out; > - > - ret = lbs_associate(priv, assoc_req, CMD_802_11_ASSOCIATE); > - > -out: > - lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); > - return ret; > -} > - > -static int lbs_adhoc_post(struct lbs_private *priv, > - struct cmd_ds_802_11_ad_hoc_result *resp) > -{ > - int ret = 0; > - u16 command = le16_to_cpu(resp->hdr.command); > - u16 result = le16_to_cpu(resp->hdr.result); > - union iwreq_data wrqu; > - struct bss_descriptor *bss; > - DECLARE_SSID_BUF(ssid); > - > - lbs_deb_enter(LBS_DEB_JOIN); > - > - if (!priv->in_progress_assoc_req) { > - lbs_deb_join("ADHOC_RESP: no in-progress association " > - "request\n"); > - ret = -1; > - goto done; > - } > - bss = &priv->in_progress_assoc_req->bss; > - > - /* > - * Join result code 0 --> SUCCESS > - */ > - if (result) { > - lbs_deb_join("ADHOC_RESP: failed (result 0x%X)\n", result); > - if (priv->connect_status == LBS_CONNECTED) > - lbs_mac_event_disconnected(priv); > - ret = -1; > - goto done; > - } > - > - /* Send a Media Connected event, according to the Spec */ > - priv->connect_status = LBS_CONNECTED; > - > - if (command == CMD_RET(CMD_802_11_AD_HOC_START)) { > - /* Update the created network descriptor with the new BSSID */ > - memcpy(bss->bssid, resp->bssid, ETH_ALEN); > - } > - > - /* Set the BSSID from the joined/started descriptor */ > - memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN); > - > - /* Set the new SSID to current SSID */ > - memcpy(&priv->curbssparams.ssid, &bss->ssid, IEEE80211_MAX_SSID_LEN); > - priv->curbssparams.ssid_len = bss->ssid_len; > - > - netif_carrier_on(priv->dev); > - if (!priv->tx_pending_len) > - netif_wake_queue(priv->dev); > - > - memset(&wrqu, 0, sizeof(wrqu)); > - memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); > - wrqu.ap_addr.sa_family = ARPHRD_ETHER; > - wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); > - > - lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n", > - print_ssid(ssid, bss->ssid, bss->ssid_len), > - priv->curbssparams.bssid, > - priv->channel); > - > -done: > - lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); > - return ret; > -} > - > -/** > - * @brief Join an adhoc network found in a previous scan > - * > - * @param priv A pointer to struct lbs_private structure > - * @param assoc_req The association request describing the BSS to join > - * > - * @return 0 on success, error on failure > - */ > -static int lbs_adhoc_join(struct lbs_private *priv, > - struct assoc_request *assoc_req) > -{ > - struct cmd_ds_802_11_ad_hoc_join cmd; > - struct bss_descriptor *bss = &assoc_req->bss; > - u8 preamble = RADIO_PREAMBLE_LONG; > - DECLARE_SSID_BUF(ssid); > - u16 ratesize = 0; > - int ret = 0; > - > - lbs_deb_enter(LBS_DEB_ASSOC); > - > - lbs_deb_join("current SSID '%s', ssid length %u\n", > - print_ssid(ssid, priv->curbssparams.ssid, > - priv->curbssparams.ssid_len), > - priv->curbssparams.ssid_len); > - lbs_deb_join("requested ssid '%s', ssid length %u\n", > - print_ssid(ssid, bss->ssid, bss->ssid_len), > - bss->ssid_len); > - > - /* check if the requested SSID is already joined */ > - if (priv->curbssparams.ssid_len && > - !lbs_ssid_cmp(priv->curbssparams.ssid, > - priv->curbssparams.ssid_len, > - bss->ssid, bss->ssid_len) && > - (priv->mode == IW_MODE_ADHOC) && > - (priv->connect_status == LBS_CONNECTED)) { > - union iwreq_data wrqu; > - > - lbs_deb_join("ADHOC_J_CMD: New ad-hoc SSID is the same as " > - "current, not attempting to re-join"); > - > - /* Send the re-association event though, because the association > - * request really was successful, even if just a null-op. > - */ > - memset(&wrqu, 0, sizeof(wrqu)); > - memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, > - ETH_ALEN); > - wrqu.ap_addr.sa_family = ARPHRD_ETHER; > - wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); > - goto out; > - } > - > - /* Use short preamble only when both the BSS and firmware support it */ > - if (bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) { > - lbs_deb_join("AdhocJoin: Short preamble\n"); > - preamble = RADIO_PREAMBLE_SHORT; > - } > - > - ret = lbs_set_radio(priv, preamble, 1); > - if (ret) > - goto out; > - > - lbs_deb_join("AdhocJoin: channel = %d\n", assoc_req->channel); > - lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band); > - > - priv->adhoccreate = 0; > - priv->channel = bss->channel; > - > - /* Build the join command */ > - memset(&cmd, 0, sizeof(cmd)); > - cmd.hdr.size = cpu_to_le16(sizeof(cmd)); > - > - cmd.bss.type = CMD_BSS_TYPE_IBSS; > - cmd.bss.beaconperiod = cpu_to_le16(bss->beaconperiod); > - > - memcpy(&cmd.bss.bssid, &bss->bssid, ETH_ALEN); > - memcpy(&cmd.bss.ssid, &bss->ssid, bss->ssid_len); > - > - memcpy(&cmd.bss.ds, &bss->phy.ds, sizeof(struct ieee_ie_ds_param_set)); > - > - memcpy(&cmd.bss.ibss, &bss->ss.ibss, > - sizeof(struct ieee_ie_ibss_param_set)); > - > - cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK); > - lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n", > - bss->capability, CAPINFO_MASK); > - > - /* information on BSSID descriptor passed to FW */ > - lbs_deb_join("ADHOC_J_CMD: BSSID = %pM, SSID = '%s'\n", > - cmd.bss.bssid, cmd.bss.ssid); > - > - /* Only v8 and below support setting these */ > - if (priv->fwrelease < 0x09000000) { > - /* failtimeout */ > - cmd.failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT); > - /* probedelay */ > - cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); > - } > - > - /* Copy Data rates from the rates recorded in scan response */ > - memset(cmd.bss.rates, 0, sizeof(cmd.bss.rates)); > - ratesize = min_t(u16, ARRAY_SIZE(cmd.bss.rates), ARRAY_SIZE (bss->rates)); > - memcpy(cmd.bss.rates, bss->rates, ratesize); > - if (get_common_rates(priv, cmd.bss.rates, &ratesize)) { > - lbs_deb_join("ADHOC_JOIN: get_common_rates returned error.\n"); > - ret = -1; > - goto out; > - } > - > - /* Copy the ad-hoc creation rates into Current BSS state structure */ > - memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); > - memcpy(&priv->curbssparams.rates, cmd.bss.rates, ratesize); > - > - /* Set MSB on basic rates as the firmware requires, but _after_ > - * copying to current bss rates. > - */ > - lbs_set_basic_rate_flags(cmd.bss.rates, ratesize); > - > - cmd.bss.ibss.atimwindow = bss->atimwindow; > - > - if (assoc_req->secinfo.wep_enabled) { > - u16 tmp = le16_to_cpu(cmd.bss.capability); > - tmp |= WLAN_CAPABILITY_PRIVACY; > - cmd.bss.capability = cpu_to_le16(tmp); > - } > - > - if (priv->psmode == LBS802_11POWERMODEMAX_PSP) { > - __le32 local_ps_mode = cpu_to_le32(LBS802_11POWERMODECAM); > - > - /* wake up first */ > - ret = lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE, > - CMD_ACT_SET, 0, 0, > - &local_ps_mode); > - if (ret) { > - ret = -1; > - goto out; > - } > - } > - > - ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd); > - if (ret == 0) { > - ret = lbs_adhoc_post(priv, > - (struct cmd_ds_802_11_ad_hoc_result *)&cmd); > - } > - > -out: > - lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); > - return ret; > -} > - > -/** > - * @brief Start an Adhoc Network > - * > - * @param priv A pointer to struct lbs_private structure > - * @param assoc_req The association request describing the BSS to start > - * > - * @return 0 on success, error on failure > - */ > -static int lbs_adhoc_start(struct lbs_private *priv, > - struct assoc_request *assoc_req) > -{ > - struct cmd_ds_802_11_ad_hoc_start cmd; > - u8 preamble = RADIO_PREAMBLE_SHORT; > - size_t ratesize = 0; > - u16 tmpcap = 0; > - int ret = 0; > - DECLARE_SSID_BUF(ssid); > - > - lbs_deb_enter(LBS_DEB_ASSOC); > - > - ret = lbs_set_radio(priv, preamble, 1); > - if (ret) > - goto out; > - > - /* Build the start command */ > - memset(&cmd, 0, sizeof(cmd)); > - cmd.hdr.size = cpu_to_le16(sizeof(cmd)); > - > - memcpy(cmd.ssid, assoc_req->ssid, assoc_req->ssid_len); > - > - lbs_deb_join("ADHOC_START: SSID '%s', ssid length %u\n", > - print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len), > - assoc_req->ssid_len); > - > - cmd.bsstype = CMD_BSS_TYPE_IBSS; > - > - if (priv->beacon_period == 0) > - priv->beacon_period = MRVDRV_BEACON_INTERVAL; > - cmd.beaconperiod = cpu_to_le16(priv->beacon_period); > - > - WARN_ON(!assoc_req->channel); > - > - /* set Physical parameter set */ > - cmd.ds.header.id = WLAN_EID_DS_PARAMS; > - cmd.ds.header.len = 1; > - cmd.ds.channel = assoc_req->channel; > - > - /* set IBSS parameter set */ > - cmd.ibss.header.id = WLAN_EID_IBSS_PARAMS; > - cmd.ibss.header.len = 2; > - cmd.ibss.atimwindow = cpu_to_le16(0); > - > - /* set capability info */ > - tmpcap = WLAN_CAPABILITY_IBSS; > - if (assoc_req->secinfo.wep_enabled || > - assoc_req->secinfo.WPAenabled || > - assoc_req->secinfo.WPA2enabled) { > - lbs_deb_join("ADHOC_START: WEP/WPA enabled, privacy on\n"); > - tmpcap |= WLAN_CAPABILITY_PRIVACY; > - } else > - lbs_deb_join("ADHOC_START: WEP disabled, privacy off\n"); > - > - cmd.capability = cpu_to_le16(tmpcap); > - > - /* Only v8 and below support setting probe delay */ > - if (priv->fwrelease < 0x09000000) > - cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); > - > - ratesize = min(sizeof(cmd.rates), sizeof(lbs_bg_rates)); > - memcpy(cmd.rates, lbs_bg_rates, ratesize); > - > - /* Copy the ad-hoc creating rates into Current BSS state structure */ > - memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); > - memcpy(&priv->curbssparams.rates, &cmd.rates, ratesize); > - > - /* Set MSB on basic rates as the firmware requires, but _after_ > - * copying to current bss rates. > - */ > - lbs_set_basic_rate_flags(cmd.rates, ratesize); > - > - lbs_deb_join("ADHOC_START: rates=%02x %02x %02x %02x\n", > - cmd.rates[0], cmd.rates[1], cmd.rates[2], cmd.rates[3]); > - > - lbs_deb_join("ADHOC_START: Starting Ad-Hoc BSS on channel %d, band %d\n", > - assoc_req->channel, assoc_req->band); > - > - priv->adhoccreate = 1; > - priv->mode = IW_MODE_ADHOC; > - > - ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_START, &cmd); > - if (ret == 0) > - ret = lbs_adhoc_post(priv, > - (struct cmd_ds_802_11_ad_hoc_result *)&cmd); > - > -out: > - lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); > - return ret; > -} > - > -/** > - * @brief Stop and Ad-Hoc network and exit Ad-Hoc mode > - * > - * @param priv A pointer to struct lbs_private structure > - * @return 0 on success, or an error > - */ > -int lbs_adhoc_stop(struct lbs_private *priv) > -{ > - struct cmd_ds_802_11_ad_hoc_stop cmd; > - int ret; > - > - lbs_deb_enter(LBS_DEB_JOIN); > - > - memset(&cmd, 0, sizeof (cmd)); > - cmd.hdr.size = cpu_to_le16 (sizeof (cmd)); > - > - ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_STOP, &cmd); > - > - /* Clean up everything even if there was an error */ > - lbs_mac_event_disconnected(priv); > - > - lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); > - return ret; > -} > - > -static inline int match_bss_no_security(struct lbs_802_11_security *secinfo, > - struct bss_descriptor *match_bss) > -{ > - if (!secinfo->wep_enabled && !secinfo->WPAenabled > - && !secinfo->WPA2enabled > - && match_bss->wpa_ie[0] != WLAN_EID_GENERIC > - && match_bss->rsn_ie[0] != WLAN_EID_RSN > - && !(match_bss->capability & WLAN_CAPABILITY_PRIVACY)) > - return 1; > - else > - return 0; > -} > - > -static inline int match_bss_static_wep(struct lbs_802_11_security *secinfo, > - struct bss_descriptor *match_bss) > -{ > - if (secinfo->wep_enabled && !secinfo->WPAenabled > - && !secinfo->WPA2enabled > - && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) > - return 1; > - else > - return 0; > -} > - > -static inline int match_bss_wpa(struct lbs_802_11_security *secinfo, > - struct bss_descriptor *match_bss) > -{ > - if (!secinfo->wep_enabled && secinfo->WPAenabled > - && (match_bss->wpa_ie[0] == WLAN_EID_GENERIC) > - /* privacy bit may NOT be set in some APs like LinkSys WRT54G > - && (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */ > - ) > - return 1; > - else > - return 0; > -} > - > -static inline int match_bss_wpa2(struct lbs_802_11_security *secinfo, > - struct bss_descriptor *match_bss) > -{ > - if (!secinfo->wep_enabled && secinfo->WPA2enabled && > - (match_bss->rsn_ie[0] == WLAN_EID_RSN) > - /* privacy bit may NOT be set in some APs like LinkSys WRT54G > - (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */ > - ) > - return 1; > - else > - return 0; > -} > - > -static inline int match_bss_dynamic_wep(struct lbs_802_11_security *secinfo, > - struct bss_descriptor *match_bss) > -{ > - if (!secinfo->wep_enabled && !secinfo->WPAenabled > - && !secinfo->WPA2enabled > - && (match_bss->wpa_ie[0] != WLAN_EID_GENERIC) > - && (match_bss->rsn_ie[0] != WLAN_EID_RSN) > - && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) > - return 1; > - else > - return 0; > -} > - > -/** > - * @brief Check if a scanned network compatible with the driver settings > - * > - * WEP WPA WPA2 ad-hoc encrypt Network > - * enabled enabled enabled AES mode privacy WPA WPA2 Compatible > - * 0 0 0 0 NONE 0 0 0 yes No security > - * 1 0 0 0 NONE 1 0 0 yes Static WEP > - * 0 1 0 0 x 1x 1 x yes WPA > - * 0 0 1 0 x 1x x 1 yes WPA2 > - * 0 0 0 1 NONE 1 0 0 yes Ad-hoc AES > - * 0 0 0 0 !=NONE 1 0 0 yes Dynamic WEP > - * > - * > - * @param priv A pointer to struct lbs_private > - * @param index Index in scantable to check against current driver settings > - * @param mode Network mode: Infrastructure or IBSS > - * > - * @return Index in scantable, or error code if negative > - */ > -static int is_network_compatible(struct lbs_private *priv, > - struct bss_descriptor *bss, uint8_t mode) > -{ > - int matched = 0; > - > - lbs_deb_enter(LBS_DEB_SCAN); > - > - if (bss->mode != mode) > - goto done; > - > - matched = match_bss_no_security(&priv->secinfo, bss); > - if (matched) > - goto done; > - matched = match_bss_static_wep(&priv->secinfo, bss); > - if (matched) > - goto done; > - matched = match_bss_wpa(&priv->secinfo, bss); > - if (matched) { > - lbs_deb_scan("is_network_compatible() WPA: wpa_ie 0x%x " > - "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s " > - "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0], > - priv->secinfo.wep_enabled ? "e" : "d", > - priv->secinfo.WPAenabled ? "e" : "d", > - priv->secinfo.WPA2enabled ? "e" : "d", > - (bss->capability & WLAN_CAPABILITY_PRIVACY)); > - goto done; > - } > - matched = match_bss_wpa2(&priv->secinfo, bss); > - if (matched) { > - lbs_deb_scan("is_network_compatible() WPA2: wpa_ie 0x%x " > - "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s " > - "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0], > - priv->secinfo.wep_enabled ? "e" : "d", > - priv->secinfo.WPAenabled ? "e" : "d", > - priv->secinfo.WPA2enabled ? "e" : "d", > - (bss->capability & WLAN_CAPABILITY_PRIVACY)); > - goto done; > - } > - matched = match_bss_dynamic_wep(&priv->secinfo, bss); > - if (matched) { > - lbs_deb_scan("is_network_compatible() dynamic WEP: " > - "wpa_ie 0x%x wpa2_ie 0x%x privacy 0x%x\n", > - bss->wpa_ie[0], bss->rsn_ie[0], > - (bss->capability & WLAN_CAPABILITY_PRIVACY)); > - goto done; > - } > - > - /* bss security settings don't match those configured on card */ > - lbs_deb_scan("is_network_compatible() FAILED: wpa_ie 0x%x " > - "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s privacy 0x%x\n", > - bss->wpa_ie[0], bss->rsn_ie[0], > - priv->secinfo.wep_enabled ? "e" : "d", > - priv->secinfo.WPAenabled ? "e" : "d", > - priv->secinfo.WPA2enabled ? "e" : "d", > - (bss->capability & WLAN_CAPABILITY_PRIVACY)); > - > -done: > - lbs_deb_leave_args(LBS_DEB_SCAN, "matched: %d", matched); > - return matched; > -} > - > -/** > - * @brief This function finds a specific compatible BSSID in the scan list > - * > - * Used in association code > - * > - * @param priv A pointer to struct lbs_private > - * @param bssid BSSID to find in the scan list > - * @param mode Network mode: Infrastructure or IBSS > - * > - * @return index in BSSID list, or error return code (< 0) > - */ > -static struct bss_descriptor *lbs_find_bssid_in_list(struct lbs_private *priv, > - uint8_t *bssid, uint8_t mode) > -{ > - struct bss_descriptor *iter_bss; > - struct bss_descriptor *found_bss = NULL; > - > - lbs_deb_enter(LBS_DEB_SCAN); > - > - if (!bssid) > - goto out; > - > - lbs_deb_hex(LBS_DEB_SCAN, "looking for", bssid, ETH_ALEN); > - > - /* Look through the scan table for a compatible match. The loop will > - * continue past a matched bssid that is not compatible in case there > - * is an AP with multiple SSIDs assigned to the same BSSID > - */ > - mutex_lock(&priv->lock); > - list_for_each_entry(iter_bss, &priv->network_list, list) { > - if (compare_ether_addr(iter_bss->bssid, bssid)) > - continue; /* bssid doesn't match */ > - switch (mode) { > - case IW_MODE_INFRA: > - case IW_MODE_ADHOC: > - if (!is_network_compatible(priv, iter_bss, mode)) > - break; > - found_bss = iter_bss; > - break; > - default: > - found_bss = iter_bss; > - break; > - } > - } > - mutex_unlock(&priv->lock); > - > -out: > - lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss); > - return found_bss; > -} > - > -/** > - * @brief This function finds ssid in ssid list. > - * > - * Used in association code > - * > - * @param priv A pointer to struct lbs_private > - * @param ssid SSID to find in the list > - * @param bssid BSSID to qualify the SSID selection (if provided) > - * @param mode Network mode: Infrastructure or IBSS > - * > - * @return index in BSSID list > - */ > -static struct bss_descriptor *lbs_find_ssid_in_list(struct lbs_private *priv, > - uint8_t *ssid, uint8_t ssid_len, > - uint8_t *bssid, uint8_t mode, > - int channel) > -{ > - u32 bestrssi = 0; > - struct bss_descriptor *iter_bss = NULL; > - struct bss_descriptor *found_bss = NULL; > - struct bss_descriptor *tmp_oldest = NULL; > - > - lbs_deb_enter(LBS_DEB_SCAN); > - > - mutex_lock(&priv->lock); > - > - list_for_each_entry(iter_bss, &priv->network_list, list) { > - if (!tmp_oldest || > - (iter_bss->last_scanned < tmp_oldest->last_scanned)) > - tmp_oldest = iter_bss; > - > - if (lbs_ssid_cmp(iter_bss->ssid, iter_bss->ssid_len, > - ssid, ssid_len) != 0) > - continue; /* ssid doesn't match */ > - if (bssid && compare_ether_addr(iter_bss->bssid, bssid) != 0) > - continue; /* bssid doesn't match */ > - if ((channel > 0) && (iter_bss->channel != channel)) > - continue; /* channel doesn't match */ > - > - switch (mode) { > - case IW_MODE_INFRA: > - case IW_MODE_ADHOC: > - if (!is_network_compatible(priv, iter_bss, mode)) > - break; > - > - if (bssid) { > - /* Found requested BSSID */ > - found_bss = iter_bss; > - goto out; > - } > - > - if (SCAN_RSSI(iter_bss->rssi) > bestrssi) { > - bestrssi = SCAN_RSSI(iter_bss->rssi); > - found_bss = iter_bss; > - } > - break; > - case IW_MODE_AUTO: > - default: > - if (SCAN_RSSI(iter_bss->rssi) > bestrssi) { > - bestrssi = SCAN_RSSI(iter_bss->rssi); > - found_bss = iter_bss; > - } > - break; > - } > - } > - > -out: > - mutex_unlock(&priv->lock); > - lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss); > - return found_bss; > -} > - > -static int assoc_helper_essid(struct lbs_private *priv, > - struct assoc_request * assoc_req) > -{ > - int ret = 0; > - struct bss_descriptor * bss; > - int channel = -1; > - DECLARE_SSID_BUF(ssid); > - > - lbs_deb_enter(LBS_DEB_ASSOC); > - > - /* FIXME: take channel into account when picking SSIDs if a channel > - * is set. > - */ > - > - if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) > - channel = assoc_req->channel; > - > - lbs_deb_assoc("SSID '%s' requested\n", > - print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len)); > - if (assoc_req->mode == IW_MODE_INFRA) { > - lbs_send_specific_ssid_scan(priv, assoc_req->ssid, > - assoc_req->ssid_len); > - > - bss = lbs_find_ssid_in_list(priv, assoc_req->ssid, > - assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel); > - if (bss != NULL) { > - memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor)); > - ret = lbs_try_associate(priv, assoc_req); > - } else { > - lbs_deb_assoc("SSID not found; cannot associate\n"); > - } > - } else if (assoc_req->mode == IW_MODE_ADHOC) { > - /* Scan for the network, do not save previous results. Stale > - * scan data will cause us to join a non-existant adhoc network > - */ > - lbs_send_specific_ssid_scan(priv, assoc_req->ssid, > - assoc_req->ssid_len); > - > - /* Search for the requested SSID in the scan table */ > - bss = lbs_find_ssid_in_list(priv, assoc_req->ssid, > - assoc_req->ssid_len, NULL, IW_MODE_ADHOC, channel); > - if (bss != NULL) { > - lbs_deb_assoc("SSID found, will join\n"); > - memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor)); > - lbs_adhoc_join(priv, assoc_req); > - } else { > - /* else send START command */ > - lbs_deb_assoc("SSID not found, creating adhoc network\n"); > - memcpy(&assoc_req->bss.ssid, &assoc_req->ssid, > - IEEE80211_MAX_SSID_LEN); > - assoc_req->bss.ssid_len = assoc_req->ssid_len; > - lbs_adhoc_start(priv, assoc_req); > - } > - } > - > - lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); > - return ret; > -} > - > - > -static int assoc_helper_bssid(struct lbs_private *priv, > - struct assoc_request * assoc_req) > -{ > - int ret = 0; > - struct bss_descriptor * bss; > - > - lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID %pM", assoc_req->bssid); > - > - /* Search for index position in list for requested MAC */ > - bss = lbs_find_bssid_in_list(priv, assoc_req->bssid, > - assoc_req->mode); > - if (bss == NULL) { > - lbs_deb_assoc("ASSOC: WAP: BSSID %pM not found, " > - "cannot associate.\n", assoc_req->bssid); > - goto out; > - } > - > - memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor)); > - if (assoc_req->mode == IW_MODE_INFRA) { > - ret = lbs_try_associate(priv, assoc_req); > - lbs_deb_assoc("ASSOC: lbs_try_associate(bssid) returned %d\n", > - ret); > - } else if (assoc_req->mode == IW_MODE_ADHOC) { > - lbs_adhoc_join(priv, assoc_req); > - } > - > -out: > - lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); > - return ret; > -} > - > - > -static int assoc_helper_associate(struct lbs_private *priv, > - struct assoc_request * assoc_req) > -{ > - int ret = 0, done = 0; > - > - lbs_deb_enter(LBS_DEB_ASSOC); > - > - /* If we're given and 'any' BSSID, try associating based on SSID */ > - > - if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) { > - if (compare_ether_addr(bssid_any, assoc_req->bssid) > - && compare_ether_addr(bssid_off, assoc_req->bssid)) { > - ret = assoc_helper_bssid(priv, assoc_req); > - done = 1; > - } > - } > - > - if (!done && test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { > - ret = assoc_helper_essid(priv, assoc_req); > - } > - > - lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); > - return ret; > -} > - > - > -static int assoc_helper_mode(struct lbs_private *priv, > - struct assoc_request * assoc_req) > -{ > - int ret = 0; > - > - lbs_deb_enter(LBS_DEB_ASSOC); > - > - if (assoc_req->mode == priv->mode) > - goto done; > - > - if (assoc_req->mode == IW_MODE_INFRA) { > - if (priv->psstate != PS_STATE_FULL_POWER) > - lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP); > - priv->psmode = LBS802_11POWERMODECAM; > - } > - > - priv->mode = assoc_req->mode; > - ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, > - assoc_req->mode == IW_MODE_ADHOC ? 2 : 1); > - > -done: > - lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); > - return ret; > -} > - > -static int assoc_helper_channel(struct lbs_private *priv, > - struct assoc_request * assoc_req) > -{ > - int ret = 0; > - > - lbs_deb_enter(LBS_DEB_ASSOC); > - > - ret = lbs_update_channel(priv); > - if (ret) { > - lbs_deb_assoc("ASSOC: channel: error getting channel.\n"); > - goto done; > - } > - > - if (assoc_req->channel == priv->channel) > - goto done; > - > - if (priv->mesh_dev) { > - /* Change mesh channel first; 21.p21 firmware won't let > - you change channel otherwise (even though it'll return > - an error to this */ > - lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, > - assoc_req->channel); > - } > - > - lbs_deb_assoc("ASSOC: channel: %d -> %d\n", > - priv->channel, assoc_req->channel); > - > - ret = lbs_set_channel(priv, assoc_req->channel); > - if (ret < 0) > - lbs_deb_assoc("ASSOC: channel: error setting channel.\n"); > - > - /* FIXME: shouldn't need to grab the channel _again_ after setting > - * it since the firmware is supposed to return the new channel, but > - * whatever... */ > - ret = lbs_update_channel(priv); > - if (ret) { > - lbs_deb_assoc("ASSOC: channel: error getting channel.\n"); > - goto done; > - } > - > - if (assoc_req->channel != priv->channel) { > - lbs_deb_assoc("ASSOC: channel: failed to update channel to %d\n", > - assoc_req->channel); > - goto restore_mesh; > - } > - > - 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); > - > - restore_mesh: > - if (priv->mesh_dev) > - lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, > - priv->channel); > - > - done: > - lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); > - return ret; > -} > - > - > -static int assoc_helper_wep_keys(struct lbs_private *priv, > - struct assoc_request *assoc_req) > -{ > - int i; > - int ret = 0; > - > - lbs_deb_enter(LBS_DEB_ASSOC); > - > - /* Set or remove WEP keys */ > - if (assoc_req->wep_keys[0].len || assoc_req->wep_keys[1].len || > - assoc_req->wep_keys[2].len || assoc_req->wep_keys[3].len) > - ret = lbs_cmd_802_11_set_wep(priv, CMD_ACT_ADD, assoc_req); > - else > - ret = lbs_cmd_802_11_set_wep(priv, CMD_ACT_REMOVE, assoc_req); > - > - if (ret) > - goto out; > - > - /* enable/disable the MAC's WEP packet filter */ > - if (assoc_req->secinfo.wep_enabled) > - priv->mac_control |= CMD_ACT_MAC_WEP_ENABLE; > - else > - priv->mac_control &= ~CMD_ACT_MAC_WEP_ENABLE; > - > - lbs_set_mac_control(priv); > - > - mutex_lock(&priv->lock); > - > - /* Copy WEP keys into priv wep key fields */ > - for (i = 0; i < 4; i++) { > - memcpy(&priv->wep_keys[i], &assoc_req->wep_keys[i], > - sizeof(struct enc_key)); > - } > - priv->wep_tx_keyidx = assoc_req->wep_tx_keyidx; > - > - mutex_unlock(&priv->lock); > - > -out: > - lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); > - return ret; > -} > - > -static int assoc_helper_secinfo(struct lbs_private *priv, > - struct assoc_request * assoc_req) > -{ > - int ret = 0; > - uint16_t do_wpa; > - uint16_t rsn = 0; > - > - lbs_deb_enter(LBS_DEB_ASSOC); > - > - memcpy(&priv->secinfo, &assoc_req->secinfo, > - sizeof(struct lbs_802_11_security)); > - > - lbs_set_mac_control(priv); > - > - /* If RSN is already enabled, don't try to enable it again, since > - * ENABLE_RSN resets internal state machines and will clobber the > - * 4-way WPA handshake. > - */ > - > - /* Get RSN enabled/disabled */ > - ret = lbs_cmd_802_11_enable_rsn(priv, CMD_ACT_GET, &rsn); > - if (ret) { > - lbs_deb_assoc("Failed to get RSN status: %d\n", ret); > - goto out; > - } > - > - /* Don't re-enable RSN if it's already enabled */ > - do_wpa = assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled; > - if (do_wpa == rsn) > - goto out; > - > - /* Set RSN enabled/disabled */ > - ret = lbs_cmd_802_11_enable_rsn(priv, CMD_ACT_SET, &do_wpa); > - > -out: > - lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); > - return ret; > -} > - > - > -static int assoc_helper_wpa_keys(struct lbs_private *priv, > - struct assoc_request * assoc_req) > -{ > - int ret = 0; > - unsigned int flags = assoc_req->flags; > - > - lbs_deb_enter(LBS_DEB_ASSOC); > - > - /* Work around older firmware bug where WPA unicast and multicast > - * keys must be set independently. Seen in SDIO parts with firmware > - * version 5.0.11p0. > - */ > - > - if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { > - clear_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags); > - ret = lbs_cmd_802_11_key_material(priv, CMD_ACT_SET, assoc_req); > - assoc_req->flags = flags; > - } > - > - if (ret) > - goto out; > - > - memcpy(&priv->wpa_unicast_key, &assoc_req->wpa_unicast_key, > - sizeof(struct enc_key)); > - > - if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) { > - clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags); > - > - ret = lbs_cmd_802_11_key_material(priv, CMD_ACT_SET, assoc_req); > - assoc_req->flags = flags; > - > - memcpy(&priv->wpa_mcast_key, &assoc_req->wpa_mcast_key, > - sizeof(struct enc_key)); > - } > - > -out: > - lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); > - return ret; > -} > - > - > -static int assoc_helper_wpa_ie(struct lbs_private *priv, > - struct assoc_request * assoc_req) > -{ > - int ret = 0; > - > - lbs_deb_enter(LBS_DEB_ASSOC); > - > - if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) { > - memcpy(&priv->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len); > - priv->wpa_ie_len = assoc_req->wpa_ie_len; > - } else { > - memset(&priv->wpa_ie, 0, MAX_WPA_IE_LEN); > - priv->wpa_ie_len = 0; > - } > - > - lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); > - return ret; > -} > - > - > -static int should_deauth_infrastructure(struct lbs_private *priv, > - struct assoc_request * assoc_req) > -{ > - int ret = 0; > - > - if (priv->connect_status != LBS_CONNECTED) > - return 0; > - > - lbs_deb_enter(LBS_DEB_ASSOC); > - if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { > - lbs_deb_assoc("Deauthenticating due to new SSID\n"); > - ret = 1; > - goto out; > - } > - > - if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) { > - if (priv->secinfo.auth_mode != assoc_req->secinfo.auth_mode) { > - lbs_deb_assoc("Deauthenticating due to new security\n"); > - ret = 1; > - goto out; > - } > - } > - > - if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) { > - lbs_deb_assoc("Deauthenticating due to new BSSID\n"); > - ret = 1; > - goto out; > - } > - > - if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) { > - lbs_deb_assoc("Deauthenticating due to channel switch\n"); > - ret = 1; > - goto out; > - } > - > - /* FIXME: deal with 'auto' mode somehow */ > - if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) { > - if (assoc_req->mode != IW_MODE_INFRA) { > - lbs_deb_assoc("Deauthenticating due to leaving " > - "infra mode\n"); > - ret = 1; > - goto out; > - } > - } > - > -out: > - lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); > - return ret; > -} > - > - > -static int should_stop_adhoc(struct lbs_private *priv, > - struct assoc_request * assoc_req) > -{ > - lbs_deb_enter(LBS_DEB_ASSOC); > - > - if (priv->connect_status != LBS_CONNECTED) > - return 0; > - > - if (lbs_ssid_cmp(priv->curbssparams.ssid, > - priv->curbssparams.ssid_len, > - assoc_req->ssid, assoc_req->ssid_len) != 0) > - return 1; > - > - /* FIXME: deal with 'auto' mode somehow */ > - if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) { > - if (assoc_req->mode != IW_MODE_ADHOC) > - return 1; > - } > - > - if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) { > - if (assoc_req->channel != priv->channel) > - return 1; > - } > - > - lbs_deb_leave(LBS_DEB_ASSOC); > - return 0; > -} > - > - > -/** > - * @brief This function finds the best SSID in the Scan List > - * > - * Search the scan table for the best SSID that also matches the current > - * adapter network preference (infrastructure or adhoc) > - * > - * @param priv A pointer to struct lbs_private > - * > - * @return index in BSSID list > - */ > -static struct bss_descriptor *lbs_find_best_ssid_in_list( > - struct lbs_private *priv, uint8_t mode) > -{ > - uint8_t bestrssi = 0; > - struct bss_descriptor *iter_bss; > - struct bss_descriptor *best_bss = NULL; > - > - lbs_deb_enter(LBS_DEB_SCAN); > - > - mutex_lock(&priv->lock); > - > - list_for_each_entry(iter_bss, &priv->network_list, list) { > - switch (mode) { > - case IW_MODE_INFRA: > - case IW_MODE_ADHOC: > - if (!is_network_compatible(priv, iter_bss, mode)) > - break; > - if (SCAN_RSSI(iter_bss->rssi) <= bestrssi) > - break; > - bestrssi = SCAN_RSSI(iter_bss->rssi); > - best_bss = iter_bss; > - break; > - case IW_MODE_AUTO: > - default: > - if (SCAN_RSSI(iter_bss->rssi) <= bestrssi) > - break; > - bestrssi = SCAN_RSSI(iter_bss->rssi); > - best_bss = iter_bss; > - break; > - } > - } > - > - mutex_unlock(&priv->lock); > - lbs_deb_leave_args(LBS_DEB_SCAN, "best_bss %p", best_bss); > - return best_bss; > -} > - > -/** > - * @brief Find the best AP > - * > - * Used from association worker. > - * > - * @param priv A pointer to struct lbs_private structure > - * @param pSSID A pointer to AP's ssid > - * > - * @return 0--success, otherwise--fail > - */ > -static int lbs_find_best_network_ssid(struct lbs_private *priv, > - uint8_t *out_ssid, uint8_t *out_ssid_len, uint8_t preferred_mode, > - uint8_t *out_mode) > -{ > - int ret = -1; > - struct bss_descriptor *found; > - > - lbs_deb_enter(LBS_DEB_SCAN); > - > - priv->scan_ssid_len = 0; > - lbs_scan_networks(priv, 1); > - if (priv->surpriseremoved) > - goto out; > - > - found = lbs_find_best_ssid_in_list(priv, preferred_mode); > - if (found && (found->ssid_len > 0)) { > - memcpy(out_ssid, &found->ssid, IEEE80211_MAX_SSID_LEN); > - *out_ssid_len = found->ssid_len; > - *out_mode = found->mode; > - ret = 0; > - } > - > -out: > - lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); > - return ret; > -} > - > - > -void lbs_association_worker(struct work_struct *work) > -{ > - struct lbs_private *priv = container_of(work, struct lbs_private, > - assoc_work.work); > - struct assoc_request * assoc_req = NULL; > - int ret = 0; > - int find_any_ssid = 0; > - DECLARE_SSID_BUF(ssid); > - > - lbs_deb_enter(LBS_DEB_ASSOC); > - > - mutex_lock(&priv->lock); > - assoc_req = priv->pending_assoc_req; > - priv->pending_assoc_req = NULL; > - priv->in_progress_assoc_req = assoc_req; > - mutex_unlock(&priv->lock); > - > - if (!assoc_req) > - goto done; > - > - lbs_deb_assoc( > - "Association Request:\n" > - " flags: 0x%08lx\n" > - " SSID: '%s'\n" > - " chann: %d\n" > - " band: %d\n" > - " mode: %d\n" > - " BSSID: %pM\n" > - " secinfo: %s%s%s\n" > - " auth_mode: %d\n", > - assoc_req->flags, > - print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len), > - assoc_req->channel, assoc_req->band, assoc_req->mode, > - assoc_req->bssid, > - assoc_req->secinfo.WPAenabled ? " WPA" : "", > - assoc_req->secinfo.WPA2enabled ? " WPA2" : "", > - assoc_req->secinfo.wep_enabled ? " WEP" : "", > - assoc_req->secinfo.auth_mode); > - > - /* If 'any' SSID was specified, find an SSID to associate with */ > - if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags) > - && !assoc_req->ssid_len) > - find_any_ssid = 1; > - > - /* But don't use 'any' SSID if there's a valid locked BSSID to use */ > - if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) { > - if (compare_ether_addr(assoc_req->bssid, bssid_any) > - && compare_ether_addr(assoc_req->bssid, bssid_off)) > - find_any_ssid = 0; > - } > - > - if (find_any_ssid) { > - u8 new_mode = assoc_req->mode; > - > - ret = lbs_find_best_network_ssid(priv, assoc_req->ssid, > - &assoc_req->ssid_len, assoc_req->mode, &new_mode); > - if (ret) { > - lbs_deb_assoc("Could not find best network\n"); > - ret = -ENETUNREACH; > - goto out; > - } > - > - /* Ensure we switch to the mode of the AP */ > - if (assoc_req->mode == IW_MODE_AUTO) { > - set_bit(ASSOC_FLAG_MODE, &assoc_req->flags); > - assoc_req->mode = new_mode; > - } > - } > - > - /* > - * Check if the attributes being changing require deauthentication > - * from the currently associated infrastructure access point. > - */ > - if (priv->mode == IW_MODE_INFRA) { > - if (should_deauth_infrastructure(priv, assoc_req)) { > - ret = lbs_cmd_80211_deauthenticate(priv, > - priv->curbssparams.bssid, > - WLAN_REASON_DEAUTH_LEAVING); > - if (ret) { > - lbs_deb_assoc("Deauthentication due to new " > - "configuration request failed: %d\n", > - ret); > - } > - } > - } else if (priv->mode == IW_MODE_ADHOC) { > - if (should_stop_adhoc(priv, assoc_req)) { > - ret = lbs_adhoc_stop(priv); > - if (ret) { > - lbs_deb_assoc("Teardown of AdHoc network due to " > - "new configuration request failed: %d\n", > - ret); > - } > - > - } > - } > - > - /* Send the various configuration bits to the firmware */ > - if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) { > - ret = assoc_helper_mode(priv, assoc_req); > - if (ret) > - goto out; > - } > - > - if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) { > - ret = assoc_helper_channel(priv, assoc_req); > - if (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); > - if (ret) > - goto out; > - } > - > - if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) { > - ret = assoc_helper_secinfo(priv, assoc_req); > - if (ret) > - goto out; > - } > - > - if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) { > - ret = assoc_helper_wpa_ie(priv, assoc_req); > - if (ret) > - goto out; > - } > - > - if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags) > - || test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { > - ret = assoc_helper_wpa_keys(priv, assoc_req); > - if (ret) > - goto out; > - } > - > - /* SSID/BSSID should be the _last_ config option set, because they > - * trigger the association attempt. > - */ > - if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags) > - || test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { > - int success = 1; > - > - ret = assoc_helper_associate(priv, assoc_req); > - if (ret) { > - lbs_deb_assoc("ASSOC: association unsuccessful: %d\n", > - ret); > - success = 0; > - } > - > - if (priv->connect_status != LBS_CONNECTED) { > - lbs_deb_assoc("ASSOC: association unsuccessful, " > - "not connected\n"); > - success = 0; > - } > - > - if (success) { > - lbs_deb_assoc("associated to %pM\n", > - priv->curbssparams.bssid); > - lbs_prepare_and_send_command(priv, > - CMD_802_11_RSSI, > - 0, CMD_OPTION_WAITFORRSP, 0, NULL); > - } else { > - ret = -1; > - } > - } > - > -out: > - if (ret) { > - lbs_deb_assoc("ASSOC: reconfiguration attempt unsuccessful: %d\n", > - ret); > - } > - > - mutex_lock(&priv->lock); > - priv->in_progress_assoc_req = NULL; > - mutex_unlock(&priv->lock); > - kfree(assoc_req); > - > -done: > - lbs_deb_leave(LBS_DEB_ASSOC); > -} > - > - > -/* > - * Caller MUST hold any necessary locks > - */ > -struct assoc_request *lbs_get_association_request(struct lbs_private *priv) > -{ > - struct assoc_request * assoc_req; > - > - lbs_deb_enter(LBS_DEB_ASSOC); > - if (!priv->pending_assoc_req) { > - priv->pending_assoc_req = kzalloc(sizeof(struct assoc_request), > - GFP_KERNEL); > - if (!priv->pending_assoc_req) { > - lbs_pr_info("Not enough memory to allocate association" > - " request!\n"); > - return NULL; > - } > - } > - > - /* Copy current configuration attributes to the association request, > - * but don't overwrite any that are already set. > - */ > - assoc_req = priv->pending_assoc_req; > - if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { > - memcpy(&assoc_req->ssid, &priv->curbssparams.ssid, > - IEEE80211_MAX_SSID_LEN); > - assoc_req->ssid_len = priv->curbssparams.ssid_len; > - } > - > - if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) > - assoc_req->channel = priv->channel; > - > - if (!test_bit(ASSOC_FLAG_BAND, &assoc_req->flags)) > - assoc_req->band = priv->curbssparams.band; > - > - if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) > - assoc_req->mode = priv->mode; > - > - if (!test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) { > - memcpy(&assoc_req->bssid, priv->curbssparams.bssid, > - ETH_ALEN); > - } > - > - if (!test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)) { > - int i; > - for (i = 0; i < 4; i++) { > - memcpy(&assoc_req->wep_keys[i], &priv->wep_keys[i], > - sizeof(struct enc_key)); > - } > - } > - > - if (!test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) > - assoc_req->wep_tx_keyidx = priv->wep_tx_keyidx; > - > - if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) { > - memcpy(&assoc_req->wpa_mcast_key, &priv->wpa_mcast_key, > - sizeof(struct enc_key)); > - } > - > - if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { > - memcpy(&assoc_req->wpa_unicast_key, &priv->wpa_unicast_key, > - sizeof(struct enc_key)); > - } > - > - if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) { > - memcpy(&assoc_req->secinfo, &priv->secinfo, > - sizeof(struct lbs_802_11_security)); > - } > - > - if (!test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) { > - memcpy(&assoc_req->wpa_ie, &priv->wpa_ie, > - MAX_WPA_IE_LEN); > - assoc_req->wpa_ie_len = priv->wpa_ie_len; > - } > - > - lbs_deb_leave(LBS_DEB_ASSOC); > - return assoc_req; > -} > - > - > -/** > - * @brief Deauthenticate from a specific BSS > - * > - * @param priv A pointer to struct lbs_private structure > - * @param bssid The specific BSS to deauthenticate from > - * @param reason The 802.11 sec. 7.3.1.7 Reason Code for deauthenticating > - * > - * @return 0 on success, error on failure > - */ > -int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, u8 bssid[ETH_ALEN], > - u16 reason) > -{ > - struct cmd_ds_802_11_deauthenticate cmd; > - int ret; > - > - lbs_deb_enter(LBS_DEB_JOIN); > - > - memset(&cmd, 0, sizeof(cmd)); > - cmd.hdr.size = cpu_to_le16(sizeof(cmd)); > - memcpy(cmd.macaddr, &bssid[0], ETH_ALEN); > - cmd.reasoncode = cpu_to_le16(reason); > - > - ret = lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd); > - > - /* Clean up everything even if there was an error; can't assume that > - * we're still authenticated to the AP after trying to deauth. > - */ > - lbs_mac_event_disconnected(priv); > - > - lbs_deb_leave(LBS_DEB_JOIN); > - return ret; > -} > - > --- linux-wl.orig/drivers/net/wireless/libertas/scan.h > +++ /dev/null > @@ -1,63 +0,0 @@ > -/** > - * Interface for the wlan network scan routines > - * > - * Driver interface functions and type declarations for the scan module > - * implemented in scan.c. > - */ > -#ifndef _LBS_SCAN_H > -#define _LBS_SCAN_H > - > -#include > - > -struct lbs_private; > - > -#define MAX_NETWORK_COUNT 128 > - > -/** Chan-freq-TxPower mapping table*/ > -struct chan_freq_power { > - /** channel Number */ > - u16 channel; > - /** frequency of this channel */ > - u32 freq; > - /** Max allowed Tx power level */ > - u16 maxtxpower; > - /** TRUE:channel unsupported; FLASE:supported*/ > - u8 unsupported; > -}; > - > -/** region-band mapping table*/ > -struct region_channel { > - /** TRUE if this entry is valid */ > - u8 valid; > - /** region code for US, Japan ... */ > - u8 region; > - /** band B/G/A, used for BAND_CONFIG cmd */ > - u8 band; > - /** Actual No. of elements in the array below */ > - u8 nrcfp; > - /** chan-freq-txpower mapping table*/ > - struct chan_freq_power *CFP; > -}; > - > -/** > - * @brief Maximum number of channels that can be sent in a setuserscan ioctl > - */ > -#define LBS_IOCTL_USER_SCAN_CHAN_MAX 50 > - > -int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len); > - > -int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band); > - > -int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid, > - u8 ssid_len); > - > -int lbs_get_scan(struct net_device *dev, struct iw_request_info *info, > - struct iw_point *dwrq, char *extra); > -int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, > - union iwreq_data *wrqu, char *extra); > - > -int lbs_scan_networks(struct lbs_private *priv, int full_scan); > - > -void lbs_scan_worker(struct work_struct *work); > - > -#endif > --- linux-wl.orig/drivers/net/wireless/libertas/scan.c > +++ /dev/null > @@ -1,1359 +0,0 @@ > -/** > - * Functions implementing wlan scan IOCTL and firmware command APIs > - * > - * IOCTL handlers as well as command preperation and response routines > - * for sending scan commands to the firmware. > - */ > -#include > -#include > -#include > -#include > -#include > -#include > - > -#include "host.h" > -#include "dev.h" > -#include "scan.h" > -#include "assoc.h" > -#include "wext.h" > -#include "cmd.h" > - > -//! Approximate amount of data needed to pass a scan result back to iwlist > -#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \ > - + IEEE80211_MAX_SSID_LEN \ > - + IW_EV_UINT_LEN \ > - + IW_EV_FREQ_LEN \ > - + IW_EV_QUAL_LEN \ > - + IEEE80211_MAX_SSID_LEN \ > - + IW_EV_PARAM_LEN \ > - + 40) /* 40 for WPAIE */ > - > -//! Memory needed to store a max sized channel List TLV for a firmware scan > -#define CHAN_TLV_MAX_SIZE (sizeof(struct mrvl_ie_header) \ > - + (MRVDRV_MAX_CHANNELS_PER_SCAN \ > - * sizeof(struct chanscanparamset))) > - > -//! Memory needed to store a max number/size SSID TLV for a firmware scan > -#define SSID_TLV_MAX_SIZE (1 * sizeof(struct mrvl_ie_ssid_param_set)) > - > -//! Maximum memory needed for a cmd_ds_802_11_scan with all TLVs at max > -#define MAX_SCAN_CFG_ALLOC (sizeof(struct cmd_ds_802_11_scan) \ > - + CHAN_TLV_MAX_SIZE + SSID_TLV_MAX_SIZE) > - > -//! The maximum number of channels the firmware can scan per command > -#define MRVDRV_MAX_CHANNELS_PER_SCAN 14 > - > -/** > - * @brief Number of channels to scan per firmware scan command issuance. > - * > - * Number restricted to prevent hitting the limit on the amount of scan data > - * returned in a single firmware scan command. > - */ > -#define MRVDRV_CHANNELS_PER_SCAN_CMD 4 > - > -//! Scan time specified in the channel TLV for each channel for passive scans > -#define MRVDRV_PASSIVE_SCAN_CHAN_TIME 100 > - > -//! Scan time specified in the channel TLV for each channel for active scans > -#define MRVDRV_ACTIVE_SCAN_CHAN_TIME 100 > - > -#define DEFAULT_MAX_SCAN_AGE (15 * HZ) > - > -static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy, > - struct cmd_header *resp); > - > -/*********************************************************************/ > -/* */ > -/* Misc helper functions */ > -/* */ > -/*********************************************************************/ > - > -/** > - * @brief Unsets the MSB on basic rates > - * > - * Scan through an array and unset the MSB for basic data rates. > - * > - * @param rates buffer of data rates > - * @param len size of buffer > - */ > -static void lbs_unset_basic_rate_flags(u8 *rates, size_t len) > -{ > - int i; > - > - for (i = 0; i < len; i++) > - rates[i] &= 0x7f; > -} > - > - > -static inline void clear_bss_descriptor(struct bss_descriptor *bss) > -{ > - /* Don't blow away ->list, just BSS data */ > - memset(bss, 0, offsetof(struct bss_descriptor, list)); > -} > - > -/** > - * @brief Compare two SSIDs > - * > - * @param ssid1 A pointer to ssid to compare > - * @param ssid2 A pointer to ssid to compare > - * > - * @return 0: ssid is same, otherwise is different > - */ > -int lbs_ssid_cmp(uint8_t *ssid1, uint8_t ssid1_len, uint8_t *ssid2, > - uint8_t ssid2_len) > -{ > - if (ssid1_len != ssid2_len) > - return -1; > - > - return memcmp(ssid1, ssid2, ssid1_len); > -} > - > -static inline int is_same_network(struct bss_descriptor *src, > - struct bss_descriptor *dst) > -{ > - /* A network is only a duplicate if the channel, BSSID, and ESSID > - * all match. We treat all with the same BSSID and channel > - * as one network */ > - return ((src->ssid_len == dst->ssid_len) && > - (src->channel == dst->channel) && > - !compare_ether_addr(src->bssid, dst->bssid) && > - !memcmp(src->ssid, dst->ssid, src->ssid_len)); > -} > - > - > - > -/*********************************************************************/ > -/* */ > -/* Region channel support */ > -/* */ > -/*********************************************************************/ > - > -#define LBS_TX_PWR_DEFAULT 20 /*100mW */ > -#define LBS_TX_PWR_US_DEFAULT 20 /*100mW */ > -#define LBS_TX_PWR_JP_DEFAULT 16 /*50mW */ > -#define LBS_TX_PWR_FR_DEFAULT 20 /*100mW */ > -#define LBS_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, LBS_TX_PWR_US_DEFAULT}, > - {2, 2417, LBS_TX_PWR_US_DEFAULT}, > - {3, 2422, LBS_TX_PWR_US_DEFAULT}, > - {4, 2427, LBS_TX_PWR_US_DEFAULT}, > - {5, 2432, LBS_TX_PWR_US_DEFAULT}, > - {6, 2437, LBS_TX_PWR_US_DEFAULT}, > - {7, 2442, LBS_TX_PWR_US_DEFAULT}, > - {8, 2447, LBS_TX_PWR_US_DEFAULT}, > - {9, 2452, LBS_TX_PWR_US_DEFAULT}, > - {10, 2457, LBS_TX_PWR_US_DEFAULT}, > - {11, 2462, LBS_TX_PWR_US_DEFAULT} > -}; > - > -/* band: 'B/G', region: Europe ETSI */ > -static struct chan_freq_power channel_freq_power_EU_BG[] = { > - {1, 2412, LBS_TX_PWR_EMEA_DEFAULT}, > - {2, 2417, LBS_TX_PWR_EMEA_DEFAULT}, > - {3, 2422, LBS_TX_PWR_EMEA_DEFAULT}, > - {4, 2427, LBS_TX_PWR_EMEA_DEFAULT}, > - {5, 2432, LBS_TX_PWR_EMEA_DEFAULT}, > - {6, 2437, LBS_TX_PWR_EMEA_DEFAULT}, > - {7, 2442, LBS_TX_PWR_EMEA_DEFAULT}, > - {8, 2447, LBS_TX_PWR_EMEA_DEFAULT}, > - {9, 2452, LBS_TX_PWR_EMEA_DEFAULT}, > - {10, 2457, LBS_TX_PWR_EMEA_DEFAULT}, > - {11, 2462, LBS_TX_PWR_EMEA_DEFAULT}, > - {12, 2467, LBS_TX_PWR_EMEA_DEFAULT}, > - {13, 2472, LBS_TX_PWR_EMEA_DEFAULT} > -}; > - > -/* band: 'B/G', region: Spain */ > -static struct chan_freq_power channel_freq_power_SPN_BG[] = { > - {10, 2457, LBS_TX_PWR_DEFAULT}, > - {11, 2462, LBS_TX_PWR_DEFAULT} > -}; > - > -/* band: 'B/G', region: France */ > -static struct chan_freq_power channel_freq_power_FR_BG[] = { > - {10, 2457, LBS_TX_PWR_FR_DEFAULT}, > - {11, 2462, LBS_TX_PWR_FR_DEFAULT}, > - {12, 2467, LBS_TX_PWR_FR_DEFAULT}, > - {13, 2472, LBS_TX_PWR_FR_DEFAULT} > -}; > - > -/* band: 'B/G', region: Japan */ > -static struct chan_freq_power channel_freq_power_JPN_BG[] = { > - {1, 2412, LBS_TX_PWR_JP_DEFAULT}, > - {2, 2417, LBS_TX_PWR_JP_DEFAULT}, > - {3, 2422, LBS_TX_PWR_JP_DEFAULT}, > - {4, 2427, LBS_TX_PWR_JP_DEFAULT}, > - {5, 2432, LBS_TX_PWR_JP_DEFAULT}, > - {6, 2437, LBS_TX_PWR_JP_DEFAULT}, > - {7, 2442, LBS_TX_PWR_JP_DEFAULT}, > - {8, 2447, LBS_TX_PWR_JP_DEFAULT}, > - {9, 2452, LBS_TX_PWR_JP_DEFAULT}, > - {10, 2457, LBS_TX_PWR_JP_DEFAULT}, > - {11, 2462, LBS_TX_PWR_JP_DEFAULT}, > - {12, 2467, LBS_TX_PWR_JP_DEFAULT}, > - {13, 2472, LBS_TX_PWR_JP_DEFAULT}, > - {14, 2484, LBS_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 */ > -}; > - > -/** > - * @brief This function finds the CFP in > - * region_cfp_table based on region and band parameter. > - * > - * @param region The region code > - * @param band The band > - * @param cfp_no A pointer to CFP number > - * @return A pointer to CFP > - */ > -static struct chan_freq_power *lbs_get_region_cfp_table(u8 region, int *cfp_no) > -{ > - int i, end; > - > - lbs_deb_enter(LBS_DEB_MAIN); > - > - end = ARRAY_SIZE(region_cfp_table); > - > - for (i = 0; i < end ; i++) { > - lbs_deb_main("region_cfp_table[i].region=%d\n", > - region_cfp_table[i].region); > - if (region_cfp_table[i].region == region) { > - *cfp_no = region_cfp_table[i].cfp_no_BG; > - lbs_deb_leave(LBS_DEB_MAIN); > - return region_cfp_table[i].cfp_BG; > - } > - } > - > - lbs_deb_leave_args(LBS_DEB_MAIN, "ret NULL"); > - return NULL; > -} > - > -int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band) > -{ > - int ret = 0; > - int i = 0; > - > - struct chan_freq_power *cfp; > - int cfp_no; > - > - lbs_deb_enter(LBS_DEB_MAIN); > - > - memset(priv->region_channel, 0, sizeof(priv->region_channel)); > - > - cfp = lbs_get_region_cfp_table(region, &cfp_no); > - if (cfp != NULL) { > - priv->region_channel[i].nrcfp = cfp_no; > - priv->region_channel[i].CFP = cfp; > - } else { > - lbs_deb_main("wrong region code %#x in band B/G\n", > - region); > - ret = -1; > - goto out; > - } > - priv->region_channel[i].valid = 1; > - priv->region_channel[i].region = region; > - priv->region_channel[i].band = band; > - i++; > -out: > - lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); > - return ret; > -} > - > - > - > - > -/*********************************************************************/ > -/* */ > -/* Main scanning support */ > -/* */ > -/*********************************************************************/ > - > -/** > - * @brief Create a channel list for the driver to scan based on region info > - * > - * Only used from lbs_scan_setup_scan_config() > - * > - * Use the driver region/band information to construct a comprehensive list > - * of channels to scan. This routine is used for any scan that is not > - * provided a specific channel list to scan. > - * > - * @param priv A pointer to struct lbs_private structure > - * @param scanchanlist Output parameter: resulting channel list to scan > - * > - * @return void > - */ > -static int lbs_scan_create_channel_list(struct lbs_private *priv, > - struct chanscanparamset *scanchanlist) > -{ > - struct region_channel *scanregion; > - struct chan_freq_power *cfp; > - int rgnidx; > - int chanidx; > - int nextchan; > - uint8_t scantype; > - > - chanidx = 0; > - > - /* Set the default scan type to the user specified type, will later > - * be changed to passive on a per channel basis if restricted by > - * regulatory requirements (11d or 11h) > - */ > - scantype = CMD_SCAN_TYPE_ACTIVE; > - > - for (rgnidx = 0; rgnidx < ARRAY_SIZE(priv->region_channel); rgnidx++) { > - if (!priv->region_channel[rgnidx].valid) > - continue; > - scanregion = &priv->region_channel[rgnidx]; > - > - for (nextchan = 0; nextchan < scanregion->nrcfp; nextchan++, chanidx++) { > - struct chanscanparamset *chan = &scanchanlist[chanidx]; > - > - cfp = scanregion->CFP + nextchan; > - > - if (scanregion->band == BAND_B || scanregion->band == BAND_G) > - chan->radiotype = CMD_SCAN_RADIO_TYPE_BG; > - > - if (scantype == CMD_SCAN_TYPE_PASSIVE) { > - chan->maxscantime = cpu_to_le16(MRVDRV_PASSIVE_SCAN_CHAN_TIME); > - chan->chanscanmode.passivescan = 1; > - } else { > - chan->maxscantime = cpu_to_le16(MRVDRV_ACTIVE_SCAN_CHAN_TIME); > - chan->chanscanmode.passivescan = 0; > - } > - > - chan->channumber = cfp->channel; > - } > - } > - return chanidx; > -} > - > -/* > - * Add SSID TLV of the form: > - * > - * TLV-ID SSID 00 00 > - * length 06 00 > - * ssid 4d 4e 54 45 53 54 > - */ > -static int lbs_scan_add_ssid_tlv(struct lbs_private *priv, u8 *tlv) > -{ > - struct mrvl_ie_ssid_param_set *ssid_tlv = (void *)tlv; > - > - ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID); > - ssid_tlv->header.len = cpu_to_le16(priv->scan_ssid_len); > - memcpy(ssid_tlv->ssid, priv->scan_ssid, priv->scan_ssid_len); > - return sizeof(ssid_tlv->header) + priv->scan_ssid_len; > -} > - > -/* > - * Add CHANLIST TLV of the form > - * > - * TLV-ID CHANLIST 01 01 > - * length 5b 00 > - * channel 1 00 01 00 00 00 64 00 > - * radio type 00 > - * channel 01 > - * scan type 00 > - * min scan time 00 00 > - * max scan time 64 00 > - * channel 2 00 02 00 00 00 64 00 > - * channel 3 00 03 00 00 00 64 00 > - * channel 4 00 04 00 00 00 64 00 > - * channel 5 00 05 00 00 00 64 00 > - * channel 6 00 06 00 00 00 64 00 > - * channel 7 00 07 00 00 00 64 00 > - * channel 8 00 08 00 00 00 64 00 > - * channel 9 00 09 00 00 00 64 00 > - * channel 10 00 0a 00 00 00 64 00 > - * channel 11 00 0b 00 00 00 64 00 > - * channel 12 00 0c 00 00 00 64 00 > - * channel 13 00 0d 00 00 00 64 00 > - * > - */ > -static int lbs_scan_add_chanlist_tlv(uint8_t *tlv, > - struct chanscanparamset *chan_list, > - int chan_count) > -{ > - size_t size = sizeof(struct chanscanparamset) *chan_count; > - struct mrvl_ie_chanlist_param_set *chan_tlv = (void *)tlv; > - > - chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); > - memcpy(chan_tlv->chanscanparam, chan_list, size); > - chan_tlv->header.len = cpu_to_le16(size); > - return sizeof(chan_tlv->header) + size; > -} > - > -/* > - * Add RATES TLV of the form > - * > - * TLV-ID RATES 01 00 > - * length 0e 00 > - * rates 82 84 8b 96 0c 12 18 24 30 48 60 6c > - * > - * The rates are in lbs_bg_rates[], but for the 802.11b > - * rates the high bit isn't set. > - */ > -static int lbs_scan_add_rates_tlv(uint8_t *tlv) > -{ > - int i; > - struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv; > - > - rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES); > - tlv += sizeof(rate_tlv->header); > - for (i = 0; i < MAX_RATES; i++) { > - *tlv = lbs_bg_rates[i]; > - if (*tlv == 0) > - break; > - /* This code makes sure that the 802.11b rates (1 MBit/s, 2 > - MBit/s, 5.5 MBit/s and 11 MBit/s get's the high bit set. > - Note that the values are MBit/s * 2, to mark them as > - basic rates so that the firmware likes it better */ > - if (*tlv == 0x02 || *tlv == 0x04 || > - *tlv == 0x0b || *tlv == 0x16) > - *tlv |= 0x80; > - tlv++; > - } > - rate_tlv->header.len = cpu_to_le16(i); > - return sizeof(rate_tlv->header) + i; > -} > - > -/* > - * Generate the CMD_802_11_SCAN command with the proper tlv > - * for a bunch of channels. > - */ > -static int lbs_do_scan(struct lbs_private *priv, uint8_t bsstype, > - struct chanscanparamset *chan_list, int chan_count) > -{ > - int ret = -ENOMEM; > - struct cmd_ds_802_11_scan *scan_cmd; > - uint8_t *tlv; /* pointer into our current, growing TLV storage area */ > - > - lbs_deb_enter_args(LBS_DEB_SCAN, "bsstype %d, chanlist[].chan %d, chan_count %d", > - bsstype, chan_list ? chan_list[0].channumber : -1, > - chan_count); > - > - /* create the fixed part for scan command */ > - scan_cmd = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL); > - if (scan_cmd == NULL) > - goto out; > - > - tlv = scan_cmd->tlvbuffer; > - /* TODO: do we need to scan for a specific BSSID? > - memcpy(scan_cmd->bssid, priv->scan_bssid, ETH_ALEN); */ > - scan_cmd->bsstype = bsstype; > - > - /* add TLVs */ > - if (priv->scan_ssid_len) > - tlv += lbs_scan_add_ssid_tlv(priv, tlv); > - if (chan_list && chan_count) > - tlv += lbs_scan_add_chanlist_tlv(tlv, chan_list, chan_count); > - tlv += lbs_scan_add_rates_tlv(tlv); > - > - /* This is the final data we are about to send */ > - scan_cmd->hdr.size = cpu_to_le16(tlv - (uint8_t *)scan_cmd); > - lbs_deb_hex(LBS_DEB_SCAN, "SCAN_CMD", (void *)scan_cmd, > - sizeof(*scan_cmd)); > - lbs_deb_hex(LBS_DEB_SCAN, "SCAN_TLV", scan_cmd->tlvbuffer, > - tlv - scan_cmd->tlvbuffer); > - > - ret = __lbs_cmd(priv, CMD_802_11_SCAN, &scan_cmd->hdr, > - le16_to_cpu(scan_cmd->hdr.size), > - lbs_ret_80211_scan, 0); > - > -out: > - kfree(scan_cmd); > - lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); > - return ret; > -} > - > -/** > - * @brief Internal function used to start a scan based on an input config > - * > - * Use the input user scan configuration information when provided in > - * order to send the appropriate scan commands to firmware to populate or > - * update the internal driver scan table > - * > - * @param priv A pointer to struct lbs_private structure > - * @param full_scan Do a full-scan (blocking) > - * > - * @return 0 or < 0 if error > - */ > -int lbs_scan_networks(struct lbs_private *priv, int full_scan) > -{ > - int ret = -ENOMEM; > - struct chanscanparamset *chan_list; > - struct chanscanparamset *curr_chans; > - int chan_count; > - uint8_t bsstype = CMD_BSS_TYPE_ANY; > - int numchannels = MRVDRV_CHANNELS_PER_SCAN_CMD; > - union iwreq_data wrqu; > -#ifdef CONFIG_LIBERTAS_DEBUG > - struct bss_descriptor *iter; > - int i = 0; > - DECLARE_SSID_BUF(ssid); > -#endif > - > - lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", full_scan); > - > - /* Cancel any partial outstanding partial scans if this scan > - * is a full scan. > - */ > - if (full_scan && delayed_work_pending(&priv->scan_work)) > - cancel_delayed_work(&priv->scan_work); > - > - /* User-specified bsstype or channel list > - TODO: this can be implemented if some user-space application > - need the feature. Formerly, it was accessible from debugfs, > - but then nowhere used. > - if (user_cfg) { > - if (user_cfg->bsstype) > - bsstype = user_cfg->bsstype; > - } */ > - > - lbs_deb_scan("numchannels %d, bsstype %d\n", numchannels, bsstype); > - > - /* Create list of channels to scan */ > - chan_list = kzalloc(sizeof(struct chanscanparamset) * > - LBS_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL); > - if (!chan_list) { > - lbs_pr_alert("SCAN: chan_list empty\n"); > - goto out; > - } > - > - /* We want to scan all channels */ > - chan_count = lbs_scan_create_channel_list(priv, chan_list); > - > - netif_stop_queue(priv->dev); > - netif_carrier_off(priv->dev); > - if (priv->mesh_dev) { > - netif_stop_queue(priv->mesh_dev); > - netif_carrier_off(priv->mesh_dev); > - } > - > - /* Prepare to continue an interrupted scan */ > - lbs_deb_scan("chan_count %d, scan_channel %d\n", > - chan_count, priv->scan_channel); > - curr_chans = chan_list; > - /* advance channel list by already-scanned-channels */ > - if (priv->scan_channel > 0) { > - curr_chans += priv->scan_channel; > - chan_count -= priv->scan_channel; > - } > - > - /* Send scan command(s) > - * numchannels contains the number of channels we should maximally scan > - * chan_count is the total number of channels to scan > - */ > - > - while (chan_count) { > - int to_scan = min(numchannels, chan_count); > - lbs_deb_scan("scanning %d of %d channels\n", > - to_scan, chan_count); > - ret = lbs_do_scan(priv, bsstype, curr_chans, > - to_scan); > - if (ret) { > - lbs_pr_err("SCAN_CMD failed\n"); > - goto out2; > - } > - curr_chans += to_scan; > - chan_count -= to_scan; > - > - /* somehow schedule the next part of the scan */ > - if (chan_count && !full_scan && > - !priv->surpriseremoved) { > - /* -1 marks just that we're currently scanning */ > - if (priv->scan_channel < 0) > - priv->scan_channel = to_scan; > - else > - priv->scan_channel += to_scan; > - cancel_delayed_work(&priv->scan_work); > - queue_delayed_work(priv->work_thread, &priv->scan_work, > - msecs_to_jiffies(300)); > - /* skip over GIWSCAN event */ > - goto out; > - } > - > - } > - memset(&wrqu, 0, sizeof(union iwreq_data)); > - wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); > - > -#ifdef CONFIG_LIBERTAS_DEBUG > - /* Dump the scan table */ > - mutex_lock(&priv->lock); > - lbs_deb_scan("scan table:\n"); > - list_for_each_entry(iter, &priv->network_list, list) > - lbs_deb_scan("%02d: BSSID %pM, RSSI %d, SSID '%s'\n", > - i++, iter->bssid, iter->rssi, > - print_ssid(ssid, iter->ssid, iter->ssid_len)); > - mutex_unlock(&priv->lock); > -#endif > - > -out2: > - priv->scan_channel = 0; > - > -out: > - if (priv->connect_status == LBS_CONNECTED) { > - netif_carrier_on(priv->dev); > - if (!priv->tx_pending_len) > - netif_wake_queue(priv->dev); > - } > - if (priv->mesh_dev && lbs_mesh_connected(priv)) { > - netif_carrier_on(priv->mesh_dev); > - if (!priv->tx_pending_len) > - netif_wake_queue(priv->mesh_dev); > - } > - kfree(chan_list); > - > - lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); > - return ret; > -} > - > -void lbs_scan_worker(struct work_struct *work) > -{ > - struct lbs_private *priv = > - container_of(work, struct lbs_private, scan_work.work); > - > - lbs_deb_enter(LBS_DEB_SCAN); > - lbs_scan_networks(priv, 0); > - lbs_deb_leave(LBS_DEB_SCAN); > -} > - > - > -/*********************************************************************/ > -/* */ > -/* Result interpretation */ > -/* */ > -/*********************************************************************/ > - > -/** > - * @brief Interpret a BSS scan response returned from the firmware > - * > - * Parse the various fixed fields and IEs passed back for a a BSS probe > - * response or beacon from the scan command. Record information as needed > - * in the scan table struct bss_descriptor for that entry. > - * > - * @param bss Output parameter: Pointer to the BSS Entry > - * > - * @return 0 or -1 > - */ > -static int lbs_process_bss(struct bss_descriptor *bss, > - uint8_t **pbeaconinfo, int *bytesleft) > -{ > - struct ieee_ie_fh_param_set *fh; > - struct ieee_ie_ds_param_set *ds; > - struct ieee_ie_cf_param_set *cf; > - struct ieee_ie_ibss_param_set *ibss; > - DECLARE_SSID_BUF(ssid); > - uint8_t *pos, *end, *p; > - uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0; > - uint16_t beaconsize = 0; > - int ret; > - > - lbs_deb_enter(LBS_DEB_SCAN); > - > - if (*bytesleft >= sizeof(beaconsize)) { > - /* Extract & convert beacon size from the command buffer */ > - beaconsize = get_unaligned_le16(*pbeaconinfo); > - *bytesleft -= sizeof(beaconsize); > - *pbeaconinfo += sizeof(beaconsize); > - } > - > - if (beaconsize == 0 || beaconsize > *bytesleft) { > - *pbeaconinfo += *bytesleft; > - *bytesleft = 0; > - ret = -1; > - goto done; > - } > - > - /* Initialize the current working beacon pointer for this BSS iteration */ > - pos = *pbeaconinfo; > - end = pos + beaconsize; > - > - /* Advance the return beacon pointer past the current beacon */ > - *pbeaconinfo += beaconsize; > - *bytesleft -= beaconsize; > - > - memcpy(bss->bssid, pos, ETH_ALEN); > - lbs_deb_scan("process_bss: BSSID %pM\n", bss->bssid); > - pos += ETH_ALEN; > - > - if ((end - pos) < 12) { > - lbs_deb_scan("process_bss: Not enough bytes left\n"); > - ret = -1; > - goto done; > - } > - > - /* > - * next 4 fields are RSSI, time stamp, beacon interval, > - * and capability information > - */ > - > - /* RSSI is 1 byte long */ > - bss->rssi = *pos; > - lbs_deb_scan("process_bss: RSSI %d\n", *pos); > - pos++; > - > - /* time stamp is 8 bytes long */ > - pos += 8; > - > - /* beacon interval is 2 bytes long */ > - bss->beaconperiod = get_unaligned_le16(pos); > - pos += 2; > - > - /* capability information is 2 bytes long */ > - bss->capability = get_unaligned_le16(pos); > - lbs_deb_scan("process_bss: capabilities 0x%04x\n", bss->capability); > - pos += 2; > - > - if (bss->capability & WLAN_CAPABILITY_PRIVACY) > - lbs_deb_scan("process_bss: WEP enabled\n"); > - if (bss->capability & WLAN_CAPABILITY_IBSS) > - bss->mode = IW_MODE_ADHOC; > - else > - bss->mode = IW_MODE_INFRA; > - > - /* rest of the current buffer are IE's */ > - lbs_deb_scan("process_bss: IE len %zd\n", end - pos); > - lbs_deb_hex(LBS_DEB_SCAN, "process_bss: IE info", pos, end - pos); > - > - /* process variable IE */ > - while (pos <= end - 2) { > - if (pos + pos[1] > end) { > - lbs_deb_scan("process_bss: error in processing IE, " > - "bytes left < IE length\n"); > - break; > - } > - > - switch (pos[0]) { > - case WLAN_EID_SSID: > - bss->ssid_len = min_t(int, IEEE80211_MAX_SSID_LEN, pos[1]); > - memcpy(bss->ssid, pos + 2, bss->ssid_len); > - lbs_deb_scan("got SSID IE: '%s', len %u\n", > - print_ssid(ssid, bss->ssid, bss->ssid_len), > - bss->ssid_len); > - break; > - > - case WLAN_EID_SUPP_RATES: > - n_basic_rates = min_t(uint8_t, MAX_RATES, pos[1]); > - memcpy(bss->rates, pos + 2, n_basic_rates); > - got_basic_rates = 1; > - lbs_deb_scan("got RATES IE\n"); > - break; > - > - case WLAN_EID_FH_PARAMS: > - fh = (struct ieee_ie_fh_param_set *) pos; > - memcpy(&bss->phy.fh, fh, sizeof(*fh)); > - lbs_deb_scan("got FH IE\n"); > - break; > - > - case WLAN_EID_DS_PARAMS: > - ds = (struct ieee_ie_ds_param_set *) pos; > - bss->channel = ds->channel; > - memcpy(&bss->phy.ds, ds, sizeof(*ds)); > - lbs_deb_scan("got DS IE, channel %d\n", bss->channel); > - break; > - > - case WLAN_EID_CF_PARAMS: > - cf = (struct ieee_ie_cf_param_set *) pos; > - memcpy(&bss->ss.cf, cf, sizeof(*cf)); > - lbs_deb_scan("got CF IE\n"); > - break; > - > - case WLAN_EID_IBSS_PARAMS: > - ibss = (struct ieee_ie_ibss_param_set *) pos; > - bss->atimwindow = ibss->atimwindow; > - memcpy(&bss->ss.ibss, ibss, sizeof(*ibss)); > - lbs_deb_scan("got IBSS IE\n"); > - break; > - > - case WLAN_EID_EXT_SUPP_RATES: > - /* only process extended supported rate if data rate is > - * already found. Data rate IE should come before > - * extended supported rate IE > - */ > - lbs_deb_scan("got RATESEX IE\n"); > - if (!got_basic_rates) { > - lbs_deb_scan("... but ignoring it\n"); > - break; > - } > - > - n_ex_rates = pos[1]; > - if (n_basic_rates + n_ex_rates > MAX_RATES) > - n_ex_rates = MAX_RATES - n_basic_rates; > - > - p = bss->rates + n_basic_rates; > - memcpy(p, pos + 2, n_ex_rates); > - break; > - > - case WLAN_EID_GENERIC: > - if (pos[1] >= 4 && > - pos[2] == 0x00 && pos[3] == 0x50 && > - pos[4] == 0xf2 && pos[5] == 0x01) { > - bss->wpa_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN); > - memcpy(bss->wpa_ie, pos, bss->wpa_ie_len); > - lbs_deb_scan("got WPA IE\n"); > - lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie, > - bss->wpa_ie_len); > - } else if (pos[1] >= MARVELL_MESH_IE_LENGTH && > - pos[2] == 0x00 && pos[3] == 0x50 && > - pos[4] == 0x43 && pos[5] == 0x04) { > - lbs_deb_scan("got mesh IE\n"); > - bss->mesh = 1; > - } else { > - lbs_deb_scan("got generic IE: %02x:%02x:%02x:%02x, len %d\n", > - pos[2], pos[3], > - pos[4], pos[5], > - pos[1]); > - } > - break; > - > - case WLAN_EID_RSN: > - lbs_deb_scan("got RSN IE\n"); > - bss->rsn_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN); > - memcpy(bss->rsn_ie, pos, bss->rsn_ie_len); > - lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE", > - bss->rsn_ie, bss->rsn_ie_len); > - break; > - > - default: > - lbs_deb_scan("got IE 0x%04x, len %d\n", > - pos[0], pos[1]); > - break; > - } > - > - pos += pos[1] + 2; > - } > - > - /* Timestamp */ > - bss->last_scanned = jiffies; > - lbs_unset_basic_rate_flags(bss->rates, sizeof(bss->rates)); > - > - ret = 0; > - > -done: > - lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); > - return ret; > -} > - > -/** > - * @brief Send a scan command for all available channels filtered on a spec > - * > - * Used in association code and from debugfs > - * > - * @param priv A pointer to struct lbs_private structure > - * @param ssid A pointer to the SSID to scan for > - * @param ssid_len Length of the SSID > - * > - * @return 0-success, otherwise fail > - */ > -int lbs_send_specific_ssid_scan(struct lbs_private *priv, uint8_t *ssid, > - uint8_t ssid_len) > -{ > - DECLARE_SSID_BUF(ssid_buf); > - int ret = 0; > - > - lbs_deb_enter_args(LBS_DEB_SCAN, "SSID '%s'\n", > - print_ssid(ssid_buf, ssid, ssid_len)); > - > - if (!ssid_len) > - goto out; > - > - memcpy(priv->scan_ssid, ssid, ssid_len); > - priv->scan_ssid_len = ssid_len; > - > - lbs_scan_networks(priv, 1); > - if (priv->surpriseremoved) { > - ret = -1; > - goto out; > - } > - > -out: > - lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); > - return ret; > -} > - > - > - > - > -/*********************************************************************/ > -/* */ > -/* Support for Wireless Extensions */ > -/* */ > -/*********************************************************************/ > - > - > -#define MAX_CUSTOM_LEN 64 > - > -static inline char *lbs_translate_scan(struct lbs_private *priv, > - struct iw_request_info *info, > - char *start, char *stop, > - struct bss_descriptor *bss) > -{ > - struct chan_freq_power *cfp; > - char *current_val; /* For rates */ > - struct iw_event iwe; /* Temporary buffer */ > - int j; > -#define PERFECT_RSSI ((uint8_t)50) > -#define WORST_RSSI ((uint8_t)0) > -#define RSSI_DIFF ((uint8_t)(PERFECT_RSSI - WORST_RSSI)) > - uint8_t rssi; > - > - lbs_deb_enter(LBS_DEB_SCAN); > - > - cfp = lbs_find_cfp_by_band_and_channel(priv, 0, bss->channel); > - if (!cfp) { > - lbs_deb_scan("Invalid channel number %d\n", bss->channel); > - start = NULL; > - goto out; > - } > - > - /* First entry *MUST* be the BSSID */ > - iwe.cmd = SIOCGIWAP; > - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; > - memcpy(iwe.u.ap_addr.sa_data, &bss->bssid, ETH_ALEN); > - start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN); > - > - /* SSID */ > - iwe.cmd = SIOCGIWESSID; > - iwe.u.data.flags = 1; > - iwe.u.data.length = min((uint32_t) bss->ssid_len, (uint32_t) IEEE80211_MAX_SSID_LEN); > - start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid); > - > - /* Mode */ > - iwe.cmd = SIOCGIWMODE; > - iwe.u.mode = bss->mode; > - start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_UINT_LEN); > - > - /* Frequency */ > - iwe.cmd = SIOCGIWFREQ; > - iwe.u.freq.m = (long)cfp->freq * 100000; > - iwe.u.freq.e = 1; > - start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN); > - > - /* Add quality statistics */ > - iwe.cmd = IWEVQUAL; > - iwe.u.qual.updated = IW_QUAL_ALL_UPDATED; > - iwe.u.qual.level = SCAN_RSSI(bss->rssi); > - > - rssi = iwe.u.qual.level - MRVDRV_NF_DEFAULT_SCAN_VALUE; > - iwe.u.qual.qual = > - (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - rssi) * > - (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - rssi))) / > - (RSSI_DIFF * RSSI_DIFF); > - if (iwe.u.qual.qual > 100) > - iwe.u.qual.qual = 100; > - > - if (priv->NF[TYPE_BEACON][TYPE_NOAVG] == 0) { > - iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE; > - } else { > - iwe.u.qual.noise = CAL_NF(priv->NF[TYPE_BEACON][TYPE_NOAVG]); > - } > - > - /* Locally created ad-hoc BSSs won't have beacons if this is the > - * only station in the adhoc network; so get signal strength > - * from receive statistics. > - */ > - if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate > - && !lbs_ssid_cmp(priv->curbssparams.ssid, > - priv->curbssparams.ssid_len, > - bss->ssid, bss->ssid_len)) { > - int snr, nf; > - snr = priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; > - nf = priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; > - iwe.u.qual.level = CAL_RSSI(snr, nf); > - } > - start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN); > - > - /* Add encryption capability */ > - iwe.cmd = SIOCGIWENCODE; > - if (bss->capability & WLAN_CAPABILITY_PRIVACY) { > - iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; > - } else { > - iwe.u.data.flags = IW_ENCODE_DISABLED; > - } > - iwe.u.data.length = 0; > - start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid); > - > - current_val = start + iwe_stream_lcp_len(info); > - > - iwe.cmd = SIOCGIWRATE; > - iwe.u.bitrate.fixed = 0; > - iwe.u.bitrate.disabled = 0; > - iwe.u.bitrate.value = 0; > - > - for (j = 0; j < ARRAY_SIZE(bss->rates) && bss->rates[j]; j++) { > - /* Bit rate given in 500 kb/s units */ > - iwe.u.bitrate.value = bss->rates[j] * 500000; > - current_val = iwe_stream_add_value(info, start, current_val, > - stop, &iwe, IW_EV_PARAM_LEN); > - } > - if ((bss->mode == IW_MODE_ADHOC) && priv->adhoccreate > - && !lbs_ssid_cmp(priv->curbssparams.ssid, > - priv->curbssparams.ssid_len, > - bss->ssid, bss->ssid_len)) { > - iwe.u.bitrate.value = 22 * 500000; > - current_val = iwe_stream_add_value(info, start, current_val, > - stop, &iwe, IW_EV_PARAM_LEN); > - } > - /* Check if we added any event */ > - if ((current_val - start) > iwe_stream_lcp_len(info)) > - start = current_val; > - > - memset(&iwe, 0, sizeof(iwe)); > - if (bss->wpa_ie_len) { > - char buf[MAX_WPA_IE_LEN]; > - memcpy(buf, bss->wpa_ie, bss->wpa_ie_len); > - iwe.cmd = IWEVGENIE; > - iwe.u.data.length = bss->wpa_ie_len; > - start = iwe_stream_add_point(info, start, stop, &iwe, buf); > - } > - > - memset(&iwe, 0, sizeof(iwe)); > - if (bss->rsn_ie_len) { > - char buf[MAX_WPA_IE_LEN]; > - memcpy(buf, bss->rsn_ie, bss->rsn_ie_len); > - iwe.cmd = IWEVGENIE; > - iwe.u.data.length = bss->rsn_ie_len; > - start = iwe_stream_add_point(info, start, stop, &iwe, buf); > - } > - > - if (bss->mesh) { > - char custom[MAX_CUSTOM_LEN]; > - char *p = custom; > - > - iwe.cmd = IWEVCUSTOM; > - p += snprintf(p, MAX_CUSTOM_LEN, "mesh-type: olpc"); > - iwe.u.data.length = p - custom; > - if (iwe.u.data.length) > - start = iwe_stream_add_point(info, start, stop, > - &iwe, custom); > - } > - > -out: > - lbs_deb_leave_args(LBS_DEB_SCAN, "start %p", start); > - return start; > -} > - > - > -/** > - * @brief Handle Scan Network ioctl > - * > - * @param dev A pointer to net_device structure > - * @param info A pointer to iw_request_info structure > - * @param vwrq A pointer to iw_param structure > - * @param extra A pointer to extra data buf > - * > - * @return 0 --success, otherwise fail > - */ > -int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, > - union iwreq_data *wrqu, char *extra) > -{ > - DECLARE_SSID_BUF(ssid); > - struct lbs_private *priv = dev->ml_priv; > - int ret = 0; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - if (!priv->radio_on) { > - ret = -EINVAL; > - goto out; > - } > - > - if (!netif_running(dev)) { > - ret = -ENETDOWN; > - goto out; > - } > - > - /* mac80211 does this: > - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); > - if (sdata->type != IEEE80211_IF_TYPE_xxx) { > - ret = -EOPNOTSUPP; > - goto out; > - } > - */ > - > - if (wrqu->data.length == sizeof(struct iw_scan_req) && > - wrqu->data.flags & IW_SCAN_THIS_ESSID) { > - struct iw_scan_req *req = (struct iw_scan_req *)extra; > - priv->scan_ssid_len = req->essid_len; > - memcpy(priv->scan_ssid, req->essid, priv->scan_ssid_len); > - lbs_deb_wext("set_scan, essid '%s'\n", > - print_ssid(ssid, priv->scan_ssid, priv->scan_ssid_len)); > - } else { > - priv->scan_ssid_len = 0; > - } > - > - if (!delayed_work_pending(&priv->scan_work)) > - queue_delayed_work(priv->work_thread, &priv->scan_work, > - msecs_to_jiffies(50)); > - /* set marker that currently a scan is taking place */ > - priv->scan_channel = -1; > - > - if (priv->surpriseremoved) > - ret = -EIO; > - > -out: > - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); > - return ret; > -} > - > - > -/** > - * @brief Handle Retrieve scan table ioctl > - * > - * @param dev A pointer to net_device structure > - * @param info A pointer to iw_request_info structure > - * @param dwrq A pointer to iw_point structure > - * @param extra A pointer to extra data buf > - * > - * @return 0 --success, otherwise fail > - */ > -int lbs_get_scan(struct net_device *dev, struct iw_request_info *info, > - struct iw_point *dwrq, char *extra) > -{ > -#define SCAN_ITEM_SIZE 128 > - struct lbs_private *priv = dev->ml_priv; > - int err = 0; > - char *ev = extra; > - char *stop = ev + dwrq->length; > - struct bss_descriptor *iter_bss; > - struct bss_descriptor *safe; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - /* iwlist should wait until the current scan is finished */ > - if (priv->scan_channel) > - return -EAGAIN; > - > - /* Update RSSI if current BSS is a locally created ad-hoc BSS */ > - if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate) { > - err = lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, > - CMD_OPTION_WAITFORRSP, 0, NULL); > - if (err) > - goto out; > - } > - > - mutex_lock(&priv->lock); > - list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) { > - char *next_ev; > - unsigned long stale_time; > - > - if (stop - ev < SCAN_ITEM_SIZE) { > - err = -E2BIG; > - break; > - } > - > - /* For mesh device, list only mesh networks */ > - if (dev == priv->mesh_dev && !iter_bss->mesh) > - continue; > - > - /* Prune old an old scan result */ > - stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE; > - if (time_after(jiffies, stale_time)) { > - list_move_tail(&iter_bss->list, &priv->network_free_list); > - clear_bss_descriptor(iter_bss); > - continue; > - } > - > - /* Translate to WE format this entry */ > - next_ev = lbs_translate_scan(priv, info, ev, stop, iter_bss); > - if (next_ev == NULL) > - continue; > - ev = next_ev; > - } > - mutex_unlock(&priv->lock); > - > - dwrq->length = (ev - extra); > - dwrq->flags = 0; > -out: > - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", err); > - return err; > -} > - > - > - > - > -/*********************************************************************/ > -/* */ > -/* Command execution */ > -/* */ > -/*********************************************************************/ > - > - > -/** > - * @brief This function handles the command response of scan > - * > - * Called from handle_cmd_response() in cmdrespc. > - * > - * The response buffer for the scan command has the following > - * memory layout: > - * > - * .-----------------------------------------------------------. > - * | header (4 * sizeof(u16)): Standard command response hdr | > - * .-----------------------------------------------------------. > - * | bufsize (u16) : sizeof the BSS Description data | > - * .-----------------------------------------------------------. > - * | NumOfSet (u8) : Number of BSS Descs returned | > - * .-----------------------------------------------------------. > - * | BSSDescription data (variable, size given in bufsize) | > - * .-----------------------------------------------------------. > - * | TLV data (variable, size calculated using header->size, | > - * | bufsize and sizeof the fixed fields above) | > - * .-----------------------------------------------------------. > - * > - * @param priv A pointer to struct lbs_private structure > - * @param resp A pointer to cmd_ds_command > - * > - * @return 0 or -1 > - */ > -static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy, > - struct cmd_header *resp) > -{ > - struct cmd_ds_802_11_scan_rsp *scanresp = (void *)resp; > - struct bss_descriptor *iter_bss; > - struct bss_descriptor *safe; > - uint8_t *bssinfo; > - uint16_t scanrespsize; > - int bytesleft; > - int idx; > - int tlvbufsize; > - int ret; > - > - lbs_deb_enter(LBS_DEB_SCAN); > - > - /* Prune old entries from scan table */ > - list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) { > - unsigned long stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE; > - if (time_before(jiffies, stale_time)) > - continue; > - list_move_tail (&iter_bss->list, &priv->network_free_list); > - clear_bss_descriptor(iter_bss); > - } > - > - if (scanresp->nr_sets > MAX_NETWORK_COUNT) { > - lbs_deb_scan("SCAN_RESP: too many scan results (%d, max %d)\n", > - scanresp->nr_sets, MAX_NETWORK_COUNT); > - ret = -1; > - goto done; > - } > - > - bytesleft = get_unaligned_le16(&scanresp->bssdescriptsize); > - lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft); > - > - scanrespsize = le16_to_cpu(resp->size); > - lbs_deb_scan("SCAN_RESP: scan results %d\n", scanresp->nr_sets); > - > - bssinfo = scanresp->bssdesc_and_tlvbuffer; > - > - /* The size of the TLV buffer is equal to the entire command response > - * size (scanrespsize) minus the fixed fields (sizeof()'s), the > - * BSS Descriptions (bssdescriptsize as bytesLef) and the command > - * response header (sizeof(struct cmd_header)) > - */ > - tlvbufsize = scanrespsize - (bytesleft + sizeof(scanresp->bssdescriptsize) > - + sizeof(scanresp->nr_sets) > - + sizeof(struct cmd_header)); > - > - /* > - * Process each scan response returned (scanresp->nr_sets). Save > - * the information in the newbssentry and then insert into the > - * driver scan table either as an update to an existing entry > - * or as an addition at the end of the table > - */ > - for (idx = 0; idx < scanresp->nr_sets && bytesleft; idx++) { > - struct bss_descriptor new; > - struct bss_descriptor *found = NULL; > - struct bss_descriptor *oldest = NULL; > - > - /* Process the data fields and IEs returned for this BSS */ > - memset(&new, 0, sizeof (struct bss_descriptor)); > - if (lbs_process_bss(&new, &bssinfo, &bytesleft) != 0) { > - /* error parsing the scan response, skipped */ > - lbs_deb_scan("SCAN_RESP: process_bss returned ERROR\n"); > - continue; > - } > - > - /* Try to find this bss in the scan table */ > - list_for_each_entry (iter_bss, &priv->network_list, list) { > - if (is_same_network(iter_bss, &new)) { > - found = iter_bss; > - break; > - } > - > - if ((oldest == NULL) || > - (iter_bss->last_scanned < oldest->last_scanned)) > - oldest = iter_bss; > - } > - > - if (found) { > - /* found, clear it */ > - clear_bss_descriptor(found); > - } else if (!list_empty(&priv->network_free_list)) { > - /* Pull one from the free list */ > - found = list_entry(priv->network_free_list.next, > - struct bss_descriptor, list); > - list_move_tail(&found->list, &priv->network_list); > - } else if (oldest) { > - /* If there are no more slots, expire the oldest */ > - found = oldest; > - clear_bss_descriptor(found); > - list_move_tail(&found->list, &priv->network_list); > - } else { > - continue; > - } > - > - lbs_deb_scan("SCAN_RESP: BSSID %pM\n", new.bssid); > - > - /* Copy the locally created newbssentry to the scan table */ > - memcpy(found, &new, offsetof(struct bss_descriptor, list)); > - } > - > - ret = 0; > - > -done: > - lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); > - return ret; > -} > --- linux-wl.orig/drivers/net/wireless/libertas/wext.h > +++ /dev/null > @@ -1,17 +0,0 @@ > -/** > - * This file contains definition for IOCTL call. > - */ > -#ifndef _LBS_WEXT_H_ > -#define _LBS_WEXT_H_ > - > -void lbs_send_disconnect_notification(struct lbs_private *priv); > -void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event); > - > -struct chan_freq_power *lbs_find_cfp_by_band_and_channel( > - struct lbs_private *priv, > - u8 band, > - u16 channel); > - > -extern struct iw_handler_def lbs_handler_def; > - > -#endif > --- linux-wl.orig/drivers/net/wireless/libertas/wext.c > +++ /dev/null > @@ -1,2350 +0,0 @@ > -/** > - * This file contains ioctl functions > - */ > -#include > -#include > -#include > -#include > -#include > -#include > - > -#include > -#include > - > -#include "host.h" > -#include "radiotap.h" > -#include "decl.h" > -#include "defs.h" > -#include "dev.h" > -#include "wext.h" > -#include "scan.h" > -#include "assoc.h" > -#include "cmd.h" > - > - > -static inline void lbs_postpone_association_work(struct lbs_private *priv) > -{ > - if (priv->surpriseremoved) > - return; > - cancel_delayed_work(&priv->assoc_work); > - queue_delayed_work(priv->work_thread, &priv->assoc_work, HZ / 2); > -} > - > -static inline void lbs_do_association_work(struct lbs_private *priv) > -{ > - if (priv->surpriseremoved) > - return; > - cancel_delayed_work(&priv->assoc_work); > - queue_delayed_work(priv->work_thread, &priv->assoc_work, 0); > -} > - > -static inline void lbs_cancel_association_work(struct lbs_private *priv) > -{ > - cancel_delayed_work(&priv->assoc_work); > - kfree(priv->pending_assoc_req); > - priv->pending_assoc_req = NULL; > -} > - > -void lbs_send_disconnect_notification(struct lbs_private *priv) > -{ > - union iwreq_data wrqu; > - > - memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN); > - wrqu.ap_addr.sa_family = ARPHRD_ETHER; > - wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); > -} > - > -static void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str) > -{ > - union iwreq_data iwrq; > - u8 buf[50]; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - memset(&iwrq, 0, sizeof(union iwreq_data)); > - memset(buf, 0, sizeof(buf)); > - > - snprintf(buf, sizeof(buf) - 1, "%s", str); > - > - iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN; > - > - /* Send Event to upper layer */ > - lbs_deb_wext("event indication string %s\n", (char *)buf); > - lbs_deb_wext("event indication length %d\n", iwrq.data.length); > - lbs_deb_wext("sending wireless event IWEVCUSTOM for %s\n", str); > - > - wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf); > - > - lbs_deb_leave(LBS_DEB_WEXT); > -} > - > -/** > - * @brief This function handles MIC failure event. > - * > - * @param priv A pointer to struct lbs_private structure > - * @para event the event id > - * @return n/a > - */ > -void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event) > -{ > - char buf[50]; > - > - lbs_deb_enter(LBS_DEB_CMD); > - memset(buf, 0, sizeof(buf)); > - > - sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication "); > - > - if (event == MACREG_INT_CODE_MIC_ERR_UNICAST) > - strcat(buf, "unicast "); > - else > - strcat(buf, "multicast "); > - > - lbs_send_iwevcustom_event(priv, buf); > - lbs_deb_leave(LBS_DEB_CMD); > -} > - > -/** > - * @brief Find the channel frequency power info with specific channel > - * > - * @param priv A pointer to struct lbs_private structure > - * @param band it can be BAND_A, BAND_G or BAND_B > - * @param channel the channel for looking > - * @return A pointer to struct chan_freq_power structure or NULL if not find. > - */ > -struct chan_freq_power *lbs_find_cfp_by_band_and_channel( > - struct lbs_private *priv, > - u8 band, > - u16 channel) > -{ > - struct chan_freq_power *cfp = NULL; > - struct region_channel *rc; > - int i, j; > - > - for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) { > - rc = &priv->region_channel[j]; > - > - if (!rc->valid || !rc->CFP) > - continue; > - if (rc->band != band) > - continue; > - for (i = 0; i < rc->nrcfp; i++) { > - if (rc->CFP[i].channel == channel) { > - cfp = &rc->CFP[i]; > - break; > - } > - } > - } > - > - if (!cfp && channel) > - lbs_deb_wext("lbs_find_cfp_by_band_and_channel: can't find " > - "cfp by band %d / channel %d\n", band, channel); > - > - return cfp; > -} > - > -/** > - * @brief Find the channel frequency power info with specific frequency > - * > - * @param priv A pointer to struct lbs_private structure > - * @param band it can be BAND_A, BAND_G or BAND_B > - * @param freq the frequency for looking > - * @return A pointer to struct chan_freq_power structure or NULL if not find. > - */ > -static struct chan_freq_power *find_cfp_by_band_and_freq( > - struct lbs_private *priv, > - u8 band, > - u32 freq) > -{ > - struct chan_freq_power *cfp = NULL; > - struct region_channel *rc; > - int i, j; > - > - for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) { > - rc = &priv->region_channel[j]; > - > - if (!rc->valid || !rc->CFP) > - continue; > - if (rc->band != band) > - continue; > - for (i = 0; i < rc->nrcfp; i++) { > - if (rc->CFP[i].freq == freq) { > - cfp = &rc->CFP[i]; > - break; > - } > - } > - } > - > - if (!cfp && freq) > - lbs_deb_wext("find_cfp_by_band_and_freql: can't find cfp by " > - "band %d / freq %d\n", band, freq); > - > - return cfp; > -} > - > -/** > - * @brief Copy active data rates based on adapter mode and status > - * > - * @param priv A pointer to struct lbs_private structure > - * @param rate The buf to return the active rates > - */ > -static void copy_active_data_rates(struct lbs_private *priv, u8 *rates) > -{ > - lbs_deb_enter(LBS_DEB_WEXT); > - > - if ((priv->connect_status != LBS_CONNECTED) && > - !lbs_mesh_connected(priv)) > - memcpy(rates, lbs_bg_rates, MAX_RATES); > - else > - memcpy(rates, priv->curbssparams.rates, MAX_RATES); > - > - lbs_deb_leave(LBS_DEB_WEXT); > -} > - > -static int lbs_get_name(struct net_device *dev, struct iw_request_info *info, > - char *cwrq, char *extra) > -{ > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - /* We could add support for 802.11n here as needed. Jean II */ > - snprintf(cwrq, IFNAMSIZ, "IEEE 802.11b/g"); > - > - lbs_deb_leave(LBS_DEB_WEXT); > - return 0; > -} > - > -static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info, > - struct iw_freq *fwrq, char *extra) > -{ > - struct lbs_private *priv = dev->ml_priv; > - struct chan_freq_power *cfp; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - cfp = lbs_find_cfp_by_band_and_channel(priv, 0, > - priv->channel); > - > - if (!cfp) { > - if (priv->channel) > - lbs_deb_wext("invalid channel %d\n", > - priv->channel); > - return -EINVAL; > - } > - > - fwrq->m = (long)cfp->freq * 100000; > - fwrq->e = 1; > - > - lbs_deb_wext("freq %u\n", fwrq->m); > - lbs_deb_leave(LBS_DEB_WEXT); > - return 0; > -} > - > -static int lbs_get_wap(struct net_device *dev, struct iw_request_info *info, > - struct sockaddr *awrq, char *extra) > -{ > - struct lbs_private *priv = dev->ml_priv; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - if (priv->connect_status == LBS_CONNECTED) { > - memcpy(awrq->sa_data, priv->curbssparams.bssid, ETH_ALEN); > - } else { > - memset(awrq->sa_data, 0, ETH_ALEN); > - } > - awrq->sa_family = ARPHRD_ETHER; > - > - lbs_deb_leave(LBS_DEB_WEXT); > - return 0; > -} > - > -static int lbs_set_nick(struct net_device *dev, struct iw_request_info *info, > - struct iw_point *dwrq, char *extra) > -{ > - struct lbs_private *priv = dev->ml_priv; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - /* > - * Check the size of the string > - */ > - > - if (dwrq->length > 16) { > - return -E2BIG; > - } > - > - mutex_lock(&priv->lock); > - memset(priv->nodename, 0, sizeof(priv->nodename)); > - memcpy(priv->nodename, extra, dwrq->length); > - mutex_unlock(&priv->lock); > - > - lbs_deb_leave(LBS_DEB_WEXT); > - return 0; > -} > - > -static int lbs_get_nick(struct net_device *dev, struct iw_request_info *info, > - struct iw_point *dwrq, char *extra) > -{ > - struct lbs_private *priv = dev->ml_priv; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - dwrq->length = strlen(priv->nodename); > - memcpy(extra, priv->nodename, dwrq->length); > - extra[dwrq->length] = '\0'; > - > - dwrq->flags = 1; /* active */ > - > - lbs_deb_leave(LBS_DEB_WEXT); > - return 0; > -} > - > -#ifdef CONFIG_LIBERTAS_MESH > -static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info, > - struct iw_point *dwrq, char *extra) > -{ > - struct lbs_private *priv = dev->ml_priv; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - /* Use nickname to indicate that mesh is on */ > - > - if (lbs_mesh_connected(priv)) { > - strncpy(extra, "Mesh", 12); > - extra[12] = '\0'; > - dwrq->length = strlen(extra); > - } > - > - else { > - extra[0] = '\0'; > - dwrq->length = 0; > - } > - > - lbs_deb_leave(LBS_DEB_WEXT); > - return 0; > -} > -#endif > - > -static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info, > - struct iw_param *vwrq, char *extra) > -{ > - int ret = 0; > - struct lbs_private *priv = dev->ml_priv; > - u32 val = vwrq->value; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - if (vwrq->disabled) > - val = MRVDRV_RTS_MAX_VALUE; > - > - if (val > MRVDRV_RTS_MAX_VALUE) /* min rts value is 0 */ > - return -EINVAL; > - > - ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, (u16) val); > - > - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); > - return ret; > -} > - > -static int lbs_get_rts(struct net_device *dev, struct iw_request_info *info, > - struct iw_param *vwrq, char *extra) > -{ > - struct lbs_private *priv = dev->ml_priv; > - int ret = 0; > - u16 val = 0; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, &val); > - if (ret) > - goto out; > - > - vwrq->value = val; > - vwrq->disabled = val > MRVDRV_RTS_MAX_VALUE; /* min rts value is 0 */ > - vwrq->fixed = 1; > - > -out: > - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); > - return ret; > -} > - > -static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info, > - struct iw_param *vwrq, char *extra) > -{ > - struct lbs_private *priv = dev->ml_priv; > - int ret = 0; > - u32 val = vwrq->value; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - if (vwrq->disabled) > - val = MRVDRV_FRAG_MAX_VALUE; > - > - if (val < MRVDRV_FRAG_MIN_VALUE || val > MRVDRV_FRAG_MAX_VALUE) > - return -EINVAL; > - > - ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, (u16) val); > - > - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); > - return ret; > -} > - > -static int lbs_get_frag(struct net_device *dev, struct iw_request_info *info, > - struct iw_param *vwrq, char *extra) > -{ > - struct lbs_private *priv = dev->ml_priv; > - int ret = 0; > - u16 val = 0; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, &val); > - if (ret) > - goto out; > - > - vwrq->value = val; > - vwrq->disabled = ((val < MRVDRV_FRAG_MIN_VALUE) > - || (val > MRVDRV_FRAG_MAX_VALUE)); > - vwrq->fixed = 1; > - > -out: > - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); > - return ret; > -} > - > -static int lbs_get_mode(struct net_device *dev, > - struct iw_request_info *info, u32 * uwrq, char *extra) > -{ > - struct lbs_private *priv = dev->ml_priv; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - *uwrq = priv->mode; > - > - lbs_deb_leave(LBS_DEB_WEXT); > - return 0; > -} > - > -#ifdef CONFIG_LIBERTAS_MESH > -static int mesh_wlan_get_mode(struct net_device *dev, > - struct iw_request_info *info, u32 * uwrq, > - char *extra) > -{ > - lbs_deb_enter(LBS_DEB_WEXT); > - > - *uwrq = IW_MODE_REPEAT; > - > - lbs_deb_leave(LBS_DEB_WEXT); > - return 0; > -} > -#endif > - > -static int lbs_get_txpow(struct net_device *dev, > - struct iw_request_info *info, > - struct iw_param *vwrq, char *extra) > -{ > - struct lbs_private *priv = dev->ml_priv; > - s16 curlevel = 0; > - int ret = 0; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - if (!priv->radio_on) { > - lbs_deb_wext("tx power off\n"); > - vwrq->value = 0; > - vwrq->disabled = 1; > - goto out; > - } > - > - ret = lbs_get_tx_power(priv, &curlevel, NULL, NULL); > - if (ret) > - goto out; > - > - lbs_deb_wext("tx power level %d dbm\n", curlevel); > - priv->txpower_cur = curlevel; > - > - vwrq->value = curlevel; > - vwrq->fixed = 1; > - vwrq->disabled = 0; > - vwrq->flags = IW_TXPOW_DBM; > - > -out: > - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); > - return ret; > -} > - > -static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info, > - struct iw_param *vwrq, char *extra) > -{ > - struct lbs_private *priv = dev->ml_priv; > - int ret = 0; > - u16 slimit = 0, llimit = 0; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - if ((vwrq->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT) > - return -EOPNOTSUPP; > - > - /* The MAC has a 4-bit Total_Tx_Count register > - Total_Tx_Count = 1 + Tx_Retry_Count */ > -#define TX_RETRY_MIN 0 > -#define TX_RETRY_MAX 14 > - if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX) > - return -EINVAL; > - > - /* Add 1 to convert retry count to try count */ > - if (vwrq->flags & IW_RETRY_SHORT) > - slimit = (u16) (vwrq->value + 1); > - else if (vwrq->flags & IW_RETRY_LONG) > - llimit = (u16) (vwrq->value + 1); > - else > - slimit = llimit = (u16) (vwrq->value + 1); /* set both */ > - > - if (llimit) { > - ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_LONG_RETRY_LIMIT, > - llimit); > - if (ret) > - goto out; > - } > - > - if (slimit) { > - /* txretrycount follows the short retry limit */ > - priv->txretrycount = slimit; > - ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_SHORT_RETRY_LIMIT, > - slimit); > - if (ret) > - goto out; > - } > - > -out: > - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); > - return ret; > -} > - > -static int lbs_get_retry(struct net_device *dev, struct iw_request_info *info, > - struct iw_param *vwrq, char *extra) > -{ > - struct lbs_private *priv = dev->ml_priv; > - int ret = 0; > - u16 val = 0; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - vwrq->disabled = 0; > - > - if (vwrq->flags & IW_RETRY_LONG) { > - ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_LONG_RETRY_LIMIT, &val); > - if (ret) > - goto out; > - > - /* Subtract 1 to convert try count to retry count */ > - vwrq->value = val - 1; > - vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; > - } else { > - ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_SHORT_RETRY_LIMIT, &val); > - if (ret) > - goto out; > - > - /* txretry count follows the short retry limit */ > - priv->txretrycount = val; > - /* Subtract 1 to convert try count to retry count */ > - vwrq->value = val - 1; > - vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_SHORT; > - } > - > -out: > - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); > - return ret; > -} > - > -static inline void sort_channels(struct iw_freq *freq, int num) > -{ > - int i, j; > - struct iw_freq temp; > - > - for (i = 0; i < num; i++) > - for (j = i + 1; j < num; j++) > - if (freq[i].i > freq[j].i) { > - temp.i = freq[i].i; > - temp.m = freq[i].m; > - > - freq[i].i = freq[j].i; > - freq[i].m = freq[j].m; > - > - freq[j].i = temp.i; > - freq[j].m = temp.m; > - } > -} > - > -/* data rate listing > - MULTI_BANDS: > - abg a b b/g > - Infra G(12) A(8) B(4) G(12) > - Adhoc A+B(12) A(8) B(4) B(4) > - > - non-MULTI_BANDS: > - b b/g > - Infra B(4) G(12) > - Adhoc B(4) B(4) > - */ > -/** > - * @brief Get Range Info > - * > - * @param dev A pointer to net_device structure > - * @param info A pointer to iw_request_info structure > - * @param vwrq A pointer to iw_param structure > - * @param extra A pointer to extra data buf > - * @return 0 --success, otherwise fail > - */ > -static int lbs_get_range(struct net_device *dev, struct iw_request_info *info, > - struct iw_point *dwrq, char *extra) > -{ > - int i, j; > - struct lbs_private *priv = dev->ml_priv; > - struct iw_range *range = (struct iw_range *)extra; > - struct chan_freq_power *cfp; > - u8 rates[MAX_RATES + 1]; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - dwrq->length = sizeof(struct iw_range); > - memset(range, 0, sizeof(struct iw_range)); > - > - range->min_nwid = 0; > - range->max_nwid = 0; > - > - memset(rates, 0, sizeof(rates)); > - copy_active_data_rates(priv, rates); > - range->num_bitrates = strnlen(rates, IW_MAX_BITRATES); > - for (i = 0; i < range->num_bitrates; i++) > - range->bitrate[i] = rates[i] * 500000; > - range->num_bitrates = i; > - lbs_deb_wext("IW_MAX_BITRATES %d, num_bitrates %d\n", IW_MAX_BITRATES, > - range->num_bitrates); > - > - range->num_frequency = 0; > - > - range->scan_capa = IW_SCAN_CAPA_ESSID; > - > - for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES) > - && (j < ARRAY_SIZE(priv->region_channel)); j++) { > - cfp = priv->region_channel[j].CFP; > - for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES) > - && priv->region_channel[j].valid > - && cfp > - && (i < priv->region_channel[j].nrcfp); i++) { > - range->freq[range->num_frequency].i = > - (long)cfp->channel; > - range->freq[range->num_frequency].m = > - (long)cfp->freq * 100000; > - range->freq[range->num_frequency].e = 1; > - cfp++; > - range->num_frequency++; > - } > - } > - > - lbs_deb_wext("IW_MAX_FREQUENCIES %d, num_frequency %d\n", > - IW_MAX_FREQUENCIES, range->num_frequency); > - > - range->num_channels = range->num_frequency; > - > - sort_channels(&range->freq[0], range->num_frequency); > - > - /* > - * Set an indication of the max TCP throughput in bit/s that we can > - * expect using this interface > - */ > - if (i > 2) > - range->throughput = 5000 * 1000; > - else > - range->throughput = 1500 * 1000; > - > - range->min_rts = MRVDRV_RTS_MIN_VALUE; > - range->max_rts = MRVDRV_RTS_MAX_VALUE; > - range->min_frag = MRVDRV_FRAG_MIN_VALUE; > - range->max_frag = MRVDRV_FRAG_MAX_VALUE; > - > - range->encoding_size[0] = 5; > - range->encoding_size[1] = 13; > - range->num_encoding_sizes = 2; > - range->max_encoding_tokens = 4; > - > - /* > - * Right now we support only "iwconfig ethX power on|off" > - */ > - range->pm_capa = IW_POWER_ON; > - > - /* > - * Minimum version we recommend > - */ > - range->we_version_source = 15; > - > - /* > - * Version we are compiled with > - */ > - range->we_version_compiled = WIRELESS_EXT; > - > - range->retry_capa = IW_RETRY_LIMIT; > - range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX; > - > - range->min_retry = TX_RETRY_MIN; > - range->max_retry = TX_RETRY_MAX; > - > - /* > - * Set the qual, level and noise range values > - */ > - range->max_qual.qual = 100; > - range->max_qual.level = 0; > - range->max_qual.noise = 0; > - range->max_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; > - > - range->avg_qual.qual = 70; > - /* TODO: Find real 'good' to 'bad' threshold value for RSSI */ > - range->avg_qual.level = 0; > - range->avg_qual.noise = 0; > - range->avg_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; > - > - range->sensitivity = 0; > - > - /* Setup the supported power level ranges */ > - memset(range->txpower, 0, sizeof(range->txpower)); > - range->txpower_capa = IW_TXPOW_DBM | IW_TXPOW_RANGE; > - range->txpower[0] = priv->txpower_min; > - range->txpower[1] = priv->txpower_max; > - range->num_txpower = 2; > - > - range->event_capa[0] = (IW_EVENT_CAPA_K_0 | > - IW_EVENT_CAPA_MASK(SIOCGIWAP) | > - IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); > - range->event_capa[1] = IW_EVENT_CAPA_K_1; > - > - if (priv->fwcapinfo & FW_CAPINFO_WPA) { > - range->enc_capa = IW_ENC_CAPA_WPA > - | IW_ENC_CAPA_WPA2 > - | IW_ENC_CAPA_CIPHER_TKIP > - | IW_ENC_CAPA_CIPHER_CCMP; > - } > - > - lbs_deb_leave(LBS_DEB_WEXT); > - return 0; > -} > - > -static int lbs_set_power(struct net_device *dev, struct iw_request_info *info, > - struct iw_param *vwrq, char *extra) > -{ > - struct lbs_private *priv = dev->ml_priv; > - int ret = 0; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - if (!(priv->fwcapinfo & FW_CAPINFO_PS)) { > - if (vwrq->disabled) > - return 0; > - else > - return -EINVAL; > - } > - > - /* PS is currently supported only in Infrastructure mode > - * Remove this check if it is to be supported in IBSS mode also > - */ > - > - if (vwrq->disabled) { > - priv->psmode = LBS802_11POWERMODECAM; > - if (priv->psstate != PS_STATE_FULL_POWER) { > - lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP); > - } > - > - return 0; > - } > - > - if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { > - lbs_deb_wext( > - "setting power timeout is not supported\n"); > - return -EINVAL; > - } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) { > - vwrq->value = vwrq->value / 1000; > - if (!priv->enter_deep_sleep) { > - lbs_pr_err("deep sleep feature is not implemented " > - "for this interface driver\n"); > - return -EINVAL; > - } > - > - if (priv->connect_status == LBS_CONNECTED) { > - if ((priv->is_auto_deep_sleep_enabled) && > - (vwrq->value == -1000)) { > - lbs_exit_auto_deep_sleep(priv); > - return 0; > - } else { > - lbs_pr_err("can't use deep sleep cmd in " > - "connected state\n"); > - return -EINVAL; > - } > - } > - > - if ((vwrq->value < 0) && (vwrq->value != -1000)) { > - lbs_pr_err("unknown option\n"); > - return -EINVAL; > - } > - > - if (vwrq->value > 0) { > - if (!priv->is_auto_deep_sleep_enabled) { > - priv->is_activity_detected = 0; > - priv->auto_deep_sleep_timeout = vwrq->value; > - lbs_enter_auto_deep_sleep(priv); > - } else { > - priv->auto_deep_sleep_timeout = vwrq->value; > - lbs_deb_debugfs("auto deep sleep: " > - "already enabled\n"); > - } > - return 0; > - } else { > - if (priv->is_auto_deep_sleep_enabled) { > - lbs_exit_auto_deep_sleep(priv); > - /* Try to exit deep sleep if auto */ > - /*deep sleep disabled */ > - ret = lbs_set_deep_sleep(priv, 0); > - } > - if (vwrq->value == 0) > - ret = lbs_set_deep_sleep(priv, 1); > - else if (vwrq->value == -1000) > - ret = lbs_set_deep_sleep(priv, 0); > - return ret; > - } > - } > - > - if (priv->psmode != LBS802_11POWERMODECAM) { > - return 0; > - } > - > - priv->psmode = LBS802_11POWERMODEMAX_PSP; > - > - if (priv->connect_status == LBS_CONNECTED) { > - lbs_ps_sleep(priv, CMD_OPTION_WAITFORRSP); > - } > - > - lbs_deb_leave(LBS_DEB_WEXT); > - > - return 0; > -} > - > -static int lbs_get_power(struct net_device *dev, struct iw_request_info *info, > - struct iw_param *vwrq, char *extra) > -{ > - struct lbs_private *priv = dev->ml_priv; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - vwrq->value = 0; > - vwrq->flags = 0; > - vwrq->disabled = priv->psmode == LBS802_11POWERMODECAM > - || priv->connect_status == LBS_DISCONNECTED; > - > - lbs_deb_leave(LBS_DEB_WEXT); > - return 0; > -} > - > -static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev) > -{ > - enum { > - POOR = 30, > - FAIR = 60, > - GOOD = 80, > - VERY_GOOD = 90, > - EXCELLENT = 95, > - PERFECT = 100 > - }; > - struct lbs_private *priv = dev->ml_priv; > - u32 rssi_qual; > - u32 tx_qual; > - u32 quality = 0; > - int ret, stats_valid = 0; > - u8 rssi; > - u32 tx_retries; > - struct cmd_ds_802_11_get_log log; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - priv->wstats.status = priv->mode; > - > - /* If we're not associated, all quality values are meaningless */ > - if ((priv->connect_status != LBS_CONNECTED) && > - !lbs_mesh_connected(priv)) > - goto out; > - > - /* Quality by RSSI */ > - priv->wstats.qual.level = > - CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG], > - priv->NF[TYPE_BEACON][TYPE_NOAVG]); > - > - if (priv->NF[TYPE_BEACON][TYPE_NOAVG] == 0) { > - priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE; > - } else { > - priv->wstats.qual.noise = > - CAL_NF(priv->NF[TYPE_BEACON][TYPE_NOAVG]); > - } > - > - lbs_deb_wext("signal level %#x\n", priv->wstats.qual.level); > - lbs_deb_wext("noise %#x\n", priv->wstats.qual.noise); > - > - rssi = priv->wstats.qual.level - priv->wstats.qual.noise; > - if (rssi < 15) > - rssi_qual = rssi * POOR / 10; > - else if (rssi < 20) > - rssi_qual = (rssi - 15) * (FAIR - POOR) / 5 + POOR; > - else if (rssi < 30) > - rssi_qual = (rssi - 20) * (GOOD - FAIR) / 5 + FAIR; > - else if (rssi < 40) > - rssi_qual = (rssi - 30) * (VERY_GOOD - GOOD) / > - 10 + GOOD; > - else > - rssi_qual = (rssi - 40) * (PERFECT - VERY_GOOD) / > - 10 + VERY_GOOD; > - quality = rssi_qual; > - > - /* Quality by TX errors */ > - priv->wstats.discard.retries = dev->stats.tx_errors; > - > - memset(&log, 0, sizeof(log)); > - log.hdr.size = cpu_to_le16(sizeof(log)); > - ret = lbs_cmd_with_response(priv, CMD_802_11_GET_LOG, &log); > - if (ret) > - goto out; > - > - tx_retries = le32_to_cpu(log.retry); > - > - if (tx_retries > 75) > - tx_qual = (90 - tx_retries) * POOR / 15; > - else if (tx_retries > 70) > - tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR; > - else if (tx_retries > 65) > - tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR; > - else if (tx_retries > 50) > - tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) / > - 15 + GOOD; > - else > - tx_qual = (50 - tx_retries) * > - (PERFECT - VERY_GOOD) / 50 + VERY_GOOD; > - quality = min(quality, tx_qual); > - > - priv->wstats.discard.code = le32_to_cpu(log.wepundecryptable); > - priv->wstats.discard.retries = tx_retries; > - priv->wstats.discard.misc = le32_to_cpu(log.ackfailure); > - > - /* Calculate quality */ > - priv->wstats.qual.qual = min_t(u8, quality, 100); > - priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; > - stats_valid = 1; > - > - /* update stats asynchronously for future calls */ > - ret = lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, > - 0, 0, NULL); > - if (ret) > - lbs_pr_err("RSSI command failed\n"); > -out: > - if (!stats_valid) { > - priv->wstats.miss.beacon = 0; > - priv->wstats.discard.retries = 0; > - priv->wstats.qual.qual = 0; > - priv->wstats.qual.level = 0; > - priv->wstats.qual.noise = 0; > - priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED; > - priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID | > - IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; > - } > - > - lbs_deb_leave(LBS_DEB_WEXT); > - return &priv->wstats; > - > - > -} > - > -static int lbs_set_freq(struct net_device *dev, struct iw_request_info *info, > - struct iw_freq *fwrq, char *extra) > -{ > - int ret = -EINVAL; > - struct lbs_private *priv = dev->ml_priv; > - struct chan_freq_power *cfp; > - struct assoc_request * assoc_req; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - mutex_lock(&priv->lock); > - assoc_req = lbs_get_association_request(priv); > - if (!assoc_req) { > - ret = -ENOMEM; > - goto out; > - } > - > - /* If setting by frequency, convert to a channel */ > - if (fwrq->e == 1) { > - long f = fwrq->m / 100000; > - > - cfp = find_cfp_by_band_and_freq(priv, 0, f); > - if (!cfp) { > - lbs_deb_wext("invalid freq %ld\n", f); > - goto out; > - } > - > - fwrq->e = 0; > - fwrq->m = (int) cfp->channel; > - } > - > - /* Setting by channel number */ > - if (fwrq->m > 1000 || fwrq->e > 0) { > - goto out; > - } > - > - cfp = lbs_find_cfp_by_band_and_channel(priv, 0, fwrq->m); > - if (!cfp) { > - goto out; > - } > - > - assoc_req->channel = fwrq->m; > - ret = 0; > - > -out: > - if (ret == 0) { > - set_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags); > - lbs_postpone_association_work(priv); > - } else { > - lbs_cancel_association_work(priv); > - } > - mutex_unlock(&priv->lock); > - > - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); > - return ret; > -} > - > -#ifdef CONFIG_LIBERTAS_MESH > -static int lbs_mesh_set_freq(struct net_device *dev, > - struct iw_request_info *info, > - struct iw_freq *fwrq, char *extra) > -{ > - struct lbs_private *priv = dev->ml_priv; > - struct chan_freq_power *cfp; > - int ret = -EINVAL; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - /* If setting by frequency, convert to a channel */ > - if (fwrq->e == 1) { > - long f = fwrq->m / 100000; > - > - cfp = find_cfp_by_band_and_freq(priv, 0, f); > - if (!cfp) { > - lbs_deb_wext("invalid freq %ld\n", f); > - goto out; > - } > - > - fwrq->e = 0; > - fwrq->m = (int) cfp->channel; > - } > - > - /* Setting by channel number */ > - if (fwrq->m > 1000 || fwrq->e > 0) { > - goto out; > - } > - > - cfp = lbs_find_cfp_by_band_and_channel(priv, 0, fwrq->m); > - if (!cfp) { > - goto out; > - } > - > - if (fwrq->m != priv->channel) { > - lbs_deb_wext("mesh channel change forces eth disconnect\n"); > - if (priv->mode == IW_MODE_INFRA) > - lbs_cmd_80211_deauthenticate(priv, > - priv->curbssparams.bssid, > - WLAN_REASON_DEAUTH_LEAVING); > - else if (priv->mode == IW_MODE_ADHOC) > - lbs_adhoc_stop(priv); > - } > - lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, fwrq->m); > - lbs_update_channel(priv); > - ret = 0; > - > -out: > - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); > - return ret; > -} > -#endif > - > -static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info, > - struct iw_param *vwrq, char *extra) > -{ > - struct lbs_private *priv = dev->ml_priv; > - u8 new_rate = 0; > - int ret = -EINVAL; > - u8 rates[MAX_RATES + 1]; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - lbs_deb_wext("vwrq->value %d\n", vwrq->value); > - lbs_deb_wext("vwrq->fixed %d\n", vwrq->fixed); > - > - if (vwrq->fixed && vwrq->value == -1) > - goto out; > - > - /* Auto rate? */ > - priv->enablehwauto = !vwrq->fixed; > - > - if (vwrq->value == -1) > - priv->cur_rate = 0; > - else { > - if (vwrq->value % 100000) > - goto out; > - > - new_rate = vwrq->value / 500000; > - priv->cur_rate = new_rate; > - /* the rest is only needed for lbs_set_data_rate() */ > - memset(rates, 0, sizeof(rates)); > - copy_active_data_rates(priv, rates); > - if (!memchr(rates, new_rate, sizeof(rates))) { > - lbs_pr_alert("fixed data rate 0x%X out of range\n", > - new_rate); > - goto out; > - } > - if (priv->fwrelease < 0x09000000) { > - ret = lbs_set_power_adapt_cfg(priv, 0, > - POW_ADAPT_DEFAULT_P0, > - POW_ADAPT_DEFAULT_P1, > - POW_ADAPT_DEFAULT_P2); > - if (ret) > - goto out; > - } > - ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1, > - TPC_DEFAULT_P2, 1); > - if (ret) > - goto out; > - } > - > - /* Try the newer command first (Firmware Spec 5.1 and above) */ > - ret = lbs_cmd_802_11_rate_adapt_rateset(priv, CMD_ACT_SET); > - > - /* Fallback to older version */ > - if (ret) > - ret = lbs_set_data_rate(priv, new_rate); > - > -out: > - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); > - return ret; > -} > - > -static int lbs_get_rate(struct net_device *dev, struct iw_request_info *info, > - struct iw_param *vwrq, char *extra) > -{ > - struct lbs_private *priv = dev->ml_priv; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - if (priv->connect_status == LBS_CONNECTED) { > - vwrq->value = priv->cur_rate * 500000; > - > - if (priv->enablehwauto) > - vwrq->fixed = 0; > - else > - vwrq->fixed = 1; > - > - } else { > - vwrq->fixed = 0; > - vwrq->value = 0; > - } > - > - lbs_deb_leave(LBS_DEB_WEXT); > - return 0; > -} > - > -static int lbs_set_mode(struct net_device *dev, > - struct iw_request_info *info, u32 * uwrq, char *extra) > -{ > - int ret = 0; > - struct lbs_private *priv = dev->ml_priv; > - struct assoc_request * assoc_req; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - if ( (*uwrq != IW_MODE_ADHOC) > - && (*uwrq != IW_MODE_INFRA) > - && (*uwrq != IW_MODE_AUTO)) { > - lbs_deb_wext("Invalid mode: 0x%x\n", *uwrq); > - ret = -EINVAL; > - goto out; > - } > - > - mutex_lock(&priv->lock); > - assoc_req = lbs_get_association_request(priv); > - if (!assoc_req) { > - ret = -ENOMEM; > - lbs_cancel_association_work(priv); > - } else { > - assoc_req->mode = *uwrq; > - set_bit(ASSOC_FLAG_MODE, &assoc_req->flags); > - lbs_postpone_association_work(priv); > - lbs_deb_wext("Switching to mode: 0x%x\n", *uwrq); > - } > - mutex_unlock(&priv->lock); > - > -out: > - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); > - return ret; > -} > - > - > -/** > - * @brief Get Encryption key > - * > - * @param dev A pointer to net_device structure > - * @param info A pointer to iw_request_info structure > - * @param vwrq A pointer to iw_param structure > - * @param extra A pointer to extra data buf > - * @return 0 --success, otherwise fail > - */ > -static int lbs_get_encode(struct net_device *dev, > - struct iw_request_info *info, > - struct iw_point *dwrq, u8 * extra) > -{ > - struct lbs_private *priv = dev->ml_priv; > - int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - lbs_deb_wext("flags 0x%x, index %d, length %d, wep_tx_keyidx %d\n", > - dwrq->flags, index, dwrq->length, priv->wep_tx_keyidx); > - > - dwrq->flags = 0; > - > - /* Authentication method */ > - switch (priv->secinfo.auth_mode) { > - case IW_AUTH_ALG_OPEN_SYSTEM: > - dwrq->flags = IW_ENCODE_OPEN; > - break; > - > - case IW_AUTH_ALG_SHARED_KEY: > - case IW_AUTH_ALG_LEAP: > - dwrq->flags = IW_ENCODE_RESTRICTED; > - break; > - default: > - dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN; > - break; > - } > - > - memset(extra, 0, 16); > - > - mutex_lock(&priv->lock); > - > - /* Default to returning current transmit key */ > - if (index < 0) > - index = priv->wep_tx_keyidx; > - > - if ((priv->wep_keys[index].len) && priv->secinfo.wep_enabled) { > - memcpy(extra, priv->wep_keys[index].key, > - priv->wep_keys[index].len); > - dwrq->length = priv->wep_keys[index].len; > - > - dwrq->flags |= (index + 1); > - /* Return WEP enabled */ > - dwrq->flags &= ~IW_ENCODE_DISABLED; > - } else if ((priv->secinfo.WPAenabled) > - || (priv->secinfo.WPA2enabled)) { > - /* return WPA enabled */ > - dwrq->flags &= ~IW_ENCODE_DISABLED; > - dwrq->flags |= IW_ENCODE_NOKEY; > - } else { > - dwrq->flags |= IW_ENCODE_DISABLED; > - } > - > - mutex_unlock(&priv->lock); > - > - lbs_deb_wext("key: %02x:%02x:%02x:%02x:%02x:%02x, keylen %d\n", > - extra[0], extra[1], extra[2], > - extra[3], extra[4], extra[5], dwrq->length); > - > - lbs_deb_wext("return flags 0x%x\n", dwrq->flags); > - > - lbs_deb_leave(LBS_DEB_WEXT); > - return 0; > -} > - > -/** > - * @brief Set Encryption key (internal) > - * > - * @param priv A pointer to private card structure > - * @param key_material A pointer to key material > - * @param key_length length of key material > - * @param index key index to set > - * @param set_tx_key Force set TX key (1 = yes, 0 = no) > - * @return 0 --success, otherwise fail > - */ > -static int lbs_set_wep_key(struct assoc_request *assoc_req, > - const char *key_material, > - u16 key_length, > - u16 index, > - int set_tx_key) > -{ > - int ret = 0; > - struct enc_key *pkey; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - /* Paranoid validation of key index */ > - if (index > 3) { > - ret = -EINVAL; > - goto out; > - } > - > - /* validate max key length */ > - if (key_length > KEY_LEN_WEP_104) { > - ret = -EINVAL; > - goto out; > - } > - > - pkey = &assoc_req->wep_keys[index]; > - > - if (key_length > 0) { > - memset(pkey, 0, sizeof(struct enc_key)); > - pkey->type = KEY_TYPE_ID_WEP; > - > - /* Standardize the key length */ > - pkey->len = (key_length > KEY_LEN_WEP_40) ? > - KEY_LEN_WEP_104 : KEY_LEN_WEP_40; > - memcpy(pkey->key, key_material, key_length); > - } > - > - if (set_tx_key) { > - /* Ensure the chosen key is valid */ > - if (!pkey->len) { > - lbs_deb_wext("key not set, so cannot enable it\n"); > - ret = -EINVAL; > - goto out; > - } > - assoc_req->wep_tx_keyidx = index; > - } > - > - assoc_req->secinfo.wep_enabled = 1; > - > -out: > - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); > - return ret; > -} > - > -static int validate_key_index(u16 def_index, u16 raw_index, > - u16 *out_index, u16 *is_default) > -{ > - if (!out_index || !is_default) > - return -EINVAL; > - > - /* Verify index if present, otherwise use default TX key index */ > - if (raw_index > 0) { > - if (raw_index > 4) > - return -EINVAL; > - *out_index = raw_index - 1; > - } else { > - *out_index = def_index; > - *is_default = 1; > - } > - return 0; > -} > - > -static void disable_wep(struct assoc_request *assoc_req) > -{ > - int i; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - /* Set Open System auth mode */ > - assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; > - > - /* Clear WEP keys and mark WEP as disabled */ > - assoc_req->secinfo.wep_enabled = 0; > - for (i = 0; i < 4; i++) > - assoc_req->wep_keys[i].len = 0; > - > - set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); > - set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags); > - > - lbs_deb_leave(LBS_DEB_WEXT); > -} > - > -static void disable_wpa(struct assoc_request *assoc_req) > -{ > - lbs_deb_enter(LBS_DEB_WEXT); > - > - memset(&assoc_req->wpa_mcast_key, 0, sizeof (struct enc_key)); > - assoc_req->wpa_mcast_key.flags = KEY_INFO_WPA_MCAST; > - set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags); > - > - memset(&assoc_req->wpa_unicast_key, 0, sizeof (struct enc_key)); > - assoc_req->wpa_unicast_key.flags = KEY_INFO_WPA_UNICAST; > - set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags); > - > - assoc_req->secinfo.WPAenabled = 0; > - assoc_req->secinfo.WPA2enabled = 0; > - set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); > - > - lbs_deb_leave(LBS_DEB_WEXT); > -} > - > -/** > - * @brief Set Encryption key > - * > - * @param dev A pointer to net_device structure > - * @param info A pointer to iw_request_info structure > - * @param vwrq A pointer to iw_param structure > - * @param extra A pointer to extra data buf > - * @return 0 --success, otherwise fail > - */ > -static int lbs_set_encode(struct net_device *dev, > - struct iw_request_info *info, > - struct iw_point *dwrq, char *extra) > -{ > - int ret = 0; > - struct lbs_private *priv = dev->ml_priv; > - struct assoc_request * assoc_req; > - u16 is_default = 0, index = 0, set_tx_key = 0; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - mutex_lock(&priv->lock); > - assoc_req = lbs_get_association_request(priv); > - if (!assoc_req) { > - ret = -ENOMEM; > - goto out; > - } > - > - if (dwrq->flags & IW_ENCODE_DISABLED) { > - disable_wep (assoc_req); > - disable_wpa (assoc_req); > - goto out; > - } > - > - ret = validate_key_index(assoc_req->wep_tx_keyidx, > - (dwrq->flags & IW_ENCODE_INDEX), > - &index, &is_default); > - if (ret) { > - ret = -EINVAL; > - goto out; > - } > - > - /* If WEP isn't enabled, or if there is no key data but a valid > - * index, set the TX key. > - */ > - if (!assoc_req->secinfo.wep_enabled || (dwrq->length == 0 && !is_default)) > - set_tx_key = 1; > - > - ret = lbs_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key); > - if (ret) > - goto out; > - > - if (dwrq->length) > - set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags); > - if (set_tx_key) > - set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags); > - > - if (dwrq->flags & IW_ENCODE_RESTRICTED) { > - assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY; > - } else if (dwrq->flags & IW_ENCODE_OPEN) { > - assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; > - } > - > -out: > - if (ret == 0) { > - set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); > - lbs_postpone_association_work(priv); > - } else { > - lbs_cancel_association_work(priv); > - } > - mutex_unlock(&priv->lock); > - > - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); > - return ret; > -} > - > -/** > - * @brief Get Extended Encryption key (WPA/802.1x and WEP) > - * > - * @param dev A pointer to net_device structure > - * @param info A pointer to iw_request_info structure > - * @param vwrq A pointer to iw_param structure > - * @param extra A pointer to extra data buf > - * @return 0 on success, otherwise failure > - */ > -static int lbs_get_encodeext(struct net_device *dev, > - struct iw_request_info *info, > - struct iw_point *dwrq, > - char *extra) > -{ > - int ret = -EINVAL; > - struct lbs_private *priv = dev->ml_priv; > - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; > - int index, max_key_len; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - max_key_len = dwrq->length - sizeof(*ext); > - if (max_key_len < 0) > - goto out; > - > - index = dwrq->flags & IW_ENCODE_INDEX; > - if (index) { > - if (index < 1 || index > 4) > - goto out; > - index--; > - } else { > - index = priv->wep_tx_keyidx; > - } > - > - if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) && > - ext->alg != IW_ENCODE_ALG_WEP) { > - if (index != 0 || priv->mode != IW_MODE_INFRA) > - goto out; > - } > - > - dwrq->flags = index + 1; > - memset(ext, 0, sizeof(*ext)); > - > - if ( !priv->secinfo.wep_enabled > - && !priv->secinfo.WPAenabled > - && !priv->secinfo.WPA2enabled) { > - ext->alg = IW_ENCODE_ALG_NONE; > - ext->key_len = 0; > - dwrq->flags |= IW_ENCODE_DISABLED; > - } else { > - u8 *key = NULL; > - > - if ( priv->secinfo.wep_enabled > - && !priv->secinfo.WPAenabled > - && !priv->secinfo.WPA2enabled) { > - /* WEP */ > - ext->alg = IW_ENCODE_ALG_WEP; > - ext->key_len = priv->wep_keys[index].len; > - key = &priv->wep_keys[index].key[0]; > - } else if ( !priv->secinfo.wep_enabled > - && (priv->secinfo.WPAenabled || > - priv->secinfo.WPA2enabled)) { > - /* WPA */ > - struct enc_key * pkey = NULL; > - > - if ( priv->wpa_mcast_key.len > - && (priv->wpa_mcast_key.flags & KEY_INFO_WPA_ENABLED)) > - pkey = &priv->wpa_mcast_key; > - else if ( priv->wpa_unicast_key.len > - && (priv->wpa_unicast_key.flags & KEY_INFO_WPA_ENABLED)) > - pkey = &priv->wpa_unicast_key; > - > - if (pkey) { > - if (pkey->type == KEY_TYPE_ID_AES) { > - ext->alg = IW_ENCODE_ALG_CCMP; > - } else { > - ext->alg = IW_ENCODE_ALG_TKIP; > - } > - ext->key_len = pkey->len; > - key = &pkey->key[0]; > - } else { > - ext->alg = IW_ENCODE_ALG_TKIP; > - ext->key_len = 0; > - } > - } else { > - goto out; > - } > - > - if (ext->key_len > max_key_len) { > - ret = -E2BIG; > - goto out; > - } > - > - if (ext->key_len) > - memcpy(ext->key, key, ext->key_len); > - else > - dwrq->flags |= IW_ENCODE_NOKEY; > - dwrq->flags |= IW_ENCODE_ENABLED; > - } > - ret = 0; > - > -out: > - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); > - return ret; > -} > - > -/** > - * @brief Set Encryption key Extended (WPA/802.1x and WEP) > - * > - * @param dev A pointer to net_device structure > - * @param info A pointer to iw_request_info structure > - * @param vwrq A pointer to iw_param structure > - * @param extra A pointer to extra data buf > - * @return 0 --success, otherwise fail > - */ > -static int lbs_set_encodeext(struct net_device *dev, > - struct iw_request_info *info, > - struct iw_point *dwrq, > - char *extra) > -{ > - int ret = 0; > - struct lbs_private *priv = dev->ml_priv; > - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; > - int alg = ext->alg; > - struct assoc_request * assoc_req; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - mutex_lock(&priv->lock); > - assoc_req = lbs_get_association_request(priv); > - if (!assoc_req) { > - ret = -ENOMEM; > - goto out; > - } > - > - if ((alg == IW_ENCODE_ALG_NONE) || (dwrq->flags & IW_ENCODE_DISABLED)) { > - disable_wep (assoc_req); > - disable_wpa (assoc_req); > - } else if (alg == IW_ENCODE_ALG_WEP) { > - u16 is_default = 0, index, set_tx_key = 0; > - > - ret = validate_key_index(assoc_req->wep_tx_keyidx, > - (dwrq->flags & IW_ENCODE_INDEX), > - &index, &is_default); > - if (ret) > - goto out; > - > - /* If WEP isn't enabled, or if there is no key data but a valid > - * index, or if the set-TX-key flag was passed, set the TX key. > - */ > - if ( !assoc_req->secinfo.wep_enabled > - || (dwrq->length == 0 && !is_default) > - || (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) > - set_tx_key = 1; > - > - /* Copy key to driver */ > - ret = lbs_set_wep_key(assoc_req, ext->key, ext->key_len, index, > - set_tx_key); > - if (ret) > - goto out; > - > - if (dwrq->flags & IW_ENCODE_RESTRICTED) { > - assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY; > - } else if (dwrq->flags & IW_ENCODE_OPEN) { > - assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; > - } > - > - /* Mark the various WEP bits as modified */ > - set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); > - if (dwrq->length) > - set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags); > - if (set_tx_key) > - set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags); > - } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) { > - struct enc_key * pkey; > - > - /* validate key length */ > - if (((alg == IW_ENCODE_ALG_TKIP) > - && (ext->key_len != KEY_LEN_WPA_TKIP)) > - || ((alg == IW_ENCODE_ALG_CCMP) > - && (ext->key_len != KEY_LEN_WPA_AES))) { > - lbs_deb_wext("invalid size %d for key of alg " > - "type %d\n", > - ext->key_len, > - alg); > - ret = -EINVAL; > - goto out; > - } > - > - if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { > - pkey = &assoc_req->wpa_mcast_key; > - set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags); > - } else { > - pkey = &assoc_req->wpa_unicast_key; > - set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags); > - } > - > - memset(pkey, 0, sizeof (struct enc_key)); > - memcpy(pkey->key, ext->key, ext->key_len); > - pkey->len = ext->key_len; > - if (pkey->len) > - pkey->flags |= KEY_INFO_WPA_ENABLED; > - > - /* Do this after zeroing key structure */ > - if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { > - pkey->flags |= KEY_INFO_WPA_MCAST; > - } else { > - pkey->flags |= KEY_INFO_WPA_UNICAST; > - } > - > - if (alg == IW_ENCODE_ALG_TKIP) { > - pkey->type = KEY_TYPE_ID_TKIP; > - } else if (alg == IW_ENCODE_ALG_CCMP) { > - pkey->type = KEY_TYPE_ID_AES; > - } > - > - /* If WPA isn't enabled yet, do that now */ > - if ( assoc_req->secinfo.WPAenabled == 0 > - && assoc_req->secinfo.WPA2enabled == 0) { > - assoc_req->secinfo.WPAenabled = 1; > - assoc_req->secinfo.WPA2enabled = 1; > - set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); > - } > - > - /* Only disable wep if necessary: can't waste time here. */ > - if (priv->mac_control & CMD_ACT_MAC_WEP_ENABLE) > - disable_wep(assoc_req); > - } > - > -out: > - if (ret == 0) { > - /* 802.1x and WPA rekeying must happen as quickly as possible, > - * especially during the 4-way handshake; thus if in > - * infrastructure mode, and either (a) 802.1x is enabled or > - * (b) WPA is being used, set the key right away. > - */ > - if (assoc_req->mode == IW_MODE_INFRA && > - ((assoc_req->secinfo.key_mgmt & IW_AUTH_KEY_MGMT_802_1X) || > - (assoc_req->secinfo.key_mgmt & IW_AUTH_KEY_MGMT_PSK) || > - assoc_req->secinfo.WPAenabled || > - assoc_req->secinfo.WPA2enabled)) { > - lbs_do_association_work(priv); > - } else > - lbs_postpone_association_work(priv); > - } else { > - lbs_cancel_association_work(priv); > - } > - mutex_unlock(&priv->lock); > - > - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); > - return ret; > -} > - > - > -static int lbs_set_genie(struct net_device *dev, > - struct iw_request_info *info, > - struct iw_point *dwrq, > - char *extra) > -{ > - struct lbs_private *priv = dev->ml_priv; > - int ret = 0; > - struct assoc_request * assoc_req; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - mutex_lock(&priv->lock); > - assoc_req = lbs_get_association_request(priv); > - if (!assoc_req) { > - ret = -ENOMEM; > - goto out; > - } > - > - if (dwrq->length > MAX_WPA_IE_LEN || > - (dwrq->length && extra == NULL)) { > - ret = -EINVAL; > - goto out; > - } > - > - if (dwrq->length) { > - memcpy(&assoc_req->wpa_ie[0], extra, dwrq->length); > - assoc_req->wpa_ie_len = dwrq->length; > - } else { > - memset(&assoc_req->wpa_ie[0], 0, sizeof(priv->wpa_ie)); > - assoc_req->wpa_ie_len = 0; > - } > - > -out: > - if (ret == 0) { > - set_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags); > - lbs_postpone_association_work(priv); > - } else { > - lbs_cancel_association_work(priv); > - } > - mutex_unlock(&priv->lock); > - > - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); > - return ret; > -} > - > -static int lbs_get_genie(struct net_device *dev, > - struct iw_request_info *info, > - struct iw_point *dwrq, > - char *extra) > -{ > - int ret = 0; > - struct lbs_private *priv = dev->ml_priv; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - if (priv->wpa_ie_len == 0) { > - dwrq->length = 0; > - goto out; > - } > - > - if (dwrq->length < priv->wpa_ie_len) { > - ret = -E2BIG; > - goto out; > - } > - > - dwrq->length = priv->wpa_ie_len; > - memcpy(extra, &priv->wpa_ie[0], priv->wpa_ie_len); > - > -out: > - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); > - return ret; > -} > - > - > -static int lbs_set_auth(struct net_device *dev, > - struct iw_request_info *info, > - struct iw_param *dwrq, > - char *extra) > -{ > - struct lbs_private *priv = dev->ml_priv; > - struct assoc_request * assoc_req; > - int ret = 0; > - int updated = 0; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - mutex_lock(&priv->lock); > - assoc_req = lbs_get_association_request(priv); > - if (!assoc_req) { > - ret = -ENOMEM; > - goto out; > - } > - > - switch (dwrq->flags & IW_AUTH_INDEX) { > - case IW_AUTH_PRIVACY_INVOKED: > - case IW_AUTH_RX_UNENCRYPTED_EAPOL: > - case IW_AUTH_TKIP_COUNTERMEASURES: > - case IW_AUTH_CIPHER_PAIRWISE: > - case IW_AUTH_CIPHER_GROUP: > - case IW_AUTH_DROP_UNENCRYPTED: > - /* > - * libertas does not use these parameters > - */ > - break; > - > - case IW_AUTH_KEY_MGMT: > - assoc_req->secinfo.key_mgmt = dwrq->value; > - updated = 1; > - break; > - > - case IW_AUTH_WPA_VERSION: > - if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) { > - assoc_req->secinfo.WPAenabled = 0; > - assoc_req->secinfo.WPA2enabled = 0; > - disable_wpa (assoc_req); > - } > - if (dwrq->value & IW_AUTH_WPA_VERSION_WPA) { > - assoc_req->secinfo.WPAenabled = 1; > - assoc_req->secinfo.wep_enabled = 0; > - assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; > - } > - if (dwrq->value & IW_AUTH_WPA_VERSION_WPA2) { > - assoc_req->secinfo.WPA2enabled = 1; > - assoc_req->secinfo.wep_enabled = 0; > - assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; > - } > - updated = 1; > - break; > - > - case IW_AUTH_80211_AUTH_ALG: > - if (dwrq->value & IW_AUTH_ALG_SHARED_KEY) { > - assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY; > - } else if (dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) { > - assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; > - } else if (dwrq->value & IW_AUTH_ALG_LEAP) { > - assoc_req->secinfo.auth_mode = IW_AUTH_ALG_LEAP; > - } else { > - ret = -EINVAL; > - } > - updated = 1; > - break; > - > - case IW_AUTH_WPA_ENABLED: > - if (dwrq->value) { > - if (!assoc_req->secinfo.WPAenabled && > - !assoc_req->secinfo.WPA2enabled) { > - assoc_req->secinfo.WPAenabled = 1; > - assoc_req->secinfo.WPA2enabled = 1; > - assoc_req->secinfo.wep_enabled = 0; > - assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; > - } > - } else { > - assoc_req->secinfo.WPAenabled = 0; > - assoc_req->secinfo.WPA2enabled = 0; > - disable_wpa (assoc_req); > - } > - updated = 1; > - break; > - > - default: > - ret = -EOPNOTSUPP; > - break; > - } > - > -out: > - if (ret == 0) { > - if (updated) > - set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); > - lbs_postpone_association_work(priv); > - } else if (ret != -EOPNOTSUPP) { > - lbs_cancel_association_work(priv); > - } > - mutex_unlock(&priv->lock); > - > - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); > - return ret; > -} > - > -static int lbs_get_auth(struct net_device *dev, > - struct iw_request_info *info, > - struct iw_param *dwrq, > - char *extra) > -{ > - int ret = 0; > - struct lbs_private *priv = dev->ml_priv; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - switch (dwrq->flags & IW_AUTH_INDEX) { > - case IW_AUTH_KEY_MGMT: > - dwrq->value = priv->secinfo.key_mgmt; > - break; > - > - case IW_AUTH_WPA_VERSION: > - dwrq->value = 0; > - if (priv->secinfo.WPAenabled) > - dwrq->value |= IW_AUTH_WPA_VERSION_WPA; > - if (priv->secinfo.WPA2enabled) > - dwrq->value |= IW_AUTH_WPA_VERSION_WPA2; > - if (!dwrq->value) > - dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED; > - break; > - > - case IW_AUTH_80211_AUTH_ALG: > - dwrq->value = priv->secinfo.auth_mode; > - break; > - > - case IW_AUTH_WPA_ENABLED: > - if (priv->secinfo.WPAenabled && priv->secinfo.WPA2enabled) > - dwrq->value = 1; > - break; > - > - default: > - ret = -EOPNOTSUPP; > - } > - > - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); > - return ret; > -} > - > - > -static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info, > - struct iw_param *vwrq, char *extra) > -{ > - int ret = 0; > - struct lbs_private *priv = dev->ml_priv; > - s16 dbm = (s16) vwrq->value; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - if (vwrq->disabled) { > - lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 0); > - goto out; > - } > - > - if (vwrq->fixed == 0) { > - /* User requests automatic tx power control, however there are > - * many auto tx settings. For now use firmware defaults until > - * we come up with a good way to expose these to the user. */ > - if (priv->fwrelease < 0x09000000) { > - ret = lbs_set_power_adapt_cfg(priv, 1, > - POW_ADAPT_DEFAULT_P0, > - POW_ADAPT_DEFAULT_P1, > - POW_ADAPT_DEFAULT_P2); > - if (ret) > - goto out; > - } > - ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1, > - TPC_DEFAULT_P2, 1); > - if (ret) > - goto out; > - dbm = priv->txpower_max; > - } else { > - /* Userspace check in iwrange if it should use dBm or mW, > - * therefore this should never happen... Jean II */ > - if ((vwrq->flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) { > - ret = -EOPNOTSUPP; > - goto out; > - } > - > - /* Validate requested power level against firmware allowed > - * levels */ > - if (priv->txpower_min && (dbm < priv->txpower_min)) { > - ret = -EINVAL; > - goto out; > - } > - > - if (priv->txpower_max && (dbm > priv->txpower_max)) { > - ret = -EINVAL; > - goto out; > - } > - if (priv->fwrelease < 0x09000000) { > - ret = lbs_set_power_adapt_cfg(priv, 0, > - POW_ADAPT_DEFAULT_P0, > - POW_ADAPT_DEFAULT_P1, > - POW_ADAPT_DEFAULT_P2); > - if (ret) > - goto out; > - } > - ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1, > - TPC_DEFAULT_P2, 1); > - if (ret) > - goto out; > - } > - > - /* If the radio was off, turn it on */ > - if (!priv->radio_on) { > - ret = lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 1); > - if (ret) > - goto out; > - } > - > - lbs_deb_wext("txpower set %d dBm\n", dbm); > - > - ret = lbs_set_tx_power(priv, dbm); > - > -out: > - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); > - return ret; > -} > - > -static int lbs_get_essid(struct net_device *dev, struct iw_request_info *info, > - struct iw_point *dwrq, char *extra) > -{ > - struct lbs_private *priv = dev->ml_priv; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - /* > - * Note : if dwrq->flags != 0, we should get the relevant SSID from > - * the SSID list... > - */ > - > - /* > - * Get the current SSID > - */ > - if (priv->connect_status == LBS_CONNECTED) { > - memcpy(extra, priv->curbssparams.ssid, > - priv->curbssparams.ssid_len); > - extra[priv->curbssparams.ssid_len] = '\0'; > - } else { > - memset(extra, 0, 32); > - extra[priv->curbssparams.ssid_len] = '\0'; > - } > - /* > - * If none, we may want to get the one that was set > - */ > - > - dwrq->length = priv->curbssparams.ssid_len; > - > - dwrq->flags = 1; /* active */ > - > - lbs_deb_leave(LBS_DEB_WEXT); > - return 0; > -} > - > -static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info, > - struct iw_point *dwrq, char *extra) > -{ > - struct lbs_private *priv = dev->ml_priv; > - int ret = 0; > - u8 ssid[IEEE80211_MAX_SSID_LEN]; > - u8 ssid_len = 0; > - struct assoc_request * assoc_req; > - int in_ssid_len = dwrq->length; > - DECLARE_SSID_BUF(ssid_buf); > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - if (!priv->radio_on) { > - ret = -EINVAL; > - goto out; > - } > - > - /* Check the size of the string */ > - if (in_ssid_len > IEEE80211_MAX_SSID_LEN) { > - ret = -E2BIG; > - goto out; > - } > - > - memset(&ssid, 0, sizeof(ssid)); > - > - if (!dwrq->flags || !in_ssid_len) { > - /* "any" SSID requested; leave SSID blank */ > - } else { > - /* Specific SSID requested */ > - memcpy(&ssid, extra, in_ssid_len); > - ssid_len = in_ssid_len; > - } > - > - if (!ssid_len) { > - lbs_deb_wext("requested any SSID\n"); > - } else { > - lbs_deb_wext("requested SSID '%s'\n", > - print_ssid(ssid_buf, ssid, ssid_len)); > - } > - > -out: > - mutex_lock(&priv->lock); > - if (ret == 0) { > - /* Get or create the current association request */ > - assoc_req = lbs_get_association_request(priv); > - if (!assoc_req) { > - ret = -ENOMEM; > - } else { > - /* Copy the SSID to the association request */ > - memcpy(&assoc_req->ssid, &ssid, IEEE80211_MAX_SSID_LEN); > - assoc_req->ssid_len = ssid_len; > - set_bit(ASSOC_FLAG_SSID, &assoc_req->flags); > - lbs_postpone_association_work(priv); > - } > - } > - > - /* Cancel the association request if there was an error */ > - if (ret != 0) { > - lbs_cancel_association_work(priv); > - } > - > - mutex_unlock(&priv->lock); > - > - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); > - return ret; > -} > - > -#ifdef CONFIG_LIBERTAS_MESH > -static int lbs_mesh_get_essid(struct net_device *dev, > - struct iw_request_info *info, > - struct iw_point *dwrq, char *extra) > -{ > - struct lbs_private *priv = dev->ml_priv; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - memcpy(extra, priv->mesh_ssid, priv->mesh_ssid_len); > - > - dwrq->length = priv->mesh_ssid_len; > - > - dwrq->flags = 1; /* active */ > - > - lbs_deb_leave(LBS_DEB_WEXT); > - return 0; > -} > - > -static int lbs_mesh_set_essid(struct net_device *dev, > - struct iw_request_info *info, > - struct iw_point *dwrq, char *extra) > -{ > - struct lbs_private *priv = dev->ml_priv; > - int ret = 0; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - if (!priv->radio_on) { > - ret = -EINVAL; > - goto out; > - } > - > - /* Check the size of the string */ > - if (dwrq->length > IEEE80211_MAX_SSID_LEN) { > - ret = -E2BIG; > - goto out; > - } > - > - if (!dwrq->flags || !dwrq->length) { > - ret = -EINVAL; > - goto out; > - } else { > - /* Specific SSID requested */ > - memcpy(priv->mesh_ssid, extra, dwrq->length); > - priv->mesh_ssid_len = dwrq->length; > - } > - > - lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, > - priv->channel); > - out: > - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); > - return ret; > -} > -#endif > - > -/** > - * @brief Connect to the AP or Ad-hoc Network with specific bssid > - * > - * @param dev A pointer to net_device structure > - * @param info A pointer to iw_request_info structure > - * @param awrq A pointer to iw_param structure > - * @param extra A pointer to extra data buf > - * @return 0 --success, otherwise fail > - */ > -static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info, > - struct sockaddr *awrq, char *extra) > -{ > - struct lbs_private *priv = dev->ml_priv; > - struct assoc_request * assoc_req; > - int ret = 0; > - > - lbs_deb_enter(LBS_DEB_WEXT); > - > - if (!priv->radio_on) > - return -EINVAL; > - > - if (awrq->sa_family != ARPHRD_ETHER) > - return -EINVAL; > - > - lbs_deb_wext("ASSOC: WAP: sa_data %pM\n", awrq->sa_data); > - > - mutex_lock(&priv->lock); > - > - /* Get or create the current association request */ > - assoc_req = lbs_get_association_request(priv); > - if (!assoc_req) { > - lbs_cancel_association_work(priv); > - ret = -ENOMEM; > - } else { > - /* Copy the BSSID to the association request */ > - memcpy(&assoc_req->bssid, awrq->sa_data, ETH_ALEN); > - set_bit(ASSOC_FLAG_BSSID, &assoc_req->flags); > - lbs_postpone_association_work(priv); > - } > - > - mutex_unlock(&priv->lock); > - > - return ret; > -} > - > -/* > - * iwconfig settable callbacks > - */ > -static const iw_handler lbs_handler[] = { > - (iw_handler) NULL, /* SIOCSIWCOMMIT */ > - (iw_handler) lbs_get_name, /* SIOCGIWNAME */ > - (iw_handler) NULL, /* SIOCSIWNWID */ > - (iw_handler) NULL, /* SIOCGIWNWID */ > - (iw_handler) lbs_set_freq, /* SIOCSIWFREQ */ > - (iw_handler) lbs_get_freq, /* SIOCGIWFREQ */ > - (iw_handler) lbs_set_mode, /* SIOCSIWMODE */ > - (iw_handler) lbs_get_mode, /* SIOCGIWMODE */ > - (iw_handler) NULL, /* SIOCSIWSENS */ > - (iw_handler) NULL, /* SIOCGIWSENS */ > - (iw_handler) NULL, /* SIOCSIWRANGE */ > - (iw_handler) lbs_get_range, /* SIOCGIWRANGE */ > - (iw_handler) NULL, /* SIOCSIWPRIV */ > - (iw_handler) NULL, /* SIOCGIWPRIV */ > - (iw_handler) NULL, /* SIOCSIWSTATS */ > - (iw_handler) NULL, /* SIOCGIWSTATS */ > - iw_handler_set_spy, /* SIOCSIWSPY */ > - iw_handler_get_spy, /* SIOCGIWSPY */ > - iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ > - iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ > - (iw_handler) lbs_set_wap, /* SIOCSIWAP */ > - (iw_handler) lbs_get_wap, /* SIOCGIWAP */ > - (iw_handler) NULL, /* SIOCSIWMLME */ > - (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */ > - (iw_handler) lbs_set_scan, /* SIOCSIWSCAN */ > - (iw_handler) lbs_get_scan, /* SIOCGIWSCAN */ > - (iw_handler) lbs_set_essid, /* SIOCSIWESSID */ > - (iw_handler) lbs_get_essid, /* SIOCGIWESSID */ > - (iw_handler) lbs_set_nick, /* SIOCSIWNICKN */ > - (iw_handler) lbs_get_nick, /* SIOCGIWNICKN */ > - (iw_handler) NULL, /* -- hole -- */ > - (iw_handler) NULL, /* -- hole -- */ > - (iw_handler) lbs_set_rate, /* SIOCSIWRATE */ > - (iw_handler) lbs_get_rate, /* SIOCGIWRATE */ > - (iw_handler) lbs_set_rts, /* SIOCSIWRTS */ > - (iw_handler) lbs_get_rts, /* SIOCGIWRTS */ > - (iw_handler) lbs_set_frag, /* SIOCSIWFRAG */ > - (iw_handler) lbs_get_frag, /* SIOCGIWFRAG */ > - (iw_handler) lbs_set_txpow, /* SIOCSIWTXPOW */ > - (iw_handler) lbs_get_txpow, /* SIOCGIWTXPOW */ > - (iw_handler) lbs_set_retry, /* SIOCSIWRETRY */ > - (iw_handler) lbs_get_retry, /* SIOCGIWRETRY */ > - (iw_handler) lbs_set_encode, /* SIOCSIWENCODE */ > - (iw_handler) lbs_get_encode, /* SIOCGIWENCODE */ > - (iw_handler) lbs_set_power, /* SIOCSIWPOWER */ > - (iw_handler) lbs_get_power, /* SIOCGIWPOWER */ > - (iw_handler) NULL, /* -- hole -- */ > - (iw_handler) NULL, /* -- hole -- */ > - (iw_handler) lbs_set_genie, /* SIOCSIWGENIE */ > - (iw_handler) lbs_get_genie, /* SIOCGIWGENIE */ > - (iw_handler) lbs_set_auth, /* SIOCSIWAUTH */ > - (iw_handler) lbs_get_auth, /* SIOCGIWAUTH */ > - (iw_handler) lbs_set_encodeext,/* SIOCSIWENCODEEXT */ > - (iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */ > - (iw_handler) NULL, /* SIOCSIWPMKSA */ > -}; > -struct iw_handler_def lbs_handler_def = { > - .num_standard = ARRAY_SIZE(lbs_handler), > - .standard = (iw_handler *) lbs_handler, > - .get_wireless_stats = lbs_get_wireless_stats, > -}; > - > -#ifdef CONFIG_LIBERTAS_MESH > -static const iw_handler mesh_wlan_handler[] = { > - (iw_handler) NULL, /* SIOCSIWCOMMIT */ > - (iw_handler) lbs_get_name, /* SIOCGIWNAME */ > - (iw_handler) NULL, /* SIOCSIWNWID */ > - (iw_handler) NULL, /* SIOCGIWNWID */ > - (iw_handler) lbs_mesh_set_freq, /* SIOCSIWFREQ */ > - (iw_handler) lbs_get_freq, /* SIOCGIWFREQ */ > - (iw_handler) NULL, /* SIOCSIWMODE */ > - (iw_handler) mesh_wlan_get_mode, /* SIOCGIWMODE */ > - (iw_handler) NULL, /* SIOCSIWSENS */ > - (iw_handler) NULL, /* SIOCGIWSENS */ > - (iw_handler) NULL, /* SIOCSIWRANGE */ > - (iw_handler) lbs_get_range, /* SIOCGIWRANGE */ > - (iw_handler) NULL, /* SIOCSIWPRIV */ > - (iw_handler) NULL, /* SIOCGIWPRIV */ > - (iw_handler) NULL, /* SIOCSIWSTATS */ > - (iw_handler) NULL, /* SIOCGIWSTATS */ > - iw_handler_set_spy, /* SIOCSIWSPY */ > - iw_handler_get_spy, /* SIOCGIWSPY */ > - iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ > - iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ > - (iw_handler) NULL, /* SIOCSIWAP */ > - (iw_handler) NULL, /* SIOCGIWAP */ > - (iw_handler) NULL, /* SIOCSIWMLME */ > - (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */ > - (iw_handler) lbs_set_scan, /* SIOCSIWSCAN */ > - (iw_handler) lbs_get_scan, /* SIOCGIWSCAN */ > - (iw_handler) lbs_mesh_set_essid,/* SIOCSIWESSID */ > - (iw_handler) lbs_mesh_get_essid,/* SIOCGIWESSID */ > - (iw_handler) NULL, /* SIOCSIWNICKN */ > - (iw_handler) mesh_get_nick, /* SIOCGIWNICKN */ > - (iw_handler) NULL, /* -- hole -- */ > - (iw_handler) NULL, /* -- hole -- */ > - (iw_handler) lbs_set_rate, /* SIOCSIWRATE */ > - (iw_handler) lbs_get_rate, /* SIOCGIWRATE */ > - (iw_handler) lbs_set_rts, /* SIOCSIWRTS */ > - (iw_handler) lbs_get_rts, /* SIOCGIWRTS */ > - (iw_handler) lbs_set_frag, /* SIOCSIWFRAG */ > - (iw_handler) lbs_get_frag, /* SIOCGIWFRAG */ > - (iw_handler) lbs_set_txpow, /* SIOCSIWTXPOW */ > - (iw_handler) lbs_get_txpow, /* SIOCGIWTXPOW */ > - (iw_handler) lbs_set_retry, /* SIOCSIWRETRY */ > - (iw_handler) lbs_get_retry, /* SIOCGIWRETRY */ > - (iw_handler) lbs_set_encode, /* SIOCSIWENCODE */ > - (iw_handler) lbs_get_encode, /* SIOCGIWENCODE */ > - (iw_handler) lbs_set_power, /* SIOCSIWPOWER */ > - (iw_handler) lbs_get_power, /* SIOCGIWPOWER */ > - (iw_handler) NULL, /* -- hole -- */ > - (iw_handler) NULL, /* -- hole -- */ > - (iw_handler) lbs_set_genie, /* SIOCSIWGENIE */ > - (iw_handler) lbs_get_genie, /* SIOCGIWGENIE */ > - (iw_handler) lbs_set_auth, /* SIOCSIWAUTH */ > - (iw_handler) lbs_get_auth, /* SIOCGIWAUTH */ > - (iw_handler) lbs_set_encodeext,/* SIOCSIWENCODEEXT */ > - (iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */ > - (iw_handler) NULL, /* SIOCSIWPMKSA */ > -}; > - > -struct iw_handler_def mesh_handler_def = { > - .num_standard = ARRAY_SIZE(mesh_wlan_handler), > - .standard = (iw_handler *) mesh_wlan_handler, > - .get_wireless_stats = lbs_get_wireless_stats, > -}; > -#endif > --- linux-wl.orig/drivers/net/wireless/libertas/decl.h > +++ linux-wl/drivers/net/wireless/libertas/decl.h > @@ -1,3 +1,4 @@ > + > /** > * This file contains declaration referring to > * functions defined in other source files > @@ -34,6 +35,8 @@ int lbs_start_card(struct lbs_private *p > void lbs_stop_card(struct lbs_private *priv); > void lbs_host_to_card_done(struct lbs_private *priv); > > +int lbs_rtap_supported(struct lbs_private *priv); > + > int lbs_set_mac_address(struct net_device *dev, void *addr); > void lbs_set_multicast_list(struct net_device *dev); > >