Import Upstream version 1.2.2
[quagga-debian.git] / isisd / isis_circuit.c
1 /*
2  * IS-IS Rout(e)ing protocol - isis_circuit.h
3  *
4  * Copyright (C) 2001,2002   Sampo Saaristo
5  *                           Tampere University of Technology      
6  *                           Institute of Communications Engineering
7  *
8  * This program is free software; you can redistribute it and/or modify it 
9  * under the terms of the GNU General Public Licenseas published by the Free 
10  * Software Foundation; either version 2 of the License, or (at your option) 
11  * any later version.
12  *
13  * This program is distributed in the hope that it will be useful,but WITHOUT 
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
16  * more details.
17
18  * You should have received a copy of the GNU General Public License along 
19  * with this program; if not, write to the Free Software Foundation, Inc., 
20  * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  */
22 #include <zebra.h>
23 #ifdef GNU_LINUX
24 #include <net/ethernet.h>
25 #else
26 #include <netinet/if_ether.h>
27 #endif
28
29 #ifndef ETHER_ADDR_LEN
30 #define ETHER_ADDR_LEN  ETHERADDRL
31 #endif
32
33 #include "log.h"
34 #include "memory.h"
35 #include "if.h"
36 #include "linklist.h"
37 #include "command.h"
38 #include "thread.h"
39 #include "vty.h"
40 #include "hash.h"
41 #include "prefix.h"
42 #include "stream.h"
43
44 #include "isisd/dict.h"
45 #include "isisd/include-netbsd/iso.h"
46 #include "isisd/isis_constants.h"
47 #include "isisd/isis_common.h"
48 #include "isisd/isis_flags.h"
49 #include "isisd/isis_circuit.h"
50 #include "isisd/isis_tlv.h"
51 #include "isisd/isis_lsp.h"
52 #include "isisd/isis_pdu.h"
53 #include "isisd/isis_network.h"
54 #include "isisd/isis_misc.h"
55 #include "isisd/isis_constants.h"
56 #include "isisd/isis_adjacency.h"
57 #include "isisd/isis_dr.h"
58 #include "isisd/isisd.h"
59 #include "isisd/isis_csm.h"
60 #include "isisd/isis_events.h"
61 #include "isisd/isis_te.h"
62
63 /*
64  * Prototypes.
65  */
66 int isis_interface_config_write(struct vty *);
67 int isis_if_new_hook(struct interface *);
68 int isis_if_delete_hook(struct interface *);
69
70 struct isis_circuit *
71 isis_circuit_new ()
72 {
73   struct isis_circuit *circuit;
74   int i;
75
76   circuit = XCALLOC (MTYPE_ISIS_CIRCUIT, sizeof (struct isis_circuit));
77   if (circuit == NULL)
78     {
79       zlog_err ("Can't malloc isis circuit");
80       return NULL;
81     }
82
83   /*
84    * Default values
85    */
86   circuit->is_type = IS_LEVEL_1_AND_2;
87   circuit->flags = 0;
88   circuit->pad_hellos = 1;
89   for (i = 0; i < 2; i++)
90     {
91       circuit->hello_interval[i] = DEFAULT_HELLO_INTERVAL;
92       circuit->hello_multiplier[i] = DEFAULT_HELLO_MULTIPLIER;
93       circuit->csnp_interval[i] = DEFAULT_CSNP_INTERVAL;
94       circuit->psnp_interval[i] = DEFAULT_PSNP_INTERVAL;
95       circuit->priority[i] = DEFAULT_PRIORITY;
96       circuit->metric[i] = DEFAULT_CIRCUIT_METRIC;
97       circuit->te_metric[i] = DEFAULT_CIRCUIT_METRIC;
98     }
99
100   circuit->mtc = mpls_te_circuit_new();
101
102   return circuit;
103 }
104
105 void
106 isis_circuit_del (struct isis_circuit *circuit)
107 {
108   if (!circuit)
109     return;
110
111   isis_circuit_if_unbind (circuit, circuit->interface);
112
113   /* and lastly the circuit itself */
114   XFREE (MTYPE_ISIS_CIRCUIT, circuit);
115
116   return;
117 }
118
119 void
120 isis_circuit_configure (struct isis_circuit *circuit, struct isis_area *area)
121 {
122   assert (area);
123   circuit->area = area;
124
125   /*
126    * Whenever the is-type of an area is changed, the is-type of each circuit
127    * in that area is updated to a non-empty subset of the area is-type.
128    * Inversely, when configuring a new circuit, this property should be
129    * ensured as well.
130    */
131   if (area->is_type != IS_LEVEL_1_AND_2)
132     circuit->is_type = area->is_type;
133
134   /*
135    * Add the circuit into area
136    */
137   listnode_add (area->circuit_list, circuit);
138
139   circuit->idx = flags_get_index (&area->flags);
140
141   return;
142 }
143
144 void
145 isis_circuit_deconfigure (struct isis_circuit *circuit, struct isis_area *area)
146 {
147   /* Free the index of SRM and SSN flags */
148   flags_free_index (&area->flags, circuit->idx);
149   circuit->idx = 0;
150   /* Remove circuit from area */
151   assert (circuit->area == area);
152   listnode_delete (area->circuit_list, circuit);
153   circuit->area = NULL;
154
155   return;
156 }
157
158 struct isis_circuit *
159 circuit_lookup_by_ifp (struct interface *ifp, struct list *list)
160 {
161   struct isis_circuit *circuit = NULL;
162   struct listnode *node;
163
164   if (!list)
165     return NULL;
166
167   for (ALL_LIST_ELEMENTS_RO (list, node, circuit))
168     if (circuit->interface == ifp)
169       {
170         assert (ifp->info == circuit);
171         return circuit;
172       }
173
174   return NULL;
175 }
176
177 struct isis_circuit *
178 circuit_scan_by_ifp (struct interface *ifp)
179 {
180   struct isis_area *area;
181   struct listnode *node;
182   struct isis_circuit *circuit;
183
184   if (ifp->info)
185     return (struct isis_circuit *)ifp->info;
186
187   if (isis->area_list)
188     {
189       for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
190         {
191           circuit = circuit_lookup_by_ifp (ifp, area->circuit_list);
192           if (circuit)
193             return circuit;
194         }
195     }
196   return circuit_lookup_by_ifp (ifp, isis->init_circ_list);
197 }
198
199 void
200 isis_circuit_add_addr (struct isis_circuit *circuit,
201                        struct connected *connected)
202 {
203   struct listnode *node;
204   struct prefix_ipv4 *ipv4;
205   u_char buf[BUFSIZ];
206 #ifdef HAVE_IPV6
207   struct prefix_ipv6 *ipv6;
208 #endif /* HAVE_IPV6 */
209
210   memset (&buf, 0, BUFSIZ);
211   if (connected->address->family == AF_INET)
212     {
213       u_int32_t addr = connected->address->u.prefix4.s_addr;
214       addr = ntohl (addr);
215       if (IPV4_NET0(addr) ||
216           IPV4_NET127(addr) ||
217           IN_CLASSD(addr) ||
218           IPV4_LINKLOCAL(addr))
219         return;
220
221       for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, node, ipv4))
222         if (prefix_same ((struct prefix *) ipv4, connected->address))
223           return;
224
225       ipv4 = prefix_ipv4_new ();
226       ipv4->prefixlen = connected->address->prefixlen;
227       ipv4->prefix = connected->address->u.prefix4;
228       listnode_add (circuit->ip_addrs, ipv4);
229
230       /* Update MPLS TE Local IP address parameter */
231       set_circuitparams_local_ipaddr (circuit->mtc, ipv4->prefix);
232
233       if (circuit->area)
234         lsp_regenerate_schedule (circuit->area, circuit->is_type, 0);
235
236 #ifdef EXTREME_DEBUG
237       prefix2str (connected->address, buf, BUFSIZ);
238       zlog_debug ("Added IP address %s to circuit %d", buf,
239                  circuit->circuit_id);
240 #endif /* EXTREME_DEBUG */
241     }
242 #ifdef HAVE_IPV6
243   if (connected->address->family == AF_INET6)
244     {
245       if (IN6_IS_ADDR_LOOPBACK(&connected->address->u.prefix6))
246         return;
247
248       for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_link, node, ipv6))
249         if (prefix_same ((struct prefix *) ipv6, connected->address))
250           return;
251       for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, node, ipv6))
252         if (prefix_same ((struct prefix *) ipv6, connected->address))
253           return;
254
255       ipv6 = prefix_ipv6_new ();
256       ipv6->prefixlen = connected->address->prefixlen;
257       ipv6->prefix = connected->address->u.prefix6;
258
259       if (IN6_IS_ADDR_LINKLOCAL (&ipv6->prefix))
260         listnode_add (circuit->ipv6_link, ipv6);
261       else
262         listnode_add (circuit->ipv6_non_link, ipv6);
263       if (circuit->area)
264         lsp_regenerate_schedule (circuit->area, circuit->is_type, 0);
265
266 #ifdef EXTREME_DEBUG
267       prefix2str (connected->address, buf, BUFSIZ);
268       zlog_debug ("Added IPv6 address %s to circuit %d", buf,
269                  circuit->circuit_id);
270 #endif /* EXTREME_DEBUG */
271     }
272 #endif /* HAVE_IPV6 */
273   return;
274 }
275
276 void
277 isis_circuit_del_addr (struct isis_circuit *circuit,
278                        struct connected *connected)
279 {
280   struct prefix_ipv4 *ipv4, *ip = NULL;
281   struct listnode *node;
282   u_char buf[BUFSIZ];
283 #ifdef HAVE_IPV6
284   struct prefix_ipv6 *ipv6, *ip6 = NULL;
285   int found = 0;
286 #endif /* HAVE_IPV6 */
287
288   memset (&buf, 0, BUFSIZ);
289   if (connected->address->family == AF_INET)
290     {
291       ipv4 = prefix_ipv4_new ();
292       ipv4->prefixlen = connected->address->prefixlen;
293       ipv4->prefix = connected->address->u.prefix4;
294
295       for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, node, ip))
296         if (prefix_same ((struct prefix *) ip, (struct prefix *) ipv4))
297           break;
298
299       if (ip)
300         {
301           listnode_delete (circuit->ip_addrs, ip);
302           if (circuit->area)
303             lsp_regenerate_schedule (circuit->area, circuit->is_type, 0);
304         }
305       else
306         {
307           prefix2str (connected->address, (char *)buf, BUFSIZ);
308           zlog_warn ("Nonexitant ip address %s removal attempt from \
309                       circuit %d", buf, circuit->circuit_id);
310           zlog_warn ("Current ip addresses on %s:", circuit->interface->name);
311           for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node, ip))
312             {
313               prefix2str((struct prefix*)ip, (char *)buf, BUFSIZ);
314               zlog_warn("  %s", buf);
315             }
316           zlog_warn("End of addresses");
317         }
318
319       prefix_ipv4_free (ipv4);
320     }
321 #ifdef HAVE_IPV6
322   if (connected->address->family == AF_INET6)
323     {
324       ipv6 = prefix_ipv6_new ();
325       ipv6->prefixlen = connected->address->prefixlen;
326       ipv6->prefix = connected->address->u.prefix6;
327
328       if (IN6_IS_ADDR_LINKLOCAL (&ipv6->prefix))
329         {
330           for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_link, node, ip6))
331             {
332               if (prefix_same ((struct prefix *) ip6, (struct prefix *) ipv6))
333                 break;
334             }
335           if (ip6)
336             {
337               listnode_delete (circuit->ipv6_link, ip6);
338               found = 1;
339             }
340         }
341       else
342         {
343           for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, node, ip6))
344             {
345               if (prefix_same ((struct prefix *) ip6, (struct prefix *) ipv6))
346                 break;
347             }
348           if (ip6)
349             {
350               listnode_delete (circuit->ipv6_non_link, ip6);
351               found = 1;
352             }
353         }
354
355       if (!found)
356         {
357           prefix2str (connected->address, (char *)buf, BUFSIZ);
358           zlog_warn ("Nonexitant ip address %s removal attempt from \
359                       circuit %d", buf, circuit->circuit_id);
360           zlog_warn ("Current ip addresses on %s:", circuit->interface->name);
361           for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node, ip6))
362             {
363               prefix2str((struct prefix*)ip6, (char *)buf, BUFSIZ);
364               zlog_warn("  %s", buf);
365             }
366           zlog_warn(" -----");
367           for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node, ip6))
368             {
369               prefix2str((struct prefix*)ip6, (char *)buf, BUFSIZ);
370               zlog_warn("  %s", buf);
371             }
372           zlog_warn("End of addresses");
373         }
374       else if (circuit->area)
375           lsp_regenerate_schedule (circuit->area, circuit->is_type, 0);
376
377       prefix_ipv6_free (ipv6);
378     }
379 #endif /* HAVE_IPV6 */
380   return;
381 }
382
383 static u_char
384 isis_circuit_id_gen (struct interface *ifp)
385 {
386   u_char id = 0;
387   char ifname[16];
388   unsigned int i;
389   int start = -1, end = -1;
390
391   /*
392    * Get a stable circuit id from ifname. This makes
393    * the ifindex from flapping when netdevs are created
394    * and deleted on the fly. Note that this circuit id
395    * is used in pseudo lsps so it is better to be stable.
396    * The following code works on any reasonanle ifname
397    * like: eth1 or trk-1.1 etc.
398    */
399   for (i = 0; i < strlen (ifp->name); i++)
400     {
401       if (isdigit((unsigned char)ifp->name[i]))
402         {
403           if (start < 0)
404             {
405               start = i;
406               end = i + 1;
407             }
408           else
409             {
410               end = i + 1;
411             }
412         }
413       else if (start >= 0)
414         break;
415     }
416
417   if ((start >= 0) && (end >= start) && (end - start) < 16)
418     {
419       memset (ifname, 0, 16);
420       strncpy (ifname, &ifp->name[start], end - start);
421       id = (u_char)atoi(ifname);
422     }
423
424   /* Try to be unique. */
425   if (!id)
426     id = (u_char)((ifp->ifindex & 0xff) | 0x80);
427
428   return id;
429 }
430
431 void
432 isis_circuit_if_add (struct isis_circuit *circuit, struct interface *ifp)
433 {
434   struct listnode *node, *nnode;
435   struct connected *conn;
436
437   circuit->circuit_id = isis_circuit_id_gen (ifp);
438
439   isis_circuit_if_bind (circuit, ifp);
440   /*  isis_circuit_update_addrs (circuit, ifp); */
441
442   if (if_is_broadcast (ifp))
443     {
444       if (circuit->circ_type_config == CIRCUIT_T_P2P)
445         circuit->circ_type = CIRCUIT_T_P2P;
446       else
447         circuit->circ_type = CIRCUIT_T_BROADCAST;
448     }
449   else if (if_is_pointopoint (ifp))
450     {
451       circuit->circ_type = CIRCUIT_T_P2P;
452     }
453   else if (if_is_loopback (ifp))
454     {
455       circuit->circ_type = CIRCUIT_T_LOOPBACK;
456       circuit->is_passive = 1;
457     }
458   else
459     {
460       /* It's normal in case of loopback etc. */
461       if (isis->debugs & DEBUG_EVENTS)
462         zlog_debug ("isis_circuit_if_add: unsupported media");
463       circuit->circ_type = CIRCUIT_T_UNKNOWN;
464     }
465
466   circuit->ip_addrs = list_new ();
467 #ifdef HAVE_IPV6
468   circuit->ipv6_link = list_new ();
469   circuit->ipv6_non_link = list_new ();
470 #endif /* HAVE_IPV6 */
471
472   for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, conn))
473     isis_circuit_add_addr (circuit, conn);
474
475   return;
476 }
477
478 void
479 isis_circuit_if_del (struct isis_circuit *circuit, struct interface *ifp)
480 {
481   struct listnode *node, *nnode;
482   struct connected *conn;
483
484   assert (circuit->interface == ifp);
485
486   /* destroy addresses */
487   for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, conn))
488     isis_circuit_del_addr (circuit, conn);
489
490   if (circuit->ip_addrs)
491     {
492       assert (listcount(circuit->ip_addrs) == 0);
493       list_delete (circuit->ip_addrs);
494       circuit->ip_addrs = NULL;
495     }
496
497 #ifdef HAVE_IPV6
498   if (circuit->ipv6_link)
499     {
500       assert (listcount(circuit->ipv6_link) == 0);
501       list_delete (circuit->ipv6_link);
502       circuit->ipv6_link = NULL;
503     }
504
505   if (circuit->ipv6_non_link)
506     {
507       assert (listcount(circuit->ipv6_non_link) == 0);
508       list_delete (circuit->ipv6_non_link);
509       circuit->ipv6_non_link = NULL;
510     }
511 #endif /* HAVE_IPV6 */
512
513   circuit->circ_type = CIRCUIT_T_UNKNOWN;
514   circuit->circuit_id = 0;
515
516   return;
517 }
518
519 void
520 isis_circuit_if_bind (struct isis_circuit *circuit, struct interface *ifp)
521 {
522   assert (circuit != NULL);
523   assert (ifp != NULL);
524   if (circuit->interface)
525     assert (circuit->interface == ifp);
526   else
527     circuit->interface = ifp;
528   if (ifp->info)
529     assert (ifp->info == circuit);
530   else
531     ifp->info = circuit;
532   isis_link_params_update (circuit, ifp);
533 }
534
535 void
536 isis_circuit_if_unbind (struct isis_circuit *circuit, struct interface *ifp)
537 {
538   assert (circuit != NULL);
539   assert (ifp != NULL);
540   assert (circuit->interface == ifp);
541   assert (ifp->info == circuit);
542   circuit->interface = NULL;
543   ifp->info = NULL;
544 }
545
546 static void
547 isis_circuit_update_all_srmflags (struct isis_circuit *circuit, int is_set)
548 {
549   struct isis_area *area;
550   struct isis_lsp *lsp;
551   dnode_t *dnode, *dnode_next;
552   int level;
553
554   assert (circuit);
555   area = circuit->area;
556   assert (area);
557   for (level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++)
558     {
559       if (level & circuit->is_type)
560         {
561           if (area->lspdb[level - 1] &&
562               dict_count (area->lspdb[level - 1]) > 0)
563             {
564               for (dnode = dict_first (area->lspdb[level - 1]);
565                    dnode != NULL; dnode = dnode_next)
566                 {
567                   dnode_next = dict_next (area->lspdb[level - 1], dnode);
568                   lsp = dnode_get (dnode);
569                   if (is_set)
570                     {
571                       ISIS_SET_FLAG (lsp->SRMflags, circuit);
572                     }
573                   else
574                     {
575                       ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
576                     }
577                 }
578             }
579         }
580     }
581 }
582
583 size_t
584 isis_circuit_pdu_size(struct isis_circuit *circuit)
585 {
586   return ISO_MTU(circuit);
587 }
588
589 void
590 isis_circuit_stream(struct isis_circuit *circuit, struct stream **stream)
591 {
592   size_t stream_size = isis_circuit_pdu_size(circuit);
593
594   if (!*stream)
595     {
596       *stream = stream_new(stream_size);
597     }
598   else
599     {
600       if (STREAM_SIZE(*stream) != stream_size)
601         stream_resize(*stream, stream_size);
602       stream_reset(*stream);
603     }
604 }
605
606 int
607 isis_circuit_up (struct isis_circuit *circuit)
608 {
609   int retv;
610
611   /* Set the flags for all the lsps of the circuit. */
612   isis_circuit_update_all_srmflags (circuit, 1);
613
614   if (circuit->state == C_STATE_UP)
615     return ISIS_OK;
616
617   if (circuit->is_passive)
618     return ISIS_OK;
619
620   if (circuit->area->lsp_mtu > isis_circuit_pdu_size(circuit))
621     {
622       zlog_err("Interface MTU %zu on %s is too low to support area lsp mtu %u!",
623                isis_circuit_pdu_size(circuit), circuit->interface->name,
624                circuit->area->lsp_mtu);
625       isis_circuit_update_all_srmflags(circuit, 0);
626       return ISIS_ERROR;
627     }
628
629   if (circuit->circ_type == CIRCUIT_T_BROADCAST)
630     {
631       /*
632        * Get the Hardware Address
633        */
634       if (circuit->interface->hw_addr_len != ETH_ALEN)
635         {
636           zlog_warn ("unsupported link layer");
637         }
638       else
639         {
640           memcpy (circuit->u.bc.snpa, circuit->interface->hw_addr, ETH_ALEN);
641         }
642 #ifdef EXTREME_DEGUG
643       zlog_debug ("isis_circuit_if_add: if_id %d, isomtu %d snpa %s",
644                   circuit->interface->ifindex, ISO_MTU (circuit),
645                   snpa_print (circuit->u.bc.snpa));
646 #endif /* EXTREME_DEBUG */
647
648       circuit->u.bc.adjdb[0] = list_new ();
649       circuit->u.bc.adjdb[1] = list_new ();
650
651       /*
652        * ISO 10589 - 8.4.1 Enabling of broadcast circuits
653        */
654
655       /* initilizing the hello sending threads
656        * for a broadcast IF
657        */
658
659       /* 8.4.1 a) commence sending of IIH PDUs */
660
661       if (circuit->is_type & IS_LEVEL_1)
662         {
663           thread_add_event (master, send_lan_l1_hello, circuit, 0);
664           circuit->u.bc.lan_neighs[0] = list_new ();
665         }
666
667       if (circuit->is_type & IS_LEVEL_2)
668         {
669           thread_add_event (master, send_lan_l2_hello, circuit, 0);
670           circuit->u.bc.lan_neighs[1] = list_new ();
671         }
672
673       /* 8.4.1 b) FIXME: solicit ES - 8.4.6 */
674       /* 8.4.1 c) FIXME: listen for ESH PDUs */
675
676       /* 8.4.1 d) */
677       /* dr election will commence in... */
678       if (circuit->is_type & IS_LEVEL_1)
679         THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1,
680             circuit, 2 * circuit->hello_interval[0]);
681       if (circuit->is_type & IS_LEVEL_2)
682         THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2,
683             circuit, 2 * circuit->hello_interval[1]);
684     }
685   else
686     {
687       /* initializing the hello send threads
688        * for a ptp IF
689        */
690       circuit->u.p2p.neighbor = NULL;
691       thread_add_event (master, send_p2p_hello, circuit, 0);
692     }
693
694   /* initializing PSNP timers */
695   if (circuit->is_type & IS_LEVEL_1)
696     THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit,
697                      isis_jitter (circuit->psnp_interval[0], PSNP_JITTER));
698
699   if (circuit->is_type & IS_LEVEL_2)
700     THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit,
701                      isis_jitter (circuit->psnp_interval[1], PSNP_JITTER));
702
703   /* unified init for circuits; ignore warnings below this level */
704   retv = isis_sock_init (circuit);
705   if (retv != ISIS_OK)
706     {
707       isis_circuit_down (circuit);
708       return retv;
709     }
710
711   /* initialize the circuit streams after opening connection */
712   isis_circuit_stream(circuit, &circuit->rcv_stream);
713   isis_circuit_stream(circuit, &circuit->snd_stream);
714
715 #ifdef GNU_LINUX
716   THREAD_READ_ON (master, circuit->t_read, isis_receive, circuit,
717                   circuit->fd);
718 #else
719   THREAD_TIMER_ON (master, circuit->t_read, isis_receive, circuit,
720                    circuit->fd);
721 #endif
722
723   circuit->lsp_queue = list_new ();
724   circuit->lsp_queue_last_cleared = time (NULL);
725
726   return ISIS_OK;
727 }
728
729 void
730 isis_circuit_down (struct isis_circuit *circuit)
731 {
732   if (circuit->state != C_STATE_UP)
733     return;
734
735   /* Clear the flags for all the lsps of the circuit. */
736   isis_circuit_update_all_srmflags (circuit, 0);
737
738   if (circuit->circ_type == CIRCUIT_T_BROADCAST)
739     {
740       /* destroy neighbour lists */
741       if (circuit->u.bc.lan_neighs[0])
742         {
743           list_delete (circuit->u.bc.lan_neighs[0]);
744           circuit->u.bc.lan_neighs[0] = NULL;
745         }
746       if (circuit->u.bc.lan_neighs[1])
747         {
748           list_delete (circuit->u.bc.lan_neighs[1]);
749           circuit->u.bc.lan_neighs[1] = NULL;
750         }
751       /* destroy adjacency databases */
752       if (circuit->u.bc.adjdb[0])
753         {
754           circuit->u.bc.adjdb[0]->del = isis_delete_adj;
755           list_delete (circuit->u.bc.adjdb[0]);
756           circuit->u.bc.adjdb[0] = NULL;
757         }
758       if (circuit->u.bc.adjdb[1])
759         {
760           circuit->u.bc.adjdb[1]->del = isis_delete_adj;
761           list_delete (circuit->u.bc.adjdb[1]);
762           circuit->u.bc.adjdb[1] = NULL;
763         }
764       if (circuit->u.bc.is_dr[0])
765         {
766           isis_dr_resign (circuit, 1);
767           circuit->u.bc.is_dr[0] = 0;
768         }
769       memset (circuit->u.bc.l1_desig_is, 0, ISIS_SYS_ID_LEN + 1);
770       if (circuit->u.bc.is_dr[1])
771         {
772           isis_dr_resign (circuit, 2);
773           circuit->u.bc.is_dr[1] = 0;
774         }
775       memset (circuit->u.bc.l2_desig_is, 0, ISIS_SYS_ID_LEN + 1);
776       memset (circuit->u.bc.snpa, 0, ETH_ALEN);
777
778       THREAD_TIMER_OFF (circuit->u.bc.t_send_lan_hello[0]);
779       THREAD_TIMER_OFF (circuit->u.bc.t_send_lan_hello[1]);
780       THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[0]);
781       THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[1]);
782       THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[0]);
783       THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[1]);
784       circuit->lsp_regenerate_pending[0] = 0;
785       circuit->lsp_regenerate_pending[1] = 0;
786     }
787   else if (circuit->circ_type == CIRCUIT_T_P2P)
788     {
789       isis_delete_adj (circuit->u.p2p.neighbor);
790       circuit->u.p2p.neighbor = NULL;
791       THREAD_TIMER_OFF (circuit->u.p2p.t_send_p2p_hello);
792     }
793
794   /* Cancel all active threads */
795   THREAD_TIMER_OFF (circuit->t_send_csnp[0]);
796   THREAD_TIMER_OFF (circuit->t_send_csnp[1]);
797   THREAD_TIMER_OFF (circuit->t_send_psnp[0]);
798   THREAD_TIMER_OFF (circuit->t_send_psnp[1]);
799   THREAD_OFF (circuit->t_read);
800
801   if (circuit->lsp_queue)
802     {
803       circuit->lsp_queue->del = NULL;
804       list_delete (circuit->lsp_queue);
805       circuit->lsp_queue = NULL;
806     }
807
808   /* send one gratuitous hello to spead up convergence */
809   if (circuit->is_type & IS_LEVEL_1)
810     send_hello (circuit, IS_LEVEL_1);
811   if (circuit->is_type & IS_LEVEL_2)
812     send_hello (circuit, IS_LEVEL_2);
813
814   circuit->upadjcount[0] = 0;
815   circuit->upadjcount[1] = 0;
816
817   /* close the socket */
818   if (circuit->fd)
819     {
820       close (circuit->fd);
821       circuit->fd = 0;
822     }
823
824   if (circuit->rcv_stream != NULL)
825     {
826       stream_free (circuit->rcv_stream);
827       circuit->rcv_stream = NULL;
828     }
829
830   if (circuit->snd_stream != NULL)
831     {
832       stream_free (circuit->snd_stream);
833       circuit->snd_stream = NULL;
834     }
835
836   thread_cancel_event (master, circuit);
837
838   return;
839 }
840
841 void
842 circuit_update_nlpids (struct isis_circuit *circuit)
843 {
844   circuit->nlpids.count = 0;
845
846   if (circuit->ip_router)
847     {
848       circuit->nlpids.nlpids[0] = NLPID_IP;
849       circuit->nlpids.count++;
850     }
851 #ifdef HAVE_IPV6
852   if (circuit->ipv6_router)
853     {
854       circuit->nlpids.nlpids[circuit->nlpids.count] = NLPID_IPV6;
855       circuit->nlpids.count++;
856     }
857 #endif /* HAVE_IPV6 */
858   return;
859 }
860
861 void
862 isis_circuit_print_vty (struct isis_circuit *circuit, struct vty *vty,
863                         char detail)
864 {
865   if (detail == ISIS_UI_LEVEL_BRIEF)
866     {
867       vty_out (vty, "  %-12s", circuit->interface->name);
868       vty_out (vty, "0x%-7x", circuit->circuit_id);
869       vty_out (vty, "%-9s", circuit_state2string (circuit->state));
870       vty_out (vty, "%-9s", circuit_type2string (circuit->circ_type));
871       vty_out (vty, "%-9s", circuit_t2string (circuit->is_type));
872       vty_out (vty, "%s", VTY_NEWLINE);
873     }
874
875   if (detail == ISIS_UI_LEVEL_DETAIL)
876     {
877       struct listnode *node;
878       struct prefix *ip_addr;
879       u_char buf[BUFSIZ];
880
881       vty_out (vty, "  Interface: %s", circuit->interface->name);
882       vty_out (vty, ", State: %s", circuit_state2string (circuit->state));
883       if (circuit->is_passive)
884         vty_out (vty, ", Passive");
885       else
886         vty_out (vty, ", Active");
887       vty_out (vty, ", Circuit Id: 0x%x", circuit->circuit_id);
888       vty_out (vty, "%s", VTY_NEWLINE);
889       vty_out (vty, "    Type: %s", circuit_type2string (circuit->circ_type));
890       vty_out (vty, ", Level: %s", circuit_t2string (circuit->is_type));
891       if (circuit->circ_type == CIRCUIT_T_BROADCAST)
892         vty_out (vty, ", SNPA: %-10s", snpa_print (circuit->u.bc.snpa));
893       vty_out (vty, "%s", VTY_NEWLINE);
894       if (circuit->is_type & IS_LEVEL_1)
895         {
896           vty_out (vty, "    Level-1 Information:%s", VTY_NEWLINE);
897           if (circuit->area->newmetric)
898             vty_out (vty, "      Metric: %d", circuit->te_metric[0]);
899           else
900             vty_out (vty, "      Metric: %d",
901                      circuit->metric[0]);
902           if (!circuit->is_passive)
903             {
904               vty_out (vty, ", Active neighbors: %u%s",
905                        circuit->upadjcount[0], VTY_NEWLINE);
906               vty_out (vty, "      Hello interval: %u, "
907                             "Holddown count: %u %s%s",
908                        circuit->hello_interval[0],
909                        circuit->hello_multiplier[0],
910                        (circuit->pad_hellos ? "(pad)" : "(no-pad)"),
911                        VTY_NEWLINE);
912               vty_out (vty, "      CNSP interval: %u, "
913                             "PSNP interval: %u%s",
914                        circuit->csnp_interval[0],
915                        circuit->psnp_interval[0], VTY_NEWLINE);
916               if (circuit->circ_type == CIRCUIT_T_BROADCAST)
917                 vty_out (vty, "      LAN Priority: %u, %s%s",
918                          circuit->priority[0],
919                          (circuit->u.bc.is_dr[0] ? \
920                           "is DIS" : "is not DIS"), VTY_NEWLINE);
921             }
922           else
923             {
924               vty_out (vty, "%s", VTY_NEWLINE);
925             }
926         }
927       if (circuit->is_type & IS_LEVEL_2)
928         {
929           vty_out (vty, "    Level-2 Information:%s", VTY_NEWLINE);
930           if (circuit->area->newmetric)
931             vty_out (vty, "      Metric: %d", circuit->te_metric[1]);
932           else
933             vty_out (vty, "      Metric: %d",
934                      circuit->metric[1]);
935           if (!circuit->is_passive)
936             {
937               vty_out (vty, ", Active neighbors: %u%s",
938                        circuit->upadjcount[1], VTY_NEWLINE);
939               vty_out (vty, "      Hello interval: %u, "
940                             "Holddown count: %u %s%s",
941                        circuit->hello_interval[1],
942                        circuit->hello_multiplier[1],
943                        (circuit->pad_hellos ? "(pad)" : "(no-pad)"),
944                        VTY_NEWLINE);
945               vty_out (vty, "      CNSP interval: %u, "
946                             "PSNP interval: %u%s",
947                        circuit->csnp_interval[1],
948                        circuit->psnp_interval[1], VTY_NEWLINE);
949               if (circuit->circ_type == CIRCUIT_T_BROADCAST)
950                 vty_out (vty, "      LAN Priority: %u, %s%s",
951                          circuit->priority[1],
952                          (circuit->u.bc.is_dr[1] ? \
953                           "is DIS" : "is not DIS"), VTY_NEWLINE);
954             }
955           else
956             {
957               vty_out (vty, "%s", VTY_NEWLINE);
958             }
959         }
960       if (circuit->ip_addrs && listcount (circuit->ip_addrs) > 0)
961         {
962           vty_out (vty, "    IP Prefix(es):%s", VTY_NEWLINE);
963           for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, node, ip_addr))
964             {
965               prefix2str (ip_addr, (char*)buf, BUFSIZ),
966               vty_out (vty, "      %s%s", buf, VTY_NEWLINE);
967             }
968         }
969       if (circuit->ipv6_link && listcount(circuit->ipv6_link) > 0)
970         {
971           vty_out(vty, "    IPv6 Link-Locals:%s", VTY_NEWLINE);
972           for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node, ip_addr))
973             {
974               prefix2str(ip_addr, (char*)buf, BUFSIZ),
975               vty_out(vty, "      %s%s", buf, VTY_NEWLINE);
976             }
977         }
978       if (circuit->ipv6_non_link && listcount(circuit->ipv6_non_link) > 0)
979         {
980           vty_out(vty, "    IPv6 Prefixes:%s", VTY_NEWLINE);
981           for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node, ip_addr))
982             {
983               prefix2str(ip_addr, (char*)buf, BUFSIZ),
984               vty_out(vty, "      %s%s", buf, VTY_NEWLINE);
985             }
986         }
987
988       vty_out (vty, "%s", VTY_NEWLINE);
989     }
990   return;
991 }
992
993 int
994 isis_interface_config_write (struct vty *vty)
995 {
996   int write = 0;
997   struct listnode *node, *node2;
998   struct interface *ifp;
999   struct isis_area *area;
1000   struct isis_circuit *circuit;
1001   int i;
1002
1003   for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
1004     {
1005       /* IF name */
1006       vty_out (vty, "interface %s%s", ifp->name, VTY_NEWLINE);
1007       write++;
1008       /* IF desc */
1009       if (ifp->desc)
1010         {
1011           vty_out (vty, " description %s%s", ifp->desc, VTY_NEWLINE);
1012           write++;
1013         }
1014       /* ISIS Circuit */
1015       for (ALL_LIST_ELEMENTS_RO (isis->area_list, node2, area))
1016         {
1017           circuit = circuit_lookup_by_ifp (ifp, area->circuit_list);
1018           if (circuit == NULL)
1019             continue;
1020           if (circuit->ip_router)
1021             {
1022               vty_out (vty, " ip router isis %s%s", area->area_tag,
1023                        VTY_NEWLINE);
1024               write++;
1025             }
1026           if (circuit->is_passive)
1027             {
1028               vty_out (vty, " isis passive%s", VTY_NEWLINE);
1029               write++;
1030             }
1031           if (circuit->circ_type_config == CIRCUIT_T_P2P)
1032             {
1033               vty_out (vty, " isis network point-to-point%s", VTY_NEWLINE);
1034               write++;
1035             }
1036 #ifdef HAVE_IPV6
1037           if (circuit->ipv6_router)
1038             {
1039               vty_out (vty, " ipv6 router isis %s%s", area->area_tag,
1040                   VTY_NEWLINE);
1041               write++;
1042             }
1043 #endif /* HAVE_IPV6 */
1044
1045           /* ISIS - circuit type */
1046           if (circuit->is_type == IS_LEVEL_1)
1047             {
1048               vty_out (vty, " isis circuit-type level-1%s", VTY_NEWLINE);
1049               write++;
1050             }
1051           else
1052             {
1053               if (circuit->is_type == IS_LEVEL_2)
1054                 {
1055                   vty_out (vty, " isis circuit-type level-2-only%s",
1056                            VTY_NEWLINE);
1057                   write++;
1058                 }
1059             }
1060
1061           /* ISIS - CSNP interval */
1062           if (circuit->csnp_interval[0] == circuit->csnp_interval[1])
1063             {
1064               if (circuit->csnp_interval[0] != DEFAULT_CSNP_INTERVAL)
1065                 {
1066                   vty_out (vty, " isis csnp-interval %d%s",
1067                            circuit->csnp_interval[0], VTY_NEWLINE);
1068                   write++;
1069                 }
1070             }
1071           else
1072           {
1073             for (i = 0; i < 2; i++)
1074               {
1075                 if (circuit->csnp_interval[i] != DEFAULT_CSNP_INTERVAL)
1076                   {
1077                     vty_out (vty, " isis csnp-interval %d level-%d%s",
1078                              circuit->csnp_interval[i], i + 1, VTY_NEWLINE);
1079                     write++;
1080                   }
1081               }
1082           }
1083
1084           /* ISIS - PSNP interval */
1085           if (circuit->psnp_interval[0] == circuit->psnp_interval[1])
1086             {
1087               if (circuit->psnp_interval[0] != DEFAULT_PSNP_INTERVAL)
1088                 {
1089                   vty_out (vty, " isis psnp-interval %d%s",
1090                            circuit->psnp_interval[0], VTY_NEWLINE);
1091                   write++;
1092                 }
1093             }
1094           else
1095             {
1096               for (i = 0; i < 2; i++)
1097                 {
1098                   if (circuit->psnp_interval[i] != DEFAULT_PSNP_INTERVAL)
1099                   {
1100                     vty_out (vty, " isis psnp-interval %d level-%d%s",
1101                              circuit->psnp_interval[i], i + 1, VTY_NEWLINE);
1102                     write++;
1103                   }
1104                 }
1105             }
1106
1107           /* ISIS - Hello padding - Defaults to true so only display if false */
1108           if (circuit->pad_hellos == 0)
1109             {
1110               vty_out (vty, " no isis hello padding%s", VTY_NEWLINE);
1111               write++;
1112             }
1113
1114           /* ISIS - Hello interval */
1115           if (circuit->hello_interval[0] == circuit->hello_interval[1])
1116             {
1117               if (circuit->hello_interval[0] != DEFAULT_HELLO_INTERVAL)
1118                 {
1119                   vty_out (vty, " isis hello-interval %d%s",
1120                            circuit->hello_interval[0], VTY_NEWLINE);
1121                   write++;
1122                 }
1123             }
1124           else
1125             {
1126               for (i = 0; i < 2; i++)
1127                 {
1128                   if (circuit->hello_interval[i] != DEFAULT_HELLO_INTERVAL)
1129                     {
1130                       vty_out (vty, " isis hello-interval %d level-%d%s",
1131                                circuit->hello_interval[i], i + 1, VTY_NEWLINE);
1132                       write++;
1133                     }
1134                 }
1135             }
1136
1137           /* ISIS - Hello Multiplier */
1138           if (circuit->hello_multiplier[0] == circuit->hello_multiplier[1])
1139             {
1140               if (circuit->hello_multiplier[0] != DEFAULT_HELLO_MULTIPLIER)
1141                 {
1142                   vty_out (vty, " isis hello-multiplier %d%s",
1143                            circuit->hello_multiplier[0], VTY_NEWLINE);
1144                   write++;
1145                 }
1146             }
1147           else
1148             {
1149               for (i = 0; i < 2; i++)
1150                 {
1151                   if (circuit->hello_multiplier[i] != DEFAULT_HELLO_MULTIPLIER)
1152                     {
1153                       vty_out (vty, " isis hello-multiplier %d level-%d%s",
1154                                circuit->hello_multiplier[i], i + 1,
1155                                VTY_NEWLINE);
1156                       write++;
1157                     }
1158                 }
1159             }
1160
1161           /* ISIS - Priority */
1162           if (circuit->priority[0] == circuit->priority[1])
1163             {
1164               if (circuit->priority[0] != DEFAULT_PRIORITY)
1165                 {
1166                   vty_out (vty, " isis priority %d%s",
1167                            circuit->priority[0], VTY_NEWLINE);
1168                   write++;
1169                 }
1170             }
1171           else
1172             {
1173               for (i = 0; i < 2; i++)
1174                 {
1175                   if (circuit->priority[i] != DEFAULT_PRIORITY)
1176                     {
1177                       vty_out (vty, " isis priority %d level-%d%s",
1178                                circuit->priority[i], i + 1, VTY_NEWLINE);
1179                       write++;
1180                     }
1181                 }
1182             }
1183
1184           /* ISIS - Metric */
1185           if (circuit->te_metric[0] == circuit->te_metric[1])
1186             {
1187               if (circuit->te_metric[0] != DEFAULT_CIRCUIT_METRIC)
1188                 {
1189                   vty_out (vty, " isis metric %d%s", circuit->te_metric[0],
1190                            VTY_NEWLINE);
1191                   write++;
1192                 }
1193             }
1194           else
1195             {
1196               for (i = 0; i < 2; i++)
1197                 {
1198                   if (circuit->te_metric[i] != DEFAULT_CIRCUIT_METRIC)
1199                     {
1200                       vty_out (vty, " isis metric %d level-%d%s",
1201                                circuit->te_metric[i], i + 1, VTY_NEWLINE);
1202                       write++;
1203                     }
1204                 }
1205             }
1206           if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5)
1207             {
1208               vty_out (vty, " isis password md5 %s%s", circuit->passwd.passwd,
1209                        VTY_NEWLINE);
1210               write++;
1211             }
1212           else if (circuit->passwd.type == ISIS_PASSWD_TYPE_CLEARTXT)
1213             {
1214               vty_out (vty, " isis password clear %s%s", circuit->passwd.passwd,
1215                        VTY_NEWLINE);
1216               write++;
1217             }
1218         }
1219       vty_out (vty, "!%s", VTY_NEWLINE);
1220     }
1221
1222   return write;
1223 }
1224
1225 struct isis_circuit *
1226 isis_circuit_create (struct isis_area *area, struct interface *ifp)
1227 {
1228   struct isis_circuit *circuit = circuit_scan_by_ifp (ifp);
1229   if (circuit && circuit->area)
1230     return NULL;
1231   circuit = isis_csm_state_change (ISIS_ENABLE, circuit, area);
1232   if (circuit->state != C_STATE_CONF && circuit->state != C_STATE_UP)
1233     return circuit;
1234   isis_circuit_if_bind (circuit, ifp);
1235   return circuit;
1236 }
1237
1238 void
1239 isis_circuit_af_set (struct isis_circuit *circuit, bool ip_router, bool ipv6_router)
1240 {
1241   struct isis_area *area = circuit->area;
1242   bool change = circuit->ip_router != ip_router || circuit->ipv6_router != ipv6_router;
1243   bool was_enabled = !!circuit->area;
1244
1245   area->ip_circuits   += ip_router   - circuit->ip_router;
1246   area->ipv6_circuits += ipv6_router - circuit->ipv6_router;
1247   circuit->ip_router   = ip_router;
1248   circuit->ipv6_router = ipv6_router;
1249
1250   if (!change)
1251     return;
1252
1253   circuit_update_nlpids (circuit);
1254
1255   if (!ip_router && !ipv6_router)
1256     isis_csm_state_change (ISIS_DISABLE, circuit, area);
1257   else if (!was_enabled)
1258     isis_csm_state_change (ISIS_ENABLE, circuit, area);
1259   else
1260     lsp_regenerate_schedule(circuit->area, circuit->is_type, 0);
1261 }
1262
1263 int
1264 isis_circuit_passive_set (struct isis_circuit *circuit, bool passive)
1265 {
1266   if (circuit->is_passive == passive)
1267     return 0;
1268
1269   if (if_is_loopback (circuit->interface) && !passive)
1270     return -1;
1271
1272   if (circuit->state != C_STATE_UP)
1273     {
1274       circuit->is_passive = passive;
1275     }
1276   else
1277     {
1278       struct isis_area *area = circuit->area;
1279       isis_csm_state_change (ISIS_DISABLE, circuit, area);
1280       circuit->is_passive = passive;
1281       isis_csm_state_change (ISIS_ENABLE, circuit, area);
1282     }
1283
1284   return 0;
1285 }
1286
1287 int
1288 isis_circuit_metric_set (struct isis_circuit *circuit, int level, int metric)
1289 {
1290   assert (level == IS_LEVEL_1 || level == IS_LEVEL_2);
1291   if (metric > MAX_WIDE_LINK_METRIC)
1292     return -1;
1293   if (circuit->area && circuit->area->oldmetric
1294       && metric > MAX_NARROW_LINK_METRIC)
1295     return -1;
1296
1297   circuit->te_metric[level - 1] = metric;
1298   circuit->metric[level - 1] = metric;
1299
1300   if (circuit->area)
1301     lsp_regenerate_schedule (circuit->area, level, 0);
1302   return 0;
1303 }
1304
1305 int
1306 isis_circuit_passwd_unset (struct isis_circuit *circuit)
1307 {
1308   memset(&circuit->passwd, 0, sizeof(circuit->passwd));
1309   return 0;
1310 }
1311
1312 static int
1313 isis_circuit_passwd_set (struct isis_circuit *circuit, u_char passwd_type, const char *passwd)
1314 {
1315   int len;
1316
1317   if (!passwd)
1318     return -1;
1319
1320   len = strlen(passwd);
1321   if (len > 254)
1322     return -1;
1323
1324   circuit->passwd.len = len;
1325   strncpy((char *)circuit->passwd.passwd, passwd, 255);
1326   circuit->passwd.type = passwd_type;
1327   return 0;
1328 }
1329
1330 int
1331 isis_circuit_passwd_cleartext_set (struct isis_circuit *circuit, const char *passwd)
1332 {
1333   return isis_circuit_passwd_set (circuit, ISIS_PASSWD_TYPE_CLEARTXT, passwd);
1334 }
1335
1336 int
1337 isis_circuit_passwd_hmac_md5_set (struct isis_circuit *circuit, const char *passwd)
1338 {
1339   return isis_circuit_passwd_set (circuit, ISIS_PASSWD_TYPE_HMAC_MD5, passwd);
1340 }
1341 struct cmd_node interface_node = {
1342   INTERFACE_NODE,
1343   "%s(config-if)# ",
1344   1,
1345 };
1346
1347 int
1348 isis_circuit_circ_type_set(struct isis_circuit *circuit, int circ_type)
1349 {
1350   /* Changing the network type to/of loopback or unknown interfaces
1351    * is not supported. */
1352   if (circ_type == CIRCUIT_T_UNKNOWN
1353       || circ_type == CIRCUIT_T_LOOPBACK
1354       || circuit->circ_type == CIRCUIT_T_LOOPBACK)
1355     {
1356       if (circuit->circ_type != circ_type)
1357         return -1;
1358       else
1359         return 0;
1360     }
1361
1362   if (circuit->circ_type == circ_type)
1363     return 0;
1364
1365   if (circuit->state != C_STATE_UP)
1366     {
1367       circuit->circ_type = circ_type;
1368       circuit->circ_type_config = circ_type;
1369     }
1370   else
1371     {
1372       struct isis_area *area = circuit->area;
1373       if (circ_type == CIRCUIT_T_BROADCAST
1374           && !if_is_broadcast(circuit->interface))
1375         return -1;
1376
1377       isis_csm_state_change(ISIS_DISABLE, circuit, area);
1378       circuit->circ_type = circ_type;
1379       circuit->circ_type_config = circ_type;
1380       isis_csm_state_change(ISIS_ENABLE, circuit, area);
1381     }
1382   return 0;
1383 }
1384
1385 int
1386 isis_if_new_hook (struct interface *ifp)
1387 {
1388   return 0;
1389 }
1390
1391 int
1392 isis_if_delete_hook (struct interface *ifp)
1393 {
1394   struct isis_circuit *circuit;
1395   /* Clean up the circuit data */
1396   if (ifp && ifp->info)
1397     {
1398       circuit = ifp->info;
1399       isis_csm_state_change (IF_DOWN_FROM_Z, circuit, circuit->area);
1400       isis_csm_state_change (ISIS_DISABLE, circuit, circuit->area);
1401     }
1402
1403   return 0;
1404 }
1405
1406 void
1407 isis_circuit_init ()
1408 {
1409   /* Initialize Zebra interface data structure */
1410   if_add_hook (IF_NEW_HOOK, isis_if_new_hook);
1411   if_add_hook (IF_DELETE_HOOK, isis_if_delete_hook);
1412
1413   /* Install interface node */
1414   install_node (&interface_node, isis_interface_config_write);
1415   install_element (CONFIG_NODE, &interface_cmd);
1416   install_element (CONFIG_NODE, &no_interface_cmd);
1417
1418   install_default (INTERFACE_NODE);
1419   install_element (INTERFACE_NODE, &interface_desc_cmd);
1420   install_element (INTERFACE_NODE, &no_interface_desc_cmd);
1421
1422   isis_vty_init ();
1423 }