Logo Search packages:      
Sourcecode: libnl2 version File versions  Download package

queue.c

/*
 * lib/netfilter/queue.c      Netfilter Queue
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License as published by the Free Software Foundation version 2.1
 *    of the License.
 *
 * Copyright (c) 2007, 2008 Patrick McHardy <kaber@trash.net>
 */

/**
 * @ingroup nfnl
 * @defgroup queue Queue
 * @brief
 * @{
 */

#include <sys/types.h>
#include <linux/netfilter/nfnetlink_queue.h>

#include <netlink-local.h>
#include <netlink/attr.h>
#include <netlink/netfilter/nfnl.h>
#include <netlink/netfilter/queue.h>

struct nl_sock *nfnl_queue_socket_alloc(void)
{
      struct nl_sock *nlsk;

      nlsk = nl_socket_alloc();
      if (nlsk)
            nl_socket_disable_auto_ack(nlsk);
      return nlsk;
}

static int send_queue_request(struct nl_sock *sk, struct nl_msg *msg)
{
      int err;

      err = nl_send_auto_complete(sk, msg);
      nlmsg_free(msg);
      if (err < 0)
            return err;

      return wait_for_ack(sk);
}

/**
 * @name Queue Commands
 * @{
 */

static int build_queue_cmd_request(uint8_t family, uint16_t queuenum,
                           uint8_t command, struct nl_msg **result)
{
      struct nl_msg *msg;
      struct nfqnl_msg_config_cmd cmd;

      msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_QUEUE, NFQNL_MSG_CONFIG, 0,
                           family, queuenum);
      if (msg == NULL)
            return -NLE_NOMEM;

      cmd.pf = htons(family);
      cmd._pad = 0;
      cmd.command = command;
      if (nla_put(msg, NFQA_CFG_CMD, sizeof(cmd), &cmd) < 0)
            goto nla_put_failure;

      *result = msg;
      return 0;

nla_put_failure:
      nlmsg_free(msg);
      return -NLE_MSGSIZE;
}

int nfnl_queue_build_pf_bind(uint8_t pf, struct nl_msg **result)
{
      return build_queue_cmd_request(pf, 0, NFQNL_CFG_CMD_PF_BIND, result);
}

int nfnl_queue_pf_bind(struct nl_sock *nlh, uint8_t pf)
{
      struct nl_msg *msg;
      int err;

      if ((err = nfnl_queue_build_pf_bind(pf, &msg)) < 0)
            return err;

      return send_queue_request(nlh, msg);
}

int nfnl_queue_build_pf_unbind(uint8_t pf, struct nl_msg **result)
{
      return build_queue_cmd_request(pf, 0, NFQNL_CFG_CMD_PF_UNBIND, result);
}

int nfnl_queue_pf_unbind(struct nl_sock *nlh, uint8_t pf)
{
      struct nl_msg *msg;
      int err;

      if ((err = nfnl_queue_build_pf_unbind(pf, &msg)) < 0)
            return err;

      return send_queue_request(nlh, msg);
}

static int nfnl_queue_build_request(const struct nfnl_queue *queue,
                            struct nl_msg **result)
{
      struct nl_msg *msg;

      if (!nfnl_queue_test_group(queue))
            return -NLE_MISSING_ATTR;

      msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_QUEUE, NFQNL_MSG_CONFIG, 0,
                           0, nfnl_queue_get_group(queue));
      if (msg == NULL)
            return -NLE_NOMEM;

      if (nfnl_queue_test_maxlen(queue) &&
          nla_put_u32(msg, NFQA_CFG_QUEUE_MAXLEN,
                  htonl(nfnl_queue_get_maxlen(queue))) < 0)
            goto nla_put_failure;

      /* This sucks, the nfnetlink_queue interface always expects both
       * parameters to be present. Needs to be done properly.
       */
      if (nfnl_queue_test_copy_mode(queue)) {
            struct nfqnl_msg_config_params params;

            switch (nfnl_queue_get_copy_mode(queue)) {
            case NFNL_QUEUE_COPY_NONE:
                  params.copy_mode = NFQNL_COPY_NONE;
                  break;
            case NFNL_QUEUE_COPY_META:
                  params.copy_mode = NFQNL_COPY_META;
                  break;
            case NFNL_QUEUE_COPY_PACKET:
                  params.copy_mode = NFQNL_COPY_PACKET;
                  break;
            }
            params.copy_range = htonl(nfnl_queue_get_copy_range(queue));

            if (nla_put(msg, NFQA_CFG_PARAMS, sizeof(params), &params) < 0)
                  goto nla_put_failure;
      }

      *result = msg;
      return 0;

nla_put_failure:
      nlmsg_free(msg);
      return -NLE_MSGSIZE;
}

int nfnl_queue_build_create_request(const struct nfnl_queue *queue,
                            struct nl_msg **result)
{
      struct nfqnl_msg_config_cmd cmd;
      int err;

      if ((err = nfnl_queue_build_request(queue, result)) < 0)
            return err;

      cmd.pf = 0;
      cmd._pad = 0;
      cmd.command = NFQNL_CFG_CMD_BIND;

      NLA_PUT(*result, NFQA_CFG_CMD, sizeof(cmd), &cmd);

      return 0;

nla_put_failure:
      nlmsg_free(*result);
      return -NLE_MSGSIZE;
}

int nfnl_queue_create(struct nl_sock *nlh, const struct nfnl_queue *queue)
{
      struct nl_msg *msg;
      int err;

      if ((err = nfnl_queue_build_create_request(queue, &msg)) < 0)
            return err;

      return send_queue_request(nlh, msg);
}

int nfnl_queue_build_change_request(const struct nfnl_queue *queue,
                            struct nl_msg **result)
{
      return nfnl_queue_build_request(queue, result);
}

int nfnl_queue_change(struct nl_sock *nlh, const struct nfnl_queue *queue)
{
      struct nl_msg *msg;
      int err;

      if ((err = nfnl_queue_build_change_request(queue, &msg)) < 0)
            return err;

      return send_queue_request(nlh, msg);
}

int nfnl_queue_build_delete_request(const struct nfnl_queue *queue,
                            struct nl_msg **result)
{
      if (!nfnl_queue_test_group(queue))
            return -NLE_MISSING_ATTR;

      return build_queue_cmd_request(0, nfnl_queue_get_group(queue),
                               NFQNL_CFG_CMD_UNBIND, result);
}

int nfnl_queue_delete(struct nl_sock *nlh, const struct nfnl_queue *queue)
{
      struct nl_msg *msg;
      int err;

      if ((err = nfnl_queue_build_delete_request(queue, &msg)) < 0)
            return err;

      return send_queue_request(nlh, msg);
}

/** @} */

static struct nl_cache_ops nfnl_queue_ops = {
      .co_name          = "netfilter/queue",
      .co_obj_ops       = &queue_obj_ops,
      .co_msgtypes            = {
            END_OF_MSGTYPES_LIST,
      },
};

static void __init nfnl_queue_init(void)
{
      nl_cache_mngt_register(&nfnl_queue_ops);
}

static void __exit nfnl_queue_exit(void)
{
      nl_cache_mngt_unregister(&nfnl_queue_ops);
}

/** @} */

Generated by  Doxygen 1.6.0   Back to index