aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJavier Cardona <javier@cozybit.com>2010-12-16 20:37:49 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-12-20 14:46:57 -0500
commitc80d545da3f7c0e534ccd4a780f322f80a92cff1 (patch)
treeedd5c51676b4677fc1a0b2fc692ffe97df863f25
parent24bdd9f4c9af75b33b438d60381a67626de0128d (diff)
mac80211: Let userspace enable and configure vendor specific path selection.
Userspace will now be allowed to toggle between the default path selection algorithm (HWMP, implemented in the kernel), and a vendor specific alternative. Also in the same patch, allow userspace to add information elements to mesh beacons. This is accordance with the Extensible Path Selection Framework specified in version 7.0 of the 802.11s draft. Signed-off-by: Javier Cardona <javier@cozybit.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-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)