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