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

Line Branch Exec Source
1
/*	$OpenBSD: handle.c,v 1.12 2015/01/16 06:40:17 deraadt Exp $	*/
2
3
/*
4
 * Copyright (c) 2005, 2006 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/ioctl.h>
20
#include <sys/types.h>
21
#include <sys/socket.h>
22
#include <sys/time.h>
23
24
#include <net/if.h>
25
#include <net/if_dl.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.h>
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
47
int	 hostapd_handle_frame(struct hostapd_apme *, struct hostapd_frame *,
48
	    u_int8_t *, const u_int);
49
int	 hostapd_handle_action(struct hostapd_apme *, struct hostapd_frame *,
50
	    u_int8_t *, u_int8_t *, u_int8_t *, u_int8_t *, const u_int);
51
void	 hostapd_handle_addr(const u_int32_t, u_int32_t *, u_int8_t *,
52
	    u_int8_t *, struct hostapd_table *);
53
void	 hostapd_handle_ref(u_int, u_int, u_int8_t *, u_int8_t *, u_int8_t *,
54
	    u_int8_t *);
55
int	 hostapd_handle_radiotap(struct hostapd_radiotap *, u_int8_t *,
56
	    const u_int);
57
int	 hostapd_cmp(enum hostapd_op, int, int);
58
59
int
60
hostapd_handle_input(struct hostapd_apme *apme, u_int8_t *buf, u_int len)
61
{
62
	struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg;
63
	struct hostapd_frame *frame;
64
	int ret;
65
66
	TAILQ_FOREACH(frame, &cfg->c_frames, f_entries) {
67
		if ((ret = hostapd_handle_frame(apme, frame, buf, len)) != 0)
68
			return (ret);
69
	}
70
71
	return (0);
72
}
73
74
void
75
hostapd_handle_addr(const u_int32_t mask, u_int32_t *flags, u_int8_t *addr,
76
    u_int8_t *maddr, struct hostapd_table *table)
77
{
78
	int ret = 0;
79
80
	if ((*flags & mask) & HOSTAPD_FRAME_TABLE) {
81
		if (hostapd_entry_lookup(table, addr) == NULL)
82
			ret = 1;
83
	} else if (bcmp(addr, maddr, IEEE80211_ADDR_LEN) != 0)
84
			ret = 1;
85
86
	if ((ret == 1 && (*flags & mask) & HOSTAPD_FRAME_N) ||
87
	    (ret == 0 && ((*flags & mask) & HOSTAPD_FRAME_N) == 0))
88
		*flags &= ~mask;
89
}
90
91
void
92
hostapd_handle_ref(u_int flags, u_int shift, u_int8_t *wfrom, u_int8_t *wto,
93
    u_int8_t *wbssid, u_int8_t *addr)
94
{
95
	if (flags & (HOSTAPD_ACTION_F_REF_FROM << shift))
96
		bcopy(wfrom, addr, IEEE80211_ADDR_LEN);
97
	else if (flags & (HOSTAPD_ACTION_F_REF_TO << shift))
98
		bcopy(wto, addr, IEEE80211_ADDR_LEN);
99
	else if (flags & (HOSTAPD_ACTION_F_REF_BSSID << shift))
100
		bcopy(wbssid, addr, IEEE80211_ADDR_LEN);
101
	else if (flags & (HOSTAPD_ACTION_F_REF_RANDOM << shift)) {
102
		hostapd_randval(addr, IEEE80211_ADDR_LEN);
103
		/* Avoid multicast/broadcast addresses */
104
		addr[0] &= ~0x1;
105
	}
106
}
107
108
int
109
hostapd_handle_frame(struct hostapd_apme *apme, struct hostapd_frame *frame,
110
    u_int8_t *buf, const u_int len)
111
{
112
	struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg;
113
	struct ieee80211_frame *wh;
114
	struct hostapd_ieee80211_frame *mh;
115
	struct hostapd_radiotap rtap;
116
	u_int8_t *wfrom, *wto, *wbssid;
117
	struct timeval t_now;
118
	u_int32_t flags;
119
	int offset, min_rate = 0, val;
120
121
	if ((offset = hostapd_apme_offset(apme, buf, len)) < 0)
122
		return (0);
123
	wh = (struct ieee80211_frame *)(buf + offset);
124
125
	mh = &frame->f_frame;
126
	flags = frame->f_flags;
127
128
	/* Get timestamp */
129
	if (gettimeofday(&t_now, NULL) == -1)
130
		hostapd_fatal("gettimeofday");
131
132
	/* Handle optional limit */
133
	if (frame->f_limit.tv_sec || frame->f_limit.tv_usec) {
134
		if (timercmp(&t_now, &frame->f_then, <))
135
			return (0);
136
		timeradd(&t_now, &frame->f_limit, &frame->f_then);
137
	}
138
139
	switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
140
	case IEEE80211_FC1_DIR_NODS:
141
		wfrom = wh->i_addr2;
142
		wto = wh->i_addr1;
143
		wbssid = wh->i_addr3;
144
		break;
145
	case IEEE80211_FC1_DIR_TODS:
146
		wfrom = wh->i_addr2;
147
		wto = wh->i_addr3;
148
		wbssid = wh->i_addr1;
149
		break;
150
	case IEEE80211_FC1_DIR_FROMDS:
151
		wfrom = wh->i_addr3;
152
		wto = wh->i_addr1;
153
		wbssid = wh->i_addr2;
154
		break;
155
	default:
156
	case IEEE80211_FC1_DIR_DSTODS:
157
		return (0);
158
	}
159
160
	if (flags & HOSTAPD_FRAME_F_APME_M) {
161
		if (frame->f_apme == NULL)
162
			return (0);
163
		/* Match hostap interface */
164
		if ((flags & HOSTAPD_FRAME_F_APME &&
165
		    apme == frame->f_apme) ||
166
		    (flags & HOSTAPD_FRAME_F_APME_N &&
167
		    apme != frame->f_apme))
168
			flags &= ~HOSTAPD_FRAME_F_APME_M;
169
	}
170
171
	if (flags & HOSTAPD_FRAME_F_TYPE) {
172
		/* type $type */
173
		if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
174
		    (mh->i_fc[0] & IEEE80211_FC0_TYPE_MASK))
175
			flags &= ~HOSTAPD_FRAME_F_TYPE;
176
	} else if (flags & HOSTAPD_FRAME_F_TYPE_N) {
177
		/* type !$type */
178
		if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) !=
179
		    (mh->i_fc[0] & IEEE80211_FC0_TYPE_MASK))
180
			flags &= ~HOSTAPD_FRAME_F_TYPE_N;
181
	}
182
183
	if (flags & HOSTAPD_FRAME_F_SUBTYPE) {
184
		/* subtype $subtype */
185
		if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
186
		    (mh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK))
187
			flags &= ~HOSTAPD_FRAME_F_SUBTYPE;
188
	} else if (flags & HOSTAPD_FRAME_F_SUBTYPE_N) {
189
		/* subtype !$subtype */
190
		if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) !=
191
		    (mh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK))
192
			flags &= ~HOSTAPD_FRAME_F_SUBTYPE_N;
193
	}
194
195
	if (flags & HOSTAPD_FRAME_F_DIR) {
196
		/* dir $dir */
197
		if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) ==
198
		    (mh->i_fc[1] & IEEE80211_FC1_DIR_MASK))
199
			flags &= ~HOSTAPD_FRAME_F_DIR;
200
	} else if (flags & HOSTAPD_FRAME_F_DIR_N) {
201
		/* dir !$dir */
202
		if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) !=
203
		    (mh->i_fc[1] & IEEE80211_FC1_DIR_MASK))
204
			flags &= ~HOSTAPD_FRAME_F_DIR_N;
205
	}
206
207
	/* from/to/bssid [!]$addr/<table> */
208
	hostapd_handle_addr(HOSTAPD_FRAME_F_FROM_M, &flags, wfrom,
209
	    mh->i_from, frame->f_from);
210
	hostapd_handle_addr(HOSTAPD_FRAME_F_TO_M, &flags, wto,
211
	    mh->i_to, frame->f_to);
212
	hostapd_handle_addr(HOSTAPD_FRAME_F_BSSID_M, &flags, wbssid,
213
	    mh->i_bssid, frame->f_bssid);
214
215
	/* parse the optional radiotap header if required */
216
	if (frame->f_radiotap) {
217
		if (hostapd_handle_radiotap(&rtap, buf, len) != 0)
218
			return (0);
219
		else if ((rtap.r_present & frame->f_radiotap) !=
220
		    frame->f_radiotap) {
221
			cfg->c_stats.cn_rtap_miss++;
222
			return (0);
223
		}
224
		if (flags & HOSTAPD_FRAME_F_RSSI && rtap.r_max_rssi) {
225
			val = ((float)rtap.r_rssi / rtap.r_max_rssi) * 100;
226
			if (hostapd_cmp(frame->f_rssi_op,
227
			    val, frame->f_rssi))
228
				flags &= ~HOSTAPD_FRAME_F_RSSI;
229
		}
230
		if (flags & HOSTAPD_FRAME_F_RATE) {
231
			val = rtap.r_txrate;
232
			if (hostapd_cmp(frame->f_txrate_op,
233
			    val, frame->f_txrate))
234
				flags &= ~HOSTAPD_FRAME_F_RATE;
235
		}
236
		if (flags & HOSTAPD_FRAME_F_CHANNEL) {
237
			val = rtap.r_chan;
238
			if (hostapd_cmp(frame->f_chan_op,
239
			    val, frame->f_chan))
240
				flags &= ~HOSTAPD_FRAME_F_CHANNEL;
241
		}
242
	}
243
244
	/* Handle if frame matches */
245
	if ((flags & HOSTAPD_FRAME_F_M) != 0)
246
		return (0);
247
248
	/* Handle optional minimal rate */
249
	if (frame->f_rate && frame->f_rate_intval) {
250
		frame->f_rate_delay = t_now.tv_sec - frame->f_last.tv_sec;
251
		if (frame->f_rate_delay < frame->f_rate_intval) {
252
			frame->f_rate_cnt++;
253
			if (frame->f_rate_cnt < frame->f_rate)
254
				min_rate = 1;
255
		} else {
256
			min_rate = 1;
257
			frame->f_rate_cnt = 0;
258
		}
259
	}
260
261
	/* Update timestamp for the last match of this event */
262
	if (frame->f_rate_cnt == 0 || min_rate == 0)
263
		bcopy(&t_now, &frame->f_last, sizeof(struct timeval));
264
265
	/* Return if the minimal rate is not reached, yet */
266
	if (min_rate)
267
		return (0);
268
269
	if (hostapd_handle_action(apme, frame, wfrom, wto, wbssid, buf,
270
	    len) != 0)
271
		return (0);
272
273
	/* Reset minimal rate counter after successfully handled the frame */
274
	frame->f_rate_cnt = 0;
275
276
	return ((frame->f_flags & HOSTAPD_FRAME_F_RET_M) >>
277
	    HOSTAPD_FRAME_F_RET_S);
278
}
279
280
int
281
hostapd_handle_action(struct hostapd_apme *apme, struct hostapd_frame *frame,
282
    u_int8_t *wfrom, u_int8_t *wto, u_int8_t *wbssid, u_int8_t *buf,
283
    const u_int len)
284
{
285
	struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg;
286
	struct hostapd_iapp *iapp = &cfg->c_iapp;
287
	struct hostapd_action_data *action = &frame->f_action_data;
288
	struct hostapd_node node;
289
	u_int8_t *lladdr = NULL;
290
	int ret = 0, offset;
291
292
	switch (frame->f_action) {
293
	case HOSTAPD_ACTION_RADIOTAP:
294
		/* Send IAPP frame with radiotap/pcap payload */
295
		if ((ret = hostapd_iapp_radiotap(apme, buf, len)) != 0)
296
			return (ret);
297
298
		if ((frame->f_action_flags & HOSTAPD_ACTION_VERBOSE) == 0)
299
			return (0);
300
301
		hostapd_log(HOSTAPD_LOG,
302
		    "%s: sent IAPP frame HOSTAPD_%s (%u bytes)",
303
		    iapp->i_iface, cfg->c_apme_dlt ==
304
		    DLT_IEEE802_11_RADIO ? "RADIOTAP" : "PCAP", len);
305
		break;
306
307
	case HOSTAPD_ACTION_LOG:
308
		/* Log frame to syslog/stderr */
309
		if (frame->f_rate && frame->f_rate_intval) {
310
			hostapd_printf("%s: (rate: %ld/%ld sec) ",
311
			    apme->a_iface, frame->f_rate_cnt,
312
			    frame->f_rate_delay + 1);
313
		} else
314
			hostapd_printf("%s: ", apme->a_iface);
315
316
		hostapd_print_ieee80211(cfg->c_apme_dlt, frame->f_action_flags &
317
		    HOSTAPD_ACTION_VERBOSE, buf, len);
318
319
		/* Flush output buffer */
320
		hostapd_printf(NULL);
321
		break;
322
323
	case HOSTAPD_ACTION_DELNODE:
324
	case HOSTAPD_ACTION_ADDNODE:
325
		bzero(&node, sizeof(node));
326
327
		if (action->a_flags & HOSTAPD_ACTION_F_REF_FROM)
328
			lladdr = wfrom;
329
		else if (action->a_flags & HOSTAPD_ACTION_F_REF_TO)
330
			lladdr = wto;
331
		else if (action->a_flags & HOSTAPD_ACTION_F_REF_BSSID)
332
			lladdr = wbssid;
333
		else
334
			lladdr = action->a_lladdr;
335
336
		bcopy(lladdr, &node.ni_macaddr, IEEE80211_ADDR_LEN);
337
338
		if (frame->f_action == HOSTAPD_ACTION_DELNODE)
339
			ret = hostapd_apme_delnode(apme, &node);
340
		else
341
			ret = hostapd_apme_addnode(apme, &node);
342
343
		if (ret != 0)  {
344
			hostapd_log(HOSTAPD_LOG_DEBUG,
345
			    "%s: node add/delete %s failed: %s",
346
			    apme->a_iface, etheraddr_string(lladdr),
347
			    strerror(ret));
348
		}
349
		break;
350
351
	case HOSTAPD_ACTION_NONE:
352
		/* Nothing */
353
		break;
354
355
	case HOSTAPD_ACTION_RESEND:
356
		/* Resend received raw IEEE 802.11 frame */
357
		if ((offset = hostapd_apme_offset(apme, buf, len)) < 0)
358
			return (EINVAL);
359
		if (write(apme->a_raw, buf + offset, len - offset) == -1)
360
			ret = errno;
361
		break;
362
363
	case HOSTAPD_ACTION_FRAME:
364
		if (action->a_flags & HOSTAPD_ACTION_F_REF_M) {
365
			hostapd_handle_ref(action->a_flags &
366
			    HOSTAPD_ACTION_F_REF_FROM_M,
367
			    HOSTAPD_ACTION_F_REF_FROM_S, wfrom, wto, wbssid,
368
			    action->a_frame.i_from);
369
			hostapd_handle_ref(action->a_flags &
370
			    HOSTAPD_ACTION_F_REF_TO_M,
371
			    HOSTAPD_ACTION_F_REF_TO_S, wfrom, wto, wbssid,
372
			    action->a_frame.i_to);
373
			hostapd_handle_ref(action->a_flags &
374
			    HOSTAPD_ACTION_F_REF_BSSID_M,
375
			    HOSTAPD_ACTION_F_REF_BSSID_S, wfrom, wto, wbssid,
376
			    action->a_frame.i_bssid);
377
		}
378
379
		/* Send a raw IEEE 802.11 frame */
380
		return (hostapd_apme_output(apme, &action->a_frame));
381
382
	default:
383
		return (0);
384
	}
385
386
	return (ret);
387
}
388
389
int
390
hostapd_handle_radiotap(struct hostapd_radiotap *rtap,
391
    u_int8_t *buf, const u_int len)
392
{
393
	struct ieee80211_radiotap_header *rh =
394
	    (struct ieee80211_radiotap_header*)buf;
395
	u_int8_t *t, *ptr = NULL;
396
	u_int rh_len;
397
	const u_int8_t *snapend = buf + len;
398
399
	TCHECK(*rh);
400
401
	rh_len = letoh16(rh->it_len);
402
	if (rh->it_version != 0)
403
		return (EINVAL);
404
	if (len <= rh_len)
405
		goto trunc;
406
407
	bzero(rtap, sizeof(struct hostapd_radiotap));
408
409
	t = (u_int8_t*)buf + sizeof(struct ieee80211_radiotap_header);
410
	if ((rtap->r_present = letoh32(rh->it_present)) == 0)
411
		return (0);
412
413
#define RADIOTAP(_x, _len)						\
414
	if (rtap->r_present & HOSTAPD_RADIOTAP_F(_x)) {			\
415
		TCHECK2(*t, _len);					\
416
		ptr = t;						\
417
		t += _len;						\
418
	} else								\
419
		ptr = NULL;
420
421
	/* radiotap doesn't use TLV header fields, ugh */
422
	RADIOTAP(TSFT, 8);
423
	RADIOTAP(FLAGS, 1);
424
425
	RADIOTAP(RATE, 1);
426
	if (ptr != NULL) {
427
		rtap->r_txrate = *(u_int8_t *)ptr;
428
	}
429
430
	RADIOTAP(CHANNEL, 4);
431
	if (ptr != NULL) {
432
		rtap->r_chan = letoh16(*(u_int16_t*)ptr);
433
		rtap->r_chan_flags = letoh16(*(u_int16_t*)ptr + 1);
434
	}
435
436
	RADIOTAP(FHSS, 2);
437
	RADIOTAP(DBM_ANTSIGNAL, 1);
438
	RADIOTAP(DBM_ANTNOISE, 1);
439
	RADIOTAP(LOCK_QUALITY, 2);
440
	RADIOTAP(TX_ATTENUATION, 2);
441
	RADIOTAP(DB_TX_ATTENUATION, 2);
442
	RADIOTAP(DBM_TX_POWER, 1);
443
	RADIOTAP(ANTENNA, 1);
444
	RADIOTAP(DB_ANTSIGNAL, 1);
445
	RADIOTAP(DB_ANTNOISE, 1);
446
	RADIOTAP(FCS, 4);
447
448
	RADIOTAP(RSSI, 2);
449
	if (ptr != NULL) {
450
		rtap->r_rssi = *(u_int8_t *)ptr;
451
		rtap->r_max_rssi = *(u_int8_t *)ptr + 1;
452
	}
453
454
	return (0);
455
456
 trunc:
457
	return (EINVAL);
458
}
459
460
int
461
hostapd_cmp(enum hostapd_op op, int val1, int val2)
462
{
463
	if ((op == HOSTAPD_OP_EQ && val1 == val2) ||
464
	    (op == HOSTAPD_OP_NE && val1 != val2) ||
465
	    (op == HOSTAPD_OP_LE && val1 <= val2) ||
466
	    (op == HOSTAPD_OP_LT && val1 <  val2) ||
467
	    (op == HOSTAPD_OP_GE && val1 >= val2) ||
468
	    (op == HOSTAPD_OP_GT && val1 >  val2))
469
		return (1);
470
	return (0);
471
}