From db149ac9492c7da0db7e172cf777a4385712c278 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 20 Apr 2009 16:27:45 +0300 Subject: [PATCH] wpa_supplicant AP: Add EAPOL frame TX and RX This allows WPA-Personal 4-way handshake to be completed successfully. --- src/drivers/driver_nl80211.c | 142 ++++++++++++++++---------------- wpa_supplicant/ap.c | 19 +++++ wpa_supplicant/ap.h | 2 + wpa_supplicant/driver_i.h | 12 +++ wpa_supplicant/wpa_supplicant.c | 7 ++ 5 files changed, 111 insertions(+), 71 deletions(-) diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 95fa6d185..7c5503c7d 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -2885,6 +2885,76 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv) return -1; } + +static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; + +static int wpa_driver_nl80211_hapd_send_eapol( + void *priv, const u8 *addr, const u8 *data, + size_t data_len, int encrypt, const u8 *own_addr) +{ + struct wpa_driver_nl80211_data *drv = priv; + struct ieee80211_hdr *hdr; + size_t len; + u8 *pos; + int res; +#if 0 /* FIX */ + int qos = sta->flags & WLAN_STA_WME; +#else + int qos = 0; +#endif + + len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 + + data_len; + hdr = os_zalloc(len); + if (hdr == NULL) { + printf("malloc() failed for i802_send_data(len=%lu)\n", + (unsigned long) len); + return -1; + } + + hdr->frame_control = + IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA); + hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS); + if (encrypt) + hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP); +#if 0 /* To be enabled if qos determination is added above */ + if (qos) { + hdr->frame_control |= + host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4); + } +#endif + + memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN); + memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN); + memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); + pos = (u8 *) (hdr + 1); + +#if 0 /* To be enabled if qos determination is added above */ + if (qos) { + /* add an empty QoS header if needed */ + pos[0] = 0; + pos[1] = 0; + pos += 2; + } +#endif + + memcpy(pos, rfc1042_header, sizeof(rfc1042_header)); + pos += sizeof(rfc1042_header); + WPA_PUT_BE16(pos, ETH_P_PAE); + pos += 2; + memcpy(pos, data, data_len); + + res = wpa_driver_nl80211_send_frame(drv, (u8 *) hdr, len, encrypt); + if (res < 0) { + wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - " + "failed: %d (%s)", + (unsigned long) len, errno, strerror(errno)); + } + free(hdr); + + return res; +} + #endif /* CONFIG_AP || HOSTAPD */ #ifdef CONFIG_AP @@ -3094,9 +3164,6 @@ static int wpa_driver_nl80211_set_operstate(void *priv, int state) #ifdef HOSTAPD -static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; - - static struct i802_bss * get_bss(struct wpa_driver_nl80211_data *drv, int ifindex) { @@ -3450,73 +3517,6 @@ static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data, } -static int i802_send_eapol(void *priv, const u8 *addr, const u8 *data, - size_t data_len, int encrypt, const u8 *own_addr) -{ - struct wpa_driver_nl80211_data *drv = priv; - struct ieee80211_hdr *hdr; - size_t len; - u8 *pos; - int res; -#if 0 /* FIX */ - int qos = sta->flags & WLAN_STA_WME; -#else - int qos = 0; -#endif - - len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 + - data_len; - hdr = os_zalloc(len); - if (hdr == NULL) { - printf("malloc() failed for i802_send_data(len=%lu)\n", - (unsigned long) len); - return -1; - } - - hdr->frame_control = - IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA); - hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS); - if (encrypt) - hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP); -#if 0 /* To be enabled if qos determination is added above */ - if (qos) { - hdr->frame_control |= - host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4); - } -#endif - - memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN); - memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN); - memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); - pos = (u8 *) (hdr + 1); - -#if 0 /* To be enabled if qos determination is added above */ - if (qos) { - /* add an empty QoS header if needed */ - pos[0] = 0; - pos[1] = 0; - pos += 2; - } -#endif - - memcpy(pos, rfc1042_header, sizeof(rfc1042_header)); - pos += sizeof(rfc1042_header); - WPA_PUT_BE16(pos, ETH_P_PAE); - pos += 2; - memcpy(pos, data, data_len); - - res = wpa_driver_nl80211_send_frame(drv, (u8 *) hdr, len, encrypt); - if (res < 0) { - wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - " - "failed: %d (%s)", - (unsigned long) len, errno, strerror(errno)); - } - free(hdr); - - return res; -} - - static int i802_sta_set_flags(void *priv, const u8 *addr, int total_flags, int flags_or, int flags_and) { @@ -3969,6 +3969,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data, .sta_add = wpa_driver_nl80211_sta_add, .sta_remove = wpa_driver_nl80211_sta_remove, + .hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol, #endif /* CONFIG_AP || HOSTAPD */ #ifdef HOSTAPD .hapd_init = i802_init, @@ -3977,7 +3978,6 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .get_seqnum = i802_get_seqnum, .flush = i802_flush, .read_sta_data = i802_read_sta_data, - .hapd_send_eapol = i802_send_eapol, .sta_set_flags = i802_sta_set_flags, .sta_deauth = i802_sta_deauth, .sta_disassoc = i802_sta_disassoc, diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c index 9fcdaabe0..4ab4cc965 100644 --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -248,6 +248,17 @@ static struct hostapd_hw_modes *ap_driver_get_hw_feature_data(void *priv, } +static int ap_driver_hapd_send_eapol(void *priv, const u8 *addr, + const u8 *data, size_t data_len, + int encrypt, const u8 *own_addr) +{ + struct ap_driver_data *drv = priv; + struct wpa_supplicant *wpa_s = drv->hapd->iface->owner; + return wpa_drv_hapd_send_eapol(wpa_s, addr, data, data_len, encrypt, + own_addr); +} + + struct wpa_driver_ops ap_driver_ops = { .name = "wpa_supplicant", @@ -273,6 +284,7 @@ struct wpa_driver_ops ap_driver_ops = .set_short_slot_time = ap_driver_set_short_slot_time, .set_tx_queue_params = ap_driver_set_tx_queue_params, .get_hw_feature_data = ap_driver_get_hw_feature_data, + .hapd_send_eapol = ap_driver_hapd_send_eapol, }; @@ -486,3 +498,10 @@ void ap_mgmt_tx_cb(void *ctx, u8 *buf, size_t len, u16 stype, int ok) ieee802_11_mgmt_cb(wpa_s->ap_iface->bss[0], buf, len, stype, ok); } #endif /* NEED_MLME */ + + +void wpa_supplicant_ap_rx_eapol(struct wpa_supplicant *wpa_s, + const u8 *src_addr, const u8 *buf, size_t len) +{ + hostapd_eapol_receive(wpa_s->ap_iface->bss[0], src_addr, buf, len); +} diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h index 1234954a8..782c53ae2 100644 --- a/wpa_supplicant/ap.h +++ b/wpa_supplicant/ap.h @@ -19,5 +19,7 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpa_supplicant_ap_deinit(struct wpa_supplicant *wpa_s); +void wpa_supplicant_ap_rx_eapol(struct wpa_supplicant *wpa_s, + const u8 *src_addr, const u8 *buf, size_t len); #endif /* AP_H */ diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index 0c10b0f3d..45107f7b9 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -415,4 +415,16 @@ static inline int wpa_drv_sta_remove(struct wpa_supplicant *wpa_s, return -1; } +static inline int wpa_drv_hapd_send_eapol(struct wpa_supplicant *wpa_s, + const u8 *addr, const u8 *data, + size_t data_len, int encrypt, + const u8 *own_addr) +{ + if (wpa_s->driver->hapd_send_eapol) + return wpa_s->driver->hapd_send_eapol(wpa_s->drv_priv, addr, + data, data_len, encrypt, + own_addr); + return -1; +} + #endif /* DRIVER_I_H */ diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index f730bcfbb..7804f7b39 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -1570,6 +1570,13 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, wpa_printf(MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr)); wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len); +#ifdef CONFIG_AP + if (wpa_s->ap_iface) { + wpa_supplicant_ap_rx_eapol(wpa_s, src_addr, buf, len); + return; + } +#endif /* CONFIG_AP */ + if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) { wpa_printf(MSG_DEBUG, "Ignored received EAPOL frame since " "no key management is configured");