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. */
26int
27ospf6_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 */
73static void
74ospf6_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 */
101void
102ospf6_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 */
129static int
130ospf6_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
180static void
181ospf6_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
196void
197ospf6_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 */
219void
220ospf6_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  /* make lsa structure for received lsa */
234  received = ospf6_lsa_create (lsa_header);
235
236  if (IS_OSPF6_DUMP_DBEX)
237    zlog_info ("Receive %s from %s", received->str, from->str);
238
239  /* set LSA scope */
240  if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (htons (lsa_header->type)))
241    received->scope = from->ospf6_interface;
242  else if (OSPF6_LSA_IS_SCOPE_AREA (htons (lsa_header->type)))
243    received->scope = from->ospf6_interface->area;
244  else if (OSPF6_LSA_IS_SCOPE_AS (htons (lsa_header->type)))
245    received->scope = from->ospf6_interface->area->ospf6;
246
247  /* (1) LSA Checksum */
248  cksum = ntohs (lsa_header->checksum);
249  if (ntohs (ospf6_lsa_checksum (lsa_header)) != cksum)
250    {
251      zlog_warn ("DBEX: LSA cksum wrong: %s checksum %#hx should be %#hx",
252                 received->str, cksum, ntohs (ospf6_lsa_checksum (lsa_header)));
253      ospf6_lsa_delete (received);
254      return;
255    }
256
257#if 0
258  /* (2) warn if unknown */
259  if (! ospf6_lsa_is_known_type (lsa_header))
260    zlog_warn ("[%s:%s] receive LSA unknown: %#x",
261               from->str, from->ospf6_interface->interface->name,
262               ntohs (lsa_header->type));
263#endif /*0*/
264
265  /* (3) Ebit Missmatch: AS-External-LSA */
266  if (lsa_header->type == htons (OSPF6_LSA_TYPE_AS_EXTERNAL) &&
267      ospf6_area_is_stub (from->ospf6_interface->area))
268    {
269      zlog_err ("DBEX: [%s:%s] receive LSA E-bit mismatch: %s",
270                 from->str, from->ospf6_interface->interface->name,
271                 received->str);
272      ospf6_lsa_delete (received);
273      return;
274    }
275
276  /* (4) if MaxAge LSA and if we have no instance, and no neighbor
277         is in states Exchange or Loading */
278  if (ospf6_dbex_is_maxage_to_be_dropped (received, from))
279    {
280      /* log */
281      if (IS_OSPF6_DUMP_DBEX)
282        zlog_info ("Drop MaxAge LSA: no instance, no neighbor "
283                   "exchanging DB: %s", received->str);
284
285      /* a) Acknowledge back to neighbor (13.5) */
286        /* Direct Acknowledgement */
287      ospf6_dbex_acknowledge_direct (received, from);
288
289      /* b) Discard */
290      ospf6_lsa_delete (received);
291      return;
292    }
293
294  /* (5) */
295  /* lookup the same database copy in lsdb */
296  have = ospf6_lsdb_lookup (lsa_header->type, lsa_header->ls_id,
297                            lsa_header->advrtr,
298                            ospf6_lsa_get_scope (lsa_header->type,
299                                                 from->ospf6_interface));
300  if (have)
301    {
302      ismore_recent = ospf6_lsa_check_recent (received, have);
303      if (ntohl (received->header->seqnum) == ntohl (have->header->seqnum))
304        SET_FLAG (received->flag, OSPF6_LSA_FLAG_DUPLICATE);
305    }
306
307  /* if no database copy or received is more recent */
308  if (!have || ismore_recent < 0)
309    {
310      /* in case we have no database copy */
311      ismore_recent = -1;
312
313      /* (a) MinLSArrival check */
314      gettimeofday (&now, (struct timezone *)NULL);
315      if (have && now.tv_sec - have->installed.tv_sec <= OSPF6_MIN_LS_ARRIVAL)
316        {
317          if (IS_OSPF6_DUMP_DBEX)
318            zlog_info ("DBEX: [%s:%s] received LSA too soon: %s",
319                       from->str, from->ospf6_interface->interface->name,
320                       received->str);
321
322          /* this will do free this lsa */
323          ospf6_lsa_delete (received);
324          return;   /* examin next lsa */
325        }
326
327      /* (b) immediately flood */
328      ospf6_dbex_flood (received, from);
329
330#if 0
331      /* Because New LSDB do not permit two LSA having the same identifier
332         exist in a LSDB list, above ospf6_dbex_flood() will remove
333         the old instance automatically. thus bellow is not needed. */
334      /* (c) remove database copy from all neighbor's retranslist */
335      if (have)
336        ospf6_dbex_remove_from_all_retrans_list (have);
337#endif
338
339      /* (d), installing lsdb, which may cause routing
340              table calculation (replacing database copy) */
341      ospf6_lsdb_install (received);
342
343      /* (e) possibly acknowledge */
344      acktype = ack_type (received, ismore_recent, from);
345      if (acktype == DIRECT_ACK)
346        {
347          ospf6_dbex_acknowledge_direct (received, from);
348        }
349      else if (acktype == DELAYED_ACK)
350        {
351          ospf6_dbex_acknowledge_delayed (received, from->ospf6_interface);
352        }
353      else
354        {
355          if (IS_OSPF6_DUMP_DBEX)
356            zlog_info ("DBEX: [%s:%s] don't ack %s",
357                       from->str, from->ospf6_interface->interface->name,
358                       received->str);
359        }
360
361      /* (f) */
362      /* Self Originated LSA, section 13.4 */
363      if (received->lsa_hdr->lsh_advrtr == ospf6->router_id
364          && have && ismore_recent < 0)
365        {
366          /* we're going to make new lsa or to flush this LSA. */
367          if (IS_OSPF6_DUMP_DBEX)
368            zlog_info ("DBEX: Self-originated LSA %s from %s:%s",
369                       received->str, from->str,
370                       from->ospf6_interface->interface->name);
371          if (IS_OSPF6_DUMP_DBEX)
372            zlog_info ("DBEX: %s: Make new one/Flush", received->str);
373
374          SET_FLAG (received->flag, OSPF6_LSA_FLAG_REFRESH);
375          slot = ospf6_lsa_slot_get (received->header->type);
376          if (slot && slot->func_refresh)
377            {
378              (*slot->func_refresh) (received);
379              return;
380            }
381
382          zlog_warn ("Can't Refresh LSA: Unknown type: %#x, Flush",
383                     ntohs (received->header->type));
384          ospf6_lsa_premature_aging (received);
385          return;
386        }
387    }
388  else if (ospf6_lsdb_lookup_lsdb (received->header->type,
389                                   received->header->id,
390                                   received->header->adv_router,
391                                   from->request_list))
392    /* (6) if there is instance on sending neighbor's request list */
393    {
394      /* if no database copy, should go above state (5) */
395      assert (have);
396
397      zlog_warn ("DBEX: [%s:%s] received LSA %s is not newer,"
398                 " and is on his requestlist: Generate BadLSReq",
399                 from->str, from->ospf6_interface->interface->name,
400                 received->str);
401
402      /* BadLSReq */
403      thread_add_event (master, bad_lsreq, from, 0);
404
405      ospf6_lsa_delete (received);
406    }
407  else if (ismore_recent == 0) /* (7) if neither is more recent */
408    {
409      /* (a) if on retranslist, Treat this LSA as an Ack: Implied Ack */
410      rem = ospf6_lsdb_lookup_lsdb (received->header->type,
411                                    received->header->id,
412                                    received->header->adv_router,
413                                    from->retrans_list);
414      if (rem)
415        {
416          SET_FLAG (received->flag, OSPF6_LSA_FLAG_IMPLIEDACK);
417          ospf6_neighbor_retrans_remove (rem, from);
418        }
419
420      /* (b) possibly acknowledge */
421      acktype = ack_type (received, ismore_recent, from);
422      if (acktype == DIRECT_ACK)
423        {
424          ospf6_dbex_acknowledge_direct (received, from);
425        }
426      else if (acktype == DELAYED_ACK)
427        {
428          ospf6_dbex_acknowledge_delayed (received, from->ospf6_interface);
429        }
430      else
431        {
432          if (IS_OSPF6_DUMP_DBEX)
433            zlog_info ("DBEX: [%s:%s] will no ack %s",
434                       from->str, from->ospf6_interface->interface->name,
435                       received->str);
436        }
437      ospf6_lsa_delete (received);
438    }
439  else /* (8) previous database copy is more recent */
440    {
441      /* If Seqnumber Wrapping, simply discard
442         Otherwise, Send database copy of this LSA to this neighbor */
443      if (! IS_LSA_MAXAGE (received) ||
444          received->lsa_hdr->lsh_seqnum != MAX_SEQUENCE_NUMBER)
445        {
446          ospf6_send_lsupdate_direct (have, from);
447        }
448      ospf6_lsa_delete (received);
449    }
450}
451
452/* RFC2328: Table 19: Sending link state acknowledgements. */
453int
454ack_type (struct ospf6_lsa *newp, int ismore_recent,
455          struct ospf6_neighbor *from)
456{
457  struct ospf6_interface *ospf6_interface;
458  struct ospf6_neighbor *nbr;
459  listnode n, m;
460
461  assert (from && from->ospf6_interface);
462  ospf6_interface = from->ospf6_interface;
463
464  if (CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_FLOODBACK))
465    {
466      return NO_ACK;
467    }
468  else if (ismore_recent < 0 &&
469           ! CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_FLOODBACK))
470    {
471      if (ospf6_interface->state == IFS_BDR)
472        {
473          if (ospf6_interface->dr == from->router_id)
474            {
475              return DELAYED_ACK;
476            }
477          else
478            {
479              return NO_ACK;
480            }
481        }
482      else
483        {
484          return DELAYED_ACK;
485        }
486    }
487  else if (CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_DUPLICATE) &&
488           CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_IMPLIEDACK))
489    {
490      if (ospf6_interface->state == IFS_BDR)
491        {
492          if (ospf6_interface->dr == from->router_id)
493            {
494              return DELAYED_ACK;
495            }
496          else
497            {
498              return NO_ACK;
499            }
500        }
501      else
502        {
503          return NO_ACK;
504        }
505    }
506  else if (CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_DUPLICATE) &&
507           ! CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_IMPLIEDACK))
508    {
509      return DIRECT_ACK;
510    }
511  else if (IS_LSA_MAXAGE (newp))
512    {
513      if (! ospf6_lsdb_lookup (newp->header->type, newp->header->id,
514                               newp->header->adv_router,
515                               ospf6_lsa_get_scope (newp->header->type,
516                                                    from->ospf6_interface)))
517        {
518          for (n = listhead (from->ospf6_interface->area->if_list);
519               n; nextnode (n))
520            {
521              ospf6_interface = (struct ospf6_interface *) getdata (n);
522              for (m = listhead (ospf6_interface->neighbor_list);
523                   m; nextnode (m))
524                {
525                  nbr = (struct ospf6_neighbor *) getdata (m);
526                  if (nbr->state == NBS_EXCHANGE || nbr->state == NBS_LOADING)
527                    {
528                      return NO_ACK;
529                    }
530                }
531            }
532          return DIRECT_ACK;
533        }
534    }
535
536  return NO_ACK;
537}
538
539static void
540ospf6_dbex_flood_linklocal (struct ospf6_lsa *lsa, struct ospf6_interface *o6i,
541                            struct ospf6_neighbor *from)
542{
543  struct ospf6_neighbor *o6n = (struct ospf6_neighbor *) NULL;
544  int ismore_recent, addretrans = 0;
545  listnode n;
546  struct ospf6_lsa *req;
547
548  /* (1) for each neighbor */
549  for (n = listhead (o6i->neighbor_list); n; nextnode (n))
550    {
551      o6n = (struct ospf6_neighbor *) getdata (n);
552
553      /* (a) */
554      if (o6n->state < NBS_EXCHANGE)
555        continue;  /* examin next neighbor */
556
557      /* (b) */
558      if (o6n->state == NBS_EXCHANGE
559          || o6n->state == NBS_LOADING)
560        {
561          req = ospf6_lsdb_lookup_lsdb (lsa->header->type,
562                                        lsa->header->id,
563                                        lsa->header->adv_router,
564                                        o6n->request_list);
565          if (req)
566            {
567              ismore_recent = ospf6_lsa_check_recent (lsa, req);
568              if (ismore_recent > 0)
569                {
570                  continue; /* examin next neighbor */
571                }
572              else if (ismore_recent == 0)
573                {
574                  ospf6_neighbor_request_remove (req, o6n);
575                  continue; /* examin next neighbor */
576                }
577              else /* ismore_recent < 0 (the new LSA is more recent) */
578                {
579                  ospf6_neighbor_request_remove (req, o6n);
580                }
581            }
582        }
583
584      /* (c) */
585      if (from && from->router_id == o6n->router_id)
586        continue; /* examin next neighbor */
587
588      /* (d) add retranslist */
589      if (IS_OSPF6_DUMP_DBEX)
590        zlog_info ("DBEX: schedule flooding [%s:%s]: %s",
591                   o6n->str, o6n->ospf6_interface->interface->name,
592                   lsa->str);
593      ospf6_neighbor_retrans_add (lsa, o6n);
594      addretrans++;
595      if (o6n->send_update == (struct thread *) NULL)
596        o6n->send_update =
597          thread_add_timer (master, ospf6_send_lsupdate_rxmt, o6n,
598                            o6n->ospf6_interface->rxmt_interval);
599    }
600
601  /* (2) */
602  if (addretrans == 0)
603    {
604      return; /* examin next interface */
605    }
606  else if (from && from->ospf6_interface == o6i)
607    {
608      /* note occurence of floodback */
609      SET_FLAG (lsa->flag, OSPF6_LSA_FLAG_FLOODBACK);
610    }
611
612  /* (3) */
613  if (from && from->ospf6_interface == o6i)
614    {
615      /* if from DR or BDR, don't need to flood this interface */
616      if (from->router_id == from->ospf6_interface->dr ||
617          from->router_id == from->ospf6_interface->bdr)
618        return; /* examin next interface */
619    }
620
621  /* (4) if I'm BDR, DR will flood this interface */
622  if (from && from->ospf6_interface == o6i
623      && o6i->state == IFS_BDR)
624    return; /* examin next interface */
625
626  if (IS_OSPF6_DUMP_DBEX)
627    zlog_info ("  Flood to interface %s", o6i->interface->name);
628
629  /* (5) send LinkState Update */
630  ospf6_send_lsupdate_flood (lsa, o6i);
631
632  return;
633}
634
635/* RFC2328 section 13.3 */
636static void
637ospf6_dbex_flood_area (struct ospf6_lsa *lsa, struct ospf6_area *area,
638                       struct ospf6_neighbor *from)
639{
640  listnode n;
641  struct ospf6_interface *ospf6_interface;
642
643  assert (lsa && lsa->lsa_hdr && area);
644
645  /* for each eligible ospf_ifs */
646  for (n = listhead (area->if_list); n; nextnode (n))
647    {
648      ospf6_interface = (struct ospf6_interface *) getdata (n);
649      ospf6_dbex_flood_linklocal (lsa, ospf6_interface, from);
650    }
651}
652
653static void
654ospf6_dbex_flood_as (struct ospf6_lsa *lsa, struct ospf6 *ospf6,
655                     struct ospf6_neighbor *from)
656{
657  listnode n;
658  struct ospf6_area *o6a;
659
660  assert (lsa && lsa->lsa_hdr && ospf6);
661
662  /* for each attached area */
663  for (n = listhead (ospf6->area_list); n; nextnode (n))
664    {
665      o6a = (struct ospf6_area *) getdata (n);
666      ospf6_dbex_flood_area (lsa, o6a, from);
667    }
668}
669
670/* flood ospf6_lsa within appropriate scope */
671void
672ospf6_dbex_flood (struct ospf6_lsa *lsa, struct ospf6_neighbor *from)
673{
674  struct ospf6_area *o6a;
675  struct ospf6_interface *o6i;
676  struct ospf6 *o6;
677  struct ospf6_lsa_header *lsa_header;
678
679  lsa_header = (struct ospf6_lsa_header *) lsa->lsa_hdr;
680
681  if (IS_OSPF6_DUMP_DBEX)
682    zlog_info ("Flood: %s", lsa->str);
683
684  if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (ntohs (lsa_header->type)))
685    {
686      o6i = (struct ospf6_interface *) lsa->scope;
687      assert (o6i);
688
689      ospf6_dbex_flood_linklocal (lsa, o6i, from);
690    }
691  else if (OSPF6_LSA_IS_SCOPE_AREA (ntohs (lsa_header->type)))
692    {
693      o6a = (struct ospf6_area *) lsa->scope;
694      assert (o6a);
695
696      ospf6_dbex_flood_area (lsa, o6a, from);
697    }
698  else if (OSPF6_LSA_IS_SCOPE_AS (ntohs (lsa_header->type)))
699    {
700      o6 = (struct ospf6 *) lsa->scope;
701      assert (o6);
702
703      ospf6_dbex_flood_as (lsa, o6, from);
704    }
705  else
706    {
707      zlog_warn ("Can't Flood %s: scope unknown", lsa->str);
708    }
709}
710
711
712