Browse Source

nl80211: Add support for setting channel frequency and HT20 vs. HT40

This depends on a patch to Linux nl80211/mac80211 that has not yet been
merged into wireless-testing. If that change is not present, the old
mechanism (WEXT) will be used instead.
Jouni Malinen 16 years ago
parent
commit
95da9bbc36
4 changed files with 60 additions and 7 deletions
  1. 1 1
      hostapd/config.h
  2. 24 2
      hostapd/driver.h
  3. 33 3
      hostapd/driver_nl80211.c
  4. 2 1
      hostapd/hostapd.c

+ 1 - 1
hostapd/config.h

@@ -378,8 +378,8 @@ struct hostapd_config {
 	int ieee80211n;
 	int ieee80211n;
 	int ht_op_mode_fixed;
 	int ht_op_mode_fixed;
 	u16 ht_capab;
 	u16 ht_capab;
-	int secondary_channel;
 #endif /* CONFIG_IEEE80211N */
 #endif /* CONFIG_IEEE80211N */
+	int secondary_channel;
 };
 };
 
 
 
 

+ 24 - 2
hostapd/driver.h

@@ -27,6 +27,14 @@ struct hostapd_sta_add_params {
 	const struct ht_cap_ie *ht_capabilities;
 	const struct ht_cap_ie *ht_capabilities;
 };
 };
 
 
+struct hostapd_freq_params {
+	int mode;
+	int freq;
+	int sec_channel_offset; /* 0 = HT40 disabled, -1 = HT40 enabled,
+				 * secondary channel below primary, 1 = HT40
+				 * enabled, secondary channel above primary */
+};
+
 enum hostapd_driver_if_type {
 enum hostapd_driver_if_type {
 	HOSTAPD_IF_VLAN, HOSTAPD_IF_WDS
 	HOSTAPD_IF_VLAN, HOSTAPD_IF_WDS
 };
 };
@@ -99,7 +107,9 @@ struct wpa_driver_ops {
 	int (*get_inact_sec)(void *priv, const u8 *addr);
 	int (*get_inact_sec)(void *priv, const u8 *addr);
 	int (*sta_clear_stats)(void *priv, const u8 *addr);
 	int (*sta_clear_stats)(void *priv, const u8 *addr);
 
 
+	/* note: set_freq() is deprecated; use sta_freq() instead */
 	int (*set_freq)(void *priv, int mode, int freq);
 	int (*set_freq)(void *priv, int mode, int freq);
+	int (*set_freq2)(void *priv, struct hostapd_freq_params *freq);
 	int (*set_rts)(void *priv, int rts);
 	int (*set_rts)(void *priv, int rts);
 	int (*get_rts)(void *priv, int *rts);
 	int (*get_rts)(void *priv, int *rts);
 	int (*set_frag)(void *priv, int frag);
 	int (*set_frag)(void *priv, int frag);
@@ -421,9 +431,21 @@ hostapd_get_inact_sec(struct hostapd_data *hapd, const u8 *addr)
 }
 }
 
 
 static inline int
 static inline int
-hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq)
+hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq,
+		 int sec_channel_offset)
 {
 {
-	if (hapd->driver == NULL || hapd->driver->set_freq == NULL)
+	if (hapd->driver == NULL)
+		return 0;
+	if (hapd->driver->set_freq2) {
+		struct hostapd_freq_params data;
+		os_memset(&data, 0, sizeof(data));
+		data.mode = mode;
+		data.freq = freq;
+		data.sec_channel_offset = sec_channel_offset;
+		return hapd->driver->set_freq2(hapd->drv_priv, &data);
+	}
+
+	if (hapd->driver->set_freq == NULL)
 		return 0;
 		return 0;
 	return hapd->driver->set_freq(hapd->drv_priv, mode, freq);
 	return hapd->driver->set_freq(hapd->drv_priv, mode, freq);
 }
 }

+ 33 - 3
hostapd/driver_nl80211.c

@@ -461,14 +461,43 @@ static int i802_send_mgmt_frame(void *priv, const void *data, size_t len,
 }
 }
 
 
 /* Set kernel driver on given frequency (MHz) */
 /* Set kernel driver on given frequency (MHz) */
-static int i802_set_freq(void *priv, int mode, int freq)
+static int i802_set_freq2(void *priv, struct hostapd_freq_params *freq)
 {
 {
+#ifdef NL80211_ATTR_WIPHY_FREQ
+	struct i802_driver_data *drv = priv;
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+		    NL80211_CMD_SET_WIPHY, 0);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface));
+	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq);
+	switch (freq->sec_channel_offset) {
+	case -1:
+		NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET,
+			   NL80211_SEC_CHAN_BELOW);
+		break;
+	case 1:
+		NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET,
+			   NL80211_SEC_CHAN_ABOVE);
+		break;
+	}
+
+	if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
+		return 0;
+ nla_put_failure:
+	return -1;
+#else /* NL80211_ATTR_WIPHY_FREQ */
 	struct i802_driver_data *drv = priv;
 	struct i802_driver_data *drv = priv;
 	struct iwreq iwr;
 	struct iwreq iwr;
 
 
 	memset(&iwr, 0, sizeof(iwr));
 	memset(&iwr, 0, sizeof(iwr));
 	os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ);
 	os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ);
-	iwr.u.freq.m = freq;
+	iwr.u.freq.m = freq->freq;
 	iwr.u.freq.e = 6;
 	iwr.u.freq.e = 6;
 
 
 	if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
 	if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
@@ -477,6 +506,7 @@ static int i802_set_freq(void *priv, int mode, int freq)
 	}
 	}
 
 
 	return 0;
 	return 0;
+#endif /* NL80211_ATTR_WIPHY_FREQ */
 }
 }
 
 
 
 
@@ -2402,7 +2432,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 	.sta_add2 = i802_sta_add2,
 	.sta_add2 = i802_sta_add2,
 	.get_inact_sec = i802_get_inact_sec,
 	.get_inact_sec = i802_get_inact_sec,
 	.sta_clear_stats = i802_sta_clear_stats,
 	.sta_clear_stats = i802_sta_clear_stats,
-	.set_freq = i802_set_freq,
+	.set_freq2 = i802_set_freq2,
 	.set_rts = i802_set_rts,
 	.set_rts = i802_set_rts,
 	.get_rts = i802_get_rts,
 	.get_rts = i802_get_rts,
 	.set_frag = i802_set_frag,
 	.set_frag = i802_set_frag,

+ 2 - 1
hostapd/hostapd.c

@@ -1553,7 +1553,8 @@ static int setup_interface(struct hostapd_iface *iface)
 		       hostapd_hw_mode_txt(hapd->iconf->hw_mode),
 		       hostapd_hw_mode_txt(hapd->iconf->hw_mode),
 		       hapd->iconf->channel, freq);
 		       hapd->iconf->channel, freq);
 
 
-		if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, freq)) {
+		if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, freq,
+				     hapd->iconf->secondary_channel)) {
 			printf("Could not set channel for kernel driver\n");
 			printf("Could not set channel for kernel driver\n");
 			return -1;
 			return -1;
 		}
 		}