GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/ospfd/interface.c Lines: 36 395 9.1 %
Date: 2017-11-07 Branches: 12 282 4.3 %

Line Branch Exec Source
1
/*	$OpenBSD: interface.c,v 1.81 2015/12/05 12:20:13 claudio Exp $ */
2
3
/*
4
 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
5
 * Copyright (c) 2004, 2005 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
#include <net/if_types.h>
28
#include <ctype.h>
29
#include <err.h>
30
#include <stdio.h>
31
#include <stdlib.h>
32
#include <unistd.h>
33
#include <string.h>
34
#include <event.h>
35
36
#include "ospfd.h"
37
#include "ospf.h"
38
#include "log.h"
39
#include "ospfe.h"
40
41
void		 if_hello_timer(int, short, void *);
42
void		 if_start_hello_timer(struct iface *);
43
void		 if_stop_hello_timer(struct iface *);
44
void		 if_stop_wait_timer(struct iface *);
45
void		 if_wait_timer(int, short, void *);
46
void		 if_start_wait_timer(struct iface *);
47
void		 if_stop_wait_timer(struct iface *);
48
struct nbr	*if_elect(struct nbr *, struct nbr *);
49
50
struct {
51
	int			state;
52
	enum iface_event	event;
53
	enum iface_action	action;
54
	int			new_state;
55
} iface_fsm[] = {
56
    /* current state	event that happened	action to take	resulting state */
57
    {IF_STA_DOWN,	IF_EVT_UP,		IF_ACT_STRT,	0},
58
    {IF_STA_WAITING,	IF_EVT_BACKUP_SEEN,	IF_ACT_ELECT,	0},
59
    {IF_STA_WAITING,	IF_EVT_WTIMER,		IF_ACT_ELECT,	0},
60
    {IF_STA_ANY,	IF_EVT_WTIMER,		IF_ACT_NOTHING,	0},
61
    {IF_STA_WAITING,	IF_EVT_NBR_CHNG,	IF_ACT_NOTHING,	0},
62
    {IF_STA_MULTI,	IF_EVT_NBR_CHNG,	IF_ACT_ELECT,	0},
63
    {IF_STA_ANY,	IF_EVT_NBR_CHNG,	IF_ACT_NOTHING,	0},
64
    {IF_STA_ANY,	IF_EVT_DOWN,		IF_ACT_RST,	IF_STA_DOWN},
65
    {IF_STA_ANY,	IF_EVT_LOOP,		IF_ACT_RST,	IF_STA_LOOPBACK},
66
    {IF_STA_LOOPBACK,	IF_EVT_UNLOOP,		IF_ACT_NOTHING,	IF_STA_DOWN},
67
    {-1,		IF_EVT_NOTHING,		IF_ACT_NOTHING,	0},
68
};
69
70
static int vlink_cnt = 0;
71
72
const char * const if_event_names[] = {
73
	"NOTHING",
74
	"UP",
75
	"WAITTIMER",
76
	"BACKUPSEEN",
77
	"NEIGHBORCHANGE",
78
	"LOOP",
79
	"UNLOOP",
80
	"DOWN"
81
};
82
83
const char * const if_action_names[] = {
84
	"NOTHING",
85
	"START",
86
	"ELECT",
87
	"RESET"
88
};
89
90
int
91
if_fsm(struct iface *iface, enum iface_event event)
92
{
93
	int	old_state;
94
	int	new_state = 0;
95
	int	i, ret = 0;
96
97
	old_state = iface->state;
98
99
	for (i = 0; iface_fsm[i].state != -1; i++)
100
		if ((iface_fsm[i].state & old_state) &&
101
		    (iface_fsm[i].event == event)) {
102
			new_state = iface_fsm[i].new_state;
103
			break;
104
		}
105
106
	if (iface_fsm[i].state == -1) {
107
		/* event outside of the defined fsm, ignore it. */
108
		log_debug("if_fsm: interface %s, "
109
		    "event %s not expected in state %s", iface->name,
110
		    if_event_names[event], if_state_name(old_state));
111
		return (0);
112
	}
113
114
	switch (iface_fsm[i].action) {
115
	case IF_ACT_STRT:
116
		ret = if_act_start(iface);
117
		break;
118
	case IF_ACT_ELECT:
119
		ret = if_act_elect(iface);
120
		break;
121
	case IF_ACT_RST:
122
		ret = if_act_reset(iface);
123
		break;
124
	case IF_ACT_NOTHING:
125
		/* do nothing */
126
		break;
127
	}
128
129
	if (ret) {
130
		log_debug("if_fsm: error changing state for interface %s, "
131
		    "event %s, state %s", iface->name, if_event_names[event],
132
		    if_state_name(old_state));
133
		return (-1);
134
	}
135
136
	if (new_state != 0)
137
		iface->state = new_state;
138
139
	if (iface->state != old_state) {
140
		area_track(iface->area);
141
		orig_rtr_lsa(iface->area);
142
	}
143
144
	if (old_state & (IF_STA_MULTI | IF_STA_POINTTOPOINT) &&
145
	    (iface->state & (IF_STA_MULTI | IF_STA_POINTTOPOINT)) == 0)
146
		ospfe_demote_iface(iface, 0);
147
	if ((old_state & (IF_STA_MULTI | IF_STA_POINTTOPOINT)) == 0 &&
148
	    iface->state & (IF_STA_MULTI | IF_STA_POINTTOPOINT))
149
		ospfe_demote_iface(iface, 1);
150
151
	log_debug("if_fsm: event %s resulted in action %s and changing "
152
	    "state for interface %s from %s to %s",
153
	    if_event_names[event], if_action_names[iface_fsm[i].action],
154
	    iface->name, if_state_name(old_state), if_state_name(iface->state));
155
156
	return (ret);
157
}
158
159
struct iface *
160
if_new(struct kif *kif, struct kif_addr *ka)
161
{
162
	struct iface		*iface;
163
164
32
	if ((iface = calloc(1, sizeof(*iface))) == NULL)
165
		err(1, "if_new: calloc");
166
167
16
	iface->state = IF_STA_DOWN;
168
169
16
	LIST_INIT(&iface->nbr_list);
170
16
	TAILQ_INIT(&iface->ls_ack_list);
171
16
	TAILQ_INIT(&iface->auth_md_list);
172
16
	RB_INIT(&iface->lsa_tree);
173
174
16
	iface->crypt_seq_num = arc4random() & 0x0fffffff;
175
176
16
	if (kif == NULL) {
177
		iface->type = IF_TYPE_VIRTUALLINK;
178
		snprintf(iface->name, sizeof(iface->name), "vlink%d",
179
		    vlink_cnt++);
180
		iface->flags |= IFF_UP;
181
		iface->mtu = IP_MSS;
182
		return (iface);
183
	}
184
185
16
	strlcpy(iface->name, kif->ifname, sizeof(iface->name));
186
187
	/* get type */
188
16
	if (kif->flags & IFF_POINTOPOINT)
189
		iface->type = IF_TYPE_POINTOPOINT;
190

32
	if (kif->flags & IFF_BROADCAST &&
191
16
	    kif->flags & IFF_MULTICAST)
192
16
		iface->type = IF_TYPE_BROADCAST;
193
16
	if (kif->flags & IFF_LOOPBACK) {
194
		iface->type = IF_TYPE_POINTOPOINT;
195
		iface->passive = 1;
196
	}
197
198
	/* get mtu, index and flags */
199
16
	iface->mtu = kif->mtu;
200
16
	iface->ifindex = kif->ifindex;
201
16
	iface->rdomain = kif->rdomain;
202
16
	iface->flags = kif->flags;
203
16
	iface->linkstate = kif->link_state;
204
16
	iface->if_type = kif->if_type;
205
16
	iface->baudrate = kif->baudrate;
206
207
	/* set address, mask and p2p addr */
208
16
	iface->addr = ka->addr;
209
16
	iface->mask = ka->mask;
210
16
	if (kif->flags & IFF_POINTOPOINT) {
211
		iface->dst = ka->dstbrd;
212
	}
213
214
16
	return (iface);
215
16
}
216
217
void
218
if_del(struct iface *iface)
219
{
220
	struct nbr	*nbr = NULL;
221
222
	/* revert the demotion when the interface is deleted */
223
32
	if ((iface->state & (IF_STA_MULTI | IF_STA_POINTTOPOINT)) == 0)
224
16
		ospfe_demote_iface(iface, 1);
225
226
	/* clear lists etc */
227
16
	while ((nbr = LIST_FIRST(&iface->nbr_list)) != NULL)
228
		nbr_del(nbr);
229
230
16
	if (evtimer_pending(&iface->hello_timer, NULL))
231
		evtimer_del(&iface->hello_timer);
232
16
	if (evtimer_pending(&iface->wait_timer, NULL))
233
		evtimer_del(&iface->wait_timer);
234
16
	if (evtimer_pending(&iface->lsack_tx_timer, NULL))
235
		evtimer_del(&iface->lsack_tx_timer);
236
237
16
	ls_ack_list_clr(iface);
238
16
	md_list_clr(&iface->auth_md_list);
239
16
	free(iface);
240
16
}
241
242
void
243
if_init(struct ospfd_conf *xconf, struct iface *iface)
244
{
245
	/* init the dummy local neighbor */
246
	iface->self = nbr_new(ospfe_router_id(), iface, 1);
247
248
	/* set event handlers for interface */
249
	evtimer_set(&iface->lsack_tx_timer, ls_ack_tx_timer, iface);
250
	evtimer_set(&iface->hello_timer, if_hello_timer, iface);
251
	evtimer_set(&iface->wait_timer, if_wait_timer, iface);
252
253
	iface->fd = xconf->ospf_socket;
254
255
	ospfe_demote_iface(iface, 0);
256
}
257
258
/* timers */
259
/* ARGSUSED */
260
void
261
if_hello_timer(int fd, short event, void *arg)
262
{
263
	struct iface *iface = arg;
264
	struct timeval tv;
265
266
	send_hello(iface);
267
268
	/* reschedule hello_timer */
269
	timerclear(&tv);
270
	if (iface->dead_interval == FAST_RTR_DEAD_TIME)
271
		tv.tv_usec = iface->fast_hello_interval * 1000;
272
	else
273
		tv.tv_sec = iface->hello_interval;
274
	if (evtimer_add(&iface->hello_timer, &tv) == -1)
275
		fatal("if_hello_timer");
276
}
277
278
void
279
if_start_hello_timer(struct iface *iface)
280
{
281
	struct timeval tv;
282
283
	timerclear(&tv);
284
	if (evtimer_add(&iface->hello_timer, &tv) == -1)
285
		fatal("if_start_hello_timer");
286
}
287
288
void
289
if_stop_hello_timer(struct iface *iface)
290
{
291
	if (evtimer_del(&iface->hello_timer) == -1)
292
		fatal("if_stop_hello_timer");
293
}
294
295
/* ARGSUSED */
296
void
297
if_wait_timer(int fd, short event, void *arg)
298
{
299
	struct iface *iface = arg;
300
301
	if_fsm(iface, IF_EVT_WTIMER);
302
}
303
304
void
305
if_start_wait_timer(struct iface *iface)
306
{
307
	struct timeval	tv;
308
309
	timerclear(&tv);
310
	tv.tv_sec = iface->dead_interval;
311
	if (evtimer_add(&iface->wait_timer, &tv) == -1)
312
		fatal("if_start_wait_timer");
313
}
314
315
void
316
if_stop_wait_timer(struct iface *iface)
317
{
318
	if (evtimer_del(&iface->wait_timer) == -1)
319
		fatal("if_stop_wait_timer");
320
}
321
322
/* actions */
323
int
324
if_act_start(struct iface *iface)
325
{
326
	struct in_addr		 addr;
327
	struct timeval		 now;
328
329
	if (!(iface->flags & IFF_UP) ||
330
	    (!LINK_STATE_IS_UP(iface->linkstate) &&
331
	    !(iface->if_type == IFT_CARP &&
332
	    iface->linkstate == LINK_STATE_DOWN)))
333
		return (0);
334
335
	if (iface->if_type == IFT_CARP && iface->passive == 0) {
336
		/* force passive mode on carp interfaces */
337
		log_warnx("if_act_start: forcing interface %s to passive",
338
		    iface->name);
339
		iface->passive = 1;
340
	}
341
342
	gettimeofday(&now, NULL);
343
	iface->uptime = now.tv_sec;
344
345
	/* loopback interfaces have a special state and are passive */
346
	if (iface->flags & IFF_LOOPBACK)
347
		iface->state = IF_STA_LOOPBACK;
348
349
	if (iface->passive) {
350
		/* for an update of stub network entries */
351
		orig_rtr_lsa(iface->area);
352
		return (0);
353
	}
354
355
	switch (iface->type) {
356
	case IF_TYPE_POINTOPOINT:
357
		inet_aton(AllSPFRouters, &addr);
358
		if (if_join_group(iface, &addr))
359
			return (-1);
360
		iface->state = IF_STA_POINTTOPOINT;
361
		break;
362
	case IF_TYPE_VIRTUALLINK:
363
		iface->state = IF_STA_POINTTOPOINT;
364
		break;
365
	case IF_TYPE_POINTOMULTIPOINT:
366
	case IF_TYPE_NBMA:
367
		log_debug("if_act_start: type %s not supported, interface %s",
368
		    if_type_name(iface->type), iface->name);
369
		return (-1);
370
	case IF_TYPE_BROADCAST:
371
		inet_aton(AllSPFRouters, &addr);
372
		if (if_join_group(iface, &addr))
373
			return (-1);
374
		if (iface->priority == 0) {
375
			iface->state = IF_STA_DROTHER;
376
		} else {
377
			iface->state = IF_STA_WAITING;
378
			if_start_wait_timer(iface);
379
		}
380
		break;
381
	default:
382
		fatalx("if_act_start: unknown interface type");
383
	}
384
385
	/* hello timer needs to be started in any case */
386
	if_start_hello_timer(iface);
387
	return (0);
388
}
389
390
struct nbr *
391
if_elect(struct nbr *a, struct nbr *b)
392
{
393
	if (a->priority > b->priority)
394
		return (a);
395
	if (a->priority < b->priority)
396
		return (b);
397
	if (ntohl(a->id.s_addr) > ntohl(b->id.s_addr))
398
		return (a);
399
	return (b);
400
}
401
402
int
403
if_act_elect(struct iface *iface)
404
{
405
	struct in_addr	 addr;
406
	struct nbr	*nbr, *bdr = NULL, *dr = NULL;
407
	int		 round = 0;
408
	int		 changed = 0;
409
	int		 old_state;
410
	char		 b1[16], b2[16], b3[16], b4[16];
411
412
start:
413
	/* elect backup designated router */
414
	LIST_FOREACH(nbr, &iface->nbr_list, entry) {
415
		if (nbr->priority == 0 || nbr == dr ||	/* not electable */
416
		    nbr->state & NBR_STA_PRELIM ||	/* not available */
417
		    nbr->dr.s_addr == nbr->addr.s_addr)	/* don't elect DR */
418
			continue;
419
		if (bdr != NULL) {
420
			/*
421
			 * routers announcing themselves as BDR have higher
422
			 * precedence over those routers announcing a
423
			 * different BDR.
424
			 */
425
			if (nbr->bdr.s_addr == nbr->addr.s_addr) {
426
				if (bdr->bdr.s_addr == bdr->addr.s_addr)
427
					bdr = if_elect(bdr, nbr);
428
				else
429
					bdr = nbr;
430
			} else if (bdr->bdr.s_addr != bdr->addr.s_addr)
431
					bdr = if_elect(bdr, nbr);
432
		} else
433
			bdr = nbr;
434
	}
435
436
	/* elect designated router */
437
	LIST_FOREACH(nbr, &iface->nbr_list, entry) {
438
		if (nbr->priority == 0 || nbr->state & NBR_STA_PRELIM ||
439
		    (nbr != dr && nbr->dr.s_addr != nbr->addr.s_addr))
440
			/* only DR may be elected check priority too */
441
			continue;
442
		if (dr == NULL)
443
			dr = nbr;
444
		else
445
			dr = if_elect(dr, nbr);
446
	}
447
448
	if (dr == NULL) {
449
		/* no designated router found use backup DR */
450
		dr = bdr;
451
		bdr = NULL;
452
	}
453
454
	/*
455
	 * if we are involved in the election (e.g. new DR or no
456
	 * longer BDR) redo the election
457
	 */
458
	if (round == 0 &&
459
	    ((iface->self == dr && iface->self != iface->dr) ||
460
	    (iface->self != dr && iface->self == iface->dr) ||
461
	    (iface->self == bdr && iface->self != iface->bdr) ||
462
	    (iface->self != bdr && iface->self == iface->bdr))) {
463
		/*
464
		 * Reset announced DR/BDR to calculated one, so
465
		 * that we may get elected in the second round.
466
		 * This is needed to drop from a DR to a BDR.
467
		 */
468
		iface->self->dr.s_addr = dr->addr.s_addr;
469
		if (bdr)
470
			iface->self->bdr.s_addr = bdr->addr.s_addr;
471
		round = 1;
472
		goto start;
473
	}
474
475
	log_debug("if_act_elect: interface %s old dr %s new dr %s, "
476
	    "old bdr %s new bdr %s", iface->name,
477
	    iface->dr ? inet_ntop(AF_INET, &iface->dr->addr, b1, sizeof(b1)) :
478
	    "none", dr ? inet_ntop(AF_INET, &dr->addr, b2, sizeof(b2)) : "none",
479
	    iface->bdr ? inet_ntop(AF_INET, &iface->bdr->addr, b3, sizeof(b3)) :
480
	    "none", bdr ? inet_ntop(AF_INET, &bdr->addr, b4, sizeof(b4)) :
481
	    "none");
482
483
	/*
484
	 * After the second round still DR or BDR change state to DR or BDR,
485
	 * etc.
486
	 */
487
	old_state = iface->state;
488
	if (dr == iface->self)
489
		iface->state = IF_STA_DR;
490
	else if (bdr == iface->self)
491
		iface->state = IF_STA_BACKUP;
492
	else
493
		iface->state = IF_STA_DROTHER;
494
495
	/* TODO if iface is NBMA send all non eligible neighbors event Start */
496
497
	/*
498
	 * if DR or BDR changed issue a AdjOK? event for all neighbors > 2-Way
499
	 */
500
	if (iface->dr != dr || iface->bdr != bdr)
501
		changed = 1;
502
503
	iface->dr = dr;
504
	iface->bdr = bdr;
505
506
	if (changed) {
507
		inet_aton(AllDRouters, &addr);
508
		if (old_state & IF_STA_DRORBDR &&
509
		    (iface->state & IF_STA_DRORBDR) == 0) {
510
			if (if_leave_group(iface, &addr))
511
				return (-1);
512
		} else if ((old_state & IF_STA_DRORBDR) == 0 &&
513
		    iface->state & IF_STA_DRORBDR) {
514
			if (if_join_group(iface, &addr))
515
				return (-1);
516
		}
517
518
		LIST_FOREACH(nbr, &iface->nbr_list, entry) {
519
			if (nbr->state & NBR_STA_BIDIR)
520
				nbr_fsm(nbr, NBR_EVT_ADJ_OK);
521
		}
522
523
		orig_rtr_lsa(iface->area);
524
		if (iface->state & IF_STA_DR || old_state & IF_STA_DR)
525
			orig_net_lsa(iface);
526
	}
527
528
	if_start_hello_timer(iface);
529
	return (0);
530
}
531
532
int
533
if_act_reset(struct iface *iface)
534
{
535
	struct nbr		*nbr = NULL;
536
	struct in_addr		 addr;
537
538
	if (iface->passive) {
539
		/* for an update of stub network entries */
540
		orig_rtr_lsa(iface->area);
541
		return (0);
542
	}
543
544
	switch (iface->type) {
545
	case IF_TYPE_POINTOPOINT:
546
	case IF_TYPE_BROADCAST:
547
		/* try to cleanup */
548
		inet_aton(AllSPFRouters, &addr);
549
		if_leave_group(iface, &addr);
550
		if (iface->state & IF_STA_DRORBDR) {
551
			inet_aton(AllDRouters, &addr);
552
			if_leave_group(iface, &addr);
553
		}
554
		break;
555
	case IF_TYPE_VIRTUALLINK:
556
		/* nothing */
557
		break;
558
	case IF_TYPE_NBMA:
559
	case IF_TYPE_POINTOMULTIPOINT:
560
		log_debug("if_act_reset: type %s not supported, interface %s",
561
		    if_type_name(iface->type), iface->name);
562
		return (-1);
563
	default:
564
		fatalx("if_act_reset: unknown interface type");
565
	}
566
567
	LIST_FOREACH(nbr, &iface->nbr_list, entry) {
568
		if (nbr_fsm(nbr, NBR_EVT_KILL_NBR)) {
569
			log_debug("if_act_reset: error killing neighbor %s",
570
			    inet_ntoa(nbr->id));
571
		}
572
	}
573
574
	iface->dr = NULL;
575
	iface->bdr = NULL;
576
577
	ls_ack_list_clr(iface);
578
	stop_ls_ack_tx_timer(iface);
579
	if_stop_hello_timer(iface);
580
	if_stop_wait_timer(iface);
581
582
	/* send empty hello to tell everybody that we are going down */
583
	send_hello(iface);
584
585
	return (0);
586
}
587
588
struct ctl_iface *
589
if_to_ctl(struct iface *iface)
590
{
591
	static struct ctl_iface	 ictl;
592
	struct timeval		 tv, now, res;
593
	struct nbr		*nbr;
594
595
	memcpy(ictl.name, iface->name, sizeof(ictl.name));
596
	memcpy(&ictl.addr, &iface->addr, sizeof(ictl.addr));
597
	memcpy(&ictl.mask, &iface->mask, sizeof(ictl.mask));
598
	ictl.rtr_id.s_addr = ospfe_router_id();
599
	memcpy(&ictl.area, &iface->area->id, sizeof(ictl.area));
600
	if (iface->dr) {
601
		memcpy(&ictl.dr_id, &iface->dr->id, sizeof(ictl.dr_id));
602
		memcpy(&ictl.dr_addr, &iface->dr->addr, sizeof(ictl.dr_addr));
603
	} else {
604
		bzero(&ictl.dr_id, sizeof(ictl.dr_id));
605
		bzero(&ictl.dr_addr, sizeof(ictl.dr_addr));
606
	}
607
	if (iface->bdr) {
608
		memcpy(&ictl.bdr_id, &iface->bdr->id, sizeof(ictl.bdr_id));
609
		memcpy(&ictl.bdr_addr, &iface->bdr->addr,
610
		    sizeof(ictl.bdr_addr));
611
	} else {
612
		bzero(&ictl.bdr_id, sizeof(ictl.bdr_id));
613
		bzero(&ictl.bdr_addr, sizeof(ictl.bdr_addr));
614
	}
615
	ictl.ifindex = iface->ifindex;
616
	ictl.state = iface->state;
617
	ictl.mtu = iface->mtu;
618
	ictl.nbr_cnt = 0;
619
	ictl.adj_cnt = 0;
620
	ictl.baudrate = iface->baudrate;
621
	ictl.dead_interval = iface->dead_interval;
622
	ictl.fast_hello_interval = iface->fast_hello_interval;
623
	ictl.transmit_delay = iface->transmit_delay;
624
	ictl.hello_interval = iface->hello_interval;
625
	ictl.flags = iface->flags;
626
	ictl.metric = iface->metric;
627
	ictl.rxmt_interval = iface->rxmt_interval;
628
	ictl.type = iface->type;
629
	ictl.linkstate = iface->linkstate;
630
	ictl.if_type = iface->if_type;
631
	ictl.priority = iface->priority;
632
	ictl.passive = iface->passive;
633
	ictl.auth_type = iface->auth_type;
634
	ictl.auth_keyid = iface->auth_keyid;
635
636
	gettimeofday(&now, NULL);
637
	if (evtimer_pending(&iface->hello_timer, &tv)) {
638
		timersub(&tv, &now, &res);
639
		ictl.hello_timer = res;
640
	} else {
641
		ictl.hello_timer.tv_sec = -1;
642
	}
643
644
	if (iface->state != IF_STA_DOWN &&
645
	    iface->uptime != 0) {
646
		ictl.uptime = now.tv_sec - iface->uptime;
647
	} else
648
		ictl.uptime = 0;
649
650
	LIST_FOREACH(nbr, &iface->nbr_list, entry) {
651
		if (nbr == iface->self)
652
			continue;
653
		ictl.nbr_cnt++;
654
		if (nbr->state & NBR_STA_ADJFORM)
655
			ictl.adj_cnt++;
656
	}
657
658
	return (&ictl);
659
}
660
661
/* misc */
662
int
663
if_set_recvif(int fd, int enable)
664
{
665
	if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &enable,
666
	    sizeof(enable)) < 0) {
667
		log_warn("if_set_recvif: error setting IP_RECVIF");
668
		return (-1);
669
	}
670
	return (0);
671
}
672
673
void
674
if_set_sockbuf(int fd)
675
{
676
	int	bsize;
677
678
	bsize = 65535;
679
	while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize,
680
	    sizeof(bsize)) == -1)
681
		bsize /= 2;
682
683
	if (bsize != 65535)
684
		log_warnx("if_set_sockbuf: recvbuf size only %d", bsize);
685
686
	bsize = 65535;
687
	while (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &bsize,
688
	    sizeof(bsize)) == -1)
689
		bsize /= 2;
690
691
	if (bsize != 65535)
692
		log_warnx("if_set_sockbuf: sendbuf size only %d", bsize);
693
}
694
695
/*
696
 * only one JOIN or DROP per interface and address is allowed so we need
697
 * to keep track of what is added and removed.
698
 */
699
struct if_group_count {
700
	LIST_ENTRY(if_group_count)	entry;
701
	struct in_addr			addr;
702
	unsigned int			ifindex;
703
	int				count;
704
};
705
706
LIST_HEAD(,if_group_count) ifglist = LIST_HEAD_INITIALIZER(ifglist);
707
708
int
709
if_join_group(struct iface *iface, struct in_addr *addr)
710
{
711
	struct ip_mreq		 mreq;
712
	struct if_group_count	*ifg;
713
714
	switch (iface->type) {
715
	case IF_TYPE_POINTOPOINT:
716
	case IF_TYPE_BROADCAST:
717
		LIST_FOREACH(ifg, &ifglist, entry)
718
			if (iface->ifindex == ifg->ifindex &&
719
			    addr->s_addr == ifg->addr.s_addr)
720
				break;
721
		if (ifg == NULL) {
722
			if ((ifg = calloc(1, sizeof(*ifg))) == NULL)
723
				fatal("if_join_group");
724
			ifg->addr.s_addr = addr->s_addr;
725
			ifg->ifindex = iface->ifindex;
726
			LIST_INSERT_HEAD(&ifglist, ifg, entry);
727
		}
728
729
		if (ifg->count++ != 0)
730
			/* already joined */
731
			return (0);
732
733
		mreq.imr_multiaddr.s_addr = addr->s_addr;
734
		mreq.imr_interface.s_addr = iface->addr.s_addr;
735
736
		if (setsockopt(iface->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
737
		    (void *)&mreq, sizeof(mreq)) < 0) {
738
			log_warn("if_join_group: error IP_ADD_MEMBERSHIP, "
739
			    "interface %s address %s", iface->name,
740
			    inet_ntoa(*addr));
741
			return (-1);
742
		}
743
		break;
744
	case IF_TYPE_POINTOMULTIPOINT:
745
	case IF_TYPE_VIRTUALLINK:
746
	case IF_TYPE_NBMA:
747
		log_debug("if_join_group: type %s not supported, interface %s",
748
		    if_type_name(iface->type), iface->name);
749
		return (-1);
750
	default:
751
		fatalx("if_join_group: unknown interface type");
752
	}
753
754
	return (0);
755
}
756
757
int
758
if_leave_group(struct iface *iface, struct in_addr *addr)
759
{
760
	struct ip_mreq		 mreq;
761
	struct if_group_count	*ifg;
762
763
	switch (iface->type) {
764
	case IF_TYPE_POINTOPOINT:
765
	case IF_TYPE_BROADCAST:
766
		LIST_FOREACH(ifg, &ifglist, entry)
767
			if (iface->ifindex == ifg->ifindex &&
768
			    addr->s_addr == ifg->addr.s_addr)
769
				break;
770
771
		/* if interface is not found just try to drop membership */
772
		if (ifg) {
773
			if (--ifg->count != 0)
774
				/* others still joined */
775
				return (0);
776
777
			LIST_REMOVE(ifg, entry);
778
			free(ifg);
779
		}
780
781
		mreq.imr_multiaddr.s_addr = addr->s_addr;
782
		mreq.imr_interface.s_addr = iface->addr.s_addr;
783
784
		if (setsockopt(iface->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
785
		    (void *)&mreq, sizeof(mreq)) < 0) {
786
			log_warn("if_leave_group: error IP_DROP_MEMBERSHIP, "
787
			    "interface %s address %s", iface->name,
788
			    inet_ntoa(*addr));
789
			return (-1);
790
		}
791
		break;
792
	case IF_TYPE_POINTOMULTIPOINT:
793
	case IF_TYPE_VIRTUALLINK:
794
	case IF_TYPE_NBMA:
795
		log_debug("if_leave_group: type %s not supported, interface %s",
796
		    if_type_name(iface->type), iface->name);
797
		return (-1);
798
	default:
799
		fatalx("if_leave_group: unknown interface type");
800
	}
801
802
	return (0);
803
}
804
805
int
806
if_set_mcast(struct iface *iface)
807
{
808
	switch (iface->type) {
809
	case IF_TYPE_POINTOPOINT:
810
	case IF_TYPE_BROADCAST:
811
		if (setsockopt(iface->fd, IPPROTO_IP, IP_MULTICAST_IF,
812
		    &iface->addr.s_addr, sizeof(iface->addr.s_addr)) < 0) {
813
			log_warn("if_set_mcast: error setting "
814
			    "IP_MULTICAST_IF, interface %s", iface->name);
815
			return (-1);
816
		}
817
		break;
818
	case IF_TYPE_POINTOMULTIPOINT:
819
	case IF_TYPE_VIRTUALLINK:
820
	case IF_TYPE_NBMA:
821
		log_debug("if_set_mcast: type %s not supported, interface %s",
822
		    if_type_name(iface->type), iface->name);
823
		return (-1);
824
	default:
825
		fatalx("if_set_mcast: unknown interface type");
826
	}
827
828
	return (0);
829
}
830
831
int
832
if_set_mcast_loop(int fd)
833
{
834
	u_int8_t	loop = 0;
835
836
	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
837
	    (char *)&loop, sizeof(loop)) < 0) {
838
		log_warn("if_set_mcast_loop: error setting IP_MULTICAST_LOOP");
839
		return (-1);
840
	}
841
842
	return (0);
843
}
844
845
int
846
if_set_ip_hdrincl(int fd)
847
{
848
	int	hincl = 1;
849
850
	if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof(hincl)) < 0) {
851
		log_warn("if_set_ip_hdrincl: error setting IP_HDRINCL");
852
		return (-1);
853
	}
854
855
	return (0);
856
}