nl80211_packet.cpp revision e6dce59eaa5f1fcbdfb4b3fc6a60d5cd3b522b06
1337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang/*
2337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang * Copyright (C) 2016 The Android Open Source Project
3337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang *
4337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang * Licensed under the Apache License, Version 2.0 (the "License");
5337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang * you may not use this file except in compliance with the License.
6337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang * You may obtain a copy of the License at
7337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang *
8337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang *      http://www.apache.org/licenses/LICENSE-2.0
9337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang *
10337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang * Unless required by applicable law or agreed to in writing, software
11337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang * distributed under the License is distributed on an "AS IS" BASIS,
12337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang * See the License for the specific language governing permissions and
14337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang * limitations under the License.
15337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang */
16337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang
17808c670699b218f8cc16f83e81be408ae441d44aNingyuan Wang#include "wificond/net/nl80211_packet.h"
18337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang
19337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang#include <android-base/logging.h>
20337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang
21337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wangusing std::vector;
22337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang
23337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wangnamespace android {
24337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wangnamespace wificond {
25337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang
26337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan WangNL80211Packet::NL80211Packet(const vector<uint8_t>& data)
27337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang    : data_(data) {
28337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  data_ = data;
29337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang}
30337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang
317397e6b7c3635e2121f6d2229557e684bc4756cfNingyuan WangNL80211Packet::NL80211Packet(uint16_t type,
327397e6b7c3635e2121f6d2229557e684bc4756cfNingyuan Wang                             uint8_t command,
337397e6b7c3635e2121f6d2229557e684bc4756cfNingyuan Wang                             uint32_t sequence,
347397e6b7c3635e2121f6d2229557e684bc4756cfNingyuan Wang                             uint32_t pid) {
35337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  // Initialize the netlink header and generic netlink header.
36337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  // NLMSG_HDRLEN and GENL_HDRLEN already include the padding size.
37337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  data_.resize(NLMSG_HDRLEN + GENL_HDRLEN, 0);
38337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  // Initialize length field.
39337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  nlmsghdr* nl_header = reinterpret_cast<nlmsghdr*>(data_.data());
40337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  nl_header->nlmsg_len = data_.size();
41337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  // Add NLM_F_REQUEST flag.
42337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  nl_header->nlmsg_flags = nl_header->nlmsg_flags | NLM_F_REQUEST;
437397e6b7c3635e2121f6d2229557e684bc4756cfNingyuan Wang  nl_header->nlmsg_type = type;
447397e6b7c3635e2121f6d2229557e684bc4756cfNingyuan Wang  nl_header->nlmsg_seq = sequence;
457397e6b7c3635e2121f6d2229557e684bc4756cfNingyuan Wang  nl_header->nlmsg_pid = pid;
46337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang
47337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  genlmsghdr* genl_header =
48337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang      reinterpret_cast<genlmsghdr*>(data_.data() + NLMSG_HDRLEN);
49337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  genl_header->version = 1;
507397e6b7c3635e2121f6d2229557e684bc4756cfNingyuan Wang  genl_header->cmd = command;
51337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  // genl_header->reserved is aready 0.
52337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang}
53337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang
54337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wangbool NL80211Packet::IsValid() const {
55337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  // Verify the size of packet.
56337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  if (data_.size() < NLMSG_HDRLEN) {
57337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang    LOG(ERROR) << "Cannot retrieve netlink header.";
58337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang    return false;
59337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  }
60337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang
61337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  // If type < NLMSG_MIN_TYPE, this should be a reserved control message,
62337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  // which doesn't carry a generic netlink header.
63337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  if (GetMessageType() >= NLMSG_MIN_TYPE) {
64337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang    if (data_.size() < NLMSG_HDRLEN + GENL_HDRLEN) {
65337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang      LOG(ERROR) << "Cannot retrieve generic netlink header.";
66337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang      return false;
67337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang    }
68337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  }
69337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  const nlmsghdr* nl_header = reinterpret_cast<const nlmsghdr*>(data_.data());
70337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  // Verify the netlink header.
71337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  if (data_.size() < nl_header->nlmsg_len ||
72337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang      nl_header->nlmsg_len < sizeof(nlmsghdr)) {
73337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang    LOG(ERROR) << "Discarding incomplete / invalid message.";
74337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang    return false;
75337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  }
76337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  return true;
77337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang}
78337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang
79337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wangbool NL80211Packet::IsDump() const {
80337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  return GetFlags() & NLM_F_DUMP;
81337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang}
82337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang
83337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wangbool NL80211Packet::IsMulti() const {
84337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  return GetFlags() & NLM_F_MULTI;
85337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang}
86337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang
87337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wanguint8_t NL80211Packet::GetCommand() const {
88337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  const genlmsghdr* genl_header = reinterpret_cast<const genlmsghdr*>(
89337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang      data_.data() + NLMSG_HDRLEN);
90337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  return genl_header->cmd;
91337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang}
92337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang
93337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wanguint16_t NL80211Packet::GetFlags() const {
94337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  const nlmsghdr* nl_header = reinterpret_cast<const nlmsghdr*>(data_.data());
95337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  return nl_header->nlmsg_flags;
96337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang}
97337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang
98337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wanguint16_t NL80211Packet::GetMessageType() const {
99337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  const nlmsghdr* nl_header = reinterpret_cast<const nlmsghdr*>(data_.data());
100337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  return nl_header->nlmsg_type;
101337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang}
102337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang
103337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wanguint32_t NL80211Packet::GetMessageSequence() const {
104337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  const nlmsghdr* nl_header = reinterpret_cast<const nlmsghdr*>(data_.data());
105337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  return nl_header->nlmsg_seq;
106337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang}
107337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang
108337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wanguint32_t NL80211Packet::GetPortId() const {
109337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  const nlmsghdr* nl_header = reinterpret_cast<const nlmsghdr*>(data_.data());
110337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  return nl_header->nlmsg_pid;
111337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang}
112337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang
1137397e6b7c3635e2121f6d2229557e684bc4756cfNingyuan Wangconst vector<uint8_t>& NL80211Packet::GetConstData() const {
1147397e6b7c3635e2121f6d2229557e684bc4756cfNingyuan Wang  return data_;
1157397e6b7c3635e2121f6d2229557e684bc4756cfNingyuan Wang}
1167397e6b7c3635e2121f6d2229557e684bc4756cfNingyuan Wang
117337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wangvoid NL80211Packet::SetCommand(uint8_t command) {
118337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  genlmsghdr* genl_header = reinterpret_cast<genlmsghdr*>(
119337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang      data_.data() + NLMSG_HDRLEN);
120337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  genl_header->cmd = command;
121337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang}
122337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang
123e6dce59eaa5f1fcbdfb4b3fc6a60d5cd3b522b06Ningyuan Wangvoid NL80211Packet::AddFlag(uint16_t flag) {
124e6dce59eaa5f1fcbdfb4b3fc6a60d5cd3b522b06Ningyuan Wang  nlmsghdr* nl_header = reinterpret_cast<nlmsghdr*>(data_.data());
125e6dce59eaa5f1fcbdfb4b3fc6a60d5cd3b522b06Ningyuan Wang  nl_header->nlmsg_flags |= flag;
126e6dce59eaa5f1fcbdfb4b3fc6a60d5cd3b522b06Ningyuan Wang}
127e6dce59eaa5f1fcbdfb4b3fc6a60d5cd3b522b06Ningyuan Wang
128337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wangvoid NL80211Packet::SetFlags(uint16_t flags) {
129337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  nlmsghdr* nl_header = reinterpret_cast<nlmsghdr*>(data_.data());
130337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  nl_header->nlmsg_flags = flags;
131337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang}
132337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang
133337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wangvoid NL80211Packet::SetMessageType(uint16_t message_type) {
134337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  nlmsghdr* nl_header = reinterpret_cast<nlmsghdr*>(data_.data());
135337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  nl_header->nlmsg_type = message_type;
136337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang}
137337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang
138337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wangvoid NL80211Packet::SetMessageSequence(uint32_t message_sequence) {
139337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  nlmsghdr* nl_header = reinterpret_cast<nlmsghdr*>(data_.data());
140337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  nl_header->nlmsg_seq = message_sequence;
141337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang}
142337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang
143337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wangvoid NL80211Packet::SetPortId(uint32_t pid) {
144337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  nlmsghdr* nl_header = reinterpret_cast<nlmsghdr*>(data_.data());
145337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  nl_header->nlmsg_pid = pid;
146337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang}
147337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang
148337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wangvoid NL80211Packet::AddAttribute(const BaseNL80211Attr& attribute) {
149337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  const vector<uint8_t>& append_data = attribute.GetConstData();
150337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  // Append the data of |attribute| to |this|.
151337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  data_.insert(data_.end(), append_data.begin(), append_data.end());
152337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  nlmsghdr* nl_header = reinterpret_cast<nlmsghdr*>(data_.data());
153337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  // We don't need to worry about padding for a nl80211 packet.
154337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  // Because as long as all sub attributes have padding, the payload is aligned.
155337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  nl_header->nlmsg_len += append_data.size();
156337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang}
157337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang
158337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wangvoid NL80211Packet::AddFlagAttribute(int attribute_id) {
159337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  // We only need to append a header for flag attribute.
160337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  // Make space for the new attribute.
161337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  data_.resize(data_.size() + NLA_HDRLEN, 0);
162337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  nlattr* flag_header =
163337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang      reinterpret_cast<nlattr*>(data_.data() + data_.size() - NLA_HDRLEN);
164337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  flag_header->nla_type = attribute_id;
165337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  flag_header->nla_len = NLA_HDRLEN;
166337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  nlmsghdr* nl_header = reinterpret_cast<nlmsghdr*>(data_.data());
167337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  nl_header->nlmsg_len += NLA_HDRLEN;
168337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang}
169337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang
170337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wangbool NL80211Packet::HasAttribute(int id) const {
171337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  return BaseNL80211Attr::GetAttributeImpl(
172337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang      data_.data() + NLMSG_HDRLEN + GENL_HDRLEN,
173337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang      data_.size() - NLMSG_HDRLEN - GENL_HDRLEN,
174337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang      id, nullptr, nullptr);
175337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang}
176337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang
177337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wangbool NL80211Packet::GetAttribute(int id,
178337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang    NL80211NestedAttr* attribute) const {
179337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  uint8_t* start = nullptr;
180337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  uint8_t* end = nullptr;
181337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  if (!BaseNL80211Attr::GetAttributeImpl(
182337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang          data_.data() + NLMSG_HDRLEN + GENL_HDRLEN,
183337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang          data_.size() - NLMSG_HDRLEN - GENL_HDRLEN,
184337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang          id, &start, &end) ||
185337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang      start == nullptr ||
186337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang      end == nullptr) {
187337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang    return false;
188337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  }
189337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  *attribute = NL80211NestedAttr(vector<uint8_t>(start, end));
190337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  if (!attribute->IsValid()) {
191337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang    return false;
192337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  }
193337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang  return true;
194337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang}
195337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang
196337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang}  // namespace wificond
197337a336edb8fc48848883a4c0d7a91e63f445f6fNingyuan Wang}  // namespace android
198