• 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 "hmac_rx_filter.h"
23 #include "wlan_types.h"
24 #include "mac_device.h"
25 #include "dmac_ext_if.h"
26 #include "hcc_hmac_if.h"
27 #include "frw_event.h"
28 #include "hmac_ext_if.h"
29 
30 #ifdef __cplusplus
31 #if __cplusplus
32 extern "C" {
33 #endif
34 #endif
35 
36 /* ****************************************************************************
37   3 函数实现
38 **************************************************************************** */
39 /* ****************************************************************************
40  功能描述  : 查找是否有已经UP的STA
41  修改历史      :
42   1.日    期   : 2015年8月31日
43     作    者   : HiSilicon
44     修改内容   : 新生成函数
45 **************************************************************************** */
hmac_find_is_sta_up(const mac_device_stru * mac_dev)46 hi_u8 hmac_find_is_sta_up(const mac_device_stru *mac_dev)
47 {
48     mac_vap_stru *mac_vap = HI_NULL;
49     hi_u8 vap_idx;
50 
51     for (vap_idx = 0; vap_idx < mac_dev->vap_num; vap_idx++) {
52         mac_vap = mac_vap_get_vap_stru(mac_dev->auc_vap_id[vap_idx]);
53         if (mac_vap == HI_NULL) {
54             continue;
55         }
56         if ((mac_vap->vap_mode == WLAN_VAP_MODE_BSS_STA) && (mac_vap->vap_state == MAC_VAP_STATE_UP)) {
57             return HI_TRUE;
58         }
59     }
60     return HI_FALSE;
61 }
62 
63 /* ****************************************************************************
64  功能描述  : 查找是否有已经UP的AP
65  修改历史      :
66   1.日    期   : 2015年8月31日
67     作    者   : HiSilicon
68     修改内容   : 新生成函数
69 **************************************************************************** */
hmac_find_is_ap_up(const mac_device_stru * mac_dev)70 hi_u8 hmac_find_is_ap_up(const mac_device_stru *mac_dev)
71 {
72     mac_vap_stru *mac_vap = HI_NULL;
73     hi_u8 vap_idx;
74 
75     for (vap_idx = 0; vap_idx < mac_dev->vap_num; vap_idx++) {
76         mac_vap = mac_vap_get_vap_stru(mac_dev->auc_vap_id[vap_idx]);
77         if (mac_vap == HI_NULL) {
78             continue;
79         }
80         if ((mac_vap->vap_state != MAC_VAP_STATE_INIT) && (mac_vap->vap_mode == WLAN_VAP_MODE_BSS_AP)) {
81             return HI_TRUE;
82         }
83 #ifdef _PRE_WLAN_FEATURE_MESH
84         if ((mac_vap->vap_state != MAC_VAP_STATE_INIT) && (mac_vap->vap_mode == WLAN_VAP_MODE_MESH)) {
85             return HI_TRUE;
86         }
87 #endif
88     }
89     return HI_FALSE;
90 }
91 
92 
93 /* ****************************************************************************
94  功能描述  : 查找是否有已有AP
95 **************************************************************************** */
hmac_find_is_ap(const mac_device_stru * mac_device)96 hi_u8 hmac_find_is_ap(const mac_device_stru *mac_device)
97 {
98     mac_vap_stru *vap = HI_NULL;
99     hi_u8 vap_idx;
100 
101     for (vap_idx = 0; vap_idx < mac_device->vap_num; vap_idx++) {
102         vap = mac_vap_get_vap_stru(mac_device->auc_vap_id[vap_idx]);
103         if (vap == HI_NULL) {
104             continue;
105         }
106         if (vap->vap_mode == WLAN_VAP_MODE_BSS_AP) {
107             return HI_TRUE;
108         }
109 #ifdef _PRE_WLAN_FEATURE_MESH
110         if (vap->vap_mode == WLAN_VAP_MODE_MESH) {
111             return HI_TRUE;
112         }
113 #endif
114     }
115 
116     return HI_FALSE;
117 }
118 
119 /* ****************************************************************************
120  功能描述  : 计算不处于inti状态的VAP个数
121  修改历史      :
122   1.日    期   : 2014年7月14日
123     作    者   : HiSilicon
124     修改内容   : 新生成函数
125 **************************************************************************** */
hmac_calc_up_vap_num(const mac_device_stru * mac_dev)126 hi_u32 hmac_calc_up_vap_num(const mac_device_stru *mac_dev)
127 {
128     mac_vap_stru *mac_vap = HI_NULL;
129     hi_u8 vap_idx;
130     hi_u8 up_ap_num = 0;
131 
132     for (vap_idx = 0; vap_idx < mac_dev->vap_num; vap_idx++) {
133         mac_vap = mac_vap_get_vap_stru(mac_dev->auc_vap_id[vap_idx]);
134         if (mac_vap == HI_NULL) {
135             continue;
136         }
137 
138         if ((mac_vap->vap_state != MAC_VAP_STATE_INIT) && ((mac_vap->vap_mode == WLAN_VAP_MODE_BSS_AP)
139 #ifdef _PRE_WLAN_FEATURE_MESH
140             || (mac_vap->vap_mode == WLAN_VAP_MODE_MESH)
141 #endif
142             )) {
143             up_ap_num++;
144         } else if ((mac_vap->vap_mode == WLAN_VAP_MODE_BSS_STA) && (mac_vap->vap_state == MAC_VAP_STATE_UP)) {
145             up_ap_num++;
146         }
147     }
148 
149     return up_ap_num;
150 }
151 
152 /* ****************************************************************************
153  功能描述  : 单vap模式下根据模式和状态获取对应的接收过滤值
154  修改历史      :
155   1.日    期   : 2019年6月14日
156     作    者   : HiSilicon
157     修改内容   : 新生成函数
158  **************************************************************************** */
159 /* ********************************************* SINGLE VAP ******************************************************
160     WLAN_VAP_MODE_CONFIG  配置模式                        WLAN_VAP_MODE_BSS_STA              BSS STA模式
161   +-----------------------------+-----------------+      +----------------------------------+-----------------+
162   | FSM State                   | RX FILTER VALUE |      | FSM State                        | RX FILTER VALUE |
163   +-----------------------------+-----------------+      +----------------------------------+-----------------+
164   | All states                  | 0x37BDEEFA      |      | MAC_VAP_STATE_INIT               | 0x37BDEEFA      |
165   +-----------------------------+----- -----------+      | MAC_VAP_STATE_UP                 | 0x37BDEADA      |
166                                                          | MAC_VAP_STATE_STA_FAKE_UP        | 0x37BDEEFA      |
167    WLAN_VAP_MODE_BSS_AP             BSS AP模式           | MAC_VAP_STATE_STA_WAIT_SCAN      | 0x37BDCEEA      |
168   +-----------------------------+-----------------+      | MAC_VAP_STATE_STA_SCAN_COMP      | 0x37BDEEDA      |
169   | FSM State                   | RX FILTER VALUE |      | MAC_VAP_STATE_STA_WAIT_JOIN      | 0x37BDEEDA      |
170   +-----------------------------+-----------------+      | MAC_VAP_STATE_STA_JOIN_COMP      | 0x37BDEEDA      |
171   | MAC_VAP_STATE_INIT          | 0xF7B9EEFA      |      | MAC_VAP_STATE_STA_WAIT_AUTH_SEQ2 | 0x37BDEEDA      |
172   | MAC_VAP_STATE_UP            | 0x73B9EAEA      |      | MAC_VAP_STATE_STA_WAIT_AUTH_SEQ4 | 0x37BDEEDA      |
173   | MAC_VAP_STATE_PAUSE         | 0x73B9EAEA      |      | MAC_VAP_STATE_STA_AUTH_COMP      | 0x37BDEEDA      |
174   | MAC_VAP_STATE_AP_WAIT_START | 0x73B9EAEA      |      | MAC_VAP_STATE_STA_WAIT_ASOC      | 0x37BDEEDA      |
175   +-----------------------------+-----------------+      | MAC_VAP_STATE_STA_OBSS_SCAN      | 0x37BDCEEA      |
176                                                          | MAC_VAP_STATE_STA_BG_SCAN        | 0x37BDCEEA      |
177    WLAN_VAP_MODE_MONITOER           侦听模式             | MAC_VAP_STATE_STA_LISTEN         | 0x33A9EECA      |
178   +-----------------------------+-----------------+      +----------------------------------+-----------------+
179   | FSM State                   | RX FILTER VALUE |
180   +-----------------------------+-----------------+
181   | all status                  | 0x1             |
182   +-----------------------------+-----------------+
183 *********************************************** MULTI  VAP **************************************************** */
hmac_get_single_vap_rx_filter(const mac_vap_stru * mac_vap)184 hi_u32 hmac_get_single_vap_rx_filter(const mac_vap_stru *mac_vap)
185 {
186     hi_u32 def_value = (BIT0 << 21); /* 默认开启FCS ERROR过滤 21: 左移21位 */
187 
188     if (mac_vap->vap_mode == WLAN_VAP_MODE_CONFIG) {
189         return 0x37B9FEFA; /* 配置vap均使用0x37B9FEFA */
190     } else if (mac_vap->vap_mode == WLAN_VAP_MODE_BSS_STA) {
191         switch (mac_vap->vap_state) { /* STA各状态下的过滤寄存器设置 */
192             case MAC_VAP_STATE_INIT:
193             case MAC_VAP_STATE_STA_FAKE_UP:
194                 return 0xF7B9FEFA;
195             case MAC_VAP_STATE_STA_WAIT_SCAN:
196                 return 0x37B9DECA;
197             case MAC_VAP_STATE_STA_OBSS_SCAN:
198             case MAC_VAP_STATE_STA_BG_SCAN:
199                 return 0x37B9DEEA;
200             case MAC_VAP_STATE_STA_LISTEN:
201                 return 0x33A9FECA;
202             default:
203                 return 0x73B9FADA;
204         }
205     } else if (is_ap(mac_vap)) {
206         switch (mac_vap->vap_state) { /* AP以及MESH AP各状态下的过滤寄存器设置 */
207             case MAC_VAP_STATE_INIT:
208                 return 0xF7B9FEFA;
209             case MAC_VAP_STATE_UP:
210                 return 0xF7B9FAEA;
211             case MAC_VAP_STATE_PAUSE:
212             case MAC_VAP_STATE_AP_WAIT_START:
213                 return 0x73B9FAEA;
214             default: /* AP下异常状态返回默认值 */
215                 return def_value;
216         }
217     } else if (mac_vap->vap_mode == WLAN_VAP_MODE_MONITOER) {
218         return def_value | BIT0; /* 混杂模式需要置BIT0 和FCS ERROR */
219     } else {
220         return def_value; /* 其他模式下均返回默认值 */
221     }
222 }
223 
224 /* ****************************************************************************
225  功能描述  : 存在已经UP的STA,当前的vap模式为AP/MESH时,根据其状态获取对应的接收过滤值
226        WLAN_VAP_MODE_BSS_AP/MESH               BSS AP模式              BSS MESH模式
227      +----------------------------------+--------------------------+--------------------------+
228      | FSM State                        | RX FILTER VALUE          | RX FILTER VALUE          |
229      +----------------------------------+--------------------------+--------------------------+
230      | MAC_VAP_STATE_INIT               | 保持原有值不配置         | 保持原有值不配置         |
231      | MAC_VAP_STATE_UP                 | 0x73B9EACA               | 0x73B9EADA               |
232      | MAC_VAP_STATE_PAUSE              | 0x73B9EACA               | 0x73B9EADA               |
233      | MAC_VAP_STATE_AP_WAIT_START      | 0x73B9EACA               | 0x73B9EADA               |
234      +----------------------------------+--------------------------+--------------------------+
235  修改历史      :
236   1.日    期   : 2019年6月14日
237     作    者   : HiSilicon
238     修改内容   : 新生成函数
239 **************************************************************************** */
hmac_get_staup_ap_rx_filter(const mac_vap_stru * mac_vap)240 hi_u32 hmac_get_staup_ap_rx_filter(const mac_vap_stru *mac_vap)
241 {
242     switch (mac_vap->vap_state) {
243         case MAC_VAP_STATE_INIT:
244             return 0;
245         default:
246             return 0x73B9FACA;
247     }
248 }
249 
250 /* ****************************************************************************
251  功能描述  : 存在已经UP的STA,当前的vap模式为STA时,根据其状态获取对应的接收过滤值
252     /  多STA模式    WLAN_VAP_MODE_BSS_STA          BSS STA模式        /
253     / +----------------------------------+--------------------------+ /
254     / | FSM State                        | RX FILTER VALUE          | /
255     / +----------------------------------+--------------------------+ /
256     / | MAC_VAP_STATE_STA_WAIT_SCAN      | 0x33B9CACA               | /
257     / | MAC_VAP_STATE_STA_OBSS_SCAN      | 0x33B9CACA               | /
258     / | MAC_VAP_STATE_STA_BG_SCAN        | 0x33B9CACA               | /
259     / | MAC_VAP_STATE_STA_LISTEN         | 0x33A9EACA               | /
260     / | ALL OTHER STATE                  | 0x73B9EADA               | /
261     / +----------------------------------+--------------------------+ /
262  修改历史:
263   1.日    期   : 2019年6月14日
264     作    者   : HiSilicon
265     修改内容   : 新生成函数
266 **************************************************************************** */
hmac_get_staup_sta_rx_filter(const mac_vap_stru * mac_vap)267 hi_u32 hmac_get_staup_sta_rx_filter(const mac_vap_stru *mac_vap)
268 {
269     switch (mac_vap->vap_state) {
270         case MAC_VAP_STATE_STA_WAIT_SCAN:
271         case MAC_VAP_STATE_STA_OBSS_SCAN:
272         case MAC_VAP_STATE_STA_BG_SCAN:
273             return 0x33B9DACA;
274         case MAC_VAP_STATE_STA_LISTEN:
275             return 0x33A9FACA;
276         default:
277             return 0x73B9FADA;
278     }
279 }
280 
281 /* ****************************************************************************
282  功能描述  : 存在已经UP的AP,当前的vap模式为STA时,根据其状态获取对应的接收过滤值
283     / 多AP UP时,STA配置场景:  WLAN_VAP_MODE_BSS_STA   BSS STA模式     /
284     / +----------------------------------+--------------------------+ /
285     / | FSM State                        | RX FILTER VALUE          | /
286     / +----------------------------------+--------------------------+ /
287     / | MAC_VAP_STATE_INIT               | 保持原有值不配置         | /
288     / | MAC_VAP_STATE_UP                 | 0x73B9FACA               | /
289     / | MAC_VAP_STATE_STA_FAKE_UP        | 保持原有值不配置         | /
290     / | MAC_VAP_STATE_STA_WAIT_SCAN      | 0x33B9CACA               | /
291     / | MAC_VAP_STATE_STA_SCAN_COMP      | 0x73B9FACA               | /
292     / | MAC_VAP_STATE_STA_WAIT_JOIN      | 0x73B9FACA               | /
293     / | MAC_VAP_STATE_STA_JOIN_COMP      | 0x73B9FACA               | /
294     / | MAC_VAP_STATE_STA_WAIT_AUTH_SEQ2 | 0x73B9FACA               | /
295     / | MAC_VAP_STATE_STA_WAIT_AUTH_SEQ4 | 0x73B9FACA               | /
296     / | MAC_VAP_STATE_STA_AUTH_COMP      | 0x73B9FACA               | /
297     / | MAC_VAP_STATE_STA_WAIT_ASOC      | 0x73B9FACA               | /
298     / | MAC_VAP_STATE_STA_OBSS_SCAN      | 0x33B9CACA               | /
299     / | MAC_VAP_STATE_STA_BG_SCAN        | 0x33B9CACA               | /
300     / | MAC_VAP_STATE_STA_LISTEN         | 0x33A9EACA               | /
301     / +----------------------------------+--------------------------+ /
302  修改历史:
303   1.日    期   : 2019年6月14日
304     作    者   : HiSilicon
305     修改内容   : 新生成函数
306 **************************************************************************** */
hmac_get_apup_sta_rx_filter(const mac_vap_stru * mac_vap)307 hi_u32 hmac_get_apup_sta_rx_filter(const mac_vap_stru *mac_vap)
308 {
309     switch (mac_vap->vap_state) {
310         case MAC_VAP_STATE_STA_WAIT_SCAN:
311         case MAC_VAP_STATE_STA_OBSS_SCAN:
312         case MAC_VAP_STATE_STA_BG_SCAN:
313             return 0x33B9DACA;
314         case MAC_VAP_STATE_STA_LISTEN:
315             return 0x33A9FACA;
316         case MAC_VAP_STATE_INIT:
317         case MAC_VAP_STATE_STA_FAKE_UP:
318             return 0;
319         default:
320             return 0x73B9FACA;
321     }
322 }
323 
324 #ifndef _PRE_WLAN_PHY_PERFORMANCE
hmac_send_rx_filter_event(const mac_vap_stru * mac_vap,hi_u32 rx_filter_val)325 hi_u32 hmac_send_rx_filter_event(const mac_vap_stru *mac_vap, hi_u32 rx_filter_val)
326 {
327     hmac_vap_stru *hmac_vap = hmac_vap_get_vap_stru(mac_vap->vap_id);
328     if (hmac_vap == HI_NULL) {
329         oam_error_log0(0, OAM_SF_ANY, "{hmac_set_rx_filter_value::hmac_vap is null}");
330         return HI_ERR_CODE_PTR_NULL;
331     }
332 
333     if ((hmac_vap->hmac_al_rx_flag == HI_TRUE) && (hmac_vap->mac_filter_flag == HI_FALSE)) {
334         /* 常收关闭过滤 */
335         rx_filter_val |= (BIT0);
336     }
337 
338 #if (_PRE_OS_VERSION_LITEOS == _PRE_OS_VERSION)
339 #ifdef _PRE_WLAN_FEATURE_PROMIS
340     if (mac_res_get_dev()->promis_switch) {
341         hi_u32 filter = hwal_get_promis_filter();
342         if ((filter & 0x1) == HI_TRUE) { /* bit 0 :上报组播(广播)数据帧使能标志 */
343             rx_filter_val = rx_filter_val & (~BIT3) & (~BIT12);
344         }
345         if (((filter >> 1) & 0x1) == HI_TRUE) { /* bit 1 :上报单播数据包使能标志 */
346             rx_filter_val = rx_filter_val & (~BIT11);
347         }
348         if (((filter >> 2) & 0x1) == HI_TRUE) { /* bit 2 :上报组播(广播)管理帧使能标志 */
349             rx_filter_val = rx_filter_val & (~BIT4);
350         }
351         if (((filter >> 3) & 0x1) == HI_TRUE) { /* bit 3 :上报单播管理帧使能标志 */
352             rx_filter_val = rx_filter_val & (~BIT13);
353         }
354     }
355 #endif
356 #endif
357 
358     /* 抛事件到DMAC, 申请事件内存 */
359     frw_event_mem_stru *event_mem = frw_event_alloc(sizeof(hi_u32));
360     if (event_mem == HI_NULL) {
361         oam_error_log0(0, OAM_SF_ANY, "{hmac_set_rx_filter_value::event_mem null.}");
362         return HI_ERR_CODE_PTR_NULL;
363     }
364 
365     /* 填写事件 */
366     frw_event_stru *event = (frw_event_stru *)event_mem->puc_data;
367     frw_event_hdr_init(&(event->event_hdr), FRW_EVENT_TYPE_WLAN_CTX, DMAC_WLAN_CTX_EVENT_SUB_TYPE_SET_RX_FILTER,
368         sizeof(hi_u32), FRW_EVENT_PIPELINE_STAGE_1, mac_vap->vap_id);
369     /* 拷贝参数 */
370     hi_u32 *event_data = (hi_u32 *)((hi_void *)event->auc_event_data);
371     *event_data = rx_filter_val;
372 
373     if (hcc_hmac_tx_control_event(event_mem, sizeof(hi_u32)) != HI_SUCCESS) {
374         frw_event_free(event_mem);
375         return HI_FAIL;
376     }
377 
378     frw_event_free(event_mem);
379 
380     return HI_SUCCESS;
381 }
382 #endif
383 
384 /* ****************************************************************************
385  功能描述  : AP侧接收到对应STA的关联请求消息
386              待修订为dmac_set_rx_filter_value
387  修改历史      :
388   1.日    期   : 2014年4月16日
389     作    者   : HiSilicon
390     修改内容   : 新生成函数
391 **************************************************************************** */
hmac_set_rx_filter_value(const mac_vap_stru * mac_vap)392 hi_u32 hmac_set_rx_filter_value(const mac_vap_stru *mac_vap)
393 {
394 #ifndef _PRE_WLAN_PHY_PERFORMANCE
395     hi_u32           rx_filter_val;
396     mac_device_stru *mac_dev = mac_res_get_dev();
397 
398     if (mac_vap == HI_NULL) {
399         oam_error_log0(0, OAM_SF_ANY, "{hmac_set_rx_filter_value::pst_mac_vap null.}");
400         return HI_ERR_CODE_PTR_NULL;
401     }
402 
403     if (mac_vap->vap_state == MAC_VAP_STATE_PAUSE) {
404         return HI_SUCCESS;
405     }
406 
407     if (hmac_find_is_ap_up(mac_dev) == HI_TRUE) { /* 多VAP模式,AP已经UP */
408         if ((mac_vap->vap_state == MAC_VAP_STATE_INIT) || (mac_vap->vap_state == MAC_VAP_STATE_STA_FAKE_UP)) {
409             return HI_SUCCESS;
410         }
411 
412         /* 多VAP模式,STA配置(在STA已经up和没有STA up的情况下,配置AP模式都使用该配置) */
413         /* 已有AP UP,再起AP时使用单vap配置值 */
414         rx_filter_val = (!is_ap(mac_vap)) ? hmac_get_apup_sta_rx_filter(mac_vap) :
415             ((hmac_find_is_sta_up(mac_dev) && mac_vap->vap_state < MAC_VAP_AP_STATE_BUTT) ?
416             hmac_get_staup_ap_rx_filter(mac_vap) : hmac_get_single_vap_rx_filter(mac_vap));
417     } else if (hmac_find_is_sta_up(mac_dev) == HI_TRUE) {   /* 多VAP模式,STA已经UP */
418         /* 多VAP模式,STA配置(在STA已经up和没有STA up的情况下,配置AP模式都使用该配置) */
419         if ((mac_vap->vap_state == MAC_VAP_STATE_INIT) || (mac_vap->vap_state == MAC_VAP_STATE_STA_FAKE_UP)) {
420             return HI_SUCCESS;
421         }
422 
423         /* STA已经UP的状态下,STA的配置 */
424         if (mac_vap->vap_mode == WLAN_VAP_MODE_BSS_STA) {
425             rx_filter_val = hmac_get_staup_sta_rx_filter(mac_vap);
426         } else if (is_ap(mac_vap)) {
427             rx_filter_val = hmac_get_staup_ap_rx_filter(mac_vap);
428         } else {
429             return HI_SUCCESS;
430         }
431     } else {
432         /* 没有任何设备处于UP状态,即单VAP存在 */
433         rx_filter_val = hmac_get_single_vap_rx_filter(mac_vap);
434     }
435 
436     /* 支持ANY的设备(STA & AP等)需要能够收到来自其他BSS的广播管理帧,尤其是probe req, 这里设置不过滤,清零BIT4 */
437     rx_filter_val = (mac_vap->support_any == HI_TRUE) ? (rx_filter_val & (~BIT4)) : rx_filter_val;
438 
439     /* 过滤值为0时 表示维持原有值不变 不需要配置 */
440     if (rx_filter_val == 0) {
441         return HI_SUCCESS;
442     }
443 
444     hi_u32 ret = hmac_send_rx_filter_event(mac_vap, rx_filter_val);
445     if (ret != HI_SUCCESS) {
446         return ret;
447     }
448 
449 #endif /* #ifndef _PRE_WLAN_PHY_PERFORMANCE */
450 
451     return HI_SUCCESS;
452 }
453 
454 #ifdef __cplusplus
455 #if __cplusplus
456 }
457 #endif
458 #endif
459