| 1 | --- a/net80211/ieee80211_var.h |
| 2 | +++ b/net80211/ieee80211_var.h |
| 3 | @@ -198,6 +198,7 @@ struct ieee80211vap { |
| 4 | u_int32_t iv_debug; /* debug msg flags */ |
| 5 | struct ieee80211_stats iv_stats; /* statistics */ |
| 6 | |
| 7 | + int iv_max_nodes; |
| 8 | int iv_monitor_nods_only; /* in monitor mode only nods traffic */ |
| 9 | int iv_monitor_txf_len; /* in monitor mode, truncate tx packets */ |
| 10 | int iv_monitor_phy_errors; /* in monitor mode, accept phy errors */ |
| 11 | --- a/net80211/ieee80211_ioctl.h |
| 12 | +++ b/net80211/ieee80211_ioctl.h |
| 13 | @@ -650,6 +650,7 @@ enum { |
| 14 | IEEE80211_PARAM_RSSI_DIS_THR = 80, /* rssi threshold for disconnection */ |
| 15 | IEEE80211_PARAM_RSSI_DIS_COUNT = 81, /* counter for rssi threshold */ |
| 16 | IEEE80211_PARAM_WDS_SEP = 82, /* move wds stations into separate interfaces */ |
| 17 | + IEEE80211_PARAM_MAXASSOC = 83, /* maximum associated stations */ |
| 18 | }; |
| 19 | |
| 20 | #define SIOCG80211STATS (SIOCDEVPRIVATE+2) |
| 21 | --- a/net80211/ieee80211_wireless.c |
| 22 | +++ b/net80211/ieee80211_wireless.c |
| 23 | @@ -2875,6 +2875,12 @@ ieee80211_ioctl_setparam(struct net_devi |
| 24 | else |
| 25 | vap->iv_flags_ext &= ~IEEE80211_FEXT_WDSSEP; |
| 26 | break; |
| 27 | + case IEEE80211_PARAM_MAXASSOC: |
| 28 | + if (vap->iv_opmode != IEEE80211_M_HOSTAP) |
| 29 | + retv = -EINVAL; |
| 30 | + else |
| 31 | + vap->iv_max_nodes = value; |
| 32 | + break; |
| 33 | #ifdef ATH_REVERSE_ENGINEERING |
| 34 | case IEEE80211_PARAM_DUMPREGS: |
| 35 | ieee80211_dump_registers(dev, info, w, extra); |
| 36 | @@ -3234,6 +3240,9 @@ ieee80211_ioctl_getparam(struct net_devi |
| 37 | case IEEE80211_PARAM_WDS_SEP: |
| 38 | param[0] = !!(vap->iv_flags_ext & IEEE80211_FEXT_WDSSEP); |
| 39 | break; |
| 40 | + case IEEE80211_PARAM_MAXASSOC: |
| 41 | + param[0] = vap->iv_max_nodes; |
| 42 | + break; |
| 43 | default: |
| 44 | return -EOPNOTSUPP; |
| 45 | } |
| 46 | @@ -5789,6 +5798,10 @@ static const struct iw_priv_args ieee802 |
| 47 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wdssep"}, |
| 48 | { IEEE80211_PARAM_WDS_SEP, |
| 49 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_wdssep"}, |
| 50 | + { IEEE80211_PARAM_MAXASSOC, |
| 51 | + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "maxassoc"}, |
| 52 | + { IEEE80211_PARAM_MAXASSOC, |
| 53 | + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_maxassoc"}, |
| 54 | |
| 55 | #ifdef ATH_REVERSE_ENGINEERING |
| 56 | /* |
| 57 | --- a/net80211/ieee80211_input.c |
| 58 | +++ b/net80211/ieee80211_input.c |
| 59 | @@ -4020,7 +4020,26 @@ ieee80211_recv_mgmt(struct ieee80211vap |
| 60 | vap->iv_stats.is_rx_assoc_norate++; |
| 61 | return; |
| 62 | } |
| 63 | + if (vap->iv_max_nodes > 0) { |
| 64 | + unsigned int active_nodes = 0; |
| 65 | + struct ieee80211_node *tni; |
| 66 | + |
| 67 | + IEEE80211_NODE_TABLE_LOCK_IRQ(&ic->ic_sta); |
| 68 | + TAILQ_FOREACH(tni, &ic->ic_sta.nt_node, ni_list) { |
| 69 | + if (tni->ni_vap != vap) |
| 70 | + continue; |
| 71 | + if (tni->ni_associd == 0) |
| 72 | + continue; |
| 73 | + active_nodes++; |
| 74 | + } |
| 75 | + IEEE80211_NODE_TABLE_UNLOCK_IRQ(&ic->ic_sta); |
| 76 | |
| 77 | + if (active_nodes >= vap->iv_max_nodes) { |
| 78 | + /* too many nodes connected */ |
| 79 | + ieee80211_node_leave(ni); |
| 80 | + return; |
| 81 | + } |
| 82 | + } |
| 83 | if (ni->ni_associd != 0 && |
| 84 | IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan)) { |
| 85 | if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) |
| 86 | |