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 }