From 95da9bbc364778c4cc72dff9d60f74bc1dbdfbb5 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 25 Nov 2008 20:59:39 +0200 Subject: [PATCH] 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. --- hostapd/config.h | 2 +- hostapd/driver.h | 26 ++++++++++++++++++++++++-- hostapd/driver_nl80211.c | 36 +++++++++++++++++++++++++++++++++--- hostapd/hostapd.c | 3 ++- 4 files changed, 60 insertions(+), 7 deletions(-) diff --git a/hostapd/config.h b/hostapd/config.h index c776b7faf..832d65717 100644 --- a/hostapd/config.h +++ b/hostapd/config.h @@ -378,8 +378,8 @@ struct hostapd_config { int ieee80211n; int ht_op_mode_fixed; u16 ht_capab; - int secondary_channel; #endif /* CONFIG_IEEE80211N */ + int secondary_channel; }; diff --git a/hostapd/driver.h b/hostapd/driver.h index 723275f7d..4331e1b48 100644 --- a/hostapd/driver.h +++ b/hostapd/driver.h @@ -27,6 +27,14 @@ struct hostapd_sta_add_params { 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 { HOSTAPD_IF_VLAN, HOSTAPD_IF_WDS }; @@ -99,7 +107,9 @@ struct wpa_driver_ops { int (*get_inact_sec)(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_freq2)(void *priv, struct hostapd_freq_params *freq); int (*set_rts)(void *priv, int rts); int (*get_rts)(void *priv, int *rts); 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 -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 hapd->driver->set_freq(hapd->drv_priv, mode, freq); } diff --git a/hostapd/driver_nl80211.c b/hostapd/driver_nl80211.c index 3fcb4dd36..b2529b1f2 100644 --- a/hostapd/driver_nl80211.c +++ b/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) */ -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 iwreq iwr; memset(&iwr, 0, sizeof(iwr)); 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; 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; +#endif /* NL80211_ATTR_WIPHY_FREQ */ } @@ -2402,7 +2432,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .sta_add2 = i802_sta_add2, .get_inact_sec = i802_get_inact_sec, .sta_clear_stats = i802_sta_clear_stats, - .set_freq = i802_set_freq, + .set_freq2 = i802_set_freq2, .set_rts = i802_set_rts, .get_rts = i802_get_rts, .set_frag = i802_set_frag, diff --git a/hostapd/hostapd.c b/hostapd/hostapd.c index 937e48a9e..681ebbfd0 100644 --- a/hostapd/hostapd.c +++ b/hostapd/hostapd.c @@ -1553,7 +1553,8 @@ static int setup_interface(struct hostapd_iface *iface) hostapd_hw_mode_txt(hapd->iconf->hw_mode), 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"); return -1; }