xref: /openbsd/usr.sbin/hostapd/handle.c (revision 274d7c50)
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 
46 int	 hostapd_handle_frame(struct hostapd_apme *, struct hostapd_frame *,
47 	    u_int8_t *, const u_int);
48 int	 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);
50 void	 hostapd_handle_addr(const u_int32_t, u_int32_t *, u_int8_t *,
51 	    u_int8_t *, struct hostapd_table *);
52 void	 hostapd_handle_ref(u_int, u_int, u_int8_t *, u_int8_t *, u_int8_t *,
53 	    u_int8_t *);
54 int	 hostapd_handle_radiotap(struct hostapd_radiotap *, u_int8_t *,
55 	    const u_int);
56 int	 hostapd_cmp(enum hostapd_op, int, int);
57 
58 int
59 hostapd_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 
73 void
74 hostapd_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 
90 void
91 hostapd_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 
107 int
108 hostapd_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 
279 int
280 hostapd_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 
388 int
389 hostapd_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 
459 int
460 hostapd_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