Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 843dc664 authored by John W. Linville's avatar John W. Linville
Browse files

Merge branch 'for-linville' of git://github.com/kvalo/ath6kl

parents 5d6a1b06 9df2a0b7
Loading
Loading
Loading
Loading
+2 −1
Original line number Original line Diff line number Diff line
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# Copyright (c) 2004-2010 Atheros Communications Inc.
# Copyright (c) 2004-2011 Atheros Communications Inc.
# Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
# All rights reserved.
# All rights reserved.
#
#
#
#
+4 −3
Original line number Original line Diff line number Diff line
/*
/*
 * Copyright (c) 2004-2011 Atheros Communications Inc.
 * Copyright (c) 2004-2011 Atheros Communications Inc.
 * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
 *
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * purpose with or without fee is hereby granted, provided that the above
+24 −0
Original line number Original line Diff line number Diff line
/*
/*
 * Copyright (c) 2004-2011 Atheros Communications Inc.
 * Copyright (c) 2004-2011 Atheros Communications Inc.
 * Copyright (c) 2011 Qualcomm Atheros, Inc.
 *
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * purpose with or without fee is hereby granted, provided that the above
@@ -222,6 +223,29 @@ struct ath6kl_bmi_target_info {
	__le32 type;         /* target type */
	__le32 type;         /* target type */
} __packed;
} __packed;


#define ath6kl_bmi_write_hi32(ar, item, val)				\
	({								\
		u32 addr;						\
		__le32 v;						\
									\
		addr = ath6kl_get_hi_item_addr(ar, HI_ITEM(item));	\
		v = cpu_to_le32(val);					\
		ath6kl_bmi_write(ar, addr, (u8 *) &v, sizeof(v));	\
	})

#define ath6kl_bmi_read_hi32(ar, item, val)				\
	({								\
		u32 addr, *check_type = val;				\
		__le32 tmp;						\
		int ret;						\
									\
		(void) (check_type == val);				\
		addr = ath6kl_get_hi_item_addr(ar, HI_ITEM(item));	\
		ret = ath6kl_bmi_read(ar, addr, (u8 *) &tmp, 4);	\
		*val = le32_to_cpu(tmp);				\
		ret;							\
	})

int ath6kl_bmi_init(struct ath6kl *ar);
int ath6kl_bmi_init(struct ath6kl *ar);
void ath6kl_bmi_cleanup(struct ath6kl *ar);
void ath6kl_bmi_cleanup(struct ath6kl *ar);
void ath6kl_bmi_reset(struct ath6kl *ar);
void ath6kl_bmi_reset(struct ath6kl *ar);
+262 −80
Original line number Original line Diff line number Diff line
/*
/*
 * Copyright (c) 2004-2011 Atheros Communications Inc.
 * Copyright (c) 2004-2011 Atheros Communications Inc.
 * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
 *
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * purpose with or without fee is hereby granted, provided that the above
@@ -68,6 +69,10 @@ static struct ieee80211_rate ath6kl_rates[] = {
#define ath6kl_g_rates     (ath6kl_rates + 0)
#define ath6kl_g_rates     (ath6kl_rates + 0)
#define ath6kl_g_rates_size    12
#define ath6kl_g_rates_size    12


#define ath6kl_g_htcap (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \
			IEEE80211_HT_CAP_SGI_20		 | \
			IEEE80211_HT_CAP_SGI_40)

static struct ieee80211_channel ath6kl_2ghz_channels[] = {
static struct ieee80211_channel ath6kl_2ghz_channels[] = {
	CHAN2G(1, 2412, 0),
	CHAN2G(1, 2412, 0),
	CHAN2G(2, 2417, 0),
	CHAN2G(2, 2417, 0),
@@ -112,6 +117,8 @@ static struct ieee80211_supported_band ath6kl_band_2ghz = {
	.channels = ath6kl_2ghz_channels,
	.channels = ath6kl_2ghz_channels,
	.n_bitrates = ath6kl_g_rates_size,
	.n_bitrates = ath6kl_g_rates_size,
	.bitrates = ath6kl_g_rates,
	.bitrates = ath6kl_g_rates,
	.ht_cap.cap = ath6kl_g_htcap,
	.ht_cap.ht_supported = true,
};
};


static struct ieee80211_supported_band ath6kl_band_5ghz = {
static struct ieee80211_supported_band ath6kl_band_5ghz = {
@@ -119,6 +126,8 @@ static struct ieee80211_supported_band ath6kl_band_5ghz = {
	.channels = ath6kl_5ghz_a_channels,
	.channels = ath6kl_5ghz_a_channels,
	.n_bitrates = ath6kl_a_rates_size,
	.n_bitrates = ath6kl_a_rates_size,
	.bitrates = ath6kl_a_rates,
	.bitrates = ath6kl_a_rates,
	.ht_cap.cap = ath6kl_g_htcap,
	.ht_cap.ht_supported = true,
};
};


#define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */
#define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */
@@ -407,6 +416,12 @@ static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type,
	return false;
	return false;
}
}


static bool ath6kl_is_tx_pending(struct ath6kl *ar)
{
	return ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0;
}


static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
				   struct cfg80211_connect_params *sme)
				   struct cfg80211_connect_params *sme)
{
{
@@ -414,6 +429,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
	struct ath6kl_vif *vif = netdev_priv(dev);
	struct ath6kl_vif *vif = netdev_priv(dev);
	int status;
	int status;
	u8 nw_subtype = (ar->p2p) ? SUBTYPE_P2PDEV : SUBTYPE_NONE;
	u8 nw_subtype = (ar->p2p) ? SUBTYPE_P2PDEV : SUBTYPE_NONE;
	u16 interval;


	ath6kl_cfg80211_sscan_disable(vif);
	ath6kl_cfg80211_sscan_disable(vif);


@@ -450,7 +466,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
		 * sleep until the command queue drains
		 * sleep until the command queue drains
		 */
		 */
		wait_event_interruptible_timeout(ar->event_wq,
		wait_event_interruptible_timeout(ar->event_wq,
			ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0,
						 ath6kl_is_tx_pending(ar),
						 WMI_TIMEOUT);
						 WMI_TIMEOUT);
		if (signal_pending(current)) {
		if (signal_pending(current)) {
			ath6kl_err("cmd queue drain timeout\n");
			ath6kl_err("cmd queue drain timeout\n");
@@ -568,6 +584,20 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
		   vif->grp_crypto_len, vif->ch_hint);
		   vif->grp_crypto_len, vif->ch_hint);


	vif->reconnect_flag = 0;
	vif->reconnect_flag = 0;

	if (vif->nw_type == INFRA_NETWORK) {
		interval = max_t(u16, vif->listen_intvl_t,
				 ATH6KL_MAX_WOW_LISTEN_INTL);
		status = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
						       interval,
						       0);
		if (status) {
			ath6kl_err("couldn't set listen intervel\n");
			up(&ar->sem);
			return status;
		}
	}

	status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
	status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type,
					vif->dot11_auth_mode, vif->auth_mode,
					vif->dot11_auth_mode, vif->auth_mode,
					vif->prwise_crypto,
					vif->prwise_crypto,
@@ -590,8 +620,8 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
	}
	}


	if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) &&
	if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) &&
	    ((vif->auth_mode == WPA_PSK_AUTH)
	    ((vif->auth_mode == WPA_PSK_AUTH) ||
	     || (vif->auth_mode == WPA2_PSK_AUTH))) {
	     (vif->auth_mode == WPA2_PSK_AUTH))) {
		mod_timer(&vif->disconnect_timer,
		mod_timer(&vif->disconnect_timer,
			  jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL));
			  jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL));
	}
	}
@@ -876,11 +906,7 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
						  request->ssids[i].ssid);
						  request->ssids[i].ssid);
	}
	}


	/*
	/* this also clears IE in fw if it's not set */
	 * FIXME: we should clear the IE in fw if it's not set so just
	 * remove the check altogether
	 */
	if (request->ie) {
	ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
	ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
				       WMI_FRAME_PROBE_REQ,
				       WMI_FRAME_PROBE_REQ,
				       request->ie, request->ie_len);
				       request->ie, request->ie_len);
@@ -889,7 +915,6 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
			   "scan");
			   "scan");
		return ret;
		return ret;
	}
	}
	}


	/*
	/*
	 * Scan only the requested channels if the request specifies a set of
	 * Scan only the requested channels if the request specifies a set of
@@ -926,14 +951,17 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
		 */
		 */
		ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx,
		ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx,
						WMI_LONG_SCAN, force_fg_scan,
						WMI_LONG_SCAN, force_fg_scan,
						false, 0, 0, n_channels,
						false, 0,
						channels, request->no_cck,
						ATH6KL_FG_SCAN_INTERVAL,
						n_channels, channels,
						request->no_cck,
						request->rates);
						request->rates);
	} else {
	} else {
		ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx,
		ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx,
						WMI_LONG_SCAN, force_fg_scan,
						WMI_LONG_SCAN, force_fg_scan,
						false, 0, 0, n_channels,
						false, 0,
						channels);
						ATH6KL_FG_SCAN_INTERVAL,
						n_channels, channels);
	}
	}
	if (ret)
	if (ret)
		ath6kl_err("wmi_startscan_cmd failed\n");
		ath6kl_err("wmi_startscan_cmd failed\n");
@@ -1046,9 +1074,9 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
		return -ENOTSUPP;
		return -ENOTSUPP;
	}
	}


	if (((vif->auth_mode == WPA_PSK_AUTH)
	if (((vif->auth_mode == WPA_PSK_AUTH) ||
	     || (vif->auth_mode == WPA2_PSK_AUTH))
	     (vif->auth_mode == WPA2_PSK_AUTH)) &&
	    && (key_usage & GROUP_USAGE))
	    (key_usage & GROUP_USAGE))
		del_timer(&vif->disconnect_timer);
		del_timer(&vif->disconnect_timer);


	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
@@ -1058,7 +1086,7 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,


	if (vif->nw_type == AP_NETWORK && !pairwise &&
	if (vif->nw_type == AP_NETWORK && !pairwise &&
	    (key_type == TKIP_CRYPT || key_type == AES_CRYPT ||
	    (key_type == TKIP_CRYPT || key_type == AES_CRYPT ||
	     key_type == WAPI_CRYPT) && params) {
	     key_type == WAPI_CRYPT)) {
		ar->ap_mode_bkey.valid = true;
		ar->ap_mode_bkey.valid = true;
		ar->ap_mode_bkey.key_index = key_index;
		ar->ap_mode_bkey.key_index = key_index;
		ar->ap_mode_bkey.key_type = key_type;
		ar->ap_mode_bkey.key_type = key_type;
@@ -1263,7 +1291,6 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
{
{
	struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
	struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
	struct ath6kl_vif *vif;
	struct ath6kl_vif *vif;
	u8 ath6kl_dbm;
	int dbm = MBM_TO_DBM(mbm);
	int dbm = MBM_TO_DBM(mbm);


	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
	ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__,
@@ -1280,7 +1307,7 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
	case NL80211_TX_POWER_AUTOMATIC:
	case NL80211_TX_POWER_AUTOMATIC:
		return 0;
		return 0;
	case NL80211_TX_POWER_LIMITED:
	case NL80211_TX_POWER_LIMITED:
		ar->tx_pwr = ath6kl_dbm = dbm;
		ar->tx_pwr = dbm;
		break;
		break;
	default:
	default:
		ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
		ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n",
@@ -1288,7 +1315,7 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
		return -EOPNOTSUPP;
		return -EOPNOTSUPP;
	}
	}


	ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, ath6kl_dbm);
	ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, dbm);


	return 0;
	return 0;
}
}
@@ -1904,7 +1931,7 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
	struct ath6kl_vif *vif;
	struct ath6kl_vif *vif;
	int ret, left;
	int ret, left;
	u32 filter = 0;
	u32 filter = 0;
	u16 i;
	u16 i, bmiss_time;
	u8 index = 0;
	u8 index = 0;
	__be32 ips[MAX_IP_ADDRS];
	__be32 ips[MAX_IP_ADDRS];


@@ -1941,6 +1968,34 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
	if (ret)
	if (ret)
		return ret;
		return ret;


	netif_stop_queue(vif->ndev);

	if (vif->nw_type != AP_NETWORK) {
		ret = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
						    ATH6KL_MAX_WOW_LISTEN_INTL,
						    0);
		if (ret)
			return ret;

		/* Set listen interval x 15 times as bmiss time */
		bmiss_time = ATH6KL_MAX_WOW_LISTEN_INTL * 15;
		if (bmiss_time > ATH6KL_MAX_BMISS_TIME)
			bmiss_time = ATH6KL_MAX_BMISS_TIME;

		ret = ath6kl_wmi_bmisstime_cmd(ar->wmi, vif->fw_vif_idx,
					       bmiss_time, 0);
		if (ret)
			return ret;

		ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
						0xFFFF, 0, 0xFFFF, 0, 0, 0,
						0, 0, 0, 0);
		if (ret)
			return ret;
	}

	ar->state = ATH6KL_STATE_SUSPENDING;

	/* Setup own IP addr for ARP agent. */
	/* Setup own IP addr for ARP agent. */
	in_dev = __in_dev_get_rtnl(vif->ndev);
	in_dev = __in_dev_get_rtnl(vif->ndev);
	if (!in_dev)
	if (!in_dev)
@@ -2019,15 +2074,46 @@ static int ath6kl_wow_resume(struct ath6kl *ar)
	if (!vif)
	if (!vif)
		return -EIO;
		return -EIO;


	ar->state = ATH6KL_STATE_RESUMING;

	ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
	ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
						 ATH6KL_HOST_MODE_AWAKE);
						 ATH6KL_HOST_MODE_AWAKE);
	if (ret) {
		ath6kl_warn("Failed to configure host sleep mode for "
			    "wow resume: %d\n", ret);
		ar->state = ATH6KL_STATE_WOW;
		return ret;
	}

	if (vif->nw_type != AP_NETWORK) {
		ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
						0, 0, 0, 0, 0, 0, 3, 0, 0, 0);
		if (ret)
			return ret;

		ret = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
						    vif->listen_intvl_t, 0);
		if (ret)
			return ret;

		ret = ath6kl_wmi_bmisstime_cmd(ar->wmi, vif->fw_vif_idx,
					       vif->bmiss_time_t, 0);
		if (ret)
			return ret;
			return ret;
	}
	}


	ar->state = ATH6KL_STATE_ON;

	netif_wake_queue(vif->ndev);

	return 0;
}

int ath6kl_cfg80211_suspend(struct ath6kl *ar,
int ath6kl_cfg80211_suspend(struct ath6kl *ar,
			    enum ath6kl_cfg_suspend_mode mode,
			    enum ath6kl_cfg_suspend_mode mode,
			    struct cfg80211_wowlan *wow)
			    struct cfg80211_wowlan *wow)
{
{
	enum ath6kl_state prev_state;
	int ret;
	int ret;


	switch (mode) {
	switch (mode) {
@@ -2038,11 +2124,14 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
		/* Flush all non control pkts in TX path */
		/* Flush all non control pkts in TX path */
		ath6kl_tx_data_cleanup(ar);
		ath6kl_tx_data_cleanup(ar);


		prev_state = ar->state;

		ret = ath6kl_wow_suspend(ar, wow);
		ret = ath6kl_wow_suspend(ar, wow);
		if (ret) {
		if (ret) {
			ath6kl_err("wow suspend failed: %d\n", ret);
			ar->state = prev_state;
			return ret;
			return ret;
		}
		}

		ar->state = ATH6KL_STATE_WOW;
		ar->state = ATH6KL_STATE_WOW;
		break;
		break;


@@ -2114,7 +2203,6 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar)
			return ret;
			return ret;
		}
		}


		ar->state = ATH6KL_STATE_ON;
		break;
		break;


	case ATH6KL_STATE_DEEPSLEEP:
	case ATH6KL_STATE_DEEPSLEEP:
@@ -2188,6 +2276,9 @@ static int __ath6kl_cfg80211_resume(struct wiphy *wiphy)
 */
 */
void ath6kl_check_wow_status(struct ath6kl *ar)
void ath6kl_check_wow_status(struct ath6kl *ar)
{
{
	if (ar->state == ATH6KL_STATE_SUSPENDING)
		return;

	if (ar->state == ATH6KL_STATE_WOW)
	if (ar->state == ATH6KL_STATE_WOW)
		ath6kl_cfg80211_resume(ar);
		ath6kl_cfg80211_resume(ar);
}
}
@@ -2275,30 +2366,27 @@ static int ath6kl_set_ies(struct ath6kl_vif *vif,
	struct ath6kl *ar = vif->ar;
	struct ath6kl *ar = vif->ar;
	int res;
	int res;


	if (info->beacon_ies) {
	/* this also clears IE in fw if it's not set */
	res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
	res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
				       WMI_FRAME_BEACON,
				       WMI_FRAME_BEACON,
				       info->beacon_ies,
				       info->beacon_ies,
				       info->beacon_ies_len);
				       info->beacon_ies_len);
	if (res)
	if (res)
		return res;
		return res;
	}


	if (info->proberesp_ies) {
	/* this also clears IE in fw if it's not set */
	res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies,
	res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies,
					   info->proberesp_ies_len);
					   info->proberesp_ies_len);
	if (res)
	if (res)
		return res;
		return res;
	}


	if (info->assocresp_ies) {
	/* this also clears IE in fw if it's not set */
	res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
	res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
				       WMI_FRAME_ASSOC_RESP,
				       WMI_FRAME_ASSOC_RESP,
				       info->assocresp_ies,
				       info->assocresp_ies,
				       info->assocresp_ies_len);
				       info->assocresp_ies_len);
	if (res)
	if (res)
		return res;
		return res;
	}


	return 0;
	return 0;
}
}
@@ -2309,6 +2397,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
	struct ath6kl *ar = ath6kl_priv(dev);
	struct ath6kl *ar = ath6kl_priv(dev);
	struct ath6kl_vif *vif = netdev_priv(dev);
	struct ath6kl_vif *vif = netdev_priv(dev);
	struct ieee80211_mgmt *mgmt;
	struct ieee80211_mgmt *mgmt;
	bool hidden = false;
	u8 *ies;
	u8 *ies;
	int ies_len;
	int ies_len;
	struct wmi_connect_cmd p;
	struct wmi_connect_cmd p;
@@ -2345,7 +2434,11 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
	memcpy(vif->ssid, info->ssid, info->ssid_len);
	memcpy(vif->ssid, info->ssid, info->ssid_len);
	vif->ssid_len = info->ssid_len;
	vif->ssid_len = info->ssid_len;
	if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
	if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE)
		return -EOPNOTSUPP; /* TODO */
		hidden = true;

	res = ath6kl_wmi_ap_hidden_ssid(ar->wmi, vif->fw_vif_idx, hidden);
	if (res)
		return res;


	ret = ath6kl_set_auth_type(vif, info->auth_type);
	ret = ath6kl_set_auth_type(vif, info->auth_type);
	if (ret)
	if (ret)
@@ -2584,6 +2677,76 @@ static int ath6kl_send_go_probe_resp(struct ath6kl_vif *vif,
	return ret;
	return ret;
}
}


static bool ath6kl_mgmt_powersave_ap(struct ath6kl_vif *vif,
				     u32 id,
				     u32 freq,
				     u32 wait,
				     const u8 *buf,
				     size_t len,
				     bool *more_data,
				     bool no_cck)
{
	struct ieee80211_mgmt *mgmt;
	struct ath6kl_sta *conn;
	bool is_psq_empty = false;
	struct ath6kl_mgmt_buff *mgmt_buf;
	size_t mgmt_buf_size;
	struct ath6kl *ar = vif->ar;

	mgmt = (struct ieee80211_mgmt *) buf;
	if (is_multicast_ether_addr(mgmt->da))
		return false;

	conn = ath6kl_find_sta(vif, mgmt->da);
	if (!conn)
		return false;

	if (conn->sta_flags & STA_PS_SLEEP) {
		if (!(conn->sta_flags & STA_PS_POLLED)) {
			/* Queue the frames if the STA is sleeping */
			mgmt_buf_size = len + sizeof(struct ath6kl_mgmt_buff);
			mgmt_buf = kmalloc(mgmt_buf_size, GFP_KERNEL);
			if (!mgmt_buf)
				return false;

			INIT_LIST_HEAD(&mgmt_buf->list);
			mgmt_buf->id = id;
			mgmt_buf->freq = freq;
			mgmt_buf->wait = wait;
			mgmt_buf->len = len;
			mgmt_buf->no_cck = no_cck;
			memcpy(mgmt_buf->buf, buf, len);
			spin_lock_bh(&conn->psq_lock);
			is_psq_empty = skb_queue_empty(&conn->psq) &&
					(conn->mgmt_psq_len == 0);
			list_add_tail(&mgmt_buf->list, &conn->mgmt_psq);
			conn->mgmt_psq_len++;
			spin_unlock_bh(&conn->psq_lock);

			/*
			 * If this is the first pkt getting queued
			 * for this STA, update the PVB for this
			 * STA.
			 */
			if (is_psq_empty)
				ath6kl_wmi_set_pvb_cmd(ar->wmi, vif->fw_vif_idx,
						       conn->aid, 1);
			return true;
		}

		/*
		 * This tx is because of a PsPoll.
		 * Determine if MoreData bit has to be set.
		 */
		spin_lock_bh(&conn->psq_lock);
		if (!skb_queue_empty(&conn->psq) || (conn->mgmt_psq_len != 0))
			*more_data = true;
		spin_unlock_bh(&conn->psq_lock);
	}

	return false;
}

static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
			  struct ieee80211_channel *chan, bool offchan,
			  struct ieee80211_channel *chan, bool offchan,
			  enum nl80211_channel_type channel_type,
			  enum nl80211_channel_type channel_type,
@@ -2595,6 +2758,7 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
	struct ath6kl_vif *vif = netdev_priv(dev);
	struct ath6kl_vif *vif = netdev_priv(dev);
	u32 id;
	u32 id;
	const struct ieee80211_mgmt *mgmt;
	const struct ieee80211_mgmt *mgmt;
	bool more_data, queued;


	mgmt = (const struct ieee80211_mgmt *) buf;
	mgmt = (const struct ieee80211_mgmt *) buf;
	if (buf + len >= mgmt->u.probe_resp.variable &&
	if (buf + len >= mgmt->u.probe_resp.variable &&
@@ -2620,22 +2784,19 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,


	*cookie = id;
	*cookie = id;


	if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
	/* AP mode Power saving processing */
		    ar->fw_capabilities)) {
	if (vif->nw_type == AP_NETWORK) {
		/*
		queued = ath6kl_mgmt_powersave_ap(vif,
		 * If capable of doing P2P mgmt operations using
					id, chan->center_freq,
		 * station interface, send additional information like
					wait, buf,
		 * supported rates to advertise and xmit rates for
					len, &more_data, no_cck);
		 * probe requests
		if (queued)
		 */
			return 0;
	}

	return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id,
	return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id,
					chan->center_freq, wait,
					chan->center_freq, wait,
					buf, len, no_cck);
					buf, len, no_cck);
	} else {
		return ath6kl_wmi_send_action_cmd(ar->wmi, vif->fw_vif_idx, id,
						  chan->center_freq, wait,
						  buf, len);
	}
}
}


static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
@@ -2929,7 +3090,10 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
	vif->wdev.netdev = ndev;
	vif->wdev.netdev = ndev;
	vif->wdev.iftype = type;
	vif->wdev.iftype = type;
	vif->fw_vif_idx = fw_vif_idx;
	vif->fw_vif_idx = fw_vif_idx;
	vif->nw_type = vif->next_mode = nw_type;
	vif->nw_type = nw_type;
	vif->next_mode = nw_type;
	vif->listen_intvl_t = ATH6KL_DEFAULT_LISTEN_INTVAL;
	vif->bmiss_time_t = ATH6KL_DEFAULT_BMISS_TIME;


	memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
	memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
	if (fw_vif_idx != 0)
	if (fw_vif_idx != 0)
@@ -3009,18 +3173,36 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)


	wiphy->max_sched_scan_ssids = 10;
	wiphy->max_sched_scan_ssids = 10;


	ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM |
			    WIPHY_FLAG_HAVE_AP_SME |
			    WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
			    WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;

	if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities))
		ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;

	ar->wiphy->probe_resp_offload =
		NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
		NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
		NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P |
		NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U;

	ret = wiphy_register(wiphy);
	ret = wiphy_register(wiphy);
	if (ret < 0) {
	if (ret < 0) {
		ath6kl_err("couldn't register wiphy device\n");
		ath6kl_err("couldn't register wiphy device\n");
		return ret;
		return ret;
	}
	}


	ar->wiphy_registered = true;

	return 0;
	return 0;
}
}


void ath6kl_cfg80211_cleanup(struct ath6kl *ar)
void ath6kl_cfg80211_cleanup(struct ath6kl *ar)
{
{
	wiphy_unregister(ar->wiphy);
	wiphy_unregister(ar->wiphy);

	ar->wiphy_registered = false;
}
}


struct ath6kl *ath6kl_cfg80211_create(void)
struct ath6kl *ath6kl_cfg80211_create(void)
+1 −0
Original line number Original line Diff line number Diff line
/*
/*
 * Copyright (c) 2011 Atheros Communications Inc.
 * Copyright (c) 2011 Atheros Communications Inc.
 * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
 *
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * purpose with or without fee is hereby granted, provided that the above
Loading