blob: bb65fccbffac4c2cb52fb63c4e0dd6e5cb9e969b [file] [log] [blame]
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "shill/nl80211_attribute.h"
#include <ctype.h>
#include <linux/nl80211.h>
#include <netlink/attr.h>
#include <netlink/netlink.h>
#include <iomanip>
#include <string>
#include <base/format_macros.h>
#include <base/stl_util.h>
#include <base/stringprintf.h>
#include "shill/logging.h"
#include "shill/scope_logger.h"
using std::string;
using base::StringAppendF;
using base::StringPrintf;
namespace shill {
Nl80211Attribute::Nl80211Attribute(enum nl80211_attrs name,
const char *name_string,
Type type,
const char *type_string)
: name_(name), name_string_(name_string), type_(type),
type_string_(type_string) {}
// static
Nl80211Attribute *Nl80211Attribute::NewFromNlAttr(nl80211_attrs name,
const nlattr *data) {
scoped_ptr<Nl80211Attribute> attr;
switch (name) {
case NL80211_ATTR_COOKIE:
attr.reset(new Nl80211AttributeCookie());
break;
case NL80211_ATTR_CQM:
attr.reset(new Nl80211AttributeCqm());
break;
case NL80211_ATTR_DISCONNECTED_BY_AP:
attr.reset(new Nl80211AttributeDisconnectedByAp());
break;
case NL80211_ATTR_DURATION:
attr.reset(new Nl80211AttributeDuration());
break;
case NL80211_ATTR_FRAME:
attr.reset(new Nl80211AttributeFrame());
break;
case NL80211_ATTR_GENERATION:
attr.reset(new Nl80211AttributeGeneration());
break;
case NL80211_ATTR_IFINDEX:
attr.reset(new Nl80211AttributeIfindex());
break;
case NL80211_ATTR_KEY_IDX:
attr.reset(new Nl80211AttributeKeyIdx());
break;
case NL80211_ATTR_KEY_SEQ:
attr.reset(new Nl80211AttributeKeySeq());
break;
case NL80211_ATTR_KEY_TYPE:
attr.reset(new Nl80211AttributeKeyType());
break;
case NL80211_ATTR_MAC:
attr.reset(new Nl80211AttributeMac());
break;
case NL80211_ATTR_REASON_CODE:
attr.reset(new Nl80211AttributeReasonCode());
break;
case NL80211_ATTR_REG_ALPHA2:
attr.reset(new Nl80211AttributeRegAlpha2());
break;
case NL80211_ATTR_REG_INITIATOR:
attr.reset(new Nl80211AttributeRegInitiator());
break;
case NL80211_ATTR_REG_TYPE:
attr.reset(new Nl80211AttributeRegType());
break;
case NL80211_ATTR_RESP_IE:
attr.reset(new Nl80211AttributeRespIe());
break;
case NL80211_ATTR_SCAN_FREQUENCIES:
attr.reset(new Nl80211AttributeScanFrequencies());
break;
case NL80211_ATTR_SCAN_SSIDS:
attr.reset(new Nl80211AttributeScanSsids());
break;
case NL80211_ATTR_STA_INFO:
attr.reset(new Nl80211AttributeStaInfo());
break;
case NL80211_ATTR_STATUS_CODE:
attr.reset(new Nl80211AttributeStatusCode());
break;
case NL80211_ATTR_SUPPORT_MESH_AUTH:
attr.reset(new Nl80211AttributeSupportMeshAuth());
break;
case NL80211_ATTR_TIMED_OUT:
attr.reset(new Nl80211AttributeTimedOut());
break;
case NL80211_ATTR_WIPHY_FREQ:
attr.reset(new Nl80211AttributeWiphyFreq());
break;
case NL80211_ATTR_WIPHY:
attr.reset(new Nl80211AttributeWiphy());
break;
case NL80211_ATTR_WIPHY_NAME:
attr.reset(new Nl80211AttributeWiphyName());
break;
default:
attr.reset(new Nl80211AttributeGeneric(name));
break;
}
attr->InitFromNlAttr(data);
return attr.release();
}
// Duplicate attribute data, store in map indexed on |name|.
bool Nl80211Attribute::InitFromNlAttr(const nlattr *other) {
if (!other) {
LOG(ERROR) << "NULL data";
return false;
}
data_ = ByteString(reinterpret_cast<const unsigned char *>(other),
nla_total_size(nla_len(const_cast<nlattr *>(other))));
return true;
}
// Copies raw attribute data but not the header.
bool Nl80211Attribute::GetRawData(ByteString *output) const {
if (!output) {
LOG(ERROR) << "Null |output| parameter";
return false;
}
*output = data_;
return true;
}
string Nl80211Attribute::RawToString() const {
string output = " === RAW: ";
nlattr *data_nlattr = const_cast<nlattr *>(data());
uint16_t length = nla_len(data_nlattr);
StringAppendF(&output, "len=%u", length);
const uint8_t *const_data = reinterpret_cast<const uint8_t *>(data());
output.append(" DATA: ");
for (int i =0 ; i < length; ++i) {
StringAppendF(&output, "[%d]=%02x ", i, *(const_data)+i);
}
output.append(" ==== ");
return output;
}
// Nl80211U8Attribute
const char Nl80211U8Attribute::kMyTypeString[] = "uint8_t";
const Nl80211Attribute::Type Nl80211U8Attribute::kType =
Nl80211Attribute::kTypeU8;
bool Nl80211U8Attribute::InitFromNlAttr(const nlattr *input) {
if (!input) {
LOG(ERROR) << "Null |input| parameter";
return false;
}
uint8_t data = NlaGetU8(input);
SetU8Value(data);
return Nl80211Attribute::InitFromNlAttr(input);
}
bool Nl80211U8Attribute::GetU8Value(uint8_t *output) const {
if (!output) {
LOG(ERROR) << "Null |output| parameter";
return false;
}
*output = value_;
return true;
}
bool Nl80211U8Attribute::SetU8Value(uint8_t new_value) {
value_ = new_value;
return true;
}
bool Nl80211U8Attribute::AsString(string *output) const {
if (!output) {
LOG(ERROR) << "Null |output| parameter";
return false;
}
uint8_t value;
if (!GetU8Value(&value))
return false;
*output = StringPrintf("%u", value);
return true;
}
// Nl80211U16Attribute
const char Nl80211U16Attribute::kMyTypeString[] = "uint16_t";
const Nl80211Attribute::Type Nl80211U16Attribute::kType =
Nl80211Attribute::kTypeU16;
bool Nl80211U16Attribute::InitFromNlAttr(const nlattr *input) {
if (!input) {
LOG(ERROR) << "Null |input| parameter";
return false;
}
uint16_t data = NlaGetU16(input);
SetU16Value(data);
return Nl80211Attribute::InitFromNlAttr(input);
}
bool Nl80211U16Attribute::GetU16Value(uint16_t *output) const {
if (!output) {
LOG(ERROR) << "Null |output| parameter";
return false;
}
*output = value_;
return true;
}
bool Nl80211U16Attribute::SetU16Value(uint16_t new_value) {
value_ = new_value;
return true;
}
bool Nl80211U16Attribute::AsString(string *output) const {
if (!output) {
LOG(ERROR) << "Null |output| parameter";
return false;
}
uint16_t value;
if (!GetU16Value(&value))
return false;
*output = StringPrintf("%u", value);
return true;
}
// Nl80211U32Attribute::
const char Nl80211U32Attribute::kMyTypeString[] = "uint32_t";
const Nl80211Attribute::Type Nl80211U32Attribute::kType =
Nl80211Attribute::kTypeU32;
bool Nl80211U32Attribute::InitFromNlAttr(const nlattr *input) {
if (!input) {
LOG(ERROR) << "Null |input| parameter";
return false;
}
uint32_t data = NlaGetU32(input);
SetU32Value(data);
return Nl80211Attribute::InitFromNlAttr(input);
}
bool Nl80211U32Attribute::GetU32Value(uint32_t *output) const {
if (!output) {
LOG(ERROR) << "Null |output| parameter";
return false;
}
*output = value_;
return true;
}
bool Nl80211U32Attribute::SetU32Value(uint32_t new_value) {
value_ = new_value;
return true;
}
bool Nl80211U32Attribute::AsString(string *output) const {
if (!output) {
LOG(ERROR) << "Null |output| parameter";
return false;
}
uint32_t value;
if (!GetU32Value(&value))
return false;
*output = StringPrintf("%" PRIu32, value);
return true;
}
// Nl80211U64Attribute
const char Nl80211U64Attribute::kMyTypeString[] = "uint64_t";
const Nl80211Attribute::Type Nl80211U64Attribute::kType =
Nl80211Attribute::kTypeU64;
bool Nl80211U64Attribute::InitFromNlAttr(const nlattr *input) {
if (!input) {
LOG(ERROR) << "Null |input| parameter";
return false;
}
uint64_t data = NlaGetU64(input);
SetU64Value(data);
return Nl80211Attribute::InitFromNlAttr(input);
}
bool Nl80211U64Attribute::GetU64Value(uint64_t *output) const {
if (!output) {
LOG(ERROR) << "Null |output| parameter";
return false;
}
*output = value_;
return true;
}
bool Nl80211U64Attribute::SetU64Value(uint64_t new_value) {
value_ = new_value;
return true;
}
bool Nl80211U64Attribute::AsString(string *output) const {
if (!output) {
LOG(ERROR) << "Null |output| parameter";
return false;
}
uint64_t value;
if (!GetU64Value(&value))
return false;
*output = StringPrintf("%" PRIu64, value);
return true;
}
// Nl80211FlagAttribute
const char Nl80211FlagAttribute::kMyTypeString[] = "flag";
const Nl80211Attribute::Type Nl80211FlagAttribute::kType =
Nl80211Attribute::kTypeFlag;
bool Nl80211FlagAttribute::InitFromNlAttr(const nlattr *input) {
if (!input) {
LOG(ERROR) << "Null |input| parameter";
return false;
}
// The existence of the parameter means it's true
SetFlagValue(true);
return Nl80211Attribute::InitFromNlAttr(input);
}
bool Nl80211FlagAttribute::GetFlagValue(bool *output) const {
if (!output) {
LOG(ERROR) << "Null |output| parameter";
return false;
}
*output = value_;
return true;
}
bool Nl80211FlagAttribute::SetFlagValue(bool new_value) {
value_ = new_value;
return true;
}
bool Nl80211FlagAttribute::AsString(string *output) const {
if (!output) {
LOG(ERROR) << "Null |output| parameter";
return false;
}
bool value;
if (!GetFlagValue(&value))
return false;
*output = StringPrintf("%s", value ? "true" : "false");
return true;
}
// Nl80211StringAttribute
const char Nl80211StringAttribute::kMyTypeString[] = "string";
const Nl80211Attribute::Type Nl80211StringAttribute::kType =
Nl80211Attribute::kTypeString;
bool Nl80211StringAttribute::InitFromNlAttr(const nlattr *input) {
if (!input) {
LOG(ERROR) << "Null |input| parameter";
return false;
}
SetStringValue(NlaGetString(input));
return Nl80211Attribute::InitFromNlAttr(input);
}
bool Nl80211StringAttribute::GetStringValue(string *output) const {
if (!output) {
LOG(ERROR) << "Null |output| parameter";
return false;
}
*output = value_;
return true;
}
bool Nl80211StringAttribute::SetStringValue(const string new_value) {
value_ = new_value;
return true;
}
bool Nl80211StringAttribute::AsString(string *output) const {
if (!output) {
LOG(ERROR) << "Null |output| parameter";
return false;
}
return GetStringValue(output);
}
// Nl80211RawAttribute
const char Nl80211RawAttribute::kMyTypeString[] = "<raw>";
const Nl80211Attribute::Type Nl80211RawAttribute::kType =
Nl80211Attribute::kTypeRaw;
bool Nl80211RawAttribute::InitFromNlAttr(const nlattr *input) {
if (!input) {
LOG(ERROR) << "Null |input| parameter";
return false;
}
return Nl80211Attribute::InitFromNlAttr(input);
}
bool Nl80211RawAttribute::GetRawValue(ByteString *output) const {
if (!output) {
LOG(ERROR) << "NULL |output|";
return false;
}
*output = data_;
return true;
}
bool Nl80211RawAttribute::AsString(string *output) const {
if (!output) {
LOG(ERROR) << "Null |output| parameter";
return false;
}
// TODO(wdg): Make sure that 'data' is valid.
const uint8_t *raw_data = reinterpret_cast<const uint8_t *>(data());
int total_bytes = nla_len(data());
*output = StringPrintf("%d bytes:", total_bytes);
for (int i = 0; i < total_bytes; ++i) {
StringAppendF(output, " 0x%02x", raw_data[i]);
}
return true;
}
// Specific Attributes.
const nl80211_attrs Nl80211AttributeCookie::kName = NL80211_ATTR_COOKIE;
const char Nl80211AttributeCookie::kNameString[] = "NL80211_ATTR_COOKIE";
const nl80211_attrs Nl80211AttributeCqm::kName = NL80211_ATTR_CQM;
const char Nl80211AttributeCqm::kNameString[] = "NL80211_ATTR_CQM";
const nl80211_attrs Nl80211AttributeDisconnectedByAp::kName
= NL80211_ATTR_DISCONNECTED_BY_AP;
const char Nl80211AttributeDisconnectedByAp::kNameString[]
= "NL80211_ATTR_DISCONNECTED_BY_AP";
const nl80211_attrs Nl80211AttributeDuration::kName = NL80211_ATTR_DURATION;
const char Nl80211AttributeDuration::kNameString[] = "NL80211_ATTR_DURATION";
const nl80211_attrs Nl80211AttributeFrame::kName = NL80211_ATTR_FRAME;
const char Nl80211AttributeFrame::kNameString[] = "NL80211_ATTR_FRAME";
const nl80211_attrs Nl80211AttributeGeneration::kName = NL80211_ATTR_GENERATION;
const char Nl80211AttributeGeneration::kNameString[]
= "NL80211_ATTR_GENERATION";
const nl80211_attrs Nl80211AttributeIfindex::kName = NL80211_ATTR_IFINDEX;
const char Nl80211AttributeIfindex::kNameString[] = "NL80211_ATTR_IFINDEX";
const nl80211_attrs Nl80211AttributeKeyIdx::kName = NL80211_ATTR_KEY_IDX;
const char Nl80211AttributeKeyIdx::kNameString[] = "NL80211_ATTR_KEY_IDX";
const nl80211_attrs Nl80211AttributeKeySeq::kName = NL80211_ATTR_KEY_SEQ;
const char Nl80211AttributeKeySeq::kNameString[] = "NL80211_ATTR_KEY_SEQ";
const nl80211_attrs Nl80211AttributeKeyType::kName = NL80211_ATTR_KEY_TYPE;
const char Nl80211AttributeKeyType::kNameString[] = "NL80211_ATTR_KEY_TYPE";
const nl80211_attrs Nl80211AttributeMac::kName = NL80211_ATTR_MAC;
const char Nl80211AttributeMac::kNameString[] = "NL80211_ATTR_MAC";
const nl80211_attrs Nl80211AttributeReasonCode::kName
= NL80211_ATTR_REASON_CODE;
const char Nl80211AttributeReasonCode::kNameString[]
= "NL80211_ATTR_REASON_CODE";
const nl80211_attrs Nl80211AttributeRegAlpha2::kName = NL80211_ATTR_REG_ALPHA2;
const char Nl80211AttributeRegAlpha2::kNameString[] = "NL80211_ATTR_REG_ALPHA2";
const nl80211_attrs Nl80211AttributeRegInitiator::kName
= NL80211_ATTR_REG_INITIATOR;
const char Nl80211AttributeRegInitiator::kNameString[]
= "NL80211_ATTR_REG_INITIATOR";
const nl80211_attrs Nl80211AttributeRegType::kName = NL80211_ATTR_REG_TYPE;
const char Nl80211AttributeRegType::kNameString[] = "NL80211_ATTR_REG_TYPE";
const nl80211_attrs Nl80211AttributeRespIe::kName = NL80211_ATTR_RESP_IE;
const char Nl80211AttributeRespIe::kNameString[] = "NL80211_ATTR_RESP_IE";
const nl80211_attrs Nl80211AttributeScanFrequencies::kName
= NL80211_ATTR_SCAN_FREQUENCIES;
const char Nl80211AttributeScanFrequencies::kNameString[]
= "NL80211_ATTR_SCAN_FREQUENCIES";
const nl80211_attrs Nl80211AttributeScanSsids::kName = NL80211_ATTR_SCAN_SSIDS;
const char Nl80211AttributeScanSsids::kNameString[] = "NL80211_ATTR_SCAN_SSIDS";
const nl80211_attrs Nl80211AttributeStaInfo::kName = NL80211_ATTR_STA_INFO;
const char Nl80211AttributeStaInfo::kNameString[] = "NL80211_ATTR_STA_INFO";
const nl80211_attrs Nl80211AttributeStatusCode::kName
= NL80211_ATTR_STATUS_CODE;
const char Nl80211AttributeStatusCode::kNameString[]
= "NL80211_ATTR_STATUS_CODE";
const nl80211_attrs Nl80211AttributeSupportMeshAuth::kName
= NL80211_ATTR_SUPPORT_MESH_AUTH;
const char Nl80211AttributeSupportMeshAuth::kNameString[]
= "NL80211_ATTR_SUPPORT_MESH_AUTH";
const nl80211_attrs Nl80211AttributeTimedOut::kName = NL80211_ATTR_TIMED_OUT;
const char Nl80211AttributeTimedOut::kNameString[] = "NL80211_ATTR_TIMED_OUT";
const nl80211_attrs Nl80211AttributeWiphyFreq::kName = NL80211_ATTR_WIPHY_FREQ;
const char Nl80211AttributeWiphyFreq::kNameString[] = "NL80211_ATTR_WIPHY_FREQ";
const nl80211_attrs Nl80211AttributeWiphy::kName = NL80211_ATTR_WIPHY;
const char Nl80211AttributeWiphy::kNameString[] = "NL80211_ATTR_WIPHY";
const nl80211_attrs Nl80211AttributeWiphyName::kName = NL80211_ATTR_WIPHY_NAME;
const char Nl80211AttributeWiphyName::kNameString[] = "NL80211_ATTR_WIPHY_NAME";
Nl80211AttributeGeneric::Nl80211AttributeGeneric(nl80211_attrs name)
: Nl80211RawAttribute(name, "unused-string") {
StringAppendF(&name_string_, "<UNKNOWN ATTRIBUTE %d>", name);
}
const char *Nl80211AttributeGeneric::name_string() const {
return name_string_.c_str();
}
} // namespace shill