diff options
author | John W. Linville <linville@tuxdriver.com> | 2010-12-13 15:20:45 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-12-13 15:20:45 -0500 |
commit | 1d212aa96e1b63459486f729af9a3fa38768b801 (patch) | |
tree | e91e74db57a5bb7884b4681cdb788d405ec8f10f /net | |
parent | 8c4877a4128e7931077b024a891a4b284d8756a3 (diff) | |
parent | b7613370db5ba66ad81e41cd3a5417fde4d5e03c (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6 into for-davem
Diffstat (limited to 'net')
-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 | ||||
-rw-r--r-- | net/wireless/Makefile | 2 | ||||
-rw-r--r-- | net/wireless/core.c | 15 | ||||
-rw-r--r-- | net/wireless/core.h | 13 | ||||
-rw-r--r-- | net/wireless/mesh.c | 140 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 212 | ||||
-rw-r--r-- | net/wireless/util.c | 1 |
23 files changed, 537 insertions, 206 deletions
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 4d6f8653ec88..798d9b9462e2 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig | |||
@@ -6,6 +6,7 @@ config MAC80211 | |||
6 | select CRYPTO_ARC4 | 6 | select CRYPTO_ARC4 |
7 | select CRYPTO_AES | 7 | select CRYPTO_AES |
8 | select CRC32 | 8 | select CRC32 |
9 | select AVERAGE | ||
9 | ---help--- | 10 | ---help--- |
10 | This option enables the hardware independent IEEE 802.11 | 11 | This option enables the hardware independent IEEE 802.11 |
11 | networking stack. | 12 | networking stack. |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index db134b500caa..c30b8b72eedb 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -19,9 +19,10 @@ | |||
19 | #include "rate.h" | 19 | #include "rate.h" |
20 | #include "mesh.h" | 20 | #include "mesh.h" |
21 | 21 | ||
22 | static int ieee80211_add_iface(struct wiphy *wiphy, char *name, | 22 | static struct net_device *ieee80211_add_iface(struct wiphy *wiphy, char *name, |
23 | enum nl80211_iftype type, u32 *flags, | 23 | enum nl80211_iftype type, |
24 | struct vif_params *params) | 24 | u32 *flags, |
25 | struct vif_params *params) | ||
25 | { | 26 | { |
26 | struct ieee80211_local *local = wiphy_priv(wiphy); | 27 | struct ieee80211_local *local = wiphy_priv(wiphy); |
27 | struct net_device *dev; | 28 | struct net_device *dev; |
@@ -29,12 +30,15 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name, | |||
29 | int err; | 30 | int err; |
30 | 31 | ||
31 | err = ieee80211_if_add(local, name, &dev, type, params); | 32 | err = ieee80211_if_add(local, name, &dev, type, params); |
32 | if (err || type != NL80211_IFTYPE_MONITOR || !flags) | 33 | if (err) |
33 | return err; | 34 | return ERR_PTR(err); |
34 | 35 | ||
35 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 36 | if (type == NL80211_IFTYPE_MONITOR && flags) { |
36 | sdata->u.mntr_flags = *flags; | 37 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
37 | return 0; | 38 | sdata->u.mntr_flags = *flags; |
39 | } | ||
40 | |||
41 | return dev; | ||
38 | } | 42 | } |
39 | 43 | ||
40 | static int ieee80211_del_iface(struct wiphy *wiphy, struct net_device *dev) | 44 | static int ieee80211_del_iface(struct wiphy *wiphy, struct net_device *dev) |
@@ -56,11 +60,6 @@ static int ieee80211_change_iface(struct wiphy *wiphy, | |||
56 | if (ret) | 60 | if (ret) |
57 | return ret; | 61 | return ret; |
58 | 62 | ||
59 | if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len) | ||
60 | ieee80211_sdata_set_mesh_id(sdata, | ||
61 | params->mesh_id_len, | ||
62 | params->mesh_id); | ||
63 | |||
64 | if (type == NL80211_IFTYPE_AP_VLAN && | 63 | if (type == NL80211_IFTYPE_AP_VLAN && |
65 | params && params->use_4addr == 0) | 64 | params && params->use_4addr == 0) |
66 | rcu_assign_pointer(sdata->u.vlan.sta, NULL); | 65 | 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) | |||
343 | 342 | ||
344 | if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || | 343 | if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || |
345 | (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { | 344 | (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { |
346 | sinfo->filled |= STATION_INFO_SIGNAL; | 345 | sinfo->filled |= STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG; |
347 | sinfo->signal = (s8)sta->last_signal; | 346 | sinfo->signal = (s8)sta->last_signal; |
347 | sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal); | ||
348 | } | 348 | } |
349 | 349 | ||
350 | sinfo->txrate.flags = 0; | 350 | sinfo->txrate.flags = 0; |
@@ -999,9 +999,9 @@ static inline bool _chg_mesh_attr(enum nl80211_meshconf_params parm, u32 mask) | |||
999 | return (mask >> (parm-1)) & 0x1; | 999 | return (mask >> (parm-1)) & 0x1; |
1000 | } | 1000 | } |
1001 | 1001 | ||
1002 | static int ieee80211_set_mesh_params(struct wiphy *wiphy, | 1002 | static int ieee80211_update_mesh_params(struct wiphy *wiphy, |
1003 | struct net_device *dev, | 1003 | struct net_device *dev, u32 mask, |
1004 | const struct mesh_config *nconf, u32 mask) | 1004 | const struct mesh_config *nconf) |
1005 | { | 1005 | { |
1006 | struct mesh_config *conf; | 1006 | struct mesh_config *conf; |
1007 | struct ieee80211_sub_if_data *sdata; | 1007 | struct ieee80211_sub_if_data *sdata; |
@@ -1024,6 +1024,8 @@ static int ieee80211_set_mesh_params(struct wiphy *wiphy, | |||
1024 | conf->dot11MeshMaxRetries = nconf->dot11MeshMaxRetries; | 1024 | conf->dot11MeshMaxRetries = nconf->dot11MeshMaxRetries; |
1025 | if (_chg_mesh_attr(NL80211_MESHCONF_TTL, mask)) | 1025 | if (_chg_mesh_attr(NL80211_MESHCONF_TTL, mask)) |
1026 | conf->dot11MeshTTL = nconf->dot11MeshTTL; | 1026 | conf->dot11MeshTTL = nconf->dot11MeshTTL; |
1027 | if (_chg_mesh_attr(NL80211_MESHCONF_ELEMENT_TTL, mask)) | ||
1028 | conf->dot11MeshTTL = nconf->element_ttl; | ||
1027 | if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask)) | 1029 | if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask)) |
1028 | conf->auto_open_plinks = nconf->auto_open_plinks; | 1030 | conf->auto_open_plinks = nconf->auto_open_plinks; |
1029 | if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, mask)) | 1031 | if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, mask)) |
@@ -1050,6 +1052,30 @@ static int ieee80211_set_mesh_params(struct wiphy *wiphy, | |||
1050 | return 0; | 1052 | return 0; |
1051 | } | 1053 | } |
1052 | 1054 | ||
1055 | static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev, | ||
1056 | const struct mesh_config *conf, | ||
1057 | const struct mesh_setup *setup) | ||
1058 | { | ||
1059 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1060 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
1061 | |||
1062 | memcpy(&sdata->u.mesh.mshcfg, conf, sizeof(struct mesh_config)); | ||
1063 | ifmsh->mesh_id_len = setup->mesh_id_len; | ||
1064 | memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len); | ||
1065 | |||
1066 | ieee80211_start_mesh(sdata); | ||
1067 | |||
1068 | return 0; | ||
1069 | } | ||
1070 | |||
1071 | static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev) | ||
1072 | { | ||
1073 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1074 | |||
1075 | ieee80211_stop_mesh(sdata); | ||
1076 | |||
1077 | return 0; | ||
1078 | } | ||
1053 | #endif | 1079 | #endif |
1054 | 1080 | ||
1055 | static int ieee80211_change_bss(struct wiphy *wiphy, | 1081 | static int ieee80211_change_bss(struct wiphy *wiphy, |
@@ -1108,6 +1134,12 @@ static int ieee80211_change_bss(struct wiphy *wiphy, | |||
1108 | sdata->flags &= ~IEEE80211_SDATA_DONT_BRIDGE_PACKETS; | 1134 | sdata->flags &= ~IEEE80211_SDATA_DONT_BRIDGE_PACKETS; |
1109 | } | 1135 | } |
1110 | 1136 | ||
1137 | if (params->ht_opmode >= 0) { | ||
1138 | sdata->vif.bss_conf.ht_operation_mode = | ||
1139 | (u16) params->ht_opmode; | ||
1140 | changed |= BSS_CHANGED_HT; | ||
1141 | } | ||
1142 | |||
1111 | ieee80211_bss_info_change_notify(sdata, changed); | 1143 | ieee80211_bss_info_change_notify(sdata, changed); |
1112 | 1144 | ||
1113 | return 0; | 1145 | return 0; |
@@ -1754,8 +1786,10 @@ struct cfg80211_ops mac80211_config_ops = { | |||
1754 | .change_mpath = ieee80211_change_mpath, | 1786 | .change_mpath = ieee80211_change_mpath, |
1755 | .get_mpath = ieee80211_get_mpath, | 1787 | .get_mpath = ieee80211_get_mpath, |
1756 | .dump_mpath = ieee80211_dump_mpath, | 1788 | .dump_mpath = ieee80211_dump_mpath, |
1757 | .set_mesh_params = ieee80211_set_mesh_params, | 1789 | .update_mesh_params = ieee80211_update_mesh_params, |
1758 | .get_mesh_params = ieee80211_get_mesh_params, | 1790 | .get_mesh_params = ieee80211_get_mesh_params, |
1791 | .join_mesh = ieee80211_join_mesh, | ||
1792 | .leave_mesh = ieee80211_leave_mesh, | ||
1759 | #endif | 1793 | #endif |
1760 | .change_bss = ieee80211_change_bss, | 1794 | .change_bss = ieee80211_change_bss, |
1761 | .set_txq_params = ieee80211_set_txq_params, | 1795 | .set_txq_params = ieee80211_set_txq_params, |
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index cbdf36d7841c..2dabdf7680d0 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c | |||
@@ -251,6 +251,7 @@ IEEE80211_IF_FILE(dot11MeshConfirmTimeout, | |||
251 | IEEE80211_IF_FILE(dot11MeshHoldingTimeout, | 251 | IEEE80211_IF_FILE(dot11MeshHoldingTimeout, |
252 | u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC); | 252 | u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC); |
253 | IEEE80211_IF_FILE(dot11MeshTTL, u.mesh.mshcfg.dot11MeshTTL, DEC); | 253 | IEEE80211_IF_FILE(dot11MeshTTL, u.mesh.mshcfg.dot11MeshTTL, DEC); |
254 | IEEE80211_IF_FILE(element_ttl, u.mesh.mshcfg.element_ttl, DEC); | ||
254 | IEEE80211_IF_FILE(auto_open_plinks, u.mesh.mshcfg.auto_open_plinks, DEC); | 255 | IEEE80211_IF_FILE(auto_open_plinks, u.mesh.mshcfg.auto_open_plinks, DEC); |
255 | IEEE80211_IF_FILE(dot11MeshMaxPeerLinks, | 256 | IEEE80211_IF_FILE(dot11MeshMaxPeerLinks, |
256 | u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC); | 257 | u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC); |
@@ -355,6 +356,7 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata) | |||
355 | MESHPARAMS_ADD(dot11MeshConfirmTimeout); | 356 | MESHPARAMS_ADD(dot11MeshConfirmTimeout); |
356 | MESHPARAMS_ADD(dot11MeshHoldingTimeout); | 357 | MESHPARAMS_ADD(dot11MeshHoldingTimeout); |
357 | MESHPARAMS_ADD(dot11MeshTTL); | 358 | MESHPARAMS_ADD(dot11MeshTTL); |
359 | MESHPARAMS_ADD(element_ttl); | ||
358 | MESHPARAMS_ADD(auto_open_plinks); | 360 | MESHPARAMS_ADD(auto_open_plinks); |
359 | MESHPARAMS_ADD(dot11MeshMaxPeerLinks); | 361 | MESHPARAMS_ADD(dot11MeshMaxPeerLinks); |
360 | MESHPARAMS_ADD(dot11MeshHWMPactivePathTimeout); | 362 | MESHPARAMS_ADD(dot11MeshHWMPactivePathTimeout); |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 66b0b52b828d..72499fe5fc36 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -357,6 +357,7 @@ struct ieee80211_if_managed { | |||
357 | unsigned long beacon_timeout; | 357 | unsigned long beacon_timeout; |
358 | unsigned long probe_timeout; | 358 | unsigned long probe_timeout; |
359 | int probe_send_count; | 359 | int probe_send_count; |
360 | bool nullfunc_failed; | ||
360 | 361 | ||
361 | struct mutex mtx; | 362 | struct mutex mtx; |
362 | struct cfg80211_bss *associated; | 363 | struct cfg80211_bss *associated; |
@@ -608,19 +609,6 @@ struct ieee80211_sub_if_data *vif_to_sdata(struct ieee80211_vif *p) | |||
608 | return container_of(p, struct ieee80211_sub_if_data, vif); | 609 | return container_of(p, struct ieee80211_sub_if_data, vif); |
609 | } | 610 | } |
610 | 611 | ||
611 | static inline void | ||
612 | ieee80211_sdata_set_mesh_id(struct ieee80211_sub_if_data *sdata, | ||
613 | u8 mesh_id_len, u8 *mesh_id) | ||
614 | { | ||
615 | #ifdef CONFIG_MAC80211_MESH | ||
616 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
617 | ifmsh->mesh_id_len = mesh_id_len; | ||
618 | memcpy(ifmsh->mesh_id, mesh_id, mesh_id_len); | ||
619 | #else | ||
620 | WARN_ON(1); | ||
621 | #endif | ||
622 | } | ||
623 | |||
624 | enum sdata_queue_type { | 612 | enum sdata_queue_type { |
625 | IEEE80211_SDATA_QUEUE_TYPE_FRAME = 0, | 613 | IEEE80211_SDATA_QUEUE_TYPE_FRAME = 0, |
626 | IEEE80211_SDATA_QUEUE_AGG_START = 1, | 614 | IEEE80211_SDATA_QUEUE_AGG_START = 1, |
@@ -1271,7 +1259,7 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local, | |||
1271 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | 1259 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, |
1272 | struct ieee80211_hdr *hdr); | 1260 | struct ieee80211_hdr *hdr); |
1273 | void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, | 1261 | void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, |
1274 | struct ieee80211_hdr *hdr); | 1262 | struct ieee80211_hdr *hdr, bool ack); |
1275 | void ieee80211_beacon_connection_loss_work(struct work_struct *work); | 1263 | void ieee80211_beacon_connection_loss_work(struct work_struct *work); |
1276 | 1264 | ||
1277 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, | 1265 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 7aa85591dbe7..f0f11bb794af 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) | |||
197 | sdata->bss = &sdata->u.ap; | 197 | sdata->bss = &sdata->u.ap; |
198 | break; | 198 | break; |
199 | case NL80211_IFTYPE_MESH_POINT: | 199 | case NL80211_IFTYPE_MESH_POINT: |
200 | if (!ieee80211_vif_is_mesh(&sdata->vif)) | ||
201 | break; | ||
202 | /* mesh ifaces must set allmulti to forward mcast traffic */ | ||
203 | atomic_inc(&local->iff_allmultis); | ||
204 | break; | ||
205 | case NL80211_IFTYPE_STATION: | 200 | case NL80211_IFTYPE_STATION: |
206 | case NL80211_IFTYPE_MONITOR: | 201 | case NL80211_IFTYPE_MONITOR: |
207 | case NL80211_IFTYPE_ADHOC: | 202 | case NL80211_IFTYPE_ADHOC: |
@@ -273,12 +268,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) | |||
273 | goto err_stop; | 268 | goto err_stop; |
274 | } | 269 | } |
275 | 270 | ||
276 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 271 | if (sdata->vif.type == NL80211_IFTYPE_AP) { |
277 | local->fif_other_bss++; | ||
278 | ieee80211_configure_filter(local); | ||
279 | |||
280 | ieee80211_start_mesh(sdata); | ||
281 | } else if (sdata->vif.type == NL80211_IFTYPE_AP) { | ||
282 | local->fif_pspoll++; | 272 | local->fif_pspoll++; |
283 | local->fif_probe_req++; | 273 | local->fif_probe_req++; |
284 | 274 | ||
@@ -503,18 +493,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
503 | ieee80211_adjust_monitor_flags(sdata, -1); | 493 | ieee80211_adjust_monitor_flags(sdata, -1); |
504 | ieee80211_configure_filter(local); | 494 | ieee80211_configure_filter(local); |
505 | break; | 495 | break; |
506 | case NL80211_IFTYPE_MESH_POINT: | ||
507 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
508 | /* other_bss and allmulti are always set on mesh | ||
509 | * ifaces */ | ||
510 | local->fif_other_bss--; | ||
511 | atomic_dec(&local->iff_allmultis); | ||
512 | |||
513 | ieee80211_configure_filter(local); | ||
514 | |||
515 | ieee80211_stop_mesh(sdata); | ||
516 | } | ||
517 | /* fall through */ | ||
518 | default: | 496 | default: |
519 | flush_work(&sdata->work); | 497 | flush_work(&sdata->work); |
520 | /* | 498 | /* |
@@ -1204,12 +1182,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
1204 | if (ret) | 1182 | if (ret) |
1205 | goto fail; | 1183 | goto fail; |
1206 | 1184 | ||
1207 | if (ieee80211_vif_is_mesh(&sdata->vif) && | ||
1208 | params && params->mesh_id_len) | ||
1209 | ieee80211_sdata_set_mesh_id(sdata, | ||
1210 | params->mesh_id_len, | ||
1211 | params->mesh_id); | ||
1212 | |||
1213 | mutex_lock(&local->iflist_mtx); | 1185 | mutex_lock(&local->iflist_mtx); |
1214 | list_add_tail_rcu(&sdata->list, &local->interfaces); | 1186 | list_add_tail_rcu(&sdata->list, &local->interfaces); |
1215 | mutex_unlock(&local->iflist_mtx); | 1187 | mutex_unlock(&local->iflist_mtx); |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 107a0cbe52ac..973fee9f7d69 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, | |||
245 | sdata->vif.bss_conf.enable_beacon = | 245 | sdata->vif.bss_conf.enable_beacon = |
246 | !!sdata->u.ibss.presp; | 246 | !!sdata->u.ibss.presp; |
247 | break; | 247 | break; |
248 | #ifdef CONFIG_MAC80211_MESH | ||
248 | case NL80211_IFTYPE_MESH_POINT: | 249 | case NL80211_IFTYPE_MESH_POINT: |
249 | sdata->vif.bss_conf.enable_beacon = true; | 250 | sdata->vif.bss_conf.enable_beacon = |
251 | !!sdata->u.mesh.mesh_id_len; | ||
250 | break; | 252 | break; |
253 | #endif | ||
251 | default: | 254 | default: |
252 | /* not reached */ | 255 | /* not reached */ |
253 | WARN_ON(1); | 256 | WARN_ON(1); |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index c8a4f19ed13b..63e1188d5062 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) | |||
513 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 513 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
514 | struct ieee80211_local *local = sdata->local; | 514 | struct ieee80211_local *local = sdata->local; |
515 | 515 | ||
516 | local->fif_other_bss++; | ||
517 | /* mesh ifaces must set allmulti to forward mcast traffic */ | ||
518 | atomic_inc(&local->iff_allmultis); | ||
519 | ieee80211_configure_filter(local); | ||
520 | |||
516 | set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); | 521 | set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); |
517 | ieee80211_mesh_root_setup(ifmsh); | 522 | ieee80211_mesh_root_setup(ifmsh); |
518 | ieee80211_queue_work(&local->hw, &sdata->work); | 523 | ieee80211_queue_work(&local->hw, &sdata->work); |
@@ -524,6 +529,13 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | |||
524 | 529 | ||
525 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) | 530 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) |
526 | { | 531 | { |
532 | struct ieee80211_local *local = sdata->local; | ||
533 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
534 | |||
535 | ifmsh->mesh_id_len = 0; | ||
536 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); | ||
537 | sta_info_flush(local, NULL); | ||
538 | |||
527 | del_timer_sync(&sdata->u.mesh.housekeeping_timer); | 539 | del_timer_sync(&sdata->u.mesh.housekeeping_timer); |
528 | del_timer_sync(&sdata->u.mesh.mesh_path_root_timer); | 540 | del_timer_sync(&sdata->u.mesh.mesh_path_root_timer); |
529 | /* | 541 | /* |
@@ -534,6 +546,10 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) | |||
534 | * it no longer is. | 546 | * it no longer is. |
535 | */ | 547 | */ |
536 | cancel_work_sync(&sdata->work); | 548 | cancel_work_sync(&sdata->work); |
549 | |||
550 | local->fif_other_bss--; | ||
551 | atomic_dec(&local->iff_allmultis); | ||
552 | ieee80211_configure_filter(local); | ||
537 | } | 553 | } |
538 | 554 | ||
539 | static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | 555 | 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) | |||
663 | ieee80211_mesh_housekeeping_timer, | 679 | ieee80211_mesh_housekeeping_timer, |
664 | (unsigned long) sdata); | 680 | (unsigned long) sdata); |
665 | 681 | ||
666 | ifmsh->mshcfg.dot11MeshRetryTimeout = MESH_RET_T; | ||
667 | ifmsh->mshcfg.dot11MeshConfirmTimeout = MESH_CONF_T; | ||
668 | ifmsh->mshcfg.dot11MeshHoldingTimeout = MESH_HOLD_T; | ||
669 | ifmsh->mshcfg.dot11MeshMaxRetries = MESH_MAX_RETR; | ||
670 | ifmsh->mshcfg.dot11MeshTTL = MESH_TTL; | ||
671 | ifmsh->mshcfg.auto_open_plinks = true; | ||
672 | ifmsh->mshcfg.dot11MeshMaxPeerLinks = | ||
673 | MESH_MAX_ESTAB_PLINKS; | ||
674 | ifmsh->mshcfg.dot11MeshHWMPactivePathTimeout = | ||
675 | MESH_PATH_TIMEOUT; | ||
676 | ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval = | ||
677 | MESH_PREQ_MIN_INT; | ||
678 | ifmsh->mshcfg.dot11MeshHWMPnetDiameterTraversalTime = | ||
679 | MESH_DIAM_TRAVERSAL_TIME; | ||
680 | ifmsh->mshcfg.dot11MeshHWMPmaxPREQretries = | ||
681 | MESH_MAX_PREQ_RETRIES; | ||
682 | ifmsh->mshcfg.path_refresh_time = | ||
683 | MESH_PATH_REFRESH_TIME; | ||
684 | ifmsh->mshcfg.min_discovery_timeout = | ||
685 | MESH_MIN_DISCOVERY_TIMEOUT; | ||
686 | ifmsh->accepting_plinks = true; | 682 | ifmsh->accepting_plinks = true; |
687 | ifmsh->preq_id = 0; | 683 | ifmsh->preq_id = 0; |
688 | ifmsh->sn = 0; | 684 | ifmsh->sn = 0; |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 58e741128968..039d7fa0af74 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -175,33 +175,10 @@ struct mesh_rmc { | |||
175 | */ | 175 | */ |
176 | #define MESH_CFG_CMP_LEN (IEEE80211_MESH_CONFIG_LEN - 2) | 176 | #define MESH_CFG_CMP_LEN (IEEE80211_MESH_CONFIG_LEN - 2) |
177 | 177 | ||
178 | /* Default values, timeouts in ms */ | ||
179 | #define MESH_TTL 31 | ||
180 | #define MESH_MAX_RETR 3 | ||
181 | #define MESH_RET_T 100 | ||
182 | #define MESH_CONF_T 100 | ||
183 | #define MESH_HOLD_T 100 | ||
184 | |||
185 | #define MESH_PATH_TIMEOUT 5000 | ||
186 | /* Minimum interval between two consecutive PREQs originated by the same | ||
187 | * interface | ||
188 | */ | ||
189 | #define MESH_PREQ_MIN_INT 10 | ||
190 | #define MESH_DIAM_TRAVERSAL_TIME 50 | ||
191 | /* A path will be refreshed if it is used PATH_REFRESH_TIME milliseconds before | ||
192 | * timing out. This way it will remain ACTIVE and no data frames will be | ||
193 | * unnecesarily held in the pending queue. | ||
194 | */ | ||
195 | #define MESH_PATH_REFRESH_TIME 1000 | ||
196 | #define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME) | ||
197 | #define MESH_DEFAULT_BEACON_INTERVAL 1000 /* in 1024 us units */ | 178 | #define MESH_DEFAULT_BEACON_INTERVAL 1000 /* in 1024 us units */ |
198 | 179 | ||
199 | #define MESH_MAX_PREQ_RETRIES 4 | ||
200 | #define MESH_PATH_EXPIRE (600 * HZ) | 180 | #define MESH_PATH_EXPIRE (600 * HZ) |
201 | 181 | ||
202 | /* Default maximum number of established plinks per interface */ | ||
203 | #define MESH_MAX_ESTAB_PLINKS 32 | ||
204 | |||
205 | /* Default maximum number of plinks per interface */ | 182 | /* Default maximum number of plinks per interface */ |
206 | #define MESH_MAX_PLINKS 256 | 183 | #define MESH_MAX_PLINKS 256 |
207 | 184 | ||
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 829e08a657d0..5bf64d7112b3 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, | |||
232 | *pos++ = WLAN_EID_PERR; | 232 | *pos++ = WLAN_EID_PERR; |
233 | *pos++ = ie_len; | 233 | *pos++ = ie_len; |
234 | /* ttl */ | 234 | /* ttl */ |
235 | *pos++ = MESH_TTL; | 235 | *pos++ = ttl; |
236 | /* number of destinations */ | 236 | /* number of destinations */ |
237 | *pos++ = 1; | 237 | *pos++ = 1; |
238 | /* | 238 | /* |
@@ -522,7 +522,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, | |||
522 | 522 | ||
523 | if (reply) { | 523 | if (reply) { |
524 | lifetime = PREQ_IE_LIFETIME(preq_elem); | 524 | lifetime = PREQ_IE_LIFETIME(preq_elem); |
525 | ttl = ifmsh->mshcfg.dot11MeshTTL; | 525 | ttl = ifmsh->mshcfg.element_ttl; |
526 | if (ttl != 0) { | 526 | if (ttl != 0) { |
527 | mhwmp_dbg("replying to the PREQ\n"); | 527 | mhwmp_dbg("replying to the PREQ\n"); |
528 | mesh_path_sel_frame_tx(MPATH_PREP, 0, target_addr, | 528 | 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) | |||
877 | sdata->u.mesh.last_sn_update = jiffies; | 877 | sdata->u.mesh.last_sn_update = jiffies; |
878 | } | 878 | } |
879 | lifetime = default_lifetime(sdata); | 879 | lifetime = default_lifetime(sdata); |
880 | ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; | 880 | ttl = sdata->u.mesh.mshcfg.element_ttl; |
881 | if (ttl == 0) { | 881 | if (ttl == 0) { |
882 | sdata->u.mesh.mshstats.dropped_frames_ttl++; | 882 | sdata->u.mesh.mshstats.dropped_frames_ttl++; |
883 | spin_unlock_bh(&mpath->state_lock); | 883 | spin_unlock_bh(&mpath->state_lock); |
@@ -1013,5 +1013,6 @@ mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata) | |||
1013 | mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->vif.addr, | 1013 | mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->vif.addr, |
1014 | cpu_to_le32(++ifmsh->sn), | 1014 | cpu_to_le32(++ifmsh->sn), |
1015 | 0, NULL, 0, broadcast_addr, | 1015 | 0, NULL, 0, broadcast_addr, |
1016 | 0, MESH_TTL, 0, 0, 0, sdata); | 1016 | 0, sdata->u.mesh.mshcfg.element_ttl, |
1017 | 0, 0, 0, sdata); | ||
1017 | } | 1018 | } |
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 349e466cf08b..8d65b47d9837 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) | |||
467 | mpath->flags &= ~MESH_PATH_ACTIVE; | 467 | mpath->flags &= ~MESH_PATH_ACTIVE; |
468 | ++mpath->sn; | 468 | ++mpath->sn; |
469 | spin_unlock_bh(&mpath->state_lock); | 469 | spin_unlock_bh(&mpath->state_lock); |
470 | mesh_path_error_tx(MESH_TTL, mpath->dst, | 470 | mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl, |
471 | cpu_to_le32(mpath->sn), | 471 | mpath->dst, cpu_to_le32(mpath->sn), |
472 | cpu_to_le16(PERR_RCODE_DEST_UNREACH), | 472 | cpu_to_le16(PERR_RCODE_DEST_UNREACH), |
473 | bcast, sdata); | 473 | bcast, sdata); |
474 | } else | 474 | } else |
@@ -614,7 +614,8 @@ void mesh_path_discard_frame(struct sk_buff *skb, | |||
614 | mpath = mesh_path_lookup(da, sdata); | 614 | mpath = mesh_path_lookup(da, sdata); |
615 | if (mpath) | 615 | if (mpath) |
616 | sn = ++mpath->sn; | 616 | sn = ++mpath->sn; |
617 | mesh_path_error_tx(MESH_TTL, skb->data, cpu_to_le32(sn), | 617 | mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl, skb->data, |
618 | cpu_to_le32(sn), | ||
618 | cpu_to_le16(PERR_RCODE_NO_ROUTE), ra, sdata); | 619 | cpu_to_le16(PERR_RCODE_NO_ROUTE), ra, sdata); |
619 | } | 620 | } |
620 | 621 | ||
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 794807914940..45fbb9e33746 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) | |||
625 | /* | 625 | /* |
626 | * Go to full PSM if the user configures a very low | 626 | * Go to full PSM if the user configures a very low |
627 | * latency requirement. | 627 | * latency requirement. |
628 | * The 2 second value is there for compatibility until | 628 | * The 2000 second value is there for compatibility |
629 | * the PM_QOS_NETWORK_LATENCY is configured with real | 629 | * until the PM_QOS_NETWORK_LATENCY is configured |
630 | * values. | 630 | * with real values. |
631 | */ | 631 | */ |
632 | if (latency > 1900000000 && latency != 2000000000) | 632 | if (latency > (1900 * USEC_PER_MSEC) && |
633 | latency != (2000 * USEC_PER_SEC)) | ||
633 | timeout = 0; | 634 | timeout = 0; |
634 | else | 635 | else |
635 | timeout = 100; | 636 | timeout = 100; |
@@ -1065,17 +1066,20 @@ static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata) | |||
1065 | } | 1066 | } |
1066 | 1067 | ||
1067 | void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, | 1068 | void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, |
1068 | struct ieee80211_hdr *hdr) | 1069 | struct ieee80211_hdr *hdr, bool ack) |
1069 | { | 1070 | { |
1070 | if (!ieee80211_is_data(hdr->frame_control) && | 1071 | if (!ieee80211_is_data(hdr->frame_control)) |
1071 | !ieee80211_is_nullfunc(hdr->frame_control)) | ||
1072 | return; | 1072 | return; |
1073 | 1073 | ||
1074 | ieee80211_sta_reset_conn_monitor(sdata); | 1074 | if (ack) |
1075 | ieee80211_sta_reset_conn_monitor(sdata); | ||
1075 | 1076 | ||
1076 | if (ieee80211_is_nullfunc(hdr->frame_control) && | 1077 | if (ieee80211_is_nullfunc(hdr->frame_control) && |
1077 | sdata->u.mgd.probe_send_count > 0) { | 1078 | sdata->u.mgd.probe_send_count > 0) { |
1078 | sdata->u.mgd.probe_send_count = 0; | 1079 | if (ack) |
1080 | sdata->u.mgd.probe_send_count = 0; | ||
1081 | else | ||
1082 | sdata->u.mgd.nullfunc_failed = true; | ||
1079 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); | 1083 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); |
1080 | } | 1084 | } |
1081 | } | 1085 | } |
@@ -1102,9 +1106,10 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | |||
1102 | * anymore. The timeout will be reset if the frame is ACKed by | 1106 | * anymore. The timeout will be reset if the frame is ACKed by |
1103 | * the AP. | 1107 | * the AP. |
1104 | */ | 1108 | */ |
1105 | if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) | 1109 | if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) { |
1110 | ifmgd->nullfunc_failed = false; | ||
1106 | ieee80211_send_nullfunc(sdata->local, sdata, 0); | 1111 | ieee80211_send_nullfunc(sdata->local, sdata, 0); |
1107 | else { | 1112 | } else { |
1108 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); | 1113 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); |
1109 | ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0); | 1114 | ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0); |
1110 | } | 1115 | } |
@@ -1913,6 +1918,31 @@ static void ieee80211_sta_timer(unsigned long data) | |||
1913 | ieee80211_queue_work(&local->hw, &sdata->work); | 1918 | ieee80211_queue_work(&local->hw, &sdata->work); |
1914 | } | 1919 | } |
1915 | 1920 | ||
1921 | static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, | ||
1922 | u8 *bssid) | ||
1923 | { | ||
1924 | struct ieee80211_local *local = sdata->local; | ||
1925 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1926 | |||
1927 | ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | | ||
1928 | IEEE80211_STA_BEACON_POLL); | ||
1929 | |||
1930 | ieee80211_set_disassoc(sdata, true, true); | ||
1931 | mutex_unlock(&ifmgd->mtx); | ||
1932 | mutex_lock(&local->mtx); | ||
1933 | ieee80211_recalc_idle(local); | ||
1934 | mutex_unlock(&local->mtx); | ||
1935 | /* | ||
1936 | * must be outside lock due to cfg80211, | ||
1937 | * but that's not a problem. | ||
1938 | */ | ||
1939 | ieee80211_send_deauth_disassoc(sdata, bssid, | ||
1940 | IEEE80211_STYPE_DEAUTH, | ||
1941 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, | ||
1942 | NULL, true); | ||
1943 | mutex_lock(&ifmgd->mtx); | ||
1944 | } | ||
1945 | |||
1916 | void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | 1946 | void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) |
1917 | { | 1947 | { |
1918 | struct ieee80211_local *local = sdata->local; | 1948 | struct ieee80211_local *local = sdata->local; |
@@ -1937,11 +1967,37 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
1937 | /* ACK received for nullfunc probing frame */ | 1967 | /* ACK received for nullfunc probing frame */ |
1938 | if (!ifmgd->probe_send_count) | 1968 | if (!ifmgd->probe_send_count) |
1939 | ieee80211_reset_ap_probe(sdata); | 1969 | ieee80211_reset_ap_probe(sdata); |
1940 | 1970 | else if (ifmgd->nullfunc_failed) { | |
1941 | else if (time_is_after_jiffies(ifmgd->probe_timeout)) | 1971 | if (ifmgd->probe_send_count < max_tries) { |
1972 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
1973 | wiphy_debug(local->hw.wiphy, | ||
1974 | "%s: No ack for nullfunc frame to" | ||
1975 | " AP %pM, try %d\n", | ||
1976 | sdata->name, bssid, | ||
1977 | ifmgd->probe_send_count); | ||
1978 | #endif | ||
1979 | ieee80211_mgd_probe_ap_send(sdata); | ||
1980 | } else { | ||
1981 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
1982 | wiphy_debug(local->hw.wiphy, | ||
1983 | "%s: No ack for nullfunc frame to" | ||
1984 | " AP %pM, disconnecting.\n", | ||
1985 | sdata->name, bssid); | ||
1986 | #endif | ||
1987 | ieee80211_sta_connection_lost(sdata, bssid); | ||
1988 | } | ||
1989 | } else if (time_is_after_jiffies(ifmgd->probe_timeout)) | ||
1942 | run_again(ifmgd, ifmgd->probe_timeout); | 1990 | run_again(ifmgd, ifmgd->probe_timeout); |
1943 | 1991 | else if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) { | |
1944 | else if (ifmgd->probe_send_count < max_tries) { | 1992 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
1993 | wiphy_debug(local->hw.wiphy, | ||
1994 | "%s: Failed to send nullfunc to AP %pM" | ||
1995 | " after %dms, disconnecting.\n", | ||
1996 | sdata->name, | ||
1997 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); | ||
1998 | #endif | ||
1999 | ieee80211_sta_connection_lost(sdata, bssid); | ||
2000 | } else if (ifmgd->probe_send_count < max_tries) { | ||
1945 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 2001 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
1946 | wiphy_debug(local->hw.wiphy, | 2002 | wiphy_debug(local->hw.wiphy, |
1947 | "%s: No probe response from AP %pM" | 2003 | "%s: No probe response from AP %pM" |
@@ -1956,27 +2012,13 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
1956 | * We actually lost the connection ... or did we? | 2012 | * We actually lost the connection ... or did we? |
1957 | * Let's make sure! | 2013 | * Let's make sure! |
1958 | */ | 2014 | */ |
1959 | ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | | ||
1960 | IEEE80211_STA_BEACON_POLL); | ||
1961 | wiphy_debug(local->hw.wiphy, | 2015 | wiphy_debug(local->hw.wiphy, |
1962 | "%s: No probe response from AP %pM" | 2016 | "%s: No probe response from AP %pM" |
1963 | " after %dms, disconnecting.\n", | 2017 | " after %dms, disconnecting.\n", |
1964 | sdata->name, | 2018 | sdata->name, |
1965 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); | 2019 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); |
1966 | ieee80211_set_disassoc(sdata, true, true); | 2020 | |
1967 | mutex_unlock(&ifmgd->mtx); | 2021 | ieee80211_sta_connection_lost(sdata, bssid); |
1968 | mutex_lock(&local->mtx); | ||
1969 | ieee80211_recalc_idle(local); | ||
1970 | mutex_unlock(&local->mtx); | ||
1971 | /* | ||
1972 | * must be outside lock due to cfg80211, | ||
1973 | * but that's not a problem. | ||
1974 | */ | ||
1975 | ieee80211_send_deauth_disassoc(sdata, bssid, | ||
1976 | IEEE80211_STYPE_DEAUTH, | ||
1977 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, | ||
1978 | NULL, true); | ||
1979 | mutex_lock(&ifmgd->mtx); | ||
1980 | } | 2022 | } |
1981 | } | 2023 | } |
1982 | 2024 | ||
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 6289525c0998..2fe8f5f86499 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) | |||
1163 | sta->rx_fragments++; | 1163 | sta->rx_fragments++; |
1164 | sta->rx_bytes += rx->skb->len; | 1164 | sta->rx_bytes += rx->skb->len; |
1165 | sta->last_signal = status->signal; | 1165 | sta->last_signal = status->signal; |
1166 | ewma_add(&sta->avg_signal, -status->signal); | ||
1166 | 1167 | ||
1167 | /* | 1168 | /* |
1168 | * Change STA power saving mode only at the end of a frame | 1169 | * 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 eff58571fd7e..c426504ed1cf 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, | |||
244 | sta->local = local; | 244 | sta->local = local; |
245 | sta->sdata = sdata; | 245 | sta->sdata = sdata; |
246 | 246 | ||
247 | ewma_init(&sta->avg_signal, 1024, 8); | ||
248 | |||
247 | if (sta_prepare_rate_control(local, sta, gfp)) { | 249 | if (sta_prepare_rate_control(local, sta, gfp)) { |
248 | kfree(sta); | 250 | kfree(sta); |
249 | return NULL; | 251 | return NULL; |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 05f11302443b..fdca52cf88de 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/types.h> | 13 | #include <linux/types.h> |
14 | #include <linux/if_ether.h> | 14 | #include <linux/if_ether.h> |
15 | #include <linux/workqueue.h> | 15 | #include <linux/workqueue.h> |
16 | #include <linux/average.h> | ||
16 | #include "key.h" | 17 | #include "key.h" |
17 | 18 | ||
18 | /** | 19 | /** |
@@ -223,6 +224,7 @@ enum plink_state { | |||
223 | * @rx_fragments: number of received MPDUs | 224 | * @rx_fragments: number of received MPDUs |
224 | * @rx_dropped: number of dropped MPDUs from this STA | 225 | * @rx_dropped: number of dropped MPDUs from this STA |
225 | * @last_signal: signal of last received frame from this STA | 226 | * @last_signal: signal of last received frame from this STA |
227 | * @avg_signal: moving average of signal of received frames from this STA | ||
226 | * @last_seq_ctrl: last received seq/frag number from this STA (per RX queue) | 228 | * @last_seq_ctrl: last received seq/frag number from this STA (per RX queue) |
227 | * @tx_filtered_count: number of frames the hardware filtered for this STA | 229 | * @tx_filtered_count: number of frames the hardware filtered for this STA |
228 | * @tx_retry_failed: number of frames that failed retry | 230 | * @tx_retry_failed: number of frames that failed retry |
@@ -291,6 +293,7 @@ struct sta_info { | |||
291 | unsigned long rx_fragments; | 293 | unsigned long rx_fragments; |
292 | unsigned long rx_dropped; | 294 | unsigned long rx_dropped; |
293 | int last_signal; | 295 | int last_signal; |
296 | struct ewma avg_signal; | ||
294 | __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES]; | 297 | __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES]; |
295 | 298 | ||
296 | /* Updated from TX status path only, no locking requirements */ | 299 | /* Updated from TX status path only, no locking requirements */ |
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 4958710a7d92..38a797217a91 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) | |||
155 | 155 | ||
156 | ieee80211_queue_work(&local->hw, &local->recalc_smps); | 156 | ieee80211_queue_work(&local->hw, &local->recalc_smps); |
157 | } | 157 | } |
158 | |||
159 | if ((sdata->vif.type == NL80211_IFTYPE_STATION) && | ||
160 | (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) | ||
161 | ieee80211_sta_tx_notify(sdata, (void *) skb->data); | ||
162 | } | 158 | } |
163 | 159 | ||
164 | /* | 160 | /* |
@@ -186,6 +182,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
186 | int retry_count = -1, i; | 182 | int retry_count = -1, i; |
187 | int rates_idx = -1; | 183 | int rates_idx = -1; |
188 | bool send_to_cooked; | 184 | bool send_to_cooked; |
185 | bool acked; | ||
189 | 186 | ||
190 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { | 187 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { |
191 | /* the HW cannot have attempted that rate */ | 188 | /* the HW cannot have attempted that rate */ |
@@ -211,8 +208,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
211 | if (memcmp(hdr->addr2, sta->sdata->vif.addr, ETH_ALEN)) | 208 | if (memcmp(hdr->addr2, sta->sdata->vif.addr, ETH_ALEN)) |
212 | continue; | 209 | continue; |
213 | 210 | ||
214 | if (!(info->flags & IEEE80211_TX_STAT_ACK) && | 211 | acked = !!(info->flags & IEEE80211_TX_STAT_ACK); |
215 | test_sta_flags(sta, WLAN_STA_PS_STA)) { | 212 | if (!acked && test_sta_flags(sta, WLAN_STA_PS_STA)) { |
216 | /* | 213 | /* |
217 | * The STA is in power save mode, so assume | 214 | * The STA is in power save mode, so assume |
218 | * that this TX packet failed because of that. | 215 | * that this TX packet failed because of that. |
@@ -244,7 +241,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
244 | rcu_read_unlock(); | 241 | rcu_read_unlock(); |
245 | return; | 242 | return; |
246 | } else { | 243 | } else { |
247 | if (!(info->flags & IEEE80211_TX_STAT_ACK)) | 244 | if (!acked) |
248 | sta->tx_retry_failed++; | 245 | sta->tx_retry_failed++; |
249 | sta->tx_retry_count += retry_count; | 246 | sta->tx_retry_count += retry_count; |
250 | } | 247 | } |
@@ -253,10 +250,13 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
253 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) | 250 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) |
254 | ieee80211s_update_metric(local, sta, skb); | 251 | ieee80211s_update_metric(local, sta, skb); |
255 | 252 | ||
256 | if (!(info->flags & IEEE80211_TX_CTL_INJECTED) && | 253 | if (!(info->flags & IEEE80211_TX_CTL_INJECTED) && acked) |
257 | (info->flags & IEEE80211_TX_STAT_ACK)) | ||
258 | ieee80211_frame_acked(sta, skb); | 254 | ieee80211_frame_acked(sta, skb); |
259 | 255 | ||
256 | if ((sta->sdata->vif.type == NL80211_IFTYPE_STATION) && | ||
257 | (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) | ||
258 | ieee80211_sta_tx_notify(sta->sdata, (void *) skb->data, acked); | ||
259 | |||
260 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) { | 260 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) { |
261 | if (info->flags & IEEE80211_TX_STAT_ACK) { | 261 | if (info->flags & IEEE80211_TX_STAT_ACK) { |
262 | if (sta->lost_packets) | 262 | if (sta->lost_packets) |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 2ba742656825..0ee56bb0ea7e 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) | |||
666 | if (unlikely(info->control.rates[0].idx < 0)) | 666 | if (unlikely(info->control.rates[0].idx < 0)) |
667 | return TX_DROP; | 667 | return TX_DROP; |
668 | 668 | ||
669 | if (txrc.reported_rate.idx < 0) | 669 | if (txrc.reported_rate.idx < 0) { |
670 | txrc.reported_rate = info->control.rates[0]; | 670 | txrc.reported_rate = info->control.rates[0]; |
671 | 671 | if (tx->sta && ieee80211_is_data(hdr->frame_control)) | |
672 | if (tx->sta) | 672 | tx->sta->last_tx_rate = txrc.reported_rate; |
673 | } else if (tx->sta) | ||
673 | tx->sta->last_tx_rate = txrc.reported_rate; | 674 | tx->sta->last_tx_rate = txrc.reported_rate; |
674 | 675 | ||
675 | if (unlikely(!info->control.rates[0].count)) | 676 | if (unlikely(!info->control.rates[0].count)) |
@@ -1745,15 +1746,13 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1745 | int nh_pos, h_pos; | 1746 | int nh_pos, h_pos; |
1746 | struct sta_info *sta = NULL; | 1747 | struct sta_info *sta = NULL; |
1747 | u32 sta_flags = 0; | 1748 | u32 sta_flags = 0; |
1749 | struct sk_buff *tmp_skb; | ||
1748 | 1750 | ||
1749 | if (unlikely(skb->len < ETH_HLEN)) { | 1751 | if (unlikely(skb->len < ETH_HLEN)) { |
1750 | ret = NETDEV_TX_OK; | 1752 | ret = NETDEV_TX_OK; |
1751 | goto fail; | 1753 | goto fail; |
1752 | } | 1754 | } |
1753 | 1755 | ||
1754 | nh_pos = skb_network_header(skb) - skb->data; | ||
1755 | h_pos = skb_transport_header(skb) - skb->data; | ||
1756 | |||
1757 | /* convert Ethernet header to proper 802.11 header (based on | 1756 | /* convert Ethernet header to proper 802.11 header (based on |
1758 | * operation mode) */ | 1757 | * operation mode) */ |
1759 | ethertype = (skb->data[12] << 8) | skb->data[13]; | 1758 | ethertype = (skb->data[12] << 8) | skb->data[13]; |
@@ -1926,6 +1925,20 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1926 | goto fail; | 1925 | goto fail; |
1927 | } | 1926 | } |
1928 | 1927 | ||
1928 | /* | ||
1929 | * If the skb is shared we need to obtain our own copy. | ||
1930 | */ | ||
1931 | if (skb_shared(skb)) { | ||
1932 | tmp_skb = skb; | ||
1933 | skb = skb_copy(skb, GFP_ATOMIC); | ||
1934 | kfree_skb(tmp_skb); | ||
1935 | |||
1936 | if (!skb) { | ||
1937 | ret = NETDEV_TX_OK; | ||
1938 | goto fail; | ||
1939 | } | ||
1940 | } | ||
1941 | |||
1929 | hdr.frame_control = fc; | 1942 | hdr.frame_control = fc; |
1930 | hdr.duration_id = 0; | 1943 | hdr.duration_id = 0; |
1931 | hdr.seq_ctrl = 0; | 1944 | hdr.seq_ctrl = 0; |
@@ -1944,6 +1957,9 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1944 | encaps_len = 0; | 1957 | encaps_len = 0; |
1945 | } | 1958 | } |
1946 | 1959 | ||
1960 | nh_pos = skb_network_header(skb) - skb->data; | ||
1961 | h_pos = skb_transport_header(skb) - skb->data; | ||
1962 | |||
1947 | skb_pull(skb, skip_header_bytes); | 1963 | skb_pull(skb, skip_header_bytes); |
1948 | nh_pos -= skip_header_bytes; | 1964 | nh_pos -= skip_header_bytes; |
1949 | h_pos -= skip_header_bytes; | 1965 | h_pos -= skip_header_bytes; |
diff --git a/net/mac80211/work.c b/net/mac80211/work.c index 2b5c3f267198..de43753076d2 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c | |||
@@ -458,8 +458,9 @@ ieee80211_direct_probe(struct ieee80211_work *wk) | |||
458 | return WORK_ACT_TIMEOUT; | 458 | return WORK_ACT_TIMEOUT; |
459 | } | 459 | } |
460 | 460 | ||
461 | printk(KERN_DEBUG "%s: direct probe to %pM (try %d)\n", | 461 | printk(KERN_DEBUG "%s: direct probe to %pM (try %d/%i)\n", |
462 | sdata->name, wk->filter_ta, wk->probe_auth.tries); | 462 | sdata->name, wk->filter_ta, wk->probe_auth.tries, |
463 | IEEE80211_AUTH_MAX_TRIES); | ||
463 | 464 | ||
464 | /* | 465 | /* |
465 | * Direct probe is sent to broadcast address as some APs | 466 | * Direct probe is sent to broadcast address as some APs |
diff --git a/net/wireless/Makefile b/net/wireless/Makefile index e77e508126fa..55a28ab21db9 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile | |||
@@ -10,7 +10,7 @@ obj-$(CONFIG_WEXT_SPY) += wext-spy.o | |||
10 | obj-$(CONFIG_WEXT_PRIV) += wext-priv.o | 10 | obj-$(CONFIG_WEXT_PRIV) += wext-priv.o |
11 | 11 | ||
12 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o | 12 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o |
13 | cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o | 13 | cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o |
14 | cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o | 14 | cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o |
15 | cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o | 15 | cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o |
16 | cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o | 16 | cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 630bcf0a2f04..79772fcc37bc 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -332,6 +332,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
332 | WARN_ON(ops->add_virtual_intf && !ops->del_virtual_intf); | 332 | WARN_ON(ops->add_virtual_intf && !ops->del_virtual_intf); |
333 | WARN_ON(ops->add_station && !ops->del_station); | 333 | WARN_ON(ops->add_station && !ops->del_station); |
334 | WARN_ON(ops->add_mpath && !ops->del_mpath); | 334 | WARN_ON(ops->add_mpath && !ops->del_mpath); |
335 | WARN_ON(ops->join_mesh && !ops->leave_mesh); | ||
335 | 336 | ||
336 | alloc_size = sizeof(*rdev) + sizeof_priv; | 337 | alloc_size = sizeof(*rdev) + sizeof_priv; |
337 | 338 | ||
@@ -752,6 +753,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
752 | cfg80211_mlme_down(rdev, dev); | 753 | cfg80211_mlme_down(rdev, dev); |
753 | wdev_unlock(wdev); | 754 | wdev_unlock(wdev); |
754 | break; | 755 | break; |
756 | case NL80211_IFTYPE_MESH_POINT: | ||
757 | cfg80211_leave_mesh(rdev, dev); | ||
758 | break; | ||
755 | default: | 759 | default: |
756 | break; | 760 | break; |
757 | } | 761 | } |
@@ -775,20 +779,27 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
775 | } | 779 | } |
776 | cfg80211_lock_rdev(rdev); | 780 | cfg80211_lock_rdev(rdev); |
777 | mutex_lock(&rdev->devlist_mtx); | 781 | mutex_lock(&rdev->devlist_mtx); |
778 | #ifdef CONFIG_CFG80211_WEXT | ||
779 | wdev_lock(wdev); | 782 | wdev_lock(wdev); |
780 | switch (wdev->iftype) { | 783 | switch (wdev->iftype) { |
784 | #ifdef CONFIG_CFG80211_WEXT | ||
781 | case NL80211_IFTYPE_ADHOC: | 785 | case NL80211_IFTYPE_ADHOC: |
782 | cfg80211_ibss_wext_join(rdev, wdev); | 786 | cfg80211_ibss_wext_join(rdev, wdev); |
783 | break; | 787 | break; |
784 | case NL80211_IFTYPE_STATION: | 788 | case NL80211_IFTYPE_STATION: |
785 | cfg80211_mgd_wext_connect(rdev, wdev); | 789 | cfg80211_mgd_wext_connect(rdev, wdev); |
786 | break; | 790 | break; |
791 | #endif | ||
792 | case NL80211_IFTYPE_MESH_POINT: | ||
793 | /* backward compat code ... */ | ||
794 | if (wdev->mesh_id_up_len) | ||
795 | __cfg80211_join_mesh(rdev, dev, wdev->ssid, | ||
796 | wdev->mesh_id_up_len, | ||
797 | &default_mesh_config); | ||
798 | break; | ||
787 | default: | 799 | default: |
788 | break; | 800 | break; |
789 | } | 801 | } |
790 | wdev_unlock(wdev); | 802 | wdev_unlock(wdev); |
791 | #endif | ||
792 | rdev->opencount++; | 803 | rdev->opencount++; |
793 | mutex_unlock(&rdev->devlist_mtx); | 804 | mutex_unlock(&rdev->devlist_mtx); |
794 | cfg80211_unlock_rdev(rdev); | 805 | cfg80211_unlock_rdev(rdev); |
diff --git a/net/wireless/core.h b/net/wireless/core.h index ee80ad8dc655..743203bb61ac 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -285,6 +285,19 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid); | |||
285 | int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, | 285 | int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, |
286 | struct wireless_dev *wdev); | 286 | struct wireless_dev *wdev); |
287 | 287 | ||
288 | /* mesh */ | ||
289 | extern const struct mesh_config default_mesh_config; | ||
290 | int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | ||
291 | struct net_device *dev, | ||
292 | const u8 *mesh_id, u8 mesh_id_len, | ||
293 | const struct mesh_config *conf); | ||
294 | int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | ||
295 | struct net_device *dev, | ||
296 | const u8 *mesh_id, u8 mesh_id_len, | ||
297 | const struct mesh_config *conf); | ||
298 | int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, | ||
299 | struct net_device *dev); | ||
300 | |||
288 | /* MLME */ | 301 | /* MLME */ |
289 | int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | 302 | int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, |
290 | struct net_device *dev, | 303 | struct net_device *dev, |
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c new file mode 100644 index 000000000000..e0b9747fe50a --- /dev/null +++ b/net/wireless/mesh.c | |||
@@ -0,0 +1,140 @@ | |||
1 | #include <linux/ieee80211.h> | ||
2 | #include <net/cfg80211.h> | ||
3 | #include "core.h" | ||
4 | |||
5 | /* Default values, timeouts in ms */ | ||
6 | #define MESH_TTL 31 | ||
7 | #define MESH_DEFAULT_ELEMENT_TTL 31 | ||
8 | #define MESH_MAX_RETR 3 | ||
9 | #define MESH_RET_T 100 | ||
10 | #define MESH_CONF_T 100 | ||
11 | #define MESH_HOLD_T 100 | ||
12 | |||
13 | #define MESH_PATH_TIMEOUT 5000 | ||
14 | |||
15 | /* | ||
16 | * Minimum interval between two consecutive PREQs originated by the same | ||
17 | * interface | ||
18 | */ | ||
19 | #define MESH_PREQ_MIN_INT 10 | ||
20 | #define MESH_DIAM_TRAVERSAL_TIME 50 | ||
21 | |||
22 | /* | ||
23 | * A path will be refreshed if it is used PATH_REFRESH_TIME milliseconds | ||
24 | * before timing out. This way it will remain ACTIVE and no data frames | ||
25 | * will be unnecessarily held in the pending queue. | ||
26 | */ | ||
27 | #define MESH_PATH_REFRESH_TIME 1000 | ||
28 | #define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME) | ||
29 | |||
30 | /* Default maximum number of established plinks per interface */ | ||
31 | #define MESH_MAX_ESTAB_PLINKS 32 | ||
32 | |||
33 | #define MESH_MAX_PREQ_RETRIES 4 | ||
34 | |||
35 | |||
36 | const struct mesh_config default_mesh_config = { | ||
37 | .dot11MeshRetryTimeout = MESH_RET_T, | ||
38 | .dot11MeshConfirmTimeout = MESH_CONF_T, | ||
39 | .dot11MeshHoldingTimeout = MESH_HOLD_T, | ||
40 | .dot11MeshMaxRetries = MESH_MAX_RETR, | ||
41 | .dot11MeshTTL = MESH_TTL, | ||
42 | .element_ttl = MESH_DEFAULT_ELEMENT_TTL, | ||
43 | .auto_open_plinks = true, | ||
44 | .dot11MeshMaxPeerLinks = MESH_MAX_ESTAB_PLINKS, | ||
45 | .dot11MeshHWMPactivePathTimeout = MESH_PATH_TIMEOUT, | ||
46 | .dot11MeshHWMPpreqMinInterval = MESH_PREQ_MIN_INT, | ||
47 | .dot11MeshHWMPnetDiameterTraversalTime = MESH_DIAM_TRAVERSAL_TIME, | ||
48 | .dot11MeshHWMPmaxPREQretries = MESH_MAX_PREQ_RETRIES, | ||
49 | .path_refresh_time = MESH_PATH_REFRESH_TIME, | ||
50 | .min_discovery_timeout = MESH_MIN_DISCOVERY_TIMEOUT, | ||
51 | }; | ||
52 | |||
53 | |||
54 | int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | ||
55 | struct net_device *dev, | ||
56 | const u8 *mesh_id, u8 mesh_id_len, | ||
57 | const struct mesh_config *conf) | ||
58 | { | ||
59 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
60 | struct mesh_setup setup = { | ||
61 | .mesh_id = mesh_id, | ||
62 | .mesh_id_len = mesh_id_len, | ||
63 | }; | ||
64 | int err; | ||
65 | |||
66 | BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN); | ||
67 | |||
68 | ASSERT_WDEV_LOCK(wdev); | ||
69 | |||
70 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) | ||
71 | return -EOPNOTSUPP; | ||
72 | |||
73 | if (wdev->mesh_id_len) | ||
74 | return -EALREADY; | ||
75 | |||
76 | if (!mesh_id_len) | ||
77 | return -EINVAL; | ||
78 | |||
79 | if (!rdev->ops->join_mesh) | ||
80 | return -EOPNOTSUPP; | ||
81 | |||
82 | err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, &setup); | ||
83 | if (!err) { | ||
84 | memcpy(wdev->ssid, mesh_id, mesh_id_len); | ||
85 | wdev->mesh_id_len = mesh_id_len; | ||
86 | } | ||
87 | |||
88 | return err; | ||
89 | } | ||
90 | |||
91 | int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | ||
92 | struct net_device *dev, | ||
93 | const u8 *mesh_id, u8 mesh_id_len, | ||
94 | const struct mesh_config *conf) | ||
95 | { | ||
96 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
97 | int err; | ||
98 | |||
99 | wdev_lock(wdev); | ||
100 | err = __cfg80211_join_mesh(rdev, dev, mesh_id, mesh_id_len, conf); | ||
101 | wdev_unlock(wdev); | ||
102 | |||
103 | return err; | ||
104 | } | ||
105 | |||
106 | static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, | ||
107 | struct net_device *dev) | ||
108 | { | ||
109 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
110 | int err; | ||
111 | |||
112 | ASSERT_WDEV_LOCK(wdev); | ||
113 | |||
114 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) | ||
115 | return -EOPNOTSUPP; | ||
116 | |||
117 | if (!rdev->ops->leave_mesh) | ||
118 | return -EOPNOTSUPP; | ||
119 | |||
120 | if (!wdev->mesh_id_len) | ||
121 | return -ENOTCONN; | ||
122 | |||
123 | err = rdev->ops->leave_mesh(&rdev->wiphy, dev); | ||
124 | if (!err) | ||
125 | wdev->mesh_id_len = 0; | ||
126 | return err; | ||
127 | } | ||
128 | |||
129 | int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, | ||
130 | struct net_device *dev) | ||
131 | { | ||
132 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
133 | int err; | ||
134 | |||
135 | wdev_lock(wdev); | ||
136 | err = __cfg80211_leave_mesh(rdev, dev); | ||
137 | wdev_unlock(wdev); | ||
138 | |||
139 | return err; | ||
140 | } | ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 960be4e650f0..c3f80e565365 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -121,6 +121,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
121 | [NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 }, | 121 | [NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 }, |
122 | [NL80211_ATTR_BSS_BASIC_RATES] = { .type = NLA_BINARY, | 122 | [NL80211_ATTR_BSS_BASIC_RATES] = { .type = NLA_BINARY, |
123 | .len = NL80211_MAX_SUPP_RATES }, | 123 | .len = NL80211_MAX_SUPP_RATES }, |
124 | [NL80211_ATTR_BSS_HT_OPMODE] = { .type = NLA_U16 }, | ||
124 | 125 | ||
125 | [NL80211_ATTR_MESH_PARAMS] = { .type = NLA_NESTED }, | 126 | [NL80211_ATTR_MESH_PARAMS] = { .type = NLA_NESTED }, |
126 | 127 | ||
@@ -661,13 +662,14 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
661 | CMD(add_beacon, NEW_BEACON); | 662 | CMD(add_beacon, NEW_BEACON); |
662 | CMD(add_station, NEW_STATION); | 663 | CMD(add_station, NEW_STATION); |
663 | CMD(add_mpath, NEW_MPATH); | 664 | CMD(add_mpath, NEW_MPATH); |
664 | CMD(set_mesh_params, SET_MESH_PARAMS); | 665 | CMD(update_mesh_params, SET_MESH_PARAMS); |
665 | CMD(change_bss, SET_BSS); | 666 | CMD(change_bss, SET_BSS); |
666 | CMD(auth, AUTHENTICATE); | 667 | CMD(auth, AUTHENTICATE); |
667 | CMD(assoc, ASSOCIATE); | 668 | CMD(assoc, ASSOCIATE); |
668 | CMD(deauth, DEAUTHENTICATE); | 669 | CMD(deauth, DEAUTHENTICATE); |
669 | CMD(disassoc, DISASSOCIATE); | 670 | CMD(disassoc, DISASSOCIATE); |
670 | CMD(join_ibss, JOIN_IBSS); | 671 | CMD(join_ibss, JOIN_IBSS); |
672 | CMD(join_mesh, JOIN_MESH); | ||
671 | CMD(set_pmksa, SET_PMKSA); | 673 | CMD(set_pmksa, SET_PMKSA); |
672 | CMD(del_pmksa, DEL_PMKSA); | 674 | CMD(del_pmksa, DEL_PMKSA); |
673 | CMD(flush_pmksa, FLUSH_PMKSA); | 675 | CMD(flush_pmksa, FLUSH_PMKSA); |
@@ -1324,11 +1326,21 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
1324 | } | 1326 | } |
1325 | 1327 | ||
1326 | if (info->attrs[NL80211_ATTR_MESH_ID]) { | 1328 | if (info->attrs[NL80211_ATTR_MESH_ID]) { |
1329 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
1330 | |||
1327 | if (ntype != NL80211_IFTYPE_MESH_POINT) | 1331 | if (ntype != NL80211_IFTYPE_MESH_POINT) |
1328 | return -EINVAL; | 1332 | return -EINVAL; |
1329 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); | 1333 | if (netif_running(dev)) |
1330 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | 1334 | return -EBUSY; |
1331 | change = true; | 1335 | |
1336 | wdev_lock(wdev); | ||
1337 | BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != | ||
1338 | IEEE80211_MAX_MESH_ID_LEN); | ||
1339 | wdev->mesh_id_up_len = | ||
1340 | nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | ||
1341 | memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]), | ||
1342 | wdev->mesh_id_up_len); | ||
1343 | wdev_unlock(wdev); | ||
1332 | } | 1344 | } |
1333 | 1345 | ||
1334 | if (info->attrs[NL80211_ATTR_4ADDR]) { | 1346 | if (info->attrs[NL80211_ATTR_4ADDR]) { |
@@ -1368,6 +1380,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1368 | { | 1380 | { |
1369 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 1381 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1370 | struct vif_params params; | 1382 | struct vif_params params; |
1383 | struct net_device *dev; | ||
1371 | int err; | 1384 | int err; |
1372 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; | 1385 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; |
1373 | u32 flags; | 1386 | u32 flags; |
@@ -1387,12 +1400,6 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1387 | !(rdev->wiphy.interface_modes & (1 << type))) | 1400 | !(rdev->wiphy.interface_modes & (1 << type))) |
1388 | return -EOPNOTSUPP; | 1401 | return -EOPNOTSUPP; |
1389 | 1402 | ||
1390 | if (type == NL80211_IFTYPE_MESH_POINT && | ||
1391 | info->attrs[NL80211_ATTR_MESH_ID]) { | ||
1392 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); | ||
1393 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | ||
1394 | } | ||
1395 | |||
1396 | if (info->attrs[NL80211_ATTR_4ADDR]) { | 1403 | if (info->attrs[NL80211_ATTR_4ADDR]) { |
1397 | params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); | 1404 | params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); |
1398 | err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type); | 1405 | err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type); |
@@ -1403,11 +1410,27 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1403 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? | 1410 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? |
1404 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, | 1411 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, |
1405 | &flags); | 1412 | &flags); |
1406 | err = rdev->ops->add_virtual_intf(&rdev->wiphy, | 1413 | dev = rdev->ops->add_virtual_intf(&rdev->wiphy, |
1407 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), | 1414 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), |
1408 | type, err ? NULL : &flags, ¶ms); | 1415 | type, err ? NULL : &flags, ¶ms); |
1416 | if (IS_ERR(dev)) | ||
1417 | return PTR_ERR(dev); | ||
1409 | 1418 | ||
1410 | return err; | 1419 | if (type == NL80211_IFTYPE_MESH_POINT && |
1420 | info->attrs[NL80211_ATTR_MESH_ID]) { | ||
1421 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
1422 | |||
1423 | wdev_lock(wdev); | ||
1424 | BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != | ||
1425 | IEEE80211_MAX_MESH_ID_LEN); | ||
1426 | wdev->mesh_id_up_len = | ||
1427 | nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | ||
1428 | memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]), | ||
1429 | wdev->mesh_id_up_len); | ||
1430 | wdev_unlock(wdev); | ||
1431 | } | ||
1432 | |||
1433 | return 0; | ||
1411 | } | 1434 | } |
1412 | 1435 | ||
1413 | static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) | 1436 | static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) |
@@ -1874,6 +1897,9 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, | |||
1874 | if (sinfo->filled & STATION_INFO_SIGNAL) | 1897 | if (sinfo->filled & STATION_INFO_SIGNAL) |
1875 | NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL, | 1898 | NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL, |
1876 | sinfo->signal); | 1899 | sinfo->signal); |
1900 | if (sinfo->filled & STATION_INFO_SIGNAL_AVG) | ||
1901 | NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL_AVG, | ||
1902 | sinfo->signal_avg); | ||
1877 | if (sinfo->filled & STATION_INFO_TX_BITRATE) { | 1903 | if (sinfo->filled & STATION_INFO_TX_BITRATE) { |
1878 | txrate = nla_nest_start(msg, NL80211_STA_INFO_TX_BITRATE); | 1904 | txrate = nla_nest_start(msg, NL80211_STA_INFO_TX_BITRATE); |
1879 | if (!txrate) | 1905 | if (!txrate) |
@@ -2437,6 +2463,7 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) | |||
2437 | params.use_short_preamble = -1; | 2463 | params.use_short_preamble = -1; |
2438 | params.use_short_slot_time = -1; | 2464 | params.use_short_slot_time = -1; |
2439 | params.ap_isolate = -1; | 2465 | params.ap_isolate = -1; |
2466 | params.ht_opmode = -1; | ||
2440 | 2467 | ||
2441 | if (info->attrs[NL80211_ATTR_BSS_CTS_PROT]) | 2468 | if (info->attrs[NL80211_ATTR_BSS_CTS_PROT]) |
2442 | params.use_cts_prot = | 2469 | params.use_cts_prot = |
@@ -2455,6 +2482,9 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) | |||
2455 | } | 2482 | } |
2456 | if (info->attrs[NL80211_ATTR_AP_ISOLATE]) | 2483 | if (info->attrs[NL80211_ATTR_AP_ISOLATE]) |
2457 | params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]); | 2484 | params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]); |
2485 | if (info->attrs[NL80211_ATTR_BSS_HT_OPMODE]) | ||
2486 | params.ht_opmode = | ||
2487 | nla_get_u16(info->attrs[NL80211_ATTR_BSS_HT_OPMODE]); | ||
2458 | 2488 | ||
2459 | if (!rdev->ops->change_bss) | 2489 | if (!rdev->ops->change_bss) |
2460 | return -EOPNOTSUPP; | 2490 | return -EOPNOTSUPP; |
@@ -2540,21 +2570,32 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
2540 | } | 2570 | } |
2541 | 2571 | ||
2542 | static int nl80211_get_mesh_params(struct sk_buff *skb, | 2572 | static int nl80211_get_mesh_params(struct sk_buff *skb, |
2543 | struct genl_info *info) | 2573 | struct genl_info *info) |
2544 | { | 2574 | { |
2545 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 2575 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2546 | struct mesh_config cur_params; | ||
2547 | int err; | ||
2548 | struct net_device *dev = info->user_ptr[1]; | 2576 | struct net_device *dev = info->user_ptr[1]; |
2577 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
2578 | struct mesh_config cur_params; | ||
2579 | int err = 0; | ||
2549 | void *hdr; | 2580 | void *hdr; |
2550 | struct nlattr *pinfoattr; | 2581 | struct nlattr *pinfoattr; |
2551 | struct sk_buff *msg; | 2582 | struct sk_buff *msg; |
2552 | 2583 | ||
2584 | if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) | ||
2585 | return -EOPNOTSUPP; | ||
2586 | |||
2553 | if (!rdev->ops->get_mesh_params) | 2587 | if (!rdev->ops->get_mesh_params) |
2554 | return -EOPNOTSUPP; | 2588 | return -EOPNOTSUPP; |
2555 | 2589 | ||
2556 | /* Get the mesh params */ | 2590 | wdev_lock(wdev); |
2557 | err = rdev->ops->get_mesh_params(&rdev->wiphy, dev, &cur_params); | 2591 | /* If not connected, get default parameters */ |
2592 | if (!wdev->mesh_id_len) | ||
2593 | memcpy(&cur_params, &default_mesh_config, sizeof(cur_params)); | ||
2594 | else | ||
2595 | err = rdev->ops->get_mesh_params(&rdev->wiphy, dev, | ||
2596 | &cur_params); | ||
2597 | wdev_unlock(wdev); | ||
2598 | |||
2558 | if (err) | 2599 | if (err) |
2559 | return err; | 2600 | return err; |
2560 | 2601 | ||
@@ -2582,6 +2623,8 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, | |||
2582 | cur_params.dot11MeshMaxRetries); | 2623 | cur_params.dot11MeshMaxRetries); |
2583 | NLA_PUT_U8(msg, NL80211_MESHCONF_TTL, | 2624 | NLA_PUT_U8(msg, NL80211_MESHCONF_TTL, |
2584 | cur_params.dot11MeshTTL); | 2625 | cur_params.dot11MeshTTL); |
2626 | NLA_PUT_U8(msg, NL80211_MESHCONF_ELEMENT_TTL, | ||
2627 | cur_params.element_ttl); | ||
2585 | NLA_PUT_U8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS, | 2628 | NLA_PUT_U8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS, |
2586 | cur_params.auto_open_plinks); | 2629 | cur_params.auto_open_plinks); |
2587 | NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, | 2630 | NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, |
@@ -2608,14 +2651,6 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, | |||
2608 | return -ENOBUFS; | 2651 | return -ENOBUFS; |
2609 | } | 2652 | } |
2610 | 2653 | ||
2611 | #define FILL_IN_MESH_PARAM_IF_SET(table, cfg, param, mask, attr_num, nla_fn) \ | ||
2612 | do {\ | ||
2613 | if (table[attr_num]) {\ | ||
2614 | cfg.param = nla_fn(table[attr_num]); \ | ||
2615 | mask |= (1 << (attr_num - 1)); \ | ||
2616 | } \ | ||
2617 | } while (0);\ | ||
2618 | |||
2619 | static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_ATTR_MAX+1] = { | 2654 | static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_ATTR_MAX+1] = { |
2620 | [NL80211_MESHCONF_RETRY_TIMEOUT] = { .type = NLA_U16 }, | 2655 | [NL80211_MESHCONF_RETRY_TIMEOUT] = { .type = NLA_U16 }, |
2621 | [NL80211_MESHCONF_CONFIRM_TIMEOUT] = { .type = NLA_U16 }, | 2656 | [NL80211_MESHCONF_CONFIRM_TIMEOUT] = { .type = NLA_U16 }, |
@@ -2623,6 +2658,7 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A | |||
2623 | [NL80211_MESHCONF_MAX_PEER_LINKS] = { .type = NLA_U16 }, | 2658 | [NL80211_MESHCONF_MAX_PEER_LINKS] = { .type = NLA_U16 }, |
2624 | [NL80211_MESHCONF_MAX_RETRIES] = { .type = NLA_U8 }, | 2659 | [NL80211_MESHCONF_MAX_RETRIES] = { .type = NLA_U8 }, |
2625 | [NL80211_MESHCONF_TTL] = { .type = NLA_U8 }, | 2660 | [NL80211_MESHCONF_TTL] = { .type = NLA_U8 }, |
2661 | [NL80211_MESHCONF_ELEMENT_TTL] = { .type = NLA_U8 }, | ||
2626 | [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 }, | 2662 | [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 }, |
2627 | 2663 | ||
2628 | [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 }, | 2664 | [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 }, |
@@ -2633,31 +2669,34 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A | |||
2633 | [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 }, | 2669 | [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 }, |
2634 | }; | 2670 | }; |
2635 | 2671 | ||
2636 | static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) | 2672 | static int nl80211_parse_mesh_params(struct genl_info *info, |
2673 | struct mesh_config *cfg, | ||
2674 | u32 *mask_out) | ||
2637 | { | 2675 | { |
2638 | u32 mask; | ||
2639 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
2640 | struct net_device *dev = info->user_ptr[1]; | ||
2641 | struct mesh_config cfg; | ||
2642 | struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1]; | 2676 | struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1]; |
2643 | struct nlattr *parent_attr; | 2677 | u32 mask = 0; |
2678 | |||
2679 | #define FILL_IN_MESH_PARAM_IF_SET(table, cfg, param, mask, attr_num, nla_fn) \ | ||
2680 | do {\ | ||
2681 | if (table[attr_num]) {\ | ||
2682 | cfg->param = nla_fn(table[attr_num]); \ | ||
2683 | mask |= (1 << (attr_num - 1)); \ | ||
2684 | } \ | ||
2685 | } while (0);\ | ||
2686 | |||
2644 | 2687 | ||
2645 | parent_attr = info->attrs[NL80211_ATTR_MESH_PARAMS]; | 2688 | if (!info->attrs[NL80211_ATTR_MESH_PARAMS]) |
2646 | if (!parent_attr) | ||
2647 | return -EINVAL; | 2689 | return -EINVAL; |
2648 | if (nla_parse_nested(tb, NL80211_MESHCONF_ATTR_MAX, | 2690 | if (nla_parse_nested(tb, NL80211_MESHCONF_ATTR_MAX, |
2649 | parent_attr, nl80211_meshconf_params_policy)) | 2691 | info->attrs[NL80211_ATTR_MESH_PARAMS], |
2692 | nl80211_meshconf_params_policy)) | ||
2650 | return -EINVAL; | 2693 | return -EINVAL; |
2651 | 2694 | ||
2652 | if (!rdev->ops->set_mesh_params) | ||
2653 | return -EOPNOTSUPP; | ||
2654 | |||
2655 | /* This makes sure that there aren't more than 32 mesh config | 2695 | /* This makes sure that there aren't more than 32 mesh config |
2656 | * parameters (otherwise our bitfield scheme would not work.) */ | 2696 | * parameters (otherwise our bitfield scheme would not work.) */ |
2657 | BUILD_BUG_ON(NL80211_MESHCONF_ATTR_MAX > 32); | 2697 | BUILD_BUG_ON(NL80211_MESHCONF_ATTR_MAX > 32); |
2658 | 2698 | ||
2659 | /* Fill in the params struct */ | 2699 | /* Fill in the params struct */ |
2660 | mask = 0; | ||
2661 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, | 2700 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, |
2662 | mask, NL80211_MESHCONF_RETRY_TIMEOUT, nla_get_u16); | 2701 | mask, NL80211_MESHCONF_RETRY_TIMEOUT, nla_get_u16); |
2663 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, | 2702 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, |
@@ -2670,6 +2709,8 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) | |||
2670 | mask, NL80211_MESHCONF_MAX_RETRIES, nla_get_u8); | 2709 | mask, NL80211_MESHCONF_MAX_RETRIES, nla_get_u8); |
2671 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, | 2710 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, |
2672 | mask, NL80211_MESHCONF_TTL, nla_get_u8); | 2711 | mask, NL80211_MESHCONF_TTL, nla_get_u8); |
2712 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, element_ttl, | ||
2713 | mask, NL80211_MESHCONF_ELEMENT_TTL, nla_get_u8); | ||
2673 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, | 2714 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, |
2674 | mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS, nla_get_u8); | 2715 | mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS, nla_get_u8); |
2675 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, | 2716 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, |
@@ -2695,11 +2736,45 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) | |||
2695 | NL80211_MESHCONF_HWMP_ROOTMODE, | 2736 | NL80211_MESHCONF_HWMP_ROOTMODE, |
2696 | nla_get_u8); | 2737 | nla_get_u8); |
2697 | 2738 | ||
2698 | /* Apply changes */ | 2739 | if (mask_out) |
2699 | return rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask); | 2740 | *mask_out = mask; |
2700 | } | 2741 | return 0; |
2701 | 2742 | ||
2702 | #undef FILL_IN_MESH_PARAM_IF_SET | 2743 | #undef FILL_IN_MESH_PARAM_IF_SET |
2744 | } | ||
2745 | |||
2746 | static int nl80211_update_mesh_params(struct sk_buff *skb, | ||
2747 | struct genl_info *info) | ||
2748 | { | ||
2749 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
2750 | struct net_device *dev = info->user_ptr[1]; | ||
2751 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
2752 | struct mesh_config cfg; | ||
2753 | u32 mask; | ||
2754 | int err; | ||
2755 | |||
2756 | if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) | ||
2757 | return -EOPNOTSUPP; | ||
2758 | |||
2759 | if (!rdev->ops->update_mesh_params) | ||
2760 | return -EOPNOTSUPP; | ||
2761 | |||
2762 | err = nl80211_parse_mesh_params(info, &cfg, &mask); | ||
2763 | if (err) | ||
2764 | return err; | ||
2765 | |||
2766 | wdev_lock(wdev); | ||
2767 | if (!wdev->mesh_id_len) | ||
2768 | err = -ENOLINK; | ||
2769 | |||
2770 | if (!err) | ||
2771 | err = rdev->ops->update_mesh_params(&rdev->wiphy, dev, | ||
2772 | mask, &cfg); | ||
2773 | |||
2774 | wdev_unlock(wdev); | ||
2775 | |||
2776 | return err; | ||
2777 | } | ||
2703 | 2778 | ||
2704 | static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | 2779 | static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) |
2705 | { | 2780 | { |
@@ -4482,6 +4557,41 @@ out: | |||
4482 | return err; | 4557 | return err; |
4483 | } | 4558 | } |
4484 | 4559 | ||
4560 | static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info) | ||
4561 | { | ||
4562 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
4563 | struct net_device *dev = info->user_ptr[1]; | ||
4564 | struct mesh_config cfg; | ||
4565 | int err; | ||
4566 | |||
4567 | /* start with default */ | ||
4568 | memcpy(&cfg, &default_mesh_config, sizeof(cfg)); | ||
4569 | |||
4570 | if (info->attrs[NL80211_ATTR_MESH_PARAMS]) { | ||
4571 | /* and parse parameters if given */ | ||
4572 | err = nl80211_parse_mesh_params(info, &cfg, NULL); | ||
4573 | if (err) | ||
4574 | return err; | ||
4575 | } | ||
4576 | |||
4577 | if (!info->attrs[NL80211_ATTR_MESH_ID] || | ||
4578 | !nla_len(info->attrs[NL80211_ATTR_MESH_ID])) | ||
4579 | return -EINVAL; | ||
4580 | |||
4581 | return cfg80211_join_mesh(rdev, dev, | ||
4582 | nla_data(info->attrs[NL80211_ATTR_MESH_ID]), | ||
4583 | nla_len(info->attrs[NL80211_ATTR_MESH_ID]), | ||
4584 | &cfg); | ||
4585 | } | ||
4586 | |||
4587 | static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info) | ||
4588 | { | ||
4589 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
4590 | struct net_device *dev = info->user_ptr[1]; | ||
4591 | |||
4592 | return cfg80211_leave_mesh(rdev, dev); | ||
4593 | } | ||
4594 | |||
4485 | #define NL80211_FLAG_NEED_WIPHY 0x01 | 4595 | #define NL80211_FLAG_NEED_WIPHY 0x01 |
4486 | #define NL80211_FLAG_NEED_NETDEV 0x02 | 4596 | #define NL80211_FLAG_NEED_NETDEV 0x02 |
4487 | #define NL80211_FLAG_NEED_RTNL 0x04 | 4597 | #define NL80211_FLAG_NEED_RTNL 0x04 |
@@ -4746,10 +4856,10 @@ static struct genl_ops nl80211_ops[] = { | |||
4746 | }, | 4856 | }, |
4747 | { | 4857 | { |
4748 | .cmd = NL80211_CMD_SET_MESH_PARAMS, | 4858 | .cmd = NL80211_CMD_SET_MESH_PARAMS, |
4749 | .doit = nl80211_set_mesh_params, | 4859 | .doit = nl80211_update_mesh_params, |
4750 | .policy = nl80211_policy, | 4860 | .policy = nl80211_policy, |
4751 | .flags = GENL_ADMIN_PERM, | 4861 | .flags = GENL_ADMIN_PERM, |
4752 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | 4862 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | |
4753 | NL80211_FLAG_NEED_RTNL, | 4863 | NL80211_FLAG_NEED_RTNL, |
4754 | }, | 4864 | }, |
4755 | { | 4865 | { |
@@ -4964,6 +5074,22 @@ static struct genl_ops nl80211_ops[] = { | |||
4964 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | 5074 | .internal_flags = NL80211_FLAG_NEED_NETDEV | |
4965 | NL80211_FLAG_NEED_RTNL, | 5075 | NL80211_FLAG_NEED_RTNL, |
4966 | }, | 5076 | }, |
5077 | { | ||
5078 | .cmd = NL80211_CMD_JOIN_MESH, | ||
5079 | .doit = nl80211_join_mesh, | ||
5080 | .policy = nl80211_policy, | ||
5081 | .flags = GENL_ADMIN_PERM, | ||
5082 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
5083 | NL80211_FLAG_NEED_RTNL, | ||
5084 | }, | ||
5085 | { | ||
5086 | .cmd = NL80211_CMD_LEAVE_MESH, | ||
5087 | .doit = nl80211_leave_mesh, | ||
5088 | .policy = nl80211_policy, | ||
5089 | .flags = GENL_ADMIN_PERM, | ||
5090 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
5091 | NL80211_FLAG_NEED_RTNL, | ||
5092 | }, | ||
4967 | }; | 5093 | }; |
4968 | 5094 | ||
4969 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 5095 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
diff --git a/net/wireless/util.c b/net/wireless/util.c index fee020b15a4e..4de624ca4c63 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -792,6 +792,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
792 | 792 | ||
793 | if (ntype != otype) { | 793 | if (ntype != otype) { |
794 | dev->ieee80211_ptr->use_4addr = false; | 794 | dev->ieee80211_ptr->use_4addr = false; |
795 | dev->ieee80211_ptr->mesh_id_up_len = 0; | ||
795 | 796 | ||
796 | switch (otype) { | 797 | switch (otype) { |
797 | case NL80211_IFTYPE_ADHOC: | 798 | case NL80211_IFTYPE_ADHOC: |