queue.c

00001 /*
00002  * lib/netfilter/queue.c        Netfilter Queue
00003  *
00004  *      This library is free software; you can redistribute it and/or
00005  *      modify it under the terms of the GNU Lesser General Public
00006  *      License as published by the Free Software Foundation version 2.1
00007  *      of the License.
00008  *
00009  * Copyright (c) 2007, 2008 Patrick McHardy <kaber@trash.net>
00010  */
00011 
00012 /**
00013  * @ingroup nfnl
00014  * @defgroup queue Queue
00015  * @brief
00016  * @{
00017  */
00018 
00019 #include <sys/types.h>
00020 #include <linux/netfilter/nfnetlink_queue.h>
00021 
00022 #include <netlink-local.h>
00023 #include <netlink/attr.h>
00024 #include <netlink/netfilter/nfnl.h>
00025 #include <netlink/netfilter/queue.h>
00026 
00027 struct nl_sock *nfnl_queue_socket_alloc(void)
00028 {
00029         struct nl_sock *nlsk;
00030 
00031         nlsk = nl_socket_alloc();
00032         if (nlsk)
00033                 nl_socket_disable_auto_ack(nlsk);
00034         return nlsk;
00035 }
00036 
00037 static int send_queue_request(struct nl_sock *sk, struct nl_msg *msg)
00038 {
00039         int err;
00040 
00041         err = nl_send_auto_complete(sk, msg);
00042         nlmsg_free(msg);
00043         if (err < 0)
00044                 return err;
00045 
00046         return wait_for_ack(sk);
00047 }
00048 
00049 /**
00050  * @name Queue Commands
00051  * @{
00052  */
00053 
00054 static int build_queue_cmd_request(uint8_t family, uint16_t queuenum,
00055                                    uint8_t command, struct nl_msg **result)
00056 {
00057         struct nl_msg *msg;
00058         struct nfqnl_msg_config_cmd cmd;
00059 
00060         msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_QUEUE, NFQNL_MSG_CONFIG, 0,
00061                                    family, queuenum);
00062         if (msg == NULL)
00063                 return -NLE_NOMEM;
00064 
00065         cmd.pf = htons(family);
00066         cmd._pad = 0;
00067         cmd.command = command;
00068         if (nla_put(msg, NFQA_CFG_CMD, sizeof(cmd), &cmd) < 0)
00069                 goto nla_put_failure;
00070 
00071         *result = msg;
00072         return 0;
00073 
00074 nla_put_failure:
00075         nlmsg_free(msg);
00076         return -NLE_MSGSIZE;
00077 }
00078 
00079 int nfnl_queue_build_pf_bind(uint8_t pf, struct nl_msg **result)
00080 {
00081         return build_queue_cmd_request(pf, 0, NFQNL_CFG_CMD_PF_BIND, result);
00082 }
00083 
00084 int nfnl_queue_pf_bind(struct nl_sock *nlh, uint8_t pf)
00085 {
00086         struct nl_msg *msg;
00087         int err;
00088 
00089         if ((err = nfnl_queue_build_pf_bind(pf, &msg)) < 0)
00090                 return err;
00091 
00092         return send_queue_request(nlh, msg);
00093 }
00094 
00095 int nfnl_queue_build_pf_unbind(uint8_t pf, struct nl_msg **result)
00096 {
00097         return build_queue_cmd_request(pf, 0, NFQNL_CFG_CMD_PF_UNBIND, result);
00098 }
00099 
00100 int nfnl_queue_pf_unbind(struct nl_sock *nlh, uint8_t pf)
00101 {
00102         struct nl_msg *msg;
00103         int err;
00104 
00105         if ((err = nfnl_queue_build_pf_unbind(pf, &msg)) < 0)
00106                 return err;
00107 
00108         return send_queue_request(nlh, msg);
00109 }
00110 
00111 static int nfnl_queue_build_request(const struct nfnl_queue *queue,
00112                                     struct nl_msg **result)
00113 {
00114         struct nl_msg *msg;
00115 
00116         if (!nfnl_queue_test_group(queue))
00117                 return -NLE_MISSING_ATTR;
00118 
00119         msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_QUEUE, NFQNL_MSG_CONFIG, 0,
00120                                    0, nfnl_queue_get_group(queue));
00121         if (msg == NULL)
00122                 return -NLE_NOMEM;
00123 
00124         if (nfnl_queue_test_maxlen(queue) &&
00125             nla_put_u32(msg, NFQA_CFG_QUEUE_MAXLEN,
00126                         htonl(nfnl_queue_get_maxlen(queue))) < 0)
00127                 goto nla_put_failure;
00128 
00129         /* This sucks, the nfnetlink_queue interface always expects both
00130          * parameters to be present. Needs to be done properly.
00131          */
00132         if (nfnl_queue_test_copy_mode(queue)) {
00133                 struct nfqnl_msg_config_params params;
00134 
00135                 switch (nfnl_queue_get_copy_mode(queue)) {
00136                 case NFNL_QUEUE_COPY_NONE:
00137                         params.copy_mode = NFQNL_COPY_NONE;
00138                         break;
00139                 case NFNL_QUEUE_COPY_META:
00140                         params.copy_mode = NFQNL_COPY_META;
00141                         break;
00142                 case NFNL_QUEUE_COPY_PACKET:
00143                         params.copy_mode = NFQNL_COPY_PACKET;
00144                         break;
00145                 }
00146                 params.copy_range = htonl(nfnl_queue_get_copy_range(queue));
00147 
00148                 if (nla_put(msg, NFQA_CFG_PARAMS, sizeof(params), &params) < 0)
00149                         goto nla_put_failure;
00150         }
00151 
00152         *result = msg;
00153         return 0;
00154 
00155 nla_put_failure:
00156         nlmsg_free(msg);
00157         return -NLE_MSGSIZE;
00158 }
00159 
00160 int nfnl_queue_build_create_request(const struct nfnl_queue *queue,
00161                                     struct nl_msg **result)
00162 {
00163         struct nfqnl_msg_config_cmd cmd;
00164         int err;
00165 
00166         if ((err = nfnl_queue_build_request(queue, result)) < 0)
00167                 return err;
00168 
00169         cmd.pf = 0;
00170         cmd._pad = 0;
00171         cmd.command = NFQNL_CFG_CMD_BIND;
00172 
00173         NLA_PUT(*result, NFQA_CFG_CMD, sizeof(cmd), &cmd);
00174 
00175         return 0;
00176 
00177 nla_put_failure:
00178         nlmsg_free(*result);
00179         return -NLE_MSGSIZE;
00180 }
00181 
00182 int nfnl_queue_create(struct nl_sock *nlh, const struct nfnl_queue *queue)
00183 {
00184         struct nl_msg *msg;
00185         int err;
00186 
00187         if ((err = nfnl_queue_build_create_request(queue, &msg)) < 0)
00188                 return err;
00189 
00190         return send_queue_request(nlh, msg);
00191 }
00192 
00193 int nfnl_queue_build_change_request(const struct nfnl_queue *queue,
00194                                     struct nl_msg **result)
00195 {
00196         return nfnl_queue_build_request(queue, result);
00197 }
00198 
00199 int nfnl_queue_change(struct nl_sock *nlh, const struct nfnl_queue *queue)
00200 {
00201         struct nl_msg *msg;
00202         int err;
00203 
00204         if ((err = nfnl_queue_build_change_request(queue, &msg)) < 0)
00205                 return err;
00206 
00207         return send_queue_request(nlh, msg);
00208 }
00209 
00210 int nfnl_queue_build_delete_request(const struct nfnl_queue *queue,
00211                                     struct nl_msg **result)
00212 {
00213         if (!nfnl_queue_test_group(queue))
00214                 return -NLE_MISSING_ATTR;
00215 
00216         return build_queue_cmd_request(0, nfnl_queue_get_group(queue),
00217                                        NFQNL_CFG_CMD_UNBIND, result);
00218 }
00219 
00220 int nfnl_queue_delete(struct nl_sock *nlh, const struct nfnl_queue *queue)
00221 {
00222         struct nl_msg *msg;
00223         int err;
00224 
00225         if ((err = nfnl_queue_build_delete_request(queue, &msg)) < 0)
00226                 return err;
00227 
00228         return send_queue_request(nlh, msg);
00229 }
00230 
00231 /** @} */
00232 
00233 static struct nl_cache_ops nfnl_queue_ops = {
00234         .co_name                = "netfilter/queue",
00235         .co_obj_ops             = &queue_obj_ops,
00236         .co_msgtypes            = {
00237                 END_OF_MSGTYPES_LIST,
00238         },
00239 };
00240 
00241 static void __init nfnl_queue_init(void)
00242 {
00243         nl_cache_mngt_register(&nfnl_queue_ops);
00244 }
00245 
00246 static void __exit nfnl_queue_exit(void)
00247 {
00248         nl_cache_mngt_unregister(&nfnl_queue_ops);
00249 }
00250 
00251 /** @} */