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