1 /*
2 * Driver interaction with Linux nl80211/cfg80211 - AP monitor interface
3 * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
4 * Copyright (c) 2003-2004, Instant802 Networks, Inc.
5 * Copyright (c) 2005-2006, Devicescape Software, Inc.
6 * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
7 * Copyright (c) 2009-2010, Atheros Communications
8 *
9 * This software may be distributed under the terms of the BSD license.
10 * See README for more details.
11 */
12
13 #include "includes.h"
14 #include <netpacket/packet.h>
15 #include <linux/filter.h>
16
17 #include "utils/common.h"
18 #include "utils/eloop.h"
19 #include "common/ieee802_11_defs.h"
20 #include "common/ieee802_11_common.h"
21 #include "linux_ioctl.h"
22 #include "radiotap_iter.h"
23 #include "driver_nl80211.h"
24
25
26 #ifdef CONFIG_TESTING_OPTIONS
27
28 static struct sock_filter msock_filter_insns[] = {
29 /* return 0 == "DROP", we don't want RX */
30 BPF_STMT(BPF_RET | BPF_K, 0),
31 };
32
33 static const struct sock_fprog msock_filter = {
34 .len = ARRAY_SIZE(msock_filter_insns),
35 .filter = msock_filter_insns,
36 };
37
38
add_monitor_filter(int s)39 static int add_monitor_filter(int s)
40 {
41 if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER,
42 &msock_filter, sizeof(msock_filter))) {
43 wpa_printf(MSG_ERROR, "nl80211: setsockopt(SO_ATTACH_FILTER) failed: %s",
44 strerror(errno));
45 return -1;
46 }
47
48 return 0;
49 }
50
51
52 static void
nl80211_remove_monitor_interface(struct wpa_driver_nl80211_data * drv,int ifidx,int sock)53 nl80211_remove_monitor_interface(struct wpa_driver_nl80211_data *drv,
54 int ifidx, int sock)
55 {
56 wpa_printf(MSG_DEBUG, "nl80211: Remove monitor interface");
57
58 if (ifidx >= 0)
59 nl80211_remove_iface(drv, ifidx);
60 if (sock >= 0)
61 close(sock);
62 }
63
64
nl80211_create_monitor_interface(struct wpa_driver_nl80211_data * drv,int * ifidx,int * sock)65 static int nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv,
66 int *ifidx, int *sock)
67 {
68 char buf[IFNAMSIZ];
69 struct sockaddr_ll ll;
70 int optval;
71 socklen_t optlen;
72
73 *ifidx = -1;
74 *sock = -1;
75
76 if (os_strncmp(drv->first_bss->ifname, "p2p-", 4) == 0) {
77 /*
78 * P2P interface name is of the format p2p-%s-%d. For monitor
79 * interface name corresponding to P2P GO, replace "p2p-" with
80 * "mon-" to retain the same interface name length and to
81 * indicate that it is a monitor interface.
82 */
83 snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss->ifname + 4);
84 } else {
85 int ret;
86
87 /* Non-P2P interface with AP functionality. */
88 ret = os_snprintf(buf, IFNAMSIZ, "mon.%s",
89 drv->first_bss->ifname);
90 if (ret >= (int) sizeof(buf))
91 wpa_printf(MSG_DEBUG,
92 "nl80211: Monitor interface name has been truncated to %s",
93 buf);
94 else if (ret < 0)
95 return ret;
96 }
97
98 buf[IFNAMSIZ - 1] = '\0';
99
100 *ifidx = nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
101 0, NULL, NULL, 0);
102
103 if (*ifidx < 0)
104 return -1;
105
106 if (linux_set_iface_flags(drv->global->ioctl_sock, buf, 1))
107 goto error;
108
109 memset(&ll, 0, sizeof(ll));
110 ll.sll_family = AF_PACKET;
111 ll.sll_ifindex = *ifidx;
112 *sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
113 if (*sock < 0) {
114 wpa_printf(MSG_ERROR, "nl80211: socket[PF_PACKET,SOCK_RAW] failed: %s",
115 strerror(errno));
116 goto error;
117 }
118
119 if (add_monitor_filter(*sock)) {
120 wpa_printf(MSG_INFO, "Failed to set socket filter for monitor "
121 "interface; do filtering in user space");
122 /* This works, but will cost in performance. */
123 }
124
125 if (bind(*sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
126 wpa_printf(MSG_ERROR, "nl80211: monitor socket bind failed: %s",
127 strerror(errno));
128 goto error;
129 }
130
131 optlen = sizeof(optval);
132 optval = 20;
133 if (setsockopt(*sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) {
134 wpa_printf(MSG_ERROR, "nl80211: Failed to set socket priority: %s",
135 strerror(errno));
136 goto error;
137 }
138
139 return 0;
140 error:
141 nl80211_remove_monitor_interface(drv, *ifidx, *sock);
142 return -1;
143 }
144
145
_nl80211_send_monitor(int monitor_sock,const void * data,size_t len,int encrypt,int noack)146 static int _nl80211_send_monitor(int monitor_sock,
147 const void *data, size_t len,
148 int encrypt, int noack)
149 {
150 __u8 rtap_hdr[] = {
151 0x00, 0x00, /* radiotap version */
152 0x0e, 0x00, /* radiotap length */
153 0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */
154 IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */
155 0x00, /* padding */
156 0x00, 0x00, /* RX and TX flags to indicate that */
157 0x00, 0x00, /* this is the injected frame directly */
158 };
159 struct iovec iov[2] = {
160 {
161 .iov_base = &rtap_hdr,
162 .iov_len = sizeof(rtap_hdr),
163 },
164 {
165 .iov_base = (void *) data,
166 .iov_len = len,
167 }
168 };
169 struct msghdr msg = {
170 .msg_name = NULL,
171 .msg_namelen = 0,
172 .msg_iov = iov,
173 .msg_iovlen = 2,
174 .msg_control = NULL,
175 .msg_controllen = 0,
176 .msg_flags = 0,
177 };
178 int res;
179 u16 txflags = 0;
180
181 if (encrypt)
182 rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP;
183
184 if (noack)
185 txflags |= IEEE80211_RADIOTAP_F_TX_NOACK;
186 WPA_PUT_LE16(&rtap_hdr[12], txflags);
187
188 res = sendmsg(monitor_sock, &msg, 0);
189 if (res < 0) {
190 wpa_printf(MSG_INFO, "nl80211: sendmsg: %s", strerror(errno));
191 return -1;
192 }
193 return 0;
194 }
195
196
nl80211_send_monitor(struct wpa_driver_nl80211_data * drv,const void * data,size_t len,int encrypt,int noack)197 int nl80211_send_monitor(struct wpa_driver_nl80211_data *drv,
198 const void *data, size_t len,
199 int encrypt, int noack)
200 {
201 int res, ifidx, sock;
202
203 res = nl80211_create_monitor_interface(drv, &ifidx, &sock);
204 if (res < 0)
205 return res;
206
207 res = _nl80211_send_monitor(sock, data, len, encrypt, noack);
208 nl80211_remove_monitor_interface(drv, ifidx, sock);
209 return res;
210 }
211
212 #endif /* CONFIG_TESTING_OPTIONS */
213