xref: /aosp_15_r20/external/libnfnetlink/src/rtnl.c (revision a376eb3279f225b393114c4820c780cbda860a6c)
1*a376eb32SXin Li /* rtnl - rtnetlink utility functions
2*a376eb32SXin Li  *
3*a376eb32SXin Li  * (C) 2004 by Astaro AG, written by Harald Welte <[email protected]>
4*a376eb32SXin Li  *
5*a376eb32SXin Li  * Adapted to nfnetlink by Eric Leblond <[email protected]>
6*a376eb32SXin Li  *
7*a376eb32SXin Li  * This software is free software and licensed under GNU GPLv2.
8*a376eb32SXin Li  *
9*a376eb32SXin Li  */
10*a376eb32SXin Li 
11*a376eb32SXin Li /* rtnetlink - routing table netlink interface */
12*a376eb32SXin Li 
13*a376eb32SXin Li #include <unistd.h>
14*a376eb32SXin Li #include <stdlib.h>
15*a376eb32SXin Li #include <string.h>
16*a376eb32SXin Li #include <errno.h>
17*a376eb32SXin Li #include <time.h>
18*a376eb32SXin Li #include <sys/types.h>
19*a376eb32SXin Li #include <sys/uio.h>
20*a376eb32SXin Li 
21*a376eb32SXin Li #include <netinet/in.h>
22*a376eb32SXin Li 
23*a376eb32SXin Li #include <linux/types.h>
24*a376eb32SXin Li #include <sys/socket.h>
25*a376eb32SXin Li #include <linux/netlink.h>
26*a376eb32SXin Li #include <linux/rtnetlink.h>
27*a376eb32SXin Li 
28*a376eb32SXin Li #include "rtnl.h"
29*a376eb32SXin Li 
30*a376eb32SXin Li #define rtnl_log(x, ...)
31*a376eb32SXin Li 
32*a376eb32SXin Li static inline struct rtnl_handler *
find_handler(struct rtnl_handle * rtnl_handle,u_int16_t type)33*a376eb32SXin Li find_handler(struct rtnl_handle *rtnl_handle, u_int16_t type)
34*a376eb32SXin Li {
35*a376eb32SXin Li 	struct rtnl_handler *h;
36*a376eb32SXin Li 	for (h = rtnl_handle->handlers; h; h = h->next) {
37*a376eb32SXin Li 		if (h->nlmsg_type == type)
38*a376eb32SXin Li 			return h;
39*a376eb32SXin Li 	}
40*a376eb32SXin Li 	return NULL;
41*a376eb32SXin Li }
42*a376eb32SXin Li 
call_handler(struct rtnl_handle * rtnl_handle,u_int16_t type,struct nlmsghdr * hdr)43*a376eb32SXin Li static int call_handler(struct rtnl_handle *rtnl_handle,
44*a376eb32SXin Li 			u_int16_t type,
45*a376eb32SXin Li 			struct nlmsghdr *hdr)
46*a376eb32SXin Li {
47*a376eb32SXin Li 	struct rtnl_handler *h = find_handler(rtnl_handle, type);
48*a376eb32SXin Li 
49*a376eb32SXin Li 	if (!h) {
50*a376eb32SXin Li 		rtnl_log(LOG_DEBUG, "no registered handler for type %u", type);
51*a376eb32SXin Li 		return 0;
52*a376eb32SXin Li 	}
53*a376eb32SXin Li 
54*a376eb32SXin Li 	return (h->handlefn)(hdr, h->arg);
55*a376eb32SXin Li }
56*a376eb32SXin Li 
57*a376eb32SXin Li /* rtnl_handler_register - register handler for given nlmsg type
58*a376eb32SXin Li  * @hdlr:	handler structure
59*a376eb32SXin Li  */
rtnl_handler_register(struct rtnl_handle * rtnl_handle,struct rtnl_handler * hdlr)60*a376eb32SXin Li int rtnl_handler_register(struct rtnl_handle *rtnl_handle,
61*a376eb32SXin Li 			  struct rtnl_handler *hdlr)
62*a376eb32SXin Li {
63*a376eb32SXin Li 	rtnl_log(LOG_DEBUG, "registering handler for type %u",
64*a376eb32SXin Li 		 hdlr->nlmsg_type);
65*a376eb32SXin Li 	hdlr->next = rtnl_handle->handlers;
66*a376eb32SXin Li 	rtnl_handle->handlers = hdlr;
67*a376eb32SXin Li 	return 1;
68*a376eb32SXin Li }
69*a376eb32SXin Li 
70*a376eb32SXin Li /* rtnl_handler_unregister - unregister handler for given nlmst type
71*a376eb32SXin Li  * @hdlr:	handler structure
72*a376eb32SXin Li  */
rtnl_handler_unregister(struct rtnl_handle * rtnl_handle,struct rtnl_handler * hdlr)73*a376eb32SXin Li int rtnl_handler_unregister(struct rtnl_handle *rtnl_handle,
74*a376eb32SXin Li 			    struct rtnl_handler *hdlr)
75*a376eb32SXin Li {
76*a376eb32SXin Li 	struct rtnl_handler *h, *prev = NULL;
77*a376eb32SXin Li 
78*a376eb32SXin Li 	rtnl_log(LOG_DEBUG, "unregistering handler for type %u",
79*a376eb32SXin Li 		 hdlr->nlmsg_type);
80*a376eb32SXin Li 
81*a376eb32SXin Li 	for (h = rtnl_handle->handlers; h; h = h->next) {
82*a376eb32SXin Li 		if (h == hdlr) {
83*a376eb32SXin Li 			if (prev)
84*a376eb32SXin Li 				prev->next = h->next;
85*a376eb32SXin Li 			else
86*a376eb32SXin Li 				rtnl_handle->handlers = h->next;
87*a376eb32SXin Li 			return 1;
88*a376eb32SXin Li 		}
89*a376eb32SXin Li 		prev = h;
90*a376eb32SXin Li 	}
91*a376eb32SXin Li 	return 0;
92*a376eb32SXin Li }
93*a376eb32SXin Li 
rtnl_parse_rtattr(struct rtattr * tb[],int max,struct rtattr * rta,int len)94*a376eb32SXin Li int rtnl_parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
95*a376eb32SXin Li {
96*a376eb32SXin Li 	memset(tb, 0, sizeof(struct rtattr *) * max);
97*a376eb32SXin Li 
98*a376eb32SXin Li 	while (RTA_OK(rta, len)) {
99*a376eb32SXin Li 		if (rta->rta_type <= max)
100*a376eb32SXin Li 			tb[rta->rta_type] = rta;
101*a376eb32SXin Li 		rta = RTA_NEXT(rta,len);
102*a376eb32SXin Li 	}
103*a376eb32SXin Li 	if (len)
104*a376eb32SXin Li 		return -1;
105*a376eb32SXin Li 	return 0;
106*a376eb32SXin Li }
107*a376eb32SXin Li 
108*a376eb32SXin Li /* rtnl_dump_type - ask rtnetlink to dump a specific table
109*a376eb32SXin Li  * @type:	type of table to be dumped
110*a376eb32SXin Li  */
rtnl_dump_type(struct rtnl_handle * rtnl_handle,unsigned int type)111*a376eb32SXin Li int rtnl_dump_type(struct rtnl_handle *rtnl_handle, unsigned int type)
112*a376eb32SXin Li {
113*a376eb32SXin Li 	struct {
114*a376eb32SXin Li 		struct nlmsghdr nlh;
115*a376eb32SXin Li 		struct rtgenmsg g;
116*a376eb32SXin Li 	} req;
117*a376eb32SXin Li 	struct sockaddr_nl nladdr;
118*a376eb32SXin Li 
119*a376eb32SXin Li 	memset(&nladdr, 0, sizeof(nladdr));
120*a376eb32SXin Li 	memset(&req, 0, sizeof(req));
121*a376eb32SXin Li 	nladdr.nl_family = AF_NETLINK;
122*a376eb32SXin Li 
123*a376eb32SXin Li 	req.nlh.nlmsg_len = sizeof(req);
124*a376eb32SXin Li  	req.nlh.nlmsg_type = type;
125*a376eb32SXin Li 	req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
126*a376eb32SXin Li 	req.nlh.nlmsg_pid = 0;
127*a376eb32SXin Li 	req.nlh.nlmsg_seq = rtnl_handle->rtnl_dump = ++(rtnl_handle->rtnl_seq);
128*a376eb32SXin Li 	req.g.rtgen_family = AF_INET;
129*a376eb32SXin Li 
130*a376eb32SXin Li 	return sendto(rtnl_handle->rtnl_fd, &req, sizeof(req), 0,
131*a376eb32SXin Li 		      (struct sockaddr*)&nladdr, sizeof(nladdr));
132*a376eb32SXin Li }
133*a376eb32SXin Li 
134*a376eb32SXin Li /* rtnl_receive - receive netlink packets from rtnetlink socket */
rtnl_receive(struct rtnl_handle * rtnl_handle)135*a376eb32SXin Li int rtnl_receive(struct rtnl_handle *rtnl_handle)
136*a376eb32SXin Li {
137*a376eb32SXin Li 	int status;
138*a376eb32SXin Li 	char buf[8192];
139*a376eb32SXin Li 	struct sockaddr_nl nladdr;
140*a376eb32SXin Li 	struct iovec iov = { buf, sizeof(buf) };
141*a376eb32SXin Li 	struct nlmsghdr *h;
142*a376eb32SXin Li 
143*a376eb32SXin Li 	struct msghdr msg = {
144*a376eb32SXin Li 		.msg_name    = &nladdr,
145*a376eb32SXin Li 		.msg_namelen = sizeof(nladdr),
146*a376eb32SXin Li 		.msg_iov     = &iov,
147*a376eb32SXin Li 		.msg_iovlen  = 1,
148*a376eb32SXin Li 	};
149*a376eb32SXin Li 
150*a376eb32SXin Li 	status = recvmsg(rtnl_handle->rtnl_fd, &msg, 0);
151*a376eb32SXin Li 	if (status < 0) {
152*a376eb32SXin Li 		if (errno == EINTR)
153*a376eb32SXin Li 			return 0;
154*a376eb32SXin Li 		rtnl_log(LOG_NOTICE, "OVERRUN on rtnl socket");
155*a376eb32SXin Li 		return -1;
156*a376eb32SXin Li 	}
157*a376eb32SXin Li 	if (status == 0) {
158*a376eb32SXin Li 		rtnl_log(LOG_ERROR, "EOF on rtnl socket");
159*a376eb32SXin Li 		return -1;
160*a376eb32SXin Li 	}
161*a376eb32SXin Li 	if (msg.msg_namelen != sizeof(nladdr)) {
162*a376eb32SXin Li 		rtnl_log(LOG_ERROR, "invalid address size");
163*a376eb32SXin Li 		return -1;
164*a376eb32SXin Li 	}
165*a376eb32SXin Li 
166*a376eb32SXin Li 	h = (struct nlmsghdr *) buf;
167*a376eb32SXin Li 	while (NLMSG_OK(h, status)) {
168*a376eb32SXin Li #if 0
169*a376eb32SXin Li 		if (h->nlmsg_pid != rtnl_local.nl_pid ||
170*a376eb32SXin Li 		    h->nlmsg_seq != rtnl_dump) {
171*a376eb32SXin Li 			goto skip;
172*a376eb32SXin Li 		}
173*a376eb32SXin Li #endif
174*a376eb32SXin Li 
175*a376eb32SXin Li 		if (h->nlmsg_type == NLMSG_DONE) {
176*a376eb32SXin Li 			rtnl_log(LOG_NOTICE, "NLMSG_DONE");
177*a376eb32SXin Li 			return 0;
178*a376eb32SXin Li 		}
179*a376eb32SXin Li 		if (h->nlmsg_type == NLMSG_ERROR) {
180*a376eb32SXin Li 			struct nlmsgerr *err = NLMSG_DATA(h);
181*a376eb32SXin Li 			if (h->nlmsg_len>=NLMSG_LENGTH(sizeof(struct nlmsgerr)))
182*a376eb32SXin Li 				errno = -err->error;
183*a376eb32SXin Li 			rtnl_log(LOG_ERROR, "NLMSG_ERROR, errnp=%d",
184*a376eb32SXin Li 				 errno);
185*a376eb32SXin Li 			return -1;
186*a376eb32SXin Li 		}
187*a376eb32SXin Li 
188*a376eb32SXin Li 		if (call_handler(rtnl_handle, h->nlmsg_type, h) == 0)
189*a376eb32SXin Li 			rtnl_log(LOG_NOTICE, "unhandled nlmsg_type %u",
190*a376eb32SXin Li 				 h->nlmsg_type);
191*a376eb32SXin Li 		h = NLMSG_NEXT(h, status);
192*a376eb32SXin Li 	}
193*a376eb32SXin Li 	return 1;
194*a376eb32SXin Li }
195*a376eb32SXin Li 
rtnl_receive_multi(struct rtnl_handle * rtnl_handle)196*a376eb32SXin Li int rtnl_receive_multi(struct rtnl_handle *rtnl_handle)
197*a376eb32SXin Li {
198*a376eb32SXin Li 	while (1) {
199*a376eb32SXin Li 		if (rtnl_receive(rtnl_handle) <= 0)
200*a376eb32SXin Li 			break;
201*a376eb32SXin Li 	}
202*a376eb32SXin Li 	return 1;
203*a376eb32SXin Li }
204*a376eb32SXin Li 
205*a376eb32SXin Li /* rtnl_open - constructor of rtnetlink module */
rtnl_open(void)206*a376eb32SXin Li struct rtnl_handle *rtnl_open(void)
207*a376eb32SXin Li {
208*a376eb32SXin Li 	socklen_t addrlen;
209*a376eb32SXin Li 	struct rtnl_handle *h;
210*a376eb32SXin Li 
211*a376eb32SXin Li 	h = calloc(1, sizeof(struct rtnl_handle));
212*a376eb32SXin Li 	if (!h)
213*a376eb32SXin Li 		return NULL;
214*a376eb32SXin Li 
215*a376eb32SXin Li 	addrlen = sizeof(h->rtnl_local);
216*a376eb32SXin Li 
217*a376eb32SXin Li 	h->rtnl_local.nl_pid = getpid();
218*a376eb32SXin Li 	h->rtnl_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
219*a376eb32SXin Li 	if (h->rtnl_fd < 0) {
220*a376eb32SXin Li 		rtnl_log(LOG_ERROR, "unable to create rtnetlink socket");
221*a376eb32SXin Li 		goto err;
222*a376eb32SXin Li 	}
223*a376eb32SXin Li 
224*a376eb32SXin Li 	memset(&h->rtnl_local, 0, sizeof(h->rtnl_local));
225*a376eb32SXin Li 	h->rtnl_local.nl_family = AF_NETLINK;
226*a376eb32SXin Li 	h->rtnl_local.nl_groups = RTMGRP_LINK;
227*a376eb32SXin Li 	if (bind(h->rtnl_fd, (struct sockaddr *) &h->rtnl_local, addrlen) < 0) {
228*a376eb32SXin Li 		rtnl_log(LOG_ERROR, "unable to bind rtnetlink socket");
229*a376eb32SXin Li 		goto err_close;
230*a376eb32SXin Li 	}
231*a376eb32SXin Li 
232*a376eb32SXin Li 	if (getsockname(h->rtnl_fd,
233*a376eb32SXin Li 			(struct sockaddr *) &h->rtnl_local,
234*a376eb32SXin Li 			&addrlen) < 0) {
235*a376eb32SXin Li 		rtnl_log(LOG_ERROR, "cannot gescockname(rtnl_socket)");
236*a376eb32SXin Li 		goto err_close;
237*a376eb32SXin Li 	}
238*a376eb32SXin Li 
239*a376eb32SXin Li 	if (addrlen != sizeof(h->rtnl_local)) {
240*a376eb32SXin Li 		rtnl_log(LOG_ERROR, "invalid address size %u", addr_len);
241*a376eb32SXin Li 		goto err_close;
242*a376eb32SXin Li 	}
243*a376eb32SXin Li 
244*a376eb32SXin Li 	if (h->rtnl_local.nl_family != AF_NETLINK) {
245*a376eb32SXin Li 		rtnl_log(LOG_ERROR, "invalid AF %u", h->rtnl_local.nl_family);
246*a376eb32SXin Li 		goto err_close;
247*a376eb32SXin Li 	}
248*a376eb32SXin Li 
249*a376eb32SXin Li 	h->rtnl_seq = time(NULL);
250*a376eb32SXin Li 
251*a376eb32SXin Li 	return h;
252*a376eb32SXin Li 
253*a376eb32SXin Li err_close:
254*a376eb32SXin Li 	close(h->rtnl_fd);
255*a376eb32SXin Li err:
256*a376eb32SXin Li 	free(h);
257*a376eb32SXin Li 	return NULL;
258*a376eb32SXin Li }
259*a376eb32SXin Li 
260*a376eb32SXin Li /* rtnl_close - destructor of rtnetlink module */
rtnl_close(struct rtnl_handle * rtnl_handle)261*a376eb32SXin Li void rtnl_close(struct rtnl_handle *rtnl_handle)
262*a376eb32SXin Li {
263*a376eb32SXin Li 	close(rtnl_handle->rtnl_fd);
264*a376eb32SXin Li 	free(rtnl_handle);
265*a376eb32SXin Li 	return;
266*a376eb32SXin Li }
267