summaryrefslogtreecommitdiffstats
path: root/sys/net80211
diff options
context:
space:
mode:
authoradrian <adrian@FreeBSD.org>2011-11-08 04:00:24 +0000
committeradrian <adrian@FreeBSD.org>2011-11-08 04:00:24 +0000
commit1a3216b0414a93a36aa9bbf154f8e323454f5ac4 (patch)
tree496f530d1aaf071e9027c713f25bab37278804e4 /sys/net80211
parent476761abc0abdd48513d660ddbe8ce091975f133 (diff)
downloadFreeBSD-src-1a3216b0414a93a36aa9bbf154f8e323454f5ac4.zip
FreeBSD-src-1a3216b0414a93a36aa9bbf154f8e323454f5ac4.tar.gz
Add 802.11h quiet time element support into net80211.
This supports both station and hostap modes: * Station mode quiet time element support listens to quiet time IE's and modifies the local quiet time configuration as appropriate; * Hostap mode both obeys the locally configured quiet time period and includes it in beacon frames so stations also can obey as needed. Submitted by: Himali Patel <himali.patel@sibridgetech.com> Sponsored by: Sibridge Technologies
Diffstat (limited to 'sys/net80211')
-rw-r--r--sys/net80211/ieee80211.h12
-rw-r--r--sys/net80211/ieee80211_dfs.c8
-rw-r--r--sys/net80211/ieee80211_input.c3
-rw-r--r--sys/net80211/ieee80211_ioctl.c33
-rw-r--r--sys/net80211/ieee80211_ioctl.h5
-rw-r--r--sys/net80211/ieee80211_output.c58
-rw-r--r--sys/net80211/ieee80211_proto.h1
-rw-r--r--sys/net80211/ieee80211_scan.h1
-rw-r--r--sys/net80211/ieee80211_sta.c2
-rw-r--r--sys/net80211/ieee80211_var.h10
10 files changed, 131 insertions, 2 deletions
diff --git a/sys/net80211/ieee80211.h b/sys/net80211/ieee80211.h
index 5d8d8fa..028afec 100644
--- a/sys/net80211/ieee80211.h
+++ b/sys/net80211/ieee80211.h
@@ -759,6 +759,18 @@ struct ieee80211_country_ie {
/*
* 802.11h Channel Switch Announcement (CSA).
*/
+struct ieee80211_quiet_ie {
+ uint8_t quiet_ie; /* IEEE80211_ELEMID_QUIET */
+ uint8_t len;
+ uint8_t tbttcount; /* quiet start */
+ uint8_t period; /* beacon intervals between quiets */
+ uint16_t duration; /* TUs of each quiet*/
+ uint16_t offset; /* TUs of from TBTT of quiet start */
+} __packed;
+
+/*
+ * 802.11h Channel Switch Announcement (CSA).
+ */
struct ieee80211_csa_ie {
uint8_t csa_ie; /* IEEE80211_ELEMID_CHANSWITCHANN */
uint8_t csa_len;
diff --git a/sys/net80211/ieee80211_dfs.c b/sys/net80211/ieee80211_dfs.c
index d44420c..ffb05e9 100644
--- a/sys/net80211/ieee80211_dfs.c
+++ b/sys/net80211/ieee80211_dfs.c
@@ -64,6 +64,12 @@ SYSCTL_INT(_net_wlan, OID_AUTO, cac_timeout, CTLFLAG_RW,
&ieee80211_cac_timeout, 0, "CAC timeout (secs)");
#define CAC_TIMEOUT msecs_to_ticks(ieee80211_cac_timeout*1000)
+static int
+null_set_quiet(struct ieee80211_node *ni, u_int8_t *quiet_elm)
+{
+ return ENOSYS;
+}
+
void
ieee80211_dfs_attach(struct ieee80211com *ic)
{
@@ -71,6 +77,8 @@ ieee80211_dfs_attach(struct ieee80211com *ic)
callout_init_mtx(&dfs->nol_timer, IEEE80211_LOCK_OBJ(ic), 0);
callout_init_mtx(&dfs->cac_timer, IEEE80211_LOCK_OBJ(ic), 0);
+
+ ic->ic_set_quiet = null_set_quiet;
}
void
diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c
index a18da4a..6fdc499 100644
--- a/sys/net80211/ieee80211_input.c
+++ b/sys/net80211/ieee80211_input.c
@@ -522,6 +522,9 @@ ieee80211_parse_beacon(struct ieee80211_node *ni, struct mbuf *m,
case IEEE80211_ELEMID_CSA:
scan->csa = frm;
break;
+ case IEEE80211_ELEMID_QUIET:
+ scan->quiet = frm;
+ break;
case IEEE80211_ELEMID_FHPARMS:
if (ic->ic_phytype == IEEE80211_T_FH) {
scan->fhdwell = LE_READ_2(&frm[2]);
diff --git a/sys/net80211/ieee80211_ioctl.c b/sys/net80211/ieee80211_ioctl.c
index f8e1785..2e388ae 100644
--- a/sys/net80211/ieee80211_ioctl.c
+++ b/sys/net80211/ieee80211_ioctl.c
@@ -972,6 +972,21 @@ ieee80211_ioctl_get80211(struct ieee80211vap *vap, u_long cmd,
case IEEE80211_IOC_PUREG:
ireq->i_val = (vap->iv_flags & IEEE80211_F_PUREG) != 0;
break;
+ case IEEE80211_IOC_QUIET:
+ ireq->i_val = vap->iv_quiet;
+ break;
+ case IEEE80211_IOC_QUIET_COUNT:
+ ireq->i_val = vap->iv_quiet_count;
+ break;
+ case IEEE80211_IOC_QUIET_PERIOD:
+ ireq->i_val = vap->iv_quiet_period;
+ break;
+ case IEEE80211_IOC_QUIET_DUR:
+ ireq->i_val = vap->iv_quiet_duration;
+ break;
+ case IEEE80211_IOC_QUIET_OFFSET:
+ ireq->i_val = vap->iv_quiet_offset;
+ break;
case IEEE80211_IOC_BGSCAN:
ireq->i_val = (vap->iv_flags & IEEE80211_F_BGSCAN) != 0;
break;
@@ -2939,6 +2954,24 @@ ieee80211_ioctl_set80211(struct ieee80211vap *vap, u_long cmd, struct ieee80211r
if (isvap11g(vap))
error = ENETRESET;
break;
+ case IEEE80211_IOC_QUIET:
+ vap->iv_quiet= ireq->i_val;
+ break;
+ case IEEE80211_IOC_QUIET_COUNT:
+ vap->iv_quiet_count=ireq->i_val;
+ break;
+ case IEEE80211_IOC_QUIET_PERIOD:
+ vap->iv_quiet_period=ireq->i_val;
+ break;
+ case IEEE80211_IOC_QUIET_OFFSET:
+ vap->iv_quiet_offset=ireq->i_val;
+ break;
+ case IEEE80211_IOC_QUIET_DUR:
+ if(ireq->i_val < vap->iv_bss->ni_intval)
+ vap->iv_quiet_duration = ireq->i_val;
+ else
+ error = EINVAL;
+ break;
case IEEE80211_IOC_BGSCAN:
if (ireq->i_val) {
if ((vap->iv_caps & IEEE80211_C_BGSCAN) == 0)
diff --git a/sys/net80211/ieee80211_ioctl.h b/sys/net80211/ieee80211_ioctl.h
index cad5576..0f11bc6 100644
--- a/sys/net80211/ieee80211_ioctl.h
+++ b/sys/net80211/ieee80211_ioctl.h
@@ -715,6 +715,11 @@ struct ieee80211req {
#define IEEE80211_IOC_TDMA_SLOTLEN 203 /* TDMA: slot length (usecs) */
#define IEEE80211_IOC_TDMA_BINTERVAL 204 /* TDMA: beacon intvl (slots) */
+#define IEEE80211_IOC_QUIET 205 /* Quiet Enable/Disable */
+#define IEEE80211_IOC_QUIET_PERIOD 206 /* Quiet Period */
+#define IEEE80211_IOC_QUIET_OFFSET 207 /* Quiet Offset */
+#define IEEE80211_IOC_QUIET_DUR 208 /* Quiet Duration */
+#define IEEE80211_IOC_QUIET_COUNT 209 /* Quiet Count */
/*
* Parameters for controlling a scan requested with
* IEEE80211_IOC_SCAN_REQ.
diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c
index bcd3c2b..0e45e8c 100644
--- a/sys/net80211/ieee80211_output.c
+++ b/sys/net80211/ieee80211_output.c
@@ -1661,6 +1661,33 @@ ieee80211_add_supportedchannels(uint8_t *frm, struct ieee80211com *ic)
}
/*
+ * Add an 11h Quiet time element to a frame.
+ */
+static uint8_t *
+ieee80211_add_quiet(uint8_t *frm, struct ieee80211vap *vap)
+{
+ struct ieee80211_quiet_ie *quiet = (struct ieee80211_quiet_ie *) frm;
+
+ quiet->quiet_ie = IEEE80211_ELEMID_QUIET;
+ quiet->len = 6;
+ if (vap->iv_quiet_count_value == 1)
+ vap->iv_quiet_count_value = vap->iv_quiet_count;
+ else if (vap->iv_quiet_count_value > 1)
+ vap->iv_quiet_count_value--;
+
+ if (vap->iv_quiet_count_value == 0) {
+ /* value 0 is reserved as per 802.11h standerd */
+ vap->iv_quiet_count_value = 1;
+ }
+
+ quiet->tbttcount = vap->iv_quiet_count_value;
+ quiet->period = vap->iv_quiet_period;
+ quiet->duration = htole16(vap->iv_quiet_duration);
+ quiet->offset = htole16(vap->iv_quiet_offset);
+ return frm + sizeof(*quiet);
+}
+
+/*
* Add an 11h Channel Switch Announcement element to a frame.
* Note that we use the per-vap CSA count to adjust the global
* counter so we can use this routine to form probe response
@@ -2253,6 +2280,7 @@ ieee80211_alloc_proberesp(struct ieee80211_node *bss, int legacy)
+ IEEE80211_COUNTRY_MAX_SIZE
+ 3
+ sizeof(struct ieee80211_csa_ie)
+ + sizeof(struct ieee80211_quiet_ie)
+ 3
+ 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
+ sizeof(struct ieee80211_ie_wpa)
@@ -2319,6 +2347,13 @@ ieee80211_alloc_proberesp(struct ieee80211_node *bss, int legacy)
if (ic->ic_flags & IEEE80211_F_CSAPENDING)
frm = ieee80211_add_csa(frm, vap);
}
+ if (vap->iv_flags & IEEE80211_F_DOTH) {
+ if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) &&
+ (vap->iv_flags_ext & IEEE80211_FEXT_DFS)) {
+ if (vap->iv_quiet)
+ frm = ieee80211_add_quiet(frm, vap);
+ }
+ }
if (IEEE80211_IS_CHAN_ANYG(bss->ni_chan))
frm = ieee80211_add_erp(frm, ic);
frm = ieee80211_add_xrates(frm, rs);
@@ -2617,9 +2652,20 @@ ieee80211_beacon_construct(struct mbuf *m, uint8_t *frm,
frm = ieee80211_add_powerconstraint(frm, vap);
bo->bo_csa = frm;
if (ic->ic_flags & IEEE80211_F_CSAPENDING)
- frm = ieee80211_add_csa(frm, vap);
+ frm = ieee80211_add_csa(frm, vap);
} else
bo->bo_csa = frm;
+
+ if (vap->iv_flags & IEEE80211_F_DOTH) {
+ bo->bo_quiet = frm;
+ if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) &&
+ (vap->iv_flags_ext & IEEE80211_FEXT_DFS)) {
+ if (vap->iv_quiet)
+ frm = ieee80211_add_quiet(frm,vap);
+ }
+ } else
+ bo->bo_quiet = frm;
+
if (IEEE80211_IS_CHAN_ANYG(ni->ni_chan)) {
bo->bo_erp = frm;
frm = ieee80211_add_erp(frm, ic);
@@ -2733,7 +2779,8 @@ ieee80211_beacon_alloc(struct ieee80211_node *ni,
+ 2 + 4 + vap->iv_tim_len /* DTIM/IBSSPARMS */
+ IEEE80211_COUNTRY_MAX_SIZE /* country */
+ 2 + 1 /* power control */
- + sizeof(struct ieee80211_csa_ie) /* CSA */
+ + sizeof(struct ieee80211_csa_ie) /* CSA */
+ + sizeof(struct ieee80211_quiet_ie) /* Quiet */
+ 2 + 1 /* ERP */
+ 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
+ (vap->iv_caps & IEEE80211_C_WPA ? /* WPA 1+2 */
@@ -2953,6 +3000,7 @@ ieee80211_beacon_update(struct ieee80211_node *ni,
bo->bo_appie += adjust;
bo->bo_wme += adjust;
bo->bo_csa += adjust;
+ bo->bo_quiet += adjust;
bo->bo_tim_len = timlen;
/* update information element */
@@ -3006,6 +3054,7 @@ ieee80211_beacon_update(struct ieee80211_node *ni,
#endif
bo->bo_appie += sizeof(*csa);
bo->bo_csa_trailer_len += sizeof(*csa);
+ bo->bo_quiet += sizeof(*csa);
bo->bo_tim_trailer_len += sizeof(*csa);
m->m_len += sizeof(*csa);
m->m_pkthdr.len += sizeof(*csa);
@@ -3016,6 +3065,11 @@ ieee80211_beacon_update(struct ieee80211_node *ni,
vap->iv_csa_count++;
/* NB: don't clear IEEE80211_BEACON_CSA */
}
+ if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) &&
+ (vap->iv_flags_ext & IEEE80211_FEXT_DFS) ){
+ if (vap->iv_quiet)
+ ieee80211_add_quiet(bo->bo_quiet, vap);
+ }
if (isset(bo->bo_flags, IEEE80211_BEACON_ERP)) {
/*
* ERP element needs updating.
diff --git a/sys/net80211/ieee80211_proto.h b/sys/net80211/ieee80211_proto.h
index 7e88216..54af007 100644
--- a/sys/net80211/ieee80211_proto.h
+++ b/sys/net80211/ieee80211_proto.h
@@ -344,6 +344,7 @@ struct ieee80211_beacon_offsets {
uint16_t bo_appie_len; /* AppIE length in bytes */
uint16_t bo_csa_trailer_len;
uint8_t *bo_csa; /* start of CSA element */
+ uint8_t *bo_quiet; /* start of Quiet element */
uint8_t *bo_meshconf; /* start of MESHCONF element */
uint8_t *bo_spare[3];
};
diff --git a/sys/net80211/ieee80211_scan.h b/sys/net80211/ieee80211_scan.h
index 4c5e869..3f13e17 100644
--- a/sys/net80211/ieee80211_scan.h
+++ b/sys/net80211/ieee80211_scan.h
@@ -213,6 +213,7 @@ struct ieee80211_scanparams {
uint8_t *ath;
uint8_t *tdma;
uint8_t *csa;
+ uint8_t *quiet;
uint8_t *meshid;
uint8_t *meshconf;
uint8_t *spare[3];
diff --git a/sys/net80211/ieee80211_sta.c b/sys/net80211/ieee80211_sta.c
index 97a9dbc..db09913 100644
--- a/sys/net80211/ieee80211_sta.c
+++ b/sys/net80211/ieee80211_sta.c
@@ -1347,6 +1347,8 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
scan.htcap, scan.htinfo);
/* XXX state changes? */
}
+ if (scan.quiet)
+ ic->ic_set_quiet(ni, scan.quiet);
if (scan.tim != NULL) {
struct ieee80211_tim_ie *tim =
(struct ieee80211_tim_ie *) scan.tim;
diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h
index a3dcd9f..60fbacb 100644
--- a/sys/net80211/ieee80211_var.h
+++ b/sys/net80211/ieee80211_var.h
@@ -242,6 +242,10 @@ struct ieee80211com {
int (*ic_setregdomain)(struct ieee80211com *,
struct ieee80211_regdomain *,
int, struct ieee80211_channel []);
+
+ int (*ic_set_quiet)(struct ieee80211_node *,
+ u_int8_t *quiet_elm);
+
/* send/recv 802.11 management frame */
int (*ic_send_mgmt)(struct ieee80211_node *,
int, int);
@@ -403,6 +407,12 @@ struct ieee80211vap {
uint8_t iv_dtim_period; /* DTIM period */
uint8_t iv_dtim_count; /* DTIM count from last bcn */
/* set/unset aid pwrsav state */
+ uint8_t iv_quiet; /* Quiet Element */
+ uint8_t iv_quiet_count; /* constant count for Quiet Element */
+ uint8_t iv_quiet_count_value; /* variable count for Quiet Element */
+ uint8_t iv_quiet_period; /* period for Quiet Element */
+ uint16_t iv_quiet_duration; /* duration for Quiet Element */
+ uint16_t iv_quiet_offset; /* offset for Quiet Element */
int iv_csa_count; /* count for doing CSA */
struct ieee80211_node *iv_bss; /* information for this node */
OpenPOWER on IntegriCloud