aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-05-16 17:50:20 -0400
committerJohn W. Linville <linville@tuxdriver.com>2012-06-05 15:32:18 -0400
commitcc1d2806bf06ab92268343d26eb3d8d8f00f8bc9 (patch)
treeb14ffa920d616470715e715df49f990bfdcf12ae /net
parent685d12a1929f274bd91497e33b4255fe164ac8ec (diff)
cfg80211: provide channel to join_mesh function
Just like the AP mode patch, instead of setting the channel and then joining the mesh network, provide the channel to join the network on to the join_mesh() function. Like in AP mode, you can also give the channel to the join-mesh nl80211 command now. Unlike AP mode, it picks a default channel if none was given. As libertas uses mesh mode interfaces but has no join_mesh callback and we can't simply break it, keep some compatibility code for that case and configure the channel directly for it. In the non-libertas case, where we store the channel until join, allow setting it while the interface is down. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/cfg.c6
-rw-r--r--net/wireless/core.h7
-rw-r--r--net/wireless/mesh.c91
-rw-r--r--net/wireless/nl80211.c43
-rw-r--r--net/wireless/wext-compat.c12
5 files changed, 144 insertions, 15 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 8e9d525c4653..f47af8b3185e 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1598,6 +1598,12 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev,
1598 err = copy_mesh_setup(ifmsh, setup); 1598 err = copy_mesh_setup(ifmsh, setup);
1599 if (err) 1599 if (err)
1600 return err; 1600 return err;
1601
1602 err = ieee80211_set_channel(wiphy, dev, setup->channel,
1603 setup->channel_type);
1604 if (err)
1605 return err;
1606
1601 ieee80211_start_mesh(sdata); 1607 ieee80211_start_mesh(sdata);
1602 1608
1603 return 0; 1609 return 0;
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 8523f3878677..1d3d24126946 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -303,14 +303,17 @@ extern const struct mesh_config default_mesh_config;
303extern const struct mesh_setup default_mesh_setup; 303extern const struct mesh_setup default_mesh_setup;
304int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, 304int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
305 struct net_device *dev, 305 struct net_device *dev,
306 const struct mesh_setup *setup, 306 struct mesh_setup *setup,
307 const struct mesh_config *conf); 307 const struct mesh_config *conf);
308int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, 308int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
309 struct net_device *dev, 309 struct net_device *dev,
310 const struct mesh_setup *setup, 310 struct mesh_setup *setup,
311 const struct mesh_config *conf); 311 const struct mesh_config *conf);
312int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, 312int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
313 struct net_device *dev); 313 struct net_device *dev);
314int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
315 struct wireless_dev *wdev, int freq,
316 enum nl80211_channel_type channel_type);
314 317
315/* MLME */ 318/* MLME */
316int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, 319int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index 2749cb86b462..2e3b700eba32 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -65,6 +65,9 @@ const struct mesh_config default_mesh_config = {
65}; 65};
66 66
67const struct mesh_setup default_mesh_setup = { 67const struct mesh_setup default_mesh_setup = {
68 /* cfg80211_join_mesh() will pick a channel if needed */
69 .channel = NULL,
70 .channel_type = NL80211_CHAN_NO_HT,
68 .sync_method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET, 71 .sync_method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET,
69 .path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP, 72 .path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP,
70 .path_metric = IEEE80211_PATH_METRIC_AIRTIME, 73 .path_metric = IEEE80211_PATH_METRIC_AIRTIME,
@@ -75,7 +78,7 @@ const struct mesh_setup default_mesh_setup = {
75 78
76int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, 79int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
77 struct net_device *dev, 80 struct net_device *dev,
78 const struct mesh_setup *setup, 81 struct mesh_setup *setup,
79 const struct mesh_config *conf) 82 const struct mesh_config *conf)
80{ 83{
81 struct wireless_dev *wdev = dev->ieee80211_ptr; 84 struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -101,6 +104,51 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
101 if (!rdev->ops->join_mesh) 104 if (!rdev->ops->join_mesh)
102 return -EOPNOTSUPP; 105 return -EOPNOTSUPP;
103 106
107 if (!setup->channel) {
108 /* if no channel explicitly given, use preset channel */
109 setup->channel = wdev->preset_chan;
110 setup->channel_type = wdev->preset_chantype;
111 }
112
113 if (!setup->channel) {
114 /* if we don't have that either, use the first usable channel */
115 enum ieee80211_band band;
116
117 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
118 struct ieee80211_supported_band *sband;
119 struct ieee80211_channel *chan;
120 int i;
121
122 sband = rdev->wiphy.bands[band];
123 if (!sband)
124 continue;
125
126 for (i = 0; i < sband->n_channels; i++) {
127 chan = &sband->channels[i];
128 if (chan->flags & (IEEE80211_CHAN_NO_IBSS |
129 IEEE80211_CHAN_PASSIVE_SCAN |
130 IEEE80211_CHAN_DISABLED |
131 IEEE80211_CHAN_RADAR))
132 continue;
133 setup->channel = chan;
134 break;
135 }
136
137 if (setup->channel)
138 break;
139 }
140
141 /* no usable channel ... */
142 if (!setup->channel)
143 return -EINVAL;
144
145 setup->channel_type = NL80211_CHAN_NO_HT;
146 }
147
148 if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, setup->channel,
149 setup->channel_type))
150 return -EINVAL;
151
104 err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup); 152 err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup);
105 if (!err) { 153 if (!err) {
106 memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); 154 memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len);
@@ -112,7 +160,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
112 160
113int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, 161int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
114 struct net_device *dev, 162 struct net_device *dev,
115 const struct mesh_setup *setup, 163 struct mesh_setup *setup,
116 const struct mesh_config *conf) 164 const struct mesh_config *conf)
117{ 165{
118 struct wireless_dev *wdev = dev->ieee80211_ptr; 166 struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -125,6 +173,45 @@ int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
125 return err; 173 return err;
126} 174}
127 175
176int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
177 struct wireless_dev *wdev, int freq,
178 enum nl80211_channel_type channel_type)
179{
180 struct ieee80211_channel *channel;
181
182 /*
183 * Workaround for libertas (only!), it puts the interface
184 * into mesh mode but doesn't implement join_mesh. Instead,
185 * it is configured via sysfs and then joins the mesh when
186 * you set the channel. Note that the libertas mesh isn't
187 * compatible with 802.11 mesh.
188 */
189 if (!rdev->ops->join_mesh) {
190 int err;
191
192 if (!netif_running(wdev->netdev))
193 return -ENETDOWN;
194 wdev_lock(wdev);
195 err = cfg80211_set_freq(rdev, wdev, freq, channel_type);
196 wdev_unlock(wdev);
197
198 return err;
199 }
200
201 if (wdev->mesh_id_len)
202 return -EBUSY;
203
204 channel = rdev_freq_to_chan(rdev, freq, channel_type);
205 if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy,
206 channel,
207 channel_type)) {
208 return -EINVAL;
209 }
210 wdev->preset_chan = channel;
211 wdev->preset_chantype = channel_type;
212 return 0;
213}
214
128void cfg80211_notify_new_peer_candidate(struct net_device *dev, 215void cfg80211_notify_new_peer_candidate(struct net_device *dev,
129 const u8 *macaddr, const u8* ie, u8 ie_len, gfp_t gfp) 216 const u8 *macaddr, const u8* ie, u8 ie_len, gfp_t gfp)
130{ 217{
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 089a5204dad5..b22f1f876881 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -921,7 +921,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
921 if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS)) 921 if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
922 goto nla_put_failure; 922 goto nla_put_failure;
923 } 923 }
924 if (dev->ops->set_channel || dev->ops->start_ap) { 924 if (dev->ops->set_channel || dev->ops->start_ap ||
925 dev->ops->join_mesh) {
925 i++; 926 i++;
926 if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL)) 927 if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
927 goto nla_put_failure; 928 goto nla_put_failure;
@@ -1166,17 +1167,19 @@ static int parse_txq_params(struct nlattr *tb[],
1166static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev) 1167static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
1167{ 1168{
1168 /* 1169 /*
1169 * You can only set the channel explicitly for AP and 1170 * You can only set the channel explicitly for WDS interfaces,
1170 * mesh type interfaces; all others have their channel 1171 * all others have their channel managed via their respective
1171 * managed via their respective "establish a connection" 1172 * "establish a connection" command (connect, join, ...)
1172 * command (connect, join, ...) 1173 *
1174 * For AP/GO and mesh mode, the channel can be set with the
1175 * channel userspace API, but is only stored and passed to the
1176 * low-level driver when the AP starts or the mesh is joined.
1177 * This is for backward compatibility, userspace can also give
1178 * the channel in the start-ap or join-mesh commands instead.
1173 * 1179 *
1174 * Monitors are special as they are normally slaved to 1180 * Monitors are special as they are normally slaved to
1175 * whatever else is going on, so they behave as though 1181 * whatever else is going on, so they behave as though
1176 * you tried setting the wiphy channel itself. 1182 * you tried setting the wiphy channel itself.
1177 *
1178 * For AP/GO modes, it's only for compatibility, you can
1179 * also give the channel to the start-AP command.
1180 */ 1183 */
1181 return !wdev || 1184 return !wdev ||
1182 wdev->iftype == NL80211_IFTYPE_AP || 1185 wdev->iftype == NL80211_IFTYPE_AP ||
@@ -1246,6 +1249,9 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
1246 wdev->preset_chantype = channel_type; 1249 wdev->preset_chantype = channel_type;
1247 result = 0; 1250 result = 0;
1248 break; 1251 break;
1252 case NL80211_IFTYPE_MESH_POINT:
1253 result = cfg80211_set_mesh_freq(rdev, wdev, freq, channel_type);
1254 break;
1249 default: 1255 default:
1250 wdev_lock(wdev); 1256 wdev_lock(wdev);
1251 result = cfg80211_set_freq(rdev, wdev, freq, channel_type); 1257 result = cfg80211_set_freq(rdev, wdev, freq, channel_type);
@@ -1335,8 +1341,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
1335 result = 0; 1341 result = 0;
1336 1342
1337 mutex_lock(&rdev->mtx); 1343 mutex_lock(&rdev->mtx);
1338 } else if (netif_running(netdev) && 1344 } else if (nl80211_can_set_dev_channel(netdev->ieee80211_ptr))
1339 nl80211_can_set_dev_channel(netdev->ieee80211_ptr))
1340 wdev = netdev->ieee80211_ptr; 1345 wdev = netdev->ieee80211_ptr;
1341 else 1346 else
1342 wdev = NULL; 1347 wdev = NULL;
@@ -6080,6 +6085,24 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
6080 return err; 6085 return err;
6081 } 6086 }
6082 6087
6088 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
6089 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
6090
6091 if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] &&
6092 !nl80211_valid_channel_type(info, &channel_type))
6093 return -EINVAL;
6094
6095 setup.channel = rdev_freq_to_chan(rdev,
6096 nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]),
6097 channel_type);
6098 if (!setup.channel)
6099 return -EINVAL;
6100 setup.channel_type = channel_type;
6101 } else {
6102 /* cfg80211_join_mesh() will sort it out */
6103 setup.channel = NULL;
6104 }
6105
6083 return cfg80211_join_mesh(rdev, dev, &setup, &cfg); 6106 return cfg80211_join_mesh(rdev, dev, &setup, &cfg);
6084} 6107}
6085 6108
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index b082fcc26f06..faeb03548aa4 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -796,7 +796,6 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
796 case NL80211_IFTYPE_ADHOC: 796 case NL80211_IFTYPE_ADHOC:
797 return cfg80211_ibss_wext_siwfreq(dev, info, wextfreq, extra); 797 return cfg80211_ibss_wext_siwfreq(dev, info, wextfreq, extra);
798 case NL80211_IFTYPE_MONITOR: 798 case NL80211_IFTYPE_MONITOR:
799 case NL80211_IFTYPE_MESH_POINT:
800 freq = cfg80211_wext_freq(wdev->wiphy, wextfreq); 799 freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
801 if (freq < 0) 800 if (freq < 0)
802 return freq; 801 return freq;
@@ -808,6 +807,17 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
808 wdev_unlock(wdev); 807 wdev_unlock(wdev);
809 mutex_unlock(&rdev->devlist_mtx); 808 mutex_unlock(&rdev->devlist_mtx);
810 return err; 809 return err;
810 case NL80211_IFTYPE_MESH_POINT:
811 freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
812 if (freq < 0)
813 return freq;
814 if (freq == 0)
815 return -EINVAL;
816 mutex_lock(&rdev->devlist_mtx);
817 err = cfg80211_set_mesh_freq(rdev, wdev, freq,
818 NL80211_CHAN_NO_HT);
819 mutex_unlock(&rdev->devlist_mtx);
820 return err;
811 default: 821 default:
812 return -EOPNOTSUPP; 822 return -EOPNOTSUPP;
813 } 823 }