普通文本  |  162行  |  4.7 KB

//
// Copyright (C) 2013 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 "shill/net/generic_netlink_message.h"

#include <base/bind.h>
#include <base/logging.h>
#include <base/strings/stringprintf.h>

#include "shill/net/netlink_attribute.h"
#include "shill/net/netlink_packet.h"

using base::Bind;
using base::StringPrintf;

namespace shill {

ByteString GenericNetlinkMessage::EncodeHeader(uint32_t sequence_number) {
  // Build nlmsghdr.
  ByteString result(NetlinkMessage::EncodeHeader(sequence_number));
  if (result.GetLength() == 0) {
    LOG(ERROR) << "Couldn't encode message header.";
    return result;
  }

  // Build and append the genl message header.
  genlmsghdr genl_header;
  genl_header.cmd = command();
  genl_header.version = 1;
  genl_header.reserved = 0;

  ByteString genl_header_string(
      reinterpret_cast<unsigned char*>(&genl_header), sizeof(genl_header));
  size_t genlmsghdr_with_pad = NLMSG_ALIGN(sizeof(genl_header));
  genl_header_string.Resize(genlmsghdr_with_pad);  // Zero-fill.

  nlmsghdr* pheader = reinterpret_cast<nlmsghdr*>(result.GetData());
  pheader->nlmsg_len += genlmsghdr_with_pad;
  result.Append(genl_header_string);
  return result;
}

ByteString GenericNetlinkMessage::Encode(uint32_t sequence_number) {
  ByteString result(EncodeHeader(sequence_number));
  if (result.GetLength() == 0) {
    LOG(ERROR) << "Couldn't encode message header.";
    return result;
  }

  // Build and append attributes (padding is included by
  // AttributeList::Encode).
  ByteString attribute_string = attributes_->Encode();

  // Need to re-calculate |header| since |Append|, above, moves the data.
  nlmsghdr* pheader = reinterpret_cast<nlmsghdr*>(result.GetData());
  pheader->nlmsg_len += attribute_string.GetLength();
  result.Append(attribute_string);

  return result;
}

bool GenericNetlinkMessage::InitAndStripHeader(NetlinkPacket* packet) {
  if (!packet) {
    LOG(ERROR) << "NULL packet";
    return false;
  }
  if (!NetlinkMessage::InitAndStripHeader(packet)) {
    return false;
  }

  genlmsghdr gnlh;
  if (!packet->ConsumeData(sizeof(gnlh), &gnlh)) {
    return false;
  }

  if (command_ != gnlh.cmd) {
    LOG(WARNING) << "This object thinks it's a " << command_
                 << " but the message thinks it's a " << gnlh.cmd;
  }

  return true;
}

void GenericNetlinkMessage::Print(int header_log_level,
                                  int detail_log_level) const {
  VLOG(header_log_level) << StringPrintf("Message %s (%d)",
                                         command_string(),
                                         command());
  attributes_->Print(detail_log_level, 1);
}

// Control Message

const uint16_t ControlNetlinkMessage::kMessageType = GENL_ID_CTRL;

bool ControlNetlinkMessage::InitFromPacket(
    NetlinkPacket* packet, NetlinkMessage::MessageContext context) {
  if (!packet) {
    LOG(ERROR) << "Null |packet| parameter";
    return false;
  }

  if (!InitAndStripHeader(packet)) {
    return false;
  }

  return packet->ConsumeAttributes(
      Bind(&NetlinkAttribute::NewControlAttributeFromId), attributes_);
}

// Specific Control types.

const uint8_t NewFamilyMessage::kCommand = CTRL_CMD_NEWFAMILY;
const char NewFamilyMessage::kCommandString[] = "CTRL_CMD_NEWFAMILY";

const uint8_t GetFamilyMessage::kCommand = CTRL_CMD_GETFAMILY;
const char GetFamilyMessage::kCommandString[] = "CTRL_CMD_GETFAMILY";

GetFamilyMessage::GetFamilyMessage()
    : ControlNetlinkMessage(kCommand, kCommandString) {
  attributes()->CreateStringAttribute(CTRL_ATTR_FAMILY_NAME,
                                      "CTRL_ATTR_FAMILY_NAME");
}

// static
NetlinkMessage* ControlNetlinkMessage::CreateMessage(
    const NetlinkPacket& packet) {
  genlmsghdr header;
  if (!packet.GetGenlMsgHdr(&header)) {
    LOG(ERROR) << "Could not read genl header.";
    return nullptr;
  }

  switch (header.cmd) {
    case NewFamilyMessage::kCommand:
      return new NewFamilyMessage();
    case GetFamilyMessage::kCommand:
      return new GetFamilyMessage();
    default:
      LOG(WARNING) << "Unknown/unhandled netlink control message "
                   << header.cmd;
      return new UnknownControlMessage(header.cmd);
      break;
  }
  return nullptr;
}

}  // namespace shill.