aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
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 /net/wireless
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>
Diffstat (limited to 'net/wireless')
-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
4 files changed, 90 insertions, 24 deletions
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)