root/usr.sbin/hostapd/hostapd.h
/*      $OpenBSD: hostapd.h,v 1.21 2015/01/16 06:40:17 deraadt Exp $    */

/*
 * Copyright (c) 2004, 2005 Reyk Floeter <reyk@openbsd.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef _HOSTAPD_H
#define _HOSTAPD_H

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/tree.h>

#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <errno.h>
#include <event.h>
#include <syslog.h>

#include <net80211/ieee80211.h>
#include <net80211/ieee80211_ioctl.h>

/*
 * hostapd (IAPP) <-> Host AP (APME)
 */

struct hostapd_node {
        u_int8_t        ni_macaddr[IEEE80211_ADDR_LEN];
        u_int8_t        ni_bssid[IEEE80211_ADDR_LEN];
        u_int32_t       ni_associd;
        u_int16_t       ni_capinfo;
        u_int16_t       ni_flags;
        u_int16_t       ni_rxseq;
        u_int16_t       ni_rssi;
};

/*
 * IAPP -> switches (LLC)
 */

struct hostapd_llc {
        struct ether_header x_hdr;
        struct llc x_llc;
} __packed;

#define IAPP_LLC        LLC_XID
#define IAPP_LLC_XID    0x81
#define IAPP_LLC_CLASS  1
#define IAPP_LLC_WINDOW 1 << 1

/*
 * hostapd configuration
 */

struct hostapd_counter {
        u_int64_t       cn_tx_llc;      /* sent LLC messages */
        u_int64_t       cn_rx_iapp;     /* received IAPP messages */
        u_int64_t       cn_tx_iapp;     /* sent IAPP messages */
        u_int64_t       cn_rx_apme;     /* received Host AP messages */
        u_int64_t       cn_tx_apme;     /* sent Host AP messages */
        u_int64_t       cn_rtap_miss;   /* missing radiotap field */
};

#define HOSTAPD_ENTRY_MASK_ADD(_a, _m)  do {                                    \
        (_a)[0] &= (_m)[0];                                                     \
        (_a)[1] &= (_m)[1];                                                     \
        (_a)[2] &= (_m)[2];                                                     \
        (_a)[3] &= (_m)[3];                                                     \
        (_a)[4] &= (_m)[4];                                                     \
        (_a)[5] &= (_m)[5];                                                     \
} while (0);
#define HOSTAPD_ENTRY_MASK_MATCH(_e, _b)        (                               \
        ((_e)->e_lladdr[0] == ((_b)[0] & (_e)->e_addr.a_mask[0])) &&            \
        ((_e)->e_lladdr[1] == ((_b)[1] & (_e)->e_addr.a_mask[1])) &&            \
        ((_e)->e_lladdr[2] == ((_b)[2] & (_e)->e_addr.a_mask[2])) &&            \
        ((_e)->e_lladdr[3] == ((_b)[3] & (_e)->e_addr.a_mask[3])) &&            \
        ((_e)->e_lladdr[4] == ((_b)[4] & (_e)->e_addr.a_mask[4])) &&            \
        ((_e)->e_lladdr[5] == ((_b)[5] & (_e)->e_addr.a_mask[5]))               \
)

struct hostapd_inaddr {
        sa_family_t             in_af;
        union {
                struct in_addr  v4;
                struct in6_addr v6;
        } in_v;
        int                     in_netmask;
};

#define in_v4                   in_v.v4
#define in_v6                   in_v.v6

struct hostapd_entry {
        u_int8_t                        e_lladdr[IEEE80211_ADDR_LEN];
        u_int8_t                        e_flags;

#define HOSTAPD_ENTRY_F_LLADDR          0x00
#define HOSTAPD_ENTRY_F_MASK            0x01
#define HOSTAPD_ENTRY_F_INADDR          0x02

        union {
                u_int8_t                a_mask[IEEE80211_ADDR_LEN];
                struct hostapd_inaddr   a_inaddr;
        }                               e_addr;

        RB_ENTRY(hostapd_entry)         e_nodes;
        TAILQ_ENTRY(hostapd_entry)      e_entries;
};

#define e_mask                          e_addr.a_mask
#define e_inaddr                        e_addr.a_inaddr

#define HOSTAPD_TABLE_NAMELEN           32

RB_HEAD(hostapd_tree, hostapd_entry);

struct hostapd_table {
        char                            t_name[HOSTAPD_TABLE_NAMELEN];
        u_int8_t                        t_flags;

#define HOSTAPD_TABLE_F_CONST           0x01

        struct hostapd_tree             t_tree;
        TAILQ_HEAD(, hostapd_entry)     t_mask_head;
        TAILQ_ENTRY(hostapd_table)      t_entries;
};

struct hostapd_radiotap {
        u_int32_t       r_present;
        u_int8_t        r_txrate;
        u_int16_t       r_chan;
        u_int16_t       r_chan_flags;
        u_int8_t        r_rssi;
        u_int8_t        r_max_rssi;
};
#define HOSTAPD_RADIOTAP_F(_x)  (1 << IEEE80211_RADIOTAP_##_x)

struct hostapd_ieee80211_frame {
        u_int8_t        i_fc[2];
        u_int8_t        i_dur[2];
        u_int8_t        i_from[IEEE80211_ADDR_LEN];
        u_int8_t        i_to[IEEE80211_ADDR_LEN];
        u_int8_t        i_bssid[IEEE80211_ADDR_LEN];
        u_int8_t        i_seq[2];
        void            *i_data;
        u_int           i_data_len;
};

enum hostapd_action {
        HOSTAPD_ACTION_NONE     = 0,
        HOSTAPD_ACTION_LOG      = 1,
        HOSTAPD_ACTION_RADIOTAP = 2,
        HOSTAPD_ACTION_FRAME    = 3,
        HOSTAPD_ACTION_ADDNODE  = 4,
        HOSTAPD_ACTION_DELNODE  = 5,
        HOSTAPD_ACTION_RESEND   = 6
};

enum hostapd_op {
        HOSTAPD_OP_EQ           = 0,
        HOSTAPD_OP_NE           = 1,
        HOSTAPD_OP_LE           = 2,
        HOSTAPD_OP_LT           = 3,
        HOSTAPD_OP_GE           = 4,
        HOSTAPD_OP_GT           = 5
};

struct hostapd_action_data {
        union {
                struct hostapd_ieee80211_frame  u_frame;
                u_int8_t                        u_lladdr[IEEE80211_ADDR_LEN];
        } a_data;
        u_int16_t                               a_flags;

#define HOSTAPD_ACTION_F_REF_FROM               0x0001
#define HOSTAPD_ACTION_F_REF_TO                 0x0002
#define HOSTAPD_ACTION_F_REF_BSSID              0x0004
#define HOSTAPD_ACTION_F_REF_RANDOM             0x0008
#define HOSTAPD_ACTION_F_REF_FROM_M             0x000f
#define HOSTAPD_ACTION_F_REF_FROM_S             0
#define HOSTAPD_ACTION_F_REF_TO_M               0x00f0
#define HOSTAPD_ACTION_F_REF_TO_S               4
#define HOSTAPD_ACTION_F_REF_BSSID_M            0x0f00
#define HOSTAPD_ACTION_F_REF_BSSID_S            8
#define HOSTAPD_ACTION_F_REF_M                  0x0fff
#define HOSTAPD_ACTION_F_OPT_DIR_AUTO           0x1000
#define HOSTAPD_ACTION_F_OPT_LLADDR             0x2000
#define HOSTAPD_ACTION_F_OPT_TABLE              0x4000
};

#define a_frame                                 a_data.u_frame
#define a_lladdr                                a_data.u_lladdr

struct hostapd_frame {
        struct hostapd_ieee80211_frame  f_frame;
        u_int32_t                       f_radiotap;

        u_int32_t                       f_flags;

#define HOSTAPD_FRAME_F_TYPE            0x00000001
#define HOSTAPD_FRAME_F_TYPE_N          0x00000002
#define HOSTAPD_FRAME_F_SUBTYPE         0x00000004
#define HOSTAPD_FRAME_F_SUBTYPE_N       0x00000008
#define HOSTAPD_FRAME_F_DIR             0x00000010
#define HOSTAPD_FRAME_F_DIR_N           0x00000020
#define HOSTAPD_FRAME_F_FROM            0x00000040
#define HOSTAPD_FRAME_F_FROM_N          0x00000080
#define HOSTAPD_FRAME_F_FROM_TABLE      0x00000100
#define HOSTAPD_FRAME_F_FROM_M          0x000001c0
#define HOSTAPD_FRAME_F_TO              0x00000200
#define HOSTAPD_FRAME_F_TO_N            0x00000400
#define HOSTAPD_FRAME_F_TO_TABLE        0x00000800
#define HOSTAPD_FRAME_F_TO_M            0x00000e00
#define HOSTAPD_FRAME_F_BSSID           0x00001000
#define HOSTAPD_FRAME_F_BSSID_N         0x00002000
#define HOSTAPD_FRAME_F_BSSID_TABLE     0x00004000
#define HOSTAPD_FRAME_F_BSSID_M         0x00007000
#define HOSTAPD_FRAME_F_APME            0x00008000
#define HOSTAPD_FRAME_F_APME_N          0x00010000
#define HOSTAPD_FRAME_F_APME_M          0x00018000
#define HOSTAPD_FRAME_F_RSSI            0x00020000
#define HOSTAPD_FRAME_F_RATE            0x00040000
#define HOSTAPD_FRAME_F_CHANNEL         0x00080000
#define HOSTAPD_FRAME_F_RADIOTAP_M      0x000e0000
#define HOSTAPD_FRAME_F_M               0x0fffffff
#define HOSTAPD_FRAME_F_RET_OK          0x00000000
#define HOSTAPD_FRAME_F_RET_QUICK       0x10000000
#define HOSTAPD_FRAME_F_RET_SKIP        0x20000000
#define HOSTAPD_FRAME_F_RET_M           0xf0000000
#define HOSTAPD_FRAME_F_RET_S           28

#define HOSTAPD_FRAME_TABLE                                             \
        (HOSTAPD_FRAME_F_FROM_TABLE | HOSTAPD_FRAME_F_TO_TABLE |        \
        HOSTAPD_FRAME_F_BSSID_TABLE)
#define HOSTAPD_FRAME_N                                                 \
        (HOSTAPD_FRAME_F_FROM_N | HOSTAPD_FRAME_F_TO_N |                \
        HOSTAPD_FRAME_F_BSSID_N)

        struct hostapd_apme             *f_apme;
        struct hostapd_table            *f_from, *f_to, *f_bssid;
        struct timeval                  f_limit, f_then, f_last;
        long                            f_rate, f_rate_intval;
        long                            f_rate_cnt, f_rate_delay;

        enum hostapd_op                 f_rssi_op, f_txrate_op, f_chan_op;
        short                           f_rssi, f_txrate, f_chan;

        enum hostapd_action             f_action;
        u_int32_t                       f_action_flags;

#define HOSTAPD_ACTION_VERBOSE          0x00000001

        struct hostapd_action_data      f_action_data;

        TAILQ_ENTRY(hostapd_frame)      f_entries;
};

struct hostapd_apme {
        int                             a_raw;
        u_int                           a_rawlen;
        struct event                    a_ev;
        char                            a_iface[IFNAMSIZ];
        u_int8_t                        a_bssid[IEEE80211_ADDR_LEN];
        void                            *a_cfg;
        struct sockaddr_in              a_addr;

        struct event                    a_chanev;
        u_int8_t                        *a_chanavail;
        u_int8_t                        a_curchan;
        u_int                           a_maxchan;
        struct ieee80211chanreq         a_chanreq;

        TAILQ_ENTRY(hostapd_apme)       a_entries;
};

#ifndef IEEE80211_CHAN_MAX
#define IEEE80211_CHAN_MAX      255
#endif

#define HOSTAPD_HOPPER_MDELAY   800

struct hostapd_iapp {
        u_int16_t                       i_cnt;
        int                             i_raw;
        char                            i_iface[IFNAMSIZ];
        int                             i_udp;
        struct event                    i_udp_ev;
        u_int16_t                       i_udp_port;
        struct sockaddr_in              i_addr;
        struct sockaddr_in              i_broadcast;
        struct sockaddr_in              i_multicast;
        u_int8_t                        i_ttl;
        u_int8_t                        i_flags;

#define HOSTAPD_IAPP_F_ADD_NOTIFY       0x01
#define HOSTAPD_IAPP_F_RADIOTAP         0x02
#define HOSTAPD_IAPP_F_ROAMING_ADDRESS  0x04
#define HOSTAPD_IAPP_F_ROAMING_ROUTE    0x08
#define HOSTAPD_IAPP_F_DEFAULT                                                  \
        (HOSTAPD_IAPP_F_ADD_NOTIFY | HOSTAPD_IAPP_F_RADIOTAP)
#define HOSTAPD_IAPP_F_ROAMING                                                  \
        (HOSTAPD_IAPP_F_ROAMING_ROUTE | HOSTAPD_IAPP_F_ROAMING_ADDRESS)
#define HOSTAPD_IAPP_F_ADD              \
        (HOSTAPD_IAPP_F_ADD_NOTIFY | HOSTAPD_IAPP_F_ROAMING)

        struct hostapd_table            *i_addr_tbl;
        struct hostapd_table            *i_route_tbl;
};

struct hostapd_config {
        int                             c_apme_ctl;
        u_int                           c_apme_dlt;
        struct timeval                  c_apme_hopdelay;

        struct hostapd_iapp             c_iapp;

        int                             c_rtsock;
        int                             c_rtseq;

        u_int8_t                        c_flags;

#define HOSTAPD_CFG_F_APME              0x01
#define HOSTAPD_CFG_F_IAPP              0x02
#define HOSTAPD_CFG_F_IAPP_PASSIVE      0x04
#define HOSTAPD_CFG_F_RAW               0x08
#define HOSTAPD_CFG_F_UDP               0x10
#define HOSTAPD_CFG_F_BRDCAST           0x20
#define HOSTAPD_CFG_F_PRIV              0x40

        struct event                    c_priv_ev;

        char                            c_config[PATH_MAX];

        u_int                           c_verbose;
        u_int                           c_debug;
        u_int                           c_id;

        struct hostapd_counter          c_stats;

        TAILQ_HEAD(, hostapd_apme)      c_apmes;
        TAILQ_HEAD(, hostapd_table)     c_tables;
        TAILQ_HEAD(, hostapd_frame)     c_frames;
};

#define HOSTAPD_USER    "_hostapd"
#define HOSTAPD_CONFIG  "/etc/hostapd.conf"
#define HOSTAPD_DLT     DLT_IEEE802_11

#define HOSTAPD_LOG             0
#define HOSTAPD_LOG_VERBOSE     1
#define HOSTAPD_LOG_DEBUG       2

#define PRINTF                  hostapd_printf
#define etheraddr_string(_s)    ether_ntoa((struct ether_addr*)_s)
#define TTEST2(var, l)          (                                               \
        snapend - (l) <= snapend && (const u_char *)&(var) <= snapend - (l)     \
)
#define TTEST(var)              TTEST2(var, sizeof(var))
#define TCHECK2(var, l)         if (!TTEST2(var, l)) goto trunc
#define TCHECK(var)             TCHECK2(var, sizeof(var))

__BEGIN_DECLS

void     hostapd_log(u_int, const char *, ...);
void     hostapd_printf(const char *, ...);
void     hostapd_fatal(const char *, ...);
int      hostapd_bpf_open(u_int);
void     hostapd_cleanup(struct hostapd_config *);
int      hostapd_check_file_secrecy(int, const char *);
void     hostapd_randval(u_int8_t *, const u_int)
            __attribute__((__bounded__(__buffer__, 1, 2)));

struct hostapd_table *hostapd_table_add(struct hostapd_config *,
            const char *);
struct hostapd_table *hostapd_table_lookup(struct hostapd_config *,
            const char *);
struct hostapd_entry *hostapd_entry_add(struct hostapd_table *,
            u_int8_t *);
struct hostapd_entry *hostapd_entry_lookup(struct hostapd_table *,
            u_int8_t *);
void     hostapd_entry_update(struct hostapd_table *,
            struct hostapd_entry *);

RB_PROTOTYPE(hostapd_tree, hostapd_entry, e_nodes, hostapd_entry_cmp);

int      hostapd_parse_file(struct hostapd_config *);
int      hostapd_parse_symset(char *);

void     hostapd_priv_init(struct hostapd_config *);
int      hostapd_priv_llc_xid(struct hostapd_config *, struct hostapd_node *);
void     hostapd_priv_apme_bssid(struct hostapd_apme *);
int      hostapd_priv_apme_getnode(struct hostapd_apme *,
            struct hostapd_node *);
int      hostapd_priv_apme_setnode(struct hostapd_apme *,
            struct hostapd_node *node, int);
int      hostapd_priv_roaming(struct hostapd_apme *, struct hostapd_node *,
            int);

void     hostapd_apme_init(struct hostapd_apme *);
int      hostapd_apme_deauth(struct hostapd_apme *);
int      hostapd_apme_add(struct hostapd_config *, const char *);
void     hostapd_apme_term(struct hostapd_apme *);
struct hostapd_apme *hostapd_apme_lookup(struct hostapd_config *,
            const char *);
void     hostapd_apme_input(int, short, void *);
int      hostapd_apme_output(struct hostapd_apme *,
            struct hostapd_ieee80211_frame *);
int      hostapd_apme_addnode(struct hostapd_apme *,
            struct hostapd_node *node);
int      hostapd_apme_delnode(struct hostapd_apme *,
            struct hostapd_node *node);
int      hostapd_apme_offset(struct hostapd_apme *, u_int8_t *,
            const u_int);
struct hostapd_apme *hostapd_apme_addhopper(struct hostapd_config *,
            const char *);
void     hostapd_apme_sethopper(struct hostapd_apme *, int);

void     hostapd_iapp_init(struct hostapd_config *);
void     hostapd_iapp_term(struct hostapd_config *);
int      hostapd_iapp_add_notify(struct hostapd_apme *,
            struct hostapd_node *);
int      hostapd_iapp_radiotap(struct hostapd_apme *,
            u_int8_t *, const u_int);
void     hostapd_iapp_input(int, short, void *);

void     hostapd_llc_init(struct hostapd_config *);
int      hostapd_llc_send_xid(struct hostapd_config *, struct hostapd_node *);

int      hostapd_handle_input(struct hostapd_apme *, u_int8_t *, u_int);

void     hostapd_print_ieee80211(u_int, u_int, u_int8_t *, u_int);

void     hostapd_roaming_init(struct hostapd_config *);
void     hostapd_roaming_term(struct hostapd_apme *);
int      hostapd_roaming(struct hostapd_apme *, struct hostapd_node *, int);
int      hostapd_roaming_add(struct hostapd_apme *,
            struct hostapd_node *node);
int      hostapd_roaming_del(struct hostapd_apme *,
            struct hostapd_node *node);

__END_DECLS

#endif /* _HOSTAPD_H */