普通文本  |  393行  |  11.48 KB

//
// Copyright (C) 2014 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#include "apmanager/device.h"

#include <base/strings/stringprintf.h>
#include <brillo/strings/string_utils.h>
#include <shill/net/attribute_list.h>
#include <shill/net/ieee80211.h>

#include "apmanager/config.h"
#include "apmanager/control_interface.h"
#include "apmanager/manager.h"

using shill::ByteString;
using std::string;

namespace apmanager {

Device::Device(Manager* manager,
               const string& device_name,
               int identifier)
    : manager_(manager),
      supports_ap_mode_(false),
      identifier_(identifier),
      adaptor_(manager->control_interface()->CreateDeviceAdaptor(this)) {
  SetDeviceName(device_name);
  SetInUse(false);
}

Device::~Device() {}

void Device::RegisterInterface(const WiFiInterface& new_interface) {
  LOG(INFO) << "RegisteringInterface " << new_interface.iface_name
            << " on device " << GetDeviceName();
  for (const auto& interface : interface_list_) {
    // Done if interface already in the list.
    if (interface.iface_index == new_interface.iface_index) {
      LOG(INFO) << "Interface " << new_interface.iface_name
                << " already registered.";
      return;
    }
  }
  interface_list_.push_back(new_interface);
  UpdatePreferredAPInterface();
}

void Device::DeregisterInterface(const WiFiInterface& interface) {
  LOG(INFO) << "DeregisteringInterface " << interface.iface_name
            << " on device " << GetDeviceName();
  for (auto it = interface_list_.begin(); it != interface_list_.end(); ++it) {
    if (it->iface_index == interface.iface_index) {
      interface_list_.erase(it);
      UpdatePreferredAPInterface();
      return;
    }
  }
}

void Device::ParseWiphyCapability(const shill::Nl80211Message& msg) {
  // Parse NL80211_ATTR_SUPPORTED_IFTYPES for AP mode interface support.
  shill::AttributeListConstRefPtr supported_iftypes;
  if (!msg.const_attributes()->ConstGetNestedAttributeList(
      NL80211_ATTR_SUPPORTED_IFTYPES, &supported_iftypes)) {
    LOG(ERROR) << "NL80211_CMD_NEW_WIPHY had no NL80211_ATTR_SUPPORTED_IFTYPES";
    return;
  }
  supported_iftypes->GetFlagAttributeValue(NL80211_IFTYPE_AP,
                                           &supports_ap_mode_);

  // Parse WiFi band capabilities.
  shill::AttributeListConstRefPtr wiphy_bands;
  if (!msg.const_attributes()->ConstGetNestedAttributeList(
      NL80211_ATTR_WIPHY_BANDS, &wiphy_bands)) {
    LOG(ERROR) << "NL80211_CMD_NEW_WIPHY had no NL80211_ATTR_WIPHY_BANDS";
    return;
  }

  shill::AttributeIdIterator band_iter(*wiphy_bands);
  for (; !band_iter.AtEnd(); band_iter.Advance()) {
    BandCapability band_cap;

    shill::AttributeListConstRefPtr wiphy_band;
    if (!wiphy_bands->ConstGetNestedAttributeList(band_iter.GetId(),
                                                  &wiphy_band)) {
      LOG(WARNING) << "WiFi band " << band_iter.GetId() << " not found";
      continue;
    }

    // ...Each band has a FREQS attribute...
    shill::AttributeListConstRefPtr frequencies;
    if (!wiphy_band->ConstGetNestedAttributeList(NL80211_BAND_ATTR_FREQS,
                                                 &frequencies)) {
      LOG(ERROR) << "BAND " << band_iter.GetId()
                 << " had no 'frequencies' attribute";
      continue;
    }

    // ...And each FREQS attribute contains an array of information about the
    // frequency...
    shill::AttributeIdIterator freq_iter(*frequencies);
    for (; !freq_iter.AtEnd(); freq_iter.Advance()) {
      shill::AttributeListConstRefPtr frequency;
      if (frequencies->ConstGetNestedAttributeList(freq_iter.GetId(),
                                                   &frequency)) {
        // ...Including the frequency, itself (the part we want).
        uint32_t frequency_value = 0;
        if (frequency->GetU32AttributeValue(NL80211_FREQUENCY_ATTR_FREQ,
                                            &frequency_value)) {
          band_cap.frequencies.push_back(frequency_value);
        }
      }
    }

    wiphy_band->GetU16AttributeValue(NL80211_BAND_ATTR_HT_CAPA,
                                     &band_cap.ht_capability_mask);
    wiphy_band->GetU16AttributeValue(NL80211_BAND_ATTR_VHT_CAPA,
                                     &band_cap.vht_capability_mask);
    band_capability_.push_back(band_cap);
  }
}

bool Device::ClaimDevice(bool full_control) {
  if (GetInUse()) {
    LOG(ERROR) << "Failed to claim device [" << GetDeviceName()
               << "]: already in used.";
    return false;
  }

  if (full_control) {
    for (const auto& interface : interface_list_) {
      manager_->ClaimInterface(interface.iface_name);
      claimed_interfaces_.insert(interface.iface_name);
    }
  } else {
    manager_->ClaimInterface(GetPreferredApInterface());
    claimed_interfaces_.insert(GetPreferredApInterface());
  }
  SetInUse(true);
  return true;
}

bool Device::ReleaseDevice() {
  if (!GetInUse()) {
    LOG(ERROR) << "Failed to release device [" << GetDeviceName()
               << "]: not currently in-used.";
    return false;
  }

  for (const auto& interface : claimed_interfaces_) {
    manager_->ReleaseInterface(interface);
  }
  claimed_interfaces_.clear();
  SetInUse(false);
  return true;
}

bool Device::InterfaceExists(const string& interface_name) {
  for (const auto& interface : interface_list_) {
    if (interface.iface_name == interface_name) {
      return true;
    }
  }
  return false;
}

bool Device::GetHTCapability(uint16_t channel, string* ht_cap) {
  // Get the band capability based on the channel.
  BandCapability band_cap;
  if (!GetBandCapability(channel, &band_cap)) {
    LOG(ERROR) << "No band capability found for channel " << channel;
    return false;
  }

  std::vector<string> ht_capability;
  // LDPC coding capability.
  if (band_cap.ht_capability_mask & shill::IEEE_80211::kHTCapMaskLdpcCoding) {
    ht_capability.push_back("LDPC");
  }

  // Supported channel width set.
  if (band_cap.ht_capability_mask &
      shill::IEEE_80211::kHTCapMaskSupWidth2040) {
    // Determine secondary channel is below or above the primary.
    bool above = false;
    if (!GetHTSecondaryChannelLocation(channel, &above)) {
      LOG(ERROR) << "Unable to determine secondary channel location for "
                 << "channel " << channel;
      return false;
    }
    if (above) {
      ht_capability.push_back("HT40+");
    } else {
      ht_capability.push_back("HT40-");
    }
  }

  // Spatial Multiplexing (SM) Power Save.
  uint16_t power_save_mask =
      (band_cap.ht_capability_mask >>
          shill::IEEE_80211::kHTCapMaskSmPsShift) & 0x3;
  if (power_save_mask == 0) {
    ht_capability.push_back("SMPS-STATIC");
  } else if (power_save_mask == 1) {
    ht_capability.push_back("SMPS-DYNAMIC");
  }

  // HT-greenfield.
  if (band_cap.ht_capability_mask & shill::IEEE_80211::kHTCapMaskGrnFld) {
    ht_capability.push_back("GF");
  }

  // Short GI for 20 MHz.
  if (band_cap.ht_capability_mask & shill::IEEE_80211::kHTCapMaskSgi20) {
    ht_capability.push_back("SHORT-GI-20");
  }

  // Short GI for 40 MHz.
  if (band_cap.ht_capability_mask & shill::IEEE_80211::kHTCapMaskSgi40) {
    ht_capability.push_back("SHORT-GI-40");
  }

  // Tx STBC.
  if (band_cap.ht_capability_mask & shill::IEEE_80211::kHTCapMaskTxStbc) {
    ht_capability.push_back("TX-STBC");
  }

  // Rx STBC.
  uint16_t rx_stbc =
      (band_cap.ht_capability_mask >>
          shill::IEEE_80211::kHTCapMaskRxStbcShift) & 0x3;
  if (rx_stbc == 1) {
    ht_capability.push_back("RX-STBC1");
  } else if (rx_stbc == 2) {
    ht_capability.push_back("RX-STBC12");
  } else if (rx_stbc == 3) {
    ht_capability.push_back("RX-STBC123");
  }

  // HT-delayed Block Ack.
  if (band_cap.ht_capability_mask & shill::IEEE_80211::kHTCapMaskDelayBA) {
    ht_capability.push_back("DELAYED-BA");
  }

  // Maximum A-MSDU length.
  if (band_cap.ht_capability_mask & shill::IEEE_80211::kHTCapMaskMaxAmsdu) {
    ht_capability.push_back("MAX-AMSDU-7935");
  }

  // DSSS/CCK Mode in 40 MHz.
  if (band_cap.ht_capability_mask & shill::IEEE_80211::kHTCapMaskDsssCck40) {
    ht_capability.push_back("DSSS_CCK-40");
  }

  // 40 MHz intolerant.
  if (band_cap.ht_capability_mask &
      shill::IEEE_80211::kHTCapMask40MHzIntolerant) {
    ht_capability.push_back("40-INTOLERANT");
  }

  *ht_cap = base::StringPrintf("[%s]",
      brillo::string_utils::Join(" ", ht_capability).c_str());
  return true;
}

bool Device::GetVHTCapability(uint16_t channel, string* vht_cap) {
  // TODO(zqiu): to be implemented.
  return false;
}

void Device::SetDeviceName(const std::string& device_name) {
  adaptor_->SetDeviceName(device_name);
}

string Device::GetDeviceName() const {
  return adaptor_->GetDeviceName();
}

void Device::SetPreferredApInterface(const std::string& interface_name) {
  adaptor_->SetPreferredApInterface(interface_name);
}

string Device::GetPreferredApInterface() const {
  return adaptor_->GetPreferredApInterface();
}

void Device::SetInUse(bool in_use) {
  return adaptor_->SetInUse(in_use);
}

bool Device::GetInUse() const {
  return adaptor_->GetInUse();
}

// static
bool Device::GetHTSecondaryChannelLocation(uint16_t channel, bool* above) {
  bool ret_val = true;

  // Determine secondary channel location base on the channel. Refer to
  // ht_cap section in hostapd.conf documentation.
  switch (channel) {
    case 7:
    case 8:
    case 9:
    case 10:
    case 11:
    case 12:
    case 13:
    case 40:
    case 48:
    case 56:
    case 64:
      *above = false;
      break;

    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
    case 6:
    case 36:
    case 44:
    case 52:
    case 60:
      *above = true;
      break;

    default:
      ret_val = false;
      break;
  }

  return ret_val;
}

bool Device::GetBandCapability(uint16_t channel, BandCapability* capability) {
  uint32_t frequency;
  if (!Config::GetFrequencyFromChannel(channel, &frequency)) {
    LOG(ERROR) << "Invalid channel " << channel;
    return false;
  }

  for (const auto& band : band_capability_) {
    if (std::find(band.frequencies.begin(),
                  band.frequencies.end(),
                  frequency) != band.frequencies.end()) {
      *capability = band;
      return true;
    }
  }
  return false;
}

void Device::UpdatePreferredAPInterface() {
  // Return if device doesn't support AP interface mode.
  if (!supports_ap_mode_) {
    return;
  }

  // Use the first registered AP mode interface if there is one, otherwise use
  // the first registered managed mode interface. If none are available, then
  // no interface can be used for AP operation on this device.
  WiFiInterface preferred_interface;
  for (const auto& interface : interface_list_) {
    if (interface.iface_type == NL80211_IFTYPE_AP) {
      preferred_interface = interface;
      break;
    } else if (interface.iface_type == NL80211_IFTYPE_STATION &&
               preferred_interface.iface_name.empty()) {
      preferred_interface = interface;
    }
    // Ignore all other interface types.
  }
  // Update preferred AP interface property.
  SetPreferredApInterface(preferred_interface.iface_name);
}

}  // namespace apmanager