interface.c revision 1.35
1/*	$OpenBSD: interface.c,v 1.35 2016/05/23 17:00:40 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 *);
46void		 if_stop_hello_timer(struct iface *);
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	iface->state = IF_STA_DOWN;
57
58	LIST_INIT(&iface->addr_list);
59	LIST_INIT(&iface->adj_list);
60
61	strlcpy(iface->name, kif->ifname, sizeof(iface->name));
62
63	/* get type */
64	if (kif->flags & IFF_POINTOPOINT)
65		iface->type = IF_TYPE_POINTOPOINT;
66	if (kif->flags & IFF_BROADCAST &&
67	    kif->flags & IFF_MULTICAST)
68		iface->type = IF_TYPE_BROADCAST;
69
70	/* get index and flags */
71	iface->ifindex = kif->ifindex;
72	iface->flags = kif->flags;
73	iface->linkstate = kif->link_state;
74	iface->if_type = kif->if_type;
75
76	return (iface);
77}
78
79void
80if_del(struct iface *iface)
81{
82	struct if_addr		*if_addr;
83
84	if (iface->state == IF_STA_ACTIVE)
85		if_reset(iface);
86
87	log_debug("%s: interface %s", __func__, iface->name);
88
89	while ((if_addr = LIST_FIRST(&iface->addr_list)) != NULL) {
90		LIST_REMOVE(if_addr, entry);
91		free(if_addr);
92	}
93
94	free(iface);
95}
96
97void
98if_init(struct ldpd_conf *xconf, struct iface *iface)
99{
100	/* set event handlers for interface */
101	evtimer_set(&iface->hello_timer, if_hello_timer, iface);
102
103	iface->discovery_fd = xconf->ldp_discovery_socket;
104}
105
106struct iface *
107if_lookup(struct ldpd_conf *xconf, u_short ifindex)
108{
109	struct iface *iface;
110
111	LIST_FOREACH(iface, &xconf->iface_list, entry)
112		if (iface->ifindex == ifindex)
113			return (iface);
114
115	return (NULL);
116}
117
118struct if_addr *
119if_addr_new(struct kaddr *ka)
120{
121	struct if_addr	*if_addr;
122
123	if ((if_addr = calloc(1, sizeof(*if_addr))) == NULL)
124		fatal(__func__);
125
126	if_addr->addr.s_addr = ka->addr.s_addr;
127	if_addr->mask.s_addr = ka->mask.s_addr;
128	if_addr->dstbrd.s_addr = ka->dstbrd.s_addr;
129
130	return (if_addr);
131}
132
133struct if_addr *
134if_addr_lookup(struct if_addr_head *addr_list, struct kaddr *ka)
135{
136	struct if_addr *if_addr;
137
138	LIST_FOREACH(if_addr, addr_list, entry)
139		if (if_addr->addr.s_addr == ka->addr.s_addr &&
140		    if_addr->mask.s_addr == ka->mask.s_addr &&
141		    if_addr->dstbrd.s_addr == ka->dstbrd.s_addr)
142			return (if_addr);
143
144	return (NULL);
145}
146
147void
148if_addr_add(struct kaddr *ka)
149{
150	struct iface		*iface;
151	struct if_addr		*if_addr;
152	struct nbr		*nbr;
153
154	if (if_addr_lookup(&global.addr_list, ka) == NULL) {
155		if_addr = if_addr_new(ka);
156
157		LIST_INSERT_HEAD(&global.addr_list, if_addr, entry);
158		RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
159			if (nbr->state != NBR_STA_OPER)
160				continue;
161
162			send_address(nbr, if_addr, 0);
163		}
164	}
165
166	iface = if_lookup(leconf, ka->ifindex);
167	if (iface &&
168	    if_addr_lookup(&iface->addr_list, ka) == NULL) {
169		if_addr = if_addr_new(ka);
170		LIST_INSERT_HEAD(&iface->addr_list, if_addr, entry);
171		if_update(iface);
172	}
173}
174
175void
176if_addr_del(struct kaddr *ka)
177{
178	struct iface		*iface;
179	struct if_addr		*if_addr;
180	struct nbr		*nbr;
181
182	iface = if_lookup(leconf, ka->ifindex);
183	if (iface) {
184		if_addr = if_addr_lookup(&iface->addr_list, ka);
185		if (if_addr) {
186			LIST_REMOVE(if_addr, entry);
187			free(if_addr);
188			if_update(iface);
189		}
190	}
191
192	if_addr = if_addr_lookup(&global.addr_list, ka);
193	if (if_addr) {
194		RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
195			if (nbr->state != NBR_STA_OPER)
196				continue;
197			send_address(nbr, if_addr, 1);
198		}
199		LIST_REMOVE(if_addr, entry);
200		free(if_addr);
201	}
202}
203
204int
205if_start(struct iface *iface)
206{
207	struct in_addr		 addr;
208	struct timeval		 now;
209
210	log_debug("%s: %s", __func__, iface->name);
211
212	gettimeofday(&now, NULL);
213	iface->uptime = now.tv_sec;
214
215	inet_aton(AllRouters, &addr);
216	if (if_join_group(iface, &addr))
217		return (-1);
218
219	send_hello(HELLO_LINK, iface, NULL);
220	if_start_hello_timer(iface);
221	return (0);
222}
223
224int
225if_reset(struct iface *iface)
226{
227	struct in_addr		 addr;
228	struct adj		*adj;
229
230	log_debug("%s: %s", __func__, iface->name);
231
232	while ((adj = LIST_FIRST(&iface->adj_list)) != NULL)
233		adj_del(adj);
234
235	if_stop_hello_timer(iface);
236
237	/* try to cleanup */
238	inet_aton(AllRouters, &addr);
239	if_leave_group(iface, &addr);
240
241	return (0);
242}
243
244int
245if_update(struct iface *iface)
246{
247	int ret;
248
249	if (iface->state == IF_STA_DOWN) {
250		if (!(iface->flags & IFF_UP) ||
251		    !LINK_STATE_IS_UP(iface->linkstate) ||
252		    LIST_EMPTY(&iface->addr_list))
253			return (0);
254
255		iface->state = IF_STA_ACTIVE;
256		ret = if_start(iface);
257	} else {
258		if ((iface->flags & IFF_UP) &&
259		    LINK_STATE_IS_UP(iface->linkstate) &&
260		    !LIST_EMPTY(&iface->addr_list))
261			return (0);
262
263		iface->state = IF_STA_DOWN;
264		ret = if_reset(iface);
265	}
266
267	return (ret);
268}
269
270/* timers */
271/* ARGSUSED */
272void
273if_hello_timer(int fd, short event, void *arg)
274{
275	struct iface		*iface = arg;
276
277	send_hello(HELLO_LINK, iface, NULL);
278	if_start_hello_timer(iface);
279}
280
281void
282if_start_hello_timer(struct iface *iface)
283{
284	struct timeval		 tv;
285
286	timerclear(&tv);
287	tv.tv_sec = iface->hello_interval;
288	if (evtimer_add(&iface->hello_timer, &tv) == -1)
289		fatal(__func__);
290}
291
292void
293if_stop_hello_timer(struct iface *iface)
294{
295	if (evtimer_pending(&iface->hello_timer, NULL) &&
296	    evtimer_del(&iface->hello_timer) == -1)
297		fatal(__func__);
298}
299
300struct ctl_iface *
301if_to_ctl(struct iface *iface)
302{
303	static struct ctl_iface	 ictl;
304	struct timeval		 now;
305	struct adj		*adj;
306
307	memcpy(ictl.name, iface->name, sizeof(ictl.name));
308	ictl.ifindex = iface->ifindex;
309	ictl.state = iface->state;
310	ictl.hello_holdtime = iface->hello_holdtime;
311	ictl.hello_interval = iface->hello_interval;
312	ictl.flags = iface->flags;
313	ictl.type = iface->type;
314	ictl.linkstate = iface->linkstate;
315	ictl.if_type = iface->if_type;
316
317	gettimeofday(&now, NULL);
318	if (iface->state != IF_STA_DOWN &&
319	    iface->uptime != 0) {
320		ictl.uptime = now.tv_sec - iface->uptime;
321	} else
322		ictl.uptime = 0;
323
324	ictl.adj_cnt = 0;
325	LIST_FOREACH(adj, &iface->adj_list, iface_entry)
326		ictl.adj_cnt++;
327
328	return (&ictl);
329}
330
331/* misc */
332int
333if_set_mcast_ttl(int fd, u_int8_t ttl)
334{
335	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
336	    (char *)&ttl, sizeof(ttl)) < 0) {
337		log_warn("%s: error setting IP_MULTICAST_TTL to %d",
338		    __func__, ttl);
339		return (-1);
340	}
341
342	return (0);
343}
344
345int
346if_set_tos(int fd, int tos)
347{
348	if (setsockopt(fd, IPPROTO_IP, IP_TOS, (int *)&tos, sizeof(tos)) < 0) {
349		log_warn("%s: error setting IP_TOS to 0x%x", __func__, tos);
350		return (-1);
351	}
352
353	return (0);
354}
355
356int
357if_set_recvif(int fd, int enable)
358{
359	if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &enable,
360	    sizeof(enable)) < 0) {
361		log_warn("%s: error setting IP_RECVIF", __func__);
362		return (-1);
363	}
364	return (0);
365}
366
367void
368if_set_recvbuf(int fd)
369{
370	int	bsize;
371
372	bsize = 65535;
373	while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize,
374	    sizeof(bsize)) == -1)
375		bsize /= 2;
376}
377
378int
379if_set_reuse(int fd, int enable)
380{
381	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable,
382	    sizeof(int)) < 0) {
383		log_warn("%s: error setting SO_REUSEADDR", __func__);
384		return (-1);
385	}
386
387	return (0);
388}
389
390/*
391 * only one JOIN or DROP per interface and address is allowed so we need
392 * to keep track of what is added and removed.
393 */
394struct if_group_count {
395	LIST_ENTRY(if_group_count)	entry;
396	struct in_addr			addr;
397	unsigned int			ifindex;
398	int				count;
399};
400
401LIST_HEAD(,if_group_count) ifglist = LIST_HEAD_INITIALIZER(ifglist);
402
403int
404if_set_mcast_ttl(int fd, uint8_t ttl)
405{
406	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
407	    (char *)&ttl, sizeof(ttl)) < 0) {
408		log_warn("%s: error setting IP_MULTICAST_TTL to %d",
409		    __func__, ttl);
410		return (-1);
411	}
412
413	return (0);
414}
415
416int
417if_set_tos(int fd, int tos)
418{
419	if (setsockopt(fd, IPPROTO_IP, IP_TOS, (int *)&tos, sizeof(tos)) < 0) {
420		log_warn("%s: error setting IP_TOS to 0x%x", __func__, tos);
421		return (-1);
422	}
423
424	return (0);
425}
426
427int
428if_set_recvif(int fd, int enable)
429{
430	if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &enable,
431	    sizeof(enable)) < 0) {
432		log_warn("%s: error setting IP_RECVIF", __func__);
433		return (-1);
434	}
435	return (0);
436}
437
438void
439if_set_recvbuf(int fd)
440{
441	int	bsize;
442
443	bsize = 65535;
444	while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize,
445	    sizeof(bsize)) == -1)
446		bsize /= 2;
447}
448
449int
450if_set_reuse(int fd, int enable)
451{
452	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable,
453	    sizeof(int)) < 0) {
454		log_warn("%s: error setting SO_REUSEADDR", __func__);
455		return (-1);
456	}
457
458	return (0);
459}
460
461int
462if_join_group(struct iface *iface, struct in_addr *addr)
463{
464	struct ip_mreq		 mreq;
465	struct if_group_count	*ifg;
466	struct if_addr		*if_addr;
467
468	LIST_FOREACH(ifg, &ifglist, entry)
469		if (iface->ifindex == ifg->ifindex &&
470		    addr->s_addr == ifg->addr.s_addr)
471			break;
472	if (ifg == NULL) {
473		if ((ifg = calloc(1, sizeof(*ifg))) == NULL)
474			fatal(__func__);
475		ifg->addr.s_addr = addr->s_addr;
476		ifg->ifindex = iface->ifindex;
477		LIST_INSERT_HEAD(&ifglist, ifg, entry);
478	}
479
480	if (ifg->count++ != 0)
481		/* already joined */
482		return (0);
483
484	if_addr = LIST_FIRST(&iface->addr_list);
485	mreq.imr_multiaddr.s_addr = addr->s_addr;
486	mreq.imr_interface.s_addr = if_addr->addr.s_addr;
487
488	if (setsockopt(iface->discovery_fd, IPPROTO_IP,
489	    IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) {
490		log_warn("%s: error IP_ADD_MEMBERSHIP, "
491		    "interface %s address %s", __func__, iface->name,
492		    inet_ntoa(*addr));
493		LIST_REMOVE(ifg, entry);
494		free(ifg);
495		return (-1);
496	}
497	return (0);
498}
499
500int
501if_leave_group(struct iface *iface, struct in_addr *addr)
502{
503	struct ip_mreq		 mreq;
504	struct if_group_count	*ifg;
505	struct if_addr		*if_addr;
506
507	LIST_FOREACH(ifg, &ifglist, entry)
508		if (iface->ifindex == ifg->ifindex &&
509		    addr->s_addr == ifg->addr.s_addr)
510			break;
511
512	/* if interface is not found just try to drop membership */
513	if (ifg) {
514		if (--ifg->count != 0)
515			/* others still joined */
516			return (0);
517
518		LIST_REMOVE(ifg, entry);
519		free(ifg);
520	}
521
522	if_addr = LIST_FIRST(&iface->addr_list);
523	if (!if_addr)
524		return (0);
525
526	mreq.imr_multiaddr.s_addr = addr->s_addr;
527	mreq.imr_interface.s_addr = if_addr->addr.s_addr;
528
529	if (setsockopt(iface->discovery_fd, IPPROTO_IP,
530	    IP_DROP_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) {
531		log_warn("%s: error IP_DROP_MEMBERSHIP, interface %s "
532		    "address %s", __func__, iface->name, inet_ntoa(*addr));
533		return (-1);
534	}
535
536	return (0);
537}
538
539int
540if_set_mcast(struct iface *iface)
541{
542	struct if_addr		*if_addr;
543
544	if_addr = LIST_FIRST(&iface->addr_list);
545
546	if (setsockopt(global.ldp_disc_socket, IPPROTO_IP, IP_MULTICAST_IF,
547	    &if_addr->addr.s_addr, sizeof(if_addr->addr.s_addr)) < 0) {
548		log_debug("%s: error setting IP_MULTICAST_IF, interface %s",
549		    __func__, iface->name);
550		return (-1);
551	}
552
553	return (0);
554}
555
556int
557if_set_mcast_loop(int fd)
558{
559	uint8_t	loop = 0;
560
561	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
562	    (char *)&loop, sizeof(loop)) < 0) {
563		log_warn("%s: error setting IP_MULTICAST_LOOP", __func__);
564		return (-1);
565	}
566
567	return (0);
568}
569
570int
571if_set_mcast(struct iface *iface)
572{
573	struct if_addr		*if_addr;
574
575	if_addr = LIST_FIRST(&iface->addr_list);
576
577	if (setsockopt(global.ldp_disc_socket, IPPROTO_IP, IP_MULTICAST_IF,
578	    &if_addr->addr.s_addr, sizeof(if_addr->addr.s_addr)) < 0) {
579		log_debug("%s: error setting IP_MULTICAST_IF, interface %s",
580		    __func__, iface->name);
581		return (-1);
582	}
583
584	return (0);
585}
586
587int
588if_set_mcast_loop(int fd)
589{
590	u_int8_t	loop = 0;
591
592	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
593	    (char *)&loop, sizeof(loop)) < 0) {
594		log_warn("%s: error setting IP_MULTICAST_LOOP", __func__);
595		return (-1);
596	}
597
598	return (0);
599}
600