"Fossies" - the Fresh Open Source Software Archive 
Member "ospfd/interface.c" (5 Jun 2009, 21258 Bytes) of package /linux/privat/old/openospfd-4.6.tgz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "interface.c" see the
Fossies "Dox" file reference documentation.
1 /* $OpenBSD: interface.c,v 1.63 2009/06/05 04:12:52 claudio Exp $ */
2
3 /*
4 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
5 * Copyright (c) 2004, 2005 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 <ctype.h>
29 #include <err.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <string.h>
34 #include <event.h>
35
36 #include "ospfd.h"
37 #include "ospf.h"
38 #include "log.h"
39 #include "ospfe.h"
40
41 void if_hello_timer(int, short, void *);
42 void if_start_hello_timer(struct iface *);
43 void if_stop_hello_timer(struct iface *);
44 void if_stop_wait_timer(struct iface *);
45 void if_wait_timer(int, short, void *);
46 void if_start_wait_timer(struct iface *);
47 void if_stop_wait_timer(struct iface *);
48 struct nbr *if_elect(struct nbr *, struct nbr *);
49
50 struct {
51 int state;
52 enum iface_event event;
53 enum iface_action action;
54 int new_state;
55 } iface_fsm[] = {
56 /* current state event that happened action to take resulting state */
57 {IF_STA_DOWN, IF_EVT_UP, IF_ACT_STRT, 0},
58 {IF_STA_WAITING, IF_EVT_BACKUP_SEEN, IF_ACT_ELECT, 0},
59 {IF_STA_WAITING, IF_EVT_WTIMER, IF_ACT_ELECT, 0},
60 {IF_STA_ANY, IF_EVT_WTIMER, IF_ACT_NOTHING, 0},
61 {IF_STA_WAITING, IF_EVT_NBR_CHNG, IF_ACT_NOTHING, 0},
62 {IF_STA_MULTI, IF_EVT_NBR_CHNG, IF_ACT_ELECT, 0},
63 {IF_STA_ANY, IF_EVT_NBR_CHNG, IF_ACT_NOTHING, 0},
64 {IF_STA_ANY, IF_EVT_DOWN, IF_ACT_RST, IF_STA_DOWN},
65 {IF_STA_ANY, IF_EVT_LOOP, IF_ACT_RST, IF_STA_LOOPBACK},
66 {IF_STA_LOOPBACK, IF_EVT_UNLOOP, IF_ACT_NOTHING, IF_STA_DOWN},
67 {-1, IF_EVT_NOTHING, IF_ACT_NOTHING, 0},
68 };
69
70 static int vlink_cnt = 0;
71
72 const char * const if_event_names[] = {
73 "NOTHING",
74 "UP",
75 "WAITTIMER",
76 "BACKUPSEEN",
77 "NEIGHBORCHANGE",
78 "LOOP",
79 "UNLOOP",
80 "DOWN"
81 };
82
83 const char * const if_action_names[] = {
84 "NOTHING",
85 "START",
86 "ELECT",
87 "RESET"
88 };
89
90 int
91 if_fsm(struct iface *iface, enum iface_event event)
92 {
93 int old_state;
94 int new_state = 0;
95 int i, ret = 0;
96
97 old_state = iface->state;
98
99 for (i = 0; iface_fsm[i].state != -1; i++)
100 if ((iface_fsm[i].state & old_state) &&
101 (iface_fsm[i].event == event)) {
102 new_state = iface_fsm[i].new_state;
103 break;
104 }
105
106 if (iface_fsm[i].state == -1) {
107 /* event outside of the defined fsm, ignore it. */
108 log_debug("if_fsm: interface %s, "
109 "event %s not expected in state %s", iface->name,
110 if_event_names[event], if_state_name(old_state));
111 return (0);
112 }
113
114 switch (iface_fsm[i].action) {
115 case IF_ACT_STRT:
116 ret = if_act_start(iface);
117 break;
118 case IF_ACT_ELECT:
119 ret = if_act_elect(iface);
120 break;
121 case IF_ACT_RST:
122 ret = if_act_reset(iface);
123 break;
124 case IF_ACT_NOTHING:
125 /* do nothing */
126 break;
127 }
128
129 if (ret) {
130 log_debug("if_fsm: error changing state for interface %s, "
131 "event %s, state %s", iface->name, if_event_names[event],
132 if_state_name(old_state));
133 return (-1);
134 }
135
136 if (new_state != 0)
137 iface->state = new_state;
138
139 if (iface->state != old_state)
140 orig_rtr_lsa(iface->area);
141
142 if (old_state & (IF_STA_MULTI | IF_STA_POINTTOPOINT) &&
143 (iface->state & (IF_STA_MULTI | IF_STA_POINTTOPOINT)) == 0)
144 ospfe_demote_iface(iface, 0);
145 if ((old_state & (IF_STA_MULTI | IF_STA_POINTTOPOINT)) == 0 &&
146 iface->state & (IF_STA_MULTI | IF_STA_POINTTOPOINT))
147 ospfe_demote_iface(iface, 1);
148
149 log_debug("if_fsm: event %s resulted in action %s and changing "
150 "state for interface %s from %s to %s",
151 if_event_names[event], if_action_names[iface_fsm[i].action],
152 iface->name, if_state_name(old_state), if_state_name(iface->state));
153
154 return (ret);
155 }
156
157 struct iface *
158 if_new(struct kif *kif, struct kif_addr *ka)
159 {
160 struct iface *iface;
161
162 if ((iface = calloc(1, sizeof(*iface))) == NULL)
163 err(1, "if_new: calloc");
164
165 iface->state = IF_STA_DOWN;
166
167 LIST_INIT(&iface->nbr_list);
168 TAILQ_INIT(&iface->ls_ack_list);
169 TAILQ_INIT(&iface->auth_md_list);
170
171 iface->crypt_seq_num = arc4random() & 0x0fffffff;
172
173 if (kif == NULL) {
174 iface->type = IF_TYPE_VIRTUALLINK;
175 snprintf(iface->name, sizeof(iface->name), "vlink%d",
176 vlink_cnt++);
177 iface->flags |= IFF_UP;
178 iface->mtu = IP_MSS;
179 return (iface);
180 }
181
182 strlcpy(iface->name, kif->ifname, sizeof(iface->name));
183
184 /* get type */
185 if (kif->flags & IFF_POINTOPOINT)
186 iface->type = IF_TYPE_POINTOPOINT;
187 if (kif->flags & IFF_BROADCAST &&
188 kif->flags & IFF_MULTICAST)
189 iface->type = IF_TYPE_BROADCAST;
190 if (kif->flags & IFF_LOOPBACK) {
191 iface->type = IF_TYPE_POINTOPOINT;
192 iface->state = IF_STA_LOOPBACK;
193 }
194
195 /* get mtu, index and flags */
196 iface->mtu = kif->mtu;
197 iface->ifindex = kif->ifindex;
198 iface->flags = kif->flags;
199 iface->linkstate = kif->link_state;
200 iface->media_type = kif->media_type;
201 iface->baudrate = kif->baudrate;
202
203 /* set address, mask and p2p addr */
204 iface->addr = ka->addr;
205 iface->mask = ka->mask;
206 if (kif->flags & IFF_POINTOPOINT) {
207 iface->dst = ka->dstbrd;
208 }
209
210 return (iface);
211 }
212
213 void
214 if_del(struct iface *iface)
215 {
216 struct nbr *nbr = NULL;
217
218 /* revert the demotion when the interface is deleted */
219 if ((iface->state & (IF_STA_MULTI | IF_STA_POINTTOPOINT)) == 0)
220 ospfe_demote_iface(iface, 1);
221
222 /* clear lists etc */
223 while ((nbr = LIST_FIRST(&iface->nbr_list)) != NULL)
224 nbr_del(nbr);
225
226 if (evtimer_pending(&iface->hello_timer, NULL))
227 evtimer_del(&iface->hello_timer);
228 if (evtimer_pending(&iface->wait_timer, NULL))
229 evtimer_del(&iface->wait_timer);
230 if (evtimer_pending(&iface->lsack_tx_timer, NULL))
231 evtimer_del(&iface->lsack_tx_timer);
232
233 ls_ack_list_clr(iface);
234 md_list_clr(&iface->auth_md_list);
235 free(iface);
236 }
237
238 void
239 if_init(struct ospfd_conf *xconf, struct iface *iface)
240 {
241 struct ifreq ifr;
242 u_int rdomain;
243
244 /* init the dummy local neighbor */
245 iface->self = nbr_new(ospfe_router_id(), iface, 1);
246
247 /* set event handlers for interface */
248 evtimer_set(&iface->lsack_tx_timer, ls_ack_tx_timer, iface);
249 evtimer_set(&iface->hello_timer, if_hello_timer, iface);
250 evtimer_set(&iface->wait_timer, if_wait_timer, iface);
251
252 iface->fd = xconf->ospf_socket;
253
254 strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
255 if (ioctl(iface->fd, SIOCGIFRTABLEID, (caddr_t)&ifr) == -1)
256 rdomain = 0;
257 else {
258 rdomain = ifr.ifr_rdomainid;
259 if (setsockopt(iface->fd, IPPROTO_IP, SO_RDOMAIN,
260 &rdomain, sizeof(rdomain)) == -1)
261 fatal("failed to set rdomain");
262 }
263 if (rdomain != xconf->rdomain)
264 fatalx("interface rdomain mismatch");
265
266 ospfe_demote_iface(iface, 0);
267 }
268
269 /* timers */
270 /* ARGSUSED */
271 void
272 if_hello_timer(int fd, short event, void *arg)
273 {
274 struct iface *iface = arg;
275 struct timeval tv;
276
277 send_hello(iface);
278
279 /* reschedule hello_timer */
280 timerclear(&tv);
281 tv.tv_sec = iface->hello_interval;
282 if (evtimer_add(&iface->hello_timer, &tv) == -1)
283 fatal("if_hello_timer");
284 }
285
286 void
287 if_start_hello_timer(struct iface *iface)
288 {
289 struct timeval tv;
290
291 timerclear(&tv);
292 if (evtimer_add(&iface->hello_timer, &tv) == -1)
293 fatal("if_start_hello_timer");
294 }
295
296 void
297 if_stop_hello_timer(struct iface *iface)
298 {
299 if (evtimer_del(&iface->hello_timer) == -1)
300 fatal("if_stop_hello_timer");
301 }
302
303 /* ARGSUSED */
304 void
305 if_wait_timer(int fd, short event, void *arg)
306 {
307 struct iface *iface = arg;
308
309 if_fsm(iface, IF_EVT_WTIMER);
310 }
311
312 void
313 if_start_wait_timer(struct iface *iface)
314 {
315 struct timeval tv;
316
317 timerclear(&tv);
318 tv.tv_sec = iface->dead_interval;
319 if (evtimer_add(&iface->wait_timer, &tv) == -1)
320 fatal("if_start_wait_timer");
321 }
322
323 void
324 if_stop_wait_timer(struct iface *iface)
325 {
326 if (evtimer_del(&iface->wait_timer) == -1)
327 fatal("if_stop_wait_timer");
328 }
329
330 /* actions */
331 int
332 if_act_start(struct iface *iface)
333 {
334 struct in_addr addr;
335 struct timeval now;
336
337 if (!((iface->flags & IFF_UP) &&
338 (LINK_STATE_IS_UP(iface->linkstate) ||
339 (iface->linkstate == LINK_STATE_UNKNOWN &&
340 iface->media_type != IFT_CARP))))
341 return (0);
342
343 if (iface->media_type == IFT_CARP && iface->passive == 0) {
344 /* force passive mode on carp interfaces */
345 log_warnx("if_act_start: forcing interface %s to passive",
346 iface->name);
347 iface->passive = 1;
348 }
349
350 if (iface->passive) {
351 /* for an update of stub network entries */
352 orig_rtr_lsa(iface->area);
353 return (0);
354 }
355
356 gettimeofday(&now, NULL);
357 iface->uptime = now.tv_sec;
358
359 switch (iface->type) {
360 case IF_TYPE_POINTOPOINT:
361 inet_aton(AllSPFRouters, &addr);
362 if (if_join_group(iface, &addr))
363 return (-1);
364 iface->state = IF_STA_POINTTOPOINT;
365 break;
366 case IF_TYPE_VIRTUALLINK:
367 iface->state = IF_STA_POINTTOPOINT;
368 break;
369 case IF_TYPE_POINTOMULTIPOINT:
370 case IF_TYPE_NBMA:
371 log_debug("if_act_start: type %s not supported, interface %s",
372 if_type_name(iface->type), iface->name);
373 return (-1);
374 case IF_TYPE_BROADCAST:
375 inet_aton(AllSPFRouters, &addr);
376 if (if_join_group(iface, &addr))
377 return (-1);
378 if (iface->priority == 0) {
379 iface->state = IF_STA_DROTHER;
380 } else {
381 iface->state = IF_STA_WAITING;
382 if_start_wait_timer(iface);
383 }
384 break;
385 default:
386 fatalx("if_act_start: unknown interface type");
387 }
388
389 /* hello timer needs to be started in any case */
390 if_start_hello_timer(iface);
391 return (0);
392 }
393
394 struct nbr *
395 if_elect(struct nbr *a, struct nbr *b)
396 {
397 if (a->priority > b->priority)
398 return (a);
399 if (a->priority < b->priority)
400 return (b);
401 if (ntohl(a->id.s_addr) > ntohl(b->id.s_addr))
402 return (a);
403 return (b);
404 }
405
406 int
407 if_act_elect(struct iface *iface)
408 {
409 struct in_addr addr;
410 struct nbr *nbr, *bdr = NULL, *dr = NULL;
411 int round = 0;
412 int changed = 0;
413 int old_state;
414 char b1[16], b2[16], b3[16], b4[16];
415
416 start:
417 /* elect backup designated router */
418 LIST_FOREACH(nbr, &iface->nbr_list, entry) {
419 if (nbr->priority == 0 || nbr == dr || /* not electable */
420 nbr->state & NBR_STA_PRELIM || /* not available */
421 nbr->dr.s_addr == nbr->addr.s_addr) /* don't elect DR */
422 continue;
423 if (bdr != NULL) {
424 /*
425 * routers announcing themselves as BDR have higher
426 * precedence over those routers announcing a
427 * different BDR.
428 */
429 if (nbr->bdr.s_addr == nbr->addr.s_addr) {
430 if (bdr->bdr.s_addr == bdr->addr.s_addr)
431 bdr = if_elect(bdr, nbr);
432 else
433 bdr = nbr;
434 } else if (bdr->bdr.s_addr != bdr->addr.s_addr)
435 bdr = if_elect(bdr, nbr);
436 } else
437 bdr = nbr;
438 }
439
440 /* elect designated router */
441 LIST_FOREACH(nbr, &iface->nbr_list, entry) {
442 if (nbr->priority == 0 || nbr->state & NBR_STA_PRELIM ||
443 (nbr != dr && nbr->dr.s_addr != nbr->addr.s_addr))
444 /* only DR may be elected check priority too */
445 continue;
446 if (dr == NULL)
447 dr = nbr;
448 else
449 dr = if_elect(dr, nbr);
450 }
451
452 if (dr == NULL) {
453 /* no designated router found use backup DR */
454 dr = bdr;
455 bdr = NULL;
456 }
457
458 /*
459 * if we are involved in the election (e.g. new DR or no
460 * longer BDR) redo the election
461 */
462 if (round == 0 &&
463 ((iface->self == dr && iface->self != iface->dr) ||
464 (iface->self != dr && iface->self == iface->dr) ||
465 (iface->self == bdr && iface->self != iface->bdr) ||
466 (iface->self != bdr && iface->self == iface->bdr))) {
467 /*
468 * Reset announced DR/BDR to calculated one, so
469 * that we may get elected in the second round.
470 * This is needed to drop from a DR to a BDR.
471 */
472 iface->self->dr.s_addr = dr->addr.s_addr;
473 if (bdr)
474 iface->self->bdr.s_addr = bdr->addr.s_addr;
475 round = 1;
476 goto start;
477 }
478
479 log_debug("if_act_elect: interface %s old dr %s new dr %s, "
480 "old bdr %s new bdr %s", iface->name,
481 iface->dr ? inet_ntop(AF_INET, &iface->dr->addr, b1, sizeof(b1)) :
482 "none", dr ? inet_ntop(AF_INET, &dr->addr, b2, sizeof(b2)) : "none",
483 iface->bdr ? inet_ntop(AF_INET, &iface->bdr->addr, b3, sizeof(b3)) :
484 "none", bdr ? inet_ntop(AF_INET, &bdr->addr, b4, sizeof(b4)) :
485 "none");
486
487 /*
488 * After the second round still DR or BDR change state to DR or BDR,
489 * etc.
490 */
491 old_state = iface->state;
492 if (dr == iface->self)
493 iface->state = IF_STA_DR;
494 else if (bdr == iface->self)
495 iface->state = IF_STA_BACKUP;
496 else
497 iface->state = IF_STA_DROTHER;
498
499 /* TODO if iface is NBMA send all non eligible neighbors event Start */
500
501 /*
502 * if DR or BDR changed issue a AdjOK? event for all neighbors > 2-Way
503 */
504 if (iface->dr != dr || iface->bdr != bdr)
505 changed = 1;
506
507 iface->dr = dr;
508 iface->bdr = bdr;
509
510 if (changed) {
511 inet_aton(AllDRouters, &addr);
512 if (old_state & IF_STA_DRORBDR &&
513 (iface->state & IF_STA_DRORBDR) == 0) {
514 if (if_leave_group(iface, &addr))
515 return (-1);
516 } else if ((old_state & IF_STA_DRORBDR) == 0 &&
517 iface->state & IF_STA_DRORBDR) {
518 if (if_join_group(iface, &addr))
519 return (-1);
520 }
521
522 LIST_FOREACH(nbr, &iface->nbr_list, entry) {
523 if (nbr->state & NBR_STA_BIDIR)
524 nbr_fsm(nbr, NBR_EVT_ADJ_OK);
525 }
526
527 orig_rtr_lsa(iface->area);
528 if (iface->state & IF_STA_DR || old_state & IF_STA_DR)
529 orig_net_lsa(iface);
530 }
531
532 if_start_hello_timer(iface);
533 return (0);
534 }
535
536 int
537 if_act_reset(struct iface *iface)
538 {
539 struct nbr *nbr = NULL;
540 struct in_addr addr;
541
542 if (iface->passive) {
543 /* for an update of stub network entries */
544 orig_rtr_lsa(iface->area);
545 return (0);
546 }
547
548 switch (iface->type) {
549 case IF_TYPE_POINTOPOINT:
550 case IF_TYPE_BROADCAST:
551 inet_aton(AllSPFRouters, &addr);
552 if (if_leave_group(iface, &addr)) {
553 log_warnx("if_act_reset: error leaving group %s, "
554 "interface %s", inet_ntoa(addr), iface->name);
555 }
556 if (iface->state & IF_STA_DRORBDR) {
557 inet_aton(AllDRouters, &addr);
558 if (if_leave_group(iface, &addr)) {
559 log_warnx("if_act_reset: "
560 "error leaving group %s, interface %s",
561 inet_ntoa(addr), iface->name);
562 }
563 }
564 break;
565 case IF_TYPE_VIRTUALLINK:
566 /* nothing */
567 break;
568 case IF_TYPE_NBMA:
569 case IF_TYPE_POINTOMULTIPOINT:
570 log_debug("if_act_reset: type %s not supported, interface %s",
571 if_type_name(iface->type), iface->name);
572 return (-1);
573 default:
574 fatalx("if_act_reset: unknown interface type");
575 }
576
577 LIST_FOREACH(nbr, &iface->nbr_list, entry) {
578 if (nbr_fsm(nbr, NBR_EVT_KILL_NBR)) {
579 log_debug("if_act_reset: error killing neighbor %s",
580 inet_ntoa(nbr->id));
581 }
582 }
583
584 iface->dr = NULL;
585 iface->bdr = NULL;
586
587 ls_ack_list_clr(iface);
588 stop_ls_ack_tx_timer(iface);
589 if_stop_hello_timer(iface);
590 if_stop_wait_timer(iface);
591
592 /* send empty hello to tell everybody that we are going down */
593 send_hello(iface);
594
595 return (0);
596 }
597
598 struct ctl_iface *
599 if_to_ctl(struct iface *iface)
600 {
601 static struct ctl_iface ictl;
602 struct timeval tv, now, res;
603 struct nbr *nbr;
604
605 memcpy(ictl.name, iface->name, sizeof(ictl.name));
606 memcpy(&ictl.addr, &iface->addr, sizeof(ictl.addr));
607 memcpy(&ictl.mask, &iface->mask, sizeof(ictl.mask));
608 ictl.rtr_id.s_addr = ospfe_router_id();
609 memcpy(&ictl.area, &iface->area->id, sizeof(ictl.area));
610 if (iface->dr) {
611 memcpy(&ictl.dr_id, &iface->dr->id, sizeof(ictl.dr_id));
612 memcpy(&ictl.dr_addr, &iface->dr->addr, sizeof(ictl.dr_addr));
613 } else {
614 bzero(&ictl.dr_id, sizeof(ictl.dr_id));
615 bzero(&ictl.dr_addr, sizeof(ictl.dr_addr));
616 }
617 if (iface->bdr) {
618 memcpy(&ictl.bdr_id, &iface->bdr->id, sizeof(ictl.bdr_id));
619 memcpy(&ictl.bdr_addr, &iface->bdr->addr,
620 sizeof(ictl.bdr_addr));
621 } else {
622 bzero(&ictl.bdr_id, sizeof(ictl.bdr_id));
623 bzero(&ictl.bdr_addr, sizeof(ictl.bdr_addr));
624 }
625 ictl.ifindex = iface->ifindex;
626 ictl.state = iface->state;
627 ictl.mtu = iface->mtu;
628 ictl.nbr_cnt = 0;
629 ictl.adj_cnt = 0;
630 ictl.baudrate = iface->baudrate;
631 ictl.dead_interval = iface->dead_interval;
632 ictl.transmit_delay = iface->transmit_delay;
633 ictl.hello_interval = iface->hello_interval;
634 ictl.flags = iface->flags;
635 ictl.metric = iface->metric;
636 ictl.rxmt_interval = iface->rxmt_interval;
637 ictl.type = iface->type;
638 ictl.linkstate = iface->linkstate;
639 ictl.mediatype = iface->media_type;
640 ictl.priority = iface->priority;
641 ictl.passive = iface->passive;
642 ictl.auth_type = iface->auth_type;
643 ictl.auth_keyid = iface->auth_keyid;
644
645 gettimeofday(&now, NULL);
646 if (evtimer_pending(&iface->hello_timer, &tv)) {
647 timersub(&tv, &now, &res);
648 ictl.hello_timer = res.tv_sec;
649 } else
650 ictl.hello_timer = -1;
651
652 if (iface->state != IF_STA_DOWN) {
653 ictl.uptime = now.tv_sec - iface->uptime;
654 } else
655 ictl.uptime = 0;
656
657 LIST_FOREACH(nbr, &iface->nbr_list, entry) {
658 if (nbr == iface->self)
659 continue;
660 ictl.nbr_cnt++;
661 if (nbr->state & NBR_STA_ADJFORM)
662 ictl.adj_cnt++;
663 }
664
665 return (&ictl);
666 }
667
668 /* misc */
669 int
670 if_set_recvif(int fd, int enable)
671 {
672 if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &enable,
673 sizeof(enable)) < 0) {
674 log_warn("if_set_recvif: error setting IP_RECVIF");
675 return (-1);
676 }
677 return (0);
678 }
679
680 void
681 if_set_recvbuf(int fd)
682 {
683 int bsize;
684
685 bsize = 65535;
686 while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize,
687 sizeof(bsize)) == -1)
688 bsize /= 2;
689 }
690
691 /*
692 * only one JOIN or DROP per interface and address is allowed so we need
693 * to keep track of what is added and removed.
694 */
695 struct if_group_count {
696 LIST_ENTRY(if_group_count) entry;
697 struct in_addr addr;
698 unsigned int ifindex;
699 int count;
700 };
701
702 LIST_HEAD(,if_group_count) ifglist = LIST_HEAD_INITIALIZER(ifglist);
703
704 int
705 if_join_group(struct iface *iface, struct in_addr *addr)
706 {
707 struct ip_mreq mreq;
708 struct if_group_count *ifg;
709
710 switch (iface->type) {
711 case IF_TYPE_POINTOPOINT:
712 case IF_TYPE_BROADCAST:
713 LIST_FOREACH(ifg, &ifglist, entry)
714 if (iface->ifindex == ifg->ifindex &&
715 addr->s_addr == ifg->addr.s_addr)
716 break;
717 if (ifg == NULL) {
718 if ((ifg = calloc(1, sizeof(*ifg))) == NULL)
719 fatal("if_join_group");
720 ifg->addr.s_addr = addr->s_addr;
721 ifg->ifindex = iface->ifindex;
722 LIST_INSERT_HEAD(&ifglist, ifg, entry);
723 }
724
725 if (ifg->count++ != 0)
726 /* already joined */
727 return (0);
728
729 mreq.imr_multiaddr.s_addr = addr->s_addr;
730 mreq.imr_interface.s_addr = iface->addr.s_addr;
731
732 if (setsockopt(iface->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
733 (void *)&mreq, sizeof(mreq)) < 0) {
734 log_warn("if_join_group: error IP_ADD_MEMBERSHIP, "
735 "interface %s address %s", iface->name,
736 inet_ntoa(*addr));
737 return (-1);
738 }
739 break;
740 case IF_TYPE_POINTOMULTIPOINT:
741 case IF_TYPE_VIRTUALLINK:
742 case IF_TYPE_NBMA:
743 log_debug("if_join_group: type %s not supported, interface %s",
744 if_type_name(iface->type), iface->name);
745 return (-1);
746 default:
747 fatalx("if_join_group: unknown interface type");
748 }
749
750 return (0);
751 }
752
753 int
754 if_leave_group(struct iface *iface, struct in_addr *addr)
755 {
756 struct ip_mreq mreq;
757 struct if_group_count *ifg;
758
759 switch (iface->type) {
760 case IF_TYPE_POINTOPOINT:
761 case IF_TYPE_BROADCAST:
762 LIST_FOREACH(ifg, &ifglist, entry)
763 if (iface->ifindex == ifg->ifindex &&
764 addr->s_addr == ifg->addr.s_addr)
765 break;
766
767 /* if interface is not found just try to drop membership */
768 if (ifg && --ifg->count != 0)
769 /* others still joined */
770 return (0);
771
772 mreq.imr_multiaddr.s_addr = addr->s_addr;
773 mreq.imr_interface.s_addr = iface->addr.s_addr;
774
775 if (setsockopt(iface->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
776 (void *)&mreq, sizeof(mreq)) < 0) {
777 log_warn("if_leave_group: error IP_DROP_MEMBERSHIP, "
778 "interface %s address %s", iface->name,
779 inet_ntoa(*addr));
780 return (-1);
781 }
782
783 if (ifg) {
784 LIST_REMOVE(ifg, entry);
785 free(ifg);
786 }
787 break;
788 case IF_TYPE_POINTOMULTIPOINT:
789 case IF_TYPE_VIRTUALLINK:
790 case IF_TYPE_NBMA:
791 log_debug("if_leave_group: type %s not supported, interface %s",
792 if_type_name(iface->type), iface->name);
793 return (-1);
794 default:
795 fatalx("if_leave_group: unknown interface type");
796 }
797
798 return (0);
799 }
800
801 int
802 if_set_mcast(struct iface *iface)
803 {
804 switch (iface->type) {
805 case IF_TYPE_POINTOPOINT:
806 case IF_TYPE_BROADCAST:
807 if (setsockopt(iface->fd, IPPROTO_IP, IP_MULTICAST_IF,
808 &iface->addr.s_addr, sizeof(iface->addr.s_addr)) < 0) {
809 log_debug("if_set_mcast: error setting "
810 "IP_MULTICAST_IF, interface %s", iface->name);
811 return (-1);
812 }
813 break;
814 case IF_TYPE_POINTOMULTIPOINT:
815 case IF_TYPE_VIRTUALLINK:
816 case IF_TYPE_NBMA:
817 log_debug("if_set_mcast: type %s not supported, interface %s",
818 if_type_name(iface->type), iface->name);
819 return (-1);
820 default:
821 fatalx("if_set_mcast: unknown interface type");
822 }
823
824 return (0);
825 }
826
827 int
828 if_set_mcast_loop(int fd)
829 {
830 u_int8_t loop = 0;
831
832 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
833 (char *)&loop, sizeof(loop)) < 0) {
834 log_warn("if_set_mcast_loop: error setting IP_MULTICAST_LOOP");
835 return (-1);
836 }
837
838 return (0);
839 }
840
841 int
842 if_set_ip_hdrincl(int fd)
843 {
844 int hincl = 1;
845
846 if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof(hincl)) < 0) {
847 log_warn("if_set_ip_hdrincl: error setting IP_HDRINCL");
848 return (-1);
849 }
850
851 return (0);
852 }