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 #include "nstackx_inet.h"
28
29 #define TAG "LOCALDEVICE"
30 enum {
31 IFACE_STATE_READY,
32 IFACE_STATE_DESTROYING,
33 IFACE_STATE_CREATING,
34 };
35
36 struct LocalIface {
37 List node;
38
39 uint8_t type;
40 uint8_t state;
41 uint8_t createCount;
42 uint8_t af;
43 char ifname[NSTACKX_MAX_INTERFACE_NAME_LEN];
44 char ipStr[NSTACKX_MAX_IP_STRING_LEN];
45 union InetAddr addr;
46 char serviceData[NSTACKX_MAX_SERVICE_DATA_LEN];
47 struct timespec updateTime;
48
49 Timer *timer;
50 CoapCtxType *ctx;
51 };
52
53 typedef struct LocalDevice_ {
54 DeviceInfo deviceInfo;
55
56 List readyList[IFACE_TYPE_MAX];
57 List creatingList;
58 List destroyList;
59
60 Timer *timer;
61 bool inited;
62 } LocalDevice;
63
64 static LocalDevice g_localDevice;
65
66 #define LOCAL_DEVICE_OFFLINE_DEFERRED_DURATION 5000 /* Defer local device offline event, 5 seconds */
67
68 #define NSTACKX_DEFAULT_DEVICE_NAME "nStack Device"
69 #define NSTACKX_IPV6_MULTICAST_ADDR "FF02::1"
70 #define DEFAULT_IFACE_NUM 1
71
72 #define IFACE_COAP_CTX_INIT_MAX_RETRY_TIMES 4
73 static const uint32_t g_ifaceCoapCtxRetryBackoffList[IFACE_COAP_CTX_INIT_MAX_RETRY_TIMES] = { 10, 15, 25, 100 };
74
75 static pthread_mutex_t g_capabilityLock = PTHREAD_MUTEX_INITIALIZER;
76 static pthread_mutex_t g_serviceDataLock = PTHREAD_MUTEX_INITIALIZER;
77 static pthread_mutex_t g_businessDataLock = PTHREAD_MUTEX_INITIALIZER;
78 static pthread_mutex_t g_extendServiceDataLock = PTHREAD_MUTEX_INITIALIZER;
79 static pthread_mutex_t g_deviceInfoLock = PTHREAD_MUTEX_INITIALIZER;
80
LocalDeviceTimeout(void * data)81 static void LocalDeviceTimeout(void *data)
82 {
83 (void)data;
84
85 struct timespec cur;
86 ClockGetTime(CLOCK_MONOTONIC, &cur);
87
88 uint32_t nextTimeout = 0;
89 List *pos = NULL;
90 List *tmp = NULL;
91 LIST_FOR_EACH_SAFE(pos, tmp, &g_localDevice.destroyList) {
92 struct LocalIface *iface = (struct LocalIface *)pos;
93 uint32_t diff = GetTimeDiffMs(&cur, &iface->updateTime);
94 if (diff < LOCAL_DEVICE_OFFLINE_DEFERRED_DURATION) {
95 nextTimeout = LOCAL_DEVICE_OFFLINE_DEFERRED_DURATION - diff;
96 break;
97 }
98
99 DestroyLocalIface(iface, NSTACKX_FALSE);
100 }
101
102 if (nextTimeout != 0) {
103 DFINDER_LOGD(TAG, "start offline timer again, timeout %u", nextTimeout);
104 (void)TimerSetTimeout(g_localDevice.timer, nextTimeout, NSTACKX_FALSE);
105 }
106 }
107
LocalDeviceDeinit(void)108 void LocalDeviceDeinit(void)
109 {
110 if (!g_localDevice.inited) {
111 DFINDER_LOGW(TAG, "local device not inited");
112 return;
113 }
114
115 List *pos = NULL;
116 List *tmp = NULL;
117 int i;
118 for (i = 0; i < IFACE_TYPE_MAX; i++) {
119 LIST_FOR_EACH_SAFE(pos, tmp, &g_localDevice.readyList[i]) {
120 DestroyLocalIface((struct LocalIface *)pos, NSTACKX_TRUE);
121 }
122 }
123
124 LIST_FOR_EACH_SAFE(pos, tmp, &g_localDevice.destroyList) {
125 DestroyLocalIface((struct LocalIface *)pos, NSTACKX_TRUE);
126 }
127
128 LIST_FOR_EACH_SAFE(pos, tmp, &g_localDevice.creatingList) {
129 DestroyLocalIface((struct LocalIface *)pos, NSTACKX_TRUE);
130 }
131
132 if (g_localDevice.timer != NULL) {
133 TimerDelete(g_localDevice.timer);
134 g_localDevice.timer = NULL;
135 }
136
137 g_localDevice.inited = NSTACKX_FALSE;
138 }
139
LocalDeviceInit(EpollDesc epollfd)140 int LocalDeviceInit(EpollDesc epollfd)
141 {
142 (void)memset_s(&g_localDevice, sizeof(g_localDevice), 0, sizeof(g_localDevice));
143 g_localDevice.timer = TimerStart(epollfd, 0, NSTACKX_FALSE, LocalDeviceTimeout, NULL);
144 if (g_localDevice.timer == NULL) {
145 DFINDER_LOGE(TAG, "timer init failed");
146 return NSTACKX_EFAILED;
147 }
148
149 int i;
150 for (i = 0; i < IFACE_TYPE_MAX; i++) {
151 ListInitHead(&g_localDevice.readyList[i]);
152 }
153
154 ListInitHead(&g_localDevice.destroyList);
155 ListInitHead(&g_localDevice.creatingList);
156 g_localDevice.inited = NSTACKX_TRUE;
157
158 return NSTACKX_EOK;
159 }
160
ResetLocalDeviceTaskCount(uint8_t isBusy)161 void ResetLocalDeviceTaskCount(uint8_t isBusy)
162 {
163 if (g_localDevice.timer != NULL) {
164 if (isBusy) {
165 DFINDER_LOGI(TAG, "in this busy interval: offline deferred timer task count %llu",
166 g_localDevice.timer->task.count);
167 }
168 g_localDevice.timer->task.count = 0;
169 }
170 }
171
LocalIfaceChangeState(struct LocalIface * iface,List * targetList,uint8_t state)172 static inline void LocalIfaceChangeState(struct LocalIface *iface, List *targetList, uint8_t state)
173 {
174 DFINDER_LOGI(TAG, "iface %s state change: %hhu -> %hhu", iface->ifname, iface->state, state);
175 ListRemoveNode(&iface->node);
176 iface->state = state;
177 ListInsertTail(targetList, &iface->node);
178 }
179
LocalIfaceCreateContextTimeout(void * arg)180 static void LocalIfaceCreateContextTimeout(void *arg)
181 {
182 struct LocalIface *iface = (struct LocalIface *)arg;
183 DFINDER_LOGD(TAG, "iface %s create context for %u times", iface->ifname, iface->createCount);
184 iface->ctx = CoapServerInit(iface->af, &iface->addr, (void *)iface);
185 if (iface->ctx != NULL) {
186 DFINDER_LOGD(TAG, "iface %s create coap context success", iface->ifname);
187 TimerDelete(iface->timer);
188 iface->timer = NULL;
189 LocalIfaceChangeState(iface, &g_localDevice.readyList[iface->type], IFACE_STATE_READY);
190 return;
191 }
192
193 if (iface->createCount >= IFACE_COAP_CTX_INIT_MAX_RETRY_TIMES) {
194 DFINDER_LOGE(TAG, "create context retry reach max times %hhu", iface->createCount);
195 DestroyLocalIface(iface, NSTACKX_FALSE);
196 return;
197 }
198
199 (void)TimerSetTimeout(iface->timer, g_ifaceCoapCtxRetryBackoffList[iface->createCount], NSTACKX_FALSE);
200 iface->createCount++;
201 }
202
NeedCreateSynchronously(uint8_t ifaceType)203 static inline bool NeedCreateSynchronously(uint8_t ifaceType)
204 {
205 return ifaceType < IFACE_TYPE_P2P;
206 }
207
LocalIfaceInit(struct LocalIface * iface,const char * ifname,const char * ipStr)208 static int LocalIfaceInit(struct LocalIface *iface, const char *ifname, const char *ipStr)
209 {
210 DFINDER_LOGI(TAG, "trying to bring up interface %s", ifname);
211
212 if (strcpy_s(iface->ifname, sizeof(iface->ifname), ifname) != EOK) {
213 DFINDER_LOGE(TAG, "copy ifname %s failed", ifname);
214 return NSTACKX_EFAILED;
215 }
216 if (strcpy_s(iface->ipStr, sizeof(iface->ipStr), ipStr) != EOK) {
217 DFINDER_LOGE(TAG, "copy iface %s ip string failed", ifname);
218 return NSTACKX_EFAILED;
219 }
220
221 if (NeedCreateSynchronously(iface->type)) {
222 iface->ctx = CoapServerInit(iface->af, &iface->addr, (void *)iface);
223 if (iface->ctx == NULL) {
224 DFINDER_LOGE(TAG, "create coap context for iface %s failed", ifname);
225 IncStatistics(STATS_CREATE_SERVER_FAILED);
226 return NSTACKX_EFAILED;
227 }
228 iface->state = IFACE_STATE_READY;
229 ListInsertTail(&g_localDevice.readyList[iface->type], &iface->node);
230 DFINDER_LOGI(TAG, "bring up interface %s success", ifname);
231 } else {
232 iface->timer = TimerStart(GetEpollFD(), g_ifaceCoapCtxRetryBackoffList[0],
233 NSTACKX_FALSE, LocalIfaceCreateContextTimeout, iface);
234 if (iface->timer == NULL) {
235 DFINDER_LOGE(TAG, "iface %s create timer to create context async failed", iface->ifname);
236 return NSTACKX_EFAILED;
237 }
238 iface->createCount = 1;
239 iface->state = IFACE_STATE_CREATING;
240 ListInsertTail(&g_localDevice.creatingList, &iface->node);
241 }
242
243 return NSTACKX_EOK;
244 }
245
CreateLocalIface(const char * ifname,const char * serviceData,uint8_t af,const union InetAddr * addr,const char * ipStr)246 static struct LocalIface *CreateLocalIface(const char *ifname, const char *serviceData, uint8_t af,
247 const union InetAddr *addr, const char *ipStr)
248 {
249 struct LocalIface *iface = (struct LocalIface *)calloc(1, sizeof(struct LocalIface));
250 if (iface == NULL) {
251 DFINDER_LOGE(TAG, "calloc local iface fail");
252 return NULL;
253 }
254
255 iface->type = GetIfaceType(ifname);
256 DFINDER_LOGI(TAG, "GetIfaceType type %hhu", iface->type);
257 iface->addr = *addr;
258 iface->af = af;
259 (void)memcpy_s(iface->serviceData, NSTACKX_MAX_SERVICE_DATA_LEN, serviceData, NSTACKX_MAX_SERVICE_DATA_LEN);
260 if (LocalIfaceInit(iface, ifname, ipStr) != NSTACKX_EOK) {
261 DFINDER_LOGE(TAG, "local iface %s init failed", ifname);
262 free(iface);
263 return NULL;
264 }
265
266 return iface;
267 }
268
DestroyLocalIface(struct LocalIface * iface,bool moduleDeinit)269 void DestroyLocalIface(struct LocalIface *iface, bool moduleDeinit)
270 {
271 DFINDER_LOGI(TAG, "destroy iface %s, type: %hhu state: %hhu", iface->ifname, iface->type, iface->state);
272
273 #ifdef DFINDER_SAVE_DEVICE_LIST
274 DestroyRxIfaceByIfname(iface->ifname);
275 #endif
276
277 if (iface->ctx != NULL) {
278 CoapServerDestroy(iface->ctx, moduleDeinit);
279 }
280 ListRemoveNode(&iface->node);
281 if (iface->timer != NULL) {
282 TimerDelete(iface->timer);
283 }
284 free(iface);
285 }
286
GetLocalIface(List * head,const char * ifname,uint8_t af,const union InetAddr * addr)287 static struct LocalIface *GetLocalIface(List *head, const char *ifname, uint8_t af, const union InetAddr *addr)
288 {
289 List *pos = NULL;
290 LIST_FOR_EACH(pos, head) {
291 struct LocalIface *iface = (struct LocalIface *)pos;
292 if (iface->af != af || strcmp(iface->ifname, ifname) != 0) {
293 continue;
294 }
295 if (addr == NULL || InetEqual(af, addr, &iface->addr)) {
296 return iface;
297 }
298 }
299
300 return NULL;
301 }
302
GetActiveLocalIface(uint8_t af,const char * ifname)303 static struct LocalIface *GetActiveLocalIface(uint8_t af, const char *ifname)
304 {
305 uint8_t type = GetIfaceType(ifname);
306 struct LocalIface *iface = GetLocalIface(&g_localDevice.readyList[type], ifname, af, NULL);
307 if (iface == NULL) {
308 iface = GetLocalIface(&g_localDevice.creatingList, ifname, af, NULL);
309 }
310
311 return iface;
312 }
313
AddToDestroyList(struct LocalIface * iface)314 static void AddToDestroyList(struct LocalIface *iface)
315 {
316 if (iface->state != IFACE_STATE_DESTROYING) {
317 if (ListIsEmpty(&g_localDevice.destroyList)) {
318 (void)TimerSetTimeout(g_localDevice.timer, LOCAL_DEVICE_OFFLINE_DEFERRED_DURATION, NSTACKX_FALSE);
319 DFINDER_LOGD(TAG, "iface %s start offline timer", iface->ifname);
320 }
321 LocalIfaceChangeState(iface, &g_localDevice.destroyList, IFACE_STATE_DESTROYING);
322 (void)memset_s(iface->serviceData, NSTACKX_MAX_SERVICE_DATA_LEN, 0, NSTACKX_MAX_SERVICE_DATA_LEN);
323 ClockGetTime(CLOCK_MONOTONIC, &iface->updateTime);
324 if (iface->timer != NULL) {
325 (void)TimerSetTimeout(iface->timer, 0, NSTACKX_FALSE);
326 iface->createCount = 0;
327 }
328 }
329 }
330
AddLocalIface(const char * ifname,const char * serviceData,uint8_t af,const union InetAddr * addr)331 int AddLocalIface(const char *ifname, const char *serviceData, uint8_t af, const union InetAddr *addr)
332 {
333 struct LocalIface *iface = GetActiveLocalIface(af, ifname);
334 if (iface == NULL) {
335 iface = GetLocalIface(&g_localDevice.destroyList, ifname, af, addr);
336 if (iface != NULL) {
337 DFINDER_LOGI(TAG, "iface %s is in destroying, now make it in ready state", ifname);
338 (void)memcpy_s(iface->serviceData, NSTACKX_MAX_SERVICE_DATA_LEN,
339 serviceData, NSTACKX_MAX_SERVICE_DATA_LEN);
340 LocalIfaceChangeState(iface, &g_localDevice.readyList[iface->type], IFACE_STATE_READY);
341 return NSTACKX_EOK;
342 }
343 } else {
344 if (iface->af == af && InetEqual(af, &(iface->addr), addr)) {
345 DFINDER_LOGI(TAG, "iface %s already existed and in correct state", ifname);
346 (void)memcpy_s(iface->serviceData, NSTACKX_MAX_SERVICE_DATA_LEN,
347 serviceData, NSTACKX_MAX_SERVICE_DATA_LEN);
348 return NSTACKX_EOK;
349 }
350 AddToDestroyList(iface);
351 }
352
353 char ipStr[NSTACKX_MAX_IP_STRING_LEN] = {0};
354 if (inet_ntop(af, addr, ipStr, sizeof(ipStr)) == NULL) {
355 DFINDER_LOGE(TAG, "inet_ntop fail, errno: %d, desc: %s", errno, strerror(errno));
356 return NSTACKX_EFAILED;
357 }
358 iface = CreateLocalIface(ifname, serviceData, af, addr, ipStr);
359 return (iface == NULL) ? NSTACKX_EFAILED : NSTACKX_EOK;
360 }
361
RemoveLocalIface(uint8_t af,const char * ifname)362 void RemoveLocalIface(uint8_t af, const char *ifname)
363 {
364 struct LocalIface *iface = GetActiveLocalIface(af, ifname);
365 if (iface == NULL) {
366 DFINDER_LOGI(TAG, "af %hhu iface %s not found when deleting iface", af, ifname);
367 return;
368 }
369
370 AddToDestroyList(iface);
371 }
372
RemoveAllLocalIfaceOfList(List * list)373 static void RemoveAllLocalIfaceOfList(List *list)
374 {
375 List *pos = NULL;
376 List *tmp = NULL;
377 LIST_FOR_EACH_SAFE(pos, tmp, list) {
378 AddToDestroyList((struct LocalIface *)pos);
379 }
380 }
381
RemoveAllLocalIface(void)382 static void RemoveAllLocalIface(void)
383 {
384 for (uint8_t i = IFACE_TYPE_ETH; i < IFACE_TYPE_MAX; i++) {
385 RemoveAllLocalIfaceOfList(&g_localDevice.readyList[i]);
386 }
387
388 RemoveAllLocalIfaceOfList(&g_localDevice.creatingList);
389 }
390
DestroyAllLocalIfaceOfList(List * list,uint8_t af)391 static void DestroyAllLocalIfaceOfList(List *list, uint8_t af)
392 {
393 List *pos = NULL;
394 List *tmp = NULL;
395 LIST_FOR_EACH_SAFE(pos, tmp, list) {
396 struct LocalIface *iface = (struct LocalIface *)pos;
397 if (iface->af != af) {
398 continue;
399 }
400 DestroyLocalIface(iface, true);
401 }
402 }
403
DestroyAllLocalIface(uint8_t af)404 static void DestroyAllLocalIface(uint8_t af)
405 {
406 for (uint8_t i = IFACE_TYPE_ETH; i < IFACE_TYPE_MAX; i++) {
407 DestroyAllLocalIfaceOfList(&g_localDevice.readyList[i], af);
408 }
409
410 DestroyAllLocalIfaceOfList(&g_localDevice.creatingList, af);
411 DestroyAllLocalIfaceOfList(&g_localDevice.destroyList, af);
412 }
413
IsDestroyIfaceByAddr(const NSTACKX_InterfaceInfo * ifInfo,uint32_t ifNums)414 static bool IsDestroyIfaceByAddr(const NSTACKX_InterfaceInfo *ifInfo, uint32_t ifNums)
415 {
416 if (ifNums != DEFAULT_IFACE_NUM) {
417 DFINDER_LOGW(TAG, "ifnums is %u not match, so no need destroy iface", ifNums);
418 return false;
419 }
420 union InetAddr addr;
421 uint8_t af = InetGetAfType(ifInfo[0].networkIpAddr, &addr);
422 if (af == AF_ERROR) {
423 DFINDER_LOGE(TAG, "inet_pton fail");
424 return false;
425 }
426 if (InetEqualZero(af, &addr) || InetEqualLoop(af, ifInfo[0].networkIpAddr)) {
427 DFINDER_LOGI(TAG, "destroy ip with any with af %hhu th nic %s", af, ifInfo[0].networkName);
428 DestroyAllLocalIface(af);
429 return true;
430 }
431 return false;
432 }
433
RemoveSpecifiedLocalIface(const NSTACKX_InterfaceInfo * ifInfo,uint32_t ifNums)434 static void RemoveSpecifiedLocalIface(const NSTACKX_InterfaceInfo *ifInfo, uint32_t ifNums)
435 {
436 uint32_t i;
437 for (i = 0; i < ifNums; ++i) {
438 // af is always AF_INET/AF_INET6
439 union InetAddr addr;
440 uint8_t af = InetGetAfType(ifInfo[i].networkIpAddr, &addr);
441 struct LocalIface *iface = GetActiveLocalIface(af, ifInfo[i].networkName);
442 if (iface == NULL) {
443 DFINDER_LOGI(TAG, "af %hhu iface %s not found when deleting iface", af, ifInfo[i].networkName);
444 continue;
445 }
446
447 if (af == AF_INET) {
448 AddToDestroyList(iface);
449 } else {
450 // USB(ipv6) use old iface, send coap unicast failed(network unreachable), must destroy iface
451 DestroyLocalIface(iface, true);
452 }
453 }
454 }
455
AddLocalIfaceIpChanged(const NSTACKX_InterfaceInfo * ifInfo,uint32_t ifNums)456 static int AddLocalIfaceIpChanged(const NSTACKX_InterfaceInfo *ifInfo, uint32_t ifNums)
457 {
458 uint8_t ifaceType = IFACE_TYPE_MAX;
459 uint32_t i;
460 for (i = 0; i < ifNums; ++i) {
461 if (ifInfo[i].networkName[0] == '\0' || ifInfo[i].networkIpAddr[0] == '\0') {
462 DFINDER_LOGI(TAG, "skip empty network name or ip addr");
463 continue;
464 }
465
466 union InetAddr addr;
467 uint8_t af = InetGetAfType(ifInfo[i].networkIpAddr, &addr);
468 if (af == AF_ERROR) {
469 DFINDER_LOGE(TAG, "inet_pton fail for %u th nic %s, errno: %d, desc: %s",
470 i, ifInfo[i].networkName, errno, strerror(errno));
471 return NSTACKX_EFAILED;
472 }
473 if (InetEqualZero(af, &addr) || InetEqualLoop(af, ifInfo[i].networkIpAddr)) {
474 DFINDER_LOGI(TAG, "skip ip with any with %u af %hhu th nic %s", i, af, ifInfo[i].networkName);
475 continue;
476 }
477
478 if (AddLocalIface(ifInfo[i].networkName, ifInfo[i].serviceData, af, &addr) != NSTACKX_EOK) {
479 DFINDER_LOGE(TAG, "create local iface %s failed", ifInfo[i].networkName);
480 return NSTACKX_EFAILED;
481 }
482
483 uint8_t curIfaceType = GetIfaceType(ifInfo[i].networkName);
484 if (curIfaceType < ifaceType) { /* storge the highest priority interface name */
485 if (strcpy_s(g_localDevice.deviceInfo.networkName, sizeof(g_localDevice.deviceInfo.networkName),
486 ifInfo[i].networkName) != EOK) {
487 DFINDER_LOGE(TAG, "copy ifname %s failed", ifInfo[i].networkName);
488 return NSTACKX_EFAILED;
489 }
490 ifaceType = curIfaceType;
491 }
492 }
493
494 return NSTACKX_EOK;
495 }
496
CopyDeviceInfoV2(const NSTACKX_LocalDeviceInfoV2 * devInfo)497 static int CopyDeviceInfoV2(const NSTACKX_LocalDeviceInfoV2 *devInfo)
498 {
499 if (strcpy_s(g_localDevice.deviceInfo.deviceId, sizeof(g_localDevice.deviceInfo.deviceId),
500 devInfo->deviceId) != EOK) {
501 DFINDER_LOGE(TAG, "copy device id failed");
502 return NSTACKX_EFAILED;
503 }
504
505 if (devInfo->name[0] == '\0') {
506 DFINDER_LOGW(TAG, "try to register invalid device name, will use default: %s", NSTACKX_DEFAULT_DEVICE_NAME);
507 (void)strcpy_s(g_localDevice.deviceInfo.deviceName,
508 sizeof(g_localDevice.deviceInfo.deviceName), NSTACKX_DEFAULT_DEVICE_NAME);
509 } else {
510 if (strcpy_s(g_localDevice.deviceInfo.deviceName,
511 sizeof(g_localDevice.deviceInfo.deviceName), devInfo->name) != EOK) {
512 DFINDER_LOGE(TAG, "copy device name %s failed", devInfo->name);
513 return NSTACKX_EFAILED;
514 }
515 }
516
517 g_localDevice.deviceInfo.deviceType = devInfo->deviceType;
518 g_localDevice.deviceInfo.businessType = devInfo->businessType;
519 if (devInfo->hasDeviceHash) {
520 SetLocalDeviceHash(devInfo->deviceHash);
521 }
522
523 return NSTACKX_EOK;
524 }
525
RegisterLocalDeviceV2(const NSTACKX_LocalDeviceInfoV2 * devInfo,int registerType)526 int RegisterLocalDeviceV2(const NSTACKX_LocalDeviceInfoV2 *devInfo, int registerType)
527 {
528 if (PthreadMutexLock(&g_deviceInfoLock) != 0) {
529 DFINDER_LOGE(TAG, "failed to lock");
530 return NSTACKX_EFAILED;
531 }
532 if (IsDestroyIfaceByAddr(devInfo->localIfInfo, devInfo->ifNums)) {
533 if (PthreadMutexUnlock(&g_deviceInfoLock) != 0) {
534 DFINDER_LOGE(TAG, "failed to unlock");
535 }
536 return NSTACKX_EOK;
537 }
538 if (registerType == REGISTER_TYPE_UPDATE_ALL) {
539 RemoveAllLocalIface();
540 } else {
541 RemoveSpecifiedLocalIface(devInfo->localIfInfo, devInfo->ifNums);
542 }
543
544 if (CopyDeviceInfoV2(devInfo) != NSTACKX_EOK) {
545 if (PthreadMutexUnlock(&g_deviceInfoLock) != 0) {
546 DFINDER_LOGE(TAG, "failed to unlock");
547 }
548 return NSTACKX_EFAILED;
549 }
550
551 if (AddLocalIfaceIpChanged(devInfo->localIfInfo, devInfo->ifNums) != NSTACKX_EOK) {
552 if (registerType == REGISTER_TYPE_UPDATE_ALL) {
553 RemoveAllLocalIface(); /* maybe some ifaces is added, so remove all ifaces again */
554 }
555 if (PthreadMutexUnlock(&g_deviceInfoLock) != 0) {
556 DFINDER_LOGE(TAG, "failed to unlock");
557 }
558 return NSTACKX_EFAILED;
559 }
560 if (PthreadMutexUnlock(&g_deviceInfoLock) != 0) {
561 DFINDER_LOGE(TAG, "failed to unlock");
562 return NSTACKX_EFAILED;
563 }
564
565 return NSTACKX_EOK;
566 }
567
ConfigureLocalDeviceName(const char * localDeviceName)568 void ConfigureLocalDeviceName(const char *localDeviceName)
569 {
570 char backupDevName[NSTACKX_MAX_DEVICE_NAME_LEN] = {0};
571 if (memcpy_s(backupDevName, sizeof(backupDevName), g_localDevice.deviceInfo.deviceName,
572 sizeof(g_localDevice.deviceInfo.deviceName)) != EOK) {
573 DFINDER_LOGE(TAG, "backup local device name failed!");
574 return;
575 }
576 if (strncpy_s(g_localDevice.deviceInfo.deviceName, NSTACKX_MAX_DEVICE_NAME_LEN,
577 localDeviceName, NSTACKX_MAX_DEVICE_NAME_LEN - 1) != EOK) {
578 DFINDER_LOGW(TAG, "copy local device failed, will use current name");
579 if (strcpy_s(g_localDevice.deviceInfo.deviceName, NSTACKX_MAX_DEVICE_NAME_LEN, backupDevName) != EOK) {
580 DFINDER_LOGE(TAG, "config device name failed and cannot restore!");
581 }
582 }
583 }
584
SetLocalDeviceHash(uint64_t deviceHash)585 void SetLocalDeviceHash(uint64_t deviceHash)
586 {
587 (void)memset_s(g_localDevice.deviceInfo.deviceHash, sizeof(g_localDevice.deviceInfo.deviceHash),
588 0, sizeof(g_localDevice.deviceInfo.deviceHash));
589 if (sprintf_s(g_localDevice.deviceInfo.deviceHash, DEVICE_HASH_LEN,
590 "%ju", deviceHash) == -1) {
591 DFINDER_LOGE(TAG, "set device hash error");
592 }
593 }
594
SetLocalDeviceCapability(uint32_t capabilityBitmapNum,uint32_t capabilityBitmap[])595 int SetLocalDeviceCapability(uint32_t capabilityBitmapNum, uint32_t capabilityBitmap[])
596 {
597 if (PthreadMutexLock(&g_capabilityLock) != 0) {
598 DFINDER_LOGE(TAG, "failed to lock");
599 return NSTACKX_EFAILED;
600 }
601 (void)memset_s(g_localDevice.deviceInfo.capabilityBitmap, sizeof(g_localDevice.deviceInfo.capabilityBitmap),
602 0, sizeof(g_localDevice.deviceInfo.capabilityBitmap));
603 g_localDevice.deviceInfo.capabilityBitmapNum = 0;
604
605 if (capabilityBitmapNum > 0) {
606 if (memcpy_s(g_localDevice.deviceInfo.capabilityBitmap, sizeof(g_localDevice.deviceInfo.capabilityBitmap),
607 capabilityBitmap, sizeof(uint32_t) * capabilityBitmapNum) != EOK) {
608 DFINDER_LOGE(TAG, "capabilityBitmap copy error");
609 if (PthreadMutexUnlock(&g_capabilityLock) != 0) {
610 DFINDER_LOGE(TAG, "failed to unlock");
611 }
612 return NSTACKX_EFAILED;
613 }
614 }
615
616 g_localDevice.deviceInfo.capabilityBitmapNum = capabilityBitmapNum;
617 if (PthreadMutexUnlock(&g_capabilityLock) != 0) {
618 DFINDER_LOGE(TAG, "failed to unlock");
619 return NSTACKX_EFAILED;
620 }
621 return NSTACKX_EOK;
622 }
623
SetLocalDeviceServiceData(const char * serviceData)624 int32_t SetLocalDeviceServiceData(const char *serviceData)
625 {
626 if (PthreadMutexLock(&g_serviceDataLock) != 0) {
627 DFINDER_LOGE(TAG, "failed to lock");
628 return NSTACKX_EFAILED;
629 }
630 if (strcpy_s(g_localDevice.deviceInfo.serviceData, NSTACKX_MAX_SERVICE_DATA_LEN, serviceData) != EOK) {
631 DFINDER_LOGE(TAG, "serviceData copy error");
632 if (PthreadMutexUnlock(&g_serviceDataLock) != 0) {
633 DFINDER_LOGE(TAG, "failed to unlock");
634 }
635 return NSTACKX_EFAILED;
636 }
637 if (PthreadMutexUnlock(&g_serviceDataLock) != 0) {
638 DFINDER_LOGE(TAG, "failed to unlock");
639 return NSTACKX_EFAILED;
640 }
641 return NSTACKX_EOK;
642 }
643
GetLocalIfaceByIp(List * head,uint8_t af,const char * ip,uint32_t len)644 static struct LocalIface *GetLocalIfaceByIp(List *head, uint8_t af, const char *ip, uint32_t len)
645 {
646 List *pos = NULL;
647 LIST_FOR_EACH(pos, head) {
648 struct LocalIface *iface = (struct LocalIface *)pos;
649 if (iface->af != af || len != strlen(iface->ipStr)) {
650 continue;
651 }
652
653 if (strcmp(iface->ipStr, ip) == 0) {
654 return iface;
655 }
656 }
657
658 return NULL;
659 }
660
UpdateLocalDeviceServiceDataV2(uint8_t af,const struct NSTACKX_ServiceData * data)661 static int32_t UpdateLocalDeviceServiceDataV2(uint8_t af, const struct NSTACKX_ServiceData *data)
662 {
663 uint8_t i;
664 struct LocalIface *iface = NULL;
665 const char *ip = data->ip;
666 uint32_t len = (uint32_t)strlen(data->ip);
667
668 iface = GetLocalIfaceByIp(&g_localDevice.creatingList, af, ip, len);
669 if (iface != NULL) {
670 (void)memcpy_s(iface->serviceData, NSTACKX_MAX_SERVICE_DATA_LEN,
671 data->serviceData, NSTACKX_MAX_SERVICE_DATA_LEN);
672 DFINDER_LOGI(TAG, "set service data sucess");
673 return NSTACKX_EOK;
674 }
675
676 for (i = 0; i < IFACE_TYPE_MAX; i++) {
677 iface = GetLocalIfaceByIp(&g_localDevice.readyList[i], af, ip, len);
678 if (iface != NULL) {
679 (void)memcpy_s(iface->serviceData, NSTACKX_MAX_SERVICE_DATA_LEN,
680 data->serviceData, NSTACKX_MAX_SERVICE_DATA_LEN);
681 DFINDER_LOGI(TAG, "set service data sucess");
682 return NSTACKX_EOK;
683 }
684 }
685
686 return NSTACKX_EFAILED;
687 }
688
SetLocalDeviceServiceDataV2(const struct NSTACKX_ServiceData * param,uint32_t cnt)689 int32_t SetLocalDeviceServiceDataV2(const struct NSTACKX_ServiceData *param, uint32_t cnt)
690 {
691 int32_t ret = NSTACKX_EFAILED;
692 uint32_t i;
693 if (PthreadMutexLock(&g_serviceDataLock) != 0) {
694 DFINDER_LOGE(TAG, "failed to lock");
695 return NSTACKX_EFAILED;
696 }
697
698 for (i = 0; i < cnt; i++) {
699 union InetAddr addr;
700 uint8_t af = InetGetAfType(param[i].ip, &addr);
701 if (UpdateLocalDeviceServiceDataV2(af, &(param[i])) == NSTACKX_EOK) {
702 DFINDER_LOGI(TAG, "update local device serviceData by param[%u]", i);
703 ret = NSTACKX_EOK;
704 }
705 }
706 if (PthreadMutexUnlock(&g_serviceDataLock) != 0) {
707 DFINDER_LOGE(TAG, "failed to unlock");
708 return NSTACKX_EFAILED;
709 }
710 return ret;
711 }
712
SetLocalDeviceBusinessType(uint8_t businessType)713 void SetLocalDeviceBusinessType(uint8_t businessType)
714 {
715 g_localDevice.deviceInfo.businessType = businessType;
716 }
717
GetLocalDeviceBusinessType(void)718 uint8_t GetLocalDeviceBusinessType(void)
719 {
720 return g_localDevice.deviceInfo.businessType;
721 }
722
SetLocalDeviceBusinessData(const char * data,bool unicast)723 int SetLocalDeviceBusinessData(const char *data, bool unicast)
724 {
725 if (PthreadMutexLock(&g_businessDataLock) != 0) {
726 DFINDER_LOGE(TAG, "failed to lock");
727 return NSTACKX_EFAILED;
728 }
729 int ret = EOK;
730 if (unicast) {
731 ret = strcpy_s(g_localDevice.deviceInfo.businessData.businessDataUnicast,
732 NSTACKX_MAX_BUSINESS_DATA_LEN, data);
733 } else {
734 ret = strcpy_s(g_localDevice.deviceInfo.businessData.businessDataBroadcast,
735 NSTACKX_MAX_BUSINESS_DATA_LEN, data);
736 }
737
738 if (ret != EOK) {
739 DFINDER_LOGE(TAG, "businessData copy error, unicast: %d", unicast);
740 if (PthreadMutexUnlock(&g_businessDataLock) != 0) {
741 DFINDER_LOGE(TAG, "failed to unlock");
742 }
743 return NSTACKX_EFAILED;
744 }
745
746 if (PthreadMutexUnlock(&g_businessDataLock) != 0) {
747 DFINDER_LOGE(TAG, "failed to unlock");
748 return NSTACKX_EFAILED;
749 }
750
751 return NSTACKX_EOK;
752 }
753
LocalizeNotificationMsg(const char * msg)754 int32_t LocalizeNotificationMsg(const char *msg)
755 {
756 if (strcpy_s(g_localDevice.deviceInfo.notification, NSTACKX_MAX_NOTIFICATION_DATA_LEN, msg) != EOK) {
757 DFINDER_LOGE(TAG, "copy notification msg to local dev failed");
758 return NSTACKX_EFAILED;
759 }
760 return NSTACKX_EOK;
761 }
762
GetLocalDeviceMode(void)763 uint8_t GetLocalDeviceMode(void)
764 {
765 return g_localDevice.deviceInfo.mode;
766 }
767
SetLocalDeviceMode(uint8_t mode)768 void SetLocalDeviceMode(uint8_t mode)
769 {
770 g_localDevice.deviceInfo.mode = mode;
771 }
772
773 #ifndef DFINDER_USE_MINI_NSTACKX
SetLocalDeviceExtendServiceData(const char * extendServiceData)774 int32_t SetLocalDeviceExtendServiceData(const char *extendServiceData)
775 {
776 if (PthreadMutexLock(&g_extendServiceDataLock) != 0) {
777 DFINDER_LOGE(TAG, "failed to lock");
778 return NSTACKX_EFAILED;
779 }
780 if (strcpy_s(g_localDevice.deviceInfo.extendServiceData, NSTACKX_MAX_EXTEND_SERVICE_DATA_LEN,
781 extendServiceData) != EOK) {
782 DFINDER_LOGE(TAG, "extendServiceData copy error");
783 if (PthreadMutexUnlock(&g_extendServiceDataLock) != 0) {
784 DFINDER_LOGE(TAG, "failed to unlock");
785 }
786 return NSTACKX_EFAILED;
787 }
788 if (PthreadMutexUnlock(&g_extendServiceDataLock) != 0) {
789 DFINDER_LOGE(TAG, "failed to unlock");
790 return NSTACKX_EFAILED;
791 }
792 return NSTACKX_EOK;
793 }
794
795 #ifndef _WIN32
DetectLocalIface(void * arg)796 void DetectLocalIface(void *arg)
797 {
798 struct ifconf ifc;
799 struct ifreq req[INTERFACE_MAX];
800 int fd = GetInterfaceList(&ifc, req, sizeof(req));
801 if (fd < 0) {
802 DFINDER_LOGE(TAG, "get iface list failed");
803 return;
804 }
805
806 int interfaceNum = ifc.ifc_len / (int)sizeof(struct ifreq);
807 for (int i = 0; i < interfaceNum && i < INTERFACE_MAX; i++) {
808 /* get IP of this interface */
809 int state = GetInterfaceIP(fd, &req[i]);
810 if (state == NSTACKX_EFAILED) {
811 (void)close(fd);
812 return;
813 } else if (state == NSTACKX_EINVAL) {
814 continue;
815 }
816
817 uint8_t ifaceType = GetIfaceType(req[i].ifr_name);
818 if (ifaceType > IFACE_TYPE_WLAN) {
819 DFINDER_LOGI(TAG, "skip iface %s", req[i].ifr_name);
820 continue;
821 }
822
823 union InetAddr addr;
824 addr.in.s_addr = (((struct sockaddr_in *)&req[i].ifr_addr)->sin_addr).s_addr;
825 if (req[i].ifr_addr.sa_family != AF_INET || addr.in.s_addr == 0) {
826 DFINDER_LOGI(TAG, "iface %s is not ipv4 or ip is any", req[i].ifr_name);
827 continue;
828 }
829
830 DFINDER_LOGI(TAG, "try to add new iface %s", req[i].ifr_name);
831 char serviceData[NSTACKX_MAX_SERVICE_DATA_LEN];
832 (void)memset_s(serviceData, NSTACKX_MAX_SERVICE_DATA_LEN, 0, NSTACKX_MAX_SERVICE_DATA_LEN);
833 (void)AddLocalIface(req[i].ifr_name, serviceData, AF_INET, &addr);
834 }
835 (void)close(fd);
836
837 (void)arg;
838 }
839 #endif /* _WIN32 */
840
841 #endif /* END OF DFINDER_USE_MINI_NSTACKX */
842
GetBroadcastIp(const struct LocalIface * iface,char * ipStr,size_t ipStrLen)843 int GetBroadcastIp(const struct LocalIface *iface, char *ipStr, size_t ipStrLen)
844 {
845 #ifdef _WIN32
846 return GetIfBroadcastAddr(&iface->ip, ipStr, ipStrLen);
847 #else
848 if (iface->af == AF_INET) {
849 return GetIfBroadcastIp(iface->ifname, ipStr, ipStrLen);
850 }
851
852 // ipv6 not support broadcast, only use multicast
853 if (strcpy_s(ipStr, ipStrLen, NSTACKX_IPV6_MULTICAST_ADDR) != EOK) {
854 DFINDER_LOGE(TAG, "strcpy_s failed");
855 return NSTACKX_EFAILED;
856 }
857
858 return NSTACKX_EOK;
859 #endif
860 }
861
GetLocalDeviceId(void)862 const char *GetLocalDeviceId(void)
863 {
864 return g_localDevice.deviceInfo.deviceId;
865 }
866
GetLocalDeviceInfo(void)867 DeviceInfo *GetLocalDeviceInfo(void)
868 {
869 return &g_localDevice.deviceInfo;
870 }
871
GetLocalDeviceNetworkName(void)872 const char *GetLocalDeviceNetworkName(void)
873 {
874 return g_localDevice.deviceInfo.networkName;
875 }
876
GetLocalIfaceIpStr(const struct LocalIface * iface)877 const char *GetLocalIfaceIpStr(const struct LocalIface *iface)
878 {
879 return iface->ipStr;
880 }
881
GetLocalIfaceServiceData(const struct LocalIface * iface)882 const char *GetLocalIfaceServiceData(const struct LocalIface *iface)
883 {
884 return iface->serviceData;
885 }
886
GetLocalIfaceAf(const struct LocalIface * iface)887 uint8_t GetLocalIfaceAf(const struct LocalIface *iface)
888 {
889 return iface->af;
890 }
891
GetLocalIfaceName(const struct LocalIface * iface)892 const char *GetLocalIfaceName(const struct LocalIface *iface)
893 {
894 return iface->ifname;
895 }
896
LocalIfaceGetCoapCtx(uint8_t af,const char * ifname)897 CoapCtxType *LocalIfaceGetCoapCtx(uint8_t af, const char *ifname)
898 {
899 int i;
900 for (i = 0; i < IFACE_TYPE_MAX; i++) {
901 List *pos = NULL;
902 LIST_FOR_EACH(pos, &g_localDevice.readyList[i]) {
903 struct LocalIface *iface = (struct LocalIface *)pos;
904 if (af != iface->af || strcmp(iface->ifname, ifname) != 0) {
905 continue;
906 }
907
908 return iface->ctx;
909 }
910 }
911
912 return NULL;
913 }
914
915 #ifdef _WIN32
GetLocalIfaceByLocalIp(const struct in_addr * ip)916 static struct LocalIface *GetLocalIfaceByLocalIp(const struct in_addr *ip)
917 {
918 int i;
919 for (i = 0; i < IFACE_TYPE_MAX; i++) {
920 List *pos = NULL;
921 LIST_FOR_EACH(pos, &g_localDevice.readyList[i]) {
922 struct LocalIface *iface = (struct LocalIface *)pos;
923 if (iface->ip.s_addr != ip->s_addr) {
924 continue;
925 }
926
927 return iface;
928 }
929 }
930
931 return NULL;
932 }
933 #endif
934
935 #ifndef DFINDER_USE_MINI_NSTACKX
IfaceTypeIsMatch(uint8_t ifaceType,uint8_t serverType)936 static inline bool IfaceTypeIsMatch(uint8_t ifaceType, uint8_t serverType)
937 {
938 return serverType == INVALID_TYPE ||
939 (serverType == SERVER_TYPE_WLANORETH && (ifaceType == IFACE_TYPE_ETH || ifaceType == IFACE_TYPE_WLAN)) ||
940 (serverType == SERVER_TYPE_P2P && ifaceType == IFACE_TYPE_P2P) ||
941 (serverType == SERVER_TYPE_USB && ifaceType == IFACE_TYPE_USB) ||
942 (serverType == IFACE_TYPE_USB_SCALE && ifaceType == IFACE_TYPE_USB_SCALE);
943 }
944
LocalIfaceGetCoapCtxByRemoteIp(const struct in_addr * remoteIp,uint8_t serverType)945 CoapCtxType *LocalIfaceGetCoapCtxByRemoteIp(const struct in_addr *remoteIp, uint8_t serverType)
946 {
947 struct LocalIface *iface = NULL;
948 struct sockaddr_in addr;
949 addr.sin_addr.s_addr = remoteIp->s_addr;
950 #ifdef _WIN32
951 InterfaceInfo localDev;
952 (void)memset_s(&localDev, sizeof(InterfaceInfo), 0, sizeof(InterfaceInfo));
953 if (GetTargetAdapter(&addr, &localDev) != NSTACKX_EOK) {
954 DFINDER_LOGE(TAG, "get target adapter failed");
955 return NULL;
956 }
957 struct in_addr localIp = { .s_addr = localDev.ipAddr };
958 iface = GetLocalIfaceByLocalIp(&localIp);
959 #else
960 struct ifreq req;
961 (void)memset_s(&req, sizeof(struct ifreq), 0, sizeof(struct ifreq));
962 if (GetTargetInterface(&addr, &req) != NSTACKX_EOK) {
963 DFINDER_LOGE(TAG, "get target interface failed");
964 return NULL;
965 }
966
967 uint8_t ifaceType = GetIfaceType(req.ifr_ifrn.ifrn_name);
968 DFINDER_LOGD(TAG, "ifaceType: %hhu", ifaceType);
969 iface = GetLocalIface(&g_localDevice.readyList[ifaceType], req.ifr_ifrn.ifrn_name, AF_INET, NULL);
970 #endif
971 if (iface == NULL) {
972 DFINDER_LOGE(TAG, "can not find iface");
973 return NULL;
974 }
975
976 if (!IfaceTypeIsMatch(iface->type, serverType)) {
977 DFINDER_LOGE(TAG, "type not match, iface type: %hhu, server type: %hhu", iface->type, serverType);
978 return NULL;
979 }
980
981 return iface->ctx;
982 }
983
984 #else
GetLocalIfaceIp(const struct LocalIface * iface)985 const struct in_addr *GetLocalIfaceIp(const struct LocalIface *iface)
986 {
987 return &iface->in;
988 }
989 #endif
990
991 #ifdef NSTACKX_DFINDER_HIDUMP
992
LocalSetDumpIfaceInfo(struct DumpIfaceInfo * info,const char * ifname,uint8_t state,uint8_t af,union InetAddr * addr)993 static inline struct DumpIfaceInfo *LocalSetDumpIfaceInfo(struct DumpIfaceInfo *info, const char *ifname, uint8_t state,
994 uint8_t af, union InetAddr *addr)
995 {
996 info->ifname = ifname;
997 info->state = state;
998 info->af = af;
999 info->addr = addr;
1000 return info;
1001 }
1002
LocalIfaceDump(char * buf,size_t size)1003 int LocalIfaceDump(char *buf, size_t size)
1004 {
1005 List *pos = NULL;
1006 struct DumpIfaceInfo info;
1007 struct LocalIface *iface = NULL;
1008 int ret;
1009 size_t index = 0;
1010 int i;
1011 for (i = 0; i < IFACE_TYPE_MAX; i++) {
1012 LIST_FOR_EACH(pos, &g_localDevice.readyList[i]) {
1013 iface = (struct LocalIface *)pos;
1014
1015 ret = DFinderDumpIface(LocalSetDumpIfaceInfo(&info, iface->ifname, iface->state, iface->af, &iface->addr),
1016 buf + index, size - index);
1017 if (ret < 0 || (uint32_t)ret > size - index) {
1018 return NSTACKX_EFAILED;
1019 }
1020
1021 index += (uint32_t)ret;
1022 }
1023 }
1024
1025 LIST_FOR_EACH(pos, &g_localDevice.creatingList) {
1026 iface = (struct LocalIface *)pos;
1027 ret = DFinderDumpIface(LocalSetDumpIfaceInfo(&info, iface->ifname, iface->state, iface->af, &iface->addr),
1028 buf + index, size - index);
1029 if (ret < 0 || (uint32_t)ret > size - index) {
1030 return NSTACKX_EFAILED;
1031 }
1032
1033 index += (uint32_t)ret;
1034 }
1035
1036 LIST_FOR_EACH(pos, &g_localDevice.destroyList) {
1037 iface = (struct LocalIface *)pos;
1038 ret = DFinderDumpIface(LocalSetDumpIfaceInfo(&info, iface->ifname, iface->state, iface->af, &iface->addr),
1039 buf + index, size - index);
1040 if (ret < 0 || (uint32_t)ret > size - index) {
1041 return NSTACKX_EFAILED;
1042 }
1043
1044 index += (uint32_t)ret;
1045 }
1046
1047 return index;
1048 }
1049 #endif
1050