uap_cmd.c revision f752dcd52923b8de82881cf1269f0dc03dbd1088
1/* 2 * Marvell Wireless LAN device driver: AP specific command handling 3 * 4 * Copyright (C) 2012, Marvell International Ltd. 5 * 6 * This software file (the "File") is distributed by Marvell International 7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991 8 * (the "License"). You may use, redistribute and/or modify this File in 9 * accordance with the terms and conditions of the License, a copy of which 10 * is available by writing to the Free Software Foundation, Inc., 11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the 12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. 13 * 14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about 17 * this warranty disclaimer. 18 */ 19 20#include "main.h" 21 22/* This function parses security related parameters from cfg80211_ap_settings 23 * and sets into FW understandable bss_config structure. 24 */ 25int mwifiex_set_secure_params(struct mwifiex_private *priv, 26 struct mwifiex_uap_bss_param *bss_config, 27 struct cfg80211_ap_settings *params) { 28 int i; 29 30 switch (params->auth_type) { 31 case NL80211_AUTHTYPE_OPEN_SYSTEM: 32 bss_config->auth_mode = WLAN_AUTH_OPEN; 33 break; 34 case NL80211_AUTHTYPE_SHARED_KEY: 35 bss_config->auth_mode = WLAN_AUTH_SHARED_KEY; 36 break; 37 case NL80211_AUTHTYPE_NETWORK_EAP: 38 bss_config->auth_mode = WLAN_AUTH_LEAP; 39 break; 40 default: 41 bss_config->auth_mode = MWIFIEX_AUTH_MODE_AUTO; 42 break; 43 } 44 45 bss_config->key_mgmt_operation |= KEY_MGMT_ON_HOST; 46 47 for (i = 0; i < params->crypto.n_akm_suites; i++) { 48 switch (params->crypto.akm_suites[i]) { 49 case WLAN_AKM_SUITE_8021X: 50 if (params->crypto.wpa_versions & 51 NL80211_WPA_VERSION_1) { 52 bss_config->protocol = PROTOCOL_WPA; 53 bss_config->key_mgmt = KEY_MGMT_EAP; 54 } 55 if (params->crypto.wpa_versions & 56 NL80211_WPA_VERSION_2) { 57 bss_config->protocol = PROTOCOL_WPA2; 58 bss_config->key_mgmt = KEY_MGMT_EAP; 59 } 60 break; 61 case WLAN_AKM_SUITE_PSK: 62 if (params->crypto.wpa_versions & 63 NL80211_WPA_VERSION_1) { 64 bss_config->protocol = PROTOCOL_WPA; 65 bss_config->key_mgmt = KEY_MGMT_PSK; 66 } 67 if (params->crypto.wpa_versions & 68 NL80211_WPA_VERSION_2) { 69 bss_config->protocol = PROTOCOL_WPA2; 70 bss_config->key_mgmt = KEY_MGMT_PSK; 71 } 72 break; 73 default: 74 break; 75 } 76 } 77 for (i = 0; i < params->crypto.n_ciphers_pairwise; i++) { 78 switch (params->crypto.ciphers_pairwise[i]) { 79 case WLAN_CIPHER_SUITE_WEP40: 80 case WLAN_CIPHER_SUITE_WEP104: 81 break; 82 case WLAN_CIPHER_SUITE_TKIP: 83 bss_config->wpa_cfg.pairwise_cipher_wpa = CIPHER_TKIP; 84 break; 85 case WLAN_CIPHER_SUITE_CCMP: 86 bss_config->wpa_cfg.pairwise_cipher_wpa2 = 87 CIPHER_AES_CCMP; 88 default: 89 break; 90 } 91 } 92 93 switch (params->crypto.cipher_group) { 94 case WLAN_CIPHER_SUITE_WEP40: 95 case WLAN_CIPHER_SUITE_WEP104: 96 break; 97 case WLAN_CIPHER_SUITE_TKIP: 98 bss_config->wpa_cfg.group_cipher = CIPHER_TKIP; 99 break; 100 case WLAN_CIPHER_SUITE_CCMP: 101 bss_config->wpa_cfg.group_cipher = CIPHER_AES_CCMP; 102 break; 103 default: 104 break; 105 } 106 107 return 0; 108} 109 110/* This function initializes some of mwifiex_uap_bss_param variables. 111 * This helps FW in ignoring invalid values. These values may or may not 112 * be get updated to valid ones at later stage. 113 */ 114void mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config) 115{ 116 config->bcast_ssid_ctl = 0x7F; 117 config->radio_ctl = 0x7F; 118 config->dtim_period = 0x7F; 119 config->beacon_period = 0x7FFF; 120 config->auth_mode = 0x7F; 121 config->rts_threshold = 0x7FFF; 122 config->frag_threshold = 0x7FFF; 123 config->retry_limit = 0x7F; 124} 125 126/* Parse AP config structure and prepare TLV based command structure 127 * to be sent to FW for uAP configuration 128 */ 129static int mwifiex_cmd_uap_sys_config(struct host_cmd_ds_command *cmd, 130 u16 cmd_action, void *cmd_buf) 131{ 132 u8 *tlv; 133 struct host_cmd_ds_sys_config *sys_config = &cmd->params.uap_sys_config; 134 struct host_cmd_tlv_dtim_period *dtim_period; 135 struct host_cmd_tlv_beacon_period *beacon_period; 136 struct host_cmd_tlv_ssid *ssid; 137 struct host_cmd_tlv_channel_band *chan_band; 138 struct host_cmd_tlv_frag_threshold *frag_threshold; 139 struct host_cmd_tlv_rts_threshold *rts_threshold; 140 struct host_cmd_tlv_retry_limit *retry_limit; 141 struct host_cmd_tlv_pwk_cipher *pwk_cipher; 142 struct host_cmd_tlv_gwk_cipher *gwk_cipher; 143 struct host_cmd_tlv_encrypt_protocol *encrypt_protocol; 144 struct host_cmd_tlv_auth_type *auth_type; 145 struct host_cmd_tlv_passphrase *passphrase; 146 struct host_cmd_tlv_akmp *tlv_akmp; 147 struct mwifiex_uap_bss_param *bss_cfg = cmd_buf; 148 u16 cmd_size; 149 150 cmd->command = cpu_to_le16(HostCmd_CMD_UAP_SYS_CONFIG); 151 cmd_size = (u16)(sizeof(struct host_cmd_ds_sys_config) + S_DS_GEN); 152 153 sys_config->action = cpu_to_le16(cmd_action); 154 155 tlv = sys_config->tlv; 156 157 if (bss_cfg->ssid.ssid_len) { 158 ssid = (struct host_cmd_tlv_ssid *)tlv; 159 ssid->tlv.type = cpu_to_le16(TLV_TYPE_UAP_SSID); 160 ssid->tlv.len = cpu_to_le16((u16)bss_cfg->ssid.ssid_len); 161 memcpy(ssid->ssid, bss_cfg->ssid.ssid, bss_cfg->ssid.ssid_len); 162 cmd_size += sizeof(struct host_cmd_tlv) + 163 bss_cfg->ssid.ssid_len; 164 tlv += sizeof(struct host_cmd_tlv) + bss_cfg->ssid.ssid_len; 165 } 166 if (bss_cfg->channel && bss_cfg->channel <= MAX_CHANNEL_BAND_BG) { 167 chan_band = (struct host_cmd_tlv_channel_band *)tlv; 168 chan_band->tlv.type = cpu_to_le16(TLV_TYPE_CHANNELBANDLIST); 169 chan_band->tlv.len = 170 cpu_to_le16(sizeof(struct host_cmd_tlv_channel_band) - 171 sizeof(struct host_cmd_tlv)); 172 chan_band->band_config = bss_cfg->band_cfg; 173 chan_band->channel = bss_cfg->channel; 174 cmd_size += sizeof(struct host_cmd_tlv_channel_band); 175 tlv += sizeof(struct host_cmd_tlv_channel_band); 176 } 177 if (bss_cfg->beacon_period >= MIN_BEACON_PERIOD && 178 bss_cfg->beacon_period <= MAX_BEACON_PERIOD) { 179 beacon_period = (struct host_cmd_tlv_beacon_period *)tlv; 180 beacon_period->tlv.type = 181 cpu_to_le16(TLV_TYPE_UAP_BEACON_PERIOD); 182 beacon_period->tlv.len = 183 cpu_to_le16(sizeof(struct host_cmd_tlv_beacon_period) - 184 sizeof(struct host_cmd_tlv)); 185 beacon_period->period = cpu_to_le16(bss_cfg->beacon_period); 186 cmd_size += sizeof(struct host_cmd_tlv_beacon_period); 187 tlv += sizeof(struct host_cmd_tlv_beacon_period); 188 } 189 if (bss_cfg->dtim_period >= MIN_DTIM_PERIOD && 190 bss_cfg->dtim_period <= MAX_DTIM_PERIOD) { 191 dtim_period = (struct host_cmd_tlv_dtim_period *)tlv; 192 dtim_period->tlv.type = cpu_to_le16(TLV_TYPE_UAP_DTIM_PERIOD); 193 dtim_period->tlv.len = 194 cpu_to_le16(sizeof(struct host_cmd_tlv_dtim_period) - 195 sizeof(struct host_cmd_tlv)); 196 dtim_period->period = bss_cfg->dtim_period; 197 cmd_size += sizeof(struct host_cmd_tlv_dtim_period); 198 tlv += sizeof(struct host_cmd_tlv_dtim_period); 199 } 200 if (bss_cfg->rts_threshold <= MWIFIEX_RTS_MAX_VALUE) { 201 rts_threshold = (struct host_cmd_tlv_rts_threshold *)tlv; 202 rts_threshold->tlv.type = 203 cpu_to_le16(TLV_TYPE_UAP_RTS_THRESHOLD); 204 rts_threshold->tlv.len = 205 cpu_to_le16(sizeof(struct host_cmd_tlv_rts_threshold) - 206 sizeof(struct host_cmd_tlv)); 207 rts_threshold->rts_thr = cpu_to_le16(bss_cfg->rts_threshold); 208 cmd_size += sizeof(struct host_cmd_tlv_frag_threshold); 209 tlv += sizeof(struct host_cmd_tlv_frag_threshold); 210 } 211 if ((bss_cfg->frag_threshold >= MWIFIEX_FRAG_MIN_VALUE) && 212 (bss_cfg->frag_threshold <= MWIFIEX_FRAG_MAX_VALUE)) { 213 frag_threshold = (struct host_cmd_tlv_frag_threshold *)tlv; 214 frag_threshold->tlv.type = 215 cpu_to_le16(TLV_TYPE_UAP_FRAG_THRESHOLD); 216 frag_threshold->tlv.len = 217 cpu_to_le16(sizeof(struct host_cmd_tlv_frag_threshold) - 218 sizeof(struct host_cmd_tlv)); 219 frag_threshold->frag_thr = cpu_to_le16(bss_cfg->frag_threshold); 220 cmd_size += sizeof(struct host_cmd_tlv_frag_threshold); 221 tlv += sizeof(struct host_cmd_tlv_frag_threshold); 222 } 223 if (bss_cfg->retry_limit <= MWIFIEX_RETRY_LIMIT) { 224 retry_limit = (struct host_cmd_tlv_retry_limit *)tlv; 225 retry_limit->tlv.type = cpu_to_le16(TLV_TYPE_UAP_RETRY_LIMIT); 226 retry_limit->tlv.len = 227 cpu_to_le16(sizeof(struct host_cmd_tlv_retry_limit) - 228 sizeof(struct host_cmd_tlv)); 229 retry_limit->limit = (u8)bss_cfg->retry_limit; 230 cmd_size += sizeof(struct host_cmd_tlv_retry_limit); 231 tlv += sizeof(struct host_cmd_tlv_retry_limit); 232 } 233 if ((bss_cfg->protocol & PROTOCOL_WPA) || 234 (bss_cfg->protocol & PROTOCOL_WPA2) || 235 (bss_cfg->protocol & PROTOCOL_EAP)) { 236 tlv_akmp = (struct host_cmd_tlv_akmp *)tlv; 237 tlv_akmp->tlv.type = cpu_to_le16(TLV_TYPE_UAP_AKMP); 238 tlv_akmp->tlv.len = 239 cpu_to_le16(sizeof(struct host_cmd_tlv_akmp) - 240 sizeof(struct host_cmd_tlv)); 241 tlv_akmp->key_mgmt_operation = 242 cpu_to_le16(bss_cfg->key_mgmt_operation); 243 tlv_akmp->key_mgmt = cpu_to_le16(bss_cfg->key_mgmt); 244 cmd_size += sizeof(struct host_cmd_tlv_akmp); 245 tlv += sizeof(struct host_cmd_tlv_akmp); 246 247 if (bss_cfg->wpa_cfg.pairwise_cipher_wpa & 248 VALID_CIPHER_BITMAP) { 249 pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv; 250 pwk_cipher->tlv.type = 251 cpu_to_le16(TLV_TYPE_PWK_CIPHER); 252 pwk_cipher->tlv.len = cpu_to_le16( 253 sizeof(struct host_cmd_tlv_pwk_cipher) - 254 sizeof(struct host_cmd_tlv)); 255 pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA); 256 pwk_cipher->cipher = 257 bss_cfg->wpa_cfg.pairwise_cipher_wpa; 258 cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher); 259 tlv += sizeof(struct host_cmd_tlv_pwk_cipher); 260 } 261 if (bss_cfg->wpa_cfg.pairwise_cipher_wpa2 & 262 VALID_CIPHER_BITMAP) { 263 pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv; 264 pwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER); 265 pwk_cipher->tlv.len = cpu_to_le16( 266 sizeof(struct host_cmd_tlv_pwk_cipher) - 267 sizeof(struct host_cmd_tlv)); 268 pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA2); 269 pwk_cipher->cipher = 270 bss_cfg->wpa_cfg.pairwise_cipher_wpa2; 271 cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher); 272 tlv += sizeof(struct host_cmd_tlv_pwk_cipher); 273 } 274 if (bss_cfg->wpa_cfg.group_cipher & VALID_CIPHER_BITMAP) { 275 gwk_cipher = (struct host_cmd_tlv_gwk_cipher *)tlv; 276 gwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_GWK_CIPHER); 277 gwk_cipher->tlv.len = cpu_to_le16( 278 sizeof(struct host_cmd_tlv_gwk_cipher) - 279 sizeof(struct host_cmd_tlv)); 280 gwk_cipher->cipher = bss_cfg->wpa_cfg.group_cipher; 281 cmd_size += sizeof(struct host_cmd_tlv_gwk_cipher); 282 tlv += sizeof(struct host_cmd_tlv_gwk_cipher); 283 } 284 if (bss_cfg->wpa_cfg.length) { 285 passphrase = (struct host_cmd_tlv_passphrase *)tlv; 286 passphrase->tlv.type = 287 cpu_to_le16(TLV_TYPE_UAP_WPA_PASSPHRASE); 288 passphrase->tlv.len = 289 cpu_to_le16(bss_cfg->wpa_cfg.length); 290 memcpy(passphrase->passphrase, 291 bss_cfg->wpa_cfg.passphrase, 292 bss_cfg->wpa_cfg.length); 293 cmd_size += sizeof(struct host_cmd_tlv) + 294 bss_cfg->wpa_cfg.length; 295 tlv += sizeof(struct host_cmd_tlv) + 296 bss_cfg->wpa_cfg.length; 297 } 298 } 299 if ((bss_cfg->auth_mode <= WLAN_AUTH_SHARED_KEY) || 300 (bss_cfg->auth_mode == MWIFIEX_AUTH_MODE_AUTO)) { 301 auth_type = (struct host_cmd_tlv_auth_type *)tlv; 302 auth_type->tlv.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE); 303 auth_type->tlv.len = 304 cpu_to_le16(sizeof(struct host_cmd_tlv_auth_type) - 305 sizeof(struct host_cmd_tlv)); 306 auth_type->auth_type = (u8)bss_cfg->auth_mode; 307 cmd_size += sizeof(struct host_cmd_tlv_auth_type); 308 tlv += sizeof(struct host_cmd_tlv_auth_type); 309 } 310 if (bss_cfg->protocol) { 311 encrypt_protocol = (struct host_cmd_tlv_encrypt_protocol *)tlv; 312 encrypt_protocol->tlv.type = 313 cpu_to_le16(TLV_TYPE_UAP_ENCRY_PROTOCOL); 314 encrypt_protocol->tlv.len = 315 cpu_to_le16(sizeof(struct host_cmd_tlv_encrypt_protocol) 316 - sizeof(struct host_cmd_tlv)); 317 encrypt_protocol->proto = cpu_to_le16(bss_cfg->protocol); 318 cmd_size += sizeof(struct host_cmd_tlv_encrypt_protocol); 319 tlv += sizeof(struct host_cmd_tlv_encrypt_protocol); 320 } 321 322 cmd->size = cpu_to_le16(cmd_size); 323 return 0; 324} 325 326/* This function prepares the AP specific commands before sending them 327 * to the firmware. 328 * This is a generic function which calls specific command preparation 329 * routines based upon the command number. 330 */ 331int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no, 332 u16 cmd_action, u32 cmd_oid, 333 void *data_buf, void *cmd_buf) 334{ 335 struct host_cmd_ds_command *cmd = cmd_buf; 336 337 switch (cmd_no) { 338 case HostCmd_CMD_UAP_SYS_CONFIG: 339 if (mwifiex_cmd_uap_sys_config(cmd, cmd_action, data_buf)) 340 return -1; 341 break; 342 case HostCmd_CMD_UAP_BSS_START: 343 case HostCmd_CMD_UAP_BSS_STOP: 344 cmd->command = cpu_to_le16(cmd_no); 345 cmd->size = cpu_to_le16(S_DS_GEN); 346 break; 347 default: 348 dev_err(priv->adapter->dev, 349 "PREP_CMD: unknown cmd %#x\n", cmd_no); 350 return -1; 351 } 352 353 return 0; 354} 355 356/* This function sets the RF channel for AP. 357 * 358 * This function populates channel information in AP config structure 359 * and sends command to configure channel information in AP. 360 */ 361int mwifiex_uap_set_channel(struct mwifiex_private *priv, int channel) 362{ 363 struct mwifiex_uap_bss_param *bss_cfg; 364 struct wiphy *wiphy = priv->wdev->wiphy; 365 366 bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL); 367 if (!bss_cfg) 368 return -ENOMEM; 369 370 bss_cfg->band_cfg = BAND_CONFIG_MANUAL; 371 bss_cfg->channel = channel; 372 373 if (mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_SYS_CONFIG, 374 HostCmd_ACT_GEN_SET, 0, bss_cfg)) { 375 wiphy_err(wiphy, "Failed to set the uAP channel\n"); 376 kfree(bss_cfg); 377 return -1; 378 } 379 380 kfree(bss_cfg); 381 return 0; 382} 383