2 * Received frame processing
3 * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
9 #include "utils/includes.h"
11 #include "utils/common.h"
12 #include "utils/crc32.h"
13 #include "utils/radiotap.h"
14 #include "utils/radiotap_iter.h"
15 #include "common/ieee802_11_defs.h"
16 #include "common/qca-vendor.h"
20 static struct wlantest_sta
* rx_get_sta(struct wlantest
*wt
,
21 const struct ieee80211_hdr
*hdr
,
22 size_t len
, int *to_ap
)
25 const u8
*sta_addr
, *bssid
;
26 struct wlantest_bss
*bss
;
29 if (hdr
->addr1
[0] & 0x01)
30 return NULL
; /* Ignore group addressed frames */
32 fc
= le_to_host16(hdr
->frame_control
);
33 switch (WLAN_FC_GET_TYPE(fc
)) {
34 case WLAN_FC_TYPE_MGMT
:
38 if (os_memcmp(bssid
, hdr
->addr2
, ETH_ALEN
) == 0) {
39 sta_addr
= hdr
->addr1
;
42 if (os_memcmp(bssid
, hdr
->addr1
, ETH_ALEN
) != 0)
43 return NULL
; /* Unsupported STA-to-STA frame */
44 sta_addr
= hdr
->addr2
;
48 case WLAN_FC_TYPE_DATA
:
51 switch (fc
& (WLAN_FC_TODS
| WLAN_FC_FROMDS
)) {
53 return NULL
; /* IBSS not supported */
55 sta_addr
= hdr
->addr1
;
60 sta_addr
= hdr
->addr2
;
64 case WLAN_FC_TODS
| WLAN_FC_FROMDS
:
65 return NULL
; /* WDS not supported */
70 case WLAN_FC_TYPE_CTRL
:
71 if (WLAN_FC_GET_STYPE(fc
) == WLAN_FC_STYPE_PSPOLL
&&
73 sta_addr
= hdr
->addr2
;
83 bss
= bss_find(wt
, bssid
);
86 return sta_find(bss
, sta_addr
);
90 static void rx_update_ps(struct wlantest
*wt
, const struct ieee80211_hdr
*hdr
,
91 size_t len
, struct wlantest_sta
*sta
, int to_ap
)
98 fc
= le_to_host16(hdr
->frame_control
);
99 type
= WLAN_FC_GET_TYPE(fc
);
100 stype
= WLAN_FC_GET_STYPE(fc
);
103 if (sta
->pwrmgt
&& !sta
->pspoll
) {
104 u16 seq_ctrl
= le_to_host16(hdr
->seq_ctrl
);
105 add_note(wt
, MSG_DEBUG
, "AP " MACSTR
" sent a frame "
106 "(%u:%u) to a sleeping STA " MACSTR
108 MAC2STR(sta
->bss
->bssid
),
109 type
, stype
, MAC2STR(sta
->addr
),
110 WLAN_GET_SEQ_SEQ(seq_ctrl
));
118 if (type
== WLAN_FC_TYPE_DATA
|| type
== WLAN_FC_TYPE_MGMT
||
119 (type
== WLAN_FC_TYPE_CTRL
&& stype
== WLAN_FC_STYPE_PSPOLL
)) {
121 * In theory, the PS state changes only at the end of the frame
122 * exchange that is ACKed by the AP. However, most cases are
123 * handled with this simpler implementation that does not
124 * maintain state through the frame exchange.
126 if (sta
->pwrmgt
&& !(fc
& WLAN_FC_PWRMGT
)) {
127 add_note(wt
, MSG_DEBUG
, "STA " MACSTR
" woke up from "
128 "sleep", MAC2STR(sta
->addr
));
130 } else if (!sta
->pwrmgt
&& (fc
& WLAN_FC_PWRMGT
)) {
131 add_note(wt
, MSG_DEBUG
, "STA " MACSTR
" went to sleep",
137 if (type
== WLAN_FC_TYPE_CTRL
&& stype
== WLAN_FC_STYPE_PSPOLL
)
142 static int rx_duplicate(struct wlantest
*wt
, const struct ieee80211_hdr
*hdr
,
143 size_t len
, struct wlantest_sta
*sta
, int to_ap
)
152 fc
= le_to_host16(hdr
->frame_control
);
153 if (WLAN_FC_GET_TYPE(fc
) == WLAN_FC_TYPE_DATA
&&
154 (WLAN_FC_GET_STYPE(fc
) & 0x08) && len
>= 26) {
155 const u8
*qos
= ((const u8
*) hdr
) + 24;
160 seq_ctrl
= &sta
->seq_ctrl_to_ap
[tid
];
162 seq_ctrl
= &sta
->seq_ctrl_to_sta
[tid
];
164 if ((fc
& WLAN_FC_RETRY
) && hdr
->seq_ctrl
== *seq_ctrl
&&
165 !sta
->allow_duplicate
) {
166 u16 s
= le_to_host16(hdr
->seq_ctrl
);
167 add_note(wt
, MSG_MSGDUMP
, "Ignore duplicated frame (seq=%u "
168 "frag=%u A1=" MACSTR
" A2=" MACSTR
")",
169 WLAN_GET_SEQ_SEQ(s
), WLAN_GET_SEQ_FRAG(s
),
170 MAC2STR(hdr
->addr1
), MAC2STR(hdr
->addr2
));
174 *seq_ctrl
= hdr
->seq_ctrl
;
175 sta
->allow_duplicate
= 0;
181 static void rx_ack(struct wlantest
*wt
, const struct ieee80211_hdr
*hdr
)
183 struct ieee80211_hdr
*last
= (struct ieee80211_hdr
*) wt
->last_hdr
;
186 if (wt
->last_len
< 24 || (last
->addr1
[0] & 0x01) ||
187 os_memcmp(hdr
->addr1
, last
->addr2
, ETH_ALEN
) != 0) {
188 add_note(wt
, MSG_MSGDUMP
, "Unknown Ack frame (previous frame "
193 /* Ack to the previous frame */
194 fc
= le_to_host16(last
->frame_control
);
195 if (WLAN_FC_GET_TYPE(fc
) == WLAN_FC_TYPE_MGMT
)
196 rx_mgmt_ack(wt
, last
);
200 static void rx_frame(struct wlantest
*wt
, const u8
*data
, size_t len
)
202 const struct ieee80211_hdr
*hdr
;
204 struct wlantest_sta
*sta
;
207 wpa_hexdump(MSG_EXCESSIVE
, "RX frame", data
, len
);
211 hdr
= (const struct ieee80211_hdr
*) data
;
212 fc
= le_to_host16(hdr
->frame_control
);
213 if (fc
& WLAN_FC_PVER
) {
214 wpa_printf(MSG_DEBUG
, "Drop RX frame with unexpected pver=%d",
219 sta
= rx_get_sta(wt
, hdr
, len
, &to_ap
);
221 switch (WLAN_FC_GET_TYPE(fc
)) {
222 case WLAN_FC_TYPE_MGMT
:
225 if (rx_duplicate(wt
, hdr
, len
, sta
, to_ap
))
227 rx_update_ps(wt
, hdr
, len
, sta
, to_ap
);
228 rx_mgmt(wt
, data
, len
);
230 case WLAN_FC_TYPE_CTRL
:
234 rx_update_ps(wt
, hdr
, len
, sta
, to_ap
);
235 if (WLAN_FC_GET_STYPE(fc
) == WLAN_FC_STYPE_ACK
)
238 case WLAN_FC_TYPE_DATA
:
241 if (rx_duplicate(wt
, hdr
, len
, sta
, to_ap
))
243 rx_update_ps(wt
, hdr
, len
, sta
, to_ap
);
244 rx_data(wt
, data
, len
);
247 wpa_printf(MSG_DEBUG
, "Drop RX frame with unexpected type %d",
248 WLAN_FC_GET_TYPE(fc
));
252 os_memcpy(wt
->last_hdr
, data
, len
> sizeof(wt
->last_hdr
) ?
253 sizeof(wt
->last_hdr
) : len
);
258 static void tx_status(struct wlantest
*wt
, const u8
*data
, size_t len
, int ack
)
260 wpa_printf(MSG_DEBUG
, "TX status: ack=%d", ack
);
261 wpa_hexdump(MSG_EXCESSIVE
, "TX status frame", data
, len
);
265 static int check_fcs(const u8
*frame
, size_t frame_len
, const u8
*fcs
)
267 if (WPA_GET_LE32(fcs
) != crc32(frame
, frame_len
))
273 void wlantest_process(struct wlantest
*wt
, const u8
*data
, size_t len
)
275 struct ieee80211_radiotap_iterator iter
;
277 int rxflags
= 0, txflags
= 0, failed
= 0, fcs
= 0;
278 const u8
*frame
, *fcspos
;
281 wpa_hexdump(MSG_EXCESSIVE
, "Process data", data
, len
);
283 if (ieee80211_radiotap_iterator_init(&iter
, (void *) data
, len
, NULL
)) {
284 add_note(wt
, MSG_INFO
, "Invalid radiotap frame");
289 ret
= ieee80211_radiotap_iterator_next(&iter
);
290 wpa_printf(MSG_EXCESSIVE
, "radiotap iter: %d "
291 "this_arg_index=%d", ret
, iter
.this_arg_index
);
295 add_note(wt
, MSG_INFO
, "Invalid radiotap header: %d",
299 switch (iter
.this_arg_index
) {
300 case IEEE80211_RADIOTAP_FLAGS
:
301 if (*iter
.this_arg
& IEEE80211_RADIOTAP_F_FCS
)
304 case IEEE80211_RADIOTAP_RX_FLAGS
:
307 case IEEE80211_RADIOTAP_TX_FLAGS
:
309 failed
= le_to_host16((*(u16
*) iter
.this_arg
)) &
310 IEEE80211_RADIOTAP_F_TX_FAIL
;
312 case IEEE80211_RADIOTAP_VENDOR_NAMESPACE
:
313 if (WPA_GET_BE24(iter
.this_arg
) == OUI_QCA
&&
314 iter
.this_arg
[3] == QCA_RADIOTAP_VID_WLANTEST
) {
315 add_note(wt
, MSG_DEBUG
,
316 "Skip frame inserted by wlantest");
322 frame
= data
+ iter
._max_length
;
323 frame_len
= len
- iter
._max_length
;
325 if (fcs
&& frame_len
>= 4) {
327 fcspos
= frame
+ frame_len
;
328 if (check_fcs(frame
, frame_len
, fcspos
) < 0) {
329 add_note(wt
, MSG_EXCESSIVE
, "Drop RX frame with "
336 if (rxflags
&& txflags
)
339 rx_frame(wt
, frame
, frame_len
);
341 add_note(wt
, MSG_EXCESSIVE
, "TX status - process as RX of "
343 tx_status(wt
, frame
, frame_len
, !failed
);
344 /* Process as RX frame to support local monitor interface */
345 rx_frame(wt
, frame
, frame_len
);
350 void wlantest_process_prism(struct wlantest
*wt
, const u8
*data
, size_t len
)
353 const u8
*frame
, *fcspos
;
357 wpa_hexdump(MSG_EXCESSIVE
, "Process data", data
, len
);
361 hdrlen
= WPA_GET_LE32(data
+ 4);
364 wpa_printf(MSG_INFO
, "Too short frame to include prism "
369 frame
= data
+ hdrlen
;
370 frame_len
= len
- hdrlen
;
373 if (fcs
&& frame_len
>= 4) {
375 fcspos
= frame
+ frame_len
;
376 if (check_fcs(frame
, frame_len
, fcspos
) < 0) {
377 add_note(wt
, MSG_EXCESSIVE
, "Drop RX frame with "
384 rx_frame(wt
, frame
, frame_len
);
388 void wlantest_process_80211(struct wlantest
*wt
, const u8
*data
, size_t len
)
390 wpa_hexdump(MSG_EXCESSIVE
, "Process data", data
, len
);
392 if (wt
->assume_fcs
&& len
>= 4) {
397 if (check_fcs(data
, len
, fcspos
) < 0) {
398 add_note(wt
, MSG_EXCESSIVE
, "Drop RX frame with "
405 rx_frame(wt
, data
, len
);