]> git.proxmox.com Git - mirror_frr.git/blob - ospf6d/ospf6_dbex.c
Start of new ospf6d merge from Zebra.
[mirror_frr.git] / ospf6d / ospf6_dbex.c
1 /*
2 * Copyright (C) 1999 Yasuhiro Ohara
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Zebra; see the file COPYING. If not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 */
21
22 #include "ospf6d.h"
23
24 /* check validity and put lsa in reqestlist if needed. */
25 /* returns -1 if SeqNumMismatch required. */
26 int
27 ospf6_dbex_check_dbdesc_lsa_header (struct ospf6_lsa_header *lsa_header,
28 struct ospf6_neighbor *from)
29 {
30 struct ospf6_lsa *received = NULL;
31 struct ospf6_lsa *have = NULL;
32
33 received = ospf6_lsa_summary_create
34 ((struct ospf6_lsa_header__ *) lsa_header);
35
36 /* case when received is AS-External though neighbor belongs stub area */
37 if (lsa_header->type == htons (OSPF6_LSA_TYPE_AS_EXTERNAL) &&
38 ospf6_area_is_stub (from->ospf6_interface->area))
39 {
40 zlog_err ("DbDesc %s receive from %s", from->str, received->str);
41 zlog_err (" E-bit mismatch: %s", received->str);
42 ospf6_lsa_delete (received);
43 return -1;
44 }
45
46 /* if already have newer database copy, check next LSA */
47 have = ospf6_lsdb_lookup (lsa_header->type, lsa_header->ls_id,
48 lsa_header->advrtr,
49 ospf6_lsa_get_scope (lsa_header->type,
50 from->ospf6_interface));
51 if (! have)
52 {
53 /* if we don't have database copy, add request */
54 if (IS_OSPF6_DUMP_DBEX)
55 zlog_info ("Have no database copy, Request");
56 ospf6_neighbor_request_add (received, from);
57 }
58 else if (have)
59 {
60 /* if database copy is less recent, add request */
61 if (ospf6_lsa_check_recent (received, have) < 0)
62 {
63 if (IS_OSPF6_DUMP_DBEX)
64 zlog_info ("Database copy less recent, Request");
65 ospf6_neighbor_request_add (received, from);
66 }
67 }
68
69 return 0;
70 }
71
72 /* Direct acknowledgement */
73 static void
74 ospf6_dbex_acknowledge_direct (struct ospf6_lsa *lsa,
75 struct ospf6_neighbor *o6n)
76 {
77 struct iovec directack[MAXIOVLIST];
78 assert (lsa);
79
80 if (IS_OSPF6_DUMP_DBEX)
81 zlog_info ("DBEX: [%s:%s] direct ack %s ",
82 o6n->str, o6n->ospf6_interface->interface->name,
83 lsa->str);
84
85 /* clear pointers to fragments of packet for direct acknowledgement */
86 iov_clear (directack, MAXIOVLIST);
87
88 /* set pointer of LSA to send */
89 OSPF6_MESSAGE_ATTACH (directack, lsa->header,
90 sizeof (struct ospf6_lsa_header));
91
92 /* age update and add InfTransDelay */
93 ospf6_lsa_age_update_to_send (lsa, o6n->ospf6_interface->transdelay);
94
95 /* send unicast packet to neighbor's ipaddress */
96 ospf6_message_send (OSPF6_MESSAGE_TYPE_LSACK, directack, &o6n->hisaddr,
97 o6n->ospf6_interface->if_id);
98 }
99
100 /* Delayed acknowledgement */
101 void
102 ospf6_dbex_acknowledge_delayed (struct ospf6_lsa *lsa,
103 struct ospf6_interface *o6i)
104 {
105 assert (o6i);
106
107 if (IS_OSPF6_DUMP_DBEX)
108 zlog_info ("DBEX: [%s] delayed ack %s", o6i->interface->name, lsa->str);
109
110 /* attach delayed acknowledge list */
111 ospf6_lsa_age_current (lsa);
112 ospf6_interface_delayed_ack_add (lsa, o6i);
113
114 /* if not yet, schedule delayed acknowledge RxmtInterval later.
115 timers should be *less than* RxmtInterval
116 or needless retrans will ensue */
117 if (o6i->thread_send_lsack_delayed == NULL)
118 o6i->thread_send_lsack_delayed
119 = thread_add_timer (master, ospf6_send_lsack_delayed,
120 o6i, o6i->rxmt_interval - 1);
121
122 return;
123 }
124
125 /* RFC2328 section 13 (4):
126 if MaxAge LSA and if we have no instance, and no neighbor
127 is in states Exchange or Loading */
128 /* returns 1 if match this case, else returns 0 */
129 static int
130 ospf6_dbex_is_maxage_to_be_dropped (struct ospf6_lsa *received,
131 struct ospf6_neighbor *from)
132 {
133 int count;
134
135 if (! IS_LSA_MAXAGE (received))
136 return 0;
137
138 if (ospf6_lsdb_lookup (received->header->type, received->header->id,
139 received->header->adv_router,
140 ospf6_lsa_get_scope (received->header->type,
141 from->ospf6_interface)))
142 return 0;
143
144 if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (ntohs (received->header->type)))
145 {
146 count = 0;
147 (*from->ospf6_interface->foreach_nei)
148 (from->ospf6_interface, &count, NBS_EXCHANGE, ospf6_count_state);
149 (*from->ospf6_interface->foreach_nei)
150 (from->ospf6_interface, &count, NBS_LOADING, ospf6_count_state);
151 if (count)
152 return 0;
153 }
154 else if (OSPF6_LSA_IS_SCOPE_AREA (ntohs (received->header->type)))
155 {
156 count = 0;
157 (*from->ospf6_interface->area->foreach_nei)
158 (from->ospf6_interface->area, &count, NBS_EXCHANGE, ospf6_count_state);
159 (*from->ospf6_interface->area->foreach_nei)
160 (from->ospf6_interface->area, &count, NBS_LOADING, ospf6_count_state);
161 if (count)
162 return 0;
163 }
164 else if (OSPF6_LSA_IS_SCOPE_AS (ntohs (received->header->type)))
165 {
166 count = 0;
167 (*from->ospf6_interface->area->ospf6->foreach_nei)
168 (from->ospf6_interface->area->ospf6, &count, NBS_EXCHANGE,
169 ospf6_count_state);
170 (*from->ospf6_interface->area->ospf6->foreach_nei)
171 (from->ospf6_interface->area->ospf6, &count, NBS_LOADING,
172 ospf6_count_state);
173 if (count)
174 return 0;
175 }
176
177 return 1;
178 }
179
180 static void
181 ospf6_dbex_remove_retrans (void *arg, int val, void *obj)
182 {
183 struct ospf6_lsa *rem;
184 struct ospf6_neighbor *nei = (struct ospf6_neighbor *) obj;
185 struct ospf6_lsa *lsa = (struct ospf6_lsa *) arg;
186
187 rem = ospf6_lsdb_lookup_lsdb (lsa->header->type, lsa->header->id,
188 lsa->header->adv_router, nei->retrans_list);
189 if (rem)
190 {
191 ospf6_neighbor_retrans_remove (rem, nei);
192 ospf6_maxage_remover ();
193 }
194 }
195
196 void
197 ospf6_dbex_remove_from_all_retrans_list (struct ospf6_lsa *lsa)
198 {
199 struct ospf6_interface *o6i;
200 struct ospf6_area *o6a;
201
202 if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (htons (lsa->header->type)))
203 {
204 o6i = lsa->scope;
205 (*o6i->foreach_nei) (o6i, lsa, 0, ospf6_dbex_remove_retrans);
206 }
207 else if (OSPF6_LSA_IS_SCOPE_AREA (htons (lsa->header->type)))
208 {
209 o6a = lsa->scope;
210 (*o6a->foreach_nei) (o6a, lsa, 0, ospf6_dbex_remove_retrans);
211 }
212 else if (OSPF6_LSA_IS_SCOPE_AS (htons (lsa->header->type)))
213 {
214 (*ospf6->foreach_nei) (ospf6, lsa, 0, ospf6_dbex_remove_retrans);
215 }
216 }
217
218 /* RFC2328 section 13 */
219 void
220 ospf6_dbex_receive_lsa (struct ospf6_lsa_header *lsa_header,
221 struct ospf6_neighbor *from)
222 {
223 struct ospf6_lsa *received, *have, *rem;
224 struct timeval now;
225 int ismore_recent, acktype;
226 unsigned short cksum;
227 struct ospf6_lsa_slot *slot;
228
229 received = have = (struct ospf6_lsa *)NULL;
230 ismore_recent = -1;
231 recent_reason = "no instance";
232
233 zlog_info ("Receive LSA (header -> %p)", lsa_header);
234
235 /* make lsa structure for received lsa */
236 received = ospf6_lsa_create (lsa_header);
237
238 /* set LSA scope */
239 if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (htons (lsa_header->type)))
240 received->scope = from->ospf6_interface;
241 else if (OSPF6_LSA_IS_SCOPE_AREA (htons (lsa_header->type)))
242 received->scope = from->ospf6_interface->area;
243 else if (OSPF6_LSA_IS_SCOPE_AS (htons (lsa_header->type)))
244 received->scope = from->ospf6_interface->area->ospf6;
245
246 /* (1) LSA Checksum */
247 cksum = ntohs (lsa_header->checksum);
248 if (ntohs (ospf6_lsa_checksum (lsa_header)) != cksum)
249 {
250 if (IS_OSPF6_DUMP_DBEX)
251 zlog_info ("DBEX: received %s from %s%%%s"
252 ": wrong checksum, drop",
253 received->str, from->str,
254 from->ospf6_interface->interface->name);
255 ospf6_lsa_delete (received);
256 return;
257 }
258
259 /* (3) Ebit Missmatch: AS-External-LSA */
260 if (lsa_header->type == htons (OSPF6_LSA_TYPE_AS_EXTERNAL) &&
261 ospf6_area_is_stub (from->ospf6_interface->area))
262 {
263 if (IS_OSPF6_DUMP_DBEX)
264 zlog_info ("DBEX: received %s from %s%%%s"
265 ": E-bit mismatch, drop",
266 received->str, from->str,
267 from->ospf6_interface->interface->name);
268 ospf6_lsa_delete (received);
269 return;
270 }
271
272 /* (4) if MaxAge LSA and if we have no instance, and no neighbor
273 is in states Exchange or Loading */
274 if (ospf6_dbex_is_maxage_to_be_dropped (received, from))
275 {
276 /* log */
277 if (IS_OSPF6_DUMP_DBEX)
278 zlog_info ("DBEX: received %s from %s%%%s"
279 ": MaxAge, no instance, no neighbor exchange, drop",
280 received->str, from->str,
281 from->ospf6_interface->interface->name);
282
283 /* a) Acknowledge back to neighbor (13.5) */
284 /* Direct Acknowledgement */
285 ospf6_dbex_acknowledge_direct (received, from);
286
287 /* b) Discard */
288 ospf6_lsa_delete (received);
289 return;
290 }
291
292 /* (5) */
293 /* lookup the same database copy in lsdb */
294 have = ospf6_lsdb_lookup (lsa_header->type, lsa_header->ls_id,
295 lsa_header->advrtr,
296 ospf6_lsa_get_scope (lsa_header->type,
297 from->ospf6_interface));
298 if (have)
299 {
300 ismore_recent = ospf6_lsa_check_recent (received, have);
301 if (ntohl (received->header->seqnum) == ntohl (have->header->seqnum))
302 SET_FLAG (received->flag, OSPF6_LSA_FLAG_DUPLICATE);
303 }
304
305 /* if no database copy or received is more recent */
306 if (!have || ismore_recent < 0)
307 {
308 /* in case we have no database copy */
309 ismore_recent = -1;
310
311 /* (a) MinLSArrival check */
312 gettimeofday (&now, (struct timezone *)NULL);
313 if (have && SEC_TVDIFF (&now, &have->installed) < OSPF6_MIN_LS_ARRIVAL)
314 {
315 //if (IS_OSPF6_DUMP_DBEX)
316 zlog_info ("DBEX: Receive new LSA from %s: %s seq: %#x age: %d "
317 "within MinLSArrival, drop: %ld.%06ld",
318 from->str, received->str,
319 ntohl (received->header->seqnum),
320 ntohs (received->header->age),
321 now.tv_sec, now.tv_usec);
322
323 /* this will do free this lsa */
324 ospf6_lsa_delete (received);
325 return; /* examin next lsa */
326 }
327
328 //if (IS_OSPF6_DUMP_DBEX)
329 zlog_info ("DBEX: Receive new LSA from %s: %s seq: %#x age: %d: "
330 "%ld.%06ld",
331 from->str, received->str,
332 ntohl (received->header->seqnum),
333 ntohs (received->header->age),
334 now.tv_sec, now.tv_usec);
335
336 /* (b) immediately flood */
337 ospf6_dbex_flood (received, from);
338
339 #if 0
340 /* Because New LSDB do not permit two LSA having the same identifier
341 exist in a LSDB list, above ospf6_dbex_flood() will remove
342 the old instance automatically. thus bellow is not needed. */
343 /* (c) remove database copy from all neighbor's retranslist */
344 if (have)
345 ospf6_dbex_remove_from_all_retrans_list (have);
346 #endif
347
348 /* (d), installing lsdb, which may cause routing
349 table calculation (replacing database copy) */
350 ospf6_lsdb_install (received);
351
352 /* (e) possibly acknowledge */
353 acktype = ack_type (received, ismore_recent, from);
354 if (acktype == DIRECT_ACK)
355 {
356 if (IS_OSPF6_DUMP_DBEX)
357 zlog_info ("DBEX: Direct Ack to %s", from->str);
358 ospf6_dbex_acknowledge_direct (received, from);
359 }
360 else if (acktype == DELAYED_ACK)
361 {
362 if (IS_OSPF6_DUMP_DBEX)
363 zlog_info ("DBEX: Delayed Ack to %s", from->str);
364 ospf6_dbex_acknowledge_delayed (received, from->ospf6_interface);
365 }
366 else
367 {
368 if (IS_OSPF6_DUMP_DBEX)
369 zlog_info ("DBEX: No Ack to %s", from->str);
370 }
371
372 /* (f) */
373 /* Self Originated LSA, section 13.4 */
374 if (received->lsa_hdr->lsh_advrtr == ospf6->router_id
375 && (! have || ismore_recent < 0))
376 {
377 /* we're going to make new lsa or to flush this LSA. */
378 if (IS_OSPF6_DUMP_DBEX)
379 zlog_info ("DBEX: Self-originated LSA %s from %s:%s",
380 received->str, from->str,
381 from->ospf6_interface->interface->name);
382 if (IS_OSPF6_DUMP_DBEX)
383 zlog_info ("DBEX: %s: Make new one/Flush", received->str);
384
385 SET_FLAG (received->flag, OSPF6_LSA_FLAG_REFRESH);
386 slot = ospf6_lsa_slot_get (received->header->type);
387 if (slot && slot->func_refresh)
388 {
389 (*slot->func_refresh) (received);
390 return;
391 }
392
393 zlog_warn ("Can't Refresh LSA: Unknown type: %#x, Flush",
394 ntohs (received->header->type));
395 ospf6_lsa_premature_aging (received);
396 return;
397 }
398 }
399 else if (ospf6_lsdb_lookup_lsdb (received->header->type,
400 received->header->id,
401 received->header->adv_router,
402 from->request_list))
403 /* (6) if there is instance on sending neighbor's request list */
404 {
405 /* if no database copy, should go above state (5) */
406 assert (have);
407
408 zlog_warn ("DBEX: [%s:%s] received LSA %s is not newer,"
409 " and is on his requestlist: Generate BadLSReq",
410 from->str, from->ospf6_interface->interface->name,
411 received->str);
412
413 /* BadLSReq */
414 thread_add_event (master, bad_lsreq, from, 0);
415
416 ospf6_lsa_delete (received);
417 }
418 else if (ismore_recent == 0) /* (7) if neither is more recent */
419 {
420 /* (a) if on retranslist, Treat this LSA as an Ack: Implied Ack */
421 rem = ospf6_lsdb_lookup_lsdb (received->header->type,
422 received->header->id,
423 received->header->adv_router,
424 from->retrans_list);
425 if (rem)
426 {
427 if (IS_OSPF6_DUMP_DBEX)
428 zlog_info ("DBEX: Implied Ack from %s, (remove retrans)",
429 from->str);
430 SET_FLAG (received->flag, OSPF6_LSA_FLAG_IMPLIEDACK);
431 ospf6_neighbor_retrans_remove (rem, from);
432 }
433
434 /* (b) possibly acknowledge */
435 acktype = ack_type (received, ismore_recent, from);
436 if (acktype == DIRECT_ACK)
437 {
438 if (IS_OSPF6_DUMP_DBEX)
439 zlog_info ("DBEX: Direct Ack to %s", from->str);
440 ospf6_dbex_acknowledge_direct (received, from);
441 }
442 else if (acktype == DELAYED_ACK)
443 {
444 if (IS_OSPF6_DUMP_DBEX)
445 zlog_info ("DBEX: Delayed Ack to %s", from->str);
446 ospf6_dbex_acknowledge_delayed (received, from->ospf6_interface);
447 }
448 else
449 {
450 if (IS_OSPF6_DUMP_DBEX)
451 zlog_info ("DBEX: No Ack to %s", from->str);
452 }
453 ospf6_lsa_delete (received);
454 }
455 else /* (8) previous database copy is more recent */
456 {
457 /* If Seqnumber Wrapping, simply discard
458 Otherwise, Send database copy of this LSA to this neighbor */
459 if (! IS_LSA_MAXAGE (received) ||
460 received->lsa_hdr->lsh_seqnum != MAX_SEQUENCE_NUMBER)
461 {
462 if (IS_OSPF6_DUMP_DBEX)
463 zlog_info ("DBEX: database is more recent: send back to %s",
464 from->str);
465 ospf6_send_lsupdate_direct (have, from);
466 }
467 ospf6_lsa_delete (received);
468 }
469 }
470
471 /* RFC2328: Table 19: Sending link state acknowledgements. */
472 int
473 ack_type (struct ospf6_lsa *newp, int ismore_recent,
474 struct ospf6_neighbor *from)
475 {
476 struct ospf6_interface *ospf6_interface;
477 struct ospf6_lsa *have;
478 int count;
479
480 assert (from && from->ospf6_interface);
481 ospf6_interface = from->ospf6_interface;
482
483 if (CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_FLOODBACK))
484 return NO_ACK;
485
486 if (ismore_recent < 0)
487 {
488 if (ospf6_interface->state != IFS_BDR)
489 return DELAYED_ACK;
490
491 if (ospf6_interface->dr == from->router_id)
492 return DELAYED_ACK;
493 return NO_ACK;
494 }
495
496 if (CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_DUPLICATE) &&
497 CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_IMPLIEDACK))
498 {
499 if (ospf6_interface->state != IFS_BDR)
500 return NO_ACK;
501
502 if (ospf6_interface->dr == from->router_id)
503 return DELAYED_ACK;
504
505 return NO_ACK;
506 }
507
508 if (CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_DUPLICATE) &&
509 ! CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_IMPLIEDACK))
510 return DIRECT_ACK;
511
512 have = ospf6_lsdb_lookup (newp->header->type, newp->header->id,
513 newp->header->adv_router,
514 ospf6_lsa_get_scope (newp->header->type,
515 from->ospf6_interface));
516
517 count = 0;
518 ospf6->foreach_nei (ospf6, &count, NBS_EXCHANGE, ospf6_count_state);
519 ospf6->foreach_nei (ospf6, &count, NBS_LOADING, ospf6_count_state);
520
521 if (IS_LSA_MAXAGE (newp) && have == NULL && count == 0)
522 return DIRECT_ACK;
523
524 return NO_ACK;
525 }
526
527 static void
528 ospf6_dbex_flood_linklocal (struct ospf6_lsa *lsa, struct ospf6_interface *o6i,
529 struct ospf6_neighbor *from)
530 {
531 struct ospf6_neighbor *o6n = (struct ospf6_neighbor *) NULL;
532 int ismore_recent, addretrans = 0;
533 listnode n;
534 struct ospf6_lsa *req;
535
536 /* (1) for each neighbor */
537 for (n = listhead (o6i->neighbor_list); n; nextnode (n))
538 {
539 o6n = (struct ospf6_neighbor *) getdata (n);
540
541 /* (a) */
542 if (o6n->state < NBS_EXCHANGE)
543 continue; /* examin next neighbor */
544
545 /* (b) */
546 if (o6n->state == NBS_EXCHANGE
547 || o6n->state == NBS_LOADING)
548 {
549 req = ospf6_lsdb_lookup_lsdb (lsa->header->type,
550 lsa->header->id,
551 lsa->header->adv_router,
552 o6n->request_list);
553 if (req)
554 {
555 ismore_recent = ospf6_lsa_check_recent (lsa, req);
556 if (ismore_recent > 0)
557 {
558 continue; /* examin next neighbor */
559 }
560 else if (ismore_recent == 0)
561 {
562 ospf6_neighbor_request_remove (req, o6n);
563 continue; /* examin next neighbor */
564 }
565 else /* ismore_recent < 0 (the new LSA is more recent) */
566 {
567 ospf6_neighbor_request_remove (req, o6n);
568 }
569 }
570 }
571
572 /* (c) */
573 if (from && from->router_id == o6n->router_id)
574 continue; /* examin next neighbor */
575
576 /* (d) add retranslist */
577 if (IS_OSPF6_DUMP_DBEX)
578 zlog_info ("DBEX: schedule flooding [%s:%s]: %s",
579 o6n->str, o6n->ospf6_interface->interface->name,
580 lsa->str);
581 ospf6_neighbor_retrans_add (lsa, o6n);
582 addretrans++;
583 if (o6n->send_update == (struct thread *) NULL)
584 o6n->send_update =
585 thread_add_timer (master, ospf6_send_lsupdate_rxmt, o6n,
586 o6n->ospf6_interface->rxmt_interval);
587 }
588
589 /* (2) */
590 if (addretrans == 0)
591 return; /* examin next interface */
592
593 if (from && from->ospf6_interface == o6i)
594 {
595 if (IS_OSPF6_DUMP_DBEX)
596 zlog_info ("DBEX: flood back %s to %s",
597 lsa->str, o6i->interface->name);
598 /* note occurence of floodback */
599 SET_FLAG (lsa->flag, OSPF6_LSA_FLAG_FLOODBACK);
600 }
601
602 /* (3) */
603 if (from && from->ospf6_interface == o6i)
604 {
605 /* if from DR or BDR, don't need to flood this interface */
606 if (from->router_id == from->ospf6_interface->dr ||
607 from->router_id == from->ospf6_interface->bdr)
608 return; /* examin next interface */
609 }
610
611 /* (4) if I'm BDR, DR will flood this interface */
612 if (from && from->ospf6_interface == o6i
613 && o6i->state == IFS_BDR)
614 return; /* examin next interface */
615
616 if (IS_OSPF6_DUMP_DBEX)
617 zlog_info ("Flood to interface %s", o6i->interface->name);
618
619 /* (5) send LinkState Update */
620 ospf6_send_lsupdate_flood (lsa, o6i);
621
622 return;
623 }
624
625 /* RFC2328 section 13.3 */
626 static void
627 ospf6_dbex_flood_area (struct ospf6_lsa *lsa, struct ospf6_area *area,
628 struct ospf6_neighbor *from)
629 {
630 listnode n;
631 struct ospf6_interface *ospf6_interface;
632
633 assert (lsa && lsa->lsa_hdr && area);
634
635 /* for each eligible ospf_ifs */
636 for (n = listhead (area->if_list); n; nextnode (n))
637 {
638 ospf6_interface = (struct ospf6_interface *) getdata (n);
639 ospf6_dbex_flood_linklocal (lsa, ospf6_interface, from);
640 }
641 }
642
643 static void
644 ospf6_dbex_flood_as (struct ospf6_lsa *lsa, struct ospf6 *ospf6,
645 struct ospf6_neighbor *from)
646 {
647 listnode n;
648 struct ospf6_area *o6a;
649
650 assert (lsa && lsa->lsa_hdr && ospf6);
651
652 /* for each attached area */
653 for (n = listhead (ospf6->area_list); n; nextnode (n))
654 {
655 o6a = (struct ospf6_area *) getdata (n);
656 ospf6_dbex_flood_area (lsa, o6a, from);
657 }
658 }
659
660 /* flood ospf6_lsa within appropriate scope */
661 void
662 ospf6_dbex_flood (struct ospf6_lsa *lsa, struct ospf6_neighbor *from)
663 {
664 struct ospf6_area *o6a;
665 struct ospf6_interface *o6i;
666 struct ospf6 *o6;
667 struct ospf6_lsa_header *lsa_header;
668
669 lsa_header = (struct ospf6_lsa_header *) lsa->lsa_hdr;
670
671 if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (ntohs (lsa_header->type)))
672 {
673 o6i = (struct ospf6_interface *) lsa->scope;
674 assert (o6i);
675
676 if (IS_OSPF6_DUMP_DBEX)
677 zlog_info ("Flood Linklocal: %s", o6i->interface->name);
678 ospf6_dbex_flood_linklocal (lsa, o6i, from);
679 }
680 else if (OSPF6_LSA_IS_SCOPE_AREA (ntohs (lsa_header->type)))
681 {
682 o6a = (struct ospf6_area *) lsa->scope;
683 assert (o6a);
684
685 if (IS_OSPF6_DUMP_DBEX)
686 zlog_info ("Flood Area: %s", o6a->str);
687 ospf6_dbex_flood_area (lsa, o6a, from);
688 }
689 else if (OSPF6_LSA_IS_SCOPE_AS (ntohs (lsa_header->type)))
690 {
691 o6 = (struct ospf6 *) lsa->scope;
692 assert (o6);
693
694 if (IS_OSPF6_DUMP_DBEX)
695 zlog_info ("Flood AS");
696 ospf6_dbex_flood_as (lsa, o6, from);
697 }
698 else
699 {
700 zlog_warn ("Can't Flood %s: scope unknown", lsa->str);
701 }
702 }
703
704