GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/dvmrpd/neighbor.c Lines: 0 132 0.0 %
Date: 2017-11-07 Branches: 0 63 0.0 %

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