Import Upstream version 1.2.2
[quagga-debian.git] / isisd / isis_lsp.c
1 /*
2  * IS-IS Rout(e)ing protocol - isis_lsp.c
3  *                             LSP processing
4  *
5  * Copyright (C) 2001,2002   Sampo Saaristo
6  *                           Tampere University of Technology      
7  *                           Institute of Communications Engineering
8  * Copyright (C) 2013-2015   Christian Franke <chris@opensourcerouting.org>
9  *
10  * This program is free software; you can redistribute it and/or modify it 
11  * under the terms of the GNU General Public License as published by the Free 
12  * Software Foundation; either version 2 of the License, or (at your option) 
13  * any later version.
14  *
15  * This program is distributed in the hope that it will be useful,but WITHOUT 
16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
17  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
18  * more details.
19
20  * You should have received a copy of the GNU General Public License along 
21  * with this program; if not, write to the Free Software Foundation, Inc., 
22  * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #include <zebra.h>
26
27 #include "linklist.h"
28 #include "thread.h"
29 #include "vty.h"
30 #include "stream.h"
31 #include "memory.h"
32 #include "log.h"
33 #include "prefix.h"
34 #include "command.h"
35 #include "hash.h"
36 #include "if.h"
37 #include "checksum.h"
38 #include "md5.h"
39 #include "table.h"
40
41 #include "isisd/dict.h"
42 #include "isisd/isis_constants.h"
43 #include "isisd/isis_common.h"
44 #include "isisd/isis_flags.h"
45 #include "isisd/isis_circuit.h"
46 #include "isisd/isisd.h"
47 #include "isisd/isis_tlv.h"
48 #include "isisd/isis_lsp.h"
49 #include "isisd/isis_pdu.h"
50 #include "isisd/isis_dynhn.h"
51 #include "isisd/isis_misc.h"
52 #include "isisd/isis_csm.h"
53 #include "isisd/isis_adjacency.h"
54 #include "isisd/isis_spf.h"
55 #include "isisd/isis_te.h"
56
57 #ifdef TOPOLOGY_GENERATE
58 #include "spgrid.h"
59 #endif
60
61 /* staticly assigned vars for printing purposes */
62 char lsp_bits_string[200];     /* FIXME: enough ? */
63
64 static int lsp_l1_refresh (struct thread *thread);
65 static int lsp_l2_refresh (struct thread *thread);
66 static int lsp_l1_refresh_pseudo (struct thread *thread);
67 static int lsp_l2_refresh_pseudo (struct thread *thread);
68
69 int
70 lsp_id_cmp (u_char * id1, u_char * id2)
71 {
72   return memcmp (id1, id2, ISIS_SYS_ID_LEN + 2);
73 }
74
75 dict_t *
76 lsp_db_init (void)
77 {
78   dict_t *dict;
79
80   dict = dict_create (DICTCOUNT_T_MAX, (dict_comp_t) lsp_id_cmp);
81
82   return dict;
83 }
84
85 struct isis_lsp *
86 lsp_search (u_char * id, dict_t * lspdb)
87 {
88   dnode_t *node;
89
90 #ifdef EXTREME_DEBUG
91   dnode_t *dn;
92
93   zlog_debug ("searching db");
94   for (dn = dict_first (lspdb); dn; dn = dict_next (lspdb, dn))
95     {
96       zlog_debug ("%s\t%pX", rawlspid_print ((u_char *) dnode_getkey (dn)),
97                   dnode_get (dn));
98     }
99 #endif /* EXTREME DEBUG */
100
101   node = dict_lookup (lspdb, id);
102
103   if (node)
104     return (struct isis_lsp *) dnode_get (node);
105
106   return NULL;
107 }
108
109 static void
110 lsp_clear_data (struct isis_lsp *lsp)
111 {
112   if (!lsp)
113     return;
114
115   if (lsp->tlv_data.hostname)
116     isis_dynhn_remove (lsp->lsp_header->lsp_id);
117
118   if (lsp->own_lsp)
119     {
120       if (lsp->tlv_data.nlpids)
121         XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.nlpids);
122       if (lsp->tlv_data.hostname)
123         XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.hostname);
124       if (lsp->tlv_data.router_id)
125         XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.router_id);
126     }
127
128   free_tlvs (&lsp->tlv_data);
129 }
130
131 static void
132 lsp_destroy (struct isis_lsp *lsp)
133 {
134   struct listnode *cnode, *lnode, *lnnode;
135   struct isis_lsp *lsp_in_list;
136   struct isis_circuit *circuit;
137
138   if (!lsp)
139     return;
140
141   if (lsp->area->circuit_list) {
142     for (ALL_LIST_ELEMENTS_RO (lsp->area->circuit_list, cnode, circuit))
143       {
144         if (circuit->lsp_queue == NULL)
145           continue;
146         for (ALL_LIST_ELEMENTS (circuit->lsp_queue, lnode, lnnode, lsp_in_list))
147           if (lsp_in_list == lsp)
148             list_delete_node(circuit->lsp_queue, lnode);
149       }
150   }
151   ISIS_FLAGS_CLEAR_ALL (lsp->SSNflags);
152   ISIS_FLAGS_CLEAR_ALL (lsp->SRMflags);
153
154   lsp_clear_data (lsp);
155
156   if (LSP_FRAGMENT (lsp->lsp_header->lsp_id) == 0 && lsp->lspu.frags)
157     {
158       list_delete (lsp->lspu.frags);
159       lsp->lspu.frags = NULL;
160     }
161
162   isis_spf_schedule (lsp->area, lsp->level);
163 #ifdef HAVE_IPV6
164   isis_spf_schedule6 (lsp->area, lsp->level);
165 #endif
166
167   if (lsp->pdu)
168     stream_free (lsp->pdu);
169   XFREE (MTYPE_ISIS_LSP, lsp);
170 }
171
172 void
173 lsp_db_destroy (dict_t * lspdb)
174 {
175   dnode_t *dnode, *next;
176   struct isis_lsp *lsp;
177
178   dnode = dict_first (lspdb);
179   while (dnode)
180     {
181       next = dict_next (lspdb, dnode);
182       lsp = dnode_get (dnode);
183       lsp_destroy (lsp);
184       dict_delete_free (lspdb, dnode);
185       dnode = next;
186     }
187
188   dict_free (lspdb);
189
190   return;
191 }
192
193 /*
194  * Remove all the frags belonging to the given lsp
195  */
196 static void
197 lsp_remove_frags (struct list *frags, dict_t * lspdb)
198 {
199   dnode_t *dnode;
200   struct listnode *lnode, *lnnode;
201   struct isis_lsp *lsp;
202
203   for (ALL_LIST_ELEMENTS (frags, lnode, lnnode, lsp))
204     {
205       dnode = dict_lookup (lspdb, lsp->lsp_header->lsp_id);
206       lsp_destroy (lsp);
207       dnode_destroy (dict_delete (lspdb, dnode));
208     }
209
210   list_delete_all_node (frags);
211
212   return;
213 }
214
215 void
216 lsp_search_and_destroy (u_char * id, dict_t * lspdb)
217 {
218   dnode_t *node;
219   struct isis_lsp *lsp;
220
221   node = dict_lookup (lspdb, id);
222   if (node)
223     {
224       node = dict_delete (lspdb, node);
225       lsp = dnode_get (node);
226       /*
227        * If this is a zero lsp, remove all the frags now 
228        */
229       if (LSP_FRAGMENT (lsp->lsp_header->lsp_id) == 0)
230         {
231           if (lsp->lspu.frags)
232             lsp_remove_frags (lsp->lspu.frags, lspdb);
233         }
234       else
235         {
236           /* 
237            * else just remove this frag, from the zero lsps' frag list
238            */
239           if (lsp->lspu.zero_lsp && lsp->lspu.zero_lsp->lspu.frags)
240             listnode_delete (lsp->lspu.zero_lsp->lspu.frags, lsp);
241         }
242       lsp_destroy (lsp);
243       dnode_destroy (node);
244     }
245 }
246
247 /*
248  * Compares a LSP to given values
249  * Params are given in net order
250  */
251 int
252 lsp_compare (char *areatag, struct isis_lsp *lsp, u_int32_t seq_num,
253              u_int16_t checksum, u_int16_t rem_lifetime)
254 {
255   /* no point in double ntohl on seqnum */
256   if (lsp->lsp_header->seq_num == seq_num &&
257       lsp->lsp_header->checksum == checksum &&
258       /*comparing with 0, no need to do ntohl */
259       ((lsp->lsp_header->rem_lifetime == 0 && rem_lifetime == 0) ||
260        (lsp->lsp_header->rem_lifetime != 0 && rem_lifetime != 0)))
261     {
262       if (isis->debugs & DEBUG_SNP_PACKETS)
263         {
264           zlog_debug ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x,"
265                       " lifetime %us",
266                       areatag,
267                       rawlspid_print (lsp->lsp_header->lsp_id),
268                       ntohl (lsp->lsp_header->seq_num),
269                       ntohs (lsp->lsp_header->checksum),
270                       ntohs (lsp->lsp_header->rem_lifetime));
271           zlog_debug ("ISIS-Snp (%s):         is equal to ours seq 0x%08x,"
272                       " cksum 0x%04x, lifetime %us",
273                       areatag,
274                       ntohl (seq_num), ntohs (checksum), ntohs (rem_lifetime));
275         }
276       return LSP_EQUAL;
277     }
278
279   /*
280    * LSPs with identical checksums should only be treated as newer if:
281    * a) The current LSP has a remaining lifetime != 0 and the other LSP has a
282    *    remaining lifetime == 0. In this case, we should participate in the purge
283    *    and should not treat the current LSP with remaining lifetime == 0 as older.
284    * b) The LSP has an incorrect checksum. In this case, we need to react as given
285    *    in 7.3.16.2.
286    */
287    if (ntohl (seq_num) > ntohl (lsp->lsp_header->seq_num)
288       || (ntohl(seq_num) == ntohl(lsp->lsp_header->seq_num)
289           && (  (lsp->lsp_header->rem_lifetime != 0
290                  && rem_lifetime == 0)
291               || lsp->lsp_header->checksum != checksum)))
292     {
293       if (isis->debugs & DEBUG_SNP_PACKETS)
294         {
295           zlog_debug ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x,"
296                       " lifetime %us",
297                       areatag,
298                       rawlspid_print (lsp->lsp_header->lsp_id),
299                       ntohl (seq_num), ntohs (checksum), ntohs (rem_lifetime));
300           zlog_debug ("ISIS-Snp (%s):       is newer than ours seq 0x%08x, "
301                       "cksum 0x%04x, lifetime %us",
302                       areatag,
303                       ntohl (lsp->lsp_header->seq_num),
304                       ntohs (lsp->lsp_header->checksum),
305                       ntohs (lsp->lsp_header->rem_lifetime));
306         }
307       return LSP_NEWER;
308     }
309   if (isis->debugs & DEBUG_SNP_PACKETS)
310     {
311       zlog_debug
312         ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x, lifetime %us",
313          areatag, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (seq_num),
314          ntohs (checksum), ntohs (rem_lifetime));
315       zlog_debug ("ISIS-Snp (%s):       is older than ours seq 0x%08x,"
316                   " cksum 0x%04x, lifetime %us", areatag,
317                   ntohl (lsp->lsp_header->seq_num),
318                   ntohs (lsp->lsp_header->checksum),
319                   ntohs (lsp->lsp_header->rem_lifetime));
320     }
321
322   return LSP_OLDER;
323 }
324
325 static void
326 lsp_auth_add (struct isis_lsp *lsp)
327 {
328   struct isis_passwd *passwd;
329   unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
330
331   /*
332    * Add the authentication info if its present
333    */
334   (lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd) :
335                                (passwd = &lsp->area->domain_passwd);
336   switch (passwd->type)
337     {
338       /* Cleartext */
339       case ISIS_PASSWD_TYPE_CLEARTXT:
340         memcpy (&lsp->tlv_data.auth_info, passwd, sizeof (struct isis_passwd));
341         tlv_add_authinfo (passwd->type, passwd->len, passwd->passwd, lsp->pdu);
342         break;
343
344       /* HMAC MD5 */
345       case ISIS_PASSWD_TYPE_HMAC_MD5:
346         /* Remember where TLV is written so we can later
347          * overwrite the MD5 hash */
348         lsp->auth_tlv_offset = stream_get_endp (lsp->pdu);
349         memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
350         lsp->tlv_data.auth_info.type = ISIS_PASSWD_TYPE_HMAC_MD5;
351         lsp->tlv_data.auth_info.len = ISIS_AUTH_MD5_SIZE;
352         memcpy (&lsp->tlv_data.auth_info.passwd, hmac_md5_hash,
353                 ISIS_AUTH_MD5_SIZE);
354         tlv_add_authinfo (passwd->type, ISIS_AUTH_MD5_SIZE, hmac_md5_hash,
355                           lsp->pdu);
356         break;
357
358       default:
359         break;
360     }
361 }
362
363 static void
364 lsp_auth_update (struct isis_lsp *lsp)
365 {
366   struct isis_passwd *passwd;
367   unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
368   uint16_t checksum, rem_lifetime;
369
370   /* For HMAC MD5 we need to recompute the md5 hash and store it */
371   (lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd) :
372                                (passwd = &lsp->area->domain_passwd);
373   if (passwd->type != ISIS_PASSWD_TYPE_HMAC_MD5)
374     return;
375
376   /*
377    * In transient conditions (when net is configured where authentication
378    * config and lsp regenerate schedule is not yet run), there could be
379    * an own_lsp with auth_tlv_offset set to 0. In such a case, simply
380    * return, when lsp_regenerate is run, lsp will have auth tlv.
381    */
382   if (lsp->auth_tlv_offset == 0)
383     return;
384
385   /*
386    * RFC 5304 set auth value, checksum and remaining lifetime to zero
387    * before computation and reset to old values after computation.
388    */
389   checksum = lsp->lsp_header->checksum;
390   rem_lifetime = lsp->lsp_header->rem_lifetime;
391   lsp->lsp_header->checksum = 0;
392   lsp->lsp_header->rem_lifetime = 0;
393   /* Set the authentication value as well to zero */
394   memset (STREAM_DATA (lsp->pdu) + lsp->auth_tlv_offset + 3,
395           0, ISIS_AUTH_MD5_SIZE);
396   /* Compute autentication value */
397   hmac_md5 (STREAM_DATA (lsp->pdu), stream_get_endp(lsp->pdu),
398             (unsigned char *) &passwd->passwd, passwd->len,
399             (unsigned char *) &hmac_md5_hash);
400   /* Copy the hash into the stream */
401   memcpy (STREAM_DATA (lsp->pdu) + lsp->auth_tlv_offset + 3,
402           hmac_md5_hash, ISIS_AUTH_MD5_SIZE);
403   memcpy (&lsp->tlv_data.auth_info.passwd, hmac_md5_hash,
404           ISIS_AUTH_MD5_SIZE);
405   /* Copy back the checksum and remaining lifetime */
406   lsp->lsp_header->checksum = checksum;
407   lsp->lsp_header->rem_lifetime = rem_lifetime;
408 }
409
410 void
411 lsp_inc_seqnum (struct isis_lsp *lsp, u_int32_t seq_num)
412 {
413   u_int32_t newseq;
414
415   if (seq_num == 0 || ntohl (lsp->lsp_header->seq_num) > seq_num)
416     newseq = ntohl (lsp->lsp_header->seq_num) + 1;
417   else
418     newseq = seq_num + 1;
419
420   lsp->lsp_header->seq_num = htonl (newseq);
421
422   /* Recompute authentication and checksum information */
423   lsp_auth_update (lsp);
424   /* ISO 10589 - 7.3.11 Generation of the checksum
425    * The checksum shall be computed over all fields in the LSP which appear
426    * after the Remaining Lifetime field. This field (and those appearing
427    * before it) are excluded so that the LSP may be aged by systems without
428    * requiring recomputation.
429    */
430   fletcher_checksum(STREAM_DATA (lsp->pdu) + 12,
431                     ntohs (lsp->lsp_header->pdu_len) - 12, 12);
432
433   isis_spf_schedule (lsp->area, lsp->level);
434 #ifdef HAVE_IPV6
435   isis_spf_schedule6 (lsp->area, lsp->level);
436 #endif
437
438   return;
439 }
440
441 /*
442  * Genetates checksum for LSP and its frags
443  */
444 static void
445 lsp_seqnum_update (struct isis_lsp *lsp0)
446 {
447   struct isis_lsp *lsp;
448   struct listnode *node;
449
450   lsp_inc_seqnum (lsp0, 0);
451
452   if (!lsp0->lspu.frags)
453     return;
454
455   for (ALL_LIST_ELEMENTS_RO (lsp0->lspu.frags, node, lsp))
456     lsp_inc_seqnum (lsp, 0);
457
458   return;
459 }
460
461 static u_int8_t
462 lsp_bits_generate (int level, int overload_bit, int attached_bit)
463 {
464   u_int8_t lsp_bits = 0;
465   if (level == IS_LEVEL_1)
466     lsp_bits = IS_LEVEL_1;
467   else
468     lsp_bits = IS_LEVEL_1_AND_2;
469   if (overload_bit)
470     lsp_bits |= overload_bit;
471   if (attached_bit)
472     lsp_bits |= attached_bit;
473   return lsp_bits;
474 }
475
476 static void
477 lsp_update_data (struct isis_lsp *lsp, struct stream *stream,
478                  struct isis_area *area, int level)
479 {
480   uint32_t expected = 0, found;
481   int retval;
482
483   /* free the old lsp data */
484   lsp_clear_data (lsp);
485
486   /* copying only the relevant part of our stream */
487   if (lsp->pdu != NULL)
488     stream_free (lsp->pdu);
489   lsp->pdu = stream_dup (stream);
490
491   /* setting pointers to the correct place */
492   lsp->isis_header = (struct isis_fixed_hdr *) (STREAM_DATA (lsp->pdu));
493   lsp->lsp_header = (struct isis_link_state_hdr *) (STREAM_DATA (lsp->pdu) +
494                                                     ISIS_FIXED_HDR_LEN);
495   lsp->area = area;
496   lsp->level = level;
497   lsp->age_out = ZERO_AGE_LIFETIME;
498   lsp->installed = time (NULL);
499   /*
500    * Get LSP data i.e. TLVs
501    */
502   expected |= TLVFLAG_AUTH_INFO;
503   expected |= TLVFLAG_AREA_ADDRS;
504   expected |= TLVFLAG_IS_NEIGHS;
505   expected |= TLVFLAG_NLPID;
506   if (area->dynhostname)
507     expected |= TLVFLAG_DYN_HOSTNAME;
508   if (area->newmetric)
509     {
510       expected |= TLVFLAG_TE_IS_NEIGHS;
511       expected |= TLVFLAG_TE_IPV4_REACHABILITY;
512       expected |= TLVFLAG_TE_ROUTER_ID;
513     }
514   expected |= TLVFLAG_IPV4_ADDR;
515   expected |= TLVFLAG_IPV4_INT_REACHABILITY;
516   expected |= TLVFLAG_IPV4_EXT_REACHABILITY;
517 #ifdef HAVE_IPV6
518   expected |= TLVFLAG_IPV6_ADDR;
519   expected |= TLVFLAG_IPV6_REACHABILITY;
520 #endif /* HAVE_IPV6 */
521
522   retval = parse_tlvs (area->area_tag, STREAM_DATA (lsp->pdu) +
523                        ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN,
524                        ntohs (lsp->lsp_header->pdu_len) -
525                        ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN,
526                        &expected, &found, &lsp->tlv_data,
527                        NULL);
528   if (retval != ISIS_OK)
529     {
530       zlog_warn ("Could not parse LSP");
531       return;
532     }
533
534   if ((found & TLVFLAG_DYN_HOSTNAME) && (area->dynhostname))
535     {
536       isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname,
537                          (lsp->lsp_header->lsp_bits & LSPBIT_IST) ==
538                           IS_LEVEL_1_AND_2 ? IS_LEVEL_2 : IS_LEVEL_1);
539     }
540
541   return;
542 }
543
544 void
545 lsp_update (struct isis_lsp *lsp, struct stream *stream,
546             struct isis_area *area, int level)
547 {
548   dnode_t *dnode = NULL;
549
550   /* Remove old LSP from database. This is required since the
551    * lsp_update_data will free the lsp->pdu (which has the key, lsp_id)
552    * and will update it with the new data in the stream. */
553   dnode = dict_lookup (area->lspdb[level - 1], lsp->lsp_header->lsp_id);
554   if (dnode)
555     dnode_destroy (dict_delete (area->lspdb[level - 1], dnode));
556
557   /* rebuild the lsp data */
558   lsp_update_data (lsp, stream, area, level);
559
560   /* insert the lsp back into the database */
561   lsp_insert (lsp, area->lspdb[level - 1]);
562 }
563
564 /* creation of LSP directly from what we received */
565 struct isis_lsp *
566 lsp_new_from_stream_ptr (struct stream *stream,
567                          u_int16_t pdu_len, struct isis_lsp *lsp0,
568                          struct isis_area *area, int level)
569 {
570   struct isis_lsp *lsp;
571
572   lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp));
573   lsp_update_data (lsp, stream, area, level);
574
575   if (lsp0 == NULL)
576     {
577       /*
578        * zero lsp -> create the list for fragments
579        */
580       lsp->lspu.frags = list_new ();
581     }
582   else
583     {
584       /*
585        * a fragment -> set the backpointer and add this to zero lsps frag list
586        */
587       lsp->lspu.zero_lsp = lsp0;
588       listnode_add (lsp0->lspu.frags, lsp);
589     }
590
591   return lsp;
592 }
593
594 struct isis_lsp *
595 lsp_new(struct isis_area *area, u_char * lsp_id,
596         u_int16_t rem_lifetime, u_int32_t seq_num,
597         u_int8_t lsp_bits, u_int16_t checksum, int level)
598 {
599   struct isis_lsp *lsp;
600
601   lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp));
602   lsp->area = area;
603
604   lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu);
605   if (LSP_FRAGMENT (lsp_id) == 0)
606     lsp->lspu.frags = list_new ();
607   lsp->isis_header = (struct isis_fixed_hdr *) (STREAM_DATA (lsp->pdu));
608   lsp->lsp_header = (struct isis_link_state_hdr *)
609     (STREAM_DATA (lsp->pdu) + ISIS_FIXED_HDR_LEN);
610
611   /* at first we fill the FIXED HEADER */
612   (level == IS_LEVEL_1) ? fill_fixed_hdr (lsp->isis_header, L1_LINK_STATE) :
613     fill_fixed_hdr (lsp->isis_header, L2_LINK_STATE);
614
615   /* now for the LSP HEADER */
616   /* Minimal LSP PDU size */
617   lsp->lsp_header->pdu_len = htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
618   memcpy (lsp->lsp_header->lsp_id, lsp_id, ISIS_SYS_ID_LEN + 2);
619   lsp->lsp_header->checksum = checksum; /* Provided in network order */
620   lsp->lsp_header->seq_num = htonl (seq_num);
621   lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
622   lsp->lsp_header->lsp_bits = lsp_bits;
623   lsp->level = level;
624   lsp->age_out = ZERO_AGE_LIFETIME;
625
626   stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
627
628   if (isis->debugs & DEBUG_EVENTS)
629     zlog_debug ("New LSP with ID %s-%02x-%02x len %d seqnum %08x",
630                 sysid_print (lsp_id), LSP_PSEUDO_ID (lsp->lsp_header->lsp_id),
631                 LSP_FRAGMENT (lsp->lsp_header->lsp_id),
632                 ntohl (lsp->lsp_header->pdu_len),
633                 ntohl (lsp->lsp_header->seq_num));
634
635   return lsp;
636 }
637
638 void
639 lsp_insert (struct isis_lsp *lsp, dict_t * lspdb)
640 {
641   dict_alloc_insert (lspdb, lsp->lsp_header->lsp_id, lsp);
642   if (lsp->lsp_header->seq_num != 0)
643     {
644       isis_spf_schedule (lsp->area, lsp->level);
645 #ifdef HAVE_IPV6
646       isis_spf_schedule6 (lsp->area, lsp->level);
647 #endif
648     }
649 }
650
651 /*
652  * Build a list of LSPs with non-zero ht bounded by start and stop ids
653  */
654 void
655 lsp_build_list_nonzero_ht (u_char * start_id, u_char * stop_id,
656                            struct list *list, dict_t * lspdb)
657 {
658   dnode_t *first, *last, *curr;
659
660   first = dict_lower_bound (lspdb, start_id);
661   if (!first)
662     return;
663
664   last = dict_upper_bound (lspdb, stop_id);
665
666   curr = first;
667
668   if (((struct isis_lsp *) (curr->dict_data))->lsp_header->rem_lifetime)
669     listnode_add (list, first->dict_data);
670
671   while (curr)
672     {
673       curr = dict_next (lspdb, curr);
674       if (curr &&
675           ((struct isis_lsp *) (curr->dict_data))->lsp_header->rem_lifetime)
676         listnode_add (list, curr->dict_data);
677       if (curr == last)
678         break;
679     }
680
681   return;
682 }
683
684 /*
685  * Build a list of num_lsps LSPs bounded by start_id and stop_id.
686  */
687 void
688 lsp_build_list (u_char * start_id, u_char * stop_id, u_char num_lsps,
689                 struct list *list, dict_t * lspdb)
690 {
691   u_char count;
692   dnode_t *first, *last, *curr;
693
694   first = dict_lower_bound (lspdb, start_id);
695   if (!first)
696     return;
697
698   last = dict_upper_bound (lspdb, stop_id);
699
700   curr = first;
701
702   listnode_add (list, first->dict_data);
703   count = 1;
704
705   while (curr)
706     {
707       curr = dict_next (lspdb, curr);
708       if (curr)
709         {
710           listnode_add (list, curr->dict_data);
711           count++;
712         }
713       if (count == num_lsps || curr == last)
714         break;
715     }
716
717   return;
718 }
719
720 /*
721  * Build a list of LSPs with SSN flag set for the given circuit
722  */
723 void
724 lsp_build_list_ssn (struct isis_circuit *circuit, u_char num_lsps,
725                     struct list *list, dict_t * lspdb)
726 {
727   dnode_t *dnode, *next;
728   struct isis_lsp *lsp;
729   u_char count = 0;
730
731   dnode = dict_first (lspdb);
732   while (dnode != NULL)
733     {
734       next = dict_next (lspdb, dnode);
735       lsp = dnode_get (dnode);
736       if (ISIS_CHECK_FLAG (lsp->SSNflags, circuit))
737         {
738           listnode_add (list, lsp);
739           ++count;
740         }
741       if (count == num_lsps)
742         break;
743       dnode = next;
744     }
745
746   return;
747 }
748
749 static void
750 lsp_set_time (struct isis_lsp *lsp)
751 {
752   assert (lsp);
753
754   if (lsp->lsp_header->rem_lifetime == 0)
755     {
756       if (lsp->age_out > 0)
757         lsp->age_out--;
758       return;
759     }
760
761   lsp->lsp_header->rem_lifetime =
762     htons (ntohs (lsp->lsp_header->rem_lifetime) - 1);
763 }
764
765 static void
766 lspid_print (u_char * lsp_id, u_char * trg, char dynhost, char frag)
767 {
768   struct isis_dynhn *dyn = NULL;
769   u_char id[SYSID_STRLEN];
770
771   if (dynhost)
772     dyn = dynhn_find_by_id (lsp_id);
773   else
774     dyn = NULL;
775
776   if (dyn)
777       sprintf ((char *)id, "%.14s", dyn->name.name);
778   else if (!memcmp (isis->sysid, lsp_id, ISIS_SYS_ID_LEN) && dynhost)
779       sprintf ((char *)id, "%.14s", unix_hostname ());
780   else
781       memcpy (id, sysid_print (lsp_id), 15);
782   if (frag)
783     sprintf ((char *)trg, "%s.%02x-%02x", id, LSP_PSEUDO_ID (lsp_id),
784              LSP_FRAGMENT (lsp_id));
785   else
786     sprintf ((char *)trg, "%s.%02x", id, LSP_PSEUDO_ID (lsp_id));
787 }
788
789 /* Convert the lsp attribute bits to attribute string */
790 const char *
791 lsp_bits2string (u_char * lsp_bits)
792 {
793   char *pos = lsp_bits_string;
794
795   if (!*lsp_bits)
796     return " none";
797
798   /* we only focus on the default metric */
799   pos += sprintf (pos, "%d/",
800                   ISIS_MASK_LSP_ATT_DEFAULT_BIT (*lsp_bits) ? 1 : 0);
801
802   pos += sprintf (pos, "%d/",
803                   ISIS_MASK_LSP_PARTITION_BIT (*lsp_bits) ? 1 : 0);
804
805   pos += sprintf (pos, "%d", ISIS_MASK_LSP_OL_BIT (*lsp_bits) ? 1 : 0);
806
807   *(pos) = '\0';
808
809   return lsp_bits_string;
810 }
811
812 /* this function prints the lsp on show isis database */
813 void
814 lsp_print (struct isis_lsp *lsp, struct vty *vty, char dynhost)
815 {
816   u_char LSPid[255];
817   char age_out[8];
818
819   lspid_print (lsp->lsp_header->lsp_id, LSPid, dynhost, 1);
820   vty_out (vty, "%-21s%c  ", LSPid, lsp->own_lsp ? '*' : ' ');
821   vty_out (vty, "%5u   ", ntohs (lsp->lsp_header->pdu_len));
822   vty_out (vty, "0x%08x  ", ntohl (lsp->lsp_header->seq_num));
823   vty_out (vty, "0x%04x  ", ntohs (lsp->lsp_header->checksum));
824   if (ntohs (lsp->lsp_header->rem_lifetime) == 0)
825     {
826       snprintf (age_out, 8, "(%u)", lsp->age_out);
827       age_out[7] = '\0';
828       vty_out (vty, "%7s   ", age_out);
829     }
830   else
831     vty_out (vty, " %5u    ", ntohs (lsp->lsp_header->rem_lifetime));
832   vty_out (vty, "%s%s",
833            lsp_bits2string (&lsp->lsp_header->lsp_bits), VTY_NEWLINE);
834 }
835
836 void
837 lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
838 {
839   struct area_addr *area_addr;
840   int i;
841   struct listnode *lnode;
842   struct is_neigh *is_neigh;
843   struct te_is_neigh *te_is_neigh;
844   struct ipv4_reachability *ipv4_reach;
845   struct in_addr *ipv4_addr;
846   struct te_ipv4_reachability *te_ipv4_reach;
847 #ifdef HAVE_IPV6
848   struct ipv6_reachability *ipv6_reach;
849   struct in6_addr in6;
850   u_char buff[BUFSIZ];
851 #endif
852   u_char LSPid[255];
853   u_char hostname[255];
854   u_char ipv4_reach_prefix[20];
855   u_char ipv4_reach_mask[20];
856   u_char ipv4_address[20];
857
858   lspid_print (lsp->lsp_header->lsp_id, LSPid, dynhost, 1);
859   lsp_print (lsp, vty, dynhost);
860
861   /* for all area address */
862   if (lsp->tlv_data.area_addrs)
863     for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.area_addrs, lnode, area_addr))
864       {
865         vty_out (vty, "  Area Address: %s%s",
866                  isonet_print (area_addr->area_addr, area_addr->addr_len),
867                  VTY_NEWLINE);
868       }
869   
870   /* for the nlpid tlv */
871   if (lsp->tlv_data.nlpids)
872     {
873       for (i = 0; i < lsp->tlv_data.nlpids->count; i++)
874         {
875           switch (lsp->tlv_data.nlpids->nlpids[i])
876             {
877             case NLPID_IP:
878             case NLPID_IPV6:
879               vty_out (vty, "  NLPID       : 0x%X%s",
880                        lsp->tlv_data.nlpids->nlpids[i], VTY_NEWLINE);
881               break;
882             default:
883               vty_out (vty, "  NLPID       : %s%s", "unknown", VTY_NEWLINE);
884               break;
885             }
886         }
887     }
888
889   /* for the hostname tlv */
890   if (lsp->tlv_data.hostname)
891     {
892       bzero (hostname, sizeof (hostname));
893       memcpy (hostname, lsp->tlv_data.hostname->name,
894               lsp->tlv_data.hostname->namelen);
895       vty_out (vty, "  Hostname    : %s%s", hostname, VTY_NEWLINE);
896     }
897
898   /* authentication tlv */
899   if (lsp->tlv_data.auth_info.type != ISIS_PASSWD_TYPE_UNUSED)
900     {
901       if (lsp->tlv_data.auth_info.type == ISIS_PASSWD_TYPE_HMAC_MD5)
902         vty_out (vty, "  Auth type   : md5%s", VTY_NEWLINE);
903       else if (lsp->tlv_data.auth_info.type == ISIS_PASSWD_TYPE_CLEARTXT)
904         vty_out (vty, "  Auth type   : clear text%s", VTY_NEWLINE);
905     }
906
907   /* TE router id */
908   if (lsp->tlv_data.router_id)
909     {
910       memcpy (ipv4_address, inet_ntoa (lsp->tlv_data.router_id->id),
911               sizeof (ipv4_address));
912       vty_out (vty, "  Router ID   : %s%s", ipv4_address, VTY_NEWLINE);
913     }
914
915   if (lsp->tlv_data.ipv4_addrs)
916     for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_addrs, lnode, ipv4_addr))
917       {
918         memcpy (ipv4_address, inet_ntoa (*ipv4_addr), sizeof (ipv4_address));
919         vty_out (vty, "  IPv4 Address: %s%s", ipv4_address, VTY_NEWLINE);
920       }
921
922   /* for the IS neighbor tlv */
923   if (lsp->tlv_data.is_neighs)
924     for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, lnode, is_neigh))
925       {
926         lspid_print (is_neigh->neigh_id, LSPid, dynhost, 0);
927         vty_out (vty, "  Metric      : %-8d IS            : %s%s",
928                  is_neigh->metrics.metric_default, LSPid, VTY_NEWLINE);
929       }
930   
931   /* for the internal reachable tlv */
932   if (lsp->tlv_data.ipv4_int_reachs)
933     for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_int_reachs, lnode,
934                                ipv4_reach))
935     {
936       memcpy (ipv4_reach_prefix, inet_ntoa (ipv4_reach->prefix),
937               sizeof (ipv4_reach_prefix));
938       memcpy (ipv4_reach_mask, inet_ntoa (ipv4_reach->mask),
939               sizeof (ipv4_reach_mask));
940       vty_out (vty, "  Metric      : %-8d IPv4-Internal : %s %s%s",
941                ipv4_reach->metrics.metric_default, ipv4_reach_prefix,
942                ipv4_reach_mask, VTY_NEWLINE);
943     }
944
945   /* for the external reachable tlv */
946   if (lsp->tlv_data.ipv4_ext_reachs)
947     for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_ext_reachs, lnode, 
948                                ipv4_reach))
949     {
950       memcpy (ipv4_reach_prefix, inet_ntoa (ipv4_reach->prefix),
951               sizeof (ipv4_reach_prefix));
952       memcpy (ipv4_reach_mask, inet_ntoa (ipv4_reach->mask),
953               sizeof (ipv4_reach_mask));
954       vty_out (vty, "  Metric      : %-8d IPv4-External : %s %s%s",
955                ipv4_reach->metrics.metric_default, ipv4_reach_prefix,
956                ipv4_reach_mask, VTY_NEWLINE);
957     }
958   
959   /* IPv6 tlv */
960 #ifdef HAVE_IPV6
961   if (lsp->tlv_data.ipv6_reachs)
962     for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs, lnode, ipv6_reach))
963     {
964       memset (&in6, 0, sizeof (in6));
965       memcpy (in6.s6_addr, ipv6_reach->prefix,
966               PSIZE (ipv6_reach->prefix_len));
967       inet_ntop (AF_INET6, &in6, (char *)buff, BUFSIZ);
968       if ((ipv6_reach->control_info &
969            CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL)
970         vty_out (vty, "  Metric      : %-8d IPv6-Internal : %s/%d%s",
971                  ntohl (ipv6_reach->metric),
972                  buff, ipv6_reach->prefix_len, VTY_NEWLINE);
973       else
974         vty_out (vty, "  Metric      : %-8d IPv6-External : %s/%d%s",
975                  ntohl (ipv6_reach->metric),
976                  buff, ipv6_reach->prefix_len, VTY_NEWLINE);
977     }
978 #endif
979
980   /* TE IS neighbor tlv */
981   if (lsp->tlv_data.te_is_neighs)
982     for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, lnode, te_is_neigh))
983     {
984       lspid_print (te_is_neigh->neigh_id, LSPid, dynhost, 0);
985       vty_out (vty, "  Metric      : %-8d IS-Extended   : %s%s",
986                GET_TE_METRIC(te_is_neigh), LSPid, VTY_NEWLINE);
987       if (IS_MPLS_TE(isisMplsTE))
988         mpls_te_print_detail(vty, te_is_neigh);
989     }
990
991   /* TE IPv4 tlv */
992   if (lsp->tlv_data.te_ipv4_reachs)
993     for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs, lnode,
994                                te_ipv4_reach))
995     {
996       /* FIXME: There should be better way to output this stuff. */
997       vty_out (vty, "  Metric      : %-8d IPv4-Extended : %s/%d%s",
998                ntohl (te_ipv4_reach->te_metric),
999                inet_ntoa (newprefix2inaddr (&te_ipv4_reach->prefix_start,
1000                                             te_ipv4_reach->control)),
1001                te_ipv4_reach->control & 0x3F, VTY_NEWLINE);
1002     }
1003   vty_out (vty, "%s", VTY_NEWLINE);
1004
1005   return;
1006 }
1007
1008 /* print all the lsps info in the local lspdb */
1009 int
1010 lsp_print_all (struct vty *vty, dict_t * lspdb, char detail, char dynhost)
1011 {
1012
1013   dnode_t *node = dict_first (lspdb), *next;
1014   int lsp_count = 0;
1015
1016   if (detail == ISIS_UI_LEVEL_BRIEF)
1017     {
1018       while (node != NULL)
1019         {
1020           /* I think it is unnecessary, so I comment it out */
1021           /* dict_contains (lspdb, node); */
1022           next = dict_next (lspdb, node);
1023           lsp_print (dnode_get (node), vty, dynhost);
1024           node = next;
1025           lsp_count++;
1026         }
1027     }
1028   else if (detail == ISIS_UI_LEVEL_DETAIL)
1029     {
1030       while (node != NULL)
1031         {
1032           next = dict_next (lspdb, node);
1033           lsp_print_detail (dnode_get (node), vty, dynhost);
1034           node = next;
1035           lsp_count++;
1036         }
1037     }
1038
1039   return lsp_count;
1040 }
1041
1042 #define FRAG_THOLD(S,T) \
1043   ((STREAM_SIZE(S)*T)/100)
1044
1045 /* stream*, area->lsp_frag_threshold, increment */
1046 #define FRAG_NEEDED(S,T,I) \
1047   (STREAM_SIZE(S)-STREAM_REMAIN(S)+(I) > FRAG_THOLD(S,T))
1048
1049 /* FIXME: It shouldn't be necessary to pass tlvsize here, TLVs can have
1050  * variable length (TE TLVs, sub TLVs). */
1051 static void
1052 lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to,
1053              int tlvsize, int frag_thold,
1054              int tlv_build_func (struct list *, struct stream *))
1055 {
1056   int count, i;
1057
1058   /* can we fit all ? */
1059   if (!FRAG_NEEDED (lsp->pdu, frag_thold, listcount (*from) * tlvsize + 2))
1060     {
1061       tlv_build_func (*from, lsp->pdu);
1062       if (listcount (*to) != 0)
1063         {
1064           struct listnode *node, *nextnode;
1065           void *elem;
1066
1067           for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem))
1068             {
1069               listnode_add (*to, elem);
1070               list_delete_node (*from, node);
1071             }
1072         }
1073       else
1074         {
1075           list_free (*to);
1076           *to = *from;
1077           *from = NULL;
1078         }
1079     }
1080   else if (!FRAG_NEEDED (lsp->pdu, frag_thold, tlvsize + 2))
1081     {
1082       /* fit all we can */
1083       count = FRAG_THOLD (lsp->pdu, frag_thold) - 2 -
1084         (STREAM_SIZE (lsp->pdu) - STREAM_REMAIN (lsp->pdu));
1085       count = count / tlvsize;
1086       if (count > (int)listcount (*from))
1087         count = listcount (*from);
1088       for (i = 0; i < count; i++)
1089         {
1090           listnode_add (*to, listgetdata (listhead (*from)));
1091           listnode_delete (*from, listgetdata (listhead (*from)));
1092         }
1093       tlv_build_func (*to, lsp->pdu);
1094     }
1095   lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
1096   return;
1097 }
1098
1099 /* Process IS_NEIGHBOURS TLV with TE subTLVs */
1100 static void
1101 lsp_te_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to, int frag_thold)
1102 {
1103   int count, size = 0;
1104   struct listnode *node, *nextnode;
1105   struct te_is_neigh *elem;
1106
1107   /* Start computing real size of TLVs */
1108   for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem))
1109     size = size + elem->sub_tlvs_length + IS_NEIGHBOURS_LEN;
1110
1111   /* can we fit all ? */
1112   if (!FRAG_NEEDED (lsp->pdu, frag_thold, size))
1113     {
1114       tlv_add_te_is_neighs (*from, lsp->pdu);
1115       if (listcount (*to) != 0)
1116         {
1117           for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem))
1118             {
1119               listnode_add (*to, elem);
1120               list_delete_node (*from, node);
1121             }
1122         }
1123       else
1124         {
1125           list_free (*to);
1126           *to = *from;
1127           *from = NULL;
1128         }
1129     }
1130   else
1131     {
1132       /* fit all we can */
1133       /* Compute remaining place in LSP PDU */
1134       count = FRAG_THOLD (lsp->pdu, frag_thold) - 2 -
1135         (STREAM_SIZE (lsp->pdu) - STREAM_REMAIN (lsp->pdu));
1136       /* Determine size of TE SubTLVs */
1137       elem = (struct te_is_neigh *)listgetdata ((struct listnode *)listhead (*from));
1138       count = count - elem->sub_tlvs_length - IS_NEIGHBOURS_LEN;
1139       if (count > 0)
1140         {
1141           while (count > 0)
1142             {
1143               listnode_add (*to, listgetdata ((struct listnode *)listhead (*from)));
1144               listnode_delete (*from, listgetdata ((struct listnode *)listhead (*from)));
1145
1146               elem = (struct te_is_neigh *)listgetdata ((struct listnode *)listhead (*from));
1147               count = count - elem->sub_tlvs_length - IS_NEIGHBOURS_LEN;
1148             }
1149
1150           tlv_add_te_is_neighs (*to, lsp->pdu);
1151         }
1152     }
1153   lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
1154   return;
1155 }
1156
1157 static u_int16_t
1158 lsp_rem_lifetime (struct isis_area *area, int level)
1159 {
1160   u_int16_t rem_lifetime;
1161
1162   /* Add jitter to configured LSP lifetime */
1163   rem_lifetime = isis_jitter (area->max_lsp_lifetime[level - 1],
1164                               MAX_AGE_JITTER);
1165
1166   /* No jitter if the max refresh will be less than configure gen interval */
1167   /* N.B. this calucation is acceptable since rem_lifetime is in [332,65535] at
1168    * this point */
1169   if (area->lsp_gen_interval[level - 1] > (rem_lifetime - 300))
1170     rem_lifetime = area->max_lsp_lifetime[level - 1];
1171
1172   return rem_lifetime;
1173 }
1174
1175 static u_int16_t
1176 lsp_refresh_time (struct isis_lsp *lsp, u_int16_t rem_lifetime)
1177 {
1178   struct isis_area *area = lsp->area;
1179   int level = lsp->level;
1180   u_int16_t refresh_time;
1181
1182   /* Add jitter to LSP refresh time */
1183   refresh_time = isis_jitter (area->lsp_refresh[level - 1],
1184                               MAX_LSP_GEN_JITTER);
1185
1186   /* RFC 4444 : make sure the refresh time is at least less than 300
1187    * of the remaining lifetime and more than gen interval */
1188   if (refresh_time <= area->lsp_gen_interval[level - 1] ||
1189       refresh_time > (rem_lifetime - 300))
1190     refresh_time = rem_lifetime - 300;
1191
1192   /* In cornercases, refresh_time might be <= lsp_gen_interval, however
1193    * we accept this violation to satisfy refresh_time <= rem_lifetime - 300 */
1194
1195   return refresh_time;
1196 }
1197
1198 static struct isis_lsp *
1199 lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, struct isis_area *area,
1200                int level)
1201 {
1202   struct isis_lsp *lsp;
1203   u_char frag_id[ISIS_SYS_ID_LEN + 2];
1204
1205   memcpy (frag_id, lsp0->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 1);
1206   LSP_FRAGMENT (frag_id) = frag_num;
1207   /* FIXME add authentication TLV for fragment LSPs */
1208   lsp = lsp_search (frag_id, area->lspdb[level - 1]);
1209   if (lsp)
1210     {
1211       /* Clear the TLVs */
1212       lsp_clear_data (lsp);
1213       return lsp;
1214     }
1215   lsp = lsp_new (area, frag_id, ntohs(lsp0->lsp_header->rem_lifetime), 0,
1216                  lsp_bits_generate (level, area->overload_bit,
1217                  area->attached_bit), 0, level);
1218   lsp->area = area;
1219   lsp->own_lsp = 1;
1220   lsp_insert (lsp, area->lspdb[level - 1]);
1221   listnode_add (lsp0->lspu.frags, lsp);
1222   lsp->lspu.zero_lsp = lsp0;
1223   return lsp;
1224 }
1225
1226 static void
1227 lsp_build_ext_reach_ipv4(struct isis_lsp *lsp, struct isis_area *area,
1228                          struct tlvs *tlv_data)
1229 {
1230   struct route_table *er_table;
1231   struct route_node *rn;
1232   struct prefix_ipv4 *ipv4;
1233   struct isis_ext_info *info;
1234   struct ipv4_reachability *ipreach;
1235   struct te_ipv4_reachability *te_ipreach;
1236
1237   er_table = get_ext_reach(area, AF_INET, lsp->level);
1238   if (!er_table)
1239     return;
1240
1241   for (rn = route_top(er_table); rn; rn = route_next(rn))
1242     {
1243       if (!rn->info)
1244         continue;
1245
1246       ipv4 = (struct prefix_ipv4*)&rn->p;
1247       info = rn->info;
1248       if (area->oldmetric)
1249         {
1250           if (tlv_data->ipv4_ext_reachs == NULL)
1251             {
1252               tlv_data->ipv4_ext_reachs = list_new();
1253               tlv_data->ipv4_ext_reachs->del = free_tlv;
1254             }
1255           ipreach = XMALLOC(MTYPE_ISIS_TLV, sizeof(*ipreach));
1256
1257           ipreach->prefix.s_addr = ipv4->prefix.s_addr;
1258           masklen2ip(ipv4->prefixlen, &ipreach->mask);
1259           ipreach->prefix.s_addr &= ipreach->mask.s_addr;
1260
1261           if ((info->metric & 0x3f) != info->metric)
1262             ipreach->metrics.metric_default = 0x3f;
1263           else
1264             ipreach->metrics.metric_default = info->metric;
1265           ipreach->metrics.metric_expense = METRICS_UNSUPPORTED;
1266           ipreach->metrics.metric_error = METRICS_UNSUPPORTED;
1267           ipreach->metrics.metric_delay = METRICS_UNSUPPORTED;
1268           listnode_add(tlv_data->ipv4_ext_reachs, ipreach);
1269         }
1270       if (area->newmetric)
1271         {
1272           if (tlv_data->te_ipv4_reachs == NULL)
1273             {
1274               tlv_data->te_ipv4_reachs = list_new();
1275               tlv_data->te_ipv4_reachs->del = free_tlv;
1276             }
1277           te_ipreach =
1278               XCALLOC(MTYPE_ISIS_TLV,
1279                       sizeof(*te_ipreach) - 1 + PSIZE(ipv4->prefixlen));
1280           if (info->metric > MAX_WIDE_PATH_METRIC)
1281             te_ipreach->te_metric = htonl(MAX_WIDE_PATH_METRIC);
1282           else
1283             te_ipreach->te_metric = htonl(info->metric);
1284           te_ipreach->control = ipv4->prefixlen & 0x3f;
1285           memcpy(&te_ipreach->prefix_start, &ipv4->prefix.s_addr,
1286                  PSIZE(ipv4->prefixlen));
1287           listnode_add(tlv_data->te_ipv4_reachs, te_ipreach);
1288         }
1289     }
1290 }
1291
1292 static void
1293 lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, struct isis_area *area,
1294                          struct tlvs *tlv_data)
1295 {
1296   struct route_table *er_table;
1297   struct route_node *rn;
1298   struct prefix_ipv6 *ipv6;
1299   struct isis_ext_info *info;
1300   struct ipv6_reachability *ip6reach;
1301
1302   er_table = get_ext_reach(area, AF_INET6, lsp->level);
1303   if (!er_table)
1304     return;
1305
1306   for (rn = route_top(er_table); rn; rn = route_next(rn))
1307     {
1308       if (!rn->info)
1309         continue;
1310
1311       ipv6 = (struct prefix_ipv6*)&rn->p;
1312       info = rn->info;
1313
1314       if (tlv_data->ipv6_reachs == NULL)
1315         {
1316           tlv_data->ipv6_reachs = list_new();
1317           tlv_data->ipv6_reachs->del = free_tlv;
1318         }
1319       ip6reach = XCALLOC(MTYPE_ISIS_TLV, sizeof(*ip6reach));
1320       if (info->metric > MAX_WIDE_PATH_METRIC)
1321         ip6reach->metric = htonl(MAX_WIDE_PATH_METRIC);
1322       else
1323         ip6reach->metric = htonl(info->metric);
1324       ip6reach->control_info = DISTRIBUTION_EXTERNAL;
1325       ip6reach->prefix_len = ipv6->prefixlen;
1326       memcpy(ip6reach->prefix, ipv6->prefix.s6_addr, sizeof(ip6reach->prefix));
1327       listnode_add(tlv_data->ipv6_reachs, ip6reach);
1328     }
1329 }
1330
1331 static void
1332 lsp_build_ext_reach (struct isis_lsp *lsp, struct isis_area *area,
1333                      struct tlvs *tlv_data)
1334 {
1335   lsp_build_ext_reach_ipv4(lsp, area, tlv_data);
1336   lsp_build_ext_reach_ipv6(lsp, area, tlv_data);
1337 }
1338
1339 /*
1340  * Builds the LSP data part. This func creates a new frag whenever 
1341  * area->lsp_frag_threshold is exceeded.
1342  */
1343 static void
1344 lsp_build (struct isis_lsp *lsp, struct isis_area *area)
1345 {
1346   struct is_neigh *is_neigh;
1347   struct te_is_neigh *te_is_neigh;
1348   struct listnode *node, *ipnode;
1349   int level = lsp->level;
1350   struct isis_circuit *circuit;
1351   struct prefix_ipv4 *ipv4;
1352   struct ipv4_reachability *ipreach;
1353   struct te_ipv4_reachability *te_ipreach;
1354   struct isis_adjacency *nei;
1355 #ifdef HAVE_IPV6
1356   struct prefix_ipv6 *ipv6, ip6prefix;
1357   struct ipv6_reachability *ip6reach;
1358 #endif /* HAVE_IPV6 */
1359   struct tlvs tlv_data;
1360   struct isis_lsp *lsp0 = lsp;
1361   struct in_addr *routerid;
1362   uint32_t expected = 0, found = 0;
1363   uint32_t metric;
1364   u_char zero_id[ISIS_SYS_ID_LEN + 1];
1365   int retval = ISIS_OK;
1366   char buf[BUFSIZ];
1367
1368   lsp_debug("ISIS (%s): Constructing local system LSP for level %d", area->area_tag, level);
1369
1370   /*
1371    * Building the zero lsp
1372    */
1373   memset (zero_id, 0, ISIS_SYS_ID_LEN + 1);
1374
1375   /* Reset stream endp. Stream is always there and on every LSP refresh only
1376    * TLV part of it is overwritten. So we must seek past header we will not
1377    * touch. */
1378   stream_reset (lsp->pdu);
1379   stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
1380
1381   /*
1382    * Add the authentication info if its present
1383    */
1384   lsp_auth_add (lsp);
1385
1386   /*
1387    * First add the tlvs related to area
1388    */
1389
1390   /* Area addresses */
1391   if (lsp->tlv_data.area_addrs == NULL)
1392     lsp->tlv_data.area_addrs = list_new ();
1393   list_add_list (lsp->tlv_data.area_addrs, area->area_addrs);
1394   if (listcount (lsp->tlv_data.area_addrs) > 0)
1395     tlv_add_area_addrs (lsp->tlv_data.area_addrs, lsp->pdu);
1396
1397   /* Protocols Supported */
1398   if (area->ip_circuits > 0
1399 #ifdef HAVE_IPV6
1400       || area->ipv6_circuits > 0
1401 #endif /* HAVE_IPV6 */
1402     )
1403     {
1404       lsp->tlv_data.nlpids = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct nlpids));
1405       lsp->tlv_data.nlpids->count = 0;
1406       if (area->ip_circuits > 0)
1407         {
1408           lsp_debug("ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs", area->area_tag);
1409           lsp->tlv_data.nlpids->count++;
1410           lsp->tlv_data.nlpids->nlpids[0] = NLPID_IP;
1411         }
1412 #ifdef HAVE_IPV6
1413       if (area->ipv6_circuits > 0)
1414         {
1415           lsp_debug("ISIS (%s): Found IPv6 circuit, adding IPv6 to NLPIDs", area->area_tag);
1416           lsp->tlv_data.nlpids->count++;
1417           lsp->tlv_data.nlpids->nlpids[lsp->tlv_data.nlpids->count - 1] =
1418             NLPID_IPV6;
1419         }
1420 #endif /* HAVE_IPV6 */
1421       tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu);
1422     }
1423
1424   /* Dynamic Hostname */
1425   if (area->dynhostname)
1426     {
1427       const char *hostname = unix_hostname();
1428       size_t hostname_len = strlen(hostname);
1429
1430       lsp->tlv_data.hostname = XMALLOC (MTYPE_ISIS_TLV,
1431                                         sizeof (struct hostname));
1432
1433       strncpy((char *)lsp->tlv_data.hostname->name, hostname,
1434               sizeof(lsp->tlv_data.hostname->name));
1435       if (hostname_len <= MAX_TLV_LEN)
1436         lsp->tlv_data.hostname->namelen = hostname_len;
1437       else
1438         lsp->tlv_data.hostname->namelen = MAX_TLV_LEN;
1439
1440       lsp_debug("ISIS (%s): Adding dynamic hostname '%.*s'", area->area_tag,
1441                 lsp->tlv_data.hostname->namelen, lsp->tlv_data.hostname->name);
1442       tlv_add_dynamic_hostname (lsp->tlv_data.hostname, lsp->pdu);
1443     }
1444   else
1445     {
1446       lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)", area->area_tag);
1447     }
1448
1449   /* IPv4 address and TE router ID TLVs. In case of the first one we don't
1450    * follow "C" vendor, but "J" vendor behavior - one IPv4 address is put into
1451    * LSP and this address is same as router id. */
1452   if (isis->router_id != 0)
1453     {
1454       inet_ntop(AF_INET, &isis->router_id, buf, sizeof(buf));
1455       lsp_debug("ISIS (%s): Adding router ID %s as IPv4 tlv.", area->area_tag, buf);
1456       if (lsp->tlv_data.ipv4_addrs == NULL)
1457         {
1458           lsp->tlv_data.ipv4_addrs = list_new ();
1459           lsp->tlv_data.ipv4_addrs->del = free_tlv;
1460         }
1461
1462       routerid = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct in_addr));
1463       routerid->s_addr = isis->router_id;
1464       listnode_add (lsp->tlv_data.ipv4_addrs, routerid);
1465       tlv_add_in_addr (routerid, lsp->pdu, IPV4_ADDR);
1466
1467       /* Exactly same data is put into TE router ID TLV, but only if new style
1468        * TLV's are in use. */
1469       if (area->newmetric)
1470         {
1471           lsp_debug("ISIS (%s): Adding router ID also as TE router ID tlv.", area->area_tag);
1472           lsp->tlv_data.router_id = XMALLOC (MTYPE_ISIS_TLV,
1473                                              sizeof (struct in_addr));
1474           lsp->tlv_data.router_id->id.s_addr = isis->router_id;
1475           tlv_add_in_addr (&lsp->tlv_data.router_id->id, lsp->pdu,
1476                            TE_ROUTER_ID);
1477         }
1478     }
1479   else
1480     {
1481       lsp_debug("ISIS (%s): Router ID is unset. Not adding tlv.", area->area_tag);
1482     }
1483
1484   memset (&tlv_data, 0, sizeof (struct tlvs));
1485
1486 #ifdef TOPOLOGY_GENERATE
1487   /* If topology exists (and we create topology for level 1 only), create
1488    * (hardcoded) link to topology. */
1489   if (area->topology && level == IS_LEVEL_1)
1490     {
1491       if (tlv_data.is_neighs == NULL)
1492         {
1493           tlv_data.is_neighs = list_new ();
1494           tlv_data.is_neighs->del = free_tlv;
1495         }
1496       is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
1497
1498       memcpy (&is_neigh->neigh_id, area->topology_baseis, ISIS_SYS_ID_LEN);
1499       is_neigh->neigh_id[ISIS_SYS_ID_LEN - 1] = (1 & 0xFF);
1500       is_neigh->neigh_id[ISIS_SYS_ID_LEN - 2] = ((1 >> 8) & 0xFF);
1501       is_neigh->metrics.metric_default = 0x01;
1502       is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED;
1503       is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED;
1504       is_neigh->metrics.metric_error = METRICS_UNSUPPORTED;
1505       listnode_add (tlv_data.is_neighs, is_neigh);
1506     }
1507 #endif /* TOPOLOGY_GENERATE */
1508
1509   lsp_debug("ISIS (%s): Adding circuit specific information.", area->area_tag);
1510
1511   /*
1512    * Then build lists of tlvs related to circuits
1513    */
1514   for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit))
1515     {
1516       if (!circuit->interface)
1517         lsp_debug("ISIS (%s): Processing %s circuit %p with unknown interface",
1518                   area->area_tag, circuit_type2string(circuit->circ_type), circuit);
1519       else
1520         lsp_debug("ISIS (%s): Processing %s circuit %s",
1521                   area->area_tag, circuit_type2string(circuit->circ_type), circuit->interface->name);
1522
1523       if (circuit->state != C_STATE_UP)
1524         {
1525           lsp_debug("ISIS (%s): Circuit is not up, ignoring.", area->area_tag);
1526           continue;
1527         }
1528
1529       /*
1530        * Add IPv4 internal reachability of this circuit
1531        */
1532       if (circuit->ip_router && circuit->ip_addrs &&
1533           circuit->ip_addrs->count > 0)
1534         {
1535           lsp_debug("ISIS (%s): Circuit has IPv4 active, adding respective TLVs.", area->area_tag);
1536           if (area->oldmetric)
1537             {
1538               if (tlv_data.ipv4_int_reachs == NULL)
1539                 {
1540                   tlv_data.ipv4_int_reachs = list_new ();
1541                   tlv_data.ipv4_int_reachs->del = free_tlv;
1542                 }
1543               for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, ipnode, ipv4))
1544                 {
1545                   ipreach =
1546                     XMALLOC (MTYPE_ISIS_TLV, sizeof (struct ipv4_reachability));
1547                   ipreach->metrics.metric_default = circuit->metric[level - 1];
1548                   ipreach->metrics.metric_expense = METRICS_UNSUPPORTED;
1549                   ipreach->metrics.metric_error = METRICS_UNSUPPORTED;
1550                   ipreach->metrics.metric_delay = METRICS_UNSUPPORTED;
1551                   masklen2ip (ipv4->prefixlen, &ipreach->mask);
1552                   ipreach->prefix.s_addr = ((ipreach->mask.s_addr) &
1553                                             (ipv4->prefix.s_addr));
1554                   inet_ntop(AF_INET, &ipreach->prefix.s_addr, buf, sizeof(buf));
1555                   lsp_debug("ISIS (%s): Adding old-style IP reachability for %s/%d",
1556                             area->area_tag, buf, ipv4->prefixlen);
1557                   listnode_add (tlv_data.ipv4_int_reachs, ipreach);
1558                 }
1559             }
1560           if (area->newmetric)
1561             {
1562               if (tlv_data.te_ipv4_reachs == NULL)
1563                 {
1564                   tlv_data.te_ipv4_reachs = list_new ();
1565                   tlv_data.te_ipv4_reachs->del = free_tlv;
1566                 }
1567               for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, ipnode, ipv4))
1568                 {
1569                   /* FIXME All this assumes that we have no sub TLVs. */
1570                   te_ipreach = XCALLOC (MTYPE_ISIS_TLV,
1571                                         sizeof (struct te_ipv4_reachability) +
1572                                         ((ipv4->prefixlen + 7)/8) - 1);
1573
1574                   if (area->oldmetric)
1575                     te_ipreach->te_metric = htonl (circuit->metric[level - 1]);
1576                   else
1577                     te_ipreach->te_metric = htonl (circuit->te_metric[level - 1]);
1578
1579                   te_ipreach->control = (ipv4->prefixlen & 0x3F);
1580                   memcpy (&te_ipreach->prefix_start, &ipv4->prefix.s_addr,
1581                           (ipv4->prefixlen + 7)/8);
1582                   inet_ntop(AF_INET, &ipv4->prefix.s_addr, buf, sizeof(buf));
1583                   lsp_debug("ISIS (%s): Adding te-style IP reachability for %s/%d",
1584                             area->area_tag, buf, ipv4->prefixlen);
1585                   listnode_add (tlv_data.te_ipv4_reachs, te_ipreach);
1586                 }
1587             }
1588         }
1589
1590 #ifdef HAVE_IPV6
1591       /*
1592        * Add IPv6 reachability of this circuit
1593        */
1594       if (circuit->ipv6_router && circuit->ipv6_non_link &&
1595           circuit->ipv6_non_link->count > 0)
1596         {
1597
1598           if (tlv_data.ipv6_reachs == NULL)
1599             {
1600               tlv_data.ipv6_reachs = list_new ();
1601               tlv_data.ipv6_reachs->del = free_tlv;
1602             }
1603           for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, ipnode, ipv6))
1604             {
1605               ip6reach =
1606                 XCALLOC (MTYPE_ISIS_TLV, sizeof (struct ipv6_reachability));
1607
1608               if (area->oldmetric)
1609                 ip6reach->metric =
1610                           htonl (circuit->metric[level - 1]);
1611               else
1612                   ip6reach->metric = htonl (circuit->te_metric[level - 1]);
1613
1614               ip6reach->control_info = 0;
1615               ip6reach->prefix_len = ipv6->prefixlen;
1616               memcpy(&ip6prefix, ipv6, sizeof(ip6prefix));
1617               apply_mask_ipv6(&ip6prefix);
1618
1619               inet_ntop(AF_INET6, &ip6prefix.prefix.s6_addr, buf, sizeof(buf));
1620               lsp_debug("ISIS (%s): Adding IPv6 reachability for %s/%d",
1621                         area->area_tag, buf, ipv6->prefixlen);
1622
1623               memcpy (ip6reach->prefix, ip6prefix.prefix.s6_addr,
1624                       sizeof (ip6reach->prefix));
1625               listnode_add (tlv_data.ipv6_reachs, ip6reach);
1626             }
1627         }
1628 #endif /* HAVE_IPV6 */
1629
1630       switch (circuit->circ_type)
1631         {
1632         case CIRCUIT_T_BROADCAST:
1633           if (level & circuit->is_type)
1634             {
1635               if (area->oldmetric)
1636                 {
1637                   if (tlv_data.is_neighs == NULL)
1638                     {
1639                       tlv_data.is_neighs = list_new ();
1640                       tlv_data.is_neighs->del = free_tlv;
1641                     }
1642                   is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
1643                   if (level == IS_LEVEL_1)
1644                     memcpy (is_neigh->neigh_id,
1645                             circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
1646                   else
1647                     memcpy (is_neigh->neigh_id,
1648                             circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
1649                   is_neigh->metrics.metric_default = circuit->metric[level - 1];
1650                   is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED;
1651                   is_neigh->metrics.metric_error = METRICS_UNSUPPORTED;
1652                   is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED;
1653                   if (!memcmp (is_neigh->neigh_id, zero_id,
1654                                ISIS_SYS_ID_LEN + 1))
1655                     {
1656                       XFREE (MTYPE_ISIS_TLV, is_neigh);
1657                       lsp_debug("ISIS (%s): No DIS for circuit, not adding old-style IS neighbor.",
1658                                 area->area_tag);
1659                     }
1660                   else
1661                     {
1662                       listnode_add (tlv_data.is_neighs, is_neigh);
1663                       lsp_debug("ISIS (%s): Adding DIS %s.%02x as old-style neighbor",
1664                                 area->area_tag, sysid_print(is_neigh->neigh_id),
1665                                 LSP_PSEUDO_ID(is_neigh->neigh_id));
1666                     }
1667                 }
1668               if (area->newmetric)
1669                 {
1670                   if (tlv_data.te_is_neighs == NULL)
1671                     {
1672                       tlv_data.te_is_neighs = list_new ();
1673                       tlv_data.te_is_neighs->del = free_tlv;
1674                     }
1675                   te_is_neigh = XCALLOC (MTYPE_ISIS_TLV,
1676                                          sizeof (struct te_is_neigh));
1677                   if (level == IS_LEVEL_1)
1678                     memcpy (te_is_neigh->neigh_id,
1679                             circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
1680                   else
1681                     memcpy (te_is_neigh->neigh_id,
1682                             circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
1683                   if (area->oldmetric)
1684                     metric = circuit->metric[level - 1];
1685                   else
1686                     metric = circuit->te_metric[level - 1];
1687                   SET_TE_METRIC(te_is_neigh, metric);
1688                   if (!memcmp (te_is_neigh->neigh_id, zero_id,
1689                                ISIS_SYS_ID_LEN + 1))
1690                     {
1691                       XFREE (MTYPE_ISIS_TLV, te_is_neigh);
1692                       lsp_debug("ISIS (%s): No DIS for circuit, not adding te-style IS neighbor.",
1693                                 area->area_tag);
1694                     }
1695                   else
1696                     {
1697                       /* Check if MPLS_TE is activate */
1698                       if (IS_MPLS_TE(isisMplsTE) && HAS_LINK_PARAMS(circuit->interface))
1699                         /* Add SubTLVs & Adjust real size of SubTLVs */
1700                         te_is_neigh->sub_tlvs_length = add_te_subtlvs(te_is_neigh->sub_tlvs, circuit->mtc);
1701                       else
1702                         /* Or keep only TE metric with no SubTLVs if MPLS_TE is off */
1703                         te_is_neigh->sub_tlvs_length = 0;
1704
1705                       listnode_add (tlv_data.te_is_neighs, te_is_neigh);
1706                       lsp_debug("ISIS (%s): Adding DIS %s.%02x as te-style neighbor",
1707                                 area->area_tag, sysid_print(te_is_neigh->neigh_id),
1708                                 LSP_PSEUDO_ID(te_is_neigh->neigh_id));
1709                     }
1710                 }
1711             }
1712           else
1713             {
1714               lsp_debug("ISIS (%s): Circuit is not active for current level. Not adding IS neighbors",
1715                         area->area_tag);
1716             }
1717           break;
1718         case CIRCUIT_T_P2P:
1719           nei = circuit->u.p2p.neighbor;
1720           if (nei && (level & nei->circuit_t))
1721             {
1722               if (area->oldmetric)
1723                 {
1724                   if (tlv_data.is_neighs == NULL)
1725                     {
1726                       tlv_data.is_neighs = list_new ();
1727                       tlv_data.is_neighs->del = free_tlv;
1728                     }
1729                   is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
1730                   memcpy (is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN);
1731                   is_neigh->metrics.metric_default = circuit->metric[level - 1];
1732                   is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED;
1733                   is_neigh->metrics.metric_error = METRICS_UNSUPPORTED;
1734                   is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED;
1735                   listnode_add (tlv_data.is_neighs, is_neigh);
1736                   lsp_debug("ISIS (%s): Adding old-style is reach for %s", area->area_tag,
1737                             sysid_print(is_neigh->neigh_id));
1738                 }
1739               if (area->newmetric)
1740                 {
1741                   uint32_t metric;
1742
1743                   if (tlv_data.te_is_neighs == NULL)
1744                     {
1745                       tlv_data.te_is_neighs = list_new ();
1746                       tlv_data.te_is_neighs->del = free_tlv;
1747                     }
1748                   te_is_neigh = XCALLOC (MTYPE_ISIS_TLV,
1749                                          sizeof (struct te_is_neigh));
1750                   memcpy (te_is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN);
1751                   metric = circuit->te_metric[level - 1];
1752                   SET_TE_METRIC(te_is_neigh, metric);
1753                   /* Check if MPLS_TE is activate */
1754                   if (IS_MPLS_TE(isisMplsTE) && HAS_LINK_PARAMS(circuit->interface))
1755                     /* Update Local and Remote IP address for MPLS TE circuit parameters */
1756                     /* NOTE sure that it is the pertinent place for that updates */
1757                     /* Local IP address could be updated in isis_circuit.c - isis_circuit_add_addr() */
1758                     /* But, where update remote IP address ? in isis_pdu.c - process_p2p_hello() ? */
1759
1760                     /* Add SubTLVs & Adjust real size of SubTLVs */
1761                     te_is_neigh->sub_tlvs_length = add_te_subtlvs(te_is_neigh->sub_tlvs, circuit->mtc);
1762                   else
1763                     /* Or keep only TE metric with no SubTLVs if MPLS_TE is off */
1764                     te_is_neigh->sub_tlvs_length = 0;
1765                   listnode_add (tlv_data.te_is_neighs, te_is_neigh);
1766                   lsp_debug("ISIS (%s): Adding te-style is reach for %s", area->area_tag,
1767                             sysid_print(te_is_neigh->neigh_id));
1768                 }
1769             }
1770           else
1771             {
1772               lsp_debug("ISIS (%s): No adjacency for given level on this circuit. Not adding IS neighbors",
1773               area->area_tag);
1774             }
1775           break;
1776         case CIRCUIT_T_LOOPBACK:
1777           break;
1778         default:
1779           zlog_warn ("lsp_area_create: unknown circuit type");
1780         }
1781     }
1782
1783   lsp_build_ext_reach(lsp, area, &tlv_data);
1784
1785   lsp_debug("ISIS (%s): LSP construction is complete. Serializing...", area->area_tag);
1786
1787   while (tlv_data.ipv4_int_reachs && listcount (tlv_data.ipv4_int_reachs))
1788     {
1789       if (lsp->tlv_data.ipv4_int_reachs == NULL)
1790         lsp->tlv_data.ipv4_int_reachs = list_new ();
1791       lsp_tlv_fit (lsp, &tlv_data.ipv4_int_reachs,
1792                    &lsp->tlv_data.ipv4_int_reachs,
1793                    IPV4_REACH_LEN, area->lsp_frag_threshold,
1794                    tlv_add_ipv4_int_reachs);
1795       if (tlv_data.ipv4_int_reachs && listcount (tlv_data.ipv4_int_reachs))
1796         lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
1797                              lsp0, area, level);
1798     }
1799
1800   while (tlv_data.ipv4_ext_reachs && listcount (tlv_data.ipv4_ext_reachs))
1801     {
1802       if (lsp->tlv_data.ipv4_ext_reachs == NULL)
1803         lsp->tlv_data.ipv4_ext_reachs = list_new ();
1804       lsp_tlv_fit (lsp, &tlv_data.ipv4_ext_reachs,
1805                    &lsp->tlv_data.ipv4_ext_reachs,
1806                    IPV4_REACH_LEN, area->lsp_frag_threshold,
1807                    tlv_add_ipv4_ext_reachs);
1808       if (tlv_data.ipv4_ext_reachs && listcount (tlv_data.ipv4_ext_reachs))
1809         lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
1810                              lsp0, area, level);
1811     }
1812
1813   /* FIXME: We pass maximum te_ipv4_reachability length to the lsp_tlv_fit()
1814    * for now. lsp_tlv_fit() needs to be fixed to deal with variable length
1815    * TLVs (sub TLVs!). */
1816   while (tlv_data.te_ipv4_reachs && listcount (tlv_data.te_ipv4_reachs))
1817     {
1818       if (lsp->tlv_data.te_ipv4_reachs == NULL)
1819         lsp->tlv_data.te_ipv4_reachs = list_new ();
1820       lsp_tlv_fit (lsp, &tlv_data.te_ipv4_reachs,
1821                    &lsp->tlv_data.te_ipv4_reachs,
1822                    TE_IPV4_REACH_LEN, area->lsp_frag_threshold,
1823                    tlv_add_te_ipv4_reachs);
1824       if (tlv_data.te_ipv4_reachs && listcount (tlv_data.te_ipv4_reachs))
1825         lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
1826                              lsp0, area, level);
1827     }
1828
1829 #ifdef  HAVE_IPV6
1830   while (tlv_data.ipv6_reachs && listcount (tlv_data.ipv6_reachs))
1831     {
1832       if (lsp->tlv_data.ipv6_reachs == NULL)
1833         lsp->tlv_data.ipv6_reachs = list_new ();
1834       lsp_tlv_fit (lsp, &tlv_data.ipv6_reachs,
1835                    &lsp->tlv_data.ipv6_reachs,
1836                    IPV6_REACH_LEN, area->lsp_frag_threshold,
1837                    tlv_add_ipv6_reachs);
1838       if (tlv_data.ipv6_reachs && listcount (tlv_data.ipv6_reachs))
1839         lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
1840                              lsp0, area, level);
1841     }
1842 #endif /* HAVE_IPV6 */
1843
1844   while (tlv_data.is_neighs && listcount (tlv_data.is_neighs))
1845     {
1846       if (lsp->tlv_data.is_neighs == NULL)
1847         lsp->tlv_data.is_neighs = list_new ();
1848       lsp_tlv_fit (lsp, &tlv_data.is_neighs,
1849                    &lsp->tlv_data.is_neighs,
1850                    IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
1851                    tlv_add_is_neighs);
1852       if (tlv_data.is_neighs && listcount (tlv_data.is_neighs))
1853         lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
1854                              lsp0, area, level);
1855     }
1856
1857   while (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs))
1858     {
1859       if (lsp->tlv_data.te_is_neighs == NULL)
1860         lsp->tlv_data.te_is_neighs = list_new ();
1861       lsp_tlv_fit (lsp, &tlv_data.te_is_neighs, &lsp->tlv_data.te_is_neighs,
1862                    IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
1863                    tlv_add_te_is_neighs);
1864       if (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs))
1865         lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
1866                              lsp0, area, level);
1867     }
1868   lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
1869
1870   free_tlvs (&tlv_data);
1871
1872   /* Validate the LSP */
1873   retval = parse_tlvs (area->area_tag, STREAM_DATA (lsp->pdu) +
1874                        ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN,
1875                        stream_get_endp (lsp->pdu) -
1876                        ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN,
1877                        &expected, &found, &tlv_data, NULL);
1878   assert (retval == ISIS_OK);
1879
1880   return;
1881 }
1882
1883 /*
1884  * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs
1885  */
1886 int
1887 lsp_generate (struct isis_area *area, int level)
1888 {
1889   struct isis_lsp *oldlsp, *newlsp;
1890   u_int32_t seq_num = 0;
1891   u_char lspid[ISIS_SYS_ID_LEN + 2];
1892   u_int16_t rem_lifetime, refresh_time;
1893
1894   if ((area == NULL) || (area->is_type & level) != level)
1895     return ISIS_ERROR;
1896
1897   memset (&lspid, 0, ISIS_SYS_ID_LEN + 2);
1898   memcpy (&lspid, isis->sysid, ISIS_SYS_ID_LEN);
1899
1900   /* only builds the lsp if the area shares the level */
1901   oldlsp = lsp_search (lspid, area->lspdb[level - 1]);
1902   if (oldlsp)
1903     {
1904       /* FIXME: we should actually initiate a purge */
1905       seq_num = ntohl (oldlsp->lsp_header->seq_num);
1906       lsp_search_and_destroy (oldlsp->lsp_header->lsp_id,
1907                               area->lspdb[level - 1]);
1908     }
1909   rem_lifetime = lsp_rem_lifetime (area, level);
1910   newlsp = lsp_new (area, lspid, rem_lifetime, seq_num,
1911                     area->is_type | area->overload_bit | area->attached_bit,
1912                     0, level);
1913   newlsp->area = area;
1914   newlsp->own_lsp = 1;
1915
1916   lsp_insert (newlsp, area->lspdb[level - 1]);
1917   /* build_lsp_data (newlsp, area); */
1918   lsp_build (newlsp, area);
1919   /* time to calculate our checksum */
1920   lsp_seqnum_update (newlsp);
1921   newlsp->last_generated = time(NULL);
1922   lsp_set_all_srmflags (newlsp);
1923
1924   refresh_time = lsp_refresh_time (newlsp, rem_lifetime);
1925
1926   THREAD_TIMER_OFF (area->t_lsp_refresh[level - 1]);
1927   area->lsp_regenerate_pending[level - 1] = 0;
1928   if (level == IS_LEVEL_1)
1929     THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
1930                      lsp_l1_refresh, area, refresh_time);
1931   else if (level == IS_LEVEL_2)
1932     THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
1933                      lsp_l2_refresh, area, refresh_time);
1934
1935   if (isis->debugs & DEBUG_UPDATE_PACKETS)
1936     {
1937       zlog_debug ("ISIS-Upd (%s): Building L%d LSP %s, len %d, "
1938                   "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us",
1939                   area->area_tag, level,
1940                   rawlspid_print (newlsp->lsp_header->lsp_id),
1941                   ntohl (newlsp->lsp_header->pdu_len),
1942                   ntohl (newlsp->lsp_header->seq_num),
1943                   ntohs (newlsp->lsp_header->checksum),
1944                   ntohs (newlsp->lsp_header->rem_lifetime),
1945                   refresh_time);
1946     }
1947   sched_debug("ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.",
1948               area->area_tag, level);
1949
1950   return ISIS_OK;
1951 }
1952
1953 /*
1954  * Search own LSPs, update holding time and set SRM
1955  */
1956 static int
1957 lsp_regenerate (struct isis_area *area, int level)
1958 {
1959   dict_t *lspdb;
1960   struct isis_lsp *lsp, *frag;
1961   struct listnode *node;
1962   u_char lspid[ISIS_SYS_ID_LEN + 2];
1963   u_int16_t rem_lifetime, refresh_time;
1964
1965   if ((area == NULL) || (area->is_type & level) != level)
1966     return ISIS_ERROR;
1967
1968   lspdb = area->lspdb[level - 1];
1969
1970   memset (lspid, 0, ISIS_SYS_ID_LEN + 2);
1971   memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN);
1972
1973   lsp = lsp_search (lspid, lspdb);
1974
1975   if (!lsp)
1976     {
1977       zlog_err ("ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
1978                 area->area_tag, level);
1979       return ISIS_ERROR;
1980     }
1981
1982   lsp_clear_data (lsp);
1983   lsp_build (lsp, area);
1984   lsp->lsp_header->lsp_bits = lsp_bits_generate (level, area->overload_bit,
1985                                                  area->attached_bit);
1986   rem_lifetime = lsp_rem_lifetime (area, level);
1987   lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
1988   lsp_seqnum_update (lsp);
1989
1990   lsp->last_generated = time (NULL);
1991   lsp_set_all_srmflags (lsp);
1992   for (ALL_LIST_ELEMENTS_RO (lsp->lspu.frags, node, frag))
1993     {
1994       frag->lsp_header->lsp_bits = lsp_bits_generate (level,
1995                                                       area->overload_bit,
1996                                                       area->attached_bit);
1997       /* Set the lifetime values of all the fragments to the same value,
1998        * so that no fragment expires before the lsp is refreshed.
1999        */
2000       frag->lsp_header->rem_lifetime = htons (rem_lifetime);
2001       lsp_set_all_srmflags (frag);
2002     }
2003
2004   refresh_time = lsp_refresh_time (lsp, rem_lifetime);
2005   if (level == IS_LEVEL_1)
2006     THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
2007                      lsp_l1_refresh, area, refresh_time);
2008   else if (level == IS_LEVEL_2)
2009     THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
2010                      lsp_l2_refresh, area, refresh_time);
2011   area->lsp_regenerate_pending[level - 1] = 0;
2012
2013   if (isis->debugs & DEBUG_UPDATE_PACKETS)
2014     {
2015       zlog_debug ("ISIS-Upd (%s): Refreshing our L%d LSP %s, len %d, "
2016                   "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us",
2017                   area->area_tag, level,
2018                   rawlspid_print (lsp->lsp_header->lsp_id),
2019                   ntohl (lsp->lsp_header->pdu_len),
2020                   ntohl (lsp->lsp_header->seq_num),
2021                   ntohs (lsp->lsp_header->checksum),
2022                   ntohs (lsp->lsp_header->rem_lifetime),
2023                   refresh_time);
2024     }
2025   sched_debug("ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to non-pending.",
2026               area->area_tag, level);
2027
2028   return ISIS_OK;
2029 }
2030
2031 /*
2032  * Something has changed or periodic refresh -> regenerate LSP
2033  */
2034 static int
2035 lsp_l1_refresh (struct thread *thread)
2036 {
2037   struct isis_area *area;
2038
2039   area = THREAD_ARG (thread);
2040   assert (area);
2041
2042   area->t_lsp_refresh[0] = NULL;
2043   area->lsp_regenerate_pending[0] = 0;
2044
2045   if ((area->is_type & IS_LEVEL_1) == 0)
2046     return ISIS_ERROR;
2047
2048   sched_debug("ISIS (%s): LSP L1 refresh timer expired. Refreshing LSP...", area->area_tag);
2049   return lsp_regenerate (area, IS_LEVEL_1);
2050 }
2051
2052 static int
2053 lsp_l2_refresh (struct thread *thread)
2054 {
2055   struct isis_area *area;
2056
2057   area = THREAD_ARG (thread);
2058   assert (area);
2059
2060   area->t_lsp_refresh[1] = NULL;
2061   area->lsp_regenerate_pending[1] = 0;
2062
2063   if ((area->is_type & IS_LEVEL_2) == 0)
2064     return ISIS_ERROR;
2065
2066   sched_debug("ISIS (%s): LSP L2 refresh timer expired. Refreshing LSP...", area->area_tag);
2067   return lsp_regenerate (area, IS_LEVEL_2);
2068 }
2069
2070 int
2071 lsp_regenerate_schedule (struct isis_area *area, int level, int all_pseudo)
2072 {
2073   struct isis_lsp *lsp;
2074   u_char id[ISIS_SYS_ID_LEN + 2];
2075   time_t now, diff;
2076   long timeout;
2077   struct listnode *cnode;
2078   struct isis_circuit *circuit;
2079   int lvl;
2080
2081   if (area == NULL)
2082     return ISIS_ERROR;
2083
2084   sched_debug("ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs",
2085             area->area_tag, circuit_t2string(level), all_pseudo ? "" : "not ");
2086
2087   memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
2088   LSP_PSEUDO_ID (id) = LSP_FRAGMENT (id) = 0;
2089   now = time (NULL);
2090
2091   for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++)
2092     {
2093       if (!((level & lvl) && (area->is_type & lvl)))
2094         continue;
2095
2096       sched_debug("ISIS (%s): Checking whether L%d needs to be scheduled",
2097                   area->area_tag, lvl);
2098
2099       if (area->lsp_regenerate_pending[lvl - 1])
2100         {
2101           struct timeval remain = thread_timer_remain(area->t_lsp_refresh[lvl - 1]);
2102           sched_debug("ISIS (%s): Regeneration is already pending, nothing todo."
2103                       " (Due in %lld.%03lld seconds)", area->area_tag,
2104                       (long long)remain.tv_sec, (long long)remain.tv_usec / 1000);
2105           continue;
2106         }
2107
2108       lsp = lsp_search (id, area->lspdb[lvl - 1]);
2109       if (!lsp)
2110         {
2111           sched_debug("ISIS (%s): We do not have any LSPs to regenerate, nothing todo.",
2112                       area->area_tag);
2113           continue;
2114         }
2115
2116       /*
2117        * Throttle avoidance
2118        */
2119       sched_debug("ISIS (%s): Will schedule regen timer. Last run was: %lld, Now is: %lld",
2120                   area->area_tag, (long long)lsp->last_generated, (long long)now);
2121       THREAD_TIMER_OFF (area->t_lsp_refresh[lvl - 1]);
2122       diff = now - lsp->last_generated;
2123       if (diff < area->lsp_gen_interval[lvl - 1])
2124         {
2125           timeout = 1000 * (area->lsp_gen_interval[lvl - 1] - diff);
2126           sched_debug("ISIS (%s): Scheduling in %ld ms to match configured lsp_gen_interval",
2127                       area->area_tag, timeout);
2128         }
2129       else
2130         {
2131           /*
2132            * lsps are not regenerated if lsp_regenerate function is called
2133            * directly. However if the lsp_regenerate call is queued for
2134            * later execution it works.
2135            */
2136           timeout = 100;
2137           sched_debug("ISIS (%s): Last generation was more than lsp_gen_interval ago."
2138                       " Scheduling for execution in %ld ms.", area->area_tag, timeout);
2139         }
2140
2141       area->lsp_regenerate_pending[lvl - 1] = 1;
2142       if (lvl == IS_LEVEL_1)
2143         {
2144           THREAD_TIMER_MSEC_ON(master, area->t_lsp_refresh[lvl - 1],
2145                                lsp_l1_refresh, area, timeout);
2146         }
2147       else if (lvl == IS_LEVEL_2)
2148         {
2149           THREAD_TIMER_MSEC_ON(master, area->t_lsp_refresh[lvl - 1],
2150                                lsp_l2_refresh, area, timeout);
2151         }
2152     }
2153
2154   if (all_pseudo)
2155     {
2156       for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit))
2157         lsp_regenerate_schedule_pseudo (circuit, level);
2158     }
2159
2160   return ISIS_OK;
2161 }
2162
2163 /*
2164  * Funcs for pseudonode LSPs
2165  */
2166
2167 /*
2168  * 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs 
2169  */
2170 static void
2171 lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit,
2172                   int level)
2173 {
2174   struct isis_adjacency *adj;
2175   struct is_neigh *is_neigh;
2176   struct te_is_neigh *te_is_neigh;
2177   struct es_neigh *es_neigh;
2178   struct list *adj_list;
2179   struct listnode *node;
2180   struct isis_area *area = circuit->area;
2181
2182   lsp_debug("ISIS (%s): Constructing pseudo LSP %s for interface %s level %d",
2183             area->area_tag, rawlspid_print(lsp->lsp_header->lsp_id),
2184             circuit->interface->name, level);
2185
2186   lsp->level = level;
2187   /* RFC3787  section 4 SHOULD not set overload bit in pseudo LSPs */
2188   lsp->lsp_header->lsp_bits = lsp_bits_generate (level, 0,
2189                                                  circuit->area->attached_bit);
2190
2191   /*
2192    * add self to IS neighbours 
2193    */
2194   if (circuit->area->oldmetric)
2195     {
2196       if (lsp->tlv_data.is_neighs == NULL)
2197         {
2198           lsp->tlv_data.is_neighs = list_new ();
2199           lsp->tlv_data.is_neighs->del = free_tlv;
2200         }
2201       is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
2202
2203       memcpy (&is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN);
2204       listnode_add (lsp->tlv_data.is_neighs, is_neigh);
2205       lsp_debug("ISIS (%s): Adding %s.%02x as old-style neighbor (self)",
2206                 area->area_tag, sysid_print(is_neigh->neigh_id),
2207                 LSP_PSEUDO_ID(is_neigh->neigh_id));
2208     }
2209   if (circuit->area->newmetric)
2210     {
2211       if (lsp->tlv_data.te_is_neighs == NULL)
2212         {
2213           lsp->tlv_data.te_is_neighs = list_new ();
2214           lsp->tlv_data.te_is_neighs->del = free_tlv;
2215         }
2216       te_is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct te_is_neigh));
2217
2218       memcpy (&te_is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN);
2219       listnode_add (lsp->tlv_data.te_is_neighs, te_is_neigh);
2220       lsp_debug("ISIS (%s): Adding %s.%02x as te-style neighbor (self)",
2221                 area->area_tag, sysid_print(te_is_neigh->neigh_id),
2222                 LSP_PSEUDO_ID(te_is_neigh->neigh_id));
2223     }
2224
2225   adj_list = list_new ();
2226   isis_adj_build_up_list (circuit->u.bc.adjdb[level - 1], adj_list);
2227
2228   for (ALL_LIST_ELEMENTS_RO (adj_list, node, adj))
2229     {
2230       if (adj->level & level)
2231         {
2232           if ((level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_L1_IS) ||
2233               (level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_L2_IS &&
2234               adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
2235               (level == IS_LEVEL_2 && adj->sys_type == ISIS_SYSTYPE_L2_IS))
2236             {
2237               /* an IS neighbour -> add it */
2238               if (circuit->area->oldmetric)
2239                 {
2240                   is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
2241
2242                   memcpy (&is_neigh->neigh_id, adj->sysid, ISIS_SYS_ID_LEN);
2243                   listnode_add (lsp->tlv_data.is_neighs, is_neigh);
2244                   lsp_debug("ISIS (%s): Adding %s.%02x as old-style neighbor (peer)",
2245                             area->area_tag, sysid_print(is_neigh->neigh_id),
2246                             LSP_PSEUDO_ID(is_neigh->neigh_id));
2247                 }
2248               if (circuit->area->newmetric)
2249                 {
2250                   te_is_neigh = XCALLOC (MTYPE_ISIS_TLV,
2251                                          sizeof (struct te_is_neigh));
2252                   memcpy (&te_is_neigh->neigh_id, adj->sysid, ISIS_SYS_ID_LEN);
2253                   listnode_add (lsp->tlv_data.te_is_neighs, te_is_neigh);
2254                   lsp_debug("ISIS (%s): Adding %s.%02x as te-style neighbor (peer)",
2255                             area->area_tag, sysid_print(te_is_neigh->neigh_id),
2256                             LSP_PSEUDO_ID(te_is_neigh->neigh_id));
2257                 }
2258             }
2259           else if (level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_ES)
2260             {
2261               /* an ES neigbour add it, if we are building level 1 LSP */
2262               /* FIXME: the tlv-format is hard to use here */
2263               if (lsp->tlv_data.es_neighs == NULL)
2264                 {
2265                   lsp->tlv_data.es_neighs = list_new ();
2266                   lsp->tlv_data.es_neighs->del = free_tlv;
2267                 }
2268               es_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct es_neigh));
2269               
2270               memcpy (&es_neigh->first_es_neigh, adj->sysid, ISIS_SYS_ID_LEN);
2271               listnode_add (lsp->tlv_data.es_neighs, es_neigh);
2272               lsp_debug("ISIS (%s): Adding %s as ES neighbor (peer)",
2273                         area->area_tag, sysid_print(es_neigh->first_es_neigh));
2274             }
2275           else
2276             {
2277               lsp_debug("ISIS (%s): Ignoring neighbor %s, level does not match",
2278                         area->area_tag, sysid_print(adj->sysid));
2279             }
2280         }
2281       else
2282         {
2283           lsp_debug("ISIS (%s): Ignoring neighbor %s, level does not intersect",
2284                     area->area_tag, sysid_print(adj->sysid));
2285         }
2286     }
2287   list_delete (adj_list);
2288
2289   lsp_debug("ISIS (%s): Pseudo LSP construction is complete.", area->area_tag);
2290
2291   /* Reset endp of stream to overwrite only TLV part of it. */
2292   stream_reset (lsp->pdu);
2293   stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
2294
2295   /*
2296    * Add the authentication info if it's present
2297    */
2298   lsp_auth_add (lsp);
2299
2300   if (lsp->tlv_data.is_neighs && listcount (lsp->tlv_data.is_neighs) > 0)
2301     tlv_add_is_neighs (lsp->tlv_data.is_neighs, lsp->pdu);
2302
2303   if (lsp->tlv_data.te_is_neighs && listcount (lsp->tlv_data.te_is_neighs) > 0)
2304     tlv_add_te_is_neighs (lsp->tlv_data.te_is_neighs, lsp->pdu);
2305
2306   if (lsp->tlv_data.es_neighs && listcount (lsp->tlv_data.es_neighs) > 0)
2307     tlv_add_is_neighs (lsp->tlv_data.es_neighs, lsp->pdu);
2308
2309   lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
2310
2311   /* Recompute authentication and checksum information */
2312   lsp_auth_update (lsp);
2313   fletcher_checksum(STREAM_DATA (lsp->pdu) + 12,
2314                     ntohs (lsp->lsp_header->pdu_len) - 12, 12);
2315
2316   return;
2317 }
2318
2319 int
2320 lsp_generate_pseudo (struct isis_circuit *circuit, int level)
2321 {
2322   dict_t *lspdb = circuit->area->lspdb[level - 1];
2323   struct isis_lsp *lsp;
2324   u_char lsp_id[ISIS_SYS_ID_LEN + 2];
2325   u_int16_t rem_lifetime, refresh_time;
2326
2327   if ((circuit->is_type & level) != level ||
2328       (circuit->state != C_STATE_UP) ||
2329       (circuit->circ_type != CIRCUIT_T_BROADCAST) ||
2330       (circuit->u.bc.is_dr[level - 1] == 0))
2331     return ISIS_ERROR;
2332
2333   memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
2334   LSP_FRAGMENT (lsp_id) = 0;
2335   LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id;
2336
2337   /*
2338    * If for some reason have a pseudo LSP in the db already -> regenerate
2339    */
2340   if (lsp_search (lsp_id, lspdb))
2341     return lsp_regenerate_schedule_pseudo (circuit, level);
2342
2343   rem_lifetime = lsp_rem_lifetime (circuit->area, level);
2344   /* RFC3787  section 4 SHOULD not set overload bit in pseudo LSPs */
2345   lsp = lsp_new (circuit->area, lsp_id, rem_lifetime, 1,
2346                  circuit->area->is_type | circuit->area->attached_bit,
2347                  0, level);
2348   lsp->area = circuit->area;
2349
2350   lsp_build_pseudo (lsp, circuit, level);
2351
2352   lsp->own_lsp = 1;
2353   lsp_insert (lsp, lspdb);
2354   lsp_set_all_srmflags (lsp);
2355
2356   refresh_time = lsp_refresh_time (lsp, rem_lifetime);
2357   THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
2358   circuit->lsp_regenerate_pending[level - 1] = 0;
2359   if (level == IS_LEVEL_1)
2360     THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
2361                      lsp_l1_refresh_pseudo, circuit, refresh_time);
2362   else if (level == IS_LEVEL_2)
2363     THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
2364                      lsp_l2_refresh_pseudo, circuit, refresh_time);
2365
2366   if (isis->debugs & DEBUG_UPDATE_PACKETS)
2367     {
2368       zlog_debug ("ISIS-Upd (%s): Building L%d Pseudo LSP %s, len %d, "
2369                   "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us",
2370                   circuit->area->area_tag, level,
2371                   rawlspid_print (lsp->lsp_header->lsp_id),
2372                   ntohl (lsp->lsp_header->pdu_len),
2373                   ntohl (lsp->lsp_header->seq_num),
2374                   ntohs (lsp->lsp_header->checksum),
2375                   ntohs (lsp->lsp_header->rem_lifetime),
2376                   refresh_time);
2377     }
2378
2379   return ISIS_OK;
2380 }
2381
2382 static int
2383 lsp_regenerate_pseudo (struct isis_circuit *circuit, int level)
2384 {
2385   dict_t *lspdb = circuit->area->lspdb[level - 1];
2386   struct isis_lsp *lsp;
2387   u_char lsp_id[ISIS_SYS_ID_LEN + 2];
2388   u_int16_t rem_lifetime, refresh_time;
2389
2390   if ((circuit->is_type & level) != level ||
2391       (circuit->state != C_STATE_UP) ||
2392       (circuit->circ_type != CIRCUIT_T_BROADCAST) ||
2393       (circuit->u.bc.is_dr[level - 1] == 0))
2394     return ISIS_ERROR;
2395
2396   memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
2397   LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id;
2398   LSP_FRAGMENT (lsp_id) = 0;
2399
2400   lsp = lsp_search (lsp_id, lspdb);
2401
2402   if (!lsp)
2403     {
2404       zlog_err ("lsp_regenerate_pseudo: no l%d LSP %s found!",
2405                 level, rawlspid_print (lsp_id));
2406       return ISIS_ERROR;
2407     }
2408   lsp_clear_data (lsp);
2409
2410   lsp_build_pseudo (lsp, circuit, level);
2411
2412   /* RFC3787  section 4 SHOULD not set overload bit in pseudo LSPs */
2413   lsp->lsp_header->lsp_bits = lsp_bits_generate (level, 0,
2414                                                  circuit->area->attached_bit);
2415   rem_lifetime = lsp_rem_lifetime (circuit->area, level);
2416   lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
2417   lsp_inc_seqnum (lsp, 0);
2418   lsp->last_generated = time (NULL);
2419   lsp_set_all_srmflags (lsp);
2420
2421   refresh_time = lsp_refresh_time (lsp, rem_lifetime);
2422   if (level == IS_LEVEL_1)
2423     THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
2424                      lsp_l1_refresh_pseudo, circuit, refresh_time);
2425   else if (level == IS_LEVEL_2)
2426     THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
2427                      lsp_l2_refresh_pseudo, circuit, refresh_time);
2428
2429   if (isis->debugs & DEBUG_UPDATE_PACKETS)
2430     {
2431       zlog_debug ("ISIS-Upd (%s): Refreshing L%d Pseudo LSP %s, len %d, "
2432                   "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us",
2433                   circuit->area->area_tag, level,
2434                   rawlspid_print (lsp->lsp_header->lsp_id),
2435                   ntohl (lsp->lsp_header->pdu_len),
2436                   ntohl (lsp->lsp_header->seq_num),
2437                   ntohs (lsp->lsp_header->checksum),
2438                   ntohs (lsp->lsp_header->rem_lifetime),
2439                   refresh_time);
2440     }
2441
2442   return ISIS_OK;
2443 }
2444
2445 /*
2446  * Something has changed or periodic refresh -> regenerate pseudo LSP
2447  */
2448 static int
2449 lsp_l1_refresh_pseudo (struct thread *thread)
2450 {
2451   struct isis_circuit *circuit;
2452   u_char id[ISIS_SYS_ID_LEN + 2];
2453
2454   circuit = THREAD_ARG (thread);
2455
2456   circuit->u.bc.t_refresh_pseudo_lsp[0] = NULL;
2457   circuit->lsp_regenerate_pending[0] = 0;
2458
2459   if ((circuit->u.bc.is_dr[0] == 0) ||
2460       (circuit->is_type & IS_LEVEL_1) == 0)
2461     {
2462       memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
2463       LSP_PSEUDO_ID (id) = circuit->circuit_id;
2464       LSP_FRAGMENT (id) = 0;
2465       lsp_purge_pseudo (id, circuit, IS_LEVEL_1);
2466       return ISIS_ERROR;
2467     }
2468
2469   return lsp_regenerate_pseudo (circuit, IS_LEVEL_1);
2470 }
2471
2472 static int
2473 lsp_l2_refresh_pseudo (struct thread *thread)
2474 {
2475   struct isis_circuit *circuit;
2476   u_char id[ISIS_SYS_ID_LEN + 2];
2477
2478   circuit = THREAD_ARG (thread);
2479
2480   circuit->u.bc.t_refresh_pseudo_lsp[1] = NULL;
2481   circuit->lsp_regenerate_pending[1] = 0;
2482
2483   if ((circuit->u.bc.is_dr[1] == 0) ||
2484       (circuit->is_type & IS_LEVEL_2) == 0)
2485     {
2486       memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
2487       LSP_PSEUDO_ID (id) = circuit->circuit_id;
2488       LSP_FRAGMENT (id) = 0;
2489       lsp_purge_pseudo (id, circuit, IS_LEVEL_2);
2490       return ISIS_ERROR;
2491     }
2492
2493   return lsp_regenerate_pseudo (circuit, IS_LEVEL_2);
2494 }
2495
2496 int
2497 lsp_regenerate_schedule_pseudo (struct isis_circuit *circuit, int level)
2498 {
2499   struct isis_lsp *lsp;
2500   u_char lsp_id[ISIS_SYS_ID_LEN + 2];
2501   time_t now, diff;
2502   long timeout;
2503   int lvl;
2504   struct isis_area *area = circuit->area;
2505
2506   if (circuit == NULL ||
2507       circuit->circ_type != CIRCUIT_T_BROADCAST ||
2508       circuit->state != C_STATE_UP)
2509     return ISIS_OK;
2510
2511   sched_debug("ISIS (%s): Scheduling regeneration of %s pseudo LSP for interface %s",
2512               area->area_tag, circuit_t2string(level), circuit->interface->name);
2513
2514   memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
2515   LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id;
2516   LSP_FRAGMENT (lsp_id) = 0;
2517   now = time (NULL);
2518
2519   for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++)
2520     {
2521       sched_debug("ISIS (%s): Checking whether L%d pseudo LSP needs to be scheduled",
2522                   area->area_tag, lvl);
2523
2524       if (!((level & lvl) && (circuit->is_type & lvl)))
2525         {
2526           sched_debug("ISIS (%s): Level is not active on circuit",
2527                       area->area_tag);
2528           continue;
2529         }
2530
2531       if (circuit->u.bc.is_dr[lvl - 1] == 0)
2532         {
2533           sched_debug("ISIS (%s): This IS is not DR, nothing to do.",
2534                       area->area_tag);
2535           continue;
2536         }
2537
2538       if (circuit->lsp_regenerate_pending[lvl - 1])
2539         {
2540           struct timeval remain =
2541                   thread_timer_remain(circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
2542           sched_debug("ISIS (%s): Regenerate is already pending, nothing todo."
2543                       " (Due in %lld.%03lld seconds)", area->area_tag,
2544                       (long long)remain.tv_sec, (long long)remain.tv_usec/1000);
2545           continue;
2546         }
2547
2548       lsp = lsp_search (lsp_id, circuit->area->lspdb[lvl - 1]);
2549       if (!lsp)
2550         {
2551           sched_debug("ISIS (%s): Pseudonode LSP does not exist yet, nothing to regenerate.",
2552                       area->area_tag);
2553           continue;
2554         }
2555
2556       /*
2557        * Throttle avoidance
2558        */
2559       sched_debug("ISIS (%s): Will schedule PSN regen timer. Last run was: %lld, Now is: %lld",
2560                   area->area_tag, (long long)lsp->last_generated, (long long) now);
2561       THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
2562       diff = now - lsp->last_generated;
2563       if (diff < circuit->area->lsp_gen_interval[lvl - 1])
2564         {
2565           timeout = 1000 * (circuit->area->lsp_gen_interval[lvl - 1] - diff);
2566           sched_debug("ISIS (%s): Sechduling in %ld ms to match configured lsp_gen_interval",
2567                       area->area_tag, timeout);
2568         }
2569       else
2570         {
2571           timeout = 100;
2572           sched_debug("ISIS (%s): Last generation was more than lsp_gen_interval ago."
2573                       " Scheduling for execution in %ld ms.", area->area_tag, timeout);
2574         }
2575
2576       circuit->lsp_regenerate_pending[lvl - 1] = 1;
2577
2578       if (lvl == IS_LEVEL_1)
2579         {
2580           THREAD_TIMER_MSEC_ON(master,
2581                                circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1],
2582                                lsp_l1_refresh_pseudo, circuit, timeout);
2583         }
2584       else if (lvl == IS_LEVEL_2)
2585         {
2586           THREAD_TIMER_MSEC_ON(master,
2587                                circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1],
2588                                lsp_l2_refresh_pseudo, circuit, timeout);
2589         }
2590     }
2591
2592   return ISIS_OK;
2593 }
2594
2595 /*
2596  * Walk through LSPs for an area
2597  *  - set remaining lifetime
2598  *  - set LSPs with SRMflag set for sending
2599  */
2600 int
2601 lsp_tick (struct thread *thread)
2602 {
2603   struct isis_area *area;
2604   struct isis_circuit *circuit;
2605   struct isis_lsp *lsp;
2606   struct list *lsp_list;
2607   struct listnode *lspnode, *cnode;
2608   dnode_t *dnode, *dnode_next;
2609   int level;
2610   u_int16_t rem_lifetime;
2611
2612   lsp_list = list_new ();
2613
2614   area = THREAD_ARG (thread);
2615   assert (area);
2616   area->t_tick = NULL;
2617   THREAD_TIMER_ON (master, area->t_tick, lsp_tick, area, 1);
2618
2619   /*
2620    * Build a list of LSPs with (any) SRMflag set
2621    * and removed the ones that have aged out
2622    */
2623   for (level = 0; level < ISIS_LEVELS; level++)
2624     {
2625       if (area->lspdb[level] && dict_count (area->lspdb[level]) > 0)
2626         {
2627           for (dnode = dict_first (area->lspdb[level]);
2628                dnode != NULL; dnode = dnode_next)
2629             {
2630               dnode_next = dict_next (area->lspdb[level], dnode);
2631               lsp = dnode_get (dnode);
2632
2633               /*
2634                * The lsp rem_lifetime is kept at 0 for MaxAge or
2635                * ZeroAgeLifetime depending on explicit purge or
2636                * natural age out. So schedule spf only once when
2637                * the first time rem_lifetime becomes 0.
2638                */
2639               rem_lifetime = ntohs(lsp->lsp_header->rem_lifetime);
2640               lsp_set_time (lsp);
2641
2642               /*
2643                * Schedule may run spf which should be done only after
2644                * the lsp rem_lifetime becomes 0 for the first time.
2645                * ISO 10589 - 7.3.16.4 first paragraph.
2646                */
2647               if (rem_lifetime == 1 && lsp->lsp_header->seq_num != 0)
2648                 {
2649                   /* 7.3.16.4 a) set SRM flags on all */
2650                   lsp_set_all_srmflags (lsp);
2651                   /* 7.3.16.4 b) retain only the header FIXME  */
2652                   /* 7.3.16.4 c) record the time to purge FIXME */
2653                   /* run/schedule spf */
2654                   /* isis_spf_schedule is called inside lsp_destroy() below;
2655                    * so it is not needed here. */
2656                   /* isis_spf_schedule (lsp->area, lsp->level); */
2657                 }
2658
2659               if (lsp->age_out == 0)
2660                 {
2661                   zlog_debug ("ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out",
2662                               area->area_tag,
2663                               lsp->level,
2664                               rawlspid_print (lsp->lsp_header->lsp_id),
2665                               ntohl (lsp->lsp_header->seq_num));
2666 #ifdef TOPOLOGY_GENERATE
2667                   if (lsp->from_topology)
2668                     THREAD_TIMER_OFF (lsp->t_lsp_top_ref);
2669 #endif /* TOPOLOGY_GENERATE */
2670                   lsp_destroy (lsp);
2671                   lsp = NULL;
2672                   dict_delete_free (area->lspdb[level], dnode);
2673                 }
2674               else if (flags_any_set (lsp->SRMflags))
2675                 listnode_add (lsp_list, lsp);
2676             }
2677
2678           /*
2679            * Send LSPs on circuits indicated by the SRMflags
2680            */
2681           if (listcount (lsp_list) > 0)
2682             {
2683               for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit))
2684                 {
2685                   int diff = time (NULL) - circuit->lsp_queue_last_cleared;
2686                   if (circuit->lsp_queue == NULL ||
2687                       diff < MIN_LSP_TRANS_INTERVAL)
2688                     continue;
2689                   for (ALL_LIST_ELEMENTS_RO (lsp_list, lspnode, lsp))
2690                     {
2691                       if (circuit->upadjcount[lsp->level - 1] &&
2692                           ISIS_CHECK_FLAG (lsp->SRMflags, circuit))
2693                         {
2694                           /* Add the lsp only if it is not already in lsp
2695                            * queue */
2696                           if (! listnode_lookup (circuit->lsp_queue, lsp))
2697                             {
2698                               listnode_add (circuit->lsp_queue, lsp);
2699                               thread_add_event (master, send_lsp, circuit, 0);
2700                             }
2701                         }
2702                     }
2703                 }
2704               list_delete_all_node (lsp_list);
2705             }
2706         }
2707     }
2708
2709   list_delete (lsp_list);
2710
2711   return ISIS_OK;
2712 }
2713
2714 void
2715 lsp_purge_pseudo (u_char * id, struct isis_circuit *circuit, int level)
2716 {
2717   struct isis_lsp *lsp;
2718   u_int16_t seq_num;
2719   u_int8_t lsp_bits;
2720
2721   lsp = lsp_search (id, circuit->area->lspdb[level - 1]);
2722   if (!lsp)
2723     return;
2724
2725   /* store old values */
2726   seq_num = lsp->lsp_header->seq_num;
2727   lsp_bits = lsp->lsp_header->lsp_bits;
2728
2729   /* reset stream */
2730   lsp_clear_data (lsp);
2731   stream_reset (lsp->pdu);
2732
2733   /* update header */
2734   lsp->lsp_header->pdu_len = htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
2735   memcpy (lsp->lsp_header->lsp_id, id, ISIS_SYS_ID_LEN + 2);
2736   lsp->lsp_header->checksum = 0;
2737   lsp->lsp_header->seq_num = seq_num;
2738   lsp->lsp_header->rem_lifetime = 0;
2739   lsp->lsp_header->lsp_bits = lsp_bits;
2740   lsp->level = level;
2741   lsp->age_out = lsp->area->max_lsp_lifetime[level-1];
2742   stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
2743
2744   /*
2745    * Add and update the authentication info if its present
2746    */
2747   lsp_auth_add (lsp);
2748   lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
2749   lsp_auth_update (lsp);
2750   fletcher_checksum(STREAM_DATA (lsp->pdu) + 12,
2751                     ntohs (lsp->lsp_header->pdu_len) - 12, 12);
2752
2753   lsp_set_all_srmflags (lsp);
2754
2755   return;
2756 }
2757
2758 /*
2759  * Purge own LSP that is received and we don't have. 
2760  * -> Do as in 7.3.16.4
2761  */
2762 void
2763 lsp_purge_non_exist (int level,
2764                      struct isis_link_state_hdr *lsp_hdr,
2765                      struct isis_area *area)
2766 {
2767   struct isis_lsp *lsp;
2768
2769   /*
2770    * We need to create the LSP to be purged 
2771    */
2772   lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp));
2773   lsp->area = area;
2774   lsp->level = level;
2775   lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu);
2776   lsp->isis_header = (struct isis_fixed_hdr *) STREAM_DATA (lsp->pdu);
2777   fill_fixed_hdr (lsp->isis_header, (lsp->level == IS_LEVEL_1) ? L1_LINK_STATE
2778                   : L2_LINK_STATE);
2779   lsp->lsp_header = (struct isis_link_state_hdr *) (STREAM_DATA (lsp->pdu) +
2780                                                     ISIS_FIXED_HDR_LEN);
2781   memcpy (lsp->lsp_header, lsp_hdr, ISIS_LSP_HDR_LEN);
2782   stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
2783
2784   /*
2785    * Set the remaining lifetime to 0
2786    */
2787   lsp->lsp_header->rem_lifetime = 0;
2788
2789   /*
2790    * Add and update the authentication info if its present
2791    */
2792   lsp_auth_add (lsp);
2793   lsp_auth_update (lsp);
2794
2795   /*
2796    * Update the PDU length to header plus any authentication TLV.
2797    */
2798   lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
2799
2800   /*
2801    * Put the lsp into LSPdb
2802    */
2803   lsp_insert (lsp, area->lspdb[lsp->level - 1]);
2804
2805   /*
2806    * Send in to whole area
2807    */
2808   lsp_set_all_srmflags (lsp);
2809
2810   return;
2811 }
2812
2813 void lsp_set_all_srmflags (struct isis_lsp *lsp)
2814 {
2815   struct listnode *node;
2816   struct isis_circuit *circuit;
2817
2818   assert (lsp);
2819
2820   ISIS_FLAGS_CLEAR_ALL(lsp->SRMflags);
2821
2822   if (lsp->area)
2823     {
2824       struct list *circuit_list = lsp->area->circuit_list;
2825       for (ALL_LIST_ELEMENTS_RO (circuit_list, node, circuit))
2826         {
2827           ISIS_SET_FLAG(lsp->SRMflags, circuit);
2828         }
2829     }
2830 }
2831
2832 #ifdef TOPOLOGY_GENERATE
2833 static int
2834 top_lsp_refresh (struct thread *thread)
2835 {
2836   struct isis_lsp *lsp;
2837   u_int16_t rem_lifetime;
2838
2839   lsp = THREAD_ARG (thread);
2840   assert (lsp);
2841
2842   lsp->t_lsp_top_ref = NULL;
2843
2844   lsp_seqnum_update (lsp);
2845
2846   lsp_set_all_srmflags (lsp);
2847   if (isis->debugs & DEBUG_UPDATE_PACKETS)
2848     {
2849       zlog_debug ("ISIS-Upd (): refreshing Topology L1 %s",
2850                   rawlspid_print (lsp->lsp_header->lsp_id));
2851     }
2852   /* Refresh dynamic hostname in the cache. */
2853   isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname,
2854                      IS_LEVEL_1);
2855
2856   lsp->lsp_header->lsp_bits = lsp_bits_generate (lsp->level,
2857                                                  lsp->area->overload_bit,
2858                                                  lsp->area->attached_bit);
2859   rem_lifetime = lsp_rem_lifetime (lsp->area, IS_LEVEL_1);
2860   lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
2861
2862   /* refresh_time = lsp_refresh_time (lsp, rem_lifetime); */
2863   THREAD_TIMER_ON (master, lsp->t_lsp_top_ref, top_lsp_refresh, lsp,
2864                    lsp->area->lsp_refresh[0]);
2865
2866   return ISIS_OK;
2867 }
2868
2869 void
2870 generate_topology_lsps (struct isis_area *area)
2871 {
2872   struct listnode *node;
2873   int i, max = 0;
2874   struct arc *arc;
2875   u_char lspid[ISIS_SYS_ID_LEN + 2];
2876   struct isis_lsp *lsp;
2877   u_int16_t rem_lifetime, refresh_time;
2878
2879   /* first we find the maximal node */
2880   for (ALL_LIST_ELEMENTS_RO (area->topology, node, arc))
2881     {
2882       if (arc->from_node > max)
2883         max = arc->from_node;
2884       if (arc->to_node > max)
2885         max = arc->to_node;
2886     }
2887
2888   for (i = 1; i < (max + 1); i++)
2889     {
2890       memcpy (lspid, area->topology_baseis, ISIS_SYS_ID_LEN);
2891       LSP_PSEUDO_ID (lspid) = 0x00;
2892       LSP_FRAGMENT (lspid) = 0x00;
2893       lspid[ISIS_SYS_ID_LEN - 1] = (i & 0xFF);
2894       lspid[ISIS_SYS_ID_LEN - 2] = ((i >> 8) & 0xFF);
2895
2896       rem_lifetime = lsp_rem_lifetime (area, IS_LEVEL_1);
2897       lsp = lsp_new (area, lspid, rem_lifetime, 1,
2898                      IS_LEVEL_1 | area->overload_bit | area->attached_bit,
2899                      0, 1);
2900       if (!lsp)
2901         return;
2902       lsp->from_topology = 1;
2903
2904       /* Creating LSP data based on topology info. */
2905       build_topology_lsp_data (lsp, area, i);
2906       /* Checksum is also calculated here. */
2907       lsp_seqnum_update (lsp);
2908       /* Take care of inserting dynamic hostname into cache. */
2909       isis_dynhn_insert (lspid, lsp->tlv_data.hostname, IS_LEVEL_1);
2910
2911       refresh_time = lsp_refresh_time (lsp, rem_lifetime);
2912       THREAD_TIMER_ON (master, lsp->t_lsp_top_ref, top_lsp_refresh, lsp,
2913                        refresh_time);
2914       lsp_set_all_srmflags (lsp);
2915       lsp_insert (lsp, area->lspdb[0]);
2916     }
2917 }
2918
2919 void
2920 remove_topology_lsps (struct isis_area *area)
2921 {
2922   struct isis_lsp *lsp;
2923   dnode_t *dnode, *dnode_next;
2924
2925   dnode = dict_first (area->lspdb[0]);
2926   while (dnode != NULL)
2927     {
2928       dnode_next = dict_next (area->lspdb[0], dnode);
2929       lsp = dnode_get (dnode);
2930       if (lsp->from_topology)
2931         {
2932           THREAD_TIMER_OFF (lsp->t_lsp_top_ref);
2933           lsp_destroy (lsp);
2934           dict_delete (area->lspdb[0], dnode);
2935         }
2936       dnode = dnode_next;
2937     }
2938 }
2939
2940 void
2941 build_topology_lsp_data (struct isis_lsp *lsp, struct isis_area *area,
2942                          int lsp_top_num)
2943 {
2944   struct listnode *node;
2945   struct arc *arc;
2946   struct is_neigh *is_neigh;
2947   struct te_is_neigh *te_is_neigh;
2948   char buff[200];
2949   struct tlvs tlv_data;
2950   struct isis_lsp *lsp0 = lsp;
2951
2952   /* Add area addresses. FIXME: Is it needed at all? */
2953   if (lsp->tlv_data.area_addrs == NULL)
2954     lsp->tlv_data.area_addrs = list_new ();
2955   list_add_list (lsp->tlv_data.area_addrs, area->area_addrs);
2956
2957   if (lsp->tlv_data.nlpids == NULL)
2958     lsp->tlv_data.nlpids = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct nlpids));
2959   lsp->tlv_data.nlpids->count = 1;
2960   lsp->tlv_data.nlpids->nlpids[0] = NLPID_IP;
2961
2962   if (area->dynhostname)
2963     {
2964       lsp->tlv_data.hostname = XMALLOC (MTYPE_ISIS_TLV,
2965                                         sizeof (struct hostname));
2966       memset (buff, 0x00, 200);
2967       sprintf (buff, "%s%d", area->topology_basedynh ? area->topology_basedynh :
2968                "feedme", lsp_top_num);
2969       memcpy (lsp->tlv_data.hostname->name, buff, strlen (buff));
2970       lsp->tlv_data.hostname->namelen = strlen (buff);
2971     }
2972
2973   if (lsp->tlv_data.nlpids)
2974     tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu);
2975   if (lsp->tlv_data.hostname)
2976     tlv_add_dynamic_hostname (lsp->tlv_data.hostname, lsp->pdu);
2977   if (lsp->tlv_data.area_addrs && listcount (lsp->tlv_data.area_addrs) > 0)
2978     tlv_add_area_addrs (lsp->tlv_data.area_addrs, lsp->pdu);
2979
2980   memset (&tlv_data, 0, sizeof (struct tlvs));
2981   if (tlv_data.is_neighs == NULL)
2982     {
2983       tlv_data.is_neighs = list_new ();
2984       tlv_data.is_neighs->del = free_tlv;
2985     }
2986
2987   /* Add reachability for this IS for simulated 1. */
2988   if (lsp_top_num == 1)
2989     {
2990       is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
2991
2992       memcpy (&is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN);
2993       LSP_PSEUDO_ID (is_neigh->neigh_id) = 0x00;
2994       /* Metric MUST NOT be 0, unless it's not alias TLV. */
2995       is_neigh->metrics.metric_default = 0x01;
2996       is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED;
2997       is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED;
2998       is_neigh->metrics.metric_error = METRICS_UNSUPPORTED;
2999       listnode_add (tlv_data.is_neighs, is_neigh);
3000     }
3001
3002   /* Add IS reachabilities. */
3003   for (ALL_LIST_ELEMENTS_RO (area->topology, node, arc))
3004     {
3005       int to_lsp = 0;
3006       
3007       if ((lsp_top_num != arc->from_node) && (lsp_top_num != arc->to_node))
3008         continue;
3009
3010       if (lsp_top_num == arc->from_node)
3011         to_lsp = arc->to_node;
3012       else
3013         to_lsp = arc->from_node;
3014
3015       if (area->oldmetric)
3016         {
3017           is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
3018
3019           memcpy (&is_neigh->neigh_id, area->topology_baseis, ISIS_SYS_ID_LEN);
3020           is_neigh->neigh_id[ISIS_SYS_ID_LEN - 1] = (to_lsp & 0xFF);
3021           is_neigh->neigh_id[ISIS_SYS_ID_LEN - 2] = ((to_lsp >> 8) & 0xFF);
3022           is_neigh->metrics.metric_default = arc->distance;
3023           is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED;
3024           is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED;
3025           is_neigh->metrics.metric_error = METRICS_UNSUPPORTED;
3026           listnode_add (tlv_data.is_neighs, is_neigh);
3027         }
3028
3029       if (area->newmetric)
3030         {
3031           if (tlv_data.te_is_neighs == NULL)
3032             {
3033               tlv_data.te_is_neighs = list_new ();
3034               tlv_data.te_is_neighs->del = free_tlv;
3035             }
3036           te_is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct te_is_neigh));
3037           memcpy (&te_is_neigh->neigh_id, area->topology_baseis,
3038                   ISIS_SYS_ID_LEN);
3039           te_is_neigh->neigh_id[ISIS_SYS_ID_LEN - 1] = (to_lsp & 0xFF);
3040           te_is_neigh->neigh_id[ISIS_SYS_ID_LEN - 2] = ((to_lsp >> 8) & 0xFF);
3041           SET_TE_METRIC(te_is_neigh, arc->distance);
3042           listnode_add (tlv_data.te_is_neighs, te_is_neigh);
3043         }
3044     }
3045
3046   while (tlv_data.is_neighs && listcount (tlv_data.is_neighs))
3047     {
3048       if (lsp->tlv_data.is_neighs == NULL)
3049         lsp->tlv_data.is_neighs = list_new ();
3050       lsp_tlv_fit (lsp, &tlv_data.is_neighs, &lsp->tlv_data.is_neighs,
3051                    IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
3052                    tlv_add_is_neighs);
3053       if (tlv_data.is_neighs && listcount (tlv_data.is_neighs))
3054         lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
3055                              lsp0, area, IS_LEVEL_1);
3056     }
3057
3058   while (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs))
3059     {
3060       if (lsp->tlv_data.te_is_neighs == NULL)
3061         lsp->tlv_data.te_is_neighs = list_new ();
3062       lsp_tlv_fit (lsp, &tlv_data.te_is_neighs, &lsp->tlv_data.te_is_neighs,
3063                    IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
3064                    tlv_add_te_is_neighs);
3065       if (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs))
3066         lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
3067                              lsp0, area, IS_LEVEL_1);
3068     }
3069
3070   free_tlvs (&tlv_data);
3071   return;
3072 }
3073 #endif /* TOPOLOGY_GENERATE */