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