xref: /openbsd/usr.sbin/hostapd/apme.c (revision cb21588b)
1 /*	$OpenBSD: apme.c,v 1.17 2019/05/10 01:29:31 guenther Exp $	*/
2 
3 /*
4  * Copyright (c) 2004, 2005 Reyk Floeter <reyk@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>	/* roundup isclr */
20 #include <sys/ioctl.h>
21 #include <sys/socket.h>
22 #include <sys/time.h>
23 #include <sys/uio.h>
24 
25 #include <net/if.h>
26 #include <net/if_media.h>
27 #include <net/if_arp.h>
28 #include <net/if_llc.h>
29 #include <net/bpf.h>
30 
31 #include <netinet/in.h>
32 #include <netinet/if_ether.h>
33 #include <arpa/inet.h>
34 
35 #include <net80211/ieee80211_radiotap.h>
36 
37 #include <fcntl.h>
38 #include <stdlib.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include <limits.h>
43 
44 #include "hostapd.h"
45 #include "iapp.h"
46 
47 void	 hostapd_apme_frame(struct hostapd_apme *, u_int8_t *, u_int);
48 void	 hostapd_apme_hopper(int, short, void *);
49 
50 int
hostapd_apme_add(struct hostapd_config * cfg,const char * name)51 hostapd_apme_add(struct hostapd_config *cfg, const char *name)
52 {
53 	struct hostapd_apme *apme;
54 
55 	if (hostapd_apme_lookup(cfg, name) != NULL)
56 		return (EEXIST);
57 	if ((apme = (struct hostapd_apme *)
58 	    calloc(1, sizeof(struct hostapd_apme))) == NULL)
59 		return (ENOMEM);
60 	if (strlcpy(apme->a_iface, name, sizeof(apme->a_iface)) >=
61 	    sizeof(apme->a_iface)) {
62 		free(apme);
63 		return (EINVAL);
64 	}
65 
66 	apme->a_cfg = cfg;
67 	apme->a_chanavail = NULL;
68 
69 	TAILQ_INSERT_TAIL(&cfg->c_apmes, apme, a_entries);
70 
71 	hostapd_log(HOSTAPD_LOG_DEBUG,
72 	    "%s: Host AP interface added", apme->a_iface);
73 
74 	return (0);
75 }
76 
77 int
hostapd_apme_deauth(struct hostapd_apme * apme)78 hostapd_apme_deauth(struct hostapd_apme *apme)
79 {
80 	struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg;
81 	struct hostapd_iapp *iapp = &cfg->c_iapp;
82 	u_int8_t buf[sizeof(struct ieee80211_frame) + sizeof(u_int16_t)];
83 	struct ieee80211_frame *wh;
84 
85 	bzero(&buf, sizeof(buf));
86 	wh = (struct ieee80211_frame *)&buf[0];
87 	wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
88 	    IEEE80211_FC0_SUBTYPE_DEAUTH;
89 	wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
90 	memset(&wh->i_addr1, 0xff, IEEE80211_ADDR_LEN);
91 	bcopy(apme->a_bssid, wh->i_addr2, IEEE80211_ADDR_LEN);
92 	bcopy(apme->a_bssid, wh->i_addr3, IEEE80211_ADDR_LEN);
93 	*(u_int16_t *)(wh + 1) = htole16(IEEE80211_REASON_AUTH_EXPIRE);
94 
95 	if (write(apme->a_raw, buf, sizeof(buf)) == -1) {
96 		hostapd_log(HOSTAPD_LOG_VERBOSE,
97 		    "%s/%s: failed to deauthenticate all stations: %s",
98 		    iapp->i_iface, apme->a_iface,
99 		    strerror(errno));
100 		return (EIO);
101 	}
102 
103 	hostapd_log(HOSTAPD_LOG_VERBOSE,
104 	    "%s/%s: deauthenticated all stations",
105 	    apme->a_iface, iapp->i_iface);
106 
107 	return (0);
108 }
109 
110 struct hostapd_apme *
hostapd_apme_lookup(struct hostapd_config * cfg,const char * name)111 hostapd_apme_lookup(struct hostapd_config *cfg, const char *name)
112 {
113 	struct hostapd_apme *apme;
114 
115 	TAILQ_FOREACH(apme, &cfg->c_apmes, a_entries) {
116 		if (strcmp(name, apme->a_iface) == 0)
117 			return (apme);
118 	}
119 
120 	return (NULL);
121 }
122 
123 struct hostapd_apme *
hostapd_apme_addhopper(struct hostapd_config * cfg,const char * name)124 hostapd_apme_addhopper(struct hostapd_config *cfg, const char *name)
125 {
126 	struct hostapd_apme *apme;
127 
128 	if ((apme = hostapd_apme_lookup(cfg, name)) == NULL)
129 		return (NULL);
130 	if (apme->a_chanavail != NULL)
131 		return (NULL);
132 	apme->a_curchan = IEEE80211_CHAN_MAX;
133 	apme->a_maxchan = roundup(IEEE80211_CHAN_MAX, NBBY);
134 	if ((apme->a_chanavail = (u_int8_t *)
135 	    calloc(apme->a_maxchan, sizeof(u_int8_t))) == NULL)
136 		return (NULL);
137 	memset(apme->a_chanavail, 0xff,
138 	    apme->a_maxchan * sizeof(u_int8_t));
139 	(void)strlcpy(apme->a_chanreq.i_name, apme->a_iface, IFNAMSIZ);
140 
141 	return (apme);
142 }
143 
144 void
hostapd_apme_sethopper(struct hostapd_apme * apme,int now)145 hostapd_apme_sethopper(struct hostapd_apme *apme, int now)
146 {
147 	struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg;
148 	struct timeval tv;
149 
150 	bzero(&tv, sizeof(tv));
151 	if (!now)
152 		bcopy(&cfg->c_apme_hopdelay, &tv, sizeof(tv));
153 
154 	if (!evtimer_initialized(&apme->a_chanev))
155 		evtimer_set(&apme->a_chanev, hostapd_apme_hopper, apme);
156 	if (evtimer_add(&apme->a_chanev, &tv) == -1)
157 		hostapd_fatal("failed to add hopper event");
158 }
159 
160 void
hostapd_apme_hopper(int fd,short sig,void * arg)161 hostapd_apme_hopper(int fd, short sig, void *arg)
162 {
163 	struct hostapd_apme *apme = (struct hostapd_apme *)arg;
164 	struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg;
165 	int ret;
166 
167 	if (apme->a_curchan >= IEEE80211_CHAN_MAX)
168 		apme->a_curchan = 0;
169 
170 	do {
171 		if (apme->a_curchan >= IEEE80211_CHAN_MAX)
172 			return;
173 		apme->a_curchan %= IEEE80211_CHAN_MAX;
174 		apme->a_curchan++;
175 	} while (isclr(apme->a_chanavail, apme->a_curchan));
176 
177 	apme->a_chanreq.i_channel = apme->a_curchan;
178 	if ((ret = ioctl(cfg->c_apme_ctl, SIOCS80211CHANNEL,
179 	    &apme->a_chanreq)) != 0) {
180 		hostapd_apme_sethopper(apme, 1);
181 		return;
182 	}
183 
184 	hostapd_log(HOSTAPD_LOG_DEBUG,
185 	    "[priv]: %s setting to channel %d",
186 	    apme->a_iface, apme->a_curchan);
187 
188 	hostapd_apme_sethopper(apme, 0);
189 }
190 
191 void
hostapd_apme_term(struct hostapd_apme * apme)192 hostapd_apme_term(struct hostapd_apme *apme)
193 {
194 	struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg;
195 
196 	/* Remove the channel hopper, if active */
197 	if (apme->a_chanavail != NULL) {
198 		(void)event_del(&apme->a_chanev);
199 		free(apme->a_chanavail);
200 		apme->a_chanavail = NULL;
201 	}
202 
203 	/* Kick a specified Host AP interface */
204 	(void)event_del(&apme->a_ev);
205 	if (close(apme->a_raw))
206 		hostapd_fatal("failed to close: %s\n",
207 		    strerror(errno));
208 
209 	TAILQ_REMOVE(&cfg->c_apmes, apme, a_entries);
210 
211 	/* Remove all dynamic roaming addresses */
212 	if (cfg->c_flags & HOSTAPD_CFG_F_PRIV)
213 		hostapd_roaming_term(apme);
214 
215 	hostapd_log(HOSTAPD_LOG_DEBUG,
216 	    "%s: Host AP interface removed", apme->a_iface);
217 
218 	free(apme);
219 }
220 
221 void
hostapd_apme_input(int fd,short sig,void * arg)222 hostapd_apme_input(int fd, short sig, void *arg)
223 {
224 	struct hostapd_apme *apme = (struct hostapd_apme *)arg;
225 	u_int8_t buf[IAPP_MAXSIZE], *bp, *ep;
226 	struct bpf_hdr *bph;
227 	ssize_t len;
228 
229 	/* Ignore invalid signals */
230 	if (sig != EV_READ)
231 		return;
232 
233 	bzero(&buf, sizeof(buf));
234 
235 	if ((len = read(fd, buf, sizeof(buf))) <
236 	    (ssize_t)sizeof(struct ieee80211_frame))
237 		return;
238 
239 	/*
240 	 * Loop through each frame.
241 	 */
242 
243 	bp = (u_int8_t *)&buf;
244 	ep = bp + len;
245 
246 	while (bp < ep) {
247 		register u_int caplen, hdrlen;
248 
249 		bph = (struct bpf_hdr *)bp;
250 		caplen = bph->bh_caplen;
251 		hdrlen = bph->bh_hdrlen;
252 
253 		/* Process frame */
254 		hostapd_apme_frame(apme, bp + hdrlen, caplen);
255 
256 		bp += BPF_WORDALIGN(caplen + hdrlen);
257 	}
258 }
259 
260 int
hostapd_apme_output(struct hostapd_apme * apme,struct hostapd_ieee80211_frame * frame)261 hostapd_apme_output(struct hostapd_apme *apme,
262     struct hostapd_ieee80211_frame *frame)
263 {
264 	struct iovec iov[2];
265 	int iovcnt;
266 	struct ieee80211_frame wh;
267 
268 	bzero(&wh, sizeof(wh));
269 
270 	switch (frame->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
271 	case IEEE80211_FC1_DIR_NODS:
272 		bcopy(frame->i_from, wh.i_addr2, IEEE80211_ADDR_LEN);
273 		bcopy(frame->i_to, wh.i_addr1, IEEE80211_ADDR_LEN);
274 		bcopy(frame->i_bssid, wh.i_addr3, IEEE80211_ADDR_LEN);
275 		break;
276 	case IEEE80211_FC1_DIR_TODS:
277 		bcopy(frame->i_from, wh.i_addr2, IEEE80211_ADDR_LEN);
278 		bcopy(frame->i_to, wh.i_addr3, IEEE80211_ADDR_LEN);
279 		bcopy(frame->i_bssid, wh.i_addr1, IEEE80211_ADDR_LEN);
280 		break;
281 	case IEEE80211_FC1_DIR_FROMDS:
282 		bcopy(frame->i_from, wh.i_addr3, IEEE80211_ADDR_LEN);
283 		bcopy(frame->i_to, wh.i_addr1, IEEE80211_ADDR_LEN);
284 		bcopy(frame->i_bssid, wh.i_addr2, IEEE80211_ADDR_LEN);
285 		break;
286 	default:
287 	case IEEE80211_FC1_DIR_DSTODS:
288 		return (EINVAL);
289 	}
290 
291 	wh.i_fc[0] = IEEE80211_FC0_VERSION_0 | frame->i_fc[0];
292 	wh.i_fc[1] = frame->i_fc[1];
293 	bcopy(frame->i_dur, wh.i_dur, sizeof(wh.i_dur));
294 	bcopy(frame->i_seq, wh.i_seq, sizeof(wh.i_seq));
295 
296 	iovcnt = 1;
297 	iov[0].iov_base = &wh;
298 	iov[0].iov_len = sizeof(struct ieee80211_frame);
299 
300 	if (frame->i_data != NULL && frame->i_data_len > 0) {
301 		iovcnt = 2;
302 		iov[1].iov_base = frame->i_data;
303 		iov[1].iov_len = frame->i_data_len;
304 	}
305 
306 	if (writev(apme->a_raw, iov, iovcnt) == -1)
307 		return (errno);
308 
309 	return (0);
310 }
311 
312 int
hostapd_apme_offset(struct hostapd_apme * apme,u_int8_t * buf,const u_int len)313 hostapd_apme_offset(struct hostapd_apme *apme,
314     u_int8_t *buf, const u_int len)
315 {
316 	struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg;
317 	struct ieee80211_radiotap_header *rh;
318 	u_int rh_len;
319 
320 	if (cfg->c_apme_dlt == DLT_IEEE802_11)
321 		return (0);
322 	else if (cfg->c_apme_dlt != DLT_IEEE802_11_RADIO)
323 		return (-1);
324 
325 	if (len < sizeof(struct ieee80211_radiotap_header))
326 		return (-1);
327 
328 	rh = (struct ieee80211_radiotap_header*)buf;
329 	rh_len = letoh16(rh->it_len);
330 
331 	if (rh->it_version != 0)
332 		return (-1);
333 	if (len <= rh_len)
334 		return (-1);
335 
336 	return ((int)rh_len);
337 }
338 
339 void
hostapd_apme_frame(struct hostapd_apme * apme,u_int8_t * buf,u_int len)340 hostapd_apme_frame(struct hostapd_apme *apme, u_int8_t *buf, u_int len)
341 {
342 	struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg;
343 	struct hostapd_iapp *iapp = &cfg->c_iapp;
344 	struct hostapd_apme *other_apme;
345 	struct hostapd_node node;
346 	struct ieee80211_frame *wh;
347 	int offset;
348 
349 	if ((offset = hostapd_apme_offset(apme, buf, len)) < 0)
350 		return;
351 	wh = (struct ieee80211_frame *)(buf + offset);
352 
353 	/* Ignore short frames or fragments */
354 	if (len < sizeof(struct ieee80211_frame))
355 		return;
356 
357 	/* Handle received frames */
358 	if ((hostapd_handle_input(apme, buf, len) ==
359 	    (HOSTAPD_FRAME_F_RET_SKIP >> HOSTAPD_FRAME_F_RET_S)) ||
360 	    cfg->c_flags & HOSTAPD_CFG_F_IAPP_PASSIVE)
361 		return;
362 
363 	/*
364 	 * Only accept local association response frames, ...
365 	 */
366 	if (!((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) ==
367 	    IEEE80211_FC1_DIR_NODS &&
368 	    (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
369 	    IEEE80211_FC0_TYPE_MGT &&
370 	    (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
371 	    IEEE80211_FC0_SUBTYPE_ASSOC_RESP))
372 		return;
373 
374 	/*
375 	 * ...sent by the Host AP (addr2) to our BSSID (addr3)
376 	 */
377 	if (bcmp(wh->i_addr2, apme->a_bssid, IEEE80211_ADDR_LEN) != 0 ||
378 	    bcmp(wh->i_addr3, apme->a_bssid, IEEE80211_ADDR_LEN) != 0)
379 		return;
380 
381 	cfg->c_stats.cn_rx_apme++;
382 
383 	/*
384 	 * Double-check if the station got associated to our Host AP
385 	 */
386 	bcopy(wh->i_addr1, node.ni_macaddr, IEEE80211_ADDR_LEN);
387 	if (hostapd_priv_apme_getnode(apme, &node) != 0) {
388 		hostapd_log(HOSTAPD_LOG_DEBUG,
389 		    "%s: invalid association from %s on the Host AP",
390 		    apme->a_iface, etheraddr_string(wh->i_addr1));
391 		return;
392 	}
393 	cfg->c_stats.cn_tx_apme++;
394 
395 	/*
396 	 * Delete node on other attached Host APs
397 	 */
398 	TAILQ_FOREACH(other_apme, &cfg->c_apmes, a_entries) {
399 		if (apme == other_apme)
400 			continue;
401 		if (iapp->i_flags & HOSTAPD_IAPP_F_ROAMING)
402 			(void)hostapd_roaming_del(other_apme, &node);
403 		if (hostapd_apme_delnode(other_apme, &node) == 0)
404 			cfg->c_stats.cn_tx_apme++;
405 	}
406 
407 	if (iapp->i_flags & HOSTAPD_IAPP_F_ROAMING)
408 		(void)hostapd_roaming_add(apme, &node);
409 
410 	(void)hostapd_iapp_add_notify(apme, &node);
411 }
412 
413 void
hostapd_apme_init(struct hostapd_apme * apme)414 hostapd_apme_init(struct hostapd_apme *apme)
415 {
416 	struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg;
417 	u_int i, dlt;
418 	struct ifreq ifr;
419 
420 	apme->a_raw = hostapd_bpf_open(O_RDWR);
421 
422 	apme->a_rawlen = IAPP_MAXSIZE;
423 	if (ioctl(apme->a_raw, BIOCSBLEN, &apme->a_rawlen) == -1)
424 		hostapd_fatal("failed to set BPF buffer len \"%s\": %s\n",
425 		    apme->a_iface, strerror(errno));
426 
427 	i = 1;
428 	if (ioctl(apme->a_raw, BIOCIMMEDIATE, &i) == -1)
429 		hostapd_fatal("failed to set BPF immediate mode on \"%s\": "
430 		    "%s\n", apme->a_iface, strerror(errno));
431 
432 	bzero(&ifr, sizeof(struct ifreq));
433 	(void)strlcpy(ifr.ifr_name, apme->a_iface, sizeof(ifr.ifr_name));
434 
435 	/* This may fail, ignore it */
436 	(void)ioctl(apme->a_raw, BIOCPROMISC, NULL);
437 
438 	/* Associate the wireless network interface to the BPF descriptor */
439 	if (ioctl(apme->a_raw, BIOCSETIF, &ifr) == -1)
440 		hostapd_fatal("failed to set BPF interface \"%s\": %s\n",
441 		    apme->a_iface, strerror(errno));
442 
443 	dlt = cfg->c_apme_dlt;
444 	if (ioctl(apme->a_raw, BIOCSDLT, &dlt) == -1)
445 		hostapd_fatal("failed to set BPF link type on \"%s\": %s\n",
446 		    apme->a_iface, strerror(errno));
447 
448 	/* Lock the BPF descriptor, no further configuration */
449 	if (ioctl(apme->a_raw, BIOCLOCK, NULL) == -1)
450 		hostapd_fatal("failed to lock BPF interface on \"%s\": %s\n",
451 		    apme->a_iface, strerror(errno));
452 }
453 
454 int
hostapd_apme_addnode(struct hostapd_apme * apme,struct hostapd_node * node)455 hostapd_apme_addnode(struct hostapd_apme *apme, struct hostapd_node *node)
456 {
457 	return (hostapd_priv_apme_setnode(apme, node, 1));
458 }
459 
460 int
hostapd_apme_delnode(struct hostapd_apme * apme,struct hostapd_node * node)461 hostapd_apme_delnode(struct hostapd_apme *apme, struct hostapd_node *node)
462 {
463 	return (hostapd_priv_apme_setnode(apme, node, 0));
464 }
465