Commit | Line | Data |
---|---|---|
c5c77ba1 | 1 | #include "coreconfigurator.h" |
dd322576 | 2 | #include "wilc_wlan_if.h" |
1028e5a4 | 3 | #include "wilc_wlan.h" |
24db713f | 4 | #include <linux/errno.h> |
e215a871 | 5 | #include <linux/slab.h> |
c5c77ba1 | 6 | #define TAG_PARAM_OFFSET (MAC_HDR_LEN + TIME_STAMP_LEN + \ |
e0990c15 | 7 | BEACON_INTERVAL_LEN + CAP_INFO_LEN) |
c5c77ba1 | 8 | |
9dd2f771 | 9 | enum basic_frame_type { |
13994d1e SK |
10 | FRAME_TYPE_CONTROL = 0x04, |
11 | FRAME_TYPE_DATA = 0x08, | |
12 | FRAME_TYPE_MANAGEMENT = 0x00, | |
13 | FRAME_TYPE_RESERVED = 0x0C, | |
14 | FRAME_TYPE_FORCE_32BIT = 0xFFFFFFFF | |
9dd2f771 | 15 | }; |
c5c77ba1 | 16 | |
9dd2f771 | 17 | enum sub_frame_type { |
c5c77ba1 JK |
18 | ASSOC_REQ = 0x00, |
19 | ASSOC_RSP = 0x10, | |
20 | REASSOC_REQ = 0x20, | |
21 | REASSOC_RSP = 0x30, | |
22 | PROBE_REQ = 0x40, | |
23 | PROBE_RSP = 0x50, | |
24 | BEACON = 0x80, | |
25 | ATIM = 0x90, | |
26 | DISASOC = 0xA0, | |
27 | AUTH = 0xB0, | |
28 | DEAUTH = 0xC0, | |
29 | ACTION = 0xD0, | |
30 | PS_POLL = 0xA4, | |
31 | RTS = 0xB4, | |
32 | CTS = 0xC4, | |
33 | ACK = 0xD4, | |
34 | CFEND = 0xE4, | |
35 | CFEND_ACK = 0xF4, | |
36 | DATA = 0x08, | |
37 | DATA_ACK = 0x18, | |
38 | DATA_POLL = 0x28, | |
39 | DATA_POLL_ACK = 0x38, | |
40 | NULL_FRAME = 0x48, | |
41 | CFACK = 0x58, | |
42 | CFPOLL = 0x68, | |
43 | CFPOLL_ACK = 0x78, | |
44 | QOS_DATA = 0x88, | |
45 | QOS_DATA_ACK = 0x98, | |
46 | QOS_DATA_POLL = 0xA8, | |
47 | QOS_DATA_POLL_ACK = 0xB8, | |
48 | QOS_NULL_FRAME = 0xC8, | |
49 | QOS_CFPOLL = 0xE8, | |
50 | QOS_CFPOLL_ACK = 0xF8, | |
51 | BLOCKACK_REQ = 0x84, | |
52 | BLOCKACK = 0x94, | |
53 | FRAME_SUBTYPE_FORCE_32BIT = 0xFFFFFFFF | |
9dd2f771 | 54 | }; |
c5c77ba1 | 55 | |
9dd2f771 | 56 | enum info_element_id { |
c5c77ba1 JK |
57 | ISSID = 0, /* Service Set Identifier */ |
58 | ISUPRATES = 1, /* Supported Rates */ | |
59 | IFHPARMS = 2, /* FH parameter set */ | |
60 | IDSPARMS = 3, /* DS parameter set */ | |
61 | ICFPARMS = 4, /* CF parameter set */ | |
62 | ITIM = 5, /* Traffic Information Map */ | |
63 | IIBPARMS = 6, /* IBSS parameter set */ | |
64 | ICOUNTRY = 7, /* Country element */ | |
65 | IEDCAPARAMS = 12, /* EDCA parameter set */ | |
66 | ITSPEC = 13, /* Traffic Specification */ | |
67 | ITCLAS = 14, /* Traffic Classification */ | |
68 | ISCHED = 15, /* Schedule */ | |
69 | ICTEXT = 16, /* Challenge Text */ | |
70 | IPOWERCONSTRAINT = 32, /* Power Constraint */ | |
71 | IPOWERCAPABILITY = 33, /* Power Capability */ | |
72 | ITPCREQUEST = 34, /* TPC Request */ | |
73 | ITPCREPORT = 35, /* TPC Report */ | |
74 | ISUPCHANNEL = 36, /* Supported channel list */ | |
75 | ICHSWANNOUNC = 37, /* Channel Switch Announcement */ | |
76 | IMEASUREMENTREQUEST = 38, /* Measurement request */ | |
77 | IMEASUREMENTREPORT = 39, /* Measurement report */ | |
78 | IQUIET = 40, /* Quiet element Info */ | |
79 | IIBSSDFS = 41, /* IBSS DFS */ | |
80 | IERPINFO = 42, /* ERP Information */ | |
81 | ITSDELAY = 43, /* TS Delay */ | |
82 | ITCLASPROCESS = 44, /* TCLAS Processing */ | |
83 | IHTCAP = 45, /* HT Capabilities */ | |
84 | IQOSCAP = 46, /* QoS Capability */ | |
85 | IRSNELEMENT = 48, /* RSN Information Element */ | |
86 | IEXSUPRATES = 50, /* Extended Supported Rates */ | |
87 | IEXCHSWANNOUNC = 60, /* Extended Ch Switch Announcement*/ | |
88 | IHTOPERATION = 61, /* HT Information */ | |
89 | ISECCHOFF = 62, /* Secondary Channel Offeset */ | |
90 | I2040COEX = 72, /* 20/40 Coexistence IE */ | |
91 | I2040INTOLCHREPORT = 73, /* 20/40 Intolerant channel report*/ | |
92 | IOBSSSCAN = 74, /* OBSS Scan parameters */ | |
93 | IEXTCAP = 127, /* Extended capability */ | |
94 | IWMM = 221, /* WMM parameters */ | |
95 | IWPAELEMENT = 221, /* WPA Information Element */ | |
96 | INFOELEM_ID_FORCE_32BIT = 0xFFFFFFFF | |
9dd2f771 | 97 | }; |
c5c77ba1 | 98 | |
9af382bc | 99 | static inline u16 get_beacon_period(u8 *data) |
c5c77ba1 | 100 | { |
b5c84cd8 | 101 | u16 bcn_per; |
c5c77ba1 JK |
102 | |
103 | bcn_per = data[0]; | |
104 | bcn_per |= (data[1] << 8); | |
105 | ||
106 | return bcn_per; | |
107 | } | |
108 | ||
9af382bc | 109 | static inline u32 get_beacon_timestamp_lo(u8 *data) |
c5c77ba1 | 110 | { |
4e4467fd CL |
111 | u32 time_stamp = 0; |
112 | u32 index = MAC_HDR_LEN; | |
c5c77ba1 JK |
113 | |
114 | time_stamp |= data[index++]; | |
115 | time_stamp |= (data[index++] << 8); | |
116 | time_stamp |= (data[index++] << 16); | |
117 | time_stamp |= (data[index] << 24); | |
118 | ||
119 | return time_stamp; | |
120 | } | |
121 | ||
9af382bc | 122 | static inline u32 get_beacon_timestamp_hi(u8 *data) |
c5c77ba1 | 123 | { |
8a54d917 CL |
124 | u32 time_stamp = 0; |
125 | u32 index = (MAC_HDR_LEN + 4); | |
c5c77ba1 JK |
126 | |
127 | time_stamp |= data[index++]; | |
128 | time_stamp |= (data[index++] << 8); | |
129 | time_stamp |= (data[index++] << 16); | |
130 | time_stamp |= (data[index] << 24); | |
131 | ||
132 | return time_stamp; | |
133 | } | |
134 | ||
9dd2f771 | 135 | static inline enum sub_frame_type get_sub_type(u8 *header) |
c5c77ba1 | 136 | { |
9dd2f771 | 137 | return ((enum sub_frame_type)(header[0] & 0xFC)); |
c5c77ba1 JK |
138 | } |
139 | ||
9af382bc | 140 | static inline u8 get_to_ds(u8 *header) |
c5c77ba1 JK |
141 | { |
142 | return (header[1] & 0x01); | |
143 | } | |
144 | ||
9af382bc | 145 | static inline u8 get_from_ds(u8 *header) |
c5c77ba1 JK |
146 | { |
147 | return ((header[1] & 0x02) >> 1); | |
148 | } | |
149 | ||
b57f9f34 GL |
150 | static inline void get_address1(u8 *pu8msa, u8 *addr) |
151 | { | |
152 | memcpy(addr, pu8msa + 4, 6); | |
153 | } | |
154 | ||
b57f9f34 GL |
155 | static inline void get_address2(u8 *pu8msa, u8 *addr) |
156 | { | |
157 | memcpy(addr, pu8msa + 10, 6); | |
158 | } | |
159 | ||
b57f9f34 GL |
160 | static inline void get_address3(u8 *pu8msa, u8 *addr) |
161 | { | |
162 | memcpy(addr, pu8msa + 16, 6); | |
163 | } | |
164 | ||
9af382bc | 165 | static inline void get_BSSID(u8 *data, u8 *bssid) |
c5c77ba1 JK |
166 | { |
167 | if (get_from_ds(data) == 1) | |
b57f9f34 | 168 | get_address2(data, bssid); |
c5c77ba1 | 169 | else if (get_to_ds(data) == 1) |
b57f9f34 | 170 | get_address1(data, bssid); |
c5c77ba1 | 171 | else |
b57f9f34 | 172 | get_address3(data, bssid); |
c5c77ba1 JK |
173 | } |
174 | ||
9af382bc | 175 | static inline void get_ssid(u8 *data, u8 *ssid, u8 *p_ssid_len) |
c5c77ba1 | 176 | { |
63d03e47 GKH |
177 | u8 len = 0; |
178 | u8 i = 0; | |
179 | u8 j = 0; | |
c5c77ba1 | 180 | |
7902451c CL |
181 | len = data[TAG_PARAM_OFFSET + 1]; |
182 | j = TAG_PARAM_OFFSET + 2; | |
c5c77ba1 | 183 | |
c5c77ba1 JK |
184 | if (len >= MAX_SSID_LEN) |
185 | len = 0; | |
186 | ||
187 | for (i = 0; i < len; i++, j++) | |
188 | ssid[i] = data[j]; | |
189 | ||
190 | ssid[len] = '\0'; | |
191 | ||
192 | *p_ssid_len = len; | |
193 | } | |
194 | ||
9af382bc | 195 | static inline u16 get_cap_info(u8 *data) |
c5c77ba1 | 196 | { |
d85f5326 CL |
197 | u16 cap_info = 0; |
198 | u16 index = MAC_HDR_LEN; | |
9dd2f771 | 199 | enum sub_frame_type st; |
c5c77ba1 JK |
200 | |
201 | st = get_sub_type(data); | |
202 | ||
c5c77ba1 JK |
203 | if ((st == BEACON) || (st == PROBE_RSP)) |
204 | index += TIME_STAMP_LEN + BEACON_INTERVAL_LEN; | |
205 | ||
206 | cap_info = data[index]; | |
207 | cap_info |= (data[index + 1] << 8); | |
208 | ||
209 | return cap_info; | |
210 | } | |
211 | ||
9af382bc | 212 | static inline u16 get_assoc_resp_cap_info(u8 *data) |
c5c77ba1 | 213 | { |
b5c84cd8 | 214 | u16 cap_info; |
c5c77ba1 JK |
215 | |
216 | cap_info = data[0]; | |
217 | cap_info |= (data[1] << 8); | |
218 | ||
219 | return cap_info; | |
220 | } | |
221 | ||
9af382bc | 222 | static inline u16 get_asoc_status(u8 *data) |
c5c77ba1 | 223 | { |
b5c84cd8 | 224 | u16 asoc_status; |
c5c77ba1 JK |
225 | |
226 | asoc_status = data[3]; | |
3b438f2c | 227 | return (asoc_status << 8) | data[2]; |
c5c77ba1 JK |
228 | } |
229 | ||
9af382bc | 230 | static inline u16 get_asoc_id(u8 *data) |
c5c77ba1 | 231 | { |
b5c84cd8 | 232 | u16 asoc_id; |
c5c77ba1 JK |
233 | |
234 | asoc_id = data[4]; | |
235 | asoc_id |= (data[5] << 8); | |
236 | ||
237 | return asoc_id; | |
238 | } | |
239 | ||
6c25d7cb | 240 | static u8 *get_tim_elm(u8 *pu8msa, u16 rx_len, u16 tag_param_offset) |
c5c77ba1 | 241 | { |
c8a06381 | 242 | u16 index; |
c5c77ba1 | 243 | |
c8a06381 | 244 | index = tag_param_offset; |
c5c77ba1 | 245 | |
c8a06381 LK |
246 | while (index < (rx_len - FCS_LEN)) { |
247 | if (pu8msa[index] == ITIM) | |
248 | return &pu8msa[index]; | |
249 | index += (IE_HDR_LEN + pu8msa[index + 1]); | |
c5c77ba1 JK |
250 | } |
251 | ||
0e04f3f3 | 252 | return NULL; |
c5c77ba1 JK |
253 | } |
254 | ||
e1a9db87 | 255 | static u8 get_current_channel_802_11n(u8 *pu8msa, u16 rx_len) |
c5c77ba1 | 256 | { |
d85f5326 | 257 | u16 index; |
c5c77ba1 JK |
258 | |
259 | index = TAG_PARAM_OFFSET; | |
e1a9db87 | 260 | while (index < (rx_len - FCS_LEN)) { |
c5c77ba1 | 261 | if (pu8msa[index] == IDSPARMS) |
cea3b202 | 262 | return pu8msa[index + 2]; |
86e4180e | 263 | index += pu8msa[index + 1] + IE_HDR_LEN; |
c5c77ba1 JK |
264 | } |
265 | ||
43b36e42 | 266 | return 0; |
c5c77ba1 JK |
267 | } |
268 | ||
6b5180a0 LK |
269 | s32 wilc_parse_network_info(u8 *msg_buffer, |
270 | struct network_info **ret_network_info) | |
c5c77ba1 | 271 | { |
6b5180a0 | 272 | struct network_info *network_info = NULL; |
5fd5e1e1 LK |
273 | u8 msg_type = 0; |
274 | u8 msg_id = 0; | |
275 | u16 msg_len = 0; | |
c5c77ba1 | 276 | |
5fd5e1e1 LK |
277 | u16 wid_id = (u16)WID_NIL; |
278 | u16 wid_len = 0; | |
279 | u8 *wid_val = NULL; | |
c5c77ba1 | 280 | |
5fd5e1e1 | 281 | msg_type = msg_buffer[0]; |
c5c77ba1 | 282 | |
3b9d7dca | 283 | if ('N' != msg_type) |
24db713f | 284 | return -EFAULT; |
c5c77ba1 | 285 | |
5fd5e1e1 LK |
286 | msg_id = msg_buffer[1]; |
287 | msg_len = MAKE_WORD16(msg_buffer[2], msg_buffer[3]); | |
288 | wid_id = MAKE_WORD16(msg_buffer[4], msg_buffer[5]); | |
289 | wid_len = MAKE_WORD16(msg_buffer[6], msg_buffer[7]); | |
290 | wid_val = &msg_buffer[8]; | |
c5c77ba1 | 291 | |
c5c77ba1 | 292 | { |
e509681d | 293 | u8 *msa = NULL; |
e1a9db87 | 294 | u16 rx_len = 0; |
e509681d LK |
295 | u8 *tim_elm = NULL; |
296 | u8 *ies = NULL; | |
297 | u16 ies_len = 0; | |
298 | u8 index = 0; | |
299 | u32 tsf_lo; | |
300 | u32 tsf_hi; | |
c5c77ba1 | 301 | |
6b5180a0 | 302 | network_info = kzalloc(sizeof(*network_info), GFP_KERNEL); |
5fd5e1e1 | 303 | if (!network_info) |
a78d9a38 CL |
304 | return -ENOMEM; |
305 | ||
5c23a291 | 306 | network_info->rssi = wid_val[0]; |
c5c77ba1 | 307 | |
e509681d | 308 | msa = &wid_val[1]; |
c5c77ba1 | 309 | |
5fd5e1e1 | 310 | rx_len = wid_len - 1; |
fa5e2d15 | 311 | network_info->cap_info = get_cap_info(msa); |
afb70653 | 312 | network_info->tsf_lo = get_beacon_timestamp_lo(msa); |
c5c77ba1 | 313 | |
e509681d LK |
314 | tsf_lo = get_beacon_timestamp_lo(msa); |
315 | tsf_hi = get_beacon_timestamp_hi(msa); | |
c5c77ba1 | 316 | |
17d2f2b3 | 317 | network_info->tsf_hi = tsf_lo | ((u64)tsf_hi << 32); |
c5c77ba1 | 318 | |
a36e89e9 | 319 | get_ssid(msa, network_info->ssid, &network_info->ssid_len); |
38d3bb78 | 320 | get_BSSID(msa, network_info->bssid); |
c5c77ba1 | 321 | |
405a8c78 | 322 | network_info->ch = get_current_channel_802_11n(msa, |
e1a9db87 | 323 | rx_len + FCS_LEN); |
c5c77ba1 | 324 | |
e509681d | 325 | index = MAC_HDR_LEN + TIME_STAMP_LEN; |
c5c77ba1 | 326 | |
4b313e91 | 327 | network_info->beacon_period = get_beacon_period(msa + index); |
c5c77ba1 | 328 | |
e509681d | 329 | index += BEACON_INTERVAL_LEN + CAP_INFO_LEN; |
c5c77ba1 | 330 | |
e509681d LK |
331 | tim_elm = get_tim_elm(msa, rx_len + FCS_LEN, index); |
332 | if (tim_elm) | |
df340fdf | 333 | network_info->dtim_period = tim_elm[3]; |
7902451c CL |
334 | ies = &msa[TAG_PARAM_OFFSET]; |
335 | ies_len = rx_len - TAG_PARAM_OFFSET; | |
c5c77ba1 | 336 | |
e509681d | 337 | if (ies_len > 0) { |
390b6db0 | 338 | network_info->ies = kmemdup(ies, ies_len, GFP_KERNEL); |
f54e994c CIK |
339 | if (!network_info->ies) { |
340 | kfree(network_info); | |
a78d9a38 | 341 | return -ENOMEM; |
f54e994c | 342 | } |
c5c77ba1 | 343 | } |
390b6db0 | 344 | network_info->ies_len = ies_len; |
c5c77ba1 JK |
345 | } |
346 | ||
5fd5e1e1 | 347 | *ret_network_info = network_info; |
c5c77ba1 | 348 | |
74a443e0 | 349 | return 0; |
c5c77ba1 JK |
350 | } |
351 | ||
946a9ddb | 352 | s32 wilc_parse_assoc_resp_info(u8 *buffer, u32 buffer_len, |
40d96e1d | 353 | struct connect_resp_info **ret_connect_resp_info) |
c5c77ba1 | 354 | { |
40d96e1d | 355 | struct connect_resp_info *connect_resp_info = NULL; |
ebd7a9b0 LK |
356 | u16 assoc_resp_len = 0; |
357 | u8 *ies = NULL; | |
358 | u16 ies_len = 0; | |
c5c77ba1 | 359 | |
40d96e1d | 360 | connect_resp_info = kzalloc(sizeof(*connect_resp_info), GFP_KERNEL); |
ebd7a9b0 | 361 | if (!connect_resp_info) |
a78d9a38 CL |
362 | return -ENOMEM; |
363 | ||
ebd7a9b0 | 364 | assoc_resp_len = (u16)buffer_len; |
c5c77ba1 | 365 | |
ba7b6ff5 LK |
366 | connect_resp_info->status = get_asoc_status(buffer); |
367 | if (connect_resp_info->status == SUCCESSFUL_STATUSCODE) { | |
368 | connect_resp_info->capability = get_assoc_resp_cap_info(buffer); | |
369 | connect_resp_info->assoc_id = get_asoc_id(buffer); | |
c5c77ba1 | 370 | |
ebd7a9b0 | 371 | ies = &buffer[CAP_INFO_LEN + STATUS_CODE_LEN + AID_LEN]; |
e0990c15 LK |
372 | ies_len = assoc_resp_len - (CAP_INFO_LEN + STATUS_CODE_LEN + |
373 | AID_LEN); | |
c5c77ba1 | 374 | |
ba7b6ff5 | 375 | connect_resp_info->ies = kmemdup(ies, ies_len, GFP_KERNEL); |
f54e994c CIK |
376 | if (!connect_resp_info->ies) { |
377 | kfree(connect_resp_info); | |
a78d9a38 | 378 | return -ENOMEM; |
f54e994c | 379 | } |
a78d9a38 | 380 | |
ba7b6ff5 | 381 | connect_resp_info->ies_len = ies_len; |
c5c77ba1 JK |
382 | } |
383 | ||
ebd7a9b0 | 384 | *ret_connect_resp_info = connect_resp_info; |
c5c77ba1 | 385 | |
66d77cb5 | 386 | return 0; |
c5c77ba1 | 387 | } |