libmnl
1.0.3
|
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