1 /*
2 * Copyright (C) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "dhcp_message_sim.h"
17 #include <cstdio>
18 #include <cstdint>
19 #include <net/if.h>
20 #include <arpa/inet.h>
21 #include <netinet/in.h>
22 #include <sys/types.h>
23 #include <fcntl.h>
24 #include "dhcp_logger.h"
25 #include "dhcp_option.h"
26 #include "dhcp_ipv4.h"
27 #include "address_utils.h"
28 #include "securec.h"
29 #include "common_util.h"
30
31 #undef LOG_TAG
32 #define LOG_TAG "DhcpMessageSimulator"
33 using namespace OHOS::Wifi;
34
35 constexpr int OPT_MESSAGE_TYPE_LEGTH = 1;
36 constexpr uint8_t OPT_HEADER_LENGTH = 2;
37 constexpr uint8_t MAGIC_COOKIE_LENGTH = 4;
38 constexpr uint32_t DHCP_MAGIC_COOKIE = 0x63825363;
39
GetInstance()40 DhcpMsgManager& DhcpMsgManager::GetInstance()
41 {
42 static DhcpMsgManager gMessageManager;
43 return gMessageManager;
44 }
45
SendTotal()46 int DhcpMsgManager::SendTotal()
47 {
48 int total = 0;
49 m_sendQueueLocker.lock();
50 total = m_sendMessages.size();
51 m_sendQueueLocker.unlock();
52 return total;
53 }
54
RecvTotal()55 int DhcpMsgManager::RecvTotal()
56 {
57 int total = 0;
58 m_recvQueueLocker.lock();
59 total = m_recvMessages.size();
60 m_recvQueueLocker.unlock();
61 return total;
62 }
63
FrontSendMsg(DhcpMessage * msg)64 bool DhcpMsgManager::FrontSendMsg(DhcpMessage *msg)
65 {
66 int retval = false;
67 if (!msg) {
68 return retval;
69 }
70 m_sendQueueLocker.lock();
71 if (!m_sendMessages.empty()) {
72 DhcpMessage fmsg = m_sendMessages.front();
73 if (memcpy_s(msg, sizeof(DhcpMessage), &fmsg, sizeof(DhcpMessage)) == EOK) {
74 retval = true;
75 }
76 }
77 m_sendQueueLocker.unlock();
78 return retval;
79 }
80
PopSendMsg()81 void DhcpMsgManager::PopSendMsg()
82 {
83 m_sendQueueLocker.lock();
84 if (m_sendMessages.size() > 0) {
85 m_sendMessages.pop();
86 }
87 m_sendQueueLocker.unlock();
88 }
89
PopRecvMsg()90 void DhcpMsgManager::PopRecvMsg()
91 {
92 m_recvQueueLocker.lock();
93 if (!m_recvMessages.empty()) {
94 m_recvMessages.pop();
95 }
96 m_recvQueueLocker.unlock();
97 }
98
PushSendMsg(const DhcpMessage & msg)99 int DhcpMsgManager::PushSendMsg(const DhcpMessage &msg)
100 {
101 m_sendQueueLocker.lock();
102 m_sendMessages.push(msg);
103 m_sendQueueLocker.unlock();
104 return 1;
105 }
106
PushRecvMsg(const DhcpMessage & msg)107 int DhcpMsgManager::PushRecvMsg(const DhcpMessage &msg)
108 {
109 m_recvQueueLocker.lock();
110 m_recvMessages.push(msg);
111 m_recvQueueLocker.unlock();
112 return 1;
113 }
114
SetClientIp(uint32_t ipAddr)115 void DhcpMsgManager::SetClientIp(uint32_t ipAddr)
116 {
117 m_clientIpAddress = ipAddr;
118 }
GetClientIp() const119 uint32_t DhcpMsgManager::GetClientIp() const
120 {
121 return m_clientIpAddress;
122 }
123
FillHwAddr(uint8_t * dst,size_t dsize,uint8_t * src,size_t ssize)124 int FillHwAddr(uint8_t *dst, size_t dsize, uint8_t *src, size_t ssize)
125 {
126 if (!dst || !src) {
127 return DHCP_FALSE;
128 }
129 if (ssize > dsize) {
130 return DHCP_FALSE;
131 }
132 if (memset_s(dst, dsize, 0, dsize) != EOK) {
133 return DHCP_FALSE;
134 }
135 if (memcpy_s(dst, dsize, src, ssize) != EOK) {
136 return DHCP_FALSE;
137 }
138 return DHCP_TRUE;
139 }
140
InitialDhcpClient(DhcpClientConfig * config)141 DhcpClientContext *InitialDhcpClient(DhcpClientConfig *config)
142 {
143 LOGD("init dhcp client.");
144 if (!config) {
145 return nullptr;
146 }
147 DhcpClientContext *context = reinterpret_cast<DhcpClientContext *>(calloc(1, sizeof(DhcpClientContext)));
148 if (context == nullptr) {
149 LOGE("failed to calloc client context.");
150 return nullptr;
151 }
152 if (memset_s(context, sizeof(DhcpClientContext), 0, sizeof(DhcpClientContext)) != EOK) {
153 LOGE("failed to reset client context.");
154 free(context);
155 return nullptr;
156 }
157 if (memset_s(context->config.ifname, IFACE_NAME_SIZE, '\0', IFACE_NAME_SIZE) != EOK) {
158 LOGE("failed to reset interface name.");
159 free(context);
160 return nullptr;
161 }
162 if (strncpy_s(context->config.ifname, IFACE_NAME_SIZE, config->ifname, strlen(config->ifname)) != EOK) {
163 LOGE("failed to set interface name.");
164 free(context);
165 return nullptr;
166 }
167 if (!FillHwAddr(context->config.chaddr, DHCP_HWADDR_LENGTH, config->chaddr, MAC_ADDR_LENGTH)) {
168 LOGE("failed to set chaddr.");
169 free(context);
170 return nullptr;
171 }
172 context->clientFd = 1;
173 return context;
174 }
175
ParseDhcpOptions(PDhcpMsgInfo msg)176 static int ParseDhcpOptions(PDhcpMsgInfo msg)
177 {
178 int ret;
179 PDhcpOptionNode pNode = msg->options.first->next;
180 DhcpOption endOpt = {END_OPTION, 0, {0}};
181 PushBackOption(&msg->options, &endOpt);
182 int replyOptsLength = 0;
183 uint8_t *current = msg->packet.options, olen = MAGIC_COOKIE_LENGTH;
184 uint32_t cookie = htonl(DHCP_MAGIC_COOKIE);
185 if (memcpy_s(current, olen, &cookie, olen) != EOK) {
186 LOGE("memcpy cookie out of options buffer!");
187 return RET_FAILED;
188 }
189 replyOptsLength += olen;
190 current += olen;
191 ret = RET_SUCCESS;
192 while (pNode && (uint32_t)pNode->option.length < DHCP_OPTION_SIZE) {
193 if ((uint32_t)pNode->option.code == END_OPTION) {
194 olen = OPT_HEADER_LENGTH + 1;
195 } else {
196 olen = OPT_HEADER_LENGTH + pNode->option.length;
197 }
198 if (memcpy_s(current, olen, &pNode->option, olen) != EOK) {
199 LOGE("memcpy current option out of options buffer!");
200 ret = RET_FAILED;
201 break;
202 }
203 current += olen;
204 replyOptsLength += olen;
205 if ((uint32_t)pNode->option.code == END_OPTION) {
206 break;
207 }
208 pNode = pNode->next;
209 if (replyOptsLength >= DHCP_OPTIONS_SIZE) {
210 LOGE("current option out of options buffer!");
211 ret = RET_FAILED;
212 break;
213 }
214 }
215 msg->length += replyOptsLength;
216 return ret;
217 }
218
SendDhcpMessage(const DhcpClientContext * ctx,PDhcpMsgInfo msg)219 int SendDhcpMessage(const DhcpClientContext *ctx, PDhcpMsgInfo msg)
220 {
221 if (!ctx || !msg) {
222 LOGE("client context or message pointer is null.");
223 return RET_FAILED;
224 }
225 if (ParseDhcpOptions(msg) != RET_SUCCESS) {
226 LOGE("failed to parse dhcp message info.");
227 return RET_FAILED;
228 }
229 DhcpMsgManager::GetInstance().PushSendMsg(msg->packet);
230 return RET_SUCCESS;
231 }
232
GetXid(int update)233 static uint32_t GetXid(int update)
234 {
235 static uint32_t currXid = Tmspsec();
236 if (update) {
237 currXid = Tmspsec();
238 }
239 return currXid;
240 }
241
InitMessage(DhcpClientContext * ctx,PDhcpMsgInfo msg,uint8_t msgType)242 int InitMessage(DhcpClientContext *ctx, PDhcpMsgInfo msg, uint8_t msgType)
243 {
244 LOGD("init dhcp message...");
245 if (!ctx) {
246 LOGD("client context pointer is null.");
247 return DHCP_FALSE;
248 }
249 if (!msg) {
250 LOGD("dhcp message pointer is null.");
251 return DHCP_FALSE;
252 }
253 if (memset_s(msg, sizeof(DhcpMsgInfo), 0, sizeof(DhcpMsgInfo)) != EOK) {
254 LOGD("message info pointer is null.");
255 return DHCP_FALSE;
256 }
257 if (InitOptionList(&msg->options) != RET_SUCCESS) {
258 LOGD("failed to initialize dhcp client options.");
259 return DHCP_FALSE;
260 }
261 if (!FillHwAddr(msg->packet.chaddr, DHCP_HWADDR_LENGTH, ctx->config.chaddr, MAC_ADDR_LENGTH)) {
262 return DHCP_FALSE;
263 }
264 msg->packet.op = BOOTREQUEST;
265 msg->packet.htype = 0x01;
266 msg->packet.hlen = MAC_ADDR_LENGTH;
267 if (msgType == DHCPDISCOVER) {
268 msg->packet.xid = GetXid(DHCP_TRUE);
269 } else {
270 msg->packet.xid = GetXid(DHCP_FALSE);
271 }
272
273 if (DhcpMsgManager::GetInstance().GetClientIp() != 0) {
274 DhcpOption optReqIp = {REQUESTED_IP_ADDRESS_OPTION, 0, {0}};
275 AppendAddressOption(&optReqIp, DhcpMsgManager::GetInstance().GetClientIp());
276 PushFrontOption(&msg->options, &optReqIp);
277 }
278
279 DhcpOption optMsgType = {DHCP_MESSAGE_TYPE_OPTION, OPT_MESSAGE_TYPE_LEGTH, {msgType, 0}};
280 PushFrontOption(&msg->options, &optMsgType);
281
282 PDhcpOption pEndOpt = GetOption(&msg->options, END_OPTION);
283 if (pEndOpt == NULL) {
284 DhcpOption endOpt = {END_OPTION, 0, {0}};
285 PushBackOption(&msg->options, &endOpt);
286 }
287 return DHCP_TRUE;
288 }
289
DhcpDiscover(DhcpClientContext * ctx)290 int DhcpDiscover(DhcpClientContext *ctx)
291 {
292 if (!ctx) {
293 return RET_FAILED;
294 }
295 DhcpMsgInfo msgInfo;
296 if (!InitMessage(ctx, &msgInfo, DHCPDISCOVER)) {
297 LOGD("failed to init dhcp message.");
298 return RET_FAILED;
299 }
300 if (SendDhcpMessage(ctx, &msgInfo) != RET_SUCCESS) {
301 LOGD("failed to send dhcp message.");
302 return RET_FAILED;
303 }
304 LOGD("send dhcp discover...");
305 return RET_SUCCESS;
306 }
307
DhcpRequest(DhcpClientContext * ctx)308 int DhcpRequest(DhcpClientContext *ctx)
309 {
310 if (!ctx) {
311 return RET_FAILED;
312 }
313 DhcpMsgInfo msgInfo;
314 if (!InitMessage(ctx, &msgInfo, DHCPREQUEST)) {
315 LOGD("failed to init dhcp message.");
316 return RET_FAILED;
317 }
318 if (SendDhcpMessage(ctx, &msgInfo) != RET_SUCCESS) {
319 LOGD("failed to send dhcp message.");
320 return RET_FAILED;
321 }
322 LOGD("send dhcp request...");
323 return RET_SUCCESS;
324 }
325
DhcpInform(DhcpClientContext * ctx)326 int DhcpInform(DhcpClientContext *ctx)
327 {
328 if (!ctx) {
329 return RET_FAILED;
330 }
331 DhcpMsgInfo msgInfo;
332 if (!InitMessage(ctx, &msgInfo, DHCPINFORM)) {
333 LOGD("failed to init dhcp message.");
334 return RET_FAILED;
335 }
336 if (SendDhcpMessage(ctx, &msgInfo) != RET_SUCCESS) {
337 LOGD("failed to send dhcp message.");
338 return RET_FAILED;
339 }
340 LOGD("send dhcp inform...");
341 return RET_SUCCESS;
342 }
343
DhcpDecline(DhcpClientContext * ctx)344 int DhcpDecline(DhcpClientContext *ctx)
345 {
346 if (!ctx) {
347 return RET_FAILED;
348 }
349 DhcpMsgInfo msgInfo;
350 if (!InitMessage(ctx, &msgInfo, DHCPDECLINE)) {
351 LOGD("failed to init dhcp message.");
352 return RET_FAILED;
353 }
354 if (SendDhcpMessage(ctx, &msgInfo) != RET_SUCCESS) {
355 LOGD("failed to send dhcp message.");
356 return RET_FAILED;
357 }
358 LOGD("send dhcp decline...");
359 return RET_SUCCESS;
360 }
361
DhcpRelease(DhcpClientContext * ctx)362 int DhcpRelease(DhcpClientContext *ctx)
363 {
364 if (!ctx) {
365 return RET_FAILED;
366 }
367 DhcpMsgInfo msgInfo;
368 if (!InitMessage(ctx, &msgInfo, DHCPRELEASE)) {
369 LOGD("failed to init dhcp message.");
370 return RET_FAILED;
371 }
372 if (SendDhcpMessage(ctx, &msgInfo) != RET_SUCCESS) {
373 LOGD("failed to send dhcp message.");
374 return RET_FAILED;
375 }
376 LOGD("send dhcp release...");
377 return RET_SUCCESS;
378 }