#include <linux/firmware.h>
#include <wl_cfg80211.h>
+void sdioh_sdio_set_host_pm_flags(int flag);
+
static struct sdio_func *cfg80211_sdio_func;
static struct wl_dev *wl_cfg80211_dev;
static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255};
** cfg80211 connect utilites
*/
static s32 wl_set_wpa_version(struct net_device *dev,
- struct cfg80211_connect_params *sme);
+ struct cfg80211_connect_params *sme);
static s32 wl_set_auth_type(struct net_device *dev,
- struct cfg80211_connect_params *sme);
+ struct cfg80211_connect_params *sme);
static s32 wl_set_set_cipher(struct net_device *dev,
- struct cfg80211_connect_params *sme);
+ struct cfg80211_connect_params *sme);
static s32 wl_set_key_mgmt(struct net_device *dev,
- struct cfg80211_connect_params *sme);
+ struct cfg80211_connect_params *sme);
static s32 wl_set_set_sharedkey(struct net_device *dev,
- struct cfg80211_connect_params *sme);
+ struct cfg80211_connect_params *sme);
static s32 wl_get_assoc_ies(struct wl_priv *wl);
+static void wl_clear_assoc_ies(struct wl_priv *wl);
static void wl_ch_to_chanspec(int ch,
struct wl_join_params *join_params, size_t *join_params_size);
/*
** information element utilities
*/
-static void wl_rst_ie(struct wl_priv *wl);
static __used s32 wl_add_ie(struct wl_priv *wl, u8 t, u8 l, u8 *v);
-static s32 wl_mrg_ie(struct wl_priv *wl, u8 *ie_stream, u16 ie_size);
-static s32 wl_cp_ie(struct wl_priv *wl, u8 *dst, u16 dst_size);
-static u32 wl_get_ielen(struct wl_priv *wl);
-
static s32 wl_mode_to_nl80211_iftype(s32 mode);
-
static struct wireless_dev *wl_alloc_wdev(s32 sizeof_iface,
- struct device *dev);
+ struct device *dev);
static void wl_free_wdev(struct wl_priv *wl);
-
static s32 wl_inform_bss(struct wl_priv *wl);
static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi);
static s32 wl_update_bss_info(struct wl_priv *wl);
-
static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
- u8 key_idx, const u8 *mac_addr,
- struct key_params *params);
+ u8 key_idx, const u8 *mac_addr,
+ struct key_params *params);
/*
** key indianess swap utilities
** ibss mode utilities
*/
static bool wl_is_ibssmode(struct wl_priv *wl);
-static bool wl_is_ibssstarter(struct wl_priv *wl);
/*
** dongle up/down , default configuration utilities
static bool wl_is_linkdown(struct wl_priv *wl, const wl_event_msg_t *e);
static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e);
static bool wl_is_nonetwork(struct wl_priv *wl, const wl_event_msg_t *e);
-static void wl_link_up(struct wl_priv *wl);
static void wl_link_down(struct wl_priv *wl);
static s32 wl_dongle_mode(struct net_device *ndev, s32 iftype);
static s32 __wl_cfg80211_up(struct wl_priv *wl);
static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode);
static s32 wl_dongle_glom(struct net_device *ndev, u32 glom,
u32 dongle_align);
-static s32 wl_dongle_roam(struct net_device *ndev, u32 roamvar,
- u32 bcn_timeout);
-static s32 wl_dongle_eventmsg(struct net_device *ndev);
-static s32 wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
- s32 scan_unassoc_time);
static s32 wl_dongle_offload(struct net_device *ndev, s32 arpoe,
s32 arp_ol);
static s32 wl_pattern_atoh(s8 *src, s8 *dst);
static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode);
static s32 wl_update_wiphybands(struct wl_priv *wl);
#endif /* !EMBEDDED_PLATFORM */
+
+static s32 wl_dongle_eventmsg(struct net_device *ndev);
+static s32 wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
+ s32 scan_unassoc_time, s32 scan_passive_time);
static s32 wl_config_dongle(struct wl_priv *wl, bool need_lock);
+static s32 wl_dongle_roam(struct net_device *ndev, u32 roamvar,
+ u32 bcn_timeout);
/*
** iscan handler
struct wl_priv *wl = wiphy_to_wl(wiphy);
struct wireless_dev *wdev;
s32 infra = 0;
- s32 ap = 0;
s32 err = 0;
CHECK_SYS_UP();
+
switch (type) {
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_WDS:
return -EOPNOTSUPP;
case NL80211_IFTYPE_ADHOC:
wl->conf->mode = WL_MODE_IBSS;
+ infra = 0;
break;
case NL80211_IFTYPE_STATION:
wl->conf->mode = WL_MODE_BSS;
infra = 1;
break;
default:
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
+
infra = cpu_to_le32(infra);
- ap = cpu_to_le32(ap);
- wdev = ndev->ieee80211_ptr;
- wdev->iftype = type;
- WL_DBG("%s : ap (%d), infra (%d)\n", ndev->name, ap, infra);
err = wl_dev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra));
if (unlikely(err)) {
WL_ERR("WLC_SET_INFRA error (%d)\n", err);
- return err;
- }
- err = wl_dev_ioctl(ndev, WLC_SET_AP, &ap, sizeof(ap));
- if (unlikely(err)) {
- WL_ERR("WLC_SET_AP error (%d)\n", err);
- return err;
+ err = -EAGAIN;
+ } else {
+ wdev = ndev->ieee80211_ptr;
+ wdev->iftype = type;
}
- /* -EINPROGRESS: Call commit handler */
- return -EINPROGRESS;
+ WL_INFO("IF Type = %s\n",
+ (wl->conf->mode == WL_MODE_IBSS) ? "Adhoc" : "Infra");
+
+done:
+ return err;
}
static void wl_iscan_prep(struct wl_scan_params *params, struct wlc_ssid *ssid)
struct cfg80211_ibss_params *params)
{
struct wl_priv *wl = wiphy_to_wl(wiphy);
- struct cfg80211_bss *bss;
- struct ieee80211_channel *chan;
struct wl_join_params join_params;
- struct cfg80211_ssid ssid;
- s32 scan_retry = 0;
+ size_t join_params_size = 0;
s32 err = 0;
+ s32 wsec = 0;
+ s32 bcnprd;
CHECK_SYS_UP();
- if (params->bssid) {
- WL_ERR("Invalid bssid\n");
+
+ if (params->ssid)
+ WL_DBG("SSID: %s\n", params->ssid);
+ else {
+ WL_DBG("SSID: NULL, Not supported\n");
return -EOPNOTSUPP;
}
- bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len);
- if (!bss) {
- memcpy(ssid.ssid, params->ssid, params->ssid_len);
- ssid.ssid_len = params->ssid_len;
- do {
- if (unlikely
- (__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) ==
- -EBUSY)) {
- wl_delay(150);
- } else {
- break;
- }
- } while (++scan_retry < WL_SCAN_RETRY_MAX);
- rtnl_unlock(); /* to allow scan_inform to paropagate
- to cfg80211 plane */
- schedule_timeout_interruptible(4 * HZ); /* wait 4 secons
- till scan done.... */
- rtnl_lock();
- bss = cfg80211_get_ibss(wiphy, NULL,
- params->ssid, params->ssid_len);
+
+ if (params->bssid)
+ WL_DBG("BSSID: %02X %02X %02X %02X %02X %02X\n",
+ params->bssid[0], params->bssid[1], params->bssid[2],
+ params->bssid[3], params->bssid[4], params->bssid[5]);
+ else
+ WL_DBG("No BSSID specified\n");
+
+ if (params->channel)
+ WL_DBG("channel: %d\n", params->channel->center_freq);
+ else
+ WL_DBG("no channel specified\n");
+
+ if (params->channel_fixed)
+ WL_DBG("fixed channel required\n");
+ else
+ WL_DBG("no fixed channel required\n");
+
+ if (params->ie && params->ie_len)
+ WL_DBG("ie len: %d\n", params->ie_len);
+ else
+ WL_DBG("no ie specified\n");
+
+ if (params->beacon_interval)
+ WL_DBG("beacon interval: %d\n", params->beacon_interval);
+ else
+ WL_DBG("no beacon interval specified\n");
+
+ if (params->basic_rates)
+ WL_DBG("basic rates: %08X\n", params->basic_rates);
+ else
+ WL_DBG("no basic rates specified\n");
+
+ if (params->privacy)
+ WL_DBG("privacy required\n");
+ else
+ WL_DBG("no privacy required\n");
+
+ /* Configure Privacy for starter */
+ if (params->privacy)
+ wsec |= WEP_ENABLED;
+
+ err = wl_dev_intvar_set(dev, "wsec", wsec);
+ if (unlikely(err)) {
+ WL_ERR("wsec failed (%d)\n", err);
+ goto done;
+ }
+
+ /* Configure Beacon Interval for starter */
+ if (params->beacon_interval)
+ bcnprd = cpu_to_le32(params->beacon_interval);
+ else
+ bcnprd = cpu_to_le32(100);
+
+ err = wl_dev_ioctl(dev, WLC_SET_BCNPRD, &bcnprd, sizeof(bcnprd));
+ if (unlikely(err)) {
+ WL_ERR("WLC_SET_BCNPRD failed (%d)\n", err);
+ goto done;
}
- if (bss) {
- wl->ibss_starter = false;
- WL_DBG("Found IBSS\n");
+
+ /* Configure required join parameter */
+ memset(&join_params, 0, sizeof(wl_join_params_t));
+
+ /* SSID */
+ join_params.ssid.SSID_len =
+ (params->ssid_len > 32) ? 32 : params->ssid_len;
+ memcpy(join_params.ssid.SSID, params->ssid, join_params.ssid.SSID_len);
+ join_params.ssid.SSID_len = cpu_to_le32(join_params.ssid.SSID_len);
+ join_params_size = sizeof(join_params.ssid);
+ wl_update_prof(wl, NULL, &join_params.ssid, WL_PROF_SSID);
+
+ /* BSSID */
+ if (params->bssid) {
+ memcpy(join_params.params.bssid, params->bssid, ETH_ALEN);
+ join_params_size =
+ sizeof(join_params.ssid) + WL_ASSOC_PARAMS_FIXED_SIZE;
} else {
- wl->ibss_starter = true;
+ memcpy(join_params.params.bssid, ether_bcast, ETH_ALEN);
}
- chan = params->channel;
- if (chan)
- wl->channel = ieee80211_frequency_to_channel(chan->center_freq);
- /*
- ** Join with specific BSSID and cached SSID
- ** If SSID is zero join based on BSSID only
- */
- memset(&join_params, 0, sizeof(join_params));
- memcpy((void *)join_params.ssid.SSID, (void *)params->ssid,
- params->ssid_len);
- join_params.ssid.SSID_len = cpu_to_le32(params->ssid_len);
- if (params->bssid)
- memcpy(&join_params.params.bssid, params->bssid,
- ETH_ALEN);
- else
- memset(&join_params.params.bssid, 0, ETH_ALEN);
+ wl_update_prof(wl, NULL, &join_params.params.bssid, WL_PROF_BSSID);
+
+ /* Channel */
+ if (params->channel) {
+ u32 target_channel;
+
+ wl->channel =
+ ieee80211_frequency_to_channel(
+ params->channel->center_freq);
+ if (params->channel_fixed) {
+ /* adding chanspec */
+ wl_ch_to_chanspec(wl->channel,
+ &join_params, &join_params_size);
+ }
+
+ /* set channel for starter */
+ target_channel = cpu_to_le32(wl->channel);
+ err = wl_dev_ioctl(dev, WLC_SET_CHANNEL,
+ &target_channel, sizeof(target_channel));
+ if (unlikely(err)) {
+ WL_ERR("WLC_SET_CHANNEL failed (%d)\n", err);
+ goto done;
+ }
+ } else
+ wl->channel = 0;
+
+ wl->ibss_starter = false;
+
- err = wl_dev_ioctl(dev, WLC_SET_SSID, &join_params,
- sizeof(join_params));
+ err = wl_dev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size);
if (unlikely(err)) {
- WL_ERR("Error (%d)\n", err);
- return err;
+ WL_ERR("WLC_SET_SSID failed (%d)\n", err);
+ goto done;
}
+
+ set_bit(WL_STATUS_CONNECTING, &wl->status);
+
+done:
return err;
}
return -EOPNOTSUPP;
}
if (chan) {
- wl->channel = ieee80211_frequency_to_channel(chan->center_freq);
+ wl->channel =
+ ieee80211_frequency_to_channel(chan->center_freq);
WL_DBG("channel (%d), center_req (%d)\n",
- wl->channel, chan->center_freq);
- }
+ wl->channel, chan->center_freq);
+ } else
+ wl->channel = 0;
WL_DBG("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
err = wl_set_wpa_version(dev, sme);
if (unlikely(err))
memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len);
join_params.ssid.SSID_len = cpu_to_le32(join_params.ssid.SSID_len);
wl_update_prof(wl, NULL, &join_params.ssid, WL_PROF_SSID);
- memcpy(join_params.params.bssid, ether_bcast, ETH_ALEN);
- wl_ch_to_chanspec(wl->channel, &join_params, &join_params_size);
- WL_DBG("join_param_size %zu\n", join_params_size);
+ if (sme->bssid)
+ memcpy(join_params.params.bssid, sme->bssid, ETH_ALEN);
+ else
+ memcpy(join_params.params.bssid, ether_bcast, ETH_ALEN);
if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
WL_DBG("ssid \"%s\", len (%d)\n",
join_params.ssid.SSID, join_params.ssid.SSID_len);
}
+
+ wl_ch_to_chanspec(wl->channel, &join_params, &join_params_size);
err = wl_dev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size);
if (unlikely(err)) {
WL_ERR("error (%d)\n", err);
{
struct wl_priv *wl = wiphy_to_wl(wiphy);
scb_val_t scbval;
- bool act = false;
s32 err = 0;
WL_DBG("Reason %d\n", reason_code);
CHECK_SYS_UP();
- act = *(bool *) wl_read_prof(wl, WL_PROF_ACT);
- if (likely(act)) {
- scbval.val = reason_code;
- memcpy(&scbval.ea, &wl->bssid, ETH_ALEN);
- scbval.val = cpu_to_le32(scbval.val);
- err = wl_dev_ioctl(dev, WLC_DISASSOC, &scbval,
- sizeof(scb_val_t));
- if (unlikely(err)) {
- WL_ERR("error (%d)\n", err);
- return err;
- }
- }
+
+ clear_bit(WL_STATUS_CONNECTED, &wl->status);
+
+ scbval.val = reason_code;
+ memcpy(&scbval.ea, wl_read_prof(wl, WL_PROF_BSSID), ETH_ALEN);
+ scbval.val = cpu_to_le32(scbval.val);
+ err = wl_dev_ioctl(dev, WLC_DISASSOC, &scbval,
+ sizeof(scb_val_t));
+ if (unlikely(err))
+ WL_ERR("error (%d)\n", err);
+
+ wl->link_up = false;
return err;
}
s32 val;
s32 wsec;
s32 err = 0;
+ u8 keybuf[8];
WL_DBG("key index (%d)\n", key_idx);
CHECK_SYS_UP();
WL_DBG("WLAN_CIPHER_SUITE_WEP104\n");
break;
case WLAN_CIPHER_SUITE_TKIP:
+ memcpy(keybuf, &key.data[24], sizeof(keybuf));
+ memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
+ memcpy(&key.data[16], keybuf, sizeof(keybuf));
key.algo = CRYPTO_ALGO_TKIP;
WL_DBG("WLAN_CIPHER_SUITE_TKIP\n");
break;
static s32 wl_cfg80211_resume(struct wiphy *wiphy)
{
- s32 err = 0;
+ struct wl_priv *wl = wiphy_to_wl(wiphy);
+ struct net_device *ndev = wl_to_ndev(wl);
- CHECK_SYS_UP();
- wl_invoke_iscan(wiphy_to_wl(wiphy));
+ /*
+ * Check for WL_STATUS_READY before any function call which
+ * could result is bus access. Don't block the resume for
+ * any driver error conditions
+ */
- return err;
+#if defined(CONFIG_PM_SLEEP)
+ atomic_set(&dhd_mmc_suspend, false);
+#endif /* defined(CONFIG_PM_SLEEP) */
+
+ if (test_bit(WL_STATUS_READY, &wl->status)) {
+ /* Turn on Watchdog timer */
+ wl_os_wd_timer(ndev, dhd_watchdog_ms);
+ wl_invoke_iscan(wiphy_to_wl(wiphy));
+ }
+
+ return 0;
}
static s32 wl_cfg80211_suspend(struct wiphy *wiphy)
{
struct wl_priv *wl = wiphy_to_wl(wiphy);
struct net_device *ndev = wl_to_ndev(wl);
- s32 err = 0;
+
+
+ /*
+ * Check for WL_STATUS_READY before any function call which
+ * could result is bus access. Don't block the suspend for
+ * any driver error conditions
+ */
+
+ /*
+ * While going to suspend if associated with AP disassociate
+ * from AP to save power while system is in suspended state
+ */
+ if (test_bit(WL_STATUS_CONNECTED, &wl->status) &&
+ test_bit(WL_STATUS_READY, &wl->status)) {
+ WL_INFO("Disassociating from AP"
+ " while entering suspend state\n");
+ wl_link_down(wl);
+
+ /*
+ * Make sure WPA_Supplicant receives all the event
+ * generated due to DISASSOC call to the fw to keep
+ * the state fw and WPA_Supplicant state consistent
+ */
+ rtnl_unlock();
+ wl_delay(500);
+ rtnl_lock();
+ }
set_bit(WL_STATUS_SCAN_ABORTING, &wl->status);
- wl_term_iscan(wl);
+ if (test_bit(WL_STATUS_READY, &wl->status))
+ wl_term_iscan(wl);
+
if (wl->scan_request) {
- cfg80211_scan_done(wl->scan_request, true); /* true means
- abort */
- wl_set_mpc(ndev, 1);
+ /* Indidate scan abort to cfg80211 layer */
+ WL_INFO("Terminating scan in progress\n");
+ cfg80211_scan_done(wl->scan_request, true);
wl->scan_request = NULL;
}
clear_bit(WL_STATUS_SCANNING, &wl->status);
clear_bit(WL_STATUS_SCAN_ABORTING, &wl->status);
+ clear_bit(WL_STATUS_CONNECTING, &wl->status);
+ clear_bit(WL_STATUS_CONNECTED, &wl->status);
- return err;
+ /* Inform SDIO stack not to switch off power to the chip */
+ sdioh_sdio_set_host_pm_flags(MMC_PM_KEEP_POWER);
+
+ /* Turn off watchdog timer */
+ if (test_bit(WL_STATUS_READY, &wl->status)) {
+ WL_INFO("Terminate watchdog timer and enable MPC\n");
+ wl_set_mpc(ndev, 1);
+ wl_os_wd_timer(ndev, 0);
+ }
+
+#if defined(CONFIG_PM_SLEEP)
+ atomic_set(&dhd_mmc_suspend, true);
+#endif /* defined(CONFIG_PM_SLEEP) */
+
+
+ return 0;
}
static __used s32
return err;
}
+
static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi)
{
struct wiphy *wiphy = wl_to_wiphy(wl);
- struct ieee80211_mgmt *mgmt;
- struct ieee80211_channel *channel;
+ struct ieee80211_channel *notify_channel;
+ struct cfg80211_bss *bss;
struct ieee80211_supported_band *band;
- struct wl_cfg80211_bss_info *notif_bss_info;
- struct wl_scan_req *sr = wl_to_sr(wl);
- struct beacon_proberesp *beacon_proberesp;
- s32 mgmt_type;
- u32 signal;
- u32 freq;
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_DBG("Beacon is larger than buffer. Discarding\n");
- return err;
- }
- notif_bss_info =
- kzalloc(sizeof(*notif_bss_info) + sizeof(*mgmt) - sizeof(u8) +
- WL_BSS_INFO_MAX, GFP_KERNEL);
- if (unlikely(!notif_bss_info)) {
- WL_ERR("notif_bss_info alloc failed\n");
- return -ENOMEM;
+ WL_ERR("Bss info is larger than buffer. Discarding\n");
+ return 0;
}
- mgmt = (struct ieee80211_mgmt *)notif_bss_info->frame_buf;
- notif_bss_info->channel =
- bi->ctl_ch ? bi->ctl_ch : CHSPEC_CHANNEL(bi->chanspec);
- if (notif_bss_info->channel <= CH_MAX_2G_CHANNEL)
+ 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];
- notif_bss_info->rssi = bi->RSSI;
- memcpy(mgmt->bssid, &bi->BSSID, ETH_ALEN);
- mgmt_type = wl->active_scan ?
- IEEE80211_STYPE_PROBE_RESP : IEEE80211_STYPE_BEACON;
- if (!memcmp(bi->SSID, sr->ssid.SSID, bi->SSID_len)) {
- mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
- mgmt_type);
- }
- beacon_proberesp = wl->active_scan ?
- (struct beacon_proberesp *)&mgmt->u.probe_resp :
- (struct beacon_proberesp *)&mgmt->u.beacon;
- beacon_proberesp->timestamp = 0;
- beacon_proberesp->beacon_int = cpu_to_le16(bi->beacon_period);
- beacon_proberesp->capab_info = cpu_to_le16(bi->capability);
- wl_rst_ie(wl);
- /*
- * wl_add_ie is not necessary because it can only add duplicated
- * SSID, rate information to frame_buf
- */
- /*
- * wl_add_ie(wl, WLAN_EID_SSID, bi->SSID_len, bi->SSID);
- * wl_add_ie(wl, WLAN_EID_SUPP_RATES, bi->rateset.count,
- * bi->rateset.rates);
- */
- wl_mrg_ie(wl, ((u8 *) bi) + bi->ie_offset, bi->ie_length);
- wl_cp_ie(wl, beacon_proberesp->variable, WL_BSS_INFO_MAX -
- offsetof(struct wl_cfg80211_bss_info, frame_buf));
- notif_bss_info->frame_len =
- offsetof(struct ieee80211_mgmt,
- u.beacon.variable) + wl_get_ielen(wl);
- freq = ieee80211_channel_to_frequency(notif_bss_info->channel,
- band->band);
-
- channel = ieee80211_get_channel(wiphy, freq);
-
- WL_DBG("SSID : \"%s\", rssi %d, channel %d, capability : 0x04%x, bssid %pM\n",
- bi->SSID,
- notif_bss_info->rssi, notif_bss_info->channel,
- mgmt->u.beacon.capab_info, &bi->BSSID);
-
- signal = notif_bss_info->rssi * 100;
- if (unlikely(!cfg80211_inform_bss_frame(wiphy, channel, mgmt,
- le16_to_cpu
- (notif_bss_info->frame_len),
- signal, GFP_KERNEL))) {
+
+ 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_DBG("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_DBG("Channel: %d(%d)\n", channel, freq);
+ WL_DBG("Capability: %X\n", notify_capability);
+ WL_DBG("Beacon interval: %d\n", notify_interval);
+ WL_DBG("Signal: %d\n", notify_signal);
+ WL_DBG("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");
- kfree(notif_bss_info);
return -EINVAL;
}
- kfree(notif_bss_info);
+
+ return err;
+}
+
+static s32
+wl_inform_ibss(struct wl_priv *wl, struct net_device *dev, const u8 *bssid)
+{
+ struct wiphy *wiphy = wl_to_wiphy(wl);
+ struct ieee80211_channel *notify_channel;
+ struct wl_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;
+
+ 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 = wl_dev_ioctl(dev, WLC_GET_BSS_INFO, buf, WL_BSS_INFO_MAX);
+ if (unlikely(err)) {
+ WL_ERR("WLC_GET_BSS_INFO failed: %d\n", err);
+ goto CleanUp;
+ }
+
+ bi = (wl_bss_info_t *)(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_DBG("channel: %d(%d)\n", channel, freq);
+ WL_DBG("capability: %X\n", notify_capability);
+ WL_DBG("beacon interval: %d\n", notify_interval);
+ WL_DBG("signal: %d\n", notify_signal);
+ WL_DBG("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);
return err;
}
static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e)
{
u32 event = be32_to_cpu(e->event_type);
- u16 flags = be16_to_cpu(e->flags);
+ u32 status = be32_to_cpu(e->status);
- if (event == WLC_E_LINK) {
- if (flags & WLC_EVENT_MSG_LINK) {
- if (wl_is_ibssmode(wl)) {
- if (wl_is_ibssstarter(wl)) {
- }
- } else {
- return true;
- }
- }
+ if (event == WLC_E_SET_SSID && status == WLC_E_STATUS_SUCCESS) {
+ WL_DBG("Processing set ssid\n");
+ wl->link_up = true;
+ return true;
}
return false;
u32 event = be32_to_cpu(e->event_type);
u16 flags = be16_to_cpu(e->flags);
- if (event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) {
+ if (event == WLC_E_LINK && (!(flags & WLC_EVENT_MSG_LINK))) {
+ WL_DBG("Processing link down\n");
return true;
- } else if (event == WLC_E_LINK) {
- if (!(flags & WLC_EVENT_MSG_LINK))
- return true;
}
-
return false;
}
{
u32 event = be32_to_cpu(e->event_type);
u32 status = be32_to_cpu(e->status);
+ u16 flags = be16_to_cpu(e->flags);
+
+ if (event == WLC_E_LINK && status == WLC_E_STATUS_NO_NETWORKS) {
+ WL_DBG("Processing Link %s & no network found\n",
+ flags & WLC_EVENT_MSG_LINK ? "up" : "down");
+ return true;
+ }
- if (event == WLC_E_SET_SSID || event == WLC_E_LINK) {
- if (status == WLC_E_STATUS_NO_NETWORKS)
- return true;
+ if (event == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS) {
+ WL_DBG("Processing connecting & no network found\n");
+ return true;
}
return false;
wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
const wl_event_msg_t *e, void *data)
{
- bool act;
s32 err = 0;
if (wl_is_linkup(wl, e)) {
- wl_link_up(wl);
+ WL_DBG("Linkup\n");
if (wl_is_ibssmode(wl)) {
- cfg80211_ibss_joined(ndev, (s8 *)&e->addr,
- GFP_KERNEL);
- WL_DBG("joined in IBSS network\n");
- } else {
+ wl_update_prof(wl, NULL, (void *)e->addr,
+ WL_PROF_BSSID);
+ wl_inform_ibss(wl, ndev, e->addr);
+ cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL);
+ clear_bit(WL_STATUS_CONNECTING, &wl->status);
+ set_bit(WL_STATUS_CONNECTED, &wl->status);
+ } else
wl_bss_connect_done(wl, ndev, e, data, true);
- WL_DBG("joined in BSS network \"%s\"\n",
- ((struct wlc_ssid *)
- wl_read_prof(wl, WL_PROF_SSID))->SSID);
- }
- act = true;
- wl_update_prof(wl, e, &act, WL_PROF_ACT);
} else if (wl_is_linkdown(wl, e)) {
- cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL);
- clear_bit(WL_STATUS_CONNECTED, &wl->status);
- wl_link_down(wl);
+ WL_DBG("Linkdown\n");
+ if (wl_is_ibssmode(wl)) {
+ if (test_and_clear_bit(WL_STATUS_CONNECTED,
+ &wl->status))
+ wl_link_down(wl);
+ } else {
+ if (test_and_clear_bit(WL_STATUS_CONNECTED,
+ &wl->status)) {
+ cfg80211_disconnected(ndev, 0, NULL, 0,
+ GFP_KERNEL);
+ wl_link_down(wl);
+ }
+ }
wl_init_prof(wl->profile);
} else if (wl_is_nonetwork(wl, e)) {
- wl_bss_connect_done(wl, ndev, e, data, false);
+ if (wl_is_ibssmode(wl))
+ clear_bit(WL_STATUS_CONNECTING, &wl->status);
+ else
+ wl_bss_connect_done(wl, ndev, e, data, false);
}
return err;
wl_notify_roaming_status(struct wl_priv *wl, struct net_device *ndev,
const wl_event_msg_t *e, void *data)
{
- bool act;
s32 err = 0;
+ u32 event = be32_to_cpu(e->event_type);
+ u32 status = be32_to_cpu(e->status);
- wl_bss_roaming_done(wl, ndev, e, data);
- act = true;
- wl_update_prof(wl, e, &act, WL_PROF_ACT);
+ if (event == WLC_E_ROAM && status == WLC_E_STATUS_SUCCESS) {
+ if (test_bit(WL_STATUS_CONNECTED, &wl->status))
+ wl_bss_roaming_done(wl, ndev, e, data);
+ else
+ wl_bss_connect_done(wl, ndev, e, data, true);
+ }
return err;
}
u32 resp_len;
s32 err = 0;
+ wl_clear_assoc_ies(wl);
+
err = wl_dev_bufvar_get(ndev, "assoc_info", wl->extra_buf,
WL_ASSOC_INFO_MAX);
if (unlikely(err)) {
return err;
}
+static void wl_clear_assoc_ies(struct wl_priv *wl)
+{
+ struct wl_connect_info *conn_info = wl_to_conn(wl);
+
+ 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 wl_ch_to_chanspec(int ch, struct wl_join_params *join_params,
size_t *join_params_size)
{
join_params->params.chanspec_num = 1;
join_params->params.chanspec_list[0] = ch;
- if (join_params->params.chanspec_list[0])
+ if (join_params->params.chanspec_list[0] <= CH_MAX_2G_CHANNEL)
chanspec |= WL_CHANSPEC_BAND_2G;
else
chanspec |= WL_CHANSPEC_BAND_5G;
static s32 wl_update_bss_info(struct wl_priv *wl)
{
- struct cfg80211_bss *bss;
struct wl_bss_info *bi;
struct wlc_ssid *ssid;
struct bcm_tlv *tim;
return err;
ssid = (struct wlc_ssid *)wl_read_prof(wl, WL_PROF_SSID);
- bss =
- cfg80211_get_bss(wl_to_wiphy(wl), NULL, (s8 *)&wl->bssid,
- ssid->SSID, ssid->SSID_len, WLAN_CAPABILITY_ESS,
- WLAN_CAPABILITY_ESS);
-
- rtnl_lock();
- if (unlikely(!bss)) {
- WL_DBG("Could not find the AP\n");
- *(u32 *) wl->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
- err = wl_dev_ioctl(wl_to_ndev(wl), WLC_GET_BSS_INFO,
- wl->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 wl_bss_info *)(wl->extra_buf + 4);
- if (unlikely(memcmp(&bi->BSSID, &wl->bssid, ETH_ALEN))) {
- err = -EIO;
- goto update_bss_info_out;
- }
- err = wl_inform_single_bss(wl, 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);
- } else {
- WL_DBG("Found the AP in the list - BSSID %pM\n", bss->bssid);
- ie = bss->information_elements;
- ie_len = bss->len_information_elements;
- beacon_interval = bss->beacon_interval;
- cfg80211_put_bss(bss);
+ *(u32 *)wl->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
+ err = wl_dev_ioctl(wl_to_ndev(wl), WLC_GET_BSS_INFO,
+ wl->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 wl_bss_info *)(wl->extra_buf + 4);
+ err = wl_inform_single_bss(wl, 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 = bcm_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
- if (tim) {
+ if (tim)
dtim_period = tim->data[1];
- } else {
+ else {
/*
* active scan was done so we could not get dtim
* information out of probe response.
* so we speficially query dtim information to dongle.
*/
- err = wl_dev_ioctl(wl_to_ndev(wl), WLC_GET_DTIMPRD,
- &dtim_period, sizeof(dtim_period));
+ u32 var;
+ err = wl_dev_intvar_get(wl_to_ndev(wl), "dtim_assoc", &var);
if (unlikely(err)) {
- WL_ERR("WLC_GET_DTIMPRD error (%d)\n", err);
+ WL_ERR("wl dtim_assoc failed (%d)\n", err);
goto update_bss_info_out;
}
+ dtim_period = (u8)var;
}
wl_update_prof(wl, NULL, &beacon_interval, WL_PROF_BEACONINT);
wl_update_prof(wl, NULL, &dtim_period, WL_PROF_DTIMPERIOD);
update_bss_info_out:
- rtnl_unlock();
return err;
}
s32 err = 0;
wl_get_assoc_ies(wl);
- memcpy(&wl->bssid, &e->addr, ETH_ALEN);
+ wl_update_prof(wl, NULL, &e->addr, WL_PROF_BSSID);
wl_update_bss_info(wl);
+
cfg80211_roamed(ndev,
- (u8 *)&wl->bssid,
+ (u8 *)wl_read_prof(wl, WL_PROF_BSSID),
conn_info->req_ie, conn_info->req_ie_len,
conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
WL_DBG("Report roaming result\n");
struct wl_connect_info *conn_info = wl_to_conn(wl);
s32 err = 0;
- wl_get_assoc_ies(wl);
- memcpy(&wl->bssid, &e->addr, ETH_ALEN);
- wl_update_bss_info(wl);
+
if (test_and_clear_bit(WL_STATUS_CONNECTING, &wl->status)) {
+ if (completed) {
+ wl_get_assoc_ies(wl);
+ wl_update_prof(wl, NULL, &e->addr, WL_PROF_BSSID);
+ wl_update_bss_info(wl);
+ }
cfg80211_connect_result(ndev,
- (u8 *)&wl->bssid,
+ (u8 *)wl_read_prof(wl, WL_PROF_BSSID),
conn_info->req_ie,
conn_info->req_ie_len,
conn_info->resp_ie,
conn_info->resp_ie_len,
completed ? WLAN_STATUS_SUCCESS : WLAN_STATUS_AUTH_TIMEOUT,
GFP_KERNEL);
+ if (completed)
+ set_bit(WL_STATUS_CONNECTED, &wl->status);
WL_DBG("Report connect result - connection %s\n",
- completed ? "succeeded" : "failed");
- } else {
- cfg80211_roamed(ndev,
- (u8 *)&wl->bssid,
- conn_info->req_ie, conn_info->req_ie_len,
- conn_info->resp_ie, conn_info->resp_ie_len,
- GFP_KERNEL);
- WL_DBG("Report roaming result\n");
+ completed ? "succeeded" : "failed");
}
- set_bit(WL_STATUS_CONNECTED, &wl->status);
-
return err;
}
{
memset(el, 0, sizeof(*el));
el->handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status;
- el->handler[WLC_E_JOIN] = wl_notify_connect_status;
el->handler[WLC_E_LINK] = wl_notify_connect_status;
- el->handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status;
- el->handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status;
- el->handler[WLC_E_ASSOC_IND] = wl_notify_connect_status;
- el->handler[WLC_E_REASSOC_IND] = wl_notify_connect_status;
el->handler[WLC_E_ROAM] = wl_notify_roaming_status;
el->handler[WLC_E_MIC_ERROR] = wl_notify_mic_status;
el->handler[WLC_E_SET_SSID] = wl_notify_connect_status;
static s32 wl_dongle_mode(struct net_device *ndev, s32 iftype)
{
s32 infra = 0;
- s32 ap = 0;
s32 err = 0;
switch (iftype) {
err = -EINVAL;
return err;
case NL80211_IFTYPE_ADHOC:
+ infra = 0;
break;
case NL80211_IFTYPE_STATION:
infra = 1;
return err;
}
infra = cpu_to_le32(infra);
- ap = cpu_to_le32(ap);
- WL_DBG("%s ap (%d), infra (%d)\n", ndev->name, ap, infra);
err = wl_dev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra));
if (unlikely(err)) {
WL_ERR("WLC_SET_INFRA error (%d)\n", err);
return err;
}
- err = wl_dev_ioctl(ndev, WLC_SET_AP, &ap, sizeof(ap));
- if (unlikely(err)) {
- WL_ERR("WLC_SET_AP error (%d)\n", err);
- return err;
- }
- return -EINPROGRESS;
+ return 0;
}
#ifndef EMBEDDED_PLATFORM
return err;
}
-static s32
-wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
-{
- s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" +
- '\0' + bitvec */
- s32 err = 0;
-
- /* Setup timeout if Beacons are lost and roam is
- off to report link down */
- if (roamvar) {
- bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf,
- sizeof(iovbuf));
- err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
- if (unlikely(err)) {
- WL_ERR("bcn_timeout error (%d)\n", err);
- goto dongle_rom_out;
- }
- }
- /* Enable/Disable built-in roaming to allow supplicant
- to take care of roaming */
- bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
- err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
- if (unlikely(err)) {
- WL_ERR("roam_off error (%d)\n", err);
- goto dongle_rom_out;
- }
-dongle_rom_out:
- return err;
-}
-
-static s32 wl_dongle_eventmsg(struct net_device *ndev)
-{
-
- s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" +
- '\0' + bitvec */
- s8 eventmask[WL_EVENTING_MASK_LEN];
- s32 err = 0;
-
- /* Setup event_msgs */
- bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
- sizeof(iovbuf));
- err = wl_dev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf));
- if (unlikely(err)) {
- WL_ERR("Get event_msgs error (%d)\n", err);
- goto dongle_eventmsg_out;
- }
- memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
-
- setbit(eventmask, WLC_E_SET_SSID);
- setbit(eventmask, WLC_E_PRUNE);
- setbit(eventmask, WLC_E_AUTH);
- setbit(eventmask, WLC_E_REASSOC);
- setbit(eventmask, WLC_E_REASSOC_IND);
- setbit(eventmask, WLC_E_DEAUTH_IND);
- setbit(eventmask, WLC_E_DISASSOC_IND);
- setbit(eventmask, WLC_E_DISASSOC);
- setbit(eventmask, WLC_E_JOIN);
- setbit(eventmask, WLC_E_ASSOC_IND);
- setbit(eventmask, WLC_E_PSK_SUP);
- setbit(eventmask, WLC_E_LINK);
- setbit(eventmask, WLC_E_NDIS_LINK);
- setbit(eventmask, WLC_E_MIC_ERROR);
- setbit(eventmask, WLC_E_PMKID_CACHE);
- setbit(eventmask, WLC_E_TXFAIL);
- setbit(eventmask, WLC_E_JOIN_START);
- setbit(eventmask, WLC_E_SCAN_COMPLETE);
-
- bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
- sizeof(iovbuf));
- err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
- if (unlikely(err)) {
- WL_ERR("Set event_msgs error (%d)\n", err);
- goto dongle_eventmsg_out;
- }
-
-dongle_eventmsg_out:
- return err;
-}
-
-static s32
-wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
- s32 scan_unassoc_time)
-{
- s32 err = 0;
-
- err = wl_dev_ioctl(ndev, WLC_SET_SCAN_CHANNEL_TIME, &scan_assoc_time,
- sizeof(scan_assoc_time));
- if (err) {
- if (err == -EOPNOTSUPP) {
- WL_INFO("Scan assoc time is not supported\n");
- } else {
- WL_ERR("Scan assoc time error (%d)\n", err);
- }
- goto dongle_scantime_out;
- }
- err = wl_dev_ioctl(ndev, WLC_SET_SCAN_UNASSOC_TIME, &scan_unassoc_time,
- sizeof(scan_unassoc_time));
- if (err) {
- if (err == -EOPNOTSUPP) {
- WL_INFO("Scan unassoc time is not supported\n");
- } else {
- WL_ERR("Scan unassoc time error (%d)\n", err);
- }
- goto dongle_scantime_out;
- }
-
-dongle_scantime_out:
- return err;
-}
-
static s32
wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol)
{
}
#endif /* !EMBEDDED_PLATFORM */
+static s32 wl_dongle_eventmsg(struct net_device *ndev)
+{
+ s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" +
+ '\0' + bitvec */
+ s8 eventmask[WL_EVENTING_MASK_LEN];
+ s32 err = 0;
+
+ /* Setup event_msgs */
+ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
+ sizeof(iovbuf));
+ err = wl_dev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf));
+ if (unlikely(err)) {
+ WL_ERR("Get event_msgs error (%d)\n", err);
+ goto dongle_eventmsg_out;
+ }
+ memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
+
+ setbit(eventmask, WLC_E_SET_SSID);
+ setbit(eventmask, WLC_E_ROAM);
+ setbit(eventmask, WLC_E_PRUNE);
+ setbit(eventmask, WLC_E_AUTH);
+ setbit(eventmask, WLC_E_REASSOC);
+ setbit(eventmask, WLC_E_REASSOC_IND);
+ setbit(eventmask, WLC_E_DEAUTH_IND);
+ setbit(eventmask, WLC_E_DISASSOC_IND);
+ setbit(eventmask, WLC_E_DISASSOC);
+ setbit(eventmask, WLC_E_JOIN);
+ setbit(eventmask, WLC_E_ASSOC_IND);
+ setbit(eventmask, WLC_E_PSK_SUP);
+ setbit(eventmask, WLC_E_LINK);
+ setbit(eventmask, WLC_E_NDIS_LINK);
+ setbit(eventmask, WLC_E_MIC_ERROR);
+ setbit(eventmask, WLC_E_PMKID_CACHE);
+ setbit(eventmask, WLC_E_TXFAIL);
+ setbit(eventmask, WLC_E_JOIN_START);
+ setbit(eventmask, WLC_E_SCAN_COMPLETE);
+
+ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
+ sizeof(iovbuf));
+ err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
+ if (unlikely(err)) {
+ WL_ERR("Set event_msgs error (%d)\n", err);
+ goto dongle_eventmsg_out;
+ }
+
+dongle_eventmsg_out:
+ return err;
+}
+
+static s32
+wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
+{
+ s8 iovbuf[32];
+ s32 roamtrigger[2];
+ s32 roam_delta[2];
+ s32 err = 0;
+
+ /*
+ * Setup timeout if Beacons are lost and roam is
+ * off to report link down
+ */
+ if (roamvar) {
+ bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout,
+ sizeof(bcn_timeout), iovbuf, sizeof(iovbuf));
+ err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
+ if (unlikely(err)) {
+ WL_ERR("bcn_timeout error (%d)\n", err);
+ goto dongle_rom_out;
+ }
+ }
+
+ /*
+ * Enable/Disable built-in roaming to allow supplicant
+ * to take care of roaming
+ */
+ WL_INFO("Internal Roaming = %s\n", roamvar ? "Off" : "On");
+ bcm_mkiovar("roam_off", (char *)&roamvar,
+ sizeof(roamvar), iovbuf, sizeof(iovbuf));
+ err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
+ if (unlikely(err)) {
+ WL_ERR("roam_off error (%d)\n", err);
+ goto dongle_rom_out;
+ }
+
+ roamtrigger[0] = WL_ROAM_TRIGGER_LEVEL;
+ roamtrigger[1] = WLC_BAND_ALL;
+ err = wl_dev_ioctl(ndev, WLC_SET_ROAM_TRIGGER,
+ (void *)roamtrigger, sizeof(roamtrigger));
+ if (unlikely(err)) {
+ WL_ERR("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
+ goto dongle_rom_out;
+ }
+
+ roam_delta[0] = WL_ROAM_DELTA;
+ roam_delta[1] = WLC_BAND_ALL;
+ err = wl_dev_ioctl(ndev, WLC_SET_ROAM_DELTA,
+ (void *)roam_delta, sizeof(roam_delta));
+ if (unlikely(err)) {
+ WL_ERR("WLC_SET_ROAM_DELTA error (%d)\n", err);
+ goto dongle_rom_out;
+ }
+
+dongle_rom_out:
+ return err;
+}
+
+static s32
+wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
+ s32 scan_unassoc_time, s32 scan_passive_time)
+{
+ s32 err = 0;
+
+ err = wl_dev_ioctl(ndev, WLC_SET_SCAN_CHANNEL_TIME, &scan_assoc_time,
+ sizeof(scan_assoc_time));
+ if (err) {
+ if (err == -EOPNOTSUPP)
+ WL_INFO("Scan assoc time is not supported\n");
+ else
+ WL_ERR("Scan assoc time error (%d)\n", err);
+ goto dongle_scantime_out;
+ }
+ err = wl_dev_ioctl(ndev, WLC_SET_SCAN_UNASSOC_TIME, &scan_unassoc_time,
+ sizeof(scan_unassoc_time));
+ if (err) {
+ if (err == -EOPNOTSUPP)
+ WL_INFO("Scan unassoc time is not supported\n");
+ else
+ WL_ERR("Scan unassoc time error (%d)\n", err);
+ goto dongle_scantime_out;
+ }
+
+ err = wl_dev_ioctl(ndev, WLC_SET_SCAN_PASSIVE_TIME, &scan_passive_time,
+ sizeof(scan_passive_time));
+ if (err) {
+ if (err == -EOPNOTSUPP)
+ WL_INFO("Scan passive time is not supported\n");
+ else
+ WL_ERR("Scan passive time error (%d)\n", err);
+ goto dongle_scantime_out;
+ }
+
+dongle_scantime_out:
+ return err;
+}
+
s32 wl_config_dongle(struct wl_priv *wl, bool need_lock)
{
#ifndef DHD_SDALIGN
if (unlikely(err))
goto default_conf_out;
err = wl_dongle_glom(ndev, 0, DHD_SDALIGN);
- if (unlikely(err))
- goto default_conf_out;
- err = wl_dongle_roam(ndev, (wl->roam_on ? 0 : 1), 3);
- if (unlikely(err))
- goto default_conf_out;
- err = wl_dongle_eventmsg(ndev);
if (unlikely(err))
goto default_conf_out;
- wl_dongle_scantime(ndev, 40, 80);
wl_dongle_offload(ndev, 1, 0xf);
wl_dongle_filter(ndev, 1);
-#endif /* !EMBEDDED_PLATFORM */
+#endif /* !EMBEDDED_PLATFORM */
+
+ wl_dongle_scantime(ndev, WL_SCAN_CHANNEL_TIME,
+ WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
+ err = wl_dongle_eventmsg(ndev);
+ if (unlikely(err))
+ goto default_conf_out;
+ err = wl_dongle_roam(ndev, (wl->roam_on ? 0 : 1), WL_BEACON_TIMEOUT);
+ if (unlikely(err))
+ goto default_conf_out;
err = wl_dongle_mode(ndev, wdev->iftype);
if (unlikely(err && err != -EINPROGRESS))
goto default_conf_out;
return wl->conf->mode == WL_MODE_IBSS;
}
-static bool wl_is_ibssstarter(struct wl_priv *wl)
-{
- return wl->ibss_starter;
-}
-
-static void wl_rst_ie(struct wl_priv *wl)
-{
- struct wl_ie *ie = wl_to_ie(wl);
-
- ie->offset = 0;
-}
-
static __used s32 wl_add_ie(struct wl_priv *wl, u8 t, u8 l, u8 *v)
{
struct wl_ie *ie = wl_to_ie(wl);
return err;
}
-static s32 wl_mrg_ie(struct wl_priv *wl, u8 *ie_stream, u16 ie_size)
-{
- struct wl_ie *ie = wl_to_ie(wl);
- s32 err = 0;
- if (unlikely(ie->offset + ie_size > WL_TLV_INFO_MAX)) {
- WL_ERR("ei_stream crosses buffer boundary\n");
- return -ENOSPC;
- }
- memcpy(&ie->buf[ie->offset], ie_stream, ie_size);
- ie->offset += ie_size;
-
- return err;
-}
-
-static s32 wl_cp_ie(struct wl_priv *wl, u8 *dst, u16 dst_size)
+static void wl_link_down(struct wl_priv *wl)
{
- struct wl_ie *ie = wl_to_ie(wl);
+ struct net_device *dev = NULL;
s32 err = 0;
- if (unlikely(ie->offset > dst_size)) {
- WL_ERR("dst_size is not enough\n");
- return -ENOSPC;
- }
- memcpy(dst, &ie->buf[0], ie->offset);
-
- return err;
-}
-
-static u32 wl_get_ielen(struct wl_priv *wl)
-{
- struct wl_ie *ie = wl_to_ie(wl);
-
- return ie->offset;
-}
-
-static void wl_link_up(struct wl_priv *wl)
-{
- wl->link_up = true;
-}
-
-static void wl_link_down(struct wl_priv *wl)
-{
- struct wl_connect_info *conn_info = wl_to_conn(wl);
+ clear_bit(WL_STATUS_CONNECTED, &wl->status);
- wl->link_up = false;
- 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;
+ if (wl->link_up) {
+ dev = wl_to_ndev(wl);
+ WL_INFO("Call WLC_DISASSOC to stop excess roaming\n ");
+ err = wl_dev_ioctl(dev, WLC_DISASSOC, NULL, 0);
+ if (unlikely(err))
+ WL_ERR("WLC_DISASSOC failed (%d)\n", err);
+ wl->link_up = false;
+ }
}
static void wl_lock_eq(struct wl_priv *wl)