diff --git a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c index d33d2cdd3151..198f0cc1ebe7 100644 --- a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c @@ -40,269 +40,19 @@ static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255}; static u32 brcmf_dbg_level = WL_DBG_ERR; -/* -** cfg80211_ops api/callback list -*/ -static s32 brcmf_cfg80211_change_iface(struct wiphy *wiphy, - struct net_device *ndev, - enum nl80211_iftype type, u32 *flags, - struct vif_params *params); -static s32 __brcmf_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, - struct cfg80211_scan_request *request, - struct cfg80211_ssid *this_ssid); -static s32 brcmf_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, - struct cfg80211_scan_request *request); -static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed); -static s32 brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_ibss_params *params); -static s32 brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, - struct net_device *dev); -static s32 brcmf_cfg80211_get_station(struct wiphy *wiphy, - struct net_device *dev, u8 *mac, - struct station_info *sinfo); -static s32 brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, - struct net_device *dev, bool enabled, - s32 timeout); -static s32 brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, - struct net_device *dev, - const u8 *addr, - const struct cfg80211_bitrate_mask - *mask); -static int brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_connect_params *sme); -static s32 brcmf_cfg80211_disconnect(struct wiphy *wiphy, - struct net_device *dev, - u16 reason_code); -static s32 brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, - enum nl80211_tx_power_setting type, - s32 dbm); -static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm); -static s32 brcmf_cfg80211_config_default_key(struct wiphy *wiphy, - struct net_device *dev, u8 key_idx, - bool unicast, bool multicast); -static s32 brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_idx, bool pairwise, const u8 *mac_addr, - struct key_params *params); -static s32 brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_idx, bool pairwise, const u8 *mac_addr); -static s32 brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_idx, bool pairwise, const u8 *mac_addr, - void *cookie, void (*callback) (void *cookie, - struct - key_params * - params)); -static s32 brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, - struct net_device *dev, - u8 key_idx); -static s32 brcmf_cfg80211_resume(struct wiphy *wiphy); -static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy, - struct cfg80211_wowlan *wow); -static s32 brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_pmksa *pmksa); -static s32 brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_pmksa *pmksa); -static s32 brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, - struct net_device *dev); -/* -** event & event Q handlers for cfg80211 interfaces -*/ -static s32 brcmf_create_event_handler(struct brcmf_cfg80211_priv *cfg_priv); -static void brcmf_destroy_event_handler(struct brcmf_cfg80211_priv *cfg_priv); -static s32 brcmf_event_handler(void *data); -static void brcmf_init_eq(struct brcmf_cfg80211_priv *cfg_priv); -static void brcmf_flush_eq(struct brcmf_cfg80211_priv *cfg_priv); -static void brcmf_lock_eq(struct brcmf_cfg80211_priv *cfg_priv); -static void brcmf_unlock_eq(struct brcmf_cfg80211_priv *cfg_priv); -static void brcmf_init_eq_lock(struct brcmf_cfg80211_priv *cfg_priv); -static void brcmf_init_eloop_handler(struct brcmf_cfg80211_event_loop *el); -static struct brcmf_cfg80211_event_q * -brcmf_deq_event(struct brcmf_cfg80211_priv *cfg_priv); -static s32 brcmf_enq_event(struct brcmf_cfg80211_priv *cfg_priv, u32 type, - const struct brcmf_event_msg *msg); -static void brcmf_put_event(struct brcmf_cfg80211_event_q *e); -static void brcmf_wakeup_event(struct brcmf_cfg80211_priv *cfg_priv); -static s32 brcmf_notify_connect_status(struct brcmf_cfg80211_priv *cfg_priv, - struct net_device *ndev, - const struct brcmf_event_msg *e, - void *data); -static s32 brcmf_notify_roaming_status(struct brcmf_cfg80211_priv *cfg_priv, - struct net_device *ndev, - const struct brcmf_event_msg *e, - void *data); -static s32 brcmf_notify_scan_status(struct brcmf_cfg80211_priv *cfg_priv, - struct net_device *ndev, - const struct brcmf_event_msg *e, - void *data); -static s32 brcmf_bss_connect_done(struct brcmf_cfg80211_priv *cfg_priv, - struct net_device *ndev, - const struct brcmf_event_msg *e, - bool completed); -static s32 brcmf_bss_roaming_done(struct brcmf_cfg80211_priv *cfg_priv, - struct net_device *ndev, - const struct brcmf_event_msg *e); -static s32 brcmf_notify_mic_status(struct brcmf_cfg80211_priv *cfg_priv, - struct net_device *ndev, - const struct brcmf_event_msg *e, void *data); +static void brcmf_set_drvdata(struct brcmf_cfg80211_dev *dev, void *data) +{ + dev->driver_data = data; +} -/* -** ioctl utilites -*/ -static s32 brcmf_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf, - s32 buf_len); -static __used s32 brcmf_dev_bufvar_set(struct net_device *dev, s8 *name, - s8 *buf, s32 len); -static s32 brcmf_dev_intvar_set(struct net_device *dev, s8 *name, s32 val); -static s32 brcmf_dev_intvar_get(struct net_device *dev, s8 *name, - s32 *retval); -static s32 brcmf_dev_ioctl(struct net_device *dev, u32 cmd, void *arg, - u32 len); +static void *brcmf_get_drvdata(struct brcmf_cfg80211_dev *dev) +{ + void *data = NULL; -/* -** cfg80211 set_wiphy_params utilities -*/ -static s32 brcmf_set_frag(struct net_device *dev, u32 frag_threshold); -static s32 brcmf_set_rts(struct net_device *dev, u32 frag_threshold); -static s32 brcmf_set_retry(struct net_device *dev, u32 retry, bool l); - -/* -** wl profile utilities -*/ -static s32 brcmf_update_prof(struct brcmf_cfg80211_priv *cfg_priv, - const struct brcmf_event_msg *e, - void *data, s32 item); -static void *brcmf_read_prof(struct brcmf_cfg80211_priv *cfg_priv, s32 item); -static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof); - -/* -** cfg80211 connect utilites -*/ -static s32 brcmf_set_wpa_version(struct net_device *dev, - struct cfg80211_connect_params *sme); -static s32 brcmf_set_auth_type(struct net_device *dev, - struct cfg80211_connect_params *sme); -static s32 brcmf_set_set_cipher(struct net_device *dev, - struct cfg80211_connect_params *sme); -static s32 brcmf_set_key_mgmt(struct net_device *dev, - struct cfg80211_connect_params *sme); -static s32 brcmf_set_set_sharedkey(struct net_device *dev, - struct cfg80211_connect_params *sme); -static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv); -static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv); -static void brcmf_ch_to_chanspec(int ch, - struct brcmf_join_params *join_params, size_t *join_params_size); - -/* -** information element utilities -*/ -static __used s32 brcmf_add_ie(struct brcmf_cfg80211_priv *cfg_priv, - u8 t, u8 l, u8 *v); -static s32 brcmf_mode_to_nl80211_iftype(s32 mode); -static struct wireless_dev *brcmf_alloc_wdev(s32 sizeof_iface, - struct device *dev); -static void brcmf_free_wdev(struct brcmf_cfg80211_priv *cfg_priv); -static s32 brcmf_inform_bss(struct brcmf_cfg80211_priv *cfg_priv); -static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_priv *cfg_priv, - struct brcmf_bss_info *bi); -static s32 brcmf_update_bss_info(struct brcmf_cfg80211_priv *cfg_priv); -static s32 brcmf_add_keyext(struct wiphy *wiphy, struct net_device *dev, - u8 key_idx, const u8 *mac_addr, - struct key_params *params); - -/* -** key indianess swap utilities -*/ -static void convert_key_from_CPU(struct brcmf_wsec_key *key); -static void convert_key_to_CPU(struct brcmf_wsec_key *key); - -/* -** brcmf_cfg80211_priv memory init/deinit utilities -*/ -static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_priv *cfg_priv); -static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_priv *cfg_priv); - -static void brcmf_delay(u32 ms); - -/* -** store/restore cfg80211 instance data -*/ -static void brcmf_set_drvdata(struct brcmf_cfg80211_dev *dev, void *data); -static void *brcmf_get_drvdata(struct brcmf_cfg80211_dev *dev); - -/* -** ibss mode utilities -*/ -static bool brcmf_is_ibssmode(struct brcmf_cfg80211_priv *cfg_priv); - -/* -** dongle up/down , default configuration utilities -*/ -static bool brcmf_is_linkdown(struct brcmf_cfg80211_priv *cfg_priv, - const struct brcmf_event_msg *e); -static bool brcmf_is_linkup(struct brcmf_cfg80211_priv *cfg_priv, - const struct brcmf_event_msg *e); -static bool brcmf_is_nonetwork(struct brcmf_cfg80211_priv *cfg_priv, - const struct brcmf_event_msg *e); -static void brcmf_link_down(struct brcmf_cfg80211_priv *cfg_priv); -static s32 brcmf_dongle_mode(struct net_device *ndev, s32 iftype); -static s32 __brcmf_cfg80211_up(struct brcmf_cfg80211_priv *cfg_priv); -static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_priv *cfg_priv); -static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_priv *cfg_priv); -static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf); - -/* -** dongle configuration utilities -*/ -static s32 brcmf_dongle_eventmsg(struct net_device *ndev); -static s32 brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, - s32 scan_unassoc_time, s32 scan_passive_time); -static s32 brcmf_config_dongle(struct brcmf_cfg80211_priv *cfg_priv, - bool need_lock); -static s32 brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, - u32 bcn_timeout); - -/* -** iscan handler -*/ -static void brcmf_iscan_timer(unsigned long data); -static void brcmf_term_iscan(struct brcmf_cfg80211_priv *cfg_priv); -static s32 brcmf_init_iscan(struct brcmf_cfg80211_priv *cfg_priv); -static s32 brcmf_dev_iovar_setbuf(struct net_device *dev, s8 *iovar, - void *param, s32 paramlen, void *bufptr, - s32 buflen); -static s32 brcmf_dev_iovar_getbuf(struct net_device *dev, s8 *iovar, - void *param, s32 paramlen, void *bufptr, - s32 buflen); -static s32 brcmf_run_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan, - struct brcmf_ssid *ssid, u16 action); -static s32 brcmf_do_iscan(struct brcmf_cfg80211_priv *cfg_priv); -static s32 brcmf_wakeup_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan); -static s32 brcmf_invoke_iscan(struct brcmf_cfg80211_priv *cfg_priv); -static s32 brcmf_get_iscan_results(struct brcmf_cfg80211_iscan_ctrl *iscan, - u32 *status, - struct brcmf_scan_results **bss_list); -static void brcmf_notify_iscan_complete(struct brcmf_cfg80211_iscan_ctrl *iscan, - bool aborted); -static void brcmf_init_iscan_eloop(struct brcmf_cfg80211_iscan_eloop *el); -static s32 brcmf_iscan_done(struct brcmf_cfg80211_priv *cfg_priv); -static s32 brcmf_iscan_pending(struct brcmf_cfg80211_priv *cfg_priv); -static s32 brcmf_iscan_inprogress(struct brcmf_cfg80211_priv *cfg_priv); -static s32 brcmf_iscan_aborted(struct brcmf_cfg80211_priv *cfg_priv); - -/* -* update pmklist to dongle -*/ -static __used s32 brcmf_update_pmklist(struct net_device *dev, - struct brcmf_cfg80211_pmk_list *pmk_list, - s32 err); - -static void brcmf_set_mpc(struct net_device *ndev, int mpc); - -/* -* debufs support -*/ -static int -brcmf_debugfs_add_netdev_params(struct brcmf_cfg80211_priv *cfg_priv); -static void brcmf_debugfs_remove_netdev(struct brcmf_cfg80211_priv *cfg_priv); + if (dev) + data = dev->driver_data; + return data; +} static struct brcmf_cfg80211_priv *brcmf_priv_get(struct brcmf_cfg80211_dev *cfg_dev) @@ -594,6 +344,63 @@ done: return err; } +static s32 brcmf_dev_intvar_set(struct net_device *dev, s8 *name, s32 val) +{ + s8 buf[BRCMF_C_IOCTL_SMLEN]; + u32 len; + s32 err = 0; + + val = cpu_to_le32(val); + len = brcmu_mkiovar(name, (char *)(&val), sizeof(val), buf, + sizeof(buf)); + BUG_ON(!len); + + err = brcmf_dev_ioctl(dev, BRCMF_C_SET_VAR, buf, len); + if (unlikely(err)) + WL_ERR("error (%d)\n", err); + + return err; +} + +static s32 +brcmf_dev_intvar_get(struct net_device *dev, s8 *name, s32 *retval) +{ + union { + s8 buf[BRCMF_C_IOCTL_SMLEN]; + s32 val; + } var; + u32 len; + u32 data_null; + s32 err = 0; + + len = + brcmu_mkiovar(name, (char *)(&data_null), 0, (char *)(&var), + sizeof(var.buf)); + BUG_ON(!len); + err = brcmf_dev_ioctl(dev, BRCMF_C_GET_VAR, &var, len); + if (unlikely(err)) + WL_ERR("error (%d)\n", err); + + *retval = le32_to_cpu(var.val); + + return err; +} + +static void brcmf_set_mpc(struct net_device *ndev, int mpc) +{ + s32 err = 0; + struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); + + if (test_bit(WL_STATUS_READY, &cfg_priv->status)) { + err = brcmf_dev_intvar_set(ndev, "mpc", mpc); + if (unlikely(err)) { + WL_ERR("fail to set mpc\n"); + return; + } + WL_INFO("MPC : %d\n", mpc); + } +} + static void wl_iscan_prep(struct brcmf_scan_params *params, struct brcmf_ssid *ssid) { @@ -820,48 +627,6 @@ brcmf_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, return err; } -static s32 brcmf_dev_intvar_set(struct net_device *dev, s8 *name, s32 val) -{ - s8 buf[BRCMF_C_IOCTL_SMLEN]; - u32 len; - s32 err = 0; - - val = cpu_to_le32(val); - len = brcmu_mkiovar(name, (char *)(&val), sizeof(val), buf, - sizeof(buf)); - BUG_ON(!len); - - err = brcmf_dev_ioctl(dev, BRCMF_C_SET_VAR, buf, len); - if (unlikely(err)) - WL_ERR("error (%d)\n", err); - - return err; -} - -static s32 -brcmf_dev_intvar_get(struct net_device *dev, s8 *name, s32 *retval) -{ - union { - s8 buf[BRCMF_C_IOCTL_SMLEN]; - s32 val; - } var; - u32 len; - u32 data_null; - s32 err = 0; - - len = - brcmu_mkiovar(name, (char *)(&data_null), 0, (char *)(&var), - sizeof(var.buf)); - BUG_ON(!len); - err = brcmf_dev_ioctl(dev, BRCMF_C_GET_VAR, &var, len); - if (unlikely(err)) - WL_ERR("error (%d)\n", err); - - *retval = le32_to_cpu(var.val); - - return err; -} - static s32 brcmf_set_rts(struct net_device *dev, u32 rts_threshold) { s32 err = 0; @@ -942,6 +707,118 @@ done: return err; } +static void *brcmf_read_prof(struct brcmf_cfg80211_priv *cfg_priv, s32 item) +{ + switch (item) { + case WL_PROF_SEC: + return &cfg_priv->profile->sec; + case WL_PROF_BSSID: + return &cfg_priv->profile->bssid; + case WL_PROF_SSID: + return &cfg_priv->profile->ssid; + } + WL_ERR("invalid item (%d)\n", item); + return NULL; +} + +static s32 +brcmf_update_prof(struct brcmf_cfg80211_priv *cfg_priv, + const struct brcmf_event_msg *e, void *data, s32 item) +{ + s32 err = 0; + struct brcmf_ssid *ssid; + + switch (item) { + case WL_PROF_SSID: + ssid = (struct brcmf_ssid *) data; + memset(cfg_priv->profile->ssid.SSID, 0, + sizeof(cfg_priv->profile->ssid.SSID)); + memcpy(cfg_priv->profile->ssid.SSID, + ssid->SSID, ssid->SSID_len); + cfg_priv->profile->ssid.SSID_len = ssid->SSID_len; + break; + case WL_PROF_BSSID: + if (data) + memcpy(cfg_priv->profile->bssid, data, ETH_ALEN); + else + memset(cfg_priv->profile->bssid, 0, ETH_ALEN); + break; + case WL_PROF_SEC: + memcpy(&cfg_priv->profile->sec, data, + sizeof(cfg_priv->profile->sec)); + break; + case WL_PROF_BEACONINT: + cfg_priv->profile->beacon_interval = *(u16 *)data; + break; + case WL_PROF_DTIMPERIOD: + cfg_priv->profile->dtim_period = *(u8 *)data; + break; + default: + WL_ERR("unsupported item (%d)\n", item); + err = -EOPNOTSUPP; + break; + } + + return err; +} + +static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof) +{ + memset(prof, 0, sizeof(*prof)); +} + +static void brcmf_ch_to_chanspec(int ch, struct brcmf_join_params *join_params, + size_t *join_params_size) +{ + u16 chanspec = 0; + + if (ch != 0) { + join_params->params.chanspec_num = 1; + join_params->params.chanspec_list[0] = ch; + + if (join_params->params.chanspec_list[0] <= CH_MAX_2G_CHANNEL) + chanspec |= WL_CHANSPEC_BAND_2G; + else + chanspec |= WL_CHANSPEC_BAND_5G; + + chanspec |= WL_CHANSPEC_BW_20; + chanspec |= WL_CHANSPEC_CTL_SB_NONE; + + *join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE + + join_params->params.chanspec_num * sizeof(u16); + + join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK; + join_params->params.chanspec_list[0] |= chanspec; + join_params->params.chanspec_list[0] = + cpu_to_le16(join_params->params.chanspec_list[0]); + + join_params->params.chanspec_num = + cpu_to_le32(join_params->params.chanspec_num); + + WL_CONN("join_params->params.chanspec_list[0]= %#X," + "channel %d, chanspec %#X\n", + join_params->params.chanspec_list[0], ch, chanspec); + } +} + +static void brcmf_link_down(struct brcmf_cfg80211_priv *cfg_priv) +{ + struct net_device *dev = NULL; + s32 err = 0; + + WL_TRACE("Enter\n"); + + if (cfg_priv->link_up) { + dev = cfg_to_ndev(cfg_priv); + WL_INFO("Call WLC_DISASSOC to stop excess roaming\n "); + err = brcmf_dev_ioctl(dev, BRCMF_C_DISASSOC, NULL, 0); + if (unlikely(err)) + WL_ERR("WLC_DISASSOC failed (%d)\n", err); + cfg_priv->link_up = false; + } + WL_TRACE("Exit\n"); +} + static s32 brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ibss_params *params) @@ -2071,6 +1948,463 @@ done: return err; } +static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_priv *cfg_priv, + struct brcmf_bss_info *bi) +{ + struct wiphy *wiphy = cfg_to_wiphy(cfg_priv); + struct ieee80211_channel *notify_channel; + struct cfg80211_bss *bss; + struct ieee80211_supported_band *band; + s32 err = 0; + u16 channel; + u32 freq; + u64 notify_timestamp; + u16 notify_capability; + u16 notify_interval; + u8 *notify_ie; + size_t notify_ielen; + s32 notify_signal; + + if (unlikely(le32_to_cpu(bi->length) > WL_BSS_INFO_MAX)) { + WL_ERR("Bss info is larger than buffer. Discarding\n"); + return 0; + } + + channel = bi->ctl_ch ? bi->ctl_ch : + CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec)); + + if (channel <= CH_MAX_2G_CHANNEL) + band = wiphy->bands[IEEE80211_BAND_2GHZ]; + else + band = wiphy->bands[IEEE80211_BAND_5GHZ]; + + freq = ieee80211_channel_to_frequency(channel, band->band); + notify_channel = ieee80211_get_channel(wiphy, freq); + + notify_timestamp = jiffies_to_msecs(jiffies)*1000; /* uSec */ + notify_capability = le16_to_cpu(bi->capability); + notify_interval = le16_to_cpu(bi->beacon_period); + notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset); + notify_ielen = le16_to_cpu(bi->ie_length); + notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100; + + WL_CONN("bssid: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", + bi->BSSID[0], bi->BSSID[1], bi->BSSID[2], + bi->BSSID[3], bi->BSSID[4], bi->BSSID[5]); + WL_CONN("Channel: %d(%d)\n", channel, freq); + WL_CONN("Capability: %X\n", notify_capability); + WL_CONN("Beacon interval: %d\n", notify_interval); + WL_CONN("Signal: %d\n", notify_signal); + WL_CONN("notify_timestamp: %#018llx\n", notify_timestamp); + + bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID, + notify_timestamp, notify_capability, notify_interval, notify_ie, + notify_ielen, notify_signal, GFP_KERNEL); + + if (unlikely(!bss)) { + WL_ERR("cfg80211_inform_bss_frame error\n"); + return -EINVAL; + } + + return err; +} + +static s32 brcmf_inform_bss(struct brcmf_cfg80211_priv *cfg_priv) +{ + struct brcmf_scan_results *bss_list; + struct brcmf_bss_info *bi = NULL; /* must be initialized */ + s32 err = 0; + int i; + + bss_list = cfg_priv->bss_list; + if (unlikely(bss_list->version != BRCMF_BSS_INFO_VERSION)) { + WL_ERR("Version %d != WL_BSS_INFO_VERSION\n", + bss_list->version); + return -EOPNOTSUPP; + } + WL_SCAN("scanned AP count (%d)\n", bss_list->count); + bi = next_bss(bss_list, bi); + for_each_bss(bss_list, bi, i) { + err = brcmf_inform_single_bss(cfg_priv, bi); + if (unlikely(err)) + break; + } + return err; +} + +static s32 wl_inform_ibss(struct brcmf_cfg80211_priv *cfg_priv, + struct net_device *dev, const u8 *bssid) +{ + struct wiphy *wiphy = cfg_to_wiphy(cfg_priv); + struct ieee80211_channel *notify_channel; + struct brcmf_bss_info *bi = NULL; + struct ieee80211_supported_band *band; + u8 *buf = NULL; + s32 err = 0; + u16 channel; + u32 freq; + u64 notify_timestamp; + u16 notify_capability; + u16 notify_interval; + u8 *notify_ie; + size_t notify_ielen; + s32 notify_signal; + + WL_TRACE("Enter\n"); + + buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); + if (buf == NULL) { + WL_ERR("kzalloc() failed\n"); + err = -ENOMEM; + goto CleanUp; + } + + *(u32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX); + + err = brcmf_dev_ioctl(dev, BRCMF_C_GET_BSS_INFO, buf, WL_BSS_INFO_MAX); + if (unlikely(err)) { + WL_ERR("WLC_GET_BSS_INFO failed: %d\n", err); + goto CleanUp; + } + + bi = (struct brcmf_bss_info *)(buf + 4); + + channel = bi->ctl_ch ? bi->ctl_ch : + CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec)); + + if (channel <= CH_MAX_2G_CHANNEL) + band = wiphy->bands[IEEE80211_BAND_2GHZ]; + else + band = wiphy->bands[IEEE80211_BAND_5GHZ]; + + freq = ieee80211_channel_to_frequency(channel, band->band); + notify_channel = ieee80211_get_channel(wiphy, freq); + + notify_timestamp = jiffies_to_msecs(jiffies)*1000; /* uSec */ + notify_capability = le16_to_cpu(bi->capability); + notify_interval = le16_to_cpu(bi->beacon_period); + notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset); + notify_ielen = le16_to_cpu(bi->ie_length); + notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100; + + WL_CONN("channel: %d(%d)\n", channel, freq); + WL_CONN("capability: %X\n", notify_capability); + WL_CONN("beacon interval: %d\n", notify_interval); + WL_CONN("signal: %d\n", notify_signal); + WL_CONN("notify_timestamp: %#018llx\n", notify_timestamp); + + cfg80211_inform_bss(wiphy, notify_channel, bssid, + notify_timestamp, notify_capability, notify_interval, + notify_ie, notify_ielen, notify_signal, GFP_KERNEL); + +CleanUp: + + kfree(buf); + + WL_TRACE("Exit\n"); + + return err; +} + +static bool brcmf_is_ibssmode(struct brcmf_cfg80211_priv *cfg_priv) +{ + return cfg_priv->conf->mode == WL_MODE_IBSS; +} + +static s32 brcmf_update_bss_info(struct brcmf_cfg80211_priv *cfg_priv) +{ + struct brcmf_bss_info *bi; + struct brcmf_ssid *ssid; + struct brcmu_tlv *tim; + u16 beacon_interval; + u8 dtim_period; + size_t ie_len; + u8 *ie; + s32 err = 0; + + WL_TRACE("Enter\n"); + if (brcmf_is_ibssmode(cfg_priv)) + return err; + + ssid = (struct brcmf_ssid *)brcmf_read_prof(cfg_priv, WL_PROF_SSID); + + *(u32 *)cfg_priv->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX); + err = brcmf_dev_ioctl(cfg_to_ndev(cfg_priv), BRCMF_C_GET_BSS_INFO, + cfg_priv->extra_buf, WL_EXTRA_BUF_MAX); + if (unlikely(err)) { + WL_ERR("Could not get bss info %d\n", err); + goto update_bss_info_out; + } + + bi = (struct brcmf_bss_info *)(cfg_priv->extra_buf + 4); + err = brcmf_inform_single_bss(cfg_priv, bi); + if (unlikely(err)) + goto update_bss_info_out; + + ie = ((u8 *)bi) + bi->ie_offset; + ie_len = bi->ie_length; + beacon_interval = cpu_to_le16(bi->beacon_period); + + tim = brcmu_parse_tlvs(ie, ie_len, WLAN_EID_TIM); + if (tim) + dtim_period = tim->data[1]; + else { + /* + * active scan was done so we could not get dtim + * information out of probe response. + * so we speficially query dtim information to dongle. + */ + u32 var; + err = brcmf_dev_intvar_get(cfg_to_ndev(cfg_priv), + "dtim_assoc", &var); + if (unlikely(err)) { + WL_ERR("wl dtim_assoc failed (%d)\n", err); + goto update_bss_info_out; + } + dtim_period = (u8)var; + } + + brcmf_update_prof(cfg_priv, NULL, &beacon_interval, WL_PROF_BEACONINT); + brcmf_update_prof(cfg_priv, NULL, &dtim_period, WL_PROF_DTIMPERIOD); + +update_bss_info_out: + WL_TRACE("Exit"); + return err; +} + +static void brcmf_term_iscan(struct brcmf_cfg80211_priv *cfg_priv) +{ + struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv); + struct brcmf_ssid ssid; + + if (cfg_priv->iscan_on) { + iscan->state = WL_ISCAN_STATE_IDLE; + + if (iscan->timer_on) { + del_timer_sync(&iscan->timer); + iscan->timer_on = 0; + } + + cancel_work_sync(&iscan->work); + + /* Abort iscan running in FW */ + memset(&ssid, 0, sizeof(ssid)); + brcmf_run_iscan(iscan, &ssid, WL_SCAN_ACTION_ABORT); + } +} + +static void brcmf_notify_iscan_complete(struct brcmf_cfg80211_iscan_ctrl *iscan, + bool aborted) +{ + struct brcmf_cfg80211_priv *cfg_priv = iscan_to_cfg(iscan); + struct net_device *ndev = cfg_to_ndev(cfg_priv); + + if (unlikely(!test_and_clear_bit(WL_STATUS_SCANNING, + &cfg_priv->status))) { + WL_ERR("Scan complete while device not scanning\n"); + return; + } + if (likely(cfg_priv->scan_request)) { + WL_SCAN("ISCAN Completed scan: %s\n", + aborted ? "Aborted" : "Done"); + cfg80211_scan_done(cfg_priv->scan_request, aborted); + brcmf_set_mpc(ndev, 1); + cfg_priv->scan_request = NULL; + } + cfg_priv->iscan_kickstart = false; +} + +static s32 brcmf_wakeup_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan) +{ + if (likely(iscan->state != WL_ISCAN_STATE_IDLE)) { + WL_SCAN("wake up iscan\n"); + schedule_work(&iscan->work); + return 0; + } + + return -EIO; +} + +static s32 +brcmf_get_iscan_results(struct brcmf_cfg80211_iscan_ctrl *iscan, u32 *status, + struct brcmf_scan_results **bss_list) +{ + struct brcmf_iscan_results list; + struct brcmf_scan_results *results; + struct brcmf_iscan_results *list_buf; + s32 err = 0; + + memset(iscan->scan_buf, 0, WL_ISCAN_BUF_MAX); + list_buf = (struct brcmf_iscan_results *)iscan->scan_buf; + results = &list_buf->results; + results->buflen = BRCMF_ISCAN_RESULTS_FIXED_SIZE; + results->version = 0; + results->count = 0; + + memset(&list, 0, sizeof(list)); + list.results.buflen = cpu_to_le32(WL_ISCAN_BUF_MAX); + err = brcmf_dev_iovar_getbuf(iscan->dev, "iscanresults", &list, + BRCMF_ISCAN_RESULTS_FIXED_SIZE, iscan->scan_buf, + WL_ISCAN_BUF_MAX); + if (unlikely(err)) { + WL_ERR("error (%d)\n", err); + return err; + } + results->buflen = le32_to_cpu(results->buflen); + results->version = le32_to_cpu(results->version); + results->count = le32_to_cpu(results->count); + WL_SCAN("results->count = %d\n", results->count); + WL_SCAN("results->buflen = %d\n", results->buflen); + *status = le32_to_cpu(list_buf->status); + WL_SCAN("status = %d\n", *status); + *bss_list = results; + + return err; +} + +static s32 brcmf_iscan_done(struct brcmf_cfg80211_priv *cfg_priv) +{ + struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan; + s32 err = 0; + + iscan->state = WL_ISCAN_STATE_IDLE; + rtnl_lock(); + brcmf_inform_bss(cfg_priv); + brcmf_notify_iscan_complete(iscan, false); + rtnl_unlock(); + + return err; +} + +static s32 brcmf_iscan_pending(struct brcmf_cfg80211_priv *cfg_priv) +{ + struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan; + s32 err = 0; + + /* Reschedule the timer */ + mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); + iscan->timer_on = 1; + + return err; +} + +static s32 brcmf_iscan_inprogress(struct brcmf_cfg80211_priv *cfg_priv) +{ + struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan; + s32 err = 0; + + rtnl_lock(); + brcmf_inform_bss(cfg_priv); + brcmf_run_iscan(iscan, NULL, BRCMF_SCAN_ACTION_CONTINUE); + rtnl_unlock(); + /* Reschedule the timer */ + mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); + iscan->timer_on = 1; + + return err; +} + +static s32 brcmf_iscan_aborted(struct brcmf_cfg80211_priv *cfg_priv) +{ + struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan; + s32 err = 0; + + iscan->state = WL_ISCAN_STATE_IDLE; + rtnl_lock(); + brcmf_notify_iscan_complete(iscan, true); + rtnl_unlock(); + + return err; +} + +static void brcmf_cfg80211_iscan_handler(struct work_struct *work) +{ + struct brcmf_cfg80211_iscan_ctrl *iscan = + container_of(work, struct brcmf_cfg80211_iscan_ctrl, + work); + struct brcmf_cfg80211_priv *cfg_priv = iscan_to_cfg(iscan); + struct brcmf_cfg80211_iscan_eloop *el = &iscan->el; + u32 status = BRCMF_SCAN_RESULTS_PARTIAL; + + if (iscan->timer_on) { + del_timer_sync(&iscan->timer); + iscan->timer_on = 0; + } + + rtnl_lock(); + if (brcmf_get_iscan_results(iscan, &status, &cfg_priv->bss_list)) { + status = BRCMF_SCAN_RESULTS_ABORTED; + WL_ERR("Abort iscan\n"); + } + rtnl_unlock(); + + el->handler[status](cfg_priv); +} + +static void brcmf_iscan_timer(unsigned long data) +{ + struct brcmf_cfg80211_iscan_ctrl *iscan = + (struct brcmf_cfg80211_iscan_ctrl *)data; + + if (iscan) { + iscan->timer_on = 0; + WL_SCAN("timer expired\n"); + brcmf_wakeup_iscan(iscan); + } +} + +static s32 brcmf_invoke_iscan(struct brcmf_cfg80211_priv *cfg_priv) +{ + struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv); + + if (cfg_priv->iscan_on) { + iscan->state = WL_ISCAN_STATE_IDLE; + INIT_WORK(&iscan->work, brcmf_cfg80211_iscan_handler); + } + + return 0; +} + +static void brcmf_init_iscan_eloop(struct brcmf_cfg80211_iscan_eloop *el) +{ + memset(el, 0, sizeof(*el)); + el->handler[BRCMF_SCAN_RESULTS_SUCCESS] = brcmf_iscan_done; + el->handler[BRCMF_SCAN_RESULTS_PARTIAL] = brcmf_iscan_inprogress; + el->handler[BRCMF_SCAN_RESULTS_PENDING] = brcmf_iscan_pending; + el->handler[BRCMF_SCAN_RESULTS_ABORTED] = brcmf_iscan_aborted; + el->handler[BRCMF_SCAN_RESULTS_NO_MEM] = brcmf_iscan_aborted; +} + +static s32 brcmf_init_iscan(struct brcmf_cfg80211_priv *cfg_priv) +{ + struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv); + int err = 0; + + if (cfg_priv->iscan_on) { + iscan->dev = cfg_to_ndev(cfg_priv); + brcmf_init_iscan_eloop(&iscan->el); + iscan->timer_ms = WL_ISCAN_TIMER_INTERVAL_MS; + init_timer(&iscan->timer); + iscan->timer.data = (unsigned long) iscan; + iscan->timer.function = brcmf_iscan_timer; + err = brcmf_invoke_iscan(cfg_priv); + if (!err) + iscan->data = cfg_priv; + } + + return err; +} + +static void brcmf_delay(u32 ms) +{ + if (ms < 1000 / HZ) { + cond_resched(); + mdelay(ms); + } else { + msleep(ms); + } +} + static s32 brcmf_cfg80211_resume(struct wiphy *wiphy) { struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); @@ -2148,6 +2482,42 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy, return 0; } +static __used s32 +brcmf_dev_bufvar_set(struct net_device *dev, s8 *name, s8 *buf, s32 len) +{ + struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(dev); + u32 buflen; + + buflen = brcmu_mkiovar(name, buf, len, cfg_priv->ioctl_buf, + WL_IOCTL_LEN_MAX); + BUG_ON(!buflen); + + return brcmf_dev_ioctl(dev, BRCMF_C_SET_VAR, cfg_priv->ioctl_buf, + buflen); +} + +static s32 +brcmf_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf, + s32 buf_len) +{ + struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(dev); + u32 len; + s32 err = 0; + + len = brcmu_mkiovar(name, NULL, 0, cfg_priv->ioctl_buf, + WL_IOCTL_LEN_MAX); + BUG_ON(!len); + err = brcmf_dev_ioctl(dev, BRCMF_C_GET_VAR, (void *)cfg_priv->ioctl_buf, + WL_IOCTL_LEN_MAX); + if (unlikely(err)) { + WL_ERR("error (%d)\n", err); + return err; + } + memcpy(buf, cfg_priv->ioctl_buf, buf_len); + + return err; +} + static __used s32 brcmf_update_pmklist(struct net_device *dev, struct brcmf_cfg80211_pmk_list *pmk_list, s32 err) @@ -2382,165 +2752,6 @@ static void brcmf_free_wdev(struct brcmf_cfg80211_priv *cfg_priv) cfg_priv->wdev = NULL; } -static s32 brcmf_inform_bss(struct brcmf_cfg80211_priv *cfg_priv) -{ - struct brcmf_scan_results *bss_list; - struct brcmf_bss_info *bi = NULL; /* must be initialized */ - s32 err = 0; - int i; - - bss_list = cfg_priv->bss_list; - if (unlikely(bss_list->version != BRCMF_BSS_INFO_VERSION)) { - WL_ERR("Version %d != WL_BSS_INFO_VERSION\n", - bss_list->version); - return -EOPNOTSUPP; - } - WL_SCAN("scanned AP count (%d)\n", bss_list->count); - bi = next_bss(bss_list, bi); - for_each_bss(bss_list, bi, i) { - err = brcmf_inform_single_bss(cfg_priv, bi); - if (unlikely(err)) - break; - } - return err; -} - - -static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_priv *cfg_priv, - struct brcmf_bss_info *bi) -{ - struct wiphy *wiphy = cfg_to_wiphy(cfg_priv); - struct ieee80211_channel *notify_channel; - struct cfg80211_bss *bss; - struct ieee80211_supported_band *band; - s32 err = 0; - u16 channel; - u32 freq; - u64 notify_timestamp; - u16 notify_capability; - u16 notify_interval; - u8 *notify_ie; - size_t notify_ielen; - s32 notify_signal; - - if (unlikely(le32_to_cpu(bi->length) > WL_BSS_INFO_MAX)) { - WL_ERR("Bss info is larger than buffer. Discarding\n"); - return 0; - } - - channel = bi->ctl_ch ? bi->ctl_ch : - CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec)); - - if (channel <= CH_MAX_2G_CHANNEL) - band = wiphy->bands[IEEE80211_BAND_2GHZ]; - else - band = wiphy->bands[IEEE80211_BAND_5GHZ]; - - freq = ieee80211_channel_to_frequency(channel, band->band); - notify_channel = ieee80211_get_channel(wiphy, freq); - - notify_timestamp = jiffies_to_msecs(jiffies)*1000; /* uSec */ - notify_capability = le16_to_cpu(bi->capability); - notify_interval = le16_to_cpu(bi->beacon_period); - notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset); - notify_ielen = le16_to_cpu(bi->ie_length); - notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100; - - WL_CONN("bssid: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", - bi->BSSID[0], bi->BSSID[1], bi->BSSID[2], - bi->BSSID[3], bi->BSSID[4], bi->BSSID[5]); - WL_CONN("Channel: %d(%d)\n", channel, freq); - WL_CONN("Capability: %X\n", notify_capability); - WL_CONN("Beacon interval: %d\n", notify_interval); - WL_CONN("Signal: %d\n", notify_signal); - WL_CONN("notify_timestamp: %#018llx\n", notify_timestamp); - - bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID, - notify_timestamp, notify_capability, notify_interval, notify_ie, - notify_ielen, notify_signal, GFP_KERNEL); - - if (unlikely(!bss)) { - WL_ERR("cfg80211_inform_bss_frame error\n"); - return -EINVAL; - } - - return err; -} - -static s32 wl_inform_ibss(struct brcmf_cfg80211_priv *cfg_priv, - struct net_device *dev, const u8 *bssid) -{ - struct wiphy *wiphy = cfg_to_wiphy(cfg_priv); - struct ieee80211_channel *notify_channel; - struct brcmf_bss_info *bi = NULL; - struct ieee80211_supported_band *band; - u8 *buf = NULL; - s32 err = 0; - u16 channel; - u32 freq; - u64 notify_timestamp; - u16 notify_capability; - u16 notify_interval; - u8 *notify_ie; - size_t notify_ielen; - s32 notify_signal; - - WL_TRACE("Enter\n"); - - buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); - if (buf == NULL) { - WL_ERR("kzalloc() failed\n"); - err = -ENOMEM; - goto CleanUp; - } - - *(u32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX); - - err = brcmf_dev_ioctl(dev, BRCMF_C_GET_BSS_INFO, buf, WL_BSS_INFO_MAX); - if (unlikely(err)) { - WL_ERR("WLC_GET_BSS_INFO failed: %d\n", err); - goto CleanUp; - } - - bi = (struct brcmf_bss_info *)(buf + 4); - - channel = bi->ctl_ch ? bi->ctl_ch : - CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec)); - - if (channel <= CH_MAX_2G_CHANNEL) - band = wiphy->bands[IEEE80211_BAND_2GHZ]; - else - band = wiphy->bands[IEEE80211_BAND_5GHZ]; - - freq = ieee80211_channel_to_frequency(channel, band->band); - notify_channel = ieee80211_get_channel(wiphy, freq); - - notify_timestamp = jiffies_to_msecs(jiffies)*1000; /* uSec */ - notify_capability = le16_to_cpu(bi->capability); - notify_interval = le16_to_cpu(bi->beacon_period); - notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset); - notify_ielen = le16_to_cpu(bi->ie_length); - notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100; - - WL_CONN("channel: %d(%d)\n", channel, freq); - WL_CONN("capability: %X\n", notify_capability); - WL_CONN("beacon interval: %d\n", notify_interval); - WL_CONN("signal: %d\n", notify_signal); - WL_CONN("notify_timestamp: %#018llx\n", notify_timestamp); - - cfg80211_inform_bss(wiphy, notify_channel, bssid, - notify_timestamp, notify_capability, notify_interval, - notify_ie, notify_ielen, notify_signal, GFP_KERNEL); - -CleanUp: - - kfree(buf); - - WL_TRACE("Exit\n"); - - return err; -} - static bool brcmf_is_linkup(struct brcmf_cfg80211_priv *cfg_priv, const struct brcmf_event_msg *e) { @@ -2590,104 +2801,16 @@ static bool brcmf_is_nonetwork(struct brcmf_cfg80211_priv *cfg_priv, return false; } -static s32 -brcmf_notify_connect_status(struct brcmf_cfg80211_priv *cfg_priv, - struct net_device *ndev, - const struct brcmf_event_msg *e, void *data) +static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv) { - s32 err = 0; + struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv); - if (brcmf_is_linkup(cfg_priv, e)) { - WL_CONN("Linkup\n"); - if (brcmf_is_ibssmode(cfg_priv)) { - brcmf_update_prof(cfg_priv, NULL, (void *)e->addr, - WL_PROF_BSSID); - wl_inform_ibss(cfg_priv, ndev, e->addr); - cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL); - clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status); - set_bit(WL_STATUS_CONNECTED, &cfg_priv->status); - } else - brcmf_bss_connect_done(cfg_priv, ndev, e, true); - } else if (brcmf_is_linkdown(cfg_priv, e)) { - WL_CONN("Linkdown\n"); - if (brcmf_is_ibssmode(cfg_priv)) { - clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status); - if (test_and_clear_bit(WL_STATUS_CONNECTED, - &cfg_priv->status)) - brcmf_link_down(cfg_priv); - } else { - brcmf_bss_connect_done(cfg_priv, ndev, e, false); - if (test_and_clear_bit(WL_STATUS_CONNECTED, - &cfg_priv->status)) { - cfg80211_disconnected(ndev, 0, NULL, 0, - GFP_KERNEL); - brcmf_link_down(cfg_priv); - } - } - brcmf_init_prof(cfg_priv->profile); - } else if (brcmf_is_nonetwork(cfg_priv, e)) { - if (brcmf_is_ibssmode(cfg_priv)) - clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status); - else - brcmf_bss_connect_done(cfg_priv, ndev, e, false); - } - - return err; -} - -static s32 -brcmf_notify_roaming_status(struct brcmf_cfg80211_priv *cfg_priv, - struct net_device *ndev, - const struct brcmf_event_msg *e, void *data) -{ - s32 err = 0; - u32 event = be32_to_cpu(e->event_type); - u32 status = be32_to_cpu(e->status); - - if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) { - if (test_bit(WL_STATUS_CONNECTED, &cfg_priv->status)) - brcmf_bss_roaming_done(cfg_priv, ndev, e); - else - brcmf_bss_connect_done(cfg_priv, ndev, e, true); - } - - return err; -} - -static __used s32 -brcmf_dev_bufvar_set(struct net_device *dev, s8 *name, s8 *buf, s32 len) -{ - struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(dev); - u32 buflen; - - buflen = brcmu_mkiovar(name, buf, len, cfg_priv->ioctl_buf, - WL_IOCTL_LEN_MAX); - BUG_ON(!buflen); - - return brcmf_dev_ioctl(dev, BRCMF_C_SET_VAR, cfg_priv->ioctl_buf, - buflen); -} - -static s32 -brcmf_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf, - s32 buf_len) -{ - struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(dev); - u32 len; - s32 err = 0; - - len = brcmu_mkiovar(name, NULL, 0, cfg_priv->ioctl_buf, - WL_IOCTL_LEN_MAX); - BUG_ON(!len); - err = brcmf_dev_ioctl(dev, BRCMF_C_GET_VAR, (void *)cfg_priv->ioctl_buf, - WL_IOCTL_LEN_MAX); - if (unlikely(err)) { - WL_ERR("error (%d)\n", err); - return err; - } - memcpy(buf, cfg_priv->ioctl_buf, buf_len); - - return err; + kfree(conn_info->req_ie); + conn_info->req_ie = NULL; + conn_info->req_ie_len = 0; + kfree(conn_info->resp_ie); + conn_info->resp_ie = NULL; + conn_info->resp_ie_len = 0; } static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv) @@ -2748,114 +2871,6 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv) return err; } -static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv) -{ - struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv); - - kfree(conn_info->req_ie); - conn_info->req_ie = NULL; - conn_info->req_ie_len = 0; - kfree(conn_info->resp_ie); - conn_info->resp_ie = NULL; - conn_info->resp_ie_len = 0; -} - - -static void brcmf_ch_to_chanspec(int ch, struct brcmf_join_params *join_params, - size_t *join_params_size) -{ - u16 chanspec = 0; - - if (ch != 0) { - join_params->params.chanspec_num = 1; - join_params->params.chanspec_list[0] = ch; - - if (join_params->params.chanspec_list[0] <= CH_MAX_2G_CHANNEL) - chanspec |= WL_CHANSPEC_BAND_2G; - else - chanspec |= WL_CHANSPEC_BAND_5G; - - chanspec |= WL_CHANSPEC_BW_20; - chanspec |= WL_CHANSPEC_CTL_SB_NONE; - - *join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE + - join_params->params.chanspec_num * sizeof(u16); - - join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK; - join_params->params.chanspec_list[0] |= chanspec; - join_params->params.chanspec_list[0] = - cpu_to_le16(join_params->params.chanspec_list[0]); - - join_params->params.chanspec_num = - cpu_to_le32(join_params->params.chanspec_num); - - WL_CONN("join_params->params.chanspec_list[0]= %#X," - "channel %d, chanspec %#X\n", - join_params->params.chanspec_list[0], ch, chanspec); - } -} - -static s32 brcmf_update_bss_info(struct brcmf_cfg80211_priv *cfg_priv) -{ - struct brcmf_bss_info *bi; - struct brcmf_ssid *ssid; - struct brcmu_tlv *tim; - u16 beacon_interval; - u8 dtim_period; - size_t ie_len; - u8 *ie; - s32 err = 0; - - WL_TRACE("Enter\n"); - if (brcmf_is_ibssmode(cfg_priv)) - return err; - - ssid = (struct brcmf_ssid *)brcmf_read_prof(cfg_priv, WL_PROF_SSID); - - *(u32 *)cfg_priv->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX); - err = brcmf_dev_ioctl(cfg_to_ndev(cfg_priv), BRCMF_C_GET_BSS_INFO, - cfg_priv->extra_buf, WL_EXTRA_BUF_MAX); - if (unlikely(err)) { - WL_ERR("Could not get bss info %d\n", err); - goto update_bss_info_out; - } - - bi = (struct brcmf_bss_info *)(cfg_priv->extra_buf + 4); - err = brcmf_inform_single_bss(cfg_priv, bi); - if (unlikely(err)) - goto update_bss_info_out; - - ie = ((u8 *)bi) + bi->ie_offset; - ie_len = bi->ie_length; - beacon_interval = cpu_to_le16(bi->beacon_period); - - tim = brcmu_parse_tlvs(ie, ie_len, WLAN_EID_TIM); - if (tim) - dtim_period = tim->data[1]; - else { - /* - * active scan was done so we could not get dtim - * information out of probe response. - * so we speficially query dtim information to dongle. - */ - u32 var; - err = brcmf_dev_intvar_get(cfg_to_ndev(cfg_priv), - "dtim_assoc", &var); - if (unlikely(err)) { - WL_ERR("wl dtim_assoc failed (%d)\n", err); - goto update_bss_info_out; - } - dtim_period = (u8)var; - } - - brcmf_update_prof(cfg_priv, NULL, &beacon_interval, WL_PROF_BEACONINT); - brcmf_update_prof(cfg_priv, NULL, &dtim_period, WL_PROF_DTIMPERIOD); - -update_bss_info_out: - WL_TRACE("Exit"); - return err; -} - static s32 brcmf_bss_roaming_done(struct brcmf_cfg80211_priv *cfg_priv, struct net_device *ndev, @@ -2936,6 +2951,70 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_priv *cfg_priv, return err; } +static s32 +brcmf_notify_connect_status(struct brcmf_cfg80211_priv *cfg_priv, + struct net_device *ndev, + const struct brcmf_event_msg *e, void *data) +{ + s32 err = 0; + + if (brcmf_is_linkup(cfg_priv, e)) { + WL_CONN("Linkup\n"); + if (brcmf_is_ibssmode(cfg_priv)) { + brcmf_update_prof(cfg_priv, NULL, (void *)e->addr, + WL_PROF_BSSID); + wl_inform_ibss(cfg_priv, ndev, e->addr); + cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL); + clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status); + set_bit(WL_STATUS_CONNECTED, &cfg_priv->status); + } else + brcmf_bss_connect_done(cfg_priv, ndev, e, true); + } else if (brcmf_is_linkdown(cfg_priv, e)) { + WL_CONN("Linkdown\n"); + if (brcmf_is_ibssmode(cfg_priv)) { + clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status); + if (test_and_clear_bit(WL_STATUS_CONNECTED, + &cfg_priv->status)) + brcmf_link_down(cfg_priv); + } else { + brcmf_bss_connect_done(cfg_priv, ndev, e, false); + if (test_and_clear_bit(WL_STATUS_CONNECTED, + &cfg_priv->status)) { + cfg80211_disconnected(ndev, 0, NULL, 0, + GFP_KERNEL); + brcmf_link_down(cfg_priv); + } + } + brcmf_init_prof(cfg_priv->profile); + } else if (brcmf_is_nonetwork(cfg_priv, e)) { + if (brcmf_is_ibssmode(cfg_priv)) + clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status); + else + brcmf_bss_connect_done(cfg_priv, ndev, e, false); + } + + return err; +} + +static s32 +brcmf_notify_roaming_status(struct brcmf_cfg80211_priv *cfg_priv, + struct net_device *ndev, + const struct brcmf_event_msg *e, void *data) +{ + s32 err = 0; + u32 event = be32_to_cpu(e->event_type); + u32 status = be32_to_cpu(e->status); + + if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) { + if (test_bit(WL_STATUS_CONNECTED, &cfg_priv->status)) + brcmf_bss_roaming_done(cfg_priv, ndev, e); + else + brcmf_bss_connect_done(cfg_priv, ndev, e, true); + } + + return err; +} + static s32 brcmf_notify_mic_status(struct brcmf_cfg80211_priv *cfg_priv, struct net_device *ndev, @@ -3041,11 +3120,6 @@ static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf) conf->tx_power = -1; } -static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof) -{ - memset(prof, 0, sizeof(*prof)); -} - static void brcmf_init_eloop_handler(struct brcmf_cfg80211_event_loop *el) { memset(el, 0, sizeof(*el)); @@ -3056,6 +3130,28 @@ static void brcmf_init_eloop_handler(struct brcmf_cfg80211_event_loop *el) el->handler[BRCMF_E_SET_SSID] = brcmf_notify_connect_status; } +static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_priv *cfg_priv) +{ + kfree(cfg_priv->scan_results); + cfg_priv->scan_results = NULL; + kfree(cfg_priv->bss_info); + cfg_priv->bss_info = NULL; + kfree(cfg_priv->conf); + cfg_priv->conf = NULL; + kfree(cfg_priv->profile); + cfg_priv->profile = NULL; + kfree(cfg_priv->scan_req_int); + cfg_priv->scan_req_int = NULL; + kfree(cfg_priv->ioctl_buf); + cfg_priv->ioctl_buf = NULL; + kfree(cfg_priv->extra_buf); + cfg_priv->extra_buf = NULL; + kfree(cfg_priv->iscan); + cfg_priv->iscan = NULL; + kfree(cfg_priv->pmk_list); + cfg_priv->pmk_list = NULL; +} + static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_priv *cfg_priv) { cfg_priv->scan_results = kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL); @@ -3113,26 +3209,114 @@ init_priv_mem_out: return -ENOMEM; } -static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_priv *cfg_priv) +static void brcmf_lock_eq(struct brcmf_cfg80211_priv *cfg_priv) { - kfree(cfg_priv->scan_results); - cfg_priv->scan_results = NULL; - kfree(cfg_priv->bss_info); - cfg_priv->bss_info = NULL; - kfree(cfg_priv->conf); - cfg_priv->conf = NULL; - kfree(cfg_priv->profile); - cfg_priv->profile = NULL; - kfree(cfg_priv->scan_req_int); - cfg_priv->scan_req_int = NULL; - kfree(cfg_priv->ioctl_buf); - cfg_priv->ioctl_buf = NULL; - kfree(cfg_priv->extra_buf); - cfg_priv->extra_buf = NULL; - kfree(cfg_priv->iscan); - cfg_priv->iscan = NULL; - kfree(cfg_priv->pmk_list); - cfg_priv->pmk_list = NULL; + spin_lock_irq(&cfg_priv->eq_lock); +} + +static void brcmf_unlock_eq(struct brcmf_cfg80211_priv *cfg_priv) +{ + spin_unlock_irq(&cfg_priv->eq_lock); +} + +static void brcmf_init_eq_lock(struct brcmf_cfg80211_priv *cfg_priv) +{ + spin_lock_init(&cfg_priv->eq_lock); +} + +/* +* retrieve first queued event from head +*/ + +static struct brcmf_cfg80211_event_q *brcmf_deq_event( + struct brcmf_cfg80211_priv *cfg_priv) +{ + struct brcmf_cfg80211_event_q *e = NULL; + + brcmf_lock_eq(cfg_priv); + if (likely(!list_empty(&cfg_priv->eq_list))) { + e = list_first_entry(&cfg_priv->eq_list, + struct brcmf_cfg80211_event_q, eq_list); + list_del(&e->eq_list); + } + brcmf_unlock_eq(cfg_priv); + + return e; +} + +/* +** push event to tail of the queue +*/ + +static s32 +brcmf_enq_event(struct brcmf_cfg80211_priv *cfg_priv, u32 event, + const struct brcmf_event_msg *msg) +{ + struct brcmf_cfg80211_event_q *e; + s32 err = 0; + + e = kzalloc(sizeof(struct brcmf_cfg80211_event_q), GFP_KERNEL); + if (unlikely(!e)) { + WL_ERR("event alloc failed\n"); + return -ENOMEM; + } + + e->etype = event; + memcpy(&e->emsg, msg, sizeof(struct brcmf_event_msg)); + + brcmf_lock_eq(cfg_priv); + list_add_tail(&e->eq_list, &cfg_priv->eq_list); + brcmf_unlock_eq(cfg_priv); + + return err; +} + +static void brcmf_put_event(struct brcmf_cfg80211_event_q *e) +{ + kfree(e); +} + +static s32 brcmf_event_handler(void *data) +{ + struct brcmf_cfg80211_priv *cfg_priv = + (struct brcmf_cfg80211_priv *)data; + struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1 }; + struct brcmf_cfg80211_event_q *e; + DECLARE_WAITQUEUE(wait, current); + + sched_setscheduler(current, SCHED_FIFO, ¶m); + allow_signal(SIGTERM); + add_wait_queue(&cfg_priv->event_waitq, &wait); + while (1) { + prepare_to_wait(&cfg_priv->event_waitq, &wait, + TASK_INTERRUPTIBLE); + + schedule(); + + if (kthread_should_stop()) + break; + + e = brcmf_deq_event(cfg_priv); + if (unlikely(!e)) { + WL_ERR("event queue empty...\n"); + continue; + } + + do { + WL_INFO("event type (%d)\n", e->etype); + if (cfg_priv->el.handler[e->etype]) + cfg_priv->el.handler[e->etype](cfg_priv, + cfg_to_ndev(cfg_priv), + &e->emsg, e->edata); + else + WL_INFO("Unknown Event (%d): ignoring\n", + e->etype); + brcmf_put_event(e); + } while ((e = brcmf_deq_event(cfg_priv))); + } + finish_wait(&cfg_priv->event_waitq, &wait); + WL_INFO("was terminated\n"); + return 0; } static s32 brcmf_create_event_handler(struct brcmf_cfg80211_priv *cfg_priv) @@ -3157,227 +3341,24 @@ static void brcmf_destroy_event_handler(struct brcmf_cfg80211_priv *cfg_priv) } } -static void brcmf_term_iscan(struct brcmf_cfg80211_priv *cfg_priv) +static void brcmf_init_eq(struct brcmf_cfg80211_priv *cfg_priv) { - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv); - struct brcmf_ssid ssid; + brcmf_init_eq_lock(cfg_priv); + INIT_LIST_HEAD(&cfg_priv->eq_list); +} - if (cfg_priv->iscan_on) { - iscan->state = WL_ISCAN_STATE_IDLE; +static void brcmf_flush_eq(struct brcmf_cfg80211_priv *cfg_priv) +{ + struct brcmf_cfg80211_event_q *e; - if (iscan->timer_on) { - del_timer_sync(&iscan->timer); - iscan->timer_on = 0; - } - - cancel_work_sync(&iscan->work); - - /* Abort iscan running in FW */ - memset(&ssid, 0, sizeof(ssid)); - brcmf_run_iscan(iscan, &ssid, WL_SCAN_ACTION_ABORT); + brcmf_lock_eq(cfg_priv); + while (!list_empty(&cfg_priv->eq_list)) { + e = list_first_entry(&cfg_priv->eq_list, + struct brcmf_cfg80211_event_q, eq_list); + list_del(&e->eq_list); + kfree(e); } -} - -static void brcmf_notify_iscan_complete(struct brcmf_cfg80211_iscan_ctrl *iscan, - bool aborted) -{ - struct brcmf_cfg80211_priv *cfg_priv = iscan_to_cfg(iscan); - struct net_device *ndev = cfg_to_ndev(cfg_priv); - - if (unlikely(!test_and_clear_bit(WL_STATUS_SCANNING, - &cfg_priv->status))) { - WL_ERR("Scan complete while device not scanning\n"); - return; - } - if (likely(cfg_priv->scan_request)) { - WL_SCAN("ISCAN Completed scan: %s\n", - aborted ? "Aborted" : "Done"); - cfg80211_scan_done(cfg_priv->scan_request, aborted); - brcmf_set_mpc(ndev, 1); - cfg_priv->scan_request = NULL; - } - cfg_priv->iscan_kickstart = false; -} - -static s32 brcmf_wakeup_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan) -{ - if (likely(iscan->state != WL_ISCAN_STATE_IDLE)) { - WL_SCAN("wake up iscan\n"); - schedule_work(&iscan->work); - return 0; - } - - return -EIO; -} - -static s32 -brcmf_get_iscan_results(struct brcmf_cfg80211_iscan_ctrl *iscan, u32 *status, - struct brcmf_scan_results **bss_list) -{ - struct brcmf_iscan_results list; - struct brcmf_scan_results *results; - struct brcmf_iscan_results *list_buf; - s32 err = 0; - - memset(iscan->scan_buf, 0, WL_ISCAN_BUF_MAX); - list_buf = (struct brcmf_iscan_results *)iscan->scan_buf; - results = &list_buf->results; - results->buflen = BRCMF_ISCAN_RESULTS_FIXED_SIZE; - results->version = 0; - results->count = 0; - - memset(&list, 0, sizeof(list)); - list.results.buflen = cpu_to_le32(WL_ISCAN_BUF_MAX); - err = brcmf_dev_iovar_getbuf(iscan->dev, "iscanresults", &list, - BRCMF_ISCAN_RESULTS_FIXED_SIZE, iscan->scan_buf, - WL_ISCAN_BUF_MAX); - if (unlikely(err)) { - WL_ERR("error (%d)\n", err); - return err; - } - results->buflen = le32_to_cpu(results->buflen); - results->version = le32_to_cpu(results->version); - results->count = le32_to_cpu(results->count); - WL_SCAN("results->count = %d\n", results->count); - WL_SCAN("results->buflen = %d\n", results->buflen); - *status = le32_to_cpu(list_buf->status); - WL_SCAN("status = %d\n", *status); - *bss_list = results; - - return err; -} - -static s32 brcmf_iscan_done(struct brcmf_cfg80211_priv *cfg_priv) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan; - s32 err = 0; - - iscan->state = WL_ISCAN_STATE_IDLE; - rtnl_lock(); - brcmf_inform_bss(cfg_priv); - brcmf_notify_iscan_complete(iscan, false); - rtnl_unlock(); - - return err; -} - -static s32 brcmf_iscan_pending(struct brcmf_cfg80211_priv *cfg_priv) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan; - s32 err = 0; - - /* Reschedule the timer */ - mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); - iscan->timer_on = 1; - - return err; -} - -static s32 brcmf_iscan_inprogress(struct brcmf_cfg80211_priv *cfg_priv) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan; - s32 err = 0; - - rtnl_lock(); - brcmf_inform_bss(cfg_priv); - brcmf_run_iscan(iscan, NULL, BRCMF_SCAN_ACTION_CONTINUE); - rtnl_unlock(); - /* Reschedule the timer */ - mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); - iscan->timer_on = 1; - - return err; -} - -static s32 brcmf_iscan_aborted(struct brcmf_cfg80211_priv *cfg_priv) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan; - s32 err = 0; - - iscan->state = WL_ISCAN_STATE_IDLE; - rtnl_lock(); - brcmf_notify_iscan_complete(iscan, true); - rtnl_unlock(); - - return err; -} - -static void brcmf_cfg80211_iscan_handler(struct work_struct *work) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = - container_of(work, struct brcmf_cfg80211_iscan_ctrl, - work); - struct brcmf_cfg80211_priv *cfg_priv = iscan_to_cfg(iscan); - struct brcmf_cfg80211_iscan_eloop *el = &iscan->el; - u32 status = BRCMF_SCAN_RESULTS_PARTIAL; - - if (iscan->timer_on) { - del_timer_sync(&iscan->timer); - iscan->timer_on = 0; - } - - rtnl_lock(); - if (brcmf_get_iscan_results(iscan, &status, &cfg_priv->bss_list)) { - status = BRCMF_SCAN_RESULTS_ABORTED; - WL_ERR("Abort iscan\n"); - } - rtnl_unlock(); - - el->handler[status](cfg_priv); -} - -static void brcmf_iscan_timer(unsigned long data) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = - (struct brcmf_cfg80211_iscan_ctrl *)data; - - if (iscan) { - iscan->timer_on = 0; - WL_SCAN("timer expired\n"); - brcmf_wakeup_iscan(iscan); - } -} - -static s32 brcmf_invoke_iscan(struct brcmf_cfg80211_priv *cfg_priv) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv); - - if (cfg_priv->iscan_on) { - iscan->state = WL_ISCAN_STATE_IDLE; - INIT_WORK(&iscan->work, brcmf_cfg80211_iscan_handler); - } - - return 0; -} - -static void brcmf_init_iscan_eloop(struct brcmf_cfg80211_iscan_eloop *el) -{ - memset(el, 0, sizeof(*el)); - el->handler[BRCMF_SCAN_RESULTS_SUCCESS] = brcmf_iscan_done; - el->handler[BRCMF_SCAN_RESULTS_PARTIAL] = brcmf_iscan_inprogress; - el->handler[BRCMF_SCAN_RESULTS_PENDING] = brcmf_iscan_pending; - el->handler[BRCMF_SCAN_RESULTS_ABORTED] = brcmf_iscan_aborted; - el->handler[BRCMF_SCAN_RESULTS_NO_MEM] = brcmf_iscan_aborted; -} - -static s32 brcmf_init_iscan(struct brcmf_cfg80211_priv *cfg_priv) -{ - struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv); - int err = 0; - - if (cfg_priv->iscan_on) { - iscan->dev = cfg_to_ndev(cfg_priv); - brcmf_init_iscan_eloop(&iscan->el); - iscan->timer_ms = WL_ISCAN_TIMER_INTERVAL_MS; - init_timer(&iscan->timer); - iscan->timer.data = (unsigned long) iscan; - iscan->timer.function = brcmf_iscan_timer; - err = brcmf_invoke_iscan(cfg_priv); - if (!err) - iscan->data = cfg_priv; - } - - return err; + brcmf_unlock_eq(cfg_priv); } static s32 wl_init_priv(struct brcmf_cfg80211_priv *cfg_priv) @@ -3490,49 +3471,6 @@ static void brcmf_wakeup_event(struct brcmf_cfg80211_priv *cfg_priv) wake_up(&cfg_priv->event_waitq); } -static s32 brcmf_event_handler(void *data) -{ - struct brcmf_cfg80211_priv *cfg_priv = - (struct brcmf_cfg80211_priv *)data; - struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1 }; - struct brcmf_cfg80211_event_q *e; - DECLARE_WAITQUEUE(wait, current); - - sched_setscheduler(current, SCHED_FIFO, ¶m); - allow_signal(SIGTERM); - add_wait_queue(&cfg_priv->event_waitq, &wait); - while (1) { - prepare_to_wait(&cfg_priv->event_waitq, &wait, - TASK_INTERRUPTIBLE); - - schedule(); - - if (kthread_should_stop()) - break; - - e = brcmf_deq_event(cfg_priv); - if (unlikely(!e)) { - WL_ERR("event queue empty...\n"); - continue; - } - - do { - WL_INFO("event type (%d)\n", e->etype); - if (cfg_priv->el.handler[e->etype]) - cfg_priv->el.handler[e->etype](cfg_priv, - cfg_to_ndev(cfg_priv), - &e->emsg, e->edata); - else - WL_INFO("Unknown Event (%d): ignoring\n", - e->etype); - brcmf_put_event(e); - } while ((e = brcmf_deq_event(cfg_priv))); - } - finish_wait(&cfg_priv->event_waitq, &wait); - WL_INFO("was terminated\n"); - return 0; -} - void brcmf_cfg80211_event(struct net_device *ndev, const struct brcmf_event_msg *e, void *data) @@ -3544,78 +3482,6 @@ brcmf_cfg80211_event(struct net_device *ndev, brcmf_wakeup_event(cfg_priv); } -static void brcmf_init_eq(struct brcmf_cfg80211_priv *cfg_priv) -{ - brcmf_init_eq_lock(cfg_priv); - INIT_LIST_HEAD(&cfg_priv->eq_list); -} - -static void brcmf_flush_eq(struct brcmf_cfg80211_priv *cfg_priv) -{ - struct brcmf_cfg80211_event_q *e; - - brcmf_lock_eq(cfg_priv); - while (!list_empty(&cfg_priv->eq_list)) { - e = list_first_entry(&cfg_priv->eq_list, - struct brcmf_cfg80211_event_q, eq_list); - list_del(&e->eq_list); - kfree(e); - } - brcmf_unlock_eq(cfg_priv); -} - -/* -* retrieve first queued event from head -*/ - -static struct brcmf_cfg80211_event_q *brcmf_deq_event( - struct brcmf_cfg80211_priv *cfg_priv) -{ - struct brcmf_cfg80211_event_q *e = NULL; - - brcmf_lock_eq(cfg_priv); - if (likely(!list_empty(&cfg_priv->eq_list))) { - e = list_first_entry(&cfg_priv->eq_list, - struct brcmf_cfg80211_event_q, eq_list); - list_del(&e->eq_list); - } - brcmf_unlock_eq(cfg_priv); - - return e; -} - -/* -** push event to tail of the queue -*/ - -static s32 -brcmf_enq_event(struct brcmf_cfg80211_priv *cfg_priv, u32 event, - const struct brcmf_event_msg *msg) -{ - struct brcmf_cfg80211_event_q *e; - s32 err = 0; - - e = kzalloc(sizeof(struct brcmf_cfg80211_event_q), GFP_KERNEL); - if (unlikely(!e)) { - WL_ERR("event alloc failed\n"); - return -ENOMEM; - } - - e->etype = event; - memcpy(&e->emsg, msg, sizeof(struct brcmf_event_msg)); - - brcmf_lock_eq(cfg_priv); - list_add_tail(&e->eq_list, &cfg_priv->eq_list); - brcmf_unlock_eq(cfg_priv); - - return err; -} - -static void brcmf_put_event(struct brcmf_cfg80211_event_q *e) -{ - kfree(e); -} - static s32 brcmf_dongle_mode(struct net_device *ndev, s32 iftype) { s32 infra = 0; @@ -3798,6 +3664,35 @@ dongle_scantime_out: return err; } +static s32 wl_update_wiphybands(struct brcmf_cfg80211_priv *cfg_priv) +{ + struct wiphy *wiphy; + s32 phy_list; + s8 phy; + s32 err = 0; + + err = brcmf_dev_ioctl(cfg_to_ndev(cfg_priv), BRCM_GET_PHYLIST, + &phy_list, sizeof(phy_list)); + if (unlikely(err)) { + WL_ERR("error (%d)\n", err); + return err; + } + + phy = ((char *)&phy_list)[1]; + WL_INFO("%c phy\n", phy); + if (phy == 'n' || phy == 'a') { + wiphy = cfg_to_wiphy(cfg_priv); + wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n; + } + + return err; +} + +static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_priv *cfg_priv) +{ + return wl_update_wiphybands(cfg_priv); +} + static s32 brcmf_config_dongle(struct brcmf_cfg80211_priv *cfg_priv, bool need_lock) { @@ -3853,30 +3748,40 @@ default_conf_out: } -static s32 wl_update_wiphybands(struct brcmf_cfg80211_priv *cfg_priv) +static int brcmf_debugfs_add_netdev_params(struct brcmf_cfg80211_priv *cfg_priv) { - struct wiphy *wiphy; - s32 phy_list; - s8 phy; + char buf[10+IFNAMSIZ]; + struct dentry *fd; s32 err = 0; - err = brcmf_dev_ioctl(cfg_to_ndev(cfg_priv), BRCM_GET_PHYLIST, - &phy_list, sizeof(phy_list)); - if (unlikely(err)) { - WL_ERR("error (%d)\n", err); - return err; + sprintf(buf, "netdev:%s", cfg_to_ndev(cfg_priv)->name); + cfg_priv->debugfsdir = debugfs_create_dir(buf, + cfg_to_wiphy(cfg_priv)->debugfsdir); + + fd = debugfs_create_u16("beacon_int", S_IRUGO, cfg_priv->debugfsdir, + (u16 *)&cfg_priv->profile->beacon_interval); + if (!fd) { + err = -ENOMEM; + goto err_out; } - phy = ((char *)&phy_list)[1]; - WL_INFO("%c phy\n", phy); - if (phy == 'n' || phy == 'a') { - wiphy = cfg_to_wiphy(cfg_priv); - wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n; + fd = debugfs_create_u8("dtim_period", S_IRUGO, cfg_priv->debugfsdir, + (u8 *)&cfg_priv->profile->dtim_period); + if (!fd) { + err = -ENOMEM; + goto err_out; } +err_out: return err; } +static void brcmf_debugfs_remove_netdev(struct brcmf_cfg80211_priv *cfg_priv) +{ + debugfs_remove_recursive(cfg_priv->debugfsdir); + cfg_priv->debugfsdir = NULL; +} + static s32 __brcmf_cfg80211_up(struct brcmf_cfg80211_priv *cfg_priv) { s32 err = 0; @@ -3958,71 +3863,6 @@ s32 brcmf_cfg80211_down(struct brcmf_cfg80211_dev *cfg_dev) return err; } -static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_priv *cfg_priv) -{ - return wl_update_wiphybands(cfg_priv); -} - -static void *brcmf_read_prof(struct brcmf_cfg80211_priv *cfg_priv, s32 item) -{ - switch (item) { - case WL_PROF_SEC: - return &cfg_priv->profile->sec; - case WL_PROF_BSSID: - return &cfg_priv->profile->bssid; - case WL_PROF_SSID: - return &cfg_priv->profile->ssid; - } - WL_ERR("invalid item (%d)\n", item); - return NULL; -} - -static s32 -brcmf_update_prof(struct brcmf_cfg80211_priv *cfg_priv, - const struct brcmf_event_msg *e, void *data, s32 item) -{ - s32 err = 0; - struct brcmf_ssid *ssid; - - switch (item) { - case WL_PROF_SSID: - ssid = (struct brcmf_ssid *) data; - memset(cfg_priv->profile->ssid.SSID, 0, - sizeof(cfg_priv->profile->ssid.SSID)); - memcpy(cfg_priv->profile->ssid.SSID, - ssid->SSID, ssid->SSID_len); - cfg_priv->profile->ssid.SSID_len = ssid->SSID_len; - break; - case WL_PROF_BSSID: - if (data) - memcpy(cfg_priv->profile->bssid, data, ETH_ALEN); - else - memset(cfg_priv->profile->bssid, 0, ETH_ALEN); - break; - case WL_PROF_SEC: - memcpy(&cfg_priv->profile->sec, data, - sizeof(cfg_priv->profile->sec)); - break; - case WL_PROF_BEACONINT: - cfg_priv->profile->beacon_interval = *(u16 *)data; - break; - case WL_PROF_DTIMPERIOD: - cfg_priv->profile->dtim_period = *(u8 *)data; - break; - default: - WL_ERR("unsupported item (%d)\n", item); - err = -EOPNOTSUPP; - break; - } - - return err; -} - -static bool brcmf_is_ibssmode(struct brcmf_cfg80211_priv *cfg_priv) -{ - return cfg_priv->conf->mode == WL_MODE_IBSS; -} - static __used s32 brcmf_add_ie(struct brcmf_cfg80211_priv *cfg_priv, u8 t, u8 l, u8 *v) { @@ -4040,109 +3880,3 @@ static __used s32 brcmf_add_ie(struct brcmf_cfg80211_priv *cfg_priv, return err; } - -static void brcmf_link_down(struct brcmf_cfg80211_priv *cfg_priv) -{ - struct net_device *dev = NULL; - s32 err = 0; - - WL_TRACE("Enter\n"); - - if (cfg_priv->link_up) { - dev = cfg_to_ndev(cfg_priv); - WL_INFO("Call WLC_DISASSOC to stop excess roaming\n "); - err = brcmf_dev_ioctl(dev, BRCMF_C_DISASSOC, NULL, 0); - if (unlikely(err)) - WL_ERR("WLC_DISASSOC failed (%d)\n", err); - cfg_priv->link_up = false; - } - WL_TRACE("Exit\n"); -} - -static void brcmf_lock_eq(struct brcmf_cfg80211_priv *cfg_priv) -{ - spin_lock_irq(&cfg_priv->eq_lock); -} - -static void brcmf_unlock_eq(struct brcmf_cfg80211_priv *cfg_priv) -{ - spin_unlock_irq(&cfg_priv->eq_lock); -} - -static void brcmf_init_eq_lock(struct brcmf_cfg80211_priv *cfg_priv) -{ - spin_lock_init(&cfg_priv->eq_lock); -} - -static void brcmf_delay(u32 ms) -{ - if (ms < 1000 / HZ) { - cond_resched(); - mdelay(ms); - } else { - msleep(ms); - } -} - -static void brcmf_set_drvdata(struct brcmf_cfg80211_dev *dev, void *data) -{ - dev->driver_data = data; -} - -static void *brcmf_get_drvdata(struct brcmf_cfg80211_dev *dev) -{ - void *data = NULL; - - if (dev) - data = dev->driver_data; - return data; -} - -static void brcmf_set_mpc(struct net_device *ndev, int mpc) -{ - s32 err = 0; - struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); - - if (test_bit(WL_STATUS_READY, &cfg_priv->status)) { - err = brcmf_dev_intvar_set(ndev, "mpc", mpc); - if (unlikely(err)) { - WL_ERR("fail to set mpc\n"); - return; - } - WL_INFO("MPC : %d\n", mpc); - } -} - -static int brcmf_debugfs_add_netdev_params(struct brcmf_cfg80211_priv *cfg_priv) -{ - char buf[10+IFNAMSIZ]; - struct dentry *fd; - s32 err = 0; - - sprintf(buf, "netdev:%s", cfg_to_ndev(cfg_priv)->name); - cfg_priv->debugfsdir = debugfs_create_dir(buf, - cfg_to_wiphy(cfg_priv)->debugfsdir); - - fd = debugfs_create_u16("beacon_int", S_IRUGO, cfg_priv->debugfsdir, - (u16 *)&cfg_priv->profile->beacon_interval); - if (!fd) { - err = -ENOMEM; - goto err_out; - } - - fd = debugfs_create_u8("dtim_period", S_IRUGO, cfg_priv->debugfsdir, - (u8 *)&cfg_priv->profile->dtim_period); - if (!fd) { - err = -ENOMEM; - goto err_out; - } - -err_out: - return err; -} - -static void brcmf_debugfs_remove_netdev(struct brcmf_cfg80211_priv *cfg_priv) -{ - debugfs_remove_recursive(cfg_priv->debugfsdir); - cfg_priv->debugfsdir = NULL; -}