blob: 5219466be7cce045276b83ff1f81a635c65cb9b9 [file] [log] [blame]
Peter Qiu326b6cf2015-09-02 11:11:42 -07001//
2// Copyright (C) 2014 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
Peter Qiufb39ba42014-11-21 09:09:59 -080016
17#include "apmanager/device.h"
18
19#include <base/strings/stringprintf.h>
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -070020#include <brillo/strings/string_utils.h>
Peter Qiu8e785b92014-11-24 10:01:08 -080021#include <shill/net/attribute_list.h>
Peter Qiufb39ba42014-11-21 09:09:59 -080022#include <shill/net/ieee80211.h>
23
Peter Qiu8e785b92014-11-24 10:01:08 -080024#include "apmanager/config.h"
Peter Qiuf9335402015-11-16 12:09:16 -080025#include "apmanager/control_interface.h"
Peter Qiu7e0ffcf2014-12-02 12:53:27 -080026#include "apmanager/manager.h"
Peter Qiu8e785b92014-11-24 10:01:08 -080027
Peter Qiufb39ba42014-11-21 09:09:59 -080028using shill::ByteString;
29using std::string;
30
31namespace apmanager {
32
Peter Qiuf9335402015-11-16 12:09:16 -080033Device::Device(Manager* manager,
34 const string& device_name,
35 int identifier)
36 : manager_(manager),
37 supports_ap_mode_(false),
38 identifier_(identifier),
39 adaptor_(manager->control_interface()->CreateDeviceAdaptor(this)) {
Peter Qiu1ff67a72014-11-22 07:06:10 -080040 SetDeviceName(device_name);
Garret Kelly0c0e9e72015-09-01 17:28:01 -040041 SetInUse(false);
Peter Qiufb39ba42014-11-21 09:09:59 -080042}
43
44Device::~Device() {}
45
Peter Qiufb39ba42014-11-21 09:09:59 -080046void Device::RegisterInterface(const WiFiInterface& new_interface) {
47 LOG(INFO) << "RegisteringInterface " << new_interface.iface_name
48 << " on device " << GetDeviceName();
49 for (const auto& interface : interface_list_) {
50 // Done if interface already in the list.
51 if (interface.iface_index == new_interface.iface_index) {
52 LOG(INFO) << "Interface " << new_interface.iface_name
53 << " already registered.";
54 return;
55 }
56 }
57 interface_list_.push_back(new_interface);
58 UpdatePreferredAPInterface();
59}
60
61void Device::DeregisterInterface(const WiFiInterface& interface) {
62 LOG(INFO) << "DeregisteringInterface " << interface.iface_name
63 << " on device " << GetDeviceName();
64 for (auto it = interface_list_.begin(); it != interface_list_.end(); ++it) {
65 if (it->iface_index == interface.iface_index) {
66 interface_list_.erase(it);
67 UpdatePreferredAPInterface();
68 return;
69 }
70 }
71}
72
Peter Qiu1ff67a72014-11-22 07:06:10 -080073void Device::ParseWiphyCapability(const shill::Nl80211Message& msg) {
Peter Qiu3d95ac72014-12-06 18:26:18 -080074 // Parse NL80211_ATTR_SUPPORTED_IFTYPES for AP mode interface support.
75 shill::AttributeListConstRefPtr supported_iftypes;
76 if (!msg.const_attributes()->ConstGetNestedAttributeList(
77 NL80211_ATTR_SUPPORTED_IFTYPES, &supported_iftypes)) {
78 LOG(ERROR) << "NL80211_CMD_NEW_WIPHY had no NL80211_ATTR_SUPPORTED_IFTYPES";
79 return;
80 }
81 supported_iftypes->GetFlagAttributeValue(NL80211_IFTYPE_AP,
82 &supports_ap_mode_);
Peter Qiu8e785b92014-11-24 10:01:08 -080083
84 // Parse WiFi band capabilities.
85 shill::AttributeListConstRefPtr wiphy_bands;
86 if (!msg.const_attributes()->ConstGetNestedAttributeList(
87 NL80211_ATTR_WIPHY_BANDS, &wiphy_bands)) {
88 LOG(ERROR) << "NL80211_CMD_NEW_WIPHY had no NL80211_ATTR_WIPHY_BANDS";
89 return;
90 }
91
92 shill::AttributeIdIterator band_iter(*wiphy_bands);
93 for (; !band_iter.AtEnd(); band_iter.Advance()) {
94 BandCapability band_cap;
95
96 shill::AttributeListConstRefPtr wiphy_band;
97 if (!wiphy_bands->ConstGetNestedAttributeList(band_iter.GetId(),
98 &wiphy_band)) {
99 LOG(WARNING) << "WiFi band " << band_iter.GetId() << " not found";
100 continue;
101 }
102
103 // ...Each band has a FREQS attribute...
104 shill::AttributeListConstRefPtr frequencies;
105 if (!wiphy_band->ConstGetNestedAttributeList(NL80211_BAND_ATTR_FREQS,
106 &frequencies)) {
107 LOG(ERROR) << "BAND " << band_iter.GetId()
108 << " had no 'frequencies' attribute";
109 continue;
110 }
111
112 // ...And each FREQS attribute contains an array of information about the
113 // frequency...
114 shill::AttributeIdIterator freq_iter(*frequencies);
115 for (; !freq_iter.AtEnd(); freq_iter.Advance()) {
116 shill::AttributeListConstRefPtr frequency;
117 if (frequencies->ConstGetNestedAttributeList(freq_iter.GetId(),
118 &frequency)) {
119 // ...Including the frequency, itself (the part we want).
120 uint32_t frequency_value = 0;
121 if (frequency->GetU32AttributeValue(NL80211_FREQUENCY_ATTR_FREQ,
122 &frequency_value)) {
123 band_cap.frequencies.push_back(frequency_value);
124 }
125 }
126 }
127
128 wiphy_band->GetU16AttributeValue(NL80211_BAND_ATTR_HT_CAPA,
129 &band_cap.ht_capability_mask);
130 wiphy_band->GetU16AttributeValue(NL80211_BAND_ATTR_VHT_CAPA,
131 &band_cap.vht_capability_mask);
132 band_capability_.push_back(band_cap);
133 }
Peter Qiufb39ba42014-11-21 09:09:59 -0800134}
135
Peter Qiu0ca183b2015-03-09 13:41:06 -0700136bool Device::ClaimDevice(bool full_control) {
Garret Kelly0c0e9e72015-09-01 17:28:01 -0400137 if (GetInUse()) {
Peter Qiufb39ba42014-11-21 09:09:59 -0800138 LOG(ERROR) << "Failed to claim device [" << GetDeviceName()
139 << "]: already in used.";
140 return false;
141 }
142
Peter Qiu0ca183b2015-03-09 13:41:06 -0700143 if (full_control) {
144 for (const auto& interface : interface_list_) {
145 manager_->ClaimInterface(interface.iface_name);
146 claimed_interfaces_.insert(interface.iface_name);
147 }
148 } else {
149 manager_->ClaimInterface(GetPreferredApInterface());
150 claimed_interfaces_.insert(GetPreferredApInterface());
Peter Qiu7e0ffcf2014-12-02 12:53:27 -0800151 }
Garret Kelly0c0e9e72015-09-01 17:28:01 -0400152 SetInUse(true);
Peter Qiufb39ba42014-11-21 09:09:59 -0800153 return true;
154}
155
156bool Device::ReleaseDevice() {
Garret Kelly0c0e9e72015-09-01 17:28:01 -0400157 if (!GetInUse()) {
Peter Qiufb39ba42014-11-21 09:09:59 -0800158 LOG(ERROR) << "Failed to release device [" << GetDeviceName()
159 << "]: not currently in-used.";
160 return false;
161 }
162
Peter Qiu0ca183b2015-03-09 13:41:06 -0700163 for (const auto& interface : claimed_interfaces_) {
164 manager_->ReleaseInterface(interface);
Peter Qiu7e0ffcf2014-12-02 12:53:27 -0800165 }
Peter Qiu0ca183b2015-03-09 13:41:06 -0700166 claimed_interfaces_.clear();
Garret Kelly0c0e9e72015-09-01 17:28:01 -0400167 SetInUse(false);
Peter Qiufb39ba42014-11-21 09:09:59 -0800168 return true;
169}
170
171bool Device::InterfaceExists(const string& interface_name) {
172 for (const auto& interface : interface_list_) {
173 if (interface.iface_name == interface_name) {
174 return true;
175 }
176 }
177 return false;
178}
179
Peter Qiu8e785b92014-11-24 10:01:08 -0800180bool Device::GetHTCapability(uint16_t channel, string* ht_cap) {
181 // Get the band capability based on the channel.
182 BandCapability band_cap;
183 if (!GetBandCapability(channel, &band_cap)) {
184 LOG(ERROR) << "No band capability found for channel " << channel;
185 return false;
186 }
187
188 std::vector<string> ht_capability;
189 // LDPC coding capability.
190 if (band_cap.ht_capability_mask & shill::IEEE_80211::kHTCapMaskLdpcCoding) {
191 ht_capability.push_back("LDPC");
192 }
193
194 // Supported channel width set.
195 if (band_cap.ht_capability_mask &
196 shill::IEEE_80211::kHTCapMaskSupWidth2040) {
197 // Determine secondary channel is below or above the primary.
198 bool above = false;
199 if (!GetHTSecondaryChannelLocation(channel, &above)) {
200 LOG(ERROR) << "Unable to determine secondary channel location for "
201 << "channel " << channel;
202 return false;
203 }
204 if (above) {
205 ht_capability.push_back("HT40+");
206 } else {
207 ht_capability.push_back("HT40-");
208 }
209 }
210
211 // Spatial Multiplexing (SM) Power Save.
212 uint16_t power_save_mask =
213 (band_cap.ht_capability_mask >>
214 shill::IEEE_80211::kHTCapMaskSmPsShift) & 0x3;
215 if (power_save_mask == 0) {
216 ht_capability.push_back("SMPS-STATIC");
217 } else if (power_save_mask == 1) {
218 ht_capability.push_back("SMPS-DYNAMIC");
219 }
220
221 // HT-greenfield.
222 if (band_cap.ht_capability_mask & shill::IEEE_80211::kHTCapMaskGrnFld) {
223 ht_capability.push_back("GF");
224 }
225
226 // Short GI for 20 MHz.
227 if (band_cap.ht_capability_mask & shill::IEEE_80211::kHTCapMaskSgi20) {
228 ht_capability.push_back("SHORT-GI-20");
229 }
230
231 // Short GI for 40 MHz.
232 if (band_cap.ht_capability_mask & shill::IEEE_80211::kHTCapMaskSgi40) {
233 ht_capability.push_back("SHORT-GI-40");
234 }
235
236 // Tx STBC.
237 if (band_cap.ht_capability_mask & shill::IEEE_80211::kHTCapMaskTxStbc) {
238 ht_capability.push_back("TX-STBC");
239 }
240
241 // Rx STBC.
242 uint16_t rx_stbc =
243 (band_cap.ht_capability_mask >>
244 shill::IEEE_80211::kHTCapMaskRxStbcShift) & 0x3;
245 if (rx_stbc == 1) {
246 ht_capability.push_back("RX-STBC1");
247 } else if (rx_stbc == 2) {
248 ht_capability.push_back("RX-STBC12");
249 } else if (rx_stbc == 3) {
250 ht_capability.push_back("RX-STBC123");
251 }
252
253 // HT-delayed Block Ack.
254 if (band_cap.ht_capability_mask & shill::IEEE_80211::kHTCapMaskDelayBA) {
255 ht_capability.push_back("DELAYED-BA");
256 }
257
258 // Maximum A-MSDU length.
259 if (band_cap.ht_capability_mask & shill::IEEE_80211::kHTCapMaskMaxAmsdu) {
260 ht_capability.push_back("MAX-AMSDU-7935");
261 }
262
263 // DSSS/CCK Mode in 40 MHz.
264 if (band_cap.ht_capability_mask & shill::IEEE_80211::kHTCapMaskDsssCck40) {
265 ht_capability.push_back("DSSS_CCK-40");
266 }
267
268 // 40 MHz intolerant.
269 if (band_cap.ht_capability_mask &
270 shill::IEEE_80211::kHTCapMask40MHzIntolerant) {
271 ht_capability.push_back("40-INTOLERANT");
272 }
273
274 *ht_cap = base::StringPrintf("[%s]",
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700275 brillo::string_utils::Join(" ", ht_capability).c_str());
Peter Qiu8e785b92014-11-24 10:01:08 -0800276 return true;
277}
278
279bool Device::GetVHTCapability(uint16_t channel, string* vht_cap) {
280 // TODO(zqiu): to be implemented.
281 return false;
282}
283
Peter Qiuf9335402015-11-16 12:09:16 -0800284void Device::SetDeviceName(const std::string& device_name) {
285 adaptor_->SetDeviceName(device_name);
286}
287
288string Device::GetDeviceName() const {
289 return adaptor_->GetDeviceName();
290}
291
292void Device::SetPreferredApInterface(const std::string& interface_name) {
293 adaptor_->SetPreferredApInterface(interface_name);
294}
295
296string Device::GetPreferredApInterface() const {
297 return adaptor_->GetPreferredApInterface();
298}
299
300void Device::SetInUse(bool in_use) {
301 return adaptor_->SetInUse(in_use);
302}
303
304bool Device::GetInUse() const {
305 return adaptor_->GetInUse();
306}
307
Peter Qiu8e785b92014-11-24 10:01:08 -0800308// static
309bool Device::GetHTSecondaryChannelLocation(uint16_t channel, bool* above) {
310 bool ret_val = true;
311
312 // Determine secondary channel location base on the channel. Refer to
313 // ht_cap section in hostapd.conf documentation.
314 switch (channel) {
315 case 7:
316 case 8:
317 case 9:
318 case 10:
319 case 11:
320 case 12:
321 case 13:
322 case 40:
323 case 48:
324 case 56:
325 case 64:
326 *above = false;
327 break;
328
329 case 1:
330 case 2:
331 case 3:
332 case 4:
333 case 5:
334 case 6:
335 case 36:
336 case 44:
337 case 52:
338 case 60:
339 *above = true;
340 break;
341
342 default:
343 ret_val = false;
344 break;
345 }
346
347 return ret_val;
348}
349
350bool Device::GetBandCapability(uint16_t channel, BandCapability* capability) {
351 uint32_t frequency;
352 if (!Config::GetFrequencyFromChannel(channel, &frequency)) {
353 LOG(ERROR) << "Invalid channel " << channel;
354 return false;
355 }
356
357 for (const auto& band : band_capability_) {
358 if (std::find(band.frequencies.begin(),
359 band.frequencies.end(),
360 frequency) != band.frequencies.end()) {
361 *capability = band;
362 return true;
363 }
364 }
365 return false;
366}
367
Peter Qiufb39ba42014-11-21 09:09:59 -0800368void Device::UpdatePreferredAPInterface() {
Peter Qiu3d95ac72014-12-06 18:26:18 -0800369 // Return if device doesn't support AP interface mode.
370 if (!supports_ap_mode_) {
371 return;
372 }
Peter Qiu8e785b92014-11-24 10:01:08 -0800373
Peter Qiufb39ba42014-11-21 09:09:59 -0800374 // Use the first registered AP mode interface if there is one, otherwise use
375 // the first registered managed mode interface. If none are available, then
376 // no interface can be used for AP operation on this device.
377 WiFiInterface preferred_interface;
378 for (const auto& interface : interface_list_) {
379 if (interface.iface_type == NL80211_IFTYPE_AP) {
380 preferred_interface = interface;
381 break;
382 } else if (interface.iface_type == NL80211_IFTYPE_STATION &&
383 preferred_interface.iface_name.empty()) {
384 preferred_interface = interface;
385 }
386 // Ignore all other interface types.
387 }
388 // Update preferred AP interface property.
389 SetPreferredApInterface(preferred_interface.iface_name);
390}
391
392} // namespace apmanager