nl80211: Add support for setting channel frequency and HT20 vs. HT40
authorJouni Malinen <jouni.malinen@atheros.com>
Tue, 25 Nov 2008 18:59:39 +0000 (20:59 +0200)
committerJouni Malinen <j@w1.fi>
Tue, 25 Nov 2008 18:59:39 +0000 (20:59 +0200)
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
hostapd/driver.h
hostapd/driver_nl80211.c
hostapd/hostapd.c

index c776b7f..832d657 100644 (file)
@@ -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;
 };
 
 
index 723275f..4331e1b 100644 (file)
@@ -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);
 }
index 3fcb4dd..b2529b1 100644 (file)
@@ -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,
index 937e48a..681ebbf 100644 (file)
@@ -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;
                }