]> git.ipfire.org Git - thirdparty/hostap.git/blob - wlantest/inject.c
AOSP: P2P find stopped ctrl_iface event of p2p_flush
[thirdparty/hostap.git] / wlantest / inject.c
1 /*
2 * wlantest frame injection
3 * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9 #include "utils/includes.h"
10
11 #include "utils/common.h"
12 #include "common/defs.h"
13 #include "common/ieee802_11_defs.h"
14 #include "crypto/aes_wrap.h"
15 #include "wlantest.h"
16
17
18 static int inject_frame(int s, const void *data, size_t len)
19 {
20 #define IEEE80211_RADIOTAP_F_FRAG 0x08
21 unsigned char rtap_hdr[] = {
22 0x00, 0x00, /* radiotap version */
23 0x0e, 0x00, /* radiotap length */
24 0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */
25 IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */
26 0x00, /* padding */
27 0x00, 0x00, /* RX and TX flags to indicate that */
28 0x00, 0x00, /* this is the injected frame directly */
29 };
30 struct iovec iov[2] = {
31 {
32 .iov_base = &rtap_hdr,
33 .iov_len = sizeof(rtap_hdr),
34 },
35 {
36 .iov_base = (void *) data,
37 .iov_len = len,
38 }
39 };
40 struct msghdr msg = {
41 .msg_name = NULL,
42 .msg_namelen = 0,
43 .msg_iov = iov,
44 .msg_iovlen = 2,
45 .msg_control = NULL,
46 .msg_controllen = 0,
47 .msg_flags = 0,
48 };
49 int ret;
50
51 ret = sendmsg(s, &msg, 0);
52 if (ret < 0)
53 perror("sendmsg");
54 return ret;
55 }
56
57
58 static int is_robust_mgmt(u8 *frame, size_t len)
59 {
60 struct ieee80211_mgmt *mgmt;
61 u16 fc, stype;
62 if (len < 24)
63 return 0;
64 mgmt = (struct ieee80211_mgmt *) frame;
65 fc = le_to_host16(mgmt->frame_control);
66 if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT)
67 return 0;
68 stype = WLAN_FC_GET_STYPE(fc);
69 if (stype == WLAN_FC_STYPE_DEAUTH || stype == WLAN_FC_STYPE_DISASSOC)
70 return 1;
71 if (stype == WLAN_FC_STYPE_ACTION) {
72 if (len < 25)
73 return 0;
74 if (mgmt->u.action.category != WLAN_ACTION_PUBLIC)
75 return 1;
76 }
77 return 0;
78 }
79
80
81 static int wlantest_inject_bip(struct wlantest *wt, struct wlantest_bss *bss,
82 u8 *frame, size_t len, int incorrect_key)
83 {
84 u8 *prot, *pos, *buf;
85 u8 mic[16];
86 u8 dummy[16];
87 int ret;
88 u16 fc;
89 struct ieee80211_hdr *hdr;
90 size_t plen;
91
92 if (!bss->igtk_set[bss->igtk_idx])
93 return -1;
94
95 plen = len + 18;
96 prot = os_malloc(plen);
97 if (prot == NULL)
98 return -1;
99 os_memcpy(prot, frame, len);
100 pos = prot + len;
101 *pos++ = WLAN_EID_MMIE;
102 *pos++ = 16;
103 WPA_PUT_LE16(pos, bss->igtk_idx);
104 pos += 2;
105 inc_byte_array(bss->ipn[bss->igtk_idx], 6);
106 os_memcpy(pos, bss->ipn[bss->igtk_idx], 6);
107 pos += 6;
108 os_memset(pos, 0, 8); /* MIC */
109
110 buf = os_malloc(plen + 20 - 24);
111 if (buf == NULL) {
112 os_free(prot);
113 return -1;
114 }
115
116 /* BIP AAD: FC(masked) A1 A2 A3 */
117 hdr = (struct ieee80211_hdr *) frame;
118 fc = le_to_host16(hdr->frame_control);
119 fc &= ~(WLAN_FC_RETRY | WLAN_FC_PWRMGT | WLAN_FC_MOREDATA);
120 WPA_PUT_LE16(buf, fc);
121 os_memcpy(buf + 2, hdr->addr1, 3 * ETH_ALEN);
122 os_memcpy(buf + 20, prot + 24, plen - 24);
123 wpa_hexdump(MSG_MSGDUMP, "BIP: AAD|Body(masked)", buf, plen + 20 - 24);
124 /* MIC = L(AES-128-CMAC(AAD || Frame Body(masked)), 0, 64) */
125 os_memset(dummy, 0x11, sizeof(dummy));
126 if (omac1_aes_128(incorrect_key ? dummy : bss->igtk[bss->igtk_idx],
127 buf, plen + 20 - 24, mic) < 0) {
128 os_free(prot);
129 os_free(buf);
130 return -1;
131 }
132 os_free(buf);
133
134 os_memcpy(pos, mic, 8);
135 wpa_hexdump(MSG_DEBUG, "BIP MMIE MIC", pos, 8);
136
137 ret = inject_frame(wt->monitor_sock, prot, plen);
138 os_free(prot);
139
140 return (ret < 0) ? -1 : 0;
141 }
142
143
144 static int wlantest_inject_prot_bc(struct wlantest *wt,
145 struct wlantest_bss *bss,
146 u8 *frame, size_t len, int incorrect_key)
147 {
148 u8 *crypt;
149 size_t crypt_len;
150 int ret;
151 u8 dummy[64];
152 u8 *pn;
153 struct ieee80211_hdr *hdr;
154 u16 fc;
155 int hdrlen;
156
157 hdr = (struct ieee80211_hdr *) frame;
158 hdrlen = 24;
159 fc = le_to_host16(hdr->frame_control);
160
161 if (!bss->gtk_len[bss->gtk_idx])
162 return -1;
163
164 if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
165 (WLAN_FC_TODS | WLAN_FC_FROMDS))
166 hdrlen += ETH_ALEN;
167 pn = bss->rsc[bss->gtk_idx];
168 inc_byte_array(pn, 6);
169
170 os_memset(dummy, 0x11, sizeof(dummy));
171 if (bss->group_cipher == WPA_CIPHER_TKIP)
172 crypt = tkip_encrypt(incorrect_key ? dummy :
173 bss->gtk[bss->gtk_idx],
174 frame, len, hdrlen, NULL, pn,
175 bss->gtk_idx, &crypt_len);
176 else
177 crypt = ccmp_encrypt(incorrect_key ? dummy :
178 bss->gtk[bss->gtk_idx],
179 frame, len, hdrlen, NULL, pn,
180 bss->gtk_idx, &crypt_len);
181
182 if (crypt == NULL)
183 return -1;
184
185 ret = inject_frame(wt->monitor_sock, crypt, crypt_len);
186 os_free(crypt);
187
188 return (ret < 0) ? -1 : 0;
189 }
190
191
192 static int wlantest_inject_prot(struct wlantest *wt, struct wlantest_bss *bss,
193 struct wlantest_sta *sta, u8 *frame,
194 size_t len, int incorrect_key)
195 {
196 u8 *crypt;
197 size_t crypt_len;
198 int ret;
199 u8 dummy[64];
200 u8 *pn;
201 struct ieee80211_hdr *hdr;
202 u16 fc;
203 int tid = 0;
204 u8 *qos = NULL;
205 int hdrlen;
206 struct wlantest_tdls *tdls = NULL;
207 const u8 *tk = NULL;
208
209 hdr = (struct ieee80211_hdr *) frame;
210 hdrlen = 24;
211 fc = le_to_host16(hdr->frame_control);
212
213 if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA &&
214 (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) == 0) {
215 struct wlantest_sta *sta2;
216 bss = bss_get(wt, hdr->addr3);
217 if (bss == NULL) {
218 wpa_printf(MSG_DEBUG, "No BSS found for TDLS "
219 "injection");
220 return -1;
221 }
222 sta = sta_find(bss, hdr->addr2);
223 sta2 = sta_find(bss, hdr->addr1);
224 if (sta == NULL || sta2 == NULL) {
225 wpa_printf(MSG_DEBUG, "No stations found for TDLS "
226 "injection");
227 return -1;
228 }
229 dl_list_for_each(tdls, &bss->tdls, struct wlantest_tdls, list)
230 {
231 if ((tdls->init == sta && tdls->resp == sta2) ||
232 (tdls->init == sta2 && tdls->resp == sta)) {
233 if (!tdls->link_up)
234 wpa_printf(MSG_DEBUG, "TDLS: Link not "
235 "up, but injecting Data "
236 "frame on direct link");
237 tk = tdls->tpk.tk;
238 break;
239 }
240 }
241 }
242
243 if (tk == NULL && sta == NULL) {
244 if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT)
245 return wlantest_inject_bip(wt, bss, frame, len,
246 incorrect_key);
247 return wlantest_inject_prot_bc(wt, bss, frame, len,
248 incorrect_key);
249 }
250
251 if (tk == NULL && !sta->ptk_set) {
252 wpa_printf(MSG_DEBUG, "No key known for injection");
253 return -1;
254 }
255
256 if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT)
257 tid = 16;
258 else if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA) {
259 if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
260 (WLAN_FC_TODS | WLAN_FC_FROMDS))
261 hdrlen += ETH_ALEN;
262 if (WLAN_FC_GET_STYPE(fc) & 0x08) {
263 qos = frame + hdrlen;
264 hdrlen += 2;
265 tid = qos[0] & 0x0f;
266 }
267 }
268 if (tk) {
269 if (os_memcmp(hdr->addr2, tdls->init->addr, ETH_ALEN) == 0)
270 pn = tdls->rsc_init[tid];
271 else
272 pn = tdls->rsc_resp[tid];
273 } else if (os_memcmp(hdr->addr2, bss->bssid, ETH_ALEN) == 0)
274 pn = sta->rsc_fromds[tid];
275 else
276 pn = sta->rsc_tods[tid];
277 inc_byte_array(pn, 6);
278
279 os_memset(dummy, 0x11, sizeof(dummy));
280 if (tk)
281 crypt = ccmp_encrypt(incorrect_key ? dummy : tk,
282 frame, len, hdrlen, qos, pn, 0,
283 &crypt_len);
284 else if (sta->pairwise_cipher == WPA_CIPHER_TKIP)
285 crypt = tkip_encrypt(incorrect_key ? dummy : sta->ptk.tk1,
286 frame, len, hdrlen, qos, pn, 0,
287 &crypt_len);
288 else
289 crypt = ccmp_encrypt(incorrect_key ? dummy : sta->ptk.tk1,
290 frame, len, hdrlen, qos, pn, 0,
291 &crypt_len);
292
293 if (crypt == NULL) {
294 wpa_printf(MSG_DEBUG, "Frame encryption failed");
295 return -1;
296 }
297
298 wpa_hexdump(MSG_DEBUG, "Inject frame (encrypted)", crypt, crypt_len);
299 ret = inject_frame(wt->monitor_sock, crypt, crypt_len);
300 os_free(crypt);
301 wpa_printf(MSG_DEBUG, "inject_frame for protected frame: %d", ret);
302
303 return (ret < 0) ? -1 : 0;
304 }
305
306
307 int wlantest_inject(struct wlantest *wt, struct wlantest_bss *bss,
308 struct wlantest_sta *sta, u8 *frame, size_t len,
309 enum wlantest_inject_protection prot)
310 {
311 int ret;
312 struct ieee80211_hdr *hdr;
313 u16 fc;
314 int protectable, protect = 0;
315
316 wpa_hexdump(MSG_DEBUG, "Inject frame", frame, len);
317 if (wt->monitor_sock < 0) {
318 wpa_printf(MSG_INFO, "Cannot inject frames when monitor "
319 "interface is not in use");
320 return -1;
321 }
322
323 if (prot != WLANTEST_INJECT_UNPROTECTED &&
324 (bss == NULL || sta == NULL)) {
325 wpa_printf(MSG_INFO, "No BSS/STA information to inject "
326 "protected frames");
327 return -1;
328 }
329
330 hdr = (struct ieee80211_hdr *) frame;
331 fc = le_to_host16(hdr->frame_control);
332 protectable = WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA ||
333 is_robust_mgmt(frame, len);
334
335 if ((prot == WLANTEST_INJECT_PROTECTED ||
336 prot == WLANTEST_INJECT_INCORRECT_KEY) && bss) {
337 if (!sta &&
338 ((WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
339 !bss->igtk_set[bss->igtk_idx]) ||
340 (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA &&
341 !bss->gtk_len[bss->gtk_idx]))) {
342 wpa_printf(MSG_INFO, "No GTK/IGTK known for "
343 MACSTR " to protect the injected "
344 "frame", MAC2STR(bss->bssid));
345 return -1;
346 }
347 if (sta && !sta->ptk_set) {
348 wpa_printf(MSG_INFO, "No PTK known for the STA " MACSTR
349 " to encrypt the injected frame",
350 MAC2STR(sta->addr));
351 return -1;
352 }
353 protect = 1;
354 } else if (protectable && prot != WLANTEST_INJECT_UNPROTECTED && bss) {
355 if (sta && sta->ptk_set)
356 protect = 1;
357 else if (!sta) {
358 if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA &&
359 bss->gtk_len[bss->gtk_idx])
360 protect = 1;
361 if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
362 bss->igtk_set[bss->igtk_idx])
363 protect = 1;
364 }
365 }
366
367 if (protect && bss)
368 return wlantest_inject_prot(
369 wt, bss, sta, frame, len,
370 prot == WLANTEST_INJECT_INCORRECT_KEY);
371
372 ret = inject_frame(wt->monitor_sock, frame, len);
373 wpa_printf(MSG_DEBUG, "inject_frame for unprotected frame: %d", ret);
374 return (ret < 0) ? -1 : 0;
375 }