• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }