1 /*
2  * Copyright (C) 2021-2023 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 "nstackx_device_local.h"
17 #include <securec.h>
18 #include "nstackx_dfinder_hidump.h"
19 #include "nstackx_error.h"
20 #include "nstackx_dev.h"
21 #include "nstackx_dfinder_log.h"
22 #include "nstackx_statistics.h"
23 #include "nstackx_timer.h"
24 #include "nstackx_util.h"
25 #include "nstackx_device_remote.h"
26 #include "nstackx_list.h"
27 
28 #define TAG "LOCALDEVICE"
29 enum {
30     IFACE_STATE_READY,
31     IFACE_STATE_DESTROYING,
32     IFACE_STATE_CREATING,
33 };
34 
35 struct LocalIface {
36     List node;
37 
38     char ifname[NSTACKX_MAX_INTERFACE_NAME_LEN];
39     char ipStr[NSTACKX_MAX_IP_STRING_LEN];
40     struct in_addr ip;
41 
42     uint8_t type;
43     uint8_t state;
44     struct timespec updateTime;
45 
46     Timer *timer;
47     uint8_t createCount;
48 
49     CoapCtxType *ctx;
50 };
51 
52 typedef struct LocalDevice_ {
53     DeviceInfo deviceInfo;
54 
55     List readyList[IFACE_TYPE_MAX];
56     List creatingList;
57     List destroyList;
58 
59     Timer *timer;
60     bool inited;
61 } LocalDevice;
62 
63 static LocalDevice g_localDevice;
64 
65 #define LOCAL_DEVICE_OFFLINE_DEFERRED_DURATION 5000 /* Defer local device offline event, 5 seconds */
66 
67 #define NSTACKX_DEFAULT_DEVICE_NAME "nStack Device"
68 
69 #define IFACE_COAP_CTX_INIT_MAX_RETRY_TIMES 4
70 static const uint32_t g_ifaceCoapCtxRetryBackoffList[IFACE_COAP_CTX_INIT_MAX_RETRY_TIMES] = { 10, 15, 25, 100 };
71 
LocalDeviceTimeout(void * data)72 static void LocalDeviceTimeout(void *data)
73 {
74     (void)data;
75 
76     struct timespec cur;
77     ClockGetTime(CLOCK_MONOTONIC, &cur);
78 
79     uint32_t nextTimeout = 0;
80     List *pos = NULL;
81     List *tmp = NULL;
82     LIST_FOR_EACH_SAFE(pos, tmp, &g_localDevice.destroyList) {
83         struct LocalIface *iface = (struct LocalIface *)pos;
84         uint32_t diff = GetTimeDiffMs(&cur, &iface->updateTime);
85         if (diff < LOCAL_DEVICE_OFFLINE_DEFERRED_DURATION) {
86             nextTimeout = LOCAL_DEVICE_OFFLINE_DEFERRED_DURATION - diff;
87             break;
88         }
89 
90         DestroyLocalIface(iface, NSTACKX_FALSE);
91     }
92 
93     if (nextTimeout != 0) {
94         DFINDER_LOGD(TAG, "start offline timer again, timeout %u", nextTimeout);
95         (void)TimerSetTimeout(g_localDevice.timer, nextTimeout, NSTACKX_FALSE);
96     }
97 }
98 
LocalDeviceDeinit(void)99 void LocalDeviceDeinit(void)
100 {
101     if (!g_localDevice.inited) {
102         DFINDER_LOGW(TAG, "local device not inited");
103         return;
104     }
105 
106     List *pos = NULL;
107     List *tmp = NULL;
108     int i;
109     for (i = 0; i < IFACE_TYPE_MAX; i++) {
110         LIST_FOR_EACH_SAFE(pos, tmp, &g_localDevice.readyList[i]) {
111             DestroyLocalIface((struct LocalIface *)pos, NSTACKX_TRUE);
112         }
113     }
114 
115     LIST_FOR_EACH_SAFE(pos, tmp, &g_localDevice.destroyList) {
116         DestroyLocalIface((struct LocalIface *)pos, NSTACKX_TRUE);
117     }
118 
119     LIST_FOR_EACH_SAFE(pos, tmp, &g_localDevice.creatingList) {
120         DestroyLocalIface((struct LocalIface *)pos, NSTACKX_TRUE);
121     }
122 
123     if (g_localDevice.timer != NULL) {
124         TimerDelete(g_localDevice.timer);
125         g_localDevice.timer = NULL;
126     }
127 
128     g_localDevice.inited = NSTACKX_FALSE;
129 }
130 
LocalDeviceInit(EpollDesc epollfd)131 int LocalDeviceInit(EpollDesc epollfd)
132 {
133     (void)memset_s(&g_localDevice, sizeof(g_localDevice), 0, sizeof(g_localDevice));
134     g_localDevice.timer = TimerStart(epollfd, 0, NSTACKX_FALSE, LocalDeviceTimeout, NULL);
135     if (g_localDevice.timer == NULL) {
136         DFINDER_LOGE(TAG, "timer init failed");
137         return NSTACKX_EFAILED;
138     }
139 
140     int i;
141     for (i = 0; i < IFACE_TYPE_MAX; i++) {
142         ListInitHead(&g_localDevice.readyList[i]);
143     }
144 
145     ListInitHead(&g_localDevice.destroyList);
146     ListInitHead(&g_localDevice.creatingList);
147     g_localDevice.inited = NSTACKX_TRUE;
148 
149     return NSTACKX_EOK;
150 }
151 
ResetLocalDeviceTaskCount(uint8_t isBusy)152 void ResetLocalDeviceTaskCount(uint8_t isBusy)
153 {
154     if (g_localDevice.timer != NULL) {
155         if (isBusy) {
156             DFINDER_LOGI(TAG, "in this busy interval: offline deferred timer task count %llu",
157                          g_localDevice.timer->task.count);
158         }
159         g_localDevice.timer->task.count = 0;
160     }
161 }
162 
LocalIfaceChangeState(struct LocalIface * iface,List * targetList,uint8_t state)163 static inline void LocalIfaceChangeState(struct LocalIface *iface, List *targetList, uint8_t state)
164 {
165     DFINDER_LOGI(TAG, "iface %s state change: %hhu -> %hhu", iface->ifname, iface->state, state);
166     ListRemoveNode(&iface->node);
167     iface->state = state;
168     ListInsertTail(targetList, &iface->node);
169 }
170 
LocalIfaceCreateContextTimeout(void * arg)171 static void LocalIfaceCreateContextTimeout(void *arg)
172 {
173     struct LocalIface *iface = (struct LocalIface *)arg;
174     DFINDER_LOGD(TAG, "iface %s create context for %u times", iface->ifname, iface->createCount);
175     iface->ctx = CoapServerInit(&iface->ip, (void *)iface);
176     if (iface->ctx != NULL) {
177         DFINDER_LOGD(TAG, "iface %s create coap context success", iface->ifname);
178         TimerDelete(iface->timer);
179         iface->timer = NULL;
180         LocalIfaceChangeState(iface, &g_localDevice.readyList[iface->type], IFACE_STATE_READY);
181         return;
182     }
183 
184     if (iface->createCount >= IFACE_COAP_CTX_INIT_MAX_RETRY_TIMES) {
185         DFINDER_LOGE(TAG, "create context retry reach max times %hhu", iface->createCount);
186         DestroyLocalIface(iface, NSTACKX_FALSE);
187         return;
188     }
189 
190     (void)TimerSetTimeout(iface->timer, g_ifaceCoapCtxRetryBackoffList[iface->createCount], NSTACKX_FALSE);
191     iface->createCount++;
192 }
193 
NeedCreateSynchronously(uint8_t ifaceType)194 static inline bool NeedCreateSynchronously(uint8_t ifaceType)
195 {
196     return ifaceType < IFACE_TYPE_P2P;
197 }
198 
LocalIfaceInit(struct LocalIface * iface,const char * ifname,const struct in_addr * ip,const char * ipStr)199 static int LocalIfaceInit(struct LocalIface *iface, const char *ifname, const struct in_addr *ip, const char *ipStr)
200 {
201     DFINDER_LOGI(TAG, "trying to bring up interface %s", ifname);
202 
203     if (strcpy_s(iface->ifname, sizeof(iface->ifname), ifname) != EOK) {
204         DFINDER_LOGE(TAG, "copy ifname %s failed", ifname);
205         return NSTACKX_EFAILED;
206     }
207     if (strcpy_s(iface->ipStr, sizeof(iface->ipStr), ipStr) != EOK) {
208         DFINDER_LOGE(TAG, "copy ip string failed");
209         return NSTACKX_EFAILED;
210     }
211     iface->type = GetIfaceType(ifname);
212     iface->ip.s_addr = ip->s_addr;
213 
214     if (NeedCreateSynchronously(iface->type)) {
215         iface->ctx = CoapServerInit(ip, (void *)iface);
216         if (iface->ctx == NULL) {
217             DFINDER_LOGE(TAG, "create coap context failed");
218             IncStatistics(STATS_CREATE_SERVER_FAILED);
219             return NSTACKX_EFAILED;
220         }
221         iface->state = IFACE_STATE_READY;
222         ListInsertTail(&g_localDevice.readyList[iface->type], &iface->node);
223     } else {
224         iface->timer = TimerStart(GetEpollFD(), g_ifaceCoapCtxRetryBackoffList[0],
225             NSTACKX_FALSE, LocalIfaceCreateContextTimeout, iface);
226         if (iface->timer == NULL) {
227             DFINDER_LOGE(TAG, "iface %s create timer to create context async failed", iface->ifname);
228             return NSTACKX_EFAILED;
229         }
230         iface->createCount = 1;
231         iface->state = IFACE_STATE_CREATING;
232         ListInsertTail(&g_localDevice.creatingList, &iface->node);
233     }
234 
235     return NSTACKX_EOK;
236 }
237 
CreateLocalIface(const char * ifname,const struct in_addr * ip,const char * ipStr)238 static struct LocalIface *CreateLocalIface(const char *ifname, const struct in_addr *ip, const char *ipStr)
239 {
240     struct LocalIface *iface = calloc(1, sizeof(struct LocalIface));
241     if (iface == NULL) {
242         DFINDER_LOGE(TAG, "alloc falied");
243         return NULL;
244     }
245 
246     if (LocalIfaceInit(iface, ifname, ip, ipStr) != NSTACKX_EOK) {
247         DFINDER_LOGE(TAG, "local iface init failed");
248         free(iface);
249         return NULL;
250     }
251 
252     return iface;
253 }
254 
DestroyLocalIface(struct LocalIface * iface,bool moduleDeinit)255 void DestroyLocalIface(struct LocalIface *iface, bool moduleDeinit)
256 {
257     DFINDER_LOGI(TAG, "destroy iface %s, type: %hhu state: %hhu", iface->ifname, iface->type, iface->state);
258 
259 #ifdef DFINDER_SAVE_DEVICE_LIST
260     DestroyRxIfaceByIfname(iface->ifname);
261 #endif
262 
263     if (iface->ctx != NULL) {
264         CoapServerDestroy(iface->ctx, moduleDeinit);
265     }
266     ListRemoveNode(&iface->node);
267     if (iface->timer != NULL) {
268         TimerDelete(iface->timer);
269     }
270     free(iface);
271 }
272 
GetLocalIface(List * head,const char * ifname,const struct in_addr * ip)273 static struct LocalIface *GetLocalIface(List *head, const char *ifname, const struct in_addr *ip)
274 {
275     List *pos = NULL;
276     LIST_FOR_EACH(pos, head) {
277         struct LocalIface *iface = (struct LocalIface *)pos;
278         DFINDER_LOGD(TAG, "local ifname: %s, ifname: %s", iface->ifname, ifname);
279         if (strcmp(iface->ifname, ifname) == 0 && (ip == NULL || ip->s_addr == iface->ip.s_addr)) {
280             return iface;
281         }
282     }
283 
284     return NULL;
285 }
286 
GetActiveLocalIface(const char * ifname)287 static struct LocalIface *GetActiveLocalIface(const char *ifname)
288 {
289     uint8_t type = GetIfaceType(ifname);
290     struct LocalIface *iface = GetLocalIface(&g_localDevice.readyList[type], ifname, NULL);
291     if (iface == NULL) {
292         iface = GetLocalIface(&g_localDevice.creatingList, ifname, NULL);
293     }
294 
295     return iface;
296 }
297 
AddToDestroyList(struct LocalIface * iface)298 static void AddToDestroyList(struct LocalIface *iface)
299 {
300     if (iface->state != IFACE_STATE_DESTROYING) {
301         if (ListIsEmpty(&g_localDevice.destroyList)) {
302             (void)TimerSetTimeout(g_localDevice.timer, LOCAL_DEVICE_OFFLINE_DEFERRED_DURATION, NSTACKX_FALSE);
303             DFINDER_LOGD(TAG, "iface %s start offline timer", iface->ifname);
304         }
305         LocalIfaceChangeState(iface, &g_localDevice.destroyList, IFACE_STATE_DESTROYING);
306         ClockGetTime(CLOCK_MONOTONIC, &iface->updateTime);
307         if (iface->timer != NULL) {
308             (void)TimerSetTimeout(iface->timer, 0, NSTACKX_FALSE);
309             iface->createCount = 0;
310         }
311     }
312 }
313 
AddLocalIface(const char * ifname,const struct in_addr * ip)314 int AddLocalIface(const char *ifname, const struct in_addr *ip)
315 {
316     struct LocalIface *iface = GetActiveLocalIface(ifname);
317     if (iface == NULL) {
318         iface = GetLocalIface(&g_localDevice.destroyList, ifname, ip);
319         if (iface != NULL) {
320             DFINDER_LOGW(TAG, "iface %s is in destroying", ifname);
321             LocalIfaceChangeState(iface, &g_localDevice.readyList[iface->type], IFACE_STATE_READY);
322             return NSTACKX_EOK;
323         }
324     } else {
325         if (iface->ip.s_addr == ip->s_addr) {
326             DFINDER_LOGW(TAG, "iface %s already existed", ifname);
327             return NSTACKX_EOK;
328         }
329 
330         AddToDestroyList(iface);
331     }
332 
333     char ipStr[INET_ADDRSTRLEN] = {0};
334     if (inet_ntop(AF_INET, ip, ipStr, sizeof(ipStr)) == NULL) {
335         DFINDER_LOGE(TAG, "ip to string failed");
336         return NSTACKX_EFAILED;
337     }
338 
339     iface = CreateLocalIface(ifname, ip, ipStr);
340     return (iface == NULL) ? NSTACKX_EFAILED : NSTACKX_EOK;
341 }
342 
RemoveLocalIface(const char * ifname)343 void RemoveLocalIface(const char *ifname)
344 {
345     struct LocalIface *iface = GetActiveLocalIface(ifname);
346     if (iface == NULL) {
347         DFINDER_LOGW(TAG, "iface %s not found when deleting iface", ifname);
348         return;
349     }
350 
351     AddToDestroyList(iface);
352 }
353 
RemoveAllLocalIfaceOfList(List * list)354 static void RemoveAllLocalIfaceOfList(List *list)
355 {
356     List *pos = NULL;
357     List *tmp = NULL;
358     LIST_FOR_EACH_SAFE(pos, tmp, list) {
359         AddToDestroyList((struct LocalIface *)pos);
360     }
361 }
362 
RemoveAllLocalIface(void)363 static void RemoveAllLocalIface(void)
364 {
365     uint8_t i;
366     for (i = IFACE_TYPE_ETH; i < IFACE_TYPE_MAX; i++) {
367         RemoveAllLocalIfaceOfList(&g_localDevice.readyList[i]);
368     }
369 
370     RemoveAllLocalIfaceOfList(&g_localDevice.creatingList);
371 }
372 
RemoveSpecifiedLocalIface(const NSTACKX_InterfaceInfo * ifInfo,uint32_t ifNums)373 static inline void RemoveSpecifiedLocalIface(const NSTACKX_InterfaceInfo *ifInfo, uint32_t ifNums)
374 {
375     uint32_t i;
376     for (i = 0; i < ifNums; ++i) {
377         RemoveLocalIface(ifInfo[i].networkName);
378     }
379 }
380 
AddLocalIfaceIpChanged(const NSTACKX_InterfaceInfo * ifInfo,uint32_t ifNums)381 static int AddLocalIfaceIpChanged(const NSTACKX_InterfaceInfo *ifInfo, uint32_t ifNums)
382 {
383     uint8_t ifaceType = IFACE_TYPE_MAX;
384     uint32_t i;
385     for (i = 0; i < ifNums; ++i) {
386         if (ifInfo->networkName[0] == '\0' || ifInfo->networkIpAddr[0] == '\0') {
387             DFINDER_LOGI(TAG, "skip empty network name or ip addr");
388             continue;
389         }
390 
391         struct in_addr ip;
392         if (inet_pton(AF_INET, ifInfo[i].networkIpAddr, &ip) != 1) {
393             DFINDER_LOGE(TAG, "invalid ip addr of iface %u", ifInfo[i].networkName);
394             return NSTACKX_EFAILED;
395         }
396 
397         if (ip.s_addr == 0) {
398             DFINDER_LOGI(TAG, "skip ip with any");
399             continue;
400         }
401 
402         if (AddLocalIface(ifInfo[i].networkName, &ip) != NSTACKX_EOK) {
403             DFINDER_LOGE(TAG, "create local iface %s failed", ifInfo[i].networkName);
404             return NSTACKX_EFAILED;
405         }
406 
407         uint8_t curIfaceType = GetIfaceType(ifInfo[i].networkName);
408         if (curIfaceType < ifaceType) { /* storge the highest priority interface name */
409             if (strcpy_s(g_localDevice.deviceInfo.networkName, sizeof(g_localDevice.deviceInfo.networkName),
410                 ifInfo[i].networkName) != EOK) {
411                 DFINDER_LOGE(TAG, "copy ifname %s failed", ifInfo[i].networkName);
412                 return NSTACKX_EFAILED;
413             }
414             ifaceType = curIfaceType;
415         }
416     }
417 
418     return NSTACKX_EOK;
419 }
420 
CopyDeviceInfoV2(const NSTACKX_LocalDeviceInfoV2 * devInfo)421 static int CopyDeviceInfoV2(const NSTACKX_LocalDeviceInfoV2 *devInfo)
422 {
423     if (strcpy_s(g_localDevice.deviceInfo.deviceId, sizeof(g_localDevice.deviceInfo.deviceId),
424         devInfo->deviceId) != EOK) {
425         DFINDER_LOGE(TAG, "copy device id failed");
426         return NSTACKX_EFAILED;
427     }
428 
429     if (devInfo->name[0] == '\0') {
430         DFINDER_LOGW(TAG, "Invalid device name. Will use default name");
431         (void)strcpy_s(g_localDevice.deviceInfo.deviceName,
432             sizeof(g_localDevice.deviceInfo.deviceName), NSTACKX_DEFAULT_DEVICE_NAME);
433     } else {
434         if (strcpy_s(g_localDevice.deviceInfo.deviceName,
435             sizeof(g_localDevice.deviceInfo.deviceName), devInfo->name) != EOK) {
436             DFINDER_LOGE(TAG, "copy device name %s failed", devInfo->name);
437             return NSTACKX_EFAILED;
438         }
439     }
440 
441     if (strcpy_s(g_localDevice.deviceInfo.version, sizeof(g_localDevice.deviceInfo.version),
442         devInfo->version) != EOK) {
443         DFINDER_LOGE(TAG, "copy version %s failed", devInfo->version);
444         return NSTACKX_EFAILED;
445     }
446 
447     g_localDevice.deviceInfo.deviceType = devInfo->deviceType;
448     g_localDevice.deviceInfo.businessType = devInfo->businessType;
449     if (devInfo->hasDeviceHash) {
450         SetLocalDeviceHash(devInfo->deviceHash);
451     }
452 
453     return NSTACKX_EOK;
454 }
455 
RegisterLocalDeviceV2(const NSTACKX_LocalDeviceInfoV2 * devInfo,int registerType)456 int RegisterLocalDeviceV2(const NSTACKX_LocalDeviceInfoV2 *devInfo, int registerType)
457 {
458     if (registerType == REGISTER_TYPE_UPDATE_ALL) {
459         RemoveAllLocalIface();
460     } else {
461         RemoveSpecifiedLocalIface(devInfo->localIfInfo, devInfo->ifNums);
462     }
463 
464     if (CopyDeviceInfoV2(devInfo) != NSTACKX_EOK) {
465         return NSTACKX_EFAILED;
466     }
467 
468     if (AddLocalIfaceIpChanged(devInfo->localIfInfo, devInfo->ifNums) != NSTACKX_EOK) {
469         if (registerType == REGISTER_TYPE_UPDATE_ALL) {
470             RemoveAllLocalIface(); /* maybe some ifaces is added, so remove all ifaces again */
471         }
472         return NSTACKX_EFAILED;
473     }
474 
475     return NSTACKX_EOK;
476 }
477 
ConfigureLocalDeviceName(const char * localDeviceName)478 void ConfigureLocalDeviceName(const char *localDeviceName)
479 {
480     char backupDevName[NSTACKX_MAX_DEVICE_NAME_LEN] = {0};
481     if (memcpy_s(backupDevName, sizeof(backupDevName), g_localDevice.deviceInfo.deviceName,
482         sizeof(g_localDevice.deviceInfo.deviceName)) != EOK) {
483         DFINDER_LOGE(TAG, "backup local device name failed!");
484         return;
485     }
486     if (strncpy_s(g_localDevice.deviceInfo.deviceName, NSTACKX_MAX_DEVICE_NAME_LEN,
487         localDeviceName, NSTACKX_MAX_DEVICE_NAME_LEN - 1) != EOK) {
488         DFINDER_LOGW(TAG, "copy local device failed, will use current name");
489         if (strcpy_s(g_localDevice.deviceInfo.deviceName, NSTACKX_MAX_DEVICE_NAME_LEN, backupDevName) != EOK) {
490             DFINDER_LOGE(TAG, "config device name failed and cannot restore!");
491         }
492     }
493 }
494 
SetLocalDeviceHash(uint64_t deviceHash)495 void SetLocalDeviceHash(uint64_t deviceHash)
496 {
497     (void)memset_s(g_localDevice.deviceInfo.deviceHash, sizeof(g_localDevice.deviceInfo.deviceHash),
498         0, sizeof(g_localDevice.deviceInfo.deviceHash));
499     if (sprintf_s(g_localDevice.deviceInfo.deviceHash, DEVICE_HASH_LEN,
500         "%ju", deviceHash) == -1) {
501         DFINDER_LOGE(TAG, "set device hash error");
502     }
503 }
504 
SetLocalDeviceCapability(uint32_t capabilityBitmapNum,uint32_t capabilityBitmap[])505 int SetLocalDeviceCapability(uint32_t capabilityBitmapNum, uint32_t capabilityBitmap[])
506 {
507     (void)memset_s(g_localDevice.deviceInfo.capabilityBitmap, sizeof(g_localDevice.deviceInfo.capabilityBitmap),
508         0, sizeof(g_localDevice.deviceInfo.capabilityBitmap));
509     g_localDevice.deviceInfo.capabilityBitmapNum = 0;
510 
511     if (capabilityBitmapNum > 0) {
512         if (memcpy_s(g_localDevice.deviceInfo.capabilityBitmap, sizeof(g_localDevice.deviceInfo.capabilityBitmap),
513             capabilityBitmap, sizeof(uint32_t) * capabilityBitmapNum) != EOK) {
514             DFINDER_LOGE(TAG, "capabilityBitmap copy error");
515             return NSTACKX_EFAILED;
516         }
517     }
518 
519     g_localDevice.deviceInfo.capabilityBitmapNum = capabilityBitmapNum;
520     return NSTACKX_EOK;
521 }
522 
SetLocalDeviceServiceData(const char * serviceData)523 int32_t SetLocalDeviceServiceData(const char *serviceData)
524 {
525     if (strcpy_s(g_localDevice.deviceInfo.serviceData, NSTACKX_MAX_SERVICE_DATA_LEN, serviceData) != EOK) {
526         DFINDER_LOGE(TAG, "serviceData copy error");
527         return NSTACKX_EFAILED;
528     }
529     return NSTACKX_EOK;
530 }
531 
SetLocalDeviceBusinessType(uint8_t businessType)532 void SetLocalDeviceBusinessType(uint8_t businessType)
533 {
534     g_localDevice.deviceInfo.businessType = businessType;
535 }
536 
GetLocalDeviceBusinessType(void)537 uint8_t GetLocalDeviceBusinessType(void)
538 {
539     return g_localDevice.deviceInfo.businessType;
540 }
541 
SetLocalDeviceBusinessData(const char * data,bool unicast)542 int SetLocalDeviceBusinessData(const char *data, bool unicast)
543 {
544     int ret = EOK;
545     if (unicast) {
546         ret = strcpy_s(g_localDevice.deviceInfo.businessData.businessDataUnicast,
547             NSTACKX_MAX_BUSINESS_DATA_LEN, data);
548     } else {
549         ret = strcpy_s(g_localDevice.deviceInfo.businessData.businessDataBroadcast,
550             NSTACKX_MAX_BUSINESS_DATA_LEN, data);
551     }
552 
553     if (ret != EOK) {
554         DFINDER_LOGE(TAG, "businessData copy error, unicast: %d", unicast);
555         return NSTACKX_EFAILED;
556     }
557 
558     return NSTACKX_EOK;
559 }
560 
LocalizeNotificationMsg(const char * msg)561 int32_t LocalizeNotificationMsg(const char *msg)
562 {
563     if (strcpy_s(g_localDevice.deviceInfo.notification, NSTACKX_MAX_NOTIFICATION_DATA_LEN, msg) != EOK) {
564         DFINDER_LOGE(TAG, "copy notification msg to local dev failed");
565         return NSTACKX_EFAILED;
566     }
567     return NSTACKX_EOK;
568 }
569 
GetLocalDeviceMode(void)570 uint8_t GetLocalDeviceMode(void)
571 {
572     return g_localDevice.deviceInfo.mode;
573 }
574 
SetLocalDeviceMode(uint8_t mode)575 void SetLocalDeviceMode(uint8_t mode)
576 {
577     g_localDevice.deviceInfo.mode = mode;
578 }
579 
580 #ifndef DFINDER_USE_MINI_NSTACKX
SetLocalDeviceExtendServiceData(const char * extendServiceData)581 int32_t SetLocalDeviceExtendServiceData(const char *extendServiceData)
582 {
583     if (strcpy_s(g_localDevice.deviceInfo.extendServiceData, NSTACKX_MAX_EXTEND_SERVICE_DATA_LEN,
584         extendServiceData) != EOK) {
585         DFINDER_LOGE(TAG, "extendServiceData copy error");
586         return NSTACKX_EFAILED;
587     }
588     return NSTACKX_EOK;
589 }
590 
591 #ifndef _WIN32
DetectLocalIface(void * arg)592 void DetectLocalIface(void *arg)
593 {
594     struct ifconf ifc;
595     struct ifreq req[INTERFACE_MAX];
596     int fd = GetInterfaceList(&ifc, req, sizeof(req));
597     if (fd < 0) {
598         DFINDER_LOGE(TAG, "get iface list failed");
599         return;
600     }
601 
602     int interfaceNum = ifc.ifc_len / (int)sizeof(struct ifreq);
603     for (int i = 0; i < interfaceNum && i < INTERFACE_MAX; i++) {
604         /* get IP of this interface */
605         int state = GetInterfaceIP(fd, &req[i]);
606         if (state == NSTACKX_EFAILED) {
607             (void)close(fd);
608             return;
609         } else if (state == NSTACKX_EINVAL) {
610             continue;
611         }
612 
613         uint8_t ifaceType = GetIfaceType(req[i].ifr_name);
614         if (ifaceType > IFACE_TYPE_WLAN) {
615             DFINDER_LOGI(TAG, "skip iface %s", req[i].ifr_name);
616             continue;
617         }
618 
619         struct in_addr *ip = &((struct sockaddr_in *)&req[i].ifr_addr)->sin_addr;
620         if (req[i].ifr_addr.sa_family != AF_INET || ip->s_addr == 0) {
621             DFINDER_LOGD(TAG, "iface %s is not ipv4 or ip is any", req[i].ifr_name);
622             continue;
623         }
624 
625         DFINDER_LOGI(TAG, "try to add new iface %s", req[i].ifr_name);
626         (void)AddLocalIface(req[i].ifr_name, ip);
627     }
628     (void)close(fd);
629 
630     (void)arg;
631 }
632 #endif /* _WIN32 */
633 
634 #endif /* END OF DFINDER_USE_MINI_NSTACKX */
635 
GetBroadcastIp(const struct LocalIface * iface,char * ipStr,size_t ipStrLen)636 int GetBroadcastIp(const struct LocalIface *iface, char *ipStr, size_t ipStrLen)
637 {
638 #ifdef _WIN32
639     return GetIfBroadcastAddr(&iface->ip, ipStr, ipStrLen);
640 #else
641     return GetIfBroadcastIp(iface->ifname, ipStr, ipStrLen);
642 #endif
643 }
644 
GetLocalDeviceId(void)645 const char *GetLocalDeviceId(void)
646 {
647     return g_localDevice.deviceInfo.deviceId;
648 }
649 
GetLocalDeviceInfo(void)650 DeviceInfo *GetLocalDeviceInfo(void)
651 {
652     return &g_localDevice.deviceInfo;
653 }
654 
GetLocalDeviceNetworkName(void)655 const char *GetLocalDeviceNetworkName(void)
656 {
657     return g_localDevice.deviceInfo.networkName;
658 }
659 
GetLocalIfaceIp(const struct LocalIface * iface)660 const struct in_addr *GetLocalIfaceIp(const struct LocalIface *iface)
661 {
662     return &iface->ip;
663 }
664 
GetLocalIfaceIpStr(const struct LocalIface * iface)665 const char *GetLocalIfaceIpStr(const struct LocalIface *iface)
666 {
667     return iface->ipStr;
668 }
669 
GetLocalIfaceName(const struct LocalIface * iface)670 const char *GetLocalIfaceName(const struct LocalIface *iface)
671 {
672     return iface->ifname;
673 }
674 
LocalIfaceGetCoapCtx(const char * ifname)675 CoapCtxType *LocalIfaceGetCoapCtx(const char *ifname)
676 {
677     int i;
678     for (i = 0; i < IFACE_TYPE_MAX; i++) {
679         List *pos = NULL;
680         LIST_FOR_EACH(pos, &g_localDevice.readyList[i]) {
681             struct LocalIface *iface = (struct LocalIface *)pos;
682             if (strcmp(iface->ifname, ifname) != 0) {
683                 continue;
684             }
685 
686             return iface->ctx;
687         }
688     }
689 
690     return NULL;
691 }
692 
693 #ifdef _WIN32
GetLocalIfaceByLocalIp(const struct in_addr * ip)694 static struct LocalIface *GetLocalIfaceByLocalIp(const struct in_addr *ip)
695 {
696     int i;
697     for (i = 0; i < IFACE_TYPE_MAX; i++) {
698         List *pos = NULL;
699         LIST_FOR_EACH(pos, &g_localDevice.readyList[i]) {
700             struct LocalIface *iface = (struct LocalIface *)pos;
701             if (iface->ip.s_addr != ip->s_addr) {
702                 continue;
703             }
704 
705             return iface;
706         }
707     }
708 
709     return NULL;
710 }
711 #endif
712 
713 #ifndef DFINDER_USE_MINI_NSTACKX
IfaceTypeIsMatch(uint8_t ifaceType,uint8_t serverType)714 static inline bool IfaceTypeIsMatch(uint8_t ifaceType, uint8_t serverType)
715 {
716     return serverType == INVALID_TYPE ||
717         (serverType == SERVER_TYPE_WLANORETH && (ifaceType == IFACE_TYPE_ETH || ifaceType == IFACE_TYPE_WLAN)) ||
718         (serverType == SERVER_TYPE_P2P && ifaceType == IFACE_TYPE_P2P) ||
719         (serverType == SERVER_TYPE_USB && ifaceType == IFACE_TYPE_USB);
720 }
721 
LocalIfaceGetCoapCtxByRemoteIp(const struct in_addr * remoteIp,uint8_t serverType)722 CoapCtxType *LocalIfaceGetCoapCtxByRemoteIp(const struct in_addr *remoteIp, uint8_t serverType)
723 {
724     struct LocalIface *iface = NULL;
725     struct sockaddr_in addr;
726     addr.sin_addr.s_addr = remoteIp->s_addr;
727 #ifdef _WIN32
728     InterfaceInfo localDev;
729     (void)memset_s(&localDev, sizeof(InterfaceInfo), 0, sizeof(InterfaceInfo));
730     if (GetTargetAdapter(&addr, &localDev) != NSTACKX_EOK) {
731         DFINDER_LOGE(TAG, "get target adapter failed");
732         return NULL;
733     }
734     struct in_addr localIp = { .s_addr = localDev.ipAddr };
735     iface = GetLocalIfaceByLocalIp(&localIp);
736 #else
737     struct ifreq req;
738     (void)memset_s(&req, sizeof(struct ifreq), 0, sizeof(struct ifreq));
739     if (GetTargetInterface(&addr, &req) != NSTACKX_EOK) {
740         DFINDER_LOGE(TAG, "get target interface failed");
741         return NULL;
742     }
743 
744     uint8_t ifaceType = GetIfaceType(req.ifr_ifrn.ifrn_name);
745     DFINDER_LOGD(TAG, "ifaceType: %hhu", ifaceType);
746     iface = GetLocalIface(&g_localDevice.readyList[ifaceType], req.ifr_ifrn.ifrn_name, NULL);
747 #endif
748     if (iface == NULL) {
749         DFINDER_LOGE(TAG, "can not find iface");
750         return NULL;
751     }
752 
753     if (!IfaceTypeIsMatch(iface->type, serverType)) {
754         DFINDER_LOGE(TAG, "type not match, iface type: %hhu, server type: %hhu", iface->type, serverType);
755         return NULL;
756     }
757 
758     return iface->ctx;
759 }
760 #endif
761 
762 #ifdef NSTACKX_DFINDER_HIDUMP
LocalIfaceDump(char * buf,size_t size)763 int LocalIfaceDump(char *buf, size_t size)
764 {
765     List *pos = NULL;
766     struct LocalIface *iface = NULL;
767     int ret;
768     size_t index = 0;
769     int i;
770     for (i = 0; i < IFACE_TYPE_MAX; i++) {
771         LIST_FOR_EACH(pos, &g_localDevice.readyList[i]) {
772             iface = (struct LocalIface *)pos;
773             ret = DFinderDumpIface(buf + index, size - index, iface->ifname, &iface->ip, iface->state);
774             if (ret < 0 || (uint32_t)ret > size - index) {
775                 return NSTACKX_EFAILED;
776             }
777 
778             index += (uint32_t)ret;
779         }
780     }
781 
782     LIST_FOR_EACH(pos, &g_localDevice.creatingList) {
783         iface = (struct LocalIface *)pos;
784         ret = DFinderDumpIface(buf + index, size - index, iface->ifname, &iface->ip, iface->state);
785         if (ret < 0 || (uint32_t)ret > size - index) {
786             return NSTACKX_EFAILED;
787         }
788 
789         index += (uint32_t)ret;
790     }
791 
792     LIST_FOR_EACH(pos, &g_localDevice.destroyList) {
793         iface = (struct LocalIface *)pos;
794         ret = DFinderDumpIface(buf + index, size - index, iface->ifname, &iface->ip, iface->state);
795         if (ret < 0 || (uint32_t)ret > size - index) {
796             return NSTACKX_EFAILED;
797         }
798 
799         index += (uint32_t)ret;
800     }
801 
802     return index;
803 }
804 #endif
805