1 /*
2 * Copyright (c) 2024 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 "lnn_ctrl_lane.h"
17
18 #include <securec.h>
19
20 #include "auth_interface.h"
21 #include "bus_center_manager.h"
22 #include "lnn_lane_common.h"
23 #include "lnn_lane_interface.h"
24 #include "lnn_log.h"
25 #include "lnn_lane_select.h"
26 #include "softbus_adapter_mem.h"
27 #include "softbus_errcode.h"
28 #include "wifi_direct_manager.h"
29
30 typedef struct {
31 ListNode node;
32 uint32_t laneHandle;
33 uint64_t laneId;
34 uint32_t linkListIdx;
35 LaneAllocInfo allocInfo;
36 LanePreferredLinkList linkList;
37 LaneAllocListener listener;
38 } CtrlReqInfo;
39
40 typedef struct {
41 uint32_t cnt;
42 ListNode list;
43 } CtrlLaneList;
44
45 static SoftBusMutex g_ctrlLaneMutex;
46 static CtrlLaneList *g_ctrlReqList = NULL;
47
48 static int32_t CtrlTriggerLink(uint32_t laneHandle);
49
Lock(void)50 static int32_t Lock(void)
51 {
52 return SoftBusMutexLock(&g_ctrlLaneMutex);
53 }
54
Unlock(void)55 static void Unlock(void)
56 {
57 (void)SoftBusMutexUnlock(&g_ctrlLaneMutex);
58 }
59
ConvertAuthLinkToLaneLink(AuthLinkTypeList * authLinkType,LanePreferredLinkList * laneLinkType)60 static int32_t ConvertAuthLinkToLaneLink(AuthLinkTypeList *authLinkType, LanePreferredLinkList *laneLinkType)
61 {
62 if (authLinkType == NULL || laneLinkType == NULL) {
63 LNN_LOGE(LNN_LANE, "param invalid");
64 return SOFTBUS_INVALID_PARAM;
65 }
66 laneLinkType->linkTypeNum = 0;
67 for (uint32_t i = 0; i < authLinkType->linkTypeNum; ++i) {
68 switch (authLinkType->linkType[i]) {
69 case AUTH_LINK_TYPE_WIFI:
70 laneLinkType->linkType[laneLinkType->linkTypeNum++] = LANE_WLAN_5G;
71 laneLinkType->linkType[laneLinkType->linkTypeNum++] = LANE_WLAN_2P4G;
72 break;
73 case AUTH_LINK_TYPE_BR:
74 laneLinkType->linkType[laneLinkType->linkTypeNum++] = LANE_BR;
75 break;
76 case AUTH_LINK_TYPE_BLE:
77 laneLinkType->linkType[laneLinkType->linkTypeNum++] = LANE_BLE;
78 break;
79 case AUTH_LINK_TYPE_P2P:
80 laneLinkType->linkType[laneLinkType->linkTypeNum++] = LANE_P2P;
81 break;
82 case AUTH_LINK_TYPE_ENHANCED_P2P:
83 laneLinkType->linkType[laneLinkType->linkTypeNum++] = LANE_HML;
84 break;
85 default:
86 break;
87 }
88 }
89 return SOFTBUS_OK;
90 }
91
IsAuthReuseP2p(const char * networkId,const char * udid,AuthLinkType authType)92 bool IsAuthReuseP2p(const char *networkId, const char *udid, AuthLinkType authType)
93 {
94 LaneResource resoureItem;
95 if (memset_s(&resoureItem, sizeof(LaneResource), 0, sizeof(LaneResource)) != EOK) {
96 LNN_LOGE(LNN_LANE, "memset_s LaneResource fail");
97 return false;
98 }
99 if (authType == AUTH_LINK_TYPE_ENHANCED_P2P &&
100 FindLaneResourceByLinkType(udid, LANE_HML, &resoureItem) == SOFTBUS_OK &&
101 !GetWifiDirectManager()->isNegotiateChannelNeeded(networkId, WIFI_DIRECT_LINK_TYPE_HML)) {
102 LNN_LOGI(LNN_LANE, "can use HML");
103 return true;
104 } else if (authType == AUTH_LINK_TYPE_P2P &&
105 FindLaneResourceByLinkType(udid, LANE_P2P, &resoureItem) == SOFTBUS_OK &&
106 !GetWifiDirectManager()->isNegotiateChannelNeeded(networkId, WIFI_DIRECT_LINK_TYPE_P2P)) {
107 LNN_LOGI(LNN_LANE, "can use P2P");
108 return true;
109 } else {
110 return false;
111 }
112 }
113
GetCtrlReqInfo(uint32_t laneHandle,CtrlReqInfo * reqInfo)114 static int32_t GetCtrlReqInfo(uint32_t laneHandle, CtrlReqInfo *reqInfo)
115 {
116 if (reqInfo == NULL || laneHandle == INVALID_LANE_REQ_ID) {
117 return SOFTBUS_INVALID_PARAM;
118 }
119 if (Lock() != SOFTBUS_OK) {
120 LNN_LOGE(LNN_LANE, "get lock fail");
121 return SOFTBUS_LOCK_ERR;
122 }
123 CtrlReqInfo *item = NULL;
124 LIST_FOR_EACH_ENTRY(item, &g_ctrlReqList->list, CtrlReqInfo, node) {
125 if (item->laneHandle == laneHandle) {
126 if (memcpy_s(reqInfo, sizeof(CtrlReqInfo), item, sizeof(CtrlReqInfo)) != EOK) {
127 LNN_LOGE(LNN_LANE, "memcpy CtrlReqInfo fail");
128 Unlock();
129 return SOFTBUS_MEM_ERR;
130 }
131 Unlock();
132 return SOFTBUS_OK;
133 }
134 }
135 Unlock();
136 return SOFTBUS_LANE_NOT_FOUND;
137 }
138
DeleteCtrlRequestNode(uint32_t laneHandle)139 static void DeleteCtrlRequestNode(uint32_t laneHandle)
140 {
141 if (Lock() != SOFTBUS_OK) {
142 LNN_LOGE(LNN_LANE, "get lock fail");
143 return;
144 }
145 CtrlReqInfo *item = NULL;
146 CtrlReqInfo *next = NULL;
147 LIST_FOR_EACH_ENTRY_SAFE(item, next, &g_ctrlReqList->list, CtrlReqInfo, node) {
148 if (item->laneHandle == laneHandle) {
149 ListDelete(&item->node);
150 SoftBusFree(item);
151 g_ctrlReqList->cnt--;
152 break;
153 }
154 }
155 Unlock();
156 }
157
CtrlLinkFail(uint32_t laneHandle,int32_t reason,LaneLinkType linkType)158 static void CtrlLinkFail(uint32_t laneHandle, int32_t reason, LaneLinkType linkType)
159 {
160 (void)linkType;
161 CtrlReqInfo reqInfo;
162 (void)memset_s(&reqInfo, sizeof(CtrlReqInfo), 0, sizeof(CtrlReqInfo));
163 if (GetCtrlReqInfo(laneHandle, &reqInfo) != SOFTBUS_OK) {
164 LNN_LOGE(LNN_LANE, "get lane reqInfo fail");
165 return;
166 }
167 if (reqInfo.linkListIdx >= reqInfo.linkList.linkTypeNum) {
168 reqInfo.listener.onLaneAllocFail(laneHandle, reason);
169 FreeLaneReqId(laneHandle);
170 DeleteCtrlRequestNode(laneHandle);
171 return;
172 }
173 CtrlTriggerLink(laneHandle);
174 }
175
UpdateCtrlReqInfo(uint32_t laneHandle,uint64_t laneId)176 static void UpdateCtrlReqInfo(uint32_t laneHandle, uint64_t laneId)
177 {
178 if (Lock() != SOFTBUS_OK) {
179 LNN_LOGE(LNN_LANE, "get lock fail");
180 return;
181 }
182 CtrlReqInfo *item = NULL;
183 LIST_FOR_EACH_ENTRY(item, &g_ctrlReqList->list, CtrlReqInfo, node) {
184 if (item->laneHandle == laneHandle) {
185 item->laneId = laneId;
186 Unlock();
187 return;
188 }
189 }
190 Unlock();
191 }
192
CtrlNotifyLaneAllocSuccess(uint32_t laneHandle,uint64_t laneId,const LaneLinkInfo * info)193 static void CtrlNotifyLaneAllocSuccess(uint32_t laneHandle, uint64_t laneId, const LaneLinkInfo *info)
194 {
195 UpdateCtrlReqInfo(laneHandle, laneId);
196 CtrlReqInfo reqInfo;
197 (void)memset_s(&reqInfo, sizeof(CtrlReqInfo), 0, sizeof(CtrlReqInfo));
198 if (GetCtrlReqInfo(laneHandle, &reqInfo) != SOFTBUS_OK) {
199 LNN_LOGE(LNN_LANE, "get lane reqInfo fail");
200 return;
201 }
202
203 LaneProfile profile;
204 LaneConnInfo connInfo;
205 (void)memset_s(&profile, sizeof(LaneProfile), 0, sizeof(LaneProfile));
206 if (LaneInfoProcess(info, &connInfo, &profile) != SOFTBUS_OK) {
207 LNN_LOGE(LNN_LANE, "lane alloc success, but laneInfo proc fail");
208 return;
209 }
210 LNN_LOGI(LNN_LANE, "ctrl notify laneAlloc succ, laneHandle=%{public}u, linkType=%{public}d, "
211 "laneId=%{public}" PRIu64 "", laneHandle, info->type, laneId);
212 connInfo.laneId = laneId;
213 reqInfo.listener.onLaneAllocSuccess(laneHandle, &connInfo);
214 }
215
CtrlLinkSuccess(uint32_t laneHandle,LaneLinkType linkType,const LaneLinkInfo * linkInfo)216 static void CtrlLinkSuccess(uint32_t laneHandle, LaneLinkType linkType, const LaneLinkInfo *linkInfo)
217 {
218 if (linkInfo == NULL) {
219 LNN_LOGE(LNN_LANE, "linkSuccess param invalid");
220 return;
221 }
222 char localUdid[UDID_BUF_LEN] = {0};
223 if (LnnGetLocalStrInfo(STRING_KEY_DEV_UDID, localUdid, UDID_BUF_LEN) != SOFTBUS_OK) {
224 LNN_LOGE(LNN_LANE, "get udid fail, laneHandle=%{public}u", laneHandle);
225 CtrlLinkFail(laneHandle, SOFTBUS_LANE_GET_LEDGER_INFO_ERR, linkType);
226 return;
227 }
228 uint64_t laneId = GenerateLaneId(localUdid, linkInfo->peerUdid, linkInfo->type);
229 if (laneId == INVALID_LANE_ID) {
230 LNN_LOGE(LNN_LANE, "generate laneId fail, laneHandle=%{public}u", laneHandle);
231 CtrlLinkFail(laneHandle, SOFTBUS_LANE_ID_GENERATE_FAIL, linkType);
232 return;
233 }
234 int32_t ret = AddLaneResourceToPool(linkInfo, laneId, false);
235 if (ret != SOFTBUS_OK) {
236 LNN_LOGE(LNN_LANE, "add linkInfo item fail, laneHandle=%{public}u", laneHandle);
237 CtrlLinkFail(laneHandle, ret, linkType);
238 return;
239 }
240 CtrlNotifyLaneAllocSuccess(laneHandle, laneId, linkInfo);
241 }
242
CreateLinkRequestNode(const LaneAllocInfo * allocInfo,LinkRequest * requestInfo)243 static int32_t CreateLinkRequestNode(const LaneAllocInfo *allocInfo, LinkRequest *requestInfo)
244 {
245 requestInfo->networkDelegate = allocInfo->extendInfo.networkDelegate;
246 requestInfo->pid = allocInfo->pid;
247 requestInfo->acceptableProtocols = allocInfo->acceptableProtocols;
248 requestInfo->transType = allocInfo->transType;
249 if (memcpy_s(requestInfo->peerNetworkId, NETWORK_ID_BUF_LEN,
250 allocInfo->networkId, NETWORK_ID_BUF_LEN) != EOK) {
251 LNN_LOGE(LNN_LANE, "memcpy networkId fail");
252 return SOFTBUS_MEM_ERR;
253 }
254 if (memcpy_s(requestInfo->peerBleMac, MAX_MAC_LEN, allocInfo->extendInfo.peerBleMac, MAX_MAC_LEN) != EOK) {
255 LNN_LOGE(LNN_LANE, "memcpy peerBleMac fail");
256 return SOFTBUS_MEM_ERR;
257 }
258 return SOFTBUS_OK;
259 }
260
CreateCtrlReqNode(uint32_t laneHandle,const LaneAllocInfo * allocInfo,const LaneAllocListener * listener,LanePreferredLinkList * recommendLinkList)261 static int32_t CreateCtrlReqNode(uint32_t laneHandle, const LaneAllocInfo *allocInfo,
262 const LaneAllocListener *listener, LanePreferredLinkList *recommendLinkList)
263 {
264 CtrlReqInfo *newNode = (CtrlReqInfo *)SoftBusCalloc(sizeof(CtrlReqInfo));
265 if (newNode == NULL) {
266 LNN_LOGE(LNN_LANE, "malloc fail");
267 return SOFTBUS_MALLOC_ERR;
268 }
269 if (memcpy_s(&newNode->allocInfo, sizeof(LaneAllocInfo), allocInfo, sizeof(LaneAllocInfo)) != EOK ||
270 memcpy_s(&newNode->listener, sizeof(LaneAllocListener), listener, sizeof(LaneAllocListener)) != EOK ||
271 memcpy_s(&newNode->linkList, sizeof(LanePreferredLinkList), recommendLinkList,
272 sizeof(LanePreferredLinkList)) != EOK) {
273 LNN_LOGE(LNN_LANE, "memcpy fail for lane alloc listener");
274 SoftBusFree(newNode);
275 return SOFTBUS_MEM_ERR;
276 }
277 newNode->laneHandle = laneHandle;
278 newNode->linkListIdx = 0;
279 ListInit(&newNode->node);
280 if (Lock() != SOFTBUS_OK) {
281 LNN_LOGE(LNN_LANE, "get lock fail");
282 SoftBusFree(newNode);
283 return SOFTBUS_LOCK_ERR;
284 }
285 ListTailInsert(&g_ctrlReqList->list, &newNode->node);
286 g_ctrlReqList->cnt++;
287 Unlock();
288 return SOFTBUS_OK;
289 }
290
GetCtrlReqInfoWithoutLock(uint32_t laneHandle)291 static CtrlReqInfo *GetCtrlReqInfoWithoutLock(uint32_t laneHandle)
292 {
293 CtrlReqInfo *item = NULL;
294 LIST_FOR_EACH_ENTRY(item, &g_ctrlReqList->list, CtrlReqInfo, node) {
295 if (item->laneHandle == laneHandle) {
296 return item;
297 }
298 }
299 return NULL;
300 }
301
CtrlTriggerLink(uint32_t laneHandle)302 static int32_t CtrlTriggerLink(uint32_t laneHandle)
303 {
304 if (Lock() != SOFTBUS_OK) {
305 LNN_LOGE(LNN_LANE, "get lock fail");
306 return SOFTBUS_LOCK_ERR;
307 }
308 CtrlReqInfo *reqInfo = GetCtrlReqInfoWithoutLock(laneHandle);
309 if (reqInfo == NULL) {
310 LNN_LOGE(LNN_LANE, "get lane reqInfo fail");
311 Unlock();
312 return SOFTBUS_LANE_NOT_FOUND;
313 }
314 LaneLinkCb linkCb = {
315 .onLaneLinkSuccess = CtrlLinkSuccess,
316 .onLaneLinkFail = CtrlLinkFail,
317 };
318 LinkRequest requestInfo = {0};
319 int32_t ret = SOFTBUS_LANE_TRIGGER_LINK_FAIL;
320 do {
321 ret = CreateLinkRequestNode(&reqInfo->allocInfo, &requestInfo);
322 if (ret != SOFTBUS_OK) {
323 Unlock();
324 LNN_LOGE(LNN_LANE, "Create LinkRequestNode fail.");
325 break;
326 }
327 requestInfo.linkType = reqInfo->linkList.linkType[reqInfo->linkListIdx];
328 reqInfo->linkListIdx++;
329 Unlock();
330 ret = BuildLink(&requestInfo, laneHandle, &linkCb);
331 if (ret == SOFTBUS_OK) {
332 return SOFTBUS_OK;
333 }
334 } while (false);
335 linkCb.onLaneLinkFail(laneHandle, ret, requestInfo.linkType);
336 return ret;
337 }
338
AllocCtrlLane(uint32_t laneHandle,const LaneAllocInfo * allocInfo,const LaneAllocListener * listener)339 static int32_t AllocCtrlLane(uint32_t laneHandle, const LaneAllocInfo *allocInfo, const LaneAllocListener *listener)
340 {
341 AuthLinkTypeList authList;
342 if (memset_s(&authList, sizeof(AuthLinkTypeList), 0, sizeof(AuthLinkTypeList)) != EOK) {
343 return SOFTBUS_MEM_ERR;
344 }
345 int32_t ret = GetAuthLinkTypeList(allocInfo->networkId, &authList);
346 if (ret != SOFTBUS_OK) {
347 LNN_LOGE(LNN_LANE, "get authList fail");
348 return ret;
349 }
350 LanePreferredLinkList request;
351 if (memset_s(&request, sizeof(LanePreferredLinkList), 0, sizeof(LanePreferredLinkList)) != EOK) {
352 LNN_LOGE(LNN_LANE, "memset_s request fail");
353 return SOFTBUS_MEM_ERR;
354 }
355 ret = ConvertAuthLinkToLaneLink(&authList, &request);
356 if (ret != SOFTBUS_OK) {
357 LNN_LOGE(LNN_LANE, "convert authLink to laneLink fail");
358 return ret;
359 }
360 LanePreferredLinkList *recommendLinkList = (LanePreferredLinkList *)SoftBusCalloc(sizeof(LanePreferredLinkList));
361 if (recommendLinkList == NULL) {
362 LNN_LOGE(LNN_LANE, "calloc recommendLinkList fail");
363 return SOFTBUS_MALLOC_ERR;
364 }
365 recommendLinkList->linkTypeNum = 0;
366 ret = SelectAuthLane(allocInfo->networkId, &request, recommendLinkList);
367 if (ret != SOFTBUS_OK) {
368 SoftBusFree(recommendLinkList);
369 LNN_LOGE(LNN_LANE, "select auth lane fail, laneHandle=%{public}u", laneHandle);
370 return ret;
371 }
372 for (uint32_t i = 0; i < recommendLinkList->linkTypeNum; ++i) {
373 LNN_LOGI(LNN_LANE, "auth expect recommendLinkList nums=%{public}u, priority=%{public}u, link=%{public}u",
374 recommendLinkList->linkTypeNum, i, recommendLinkList->linkType[i]);
375 }
376 if (CreateCtrlReqNode(laneHandle, allocInfo, listener, recommendLinkList) != SOFTBUS_OK) {
377 SoftBusFree(recommendLinkList);
378 LNN_LOGE(LNN_LANE, "create ctrlReqInfo node fail.");
379 return SOFTBUS_LANE_LIST_ERR;
380 }
381 ret = CtrlTriggerLink(laneHandle);
382 if (ret != SOFTBUS_OK) {
383 SoftBusFree(recommendLinkList);
384 DeleteCtrlRequestNode(laneHandle);
385 LNN_LOGE(LNN_LANE, "trigger link fail, laneHandle=%{public}u", laneHandle);
386 return ret;
387 }
388 return SOFTBUS_OK;
389 }
390
CtrlAlloc(uint32_t laneHandle,const LaneAllocInfo * allocInfo,const LaneAllocListener * listener)391 static int32_t CtrlAlloc(uint32_t laneHandle, const LaneAllocInfo *allocInfo, const LaneAllocListener *listener)
392 {
393 if (laneHandle == INVALID_LANE_REQ_ID || allocInfo == NULL || allocInfo->type != LANE_TYPE_CTRL) {
394 LNN_LOGE(LNN_LANE, "param invalid");
395 return SOFTBUS_INVALID_PARAM;
396 }
397 int32_t ret = AllocCtrlLane(laneHandle, allocInfo, listener);
398 if (ret != SOFTBUS_OK) {
399 LNN_LOGE(LNN_LANE, "alloc valid lane fail, laneHandle=%{public}u", laneHandle);
400 FreeLaneReqId(laneHandle);
401 return ret;
402 }
403 return SOFTBUS_OK;
404 }
405
CtrlInit(const ILaneIdStateListener * listener)406 static void CtrlInit(const ILaneIdStateListener *listener)
407 {
408 if (g_ctrlReqList != NULL) {
409 LNN_LOGW(LNN_LANE, "already init");
410 return;
411 }
412 if (SoftBusMutexInit(&g_ctrlLaneMutex, NULL) != SOFTBUS_OK) {
413 LNN_LOGE(LNN_LANE, "ctrlLane mutex init fail");
414 return;
415 }
416 g_ctrlReqList = (CtrlLaneList *)SoftBusCalloc(sizeof(CtrlLaneList));
417 if (g_ctrlReqList == NULL) {
418 LNN_LOGE(LNN_LANE, "ctrlLane malloc fail");
419 (void)SoftBusMutexDestroy(&g_ctrlLaneMutex);
420 return;
421 }
422 ListInit(&g_ctrlReqList->list);
423 }
424
CtrlDeinit(void)425 static void CtrlDeinit(void)
426 {
427 if (g_ctrlReqList == NULL) {
428 return;
429 }
430 if (Lock() != SOFTBUS_OK) {
431 LNN_LOGE(LNN_LANE, "get lock fail");
432 return;
433 }
434 CtrlReqInfo *item = NULL;
435 CtrlReqInfo *nextItem = NULL;
436 LIST_FOR_EACH_ENTRY_SAFE(item, nextItem, &g_ctrlReqList->list, CtrlReqInfo, node) {
437 ListDelete(&item->node);
438 SoftBusFree(item);
439 g_ctrlReqList->cnt--;
440 }
441 Unlock();
442 (void)SoftBusMutexDestroy(&g_ctrlLaneMutex);
443 SoftBusFree(g_ctrlReqList);
444 g_ctrlReqList = NULL;
445 }
446
FreeLaneLink(uint32_t laneHandle,uint64_t laneId)447 static int32_t FreeLaneLink(uint32_t laneHandle, uint64_t laneId)
448 {
449 LaneResource resourceItem;
450 (void)memset_s(&resourceItem, sizeof(LaneResource), 0, sizeof(LaneResource));
451 if (FindLaneResourceByLaneId(laneId, &resourceItem) != SOFTBUS_OK) {
452 return SOFTBUS_LANE_RESOURCE_NOT_FOUND;
453 }
454 char networkId[NETWORK_ID_BUF_LEN] = { 0 };
455 if (LnnGetNetworkIdByUdid(resourceItem.link.peerUdid, networkId, sizeof(networkId)) != SOFTBUS_OK) {
456 return SOFTBUS_LANE_GET_LEDGER_INFO_ERR;
457 }
458 DestroyLink(networkId, laneHandle, resourceItem.link.type);
459 DelLaneResourceByLaneId(laneId, false);
460 return SOFTBUS_OK;
461 }
462
CtrlFree(uint32_t laneHandle)463 static int32_t CtrlFree(uint32_t laneHandle)
464 {
465 if (Lock() != SOFTBUS_OK) {
466 LNN_LOGE(LNN_LANE, "get lock fail");
467 return SOFTBUS_LOCK_ERR;
468 }
469 CtrlReqInfo *item = NULL;
470 CtrlReqInfo *next = NULL;
471 LIST_FOR_EACH_ENTRY_SAFE(item, next, &g_ctrlReqList->list, CtrlReqInfo, node) {
472 if (item->laneHandle == laneHandle) {
473 ListDelete(&item->node);
474 g_ctrlReqList->cnt--;
475 Unlock();
476 FreeLaneLink(laneHandle, item->laneId);
477 SoftBusFree(item);
478 FreeLaneReqId(laneHandle);
479 return SOFTBUS_OK;
480 }
481 }
482 Unlock();
483 LNN_LOGI(LNN_LANE, "no find lane need free, laneHandle=%{public}u", laneHandle);
484 FreeLaneReqId(laneHandle);
485 return SOFTBUS_OK;
486 }
487
488 static LaneInterface g_ctrlLaneObject = {
489 .init = CtrlInit,
490 .allocLaneByQos = CtrlAlloc,
491 .freeLane = CtrlFree,
492 .deinit = CtrlDeinit,
493 };
494
CtrlLaneGetInstance(void)495 LaneInterface *CtrlLaneGetInstance(void)
496 {
497 return &g_ctrlLaneObject;
498 }