• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (C) 2015 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 // This file tests some public interface methods of AttributeList.
18 #include "shill/net/attribute_list.h"
19 
20 #include <linux/netlink.h>
21 
22 #include <string>
23 
24 #include <base/bind.h>
25 #include <gmock/gmock.h>
26 #include <gtest/gtest.h>
27 
28 #include "shill/net/byte_string.h"
29 
30 using testing::_;
31 using testing::InSequence;
32 using testing::Mock;
33 using testing::Return;
34 using testing::Test;
35 
36 namespace shill {
37 
38 class AttributeListTest : public Test {
39  public:
40   MOCK_METHOD2(AttributeMethod, bool(int id, const ByteString& value));
41 
42  protected:
43   static const uint16_t kHeaderLength = 4;
44   static const uint16_t kType1 = 1;
45   static const uint16_t kType2 = 2;
46   static const uint16_t kType3 = 3;
47 
MakeNetlinkAttribute(uint16_t len,uint16_t type,const std::string & payload)48   static ByteString MakeNetlinkAttribute(uint16_t len,
49                                          uint16_t type,
50                                          const std::string& payload) {
51     nlattr attribute{ len, type };
52     ByteString data(reinterpret_cast<const char*>(&attribute),
53                     sizeof(attribute));
54     data.Append(ByteString(payload, false));
55     return data;
56   }
57 
MakePaddedNetlinkAttribute(uint16_t len,uint16_t type,const std::string & payload)58   static ByteString MakePaddedNetlinkAttribute(uint16_t len,
59                                                uint16_t type,
60                                                const std::string& payload) {
61     ByteString data(MakeNetlinkAttribute(len, type, payload));
62     ByteString padding(NLA_ALIGN(data.GetLength()) - data.GetLength());
63     data.Append(padding);
64     return data;
65   }
66 };
67 
68 MATCHER_P(PayloadIs, payload, "") {
69   return arg.Equals(ByteString(std::string(payload), false));
70 }
71 
TEST_F(AttributeListTest,IterateEmptyPayload)72 TEST_F(AttributeListTest, IterateEmptyPayload) {
73   EXPECT_CALL(*this, AttributeMethod(_, _)).Times(0);
74   AttributeListRefPtr list(new AttributeList());
75   EXPECT_TRUE(list->IterateAttributes(
76       ByteString(), 0,
77       base::Bind(&AttributeListTest::AttributeMethod, base::Unretained(this))));
78 }
79 
TEST_F(AttributeListTest,IteratePayload)80 TEST_F(AttributeListTest, IteratePayload) {
81   ByteString payload;
82   payload.Append(MakePaddedNetlinkAttribute(
83       kHeaderLength + 10, kType1, "0123456789"));
84   const uint16_t kLength1 = kHeaderLength + 10 + 2;  // 2 bytes padding.
85   ASSERT_EQ(kLength1, payload.GetLength());
86   payload.Append(MakePaddedNetlinkAttribute(kHeaderLength + 3, kType2, "123"));
87   const uint16_t kLength2 = kLength1 + kHeaderLength + 3 + 1;  // 1 byte pad.
88   ASSERT_EQ(kLength2, payload.GetLength());
89 
90   payload.Append(MakeNetlinkAttribute(kHeaderLength + 5, kType3, "12345"));
91   const uint16_t kLength3 = kLength2 + kHeaderLength + 5;
92   ASSERT_EQ(kLength3, payload.GetLength());
93 
94   InSequence seq;
95   EXPECT_CALL(*this, AttributeMethod(kType1, PayloadIs("0123456789")))
96       .WillOnce(Return(true));
97   EXPECT_CALL(*this, AttributeMethod(kType2, PayloadIs("123")))
98       .WillOnce(Return(true));
99   EXPECT_CALL(*this, AttributeMethod(kType3, PayloadIs("12345")))
100       .WillOnce(Return(true));
101   AttributeListRefPtr list(new AttributeList());
102   EXPECT_TRUE(list->IterateAttributes(
103       payload, 0,
104       base::Bind(&AttributeListTest::AttributeMethod, base::Unretained(this))));
105   Mock::VerifyAndClearExpectations(this);
106 
107   // If a valid offset is provided only the attributes that follow should
108   // be enumerated.
109   EXPECT_CALL(*this, AttributeMethod(kType1, _)).Times(0);
110   EXPECT_CALL(*this, AttributeMethod(kType2, PayloadIs("123")))
111       .WillOnce(Return(true));
112   EXPECT_CALL(*this, AttributeMethod(kType3, PayloadIs("12345")))
113       .WillOnce(Return(true));
114   EXPECT_TRUE(list->IterateAttributes(
115       payload, kLength1,
116       base::Bind(&AttributeListTest::AttributeMethod, base::Unretained(this))));
117   Mock::VerifyAndClearExpectations(this);
118 
119   // If one of the attribute methods returns false, the iteration should abort.
120   EXPECT_CALL(*this, AttributeMethod(kType1, PayloadIs("0123456789")))
121       .WillOnce(Return(true));
122   EXPECT_CALL(*this, AttributeMethod(kType2, PayloadIs("123")))
123       .WillOnce(Return(false));
124   EXPECT_CALL(*this, AttributeMethod(kType3, PayloadIs("12345"))).Times(0);
125   EXPECT_FALSE(list->IterateAttributes(
126       payload, 0,
127       base::Bind(&AttributeListTest::AttributeMethod, base::Unretained(this))));
128   Mock::VerifyAndClearExpectations(this);
129 }
130 
TEST_F(AttributeListTest,SmallPayloads)131 TEST_F(AttributeListTest, SmallPayloads) {
132   // A payload must be at least 4 bytes long to incorporate the nlattr header.
133   EXPECT_CALL(*this, AttributeMethod(_, _)).Times(0);
134   AttributeListRefPtr list(new AttributeList());
135   EXPECT_FALSE(list->IterateAttributes(
136       MakeNetlinkAttribute(kHeaderLength - 1, kType1, "0123"), 0,
137       base::Bind(&AttributeListTest::AttributeMethod, base::Unretained(this))));
138   Mock::VerifyAndClearExpectations(this);
139 
140   // This is a minimal valid payload.
141   EXPECT_CALL(*this, AttributeMethod(
142       kType2, PayloadIs(""))).WillOnce(Return(true));
143   EXPECT_TRUE(list->IterateAttributes(
144       MakeNetlinkAttribute(kHeaderLength, kType2, ""), 0,
145       base::Bind(&AttributeListTest::AttributeMethod, base::Unretained(this))));
146   Mock::VerifyAndClearExpectations(this);
147 
148   // This is a minmal payload except there are not enough bytes to retrieve
149   // the attribute value.
150   const uint16_t kType3 = 1;
151   EXPECT_CALL(*this, AttributeMethod(_, _)).Times(0);
152   EXPECT_FALSE(list->IterateAttributes(
153       MakeNetlinkAttribute(kHeaderLength + 1, kType3, ""), 0,
154       base::Bind(&AttributeListTest::AttributeMethod, base::Unretained(this))));
155 }
156 
TEST_F(AttributeListTest,TrailingGarbage)157 TEST_F(AttributeListTest, TrailingGarbage) {
158   // +---------+
159   // | Attr #1 |
160   // +-+-+-+-+-+
161   // |LEN|TYP|0|
162   // +-+-+-+-+-+
163   // Well formed frame.
164   ByteString payload(MakeNetlinkAttribute(kHeaderLength + 1, kType1, "0"));
165   EXPECT_CALL(*this, AttributeMethod(kType1, PayloadIs("0")))
166       .WillOnce(Return(true));
167   AttributeListRefPtr list(new AttributeList());
168   EXPECT_TRUE(list->IterateAttributes(
169       payload, 0,
170       base::Bind(&AttributeListTest::AttributeMethod, base::Unretained(this))));
171   Mock::VerifyAndClearExpectations(this);
172 
173   // +---------------+
174   // | Attr #1 + pad |
175   // +-+-+-+-+-+-+-+-+
176   // |LEN|TYP|0|1|2|3|
177   // +-+-+-+-+-+-+-+-+
178   // "123" assumed to be padding for attr1.
179   payload.Append(ByteString(std::string("123"), false));
180   EXPECT_CALL(*this, AttributeMethod(kType1, PayloadIs("0")))
181       .WillOnce(Return(true));
182   EXPECT_TRUE(list->IterateAttributes(
183       payload, 0,
184       base::Bind(&AttributeListTest::AttributeMethod, base::Unretained(this))));
185   Mock::VerifyAndClearExpectations(this);
186 
187   // +---------------+-----+
188   // | Attr #1 + pad |RUNT |
189   // +-+-+-+-+-+-+-+-+-+-+-+
190   // |LEN|TYP|0|1|2|3|4|5|6|
191   // +-+-+-+-+-+-+-+-+-+-+-+
192   // "456" is acceptable since it is not long enough to complete an netlink
193   // attribute header.
194   payload.Append(ByteString(std::string("456"), false));
195   EXPECT_CALL(*this, AttributeMethod(kType1, PayloadIs("0")))
196       .WillOnce(Return(true));
197   EXPECT_TRUE(list->IterateAttributes(
198       payload, 0,
199       base::Bind(&AttributeListTest::AttributeMethod, base::Unretained(this))));
200   Mock::VerifyAndClearExpectations(this);
201 
202   // +---------------+-------+
203   // | Attr #1 + pad |Broken |
204   // +-+-+-+-+-+-+-+-+-+-+-+-+
205   // |LEN|TYP|0|1|2|3|4|5|6|7|
206   // +-+-+-+-+-+-+-+-+-+-+-+-+
207   // This is a broken frame, since '4567' can be interpreted as a complete
208   // nlatter header, but is malformed since there is not enough payload to
209   // satisfy the "length" parameter.
210   payload.Append(ByteString(std::string("7"), false));
211   EXPECT_CALL(*this, AttributeMethod(kType1, PayloadIs("0")))
212       .WillOnce(Return(true));
213   EXPECT_FALSE(list->IterateAttributes(
214       payload, 0,
215       base::Bind(&AttributeListTest::AttributeMethod, base::Unretained(this))));
216   Mock::VerifyAndClearExpectations(this);
217 }
218 
219 }  // namespace shill
220