diff options
Diffstat (limited to 'wpa_supplicant/ibss_rsn.c')
-rw-r--r-- | wpa_supplicant/ibss_rsn.c | 176 |
1 files changed, 161 insertions, 15 deletions
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c index 0e332534e491e..046f181f031ec 100644 --- a/wpa_supplicant/ibss_rsn.c +++ b/wpa_supplicant/ibss_rsn.c @@ -2,14 +2,8 @@ * 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. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "includes.h" @@ -24,6 +18,18 @@ #include "ibss_rsn.h" +static struct ibss_rsn_peer * ibss_rsn_get_peer(struct ibss_rsn *ibss_rsn, + const u8 *addr) +{ + struct ibss_rsn_peer *peer; + + for (peer = ibss_rsn->peers; peer; peer = peer->next) + if (os_memcmp(addr, peer->addr, ETH_ALEN) == 0) + break; + return peer; +} + + static void ibss_rsn_free(struct ibss_rsn_peer *peer) { wpa_auth_sta_deinit(peer->auth); @@ -39,6 +45,13 @@ static void supp_set_state(void *ctx, enum wpa_states state) } +static enum wpa_states supp_get_state(void *ctx) +{ + struct ibss_rsn_peer *peer = ctx; + return peer->supp_state; +} + + static int supp_ether_send(void *ctx, const u8 *dest, u16 proto, const u8 *buf, size_t len) { @@ -125,6 +138,8 @@ static int supp_set_key(void *ctx, enum wpa_alg alg, } } + if (is_broadcast_ether_addr(addr)) + addr = peer->addr; return wpa_drv_set_key(peer->ibss_rsn->wpa_s, alg, addr, key_idx, set_tx, seq, seq_len, key, key_len); } @@ -153,8 +168,14 @@ static void supp_cancel_auth_timeout(void *ctx) } -int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr, - const u8 *psk) +static void supp_deauthenticate(void * ctx, int reason_code) +{ + wpa_printf(MSG_DEBUG, "SUPP: %s (TODO)", __func__); +} + + +static 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) @@ -163,6 +184,7 @@ int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr, ctx->ctx = peer; ctx->msg_ctx = peer->ibss_rsn->wpa_s; ctx->set_state = supp_set_state; + ctx->get_state = supp_get_state; ctx->ether_send = supp_ether_send; ctx->get_beacon_ie = supp_get_beacon_ie; ctx->alloc_eapol = supp_alloc_eapol; @@ -170,6 +192,7 @@ int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr, ctx->get_network_ctx = supp_get_network_ctx; ctx->mlme_setprotection = supp_mlme_setprotection; ctx->cancel_auth_timeout = supp_cancel_auth_timeout; + ctx->deauthenticate = supp_deauthenticate; peer->supp = wpa_sm_init(ctx); if (peer->supp == NULL) { wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed"); @@ -273,6 +296,71 @@ static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg, } +static int auth_for_each_sta(void *ctx, int (*cb)(struct wpa_state_machine *sm, + void *ctx), + void *cb_ctx) +{ + struct ibss_rsn *ibss_rsn = ctx; + struct ibss_rsn_peer *peer; + + wpa_printf(MSG_DEBUG, "AUTH: for_each_sta"); + + for (peer = ibss_rsn->peers; peer; peer = peer->next) { + if (peer->auth && cb(peer->auth, cb_ctx)) + return 1; + } + + return 0; +} + + +static void ibss_set_sta_authorized(struct ibss_rsn *ibss_rsn, + struct ibss_rsn_peer *peer, int authorized) +{ + int res; + + if (authorized) { + res = wpa_drv_sta_set_flags(ibss_rsn->wpa_s, peer->addr, + WPA_STA_AUTHORIZED, + WPA_STA_AUTHORIZED, ~0); + wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " authorizing port", + MAC2STR(peer->addr)); + } else { + res = wpa_drv_sta_set_flags(ibss_rsn->wpa_s, peer->addr, + 0, 0, ~WPA_STA_AUTHORIZED); + wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " unauthorizing port", + MAC2STR(peer->addr)); + } + + if (res && errno != ENOENT) { + wpa_printf(MSG_DEBUG, "Could not set station " MACSTR " flags " + "for kernel driver (errno=%d)", + MAC2STR(peer->addr), errno); + } +} + + +static void auth_set_eapol(void *ctx, const u8 *addr, + wpa_eapol_variable var, int value) +{ + struct ibss_rsn *ibss_rsn = ctx; + struct ibss_rsn_peer *peer = ibss_rsn_get_peer(ibss_rsn, addr); + + if (peer == NULL) + return; + + switch (var) { + case WPA_EAPOL_authorized: + ibss_set_sta_authorized(ibss_rsn, peer, value); + break; + default: + /* do not handle any other event */ + wpa_printf(MSG_DEBUG, "AUTH: eapol event not handled %d", var); + break; + } +} + + static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn, const u8 *own_addr) { @@ -288,13 +376,16 @@ static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn, conf.rsn_pairwise = WPA_CIPHER_CCMP; conf.wpa_group = WPA_CIPHER_CCMP; conf.eapol_version = 2; + conf.wpa_group_rekey = 600; os_memset(&cb, 0, sizeof(cb)); cb.ctx = ibss_rsn; cb.logger = auth_logger; + cb.set_eapol = auth_set_eapol; cb.send_eapol = auth_send_eapol; cb.get_psk = auth_get_psk; cb.set_key = auth_set_key; + cb.for_each_sta = auth_for_each_sta; ibss_rsn->auth_group = wpa_init(own_addr, &conf, &cb); if (ibss_rsn->auth_group == NULL) { @@ -302,6 +393,8 @@ static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn, return -1; } + wpa_init_keys(ibss_rsn->auth_group); + return 0; } @@ -341,6 +434,16 @@ int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr) { struct ibss_rsn_peer *peer; + if (ibss_rsn == NULL) + return -1; + + if (ibss_rsn_get_peer(ibss_rsn, addr)) { + wpa_printf(MSG_DEBUG, "RSN: IBSS Authenticator and Supplicant " + "for peer " MACSTR " already running", + MAC2STR(addr)); + return 0; + } + wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Authenticator and " "Supplicant for peer " MACSTR, MAC2STR(addr)); @@ -369,6 +472,46 @@ int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr) } +void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac) +{ + struct ibss_rsn_peer *peer, *prev; + + if (ibss_rsn == NULL) + return; + + if (peermac == NULL) { + /* remove all peers */ + wpa_printf(MSG_DEBUG, "%s: Remove all peers", __func__); + peer = ibss_rsn->peers; + while (peer) { + prev = peer; + peer = peer->next; + ibss_rsn_free(prev); + ibss_rsn->peers = peer; + } + } else { + /* remove specific peer */ + wpa_printf(MSG_DEBUG, "%s: Remove specific peer " MACSTR, + __func__, MAC2STR(peermac)); + + for (prev = NULL, peer = ibss_rsn->peers; peer != NULL; + prev = peer, peer = peer->next) { + if (os_memcmp(peermac, peer->addr, ETH_ALEN) == 0) { + if (prev == NULL) + ibss_rsn->peers = peer->next; + else + prev->next = peer->next; + ibss_rsn_free(peer); + wpa_printf(MSG_DEBUG, "%s: Successfully " + "removed a specific peer", + __func__); + break; + } + } + } +} + + struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s) { struct ibss_rsn *ibss_rsn; @@ -483,11 +626,12 @@ int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr, { struct ibss_rsn_peer *peer; - for (peer = ibss_rsn->peers; peer; peer = peer->next) { - if (os_memcmp(src_addr, peer->addr, ETH_ALEN) == 0) - return ibss_rsn_process_rx_eapol(ibss_rsn, peer, - buf, len); - } + if (ibss_rsn == NULL) + return -1; + + peer = ibss_rsn_get_peer(ibss_rsn, src_addr); + if (peer) + return ibss_rsn_process_rx_eapol(ibss_rsn, peer, buf, len); if (ibss_rsn_eapol_dst_supp(buf, len) > 0) { /* @@ -506,5 +650,7 @@ int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr, void ibss_rsn_set_psk(struct ibss_rsn *ibss_rsn, const u8 *psk) { + if (ibss_rsn == NULL) + return; os_memcpy(ibss_rsn->psk, psk, PMK_LEN); } |