/* * This function maps the nl802.11 channel type into driver channel type. * * The mapping is as follows - * NL80211_CHAN_NO_HT -> IEEE80211_HT_PARAM_CHA_SEC_NONE * NL80211_CHAN_HT20 -> IEEE80211_HT_PARAM_CHA_SEC_NONE * NL80211_CHAN_HT40PLUS -> IEEE80211_HT_PARAM_CHA_SEC_ABOVE * NL80211_CHAN_HT40MINUS -> IEEE80211_HT_PARAM_CHA_SEC_BELOW * Others -> IEEE80211_HT_PARAM_CHA_SEC_NONE
*/
u8 mwifiex_chan_type_to_sec_chan_offset(enum nl80211_channel_type chan_type)
{ switch (chan_type) { case NL80211_CHAN_NO_HT: case NL80211_CHAN_HT20: return IEEE80211_HT_PARAM_CHA_SEC_NONE; case NL80211_CHAN_HT40PLUS: return IEEE80211_HT_PARAM_CHA_SEC_ABOVE; case NL80211_CHAN_HT40MINUS: return IEEE80211_HT_PARAM_CHA_SEC_BELOW; default: return IEEE80211_HT_PARAM_CHA_SEC_NONE;
}
}
/* This function maps IEEE HT secondary channel type to NL80211 channel type
*/
u8 mwifiex_get_chan_type(struct mwifiex_private *priv)
{ struct mwifiex_channel_band channel_band; int ret;
ret = mwifiex_get_chan_info(priv, &channel_band);
if (!ret) { switch (channel_band.band_config.chan_width) { case CHAN_BW_20MHZ: if (IS_11N_ENABLED(priv)) return NL80211_CHAN_HT20; else return NL80211_CHAN_NO_HT; case CHAN_BW_40MHZ: if (channel_band.band_config.chan2_offset ==
SEC_CHAN_ABOVE) return NL80211_CHAN_HT40PLUS; else return NL80211_CHAN_HT40MINUS; default: return NL80211_CHAN_HT20;
}
}
return NL80211_CHAN_HT20;
}
/* * This function checks whether WEP is set.
*/ staticint
mwifiex_is_alg_wep(u32 cipher)
{ switch (cipher) { case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: return1; default: break;
}
return0;
}
/* * This function retrieves the private structure from kernel wiphy structure.
*/ staticvoid *mwifiex_cfg80211_get_adapter(struct wiphy *wiphy)
{ return (void *) (*(unsignedlong *) wiphy_priv(wiphy));
}
if (!buf || !len) {
mwifiex_dbg(priv->adapter, ERROR, "invalid buffer and length\n"); return -EFAULT;
}
mgmt = (conststruct ieee80211_mgmt *)buf; if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA &&
ieee80211_is_probe_resp(mgmt->frame_control)) { /* Since we support offload probe resp, we need to skip probe
* resp in AP or GO mode */
mwifiex_dbg(priv->adapter, INFO, "info: skip to send probe resp in AP or GO mode\n"); return0;
}
if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { if (ieee80211_is_auth(mgmt->frame_control))
mwifiex_dbg(priv->adapter, MSG, "auth: send auth to %pM\n", mgmt->da); if (ieee80211_is_deauth(mgmt->frame_control))
mwifiex_dbg(priv->adapter, MSG, "auth: send deauth to %pM\n", mgmt->da); if (ieee80211_is_disassoc(mgmt->frame_control))
mwifiex_dbg(priv->adapter, MSG, "assoc: send disassoc to %pM\n", mgmt->da); if (ieee80211_is_assoc_resp(mgmt->frame_control))
mwifiex_dbg(priv->adapter, MSG, "assoc: send assoc resp to %pM\n",
mgmt->da); if (ieee80211_is_reassoc_resp(mgmt->frame_control))
mwifiex_dbg(priv->adapter, MSG, "assoc: send reassoc resp to %pM\n",
mgmt->da);
}
/* * CFG802.11 operation handler to get Tx power.
*/ staticint
mwifiex_cfg80211_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, int radio_idx, unsignedint link_id, int *dbm)
{ struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); struct mwifiex_private *priv = mwifiex_get_priv(adapter,
MWIFIEX_BSS_ROLE_ANY); int ret = mwifiex_send_cmd(priv, HostCmd_CMD_RF_TX_PWR,
HostCmd_ACT_GEN_GET, 0, NULL, true);
if (ret < 0) return ret;
/* tx_power_level is set in HostCmd_CMD_RF_TX_PWR command handler */
*dbm = priv->tx_power_level;
return0;
}
/* * CFG802.11 operation handler to set Power Save option. * * The timeout value, if provided, is currently ignored.
*/ staticint
mwifiex_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, bool enabled, int timeout)
{ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
u32 ps_mode;
if (timeout)
mwifiex_dbg(priv->adapter, INFO, "info: ignore timeout value for IEEE Power Save\n");
ps_mode = enabled;
return mwifiex_drv_set_power(priv, &ps_mode);
}
/* * CFG802.11 operation handler to set the default network key.
*/ staticint
mwifiex_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev, int link_id, u8 key_index, bool unicast, bool multicast)
{ struct mwifiex_private *priv = mwifiex_netdev_get_priv(netdev);
/* Return if WEP key not configured */ if (!priv->sec_info.wep_enabled) return0;
/* * This function sends domain information to the firmware. * * The following information are passed to the firmware - * - Country codes * - Sub bands (first channel, number of channels, maximum Tx power)
*/ int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy)
{
u8 no_of_triplet = 0; struct ieee80211_country_ie_triplet *t;
u8 no_of_parsed_chan = 0;
u8 first_chan = 0, next_chan = 0, max_pwr = 0;
u8 i, flag = 0; enum nl80211_band band; struct ieee80211_supported_band *sband; struct ieee80211_channel *ch; struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); struct mwifiex_private *priv; struct mwifiex_802_11d_domain_reg *domain_info = &adapter->domain_reg;
/* Set country code */
domain_info->country_code[0] = adapter->country_code[0];
domain_info->country_code[1] = adapter->country_code[1];
domain_info->country_code[2] = ' ';
band = mwifiex_band_to_radio_type(adapter->config_bands); if (!wiphy->bands[band]) {
mwifiex_dbg(adapter, ERROR, "11D: setting domain info in FW\n"); return -1;
}
sband = wiphy->bands[band];
for (i = 0; i < sband->n_channels ; i++) {
ch = &sband->channels[i]; if (ch->flags & IEEE80211_CHAN_DISABLED) continue;
if (!wiphy->bands[NL80211_BAND_5GHZ]) return;
sband = wiphy->bands[NL80211_BAND_5GHZ];
for (i = 0; i < sband->n_channels; i++) {
chan = &sband->channels[i]; if ((!(chan->flags & IEEE80211_CHAN_DISABLED)) &&
(chan->flags & IEEE80211_CHAN_RADAR))
chan->flags |= IEEE80211_CHAN_NO_IR;
}
}
/* * CFG802.11 regulatory domain callback function. * * This function is called when the regulatory domain is changed due to the * following reasons - * - Set by driver * - Set by system core * - Set by user * - Set bt Country IE
*/ staticvoid mwifiex_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
{ struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); struct mwifiex_private *priv = mwifiex_get_priv(adapter,
MWIFIEX_BSS_ROLE_ANY);
mwifiex_dbg(adapter, INFO, "info: cfg80211 regulatory domain callback for %c%c\n",
request->alpha2[0], request->alpha2[1]);
mwifiex_reg_apply_radar_flags(wiphy);
switch (request->initiator) { case NL80211_REGDOM_SET_BY_DRIVER: case NL80211_REGDOM_SET_BY_CORE: case NL80211_REGDOM_SET_BY_USER: case NL80211_REGDOM_SET_BY_COUNTRY_IE: break; default:
mwifiex_dbg(adapter, ERROR, "unknown regdom initiator: %d\n",
request->initiator); return;
}
/* Don't send same regdom info to firmware */ if (strncmp(request->alpha2, adapter->country_code, sizeof(request->alpha2)) != 0) {
memcpy(adapter->country_code, request->alpha2, sizeof(request->alpha2));
mwifiex_send_domain_info_cmd_fw(wiphy);
mwifiex_dnld_txpwr_table(priv);
}
}
/* * This function sets the fragmentation threshold. * * The fragmentation threshold value must lie between MWIFIEX_FRAG_MIN_VALUE * and MWIFIEX_FRAG_MAX_VALUE.
*/ staticint
mwifiex_set_frag(struct mwifiex_private *priv, u32 frag_thr)
{ if (frag_thr < MWIFIEX_FRAG_MIN_VALUE ||
frag_thr > MWIFIEX_FRAG_MAX_VALUE)
frag_thr = MWIFIEX_FRAG_MAX_VALUE;
* The rts value must lie between MWIFIEX_RTS_MIN_VALUE * and MWIFIEX_RTS_MAX_VALUE.
*/ staticint
mwifiex_set_rts(struct mwifiex_private *priv, u32 rts_thr)
{ if (rts_thr < MWIFIEX_RTS_MIN_VALUE || rts_thr > MWIFIEX_RTS_MAX_VALUE)
rts_thr = MWIFIEX_RTS_MAX_VALUE;
/* * CFG802.11 operation handler to set wiphy parameters. * * This function can be used to set the RTS threshold and the * Fragmentation threshold of the driver.
*/ staticint
mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, int radio_idx,
u32 changed)
{ struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); struct mwifiex_private *priv; struct mwifiex_uap_bss_param *bss_cfg; int ret;
/* * This function initializes the functionalities for P2P GO. * The P2P GO initialization sequence is: * disable -> device -> GO
*/ staticint
mwifiex_cfg80211_init_p2p_go(struct mwifiex_private *priv)
{
u16 mode;
staticbool
is_vif_type_change_allowed(struct mwifiex_adapter *adapter, enum nl80211_iftype old_iftype, enum nl80211_iftype new_iftype)
{ switch (old_iftype) { case NL80211_IFTYPE_ADHOC: switch (new_iftype) { case NL80211_IFTYPE_STATION: returntrue; case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_GO: return adapter->curr_iface_comb.p2p_intf !=
adapter->iface_limit.p2p_intf; case NL80211_IFTYPE_AP: return adapter->curr_iface_comb.uap_intf !=
adapter->iface_limit.uap_intf; default: returnfalse;
}
case NL80211_IFTYPE_STATION: switch (new_iftype) { case NL80211_IFTYPE_ADHOC: returntrue; case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_GO: return adapter->curr_iface_comb.p2p_intf !=
adapter->iface_limit.p2p_intf; case NL80211_IFTYPE_AP: return adapter->curr_iface_comb.uap_intf !=
adapter->iface_limit.uap_intf; default: returnfalse;
}
case NL80211_IFTYPE_AP: switch (new_iftype) { case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_STATION: return adapter->curr_iface_comb.sta_intf !=
adapter->iface_limit.sta_intf; case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_GO: return adapter->curr_iface_comb.p2p_intf !=
adapter->iface_limit.p2p_intf; default: returnfalse;
}
case NL80211_IFTYPE_P2P_CLIENT: switch (new_iftype) { case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_STATION: returntrue; case NL80211_IFTYPE_P2P_GO: returntrue; case NL80211_IFTYPE_AP: return adapter->curr_iface_comb.uap_intf !=
adapter->iface_limit.uap_intf; default: returnfalse;
}
case NL80211_IFTYPE_P2P_GO: switch (new_iftype) { case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_STATION: returntrue; case NL80211_IFTYPE_P2P_CLIENT: returntrue; case NL80211_IFTYPE_AP: return adapter->curr_iface_comb.uap_intf !=
adapter->iface_limit.uap_intf; default: returnfalse;
}
default: break;
}
returnfalse;
}
staticvoid
update_vif_type_counter(struct mwifiex_adapter *adapter, enum nl80211_iftype iftype, int change)
{ switch (iftype) { case NL80211_IFTYPE_UNSPECIFIED: case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_STATION:
adapter->curr_iface_comb.sta_intf += change; break; case NL80211_IFTYPE_AP:
adapter->curr_iface_comb.uap_intf += change; break; case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_GO:
adapter->curr_iface_comb.p2p_intf += change; break; default:
mwifiex_dbg(adapter, ERROR, "%s: Unsupported iftype passed: %d\n",
__func__, iftype); break;
}
}
if (type == NL80211_IFTYPE_STATION)
mwifiex_dbg(adapter, INFO, "%s: changing role to station\n", dev->name); else
mwifiex_dbg(adapter, INFO, "%s: changing role to adhoc\n", dev->name);
if (mwifiex_deinit_priv_params(priv)) return -1; if (mwifiex_init_new_priv_params(priv, dev, type)) return -1;
if (priv->scan_request) {
mwifiex_dbg(priv->adapter, ERROR, "change virtual interface: scan in process\n"); return -EBUSY;
}
if (type == NL80211_IFTYPE_UNSPECIFIED) {
mwifiex_dbg(priv->adapter, INFO, "%s: no new type specified, keeping old type %d\n",
dev->name, curr_iftype); return0;
}
if (curr_iftype == type) {
mwifiex_dbg(priv->adapter, INFO, "%s: interface already is of type %d\n",
dev->name, curr_iftype); return0;
}
if (!is_vif_type_change_allowed(priv->adapter, curr_iftype, type)) {
mwifiex_dbg(priv->adapter, ERROR, "%s: change from type %d to %d is not allowed\n",
dev->name, curr_iftype, type); return -EOPNOTSUPP;
}
switch (curr_iftype) { case NL80211_IFTYPE_ADHOC: switch (type) { case NL80211_IFTYPE_STATION:
priv->bss_mode = type;
priv->sec_info.authentication_mode =
NL80211_AUTHTYPE_OPEN_SYSTEM;
dev->ieee80211_ptr->iftype = type;
mwifiex_deauthenticate(priv, NULL); return mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE,
HostCmd_ACT_GEN_SET, 0, NULL, true); case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_GO: return mwifiex_change_vif_to_p2p(dev, curr_iftype,
type, params); case NL80211_IFTYPE_AP: return mwifiex_change_vif_to_ap(dev, curr_iftype, type,
params); default: goto errnotsupp;
}
case NL80211_IFTYPE_STATION: switch (type) { case NL80211_IFTYPE_ADHOC:
priv->bss_mode = type;
priv->sec_info.authentication_mode =
NL80211_AUTHTYPE_OPEN_SYSTEM;
dev->ieee80211_ptr->iftype = type;
mwifiex_deauthenticate(priv, NULL); return mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE,
HostCmd_ACT_GEN_SET, 0, NULL, true); case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_GO: return mwifiex_change_vif_to_p2p(dev, curr_iftype,
type, params); case NL80211_IFTYPE_AP: return mwifiex_change_vif_to_ap(dev, curr_iftype, type,
params); default: goto errnotsupp;
}
case NL80211_IFTYPE_AP: switch (type) { case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_STATION: return mwifiex_change_vif_to_sta_adhoc(dev, curr_iftype,
type, params); break; case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_GO: return mwifiex_change_vif_to_p2p(dev, curr_iftype,
type, params); default: goto errnotsupp;
}
case NL80211_IFTYPE_P2P_CLIENT: if (mwifiex_cfg80211_deinit_p2p(priv)) return -EFAULT;
switch (type) { case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_STATION: return mwifiex_change_vif_to_sta_adhoc(dev, curr_iftype,
type, params); case NL80211_IFTYPE_P2P_GO: return mwifiex_change_vif_to_p2p(dev, curr_iftype,
type, params); case NL80211_IFTYPE_AP: return mwifiex_change_vif_to_ap(dev, curr_iftype, type,
params); default: goto errnotsupp;
}
case NL80211_IFTYPE_P2P_GO: if (mwifiex_cfg80211_deinit_p2p(priv)) return -EFAULT;
switch (type) { case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_STATION: return mwifiex_change_vif_to_sta_adhoc(dev, curr_iftype,
type, params); case NL80211_IFTYPE_P2P_CLIENT: return mwifiex_change_vif_to_p2p(dev, curr_iftype,
type, params); case NL80211_IFTYPE_AP: return mwifiex_change_vif_to_ap(dev, curr_iftype, type,
params); default: goto errnotsupp;
}
default: goto errnotsupp;
}
return0;
errnotsupp:
mwifiex_dbg(priv->adapter, ERROR, "unsupported interface type transition: %d to %d\n",
curr_iftype, type); return -EOPNOTSUPP;
}
/* * This function dumps the station information on a buffer. * * The following information are shown - * - Total bytes transmitted * - Total bytes received * - Total packets transmitted * - Total packets received * - Signal quality level * - Transmission rate
*/ staticint
mwifiex_dump_station_info(struct mwifiex_private *priv, struct mwifiex_sta_node *node, struct station_info *sinfo)
{
u32 rate;
/* Get signal information from the firmware */ if (mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO,
HostCmd_ACT_GEN_GET, 0, NULL, true)) {
mwifiex_dbg(priv->adapter, ERROR, "failed to get signal information\n"); return -EFAULT;
}
if (mwifiex_drv_get_data_rate(priv, &rate)) {
mwifiex_dbg(priv->adapter, ERROR, "getting data rate error\n"); return -EFAULT;
}
/* Get DTIM period information from firmware */
mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
HostCmd_ACT_GEN_GET, DTIM_PERIOD_I,
&priv->dtim_period, true);
/* * CFG802.11 operation handler to get station information. * * This function only works in connected mode, and dumps the * requested station information, if available.
*/ staticint
mwifiex_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, const u8 *mac, struct station_info *sinfo)
{ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
if (!priv->media_connected) return -ENOENT; if (memcmp(mac, priv->cfg_bssid, ETH_ALEN)) return -ENOENT;
/* cfg80211 operation handler for del_station. * Function deauthenticates station which value is provided in mac parameter. * If mac is NULL/broadcast, all stations in associated station list are * deauthenticated. If bss is not started or there are no stations in * associated stations list, no action is taken.
*/ staticint
mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, struct station_del_parameters *params)
{ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); struct mwifiex_sta_node *sta_node;
u8 deauth_mac[ETH_ALEN];
if (adapter->hw_dev_mcs_support != HT_STREAM_2X2) { /* Not a MIMO chip. User should provide specific antenna number * for Tx/Rx path or enable all antennas for diversity
*/ if (tx_ant != rx_ant) return -EOPNOTSUPP;
if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP,
HostCmd_ACT_GEN_SET, 0, NULL, true)) {
mwifiex_dbg(priv->adapter, ERROR, "Failed to stop the BSS\n"); return -1;
}
if (mwifiex_send_cmd(priv, HOST_CMD_APCMD_SYS_RESET,
HostCmd_ACT_GEN_SET, 0, NULL, true)) {
mwifiex_dbg(priv->adapter, ERROR, "Failed to reset BSS\n"); return -1;
}
if (netif_carrier_ok(priv->netdev))
netif_carrier_off(priv->netdev);
mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter);
return0;
}
/* cfg80211 operation handler for start_ap. * Function sets beacon period, DTIM period, SSID and security into * AP config structure. * AP is configured with these settings and BSS is started.
*/ staticint mwifiex_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ap_settings *params)
{ struct mwifiex_uap_bss_param *bss_cfg; struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP) return -1;
bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL); if (!bss_cfg) return -ENOMEM;
/* * CFG802.11 operation handler for disconnection request. * * This function does not work when there is already a disconnection * procedure going on.
*/ staticint
mwifiex_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
u16 reason_code)
{ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
if (!mwifiex_stop_bg_scan(priv))
cfg80211_sched_scan_stopped_locked(priv->wdev.wiphy, 0);
if (mwifiex_deauthenticate(priv, NULL)) return -EFAULT;
/* * This function informs the CFG802.11 subsystem of a new IBSS. * * The following information are sent to the CFG802.11 subsystem * to register the new IBSS. If we do not register the new IBSS, * a kernel panic will result. * - SSID * - SSID length * - BSSID * - Channel
*/ staticint mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)
{ struct ieee80211_channel *chan; struct mwifiex_bss_info bss_info; struct cfg80211_bss *bss; int ie_len;
u8 ie_buf[IEEE80211_MAX_SSID_LEN + sizeof(struct ieee_types_header)]; enum nl80211_band band;
if (mwifiex_get_bss_info(priv, &bss_info)) return -1;
/* * This function connects with a BSS. * * This function handles both Infra and Ad-Hoc modes. It also performs * validity checking on the provided parameters, disconnects from the * current BSS (if any), sets up the association/scan parameters, * including security settings, and performs specific SSID scan before * trying to connect. * * For Infra mode, the function returns failure if the specified SSID * is not found in scan table. However, for Ad-Hoc mode, it can create * the IBSS if it does not exist. On successful completion in either case, * the function notifies the CFG802.11 subsystem of the new BSS connection.
*/ staticint
mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, const u8 *ssid, const u8 *bssid, int mode, struct ieee80211_channel *channel, struct cfg80211_connect_params *sme, bool privacy, struct cfg80211_bss **sel_bss)
{ struct cfg80211_ssid req_ssid; int ret, auth_type = 0; struct cfg80211_bss *bss = NULL;
u8 is_scanning_required = 0;
/* As this is new association, clear locally stored
* keys and security related flags */
priv->sec_info.wpa_enabled = false;
priv->sec_info.wpa2_enabled = false;
priv->wep_key_curr_index = 0;
priv->sec_info.encryption_mode = 0;
priv->sec_info.is_authtype_auto = 0;
ret = mwifiex_set_encode(priv, NULL, NULL, 0, 0, NULL, 1);
if (mode == NL80211_IFTYPE_ADHOC) {
u16 enable = true;
/* set ibss coalescing_status */
ret = mwifiex_send_cmd(
priv,
HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
HostCmd_ACT_GEN_SET, 0, &enable, true); if (ret) return ret;
/* "privacy" is set only for ad-hoc mode */ if (privacy) { /* * Keep WLAN_CIPHER_SUITE_WEP104 for now so that * the firmware can find a matching network from the * scan. The cfg80211 does not give us the encryption * mode at this stage so just setting it to WEP here.
*/
priv->sec_info.encryption_mode =
WLAN_CIPHER_SUITE_WEP104;
priv->sec_info.authentication_mode =
NL80211_AUTHTYPE_OPEN_SYSTEM;
}
goto done;
}
/* Now handle infra mode. "sme" is valid for infra mode only */ if (sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) {
auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM;
priv->sec_info.is_authtype_auto = 1;
} else {
auth_type = sme->auth_type;
}
if (sme->crypto.n_ciphers_pairwise) {
priv->sec_info.encryption_mode =
sme->crypto.ciphers_pairwise[0];
priv->sec_info.authentication_mode = auth_type;
}
if (sme->crypto.cipher_group) {
priv->sec_info.encryption_mode = sme->crypto.cipher_group;
priv->sec_info.authentication_mode = auth_type;
} if (sme->ie)
ret = mwifiex_set_gen_ie(priv, sme->ie, sme->ie_len);
if (sme->key) { if (mwifiex_is_alg_wep(priv->sec_info.encryption_mode)) {
mwifiex_dbg(priv->adapter, INFO, "info: setting wep encryption\t" "with key len %d\n", sme->key_len);
priv->wep_key_curr_index = sme->key_idx;
ret = mwifiex_set_encode(priv, NULL, sme->key,
sme->key_len, sme->key_idx,
NULL, 0);
}
}
done: /* * Scan entries are valid for some time (15 sec). So we can save one * active scan time if we just try cfg80211_get_bss first. If it fails * then request scan and cfg80211_get_bss() again for final output.
*/ while (1) { if (is_scanning_required) { /* Do specific SSID scanning */ if (mwifiex_request_scan(priv, &req_ssid)) {
mwifiex_dbg(priv->adapter, ERROR, "scan error\n"); return -EFAULT;
}
}
/* Find the BSS we want using available scan results */ if (mode == NL80211_IFTYPE_ADHOC)
bss = cfg80211_get_bss(priv->wdev.wiphy, channel,
bssid, ssid, ssid_len,
IEEE80211_BSS_TYPE_IBSS,
IEEE80211_PRIVACY_ANY); else
bss = cfg80211_get_bss(priv->wdev.wiphy, channel,
bssid, ssid, ssid_len,
IEEE80211_BSS_TYPE_ESS,
IEEE80211_PRIVACY_ANY);
if (!bss) { if (is_scanning_required) {
mwifiex_dbg(priv->adapter, MSG, "assoc: requested bss not found in scan results\n"); break;
}
is_scanning_required = 1;
} else {
mwifiex_dbg(priv->adapter, MSG, "info: trying to associate to bssid %pM\n",
bss->bssid);
memcpy(&priv->cfg_bssid, bss->bssid, ETH_ALEN); break;
}
}
if (bss)
cfg80211_ref_bss(priv->adapter->wiphy, bss);
ret = mwifiex_bss_start(priv, bss, &req_ssid); if (ret) goto cleanup;
if (mode == NL80211_IFTYPE_ADHOC) { /* Inform the BSS information to kernel, otherwise
* kernel will give a panic after successful assoc */ if (mwifiex_cfg80211_inform_ibss_bss(priv)) {
ret = -EFAULT; goto cleanup;
}
}
/* Pass the selected BSS entry to caller. */ if (sel_bss) {
*sel_bss = bss;
bss = NULL;
}
cleanup: if (bss)
cfg80211_put_bss(priv->adapter->wiphy, bss); return ret;
}
/* * CFG802.11 operation handler for association request. * * This function does not work when the current mode is set to Ad-Hoc, or * when there is already an association procedure going on. The given BSS * information is used to associate.
*/ staticint
mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_connect_params *sme)
{ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); struct mwifiex_adapter *adapter = priv->adapter; struct cfg80211_bss *bss = NULL; int ret;
if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) {
mwifiex_dbg(adapter, ERROR, "%s: reject infra assoc request in non-STA role\n",
dev->name); return -EINVAL;
}
/* * This function sets following parameters for ibss network. * - channel * - start band * - 11n flag * - secondary channel offset
*/ staticint mwifiex_set_ibss_params(struct mwifiex_private *priv, struct cfg80211_ibss_params *params)
{ struct mwifiex_adapter *adapter = priv->adapter; int index = 0, i;
u8 config_bands = 0;
if (params->chandef.chan->band == NL80211_BAND_2GHZ) { if (!params->basic_rates) {
config_bands = BAND_B | BAND_G;
} else { for (i = 0; i < mwifiex_band_2ghz.n_bitrates; i++) { /* * Rates below 6 Mbps in the table are CCK * rates; 802.11b and from 6 they are OFDM; * 802.11G
*/ if (mwifiex_rates[i].bitrate == 60) {
index = 1 << i; break;
}
}
mwifiex_dbg(adapter, INFO, "info: set ibss band %d, chan %d, chan offset %d\n",
config_bands, priv->adhoc_channel,
adapter->sec_chan_offset);
return0;
}
/* * CFG802.11 operation handler to join an IBSS. * * This function does not work in any mode other than Ad-Hoc, or if * a join operation is already in progress.
*/ staticint
mwifiex_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ibss_params *params)
{ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); int ret = 0;
if (priv->bss_mode != NL80211_IFTYPE_ADHOC) {
mwifiex_dbg(priv->adapter, ERROR, "request to join ibss received\t" "when station is not in ibss mode\n"); goto done;
}
mwifiex_dbg(priv->adapter, MSG, "info: trying to join to bssid %pM\n",
params->bssid);
/* * CFG802.11 operation handler to leave an IBSS. * * This function does not work if a leave operation is * already in progress.
*/ staticint
mwifiex_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
{ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
mwifiex_dbg(priv->adapter, MSG, "info: disconnecting from essid %pM\n",
priv->cfg_bssid); if (mwifiex_deauthenticate(priv, NULL)) return -EFAULT;
eth_zero_addr(priv->cfg_bssid);
return0;
}
/* * CFG802.11 operation handler for scan request. * * This function issues a scan request to the firmware based upon * the user specified scan configuration. On successful completion, * it also informs the results.
*/ staticint
mwifiex_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
{ struct net_device *dev = request->wdev->netdev; struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); int i, offset, ret; struct ieee80211_channel *chan; struct ieee_types_header *ie; struct mwifiex_user_scan_cfg *user_scan_cfg;
u8 mac_addr[ETH_ALEN];
mwifiex_dbg(priv->adapter, CMD, "info: received scan request on %s\n", dev->name);
/* Block scan request if scan operation or scan cleanup when interface * is disabled is in process
*/ if (priv->scan_request || priv->scan_aborting) {
mwifiex_dbg(priv->adapter, WARN, "cmd: Scan already in process..\n"); return -EBUSY;
}
if (!priv->wdev.connected && priv->scan_block)
priv->scan_block = false;
if (!mwifiex_stop_bg_scan(priv))
cfg80211_sched_scan_stopped_locked(priv->wdev.wiphy, 0);
user_scan_cfg = kzalloc(sizeof(*user_scan_cfg), GFP_KERNEL); if (!user_scan_cfg) return -ENOMEM;
if (request->ie && request->ie_len) { for (i = 0; i < MWIFIEX_MAX_VSIE_NUM; i++) { if (priv->vs_ie[i].mask == MWIFIEX_VSIE_MASK_SCAN) {
priv->vs_ie[i].mask = MWIFIEX_VSIE_MASK_CLEAR;
memset(&priv->vs_ie[i].ie, 0,
MWIFIEX_MAX_VSIE_LEN);
}
}
} return0;
}
/* CFG802.11 operation handler for sched_scan_start. * * This function issues a bgscan config request to the firmware based upon * the user specified sched_scan configuration. On successful completion, * firmware will generate BGSCAN_REPORT event, driver should issue bgscan * query command to get sched_scan results from firmware.
*/ staticint
mwifiex_cfg80211_sched_scan_start(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_sched_scan_request *request)
{ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); int i, offset; struct ieee80211_channel *chan; struct mwifiex_bg_scan_cfg *bgscan_cfg; struct ieee_types_header *ie;
/* Use at least 15 second for per scan cycle */
bgscan_cfg->scan_interval = (request->scan_plans->interval >
MWIFIEX_BGSCAN_INTERVAL) ?
request->scan_plans->interval :
MWIFIEX_BGSCAN_INTERVAL;
/* Fill HT capability information */ if (ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap))
ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; else
ht_info->cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
if (ISSUPP_SHORTGI20(adapter->hw_dot_11n_dev_cap))
ht_info->cap |= IEEE80211_HT_CAP_SGI_20; else
ht_info->cap &= ~IEEE80211_HT_CAP_SGI_20;
if (ISSUPP_SHORTGI40(adapter->hw_dot_11n_dev_cap))
ht_info->cap |= IEEE80211_HT_CAP_SGI_40; else
ht_info->cap &= ~IEEE80211_HT_CAP_SGI_40;
memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); /* Set MCS for 1x1/2x2 */
memset(ht_info->mcs.rx_mask, 0xff, rx_mcs_supp);
if (priv->bss_mode == NL80211_IFTYPE_STATION ||
ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap)) /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */
SETHT_MCS32(ht_info->mcs.rx_mask);
/* * create a new virtual interface with the given name and name assign type
*/ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, constchar *name, unsignedchar name_assign_type, enum nl80211_iftype type, struct vif_params *params)
{ struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); struct mwifiex_private *priv; struct net_device *dev; void *mdev_priv; int ret;
if (!adapter) return ERR_PTR(-EFAULT);
switch (type) { case NL80211_IFTYPE_UNSPECIFIED: case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: if (adapter->curr_iface_comb.sta_intf ==
adapter->iface_limit.sta_intf) {
mwifiex_dbg(adapter, ERROR, "cannot create multiple sta/adhoc ifaces\n"); return ERR_PTR(-EINVAL);
}
priv = mwifiex_get_unused_priv_by_bss_type(
adapter, MWIFIEX_BSS_TYPE_STA); if (!priv) {
mwifiex_dbg(adapter, ERROR, "could not get free private struct\n"); return ERR_PTR(-EFAULT);
}
break; case NL80211_IFTYPE_P2P_CLIENT: if (adapter->curr_iface_comb.p2p_intf ==
adapter->iface_limit.p2p_intf) {
mwifiex_dbg(adapter, ERROR, "cannot create multiple P2P ifaces\n"); return ERR_PTR(-EINVAL);
}
priv = mwifiex_get_unused_priv_by_bss_type(
adapter, MWIFIEX_BSS_TYPE_P2P); if (!priv) {
mwifiex_dbg(adapter, ERROR, "could not get free private struct\n"); return ERR_PTR(-EFAULT);
}
/* At start-up, wpa_supplicant tries to change the interface * to NL80211_IFTYPE_STATION if it is not managed mode.
*/
priv->wdev.iftype = NL80211_IFTYPE_P2P_CLIENT;
priv->bss_mode = NL80211_IFTYPE_P2P_CLIENT;
/* Setting bss_type to P2P tells firmware that this interface * is receiving P2P peers found during find phase and doing * action frame handshake.
*/
priv->bss_type = MWIFIEX_BSS_TYPE_P2P;
dev = alloc_netdev_mqs(sizeof(struct mwifiex_private *), name,
name_assign_type, ether_setup,
IEEE80211_NUM_ACS, 1); if (!dev) {
mwifiex_dbg(adapter, ERROR, "no memory available for netdevice\n");
ret = -ENOMEM; goto err_alloc_netdev;
}
mwifiex_init_priv_params(priv, dev);
priv->netdev = dev;
if (!adapter->mfg_mode) {
mwifiex_set_mac_address(priv, dev, false, NULL);
ret = mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE,
HostCmd_ACT_GEN_SET, 0, NULL, true); if (ret) goto err_set_bss_mode;
ret = mwifiex_sta_init_cmd(priv, false); if (ret) goto err_sta_init;
}
mwifiex_setup_ht_caps(&wiphy->bands[NL80211_BAND_2GHZ]->ht_cap, priv); if (adapter->is_hw_11ac_capable)
mwifiex_setup_vht_caps(
&wiphy->bands[NL80211_BAND_2GHZ]->vht_cap, priv);
if (adapter->config_bands & BAND_A)
mwifiex_setup_ht_caps(
&wiphy->bands[NL80211_BAND_5GHZ]->ht_cap, priv);
if ((adapter->config_bands & BAND_A) && adapter->is_hw_11ac_capable)
mwifiex_setup_vht_caps(
&wiphy->bands[NL80211_BAND_5GHZ]->vht_cap, priv);
for (i = 0; i < wowlan->n_patterns; i++) {
memset(byte_seq, 0, sizeof(byte_seq)); if (!mwifiex_is_pattern_supported(&wowlan->patterns[i],
byte_seq,
MWIFIEX_MEF_MAX_BYTESEQ)) {
mwifiex_dbg(priv->adapter, ERROR, "Pattern not supported\n"); return -EOPNOTSUPP;
}
sta_priv->scan_aborting = true; for (i = 0; i < adapter->priv_num; i++) {
priv = adapter->priv[i];
mwifiex_abort_cac(priv);
}
mwifiex_cancel_all_pending_cmd(adapter);
for (i = 0; i < adapter->priv_num; i++) {
priv = adapter->priv[i]; if (priv->netdev)
netif_device_detach(priv->netdev);
}
for (i = 0; i < retry_num; i++) { if (!mwifiex_wmm_lists_empty(adapter) ||
!mwifiex_bypass_txlist_empty(adapter) ||
!skb_queue_empty(&adapter->tx_data_q))
usleep_range(10000, 15000); else break;
}
if (!wowlan) {
mwifiex_dbg(adapter, INFO, "None of the WOWLAN triggers enabled\n");
ret = 0; goto done;
}
if (!sta_priv->media_connected && !wowlan->nd_config) {
mwifiex_dbg(adapter, ERROR, "Can not configure WOWLAN in disconnected state\n");
ret = 0; goto done;
}
ret = mwifiex_set_mef_filter(sta_priv, wowlan); if (ret) {
mwifiex_dbg(adapter, ERROR, "Failed to set MEF filter\n"); goto done;
}
switch (wakeup_reason.hs_wakeup_reason) { case NO_HSWAKEUP_REASON: break; case BCAST_DATA_MATCHED: break; case MCAST_DATA_MATCHED: break; case UCAST_DATA_MATCHED: break; case MASKTABLE_EVENT_MATCHED: break; case NON_MASKABLE_EVENT_MATCHED: if (wiphy->wowlan_config->disconnect)
wakeup_report.disconnect = true; if (wiphy->wowlan_config->nd_config)
wakeup_report.net_detect = adapter->nd_info; break; case NON_MASKABLE_CONDITION_MATCHED: break; case MAGIC_PATTERN_MATCHED: if (wiphy->wowlan_config->magic_pkt)
wakeup_report.magic_pkt = true; if (wiphy->wowlan_config->n_patterns)
wakeup_report.pattern_idx = 1; break; case GTK_REKEY_FAILURE: if (wiphy->wowlan_config->gtk_rekey_failure)
wakeup_report.gtk_rekey_failure = true; break; default:
report_wakeup_reason = false; break;
}
if (report_wakeup_reason)
cfg80211_report_wowlan_wakeup(&priv->wdev, &wakeup_report,
GFP_KERNEL);
done: if (adapter->nd_info) { for (i = 0 ; i < adapter->nd_info->n_matches ; i++)
kfree(adapter->nd_info->matches[i]);
kfree(adapter->nd_info);
adapter->nd_info = NULL;
}
for (i = 0; i < crule->n_patterns; i++) {
memset(byte_seq, 0, sizeof(byte_seq)); if (!mwifiex_is_pattern_supported(&crule->patterns[i],
byte_seq,
MWIFIEX_COALESCE_MAX_BYTESEQ)) {
mwifiex_dbg(priv->adapter, ERROR, "Pattern not supported\n"); return -EOPNOTSUPP;
}
if (!crule->patterns[i].pkt_offset) {
u8 pkt_type;
memset(&coalesce_cfg, 0, sizeof(coalesce_cfg)); if (!coalesce) {
mwifiex_dbg(adapter, WARN, "Disable coalesce and reset all previous rules\n"); return mwifiex_send_cmd(priv, HostCmd_CMD_COALESCE_CFG,
HostCmd_ACT_GEN_SET, 0,
&coalesce_cfg, true);
}
coalesce_cfg.num_of_rules = coalesce->n_rules; for (i = 0; i < coalesce->n_rules; i++) {
ret = mwifiex_fill_coalesce_rule_info(priv, &coalesce->rules[i],
&coalesce_cfg.rule[i]); if (ret) {
mwifiex_dbg(adapter, ERROR, "Recheck the patterns provided for rule %d\n",
i + 1); return ret;
}
}
if (!(sta_ptr->tdls_cap.extcap.ext_capab[3] &
WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH)) {
spin_unlock_bh(&priv->sta_list_spinlock);
wiphy_err(wiphy, "%pM do not support tdls cs\n", addr); return -ENOENT;
}
if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
mwifiex_dbg(priv->adapter, ERROR, "Interface role is AP\n"); return -EFAULT;
}
if (priv->wdev.iftype != NL80211_IFTYPE_STATION) {
mwifiex_dbg(priv->adapter, ERROR, "Interface type is not correct (type %d)\n",
priv->wdev.iftype); return -EINVAL;
}
if (priv->auth_alg != WLAN_AUTH_SAE &&
(priv->auth_flag & HOST_MLME_AUTH_PENDING)) {
mwifiex_dbg(priv->adapter, ERROR, "Pending auth on going\n"); return -EBUSY;
}
int mwifiex_init_channel_scan_gap(struct mwifiex_adapter *adapter)
{
u32 n_channels_bg, n_channels_a = 0;
n_channels_bg = mwifiex_band_2ghz.n_channels;
if (adapter->config_bands & BAND_A)
n_channels_a = mwifiex_band_5ghz.n_channels;
/* allocate twice the number total channels, since the driver issues an * additional active scan request for hidden SSIDs on passive channels.
*/
adapter->num_in_chan_stats = 2 * (n_channels_bg + n_channels_a);
adapter->chan_stats = kcalloc(adapter->num_in_chan_stats, sizeof(*adapter->chan_stats),
GFP_KERNEL);
if (!adapter->chan_stats) return -ENOMEM;
return0;
}
/* * This function registers the device with CFG802.11 subsystem. * * The function creates the wireless device/wiphy, populates it with * default parameters and handler function pointers, and finally * registers the device.
*/
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.92Bemerkung:
(vorverarbeitet am 2026-06-07)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.