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