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