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