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