1/*
2 * OSPF version 2  Neighbor State Machine
3 * From RFC2328 [OSPF Version 2]
4 * Copyright (C) 1999, 2000 Toshiaki Takada
5 *
6 * This file is part of GNU Zebra.
7 *
8 * GNU Zebra is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
11 * later version.
12 *
13 * GNU Zebra is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with GNU Zebra; see the file COPYING.  If not, write to the Free
20 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21 * 02111-1307, USA.
22 */
23
24#include <zebra.h>
25
26#include "thread.h"
27#include "memory.h"
28#include "hash.h"
29#include "linklist.h"
30#include "prefix.h"
31#include "if.h"
32#include "table.h"
33#include "stream.h"
34#include "table.h"
35#include "log.h"
36
37#include "ospfd/ospfd.h"
38#include "ospfd/ospf_interface.h"
39#include "ospfd/ospf_ism.h"
40#include "ospfd/ospf_asbr.h"
41#include "ospfd/ospf_lsa.h"
42#include "ospfd/ospf_lsdb.h"
43#include "ospfd/ospf_neighbor.h"
44#include "ospfd/ospf_nsm.h"
45#include "ospfd/ospf_network.h"
46#include "ospfd/ospf_packet.h"
47#include "ospfd/ospf_dump.h"
48#include "ospfd/ospf_flood.h"
49#include "ospfd/ospf_abr.h"
50
51void nsm_reset_nbr (struct ospf_neighbor *);
52
53
54/* OSPF NSM Timer functions. */
55int
56ospf_inactivity_timer (struct thread *thread)
57{
58  struct ospf_neighbor *nbr;
59
60  nbr = THREAD_ARG (thread);
61  nbr->t_inactivity = NULL;
62
63  if (IS_DEBUG_OSPF (nsm, NSM_TIMERS))
64    zlog (NULL, LOG_DEBUG, "NSM[%s:%s]: Timer (Inactivity timer expire)",
65	  IF_NAME (nbr->oi), inet_ntoa (nbr->router_id));
66
67  OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_InactivityTimer);
68
69  return 0;
70}
71
72int
73ospf_db_desc_timer (struct thread *thread)
74{
75  struct ospf_interface *oi;
76  struct ospf_neighbor *nbr;
77
78  nbr = THREAD_ARG (thread);
79  nbr->t_db_desc = NULL;
80
81  oi = nbr->oi;
82
83  if (IS_DEBUG_OSPF (nsm, NSM_TIMERS))
84    zlog (NULL, LOG_INFO, "NSM[%s:%s]: Timer (DD Retransmit timer expire)",
85	  IF_NAME (nbr->oi), inet_ntoa (nbr->src));
86
87  /* resent last send DD packet. */
88  assert (nbr->last_send);
89  ospf_db_desc_resend (nbr);
90
91  /* DD Retransmit timer set. */
92  OSPF_NSM_TIMER_ON (nbr->t_db_desc, ospf_db_desc_timer, nbr->v_db_desc);
93
94  return 0;
95}
96
97/* Hook function called after ospf NSM event is occured. */
98
99void
100nsm_timer_set (struct ospf_neighbor *nbr)
101{
102  switch (nbr->state)
103    {
104    case NSM_Down:
105      OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
106      OSPF_NSM_TIMER_OFF (nbr->t_ls_upd);
107      break;
108    case NSM_Attempt:
109      OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
110      OSPF_NSM_TIMER_OFF (nbr->t_ls_upd);
111      break;
112    case NSM_Init:
113      OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
114      OSPF_NSM_TIMER_OFF (nbr->t_ls_upd);
115      break;
116    case NSM_TwoWay:
117      OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
118      OSPF_NSM_TIMER_OFF (nbr->t_ls_upd);
119      break;
120    case NSM_ExStart:
121      OSPF_NSM_TIMER_ON (nbr->t_db_desc, ospf_db_desc_timer, nbr->v_db_desc);
122      OSPF_NSM_TIMER_OFF (nbr->t_ls_upd);
123      break;
124    case NSM_Exchange:
125      OSPF_NSM_TIMER_ON (nbr->t_ls_upd, ospf_ls_upd_timer, nbr->v_ls_upd);
126      if (!IS_SET_DD_MS (nbr->dd_flags))
127	OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
128      break;
129    case NSM_Loading:
130      OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
131      break;
132    case NSM_Full:
133      OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
134      break;
135    default:
136      OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
137      break;
138    }
139}
140
141
142/* OSPF NSM functions. */
143int
144nsm_ignore (struct ospf_neighbor *nbr)
145{
146  if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
147    zlog (NULL, LOG_INFO, "NSM[%s:%s]: nsm_ignore called",
148	  IF_NAME (nbr->oi), inet_ntoa (nbr->router_id));
149
150  return 0;
151}
152
153int
154nsm_hello_received (struct ospf_neighbor *nbr)
155{
156  /* Start or Restart Inactivity Timer. */
157  OSPF_NSM_TIMER_OFF (nbr->t_inactivity);
158
159  OSPF_NSM_TIMER_ON (nbr->t_inactivity, ospf_inactivity_timer,
160		     nbr->v_inactivity);
161
162  if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma)
163    OSPF_POLL_TIMER_OFF (nbr->nbr_nbma->t_poll);
164
165  return 0;
166}
167
168int
169nsm_start (struct ospf_neighbor *nbr)
170{
171
172  nsm_reset_nbr (nbr);
173
174  if (nbr->nbr_nbma)
175      OSPF_POLL_TIMER_OFF (nbr->nbr_nbma->t_poll);
176
177  OSPF_NSM_TIMER_OFF (nbr->t_inactivity);
178
179  OSPF_NSM_TIMER_ON (nbr->t_inactivity, ospf_inactivity_timer,
180                     nbr->v_inactivity);
181
182  return 0;
183}
184
185int
186nsm_twoway_received (struct ospf_neighbor *nbr)
187{
188  struct ospf_interface *oi;
189  int next_state = NSM_TwoWay;
190
191  oi = nbr->oi;
192
193  /* These netowork types must be adjacency. */
194  if (oi->type == OSPF_IFTYPE_POINTOPOINT ||
195      oi->type == OSPF_IFTYPE_POINTOMULTIPOINT ||
196      oi->type == OSPF_IFTYPE_VIRTUALLINK)
197    next_state = NSM_ExStart;
198
199  /* Router itself is the DRouter or the BDRouter. */
200  if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi)) ||
201      IPV4_ADDR_SAME (&oi->address->u.prefix4, &BDR (oi)))
202    next_state = NSM_ExStart;
203
204  /* Neighboring Router is the DRouter or the BDRouter. */
205  if (IPV4_ADDR_SAME (&nbr->address.u.prefix4, &nbr->d_router) ||
206      IPV4_ADDR_SAME (&nbr->address.u.prefix4, &nbr->bd_router))
207    next_state = NSM_ExStart;
208
209  return next_state;
210}
211
212int
213ospf_db_summary_count (struct ospf_neighbor *nbr)
214{
215  return ospf_lsdb_count_all (&nbr->db_sum);
216}
217
218int
219ospf_db_summary_isempty (struct ospf_neighbor *nbr)
220{
221  return ospf_lsdb_isempty (&nbr->db_sum);
222}
223
224int
225ospf_db_summary_add (struct ospf_lsa *lsa, void *v, int i)
226{
227  struct ospf_neighbor *nbr = (struct ospf_neighbor *) v;
228
229  if (lsa == NULL)
230    return 0;
231
232#ifdef HAVE_NSSA
233  /* Stay away from any Local Translated Type-7 LSAs */
234  if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT))
235    return 0;
236#endif /* HAVE_NSSA */
237
238  if (IS_LSA_MAXAGE (lsa))
239    ospf_ls_retransmit_add (nbr, lsa);
240  else
241    ospf_lsdb_add (&nbr->db_sum, lsa);
242
243  return 0;
244}
245
246void
247ospf_db_summary_clear (struct ospf_neighbor *nbr)
248{
249  struct ospf_lsdb *lsdb;
250  int i;
251
252  lsdb = &nbr->db_sum;
253  for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
254    {
255      struct route_table *table = lsdb->type[i].db;
256      struct route_node *rn;
257
258      for (rn = route_top (table); rn; rn = route_next (rn))
259	if (rn->info)
260	  ospf_lsdb_delete (&nbr->db_sum, rn->info);
261    }
262}
263
264
265
266#ifdef HAVE_OPAQUE_LSA
267/* The area link state database consists of the router-LSAs,
268   network-LSAs, summary-LSAs, and type-9/10 opaque-LSAs contained
269			     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
270   in the area structure, along with the AS-external and type-11
271						     ^^^^^^^^^^^
272   opaque LSAs contained in the global structure.
273   ^^^^^^
274   AS-external and type-11 opaque LSAs are omitted from a virtual
275	       ^^^^^^^^^^^^^^^^^^
276   neighbor's Database summary list. AS-external and type-11 opaque
277						 ^^^^^^^^^^^^^^^^^^
278   LSAs are omitted from the Database summary list if the area has
279   been configured as a stub. */
280#else /* HAVE_OPAQUE_LSA */
281/* The area link state database consists of the router-LSAs,
282   network-LSAs and summary-LSAs contained in the area structure,
283   along with the AS-external- LSAs contained in the global structure.
284   AS- external-LSAs are omitted from a virtual neighbor's Database
285   summary list.  AS-external-LSAs are omitted from the Database
286   summary list if the area has been configured as a stub. */
287#endif /* HAVE_OPAQUE_LSA */
288int
289nsm_negotiation_done (struct ospf_neighbor *nbr)
290{
291  struct ospf_area *area;
292
293  area = nbr->oi->area;
294
295  foreach_lsa (ROUTER_LSDB (area), nbr, 0, ospf_db_summary_add);
296  foreach_lsa (NETWORK_LSDB (area), nbr, 0, ospf_db_summary_add);
297  foreach_lsa (SUMMARY_LSDB (area), nbr, 0, ospf_db_summary_add);
298  foreach_lsa (ASBR_SUMMARY_LSDB (area), nbr, 0, ospf_db_summary_add);
299
300#ifdef HAVE_OPAQUE_LSA
301  /* Process only if the neighbor is opaque capable. */
302  if (CHECK_FLAG (nbr->options, OSPF_OPTION_O))
303    {
304      foreach_lsa (OPAQUE_LINK_LSDB (area), nbr, 0, ospf_db_summary_add);
305      foreach_lsa (OPAQUE_AREA_LSDB (area), nbr, 0, ospf_db_summary_add);
306    }
307#endif /* HAVE_OPAQUE_LSA */
308
309  if (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK &&
310      area->external_routing == OSPF_AREA_DEFAULT)
311    foreach_lsa (EXTERNAL_LSDB (ospf_top), nbr, 0, ospf_db_summary_add);
312
313#ifdef HAVE_OPAQUE_LSA
314  if (CHECK_FLAG (nbr->options, OSPF_OPTION_O) &&
315      (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK &&
316       area->external_routing == OSPF_AREA_DEFAULT))
317    foreach_lsa (OPAQUE_AS_LSDB (ospf_top),
318		 nbr, 0, ospf_db_summary_add);
319#endif /* HAVE_OPAQUE_LSA */
320
321  /* OSPF_NSM_TIMER_OFF (nbr->t_db_desc); */
322
323  return 0;
324}
325
326int
327nsm_exchange_done (struct ospf_neighbor *nbr)
328{
329  struct ospf_interface *oi;
330
331  oi = nbr->oi;
332
333  if (ospf_ls_request_isempty (nbr))
334    return NSM_Full;
335
336  /* Cancel dd retransmit timer. */
337  /* OSPF_NSM_TIMER_OFF (nbr->t_db_desc); */
338
339  /* Send Link State Request. */
340  ospf_ls_req_send (nbr);
341
342  return NSM_Loading;
343}
344
345int
346nsm_bad_ls_req (struct ospf_neighbor *nbr)
347{
348  /* Clear neighbor. */
349  nsm_reset_nbr (nbr);
350
351  return 0;
352}
353
354int
355nsm_adj_ok (struct ospf_neighbor *nbr)
356{
357  struct ospf_interface *oi;
358  int next_state;
359  int flag = 0;
360
361  oi = nbr->oi;
362  next_state = nbr->state;
363
364  /* These netowork types must be adjacency. */
365  if (oi->type == OSPF_IFTYPE_POINTOPOINT ||
366      oi->type == OSPF_IFTYPE_POINTOMULTIPOINT ||
367      oi->type == OSPF_IFTYPE_VIRTUALLINK)
368    flag = 1;
369
370  /* Router itself is the DRouter or the BDRouter. */
371  if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi)) ||
372      IPV4_ADDR_SAME (&oi->address->u.prefix4, &BDR (oi)))
373    flag = 1;
374
375  if (IPV4_ADDR_SAME (&nbr->address.u.prefix4, &DR (oi)) ||
376      IPV4_ADDR_SAME (&nbr->address.u.prefix4, &BDR (oi)))
377    flag = 1;
378
379  if (nbr->state == NSM_TwoWay && flag == 1)
380    next_state = NSM_ExStart;
381  else if (nbr->state >= NSM_ExStart && flag == 0)
382    next_state = NSM_TwoWay;
383
384  return next_state;
385}
386
387int
388nsm_seq_number_mismatch (struct ospf_neighbor *nbr)
389{
390  /* Clear neighbor. */
391  nsm_reset_nbr (nbr);
392
393  return 0;
394}
395
396int
397nsm_oneway_received (struct ospf_neighbor *nbr)
398{
399  /* Clear neighbor. */
400  nsm_reset_nbr (nbr);
401
402  return 0;
403}
404
405void
406nsm_reset_nbr (struct ospf_neighbor *nbr)
407{
408  /* Clear Database Summary list. */
409  if (!ospf_db_summary_isempty (nbr))
410    ospf_db_summary_clear (nbr);
411
412  /* Clear Link State Request list. */
413  if (!ospf_ls_request_isempty (nbr))
414    ospf_ls_request_delete_all (nbr);
415
416  /* Clear Link State Retransmission list. */
417  if (!ospf_ls_retransmit_isempty (nbr))
418    ospf_ls_retransmit_clear (nbr);
419
420  /* Cancel thread. */
421  OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
422  OSPF_NSM_TIMER_OFF (nbr->t_ls_req);
423  OSPF_NSM_TIMER_OFF (nbr->t_ls_upd);
424  OSPF_NSM_TIMER_OFF (nbr->t_hello_reply);
425
426#ifdef HAVE_OPAQUE_LSA
427  if (CHECK_FLAG (nbr->options, OSPF_OPTION_O))
428    UNSET_FLAG (nbr->options, OSPF_OPTION_O);
429#endif /* HAVE_OPAQUE_LSA */
430}
431
432int
433nsm_kill_nbr (struct ospf_neighbor *nbr)
434{
435  /* call it here because we cannot call it from ospf_nsm_event */
436  nsm_change_state (nbr, NSM_Down);
437
438  /* Reset neighbor. */
439  nsm_reset_nbr (nbr);
440
441  if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma != NULL)
442    {
443      struct ospf_nbr_nbma *nbr_nbma = nbr->nbr_nbma;
444
445      nbr_nbma->nbr = NULL;
446      nbr_nbma->state_change = nbr->state_change;
447
448      nbr->nbr_nbma = NULL;
449
450      OSPF_POLL_TIMER_ON (nbr_nbma->t_poll, ospf_poll_timer,
451			  nbr_nbma->v_poll);
452
453      if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
454	zlog_info ("NSM[%s:%s]: Down (PollIntervalTimer scheduled)",
455		   IF_NAME (nbr->oi), inet_ntoa (nbr->address.u.prefix4));
456    }
457
458  /* Delete neighbor from interface. */
459  ospf_nbr_delete (nbr);
460
461  return 0;
462}
463
464int
465nsm_inactivity_timer (struct ospf_neighbor *nbr)
466{
467  /* Kill neighbor. */
468  nsm_kill_nbr (nbr);
469
470  return 0;
471}
472
473int
474nsm_ll_down (struct ospf_neighbor *nbr)
475{
476  /* Reset neighbor. */
477  /*nsm_reset_nbr (nbr);*/
478
479  /* Kill neighbor. */
480  nsm_kill_nbr (nbr);
481
482  return 0;
483}
484
485/* Neighbor State Machine */
486struct {
487  int (*func) ();
488  int next_state;
489} NSM [OSPF_NSM_STATE_MAX][OSPF_NSM_EVENT_MAX] =
490{
491  {
492    /* DependUpon: dummy state. */
493    { nsm_ignore,              NSM_DependUpon }, /* NoEvent           */
494    { nsm_ignore,              NSM_DependUpon }, /* HelloReceived     */
495    { nsm_ignore,              NSM_DependUpon }, /* Start             */
496    { nsm_ignore,              NSM_DependUpon }, /* 2-WayReceived     */
497    { nsm_ignore,              NSM_DependUpon }, /* NegotiationDone   */
498    { nsm_ignore,              NSM_DependUpon }, /* ExchangeDone      */
499    { nsm_ignore,              NSM_DependUpon }, /* BadLSReq          */
500    { nsm_ignore,              NSM_DependUpon }, /* LoadingDone       */
501    { nsm_ignore,              NSM_DependUpon }, /* AdjOK?            */
502    { nsm_ignore,              NSM_DependUpon }, /* SeqNumberMismatch */
503    { nsm_ignore,              NSM_DependUpon }, /* 1-WayReceived     */
504    { nsm_ignore,              NSM_DependUpon }, /* KillNbr           */
505    { nsm_ignore,              NSM_DependUpon }, /* InactivityTimer   */
506    { nsm_ignore,              NSM_DependUpon }, /* LLDown            */
507  },
508  {
509    /* Down: */
510    { nsm_ignore,              NSM_DependUpon }, /* NoEvent           */
511    { nsm_hello_received,      NSM_Init       }, /* HelloReceived     */
512    { nsm_start,               NSM_Attempt    }, /* Start             */
513    { nsm_ignore,              NSM_Down       }, /* 2-WayReceived     */
514    { nsm_ignore,              NSM_Down       }, /* NegotiationDone   */
515    { nsm_ignore,              NSM_Down       }, /* ExchangeDone      */
516    { nsm_ignore,              NSM_Down       }, /* BadLSReq          */
517    { nsm_ignore,              NSM_Down       }, /* LoadingDone       */
518    { nsm_ignore,              NSM_Down       }, /* AdjOK?            */
519    { nsm_ignore,              NSM_Down       }, /* SeqNumberMismatch */
520    { nsm_ignore,              NSM_Down       }, /* 1-WayReceived     */
521    { nsm_kill_nbr,            NSM_Down       }, /* KillNbr           */
522    { nsm_inactivity_timer,    NSM_Down       }, /* InactivityTimer   */
523    { nsm_ll_down,             NSM_Down       }, /* LLDown            */
524  },
525  {
526    /* Attempt: */
527    { nsm_ignore,              NSM_DependUpon }, /* NoEvent           */
528    { nsm_hello_received,      NSM_Init       }, /* HelloReceived     */
529    { nsm_ignore,              NSM_Attempt    }, /* Start             */
530    { nsm_ignore,              NSM_Attempt    }, /* 2-WayReceived     */
531    { nsm_ignore,              NSM_Attempt    }, /* NegotiationDone   */
532    { nsm_ignore,              NSM_Attempt    }, /* ExchangeDone      */
533    { nsm_ignore,              NSM_Attempt    }, /* BadLSReq          */
534    { nsm_ignore,              NSM_Attempt    }, /* LoadingDone       */
535    { nsm_ignore,              NSM_Attempt    }, /* AdjOK?            */
536    { nsm_ignore,              NSM_Attempt    }, /* SeqNumberMismatch */
537    { nsm_ignore,              NSM_Attempt    }, /* 1-WayReceived     */
538    { nsm_kill_nbr,            NSM_Down       }, /* KillNbr           */
539    { nsm_inactivity_timer,    NSM_Down       }, /* InactivityTimer   */
540    { nsm_ll_down,             NSM_Down       }, /* LLDown            */
541  },
542  {
543    /* Init: */
544    { nsm_ignore,              NSM_DependUpon }, /* NoEvent           */
545    { nsm_hello_received,      NSM_Init       }, /* HelloReceived     */
546    { nsm_ignore,              NSM_Init       }, /* Start             */
547    { nsm_twoway_received,     NSM_DependUpon }, /* 2-WayReceived     */
548    { nsm_ignore,              NSM_Init       }, /* NegotiationDone   */
549    { nsm_ignore,              NSM_Init       }, /* ExchangeDone      */
550    { nsm_ignore,              NSM_Init       }, /* BadLSReq          */
551    { nsm_ignore,              NSM_Init       }, /* LoadingDone       */
552    { nsm_ignore,              NSM_Init       }, /* AdjOK?            */
553    { nsm_ignore,              NSM_Init       }, /* SeqNumberMismatch */
554    { nsm_ignore,              NSM_Init       }, /* 1-WayReceived     */
555    { nsm_kill_nbr,            NSM_Down       }, /* KillNbr           */
556    { nsm_inactivity_timer,    NSM_Down       }, /* InactivityTimer   */
557    { nsm_ll_down,             NSM_Down       }, /* LLDown            */
558  },
559  {
560    /* 2-Way: */
561    { nsm_ignore,              NSM_DependUpon }, /* NoEvent           */
562    { nsm_hello_received,      NSM_TwoWay     }, /* HelloReceived     */
563    { nsm_ignore,              NSM_TwoWay     }, /* Start             */
564    { nsm_ignore,              NSM_TwoWay     }, /* 2-WayReceived     */
565    { nsm_ignore,              NSM_TwoWay     }, /* NegotiationDone   */
566    { nsm_ignore,              NSM_TwoWay     }, /* ExchangeDone      */
567    { nsm_ignore,              NSM_TwoWay     }, /* BadLSReq          */
568    { nsm_ignore,              NSM_TwoWay     }, /* LoadingDone       */
569    { nsm_adj_ok,              NSM_DependUpon }, /* AdjOK?            */
570    { nsm_ignore,              NSM_TwoWay     }, /* SeqNumberMismatch */
571    { nsm_oneway_received,     NSM_Init       }, /* 1-WayReceived     */
572    { nsm_kill_nbr,            NSM_Down       }, /* KillNbr           */
573    { nsm_inactivity_timer,    NSM_Down       }, /* InactivityTimer   */
574    { nsm_ll_down,             NSM_Down       }, /* LLDown            */
575  },
576  {
577    /* ExStart: */
578    { nsm_ignore,              NSM_DependUpon }, /* NoEvent           */
579    { nsm_hello_received,      NSM_ExStart    }, /* HelloReceived     */
580    { nsm_ignore,              NSM_ExStart    }, /* Start             */
581    { nsm_ignore,              NSM_ExStart    }, /* 2-WayReceived     */
582    { nsm_negotiation_done,    NSM_Exchange   }, /* NegotiationDone   */
583    { nsm_ignore,              NSM_ExStart    }, /* ExchangeDone      */
584    { nsm_ignore,              NSM_ExStart    }, /* BadLSReq          */
585    { nsm_ignore,              NSM_ExStart    }, /* LoadingDone       */
586    { nsm_adj_ok,              NSM_DependUpon }, /* AdjOK?            */
587    { nsm_ignore,              NSM_ExStart    }, /* SeqNumberMismatch */
588    { nsm_oneway_received,     NSM_Init       }, /* 1-WayReceived     */
589    { nsm_kill_nbr,            NSM_Down       }, /* KillNbr           */
590    { nsm_inactivity_timer,    NSM_Down       }, /* InactivityTimer   */
591    { nsm_ll_down,             NSM_Down       }, /* LLDown            */
592  },
593  {
594    /* Exchange: */
595    { nsm_ignore,              NSM_DependUpon }, /* NoEvent           */
596    { nsm_hello_received,      NSM_Exchange   }, /* HelloReceived     */
597    { nsm_ignore,              NSM_Exchange   }, /* Start             */
598    { nsm_ignore,              NSM_Exchange   }, /* 2-WayReceived     */
599    { nsm_ignore,              NSM_Exchange   }, /* NegotiationDone   */
600    { nsm_exchange_done,       NSM_DependUpon }, /* ExchangeDone      */
601    { nsm_bad_ls_req,          NSM_ExStart    }, /* BadLSReq          */
602    { nsm_ignore,              NSM_Exchange   }, /* LoadingDone       */
603    { nsm_adj_ok,              NSM_DependUpon }, /* AdjOK?            */
604    { nsm_seq_number_mismatch, NSM_ExStart    }, /* SeqNumberMismatch */
605    { nsm_oneway_received,     NSM_Init       }, /* 1-WayReceived     */
606    { nsm_kill_nbr,            NSM_Down       }, /* KillNbr           */
607    { nsm_inactivity_timer,    NSM_Down       }, /* InactivityTimer   */
608    { nsm_ll_down,             NSM_Down       }, /* LLDown            */
609  },
610  {
611    /* Loading: */
612    { nsm_ignore,              NSM_DependUpon }, /* NoEvent           */
613    { nsm_hello_received,      NSM_Loading    }, /* HelloReceived     */
614    { nsm_ignore,              NSM_Loading    }, /* Start             */
615    { nsm_ignore,              NSM_Loading    }, /* 2-WayReceived     */
616    { nsm_ignore,              NSM_Loading    }, /* NegotiationDone   */
617    { nsm_ignore,              NSM_Loading    }, /* ExchangeDone      */
618    { nsm_bad_ls_req,          NSM_ExStart    }, /* BadLSReq          */
619    { nsm_ignore,              NSM_Full       }, /* LoadingDone       */
620    { nsm_adj_ok,              NSM_DependUpon }, /* AdjOK?            */
621    { nsm_seq_number_mismatch, NSM_ExStart    }, /* SeqNumberMismatch */
622    { nsm_oneway_received,     NSM_Init       }, /* 1-WayReceived     */
623    { nsm_kill_nbr,            NSM_Down       }, /* KillNbr           */
624    { nsm_inactivity_timer,    NSM_Down       }, /* InactivityTimer   */
625    { nsm_ll_down,             NSM_Down       }, /* LLDown            */
626  },
627  { /* Full: */
628    { nsm_ignore,              NSM_DependUpon }, /* NoEvent           */
629    { nsm_hello_received,      NSM_Full       }, /* HelloReceived     */
630    { nsm_ignore,              NSM_Full       }, /* Start             */
631    { nsm_ignore,              NSM_Full       }, /* 2-WayReceived     */
632    { nsm_ignore,              NSM_Full       }, /* NegotiationDone   */
633    { nsm_ignore,              NSM_Full       }, /* ExchangeDone      */
634    { nsm_bad_ls_req,          NSM_ExStart    }, /* BadLSReq          */
635    { nsm_ignore,              NSM_Full       }, /* LoadingDone       */
636    { nsm_adj_ok,              NSM_DependUpon }, /* AdjOK?            */
637    { nsm_seq_number_mismatch, NSM_ExStart    }, /* SeqNumberMismatch */
638    { nsm_oneway_received,     NSM_Init       }, /* 1-WayReceived     */
639    { nsm_kill_nbr,            NSM_Down       }, /* KillNbr           */
640    { nsm_inactivity_timer,    NSM_Down       }, /* InactivityTimer   */
641    { nsm_ll_down,             NSM_Down       }, /* LLDown            */
642  },
643};
644
645static char *ospf_nsm_event_str[] =
646{
647  "NoEvent",
648  "HelloReceived",
649  "Start",
650  "2-WayReceived",
651  "NegotiationDone",
652  "ExchangeDone",
653  "BadLSReq",
654  "LoadingDone",
655  "AdjOK?",
656  "SeqNumberMismatch",
657  "1-WayReceived",
658  "KillNbr",
659  "InactivityTimer",
660  "LLDown",
661};
662
663void
664nsm_change_state (struct ospf_neighbor *nbr, int state)
665{
666  struct ospf_interface *oi;
667  struct ospf_area *vl_area = NULL;
668  u_char old_state;
669
670  /* Logging change of status. */
671  if (IS_DEBUG_OSPF (nsm, NSM_STATUS))
672    zlog_info ("NSM[%s:%s]: State change %s -> %s",
673	       IF_NAME (nbr->oi), inet_ntoa (nbr->router_id),
674	       LOOKUP (ospf_nsm_state_msg, nbr->state),
675	       LOOKUP (ospf_nsm_state_msg, state));
676
677  /* Preserve old status. */
678  old_state = nbr->state;
679
680  /* Change to new status. */
681  nbr->state = state;
682
683  /* Statistics. */
684  nbr->state_change++;
685
686  oi = nbr->oi;
687
688  if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
689    vl_area = ospf_area_lookup_by_area_id (oi->vl_data->vl_area_id);
690
691  /* One of the neighboring routers changes to/from the FULL state. */
692  if ((old_state != NSM_Full && state == NSM_Full) ||
693      (old_state == NSM_Full && state != NSM_Full))
694    {
695      if (state == NSM_Full)
696	{
697	  oi->full_nbrs++;
698	  oi->area->full_nbrs++;
699
700          ospf_check_abr_status ();
701
702	  if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
703            if (++vl_area->full_vls == 1)
704	      ospf_schedule_abr_task ();
705	}
706      else
707	{
708	  oi->full_nbrs--;
709	  oi->area->full_nbrs--;
710
711          ospf_check_abr_status ();
712
713	  if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
714	    if (vl_area->full_vls > 0)
715	      if (--vl_area->full_vls == 0)
716		ospf_schedule_abr_task ();
717
718          /* clear neighbor retransmit list */
719          if (!ospf_ls_retransmit_isempty (nbr))
720            ospf_ls_retransmit_clear (nbr);
721	}
722
723      zlog_info ("nsm_change_state(): "
724		 "scheduling new router-LSA origination");
725
726      ospf_router_lsa_timer_add (oi->area);
727
728      if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
729	{
730	  struct ospf_area *vl_area =
731	    ospf_area_lookup_by_area_id (oi->vl_data->vl_area_id);
732
733	  if (vl_area)
734	    ospf_router_lsa_timer_add (vl_area);
735	}
736
737      /* Originate network-LSA. */
738      if (oi->state == ISM_DR)
739	{
740	  if (oi->network_lsa_self && oi->full_nbrs == 0)
741	    {
742	      ospf_lsa_flush_area (oi->network_lsa_self, oi->area);
743	      ospf_lsa_unlock (oi->network_lsa_self);
744	      oi->network_lsa_self = NULL;
745	      OSPF_TIMER_OFF (oi->t_network_lsa_self);
746	    }
747	  else
748	    ospf_network_lsa_timer_add (oi);
749	}
750    }
751
752#ifdef HAVE_OPAQUE_LSA
753  ospf_opaque_nsm_change (nbr, old_state);
754#endif /* HAVE_OPAQUE_LSA */
755
756  /* Start DD exchange protocol */
757  if (state == NSM_ExStart)
758    {
759      if (nbr->dd_seqnum == 0)
760	nbr->dd_seqnum = time (NULL);
761      else
762	nbr->dd_seqnum++;
763
764      nbr->dd_flags = OSPF_DD_FLAG_I|OSPF_DD_FLAG_M|OSPF_DD_FLAG_MS;
765      ospf_db_desc_send (nbr);
766    }
767
768  /* clear cryptographic sequence number */
769  if (state == NSM_Down)
770    nbr->crypt_seqnum = 0;
771
772  /* Generete NeighborChange ISM event. */
773  if ((old_state < NSM_TwoWay && state >= NSM_TwoWay) ||
774      (old_state >= NSM_TwoWay && state < NSM_TwoWay))
775    OSPF_ISM_EVENT_EXECUTE (oi, ISM_NeighborChange);
776
777  /* Performance hack. Send hello immideately when some neighbor enter
778     Init state.  This whay we decrease neighbor discovery time. Gleb.*/
779  if (state == NSM_Init)
780    {
781      OSPF_ISM_TIMER_OFF (oi->t_hello);
782      OSPF_ISM_TIMER_ON (oi->t_hello, ospf_hello_timer, 1);
783    }
784
785  /* Preserve old status? */
786}
787
788/* Execute NSM event process. */
789int
790ospf_nsm_event (struct thread *thread)
791{
792  int event;
793  int next_state;
794  struct ospf_neighbor *nbr;
795  struct in_addr router_id;
796  int old_state;
797  struct ospf_interface *oi;
798
799  nbr = THREAD_ARG (thread);
800  event = THREAD_VAL (thread);
801  router_id = nbr->router_id;
802
803  old_state = nbr->state;
804  oi = nbr->oi ;
805
806  /* Call function. */
807  next_state = (*(NSM [nbr->state][event].func))(nbr);
808
809  /* When event is NSM_KillNbr or InactivityTimer, the neighbor is
810     deleted. */
811  if (event == NSM_KillNbr || event == NSM_InactivityTimer)
812    {
813      if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
814	zlog_info ("NSM[%s:%s]: neighbor deleted",
815		   IF_NAME (oi), inet_ntoa (router_id));
816
817      /* Timers are canceled in ospf_nbr_free, moreover we cannot call
818         nsm_timer_set here because nbr is freed already!!!*/
819      /*nsm_timer_set (nbr);*/
820
821      return 0;
822    }
823
824  if (! next_state)
825    next_state = NSM [nbr->state][event].next_state;
826
827  if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
828    zlog_info ("NSM[%s:%s]: %s (%s)", IF_NAME (oi),
829	       inet_ntoa (nbr->router_id),
830	       LOOKUP (ospf_nsm_state_msg, nbr->state),
831	       ospf_nsm_event_str [event]);
832
833  /* If state is changed. */
834  if (next_state != nbr->state)
835    nsm_change_state (nbr, next_state);
836
837  /* Make sure timer is set. */
838  nsm_timer_set (nbr);
839
840  return 0;
841}
842
843/* Check loading state. */
844void
845ospf_check_nbr_loading (struct ospf_neighbor *nbr)
846{
847  if (nbr->state == NSM_Loading)
848    {
849      if (ospf_ls_request_isempty (nbr))
850	OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_LoadingDone);
851      else if (nbr->ls_req_last == NULL)
852	ospf_ls_req_event (nbr);
853    }
854}
855