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 30using testing::_; 31using testing::InSequence; 32using testing::Mock; 33using testing::Return; 34using testing::Test; 35 36namespace shill { 37 38class 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 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 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 68MATCHER_P(PayloadIs, payload, "") { 69 return arg.Equals(ByteString(std::string(payload), false)); 70} 71 72TEST_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 80TEST_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 131TEST_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 157TEST_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