1 /*
2 * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3 */
4
5 #include "wifi_provision_internal.h"
6 #ifdef AWSS_SUPPORT_HT40
7
8 #if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
9 extern "C" {
10 #endif
11
12 /* Variable
13 * Qos: 2Byte
14 * auth offset: 36 44 52 56
15 * group frame: 4e0 3e1~3e7
16 */
17 uint8_t ht40_hint_frame_cnt[64];
18 uint8_t ht40_filter;
19 signed char ht40_rssi_low, ht40_rssi_high;
20 #define ht40_rssi_range (15) /* suggested by Fuzhibo */
21 /* for ios: start frame interval is 20/100 ms */
22 #define HIT_FRAME_PER_CHANNEL (2)
23
24 #define IEEE80211_MIN_HDRLEN (24)
25
26 uint32_t ht40_timestamp;
27 uint8_t ht40_channel[ZC_MAX_CHANNEL + 1];
28 uint8_t ht40_channel_filter[ZC_MAX_CHANNEL + 1];
29 uint8_t ht40_state;
30
ht40_init(void)31 int ht40_init(void)
32 {
33 ht40_state = 0;
34 ht40_filter = 0;
35 ht40_rssi_low = 0;
36 ht40_rssi_high = 0;
37 ht40_timestamp = 0;
38 memset(ht40_channel, 0, sizeof(ht40_channel));
39 memset(ht40_channel_filter, 0, sizeof(ht40_channel_filter));
40 memset(ht40_hint_frame_cnt, 0, sizeof(ht40_hint_frame_cnt));
41 return 0;
42 }
43
ht40_lock_channel(uint8_t channel,uint8_t filter)44 int ht40_lock_channel(uint8_t channel, uint8_t filter)
45 {
46 if (channel < 1 || channel > 14)
47 return 0;
48
49 if (!ht40_channel[channel]) {
50 ht40_channel[channel]++;
51 ht40_channel_filter[channel] = filter;
52 } else if (filter == ht40_channel_filter[channel]) {
53 ht40_channel[channel]++; /* increase */
54 } else {
55 ht40_channel[channel]--; /* decrease */
56 }
57
58 if (ht40_channel[channel] >= HIT_FRAME_PER_CHANNEL)
59 return 1;
60
61 return 0;
62 }
63
ht40_scanning_hint_frame(uint8_t filter,signed char rssi,uint32_t length,uint8_t channel)64 int ht40_scanning_hint_frame(uint8_t filter, signed char rssi, uint32_t length,
65 uint8_t channel)
66 {
67 uint8_t channel_locked = 0, next_loop = 0;
68 int hint_pos = -1;
69 int tods = 1;
70 int i, j, k;
71
72 if (ht40_state != STATE_CHN_SCANNING)
73 return -1;
74
75 /* range check, max: 0x4e0 + tkip + qos, min: 0x3e0 + open */
76 if (length > START_FRAME + zconfig_fixed_offset[2][0] + 2 ||
77 length <= GROUP_FRAME + zconfig_fixed_offset[0][0]) {
78 return -1;
79 }
80
81 for (i = 1; i >= 0; i--)
82 for (j = 3; j >= 0; j--)
83 for (k = 0; k < 8; k++) {
84 if (zconfig_hint_frame[k] + zconfig_fixed_offset[j][0] +
85 i * 2 ==
86 length) {
87 hint_pos = i * 32 + j * 8 + k;
88 awss_trace(
89 "\r\nfilter:%x, rssi:%d, len:%d, Qos:%d, auth:%d, "
90 "group:%d, %s\r\n",
91 filter, rssi, length, i, j, k, next_loop ? "DUP" : "");
92 if (!next_loop) {
93 channel_locked = ht40_lock_channel(channel, filter);
94 if (channel_locked)
95 zconfig_set_state(STATE_CHN_LOCKED_BY_BR, tods,
96 channel);
97 next_loop = 1; /* don't enter this loop again */
98 }
99
100 ht40_hint_frame_cnt[hint_pos]++;
101 }
102 }
103
104 if (channel_locked) {
105 ht40_rssi_high = rssi + ht40_rssi_range;
106 if (ht40_rssi_high > -1)
107 ht40_rssi_high = -1;
108 ht40_rssi_low = rssi - ht40_rssi_range;
109 if (ht40_rssi_low < -128)
110 ht40_rssi_low = -128;
111
112 ht40_filter = filter;
113
114 awss_trace("filter:%x, rssi range:[%d, %d]\r\n", filter, ht40_rssi_low,
115 ht40_rssi_high);
116 }
117
118 return hint_pos;
119 }
120
ht40_get_qos_auth_group_info(uint32_t length)121 int ht40_get_qos_auth_group_info(uint32_t length)
122 {
123 int count = 0, max_count = 0, max_count_pos = 0;
124 int continues = 0, max_continues = 0, max_continues_pos = 0,
125 second_continues = 0;
126 int tods = 1;
127 int i, j, k;
128
129 if (zc_state != STATE_CHN_LOCKED_BY_BR ||
130 ht40_state != STATE_CHN_SCANNING) {
131 return 0;
132 }
133
134 for (i = 1; i >= 0; i--)
135 for (j = 3; j >= 0; j--)
136 for (count = 0, continues = 0, k = 0; k < 8; k++) {
137 int pos = i * 32 + j * 8 + k;
138
139 if (ht40_hint_frame_cnt[pos]) {
140 count += ht40_hint_frame_cnt[pos];
141 if (count > max_count) {
142 max_count = count;
143 max_count_pos = pos;
144 }
145
146 continues += 1;
147 if (continues >= max_continues) {
148 second_continues = max_continues;
149 max_continues = continues;
150 max_continues_pos = pos;
151 }
152 }
153 }
154
155 awss_debug(
156 "max_cont:%d, sec_cont:%d, max_count:%d, max_cont_pos:%d, "
157 "max_count_pos:%d\r\n",
158 max_continues, second_continues, max_count, max_count_pos,
159 max_continues_pos);
160
161 if (max_continues > second_continues
162 && max_count_pos == max_continues_pos) {
163 uint8_t qos = max_count_pos / 32;
164 uint8_t auth = (max_count_pos % 32) / 8;
165
166 zc_frame_offset = zconfig_fixed_offset[auth][0] + qos * 2;
167 length -= zc_frame_offset;
168 if (is_start_frame(length) || is_group_frame(length)) {
169 uint8_t group = get_group_index(length);
170
171 zc_group_pos = group;
172 zc_cur_pos = group;
173 zc_score_uplimit = score_mid;
174 ht40_timestamp = os_get_time_ms();
175
176 ht40_state = STATE_RCV_IN_PROGRESS;
177 awss_debug("len:%d, qos:%d, auth:%d, group:%d, offset:%d\r\n",
178 length, qos, auth, group, zc_frame_offset);
179 }
180 }
181
182 return 0;
183 }
184
awss_ieee80211_ht_ctrl_process(uint8_t * ht_ctrl,int len,int link_type,struct parser_res * res,signed char rssi)185 int awss_ieee80211_ht_ctrl_process(uint8_t *ht_ctrl, int len, int link_type,
186 struct parser_res *res, signed char rssi)
187 {
188 struct ht40_ctrl *ctrl = NULL;
189 /*
190 * when device try to connect current router (include aha)
191 * skip the new packet.
192 */
193 if (ht_ctrl == NULL || zconfig_finished)
194 return ALINK_INVALID;
195 /*
196 * we don't process smartconfig until user press configure button
197 */
198 if (awss_get_config_press() == 0)
199 return ALINK_INVALID;
200
201 /*
202 * just process ht ctrl
203 */
204 if (link_type != AWSS_LINK_TYPE_HT40_CTRL)
205 return ALINK_INVALID;
206
207 ctrl = (struct ht40_ctrl *)ht_ctrl;
208 res->u.ht_ctrl.rssi = rssi;
209 res->u.ht_ctrl.filter = ctrl->filter;
210 res->u.ht_ctrl.data_len = len;
211
212 return ALINK_HT_CTRL;
213 }
214
awss_recv_callback_ht_ctrl(struct parser_res * res)215 int awss_recv_callback_ht_ctrl(struct parser_res *res)
216 {
217 uint8_t tods = 1, equal = 0, score = 0;
218 uint16_t pos = 0, index = 0, len = 0;
219 uint32_t now = os_get_time_ms();
220 int pkg_type = PKG_INVALID;
221 int hint_pos = -1;
222 signed char rssi;
223 uint16_t length;
224 uint8_t channel;
225 uint8_t filter;
226
227 rssi = res->u.ht_ctrl.rssi;
228 length = res->u.ht_ctrl.data_len;
229 filter = res->u.ht_ctrl.filter;
230 channel = res->channel;
231 if (length > IEEE80211_MIN_HDRLEN) {
232 length -= IEEE80211_MIN_HDRLEN;
233 len = length;
234 } else {
235 goto drop;
236 }
237
238 hint_pos = ht40_scanning_hint_frame(filter, rssi, length, channel);
239
240 if (hint_pos >= 0) {
241 ht40_get_qos_auth_group_info(length);
242 return PKG_GROUP_FRAME;
243 }
244
245 if (ht40_state == STATE_RCV_IN_PROGRESS) {
246 if (rssi <= ht40_rssi_low && rssi >= ht40_rssi_high)
247 goto drop;
248 if (filter != ht40_filter)
249 goto drop;
250 if (len <= zc_frame_offset) /* length invalid */
251 goto drop;
252
253 len -= zc_frame_offset;
254
255 if (is_data_frame(len)) {
256 pkg_type = PKG_DATA_FRAME;
257 index = get_data_index(len);
258 pos = zc_group_pos + index;
259
260 if (now - ht40_timestamp > time_interval) {
261 awss_debug("\t\t\t\t\ttimestamp = %d, pos:%d, len:%x\r\n",
262 now - ht40_timestamp, pos, len);
263 goto drop;
264 }
265
266 /*
267 * pos_unsync: 进入条件,任一条
268 * case1: index rollback
269 * case2: index equal but len not equal
270 * case3: data frame & timeout
271 * 退出条件:
272 * case1: 进入条件同时也是退出条件
273 * case2: 收到同步帧
274 */
275 if (pos < zc_cur_pos) {
276 awss_debug("drop: index rollback. prev:%d, cur:%d\n",
277 zc_cur_pos, pos);
278 goto drop;
279 }
280
281 if (pos == zc_cur_pos && len != pkg_len(zc_cur_pos)) {
282 awss_debug("drop: index equal, but len not. prev:%x, cur:%x\n",
283 pkg_len(pos), len);
284 pkg_score(pos)--;
285 goto drop;
286 }
287
288 if (pos > zc_cur_pos + 4) {
289 awss_debug("drop: over range too much, prev:%d, cur:%d\n",
290 zc_cur_pos, pos);
291 goto drop;
292 }
293
294 score = zc_score_uplimit - (pos - zc_cur_pos - 1);
295 zc_score_uplimit = score;
296
297 awss_trace("ht40 %d+%d [%d] -- T %-3x\r\n", zc_group_pos, index,
298 score, len);
299 /*
300 score now > last:
301 1) data equal: pkg_score = now
302 2) not equal: pkg_score = now, data replace
303 score now == last:
304 1) data equal: pkg_score++ and ???
305 2) not equal: pkg_score cut down & give warning &
306 try_to_replace score now < last: 1) data equal: score_uplimit
307 up??? 2) not equal: goto pos_unsync
308 */
309 equal = !package_cmp((uint8_t *)pkg(pos), NULL, NULL, tods, len);
310
311 if (score > pkg_score(pos)) {
312 pkg_score(pos) = score; // update score first
313 if (!equal) {
314 zc_replace = 1;
315 package_save((uint8_t *)pkg(pos), NULL, NULL, tods, len);
316 }
317 } else if (score == pkg_score(pos)) { /* range check ? */
318 if (equal) {
319 pkg_score(pos)++;
320 } else {
321 pkg_score(pos)--;
322 }
323 } else {
324 /* do nothing */
325 }
326
327 zc_cur_pos = pos;
328 zc_max_pos = (zc_max_pos < zc_cur_pos) ? zc_cur_pos : zc_max_pos;
329 if (zc_replace && zconfig_recv_completed(tods)) {
330 zc_replace = 0;
331 if (!zconfig_get_ssid_passwd(tods)) {
332 /* we got it! */
333 zconfig_set_state(STATE_RCV_DONE, tods, channel);
334 return PKG_END;
335 }
336 }
337
338 ht40_timestamp = now;
339 return pkg_type;
340
341 } else {
342 if (is_start_frame(len) || is_group_frame(len)) {
343 uint8_t group = get_group_index(len);
344
345 if (!group || group == zc_group_pos + 8) {
346 zc_group_pos = group;
347 zc_score_uplimit = score_mid;
348
349 if (zc_cur_pos + 1 == group)
350 pkg_score(zc_cur_pos) += 1;
351
352 zc_cur_pos = group;
353
354 awss_trace("%d+%d [%d] -- T %-3x\r\n", group, 0,
355 zc_score_uplimit, len);
356
357 // ignore PKG_GROUP_FRAME here
358 pkg_type = PKG_START_FRAME;
359 ht40_timestamp = now;
360 return pkg_type;
361 }
362 }
363 }
364 }
365
366 drop:
367 return PKG_INVALID;
368 }
369 #if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
370 }
371 #endif
372 #endif
373