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
30using shill::ByteString;
31namespace {
32base::LazyInstance<dhcp_client::DHCPOptionsWriter> g_dhcp_options_writer
33    = LAZY_INSTANCE_INITIALIZER;
34}  // namespace
35
36namespace dhcp_client {
37
38DHCPOptionsWriter* DHCPOptionsWriter::GetInstance() {
39  return g_dhcp_options_writer.Pointer();
40}
41
42int 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
55int 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
69int 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
83int 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
101int 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
122int 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
143int 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
167int 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
181int 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
199int 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
212int 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