From df73d284fbe60721ddedf565f53dae543348e306 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 25 Nov 2008 11:56:28 +0200 Subject: [PATCH] Added support for generating Country IE based on nl80211 regulatory info --- hostapd/ChangeLog | 2 ++ hostapd/beacon.c | 62 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog index 57b9b2e4d..aa4e2b1a6 100644 --- a/hostapd/ChangeLog +++ b/hostapd/ChangeLog @@ -11,6 +11,8 @@ ChangeLog for hostapd wps_pbc are used to configuration WPS negotiation; see README-WPS for more details * added IEEE 802.11n HT capability configuration (ht_capab) + * added support for generating Country IE based on nl80211 regulatory + information (added if ieee80211d=1 in configuration) 2008-11-23 - v0.6.6 * added a new configuration option, wpa_ptk_rekey, that can be used to diff --git a/hostapd/beacon.c b/hostapd/beacon.c index a464db732..35c702849 100644 --- a/hostapd/beacon.c +++ b/hostapd/beacon.c @@ -96,12 +96,36 @@ static u8 * hostapd_eid_erp_info(struct hostapd_data *hapd, u8 *eid) } +static u8 * hostapd_eid_country_add(u8 *pos, u8 *end, int chan_spacing, + struct hostapd_channel_data *start, + struct hostapd_channel_data *prev) +{ + if (end - pos < 3) + return pos; + + /* first channel number */ + *pos++ = start->chan; + /* number of channels */ + *pos++ = (prev->chan - start->chan) / chan_spacing + 1; + /* maximum transmit power level */ + *pos++ = start->max_tx_power; + + return pos; +} + + static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid, int max_len) { u8 *pos = eid; + u8 *end = eid + max_len; + int i; + struct hostapd_hw_modes *mode; + struct hostapd_channel_data *start, *prev; + int chan_spacing = 1; - if (!hapd->iconf->ieee80211d || max_len < 6) + if (!hapd->iconf->ieee80211d || max_len < 6 || + hapd->iface->current_mode == NULL) return eid; *pos++ = WLAN_EID_COUNTRY; @@ -109,8 +133,42 @@ static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid, os_memcpy(pos, hapd->iconf->country, 3); /* e.g., 'US ' */ pos += 3; - if ((pos - eid) & 1) + mode = hapd->iface->current_mode; + if (mode->mode == HOSTAPD_MODE_IEEE80211A) + chan_spacing = 4; + + start = prev = NULL; + for (i = 0; i < mode->num_channels; i++) { + struct hostapd_channel_data *chan = &mode->channels[i]; + if (chan->flag & HOSTAPD_CHAN_DISABLED) + continue; + if (start && prev && + prev->chan + chan_spacing == chan->chan && + start->max_tx_power == chan->max_tx_power) { + prev = chan; + continue; /* can use same entry */ + } + + if (start) { + pos = hostapd_eid_country_add(pos, end, chan_spacing, + start, prev); + start = NULL; + } + + /* Start new group */ + start = prev = chan; + } + + if (start) { + pos = hostapd_eid_country_add(pos, end, chan_spacing, + start, prev); + } + + if ((pos - eid) & 1) { + if (end - pos < 1) + return eid; *pos++ = 0; /* pad for 16-bit alignment */ + } eid[1] = (pos - eid) - 2;