aboutsummaryrefslogtreecommitdiffstats
path: root/net
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
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')
-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
9 files changed, 138 insertions, 32 deletions
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)