Browse Source

wpa_supplicant AP: Add EAPOL frame TX and RX

This allows WPA-Personal 4-way handshake to be completed successfully.
Jouni Malinen 16 years ago
parent
commit
db149ac949
5 changed files with 111 additions and 71 deletions
  1. 71 71
      src/drivers/driver_nl80211.c
  2. 19 0
      wpa_supplicant/ap.c
  3. 2 0
      wpa_supplicant/ap.h
  4. 12 0
      wpa_supplicant/driver_i.h
  5. 7 0
      wpa_supplicant/wpa_supplicant.c

+ 71 - 71
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,

+ 19 - 0
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);
+}

+ 2 - 0
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 */

+ 12 - 0
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 */

+ 7 - 0
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");