/* * 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. */ static int 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) { wiphy_err(wiphy, "request to join ibss received " "when station is not in ibss mode\n"); goto done; } wiphy_dbg(wiphy, "info: trying to join to %s and bssid %pM\n", (char *) params->ssid, params->bssid); ret = mwifiex_cfg80211_assoc(priv, params->ssid_len, params->ssid, params->bssid, priv->bss_mode, params->channel, NULL, params->privacy); done: if (!ret) { cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, GFP_KERNEL); dev_dbg(priv->adapter->dev, "info: joined/created adhoc network with bssid" " %pM successfully\n", priv->cfg_bssid); } else { dev_dbg(priv->adapter->dev, "info: failed creating/joining adhoc network\n"); } return ret; }
void ath6kl_cfg80211_disconnect_event(struct ath6kl *ar, u8 reason, u8 *bssid, u8 assoc_resp_len, u8 *assoc_info, u16 proto_reason) { if (ar->scan_req) { cfg80211_scan_done(ar->scan_req, true); ar->scan_req = NULL; } if (ar->nw_type & ADHOC_NETWORK) { if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) { ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: ath6k not in ibss mode\n", __func__); return; } memset(bssid, 0, ETH_ALEN); cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL); return; } if (ar->nw_type & INFRA_NETWORK) { if (ar->wdev->iftype != NL80211_IFTYPE_STATION && ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) { ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: ath6k not in station mode\n", __func__); return; } } /* * Send a disconnect command to target when a disconnect event is * received with reason code other than 3 (DISCONNECT_CMD - disconnect * request from host) to make the firmware stop trying to connect even * after giving disconnect event. There will be one more disconnect * event for this disconnect command with reason code DISCONNECT_CMD * which will be notified to cfg80211. */ if (reason != DISCONNECT_CMD) { ath6kl_wmi_disconnect_cmd(ar->wmi); return; } clear_bit(CONNECT_PEND, &ar->flag); if (ar->sme_state == SME_CONNECTING) { cfg80211_connect_result(ar->net_dev, bssid, NULL, 0, NULL, 0, WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_KERNEL); } else if (ar->sme_state == SME_CONNECTED) { cfg80211_disconnected(ar->net_dev, reason, NULL, 0, GFP_KERNEL); } ar->sme_state = SME_DISCONNECTED; }
static void r92su_bss_connect_work(struct work_struct *work) { struct r92su *r92su; struct c2h_join_bss_event *join_bss = NULL; struct cfg80211_bss *cfg_bss = NULL; struct r92su_bss_priv *bss_priv; u8 *resp_ie = NULL; unsigned int resp_ie_len = 0; u16 status = WLAN_STATUS_UNSPECIFIED_FAILURE; r92su = container_of(work, struct r92su, connect_bss_work); mutex_lock(&r92su->lock); if (!r92su_is_open(r92su)) goto out; cfg_bss = r92su->want_connect_bss; join_bss = r92su->connect_result; if (!cfg_bss || !join_bss) goto out; bss_priv = r92su_get_bss_priv(cfg_bss); r92su->connect_result = NULL; if (le32_to_cpu(join_bss->bss.ie_length) < 12) goto report_cfg80211; if (join_bss->join_result) { struct r92su_bss_priv *bss_priv = r92su_get_bss_priv(cfg_bss); struct r92su_sta *sta; sta = r92su_sta_alloc(r92su, join_bss->bss.bssid, BSS_MACID, le32_to_cpu(join_bss->aid), GFP_KERNEL); if (!sta) goto report_cfg80211; resp_ie = join_bss->bss.ies.ie; resp_ie_len = le32_to_cpu(join_bss->bss.ie_length) - 12; sta->enc_sta = le32_to_cpu(join_bss->bss.privacy) ? true : false; sta->qos_sta = r92su_parse_wmm_cap_ie(r92su, resp_ie, resp_ie_len); /* The 802.11-2012 spec says that a HT STA has to be QoS STA * as well. So in theory we should do instead: * sta->qos_sta |= sta->ht_sta; * However, the QoS parameters are needed for legacy STAs as * well. Therefore, there's no excuse for a HT STA to forget * the WMM IE! */ if (sta->qos_sta) sta->ht_sta = r92su_parse_ht_cap_ie(r92su, resp_ie, resp_ie_len); status = WLAN_STATUS_SUCCESS; bss_priv->sta = sta; rcu_assign_pointer(r92su->connect_bss, cfg_bss); r92su->want_connect_bss = NULL; r92su_set_state(r92su, R92SU_CONNECTED); } report_cfg80211: switch (r92su->wdev.iftype) { case NL80211_IFTYPE_STATION: cfg80211_connect_result(r92su->wdev.netdev, join_bss->bss.bssid, bss_priv->assoc_ie, bss_priv->assoc_ie_len, resp_ie, resp_ie_len, status, GFP_KERNEL); if (status == WLAN_STATUS_SUCCESS) r92su_set_power(r92su, true); break; case NL80211_IFTYPE_ADHOC: if (status == WLAN_STATUS_SUCCESS) { cfg80211_ibss_joined(r92su->wdev.netdev, join_bss->bss.bssid, cfg_bss->channel, GFP_KERNEL); } break; default: WARN(1, "unsupported network type %d\n", r92su->wdev.iftype); break; } kfree(bss_priv->assoc_ie); bss_priv->assoc_ie = NULL; out: mutex_unlock(&r92su->lock); kfree(join_bss); if (status == WLAN_STATUS_SUCCESS) { netif_tx_start_all_queues(r92su->wdev.netdev); netif_carrier_on(r92su->wdev.netdev); } else { r92su_bss_free(r92su, cfg_bss); } }
/* * This function handles the result of different pending network operations. * * The following operations are handled and CFG802.11 subsystem is * notified accordingly - * - Scan request completion * - Association request completion * - IBSS join request completion * - Disconnect request completion */ void mwifiex_cfg80211_results(struct work_struct *work) { struct mwifiex_private *priv = container_of(work, struct mwifiex_private, cfg_workqueue); struct mwifiex_user_scan_cfg *scan_req; int ret = 0, i; struct ieee80211_channel *chan; if (priv->scan_request) { scan_req = kzalloc(sizeof(struct mwifiex_user_scan_cfg), GFP_KERNEL); if (!scan_req) { dev_err(priv->adapter->dev, "failed to alloc " "scan_req\n"); return; } for (i = 0; i < priv->scan_request->n_ssids; i++) { memcpy(scan_req->ssid_list[i].ssid, priv->scan_request->ssids[i].ssid, priv->scan_request->ssids[i].ssid_len); scan_req->ssid_list[i].max_len = priv->scan_request->ssids[i].ssid_len; } for (i = 0; i < priv->scan_request->n_channels; i++) { chan = priv->scan_request->channels[i]; scan_req->chan_list[i].chan_number = chan->hw_value; scan_req->chan_list[i].radio_type = chan->band; if (chan->flags & IEEE80211_CHAN_DISABLED) scan_req->chan_list[i].scan_type = MWIFIEX_SCAN_TYPE_PASSIVE; else scan_req->chan_list[i].scan_type = MWIFIEX_SCAN_TYPE_ACTIVE; scan_req->chan_list[i].scan_time = 0; } if (mwifiex_set_user_scan_ioctl(priv, scan_req)) { ret = -EFAULT; goto done; } if (mwifiex_inform_bss_from_scan_result(priv, NULL)) ret = -EFAULT; done: priv->scan_result_status = ret; dev_dbg(priv->adapter->dev, "info: %s: sending scan results\n", __func__); cfg80211_scan_done(priv->scan_request, (priv->scan_result_status < 0)); priv->scan_request = NULL; kfree(scan_req); } if (priv->assoc_request == 1) { if (!priv->assoc_result) { cfg80211_connect_result(priv->netdev, priv->cfg_bssid, NULL, 0, NULL, 0, WLAN_STATUS_SUCCESS, GFP_KERNEL); dev_dbg(priv->adapter->dev, "info: associated to bssid %pM successfully\n", priv->cfg_bssid); } else { dev_dbg(priv->adapter->dev, "info: association to bssid %pM failed\n", priv->cfg_bssid); memset(priv->cfg_bssid, 0, ETH_ALEN); } priv->assoc_request = 0; priv->assoc_result = 0; } if (priv->ibss_join_request == 1) { if (!priv->ibss_join_result) { cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, GFP_KERNEL); dev_dbg(priv->adapter->dev, "info: joined/created adhoc network with bssid" " %pM successfully\n", priv->cfg_bssid); } else { dev_dbg(priv->adapter->dev, "info: failed creating/joining adhoc network\n"); } priv->ibss_join_request = 0; priv->ibss_join_result = 0; } if (priv->disconnect) { memset(priv->cfg_bssid, 0, ETH_ALEN); priv->disconnect = 0; } }
void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel, u8 *bssid, u16 listen_intvl, u16 beacon_intvl, enum network_type nw_type, u8 beacon_ie_len, u8 assoc_req_len, u8 assoc_resp_len, u8 *assoc_info) { struct ieee80211_channel *chan; /* capinfo + listen interval */ u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16); /* capinfo + status code + associd */ u8 assoc_resp_ie_offset = sizeof(u16) + sizeof(u16) + sizeof(u16); u8 *assoc_req_ie = assoc_info + beacon_ie_len + assoc_req_ie_offset; u8 *assoc_resp_ie = assoc_info + beacon_ie_len + assoc_req_len + assoc_resp_ie_offset; assoc_req_len -= assoc_req_ie_offset; assoc_resp_len -= assoc_resp_ie_offset; /* * Store Beacon interval here; DTIM period will be available only once * a Beacon frame from the AP is seen. */ ar->assoc_bss_beacon_int = beacon_intvl; clear_bit(DTIM_PERIOD_AVAIL, &ar->flag); if (nw_type & ADHOC_NETWORK) { if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) { ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: ath6k not in ibss mode\n", __func__); return; } } if (nw_type & INFRA_NETWORK) { if (ar->wdev->iftype != NL80211_IFTYPE_STATION && ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) { ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: ath6k not in station mode\n", __func__); return; } } chan = ieee80211_get_channel(ar->wdev->wiphy, (int) channel); if (nw_type & ADHOC_NETWORK) { cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL); return; } if (ath6kl_add_bss_if_needed(ar, bssid, chan, assoc_info, beacon_ie_len) < 0) { ath6kl_err("could not add cfg80211 bss entry for " "connect/roamed notification\n"); return; } if (ar->sme_state == SME_CONNECTING) { /* inform connect result to cfg80211 */ ar->sme_state = SME_CONNECTED; cfg80211_connect_result(ar->net_dev, bssid, assoc_req_ie, assoc_req_len, assoc_resp_ie, assoc_resp_len, WLAN_STATUS_SUCCESS, GFP_KERNEL); } else if (ar->sme_state == SME_CONNECTED) { /* inform roam event to cfg80211 */ cfg80211_roamed(ar->net_dev, chan, bssid, assoc_req_ie, assoc_req_len, assoc_resp_ie, assoc_resp_len, GFP_KERNEL); } }
static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, const u8 *bssid, const int beacon_int, struct ieee80211_channel *chan, const u32 basic_rates, const u16 capability, u64 tsf) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct ieee80211_local *local = sdata->local; int rates, i; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; u8 *pos; struct ieee80211_supported_band *sband; struct cfg80211_bss *bss; u32 bss_change; u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; enum nl80211_channel_type channel_type; lockdep_assert_held(&ifibss->mtx); /* Reset own TSF to allow time synchronization work. */ drv_reset_tsf(local, sdata); skb = ifibss->skb; RCU_INIT_POINTER(ifibss->presp, NULL); synchronize_rcu(); skb->data = skb->head; skb->len = 0; skb_reset_tail_pointer(skb); skb_reserve(skb, sdata->local->hw.extra_tx_headroom); if (memcmp(ifibss->bssid, bssid, ETH_ALEN)) sta_info_flush(sdata->local, sdata); /* if merging, indicate to driver that we leave the old IBSS */ if (sdata->vif.bss_conf.ibss_joined) { sdata->vif.bss_conf.ibss_joined = false; netif_carrier_off(sdata->dev); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IBSS); } memcpy(ifibss->bssid, bssid, ETH_ALEN); sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0; channel_type = ifibss->channel_type; if (channel_type > NL80211_CHAN_HT20 && !cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type)) channel_type = NL80211_CHAN_HT20; if (!ieee80211_set_channel_type(local, sdata, channel_type)) { /* can only fail due to HT40+/- mismatch */ channel_type = NL80211_CHAN_HT20; WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_HT20)); } ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); sband = local->hw.wiphy->bands[chan->band]; /* build supported rates array */ pos = supp_rates; for (i = 0; i < sband->n_bitrates; i++) { int rate = sband->bitrates[i].bitrate; u8 basic = 0; if (basic_rates & BIT(i)) basic = 0x80; *pos++ = basic | (u8) (rate / 5); } /* Build IBSS probe response */ mgmt = (void *) skb_put(skb, 24 + sizeof(mgmt->u.beacon)); memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP); memset(mgmt->da, 0xff, ETH_ALEN); memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN); mgmt->u.beacon.beacon_int = cpu_to_le16(beacon_int); mgmt->u.beacon.timestamp = cpu_to_le64(tsf); mgmt->u.beacon.capab_info = cpu_to_le16(capability); pos = skb_put(skb, 2 + ifibss->ssid_len); *pos++ = WLAN_EID_SSID; *pos++ = ifibss->ssid_len; memcpy(pos, ifibss->ssid, ifibss->ssid_len); rates = sband->n_bitrates; if (rates > 8) rates = 8; pos = skb_put(skb, 2 + rates); *pos++ = WLAN_EID_SUPP_RATES; *pos++ = rates; memcpy(pos, supp_rates, rates); if (sband->band == IEEE80211_BAND_2GHZ) { pos = skb_put(skb, 2 + 1); *pos++ = WLAN_EID_DS_PARAMS; *pos++ = 1; *pos++ = ieee80211_frequency_to_channel(chan->center_freq); } pos = skb_put(skb, 2 + 2); *pos++ = WLAN_EID_IBSS_PARAMS; *pos++ = 2; /* FIX: set ATIM window based on scan results */ *pos++ = 0; *pos++ = 0; if (sband->n_bitrates > 8) { rates = sband->n_bitrates - 8; pos = skb_put(skb, 2 + rates); *pos++ = WLAN_EID_EXT_SUPP_RATES; *pos++ = rates; memcpy(pos, &supp_rates[8], rates); } if (ifibss->ie_len) memcpy(skb_put(skb, ifibss->ie_len), ifibss->ie, ifibss->ie_len); /* add HT capability and information IEs */ if (channel_type && sband->ht_cap.ht_supported) { pos = skb_put(skb, 4 + sizeof(struct ieee80211_ht_cap) + sizeof(struct ieee80211_ht_info)); pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, sband->ht_cap.cap); pos = ieee80211_ie_build_ht_info(pos, &sband->ht_cap, chan, channel_type); } if (local->hw.queues >= 4) { pos = skb_put(skb, 9); *pos++ = WLAN_EID_VENDOR_SPECIFIC; *pos++ = 7; /* len */ *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ *pos++ = 0x50; *pos++ = 0xf2; *pos++ = 2; /* WME */ *pos++ = 0; /* WME info */ *pos++ = 1; /* WME ver */ *pos++ = 0; /* U-APSD no in use */ } RCU_INIT_POINTER(ifibss->presp, skb); sdata->vif.bss_conf.beacon_int = beacon_int; sdata->vif.bss_conf.basic_rates = basic_rates; bss_change = BSS_CHANGED_BEACON_INT; bss_change |= ieee80211_reset_erp_info(sdata); bss_change |= BSS_CHANGED_BSSID; bss_change |= BSS_CHANGED_BEACON; bss_change |= BSS_CHANGED_BEACON_ENABLED; bss_change |= BSS_CHANGED_BASIC_RATES; bss_change |= BSS_CHANGED_HT; bss_change |= BSS_CHANGED_IBSS; sdata->vif.bss_conf.ibss_joined = true; ieee80211_bss_info_change_notify(sdata, bss_change); ieee80211_sta_def_wmm_params(sdata, sband->n_bitrates, supp_rates); ifibss->state = IEEE80211_IBSS_MLME_JOINED; mod_timer(&ifibss->timer, round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); bss = cfg80211_inform_bss_frame(local->hw.wiphy, local->hw.conf.channel, mgmt, skb->len, 0, GFP_KERNEL); cfg80211_put_bss(bss); netif_carrier_on(sdata->dev); cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL); }