1fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt/*
2fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * Driver interaction with Linux nl80211/cfg80211 - AP monitor interface
3fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
4fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * Copyright (c) 2003-2004, Instant802 Networks, Inc.
5fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * Copyright (c) 2005-2006, Devicescape Software, Inc.
6fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
7fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * Copyright (c) 2009-2010, Atheros Communications
8fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt *
9fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
10fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * See README for more details.
11fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt */
12fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
13fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "includes.h"
14fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include <netpacket/packet.h>
15fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include <linux/filter.h>
16fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
17fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "utils/common.h"
18fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "utils/eloop.h"
19fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "common/ieee802_11_defs.h"
20fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "common/ieee802_11_common.h"
21fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "linux_ioctl.h"
22fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "radiotap_iter.h"
23fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#include "driver_nl80211.h"
24fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
25fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
26fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic void handle_tx_callback(void *ctx, u8 *buf, size_t len, int ok)
27fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{
28fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	struct ieee80211_hdr *hdr;
29fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	u16 fc;
30fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	union wpa_event_data event;
31fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
32fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	hdr = (struct ieee80211_hdr *) buf;
33fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	fc = le_to_host16(hdr->frame_control);
34fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
35fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	os_memset(&event, 0, sizeof(event));
36fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	event.tx_status.type = WLAN_FC_GET_TYPE(fc);
37fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
38fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	event.tx_status.dst = hdr->addr1;
39fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	event.tx_status.data = buf;
40fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	event.tx_status.data_len = len;
41fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	event.tx_status.ack = ok;
42fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	wpa_supplicant_event(ctx, EVENT_TX_STATUS, &event);
43fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt}
44fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
45fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
46fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic void from_unknown_sta(struct wpa_driver_nl80211_data *drv,
47fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			     u8 *buf, size_t len)
48fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{
49fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	struct ieee80211_hdr *hdr = (void *)buf;
50fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	u16 fc;
51fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	union wpa_event_data event;
52fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
53fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	if (len < sizeof(*hdr))
54fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		return;
55fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
56fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	fc = le_to_host16(hdr->frame_control);
57fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
58fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	os_memset(&event, 0, sizeof(event));
59fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	event.rx_from_unknown.bssid = get_hdr_bssid(hdr, len);
60fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	event.rx_from_unknown.addr = hdr->addr2;
61fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	event.rx_from_unknown.wds = (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) ==
62fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		(WLAN_FC_FROMDS | WLAN_FC_TODS);
63fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
64fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt}
65fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
66fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
67fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic void handle_frame(struct wpa_driver_nl80211_data *drv,
68fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			 u8 *buf, size_t len, int datarate, int ssi_signal)
69fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{
70fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	struct ieee80211_hdr *hdr;
71fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	u16 fc;
72fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	union wpa_event_data event;
73fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
74fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	hdr = (struct ieee80211_hdr *) buf;
75fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	fc = le_to_host16(hdr->frame_control);
76fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
77fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	switch (WLAN_FC_GET_TYPE(fc)) {
78fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	case WLAN_FC_TYPE_MGMT:
79fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		os_memset(&event, 0, sizeof(event));
80fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		event.rx_mgmt.frame = buf;
81fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		event.rx_mgmt.frame_len = len;
82fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		event.rx_mgmt.datarate = datarate;
83fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		event.rx_mgmt.ssi_signal = ssi_signal;
84fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
85fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		break;
86fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	case WLAN_FC_TYPE_CTRL:
87fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		/* can only get here with PS-Poll frames */
88fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		wpa_printf(MSG_DEBUG, "CTRL");
89fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		from_unknown_sta(drv, buf, len);
90fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		break;
91fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	case WLAN_FC_TYPE_DATA:
92fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		from_unknown_sta(drv, buf, len);
93fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		break;
94fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	}
95fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt}
96fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
97fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
98fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
99fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{
100fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = eloop_ctx;
101fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	int len;
102fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	unsigned char buf[3000];
103fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	struct ieee80211_radiotap_iterator iter;
104fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	int ret;
105fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	int datarate = 0, ssi_signal = 0;
106fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	int injected = 0, failed = 0, rxflags = 0;
107fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
108fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	len = recv(sock, buf, sizeof(buf), 0);
109fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	if (len < 0) {
110fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Monitor socket recv failed: %s",
111fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			   strerror(errno));
112fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		return;
113fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	}
114fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
115fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	if (ieee80211_radiotap_iterator_init(&iter, (void *) buf, len, NULL)) {
116fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame");
117fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		return;
118fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	}
119fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
120fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	while (1) {
121fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		ret = ieee80211_radiotap_iterator_next(&iter);
122fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		if (ret == -ENOENT)
123fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			break;
124fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		if (ret) {
125fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame (%d)",
126fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt				   ret);
127fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			return;
128fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		}
129fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		switch (iter.this_arg_index) {
130fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		case IEEE80211_RADIOTAP_FLAGS:
131fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS)
132fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt				len -= 4;
133fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			break;
134fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		case IEEE80211_RADIOTAP_RX_FLAGS:
135fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			rxflags = 1;
136fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			break;
137fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		case IEEE80211_RADIOTAP_TX_FLAGS:
138fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			injected = 1;
139fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			failed = le_to_host16((*(uint16_t *) iter.this_arg)) &
140fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt					IEEE80211_RADIOTAP_F_TX_FAIL;
141fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			break;
142fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		case IEEE80211_RADIOTAP_DATA_RETRIES:
143fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			break;
144fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		case IEEE80211_RADIOTAP_CHANNEL:
145fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			/* TODO: convert from freq/flags to channel number */
146fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			break;
147fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		case IEEE80211_RADIOTAP_RATE:
148fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			datarate = *iter.this_arg * 5;
149fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			break;
150fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
151fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			ssi_signal = (s8) *iter.this_arg;
152fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			break;
153fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		}
154fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	}
155fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
156fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	if (rxflags && injected)
157fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		return;
158fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
159fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	if (!injected)
160fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		handle_frame(drv, buf + iter._max_length,
161fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			     len - iter._max_length, datarate, ssi_signal);
162fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	else
163fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		handle_tx_callback(drv->ctx, buf + iter._max_length,
164fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt				   len - iter._max_length, !failed);
165fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt}
166fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
167fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
168fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt/*
169fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * we post-process the filter code later and rewrite
170fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt * this to the offset to the last instruction
171fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt */
172fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#define PASS	0xFF
173fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#define FAIL	0xFE
174fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
175fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic struct sock_filter msock_filter_insns[] = {
176fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/*
177fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	 * do a little-endian load of the radiotap length field
178fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	 */
179fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/* load lower byte into A */
180fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_STMT(BPF_LD  | BPF_B | BPF_ABS, 2),
181fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/* put it into X (== index register) */
182fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_STMT(BPF_MISC| BPF_TAX, 0),
183fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/* load upper byte into A */
184fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_STMT(BPF_LD  | BPF_B | BPF_ABS, 3),
185fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/* left-shift it by 8 */
186fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_STMT(BPF_ALU | BPF_LSH | BPF_K, 8),
187fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/* or with X */
188fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_STMT(BPF_ALU | BPF_OR | BPF_X, 0),
189fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/* put result into X */
190fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_STMT(BPF_MISC| BPF_TAX, 0),
191fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
192fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/*
193fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	 * Allow management frames through, this also gives us those
194fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	 * management frames that we sent ourselves with status
195fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	 */
196fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/* load the lower byte of the IEEE 802.11 frame control field */
197fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_STMT(BPF_LD  | BPF_B | BPF_IND, 0),
198fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/* mask off frame type and version */
199fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0xF),
200fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/* accept frame if it's both 0, fall through otherwise */
201fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, PASS, 0),
202fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
203fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/*
204fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	 * TODO: add a bit to radiotap RX flags that indicates
205fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	 * that the sending station is not associated, then
206fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	 * add a filter here that filters on our DA and that flag
207fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	 * to allow us to deauth frames to that bad station.
208fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	 *
209fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	 * For now allow all To DS data frames through.
210fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	 */
211fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/* load the IEEE 802.11 frame control field */
212fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_STMT(BPF_LD  | BPF_H | BPF_IND, 0),
213fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/* mask off frame type, version and DS status */
214fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0F03),
215fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/* accept frame if version 0, type 2 and To DS, fall through otherwise
216fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	 */
217fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0801, PASS, 0),
218fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
219fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#if 0
220fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/*
221fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	 * drop non-data frames
222fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	 */
223fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/* load the lower byte of the frame control field */
224fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_STMT(BPF_LD   | BPF_B | BPF_IND, 0),
225fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/* mask off QoS bit */
226fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_STMT(BPF_ALU  | BPF_AND | BPF_K, 0x0c),
227fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/* drop non-data frames */
228fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_JUMP(BPF_JMP  | BPF_JEQ | BPF_K, 8, 0, FAIL),
229fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt#endif
230fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/* load the upper byte of the frame control field */
231fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_STMT(BPF_LD   | BPF_B | BPF_IND, 1),
232fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/* mask off toDS/fromDS */
233fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_STMT(BPF_ALU  | BPF_AND | BPF_K, 0x03),
234fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/* accept WDS frames */
235fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_JUMP(BPF_JMP  | BPF_JEQ | BPF_K, 3, PASS, 0),
236fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
237fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/*
238fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	 * add header length to index
239fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	 */
240fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/* load the lower byte of the frame control field */
241fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_STMT(BPF_LD   | BPF_B | BPF_IND, 0),
242fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/* mask off QoS bit */
243fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_STMT(BPF_ALU  | BPF_AND | BPF_K, 0x80),
244fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/* right shift it by 6 to give 0 or 2 */
245fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_STMT(BPF_ALU  | BPF_RSH | BPF_K, 6),
246fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/* add data frame header length */
247fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_STMT(BPF_ALU  | BPF_ADD | BPF_K, 24),
248fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/* add index, was start of 802.11 header */
249fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_STMT(BPF_ALU  | BPF_ADD | BPF_X, 0),
250fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/* move to index, now start of LL header */
251fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_STMT(BPF_MISC | BPF_TAX, 0),
252fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
253fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/*
254fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	 * Accept empty data frames, we use those for
255fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	 * polling activity.
256fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	 */
257fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_STMT(BPF_LD  | BPF_W | BPF_LEN, 0),
258fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_X, 0, PASS, 0),
259fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
260fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/*
261fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	 * Accept EAPOL frames
262fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	 */
263fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_STMT(BPF_LD  | BPF_W | BPF_IND, 0),
264fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA0300, 0, FAIL),
265fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_STMT(BPF_LD  | BPF_W | BPF_IND, 4),
266fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0000888E, PASS, FAIL),
267fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
268fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/* keep these last two statements or change the code below */
269fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/* return 0 == "DROP" */
270fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_STMT(BPF_RET | BPF_K, 0),
271fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/* return ~0 == "keep all" */
272fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	BPF_STMT(BPF_RET | BPF_K, ~0),
273fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt};
274fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
275fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic struct sock_fprog msock_filter = {
276fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	.len = ARRAY_SIZE(msock_filter_insns),
277fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	.filter = msock_filter_insns,
278fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt};
279fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
280fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
281fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtstatic int add_monitor_filter(int s)
282fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{
283fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	int idx;
284fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
285fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	/* rewrite all PASS/FAIL jump offsets */
286fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	for (idx = 0; idx < msock_filter.len; idx++) {
287fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		struct sock_filter *insn = &msock_filter_insns[idx];
288fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
289fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		if (BPF_CLASS(insn->code) == BPF_JMP) {
290fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			if (insn->code == (BPF_JMP|BPF_JA)) {
291fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt				if (insn->k == PASS)
292fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt					insn->k = msock_filter.len - idx - 2;
293fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt				else if (insn->k == FAIL)
294fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt					insn->k = msock_filter.len - idx - 3;
295fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			}
296fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
297fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			if (insn->jt == PASS)
298fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt				insn->jt = msock_filter.len - idx - 2;
299fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			else if (insn->jt == FAIL)
300fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt				insn->jt = msock_filter.len - idx - 3;
301fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
302fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			if (insn->jf == PASS)
303fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt				insn->jf = msock_filter.len - idx - 2;
304fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			else if (insn->jf == FAIL)
305fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt				insn->jf = msock_filter.len - idx - 3;
306fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		}
307fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	}
308fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
309fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER,
310fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		       &msock_filter, sizeof(msock_filter))) {
311fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: setsockopt(SO_ATTACH_FILTER) failed: %s",
312fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			   strerror(errno));
313fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		return -1;
314fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	}
315fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
316fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	return 0;
317fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt}
318fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
319fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
320fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtvoid nl80211_remove_monitor_interface(struct wpa_driver_nl80211_data *drv)
321fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{
322fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	if (drv->monitor_refcount > 0)
323fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		drv->monitor_refcount--;
324fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Remove monitor interface: refcount=%d",
325fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		   drv->monitor_refcount);
326fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	if (drv->monitor_refcount > 0)
327fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		return;
328fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
329fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	if (drv->monitor_ifidx >= 0) {
330fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		nl80211_remove_iface(drv, drv->monitor_ifidx);
331fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		drv->monitor_ifidx = -1;
332fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	}
333fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	if (drv->monitor_sock >= 0) {
334fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		eloop_unregister_read_sock(drv->monitor_sock);
335fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		close(drv->monitor_sock);
336fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		drv->monitor_sock = -1;
337fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	}
338fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt}
339fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
340fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
341fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtint nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
342fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{
343fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	char buf[IFNAMSIZ];
344fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	struct sockaddr_ll ll;
345fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	int optval;
346fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	socklen_t optlen;
347fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
348fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	if (drv->monitor_ifidx >= 0) {
349fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		drv->monitor_refcount++;
350fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Re-use existing monitor interface: refcount=%d",
351fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			   drv->monitor_refcount);
352fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		return 0;
353fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	}
354fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
355fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	if (os_strncmp(drv->first_bss->ifname, "p2p-", 4) == 0) {
356fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		/*
357fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		 * P2P interface name is of the format p2p-%s-%d. For monitor
358fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		 * interface name corresponding to P2P GO, replace "p2p-" with
359fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		 * "mon-" to retain the same interface name length and to
360fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		 * indicate that it is a monitor interface.
361fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		 */
362fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss->ifname + 4);
363fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	} else {
364fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		/* Non-P2P interface with AP functionality. */
365fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss->ifname);
366fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	}
367fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
368fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	buf[IFNAMSIZ - 1] = '\0';
369fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
370fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	drv->monitor_ifidx =
371fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
372fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt				     0, NULL, NULL, 0);
373fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
374fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	if (drv->monitor_ifidx == -EOPNOTSUPP) {
375fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		/*
376fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		 * This is backward compatibility for a few versions of
377fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		 * the kernel only that didn't advertise the right
378fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		 * attributes for the only driver that then supported
379fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		 * AP mode w/o monitor -- ath6kl.
380fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		 */
381fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Driver does not support "
382fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			   "monitor interface type - try to run without it");
383fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		drv->device_ap_sme = 1;
384fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	}
385fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
386fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	if (drv->monitor_ifidx < 0)
387fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		return -1;
388fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
389fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	if (linux_set_iface_flags(drv->global->ioctl_sock, buf, 1))
390fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		goto error;
391fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
392fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	memset(&ll, 0, sizeof(ll));
393fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	ll.sll_family = AF_PACKET;
394fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	ll.sll_ifindex = drv->monitor_ifidx;
395fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
396fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	if (drv->monitor_sock < 0) {
397fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: socket[PF_PACKET,SOCK_RAW] failed: %s",
398fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			   strerror(errno));
399fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		goto error;
400fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	}
401fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
402fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	if (add_monitor_filter(drv->monitor_sock)) {
403fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		wpa_printf(MSG_INFO, "Failed to set socket filter for monitor "
404fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			   "interface; do filtering in user space");
405fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		/* This works, but will cost in performance. */
406fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	}
407fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
408fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	if (bind(drv->monitor_sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
409fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: monitor socket bind failed: %s",
410fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			   strerror(errno));
411fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		goto error;
412fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	}
413fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
414fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	optlen = sizeof(optval);
415fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	optval = 20;
416fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	if (setsockopt
417fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	    (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) {
418fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to set socket priority: %s",
419fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			   strerror(errno));
420fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		goto error;
421fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	}
422fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
423fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read,
424fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt				     drv, NULL)) {
425fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		wpa_printf(MSG_INFO, "nl80211: Could not register monitor read socket");
426fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		goto error;
427fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	}
428fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
429fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	drv->monitor_refcount++;
430fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	return 0;
431fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt error:
432fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	nl80211_remove_monitor_interface(drv);
433fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	return -1;
434fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt}
435fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
436fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
437fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidtint nl80211_send_monitor(struct wpa_driver_nl80211_data *drv,
438fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			 const void *data, size_t len,
439fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			 int encrypt, int noack)
440fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt{
441fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	__u8 rtap_hdr[] = {
442fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		0x00, 0x00, /* radiotap version */
443fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		0x0e, 0x00, /* radiotap length */
444fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */
445fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */
446fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		0x00,       /* padding */
447fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		0x00, 0x00, /* RX and TX flags to indicate that */
448fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		0x00, 0x00, /* this is the injected frame directly */
449fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	};
450fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	struct iovec iov[2] = {
451fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		{
452fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			.iov_base = &rtap_hdr,
453fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			.iov_len = sizeof(rtap_hdr),
454fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		},
455fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		{
456fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			.iov_base = (void *) data,
457fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			.iov_len = len,
458fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		}
459fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	};
460fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	struct msghdr msg = {
461fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		.msg_name = NULL,
462fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		.msg_namelen = 0,
463fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		.msg_iov = iov,
464fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		.msg_iovlen = 2,
465fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		.msg_control = NULL,
466fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		.msg_controllen = 0,
467fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		.msg_flags = 0,
468fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	};
469fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	int res;
470fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	u16 txflags = 0;
471fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
472fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	if (encrypt)
473fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP;
474fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
475fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	if (drv->monitor_sock < 0) {
476fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: No monitor socket available "
477fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt			   "for %s", __func__);
478fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		return -1;
479fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	}
480fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
481fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	if (noack)
482fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		txflags |= IEEE80211_RADIOTAP_F_TX_NOACK;
483fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	WPA_PUT_LE16(&rtap_hdr[12], txflags);
484fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt
485fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	res = sendmsg(drv->monitor_sock, &msg, 0);
486fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	if (res < 0) {
487fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		wpa_printf(MSG_INFO, "nl80211: sendmsg: %s", strerror(errno));
488fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt		return -1;
489fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	}
490fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt	return 0;
491fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt}
492