1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "lnn_linkwatch.h"
17
18 #ifndef _GNU_SOURCE
19 #define _GNU_SOURCE
20 #endif
21
22 #ifndef __MUSL__
23 #define __MUSL__
24 #endif
25
26 #include <securec.h>
27 #include <time.h>
28 #include <unistd.h>
29 #include <linux/netlink.h>
30 #include <linux/rtnetlink.h>
31
32 #include "softbus_adapter_errcode.h"
33 #include "softbus_adapter_socket.h"
34 #include "softbus_errcode.h"
35 #include "softbus_log.h"
36
37
38 #define NETLINK_BUF_LEN 1024
39
AddAttr(struct nlmsghdr * nlMsgHdr,uint32_t maxLen,int32_t type,const uint8_t * data,uint32_t attrLen)40 static int32_t AddAttr(struct nlmsghdr *nlMsgHdr, uint32_t maxLen, int32_t type,
41 const uint8_t *data, uint32_t attrLen)
42 {
43 int32_t len = RTA_LENGTH(attrLen);
44 struct rtattr *rta = NULL;
45
46 if (NLMSG_ALIGN(nlMsgHdr->nlmsg_len) + RTA_ALIGN(len) > maxLen) {
47 SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "AddAttr ERROR: message exceeded bound of %d\n", maxLen);
48 return SOFTBUS_ERR;
49 }
50 rta = ((struct rtattr *) (((uint8_t *) (nlMsgHdr)) + NLMSG_ALIGN((nlMsgHdr)->nlmsg_len)));
51 rta->rta_type = (uint16_t)type;
52 rta->rta_len = (uint16_t)len;
53 if (memcpy_s(RTA_DATA(rta), rta->rta_len, data, attrLen) != EOK) {
54 SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "AddAttr ERROR: memcpy attr failed");
55 return SOFTBUS_MEM_ERR;
56 }
57 nlMsgHdr->nlmsg_len = NLMSG_ALIGN(nlMsgHdr->nlmsg_len) + RTA_ALIGN(len);
58 return SOFTBUS_OK;
59 }
60
ProcessNetlinkAnswer(struct nlmsghdr * answer,int32_t bufLen,uint32_t seq)61 static int32_t ProcessNetlinkAnswer(struct nlmsghdr *answer, int32_t bufLen, uint32_t seq)
62 {
63 struct nlmsghdr *hdr = NULL;
64 uint32_t len;
65 int32_t remain = bufLen;
66
67 for (hdr = (struct nlmsghdr *)answer; remain >= (int32_t)sizeof(*hdr);) {
68 len = hdr->nlmsg_len;
69 if ((hdr->nlmsg_len - sizeof(*hdr)) < 0 || len > (uint32_t)remain) {
70 SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "malformed message: len=%d", len);
71 return SOFTBUS_ERR;
72 }
73 if (hdr->nlmsg_seq != seq) {
74 // skip that message
75 remain -= NLMSG_ALIGN(len);
76 hdr = (struct nlmsghdr *)((char *)hdr + NLMSG_ALIGN(len));
77 continue;
78 }
79 if (hdr->nlmsg_type == NLMSG_ERROR) {
80 SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "ERROR netlink msg");
81 return SOFTBUS_ERR;
82 }
83 return SOFTBUS_OK;
84 }
85 return SOFTBUS_ERR;
86 }
87
RtNetlinkTalk(struct nlmsghdr * nlMsgHdr,struct nlmsghdr * answer,uint32_t maxlen)88 static int32_t RtNetlinkTalk(struct nlmsghdr *nlMsgHdr, struct nlmsghdr *answer, uint32_t maxlen)
89 {
90 int32_t status;
91 int32_t fd;
92
93 int32_t ret = SoftBusSocketCreate(SOFTBUS_AF_NETLINK, SOFTBUS_SOCK_RAW, NETLINK_ROUTE, &fd);
94 if (ret != SOFTBUS_ADAPTER_OK) {
95 SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "netlink_socket failed");
96 return SOFTBUS_ERR;
97 }
98
99 status = SoftBusSocketSend(fd, nlMsgHdr, nlMsgHdr->nlmsg_len, 0);
100 if (status != (int32_t)(nlMsgHdr->nlmsg_len)) {
101 SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "Cannot talk to rtnetlink");
102 SoftBusSocketClose(fd);
103 return SOFTBUS_ERR;
104 }
105
106 while (true) {
107 status = SoftBusSocketRecv(fd, answer, maxlen, 0);
108 if (status < 0) {
109 if (status == SOFTBUS_ADAPTER_SOCKET_EINTR || status == SOFTBUS_ADAPTER_SOCKET_EAGAIN) {
110 continue;
111 }
112 SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "netlink receive error (%d)", status);
113 SoftBusSocketClose(fd);
114 return SOFTBUS_ERR;
115 }
116 if (status == 0) {
117 SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "EOF on netlink\n");
118 SoftBusSocketClose(fd);
119 return SOFTBUS_ERR;
120 }
121 SoftBusSocketClose(fd);
122 return ProcessNetlinkAnswer(answer, status, nlMsgHdr->nlmsg_seq);
123 }
124 }
125
GetRtAttr(struct rtattr * rta,int32_t len,uint16_t type,uint8_t * value,uint32_t valueLen)126 static int32_t GetRtAttr(struct rtattr *rta, int32_t len, uint16_t type, uint8_t *value, uint32_t valueLen)
127 {
128 struct rtattr *attr = rta;
129 while (RTA_OK(attr, len)) {
130 if (attr->rta_type != type) {
131 attr = RTA_NEXT(attr, len);
132 continue;
133 }
134 if (memcpy_s(value, valueLen, RTA_DATA(attr), (uint32_t)RTA_PAYLOAD(attr)) != EOK) {
135 SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "get attr fail: %d, %d",
136 valueLen, RTA_PAYLOAD(attr));
137 break;
138 }
139 return SOFTBUS_OK;
140 }
141 return SOFTBUS_ERR;
142 }
143
LnnIsLinkReady(const char * iface)144 bool LnnIsLinkReady(const char *iface)
145 {
146 if (iface == NULL) {
147 return false;
148 }
149 struct ifinfomsg *info = NULL;
150 struct {
151 struct nlmsghdr hdr;
152 struct ifinfomsg info;
153 char buf[NETLINK_BUF_LEN];
154 } req = {
155 .hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
156 .hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
157 .hdr.nlmsg_type = RTM_GETLINK,
158 .info.ifi_family = SOFTBUS_PF_UNSPEC,
159 };
160 struct {
161 struct nlmsghdr hdr;
162 char buf[NETLINK_BUF_LEN + NETLINK_BUF_LEN];
163 } answer;
164 int32_t infoDataLen, seq;
165 uint8_t carrier;
166
167 seq = time(NULL);
168 if (seq < 0) {
169 seq = 0;
170 }
171 req.hdr.nlmsg_seq = ++seq;
172 (void)memset_s(&answer, sizeof(answer), 0, sizeof(answer));
173 if (AddAttr(&req.hdr, sizeof(req), IFLA_IFNAME, (const uint8_t *)iface, strlen(iface) + 1) != SOFTBUS_OK) {
174 return false;
175 }
176 if (RtNetlinkTalk(&req.hdr, &answer.hdr, sizeof(answer)) != SOFTBUS_OK) {
177 return false;
178 }
179 info = NLMSG_DATA(&answer.hdr);
180 infoDataLen = (int32_t)answer.hdr.nlmsg_len - NLMSG_LENGTH(sizeof(struct ifinfomsg));
181 if (GetRtAttr(IFLA_RTA(info), infoDataLen, IFLA_CARRIER, &carrier, sizeof(uint8_t)) != SOFTBUS_OK) {
182 return false;
183 }
184 SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_INFO, "carrier result: %d\n", carrier);
185 return carrier != 0;
186 }