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
24static int
25nbs_full_change (struct ospf6_interface *ospf6_interface)
26{
27  CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, ospf6_interface);
28  return 0;
29}
30
31static int
32nbs_change (state_t nbs_next, char *reason, struct ospf6_neighbor *o6n)
33{
34  state_t nbs_previous;
35
36  nbs_previous = o6n->state;
37  o6n->state = nbs_next;
38
39  if (nbs_previous == nbs_next)
40    return 0;
41
42  /* statistics */
43  o6n->ospf6_stat_state_changed++;
44  gettimeofday (&o6n->last_changed, NULL);
45
46  /* log */
47  if (IS_OSPF6_DUMP_NEIGHBOR)
48    {
49      if (reason)
50        zlog_info ("Neighbor status change %s: [%s]->[%s](%s)",
51                   o6n->str,
52                   ospf6_neighbor_state_string[nbs_previous],
53                   ospf6_neighbor_state_string[nbs_next],
54                   reason);
55      else
56        zlog_info ("Neighbor status change %s: [%s]->[%s]",
57                   o6n->str,
58                   ospf6_neighbor_state_string[nbs_previous],
59                   ospf6_neighbor_state_string[nbs_next]);
60    }
61
62  if (nbs_previous == NBS_FULL || nbs_next == NBS_FULL)
63    nbs_full_change (o6n->ospf6_interface);
64
65  /* check for LSAs that already reached MaxAge */
66  if ((nbs_previous == NBS_EXCHANGE || nbs_previous == NBS_LOADING) &&
67      (nbs_next != NBS_EXCHANGE && nbs_next != NBS_LOADING))
68    {
69      ospf6_maxage_remover ();
70    }
71
72  CALL_CHANGE_HOOK (&neighbor_hook, o6n);
73
74  return 0;
75}
76
77/* RFC2328 section 10.4 */
78int
79need_adjacency (struct ospf6_neighbor *o6n)
80{
81
82  if (o6n->ospf6_interface->state == IFS_PTOP)
83    return 1;
84  if (o6n->ospf6_interface->state == IFS_DR)
85    return 1;
86  if (o6n->ospf6_interface->state == IFS_BDR)
87    return 1;
88  if (o6n->router_id == o6n->ospf6_interface->dr)
89    return 1;
90  if (o6n->router_id == o6n->ospf6_interface->bdr)
91    return 1;
92
93  return 0;
94}
95
96int
97hello_received (struct thread *thread)
98{
99  struct ospf6_neighbor *o6n;
100
101  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
102  assert (o6n);
103
104  if (IS_OSPF6_DUMP_NEIGHBOR)
105    zlog_info ("Neighbor Event %s: *HelloReceived*", o6n->str);
106
107  if (o6n->inactivity_timer)
108    thread_cancel (o6n->inactivity_timer);
109
110  o6n->inactivity_timer = thread_add_timer (master, inactivity_timer, o6n,
111                                            o6n->ospf6_interface->dead_interval);
112  if (o6n->state <= NBS_DOWN)
113    nbs_change (NBS_INIT, "HelloReceived", o6n);
114  return 0;
115}
116
117int
118twoway_received (struct thread *thread)
119{
120  struct ospf6_neighbor *o6n;
121
122  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
123  assert (o6n);
124
125  if (o6n->state > NBS_INIT)
126    return 0;
127
128  if (IS_OSPF6_DUMP_NEIGHBOR)
129    zlog_info ("Neighbor Event %s: *2Way-Received*", o6n->str);
130
131  thread_add_event (master, neighbor_change, o6n->ospf6_interface, 0);
132
133  if (!need_adjacency (o6n))
134    {
135      nbs_change (NBS_TWOWAY, "No Need Adjacency", o6n);
136      return 0;
137    }
138  else
139    nbs_change (NBS_EXSTART, "Need Adjacency", o6n);
140
141  DD_MSBIT_SET (o6n->dbdesc_bits);
142  DD_MBIT_SET (o6n->dbdesc_bits);
143  DD_IBIT_SET (o6n->dbdesc_bits);
144
145  if (o6n->thread_send_dbdesc)
146    thread_cancel (o6n->thread_send_dbdesc);
147  o6n->thread_send_dbdesc =
148    thread_add_event (master, ospf6_send_dbdesc, o6n, 0);
149  if (o6n->thread_rxmt_dbdesc)
150    thread_cancel (o6n->thread_rxmt_dbdesc);
151  o6n->thread_rxmt_dbdesc = (struct thread *) NULL;
152
153  return 0;
154}
155
156int
157negotiation_done (struct thread *thread)
158{
159  struct ospf6_neighbor *o6n;
160
161  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
162  assert (o6n);
163
164  if (o6n->state != NBS_EXSTART)
165    return 0;
166
167  if (IS_OSPF6_DUMP_NEIGHBOR)
168    zlog_info ("Neighbor Event %s: *NegotiationDone*", o6n->str);
169
170  nbs_change (NBS_EXCHANGE, "NegotiationDone", o6n);
171  DD_IBIT_CLEAR (o6n->dbdesc_bits);
172
173  return 0;
174}
175
176int
177exchange_done (struct thread *thread)
178{
179  struct ospf6_neighbor *o6n;
180
181  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
182  assert (o6n);
183
184  if (o6n->state != NBS_EXCHANGE)
185    return 0;
186
187  if (o6n->thread_rxmt_dbdesc)
188    thread_cancel (o6n->thread_rxmt_dbdesc);
189  o6n->thread_rxmt_dbdesc = (struct thread *) NULL;
190
191  if (IS_OSPF6_DUMP_NEIGHBOR)
192    zlog_info ("Neighbor Event %s: *ExchangeDone*", o6n->str);
193
194  ospf6_lsdb_remove_all (o6n->dbdesc_list);
195
196  thread_add_timer (master, ospf6_neighbor_last_dbdesc_release, o6n,
197                    o6n->ospf6_interface->dead_interval);
198
199  if (o6n->request_list->count == 0)
200    nbs_change (NBS_FULL, "Requestlist Empty", o6n);
201  else
202    {
203      thread_add_event (master, ospf6_send_lsreq, o6n, 0);
204      nbs_change (NBS_LOADING, "Requestlist Not Empty", o6n);
205    }
206  return 0;
207}
208
209int
210loading_done (struct thread *thread)
211{
212  struct ospf6_neighbor *o6n;
213
214  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
215  assert (o6n);
216
217  if (o6n->state != NBS_LOADING)
218    return 0;
219
220  if (IS_OSPF6_DUMP_NEIGHBOR)
221    zlog_info ("Neighbor Event %s: *LoadingDone*", o6n->str);
222
223  assert (o6n->request_list->count == 0);
224
225  nbs_change (NBS_FULL, "LoadingDone", o6n);
226
227  return 0;
228}
229
230int
231adj_ok (struct thread *thread)
232{
233  struct ospf6_neighbor *o6n;
234
235  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
236  assert (o6n);
237
238  if (IS_OSPF6_DUMP_NEIGHBOR)
239    zlog_info ("Neighbor Event %s: *AdjOK?*", o6n->str);
240
241  if (o6n->state == NBS_TWOWAY)
242    {
243      if (!need_adjacency (o6n))
244        {
245          nbs_change (NBS_TWOWAY, "No Need Adjacency", o6n);
246          return 0;
247        }
248      else
249        nbs_change (NBS_EXSTART, "Need Adjacency", o6n);
250
251      DD_MSBIT_SET (o6n->dbdesc_bits);
252      DD_MBIT_SET (o6n->dbdesc_bits);
253      DD_IBIT_SET (o6n->dbdesc_bits);
254
255      if (o6n->thread_send_dbdesc)
256        thread_cancel (o6n->thread_send_dbdesc);
257      o6n->thread_send_dbdesc =
258        thread_add_event (master, ospf6_send_dbdesc, o6n, 0);
259
260      return 0;
261    }
262
263  if (o6n->state >= NBS_EXSTART)
264    {
265      if (need_adjacency (o6n))
266        return 0;
267      else
268        {
269          nbs_change (NBS_TWOWAY, "No Need Adjacency", o6n);
270          ospf6_neighbor_lslist_clear (o6n);
271        }
272    }
273  return 0;
274}
275
276int
277seqnumber_mismatch (struct thread *thread)
278{
279  struct ospf6_neighbor *o6n;
280
281  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
282  assert (o6n);
283
284  if (o6n->state < NBS_EXCHANGE)
285    return 0;
286
287  /* statistics */
288  o6n->ospf6_stat_seqnum_mismatch++;
289
290  if (IS_OSPF6_DUMP_NEIGHBOR)
291    zlog_info ("Neighbor Event %s: *SeqNumberMismatch*", o6n->str);
292
293  nbs_change (NBS_EXSTART, "SeqNumberMismatch", o6n);
294
295  DD_MSBIT_SET (o6n->dbdesc_bits);
296  DD_MBIT_SET (o6n->dbdesc_bits);
297  DD_IBIT_SET (o6n->dbdesc_bits);
298  ospf6_neighbor_lslist_clear (o6n);
299
300  if (o6n->thread_send_dbdesc)
301    thread_cancel (o6n->thread_send_dbdesc);
302  o6n->thread_send_dbdesc =
303    thread_add_event (master, ospf6_send_dbdesc, o6n, 0);
304
305  return 0;
306}
307
308int
309bad_lsreq (struct thread *thread)
310{
311  struct ospf6_neighbor *o6n;
312
313  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
314  assert (o6n);
315
316  if (o6n->state < NBS_EXCHANGE)
317    return 0;
318
319  /* statistics */
320  o6n->ospf6_stat_bad_lsreq++;
321
322  if (IS_OSPF6_DUMP_NEIGHBOR)
323    zlog_info ("Neighbor Event %s: *BadLSReq*", o6n->str);
324
325  nbs_change (NBS_EXSTART, "BadLSReq", o6n);
326
327  DD_MSBIT_SET (o6n->dbdesc_bits);
328  DD_MBIT_SET (o6n->dbdesc_bits);
329  DD_IBIT_SET (o6n->dbdesc_bits);
330  ospf6_neighbor_lslist_clear (o6n);
331
332  if (o6n->thread_send_dbdesc)
333    thread_cancel (o6n->thread_send_dbdesc);
334  o6n->thread_send_dbdesc =
335    thread_add_event (master, ospf6_send_dbdesc, o6n, 0);
336
337  return 0;
338}
339
340int
341oneway_received (struct thread *thread)
342{
343  struct ospf6_neighbor *o6n;
344
345  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
346  assert (o6n);
347
348  if (o6n->state < NBS_TWOWAY)
349    return 0;
350
351  /* statistics */
352  o6n->ospf6_stat_oneway_received++;
353
354  if (IS_OSPF6_DUMP_NEIGHBOR)
355    zlog_info ("Neighbor Event %s: *1Way-Received*", o6n->str);
356
357  nbs_change (NBS_INIT, "1Way-Received", o6n);
358
359  thread_add_event (master, neighbor_change, o6n->ospf6_interface, 0);
360
361  ospf6_neighbor_thread_cancel_all (o6n);
362  ospf6_neighbor_lslist_clear (o6n);
363  return 0;
364}
365
366int
367inactivity_timer (struct thread *thread)
368{
369  struct ospf6_neighbor *o6n;
370
371  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
372  assert (o6n);
373
374  /* statistics */
375  o6n->ospf6_stat_inactivity_timer++;
376
377  if (IS_OSPF6_DUMP_NEIGHBOR)
378    zlog_info ("Neighbor Event %s: *InactivityTimer*", o6n->str);
379
380  o6n->inactivity_timer = NULL;
381  o6n->dr = o6n->bdr = o6n->prevdr = o6n->prevbdr = 0;
382  nbs_change (NBS_DOWN, "InactivityTimer", o6n);
383
384  thread_add_event (master, neighbor_change, o6n->ospf6_interface, 0);
385
386  listnode_delete (o6n->ospf6_interface->neighbor_list, o6n);
387  ospf6_neighbor_delete (o6n);
388
389  return 0;
390}
391
392