已合并
feat:添加专用热点网关模块,支持专用热点设备配网--dedap集成模块 #225
feat:添加专用热点网关模块,支持专用热点设备配网--dedap集成模块 #225
已合并
移动-吴昊创建于 8月22日
共 13 个文件变更+1924-9
@@ -21,16 +21,21 @@ set_property(CACHE TARGET_PLATFORM PROPERTY STRINGS linux android)
21option(ENABLE_ETH "Enable ETH Module support" OFF)21option(ENABLE_ETH "Enable ETH Module support" OFF)
22option(ENABLE_WIFI "Enable WIFI Module support" ON)22option(ENABLE_WIFI "Enable WIFI Module support" ON)
23option(ENABLE_BLE "Enable BLE Module support" ON)23option(ENABLE_BLE "Enable BLE Module support" ON)
24-option(ENABLE_SLE "Enable SLE Module support" OFF)24+option(ENABLE_SLE "Enable SLE Module support" ON)
25option(ENABLE_SLE_ADP "Enable SLE Adapter" ON)25option(ENABLE_SLE_ADP "Enable SLE Adapter" ON)
26+option(ENABLE_DEDAP "Enable DEDAP Module support" ON)
26 27 
27-# BLE/SLE role, default is server.28+# BLE/SLE/DEDAP role, default is server.
28option(BLE_ROLE_SERVER "BLE role, server or client" ON)29option(BLE_ROLE_SERVER "BLE role, server or client" ON)
29-option(SLE_ROLE_SERVER "SLE role, server or client" ON)30+option(SLE_ROLE_SERVER "SLE role, server or client" OFF)
31+option(DEDAP_ROLE_SERVER "DEDAP role, server or client" ON)
30 32 
31-# Bridge is enabled automatically when an enabled BLE or SLE link uses the client role.33+# Bridge is enabled automatically for a BLE/SLE client or a DEDAP server.
32set(ENABLE_BRIDGE OFF)34set(ENABLE_BRIDGE OFF)
33-if ((ENABLE_BLE AND NOT BLE_ROLE_SERVER) OR (ENABLE_SLE AND NOT SLE_ROLE_SERVER))35+set(BRIDGE_TCP_MODE_ENABLE OFF)
36+if ((ENABLE_BLE AND NOT BLE_ROLE_SERVER) OR
37+ (ENABLE_SLE AND NOT SLE_ROLE_SERVER) OR
38+ (ENABLE_DEDAP AND DEDAP_ROLE_SERVER))
34 set(ENABLE_BRIDGE ON)39 set(ENABLE_BRIDGE ON)
35endif()40endif()
36 41 
@@ -47,7 +52,7 @@ set(ONECONNECT_VERSION_CODE 2 CACHE INTEGER "OneConnect version code")
47 52 
48# SPEKE PBKDF2 iterations configuration53# SPEKE PBKDF2 iterations configuration
49set(SPEKE_PBKDF2_ITERATIONS 10000 CACHE INTEGER "SPEKE PBKDF2 iterations (1000-100000)")54set(SPEKE_PBKDF2_ITERATIONS 10000 CACHE INTEGER "SPEKE PBKDF2 iterations (1000-100000)")
50-# 暂时只支持一个管理员级别的terminal PSK55+# 锟斤拷时只支锟斤拷一锟斤拷锟斤拷锟斤拷员锟斤拷锟斤拷锟絫erminal PSK
51set(SEC_TERMINAL_PSK_MAX_NUM 1 CACHE INTEGER "Terminal PSK max num")56set(SEC_TERMINAL_PSK_MAX_NUM 1 CACHE INTEGER "Terminal PSK max num")
52if(NOT SEC_TERMINAL_PSK_MAX_NUM EQUAL 1)57if(NOT SEC_TERMINAL_PSK_MAX_NUM EQUAL 1)
53 message(FATAL_ERROR "SEC_TERMINAL_PSK_MAX_NUM must be 1")58 message(FATAL_ERROR "SEC_TERMINAL_PSK_MAX_NUM must be 1")
@@ -30,6 +30,7 @@
30 "iot_connect_sle_support",30 "iot_connect_sle_support",
31 "iot_connect_wifi_support",31 "iot_connect_wifi_support",
32 "iot_connect_eth_support",32 "iot_connect_eth_support",
33+ "iot_connect_dedap_support",
33 "iot_connect_ailife_support",34 "iot_connect_ailife_support",
34 "iot_connect_mbedtls_v2_support",35 "iot_connect_mbedtls_v2_support",
35 "iot_connect_mbedtls_psk_support",36 "iot_connect_mbedtls_psk_support",
@@ -24,13 +24,17 @@ endif()
24 24 
25if (ENABLE_ETH)25if (ENABLE_ETH)
26 add_subdirectory(eth)26 add_subdirectory(eth)
27-elseif (ENABLE_WIFI)27+endif()
28+ 
29+if (ENABLE_WIFI)
28 add_subdirectory(wifi)30 add_subdirectory(wifi)
29endif()31endif()
30 32 
31if (ENABLE_BRIDGE)33if (ENABLE_BRIDGE)
32 add_subdirectory(bridge)34 add_subdirectory(bridge)
33-else()35+endif()
36+ 
37+if (ENABLE_SLE AND NOT SLE_ROLE_SERVER)
34 add_subdirectory(gateway)38 add_subdirectory(gateway)
35endif()39endif()
36 40 
@@ -14,6 +14,10 @@
14 14 
15add_subdirectory(connect)15add_subdirectory(connect)
16add_subdirectory(softap)16add_subdirectory(softap)
17+add_subdirectory(local_control)
18+if (ENABLE_DEDAP AND DEDAP_ROLE_SERVER)
19+ add_subdirectory(dedap)
20+endif()
17 21 
18# 2.0 keeps the legacy Wi-Fi LAN Search and cloud services. 3.0 Wi-Fi Combo22# 2.0 keeps the legacy Wi-Fi LAN Search and cloud services. 3.0 Wi-Fi Combo
19# uses core/network/lan_search and does not build these legacy services.23# uses core/network/lan_search and does not build these legacy services.
@@ -0,0 +1,37 @@
1+#
2+# Copyright (c) 2024 China Mobile (Hangzhou) Information Technology 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+set(IOTC_SRC_LIST
16+ ${IOTC_SRC_LIST}
17+ ${CMAKE_CURRENT_SOURCE_DIR}/dedap_ctx.c
18+ ${CMAKE_CURRENT_SOURCE_DIR}/dedap_service.c
19+ ${CMAKE_CURRENT_SOURCE_DIR}/dedap_event_handler.c
20+ ${CMAKE_CURRENT_SOURCE_DIR}/dedap_hotspot.c
21+ ${CMAKE_CURRENT_SOURCE_DIR}/dedap_device_session.c
22+ ${CMAKE_CURRENT_SOURCE_DIR}/dedap_coap_client.c
23+ ${CMAKE_CURRENT_SOURCE_DIR}/dedap_connrequest.c
24+ ${CMAKE_CURRENT_SOURCE_DIR}/dedap_coap_server.c
25+ ${CMAKE_CURRENT_SOURCE_DIR}/dedap_provision.c
26+ ${CMAKE_CURRENT_SOURCE_DIR}/dedap_coap_enc.c
27+ ${CMAKE_CURRENT_SOURCE_DIR}/dedap_coap_apiserver.c
28+ PARENT_SCOPE
29+)
30+ 
31+set(IOTC_INC_LIST
32+ ${IOTC_INC_LIST}
33+ ${CMAKE_CURRENT_SOURCE_DIR}/include
34+ PARENT_SCOPE
35+)
36+ 
37+set(IOTC_TEST_INC_LIST ${IOTC_TEST_INC_LIST} PARENT_SCOPE)
@@ -0,0 +1,333 @@
1+/*
2+ * Copyright (c) 2024-2026 China Mobile (Hangzhou) Information Technology 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 <string.h>
17+#include "iotc_errcode.h"
18+#include "iotc_log.h"
19+#include "iotc_network.h"
20+#include "iotc_os.h"
21+#include "securec.h"
22+#include "utils_assert.h"
23+#include "utils_list.h"
24+#include "coap_codec_udp.h"
25+#include "coap_endpoint.h"
26+#include "coap_endpoint_event_source.h"
27+#include "coap_endpoint_client.h"
28+#include "coap_net_stack.h"
29+#include "trans_sess.h"
30+#include "trans_buffer_inner.h"
31+#include "sched_event_loop.h"
32+#include "dedap_coap_enc.h"
33+#include "dedap_device_session.h"
34+#include "dedap_coap_server.h"
35+#include "dedap_ctx.h"
36+ 
37+#define DEDAP_COAP_CLIENT_NAME "DEDAP_COAP"
38+#define DEDAP_COAP_RESP_TIMEOUT_MS (10 * 1000)
39+#define DEDAP_COAP_TOKEN_LEN 4
40+ 
41+// coap错误类别
42+#define COAP_CODE_CLASS_CLIENT_ERROR 4U
43+#define COAP_CODE_CLASS_SERVER_ERROR 5U
44+ 
45+static void DedapCoapServerDeinit(void);
46+ 
47+/**
48+ * @brief 获取dedap上下文(使用static局部变量实现单例)。
49+ * @return 上下文指针
50+ */
51+DedapCtx *GetDedapCtx(void)
52+{
53+ static DedapCtx ctx;
54+ return &ctx;
55+}
56+ 
57+/**
58+ * @brief 初始化dedap上下文
59+ * @details 清零结构体,初始化会话链表,设置initialized标志
60+ * @return 0成功,非0失败
61+ */
62+int32_t DedapCtxInit(void)
63+{
64+ DedapCtx *ctx = GetDedapCtx();
65+ 
66+ IOTC_LOGI("dedap ctx init starting...");
67+ 
68+ /* 清零上下文 */
69+ (void)memset_s(ctx, sizeof(DedapCtx), 0, sizeof(DedapCtx));
70+ 
71+ /* 初始化会话链表 */
72+ LIST_INIT(&ctx->sessionList);
73+ 
74+ ctx->initialized = true;
75+ 
76+ IOTC_LOGI("dedap ctx init success");
77+ return IOTC_OK;
78+}
79+ 
80+/**
81+ * @brief 创建Dedap CoAP网络栈。
82+ * @param ctx Dedap上下文。
83+ * @param port UDP端口号。
84+ * @return 0成功,非0失败。
85+ */
86+static int32_t DedapCreateCoapStack(DedapCtx *ctx, uint16_t port)
87+{
88+ char localIp[IOTC_IP_STR_MAX_LEN + 1] = {0};
89+ int32_t ret = IotcGetLocalIp(localIp, IOTC_IP_STR_MAX_LEN);
90+ if (ret != IOTC_OK) {
91+ return ret;
92+ }
93+ TransSocket *socket = TransSocketUdpNew(&(SocketUdpInitParam) {
94+ .port = port,
95+ .localAddr = localIp,
96+ .multicastAddr = NULL,
97+ .broadcastAddr = NULL,
98+ });
99+ if (socket == NULL) {
100+ return IOTC_CORE_WIFI_TRANS_ERR_SOCKET_UDP_CREATE;
101+ }
102+ CoapNetStackParam param = {
103+ .name = DEDAP_COAP_CLIENT_NAME,
104+ .socket = socket,
105+ .sessMsgSize = sizeof(CoapPacket),
106+ .sessUserData = ctx,
107+ .encoder = CoapUdpEncode,
108+ .decoder = CoapUdpDecode,
109+ .endpointUserData = ctx,
110+ };
111+ ret = CoapNetStackCreate(&ctx->coapStack, &param);
112+ if (ret != IOTC_OK) {
113+ TransSocketFree(socket);
114+ return ret;
115+ }
116+ TransSessAddRecvTailHandler(ctx->coapStack.sess, DedapCoapMsgRecvDecryptProcess, "decrypt", NULL);
117+ TransSessAddSendTailHandler(ctx->coapStack.sess, DedapCoapMsgSendEncryptProcess, "encrypt", NULL);
118+ CoapEndpointSessSetup(ctx->coapStack.endpoint);
119+ return IOTC_OK;
120+}
121+ 
122+/**
123+ * @brief 配置Dedap CoAP端点参数。
124+ * @param ctx Dedap上下文。
125+ * @return 0成功,非0失败。
126+ */
127+static int32_t DedapConfigureCoapEndpoint(DedapCtx *ctx)
128+{
129+ int32_t ret = CoapClientSetRespTimeout(ctx->coapStack.endpoint, DEDAP_COAP_RESP_TIMEOUT_MS);
130+ if (ret != IOTC_OK) {
131+ return ret;
132+ }
133+ return CoapClientSetTokenLen(ctx->coapStack.endpoint, DEDAP_COAP_TOKEN_LEN);
134+}
135+ 
136+/**
137+ * @brief 创建并注册Dedap CoAP事件源。
138+ * @param ctx Dedap上下文。
139+ * @return 0成功,非0失败。
140+ */
141+static int32_t DedapRegisterCoapEventSource(DedapCtx *ctx)
142+{
143+ ctx->coapSource = CoapEndpointEventSourceNew(ctx->coapStack.endpoint);
144+ if (ctx->coapSource == NULL) {
145+ return IOTC_ERROR;
146+ }
147+ int32_t ret = EventLoopAddSource(GetSchedEventLoop(), ctx->coapSource);
148+ if (ret != IOTC_OK) {
149+ EventSourceFree(ctx->coapSource);
150+ ctx->coapSource = NULL;
151+ }
152+ return ret;
153+}
154+ 
155+/**
156+ * @brief 初始化CoAP服务器。
157+ * @param port UDP端口号(0表示自动分配)。
158+ * @return 0成功,非0失败。
159+ */
160+static int32_t DedapCoapServerInit(uint16_t port)
161+{
162+ DedapCtx *ctx = GetDedapCtx();
163+ int32_t ret = DedapCreateCoapStack(ctx, port);
164+ if (ret == IOTC_OK) {
165+ ret = DedapConfigureCoapEndpoint(ctx);
166+ }
167+ if (ret == IOTC_OK) {
168+ ret = DedapRegisterCoapEventSource(ctx);
169+ }
170+ if (ret != IOTC_OK) {
171+ DedapCoapServerDeinit();
172+ }
173+ return ret;
174+}
175+ 
176+/**
177+ * @brief 反初始化CoAP服务器
178+ * @details 停止CoAP网络栈,移除事件源,销毁网络栈
179+ * @return 无返回值;尚未创建的资源会被跳过。
180+ */
181+static void DedapCoapServerDeinit(void)
182+{
183+ DedapCtx *ctx = GetDedapCtx();
184+ 
185+ /* 停止CoAP网络栈 */
186+ if (ctx->coapStarted) {
187+ CoapNetStackStop(&ctx->coapStack);
188+ ctx->coapStarted = false;
189+ }
190+ 
191+ /* 移除事件源 */
192+ if (ctx->coapSource != NULL) {
193+ EventLoopDelSource(GetSchedEventLoop(), ctx->coapSource);
194+ EventSourceFree(ctx->coapSource);
195+ ctx->coapSource = NULL;
196+ }
197+ 
198+ /* 销毁CoAP网络栈 */
199+ if (ctx->coapStack.endpoint != NULL) {
200+ CoapNetStackDestroy(&ctx->coapStack);
201+ }
202+}
203+ 
204+/**
205+ * @brief 启动CoAP网络栈
206+ * @details 启动已初始化的CoAP网络栈,开始监听请求
207+ * @return 0成功,非0失败
208+ */
209+static int32_t DedapCoapServerStart(void)
210+{
211+ DedapCtx *ctx = GetDedapCtx();
212+ int32_t ret = CoapNetStackStart(&ctx->coapStack);
213+ if (ret != IOTC_OK) {
214+ IOTC_LOGE("dedap:start coap stack failed %d", ret);
215+ return ret;
216+ }
217+ ctx->coapStarted = true;
218+ return IOTC_OK;
219+}
220+ 
221+/**
222+ * @brief 初始化dedap UDP传输层
223+ * @details 按顺序执行:初始化CoAP服务器、注册处理器、启动网络栈
224+ * @param port UDP端口号(0表示自动分配)
225+ * @return 0成功,非0失败
226+ */
227+int32_t DedapTransportUdpInit(uint16_t port)
228+{
229+ int32_t ret;
230+ 
231+ /* 初始化CoAP服务器基础设施 */
232+ ret = DedapCoapServerInit(port);
233+ if (ret != IOTC_OK) {
234+ IOTC_LOGE("dedap:coap server init failed %d", ret);
235+ return ret;
236+ }
237+ 
238+ /* 注册CoAP接收处理器 */
239+ ret = DedapCoapHandlerRegister();
240+ if (ret != IOTC_OK) {
241+ IOTC_LOGE("dedap:handler register failed, cleanup");
242+ DedapCoapServerDeinit();
243+ return ret;
244+ }
245+ 
246+ /* 启动CoAP网络栈(handler注册完成后再开始监听) */
247+ ret = DedapCoapServerStart();
248+ if (ret != IOTC_OK) {
249+ IOTC_LOGE("dedap:server start failed, cleanup");
250+ DedapCoapHandlerUnregister();
251+ DedapCoapServerDeinit();
252+ return ret;
253+ }
254+ 
255+ IOTC_LOGI("dedap transport mode: UDP, port=%u", port);
256+ return IOTC_OK;
257+}
258+ 
259+/**
260+ * @brief 反初始化dedap UDP传输层
261+ * @details 注销CoAP接收处理器,清理CoAP服务器
262+ * @return 无返回值。
263+ */
264+void DedapTransportUdpDeinit(void)
265+{
266+ /* 注销CoAP接收处理器 */
267+ DedapCoapHandlerUnregister();
268+ 
269+ /* 清理CoAP服务器 */
270+ DedapCoapServerDeinit();
271+}
272+ 
273+/**
274+ * @brief 反初始化dedap上下文
275+ * @details 按以下顺序清理资源:
276+ * 1. 清理传输层(调用DedapTransportUdpDeinit,包含CoAP处理器注销和CoAP服务器清理)
277+ * 2. 释放所有活跃的设备会话
278+ * 3. 清零上下文结构体,重置initialized标志
279+ * @note 调用此函数后,dedap模块完全重置,需重新调用DedapCtxInit才能使用
280+ * @return 无返回值;上下文未初始化时直接返回。
281+ */
282+void DedapCtxDeinit(void)
283+{
284+ DedapCtx *ctx = GetDedapCtx();
285+ if (!ctx->initialized) {
286+ return;
287+ }
288+ 
289+ IOTC_LOGI("dedap ctx deinit starting...");
290+ 
291+ /* 清理传输层 */
292+ DedapTransportUdpDeinit();
293+ 
294+ /* 释放所有活跃的设备会话 */
295+ ListEntry *pos = NULL;
296+ ListEntry *tmp = NULL;
297+ LIST_FOR_EACH_ITEM_SAFE(pos, tmp, &ctx->sessionList) {
298+ DedapDeviceSession *sess = CONTAINER_OF(pos, DedapDeviceSession, node);
299+ DedapFreeSession(sess);
300+ }
301+ 
302+ (void)memset_s(ctx, sizeof(DedapCtx), 0, sizeof(DedapCtx));
303+ ctx->initialized = false;
304+ 
305+ IOTC_LOGI("dedap ctx deinit done");
306+}
307+ 
308+/**
309+ * @brief 将 CoAP 响应码映射为 Dedap 业务错误码
310+ * @param coapCode CoAP 响应码
311+ * @return Dedap 业务错误码
312+ */
313+int32_t DedapMapCoapCodeToBusinessError(uint8_t coapCode)
314+{
315+ /* 2.xx 成功响应 */
316+ if (COAP_CODE_CLASS(coapCode) == COAP_CODE_CLASS_SUCC_RESP) {
317+ return IOTC_OK;
318+ }
319+ 
320+ /* 4.xx 客户端错误 - 映射为 Dedap 客户端错误 */
321+ uint8_t codeClass = COAP_CODE_CLASS(coapCode);
322+ if (codeClass == COAP_CODE_CLASS_CLIENT_ERROR) {
323+ return IOTC_CORE_DEDAP_ERR_COAP_CLIENT_ERROR;
324+ }
325+ 
326+ /* 5.xx 服务器错误 - 映射为 Dedap 服务器错误 */
327+ if (codeClass == COAP_CODE_CLASS_SERVER_ERROR) {
328+ return IOTC_CORE_DEDAP_ERR_COAP_SERVER_ERROR;
329+ }
330+ 
331+ /* 其他未知错误 */
332+ return IOTC_CORE_DEDAP_ERR_COAP_CLIENT_ERROR;
333+}
@@ -0,0 +1,203 @@
1+/*
2+ * Copyright (c) 2024-2026 China Mobile (Hangzhou) Information Technology 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 "iotc_event.h"
17+#include "iotc_event_params.h"
18+#include "iotc_log.h"
19+#include "iotc_errcode.h"
20+#include "utils_assert.h"
21+#include "utils_common.h"
22+#include "event_bus.h"
23+#include "securec.h"
24+#include "dedap_hotspot.h"
25+#include "dedap_device_session.h"
26+#include "dedap_event_handler.h"
27+ 
28+/**
29+ * @brief 处理START_DISCOVERY事件回调(bridge下行→dedap)。
30+ * @details enable=1时启动专用热点,enable=2时停止专用热点。
31+ * @param event 事件ID。
32+ * @param param 事件参数,包含enable/timeout/scanType。
33+ * @param len 参数长度。
34+ * @return 无返回值;参数非法或热点操作失败时记录日志后返回。
35+ */
36+static void DedapStartDiscoveryCallback(uint32_t event, IotcStartDiscoveryParam *param, uint32_t len)
37+{
38+ NOT_USED(event);
39+ if (param == NULL || len < sizeof(IotcStartDiscoveryParam)) {
40+ IOTC_LOGE("dedap:start discovery param invalid");
41+ return;
42+ }
43+ 
44+ IotcStartDiscoveryParam *p = param;
45+ IOTC_LOGI("dedap:[enter]%s,enable=%d,timeout=%d,scanType=0x%X",
46+ __FUNCTION__, p->enable, p->timeout, p->scanType);
47+ 
48+ int32_t ret;
49+ if (p->enable == IOTC_SCAN_CMD_STOP) {
50+ ret = DedapHotspotStop();
51+ if (ret != IOTC_OK) {
52+ IOTC_LOGE("dedap:stop hotspot failed %d", ret);
53+ }
54+ } else {
55+ ret = DedapHotspotStart();
56+ if (ret != IOTC_OK) {
57+ IOTC_LOGE("dedap:start hotspot failed %d", ret);
58+ }
59+ }
60+}
61+ 
62+/**
63+ * @brief 处理ADD_SUBDEV事件回调(bridge下行→dedap)。
64+ * @details 解析prodId/sn/mac/pin/timeout,启动指定WiFi设备的配网流程。
65+ * @param event 事件ID。
66+ * @param param 事件参数,包含添加子设备的信息。
67+ * @param len 参数长度。
68+ * @return 无返回值;参数非法、链路类型不匹配或配网启动失败时提前返回。
69+ */
70+static void DedapAddSubDevCallback(uint32_t event, IotcAddSubDevParam *param, uint32_t len)
71+{
72+ NOT_USED(event);
73+ if (param == NULL || len < sizeof(IotcAddSubDevParam)) {
74+ IOTC_LOGE("dedap:add subdev param invalid");
75+ return;
76+ }
77+ 
78+ IotcAddSubDevParam *p = param;
79+ 
80+ /* 链路类型过滤:仅处理WiFi链路的事件 */
81+ if (p->linkType != IOTC_LINK_WIFI && p->linkType != IOTC_LINK_NONE) {
82+ IOTC_LOGD("dedap:add subdev event filtered out, linkType=%d", p->linkType);
83+ return;
84+ }
85+ 
86+ IOTC_LOGI("dedap:[enter]%s,prodId=%s,mac=%s,timeout=%u",
87+ __FUNCTION__, p->prodId, p->mac, p->timeout);
88+ 
89+ int32_t ret = DedapDeviceProvisionStart(p->mac, p->prodId, p->pin);
90+ if (ret != IOTC_OK) {
91+ IOTC_LOGE("dedap:start provisioning failed %d", ret);
92+ }
93+}
94+ 
95+/**
96+ * @brief 处理HUB_SETUP事件回调(bridge下行→dedap)。
97+ * @details 将管理域和配网信息(WiFi凭证、认证信息)下发到目标WiFi设备。
98+ * 采用链式触发机制:先下发 provisionPSK,成功后由响应处理器触发 hubCfg。
99+ * @param event 事件ID。
100+ * @param param 事件参数,包含配网通知的结构化字段。
101+ * @param len 参数长度。
102+ * @return 无返回值;参数非法、链路类型不匹配或配置下发失败时提前返回。
103+ */
104+static void DedapHubSetupCallback(uint32_t event, IotcHubSetupParam *param, uint32_t len)
105+{
106+ NOT_USED(event);
107+ if (param == NULL || len < sizeof(IotcHubSetupParam)) {
108+ IOTC_LOGE("dedap:hub setup param invalid");
109+ return;
110+ }
111+ 
112+ IotcHubSetupParam *p = param;
113+ 
114+ /* 链路类型过滤:仅处理WiFi链路的事件 */
115+ if (p->linkType != IOTC_LINK_WIFI && p->linkType != IOTC_LINK_NONE) {
116+ IOTC_LOGD("dedap:hub setup event filtered out, linkType=%d", p->linkType);
117+ return;
118+ }
119+ 
120+ IOTC_LOGI("dedap:[enter]%s,prodId=%s,devId=%s,authType=%d,mac=%s",
121+ __FUNCTION__, p->prodId, p->devId, p->authType, p->mac);
122+ 
123+ int32_t ret = DedapDeviceHubSetup(p);
124+ if (ret != IOTC_OK) {
125+ IOTC_LOGE("dedap:hub setup failed %d", ret);
126+ /* 上报失败事件到 bridge */
127+ DedapPublishAddFail(p->mac, p->prodId, p->snSuffix, ret);
128+ }
129+}
130+ 
131+/**
132+ * @brief 处理SUBDEV_CLEANUP事件回调(bridge下行→dedap)。
133+ * @details 配网超时后bridge发布此事件,dedap按mac清理对应的设备会话。
134+ * @param event 事件ID。
135+ * @param param 事件参数,包含mac。
136+ * @param len 参数长度。
137+ * @return 无返回值;参数非法或链路类型不匹配时提前返回。
138+ */
139+static void DedapSubDevCleanupCallback(uint32_t event, IotcSubDevCleanupParam *param, uint32_t len)
140+{
141+ NOT_USED(event);
142+ if (param == NULL || len < sizeof(IotcSubDevCleanupParam)) {
143+ IOTC_LOGE("dedap:subdev cleanup param invalid");
144+ return;
145+ }
146+ 
147+ IotcSubDevCleanupParam *p = param;
148+ 
149+ /* 链路类型过滤:仅处理WiFi链路的事件 */
150+ if (p->linkType != IOTC_LINK_WIFI && p->linkType != IOTC_LINK_NONE) {
151+ IOTC_LOGD("dedap:subdev cleanup event filtered out, linkType=%d", p->linkType);
152+ return;
153+ }
154+ 
155+ IOTC_LOGI("dedap:[enter]%s,mac=%s", __FUNCTION__, p->mac);
156+ 
157+ /* 按mac清理指定设备会话 */
158+ DedapDeviceSession *sess = DedapFindSessionByMac(p->mac);
159+ if (sess != NULL) {
160+ IOTC_LOGI("dedap:cleanup session mac=%s", p->mac);
161+ DedapFreeSession(sess);
162+ }
163+}
164+ 
165+/**
166+ * @brief 初始化dedap事件订阅。
167+ * @details 订阅bridge下行事件(START_DISCOVERY/ADD_SUBDEV/HUB_SETUP/SUBDEV_CLEANUP)。
168+ * @return 0成功,非0失败。
169+ */
170+int32_t DedapEventHandlerInit(void)
171+{
172+ int32_t ret;
173+ 
174+ ret = EventBusSubscribe((EventBusCallback)DedapStartDiscoveryCallback, IOTC_BRIDGE_EVENT_START_DISCOVERY);
175+ CHECK_RETURN_LOGE(ret == IOTC_OK, ret, "dedap:subscribe start discovery err:%d", ret);
176+ 
177+ ret = EventBusSubscribe((EventBusCallback)DedapAddSubDevCallback, IOTC_BRIDGE_EVENT_ADD_SUBDEV);
178+ CHECK_RETURN_LOGE(ret == IOTC_OK, ret, "dedap:subscribe add subdev err:%d", ret);
179+ 
180+ ret = EventBusSubscribe((EventBusCallback)DedapHubSetupCallback, IOTC_BRIDGE_EVENT_HUB_SETUP);
181+ CHECK_RETURN_LOGE(ret == IOTC_OK, ret, "dedap:subscribe hub setup err:%d", ret);
182+ 
183+ ret = EventBusSubscribe((EventBusCallback)DedapSubDevCleanupCallback, IOTC_BRIDGE_EVENT_SUBDEV_CLEANUP);
184+ CHECK_RETURN_LOGE(ret == IOTC_OK, ret, "dedap:subscribe subdev cleanup err:%d", ret);
185+ 
186+ IOTC_LOGI("dedap:event handlers registered");
187+ return IOTC_OK;
188+}
189+ 
190+/**
191+ * @brief 反初始化dedap事件订阅。
192+ * @details 退订所有已订阅的bridge事件。
193+ * @return 无返回值。
194+ */
195+void DedapEventHandlerDeinit(void)
196+{
197+ EventBusUnsubscribe((EventBusCallback)DedapSubDevCleanupCallback);
198+ EventBusUnsubscribe((EventBusCallback)DedapHubSetupCallback);
199+ EventBusUnsubscribe((EventBusCallback)DedapAddSubDevCallback);
200+ EventBusUnsubscribe((EventBusCallback)DedapStartDiscoveryCallback);
201+ 
202+ IOTC_LOGI("dedap:event handlers unregistered");
203+}
@@ -0,0 +1,120 @@
1+/*
2+ * Copyright (c) 2024-2026 China Mobile (Hangzhou) Information Technology 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 <stdio.h>
17+#include "iotc_log.h"
18+#include "iotc_wifi.h"
19+#include "iotc_errcode.h"
20+#include "utils_assert.h"
21+#include "securec.h"
22+#include "dedap_ctx.h"
23+#include "dedap_hotspot.h"
24+ 
25+#define DEDAP_HOTSPOT_SSID_MAX_LEN (IOTC_WIFI_SSID_MAX_LEN + 1)
26+#define DEDAP_HOTSPOT_PWD_MAX_LEN (64)
27+#define DEDAP_HOTSPOT_SSID "ONECONNECT-QOC-LINK" // CMCC-GUIDE-LINK
28+ 
29+/**
30+ * @brief 生成dedap代理配网专用热点的SSID。
31+ * @param ssid 输出缓冲区,用于存放生成的SSID。
32+ * @param len 输入/输出:输入时为缓冲区最大长度,输出时为实际长度。
33+ * @return 0成功,非0失败。
34+ */
35+static int32_t BuildDedapSoftapSsid(uint8_t *ssid, uint32_t *len)
36+{
37+ CHECK_RETURN_LOGW(ssid != NULL && len != NULL && *len > 0,
38+ IOTC_ERR_PARAM_INVALID, "param invalid");
39+ 
40+ uint32_t requiredLen = (uint32_t)sizeof(DEDAP_HOTSPOT_SSID);
41+ if (*len < requiredLen) {
42+ IOTC_LOGE("dedap:ssid buffer too small");
43+ return IOTC_ERR_PARAM_INVALID;
44+ }
45+ if (strcpy_s((char *)ssid, *len, DEDAP_HOTSPOT_SSID) != EOK) {
46+ IOTC_LOGE("dedap:copy ssid failed");
47+ return IOTC_ERR_SECUREC_STRCPY;
48+ }
49+ *len = requiredLen - 1;
50+ return IOTC_OK;
51+}
52+ 
53+/**
54+ * @brief 启动专用热点(SoftAP)。
55+ * @details 生成SSID并调用底层WiFi适配器启动SoftAP,
56+ * 等待WiFi设备连接进行代理配网。
57+ * @return 0成功,非0失败。
58+ */
59+int32_t DedapHotspotStart(void)
60+{
61+ DedapCtx *ctx = GetDedapCtx();
62+ if (ctx->hotspotRunning) {
63+ IOTC_LOGW("dedap:hotspot already running");
64+ return IOTC_OK;
65+ }
66+ 
67+ uint8_t ssid[DEDAP_HOTSPOT_SSID_MAX_LEN] = {0};
68+ uint32_t ssidLen = sizeof(ssid);
69+ 
70+ int32_t ret = BuildDedapSoftapSsid(ssid, &ssidLen);
71+ if (ret != IOTC_OK) {
72+ IOTC_LOGE("dedap:build ssid failed %d", ret);
73+ return ret;
74+ }
75+ 
76+ IOTC_LOGI("dedap:starting hotspot with ssid='%.*s' len=%u", ssidLen, ssid, ssidLen);
77+ 
78+ ret = IotcStartSoftAp(ssid, ssidLen, NULL, 0);
79+ if (ret != IOTC_OK) {
80+ IOTC_LOGE("dedap:start softap failed %d", ret);
81+ return ret;
82+ }
83+ 
84+ ctx->hotspotRunning = true;
85+ IOTC_LOGI("dedap:hotspot started");
86+ return IOTC_OK;
87+}
88+ 
89+/**
90+ * @brief 停止专用热点。
91+ * @details 调用底层WiFi适配器关闭SoftAP。
92+ * @return 0成功,非0失败。
93+ */
94+int32_t DedapHotspotStop(void)
95+{
96+ DedapCtx *ctx = GetDedapCtx();
97+ if (!ctx->hotspotRunning) {
98+ IOTC_LOGW("dedap:hotspot not running");
99+ return IOTC_OK;
100+ }
101+ 
102+ int32_t ret = IotcStopSoftAp();
103+ if (ret != IOTC_OK) {
104+ IOTC_LOGE("dedap:stop softap failed %d", ret);
105+ return ret;
106+ }
107+ 
108+ ctx->hotspotRunning = false;
109+ IOTC_LOGI("dedap:hotspot stopped");
110+ return IOTC_OK;
111+}
112+ 
113+/**
114+ * @brief 检查热点是否正在运行。
115+ * @return true表示热点处于活动状态,false表示未运行。
116+ */
117+bool DedapHotspotIsRunning(void)
118+{
119+ return GetDedapCtx()->hotspotRunning;
120+}
@@ -0,0 +1,97 @@
1+/*
2+ * Copyright (c) 2024-2026 China Mobile (Hangzhou) Information Technology 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 "iotc_log.h"
17+#include "iotc_errcode.h"
18+#include "utils_assert.h"
19+#include "dedap_ctx.h"
20+#include "dedap_coap_server.h"
21+#include "dedap_event_handler.h"
22+#include "dedap_hotspot.h"
23+#include "dedap_device_session.h"
24+#include "dedap_service.h"
25+ 
26+/**
27+ * @brief 初始化dedap服务
28+ * @details 按顺序初始化:上下文 → 传输层 → 事件订阅
29+ * @return 0成功,非0失败
30+ */
31+int32_t DedapServiceInit(void)
32+{
33+ DedapCtx *ctx = GetDedapCtx();
34+ if (ctx->initialized) {
35+ IOTC_LOGW("dedap:already initialized");
36+ return IOTC_OK;
37+ }
38+ 
39+ IOTC_LOGI("dedap:service init starting...");
40+ 
41+ /* 1. 初始化上下文 */
42+ int32_t ret = DedapCtxInit();
43+ if (ret != IOTC_OK) {
44+ IOTC_LOGE("dedap:ctx init failed %d", ret);
45+ return ret;
46+ }
47+ 
48+ /* 2. 初始化传输层(UDP模式) */
49+ ret = DedapTransportUdpInit(DEDAP_DEFAULT_PORT);
50+ if (ret != IOTC_OK) {
51+ IOTC_LOGE("dedap:transport init failed %d", ret);
52+ DedapCtxDeinit();
53+ return ret;
54+ }
55+ 
56+ /* 3. 初始化事件订阅(订阅bridge事件) */
57+ ret = DedapEventHandlerInit();
58+ if (ret != IOTC_OK) {
59+ IOTC_LOGE("dedap:event handler init failed %d", ret);
60+ DedapTransportUdpDeinit();
61+ DedapCtxDeinit();
62+ return ret;
63+ }
64+ 
65+ IOTC_LOGI("dedap:service init success");
66+ return IOTC_OK;
67+}
68+ 
69+/**
70+ * @brief 反初始化dedap服务
71+ * @details 按逆序释放资源:
72+ * 1. 停止热点(如果正在运行)
73+ * 2. 退订EventBus事件(取消对bridge事件的订阅)
74+ * 3. 清理上下文(DedapCtxDeinit内部会清理传输层和所有设备会话)
75+ * @note DedapCtxDeinit已包含传输层清理,无需单独调用DedapTransportUdpDeinit
76+ * @return 无返回值;服务未初始化时直接返回。
77+ */
78+void DedapServiceDeinit(void)
79+{
80+ DedapCtx *ctx = GetDedapCtx();
81+ if (!ctx->initialized) {
82+ return;
83+ }
84+ 
85+ IOTC_LOGI("dedap:service deinit starting...");
86+ 
87+ /* 1. 停止热点(如果正在运行) */
88+ (void)DedapHotspotStop();
89+ 
90+ /* 2. 退订事件订阅 */
91+ DedapEventHandlerDeinit();
92+ 
93+ /* 3. 清理上下文(内部会调用DedapTransportUdpDeinit清理传输层,并释放所有设备会话) */
94+ DedapCtxDeinit();
95+ 
96+ IOTC_LOGI("dedap:service deinit done");
97+}
@@ -138,3 +138,22 @@ if (iotc_one_connect_version_code < 2) {
138}138}
139 139 
140iotc_core_wifi_def = []140iotc_core_wifi_def = []
141+ 
142+if (iot_connect_wifi_support && iot_connect_dedap_support &&
143+ iot_connect_dedap_role_server) {
144+ iotc_core_wifi_inc += [ "$wifi_core_path/application/dedap/include" ]
145+ iotc_core_wifi_src += [
146+ "$wifi_core_path/application/dedap/dedap_ctx.c",
147+ "$wifi_core_path/application/dedap/dedap_service.c",
148+ "$wifi_core_path/application/dedap/dedap_event_handler.c",
149+ "$wifi_core_path/application/dedap/dedap_hotspot.c",
150+ "$wifi_core_path/application/dedap/dedap_device_session.c",
151+ "$wifi_core_path/application/dedap/dedap_coap_client.c",
152+ "$wifi_core_path/application/dedap/dedap_connrequest.c",
153+ "$wifi_core_path/application/dedap/dedap_coap_server.c",
154+ "$wifi_core_path/application/dedap/dedap_provision.c",
155+ "$wifi_core_path/application/dedap/dedap_coap_enc.c",
156+ "$wifi_core_path/application/dedap/dedap_coap_apiserver.c",
157+ ]
158+ iotc_core_wifi_def += [ "ENABLE_DEDAP_GATEWAY" ]
159+}
@@ -26,6 +26,13 @@
26#if IOTC_ONECONNECT_VERSION_CODE >= 226#if IOTC_ONECONNECT_VERSION_CODE >= 2
27#include "sched_fd_watch.h"27#include "sched_fd_watch.h"
28#include "net_trans_buffer_inner.h"28#include "net_trans_buffer_inner.h"
29+#include "iotc_event.h"
30+#include "comm_def.h"
31+#include "net_lan_search.h"
32+#include "wifi_net_info.h"
33+#ifdef ENABLE_DEDAP_GATEWAY
34+#include "dedap_service.h"
35+#endif
29#else36#else
30#include "m2m_cloud_svc.h"37#include "m2m_cloud_svc.h"
31#endif38#endif
@@ -40,6 +47,9 @@ static const FwkInitUnit CORE_WIFI_V3[] = {
40 {FWK_INIT_LVL_BIZ, "wifi_connect", WifiServiceConnectInit, WifiServiceConnectDeinit},47 {FWK_INIT_LVL_BIZ, "wifi_connect", WifiServiceConnectInit, WifiServiceConnectDeinit},
41 {FWK_INIT_LVL_BIZ, "lan_search", LanSearchServiceInit, LanSearchServiceDeinit},48 {FWK_INIT_LVL_BIZ, "lan_search", LanSearchServiceInit, LanSearchServiceDeinit},
42 {FWK_INIT_LVL_BIZ, "local_control", LocalControlServiceInit, LocalControlServiceDeinit},49 {FWK_INIT_LVL_BIZ, "local_control", LocalControlServiceInit, LocalControlServiceDeinit},
50+#ifdef ENABLE_DEDAP_GATEWAY
51+ {FWK_INIT_LVL_BIZ, "dedap_gw", DedapServiceInit, DedapServiceDeinit},
52+#endif
43};53};
44#else54#else
45static const FwkInitUnit CORE_WIFI[] = {55static const FwkInitUnit CORE_WIFI[] = {
@@ -25,6 +25,8 @@ declare_args() {
25 iot_connect_wifi_support = true25 iot_connect_wifi_support = true
26 iot_connect_eth_support = false26 iot_connect_eth_support = false
27 iot_connect_bridge_support = false27 iot_connect_bridge_support = false
28+ iot_connect_dedap_support = false
29+ iot_connect_dedap_role_server = false
28 iot_connect_ailife_support = false30 iot_connect_ailife_support = false
29 iot_connect_mbedtls_v2_support = false31 iot_connect_mbedtls_v2_support = false
30 iot_connect_mbedtls_psk_support = false32 iot_connect_mbedtls_psk_support = false
@@ -46,7 +48,7 @@ declare_args() {
46 iot_connect_ble_adv_update_support = false48 iot_connect_ble_adv_update_support = false
47 #是否支持iotc数据保存49 #是否支持iotc数据保存
48 iot_connect_kv_support = true50 iot_connect_kv_support = true
49- #控制发OH靠近发现广播的发出 51+ #控制发OH靠近发现广播的发出
50 iot_connect_oh_nearlink_support = false52 iot_connect_oh_nearlink_support = false
51 iot_connect_ssl_backend = "mbedtls"53 iot_connect_ssl_backend = "mbedtls"
52 iot_connect_openhitls_include_dirs = []54 iot_connect_openhitls_include_dirs = []
@@ -78,6 +80,10 @@ if (iotc_one_connect_version_code >= 2) {
78iot_connect_network_support = iot_connect_eth_support ||80iot_connect_network_support = iot_connect_eth_support ||
79 (iot_connect_wifi_support && iotc_one_connect_version_code >= 2)81 (iot_connect_wifi_support && iotc_one_connect_version_code >= 2)
80 82 
83+if (iot_connect_dedap_support && iot_connect_dedap_role_server) {
84+ iot_connect_bridge_support = true
85+}
86+ 
81if (defined(ohos_lite)) {87if (defined(ohos_lite)) {
82 if (ohos_kernel_type == "liteos_m") {88 if (ohos_kernel_type == "liteos_m") {
83 declare_args() {89 declare_args() {