libmnl 1.0.5
callback.c
1/*
2 * (C) 2008-2010 by Pablo Neira Ayuso <pablo@netfilter.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published
6 * by the Free Software Foundation; either version 2.1 of the License, or
7 * (at your option) any later version.
8 */
9
10#include <errno.h>
11#include <libmnl/libmnl.h>
12#include "internal.h"
13
14static int mnl_cb_noop(const struct nlmsghdr *nlh, void *data)
15{
16 return MNL_CB_OK;
17}
18
19static int mnl_cb_error(const struct nlmsghdr *nlh, void *data)
20{
21 const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
22
23 if (nlh->nlmsg_len < mnl_nlmsg_size(sizeof(struct nlmsgerr))) {
24 errno = EBADMSG;
25 return MNL_CB_ERROR;
26 }
27 /* Netlink subsystems returns the errno value with different signess */
28 if (err->error < 0)
29 errno = -err->error;
30 else
31 errno = err->error;
32
33 return err->error == 0 ? MNL_CB_STOP : MNL_CB_ERROR;
34}
35
36static int mnl_cb_stop(const struct nlmsghdr *nlh, void *data)
37{
38 return MNL_CB_STOP;
39}
40
41static const mnl_cb_t default_cb_array[NLMSG_MIN_TYPE] = {
42 [NLMSG_NOOP] = mnl_cb_noop,
43 [NLMSG_ERROR] = mnl_cb_error,
44 [NLMSG_DONE] = mnl_cb_stop,
45 [NLMSG_OVERRUN] = mnl_cb_noop,
46};
47
48static inline int __mnl_cb_run(const void *buf, size_t numbytes,
49 unsigned int seq, unsigned int portid,
50 mnl_cb_t cb_data, void *data,
51 const mnl_cb_t *cb_ctl_array,
52 unsigned int cb_ctl_array_len)
53{
54 int ret = MNL_CB_OK, len = numbytes;
55 const struct nlmsghdr *nlh = buf;
56
57 while (mnl_nlmsg_ok(nlh, len)) {
58 /* check message source */
59 if (!mnl_nlmsg_portid_ok(nlh, portid)) {
60 errno = ESRCH;
61 return -1;
62 }
63 /* perform sequence tracking */
64 if (!mnl_nlmsg_seq_ok(nlh, seq)) {
65 errno = EPROTO;
66 return -1;
67 }
68
69 /* dump was interrupted */
70 if (nlh->nlmsg_flags & NLM_F_DUMP_INTR) {
71 errno = EINTR;
72 return -1;
73 }
74
75 /* netlink data message handling */
76 if (nlh->nlmsg_type >= NLMSG_MIN_TYPE) {
77 if (cb_data){
78 ret = cb_data(nlh, data);
79 if (ret <= MNL_CB_STOP)
80 goto out;
81 }
82 } else if (nlh->nlmsg_type < cb_ctl_array_len) {
83 if (cb_ctl_array && cb_ctl_array[nlh->nlmsg_type]) {
84 ret = cb_ctl_array[nlh->nlmsg_type](nlh, data);
85 if (ret <= MNL_CB_STOP)
86 goto out;
87 }
88 } else if (default_cb_array[nlh->nlmsg_type]) {
89 ret = default_cb_array[nlh->nlmsg_type](nlh, data);
90 if (ret <= MNL_CB_STOP)
91 goto out;
92 }
93 nlh = mnl_nlmsg_next(nlh, &len);
94 }
95out:
96 return ret;
97}
98
130EXPORT_SYMBOL int mnl_cb_run2(const void *buf, size_t numbytes,
131 unsigned int seq, unsigned int portid,
132 mnl_cb_t cb_data, void *data,
133 const mnl_cb_t *cb_ctl_array,
134 unsigned int cb_ctl_array_len)
135{
136 return __mnl_cb_run(buf, numbytes, seq, portid, cb_data, data,
137 cb_ctl_array, cb_ctl_array_len);
138}
139
159EXPORT_SYMBOL int mnl_cb_run(const void *buf, size_t numbytes, unsigned int seq,
160 unsigned int portid, mnl_cb_t cb_data, void *data)
161{
162 return __mnl_cb_run(buf, numbytes, seq, portid, cb_data, data, NULL, 0);
163}
164
int mnl_cb_run(const void *buf, size_t numbytes, unsigned int seq, unsigned int portid, mnl_cb_t cb_data, void *data)
Definition: callback.c:159
int mnl_cb_run2(const void *buf, size_t numbytes, unsigned int seq, unsigned int portid, mnl_cb_t cb_data, void *data, const mnl_cb_t *cb_ctl_array, unsigned int cb_ctl_array_len)
Definition: callback.c:130
size_t mnl_nlmsg_size(size_t len)
Definition: nlmsg.c:54
bool mnl_nlmsg_seq_ok(const struct nlmsghdr *nlh, unsigned int seq)
Definition: nlmsg.c:206
void * mnl_nlmsg_get_payload(const struct nlmsghdr *nlh)
Definition: nlmsg.c:117
struct nlmsghdr * mnl_nlmsg_next(const struct nlmsghdr *nlh, int *len)
Definition: nlmsg.c:172
bool mnl_nlmsg_ok(const struct nlmsghdr *nlh, int len)
Definition: nlmsg.c:152
bool mnl_nlmsg_portid_ok(const struct nlmsghdr *nlh, unsigned int portid)
Definition: nlmsg.c:226