Remove direct driver calls from ieee802_11.c
[libeap.git] / hostapd / wpa.c
index 64bc6b3..4af26e9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd - IEEE 802.11i-2004 / WPA Authenticator
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-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
 #ifndef CONFIG_NATIVE_WINDOWS
 
 #include "common.h"
+#include "eloop.h"
+#include "crypto/aes_wrap.h"
+#include "crypto/crypto.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+#include "eapol_auth/eapol_auth_sm.h"
 #include "config.h"
-#include "eapol_sm.h"
 #include "wpa.h"
-#include "sha1.h"
-#include "sha256.h"
-#include "rc4.h"
-#include "aes_wrap.h"
-#include "crypto.h"
-#include "eloop.h"
 #include "ieee802_11.h"
 #include "pmksa_cache.h"
 #include "state_machine.h"
@@ -44,6 +43,8 @@ static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx);
 static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
                              struct wpa_group *group);
 static void wpa_request_new_ptk(struct wpa_state_machine *sm);
+static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
+                         struct wpa_group *group);
 
 static const u32 dot11RSNAConfigGroupUpdateCount = 4;
 static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;
@@ -121,15 +122,6 @@ static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
 }
 
 
-static inline int wpa_auth_get_seqnum_igtk(struct wpa_authenticator *wpa_auth,
-                                          const u8 *addr, int idx, u8 *seq)
-{
-       if (wpa_auth->cb.get_seqnum_igtk == NULL)
-               return -1;
-       return wpa_auth->cb.get_seqnum_igtk(wpa_auth->cb.ctx, addr, idx, seq);
-}
-
-
 static inline int
 wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr,
                    const u8 *data, size_t data_len, int encrypt)
@@ -286,21 +278,9 @@ static void wpa_auth_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
 }
 
 
-static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
-                                        int vlan_id)
+static void wpa_group_set_key_len(struct wpa_group *group, int cipher)
 {
-       struct wpa_group *group;
-       u8 buf[ETH_ALEN + 8 + sizeof(group)];
-       u8 rkey[32];
-
-       group = os_zalloc(sizeof(struct wpa_group));
-       if (group == NULL)
-               return NULL;
-
-       group->GTKAuthenticator = TRUE;
-       group->vlan_id = vlan_id;
-
-       switch (wpa_auth->conf.wpa_group) {
+       switch (cipher) {
        case WPA_CIPHER_CCMP:
                group->GTK_len = 16;
                break;
@@ -314,6 +294,24 @@ static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
                group->GTK_len = 5;
                break;
        }
+}
+
+
+static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
+                                        int vlan_id)
+{
+       struct wpa_group *group;
+       u8 buf[ETH_ALEN + 8 + sizeof(group)];
+       u8 rkey[32];
+
+       group = os_zalloc(sizeof(struct wpa_group));
+       if (group == NULL)
+               return NULL;
+
+       group->GTKAuthenticator = TRUE;
+       group->vlan_id = vlan_id;
+
+       wpa_group_set_key_len(group, wpa_auth->conf.wpa_group);
 
        /* Counter = PRF-256(Random number, "Init Counter",
         *                   Local MAC Address || Time)
@@ -452,6 +450,7 @@ void wpa_deinit(struct wpa_authenticator *wpa_auth)
 int wpa_reconfig(struct wpa_authenticator *wpa_auth,
                 struct wpa_auth_config *conf)
 {
+       struct wpa_group *group;
        if (wpa_auth == NULL)
                return 0;
 
@@ -461,6 +460,17 @@ int wpa_reconfig(struct wpa_authenticator *wpa_auth,
                return -1;
        }
 
+       /*
+        * Reinitialize GTK to make sure it is suitable for the new
+        * configuration.
+        */
+       group = wpa_auth->group;
+       wpa_group_set_key_len(group, wpa_auth->conf.wpa_group);
+       group->GInit = TRUE;
+       wpa_group_sm_step(wpa_auth, group);
+       group->GInit = FALSE;
+       wpa_group_sm_step(wpa_auth, group);
+
        return 0;
 }
 
@@ -620,6 +630,22 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
                return;
        }
 
+       if (sm->wpa == WPA_VERSION_WPA2) {
+               if (key->type != EAPOL_KEY_TYPE_RSN) {
+                       wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with "
+                                  "unexpected type %d in RSN mode",
+                                  key->type);
+                       return;
+               }
+       } else {
+               if (key->type != EAPOL_KEY_TYPE_WPA) {
+                       wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with "
+                                  "unexpected type %d in WPA mode",
+                                  key->type);
+                       return;
+               }
+       }
+
        /* FIX: verify that the EAPOL-Key frame was encrypted if pairwise keys
         * are set */
 
@@ -1503,8 +1529,7 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
 
        igtk.keyid[0] = gsm->GN_igtk;
        igtk.keyid[1] = 0;
-       if (wpa_auth_get_seqnum_igtk(sm->wpa_auth, NULL, gsm->GN_igtk, igtk.pn)
-           < 0)
+       if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, igtk.pn) < 0)
                os_memset(igtk.pn, 0, sizeof(igtk.pn));
        os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
        pos = wpa_add_kde(pos, RSN_KEY_DATA_IGTK,