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/radiotap.h"
13 #include "utils/radiotap_iter.h"
14 #include "common/ieee802_11_defs.h"
15 #include "common/qca-vendor.h"
19 static struct wlantest_sta
* rx_get_sta(struct wlantest
*wt
,
20 const struct ieee80211_hdr
*hdr
,
21 size_t len
, int *to_ap
)
24 const u8
*sta_addr
, *bssid
;
25 struct wlantest_bss
*bss
;
28 if (hdr
->addr1
[0] & 0x01)
29 return NULL
; /* Ignore group addressed frames */
31 fc
= le_to_host16(hdr
->frame_control
);
32 switch (WLAN_FC_GET_TYPE(fc
)) {
33 case WLAN_FC_TYPE_MGMT
:
37 if (os_memcmp(bssid
, hdr
->addr2
, ETH_ALEN
) == 0) {
38 sta_addr
= hdr
->addr1
;
41 if (os_memcmp(bssid
, hdr
->addr1
, ETH_ALEN
) != 0)
42 return NULL
; /* Unsupported STA-to-STA frame */
43 sta_addr
= hdr
->addr2
;
47 case WLAN_FC_TYPE_DATA
:
50 switch (fc
& (WLAN_FC_TODS
| WLAN_FC_FROMDS
)) {
52 return NULL
; /* IBSS not supported */
54 sta_addr
= hdr
->addr1
;
59 sta_addr
= hdr
->addr2
;
63 case WLAN_FC_TODS
| WLAN_FC_FROMDS
:
64 return NULL
; /* WDS not supported */
69 case WLAN_FC_TYPE_CTRL
:
70 if (WLAN_FC_GET_STYPE(fc
) == WLAN_FC_STYPE_PSPOLL
&&
72 sta_addr
= hdr
->addr2
;
82 bss
= bss_find(wt
, bssid
);
85 return sta_find(bss
, sta_addr
);
89 static void rx_update_ps(struct wlantest
*wt
, const struct ieee80211_hdr
*hdr
,
90 size_t len
, struct wlantest_sta
*sta
, int to_ap
)
97 fc
= le_to_host16(hdr
->frame_control
);
98 type
= WLAN_FC_GET_TYPE(fc
);
99 stype
= WLAN_FC_GET_STYPE(fc
);
102 if (sta
->pwrmgt
&& !sta
->pspoll
) {
103 u16 seq_ctrl
= le_to_host16(hdr
->seq_ctrl
);
104 add_note(wt
, MSG_DEBUG
, "AP " MACSTR
" sent a frame "
105 "(%u:%u) to a sleeping STA " MACSTR
107 MAC2STR(sta
->bss
->bssid
),
108 type
, stype
, MAC2STR(sta
->addr
),
109 WLAN_GET_SEQ_SEQ(seq_ctrl
));
117 if (type
== WLAN_FC_TYPE_DATA
|| type
== WLAN_FC_TYPE_MGMT
||
118 (type
== WLAN_FC_TYPE_CTRL
&& stype
== WLAN_FC_STYPE_PSPOLL
)) {
120 * In theory, the PS state changes only at the end of the frame
121 * exchange that is ACKed by the AP. However, most cases are
122 * handled with this simpler implementation that does not
123 * maintain state through the frame exchange.
125 if (sta
->pwrmgt
&& !(fc
& WLAN_FC_PWRMGT
)) {
126 add_note(wt
, MSG_DEBUG
, "STA " MACSTR
" woke up from "
127 "sleep", MAC2STR(sta
->addr
));
129 } else if (!sta
->pwrmgt
&& (fc
& WLAN_FC_PWRMGT
)) {
130 add_note(wt
, MSG_DEBUG
, "STA " MACSTR
" went to sleep",
136 if (type
== WLAN_FC_TYPE_CTRL
&& stype
== WLAN_FC_STYPE_PSPOLL
)
141 static int rx_duplicate(struct wlantest
*wt
, const struct ieee80211_hdr
*hdr
,
142 size_t len
, struct wlantest_sta
*sta
, int to_ap
)
151 fc
= le_to_host16(hdr
->frame_control
);
152 if (WLAN_FC_GET_TYPE(fc
) == WLAN_FC_TYPE_DATA
&&
153 (WLAN_FC_GET_STYPE(fc
) & 0x08) && len
>= 26) {
154 const u8
*qos
= ((const u8
*) hdr
) + 24;
159 seq_ctrl
= &sta
->seq_ctrl_to_ap
[tid
];
161 seq_ctrl
= &sta
->seq_ctrl_to_sta
[tid
];
163 if ((fc
& WLAN_FC_RETRY
) && hdr
->seq_ctrl
== *seq_ctrl
) {
164 u16 s
= le_to_host16(hdr
->seq_ctrl
);
165 add_note(wt
, MSG_MSGDUMP
, "Ignore duplicated frame (seq=%u "
166 "frag=%u A1=" MACSTR
" A2=" MACSTR
")",
167 WLAN_GET_SEQ_SEQ(s
), WLAN_GET_SEQ_FRAG(s
),
168 MAC2STR(hdr
->addr1
), MAC2STR(hdr
->addr2
));
172 *seq_ctrl
= hdr
->seq_ctrl
;
178 static void rx_ack(struct wlantest
*wt
, const struct ieee80211_hdr
*hdr
)
180 struct ieee80211_hdr
*last
= (struct ieee80211_hdr
*) wt
->last_hdr
;
183 if (wt
->last_len
< 24 || (last
->addr1
[0] & 0x01) ||
184 os_memcmp(hdr
->addr1
, last
->addr2
, ETH_ALEN
) != 0) {
185 add_note(wt
, MSG_MSGDUMP
, "Unknown Ack frame (previous frame "
190 /* Ack to the previous frame */
191 fc
= le_to_host16(last
->frame_control
);
192 if (WLAN_FC_GET_TYPE(fc
) == WLAN_FC_TYPE_MGMT
)
193 rx_mgmt_ack(wt
, last
);
197 static void rx_frame(struct wlantest
*wt
, const u8
*data
, size_t len
)
199 const struct ieee80211_hdr
*hdr
;
201 struct wlantest_sta
*sta
;
204 wpa_hexdump(MSG_EXCESSIVE
, "RX frame", data
, len
);
208 hdr
= (const struct ieee80211_hdr
*) data
;
209 fc
= le_to_host16(hdr
->frame_control
);
210 if (fc
& WLAN_FC_PVER
) {
211 wpa_printf(MSG_DEBUG
, "Drop RX frame with unexpected pver=%d",
216 sta
= rx_get_sta(wt
, hdr
, len
, &to_ap
);
218 switch (WLAN_FC_GET_TYPE(fc
)) {
219 case WLAN_FC_TYPE_MGMT
:
222 if (rx_duplicate(wt
, hdr
, len
, sta
, to_ap
))
224 rx_update_ps(wt
, hdr
, len
, sta
, to_ap
);
225 rx_mgmt(wt
, data
, len
);
227 case WLAN_FC_TYPE_CTRL
:
231 rx_update_ps(wt
, hdr
, len
, sta
, to_ap
);
232 if (WLAN_FC_GET_STYPE(fc
) == WLAN_FC_STYPE_ACK
)
235 case WLAN_FC_TYPE_DATA
:
238 if (rx_duplicate(wt
, hdr
, len
, sta
, to_ap
))
240 rx_update_ps(wt
, hdr
, len
, sta
, to_ap
);
241 rx_data(wt
, data
, len
);
244 wpa_printf(MSG_DEBUG
, "Drop RX frame with unexpected type %d",
245 WLAN_FC_GET_TYPE(fc
));
249 os_memcpy(wt
->last_hdr
, data
, len
> sizeof(wt
->last_hdr
) ?
250 sizeof(wt
->last_hdr
) : len
);
255 static void tx_status(struct wlantest
*wt
, const u8
*data
, size_t len
, int ack
)
257 wpa_printf(MSG_DEBUG
, "TX status: ack=%d", ack
);
258 wpa_hexdump(MSG_EXCESSIVE
, "TX status frame", data
, len
);
262 static int check_fcs(const u8
*frame
, size_t frame_len
, const u8
*fcs
)
264 if (WPA_GET_LE32(fcs
) != crc32(frame
, frame_len
))
270 void wlantest_process(struct wlantest
*wt
, const u8
*data
, size_t len
)
272 struct ieee80211_radiotap_iterator iter
;
274 int rxflags
= 0, txflags
= 0, failed
= 0, fcs
= 0;
275 const u8
*frame
, *fcspos
;
278 wpa_hexdump(MSG_EXCESSIVE
, "Process data", data
, len
);
280 if (ieee80211_radiotap_iterator_init(&iter
, (void *) data
, len
, NULL
)) {
281 add_note(wt
, MSG_INFO
, "Invalid radiotap frame");
286 ret
= ieee80211_radiotap_iterator_next(&iter
);
287 wpa_printf(MSG_EXCESSIVE
, "radiotap iter: %d "
288 "this_arg_index=%d", ret
, iter
.this_arg_index
);
292 add_note(wt
, MSG_INFO
, "Invalid radiotap header: %d",
296 switch (iter
.this_arg_index
) {
297 case IEEE80211_RADIOTAP_FLAGS
:
298 if (*iter
.this_arg
& IEEE80211_RADIOTAP_F_FCS
)
301 case IEEE80211_RADIOTAP_RX_FLAGS
:
304 case IEEE80211_RADIOTAP_TX_FLAGS
:
306 failed
= le_to_host16((*(u16
*) iter
.this_arg
)) &
307 IEEE80211_RADIOTAP_F_TX_FAIL
;
309 case IEEE80211_RADIOTAP_VENDOR_NAMESPACE
:
310 if (WPA_GET_BE24(iter
.this_arg
) == OUI_QCA
&&
311 iter
.this_arg
[3] == QCA_RADIOTAP_VID_WLANTEST
) {
312 add_note(wt
, MSG_DEBUG
,
313 "Skip frame inserted by wlantest");
319 frame
= data
+ iter
._max_length
;
320 frame_len
= len
- iter
._max_length
;
322 if (fcs
&& frame_len
>= 4) {
324 fcspos
= frame
+ frame_len
;
325 if (check_fcs(frame
, frame_len
, fcspos
) < 0) {
326 add_note(wt
, MSG_EXCESSIVE
, "Drop RX frame with "
333 if (rxflags
&& txflags
)
336 rx_frame(wt
, frame
, frame_len
);
338 add_note(wt
, MSG_EXCESSIVE
, "TX status - process as RX of "
340 tx_status(wt
, frame
, frame_len
, !failed
);
341 /* Process as RX frame to support local monitor interface */
342 rx_frame(wt
, frame
, frame_len
);
347 void wlantest_process_prism(struct wlantest
*wt
, const u8
*data
, size_t len
)
350 const u8
*frame
, *fcspos
;
354 wpa_hexdump(MSG_EXCESSIVE
, "Process data", data
, len
);
358 hdrlen
= WPA_GET_LE32(data
+ 4);
361 wpa_printf(MSG_INFO
, "Too short frame to include prism "
366 frame
= data
+ hdrlen
;
367 frame_len
= len
- hdrlen
;
370 if (fcs
&& frame_len
>= 4) {
372 fcspos
= frame
+ frame_len
;
373 if (check_fcs(frame
, frame_len
, fcspos
) < 0) {
374 add_note(wt
, MSG_EXCESSIVE
, "Drop RX frame with "
381 rx_frame(wt
, frame
, frame_len
);
385 void wlantest_process_80211(struct wlantest
*wt
, const u8
*data
, size_t len
)
387 wpa_hexdump(MSG_EXCESSIVE
, "Process data", data
, len
);
389 if (wt
->assume_fcs
&& len
>= 4) {
394 if (check_fcs(data
, len
, fcspos
) < 0) {
395 add_note(wt
, MSG_EXCESSIVE
, "Drop RX frame with "
402 rx_frame(wt
, data
, len
);