aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
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 d34c7c3dd762..68329d713c02 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 e7c880725639..72499fe5fc36 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 96e27f1e79fb..f0f11bb794af 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 107a0cbe52ac..2de69766c6aa 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 0d3234875ac5..63e1188d5062 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 182942eeac4d..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
@@ -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 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: