aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
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/wireless
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/wireless')
-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
6 files changed, 284 insertions, 24 deletions
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
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 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);
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 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
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 c8d4d53fc450..56508d40c740 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 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: