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 <linux/netlink.h>
29 #include <linux/rtnetlink.h>
30
31 #include "lnn_log.h"
32 #include "softbus_adapter_errcode.h"
33 #include "softbus_adapter_socket.h"
34 #include "softbus_def.h"
35 #include "softbus_errcode.h"
36
37 #define NETLINK_BUF_LEN 1024
38
AddAttr(struct nlmsghdr * nlMsgHdr,uint32_t maxLen,uint16_t type,const uint8_t * data,uint16_t attrLen)39 static int32_t AddAttr(struct nlmsghdr *nlMsgHdr, uint32_t maxLen, uint16_t type,
40 const uint8_t *data, uint16_t attrLen)
41 {
42 uint16_t len = RTA_LENGTH(attrLen);
43 struct rtattr *rta = NULL;
44
45 if (NLMSG_ALIGN(nlMsgHdr->nlmsg_len) + RTA_ALIGN(len) > maxLen) {
46 LNN_LOGE(LNN_BUILDER, "message exceeded bound. maxLen=%{public}d", maxLen);
47 return SOFTBUS_ERR;
48 }
49 rta = ((struct rtattr *) (((uint8_t *) (nlMsgHdr)) + NLMSG_ALIGN((nlMsgHdr)->nlmsg_len)));
50 rta->rta_type = type;
51 rta->rta_len = len;
52 if (memcpy_s(RTA_DATA(rta), rta->rta_len, data, attrLen) != EOK) {
53 LNN_LOGE(LNN_BUILDER, "memcpy attr failed");
54 return SOFTBUS_MEM_ERR;
55 }
56 nlMsgHdr->nlmsg_len = NLMSG_ALIGN(nlMsgHdr->nlmsg_len) + RTA_ALIGN(len);
57 return SOFTBUS_OK;
58 }
59
ProcessNetlinkAnswer(struct nlmsghdr * answer,int32_t bufLen,uint32_t seq)60 static int32_t ProcessNetlinkAnswer(struct nlmsghdr *answer, int32_t bufLen, uint32_t seq)
61 {
62 struct nlmsghdr *hdr = NULL;
63 uint32_t len;
64 int32_t remain = bufLen;
65
66 for (hdr = (struct nlmsghdr *)answer; remain >= (int32_t)sizeof(*hdr);) {
67 len = hdr->nlmsg_len;
68 if ((hdr->nlmsg_len - sizeof(*hdr)) < 0 || len > (uint32_t)remain) {
69 LNN_LOGE(LNN_BUILDER, "malformed message: len=%{public}d", len);
70 return SOFTBUS_ERR;
71 }
72 if (hdr->nlmsg_seq != seq) {
73 // skip that message
74 remain -= NLMSG_ALIGN(len);
75 hdr = (struct nlmsghdr *)((char *)hdr + NLMSG_ALIGN(len));
76 continue;
77 }
78 if (hdr->nlmsg_type == NLMSG_ERROR) {
79 LNN_LOGE(LNN_BUILDER, "netlink msg err");
80 return SOFTBUS_ERR;
81 }
82 return SOFTBUS_OK;
83 }
84 return SOFTBUS_ERR;
85 }
86
RtNetlinkTalk(struct nlmsghdr * nlMsgHdr,struct nlmsghdr * answer,uint32_t maxlen)87 static int32_t RtNetlinkTalk(struct nlmsghdr *nlMsgHdr, struct nlmsghdr *answer, uint32_t maxlen)
88 {
89 int32_t status;
90 int32_t fd;
91
92 int32_t ret = SoftBusSocketCreate(SOFTBUS_AF_NETLINK, SOFTBUS_SOCK_RAW, NETLINK_ROUTE, &fd);
93 if (ret != SOFTBUS_ADAPTER_OK) {
94 LNN_LOGE(LNN_BUILDER, "netlink_socket failed");
95 return SOFTBUS_ERR;
96 }
97
98 status = SoftBusSocketSend(fd, nlMsgHdr, nlMsgHdr->nlmsg_len, 0);
99 if (status != (int32_t)(nlMsgHdr->nlmsg_len)) {
100 LNN_LOGE(LNN_BUILDER, "Cannot talk to rtnetlink");
101 SoftBusSocketClose(fd);
102 return SOFTBUS_ERR;
103 }
104
105 while (true) {
106 LNN_LOGI(LNN_BUILDER, "SoftBusSocketRecv begin");
107 status = SoftBusSocketRecv(fd, answer, maxlen, 0);
108 LNN_LOGI(LNN_BUILDER, "SoftBusSocketRecv end");
109 if (status < 0) {
110 if (status == SOFTBUS_ADAPTER_SOCKET_EINTR || status == SOFTBUS_ADAPTER_SOCKET_EAGAIN) {
111 continue;
112 }
113 LNN_LOGE(LNN_BUILDER, "netlink receive error, status=%{public}d", status);
114 SoftBusSocketClose(fd);
115 return SOFTBUS_ERR;
116 }
117 if (status == 0) {
118 LNN_LOGE(LNN_BUILDER, "EOF on netlink");
119 SoftBusSocketClose(fd);
120 return SOFTBUS_ERR;
121 }
122 SoftBusSocketClose(fd);
123 return ProcessNetlinkAnswer(answer, status, nlMsgHdr->nlmsg_seq);
124 }
125 }
126
GetRtAttr(struct rtattr * rta,int32_t len,uint16_t type,uint8_t * value,uint32_t valueLen)127 static int32_t GetRtAttr(struct rtattr *rta, int32_t len, uint16_t type, uint8_t *value, uint32_t valueLen)
128 {
129 struct rtattr *attr = rta;
130 while (RTA_OK(attr, len)) {
131 if (attr->rta_type != type) {
132 attr = RTA_NEXT(attr, len);
133 continue;
134 }
135 if (memcpy_s(value, valueLen, RTA_DATA(attr), (uint32_t)RTA_PAYLOAD(attr)) != EOK) {
136 LNN_LOGE(LNN_BUILDER, "get attr fail. valueLen=%{public}d, attr=%{public}u",
137 valueLen, (uint32_t)RTA_PAYLOAD(attr));
138 break;
139 }
140 return SOFTBUS_OK;
141 }
142 return SOFTBUS_ERR;
143 }
144
LnnIsLinkReady(const char * iface)145 bool LnnIsLinkReady(const char *iface)
146 {
147 if (iface == NULL) {
148 return false;
149 }
150 struct ifinfomsg *info = NULL;
151 struct {
152 struct nlmsghdr hdr;
153 struct ifinfomsg info;
154 char buf[NETLINK_BUF_LEN];
155 } req = {
156 .hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
157 .hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
158 .hdr.nlmsg_type = RTM_GETLINK,
159 .info.ifi_family = SOFTBUS_PF_UNSPEC,
160 };
161 struct {
162 struct nlmsghdr hdr;
163 char buf[NETLINK_BUF_LEN + NETLINK_BUF_LEN];
164 } answer;
165 int32_t infoDataLen, seq;
166 uint8_t carrier;
167
168 seq = time(NULL);
169 if (seq < 0) {
170 seq = 0;
171 }
172 req.hdr.nlmsg_seq = ++seq;
173 (void)memset_s(&answer, sizeof(answer), 0, sizeof(answer));
174 uint16_t len = (uint16_t)strlen(iface) + 1;
175 if (AddAttr(&req.hdr, sizeof(req), IFLA_IFNAME, (const uint8_t *)iface, len) != SOFTBUS_OK) {
176 return false;
177 }
178 if (RtNetlinkTalk(&req.hdr, &answer.hdr, sizeof(answer)) != SOFTBUS_OK) {
179 return false;
180 }
181 info = NLMSG_DATA(&answer.hdr);
182 infoDataLen = (int32_t)answer.hdr.nlmsg_len - NLMSG_LENGTH(sizeof(struct ifinfomsg));
183 if (GetRtAttr(IFLA_RTA(info), infoDataLen, IFLA_CARRIER, &carrier, sizeof(uint8_t)) != SOFTBUS_OK) {
184 return false;
185 }
186 return carrier != 0;
187 }