1/*
2 * lib/netfilter/nfnl.c		Netfilter Netlink
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) 2003-2008 Thomas Graf <tgraf@suug.ch>
10 * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
11 * Copyright (c) 2007 Secure Computing Corporation
12 */
13
14/**
15 * @defgroup nfnl Netfilter Netlink
16 *
17 * @par Message Format
18 * @code
19 *  <------- NLMSG_ALIGN(hlen) ------> <---- NLMSG_ALIGN(len) --->
20 * +----------------------------+- - -+- - - - - - - - - - -+- - -+
21 * |           Header           | Pad |       Payload       | Pad |
22 * |      struct nlmsghdr       |     |                     |     |
23 * +----------------------------+- - -+- - - - - - - - - - -+- - -+
24 * @endcode
25 * @code
26 *  <-------- NFNL_HDRLEN --------->
27 * +--------------------------+- - -+------------+
28 * | Netfilter Netlink Header | Pad | Attributes |
29 * |    struct nfgenmsg       |     |            |
30 * +--------------------------+- - -+------------+
31 * nfnlmsg_attrdata(nfg, hdrlen)-----^
32 * @endcode
33 *
34 * @par 1) Creating a new netfilter netlink message
35 * @code
36 * struct nl_msg *msg;
37 *
38 * // Create a new empty netlink message
39 * msg = nlmsg_alloc();
40 *
41 * // Append the netlink and netfilter netlink message header
42 * hdr = nfnlmsg_put(msg, PID, SEQ, SUBSYS, TYPE, NLM_F_ECHO,
43 *                   FAMILY, RES_ID);
44 *
45 * // Append the attributes.
46 * nla_put_u32(msg, 1, 0x10);
47 *
48 * // Message is ready to be sent.
49 * nl_send_auto_complete(sk, msg);
50 *
51 * // All done? Free the message.
52 * nlmsg_free(msg);
53 * @endcode
54 *
55 * @par 2) Sending of trivial messages
56 * @code
57 * // For trivial messages not requiring any subsys specific header or
58 * // attributes, nfnl_send_simple() may be used to send messages directly.
59 * nfnl_send_simple(sk, SUBSYS, TYPE, 0, FAMILY, RES_ID);
60 * @endcode
61 * @{
62 */
63
64#include <netlink-local.h>
65#include <netlink/netlink.h>
66#include <netlink/netfilter/nfnl.h>
67
68/**
69 * @name Socket Creating
70 * @{
71 */
72
73/**
74 * Create and connect netfilter netlink socket.
75 * @arg sk		Netlink socket.
76 *
77 * Creates a NETLINK_NETFILTER netlink socket, binds the socket and
78 * issues a connection attempt.
79 *
80 * @see nl_connect()
81 *
82 * @return 0 on success or a negative error code.
83 */
84int nfnl_connect(struct nl_sock *sk)
85{
86	return nl_connect(sk, NETLINK_NETFILTER);
87}
88
89/** @} */
90
91/**
92 * @name Sending
93 * @{
94 */
95
96/**
97 * Send trivial netfilter netlink message
98 * @arg sk		Netlink socket.
99 * @arg subsys_id	nfnetlink subsystem
100 * @arg type		nfnetlink message type
101 * @arg flags		message flags
102 * @arg family		nfnetlink address family
103 * @arg res_id		nfnetlink resource id
104 *
105 * @return Newly allocated netlink message or NULL.
106 */
107int nfnl_send_simple(struct nl_sock *sk, uint8_t subsys_id, uint8_t type,
108		     int flags, uint8_t family, uint16_t res_id)
109{
110	struct nfgenmsg hdr = {
111		.nfgen_family = family,
112		.version = NFNETLINK_V0,
113		.res_id = htons(res_id),
114	};
115
116	return nl_send_simple(sk, NFNLMSG_TYPE(subsys_id, type), flags,
117			      &hdr, sizeof(hdr));
118}
119
120/** @} */
121
122/**
123 * @name Message Parsing
124 * @{
125 */
126
127/**
128 * Get netfilter subsystem id from message
129 * @arg nlh	netlink messsage header
130 */
131uint8_t nfnlmsg_subsys(struct nlmsghdr *nlh)
132{
133	return NFNL_SUBSYS_ID(nlh->nlmsg_type);
134}
135
136/**
137 * Get netfilter message type from message
138 * @arg nlh	netlink messsage header
139 */
140uint8_t nfnlmsg_subtype(struct nlmsghdr *nlh)
141{
142	return NFNL_MSG_TYPE(nlh->nlmsg_type);
143}
144
145/**
146 * Get netfilter family from message
147 * @arg nlh	netlink messsage header
148 */
149uint8_t nfnlmsg_family(struct nlmsghdr *nlh)
150{
151	struct nfgenmsg *nfg = nlmsg_data(nlh);
152
153	return nfg->nfgen_family;
154}
155
156/**
157 * Get netfilter resource id from message
158 * @arg nlh	netlink messsage header
159 */
160uint16_t nfnlmsg_res_id(struct nlmsghdr *nlh)
161{
162	struct nfgenmsg *nfg = nlmsg_data(nlh);
163
164	return ntohs(nfg->res_id);
165}
166
167/** @} */
168
169/**
170 * @name Message Building
171 * @{
172 */
173
174static int nfnlmsg_append(struct nl_msg *msg, uint8_t family, uint16_t res_id)
175{
176	struct nfgenmsg *nfg;
177
178	nfg = nlmsg_reserve(msg, sizeof(*nfg), NLMSG_ALIGNTO);
179	if (nfg == NULL)
180		return -NLE_NOMEM;
181
182	nfg->nfgen_family = family;
183	nfg->version = NFNETLINK_V0;
184	nfg->res_id = htons(res_id);
185	NL_DBG(2, "msg %p: Added nfnetlink header family=%d res_id=%d\n",
186	       msg, family, res_id);
187	return 0;
188}
189
190/**
191 * Allocate a new netfilter netlink message
192 * @arg subsys_id	nfnetlink subsystem
193 * @arg type		nfnetlink message type
194 * @arg flags		message flags
195 * @arg family		nfnetlink address family
196 * @arg res_id		nfnetlink resource id
197 *
198 * @return Newly allocated netlink message or NULL.
199 */
200struct nl_msg *nfnlmsg_alloc_simple(uint8_t subsys_id, uint8_t type, int flags,
201				    uint8_t family, uint16_t res_id)
202{
203	struct nl_msg *msg;
204
205	msg = nlmsg_alloc_simple(NFNLMSG_TYPE(subsys_id, type), flags);
206	if (msg == NULL)
207		return NULL;
208
209	if (nfnlmsg_append(msg, family, res_id) < 0)
210		goto nla_put_failure;
211
212	return msg;
213
214nla_put_failure:
215	nlmsg_free(msg);
216	return NULL;
217}
218
219/**
220 * Add netlink and netfilter netlink headers to netlink message
221 * @arg msg		netlink message
222 * @arg pid		netlink process id
223 * @arg seq		sequence number of message
224 * @arg subsys_id	nfnetlink subsystem
225 * @arg type		nfnetlink message type
226 * @arg flags		message flags
227 * @arg family		nfnetlink address family
228 * @arg res_id		nfnetlink resource id
229 */
230int nfnlmsg_put(struct nl_msg *msg, uint32_t pid, uint32_t seq,
231		uint8_t subsys_id, uint8_t type, int flags, uint8_t family,
232		uint16_t res_id)
233{
234	struct nlmsghdr *nlh;
235
236	nlh = nlmsg_put(msg, pid, seq, NFNLMSG_TYPE(subsys_id, type), 0, flags);
237	if (nlh == NULL)
238		return -NLE_MSGSIZE;
239
240	return nfnlmsg_append(msg, family, res_id);
241}
242
243/** @} */
244
245/** @} */
246