1//
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//
16
17#include "apmanager/device.h"
18
19#include <base/strings/stringprintf.h>
20#include <brillo/strings/string_utils.h>
21#include <shill/net/attribute_list.h>
22#include <shill/net/ieee80211.h>
23
24#include "apmanager/config.h"
25#include "apmanager/control_interface.h"
26#include "apmanager/manager.h"
27
28using shill::ByteString;
29using std::string;
30
31namespace apmanager {
32
33Device::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)) {
40  SetDeviceName(device_name);
41  SetInUse(false);
42}
43
44Device::~Device() {}
45
46void 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
73void Device::ParseWiphyCapability(const shill::Nl80211Message& msg) {
74  // 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_);
83
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  }
134}
135
136bool Device::ClaimDevice(bool full_control) {
137  if (GetInUse()) {
138    LOG(ERROR) << "Failed to claim device [" << GetDeviceName()
139               << "]: already in used.";
140    return false;
141  }
142
143  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());
151  }
152  SetInUse(true);
153  return true;
154}
155
156bool Device::ReleaseDevice() {
157  if (!GetInUse()) {
158    LOG(ERROR) << "Failed to release device [" << GetDeviceName()
159               << "]: not currently in-used.";
160    return false;
161  }
162
163  for (const auto& interface : claimed_interfaces_) {
164    manager_->ReleaseInterface(interface);
165  }
166  claimed_interfaces_.clear();
167  SetInUse(false);
168  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
180bool 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]",
275      brillo::string_utils::Join(" ", ht_capability).c_str());
276  return true;
277}
278
279bool Device::GetVHTCapability(uint16_t channel, string* vht_cap) {
280  // TODO(zqiu): to be implemented.
281  return false;
282}
283
284void 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
308// 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
368void Device::UpdatePreferredAPInterface() {
369  // Return if device doesn't support AP interface mode.
370  if (!supports_ap_mode_) {
371    return;
372  }
373
374  // 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
393