📄 join.c
字号:
/** * Functions implementing wlan infrastructure and adhoc join routines, * IOCTL handlers as well as command preperation and response routines * for sending adhoc start, adhoc join, and association commands * to the firmware. */#include <linux/netdevice.h>#include <linux/if_arp.h>#include <linux/wireless.h>#include <linux/etherdevice.h>#include <net/iw_handler.h>#include "host.h"#include "decl.h"#include "join.h"#include "dev.h"#include "assoc.h"/* The firmware needs certain bits masked out of the beacon-derviced capability * field when associating/joining to BSSs. */#define CAPINFO_MASK (~(0xda00))/** * @brief This function finds common rates between rate1 and card rates. * * It will fill common rates in rate1 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 adapter A pointer to wlan_adapter structure * @param rate1 the buffer which keeps input and output * @param rate1_size the size of rate1 buffer; new size of buffer on return * * @return 0 or -1 */static int get_common_rates(wlan_adapter * adapter, u8 * rates, u16 *rates_size){ u8 *card_rates = libertas_bg_rates; size_t num_card_rates = sizeof(libertas_bg_rates); int ret = 0, i, j; u8 tmp[30]; size_t tmp_size = 0; /* For each rate in card_rates that exists in rate1, copy to tmp */ for (i = 0; card_rates[i] && (i < num_card_rates); i++) { for (j = 0; rates[j] && (j < *rates_size); j++) { if (rates[j] == card_rates[i]) tmp[tmp_size++] = card_rates[i]; } } lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size); lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates, num_card_rates); lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size); lbs_deb_join("Tx datarate is currently 0x%X\n", adapter->cur_rate); if (!adapter->auto_rate) { for (i = 0; i < tmp_size; i++) { if (tmp[i] == adapter->cur_rate) goto done; } lbs_pr_alert("Previously set fixed data rate %#x isn't " "compatible with the network.\n", adapter->cur_rate); ret = -1; goto done; } ret = 0;done: memset(rates, 0, *rates_size); *rates_size = min_t(int, tmp_size, *rates_size); memcpy(rates, tmp, *rates_size); return ret;}/** * @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 libertas_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; }}/** * @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 */void libertas_unset_basic_rate_flags(u8 * rates, size_t len){ int i; for (i = 0; i < len; i++) rates[i] &= 0x7f;}/** * @brief Associate to a specific BSS discovered in a scan * * @param priv A pointer to wlan_private structure * @param pbssdesc Pointer to the BSS descriptor to associate with. * * @return 0-success, otherwise fail */int wlan_associate(wlan_private * priv, struct assoc_request * assoc_req){ wlan_adapter *adapter = priv->adapter; int ret; lbs_deb_enter(LBS_DEB_JOIN); ret = libertas_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE, 0, CMD_OPTION_WAITFORRSP, 0, assoc_req->bss.bssid); if (ret) goto done; /* set preamble to firmware */ if ( (adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) adapter->preamble = CMD_TYPE_SHORT_PREAMBLE; else adapter->preamble = CMD_TYPE_LONG_PREAMBLE; libertas_set_radio_control(priv); ret = libertas_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE, 0, CMD_OPTION_WAITFORRSP, 0, assoc_req);done: lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); return ret;}/** * @brief Start an Adhoc Network * * @param priv A pointer to wlan_private structure * @param adhocssid The ssid of the Adhoc Network * @return 0--success, -1--fail */int libertas_start_adhoc_network(wlan_private * priv, struct assoc_request * assoc_req){ wlan_adapter *adapter = priv->adapter; int ret = 0; adapter->adhoccreate = 1; if (adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) { lbs_deb_join("AdhocStart: Short preamble\n"); adapter->preamble = CMD_TYPE_SHORT_PREAMBLE; } else { lbs_deb_join("AdhocStart: Long preamble\n"); adapter->preamble = CMD_TYPE_LONG_PREAMBLE; } libertas_set_radio_control(priv); lbs_deb_join("AdhocStart: channel = %d\n", assoc_req->channel); lbs_deb_join("AdhocStart: band = %d\n", assoc_req->band); ret = libertas_prepare_and_send_command(priv, CMD_802_11_AD_HOC_START, 0, CMD_OPTION_WAITFORRSP, 0, assoc_req); return ret;}/** * @brief Join an adhoc network found in a previous scan * * @param priv A pointer to wlan_private structure * @param pbssdesc Pointer to a BSS descriptor found in a previous scan * to attempt to join * * @return 0--success, -1--fail */int libertas_join_adhoc_network(wlan_private * priv, struct assoc_request * assoc_req){ wlan_adapter *adapter = priv->adapter; struct bss_descriptor * bss = &assoc_req->bss; int ret = 0; lbs_deb_join("%s: Current SSID '%s', ssid length %u\n", __func__, escape_essid(adapter->curbssparams.ssid, adapter->curbssparams.ssid_len), adapter->curbssparams.ssid_len); lbs_deb_join("%s: requested ssid '%s', ssid length %u\n", __func__, escape_essid(bss->ssid, bss->ssid_len), bss->ssid_len); /* check if the requested SSID is already joined */ if ( adapter->curbssparams.ssid_len && !libertas_ssid_cmp(adapter->curbssparams.ssid, adapter->curbssparams.ssid_len, bss->ssid, bss->ssid_len) && (adapter->mode == IW_MODE_ADHOC) && (adapter->connect_status == LIBERTAS_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, adapter->curbssparams.bssid, ETH_ALEN); wrqu.ap_addr.sa_family = ARPHRD_ETHER; wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); goto out; } /* Use shortpreamble only when both creator and card supports short preamble */ if ( !(bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) || !(adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) { lbs_deb_join("AdhocJoin: Long preamble\n"); adapter->preamble = CMD_TYPE_LONG_PREAMBLE; } else { lbs_deb_join("AdhocJoin: Short preamble\n"); adapter->preamble = CMD_TYPE_SHORT_PREAMBLE; } libertas_set_radio_control(priv); lbs_deb_join("AdhocJoin: channel = %d\n", assoc_req->channel); lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band); adapter->adhoccreate = 0; ret = libertas_prepare_and_send_command(priv, CMD_802_11_AD_HOC_JOIN, 0, CMD_OPTION_WAITFORRSP, OID_802_11_SSID, assoc_req);out: return ret;}int libertas_stop_adhoc_network(wlan_private * priv){ return libertas_prepare_and_send_command(priv, CMD_802_11_AD_HOC_STOP, 0, CMD_OPTION_WAITFORRSP, 0, NULL);}/** * @brief Send Deauthentication Request * * @param priv A pointer to wlan_private structure * @return 0--success, -1--fail */int libertas_send_deauthentication(wlan_private * priv){ return libertas_prepare_and_send_command(priv, CMD_802_11_DEAUTHENTICATE, 0, CMD_OPTION_WAITFORRSP, 0, NULL);}/** * @brief This function prepares command of authenticate. * * @param priv A pointer to wlan_private structure * @param cmd A pointer to cmd_ds_command structure * @param pdata_buf Void cast of pointer to a BSSID to authenticate with * * @return 0 or -1 */int libertas_cmd_80211_authenticate(wlan_private * priv, struct cmd_ds_command *cmd, void *pdata_buf){ wlan_adapter *adapter = priv->adapter; struct cmd_ds_802_11_authenticate *pauthenticate = &cmd->params.auth; int ret = -1; u8 *bssid = pdata_buf; DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_JOIN); cmd->command = cpu_to_le16(CMD_802_11_AUTHENTICATE); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate) + S_DS_GEN); /* translate auth mode to 802.11 defined wire value */ switch (adapter->secinfo.auth_mode) { case IW_AUTH_ALG_OPEN_SYSTEM: pauthenticate->authtype = 0x00; break; case IW_AUTH_ALG_SHARED_KEY: pauthenticate->authtype = 0x01; break; case IW_AUTH_ALG_LEAP: pauthenticate->authtype = 0x80; break; default: lbs_deb_join("AUTH_CMD: invalid auth alg 0x%X\n", adapter->secinfo.auth_mode); goto out; } memcpy(pauthenticate->macaddr, bssid, ETH_ALEN); lbs_deb_join("AUTH_CMD: BSSID is : %s auth=0x%X\n", print_mac(mac, bssid), pauthenticate->authtype); ret = 0;out: lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); return ret;}int libertas_cmd_80211_deauthenticate(wlan_private * priv, struct cmd_ds_command *cmd){ wlan_adapter *adapter = priv->adapter; struct cmd_ds_802_11_deauthenticate *dauth = &cmd->params.deauth; lbs_deb_enter(LBS_DEB_JOIN); cmd->command = cpu_to_le16(CMD_802_11_DEAUTHENTICATE); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate) + S_DS_GEN); /* set AP MAC address */ memmove(dauth->macaddr, adapter->curbssparams.bssid, ETH_ALEN); /* Reason code 3 = Station is leaving */#define REASON_CODE_STA_LEAVING 3 dauth->reasoncode = cpu_to_le16(REASON_CODE_STA_LEAVING); lbs_deb_leave(LBS_DEB_JOIN); return 0;}int libertas_cmd_80211_associate(wlan_private * priv, struct cmd_ds_command *cmd, void *pdata_buf){ wlan_adapter *adapter = priv->adapter; struct cmd_ds_802_11_associate *passo = &cmd->params.associate; int ret = 0; struct assoc_request * assoc_req = pdata_buf; struct bss_descriptor * bss = &assoc_req->bss; u8 *pos; u16 tmpcap, tmplen; struct mrvlietypes_ssidparamset *ssid; struct mrvlietypes_phyparamset *phy; struct mrvlietypes_ssparamset *ss; struct mrvlietypes_ratesparamset *rates; struct mrvlietypes_rsnparamset *rsn; lbs_deb_enter(LBS_DEB_JOIN); pos = (u8 *) passo; if (!adapter) { ret = -1; goto done; } cmd->command = cpu_to_le16(CMD_802_11_ASSOCIATE); memcpy(passo->peerstaaddr, bss->bssid, sizeof(passo->peerstaaddr)); pos += sizeof(passo->peerstaaddr); /* set the listen interval */ passo->listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL); pos += sizeof(passo->capability); pos += sizeof(passo->listeninterval); pos += sizeof(passo->bcnperiod); pos += sizeof(passo->dtimperiod); ssid = (struct mrvlietypes_ssidparamset *) 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; phy = (struct mrvlietypes_phyparamset *) pos; phy->header.type = cpu_to_le16(TLV_TYPE_PHY_DS); tmplen = sizeof(phy->fh_ds.dsparamset); phy->header.len = cpu_to_le16(tmplen); memcpy(&phy->fh_ds.dsparamset, &bss->phyparamset.dsparamset.currentchan, tmplen); pos += sizeof(phy->header) + tmplen; ss = (struct mrvlietypes_ssparamset *) pos; ss->header.type = cpu_to_le16(TLV_TYPE_CF); tmplen = sizeof(ss->cf_ibss.cfparamset); ss->header.len = cpu_to_le16(tmplen); pos += sizeof(ss->header) + tmplen; rates = (struct mrvlietypes_ratesparamset *) pos; rates->header.type = cpu_to_le16(TLV_TYPE_RATES); memcpy(&rates->rates, &bss->rates, MAX_RATES); tmplen = MAX_RATES; if (get_common_rates(adapter, rates->rates, &tmplen)) { ret = -1; goto done; } pos += sizeof(rates->header) + tmplen; rates->header.len = cpu_to_le16(tmplen); lbs_deb_join("ASSOC_CMD: num rates = %u\n", tmplen); /* Copy the infra. association rates into Current BSS state structure */ memset(&adapter->curbssparams.rates, 0, sizeof(adapter->curbssparams.rates)); memcpy(&adapter->curbssparams.rates, &rates->rates, tmplen); /* Set MSB on basic rates as the firmware requires, but _after_ * copying to current bss rates. */ libertas_set_basic_rate_flags(rates->rates, tmplen); if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) { rsn = (struct mrvlietypes_rsnparamset *) 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: RSN IE", (u8 *) rsn, sizeof(rsn->header) + tmplen); pos += sizeof(rsn->header) + tmplen; } /* update curbssparams */ adapter->curbssparams.channel = bss->phyparamset.dsparamset.currentchan; if (libertas_parse_dnld_countryinfo_11d(priv, bss)) { ret = -1; goto done; } cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN); /* set the capability info */ tmpcap = (bss->capability & CAPINFO_MASK);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -