GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/ospf6d/interface.c Lines: 0 368 0.0 %
Date: 2017-11-07 Branches: 0 254 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: interface.c,v 1.22 2015/09/27 17:31:50 stsp Exp $ */
2
3
/*
4
 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
5
 * Copyright (c) 2004, 2005, 2007 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 <stddef.h>
31
#include <stdio.h>
32
#include <stdlib.h>
33
#include <unistd.h>
34
#include <string.h>
35
#include <event.h>
36
37
#include "ospf6d.h"
38
#include "ospf6.h"
39
#include "log.h"
40
#include "ospfe.h"
41
42
void		 if_hello_timer(int, short, void *);
43
void		 if_start_hello_timer(struct iface *);
44
void		 if_stop_hello_timer(struct iface *);
45
void		 if_stop_wait_timer(struct iface *);
46
void		 if_wait_timer(int, short, void *);
47
void		 if_start_wait_timer(struct iface *);
48
void		 if_stop_wait_timer(struct iface *);
49
struct nbr	*if_elect(struct nbr *, struct nbr *);
50
51
struct {
52
	int			state;
53
	enum iface_event	event;
54
	enum iface_action	action;
55
	int			new_state;
56
} iface_fsm[] = {
57
    /* current state	event that happened	action to take	resulting state */
58
    {IF_STA_DOWN,	IF_EVT_UP,		IF_ACT_STRT,	0},
59
    {IF_STA_WAITING,	IF_EVT_BACKUP_SEEN,	IF_ACT_ELECT,	0},
60
    {IF_STA_WAITING,	IF_EVT_WTIMER,		IF_ACT_ELECT,	0},
61
    {IF_STA_ANY,	IF_EVT_WTIMER,		IF_ACT_NOTHING,	0},
62
    {IF_STA_WAITING,	IF_EVT_NBR_CHNG,	IF_ACT_NOTHING,	0},
63
    {IF_STA_MULTI,	IF_EVT_NBR_CHNG,	IF_ACT_ELECT,	0},
64
    {IF_STA_ANY,	IF_EVT_NBR_CHNG,	IF_ACT_NOTHING,	0},
65
    {IF_STA_ANY,	IF_EVT_DOWN,		IF_ACT_RST,	IF_STA_DOWN},
66
    {IF_STA_ANY,	IF_EVT_LOOP,		IF_ACT_RST,	IF_STA_LOOPBACK},
67
    {IF_STA_LOOPBACK,	IF_EVT_UNLOOP,		IF_ACT_NOTHING,	IF_STA_DOWN},
68
    {-1,		IF_EVT_NOTHING,		IF_ACT_NOTHING,	0},
69
};
70
71
#if 0
72
/* TODO virtual links */
73
static int vlink_cnt = 0;
74
#endif
75
76
TAILQ_HEAD(, iface)	iflist;
77
78
const char * const if_event_names[] = {
79
	"NOTHING",
80
	"UP",
81
	"WAITTIMER",
82
	"BACKUPSEEN",
83
	"NEIGHBORCHANGE",
84
	"LOOP",
85
	"UNLOOP",
86
	"DOWN"
87
};
88
89
const char * const if_action_names[] = {
90
	"NOTHING",
91
	"START",
92
	"ELECT",
93
	"RESET"
94
};
95
96
int
97
if_fsm(struct iface *iface, enum iface_event event)
98
{
99
	int	old_state;
100
	int	new_state = 0;
101
	int	i, ret = 0;
102
103
	old_state = iface->state;
104
105
	for (i = 0; iface_fsm[i].state != -1; i++)
106
		if ((iface_fsm[i].state & old_state) &&
107
		    (iface_fsm[i].event == event)) {
108
			new_state = iface_fsm[i].new_state;
109
			break;
110
		}
111
112
	if (iface_fsm[i].state == -1) {
113
		/* event outside of the defined fsm, ignore it. */
114
		log_debug("if_fsm: interface %s, "
115
		    "event %s not expected in state %s", iface->name,
116
		    if_event_names[event], if_state_name(old_state));
117
		return (0);
118
	}
119
120
	switch (iface_fsm[i].action) {
121
	case IF_ACT_STRT:
122
		ret = if_act_start(iface);
123
		break;
124
	case IF_ACT_ELECT:
125
		ret = if_act_elect(iface);
126
		break;
127
	case IF_ACT_RST:
128
		ret = if_act_reset(iface);
129
		break;
130
	case IF_ACT_NOTHING:
131
		/* do nothing */
132
		break;
133
	}
134
135
	if (ret) {
136
		log_debug("if_fsm: error changing state for interface %s, "
137
		    "event %s, state %s", iface->name, if_event_names[event],
138
		    if_state_name(old_state));
139
		return (-1);
140
	}
141
142
	if (new_state != 0)
143
		iface->state = new_state;
144
145
	if (iface->state != old_state) {
146
		orig_rtr_lsa(iface);
147
		orig_link_lsa(iface);
148
149
		/* state change inform RDE */
150
		ospfe_imsg_compose_rde(IMSG_IFINFO, iface->self->peerid, 0,
151
		    &iface->state, sizeof(iface->state));
152
	}
153
154
	if (old_state & (IF_STA_MULTI | IF_STA_POINTTOPOINT) &&
155
	    (iface->state & (IF_STA_MULTI | IF_STA_POINTTOPOINT)) == 0)
156
		ospfe_demote_iface(iface, 0);
157
	if ((old_state & (IF_STA_MULTI | IF_STA_POINTTOPOINT)) == 0 &&
158
	    iface->state & (IF_STA_MULTI | IF_STA_POINTTOPOINT))
159
		ospfe_demote_iface(iface, 1);
160
161
	log_debug("if_fsm: event %s resulted in action %s and changing "
162
	    "state for interface %s from %s to %s",
163
	    if_event_names[event], if_action_names[iface_fsm[i].action],
164
	    iface->name, if_state_name(old_state), if_state_name(iface->state));
165
166
	return (ret);
167
}
168
169
int
170
if_init(void)
171
{
172
	TAILQ_INIT(&iflist);
173
174
	return (fetchifs(0));
175
}
176
177
/* XXX using a linked list should be OK for now */
178
struct iface *
179
if_find(unsigned int ifindex)
180
{
181
	struct iface	*iface;
182
183
	TAILQ_FOREACH(iface, &iflist, list) {
184
		if (ifindex == iface->ifindex)
185
			return (iface);
186
	}
187
	return (NULL);
188
}
189
190
struct iface *
191
if_findname(char *name)
192
{
193
	struct iface	*iface;
194
195
	TAILQ_FOREACH(iface, &iflist, list) {
196
		if (!strcmp(name, iface->name))
197
			return (iface);
198
	}
199
	return (NULL);
200
}
201
202
struct iface *
203
if_new(u_short ifindex, char *ifname)
204
{
205
	struct iface		*iface;
206
207
	if ((iface = calloc(1, sizeof(*iface))) == NULL)
208
		err(1, "if_new: calloc");
209
210
	iface->state = IF_STA_DOWN;
211
212
	LIST_INIT(&iface->nbr_list);
213
	TAILQ_INIT(&iface->ifa_list);
214
	TAILQ_INIT(&iface->ls_ack_list);
215
	RB_INIT(&iface->lsa_tree);
216
217
#if 0
218
	/* TODO */
219
	if (virtual) {
220
		iface->type = IF_TYPE_VIRTUALLINK;
221
		snprintf(iface->name, sizeof(iface->name), "vlink%d",
222
		    vlink_cnt++);
223
		iface->flags |= IFF_UP;
224
		iface->mtu = IP_MSS;
225
		return (iface);
226
	}
227
#endif
228
	strlcpy(iface->name, ifname, sizeof(iface->name));
229
	iface->ifindex = ifindex;
230
231
	TAILQ_INSERT_TAIL(&iflist, iface, list);
232
233
	return (iface);
234
}
235
236
void
237
if_update(struct iface *iface, int mtu, int flags, u_int8_t type,
238
    u_int8_t state, u_int64_t rate)
239
{
240
	iface->mtu = mtu;
241
	iface->flags = flags;
242
	iface->if_type = type;
243
	iface->linkstate = state;
244
	iface->baudrate = rate;
245
246
	/* set type */
247
	if (flags & IFF_POINTOPOINT)
248
		iface->type = IF_TYPE_POINTOPOINT;
249
	if (flags & IFF_BROADCAST && flags & IFF_MULTICAST)
250
		iface->type = IF_TYPE_BROADCAST;
251
	if (flags & IFF_LOOPBACK) {
252
		iface->type = IF_TYPE_POINTOPOINT;
253
		iface->cflags |= F_IFACE_PASSIVE;
254
	}
255
}
256
257
void
258
if_del(struct iface *iface)
259
{
260
	struct nbr	*nbr = NULL;
261
262
	log_debug("if_del: interface %s", iface->name);
263
264
	/* revert the demotion when the interface is deleted */
265
	if ((iface->state & (IF_STA_MULTI | IF_STA_POINTTOPOINT)) == 0)
266
		ospfe_demote_iface(iface, 1);
267
268
	/* clear lists etc */
269
	while ((nbr = LIST_FIRST(&iface->nbr_list)) != NULL)
270
		nbr_del(nbr);
271
272
	if (evtimer_pending(&iface->hello_timer, NULL))
273
		evtimer_del(&iface->hello_timer);
274
	if (evtimer_pending(&iface->wait_timer, NULL))
275
		evtimer_del(&iface->wait_timer);
276
	if (evtimer_pending(&iface->lsack_tx_timer, NULL))
277
		evtimer_del(&iface->lsack_tx_timer);
278
279
	ls_ack_list_clr(iface);
280
	TAILQ_REMOVE(&iflist, iface, list);
281
	free(iface);
282
}
283
284
void
285
if_start(struct ospfd_conf *xconf, struct iface *iface)
286
{
287
	/* init the dummy local neighbor */
288
	iface->self = nbr_new(ospfe_router_id(), iface, iface->ifindex, 1,
289
			NULL);
290
291
	/* set event handlers for interface */
292
	evtimer_set(&iface->lsack_tx_timer, ls_ack_tx_timer, iface);
293
	evtimer_set(&iface->hello_timer, if_hello_timer, iface);
294
	evtimer_set(&iface->wait_timer, if_wait_timer, iface);
295
296
	iface->fd = xconf->ospf_socket;
297
298
	ospfe_demote_iface(iface, 0);
299
300
	if (if_fsm(iface, IF_EVT_UP))
301
		log_debug("error starting interface %s", iface->name);
302
}
303
304
/* timers */
305
/* ARGSUSED */
306
void
307
if_hello_timer(int fd, short event, void *arg)
308
{
309
	struct iface *iface = arg;
310
	struct timeval tv;
311
312
	send_hello(iface);
313
314
	/* reschedule hello_timer */
315
	timerclear(&tv);
316
	tv.tv_sec = iface->hello_interval;
317
	if (evtimer_add(&iface->hello_timer, &tv) == -1)
318
		fatal("if_hello_timer");
319
}
320
321
void
322
if_start_hello_timer(struct iface *iface)
323
{
324
	struct timeval tv;
325
326
	timerclear(&tv);
327
	if (evtimer_add(&iface->hello_timer, &tv) == -1)
328
		fatal("if_start_hello_timer");
329
}
330
331
void
332
if_stop_hello_timer(struct iface *iface)
333
{
334
	if (evtimer_del(&iface->hello_timer) == -1)
335
		fatal("if_stop_hello_timer");
336
}
337
338
/* ARGSUSED */
339
void
340
if_wait_timer(int fd, short event, void *arg)
341
{
342
	struct iface *iface = arg;
343
344
	if_fsm(iface, IF_EVT_WTIMER);
345
}
346
347
void
348
if_start_wait_timer(struct iface *iface)
349
{
350
	struct timeval	tv;
351
352
	timerclear(&tv);
353
	tv.tv_sec = iface->dead_interval;
354
	if (evtimer_add(&iface->wait_timer, &tv) == -1)
355
		fatal("if_start_wait_timer");
356
}
357
358
void
359
if_stop_wait_timer(struct iface *iface)
360
{
361
	if (evtimer_del(&iface->wait_timer) == -1)
362
		fatal("if_stop_wait_timer");
363
}
364
365
/* actions */
366
int
367
if_act_start(struct iface *iface)
368
{
369
	struct in6_addr		 addr;
370
	struct timeval		 now;
371
372
	if (!((iface->flags & IFF_UP) &&
373
	    LINK_STATE_IS_UP(iface->linkstate))) {
374
		log_debug("if_act_start: interface %s link down",
375
		    iface->name);
376
		return (0);
377
	}
378
379
	if (iface->if_type == IFT_CARP &&
380
	    !(iface->cflags & F_IFACE_PASSIVE)) {
381
		/* force passive mode on carp interfaces */
382
		log_warnx("if_act_start: forcing interface %s to passive",
383
		    iface->name);
384
		iface->cflags |= F_IFACE_PASSIVE;
385
	}
386
387
	gettimeofday(&now, NULL);
388
	iface->uptime = now.tv_sec;
389
390
	/* loopback interfaces have a special state */
391
	if (iface->flags & IFF_LOOPBACK)
392
		iface->state = IF_STA_LOOPBACK;
393
394
	if (iface->cflags & F_IFACE_PASSIVE) {
395
		/* for an update of stub network entries */
396
		orig_rtr_lsa(iface);
397
		return (0);
398
	}
399
400
	switch (iface->type) {
401
	case IF_TYPE_POINTOPOINT:
402
		inet_pton(AF_INET6, AllSPFRouters, &addr);
403
404
		if (if_join_group(iface, &addr))
405
			return (-1);
406
		iface->state = IF_STA_POINTTOPOINT;
407
		break;
408
	case IF_TYPE_VIRTUALLINK:
409
		iface->state = IF_STA_POINTTOPOINT;
410
		break;
411
	case IF_TYPE_POINTOMULTIPOINT:
412
	case IF_TYPE_NBMA:
413
		log_debug("if_act_start: type %s not supported, interface %s",
414
		    if_type_name(iface->type), iface->name);
415
		return (-1);
416
	case IF_TYPE_BROADCAST:
417
		inet_pton(AF_INET6, AllSPFRouters, &addr);
418
419
		if (if_join_group(iface, &addr))
420
			return (-1);
421
		if (iface->priority == 0) {
422
			iface->state = IF_STA_DROTHER;
423
		} else {
424
			iface->state = IF_STA_WAITING;
425
			if_start_wait_timer(iface);
426
		}
427
		break;
428
	default:
429
		fatalx("if_act_start: unknown interface type");
430
	}
431
432
	/* hello timer needs to be started in any case */
433
	if_start_hello_timer(iface);
434
	return (0);
435
}
436
437
struct nbr *
438
if_elect(struct nbr *a, struct nbr *b)
439
{
440
	if (a->priority > b->priority)
441
		return (a);
442
	if (a->priority < b->priority)
443
		return (b);
444
	if (ntohl(a->id.s_addr) > ntohl(b->id.s_addr))
445
		return (a);
446
	return (b);
447
}
448
449
int
450
if_act_elect(struct iface *iface)
451
{
452
	struct in6_addr	 addr;
453
	struct nbr	*nbr, *bdr = NULL, *dr = NULL;
454
	int		 round = 0;
455
	int		 changed = 0;
456
	int		 old_state;
457
	char		 b1[16], b2[16], b3[16], b4[16];
458
459
start:
460
	/* elect backup designated router */
461
	LIST_FOREACH(nbr, &iface->nbr_list, entry) {
462
		if (nbr->priority == 0 || nbr == dr ||	/* not electable */
463
		    nbr->state & NBR_STA_PRELIM ||	/* not available */
464
		    nbr->dr.s_addr == nbr->id.s_addr)	/* don't elect DR */
465
			continue;
466
		if (bdr != NULL) {
467
			/*
468
			 * routers announcing themselves as BDR have higher
469
			 * precedence over those routers announcing a
470
			 * different BDR.
471
			 */
472
			if (nbr->bdr.s_addr == nbr->id.s_addr) {
473
				if (bdr->bdr.s_addr == bdr->id.s_addr)
474
					bdr = if_elect(bdr, nbr);
475
				else
476
					bdr = nbr;
477
			} else if (bdr->bdr.s_addr != bdr->id.s_addr)
478
					bdr = if_elect(bdr, nbr);
479
		} else
480
			bdr = nbr;
481
	}
482
483
	/* elect designated router */
484
	LIST_FOREACH(nbr, &iface->nbr_list, entry) {
485
		if (nbr->priority == 0 || nbr->state & NBR_STA_PRELIM ||
486
		    (nbr != dr && nbr->dr.s_addr != nbr->id.s_addr))
487
			/* only DR may be elected check priority too */
488
			continue;
489
		if (dr == NULL)
490
			dr = nbr;
491
		else
492
			dr = if_elect(dr, nbr);
493
	}
494
495
	if (dr == NULL) {
496
		/* no designate router found use backup DR */
497
		dr = bdr;
498
		bdr = NULL;
499
	}
500
501
	/*
502
	 * if we are involved in the election (e.g. new DR or no
503
	 * longer BDR) redo the election
504
	 */
505
	if (round == 0 &&
506
	    ((iface->self == dr && iface->self != iface->dr) ||
507
	    (iface->self != dr && iface->self == iface->dr) ||
508
	    (iface->self == bdr && iface->self != iface->bdr) ||
509
	    (iface->self != bdr && iface->self == iface->bdr))) {
510
		/*
511
		 * Reset announced DR/BDR to calculated one, so
512
		 * that we may get elected in the second round.
513
		 * This is needed to drop from a DR to a BDR.
514
		 */
515
		iface->self->dr.s_addr = dr->id.s_addr;
516
		if (bdr)
517
			iface->self->bdr.s_addr = bdr->id.s_addr;
518
		round = 1;
519
		goto start;
520
	}
521
522
	log_debug("if_act_elect: interface %s old dr %s new dr %s, "
523
	    "old bdr %s new bdr %s", iface->name,
524
	    iface->dr ? inet_ntop(AF_INET, &iface->dr->id, b1, sizeof(b1)) :
525
	    "none", dr ? inet_ntop(AF_INET, &dr->id, b2, sizeof(b2)) : "none",
526
	    iface->bdr ? inet_ntop(AF_INET, &iface->bdr->id, b3, sizeof(b3)) :
527
	    "none", bdr ? inet_ntop(AF_INET, &bdr->id, b4, sizeof(b4)) :
528
	    "none");
529
530
	/*
531
	 * After the second round still DR or BDR change state to DR or BDR,
532
	 * etc.
533
	 */
534
	old_state = iface->state;
535
	if (dr == iface->self)
536
		iface->state = IF_STA_DR;
537
	else if (bdr == iface->self)
538
		iface->state = IF_STA_BACKUP;
539
	else
540
		iface->state = IF_STA_DROTHER;
541
542
	/* TODO if iface is NBMA send all non eligible neighbors event Start */
543
544
	/*
545
	 * if DR or BDR changed issue a AdjOK? event for all neighbors > 2-Way
546
	 */
547
	if (iface->dr != dr || iface->bdr != bdr)
548
		changed = 1;
549
550
	iface->dr = dr;
551
	iface->bdr = bdr;
552
553
	if (changed) {
554
		inet_pton(AF_INET6, AllDRouters, &addr);
555
		if (old_state & IF_STA_DRORBDR &&
556
		    (iface->state & IF_STA_DRORBDR) == 0) {
557
			if (if_leave_group(iface, &addr))
558
				return (-1);
559
		} else if ((old_state & IF_STA_DRORBDR) == 0 &&
560
		    iface->state & IF_STA_DRORBDR) {
561
			if (if_join_group(iface, &addr))
562
				return (-1);
563
		}
564
565
		LIST_FOREACH(nbr, &iface->nbr_list, entry) {
566
			if (nbr->state & NBR_STA_BIDIR)
567
				nbr_fsm(nbr, NBR_EVT_ADJ_OK);
568
		}
569
570
		orig_rtr_lsa(iface);
571
		if (iface->state & IF_STA_DR || old_state & IF_STA_DR)
572
			orig_net_lsa(iface);
573
	}
574
575
	if_start_hello_timer(iface);
576
	return (0);
577
}
578
579
int
580
if_act_reset(struct iface *iface)
581
{
582
	struct nbr		*nbr = NULL;
583
	struct in6_addr		 addr;
584
585
	if (iface->cflags & F_IFACE_PASSIVE) {
586
		/* for an update of stub network entries */
587
		orig_rtr_lsa(iface);
588
		return (0);
589
	}
590
591
	switch (iface->type) {
592
	case IF_TYPE_POINTOPOINT:
593
	case IF_TYPE_BROADCAST:
594
		inet_pton(AF_INET6, AllSPFRouters, &addr);
595
		if (if_leave_group(iface, &addr)) {
596
			log_warnx("if_act_reset: error leaving group %s, "
597
			    "interface %s", log_in6addr(&addr), iface->name);
598
		}
599
		if (iface->state & IF_STA_DRORBDR) {
600
			inet_pton(AF_INET6, AllDRouters, &addr);
601
			if (if_leave_group(iface, &addr)) {
602
				log_warnx("if_act_reset: "
603
				    "error leaving group %s, interface %s",
604
				    log_in6addr(&addr), iface->name);
605
			}
606
		}
607
		break;
608
	case IF_TYPE_VIRTUALLINK:
609
		/* nothing */
610
		break;
611
	case IF_TYPE_NBMA:
612
	case IF_TYPE_POINTOMULTIPOINT:
613
		log_debug("if_act_reset: type %s not supported, interface %s",
614
		    if_type_name(iface->type), iface->name);
615
		return (-1);
616
	default:
617
		fatalx("if_act_reset: unknown interface type");
618
	}
619
620
	LIST_FOREACH(nbr, &iface->nbr_list, entry) {
621
		if (nbr_fsm(nbr, NBR_EVT_KILL_NBR)) {
622
			log_debug("if_act_reset: error killing neighbor %s",
623
			    inet_ntoa(nbr->id));
624
		}
625
	}
626
627
	iface->dr = NULL;
628
	iface->bdr = NULL;
629
630
	ls_ack_list_clr(iface);
631
	stop_ls_ack_tx_timer(iface);
632
	if_stop_hello_timer(iface);
633
	if_stop_wait_timer(iface);
634
635
	/* send empty hello to tell everybody that we are going down */
636
	send_hello(iface);
637
638
	return (0);
639
}
640
641
struct ctl_iface *
642
if_to_ctl(struct iface *iface)
643
{
644
	static struct ctl_iface	 ictl;
645
	struct timeval		 tv, now, res;
646
	struct nbr		*nbr;
647
648
	memcpy(ictl.name, iface->name, sizeof(ictl.name));
649
	memcpy(&ictl.addr, &iface->addr, sizeof(ictl.addr));
650
	ictl.rtr_id.s_addr = ospfe_router_id();
651
	memcpy(&ictl.area, &iface->area_id, sizeof(ictl.area));
652
	if (iface->dr) {
653
		memcpy(&ictl.dr_id, &iface->dr->id, sizeof(ictl.dr_id));
654
		memcpy(&ictl.dr_addr, &iface->dr->addr, sizeof(ictl.dr_addr));
655
	} else {
656
		bzero(&ictl.dr_id, sizeof(ictl.dr_id));
657
		bzero(&ictl.dr_addr, sizeof(ictl.dr_addr));
658
	}
659
	if (iface->bdr) {
660
		memcpy(&ictl.bdr_id, &iface->bdr->id, sizeof(ictl.bdr_id));
661
		memcpy(&ictl.bdr_addr, &iface->bdr->addr,
662
		    sizeof(ictl.bdr_addr));
663
	} else {
664
		bzero(&ictl.bdr_id, sizeof(ictl.bdr_id));
665
		bzero(&ictl.bdr_addr, sizeof(ictl.bdr_addr));
666
	}
667
	ictl.ifindex = iface->ifindex;
668
	ictl.state = iface->state;
669
	ictl.mtu = iface->mtu;
670
	ictl.nbr_cnt = 0;
671
	ictl.adj_cnt = 0;
672
	ictl.baudrate = iface->baudrate;
673
	ictl.dead_interval = iface->dead_interval;
674
	ictl.transmit_delay = iface->transmit_delay;
675
	ictl.hello_interval = iface->hello_interval;
676
	ictl.flags = iface->flags;
677
	ictl.metric = iface->metric;
678
	ictl.rxmt_interval = iface->rxmt_interval;
679
	ictl.type = iface->type;
680
	ictl.linkstate = iface->linkstate;
681
	ictl.if_type = iface->if_type;
682
	ictl.priority = iface->priority;
683
	ictl.passive = (iface->cflags & F_IFACE_PASSIVE) == F_IFACE_PASSIVE;
684
685
	gettimeofday(&now, NULL);
686
	if (evtimer_pending(&iface->hello_timer, &tv)) {
687
		timersub(&tv, &now, &res);
688
		ictl.hello_timer = res.tv_sec;
689
	} else
690
		ictl.hello_timer = -1;
691
692
	if (iface->state != IF_STA_DOWN) {
693
		ictl.uptime = now.tv_sec - iface->uptime;
694
	} else
695
		ictl.uptime = 0;
696
697
	LIST_FOREACH(nbr, &iface->nbr_list, entry) {
698
		if (nbr == iface->self)
699
			continue;
700
		ictl.nbr_cnt++;
701
		if (nbr->state & NBR_STA_ADJFORM)
702
			ictl.adj_cnt++;
703
	}
704
705
	return (&ictl);
706
}
707
708
/* misc */
709
void
710
if_set_recvbuf(int fd)
711
{
712
	int	bsize;
713
714
	bsize = 65535;
715
	while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize,
716
	    sizeof(bsize)) == -1)
717
		bsize /= 2;
718
}
719
720
int
721
if_join_group(struct iface *iface, struct in6_addr *addr)
722
{
723
	struct ipv6_mreq	 mreq;
724
725
	switch (iface->type) {
726
	case IF_TYPE_POINTOPOINT:
727
	case IF_TYPE_BROADCAST:
728
		log_debug("if_join_group: interface %s addr %s",
729
		    iface->name, log_in6addr(addr));
730
		mreq.ipv6mr_multiaddr = *addr;
731
		mreq.ipv6mr_interface = iface->ifindex;
732
733
		if (setsockopt(iface->fd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
734
		    &mreq, sizeof(mreq)) < 0) {
735
			log_warn("if_join_group: error IPV6_JOIN_GROUP, "
736
			    "interface %s address %s", iface->name,
737
			    log_in6addr(addr));
738
			return (-1);
739
		}
740
		break;
741
	case IF_TYPE_POINTOMULTIPOINT:
742
	case IF_TYPE_VIRTUALLINK:
743
	case IF_TYPE_NBMA:
744
		log_debug("if_join_group: type %s not supported, interface %s",
745
		    if_type_name(iface->type), iface->name);
746
		return (-1);
747
	default:
748
		fatalx("if_join_group: unknown interface type");
749
	}
750
751
	return (0);
752
}
753
754
int
755
if_leave_group(struct iface *iface, struct in6_addr *addr)
756
{
757
	struct ipv6_mreq	 mreq;
758
759
	switch (iface->type) {
760
	case IF_TYPE_POINTOPOINT:
761
	case IF_TYPE_BROADCAST:
762
		log_debug("if_leave_group: interface %s addr %s",
763
		    iface->name, log_in6addr(addr));
764
		mreq.ipv6mr_multiaddr = *addr;
765
		mreq.ipv6mr_interface = iface->ifindex;
766
767
		if (setsockopt(iface->fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
768
		    (void *)&mreq, sizeof(mreq)) < 0) {
769
			log_warn("if_leave_group: error IPV6_LEAVE_GROUP, "
770
			    "interface %s address %s", iface->name,
771
			    log_in6addr(addr));
772
			return (-1);
773
		}
774
		break;
775
	case IF_TYPE_POINTOMULTIPOINT:
776
	case IF_TYPE_VIRTUALLINK:
777
	case IF_TYPE_NBMA:
778
		log_debug("if_leave_group: type %s not supported, interface %s",
779
		    if_type_name(iface->type), iface->name);
780
		return (-1);
781
	default:
782
		fatalx("if_leave_group: unknown interface type");
783
	}
784
	return (0);
785
}
786
787
int
788
if_set_mcast(struct iface *iface)
789
{
790
	switch (iface->type) {
791
	case IF_TYPE_POINTOPOINT:
792
	case IF_TYPE_BROADCAST:
793
		if (setsockopt(iface->fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
794
		    &iface->ifindex, sizeof(iface->ifindex)) < 0) {
795
			log_debug("if_set_mcast: error setting "
796
			    "IP_MULTICAST_IF, interface %s", iface->name);
797
			return (-1);
798
		}
799
		break;
800
	case IF_TYPE_POINTOMULTIPOINT:
801
	case IF_TYPE_VIRTUALLINK:
802
	case IF_TYPE_NBMA:
803
		log_debug("if_set_mcast: type %s not supported, interface %s",
804
		    if_type_name(iface->type), iface->name);
805
		return (-1);
806
	default:
807
		fatalx("if_set_mcast: unknown interface type");
808
	}
809
810
	return (0);
811
}
812
813
int
814
if_set_mcast_loop(int fd)
815
{
816
	u_int	loop = 0;
817
818
	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
819
	    (u_int *)&loop, sizeof(loop)) < 0) {
820
		log_warn("if_set_mcast_loop: error setting "
821
		    "IPV6_MULTICAST_LOOP");
822
		return (-1);
823
	}
824
825
	return (0);
826
}
827
828
int
829
if_set_ipv6_pktinfo(int fd, int enable)
830
{
831
	if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &enable,
832
	    sizeof(enable)) < 0) {
833
		log_warn("if_set_ipv6_pktinfo: error setting IPV6_PKTINFO");
834
		return (-1);
835
	}
836
837
	return (0);
838
}
839
840
int
841
if_set_ipv6_checksum(int fd)
842
{
843
	int	offset = offsetof(struct ospf_hdr, chksum);
844
845
	log_debug("if_set_ipv6_checksum setting cksum offset to %d", offset);
846
	if (setsockopt(fd, IPPROTO_IPV6, IPV6_CHECKSUM, &offset,
847
	     sizeof(offset)) < 0) {
848
		log_warn("if_set_ipv6_checksum: error setting IPV6_CHECKSUM");
849
		return (-1);
850
	}
851
	return (0);
852
}