• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 "wificond/net/nl80211_packet.h"
18 
19 #include <android-base/logging.h>
20 
21 using std::make_unique;
22 using std::unique_ptr;
23 using std::vector;
24 
25 namespace android {
26 namespace wificond {
27 
NL80211Packet(const vector<uint8_t> & data)28 NL80211Packet::NL80211Packet(const vector<uint8_t>& data)
29     : data_(data) {
30   data_ = data;
31 }
32 
NL80211Packet(const NL80211Packet & packet)33 NL80211Packet::NL80211Packet(const NL80211Packet& packet) {
34   data_ = packet.data_;
35   LOG(WARNING) << "Copy constructor is only used for unit tests";
36 }
37 
NL80211Packet(uint16_t type,uint8_t command,uint32_t sequence,uint32_t pid)38 NL80211Packet::NL80211Packet(uint16_t type,
39                              uint8_t command,
40                              uint32_t sequence,
41                              uint32_t pid) {
42   // Initialize the netlink header and generic netlink header.
43   // NLMSG_HDRLEN and GENL_HDRLEN already include the padding size.
44   data_.resize(NLMSG_HDRLEN + GENL_HDRLEN, 0);
45   // Initialize length field.
46   nlmsghdr* nl_header = reinterpret_cast<nlmsghdr*>(data_.data());
47   nl_header->nlmsg_len = data_.size();
48   // Add NLM_F_REQUEST flag.
49   nl_header->nlmsg_flags = nl_header->nlmsg_flags | NLM_F_REQUEST;
50   nl_header->nlmsg_type = type;
51   nl_header->nlmsg_seq = sequence;
52   nl_header->nlmsg_pid = pid;
53 
54   genlmsghdr* genl_header =
55       reinterpret_cast<genlmsghdr*>(data_.data() + NLMSG_HDRLEN);
56   genl_header->version = 1;
57   genl_header->cmd = command;
58   // genl_header->reserved is aready 0.
59 }
60 
IsValid() const61 bool NL80211Packet::IsValid() const {
62   // Verify the size of packet.
63   if (data_.size() < NLMSG_HDRLEN) {
64     LOG(ERROR) << "Cannot retrieve netlink header.";
65     return false;
66   }
67 
68   const nlmsghdr* nl_header = reinterpret_cast<const nlmsghdr*>(data_.data());
69 
70   // If type < NLMSG_MIN_TYPE, this should be a reserved control message,
71   // which doesn't carry a generic netlink header.
72   if (GetMessageType() >= NLMSG_MIN_TYPE) {
73     if (data_.size() < NLMSG_HDRLEN + GENL_HDRLEN ||
74         nl_header->nlmsg_len < NLMSG_HDRLEN + GENL_HDRLEN) {
75       LOG(ERROR) << "Cannot retrieve generic netlink header.";
76       return false;
77     }
78   }
79   // If it is an ERROR message, it should be long enough to carry an extra error
80   // code field.
81   // Kernel uses int for this field.
82   if (GetMessageType() == NLMSG_ERROR) {
83     if (data_.size() < NLMSG_HDRLEN + sizeof(int) ||
84         nl_header->nlmsg_len < NLMSG_HDRLEN + sizeof(int)) {
85      LOG(ERROR) << "Broken error message.";
86      return false;
87     }
88   }
89 
90   // Verify the netlink header.
91   if (data_.size() < nl_header->nlmsg_len ||
92       nl_header->nlmsg_len < sizeof(nlmsghdr)) {
93     LOG(ERROR) << "Discarding incomplete / invalid message.";
94     return false;
95   }
96   return true;
97 }
98 
IsDump() const99 bool NL80211Packet::IsDump() const {
100   return GetFlags() & NLM_F_DUMP;
101 }
102 
IsMulti() const103 bool NL80211Packet::IsMulti() const {
104   return GetFlags() & NLM_F_MULTI;
105 }
106 
GetCommand() const107 uint8_t NL80211Packet::GetCommand() const {
108   const genlmsghdr* genl_header = reinterpret_cast<const genlmsghdr*>(
109       data_.data() + NLMSG_HDRLEN);
110   return genl_header->cmd;
111 }
112 
GetFlags() const113 uint16_t NL80211Packet::GetFlags() const {
114   const nlmsghdr* nl_header = reinterpret_cast<const nlmsghdr*>(data_.data());
115   return nl_header->nlmsg_flags;
116 }
117 
GetMessageType() const118 uint16_t NL80211Packet::GetMessageType() const {
119   const nlmsghdr* nl_header = reinterpret_cast<const nlmsghdr*>(data_.data());
120   return nl_header->nlmsg_type;
121 }
122 
GetMessageSequence() const123 uint32_t NL80211Packet::GetMessageSequence() const {
124   const nlmsghdr* nl_header = reinterpret_cast<const nlmsghdr*>(data_.data());
125   return nl_header->nlmsg_seq;
126 }
127 
GetPortId() const128 uint32_t NL80211Packet::GetPortId() const {
129   const nlmsghdr* nl_header = reinterpret_cast<const nlmsghdr*>(data_.data());
130   return nl_header->nlmsg_pid;
131 }
132 
GetErrorCode() const133 int NL80211Packet::GetErrorCode() const {
134   return -*reinterpret_cast<const int*>(data_.data() + NLMSG_HDRLEN);
135 }
136 
GetConstData() const137 const vector<uint8_t>& NL80211Packet::GetConstData() const {
138   return data_;
139 }
140 
SetCommand(uint8_t command)141 void NL80211Packet::SetCommand(uint8_t command) {
142   genlmsghdr* genl_header = reinterpret_cast<genlmsghdr*>(
143       data_.data() + NLMSG_HDRLEN);
144   genl_header->cmd = command;
145 }
146 
AddFlag(uint16_t flag)147 void NL80211Packet::AddFlag(uint16_t flag) {
148   nlmsghdr* nl_header = reinterpret_cast<nlmsghdr*>(data_.data());
149   nl_header->nlmsg_flags |= flag;
150 }
151 
SetFlags(uint16_t flags)152 void NL80211Packet::SetFlags(uint16_t flags) {
153   nlmsghdr* nl_header = reinterpret_cast<nlmsghdr*>(data_.data());
154   nl_header->nlmsg_flags = flags;
155 }
156 
SetMessageType(uint16_t message_type)157 void NL80211Packet::SetMessageType(uint16_t message_type) {
158   nlmsghdr* nl_header = reinterpret_cast<nlmsghdr*>(data_.data());
159   nl_header->nlmsg_type = message_type;
160 }
161 
SetMessageSequence(uint32_t message_sequence)162 void NL80211Packet::SetMessageSequence(uint32_t message_sequence) {
163   nlmsghdr* nl_header = reinterpret_cast<nlmsghdr*>(data_.data());
164   nl_header->nlmsg_seq = message_sequence;
165 }
166 
SetPortId(uint32_t pid)167 void NL80211Packet::SetPortId(uint32_t pid) {
168   nlmsghdr* nl_header = reinterpret_cast<nlmsghdr*>(data_.data());
169   nl_header->nlmsg_pid = pid;
170 }
171 
AddAttribute(const BaseNL80211Attr & attribute)172 void NL80211Packet::AddAttribute(const BaseNL80211Attr& attribute) {
173   const vector<uint8_t>& append_data = attribute.GetConstData();
174   // Append the data of |attribute| to |this|.
175   data_.insert(data_.end(), append_data.begin(), append_data.end());
176   nlmsghdr* nl_header = reinterpret_cast<nlmsghdr*>(data_.data());
177   // We don't need to worry about padding for a nl80211 packet.
178   // Because as long as all sub attributes have padding, the payload is aligned.
179   nl_header->nlmsg_len += append_data.size();
180 }
181 
AddFlagAttribute(int attribute_id)182 void NL80211Packet::AddFlagAttribute(int attribute_id) {
183   // We only need to append a header for flag attribute.
184   // Make space for the new attribute.
185   data_.resize(data_.size() + NLA_HDRLEN, 0);
186   nlattr* flag_header =
187       reinterpret_cast<nlattr*>(data_.data() + data_.size() - NLA_HDRLEN);
188   flag_header->nla_type = attribute_id;
189   flag_header->nla_len = NLA_HDRLEN;
190   nlmsghdr* nl_header = reinterpret_cast<nlmsghdr*>(data_.data());
191   nl_header->nlmsg_len += NLA_HDRLEN;
192 }
193 
HasAttribute(int id) const194 bool NL80211Packet::HasAttribute(int id) const {
195   return BaseNL80211Attr::GetAttributeImpl(
196       data_.data() + NLMSG_HDRLEN + GENL_HDRLEN,
197       data_.size() - NLMSG_HDRLEN - GENL_HDRLEN,
198       id, nullptr, nullptr);
199 }
200 
GetAttribute(int id,NL80211NestedAttr * attribute) const201 bool NL80211Packet::GetAttribute(int id,
202     NL80211NestedAttr* attribute) const {
203   uint8_t* start = nullptr;
204   uint8_t* end = nullptr;
205   if (!BaseNL80211Attr::GetAttributeImpl(
206           data_.data() + NLMSG_HDRLEN + GENL_HDRLEN,
207           data_.size() - NLMSG_HDRLEN - GENL_HDRLEN,
208           id, &start, &end) ||
209       start == nullptr ||
210       end == nullptr) {
211     return false;
212   }
213   *attribute = NL80211NestedAttr(vector<uint8_t>(start, end));
214   if (!attribute->IsValid()) {
215     return false;
216   }
217   return true;
218 }
219 
GetAllAttributes(vector<BaseNL80211Attr> * attributes) const220 bool NL80211Packet::GetAllAttributes(
221     vector<BaseNL80211Attr>* attributes) const {
222   const uint8_t* ptr = data_.data() + NLMSG_HDRLEN + GENL_HDRLEN;
223   const uint8_t* end_ptr = data_.data() + data_.size();
224   while (ptr + NLA_HDRLEN <= end_ptr) {
225     auto header = reinterpret_cast<const nlattr*>(ptr);
226     if (ptr + NLA_ALIGN(header->nla_len) > end_ptr ||
227       header->nla_len == 0) {
228       LOG(ERROR) << "broken nl80211 atrribute.";
229       return false;
230     }
231     attributes->emplace_back(
232         header->nla_type,
233         vector<uint8_t>(ptr + NLA_HDRLEN, ptr + header->nla_len));
234     ptr += NLA_ALIGN(header->nla_len);
235   }
236   return true;
237 }
238 
DebugLog() const239 void NL80211Packet::DebugLog() const {
240   const uint8_t* ptr = data_.data() + NLMSG_HDRLEN + GENL_HDRLEN;
241   const uint8_t* end_ptr = data_.data() + data_.size();
242   while (ptr + NLA_HDRLEN <= end_ptr) {
243     const nlattr* header = reinterpret_cast<const nlattr*>(ptr);
244     if (ptr + NLA_ALIGN(header->nla_len) > end_ptr) {
245       LOG(ERROR) << "broken nl80211 atrribute.";
246       return;
247     }
248     LOG(INFO) << "Have attribute with nla_type=" << header->nla_type
249               << " and nla_len=" << header->nla_len;
250     if (header->nla_len == 0) {
251       LOG(ERROR) << "0 is a bad nla_len";
252       return;
253     }
254     ptr += NLA_ALIGN(header->nla_len);
255   }
256 }
257 
258 }  // namespace wificond
259 }  // namespace android
260