[9610] wlbt: SCSC Driver version 10.9.1.0
[GitHub/moto-9609/android_kernel_motorola_exynos9610.git] / drivers / net / wireless / scsc / cac.c
CommitLineData
533a23a1
TK
1/****************************************************************************
2 *
3 * Copyright (c) 2012 - 2017 Samsung Electronics Co., Ltd. All rights reserved
4 *
5 ****************************************************************************/
6
7#include "cac.h"
8
9static struct cac_tspec *tspec_list;
10static int tspec_list_next_id;
11static u8 dialog_token_next;
12
13/* Define the meta-data info for tspec_fields */
14static struct tspec_field tspec_fields[] = {
15 { "traffic_type", 0, 1, 0x1, 0 },
16 { "tsid", 0, 1, 0xF, 1 },
17 { "direction", 0, 1, 0x3, 5 },
18 { "access_policy", 0, 1, 0x3, 7 }, /* WMM - always set to 1 */
19 { "aggregation", 0, 1, 0x1, 9 }, /* WMM - not supported */
20 { "psb", 0, 1, 0x1, 10 },
21 { "user_priority", 0, 1, 0x7, 11 },
22 { "tsinfo_ack_policy", 0, 1, 0x3, 14 }, /* WMM - not supported */
23 { "schedule", 0, 1, 0x1, 16 }, /* WMM - not supported */
24 { "nominal_msdu_size", 0, 0, 2, OFFSETOF(nominal_msdu_size) },
25 { "max_msdu_size", 0, 0, 2, OFFSETOF(maximum_msdu_size) },
26 { "min_service_interval", 0, 0, 4, OFFSETOF(minimum_service_interval) },
27 { "max_service_interval", 0, 0, 4, OFFSETOF(maximum_service_interval) },
28 { "inactivity_interval", 0, 0, 4, OFFSETOF(inactivity_interval) },
29 { "suspension_interval", 0, 0, 4, OFFSETOF(suspension_interval) },
30 { "service_start_time", 0, 0, 4, OFFSETOF(service_start_time) },
31 { "min_data_rate", 0, 0, 4, OFFSETOF(minimum_data_rate) },
32 { "mean_data_rate", 0, 0, 4, OFFSETOF(mean_data_rate) },
33 { "peak_data_rate", 0, 0, 4, OFFSETOF(peak_data_rate) },
34 { "max_burst_size", 0, 0, 4, OFFSETOF(maximum_burst_size) },
35 { "delay_bound", 0, 0, 4, OFFSETOF(delay_bound) },
36 { "min_phy_rate", 0, 0, 4, OFFSETOF(minimum_phy_rate) },
37 { "surplus_bw_allowance", 0, 0, 2,
38 OFFSETOF(surplus_bandwidth_allowance) },
39 { "medium_time", 0, 0, 2, OFFSETOF(medium_time) },
40};
41
42/* Define the OUI type data for the corresponding IE's */
43static const u8 TSRS_OUI_TYPE[] = { 0x00, 0x40, 0x96, 0x08 };
44static const u8 EBW_OUI_TYPE[] = { 0x00, 0x40, 0x96, 0x0F };
45
46static const int NUM_TSPEC_FIELDS = sizeof(tspec_fields) / sizeof(struct tspec_field);
47static u32 previous_msdu_lifetime = MAX_TRANSMIT_MSDU_LIFETIME_NOT_VALID;
48static u8 ccx_status = BSS_CCX_DISABLED;
49
50static void cac_set_ric_ie(struct slsi_dev *sdev, struct net_device *netdev);
51static int cac_get_rde_tspec_ie(struct slsi_dev *sdev, u8 *assoc_rsp_ie, int assoc_rsp_ie_len, const u8 **tspec_ie_arr);
533a23a1
TK
52
53/* Name: find_tspec_entry
54 * Desc: Finds a tspec entry in the list of tspecs (tspec_list)
55 * according to tspec id and status (accepted or not accepted)
56 * id: the tspec id
57 * accepted: 1 : accepted by AP, 0: new or rejected by AP
58 * return: pointer to the tspec struct or NULL if a tspec doesn't exist
59 */
60static struct cac_tspec *find_tspec_entry(int id, int accepted)
61{
62 struct cac_tspec *itr;
63
64 itr = tspec_list;
65 while (itr != NULL) {
66 if ((itr->id == id) && (itr->accepted == accepted))
67 break;
68 itr = itr->next;
69 }
70 return itr;
71}
72
73/* Name: cac_query_tspec_field
74 * Desc: Get the value of a tspec's field.
75 * sdev: pointer to the slsi_dev struct
76 * entry: pointer to the tspec
77 * field: the field name
78 * value: poinet to the field value
79 * return: 0 (success), -1 (failure)
80 */
81static int cac_query_tspec_field(struct slsi_dev *sdev, struct cac_tspec *entry, const char *field, u32 *value)
82{
83 int i;
84 u32 tsinfo;
85 u8 mask;
86 u8 *pos;
87
88 if ((entry == NULL) || (field == NULL) || (value == NULL))
89 return -1;
90
91 for (i = 0; i < NUM_TSPEC_FIELDS; i++)
92 if (strcasecmp(field, tspec_fields[i].name) == 0)
93 break;
94 if (i >= NUM_TSPEC_FIELDS) {
95 SLSI_ERR(sdev, "CAC: Invalid TSPEC config field\n");
96 return -1;
97 }
98 if (tspec_fields[i].is_tsinfo_field) {
99 mask = tspec_fields[i].size;
100 tsinfo = CAC_GET_LE24(&entry->tspec.ts_info[0]) & TSINFO_MASK;
101 *value = (tsinfo >> tspec_fields[i].offset) & mask;
102 } else {
103 pos = (u8 *)(&entry->tspec) + tspec_fields[i].offset;
104 if (tspec_fields[i].size == 1)
105 *value = (*pos & 0xFF);
106 else if (tspec_fields[i].size == 2)
107 *value = CAC_GET_LE16(pos);
108 else
109 *value = CAC_GET_LE32(pos);
110 }
111
112 return 0;
113}
114
115/* Name: get_netdev_for_station
116 * Desc: Get the pointer to net_device struct with vif_type == FAPI_VIFTYPE_STATION
117 * sdev: pointer to the slsi_dev struct
118 * return: pointer to the net_device struct or NULL if the it doesn't exist
119 */
120static struct net_device *get_netdev_for_station(struct slsi_dev *sdev)
121{
122 struct net_device *dev;
123 struct netdev_vif *ndev_vif;
124 s32 vif;
125
126 for (vif = 1; vif <= CONFIG_SCSC_WLAN_MAX_INTERFACES; vif++) {
127 dev = slsi_get_netdev_locked(sdev, vif);
128 if (!dev)
129 continue;
130 ndev_vif = netdev_priv(dev);
131 if (!ndev_vif)
132 continue;
133 if (ndev_vif->vif_type == FAPI_VIFTYPE_STATION &&
134 ndev_vif->iftype == NL80211_IFTYPE_STATION)
135 return dev;
136 }
137 return NULL;
138}
139
140/* Name: add_ebw_ie
141 * Desc: Add ebw ie
142 * buf: pointer to buf that the ie is going to added
143 * buf_len: the byte length of the ie
144 * tsid: tspec id
145 * return: length of bytes that were added
146 */
147static int add_ebw_ie(u8 *buf, size_t buf_len, u8 tsid)
148{
149 u8 *pos;
150
151 if ((buf == NULL) || (buf_len < 8))
152 return -1;
153
154 pos = buf;
155 *pos++ = WLAN_EID_VENDOR_SPECIFIC; /* element id */
156 *pos++ = 6; /* length */
157 memcpy(pos, EBW_OUI_TYPE, sizeof(EBW_OUI_TYPE));
158 pos += sizeof(EBW_OUI_TYPE);
159 *pos++ = tsid;
160 *pos++ = 0;
161
162 return pos - buf;
163}
164
165/* Name: add_tsrs_ie
166 * Desc: Add tsrs_ie
167 * buf: pointer to buf that the ie is going to added
168 * buf_len: the byte length of the ie
169 * tsid: tspec id
170 * rates: list of rates that are supported
171 * num_rates: number of rates that are supported
172 * return: length of bytes that were added
173 */
174static int add_tsrs_ie(u8 *buf, size_t buf_len, u8 tsid,
175 u8 rates[CCX_MAX_NUM_RATES], int num_rates)
176{
177 u8 *pos;
178 size_t ie_len = (size_t)(7 + num_rates);
179 int i;
180
181 if ((buf == NULL) || (buf_len < ie_len) || (rates == NULL) ||
182 (num_rates > CCX_MAX_NUM_RATES))
183 return -1;
184
185 pos = buf;
186 memset(pos, 0, ie_len);
187 *pos++ = WLAN_EID_VENDOR_SPECIFIC; /* element id */
188 *pos++ = ie_len - 2; /* length */
189 memcpy(pos, TSRS_OUI_TYPE, sizeof(TSRS_OUI_TYPE));
190 pos += sizeof(TSRS_OUI_TYPE);
191 *pos++ = tsid;
192 for (i = 0; i < num_rates; i++)
193 *pos++ = rates[i];
194
195 return pos - buf;
196}
197
198/* Name: bss_get_ie
199 * Desc: Get the buffer of an IE that is included in a bss
200 * bss: pointer to the cfg80211_bss struct
201 * ie: the IE id that is going to be extracted
202 * return: pointer to the start of the IE buffer
203 */
204static const u8 *bss_get_ie(struct cfg80211_bss *bss, u8 ie)
205{
206 const u8 *pos;
207 u8 ies_len, ies_cur_len;
208
209#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
210 pos = (const u8 *)(bss->ies);
211 ies_len = (u8)bss->ies->len;
212#else
213 pos = (const u8 *)(bss->information_elements);
214 ies_len = (u8)bss->len_information_elements;
215#endif
216 ies_cur_len = 1;
217
218 while (ies_cur_len <= ies_len) {
219 if (pos[0] == ie)
220 return pos;
221
222 pos += 2 + pos[1];
223 ies_cur_len++;
224 }
225
226 return NULL;
227}
228
229/* Name: bss_get_bit_rates
230 * Desc: Get the buffer of an IE that is included in a bss
231 * bss: pointer to the cfg80211_bss struct
232 * rates: the rates that are supported
233 * return: 0 (succes), -1 (failure)
234 */
235static int bss_get_bit_rates(struct cfg80211_bss *bss, u8 **rates)
236{
237 const u8 *ie, *ie2;
238 int i, j;
239 unsigned int len;
240 u8 *r;
241
242 ie = bss_get_ie(bss, WLAN_EID_SUPP_RATES);
243 ie2 = bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
244
245 len = (ie ? ie[1] : 0) + (ie2 ? ie2[1] : 0);
246
247 if (!len)
248 return -1;
249
250 r = kmalloc(len, GFP_KERNEL);
251 if (!r)
252 return -1;
253
254 for (i = 0; ie && i < ie[1]; i++)
255 r[i] = ie[i + 2] & 0x7f;
256
257 for (j = 0; ie2 && j < ie2[1]; j++)
258 r[i + j] = ie2[j + 2] & 0x7f;
259
260 *rates = r;
261 return len;
262}
263
264/* Name: cac_send_addts
265 * Desc: Build and send the ADDTS action frame
266 * sdev: pointer to the slsi_dev struct
267 * id: the tspec id that is going to be included in the ADDTS action frame
268 * ebw: 1 (add ebw IE), 0 (don't add ebw IE)
269 * return: 0 (succes), -1 (failure)
270 */
271static int cac_send_addts(struct slsi_dev *sdev, int id, int ebw)
272{
273 struct action_addts_req *req;
274 size_t extra_ie_len = 50;
275 int ie_len = 0;
276 size_t req_len;
277 struct cac_tspec *entry;
278 u8 tsid, i;
279 u8 *rates;
280 u8 rate = 0;
281 u8 *pos;
282 int num_rates;
283 struct netdev_vif *ndev_vif;
284 struct net_device *netdev;
285 u16 host_tag = slsi_tx_mgmt_host_tag(sdev);
286 struct ieee80211_hdr *hdr;
287 u8 *buf = NULL;
288 u8 *bssid;
289 u8 r = 0;
290
291 entry = find_tspec_entry(id, 0);
292 if (entry == NULL) {
293 SLSI_ERR(sdev, "CAC-ADDTS: Invalid TSPEC ID\n");
294 return -1;
295 }
296
297 SLSI_MUTEX_LOCK(sdev->netdev_add_remove_mutex);
298 netdev = get_netdev_for_station(sdev);
299 if (netdev == NULL) {
300 SLSI_MUTEX_UNLOCK(sdev->netdev_add_remove_mutex);
301 return -1;
302 }
303 ndev_vif = netdev_priv(netdev);
304 if ((ndev_vif == NULL) || (ndev_vif->sta.sta_bss == NULL)) {
305 SLSI_MUTEX_UNLOCK(sdev->netdev_add_remove_mutex);
306 return -1;
307 }
308 SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
309
310 if ((!ndev_vif->activated) || (ndev_vif->vif_type != FAPI_VIFTYPE_STATION) ||
311 (ndev_vif->sta.vif_status != SLSI_VIF_STATUS_CONNECTED)) {
312 SLSI_ERR(sdev, "CAC-ADDTS: Not connected, can't send ADDTS\n");
313 r = -1;
314 goto exit;
315 }
316 bssid = ndev_vif->sta.sta_bss->bssid;
317 if (entry->accepted) {
318 SLSI_ERR(sdev, "CAC-ADDTS: TSPEC already accepted\n");
319 r = -1;
320 goto exit;
321 }
322
323 buf = kmalloc(IEEE80211_HEADER_SIZE + sizeof(*req) + extra_ie_len, GFP_KERNEL);
324 if (buf == NULL) {
325 SLSI_ERR(sdev, "CAC-ADDTS: Failed to allocate ADDTS request\n");
326 r = -1;
327 goto exit;
328 }
329
330 hdr = (struct ieee80211_hdr *)buf;
331 hdr->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, IEEE80211_STYPE_ACTION);
332 SLSI_ETHER_COPY(hdr->addr1, bssid);
333 SLSI_ETHER_COPY(hdr->addr2, sdev->hw_addr);
334 SLSI_ETHER_COPY(hdr->addr3, bssid);
335
336 req = (struct action_addts_req *)(buf + IEEE80211_HEADER_SIZE);
337 req->hdr.category = WLAN_CATEGORY_WMM;
338 req->hdr.action = WMM_ACTION_CODE_ADDTS_REQ;
339 if (dialog_token_next == 0)
340 dialog_token_next++;
341 req->hdr.dialog_token = dialog_token_next++;
342 req->hdr.status_code = 0;
343 tsid = (CAC_GET_LE24(req->tspec.ts_info) >> 1) & 0xF;
344
345 /* Find the value of PSB in TSPEC. If PSB is unspecified; fill the
346 * value from UAPSD value stored in Peer structure for the AC
347 */
348 if (entry->psb_specified == 0) {
349 struct slsi_peer *peer;
350 u32 priority;
351
352 peer = slsi_get_peer_from_qs(sdev, netdev, SLSI_STA_PEER_QUEUESET);
353 if (!peer) {
354 SLSI_ERR(sdev, "CAC-ADDTS: no Peer found\n");
355 r = -1;
356 goto exit_free_buf;
357 }
358
359 cac_query_tspec_field(sdev, entry, "user_priority", &priority);
360 if (peer->uapsd & BIT(slsi_frame_priority_to_ac_queue(priority)))
361 entry->tspec.ts_info[1] |= 0x04;
362 }
363 memcpy(&req->tspec, &entry->tspec, sizeof(entry->tspec));
364 req_len = sizeof(*req);
365 pos = (u8 *)(req + 1);
366 entry->ebw = ebw ? 1 : 0;
367
368 if (ebw) {
369 ie_len += add_ebw_ie(pos, extra_ie_len, tsid);
370 if (ie_len <= 0)
371 SLSI_ERR(sdev, "CAC-ADDTS: Failed to add EBW IE\n");
372 }
373
374 /* Add tsrs IE in case of ccx enabled bss */
375 if (ccx_status == BSS_CCX_ENABLED) {
376 num_rates = bss_get_bit_rates(ndev_vif->sta.sta_bss, &rates);
377 if (num_rates <= 0)
378 rate = 12; /* Default to 6Mbps */
379 else {
380 for (i = 0; i < num_rates; i++)
381 if ((rates[i] > rate) && (rates[i] <= 48))
382 rate = rates[i];
383 kfree(rates);
384 }
385
386 do {
387 /* if the nominal rate is equal to minimum_phy_rate
388 * don't add the tsrs_ie
389 */
390 if ((rate * TSRS_RATE_PER_UNIT) == req->tspec.minimum_phy_rate)
391 break;
392
393 if ((rate * TSRS_RATE_PER_UNIT) > req->tspec.minimum_phy_rate) {
394 ie_len += add_tsrs_ie(pos + ie_len, extra_ie_len - ie_len,
395 tsid, &rate, 1);
396 if (ie_len <= 0) {
397 SLSI_ERR(sdev, "CAC-ADDTS: Failed to add TSRS IE\n");
398 r = -1;
399 goto exit_free_buf;
400 }
401 } else { /* only the "<" case is possible */
402 SLSI_ERR(sdev, "CAC-ADDTS: BSS rate too low\n");
403 r = -1;
404 goto exit_free_buf;
405 }
406 } while (0);
407 }
408
409 if (slsi_mlme_send_frame_mgmt(sdev, netdev, buf, (IEEE80211_HEADER_SIZE + req_len + ie_len),
410 FAPI_DATAUNITDESCRIPTOR_IEEE802_11_FRAME, FAPI_MESSAGETYPE_IEEE80211_ACTION,
411 host_tag, 0, sdev->fw_dwell_time, 0) != 0) {
412 SLSI_ERR(sdev, "CAC-ADDTS: Failed to send ADDTS request\n");
413 r = -1;
414 goto exit_free_buf;
415 }
416 entry->dialog_token = req->hdr.dialog_token;
417
418exit_free_buf:
419 kfree(buf);
420exit:
421 SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
422 SLSI_MUTEX_UNLOCK(sdev->netdev_add_remove_mutex);
423 return r;
424}
425
426/* Name: cac_send_delts
427 * Desc: Build and send the DELTS action frame
428 * sdev: pointer to the slsi_dev struct
429 * id: the tspec id that is going the DELTS action frame to send for
430 * return: 0 (succes), -1 (failure)
431 */
432static int cac_send_delts(struct slsi_dev *sdev, int id)
433{
434 struct action_delts_req *req;
435 struct cac_tspec *entry;
436 size_t req_len;
437 u32 priority;
438 int rc;
439 struct netdev_vif *ndev_vif;
440 struct net_device *netdev;
441 u16 host_tag = slsi_tx_mgmt_host_tag(sdev);
442 struct ieee80211_hdr *hdr;
443 u8 *buf = NULL;
444 u8 *bssid;
445 u8 r = 0;
446 struct slsi_peer *stapeer;
447
448 entry = find_tspec_entry(id , 1);
449 if (entry == NULL) {
450 SLSI_ERR(sdev, "CAC-DELTS: no TSPEC has been established for tsid=%d\n", id);
451 return -1;
452 }
453
454 SLSI_MUTEX_LOCK(sdev->netdev_add_remove_mutex);
455 netdev = get_netdev_for_station(sdev);
456 if (netdev == NULL) {
457 SLSI_MUTEX_UNLOCK(sdev->netdev_add_remove_mutex);
458 return -1;
459 }
460 ndev_vif = netdev_priv(netdev);
461 if ((ndev_vif == NULL) || (ndev_vif->sta.sta_bss == NULL)) {
462 SLSI_MUTEX_UNLOCK(sdev->netdev_add_remove_mutex);
463 return -1;
464 }
465 SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
466
467 if ((!ndev_vif->activated) || (ndev_vif->vif_type != FAPI_VIFTYPE_STATION) ||
468 (ndev_vif->sta.vif_status != SLSI_VIF_STATUS_CONNECTED)) {
469 SLSI_ERR(sdev, "CAC-DELTS: Not connected, can't send DELTS\n");
470 r = -1;
471 goto exit;
472 }
473
474 stapeer = slsi_get_peer_from_qs(sdev, netdev, SLSI_STA_PEER_QUEUESET);
475 if (WARN_ON(!stapeer)) {
476 r = -1;
477 goto exit;
478 }
479
480 bssid = ndev_vif->sta.sta_bss->bssid;
481 buf = kmalloc(24 + sizeof(*req), GFP_KERNEL);
482 if (buf == NULL) {
483 SLSI_ERR(sdev, "CAC-DELTS: Failed to allocate DELTS request\n");
484 r = -1;
485 goto exit;
486 }
487 hdr = (struct ieee80211_hdr *)buf;
488 hdr->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, IEEE80211_STYPE_ACTION);
489 SLSI_ETHER_COPY(hdr->addr1, bssid);
490 SLSI_ETHER_COPY(hdr->addr2, sdev->hw_addr);
491 SLSI_ETHER_COPY(hdr->addr3, bssid);
492 req = (struct action_delts_req *)(buf + 24);
493 req_len = sizeof(*req);
494 req->hdr.category = WLAN_CATEGORY_WMM;
495 req->hdr.action = WMM_ACTION_CODE_DELTS;
496 req->hdr.dialog_token = 0;
497 req->hdr.status_code = 0;
498 memcpy(&req->tspec, &entry->tspec, sizeof(entry->tspec));
499
500 /* TODO_HARDMAC: If PMF is negotiated over the link, the host shall not
501 * issue this primitive before pairwise keys have been installed in F/W .
502 */
503 if (slsi_mlme_send_frame_mgmt(sdev, netdev, buf, (IEEE80211_HEADER_SIZE + req_len), FAPI_DATAUNITDESCRIPTOR_IEEE802_11_FRAME, FAPI_MESSAGETYPE_IEEE80211_ACTION, host_tag, 0, 0, 0) != 0) {
504 SLSI_ERR(sdev, "CAC-DELTS: Failed to send DELTS request\n");
505 r = -1;
506 goto exit_free_buf;
507 }
508 rc = cac_query_tspec_field(sdev, entry, "user_priority", &priority);
509 if (rc != 0) {
510 SLSI_ERR(sdev, "CAC-DELTS: Error in reading priority from tspec!\n");
511 r = -1;
512 goto exit_free_buf;
513 }
514
515 if (slsi_mlme_del_traffic_parameters(sdev, netdev, priority) != 0) {
516 SLSI_ERR(sdev, "CAC-DELTS: Failed to send DELTS request\n");
517 r = -1;
518 goto exit_free_buf;
519 }
520
521 /* BlockAck Control Req was previously used to enable blockack for VO & VI. This
522 * signal is removed and expected to be replaced with MIBs - not able to see
523 * through the haze yet!. Need to take approp. action when the cloud clears.
524 * Historical Data:
525 * if the DELTS request is for UP = 4 or 5 then generate a
526 * MLME-BLOCKACK-CONTROL.request so that no BlockAck is negotiated
527 * on AC_VI. And leave AC_BE enabled
528 */
529
530 entry->accepted = 0; /* DELTS sent successfully */
531 sdev->tspec_error_code = 0;
532 stapeer->tspec_established &= ~BIT(priority);
533 /* update RIC in add_info_elements for assoc req */
534 cac_set_ric_ie(sdev, netdev);
535
536 if (ccx_status == BSS_CCX_ENABLED && previous_msdu_lifetime != MAX_TRANSMIT_MSDU_LIFETIME_NOT_VALID)
537 if (slsi_send_max_transmit_msdu_lifetime(sdev, netdev, previous_msdu_lifetime) != 0) {
538 SLSI_ERR(sdev, "CAC-DELTS: slsi_send_max_msdu_lifetime failed");
539 goto exit_free_buf;
540 }
541exit_free_buf:
542 kfree(buf);
543exit:
544 SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
545 SLSI_MUTEX_UNLOCK(sdev->netdev_add_remove_mutex);
546 return r;
547}
548
549/* Name: cac_create_tspec
550 * Desc: Create a tspec entry and added it to the tspec list
551 * sdev: pointer to the slsi_dev struct
552 * id: the id of the tspec that is included in DELTS action frame
553 * return: 0 (succes), -1 (failure)
554 */
555static int cac_create_tspec(struct slsi_dev *sdev, char *args)
556{
557 struct cac_tspec *entry;
558 int id;
559 u8 tid_auto_done = 0;
560 struct netdev_vif *ndev_vif;
561 struct net_device *netdev;
562
563 SLSI_MUTEX_LOCK(sdev->netdev_add_remove_mutex);
564 netdev = get_netdev_for_station(sdev);
565 if (netdev == NULL) {
566 SLSI_MUTEX_UNLOCK(sdev->netdev_add_remove_mutex);
567 return -1;
568 }
569 ndev_vif = netdev_priv(netdev);
570 if (ndev_vif == NULL) {
571 SLSI_MUTEX_UNLOCK(sdev->netdev_add_remove_mutex);
572 return -1;
573 }
574 SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
575
576 if ((!ndev_vif->activated) || (ndev_vif->vif_type != FAPI_VIFTYPE_STATION) ||
577 (ndev_vif->sta.vif_status != SLSI_VIF_STATUS_CONNECTED)) {
578 SLSI_ERR(sdev, "CAC-ADDTS: Not connected, can't create TSPEC\n");
579 SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
580 SLSI_MUTEX_UNLOCK(sdev->netdev_add_remove_mutex);
581 return -1;
582 }
583 SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
584 SLSI_MUTEX_UNLOCK(sdev->netdev_add_remove_mutex);
585
586 if (args == NULL) {
587 /* No input for tid, so we use the auto increment*/
588 if (tspec_list_next_id <= 7) {
589 id = tspec_list_next_id++;
590 } else {
591 id = 0;
592 tspec_list_next_id = 0;
593 tspec_list_next_id++;
594 }
595 tid_auto_done = 1;
596 }
597
598 if ((!tid_auto_done) && (strtoint(args, &id) < 0)) {
599 /* Invalid input for tid, so we use the auto increment*/
600 if (tspec_list_next_id <= 7) {
601 id = tspec_list_next_id++;
602 } else {
603 id = 0;
604 tspec_list_next_id = 0;
605 tspec_list_next_id++;
606 }
607 }
608
609 if (id < TSID_MIN || id > TSID_MAX) {
610 SLSI_ERR(sdev, "CAC: Invalid TSID =%d, must be in range 0-7\n", id);
611 return -1;
612 }
613
614 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
615 if (entry == NULL) {
616 SLSI_ERR(sdev, "CAC: Failed to allocate TSPEC\n");
617 return -1;
618 }
619
620 entry->id = id;
621 entry->tspec.eid = WLAN_EID_VENDOR_SPECIFIC;
622 entry->tspec.length = sizeof(entry->tspec) - sizeof(entry->tspec.eid) - sizeof(entry->tspec.length);
623 CAC_PUT_BE24(entry->tspec.oui, WLAN_OUI_MICROSOFT);
624 entry->tspec.oui_type = WLAN_OUI_TYPE_MICROSOFT_WMM;
625 entry->tspec.oui_subtype = WMM_OUI_SUBTYPE_TSPEC_ELEMENT;
626 entry->tspec.version = WMM_VERSION;
627 entry->accepted = 0;
628 entry->psb_specified = 0;
629 /* Setting the 7th bit of ts info to 1, as its a fixed reserved bit. */
630 entry->tspec.ts_info[0] = 0x80;
631
632 entry->next = tspec_list;
633 tspec_list = entry;
634 SLSI_DBG1(sdev, SLSI_MLME, "CAC: Created TSPEC entry for id =%d\n", id);
635
636 return entry->id;
637}
638
639/* Name: cac_delete_tspec
640 * Desc: delete a tspec from the list of the tspecs
641 * sdev: pointer to the slsi_dev struct
642 * id: the id of the tspec that will be deleted
643 * return: 0 (succes), -1 (failure)
644 */
645static int cac_delete_tspec(struct slsi_dev *sdev, int id)
646{
647 struct cac_tspec *itr;
648 struct cac_tspec *prev;
649
650 itr = tspec_list;
651 prev = NULL;
652 while (itr != NULL) {
653 if (itr->id == id) {
654 if (prev)
655 prev->next = itr->next;
656 else
657 tspec_list = itr->next;
658
659 if (itr->accepted)
660 cac_send_delts(sdev, itr->id);
661
662 SLSI_DBG3(sdev, SLSI_MLME, "CAC: TSPEC entry deleted for id =%d\n", id);
663 kfree(itr);
664
665 return 0;
666 }
667 prev = itr;
668 itr = itr->next;
669 }
670 SLSI_ERR(sdev, "CAC: Couldn't find TSPEC with id %d for deletion", id);
671
672 return -1;
673}
674
675/* Name: cac_delete_tspec_by_state
676 * Desc: delete a tspec from the list of the tspecs based on id and state
677 * sdev: pointer to the slsi_dev struct
678 * id: the id of the tspec that will be deleted
679 * accepted: 0 - not yet accepted by AP, 1- accepted by AP
680 * return: 0 (succes), -1 (failure)
681 */
682static int cac_delete_tspec_by_state(struct slsi_dev *sdev, int id, int accepted)
683{
684 struct cac_tspec *itr;
685 struct cac_tspec *prev;
686
687 itr = tspec_list;
688 prev = NULL;
689 while (itr != NULL) {
690 if ((itr->id == id) && (itr->accepted == accepted)) {
691 if (prev)
692 prev->next = itr->next;
693 else
694 tspec_list = itr->next;
695
696 SLSI_DBG3(sdev, SLSI_MLME, "CAC: Deleting TSPEC 0x%p with ID %d (accepted =%d)\n", itr, id, accepted);
697 kfree(itr);
698 return 0;
699 }
700 prev = itr;
701 itr = itr->next;
702 }
703 SLSI_ERR(sdev, "CAC: Couldn't find TSPEC with ID %d (accepted =%d)\n", id, accepted);
704
705 return -1;
706}
707
708/* Name: cac_config_tspec
709 * Desc: Set a field's value of a tspec
710 * sdev: pointer to the slsi_dev struct
711 * id: the id of the tspec that will be configured
712 * field: the field name that will be changed
713 * value: the value of the field
714 * return: 0 (succes), -1 (failure)
715 */
716static int cac_config_tspec(struct slsi_dev *sdev, int id, const char *field, u32 value)
717{
718 struct cac_tspec *entry;
719 int i;
720 u32 max = 0xFFFFFFFF;
721 u32 tsinfo;
722 u8 mask;
723 u8 *pos;
724
725 if (field == NULL)
726 return -1;
727
728 entry = find_tspec_entry(id, 0);
729 if (entry == NULL) {
730 SLSI_ERR(sdev, "CAC: Invalid TSPEC ID\n");
731 return -1;
732 }
733
734 for (i = 0; i < NUM_TSPEC_FIELDS; i++)
735 if (strcasecmp(field, tspec_fields[i].name) == 0)
736 break;
737 if (i >= NUM_TSPEC_FIELDS) {
738 SLSI_ERR(sdev, "CAC: Invalid TSPEC config field\n");
739 return -1;
740 }
741 if (tspec_fields[i].read_only) {
742 SLSI_ERR(sdev, "CAC: TSPEC field is read-only\n");
743 return -1;
744 }
745 if (tspec_fields[i].is_tsinfo_field) {
746 mask = tspec_fields[i].size;
747 if (strcasecmp(field, "psb") == 0) {
748 if (value <= mask)
749 entry->psb_specified = 1;
750 else
751 return 0;
752 }
753 if (value > mask) {
754 SLSI_ERR(sdev, "CAC: TSPEC config value exceeded maximum for %s\n", tspec_fields[i].name);
755 return -1;
756 }
757
758 tsinfo = CAC_GET_LE24(&entry->tspec.ts_info[0]);
759 tsinfo &= ~(u32)(mask << tspec_fields[i].offset);
760 tsinfo |= (u32)((value & mask) << tspec_fields[i].offset);
761 CAC_PUT_LE24(entry->tspec.ts_info, tsinfo);
762 } else {
763 if (tspec_fields[i].size < 4)
764 max = ((1 << (tspec_fields[i].size * 8)) - 1);
765
766 if (value > max) {
767 SLSI_ERR(sdev, "CAC: TSPEC config value exceeded maximumfor %s\n", tspec_fields[i].name);
768 return -1;
769 }
770
771 pos = (u8 *)(&entry->tspec) + tspec_fields[i].offset;
772 if (tspec_fields[i].size == 1)
773 *pos = (value & 0xFF);
774 else if (tspec_fields[i].size == 2)
775 CAC_PUT_LE16(pos, value);
776 else
777 CAC_PUT_LE32(pos, value);
778 }
779
780 return 0;
781}
782
783/* Name: cac_ctrl_create_tspec
784 * Desc: public function to create tspec
785 * sdev: pointer to the slsi_dev struct
786 * return: tspec id
787 */
788int cac_ctrl_create_tspec(struct slsi_dev *sdev, char *args)
789{
790 int id;
791
792 id = cac_create_tspec(sdev, args);
793 if (id < 0)
794 return -1;
795
796 return id;
797}
798
799/* Name: cac_ctrl_delete_tspec
800 * Desc: public function to delete tspec
801 * sdev: pointer to the slsi_dev struct
802 * args:pointer to a buffer that contains the agrs for deleting tspec from the list
803 * return: 0 (succes), -1 (failure)
804 */
805int cac_ctrl_delete_tspec(struct slsi_dev *sdev, char *args)
806{
807 int id;
808
809 if (strtoint(args, &id) < 0) {
810 SLSI_ERR(sdev, "CAC-DELETE-TSPEC: Invalid TSPEC ID\n");
811 return -1;
812 }
813
814 if (cac_delete_tspec(sdev, id) < 0)
815 return -1;
816
817 return 0;
818}
819
820/* Name: cac_ctrl_config_tspec
821 * Desc: public function to configure a tspec
822 * sdev: pointer to the slsi_dev struct
823 * args: pointer to a buffer that contains the agrs for tspec configuration
824 * return: 0 (succes), -1 (failure)
825 */
826int cac_ctrl_config_tspec(struct slsi_dev *sdev, char *args)
827{
828 char *id;
829 char *field;
830 char *value;
831 int tspec_id;
832 u32 val;
833
834 id = args;
835 field = strchr(id, ' ');
836 if (field == NULL) {
837 SLSI_ERR(sdev, "CAC: field string is NULL\n");
838 return -1;
839 }
840 *field++ = '\0';
841 value = strchr(field, ' ');
842 if (value == NULL) {
843 SLSI_ERR(sdev, "CAC: field value is NULL\n");
844 return -1;
845 }
846 *value++ = '\0';
847
848 if (strtoint(id, &tspec_id) < 0) {
849 SLSI_ERR(sdev, "CAC: Conversion error for tspecid\n");
850 return -1;
851 }
852
853 if (strtoint(value, &val) < 0) {
854 SLSI_ERR(sdev, "CAC: Conversion error for tspecid value\n");
855 return -1;
856 }
857
858 if (cac_config_tspec(sdev, tspec_id, field, val) < 0)
859 return -1;
860
861 return 0;
862}
863
864/* Name: cac_ctrl_send_addts
865 * Desc: public function to send ADDTS action frame
866 * sdev: pointer to the slsi_dev struct
867 * args: buffer that contains the agrs for ADDTS request
868 * return: 0 (succes), -1 (failure)
869 */
870int cac_ctrl_send_addts(struct slsi_dev *sdev, char *args)
871{
872 char *id_str;
873 char *ebw_str;
874 int id;
875 int ebw = 0;
876
877 if (args == NULL)
878 return -1;
879
880 id_str = args;
881 ebw_str = strchr(id_str, ' ');
882 if (ebw_str != NULL) {
883 *ebw_str++ = '\0';
884 if (!strncmp(ebw_str, "ebw", 3))
885 ebw = 1;
886 }
887 if (strtoint(id_str, &id) < 0) {
888 SLSI_ERR(sdev, "CAC: Conversion error for tspecid value\n");
889 return -1;
890 }
891 if (cac_send_addts(sdev, id, ebw) < 0)
892 return -1;
893
894 return 0;
895}
896
897/* Name: cac_ctrl_send_delts
898 * Desc: public function to send DELTS action frame
899 * sdev: pointer to the slsi_dev struct
900 * args: buffer that contains the agrs for DELTS request
901 * return: 0 (succes), -1 (failure)
902 */
903int cac_ctrl_send_delts(struct slsi_dev *sdev, char *args)
904{
905 int id;
906
907 if (args == NULL)
908 return -1;
909
910 if (strtoint(args, &id) < 0) {
911 SLSI_ERR(sdev, "CAC: Invalid TSPEC ID\n");
912 return -1;
913 }
914 if (cac_send_delts(sdev, id) < 0)
915 return -1;
916
917 return 0;
918}
919
920/* Name: cac_process_delts_req
921 * Desc: process a DELTS request
922 * sdev: pointer to the slsi_dev struct
923 * req: buffer of the DELTS request
924 * return: 0 (succes), -1 (failure)
925 */
926static void cac_process_delts_req(struct slsi_dev *sdev, struct net_device *netdev, struct action_delts_req *req)
927{
928 struct netdev_vif *ndev_vif = netdev_priv(netdev);
929 struct cac_tspec *itr;
930 u32 priority;
931 int rc;
932 struct slsi_peer *stapeer;
933 u8 tid;
934
935 WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex));
936
937 if ((!ndev_vif->activated) || (ndev_vif->vif_type != FAPI_VIFTYPE_STATION) ||
938 (ndev_vif->sta.vif_status != SLSI_VIF_STATUS_CONNECTED) || (ndev_vif->sta.sta_bss == NULL)) {
939 SLSI_ERR(sdev, "CAC: Not connected, Unexpected DELTS request\n");
940 return;
941 }
942
943 stapeer = slsi_get_peer_from_qs(sdev, netdev, SLSI_STA_PEER_QUEUESET);
944 if (WARN_ON(!stapeer))
945 return;
946
947 tid = (CAC_GET_LE24(req->tspec.ts_info) >> 1) & 0xF;
948 SLSI_DBG1(sdev, SLSI_MLME, "CAC: TID in delts request =%d\n", tid);
949
950 itr = find_tspec_entry(tid, 1);
951 if (itr == NULL) {
952 SLSI_ERR(sdev, "CAC: No matching TSPEC found\n");
953 return;
954 }
955
956 rc = cac_query_tspec_field(sdev, itr, "user_priority", &priority);
957 if (rc != 0) {
958 SLSI_ERR(sdev, "CAC: Missing priority from TSPEC!\n");
959 return;
960 }
961
962 if (slsi_mlme_del_traffic_parameters(sdev, netdev, priority) != 0) {
963 SLSI_ERR(sdev, "CAC: Failed to send DEL-TRAFFIC_PARAMETERS request\n");
964 return;
965 }
966
967 /* BlockAck Control Req was previously used to enable blockack for VO & VI. This
968 * signal is removed and expected to be replaced with MIBs - not able to see
969 * through the haze yet!. Need to take approp. action when the cloud clears.
970 * Historical Data:
971 * if the DELTS request is for UP = 4 or 5 then generate a
972 * MLME-BLOCKACK-CONTROL.request so that no BlockAck is negotiated
973 * on AC_VI. And leave AC_BE enabled
974 */
975
976 itr->accepted = 0; /* del traffic parameters sent successfully */
977 stapeer->tspec_established &= ~BIT(priority);
978 SLSI_DBG1(sdev, SLSI_MLME, "tspec_established =%x\n", stapeer->tspec_established);
979 /* update RIC in add_info_elements for assoc req */
980 cac_set_ric_ie(sdev, netdev);
981
982 if (ccx_status == BSS_CCX_ENABLED && previous_msdu_lifetime != MAX_TRANSMIT_MSDU_LIFETIME_NOT_VALID)
983 if (slsi_send_max_transmit_msdu_lifetime(sdev, netdev, previous_msdu_lifetime) != 0) {
984 SLSI_ERR(sdev, "CAC: slsi_send_max_msdu_lifetime failed");
985 return;
986 }
987}
988
989/* Name: cac_find_edca_ie
990 * Desc: Finds the edca IE in the ADDTS response action frame
991 * sdev: pointer to the slsi_dev struct
992 * ie: buffer of the edca IE
993 * tsid: the tsid that is included in the edca IE
994 * lifetime: the lifetime value that is included in the edca IE
995 * return: 0 (succes), -1 (failure)
996 */
997static int cac_find_edca_ie(const u8 *ie, size_t ie_len, u8 *tsid, u16 *lifetime)
998{
999 const u8 *pos = ie;
1000
1001 if ((ie == NULL) || (ie_len < 9) ||
1002 (tsid == NULL) || (lifetime == NULL))
1003 return -1;
1004
1005 pos = cfg80211_find_vendor_ie(WLAN_OUI_CISCO, WLAN_OUI_TYPE_CISCO_EDCA, ie, ie_len);
1006 if (pos && (pos + 9 <= ie + ie_len)) {
1007 *tsid = pos[6];
1008 *lifetime = CAC_GET_LE16(&pos[7]);
1009 return 0;
1010 }
1011
1012 return -1;
1013}
1014
1015/* Name: cac_process_addts_rsp
1016 * Desc: parsing of the addts response
1017 * sdev: pointer to the slsi_dev struct
1018 * rsp: the buffer of the ADDTS response received
1019 * ie_len: the length of the buffer
1020 * return: 0 (succes), -1 (failure)
1021 */
1022static void cac_process_addts_rsp(struct slsi_dev *sdev, struct net_device *netdev, struct action_addts_rsp *rsp, const u8 *ie, size_t ie_len)
1023{
1024 struct netdev_vif *ndev_vif = netdev_priv(netdev);
1025 struct cac_tspec *itr, *entry;
1026 struct wmm_tspec_element *tspec;
1027 u32 priority, prev_priority;
1028 int rc;
1029 u8 tsid;
1030 u16 msdu_lifetime;
1031 struct slsi_peer *peer;
1032 u16 medium_time;
1033
1034 WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex));
1035
1036 SLSI_DBG1(sdev, SLSI_MLME, "\n");
1037
1038 if ((!ndev_vif->activated) || (ndev_vif->vif_type != FAPI_VIFTYPE_STATION) ||
1039 (ndev_vif->sta.vif_status != SLSI_VIF_STATUS_CONNECTED) || (ndev_vif->sta.sta_bss == NULL)) {
1040 SLSI_ERR(sdev, "CAC: Not connected, INVALID state for ADDTS response\n");
1041 return;
1042 }
1043
1044 peer = slsi_get_peer_from_qs(sdev, netdev, SLSI_STA_PEER_QUEUESET);
1045 if (WARN_ON(!peer))
1046 return;
1047
1048 itr = tspec_list;
1049 while (itr != NULL) {
1050 if (itr->dialog_token == rsp->hdr.dialog_token) {
1051 itr->dialog_token = 0; /*reset the dialog token to avoid any incorrect matches if AP send incorrect value*/
1052 break;
1053 }
1054 itr = itr->next;
1055 }
1056 if (itr == NULL) {
1057 SLSI_ERR(sdev, "CAC: No matching TSPEC found for ADDTS response\n");
1058 return;
1059 }
1060
1061 if (rsp->hdr.status_code != ADDTS_STATUS_ACCEPTED) {
1062 SLSI_ERR(sdev, "CAC: TSPEC rejected (status=0x%02X)", rsp->hdr.status_code);
1063 cac_delete_tspec_by_state(sdev, itr->id , 0);
1064 return;
1065 }
1066
1067 if ((ccx_status == BSS_CCX_ENABLED) && cac_find_edca_ie(ie, ie_len, &tsid, &msdu_lifetime) != 0)
1068 msdu_lifetime = MSDU_LIFETIME_DEFAULT;
1069
1070 tspec = (struct wmm_tspec_element *)(rsp + 1);
1071 medium_time = tspec->medium_time;
1072
1073 rc = cac_query_tspec_field(sdev, itr, "user_priority", &priority);
1074 SLSI_DBG1(sdev, SLSI_MLME, "CAC: Priority for current tspec id %d=%d\n", itr->id, priority);
1075
1076 if (peer->tspec_established == 0)
1077 goto set_params;
1078
1079 SLSI_DBG1(sdev, SLSI_MLME, "TSPEC already established\n");
1080
1081 /* TSPEC is already established . Check if it is for same UP / UP mapping to same AC
1082 * If same UP (or UP mapping to same AC) : set params with modified values
1083 * If not, set traffic params for this priority (new AC)
1084 */
1085 switch (priority) {
1086 /*AC_BK*/
1087 case FAPI_PRIORITY_QOS_UP1:
1088 case FAPI_PRIORITY_QOS_UP2:
1089 if (peer->tspec_established & BIT(FAPI_PRIORITY_QOS_UP1))
1090 prev_priority = FAPI_PRIORITY_QOS_UP1;
1091 else if (peer->tspec_established & BIT(FAPI_PRIORITY_QOS_UP2))
1092 prev_priority = FAPI_PRIORITY_QOS_UP2;
1093 else
1094 goto set_params;
1095 break;
1096
1097 /*AC_BE*/
1098 case FAPI_PRIORITY_QOS_UP0:
1099 case FAPI_PRIORITY_QOS_UP3:
1100 if (peer->tspec_established & BIT(FAPI_PRIORITY_QOS_UP0))
1101 prev_priority = FAPI_PRIORITY_QOS_UP0;
1102 else if (peer->tspec_established & BIT(FAPI_PRIORITY_QOS_UP3))
1103 prev_priority = FAPI_PRIORITY_QOS_UP3;
1104 else
1105 goto set_params;
1106 break;
1107
1108 /*AC_VI*/
1109 case FAPI_PRIORITY_QOS_UP4:
1110 case FAPI_PRIORITY_QOS_UP5:
1111 if (peer->tspec_established & BIT(FAPI_PRIORITY_QOS_UP4))
1112 prev_priority = FAPI_PRIORITY_QOS_UP4;
1113 else if (peer->tspec_established & BIT(FAPI_PRIORITY_QOS_UP5))
1114 prev_priority = FAPI_PRIORITY_QOS_UP5;
1115 else
1116 goto set_params;
1117 break;
1118
1119 /*AC_VO*/
1120 case FAPI_PRIORITY_QOS_UP6:
1121 case FAPI_PRIORITY_QOS_UP7:
1122 if (peer->tspec_established & BIT(FAPI_PRIORITY_QOS_UP6))
1123 prev_priority = FAPI_PRIORITY_QOS_UP6;
1124 else if (peer->tspec_established & BIT(FAPI_PRIORITY_QOS_UP7))
1125 prev_priority = FAPI_PRIORITY_QOS_UP7;
1126 else
1127 goto set_params;
1128 break;
1129 /* invalid*/
1130 default:
1131 SLSI_ERR(sdev, "CAC: Invalid UP in the request\n");
1132 return;
1133 }
1134
1135 /* Look for TSPEC entry for initial request */
1136 entry = find_tspec_entry(itr->id, 1);
1137 if (entry) { /*same TID*/
1138 cac_query_tspec_field(sdev, entry, "user_priority", &prev_priority);
1139 SLSI_DBG1(sdev, SLSI_MLME, "CAC: Modify TSPEC (prev_priority =%d)\n", prev_priority);
1140 /* On receiving the new medium time (second ADDTS Response) , driver shall issue
1141 * mlme-set-traffic-parameters.request with the received medium time.
1142 * Use UP from old entry so FW can replace the medium time
1143 * Delete the old entry in host, and replace UP in new entry.
1144 */
1145 cac_delete_tspec_by_state(sdev, entry->id, 1);
1146 if (priority != prev_priority) {
1147 itr->tspec.ts_info[1] &= ~(7 << 3) ; /*clear the value*/
1148 itr->tspec.ts_info[1] |= prev_priority << 3 ; /*set the value*/
1149 priority = prev_priority;
1150 }
1151
1152 } else {
1153 /* Two distinct TSes are being admitted, so the driver needs to add both allocated medium time
1154 * The UP must be set to the same value of the first mlme-set-traffic-parameters.request so that
1155 * the FW replaces the current medium time with the new medium time.
1156 */
1157 SLSI_DBG1(sdev, SLSI_MLME, "CAC: Modify TSPEC for different TID\n");
1158 entry = tspec_list;
1159 while (entry != NULL) {
1160 if ((entry->accepted) && ((entry->tspec.ts_info[1] >> 3 & 0x07) == prev_priority)) { /*initial TS entry for same priority*/
1161 medium_time += entry->tspec.medium_time;
1162 priority = prev_priority;
1163 break;
1164 }
1165 entry = entry->next;
1166 }
1167 if (entry == NULL) {
1168 SLSI_ERR(sdev, "CAC: Failed to find entry for prev established TSPEC!!\n");
1169 return;
1170 }
1171 }
1172
1173set_params:
1174 SLSI_DBG1(sdev, SLSI_MLME, "sending traffic params tid [%d]", itr->id);
1175 if (slsi_mlme_set_traffic_parameters(sdev, netdev, priority, medium_time, tspec->minimum_data_rate, ndev_vif->sta.sta_bss->bssid) != 0) {
1176 SLSI_ERR(sdev, "CAC: Failed to send SET_TRAFFIC_PARAMETERS request\n");
1177 return;
1178 }
1179
1180 /*update the TSPEC with medium_time allocated by AP*/
1181 itr->tspec.medium_time = medium_time;
1182
1183 /* BlockAck Control Req was previously used to enable blockack for VO & VI. This
1184 * signal is removed and expected to be replaced with MIBs - not able to see
1185 * through the haze yet!. Need to take approp. action when the cloud clears.
1186 * Historical Data:
1187 * Currently the firmware autonomously negotiates BlockAck agreement for AC_BE.
1188 * It is required for WMM-AC certification to use BlockAck for AC_VI.
1189 * So if a TSPEC for AC_VI (UP = 5 0r 4) is successfully negotiated, the host
1190 * generates an MLME-BLOCKACK-CONTROL.request, identifying that a BlockAck for the
1191 * corresponding Priority (direction set to Any) should be enabled, i.e. the F/W
1192 * will accept a downlink requested BlockAck Request, and will try to set-up an
1193 * uplink BlockAck Request for that priority (TID).
1194 * Bits for AC_BE should always be set
1195 * For WMM-AC certification, if the EDCA parameters for both VO and VI are same
1196 * during association and both are ACM = 1, then don't use BlockAck for AC_VI.
1197 */
1198
1199 /* Add store in MIB the msdu_lifetime value in case of ccx enabled bss */
1200 if (ccx_status == BSS_CCX_ENABLED) {
1201 if ((slsi_read_max_transmit_msdu_lifetime(sdev, netdev, &previous_msdu_lifetime)) != 0) {
1202 previous_msdu_lifetime = MAX_TRANSMIT_MSDU_LIFETIME_NOT_VALID;
1203 SLSI_ERR(sdev, "CAC: slsi_read_max_msdu_lifetime failed");
1204 return;
1205 }
1206
1207 if (slsi_send_max_transmit_msdu_lifetime(sdev, netdev, msdu_lifetime) != 0) {
1208 SLSI_ERR(sdev, "CAC: slsi_send_max_msdu_lifetime failed");
1209 return;
1210 }
1211 }
1212
1213 itr->accepted = 1; /* add_tspec accepted by AP*/
1214 sdev->tspec_error_code = 0; /* add_tspec response received */
1215 peer->tspec_established |= BIT(priority);
1216 /* update RIC in add_info_elements for assoc req */
1217 cac_set_ric_ie(sdev, netdev);
1218}
1219
1220/* Name: cac_rx_wmm_action
1221 * Desc: Get the action frame received and call the corresponding process routine
1222 * sdev: pointer to the slsi_dev struct
1223 * data: buffer to the action frame received
1224 * len: the length in bytes of the action frame
1225 */
1226void cac_rx_wmm_action(struct slsi_dev *sdev, struct net_device *netdev, struct ieee80211_mgmt *data, size_t len)
1227{
1228 struct ieee80211_mgmt *mgmt = data;
1229 struct action_addts_rsp *addts;
1230
1231 if ((sdev == NULL) || (data == NULL) || (netdev == NULL) || (len == 0))
1232 return;
1233
1234 if (mgmt->u.action.u.wme_action.action_code == WMM_ACTION_CODE_ADDTS_RESP) {
1235 addts = (struct action_addts_rsp *)&mgmt->u.action;
1236 cac_process_addts_rsp(sdev, netdev, addts, mgmt->u.action.u.wme_action.variable, len - sizeof(*addts) + 1);
1237 } else if (mgmt->u.action.u.wme_action.action_code == WMM_ACTION_CODE_DELTS) {
1238 cac_process_delts_req(sdev, netdev, (struct action_delts_req *)&mgmt->u.action);
1239 }
1240}
1241
1242/* Name: cac_get_active_tspecs
1243 * Desc:
1244 * tspecs: the list of active tspecs
1245 * return: 0 (succes), -1 (failure)
1246 */
1247int cac_get_active_tspecs(struct cac_activated_tspec **tspecs)
1248{
1249 struct cac_tspec *itr = tspec_list;
1250 int count = 0;
1251 int i = 0;
1252
1253 if (tspecs == NULL)
1254 return -1;
1255
1256 while (itr != NULL) {
1257 if (itr->accepted)
1258 count++;
1259 itr = itr->next;
1260 }
1261 *tspecs = kmalloc_array((size_t)count, sizeof(struct cac_activated_tspec), GFP_KERNEL);
1262 itr = tspec_list;
1263 while (itr != NULL) {
1264 if (itr->accepted) {
1265 tspecs[i]->ebw = itr->ebw;
1266 memcpy(&tspecs[i]->tspec, &itr->tspec, sizeof(itr->tspec));
1267 i++;
1268 }
1269 itr = itr->next;
1270 }
1271
1272 return count;
1273}
1274
1275/*********************************************************
1276 * call cac_delete_tspec_list to delete all tspecs
1277 * when the device is disconnecting
1278 */
1279/* Name: cac_delete_tspec_list
1280 * Desc:
1281 * sdev: pointer to the slsi_dev struct
1282 * return: None
1283 */
1284void cac_delete_tspec_list(struct slsi_dev *sdev)
1285{
1286 struct cac_tspec *itr = tspec_list;
1287 struct cac_tspec *temp = NULL;
1288
1289 SLSI_UNUSED_PARAMETER(sdev);
1290
1291 while (itr != NULL) {
1292 itr->accepted = 0;
1293 itr->dialog_token = 0;
1294 temp = itr;
1295 itr = itr->next;
1296 kfree(temp);
1297 }
1298 tspec_list = NULL;
1299}
1300
1301void cac_deactivate_tspecs(struct slsi_dev *sdev)
1302{
1303 struct cac_tspec *itr = tspec_list;
1304
1305 SLSI_UNUSED_PARAMETER(sdev);
1306
1307 while (itr) {
1308 itr->accepted = 0;
1309 itr->dialog_token = 0;
1310 itr = itr->next;
1311 }
1312}
1313
1314static void cac_set_ric_ie(struct slsi_dev *sdev, struct net_device *netdev)
1315{
1316 struct cac_tspec *itr = tspec_list;
1317 int tspec_count = 0;
1318 int buf_len = 0;
1319 u8 *buff, *add_info_ies;
1320 struct wmm_tspec_element *tspec_ie;
1321 int i = 0;
1322 struct netdev_vif *ndev_vif = netdev_priv(netdev);
1323
1324 while (itr) {
1325 if (itr->accepted)
1326 tspec_count++;
1327 itr = itr->next;
1328 }
1329
1330 if (tspec_count == 0) {
1331 slsi_mlme_add_info_elements(sdev, netdev, FAPI_PURPOSE_ASSOCIATION_REQUEST,
1332 ndev_vif->sta.assoc_req_add_info_elem,
1333 ndev_vif->sta.assoc_req_add_info_elem_len);
1334 return;
1335 }
1336
1337 /* RDE (6 bytes), WMM TSPEC * tspec_count bytes*/
1338 buf_len = 6 + (sizeof(struct wmm_tspec_element) * tspec_count);
1339 buf_len += ndev_vif->sta.assoc_req_add_info_elem_len;
1340 add_info_ies = kmalloc(buf_len, GFP_KERNEL);
1341 if (!add_info_ies) {
1342 SLSI_ERR(sdev, "malloc fail. size:%d\n", buf_len);
1343 return;
1344 }
1345 memcpy(add_info_ies, ndev_vif->sta.assoc_req_add_info_elem, ndev_vif->sta.assoc_req_add_info_elem_len);
1346
1347 buff = add_info_ies + ndev_vif->sta.assoc_req_add_info_elem_len;
1348 buff[0] = WLAN_EID_RIC_DATA;
1349 buff[1] = 4;
1350 buff[2] = 0; /* random identifier */
1351 /* buff[3]: resource desc count update after filling TSPEC */
1352 buff[4] = 0; /* buff[4]-buff[5] status code. set to success */
1353 buff[5] = 0;
1354
1355 itr = tspec_list;
1356 i = 0;
1357 while (itr) {
1358 if (itr->accepted) {
1359 tspec_ie = (struct wmm_tspec_element *)&buff[6 + i * sizeof(struct wmm_tspec_element)];
1360 memcpy(tspec_ie, &itr->tspec, sizeof(struct wmm_tspec_element));
1361 ((struct wmm_tspec_element *)tspec_ie)->medium_time = 0;
1362 i++;
1363 }
1364 itr = itr->next;
1365 }
1366 buff[3] = i;
1367 slsi_mlme_add_info_elements(sdev, netdev, FAPI_PURPOSE_ASSOCIATION_REQUEST, add_info_ies, buf_len);
1368 kfree(add_info_ies);
1369}
1370
1371static int cac_get_rde_tspec_ie(struct slsi_dev *sdev, u8 *assoc_rsp_ie, int assoc_rsp_ie_len, const u8 **tspec_ie_arr)
1372{
1373 const u8 *ie;
1374 u16 status;
1375 int tspec_count = 0, i = 0;
1376
1377 ie = assoc_rsp_ie;
1378
1379 /* Find total number of RDE TSPEC */
1380 while (ie && (assoc_rsp_ie_len > ie - assoc_rsp_ie)) {
1381 ie = cfg80211_find_ie(WLAN_EID_RIC_DATA, ie, assoc_rsp_ie_len - (ie - assoc_rsp_ie));
1382 if (!ie)
1383 break;
1384 status = CAC_GET_LE16(&ie[4]);
1385 if (status != 0)
1386 continue;
1387
1388 tspec_count += ie[3]; /* TSPEC descriptor count */
1389 ie = ie + ie[1];
1390 }
1391
1392 /* limit WMM TSPEC count to TSID_MAX */
1393 if (tspec_count > TSID_MAX) {
1394 SLSI_DBG1(sdev, SLSI_MLME, "received %d TSPEC but can accommodate only %d\n", tspec_count, TSID_MAX);
1395 tspec_count = TSID_MAX;
1396 }
1397
1398 /* Get all WMM TSPEC IE pointers */
1399 ie = cfg80211_find_ie(WLAN_EID_RIC_DATA, assoc_rsp_ie, assoc_rsp_ie_len);
1400 while (i < tspec_count && ie) {
1401 ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, WLAN_OUI_TYPE_MICROSOFT_WMM, ie,
1402 assoc_rsp_ie_len - (ie - assoc_rsp_ie));
1403 if (!ie)
1404 break;
1405 /* re-assoc-res can contain wmm parameter IE and wmm TSPEC IE.
1406 * we want wmm TSPEC Element)
1407 */
1408 if (ie[1] > 6 && ie[6] == WMM_OUI_SUBTYPE_TSPEC_ELEMENT) {
1409 tspec_ie_arr[i] = ie;
1410 i++;
1411 }
1412 ie += ie[1];
1413 }
1414
1415 return i;
1416}
1417
1418void cac_update_roam_traffic_params(struct slsi_dev *sdev, struct net_device *dev)
1419{
1420 const u8 *tspec_ie_arr[TSID_MAX];
1421 int assoc_rsp_tspec_count, i;
1422 u32 priority;
1423 struct cac_tspec *itr;
1424 struct wmm_tspec_element *assoc_rsp_tspec;
1425 struct slsi_peer *peer = slsi_get_peer_from_qs(sdev, dev, SLSI_STA_PEER_QUEUESET);
1426 struct netdev_vif *ndev_vif = netdev_priv(dev);
1427
1428 SLSI_DBG3(sdev, SLSI_MLME, "\n");
1429
1430 /* Roamed to new AP. TSPEC admitted to previous AP are no more valid.
1431 * Set all TSPEC to not admitted
1432 */
1433 cac_deactivate_tspecs(sdev);
1434
1435 if (!peer) {
1436 SLSI_ERR(sdev, "AP peer entry not found\n");
1437 return;
1438 }
1439
1440 /* Find all the admitted TSPECs in assoc resp. */
1441 assoc_rsp_tspec_count = cac_get_rde_tspec_ie(sdev, peer->assoc_resp_ie->data,
1442 peer->assoc_resp_ie->len, tspec_ie_arr);
1443
1444 SLSI_DBG3(sdev, SLSI_MLME, "assoc_rsp_tspec_count:%d\n", assoc_rsp_tspec_count);
1445
1446 if (!assoc_rsp_tspec_count)
1447 return;
1448
1449 /* update the admitted TSPECs from assoc resp and set traffic params in FW.*/
1450 for (i = 0; i < assoc_rsp_tspec_count; i++) {
1451 assoc_rsp_tspec = (struct wmm_tspec_element *)tspec_ie_arr[i];
1452 SLSI_DBG3(sdev, SLSI_MLME, "rsp_tspec:[%d] ts: [%x|%x|%x] medium time[%x]\n", i,
1453 assoc_rsp_tspec->ts_info[0], assoc_rsp_tspec->ts_info[1], assoc_rsp_tspec->ts_info[2],
1454 assoc_rsp_tspec->medium_time);
1455
1456 itr = find_tspec_entry((assoc_rsp_tspec->ts_info[0] & 0x1E) >> 1, 0);
1457 if (!itr) {
1458 SLSI_DBG3(sdev, SLSI_MLME, "tspec entry not found\n");
1459 continue;
1460 }
1461
1462 itr->tspec.medium_time = assoc_rsp_tspec->medium_time;
1463 itr->tspec.minimum_data_rate = assoc_rsp_tspec->minimum_data_rate;
1464 itr->accepted = 1;
1465 cac_query_tspec_field(sdev, itr, "user_priority", &priority);
1466 peer->tspec_established |= BIT(priority);
1467 SLSI_DBG3(sdev, SLSI_MLME, "tspec admitted id[%d]\n", itr->id);
1468 slsi_mlme_set_traffic_parameters(sdev, dev, priority, assoc_rsp_tspec->medium_time,
1469 assoc_rsp_tspec->minimum_data_rate, ndev_vif->sta.sta_bss->bssid);
1470 }
1471}
1472