interface.c revision 1.29
1/*	$OpenBSD: interface.c,v 1.29 2016/05/23 15:49:31 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		err(1, "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 *kaddr)
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 = kaddr->addr.s_addr;
127	if_addr->mask.s_addr = kaddr->mask.s_addr;
128	if_addr->dstbrd.s_addr = kaddr->dstbrd.s_addr;
129
130	return (if_addr);
131}
132
133struct if_addr *
134if_addr_lookup(struct if_addr_head *addr_list, struct kaddr *kaddr)
135{
136	struct if_addr *if_addr;
137
138	LIST_FOREACH(if_addr, addr_list, entry)
139		if (if_addr->addr.s_addr == kaddr->addr.s_addr &&
140		    if_addr->mask.s_addr == kaddr->mask.s_addr &&
141		    if_addr->dstbrd.s_addr == kaddr->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	/* hello timer needs to be started in any case */
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		LIST_REMOVE(adj, iface_entry);
234		adj_del(adj);
235	}
236
237	if_stop_hello_timer(iface);
238
239	/* try to cleanup */
240	inet_aton(AllRouters, &addr);
241	if_leave_group(iface, &addr);
242
243	return (0);
244}
245
246int
247if_update(struct iface *iface)
248{
249	int ret;
250
251	if (iface->state == IF_STA_DOWN) {
252		if (!(iface->flags & IFF_UP) ||
253		    !LINK_STATE_IS_UP(iface->linkstate) ||
254		    LIST_EMPTY(&iface->addr_list))
255			return (0);
256
257		iface->state = IF_STA_ACTIVE;
258		ret = if_start(iface);
259	} else {
260		if ((iface->flags & IFF_UP) &&
261		    LINK_STATE_IS_UP(iface->linkstate) &&
262		    !LIST_EMPTY(&iface->addr_list))
263			return (0);
264
265		iface->state = IF_STA_DOWN;
266		ret = if_reset(iface);
267	}
268
269	return (ret);
270}
271
272/* timers */
273/* ARGSUSED */
274void
275if_hello_timer(int fd, short event, void *arg)
276{
277	struct iface *iface = arg;
278	struct timeval tv;
279
280	send_hello(HELLO_LINK, iface, NULL);
281
282	/* reschedule hello_timer */
283	timerclear(&tv);
284	tv.tv_sec = iface->hello_interval;
285	if (evtimer_add(&iface->hello_timer, &tv) == -1)
286		fatal(__func__);
287}
288
289void
290if_start_hello_timer(struct iface *iface)
291{
292	struct timeval tv;
293
294	send_hello(HELLO_LINK, iface, NULL);
295
296	timerclear(&tv);
297	tv.tv_sec = iface->hello_interval;
298	if (evtimer_add(&iface->hello_timer, &tv) == -1)
299		fatal(__func__);
300}
301
302void
303if_stop_hello_timer(struct iface *iface)
304{
305	if (evtimer_pending(&iface->hello_timer, NULL) &&
306	    evtimer_del(&iface->hello_timer) == -1)
307		fatal(__func__);
308}
309
310struct ctl_iface *
311if_to_ctl(struct iface *iface)
312{
313	static struct ctl_iface	 ictl;
314	struct timeval		 now;
315	struct adj		*adj;
316
317	memcpy(ictl.name, iface->name, sizeof(ictl.name));
318	ictl.ifindex = iface->ifindex;
319	ictl.state = iface->state;
320	ictl.hello_holdtime = iface->hello_holdtime;
321	ictl.hello_interval = iface->hello_interval;
322	ictl.flags = iface->flags;
323	ictl.type = iface->type;
324	ictl.linkstate = iface->linkstate;
325	ictl.if_type = iface->if_type;
326
327	gettimeofday(&now, NULL);
328	if (iface->state != IF_STA_DOWN &&
329	    iface->uptime != 0) {
330		ictl.uptime = now.tv_sec - iface->uptime;
331	} else
332		ictl.uptime = 0;
333
334	ictl.adj_cnt = 0;
335	LIST_FOREACH(adj, &iface->adj_list, iface_entry)
336		ictl.adj_cnt++;
337
338	return (&ictl);
339}
340
341/* misc */
342int
343if_set_mcast_ttl(int fd, u_int8_t ttl)
344{
345	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
346	    (char *)&ttl, sizeof(ttl)) < 0) {
347		log_warn("%s: error setting IP_MULTICAST_TTL to %d",
348		    __func__, ttl);
349		return (-1);
350	}
351
352	return (0);
353}
354
355int
356if_set_tos(int fd, int tos)
357{
358	if (setsockopt(fd, IPPROTO_IP, IP_TOS, (int *)&tos, sizeof(tos)) < 0) {
359		log_warn("%s: error setting IP_TOS to 0x%x", __func__, tos);
360		return (-1);
361	}
362
363	return (0);
364}
365
366int
367if_set_recvif(int fd, int enable)
368{
369	if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &enable,
370	    sizeof(enable)) < 0) {
371		log_warn("%s: error setting IP_RECVIF", __func__);
372		return (-1);
373	}
374	return (0);
375}
376
377void
378if_set_recvbuf(int fd)
379{
380	int	bsize;
381
382	bsize = 65535;
383	while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize,
384	    sizeof(bsize)) == -1)
385		bsize /= 2;
386}
387
388int
389if_set_reuse(int fd, int enable)
390{
391	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable,
392	    sizeof(int)) < 0) {
393		log_warn("%s: error setting SO_REUSEADDR", __func__);
394		return (-1);
395	}
396
397	return (0);
398}
399
400/*
401 * only one JOIN or DROP per interface and address is allowed so we need
402 * to keep track of what is added and removed.
403 */
404struct if_group_count {
405	LIST_ENTRY(if_group_count)	entry;
406	struct in_addr			addr;
407	unsigned int			ifindex;
408	int				count;
409};
410
411LIST_HEAD(,if_group_count) ifglist = LIST_HEAD_INITIALIZER(ifglist);
412
413int
414if_join_group(struct iface *iface, struct in_addr *addr)
415{
416	struct ip_mreq		 mreq;
417	struct if_group_count	*ifg;
418	struct if_addr		*if_addr;
419
420	LIST_FOREACH(ifg, &ifglist, entry)
421		if (iface->ifindex == ifg->ifindex &&
422		    addr->s_addr == ifg->addr.s_addr)
423			break;
424	if (ifg == NULL) {
425		if ((ifg = calloc(1, sizeof(*ifg))) == NULL)
426			fatal(__func__);
427		ifg->addr.s_addr = addr->s_addr;
428		ifg->ifindex = iface->ifindex;
429		LIST_INSERT_HEAD(&ifglist, ifg, entry);
430	}
431
432	if (ifg->count++ != 0)
433		/* already joined */
434		return (0);
435
436	if_addr = LIST_FIRST(&iface->addr_list);
437	mreq.imr_multiaddr.s_addr = addr->s_addr;
438	mreq.imr_interface.s_addr = if_addr->addr.s_addr;
439
440	if (setsockopt(iface->discovery_fd, IPPROTO_IP,
441	    IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) {
442		log_warn("%s: error IP_ADD_MEMBERSHIP, "
443		    "interface %s address %s", __func__, iface->name,
444		    inet_ntoa(*addr));
445		LIST_REMOVE(ifg, entry);
446		free(ifg);
447		return (-1);
448	}
449	return (0);
450}
451
452int
453if_leave_group(struct iface *iface, struct in_addr *addr)
454{
455	struct ip_mreq		 mreq;
456	struct if_group_count	*ifg;
457	struct if_addr		*if_addr;
458
459	LIST_FOREACH(ifg, &ifglist, entry)
460		if (iface->ifindex == ifg->ifindex &&
461		    addr->s_addr == ifg->addr.s_addr)
462			break;
463
464	/* if interface is not found just try to drop membership */
465	if (ifg) {
466		if (--ifg->count != 0)
467			/* others still joined */
468			return (0);
469
470		LIST_REMOVE(ifg, entry);
471		free(ifg);
472	}
473
474	if_addr = LIST_FIRST(&iface->addr_list);
475	if (!if_addr)
476		return (0);
477
478	mreq.imr_multiaddr.s_addr = addr->s_addr;
479	mreq.imr_interface.s_addr = if_addr->addr.s_addr;
480
481	if (setsockopt(iface->discovery_fd, IPPROTO_IP,
482	    IP_DROP_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) {
483		log_warn("%s: error IP_DROP_MEMBERSHIP, interface %s "
484		    "address %s", __func__, iface->name, inet_ntoa(*addr));
485		return (-1);
486	}
487
488	return (0);
489}
490
491int
492if_set_mcast(struct iface *iface)
493{
494	struct if_addr		*if_addr;
495
496	if_addr = LIST_FIRST(&iface->addr_list);
497
498	if (setsockopt(iface->discovery_fd, IPPROTO_IP, IP_MULTICAST_IF,
499	    &if_addr->addr.s_addr, sizeof(if_addr->addr.s_addr)) < 0) {
500		log_debug("%s: error setting IP_MULTICAST_IF, interface %s",
501		    __func__, iface->name);
502		return (-1);
503	}
504
505	return (0);
506}
507
508int
509if_set_mcast_loop(int fd)
510{
511	u_int8_t	loop = 0;
512
513	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
514	    (char *)&loop, sizeof(loop)) < 0) {
515		log_warn("%s: error setting IP_MULTICAST_LOOP", __func__);
516		return (-1);
517	}
518
519	return (0);
520}
521