Browse Source

Add Beacon configuration for wpa_supplicant AP mode

Jouni Malinen 16 years ago
parent
commit
d2440ba01b

+ 7 - 2
src/drivers/driver.h

@@ -1142,8 +1142,13 @@ struct wpa_driver_ops {
 	 * function is expected to take care of IEEE 802.11 authentication,
 	 * function is expected to take care of IEEE 802.11 authentication,
 	 * too.
 	 * too.
 	 */
 	 */
-	 int (*authenticate)(void *priv,
-			     struct wpa_driver_auth_params *params);
+	int (*authenticate)(void *priv,
+			    struct wpa_driver_auth_params *params);
+
+	int (*set_beacon)(void *priv, const u8 *head, size_t head_len,
+			  const u8 *tail, size_t tail_len, int dtim_period);
+
+	int (*set_beacon_int)(void *priv, int value);
 };
 };
 
 
 /**
 /**

+ 3 - 1
src/drivers/driver_ndis.c

@@ -3215,5 +3215,7 @@ const struct wpa_driver_ops wpa_driver_ndis_ops = {
 	NULL /* init2 */,
 	NULL /* init2 */,
 	wpa_driver_ndis_get_interfaces,
 	wpa_driver_ndis_get_interfaces,
 	NULL /* scan2 */,
 	NULL /* scan2 */,
-	NULL /* authenticate */
+	NULL /* authenticate */,
+	NULL /* set_beacon */,
+	NULL /* set_beacon_int */
 };
 };

+ 84 - 4
src/drivers/driver_nl80211.c

@@ -64,6 +64,11 @@ struct wpa_driver_nl80211_data {
 	int associated;
 	int associated;
 	u8 ssid[32];
 	u8 ssid[32];
 	size_t ssid_len;
 	size_t ssid_len;
+
+#ifdef CONFIG_AP
+	int beacon_int;
+	unsigned int beacon_set:1;
+#endif /* CONFIG_AP */
 };
 };
 
 
 
 
@@ -1517,11 +1522,81 @@ nla_put_failure:
 
 
 
 
 #ifdef CONFIG_AP
 #ifdef CONFIG_AP
+static int wpa_driver_nl80211_set_beacon(void *priv,
+					 const u8 *head, size_t head_len,
+					 const u8 *tail, size_t tail_len,
+					 int dtim_period)
+{
+	struct wpa_driver_nl80211_data *drv = priv;
+	struct nl_msg *msg;
+	u8 cmd = NL80211_CMD_NEW_BEACON;
+	int ret;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Set beacon (beacon_set=%d)",
+		   drv->beacon_set);
+	if (drv->beacon_set)
+		cmd = NL80211_CMD_SET_BEACON;
+
+	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+		    0, cmd, 0);
+	NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, head_len, head);
+	NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, tail_len, tail);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	if (!drv->beacon_int)
+		drv->beacon_int = 100;
+	NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, drv->beacon_int);
+	NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, dtim_period);
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
+			   ret, strerror(-ret));
+	} else
+		drv->beacon_set = 1;
+	return ret;
+ nla_put_failure:
+	return -ENOBUFS;
+}
+
+
+static int wpa_driver_nl80211_set_beacon_int(void *priv, int value)
+{
+	struct wpa_driver_nl80211_data *drv = priv;
+	struct nl_msg *msg;
+
+	drv->beacon_int = value;
+
+	if (!drv->beacon_set)
+		return 0;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Set beacon interval %d "
+		   "(beacon_set=%d)", value, drv->beacon_set);
+	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+		    0, NL80211_CMD_SET_BEACON, 0);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, value);
+
+	return send_and_recv_msgs(drv, msg, NULL, NULL);
+ nla_put_failure:
+	return -ENOBUFS;
+}
+
+
 static int wpa_driver_nl80211_set_freq2(
 static int wpa_driver_nl80211_set_freq2(
 	struct wpa_driver_nl80211_data *drv,
 	struct wpa_driver_nl80211_data *drv,
 	struct wpa_driver_associate_params *params)
 	struct wpa_driver_associate_params *params)
 {
 {
 	struct nl_msg *msg;
 	struct nl_msg *msg;
+	int ret;
 
 
 	msg = nlmsg_alloc();
 	msg = nlmsg_alloc();
 	if (!msg)
 	if (!msg)
@@ -1532,11 +1607,13 @@ static int wpa_driver_nl80211_set_freq2(
 
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 
 
-	/* TODO: proper channel configuration */
-	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, 2437);
+	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
 
 
-	if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	if (ret == 0)
 		return 0;
 		return 0;
+	wpa_printf(MSG_DEBUG, "nl80211: MLME Failed to set channel (freq=%d): "
+		   "%d (%s)", params->freq, ret, strerror(-ret));
 nla_put_failure:
 nla_put_failure:
 	return -1;
 	return -1;
 }
 }
@@ -1551,7 +1628,6 @@ static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
 
 
 	/* TODO: setup monitor interface (and add code somewhere to remove this
 	/* TODO: setup monitor interface (and add code somewhere to remove this
 	 * when AP mode is stopped; associate with mode != 2 or drv_deinit) */
 	 * when AP mode is stopped; associate with mode != 2 or drv_deinit) */
-	/* TODO: setup beacon */
 
 
 	return 0;
 	return 0;
 }
 }
@@ -1748,4 +1824,8 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 	.get_capa = wpa_driver_nl80211_get_capa,
 	.get_capa = wpa_driver_nl80211_get_capa,
 	.set_operstate = wpa_driver_nl80211_set_operstate,
 	.set_operstate = wpa_driver_nl80211_set_operstate,
 	.set_country = wpa_driver_nl80211_set_country,
 	.set_country = wpa_driver_nl80211_set_country,
+#ifdef CONFIG_AP
+	.set_beacon = wpa_driver_nl80211_set_beacon,
+	.set_beacon_int = wpa_driver_nl80211_set_beacon_int,
+#endif /* CONFIG_AP */
 };
 };

+ 3 - 1
src/drivers/driver_privsep.c

@@ -811,7 +811,9 @@ struct wpa_driver_ops wpa_driver_privsep_ops = {
 	NULL /* init2 */,
 	NULL /* init2 */,
 	NULL /* get_interfaces */,
 	NULL /* get_interfaces */,
 	NULL /* scan2 */,
 	NULL /* scan2 */,
-	NULL /* authenticate */
+	NULL /* authenticate */,
+	NULL /* set_beacon */,
+	NULL /* set_beacon_int */
 };
 };
 
 
 
 

+ 3 - 1
src/drivers/driver_test.c

@@ -1327,5 +1327,7 @@ const struct wpa_driver_ops wpa_driver_test_ops = {
 	wpa_driver_test_init2,
 	wpa_driver_test_init2,
 	wpa_driver_test_get_interfaces,
 	wpa_driver_test_get_interfaces,
 	wpa_driver_test_scan,
 	wpa_driver_test_scan,
-	NULL /* authenticate */
+	NULL /* authenticate */,
+	NULL /* set_beacon */,
+	NULL /* set_beacon_int */
 };
 };

+ 25 - 27
wpa_supplicant/ap.c

@@ -180,25 +180,22 @@ static int ap_driver_set_freq(void *priv, struct hostapd_freq_params *freq)
 
 
 
 
 static int ap_driver_set_beacon(const char *iface, void *priv,
 static int ap_driver_set_beacon(const char *iface, void *priv,
-				u8 *head, size_t head_len,
-				u8 *tail, size_t tail_len)
+				const u8 *head, size_t head_len,
+				const u8 *tail, size_t tail_len,
+				int dtim_period)
 {
 {
-	wpa_printf(MSG_DEBUG, "AP TODO: %s", __func__);
-	return -1;
+	struct ap_driver_data *drv = priv;
+	struct wpa_supplicant *wpa_s = drv->hapd->iface->owner;
+	return wpa_drv_set_beacon(wpa_s, head, head_len, tail, tail_len,
+				  dtim_period);
 }
 }
 
 
 
 
 static int ap_driver_set_beacon_int(void *priv, int value)
 static int ap_driver_set_beacon_int(void *priv, int value)
 {
 {
-	wpa_printf(MSG_DEBUG, "AP TODO: %s", __func__);
-	return -1;
-}
-
-
-static int ap_driver_set_dtim_period(const char *iface, void *priv, int value)
-{
-	wpa_printf(MSG_DEBUG, "AP TODO: %s", __func__);
-	return -1;
+	struct ap_driver_data *drv = priv;
+	struct wpa_supplicant *wpa_s = drv->hapd->iface->owner;
+	return wpa_drv_set_beacon_int(wpa_s, value);
 }
 }
 
 
 
 
@@ -261,7 +258,6 @@ static struct hapd_driver_ops ap_driver_ops =
 	.set_freq = ap_driver_set_freq,
 	.set_freq = ap_driver_set_freq,
 	.set_beacon = ap_driver_set_beacon,
 	.set_beacon = ap_driver_set_beacon,
 	.set_beacon_int = ap_driver_set_beacon_int,
 	.set_beacon_int = ap_driver_set_beacon_int,
-	.set_dtim_period = ap_driver_set_dtim_period,
 	.set_cts_protect = ap_driver_set_cts_protect,
 	.set_cts_protect = ap_driver_set_cts_protect,
 	.set_preamble = ap_driver_set_preamble,
 	.set_preamble = ap_driver_set_preamble,
 	.set_short_slot_time = ap_driver_set_short_slot_time,
 	.set_short_slot_time = ap_driver_set_short_slot_time,
@@ -348,6 +344,21 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
 	}
 	}
 
 
 	wpa_supplicant_ap_deinit(wpa_s);
 	wpa_supplicant_ap_deinit(wpa_s);
+
+	wpa_printf(MSG_DEBUG, "Setting up AP (SSID='%s')",
+		   wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+
+	os_memset(&params, 0, sizeof(params));
+	params.ssid = ssid->ssid;
+	params.ssid_len = ssid->ssid_len;
+	params.mode = ssid->mode;
+	params.freq = ssid->frequency;
+
+	if (wpa_drv_associate(wpa_s, &params) < 0) {
+		wpa_msg(wpa_s, MSG_INFO, "Failed to start AP functionality");
+		return -1;
+	}
+
 	wpa_s->ap_iface = hapd_iface = os_zalloc(sizeof(*wpa_s->ap_iface));
 	wpa_s->ap_iface = hapd_iface = os_zalloc(sizeof(*wpa_s->ap_iface));
 	if (hapd_iface == NULL)
 	if (hapd_iface == NULL)
 		return -1;
 		return -1;
@@ -389,19 +400,6 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
 		return -1;
 		return -1;
 	}
 	}
 
 
-	wpa_printf(MSG_DEBUG, "Setting up AP (SSID='%s')",
-		   wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
-
-	os_memset(&params, 0, sizeof(params));
-	params.ssid = ssid->ssid;
-	params.ssid_len = ssid->ssid_len;
-	params.mode = ssid->mode;
-
-	if (wpa_drv_associate(wpa_s, &params) < 0) {
-		wpa_msg(wpa_s, MSG_INFO, "Failed to start AP functionality");
-		return -1;
-	}
-
 	return 0;
 	return 0;
 }
 }
 
 

+ 20 - 0
wpa_supplicant/driver_i.h

@@ -378,4 +378,24 @@ static inline int wpa_drv_set_probe_req_ie(struct wpa_supplicant *wpa_s,
 	return -1;
 	return -1;
 }
 }
 
 
+static inline int wpa_drv_set_beacon(struct wpa_supplicant *wpa_s,
+				     const u8 *head, size_t head_len,
+				     const u8 *tail, size_t tail_len,
+				     int dtim_period)
+{
+	if (wpa_s->driver->set_beacon)
+		return wpa_s->driver->set_beacon(wpa_s->drv_priv, head,
+						 head_len, tail, tail_len,
+						 dtim_period);
+	return -1;
+}
+
+static inline int wpa_drv_set_beacon_int(struct wpa_supplicant *wpa_s,
+					 int value)
+{
+	if (wpa_s->driver->set_beacon_int)
+		return wpa_s->driver->set_beacon_int(wpa_s->drv_priv, value);
+	return -1;
+}
+
 #endif /* DRIVER_I_H */
 #endif /* DRIVER_I_H */