• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) Huawei Device Co., Ltd. 2021-2023  All right reserved.
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 <string.h>
17 #include <stdio.h>
18 #include <arpa/inet.h>
19 #include <net/if.h>
20 #include <pthread.h>
21 #include <sys/socket.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24 #include <errno.h>
25 #include <linux/netlink.h>
26 #include <linux/rtnetlink.h>
27 
28 #include "netlink_monitor.h"
29 
30 #define LOG(fmt, args...)       printf("[LAN_UPGRADE] "fmt"\n", ##args)
31 
32 #undef NLMSG_OK
33 #define NLMSG_OK(nlh, len) (((len) >= (int32_t)(sizeof(struct nlmsghdr))) && (((nlh)->nlmsg_len) >= \
34     sizeof(struct nlmsghdr)) && ((int32_t)((nlh)->nlmsg_len) <= (len)))
35 
36 #define DEFAULT_NETLINK_RECVBUF (4 * 1024)
37 
38 static PFUN_NNL_EVENT_HANDLER g_eventHandler = NULL;
39 
CreateNetlinkSocket(void)40 static int32_t CreateNetlinkSocket(void)
41 {
42     int32_t sockFd;
43     struct sockaddr_nl nladdr;
44     int32_t sz = DEFAULT_NETLINK_RECVBUF;
45 
46     sockFd = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_ROUTE);
47     if (sockFd < 0) {
48         LOG("open netlink socket failed");
49         return -1;
50     }
51     if (setsockopt(sockFd, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0 &&
52         setsockopt(sockFd, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz)) < 0) {
53         LOG("set uevent socket SO_RCVBUF option failed");
54         close(sockFd);
55         return -1;
56     }
57     (void)memset_s(&nladdr, sizeof(nladdr), 0, sizeof(nladdr));
58     nladdr.nl_family = AF_NETLINK;
59     // Kernel will assign a unique nl_pid if set to zero.
60     nladdr.nl_pid = 0;
61     nladdr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
62     if (bind(sockFd, (struct sockaddr *)&nladdr, sizeof(nladdr)) < 0) {
63         LOG("bind netlink socket failed");
64         close(sockFd);
65         return -1;
66     }
67     return sockFd;
68 }
69 
ParseRtAttr(struct rtattr ** tb,int max,struct rtattr * attr,int len)70 static void ParseRtAttr(struct rtattr **tb, int max, struct rtattr *attr, int len)
71 {
72     struct rtattr *attr1 = attr;
73     for (; RTA_OK(attr1, len); attr1 = RTA_NEXT(attr1, len)) {
74         if (attr1->rta_type <= max) {
75             tb[attr1->rta_type] = attr1;
76         }
77     }
78 }
79 
GetAddrTypeByIfname(const char * ifname,CONNECTION_ADDR_TYPE_E * type)80 static int32_t GetAddrTypeByIfname(const char *ifname, CONNECTION_ADDR_TYPE_E *type)
81 {
82     if (ifname == NULL || type == NULL) {
83         LOG("parameters are NULL!");
84         return -1;
85     }
86 
87     if (!strncasecmp(ifname, "eth", 3L)) {
88         *type = CONNECTION_ADDR_ETH;
89     } else if (!strncasecmp(ifname, "wlan", 4L)) {
90         *type = CONNECTION_ADDR_WLAN;
91     } else {
92         *type = CONNECTION_ADDR_BUTT;
93     }
94 
95     return 0;
96 }
97 
ProcessAddrEvent(struct nlmsghdr * nlh)98 static void ProcessAddrEvent(struct nlmsghdr *nlh)
99 {
100     struct ifaddrmsg *ifa = (struct ifaddrmsg *)NLMSG_DATA(nlh);
101     char name[IFNAMSIZ];
102     CONNECTION_ADDR_TYPE_E type = CONNECTION_ADDR_BUTT;
103 
104     if (if_indextoname(ifa->ifa_index, name) == 0) {
105         LOG("invalid iface index");
106         return;
107     }
108     if (GetAddrTypeByIfname(name, &type) != 0) {
109         LOG("ProcessAddrEvent GetAddrTypeByIfname error");
110         return;
111     }
112     if (type == CONNECTION_ADDR_ETH || type == CONNECTION_ADDR_WLAN) {
113         LOG("network addr changed, type:%d", type);
114         if (g_eventHandler) {
115             g_eventHandler(NNL_EVENT_IP_ADDR_CHANGED, NULL);
116         }
117     }
118 }
119 
ProcessLinkEvent(struct nlmsghdr * nlh)120 static void ProcessLinkEvent(struct nlmsghdr *nlh)
121 {
122     int len;
123     struct rtattr *tb[IFLA_MAX + 1] = {NULL};
124     struct ifinfomsg *ifinfo = NLMSG_DATA(nlh);
125     CONNECTION_ADDR_TYPE_E type = CONNECTION_ADDR_BUTT;
126 
127     len = (int32_t)nlh->nlmsg_len - NLMSG_SPACE(sizeof(*ifinfo));
128     ParseRtAttr(tb, IFLA_MAX, IFLA_RTA(ifinfo), len);
129 
130     if (tb[IFLA_IFNAME] == NULL) {
131         LOG("netlink msg is invalid");
132         return;
133     }
134     if (GetAddrTypeByIfname(RTA_DATA(tb[IFLA_IFNAME]), &type) != 0) {
135         LOG("ProcessAddrEvent GetAddrTypeByIfname error");
136         return;
137     }
138     if (type == CONNECTION_ADDR_ETH || type == CONNECTION_ADDR_WLAN) {
139         LOG("link status changed, type:%d", type);
140         if (g_eventHandler) {
141             g_eventHandler(NNL_EVENT_IP_ADDR_CHANGED, NULL);
142         }
143     }
144 }
145 
NetlinkMonitorThread(void * para)146 static void *NetlinkMonitorThread(void *para)
147 {
148     int32_t sockFd;
149     int32_t len;
150     uint8_t buffer[DEFAULT_NETLINK_RECVBUF];
151     struct nlmsghdr *nlh = NULL;
152 
153     (void)para;
154     LOG("netlink monitor thread start");
155     sockFd = CreateNetlinkSocket();
156     if (sockFd < 0) {
157         LOG("create netlink socket failed");
158         return NULL;
159     }
160     while (1) {
161         len = recv(sockFd, buffer, DEFAULT_NETLINK_RECVBUF, 0);
162         if (len < 0 && errno == EINTR) {
163             continue;
164         }
165         if (len < 0) {
166             LOG("recv netlink socket error");
167             break;
168         }
169         if (len < (int32_t)sizeof(struct nlmsghdr)) {
170             LOG("recv buffer not enough");
171             continue;
172         }
173         nlh = (struct nlmsghdr *)buffer;
174         while (NLMSG_OK(nlh, len) && nlh->nlmsg_type != NLMSG_DONE) {
175             switch (nlh->nlmsg_type) {
176                 case RTM_NEWADDR:
177                 case RTM_DELADDR:
178                     ProcessAddrEvent(nlh);
179                     break;
180                 case RTM_NEWLINK:
181                 case RTM_DELLINK:
182                     ProcessLinkEvent(nlh);
183                     break;
184                 default:
185                     break;
186             }
187             nlh = NLMSG_NEXT(nlh, len);
188         }
189     }
190     close(sockFd);
191     LOG("netlink monitor thread exit");
192     return NULL;
193 }
194 
NetlinkMonitorStart(PFUN_NNL_EVENT_HANDLER handler)195 int32_t NetlinkMonitorStart(PFUN_NNL_EVENT_HANDLER handler)
196 {
197     pthread_t tid;
198 
199     if (handler == NULL) {
200         LOG("netlink event handler is null");
201         return -1;
202     }
203     if (pthread_create(&tid, NULL, NetlinkMonitorThread, NULL) != 0) {
204         LOG("create ip change monitor thread failed");
205         return -1;
206     }
207     g_eventHandler = handler;
208     return 0;
209 }
210 
211