Home | History | Annotate | Download | only in lib
      1 /*
      2  * lib/handlers.c	default netlink message handlers
      3  *
      4  *	This library is free software; you can redistribute it and/or
      5  *	modify it under the terms of the GNU Lesser General Public
      6  *	License as published by the Free Software Foundation version 2.1
      7  *	of the License.
      8  *
      9  * Copyright (c) 2003-2008 Thomas Graf <tgraf (at) suug.ch>
     10  */
     11 
     12 /**
     13  * @ingroup core
     14  * @defgroup cb Callbacks/Customization
     15  *
     16  * Related sections in the development guide:
     17  * - @core_doc{core_cb, Callback Configuration}
     18  *
     19  * @{
     20  *
     21  * Header
     22  * ------
     23  * ~~~~{.c}
     24  * #include <netlink/handlers.h>
     25  * ~~~~
     26  */
     27 
     28 #include <netlink-private/netlink.h>
     29 #include <netlink/netlink.h>
     30 #include <netlink/utils.h>
     31 #include <netlink/msg.h>
     32 #include <netlink/handlers.h>
     33 
     34 static void print_header_content(FILE *ofd, struct nlmsghdr *n)
     35 {
     36 	char flags[128];
     37 	char type[32];
     38 
     39 	fprintf(ofd, "type=%s length=%u flags=<%s> sequence-nr=%u pid=%u",
     40 		nl_nlmsgtype2str(n->nlmsg_type, type, sizeof(type)),
     41 		n->nlmsg_len, nl_nlmsg_flags2str(n->nlmsg_flags, flags,
     42 		sizeof(flags)), n->nlmsg_seq, n->nlmsg_pid);
     43 }
     44 
     45 static int nl_valid_handler_verbose(struct nl_msg *msg, void *arg)
     46 {
     47 	FILE *ofd = arg ? arg : stdout;
     48 
     49 	fprintf(ofd, "-- Warning: unhandled valid message: ");
     50 	print_header_content(ofd, nlmsg_hdr(msg));
     51 	fprintf(ofd, "\n");
     52 
     53 	return NL_OK;
     54 }
     55 
     56 static int nl_invalid_handler_verbose(struct nl_msg *msg, void *arg)
     57 {
     58 	FILE *ofd = arg ? arg : stderr;
     59 
     60 	fprintf(ofd, "-- Error: Invalid message: ");
     61 	print_header_content(ofd, nlmsg_hdr(msg));
     62 	fprintf(ofd, "\n");
     63 
     64 	return NL_STOP;
     65 }
     66 
     67 static int nl_overrun_handler_verbose(struct nl_msg *msg, void *arg)
     68 {
     69 	FILE *ofd = arg ? arg : stderr;
     70 
     71 	fprintf(ofd, "-- Error: Netlink Overrun: ");
     72 	print_header_content(ofd, nlmsg_hdr(msg));
     73 	fprintf(ofd, "\n");
     74 
     75 	return NL_STOP;
     76 }
     77 
     78 static int nl_error_handler_verbose(struct sockaddr_nl *who,
     79 				    struct nlmsgerr *e, void *arg)
     80 {
     81 	FILE *ofd = arg ? arg : stderr;
     82 	char buf[256];
     83 
     84 	fprintf(ofd, "-- Error received: %s\n-- Original message: ",
     85 		strerror_r(-e->error, buf, sizeof(buf)));
     86 	print_header_content(ofd, &e->msg);
     87 	fprintf(ofd, "\n");
     88 
     89 	return -nl_syserr2nlerr(e->error);
     90 }
     91 
     92 static int nl_valid_handler_debug(struct nl_msg *msg, void *arg)
     93 {
     94 	FILE *ofd = arg ? arg : stderr;
     95 
     96 	fprintf(ofd, "-- Debug: Unhandled Valid message: ");
     97 	print_header_content(ofd, nlmsg_hdr(msg));
     98 	fprintf(ofd, "\n");
     99 
    100 	return NL_OK;
    101 }
    102 
    103 static int nl_finish_handler_debug(struct nl_msg *msg, void *arg)
    104 {
    105 	FILE *ofd = arg ? arg : stderr;
    106 
    107 	fprintf(ofd, "-- Debug: End of multipart message block: ");
    108 	print_header_content(ofd, nlmsg_hdr(msg));
    109 	fprintf(ofd, "\n");
    110 
    111 	return NL_STOP;
    112 }
    113 
    114 static int nl_msg_in_handler_debug(struct nl_msg *msg, void *arg)
    115 {
    116 	FILE *ofd = arg ? arg : stderr;
    117 
    118 	fprintf(ofd, "-- Debug: Received Message:\n");
    119 	nl_msg_dump(msg, ofd);
    120 
    121 	return NL_OK;
    122 }
    123 
    124 static int nl_msg_out_handler_debug(struct nl_msg *msg, void *arg)
    125 {
    126 	FILE *ofd = arg ? arg : stderr;
    127 
    128 	fprintf(ofd, "-- Debug: Sent Message:\n");
    129 	nl_msg_dump(msg, ofd);
    130 
    131 	return NL_OK;
    132 }
    133 
    134 static int nl_skipped_handler_debug(struct nl_msg *msg, void *arg)
    135 {
    136 	FILE *ofd = arg ? arg : stderr;
    137 
    138 	fprintf(ofd, "-- Debug: Skipped message: ");
    139 	print_header_content(ofd, nlmsg_hdr(msg));
    140 	fprintf(ofd, "\n");
    141 
    142 	return NL_SKIP;
    143 }
    144 
    145 static int nl_ack_handler_debug(struct nl_msg *msg, void *arg)
    146 {
    147 	FILE *ofd = arg ? arg : stderr;
    148 
    149 	fprintf(ofd, "-- Debug: ACK: ");
    150 	print_header_content(ofd, nlmsg_hdr(msg));
    151 	fprintf(ofd, "\n");
    152 
    153 	return NL_STOP;
    154 }
    155 
    156 static nl_recvmsg_msg_cb_t cb_def[NL_CB_TYPE_MAX+1][NL_CB_KIND_MAX+1] = {
    157 	[NL_CB_VALID] = {
    158 		[NL_CB_VERBOSE]	= nl_valid_handler_verbose,
    159 		[NL_CB_DEBUG]	= nl_valid_handler_debug,
    160 	},
    161 	[NL_CB_FINISH] = {
    162 		[NL_CB_DEBUG]	= nl_finish_handler_debug,
    163 	},
    164 	[NL_CB_INVALID] = {
    165 		[NL_CB_VERBOSE]	= nl_invalid_handler_verbose,
    166 		[NL_CB_DEBUG]	= nl_invalid_handler_verbose,
    167 	},
    168 	[NL_CB_MSG_IN] = {
    169 		[NL_CB_DEBUG]	= nl_msg_in_handler_debug,
    170 	},
    171 	[NL_CB_MSG_OUT] = {
    172 		[NL_CB_DEBUG]	= nl_msg_out_handler_debug,
    173 	},
    174 	[NL_CB_OVERRUN] = {
    175 		[NL_CB_VERBOSE]	= nl_overrun_handler_verbose,
    176 		[NL_CB_DEBUG]	= nl_overrun_handler_verbose,
    177 	},
    178 	[NL_CB_SKIPPED] = {
    179 		[NL_CB_DEBUG]	= nl_skipped_handler_debug,
    180 	},
    181 	[NL_CB_ACK] = {
    182 		[NL_CB_DEBUG]	= nl_ack_handler_debug,
    183 	},
    184 };
    185 
    186 static nl_recvmsg_err_cb_t cb_err_def[NL_CB_KIND_MAX+1] = {
    187 	[NL_CB_VERBOSE]	= nl_error_handler_verbose,
    188 	[NL_CB_DEBUG]	= nl_error_handler_verbose,
    189 };
    190 
    191 /**
    192  * @name Callback Handle Management
    193  * @{
    194  */
    195 
    196 /**
    197  * Allocate a new callback handle
    198  * @arg kind		callback kind to be used for initialization
    199  * @return Newly allocated callback handle or NULL
    200  */
    201 struct nl_cb *nl_cb_alloc(enum nl_cb_kind kind)
    202 {
    203 	int i;
    204 	struct nl_cb *cb;
    205 
    206 	if (kind < 0 || kind > NL_CB_KIND_MAX)
    207 		return NULL;
    208 
    209 	cb = calloc(1, sizeof(*cb));
    210 	if (!cb)
    211 		return NULL;
    212 
    213 	cb->cb_refcnt = 1;
    214 	cb->cb_active = NL_CB_TYPE_MAX + 1;
    215 
    216 	for (i = 0; i <= NL_CB_TYPE_MAX; i++)
    217 		nl_cb_set(cb, i, kind, NULL, NULL);
    218 
    219 	nl_cb_err(cb, kind, NULL, NULL);
    220 
    221 	return cb;
    222 }
    223 
    224 /**
    225  * Clone an existing callback handle
    226  * @arg orig		original callback handle
    227  * @return Newly allocated callback handle being a duplicate of
    228  *         orig or NULL
    229  */
    230 struct nl_cb *nl_cb_clone(struct nl_cb *orig)
    231 {
    232 	struct nl_cb *cb;
    233 
    234 	cb = nl_cb_alloc(NL_CB_DEFAULT);
    235 	if (!cb)
    236 		return NULL;
    237 
    238 	memcpy(cb, orig, sizeof(*orig));
    239 	cb->cb_refcnt = 1;
    240 
    241 	return cb;
    242 }
    243 
    244 struct nl_cb *nl_cb_get(struct nl_cb *cb)
    245 {
    246 	cb->cb_refcnt++;
    247 
    248 	return cb;
    249 }
    250 
    251 void nl_cb_put(struct nl_cb *cb)
    252 {
    253 	if (!cb)
    254 		return;
    255 
    256 	cb->cb_refcnt--;
    257 
    258 	if (cb->cb_refcnt < 0)
    259 		BUG();
    260 
    261 	if (cb->cb_refcnt <= 0)
    262 		free(cb);
    263 }
    264 
    265 /**
    266  * Obtain type of current active callback
    267  * @arg cb		callback to query
    268  *
    269  * @return type or __NL_CB_TYPE_MAX if none active
    270  */
    271 enum nl_cb_type nl_cb_active_type(struct nl_cb *cb)
    272 {
    273 	return cb->cb_active;
    274 }
    275 
    276 /** @} */
    277 
    278 /**
    279  * @name Callback Setup
    280  * @{
    281  */
    282 
    283 /**
    284  * Set up a callback
    285  * @arg cb		callback set
    286  * @arg type		callback to modify
    287  * @arg kind		kind of implementation
    288  * @arg func		callback function (NL_CB_CUSTOM)
    289  * @arg arg		argument passed to callback
    290  *
    291  * @return 0 on success or a negative error code
    292  */
    293 int nl_cb_set(struct nl_cb *cb, enum nl_cb_type type, enum nl_cb_kind kind,
    294 	      nl_recvmsg_msg_cb_t func, void *arg)
    295 {
    296 	if (type < 0 || type > NL_CB_TYPE_MAX)
    297 		return -NLE_RANGE;
    298 
    299 	if (kind < 0 || kind > NL_CB_KIND_MAX)
    300 		return -NLE_RANGE;
    301 
    302 	if (kind == NL_CB_CUSTOM) {
    303 		cb->cb_set[type] = func;
    304 		cb->cb_args[type] = arg;
    305 	} else {
    306 		cb->cb_set[type] = cb_def[type][kind];
    307 		cb->cb_args[type] = arg;
    308 	}
    309 
    310 	return 0;
    311 }
    312 
    313 /**
    314  * Set up a all callbacks
    315  * @arg cb		callback set
    316  * @arg kind		kind of callback
    317  * @arg func		callback function
    318  * @arg arg		argument to be passwd to callback function
    319  *
    320  * @return 0 on success or a negative error code
    321  */
    322 int nl_cb_set_all(struct nl_cb *cb, enum nl_cb_kind kind,
    323 		  nl_recvmsg_msg_cb_t func, void *arg)
    324 {
    325 	int i, err;
    326 
    327 	for (i = 0; i <= NL_CB_TYPE_MAX; i++) {
    328 		err = nl_cb_set(cb, i, kind, func, arg);
    329 		if (err < 0)
    330 			return err;
    331 	}
    332 
    333 	return 0;
    334 }
    335 
    336 /**
    337  * Set up an error callback
    338  * @arg cb		callback set
    339  * @arg kind		kind of callback
    340  * @arg func		callback function
    341  * @arg arg		argument to be passed to callback function
    342  */
    343 int nl_cb_err(struct nl_cb *cb, enum nl_cb_kind kind,
    344 	      nl_recvmsg_err_cb_t func, void *arg)
    345 {
    346 	if (kind < 0 || kind > NL_CB_KIND_MAX)
    347 		return -NLE_RANGE;
    348 
    349 	if (kind == NL_CB_CUSTOM) {
    350 		cb->cb_err = func;
    351 		cb->cb_err_arg = arg;
    352 	} else {
    353 		cb->cb_err = cb_err_def[kind];
    354 		cb->cb_err_arg = arg;
    355 	}
    356 
    357 	return 0;
    358 }
    359 
    360 /** @} */
    361 
    362 /**
    363  * @name Overwriting
    364  * @{
    365  */
    366 
    367 /**
    368  * Overwrite internal calls to nl_recvmsgs()
    369  * @arg cb		callback set
    370  * @arg func		replacement callback for nl_recvmsgs()
    371  */
    372 void nl_cb_overwrite_recvmsgs(struct nl_cb *cb,
    373 			      int (*func)(struct nl_sock *, struct nl_cb *))
    374 {
    375 	cb->cb_recvmsgs_ow = func;
    376 }
    377 
    378 /**
    379  * Overwrite internal calls to nl_recv()
    380  * @arg cb		callback set
    381  * @arg func		replacement callback for nl_recv()
    382  */
    383 void nl_cb_overwrite_recv(struct nl_cb *cb,
    384 			  int (*func)(struct nl_sock *, struct sockaddr_nl *,
    385 				      unsigned char **, struct ucred **))
    386 {
    387 	cb->cb_recv_ow = func;
    388 }
    389 
    390 /**
    391  * Overwrite internal calls to nl_send()
    392  * @arg cb		callback set
    393  * @arg func		replacement callback for nl_send()
    394  */
    395 void nl_cb_overwrite_send(struct nl_cb *cb,
    396 			  int (*func)(struct nl_sock *, struct nl_msg *))
    397 {
    398 	cb->cb_send_ow = func;
    399 }
    400 
    401 /** @} */
    402 
    403 /** @} */
    404