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