Commit ffd6e890 authored by Franky Lin's avatar Franky Lin Committed by Greg Kroah-Hartman

staging: brcm80211: remove static function declaration in wl_cfg80211

Reshuffle function order in wl_cfg80211 of fullmac to get rid of
static function declaration
Reported-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Reviewed-by: default avatarArend van Spriel <arend@broadcom.com>
Reviewed-by: default avatarRoland Vossen <rvossen@broadcom.com>
Signed-off-by: default avatarRoland Vossen <rvossen@broadcom.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 6f42a9e5
...@@ -40,269 +40,19 @@ static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255}; ...@@ -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; static u32 brcmf_dbg_level = WL_DBG_ERR;
/* static void brcmf_set_drvdata(struct brcmf_cfg80211_dev *dev, void *data)
** cfg80211_ops api/callback list {
*/ dev->driver_data = data;
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);
/*
** 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);
/*
** 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); static void *brcmf_get_drvdata(struct brcmf_cfg80211_dev *dev)
{
void *data = NULL;
/* if (dev)
* debufs support data = dev->driver_data;
*/ return data;
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);
static static
struct brcmf_cfg80211_priv *brcmf_priv_get(struct brcmf_cfg80211_dev *cfg_dev) struct brcmf_cfg80211_priv *brcmf_priv_get(struct brcmf_cfg80211_dev *cfg_dev)
...@@ -594,6 +344,63 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, ...@@ -594,6 +344,63 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
return err; 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, static void wl_iscan_prep(struct brcmf_scan_params *params,
struct brcmf_ssid *ssid) struct brcmf_ssid *ssid)
{ {
...@@ -820,48 +627,6 @@ brcmf_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, ...@@ -820,48 +627,6 @@ brcmf_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
return err; 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) static s32 brcmf_set_rts(struct net_device *dev, u32 rts_threshold)
{ {
s32 err = 0; s32 err = 0;
...@@ -942,40 +707,152 @@ static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) ...@@ -942,40 +707,152 @@ static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
return err; 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 static s32
brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, brcmf_update_prof(struct brcmf_cfg80211_priv *cfg_priv,
struct cfg80211_ibss_params *params) const struct brcmf_event_msg *e, void *data, s32 item)
{ {
struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
struct brcmf_join_params join_params;
size_t join_params_size = 0;
s32 err = 0; s32 err = 0;
s32 wsec = 0; struct brcmf_ssid *ssid;
s32 bcnprd;
WL_TRACE("Enter\n");
if (!check_sys_up(wiphy))
return -EIO;
if (params->ssid) switch (item) {
WL_CONN("SSID: %s\n", params->ssid); case WL_PROF_SSID:
else { ssid = (struct brcmf_ssid *) data;
WL_CONN("SSID: NULL, Not supported\n"); memset(cfg_priv->profile->ssid.SSID, 0,
return -EOPNOTSUPP; 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;
} }
set_bit(WL_STATUS_CONNECTING, &cfg_priv->status); return err;
}
if (params->bssid) static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
WL_CONN("BSSID: %02X %02X %02X %02X %02X %02X\n", {
params->bssid[0], params->bssid[1], params->bssid[2], memset(prof, 0, sizeof(*prof));
params->bssid[3], params->bssid[4], params->bssid[5]); }
else
WL_CONN("No BSSID specified\n");
if (params->channel) static void brcmf_ch_to_chanspec(int ch, struct brcmf_join_params *join_params,
WL_CONN("channel: %d\n", params->channel->center_freq); size_t *join_params_size)
else {
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)
{
struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
struct brcmf_join_params join_params;
size_t join_params_size = 0;
s32 err = 0;
s32 wsec = 0;
s32 bcnprd;
WL_TRACE("Enter\n");
if (!check_sys_up(wiphy))
return -EIO;
if (params->ssid)
WL_CONN("SSID: %s\n", params->ssid);
else {
WL_CONN("SSID: NULL, Not supported\n");
return -EOPNOTSUPP;
}
set_bit(WL_STATUS_CONNECTING, &cfg_priv->status);
if (params->bssid)
WL_CONN("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_CONN("No BSSID specified\n");
if (params->channel)
WL_CONN("channel: %d\n", params->channel->center_freq);
else
WL_CONN("no channel specified\n"); WL_CONN("no channel specified\n");
if (params->channel_fixed) if (params->channel_fixed)
...@@ -2071,122 +1948,615 @@ brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev, ...@@ -2071,122 +1948,615 @@ brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev,
return err; return err;
} }
static s32 brcmf_cfg80211_resume(struct wiphy *wiphy) static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_priv *cfg_priv,
struct brcmf_bss_info *bi)
{ {
struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); struct wiphy *wiphy = cfg_to_wiphy(cfg_priv);
struct ieee80211_channel *notify_channel;
/* struct cfg80211_bss *bss;
* Check for WL_STATUS_READY before any function call which struct ieee80211_supported_band *band;
* could result is bus access. Don't block the resume for s32 err = 0;
* any driver error conditions u16 channel;
*/ u32 freq;
WL_TRACE("Enter\n"); u64 notify_timestamp;
u16 notify_capability;
if (test_bit(WL_STATUS_READY, &cfg_priv->status)) u16 notify_interval;
brcmf_invoke_iscan(wiphy_to_cfg(wiphy)); u8 *notify_ie;
size_t notify_ielen;
s32 notify_signal;
WL_TRACE("Exit\n"); if (unlikely(le32_to_cpu(bi->length) > WL_BSS_INFO_MAX)) {
WL_ERR("Bss info is larger than buffer. Discarding\n");
return 0; return 0;
} }
static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
struct cfg80211_wowlan *wow)
{
struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
struct net_device *ndev = cfg_to_ndev(cfg_priv);
WL_TRACE("Enter\n"); channel = bi->ctl_ch ? bi->ctl_ch :
CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
/* if (channel <= CH_MAX_2G_CHANNEL)
* Check for WL_STATUS_READY before any function call which band = wiphy->bands[IEEE80211_BAND_2GHZ];
* could result is bus access. Don't block the suspend for else
* any driver error conditions band = wiphy->bands[IEEE80211_BAND_5GHZ];
*/
/* freq = ieee80211_channel_to_frequency(channel, band->band);
* While going to suspend if associated with AP disassociate notify_channel = ieee80211_get_channel(wiphy, freq);
* from AP to save power while system is in suspended state
*/
if ((test_bit(WL_STATUS_CONNECTED, &cfg_priv->status) ||
test_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) &&
test_bit(WL_STATUS_READY, &cfg_priv->status)) {
WL_INFO("Disassociating from AP"
" while entering suspend state\n");
brcmf_link_down(cfg_priv);
/* notify_timestamp = jiffies_to_msecs(jiffies)*1000; /* uSec */
* Make sure WPA_Supplicant receives all the event notify_capability = le16_to_cpu(bi->capability);
* generated due to DISASSOC call to the fw to keep notify_interval = le16_to_cpu(bi->beacon_period);
* the state fw and WPA_Supplicant state consistent notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
*/ notify_ielen = le16_to_cpu(bi->ie_length);
rtnl_unlock(); notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
brcmf_delay(500);
rtnl_lock();
}
set_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status); WL_CONN("bssid: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
if (test_bit(WL_STATUS_READY, &cfg_priv->status)) bi->BSSID[0], bi->BSSID[1], bi->BSSID[2],
brcmf_term_iscan(cfg_priv); 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);
if (cfg_priv->scan_request) { bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID,
/* Indidate scan abort to cfg80211 layer */ notify_timestamp, notify_capability, notify_interval, notify_ie,
WL_INFO("Terminating scan in progress\n"); notify_ielen, notify_signal, GFP_KERNEL);
cfg80211_scan_done(cfg_priv->scan_request, true);
cfg_priv->scan_request = NULL;
}
clear_bit(WL_STATUS_SCANNING, &cfg_priv->status);
clear_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status);
/* Turn off watchdog timer */ if (unlikely(!bss)) {
if (test_bit(WL_STATUS_READY, &cfg_priv->status)) { WL_ERR("cfg80211_inform_bss_frame error\n");
WL_INFO("Enable MPC\n"); return -EINVAL;
brcmf_set_mpc(ndev, 1);
} }
WL_TRACE("Exit\n"); return err;
return 0;
} }
static __used s32 static s32 brcmf_inform_bss(struct brcmf_cfg80211_priv *cfg_priv)
brcmf_update_pmklist(struct net_device *dev,
struct brcmf_cfg80211_pmk_list *pmk_list, s32 err)
{ {
int i, j; struct brcmf_scan_results *bss_list;
struct brcmf_bss_info *bi = NULL; /* must be initialized */
s32 err = 0;
int i;
WL_CONN("No of elements %d\n", pmk_list->pmkids.npmkid); bss_list = cfg_priv->bss_list;
for (i = 0; i < pmk_list->pmkids.npmkid; i++) { if (unlikely(bss_list->version != BRCMF_BSS_INFO_VERSION)) {
WL_CONN("PMKID[%d]: %pM =\n", i, WL_ERR("Version %d != WL_BSS_INFO_VERSION\n",
&pmk_list->pmkids.pmkid[i].BSSID); bss_list->version);
for (j = 0; j < WLAN_PMKID_LEN; j++) return -EOPNOTSUPP;
WL_CONN("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j]); }
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;
} }
if (likely(!err))
brcmf_dev_bufvar_set(dev, "pmkid_info", (char *)pmk_list,
sizeof(*pmk_list));
return err; return err;
} }
static s32 static s32 wl_inform_ibss(struct brcmf_cfg80211_priv *cfg_priv,
brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev, struct net_device *dev, const u8 *bssid)
struct cfg80211_pmksa *pmksa)
{ {
struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); struct wiphy *wiphy = cfg_to_wiphy(cfg_priv);
struct pmkid_list *pmkids = &cfg_priv->pmk_list->pmkids; struct ieee80211_channel *notify_channel;
struct brcmf_bss_info *bi = NULL;
struct ieee80211_supported_band *band;
u8 *buf = NULL;
s32 err = 0; s32 err = 0;
int i; 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"); WL_TRACE("Enter\n");
if (!check_sys_up(wiphy))
return -EIO;
for (i = 0; i < pmkids->npmkid; i++) buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN)) if (buf == NULL) {
break; WL_ERR("kzalloc() failed\n");
if (i < WL_NUM_PMKIDS_MAX) { err = -ENOMEM;
memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN); 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);
/*
* 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
*/
WL_TRACE("Enter\n");
if (test_bit(WL_STATUS_READY, &cfg_priv->status))
brcmf_invoke_iscan(wiphy_to_cfg(wiphy));
WL_TRACE("Exit\n");
return 0;
}
static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
struct cfg80211_wowlan *wow)
{
struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
struct net_device *ndev = cfg_to_ndev(cfg_priv);
WL_TRACE("Enter\n");
/*
* 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, &cfg_priv->status) ||
test_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) &&
test_bit(WL_STATUS_READY, &cfg_priv->status)) {
WL_INFO("Disassociating from AP"
" while entering suspend state\n");
brcmf_link_down(cfg_priv);
/*
* 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();
brcmf_delay(500);
rtnl_lock();
}
set_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status);
if (test_bit(WL_STATUS_READY, &cfg_priv->status))
brcmf_term_iscan(cfg_priv);
if (cfg_priv->scan_request) {
/* Indidate scan abort to cfg80211 layer */
WL_INFO("Terminating scan in progress\n");
cfg80211_scan_done(cfg_priv->scan_request, true);
cfg_priv->scan_request = NULL;
}
clear_bit(WL_STATUS_SCANNING, &cfg_priv->status);
clear_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status);
/* Turn off watchdog timer */
if (test_bit(WL_STATUS_READY, &cfg_priv->status)) {
WL_INFO("Enable MPC\n");
brcmf_set_mpc(ndev, 1);
}
WL_TRACE("Exit\n");
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)
{
int i, j;
WL_CONN("No of elements %d\n", pmk_list->pmkids.npmkid);
for (i = 0; i < pmk_list->pmkids.npmkid; i++) {
WL_CONN("PMKID[%d]: %pM =\n", i,
&pmk_list->pmkids.pmkid[i].BSSID);
for (j = 0; j < WLAN_PMKID_LEN; j++)
WL_CONN("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j]);
}
if (likely(!err))
brcmf_dev_bufvar_set(dev, "pmkid_info", (char *)pmk_list,
sizeof(*pmk_list));
return err;
}
static s32
brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_pmksa *pmksa)
{
struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
struct pmkid_list *pmkids = &cfg_priv->pmk_list->pmkids;
s32 err = 0;
int i;
WL_TRACE("Enter\n");
if (!check_sys_up(wiphy))
return -EIO;
for (i = 0; i < pmkids->npmkid; i++)
if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN))
break;
if (i < WL_NUM_PMKIDS_MAX) {
memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN);
memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN); memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
if (i == pmkids->npmkid) if (i == pmkids->npmkid)
pmkids->npmkid++; pmkids->npmkid++;
...@@ -2382,165 +2752,6 @@ static void brcmf_free_wdev(struct brcmf_cfg80211_priv *cfg_priv) ...@@ -2382,165 +2752,6 @@ static void brcmf_free_wdev(struct brcmf_cfg80211_priv *cfg_priv)
cfg_priv->wdev = NULL; 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, static bool brcmf_is_linkup(struct brcmf_cfg80211_priv *cfg_priv,
const struct brcmf_event_msg *e) const struct brcmf_event_msg *e)
{ {
...@@ -2560,134 +2771,46 @@ static bool brcmf_is_linkdown(struct brcmf_cfg80211_priv *cfg_priv, ...@@ -2560,134 +2771,46 @@ static bool brcmf_is_linkdown(struct brcmf_cfg80211_priv *cfg_priv,
const struct brcmf_event_msg *e) const struct brcmf_event_msg *e)
{ {
u32 event = be32_to_cpu(e->event_type); u32 event = be32_to_cpu(e->event_type);
u16 flags = be16_to_cpu(e->flags); u16 flags = be16_to_cpu(e->flags);
if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) {
WL_CONN("Processing link down\n");
return true;
}
return false;
}
static bool brcmf_is_nonetwork(struct brcmf_cfg80211_priv *cfg_priv,
const struct brcmf_event_msg *e)
{
u32 event = be32_to_cpu(e->event_type);
u32 status = be32_to_cpu(e->status);
if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
WL_CONN("Processing Link %s & no network found\n",
be16_to_cpu(e->flags) & BRCMF_EVENT_MSG_LINK ?
"up" : "down");
return true;
}
if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
WL_CONN("Processing connecting & no network found\n");
return true;
}
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)
{
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; if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) {
WL_CONN("Processing link down\n");
return true;
}
return false;
} }
static s32 static bool brcmf_is_nonetwork(struct brcmf_cfg80211_priv *cfg_priv,
brcmf_notify_roaming_status(struct brcmf_cfg80211_priv *cfg_priv, const struct brcmf_event_msg *e)
struct net_device *ndev,
const struct brcmf_event_msg *e, void *data)
{ {
s32 err = 0;
u32 event = be32_to_cpu(e->event_type); u32 event = be32_to_cpu(e->event_type);
u32 status = be32_to_cpu(e->status); u32 status = be32_to_cpu(e->status);
if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) { if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
if (test_bit(WL_STATUS_CONNECTED, &cfg_priv->status)) WL_CONN("Processing Link %s & no network found\n",
brcmf_bss_roaming_done(cfg_priv, ndev, e); be16_to_cpu(e->flags) & BRCMF_EVENT_MSG_LINK ?
else "up" : "down");
brcmf_bss_connect_done(cfg_priv, ndev, e, true); return true;
} }
return err; if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
} WL_CONN("Processing connecting & no network found\n");
return true;
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, return false;
buflen);
} }
static s32 static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv)
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); struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv);
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) 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) ...@@ -2748,114 +2871,6 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv)
return err; 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 static s32
brcmf_bss_roaming_done(struct brcmf_cfg80211_priv *cfg_priv, brcmf_bss_roaming_done(struct brcmf_cfg80211_priv *cfg_priv,
struct net_device *ndev, struct net_device *ndev,
...@@ -2895,44 +2910,108 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_priv *cfg_priv, ...@@ -2895,44 +2910,108 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_priv *cfg_priv,
conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL); conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
WL_CONN("Report roaming result\n"); WL_CONN("Report roaming result\n");
set_bit(WL_STATUS_CONNECTED, &cfg_priv->status); set_bit(WL_STATUS_CONNECTED, &cfg_priv->status);
WL_TRACE("Exit\n"); WL_TRACE("Exit\n");
return err;
}
static s32
brcmf_bss_connect_done(struct brcmf_cfg80211_priv *cfg_priv,
struct net_device *ndev, const struct brcmf_event_msg *e,
bool completed)
{
struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv);
s32 err = 0;
WL_TRACE("Enter\n");
if (test_and_clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) {
if (completed) {
brcmf_get_assoc_ies(cfg_priv);
brcmf_update_prof(cfg_priv, NULL, &e->addr,
WL_PROF_BSSID);
brcmf_update_bss_info(cfg_priv);
}
cfg80211_connect_result(ndev,
(u8 *)brcmf_read_prof(cfg_priv,
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, &cfg_priv->status);
WL_CONN("Report connect result - connection %s\n",
completed ? "succeeded" : "failed");
}
WL_TRACE("Exit\n");
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; return err;
} }
static s32 static s32
brcmf_bss_connect_done(struct brcmf_cfg80211_priv *cfg_priv, brcmf_notify_roaming_status(struct brcmf_cfg80211_priv *cfg_priv,
struct net_device *ndev, const struct brcmf_event_msg *e, struct net_device *ndev,
bool completed) const struct brcmf_event_msg *e, void *data)
{ {
struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv);
s32 err = 0; s32 err = 0;
u32 event = be32_to_cpu(e->event_type);
u32 status = be32_to_cpu(e->status);
WL_TRACE("Enter\n"); if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
if (test_bit(WL_STATUS_CONNECTED, &cfg_priv->status))
if (test_and_clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) { brcmf_bss_roaming_done(cfg_priv, ndev, e);
if (completed) { else
brcmf_get_assoc_ies(cfg_priv); brcmf_bss_connect_done(cfg_priv, ndev, e, true);
brcmf_update_prof(cfg_priv, NULL, &e->addr,
WL_PROF_BSSID);
brcmf_update_bss_info(cfg_priv);
}
cfg80211_connect_result(ndev,
(u8 *)brcmf_read_prof(cfg_priv,
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, &cfg_priv->status);
WL_CONN("Report connect result - connection %s\n",
completed ? "succeeded" : "failed");
} }
WL_TRACE("Exit\n");
return err; return err;
} }
...@@ -3041,11 +3120,6 @@ static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf) ...@@ -3041,11 +3120,6 @@ static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
conf->tx_power = -1; 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) static void brcmf_init_eloop_handler(struct brcmf_cfg80211_event_loop *el)
{ {
memset(el, 0, sizeof(*el)); memset(el, 0, sizeof(*el));
...@@ -3056,6 +3130,28 @@ static void brcmf_init_eloop_handler(struct brcmf_cfg80211_event_loop *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; 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) static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_priv *cfg_priv)
{ {
cfg_priv->scan_results = kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL); cfg_priv->scan_results = kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL);
...@@ -3113,271 +3209,156 @@ static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_priv *cfg_priv) ...@@ -3113,271 +3209,156 @@ static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_priv *cfg_priv)
return -ENOMEM; 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); spin_lock_irq(&cfg_priv->eq_lock);
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_create_event_handler(struct brcmf_cfg80211_priv *cfg_priv) static void brcmf_unlock_eq(struct brcmf_cfg80211_priv *cfg_priv)
{ {
init_waitqueue_head(&cfg_priv->event_waitq); spin_unlock_irq(&cfg_priv->eq_lock);
cfg_priv->event_tsk = kthread_run(brcmf_event_handler, cfg_priv,
"wl_event_handler");
if (IS_ERR(cfg_priv->event_tsk)) {
cfg_priv->event_tsk = NULL;
WL_ERR("failed to create event thread\n");
return -ENOMEM;
}
return 0;
} }
static void brcmf_destroy_event_handler(struct brcmf_cfg80211_priv *cfg_priv) static void brcmf_init_eq_lock(struct brcmf_cfg80211_priv *cfg_priv)
{ {
if (cfg_priv->event_tsk) { spin_lock_init(&cfg_priv->eq_lock);
send_sig(SIGTERM, cfg_priv->event_tsk, 1);
kthread_stop(cfg_priv->event_tsk);
cfg_priv->event_tsk = NULL;
}
} }
static void brcmf_term_iscan(struct brcmf_cfg80211_priv *cfg_priv) /*
{ * retrieve first queued event from head
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, static struct brcmf_cfg80211_event_q *brcmf_deq_event(
bool aborted) struct brcmf_cfg80211_priv *cfg_priv)
{ {
struct brcmf_cfg80211_priv *cfg_priv = iscan_to_cfg(iscan); struct brcmf_cfg80211_event_q *e = NULL;
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) brcmf_lock_eq(cfg_priv);
{ if (likely(!list_empty(&cfg_priv->eq_list))) {
if (likely(iscan->state != WL_ISCAN_STATE_IDLE)) { e = list_first_entry(&cfg_priv->eq_list,
WL_SCAN("wake up iscan\n"); struct brcmf_cfg80211_event_q, eq_list);
schedule_work(&iscan->work); list_del(&e->eq_list);
return 0;
} }
brcmf_unlock_eq(cfg_priv);
return -EIO; return e;
} }
/*
** push event to tail of the queue
*/
static s32 static s32
brcmf_get_iscan_results(struct brcmf_cfg80211_iscan_ctrl *iscan, u32 *status, brcmf_enq_event(struct brcmf_cfg80211_priv *cfg_priv, u32 event,
struct brcmf_scan_results **bss_list) const struct brcmf_event_msg *msg)
{ {
struct brcmf_iscan_results list; struct brcmf_cfg80211_event_q *e;
struct brcmf_scan_results *results;
struct brcmf_iscan_results *list_buf;
s32 err = 0; s32 err = 0;
memset(iscan->scan_buf, 0, WL_ISCAN_BUF_MAX); e = kzalloc(sizeof(struct brcmf_cfg80211_event_q), GFP_KERNEL);
list_buf = (struct brcmf_iscan_results *)iscan->scan_buf; if (unlikely(!e)) {
results = &list_buf->results; WL_ERR("event alloc failed\n");
results->buflen = BRCMF_ISCAN_RESULTS_FIXED_SIZE; return -ENOMEM;
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) e->etype = event;
{ memcpy(&e->emsg, msg, sizeof(struct brcmf_event_msg));
struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan;
s32 err = 0;
rtnl_lock(); brcmf_lock_eq(cfg_priv);
brcmf_inform_bss(cfg_priv); list_add_tail(&e->eq_list, &cfg_priv->eq_list);
brcmf_run_iscan(iscan, NULL, BRCMF_SCAN_ACTION_CONTINUE); brcmf_unlock_eq(cfg_priv);
rtnl_unlock();
/* Reschedule the timer */
mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
iscan->timer_on = 1;
return err; return err;
} }
static s32 brcmf_iscan_aborted(struct brcmf_cfg80211_priv *cfg_priv) static void brcmf_put_event(struct brcmf_cfg80211_event_q *e)
{ {
struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan; kfree(e);
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) static s32 brcmf_event_handler(void *data)
{ {
struct brcmf_cfg80211_iscan_ctrl *iscan = struct brcmf_cfg80211_priv *cfg_priv =
container_of(work, struct brcmf_cfg80211_iscan_ctrl, (struct brcmf_cfg80211_priv *)data;
work); struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1 };
struct brcmf_cfg80211_priv *cfg_priv = iscan_to_cfg(iscan); struct brcmf_cfg80211_event_q *e;
struct brcmf_cfg80211_iscan_eloop *el = &iscan->el; DECLARE_WAITQUEUE(wait, current);
u32 status = BRCMF_SCAN_RESULTS_PARTIAL;
if (iscan->timer_on) { sched_setscheduler(current, SCHED_FIFO, &param);
del_timer_sync(&iscan->timer); allow_signal(SIGTERM);
iscan->timer_on = 0; add_wait_queue(&cfg_priv->event_waitq, &wait);
} while (1) {
prepare_to_wait(&cfg_priv->event_waitq, &wait,
TASK_INTERRUPTIBLE);
rtnl_lock(); schedule();
if (brcmf_get_iscan_results(iscan, &status, &cfg_priv->bss_list)) {
status = BRCMF_SCAN_RESULTS_ABORTED; if (kthread_should_stop())
WL_ERR("Abort iscan\n"); break;
e = brcmf_deq_event(cfg_priv);
if (unlikely(!e)) {
WL_ERR("event queue empty...\n");
continue;
} }
rtnl_unlock();
el->handler[status](cfg_priv); 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 void brcmf_iscan_timer(unsigned long data) static s32 brcmf_create_event_handler(struct brcmf_cfg80211_priv *cfg_priv)
{ {
struct brcmf_cfg80211_iscan_ctrl *iscan = init_waitqueue_head(&cfg_priv->event_waitq);
(struct brcmf_cfg80211_iscan_ctrl *)data; cfg_priv->event_tsk = kthread_run(brcmf_event_handler, cfg_priv,
"wl_event_handler");
if (iscan) { if (IS_ERR(cfg_priv->event_tsk)) {
iscan->timer_on = 0; cfg_priv->event_tsk = NULL;
WL_SCAN("timer expired\n"); WL_ERR("failed to create event thread\n");
brcmf_wakeup_iscan(iscan); return -ENOMEM;
} }
return 0;
} }
static s32 brcmf_invoke_iscan(struct brcmf_cfg80211_priv *cfg_priv) static void brcmf_destroy_event_handler(struct brcmf_cfg80211_priv *cfg_priv)
{ {
struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv); if (cfg_priv->event_tsk) {
send_sig(SIGTERM, cfg_priv->event_tsk, 1);
if (cfg_priv->iscan_on) { kthread_stop(cfg_priv->event_tsk);
iscan->state = WL_ISCAN_STATE_IDLE; cfg_priv->event_tsk = NULL;
INIT_WORK(&iscan->work, brcmf_cfg80211_iscan_handler);
} }
return 0;
} }
static void brcmf_init_iscan_eloop(struct brcmf_cfg80211_iscan_eloop *el) static void brcmf_init_eq(struct brcmf_cfg80211_priv *cfg_priv)
{ {
memset(el, 0, sizeof(*el)); brcmf_init_eq_lock(cfg_priv);
el->handler[BRCMF_SCAN_RESULTS_SUCCESS] = brcmf_iscan_done; INIT_LIST_HEAD(&cfg_priv->eq_list);
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) static void brcmf_flush_eq(struct brcmf_cfg80211_priv *cfg_priv)
{ {
struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv); struct brcmf_cfg80211_event_q *e;
int err = 0;
if (cfg_priv->iscan_on) { brcmf_lock_eq(cfg_priv);
iscan->dev = cfg_to_ndev(cfg_priv); while (!list_empty(&cfg_priv->eq_list)) {
brcmf_init_iscan_eloop(&iscan->el); e = list_first_entry(&cfg_priv->eq_list,
iscan->timer_ms = WL_ISCAN_TIMER_INTERVAL_MS; struct brcmf_cfg80211_event_q, eq_list);
init_timer(&iscan->timer); list_del(&e->eq_list);
iscan->timer.data = (unsigned long) iscan; kfree(e);
iscan->timer.function = brcmf_iscan_timer;
err = brcmf_invoke_iscan(cfg_priv);
if (!err)
iscan->data = cfg_priv;
} }
brcmf_unlock_eq(cfg_priv);
return err;
} }
static s32 wl_init_priv(struct brcmf_cfg80211_priv *cfg_priv) static s32 wl_init_priv(struct brcmf_cfg80211_priv *cfg_priv)
...@@ -3480,140 +3461,25 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_dev *cfg_dev) ...@@ -3480,140 +3461,25 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_dev *cfg_dev)
cfg_priv = brcmf_priv_get(cfg_dev); cfg_priv = brcmf_priv_get(cfg_dev);
wl_deinit_priv(cfg_priv); wl_deinit_priv(cfg_priv);
brcmf_free_wdev(cfg_priv); brcmf_free_wdev(cfg_priv);
brcmf_set_drvdata(cfg_dev, NULL); brcmf_set_drvdata(cfg_dev, NULL);
kfree(cfg_dev); kfree(cfg_dev);
} }
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, &param);
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)
{
u32 event_type = be32_to_cpu(e->event_type);
struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
if (likely(!brcmf_enq_event(cfg_priv, event_type, e)))
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_wakeup_event(struct brcmf_cfg80211_priv *cfg_priv)
{
wake_up(&cfg_priv->event_waitq);
} }
static void brcmf_put_event(struct brcmf_cfg80211_event_q *e) void
brcmf_cfg80211_event(struct net_device *ndev,
const struct brcmf_event_msg *e, void *data)
{ {
kfree(e); u32 event_type = be32_to_cpu(e->event_type);
struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
if (likely(!brcmf_enq_event(cfg_priv, event_type, e)))
brcmf_wakeup_event(cfg_priv);
} }
static s32 brcmf_dongle_mode(struct net_device *ndev, s32 iftype) static s32 brcmf_dongle_mode(struct net_device *ndev, s32 iftype)
...@@ -3798,6 +3664,35 @@ brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, ...@@ -3798,6 +3664,35 @@ brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
return err; 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, static s32 brcmf_config_dongle(struct brcmf_cfg80211_priv *cfg_priv,
bool need_lock) bool need_lock)
{ {
...@@ -3853,30 +3748,40 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_priv *cfg_priv, ...@@ -3853,30 +3748,40 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_priv *cfg_priv,
} }
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; char buf[10+IFNAMSIZ];
s32 phy_list; struct dentry *fd;
s8 phy;
s32 err = 0; s32 err = 0;
err = brcmf_dev_ioctl(cfg_to_ndev(cfg_priv), BRCM_GET_PHYLIST, sprintf(buf, "netdev:%s", cfg_to_ndev(cfg_priv)->name);
&phy_list, sizeof(phy_list)); cfg_priv->debugfsdir = debugfs_create_dir(buf,
if (unlikely(err)) { cfg_to_wiphy(cfg_priv)->debugfsdir);
WL_ERR("error (%d)\n", err);
return err; 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]; fd = debugfs_create_u8("dtim_period", S_IRUGO, cfg_priv->debugfsdir,
WL_INFO("%c phy\n", phy); (u8 *)&cfg_priv->profile->dtim_period);
if (phy == 'n' || phy == 'a') { if (!fd) {
wiphy = cfg_to_wiphy(cfg_priv); err = -ENOMEM;
wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n; goto err_out;
} }
err_out:
return err; 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) static s32 __brcmf_cfg80211_up(struct brcmf_cfg80211_priv *cfg_priv)
{ {
s32 err = 0; s32 err = 0;
...@@ -3958,71 +3863,6 @@ s32 brcmf_cfg80211_down(struct brcmf_cfg80211_dev *cfg_dev) ...@@ -3958,71 +3863,6 @@ s32 brcmf_cfg80211_down(struct brcmf_cfg80211_dev *cfg_dev)
return err; 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, static __used s32 brcmf_add_ie(struct brcmf_cfg80211_priv *cfg_priv,
u8 t, u8 l, u8 *v) u8 t, u8 l, u8 *v)
{ {
...@@ -4040,109 +3880,3 @@ static __used s32 brcmf_add_ie(struct brcmf_cfg80211_priv *cfg_priv, ...@@ -4040,109 +3880,3 @@ static __used s32 brcmf_add_ie(struct brcmf_cfg80211_priv *cfg_priv,
return err; 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;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment