interface.c revision 1.37
1/*	$OpenBSD: interface.c,v 1.37 2016/05/23 18:28:22 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 iface *iface)
99{
100	/* set event handlers for interface */
101	evtimer_set(&iface->hello_timer, if_hello_timer, iface);
102}
103
104struct iface *
105if_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
116struct if_addr *
117if_addr_new(struct kaddr *ka)
118{
119	struct if_addr	*if_addr;
120
121	if ((if_addr = calloc(1, sizeof(*if_addr))) == NULL)
122		fatal(__func__);
123
124	if_addr->addr = ka->addr;
125	if_addr->mask = ka->mask;
126	if_addr->dstbrd = ka->dstbrd;
127
128	return (if_addr);
129}
130
131struct if_addr *
132if_addr_lookup(struct if_addr_head *addr_list, struct kaddr *ka)
133{
134	struct if_addr *if_addr;
135
136	LIST_FOREACH(if_addr, addr_list, entry)
137		if (if_addr->addr.s_addr == ka->addr.s_addr &&
138		    if_addr->mask.s_addr == ka->mask.s_addr &&
139		    if_addr->dstbrd.s_addr == ka->dstbrd.s_addr)
140			return (if_addr);
141
142	return (NULL);
143}
144
145void
146if_addr_add(struct kaddr *ka)
147{
148	struct iface		*iface;
149	struct if_addr		*if_addr;
150	struct nbr		*nbr;
151
152	if (if_addr_lookup(&global.addr_list, ka) == NULL) {
153		if_addr = if_addr_new(ka);
154
155		LIST_INSERT_HEAD(&global.addr_list, if_addr, entry);
156		RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
157			if (nbr->state != NBR_STA_OPER)
158				continue;
159
160			send_address(nbr, if_addr, 0);
161		}
162	}
163
164	iface = if_lookup(leconf, ka->ifindex);
165	if (iface &&
166	    if_addr_lookup(&iface->addr_list, ka) == NULL) {
167		if_addr = if_addr_new(ka);
168		LIST_INSERT_HEAD(&iface->addr_list, if_addr, entry);
169		if_update(iface);
170	}
171}
172
173void
174if_addr_del(struct kaddr *ka)
175{
176	struct iface		*iface;
177	struct if_addr		*if_addr;
178	struct nbr		*nbr;
179
180	iface = if_lookup(leconf, ka->ifindex);
181	if (iface) {
182		if_addr = if_addr_lookup(&iface->addr_list, ka);
183		if (if_addr) {
184			LIST_REMOVE(if_addr, entry);
185			free(if_addr);
186			if_update(iface);
187		}
188	}
189
190	if_addr = if_addr_lookup(&global.addr_list, ka);
191	if (if_addr) {
192		RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
193			if (nbr->state != NBR_STA_OPER)
194				continue;
195			send_address(nbr, if_addr, 1);
196		}
197		LIST_REMOVE(if_addr, entry);
198		free(if_addr);
199	}
200}
201
202int
203if_start(struct iface *iface)
204{
205	struct in_addr		 addr;
206	struct timeval		 now;
207
208	log_debug("%s: %s", __func__, iface->name);
209
210	gettimeofday(&now, NULL);
211	iface->uptime = now.tv_sec;
212
213	inet_aton(AllRouters, &addr);
214	if (if_join_group(iface, &addr))
215		return (-1);
216
217	send_hello(HELLO_LINK, iface, NULL);
218	if_start_hello_timer(iface);
219	return (0);
220}
221
222int
223if_reset(struct iface *iface)
224{
225	struct in_addr		 addr;
226	struct adj		*adj;
227
228	log_debug("%s: %s", __func__, iface->name);
229
230	while ((adj = LIST_FIRST(&iface->adj_list)) != NULL)
231		adj_del(adj);
232
233	if_stop_hello_timer(iface);
234
235	/* try to cleanup */
236	inet_aton(AllRouters, &addr);
237	if_leave_group(iface, &addr);
238
239	return (0);
240}
241
242int
243if_update(struct iface *iface)
244{
245	int ret;
246
247	if (iface->state == IF_STA_DOWN) {
248		if (!(iface->flags & IFF_UP) ||
249		    !LINK_STATE_IS_UP(iface->linkstate) ||
250		    LIST_EMPTY(&iface->addr_list))
251			return (0);
252
253		iface->state = IF_STA_ACTIVE;
254		ret = if_start(iface);
255	} else {
256		if ((iface->flags & IFF_UP) &&
257		    LINK_STATE_IS_UP(iface->linkstate) &&
258		    !LIST_EMPTY(&iface->addr_list))
259			return (0);
260
261		iface->state = IF_STA_DOWN;
262		ret = if_reset(iface);
263	}
264
265	return (ret);
266}
267
268/* timers */
269/* ARGSUSED */
270void
271if_hello_timer(int fd, short event, void *arg)
272{
273	struct iface		*iface = arg;
274
275	send_hello(HELLO_LINK, iface, NULL);
276	if_start_hello_timer(iface);
277}
278
279void
280if_start_hello_timer(struct iface *iface)
281{
282	struct timeval		 tv;
283
284	timerclear(&tv);
285	tv.tv_sec = iface->hello_interval;
286	if (evtimer_add(&iface->hello_timer, &tv) == -1)
287		fatal(__func__);
288}
289
290void
291if_stop_hello_timer(struct iface *iface)
292{
293	if (evtimer_pending(&iface->hello_timer, NULL) &&
294	    evtimer_del(&iface->hello_timer) == -1)
295		fatal(__func__);
296}
297
298struct ctl_iface *
299if_to_ctl(struct iface *iface)
300{
301	static struct ctl_iface	 ictl;
302	struct timeval		 now;
303	struct adj		*adj;
304
305	memcpy(ictl.name, iface->name, sizeof(ictl.name));
306	ictl.ifindex = iface->ifindex;
307	ictl.state = iface->state;
308	ictl.hello_holdtime = iface->hello_holdtime;
309	ictl.hello_interval = iface->hello_interval;
310	ictl.flags = iface->flags;
311	ictl.type = iface->type;
312	ictl.linkstate = iface->linkstate;
313	ictl.if_type = iface->if_type;
314
315	gettimeofday(&now, NULL);
316	if (iface->state != IF_STA_DOWN &&
317	    iface->uptime != 0) {
318		ictl.uptime = now.tv_sec - iface->uptime;
319	} else
320		ictl.uptime = 0;
321
322	ictl.adj_cnt = 0;
323	LIST_FOREACH(adj, &iface->adj_list, iface_entry)
324		ictl.adj_cnt++;
325
326	return (&ictl);
327}
328
329/* misc */
330int
331if_join_group(struct iface *iface, struct in_addr *addr)
332{
333	struct ip_mreq		 mreq;
334	struct if_addr		*if_addr;
335
336	log_debug("%s: interface %s addr %s", __func__, iface->name,
337	    inet_ntoa(*addr));
338
339	if_addr = LIST_FIRST(&iface->addr_list);
340	mreq.imr_multiaddr = *addr;
341	mreq.imr_interface = if_addr->addr;
342
343	if (setsockopt(global.ldp_disc_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
344	    (void *)&mreq, sizeof(mreq)) < 0) {
345		log_warn("%s: error IP_ADD_MEMBERSHIP, interface %s address %s",
346		     __func__, iface->name, inet_ntoa(*addr));
347		return (-1);
348	}
349	return (0);
350}
351
352int
353if_leave_group(struct iface *iface, struct in_addr *addr)
354{
355	struct ip_mreq		 mreq;
356	struct if_addr		*if_addr;
357
358	log_debug("%s: interface %s addr %s", __func__, iface->name,
359	    inet_ntoa(*addr));
360
361	if_addr = LIST_FIRST(&iface->addr_list);
362	if (!if_addr)
363		return (0);
364
365	mreq.imr_multiaddr = *addr;
366	mreq.imr_interface = if_addr->addr;
367
368	if (setsockopt(global.ldp_disc_socket, IPPROTO_IP, IP_DROP_MEMBERSHIP,
369	    (void *)&mreq, sizeof(mreq)) < 0) {
370		log_warn("%s: error IP_DROP_MEMBERSHIP, interface %s "
371		    "address %s", __func__, iface->name, inet_ntoa(*addr));
372		return (-1);
373	}
374
375	return (0);
376}
377