• 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_event_monitor_impl.h"
17 
18 #ifndef _GNU_SOURCE
19 #define _GNU_SOURCE
20 #endif
21 
22 #ifndef __MUSL__
23 #define __MUSL__
24 #endif
25 
26 #include <arpa/inet.h>
27 #include <linux/netlink.h>
28 #include <linux/rtnetlink.h>
29 #include <net/if.h>
30 #include <sys/ioctl.h>
31 
32 #include "bus_center_event.h"
33 #include "lnn_network_manager.h"
34 #include "securec.h"
35 #include "softbus_adapter_errcode.h"
36 #include "softbus_adapter_mem.h"
37 #include "softbus_adapter_socket.h"
38 #include "softbus_adapter_thread.h"
39 #include "softbus_def.h"
40 #include "softbus_errcode.h"
41 #include "softbus_log.h"
42 
43 #undef NLMSG_OK
44 #define NLMSG_OK(nlh, len)                                                                               \
45     (((len) >= (int32_t)(sizeof(struct nlmsghdr))) && (((nlh)->nlmsg_len) >= sizeof(struct nlmsghdr)) && \
46         ((int32_t)((nlh)->nlmsg_len) <= (len)))
47 
48 #define DEFAULT_NETLINK_RECVBUF (32 * 1024)
49 
CreateNetlinkSocket(void)50 static int32_t CreateNetlinkSocket(void)
51 {
52     int32_t sockFd;
53     struct sockaddr_nl nladdr;
54     int32_t sz = DEFAULT_NETLINK_RECVBUF;
55 
56     int32_t ret = SoftBusSocketCreate(SOFTBUS_PF_NETLINK, SOFTBUS_SOCK_DGRAM | SOFTBUS_SOCK_CLOEXEC,
57         NETLINK_ROUTE, &sockFd);
58     if (ret != SOFTBUS_ADAPTER_OK) {
59         SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "open netlink socket failed");
60         return SOFTBUS_ERR;
61     }
62     if (SoftBusSocketSetOpt(sockFd, SOFTBUS_SOL_SOCKET, SOFTBUS_SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0 &&
63         SoftBusSocketSetOpt(sockFd, SOFTBUS_SOL_SOCKET, SOFTBUS_SO_RCVBUF, &sz, sizeof(sz)) < 0) {
64         SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "set uevent socket SO_RCVBUF option failed");
65         SoftBusSocketClose(sockFd);
66         return SOFTBUS_ERR;
67     }
68     if (memset_s(&nladdr, sizeof(nladdr), 0, sizeof(nladdr)) != EOK) {
69         SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "init sockaddr_nl failed");
70         SoftBusSocketClose(sockFd);
71         return SOFTBUS_ERR;
72     }
73     nladdr.nl_family = SOFTBUS_AF_NETLINK;
74     // Kernel will assign a unique nl_pid if set to zero.
75     nladdr.nl_pid = 0;
76     nladdr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
77     if (SoftBusSocketBind(sockFd, (SoftBusSockAddr *)&nladdr, sizeof(nladdr)) < 0) {
78         SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "bind netlink socket failed");
79         SoftBusSocketClose(sockFd);
80         return SOFTBUS_ERR;
81     }
82     return sockFd;
83 }
84 
ParseRtAttr(struct rtattr ** tb,int max,struct rtattr * attr,int len)85 static void ParseRtAttr(struct rtattr **tb, int max, struct rtattr *attr, int len)
86 {
87     struct rtattr *attr1 = attr;
88     for (; RTA_OK(attr1, len); attr1 = RTA_NEXT(attr1, len)) {
89         if (attr1->rta_type <= max) {
90             tb[attr1->rta_type] = attr1;
91         }
92     }
93 }
94 
ProcessAddrEvent(struct nlmsghdr * nlh)95 static void ProcessAddrEvent(struct nlmsghdr *nlh)
96 {
97     if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg))) {
98         SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "Wrong len");
99         return;
100     }
101     struct ifaddrmsg *ifa = (struct ifaddrmsg *)NLMSG_DATA(nlh);
102     LnnNetIfType type = LNN_NETIF_TYPE_ETH;
103     char ifnameBuffer[NET_IF_NAME_LEN];
104     char *ifName = if_indextoname(ifa->ifa_index, ifnameBuffer);
105     if (ifName == NULL) {
106         SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "invalid iface index");
107         return;
108     }
109     if (LnnGetNetIfTypeByName(ifName, &type) != SOFTBUS_OK) {
110         SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "ProcessAddrEvent LnnGetNetIfTypeByName error");
111         return;
112     }
113     if (type == LNN_NETIF_TYPE_ETH || type == LNN_NETIF_TYPE_WLAN) {
114         SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "network addr changed, type:%d", type);
115         LnnNotifyAddressChangedEvent(ifName);
116     }
117 }
118 
ProcessLinkEvent(struct nlmsghdr * nlh)119 static void ProcessLinkEvent(struct nlmsghdr *nlh)
120 {
121     int len;
122     struct rtattr *tb[IFLA_MAX + 1] = {NULL};
123     struct ifinfomsg *ifinfo = (struct ifinfomsg *)NLMSG_DATA(nlh);
124     LnnNetIfType type = LNN_NETIF_TYPE_ETH;
125 
126     len = (int32_t)nlh->nlmsg_len - NLMSG_SPACE(sizeof(*ifinfo));
127     ParseRtAttr(tb, IFLA_MAX, IFLA_RTA(ifinfo), len);
128 
129     if (tb[IFLA_IFNAME] == NULL) {
130         SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "netlink msg is invalid");
131         return;
132     }
133 
134     if (LnnGetNetIfTypeByName((const char *)RTA_DATA(tb[IFLA_IFNAME]), &type) != SOFTBUS_OK) {
135         SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "ProcessAddrEvent LnnGetNetIfTypeByName error");
136         return;
137     }
138     if (type == LNN_NETIF_TYPE_ETH || type == LNN_NETIF_TYPE_WLAN) {
139         SoftBusLog(
140             SOFTBUS_LOG_LNN, SOFTBUS_LOG_WARN, "%s:link status changed, type:%d", RTA_DATA(tb[IFLA_IFNAME]), type);
141         LnnNotifyAddressChangedEvent((const char *)RTA_DATA(tb[IFLA_IFNAME]));
142     }
143 }
144 
NetlinkMonitorThread(void * para)145 NO_SANITIZE("cfi") static void *NetlinkMonitorThread(void *para)
146 {
147     struct nlmsghdr *nlh = NULL;
148     (void)para;
149     SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_INFO, "netlink monitor thread start");
150     int32_t sockFd = CreateNetlinkSocket();
151     if (sockFd < 0) {
152         SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "create netlink socket failed");
153         return NULL;
154     }
155     uint8_t *buffer = (uint8_t *)SoftBusCalloc(DEFAULT_NETLINK_RECVBUF * sizeof(uint8_t));
156     if (buffer == NULL) {
157         SoftBusSocketClose(sockFd);
158         return NULL;
159     }
160     while (true) {
161         (void)memset_s(buffer, DEFAULT_NETLINK_RECVBUF, 0, DEFAULT_NETLINK_RECVBUF);
162         int32_t len = SoftBusSocketRecv(sockFd, buffer, DEFAULT_NETLINK_RECVBUF, 0);
163         if (len < 0 && len == SOFTBUS_ADAPTER_SOCKET_EINTR) {
164             continue;
165         }
166         if (len < 0) {
167             SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "recv netlink socket error");
168             break;
169         }
170         if (len < (int32_t)sizeof(struct nlmsghdr)) {
171             SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "recv buffer not enough");
172             continue;
173         }
174         nlh = (struct nlmsghdr *)buffer;
175         while (NLMSG_OK(nlh, len) && nlh->nlmsg_type != NLMSG_DONE) {
176             SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_INFO, "nlmsg_type: %d", nlh->nlmsg_type);
177             switch (nlh->nlmsg_type) {
178                 case RTM_NEWADDR:
179                 case RTM_DELADDR:
180                     ProcessAddrEvent(nlh);
181                     break;
182                 case RTM_NEWLINK:
183                 case RTM_DELLINK:
184                     ProcessLinkEvent(nlh);
185                     break;
186                 default:
187                     break;
188             }
189             nlh = NLMSG_NEXT(nlh, len);
190         }
191     }
192     SoftBusSocketClose(sockFd);
193     SoftBusFree(buffer);
194     SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_INFO, "netlink monitor thread exit");
195     return NULL;
196 }
197 
LnnInitNetlinkMonitorImpl(void)198 int32_t LnnInitNetlinkMonitorImpl(void)
199 {
200     SoftBusThread tid;
201     if (SoftBusThreadCreate(&tid, NULL, NetlinkMonitorThread, NULL) != 0) {
202         SoftBusLog(SOFTBUS_LOG_LNN, SOFTBUS_LOG_ERROR, "create ip change monitor thread failed");
203         return SOFTBUS_ERR;
204     }
205     return SOFTBUS_OK;
206 }