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
12 #include "libmnl.h"
13
mnl_cb_noop(const struct nlmsghdr * nlh,void * data)14 static int mnl_cb_noop(const struct nlmsghdr *nlh, void *data)
15 {
16 (void)nlh;
17 (void)data;
18 return MNL_CB_OK;
19 }
20
mnl_cb_error(const struct nlmsghdr * nlh,void * data)21 static int mnl_cb_error(const struct nlmsghdr *nlh, void *data)
22 {
23 const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
24 (void)data;
25 if (nlh->nlmsg_len < mnl_nlmsg_size(sizeof(struct nlmsgerr))) {
26 errno = EBADMSG;
27 return MNL_CB_ERROR;
28 }
29 /* Netlink subsystems returns the errno value with different signess */
30 if (err->error < 0)
31 errno = -err->error;
32 else
33 errno = err->error;
34
35 return err->error == 0 ? MNL_CB_STOP : MNL_CB_ERROR;
36 }
37
mnl_cb_stop(const struct nlmsghdr * nlh,void * data)38 static int mnl_cb_stop(const struct nlmsghdr *nlh, void *data)
39 {
40 (void)nlh;
41 (void)data;
42 return MNL_CB_STOP;
43 }
44
45 static const mnl_cb_t default_cb_array[NLMSG_MIN_TYPE] = {
46 [NLMSG_NOOP] = mnl_cb_noop,
47 [NLMSG_ERROR] = mnl_cb_error,
48 [NLMSG_DONE] = mnl_cb_stop,
49 [NLMSG_OVERRUN] = mnl_cb_noop,
50 };
51
__mnl_cb_run(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)52 static inline int __mnl_cb_run(const void *buf, size_t numbytes,
53 unsigned int seq, unsigned int portid,
54 mnl_cb_t cb_data, void *data,
55 const mnl_cb_t *cb_ctl_array,
56 unsigned int cb_ctl_array_len)
57 {
58 int ret = MNL_CB_OK, len = numbytes;
59 const struct nlmsghdr *nlh = buf;
60
61 while (mnl_nlmsg_ok(nlh, len)) {
62 /* check message source */
63 if (!mnl_nlmsg_portid_ok(nlh, portid)) {
64 errno = ESRCH;
65 return -1;
66 }
67 /* perform sequence tracking */
68 if (!mnl_nlmsg_seq_ok(nlh, seq)) {
69 errno = EPROTO;
70 return -1;
71 }
72
73 /* dump was interrupted */
74 if (nlh->nlmsg_flags & NLM_F_DUMP_INTR) {
75 errno = EINTR;
76 return -1;
77 }
78
79 /* netlink data message handling */
80 if (nlh->nlmsg_type >= NLMSG_MIN_TYPE) {
81 if (cb_data){
82 ret = cb_data(nlh, data);
83 if (ret <= MNL_CB_STOP)
84 goto out;
85 }
86 } else if (nlh->nlmsg_type < cb_ctl_array_len) {
87 if (cb_ctl_array && cb_ctl_array[nlh->nlmsg_type]) {
88 ret = cb_ctl_array[nlh->nlmsg_type](nlh, data);
89 if (ret <= MNL_CB_STOP)
90 goto out;
91 }
92 } else if (default_cb_array[nlh->nlmsg_type]) {
93 ret = default_cb_array[nlh->nlmsg_type](nlh, data);
94 if (ret <= MNL_CB_STOP)
95 goto out;
96 }
97 nlh = mnl_nlmsg_next(nlh, &len);
98 }
99 out:
100 return ret;
101 }
102
103 /**
104 * \defgroup callback Callback helpers
105 * @{
106 */
107
108 /**
109 * mnl_cb_run2 - callback runqueue for netlink messages
110 * \param buf buffer that contains the netlink messages
111 * \param numbytes number of bytes stored in the buffer
112 * \param seq sequence number that we expect to receive
113 * \param portid Netlink PortID that we expect to receive
114 * \param cb_data callback handler for data messages
115 * \param data pointer to data that will be passed to the data callback handler
116 * \param cb_ctl_array array of custom callback handlers from control messages
117 * \param cb_ctl_array_len array length of custom control callback handlers
118 *
119 * You can set the cb_ctl_array to NULL if you want to use the default control
120 * callback handlers, in that case, the parameter cb_ctl_array_len is not
121 * checked.
122 *
123 * Your callback may return three possible values:
124 * - MNL_CB_ERROR (<=-1): an error has occurred. Stop callback runqueue.
125 * - MNL_CB_STOP (=0): stop callback runqueue.
126 * - MNL_CB_OK (>=1): no problem has occurred.
127 *
128 * This function propagates the callback return value. On error, it returns
129 * -1 and errno is explicitly set. If the portID is not the expected, errno
130 * is set to ESRCH. If the sequence number is not the expected, errno is set
131 * to EPROTO. If the dump was interrupted, errno is set to EINTR and you should
132 * request a new fresh dump again.
133 */
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)134 int mnl_cb_run2(const void *buf, size_t numbytes,
135 unsigned int seq, unsigned int portid,
136 mnl_cb_t cb_data, void *data,
137 const mnl_cb_t *cb_ctl_array,
138 unsigned int cb_ctl_array_len)
139 {
140 return __mnl_cb_run(buf, numbytes, seq, portid, cb_data, data,
141 cb_ctl_array, cb_ctl_array_len);
142 }
143
144 /**
145 * mnl_cb_run - callback runqueue for netlink messages (simplified version)
146 * \param buf buffer that contains the netlink messages
147 * \param numbytes number of bytes stored in the buffer
148 * \param seq sequence number that we expect to receive
149 * \param portid Netlink PortID that we expect to receive
150 * \param cb_data callback handler for data messages
151 * \param data pointer to data that will be passed to the data callback handler
152 *
153 * This function is like mnl_cb_run2() but it does not allow you to set
154 * the control callback handlers.
155 *
156 * Your callback may return three possible values:
157 * - MNL_CB_ERROR (<=-1): an error has occurred. Stop callback runqueue.
158 * - MNL_CB_STOP (=0): stop callback runqueue.
159 * - MNL_CB_OK (>=1): no problems has occurred.
160 *
161 * This function propagates the callback return value.
162 */
mnl_cb_run(const void * buf,size_t numbytes,unsigned int seq,unsigned int portid,mnl_cb_t cb_data,void * data)163 int mnl_cb_run(const void *buf, size_t numbytes, unsigned int seq,
164 unsigned int portid, mnl_cb_t cb_data, void *data)
165 {
166 return __mnl_cb_run(buf, numbytes, seq, portid, cb_data, data, NULL, 0);
167 }
168
169 /**
170 * @}
171 */
172