aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2006-10-21 00:04:53 (GMT)
committerJouni Malinen <j@w1.fi>2006-10-21 00:04:53 (GMT)
commitf2c87bc794c6515779b8162a20d5792cd501c260 (patch)
tree103594ebcfd81e98d88c129e12df2f0768631580
parent25d7da278784a01a4a903012359b2260648f4a4f (diff)
downloadhostap-history-f2c87bc794c6515779b8162a20d5792cd501c260.zip
hostap-history-f2c87bc794c6515779b8162a20d5792cd501c260.tar.gz
hostap-history-f2c87bc794c6515779b8162a20d5792cd501c260.tar.bz2
Added preliminary code for IEEE 802.11d and 802.11h support. This is
not yet complete, so the functionality is not available, but the basic helper functions and some of the configuration options are now in. (from Devicescape)
-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 */