• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 HiSilicon (Shanghai) Technologies CO., LIMITED.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  */
18 
19 /* ****************************************************************************
20   1 头文件包含
21 **************************************************************************** */
22 #include "mac_frame.h"
23 #include "mac_data.h"
24 #include "hmac_rx_data.h"
25 #include "dmac_ext_if.h"
26 #include "hmac_vap.h"
27 #include "hmac_ext_if.h"
28 #include "oam_ext_if.h"
29 #include "oal_ext_if.h"
30 #include "oal_net.h"
31 #include "hmac_frag.h"
32 #include "hmac_11i.h"
33 #include "mac_vap.h"
34 #include "hmac_blockack.h"
35 #include "hmac_mgmt_bss_comm.h"
36 #include "hcc_hmac_if.h"
37 #include "wal_cfg80211_apt.h"
38 #ifdef _PRE_WLAN_FEATURE_WAPI
39 #include "hmac_wapi.h"
40 #endif
41 #ifdef _PRE_WLAN_FEATURE_EDCA_OPT_AP
42 #include "hmac_edca_opt.h"
43 #endif
44 #ifdef _PRE_HDF_LINUX
45 #include <linux/netdevice.h>
46 #endif
47 
48 #ifdef __cplusplus
49 #if __cplusplus
50 extern "C" {
51 #endif
52 #endif
53 
54 /* ****************************************************************************
55   2 函数实现
56 **************************************************************************** */
57 #ifdef _PRE_WLAN_FEATURE_MESH
58 hi_void hmac_rx_process_data_mesh_tcp_ack_opt(hmac_vap_stru *hmac_vap, const oal_netbuf_head_stru *netbuf_header);
59 #endif
60 
61 /* ****************************************************************************
62  功能描述  : 将MSDU转化为以太网格式的帧
63  输入参数  : pst_netbuf : 指向含有MSDU的netbuf的指针
64              puc_da     : 目的地址
65              puc_sa     : 源地址
66  修改历史      :
67   1.日    期   : 2013年12月19日
68     作    者   : HiSilicon
69     修改内容   : 新生成函数
70 **************************************************************************** */
hmac_rx_frame_80211_to_eth(oal_netbuf_stru * netbuf,const hi_u8 * da_mac_addr,hi_u8 da_addr_len,const hi_u8 * sa_mac_addr,hi_u8 sa_addr_len)71 static hi_void hmac_rx_frame_80211_to_eth(oal_netbuf_stru *netbuf, const hi_u8 *da_mac_addr, hi_u8 da_addr_len,
72     const hi_u8 *sa_mac_addr, hi_u8 sa_addr_len)
73 {
74     mac_ether_header_stru *ether_hdr = HI_NULL;
75     mac_llc_snap_stru *snap = HI_NULL;
76     hi_u16 us_ether_type;
77 
78     snap = (mac_llc_snap_stru *)oal_netbuf_data(netbuf);
79     us_ether_type = snap->us_ether_type;
80 
81     /* 将payload向前扩充6个字节,加上后面8个字节的snap头空间,构成以太网头的14字节空间 */
82     oal_netbuf_push(netbuf, HMAC_RX_DATA_ETHER_OFFSET_LENGTH);
83     ether_hdr = (mac_ether_header_stru *)oal_netbuf_data(netbuf);
84 
85     ether_hdr->us_ether_type = us_ether_type;
86     if (memcpy_s(ether_hdr->auc_ether_shost, ETHER_ADDR_LEN, sa_mac_addr, sa_addr_len) != EOK) {
87         return;
88     }
89     if (memcpy_s(ether_hdr->auc_ether_dhost, ETHER_ADDR_LEN, da_mac_addr, da_addr_len) != EOK) {
90         return;
91     }
92 }
93 
94 /* ****************************************************************************
95  功能描述  : 释放指定个数的netbuf
96  输入参数  : (1)期望删除的netbuf的起始指针
97              (2)需要删除的netbuf的个数
98  返 回 值  : 成功或者失败原因
99  修改历史      :
100   1.日    期   : 2012年12月6日
101     作    者   : HiSilicon
102     修改内容   : 新生成函数
103 **************************************************************************** */
hmac_rx_free_netbuf(oal_netbuf_stru * netbuf,hi_u16 us_nums)104 hi_void hmac_rx_free_netbuf(oal_netbuf_stru *netbuf, hi_u16 us_nums)
105 {
106     oal_netbuf_stru *netbuf_temp = HI_NULL;
107     hi_u16 us_netbuf_num;
108 
109     if (oal_unlikely(netbuf == HI_NULL)) {
110         oam_error_log0(0, OAM_SF_RX, "{hmac_rx_free_netbuf::pst_netbuf null.}\r\n");
111         return;
112     }
113 
114     for (us_netbuf_num = us_nums; us_netbuf_num > 0; us_netbuf_num--) {
115         netbuf_temp = oal_netbuf_next(netbuf);
116 
117         /* 减少netbuf对应的user引用计数 */
118         oal_netbuf_free(netbuf);
119 
120         netbuf = netbuf_temp;
121         if (netbuf == HI_NULL) {
122             if (oal_unlikely(us_netbuf_num != 1)) {
123                 oam_error_log2(0, OAM_SF_RX,
124                     "{hmac_rx_free_netbuf::pst_netbuf list broken, us_netbuf_num[%d]us_nums[%d].}", us_netbuf_num,
125                     us_nums);
126                 return;
127             }
128 
129             break;
130         }
131     }
132 }
133 
134 /* ****************************************************************************
135  功能描述  : free netbuff list
136  修改历史      :
137   1.日    期   : 2015年1月3日
138     作    者   : HiSilicon
139     修改内容   : 新生成函数
140 **************************************************************************** */
hmac_rx_free_netbuf_list(oal_netbuf_head_stru * netbuf_hdr,hi_u16 num_buf)141 hi_void hmac_rx_free_netbuf_list(oal_netbuf_head_stru *netbuf_hdr, hi_u16 num_buf)
142 {
143     oal_netbuf_stru *netbuf = HI_NULL;
144     hi_u16 us_idx;
145 
146     if (oal_unlikely(netbuf_hdr == HI_NULL)) {
147         oam_info_log0(0, OAM_SF_RX, "{hmac_rx_free_netbuf_list::pst_netbuf null.}");
148         return;
149     }
150 
151     for (us_idx = num_buf; us_idx > 0; us_idx--) {
152         netbuf = oal_netbuf_delist(netbuf_hdr);
153         if (netbuf != HI_NULL) {
154             oal_netbuf_free(netbuf);
155         }
156     }
157 }
158 
159 /* ****************************************************************************
160  功能描述  : 将数据帧发送到WLAN侧的接口函数,将一个netbuf链抛给发送流程,每个
161              netbuf的内容都是一个以太网格式的MSDU
162  输入参数  : (1)指向事件头的指针
163              (2)指向需要发送的netbuf的第一个元素的指针
164  返 回 值  : 成功或者失败原因
165  修改历史      :
166   1.日    期   : 2012年11月19日
167     作    者   : HiSilicon
168     修改内容   : 新生成函数
169   2.日    期   : 2016年06月20日
170     作    者   : HiSilicon
171 **************************************************************************** */
hmac_rx_transmit_to_wlan(frw_event_hdr_stru * event_hdr,oal_netbuf_head_stru * netbuf_head)172 static hi_u32 hmac_rx_transmit_to_wlan(frw_event_hdr_stru *event_hdr, oal_netbuf_head_stru *netbuf_head)
173 {
174     oal_netbuf_stru *netbuf = HI_NULL; /* 从netbuf链上取下来的指向netbuf的指针 */
175     hi_u32 netbuf_num;
176     hi_u32 ret;
177     oal_netbuf_stru *buf_tmp = HI_NULL; /* 暂存netbuf指针,用于while循环 */
178     hmac_tx_ctl_stru *tx_ctl = HI_NULL;
179     mac_vap_stru *mac_vap = HI_NULL;
180 
181     if (oal_unlikely((event_hdr == HI_NULL) || (netbuf_head == HI_NULL))) {
182         oam_error_log2(0, OAM_SF_RX, "{hmac_rx_transmit_to_wlan::param null, %p %p.}", (uintptr_t)event_hdr,
183             (uintptr_t)netbuf_head);
184         return HI_ERR_CODE_PTR_NULL;
185     }
186 
187     /* 获取链头的net buffer */
188     netbuf = oal_netbuf_peek(netbuf_head);
189 
190     /* 获取mac vap 结构 */
191     ret = hmac_tx_get_mac_vap(event_hdr->vap_id, &mac_vap);
192     if (oal_unlikely(ret != HI_SUCCESS)) {
193         netbuf_num = oal_netbuf_list_num(netbuf_head);
194         hmac_rx_free_netbuf(netbuf, (hi_u16)netbuf_num);
195         oam_warning_log3(event_hdr->vap_id, OAM_SF_RX,
196             "{hmac_rx_transmit_to_wlan::find vap [%d] failed[%d], free [%d] netbuffer.}", event_hdr->vap_id, ret,
197             netbuf_num);
198         return ret;
199     }
200 
201     /* 循环处理每一个netbuf,按照以太网帧的方式处理 */
202     while (netbuf != HI_NULL) {
203         buf_tmp = oal_netbuf_next(netbuf);
204         set_oal_netbuf_next(netbuf, HI_NULL);
205         set_oal_netbuf_prev(netbuf, HI_NULL);
206 
207         /* 转WLAN的报文长度必须大于ETHER_HDR_LEN,否则异常丢弃 */
208         if (oal_netbuf_len(netbuf) < ETHER_HDR_LEN) {
209             hmac_free_netbuf_list(netbuf);
210             netbuf = buf_tmp;
211             continue;
212         }
213 
214         tx_ctl = (hmac_tx_ctl_stru *)oal_netbuf_cb(netbuf);
215         if (memset_s(tx_ctl, sizeof(hmac_tx_ctl_stru), 0, sizeof(hmac_tx_ctl_stru)) != EOK) {
216             hmac_free_netbuf_list(netbuf);
217             netbuf = buf_tmp;
218             continue;
219         }
220 
221         tx_ctl->event_type = FRW_EVENT_TYPE_WLAN_DTX;
222         tx_ctl->event_sub_type = DMAC_TX_WLAN_DTX;
223 
224 #if (_PRE_MULTI_CORE_MODE_OFFLOAD_DMAC == _PRE_MULTI_CORE_MODE)
225         /* set the queue map id when wlan to wlan */
226         oal_skb_set_queue_mapping(netbuf, WLAN_NORMAL_QUEUE);
227 #endif
228 
229         ret = hmac_tx_lan_to_wlan(mac_vap, netbuf);
230         if (oal_unlikely(ret != HI_SUCCESS)) {
231             hmac_free_netbuf_list(netbuf);
232         }
233         netbuf = buf_tmp;
234     }
235 
236     return HI_SUCCESS;
237 }
238 
hmac_rx_set_msdu_state(oal_netbuf_stru * netbuf,hmac_msdu_proc_state_stru * msdu_state)239 hi_void hmac_rx_set_msdu_state(oal_netbuf_stru *netbuf, hmac_msdu_proc_state_stru *msdu_state)
240 {
241     if (msdu_state->procd_msdu_in_netbuf == 0) {
242         msdu_state->curr_netbuf = netbuf;
243 
244         /* AMSDU时,首个netbuf的中包含802.11头,对应的payload需要偏移 */
245         hmac_rx_ctl_stru *rx_ctrl = (hmac_rx_ctl_stru *)oal_netbuf_cb(msdu_state->curr_netbuf);
246 
247         msdu_state->puc_curr_netbuf_data = (hi_u8 *)(rx_ctrl->pul_mac_hdr_start_addr) + rx_ctrl->mac_header_len;
248         msdu_state->msdu_nums_in_netbuf = rx_ctrl->msdu_in_buffer;
249         msdu_state->us_submsdu_offset = 0;
250     }
251 }
252 
hmac_rx_msdu_proc(const hmac_vap_stru * hmac_vap,oal_netbuf_head_stru * netbuf_header,oal_netbuf_stru * netbuf,mac_ieee80211_frame_stru * frame_hdr,const hmac_rx_ctl_stru * rx_ctrl)253 hi_u32 hmac_rx_msdu_proc(const hmac_vap_stru *hmac_vap, oal_netbuf_head_stru *netbuf_header, oal_netbuf_stru *netbuf,
254     mac_ieee80211_frame_stru *frame_hdr, const hmac_rx_ctl_stru *rx_ctrl)
255 {
256     hi_u8 sa_mac_addr[WLAN_MAC_ADDR_LEN];
257     hi_u8 da_mac_addr[WLAN_MAC_ADDR_LEN];
258     hi_u8 *source_mac_addr = HI_NULL;
259     hi_u8 *dest_mac_addr   = HI_NULL;
260 
261     hmac_user_stru *hmac_user = (hmac_user_stru *)hmac_user_get_user_stru(rx_ctrl->us_ta_user_idx);
262     if (oal_unlikely(hmac_user == HI_NULL)) {
263         return HI_ERR_CODE_PTR_NULL;
264     }
265 
266     netbuf = hmac_defrag_process(hmac_user, netbuf, rx_ctrl->mac_header_len);
267     if (netbuf == HI_NULL) {
268         return HI_SUCCESS;
269     }
270 
271     rx_ctrl = (hmac_rx_ctl_stru *)oal_netbuf_cb(netbuf);
272     frame_hdr = (mac_ieee80211_frame_stru *)rx_ctrl->pul_mac_hdr_start_addr;
273 
274     /* 从MAC头中获取源地址和目的地址 */
275     mac_rx_get_sa(frame_hdr, &source_mac_addr);
276     mac_rx_get_da(frame_hdr, &dest_mac_addr);
277     if ((memcpy_s(sa_mac_addr, WLAN_MAC_ADDR_LEN, source_mac_addr, WLAN_MAC_ADDR_LEN) != EOK) ||
278         (memcpy_s(da_mac_addr, WLAN_MAC_ADDR_LEN, dest_mac_addr, WLAN_MAC_ADDR_LEN) != EOK)) {
279         return HI_FAIL;
280     }
281 
282     /* 将netbuf的data指针指向mac frame的payload处,也就是指向了8字节的snap头 */
283     oal_netbuf_pull(netbuf, rx_ctrl->mac_header_len);
284 
285     /* 将MSDU转化为以太网格式的帧 */
286     hmac_rx_frame_80211_to_eth(netbuf, da_mac_addr, WLAN_MAC_ADDR_LEN, sa_mac_addr, WLAN_MAC_ADDR_LEN);
287 
288     /* 安全编程规则6.6例外(1) 对固定长度的数组进行初始化 */
289     memset_s(oal_netbuf_cb(netbuf), oal_netbuf_cb_size(), 0, oal_netbuf_cb_size());
290 
291 #if defined(_PRE_WLAN_FEATURE_WPA) || defined(_PRE_WLAN_FEATURE_WPA2)
292     mac_ether_header_stru *ether = (mac_ether_header_stru *)oal_netbuf_data(netbuf);
293     if (ether == HI_NULL) {
294         return HI_FAIL;
295     }
296     if (hmac_11i_ether_type_filter(hmac_vap, ether->auc_ether_shost, ether->us_ether_type) != HI_SUCCESS) {
297         return HI_FAIL;
298     } else {
299         /* 将MSDU加入到netbuf链的最后 */
300         oal_netbuf_add_to_list_tail(netbuf, netbuf_header);
301     }
302 #else
303     /* 将MSDU加入到netbuf链的最后 */
304     oal_netbuf_add_to_list_tail(netbuf, netbuf_header);
305 #endif
306 
307     return HI_SUCCESS;
308 }
309 
310 /* ****************************************************************************
311  功能描述  : 解析MPDU,如果是非AMSDU,则将MSDU还原为以太网格式的帧,并加入到
312              netbuf链的最后,如果该MPDU是AMSDU,则解析出每一个MSDU,并且每一
313              个MSDU占用一个netbuf
314  输入参数  : pst_netbuf_header: 要交给发送流程的netbuf链表头
315              pst_netbuf       : 当前要处理的MPDU的第一个netbuf
316              pst_frame_hdr    : 当前要处理的MPDU的MAC头
317  返 回 值  : 成功或者错误码
318  修改历史      :
319   1.日    期   : 2013年12月17日
320     作    者   : HiSilicon
321     修改内容   : 新生成函数
322 **************************************************************************** */
hmac_rx_prepare_msdu_list_to_wlan(const hmac_vap_stru * hmac_vap,oal_netbuf_head_stru * netbuf_header,oal_netbuf_stru * netbuf,mac_ieee80211_frame_stru * frame_hdr)323 static hi_u32 hmac_rx_prepare_msdu_list_to_wlan(const hmac_vap_stru *hmac_vap, oal_netbuf_head_stru *netbuf_header,
324     oal_netbuf_stru *netbuf, mac_ieee80211_frame_stru *frame_hdr)
325 {
326     hi_u32 ret;
327     hmac_rx_ctl_stru *rx_ctrl = (hmac_rx_ctl_stru *)oal_netbuf_cb(netbuf); /* 获取该MPDU的控制信息 */
328 
329     /* 情况一:不是AMSDU聚合,则该MPDU对应一个MSDU,同时对应一个NETBUF,将MSDU还原
330        成以太网格式帧以后直接加入到netbuf链表最后
331      */
332     if (rx_ctrl->amsdu_enable == HI_FALSE) {
333         ret = hmac_rx_msdu_proc(hmac_vap, netbuf_header, netbuf, frame_hdr, rx_ctrl);
334         return ret;
335     } else { /* 情况二:AMSDU聚合 */
336         return HI_FAIL;
337     }
338 }
339 
340 #ifdef _PRE_WLAN_FEATURE_PKT_MEM_OPT
hmac_pkt_mem_opt_stat_reset(hmac_device_stru * hmac_dev,hi_u8 dscr_opt_state)341 static hi_void hmac_pkt_mem_opt_stat_reset(hmac_device_stru *hmac_dev, hi_u8 dscr_opt_state)
342 {
343     frw_event_mem_stru *event_mem = HI_NULL;
344     frw_event_stru *event = HI_NULL;
345     hmac_rx_dscr_opt_stru *dscr_opt = &hmac_dev->rx_dscr_opt;
346 
347     dscr_opt->dscr_opt_state = dscr_opt_state;
348     dscr_opt->rx_pkt_num = 0;
349     /* **************************************************************************
350         抛事件到dmac模块,将统计信息报给dmac
351     ************************************************************************** */
352     event_mem = frw_event_alloc(0);
353     if (oal_unlikely(event_mem == HI_NULL)) {
354         oam_error_log0(0, OAM_SF_ANY, "{hmac_rx_dscr_opt_timeout_fn::event_mem null.}");
355         return;
356     }
357 
358     event = (frw_event_stru *)event_mem->puc_data;
359 
360     /* 填写事件头 */
361     frw_event_hdr_init(&(event->event_hdr), FRW_EVENT_TYPE_WLAN_CTX, DMAC_WLAN_CTX_EVENT_SUB_TYPE_DSCR_OPT, 0,
362         FRW_EVENT_PIPELINE_STAGE_1, 0);
363 
364     /* 拷贝参数 */
365     event->auc_event_data[0] = dscr_opt->dscr_opt_state;
366 
367     /* 分发事件 */
368     hcc_hmac_tx_control_event(event_mem, 0);
369     frw_event_free(event_mem);
370 }
371 
372 /* ****************************************************************************
373  功能描述  : 配置hmac_pkt_mem_opt_cfg参数
374  输入参数  : ul_cfg_type:0 enable使能开关
375                          1 opt_limit
376                          2 reset_limit
377  修改历史      :
378   1.日    期   : 2015年10月14日
379     作    者   : HiSilicon
380     修改内容   : 新生成函数
381 **************************************************************************** */
hmac_pkt_mem_opt_cfg(hi_u32 cfg_tpye,hi_u32 cfg_value)382 hi_void hmac_pkt_mem_opt_cfg(hi_u32 cfg_tpye, hi_u32 cfg_value)
383 {
384     hmac_device_stru *hmac_dev = hmac_get_device_stru();
385     hmac_rx_dscr_opt_stru *dscr_opt = HI_NULL;
386 
387     if (cfg_tpye > 2) { /* 大于2 无效类型 */
388         oam_warning_log0(0, OAM_SF_ANY, "{hmac_rx_dscr_opt_cfg::invalid cfg tpye.}");
389         return;
390     }
391 
392     oam_warning_log2(0, OAM_SF_ANY, "{hmac_rx_dscr_opt_cfg::cfg type[%d], cfg value[%d].}", cfg_tpye, cfg_value);
393     dscr_opt = &hmac_dev->rx_dscr_opt;
394     if (cfg_tpye == 0) {
395         dscr_opt->dscr_opt_enable = (hi_u8)cfg_value;
396         if (dscr_opt->dscr_opt_enable == HI_FALSE && dscr_opt->dscr_opt_state == HI_TRUE) {
397             hmac_pkt_mem_opt_stat_reset(hmac_dev, HI_FALSE);
398         }
399     } else if (cfg_tpye == 1) {
400         dscr_opt->rx_pkt_opt_limit = cfg_value;
401     } else if (cfg_tpye == 2) { /* 等于2 reset */
402         dscr_opt->rx_pkt_reset_limit = cfg_value;
403     }
404 }
405 
hmac_pkt_mem_opt_timeout_fn(hi_void * arg)406 hi_u32 hmac_pkt_mem_opt_timeout_fn(hi_void *arg)
407 {
408     hmac_device_stru *hmac_dev = HI_NULL;
409     hmac_rx_dscr_opt_stru *dscr_opt = HI_NULL;
410 
411     if (oal_unlikely(arg == HI_NULL)) {
412         oam_warning_log0(0, OAM_SF_ANY, "{hmac_rx_dscr_opt_timeout_fn::p_arg is null.}");
413         return HI_ERR_CODE_PTR_NULL;
414     }
415 
416     hmac_dev = (hmac_device_stru *)arg;
417     dscr_opt = &hmac_dev->rx_dscr_opt;
418 
419     if (dscr_opt->dscr_opt_enable != HI_TRUE) {
420         return HI_SUCCESS;
421     }
422 
423     oam_info_log2(0, OAM_SF_ANY, "{hmac_rx_dscr_opt_timeout_fn::state[%d], pkt_num[%d]}", dscr_opt->dscr_opt_state,
424         dscr_opt->rx_pkt_num);
425 
426     /* rx_dscr未调整状态时, 检测到RX业务,调整描述符 */
427     if (dscr_opt->dscr_opt_state == HI_FALSE && dscr_opt->rx_pkt_num > dscr_opt->rx_pkt_opt_limit) {
428         hmac_pkt_mem_opt_stat_reset(hmac_dev, HI_TRUE);
429     } else if (dscr_opt->dscr_opt_state == HI_TRUE && dscr_opt->rx_pkt_num < dscr_opt->rx_pkt_reset_limit) {
430         /* rx_dscr已调整状态时, 未检测到RX业务, 调整回描述符,保证TX性能 */
431         hmac_pkt_mem_opt_stat_reset(hmac_dev, HI_FALSE);
432     } else {
433         dscr_opt->rx_pkt_num = 0;
434     }
435 
436     return HI_SUCCESS;
437 }
438 
hmac_pkt_mem_opt_init(hmac_device_stru * hmac_dev)439 hi_void hmac_pkt_mem_opt_init(hmac_device_stru *hmac_dev)
440 {
441     hmac_dev->rx_dscr_opt.dscr_opt_state = HI_FALSE;
442     hmac_dev->rx_dscr_opt.rx_pkt_num = 0;
443     hmac_dev->rx_dscr_opt.rx_pkt_opt_limit = WLAN_PKT_MEM_PKT_OPT_LIMIT;
444     hmac_dev->rx_dscr_opt.rx_pkt_reset_limit = WLAN_PKT_MEM_PKT_RESET_LIMIT;
445     /* 功能无效,暂时关闭 */
446     hmac_dev->rx_dscr_opt.dscr_opt_enable = HI_FALSE;
447 
448     frw_timer_create_timer(&(hmac_dev->rx_dscr_opt.rx_dscr_opt_timer), hmac_pkt_mem_opt_timeout_fn,
449         WLAN_PKT_MEM_OPT_TIME_MS, hmac_dev, HI_TRUE);
450 }
451 
hmac_pkt_mem_opt_exit(hmac_device_stru * hmac_dev)452 hi_void hmac_pkt_mem_opt_exit(hmac_device_stru *hmac_dev)
453 {
454     if (hmac_dev->rx_dscr_opt.rx_dscr_opt_timer.is_registerd == HI_TRUE) {
455         frw_timer_immediate_destroy_timer(&(hmac_dev->rx_dscr_opt.rx_dscr_opt_timer));
456     }
457 }
458 
hmac_pkt_mem_opt_rx_pkts_stat(const oal_ip_header_stru * ip)459 static hi_void hmac_pkt_mem_opt_rx_pkts_stat(const oal_ip_header_stru *ip)
460 {
461     hmac_device_stru *hmac_dev = hmac_get_device_stru();
462     /* 过滤IP_LEN 小于 WLAN_SHORT_NETBUF_SIZE的报文 */
463     if (oal_net2host_short(ip->us_tot_len) < WLAN_SHORT_NETBUF_SIZE) {
464         return;
465     }
466 
467     if ((ip->protocol == MAC_UDP_PROTOCAL) || (ip->protocol == MAC_TCP_PROTOCAL)) {
468         hmac_dev->rx_dscr_opt.rx_pkt_num++;
469     }
470 }
471 #endif
472 
473 #ifdef _PRE_WLAN_FEATURE_EDCA_OPT_AP
hmac_rx_transmit_edca_opt_ap(const hmac_vap_stru * hmac_vap,mac_ether_header_stru * ether_hdr)474 static hi_u32 hmac_rx_transmit_edca_opt_ap(const hmac_vap_stru *hmac_vap, mac_ether_header_stru *ether_hdr)
475 {
476     mac_vap_stru         *mac_vap = hmac_vap->base_vap;
477     hmac_user_stru       *hmac_user = HI_NULL;
478     mac_ip_header_stru   *ip = HI_NULL;
479     hi_u8                assoc_id = 0xff;
480 
481     if (((mac_vap->vap_mode == WLAN_VAP_MODE_BSS_AP)
482 #ifdef _PRE_WLAN_FEATURE_MESH
483         || (mac_vap->vap_mode == WLAN_VAP_MODE_MESH)
484 #endif
485         ) && (hmac_vap->edca_opt_flag_ap == HI_TRUE)) {
486         /* Mesh IPv6可能进行报头压缩,暂不纳入此处处理 */
487         if (oal_host2net_short(ETHER_TYPE_IP) == ether_hdr->us_ether_type) {
488             if (mac_vap_find_user_by_macaddr(mac_vap, ether_hdr->auc_ether_shost, ETHER_ADDR_LEN, &assoc_id) !=
489                 HI_SUCCESS) {
490                 oam_warning_log3(hmac_vap->base_vap->vap_id, OAM_SF_M2U,
491                     "{hmac_rx_transmit_edca_opt_ap::find_user_by_macaddr[XX:XX:XX:%02x:%02x:%02x]failed}",
492                     (hi_u32)(ether_hdr->auc_ether_shost[3]),  /* 3 元素索引 */
493                     (hi_u32)(ether_hdr->auc_ether_shost[4]),  /* 4 元素索引 */
494                     (hi_u32)(ether_hdr->auc_ether_shost[5])); /* 5 元素索引 */
495                 return HI_FAIL;
496             }
497             hmac_user = (hmac_user_stru *)hmac_user_get_user_stru(assoc_id);
498             if (hmac_user == HI_NULL) {
499                 oam_error_log1(hmac_vap->base_vap->vap_id, OAM_SF_RX,
500                     "{hmac_rx_transmit_edca_opt_ap::hmac_user_get_user_stru fail. assoc_id: %u}", assoc_id);
501                 return HI_FAIL;
502             }
503 
504             ip = (mac_ip_header_stru *)(ether_hdr + 1);
505 
506             /* mips优化:解决开启业务统计性能差10M问题 */
507             if (((ip->protocol == MAC_UDP_PROTOCAL) && (hmac_user->txrx_data_stat[WLAN_WME_AC_BE][WLAN_RX_UDP_DATA] <
508                 (HMAC_EDCA_OPT_PKT_NUM + 10))) || /* 10 用于计算 */
509                 ((ip->protocol == MAC_TCP_PROTOCAL) && (hmac_user->txrx_data_stat[WLAN_WME_AC_BE][WLAN_RX_TCP_DATA] <
510                 (HMAC_EDCA_OPT_PKT_NUM + 10)))) { /* 10 用于计算 */
511                 hmac_edca_opt_rx_pkts_stat(hmac_user, WLAN_TIDNO_BEST_EFFORT, ip);
512             }
513         }
514     }
515 
516     return HI_SUCCESS;
517 }
518 #endif
519 
520 /* ****************************************************************************
521  功能描述  : 将MSDU转发到LAN的接口,包括地址转换等信息的设置
522              说明:本函数接收到的netbuf数据域是从snap头开始
523  输入参数  : (1)指向vap的指针
524              (2)指向需要发送的msdu的指针
525  返 回 值  : 成功或者失败原因
526  修改历史      :
527   1.日    期   : 2012年11月14日
528     作    者   : HiSilicon
529     修改内容   : 新生成函数
530 **************************************************************************** */
hmac_rx_transmit_msdu_to_lan(const hmac_vap_stru * hmac_vap,hmac_msdu_stru * msdu)531 static hi_void hmac_rx_transmit_msdu_to_lan(const hmac_vap_stru *hmac_vap, hmac_msdu_stru *msdu)
532 {
533     /* 获取netbuf,该netbuf的data指针已经指向payload处 */
534     oal_netbuf_stru *netbuf = msdu->netbuf;
535 
536     set_oal_netbuf_prev(netbuf, HI_NULL);
537     set_oal_netbuf_next(netbuf, HI_NULL);
538 
539     hmac_rx_frame_80211_to_eth(netbuf, msdu->auc_da, WLAN_MAC_ADDR_LEN, msdu->auc_sa, WLAN_MAC_ADDR_LEN);
540 
541     mac_ether_header_stru *ether_hdr = (mac_ether_header_stru *)oal_netbuf_data(netbuf);
542     if (oal_unlikely(ether_hdr == HI_NULL)) {
543         oal_netbuf_free(netbuf);
544         oam_error_log0(hmac_vap->base_vap->vap_id, OAM_SF_RX, "{hmac_rx_transmit_msdu_to_lan::pst_ether_hdr null.}");
545         return;
546     }
547 #if defined(_PRE_WLAN_FEATURE_WPA) || defined(_PRE_WLAN_FEATURE_WPA2)
548     hi_u8 *mac_addr = msdu->auc_ta;
549 
550     if (HI_SUCCESS != hmac_11i_ether_type_filter(hmac_vap, mac_addr, ether_hdr->us_ether_type)) {
551         /* 接收安全数据过滤 */
552         oal_netbuf_free(netbuf);
553         return;
554     }
555 #endif
556     /* 获取net device hmac创建的时候,需要记录netdevice指针 */
557     oal_net_device_stru *netdev = hmac_vap->net_device;
558 
559     /* 对protocol模式赋值 */
560     oal_eth_type_trans(netbuf, netdev);
561 
562 #ifdef _PRE_WLAN_FEATURE_EDCA_OPT_AP
563     if (hmac_rx_transmit_edca_opt_ap(hmac_vap, ether_hdr) != HI_SUCCESS) {
564         oal_netbuf_free(netbuf);
565         return;
566     }
567 #endif
568 
569 #ifdef _PRE_WLAN_FEATURE_PKT_MEM_OPT
570     hmac_pkt_mem_opt_rx_pkts_stat((oal_ip_header_stru *)(ether_hdr + 1));
571 #endif
572 
573     /* 将skb转发给桥 */
574 #if (_PRE_OS_VERSION_LITEOS == _PRE_OS_VERSION)
575     netbuf->dev = netdev;
576 
577     /* 将skb的data指针指向以太网的帧头 */
578     /* 由于前面pull了14字节,这个地方要push回去 */
579     oal_netbuf_push(netbuf, ETHER_HDR_LEN);
580 #endif
581 
582 #ifdef _PRE_HDF_LINUX
583     netbuf->dev = (struct net_device *)netdev;
584 #endif
585 
586     if (HI_TRUE == hmac_get_rxthread_enable()) {
587         hmac_rxdata_netbuf_enqueue(netbuf);
588 
589         hmac_rxdata_sched();
590     } else {
591         oal_netif_rx_ni(netbuf);
592     }
593 
594     /* 置位net_dev->jiffies变量 */
595     oal_netdevice_last_rx(netdev) = OAL_TIME_JIFFY;
596 }
597 
hmac_rx_msdu_frame_classify(const hmac_vap_stru * hmac_vap,oal_netbuf_stru * netbuf,mac_ieee80211_frame_stru * frame_hdr,hmac_msdu_stru * msdu,hmac_user_stru * hmac_user)598 hi_void hmac_rx_msdu_frame_classify(const hmac_vap_stru *hmac_vap, oal_netbuf_stru *netbuf,
599     mac_ieee80211_frame_stru *frame_hdr, hmac_msdu_stru *msdu, hmac_user_stru *hmac_user)
600 {
601     hi_u8 *mac_addr = HI_NULL;
602     hmac_rx_ctl_stru *rx_ctrl = (hmac_rx_ctl_stru *)oal_netbuf_cb(netbuf);
603 
604 #ifdef _PRE_WLAN_FEATURE_WAPI
605     hi_bool pairwise = !ether_is_multicast(frame_hdr->auc_address1);
606     hmac_wapi_stru *wapi = hmac_user_get_wapi_ptr(hmac_vap->base_vap, pairwise, hmac_user->base_user->us_assoc_id);
607 
608     if (wapi == HI_NULL) {
609         oam_warning_log0(0, OAM_SF_WPA, "{hmac_rx_lan_frame_classify:: get pst_wapi Err!.}");
610         return;
611     }
612 
613     if ((wapi_is_port_valid(wapi) == HI_TRUE) && (wapi->wapi_netbuff_rxhandle != HI_NULL)) {
614         netbuf = wapi->wapi_netbuff_rxhandle(wapi, netbuf);
615         if (netbuf == HI_NULL) {
616             oam_warning_log0(hmac_vap->base_vap->vap_id, OAM_SF_RX, "{hmac_rx_lan_frame_classify:WapiDecrypt Err}");
617             return;
618         }
619 
620         /* 重新获取该MPDU的控制信息 */
621         rx_ctrl = (hmac_rx_ctl_stru *)oal_netbuf_cb(netbuf);
622     }
623 #endif
624 
625     netbuf = hmac_defrag_process(hmac_user, netbuf, rx_ctrl->mac_header_len);
626     if (netbuf == HI_NULL) {
627         return;
628     }
629 
630     /* 打印出关键帧(dhcp)信息 */
631     hi_u8 datatype = mac_get_data_type_from_80211(netbuf, rx_ctrl->mac_header_len);
632     if (datatype <= MAC_DATA_VIP) {
633         oam_warning_log3(hmac_vap->base_vap->vap_id, OAM_SF_RX,
634             "{hmac_rx_lan_frame_classify:user=%d,type=%u,len=%u}[0~3dhcp 4arp_req 5arp_rsp 6eapol]",
635             rx_ctrl->us_ta_user_idx, datatype, rx_ctrl->us_frame_len);
636     }
637 
638     /* 对当前的msdu进行赋值 */
639     msdu->netbuf = netbuf;
640 
641     /* 将netbuf的data指针指向mac frame的payload处 */
642     oal_netbuf_pull(netbuf, rx_ctrl->mac_header_len);
643 
644     /* 获取源地址和目的地址 */
645     mac_rx_get_sa(frame_hdr, &mac_addr);
646     if (memcpy_s(msdu->auc_sa, WLAN_MAC_ADDR_LEN, mac_addr, WLAN_MAC_ADDR_LEN) != EOK) {
647         return;
648     }
649 
650     mac_rx_get_da(frame_hdr, &mac_addr);
651     if (memcpy_s(msdu->auc_da, WLAN_MAC_ADDR_LEN, mac_addr, WLAN_MAC_ADDR_LEN) != EOK) {
652         return;
653     }
654 
655     /* 将MSDU转发到LAN */
656     hmac_rx_transmit_msdu_to_lan(hmac_vap, msdu);
657 }
658 
659 /* ****************************************************************************
660  功能描述  : HMAC接收模块,WLAN到LAN的转发接口
661  输入参数  : (1)对应MPDU的第一个netbuf的指针
662              (2)对应的MPDU占用的netbuf的数目
663  返 回 值  : 成功或者失败原因
664  修改历史      :
665   1.日    期   : 2012年12月6日
666     作    者   : HiSilicon
667     修改内容   : 新生成函数
668 **************************************************************************** */
hmac_rx_lan_frame_classify(const hmac_vap_stru * hmac_vap,oal_netbuf_stru * netbuf,mac_ieee80211_frame_stru * frame_hdr)669 hi_u32 hmac_rx_lan_frame_classify(const hmac_vap_stru *hmac_vap, oal_netbuf_stru *netbuf,
670     mac_ieee80211_frame_stru *frame_hdr)
671 {
672     hmac_msdu_stru msdu = { 0 };                                    /* 保存解析出来的每一个MSDU */
673     hi_u8 *mac_addr = HI_NULL;
674 
675     if (oal_unlikely(frame_hdr == HI_NULL)) {
676         oam_error_log0(0, OAM_SF_RX, "{hmac_rx_lan_frame_classify::params null.}");
677         return HI_FAIL;
678     }
679 
680     /* 获取该MPDU的控制信息 */
681     hmac_rx_ctl_stru *rx_ctrl = (hmac_rx_ctl_stru *)oal_netbuf_cb(netbuf);
682 
683     mac_get_transmit_addr(frame_hdr, &mac_addr);
684     if (memcpy_s(msdu.auc_ta, WLAN_MAC_ADDR_LEN, mac_addr, WLAN_MAC_ADDR_LEN) != EOK) {
685         return HI_FAIL;
686     }
687 
688     hmac_user_stru *hmac_user = (hmac_user_stru *)hmac_user_get_user_stru(rx_ctrl->us_ta_user_idx);
689     if (oal_unlikely((hmac_user == HI_NULL) || (hmac_user->base_user == HI_NULL))) {
690         oam_error_log3(hmac_vap->base_vap->vap_id, OAM_SF_RX,
691             "{hmac_rx_lan_frame_classify::hmac_user null,user_idx=%d,net_buf ptr addr=%p,cb ptr addr=%p}",
692             rx_ctrl->us_ta_user_idx, (uintptr_t)netbuf, (uintptr_t)rx_ctrl);
693 
694         /* 打印此net buf相关信息 */
695         oam_error_log4(hmac_vap->base_vap->vap_id, OAM_SF_RX,
696             "{hmac_rx_lan_frame_classify:vap id=%d,mac_hdr_len=%d,frame_len=%d,mac_hdr_start_addr=%p}", rx_ctrl->vap_id,
697             rx_ctrl->mac_header_len, rx_ctrl->us_frame_len, (uintptr_t)rx_ctrl->pul_mac_hdr_start_addr);
698 
699         return HI_FAIL;
700     }
701 
702     hmac_ba_update_rx_bitmap(hmac_user, frame_hdr);
703 
704     /* 情况一:不是AMSDU聚合,则该MPDU对应一个MSDU,同时对应一个NETBUF */
705     if (rx_ctrl->amsdu_enable == HI_FALSE) {
706         hmac_rx_msdu_frame_classify(hmac_vap, netbuf, frame_hdr, &msdu, hmac_user);
707     } else { /* 情况二:AMSDU聚合 */
708         return HI_FAIL;
709     }
710     return HI_SUCCESS;
711 }
712 
713 /* ****************************************************************************
714  功能描述  : copy netbuff
715  修改历史      :
716   1.日    期   : 2015年1月3日
717     作    者   : HiSilicon
718     修改内容   : 新生成函数
719 **************************************************************************** */
hmac_rx_copy_netbuff(oal_netbuf_stru ** dest_netbuf,const oal_netbuf_stru * src_netbuf,hi_u8 vap_id,mac_ieee80211_frame_stru ** ppul_mac_hdr_start_addr)720 hi_u32 hmac_rx_copy_netbuff(oal_netbuf_stru **dest_netbuf, const oal_netbuf_stru *src_netbuf, hi_u8 vap_id,
721     mac_ieee80211_frame_stru **ppul_mac_hdr_start_addr)
722 {
723     hmac_rx_ctl_stru *rx_ctrl = HI_NULL;
724 
725     hi_unref_param(vap_id);
726     *dest_netbuf = oal_netbuf_alloc(WLAN_LARGE_NETBUF_SIZE, 0, 4); /* align 4 */
727     if (oal_unlikely(*dest_netbuf == HI_NULL)) {
728         oam_warning_log0(vap_id, OAM_SF_RX, "{hmac_rx_copy_netbuff::pst_netbuf_copy null.}");
729         return HI_ERR_CODE_ALLOC_MEM_FAIL;
730     }
731 
732     /* 信息复制 */
733     if (memcpy_s(oal_netbuf_cb(*dest_netbuf), oal_netbuf_cb_size(), oal_netbuf_cb(src_netbuf),
734         sizeof(hmac_rx_ctl_stru)) != EOK) {
735         oal_netbuf_free(*dest_netbuf);
736         oam_error_log0(0, OAM_SF_CFG, "hmac_rx_copy_netbuff:: pst_src_netbuf memcpy_s fail.");
737         return HI_FAIL;
738     }
739     if (memcpy_s(oal_netbuf_data(*dest_netbuf), oal_netbuf_tailroom(*dest_netbuf), oal_netbuf_data(src_netbuf),
740         oal_netbuf_len(src_netbuf)) != EOK) {
741         oal_netbuf_free(*dest_netbuf);
742         oam_error_log0(0, OAM_SF_CFG, "hmac_rx_copy_netbuff:: pst_src_netbuf memcpy_s fail.");
743         return HI_FAIL;
744     }
745     /* 设置netbuf长度、TAIL指针 */
746     oal_netbuf_put(*dest_netbuf, oal_netbuf_len(src_netbuf));
747     /* 调整MAC帧头的指针copy后,对应的mac header的头已经发生变化) */
748     rx_ctrl = (hmac_rx_ctl_stru *)oal_netbuf_cb(*dest_netbuf);
749     rx_ctrl->pul_mac_hdr_start_addr = (hi_u32 *)oal_netbuf_data(*dest_netbuf);
750     *ppul_mac_hdr_start_addr = (mac_ieee80211_frame_stru *)oal_netbuf_data(*dest_netbuf);
751 
752     return HI_SUCCESS;
753 }
754 
hmac_rx_netbuf_add_to_list_tail(oal_netbuf_head_stru * netbuf_header,hmac_rx_ctl_stru * rx_ctrl,hi_u32 ret,hi_u8 buf_nums,hi_u8 is_ba_buf)755 hi_void hmac_rx_netbuf_add_to_list_tail(oal_netbuf_head_stru *netbuf_header, hmac_rx_ctl_stru *rx_ctrl, hi_u32 ret,
756     hi_u8 buf_nums, hi_u8 is_ba_buf)
757 {
758     oal_netbuf_stru *netbuf = HI_NULL;
759     hi_u8 netbuf_num;
760 
761     hi_unref_param(rx_ctrl);
762 
763     if (ret != HI_SUCCESS) {
764         hmac_rx_free_netbuf_list(netbuf_header, buf_nums);
765         return;
766     }
767 
768     if (is_ba_buf == HI_TRUE) {
769         return;
770     }
771 
772     /* 如果不buff进reorder队列,则重新挂到链表尾,保序 */
773     for (netbuf_num = 0; netbuf_num < buf_nums; netbuf_num++) {
774         netbuf = oal_netbuf_delist(netbuf_header);
775         if (oal_likely(netbuf != HI_NULL)) {
776             oal_netbuf_add_to_list_tail(netbuf, netbuf_header);
777         } else {
778             oam_warning_log0(rx_ctrl->vap_id, OAM_SF_RX, "{hmac_rx_netbuf_add_to_list_tail::no buff error.}");
779         }
780     }
781 }
782 
783 /* ****************************************************************************
784  功能描述  :
785  修改历史      :
786   1.日    期   : 2015年1月3日
787     作    者   : HiSilicon
788     修改内容   : 新生成函数
789 **************************************************************************** */
hmac_rx_process_data_filter(oal_netbuf_head_stru * netbuf_header,oal_netbuf_stru * temp_netbuf,hi_u16 us_netbuf_num)790 hi_void hmac_rx_process_data_filter(oal_netbuf_head_stru *netbuf_header, oal_netbuf_stru *temp_netbuf,
791     hi_u16 us_netbuf_num)
792 {
793     hi_u8  buf_nums;
794     hi_u32 ret = HI_SUCCESS;
795 
796     while (us_netbuf_num != 0) {
797         hi_u8 is_ba_buf = HI_FALSE;
798         oal_netbuf_stru *netbuf = temp_netbuf;
799         if (netbuf == HI_NULL) {
800             oam_warning_log1(0, OAM_SF_RX, "{hmac_rx_process_data_filter::us_netbuf_num = %d}", us_netbuf_num);
801             break;
802         }
803 
804         hmac_rx_ctl_stru *rx_ctrl = (hmac_rx_ctl_stru *)oal_netbuf_cb(netbuf);
805         buf_nums = rx_ctrl->buff_nums;
806 
807         /* 获取下一个要处理的MPDU */
808         oal_netbuf_get_appointed_netbuf(netbuf, buf_nums, &temp_netbuf);
809         us_netbuf_num = hi_sub(us_netbuf_num, buf_nums);
810 #ifdef _PRE_WLAN_FEATURE_AMPDU
811         hmac_user_stru *hmac_user = (hmac_user_stru *)hmac_user_get_user_stru(rx_ctrl->us_ta_user_idx);
812         if (oal_unlikely((hmac_user == HI_NULL) || (hmac_user->base_user == HI_NULL) ||
813             (hmac_user->base_user->is_user_alloced != MAC_USER_ALLOCED))) {
814             hmac_rx_free_netbuf_list(netbuf_header, buf_nums);
815             oam_info_log0(rx_ctrl->vap_id, OAM_SF_RX, "{hmac_rx_process_data_filter::user null.}");
816             continue;
817         }
818         mac_ieee80211_frame_stru *frame_hdr = (mac_ieee80211_frame_stru *)rx_ctrl->pul_mac_hdr_start_addr;
819 #endif
820 
821         mac_vap_stru *mac_vap = mac_vap_get_vap_stru(rx_ctrl->mac_vap_id);
822         if (oal_unlikely(mac_vap == HI_NULL)) {
823             hmac_rx_free_netbuf_list(netbuf_header, buf_nums);
824             oam_warning_log0(rx_ctrl->vap_id, OAM_SF_RX, "{hmac_rx_process_data_filter::pst_vap null.}");
825             continue;
826         }
827 
828         if (mac_vap->vap_id == 0 || mac_vap->vap_id > WLAN_VAP_NUM_PER_DEVICE) {
829             oam_error_log1(0, OAM_SF_RX, "{hmac_rx_process_data_filter::Invalid vap_id.vap_id[%u]}", mac_vap->vap_id);
830             hmac_rx_free_netbuf_list(netbuf_header, buf_nums);
831             continue;
832         }
833 
834 #ifdef _PRE_WLAN_FEATURE_AMPDU
835         hmac_filter_serv_info_stru filter_serv_info;
836         filter_serv_info.netbuf_header = netbuf_header;
837         filter_serv_info.pen_is_ba_buf = &is_ba_buf;
838         ret = HI_SUCCESS;
839         if (rx_ctrl->amsdu_enable == HI_FALSE) {
840             ret = hmac_ba_filter_serv(mac_vap, hmac_user, rx_ctrl, frame_hdr, &filter_serv_info);
841         }
842 #endif
843 
844         hmac_rx_netbuf_add_to_list_tail(netbuf_header, rx_ctrl, ret, buf_nums, is_ba_buf);
845     }
846 }
847 
848 /* ****************************************************************************
849  功能描述  : 逐一处理需要上报的帧
850  修改历史      :
851   1.日    期   : 2015年1月3日
852     作    者   : HiSilicon
853     修改内容   : 新生成函数
854 **************************************************************************** */
hmac_rx_lan_frame(const oal_netbuf_head_stru * netbuf_header)855 hi_void hmac_rx_lan_frame(const oal_netbuf_head_stru *netbuf_header)
856 {
857     hi_u32 netbuf_num;
858     oal_netbuf_stru *temp_netbuf = HI_NULL;
859     oal_netbuf_stru *netbuf = HI_NULL;
860     hi_u8 buf_nums;
861     hmac_rx_ctl_stru *rx_ctrl = HI_NULL;
862     mac_ieee80211_frame_stru *frame_hdr = HI_NULL;
863     hmac_vap_stru *hmac_vap = HI_NULL;
864     hi_u32 err_code;
865 
866     netbuf_num = oal_netbuf_get_buf_num(netbuf_header);
867     temp_netbuf = oal_netbuf_peek(netbuf_header);
868 
869     while (netbuf_num != 0) {
870         netbuf = temp_netbuf;
871         if (netbuf == NULL) {
872             break;
873         }
874 
875         rx_ctrl = (hmac_rx_ctl_stru *)oal_netbuf_cb(netbuf);
876         frame_hdr = (mac_ieee80211_frame_stru *)rx_ctrl->pul_mac_hdr_start_addr;
877         buf_nums = rx_ctrl->buff_nums;
878 
879         netbuf_num = hi_sub(netbuf_num, buf_nums);
880         oal_netbuf_get_appointed_netbuf(netbuf, buf_nums, &temp_netbuf);
881 
882         hmac_vap = hmac_vap_get_vap_stru(rx_ctrl->mac_vap_id);
883         if (hmac_vap == HI_NULL) {
884             oam_error_log1(0, OAM_SF_RX, "{hmac_rx_lan_frame::hmac_vap_get_vap_stru null. vap_id:%u}",
885                 rx_ctrl->mac_vap_id);
886             continue;
887         }
888         rx_ctrl->us_da_user_idx = hmac_vap->base_vap->assoc_vap_id;
889 
890         err_code = hmac_rx_lan_frame_classify(hmac_vap, netbuf, frame_hdr);
891         if (err_code != HI_SUCCESS) {
892             hmac_rx_free_netbuf(netbuf, (hi_u16)buf_nums);
893         }
894     }
895 }
896 
hmac_rx_process_data_insert_list(hi_u16 us_netbuf_num,oal_netbuf_stru * temp_netbuf,oal_netbuf_head_stru * netbuf_header,const hmac_vap_stru * hmac_vap)897 static hi_void hmac_rx_process_data_insert_list(hi_u16 us_netbuf_num, oal_netbuf_stru *temp_netbuf,
898     oal_netbuf_head_stru *netbuf_header, const hmac_vap_stru *hmac_vap)
899 {
900     oal_netbuf_stru *netbuf = HI_NULL; /* 用于保存当前处理的MPDU的第一个netbuf指针 */
901 #ifdef _PRE_WLAN_FEATURE_PROMIS
902 #if (_PRE_OS_VERSION_LITEOS == _PRE_OS_VERSION)
903     hmac_rx_ctl_stru *rx_ctrl = HI_NULL;
904     hi_u8 bssid[WLAN_MAC_ADDR_LEN] = {0};
905     mac_ieee80211_frame_stru *mac_frame = HI_NULL;
906 #endif
907 #endif
908     while (us_netbuf_num != 0) {
909         netbuf = temp_netbuf;
910         if (netbuf == HI_NULL) {
911             break;
912         }
913         temp_netbuf = oal_netbuf_next(netbuf);
914 #ifdef _PRE_WLAN_FEATURE_PROMIS
915 #if (_PRE_OS_VERSION_LITEOS == _PRE_OS_VERSION)
916         mac_device_stru *mac_dev = mac_res_get_dev();
917         if (mac_dev->promis_switch) {
918             /* 处理上报的其他BSS组播数据包 */
919             hi_u32 ret = hwal_send_others_bss_data(netbuf);
920             if (ret != HI_SUCCESS) {
921                 oam_error_log1(0, OAM_SF_RX, "hwal_send_others_bss_data failed! ul_ret=%d", ret);
922             }
923             rx_ctrl = (hmac_rx_ctl_stru *)oal_netbuf_cb(netbuf);
924             if (rx_ctrl == HI_NULL) {
925                 oal_netbuf_free(netbuf);
926                 us_netbuf_num--;
927                 continue;
928             }
929             mac_frame = (mac_ieee80211_frame_stru *)rx_ctrl->pul_mac_hdr_start_addr;
930             mac_get_bssid((const hi_u8 *)mac_frame, (hi_u8 *)bssid, WLAN_MAC_ADDR_LEN);
931             if (memcmp(bssid, hmac_vap->base_vap->auc_bssid, WLAN_MAC_ADDR_LEN) != 0) {
932                 oal_netbuf_free(netbuf);
933                 us_netbuf_num--;
934                 continue;
935             }
936         }
937 #endif
938 #endif
939         oal_netbuf_add_to_list_tail(netbuf, netbuf_header);
940         us_netbuf_num--;
941     }
942     if (us_netbuf_num != 0) {
943         oam_error_log1(0, OAM_SF_RX, "{hmac_rx_process_data_insert_list::us_netbuf_num[%d].}", us_netbuf_num);
944     }
945 }
946 
947 /* ****************************************************************************
948  功能描述  : AP模式下,HMAC模块接收WLAN_DRX事件(数据帧)的处理函数
949  输入参数  : 事件结构体指针
950  返 回 值  : 成功或者失败原因
951  修改历史      :
952   1.日    期   : 2013年3月05日
953     作    者   : HiSilicon
954     修改内容   : 新生成函数
955 **************************************************************************** */
hmac_rx_process_data_ap(frw_event_mem_stru * event_mem)956 hi_u32 hmac_rx_process_data_ap(frw_event_mem_stru *event_mem)
957 {
958     if (event_mem == HI_NULL) {
959         oam_error_log0(0, OAM_SF_ANY, "{hmac_rx_process_data_ap::evenevent_memt is NULL!}\r\n");
960         return HI_ERR_CODE_PTR_NULL;
961     }
962     /* 获取事件头和事件结构体指针 */
963     frw_event_stru *event = (frw_event_stru *)event_mem->puc_data;
964     frw_event_hdr_stru *event_hdr = &(event->event_hdr);
965     dmac_wlan_drx_event_stru *wlan_rx_event = (dmac_wlan_drx_event_stru *)(event->auc_event_data);
966     /* 用于临时保存下一个需要处理的netbuf指针 */
967     oal_netbuf_stru *temp_netbuf = (oal_netbuf_stru *)wlan_rx_event->netbuf;
968     hi_u16 us_netbuf_num = wlan_rx_event->us_netbuf_num; /* netbuf链表的个数 */
969     oal_netbuf_head_stru netbuf_header;                  /* 存储上报给网络层的数据 */
970 
971     hmac_vap_stru *hmac_vap = hmac_vap_get_vap_stru(event_hdr->vap_id);
972     if (hmac_vap == HI_NULL || hmac_vap->base_vap == HI_NULL) {
973         oam_error_log0(0, OAM_SF_RX, "{hmac_rx_process_data_ap::hmac_vap/mac_vap null.}");
974         return HI_ERR_CODE_PTR_NULL;
975     }
976     /* 将所有netbuff全部入链表 */
977     oal_netbuf_list_head_init(&netbuf_header);
978     hmac_rx_process_data_insert_list(us_netbuf_num, temp_netbuf, &netbuf_header, hmac_vap);
979 
980     if (oal_netbuf_list_empty(&netbuf_header) == HI_TRUE) {
981         return HI_SUCCESS;
982     }
983 
984     /* 将Dmac上报的帧进入reorder队列过滤一下 */
985     hmac_rx_process_data_filter(&netbuf_header, (oal_netbuf_stru *)wlan_rx_event->netbuf, wlan_rx_event->us_netbuf_num);
986 
987 #ifdef _PRE_WLAN_FEATURE_MESH
988     if (hmac_vap->base_vap->vap_mode == WLAN_VAP_MODE_MESH) {
989         /* 将需要上报的帧逐一出队处理 */
990         hmac_rx_process_data_mesh_tcp_ack_opt(hmac_vap, &netbuf_header);
991     } else {
992         hmac_rx_process_data_ap_tcp_ack_opt(hmac_vap, &netbuf_header);
993     }
994 #else
995     hmac_rx_process_data_ap_tcp_ack_opt(hmac_vap, &netbuf_header);
996 #endif
997 
998     return HI_SUCCESS;
999 }
1000 
hmac_rx_process_no_multicast_proc(const hmac_vap_stru * hmac_vap,const hi_u8 * mac_addr,oal_netbuf_stru * netbuf,oal_netbuf_head_stru * w2w_netbuf_hdr)1001 hi_void hmac_rx_process_no_multicast_proc(const hmac_vap_stru *hmac_vap, const hi_u8 *mac_addr,
1002     oal_netbuf_stru *netbuf, oal_netbuf_head_stru *w2w_netbuf_hdr)
1003 {
1004     hi_u8 user_idx;
1005     hmac_rx_ctl_stru         *rx_ctrl   = (hmac_rx_ctl_stru *)oal_netbuf_cb(netbuf);
1006     mac_ieee80211_frame_stru *frame_hdr = (mac_ieee80211_frame_stru *)rx_ctrl->pul_mac_hdr_start_addr;
1007 
1008     /* 获取目的地址对应的用户指针 */
1009     hi_u32 rslt = mac_vap_find_user_by_macaddr(hmac_vap->base_vap, mac_addr, WLAN_MAC_ADDR_LEN, &user_idx);
1010     if (rslt == HI_ERR_CODE_PTR_NULL) { /* 查找用户失败 */
1011         oam_warning_log0(hmac_vap->base_vap->vap_id, OAM_SF_RX, "{hmac_rx_process_no_multicast_proc::get user Err}");
1012 
1013         /* 释放当前处理的MPDU占用的netbuf */
1014         hmac_rx_free_netbuf(netbuf, (hi_u16)rx_ctrl->buff_nums);
1015         return;
1016     }
1017 
1018     /* 没有找到对应的用户 */
1019     if (rslt != HI_SUCCESS) {
1020         /* 目的用户不在AP的用户表中,调用wlan_to_lan转发接口 */
1021         rslt = hmac_rx_lan_frame_classify(hmac_vap, netbuf, frame_hdr);
1022         if (rslt != HI_SUCCESS) {
1023             oam_warning_log1(rx_ctrl->vap_id, OAM_SF_RX, "hmac_rx_process_data_ap_tcp_ack_opt:: rx_lan_frame_fail[%d]",
1024                 rslt);
1025             hmac_rx_free_netbuf(netbuf, (hi_u16)rx_ctrl->buff_nums);
1026         }
1027         return;
1028     }
1029 
1030     /* 目的用户已在AP的用户表中,进行WLAN_TO_WLAN转发 */
1031     hmac_user_stru *hmac_user = (hmac_user_stru *)hmac_user_get_user_stru(user_idx);
1032     if ((hmac_user == HI_NULL) || (hmac_user->base_user == HI_NULL)) {
1033         oam_warning_log0(hmac_vap->base_vap->vap_id, OAM_SF_RX, "{hmac_rx_process_no_multicast_proc::hmac_user null}");
1034 
1035         hmac_rx_free_netbuf(netbuf, (hi_u16)rx_ctrl->buff_nums);
1036         return;
1037     }
1038 
1039     if (hmac_user->base_user->user_asoc_state != MAC_USER_STATE_ASSOC) {
1040         oam_warning_log0(hmac_vap->base_vap->vap_id, OAM_SF_RX,
1041             "{hmac_rx_process_no_multicast_proc::the station is not associated with ap.}");
1042 
1043         hmac_rx_free_netbuf(netbuf, (hi_u16)rx_ctrl->buff_nums);
1044         hmac_mgmt_send_deauth_frame(hmac_vap->base_vap, mac_addr, WLAN_MAC_ADDR_LEN, MAC_NOT_AUTHED);
1045         return;
1046     }
1047 
1048     /* 将目的地址的资源池索引值放到cb字段中,user的asoc id会在关联的时候被赋值 */
1049     rx_ctrl->us_da_user_idx = hmac_user->base_user->us_assoc_id;
1050 
1051     /* 将MPDU解析成单个MSDU,把所有的MSDU组成一个netbuf链 */
1052     if (hmac_rx_prepare_msdu_list_to_wlan(hmac_vap, w2w_netbuf_hdr, netbuf, frame_hdr) != HI_SUCCESS) {
1053         oam_warning_log0(hmac_vap->base_vap->vap_id, OAM_SF_RX, "hmac_rx_prepare_msdu_list_to_wlan return NON SUCCESS");
1054         hmac_rx_free_netbuf(netbuf, (hi_u16)rx_ctrl->buff_nums);
1055     }
1056 }
1057 
1058 /* ****************************************************************************
1059  功能描述  : AP模式下,HMAC模块接收WLAN_DRX事件(数据帧)的处理函数
1060  输入参数  : 事件结构体指针
1061  返 回 值  : 成功或者失败原因
1062  修改历史      :
1063   1.日    期   : 2013年3月5日
1064     作    者   : HiSilicon
1065     修改内容   : 新生成函数
1066 **************************************************************************** */
hmac_rx_process_data_ap_tcp_ack_opt(const hmac_vap_stru * hmac_vap,const oal_netbuf_head_stru * netbuf_header)1067 hi_void hmac_rx_process_data_ap_tcp_ack_opt(const hmac_vap_stru *hmac_vap, const oal_netbuf_head_stru *netbuf_header)
1068 {
1069     mac_ieee80211_frame_stru *copy_frame_hdr = HI_NULL; /* 保存mac帧的指针 */
1070     oal_netbuf_stru          *netbuf_copy = HI_NULL;    /* 用于保存组播帧copy */
1071     oal_netbuf_stru          *temp_netbuf = oal_netbuf_peek(netbuf_header);
1072     hi_u8                    *mac_addr = HI_NULL;       /* 保存用户目的地址的指针 */
1073     hi_u16 us_netbuf_num = (hi_u16)oal_netbuf_get_buf_num(netbuf_header);
1074     oal_netbuf_head_stru w2w_netbuf_hdr; /* 保存wlan to wlan的netbuf链表的头 */
1075     frw_event_hdr_stru   event_hdr;
1076 
1077     event_hdr.vap_id = hmac_vap->base_vap->vap_id;
1078     /* 循环收到的每一个MPDU,处情况如下:
1079        1、组播帧时,调用WLAN TO WLAN和WLAN TO LAN接口
1080        2、其他,根据实际情况,调用WLAN TO LAN接口或者WLAN TO WLAN接口 */
1081     oal_netbuf_list_head_init(&w2w_netbuf_hdr);
1082     while (us_netbuf_num != 0) {
1083         oal_netbuf_stru *netbuf = temp_netbuf;
1084         if (netbuf == HI_NULL) {
1085             break;
1086         }
1087         hmac_rx_ctl_stru *rx_ctrl = (hmac_rx_ctl_stru *)oal_netbuf_cb(netbuf);
1088         /* 获取帧头信息 */
1089         mac_ieee80211_frame_stru *frame_hdr = (mac_ieee80211_frame_stru *)rx_ctrl->pul_mac_hdr_start_addr;
1090         /* 获取下一个要处理的MPDU */
1091         oal_netbuf_get_appointed_netbuf(netbuf, rx_ctrl->buff_nums, &temp_netbuf);
1092         us_netbuf_num = hi_sub(us_netbuf_num, rx_ctrl->buff_nums);
1093         hmac_vap = hmac_vap_get_vap_stru(rx_ctrl->mac_vap_id);
1094         if (oal_unlikely(hmac_vap == HI_NULL)) {
1095             hmac_rx_free_netbuf(netbuf, (hi_u16)rx_ctrl->buff_nums);
1096             continue;
1097         }
1098 
1099         /* 获取接收端地址  */
1100         mac_rx_get_da(frame_hdr, &mac_addr);
1101         /* 单播报文处理 */
1102         if (ether_is_multicast(mac_addr) == HI_FALSE) {
1103             hmac_rx_process_no_multicast_proc(hmac_vap, mac_addr, netbuf, &w2w_netbuf_hdr);
1104             continue;
1105         }
1106         /* 目的地址为组播地址时,进行WLAN_TO_WLAN和WLAN_TO_LAN的转发 */
1107         if (hmac_rx_copy_netbuff(&netbuf_copy, netbuf, rx_ctrl->mac_vap_id, &copy_frame_hdr) == HI_SUCCESS) {
1108             /* 将MPDU解析成单个MSDU,把所有的MSDU组成一个netbuf链 */
1109             if (hmac_rx_prepare_msdu_list_to_wlan(hmac_vap, &w2w_netbuf_hdr, netbuf_copy, copy_frame_hdr) !=
1110                 HI_SUCCESS) {
1111                 oam_warning_log0(0, OAM_SF_RX, "hmac_rx_prepare_msdu_list_to_wlan return NON SUCCESS");
1112                 oal_netbuf_free(netbuf_copy);
1113             }
1114         }
1115         /* 上报网络层 WLAN_TO_LAN */
1116         hi_u32 err_code = hmac_rx_lan_frame_classify(hmac_vap, netbuf, frame_hdr);
1117         if (err_code != HI_SUCCESS) {
1118             hmac_rx_free_netbuf(netbuf, (hi_u16)rx_ctrl->buff_nums);
1119         }
1120     }
1121 
1122     /*  将MSDU链表交给发送流程处理 WLAN_TO_WLAN */
1123     if ((oal_netbuf_list_empty(&w2w_netbuf_hdr) == HI_FALSE) && (oal_netbuf_tail(&w2w_netbuf_hdr) != HI_NULL) &&
1124         (oal_netbuf_peek(&w2w_netbuf_hdr) != HI_NULL)) {
1125         set_oal_netbuf_next((oal_netbuf_tail(&w2w_netbuf_hdr)), HI_NULL);
1126         set_oal_netbuf_prev((oal_netbuf_peek(&w2w_netbuf_hdr)), HI_NULL);
1127 
1128         hmac_rx_transmit_to_wlan(&event_hdr, &w2w_netbuf_hdr);
1129     }
1130 }
1131 
1132 /* ****************************************************************************
1133  功能描述  : STA模式下,HMAC模块接收WLAN_DRX事件(数据帧)的处理函数
1134  输入参数  : 事件结构体指针
1135  返 回 值  : 成功或者失败原因
1136  修改历史      :
1137   1.日    期   : 2013年3月5日
1138     作    者   : HiSilicon
1139     修改内容   : 新生成函数
1140 ************************ **************************************************** */
hmac_rx_process_data_sta(frw_event_mem_stru * event_mem)1141 hi_u32 hmac_rx_process_data_sta(frw_event_mem_stru *event_mem)
1142 {
1143     hi_u16 us_netbuf_num;               /* netbuf链表的个数 */
1144     oal_netbuf_head_stru netbuf_header; /* 存储上报给网络层的数据 */
1145 
1146     if (oal_unlikely(event_mem == HI_NULL)) {
1147         oam_error_log0(0, OAM_SF_RX, "{hmac_rx_process_data_sta::event_mem null.}");
1148         return HI_ERR_CODE_PTR_NULL;
1149     }
1150 
1151     /* 获取事件头和事件结构体指针 */
1152     frw_event_stru *event = (frw_event_stru *)event_mem->puc_data;
1153     frw_event_hdr_stru *event_hdr = &(event->event_hdr);
1154     dmac_wlan_drx_event_stru *wlan_rx_event = (dmac_wlan_drx_event_stru *)(event->auc_event_data);
1155     oal_netbuf_stru *temp_netbuf = (oal_netbuf_stru *)wlan_rx_event->netbuf;
1156     us_netbuf_num = wlan_rx_event->us_netbuf_num;
1157 
1158     hmac_vap_stru *hmac_vap = hmac_vap_get_vap_stru(event_hdr->vap_id);
1159     if (hmac_vap == HI_NULL || hmac_vap->base_vap == HI_NULL) {
1160         oam_error_log0(0, OAM_SF_RX, "{hmac_rx_process_data_sta::hmac_vap/mac_vap null.}");
1161         hmac_rx_free_netbuf(temp_netbuf, us_netbuf_num);
1162         return HI_ERR_CODE_PTR_NULL;
1163     }
1164 #if (_PRE_MULTI_CORE_MODE_OFFLOAD_DMAC == _PRE_MULTI_CORE_MODE)
1165     /* If mib info is null ptr,release the netbuf */
1166     if (hmac_vap->base_vap->mib_info == NULL) {
1167         oam_warning_log0(0, OAM_SF_ANY, "{hmac_rx_process_data_sta::pst_mib_info null.}");
1168         hmac_rx_free_netbuf(temp_netbuf, us_netbuf_num);
1169         return HI_SUCCESS;
1170     }
1171 #endif
1172 
1173     /* 将所有netbuff全部入链表 */
1174     oal_netbuf_list_head_init(&netbuf_header);
1175     hmac_rx_process_data_insert_list(us_netbuf_num, temp_netbuf, &netbuf_header, hmac_vap);
1176 
1177     if (oal_netbuf_list_empty(&netbuf_header) == HI_TRUE) {
1178         return HI_SUCCESS;
1179     }
1180 
1181     hmac_rx_process_data_filter(&netbuf_header, (oal_netbuf_stru *)wlan_rx_event->netbuf, wlan_rx_event->us_netbuf_num);
1182     hmac_rx_lan_frame(&netbuf_header);
1183     return HI_SUCCESS;
1184 }
1185 
1186 #ifdef _PRE_WLAN_FEATURE_MESH
1187 /* ****************************************************************************
1188  功能描述  : mesh模式下,HMAC模块接收WLAN_DRX事件(数据帧)的处理函数
1189  输入参数  : 事件结构体指针
1190  返 回 值  : 成功或者失败原因
1191  修改历史      :
1192   1.日    期   : 2019年2月23日
1193     作    者   : HiSilicon
1194     修改内容   : 新生成函数
1195 **************************************************************************** */
hmac_rx_process_data_mesh_tcp_ack_opt(hmac_vap_stru * hmac_vap,const oal_netbuf_head_stru * netbuf_header)1196 hi_void hmac_rx_process_data_mesh_tcp_ack_opt(hmac_vap_stru *hmac_vap, const oal_netbuf_head_stru *netbuf_header)
1197 {
1198     mac_ieee80211_frame_stru *frame_hdr = HI_NULL;   /* 保存mac帧的指针 */
1199     hi_u8                    *da_mac_addr = HI_NULL;          /* 保存用户目的地址的指针 */
1200     hmac_rx_ctl_stru         *rx_ctrl = HI_NULL;     /* 每一个MPDU的控制信息 */
1201     hi_u16                    us_netbuf_num;             /* netbuf链表的个数 */
1202     hi_u8                     buf_nums;               /* 每个mpdu占有buf的个数 */
1203     oal_netbuf_stru          *netbuf = HI_NULL;      /* 用于保存当前处理的MPDU的第一个netbuf指针 */
1204     oal_netbuf_stru          *temp_netbuf = HI_NULL; /* 用于临时保存下一个需要处理的netbuf指针 */
1205     hi_u32                    err_code;
1206 
1207     temp_netbuf = oal_netbuf_peek(netbuf_header);
1208     us_netbuf_num = (hi_u16)oal_netbuf_get_buf_num(netbuf_header);
1209 
1210     while (us_netbuf_num != 0) {
1211         netbuf = temp_netbuf;
1212         if (netbuf == HI_NULL) {
1213             break;
1214         }
1215 
1216         rx_ctrl = (hmac_rx_ctl_stru *)oal_netbuf_cb(netbuf);
1217 
1218         /* 获取帧头信息 */
1219         frame_hdr = (mac_ieee80211_frame_stru *)rx_ctrl->pul_mac_hdr_start_addr;
1220 
1221         /* 获取当前MPDU占用的netbuf数目 */
1222         buf_nums = rx_ctrl->buff_nums;
1223 
1224         /* 获取下一个要处理的MPDU */
1225         oal_netbuf_get_appointed_netbuf(netbuf, buf_nums, &temp_netbuf);
1226         us_netbuf_num = hi_sub(us_netbuf_num, buf_nums);
1227 
1228         hmac_vap = hmac_vap_get_vap_stru(rx_ctrl->mac_vap_id);
1229         if (oal_unlikely(hmac_vap == HI_NULL)) {
1230             oam_warning_log0(rx_ctrl->vap_id, OAM_SF_RX, "{hmac_rx_process_data_mesh_tcp_ack_opt::pst_vap null.}");
1231             hmac_rx_free_netbuf(netbuf, (hi_u16)buf_nums);
1232             continue;
1233         }
1234         /* 获取接收端地址  */
1235         mac_rx_get_da(frame_hdr, &da_mac_addr);
1236 
1237         err_code = hmac_rx_lan_frame_classify(hmac_vap, netbuf, frame_hdr); /* 上报网络层 */
1238         if (err_code != HI_SUCCESS) {
1239             oam_warning_log1(rx_ctrl->vap_id, OAM_SF_RX,
1240                 "hmac_rx_process_data_ap_tcp_ack_opt:: rx_lan_frame_fail[%d]", err_code);
1241             hmac_rx_free_netbuf(netbuf, (hi_u16)buf_nums);
1242         }
1243     }
1244 
1245     return;
1246 }
1247 #endif
1248 
1249 #ifdef __cplusplus
1250 #if __cplusplus
1251 }
1252 #endif
1253 #endif
1254