1 /*
2 * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 * 文 件 名 : hmac_tx_amsdu.c
15 * 生成日期 : 2012年11月12日
16 * 功能描述 : amsdu聚合
17 */
18
19 /*****************************************************************************
20 1 头文件包含
21 *****************************************************************************/
22 #include "hmac_tx_amsdu.h"
23
24 #include "oam_struct.h"
25 #include "hmac_tx_data.h"
26 #include "hmac_feature_dft.h"
27 #include "hmac_tx_encap.h"
28 #include "hmac_ccpriv.h"
29 #ifdef __cplusplus
30 #if __cplusplus
31 extern "C" {
32 #endif
33 #endif
34
35 #undef THIS_FILE_ID
36 #define THIS_FILE_ID DIAG_FILE_ID_WIFI_HOST_HMAC_TX_AMSDU_C
37
38 #undef THIS_MOD_ID
39 #define THIS_MOD_ID DIAG_MOD_ID_WIFI_HOST
40
41 /*****************************************************************************
42 2 全局变量定义
43 *****************************************************************************/
44 mac_llc_snap_stru g_st_mac_11c_snap_header = {
45 SNAP_LLC_LSAP,
46 SNAP_LLC_LSAP,
47 LLC_UI,
48 {
49 SNAP_RFC1042_ORGCODE_0,
50 SNAP_RFC1042_ORGCODE_1,
51 SNAP_RFC1042_ORGCODE_2,
52 },
53 0
54 };
55
56 OAL_STATIC osal_u32 hmac_amsdu_tx_timeout_process(osal_void *p_arg);
57 OAL_STATIC OAL_INLINE oal_bool_enum_uint8 hmac_tx_amsdu_is_overflow(const hmac_amsdu_stru *amsdu,
58 osal_u32 frame_len);
59 OAL_STATIC osal_u32 hmac_amsdu_send(hmac_vap_stru *hmac_vap,
60 hmac_user_stru *hmac_user,
61 hmac_amsdu_stru *amsdu);
62
63 /*****************************************************************************
64 3 函数实现
65 *****************************************************************************/
66 /*****************************************************************************
67 函 数 名 : hmac_amsdu_prepare_to_send
68 功能描述 : 发送一个amsdu帧
69 *****************************************************************************/
hmac_amsdu_prepare_to_send(hmac_vap_stru * hmac_vap,hmac_user_stru * hmac_user,hmac_amsdu_stru * amsdu)70 WIFI_HMAC_TCM_TEXT OAL_STATIC osal_void hmac_amsdu_prepare_to_send(hmac_vap_stru *hmac_vap, hmac_user_stru *hmac_user,
71 hmac_amsdu_stru *amsdu)
72 {
73 osal_u32 ul_ret;
74
75 /* 删除定时器 */
76 frw_destroy_timer_entry(&amsdu->amsdu_timer);
77 ul_ret = hmac_amsdu_send(hmac_vap, hmac_user, amsdu);
78 if (osal_unlikely(ul_ret != OAL_SUCC)) {
79 oam_warning_log2(0, OAM_SF_AMSDU,
80 "{hmac_amsdu_prepare_to_send::, amsdu send fails. erro[%d], short_pkt_num=%d.}",
81 ul_ret, amsdu->msdu_num);
82 }
83 }
84
85 #if defined(_PRE_PRODUCT_ID_HOST)
86 /*****************************************************************************
87 函 数 名 : hmac_tx_amsdu_is_overflow
88 *****************************************************************************/
hmac_tx_amsdu_is_overflow(const hmac_amsdu_stru * amsdu,osal_u32 frame_len)89 WIFI_HMAC_TCM_TEXT OAL_STATIC OAL_INLINE oal_bool_enum_uint8 hmac_tx_amsdu_is_overflow(const hmac_amsdu_stru *amsdu,
90 osal_u32 frame_len)
91
92 {
93 /* payload + padmax(3) 不能大于1568 */
94 if (((amsdu->amsdu_size + frame_len + SNAP_LLC_FRAME_LEN + 3) > WLAN_LARGE_NETBUF_SIZE) ||
95 ((amsdu->amsdu_size + frame_len + SNAP_LLC_FRAME_LEN) > WLAN_AMSDU_FRAME_MAX_LEN)) {
96 oam_info_log3(1, OAM_SF_TX,
97 "{hmac_tx_amsdu_is_overflow::amsdu_size=%d framelen=%d msdu_num=%d .}",
98 amsdu->amsdu_size, frame_len, amsdu->msdu_num);
99 return OAL_TRUE;
100 }
101
102 return OAL_FALSE;
103 }
104
105 /*****************************************************************************
106 函 数 名 : hmac_amsdu_send
107 功能描述 : 发送amsdu, 发送失败则释放buf
108 输入参数 : user: 用户结构体指针
109 amsdu: 要发送的amsdu
110 返 回 值 : 成功OAL_SUCC;失败OAL_ERR_CODE_PTR_NULL
111 *****************************************************************************/
hmac_amsdu_send(hmac_vap_stru * hmac_vap,hmac_user_stru * hmac_user,hmac_amsdu_stru * amsdu)112 WIFI_HMAC_TCM_TEXT OAL_STATIC osal_u32 hmac_amsdu_send(hmac_vap_stru *hmac_vap,
113 hmac_user_stru *hmac_user, hmac_amsdu_stru *amsdu)
114 {
115 osal_u32 ret;
116 mac_tx_ctl_stru *cb;
117 oal_netbuf_stru *net_buf = oal_netbuf_delist(&(amsdu->msdu_head));
118 osal_u8 msdu_num;
119
120 /* 给dmac传送的amsdu相关的信息以及802.11头挂接 */
121 if (osal_unlikely(net_buf == OAL_PTR_NULL)) {
122 oam_error_log1(0, OAM_SF_AMPDU, "vap_id[%d] {hmac_amsdu_send::net_buf null}", hmac_vap->vap_id);
123 return OAL_ERR_CODE_PTR_NULL;
124 }
125
126 cb = (mac_tx_ctl_stru *)oal_netbuf_cb(net_buf);
127
128 /* amsdu只聚合一个帧时,回退成非amsdu,统一encap接口 */
129 if (amsdu->msdu_num == 1) {
130 osal_s32 mret;
131
132 mret = memmove_s(OAL_NETBUF_DATA(net_buf) + SNAP_LLC_FRAME_LEN, OAL_MAC_ADDR_LEN + OAL_MAC_ADDR_LEN,
133 OAL_NETBUF_DATA(net_buf), OAL_MAC_ADDR_LEN + OAL_MAC_ADDR_LEN);
134 if (mret != EOK) {
135 oal_netbuf_free(net_buf);
136 oam_error_log1(0, OAM_SF_AMPDU, "vap_id[%d] {hmac_amsdu_send::memmove_s fail}", hmac_vap->vap_id);
137 return OAL_ERR_CODE_PTR_NULL;
138 }
139
140 oal_netbuf_pull(net_buf, SNAP_LLC_FRAME_LEN);
141
142 mac_get_cb_is_amsdu(cb) = OAL_FALSE;
143 mac_get_cb_is_first_msdu(cb) = OAL_FALSE;
144 }
145
146 /* 把最后一个子帧的PAD去除 */
147 oal_netbuf_trim(net_buf, amsdu->last_pad_len);
148
149 mac_get_cb_mpdu_len(cb) = (osal_u16)OAL_NETBUF_LEN(net_buf);
150 mac_get_cb_mpdu_num(cb) = 1;
151 mac_get_cb_msdu_num(cb) = amsdu->msdu_num;
152
153 /* 清零amsdu结构体信息 */
154 msdu_num = amsdu->msdu_num;
155 amsdu->amsdu_size = 0;
156 amsdu->msdu_num = 0;
157
158 /* 为整个amsdu封装802.11头 */
159 ret = hmac_tx_encap_etc(hmac_vap, hmac_user, net_buf);
160 if (osal_unlikely(ret != OAL_SUCC)) {
161 hmac_dft_print_drop_frame_info(THIS_FILE_ID, __LINE__, msdu_num, OSAL_NULL);
162 oal_netbuf_free(net_buf);
163 OAM_STAT_VAP_INCR(hmac_vap->vap_id, tx_abnormal_msdu_dropped, 1);
164 oam_error_log2(0, OAM_SF_AMPDU, "vap_id[%d] {hmac_amsdu_send::tx_encap failed[%d]}", hmac_vap->vap_id, ret);
165 return OAL_ERR_CODE_PTR_NULL;
166 }
167
168 // 架构变化导致Host侧发包路径变长,原bh锁的范围过长影响性能,将发送报文至dmac.ko侧的处理移至锁外
169 osal_spin_unlock_bh(&amsdu->amsdu_lock);
170 ret = hmac_tx_send_encap_data(hmac_vap, net_buf);
171 if (osal_unlikely(ret != OAL_SUCC)) {
172 oal_netbuf_free(net_buf);
173 OAM_STAT_VAP_INCR(hmac_vap->vap_id, tx_abnormal_msdu_dropped, 1);
174 oam_warning_log2(0, OAM_SF_AMPDU, "vap_id[%d]hmac_amsdu_send::frw_send_data fail[%d]", hmac_vap->vap_id, ret);
175 }
176
177 osal_spin_lock_bh(&amsdu->amsdu_lock);
178
179 return ret;
180 }
181
182 /*****************************************************************************
183 函 数 名 : hmac_amsdu_tx_encap_mpdu
184 功能描述 : 多个msdu帧组建一个mpdu,进入此函数的msdu肯定能放入netbuf,否则overflow会溢出
185 *****************************************************************************/
hmac_amsdu_tx_encap_mpdu(hmac_vap_stru * hmac_vap,hmac_user_stru * hmac_user,hmac_amsdu_stru * amsdu,oal_netbuf_stru * buf)186 WIFI_HMAC_TCM_TEXT OAL_STATIC OAL_INLINE osal_u32 hmac_amsdu_tx_encap_mpdu(hmac_vap_stru *hmac_vap,
187 hmac_user_stru *hmac_user, hmac_amsdu_stru *amsdu, oal_netbuf_stru *buf)
188 {
189 osal_u32 msdu_len;
190 osal_u32 frame_len;
191 osal_u32 tailroom;
192 osal_u16 msdu_offset; /* 拷贝新msdu帧的偏移地址 */
193 oal_netbuf_stru *dest_buf;
194 mac_ether_header_stru *ether_head; /* 以太网过来的skb的以太网头 */
195 mac_llc_snap_stru *snap_head; /* 为填写snap头的临时指针 */
196
197 /* 协议栈来帧原始长 */
198 frame_len = oal_netbuf_get_len(buf);
199 /* 4字节对齐后的msdu帧的长度 */
200 msdu_len = OAL_ROUND_UP(frame_len, 4);
201 /* msdu帧长 */
202 msdu_len += SNAP_LLC_FRAME_LEN;
203
204 dest_buf = oal_netbuf_peek(&amsdu->msdu_head);
205 if (dest_buf == OAL_PTR_NULL) {
206 /* 链表中应该有netbuf */
207 oam_error_log0(0, OAM_SF_AMSDU, "{hmac_amsdu_tx_encap_mpdu::oal_netbuf_peek return NULL}");
208 return HMAC_TX_PASS;
209 }
210
211 /* 当期netbuf剩余空间少于msdu长 */
212 tailroom = oal_netbuf_tailroom(dest_buf);
213 if (tailroom < msdu_len) {
214 oam_error_log3(0, OAM_SF_AMSDU, "{hmac_amsdu_tx_encap_mpdu::Notify1,tailroom[%d],msdu[%d],frame[%d]}",
215 tailroom, msdu_len, frame_len);
216 /* 如果加上pad超出长度,尝试尾帧去掉pad */
217 msdu_len = frame_len + SNAP_LLC_FRAME_LEN;
218 if (tailroom < msdu_len) {
219 hmac_amsdu_prepare_to_send(hmac_vap, hmac_user, amsdu);
220 return HMAC_TX_PASS;
221 }
222 }
223
224 /* NEW MSDU OFFSET */
225 msdu_offset = (osal_u16)oal_netbuf_get_len(dest_buf);
226
227 /* ETH HEAD + LLC + PAYLOAD */
228 oal_netbuf_put(dest_buf, msdu_len);
229
230 /* COPY ETH HEADER */
231 ether_head = (mac_ether_header_stru *)(oal_netbuf_data(dest_buf) + msdu_offset);
232 (osal_void)memcpy_s((osal_u8 *)ether_head, ETHER_HDR_LEN, oal_netbuf_data(buf), ETHER_HDR_LEN);
233
234 /* FILL LLC HEADER */
235 snap_head = (mac_llc_snap_stru *)((osal_u8 *)ether_head + ETHER_HDR_LEN);
236 (osal_void)memcpy_s((osal_u8 *)snap_head, SNAP_LLC_FRAME_LEN,
237 (osal_u8 *)&g_st_mac_11c_snap_header, SNAP_LLC_FRAME_LEN);
238
239 /* change type & length */
240 snap_head->ether_type = ether_head->ether_type;
241 ether_head->ether_type = oal_byteorder_host_to_net_uint16((osal_u16)(frame_len - ETHER_HDR_LEN +
242 SNAP_LLC_FRAME_LEN));
243
244 /* COPY MSDU PAYLOAD */
245 (osal_void)memcpy_s((osal_u8 *)snap_head + SNAP_LLC_FRAME_LEN, frame_len - ETHER_HDR_LEN,
246 oal_netbuf_data(buf) + ETHER_HDR_LEN, frame_len - ETHER_HDR_LEN); /* 函数调用前已校验buf长度 */
247
248 /* 释放旧msdu */
249 oal_netbuf_free(buf);
250
251 /* 更新amsdu信息 */
252 amsdu->msdu_num++;
253 amsdu->amsdu_size += (osal_u16)msdu_len;
254 amsdu->last_pad_len = (osal_u8)(msdu_len - SNAP_LLC_FRAME_LEN - frame_len);
255
256 tailroom = oal_netbuf_tailroom(dest_buf);
257 /* 当前netbuf剩余空间较少 || 已经达到聚合最大帧数 */
258 if ((tailroom < HMAC_AMSDU_TX_MIN_LENGTH) || (amsdu->msdu_num >= amsdu->amsdu_maxnum)) {
259 hmac_amsdu_prepare_to_send(hmac_vap, hmac_user, amsdu);
260 }
261
262 /* 由于最新的msdu skb已经被释放,不管当前amsdu是否缓存或发送成功/失败,都需要返回TX BUFF */
263 return HMAC_TX_BUFF;
264 }
265
266 /*****************************************************************************
267 函 数 名 : hmac_amsdu_alloc_netbuf
268 功能描述 : 申请netbuf用于聚合组装amsdu
269 *****************************************************************************/
hmac_amsdu_alloc_netbuf(hmac_amsdu_stru * amsdu,oal_netbuf_stru * buf)270 WIFI_HMAC_TCM_TEXT OAL_STATIC OAL_INLINE osal_u32 hmac_amsdu_alloc_netbuf(hmac_amsdu_stru *amsdu, oal_netbuf_stru *buf)
271 {
272 oal_netbuf_stru *dest_buf;
273 mac_tx_ctl_stru *cb;
274
275 dest_buf = OAL_MEM_NETBUF_ALLOC(OAL_NORMAL_NETBUF, WLAN_LARGE_NETBUF_SIZE, OAL_NETBUF_PRIORITY_MID);
276 if (dest_buf == OAL_PTR_NULL) {
277 return OAL_FAIL;
278 }
279
280 /* 子帧链入amsdu尾部 */
281 oal_netbuf_add_to_list_tail(dest_buf, &amsdu->msdu_head);
282
283 (osal_void)memcpy_s(oal_netbuf_cb(dest_buf), OAL_SIZEOF(mac_tx_ctl_stru),
284 oal_netbuf_cb(buf), OAL_SIZEOF(mac_tx_ctl_stru));
285
286 oal_netbuf_copy_queue_mapping(dest_buf, buf);
287
288 cb = (mac_tx_ctl_stru *)oal_netbuf_cb(dest_buf);
289 mac_get_cb_is_first_msdu(cb) = OAL_TRUE;
290 mac_get_cb_is_amsdu(cb) = OAL_TRUE;
291 mac_get_cb_netbuf_num(cb) = 1;
292
293 return OAL_SUCC;
294 }
295
296 /*****************************************************************************
297 函 数 名 : hmac_amsdu_tx_process_etc
298 功能描述 : amsdu聚合发送处理函数
299 *****************************************************************************/
hmac_amsdu_tx_process_etc(hmac_vap_stru * hmac_vap,hmac_user_stru * hmac_user,oal_netbuf_stru * buf)300 WIFI_HMAC_TCM_TEXT OSAL_STATIC osal_u32 hmac_amsdu_tx_process_etc(hmac_vap_stru *hmac_vap, hmac_user_stru *hmac_user,
301 oal_netbuf_stru *buf)
302 {
303 osal_u8 tid_no;
304 osal_u32 frame_len;
305 osal_u32 ul_ret;
306 hmac_amsdu_stru *amsdu;
307 mac_tx_ctl_stru *tx_ctl;
308
309 tx_ctl = (mac_tx_ctl_stru *)(oal_netbuf_cb(buf));
310 frame_len = oal_netbuf_get_len(buf);
311 tid_no = mac_get_cb_wme_tid_type(tx_ctl);
312 amsdu = &(hmac_user->hmac_amsdu[tid_no]);
313
314 /* amsdu组帧溢出,将链表缓存帧发送并清空,新帧作为amsdu首帧入链表 */
315 if (hmac_tx_amsdu_is_overflow(amsdu, frame_len)) {
316 hmac_amsdu_prepare_to_send(hmac_vap, hmac_user, amsdu);
317 }
318
319 if (amsdu->msdu_num == 0) {
320 oal_netbuf_list_head_init(&amsdu->msdu_head);
321 /* 申请netbuf用于聚合amsdu */
322 if (hmac_amsdu_alloc_netbuf(amsdu, buf) != OAL_SUCC) {
323 oam_warning_log1(0, OAM_SF_AMSDU, "vap_id[%d] {hmac_amsdu_tx_process_etc::failed to alloc netbuf.}",
324 hmac_vap->vap_id);
325 return HMAC_TX_PASS;
326 }
327
328 /* 启动定时器 */
329 frw_create_timer_entry(&amsdu->amsdu_timer,
330 hmac_amsdu_tx_timeout_process,
331 HMAC_AMSDU_LIFE_TIME,
332 amsdu,
333 OAL_FALSE);
334 }
335
336 /* 处理每一个msdu */
337 ul_ret = hmac_amsdu_tx_encap_mpdu(hmac_vap, hmac_user, amsdu, buf);
338 return ul_ret;
339 }
340 #endif
341
342 #ifdef _PRE_WLAN_FEATURE_MULTI_NETBUF_AMSDU
343 /*****************************************************************************
344 函 数 名 : hmac_tx_encap_large_skb_amsdu
345 功能描述 : 大包ampdu+amsdu入口函数
346 输入参数 : user: 用户结构体指针
347 buf: skb结构体指针
348 *****************************************************************************/
hmac_tx_encap_large_skb_amsdu(hmac_vap_stru * hmac_vap,hmac_user_stru * hmac_user,oal_netbuf_stru * buf,mac_tx_ctl_stru * tx_ctl)349 osal_void hmac_tx_encap_large_skb_amsdu(hmac_vap_stru *hmac_vap, hmac_user_stru *hmac_user,
350 oal_netbuf_stru *buf,
351 mac_tx_ctl_stru *tx_ctl)
352 {
353 mac_ether_header_stru *ether_hdr_temp;
354 mac_ether_header_stru *ether_hdr;
355 osal_u8 tid_no;
356 osal_u16 mpdu_len;
357 osal_u16 us_80211_frame_len;
358
359 /* AMPDU+AMSDU功能未开启,由定制化门限决定,高于300Mbps时开启amsdu大包聚合 */
360 if (g_st_tx_large_amsdu.cur_amsdu_enable == OAL_FALSE) {
361 return;
362 }
363
364 /* 针对关闭WMM,非QOS帧处理 */
365 if (hmac_user->cap_info.qos == OAL_FALSE) {
366 return;
367 }
368
369 /* VO、组播队列不开启AMPDU+AMSDU */
370 tid_no = mac_get_cb_wme_tid_type(tx_ctl);
371 if (tid_no >= WLAN_TIDNO_VOICE) {
372 return;
373 }
374
375 /* 判断该tid是否支持AMPDU+AMSDU */
376 if (hmac_user_is_amsdu_support(hmac_user, tid_no) == OAL_FALSE) {
377 return;
378 }
379
380 /* 非长帧不进行AMPDU+AMSDU */
381 mpdu_len = (osal_u16)oal_netbuf_get_len(buf);
382 if ((mpdu_len < MAC_AMSDU_SKB_LEN_DOWN_LIMIT) || (mpdu_len > MAC_AMSDU_SKB_LEN_UP_LIMIT)) {
383 return;
384 }
385
386 /* 超出分片帧门限不进行AMPDU+AMSDU,计算时考虑需要新增的EHER HEAD LEN和字节对齐,MAC HEAD考虑最长帧头 */
387 us_80211_frame_len = mpdu_len + SNAP_LLC_FRAME_LEN + 2 + MAC_80211_QOS_HTC_4ADDR_FRAME_LEN; /* 2长度 */
388 if (us_80211_frame_len > mac_mib_get_FragmentationThreshold(hmac_vap)) {
389 return;
390 }
391
392 /* 已经是小包AMSDU聚合 */
393 if (mac_get_cb_is_amsdu(tx_ctl) == OAL_TRUE) {
394 return;
395 }
396
397 /* ETHER HEAD头部空闲空间,4字节对齐;一般此条件均成立,放置于最后 */
398 if (oal_netbuf_headroom(buf) < (SNAP_LLC_FRAME_LEN + 2)) { /* 2长度判断 */
399 return;
400 }
401
402 /* 80211 FRAME INCLUDE EHTER HEAD */
403 mac_get_cb_has_ether_head(tx_ctl) = OAL_TRUE;
404
405 ether_hdr = (mac_ether_header_stru *)oal_netbuf_data(buf);
406
407 /* 预留LLC HEAD长度 */
408 oal_netbuf_push(buf, SNAP_LLC_FRAME_LEN);
409 ether_hdr_temp = (mac_ether_header_stru *)oal_netbuf_data(buf);
410 /* 拷贝mac head */
411 (osal_void)memmove_s((osal_u8 *)ether_hdr_temp, ETHER_HDR_LEN, (osal_u8 *)ether_hdr, ETHER_HDR_LEN);
412 /* 设置AMSDU帧长度 */
413 ether_hdr_temp->ether_type = oal_byteorder_host_to_net_uint16((osal_u16)(
414 mpdu_len - ETHER_HDR_LEN +
415 SNAP_LLC_FRAME_LEN));
416 }
417 #endif
418
419 /*****************************************************************************
420 函 数 名 : hmac_amsdu_tid_info_clear
421 功能描述 : 删除hmac tid中相关的amsdu信息
422 输入参数 : hmac_user : user信息
423 tid_index : TID索引0~7, 最大值为WLAN_TID_MAX_NUM = 8
424 注意事项 : 内部函数, 不校验入参有效性, 由调用者保证
425 *****************************************************************************/
hmac_amsdu_tid_info_clear(hmac_user_stru * hmac_user)426 OAL_STATIC osal_void hmac_amsdu_tid_info_clear(hmac_user_stru *hmac_user)
427 {
428 hmac_amsdu_stru *amsdu = OAL_PTR_NULL;
429 oal_netbuf_stru *amsdu_net_buf = OAL_PTR_NULL;
430 osal_u8 loop;
431
432 for (loop = 0; loop < WLAN_TID_MAX_NUM; loop++) {
433 amsdu = &(hmac_user->hmac_amsdu[loop]);
434
435 /* tid锁, 禁软中断 */
436 osal_spin_lock_bh(&amsdu->amsdu_lock);
437
438 if (amsdu->amsdu_timer.is_registerd == OAL_TRUE) {
439 frw_destroy_timer_entry(&(amsdu->amsdu_timer));
440 }
441
442 /* 清空聚合队列 */
443 if (amsdu->msdu_num != 0) {
444 while (oal_netbuf_list_empty(&amsdu->msdu_head) != OAL_TRUE) {
445 amsdu_net_buf = oal_netbuf_delist(&(amsdu->msdu_head));
446 oal_netbuf_free(amsdu_net_buf);
447 amsdu_net_buf = OAL_PTR_NULL;
448 }
449 amsdu->msdu_num = 0;
450 amsdu->amsdu_size = 0;
451 }
452
453 /* tid解锁, 使能软中断 */
454 osal_spin_unlock_bh(&amsdu->amsdu_lock);
455 }
456 return;
457 }
458
hmac_amsdu_notify_check_param(hmac_vap_stru * hmac_vap,hmac_user_stru * hmac_user,const mac_ether_header_stru * ether_header,osal_u8 tid_no)459 WIFI_HMAC_TCM_TEXT WIFI_TCM_TEXT OSAL_STATIC osal_u32 hmac_amsdu_notify_check_param(hmac_vap_stru *hmac_vap,
460 hmac_user_stru *hmac_user, const mac_ether_header_stru *ether_header, osal_u8 tid_no)
461 {
462 oal_ip_header_stru *pst_ip = OAL_PTR_NULL;
463
464 /* 检查amsdu开关是否打开,amsdu_tx_on 0/1; VAP 是否支持聚合 */
465 if ((mac_mib_get_CfgAmsduTxAtive(hmac_vap) != OAL_TRUE) ||
466 (mac_mib_get_AmsduAggregateAtive(hmac_vap) != OAL_TRUE)) {
467 return HMAC_TX_PASS;
468 }
469
470 /* 判断该tid是否在ampdu情况下支持amsdu的发送,ampdu_amsdu 0/1 */
471 if (hmac_user_is_amsdu_support(hmac_user, tid_no) == OAL_FALSE) {
472 return HMAC_TX_PASS;
473 }
474
475 if (ether_header->ether_type == oal_host2net_short(ETHER_TYPE_IP)) {
476 pst_ip = (oal_ip_header_stru *)(ether_header + 1);
477 /* 允许TCP ACK聚合 */
478 /* 为了解决业务量小时ping包延迟的问题,ICMP不聚合 */
479 if (oal_netbuf_is_icmp_etc(pst_ip) == OAL_TRUE) {
480 return HMAC_TX_PASS;
481 }
482 }
483 /* 检查用户是否是HT/VHT */
484 if (hmac_user_xht_support(hmac_user) == OAL_FALSE) {
485 oam_info_log1(0, OAM_SF_AMSDU, "vap_id[%d] {hmac_amsdu_notify_etc::user is not qos in amsdu notify}",
486 hmac_vap->vap_id);
487 return HMAC_TX_PASS;
488 }
489
490 if (osal_unlikely(tid_no >= WLAN_TID_MAX_NUM)) {
491 oam_error_log1(0, OAM_SF_AMSDU, "vap_id[%d]{hmac_amsdu_notify_etc::invalid tid from] asmdu notify}",
492 hmac_vap->vap_id);
493 return HMAC_TX_PASS;
494 }
495
496 if (tid_no == WLAN_TIDNO_VOICE) {
497 oam_info_log3(0, OAM_SF_AMSDU,
498 "vap_id[%d] {hmac_amsdu_notify_etc::VO TID NOT SUPPORT AMSDU tid_no=%d amsdu_supported=%d",
499 hmac_vap->vap_id, tid_no, hmac_user->amsdu_supported);
500 return HMAC_TX_PASS;
501 }
502 return OAL_CONTINUE;
503 }
504 /*****************************************************************************
505 函 数 名 : hmac_amsdu_notify_etc
506 功能描述 : amsdu入口函数
507 输入参数 : user: 用户结构体指针
508 buf: skb结构体指针
509 *****************************************************************************/
hmac_amsdu_notify_etc(hmac_vap_stru * hmac_vap,hmac_user_stru * hmac_user,oal_netbuf_stru * buf)510 WIFI_HMAC_TCM_TEXT WIFI_TCM_TEXT OSAL_STATIC osal_u32 hmac_amsdu_notify_etc(hmac_vap_stru *hmac_vap,
511 hmac_user_stru *hmac_user, oal_netbuf_stru *buf)
512 {
513 osal_u8 tid_no;
514 osal_u32 ul_ret; /* 所调用函数的返回值 */
515 mac_tx_ctl_stru *tx_ctl;
516 hmac_amsdu_stru *amsdu;
517
518 mac_ether_header_stru *ether_header = (mac_ether_header_stru *)oal_netbuf_data(buf);
519
520 /* 获取cb中的tid信息 */
521 tx_ctl = (mac_tx_ctl_stru *)(oal_netbuf_cb(buf));
522 tid_no = mac_get_cb_wme_tid_type(tx_ctl);
523
524 /* 针对关闭WMM,非QOS帧处理 */
525 if (hmac_user->cap_info.qos == OAL_FALSE) {
526 oam_info_log0(0, OAM_SF_TX, "{hmac_amsdu_notify_etc::UnQos Frame pass!!}");
527 return HMAC_TX_PASS;
528 }
529 /* 组播转单播数据不聚合 */
530 if (tx_ctl->is_m2u_data == OSAL_TRUE) {
531 return HMAC_TX_PASS;
532 }
533 #if !defined(_PRE_WLAN_FEATURE_WS73) && !defined(_PRE_WLAN_FEATURE_WS53)
534 if (tx_ctl->is_tcp_ack == OSAL_TRUE) {
535 return HMAC_TX_PASS;
536 }
537 #endif
538 /* vip tcp ack不聚合 */
539 if (mac_get_cb_vip_tcp_ack(tx_ctl) == OSAL_TRUE) {
540 return HMAC_TX_PASS;
541 }
542 ul_ret = hmac_amsdu_notify_check_param(hmac_vap, hmac_user, ether_header, tid_no);
543 if (ul_ret != OAL_CONTINUE) {
544 return ul_ret;
545 }
546
547 amsdu = &(hmac_user->hmac_amsdu[tid_no]);
548 osal_spin_lock_bh(&amsdu->amsdu_lock);
549
550 /* 新来帧是大帧,需将缓存帧发完 */
551 if (oal_netbuf_get_len(buf) > WLAN_MSDU_MAX_LEN) {
552 /* 防止乱序,应该先发送旧帧 */
553 if (amsdu->msdu_num != 0) {
554 hmac_amsdu_prepare_to_send(hmac_vap, hmac_user, amsdu);
555 }
556 osal_spin_unlock_bh(&amsdu->amsdu_lock);
557 return HMAC_TX_PASS;
558 }
559
560 ul_ret = hmac_amsdu_tx_process_etc(hmac_vap, hmac_user, buf);
561 osal_spin_unlock_bh(&amsdu->amsdu_lock);
562 return ul_ret;
563 }
564
565 /*****************************************************************************
566 函 数 名 : hmac_amsdu_tx_timeout_process
567 功能描述 : 时钟中断事件的处理函数
568 输入参数 : hmac_vap:
569 *****************************************************************************/
hmac_amsdu_tx_timeout_process(osal_void * p_arg)570 WIFI_HMAC_TCM_TEXT OAL_STATIC osal_u32 hmac_amsdu_tx_timeout_process(osal_void *p_arg)
571 {
572 hmac_amsdu_stru *temp_amsdu;
573 mac_tx_ctl_stru *cb;
574 hmac_user_stru *hmac_user;
575 osal_u32 ul_ret;
576 oal_netbuf_stru *pst_netbuf;
577 hmac_vap_stru *hmac_vap;
578
579 if (osal_unlikely(p_arg == OAL_PTR_NULL)) {
580 oam_error_log0(0, OAM_SF_AMPDU, "{hmac_amsdu_tx_timeout_process::input null}");
581 return OAL_ERR_CODE_PTR_NULL;
582 }
583
584 temp_amsdu = (hmac_amsdu_stru *)p_arg;
585
586 osal_spin_lock_bh(&temp_amsdu->amsdu_lock);
587
588 /* 根据要发送的amsdu下第一个msdu子帧的cb字段的信息寻找对应用户结构体 */
589 pst_netbuf = oal_netbuf_peek(&temp_amsdu->msdu_head);
590 if (pst_netbuf == OAL_PTR_NULL) {
591 oam_info_log1(0, OAM_SF_AMSDU, "hmac_amsdu_tx_timeout_process::pst_netbuf NULL. msdu_num[%d]",
592 temp_amsdu->msdu_num);
593 osal_spin_unlock_bh(&temp_amsdu->amsdu_lock);
594 return OAL_ERR_CODE_PTR_NULL;
595 }
596
597 cb = (mac_tx_ctl_stru *)oal_netbuf_cb(pst_netbuf);
598 hmac_vap = (hmac_vap_stru *)mac_res_get_hmac_vap(mac_get_cb_tx_vap_index(cb));
599 if (osal_unlikely(hmac_vap == OAL_PTR_NULL)) {
600 osal_spin_unlock_bh(&temp_amsdu->amsdu_lock);
601 oam_error_log0(0, OAM_SF_AMPDU, "{hmac_amsdu_tx_timeout_process::hmac_vap null}");
602 return OAL_ERR_CODE_PTR_NULL;
603 }
604
605 hmac_user = (hmac_user_stru *)mac_res_get_hmac_user_etc(mac_get_cb_tx_user_idx(cb));
606 if (osal_unlikely(hmac_user == OAL_PTR_NULL)) {
607 osal_spin_unlock_bh(&temp_amsdu->amsdu_lock);
608 oam_error_log1(0, OAM_SF_AMPDU, "{hmac_amsdu_tx_timeout_process::user[%d] null}",
609 mac_get_cb_tx_user_idx(cb));
610 return OAL_ERR_CODE_PTR_NULL;
611 }
612
613 ul_ret = hmac_amsdu_send(hmac_vap, hmac_user, temp_amsdu);
614 if (ul_ret != OAL_SUCC) {
615 oam_warning_log2(0, OAM_SF_AMSDU, "vap_id[%d] hmac_amsdu_tx_timeout_process::hmac_amsdu_send fail[%d]",
616 hmac_vap->vap_id, ul_ret);
617 }
618
619 osal_spin_unlock_bh(&temp_amsdu->amsdu_lock);
620 return OAL_SUCC;
621 }
622
623 /*****************************************************************************
624 函 数 名 : hmac_amsdu_init_user_etc
625 功能描述 : 初始化用户tid队列的AMSDU特性值
626 输入参数 : hmac_user_stru *hmac_user_sta
627 返 回 值 : OAL_STATIC OAL_INLINE osal_void
628 *****************************************************************************/
hmac_amsdu_init_user_etc(hmac_user_stru * hmac_user)629 OSAL_STATIC osal_void hmac_amsdu_init_user_etc(hmac_user_stru *hmac_user)
630 {
631 osal_u32 amsdu_idx;
632 hmac_amsdu_stru *amsdu;
633
634 if (hmac_user == OAL_PTR_NULL) {
635 oam_error_log0(0, OAM_SF_AMPDU, "{hmac_amsdu_init_user_etc::hmac_user_sta null}");
636 return;
637 }
638
639 hmac_user->amsdu_maxsize = WLAN_AMSDU_FRAME_MAX_LEN_LONG;
640
641 hmac_user->amsdu_supported = AMSDU_ENABLE_ALL_TID;
642
643 /* 设置amsdu域 */
644 for (amsdu_idx = 0; amsdu_idx < WLAN_TID_MAX_NUM; amsdu_idx++) {
645 amsdu = &(hmac_user->hmac_amsdu[amsdu_idx]);
646
647 osal_spin_lock_init(&amsdu->amsdu_lock);
648 oal_netbuf_list_head_init(&(amsdu->msdu_head));
649 amsdu->amsdu_size = 0;
650 amsdu->msdu_num = 0;
651 hmac_amsdu_set_maxnum(amsdu, HMAC_AMSDU_MAX_NUM);
652 }
653 }
654
655 #ifdef _PRE_WLAN_SUPPORT_CCPRIV_CMD
hmac_ccpriv_amsdu_tx_on(hmac_vap_stru * hmac_vap,const osal_s8 * param)656 OSAL_STATIC osal_s32 hmac_ccpriv_amsdu_tx_on(hmac_vap_stru *hmac_vap, const osal_s8 *param)
657 {
658 osal_s8 ac_name[CCPRIV_CMD_NAME_MAX_LEN] = {0};
659 osal_s32 ret;
660 osal_u8 aggr_tx_on;
661
662 ret = hmac_ccpriv_get_one_arg(¶m, ac_name, OAL_SIZEOF(ac_name));
663 if (ret != OAL_SUCC) {
664 oam_warning_log1(0, OAM_SF_ANY, "{hmac_ccpriv_amsdu_tx_on::get_cmd_one_arg return err_code [%d]!}", ret);
665 return ret;
666 }
667
668 aggr_tx_on = (osal_u8)oal_atoi((const osal_s8 *)ac_name);
669
670 mac_mib_set_CfgAmsduTxAtive(hmac_vap, aggr_tx_on);
671 oam_warning_log2(0, OAM_SF_CFG, "vap_id[%d] {hmac_config_set_amsdu_tx_on_etc::ENABLE[%d].}",
672 hmac_vap->vap_id, aggr_tx_on);
673
674 return OAL_SUCC;
675 }
676 #endif
677
hmac_tx_amsdu_init(osal_void)678 osal_u32 hmac_tx_amsdu_init(osal_void)
679 {
680 /* 注册对外接口 */
681 #ifdef _PRE_WLAN_FEATURE_MULTI_NETBUF_AMSDU
682 hmac_feature_hook_register(HMAC_FHOOK_AMSDU_TX_ENCAP_LARGE_SKB, hmac_tx_encap_large_skb_amsdu);
683 #endif
684 hmac_feature_hook_register(HMAC_FHOOK_AMSDU_TX_NOTIFY_ETC, hmac_amsdu_notify_etc);
685 hmac_feature_hook_register(HMAC_FHOOK_AMSDU_TX_INIT_USER_ETC, hmac_amsdu_init_user_etc);
686 hmac_feature_hook_register(HMAC_FHOOK_AMSDU_TID_INFO_CLEAR, hmac_amsdu_tid_info_clear);
687
688 #ifdef _PRE_WLAN_SUPPORT_CCPRIV_CMD
689 /* ccpriv命令注册, 开启或关闭ampdu发送功能 ccpriv "vap0 amsdu_tx_on 0\1" */
690 hmac_ccpriv_register((const osal_s8 *)"amsdu_tx_on", hmac_ccpriv_amsdu_tx_on);
691 #endif
692
693 return OAL_SUCC;
694 }
695
hmac_tx_amsdu_deinit(osal_void)696 osal_void hmac_tx_amsdu_deinit(osal_void)
697 {
698 /* 去注册对外接口 */
699 #ifdef _PRE_WLAN_FEATURE_MULTI_NETBUF_AMSDU
700 hmac_feature_hook_unregister(HMAC_FHOOK_AMSDU_TX_ENCAP_LARGE_SKB);
701 #endif
702 hmac_feature_hook_unregister(HMAC_FHOOK_AMSDU_TX_NOTIFY_ETC);
703 hmac_feature_hook_unregister(HMAC_FHOOK_AMSDU_TX_INIT_USER_ETC);
704 hmac_feature_hook_unregister(HMAC_FHOOK_AMSDU_TID_INFO_CLEAR);
705
706 #ifdef _PRE_WLAN_SUPPORT_CCPRIV_CMD
707 /* ccpriv命令去注册 */
708 hmac_ccpriv_unregister((const osal_s8 *)"amsdu_tx_on");
709 #endif
710
711 return;
712 }
713
714 #ifdef __cplusplus
715 #if __cplusplus
716 }
717 #endif
718 #endif
719
720