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