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  | 
     | 
     | 
    }  |