00001
00002
00003
00004
00005
00006
00007
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
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
00058 if (!mnl_nlmsg_portid_ok(nlh, portid)) {
00059 errno = ESRCH;
00060 return -1;
00061 }
00062
00063 if (!mnl_nlmsg_seq_ok(nlh, seq)) {
00064 errno = EPROTO;
00065 return -1;
00066 }
00067
00068
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 EXPORT_SYMBOL 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
00150 EXPORT_SYMBOL int
00151 mnl_cb_run(const void *buf, size_t numbytes, unsigned int seq,
00152 unsigned int portid, mnl_cb_t cb_data, void *data)
00153 {
00154 return __mnl_cb_run(buf, numbytes, seq, portid, cb_data, data, NULL, 0);
00155 }
00156