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 27struct 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 37static 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 54static 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 74nla_put_failure: 75 nlmsg_free(msg); 76 return -NLE_MSGSIZE; 77} 78 79int 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 84int 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 95int 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 100int 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 111static 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), ¶ms) < 0) 149 goto nla_put_failure; 150 } 151 152 *result = msg; 153 return 0; 154 155nla_put_failure: 156 nlmsg_free(msg); 157 return -NLE_MSGSIZE; 158} 159 160int 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 177nla_put_failure: 178 nlmsg_free(*result); 179 return -NLE_MSGSIZE; 180} 181 182int 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 193int 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 199int 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 210int 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 220int 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 233static 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 241static void __init nfnl_queue_init(void) 242{ 243 nl_cache_mngt_register(&nfnl_queue_ops); 244} 245 246static void __exit nfnl_queue_exit(void) 247{ 248 nl_cache_mngt_unregister(&nfnl_queue_ops); 249} 250 251/** @} */ 252