xref: /OK3568_Linux_fs/app/forlinx/quectelCM/libmnl/callback.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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