diff options
| author | John W. Linville <linville@tuxdriver.com> | 2012-06-12 14:25:04 -0400 |
|---|---|---|
| committer | John W. Linville <linville@tuxdriver.com> | 2012-06-12 14:25:04 -0400 |
| commit | 0440507bbc44149e63bbfb9df730ba3820371904 (patch) | |
| tree | 7275e41aa1aa7e4d19d0503f1c15f07991c1a120 /net/wireless/mesh.c | |
| parent | 8d242488ce4627dd7e6333caab56df11ea25e239 (diff) | |
| parent | 7f0d9f430dc99303558adc30a75eef10c43f7bec (diff) | |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Diffstat (limited to 'net/wireless/mesh.c')
| -rw-r--r-- | net/wireless/mesh.c | 91 |
1 files changed, 89 insertions, 2 deletions
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 2749cb86b462..b44c736bf9cf 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 | ||
| 67 | const struct mesh_setup default_mesh_setup = { | 67 | const 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 | ||
| 76 | int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | 79 | int __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 | ||
| 113 | int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | 161 | int 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 | ||
| 176 | int 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 | channel = rdev_freq_to_chan(rdev, freq, channel_type); | ||
| 183 | if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy, | ||
| 184 | channel, | ||
| 185 | channel_type)) { | ||
| 186 | return -EINVAL; | ||
| 187 | } | ||
| 188 | |||
| 189 | /* | ||
| 190 | * Workaround for libertas (only!), it puts the interface | ||
| 191 | * into mesh mode but doesn't implement join_mesh. Instead, | ||
| 192 | * it is configured via sysfs and then joins the mesh when | ||
| 193 | * you set the channel. Note that the libertas mesh isn't | ||
| 194 | * compatible with 802.11 mesh. | ||
| 195 | */ | ||
| 196 | if (rdev->ops->libertas_set_mesh_channel) { | ||
| 197 | if (channel_type != NL80211_CHAN_NO_HT) | ||
| 198 | return -EINVAL; | ||
| 199 | |||
| 200 | if (!netif_running(wdev->netdev)) | ||
| 201 | return -ENETDOWN; | ||
| 202 | return rdev->ops->libertas_set_mesh_channel(&rdev->wiphy, | ||
| 203 | wdev->netdev, | ||
| 204 | channel); | ||
| 205 | } | ||
| 206 | |||
| 207 | if (wdev->mesh_id_len) | ||
| 208 | return -EBUSY; | ||
| 209 | |||
| 210 | wdev->preset_chan = channel; | ||
| 211 | wdev->preset_chantype = channel_type; | ||
| 212 | return 0; | ||
| 213 | } | ||
| 214 | |||
| 128 | void cfg80211_notify_new_peer_candidate(struct net_device *dev, | 215 | void 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 | { |
