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,int32_t type,const uint8_t * data,uint32_t attrLen)39 static int32_t AddAttr(struct nlmsghdr *nlMsgHdr, uint32_t maxLen, int32_t type,
40 const uint8_t *data, uint32_t attrLen)
41 {
42 int32_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 = (uint16_t)type;
51 rta->rta_len = (uint16_t)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 status = SoftBusSocketRecv(fd, answer, maxlen, 0);
107 if (status < 0) {
108 if (status == SOFTBUS_ADAPTER_SOCKET_EINTR || status == SOFTBUS_ADAPTER_SOCKET_EAGAIN) {
109 continue;
110 }
111 LNN_LOGE(LNN_BUILDER, "netlink receive error, status=%{public}d", status);
112 SoftBusSocketClose(fd);
113 return SOFTBUS_ERR;
114 }
115 if (status == 0) {
116 LNN_LOGE(LNN_BUILDER, "EOF on netlink");
117 SoftBusSocketClose(fd);
118 return SOFTBUS_ERR;
119 }
120 SoftBusSocketClose(fd);
121 return ProcessNetlinkAnswer(answer, status, nlMsgHdr->nlmsg_seq);
122 }
123 }
124
GetRtAttr(struct rtattr * rta,int32_t len,uint16_t type,uint8_t * value,uint32_t valueLen)125 static int32_t GetRtAttr(struct rtattr *rta, int32_t len, uint16_t type, uint8_t *value, uint32_t valueLen)
126 {
127 struct rtattr *attr = rta;
128 while (RTA_OK(attr, len)) {
129 if (attr->rta_type != type) {
130 attr = RTA_NEXT(attr, len);
131 continue;
132 }
133 if (memcpy_s(value, valueLen, RTA_DATA(attr), (uint32_t)RTA_PAYLOAD(attr)) != EOK) {
134 LNN_LOGE(LNN_BUILDER, "get attr fail. valueLen=%{public}d, attr=%{public}u",
135 valueLen, (uint32_t)RTA_PAYLOAD(attr));
136 break;
137 }
138 return SOFTBUS_OK;
139 }
140 return SOFTBUS_ERR;
141 }
142
LnnIsLinkReady(const char * iface)143 bool LnnIsLinkReady(const char *iface)
144 {
145 if (iface == NULL) {
146 return false;
147 }
148 struct ifinfomsg *info = NULL;
149 struct {
150 struct nlmsghdr hdr;
151 struct ifinfomsg info;
152 char buf[NETLINK_BUF_LEN];
153 } req = {
154 .hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
155 .hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
156 .hdr.nlmsg_type = RTM_GETLINK,
157 .info.ifi_family = SOFTBUS_PF_UNSPEC,
158 };
159 struct {
160 struct nlmsghdr hdr;
161 char buf[NETLINK_BUF_LEN + NETLINK_BUF_LEN];
162 } answer;
163 int32_t infoDataLen, seq;
164 uint8_t carrier;
165
166 seq = time(NULL);
167 if (seq < 0) {
168 seq = 0;
169 }
170 req.hdr.nlmsg_seq = ++seq;
171 (void)memset_s(&answer, sizeof(answer), 0, sizeof(answer));
172 if (AddAttr(&req.hdr, sizeof(req), IFLA_IFNAME, (const uint8_t *)iface, strlen(iface) + 1) != SOFTBUS_OK) {
173 return false;
174 }
175 if (RtNetlinkTalk(&req.hdr, &answer.hdr, sizeof(answer)) != SOFTBUS_OK) {
176 return false;
177 }
178 info = NLMSG_DATA(&answer.hdr);
179 infoDataLen = (int32_t)answer.hdr.nlmsg_len - NLMSG_LENGTH(sizeof(struct ifinfomsg));
180 if (GetRtAttr(IFLA_RTA(info), infoDataLen, IFLA_CARRIER, &carrier, sizeof(uint8_t)) != SOFTBUS_OK) {
181 return false;
182 }
183 return carrier != 0;
184 }