xref: /openbsd/usr.sbin/dvmrpd/interface.c (revision 978e5cff)
1 /*	$OpenBSD: interface.c,v 1.1 2006/06/01 14:12:20 norby Exp $ */
2 
3 /*
4  * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
5  * Copyright (c) 2004, 2005, 2006 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 
25 #include <netinet/in.h>
26 #include <netinet/ip_mroute.h>
27 #include <arpa/inet.h>
28 #include <net/if.h>
29 
30 #include <ctype.h>
31 #include <err.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <string.h>
36 #include <event.h>
37 
38 #include "igmp.h"
39 #include "dvmrpd.h"
40 #include "dvmrp.h"
41 #include "log.h"
42 #include "dvmrpe.h"
43 
44 void	 if_probe_timer(int, short, void *);
45 int	 if_start_probe_timer(struct iface *);
46 int	 if_stop_probe_timer(struct iface *);
47 void	 if_query_timer(int, short, void *);
48 int	 if_start_query_timer(struct iface *);
49 int	 if_stop_query_timer(struct iface *);
50 void	 if_querier_present_timer(int, short, void *);
51 int	 if_start_querier_present_timer(struct iface *);
52 int	 if_stop_querier_present_timer(struct iface *);
53 int	 if_reset_querier_present_timer(struct iface *);
54 int	 if_act_start(struct iface *);
55 int	 if_act_query_seen(struct iface *);
56 int	 if_act_reset(struct iface *);
57 
58 struct {
59 	int			state;
60 	enum iface_event	event;
61 	enum iface_action	action;
62 	int			new_state;
63 } iface_fsm[] = {
64     /* current state	event that happened	action to take	resulting state */
65     {IF_STA_DOWN,	IF_EVT_UP,		IF_ACT_STRT,	0},
66     {IF_STA_ACTIVE,	IF_EVT_QRECVD,		IF_ACT_QPRSNT,	0},
67     {IF_STA_NONQUERIER, IF_EVT_QPRSNTTMOUT,	IF_ACT_STRT,	0},
68     {IF_STA_ANY,	IF_EVT_DOWN,		IF_ACT_RST,	IF_STA_DOWN},
69     {-1,		IF_EVT_NOTHING,		IF_ACT_NOTHING,	0},
70 };
71 
72 const char * const if_action_names[] = {
73 	"NOTHING",
74 	"START",
75 	"QPRSNT",
76 	"RESET"
77 };
78 
79 static const char * const if_event_names[] = {
80 	"NOTHING",
81 	"UP",
82 	"QTMOUT",
83 	"QRECVD",
84 	"QPRSNTTMOUT",
85 	"DOWN"
86 };
87 
88 int
89 if_fsm(struct iface *iface, enum iface_event event)
90 {
91 	int	old_state;
92 	int	new_state = 0;
93 	int	i, ret = 0;
94 
95 	old_state = iface->state;
96 
97 	for (i = 0; iface_fsm[i].state != -1; i++)
98 		if ((iface_fsm[i].state & old_state) &&
99 		    (iface_fsm[i].event == event)) {
100 			new_state = iface_fsm[i].new_state;
101 			break;
102 		}
103 
104 	if (iface_fsm[i].state == -1) {
105 		/* XXX event outside of the defined fsm, ignore it. */
106 		log_debug("fsm_if: interface %s, "
107 		    "event '%s' not expected in state '%s'", iface->name,
108 		    if_event_name(event), if_state_name(old_state));
109 		return (0);
110 	}
111 
112 	switch (iface_fsm[i].action) {
113 	case IF_ACT_STRT:
114 		ret = if_act_start(iface);
115 		break;
116 	case IF_ACT_QPRSNT:
117 		ret = if_act_query_seen(iface);
118 		break;
119 	case IF_ACT_RST:
120 		ret = if_act_reset(iface);
121 		break;
122 	case IF_ACT_NOTHING:
123 		/* do nothing */
124 		break;
125 	}
126 
127 	if (ret) {
128 		log_debug("fsm_if: error changing state for interface %s, "
129 		    "event '%s', state '%s'", iface->name, if_event_name(event),
130 		    if_state_name(old_state));
131 		return (-1);
132 	}
133 
134 	if (new_state != 0)
135 		iface->state = new_state;
136 
137 	log_debug("fsm_if: event '%s' resulted in action '%s' and changing "
138 	    "state for interface %s from '%s' to '%s'",
139 	    if_event_name(event), if_action_name(iface_fsm[i].action),
140 	    iface->name, if_state_name(old_state), if_state_name(iface->state));
141 
142 	return (ret);
143 }
144 
145 struct iface *
146 if_new(struct kif *kif)
147 {
148 	struct sockaddr_in	*sain;
149 	struct iface		*iface;
150 	struct ifreq		*ifr;
151 	int			 s;
152 
153 	if ((iface = calloc(1, sizeof(*iface))) == NULL)
154 		err(1, "if_new: calloc");
155 
156 	iface->state = IF_STA_DOWN;
157 	iface->passive = 1;
158 
159 	LIST_INIT(&iface->nbr_list);
160 	TAILQ_INIT(&iface->group_list);
161 	strlcpy(iface->name, kif->ifname, sizeof(iface->name));
162 
163 	if ((ifr = calloc(1, sizeof(*ifr))) == NULL)
164 		err(1, "if_new: calloc");
165 
166 	/* set up ifreq */
167 	strlcpy(ifr->ifr_name, kif->ifname, sizeof(ifr->ifr_name));
168 	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
169 		err(1, "if_new: socket");
170 
171 	/* get type */
172 	if ((kif->flags & IFF_POINTOPOINT))
173 		iface->type = IF_TYPE_POINTOPOINT;
174 	if ((kif->flags & IFF_BROADCAST) &&
175 	    (kif->flags & IFF_MULTICAST))
176 		iface->type = IF_TYPE_BROADCAST;
177 
178 	/* get mtu, index and flags */
179 	iface->mtu = kif->mtu;
180 	iface->ifindex = kif->ifindex;
181 	iface->flags = kif->flags;
182 	iface->linkstate = kif->link_state;
183 	iface->media_type = kif->media_type;
184 
185 	/* get address */
186 	if (ioctl(s, SIOCGIFADDR, (caddr_t)ifr) < 0)
187 		err(1, "if_new: cannot get address");
188 	sain = (struct sockaddr_in *) &ifr->ifr_addr;
189 	iface->addr = sain->sin_addr;
190 
191 	/* get mask */
192 	if (ioctl(s, SIOCGIFNETMASK, (caddr_t)ifr) < 0)
193 		err(1, "if_new: cannot get mask");
194 	sain = (struct sockaddr_in *) &ifr->ifr_addr;
195 	iface->mask = sain->sin_addr;
196 
197 	/* get p2p dst address */
198 	if (iface->type == IF_TYPE_POINTOPOINT) {
199 		if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)ifr) < 0)
200 			err(1, "if_new: cannot get dst addr");
201 		sain = (struct sockaddr_in *) &ifr->ifr_addr;
202 		iface->dst = sain->sin_addr;
203 	}
204 
205 	free(ifr);
206 	close(s);
207 
208 	return (iface);
209 }
210 
211 void
212 if_init(struct dvmrpd_conf *xconf, struct iface *iface)
213 {
214 	/* set event handlers for interface */
215 	evtimer_set(&iface->probe_timer, if_probe_timer, iface);
216 	evtimer_set(&iface->query_timer, if_query_timer, iface);
217 	evtimer_set(&iface->querier_present_timer, if_querier_present_timer,
218 	    iface);
219 
220 	TAILQ_INIT(&iface->rr_list);
221 
222 	iface->fd = xconf->dvmrp_socket;
223 	iface->gen_id = xconf->gen_id;
224 }
225 
226 int
227 if_del(struct iface *iface)
228 {
229 	struct nbr	*nbr = NULL;
230 
231 	/* clear lists etc */
232 	while ((nbr = LIST_FIRST(&iface->nbr_list)) != NULL) {
233 		LIST_REMOVE(nbr, entry);
234 		nbr_del(nbr);
235 	}
236 	group_list_clr(iface);
237 
238 	return (-1);
239 }
240 
241 int
242 if_nbr_list_empty(struct iface *iface)
243 {
244 	return (LIST_EMPTY(&iface->nbr_list));
245 }
246 
247 /* timers */
248 void
249 if_probe_timer(int fd, short event, void *arg)
250 {
251 	struct iface *iface = arg;
252 	struct timeval tv;
253 
254 	send_probe(iface);
255 
256 	/* reschedule probe_timer */
257 	if (!iface->passive) {
258 		timerclear(&tv);
259 		tv.tv_sec = iface->probe_interval;
260 		evtimer_add(&iface->probe_timer, &tv);
261 	}
262 }
263 
264 int
265 if_start_probe_timer(struct iface *iface)
266 {
267 	struct timeval tv;
268 
269 	timerclear(&tv);
270 	return (evtimer_add(&iface->probe_timer, &tv));
271 }
272 
273 int
274 if_stop_probe_timer(struct iface *iface)
275 {
276 	return (evtimer_del(&iface->probe_timer));
277 }
278 
279 void
280 if_query_timer(int fd, short event, void *arg)
281 {
282 	struct iface *iface = arg;
283 	struct timeval tv;
284 
285 	/* send a general query */
286 	send_igmp_query(iface, NULL);
287 
288 	/* reschedule query_timer */
289 	if (!iface->passive) {
290 		timerclear(&tv);
291 		if (iface->startup_query_counter != 0) {
292 			tv.tv_sec = iface->startup_query_interval;
293 			iface->startup_query_counter--;
294 		} else
295 			tv.tv_sec = iface->query_interval;
296 
297 		evtimer_add(&iface->query_timer, &tv);
298 	}
299 }
300 
301 int
302 if_start_query_timer(struct iface *iface)
303 {
304 	struct timeval tv;
305 
306 	timerclear(&tv);
307 	return (evtimer_add(&iface->query_timer, &tv));
308 }
309 
310 int
311 if_stop_query_timer(struct iface *iface)
312 {
313 	return (evtimer_del(&iface->query_timer));
314 }
315 
316 void
317 if_querier_present_timer(int fd, short event, void *arg)
318 {
319 	struct iface *iface = arg;
320 
321 	if_fsm(iface, IF_EVT_QPRSNTTMOUT);
322 }
323 
324 int
325 if_start_querier_present_timer(struct iface *iface)
326 {
327 	struct timeval tv;
328 
329 	/* Other Querier Present Interval */
330 	timerclear(&tv);
331 	tv.tv_sec = iface->robustness * iface->query_interval +
332 	    (iface->query_resp_interval / 2);
333 
334 	return (evtimer_add(&iface->querier_present_timer, &tv));
335 }
336 
337 int
338 if_stop_querier_present_timer(struct iface *iface)
339 {
340 	return (evtimer_del(&iface->querier_present_timer));
341 }
342 
343 int
344 if_reset_querier_present_timer(struct iface *iface)
345 {
346 	struct timeval	tv;
347 
348 	/* Other Querier Present Interval */
349 	timerclear(&tv);
350 	tv.tv_sec = iface->robustness * iface->query_interval +
351 	    (iface->query_resp_interval / 2);
352 
353 	return (evtimer_add(&iface->querier_present_timer, &tv));
354 }
355 
356 /* actions */
357 int
358 if_act_start(struct iface *iface)
359 {
360 	struct in_addr	 addr;
361 	struct timeval	 now;
362 
363 	if (iface->passive) {
364 		log_debug("if_act_start: cannot start passive interface %s",
365 		    iface->name);
366 		return (-1);
367 	}
368 
369 	if (!((iface->flags & IFF_UP) &&
370 	    (iface->linkstate != LINK_STATE_DOWN))) {
371 		log_debug("if_act_start: interface %s link down",
372 		    iface->name);
373 		return (0);
374 	}
375 
376 	gettimeofday(&now, NULL);
377 	iface->uptime = now.tv_sec;
378 
379 	switch (iface->type) {
380 	case IF_TYPE_POINTOPOINT:
381 	case IF_TYPE_BROADCAST:
382 		inet_aton(AllSystems, &addr);
383 		if (if_join_group(iface, &addr)) {
384 			log_warnx("if_act_start: error joining group %s, "
385 			    "interface %s", inet_ntoa(addr), iface->name);
386 			return (-1);
387 		}
388 		inet_aton(AllRouters, &addr);
389 		if (if_join_group(iface, &addr)) {
390 			log_warnx("if_act_start: error joining group %s, "
391 			    "interface %s", inet_ntoa(addr), iface->name);
392 			return (-1);
393 		}
394 		inet_aton(AllDVMRPRouters, &addr);
395 		if (if_join_group(iface, &addr)) {
396 			log_warnx("if_act_start: error joining group %s, "
397 			    "interface %s", inet_ntoa(addr), iface->name);
398 			return (-1);
399 		}
400 
401 		iface->state = IF_STA_QUERIER;
402 		if_start_query_timer(iface);
403 		if_start_probe_timer(iface);
404 		iface->startup_query_counter = iface->startup_query_cnt;
405 		break;
406 	default:
407 		fatalx("if_act_start: unknown type");
408 	}
409 
410 	return (0);
411 }
412 
413 int
414 if_act_query_seen(struct iface *iface)
415 {
416 	log_debug("if_act_query_seen: interface %s", iface->name);
417 
418 	switch (iface->type) {
419 	case IF_TYPE_POINTOPOINT:
420 		/* XXX iface p2p */
421 		break;
422 	case IF_TYPE_BROADCAST:
423 		iface->state = IF_STA_NONQUERIER;
424 		if_stop_query_timer(iface);
425 		if_reset_querier_present_timer(iface);
426 		break;
427 	default:
428 		fatalx("if_act_querier_seen: unknown type");
429 	}
430 
431 	return (0);
432 }
433 
434 int
435 if_act_reset(struct iface *iface)
436 {
437 	struct in_addr	 addr;
438 	struct nbr	*nbr;
439 
440 	switch (iface->type) {
441 	case IF_TYPE_POINTOPOINT:
442 	case IF_TYPE_BROADCAST:
443 		inet_aton(AllSystems, &addr);
444 		if (if_leave_group(iface, &addr)) {
445 			log_warnx("if_act_reset: error leaving group %s, "
446 			    "interface %s", inet_ntoa(addr), iface->name);
447 			return (-1);
448 		}
449 		inet_aton(AllRouters, &addr);
450 		if (if_leave_group(iface, &addr)) {
451 			log_warnx("if_act_reset: error leaving group %s, "
452 			    "interface %s", inet_ntoa(addr), iface->name);
453 			return (-1);
454 		}
455 		inet_aton(AllDVMRPRouters, &addr);
456 		if (if_leave_group(iface, &addr)) {
457 			log_warnx("if_act_reset: error leaving group %s, "
458 			    "interface %s", inet_ntoa(addr), iface->name);
459 			return (-1);
460 		}
461 
462 		iface->state = IF_STA_DOWN;
463 		iface->gen_id++;
464 		if_stop_query_timer(iface);
465 		if_stop_querier_present_timer(iface);
466 		/* XXX clear nbr list? */
467 		break;
468 	default:
469 		fatalx("if_act_reset: unknown type");
470 	}
471 
472 	LIST_FOREACH(nbr, &iface->nbr_list, entry) {
473 		if (nbr_fsm(nbr, NBR_EVT_KILL_NBR)) {
474 			log_debug("if_act_reset: error killing neighbor %s",
475 			    inet_ntoa(nbr->id));
476 		}
477 	}
478 
479 	group_list_clr(iface);	/* XXX clear group list? */
480 
481 	return (0);
482 }
483 
484 const char *
485 if_event_name(int event)
486 {
487 	return (if_event_names[event]);
488 }
489 
490 const char *
491 if_action_name(int action)
492 {
493 	return (if_action_names[action]);
494 }
495 
496 /* misc */
497 int
498 if_set_mcast_ttl(int fd, u_int8_t ttl)
499 {
500 	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
501 	    (char *)&ttl, sizeof(ttl)) < 0) {
502 		log_warn("if_set_mcast_ttl: error setting "
503 		    "IP_MULTICAST_TTL to %d", ttl);
504 		return (-1);
505 	}
506 
507 	return (0);
508 }
509 
510 int
511 if_set_tos(int fd, int tos)
512 {
513 	if (setsockopt(fd, IPPROTO_IP, IP_TOS,
514 	    (int *)&tos, sizeof(tos)) < 0) {
515 		log_warn("if_set_tos: error setting IP_TOS to 0x%x", tos);
516 		return (-1);
517 	}
518 
519 	return (0);
520 }
521 
522 void
523 if_set_recvbuf(int fd)
524 {
525 	int	bsize;
526 
527 	bsize = 65535;
528 	while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize,
529 	    sizeof(bsize)) == -1)
530 		bsize /= 2;
531 }
532 
533 int
534 if_join_group(struct iface *iface, struct in_addr *addr)
535 {
536 	struct ip_mreq	 mreq;
537 
538 	switch (iface->type) {
539 	case IF_TYPE_POINTOPOINT:
540 	case IF_TYPE_BROADCAST:
541 		mreq.imr_multiaddr.s_addr = addr->s_addr;
542 		mreq.imr_interface.s_addr = iface->addr.s_addr;
543 
544 		if (setsockopt(iface->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
545 		    (void *)&mreq, sizeof(mreq)) < 0) {
546 			log_debug("if_join_group: error IP_ADD_MEMBERSHIP, "
547 			    "interface %s", iface->name);
548 			return (-1);
549 		}
550 		break;
551 	default:
552 		fatalx("if_join_group: unknown interface type");
553 	}
554 
555 	return (0);
556 }
557 
558 int
559 if_leave_group(struct iface *iface, struct in_addr *addr)
560 {
561 	struct ip_mreq	 mreq;
562 
563 	switch (iface->type) {
564 	case IF_TYPE_POINTOPOINT:
565 	case IF_TYPE_BROADCAST:
566 		mreq.imr_multiaddr.s_addr = addr->s_addr;
567 		mreq.imr_interface.s_addr = iface->addr.s_addr;
568 
569 		if (setsockopt(iface->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
570 		    (void *)&mreq, sizeof(mreq)) < 0) {
571 			log_debug("if_leave_group: error IP_DROP_MEMBERSHIP, "
572 			    "interface %s", iface->name);
573 			return (-1);
574 		}
575 		break;
576 	default:
577 		fatalx("if_leave_group: unknown interface type");
578 	}
579 
580 	return (0);
581 }
582 
583 int
584 if_set_mcast(struct iface *iface)
585 {
586 	switch (iface->type) {
587 	case IF_TYPE_POINTOPOINT:
588 	case IF_TYPE_BROADCAST:
589 		if (setsockopt(iface->fd, IPPROTO_IP, IP_MULTICAST_IF,
590 		    (char *)&iface->addr.s_addr,
591 		    sizeof(iface->addr.s_addr)) < 0) {
592 			log_debug("if_set_mcast: error setting "
593 			    "IP_MULTICAST_IF, interface %s", iface->name);
594 			return (-1);
595 		}
596 		break;
597 	default:
598 		fatalx("if_set_mcast: unknown interface type");
599 	}
600 
601 	return (0);
602 }
603 
604 int
605 if_set_mcast_loop(int fd)
606 {
607 	u_int8_t	loop = 0;
608 
609 	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
610 	    (char *)&loop, sizeof(loop)) < 0) {
611 		log_warn("if_set_mcast_loop: error setting IP_MULTICAST_LOOP");
612 		return (-1);
613 	}
614 
615 	return (0);
616 }
617 
618 struct ctl_iface *
619 if_to_ctl(struct iface *iface)
620 {
621 	static struct ctl_iface	 ictl;
622 	struct timeval		 tv, now, res;
623 
624 	memcpy(ictl.name, iface->name, sizeof(ictl.name));
625 	memcpy(&ictl.addr, &iface->addr, sizeof(ictl.addr));
626 	memcpy(&ictl.mask, &iface->mask, sizeof(ictl.mask));
627 	memcpy(&ictl.querier, &iface->querier, sizeof(ictl.querier));
628 
629 	ictl.ifindex = iface->ifindex;
630 	ictl.state = iface->state;
631 	ictl.mtu = iface->mtu;
632 	ictl.nbr_cnt = 0;	/* XXX */
633 	ictl.adj_cnt = 0;	/* XXX */
634 
635 	ictl.gen_id = iface->gen_id;
636 	ictl.group_cnt = iface->group_cnt;
637 	ictl.baudrate = iface->baudrate;
638 	ictl.probe_interval = iface->probe_interval;
639 	ictl.query_interval = iface->query_interval;
640 	ictl.query_resp_interval = iface->query_resp_interval;
641 	ictl.recv_query_resp_interval = iface->recv_query_resp_interval;
642 	ictl.group_member_interval = iface->group_member_interval;
643 	ictl.querier_present_interval = iface->querier_present_interval;
644 	ictl.startup_query_interval = iface->startup_query_interval;
645 	ictl.startup_query_cnt = iface->startup_query_cnt;
646 	ictl.last_member_query_interval = iface->last_member_query_interval;
647 	ictl.last_member_query_cnt = iface->last_member_query_cnt;
648 	ictl.last_member_query_time = iface->last_member_query_time;
649 	ictl.v1_querier_present_tmout = iface->v1_querier_present_tmout;
650 	ictl.v1_host_present_interval = iface->v1_host_present_interval;
651 	ictl.dead_interval = iface->dead_interval;
652 
653 	ictl.baudrate = iface->baudrate;
654 	ictl.flags = iface->flags;
655 	ictl.metric = iface->metric;
656 	ictl.type = iface->type;
657 	ictl.robustness = iface->robustness;
658 	ictl.linkstate = iface->linkstate;
659 	ictl.passive = iface->passive;
660 	ictl.igmp_version = iface->igmp_version;
661 	ictl.mediatype = iface->media_type;
662 
663 	gettimeofday(&now, NULL);
664 	if (evtimer_pending(&iface->probe_timer, &tv)) {
665 		timersub(&tv, &now, &res);
666 		ictl.probe_timer = res.tv_sec;
667 	} else
668 		ictl.probe_timer = -1;
669 
670 	if (evtimer_pending(&iface->query_timer, &tv)) {
671 		timersub(&tv, &now, &res);
672 		ictl.query_timer = res.tv_sec;
673 	} else
674 		ictl.query_timer = -1;
675 
676 	if (evtimer_pending(&iface->querier_present_timer, &tv)) {
677 		timersub(&tv, &now, &res);
678 		ictl.querier_present_timer = res.tv_sec;
679 	} else
680 		ictl.querier_present_timer = -1;
681 
682 	if (iface->state != IF_STA_DOWN) {
683 		ictl.uptime = now.tv_sec - iface->uptime;
684 	} else
685 		ictl.uptime = 0;
686 
687 	return (&ictl);
688 }
689