GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/eigrpd/interface.c Lines: 0 347 0.0 %
Date: 2017-11-13 Branches: 0 396 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: interface.c,v 1.24 2017/02/22 14:24:50 renato Exp $ */
2
3
/*
4
 * Copyright (c) 2015 Renato Westphal <renato@openbsd.org>
5
 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
6
 * Copyright (c) 2004, 2005 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/socket.h>
23
#include <sys/ioctl.h>
24
#include <arpa/inet.h>
25
26
#include <ctype.h>
27
#include <stdlib.h>
28
#include <string.h>
29
#include <unistd.h>
30
31
#include "eigrpd.h"
32
#include "eigrpe.h"
33
#include "log.h"
34
35
static __inline int	 iface_id_compare(struct eigrp_iface *,
36
			    struct eigrp_iface *);
37
static struct iface	*if_new(struct eigrpd_conf *, struct kif *);
38
static void		 if_del(struct iface *);
39
static struct if_addr	*if_addr_lookup(struct if_addr_head *, struct kaddr *);
40
static void		 eigrp_if_start(struct eigrp_iface *);
41
static void		 eigrp_if_reset(struct eigrp_iface *);
42
static void		 eigrp_if_hello_timer(int, short, void *);
43
static void		 eigrp_if_start_hello_timer(struct eigrp_iface *);
44
static void		 eigrp_if_stop_hello_timer(struct eigrp_iface *);
45
static int		 if_join_ipv4_group(struct iface *, struct in_addr *);
46
static int		 if_leave_ipv4_group(struct iface *, struct in_addr *);
47
static int		 if_join_ipv6_group(struct iface *, struct in6_addr *);
48
static int		 if_leave_ipv6_group(struct iface *, struct in6_addr *);
49
50
RB_GENERATE(iface_id_head, eigrp_iface, id_tree, iface_id_compare)
51
52
struct iface_id_head ifaces_by_id = RB_INITIALIZER(&ifaces_by_id);
53
54
static __inline int
55
iface_id_compare(struct eigrp_iface *a, struct eigrp_iface *b)
56
{
57
	return (a->ifaceid - b->ifaceid);
58
}
59
60
static struct iface *
61
if_new(struct eigrpd_conf *xconf, struct kif *kif)
62
{
63
	struct iface		*iface;
64
65
	if ((iface = calloc(1, sizeof(*iface))) == NULL)
66
		fatal("if_new: calloc");
67
68
	TAILQ_INIT(&iface->ei_list);
69
	TAILQ_INIT(&iface->addr_list);
70
71
	strlcpy(iface->name, kif->ifname, sizeof(iface->name));
72
73
	/* get type */
74
	if (kif->flags & IFF_POINTOPOINT)
75
		iface->type = IF_TYPE_POINTOPOINT;
76
	if (kif->flags & IFF_BROADCAST &&
77
	    kif->flags & IFF_MULTICAST)
78
		iface->type = IF_TYPE_BROADCAST;
79
	if (kif->flags & IFF_LOOPBACK)
80
		iface->type = IF_TYPE_POINTOPOINT;
81
82
	/* get index and flags */
83
	iface->mtu = kif->mtu;
84
	iface->ifindex = kif->ifindex;
85
	iface->rdomain = kif->rdomain;
86
	iface->flags = kif->flags;
87
	iface->linkstate = kif->link_state;
88
	iface->if_type = kif->if_type;
89
	iface->baudrate = kif->baudrate;
90
91
	TAILQ_INSERT_TAIL(&xconf->iface_list, iface, entry);
92
93
	return (iface);
94
}
95
96
static void
97
if_del(struct iface *iface)
98
{
99
	struct if_addr		*if_addr;
100
101
	log_debug("%s: interface %s", __func__, iface->name);
102
103
	while ((if_addr = TAILQ_FIRST(&iface->addr_list)) != NULL) {
104
		TAILQ_REMOVE(&iface->addr_list, if_addr, entry);
105
		free(if_addr);
106
	}
107
108
	TAILQ_REMOVE(&econf->iface_list, iface, entry);
109
	free(iface);
110
}
111
112
struct iface *
113
if_lookup(struct eigrpd_conf *xconf, unsigned int ifindex)
114
{
115
	struct iface	*iface;
116
117
	TAILQ_FOREACH(iface, &xconf->iface_list, entry)
118
		if (iface->ifindex == ifindex)
119
			return (iface);
120
121
	return (NULL);
122
}
123
124
void
125
if_addr_new(struct iface *iface, struct kaddr *ka)
126
{
127
	struct if_addr		*if_addr;
128
	struct eigrp_iface	*ei;
129
130
	if (ka->af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&ka->addr.v6)) {
131
		iface->linklocal = ka->addr.v6;
132
		if_update(iface, AF_INET6);
133
		return;
134
	}
135
136
	if (if_addr_lookup(&iface->addr_list, ka) != NULL)
137
		return;
138
139
	if ((if_addr = calloc(1, sizeof(*if_addr))) == NULL)
140
		fatal("if_addr_new: calloc");
141
	if_addr->af = ka->af;
142
	if_addr->addr = ka->addr;
143
	if_addr->prefixlen = ka->prefixlen;
144
	if_addr->dstbrd = ka->dstbrd;
145
	TAILQ_INSERT_TAIL(&iface->addr_list, if_addr, entry);
146
147
	TAILQ_FOREACH(ei, &iface->ei_list, i_entry)
148
		if (ei->state == IF_STA_ACTIVE && ei->eigrp->af == if_addr->af)
149
			eigrpe_orig_local_route(ei, if_addr, 0);
150
151
	if (if_addr->af == AF_INET)
152
		if_update(iface, AF_INET);
153
}
154
155
void
156
if_addr_del(struct iface *iface, struct kaddr *ka)
157
{
158
	struct if_addr		*if_addr;
159
	struct eigrp_iface	*ei;
160
	int			 af = ka->af;
161
162
	if (ka->af == AF_INET6 &&
163
	    IN6_ARE_ADDR_EQUAL(&iface->linklocal, &ka->addr.v6)) {
164
		memset(&iface->linklocal, 0, sizeof(iface->linklocal));
165
		if_update(iface, AF_INET6);
166
		return;
167
	}
168
169
	if_addr = if_addr_lookup(&iface->addr_list, ka);
170
	if (if_addr == NULL)
171
		return;
172
173
	TAILQ_FOREACH(ei, &iface->ei_list, i_entry)
174
		if (ei->state == IF_STA_ACTIVE && ei->eigrp->af == if_addr->af)
175
			eigrpe_orig_local_route(ei, if_addr, 1);
176
177
	TAILQ_REMOVE(&iface->addr_list, if_addr, entry);
178
	free(if_addr);
179
180
	if (af == AF_INET)
181
		if_update(iface, AF_INET);
182
}
183
184
static struct if_addr *
185
if_addr_lookup(struct if_addr_head *addr_list, struct kaddr *ka)
186
{
187
	struct if_addr	*if_addr;
188
	int		 af = ka->af;
189
190
	TAILQ_FOREACH(if_addr, addr_list, entry)
191
		if (!eigrp_addrcmp(af, &if_addr->addr, &ka->addr) &&
192
		    if_addr->prefixlen == ka->prefixlen &&
193
		    !eigrp_addrcmp(af, &if_addr->dstbrd, &ka->dstbrd))
194
			return (if_addr);
195
196
	return (NULL);
197
}
198
199
in_addr_t
200
if_primary_addr(struct iface *iface)
201
{
202
	struct if_addr	*if_addr;
203
204
	TAILQ_FOREACH(if_addr, &iface->addr_list, entry)
205
		if (if_addr->af == AF_INET)
206
			return (if_addr->addr.v4.s_addr);
207
208
	return (INADDR_ANY);
209
}
210
211
uint8_t
212
if_primary_addr_prefixlen(struct iface *iface)
213
{
214
	struct if_addr	*if_addr;
215
216
	TAILQ_FOREACH(if_addr, &iface->addr_list, entry)
217
		if (if_addr->af == AF_INET)
218
			return (if_addr->prefixlen);
219
220
	return (0);
221
}
222
223
/* up/down events */
224
void
225
if_update(struct iface *iface, int af)
226
{
227
	struct eigrp_iface	*ei;
228
	int			 link_ok;
229
	int			 addr_ok, addr4_ok = 0, addr6_ok = 0;
230
	struct if_addr		*if_addr;
231
232
	link_ok = (iface->flags & IFF_UP) &&
233
	    LINK_STATE_IS_UP(iface->linkstate);
234
235
	/*
236
	 * NOTE: for EIGRPv4, each interface should have at least one valid
237
	 * IP address otherwise they can not be enabled in the routing domain.
238
	 */
239
	TAILQ_FOREACH(if_addr, &iface->addr_list, entry) {
240
		if (if_addr->af == AF_INET) {
241
			addr4_ok = 1;
242
			break;
243
		}
244
	}
245
	/* for IPv6 the link-local address is enough. */
246
	if (IN6_IS_ADDR_LINKLOCAL(&iface->linklocal))
247
		addr6_ok = 1;
248
249
	TAILQ_FOREACH(ei, &iface->ei_list, i_entry) {
250
		if (af != AF_UNSPEC && ei->eigrp->af != af)
251
			continue;
252
253
		switch (ei->eigrp->af) {
254
		case AF_INET:
255
			addr_ok = addr4_ok;
256
			break;
257
		case AF_INET6:
258
			addr_ok = addr6_ok;
259
			break;
260
		default:
261
			fatalx("if_update: unknown af");
262
		}
263
264
		if (ei->state == IF_STA_DOWN) {
265
			if (!link_ok || !addr_ok)
266
				continue;
267
			ei->state = IF_STA_ACTIVE;
268
			eigrp_if_start(ei);
269
		} else if (ei->state == IF_STA_ACTIVE) {
270
			if (link_ok && addr_ok)
271
				continue;
272
			ei->state = IF_STA_DOWN;
273
			eigrp_if_reset(ei);
274
		}
275
	}
276
}
277
278
struct eigrp_iface *
279
eigrp_if_new(struct eigrpd_conf *xconf, struct eigrp *eigrp, struct kif *kif)
280
{
281
	struct iface		*iface;
282
	struct eigrp_iface	*ei;
283
	static uint32_t		 ifacecnt = 1;
284
285
	iface = if_lookup(xconf, kif->ifindex);
286
	if (iface == NULL)
287
		iface = if_new(xconf, kif);
288
289
	if ((ei = calloc(1, sizeof(*ei))) == NULL)
290
		fatal("eigrp_if_new: calloc");
291
292
	ei->state = IF_STA_DOWN;
293
	/* get next unused ifaceid */
294
	while (eigrp_if_lookup_id(ifacecnt++))
295
		;
296
	ei->ifaceid = ifacecnt;
297
	ei->eigrp = eigrp;
298
	ei->iface = iface;
299
	if (ei->iface->flags & IFF_LOOPBACK)
300
		ei->passive = 1;
301
302
	TAILQ_INIT(&ei->nbr_list);
303
	TAILQ_INIT(&ei->update_list);
304
	TAILQ_INIT(&ei->query_list);
305
	TAILQ_INIT(&ei->summary_list);
306
	TAILQ_INSERT_TAIL(&iface->ei_list, ei, i_entry);
307
	TAILQ_INSERT_TAIL(&eigrp->ei_list, ei, e_entry);
308
	if (RB_INSERT(iface_id_head, &ifaces_by_id, ei) != NULL)
309
		fatalx("eigrp_if_new: RB_INSERT(ifaces_by_id) failed");
310
311
	return (ei);
312
}
313
314
void
315
eigrp_if_del(struct eigrp_iface *ei)
316
{
317
	struct summary_addr	*summary;
318
319
	RB_REMOVE(iface_id_head, &ifaces_by_id, ei);
320
	TAILQ_REMOVE(&ei->eigrp->ei_list, ei, e_entry);
321
	TAILQ_REMOVE(&ei->iface->ei_list, ei, i_entry);
322
	while ((summary = TAILQ_FIRST(&ei->summary_list)) != NULL) {
323
		TAILQ_REMOVE(&ei->summary_list, summary, entry);
324
		free(summary);
325
	}
326
	message_list_clr(&ei->query_list);
327
	message_list_clr(&ei->update_list);
328
329
	if (ei->state == IF_STA_ACTIVE)
330
		eigrp_if_reset(ei);
331
332
	if (TAILQ_EMPTY(&ei->iface->ei_list))
333
		if_del(ei->iface);
334
335
	free(ei);
336
}
337
338
struct eigrp_iface *
339
eigrp_if_lookup(struct iface *iface, int af, uint16_t as)
340
{
341
	struct eigrp_iface	*ei;
342
343
	TAILQ_FOREACH(ei, &iface->ei_list, i_entry)
344
		if (ei->eigrp->af == af &&
345
		    ei->eigrp->as == as)
346
			return (ei);
347
348
	return (NULL);
349
}
350
351
struct eigrp_iface *
352
eigrp_if_lookup_id(uint32_t ifaceid)
353
{
354
	struct eigrp_iface	 e;
355
	e.ifaceid = ifaceid;
356
	return (RB_FIND(iface_id_head, &ifaces_by_id, &e));
357
}
358
359
static void
360
eigrp_if_start(struct eigrp_iface *ei)
361
{
362
	struct eigrp		*eigrp = ei->eigrp;
363
	struct timeval		 now;
364
	struct if_addr		*if_addr;
365
	union eigrpd_addr	 addr;
366
367
	log_debug("%s: %s as %u family %s", __func__, ei->iface->name,
368
	    eigrp->as, af_name(eigrp->af));
369
370
	gettimeofday(&now, NULL);
371
	ei->uptime = now.tv_sec;
372
373
	/* init the dummy self neighbor */
374
	memset(&addr, 0, sizeof(addr));
375
	ei->self = nbr_new(ei, &addr, 0, 1);
376
	nbr_init(ei->self);
377
378
	TAILQ_FOREACH(if_addr, &ei->iface->addr_list, entry) {
379
		if (if_addr->af != eigrp->af)
380
			continue;
381
382
		eigrpe_orig_local_route(ei, if_addr, 0);
383
	}
384
385
	if (ei->passive)
386
		return;
387
388
	switch (eigrp->af) {
389
	case AF_INET:
390
		if (if_join_ipv4_group(ei->iface, &global.mcast_addr_v4))
391
			return;
392
		break;
393
	case AF_INET6:
394
		if (if_join_ipv6_group(ei->iface, &global.mcast_addr_v6))
395
			return;
396
		break;
397
	default:
398
		fatalx("eigrp_if_start: unknown af");
399
	}
400
401
	evtimer_set(&ei->hello_timer, eigrp_if_hello_timer, ei);
402
	eigrp_if_start_hello_timer(ei);
403
}
404
405
static void
406
eigrp_if_reset(struct eigrp_iface *ei)
407
{
408
	struct eigrp		*eigrp = ei->eigrp;
409
	struct nbr		*nbr;
410
411
	log_debug("%s: %s as %u family %s", __func__, ei->iface->name,
412
	    eigrp->as, af_name(eigrp->af));
413
414
	/* the rde will withdraw the connected route for us */
415
416
	while ((nbr = TAILQ_FIRST(&ei->nbr_list)) != NULL)
417
		nbr_del(nbr);
418
419
	if (ei->passive)
420
		return;
421
422
	/* try to cleanup */
423
	switch (eigrp->af) {
424
	case AF_INET:
425
		if_leave_ipv4_group(ei->iface, &global.mcast_addr_v4);
426
		break;
427
	case AF_INET6:
428
		if_leave_ipv6_group(ei->iface, &global.mcast_addr_v6);
429
		break;
430
	default:
431
		fatalx("eigrp_if_reset: unknown af");
432
	}
433
434
	eigrp_if_stop_hello_timer(ei);
435
}
436
437
/* timers */
438
/* ARGSUSED */
439
static void
440
eigrp_if_hello_timer(int fd, short event, void *arg)
441
{
442
	struct eigrp_iface	*ei = arg;
443
	struct timeval		 tv;
444
445
	send_hello(ei, NULL, 0);
446
447
	/* reschedule hello_timer */
448
	timerclear(&tv);
449
	tv.tv_sec = ei->hello_interval;
450
	if (evtimer_add(&ei->hello_timer, &tv) == -1)
451
		fatal("eigrp_if_hello_timer");
452
}
453
454
static void
455
eigrp_if_start_hello_timer(struct eigrp_iface *ei)
456
{
457
	struct timeval		 tv;
458
459
	timerclear(&tv);
460
	tv.tv_sec = ei->hello_interval;
461
	if (evtimer_add(&ei->hello_timer, &tv) == -1)
462
		fatal("eigrp_if_start_hello_timer");
463
}
464
465
static void
466
eigrp_if_stop_hello_timer(struct eigrp_iface *ei)
467
{
468
	if (evtimer_pending(&ei->hello_timer, NULL) &&
469
	    evtimer_del(&ei->hello_timer) == -1)
470
		fatal("eigrp_if_stop_hello_timer");
471
}
472
473
struct ctl_iface *
474
if_to_ctl(struct eigrp_iface *ei)
475
{
476
	static struct ctl_iface	 ictl;
477
	struct timeval		 now;
478
	struct nbr		*nbr;
479
480
	ictl.af = ei->eigrp->af;
481
	ictl.as = ei->eigrp->as;
482
	memcpy(ictl.name, ei->iface->name, sizeof(ictl.name));
483
	ictl.ifindex = ei->iface->ifindex;
484
	switch (ei->eigrp->af) {
485
	case AF_INET:
486
		ictl.addr.v4.s_addr = if_primary_addr(ei->iface);
487
		ictl.prefixlen = if_primary_addr_prefixlen(ei->iface);
488
		break;
489
	case AF_INET6:
490
		ictl.addr.v6 = ei->iface->linklocal;
491
		if (!IN6_IS_ADDR_UNSPECIFIED(&ei->iface->linklocal))
492
			ictl.prefixlen = 64;
493
		else
494
			ictl.prefixlen = 0;
495
		break;
496
	default:
497
		fatalx("if_to_ctl: unknown af");
498
	}
499
	ictl.flags = ei->iface->flags;
500
	ictl.linkstate = ei->iface->linkstate;
501
	ictl.mtu = ei->iface->mtu;
502
	ictl.type = ei->iface->type;
503
	ictl.if_type = ei->iface->if_type;
504
	ictl.baudrate = ei->iface->baudrate;
505
	ictl.delay = ei->delay;
506
	ictl.bandwidth = ei->bandwidth;
507
	ictl.hello_holdtime = ei->hello_holdtime;
508
	ictl.hello_interval = ei->hello_interval;
509
	ictl.splithorizon = ei->splithorizon;
510
	ictl.passive = ei->passive;
511
	ictl.nbr_cnt = 0;
512
513
	gettimeofday(&now, NULL);
514
	if (ei->state != IF_STA_DOWN && ei->uptime != 0)
515
		ictl.uptime = now.tv_sec - ei->uptime;
516
	else
517
		ictl.uptime = 0;
518
519
	TAILQ_FOREACH(nbr, &ei->nbr_list, entry)
520
		if (!(nbr->flags & (F_EIGRP_NBR_PENDING|F_EIGRP_NBR_SELF)))
521
			ictl.nbr_cnt++;
522
523
	return (&ictl);
524
}
525
526
/* misc */
527
void
528
if_set_sockbuf(int fd)
529
{
530
	int	bsize;
531
532
	bsize = 65535;
533
	while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize,
534
	    sizeof(bsize)) == -1)
535
		bsize /= 2;
536
537
	if (bsize != 65535)
538
		log_warnx("%s: recvbuf size only %d", __func__, bsize);
539
540
	bsize = 65535;
541
	while (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &bsize,
542
	    sizeof(bsize)) == -1)
543
		bsize /= 2;
544
545
	if (bsize != 65535)
546
		log_warnx("%s: sendbuf size only %d", __func__, bsize);
547
}
548
549
static int
550
if_join_ipv4_group(struct iface *iface, struct in_addr *addr)
551
{
552
	struct ip_mreq		 mreq;
553
554
	if (iface->group_count_v4++ != 0)
555
		/* already joined */
556
		return (0);
557
558
	log_debug("%s: interface %s addr %s", __func__, iface->name,
559
	    inet_ntoa(*addr));
560
561
	mreq.imr_multiaddr = *addr;
562
	mreq.imr_interface.s_addr = if_primary_addr(iface);
563
564
	if (setsockopt(global.eigrp_socket_v4, IPPROTO_IP, IP_ADD_MEMBERSHIP,
565
	    (void *)&mreq, sizeof(mreq)) < 0) {
566
		log_warn("%s: error IP_ADD_MEMBERSHIP, interface %s address %s",
567
		    __func__, iface->name, inet_ntoa(*addr));
568
		return (-1);
569
	}
570
571
	return (0);
572
}
573
574
static int
575
if_leave_ipv4_group(struct iface *iface, struct in_addr *addr)
576
{
577
	struct ip_mreq		 mreq;
578
579
	if (--iface->group_count_v4 != 0)
580
		/* others still joined */
581
		return (0);
582
583
	log_debug("%s: interface %s addr %s", __func__, iface->name,
584
	    inet_ntoa(*addr));
585
586
	mreq.imr_multiaddr = *addr;
587
	mreq.imr_interface.s_addr = if_primary_addr(iface);
588
589
	if (setsockopt(global.eigrp_socket_v4, IPPROTO_IP, IP_DROP_MEMBERSHIP,
590
	    (void *)&mreq, sizeof(mreq)) < 0) {
591
		log_warn("%s: error IP_DROP_MEMBERSHIP, interface %s "
592
		    "address %s", iface->name, __func__, inet_ntoa(*addr));
593
		return (-1);
594
	}
595
596
	return (0);
597
}
598
599
int
600
if_set_ipv4_mcast_ttl(int fd, uint8_t ttl)
601
{
602
	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
603
	    (char *)&ttl, sizeof(ttl)) < 0) {
604
		log_warn("%s: error setting IP_MULTICAST_TTL to %d",
605
		    __func__, ttl);
606
		return (-1);
607
	}
608
609
	return (0);
610
}
611
612
int
613
if_set_ipv4_mcast(struct iface *iface)
614
{
615
	in_addr_t	 addr;
616
617
	addr = if_primary_addr(iface);
618
619
	if (setsockopt(global.eigrp_socket_v4, IPPROTO_IP, IP_MULTICAST_IF,
620
	    &addr, sizeof(addr)) < 0) {
621
		log_warn("%s: error setting IP_MULTICAST_IF, interface %s",
622
		    __func__, iface->name);
623
		return (-1);
624
	}
625
626
	return (0);
627
}
628
629
int
630
if_set_ipv4_mcast_loop(int fd)
631
{
632
	uint8_t	loop = 0;
633
634
	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
635
	    (char *)&loop, sizeof(loop)) < 0) {
636
		log_warn("%s: error setting IP_MULTICAST_LOOP", __func__);
637
		return (-1);
638
	}
639
640
	return (0);
641
}
642
643
int
644
if_set_ipv4_recvif(int fd, int enable)
645
{
646
	if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &enable,
647
	    sizeof(enable)) < 0) {
648
		log_warn("%s: error setting IP_RECVIF", __func__);
649
		return (-1);
650
	}
651
	return (0);
652
}
653
654
int
655
if_set_ipv4_hdrincl(int fd)
656
{
657
	int	hincl = 1;
658
659
	if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof(hincl)) < 0) {
660
		log_warn("%s: error setting IP_HDRINCL", __func__);
661
		return (-1);
662
	}
663
664
	return (0);
665
}
666
667
static int
668
if_join_ipv6_group(struct iface *iface, struct in6_addr *addr)
669
{
670
	struct ipv6_mreq	 mreq;
671
672
	if (iface->group_count_v6++ != 0)
673
		/* already joined */
674
		return (0);
675
676
	log_debug("%s: interface %s addr %s", __func__, iface->name,
677
	    log_in6addr(addr));
678
679
	mreq.ipv6mr_multiaddr = *addr;
680
	mreq.ipv6mr_interface = iface->ifindex;
681
682
	if (setsockopt(global.eigrp_socket_v6, IPPROTO_IPV6, IPV6_JOIN_GROUP,
683
	    &mreq, sizeof(mreq)) < 0) {
684
		log_warn("%s: error IPV6_JOIN_GROUP, interface %s address %s",
685
		    __func__, iface->name, log_in6addr(addr));
686
		return (-1);
687
	}
688
689
	return (0);
690
}
691
692
static int
693
if_leave_ipv6_group(struct iface *iface, struct in6_addr *addr)
694
{
695
	struct ipv6_mreq	 mreq;
696
697
	if (--iface->group_count_v6 != 0)
698
		/* others still joined */
699
		return (0);
700
701
	log_debug("%s: interface %s addr %s", __func__, iface->name,
702
	    log_in6addr(addr));
703
704
	mreq.ipv6mr_multiaddr = *addr;
705
	mreq.ipv6mr_interface = iface->ifindex;
706
707
	if (setsockopt(global.eigrp_socket_v6, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
708
	    (void *)&mreq, sizeof(mreq)) < 0) {
709
		log_warn("%s: error IPV6_LEAVE_GROUP, interface %s address %s",
710
		    __func__, iface->name, log_in6addr(addr));
711
		return (-1);
712
	}
713
714
	return (0);
715
}
716
717
int
718
if_set_ipv6_mcast(struct iface *iface)
719
{
720
	if (setsockopt(global.eigrp_socket_v6, IPPROTO_IPV6, IPV6_MULTICAST_IF,
721
	    &iface->ifindex, sizeof(iface->ifindex)) < 0) {
722
		log_warn("%s: error setting IPV6_MULTICAST_IF, interface %s",
723
		    __func__, iface->name);
724
		return (-1);
725
	}
726
727
	return (0);
728
}
729
730
int
731
if_set_ipv6_mcast_loop(int fd)
732
{
733
	unsigned int	loop = 0;
734
735
	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
736
	    (unsigned int *)&loop, sizeof(loop)) < 0) {
737
		log_warn("%s: error setting IPV6_MULTICAST_LOOP", __func__);
738
		return (-1);
739
	}
740
741
	return (0);
742
}
743
744
int
745
if_set_ipv6_pktinfo(int fd, int enable)
746
{
747
	if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &enable,
748
	    sizeof(enable)) < 0) {
749
		log_warn("%s: error setting IPV6_RECVPKTINFO", __func__);
750
		return (-1);
751
	}
752
753
	return (0);
754
}
755
756
int
757
if_set_ipv6_dscp(int fd, int dscp)
758
{
759
	if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &dscp,
760
	    sizeof(dscp)) < 0) {
761
		log_warn("%s: error setting IPV6_TCLASS", __func__);
762
		return (-1);
763
	}
764
765
	return (0);
766
}