--- a/net80211/ieee80211.c +++ b/net80211/ieee80211.c @@ -333,7 +333,9 @@ ieee80211_ifattach(struct ieee80211com * IEEE80211_MS_TO_TU(IEEE80211_BMISSTHRESH_DEFAULT_MS), ic->ic_lintval), ic->ic_lintval); } - + ic->ic_protmode_timeout = IEEE80211_PROTMODE_TIMEOUT; + ic->ic_protmode_rssi = IEEE80211_PROTMODE_RSSITHR; + IEEE80211_LOCK_INIT(ic, "ieee80211com"); IEEE80211_VAPS_LOCK_INIT(ic, "ieee80211com_vaps"); TAILQ_INIT(&ic->ic_vaps); --- a/net80211/ieee80211_input.c +++ b/net80211/ieee80211_input.c @@ -3411,14 +3411,18 @@ ieee80211_recv_mgmt(struct ieee80211vap IEEE80211_IS_CHAN_ANYG(ic->ic_curchan)) { /* Assume no ERP IE == 11b AP */ - if ((!has_erp || (has_erp && (scan.erp & IEEE80211_ERP_NON_ERP_PRESENT))) && - !(ic->ic_flags & IEEE80211_F_USEPROT)) { + if ((!has_erp || (has_erp && + (scan.erp & IEEE80211_ERP_NON_ERP_PRESENT))) && + (rssi > ic->ic_protmode_rssi)) { struct ieee80211vap *tmpvap; - ic->ic_flags |= IEEE80211_F_USEPROT; - TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) { - tmpvap->iv_flags_ext |= IEEE80211_FEXT_ERPUPDATE; + if (!(ic->ic_flags & IEEE80211_F_USEPROT)) { + ic->ic_flags |= IEEE80211_F_USEPROT; + TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) { + tmpvap->iv_flags_ext |= IEEE80211_FEXT_ERPUPDATE; + } } + ic->ic_protmode_lasttrig = jiffies; } } --- a/net80211/ieee80211_ioctl.h +++ b/net80211/ieee80211_ioctl.h @@ -643,6 +643,8 @@ enum { IEEE80211_PARAM_BEACON_MISS_THRESH_MS = 74, /* Beacon miss threshold (in ms) */ IEEE80211_PARAM_MAXRATE = 75, /* Maximum rate (by table index) */ IEEE80211_PARAM_MINRATE = 76, /* Minimum rate (by table index) */ + IEEE80211_PARAM_PROTMODE_RSSI = 77, /* RSSI Threshold for enabling protection mode */ + IEEE80211_PARAM_PROTMODE_TIMEOUT = 78, /* Timeout for expiring protection mode */ }; #define SIOCG80211STATS (SIOCDEVPRIVATE+2) --- a/net80211/ieee80211_var.h +++ b/net80211/ieee80211_var.h @@ -128,6 +128,9 @@ #define IEEE80211_APPIE_MAX 1024 +#define IEEE80211_PROTMODE_RSSITHR 15 /* default rssi threshold for protection mode trigger */ +#define IEEE80211_PROTMODE_TIMEOUT 30 /* timeout for keeping protection mode alive */ + #define IEEE80211_PWRCONSTRAINT_VAL(ic) \ (((ic)->ic_bsschan->ic_maxregpower > (ic)->ic_curchanmaxpwr) ? \ (ic)->ic_bsschan->ic_maxregpower - (ic)->ic_curchanmaxpwr : 0) @@ -324,6 +327,9 @@ struct ieee80211com { u_int16_t ic_newtxpowlimit; /* tx power limit to change to (in 0.5 dBm) */ u_int16_t ic_uapsdmaxtriggers; /* max triggers that could arrive */ u_int8_t ic_coverageclass; /* coverage class */ + u_int8_t ic_protmode_rssi; /* rssi threshold for protection mode */ + u_int64_t ic_protmode_lasttrig; /* last trigger for protection mode */ + u_int16_t ic_protmode_timeout; /* protection mode timeout */ /* Channel state: * --- a/net80211/ieee80211_wireless.c +++ b/net80211/ieee80211_wireless.c @@ -2312,6 +2312,12 @@ ieee80211_ioctl_setparam(struct net_devi IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan)) retv = ENETRESET; break; + case IEEE80211_PARAM_PROTMODE_TIMEOUT: + ic->ic_protmode_timeout = value; + break; + case IEEE80211_PARAM_PROTMODE_RSSI: + ic->ic_protmode_rssi = value; + break; case IEEE80211_PARAM_MCASTCIPHER: if ((vap->iv_caps & cipher2cap(value)) == 0 && !ieee80211_crypto_available(vap, value)) @@ -2955,6 +2961,12 @@ ieee80211_ioctl_getparam(struct net_devi case IEEE80211_PARAM_PROTMODE: param[0] = ic->ic_protmode; break; + case IEEE80211_PARAM_PROTMODE_TIMEOUT: + param[0] = ic->ic_protmode_timeout; + break; + case IEEE80211_PARAM_PROTMODE_RSSI: + param[0] = ic->ic_protmode_rssi; + break; case IEEE80211_PARAM_MCASTCIPHER: param[0] = rsn->rsn_mcastcipher; break; @@ -5346,6 +5358,14 @@ static const struct iw_priv_args ieee802 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "protmode" }, { IEEE80211_PARAM_PROTMODE, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_protmode" }, + { IEEE80211_PARAM_PROTMODE_RSSI, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "protrssi" }, + { IEEE80211_PARAM_PROTMODE_RSSI, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_protrssi" }, + { IEEE80211_PARAM_PROTMODE_TIMEOUT, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "prottime" }, + { IEEE80211_PARAM_PROTMODE_TIMEOUT, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_prottime" }, { IEEE80211_PARAM_MCASTCIPHER, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "mcastcipher" }, { IEEE80211_PARAM_MCASTCIPHER, --- a/net80211/ieee80211_node.c +++ b/net80211/ieee80211_node.c @@ -1877,6 +1877,17 @@ ieee80211_node_timeout(unsigned long arg ieee80211_scan_timeout(ic); ieee80211_timeout_stations(&ic->ic_sta); + if ((ic->ic_flags & IEEE80211_F_USEPROT) && + (ic->ic_protmode_lasttrig + ic->ic_protmode_timeout * HZ < + jiffies)) { + struct ieee80211vap *tmpvap; + + /* expire protection mode */ + ic->ic_flags &= ~IEEE80211_F_USEPROT; + TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) { + tmpvap->iv_flags_ext |= IEEE80211_FEXT_ERPUPDATE; + } + } ic->ic_inact.expires = jiffies + IEEE80211_INACT_WAIT * HZ; add_timer(&ic->ic_inact);