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 #ifndef SHILL_NET_NETLINK_ATTRIBUTE_H_
18 #define SHILL_NET_NETLINK_ATTRIBUTE_H_
19 
20 #include <map>
21 #include <string>
22 #include <utility>
23 #include <vector>
24 
25 #include <base/macros.h>
26 
27 #include "shill/net/attribute_list.h"
28 #include "shill/net/byte_string.h"
29 #include "shill/net/netlink_message.h"
30 
31 struct nlattr;
32 
33 namespace shill {
34 
35 // NetlinkAttribute is an abstract base class that describes an attribute in a
36 // netlink-80211 message.  Child classes are type-specific and will define
37 // Get*Value and Set*Value methods (where * is the type).  A second-level of
38 // child classes exist for each individual attribute type.
39 //
40 // An attribute has an id (which is really an enumerated value), a data type,
41 // and a value.  In an nlattr (the underlying format for an attribute in a
42 // message), the data is stored as a blob without type information; the writer
43 // and reader of the attribute must agree on the data type.
44 class SHILL_EXPORT NetlinkAttribute {
45  public:
46   enum Type {
47     kTypeU8,
48     kTypeU16,
49     kTypeU32,
50     kTypeU64,
51     kTypeFlag,
52     kTypeString,
53     kTypeNested,
54     kTypeRaw,
55     kTypeError
56   };
57 
58   NetlinkAttribute(int id, const char* id_string,
59                    Type datatype, const char* datatype_string);
~NetlinkAttribute()60   virtual ~NetlinkAttribute() {}
61 
62   // Static factories generate the appropriate attribute object from the
63   // raw nlattr data.
64   static NetlinkAttribute* NewControlAttributeFromId(int id);
65   static NetlinkAttribute* NewNl80211AttributeFromId(
66       NetlinkMessage::MessageContext context, int id);
67 
68   virtual bool InitFromValue(const ByteString& input);
69 
70   // Accessors for the attribute's id and datatype information.
id()71   int id() const { return id_; }
id_string()72   virtual const char* id_string() const { return id_string_.c_str(); }
datatype()73   Type datatype() const { return datatype_; }
datatype_string()74   const char* datatype_string() const { return datatype_string_; }
75 
76   // Accessors.  Return false if request is made on wrong type of attribute.
77   virtual bool GetU8Value(uint8_t* value) const;
78   virtual bool SetU8Value(uint8_t new_value);
79 
80   virtual bool GetU16Value(uint16_t* value) const;
81   virtual bool SetU16Value(uint16_t value);
82 
83   virtual bool GetU32Value(uint32_t* value) const;
84   virtual bool SetU32Value(uint32_t value);
85 
86   virtual bool GetU64Value(uint64_t* value) const;
87   virtual bool SetU64Value(uint64_t value);
88 
89   virtual bool GetFlagValue(bool* value) const;
90   virtual bool SetFlagValue(bool value);
91 
92   virtual bool GetStringValue(std::string* value) const;
93   virtual bool SetStringValue(const std::string value);
94 
95   virtual bool GetNestedAttributeList(AttributeListRefPtr* value);
96   virtual bool ConstGetNestedAttributeList(
97       AttributeListConstRefPtr* value) const;
98   virtual bool SetNestedHasAValue();
99 
100   virtual bool GetRawValue(ByteString* value) const;
101   virtual bool SetRawValue(const ByteString value);
102 
103   // Prints the attribute info -- for debugging.
104   virtual void Print(int log_level, int indent) const;
105 
106   // Fill a string with characters that represents the value of the attribute.
107   // If no attribute is found or if the datatype isn't trivially stringizable,
108   // this method returns 'false' and |value| remains unchanged.
109   virtual bool ToString(std::string* value) const = 0;
110 
111   // Writes the raw attribute data to a string.  For debug.
112   std::string RawToString() const;
113 
114   // Encodes the attribute suitably for the attributes in the payload portion
115   // of a netlink message suitable for Sockets::Send.  Return value is empty on
116   // failure.
117   virtual ByteString Encode() const = 0;
118 
has_a_value()119   bool has_a_value() const { return has_a_value_; }
120 
121  protected:
122   // Builds a string to precede a printout of this attribute.
123   std::string HeaderToPrint(int indent) const;
124 
125   // Encodes the attribute suitably for the attributes in the payload portion
126   // of a netlink message suitable for Sockets::Send.  Return value is empty on
127   // failure.
128   ByteString EncodeGeneric(const unsigned char* data, size_t num_bytes) const;
129 
130   // Attribute data (NOT including the nlattr header) corresponding to the
131   // value in any of the child classes.
132   ByteString data_;
133 
134   // True if a value has been assigned to the attribute; false, otherwise.
135   bool has_a_value_;
136 
137  private:
138   int id_;
139   std::string id_string_;
140   Type datatype_;
141   const char* datatype_string_;
142 
143   DISALLOW_COPY_AND_ASSIGN(NetlinkAttribute);
144 };
145 
146 class NetlinkU8Attribute : public NetlinkAttribute {
147  public:
148   static const char kMyTypeString[];
149   static const Type kType;
NetlinkU8Attribute(int id,const char * id_string)150   NetlinkU8Attribute(int id, const char* id_string)
151       : NetlinkAttribute(id, id_string, kType, kMyTypeString) {}
152   virtual bool InitFromValue(const ByteString& data);
153   virtual bool GetU8Value(uint8_t* value) const;
154   virtual bool SetU8Value(uint8_t new_value);
155   virtual bool ToString(std::string* value) const;
156   virtual ByteString Encode() const;
157 
158  private:
159   uint8_t value_;
160 
161   DISALLOW_COPY_AND_ASSIGN(NetlinkU8Attribute);
162 };
163 
164 class NetlinkU16Attribute : public NetlinkAttribute {
165  public:
166   static const char kMyTypeString[];
167   static const Type kType;
NetlinkU16Attribute(int id,const char * id_string)168   NetlinkU16Attribute(int id, const char* id_string)
169       : NetlinkAttribute(id, id_string, kType, kMyTypeString) {}
170   virtual bool InitFromValue(const ByteString& data);
171   virtual bool GetU16Value(uint16_t* value) const;
172   virtual bool SetU16Value(uint16_t new_value);
173   virtual bool ToString(std::string* value) const;
174   virtual ByteString Encode() const;
175 
176  private:
177   uint16_t value_;
178 
179   DISALLOW_COPY_AND_ASSIGN(NetlinkU16Attribute);
180 };
181 
182 // Set SHILL_EXPORT to allow unit tests to instantiate these.
183 class SHILL_EXPORT NetlinkU32Attribute : public NetlinkAttribute {
184  public:
185   static const char kMyTypeString[];
186   static const Type kType;
NetlinkU32Attribute(int id,const char * id_string)187   NetlinkU32Attribute(int id, const char* id_string)
188       : NetlinkAttribute(id, id_string, kType, kMyTypeString) {}
189   virtual bool InitFromValue(const ByteString& data);
190   virtual bool GetU32Value(uint32_t* value) const;
191   virtual bool SetU32Value(uint32_t new_value);
192   virtual bool ToString(std::string* value) const;
193   virtual ByteString Encode() const;
194 
195  private:
196   uint32_t value_;
197 
198   DISALLOW_COPY_AND_ASSIGN(NetlinkU32Attribute);
199 };
200 
201 class NetlinkU64Attribute : public NetlinkAttribute {
202  public:
203   static const char kMyTypeString[];
204   static const Type kType;
NetlinkU64Attribute(int id,const char * id_string)205   NetlinkU64Attribute(int id, const char* id_string)
206       : NetlinkAttribute(id, id_string, kType, kMyTypeString) {}
207   virtual bool InitFromValue(const ByteString& data);
208   virtual bool GetU64Value(uint64_t* value) const;
209   virtual bool SetU64Value(uint64_t new_value);
210   virtual bool ToString(std::string* value) const;
211   virtual ByteString Encode() const;
212 
213  private:
214   uint64_t value_;
215 
216   DISALLOW_COPY_AND_ASSIGN(NetlinkU64Attribute);
217 };
218 
219 class NetlinkFlagAttribute : public NetlinkAttribute {
220  public:
221   static const char kMyTypeString[];
222   static const Type kType;
NetlinkFlagAttribute(int id,const char * id_string)223   NetlinkFlagAttribute(int id, const char* id_string)
224       : NetlinkAttribute(id, id_string, kType, kMyTypeString) {}
225   virtual bool InitFromValue(const ByteString& data);
226   virtual bool GetFlagValue(bool* value) const;
227   virtual bool SetFlagValue(bool new_value);
228   virtual bool ToString(std::string* value) const;
229   virtual ByteString Encode() const;
230 
231  private:
232   bool value_;
233 
234   DISALLOW_COPY_AND_ASSIGN(NetlinkFlagAttribute);
235 };
236 
237 // Set SHILL_EXPORT to allow unit tests to instantiate these.
238 class SHILL_EXPORT NetlinkStringAttribute : public NetlinkAttribute {
239  public:
240   static const char kMyTypeString[];
241   static const Type kType;
NetlinkStringAttribute(int id,const char * id_string)242   NetlinkStringAttribute(int id, const char* id_string)
243       : NetlinkAttribute(id, id_string, kType, kMyTypeString) {}
244   virtual bool InitFromValue(const ByteString& data);
245   virtual bool GetStringValue(std::string* value) const;
246   virtual bool SetStringValue(const std::string new_value);
247   virtual bool ToString(std::string* value) const;
248   virtual ByteString Encode() const;
value()249   std::string value() const { return value_; }
set_value(const std::string & value)250   void set_value(const std::string& value) { value_ = value; }
251 
252  private:
253   std::string value_;
254   DISALLOW_COPY_AND_ASSIGN(NetlinkStringAttribute);
255 };
256 
257 // SSID attributes are just string attributes with different output semantics.
258 class NetlinkSsidAttribute : public NetlinkStringAttribute {
259  public:
NetlinkSsidAttribute(int id,const char * id_string)260   NetlinkSsidAttribute(int id, const char* id_string)
261       : NetlinkStringAttribute(id, id_string) {}
262 
263   // NOTE: |ToString| or |Print| must be used for logging to allow scrubbing.
264   virtual bool ToString(std::string* output) const;
265 
266  private:
267   DISALLOW_COPY_AND_ASSIGN(NetlinkSsidAttribute);
268 };
269 
270 class NetlinkNestedAttribute : public NetlinkAttribute {
271  public:
272   static const char kMyTypeString[];
273   static const Type kType;
274   NetlinkNestedAttribute(int id, const char* id_string);
275   virtual bool InitFromValue(const ByteString& data);
276   virtual bool GetNestedAttributeList(AttributeListRefPtr* value);
277   virtual bool ConstGetNestedAttributeList(
278       AttributeListConstRefPtr* value) const;
279   virtual bool SetNestedHasAValue();
280   virtual void Print(int log_level, int indent) const;
281   virtual bool ToString(std::string* value) const;
282   virtual ByteString Encode() const;
283 
284  protected:
285   // Describes a single nested attribute.  Provides the expected values and
286   // type (including further nesting).  Normally, an array of these, one for
287   // each attribute at one level of nesting is presented, along with the data
288   // to be parsed, to |InitNestedFromValue|.  If the attributes on one level
289   // represent an array, a single |NestedData| is provided and |is_array| is
290   // set (note that one level of nesting either contains _only_ an array or
291   // _no_ array).
292   struct NestedData {
293     typedef base::Callback<bool (AttributeList* list, size_t id,
294                                  const std::string& attribute_name,
295                                  ByteString data)> AttributeParser;
296     typedef std::map<size_t, NestedData> NestedDataMap;
297 
298     NestedData();
299     NestedData(Type type, std::string attribute_name, bool is_array);
300     NestedData(Type type, std::string attribute_name, bool is_array,
301                const AttributeParser& parse_attribute);
302     Type type;
303     std::string attribute_name;
304     NestedDataMap deeper_nesting;
305     bool is_array;
306     // Closure that overrides the usual parsing of this attribute.  A non-NULL
307     // value for |parse_attribute| will cause the software to ignore the other
308     // members of the |NestedData| structure.
309     AttributeParser parse_attribute;
310   };
311 
312   typedef std::pair<size_t, NestedData> AttrDataPair;
313 
314   // Some Nl80211 nested attributes are containers that do not have an actual
315   // attribute id, but are nested in another attribute as array elements.
316   // In the underlying netlink message, these attributes exist in their own
317   // nested layer, and take on attribute ids equal to their index in the array.
318   // For purposes of parsing these attributes, assign them an arbitrary
319   // attribute id.
320   static const size_t kArrayAttrEnumVal;
321 
322   // Builds an AttributeList (|list|) that contains all of the attriubtes in
323   // |value|.  |value| should contain the payload of the nested attribute
324   // and not the nested attribute header itself; for the example of the nested
325   // attribute NL80211_ATTR_CQM should contain:
326   //    nlattr::nla_type: NL80211_ATTR_CQM
327   //    nlattr::nla_len: 12 bytes
328   //      nlattr::nla_type: PKT_LOSS_EVENT (1st and only nested attribute)
329   //      nlattr::nla_len: 8 bytes
330   //      <data>: 0x32
331   // One can assemble (hence, disassemble) a set of child attributes under a
332   // nested attribute parent as an array of elements or as a structure.
333   //
334   // The data is parsed using the expected configuration in |nested_template|.
335   // If the code expects an array, it will pass a single template element and
336   // mark that as an array.
337   static bool InitNestedFromValue(
338       const AttributeListRefPtr& list,
339       const NestedData::NestedDataMap& templates,
340       const ByteString& value);
341 
342   AttributeListRefPtr value_;
343   NestedData::NestedDataMap nested_template_;
344 
345  private:
346   // Helper functions used by InitNestedFromValue to add a single child
347   // attribute to a nested attribute.
348   static bool AddAttributeToNestedMap(
349     const NetlinkNestedAttribute::NestedData::NestedDataMap& templates,
350     const AttributeListRefPtr& list, int id, const ByteString& value);
351   static bool AddAttributeToNestedArray(
352     const NetlinkNestedAttribute::NestedData& array_template,
353     const AttributeListRefPtr& list, int id, const ByteString& value);
354   static bool AddAttributeToNestedInner(
355     const NetlinkNestedAttribute::NestedData& nested_template,
356     const std::string& attribute_name, const AttributeListRefPtr& list,
357     int id, const ByteString& value);
358 
359   DISALLOW_COPY_AND_ASSIGN(NetlinkNestedAttribute);
360 };
361 
362 class NetlinkRawAttribute : public NetlinkAttribute {
363  public:
364   static const char kMyTypeString[];
365   static const Type kType;
NetlinkRawAttribute(int id,const char * id_string)366   NetlinkRawAttribute(int id, const char* id_string)
367       : NetlinkAttribute(id, id_string, kType, kMyTypeString) {}
368   virtual bool InitFromValue(const ByteString& data);
369   // Gets the value of the data (the header is not stored).
370   virtual bool GetRawValue(ByteString* value) const;
371   // Should set the value of the data (not the attribute header).
372   virtual bool SetRawValue(const ByteString value);
373   virtual bool ToString(std::string* value) const;
374   virtual ByteString Encode() const;
375 
376  private:
377   DISALLOW_COPY_AND_ASSIGN(NetlinkRawAttribute);
378 };
379 
380 class NetlinkAttributeGeneric : public NetlinkRawAttribute {
381  public:
382   explicit NetlinkAttributeGeneric(int id);
383   virtual const char* id_string() const;
384 
385  private:
386   std::string id_string_;
387 
388   DISALLOW_COPY_AND_ASSIGN(NetlinkAttributeGeneric);
389 };
390 
391 }  // namespace shill
392 
393 #endif  // SHILL_NET_NETLINK_ATTRIBUTE_H_
394