GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/hostapd/apme.c Lines: 0 211 0.0 %
Date: 2017-11-07 Branches: 0 107 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: apme.c,v 1.16 2015/01/16 06:40:17 deraadt 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_dl.h>
27
#include <net/if_media.h>
28
#include <net/if_arp.h>
29
#include <net/if_llc.h>
30
#include <net/bpf.h>
31
32
#include <netinet/in.h>
33
#include <netinet/if_ether.h>
34
#include <arpa/inet.h>
35
36
#include <net80211/ieee80211_radiotap.h>
37
38
#include <fcntl.h>
39
#include <stdlib.h>
40
#include <stdio.h>
41
#include <string.h>
42
#include <unistd.h>
43
#include <limits.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
}