diff options
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/Kconfig | 1 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 70 | ||||
-rw-r--r-- | net/mac80211/debugfs_netdev.c | 2 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 16 | ||||
-rw-r--r-- | net/mac80211/iface.c | 30 | ||||
-rw-r--r-- | net/mac80211/main.c | 5 | ||||
-rw-r--r-- | net/mac80211/mesh.c | 36 | ||||
-rw-r--r-- | net/mac80211/mesh.h | 23 | ||||
-rw-r--r-- | net/mac80211/mesh_hwmp.c | 9 | ||||
-rw-r--r-- | net/mac80211/mesh_pathtbl.c | 7 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 104 | ||||
-rw-r--r-- | net/mac80211/rx.c | 1 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 2 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 3 | ||||
-rw-r--r-- | net/mac80211/status.c | 18 | ||||
-rw-r--r-- | net/mac80211/tx.c | 28 | ||||
-rw-r--r-- | net/mac80211/work.c | 5 |
17 files changed, 200 insertions, 160 deletions
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 4d6f8653..798d9b9 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -6,6 +6,7 @@ config MAC80211 select CRYPTO_ARC4 select CRYPTO_AES select CRC32 + select AVERAGE ---help--- This option enables the hardware independent IEEE 802.11 networking stack. diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index db134b5..c30b8b7 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -19,9 +19,10 @@ #include "rate.h" #include "mesh.h" -static int ieee80211_add_iface(struct wiphy *wiphy, char *name, - enum nl80211_iftype type, u32 *flags, - struct vif_params *params) +static struct net_device *ieee80211_add_iface(struct wiphy *wiphy, char *name, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) { struct ieee80211_local *local = wiphy_priv(wiphy); struct net_device *dev; @@ -29,12 +30,15 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name, int err; err = ieee80211_if_add(local, name, &dev, type, params); - if (err || type != NL80211_IFTYPE_MONITOR || !flags) - return err; + if (err) + return ERR_PTR(err); - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - sdata->u.mntr_flags = *flags; - return 0; + if (type == NL80211_IFTYPE_MONITOR && flags) { + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + sdata->u.mntr_flags = *flags; + } + + return dev; } static int ieee80211_del_iface(struct wiphy *wiphy, struct net_device *dev) @@ -56,11 +60,6 @@ static int ieee80211_change_iface(struct wiphy *wiphy, if (ret) return ret; - if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len) - ieee80211_sdata_set_mesh_id(sdata, - params->mesh_id_len, - params->mesh_id); - if (type == NL80211_IFTYPE_AP_VLAN && params && params->use_4addr == 0) rcu_assign_pointer(sdata->u.vlan.sta, NULL); @@ -343,8 +342,9 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { - sinfo->filled |= STATION_INFO_SIGNAL; + sinfo->filled |= STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG; sinfo->signal = (s8)sta->last_signal; + sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal); } sinfo->txrate.flags = 0; @@ -999,9 +999,9 @@ static inline bool _chg_mesh_attr(enum nl80211_meshconf_params parm, u32 mask) return (mask >> (parm-1)) & 0x1; } -static int ieee80211_set_mesh_params(struct wiphy *wiphy, - struct net_device *dev, - const struct mesh_config *nconf, u32 mask) +static int ieee80211_update_mesh_params(struct wiphy *wiphy, + struct net_device *dev, u32 mask, + const struct mesh_config *nconf) { struct mesh_config *conf; struct ieee80211_sub_if_data *sdata; @@ -1024,6 +1024,8 @@ static int ieee80211_set_mesh_params(struct wiphy *wiphy, conf->dot11MeshMaxRetries = nconf->dot11MeshMaxRetries; if (_chg_mesh_attr(NL80211_MESHCONF_TTL, mask)) conf->dot11MeshTTL = nconf->dot11MeshTTL; + if (_chg_mesh_attr(NL80211_MESHCONF_ELEMENT_TTL, mask)) + conf->dot11MeshTTL = nconf->element_ttl; if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask)) conf->auto_open_plinks = nconf->auto_open_plinks; if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, mask)) @@ -1050,6 +1052,30 @@ static int ieee80211_set_mesh_params(struct wiphy *wiphy, return 0; } +static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev, + const struct mesh_config *conf, + const struct mesh_setup *setup) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; + + memcpy(&sdata->u.mesh.mshcfg, conf, sizeof(struct mesh_config)); + ifmsh->mesh_id_len = setup->mesh_id_len; + memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len); + + ieee80211_start_mesh(sdata); + + return 0; +} + +static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + ieee80211_stop_mesh(sdata); + + return 0; +} #endif static int ieee80211_change_bss(struct wiphy *wiphy, @@ -1108,6 +1134,12 @@ static int ieee80211_change_bss(struct wiphy *wiphy, sdata->flags &= ~IEEE80211_SDATA_DONT_BRIDGE_PACKETS; } + if (params->ht_opmode >= 0) { + sdata->vif.bss_conf.ht_operation_mode = + (u16) params->ht_opmode; + changed |= BSS_CHANGED_HT; + } + ieee80211_bss_info_change_notify(sdata, changed); return 0; @@ -1754,8 +1786,10 @@ struct cfg80211_ops mac80211_config_ops = { .change_mpath = ieee80211_change_mpath, .get_mpath = ieee80211_get_mpath, .dump_mpath = ieee80211_dump_mpath, - .set_mesh_params = ieee80211_set_mesh_params, + .update_mesh_params = ieee80211_update_mesh_params, .get_mesh_params = ieee80211_get_mesh_params, + .join_mesh = ieee80211_join_mesh, + .leave_mesh = ieee80211_leave_mesh, #endif .change_bss = ieee80211_change_bss, .set_txq_params = ieee80211_set_txq_params, diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index cbdf36d..2dabdf7 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -251,6 +251,7 @@ IEEE80211_IF_FILE(dot11MeshConfirmTimeout, IEEE80211_IF_FILE(dot11MeshHoldingTimeout, u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC); IEEE80211_IF_FILE(dot11MeshTTL, u.mesh.mshcfg.dot11MeshTTL, DEC); +IEEE80211_IF_FILE(element_ttl, u.mesh.mshcfg.element_ttl, DEC); IEEE80211_IF_FILE(auto_open_plinks, u.mesh.mshcfg.auto_open_plinks, DEC); IEEE80211_IF_FILE(dot11MeshMaxPeerLinks, u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC); @@ -355,6 +356,7 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata) MESHPARAMS_ADD(dot11MeshConfirmTimeout); MESHPARAMS_ADD(dot11MeshHoldingTimeout); MESHPARAMS_ADD(dot11MeshTTL); + MESHPARAMS_ADD(element_ttl); MESHPARAMS_ADD(auto_open_plinks); MESHPARAMS_ADD(dot11MeshMaxPeerLinks); MESHPARAMS_ADD(dot11MeshHWMPactivePathTimeout); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 66b0b52..72499fe 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -357,6 +357,7 @@ struct ieee80211_if_managed { unsigned long beacon_timeout; unsigned long probe_timeout; int probe_send_count; + bool nullfunc_failed; struct mutex mtx; struct cfg80211_bss *associated; @@ -608,19 +609,6 @@ struct ieee80211_sub_if_data *vif_to_sdata(struct ieee80211_vif *p) return container_of(p, struct ieee80211_sub_if_data, vif); } -static inline void -ieee80211_sdata_set_mesh_id(struct ieee80211_sub_if_data *sdata, - u8 mesh_id_len, u8 *mesh_id) -{ -#ifdef CONFIG_MAC80211_MESH - struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; - ifmsh->mesh_id_len = mesh_id_len; - memcpy(ifmsh->mesh_id, mesh_id, mesh_id_len); -#else - WARN_ON(1); -#endif -} - enum sdata_queue_type { IEEE80211_SDATA_QUEUE_TYPE_FRAME = 0, IEEE80211_SDATA_QUEUE_AGG_START = 1, @@ -1271,7 +1259,7 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local, void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, struct ieee80211_hdr *hdr); void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, - struct ieee80211_hdr *hdr); + struct ieee80211_hdr *hdr, bool ack); void ieee80211_beacon_connection_loss_work(struct work_struct *work); void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 7aa8559..f0f11bb 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -197,11 +197,6 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) sdata->bss = &sdata->u.ap; break; case NL80211_IFTYPE_MESH_POINT: - if (!ieee80211_vif_is_mesh(&sdata->vif)) - break; - /* mesh ifaces must set allmulti to forward mcast traffic */ - atomic_inc(&local->iff_allmultis); - break; case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_ADHOC: @@ -273,12 +268,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) goto err_stop; } - if (ieee80211_vif_is_mesh(&sdata->vif)) { - local->fif_other_bss++; - ieee80211_configure_filter(local); - - ieee80211_start_mesh(sdata); - } else if (sdata->vif.type == NL80211_IFTYPE_AP) { + if (sdata->vif.type == NL80211_IFTYPE_AP) { local->fif_pspoll++; local->fif_probe_req++; @@ -503,18 +493,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, ieee80211_adjust_monitor_flags(sdata, -1); ieee80211_configure_filter(local); break; - case NL80211_IFTYPE_MESH_POINT: - if (ieee80211_vif_is_mesh(&sdata->vif)) { - /* other_bss and allmulti are always set on mesh - * ifaces */ - local->fif_other_bss--; - atomic_dec(&local->iff_allmultis); - - ieee80211_configure_filter(local); - - ieee80211_stop_mesh(sdata); - } - /* fall through */ default: flush_work(&sdata->work); /* @@ -1204,12 +1182,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, if (ret) goto fail; - if (ieee80211_vif_is_mesh(&sdata->vif) && - params && params->mesh_id_len) - ieee80211_sdata_set_mesh_id(sdata, - params->mesh_id_len, - params->mesh_id); - mutex_lock(&local->iflist_mtx); list_add_tail_rcu(&sdata->list, &local->interfaces); mutex_unlock(&local->iflist_mtx); diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 107a0cb..973fee9 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -245,9 +245,12 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, sdata->vif.bss_conf.enable_beacon = !!sdata->u.ibss.presp; break; +#ifdef CONFIG_MAC80211_MESH case NL80211_IFTYPE_MESH_POINT: - sdata->vif.bss_conf.enable_beacon = true; + sdata->vif.bss_conf.enable_beacon = + !!sdata->u.mesh.mesh_id_len; break; +#endif default: /* not reached */ WARN_ON(1); diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index c8a4f19..63e1188 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -513,6 +513,11 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct ieee80211_local *local = sdata->local; + local->fif_other_bss++; + /* mesh ifaces must set allmulti to forward mcast traffic */ + atomic_inc(&local->iff_allmultis); + ieee80211_configure_filter(local); + set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); ieee80211_mesh_root_setup(ifmsh); ieee80211_queue_work(&local->hw, &sdata->work); @@ -524,6 +529,13 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) { + struct ieee80211_local *local = sdata->local; + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; + + ifmsh->mesh_id_len = 0; + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); + sta_info_flush(local, NULL); + del_timer_sync(&sdata->u.mesh.housekeeping_timer); del_timer_sync(&sdata->u.mesh.mesh_path_root_timer); /* @@ -534,6 +546,10 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) * it no longer is. */ cancel_work_sync(&sdata->work); + + local->fif_other_bss--; + atomic_dec(&local->iff_allmultis); + ieee80211_configure_filter(local); } static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, @@ -663,26 +679,6 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) ieee80211_mesh_housekeeping_timer, (unsigned long) sdata); - ifmsh->mshcfg.dot11MeshRetryTimeout = MESH_RET_T; - ifmsh->mshcfg.dot11MeshConfirmTimeout = MESH_CONF_T; - ifmsh->mshcfg.dot11MeshHoldingTimeout = MESH_HOLD_T; - ifmsh->mshcfg.dot11MeshMaxRetries = MESH_MAX_RETR; - ifmsh->mshcfg.dot11MeshTTL = MESH_TTL; - ifmsh->mshcfg.auto_open_plinks = true; - ifmsh->mshcfg.dot11MeshMaxPeerLinks = - MESH_MAX_ESTAB_PLINKS; - ifmsh->mshcfg.dot11MeshHWMPactivePathTimeout = - MESH_PATH_TIMEOUT; - ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval = - MESH_PREQ_MIN_INT; - ifmsh->mshcfg.dot11MeshHWMPnetDiameterTraversalTime = - MESH_DIAM_TRAVERSAL_TIME; - ifmsh->mshcfg.dot11MeshHWMPmaxPREQretries = - MESH_MAX_PREQ_RETRIES; - ifmsh->mshcfg.path_refresh_time = - MESH_PATH_REFRESH_TIME; - ifmsh->mshcfg.min_discovery_timeout = - MESH_MIN_DISCOVERY_TIMEOUT; ifmsh->accepting_plinks = true; ifmsh->preq_id = 0; ifmsh->sn = 0; diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 58e7411..039d7fa 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -175,33 +175,10 @@ struct mesh_rmc { */ #define MESH_CFG_CMP_LEN (IEEE80211_MESH_CONFIG_LEN - 2) -/* Default values, timeouts in ms */ -#define MESH_TTL 31 -#define MESH_MAX_RETR 3 -#define MESH_RET_T 100 -#define MESH_CONF_T 100 -#define MESH_HOLD_T 100 - -#define MESH_PATH_TIMEOUT 5000 -/* Minimum interval between two consecutive PREQs originated by the same - * interface - */ -#define MESH_PREQ_MIN_INT 10 -#define MESH_DIAM_TRAVERSAL_TIME 50 -/* A path will be refreshed if it is used PATH_REFRESH_TIME milliseconds before - * timing out. This way it will remain ACTIVE and no data frames will be - * unnecesarily held in the pending queue. - */ -#define MESH_PATH_REFRESH_TIME 1000 -#define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME) #define MESH_DEFAULT_BEACON_INTERVAL 1000 /* in 1024 us units */ -#define MESH_MAX_PREQ_RETRIES 4 #define MESH_PATH_EXPIRE (600 * HZ) -/* Default maximum number of established plinks per interface */ -#define MESH_MAX_ESTAB_PLINKS 32 - /* Default maximum number of plinks per interface */ #define MESH_MAX_PLINKS 256 diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 829e08a..5bf64d7 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -232,7 +232,7 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn, *pos++ = WLAN_EID_PERR; *pos++ = ie_len; /* ttl */ - *pos++ = MESH_TTL; + *pos++ = ttl; /* number of destinations */ *pos++ = 1; /* @@ -522,7 +522,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, if (reply) { lifetime = PREQ_IE_LIFETIME(preq_elem); - ttl = ifmsh->mshcfg.dot11MeshTTL; + ttl = ifmsh->mshcfg.element_ttl; if (ttl != 0) { mhwmp_dbg("replying to the PREQ\n"); mesh_path_sel_frame_tx(MPATH_PREP, 0, target_addr, @@ -877,7 +877,7 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata) sdata->u.mesh.last_sn_update = jiffies; } lifetime = default_lifetime(sdata); - ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; + ttl = sdata->u.mesh.mshcfg.element_ttl; if (ttl == 0) { sdata->u.mesh.mshstats.dropped_frames_ttl++; spin_unlock_bh(&mpath->state_lock); @@ -1013,5 +1013,6 @@ mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata) mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->vif.addr, cpu_to_le32(++ifmsh->sn), 0, NULL, 0, broadcast_addr, - 0, MESH_TTL, 0, 0, 0, sdata); + 0, sdata->u.mesh.mshcfg.element_ttl, + 0, 0, 0, sdata); } diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 349e466..8d65b47 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -467,8 +467,8 @@ void mesh_plink_broken(struct sta_info *sta) mpath->flags &= ~MESH_PATH_ACTIVE; ++mpath->sn; spin_unlock_bh(&mpath->state_lock); - mesh_path_error_tx(MESH_TTL, mpath->dst, - cpu_to_le32(mpath->sn), + mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl, + mpath->dst, cpu_to_le32(mpath->sn), cpu_to_le16(PERR_RCODE_DEST_UNREACH), bcast, sdata); } else @@ -614,7 +614,8 @@ void mesh_path_discard_frame(struct sk_buff *skb, mpath = mesh_path_lookup(da, sdata); if (mpath) sn = ++mpath->sn; - mesh_path_error_tx(MESH_TTL, skb->data, cpu_to_le32(sn), + mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl, skb->data, + cpu_to_le32(sn), cpu_to_le16(PERR_RCODE_NO_ROUTE), ra, sdata); } diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 7948079..45fbb9e 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -625,11 +625,12 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) /* * Go to full PSM if the user configures a very low * latency requirement. - * The 2 second value is there for compatibility until - * the PM_QOS_NETWORK_LATENCY is configured with real - * values. + * The 2000 second value is there for compatibility + * until the PM_QOS_NETWORK_LATENCY is configured + * with real values. */ - if (latency > 1900000000 && latency != 2000000000) + if (latency > (1900 * USEC_PER_MSEC) && + latency != (2000 * USEC_PER_SEC)) timeout = 0; else timeout = 100; @@ -1065,17 +1066,20 @@ static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata) } void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, - struct ieee80211_hdr *hdr) + struct ieee80211_hdr *hdr, bool ack) { - if (!ieee80211_is_data(hdr->frame_control) && - !ieee80211_is_nullfunc(hdr->frame_control)) + if (!ieee80211_is_data(hdr->frame_control)) return; - ieee80211_sta_reset_conn_monitor(sdata); + if (ack) + ieee80211_sta_reset_conn_monitor(sdata); if (ieee80211_is_nullfunc(hdr->frame_control) && sdata->u.mgd.probe_send_count > 0) { - sdata->u.mgd.probe_send_count = 0; + if (ack) + sdata->u.mgd.probe_send_count = 0; + else + sdata->u.mgd.nullfunc_failed = true; ieee80211_queue_work(&sdata->local->hw, &sdata->work); } } @@ -1102,9 +1106,10 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) * anymore. The timeout will be reset if the frame is ACKed by * the AP. */ - if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) + if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) { + ifmgd->nullfunc_failed = false; ieee80211_send_nullfunc(sdata->local, sdata, 0); - else { + } else { ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0); } @@ -1913,6 +1918,31 @@ static void ieee80211_sta_timer(unsigned long data) ieee80211_queue_work(&local->hw, &sdata->work); } +static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, + u8 *bssid) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + + ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | + IEEE80211_STA_BEACON_POLL); + + ieee80211_set_disassoc(sdata, true, true); + mutex_unlock(&ifmgd->mtx); + mutex_lock(&local->mtx); + ieee80211_recalc_idle(local); + mutex_unlock(&local->mtx); + /* + * must be outside lock due to cfg80211, + * but that's not a problem. + */ + ieee80211_send_deauth_disassoc(sdata, bssid, + IEEE80211_STYPE_DEAUTH, + WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, + NULL, true); + mutex_lock(&ifmgd->mtx); +} + void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; @@ -1937,11 +1967,37 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) /* ACK received for nullfunc probing frame */ if (!ifmgd->probe_send_count) ieee80211_reset_ap_probe(sdata); - - else if (time_is_after_jiffies(ifmgd->probe_timeout)) + else if (ifmgd->nullfunc_failed) { + if (ifmgd->probe_send_count < max_tries) { +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + wiphy_debug(local->hw.wiphy, + "%s: No ack for nullfunc frame to" + " AP %pM, try %d\n", + sdata->name, bssid, + ifmgd->probe_send_count); +#endif + ieee80211_mgd_probe_ap_send(sdata); + } else { +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + wiphy_debug(local->hw.wiphy, + "%s: No ack for nullfunc frame to" + " AP %pM, disconnecting.\n", + sdata->name, bssid); +#endif + ieee80211_sta_connection_lost(sdata, bssid); + } + } else if (time_is_after_jiffies(ifmgd->probe_timeout)) run_again(ifmgd, ifmgd->probe_timeout); - - else if (ifmgd->probe_send_count < max_tries) { + else if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) { +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + wiphy_debug(local->hw.wiphy, + "%s: Failed to send nullfunc to AP %pM" + " after %dms, disconnecting.\n", + sdata->name, + bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); +#endif + ieee80211_sta_connection_lost(sdata, bssid); + } else if (ifmgd->probe_send_count < max_tries) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG wiphy_debug(local->hw.wiphy, "%s: No probe response from AP %pM" @@ -1956,27 +2012,13 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) * We actually lost the connection ... or did we? * Let's make sure! */ - ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | - IEEE80211_STA_BEACON_POLL); wiphy_debug(local->hw.wiphy, "%s: No probe response from AP %pM" " after %dms, disconnecting.\n", sdata->name, bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); - ieee80211_set_disassoc(sdata, true, true); - mutex_unlock(&ifmgd->mtx); - mutex_lock(&local->mtx); - ieee80211_recalc_idle(local); - mutex_unlock(&local->mtx); - /* - * must be outside lock due to cfg80211, - * but that's not a problem. - */ - ieee80211_send_deauth_disassoc(sdata, bssid, - IEEE80211_STYPE_DEAUTH, - WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, - NULL, true); - mutex_lock(&ifmgd->mtx); + + ieee80211_sta_connection_lost(sdata, bssid); } } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 6289525..2fe8f5f 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1163,6 +1163,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) sta->rx_fragments++; sta->rx_bytes += rx->skb->len; sta->last_signal = status->signal; + ewma_add(&sta->avg_signal, -status->signal); /* * Change STA power saving mode only at the end of a frame diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index eff5857..c426504 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -244,6 +244,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, sta->local = local; sta->sdata = sdata; + ewma_init(&sta->avg_signal, 1024, 8); + if (sta_prepare_rate_control(local, sta, gfp)) { kfree(sta); return NULL; diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 05f1130..fdca52c 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -13,6 +13,7 @@ #include <linux/types.h> #include <linux/if_ether.h> #include <linux/workqueue.h> +#include <linux/average.h> #include "key.h" /** @@ -223,6 +224,7 @@ enum plink_state { * @rx_fragments: number of received MPDUs * @rx_dropped: number of dropped MPDUs from this STA * @last_signal: signal of last received frame from this STA + * @avg_signal: moving average of signal of received frames from this STA * @last_seq_ctrl: last received seq/frag number from this STA (per RX queue) * @tx_filtered_count: number of frames the hardware filtered for this STA * @tx_retry_failed: number of frames that failed retry @@ -291,6 +293,7 @@ struct sta_info { unsigned long rx_fragments; unsigned long rx_dropped; int last_signal; + struct ewma avg_signal; __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES]; /* Updated from TX status path only, no locking requirements */ diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 4958710..38a7972 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -155,10 +155,6 @@ static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb) ieee80211_queue_work(&local->hw, &local->recalc_smps); } - - if ((sdata->vif.type == NL80211_IFTYPE_STATION) && - (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) - ieee80211_sta_tx_notify(sdata, (void *) skb->data); } /* @@ -186,6 +182,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) int retry_count = -1, i; int rates_idx = -1; bool send_to_cooked; + bool acked; for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { /* the HW cannot have attempted that rate */ @@ -211,8 +208,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) if (memcmp(hdr->addr2, sta->sdata->vif.addr, ETH_ALEN)) continue; - if (!(info->flags & IEEE80211_TX_STAT_ACK) && - test_sta_flags(sta, WLAN_STA_PS_STA)) { + acked = !!(info->flags & IEEE80211_TX_STAT_ACK); + if (!acked && test_sta_flags(sta, WLAN_STA_PS_STA)) { /* * The STA is in power save mode, so assume * that this TX packet failed because of that. @@ -244,7 +241,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) rcu_read_unlock(); return; } else { - if (!(info->flags & IEEE80211_TX_STAT_ACK)) + if (!acked) sta->tx_retry_failed++; sta->tx_retry_count += retry_count; } @@ -253,10 +250,13 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) if (ieee80211_vif_is_mesh(&sta->sdata->vif)) ieee80211s_update_metric(local, sta, skb); - if (!(info->flags & IEEE80211_TX_CTL_INJECTED) && - (info->flags & IEEE80211_TX_STAT_ACK)) + if (!(info->flags & IEEE80211_TX_CTL_INJECTED) && acked) ieee80211_frame_acked(sta, skb); + if ((sta->sdata->vif.type == NL80211_IFTYPE_STATION) && + (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) + ieee80211_sta_tx_notify(sta->sdata, (void *) skb->data, acked); + if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) { if (info->flags & IEEE80211_TX_STAT_ACK) { if (sta->lost_packets) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 2ba7426..0ee56bb 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -666,10 +666,11 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) if (unlikely(info->control.rates[0].idx < 0)) return TX_DROP; - if (txrc.reported_rate.idx < 0) + if (txrc.reported_rate.idx < 0) { txrc.reported_rate = info->control.rates[0]; - - if (tx->sta) + if (tx->sta && ieee80211_is_data(hdr->frame_control)) + tx->sta->last_tx_rate = txrc.reported_rate; + } else if (tx->sta) tx->sta->last_tx_rate = txrc.reported_rate; if (unlikely(!info->control.rates[0].count)) @@ -1745,15 +1746,13 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, int nh_pos, h_pos; struct sta_info *sta = NULL; u32 sta_flags = 0; + struct sk_buff *tmp_skb; if (unlikely(skb->len < ETH_HLEN)) { ret = NETDEV_TX_OK; goto fail; } - nh_pos = skb_network_header(skb) - skb->data; - h_pos = skb_transport_header(skb) - skb->data; - /* convert Ethernet header to proper 802.11 header (based on * operation mode) */ ethertype = (skb->data[12] << 8) | skb->data[13]; @@ -1926,6 +1925,20 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, goto fail; } + /* + * If the skb is shared we need to obtain our own copy. + */ + if (skb_shared(skb)) { + tmp_skb = skb; + skb = skb_copy(skb, GFP_ATOMIC); + kfree_skb(tmp_skb); + + if (!skb) { + ret = NETDEV_TX_OK; + goto fail; + } + } + hdr.frame_control = fc; hdr.duration_id = 0; hdr.seq_ctrl = 0; @@ -1944,6 +1957,9 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, encaps_len = 0; } + nh_pos = skb_network_header(skb) - skb->data; + h_pos = skb_transport_header(skb) - skb->data; + skb_pull(skb, skip_header_bytes); nh_pos -= skip_header_bytes; h_pos -= skip_header_bytes; diff --git a/net/mac80211/work.c b/net/mac80211/work.c index 2b5c3f2..de43753 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@ -458,8 +458,9 @@ ieee80211_direct_probe(struct ieee80211_work *wk) return WORK_ACT_TIMEOUT; } - printk(KERN_DEBUG "%s: direct probe to %pM (try %d)\n", - sdata->name, wk->filter_ta, wk->probe_auth.tries); + printk(KERN_DEBUG "%s: direct probe to %pM (try %d/%i)\n", + sdata->name, wk->filter_ta, wk->probe_auth.tries, + IEEE80211_AUTH_MAX_TRIES); /* * Direct probe is sent to broadcast address as some APs |