xref: /aosp_15_r20/external/libnl/lib/netfilter/queue.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * Copyright (c) 2007, 2008 Patrick McHardy <[email protected]>
4  */
5 
6 /**
7  * @ingroup nfnl
8  * @defgroup queue Queue
9  * @brief
10  * @{
11  */
12 
13 #include "nl-default.h"
14 
15 #include <sys/types.h>
16 
17 #include <linux/netfilter/nfnetlink_queue.h>
18 
19 #include <netlink/attr.h>
20 #include <netlink/netfilter/nfnl.h>
21 #include <netlink/netfilter/queue.h>
22 
23 #include "nl-priv-dynamic-core/nl-core.h"
24 #include "nl-priv-dynamic-core/cache-api.h"
25 
nfnl_queue_socket_alloc(void)26 struct nl_sock *nfnl_queue_socket_alloc(void)
27 {
28 	struct nl_sock *nlsk;
29 
30 	nlsk = nl_socket_alloc();
31 	if (nlsk)
32 		nl_socket_disable_auto_ack(nlsk);
33 	return nlsk;
34 }
35 
send_queue_request(struct nl_sock * sk,struct nl_msg * msg)36 static int send_queue_request(struct nl_sock *sk, struct nl_msg *msg)
37 {
38 	int err;
39 
40 	err = nl_send_auto_complete(sk, msg);
41 	nlmsg_free(msg);
42 	if (err < 0)
43 		return err;
44 
45 	return wait_for_ack(sk);
46 }
47 
48 /**
49  * @name Queue Commands
50  * @{
51  */
52 
build_queue_cmd_request(uint8_t family,uint16_t queuenum,uint8_t command,struct nl_msg ** result)53 static int build_queue_cmd_request(uint8_t family, uint16_t queuenum,
54 				   uint8_t command, struct nl_msg **result)
55 {
56 	struct nl_msg *msg;
57 	struct nfqnl_msg_config_cmd cmd;
58 
59 	msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_QUEUE, NFQNL_MSG_CONFIG, 0,
60 				   family, queuenum);
61 	if (msg == NULL)
62 		return -NLE_NOMEM;
63 
64 	cmd.pf = htons(family);
65 	cmd._pad = 0;
66 	cmd.command = command;
67 	if (nla_put(msg, NFQA_CFG_CMD, sizeof(cmd), &cmd) < 0)
68 		goto nla_put_failure;
69 
70 	*result = msg;
71 	return 0;
72 
73 nla_put_failure:
74 	nlmsg_free(msg);
75 	return -NLE_MSGSIZE;
76 }
77 
nfnl_queue_build_pf_bind(uint8_t pf,struct nl_msg ** result)78 int nfnl_queue_build_pf_bind(uint8_t pf, struct nl_msg **result)
79 {
80 	return build_queue_cmd_request(pf, 0, NFQNL_CFG_CMD_PF_BIND, result);
81 }
82 
nfnl_queue_pf_bind(struct nl_sock * nlh,uint8_t pf)83 int nfnl_queue_pf_bind(struct nl_sock *nlh, uint8_t pf)
84 {
85 	struct nl_msg *msg;
86 	int err;
87 
88 	if ((err = nfnl_queue_build_pf_bind(pf, &msg)) < 0)
89 		return err;
90 
91 	return send_queue_request(nlh, msg);
92 }
93 
nfnl_queue_build_pf_unbind(uint8_t pf,struct nl_msg ** result)94 int nfnl_queue_build_pf_unbind(uint8_t pf, struct nl_msg **result)
95 {
96 	return build_queue_cmd_request(pf, 0, NFQNL_CFG_CMD_PF_UNBIND, result);
97 }
98 
nfnl_queue_pf_unbind(struct nl_sock * nlh,uint8_t pf)99 int nfnl_queue_pf_unbind(struct nl_sock *nlh, uint8_t pf)
100 {
101 	struct nl_msg *msg;
102 	int err;
103 
104 	if ((err = nfnl_queue_build_pf_unbind(pf, &msg)) < 0)
105 		return err;
106 
107 	return send_queue_request(nlh, msg);
108 }
109 
nfnl_queue_build_request(const struct nfnl_queue * queue,struct nl_msg ** result)110 static int nfnl_queue_build_request(const struct nfnl_queue *queue,
111 				    struct nl_msg **result)
112 {
113 	struct nl_msg *msg;
114 
115 	if (!nfnl_queue_test_group(queue))
116 		return -NLE_MISSING_ATTR;
117 
118 	msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_QUEUE, NFQNL_MSG_CONFIG, 0,
119 				   0, nfnl_queue_get_group(queue));
120 	if (msg == NULL)
121 		return -NLE_NOMEM;
122 
123 	if (nfnl_queue_test_maxlen(queue) &&
124 	    nla_put_u32(msg, NFQA_CFG_QUEUE_MAXLEN,
125 			htonl(nfnl_queue_get_maxlen(queue))) < 0)
126 		goto nla_put_failure;
127 
128 	/* This sucks, the nfnetlink_queue interface always expects both
129 	 * parameters to be present. Needs to be done properly.
130 	 */
131 	if (nfnl_queue_test_copy_mode(queue)) {
132 		struct nfqnl_msg_config_params params;
133 
134 		switch (nfnl_queue_get_copy_mode(queue)) {
135 		case NFNL_QUEUE_COPY_NONE:
136 			params.copy_mode = NFQNL_COPY_NONE;
137 			break;
138 		case NFNL_QUEUE_COPY_META:
139 			params.copy_mode = NFQNL_COPY_META;
140 			break;
141 		case NFNL_QUEUE_COPY_PACKET:
142 			params.copy_mode = NFQNL_COPY_PACKET;
143 			break;
144 		}
145 		params.copy_range = htonl(nfnl_queue_get_copy_range(queue));
146 
147 		if (nla_put(msg, NFQA_CFG_PARAMS, sizeof(params), &params) < 0)
148 			goto nla_put_failure;
149 	}
150 
151 	*result = msg;
152 	return 0;
153 
154 nla_put_failure:
155 	nlmsg_free(msg);
156 	return -NLE_MSGSIZE;
157 }
158 
nfnl_queue_build_create_request(const struct nfnl_queue * queue,struct nl_msg ** result)159 int nfnl_queue_build_create_request(const struct nfnl_queue *queue,
160 				    struct nl_msg **result)
161 {
162 	struct nfqnl_msg_config_cmd cmd;
163 	int err;
164 
165 	if ((err = nfnl_queue_build_request(queue, result)) < 0)
166 		return err;
167 
168 	cmd.pf = 0;
169 	cmd._pad = 0;
170 	cmd.command = NFQNL_CFG_CMD_BIND;
171 
172 	NLA_PUT(*result, NFQA_CFG_CMD, sizeof(cmd), &cmd);
173 
174 	return 0;
175 
176 nla_put_failure:
177 	nlmsg_free(*result);
178 	return -NLE_MSGSIZE;
179 }
180 
nfnl_queue_create(struct nl_sock * nlh,const struct nfnl_queue * queue)181 int nfnl_queue_create(struct nl_sock *nlh, const struct nfnl_queue *queue)
182 {
183 	struct nl_msg *msg;
184 	int err;
185 
186 	if ((err = nfnl_queue_build_create_request(queue, &msg)) < 0)
187 		return err;
188 
189 	return send_queue_request(nlh, msg);
190 }
191 
nfnl_queue_build_change_request(const struct nfnl_queue * queue,struct nl_msg ** result)192 int nfnl_queue_build_change_request(const struct nfnl_queue *queue,
193 				    struct nl_msg **result)
194 {
195 	return nfnl_queue_build_request(queue, result);
196 }
197 
nfnl_queue_change(struct nl_sock * nlh,const struct nfnl_queue * queue)198 int nfnl_queue_change(struct nl_sock *nlh, const struct nfnl_queue *queue)
199 {
200 	struct nl_msg *msg;
201 	int err;
202 
203 	if ((err = nfnl_queue_build_change_request(queue, &msg)) < 0)
204 		return err;
205 
206 	return send_queue_request(nlh, msg);
207 }
208 
nfnl_queue_build_delete_request(const struct nfnl_queue * queue,struct nl_msg ** result)209 int nfnl_queue_build_delete_request(const struct nfnl_queue *queue,
210 				    struct nl_msg **result)
211 {
212 	if (!nfnl_queue_test_group(queue))
213 		return -NLE_MISSING_ATTR;
214 
215 	return build_queue_cmd_request(0, nfnl_queue_get_group(queue),
216 				       NFQNL_CFG_CMD_UNBIND, result);
217 }
218 
nfnl_queue_delete(struct nl_sock * nlh,const struct nfnl_queue * queue)219 int nfnl_queue_delete(struct nl_sock *nlh, const struct nfnl_queue *queue)
220 {
221 	struct nl_msg *msg;
222 	int err;
223 
224 	if ((err = nfnl_queue_build_delete_request(queue, &msg)) < 0)
225 		return err;
226 
227 	return send_queue_request(nlh, msg);
228 }
229 
230 /** @} */
231 
232 static struct nl_cache_ops nfnl_queue_ops = {
233 	.co_name		= "netfilter/queue",
234 	.co_obj_ops		= &queue_obj_ops,
235 	.co_msgtypes		= {
236 		END_OF_MSGTYPES_LIST,
237 	},
238 };
239 
nfnl_queue_init(void)240 static void _nl_init nfnl_queue_init(void)
241 {
242 	nl_cache_mngt_register(&nfnl_queue_ops);
243 }
244 
nfnl_queue_exit(void)245 static void _nl_exit nfnl_queue_exit(void)
246 {
247 	nl_cache_mngt_unregister(&nfnl_queue_ops);
248 }
249 
250 /** @} */
251