Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
uap_cmd.c
Go to the documentation of this file.
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  */
26  struct mwifiex_uap_bss_param *bss_config,
27  struct cfg80211_ap_settings *params) {
28  int i;
29  struct mwifiex_wep_key wep_key;
30 
31  if (!params->privacy) {
32  bss_config->protocol = PROTOCOL_NO_SECURITY;
33  bss_config->key_mgmt = KEY_MGMT_NONE;
34  bss_config->wpa_cfg.length = 0;
35  priv->sec_info.wep_enabled = 0;
36  priv->sec_info.wpa_enabled = 0;
37  priv->sec_info.wpa2_enabled = 0;
38 
39  return 0;
40  }
41 
42  switch (params->auth_type) {
44  bss_config->auth_mode = WLAN_AUTH_OPEN;
45  break;
47  bss_config->auth_mode = WLAN_AUTH_SHARED_KEY;
48  break;
50  bss_config->auth_mode = WLAN_AUTH_LEAP;
51  break;
52  default:
53  bss_config->auth_mode = MWIFIEX_AUTH_MODE_AUTO;
54  break;
55  }
56 
57  bss_config->key_mgmt_operation |= KEY_MGMT_ON_HOST;
58 
59  for (i = 0; i < params->crypto.n_akm_suites; i++) {
60  switch (params->crypto.akm_suites[i]) {
62  if (params->crypto.wpa_versions &
64  bss_config->protocol = PROTOCOL_WPA;
65  bss_config->key_mgmt = KEY_MGMT_EAP;
66  }
67  if (params->crypto.wpa_versions &
69  bss_config->protocol |= PROTOCOL_WPA2;
70  bss_config->key_mgmt = KEY_MGMT_EAP;
71  }
72  break;
73  case WLAN_AKM_SUITE_PSK:
74  if (params->crypto.wpa_versions &
76  bss_config->protocol = PROTOCOL_WPA;
77  bss_config->key_mgmt = KEY_MGMT_PSK;
78  }
79  if (params->crypto.wpa_versions &
81  bss_config->protocol |= PROTOCOL_WPA2;
82  bss_config->key_mgmt = KEY_MGMT_PSK;
83  }
84  break;
85  default:
86  break;
87  }
88  }
89  for (i = 0; i < params->crypto.n_ciphers_pairwise; i++) {
90  switch (params->crypto.ciphers_pairwise[i]) {
93  break;
95  if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1)
96  bss_config->wpa_cfg.pairwise_cipher_wpa |=
98  if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
99  bss_config->wpa_cfg.pairwise_cipher_wpa2 |=
100  CIPHER_TKIP;
101  break;
103  if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1)
104  bss_config->wpa_cfg.pairwise_cipher_wpa |=
106  if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
107  bss_config->wpa_cfg.pairwise_cipher_wpa2 |=
109  default:
110  break;
111  }
112  }
113 
114  switch (params->crypto.cipher_group) {
117  if (priv->sec_info.wep_enabled) {
118  bss_config->protocol = PROTOCOL_STATIC_WEP;
119  bss_config->key_mgmt = KEY_MGMT_NONE;
120  bss_config->wpa_cfg.length = 0;
121 
122  for (i = 0; i < NUM_WEP_KEYS; i++) {
123  wep_key = priv->wep_key[i];
124  bss_config->wep_cfg[i].key_index = i;
125 
126  if (priv->wep_key_curr_index == i)
127  bss_config->wep_cfg[i].is_default = 1;
128  else
129  bss_config->wep_cfg[i].is_default = 0;
130 
131  bss_config->wep_cfg[i].length =
132  wep_key.key_length;
133  memcpy(&bss_config->wep_cfg[i].key,
134  &wep_key.key_material,
135  wep_key.key_length);
136  }
137  }
138  break;
140  bss_config->wpa_cfg.group_cipher = CIPHER_TKIP;
141  break;
143  bss_config->wpa_cfg.group_cipher = CIPHER_AES_CCMP;
144  break;
145  default:
146  break;
147  }
148 
149  return 0;
150 }
151 
152 /* This function updates 11n related parameters from IE and sets them into
153  * bss_config structure.
154  */
155 void
157  struct mwifiex_uap_bss_param *bss_cfg,
159 {
160  const u8 *ht_ie;
161 
162  if (!ISSUPP_11NENABLED(priv->adapter->fw_cap_info))
163  return;
164 
165  ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, params->beacon.tail,
166  params->beacon.tail_len);
167  if (ht_ie) {
168  memcpy(&bss_cfg->ht_cap, ht_ie + 2,
169  sizeof(struct ieee80211_ht_cap));
170  priv->ap_11n_enabled = 1;
171  } else {
172  memset(&bss_cfg->ht_cap , 0, sizeof(struct ieee80211_ht_cap));
173  bss_cfg->ht_cap.cap_info = cpu_to_le16(MWIFIEX_DEF_HT_CAP);
174  bss_cfg->ht_cap.ampdu_params_info = MWIFIEX_DEF_AMPDU;
175  }
176 
177  return;
178 }
179 
180 /* This function finds supported rates IE from beacon parameter and sets
181  * these rates into bss_config structure.
182  */
183 void
186 {
187  struct ieee_types_header *rate_ie;
188  int var_offset = offsetof(struct ieee80211_mgmt, u.beacon.variable);
189  const u8 *var_pos = params->beacon.head + var_offset;
190  int len = params->beacon.head_len - var_offset;
191 
192  rate_ie = (void *)cfg80211_find_ie(WLAN_EID_SUPP_RATES, var_pos, len);
193  if (rate_ie)
194  memcpy(bss_cfg->rates, rate_ie + 1, rate_ie->len);
195 
196  return;
197 }
198 
199 /* This function initializes some of mwifiex_uap_bss_param variables.
200  * This helps FW in ignoring invalid values. These values may or may not
201  * be get updated to valid ones at later stage.
202  */
204 {
205  config->bcast_ssid_ctl = 0x7F;
206  config->radio_ctl = 0x7F;
207  config->dtim_period = 0x7F;
208  config->beacon_period = 0x7FFF;
209  config->auth_mode = 0x7F;
210  config->rts_threshold = 0x7FFF;
211  config->frag_threshold = 0x7FFF;
212  config->retry_limit = 0x7F;
213 }
214 
215 /* This function parses BSS related parameters from structure
216  * and prepares TLVs specific to WPA/WPA2 security.
217  * These TLVs are appended to command buffer.
218  */
219 static void
220 mwifiex_uap_bss_wpa(u8 **tlv_buf, void *cmd_buf, u16 *param_size)
221 {
222  struct host_cmd_tlv_pwk_cipher *pwk_cipher;
223  struct host_cmd_tlv_gwk_cipher *gwk_cipher;
225  struct host_cmd_tlv_akmp *tlv_akmp;
226  struct mwifiex_uap_bss_param *bss_cfg = cmd_buf;
228  u8 *tlv = *tlv_buf;
229 
230  tlv_akmp = (struct host_cmd_tlv_akmp *)tlv;
231  tlv_akmp->tlv.type = cpu_to_le16(TLV_TYPE_UAP_AKMP);
232  tlv_akmp->tlv.len = cpu_to_le16(sizeof(struct host_cmd_tlv_akmp) -
233  sizeof(struct host_cmd_tlv));
234  tlv_akmp->key_mgmt_operation = cpu_to_le16(bss_cfg->key_mgmt_operation);
235  tlv_akmp->key_mgmt = cpu_to_le16(bss_cfg->key_mgmt);
236  cmd_size += sizeof(struct host_cmd_tlv_akmp);
237  tlv += sizeof(struct host_cmd_tlv_akmp);
238 
239  if (bss_cfg->wpa_cfg.pairwise_cipher_wpa & VALID_CIPHER_BITMAP) {
240  pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv;
241  pwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER);
242  pwk_cipher->tlv.len =
243  cpu_to_le16(sizeof(struct host_cmd_tlv_pwk_cipher) -
244  sizeof(struct host_cmd_tlv));
245  pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA);
246  pwk_cipher->cipher = bss_cfg->wpa_cfg.pairwise_cipher_wpa;
247  cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher);
248  tlv += sizeof(struct host_cmd_tlv_pwk_cipher);
249  }
250 
251  if (bss_cfg->wpa_cfg.pairwise_cipher_wpa2 & VALID_CIPHER_BITMAP) {
252  pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv;
253  pwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER);
254  pwk_cipher->tlv.len =
255  cpu_to_le16(sizeof(struct host_cmd_tlv_pwk_cipher) -
256  sizeof(struct host_cmd_tlv));
257  pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA2);
258  pwk_cipher->cipher = bss_cfg->wpa_cfg.pairwise_cipher_wpa2;
259  cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher);
260  tlv += sizeof(struct host_cmd_tlv_pwk_cipher);
261  }
262 
263  if (bss_cfg->wpa_cfg.group_cipher & VALID_CIPHER_BITMAP) {
264  gwk_cipher = (struct host_cmd_tlv_gwk_cipher *)tlv;
265  gwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_GWK_CIPHER);
266  gwk_cipher->tlv.len =
267  cpu_to_le16(sizeof(struct host_cmd_tlv_gwk_cipher) -
268  sizeof(struct host_cmd_tlv));
269  gwk_cipher->cipher = bss_cfg->wpa_cfg.group_cipher;
270  cmd_size += sizeof(struct host_cmd_tlv_gwk_cipher);
271  tlv += sizeof(struct host_cmd_tlv_gwk_cipher);
272  }
273 
274  if (bss_cfg->wpa_cfg.length) {
275  passphrase = (struct host_cmd_tlv_passphrase *)tlv;
276  passphrase->tlv.type = cpu_to_le16(TLV_TYPE_UAP_WPA_PASSPHRASE);
277  passphrase->tlv.len = cpu_to_le16(bss_cfg->wpa_cfg.length);
278  memcpy(passphrase->passphrase, bss_cfg->wpa_cfg.passphrase,
279  bss_cfg->wpa_cfg.length);
280  cmd_size += sizeof(struct host_cmd_tlv) +
281  bss_cfg->wpa_cfg.length;
282  tlv += sizeof(struct host_cmd_tlv) + bss_cfg->wpa_cfg.length;
283  }
284 
285  *param_size = cmd_size;
286  *tlv_buf = tlv;
287 
288  return;
289 }
290 
291 /* This function parses BSS related parameters from structure
292  * and prepares TLVs specific to WEP encryption.
293  * These TLVs are appended to command buffer.
294  */
295 static void
296 mwifiex_uap_bss_wep(u8 **tlv_buf, void *cmd_buf, u16 *param_size)
297 {
299  u16 cmd_size = *param_size;
300  int i;
301  u8 *tlv = *tlv_buf;
302  struct mwifiex_uap_bss_param *bss_cfg = cmd_buf;
303 
304  for (i = 0; i < NUM_WEP_KEYS; i++) {
305  if (bss_cfg->wep_cfg[i].length &&
306  (bss_cfg->wep_cfg[i].length == WLAN_KEY_LEN_WEP40 ||
307  bss_cfg->wep_cfg[i].length == WLAN_KEY_LEN_WEP104)) {
308  wep_key = (struct host_cmd_tlv_wep_key *)tlv;
309  wep_key->tlv.type = cpu_to_le16(TLV_TYPE_UAP_WEP_KEY);
310  wep_key->tlv.len =
311  cpu_to_le16(bss_cfg->wep_cfg[i].length + 2);
312  wep_key->key_index = bss_cfg->wep_cfg[i].key_index;
313  wep_key->is_default = bss_cfg->wep_cfg[i].is_default;
314  memcpy(wep_key->key, bss_cfg->wep_cfg[i].key,
315  bss_cfg->wep_cfg[i].length);
316  cmd_size += sizeof(struct host_cmd_tlv) + 2 +
317  bss_cfg->wep_cfg[i].length;
318  tlv += sizeof(struct host_cmd_tlv) + 2 +
319  bss_cfg->wep_cfg[i].length;
320  }
321  }
322 
323  *param_size = cmd_size;
324  *tlv_buf = tlv;
325 
326  return;
327 }
328 
329 /* This function parses BSS related parameters from structure
330  * and prepares TLVs. These TLVs are appended to command buffer.
331 */
332 static int
333 mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
334 {
336  struct host_cmd_tlv_beacon_period *beacon_period;
337  struct host_cmd_tlv_ssid *ssid;
338  struct host_cmd_tlv_bcast_ssid *bcast_ssid;
339  struct host_cmd_tlv_channel_band *chan_band;
341  struct host_cmd_tlv_rts_threshold *rts_threshold;
342  struct host_cmd_tlv_retry_limit *retry_limit;
343  struct host_cmd_tlv_encrypt_protocol *encrypt_protocol;
345  struct host_cmd_tlv_rates *tlv_rates;
346  struct host_cmd_tlv_ageout_timer *ao_timer, *ps_ao_timer;
347  struct mwifiex_ie_types_htcap *htcap;
348  struct mwifiex_uap_bss_param *bss_cfg = cmd_buf;
349  int i;
350  u16 cmd_size = *param_size;
351 
352  if (bss_cfg->ssid.ssid_len) {
353  ssid = (struct host_cmd_tlv_ssid *)tlv;
354  ssid->tlv.type = cpu_to_le16(TLV_TYPE_UAP_SSID);
355  ssid->tlv.len = cpu_to_le16((u16)bss_cfg->ssid.ssid_len);
356  memcpy(ssid->ssid, bss_cfg->ssid.ssid, bss_cfg->ssid.ssid_len);
357  cmd_size += sizeof(struct host_cmd_tlv) +
358  bss_cfg->ssid.ssid_len;
359  tlv += sizeof(struct host_cmd_tlv) + bss_cfg->ssid.ssid_len;
360 
361  bcast_ssid = (struct host_cmd_tlv_bcast_ssid *)tlv;
362  bcast_ssid->tlv.type = cpu_to_le16(TLV_TYPE_UAP_BCAST_SSID);
363  bcast_ssid->tlv.len =
364  cpu_to_le16(sizeof(bcast_ssid->bcast_ctl));
365  bcast_ssid->bcast_ctl = bss_cfg->bcast_ssid_ctl;
366  cmd_size += sizeof(struct host_cmd_tlv_bcast_ssid);
367  tlv += sizeof(struct host_cmd_tlv_bcast_ssid);
368  }
369  if (bss_cfg->rates[0]) {
370  tlv_rates = (struct host_cmd_tlv_rates *)tlv;
371  tlv_rates->tlv.type = cpu_to_le16(TLV_TYPE_UAP_RATES);
372 
373  for (i = 0; i < MWIFIEX_SUPPORTED_RATES && bss_cfg->rates[i];
374  i++)
375  tlv_rates->rates[i] = bss_cfg->rates[i];
376 
377  tlv_rates->tlv.len = cpu_to_le16(i);
378  cmd_size += sizeof(struct host_cmd_tlv_rates) + i;
379  tlv += sizeof(struct host_cmd_tlv_rates) + i;
380  }
381  if (bss_cfg->channel &&
382  ((bss_cfg->band_cfg == BAND_CONFIG_BG &&
383  bss_cfg->channel <= MAX_CHANNEL_BAND_BG) ||
384  (bss_cfg->band_cfg == BAND_CONFIG_A &&
385  bss_cfg->channel <= MAX_CHANNEL_BAND_A))) {
386  chan_band = (struct host_cmd_tlv_channel_band *)tlv;
387  chan_band->tlv.type = cpu_to_le16(TLV_TYPE_CHANNELBANDLIST);
388  chan_band->tlv.len =
389  cpu_to_le16(sizeof(struct host_cmd_tlv_channel_band) -
390  sizeof(struct host_cmd_tlv));
391  chan_band->band_config = bss_cfg->band_cfg;
392  chan_band->channel = bss_cfg->channel;
393  cmd_size += sizeof(struct host_cmd_tlv_channel_band);
394  tlv += sizeof(struct host_cmd_tlv_channel_band);
395  }
396  if (bss_cfg->beacon_period >= MIN_BEACON_PERIOD &&
397  bss_cfg->beacon_period <= MAX_BEACON_PERIOD) {
398  beacon_period = (struct host_cmd_tlv_beacon_period *)tlv;
399  beacon_period->tlv.type =
401  beacon_period->tlv.len =
402  cpu_to_le16(sizeof(struct host_cmd_tlv_beacon_period) -
403  sizeof(struct host_cmd_tlv));
404  beacon_period->period = cpu_to_le16(bss_cfg->beacon_period);
405  cmd_size += sizeof(struct host_cmd_tlv_beacon_period);
406  tlv += sizeof(struct host_cmd_tlv_beacon_period);
407  }
408  if (bss_cfg->dtim_period >= MIN_DTIM_PERIOD &&
409  bss_cfg->dtim_period <= MAX_DTIM_PERIOD) {
410  dtim_period = (struct host_cmd_tlv_dtim_period *)tlv;
411  dtim_period->tlv.type = cpu_to_le16(TLV_TYPE_UAP_DTIM_PERIOD);
412  dtim_period->tlv.len =
413  cpu_to_le16(sizeof(struct host_cmd_tlv_dtim_period) -
414  sizeof(struct host_cmd_tlv));
415  dtim_period->period = bss_cfg->dtim_period;
416  cmd_size += sizeof(struct host_cmd_tlv_dtim_period);
417  tlv += sizeof(struct host_cmd_tlv_dtim_period);
418  }
419  if (bss_cfg->rts_threshold <= MWIFIEX_RTS_MAX_VALUE) {
420  rts_threshold = (struct host_cmd_tlv_rts_threshold *)tlv;
421  rts_threshold->tlv.type =
423  rts_threshold->tlv.len =
424  cpu_to_le16(sizeof(struct host_cmd_tlv_rts_threshold) -
425  sizeof(struct host_cmd_tlv));
426  rts_threshold->rts_thr = cpu_to_le16(bss_cfg->rts_threshold);
427  cmd_size += sizeof(struct host_cmd_tlv_frag_threshold);
428  tlv += sizeof(struct host_cmd_tlv_frag_threshold);
429  }
430  if ((bss_cfg->frag_threshold >= MWIFIEX_FRAG_MIN_VALUE) &&
431  (bss_cfg->frag_threshold <= MWIFIEX_FRAG_MAX_VALUE)) {
432  frag_threshold = (struct host_cmd_tlv_frag_threshold *)tlv;
433  frag_threshold->tlv.type =
435  frag_threshold->tlv.len =
437  sizeof(struct host_cmd_tlv));
438  frag_threshold->frag_thr = cpu_to_le16(bss_cfg->frag_threshold);
439  cmd_size += sizeof(struct host_cmd_tlv_frag_threshold);
440  tlv += sizeof(struct host_cmd_tlv_frag_threshold);
441  }
442  if (bss_cfg->retry_limit <= MWIFIEX_RETRY_LIMIT) {
443  retry_limit = (struct host_cmd_tlv_retry_limit *)tlv;
444  retry_limit->tlv.type = cpu_to_le16(TLV_TYPE_UAP_RETRY_LIMIT);
445  retry_limit->tlv.len =
446  cpu_to_le16(sizeof(struct host_cmd_tlv_retry_limit) -
447  sizeof(struct host_cmd_tlv));
448  retry_limit->limit = (u8)bss_cfg->retry_limit;
449  cmd_size += sizeof(struct host_cmd_tlv_retry_limit);
450  tlv += sizeof(struct host_cmd_tlv_retry_limit);
451  }
452  if ((bss_cfg->protocol & PROTOCOL_WPA) ||
453  (bss_cfg->protocol & PROTOCOL_WPA2) ||
454  (bss_cfg->protocol & PROTOCOL_EAP))
455  mwifiex_uap_bss_wpa(&tlv, cmd_buf, &cmd_size);
456  else
457  mwifiex_uap_bss_wep(&tlv, cmd_buf, &cmd_size);
458 
459  if ((bss_cfg->auth_mode <= WLAN_AUTH_SHARED_KEY) ||
460  (bss_cfg->auth_mode == MWIFIEX_AUTH_MODE_AUTO)) {
461  auth_type = (struct host_cmd_tlv_auth_type *)tlv;
462  auth_type->tlv.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
463  auth_type->tlv.len =
464  cpu_to_le16(sizeof(struct host_cmd_tlv_auth_type) -
465  sizeof(struct host_cmd_tlv));
466  auth_type->auth_type = (u8)bss_cfg->auth_mode;
467  cmd_size += sizeof(struct host_cmd_tlv_auth_type);
468  tlv += sizeof(struct host_cmd_tlv_auth_type);
469  }
470  if (bss_cfg->protocol) {
471  encrypt_protocol = (struct host_cmd_tlv_encrypt_protocol *)tlv;
472  encrypt_protocol->tlv.type =
474  encrypt_protocol->tlv.len =
476  - sizeof(struct host_cmd_tlv));
477  encrypt_protocol->proto = cpu_to_le16(bss_cfg->protocol);
478  cmd_size += sizeof(struct host_cmd_tlv_encrypt_protocol);
479  tlv += sizeof(struct host_cmd_tlv_encrypt_protocol);
480  }
481 
482  if (bss_cfg->ht_cap.cap_info) {
483  htcap = (struct mwifiex_ie_types_htcap *)tlv;
485  htcap->header.len =
486  cpu_to_le16(sizeof(struct ieee80211_ht_cap));
487  htcap->ht_cap.cap_info = bss_cfg->ht_cap.cap_info;
488  htcap->ht_cap.ampdu_params_info =
489  bss_cfg->ht_cap.ampdu_params_info;
490  memcpy(&htcap->ht_cap.mcs, &bss_cfg->ht_cap.mcs,
491  sizeof(struct ieee80211_mcs_info));
492  htcap->ht_cap.extended_ht_cap_info =
493  bss_cfg->ht_cap.extended_ht_cap_info;
494  htcap->ht_cap.tx_BF_cap_info = bss_cfg->ht_cap.tx_BF_cap_info;
495  htcap->ht_cap.antenna_selection_info =
496  bss_cfg->ht_cap.antenna_selection_info;
497  cmd_size += sizeof(struct mwifiex_ie_types_htcap);
498  tlv += sizeof(struct mwifiex_ie_types_htcap);
499  }
500 
501  if (bss_cfg->sta_ao_timer) {
502  ao_timer = (struct host_cmd_tlv_ageout_timer *)tlv;
503  ao_timer->tlv.type = cpu_to_le16(TLV_TYPE_UAP_AO_TIMER);
504  ao_timer->tlv.len = cpu_to_le16(sizeof(*ao_timer) -
505  sizeof(struct host_cmd_tlv));
506  ao_timer->sta_ao_timer = cpu_to_le32(bss_cfg->sta_ao_timer);
507  cmd_size += sizeof(*ao_timer);
508  tlv += sizeof(*ao_timer);
509  }
510 
511  if (bss_cfg->ps_sta_ao_timer) {
512  ps_ao_timer = (struct host_cmd_tlv_ageout_timer *)tlv;
513  ps_ao_timer->tlv.type = cpu_to_le16(TLV_TYPE_UAP_PS_AO_TIMER);
514  ps_ao_timer->tlv.len = cpu_to_le16(sizeof(*ps_ao_timer) -
515  sizeof(struct host_cmd_tlv));
516  ps_ao_timer->sta_ao_timer =
517  cpu_to_le32(bss_cfg->ps_sta_ao_timer);
518  cmd_size += sizeof(*ps_ao_timer);
519  tlv += sizeof(*ps_ao_timer);
520  }
521 
522  *param_size = cmd_size;
523 
524  return 0;
525 }
526 
527 /* This function parses custom IEs from IE list and prepares command buffer */
528 static int mwifiex_uap_custom_ie_prepare(u8 *tlv, void *cmd_buf, u16 *ie_size)
529 {
530  struct mwifiex_ie_list *ap_ie = cmd_buf;
531  struct host_cmd_tlv *tlv_ie = (struct host_cmd_tlv *)tlv;
532 
533  if (!ap_ie || !ap_ie->len || !ap_ie->ie_list)
534  return -1;
535 
536  *ie_size += le16_to_cpu(ap_ie->len) + sizeof(struct host_cmd_tlv);
537 
538  tlv_ie->type = cpu_to_le16(TLV_TYPE_MGMT_IE);
539  tlv_ie->len = ap_ie->len;
540  tlv += sizeof(struct host_cmd_tlv);
541 
542  memcpy(tlv, ap_ie->ie_list, le16_to_cpu(ap_ie->len));
543 
544  return 0;
545 }
546 
547 /* Parse AP config structure and prepare TLV based command structure
548  * to be sent to FW for uAP configuration
549  */
550 static int
551 mwifiex_cmd_uap_sys_config(struct host_cmd_ds_command *cmd, u16 cmd_action,
552  u32 type, void *cmd_buf)
553 {
554  u8 *tlv;
555  u16 cmd_size, param_size, ie_size;
556  struct host_cmd_ds_sys_config *sys_cfg;
557 
559  cmd_size = (u16)(sizeof(struct host_cmd_ds_sys_config) + S_DS_GEN);
560  sys_cfg = (struct host_cmd_ds_sys_config *)&cmd->params.uap_sys_config;
561  sys_cfg->action = cpu_to_le16(cmd_action);
562  tlv = sys_cfg->tlv;
563 
564  switch (type) {
565  case UAP_BSS_PARAMS_I:
566  param_size = cmd_size;
567  if (mwifiex_uap_bss_param_prepare(tlv, cmd_buf, &param_size))
568  return -1;
569  cmd->size = cpu_to_le16(param_size);
570  break;
571  case UAP_CUSTOM_IE_I:
572  ie_size = cmd_size;
573  if (mwifiex_uap_custom_ie_prepare(tlv, cmd_buf, &ie_size))
574  return -1;
575  cmd->size = cpu_to_le16(ie_size);
576  break;
577  default:
578  return -1;
579  }
580 
581  return 0;
582 }
583 
584 /* This function prepares the AP specific commands before sending them
585  * to the firmware.
586  * This is a generic function which calls specific command preparation
587  * routines based upon the command number.
588  */
590  u16 cmd_action, u32 type,
591  void *data_buf, void *cmd_buf)
592 {
593  struct host_cmd_ds_command *cmd = cmd_buf;
594 
595  switch (cmd_no) {
597  if (mwifiex_cmd_uap_sys_config(cmd, cmd_action, type, data_buf))
598  return -1;
599  break;
602  cmd->command = cpu_to_le16(cmd_no);
603  cmd->size = cpu_to_le16(S_DS_GEN);
604  break;
605  default:
606  dev_err(priv->adapter->dev,
607  "PREP_CMD: unknown cmd %#x\n", cmd_no);
608  return -1;
609  }
610 
611  return 0;
612 }