File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / isisd / isis_lsp.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jul 21 23:54:38 2013 UTC (11 years ago) by misho
Branches: quagga, MAIN
CVS tags: v0_99_22p0, v0_99_22, HEAD
0.99.22

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>