1/*
2 * (C) 2009 by Pablo Neira Ayuso <pablo@netfilter.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 */
9
10#include <stdlib.h>
11#include <unistd.h>
12#include <net/if.h>
13#include <string.h>
14#include <sys/ioctl.h>
15#include <netinet/in.h>
16#include <errno.h>
17
18#include "conntrackd.h"
19#include "channel.h"
20#include "network.h"
21#include "queue.h"
22
23static struct channel_ops *ops[CHANNEL_MAX];
24extern struct channel_ops channel_mcast;
25extern struct channel_ops channel_udp;
26extern struct channel_ops channel_tcp;
27
28static struct queue *errorq;
29
30int channel_init(void)
31{
32	ops[CHANNEL_MCAST] = &channel_mcast;
33	ops[CHANNEL_UDP] = &channel_udp;
34	ops[CHANNEL_TCP] = &channel_tcp;
35
36	errorq = queue_create("errorq", CONFIG(channelc).error_queue_length, 0);
37	if (errorq == NULL) {
38		return -1;
39	}
40	return 0;
41}
42
43void channel_end(void)
44{
45	queue_destroy(errorq);
46}
47
48struct channel_buffer {
49	char	*data;
50	int	size;
51	int	len;
52};
53
54static struct channel_buffer *
55channel_buffer_open(int mtu, int headersiz)
56{
57	struct channel_buffer *b;
58
59	b = calloc(sizeof(struct channel_buffer), 1);
60	if (b == NULL)
61		return NULL;
62
63	b->size = mtu - headersiz;
64
65	b->data = malloc(b->size);
66	if (b->data == NULL) {
67		free(b);
68		return NULL;
69	}
70	return b;
71}
72
73static void
74channel_buffer_close(struct channel_buffer *b)
75{
76	if (b == NULL)
77		return;
78
79	free(b->data);
80	free(b);
81}
82
83struct channel *
84channel_open(struct channel_conf *cfg)
85{
86	struct channel *c;
87	struct ifreq ifr;
88	int fd;
89
90	if (cfg->channel_type >= CHANNEL_MAX)
91		return NULL;
92	if (!cfg->channel_ifname[0])
93		return NULL;
94	if (cfg->channel_flags >= CHANNEL_F_MAX)
95		return NULL;
96
97	c = calloc(sizeof(struct channel), 1);
98	if (c == NULL)
99		return NULL;
100
101	c->channel_type = cfg->channel_type;
102
103	fd = socket(AF_INET, SOCK_DGRAM, 0);
104	if (fd == -1) {
105		free(c);
106		return NULL;
107	}
108	strncpy(ifr.ifr_name, cfg->channel_ifname, sizeof(ifr.ifr_name));
109
110	if (ioctl(fd, SIOCGIFMTU, &ifr) == -1) {
111		free(c);
112		return NULL;
113	}
114	close(fd);
115	c->channel_ifmtu = ifr.ifr_mtu;
116
117	c->channel_ifindex = if_nametoindex(cfg->channel_ifname);
118	if (c->channel_ifindex == 0) {
119		free(c);
120		return NULL;
121	}
122	c->ops = ops[cfg->channel_type];
123
124	if (cfg->channel_flags & CHANNEL_F_BUFFERED) {
125		c->buffer = channel_buffer_open(c->channel_ifmtu,
126						c->ops->headersiz);
127		if (c->buffer == NULL) {
128			free(c);
129			return NULL;
130		}
131	}
132	c->channel_flags = cfg->channel_flags;
133
134	c->data = c->ops->open(&cfg->u);
135	if (c->data == NULL) {
136		channel_buffer_close(c->buffer);
137		free(c);
138		return NULL;
139	}
140	return c;
141}
142
143void
144channel_close(struct channel *c)
145{
146	c->ops->close(c->data);
147	if (c->channel_flags & CHANNEL_F_BUFFERED)
148		channel_buffer_close(c->buffer);
149	free(c);
150}
151
152struct channel_error {
153	char			*data;
154	int			len;
155};
156
157static void channel_enqueue_errors(struct channel *c)
158{
159	struct queue_object *qobj;
160	struct channel_error *error;
161
162	qobj = queue_object_new(Q_ELEM_ERR, sizeof(struct channel_error));
163	if (qobj == NULL)
164		return;
165
166	error		= (struct channel_error *)qobj->data;
167	error->len	= c->buffer->len;
168
169	error->data = malloc(c->buffer->len);
170	if (error->data == NULL) {
171		queue_object_free(qobj);
172		return;
173	}
174	memcpy(error->data, c->buffer->data, c->buffer->len);
175	if (queue_add(errorq, &qobj->qnode) < 0) {
176		if (errno == ENOSPC) {
177			struct queue_node *tail;
178			struct channel_error *tmp;
179
180			tail = queue_del_head(errorq);
181			tmp = queue_node_data(tail);
182			free(tmp->data);
183			queue_object_free((struct queue_object *)tail);
184
185			queue_add(errorq, &qobj->qnode);
186		}
187	}
188}
189
190static int channel_handle_error_step(struct queue_node *n, const void *data2)
191{
192	struct channel_error *error;
193	const struct channel *c = data2;
194	int ret;
195
196	error = queue_node_data(n);
197	ret = c->ops->send(c->data, error->data, error->len);
198	if (ret != -1) {
199		/* Success. Delete it from the error queue. */
200		queue_del(n);
201		free(error->data);
202		queue_object_free((struct queue_object *)n);
203	} else {
204		/* We failed to deliver, give up now, try later. */
205		return 1;
206	}
207	return 0;
208}
209
210static int channel_handle_errors(struct channel *c)
211{
212	/* there are pending errors that we have to handle. */
213	if (c->channel_flags & CHANNEL_F_ERRORS && queue_len(errorq) > 0) {
214		queue_iterate(errorq, c, channel_handle_error_step);
215		return queue_len(errorq) > 0;
216	}
217	return 0;
218}
219
220int channel_send(struct channel *c, const struct nethdr *net)
221{
222	int ret = 0, len = ntohs(net->len), pending_errors;
223
224	pending_errors = channel_handle_errors(c);
225
226	if (!(c->channel_flags & CHANNEL_F_BUFFERED)) {
227		c->ops->send(c->data, net, len);
228		return 1;
229	}
230retry:
231	if (c->buffer->len + len < c->buffer->size) {
232		memcpy(c->buffer->data + c->buffer->len, net, len);
233		c->buffer->len += len;
234	} else {
235		/* We've got pending packets to deliver, enqueue this
236		 * packet to avoid possible re-ordering. */
237		if (pending_errors) {
238			channel_enqueue_errors(c);
239		} else {
240			ret = c->ops->send(c->data, c->buffer->data,
241					   c->buffer->len);
242			if (ret == -1 &&
243			    (c->channel_flags & CHANNEL_F_ERRORS)) {
244				/* Give it another chance to deliver. */
245				channel_enqueue_errors(c);
246			}
247		}
248		ret = 1;
249		c->buffer->len = 0;
250		goto retry;
251	}
252	return ret;
253}
254
255int channel_send_flush(struct channel *c)
256{
257	int ret, pending_errors;
258
259	pending_errors = channel_handle_errors(c);
260
261	if (!(c->channel_flags & CHANNEL_F_BUFFERED) || c->buffer->len == 0)
262		return 0;
263
264	/* We still have pending errors to deliver, avoid any re-ordering. */
265	if (pending_errors) {
266		channel_enqueue_errors(c);
267	} else {
268		ret = c->ops->send(c->data, c->buffer->data, c->buffer->len);
269		if (ret == -1 && (c->channel_flags & CHANNEL_F_ERRORS)) {
270			/* Give it another chance to deliver it. */
271			channel_enqueue_errors(c);
272		}
273	}
274	c->buffer->len = 0;
275	return 1;
276}
277
278int channel_recv(struct channel *c, char *buf, int size)
279{
280	return c->ops->recv(c->data, buf, size);
281}
282
283int channel_get_fd(struct channel *c)
284{
285	return c->ops->get_fd(c->data);
286}
287
288void channel_stats(struct channel *c, int fd)
289{
290	return c->ops->stats(c, fd);
291}
292
293void channel_stats_extended(struct channel *c, int active,
294			    struct nlif_handle *h, int fd)
295{
296	return c->ops->stats_extended(c, active, h, fd);
297}
298
299int channel_accept_isset(struct channel *c, fd_set *readfds)
300{
301	return c->ops->accept_isset(c, readfds);
302}
303
304int channel_isset(struct channel *c, fd_set *readfds)
305{
306	return c->ops->isset(c, readfds);
307}
308
309int channel_accept(struct channel *c)
310{
311	return c->ops->accept(c);
312}
313
314int channel_type(struct channel *c)
315{
316	return c->ops->type;
317}
318