aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2010-12-03 03:20:44 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-12-06 16:01:29 -0500
commit29cbe68c516a48a9a88b3226878570c6cbd83c02 (patch)
tree4774f8a3a244236234a521baa4d1ae5b3e1494ba /net
parentbd90fdcc5fbd99a2a778999610420cf793bd1be2 (diff)
cfg80211/mac80211: add mesh join/leave commands
Instead of tying mesh activity to interface up, add join and leave commands for mesh. Since we must be backward compatible, let cfg80211 handle joining a mesh if a mesh ID was pre-configured when the device goes up. Note that this therefore must modify mac80211 as well since mac80211 needs to lose the logic to start the mesh on interface up. We now allow querying mesh parameters before the mesh is connected, which simply returns defaults. Setting them (internally renamed to "update") is only allowed while connected. Specify them with the new mesh join command instead where needed. In mac80211, beaconing must now also follow the mesh enabled/not enabled state, which is done by testing the mesh ID. Signed-off-by: Javier Cardona <javier@cozybit.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/cfg.c39
-rw-r--r--net/mac80211/ieee80211_i.h13
-rw-r--r--net/mac80211/iface.c14
-rw-r--r--net/mac80211/main.c3
-rw-r--r--net/mac80211/mesh.c26
-rw-r--r--net/mac80211/mesh.h25
-rw-r--r--net/wireless/Makefile2
-rw-r--r--net/wireless/core.c15
-rw-r--r--net/wireless/core.h13
-rw-r--r--net/wireless/mesh.c140
-rw-r--r--net/wireless/nl80211.c137
-rw-r--r--net/wireless/util.c1
12 files changed, 322 insertions, 106 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index d34c7c3dd76..68329d713c0 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -60,11 +60,6 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
60 if (ret) 60 if (ret)
61 return ret; 61 return ret;
62 62
63 if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len)
64 ieee80211_sdata_set_mesh_id(sdata,
65 params->mesh_id_len,
66 params->mesh_id);
67
68 if (type == NL80211_IFTYPE_AP_VLAN && 63 if (type == NL80211_IFTYPE_AP_VLAN &&
69 params && params->use_4addr == 0) 64 params && params->use_4addr == 0)
70 rcu_assign_pointer(sdata->u.vlan.sta, NULL); 65 rcu_assign_pointer(sdata->u.vlan.sta, NULL);
@@ -1003,9 +998,9 @@ static inline bool _chg_mesh_attr(enum nl80211_meshconf_params parm, u32 mask)
1003 return (mask >> (parm-1)) & 0x1; 998 return (mask >> (parm-1)) & 0x1;
1004} 999}
1005 1000
1006static int ieee80211_set_mesh_params(struct wiphy *wiphy, 1001static int ieee80211_update_mesh_params(struct wiphy *wiphy,
1007 struct net_device *dev, 1002 struct net_device *dev, u32 mask,
1008 const struct mesh_config *nconf, u32 mask) 1003 const struct mesh_config *nconf)
1009{ 1004{
1010 struct mesh_config *conf; 1005 struct mesh_config *conf;
1011 struct ieee80211_sub_if_data *sdata; 1006 struct ieee80211_sub_if_data *sdata;
@@ -1056,6 +1051,30 @@ static int ieee80211_set_mesh_params(struct wiphy *wiphy,
1056 return 0; 1051 return 0;
1057} 1052}
1058 1053
1054static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev,
1055 const struct mesh_config *conf,
1056 const struct mesh_setup *setup)
1057{
1058 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1059 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
1060
1061 memcpy(&sdata->u.mesh.mshcfg, conf, sizeof(struct mesh_config));
1062 ifmsh->mesh_id_len = setup->mesh_id_len;
1063 memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len);
1064
1065 ieee80211_start_mesh(sdata);
1066
1067 return 0;
1068}
1069
1070static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev)
1071{
1072 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1073
1074 ieee80211_stop_mesh(sdata);
1075
1076 return 0;
1077}
1059#endif 1078#endif
1060 1079
1061static int ieee80211_change_bss(struct wiphy *wiphy, 1080static int ieee80211_change_bss(struct wiphy *wiphy,
@@ -1760,8 +1779,10 @@ struct cfg80211_ops mac80211_config_ops = {
1760 .change_mpath = ieee80211_change_mpath, 1779 .change_mpath = ieee80211_change_mpath,
1761 .get_mpath = ieee80211_get_mpath, 1780 .get_mpath = ieee80211_get_mpath,
1762 .dump_mpath = ieee80211_dump_mpath, 1781 .dump_mpath = ieee80211_dump_mpath,
1763 .set_mesh_params = ieee80211_set_mesh_params, 1782 .update_mesh_params = ieee80211_update_mesh_params,
1764 .get_mesh_params = ieee80211_get_mesh_params, 1783 .get_mesh_params = ieee80211_get_mesh_params,
1784 .join_mesh = ieee80211_join_mesh,
1785 .leave_mesh = ieee80211_leave_mesh,
1765#endif 1786#endif
1766 .change_bss = ieee80211_change_bss, 1787 .change_bss = ieee80211_change_bss,
1767 .set_txq_params = ieee80211_set_txq_params, 1788 .set_txq_params = ieee80211_set_txq_params,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index e7c88072563..72499fe5fc3 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -609,19 +609,6 @@ struct ieee80211_sub_if_data *vif_to_sdata(struct ieee80211_vif *p)
609 return container_of(p, struct ieee80211_sub_if_data, vif); 609 return container_of(p, struct ieee80211_sub_if_data, vif);
610} 610}
611 611
612static inline void
613ieee80211_sdata_set_mesh_id(struct ieee80211_sub_if_data *sdata,
614 u8 mesh_id_len, u8 *mesh_id)
615{
616#ifdef CONFIG_MAC80211_MESH
617 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
618 ifmsh->mesh_id_len = mesh_id_len;
619 memcpy(ifmsh->mesh_id, mesh_id, mesh_id_len);
620#else
621 WARN_ON(1);
622#endif
623}
624
625enum sdata_queue_type { 612enum sdata_queue_type {
626 IEEE80211_SDATA_QUEUE_TYPE_FRAME = 0, 613 IEEE80211_SDATA_QUEUE_TYPE_FRAME = 0,
627 IEEE80211_SDATA_QUEUE_AGG_START = 1, 614 IEEE80211_SDATA_QUEUE_AGG_START = 1,
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 96e27f1e79f..f0f11bb794a 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -268,9 +268,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
268 goto err_stop; 268 goto err_stop;
269 } 269 }
270 270
271 if (ieee80211_vif_is_mesh(&sdata->vif)) { 271 if (sdata->vif.type == NL80211_IFTYPE_AP) {
272 ieee80211_start_mesh(sdata);
273 } else if (sdata->vif.type == NL80211_IFTYPE_AP) {
274 local->fif_pspoll++; 272 local->fif_pspoll++;
275 local->fif_probe_req++; 273 local->fif_probe_req++;
276 274
@@ -495,10 +493,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
495 ieee80211_adjust_monitor_flags(sdata, -1); 493 ieee80211_adjust_monitor_flags(sdata, -1);
496 ieee80211_configure_filter(local); 494 ieee80211_configure_filter(local);
497 break; 495 break;
498 case NL80211_IFTYPE_MESH_POINT:
499 if (ieee80211_vif_is_mesh(&sdata->vif))
500 ieee80211_stop_mesh(sdata);
501 /* fall through */
502 default: 496 default:
503 flush_work(&sdata->work); 497 flush_work(&sdata->work);
504 /* 498 /*
@@ -1188,12 +1182,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
1188 if (ret) 1182 if (ret)
1189 goto fail; 1183 goto fail;
1190 1184
1191 if (ieee80211_vif_is_mesh(&sdata->vif) &&
1192 params && params->mesh_id_len)
1193 ieee80211_sdata_set_mesh_id(sdata,
1194 params->mesh_id_len,
1195 params->mesh_id);
1196
1197 mutex_lock(&local->iflist_mtx); 1185 mutex_lock(&local->iflist_mtx);
1198 list_add_tail_rcu(&sdata->list, &local->interfaces); 1186 list_add_tail_rcu(&sdata->list, &local->interfaces);
1199 mutex_unlock(&local->iflist_mtx); 1187 mutex_unlock(&local->iflist_mtx);
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 107a0cbe52a..2de69766c6a 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -246,7 +246,8 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
246 !!sdata->u.ibss.presp; 246 !!sdata->u.ibss.presp;
247 break; 247 break;
248 case NL80211_IFTYPE_MESH_POINT: 248 case NL80211_IFTYPE_MESH_POINT:
249 sdata->vif.bss_conf.enable_beacon = true; 249 sdata->vif.bss_conf.enable_beacon =
250 !!sdata->u.mesh.mesh_id_len;
250 break; 251 break;
251 default: 252 default:
252 /* not reached */ 253 /* not reached */
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 0d3234875ac..63e1188d506 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -530,6 +530,11 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
530void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) 530void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
531{ 531{
532 struct ieee80211_local *local = sdata->local; 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);
533 538
534 del_timer_sync(&sdata->u.mesh.housekeeping_timer); 539 del_timer_sync(&sdata->u.mesh.housekeeping_timer);
535 del_timer_sync(&sdata->u.mesh.mesh_path_root_timer); 540 del_timer_sync(&sdata->u.mesh.mesh_path_root_timer);
@@ -674,27 +679,6 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
674 ieee80211_mesh_housekeeping_timer, 679 ieee80211_mesh_housekeeping_timer,
675 (unsigned long) sdata); 680 (unsigned long) sdata);
676 681
677 ifmsh->mshcfg.dot11MeshRetryTimeout = MESH_RET_T;
678 ifmsh->mshcfg.dot11MeshConfirmTimeout = MESH_CONF_T;
679 ifmsh->mshcfg.dot11MeshHoldingTimeout = MESH_HOLD_T;
680 ifmsh->mshcfg.dot11MeshMaxRetries = MESH_MAX_RETR;
681 ifmsh->mshcfg.dot11MeshTTL = MESH_TTL;
682 ifmsh->mshcfg.element_ttl = MESH_DEFAULT_ELEMENT_TTL;
683 ifmsh->mshcfg.auto_open_plinks = true;
684 ifmsh->mshcfg.dot11MeshMaxPeerLinks =
685 MESH_MAX_ESTAB_PLINKS;
686 ifmsh->mshcfg.dot11MeshHWMPactivePathTimeout =
687 MESH_PATH_TIMEOUT;
688 ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval =
689 MESH_PREQ_MIN_INT;
690 ifmsh->mshcfg.dot11MeshHWMPnetDiameterTraversalTime =
691 MESH_DIAM_TRAVERSAL_TIME;
692 ifmsh->mshcfg.dot11MeshHWMPmaxPREQretries =
693 MESH_MAX_PREQ_RETRIES;
694 ifmsh->mshcfg.path_refresh_time =
695 MESH_PATH_REFRESH_TIME;
696 ifmsh->mshcfg.min_discovery_timeout =
697 MESH_MIN_DISCOVERY_TIMEOUT;
698 ifmsh->accepting_plinks = true; 682 ifmsh->accepting_plinks = true;
699 ifmsh->preq_id = 0; 683 ifmsh->preq_id = 0;
700 ifmsh->sn = 0; 684 ifmsh->sn = 0;
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 182942eeac4..039d7fa0af7 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
@@ -216,8 +193,6 @@ struct mesh_rmc {
216#define PERR_RCODE_NO_ROUTE 12 193#define PERR_RCODE_NO_ROUTE 12
217#define PERR_RCODE_DEST_UNREACH 13 194#define PERR_RCODE_DEST_UNREACH 13
218 195
219#define MESH_DEFAULT_ELEMENT_TTL 31
220
221/* Public interfaces */ 196/* Public interfaces */
222/* Various */ 197/* Various */
223int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, 198int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index e77e508126f..55a28ab21db 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -10,7 +10,7 @@ obj-$(CONFIG_WEXT_SPY) += wext-spy.o
10obj-$(CONFIG_WEXT_PRIV) += wext-priv.o 10obj-$(CONFIG_WEXT_PRIV) += wext-priv.o
11 11
12cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o 12cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o
13cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o 13cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o
14cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o 14cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
15cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o 15cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o
16cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o 16cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 630bcf0a2f0..79772fcc37b 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 ee80ad8dc65..743203bb61a 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);
285int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, 285int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
286 struct wireless_dev *wdev); 286 struct wireless_dev *wdev);
287 287
288/* mesh */
289extern const struct mesh_config default_mesh_config;
290int __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);
294int 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);
298int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
299 struct net_device *dev);
300
288/* MLME */ 301/* MLME */
289int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, 302int __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 00000000000..e0b9747fe50
--- /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
36const 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
54int __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
91int 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
106static 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
129int 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 c8d4d53fc45..56508d40c74 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -661,13 +661,14 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
661 CMD(add_beacon, NEW_BEACON); 661 CMD(add_beacon, NEW_BEACON);
662 CMD(add_station, NEW_STATION); 662 CMD(add_station, NEW_STATION);
663 CMD(add_mpath, NEW_MPATH); 663 CMD(add_mpath, NEW_MPATH);
664 CMD(set_mesh_params, SET_MESH_PARAMS); 664 CMD(update_mesh_params, SET_MESH_PARAMS);
665 CMD(change_bss, SET_BSS); 665 CMD(change_bss, SET_BSS);
666 CMD(auth, AUTHENTICATE); 666 CMD(auth, AUTHENTICATE);
667 CMD(assoc, ASSOCIATE); 667 CMD(assoc, ASSOCIATE);
668 CMD(deauth, DEAUTHENTICATE); 668 CMD(deauth, DEAUTHENTICATE);
669 CMD(disassoc, DISASSOCIATE); 669 CMD(disassoc, DISASSOCIATE);
670 CMD(join_ibss, JOIN_IBSS); 670 CMD(join_ibss, JOIN_IBSS);
671 CMD(join_mesh, JOIN_MESH);
671 CMD(set_pmksa, SET_PMKSA); 672 CMD(set_pmksa, SET_PMKSA);
672 CMD(del_pmksa, DEL_PMKSA); 673 CMD(del_pmksa, DEL_PMKSA);
673 CMD(flush_pmksa, FLUSH_PMKSA); 674 CMD(flush_pmksa, FLUSH_PMKSA);
@@ -1324,11 +1325,21 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
1324 } 1325 }
1325 1326
1326 if (info->attrs[NL80211_ATTR_MESH_ID]) { 1327 if (info->attrs[NL80211_ATTR_MESH_ID]) {
1328 struct wireless_dev *wdev = dev->ieee80211_ptr;
1329
1327 if (ntype != NL80211_IFTYPE_MESH_POINT) 1330 if (ntype != NL80211_IFTYPE_MESH_POINT)
1328 return -EINVAL; 1331 return -EINVAL;
1329 params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); 1332 if (netif_running(dev))
1330 params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); 1333 return -EBUSY;
1331 change = true; 1334
1335 wdev_lock(wdev);
1336 BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
1337 IEEE80211_MAX_MESH_ID_LEN);
1338 wdev->mesh_id_up_len =
1339 nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
1340 memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
1341 wdev->mesh_id_up_len);
1342 wdev_unlock(wdev);
1332 } 1343 }
1333 1344
1334 if (info->attrs[NL80211_ATTR_4ADDR]) { 1345 if (info->attrs[NL80211_ATTR_4ADDR]) {
@@ -1388,12 +1399,6 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
1388 !(rdev->wiphy.interface_modes & (1 << type))) 1399 !(rdev->wiphy.interface_modes & (1 << type)))
1389 return -EOPNOTSUPP; 1400 return -EOPNOTSUPP;
1390 1401
1391 if (type == NL80211_IFTYPE_MESH_POINT &&
1392 info->attrs[NL80211_ATTR_MESH_ID]) {
1393 params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
1394 params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
1395 }
1396
1397 if (info->attrs[NL80211_ATTR_4ADDR]) { 1402 if (info->attrs[NL80211_ATTR_4ADDR]) {
1398 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); 1403 params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
1399 err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type); 1404 err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type);
@@ -1410,6 +1415,20 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
1410 if (IS_ERR(dev)) 1415 if (IS_ERR(dev))
1411 return PTR_ERR(dev); 1416 return PTR_ERR(dev);
1412 1417
1418 if (type == NL80211_IFTYPE_MESH_POINT &&
1419 info->attrs[NL80211_ATTR_MESH_ID]) {
1420 struct wireless_dev *wdev = dev->ieee80211_ptr;
1421
1422 wdev_lock(wdev);
1423 BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
1424 IEEE80211_MAX_MESH_ID_LEN);
1425 wdev->mesh_id_up_len =
1426 nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
1427 memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
1428 wdev->mesh_id_up_len);
1429 wdev_unlock(wdev);
1430 }
1431
1413 return 0; 1432 return 0;
1414} 1433}
1415 1434
@@ -2543,21 +2562,32 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
2543} 2562}
2544 2563
2545static int nl80211_get_mesh_params(struct sk_buff *skb, 2564static int nl80211_get_mesh_params(struct sk_buff *skb,
2546 struct genl_info *info) 2565 struct genl_info *info)
2547{ 2566{
2548 struct cfg80211_registered_device *rdev = info->user_ptr[0]; 2567 struct cfg80211_registered_device *rdev = info->user_ptr[0];
2549 struct mesh_config cur_params;
2550 int err;
2551 struct net_device *dev = info->user_ptr[1]; 2568 struct net_device *dev = info->user_ptr[1];
2569 struct wireless_dev *wdev = dev->ieee80211_ptr;
2570 struct mesh_config cur_params;
2571 int err = 0;
2552 void *hdr; 2572 void *hdr;
2553 struct nlattr *pinfoattr; 2573 struct nlattr *pinfoattr;
2554 struct sk_buff *msg; 2574 struct sk_buff *msg;
2555 2575
2576 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
2577 return -EOPNOTSUPP;
2578
2556 if (!rdev->ops->get_mesh_params) 2579 if (!rdev->ops->get_mesh_params)
2557 return -EOPNOTSUPP; 2580 return -EOPNOTSUPP;
2558 2581
2559 /* Get the mesh params */ 2582 wdev_lock(wdev);
2560 err = rdev->ops->get_mesh_params(&rdev->wiphy, dev, &cur_params); 2583 /* If not connected, get default parameters */
2584 if (!wdev->mesh_id_len)
2585 memcpy(&cur_params, &default_mesh_config, sizeof(cur_params));
2586 else
2587 err = rdev->ops->get_mesh_params(&rdev->wiphy, dev,
2588 &cur_params);
2589 wdev_unlock(wdev);
2590
2561 if (err) 2591 if (err)
2562 return err; 2592 return err;
2563 2593
@@ -2705,23 +2735,37 @@ do {\
2705#undef FILL_IN_MESH_PARAM_IF_SET 2735#undef FILL_IN_MESH_PARAM_IF_SET
2706} 2736}
2707 2737
2708static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) 2738static int nl80211_update_mesh_params(struct sk_buff *skb,
2739 struct genl_info *info)
2709{ 2740{
2710 struct cfg80211_registered_device *rdev = info->user_ptr[0]; 2741 struct cfg80211_registered_device *rdev = info->user_ptr[0];
2711 struct net_device *dev = info->user_ptr[1]; 2742 struct net_device *dev = info->user_ptr[1];
2743 struct wireless_dev *wdev = dev->ieee80211_ptr;
2712 struct mesh_config cfg; 2744 struct mesh_config cfg;
2713 u32 mask; 2745 u32 mask;
2714 int err; 2746 int err;
2715 2747
2716 if (!rdev->ops->set_mesh_params) 2748 if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
2749 return -EOPNOTSUPP;
2750
2751 if (!rdev->ops->update_mesh_params)
2717 return -EOPNOTSUPP; 2752 return -EOPNOTSUPP;
2718 2753
2719 err = nl80211_parse_mesh_params(info, &cfg, &mask); 2754 err = nl80211_parse_mesh_params(info, &cfg, &mask);
2720 if (err) 2755 if (err)
2721 return err; 2756 return err;
2722 2757
2723 /* Apply changes */ 2758 wdev_lock(wdev);
2724 return rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask); 2759 if (!wdev->mesh_id_len)
2760 err = -ENOLINK;
2761
2762 if (!err)
2763 err = rdev->ops->update_mesh_params(&rdev->wiphy, dev,
2764 mask, &cfg);
2765
2766 wdev_unlock(wdev);
2767
2768 return err;
2725} 2769}
2726 2770
2727static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) 2771static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
@@ -4505,6 +4549,41 @@ out:
4505 return err; 4549 return err;
4506} 4550}
4507 4551
4552static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
4553{
4554 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4555 struct net_device *dev = info->user_ptr[1];
4556 struct mesh_config cfg;
4557 int err;
4558
4559 /* start with default */
4560 memcpy(&cfg, &default_mesh_config, sizeof(cfg));
4561
4562 if (info->attrs[NL80211_ATTR_MESH_PARAMS]) {
4563 /* and parse parameters if given */
4564 err = nl80211_parse_mesh_params(info, &cfg, NULL);
4565 if (err)
4566 return err;
4567 }
4568
4569 if (!info->attrs[NL80211_ATTR_MESH_ID] ||
4570 !nla_len(info->attrs[NL80211_ATTR_MESH_ID]))
4571 return -EINVAL;
4572
4573 return cfg80211_join_mesh(rdev, dev,
4574 nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
4575 nla_len(info->attrs[NL80211_ATTR_MESH_ID]),
4576 &cfg);
4577}
4578
4579static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info)
4580{
4581 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4582 struct net_device *dev = info->user_ptr[1];
4583
4584 return cfg80211_leave_mesh(rdev, dev);
4585}
4586
4508#define NL80211_FLAG_NEED_WIPHY 0x01 4587#define NL80211_FLAG_NEED_WIPHY 0x01
4509#define NL80211_FLAG_NEED_NETDEV 0x02 4588#define NL80211_FLAG_NEED_NETDEV 0x02
4510#define NL80211_FLAG_NEED_RTNL 0x04 4589#define NL80211_FLAG_NEED_RTNL 0x04
@@ -4769,10 +4848,10 @@ static struct genl_ops nl80211_ops[] = {
4769 }, 4848 },
4770 { 4849 {
4771 .cmd = NL80211_CMD_SET_MESH_PARAMS, 4850 .cmd = NL80211_CMD_SET_MESH_PARAMS,
4772 .doit = nl80211_set_mesh_params, 4851 .doit = nl80211_update_mesh_params,
4773 .policy = nl80211_policy, 4852 .policy = nl80211_policy,
4774 .flags = GENL_ADMIN_PERM, 4853 .flags = GENL_ADMIN_PERM,
4775 .internal_flags = NL80211_FLAG_NEED_NETDEV | 4854 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
4776 NL80211_FLAG_NEED_RTNL, 4855 NL80211_FLAG_NEED_RTNL,
4777 }, 4856 },
4778 { 4857 {
@@ -4987,6 +5066,22 @@ static struct genl_ops nl80211_ops[] = {
4987 .internal_flags = NL80211_FLAG_NEED_NETDEV | 5066 .internal_flags = NL80211_FLAG_NEED_NETDEV |
4988 NL80211_FLAG_NEED_RTNL, 5067 NL80211_FLAG_NEED_RTNL,
4989 }, 5068 },
5069 {
5070 .cmd = NL80211_CMD_JOIN_MESH,
5071 .doit = nl80211_join_mesh,
5072 .policy = nl80211_policy,
5073 .flags = GENL_ADMIN_PERM,
5074 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
5075 NL80211_FLAG_NEED_RTNL,
5076 },
5077 {
5078 .cmd = NL80211_CMD_LEAVE_MESH,
5079 .doit = nl80211_leave_mesh,
5080 .policy = nl80211_policy,
5081 .flags = GENL_ADMIN_PERM,
5082 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
5083 NL80211_FLAG_NEED_RTNL,
5084 },
4990}; 5085};
4991 5086
4992static struct genl_multicast_group nl80211_mlme_mcgrp = { 5087static struct genl_multicast_group nl80211_mlme_mcgrp = {
diff --git a/net/wireless/util.c b/net/wireless/util.c
index fee020b15a4..4de624ca4c6 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: