interface.c revision 1.27
1/*	$OpenBSD: interface.c,v 1.27 2016/05/23 15:14:07 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
147/* timers */
148/* ARGSUSED */
149void
150if_hello_timer(int fd, short event, void *arg)
151{
152	struct iface *iface = arg;
153	struct timeval tv;
154
155	send_hello(HELLO_LINK, iface, NULL);
156
157	/* reschedule hello_timer */
158	timerclear(&tv);
159	tv.tv_sec = iface->hello_interval;
160	if (evtimer_add(&iface->hello_timer, &tv) == -1)
161		fatal(__func__);
162}
163
164void
165if_start_hello_timer(struct iface *iface)
166{
167	struct timeval tv;
168
169	send_hello(HELLO_LINK, iface, NULL);
170
171	timerclear(&tv);
172	tv.tv_sec = iface->hello_interval;
173	if (evtimer_add(&iface->hello_timer, &tv) == -1)
174		fatal(__func__);
175}
176
177void
178if_stop_hello_timer(struct iface *iface)
179{
180	if (evtimer_pending(&iface->hello_timer, NULL) &&
181	    evtimer_del(&iface->hello_timer) == -1)
182		fatal(__func__);
183}
184
185int
186if_start(struct iface *iface)
187{
188	struct in_addr		 addr;
189	struct timeval		 now;
190
191	log_debug("%s: %s", __func__, iface->name);
192
193	gettimeofday(&now, NULL);
194	iface->uptime = now.tv_sec;
195
196	inet_aton(AllRouters, &addr);
197	if (if_join_group(iface, &addr))
198		return (-1);
199
200	/* hello timer needs to be started in any case */
201	if_start_hello_timer(iface);
202	return (0);
203}
204
205int
206if_reset(struct iface *iface)
207{
208	struct in_addr		 addr;
209	struct adj		*adj;
210
211	log_debug("%s: %s", __func__, iface->name);
212
213	while ((adj = LIST_FIRST(&iface->adj_list)) != NULL) {
214		LIST_REMOVE(adj, iface_entry);
215		adj_del(adj);
216	}
217
218	if_stop_hello_timer(iface);
219
220	/* try to cleanup */
221	inet_aton(AllRouters, &addr);
222	if_leave_group(iface, &addr);
223
224	return (0);
225}
226
227int
228if_update(struct iface *iface)
229{
230	int ret;
231
232	if (iface->state == IF_STA_DOWN) {
233		if (!(iface->flags & IFF_UP) ||
234		    !LINK_STATE_IS_UP(iface->linkstate) ||
235		    LIST_EMPTY(&iface->addr_list))
236			return (0);
237
238		iface->state = IF_STA_ACTIVE;
239		ret = if_start(iface);
240	} else {
241		if ((iface->flags & IFF_UP) &&
242		    LINK_STATE_IS_UP(iface->linkstate) &&
243		    !LIST_EMPTY(&iface->addr_list))
244			return (0);
245
246		iface->state = IF_STA_DOWN;
247		ret = if_reset(iface);
248	}
249
250	return (ret);
251}
252
253struct ctl_iface *
254if_to_ctl(struct iface *iface)
255{
256	static struct ctl_iface	 ictl;
257	struct timeval		 now;
258	struct adj		*adj;
259
260	memcpy(ictl.name, iface->name, sizeof(ictl.name));
261	ictl.ifindex = iface->ifindex;
262	ictl.state = iface->state;
263	ictl.hello_holdtime = iface->hello_holdtime;
264	ictl.hello_interval = iface->hello_interval;
265	ictl.flags = iface->flags;
266	ictl.type = iface->type;
267	ictl.linkstate = iface->linkstate;
268	ictl.if_type = iface->if_type;
269
270	gettimeofday(&now, NULL);
271	if (iface->state != IF_STA_DOWN &&
272	    iface->uptime != 0) {
273		ictl.uptime = now.tv_sec - iface->uptime;
274	} else
275		ictl.uptime = 0;
276
277	ictl.adj_cnt = 0;
278	LIST_FOREACH(adj, &iface->adj_list, iface_entry)
279		ictl.adj_cnt++;
280
281	return (&ictl);
282}
283
284/* misc */
285int
286if_set_mcast_ttl(int fd, u_int8_t ttl)
287{
288	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
289	    (char *)&ttl, sizeof(ttl)) < 0) {
290		log_warn("%s: error setting IP_MULTICAST_TTL to %d",
291		    __func__, ttl);
292		return (-1);
293	}
294
295	return (0);
296}
297
298int
299if_set_tos(int fd, int tos)
300{
301	if (setsockopt(fd, IPPROTO_IP, IP_TOS, (int *)&tos, sizeof(tos)) < 0) {
302		log_warn("%s: error setting IP_TOS to 0x%x", __func__, tos);
303		return (-1);
304	}
305
306	return (0);
307}
308
309int
310if_set_recvif(int fd, int enable)
311{
312	if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &enable,
313	    sizeof(enable)) < 0) {
314		log_warn("%s: error setting IP_RECVIF", __func__);
315		return (-1);
316	}
317	return (0);
318}
319
320void
321if_set_recvbuf(int fd)
322{
323	int	bsize;
324
325	bsize = 65535;
326	while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize,
327	    sizeof(bsize)) == -1)
328		bsize /= 2;
329}
330
331int
332if_set_reuse(int fd, int enable)
333{
334	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable,
335	    sizeof(int)) < 0) {
336		log_warn("%s: error setting SO_REUSEADDR", __func__);
337		return (-1);
338	}
339
340	return (0);
341}
342
343/*
344 * only one JOIN or DROP per interface and address is allowed so we need
345 * to keep track of what is added and removed.
346 */
347struct if_group_count {
348	LIST_ENTRY(if_group_count)	entry;
349	struct in_addr			addr;
350	unsigned int			ifindex;
351	int				count;
352};
353
354LIST_HEAD(,if_group_count) ifglist = LIST_HEAD_INITIALIZER(ifglist);
355
356int
357if_join_group(struct iface *iface, struct in_addr *addr)
358{
359	struct ip_mreq		 mreq;
360	struct if_group_count	*ifg;
361	struct if_addr		*if_addr;
362
363	LIST_FOREACH(ifg, &ifglist, entry)
364		if (iface->ifindex == ifg->ifindex &&
365		    addr->s_addr == ifg->addr.s_addr)
366			break;
367	if (ifg == NULL) {
368		if ((ifg = calloc(1, sizeof(*ifg))) == NULL)
369			fatal(__func__);
370		ifg->addr.s_addr = addr->s_addr;
371		ifg->ifindex = iface->ifindex;
372		LIST_INSERT_HEAD(&ifglist, ifg, entry);
373	}
374
375	if (ifg->count++ != 0)
376		/* already joined */
377		return (0);
378
379	if_addr = LIST_FIRST(&iface->addr_list);
380	mreq.imr_multiaddr.s_addr = addr->s_addr;
381	mreq.imr_interface.s_addr = if_addr->addr.s_addr;
382
383	if (setsockopt(iface->discovery_fd, IPPROTO_IP,
384	    IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) {
385		log_warn("%s: error IP_ADD_MEMBERSHIP, "
386		    "interface %s address %s", __func__, iface->name,
387		    inet_ntoa(*addr));
388		LIST_REMOVE(ifg, entry);
389		free(ifg);
390		return (-1);
391	}
392	return (0);
393}
394
395int
396if_leave_group(struct iface *iface, struct in_addr *addr)
397{
398	struct ip_mreq		 mreq;
399	struct if_group_count	*ifg;
400	struct if_addr		*if_addr;
401
402	LIST_FOREACH(ifg, &ifglist, entry)
403		if (iface->ifindex == ifg->ifindex &&
404		    addr->s_addr == ifg->addr.s_addr)
405			break;
406
407	/* if interface is not found just try to drop membership */
408	if (ifg) {
409		if (--ifg->count != 0)
410			/* others still joined */
411			return (0);
412
413		LIST_REMOVE(ifg, entry);
414		free(ifg);
415	}
416
417	if_addr = LIST_FIRST(&iface->addr_list);
418	if (!if_addr)
419		return (0);
420
421	mreq.imr_multiaddr.s_addr = addr->s_addr;
422	mreq.imr_interface.s_addr = if_addr->addr.s_addr;
423
424	if (setsockopt(iface->discovery_fd, IPPROTO_IP,
425	    IP_DROP_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) {
426		log_warn("%s: error IP_DROP_MEMBERSHIP, interface %s "
427		    "address %s", __func__, iface->name, inet_ntoa(*addr));
428		return (-1);
429	}
430
431	return (0);
432}
433
434int
435if_set_mcast(struct iface *iface)
436{
437	struct if_addr		*if_addr;
438
439	if_addr = LIST_FIRST(&iface->addr_list);
440
441	if (setsockopt(iface->discovery_fd, IPPROTO_IP, IP_MULTICAST_IF,
442	    &if_addr->addr.s_addr, sizeof(if_addr->addr.s_addr)) < 0) {
443		log_debug("%s: error setting IP_MULTICAST_IF, interface %s",
444		    __func__, iface->name);
445		return (-1);
446	}
447
448	return (0);
449}
450
451int
452if_set_mcast_loop(int fd)
453{
454	u_int8_t	loop = 0;
455
456	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
457	    (char *)&loop, sizeof(loop)) < 0) {
458		log_warn("%s: error setting IP_MULTICAST_LOOP", __func__);
459		return (-1);
460	}
461
462	return (0);
463}
464