interface.c revision 1.38
1/*	$OpenBSD: interface.c,v 1.38 2016/05/23 18:33:56 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	inet_aton(AllRouters, &addr);
232	if_leave_group(iface, &addr);
233
234	return (0);
235}
236
237int
238if_update(struct iface *iface)
239{
240	int			 link_ok, addr_ok = 0, socket_ok;
241	int			 ret;
242
243	link_ok = (iface->flags & IFF_UP) &&
244	    LINK_STATE_IS_UP(iface->linkstate);
245
246	addr_ok = !LIST_EMPTY(&iface->addr_list);
247
248	if (global.ldp_disc_socket != -1)
249		socket_ok = 1;
250	else
251		socket_ok = 0;
252
253	if (iface->state == IF_STA_DOWN) {
254		if (!link_ok || !addr_ok || !socket_ok)
255			return (0);
256
257
258		iface->state = IF_STA_ACTIVE;
259		ret = if_start(iface);
260	} else {
261		if (link_ok && addr_ok && socket_ok)
262			return (0);
263
264		iface->state = IF_STA_DOWN;
265		ret = if_reset(iface);
266	}
267
268	return (ret);
269}
270
271void
272if_update_all(void)
273{
274	struct iface		*iface;
275
276	LIST_FOREACH(iface, &leconf->iface_list, entry)
277		if_update(iface);
278}
279
280/* timers */
281/* ARGSUSED */
282void
283if_hello_timer(int fd, short event, void *arg)
284{
285	struct iface		*iface = arg;
286
287	send_hello(HELLO_LINK, iface, NULL);
288	if_start_hello_timer(iface);
289}
290
291void
292if_start_hello_timer(struct iface *iface)
293{
294	struct timeval		 tv;
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_join_group(struct iface *iface, struct in_addr *addr)
344{
345	struct ip_mreq		 mreq;
346	struct if_addr		*if_addr;
347
348	log_debug("%s: interface %s addr %s", __func__, iface->name,
349	    inet_ntoa(*addr));
350
351	if_addr = LIST_FIRST(&iface->addr_list);
352	mreq.imr_multiaddr = *addr;
353	mreq.imr_interface = if_addr->addr;
354
355	if (setsockopt(global.ldp_disc_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
356	    (void *)&mreq, sizeof(mreq)) < 0) {
357		log_warn("%s: error IP_ADD_MEMBERSHIP, interface %s address %s",
358		     __func__, iface->name, inet_ntoa(*addr));
359		return (-1);
360	}
361	return (0);
362}
363
364int
365if_leave_group(struct iface *iface, struct in_addr *addr)
366{
367	struct ip_mreq		 mreq;
368	struct if_addr		*if_addr;
369
370	log_debug("%s: interface %s addr %s", __func__, iface->name,
371	    inet_ntoa(*addr));
372
373	if_addr = LIST_FIRST(&iface->addr_list);
374	if (!if_addr)
375		return (0);
376
377	mreq.imr_multiaddr = *addr;
378	mreq.imr_interface = if_addr->addr;
379
380	if (setsockopt(global.ldp_disc_socket, IPPROTO_IP, IP_DROP_MEMBERSHIP,
381	    (void *)&mreq, sizeof(mreq)) < 0) {
382		log_warn("%s: error IP_DROP_MEMBERSHIP, interface %s "
383		    "address %s", __func__, iface->name, inet_ntoa(*addr));
384		return (-1);
385	}
386
387	return (0);
388}
389