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_parser.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#include <shill/net/byte_string.h>
28
29using shill::ByteString;
30
31namespace dhcp_client {
32
33bool UInt8Parser::GetOption(const uint8_t* buffer,
34                            uint8_t length,
35                            void* value) {
36  if (length != sizeof(uint8_t)) {
37    LOG(ERROR) << "Invalid option length field";
38    return false;
39  }
40  uint8_t* value_uint8 = static_cast<uint8_t*>(value);
41  *value_uint8 = *buffer;
42  return true;
43}
44
45bool UInt16Parser::GetOption(const uint8_t* buffer,
46                             uint8_t length,
47                             void* value) {
48  if (length != sizeof(uint16_t)) {
49    LOG(ERROR) << "Invalid option length field";
50    return false;
51  }
52  uint16_t* value_uint16 = static_cast<uint16_t*>(value);
53  *value_uint16 = ntohs(*reinterpret_cast<const uint16_t*>(buffer));
54  return true;
55}
56
57bool UInt32Parser::GetOption(const uint8_t* buffer,
58                             uint8_t length,
59                             void* value) {
60  if (length != sizeof(uint32_t)) {
61    LOG(ERROR) << "Invalid option length field";
62    return false;
63  }
64  uint32_t* value_uint32 = static_cast<uint32_t*>(value);
65  *value_uint32 = ntohl(*reinterpret_cast<const uint32_t*>(buffer));
66  return true;
67}
68
69bool UInt8ListParser::GetOption(const uint8_t* buffer,
70                                uint8_t length,
71                                void* value) {
72  if (length == 0) {
73    LOG(ERROR) << "Invalid option length field";
74    return false;
75  }
76  std::vector<uint8_t>* value_vector =
77      static_cast<std::vector<uint8_t>*>(value);
78  for (int i = 0; i < length; i++) {
79    uint8_t content = *reinterpret_cast<const uint8_t*>(buffer);
80    value_vector->push_back(content);
81    buffer += sizeof(uint8_t);
82  }
83  return true;
84}
85
86bool UInt16ListParser::GetOption(const uint8_t* buffer,
87                                 uint8_t length,
88                                 void* value) {
89  if (length == 0 || length % sizeof(uint16_t)) {
90    LOG(ERROR) << "Invalid option length field";
91    return false;
92  }
93  int num_int16s = length / sizeof(uint16_t);
94  std::vector<uint16_t>* value_vector =
95      static_cast<std::vector<uint16_t>*>(value);
96  for (int i = 0; i < num_int16s; i++) {
97    uint16_t content = *reinterpret_cast<const uint16_t*>(buffer);
98    content = ntohs(content);
99    value_vector->push_back(content);
100    buffer += sizeof(uint16_t);
101  }
102  return true;
103}
104
105bool UInt32ListParser::GetOption(const uint8_t* buffer,
106                                 uint8_t length,
107                                 void* value) {
108  if (length == 0 || length % sizeof(uint32_t)) {
109    LOG(ERROR) << "Invalid option length field";
110    return false;
111  }
112  int num_int32s = length / sizeof(uint32_t);
113  std::vector<uint32_t>* value_vector =
114      static_cast<std::vector<uint32_t>*>(value);
115  for (int i = 0; i < num_int32s; i++) {
116    uint32_t content = *reinterpret_cast<const uint32_t*>(buffer);
117    content = ntohl(content);
118    value_vector->push_back(content);
119    buffer += sizeof(uint32_t);
120  }
121  return true;
122}
123
124bool UInt32PairListParser::GetOption(const uint8_t* buffer,
125                                     uint8_t length,
126                                     void* value) {
127  if (length == 0 || length % (2 * sizeof(uint32_t))) {
128    LOG(ERROR) << "Invalid option length field";
129    return false;
130  }
131  int num_int32pairs = length / (2 * sizeof(uint32_t));
132  std::vector<std::pair<uint32_t, uint32_t>>* value_vector =
133      static_cast<std::vector<std::pair<uint32_t, uint32_t>>*>(value);
134  for (int i = 0; i < num_int32pairs; i++) {
135    uint32_t first = *reinterpret_cast<const uint32_t*>(buffer);
136    first = ntohl(first);
137    buffer += sizeof(uint32_t);
138    uint32_t second = *reinterpret_cast<const uint32_t*>(buffer);
139    second = ntohl(second);
140    value_vector->push_back(std::pair<uint32_t, uint32_t>(first, second));
141    buffer += sizeof(uint32_t);
142  }
143  return true;
144}
145
146bool BoolParser::GetOption(const uint8_t* buffer,
147                           uint8_t length,
148                           void* value) {
149  if (length != sizeof(uint8_t)) {
150    LOG(ERROR) << "Invalid option length field";
151    return false;
152  }
153  uint8_t content = *buffer;
154  bool* enable = static_cast<bool*>(value);
155  if (content == 1) {
156    *enable = true;
157  } else if (content == 0) {
158    *enable = false;
159  } else {
160    LOG(ERROR) << "Invalid option value field";
161    return false;
162  }
163  return true;
164}
165
166bool StringParser::GetOption(const uint8_t* buffer,
167                             uint8_t length,
168                             void* value) {
169  if (length == 0) {
170    LOG(ERROR) << "Invalid option length field";
171    return false;
172  }
173  std::string* option_string = static_cast<std::string*>(value);
174  option_string->assign(reinterpret_cast<const char*>(buffer), length);
175  return true;
176}
177
178bool ByteArrayParser::GetOption(const uint8_t* buffer,
179                                uint8_t length,
180                                void* value) {
181  if (length == 0) {
182    LOG(ERROR) << "Invalid option length field";
183    return false;
184  }
185  ByteString* byte_array =
186      static_cast<ByteString*>(value);
187  *byte_array = ByteString(buffer, length);
188  return true;
189}
190
191}  // namespace dhcp_client
192