xref: /aosp_15_r20/external/libwebsockets/lib/roles/netlink/ops-netlink.c (revision 1c60b9aca93fdbc9b5f19b2d2194c91294b22281)
1*1c60b9acSAndroid Build Coastguard Worker /*
2*1c60b9acSAndroid Build Coastguard Worker  * libwebsockets - small server side websockets and web server implementation
3*1c60b9acSAndroid Build Coastguard Worker  *
4*1c60b9acSAndroid Build Coastguard Worker  * Copyright (C) 2010 - 2021 Andy Green <[email protected]>
5*1c60b9acSAndroid Build Coastguard Worker  *
6*1c60b9acSAndroid Build Coastguard Worker  * Permission is hereby granted, free of charge, to any person obtaining a copy
7*1c60b9acSAndroid Build Coastguard Worker  * of this software and associated documentation files (the "Software"), to
8*1c60b9acSAndroid Build Coastguard Worker  * deal in the Software without restriction, including without limitation the
9*1c60b9acSAndroid Build Coastguard Worker  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10*1c60b9acSAndroid Build Coastguard Worker  * sell copies of the Software, and to permit persons to whom the Software is
11*1c60b9acSAndroid Build Coastguard Worker  * furnished to do so, subject to the following conditions:
12*1c60b9acSAndroid Build Coastguard Worker  *
13*1c60b9acSAndroid Build Coastguard Worker  * The above copyright notice and this permission notice shall be included in
14*1c60b9acSAndroid Build Coastguard Worker  * all copies or substantial portions of the Software.
15*1c60b9acSAndroid Build Coastguard Worker  *
16*1c60b9acSAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17*1c60b9acSAndroid Build Coastguard Worker  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18*1c60b9acSAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19*1c60b9acSAndroid Build Coastguard Worker  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20*1c60b9acSAndroid Build Coastguard Worker  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21*1c60b9acSAndroid Build Coastguard Worker  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22*1c60b9acSAndroid Build Coastguard Worker  * IN THE SOFTWARE.
23*1c60b9acSAndroid Build Coastguard Worker  *
24*1c60b9acSAndroid Build Coastguard Worker  * We mainly focus on the routing table / gateways because those are the
25*1c60b9acSAndroid Build Coastguard Worker  * elements that decide if we can get on to the internet or not.
26*1c60b9acSAndroid Build Coastguard Worker  *
27*1c60b9acSAndroid Build Coastguard Worker  * We also need to understand the source addresses of possible outgoing routes,
28*1c60b9acSAndroid Build Coastguard Worker  * and follow LINK down (ifconfig down) to clean up routes on the interface idx
29*1c60b9acSAndroid Build Coastguard Worker  * going down that are not otherwise cleaned.
30*1c60b9acSAndroid Build Coastguard Worker  */
31*1c60b9acSAndroid Build Coastguard Worker 
32*1c60b9acSAndroid Build Coastguard Worker #include <private-lib-core.h>
33*1c60b9acSAndroid Build Coastguard Worker 
34*1c60b9acSAndroid Build Coastguard Worker #include <asm/types.h>
35*1c60b9acSAndroid Build Coastguard Worker #include <sys/socket.h>
36*1c60b9acSAndroid Build Coastguard Worker #include <linux/netlink.h>
37*1c60b9acSAndroid Build Coastguard Worker #include <linux/rtnetlink.h>
38*1c60b9acSAndroid Build Coastguard Worker 
39*1c60b9acSAndroid Build Coastguard Worker /* work around CentOS 7 -Wconversion problem */
40*1c60b9acSAndroid Build Coastguard Worker #undef RTA_ALIGNTO
41*1c60b9acSAndroid Build Coastguard Worker #define RTA_ALIGNTO 4U
42*1c60b9acSAndroid Build Coastguard Worker 
43*1c60b9acSAndroid Build Coastguard Worker //#define lwsl_netlink lwsl_notice
44*1c60b9acSAndroid Build Coastguard Worker #define lwsl_cx_netlink lwsl_cx_info
45*1c60b9acSAndroid Build Coastguard Worker 
46*1c60b9acSAndroid Build Coastguard Worker static void
lws_netlink_coldplug_done_cb(lws_sorted_usec_list_t * sul)47*1c60b9acSAndroid Build Coastguard Worker lws_netlink_coldplug_done_cb(lws_sorted_usec_list_t *sul)
48*1c60b9acSAndroid Build Coastguard Worker {
49*1c60b9acSAndroid Build Coastguard Worker 	struct lws_context *ctx = lws_container_of(sul, struct lws_context,
50*1c60b9acSAndroid Build Coastguard Worker 						   sul_nl_coldplug);
51*1c60b9acSAndroid Build Coastguard Worker 	ctx->nl_initial_done = 1;
52*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_SYS_STATE)
53*1c60b9acSAndroid Build Coastguard Worker 	/* if nothing is there to intercept anything, go all the way */
54*1c60b9acSAndroid Build Coastguard Worker 	lws_state_transition_steps(&ctx->mgr_system, LWS_SYSTATE_OPERATIONAL);
55*1c60b9acSAndroid Build Coastguard Worker #endif
56*1c60b9acSAndroid Build Coastguard Worker }
57*1c60b9acSAndroid Build Coastguard Worker 
58*1c60b9acSAndroid Build Coastguard Worker static int
rops_handle_POLLIN_netlink(struct lws_context_per_thread * pt,struct lws * wsi,struct lws_pollfd * pollfd)59*1c60b9acSAndroid Build Coastguard Worker rops_handle_POLLIN_netlink(struct lws_context_per_thread *pt, struct lws *wsi,
60*1c60b9acSAndroid Build Coastguard Worker 			   struct lws_pollfd *pollfd)
61*1c60b9acSAndroid Build Coastguard Worker {
62*1c60b9acSAndroid Build Coastguard Worker 	struct lws_context	*cx = pt->context;
63*1c60b9acSAndroid Build Coastguard Worker 	uint8_t s[4096]
64*1c60b9acSAndroid Build Coastguard Worker #if defined(_DEBUG)
65*1c60b9acSAndroid Build Coastguard Worker 	        , route_change = 0
66*1c60b9acSAndroid Build Coastguard Worker #endif
67*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_SYS_SMD)
68*1c60b9acSAndroid Build Coastguard Worker 		, gateway_change = 0
69*1c60b9acSAndroid Build Coastguard Worker #endif
70*1c60b9acSAndroid Build Coastguard Worker 			;
71*1c60b9acSAndroid Build Coastguard Worker 	struct sockaddr_nl	nladdr;
72*1c60b9acSAndroid Build Coastguard Worker 	lws_route_t		robj, *rou, *rmat;
73*1c60b9acSAndroid Build Coastguard Worker 	struct nlmsghdr		*h;
74*1c60b9acSAndroid Build Coastguard Worker 	struct msghdr		msg;
75*1c60b9acSAndroid Build Coastguard Worker 	struct iovec		iov;
76*1c60b9acSAndroid Build Coastguard Worker 	unsigned int		n;
77*1c60b9acSAndroid Build Coastguard Worker 	char			buf[72];
78*1c60b9acSAndroid Build Coastguard Worker 
79*1c60b9acSAndroid Build Coastguard Worker 	if (!(pollfd->revents & LWS_POLLIN))
80*1c60b9acSAndroid Build Coastguard Worker 		return LWS_HPI_RET_HANDLED;
81*1c60b9acSAndroid Build Coastguard Worker 
82*1c60b9acSAndroid Build Coastguard Worker 	memset(&msg, 0, sizeof(msg));
83*1c60b9acSAndroid Build Coastguard Worker 
84*1c60b9acSAndroid Build Coastguard Worker 	iov.iov_base		= (void *)s;
85*1c60b9acSAndroid Build Coastguard Worker 	iov.iov_len		= sizeof(s);
86*1c60b9acSAndroid Build Coastguard Worker 
87*1c60b9acSAndroid Build Coastguard Worker 	msg.msg_name		= (void *)&(nladdr);
88*1c60b9acSAndroid Build Coastguard Worker 	msg.msg_namelen		= sizeof(nladdr);
89*1c60b9acSAndroid Build Coastguard Worker 
90*1c60b9acSAndroid Build Coastguard Worker 	msg.msg_iov		= &iov;
91*1c60b9acSAndroid Build Coastguard Worker 	msg.msg_iovlen		= 1;
92*1c60b9acSAndroid Build Coastguard Worker 
93*1c60b9acSAndroid Build Coastguard Worker 	n = (unsigned int)recvmsg(wsi->desc.sockfd, &msg, 0);
94*1c60b9acSAndroid Build Coastguard Worker 	if ((int)n < 0) {
95*1c60b9acSAndroid Build Coastguard Worker 		lwsl_cx_notice(cx, "recvmsg failed");
96*1c60b9acSAndroid Build Coastguard Worker 		return LWS_HPI_RET_PLEASE_CLOSE_ME;
97*1c60b9acSAndroid Build Coastguard Worker 	}
98*1c60b9acSAndroid Build Coastguard Worker 
99*1c60b9acSAndroid Build Coastguard Worker 	// lwsl_hexdump_notice(s, (size_t)n);
100*1c60b9acSAndroid Build Coastguard Worker 
101*1c60b9acSAndroid Build Coastguard Worker 	h = (struct nlmsghdr *)s;
102*1c60b9acSAndroid Build Coastguard Worker 
103*1c60b9acSAndroid Build Coastguard Worker 	/* we can get a bunch of messages coalesced in one read*/
104*1c60b9acSAndroid Build Coastguard Worker 
105*1c60b9acSAndroid Build Coastguard Worker 	for ( ; NLMSG_OK(h, n); h = NLMSG_NEXT(h, n)) {
106*1c60b9acSAndroid Build Coastguard Worker 		struct ifaddrmsg *ifam;
107*1c60b9acSAndroid Build Coastguard Worker 		struct rtattr *ra;
108*1c60b9acSAndroid Build Coastguard Worker 		struct rtmsg *rm;
109*1c60b9acSAndroid Build Coastguard Worker #if !defined(LWS_WITH_NO_LOGS) && defined(_DEBUG)
110*1c60b9acSAndroid Build Coastguard Worker 		struct ndmsg *nd;
111*1c60b9acSAndroid Build Coastguard Worker #endif
112*1c60b9acSAndroid Build Coastguard Worker 		unsigned int ra_len;
113*1c60b9acSAndroid Build Coastguard Worker 		uint8_t *p;
114*1c60b9acSAndroid Build Coastguard Worker 
115*1c60b9acSAndroid Build Coastguard Worker 		struct ifinfomsg *ifi;
116*1c60b9acSAndroid Build Coastguard Worker 		struct rtattr *attribute;
117*1c60b9acSAndroid Build Coastguard Worker 		unsigned int len;
118*1c60b9acSAndroid Build Coastguard Worker 
119*1c60b9acSAndroid Build Coastguard Worker 		lwsl_cx_netlink(cx, "RTM %d", h->nlmsg_type);
120*1c60b9acSAndroid Build Coastguard Worker 
121*1c60b9acSAndroid Build Coastguard Worker 		memset(&robj, 0, sizeof(robj));
122*1c60b9acSAndroid Build Coastguard Worker 		robj.if_idx = -1;
123*1c60b9acSAndroid Build Coastguard Worker 		robj.priority = -1;
124*1c60b9acSAndroid Build Coastguard Worker 		rm = (struct rtmsg *)NLMSG_DATA(h);
125*1c60b9acSAndroid Build Coastguard Worker 
126*1c60b9acSAndroid Build Coastguard Worker 		/*
127*1c60b9acSAndroid Build Coastguard Worker 		 * We have to care about NEWLINK so we can understand when a
128*1c60b9acSAndroid Build Coastguard Worker 		 * network interface went down, and clear the related routes.
129*1c60b9acSAndroid Build Coastguard Worker 		 *
130*1c60b9acSAndroid Build Coastguard Worker 		 * We don't get individual DELROUTEs for these.
131*1c60b9acSAndroid Build Coastguard Worker 		 */
132*1c60b9acSAndroid Build Coastguard Worker 
133*1c60b9acSAndroid Build Coastguard Worker 		switch (h->nlmsg_type) {
134*1c60b9acSAndroid Build Coastguard Worker 		case RTM_NEWLINK:
135*1c60b9acSAndroid Build Coastguard Worker 
136*1c60b9acSAndroid Build Coastguard Worker 			ifi = NLMSG_DATA(h);
137*1c60b9acSAndroid Build Coastguard Worker 			len = (unsigned int)(h->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)));
138*1c60b9acSAndroid Build Coastguard Worker 
139*1c60b9acSAndroid Build Coastguard Worker 			/* loop over all attributes for the NEWLINK message */
140*1c60b9acSAndroid Build Coastguard Worker 			for (attribute = IFLA_RTA(ifi); RTA_OK(attribute, len);
141*1c60b9acSAndroid Build Coastguard Worker 					 attribute = RTA_NEXT(attribute, len)) {
142*1c60b9acSAndroid Build Coastguard Worker 				lwsl_cx_netlink(cx, "if attr %d",
143*1c60b9acSAndroid Build Coastguard Worker 					    (int)attribute->rta_type);
144*1c60b9acSAndroid Build Coastguard Worker 				switch(attribute->rta_type) {
145*1c60b9acSAndroid Build Coastguard Worker 				case IFLA_IFNAME:
146*1c60b9acSAndroid Build Coastguard Worker 					lwsl_cx_netlink(cx, "NETLINK ifidx %d : %s",
147*1c60b9acSAndroid Build Coastguard Worker 						     ifi->ifi_index,
148*1c60b9acSAndroid Build Coastguard Worker 						     (char *)RTA_DATA(attribute));
149*1c60b9acSAndroid Build Coastguard Worker 					break;
150*1c60b9acSAndroid Build Coastguard Worker 				default:
151*1c60b9acSAndroid Build Coastguard Worker 					break;
152*1c60b9acSAndroid Build Coastguard Worker 				} /* switch */
153*1c60b9acSAndroid Build Coastguard Worker 			} /* for loop */
154*1c60b9acSAndroid Build Coastguard Worker 
155*1c60b9acSAndroid Build Coastguard Worker 			lwsl_cx_netlink(cx, "NEWLINK ifi_index %d, flags 0x%x",
156*1c60b9acSAndroid Build Coastguard Worker 					ifi->ifi_index, ifi->ifi_flags);
157*1c60b9acSAndroid Build Coastguard Worker 
158*1c60b9acSAndroid Build Coastguard Worker 			/*
159*1c60b9acSAndroid Build Coastguard Worker 			 * Despite "New"link this is actually telling us there
160*1c60b9acSAndroid Build Coastguard Worker 			 * is some change on the network interface IFF_ state
161*1c60b9acSAndroid Build Coastguard Worker 			 */
162*1c60b9acSAndroid Build Coastguard Worker 
163*1c60b9acSAndroid Build Coastguard Worker 			if (!(ifi->ifi_flags & IFF_UP)) {
164*1c60b9acSAndroid Build Coastguard Worker 				/*
165*1c60b9acSAndroid Build Coastguard Worker 				 * Interface is down, so scrub all routes that
166*1c60b9acSAndroid Build Coastguard Worker 				 * applied to it
167*1c60b9acSAndroid Build Coastguard Worker 				 */
168*1c60b9acSAndroid Build Coastguard Worker 				lwsl_cx_netlink(cx, "NEWLINK: ifdown %d",
169*1c60b9acSAndroid Build Coastguard Worker 						ifi->ifi_index);
170*1c60b9acSAndroid Build Coastguard Worker 				lws_pt_lock(pt, __func__);
171*1c60b9acSAndroid Build Coastguard Worker 				_lws_route_table_ifdown(pt, ifi->ifi_index);
172*1c60b9acSAndroid Build Coastguard Worker 				lws_pt_unlock(pt);
173*1c60b9acSAndroid Build Coastguard Worker 			}
174*1c60b9acSAndroid Build Coastguard Worker 			continue; /* ie, not break, no second half */
175*1c60b9acSAndroid Build Coastguard Worker 
176*1c60b9acSAndroid Build Coastguard Worker 		case RTM_NEWADDR:
177*1c60b9acSAndroid Build Coastguard Worker 		case RTM_DELADDR:
178*1c60b9acSAndroid Build Coastguard Worker 
179*1c60b9acSAndroid Build Coastguard Worker 			ifam = (struct ifaddrmsg *)NLMSG_DATA(h);
180*1c60b9acSAndroid Build Coastguard Worker 
181*1c60b9acSAndroid Build Coastguard Worker 			robj.source_ads = 1;
182*1c60b9acSAndroid Build Coastguard Worker 			robj.dest_len = ifam->ifa_prefixlen;
183*1c60b9acSAndroid Build Coastguard Worker 			robj.if_idx = (int)ifam->ifa_index;
184*1c60b9acSAndroid Build Coastguard Worker 			robj.scope = ifam->ifa_scope;
185*1c60b9acSAndroid Build Coastguard Worker 			robj.ifa_flags = ifam->ifa_flags;
186*1c60b9acSAndroid Build Coastguard Worker 			robj.dest.sa4.sin_family = ifam->ifa_family;
187*1c60b9acSAndroid Build Coastguard Worker 
188*1c60b9acSAndroid Build Coastguard Worker 			/* address attributes */
189*1c60b9acSAndroid Build Coastguard Worker 			ra = (struct rtattr *)IFA_RTA(ifam);
190*1c60b9acSAndroid Build Coastguard Worker 			ra_len = (unsigned int)IFA_PAYLOAD(h);
191*1c60b9acSAndroid Build Coastguard Worker 
192*1c60b9acSAndroid Build Coastguard Worker 			lwsl_cx_netlink(cx, "%s",
193*1c60b9acSAndroid Build Coastguard Worker 				     h->nlmsg_type == RTM_NEWADDR ?
194*1c60b9acSAndroid Build Coastguard Worker 						     "NEWADDR" : "DELADDR");
195*1c60b9acSAndroid Build Coastguard Worker 
196*1c60b9acSAndroid Build Coastguard Worker 			/*
197*1c60b9acSAndroid Build Coastguard Worker 			 * almost nothing interesting within IFA_* attributes:
198*1c60b9acSAndroid Build Coastguard Worker 			 * so skip it and goto to the second half
199*1c60b9acSAndroid Build Coastguard Worker 			 */
200*1c60b9acSAndroid Build Coastguard Worker 			goto second_half;
201*1c60b9acSAndroid Build Coastguard Worker 
202*1c60b9acSAndroid Build Coastguard Worker 		case RTM_NEWROUTE:
203*1c60b9acSAndroid Build Coastguard Worker 		case RTM_DELROUTE:
204*1c60b9acSAndroid Build Coastguard Worker 
205*1c60b9acSAndroid Build Coastguard Worker 			lwsl_cx_netlink(cx, "%s",
206*1c60b9acSAndroid Build Coastguard Worker 				     h->nlmsg_type == RTM_NEWROUTE ?
207*1c60b9acSAndroid Build Coastguard Worker 						     "NEWROUTE" : "DELROUTE");
208*1c60b9acSAndroid Build Coastguard Worker 
209*1c60b9acSAndroid Build Coastguard Worker 			/* route attributes */
210*1c60b9acSAndroid Build Coastguard Worker 			ra = (struct rtattr *)RTM_RTA(rm);
211*1c60b9acSAndroid Build Coastguard Worker 			ra_len = (unsigned int)RTM_PAYLOAD(h);
212*1c60b9acSAndroid Build Coastguard Worker 			break;
213*1c60b9acSAndroid Build Coastguard Worker 
214*1c60b9acSAndroid Build Coastguard Worker 		case RTM_DELNEIGH:
215*1c60b9acSAndroid Build Coastguard Worker 		case RTM_NEWNEIGH:
216*1c60b9acSAndroid Build Coastguard Worker 			lwsl_cx_netlink(cx, "%s", h->nlmsg_type ==
217*1c60b9acSAndroid Build Coastguard Worker 						RTM_NEWNEIGH ? "NEWNEIGH" :
218*1c60b9acSAndroid Build Coastguard Worker 							       "DELNEIGH");
219*1c60b9acSAndroid Build Coastguard Worker #if !defined(LWS_WITH_NO_LOGS) && defined(_DEBUG)
220*1c60b9acSAndroid Build Coastguard Worker 			nd = (struct ndmsg *)rm;
221*1c60b9acSAndroid Build Coastguard Worker 			lwsl_cx_netlink(cx, "fam %u, ifidx %u, flags 0x%x",
222*1c60b9acSAndroid Build Coastguard Worker 				    nd->ndm_family, nd->ndm_ifindex,
223*1c60b9acSAndroid Build Coastguard Worker 				    nd->ndm_flags);
224*1c60b9acSAndroid Build Coastguard Worker #endif
225*1c60b9acSAndroid Build Coastguard Worker 			ra = (struct rtattr *)RTM_RTA(rm);
226*1c60b9acSAndroid Build Coastguard Worker 			ra_len = (unsigned int)RTM_PAYLOAD(h);
227*1c60b9acSAndroid Build Coastguard Worker 			for ( ; RTA_OK(ra, ra_len); ra = RTA_NEXT(ra, ra_len)) {
228*1c60b9acSAndroid Build Coastguard Worker 				lwsl_cx_netlink(cx, "atr %d", ra->rta_type);
229*1c60b9acSAndroid Build Coastguard Worker 				switch (ra->rta_type) {
230*1c60b9acSAndroid Build Coastguard Worker 				case NDA_DST:
231*1c60b9acSAndroid Build Coastguard Worker 					lwsl_cx_netlink(cx, "dst len %d",
232*1c60b9acSAndroid Build Coastguard Worker 							ra->rta_len);
233*1c60b9acSAndroid Build Coastguard Worker 					break;
234*1c60b9acSAndroid Build Coastguard Worker 				}
235*1c60b9acSAndroid Build Coastguard Worker 			}
236*1c60b9acSAndroid Build Coastguard Worker 			lws_pt_lock(pt, __func__);
237*1c60b9acSAndroid Build Coastguard Worker 			_lws_route_pt_close_unroutable(pt);
238*1c60b9acSAndroid Build Coastguard Worker 			lws_pt_unlock(pt);
239*1c60b9acSAndroid Build Coastguard Worker 			continue;
240*1c60b9acSAndroid Build Coastguard Worker 
241*1c60b9acSAndroid Build Coastguard Worker 		default:
242*1c60b9acSAndroid Build Coastguard Worker 			lwsl_cx_netlink(cx, "*** Unknown RTM_%d",
243*1c60b9acSAndroid Build Coastguard Worker 					h->nlmsg_type);
244*1c60b9acSAndroid Build Coastguard Worker 			continue;
245*1c60b9acSAndroid Build Coastguard Worker 		} /* switch */
246*1c60b9acSAndroid Build Coastguard Worker 
247*1c60b9acSAndroid Build Coastguard Worker 		robj.proto = rm->rtm_protocol;
248*1c60b9acSAndroid Build Coastguard Worker 
249*1c60b9acSAndroid Build Coastguard Worker 		// iterate over route attributes
250*1c60b9acSAndroid Build Coastguard Worker 		for ( ; RTA_OK(ra, ra_len); ra = RTA_NEXT(ra, ra_len)) {
251*1c60b9acSAndroid Build Coastguard Worker 			// lwsl_netlink("%s: atr %d\n", __func__, ra->rta_type);
252*1c60b9acSAndroid Build Coastguard Worker 			switch (ra->rta_type) {
253*1c60b9acSAndroid Build Coastguard Worker 			case RTA_PREFSRC: /* protocol ads: preferred src ads */
254*1c60b9acSAndroid Build Coastguard Worker 			case RTA_SRC:
255*1c60b9acSAndroid Build Coastguard Worker 				lws_sa46_copy_address(&robj.src, RTA_DATA(ra),
256*1c60b9acSAndroid Build Coastguard Worker 							rm->rtm_family);
257*1c60b9acSAndroid Build Coastguard Worker 				robj.src_len = rm->rtm_src_len;
258*1c60b9acSAndroid Build Coastguard Worker 				lws_sa46_write_numeric_address(&robj.src, buf, sizeof(buf));
259*1c60b9acSAndroid Build Coastguard Worker 				lwsl_cx_netlink(cx, "RTA_SRC: %s", buf);
260*1c60b9acSAndroid Build Coastguard Worker 				break;
261*1c60b9acSAndroid Build Coastguard Worker 			case RTA_DST:
262*1c60b9acSAndroid Build Coastguard Worker 				lws_sa46_copy_address(&robj.dest, RTA_DATA(ra),
263*1c60b9acSAndroid Build Coastguard Worker 							rm->rtm_family);
264*1c60b9acSAndroid Build Coastguard Worker 				robj.dest_len = rm->rtm_dst_len;
265*1c60b9acSAndroid Build Coastguard Worker 				lws_sa46_write_numeric_address(&robj.dest, buf, sizeof(buf));
266*1c60b9acSAndroid Build Coastguard Worker 				lwsl_cx_netlink(cx, "RTA_DST: %s", buf);
267*1c60b9acSAndroid Build Coastguard Worker 				break;
268*1c60b9acSAndroid Build Coastguard Worker 			case RTA_GATEWAY:
269*1c60b9acSAndroid Build Coastguard Worker 				lws_sa46_copy_address(&robj.gateway,
270*1c60b9acSAndroid Build Coastguard Worker 						      RTA_DATA(ra),
271*1c60b9acSAndroid Build Coastguard Worker 						      rm->rtm_family);
272*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_SYS_SMD)
273*1c60b9acSAndroid Build Coastguard Worker 				gateway_change = 1;
274*1c60b9acSAndroid Build Coastguard Worker #endif
275*1c60b9acSAndroid Build Coastguard Worker 				break;
276*1c60b9acSAndroid Build Coastguard Worker 			case RTA_IIF: /* int: input interface index */
277*1c60b9acSAndroid Build Coastguard Worker 			case RTA_OIF: /* int: output interface index */
278*1c60b9acSAndroid Build Coastguard Worker 				robj.if_idx = *(int *)RTA_DATA(ra);
279*1c60b9acSAndroid Build Coastguard Worker 				lwsl_cx_netlink(cx, "ifidx %d", robj.if_idx);
280*1c60b9acSAndroid Build Coastguard Worker 				break;
281*1c60b9acSAndroid Build Coastguard Worker 			case RTA_PRIORITY: /* int: priority of route */
282*1c60b9acSAndroid Build Coastguard Worker 				p = RTA_DATA(ra);
283*1c60b9acSAndroid Build Coastguard Worker 				robj.priority = p[3] << 24 | p[2] << 16 |
284*1c60b9acSAndroid Build Coastguard Worker 						 p[1] << 8  | p[0];
285*1c60b9acSAndroid Build Coastguard Worker 				break;
286*1c60b9acSAndroid Build Coastguard Worker 			case RTA_CACHEINFO: /* struct rta_cacheinfo */
287*1c60b9acSAndroid Build Coastguard Worker 				break;
288*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_HAVE_RTA_PREF)
289*1c60b9acSAndroid Build Coastguard Worker 			case RTA_PREF: /* char: RFC4191 v6 router preference */
290*1c60b9acSAndroid Build Coastguard Worker 				break;
291*1c60b9acSAndroid Build Coastguard Worker #endif
292*1c60b9acSAndroid Build Coastguard Worker 			case RTA_TABLE: /* int */
293*1c60b9acSAndroid Build Coastguard Worker 				break;
294*1c60b9acSAndroid Build Coastguard Worker 
295*1c60b9acSAndroid Build Coastguard Worker 			default:
296*1c60b9acSAndroid Build Coastguard Worker 				lwsl_cx_info(cx, "unknown attr type %d",
297*1c60b9acSAndroid Build Coastguard Worker 					     ra->rta_type);
298*1c60b9acSAndroid Build Coastguard Worker 				break;
299*1c60b9acSAndroid Build Coastguard Worker 			}
300*1c60b9acSAndroid Build Coastguard Worker 		} /* for */
301*1c60b9acSAndroid Build Coastguard Worker 
302*1c60b9acSAndroid Build Coastguard Worker 		/*
303*1c60b9acSAndroid Build Coastguard Worker 		 * the second half, once all the attributes were collected
304*1c60b9acSAndroid Build Coastguard Worker 		 */
305*1c60b9acSAndroid Build Coastguard Worker second_half:
306*1c60b9acSAndroid Build Coastguard Worker 		switch (h->nlmsg_type) {
307*1c60b9acSAndroid Build Coastguard Worker 
308*1c60b9acSAndroid Build Coastguard Worker 		case RTM_DELROUTE:
309*1c60b9acSAndroid Build Coastguard Worker 			/*
310*1c60b9acSAndroid Build Coastguard Worker 			 * This will also take down wsi marked as using it
311*1c60b9acSAndroid Build Coastguard Worker 			 */
312*1c60b9acSAndroid Build Coastguard Worker 			lwsl_cx_netlink(cx, "DELROUTE: if_idx %d",
313*1c60b9acSAndroid Build Coastguard Worker 					robj.if_idx);
314*1c60b9acSAndroid Build Coastguard Worker 			lws_pt_lock(pt, __func__);
315*1c60b9acSAndroid Build Coastguard Worker 			_lws_route_remove(pt, &robj, 0);
316*1c60b9acSAndroid Build Coastguard Worker 			lws_pt_unlock(pt);
317*1c60b9acSAndroid Build Coastguard Worker 			goto inform;
318*1c60b9acSAndroid Build Coastguard Worker 
319*1c60b9acSAndroid Build Coastguard Worker 		case RTM_NEWROUTE:
320*1c60b9acSAndroid Build Coastguard Worker 
321*1c60b9acSAndroid Build Coastguard Worker 			lwsl_cx_netlink(cx, "NEWROUTE rtm_type %d",
322*1c60b9acSAndroid Build Coastguard Worker 					rm->rtm_type);
323*1c60b9acSAndroid Build Coastguard Worker 
324*1c60b9acSAndroid Build Coastguard Worker 			/*
325*1c60b9acSAndroid Build Coastguard Worker 			 * We don't want any routing debris like /32 or broadcast
326*1c60b9acSAndroid Build Coastguard Worker 			 * in our routing table... we will collect source addresses
327*1c60b9acSAndroid Build Coastguard Worker 			 * bound to interfaces via NEWADDR
328*1c60b9acSAndroid Build Coastguard Worker 			 */
329*1c60b9acSAndroid Build Coastguard Worker 
330*1c60b9acSAndroid Build Coastguard Worker 			if (rm->rtm_type != RTN_UNICAST &&
331*1c60b9acSAndroid Build Coastguard Worker 			    rm->rtm_type != RTN_LOCAL)
332*1c60b9acSAndroid Build Coastguard Worker 				break;
333*1c60b9acSAndroid Build Coastguard Worker 
334*1c60b9acSAndroid Build Coastguard Worker 			if (rm->rtm_flags & RTM_F_CLONED)
335*1c60b9acSAndroid Build Coastguard Worker 				break;
336*1c60b9acSAndroid Build Coastguard Worker 
337*1c60b9acSAndroid Build Coastguard Worker 			goto ana;
338*1c60b9acSAndroid Build Coastguard Worker 
339*1c60b9acSAndroid Build Coastguard Worker 		case RTM_DELADDR:
340*1c60b9acSAndroid Build Coastguard Worker 			lwsl_cx_notice(cx, "DELADDR");
341*1c60b9acSAndroid Build Coastguard Worker #if defined(_DEBUG)
342*1c60b9acSAndroid Build Coastguard Worker 			_lws_routing_entry_dump(cx, &robj);
343*1c60b9acSAndroid Build Coastguard Worker #endif
344*1c60b9acSAndroid Build Coastguard Worker 			lws_pt_lock(pt, __func__);
345*1c60b9acSAndroid Build Coastguard Worker 			_lws_route_remove(pt, &robj, LRR_MATCH_SRC | LRR_IGNORE_PRI);
346*1c60b9acSAndroid Build Coastguard Worker 			_lws_route_pt_close_unroutable(pt);
347*1c60b9acSAndroid Build Coastguard Worker 			lws_pt_unlock(pt);
348*1c60b9acSAndroid Build Coastguard Worker 			break;
349*1c60b9acSAndroid Build Coastguard Worker 
350*1c60b9acSAndroid Build Coastguard Worker 		case RTM_NEWADDR:
351*1c60b9acSAndroid Build Coastguard Worker 
352*1c60b9acSAndroid Build Coastguard Worker 			lwsl_cx_netlink(cx, "NEWADDR");
353*1c60b9acSAndroid Build Coastguard Worker ana:
354*1c60b9acSAndroid Build Coastguard Worker 
355*1c60b9acSAndroid Build Coastguard Worker 			/*
356*1c60b9acSAndroid Build Coastguard Worker 			 * Is robj a dupe in the routing table already?
357*1c60b9acSAndroid Build Coastguard Worker 			 *
358*1c60b9acSAndroid Build Coastguard Worker 			 * match on pri ignore == set pri and skip
359*1c60b9acSAndroid Build Coastguard Worker 			 * no match == add
360*1c60b9acSAndroid Build Coastguard Worker 			 */
361*1c60b9acSAndroid Build Coastguard Worker 
362*1c60b9acSAndroid Build Coastguard Worker 			lws_pt_lock(pt, __func__);
363*1c60b9acSAndroid Build Coastguard Worker 
364*1c60b9acSAndroid Build Coastguard Worker 			/* returns zero on match already in table */
365*1c60b9acSAndroid Build Coastguard Worker 			rmat = _lws_route_remove(pt, &robj, LRR_MATCH_SRC |
366*1c60b9acSAndroid Build Coastguard Worker 							    LRR_JUST_CHECK |
367*1c60b9acSAndroid Build Coastguard Worker 							    LRR_IGNORE_PRI);
368*1c60b9acSAndroid Build Coastguard Worker 			lws_pt_unlock(pt);
369*1c60b9acSAndroid Build Coastguard Worker 
370*1c60b9acSAndroid Build Coastguard Worker 			if (rmat) {
371*1c60b9acSAndroid Build Coastguard Worker 				rmat->priority = robj.priority;
372*1c60b9acSAndroid Build Coastguard Worker 				break;
373*1c60b9acSAndroid Build Coastguard Worker 			}
374*1c60b9acSAndroid Build Coastguard Worker 
375*1c60b9acSAndroid Build Coastguard Worker 			rou = lws_malloc(sizeof(*rou), __func__);
376*1c60b9acSAndroid Build Coastguard Worker 			if (!rou) {
377*1c60b9acSAndroid Build Coastguard Worker 				lwsl_cx_err(cx, "oom");
378*1c60b9acSAndroid Build Coastguard Worker 				return LWS_HPI_RET_HANDLED;
379*1c60b9acSAndroid Build Coastguard Worker 			}
380*1c60b9acSAndroid Build Coastguard Worker 
381*1c60b9acSAndroid Build Coastguard Worker 			*rou = robj;
382*1c60b9acSAndroid Build Coastguard Worker 
383*1c60b9acSAndroid Build Coastguard Worker 			lws_pt_lock(pt, __func__);
384*1c60b9acSAndroid Build Coastguard Worker 
385*1c60b9acSAndroid Build Coastguard Worker 			/*
386*1c60b9acSAndroid Build Coastguard Worker 			 * We lock the pt before getting the uidx, so it
387*1c60b9acSAndroid Build Coastguard Worker 			 * cannot race
388*1c60b9acSAndroid Build Coastguard Worker 			 */
389*1c60b9acSAndroid Build Coastguard Worker 
390*1c60b9acSAndroid Build Coastguard Worker 			rou->uidx = _lws_route_get_uidx(cx);
391*1c60b9acSAndroid Build Coastguard Worker 			lws_dll2_add_tail(&rou->list, &cx->routing_table);
392*1c60b9acSAndroid Build Coastguard Worker 			lwsl_cx_info(cx, "route list size %u",
393*1c60b9acSAndroid Build Coastguard Worker 					cx->routing_table.count);
394*1c60b9acSAndroid Build Coastguard Worker 
395*1c60b9acSAndroid Build Coastguard Worker 			_lws_route_pt_close_unroutable(pt);
396*1c60b9acSAndroid Build Coastguard Worker 
397*1c60b9acSAndroid Build Coastguard Worker 			lws_pt_unlock(pt);
398*1c60b9acSAndroid Build Coastguard Worker 
399*1c60b9acSAndroid Build Coastguard Worker inform:
400*1c60b9acSAndroid Build Coastguard Worker #if defined(_DEBUG)
401*1c60b9acSAndroid Build Coastguard Worker 			route_change = 1;
402*1c60b9acSAndroid Build Coastguard Worker #endif
403*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_SYS_SMD)
404*1c60b9acSAndroid Build Coastguard Worker 			/*
405*1c60b9acSAndroid Build Coastguard Worker 			 * Reflect the route add / del event using SMD.
406*1c60b9acSAndroid Build Coastguard Worker 			 * Participants interested can refer to the pt
407*1c60b9acSAndroid Build Coastguard Worker 			 * routing table
408*1c60b9acSAndroid Build Coastguard Worker 			 */
409*1c60b9acSAndroid Build Coastguard Worker 			(void)lws_smd_msg_printf(cx, LWSSMDCL_NETWORK,
410*1c60b9acSAndroid Build Coastguard Worker 				   "{\"rt\":\"%s\"}\n",
411*1c60b9acSAndroid Build Coastguard Worker 				   (h->nlmsg_type == RTM_DELROUTE) ?
412*1c60b9acSAndroid Build Coastguard Worker 						"del" : "add");
413*1c60b9acSAndroid Build Coastguard Worker #endif
414*1c60b9acSAndroid Build Coastguard Worker 
415*1c60b9acSAndroid Build Coastguard Worker 			break;
416*1c60b9acSAndroid Build Coastguard Worker 
417*1c60b9acSAndroid Build Coastguard Worker 		default:
418*1c60b9acSAndroid Build Coastguard Worker 			// lwsl_info("%s: unknown msg type %d\n", __func__,
419*1c60b9acSAndroid Build Coastguard Worker 			//		h->nlmsg_type);
420*1c60b9acSAndroid Build Coastguard Worker 			break;
421*1c60b9acSAndroid Build Coastguard Worker 		}
422*1c60b9acSAndroid Build Coastguard Worker 	} /* message iterator */
423*1c60b9acSAndroid Build Coastguard Worker 
424*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_SYS_SMD)
425*1c60b9acSAndroid Build Coastguard Worker 	if (gateway_change)
426*1c60b9acSAndroid Build Coastguard Worker 		/*
427*1c60b9acSAndroid Build Coastguard Worker 		 * If a route with a gw was added or deleted, retrigger captive
428*1c60b9acSAndroid Build Coastguard Worker 		 * portal detection if we have that
429*1c60b9acSAndroid Build Coastguard Worker 		 */
430*1c60b9acSAndroid Build Coastguard Worker 		(void)lws_smd_msg_printf(cx, LWSSMDCL_NETWORK,
431*1c60b9acSAndroid Build Coastguard Worker 				   "{\"trigger\": \"cpdcheck\", "
432*1c60b9acSAndroid Build Coastguard Worker 				   "\"src\":\"gw-change\"}");
433*1c60b9acSAndroid Build Coastguard Worker #endif
434*1c60b9acSAndroid Build Coastguard Worker 
435*1c60b9acSAndroid Build Coastguard Worker #if defined(_DEBUG)
436*1c60b9acSAndroid Build Coastguard Worker 	if (route_change) {
437*1c60b9acSAndroid Build Coastguard Worker 		lws_context_lock(cx, __func__);
438*1c60b9acSAndroid Build Coastguard Worker 		_lws_routing_table_dump(cx);
439*1c60b9acSAndroid Build Coastguard Worker 		lws_context_unlock(cx);
440*1c60b9acSAndroid Build Coastguard Worker 	}
441*1c60b9acSAndroid Build Coastguard Worker #endif
442*1c60b9acSAndroid Build Coastguard Worker 
443*1c60b9acSAndroid Build Coastguard Worker 	if (!cx->nl_initial_done &&
444*1c60b9acSAndroid Build Coastguard Worker 	    pt == &cx->pt[0] &&
445*1c60b9acSAndroid Build Coastguard Worker 	    cx->routing_table.count) {
446*1c60b9acSAndroid Build Coastguard Worker 		/*
447*1c60b9acSAndroid Build Coastguard Worker 		 * While netlink info still coming, keep moving the timer for
448*1c60b9acSAndroid Build Coastguard Worker 		 * calling it "done" to +100ms until after it stops coming
449*1c60b9acSAndroid Build Coastguard Worker 		 */
450*1c60b9acSAndroid Build Coastguard Worker 		lws_context_lock(cx, __func__);
451*1c60b9acSAndroid Build Coastguard Worker 		lws_sul_schedule(cx, 0, &cx->sul_nl_coldplug,
452*1c60b9acSAndroid Build Coastguard Worker 				 lws_netlink_coldplug_done_cb,
453*1c60b9acSAndroid Build Coastguard Worker 				 100 * LWS_US_PER_MS);
454*1c60b9acSAndroid Build Coastguard Worker 		lws_context_unlock(cx);
455*1c60b9acSAndroid Build Coastguard Worker 	}
456*1c60b9acSAndroid Build Coastguard Worker 
457*1c60b9acSAndroid Build Coastguard Worker 	return LWS_HPI_RET_HANDLED;
458*1c60b9acSAndroid Build Coastguard Worker }
459*1c60b9acSAndroid Build Coastguard Worker 
460*1c60b9acSAndroid Build Coastguard Worker struct nl_req_s {
461*1c60b9acSAndroid Build Coastguard Worker 	struct nlmsghdr hdr;
462*1c60b9acSAndroid Build Coastguard Worker 	struct rtmsg gen;
463*1c60b9acSAndroid Build Coastguard Worker };
464*1c60b9acSAndroid Build Coastguard Worker 
465*1c60b9acSAndroid Build Coastguard Worker int
rops_pt_init_destroy_netlink(struct lws_context * context,const struct lws_context_creation_info * info,struct lws_context_per_thread * pt,int destroy)466*1c60b9acSAndroid Build Coastguard Worker rops_pt_init_destroy_netlink(struct lws_context *context,
467*1c60b9acSAndroid Build Coastguard Worker 			     const struct lws_context_creation_info *info,
468*1c60b9acSAndroid Build Coastguard Worker 			     struct lws_context_per_thread *pt, int destroy)
469*1c60b9acSAndroid Build Coastguard Worker {
470*1c60b9acSAndroid Build Coastguard Worker 	struct sockaddr_nl sanl;
471*1c60b9acSAndroid Build Coastguard Worker 	struct nl_req_s req;
472*1c60b9acSAndroid Build Coastguard Worker 	struct msghdr msg;
473*1c60b9acSAndroid Build Coastguard Worker 	struct iovec iov;
474*1c60b9acSAndroid Build Coastguard Worker 	struct lws *wsi;
475*1c60b9acSAndroid Build Coastguard Worker 	int n, ret = 1;
476*1c60b9acSAndroid Build Coastguard Worker 
477*1c60b9acSAndroid Build Coastguard Worker 	if (destroy) {
478*1c60b9acSAndroid Build Coastguard Worker 
479*1c60b9acSAndroid Build Coastguard Worker 		/*
480*1c60b9acSAndroid Build Coastguard Worker 		 * pt netlink wsi closed + freed as part of pt's destroy
481*1c60b9acSAndroid Build Coastguard Worker 		 * wsi mass close, just need to take down the routing table
482*1c60b9acSAndroid Build Coastguard Worker 		 */
483*1c60b9acSAndroid Build Coastguard Worker 		_lws_route_table_empty(pt);
484*1c60b9acSAndroid Build Coastguard Worker 
485*1c60b9acSAndroid Build Coastguard Worker 		return 0;
486*1c60b9acSAndroid Build Coastguard Worker 	}
487*1c60b9acSAndroid Build Coastguard Worker 
488*1c60b9acSAndroid Build Coastguard Worker 	if (context->netlink)
489*1c60b9acSAndroid Build Coastguard Worker 		return 0;
490*1c60b9acSAndroid Build Coastguard Worker 
491*1c60b9acSAndroid Build Coastguard Worker 	if (pt > &context->pt[0])
492*1c60b9acSAndroid Build Coastguard Worker 		/* we can only have one netlink socket */
493*1c60b9acSAndroid Build Coastguard Worker 		return 0;
494*1c60b9acSAndroid Build Coastguard Worker 
495*1c60b9acSAndroid Build Coastguard Worker 	lwsl_cx_info(context, "creating netlink skt");
496*1c60b9acSAndroid Build Coastguard Worker 
497*1c60b9acSAndroid Build Coastguard Worker 	/*
498*1c60b9acSAndroid Build Coastguard Worker 	 * We want a netlink socket per pt as well
499*1c60b9acSAndroid Build Coastguard Worker 	 */
500*1c60b9acSAndroid Build Coastguard Worker 
501*1c60b9acSAndroid Build Coastguard Worker 	lws_context_lock(context, __func__);
502*1c60b9acSAndroid Build Coastguard Worker 	wsi = __lws_wsi_create_with_role(context, (int)(pt - &context->pt[0]),
503*1c60b9acSAndroid Build Coastguard Worker 				       &role_ops_netlink, NULL);
504*1c60b9acSAndroid Build Coastguard Worker 	lws_context_unlock(context);
505*1c60b9acSAndroid Build Coastguard Worker 	if (!wsi)
506*1c60b9acSAndroid Build Coastguard Worker 		goto bail;
507*1c60b9acSAndroid Build Coastguard Worker 
508*1c60b9acSAndroid Build Coastguard Worker 	wsi->desc.sockfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
509*1c60b9acSAndroid Build Coastguard Worker 	if (wsi->desc.sockfd == LWS_SOCK_INVALID) {
510*1c60b9acSAndroid Build Coastguard Worker 		lwsl_cx_err(context, "unable to open netlink");
511*1c60b9acSAndroid Build Coastguard Worker 		goto bail1;
512*1c60b9acSAndroid Build Coastguard Worker 	}
513*1c60b9acSAndroid Build Coastguard Worker 
514*1c60b9acSAndroid Build Coastguard Worker 	lws_plat_set_nonblocking(wsi->desc.sockfd);
515*1c60b9acSAndroid Build Coastguard Worker 
516*1c60b9acSAndroid Build Coastguard Worker 	__lws_lc_tag(context, &context->lcg[LWSLCG_VHOST], &wsi->lc,
517*1c60b9acSAndroid Build Coastguard Worker 			"netlink");
518*1c60b9acSAndroid Build Coastguard Worker 
519*1c60b9acSAndroid Build Coastguard Worker 	memset(&sanl, 0, sizeof(sanl));
520*1c60b9acSAndroid Build Coastguard Worker 	sanl.nl_family		= AF_NETLINK;
521*1c60b9acSAndroid Build Coastguard Worker 	sanl.nl_pid		= (uint32_t)getpid();
522*1c60b9acSAndroid Build Coastguard Worker 	sanl.nl_groups		= (1 << (RTNLGRP_LINK - 1)) |
523*1c60b9acSAndroid Build Coastguard Worker 				  (1 << (RTNLGRP_IPV4_ROUTE - 1)) |
524*1c60b9acSAndroid Build Coastguard Worker 				  (1 << (RTNLGRP_IPV4_IFADDR - 1))
525*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_IPV6)
526*1c60b9acSAndroid Build Coastguard Worker 				  | (1 << (RTNLGRP_IPV6_ROUTE - 1)) |
527*1c60b9acSAndroid Build Coastguard Worker 				    (1 << (RTNLGRP_IPV6_IFADDR - 1))
528*1c60b9acSAndroid Build Coastguard Worker #endif
529*1c60b9acSAndroid Build Coastguard Worker 				 ;
530*1c60b9acSAndroid Build Coastguard Worker 
531*1c60b9acSAndroid Build Coastguard Worker 	if (lws_fi(&context->fic, "netlink_bind") ||
532*1c60b9acSAndroid Build Coastguard Worker 	    bind(wsi->desc.sockfd, (struct sockaddr*)&sanl, sizeof(sanl)) < 0) {
533*1c60b9acSAndroid Build Coastguard Worker 		lwsl_cx_warn(context, "netlink bind failed");
534*1c60b9acSAndroid Build Coastguard Worker 		ret = 0; /* some systems deny access, just ignore */
535*1c60b9acSAndroid Build Coastguard Worker 		goto bail2;
536*1c60b9acSAndroid Build Coastguard Worker 	}
537*1c60b9acSAndroid Build Coastguard Worker 
538*1c60b9acSAndroid Build Coastguard Worker 	context->netlink = wsi;
539*1c60b9acSAndroid Build Coastguard Worker 	if (lws_wsi_inject_to_loop(pt, wsi))
540*1c60b9acSAndroid Build Coastguard Worker 		goto bail2;
541*1c60b9acSAndroid Build Coastguard Worker 
542*1c60b9acSAndroid Build Coastguard Worker /*	if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) {
543*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: pollfd in fail\n", __func__);
544*1c60b9acSAndroid Build Coastguard Worker 		goto bail2;
545*1c60b9acSAndroid Build Coastguard Worker 	}
546*1c60b9acSAndroid Build Coastguard Worker */
547*1c60b9acSAndroid Build Coastguard Worker 	/*
548*1c60b9acSAndroid Build Coastguard Worker 	 * Since we're starting the PT, ask to be sent all the existing routes.
549*1c60b9acSAndroid Build Coastguard Worker 	 *
550*1c60b9acSAndroid Build Coastguard Worker 	 * This requires CAP_ADMIN, or root... we do this early before dropping
551*1c60b9acSAndroid Build Coastguard Worker 	 * privs
552*1c60b9acSAndroid Build Coastguard Worker 	 */
553*1c60b9acSAndroid Build Coastguard Worker 
554*1c60b9acSAndroid Build Coastguard Worker 	memset(&sanl, 0, sizeof(sanl));
555*1c60b9acSAndroid Build Coastguard Worker 	memset(&msg, 0, sizeof(msg));
556*1c60b9acSAndroid Build Coastguard Worker 	memset(&req, 0, sizeof(req));
557*1c60b9acSAndroid Build Coastguard Worker 
558*1c60b9acSAndroid Build Coastguard Worker 	sanl.nl_family		= AF_NETLINK;
559*1c60b9acSAndroid Build Coastguard Worker 
560*1c60b9acSAndroid Build Coastguard Worker 	req.hdr.nlmsg_len	= NLMSG_LENGTH(sizeof(req.gen));
561*1c60b9acSAndroid Build Coastguard Worker 	req.hdr.nlmsg_type	= RTM_GETROUTE;
562*1c60b9acSAndroid Build Coastguard Worker 	req.hdr.nlmsg_flags	= NLM_F_REQUEST | NLM_F_DUMP;
563*1c60b9acSAndroid Build Coastguard Worker 	req.hdr.nlmsg_seq	= 1;
564*1c60b9acSAndroid Build Coastguard Worker 	req.hdr.nlmsg_pid	= (uint32_t)getpid();
565*1c60b9acSAndroid Build Coastguard Worker 	req.gen.rtm_family	= AF_PACKET;
566*1c60b9acSAndroid Build Coastguard Worker 	req.gen.rtm_table	= RT_TABLE_DEFAULT;
567*1c60b9acSAndroid Build Coastguard Worker 
568*1c60b9acSAndroid Build Coastguard Worker 	iov.iov_base		= &req;
569*1c60b9acSAndroid Build Coastguard Worker 	iov.iov_len		= req.hdr.nlmsg_len;
570*1c60b9acSAndroid Build Coastguard Worker 	msg.msg_iov		= &iov;
571*1c60b9acSAndroid Build Coastguard Worker 	msg.msg_iovlen		= 1;
572*1c60b9acSAndroid Build Coastguard Worker 	msg.msg_name		= &sanl;
573*1c60b9acSAndroid Build Coastguard Worker 	msg.msg_namelen		= sizeof(sanl);
574*1c60b9acSAndroid Build Coastguard Worker 
575*1c60b9acSAndroid Build Coastguard Worker 	n = (int)sendmsg(wsi->desc.sockfd, (struct msghdr *)&msg, 0);
576*1c60b9acSAndroid Build Coastguard Worker 	if (n < 0) {
577*1c60b9acSAndroid Build Coastguard Worker 		lwsl_cx_notice(context, "rt dump req failed... permissions? errno %d",
578*1c60b9acSAndroid Build Coastguard Worker 				LWS_ERRNO);
579*1c60b9acSAndroid Build Coastguard Worker 	}
580*1c60b9acSAndroid Build Coastguard Worker 
581*1c60b9acSAndroid Build Coastguard Worker 	/*
582*1c60b9acSAndroid Build Coastguard Worker 	 * Responses are going to come asynchronously, let's block moving
583*1c60b9acSAndroid Build Coastguard Worker 	 * off state IFACE_COLDPLUG until we have had them.  This is important
584*1c60b9acSAndroid Build Coastguard Worker 	 * since if we don't hold there, when we do get the responses we may
585*1c60b9acSAndroid Build Coastguard Worker 	 * cull any ongoing connections as unroutable otherwise
586*1c60b9acSAndroid Build Coastguard Worker 	 */
587*1c60b9acSAndroid Build Coastguard Worker 
588*1c60b9acSAndroid Build Coastguard Worker 	lwsl_cx_debug(context, "starting netlink coldplug wait");
589*1c60b9acSAndroid Build Coastguard Worker 
590*1c60b9acSAndroid Build Coastguard Worker 	return 0;
591*1c60b9acSAndroid Build Coastguard Worker 
592*1c60b9acSAndroid Build Coastguard Worker bail2:
593*1c60b9acSAndroid Build Coastguard Worker 	__lws_lc_untag(wsi->a.context, &wsi->lc);
594*1c60b9acSAndroid Build Coastguard Worker 	compatible_close(wsi->desc.sockfd);
595*1c60b9acSAndroid Build Coastguard Worker bail1:
596*1c60b9acSAndroid Build Coastguard Worker 	lws_free(wsi);
597*1c60b9acSAndroid Build Coastguard Worker bail:
598*1c60b9acSAndroid Build Coastguard Worker 	return ret;
599*1c60b9acSAndroid Build Coastguard Worker }
600*1c60b9acSAndroid Build Coastguard Worker 
601*1c60b9acSAndroid Build Coastguard Worker static const lws_rops_t rops_table_netlink[] = {
602*1c60b9acSAndroid Build Coastguard Worker 	/*  1 */ { .pt_init_destroy	= rops_pt_init_destroy_netlink },
603*1c60b9acSAndroid Build Coastguard Worker 	/*  2 */ { .handle_POLLIN	= rops_handle_POLLIN_netlink },
604*1c60b9acSAndroid Build Coastguard Worker };
605*1c60b9acSAndroid Build Coastguard Worker 
606*1c60b9acSAndroid Build Coastguard Worker const struct lws_role_ops role_ops_netlink = {
607*1c60b9acSAndroid Build Coastguard Worker 	/* role name */			"netlink",
608*1c60b9acSAndroid Build Coastguard Worker 	/* alpn id */			NULL,
609*1c60b9acSAndroid Build Coastguard Worker 
610*1c60b9acSAndroid Build Coastguard Worker 	/* rops_table */		rops_table_netlink,
611*1c60b9acSAndroid Build Coastguard Worker 	/* rops_idx */			{
612*1c60b9acSAndroid Build Coastguard Worker 	  /* LWS_ROPS_check_upgrades */
613*1c60b9acSAndroid Build Coastguard Worker 	  /* LWS_ROPS_pt_init_destroy */		0x01,
614*1c60b9acSAndroid Build Coastguard Worker 	  /* LWS_ROPS_init_vhost */
615*1c60b9acSAndroid Build Coastguard Worker 	  /* LWS_ROPS_destroy_vhost */			0x00,
616*1c60b9acSAndroid Build Coastguard Worker 	  /* LWS_ROPS_service_flag_pending */
617*1c60b9acSAndroid Build Coastguard Worker 	  /* LWS_ROPS_handle_POLLIN */			0x02,
618*1c60b9acSAndroid Build Coastguard Worker 	  /* LWS_ROPS_handle_POLLOUT */
619*1c60b9acSAndroid Build Coastguard Worker 	  /* LWS_ROPS_perform_user_POLLOUT */		0x00,
620*1c60b9acSAndroid Build Coastguard Worker 	  /* LWS_ROPS_callback_on_writable */
621*1c60b9acSAndroid Build Coastguard Worker 	  /* LWS_ROPS_tx_credit */			0x00,
622*1c60b9acSAndroid Build Coastguard Worker 	  /* LWS_ROPS_write_role_protocol */
623*1c60b9acSAndroid Build Coastguard Worker 	  /* LWS_ROPS_encapsulation_parent */		0x00,
624*1c60b9acSAndroid Build Coastguard Worker 	  /* LWS_ROPS_alpn_negotiated */
625*1c60b9acSAndroid Build Coastguard Worker 	  /* LWS_ROPS_close_via_role_protocol */	0x00,
626*1c60b9acSAndroid Build Coastguard Worker 	  /* LWS_ROPS_close_role */
627*1c60b9acSAndroid Build Coastguard Worker 	  /* LWS_ROPS_close_kill_connection */		0x00,
628*1c60b9acSAndroid Build Coastguard Worker 	  /* LWS_ROPS_destroy_role */
629*1c60b9acSAndroid Build Coastguard Worker 	  /* LWS_ROPS_adoption_bind */			0x00,
630*1c60b9acSAndroid Build Coastguard Worker 	  /* LWS_ROPS_client_bind */
631*1c60b9acSAndroid Build Coastguard Worker 	  /* LWS_ROPS_issue_keepalive */		0x00,
632*1c60b9acSAndroid Build Coastguard Worker 					},
633*1c60b9acSAndroid Build Coastguard Worker 
634*1c60b9acSAndroid Build Coastguard Worker 	/* adoption_cb clnt, srv */	{ 0, 0 },
635*1c60b9acSAndroid Build Coastguard Worker 	/* rx_cb clnt, srv */		{ 0, 0 },
636*1c60b9acSAndroid Build Coastguard Worker 	/* writeable cb clnt, srv */	{ 0, 0 },
637*1c60b9acSAndroid Build Coastguard Worker 	/* close cb clnt, srv */	{ 0, 0 },
638*1c60b9acSAndroid Build Coastguard Worker 	/* protocol_bind_cb c,s */	{ 0, 0 },
639*1c60b9acSAndroid Build Coastguard Worker 	/* protocol_unbind_cb c,s */	{ 0, 0 },
640*1c60b9acSAndroid Build Coastguard Worker 	/* file_handle */		0,
641*1c60b9acSAndroid Build Coastguard Worker };
642