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 <stdio.h>
18 #include <stdint.h>
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 #define OPT_MESSAGE_TYPE_LEGTH 1
32 #define OPT_HEADER_LENGTH 2
33 #define OPT_TIME_LENGTH 4
34 #define OPT_TYPE_FIELD_LENGTH 1
35 #define OPT_MAC_ADDR_LENGTH 6
36 #define MAGIC_COOKIE_LENGTH 4
37 #define OPT_BROADCAST_FLAG_ENABLE 0
38
39 #define OFFER_MIN_INTERVAL_TIME 5
40
41 #define PENDING_DEFAULT_TIMEOUT 1200
42 #define PENDING_DEFAULT_INTERVAL 1
43 #define PENDING_INTERVAL_CHECKING_ENABLE 1
44 #define DHCP_MAGIC_COOKIE 0x63825363
45 #define ALLOW_NOBINDING_REQUEST 1
46 #define REUSE_ADDRESS_ENABLE 1
47 #define WAIT_STOPED_TIME 5
48
49 #undef LOG_TAG
50 #define LOG_TAG "DhcpMessageSimulator"
51
52
53 using namespace OHOS::Wifi;
54
GetInstance()55 DhcpMsgManager& DhcpMsgManager::GetInstance()
56 {
57 static DhcpMsgManager gMessageManager;
58 return gMessageManager;
59 }
60
SendTotal()61 int DhcpMsgManager::SendTotal()
62 {
63 int total = 0;
64 m_sendQueueLocker.lock();
65 total = m_sendMessages.size();
66 m_sendQueueLocker.unlock();
67 return total;
68 }
69
RecvTotal()70 int DhcpMsgManager::RecvTotal()
71 {
72 int total = 0;
73 m_recvQueueLocker.lock();
74 total = m_recvMessages.size();
75 m_recvQueueLocker.unlock();
76 return total;
77 }
78
FrontSendMsg(DhcpMessage * msg)79 bool DhcpMsgManager::FrontSendMsg(DhcpMessage *msg)
80 {
81 int retval = false;
82 if (!msg) {
83 return retval;
84 }
85 m_sendQueueLocker.lock();
86 if (!m_sendMessages.empty()) {
87 DhcpMessage fmsg = m_sendMessages.front();
88 if (memcpy_s(msg, sizeof(DhcpMessage), &fmsg, sizeof(DhcpMessage)) == EOK) {
89 retval = true;
90 }
91 }
92 m_sendQueueLocker.unlock();
93 return retval;
94 }
95
PopSendMsg()96 void DhcpMsgManager::PopSendMsg()
97 {
98 m_sendQueueLocker.lock();
99 if (m_sendMessages.size() > 0) {
100 m_sendMessages.pop();
101 }
102 m_sendQueueLocker.unlock();
103 }
104
PopRecvMsg()105 void DhcpMsgManager::PopRecvMsg()
106 {
107 m_recvQueueLocker.lock();
108 if (!m_recvMessages.empty()) {
109 m_recvMessages.pop();
110 }
111 m_recvQueueLocker.unlock();
112 }
113
PushSendMsg(const DhcpMessage & msg)114 int DhcpMsgManager::PushSendMsg(const DhcpMessage &msg)
115 {
116 m_sendQueueLocker.lock();
117 m_sendMessages.push(msg);
118 m_sendQueueLocker.unlock();
119 return 1;
120 }
121
PushRecvMsg(const DhcpMessage & msg)122 int DhcpMsgManager::PushRecvMsg(const DhcpMessage &msg)
123 {
124 m_recvQueueLocker.lock();
125 m_recvMessages.push(msg);
126 m_recvQueueLocker.unlock();
127 return 1;
128 }
129
SetClientIp(uint32_t ipAddr)130 void DhcpMsgManager::SetClientIp(uint32_t ipAddr)
131 {
132 m_clientIpAddress = ipAddr;
133 }
GetClientIp() const134 uint32_t DhcpMsgManager::GetClientIp() const
135 {
136 return m_clientIpAddress;
137 }
138
139 struct DhcpClientContext
140 {
141 int clientFd;
142 int state;
143 DhcpClientConfig config;
144 };
145
BroadcastAddrIn(void)146 struct sockaddr_in *BroadcastAddrIn(void)
147 {
148 static struct sockaddr_in broadcastAddrIn = {0};
149 if (broadcastAddrIn.sin_port == 0) {
150 broadcastAddrIn.sin_port = htons(DHCP_SERVER_PORT);
151 broadcastAddrIn.sin_family = AF_INET;
152 broadcastAddrIn.sin_addr.s_addr = INADDR_BROADCAST;
153 }
154 return &broadcastAddrIn;
155 }
DestinationAddr(void)156 struct sockaddr_in *DestinationAddr(void)
157 {
158 static struct sockaddr_in destAddrIn = {0};
159 if (destAddrIn.sin_port == 0) {
160 destAddrIn.sin_port = htons(DHCP_SERVER_PORT);
161 destAddrIn.sin_family = AF_INET;
162 destAddrIn.sin_addr.s_addr = INADDR_BROADCAST;
163 }
164 return &destAddrIn;
165 }
166
FillHwAddr(uint8_t * dst,size_t dsize,uint8_t * src,size_t ssize)167 int FillHwAddr(uint8_t *dst, size_t dsize, uint8_t *src, size_t ssize)
168 {
169 if (!dst || !src) {
170 return DHCP_FALSE;
171 }
172 if (ssize > dsize){
173 return DHCP_FALSE;
174 }
175 if (memset_s(dst, dsize, 0, dsize) != EOK) {
176 return DHCP_FALSE;
177 }
178 if (memcpy_s(dst, dsize, src, ssize) != EOK) {
179 return DHCP_FALSE;
180 }
181 return DHCP_TRUE;
182 }
183
SetDestinationAddr(uint32_t ipAddress)184 struct sockaddr_in *SetDestinationAddr(uint32_t ipAddress)
185 {
186 struct sockaddr_in *destAddr = DestinationAddr();
187 if (destAddr != nullptr) {
188 destAddr->sin_addr.s_addr = htons(ipAddress);
189 }
190 return destAddr;
191 }
192
InitialDhcpClient(DhcpClientConfig * config)193 DhcpClientContext *InitialDhcpClient(DhcpClientConfig *config)
194 {
195 LOGD("init dhcp client.");
196 if (!config) {
197 return NULL;
198 }
199 DhcpClientContext *context = (DhcpClientContext *)calloc(1, sizeof(DhcpClientContext));
200 if (context == NULL) {
201 LOGE("failed to calloc client context.");
202 return NULL;
203 }
204 if (memset_s(context, sizeof(DhcpClientContext), 0, sizeof(DhcpClientContext)) != EOK) {
205 LOGE("failed to reset client context.");
206 free(context);
207 return NULL;
208 }
209 if (memset_s(context->config.ifname, IFACE_NAME_SIZE, '\0', IFACE_NAME_SIZE) != EOK) {
210 LOGE("failed to reset interface name.");
211 free(context);
212 return NULL;
213 }
214 if (strncpy_s(context->config.ifname, IFACE_NAME_SIZE, config->ifname, strlen(config->ifname)) != EOK) {
215 LOGE("failed to set interface name.");
216 free(context);
217 return NULL;
218 }
219 if (!FillHwAddr(context->config.chaddr, DHCP_HWADDR_LENGTH, config->chaddr, MAC_ADDR_LENGTH)) {
220 LOGE("failed to set chaddr.");
221 free(context);
222 return NULL;
223 }
224 context->clientFd = 1;
225 return context;
226 }
227
ParseDhcpOptions(PDhcpMsgInfo msg)228 int ParseDhcpOptions(PDhcpMsgInfo msg)
229 {
230 int ret;
231 PDhcpOptionNode pNode = msg->options.first->next;
232 DhcpOption endOpt = {END_OPTION, 0, {0}};
233 PushBackOption(&msg->options, &endOpt);
234 int replyOptsLength = 0;
235 uint8_t *current = msg->packet.options, olen = MAGIC_COOKIE_LENGTH;
236 uint32_t cookie = htonl(DHCP_MAGIC_COOKIE);
237 if (memcpy_s(current, olen, &cookie, olen) != EOK) {
238 LOGE("memcpy cookie out of options buffer!");
239 return RET_FAILED;
240 }
241 replyOptsLength += olen;
242 current += olen;
243 ret = RET_SUCCESS;
244 while (pNode && (uint32_t)pNode->option.length < DHCP_OPTION_SIZE) {
245 if ((uint32_t)pNode->option.code == END_OPTION) {
246 olen = OPT_HEADER_LENGTH + 1;
247 } else {
248 olen = OPT_HEADER_LENGTH + pNode->option.length;
249 }
250 if (memcpy_s(current, olen, &pNode->option, olen) != EOK) {
251 LOGE("memcpy current option out of options buffer!");
252 ret = RET_FAILED;
253 break;
254 }
255 current += olen;
256 replyOptsLength += olen;
257 if ((uint32_t)pNode->option.code == END_OPTION) {
258 break;
259 }
260 pNode = pNode->next;
261 if (replyOptsLength >= DHCP_OPTIONS_SIZE) {
262 LOGE("current option out of options buffer!");
263 ret = RET_FAILED;
264 break;
265 }
266 }
267 msg->length += replyOptsLength;
268 return ret;
269 }
270
SendDhcpMessage(DhcpClientContext * ctx,PDhcpMsgInfo msg)271 int SendDhcpMessage(DhcpClientContext *ctx, PDhcpMsgInfo msg)
272 {
273 if (!ctx || !msg) {
274 LOGE("client context or message pointer is null.");
275 return RET_FAILED;
276 }
277 if (ParseDhcpOptions(msg) != RET_SUCCESS) {
278 LOGE("failed to parse dhcp message info.");
279 return RET_FAILED;
280 }
281 DhcpMsgManager::GetInstance().PushSendMsg(msg->packet);
282 return RET_SUCCESS;
283 }
284
GetXid(int update)285 static uint32_t GetXid(int update)
286 {
287 static uint32_t currXid = Tmspsec();
288 if (update) {
289 currXid = Tmspsec();
290 }
291 return currXid;
292 }
293
InitMessage(DhcpClientContext * ctx,PDhcpMsgInfo msg,uint8_t msgType)294 int InitMessage(DhcpClientContext *ctx, PDhcpMsgInfo msg, uint8_t msgType)
295 {
296 LOGD("init dhcp message...");
297 if (!ctx) {
298 LOGD("client context pointer is null.");
299 return DHCP_FALSE;
300 }
301 if (!msg) {
302 LOGD("dhcp message pointer is null.");
303 return DHCP_FALSE;
304 }
305 if (memset_s(msg, sizeof(DhcpMsgInfo), 0, sizeof(DhcpMsgInfo)) != EOK) {
306 LOGD("message info pointer is null.");
307 return DHCP_FALSE;
308 }
309 if (InitOptionList(&msg->options) != RET_SUCCESS) {
310 LOGD("failed to initialize dhcp client options.");
311 return DHCP_FALSE;
312 }
313 if (!FillHwAddr(msg->packet.chaddr, DHCP_HWADDR_LENGTH, ctx->config.chaddr, MAC_ADDR_LENGTH)) {
314 return DHCP_FALSE;
315 }
316 msg->packet.op = BOOTREQUEST;
317 msg->packet.htype = 0x01;
318 msg->packet.hlen = MAC_ADDR_LENGTH;
319 if (msgType == DHCPDISCOVER) {
320 msg->packet.xid = GetXid(DHCP_TRUE);
321 } else {
322 msg->packet.xid = GetXid(DHCP_FALSE);
323 }
324
325 if (DhcpMsgManager::GetInstance().GetClientIp() != 0) {
326 DhcpOption optReqIp = {REQUESTED_IP_ADDRESS_OPTION, 0, {0}};
327 AppendAddressOption(&optReqIp, DhcpMsgManager::GetInstance().GetClientIp());
328 PushFrontOption(&msg->options, &optReqIp);
329 }
330
331 DhcpOption optMsgType = {DHCP_MESSAGE_TYPE_OPTION, OPT_MESSAGE_TYPE_LEGTH, {msgType, 0}};
332 PushFrontOption(&msg->options, &optMsgType);
333
334 PDhcpOption pEndOpt = GetOption(&msg->options, END_OPTION);
335 if (pEndOpt == NULL) {
336 DhcpOption endOpt = {END_OPTION, 0, {0}};
337 PushBackOption(&msg->options, &endOpt);
338 }
339 return DHCP_TRUE;
340 }
341
DhcpDiscover(DhcpClientContext * ctx)342 int DhcpDiscover(DhcpClientContext *ctx)
343 {
344 if (!ctx) {
345 return RET_FAILED;
346 }
347 DhcpMsgInfo msgInfo;
348 if (!InitMessage(ctx, &msgInfo, DHCPDISCOVER)) {
349 LOGD("failed to init dhcp message.");
350 return RET_FAILED;
351 }
352 if (SendDhcpMessage(ctx, &msgInfo) != RET_SUCCESS) {
353 LOGD("failed to send dhcp message.");
354 return RET_FAILED;
355 }
356 LOGD("send dhcp discover...");
357 return RET_SUCCESS;
358 }
359
DhcpRequest(DhcpClientContext * ctx)360 int DhcpRequest(DhcpClientContext *ctx)
361 {
362 if (!ctx) {
363 return RET_FAILED;
364 }
365 DhcpMsgInfo msgInfo;
366 if (!InitMessage(ctx, &msgInfo, DHCPREQUEST)) {
367 LOGD("failed to init dhcp message.");
368 return RET_FAILED;
369 }
370 if (SendDhcpMessage(ctx, &msgInfo) != RET_SUCCESS) {
371 LOGD("failed to send dhcp message.");
372 return RET_FAILED;
373 }
374 LOGD("send dhcp request...");
375 return RET_SUCCESS;
376 }
377
DhcpInform(DhcpClientContext * ctx)378 int DhcpInform(DhcpClientContext *ctx)
379 {
380 if (!ctx) {
381 return RET_FAILED;
382 }
383 DhcpMsgInfo msgInfo;
384 if (!InitMessage(ctx, &msgInfo, DHCPINFORM)) {
385 LOGD("failed to init dhcp message.");
386 return RET_FAILED;
387 }
388 if (SendDhcpMessage(ctx, &msgInfo) != RET_SUCCESS) {
389 LOGD("failed to send dhcp message.");
390 return RET_FAILED;
391 }
392 LOGD("send dhcp inform...");
393 return RET_SUCCESS;
394 }
395
DhcpDecline(DhcpClientContext * ctx)396 int DhcpDecline(DhcpClientContext *ctx)
397 {
398 if (!ctx) {
399 return RET_FAILED;
400 }
401 DhcpMsgInfo msgInfo;
402 if (!InitMessage(ctx, &msgInfo, DHCPDECLINE)) {
403 LOGD("failed to init dhcp message.");
404 return RET_FAILED;
405 }
406 if (SendDhcpMessage(ctx, &msgInfo) != RET_SUCCESS) {
407 LOGD("failed to send dhcp message.");
408 return RET_FAILED;
409 }
410 LOGD("send dhcp decline...");
411 return RET_SUCCESS;
412 }
413
DhcpRelease(DhcpClientContext * ctx)414 int DhcpRelease(DhcpClientContext *ctx)
415 {
416 if (!ctx) {
417 return RET_FAILED;
418 }
419 DhcpMsgInfo msgInfo;
420 if (!InitMessage(ctx, &msgInfo, DHCPRELEASE)) {
421 LOGD("failed to init dhcp message.");
422 return RET_FAILED;
423 }
424 if (SendDhcpMessage(ctx, &msgInfo) != RET_SUCCESS) {
425 LOGD("failed to send dhcp message.");
426 return RET_FAILED;
427 }
428 LOGD("send dhcp release...");
429 return RET_SUCCESS;
430 }