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