aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/ieee80211.h25
-rw-r--r--include/linux/nl80211.h47
-rw-r--r--include/net/cfg80211.h8
-rw-r--r--net/mac80211/cfg.c39
-rw-r--r--net/mac80211/ieee80211_i.h4
-rw-r--r--net/mac80211/mesh.c7
-rw-r--r--net/mac80211/mesh_plink.c3
-rw-r--r--net/mac80211/tx.c3
-rw-r--r--net/wireless/core.c22
-rw-r--r--net/wireless/core.h5
-rw-r--r--net/wireless/mesh.c24
-rw-r--r--net/wireless/nl80211.c63
12 files changed, 214 insertions, 36 deletions
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 7f2354534242..cd681681d211 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1291,6 +1291,31 @@ enum ieee80211_key_len {
1291 WLAN_KEY_LEN_AES_CMAC = 16, 1291 WLAN_KEY_LEN_AES_CMAC = 16,
1292}; 1292};
1293 1293
1294/**
1295 * enum - mesh path selection protocol identifier
1296 *
1297 * @IEEE80211_PATH_PROTOCOL_HWMP: the default path selection protocol
1298 * @IEEE80211_PATH_PROTOCOL_VENDOR: a vendor specific protocol that will
1299 * be specified in a vendor specific information element
1300 */
1301enum {
1302 IEEE80211_PATH_PROTOCOL_HWMP = 0,
1303 IEEE80211_PATH_PROTOCOL_VENDOR = 255,
1304};
1305
1306/**
1307 * enum - mesh path selection metric identifier
1308 *
1309 * @IEEE80211_PATH_METRIC_AIRTIME: the default path selection metric
1310 * @IEEE80211_PATH_METRIC_VENDOR: a vendor specific metric that will be
1311 * specified in a vendor specific information element
1312 */
1313enum {
1314 IEEE80211_PATH_METRIC_AIRTIME = 0,
1315 IEEE80211_PATH_METRIC_VENDOR = 255,
1316};
1317
1318
1294/* 1319/*
1295 * IEEE 802.11-2007 7.3.2.9 Country information element 1320 * IEEE 802.11-2007 7.3.2.9 Country information element
1296 * 1321 *
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 11a1de67b618..69eaccac78c4 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -872,6 +872,9 @@ enum nl80211_commands {
872 * attributes, specifying what a key should be set as default as. 872 * attributes, specifying what a key should be set as default as.
873 * See &enum nl80211_key_default_types. 873 * See &enum nl80211_key_default_types.
874 * 874 *
875 * @NL80211_ATTR_MESH_SETUP: Optional mesh setup parameters. These cannot be
876 * changed once the mesh is active.
877 *
875 * @NL80211_ATTR_MAX: highest attribute number currently defined 878 * @NL80211_ATTR_MAX: highest attribute number currently defined
876 * @__NL80211_ATTR_AFTER_LAST: internal use 879 * @__NL80211_ATTR_AFTER_LAST: internal use
877 */ 880 */
@@ -1054,6 +1057,8 @@ enum nl80211_attrs {
1054 1057
1055 NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION, 1058 NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION,
1056 1059
1060 NL80211_ATTR_MESH_SETUP,
1061
1057 /* add attributes here, update the policy in nl80211.c */ 1062 /* add attributes here, update the policy in nl80211.c */
1058 1063
1059 __NL80211_ATTR_AFTER_LAST, 1064 __NL80211_ATTR_AFTER_LAST,
@@ -1564,7 +1569,8 @@ enum nl80211_mntr_flags {
1564/** 1569/**
1565 * enum nl80211_meshconf_params - mesh configuration parameters 1570 * enum nl80211_meshconf_params - mesh configuration parameters
1566 * 1571 *
1567 * Mesh configuration parameters 1572 * Mesh configuration parameters. These can be changed while the mesh is
1573 * active.
1568 * 1574 *
1569 * @__NL80211_MESHCONF_INVALID: internal use 1575 * @__NL80211_MESHCONF_INVALID: internal use
1570 * 1576 *
@@ -1587,9 +1593,6 @@ enum nl80211_mntr_flags {
1587 * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh 1593 * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh
1588 * point. 1594 * point.
1589 * 1595 *
1590 * @NL80211_MESHCONF_ELEMENT_TTL: specifies the value of TTL field set at a
1591 * source mesh point for path selection elements.
1592 *
1593 * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically 1596 * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically
1594 * open peer links when we detect compatible mesh peers. 1597 * open peer links when we detect compatible mesh peers.
1595 * 1598 *
@@ -1616,6 +1619,9 @@ enum nl80211_mntr_flags {
1616 * 1619 *
1617 * @NL80211_MESHCONF_ROOTMODE: whether root mode is enabled or not 1620 * @NL80211_MESHCONF_ROOTMODE: whether root mode is enabled or not
1618 * 1621 *
1622 * @NL80211_MESHCONF_ELEMENT_TTL: specifies the value of TTL field set at a
1623 * source mesh point for path selection elements.
1624 *
1619 * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute 1625 * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute
1620 * 1626 *
1621 * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use 1627 * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
@@ -1644,6 +1650,39 @@ enum nl80211_meshconf_params {
1644}; 1650};
1645 1651
1646/** 1652/**
1653 * enum nl80211_mesh_setup_params - mesh setup parameters
1654 *
1655 * Mesh setup parameters. These are used to start/join a mesh and cannot be
1656 * changed while the mesh is active.
1657 *
1658 * @__NL80211_MESH_SETUP_INVALID: Internal use
1659 *
1660 * @NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL: Enable this option to use a
1661 * vendor specific path selection algorithm or disable it to use the default
1662 * HWMP.
1663 *
1664 * @NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC: Enable this option to use a
1665 * vendor specific path metric or disable it to use the default Airtime
1666 * metric.
1667 *
1668 * @NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE: A vendor specific information
1669 * element that vendors will use to identify the path selection methods and
1670 * metrics in use.
1671 *
1672 * @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use
1673 */
1674enum nl80211_mesh_setup_params {
1675 __NL80211_MESH_SETUP_INVALID,
1676 NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL,
1677 NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC,
1678 NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE,
1679
1680 /* keep last */
1681 __NL80211_MESH_SETUP_ATTR_AFTER_LAST,
1682 NL80211_MESH_SETUP_ATTR_MAX = __NL80211_MESH_SETUP_ATTR_AFTER_LAST - 1
1683};
1684
1685/**
1647 * enum nl80211_txq_attr - TX queue parameter attributes 1686 * enum nl80211_txq_attr - TX queue parameter attributes
1648 * @__NL80211_TXQ_ATTR_INVALID: Attribute number 0 is reserved 1687 * @__NL80211_TXQ_ATTR_INVALID: Attribute number 0 is reserved
1649 * @NL80211_TXQ_ATTR_QUEUE: TX queue identifier (NL80211_TXQ_Q_*) 1688 * @NL80211_TXQ_ATTR_QUEUE: TX queue identifier (NL80211_TXQ_Q_*)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 7283496c2d05..924d60366233 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -649,12 +649,20 @@ struct mesh_config {
649 * struct mesh_setup - 802.11s mesh setup configuration 649 * struct mesh_setup - 802.11s mesh setup configuration
650 * @mesh_id: the mesh ID 650 * @mesh_id: the mesh ID
651 * @mesh_id_len: length of the mesh ID, at least 1 and at most 32 bytes 651 * @mesh_id_len: length of the mesh ID, at least 1 and at most 32 bytes
652 * @path_sel_proto: which path selection protocol to use
653 * @path_metric: which metric to use
654 * @vendor_ie: vendor information elements (optional)
655 * @vendor_ie_len: length of vendor information elements
652 * 656 *
653 * These parameters are fixed when the mesh is created. 657 * These parameters are fixed when the mesh is created.
654 */ 658 */
655struct mesh_setup { 659struct mesh_setup {
656 const u8 *mesh_id; 660 const u8 *mesh_id;
657 u8 mesh_id_len; 661 u8 mesh_id_len;
662 u8 path_sel_proto;
663 u8 path_metric;
664 const u8 *vendor_ie;
665 u8 vendor_ie_len;
658}; 666};
659 667
660/** 668/**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 1c94a2ae22ee..ae2c7127a8aa 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1000,6 +1000,36 @@ static inline bool _chg_mesh_attr(enum nl80211_meshconf_params parm, u32 mask)
1000 return (mask >> (parm-1)) & 0x1; 1000 return (mask >> (parm-1)) & 0x1;
1001} 1001}
1002 1002
1003static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh,
1004 const struct mesh_setup *setup)
1005{
1006 u8 *new_ie;
1007 const u8 *old_ie;
1008
1009 /* first allocate the new vendor information element */
1010 new_ie = NULL;
1011 old_ie = ifmsh->vendor_ie;
1012
1013 ifmsh->vendor_ie_len = setup->vendor_ie_len;
1014 if (setup->vendor_ie_len) {
1015 new_ie = kmemdup(setup->vendor_ie, setup->vendor_ie_len,
1016 GFP_KERNEL);
1017 if (!new_ie)
1018 return -ENOMEM;
1019 }
1020
1021 /* now copy the rest of the setup parameters */
1022 ifmsh->mesh_id_len = setup->mesh_id_len;
1023 memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len);
1024 ifmsh->mesh_pp_id = setup->path_sel_proto;
1025 ifmsh->mesh_pm_id = setup->path_metric;
1026 ifmsh->vendor_ie = new_ie;
1027
1028 kfree(old_ie);
1029
1030 return 0;
1031}
1032
1003static int ieee80211_update_mesh_config(struct wiphy *wiphy, 1033static int ieee80211_update_mesh_config(struct wiphy *wiphy,
1004 struct net_device *dev, u32 mask, 1034 struct net_device *dev, u32 mask,
1005 const struct mesh_config *nconf) 1035 const struct mesh_config *nconf)
@@ -1059,11 +1089,12 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev,
1059{ 1089{
1060 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 1090 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1061 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; 1091 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
1092 int err;
1062 1093
1063 memcpy(&sdata->u.mesh.mshcfg, conf, sizeof(struct mesh_config)); 1094 memcpy(&ifmsh->mshcfg, conf, sizeof(struct mesh_config));
1064 ifmsh->mesh_id_len = setup->mesh_id_len; 1095 err = copy_mesh_setup(ifmsh, setup);
1065 memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len); 1096 if (err)
1066 1097 return err;
1067 ieee80211_start_mesh(sdata); 1098 ieee80211_start_mesh(sdata);
1068 1099
1069 return 0; 1100 return 0;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index ce58b2a676e2..eadaa243a3da 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -484,6 +484,8 @@ struct ieee80211_if_mesh {
484 struct mesh_config mshcfg; 484 struct mesh_config mshcfg;
485 u32 mesh_seqnum; 485 u32 mesh_seqnum;
486 bool accepting_plinks; 486 bool accepting_plinks;
487 const u8 *vendor_ie;
488 u8 vendor_ie_len;
487}; 489};
488 490
489#ifdef CONFIG_MAC80211_MESH 491#ifdef CONFIG_MAC80211_MESH
@@ -585,9 +587,7 @@ struct ieee80211_sub_if_data {
585 struct ieee80211_if_vlan vlan; 587 struct ieee80211_if_vlan vlan;
586 struct ieee80211_if_managed mgd; 588 struct ieee80211_if_managed mgd;
587 struct ieee80211_if_ibss ibss; 589 struct ieee80211_if_ibss ibss;
588#ifdef CONFIG_MAC80211_MESH
589 struct ieee80211_if_mesh mesh; 590 struct ieee80211_if_mesh mesh;
590#endif
591 u32 mntr_flags; 591 u32 mntr_flags;
592 } u; 592 } u;
593 593
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 63e1188d5062..c326e009389d 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -287,6 +287,13 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
287 *pos++ |= sdata->u.mesh.accepting_plinks ? 287 *pos++ |= sdata->u.mesh.accepting_plinks ?
288 MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; 288 MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
289 *pos++ = 0x00; 289 *pos++ = 0x00;
290
291 if (sdata->u.mesh.vendor_ie) {
292 int len = sdata->u.mesh.vendor_ie_len;
293 const u8 *data = sdata->u.mesh.vendor_ie;
294 if (skb_tailroom(skb) > len)
295 memcpy(skb_put(skb, len), data, len);
296 }
290} 297}
291 298
292u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, struct mesh_table *tbl) 299u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, struct mesh_table *tbl)
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 1c91f0f3c307..44b53931ba5e 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -160,7 +160,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
160 enum plink_frame_type action, u8 *da, __le16 llid, __le16 plid, 160 enum plink_frame_type action, u8 *da, __le16 llid, __le16 plid,
161 __le16 reason) { 161 __le16 reason) {
162 struct ieee80211_local *local = sdata->local; 162 struct ieee80211_local *local = sdata->local;
163 struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); 163 struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400 +
164 sdata->u.mesh.vendor_ie_len);
164 struct ieee80211_mgmt *mgmt; 165 struct ieee80211_mgmt *mgmt;
165 bool include_plid = false; 166 bool include_plid = false;
166 static const u8 meshpeeringproto[] = { 0x00, 0x0F, 0xAC, 0x2A }; 167 static const u8 meshpeeringproto[] = { 0x00, 0x0F, 0xAC, 0x2A };
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 157bde993ef5..f4b1b624ea9f 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2290,7 +2290,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
2290 u8 *pos; 2290 u8 *pos;
2291 2291
2292 /* headroom, head length, tail length and maximum TIM length */ 2292 /* headroom, head length, tail length and maximum TIM length */
2293 skb = dev_alloc_skb(local->tx_headroom + 400); 2293 skb = dev_alloc_skb(local->tx_headroom + 400 +
2294 sdata->u.mesh.vendor_ie_len);
2294 if (!skb) 2295 if (!skb)
2295 goto out; 2296 goto out;
2296 2297
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 79772fcc37bc..e9a5f8ca4c27 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -789,13 +789,23 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
789 cfg80211_mgd_wext_connect(rdev, wdev); 789 cfg80211_mgd_wext_connect(rdev, wdev);
790 break; 790 break;
791#endif 791#endif
792#ifdef CONFIG_MAC80211_MESH
792 case NL80211_IFTYPE_MESH_POINT: 793 case NL80211_IFTYPE_MESH_POINT:
793 /* backward compat code ... */ 794 {
794 if (wdev->mesh_id_up_len) 795 /* backward compat code... */
795 __cfg80211_join_mesh(rdev, dev, wdev->ssid, 796 struct mesh_setup setup;
796 wdev->mesh_id_up_len, 797 memcpy(&setup, &default_mesh_setup,
797 &default_mesh_config); 798 sizeof(setup));
798 break; 799 /* back compat only needed for mesh_id */
800 setup.mesh_id = wdev->ssid;
801 setup.mesh_id_len = wdev->mesh_id_up_len;
802 if (wdev->mesh_id_up_len)
803 __cfg80211_join_mesh(rdev, dev,
804 &setup,
805 &default_mesh_config);
806 break;
807 }
808#endif
799 default: 809 default:
800 break; 810 break;
801 } 811 }
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 743203bb61ac..26a0a084e16b 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -287,13 +287,14 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
287 287
288/* mesh */ 288/* mesh */
289extern const struct mesh_config default_mesh_config; 289extern const struct mesh_config default_mesh_config;
290extern const struct mesh_setup default_mesh_setup;
290int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, 291int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
291 struct net_device *dev, 292 struct net_device *dev,
292 const u8 *mesh_id, u8 mesh_id_len, 293 const struct mesh_setup *setup,
293 const struct mesh_config *conf); 294 const struct mesh_config *conf);
294int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, 295int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
295 struct net_device *dev, 296 struct net_device *dev,
296 const u8 *mesh_id, u8 mesh_id_len, 297 const struct mesh_setup *setup,
297 const struct mesh_config *conf); 298 const struct mesh_config *conf);
298int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, 299int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
299 struct net_device *dev); 300 struct net_device *dev);
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index e0b9747fe50a..73e39c171ffb 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -50,17 +50,19 @@ const struct mesh_config default_mesh_config = {
50 .min_discovery_timeout = MESH_MIN_DISCOVERY_TIMEOUT, 50 .min_discovery_timeout = MESH_MIN_DISCOVERY_TIMEOUT,
51}; 51};
52 52
53const struct mesh_setup default_mesh_setup = {
54 .path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP,
55 .path_metric = IEEE80211_PATH_METRIC_AIRTIME,
56 .vendor_ie = NULL,
57 .vendor_ie_len = 0,
58};
53 59
54int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, 60int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
55 struct net_device *dev, 61 struct net_device *dev,
56 const u8 *mesh_id, u8 mesh_id_len, 62 const struct mesh_setup *setup,
57 const struct mesh_config *conf) 63 const struct mesh_config *conf)
58{ 64{
59 struct wireless_dev *wdev = dev->ieee80211_ptr; 65 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; 66 int err;
65 67
66 BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN); 68 BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN);
@@ -73,16 +75,16 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
73 if (wdev->mesh_id_len) 75 if (wdev->mesh_id_len)
74 return -EALREADY; 76 return -EALREADY;
75 77
76 if (!mesh_id_len) 78 if (!setup->mesh_id_len)
77 return -EINVAL; 79 return -EINVAL;
78 80
79 if (!rdev->ops->join_mesh) 81 if (!rdev->ops->join_mesh)
80 return -EOPNOTSUPP; 82 return -EOPNOTSUPP;
81 83
82 err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, &setup); 84 err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup);
83 if (!err) { 85 if (!err) {
84 memcpy(wdev->ssid, mesh_id, mesh_id_len); 86 memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len);
85 wdev->mesh_id_len = mesh_id_len; 87 wdev->mesh_id_len = setup->mesh_id_len;
86 } 88 }
87 89
88 return err; 90 return err;
@@ -90,14 +92,14 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
90 92
91int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, 93int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
92 struct net_device *dev, 94 struct net_device *dev,
93 const u8 *mesh_id, u8 mesh_id_len, 95 const struct mesh_setup *setup,
94 const struct mesh_config *conf) 96 const struct mesh_config *conf)
95{ 97{
96 struct wireless_dev *wdev = dev->ieee80211_ptr; 98 struct wireless_dev *wdev = dev->ieee80211_ptr;
97 int err; 99 int err;
98 100
99 wdev_lock(wdev); 101 wdev_lock(wdev);
100 err = __cfg80211_join_mesh(rdev, dev, mesh_id, mesh_id_len, conf); 102 err = __cfg80211_join_mesh(rdev, dev, setup, conf);
101 wdev_unlock(wdev); 103 wdev_unlock(wdev);
102 104
103 return err; 105 return err;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 10be9350752e..eef89d0b558b 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2773,6 +2773,14 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A
2773 [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 }, 2773 [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 },
2774}; 2774};
2775 2775
2776static const struct nla_policy
2777 nl80211_mesh_setup_params_policy[NL80211_MESH_SETUP_ATTR_MAX+1] = {
2778 [NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 },
2779 [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 },
2780 [NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE] = { .type = NLA_BINARY,
2781 .len = IEEE80211_MAX_DATA_LEN },
2782};
2783
2776static int nl80211_parse_mesh_config(struct genl_info *info, 2784static int nl80211_parse_mesh_config(struct genl_info *info,
2777 struct mesh_config *cfg, 2785 struct mesh_config *cfg,
2778 u32 *mask_out) 2786 u32 *mask_out)
@@ -2839,14 +2847,50 @@ do {\
2839 dot11MeshHWMPRootMode, mask, 2847 dot11MeshHWMPRootMode, mask,
2840 NL80211_MESHCONF_HWMP_ROOTMODE, 2848 NL80211_MESHCONF_HWMP_ROOTMODE,
2841 nla_get_u8); 2849 nla_get_u8);
2842
2843 if (mask_out) 2850 if (mask_out)
2844 *mask_out = mask; 2851 *mask_out = mask;
2852
2845 return 0; 2853 return 0;
2846 2854
2847#undef FILL_IN_MESH_PARAM_IF_SET 2855#undef FILL_IN_MESH_PARAM_IF_SET
2848} 2856}
2849 2857
2858static int nl80211_parse_mesh_setup(struct genl_info *info,
2859 struct mesh_setup *setup)
2860{
2861 struct nlattr *tb[NL80211_MESH_SETUP_ATTR_MAX + 1];
2862
2863 if (!info->attrs[NL80211_ATTR_MESH_SETUP])
2864 return -EINVAL;
2865 if (nla_parse_nested(tb, NL80211_MESH_SETUP_ATTR_MAX,
2866 info->attrs[NL80211_ATTR_MESH_SETUP],
2867 nl80211_mesh_setup_params_policy))
2868 return -EINVAL;
2869
2870 if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL])
2871 setup->path_sel_proto =
2872 (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL])) ?
2873 IEEE80211_PATH_PROTOCOL_VENDOR :
2874 IEEE80211_PATH_PROTOCOL_HWMP;
2875
2876 if (tb[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC])
2877 setup->path_metric =
2878 (nla_get_u8(tb[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC])) ?
2879 IEEE80211_PATH_METRIC_VENDOR :
2880 IEEE80211_PATH_METRIC_AIRTIME;
2881
2882 if (tb[NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE]) {
2883 struct nlattr *ieattr =
2884 tb[NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE];
2885 if (!is_valid_ie_attr(ieattr))
2886 return -EINVAL;
2887 setup->vendor_ie = nla_data(ieattr);
2888 setup->vendor_ie_len = nla_len(ieattr);
2889 }
2890
2891 return 0;
2892}
2893
2850static int nl80211_update_mesh_config(struct sk_buff *skb, 2894static int nl80211_update_mesh_config(struct sk_buff *skb,
2851 struct genl_info *info) 2895 struct genl_info *info)
2852{ 2896{
@@ -4667,10 +4711,12 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
4667 struct cfg80211_registered_device *rdev = info->user_ptr[0]; 4711 struct cfg80211_registered_device *rdev = info->user_ptr[0];
4668 struct net_device *dev = info->user_ptr[1]; 4712 struct net_device *dev = info->user_ptr[1];
4669 struct mesh_config cfg; 4713 struct mesh_config cfg;
4714 struct mesh_setup setup;
4670 int err; 4715 int err;
4671 4716
4672 /* start with default */ 4717 /* start with default */
4673 memcpy(&cfg, &default_mesh_config, sizeof(cfg)); 4718 memcpy(&cfg, &default_mesh_config, sizeof(cfg));
4719 memcpy(&setup, &default_mesh_setup, sizeof(setup));
4674 4720
4675 if (info->attrs[NL80211_ATTR_MESH_CONFIG]) { 4721 if (info->attrs[NL80211_ATTR_MESH_CONFIG]) {
4676 /* and parse parameters if given */ 4722 /* and parse parameters if given */
@@ -4683,10 +4729,17 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
4683 !nla_len(info->attrs[NL80211_ATTR_MESH_ID])) 4729 !nla_len(info->attrs[NL80211_ATTR_MESH_ID]))
4684 return -EINVAL; 4730 return -EINVAL;
4685 4731
4686 return cfg80211_join_mesh(rdev, dev, 4732 setup.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
4687 nla_data(info->attrs[NL80211_ATTR_MESH_ID]), 4733 setup.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
4688 nla_len(info->attrs[NL80211_ATTR_MESH_ID]), 4734
4689 &cfg); 4735 if (info->attrs[NL80211_ATTR_MESH_SETUP]) {
4736 /* parse additional setup parameters if given */
4737 err = nl80211_parse_mesh_setup(info, &setup);
4738 if (err)
4739 return err;
4740 }
4741
4742 return cfg80211_join_mesh(rdev, dev, &setup, &cfg);
4690} 4743}
4691 4744
4692static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info) 4745static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info)