xref: /aosp_15_r20/external/ethtool/libmnl/src/callback.c (revision 1b481fc3bb1b45d4cf28d1ec12969dc1055f555d)
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