Added initial step for IBSS RSN support

This commit adds a new build option, CONFIG_IBSS_RSN=y, that can be used
to enable RSN support for IBSS. This links in RSN Authenticator code
from hostapd and adds code for managing per-peer information for IBSS. A
new wpa_cli command or driver event can be used to request RSN
authentication with an IBSS peer. New RSN Authenticator and Supplicant
will be allocated for each peer.

The basic state machine setup code is included in this commit, but the
state machines are not properly started yet. In addition, some of the
callback functions are not yet complete.
This commit is contained in:
Jouni Malinen 2009-01-15 01:21:55 +02:00
parent 4bb081f1b4
commit 11ef8d3578
9 changed files with 475 additions and 1 deletions

View file

@ -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;
};
/**

View file

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

View file

@ -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(

View file

@ -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;

319
wpa_supplicant/ibss_rsn.c Normal file
View file

@ -0,0 +1,319 @@
/*
* wpa_supplicant - IBSS RSN
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
*
* 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);
}

40
wpa_supplicant/ibss_rsn.h Normal file
View file

@ -0,0 +1,40 @@
/*
* wpa_supplicant - IBSS RSN
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
*
* 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 */

View file

@ -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,
"<BSSID> <AP PIN> = start WPS Registrar to configure an AP" },
{ "ibss_rsn", wpa_cli_cmd_ibss_rsn,
cli_cmd_flag_none,
"<addr> = request RSN authentication with <addr> in IBSS" },
{ NULL, NULL, cli_cmd_flag_none, NULL }
};

View file

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

View file

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