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