1*5b133f3fSguenther /* $OpenBSD: interface.c,v 1.26 2023/03/08 04:43:13 guenther Exp $ */
243509a12Srenato
343509a12Srenato /*
443509a12Srenato * Copyright (c) 2015 Renato Westphal <renato@openbsd.org>
543509a12Srenato * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
643509a12Srenato * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
743509a12Srenato *
843509a12Srenato * Permission to use, copy, modify, and distribute this software for any
943509a12Srenato * purpose with or without fee is hereby granted, provided that the above
1043509a12Srenato * copyright notice and this permission notice appear in all copies.
1143509a12Srenato *
1243509a12Srenato * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1343509a12Srenato * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1443509a12Srenato * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1543509a12Srenato * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1643509a12Srenato * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1743509a12Srenato * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1843509a12Srenato * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1943509a12Srenato */
2043509a12Srenato
218072de9bSrenato #include <sys/types.h>
2243509a12Srenato #include <sys/socket.h>
238072de9bSrenato #include <sys/ioctl.h>
2443509a12Srenato #include <arpa/inet.h>
258072de9bSrenato
2643509a12Srenato #include <ctype.h>
278072de9bSrenato #include <stdlib.h>
2843509a12Srenato #include <string.h>
298072de9bSrenato #include <unistd.h>
3043509a12Srenato
3143509a12Srenato #include "eigrpd.h"
3243509a12Srenato #include "eigrpe.h"
338072de9bSrenato #include "log.h"
3443509a12Srenato
35ab786365Srenato static __inline int iface_id_compare(struct eigrp_iface *,
36ab786365Srenato struct eigrp_iface *);
37ab786365Srenato static struct iface *if_new(struct eigrpd_conf *, struct kif *);
38ab786365Srenato static void if_del(struct iface *);
39ab786365Srenato static struct if_addr *if_addr_lookup(struct if_addr_head *, struct kaddr *);
40ab786365Srenato static void eigrp_if_start(struct eigrp_iface *);
41ab786365Srenato static void eigrp_if_reset(struct eigrp_iface *);
42ab786365Srenato static void eigrp_if_hello_timer(int, short, void *);
43ab786365Srenato static void eigrp_if_start_hello_timer(struct eigrp_iface *);
44ab786365Srenato static void eigrp_if_stop_hello_timer(struct eigrp_iface *);
45ab786365Srenato static int if_join_ipv4_group(struct iface *, struct in_addr *);
46ab786365Srenato static int if_leave_ipv4_group(struct iface *, struct in_addr *);
47ab786365Srenato static int if_join_ipv6_group(struct iface *, struct in6_addr *);
48ab786365Srenato static int if_leave_ipv6_group(struct iface *, struct in6_addr *);
4943509a12Srenato
50ab786365Srenato RB_GENERATE(iface_id_head, eigrp_iface, id_tree, iface_id_compare)
51ab786365Srenato
52ab786365Srenato struct iface_id_head ifaces_by_id = RB_INITIALIZER(&ifaces_by_id);
5343509a12Srenato
5443509a12Srenato static __inline int
iface_id_compare(struct eigrp_iface * a,struct eigrp_iface * b)5543509a12Srenato iface_id_compare(struct eigrp_iface *a, struct eigrp_iface *b)
5643509a12Srenato {
5743509a12Srenato return (a->ifaceid - b->ifaceid);
5843509a12Srenato }
5943509a12Srenato
60ab786365Srenato static struct iface *
if_new(struct eigrpd_conf * xconf,struct kif * kif)6143509a12Srenato if_new(struct eigrpd_conf *xconf, struct kif *kif)
6243509a12Srenato {
6343509a12Srenato struct iface *iface;
6443509a12Srenato
6543509a12Srenato if ((iface = calloc(1, sizeof(*iface))) == NULL)
6644faa115Srenato fatal("if_new: calloc");
6743509a12Srenato
6843509a12Srenato TAILQ_INIT(&iface->ei_list);
6943509a12Srenato TAILQ_INIT(&iface->addr_list);
7043509a12Srenato
7143509a12Srenato strlcpy(iface->name, kif->ifname, sizeof(iface->name));
7243509a12Srenato
7343509a12Srenato /* get type */
7443509a12Srenato if (kif->flags & IFF_POINTOPOINT)
7543509a12Srenato iface->type = IF_TYPE_POINTOPOINT;
7643509a12Srenato if (kif->flags & IFF_BROADCAST &&
7743509a12Srenato kif->flags & IFF_MULTICAST)
7843509a12Srenato iface->type = IF_TYPE_BROADCAST;
7943509a12Srenato if (kif->flags & IFF_LOOPBACK)
8043509a12Srenato iface->type = IF_TYPE_POINTOPOINT;
8143509a12Srenato
8243509a12Srenato /* get index and flags */
8343509a12Srenato iface->mtu = kif->mtu;
8443509a12Srenato iface->ifindex = kif->ifindex;
8506c7f8f8Srenato iface->rdomain = kif->rdomain;
8643509a12Srenato iface->flags = kif->flags;
8743509a12Srenato iface->linkstate = kif->link_state;
8843509a12Srenato iface->if_type = kif->if_type;
8943509a12Srenato iface->baudrate = kif->baudrate;
9043509a12Srenato
9143509a12Srenato TAILQ_INSERT_TAIL(&xconf->iface_list, iface, entry);
9243509a12Srenato
9343509a12Srenato return (iface);
9443509a12Srenato }
9543509a12Srenato
96ab786365Srenato static void
if_del(struct iface * iface)9743509a12Srenato if_del(struct iface *iface)
9843509a12Srenato {
9943509a12Srenato struct if_addr *if_addr;
10043509a12Srenato
10143509a12Srenato log_debug("%s: interface %s", __func__, iface->name);
10243509a12Srenato
10343509a12Srenato while ((if_addr = TAILQ_FIRST(&iface->addr_list)) != NULL) {
10443509a12Srenato TAILQ_REMOVE(&iface->addr_list, if_addr, entry);
10543509a12Srenato free(if_addr);
10643509a12Srenato }
10743509a12Srenato
10843509a12Srenato TAILQ_REMOVE(&econf->iface_list, iface, entry);
10943509a12Srenato free(iface);
11043509a12Srenato }
11143509a12Srenato
1122e046f62Srenato struct iface *
if_lookup(struct eigrpd_conf * xconf,unsigned int ifindex)1132e046f62Srenato if_lookup(struct eigrpd_conf *xconf, unsigned int ifindex)
1142e046f62Srenato {
1152e046f62Srenato struct iface *iface;
1162e046f62Srenato
1172e046f62Srenato TAILQ_FOREACH(iface, &xconf->iface_list, entry)
1182e046f62Srenato if (iface->ifindex == ifindex)
1192e046f62Srenato return (iface);
1202e046f62Srenato
1212e046f62Srenato return (NULL);
1222e046f62Srenato }
1232e046f62Srenato
12443509a12Srenato void
if_addr_new(struct iface * iface,struct kaddr * ka)1252e046f62Srenato if_addr_new(struct iface *iface, struct kaddr *ka)
12643509a12Srenato {
12743509a12Srenato struct if_addr *if_addr;
12843509a12Srenato struct eigrp_iface *ei;
12943509a12Srenato
130e7271a36Srenato if (ka->af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&ka->addr.v6)) {
131e7271a36Srenato iface->linklocal = ka->addr.v6;
132e7271a36Srenato if_update(iface, AF_INET6);
133e7271a36Srenato return;
134e7271a36Srenato }
135e7271a36Srenato
1362e046f62Srenato if (if_addr_lookup(&iface->addr_list, ka) != NULL)
13744faa115Srenato return;
13843509a12Srenato
13943509a12Srenato if ((if_addr = calloc(1, sizeof(*if_addr))) == NULL)
14044faa115Srenato fatal("if_addr_new: calloc");
1412e046f62Srenato if_addr->af = ka->af;
1422e046f62Srenato if_addr->addr = ka->addr;
1432e046f62Srenato if_addr->prefixlen = ka->prefixlen;
1442e046f62Srenato if_addr->dstbrd = ka->dstbrd;
14543509a12Srenato TAILQ_INSERT_TAIL(&iface->addr_list, if_addr, entry);
14643509a12Srenato
14743509a12Srenato TAILQ_FOREACH(ei, &iface->ei_list, i_entry)
14843509a12Srenato if (ei->state == IF_STA_ACTIVE && ei->eigrp->af == if_addr->af)
14943509a12Srenato eigrpe_orig_local_route(ei, if_addr, 0);
15043509a12Srenato
151e7271a36Srenato if (if_addr->af == AF_INET)
152e7271a36Srenato if_update(iface, AF_INET);
15343509a12Srenato }
15443509a12Srenato
15543509a12Srenato void
if_addr_del(struct iface * iface,struct kaddr * ka)1562e046f62Srenato if_addr_del(struct iface *iface, struct kaddr *ka)
15743509a12Srenato {
15843509a12Srenato struct if_addr *if_addr;
15943509a12Srenato struct eigrp_iface *ei;
160e7271a36Srenato int af = ka->af;
161e7271a36Srenato
162e7271a36Srenato if (ka->af == AF_INET6 &&
163e7271a36Srenato IN6_ARE_ADDR_EQUAL(&iface->linklocal, &ka->addr.v6)) {
164e7271a36Srenato memset(&iface->linklocal, 0, sizeof(iface->linklocal));
165e7271a36Srenato if_update(iface, AF_INET6);
166e7271a36Srenato return;
167e7271a36Srenato }
16843509a12Srenato
1692e046f62Srenato if_addr = if_addr_lookup(&iface->addr_list, ka);
17043509a12Srenato if (if_addr == NULL)
17143509a12Srenato return;
17243509a12Srenato
17343509a12Srenato TAILQ_FOREACH(ei, &iface->ei_list, i_entry)
17443509a12Srenato if (ei->state == IF_STA_ACTIVE && ei->eigrp->af == if_addr->af)
17543509a12Srenato eigrpe_orig_local_route(ei, if_addr, 1);
17643509a12Srenato
17743509a12Srenato TAILQ_REMOVE(&iface->addr_list, if_addr, entry);
17843509a12Srenato free(if_addr);
179e7271a36Srenato
180e7271a36Srenato if (af == AF_INET)
181e7271a36Srenato if_update(iface, AF_INET);
18243509a12Srenato }
18343509a12Srenato
184ab786365Srenato static struct if_addr *
if_addr_lookup(struct if_addr_head * addr_list,struct kaddr * ka)1852e046f62Srenato if_addr_lookup(struct if_addr_head *addr_list, struct kaddr *ka)
18643509a12Srenato {
18743509a12Srenato struct if_addr *if_addr;
1882e046f62Srenato int af = ka->af;
18943509a12Srenato
19043509a12Srenato TAILQ_FOREACH(if_addr, addr_list, entry)
1912e046f62Srenato if (!eigrp_addrcmp(af, &if_addr->addr, &ka->addr) &&
1922e046f62Srenato if_addr->prefixlen == ka->prefixlen &&
1932e046f62Srenato !eigrp_addrcmp(af, &if_addr->dstbrd, &ka->dstbrd))
19443509a12Srenato return (if_addr);
19543509a12Srenato
19643509a12Srenato return (NULL);
19743509a12Srenato }
19843509a12Srenato
19943509a12Srenato in_addr_t
if_primary_addr(struct iface * iface)20043509a12Srenato if_primary_addr(struct iface *iface)
20143509a12Srenato {
20243509a12Srenato struct if_addr *if_addr;
20343509a12Srenato
20443509a12Srenato TAILQ_FOREACH(if_addr, &iface->addr_list, entry)
20543509a12Srenato if (if_addr->af == AF_INET)
20643509a12Srenato return (if_addr->addr.v4.s_addr);
20743509a12Srenato
20843509a12Srenato return (INADDR_ANY);
20943509a12Srenato }
21043509a12Srenato
21143509a12Srenato uint8_t
if_primary_addr_prefixlen(struct iface * iface)21243509a12Srenato if_primary_addr_prefixlen(struct iface *iface)
21343509a12Srenato {
21443509a12Srenato struct if_addr *if_addr;
21543509a12Srenato
21643509a12Srenato TAILQ_FOREACH(if_addr, &iface->addr_list, entry)
21743509a12Srenato if (if_addr->af == AF_INET)
21843509a12Srenato return (if_addr->prefixlen);
21943509a12Srenato
22043509a12Srenato return (0);
22143509a12Srenato }
22243509a12Srenato
22343509a12Srenato /* up/down events */
22443509a12Srenato void
if_update(struct iface * iface,int af)22543509a12Srenato if_update(struct iface *iface, int af)
22643509a12Srenato {
22743509a12Srenato struct eigrp_iface *ei;
22843509a12Srenato int link_ok;
229d6040158Srenato int addr_ok, addr4_ok = 0, addr6_ok = 0;
23046ee0129Srenato struct if_addr *if_addr;
23143509a12Srenato
23243509a12Srenato link_ok = (iface->flags & IFF_UP) &&
23343509a12Srenato LINK_STATE_IS_UP(iface->linkstate);
23443509a12Srenato
23546ee0129Srenato /*
236d6040158Srenato * NOTE: for EIGRPv4, each interface should have at least one valid
237d6040158Srenato * IP address otherwise they can not be enabled in the routing domain.
23846ee0129Srenato */
239d6040158Srenato TAILQ_FOREACH(if_addr, &iface->addr_list, entry) {
240d6040158Srenato if (if_addr->af == AF_INET) {
241d6040158Srenato addr4_ok = 1;
24246ee0129Srenato break;
24346ee0129Srenato }
244d6040158Srenato }
245d6040158Srenato /* for IPv6 the link-local address is enough. */
246d6040158Srenato if (IN6_IS_ADDR_LINKLOCAL(&iface->linklocal))
247d6040158Srenato addr6_ok = 1;
24846ee0129Srenato
24943509a12Srenato TAILQ_FOREACH(ei, &iface->ei_list, i_entry) {
25043509a12Srenato if (af != AF_UNSPEC && ei->eigrp->af != af)
25143509a12Srenato continue;
25243509a12Srenato
253d6040158Srenato switch (ei->eigrp->af) {
254d6040158Srenato case AF_INET:
255d6040158Srenato addr_ok = addr4_ok;
256d6040158Srenato break;
257d6040158Srenato case AF_INET6:
258d6040158Srenato addr_ok = addr6_ok;
259d6040158Srenato break;
260d6040158Srenato default:
261d6040158Srenato fatalx("if_update: unknown af");
262d6040158Srenato }
263d6040158Srenato
26443509a12Srenato if (ei->state == IF_STA_DOWN) {
26546ee0129Srenato if (!link_ok || !addr_ok)
26643509a12Srenato continue;
26743509a12Srenato ei->state = IF_STA_ACTIVE;
26843509a12Srenato eigrp_if_start(ei);
26946ee0129Srenato } else if (ei->state == IF_STA_ACTIVE) {
27046ee0129Srenato if (link_ok && addr_ok)
27143509a12Srenato continue;
27243509a12Srenato ei->state = IF_STA_DOWN;
27343509a12Srenato eigrp_if_reset(ei);
27443509a12Srenato }
27543509a12Srenato }
27643509a12Srenato }
27743509a12Srenato
27843509a12Srenato struct eigrp_iface *
eigrp_if_new(struct eigrpd_conf * xconf,struct eigrp * eigrp,struct kif * kif)27943509a12Srenato eigrp_if_new(struct eigrpd_conf *xconf, struct eigrp *eigrp, struct kif *kif)
28043509a12Srenato {
28143509a12Srenato struct iface *iface;
28243509a12Srenato struct eigrp_iface *ei;
2835425f012Srenato static uint32_t ifacecnt = 1;
28443509a12Srenato
28543509a12Srenato iface = if_lookup(xconf, kif->ifindex);
28643509a12Srenato if (iface == NULL)
28743509a12Srenato iface = if_new(xconf, kif);
28843509a12Srenato
28943509a12Srenato if ((ei = calloc(1, sizeof(*ei))) == NULL)
29044faa115Srenato fatal("eigrp_if_new: calloc");
29143509a12Srenato
29243509a12Srenato ei->state = IF_STA_DOWN;
29343509a12Srenato /* get next unused ifaceid */
2942e046f62Srenato while (eigrp_if_lookup_id(ifacecnt++))
29543509a12Srenato ;
29643509a12Srenato ei->ifaceid = ifacecnt;
29743509a12Srenato ei->eigrp = eigrp;
29843509a12Srenato ei->iface = iface;
29943509a12Srenato if (ei->iface->flags & IFF_LOOPBACK)
30043509a12Srenato ei->passive = 1;
30143509a12Srenato
30243509a12Srenato TAILQ_INIT(&ei->nbr_list);
30343509a12Srenato TAILQ_INIT(&ei->update_list);
30443509a12Srenato TAILQ_INIT(&ei->query_list);
305bc6e1915Srenato TAILQ_INIT(&ei->summary_list);
30643509a12Srenato TAILQ_INSERT_TAIL(&iface->ei_list, ei, i_entry);
30743509a12Srenato TAILQ_INSERT_TAIL(&eigrp->ei_list, ei, e_entry);
30843509a12Srenato if (RB_INSERT(iface_id_head, &ifaces_by_id, ei) != NULL)
30943509a12Srenato fatalx("eigrp_if_new: RB_INSERT(ifaces_by_id) failed");
31043509a12Srenato
31143509a12Srenato return (ei);
31243509a12Srenato }
31343509a12Srenato
31443509a12Srenato void
eigrp_if_del(struct eigrp_iface * ei)31543509a12Srenato eigrp_if_del(struct eigrp_iface *ei)
31643509a12Srenato {
317bc6e1915Srenato struct summary_addr *summary;
318bc6e1915Srenato
31943509a12Srenato RB_REMOVE(iface_id_head, &ifaces_by_id, ei);
32043509a12Srenato TAILQ_REMOVE(&ei->eigrp->ei_list, ei, e_entry);
32143509a12Srenato TAILQ_REMOVE(&ei->iface->ei_list, ei, i_entry);
322bc6e1915Srenato while ((summary = TAILQ_FIRST(&ei->summary_list)) != NULL) {
323bc6e1915Srenato TAILQ_REMOVE(&ei->summary_list, summary, entry);
324bc6e1915Srenato free(summary);
325bc6e1915Srenato }
3260cefb3adSrenato message_list_clr(&ei->query_list);
3270cefb3adSrenato message_list_clr(&ei->update_list);
32843509a12Srenato
32943509a12Srenato if (ei->state == IF_STA_ACTIVE)
33043509a12Srenato eigrp_if_reset(ei);
33143509a12Srenato
33243509a12Srenato if (TAILQ_EMPTY(&ei->iface->ei_list))
33343509a12Srenato if_del(ei->iface);
33443509a12Srenato
33543509a12Srenato free(ei);
33643509a12Srenato }
33743509a12Srenato
3382e046f62Srenato struct eigrp_iface *
eigrp_if_lookup(struct iface * iface,int af,uint16_t as)3392e046f62Srenato eigrp_if_lookup(struct iface *iface, int af, uint16_t as)
3402e046f62Srenato {
3412e046f62Srenato struct eigrp_iface *ei;
3422e046f62Srenato
3432e046f62Srenato TAILQ_FOREACH(ei, &iface->ei_list, i_entry)
3442e046f62Srenato if (ei->eigrp->af == af &&
3452e046f62Srenato ei->eigrp->as == as)
3462e046f62Srenato return (ei);
3472e046f62Srenato
3482e046f62Srenato return (NULL);
3492e046f62Srenato }
3502e046f62Srenato
3512e046f62Srenato struct eigrp_iface *
eigrp_if_lookup_id(uint32_t ifaceid)3522e046f62Srenato eigrp_if_lookup_id(uint32_t ifaceid)
3532e046f62Srenato {
3542e046f62Srenato struct eigrp_iface e;
3552e046f62Srenato e.ifaceid = ifaceid;
3562e046f62Srenato return (RB_FIND(iface_id_head, &ifaces_by_id, &e));
3572e046f62Srenato }
3582e046f62Srenato
359ab786365Srenato static void
eigrp_if_start(struct eigrp_iface * ei)36043509a12Srenato eigrp_if_start(struct eigrp_iface *ei)
36143509a12Srenato {
36243509a12Srenato struct eigrp *eigrp = ei->eigrp;
3632d38b530Srenato struct timeval now;
36443509a12Srenato struct if_addr *if_addr;
36518d502b7Srenato union eigrpd_addr addr;
36643509a12Srenato
36743509a12Srenato log_debug("%s: %s as %u family %s", __func__, ei->iface->name,
36843509a12Srenato eigrp->as, af_name(eigrp->af));
36943509a12Srenato
3702d38b530Srenato gettimeofday(&now, NULL);
3712d38b530Srenato ei->uptime = now.tv_sec;
3722d38b530Srenato
37318d502b7Srenato /* init the dummy self neighbor */
37418d502b7Srenato memset(&addr, 0, sizeof(addr));
37518d502b7Srenato ei->self = nbr_new(ei, &addr, 0, 1);
37618d502b7Srenato nbr_init(ei->self);
37718d502b7Srenato
37843509a12Srenato TAILQ_FOREACH(if_addr, &ei->iface->addr_list, entry) {
37943509a12Srenato if (if_addr->af != eigrp->af)
38043509a12Srenato continue;
38143509a12Srenato
38243509a12Srenato eigrpe_orig_local_route(ei, if_addr, 0);
38343509a12Srenato }
38443509a12Srenato
38543509a12Srenato if (ei->passive)
38643509a12Srenato return;
38743509a12Srenato
38843509a12Srenato switch (eigrp->af) {
38943509a12Srenato case AF_INET:
390e14e95d7Srenato if (if_join_ipv4_group(ei->iface, &global.mcast_addr_v4))
39143509a12Srenato return;
39243509a12Srenato break;
39343509a12Srenato case AF_INET6:
394e14e95d7Srenato if (if_join_ipv6_group(ei->iface, &global.mcast_addr_v6))
39543509a12Srenato return;
39643509a12Srenato break;
39743509a12Srenato default:
3983c8071b0Srenato fatalx("eigrp_if_start: unknown af");
39943509a12Srenato }
40043509a12Srenato
4010b78755cSrenato evtimer_set(&ei->hello_timer, eigrp_if_hello_timer, ei);
40243509a12Srenato eigrp_if_start_hello_timer(ei);
40343509a12Srenato }
40443509a12Srenato
405ab786365Srenato static void
eigrp_if_reset(struct eigrp_iface * ei)40643509a12Srenato eigrp_if_reset(struct eigrp_iface *ei)
40743509a12Srenato {
40843509a12Srenato struct eigrp *eigrp = ei->eigrp;
409a2dbf0baSrenato struct nbr *nbr;
41043509a12Srenato
41143509a12Srenato log_debug("%s: %s as %u family %s", __func__, ei->iface->name,
41243509a12Srenato eigrp->as, af_name(eigrp->af));
41343509a12Srenato
41443509a12Srenato /* the rde will withdraw the connected route for us */
41543509a12Srenato
4160b78755cSrenato while ((nbr = TAILQ_FIRST(&ei->nbr_list)) != NULL)
4170b78755cSrenato nbr_del(nbr);
4180b78755cSrenato
41943509a12Srenato if (ei->passive)
42043509a12Srenato return;
42143509a12Srenato
42243509a12Srenato /* try to cleanup */
42343509a12Srenato switch (eigrp->af) {
42443509a12Srenato case AF_INET:
425e14e95d7Srenato if_leave_ipv4_group(ei->iface, &global.mcast_addr_v4);
42643509a12Srenato break;
42743509a12Srenato case AF_INET6:
428e14e95d7Srenato if_leave_ipv6_group(ei->iface, &global.mcast_addr_v6);
42943509a12Srenato break;
43043509a12Srenato default:
4313c8071b0Srenato fatalx("eigrp_if_reset: unknown af");
43243509a12Srenato }
43343509a12Srenato
43443509a12Srenato eigrp_if_stop_hello_timer(ei);
43543509a12Srenato }
43643509a12Srenato
43743509a12Srenato /* timers */
438ab786365Srenato static void
eigrp_if_hello_timer(int fd,short event,void * arg)43943509a12Srenato eigrp_if_hello_timer(int fd, short event, void *arg)
44043509a12Srenato {
44143509a12Srenato struct eigrp_iface *ei = arg;
44243509a12Srenato struct timeval tv;
44343509a12Srenato
4440e96235eSrenato send_hello(ei, NULL, 0);
44543509a12Srenato
44643509a12Srenato /* reschedule hello_timer */
44743509a12Srenato timerclear(&tv);
44843509a12Srenato tv.tv_sec = ei->hello_interval;
44943509a12Srenato if (evtimer_add(&ei->hello_timer, &tv) == -1)
45043509a12Srenato fatal("eigrp_if_hello_timer");
45143509a12Srenato }
45243509a12Srenato
453ab786365Srenato static void
eigrp_if_start_hello_timer(struct eigrp_iface * ei)45443509a12Srenato eigrp_if_start_hello_timer(struct eigrp_iface *ei)
45543509a12Srenato {
45643509a12Srenato struct timeval tv;
45743509a12Srenato
45843509a12Srenato timerclear(&tv);
45943509a12Srenato tv.tv_sec = ei->hello_interval;
46043509a12Srenato if (evtimer_add(&ei->hello_timer, &tv) == -1)
46143509a12Srenato fatal("eigrp_if_start_hello_timer");
46243509a12Srenato }
46343509a12Srenato
464ab786365Srenato static void
eigrp_if_stop_hello_timer(struct eigrp_iface * ei)46543509a12Srenato eigrp_if_stop_hello_timer(struct eigrp_iface *ei)
46643509a12Srenato {
46743509a12Srenato if (evtimer_pending(&ei->hello_timer, NULL) &&
46843509a12Srenato evtimer_del(&ei->hello_timer) == -1)
46943509a12Srenato fatal("eigrp_if_stop_hello_timer");
47043509a12Srenato }
47143509a12Srenato
47243509a12Srenato struct ctl_iface *
if_to_ctl(struct eigrp_iface * ei)47343509a12Srenato if_to_ctl(struct eigrp_iface *ei)
47443509a12Srenato {
47543509a12Srenato static struct ctl_iface ictl;
47643509a12Srenato struct timeval now;
47743509a12Srenato struct nbr *nbr;
47843509a12Srenato
47943509a12Srenato ictl.af = ei->eigrp->af;
48043509a12Srenato ictl.as = ei->eigrp->as;
48143509a12Srenato memcpy(ictl.name, ei->iface->name, sizeof(ictl.name));
48243509a12Srenato ictl.ifindex = ei->iface->ifindex;
48343509a12Srenato switch (ei->eigrp->af) {
48443509a12Srenato case AF_INET:
48543509a12Srenato ictl.addr.v4.s_addr = if_primary_addr(ei->iface);
48643509a12Srenato ictl.prefixlen = if_primary_addr_prefixlen(ei->iface);
48743509a12Srenato break;
48843509a12Srenato case AF_INET6:
4893eb03b29Srenato ictl.addr.v6 = ei->iface->linklocal;
490bce3b5b3Srenato if (!IN6_IS_ADDR_UNSPECIFIED(&ei->iface->linklocal))
49143509a12Srenato ictl.prefixlen = 64;
492bce3b5b3Srenato else
493bce3b5b3Srenato ictl.prefixlen = 0;
49443509a12Srenato break;
49543509a12Srenato default:
4963c8071b0Srenato fatalx("if_to_ctl: unknown af");
49743509a12Srenato }
49843509a12Srenato ictl.flags = ei->iface->flags;
49943509a12Srenato ictl.linkstate = ei->iface->linkstate;
50043509a12Srenato ictl.mtu = ei->iface->mtu;
50143509a12Srenato ictl.type = ei->iface->type;
50243509a12Srenato ictl.if_type = ei->iface->if_type;
50343509a12Srenato ictl.baudrate = ei->iface->baudrate;
50443509a12Srenato ictl.delay = ei->delay;
50543509a12Srenato ictl.bandwidth = ei->bandwidth;
50643509a12Srenato ictl.hello_holdtime = ei->hello_holdtime;
50743509a12Srenato ictl.hello_interval = ei->hello_interval;
50843509a12Srenato ictl.splithorizon = ei->splithorizon;
50943509a12Srenato ictl.passive = ei->passive;
51043509a12Srenato ictl.nbr_cnt = 0;
51143509a12Srenato
51243509a12Srenato gettimeofday(&now, NULL);
51343509a12Srenato if (ei->state != IF_STA_DOWN && ei->uptime != 0)
51443509a12Srenato ictl.uptime = now.tv_sec - ei->uptime;
51543509a12Srenato else
51643509a12Srenato ictl.uptime = 0;
51743509a12Srenato
51843509a12Srenato TAILQ_FOREACH(nbr, &ei->nbr_list, entry)
51943509a12Srenato if (!(nbr->flags & (F_EIGRP_NBR_PENDING|F_EIGRP_NBR_SELF)))
52043509a12Srenato ictl.nbr_cnt++;
52143509a12Srenato
52243509a12Srenato return (&ictl);
52343509a12Srenato }
52443509a12Srenato
52543509a12Srenato /* misc */
52643509a12Srenato void
if_set_sockbuf(int fd)52743509a12Srenato if_set_sockbuf(int fd)
52843509a12Srenato {
52943509a12Srenato int bsize;
53043509a12Srenato
53143509a12Srenato bsize = 65535;
53243509a12Srenato while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize,
53343509a12Srenato sizeof(bsize)) == -1)
53443509a12Srenato bsize /= 2;
53543509a12Srenato
53643509a12Srenato if (bsize != 65535)
53743509a12Srenato log_warnx("%s: recvbuf size only %d", __func__, bsize);
53843509a12Srenato
53943509a12Srenato bsize = 65535;
54043509a12Srenato while (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &bsize,
54143509a12Srenato sizeof(bsize)) == -1)
54243509a12Srenato bsize /= 2;
54343509a12Srenato
54443509a12Srenato if (bsize != 65535)
54543509a12Srenato log_warnx("%s: sendbuf size only %d", __func__, bsize);
54643509a12Srenato }
54743509a12Srenato
548ab786365Srenato static int
if_join_ipv4_group(struct iface * iface,struct in_addr * addr)54943509a12Srenato if_join_ipv4_group(struct iface *iface, struct in_addr *addr)
55043509a12Srenato {
55143509a12Srenato struct ip_mreq mreq;
55243509a12Srenato
55343509a12Srenato if (iface->group_count_v4++ != 0)
55443509a12Srenato /* already joined */
55543509a12Srenato return (0);
55643509a12Srenato
55743509a12Srenato log_debug("%s: interface %s addr %s", __func__, iface->name,
55843509a12Srenato inet_ntoa(*addr));
55943509a12Srenato
560bce3b5b3Srenato mreq.imr_multiaddr = *addr;
56143509a12Srenato mreq.imr_interface.s_addr = if_primary_addr(iface);
56243509a12Srenato
56302eb61efSrenato if (setsockopt(global.eigrp_socket_v4, IPPROTO_IP, IP_ADD_MEMBERSHIP,
564df69c215Sderaadt (void *)&mreq, sizeof(mreq)) == -1) {
56543509a12Srenato log_warn("%s: error IP_ADD_MEMBERSHIP, interface %s address %s",
56643509a12Srenato __func__, iface->name, inet_ntoa(*addr));
56743509a12Srenato return (-1);
56843509a12Srenato }
56943509a12Srenato
57043509a12Srenato return (0);
57143509a12Srenato }
57243509a12Srenato
573ab786365Srenato static int
if_leave_ipv4_group(struct iface * iface,struct in_addr * addr)57443509a12Srenato if_leave_ipv4_group(struct iface *iface, struct in_addr *addr)
57543509a12Srenato {
57643509a12Srenato struct ip_mreq mreq;
57743509a12Srenato
57843509a12Srenato if (--iface->group_count_v4 != 0)
57943509a12Srenato /* others still joined */
58043509a12Srenato return (0);
58143509a12Srenato
58243509a12Srenato log_debug("%s: interface %s addr %s", __func__, iface->name,
58343509a12Srenato inet_ntoa(*addr));
58443509a12Srenato
585bce3b5b3Srenato mreq.imr_multiaddr = *addr;
58643509a12Srenato mreq.imr_interface.s_addr = if_primary_addr(iface);
58743509a12Srenato
58802eb61efSrenato if (setsockopt(global.eigrp_socket_v4, IPPROTO_IP, IP_DROP_MEMBERSHIP,
589df69c215Sderaadt (void *)&mreq, sizeof(mreq)) == -1) {
59043509a12Srenato log_warn("%s: error IP_DROP_MEMBERSHIP, interface %s "
59143509a12Srenato "address %s", iface->name, __func__, inet_ntoa(*addr));
59243509a12Srenato return (-1);
59343509a12Srenato }
59443509a12Srenato
59543509a12Srenato return (0);
59643509a12Srenato }
59743509a12Srenato
59843509a12Srenato int
if_set_ipv4_mcast_ttl(int fd,uint8_t ttl)59943509a12Srenato if_set_ipv4_mcast_ttl(int fd, uint8_t ttl)
60043509a12Srenato {
60143509a12Srenato if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
602df69c215Sderaadt (char *)&ttl, sizeof(ttl)) == -1) {
60343509a12Srenato log_warn("%s: error setting IP_MULTICAST_TTL to %d",
60443509a12Srenato __func__, ttl);
60543509a12Srenato return (-1);
60643509a12Srenato }
60743509a12Srenato
60843509a12Srenato return (0);
60943509a12Srenato }
61043509a12Srenato
61143509a12Srenato int
if_set_ipv4_mcast(struct iface * iface)61243509a12Srenato if_set_ipv4_mcast(struct iface *iface)
61343509a12Srenato {
61443509a12Srenato in_addr_t addr;
61543509a12Srenato
61643509a12Srenato addr = if_primary_addr(iface);
61743509a12Srenato
61802eb61efSrenato if (setsockopt(global.eigrp_socket_v4, IPPROTO_IP, IP_MULTICAST_IF,
619df69c215Sderaadt &addr, sizeof(addr)) == -1) {
62043509a12Srenato log_warn("%s: error setting IP_MULTICAST_IF, interface %s",
62143509a12Srenato __func__, iface->name);
62243509a12Srenato return (-1);
62343509a12Srenato }
62443509a12Srenato
62543509a12Srenato return (0);
62643509a12Srenato }
62743509a12Srenato
62843509a12Srenato int
if_set_ipv4_mcast_loop(int fd)62943509a12Srenato if_set_ipv4_mcast_loop(int fd)
63043509a12Srenato {
63143509a12Srenato uint8_t loop = 0;
63243509a12Srenato
63343509a12Srenato if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
634df69c215Sderaadt (char *)&loop, sizeof(loop)) == -1) {
63543509a12Srenato log_warn("%s: error setting IP_MULTICAST_LOOP", __func__);
63643509a12Srenato return (-1);
63743509a12Srenato }
63843509a12Srenato
63943509a12Srenato return (0);
64043509a12Srenato }
64143509a12Srenato
64243509a12Srenato int
if_set_ipv4_recvif(int fd,int enable)64343509a12Srenato if_set_ipv4_recvif(int fd, int enable)
64443509a12Srenato {
64543509a12Srenato if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &enable,
646df69c215Sderaadt sizeof(enable)) == -1) {
64743509a12Srenato log_warn("%s: error setting IP_RECVIF", __func__);
64843509a12Srenato return (-1);
64943509a12Srenato }
65043509a12Srenato return (0);
65143509a12Srenato }
65243509a12Srenato
65343509a12Srenato int
if_set_ipv4_hdrincl(int fd)65443509a12Srenato if_set_ipv4_hdrincl(int fd)
65543509a12Srenato {
65643509a12Srenato int hincl = 1;
65743509a12Srenato
658df69c215Sderaadt if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof(hincl)) == -1) {
65943509a12Srenato log_warn("%s: error setting IP_HDRINCL", __func__);
66043509a12Srenato return (-1);
66143509a12Srenato }
66243509a12Srenato
66343509a12Srenato return (0);
66443509a12Srenato }
66543509a12Srenato
666ab786365Srenato static int
if_join_ipv6_group(struct iface * iface,struct in6_addr * addr)66743509a12Srenato if_join_ipv6_group(struct iface *iface, struct in6_addr *addr)
66843509a12Srenato {
66943509a12Srenato struct ipv6_mreq mreq;
67043509a12Srenato
67143509a12Srenato if (iface->group_count_v6++ != 0)
67243509a12Srenato /* already joined */
67343509a12Srenato return (0);
67443509a12Srenato
67543509a12Srenato log_debug("%s: interface %s addr %s", __func__, iface->name,
67643509a12Srenato log_in6addr(addr));
67743509a12Srenato
67843509a12Srenato mreq.ipv6mr_multiaddr = *addr;
67943509a12Srenato mreq.ipv6mr_interface = iface->ifindex;
68043509a12Srenato
68102eb61efSrenato if (setsockopt(global.eigrp_socket_v6, IPPROTO_IPV6, IPV6_JOIN_GROUP,
682df69c215Sderaadt &mreq, sizeof(mreq)) == -1) {
68343509a12Srenato log_warn("%s: error IPV6_JOIN_GROUP, interface %s address %s",
68443509a12Srenato __func__, iface->name, log_in6addr(addr));
68543509a12Srenato return (-1);
68643509a12Srenato }
68743509a12Srenato
68843509a12Srenato return (0);
68943509a12Srenato }
69043509a12Srenato
691ab786365Srenato static int
if_leave_ipv6_group(struct iface * iface,struct in6_addr * addr)69243509a12Srenato if_leave_ipv6_group(struct iface *iface, struct in6_addr *addr)
69343509a12Srenato {
69443509a12Srenato struct ipv6_mreq mreq;
69543509a12Srenato
69643509a12Srenato if (--iface->group_count_v6 != 0)
69743509a12Srenato /* others still joined */
69843509a12Srenato return (0);
69943509a12Srenato
70043509a12Srenato log_debug("%s: interface %s addr %s", __func__, iface->name,
70143509a12Srenato log_in6addr(addr));
70243509a12Srenato
70343509a12Srenato mreq.ipv6mr_multiaddr = *addr;
70443509a12Srenato mreq.ipv6mr_interface = iface->ifindex;
70543509a12Srenato
70602eb61efSrenato if (setsockopt(global.eigrp_socket_v6, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
707df69c215Sderaadt (void *)&mreq, sizeof(mreq)) == -1) {
70843509a12Srenato log_warn("%s: error IPV6_LEAVE_GROUP, interface %s address %s",
70943509a12Srenato __func__, iface->name, log_in6addr(addr));
71043509a12Srenato return (-1);
71143509a12Srenato }
71243509a12Srenato
71343509a12Srenato return (0);
71443509a12Srenato }
71543509a12Srenato
71643509a12Srenato int
if_set_ipv6_mcast(struct iface * iface)71743509a12Srenato if_set_ipv6_mcast(struct iface *iface)
71843509a12Srenato {
71902eb61efSrenato if (setsockopt(global.eigrp_socket_v6, IPPROTO_IPV6, IPV6_MULTICAST_IF,
720df69c215Sderaadt &iface->ifindex, sizeof(iface->ifindex)) == -1) {
72144faa115Srenato log_warn("%s: error setting IPV6_MULTICAST_IF, interface %s",
72243509a12Srenato __func__, iface->name);
72343509a12Srenato return (-1);
72443509a12Srenato }
72543509a12Srenato
72643509a12Srenato return (0);
72743509a12Srenato }
72843509a12Srenato
72943509a12Srenato int
if_set_ipv6_mcast_loop(int fd)73043509a12Srenato if_set_ipv6_mcast_loop(int fd)
73143509a12Srenato {
73243509a12Srenato unsigned int loop = 0;
73343509a12Srenato
73443509a12Srenato if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
735df69c215Sderaadt (unsigned int *)&loop, sizeof(loop)) == -1) {
73643509a12Srenato log_warn("%s: error setting IPV6_MULTICAST_LOOP", __func__);
73743509a12Srenato return (-1);
73843509a12Srenato }
73943509a12Srenato
74043509a12Srenato return (0);
74143509a12Srenato }
74243509a12Srenato
74343509a12Srenato int
if_set_ipv6_pktinfo(int fd,int enable)74443509a12Srenato if_set_ipv6_pktinfo(int fd, int enable)
74543509a12Srenato {
74643509a12Srenato if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &enable,
747df69c215Sderaadt sizeof(enable)) == -1) {
748bce3b5b3Srenato log_warn("%s: error setting IPV6_RECVPKTINFO", __func__);
74943509a12Srenato return (-1);
75043509a12Srenato }
75143509a12Srenato
75243509a12Srenato return (0);
75343509a12Srenato }
75443509a12Srenato
75543509a12Srenato int
if_set_ipv6_dscp(int fd,int dscp)75643509a12Srenato if_set_ipv6_dscp(int fd, int dscp)
75743509a12Srenato {
75843509a12Srenato if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &dscp,
759df69c215Sderaadt sizeof(dscp)) == -1) {
76043509a12Srenato log_warn("%s: error setting IPV6_TCLASS", __func__);
76143509a12Srenato return (-1);
76243509a12Srenato }
76343509a12Srenato
76443509a12Srenato return (0);
76543509a12Srenato }
766