root/usr/src/cmd/cmd-inet/usr.lib/wpad/wpa_impl.h
/*
 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*
 * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
 * Sun elects to license this software under the BSD license.
 * See README for more details.
 */
#ifndef __WPA_IMPL_H
#define __WPA_IMPL_H

#include <net/wpa.h>
#include <libdladm.h>
#include <libdllink.h>

#ifdef  __cplusplus
extern "C" {
#endif

#define BIT(n)                  (1 << (n))

#define WPA_CIPHER_NONE         BIT(0)
#define WPA_CIPHER_WEP40        BIT(1)
#define WPA_CIPHER_WEP104       BIT(2)
#define WPA_CIPHER_TKIP         BIT(3)
#define WPA_CIPHER_CCMP         BIT(4)

#define WPA_KEY_MGMT_IEEE8021X  BIT(0)
#define WPA_KEY_MGMT_PSK        BIT(1)
#define WPA_KEY_MGMT_NONE       BIT(2)
#define WPA_KEY_MGMT_IEEE8021X_NO_WPA   BIT(3)

#define WPA_PROTO_WPA           BIT(0)
#define WPA_PROTO_RSN           BIT(1)

#pragma pack(1)
struct ieee802_1x_hdr {
        uint8_t         version;
        uint8_t         type;
        uint16_t        length;
        /* followed by length octets of data */
};
#pragma pack()

#define EAPOL_VERSION   2

enum {  IEEE802_1X_TYPE_EAP_PACKET      = 0,
        IEEE802_1X_TYPE_EAPOL_START     = 1,
        IEEE802_1X_TYPE_EAPOL_LOGOFF    = 2,
        IEEE802_1X_TYPE_EAPOL_KEY       = 3,
        IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT    = 4
};

enum {  EAPOL_KEY_TYPE_RC4 = 1,
        EAPOL_KEY_TYPE_RSN = 2,
        EAPOL_KEY_TYPE_WPA = 254
};

#define WPA_NONCE_LEN           32
#define WPA_REPLAY_COUNTER_LEN  8
#define MAX_PSK_LENGTH          64
#define WPA_PMK_LEN             32

#pragma pack(1)
struct wpa_eapol_key {
        uint8_t         type;
        uint16_t        key_info;
        uint16_t        key_length;
        uint8_t         replay_counter[WPA_REPLAY_COUNTER_LEN];
        uint8_t         key_nonce[WPA_NONCE_LEN];
        uint8_t         key_iv[16];
        uint8_t         key_rsc[8];
        uint8_t         key_id[8]; /* Reserved in IEEE 802.11i/RSN */
        uint8_t         key_mic[16];
        uint16_t        key_data_length;
        /* followed by key_data_length bytes of key_data */
};
#pragma pack()

#define WPA_KEY_INFO_TYPE_MASK          (BIT(0) | BIT(1) | BIT(2))
#define WPA_KEY_INFO_TYPE_HMAC_MD5_RC4  BIT(0)
#define WPA_KEY_INFO_TYPE_HMAC_SHA1_AES BIT(1)
#define WPA_KEY_INFO_KEY_TYPE           BIT(3) /* 1: Pairwise, 0: Group key */
/* bit4..5 is used in WPA, but is reserved in IEEE 802.11i/RSN */
#define WPA_KEY_INFO_KEY_INDEX_MASK     (BIT(4) | BIT(5))
#define WPA_KEY_INFO_KEY_INDEX_SHIFT    4
#define WPA_KEY_INFO_INSTALL            BIT(6) /* pairwise */
#define WPA_KEY_INFO_TXRX               BIT(6) /* group */
#define WPA_KEY_INFO_ACK                BIT(7)
#define WPA_KEY_INFO_MIC                BIT(8)
#define WPA_KEY_INFO_SECURE             BIT(9)
#define WPA_KEY_INFO_ERROR              BIT(10)
#define WPA_KEY_INFO_REQUEST            BIT(11)
#define WPA_KEY_INFO_ENCR_KEY_DATA      BIT(12) /* IEEE 802.11i/RSN only */

#define WPA_CAPABILITY_PREAUTH          BIT(0)

#define GENERIC_INFO_ELEM               0xdd
#define RSN_INFO_ELEM                   0x30

#define MAX_LOGBUF                      4096
#define MAX_SCANRESULTS                 64

enum {
        REASON_UNSPECIFIED                      = 1,
        REASON_DEAUTH_LEAVING                   = 3,
        REASON_INVALID_IE                       = 13,
        REASON_MICHAEL_MIC_FAILURE              = 14,
        REASON_4WAY_HANDSHAKE_TIMEOUT           = 15,
        REASON_GROUP_KEY_UPDATE_TIMEOUT         = 16,
        REASON_IE_IN_4WAY_DIFFERS               = 17,
        REASON_GROUP_CIPHER_NOT_VALID           = 18,
        REASON_PAIRWISE_CIPHER_NOT_VALID        = 19,
        REASON_AKMP_NOT_VALID                   = 20,
        REASON_UNSUPPORTED_RSN_IE_VERSION       = 21,
        REASON_INVALID_RSN_IE_CAPAB             = 22,
        REASON_IEEE_802_1X_AUTH_FAILED          = 23,
        REASON_CIPHER_SUITE_REJECTED            = 24
};

/*
 * wpa_supplicant
 */
#define PMKID_LEN                       16
#define PMK_LEN                         32

#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"

struct rsn_pmksa_cache {
        struct rsn_pmksa_cache  *next;
        uint8_t                 pmkid[PMKID_LEN];
        uint8_t                 pmk[PMK_LEN];
        time_t                  expiration;
        int                     akmp; /* WPA_KEY_MGMT_* */
        uint8_t                 aa[IEEE80211_ADDR_LEN];
};

struct rsn_pmksa_candidate {
        struct rsn_pmksa_candidate *next;
        uint8_t                 bssid[IEEE80211_ADDR_LEN];
};


#pragma pack(1)
struct wpa_ptk {
        uint8_t mic_key[16]; /* EAPOL-Key MIC Key (MK) */
        uint8_t encr_key[16]; /* EAPOL-Key Encryption Key (EK) */
        uint8_t tk1[16]; /* Temporal Key 1 (TK1) */
        union {
                uint8_t tk2[16]; /* Temporal Key 2 (TK2) */
                struct {
                        uint8_t tx_mic_key[8];
                        uint8_t rx_mic_key[8];
                } auth;
        } u;
};
#pragma pack()


struct wpa_supplicant {
        struct l2_packet_data   *l2;
        unsigned char           own_addr[IEEE80211_ADDR_LEN];

        /* The handle required for libdladm calls */
        dladm_handle_t          handle;

        datalink_id_t           linkid;
        char                    kname[DLADM_SECOBJ_NAME_MAX];

        uint8_t                 pmk[PMK_LEN];

        uint8_t                 snonce[WPA_NONCE_LEN];
        uint8_t                 anonce[WPA_NONCE_LEN];
        /* ANonce from the last 1/4 msg */

        struct wpa_ptk          ptk, tptk;
        int                     ptk_set, tptk_set;
        int                     renew_snonce;

        struct wpa_config       *conf;

        uint8_t                 request_counter[WPA_REPLAY_COUNTER_LEN];
        uint8_t                 rx_replay_counter[WPA_REPLAY_COUNTER_LEN];
        int                     rx_replay_counter_set;

        uint8_t                 bssid[IEEE80211_ADDR_LEN];
        int                     reassociate; /* reassociation requested */

        uint8_t                 *ap_wpa_ie;
        size_t                  ap_wpa_ie_len;

        /*
         * Selected configuration
         * based on Beacon/ProbeResp WPA IE
         */
        int                     proto;
        int                     pairwise_cipher;
        int                     group_cipher;
        int                     key_mgmt;

        struct wpa_driver_ops   *driver;

        enum {
                WPA_DISCONNECTED,
                WPA_SCANNING,
                WPA_ASSOCIATING,
                WPA_ASSOCIATED,
                WPA_4WAY_HANDSHAKE,
                WPA_GROUP_HANDSHAKE,
                WPA_COMPLETED
        } wpa_state;

        struct rsn_pmksa_cache  *pmksa; /* PMKSA cache */
        int     pmksa_count; /* number of entries in PMKSA cache */
        struct rsn_pmksa_cache  *cur_pmksa; /* current PMKSA entry */
        struct rsn_pmksa_candidate      *pmksa_candidates;

        /*
         * number of EAPOL packets received after the
         * previous association event
         */
        int                     eapol_received;
};

struct wpa_ie_data {
        int     proto;
        int     pairwise_cipher;
        int     group_cipher;
        int     key_mgmt;
        int     capabilities;
};

/* WPA configuration */
struct wpa_ssid {
        uint8_t *ssid;
        size_t  ssid_len;

        uint8_t bssid[IEEE80211_ADDR_LEN];
        int     bssid_set;

        uint8_t psk[PMK_LEN];
        int     psk_set;
        char    *passphrase;

        /* Bitfields of allowed Pairwise/Group Ciphers, WPA_CIPHER_* */
        int     pairwise_cipher;
        int     group_cipher;

        int     key_mgmt;
        int     proto; /* Bitfield of allowed protocols (WPA_PROTO_*) */
};

struct wpa_config {
        struct wpa_ssid *ssid; /* global network list */
        int eapol_version;
        /* int ap_scan; */
};

struct wpa_config *wpa_config_read(void *);
void wpa_config_free(struct wpa_config *);

/*
 * Debugging function - conditional printf and hex dump.
 * Driver wrappers can use these for debugging purposes.
 */
enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR };

void wpa_printf(int, char *, ...);
void wpa_hexdump(int, const char *, const uint8_t *, size_t);

void wpa_event_handler(void *, wpa_event_type);
void wpa_supplicant_rx_eapol(void *, unsigned char *, unsigned char *, size_t);

void wpa_supplicant_scan(void *, void *);
void wpa_supplicant_req_scan(struct wpa_supplicant *, int, int);

void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *, int, int);
void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *);
void wpa_supplicant_disassociate(struct wpa_supplicant *, int);

void pmksa_cache_free(struct wpa_supplicant *);
void pmksa_candidate_free(struct wpa_supplicant *);
struct rsn_pmksa_cache *pmksa_cache_get(struct wpa_supplicant *,
    uint8_t *, uint8_t *);

int wpa_parse_wpa_ie(struct wpa_supplicant *, uint8_t *,
        size_t, struct wpa_ie_data *);
int wpa_gen_wpa_ie(struct wpa_supplicant *, uint8_t *);

#ifdef __cplusplus
}
#endif

#endif /* __WPA_IMPL_H */