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"
18 static struct wlantest_sta
* rx_get_sta(struct wlantest
*wt
,
19 const struct ieee80211_hdr
*hdr
,
20 size_t len
, int *to_ap
)
23 const u8
*sta_addr
, *bssid
;
24 struct wlantest_bss
*bss
;
27 if (hdr
->addr1
[0] & 0x01)
28 return NULL
; /* Ignore group addressed frames */
30 fc
= le_to_host16(hdr
->frame_control
);
31 switch (WLAN_FC_GET_TYPE(fc
)) {
32 case WLAN_FC_TYPE_MGMT
:
36 if (os_memcmp(bssid
, hdr
->addr2
, ETH_ALEN
) == 0) {
37 sta_addr
= hdr
->addr1
;
40 if (os_memcmp(bssid
, hdr
->addr1
, ETH_ALEN
) != 0)
41 return NULL
; /* Unsupported STA-to-STA frame */
42 sta_addr
= hdr
->addr2
;
46 case WLAN_FC_TYPE_DATA
:
49 switch (fc
& (WLAN_FC_TODS
| WLAN_FC_FROMDS
)) {
51 return NULL
; /* IBSS not supported */
53 sta_addr
= hdr
->addr1
;
58 sta_addr
= hdr
->addr2
;
62 case WLAN_FC_TODS
| WLAN_FC_FROMDS
:
63 return NULL
; /* WDS not supported */
68 case WLAN_FC_TYPE_CTRL
:
69 if (WLAN_FC_GET_STYPE(fc
) == WLAN_FC_STYPE_PSPOLL
&&
71 sta_addr
= hdr
->addr2
;
81 bss
= bss_find(wt
, bssid
);
84 return sta_find(bss
, sta_addr
);
88 static void rx_update_ps(struct wlantest
*wt
, const struct ieee80211_hdr
*hdr
,
89 size_t len
, struct wlantest_sta
*sta
, int to_ap
)
96 fc
= le_to_host16(hdr
->frame_control
);
97 type
= WLAN_FC_GET_TYPE(fc
);
98 stype
= WLAN_FC_GET_STYPE(fc
);
101 if (sta
->pwrmgt
&& !sta
->pspoll
) {
102 u16 seq_ctrl
= le_to_host16(hdr
->seq_ctrl
);
103 wpa_printf(MSG_DEBUG
, "AP " MACSTR
" sent a frame "
104 "(%u:%u) to a sleeping STA " MACSTR
106 MAC2STR(sta
->bss
->bssid
),
107 type
, stype
, MAC2STR(sta
->addr
),
108 WLAN_GET_SEQ_SEQ(seq_ctrl
));
116 if (type
== WLAN_FC_TYPE_DATA
|| type
== WLAN_FC_TYPE_MGMT
||
117 (type
== WLAN_FC_TYPE_CTRL
&& stype
== WLAN_FC_STYPE_PSPOLL
)) {
119 * In theory, the PS state changes only at the end of the frame
120 * exchange that is ACKed by the AP. However, most cases are
121 * handled with this simpler implementation that does not
122 * maintain state through the frame exchange.
124 if (sta
->pwrmgt
&& !(fc
& WLAN_FC_PWRMGT
)) {
125 wpa_printf(MSG_DEBUG
, "STA " MACSTR
" woke up from "
126 "sleep", MAC2STR(sta
->addr
));
128 } else if (!sta
->pwrmgt
&& (fc
& WLAN_FC_PWRMGT
)) {
129 wpa_printf(MSG_DEBUG
, "STA " MACSTR
" went to sleep",
135 if (type
== WLAN_FC_TYPE_CTRL
&& stype
== WLAN_FC_STYPE_PSPOLL
)
140 static int rx_duplicate(struct wlantest
*wt
, const struct ieee80211_hdr
*hdr
,
141 size_t len
, struct wlantest_sta
*sta
, int to_ap
)
150 fc
= le_to_host16(hdr
->frame_control
);
151 if (WLAN_FC_GET_TYPE(fc
) == WLAN_FC_TYPE_DATA
&&
152 (WLAN_FC_GET_STYPE(fc
) & 0x08) && len
>= 26) {
153 const u8
*qos
= ((const u8
*) hdr
) + 24;
158 seq_ctrl
= &sta
->seq_ctrl_to_ap
[tid
];
160 seq_ctrl
= &sta
->seq_ctrl_to_sta
[tid
];
162 if ((fc
& WLAN_FC_RETRY
) && hdr
->seq_ctrl
== *seq_ctrl
) {
163 u16 s
= le_to_host16(hdr
->seq_ctrl
);
164 wpa_printf(MSG_MSGDUMP
, "Ignore duplicated frame (seq=%u "
165 "frag=%u A1=" MACSTR
" A2=" MACSTR
")",
166 WLAN_GET_SEQ_SEQ(s
), WLAN_GET_SEQ_FRAG(s
),
167 MAC2STR(hdr
->addr1
), MAC2STR(hdr
->addr2
));
171 *seq_ctrl
= hdr
->seq_ctrl
;
177 static void rx_ack(struct wlantest
*wt
, const struct ieee80211_hdr
*hdr
)
179 struct ieee80211_hdr
*last
= (struct ieee80211_hdr
*) wt
->last_hdr
;
182 if (wt
->last_len
< 24 || (last
->addr1
[0] & 0x01) ||
183 os_memcmp(hdr
->addr1
, last
->addr2
, ETH_ALEN
) != 0) {
184 wpa_printf(MSG_MSGDUMP
, "Unknown Ack frame (previous frame "
189 /* Ack to the previous frame */
190 fc
= le_to_host16(last
->frame_control
);
191 if (WLAN_FC_GET_TYPE(fc
) == WLAN_FC_TYPE_MGMT
)
192 rx_mgmt_ack(wt
, last
);
196 static void rx_frame(struct wlantest
*wt
, const u8
*data
, size_t len
)
198 const struct ieee80211_hdr
*hdr
;
200 struct wlantest_sta
*sta
;
203 wpa_hexdump(MSG_EXCESSIVE
, "RX frame", data
, len
);
207 hdr
= (const struct ieee80211_hdr
*) data
;
208 fc
= le_to_host16(hdr
->frame_control
);
209 if (fc
& WLAN_FC_PVER
) {
210 wpa_printf(MSG_DEBUG
, "Drop RX frame with unexpected pver=%d",
215 sta
= rx_get_sta(wt
, hdr
, len
, &to_ap
);
217 switch (WLAN_FC_GET_TYPE(fc
)) {
218 case WLAN_FC_TYPE_MGMT
:
221 if (rx_duplicate(wt
, hdr
, len
, sta
, to_ap
))
223 rx_update_ps(wt
, hdr
, len
, sta
, to_ap
);
224 rx_mgmt(wt
, data
, len
);
226 case WLAN_FC_TYPE_CTRL
:
230 rx_update_ps(wt
, hdr
, len
, sta
, to_ap
);
231 if (WLAN_FC_GET_STYPE(fc
) == WLAN_FC_STYPE_ACK
)
234 case WLAN_FC_TYPE_DATA
:
237 if (rx_duplicate(wt
, hdr
, len
, sta
, to_ap
))
239 rx_update_ps(wt
, hdr
, len
, sta
, to_ap
);
240 rx_data(wt
, data
, len
);
243 wpa_printf(MSG_DEBUG
, "Drop RX frame with unexpected type %d",
244 WLAN_FC_GET_TYPE(fc
));
248 os_memcpy(wt
->last_hdr
, data
, len
> sizeof(wt
->last_hdr
) ?
249 sizeof(wt
->last_hdr
) : len
);
254 static void tx_status(struct wlantest
*wt
, const u8
*data
, size_t len
, int ack
)
256 wpa_printf(MSG_DEBUG
, "TX status: ack=%d", ack
);
257 wpa_hexdump(MSG_EXCESSIVE
, "TX status frame", data
, len
);
261 static int check_fcs(const u8
*frame
, size_t frame_len
, const u8
*fcs
)
263 if (WPA_GET_LE32(fcs
) != crc32(frame
, frame_len
))
269 void wlantest_process(struct wlantest
*wt
, const u8
*data
, size_t len
)
271 struct ieee80211_radiotap_iterator iter
;
273 int rxflags
= 0, txflags
= 0, failed
= 0, fcs
= 0;
274 const u8
*frame
, *fcspos
;
277 wpa_hexdump(MSG_EXCESSIVE
, "Process data", data
, len
);
279 if (ieee80211_radiotap_iterator_init(&iter
, (void *) data
, len
)) {
280 wpa_printf(MSG_INFO
, "Invalid radiotap frame");
285 ret
= ieee80211_radiotap_iterator_next(&iter
);
286 wpa_printf(MSG_EXCESSIVE
, "radiotap iter: %d "
287 "this_arg_index=%d", ret
, iter
.this_arg_index
);
291 wpa_printf(MSG_INFO
, "Invalid radiotap header: %d",
295 switch (iter
.this_arg_index
) {
296 case IEEE80211_RADIOTAP_FLAGS
:
297 if (*iter
.this_arg
& IEEE80211_RADIOTAP_F_FCS
)
300 case IEEE80211_RADIOTAP_RX_FLAGS
:
303 case IEEE80211_RADIOTAP_TX_FLAGS
:
305 failed
= le_to_host16((*(u16
*) iter
.this_arg
)) &
306 IEEE80211_RADIOTAP_F_TX_FAIL
;
312 if (iter
.max_length
== 8) {
313 wpa_printf(MSG_DEBUG
, "Skip frame inserted by wlantest");
316 frame
= data
+ iter
.max_length
;
317 frame_len
= len
- iter
.max_length
;
319 if (fcs
&& frame_len
>= 4) {
321 fcspos
= frame
+ frame_len
;
322 if (check_fcs(frame
, frame_len
, fcspos
) < 0) {
323 wpa_printf(MSG_EXCESSIVE
, "Drop RX frame with invalid "
330 if (rxflags
&& txflags
)
333 rx_frame(wt
, frame
, frame_len
);
335 tx_status(wt
, frame
, frame_len
, !failed
);
339 void wlantest_process_prism(struct wlantest
*wt
, const u8
*data
, size_t len
)
342 const u8
*frame
, *fcspos
;
346 wpa_hexdump(MSG_EXCESSIVE
, "Process data", data
, len
);
350 hdrlen
= WPA_GET_LE32(data
+ 4);
353 wpa_printf(MSG_INFO
, "Too short frame to include prism "
358 frame
= data
+ hdrlen
;
359 frame_len
= len
- hdrlen
;
362 if (fcs
&& frame_len
>= 4) {
364 fcspos
= frame
+ frame_len
;
365 if (check_fcs(frame
, frame_len
, fcspos
) < 0) {
366 wpa_printf(MSG_EXCESSIVE
, "Drop RX frame with invalid "
373 rx_frame(wt
, frame
, frame_len
);
377 void wlantest_process_80211(struct wlantest
*wt
, const u8
*data
, size_t len
)
379 wpa_hexdump(MSG_EXCESSIVE
, "Process data", data
, len
);
380 rx_frame(wt
, data
, len
);