1 /*
2 * (C) 2008-2010 by Pablo Neira Ayuso <[email protected]>
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
mnl_cb_noop(const struct nlmsghdr * nlh,void * data)14 static int mnl_cb_noop(const struct nlmsghdr *nlh, void *data)
15 {
16 return MNL_CB_OK;
17 }
18
mnl_cb_error(const struct nlmsghdr * nlh,void * data)19 static 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
mnl_cb_stop(const struct nlmsghdr * nlh,void * data)36 static int mnl_cb_stop(const struct nlmsghdr *nlh, void *data)
37 {
38 return MNL_CB_STOP;
39 }
40
41 static 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
__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 static 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 }
95 out:
96 return ret;
97 }
98
99 /**
100 * \defgroup callback Callback helpers
101 * @{
102 */
103
104 /**
105 * mnl_cb_run2 - callback runqueue for netlink messages
106 * \param buf buffer that contains the netlink messages
107 * \param numbytes number of bytes stored in the buffer
108 * \param seq sequence number that we expect to receive
109 * \param portid Netlink PortID that we expect to receive
110 * \param cb_data callback handler for data messages
111 * \param data pointer to data that will be passed to the data callback handler
112 * \param cb_ctl_array array of custom callback handlers from control messages
113 * \param cb_ctl_array_len array length of custom control callback handlers
114 *
115 * You can set the cb_ctl_array to NULL if you want to use the default control
116 * callback handlers, in that case, the parameter cb_ctl_array_len is not
117 * checked.
118 *
119 * Your callback may return three possible values:
120 * - MNL_CB_ERROR (<=-1): an error has occurred. Stop callback runqueue.
121 * - MNL_CB_STOP (=0): stop callback runqueue.
122 * - MNL_CB_OK (>=1): no problem has occurred.
123 *
124 * This function propagates the callback return value. On error, it returns
125 * -1 and errno is explicitly set. If the portID is not the expected, errno
126 * is set to ESRCH. If the sequence number is not the expected, errno is set
127 * to EPROTO. If the dump was interrupted, errno is set to EINTR and you should
128 * request a new fresh dump again.
129 */
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 EXPORT_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
140 /**
141 * mnl_cb_run - callback runqueue for netlink messages (simplified version)
142 * \param buf buffer that contains the netlink messages
143 * \param numbytes number of bytes stored in the buffer
144 * \param seq sequence number that we expect to receive
145 * \param portid Netlink PortID that we expect to receive
146 * \param cb_data callback handler for data messages
147 * \param data pointer to data that will be passed to the data callback handler
148 *
149 * This function is like mnl_cb_run2() but it does not allow you to set
150 * the control callback handlers.
151 *
152 * Your callback may return three possible values:
153 * - MNL_CB_ERROR (<=-1): an error has occurred. Stop callback runqueue.
154 * - MNL_CB_STOP (=0): stop callback runqueue.
155 * - MNL_CB_OK (>=1): no problems has occurred.
156 *
157 * This function propagates the callback return value.
158 */
mnl_cb_run(const void * buf,size_t numbytes,unsigned int seq,unsigned int portid,mnl_cb_t cb_data,void * data)159 EXPORT_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
165 /**
166 * @}
167 */
168