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