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 #include "dhcp_client/dhcp_options_writer.h"
18
19 #include <netinet/in.h>
20
21 #include <string>
22 #include <utility>
23 #include <vector>
24
25 #include <base/logging.h>
26 #include <base/macros.h>
27
28 #include "dhcp_client/dhcp_options.h"
29
30 using shill::ByteString;
31 namespace {
32 base::LazyInstance<dhcp_client::DHCPOptionsWriter> g_dhcp_options_writer
33 = LAZY_INSTANCE_INITIALIZER;
34 } // namespace
35
36 namespace dhcp_client {
37
GetInstance()38 DHCPOptionsWriter* DHCPOptionsWriter::GetInstance() {
39 return g_dhcp_options_writer.Pointer();
40 }
41
WriteUInt8Option(ByteString * buffer,uint8_t option_code,uint8_t value)42 int DHCPOptionsWriter::WriteUInt8Option(ByteString* buffer,
43 uint8_t option_code,
44 uint8_t value) {
45 uint8_t length = sizeof(uint8_t);
46 buffer->Append(ByteString(reinterpret_cast<const char*>(&option_code),
47 sizeof(uint8_t)));
48 buffer->Append(ByteString(reinterpret_cast<const char*>(&length),
49 sizeof(uint8_t)));
50 buffer->Append(ByteString(reinterpret_cast<const char*>(&value),
51 sizeof(uint8_t)));
52 return length + 2;
53 }
54
WriteUInt16Option(ByteString * buffer,uint8_t option_code,uint16_t value)55 int DHCPOptionsWriter::WriteUInt16Option(ByteString* buffer,
56 uint8_t option_code,
57 uint16_t value) {
58 uint8_t length = sizeof(uint16_t);
59 uint16_t value_net = htons(value);
60 buffer->Append(ByteString(reinterpret_cast<const char*>(&option_code),
61 sizeof(uint8_t)));
62 buffer->Append(ByteString(reinterpret_cast<const char*>(&length),
63 sizeof(uint8_t)));
64 buffer->Append(ByteString(reinterpret_cast<const char*>(&value_net),
65 sizeof(uint16_t)));
66 return length + 2;
67 }
68
WriteUInt32Option(ByteString * buffer,uint8_t option_code,uint32_t value)69 int DHCPOptionsWriter::WriteUInt32Option(ByteString* buffer,
70 uint8_t option_code,
71 uint32_t value) {
72 uint8_t length = sizeof(uint32_t);
73 uint32_t value_net = htonl(value);
74 buffer->Append(ByteString(reinterpret_cast<const char*>(&option_code),
75 sizeof(uint8_t)));
76 buffer->Append(ByteString(reinterpret_cast<const char*>(&length),
77 sizeof(uint8_t)));
78 buffer->Append(ByteString(reinterpret_cast<const char*>(&value_net),
79 sizeof(uint32_t)));
80 return length + 2;
81 }
82
WriteUInt8ListOption(ByteString * buffer,uint8_t option_code,const std::vector<uint8_t> & value)83 int DHCPOptionsWriter::WriteUInt8ListOption(ByteString* buffer,
84 uint8_t option_code,
85 const std::vector<uint8_t>& value) {
86 if (value.size() == 0) {
87 LOG(ERROR) << "Faild to write option: " << static_cast<int>(option_code)
88 << ", because value size cannot be 0";
89 return -1;
90 }
91 uint8_t length = value.size() * sizeof(uint8_t);
92 buffer->Append(ByteString(reinterpret_cast<const char*>(&option_code),
93 sizeof(uint8_t)));
94 buffer->Append(ByteString(reinterpret_cast<const char*>(&length),
95 sizeof(uint8_t)));
96 buffer->Append(ByteString(reinterpret_cast<const char*>(&value.front()),
97 length * sizeof(uint8_t)));
98 return length + 2;
99 }
100
WriteUInt16ListOption(ByteString * buffer,uint8_t option_code,const std::vector<uint16_t> & value)101 int DHCPOptionsWriter::WriteUInt16ListOption(ByteString* buffer,
102 uint8_t option_code,
103 const std::vector<uint16_t>& value) {
104 if (value.size() == 0) {
105 LOG(ERROR) << "Faild to write option: " << static_cast<int>(option_code)
106 << ", because value size cannot be 0";
107 return -1;
108 }
109 uint8_t length = value.size() * sizeof(uint16_t);
110 buffer->Append(ByteString(reinterpret_cast<const char*>(&option_code),
111 sizeof(uint8_t)));
112 buffer->Append(ByteString(reinterpret_cast<const char*>(&length),
113 sizeof(uint8_t)));
114 for (uint16_t element : value) {
115 uint16_t element_net = htons(element);
116 buffer->Append(ByteString(reinterpret_cast<const char *>(&element_net),
117 sizeof(uint16_t)));
118 }
119 return length + 2;
120 }
121
WriteUInt32ListOption(ByteString * buffer,uint8_t option_code,const std::vector<uint32_t> & value)122 int DHCPOptionsWriter::WriteUInt32ListOption(ByteString* buffer,
123 uint8_t option_code,
124 const std::vector<uint32_t>& value) {
125 if (value.size() == 0) {
126 LOG(ERROR) << "Faild to write option: " << static_cast<int>(option_code)
127 << ", because value size cannot be 0";
128 return -1;
129 }
130 uint8_t length = value.size() * sizeof(uint32_t);
131 buffer->Append(ByteString(reinterpret_cast<const char*>(&option_code),
132 sizeof(uint8_t)));
133 buffer->Append(ByteString(reinterpret_cast<const char*>(&length),
134 sizeof(uint8_t)));
135 for (uint32_t element : value) {
136 uint32_t element_net = htonl(element);
137 buffer->Append(ByteString(reinterpret_cast<const char*>(&element_net),
138 sizeof(uint32_t)));
139 }
140 return length + 2;
141 }
142
WriteUInt32PairListOption(ByteString * buffer,uint8_t option_code,const std::vector<std::pair<uint32_t,uint32_t>> & value)143 int DHCPOptionsWriter::WriteUInt32PairListOption(ByteString* buffer,
144 uint8_t option_code,
145 const std::vector<std::pair<uint32_t, uint32_t>>& value) {
146 if (value.size() == 0) {
147 LOG(ERROR) << "Faild to write option: " << static_cast<int>(option_code)
148 << ", because value size cannot be 0";
149 return -1;
150 }
151 uint8_t length = value.size() * sizeof(uint32_t) * 2;
152 buffer->Append(ByteString(reinterpret_cast<const char*>(&option_code),
153 sizeof(uint8_t)));
154 buffer->Append(ByteString(reinterpret_cast<const char*>(&length),
155 sizeof(uint8_t)));
156 for (auto element : value) {
157 uint32_t first_net = htonl(element.first);
158 uint32_t second_net = htonl(element.second);
159 buffer->Append(ByteString(reinterpret_cast<const char*>(&first_net),
160 sizeof(uint32_t)));
161 buffer->Append(ByteString(reinterpret_cast<const char*>(&second_net),
162 sizeof(uint32_t)));
163 }
164 return length + 2;
165 }
166
WriteBoolOption(ByteString * buffer,uint8_t option_code,const bool value)167 int DHCPOptionsWriter::WriteBoolOption(ByteString* buffer,
168 uint8_t option_code,
169 const bool value) {
170 uint8_t length = sizeof(uint8_t);
171 uint8_t value_uint8 = value ? 1 : 0;
172 buffer->Append(ByteString(reinterpret_cast<const char*>(&option_code),
173 sizeof(uint8_t)));
174 buffer->Append(ByteString(reinterpret_cast<const char*>(&length),
175 sizeof(uint8_t)));
176 buffer->Append(ByteString(reinterpret_cast<const char*>(&value_uint8),
177 sizeof(uint8_t)));
178 return length + 2;
179 }
180
WriteStringOption(ByteString * buffer,uint8_t option_code,const std::string & value)181 int DHCPOptionsWriter::WriteStringOption(ByteString* buffer,
182 uint8_t option_code,
183 const std::string& value) {
184 if (value.size() == 0) {
185 LOG(ERROR) << "Faild to write option: " << static_cast<int>(option_code)
186 << ", because value size cannot be 0";
187 return -1;
188 }
189 uint8_t length = value.size();
190 buffer->Append(ByteString(reinterpret_cast<const char*>(&option_code),
191 sizeof(uint8_t)));
192 buffer->Append(ByteString(reinterpret_cast<const char*>(&length),
193 sizeof(uint8_t)));
194 buffer->Append(ByteString(reinterpret_cast<const char*>(&value.front()),
195 length * sizeof(uint8_t)));
196 return length + 2;
197 }
198
WriteByteArrayOption(ByteString * buffer,uint8_t option_code,const ByteString & value)199 int DHCPOptionsWriter::WriteByteArrayOption(ByteString* buffer,
200 uint8_t option_code,
201 const ByteString& value) {
202 uint8_t length = value.GetLength();
203 buffer->Append(ByteString(reinterpret_cast<const char*>(&option_code),
204 sizeof(uint8_t)));
205 buffer->Append(ByteString(reinterpret_cast<const char*>(&length),
206 sizeof(uint8_t)));
207
208 buffer->Append(value);
209 return length + 2;
210 }
211
WriteEndTag(ByteString * buffer)212 int DHCPOptionsWriter::WriteEndTag(ByteString* buffer) {
213 uint8_t tag = kDHCPOptionEnd;
214 buffer->Append(ByteString(reinterpret_cast<const char*>(&tag),
215 sizeof(uint8_t)));
216 return 1;
217 }
218
219 } // namespace dhcp_client
220