libmnl  1.0.3
callback.c
00001 /*
00002  * (C) 2008-2010 by Pablo Neira Ayuso <pablo@netfilter.org>
00003  *
00004  * This program is free software; you can redistribute it and/or modify
00005  * it under the terms of the GNU Lesser General Public License as published
00006  * by the Free Software Foundation; either version 2.1 of the License, or
00007  * (at your option) any later version.
00008  */
00009 
00010 #include <errno.h>
00011 #include <libmnl/libmnl.h>
00012 #include "internal.h"
00013 
00014 static int mnl_cb_noop(const struct nlmsghdr *nlh, void *data)
00015 {
00016         return MNL_CB_OK;
00017 }
00018 
00019 static int mnl_cb_error(const struct nlmsghdr *nlh, void *data)
00020 {
00021         const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
00022 
00023         if (nlh->nlmsg_len < mnl_nlmsg_size(sizeof(struct nlmsgerr))) {
00024                 errno = EBADMSG; 
00025                 return MNL_CB_ERROR;
00026         }
00027         /* Netlink subsystems returns the errno value with different signess */
00028         if (err->error < 0)
00029                 errno = -err->error;
00030         else
00031                 errno = err->error;
00032 
00033         return err->error == 0 ? MNL_CB_STOP : MNL_CB_ERROR;
00034 }
00035 
00036 static int mnl_cb_stop(const struct nlmsghdr *nlh, void *data)
00037 {
00038         return MNL_CB_STOP;
00039 }
00040 
00041 static const mnl_cb_t default_cb_array[NLMSG_MIN_TYPE] = {
00042         [NLMSG_NOOP]    = mnl_cb_noop,
00043         [NLMSG_ERROR]   = mnl_cb_error,
00044         [NLMSG_DONE]    = mnl_cb_stop,
00045         [NLMSG_OVERRUN] = mnl_cb_noop,
00046 };
00047 
00048 static inline int
00049 __mnl_cb_run(const void *buf, size_t numbytes, unsigned int seq,
00050              unsigned int portid, mnl_cb_t cb_data, void *data,
00051              mnl_cb_t *cb_ctl_array, unsigned int cb_ctl_array_len)
00052 {
00053         int ret = MNL_CB_OK, len = numbytes;
00054         const struct nlmsghdr *nlh = buf;
00055 
00056         while (mnl_nlmsg_ok(nlh, len)) {
00057                 /* check message source */
00058                 if (!mnl_nlmsg_portid_ok(nlh, portid)) {
00059                         errno = ESRCH;
00060                         return -1;
00061                 }
00062                 /* perform sequence tracking */
00063                 if (!mnl_nlmsg_seq_ok(nlh, seq)) {
00064                         errno = EPROTO;
00065                         return -1;
00066                 }
00067 
00068                 /* netlink data message handling */
00069                 if (nlh->nlmsg_type >= NLMSG_MIN_TYPE) { 
00070                         if (cb_data){
00071                                 ret = cb_data(nlh, data);
00072                                 if (ret <= MNL_CB_STOP)
00073                                         goto out;
00074                         }
00075                 } else if (nlh->nlmsg_type < cb_ctl_array_len) {
00076                         if (cb_ctl_array && cb_ctl_array[nlh->nlmsg_type]) {
00077                                 ret = cb_ctl_array[nlh->nlmsg_type](nlh, data);
00078                                 if (ret <= MNL_CB_STOP)
00079                                         goto out;
00080                         }
00081                 } else if (default_cb_array[nlh->nlmsg_type]) {
00082                         ret = default_cb_array[nlh->nlmsg_type](nlh, data);
00083                         if (ret <= MNL_CB_STOP)
00084                                 goto out;
00085                 }
00086                 nlh = mnl_nlmsg_next(nlh, &len);
00087         }
00088 out:
00089         return ret;
00090 }
00091 
00122 int
00123 mnl_cb_run2(const void *buf, size_t numbytes, unsigned int seq,
00124             unsigned int portid, mnl_cb_t cb_data, void *data,
00125             mnl_cb_t *cb_ctl_array, unsigned int cb_ctl_array_len)
00126 {
00127         return __mnl_cb_run(buf, numbytes, seq, portid, cb_data, data,
00128                             cb_ctl_array, cb_ctl_array_len);
00129 }
00130 EXPORT_SYMBOL(mnl_cb_run2);
00131 
00151 int
00152 mnl_cb_run(const void *buf, size_t numbytes, unsigned int seq,
00153            unsigned int portid, mnl_cb_t cb_data, void *data)
00154 {
00155         return __mnl_cb_run(buf, numbytes, seq, portid, cb_data, data, NULL, 0);
00156 }
00157 EXPORT_SYMBOL(mnl_cb_run);
00158