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

Line Branch Exec Source
1
/*	$OpenBSD: interface.c,v 1.50 2017/03/03 23:41:27 renato Exp $ */
2
3
/*
4
 * Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org>
5
 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
6
 * Copyright (c) 2004, 2005, 2008 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/time.h>
23
#include <arpa/inet.h>
24
#include <stdlib.h>
25
#include <string.h>
26
27
#include "ldpd.h"
28
#include "ldpe.h"
29
#include "log.h"
30
31
static struct if_addr	*if_addr_new(struct kaddr *);
32
static struct if_addr	*if_addr_lookup(struct if_addr_head *, struct kaddr *);
33
static int		 if_start(struct iface *, int);
34
static int		 if_reset(struct iface *, int);
35
static void		 if_update_af(struct iface_af *, int);
36
static void		 if_hello_timer(int, short, void *);
37
static void		 if_start_hello_timer(struct iface_af *);
38
static void		 if_stop_hello_timer(struct iface_af *);
39
static int		 if_join_ipv4_group(struct iface *, struct in_addr *);
40
static int		 if_leave_ipv4_group(struct iface *, struct in_addr *);
41
static int		 if_join_ipv6_group(struct iface *, struct in6_addr *);
42
static int		 if_leave_ipv6_group(struct iface *, struct in6_addr *);
43
44
struct iface *
45
if_new(struct kif *kif)
46
{
47
	struct iface		*iface;
48
49
	if ((iface = calloc(1, sizeof(*iface))) == NULL)
50
		fatal("if_new: calloc");
51
52
	strlcpy(iface->name, kif->ifname, sizeof(iface->name));
53
54
	/* get type */
55
	if (kif->flags & IFF_POINTOPOINT)
56
		iface->type = IF_TYPE_POINTOPOINT;
57
	if (kif->flags & IFF_BROADCAST &&
58
	    kif->flags & IFF_MULTICAST)
59
		iface->type = IF_TYPE_BROADCAST;
60
61
	/* get index and flags */
62
	LIST_INIT(&iface->addr_list);
63
	iface->ifindex = kif->ifindex;
64
	iface->rdomain = kif->rdomain;
65
	iface->flags = kif->flags;
66
	iface->linkstate = kif->link_state;
67
	iface->if_type = kif->if_type;
68
69
	/* ipv4 */
70
	iface->ipv4.af = AF_INET;
71
	iface->ipv4.iface = iface;
72
	iface->ipv4.enabled = 0;
73
	iface->ipv4.state = IF_STA_DOWN;
74
	LIST_INIT(&iface->ipv4.adj_list);
75
76
	/* ipv6 */
77
	iface->ipv6.af = AF_INET6;
78
	iface->ipv6.iface = iface;
79
	iface->ipv6.enabled = 0;
80
	iface->ipv6.state = IF_STA_DOWN;
81
	LIST_INIT(&iface->ipv6.adj_list);
82
83
	return (iface);
84
}
85
86
void
87
if_exit(struct iface *iface)
88
{
89
	struct if_addr		*if_addr;
90
91
	log_debug("%s: interface %s", __func__, iface->name);
92
93
	if (iface->ipv4.state == IF_STA_ACTIVE)
94
		if_reset(iface, AF_INET);
95
	if (iface->ipv6.state == IF_STA_ACTIVE)
96
		if_reset(iface, AF_INET6);
97
98
	while ((if_addr = LIST_FIRST(&iface->addr_list)) != NULL) {
99
		LIST_REMOVE(if_addr, entry);
100
		free(if_addr);
101
	}
102
}
103
104
struct iface *
105
if_lookup(struct ldpd_conf *xconf, unsigned short ifindex)
106
{
107
	struct iface *iface;
108
109
	LIST_FOREACH(iface, &xconf->iface_list, entry)
110
		if (iface->ifindex == ifindex)
111
			return (iface);
112
113
	return (NULL);
114
}
115
116
struct iface_af *
117
iface_af_get(struct iface *iface, int af)
118
{
119
	switch (af) {
120
	case AF_INET:
121
		return (&iface->ipv4);
122
	case AF_INET6:
123
		return (&iface->ipv6);
124
	default:
125
		fatalx("iface_af_get: unknown af");
126
	}
127
}
128
129
static struct if_addr *
130
if_addr_new(struct kaddr *ka)
131
{
132
	struct if_addr	*if_addr;
133
134
	if ((if_addr = calloc(1, sizeof(*if_addr))) == NULL)
135
		fatal(__func__);
136
137
	if_addr->af = ka->af;
138
	if_addr->addr = ka->addr;
139
	if_addr->prefixlen = ka->prefixlen;
140
	if_addr->dstbrd = ka->dstbrd;
141
142
	return (if_addr);
143
}
144
145
static struct if_addr *
146
if_addr_lookup(struct if_addr_head *addr_list, struct kaddr *ka)
147
{
148
	struct if_addr	*if_addr;
149
	int		 af = ka->af;
150
151
	LIST_FOREACH(if_addr, addr_list, entry)
152
		if (!ldp_addrcmp(af, &if_addr->addr, &ka->addr) &&
153
		    if_addr->prefixlen == ka->prefixlen &&
154
		    !ldp_addrcmp(af, &if_addr->dstbrd, &ka->dstbrd))
155
			return (if_addr);
156
157
	return (NULL);
158
}
159
160
void
161
if_addr_add(struct kaddr *ka)
162
{
163
	struct iface		*iface;
164
	struct if_addr		*if_addr;
165
	struct nbr		*nbr;
166
167
	if (if_addr_lookup(&global.addr_list, ka) == NULL) {
168
		if_addr = if_addr_new(ka);
169
170
		LIST_INSERT_HEAD(&global.addr_list, if_addr, entry);
171
		RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
172
			if (nbr->state != NBR_STA_OPER)
173
				continue;
174
			if (if_addr->af == AF_INET && !nbr->v4_enabled)
175
				continue;
176
			if (if_addr->af == AF_INET6 && !nbr->v6_enabled)
177
				continue;
178
179
			send_address_single(nbr, if_addr, 0);
180
		}
181
	}
182
183
	iface = if_lookup(leconf, ka->ifindex);
184
	if (iface) {
185
		if (ka->af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&ka->addr.v6))
186
			iface->linklocal = ka->addr.v6;
187
188
		if (if_addr_lookup(&iface->addr_list, ka) == NULL) {
189
			if_addr = if_addr_new(ka);
190
			LIST_INSERT_HEAD(&iface->addr_list, if_addr, entry);
191
			if_update(iface, if_addr->af);
192
		}
193
	}
194
}
195
196
void
197
if_addr_del(struct kaddr *ka)
198
{
199
	struct iface		*iface;
200
	struct if_addr		*if_addr;
201
	struct nbr		*nbr;
202
203
	iface = if_lookup(leconf, ka->ifindex);
204
	if (iface) {
205
		if (ka->af == AF_INET6 &&
206
		    IN6_ARE_ADDR_EQUAL(&iface->linklocal, &ka->addr.v6))
207
			memset(&iface->linklocal, 0, sizeof(iface->linklocal));
208
209
		if_addr = if_addr_lookup(&iface->addr_list, ka);
210
		if (if_addr) {
211
			LIST_REMOVE(if_addr, entry);
212
			if_update(iface, if_addr->af);
213
			free(if_addr);
214
		}
215
	}
216
217
	if_addr = if_addr_lookup(&global.addr_list, ka);
218
	if (if_addr) {
219
		RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
220
			if (nbr->state != NBR_STA_OPER)
221
				continue;
222
			if (if_addr->af == AF_INET && !nbr->v4_enabled)
223
				continue;
224
			if (if_addr->af == AF_INET6 && !nbr->v6_enabled)
225
				continue;
226
			send_address_single(nbr, if_addr, 1);
227
		}
228
		LIST_REMOVE(if_addr, entry);
229
		free(if_addr);
230
	}
231
}
232
233
static int
234
if_start(struct iface *iface, int af)
235
{
236
	struct iface_af		*ia;
237
	struct timeval		 now;
238
239
	log_debug("%s: %s address-family %s", __func__, iface->name,
240
	    af_name(af));
241
242
	ia = iface_af_get(iface, af);
243
244
	gettimeofday(&now, NULL);
245
	ia->uptime = now.tv_sec;
246
247
	switch (af) {
248
	case AF_INET:
249
		if (if_join_ipv4_group(iface, &global.mcast_addr_v4))
250
			return (-1);
251
		break;
252
	case AF_INET6:
253
		if (if_join_ipv6_group(iface, &global.mcast_addr_v6))
254
			return (-1);
255
		break;
256
	default:
257
		fatalx("if_start: unknown af");
258
	}
259
260
	send_hello(HELLO_LINK, ia, NULL);
261
262
	evtimer_set(&ia->hello_timer, if_hello_timer, ia);
263
	if_start_hello_timer(ia);
264
	return (0);
265
}
266
267
static int
268
if_reset(struct iface *iface, int af)
269
{
270
	struct iface_af		*ia;
271
	struct adj		*adj;
272
273
	log_debug("%s: %s address-family %s", __func__, iface->name,
274
	    af_name(af));
275
276
	ia = iface_af_get(iface, af);
277
	if_stop_hello_timer(ia);
278
279
	while ((adj = LIST_FIRST(&ia->adj_list)) != NULL)
280
		adj_del(adj, S_SHUTDOWN);
281
282
	/* try to cleanup */
283
	switch (af) {
284
	case AF_INET:
285
		if (global.ipv4.ldp_disc_socket != -1)
286
			if_leave_ipv4_group(iface, &global.mcast_addr_v4);
287
		break;
288
	case AF_INET6:
289
		if (global.ipv6.ldp_disc_socket != -1)
290
			if_leave_ipv6_group(iface, &global.mcast_addr_v6);
291
		break;
292
	default:
293
		fatalx("if_start: unknown af");
294
	}
295
296
	return (0);
297
}
298
299
static void
300
if_update_af(struct iface_af *ia, int link_ok)
301
{
302
	int			 addr_ok = 0, socket_ok, rtr_id_ok;
303
	struct if_addr		*if_addr;
304
305
	switch (ia->af) {
306
	case AF_INET:
307
		/*
308
		 * NOTE: for LDPv4, each interface should have at least one
309
		 * valid IP address otherwise they can not be enabled.
310
		 */
311
		LIST_FOREACH(if_addr, &ia->iface->addr_list, entry) {
312
			if (if_addr->af == AF_INET) {
313
				addr_ok = 1;
314
				break;
315
			}
316
		}
317
		break;
318
	case AF_INET6:
319
		/* for IPv6 the link-local address is enough. */
320
		if (IN6_IS_ADDR_LINKLOCAL(&ia->iface->linklocal))
321
			addr_ok = 1;
322
		break;
323
	default:
324
		fatalx("if_update_af: unknown af");
325
	}
326
327
	if ((ldp_af_global_get(&global, ia->af))->ldp_disc_socket != -1)
328
		socket_ok = 1;
329
	else
330
		socket_ok = 0;
331
332
	if (leconf->rtr_id.s_addr != INADDR_ANY)
333
		rtr_id_ok = 1;
334
	else
335
		rtr_id_ok = 0;
336
337
	if (ia->state == IF_STA_DOWN) {
338
		if (!ia->enabled || !link_ok || !addr_ok || !socket_ok ||
339
		    !rtr_id_ok)
340
			return;
341
342
		ia->state = IF_STA_ACTIVE;
343
		if_start(ia->iface, ia->af);
344
	} else if (ia->state == IF_STA_ACTIVE) {
345
		if (ia->enabled && link_ok && addr_ok && socket_ok && rtr_id_ok)
346
			return;
347
348
		ia->state = IF_STA_DOWN;
349
		if_reset(ia->iface, ia->af);
350
	}
351
}
352
353
void
354
if_update(struct iface *iface, int af)
355
{
356
	int			 link_ok;
357
358
	link_ok = (iface->flags & IFF_UP) &&
359
	    LINK_STATE_IS_UP(iface->linkstate);
360
361
	if (af == AF_INET || af == AF_UNSPEC)
362
		if_update_af(&iface->ipv4, link_ok);
363
	if (af == AF_INET6 || af == AF_UNSPEC)
364
		if_update_af(&iface->ipv6, link_ok);
365
}
366
367
void
368
if_update_all(int af)
369
{
370
	struct iface		*iface;
371
372
	LIST_FOREACH(iface, &leconf->iface_list, entry)
373
		if_update(iface, af);
374
}
375
376
/* timers */
377
/* ARGSUSED */
378
static void
379
if_hello_timer(int fd, short event, void *arg)
380
{
381
	struct iface_af		*ia = arg;
382
383
	send_hello(HELLO_LINK, ia, NULL);
384
	if_start_hello_timer(ia);
385
}
386
387
static void
388
if_start_hello_timer(struct iface_af *ia)
389
{
390
	struct timeval		 tv;
391
392
	timerclear(&tv);
393
	tv.tv_sec = ia->hello_interval;
394
	if (evtimer_add(&ia->hello_timer, &tv) == -1)
395
		fatal(__func__);
396
}
397
398
static void
399
if_stop_hello_timer(struct iface_af *ia)
400
{
401
	if (evtimer_pending(&ia->hello_timer, NULL) &&
402
	    evtimer_del(&ia->hello_timer) == -1)
403
		fatal(__func__);
404
}
405
406
struct ctl_iface *
407
if_to_ctl(struct iface_af *ia)
408
{
409
	static struct ctl_iface	 ictl;
410
	struct timeval		 now;
411
	struct adj		*adj;
412
413
	ictl.af = ia->af;
414
	memcpy(ictl.name, ia->iface->name, sizeof(ictl.name));
415
	ictl.ifindex = ia->iface->ifindex;
416
	ictl.state = ia->state;
417
	ictl.flags = ia->iface->flags;
418
	ictl.linkstate = ia->iface->linkstate;
419
	ictl.type = ia->iface->type;
420
	ictl.if_type = ia->iface->if_type;
421
	ictl.hello_holdtime = ia->hello_holdtime;
422
	ictl.hello_interval = ia->hello_interval;
423
424
	gettimeofday(&now, NULL);
425
	if (ia->state != IF_STA_DOWN &&
426
	    ia->uptime != 0) {
427
		ictl.uptime = now.tv_sec - ia->uptime;
428
	} else
429
		ictl.uptime = 0;
430
431
	ictl.adj_cnt = 0;
432
	LIST_FOREACH(adj, &ia->adj_list, ia_entry)
433
		ictl.adj_cnt++;
434
435
	return (&ictl);
436
}
437
438
/* multicast membership sockopts */
439
in_addr_t
440
if_get_ipv4_addr(struct iface *iface)
441
{
442
	struct if_addr		*if_addr;
443
444
	LIST_FOREACH(if_addr, &iface->addr_list, entry)
445
		if (if_addr->af == AF_INET)
446
			return (if_addr->addr.v4.s_addr);
447
448
	return (INADDR_ANY);
449
}
450
451
static int
452
if_join_ipv4_group(struct iface *iface, struct in_addr *addr)
453
{
454
	struct ip_mreq		 mreq;
455
456
	log_debug("%s: interface %s addr %s", __func__, iface->name,
457
	    inet_ntoa(*addr));
458
459
	mreq.imr_multiaddr = *addr;
460
	mreq.imr_interface.s_addr = if_get_ipv4_addr(iface);
461
462
	if (setsockopt(global.ipv4.ldp_disc_socket, IPPROTO_IP,
463
	    IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) {
464
		log_warn("%s: error IP_ADD_MEMBERSHIP, interface %s address %s",
465
		     __func__, iface->name, inet_ntoa(*addr));
466
		return (-1);
467
	}
468
	return (0);
469
}
470
471
static int
472
if_leave_ipv4_group(struct iface *iface, struct in_addr *addr)
473
{
474
	struct ip_mreq		 mreq;
475
476
	log_debug("%s: interface %s addr %s", __func__, iface->name,
477
	    inet_ntoa(*addr));
478
479
	mreq.imr_multiaddr = *addr;
480
	mreq.imr_interface.s_addr = if_get_ipv4_addr(iface);
481
482
	if (setsockopt(global.ipv4.ldp_disc_socket, IPPROTO_IP,
483
	    IP_DROP_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) {
484
		log_warn("%s: error IP_DROP_MEMBERSHIP, interface %s "
485
		    "address %s", __func__, iface->name, inet_ntoa(*addr));
486
		return (-1);
487
	}
488
489
	return (0);
490
}
491
492
static int
493
if_join_ipv6_group(struct iface *iface, struct in6_addr *addr)
494
{
495
	struct ipv6_mreq	 mreq;
496
497
	log_debug("%s: interface %s addr %s", __func__, iface->name,
498
	    log_in6addr(addr));
499
500
	mreq.ipv6mr_multiaddr = *addr;
501
	mreq.ipv6mr_interface = iface->ifindex;
502
503
	if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6,
504
	    IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0) {
505
		log_warn("%s: error IPV6_JOIN_GROUP, interface %s address %s",
506
		    __func__, iface->name, log_in6addr(addr));
507
		return (-1);
508
	}
509
510
	return (0);
511
}
512
513
static int
514
if_leave_ipv6_group(struct iface *iface, struct in6_addr *addr)
515
{
516
	struct ipv6_mreq	 mreq;
517
518
	log_debug("%s: interface %s addr %s", __func__, iface->name,
519
	    log_in6addr(addr));
520
521
	mreq.ipv6mr_multiaddr = *addr;
522
	mreq.ipv6mr_interface = iface->ifindex;
523
524
	if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6,
525
	    IPV6_LEAVE_GROUP, (void *)&mreq, sizeof(mreq)) < 0) {
526
		log_warn("%s: error IPV6_LEAVE_GROUP, interface %s address %s",
527
		    __func__, iface->name, log_in6addr(addr));
528
		return (-1);
529
	}
530
531
	return (0);
532
}