1 // SPDX-License-Identifier: GPL-2.0
2 #include "coreconfigurator.h"
3 #include "wilc_wlan_if.h"
5 #include <linux/errno.h>
6 #include <linux/slab.h>
7 #define TAG_PARAM_OFFSET (MAC_HDR_LEN + TIME_STAMP_LEN + \
8 BEACON_INTERVAL_LEN + CAP_INFO_LEN)
10 enum basic_frame_type
{
11 FRAME_TYPE_CONTROL
= 0x04,
12 FRAME_TYPE_DATA
= 0x08,
13 FRAME_TYPE_MANAGEMENT
= 0x00,
14 FRAME_TYPE_RESERVED
= 0x0C,
15 FRAME_TYPE_FORCE_32BIT
= 0xFFFFFFFF
48 QOS_DATA_POLL_ACK
= 0xB8,
49 QOS_NULL_FRAME
= 0xC8,
51 QOS_CFPOLL_ACK
= 0xF8,
54 FRAME_SUBTYPE_FORCE_32BIT
= 0xFFFFFFFF
57 enum info_element_id
{
58 ISSID
= 0, /* Service Set Identifier */
59 ISUPRATES
= 1, /* Supported Rates */
60 IFHPARMS
= 2, /* FH parameter set */
61 IDSPARMS
= 3, /* DS parameter set */
62 ICFPARMS
= 4, /* CF parameter set */
63 ITIM
= 5, /* Traffic Information Map */
64 IIBPARMS
= 6, /* IBSS parameter set */
65 ICOUNTRY
= 7, /* Country element */
66 IEDCAPARAMS
= 12, /* EDCA parameter set */
67 ITSPEC
= 13, /* Traffic Specification */
68 ITCLAS
= 14, /* Traffic Classification */
69 ISCHED
= 15, /* Schedule */
70 ICTEXT
= 16, /* Challenge Text */
71 IPOWERCONSTRAINT
= 32, /* Power Constraint */
72 IPOWERCAPABILITY
= 33, /* Power Capability */
73 ITPCREQUEST
= 34, /* TPC Request */
74 ITPCREPORT
= 35, /* TPC Report */
75 ISUPCHANNEL
= 36, /* Supported channel list */
76 ICHSWANNOUNC
= 37, /* Channel Switch Announcement */
77 IMEASUREMENTREQUEST
= 38, /* Measurement request */
78 IMEASUREMENTREPORT
= 39, /* Measurement report */
79 IQUIET
= 40, /* Quiet element Info */
80 IIBSSDFS
= 41, /* IBSS DFS */
81 IERPINFO
= 42, /* ERP Information */
82 ITSDELAY
= 43, /* TS Delay */
83 ITCLASPROCESS
= 44, /* TCLAS Processing */
84 IHTCAP
= 45, /* HT Capabilities */
85 IQOSCAP
= 46, /* QoS Capability */
86 IRSNELEMENT
= 48, /* RSN Information Element */
87 IEXSUPRATES
= 50, /* Extended Supported Rates */
88 IEXCHSWANNOUNC
= 60, /* Extended Ch Switch Announcement*/
89 IHTOPERATION
= 61, /* HT Information */
90 ISECCHOFF
= 62, /* Secondary Channel Offeset */
91 I2040COEX
= 72, /* 20/40 Coexistence IE */
92 I2040INTOLCHREPORT
= 73, /* 20/40 Intolerant channel report*/
93 IOBSSSCAN
= 74, /* OBSS Scan parameters */
94 IEXTCAP
= 127, /* Extended capability */
95 IWMM
= 221, /* WMM parameters */
96 IWPAELEMENT
= 221, /* WPA Information Element */
97 INFOELEM_ID_FORCE_32BIT
= 0xFFFFFFFF
100 static inline u16
get_beacon_period(u8
*data
)
105 bcn_per
|= (data
[1] << 8);
110 static inline u32
get_beacon_timestamp_lo(u8
*data
)
113 u32 index
= MAC_HDR_LEN
;
115 time_stamp
|= data
[index
++];
116 time_stamp
|= (data
[index
++] << 8);
117 time_stamp
|= (data
[index
++] << 16);
118 time_stamp
|= (data
[index
] << 24);
123 static inline u32
get_beacon_timestamp_hi(u8
*data
)
126 u32 index
= (MAC_HDR_LEN
+ 4);
128 time_stamp
|= data
[index
++];
129 time_stamp
|= (data
[index
++] << 8);
130 time_stamp
|= (data
[index
++] << 16);
131 time_stamp
|= (data
[index
] << 24);
136 static inline enum sub_frame_type
get_sub_type(u8
*header
)
138 return ((enum sub_frame_type
)(header
[0] & 0xFC));
141 static inline u8
get_to_ds(u8
*header
)
143 return (header
[1] & 0x01);
146 static inline u8
get_from_ds(u8
*header
)
148 return ((header
[1] & 0x02) >> 1);
151 static inline void get_address1(u8
*pu8msa
, u8
*addr
)
153 memcpy(addr
, pu8msa
+ 4, 6);
156 static inline void get_address2(u8
*pu8msa
, u8
*addr
)
158 memcpy(addr
, pu8msa
+ 10, 6);
161 static inline void get_address3(u8
*pu8msa
, u8
*addr
)
163 memcpy(addr
, pu8msa
+ 16, 6);
166 static inline void get_BSSID(u8
*data
, u8
*bssid
)
168 if (get_from_ds(data
) == 1)
169 get_address2(data
, bssid
);
170 else if (get_to_ds(data
) == 1)
171 get_address1(data
, bssid
);
173 get_address3(data
, bssid
);
176 static inline void get_ssid(u8
*data
, u8
*ssid
, u8
*p_ssid_len
)
182 len
= data
[TAG_PARAM_OFFSET
+ 1];
183 j
= TAG_PARAM_OFFSET
+ 2;
185 if (len
>= MAX_SSID_LEN
)
188 for (i
= 0; i
< len
; i
++, j
++)
196 static inline u16
get_cap_info(u8
*data
)
199 u16 index
= MAC_HDR_LEN
;
200 enum sub_frame_type st
;
202 st
= get_sub_type(data
);
204 if ((st
== BEACON
) || (st
== PROBE_RSP
))
205 index
+= TIME_STAMP_LEN
+ BEACON_INTERVAL_LEN
;
207 cap_info
= data
[index
];
208 cap_info
|= (data
[index
+ 1] << 8);
213 static inline u16
get_assoc_resp_cap_info(u8
*data
)
218 cap_info
|= (data
[1] << 8);
223 static inline u16
get_asoc_status(u8
*data
)
227 asoc_status
= data
[3];
228 return (asoc_status
<< 8) | data
[2];
231 static inline u16
get_asoc_id(u8
*data
)
236 asoc_id
|= (data
[5] << 8);
241 static u8
*get_tim_elm(u8
*pu8msa
, u16 rx_len
, u16 tag_param_offset
)
245 index
= tag_param_offset
;
247 while (index
< (rx_len
- FCS_LEN
)) {
248 if (pu8msa
[index
] == ITIM
)
249 return &pu8msa
[index
];
250 index
+= (IE_HDR_LEN
+ pu8msa
[index
+ 1]);
256 static u8
get_current_channel_802_11n(u8
*pu8msa
, u16 rx_len
)
260 index
= TAG_PARAM_OFFSET
;
261 while (index
< (rx_len
- FCS_LEN
)) {
262 if (pu8msa
[index
] == IDSPARMS
)
263 return pu8msa
[index
+ 2];
264 index
+= pu8msa
[index
+ 1] + IE_HDR_LEN
;
270 s32
wilc_parse_network_info(u8
*msg_buffer
,
271 struct network_info
**ret_network_info
)
273 struct network_info
*network_info
= NULL
;
278 u16 wid_id
= (u16
)WID_NIL
;
282 msg_type
= msg_buffer
[0];
287 msg_id
= msg_buffer
[1];
288 msg_len
= MAKE_WORD16(msg_buffer
[2], msg_buffer
[3]);
289 wid_id
= MAKE_WORD16(msg_buffer
[4], msg_buffer
[5]);
290 wid_len
= MAKE_WORD16(msg_buffer
[6], msg_buffer
[7]);
291 wid_val
= &msg_buffer
[8];
303 network_info
= kzalloc(sizeof(*network_info
), GFP_KERNEL
);
307 network_info
->rssi
= wid_val
[0];
311 rx_len
= wid_len
- 1;
312 network_info
->cap_info
= get_cap_info(msa
);
313 network_info
->tsf_lo
= get_beacon_timestamp_lo(msa
);
315 tsf_lo
= get_beacon_timestamp_lo(msa
);
316 tsf_hi
= get_beacon_timestamp_hi(msa
);
318 network_info
->tsf_hi
= tsf_lo
| ((u64
)tsf_hi
<< 32);
320 get_ssid(msa
, network_info
->ssid
, &network_info
->ssid_len
);
321 get_BSSID(msa
, network_info
->bssid
);
323 network_info
->ch
= get_current_channel_802_11n(msa
,
326 index
= MAC_HDR_LEN
+ TIME_STAMP_LEN
;
328 network_info
->beacon_period
= get_beacon_period(msa
+ index
);
330 index
+= BEACON_INTERVAL_LEN
+ CAP_INFO_LEN
;
332 tim_elm
= get_tim_elm(msa
, rx_len
+ FCS_LEN
, index
);
334 network_info
->dtim_period
= tim_elm
[3];
335 ies
= &msa
[TAG_PARAM_OFFSET
];
336 ies_len
= rx_len
- TAG_PARAM_OFFSET
;
339 network_info
->ies
= kmemdup(ies
, ies_len
, GFP_KERNEL
);
340 if (!network_info
->ies
) {
345 network_info
->ies_len
= ies_len
;
348 *ret_network_info
= network_info
;
353 s32
wilc_parse_assoc_resp_info(u8
*buffer
, u32 buffer_len
,
354 struct connect_resp_info
**ret_connect_resp_info
)
356 struct connect_resp_info
*connect_resp_info
= NULL
;
357 u16 assoc_resp_len
= 0;
361 connect_resp_info
= kzalloc(sizeof(*connect_resp_info
), GFP_KERNEL
);
362 if (!connect_resp_info
)
365 assoc_resp_len
= (u16
)buffer_len
;
367 connect_resp_info
->status
= get_asoc_status(buffer
);
368 if (connect_resp_info
->status
== SUCCESSFUL_STATUSCODE
) {
369 connect_resp_info
->capability
= get_assoc_resp_cap_info(buffer
);
370 connect_resp_info
->assoc_id
= get_asoc_id(buffer
);
372 ies
= &buffer
[CAP_INFO_LEN
+ STATUS_CODE_LEN
+ AID_LEN
];
373 ies_len
= assoc_resp_len
- (CAP_INFO_LEN
+ STATUS_CODE_LEN
+
376 connect_resp_info
->ies
= kmemdup(ies
, ies_len
, GFP_KERNEL
);
377 if (!connect_resp_info
->ies
) {
378 kfree(connect_resp_info
);
382 connect_resp_info
->ies_len
= ies_len
;
385 *ret_connect_resp_info
= connect_resp_info
;