aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--driver/modules/hostap_common.h19
-rw-r--r--hostapd/Makefile2
-rw-r--r--hostapd/beacon.c81
-rw-r--r--hostapd/config.c10
-rw-r--r--hostapd/config.h10
-rw-r--r--hostapd/driver.h19
-rw-r--r--hostapd/hostapd.c16
-rw-r--r--hostapd/hostapd.conf27
-rw-r--r--hostapd/hostapd.h7
-rw-r--r--hostapd/ieee802_11.c26
-rw-r--r--hostapd/ieee802_11.h4
-rw-r--r--hostapd/ieee802_11h.c34
-rw-r--r--hostapd/ieee802_11h.h18
13 files changed, 271 insertions, 2 deletions
diff --git a/driver/modules/hostap_common.h b/driver/modules/hostap_common.h
index 80c6215..cec9457 100644
--- a/driver/modules/hostap_common.h
+++ b/driver/modules/hostap_common.h
@@ -101,10 +101,14 @@
#define WLAN_STATUS_AUTH_TIMEOUT 16
#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17
#define WLAN_STATUS_ASSOC_DENIED_RATES 18
-/* 802.11b */
+/* IEEE 802.11b */
#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19
#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20
#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21
+/* IEEE 802.11h */
+#define WLAN_STATUS_SPEC_MGMT_REQUIRED 22
+#define WLAN_STATUS_PWR_CAPABILITY_NOT_VALID 23
+#define WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24
/* IEEE 802.11i */
#define WLAN_STATUS_INVALID_IE 40
#define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41
@@ -147,7 +151,20 @@
#define WLAN_EID_CF_PARAMS 4
#define WLAN_EID_TIM 5
#define WLAN_EID_IBSS_PARAMS 6
+#define WLAN_EID_COUNTRY 7
#define WLAN_EID_CHALLENGE 16
+/* EIDs defined by IEEE 802.11h - START */
+#define WLAN_EID_PWR_CONSTRAINT 32
+#define WLAN_EID_PWR_CAPABILITY 33
+#define WLAN_EID_TPC_REQUEST 34
+#define WLAN_EID_TPC_REPORT 35
+#define WLAN_EID_SUPPORTED_CHANNELS 36
+#define WLAN_EID_CHANNEL_SWITCH 37
+#define WLAN_EID_MEASURE_REQUEST 38
+#define WLAN_EID_MEASURE_REPORT 39
+#define WLAN_EID_QUITE 40
+#define WLAN_EID_IBSS_DFS 41
+/* EIDs defined by IEEE 802.11h - END */
#define WLAN_EID_ERP_INFO 42
#define WLAN_EID_RSN 48
#define WLAN_EID_EXT_SUPP_RATES 50
diff --git a/hostapd/Makefile b/hostapd/Makefile
index b45ab2b..a3b83fd 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -41,7 +41,7 @@ OBJS = hostapd.o eloop.o ieee802_1x.o eapol_sm.o radius.o md5.o rc4.o md4.o \
sta_info.o radius_client.o sha1.o wpa.o aes_wrap.o ctrl_iface.o \
driver_conf.o os_$(CONFIG_OS).o preauth.o pmksa_cache.o beacon.o \
hw_features.o wme.o ap_list.o reconfig.o \
- mlme.o vlan_init.o
+ mlme.o vlan_init.o ieee802_11h.o
HOBJS=hlr_auc_gw.o common.o os_$(CONFIG_OS).o milenage.o aes_wrap.o
diff --git a/hostapd/beacon.c b/hostapd/beacon.c
index b53bc76..4e7f93d 100644
--- a/hostapd/beacon.c
+++ b/hostapd/beacon.c
@@ -26,6 +26,7 @@
#include "hw_features.h"
#include "driver.h"
#include "sta_info.h"
+#include "ieee802_11h.h"
static u8 ieee802_11_erp_info(struct hostapd_data *hapd)
@@ -94,6 +95,74 @@ static u8 * hostapd_eid_erp_info(struct hostapd_data *hapd, u8 *eid)
}
+static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
+ int max_len)
+{
+ int left;
+ u8 *pos = eid;
+
+ if ((!hapd->iconf->ieee80211d && !hapd->iface->dfs_enable) ||
+ max_len < 6)
+ return eid;
+
+ *pos++ = WLAN_EID_COUNTRY;
+ pos++; /* length will be set later */
+ memcpy(pos, hapd->iconf->country, 3); /* e.g., 'US ' */
+ pos += 3;
+ left = max_len - 3;
+
+ if ((pos - eid) & 1) {
+ if (left < 1)
+ return eid;
+ *pos++ = 0; /* pad for 16-bit alignment */
+ left--;
+ }
+
+ eid[1] = (pos - eid) - 2;
+
+ return pos;
+}
+
+
+static u8 * hostapd_eid_power_constraint(struct hostapd_data *hapd, u8 *eid)
+
+{
+ if (!hapd->iface->dfs_enable)
+ return eid;
+ *eid++ = WLAN_EID_PWR_CONSTRAINT;
+ *eid++ = 1;
+ *eid++ = hapd->iface->pwr_const;
+ return eid;
+}
+
+
+static u8 * hostapd_eid_tpc_report(struct hostapd_data *hapd, u8 *eid)
+
+{
+ if (!hapd->iface->dfs_enable)
+ return eid;
+ *eid++ = WLAN_EID_TPC_REPORT;
+ *eid++ = 2;
+ *eid++ = hapd->iface->tx_power; /* TX POWER */
+ *eid++ = 0; /* Link Margin */
+ return eid;
+}
+
+static u8 * hostapd_eid_channel_switch(struct hostapd_data *hapd, u8 *eid)
+
+{
+ if (!hapd->iface->dfs_enable || !hapd->iface->channel_switch)
+ return eid;
+ *eid++ = WLAN_EID_CHANNEL_SWITCH;
+ *eid++ = 3;
+ *eid++ = CHAN_SWITCH_MODE_QUIET;
+ *eid++ = hapd->iface->channel_switch; /* New channel */
+ /* 0 - very soon; 1 - before next TBTT; num - after num beacons */
+ *eid++ = 0;
+ return eid;
+}
+
+
static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len,
struct sta_info *sta)
{
@@ -203,6 +272,11 @@ void handle_probe_req(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
/* DS Params */
pos = hostapd_eid_ds_params(hapd, pos);
+ pos = hostapd_eid_country(hapd, pos, epos - pos);
+
+ pos = hostapd_eid_power_constraint(hapd, pos);
+ pos = hostapd_eid_tpc_report(hapd, pos);
+
/* ERP Information element */
pos = hostapd_eid_erp_info(hapd, pos);
@@ -286,6 +360,13 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
head_len = pos - (u8 *) head;
+ tailpos = hostapd_eid_country(hapd, tailpos,
+ tail + BEACON_TAIL_BUF_SIZE - tailpos);
+
+ tailpos = hostapd_eid_power_constraint(hapd, tailpos);
+ tailpos = hostapd_eid_channel_switch(hapd, tailpos);
+ tailpos = hostapd_eid_tpc_report(hapd, tailpos);
+
/* ERP Information element */
tailpos = hostapd_eid_erp_info(hapd, tailpos);
diff --git a/hostapd/config.c b/hostapd/config.c
index 82c9336..9616a94 100644
--- a/hostapd/config.c
+++ b/hostapd/config.c
@@ -227,6 +227,8 @@ static struct hostapd_config * hostapd_config_defaults(void)
conf->send_probe_response = 1;
conf->bridge_packets = INTERNAL_BRIDGE_DO_NOT_CONTROL;
+ sprintf(conf->country, "US ");
+
for (i = 0; i < NUM_TX_QUEUES; i++)
conf->tx_queue[i].aifs = -1; /* use hw default */
@@ -1262,6 +1264,14 @@ struct hostapd_config * hostapd_config_read(const char *fname)
}
} else if (strcmp(buf, "ap_max_inactivity") == 0) {
bss->ap_max_inactivity = atoi(pos);
+ } else if (strcmp(buf, "country_code") == 0) {
+ memcpy(conf->country, pos, 2);
+ /* FIX: make this configurable */
+ conf->country[2] = ' ';
+ } else if (strcmp(buf, "ieee80211d") == 0) {
+ conf->ieee80211d = atoi(pos);
+ } else if (strcmp(buf, "ieee80211h") == 0) {
+ conf->ieee80211h = atoi(pos);
} else if (strcmp(buf, "assoc_ap_addr") == 0) {
if (hwaddr_aton(pos, bss->assoc_ap_addr)) {
printf("Line %d: invalid MAC address '%s'\n",
diff --git a/hostapd/config.h b/hostapd/config.h
index fdc88aa..7f9ab98 100644
--- a/hostapd/config.h
+++ b/hostapd/config.h
@@ -306,6 +306,16 @@ struct hostapd_config {
int ap_table_max_size;
int ap_table_expiration_time;
+ char country[3]; /* first two octets: country code as described in
+ * ISO/IEC 3166-1. Third octet:
+ * ' ' (ascii 32): all environments
+ * 'O': Outdoor environemnt only
+ * 'I': Indoor environment only
+ */
+
+ int ieee80211d;
+ unsigned int ieee80211h; /* Enable/Disable 80211h */
+
struct hostapd_tx_queue_params tx_queue[NUM_TX_QUEUES];
/*
diff --git a/hostapd/driver.h b/hostapd/driver.h
index 68ccc93..b8b1303 100644
--- a/hostapd/driver.h
+++ b/hostapd/driver.h
@@ -83,6 +83,8 @@ struct driver_ops {
unsigned char power_level,
unsigned char antenna_max);
int (*set_regulatory_domain)(void *priv, unsigned int rd);
+ int (*set_country)(void *priv, const char *country);
+ int (*set_ieee80211d)(void *priv, int enabled);
int (*set_beacon)(const char *ifname, void *priv,
u8 *head, size_t head_len,
u8 *tail, size_t tail_len);
@@ -431,6 +433,23 @@ hostapd_set_regulatory_domain(struct hostapd_data *hapd, unsigned int rd)
return hapd->driver->set_regulatory_domain(hapd->driver, rd);
}
+static inline int
+hostapd_set_country(struct hostapd_data *hapd, const char *country)
+{
+ if (hapd->driver == NULL ||
+ hapd->driver->set_country == NULL)
+ return 0;
+ return hapd->driver->set_country(hapd->driver, country);
+}
+
+static inline int
+hostapd_set_ieee80211d(struct hostapd_data *hapd, int enabled)
+{
+ if (hapd->driver == NULL ||
+ hapd->driver->set_ieee80211d == NULL)
+ return 0;
+ return hapd->driver->set_ieee80211d(hapd->driver, enabled);
+}
void driver_register(const char *name, const struct driver_ops *ops);
void driver_unregister(const char *name);
diff --git a/hostapd/hostapd.c b/hostapd/hostapd.c
index 6ab8658..1fd1f60 100644
--- a/hostapd/hostapd.c
+++ b/hostapd/hostapd.c
@@ -1240,6 +1240,7 @@ static int setup_interface1(struct hostapd_iface *iface)
struct hostapd_data *hapd = iface->bss[0];
struct hostapd_bss_config *conf = hapd->conf;
size_t i;
+ char country[4];
/*
* Initialize the driver interface and make sure that all BSSes get
@@ -1257,6 +1258,21 @@ static int setup_interface1(struct hostapd_iface *iface)
if (hostapd_validate_bssid_configuration(iface))
return -1;
+ memcpy(country, hapd->iconf->country, 3);
+ country[3] = '\0';
+ if (hostapd_set_country(hapd, country) < 0) {
+ printf("Failed to set country code\n");
+ return -1;
+ }
+
+ if (hapd->iconf->ieee80211d || hapd->iconf->ieee80211h) {
+ if (hostapd_set_ieee80211d(hapd, 1) < 0) {
+ printf("Failed to set ieee80211d (%d)\n",
+ hapd->iconf->ieee80211d);
+ return -1;
+ }
+ }
+
if (hapd->iconf->bridge_packets != INTERNAL_BRIDGE_DO_NOT_CONTROL &&
hostapd_set_internal_bridge(hapd, hapd->iconf->bridge_packets)) {
printf("Failed to set bridge_packets for kernel driver\n");
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 82c32c2..33dd696 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -77,6 +77,33 @@ ctrl_interface_group=0
# SSID to be used in IEEE 802.11 management frames
ssid=test
+# Country code (ISO/IEC 3166-1). Used to set regulatory domain.
+# Modify as needed to indicate country in which device is operating.
+# This can limit available channels and transmit power.
+# (default: US)
+#country_code=US
+
+# Enable IEEE 802.11d. This advertises the country_code and the set of allowed
+# channels and transmit power levels based on the regulatory limits. The
+# country_code setting must be configured with the correct country for
+# IEEE 802.11d functions.
+# (default: 0 = disabled)
+#ieee80211d=1
+
+# Enable IEEE 802.11h. This enables the TPC and DFS services when operating
+# in a regulatory domain which requires them. Once enabled it will be
+# operational only when working in hw_mode a and in countries where it is
+# required. The end user should not be allowed to disable this.
+# The country_code setting must be configured with the correct country for
+# IEEE 802.11h to function.
+# When IEEE 802.11h is operational, the channel_policy and configured channel
+# settings will be ignored but will behave as though the channel_policy is
+# set to "3" (automatic channel selection). When IEEE 802.11h is enabled but
+# not operational (for example, if the radio mode is changed from "a" to "b")
+# the channel_policy and channel settings take effect again.
+# (default: 1 = enabled)
+#ieee80211h=1
+
# Operation mode (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g,
# Default: IEEE 802.11b
hw_mode=a
diff --git a/hostapd/hostapd.h b/hostapd/hostapd.h
index 5a1beef..49721de 100644
--- a/hostapd/hostapd.h
+++ b/hostapd/hostapd.h
@@ -219,6 +219,13 @@ struct hostapd_iface {
int olbc; /* Overlapping Legacy BSS Condition */
+ int dfs_enable;
+ u8 pwr_const;
+ unsigned int tx_power;
+ unsigned int sta_max_power;
+
+ unsigned int channel_switch;
+
struct hostapd_config_change *change;
hostapd_iface_cb reload_iface_cb;
hostapd_iface_cb config_reload_cb;
diff --git a/hostapd/ieee802_11.c b/hostapd/ieee802_11.c
index d877301..04dfef8 100644
--- a/hostapd/ieee802_11.c
+++ b/hostapd/ieee802_11.c
@@ -36,6 +36,7 @@
#include "accounting.h"
#include "driver.h"
#include "hostap_common.h"
+#include "ieee802_11h.h"
#include "mlme.h"
@@ -143,6 +144,9 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
hapd->iface->num_sta_no_short_slot_time == 0)
capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
+ if (hapd->iface->dfs_enable)
+ capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
+
return capab;
}
@@ -310,6 +314,14 @@ ParseRes ieee802_11_parse_elems(struct hostapd_data *hapd, u8 *start,
elems->rsn_ie = pos;
elems->rsn_ie_len = elen;
break;
+ case WLAN_EID_PWR_CAPABILITY:
+ elems->power_cap = pos;
+ elems->power_cap_len = elen;
+ break;
+ case WLAN_EID_SUPPORTED_CHANNELS:
+ elems->supp_channels = pos;
+ elems->supp_channels_len = elen;
+ break;
default:
unknown++;
if (!show_errors)
@@ -895,6 +907,20 @@ static void handle_assoc(struct hostapd_data *hapd,
goto fail;
}
+ if (hapd->iface->dfs_enable &&
+ hapd->iconf->ieee80211h == SPECT_STRICT_BINDING) {
+ if (hostapd_check_power_cap(hapd, elems.power_cap,
+ elems.power_cap_len)) {
+ resp = WLAN_STATUS_PWR_CAPABILITY_NOT_VALID;
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "Power capabilities of the station not "
+ "acceptable");
+ goto fail;
+ }
+ }
+
if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
sta->flags |= WLAN_STA_NONERP;
for (i = 0; i < sta->supported_rates_len; i++) {
diff --git a/hostapd/ieee802_11.h b/hostapd/ieee802_11.h
index 7c2a0b1..589096b 100644
--- a/hostapd/ieee802_11.h
+++ b/hostapd/ieee802_11.h
@@ -134,6 +134,10 @@ struct ieee802_11_elems {
u8 wme_len;
u8 *wme_tspec;
u8 wme_tspec_len;
+ u8 *power_cap;
+ u8 power_cap_len;
+ u8 *supp_channels;
+ u8 supp_channels_len;
};
typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
diff --git a/hostapd/ieee802_11h.c b/hostapd/ieee802_11h.c
new file mode 100644
index 0000000..926a046
--- /dev/null
+++ b/hostapd/ieee802_11h.c
@@ -0,0 +1,34 @@
+/*
+ * hostapd / IEEE 802.11h
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "hostapd.h"
+
+
+int hostapd_check_power_cap(struct hostapd_data *hapd, u8 *power, u8 len)
+{
+ unsigned int min_pwr, max_pwr;
+
+ if (len < 2) {
+ HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
+ "Too short power capability IE\n");
+ return -1;
+ }
+ min_pwr = power[0];
+ max_pwr = power[1];
+ if (max_pwr > hapd->iface->sta_max_power)
+ return -1;
+ return 0;
+}
diff --git a/hostapd/ieee802_11h.h b/hostapd/ieee802_11h.h
new file mode 100644
index 0000000..584540e
--- /dev/null
+++ b/hostapd/ieee802_11h.h
@@ -0,0 +1,18 @@
+/*
+ * hostapd / IEEE 802.11h
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * All Rights Reserved.
+ */
+
+#ifndef IEEE802_11H_H
+#define IEEE802_11H_H
+
+#define SPECT_LOOSE_BINDING 1
+#define SPECT_STRICT_BINDING 2
+
+#define CHAN_SWITCH_MODE_NOISY 0
+#define CHAN_SWITCH_MODE_QUIET 1
+
+int hostapd_check_power_cap(struct hostapd_data *hapd, u8 *power, u8 len);
+
+#endif /* IEEE802_11H_H */