diff options
-rw-r--r-- | include/linux/ieee80211.h | 25 | ||||
-rw-r--r-- | include/linux/nl80211.h | 47 | ||||
-rw-r--r-- | include/net/cfg80211.h | 8 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 39 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 4 | ||||
-rw-r--r-- | net/mac80211/mesh.c | 7 | ||||
-rw-r--r-- | net/mac80211/mesh_plink.c | 3 | ||||
-rw-r--r-- | net/mac80211/tx.c | 3 | ||||
-rw-r--r-- | net/wireless/core.c | 22 | ||||
-rw-r--r-- | net/wireless/core.h | 5 | ||||
-rw-r--r-- | net/wireless/mesh.c | 24 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 63 |
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 | */ | ||
1301 | enum { | ||
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 | */ | ||
1313 | enum { | ||
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 | */ | ||
1674 | enum 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 | */ |
655 | struct mesh_setup { | 659 | struct 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 | ||
1003 | static 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 | |||
1003 | static int ieee80211_update_mesh_config(struct wiphy *wiphy, | 1033 | static 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 | ||
292 | u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, struct mesh_table *tbl) | 299 | u32 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 */ |
289 | extern const struct mesh_config default_mesh_config; | 289 | extern const struct mesh_config default_mesh_config; |
290 | extern const struct mesh_setup default_mesh_setup; | ||
290 | int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | 291 | int __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); |
294 | int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | 295 | int 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); |
298 | int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, | 299 | int 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 | ||
53 | const 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 | ||
54 | int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | 60 | int __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 | ||
91 | int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | 93 | int 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 | ||
2776 | static 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 | |||
2776 | static int nl80211_parse_mesh_config(struct genl_info *info, | 2784 | static 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 | ||
2858 | static 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 | |||
2850 | static int nl80211_update_mesh_config(struct sk_buff *skb, | 2894 | static 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 | ||
4692 | static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info) | 4745 | static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info) |