• 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 <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 }