diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 9bce6c6e8..d3bda1800 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -1147,7 +1147,17 @@ typedef enum wpa_event_type { * FT authentication sequence from the AP. The FT IEs are included in * the extra information in union wpa_event_data::ft_ies. */ - EVENT_FT_RESPONSE + EVENT_FT_RESPONSE, + + /** + * EVENT_IBSS_RSN_START - Request RSN authentication in IBSS + * + * The driver can use this event to inform wpa_supplicant about a STA + * in an IBSS with which protected frames could be exchanged. This + * event starts RSN authentication with the other STA to authenticate + * the STA and set up encryption keys with it. + */ + EVENT_IBSS_RSN_START } wpa_event_type; @@ -1274,6 +1284,13 @@ union wpa_event_data { int ft_action; u8 target_ap[ETH_ALEN]; } ft_ies; + + /** + * struct ibss_rsn_start - Data for EVENT_IBSS_RSN_START + */ + struct ibss_rsn_start { + u8 peer[ETH_ALEN]; + } ibss_rsn_start; }; /** diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index c5a8132ce..65adf5344 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -941,6 +941,21 @@ else CFLAGS += -DCONFIG_NO_WPA -DCONFIG_NO_WPA2 endif +ifdef CONFIG_IBSS_RSN +CFLAGS += -DCONFIG_IBSS_RSN +OBJS += ibss_rsn.o +OBJS += ../hostapd/wpa.o +OBJS += ../hostapd/wpa_auth_ie.o +OBJS += ../hostapd/pmksa_cache.o +OBJS += ../src/radius/radius.o +ifdef CONFIG_IEEE80211R +OBJS += ../hostapd/wpa_ft.o +endif +ifdef CONFIG_PEERKEY +OBJS += ../hostapd/peerkey.o +endif +endif + ifdef CONFIG_NO_WPA2 CFLAGS += -DCONFIG_NO_WPA2 endif diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index d627dc654..7bb871a97 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -29,6 +29,7 @@ #include "ieee802_11_defs.h" #include "wps_supplicant.h" #include "wps/wps.h" +#include "ibss_rsn.h" static int wpa_supplicant_global_iface_list(struct wpa_global *global, char *buf, int len); @@ -227,6 +228,26 @@ static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s, #endif /* CONFIG_WPS */ +#ifdef CONFIG_IBSS_RSN +static int wpa_supplicant_ctrl_iface_ibss_rsn( + struct wpa_supplicant *wpa_s, char *addr) +{ + u8 peer[ETH_ALEN]; + + if (hwaddr_aton(addr, peer)) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN: invalid " + "address '%s'", peer); + return -1; + } + + wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN " MACSTR, + MAC2STR(peer)); + + return ibss_rsn_start(wpa_s->ibss_rsn, peer); +} +#endif /* CONFIG_IBSS_RSN */ + + static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s, char *rsp) { @@ -1566,6 +1587,11 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8)) reply_len = -1; #endif /* CONFIG_WPS */ +#ifdef CONFIG_IBSS_RSN + } else if (os_strncmp(buf, "IBSS_RSN ", 9) == 0) { + if (wpa_supplicant_ctrl_iface_ibss_rsn(wpa_s, buf + 9)) + reply_len = -1; +#endif /* CONFIG_IBSS_RSN */ } else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0) { if (wpa_supplicant_ctrl_iface_ctrl_rsp( diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 32b87e987..e169949d9 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -32,6 +32,7 @@ #include "blacklist.h" #include "wpas_glue.h" #include "wps_supplicant.h" +#include "ibss_rsn.h" static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s) @@ -1067,6 +1068,17 @@ wpa_supplicant_event_ft_response(struct wpa_supplicant *wpa_s, #endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_IBSS_RSN +static void wpa_supplicant_event_ibss_rsn_start(struct wpa_supplicant *wpa_s, + union wpa_event_data *data) +{ + if (data == NULL) + return; + ibss_rsn_start(wpa_s->ibss_rsn, data->ibss_rsn_start.peer); +} +#endif /* CONFIG_IBSS_RSN */ + + void wpa_supplicant_event(void *ctx, wpa_event_type event, union wpa_event_data *data) { @@ -1106,6 +1118,11 @@ void wpa_supplicant_event(void *ctx, wpa_event_type event, wpa_supplicant_event_ft_response(wpa_s, data); break; #endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_IBSS_RSN + case EVENT_IBSS_RSN_START: + wpa_supplicant_event_ibss_rsn_start(wpa_s, data); + break; +#endif /* CONFIG_IBSS_RSN */ default: wpa_printf(MSG_INFO, "Unknown event %d", event); break; diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c new file mode 100644 index 000000000..691a84e83 --- /dev/null +++ b/wpa_supplicant/ibss_rsn.c @@ -0,0 +1,319 @@ +/* + * wpa_supplicant - IBSS RSN + * Copyright (c) 2009, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "wpa_supplicant_i.h" +#include "wpa.h" +#include "wpa_ie.h" +#include "../hostapd/wpa.h" +#include "ibss_rsn.h" + + +static void ibss_rsn_free(struct ibss_rsn_peer *peer) +{ + wpa_auth_sta_deinit(peer->auth); + wpa_sm_deinit(peer->supp); + os_free(peer); +} + + +static int supp_ether_send(void *ctx, const u8 *dest, u16 proto, const u8 *buf, + size_t len) +{ + /* struct ibss_rsn_peer *peer = ctx; */ + + wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR " proto=0x%04x " + "len=%lu)", + __func__, MAC2STR(dest), proto, (unsigned long) len); + + /* TODO: send EAPOL frame */ + + return 0; +} + + +static u8 * supp_alloc_eapol(void *ctx, u8 type, const void *data, + u16 data_len, size_t *msg_len, void **data_pos) +{ + struct ieee802_1x_hdr *hdr; + + wpa_printf(MSG_DEBUG, "SUPP: %s(type=%d data_len=%d)", + __func__, type, data_len); + + *msg_len = sizeof(*hdr) + data_len; + hdr = os_malloc(*msg_len); + if (hdr == NULL) + return NULL; + + hdr->version = 2; + hdr->type = type; + hdr->length = host_to_be16(data_len); + + if (data) + os_memcpy(hdr + 1, data, data_len); + else + os_memset(hdr + 1, 0, data_len); + + if (data_pos) + *data_pos = hdr + 1; + + return (u8 *) hdr; +} + + +static int supp_get_beacon_ie(void *ctx) +{ + wpa_printf(MSG_DEBUG, "SUPP: %s", __func__); + /* TODO */ + return -1; +} + + +static int supp_set_key(void *ctx, wpa_alg alg, + const u8 *addr, int key_idx, int set_tx, + const u8 *seq, size_t seq_len, + const u8 *key, size_t key_len) +{ + wpa_printf(MSG_DEBUG, "SUPP: %s(alg=%d addr=" MACSTR " key_idx=%d " + "set_tx=%d)", + __func__, alg, MAC2STR(addr), key_idx, set_tx); + wpa_hexdump(MSG_DEBUG, "SUPP: set_key - seq", seq, seq_len); + wpa_hexdump(MSG_DEBUG, "SUPP: set_key - key", key, key_len); + return 0; +} + + +static int supp_mlme_setprotection(void *ctx, const u8 *addr, + int protection_type, int key_type) +{ + wpa_printf(MSG_DEBUG, "SUPP: %s(addr=" MACSTR " protection_type=%d " + "key_type=%d)", + __func__, MAC2STR(addr), protection_type, key_type); + return 0; +} + + +static void supp_cancel_auth_timeout(void *ctx) +{ + wpa_printf(MSG_DEBUG, "SUPP: %s", __func__); +} + + +int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr, + const u8 *psk) +{ + struct wpa_sm_ctx *ctx = os_zalloc(sizeof(*ctx)); + if (ctx == NULL) + return -1; + + ctx->ctx = peer; + ctx->ether_send = supp_ether_send; + ctx->get_beacon_ie = supp_get_beacon_ie; + ctx->alloc_eapol = supp_alloc_eapol; + ctx->set_key = supp_set_key; + ctx->mlme_setprotection = supp_mlme_setprotection; + ctx->cancel_auth_timeout = supp_cancel_auth_timeout; + peer->supp = wpa_sm_init(ctx); + if (peer->supp == NULL) { + wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed"); + return -1; + } + + wpa_sm_set_own_addr(peer->supp, own_addr); + wpa_sm_set_param(peer->supp, WPA_PARAM_RSN_ENABLED, 1); + wpa_sm_set_param(peer->supp, WPA_PARAM_PROTO, WPA_PROTO_RSN); + wpa_sm_set_param(peer->supp, WPA_PARAM_PAIRWISE, WPA_CIPHER_CCMP); + wpa_sm_set_param(peer->supp, WPA_PARAM_GROUP, WPA_CIPHER_CCMP); + wpa_sm_set_param(peer->supp, WPA_PARAM_KEY_MGMT, WPA_KEY_MGMT_PSK); + wpa_sm_set_pmk(peer->supp, psk, PMK_LEN); + +#if 0 /* TODO? */ + peer->supp_ie_len = sizeof(peer->supp_ie); + if (wpa_sm_set_assoc_wpa_ie_default(peer->supp, peer->supp_ie, + &peer->supp_ie_len) < 0) { + wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_set_assoc_wpa_ie_default()" + " failed"); + return -1; + } +#endif + + wpa_sm_notify_assoc(peer->supp, peer->addr); + + return 0; +} + + +static void auth_logger(void *ctx, const u8 *addr, logger_level level, + const char *txt) +{ + if (addr) + wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " - %s", + MAC2STR(addr), txt); + else + wpa_printf(MSG_DEBUG, "AUTH: %s", txt); +} + + +static const u8 * auth_get_psk(void *ctx, const u8 *addr, const u8 *prev_psk) +{ + struct ibss_rsn *ibss_rsn = ctx; + wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)", + __func__, MAC2STR(addr), prev_psk); + if (prev_psk) + return NULL; + return ibss_rsn->psk; +} + + +static int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data, + size_t data_len, int encrypt) +{ + /* struct ibss_rsn *ibss_rsn = ctx; */ + + wpa_printf(MSG_DEBUG, "AUTH: %s(addr=" MACSTR " data_len=%lu " + "encrypt=%d)", + __func__, MAC2STR(addr), (unsigned long) data_len, encrypt); + + /* TODO: send EAPOL frame */ + + return 0; +} + + +static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn, + const u8 *own_addr) +{ + struct wpa_auth_config conf; + struct wpa_auth_callbacks cb; + + wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine"); + + os_memset(&conf, 0, sizeof(conf)); + conf.wpa = 2; + conf.wpa_key_mgmt = WPA_KEY_MGMT_PSK; + conf.wpa_pairwise = WPA_CIPHER_CCMP; + conf.rsn_pairwise = WPA_CIPHER_CCMP; + conf.wpa_group = WPA_CIPHER_CCMP; + conf.eapol_version = 2; + + os_memset(&cb, 0, sizeof(cb)); + cb.ctx = ibss_rsn; + cb.logger = auth_logger; + cb.send_eapol = auth_send_eapol; + cb.get_psk = auth_get_psk; + + ibss_rsn->auth_group = wpa_init(own_addr, &conf, &cb); + if (ibss_rsn->auth_group == NULL) { + wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed"); + return -1; + } + + return 0; +} + + +static int ibss_rsn_auth_init(struct ibss_rsn *ibss_rsn, + struct ibss_rsn_peer *peer) +{ + peer->auth = wpa_auth_sta_init(ibss_rsn->auth_group, peer->addr); + if (peer->auth == NULL) { + wpa_printf(MSG_DEBUG, "AUTH: wpa_auth_sta_init() failed"); + return -1; + } + +#if 0 /* TODO: get peer RSN IE with Probe Request */ + if (wpa_validate_wpa_ie(ibss_rsn->auth_group, peer->auth, PEER_IE, + PEER_IE_LEN, NULL, 0) != WPA_IE_OK) { + wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed"); + return -1; + } +#endif + + wpa_auth_sm_event(peer->auth, WPA_ASSOC); + + wpa_auth_sta_associated(ibss_rsn->auth_group, peer->auth); + + return 0; +} + + +int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr) +{ + struct ibss_rsn_peer *peer; + + wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Authenticator and " + "Supplicant for peer " MACSTR, MAC2STR(addr)); + + peer = os_zalloc(sizeof(*peer)); + if (peer == NULL) + return -1; + + os_memcpy(peer->addr, addr, ETH_ALEN); + + if (ibss_rsn_supp_init(peer, ibss_rsn->wpa_s->own_addr, ibss_rsn->psk) + < 0) { + ibss_rsn_free(peer); + return -1; + } + + if (ibss_rsn_auth_init(ibss_rsn, peer) < 0) { + ibss_rsn_free(peer); + return -1; + } + + peer->next = ibss_rsn->peers; + ibss_rsn->peers = peer; + + return 0; +} + + +struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s) +{ + struct ibss_rsn *ibss_rsn; + + ibss_rsn = os_zalloc(sizeof(*ibss_rsn)); + if (ibss_rsn == NULL) + return NULL; + ibss_rsn->wpa_s = wpa_s; + + if (ibss_rsn_auth_init_group(ibss_rsn, wpa_s->own_addr) < 0) { + ibss_rsn_deinit(ibss_rsn); + return NULL; + } + + return ibss_rsn; +} + + +void ibss_rsn_deinit(struct ibss_rsn *ibss_rsn) +{ + struct ibss_rsn_peer *peer, *prev; + + if (ibss_rsn == NULL) + return; + + peer = ibss_rsn->peers; + while (peer) { + prev = peer; + peer = peer->next; + ibss_rsn_free(prev); + } + + wpa_deinit(ibss_rsn->auth_group); + os_free(ibss_rsn); + +} diff --git a/wpa_supplicant/ibss_rsn.h b/wpa_supplicant/ibss_rsn.h new file mode 100644 index 000000000..d301907e9 --- /dev/null +++ b/wpa_supplicant/ibss_rsn.h @@ -0,0 +1,40 @@ +/* + * wpa_supplicant - IBSS RSN + * Copyright (c) 2009, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef IBSS_RSN_H +#define IBSS_RSN_H + +struct ibss_rsn_peer { + struct ibss_rsn_peer *next; + + u8 addr[ETH_ALEN]; + + struct wpa_sm *supp; + + struct wpa_state_machine *auth; +}; + +struct ibss_rsn { + struct wpa_supplicant *wpa_s; + struct wpa_authenticator *auth_group; + struct ibss_rsn_peer *peers; + u8 psk[PMK_LEN]; +}; + + +struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s); +void ibss_rsn_deinit(struct ibss_rsn *ibss_rsn); +int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr); + +#endif /* IBSS_RSN_H */ diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index c49b67401..791155d33 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -465,6 +465,26 @@ static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[]) } +static int wpa_cli_cmd_ibss_rsn(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + char cmd[256]; + int res; + + if (argc != 1) { + printf("Invalid IBSS_RSN command: needs one argument " + "(Peer STA MAC address)\n"); + return -1; + } + + res = os_snprintf(cmd, sizeof(cmd), "IBSS_RSN %s", argv[0]); + if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { + printf("Too long IBSS_RSN command.\n"); + return -1; + } + return wpa_ctrl_command(ctrl, cmd); +} + + static int wpa_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char cmd[256]; @@ -1239,6 +1259,9 @@ static struct wpa_cli_cmd wpa_cli_commands[] = { { "wps_reg", wpa_cli_cmd_wps_reg, cli_cmd_flag_sensitive, " = start WPS Registrar to configure an AP" }, + { "ibss_rsn", wpa_cli_cmd_ibss_rsn, + cli_cmd_flag_none, + " = request RSN authentication with in IBSS" }, { NULL, NULL, cli_cmd_flag_none, NULL } }; diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index d2c45525e..71daf8d32 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -39,6 +39,7 @@ #include "blacklist.h" #include "wpas_glue.h" #include "wps_supplicant.h" +#include "ibss_rsn.h" const char *wpa_supplicant_version = "wpa_supplicant v" VERSION_STR "\n" @@ -385,6 +386,11 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) ieee80211_sta_deinit(wpa_s); wpas_wps_deinit(wpa_s); + +#ifdef CONFIG_IBSS_RSN + ibss_rsn_deinit(wpa_s->ibss_rsn); + wpa_s->ibss_rsn = NULL; +#endif /* CONFIG_IBSS_RSN */ } @@ -1859,6 +1865,14 @@ static int wpa_supplicant_init_iface2(struct wpa_supplicant *wpa_s) wpa_s->driver_4way_handshake = 1; } +#ifdef CONFIG_IBSS_RSN + wpa_s->ibss_rsn = ibss_rsn_init(wpa_s); + if (!wpa_s->ibss_rsn) { + wpa_printf(MSG_DEBUG, "Failed to init IBSS RSN"); + return -1; + } +#endif /* CONFIG_IBSS_RSN */ + return 0; } diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index f39709faa..c629a7e10 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -33,6 +33,7 @@ extern struct wpa_driver_ops *wpa_supplicant_drivers[]; struct wpa_scan_result; struct wpa_sm; struct wpa_supplicant; +struct ibss_rsn; /* * Forward declarations of private structures used within the ctrl_iface @@ -355,6 +356,8 @@ struct wpa_supplicant { int mic_errors_seen; /* Michael MIC errors with the current PTK */ struct wps_context *wps; + + struct ibss_rsn *ibss_rsn; };