GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/isakmpd/transport.c Lines: 0 105 0.0 %
Date: 2016-12-06 Branches: 0 92 0.0 %

Line Branch Exec Source
1
/* $OpenBSD: transport.c,v 1.37 2016/03/10 07:32:16 yasuoka Exp $	 */
2
/* $EOM: transport.c,v 1.43 2000/10/10 12:36:39 provos Exp $	 */
3
4
/*
5
 * Copyright (c) 1998, 1999 Niklas Hallqvist.  All rights reserved.
6
 * Copyright (c) 2001, 2004 Håkan Olsson.  All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
28
29
/*
30
 * This code was written under funding by Ericsson Radio Systems.
31
 */
32
33
#include <sys/queue.h>
34
#include <netdb.h>
35
#include <string.h>
36
37
#include "conf.h"
38
#include "exchange.h"
39
#include "log.h"
40
#include "message.h"
41
#include "sa.h"
42
#include "timer.h"
43
#include "transport.h"
44
#include "virtual.h"
45
46
/* If no retransmit limit is given, use this as a default.  */
47
#define RETRANSMIT_DEFAULT 10
48
49
LIST_HEAD(transport_method_list, transport_vtbl) transport_method_list;
50
51
/* Call the reinit function of the various transports.  */
52
void
53
transport_reinit(void)
54
{
55
	struct transport_vtbl *method;
56
57
	for (method = LIST_FIRST(&transport_method_list); method;
58
	    method = LIST_NEXT(method, link))
59
		if (method->reinit)
60
			method->reinit();
61
}
62
63
/* Initialize the transport maintenance module.  */
64
void
65
transport_init(void)
66
{
67
	LIST_INIT(&transport_list);
68
	LIST_INIT(&transport_method_list);
69
}
70
71
/* Register another transport T.  */
72
void
73
transport_setup(struct transport *t, int toplevel)
74
{
75
	if (toplevel) {
76
		/* Only the toplevel (virtual) transport has sendqueues.  */
77
		LOG_DBG((LOG_TRANSPORT, 70,
78
		    "transport_setup: virtual transport %p", t));
79
		TAILQ_INIT(&t->sendq);
80
		TAILQ_INIT(&t->prio_sendq);
81
		t->refcnt = 0;
82
	} else {
83
		/* udp and udp_encap trp goes into the transport list.  */
84
		LOG_DBG((LOG_TRANSPORT, 70,
85
		    "transport_setup: added %p to transport list", t));
86
		LIST_INSERT_HEAD(&transport_list, t, link);
87
		t->refcnt = 1;
88
	}
89
	t->flags = 0;
90
}
91
92
/* Add a referer to transport T.  */
93
void
94
transport_reference(struct transport *t)
95
{
96
	t->refcnt++;
97
	LOG_DBG((LOG_TRANSPORT, 95,
98
	    "transport_reference: transport %p now has %d references", t,
99
	    t->refcnt));
100
}
101
102
/*
103
 * Remove a referer from transport T, removing all of T when no referers left.
104
 */
105
void
106
transport_release(struct transport *t)
107
{
108
	LOG_DBG((LOG_TRANSPORT, 95,
109
	    "transport_release: transport %p had %d references", t,
110
	    t->refcnt));
111
	if (--t->refcnt)
112
		return;
113
114
	LOG_DBG((LOG_TRANSPORT, 70, "transport_release: freeing %p", t));
115
	t->vtbl->remove(t);
116
}
117
118
void
119
transport_report(void)
120
{
121
	struct virtual_transport *v;
122
	struct transport *t;
123
	struct message *msg;
124
125
	for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link)) {
126
		LOG_DBG((LOG_REPORT, 0,
127
		    "transport_report: transport %p flags %x refcnt %d", t,
128
		    t->flags, t->refcnt));
129
130
		/* XXX Report sth on the virtual transport?  */
131
		t->vtbl->report(t);
132
133
		/*
134
		 * This is the reason message_dump_raw lives outside
135
		 * message.c.
136
		 */
137
		v = (struct virtual_transport *)t->virtual;
138
		if ((v->encap_is_active && v->encap == t) ||
139
		    (!v->encap_is_active && v->main == t)) {
140
			for (msg = TAILQ_FIRST(&t->virtual->prio_sendq); msg;
141
			    msg = TAILQ_NEXT(msg, link))
142
				message_dump_raw("udp_report(prio)", msg,
143
				    LOG_REPORT);
144
145
			for (msg = TAILQ_FIRST(&t->virtual->sendq); msg;
146
			    msg = TAILQ_NEXT(msg, link))
147
				message_dump_raw("udp_report", msg,
148
				    LOG_REPORT);
149
		}
150
	}
151
}
152
153
int
154
transport_prio_sendqs_empty(void)
155
{
156
	struct transport *t;
157
158
	for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link))
159
		if (TAILQ_FIRST(&t->virtual->prio_sendq))
160
			return 0;
161
	return 1;
162
}
163
164
/* Register another transport method T.  */
165
void
166
transport_method_add(struct transport_vtbl *t)
167
{
168
	LIST_INSERT_HEAD(&transport_method_list, t, link);
169
}
170
171
/*
172
 * Build up a file descriptor set FDS with all transport descriptors we want
173
 * to read from.  Return the number of file descriptors select(2) needs to
174
 * check in order to cover the ones we setup in here.
175
 */
176
int
177
transport_fd_set(fd_set * fds)
178
{
179
	struct transport *t;
180
	int	n;
181
	int	max = -1;
182
183
	for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link))
184
		if (t->virtual->flags & TRANSPORT_LISTEN) {
185
			n = t->vtbl->fd_set(t, fds, 1);
186
			if (n > max)
187
				max = n;
188
189
			LOG_DBG((LOG_TRANSPORT, 95, "transport_fd_set: "
190
			    "transport %p (virtual %p) fd %d", t,
191
			    t->virtual, n));
192
		}
193
	return max + 1;
194
}
195
196
/*
197
 * Build up a file descriptor set FDS with all the descriptors belonging to
198
 * transport where messages are queued for transmittal.  Return the number
199
 * of file descriptors select(2) needs to check in order to cover the ones
200
 * we setup in here.
201
 */
202
int
203
transport_pending_wfd_set(fd_set * fds)
204
{
205
	struct transport *t;
206
	int	n;
207
	int	max = -1;
208
209
	for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link)) {
210
		if (TAILQ_FIRST(&t->virtual->sendq) ||
211
		    TAILQ_FIRST(&t->virtual->prio_sendq)) {
212
			n = t->vtbl->fd_set(t, fds, 1);
213
			LOG_DBG((LOG_TRANSPORT, 95,
214
			    "transport_pending_wfd_set: "
215
			    "transport %p (virtual %p) fd %d pending", t,
216
			    t->virtual, n));
217
			if (n > max)
218
				max = n;
219
		}
220
	}
221
	return max + 1;
222
}
223
224
/*
225
 * For each transport with a file descriptor in FDS, try to get an
226
 * incoming message and start processing it.
227
 */
228
void
229
transport_handle_messages(fd_set *fds)
230
{
231
	struct transport *t;
232
233
	for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link)) {
234
		if ((t->flags & TRANSPORT_LISTEN) &&
235
		    (*t->vtbl->fd_isset)(t, fds)) {
236
			(*t->virtual->vtbl->handle_message)(t);
237
			(*t->vtbl->fd_set)(t, fds, 0);
238
		}
239
	}
240
}
241
242
/*
243
 * Send the first queued message on the transports found whose file
244
 * descriptor is in FDS and has messages queued.  Remove the fd bit from
245
 * FDS as soon as one message has been sent on it so other transports
246
 * sharing the socket won't get service without an intervening select
247
 * call.  Perhaps a fairness strategy should be implemented between
248
 * such transports.  Now early transports in the list will potentially
249
 * be favoured to later ones sharing the file descriptor.
250
 */
251
void
252
transport_send_messages(fd_set * fds)
253
{
254
	struct transport *t, *next;
255
	struct message *msg;
256
	struct exchange *exchange;
257
	struct sockaddr *dst;
258
	struct timeval  expiration;
259
	int             expiry, ok_to_drop_message;
260
	char peer[NI_MAXHOST], peersv[NI_MAXSERV];
261
262
	/*
263
	 * Reference all transports first so noone will disappear while in
264
	 * use.
265
	 */
266
	for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link))
267
		transport_reference(t->virtual);
268
269
	for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link)) {
270
		if ((TAILQ_FIRST(&t->virtual->sendq) ||
271
		    TAILQ_FIRST(&t->virtual->prio_sendq)) &&
272
		    t->vtbl->fd_isset(t, fds)) {
273
			/* Remove fd bit.  */
274
			t->vtbl->fd_set(t, fds, 0);
275
276
			/* Prefer a message from the prioritized sendq.  */
277
			if (TAILQ_FIRST(&t->virtual->prio_sendq)) {
278
				msg = TAILQ_FIRST(&t->virtual->prio_sendq);
279
				TAILQ_REMOVE(&t->virtual->prio_sendq, msg,
280
				    link);
281
			} else {
282
				msg = TAILQ_FIRST(&t->virtual->sendq);
283
				TAILQ_REMOVE(&t->virtual->sendq, msg, link);
284
			}
285
286
			msg->flags &= ~MSG_IN_TRANSIT;
287
			exchange = msg->exchange;
288
			exchange->in_transit = 0;
289
290
			/*
291
			 * We disregard the potential error message here,
292
			 * hoping that the retransmit will go better.
293
			 * XXX Consider a retry/fatal error discriminator.
294
			 */
295
			t->virtual->vtbl->send_message(msg, 0);
296
			msg->xmits++;
297
298
			/*
299
			 * This piece of code has been proven to be quite
300
			 * delicate. Think twice for before altering.
301
			 * Here's an outline:
302
			 *
303
			 * If this message is not the one which finishes an
304
			 * exchange, check if we have reached the number of
305
			 * retransmit before queuing it up for another.
306
			 *
307
			 * If it is a finishing message we still may have to
308
			 * keep it around for an on-demand retransmit when
309
			 * seeing a duplicate of our peer's previous message.
310
			 */
311
			if ((msg->flags & MSG_LAST) == 0) {
312
				if (msg->flags & MSG_DONTRETRANSMIT)
313
					exchange->last_sent = 0;
314
				else if (msg->xmits > conf_get_num("General",
315
				    "retransmits", RETRANSMIT_DEFAULT)) {
316
					t->virtual->vtbl->get_dst(t->virtual, &dst);
317
					if (getnameinfo(dst, SA_LEN(dst), peer,
318
					    sizeof peer, peersv, sizeof peersv,
319
					    NI_NUMERICHOST | NI_NUMERICSERV)) {
320
						strlcpy(peer, "<unknown>", sizeof peer);
321
						strlcpy(peersv, "<?>", sizeof peersv);
322
					}
323
					log_print("transport_send_messages: "
324
					    "giving up on exchange %s, no "
325
					    "response from peer %s:%s",
326
					    exchange->name ? exchange->name :
327
					    "<unnamed>", peer, peersv);
328
329
					exchange->last_sent = 0;
330
#ifdef notyet
331
					exchange_free(exchange);
332
					exchange = 0;
333
#endif
334
				} else {
335
					gettimeofday(&expiration, 0);
336
337
					/*
338
					 * XXX Calculate from round trip
339
					 * timings and a backoff func.
340
					 */
341
					expiry = msg->xmits * 2 + 5;
342
					expiration.tv_sec += expiry;
343
					LOG_DBG((LOG_TRANSPORT, 30,
344
					    "transport_send_messages: "
345
					    "message %p scheduled for "
346
					    "retransmission %d in %d secs",
347
					    msg, msg->xmits, expiry));
348
					if (msg->retrans)
349
						timer_remove_event(msg->retrans);
350
					msg->retrans
351
					    = timer_add_event("message_send_expire",
352
						(void (*) (void *)) message_send_expire,
353
						msg, &expiration);
354
					/*
355
					 * If we cannot retransmit, we
356
					 * cannot...
357
					 */
358
					exchange->last_sent =
359
					    msg->retrans ? msg : 0;
360
				}
361
			} else
362
				exchange->last_sent =
363
				    exchange->last_received ? msg : 0;
364
365
			/*
366
			 * If this message is not referred to for later
367
			 * retransmission it will be ok for us to drop it
368
			 * after the post-send function. But as the post-send
369
			 * function may remove the exchange, we need to
370
			 * remember this fact here.
371
			 */
372
			ok_to_drop_message = exchange->last_sent == 0;
373
374
			/*
375
			 * If this is not a retransmit call post-send
376
			 * functions that allows parallel work to be done
377
			 * while the network and peer does their share of
378
			 * the job.  Note that a post-send function may take
379
			 * away the exchange we belong to, but only if no
380
			 * retransmits are possible.
381
			 */
382
			if (msg->xmits == 1)
383
				message_post_send(msg);
384
385
			if (ok_to_drop_message)
386
				message_free(msg);
387
		}
388
	}
389
390
	for (t = LIST_FIRST(&transport_list); t; t = next) {
391
		next = LIST_NEXT(t, link);
392
		transport_release(t->virtual);
393
	}
394
}
395
396
/*
397
 * Textual search after the transport method denoted by NAME, then create
398
 * a transport connected to the peer with address ADDR, given in a transport-
399
 * specific string format.
400
 */
401
struct transport *
402
transport_create(char *name, char *addr)
403
{
404
	struct transport_vtbl *method;
405
406
	for (method = LIST_FIRST(&transport_method_list); method;
407
	    method = LIST_NEXT(method, link))
408
		if (strcmp(method->name, name) == 0)
409
			return (*method->create) (addr);
410
	return 0;
411
}