1 /****************************************************************************
3 * Copyright (c) 2012 - 2017 Samsung Electronics Co., Ltd. All rights reserved
5 ****************************************************************************/
9 static struct cac_tspec
*tspec_list
;
10 static int tspec_list_next_id
;
11 static u8 dialog_token_next
;
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
) },
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 };
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
;
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
);
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)
58 static int strtoint(const char *s
, int *res
)
63 if (s
[0] == '0' && (s
[1] == 'x' || s
[1] == 'X'))
65 return kstrtoint(s
, base
, res
);
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)
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
75 static struct cac_tspec
*find_tspec_entry(int id
, int accepted
)
77 struct cac_tspec
*itr
;
81 if ((itr
->id
== id
) && (itr
->accepted
== accepted
))
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)
96 static int cac_query_tspec_field(struct slsi_dev
*sdev
, struct cac_tspec
*entry
, const char *field
, u32
*value
)
103 if ((entry
== NULL
) || (field
== NULL
) || (value
== NULL
))
106 for (i
= 0; i
< NUM_TSPEC_FIELDS
; i
++)
107 if (strcasecmp(field
, tspec_fields
[i
].name
) == 0)
109 if (i
>= NUM_TSPEC_FIELDS
) {
110 SLSI_ERR(sdev
, "CAC: Invalid TSPEC config field\n");
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
;
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
);
124 *value
= CAC_GET_LE32(pos
);
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
135 static struct net_device
*get_netdev_for_station(struct slsi_dev
*sdev
)
137 struct net_device
*dev
;
138 struct netdev_vif
*ndev_vif
;
141 for (vif
= 1; vif
<= CONFIG_SCSC_WLAN_MAX_INTERFACES
; vif
++) {
142 dev
= slsi_get_netdev_locked(sdev
, vif
);
145 ndev_vif
= netdev_priv(dev
);
148 if (ndev_vif
->vif_type
== FAPI_VIFTYPE_STATION
&&
149 ndev_vif
->iftype
== NL80211_IFTYPE_STATION
)
157 * buf: pointer to buf that the ie is going to added
158 * buf_len: the byte length of the ie
160 * return: length of bytes that were added
162 static int add_ebw_ie(u8
*buf
, size_t buf_len
, u8 tsid
)
166 if ((buf
== NULL
) || (buf_len
< 8))
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
);
182 * buf: pointer to buf that the ie is going to added
183 * buf_len: the byte length of the ie
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
189 static int add_tsrs_ie(u8
*buf
, size_t buf_len
, u8 tsid
,
190 u8 rates
[CCX_MAX_NUM_RATES
], int num_rates
)
193 size_t ie_len
= (size_t)(7 + num_rates
);
196 if ((buf
== NULL
) || (buf_len
< ie_len
) || (rates
== NULL
) ||
197 (num_rates
> CCX_MAX_NUM_RATES
))
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
);
207 for (i
= 0; i
< num_rates
; i
++)
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
219 static const u8
*bss_get_ie(struct cfg80211_bss
*bss
, u8 ie
)
222 u8 ies_len
, ies_cur_len
;
224 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
225 pos
= (const u8
*)(bss
->ies
);
226 ies_len
= (u8
)bss
->ies
->len
;
228 pos
= (const u8
*)(bss
->information_elements
);
229 ies_len
= (u8
)bss
->len_information_elements
;
233 while (ies_cur_len
<= ies_len
) {
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)
250 static int bss_get_bit_rates(struct cfg80211_bss
*bss
, u8
**rates
)
257 ie
= bss_get_ie(bss
, WLAN_EID_SUPP_RATES
);
258 ie2
= bss_get_ie(bss
, WLAN_EID_EXT_SUPP_RATES
);
260 len
= (ie
? ie
[1] : 0) + (ie2
? ie2
[1] : 0);
265 r
= kmalloc(len
, GFP_KERNEL
);
269 for (i
= 0; ie
&& i
< ie
[1]; i
++)
270 r
[i
] = ie
[i
+ 2] & 0x7f;
272 for (j
= 0; ie2
&& j
< ie2
[1]; j
++)
273 r
[i
+ j
] = ie2
[j
+ 2] & 0x7f;
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)
286 static int cac_send_addts(struct slsi_dev
*sdev
, int id
, int ebw
)
288 struct action_addts_req
*req
;
289 size_t extra_ie_len
= 50;
292 struct cac_tspec
*entry
;
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
;
306 entry
= find_tspec_entry(id
, 0);
308 SLSI_ERR(sdev
, "CAC-ADDTS: Invalid TSPEC ID\n");
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
);
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
);
323 SLSI_MUTEX_LOCK(ndev_vif
->vif_mutex
);
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");
331 bssid
= ndev_vif
->sta
.sta_bss
->bssid
;
332 if (entry
->accepted
) {
333 SLSI_ERR(sdev
, "CAC-ADDTS: TSPEC already accepted\n");
338 buf
= kmalloc(IEEE80211_HEADER_SIZE
+ sizeof(*req
) + extra_ie_len
, GFP_KERNEL
);
340 SLSI_ERR(sdev
, "CAC-ADDTS: Failed to allocate ADDTS request\n");
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
);
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)
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;
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
363 if (entry
->psb_specified
== 0) {
364 struct slsi_peer
*peer
;
367 peer
= slsi_get_peer_from_qs(sdev
, netdev
, SLSI_STA_PEER_QUEUESET
);
369 SLSI_ERR(sdev
, "CAC-ADDTS: no Peer found\n");
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;
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;
384 ie_len
+= add_ebw_ie(pos
, extra_ie_len
, tsid
);
386 SLSI_ERR(sdev
, "CAC-ADDTS: Failed to add EBW IE\n");
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
);
393 rate
= 12; /* Default to 6Mbps */
395 for (i
= 0; i
< num_rates
; i
++)
396 if ((rates
[i
] > rate
) && (rates
[i
] <= 48))
402 /* if the nominal rate is equal to minimum_phy_rate
403 * don't add the tsrs_ie
405 if ((rate
* TSRS_RATE_PER_UNIT
) == req
->tspec
.minimum_phy_rate
)
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
,
412 SLSI_ERR(sdev
, "CAC-ADDTS: Failed to add TSRS IE\n");
416 } else { /* only the "<" case is possible */
417 SLSI_ERR(sdev
, "CAC-ADDTS: BSS rate too low\n");
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");
431 entry
->dialog_token
= req
->hdr
.dialog_token
;
436 SLSI_MUTEX_UNLOCK(ndev_vif
->vif_mutex
);
437 SLSI_MUTEX_UNLOCK(sdev
->netdev_add_remove_mutex
);
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)
447 static int cac_send_delts(struct slsi_dev
*sdev
, int id
)
449 struct action_delts_req
*req
;
450 struct cac_tspec
*entry
;
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
;
461 struct slsi_peer
*stapeer
;
463 entry
= find_tspec_entry(id
, 1);
465 SLSI_ERR(sdev
, "CAC-DELTS: no TSPEC has been established for tsid=%d\n", id
);
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
);
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
);
480 SLSI_MUTEX_LOCK(ndev_vif
->vif_mutex
);
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");
489 stapeer
= slsi_get_peer_from_qs(sdev
, netdev
, SLSI_STA_PEER_QUEUESET
);
490 if (WARN_ON(!stapeer
)) {
495 bssid
= ndev_vif
->sta
.sta_bss
->bssid
;
496 buf
= kmalloc(24 + sizeof(*req
), GFP_KERNEL
);
498 SLSI_ERR(sdev
, "CAC-DELTS: Failed to allocate DELTS request\n");
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
));
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 .
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");
523 rc
= cac_query_tspec_field(sdev
, entry
, "user_priority", &priority
);
525 SLSI_ERR(sdev
, "CAC-DELTS: Error in reading priority from tspec!\n");
530 if (slsi_mlme_del_traffic_parameters(sdev
, netdev
, priority
) != 0) {
531 SLSI_ERR(sdev
, "CAC-DELTS: Failed to send DELTS request\n");
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.
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
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
);
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");
559 SLSI_MUTEX_UNLOCK(ndev_vif
->vif_mutex
);
560 SLSI_MUTEX_UNLOCK(sdev
->netdev_add_remove_mutex
);
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)
570 static int cac_create_tspec(struct slsi_dev
*sdev
, char *args
)
572 struct cac_tspec
*entry
;
574 u8 tid_auto_done
= 0;
575 struct netdev_vif
*ndev_vif
;
576 struct net_device
*netdev
;
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
);
584 ndev_vif
= netdev_priv(netdev
);
585 if (ndev_vif
== NULL
) {
586 SLSI_MUTEX_UNLOCK(sdev
->netdev_add_remove_mutex
);
589 SLSI_MUTEX_LOCK(ndev_vif
->vif_mutex
);
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
);
598 SLSI_MUTEX_UNLOCK(ndev_vif
->vif_mutex
);
599 SLSI_MUTEX_UNLOCK(sdev
->netdev_add_remove_mutex
);
602 /* No input for tid, so we use the auto increment*/
603 if (tspec_list_next_id
<= 7) {
604 id
= tspec_list_next_id
++;
607 tspec_list_next_id
= 0;
608 tspec_list_next_id
++;
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
++;
619 tspec_list_next_id
= 0;
620 tspec_list_next_id
++;
624 if (id
< TSID_MIN
|| id
> TSID_MAX
) {
625 SLSI_ERR(sdev
, "CAC: Invalid TSID =%d, must be in range 0-7\n", id
);
629 entry
= kzalloc(sizeof(*entry
), GFP_KERNEL
);
631 SLSI_ERR(sdev
, "CAC: Failed to allocate TSPEC\n");
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
;
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;
647 entry
->next
= tspec_list
;
649 SLSI_DBG1(sdev
, SLSI_MLME
, "CAC: Created TSPEC entry for id =%d\n", id
);
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)
660 static int cac_delete_tspec(struct slsi_dev
*sdev
, int id
)
662 struct cac_tspec
*itr
;
663 struct cac_tspec
*prev
;
667 while (itr
!= NULL
) {
670 prev
->next
= itr
->next
;
672 tspec_list
= itr
->next
;
675 cac_send_delts(sdev
, itr
->id
);
677 SLSI_DBG3(sdev
, SLSI_MLME
, "CAC: TSPEC entry deleted for id =%d\n", id
);
685 SLSI_ERR(sdev
, "CAC: Couldn't find TSPEC with id %d for deletion", id
);
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)
697 static int cac_delete_tspec_by_state(struct slsi_dev
*sdev
, int id
, int accepted
)
699 struct cac_tspec
*itr
;
700 struct cac_tspec
*prev
;
704 while (itr
!= NULL
) {
705 if ((itr
->id
== id
) && (itr
->accepted
== accepted
)) {
707 prev
->next
= itr
->next
;
709 tspec_list
= itr
->next
;
711 SLSI_DBG3(sdev
, SLSI_MLME
, "CAC: Deleting TSPEC 0x%p with ID %d (accepted =%d)\n", itr
, id
, accepted
);
718 SLSI_ERR(sdev
, "CAC: Couldn't find TSPEC with ID %d (accepted =%d)\n", id
, accepted
);
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)
731 static int cac_config_tspec(struct slsi_dev
*sdev
, int id
, const char *field
, u32 value
)
733 struct cac_tspec
*entry
;
735 u32 max
= 0xFFFFFFFF;
743 entry
= find_tspec_entry(id
, 0);
745 SLSI_ERR(sdev
, "CAC: Invalid TSPEC ID\n");
749 for (i
= 0; i
< NUM_TSPEC_FIELDS
; i
++)
750 if (strcasecmp(field
, tspec_fields
[i
].name
) == 0)
752 if (i
>= NUM_TSPEC_FIELDS
) {
753 SLSI_ERR(sdev
, "CAC: Invalid TSPEC config field\n");
756 if (tspec_fields
[i
].read_only
) {
757 SLSI_ERR(sdev
, "CAC: TSPEC field is read-only\n");
760 if (tspec_fields
[i
].is_tsinfo_field
) {
761 mask
= tspec_fields
[i
].size
;
762 if (strcasecmp(field
, "psb") == 0) {
764 entry
->psb_specified
= 1;
769 SLSI_ERR(sdev
, "CAC: TSPEC config value exceeded maximum for %s\n", tspec_fields
[i
].name
);
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
);
778 if (tspec_fields
[i
].size
< 4)
779 max
= ((1 << (tspec_fields
[i
].size
* 8)) - 1);
782 SLSI_ERR(sdev
, "CAC: TSPEC config value exceeded maximumfor %s\n", tspec_fields
[i
].name
);
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
);
792 CAC_PUT_LE32(pos
, value
);
798 /* Name: cac_ctrl_create_tspec
799 * Desc: public function to create tspec
800 * sdev: pointer to the slsi_dev struct
803 int cac_ctrl_create_tspec(struct slsi_dev
*sdev
, char *args
)
807 id
= cac_create_tspec(sdev
, args
);
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)
820 int cac_ctrl_delete_tspec(struct slsi_dev
*sdev
, char *args
)
824 if (strtoint(args
, &id
) < 0) {
825 SLSI_ERR(sdev
, "CAC-DELETE-TSPEC: Invalid TSPEC ID\n");
829 if (cac_delete_tspec(sdev
, id
) < 0)
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)
841 int cac_ctrl_config_tspec(struct slsi_dev
*sdev
, char *args
)
850 field
= strchr(id
, ' ');
852 SLSI_ERR(sdev
, "CAC: field string is NULL\n");
856 value
= strchr(field
, ' ');
858 SLSI_ERR(sdev
, "CAC: field value is NULL\n");
863 if (strtoint(id
, &tspec_id
) < 0) {
864 SLSI_ERR(sdev
, "CAC: Conversion error for tspecid\n");
868 if (strtoint(value
, &val
) < 0) {
869 SLSI_ERR(sdev
, "CAC: Conversion error for tspecid value\n");
873 if (cac_config_tspec(sdev
, tspec_id
, field
, val
) < 0)
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)
885 int cac_ctrl_send_addts(struct slsi_dev
*sdev
, char *args
)
896 ebw_str
= strchr(id_str
, ' ');
897 if (ebw_str
!= NULL
) {
899 if (!strncmp(ebw_str
, "ebw", 3))
902 if (strtoint(id_str
, &id
) < 0) {
903 SLSI_ERR(sdev
, "CAC: Conversion error for tspecid value\n");
906 if (cac_send_addts(sdev
, id
, ebw
) < 0)
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)
918 int cac_ctrl_send_delts(struct slsi_dev
*sdev
, char *args
)
925 if (strtoint(args
, &id
) < 0) {
926 SLSI_ERR(sdev
, "CAC: Invalid TSPEC ID\n");
929 if (cac_send_delts(sdev
, id
) < 0)
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)
941 static void cac_process_delts_req(struct slsi_dev
*sdev
, struct net_device
*netdev
, struct action_delts_req
*req
)
943 struct netdev_vif
*ndev_vif
= netdev_priv(netdev
);
944 struct cac_tspec
*itr
;
947 struct slsi_peer
*stapeer
;
950 WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif
->vif_mutex
));
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");
958 stapeer
= slsi_get_peer_from_qs(sdev
, netdev
, SLSI_STA_PEER_QUEUESET
);
959 if (WARN_ON(!stapeer
))
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
);
965 itr
= find_tspec_entry(tid
, 1);
967 SLSI_ERR(sdev
, "CAC: No matching TSPEC found\n");
971 rc
= cac_query_tspec_field(sdev
, itr
, "user_priority", &priority
);
973 SLSI_ERR(sdev
, "CAC: Missing priority from TSPEC!\n");
977 if (slsi_mlme_del_traffic_parameters(sdev
, netdev
, priority
) != 0) {
978 SLSI_ERR(sdev
, "CAC: Failed to send DEL-TRAFFIC_PARAMETERS request\n");
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.
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
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
);
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");
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)
1012 static int cac_find_edca_ie(const u8
*ie
, size_t ie_len
, u8
*tsid
, u16
*lifetime
)
1016 if ((ie
== NULL
) || (ie_len
< 9) ||
1017 (tsid
== NULL
) || (lifetime
== NULL
))
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
)) {
1023 *lifetime
= CAC_GET_LE16(&pos
[7]);
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)
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
)
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
;
1046 struct slsi_peer
*peer
;
1049 WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif
->vif_mutex
));
1051 SLSI_DBG1(sdev
, SLSI_MLME
, "\n");
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");
1059 peer
= slsi_get_peer_from_qs(sdev
, netdev
, SLSI_STA_PEER_QUEUESET
);
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*/
1072 SLSI_ERR(sdev
, "CAC: No matching TSPEC found for ADDTS response\n");
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);
1082 if ((ccx_status
== BSS_CCX_ENABLED
) && cac_find_edca_ie(ie
, ie_len
, &tsid
, &msdu_lifetime
) != 0)
1083 msdu_lifetime
= MSDU_LIFETIME_DEFAULT
;
1085 tspec
= (struct wmm_tspec_element
*)(rsp
+ 1);
1086 medium_time
= tspec
->medium_time
;
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
);
1091 if (peer
->tspec_established
== 0)
1094 SLSI_DBG1(sdev
, SLSI_MLME
, "TSPEC already established\n");
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)
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
;
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
;
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
;
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
;
1146 SLSI_ERR(sdev
, "CAC: Invalid UP in the request\n");
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.
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
;
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.
1172 SLSI_DBG1(sdev
, SLSI_MLME
, "CAC: Modify TSPEC for different TID\n");
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
;
1180 entry
= entry
->next
;
1182 if (entry
== NULL
) {
1183 SLSI_ERR(sdev
, "CAC: Failed to find entry for prev established TSPEC!!\n");
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");
1195 /*update the TSPEC with medium_time allocated by AP*/
1196 itr
->tspec
.medium_time
= medium_time
;
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.
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.
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");
1222 if (slsi_send_max_transmit_msdu_lifetime(sdev
, netdev
, msdu_lifetime
) != 0) {
1223 SLSI_ERR(sdev
, "CAC: slsi_send_max_msdu_lifetime failed");
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
);
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
1241 void cac_rx_wmm_action(struct slsi_dev
*sdev
, struct net_device
*netdev
, struct ieee80211_mgmt
*data
, size_t len
)
1243 struct ieee80211_mgmt
*mgmt
= data
;
1244 struct action_addts_rsp
*addts
;
1246 if ((sdev
== NULL
) || (data
== NULL
) || (netdev
== NULL
) || (len
== 0))
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
);
1257 /* Name: cac_get_active_tspecs
1259 * tspecs: the list of active tspecs
1260 * return: 0 (succes), -1 (failure)
1262 int cac_get_active_tspecs(struct cac_activated_tspec
**tspecs
)
1264 struct cac_tspec
*itr
= tspec_list
;
1271 while (itr
!= NULL
) {
1276 *tspecs
= kmalloc_array((size_t)count
, sizeof(struct cac_activated_tspec
), GFP_KERNEL
);
1278 while (itr
!= NULL
) {
1279 if (itr
->accepted
) {
1280 tspecs
[i
]->ebw
= itr
->ebw
;
1281 memcpy(&tspecs
[i
]->tspec
, &itr
->tspec
, sizeof(itr
->tspec
));
1290 /*********************************************************
1291 * call cac_delete_tspec_list to delete all tspecs
1292 * when the device is disconnecting
1294 /* Name: cac_delete_tspec_list
1296 * sdev: pointer to the slsi_dev struct
1299 void cac_delete_tspec_list(struct slsi_dev
*sdev
)
1301 struct cac_tspec
*itr
= tspec_list
;
1302 struct cac_tspec
*temp
= NULL
;
1304 SLSI_UNUSED_PARAMETER(sdev
);
1306 while (itr
!= NULL
) {
1308 itr
->dialog_token
= 0;
1316 void cac_deactivate_tspecs(struct slsi_dev
*sdev
)
1318 struct cac_tspec
*itr
= tspec_list
;
1320 SLSI_UNUSED_PARAMETER(sdev
);
1324 itr
->dialog_token
= 0;
1329 static void cac_set_ric_ie(struct slsi_dev
*sdev
, struct net_device
*netdev
)
1331 struct cac_tspec
*itr
= tspec_list
;
1332 int tspec_count
= 0;
1334 u8
*buff
, *add_info_ies
;
1335 struct wmm_tspec_element
*tspec_ie
;
1337 struct netdev_vif
*ndev_vif
= netdev_priv(netdev
);
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
);
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
);
1360 memcpy(add_info_ies
, ndev_vif
->sta
.assoc_req_add_info_elem
, ndev_vif
->sta
.assoc_req_add_info_elem_len
);
1362 buff
= add_info_ies
+ ndev_vif
->sta
.assoc_req_add_info_elem_len
;
1363 buff
[0] = WLAN_EID_RIC_DATA
;
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 */
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;
1382 slsi_mlme_add_info_elements(sdev
, netdev
, FAPI_PURPOSE_ASSOCIATION_REQUEST
, add_info_ies
, buf_len
);
1383 kfree(add_info_ies
);
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
)
1390 int tspec_count
= 0, i
= 0;
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
));
1399 status
= CAC_GET_LE16(&ie
[4]);
1403 tspec_count
+= ie
[3]; /* TSPEC descriptor count */
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
;
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
));
1420 /* re-assoc-res can contain wmm parameter IE and wmm TSPEC IE.
1421 * we want wmm TSPEC Element)
1423 if (ie
[1] > 6 && ie
[6] == WMM_OUI_SUBTYPE_TSPEC_ELEMENT
) {
1424 tspec_ie_arr
[i
] = ie
;
1433 void cac_update_roam_traffic_params(struct slsi_dev
*sdev
, struct net_device
*dev
)
1435 const u8
*tspec_ie_arr
[TSID_MAX
];
1436 int assoc_rsp_tspec_count
, i
;
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
);
1443 SLSI_DBG3(sdev
, SLSI_MLME
, "\n");
1445 /* Roamed to new AP. TSPEC admitted to previous AP are no more valid.
1446 * Set all TSPEC to not admitted
1448 cac_deactivate_tspecs(sdev
);
1451 SLSI_ERR(sdev
, "AP peer entry not found\n");
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
);
1459 SLSI_DBG3(sdev
, SLSI_MLME
, "assoc_rsp_tspec_count:%d\n", assoc_rsp_tspec_count
);
1461 if (!assoc_rsp_tspec_count
)
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
);
1471 itr
= find_tspec_entry((assoc_rsp_tspec
->ts_info
[0] & 0x1E) >> 1, 0);
1473 SLSI_DBG3(sdev
, SLSI_MLME
, "tspec entry not found\n");
1477 itr
->tspec
.medium_time
= assoc_rsp_tspec
->medium_time
;
1478 itr
->tspec
.minimum_data_rate
= assoc_rsp_tspec
->minimum_data_rate
;
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
);