1 /* $OpenBSD: interface.c,v 1.26 2023/03/08 04:43:13 guenther Exp $ */
2
3 /*
4 * Copyright (c) 2015 Renato Westphal <renato@openbsd.org>
5 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
6 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 */
20
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <sys/ioctl.h>
24 #include <arpa/inet.h>
25
26 #include <ctype.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30
31 #include "eigrpd.h"
32 #include "eigrpe.h"
33 #include "log.h"
34
35 static __inline int iface_id_compare(struct eigrp_iface *,
36 struct eigrp_iface *);
37 static struct iface *if_new(struct eigrpd_conf *, struct kif *);
38 static void if_del(struct iface *);
39 static struct if_addr *if_addr_lookup(struct if_addr_head *, struct kaddr *);
40 static void eigrp_if_start(struct eigrp_iface *);
41 static void eigrp_if_reset(struct eigrp_iface *);
42 static void eigrp_if_hello_timer(int, short, void *);
43 static void eigrp_if_start_hello_timer(struct eigrp_iface *);
44 static void eigrp_if_stop_hello_timer(struct eigrp_iface *);
45 static int if_join_ipv4_group(struct iface *, struct in_addr *);
46 static int if_leave_ipv4_group(struct iface *, struct in_addr *);
47 static int if_join_ipv6_group(struct iface *, struct in6_addr *);
48 static int if_leave_ipv6_group(struct iface *, struct in6_addr *);
49
50 RB_GENERATE(iface_id_head, eigrp_iface, id_tree, iface_id_compare)
51
52 struct iface_id_head ifaces_by_id = RB_INITIALIZER(&ifaces_by_id);
53
54 static __inline int
iface_id_compare(struct eigrp_iface * a,struct eigrp_iface * b)55 iface_id_compare(struct eigrp_iface *a, struct eigrp_iface *b)
56 {
57 return (a->ifaceid - b->ifaceid);
58 }
59
60 static struct iface *
if_new(struct eigrpd_conf * xconf,struct kif * kif)61 if_new(struct eigrpd_conf *xconf, struct kif *kif)
62 {
63 struct iface *iface;
64
65 if ((iface = calloc(1, sizeof(*iface))) == NULL)
66 fatal("if_new: calloc");
67
68 TAILQ_INIT(&iface->ei_list);
69 TAILQ_INIT(&iface->addr_list);
70
71 strlcpy(iface->name, kif->ifname, sizeof(iface->name));
72
73 /* get type */
74 if (kif->flags & IFF_POINTOPOINT)
75 iface->type = IF_TYPE_POINTOPOINT;
76 if (kif->flags & IFF_BROADCAST &&
77 kif->flags & IFF_MULTICAST)
78 iface->type = IF_TYPE_BROADCAST;
79 if (kif->flags & IFF_LOOPBACK)
80 iface->type = IF_TYPE_POINTOPOINT;
81
82 /* get index and flags */
83 iface->mtu = kif->mtu;
84 iface->ifindex = kif->ifindex;
85 iface->rdomain = kif->rdomain;
86 iface->flags = kif->flags;
87 iface->linkstate = kif->link_state;
88 iface->if_type = kif->if_type;
89 iface->baudrate = kif->baudrate;
90
91 TAILQ_INSERT_TAIL(&xconf->iface_list, iface, entry);
92
93 return (iface);
94 }
95
96 static void
if_del(struct iface * iface)97 if_del(struct iface *iface)
98 {
99 struct if_addr *if_addr;
100
101 log_debug("%s: interface %s", __func__, iface->name);
102
103 while ((if_addr = TAILQ_FIRST(&iface->addr_list)) != NULL) {
104 TAILQ_REMOVE(&iface->addr_list, if_addr, entry);
105 free(if_addr);
106 }
107
108 TAILQ_REMOVE(&econf->iface_list, iface, entry);
109 free(iface);
110 }
111
112 struct iface *
if_lookup(struct eigrpd_conf * xconf,unsigned int ifindex)113 if_lookup(struct eigrpd_conf *xconf, unsigned int ifindex)
114 {
115 struct iface *iface;
116
117 TAILQ_FOREACH(iface, &xconf->iface_list, entry)
118 if (iface->ifindex == ifindex)
119 return (iface);
120
121 return (NULL);
122 }
123
124 void
if_addr_new(struct iface * iface,struct kaddr * ka)125 if_addr_new(struct iface *iface, struct kaddr *ka)
126 {
127 struct if_addr *if_addr;
128 struct eigrp_iface *ei;
129
130 if (ka->af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&ka->addr.v6)) {
131 iface->linklocal = ka->addr.v6;
132 if_update(iface, AF_INET6);
133 return;
134 }
135
136 if (if_addr_lookup(&iface->addr_list, ka) != NULL)
137 return;
138
139 if ((if_addr = calloc(1, sizeof(*if_addr))) == NULL)
140 fatal("if_addr_new: calloc");
141 if_addr->af = ka->af;
142 if_addr->addr = ka->addr;
143 if_addr->prefixlen = ka->prefixlen;
144 if_addr->dstbrd = ka->dstbrd;
145 TAILQ_INSERT_TAIL(&iface->addr_list, if_addr, entry);
146
147 TAILQ_FOREACH(ei, &iface->ei_list, i_entry)
148 if (ei->state == IF_STA_ACTIVE && ei->eigrp->af == if_addr->af)
149 eigrpe_orig_local_route(ei, if_addr, 0);
150
151 if (if_addr->af == AF_INET)
152 if_update(iface, AF_INET);
153 }
154
155 void
if_addr_del(struct iface * iface,struct kaddr * ka)156 if_addr_del(struct iface *iface, struct kaddr *ka)
157 {
158 struct if_addr *if_addr;
159 struct eigrp_iface *ei;
160 int af = ka->af;
161
162 if (ka->af == AF_INET6 &&
163 IN6_ARE_ADDR_EQUAL(&iface->linklocal, &ka->addr.v6)) {
164 memset(&iface->linklocal, 0, sizeof(iface->linklocal));
165 if_update(iface, AF_INET6);
166 return;
167 }
168
169 if_addr = if_addr_lookup(&iface->addr_list, ka);
170 if (if_addr == NULL)
171 return;
172
173 TAILQ_FOREACH(ei, &iface->ei_list, i_entry)
174 if (ei->state == IF_STA_ACTIVE && ei->eigrp->af == if_addr->af)
175 eigrpe_orig_local_route(ei, if_addr, 1);
176
177 TAILQ_REMOVE(&iface->addr_list, if_addr, entry);
178 free(if_addr);
179
180 if (af == AF_INET)
181 if_update(iface, AF_INET);
182 }
183
184 static struct if_addr *
if_addr_lookup(struct if_addr_head * addr_list,struct kaddr * ka)185 if_addr_lookup(struct if_addr_head *addr_list, struct kaddr *ka)
186 {
187 struct if_addr *if_addr;
188 int af = ka->af;
189
190 TAILQ_FOREACH(if_addr, addr_list, entry)
191 if (!eigrp_addrcmp(af, &if_addr->addr, &ka->addr) &&
192 if_addr->prefixlen == ka->prefixlen &&
193 !eigrp_addrcmp(af, &if_addr->dstbrd, &ka->dstbrd))
194 return (if_addr);
195
196 return (NULL);
197 }
198
199 in_addr_t
if_primary_addr(struct iface * iface)200 if_primary_addr(struct iface *iface)
201 {
202 struct if_addr *if_addr;
203
204 TAILQ_FOREACH(if_addr, &iface->addr_list, entry)
205 if (if_addr->af == AF_INET)
206 return (if_addr->addr.v4.s_addr);
207
208 return (INADDR_ANY);
209 }
210
211 uint8_t
if_primary_addr_prefixlen(struct iface * iface)212 if_primary_addr_prefixlen(struct iface *iface)
213 {
214 struct if_addr *if_addr;
215
216 TAILQ_FOREACH(if_addr, &iface->addr_list, entry)
217 if (if_addr->af == AF_INET)
218 return (if_addr->prefixlen);
219
220 return (0);
221 }
222
223 /* up/down events */
224 void
if_update(struct iface * iface,int af)225 if_update(struct iface *iface, int af)
226 {
227 struct eigrp_iface *ei;
228 int link_ok;
229 int addr_ok, addr4_ok = 0, addr6_ok = 0;
230 struct if_addr *if_addr;
231
232 link_ok = (iface->flags & IFF_UP) &&
233 LINK_STATE_IS_UP(iface->linkstate);
234
235 /*
236 * NOTE: for EIGRPv4, each interface should have at least one valid
237 * IP address otherwise they can not be enabled in the routing domain.
238 */
239 TAILQ_FOREACH(if_addr, &iface->addr_list, entry) {
240 if (if_addr->af == AF_INET) {
241 addr4_ok = 1;
242 break;
243 }
244 }
245 /* for IPv6 the link-local address is enough. */
246 if (IN6_IS_ADDR_LINKLOCAL(&iface->linklocal))
247 addr6_ok = 1;
248
249 TAILQ_FOREACH(ei, &iface->ei_list, i_entry) {
250 if (af != AF_UNSPEC && ei->eigrp->af != af)
251 continue;
252
253 switch (ei->eigrp->af) {
254 case AF_INET:
255 addr_ok = addr4_ok;
256 break;
257 case AF_INET6:
258 addr_ok = addr6_ok;
259 break;
260 default:
261 fatalx("if_update: unknown af");
262 }
263
264 if (ei->state == IF_STA_DOWN) {
265 if (!link_ok || !addr_ok)
266 continue;
267 ei->state = IF_STA_ACTIVE;
268 eigrp_if_start(ei);
269 } else if (ei->state == IF_STA_ACTIVE) {
270 if (link_ok && addr_ok)
271 continue;
272 ei->state = IF_STA_DOWN;
273 eigrp_if_reset(ei);
274 }
275 }
276 }
277
278 struct eigrp_iface *
eigrp_if_new(struct eigrpd_conf * xconf,struct eigrp * eigrp,struct kif * kif)279 eigrp_if_new(struct eigrpd_conf *xconf, struct eigrp *eigrp, struct kif *kif)
280 {
281 struct iface *iface;
282 struct eigrp_iface *ei;
283 static uint32_t ifacecnt = 1;
284
285 iface = if_lookup(xconf, kif->ifindex);
286 if (iface == NULL)
287 iface = if_new(xconf, kif);
288
289 if ((ei = calloc(1, sizeof(*ei))) == NULL)
290 fatal("eigrp_if_new: calloc");
291
292 ei->state = IF_STA_DOWN;
293 /* get next unused ifaceid */
294 while (eigrp_if_lookup_id(ifacecnt++))
295 ;
296 ei->ifaceid = ifacecnt;
297 ei->eigrp = eigrp;
298 ei->iface = iface;
299 if (ei->iface->flags & IFF_LOOPBACK)
300 ei->passive = 1;
301
302 TAILQ_INIT(&ei->nbr_list);
303 TAILQ_INIT(&ei->update_list);
304 TAILQ_INIT(&ei->query_list);
305 TAILQ_INIT(&ei->summary_list);
306 TAILQ_INSERT_TAIL(&iface->ei_list, ei, i_entry);
307 TAILQ_INSERT_TAIL(&eigrp->ei_list, ei, e_entry);
308 if (RB_INSERT(iface_id_head, &ifaces_by_id, ei) != NULL)
309 fatalx("eigrp_if_new: RB_INSERT(ifaces_by_id) failed");
310
311 return (ei);
312 }
313
314 void
eigrp_if_del(struct eigrp_iface * ei)315 eigrp_if_del(struct eigrp_iface *ei)
316 {
317 struct summary_addr *summary;
318
319 RB_REMOVE(iface_id_head, &ifaces_by_id, ei);
320 TAILQ_REMOVE(&ei->eigrp->ei_list, ei, e_entry);
321 TAILQ_REMOVE(&ei->iface->ei_list, ei, i_entry);
322 while ((summary = TAILQ_FIRST(&ei->summary_list)) != NULL) {
323 TAILQ_REMOVE(&ei->summary_list, summary, entry);
324 free(summary);
325 }
326 message_list_clr(&ei->query_list);
327 message_list_clr(&ei->update_list);
328
329 if (ei->state == IF_STA_ACTIVE)
330 eigrp_if_reset(ei);
331
332 if (TAILQ_EMPTY(&ei->iface->ei_list))
333 if_del(ei->iface);
334
335 free(ei);
336 }
337
338 struct eigrp_iface *
eigrp_if_lookup(struct iface * iface,int af,uint16_t as)339 eigrp_if_lookup(struct iface *iface, int af, uint16_t as)
340 {
341 struct eigrp_iface *ei;
342
343 TAILQ_FOREACH(ei, &iface->ei_list, i_entry)
344 if (ei->eigrp->af == af &&
345 ei->eigrp->as == as)
346 return (ei);
347
348 return (NULL);
349 }
350
351 struct eigrp_iface *
eigrp_if_lookup_id(uint32_t ifaceid)352 eigrp_if_lookup_id(uint32_t ifaceid)
353 {
354 struct eigrp_iface e;
355 e.ifaceid = ifaceid;
356 return (RB_FIND(iface_id_head, &ifaces_by_id, &e));
357 }
358
359 static void
eigrp_if_start(struct eigrp_iface * ei)360 eigrp_if_start(struct eigrp_iface *ei)
361 {
362 struct eigrp *eigrp = ei->eigrp;
363 struct timeval now;
364 struct if_addr *if_addr;
365 union eigrpd_addr addr;
366
367 log_debug("%s: %s as %u family %s", __func__, ei->iface->name,
368 eigrp->as, af_name(eigrp->af));
369
370 gettimeofday(&now, NULL);
371 ei->uptime = now.tv_sec;
372
373 /* init the dummy self neighbor */
374 memset(&addr, 0, sizeof(addr));
375 ei->self = nbr_new(ei, &addr, 0, 1);
376 nbr_init(ei->self);
377
378 TAILQ_FOREACH(if_addr, &ei->iface->addr_list, entry) {
379 if (if_addr->af != eigrp->af)
380 continue;
381
382 eigrpe_orig_local_route(ei, if_addr, 0);
383 }
384
385 if (ei->passive)
386 return;
387
388 switch (eigrp->af) {
389 case AF_INET:
390 if (if_join_ipv4_group(ei->iface, &global.mcast_addr_v4))
391 return;
392 break;
393 case AF_INET6:
394 if (if_join_ipv6_group(ei->iface, &global.mcast_addr_v6))
395 return;
396 break;
397 default:
398 fatalx("eigrp_if_start: unknown af");
399 }
400
401 evtimer_set(&ei->hello_timer, eigrp_if_hello_timer, ei);
402 eigrp_if_start_hello_timer(ei);
403 }
404
405 static void
eigrp_if_reset(struct eigrp_iface * ei)406 eigrp_if_reset(struct eigrp_iface *ei)
407 {
408 struct eigrp *eigrp = ei->eigrp;
409 struct nbr *nbr;
410
411 log_debug("%s: %s as %u family %s", __func__, ei->iface->name,
412 eigrp->as, af_name(eigrp->af));
413
414 /* the rde will withdraw the connected route for us */
415
416 while ((nbr = TAILQ_FIRST(&ei->nbr_list)) != NULL)
417 nbr_del(nbr);
418
419 if (ei->passive)
420 return;
421
422 /* try to cleanup */
423 switch (eigrp->af) {
424 case AF_INET:
425 if_leave_ipv4_group(ei->iface, &global.mcast_addr_v4);
426 break;
427 case AF_INET6:
428 if_leave_ipv6_group(ei->iface, &global.mcast_addr_v6);
429 break;
430 default:
431 fatalx("eigrp_if_reset: unknown af");
432 }
433
434 eigrp_if_stop_hello_timer(ei);
435 }
436
437 /* timers */
438 static void
eigrp_if_hello_timer(int fd,short event,void * arg)439 eigrp_if_hello_timer(int fd, short event, void *arg)
440 {
441 struct eigrp_iface *ei = arg;
442 struct timeval tv;
443
444 send_hello(ei, NULL, 0);
445
446 /* reschedule hello_timer */
447 timerclear(&tv);
448 tv.tv_sec = ei->hello_interval;
449 if (evtimer_add(&ei->hello_timer, &tv) == -1)
450 fatal("eigrp_if_hello_timer");
451 }
452
453 static void
eigrp_if_start_hello_timer(struct eigrp_iface * ei)454 eigrp_if_start_hello_timer(struct eigrp_iface *ei)
455 {
456 struct timeval tv;
457
458 timerclear(&tv);
459 tv.tv_sec = ei->hello_interval;
460 if (evtimer_add(&ei->hello_timer, &tv) == -1)
461 fatal("eigrp_if_start_hello_timer");
462 }
463
464 static void
eigrp_if_stop_hello_timer(struct eigrp_iface * ei)465 eigrp_if_stop_hello_timer(struct eigrp_iface *ei)
466 {
467 if (evtimer_pending(&ei->hello_timer, NULL) &&
468 evtimer_del(&ei->hello_timer) == -1)
469 fatal("eigrp_if_stop_hello_timer");
470 }
471
472 struct ctl_iface *
if_to_ctl(struct eigrp_iface * ei)473 if_to_ctl(struct eigrp_iface *ei)
474 {
475 static struct ctl_iface ictl;
476 struct timeval now;
477 struct nbr *nbr;
478
479 ictl.af = ei->eigrp->af;
480 ictl.as = ei->eigrp->as;
481 memcpy(ictl.name, ei->iface->name, sizeof(ictl.name));
482 ictl.ifindex = ei->iface->ifindex;
483 switch (ei->eigrp->af) {
484 case AF_INET:
485 ictl.addr.v4.s_addr = if_primary_addr(ei->iface);
486 ictl.prefixlen = if_primary_addr_prefixlen(ei->iface);
487 break;
488 case AF_INET6:
489 ictl.addr.v6 = ei->iface->linklocal;
490 if (!IN6_IS_ADDR_UNSPECIFIED(&ei->iface->linklocal))
491 ictl.prefixlen = 64;
492 else
493 ictl.prefixlen = 0;
494 break;
495 default:
496 fatalx("if_to_ctl: unknown af");
497 }
498 ictl.flags = ei->iface->flags;
499 ictl.linkstate = ei->iface->linkstate;
500 ictl.mtu = ei->iface->mtu;
501 ictl.type = ei->iface->type;
502 ictl.if_type = ei->iface->if_type;
503 ictl.baudrate = ei->iface->baudrate;
504 ictl.delay = ei->delay;
505 ictl.bandwidth = ei->bandwidth;
506 ictl.hello_holdtime = ei->hello_holdtime;
507 ictl.hello_interval = ei->hello_interval;
508 ictl.splithorizon = ei->splithorizon;
509 ictl.passive = ei->passive;
510 ictl.nbr_cnt = 0;
511
512 gettimeofday(&now, NULL);
513 if (ei->state != IF_STA_DOWN && ei->uptime != 0)
514 ictl.uptime = now.tv_sec - ei->uptime;
515 else
516 ictl.uptime = 0;
517
518 TAILQ_FOREACH(nbr, &ei->nbr_list, entry)
519 if (!(nbr->flags & (F_EIGRP_NBR_PENDING|F_EIGRP_NBR_SELF)))
520 ictl.nbr_cnt++;
521
522 return (&ictl);
523 }
524
525 /* misc */
526 void
if_set_sockbuf(int fd)527 if_set_sockbuf(int fd)
528 {
529 int bsize;
530
531 bsize = 65535;
532 while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize,
533 sizeof(bsize)) == -1)
534 bsize /= 2;
535
536 if (bsize != 65535)
537 log_warnx("%s: recvbuf size only %d", __func__, bsize);
538
539 bsize = 65535;
540 while (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &bsize,
541 sizeof(bsize)) == -1)
542 bsize /= 2;
543
544 if (bsize != 65535)
545 log_warnx("%s: sendbuf size only %d", __func__, bsize);
546 }
547
548 static int
if_join_ipv4_group(struct iface * iface,struct in_addr * addr)549 if_join_ipv4_group(struct iface *iface, struct in_addr *addr)
550 {
551 struct ip_mreq mreq;
552
553 if (iface->group_count_v4++ != 0)
554 /* already joined */
555 return (0);
556
557 log_debug("%s: interface %s addr %s", __func__, iface->name,
558 inet_ntoa(*addr));
559
560 mreq.imr_multiaddr = *addr;
561 mreq.imr_interface.s_addr = if_primary_addr(iface);
562
563 if (setsockopt(global.eigrp_socket_v4, IPPROTO_IP, IP_ADD_MEMBERSHIP,
564 (void *)&mreq, sizeof(mreq)) == -1) {
565 log_warn("%s: error IP_ADD_MEMBERSHIP, interface %s address %s",
566 __func__, iface->name, inet_ntoa(*addr));
567 return (-1);
568 }
569
570 return (0);
571 }
572
573 static int
if_leave_ipv4_group(struct iface * iface,struct in_addr * addr)574 if_leave_ipv4_group(struct iface *iface, struct in_addr *addr)
575 {
576 struct ip_mreq mreq;
577
578 if (--iface->group_count_v4 != 0)
579 /* others still joined */
580 return (0);
581
582 log_debug("%s: interface %s addr %s", __func__, iface->name,
583 inet_ntoa(*addr));
584
585 mreq.imr_multiaddr = *addr;
586 mreq.imr_interface.s_addr = if_primary_addr(iface);
587
588 if (setsockopt(global.eigrp_socket_v4, IPPROTO_IP, IP_DROP_MEMBERSHIP,
589 (void *)&mreq, sizeof(mreq)) == -1) {
590 log_warn("%s: error IP_DROP_MEMBERSHIP, interface %s "
591 "address %s", iface->name, __func__, inet_ntoa(*addr));
592 return (-1);
593 }
594
595 return (0);
596 }
597
598 int
if_set_ipv4_mcast_ttl(int fd,uint8_t ttl)599 if_set_ipv4_mcast_ttl(int fd, uint8_t ttl)
600 {
601 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
602 (char *)&ttl, sizeof(ttl)) == -1) {
603 log_warn("%s: error setting IP_MULTICAST_TTL to %d",
604 __func__, ttl);
605 return (-1);
606 }
607
608 return (0);
609 }
610
611 int
if_set_ipv4_mcast(struct iface * iface)612 if_set_ipv4_mcast(struct iface *iface)
613 {
614 in_addr_t addr;
615
616 addr = if_primary_addr(iface);
617
618 if (setsockopt(global.eigrp_socket_v4, IPPROTO_IP, IP_MULTICAST_IF,
619 &addr, sizeof(addr)) == -1) {
620 log_warn("%s: error setting IP_MULTICAST_IF, interface %s",
621 __func__, iface->name);
622 return (-1);
623 }
624
625 return (0);
626 }
627
628 int
if_set_ipv4_mcast_loop(int fd)629 if_set_ipv4_mcast_loop(int fd)
630 {
631 uint8_t loop = 0;
632
633 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
634 (char *)&loop, sizeof(loop)) == -1) {
635 log_warn("%s: error setting IP_MULTICAST_LOOP", __func__);
636 return (-1);
637 }
638
639 return (0);
640 }
641
642 int
if_set_ipv4_recvif(int fd,int enable)643 if_set_ipv4_recvif(int fd, int enable)
644 {
645 if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &enable,
646 sizeof(enable)) == -1) {
647 log_warn("%s: error setting IP_RECVIF", __func__);
648 return (-1);
649 }
650 return (0);
651 }
652
653 int
if_set_ipv4_hdrincl(int fd)654 if_set_ipv4_hdrincl(int fd)
655 {
656 int hincl = 1;
657
658 if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof(hincl)) == -1) {
659 log_warn("%s: error setting IP_HDRINCL", __func__);
660 return (-1);
661 }
662
663 return (0);
664 }
665
666 static int
if_join_ipv6_group(struct iface * iface,struct in6_addr * addr)667 if_join_ipv6_group(struct iface *iface, struct in6_addr *addr)
668 {
669 struct ipv6_mreq mreq;
670
671 if (iface->group_count_v6++ != 0)
672 /* already joined */
673 return (0);
674
675 log_debug("%s: interface %s addr %s", __func__, iface->name,
676 log_in6addr(addr));
677
678 mreq.ipv6mr_multiaddr = *addr;
679 mreq.ipv6mr_interface = iface->ifindex;
680
681 if (setsockopt(global.eigrp_socket_v6, IPPROTO_IPV6, IPV6_JOIN_GROUP,
682 &mreq, sizeof(mreq)) == -1) {
683 log_warn("%s: error IPV6_JOIN_GROUP, interface %s address %s",
684 __func__, iface->name, log_in6addr(addr));
685 return (-1);
686 }
687
688 return (0);
689 }
690
691 static int
if_leave_ipv6_group(struct iface * iface,struct in6_addr * addr)692 if_leave_ipv6_group(struct iface *iface, struct in6_addr *addr)
693 {
694 struct ipv6_mreq mreq;
695
696 if (--iface->group_count_v6 != 0)
697 /* others still joined */
698 return (0);
699
700 log_debug("%s: interface %s addr %s", __func__, iface->name,
701 log_in6addr(addr));
702
703 mreq.ipv6mr_multiaddr = *addr;
704 mreq.ipv6mr_interface = iface->ifindex;
705
706 if (setsockopt(global.eigrp_socket_v6, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
707 (void *)&mreq, sizeof(mreq)) == -1) {
708 log_warn("%s: error IPV6_LEAVE_GROUP, interface %s address %s",
709 __func__, iface->name, log_in6addr(addr));
710 return (-1);
711 }
712
713 return (0);
714 }
715
716 int
if_set_ipv6_mcast(struct iface * iface)717 if_set_ipv6_mcast(struct iface *iface)
718 {
719 if (setsockopt(global.eigrp_socket_v6, IPPROTO_IPV6, IPV6_MULTICAST_IF,
720 &iface->ifindex, sizeof(iface->ifindex)) == -1) {
721 log_warn("%s: error setting IPV6_MULTICAST_IF, interface %s",
722 __func__, iface->name);
723 return (-1);
724 }
725
726 return (0);
727 }
728
729 int
if_set_ipv6_mcast_loop(int fd)730 if_set_ipv6_mcast_loop(int fd)
731 {
732 unsigned int loop = 0;
733
734 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
735 (unsigned int *)&loop, sizeof(loop)) == -1) {
736 log_warn("%s: error setting IPV6_MULTICAST_LOOP", __func__);
737 return (-1);
738 }
739
740 return (0);
741 }
742
743 int
if_set_ipv6_pktinfo(int fd,int enable)744 if_set_ipv6_pktinfo(int fd, int enable)
745 {
746 if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &enable,
747 sizeof(enable)) == -1) {
748 log_warn("%s: error setting IPV6_RECVPKTINFO", __func__);
749 return (-1);
750 }
751
752 return (0);
753 }
754
755 int
if_set_ipv6_dscp(int fd,int dscp)756 if_set_ipv6_dscp(int fd, int dscp)
757 {
758 if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &dscp,
759 sizeof(dscp)) == -1) {
760 log_warn("%s: error setting IPV6_TCLASS", __func__);
761 return (-1);
762 }
763
764 return (0);
765 }
766