1//
2// Copyright (C) 2012 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 "shill/net/attribute_list.h"
18
19#include <ctype.h>
20#include <linux/nl80211.h>
21
22#include <iomanip>
23#include <map>
24#include <string>
25
26#include <base/logging.h>
27#include <base/stl_util.h>
28#include <base/strings/stringprintf.h>
29
30#include "shill/net/netlink_attribute.h"
31#include "shill/net/netlink_message.h"
32
33using base::StringAppendF;
34using base::WeakPtr;
35using std::map;
36using std::string;
37
38namespace shill {
39
40bool AttributeList::CreateAttribute(
41    int id, AttributeList::NewFromIdMethod factory) {
42  if (ContainsKey(attributes_, id)) {
43    VLOG(7) << "Trying to re-add attribute " << id << ", not overwriting";
44    return true;
45  }
46  attributes_[id] = AttributePointer(factory.Run(id));
47  return true;
48}
49
50bool AttributeList::CreateControlAttribute(int id) {
51  return CreateAttribute(
52      id, base::Bind(&NetlinkAttribute::NewControlAttributeFromId));
53}
54
55bool AttributeList::CreateNl80211Attribute(
56    int id, NetlinkMessage::MessageContext context) {
57  return CreateAttribute(
58      id, base::Bind(&NetlinkAttribute::NewNl80211AttributeFromId, context));
59}
60
61bool AttributeList::CreateAndInitAttribute(
62    const AttributeList::NewFromIdMethod& factory,
63    int id, const ByteString& value) {
64  if (!CreateAttribute(id, factory)) {
65    return false;
66  }
67  return InitAttributeFromValue(id, value);
68}
69
70bool AttributeList::InitAttributeFromValue(int id, const ByteString& value) {
71  NetlinkAttribute* attribute = GetAttribute(id);
72  if (!attribute)
73    return false;
74  return attribute->InitFromValue(value);
75}
76
77void AttributeList::Print(int log_level, int indent) const {
78  map<int, AttributePointer>::const_iterator i;
79
80  for (i = attributes_.begin(); i != attributes_.end(); ++i) {
81    i->second->Print(log_level, indent);
82  }
83}
84
85// static
86bool AttributeList::IterateAttributes(
87    const ByteString& payload, size_t offset,
88    const AttributeList::AttributeMethod& method) {
89  const unsigned char* ptr = payload.GetConstData() + NLA_ALIGN(offset);
90  const unsigned char* end = payload.GetConstData() + payload.GetLength();
91  while (ptr + sizeof(nlattr) <= end) {
92    const nlattr* attribute = reinterpret_cast<const nlattr*>(ptr);
93    if (attribute->nla_len < sizeof(*attribute) ||
94        ptr + attribute->nla_len > end) {
95      LOG(ERROR) << "Malformed nla attribute indicates length "
96                 << attribute->nla_len << ".  "
97                 << (end - ptr - NLA_HDRLEN) << " bytes remain in buffer.  "
98                 << "Error occurred at offset "
99                 << (ptr - payload.GetConstData()) << ".";
100      return false;
101    }
102    ByteString value;
103    if (attribute->nla_len > NLA_HDRLEN) {
104      value = ByteString(ptr + NLA_HDRLEN, attribute->nla_len - NLA_HDRLEN);
105    }
106    if (!method.Run(attribute->nla_type, value)) {
107      return false;
108    }
109    ptr += NLA_ALIGN(attribute->nla_len);
110  }
111  if (ptr < end) {
112    LOG(INFO) << "Decode left " << (end - ptr) << " unparsed bytes.";
113  }
114  return true;
115}
116
117bool AttributeList::Decode(const ByteString& payload,
118                           size_t offset,
119                           const AttributeList::NewFromIdMethod& factory) {
120  return IterateAttributes(
121      payload, offset, base::Bind(&AttributeList::CreateAndInitAttribute,
122                                  base::Unretained(this), factory));
123}
124
125ByteString AttributeList::Encode() const {
126  ByteString result;
127  map<int, AttributePointer>::const_iterator i;
128
129  for (i = attributes_.begin(); i != attributes_.end(); ++i) {
130    result.Append(i->second->Encode());
131  }
132  return result;
133}
134
135// U8 Attribute.
136
137bool AttributeList::GetU8AttributeValue(int id, uint8_t* value) const {
138  NetlinkAttribute* attribute = GetAttribute(id);
139  if (!attribute)
140    return false;
141  return attribute->GetU8Value(value);
142}
143
144bool AttributeList::CreateU8Attribute(int id, const char* id_string) {
145  if (ContainsKey(attributes_, id)) {
146    LOG(ERROR) << "Trying to re-add attribute: " << id;
147    return false;
148  }
149  attributes_[id] = AttributePointer(
150      new NetlinkU8Attribute(id, id_string));
151  return true;
152}
153
154bool AttributeList::SetU8AttributeValue(int id, uint8_t value) {
155  NetlinkAttribute* attribute = GetAttribute(id);
156  if (!attribute)
157    return false;
158  return attribute->SetU8Value(value);
159}
160
161
162// U16 Attribute.
163
164bool AttributeList::GetU16AttributeValue(int id, uint16_t* value) const {
165  NetlinkAttribute* attribute = GetAttribute(id);
166  if (!attribute)
167    return false;
168  return attribute->GetU16Value(value);
169}
170
171bool AttributeList::CreateU16Attribute(int id, const char* id_string) {
172  if (ContainsKey(attributes_, id)) {
173    LOG(ERROR) << "Trying to re-add attribute: " << id;
174    return false;
175  }
176  attributes_[id] = AttributePointer(
177      new NetlinkU16Attribute(id, id_string));
178  return true;
179}
180
181bool AttributeList::SetU16AttributeValue(int id, uint16_t value) {
182  NetlinkAttribute* attribute = GetAttribute(id);
183  if (!attribute)
184    return false;
185  return attribute->SetU16Value(value);
186}
187
188// U32 Attribute.
189
190bool AttributeList::GetU32AttributeValue(int id, uint32_t* value) const {
191  NetlinkAttribute* attribute = GetAttribute(id);
192  if (!attribute)
193    return false;
194  return attribute->GetU32Value(value);
195}
196
197bool AttributeList::CreateU32Attribute(int id, const char* id_string) {
198  if (ContainsKey(attributes_, id)) {
199    LOG(ERROR) << "Trying to re-add attribute: " << id;
200    return false;
201  }
202  attributes_[id] = AttributePointer(
203      new NetlinkU32Attribute(id, id_string));
204  return true;
205}
206
207bool AttributeList::SetU32AttributeValue(int id, uint32_t value) {
208  NetlinkAttribute* attribute = GetAttribute(id);
209  if (!attribute)
210    return false;
211  return attribute->SetU32Value(value);
212}
213
214// U64 Attribute.
215
216bool AttributeList::GetU64AttributeValue(int id, uint64_t* value) const {
217  NetlinkAttribute* attribute = GetAttribute(id);
218  if (!attribute)
219    return false;
220  return attribute->GetU64Value(value);
221}
222
223bool AttributeList::CreateU64Attribute(int id, const char* id_string) {
224  if (ContainsKey(attributes_, id)) {
225    LOG(ERROR) << "Trying to re-add attribute: " << id;
226    return false;
227  }
228  attributes_[id] = AttributePointer(
229      new NetlinkU64Attribute(id, id_string));
230  return true;
231}
232
233bool AttributeList::SetU64AttributeValue(int id, uint64_t value) {
234  NetlinkAttribute* attribute = GetAttribute(id);
235  if (!attribute)
236    return false;
237  return attribute->SetU64Value(value);
238}
239
240// Flag Attribute.
241
242bool AttributeList::GetFlagAttributeValue(int id, bool* value) const {
243  NetlinkAttribute* attribute = GetAttribute(id);
244  if (!attribute)
245    return false;
246  return attribute->GetFlagValue(value);
247}
248
249bool AttributeList::CreateFlagAttribute(int id, const char* id_string) {
250  if (ContainsKey(attributes_, id)) {
251    LOG(ERROR) << "Trying to re-add attribute: " << id;
252    return false;
253  }
254  attributes_[id] = AttributePointer(
255      new NetlinkFlagAttribute(id, id_string));
256  return true;
257}
258
259bool AttributeList::SetFlagAttributeValue(int id, bool value) {
260  NetlinkAttribute* attribute = GetAttribute(id);
261  if (!attribute)
262    return false;
263  return attribute->SetFlagValue(value);
264}
265
266bool AttributeList::IsFlagAttributeTrue(int id) const {
267  bool flag;
268  if (!GetFlagAttributeValue(id, &flag)) {
269    return false;
270  }
271  return flag;
272}
273
274// String Attribute.
275
276bool AttributeList::GetStringAttributeValue(int id, string* value) const {
277  NetlinkAttribute* attribute = GetAttribute(id);
278  if (!attribute)
279    return false;
280  return attribute->GetStringValue(value);
281}
282
283bool AttributeList::CreateStringAttribute(int id, const char* id_string) {
284  if (ContainsKey(attributes_, id)) {
285    LOG(ERROR) << "Trying to re-add attribute: " << id;
286    return false;
287  }
288  attributes_[id] = AttributePointer(
289      new NetlinkStringAttribute(id, id_string));
290  return true;
291}
292
293bool AttributeList::CreateSsidAttribute(int id, const char* id_string) {
294  if (ContainsKey(attributes_, id)) {
295    LOG(ERROR) << "Trying to re-add attribute: " << id;
296    return false;
297  }
298  attributes_[id] = AttributePointer(
299      new NetlinkSsidAttribute(id, id_string));
300  return true;
301}
302
303bool AttributeList::SetStringAttributeValue(int id, string value) {
304  NetlinkAttribute* attribute = GetAttribute(id);
305  if (!attribute)
306    return false;
307  return attribute->SetStringValue(value);
308}
309
310// Nested Attribute.
311
312bool AttributeList::GetNestedAttributeList(int id,
313                                           AttributeListRefPtr* value) {
314  NetlinkAttribute* attribute = GetAttribute(id);
315  if (!attribute)
316    return false;
317  return attribute->GetNestedAttributeList(value);
318}
319
320bool AttributeList::ConstGetNestedAttributeList(
321    int id, AttributeListConstRefPtr* value) const {
322  NetlinkAttribute* attribute = GetAttribute(id);
323  if (!attribute)
324    return false;
325  return attribute->ConstGetNestedAttributeList(value);
326}
327
328bool AttributeList::SetNestedAttributeHasAValue(int id) {
329  NetlinkAttribute* attribute = GetAttribute(id);
330  if (!attribute)
331    return false;
332  return attribute->SetNestedHasAValue();
333}
334
335bool AttributeList::CreateNestedAttribute(int id, const char* id_string) {
336  if (ContainsKey(attributes_, id)) {
337    LOG(ERROR) << "Trying to re-add attribute: " << id;
338    return false;
339  }
340  attributes_[id] = AttributePointer(
341      new NetlinkNestedAttribute(id, id_string));
342  return true;
343}
344
345// Raw Attribute.
346
347bool AttributeList::GetRawAttributeValue(int id,
348                                         ByteString* output) const {
349  NetlinkAttribute* attribute = GetAttribute(id);
350  if (!attribute)
351    return false;
352
353  ByteString raw_value;
354
355  if (!attribute->GetRawValue(&raw_value))
356    return false;
357
358  if (output) {
359    *output = raw_value;
360  }
361  return true;
362}
363
364bool AttributeList::SetRawAttributeValue(int id, ByteString value) {
365  NetlinkAttribute* attribute = GetAttribute(id);
366  if (!attribute)
367    return false;
368  return attribute->SetRawValue(value);
369}
370
371bool AttributeList::CreateRawAttribute(int id, const char* id_string) {
372  if (ContainsKey(attributes_, id)) {
373    LOG(ERROR) << "Trying to re-add attribute: " << id;
374    return false;
375  }
376  attributes_[id] = AttributePointer(new NetlinkRawAttribute(id, id_string));
377  return true;
378}
379
380bool AttributeList::GetAttributeAsString(int id, std::string* value) const {
381  NetlinkAttribute* attribute = GetAttribute(id);
382  if (!attribute)
383    return false;
384
385  return attribute->ToString(value);
386}
387
388NetlinkAttribute* AttributeList::GetAttribute(int id) const {
389  map<int, AttributePointer>::const_iterator i;
390  i = attributes_.find(id);
391  if (i == attributes_.end()) {
392    return nullptr;
393  }
394  return i->second.get();
395}
396
397}  // namespace shill
398