GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/ripd/neighbor.c Lines: 0 130 0.0 %
Date: 2017-11-13 Branches: 0 74 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: neighbor.c,v 1.11 2017/01/17 16:30:54 jca Exp $ */
2
3
/*
4
 * Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it>
5
 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
6
 * Copyright (c) 2004, 2005, 2006 Esben Norby <norby@openbsd.org>
7
 *
8
 * Permission to use, copy, modify, and distribute this software for any
9
 * purpose with or without fee is hereby granted, provided that the above
10
 * copyright notice and this permission notice appear in all copies.
11
 *
12
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
 */
20
21
#include <sys/types.h>
22
#include <sys/ioctl.h>
23
#include <sys/time.h>
24
#include <sys/socket.h>
25
#include <netinet/in.h>
26
#include <arpa/inet.h>
27
#include <net/if.h>
28
29
#include <ctype.h>
30
#include <err.h>
31
#include <stdio.h>
32
#include <stdlib.h>
33
#include <string.h>
34
#include <event.h>
35
36
#include "ripd.h"
37
#include "rip.h"
38
#include "ripe.h"
39
#include "log.h"
40
#include "rde.h"
41
42
void	nbr_set_timer(struct nbr *);
43
void	nbr_stop_timer(struct nbr *);
44
45
void	nbr_failed_new(struct nbr *);
46
void	nbr_failed_timeout(int, short, void *);
47
48
LIST_HEAD(nbr_head, nbr);
49
50
struct nbr_table {
51
	struct nbr_head		*hashtbl;
52
	u_int32_t		 hashmask;
53
} nbrtable;
54
55
#define NBR_HASH(x)		\
56
	&nbrtable.hashtbl[(x) & nbrtable.hashmask]
57
58
u_int32_t	peercnt = NBR_CNTSTART;
59
60
struct {
61
	int		state;
62
	enum nbr_event	event;
63
	enum nbr_action	action;
64
	int		new_state;
65
} nbr_fsm_tbl[] = {
66
    /* current state	event that happened	action to take		resulting state */
67
    {NBR_STA_DOWN,	NBR_EVT_REQUEST_RCVD,	NBR_ACT_NOTHING,	NBR_STA_REQ_RCVD},
68
    {NBR_STA_DOWN,	NBR_EVT_RESPONSE_RCVD,	NBR_ACT_STRT_TIMER,	NBR_STA_ACTIVE},
69
    {NBR_STA_ACTIVE,	NBR_EVT_RESPONSE_RCVD,	NBR_ACT_RST_TIMER,	NBR_STA_ACTIVE},
70
    {NBR_STA_ACTIVE,	NBR_EVT_REQUEST_RCVD,	NBR_ACT_NOTHING,	NBR_STA_ACTIVE},
71
    {NBR_STA_ACTIVE,	NBR_EVT_TIMEOUT,	NBR_ACT_DEL,		NBR_STA_DOWN},
72
    {NBR_STA_REQ_RCVD,	NBR_EVT_RESPONSE_SENT,	NBR_ACT_DEL,		NBR_STA_DOWN},
73
    {NBR_STA_ACTIVE,	NBR_EVT_RESPONSE_SENT,	NBR_ACT_NOTHING,	NBR_STA_ACTIVE},
74
    {NBR_STA_ANY,	NBR_EVT_KILL_NBR,	NBR_ACT_DEL,		NBR_STA_DOWN},
75
    {-1,		NBR_EVT_NOTHING,	NBR_ACT_NOTHING,	0},
76
};
77
78
const char * const nbr_event_names[] = {
79
	"RESPONSE RCVD",
80
	"REQUEST RCVD",
81
	"RESPONSE SENT",
82
	"NBR TIMEOUT",
83
	"NBR KILL",
84
	"NOTHING"
85
};
86
87
const char * const nbr_action_names[] = {
88
	"START TIMER",
89
	"RESET TIMER",
90
	"DELETE NBR",
91
	"NOTHING"
92
};
93
94
int
95
nbr_fsm(struct nbr *nbr, enum nbr_event event)
96
{
97
	struct timeval	 now;
98
	int		 old_state;
99
	int		 new_state = 0;
100
	int		 i;
101
102
	old_state = nbr->state;
103
	for (i = 0; nbr_fsm_tbl[i].state != -1; i++)
104
		if ((nbr_fsm_tbl[i].state & old_state) &&
105
		    (nbr_fsm_tbl[i].event == event)) {
106
			new_state = nbr_fsm_tbl[i].new_state;
107
			break;
108
		}
109
110
	if (nbr_fsm_tbl[i].state == -1) {
111
		/* event outside of the defined fsm, ignore it. */
112
		log_warnx("nbr_fsm: neighbor ID %s, "
113
		    "event '%s' not expected in state '%s'",
114
		    inet_ntoa(nbr->id), nbr_event_name(event),
115
		    nbr_state_name(old_state));
116
		return (0);
117
	}
118
119
	switch (nbr_fsm_tbl[i].action) {
120
	case NBR_ACT_RST_TIMER:
121
		nbr_set_timer(nbr);
122
		break;
123
	case NBR_ACT_STRT_TIMER:
124
		nbr_set_timer(nbr);
125
		break;
126
	case NBR_ACT_DEL:
127
		nbr_act_del(nbr);
128
		break;
129
	case NBR_ACT_NOTHING:
130
		/* do nothing */
131
		break;
132
	}
133
134
	if (new_state != 0)
135
		nbr->state = new_state;
136
137
	if (old_state != nbr->state) {
138
		/* neighbor changed from/to ACTIVE */
139
		gettimeofday(&now, NULL);
140
		nbr->uptime = now.tv_sec;
141
142
		log_debug("nbr_fsm: event '%s' resulted in action '%s' and "
143
		    "changing state for neighbor ID %s from '%s' to '%s'",
144
		    nbr_event_name(event),
145
		    nbr_action_name(nbr_fsm_tbl[i].action),
146
		    inet_ntoa(nbr->id), nbr_state_name(old_state),
147
		    nbr_state_name(nbr->state));
148
	}
149
150
	return (0);
151
}
152
153
void
154
nbr_init(u_int32_t hashsize)
155
{
156
	u_int32_t	 hs, i;
157
158
	for (hs = 1; hs < hashsize; hs <<= 1)
159
		;
160
	nbrtable.hashtbl = calloc(hs, sizeof(struct nbr_head));
161
	if (nbrtable.hashtbl == NULL)
162
		fatal("nbr_init");
163
164
	for (i = 0; i < hs; i++)
165
		LIST_INIT(&nbrtable.hashtbl[i]);
166
167
	nbrtable.hashmask = hs - 1;
168
}
169
170
struct nbr *
171
nbr_new(u_int32_t nbr_id, struct iface *iface)
172
{
173
	struct nbr_head	*head;
174
	struct nbr	*nbr = NULL;
175
176
	if ((nbr = calloc(1, sizeof(*nbr))) == NULL)
177
		fatal("nbr_new");
178
179
	nbr->state = NBR_STA_DOWN;
180
	nbr->id.s_addr = nbr_id;
181
182
	/* get next unused peerid */
183
	while (nbr_find_peerid(++peercnt))
184
		;
185
	nbr->peerid = peercnt;
186
	head = NBR_HASH(nbr->peerid);
187
	LIST_INSERT_HEAD(head, nbr, hash);
188
189
	/* add to peer list */
190
	nbr->iface = iface;
191
	LIST_INSERT_HEAD(&iface->nbr_list, nbr, entry);
192
193
	TAILQ_INIT(&nbr->rp_list);
194
	TAILQ_INIT(&nbr->rq_list);
195
196
	/* set event structures */
197
	evtimer_set(&nbr->timeout_timer, nbr_timeout_timer, nbr);
198
199
	log_debug("nbr_new: neighbor ID %s, peerid %u",
200
	    inet_ntoa(nbr->id), nbr->peerid);
201
202
	return (nbr);
203
}
204
205
void
206
nbr_del(struct nbr *nbr)
207
{
208
	log_debug("nbr_del: neighbor ID %s, peerid %u", inet_ntoa(nbr->id),
209
	    nbr->peerid);
210
211
	/* stop timer */
212
	nbr_stop_timer(nbr);
213
214
	LIST_REMOVE(nbr, entry);
215
	LIST_REMOVE(nbr, hash);
216
217
	free(nbr);
218
}
219
220
void
221
nbr_act_del(struct nbr *nbr)
222
{
223
	/* If there is no authentication or it is just a route request
224
	 * there is no need to keep track of the failed neighbors */
225
	if (nbr->iface->auth_type == AUTH_CRYPT &&
226
	    nbr->state != NBR_STA_REQ_RCVD)
227
		nbr_failed_new(nbr);
228
229
	log_debug("nbr_act_del: neighbor ID %s, peerid %u", inet_ntoa(nbr->id),
230
	    nbr->peerid);
231
232
	/* schedule kill timer */
233
	nbr_set_timer(nbr);
234
235
	/* clear lists */
236
	clear_list(&nbr->rq_list);
237
	clear_list(&nbr->rp_list);
238
}
239
240
struct nbr *
241
nbr_find_peerid(u_int32_t peerid)
242
{
243
	struct nbr_head	*head;
244
	struct nbr	*nbr;
245
246
	head = NBR_HASH(peerid);
247
248
	LIST_FOREACH(nbr, head, hash) {
249
		if (nbr->peerid == peerid)
250
			return (nbr);
251
	}
252
253
	return (NULL);
254
}
255
256
struct nbr *
257
nbr_find_ip(struct iface *iface, u_int32_t src_ip)
258
{
259
	struct nbr	*nbr = NULL;
260
261
	LIST_FOREACH(nbr, &iface->nbr_list, entry) {
262
		if (nbr->id.s_addr == src_ip) {
263
			return (nbr);
264
		}
265
	}
266
267
	return (NULL);
268
}
269
270
/* failed nbr handling */
271
void
272
nbr_failed_new(struct nbr *nbr)
273
{
274
	struct timeval		 tv;
275
	struct iface		*iface;
276
	struct nbr_failed	*nbr_failed;
277
278
	if ((nbr_failed = calloc(1, sizeof(*nbr_failed))) == NULL)
279
		fatal("nbr_failed_new");
280
281
	nbr_failed->addr = nbr->addr;
282
	nbr_failed->auth_seq_num = nbr->auth_seq_num;
283
	iface = nbr->iface;
284
285
	timerclear(&tv);
286
	tv.tv_sec = FAILED_NBR_TIMEOUT;
287
288
	evtimer_set(&nbr_failed->timeout_timer, nbr_failed_timeout,
289
	    nbr_failed);
290
291
	if (evtimer_add(&nbr_failed->timeout_timer, &tv) == -1)
292
		fatal("nbr_failed_new");
293
294
	LIST_INSERT_HEAD(&iface->failed_nbr_list, nbr_failed, entry);
295
}
296
297
struct nbr_failed *
298
nbr_failed_find(struct iface *iface, u_int32_t src_ip)
299
{
300
	struct nbr_failed	*nbr_failed = NULL;
301
302
	LIST_FOREACH(nbr_failed, &iface->failed_nbr_list, entry) {
303
		if (nbr_failed->addr.s_addr == src_ip) {
304
			return (nbr_failed);
305
		}
306
	}
307
308
	return (NULL);
309
}
310
311
void
312
nbr_failed_delete(struct nbr_failed *nbr_failed)
313
{
314
	if (evtimer_pending(&nbr_failed->timeout_timer, NULL))
315
		if (evtimer_del(&nbr_failed->timeout_timer) == -1)
316
			fatal("nbr_failed_delete");
317
318
	LIST_REMOVE(nbr_failed, entry);
319
	free(nbr_failed);
320
}
321
322
/* timers */
323
/* ARGSUSED */
324
void
325
nbr_timeout_timer(int fd, short event, void *arg)
326
{
327
	struct nbr *nbr = arg;
328
329
	if (nbr->state == NBR_STA_DOWN)
330
		nbr_del(nbr);
331
	else
332
		nbr_fsm(nbr, NBR_EVT_TIMEOUT);
333
}
334
335
/* ARGSUSED */
336
void
337
nbr_failed_timeout(int fd, short event, void *arg)
338
{
339
	struct nbr_failed	*nbr_failed = arg;
340
341
	log_debug("nbr_failed_timeout: failed neighbor ID %s deleted",
342
	    inet_ntoa(nbr_failed->addr));
343
344
	nbr_failed_delete(nbr_failed);
345
}
346
347
/* actions */
348
void
349
nbr_set_timer(struct nbr *nbr)
350
{
351
	struct timeval	tv;
352
353
	timerclear(&tv);
354
	tv.tv_sec = NBR_TIMEOUT;
355
356
	if (evtimer_add(&nbr->timeout_timer, &tv) == -1)
357
		fatal("nbr_set_timer");
358
}
359
360
void
361
nbr_stop_timer(struct nbr *nbr)
362
{
363
	if (evtimer_del(&nbr->timeout_timer) == -1)
364
		fatal("nbr_stop_timer");
365
}
366
367
/* names */
368
const char *
369
nbr_event_name(int event)
370
{
371
	return (nbr_event_names[event]);
372
}
373
374
const char *
375
nbr_action_name(int action)
376
{
377
	return (nbr_action_names[action]);
378
}
379
380
struct ctl_nbr *
381
nbr_to_ctl(struct nbr *nbr)
382
{
383
	static struct ctl_nbr	 nctl;
384
	struct timeval		 tv, now, res;
385
386
	memcpy(nctl.name, nbr->iface->name, sizeof(nctl.name));
387
	memcpy(&nctl.id, &nbr->id, sizeof(nctl.id));
388
	memcpy(&nctl.addr, &nbr->addr, sizeof(nctl.addr));
389
390
	nctl.nbr_state = nbr->state;
391
	nctl.iface_state = nbr->iface->state;
392
393
	gettimeofday(&now, NULL);
394
	if (evtimer_pending(&nbr->timeout_timer, &tv)) {
395
		timersub(&tv, &now, &res);
396
		if (nbr->state & NBR_STA_DOWN)
397
			nctl.dead_timer = NBR_TIMEOUT - res.tv_sec;
398
		else
399
			nctl.dead_timer = res.tv_sec;
400
	} else
401
		nctl.dead_timer = 0;
402
403
	if (nbr->state == NBR_STA_ACTIVE) {
404
		nctl.uptime = now.tv_sec - nbr->uptime;
405
	} else
406
		nctl.uptime = 0;
407
408
	return (&nctl);
409
}