• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }