Diff for /embedaddon/quagga/isisd/isis_lsp.c between versions 1.1 and 1.1.1.4

version 1.1, 2012/02/21 17:26:11 version 1.1.1.4, 2016/11/02 10:09:10
Line 5 Line 5
  * Copyright (C) 2001,2002   Sampo Saaristo   * Copyright (C) 2001,2002   Sampo Saaristo
  *                           Tampere University of Technology         *                           Tampere University of Technology      
  *                           Institute of Communications Engineering   *                           Institute of Communications Engineering
    * Copyright (C) 2013-2015   Christian Franke <chris@opensourcerouting.org>
  *   *
  * This program is free software; you can redistribute it and/or modify it    * This program is free software; you can redistribute it and/or modify it 
 * under the terms of the GNU General Public Licenseas published by the Free  * under the terms of the GNU General Public License as published by the Free 
  * Software Foundation; either version 2 of the License, or (at your option)    * Software Foundation; either version 2 of the License, or (at your option) 
  * any later version.   * any later version.
  *   *
Line 34 Line 35
 #include "hash.h"  #include "hash.h"
 #include "if.h"  #include "if.h"
 #include "checksum.h"  #include "checksum.h"
   #include "md5.h"
   #include "table.h"
   
 #include "isisd/dict.h"  #include "isisd/dict.h"
 #include "isisd/isis_constants.h"  #include "isisd/isis_constants.h"
 #include "isisd/isis_common.h"  #include "isisd/isis_common.h"
   #include "isisd/isis_flags.h"
 #include "isisd/isis_circuit.h"  #include "isisd/isis_circuit.h"
 #include "isisd/isisd.h"  #include "isisd/isisd.h"
 #include "isisd/isis_tlv.h"  #include "isisd/isis_tlv.h"
Line 45 Line 49
 #include "isisd/isis_pdu.h"  #include "isisd/isis_pdu.h"
 #include "isisd/isis_dynhn.h"  #include "isisd/isis_dynhn.h"
 #include "isisd/isis_misc.h"  #include "isisd/isis_misc.h"
 #include "isisd/isis_flags.h"  
 #include "isisd/isis_csm.h"  #include "isisd/isis_csm.h"
 #include "isisd/isis_adjacency.h"  #include "isisd/isis_adjacency.h"
 #include "isisd/isis_spf.h"  #include "isisd/isis_spf.h"
Line 54 Line 57
 #include "spgrid.h"  #include "spgrid.h"
 #endif  #endif
   
 #define LSP_MEMORY_PREASSIGN  
   
 extern struct isis *isis;  
 extern struct thread_master *master;  
 extern struct in_addr router_id_zebra;  
   
 /* staticly assigned vars for printing purposes */  /* staticly assigned vars for printing purposes */
 char lsp_bits_string[200];     /* FIXME: enough ? */  char lsp_bits_string[200];     /* FIXME: enough ? */
   
   static int lsp_l1_refresh (struct thread *thread);
   static int lsp_l2_refresh (struct thread *thread);
   static int lsp_l1_refresh_pseudo (struct thread *thread);
   static int lsp_l2_refresh_pseudo (struct thread *thread);
   
 int  int
 lsp_id_cmp (u_char * id1, u_char * id2)  lsp_id_cmp (u_char * id1, u_char * id2)
 {  {
Line 90  lsp_search (u_char * id, dict_t * lspdb) Line 92  lsp_search (u_char * id, dict_t * lspdb)
   zlog_debug ("searching db");    zlog_debug ("searching db");
   for (dn = dict_first (lspdb); dn; dn = dict_next (lspdb, dn))    for (dn = dict_first (lspdb); dn; dn = dict_next (lspdb, dn))
     {      {
      zlog_debug ("%s\t%pX", rawlspid_print ((char *) dnode_getkey (dn)),      zlog_debug ("%s\t%pX", rawlspid_print ((u_char *) dnode_getkey (dn)),
                   dnode_get (dn));                    dnode_get (dn));
     }      }
 #endif /* EXTREME DEBUG */  #endif /* EXTREME DEBUG */
Line 109  lsp_clear_data (struct isis_lsp *lsp) Line 111  lsp_clear_data (struct isis_lsp *lsp)
   if (!lsp)    if (!lsp)
     return;      return;
   
     if (lsp->tlv_data.hostname)
       isis_dynhn_remove (lsp->lsp_header->lsp_id);
   
   if (lsp->own_lsp)    if (lsp->own_lsp)
     {      {
       if (lsp->tlv_data.nlpids)        if (lsp->tlv_data.nlpids)
        XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.nlpids);        XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.nlpids);
       if (lsp->tlv_data.hostname)        if (lsp->tlv_data.hostname)
        XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.hostname);        XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.hostname);
       if (lsp->tlv_data.router_id)
         XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.router_id);
     }      }
   if (lsp->tlv_data.is_neighs)  
     list_delete (lsp->tlv_data.is_neighs);  
   if (lsp->tlv_data.te_is_neighs)  
     list_delete (lsp->tlv_data.te_is_neighs);  
   if (lsp->tlv_data.area_addrs)  
     list_delete (lsp->tlv_data.area_addrs);  
   if (lsp->tlv_data.es_neighs)  
     list_delete (lsp->tlv_data.es_neighs);  
   if (lsp->tlv_data.ipv4_addrs)  
     list_delete (lsp->tlv_data.ipv4_addrs);  
   if (lsp->tlv_data.ipv4_int_reachs)  
     list_delete (lsp->tlv_data.ipv4_int_reachs);  
   if (lsp->tlv_data.ipv4_ext_reachs)  
     list_delete (lsp->tlv_data.ipv4_ext_reachs);  
   if (lsp->tlv_data.te_ipv4_reachs)  
     list_delete (lsp->tlv_data.te_ipv4_reachs);  
 #ifdef HAVE_IPV6  
   if (lsp->tlv_data.ipv6_addrs)  
     list_delete (lsp->tlv_data.ipv6_addrs);  
   if (lsp->tlv_data.ipv6_reachs)  
     list_delete (lsp->tlv_data.ipv6_reachs);  
 #endif /* HAVE_IPV6 */  
   
  memset (&lsp->tlv_data, 0, sizeof (struct tlvs));  free_tlvs (&lsp->tlv_data);
 
  return; 
 }  }
   
 static void  static void
 lsp_destroy (struct isis_lsp *lsp)  lsp_destroy (struct isis_lsp *lsp)
 {  {
     struct listnode *cnode, *lnode, *lnnode;
     struct isis_lsp *lsp_in_list;
     struct isis_circuit *circuit;
   
   if (!lsp)    if (!lsp)
     return;      return;
   
     for (ALL_LIST_ELEMENTS_RO (lsp->area->circuit_list, cnode, circuit))
       {
         if (circuit->lsp_queue == NULL)
           continue;
         for (ALL_LIST_ELEMENTS (circuit->lsp_queue, lnode, lnnode, lsp_in_list))
           if (lsp_in_list == lsp)
             list_delete_node(circuit->lsp_queue, lnode);
       }
     ISIS_FLAGS_CLEAR_ALL (lsp->SSNflags);
     ISIS_FLAGS_CLEAR_ALL (lsp->SRMflags);
   
   lsp_clear_data (lsp);    lsp_clear_data (lsp);
   
   if (LSP_FRAGMENT (lsp->lsp_header->lsp_id) == 0 && lsp->lspu.frags)    if (LSP_FRAGMENT (lsp->lsp_header->lsp_id) == 0 && lsp->lspu.frags)
     {      {
       list_delete (lsp->lspu.frags);        list_delete (lsp->lspu.frags);
         lsp->lspu.frags = NULL;
     }      }
   
     isis_spf_schedule (lsp->area, lsp->level);
   #ifdef HAVE_IPV6
     isis_spf_schedule6 (lsp->area, lsp->level);
   #endif
   
   if (lsp->pdu)    if (lsp->pdu)
     stream_free (lsp->pdu);      stream_free (lsp->pdu);
   XFREE (MTYPE_ISIS_LSP, lsp);    XFREE (MTYPE_ISIS_LSP, lsp);
Line 254  lsp_compare (char *areatag, struct isis_lsp *lsp, u_in Line 258  lsp_compare (char *areatag, struct isis_lsp *lsp, u_in
     {      {
       if (isis->debugs & DEBUG_SNP_PACKETS)        if (isis->debugs & DEBUG_SNP_PACKETS)
         {          {
          zlog_debug ("ISIS-Snp (%s): LSP %s seq 0x%08x, cksum 0x%04x,"          zlog_debug ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x,"
                       " lifetime %us",                        " lifetime %us",
                       areatag,                        areatag,
                       rawlspid_print (lsp->lsp_header->lsp_id),                        rawlspid_print (lsp->lsp_header->lsp_id),
Line 269  lsp_compare (char *areatag, struct isis_lsp *lsp, u_in Line 273  lsp_compare (char *areatag, struct isis_lsp *lsp, u_in
       return LSP_EQUAL;        return LSP_EQUAL;
     }      }
   
  if (ntohl (seq_num) >= ntohl (lsp->lsp_header->seq_num))  /*
    * LSPs with identical checksums should only be treated as newer if:
    * a) The current LSP has a remaining lifetime != 0 and the other LSP has a
    *    remaining lifetime == 0. In this case, we should participate in the purge
    *    and should not treat the current LSP with remaining lifetime == 0 as older.
    * b) The LSP has an incorrect checksum. In this case, we need to react as given
    *    in 7.3.16.2.
    */
    if (ntohl (seq_num) > ntohl (lsp->lsp_header->seq_num)
       || (ntohl(seq_num) == ntohl(lsp->lsp_header->seq_num)
           && (  (lsp->lsp_header->rem_lifetime != 0
                  && rem_lifetime == 0)
               || lsp->lsp_header->checksum != checksum)))
     {      {
       if (isis->debugs & DEBUG_SNP_PACKETS)        if (isis->debugs & DEBUG_SNP_PACKETS)
         {          {
          zlog_debug ("ISIS-Snp (%s): LSP %s seq 0x%08x, cksum 0x%04x,"          zlog_debug ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x,"
                       " lifetime %us",                        " lifetime %us",
                       areatag,                        areatag,
                       rawlspid_print (lsp->lsp_header->lsp_id),                        rawlspid_print (lsp->lsp_header->lsp_id),
Line 290  lsp_compare (char *areatag, struct isis_lsp *lsp, u_in Line 306  lsp_compare (char *areatag, struct isis_lsp *lsp, u_in
   if (isis->debugs & DEBUG_SNP_PACKETS)    if (isis->debugs & DEBUG_SNP_PACKETS)
     {      {
       zlog_debug        zlog_debug
        ("ISIS-Snp (%s): LSP %s seq 0x%08x, cksum 0x%04x, lifetime %us",        ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x, lifetime %us",
          areatag, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (seq_num),           areatag, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (seq_num),
          ntohs (checksum), ntohs (rem_lifetime));           ntohs (checksum), ntohs (rem_lifetime));
       zlog_debug ("ISIS-Snp (%s):       is older than ours seq 0x%08x,"        zlog_debug ("ISIS-Snp (%s):       is older than ours seq 0x%08x,"
Line 303  lsp_compare (char *areatag, struct isis_lsp *lsp, u_in Line 319  lsp_compare (char *areatag, struct isis_lsp *lsp, u_in
   return LSP_OLDER;    return LSP_OLDER;
 }  }
   
   static void
   lsp_auth_add (struct isis_lsp *lsp)
   {
     struct isis_passwd *passwd;
     unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
   
     /*
      * Add the authentication info if its present
      */
     (lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd) :
                                  (passwd = &lsp->area->domain_passwd);
     switch (passwd->type)
       {
         /* Cleartext */
         case ISIS_PASSWD_TYPE_CLEARTXT:
           memcpy (&lsp->tlv_data.auth_info, passwd, sizeof (struct isis_passwd));
           tlv_add_authinfo (passwd->type, passwd->len, passwd->passwd, lsp->pdu);
           break;
   
         /* HMAC MD5 */
         case ISIS_PASSWD_TYPE_HMAC_MD5:
           /* Remember where TLV is written so we can later
            * overwrite the MD5 hash */
           lsp->auth_tlv_offset = stream_get_endp (lsp->pdu);
           memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
           lsp->tlv_data.auth_info.type = ISIS_PASSWD_TYPE_HMAC_MD5;
           lsp->tlv_data.auth_info.len = ISIS_AUTH_MD5_SIZE;
           memcpy (&lsp->tlv_data.auth_info.passwd, hmac_md5_hash,
                   ISIS_AUTH_MD5_SIZE);
           tlv_add_authinfo (passwd->type, ISIS_AUTH_MD5_SIZE, hmac_md5_hash,
                             lsp->pdu);
           break;
   
         default:
           break;
       }
   }
   
   static void
   lsp_auth_update (struct isis_lsp *lsp)
   {
     struct isis_passwd *passwd;
     unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
     uint16_t checksum, rem_lifetime;
   
     /* For HMAC MD5 we need to recompute the md5 hash and store it */
     (lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd) :
                                  (passwd = &lsp->area->domain_passwd);
     if (passwd->type != ISIS_PASSWD_TYPE_HMAC_MD5)
       return;
   
     /*
      * In transient conditions (when net is configured where authentication
      * config and lsp regenerate schedule is not yet run), there could be
      * an own_lsp with auth_tlv_offset set to 0. In such a case, simply
      * return, when lsp_regenerate is run, lsp will have auth tlv.
      */
     if (lsp->auth_tlv_offset == 0)
       return;
   
     /*
      * RFC 5304 set auth value, checksum and remaining lifetime to zero
      * before computation and reset to old values after computation.
      */
     checksum = lsp->lsp_header->checksum;
     rem_lifetime = lsp->lsp_header->rem_lifetime;
     lsp->lsp_header->checksum = 0;
     lsp->lsp_header->rem_lifetime = 0;
     /* Set the authentication value as well to zero */
     memset (STREAM_DATA (lsp->pdu) + lsp->auth_tlv_offset + 3,
             0, ISIS_AUTH_MD5_SIZE);
     /* Compute autentication value */
     hmac_md5 (STREAM_DATA (lsp->pdu), stream_get_endp(lsp->pdu),
               (unsigned char *) &passwd->passwd, passwd->len,
               (unsigned char *) &hmac_md5_hash);
     /* Copy the hash into the stream */
     memcpy (STREAM_DATA (lsp->pdu) + lsp->auth_tlv_offset + 3,
             hmac_md5_hash, ISIS_AUTH_MD5_SIZE);
     memcpy (&lsp->tlv_data.auth_info.passwd, hmac_md5_hash,
             ISIS_AUTH_MD5_SIZE);
     /* Copy back the checksum and remaining lifetime */
     lsp->lsp_header->checksum = checksum;
     lsp->lsp_header->rem_lifetime = rem_lifetime;
   }
   
 void  void
 lsp_inc_seqnum (struct isis_lsp *lsp, u_int32_t seq_num)  lsp_inc_seqnum (struct isis_lsp *lsp, u_int32_t seq_num)
 {  {
Line 311  lsp_inc_seqnum (struct isis_lsp *lsp, u_int32_t seq_nu Line 412  lsp_inc_seqnum (struct isis_lsp *lsp, u_int32_t seq_nu
   if (seq_num == 0 || ntohl (lsp->lsp_header->seq_num) > seq_num)    if (seq_num == 0 || ntohl (lsp->lsp_header->seq_num) > seq_num)
     newseq = ntohl (lsp->lsp_header->seq_num) + 1;      newseq = ntohl (lsp->lsp_header->seq_num) + 1;
   else    else
    newseq = seq_num++;    newseq = seq_num + 1;
   
   lsp->lsp_header->seq_num = htonl (newseq);    lsp->lsp_header->seq_num = htonl (newseq);
   fletcher_checksum (STREAM_DATA (lsp->pdu) + 12,  
                    ntohs (lsp->lsp_header->pdu_len) - 12, 12);  
   
     /* Recompute authentication and checksum information */
     lsp_auth_update (lsp);
     /* ISO 10589 - 7.3.11 Generation of the checksum
      * The checksum shall be computed over all fields in the LSP which appear
      * after the Remaining Lifetime field. This field (and those appearing
      * before it) are excluded so that the LSP may be aged by systems without
      * requiring recomputation.
      */
     fletcher_checksum(STREAM_DATA (lsp->pdu) + 12,
                       ntohs (lsp->lsp_header->pdu_len) - 12, 12);
   
     isis_spf_schedule (lsp->area, lsp->level);
   #ifdef HAVE_IPV6
     isis_spf_schedule6 (lsp->area, lsp->level);
   #endif
   
   return;    return;
 }  }
   
Line 340  lsp_seqnum_update (struct isis_lsp *lsp0) Line 455  lsp_seqnum_update (struct isis_lsp *lsp0)
   return;    return;
 }  }
   
intstatic u_int8_t
isis_lsp_authinfo_check (struct stream *stream, struct isis_area *area,lsp_bits_generate (int level, int overload_bit, int attached_bit)
                         int pdulen, struct isis_passwd *passwd) 
 {  {
  uint32_t expected = 0, found;  u_int8_t lsp_bits = 0;
  struct tlvs tlvs;  if (level == IS_LEVEL_1)
  int retval = 0;    lsp_bits = IS_LEVEL_1;
  else
  expected |= TLVFLAG_AUTH_INFO;    lsp_bits = IS_LEVEL_1_AND_2;
  retval = parse_tlvs (area->area_tag, stream->data +  if (overload_bit)
                       ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN,    lsp_bits |= overload_bit;
                       pdulen - ISIS_FIXED_HDR_LEN  if (attached_bit)
                       - ISIS_LSP_HDR_LEN, &expected, &found, &tlvs);    lsp_bits |= attached_bit;
  if (retval || !(found & TLVFLAG_AUTH_INFO))  return lsp_bits;
    return 1;                      /* Auth fail (parsing failed or no auth-tlv) */ 
 
  return authentication_check (passwd, &tlvs.auth_info); 
 }  }
   
 static void  static void
 lsp_update_data (struct isis_lsp *lsp, struct stream *stream,  lsp_update_data (struct isis_lsp *lsp, struct stream *stream,
                 struct isis_area *area)                 struct isis_area *area, int level)
 {  {
   uint32_t expected = 0, found;    uint32_t expected = 0, found;
   int retval;    int retval;
   
     /* free the old lsp data */
     lsp_clear_data (lsp);
   
   /* copying only the relevant part of our stream */    /* copying only the relevant part of our stream */
     if (lsp->pdu != NULL)
       stream_free (lsp->pdu);
   lsp->pdu = stream_dup (stream);    lsp->pdu = stream_dup (stream);
  
   /* setting pointers to the correct place */    /* setting pointers to the correct place */
   lsp->isis_header = (struct isis_fixed_hdr *) (STREAM_DATA (lsp->pdu));    lsp->isis_header = (struct isis_fixed_hdr *) (STREAM_DATA (lsp->pdu));
   lsp->lsp_header = (struct isis_link_state_hdr *) (STREAM_DATA (lsp->pdu) +    lsp->lsp_header = (struct isis_link_state_hdr *) (STREAM_DATA (lsp->pdu) +
                                                     ISIS_FIXED_HDR_LEN);                                                      ISIS_FIXED_HDR_LEN);
     lsp->area = area;
     lsp->level = level;
   lsp->age_out = ZERO_AGE_LIFETIME;    lsp->age_out = ZERO_AGE_LIFETIME;
   lsp->installed = time (NULL);    lsp->installed = time (NULL);
   /*    /*
Line 381  lsp_update_data (struct isis_lsp *lsp, struct stream * Line 499  lsp_update_data (struct isis_lsp *lsp, struct stream *
   expected |= TLVFLAG_AUTH_INFO;    expected |= TLVFLAG_AUTH_INFO;
   expected |= TLVFLAG_AREA_ADDRS;    expected |= TLVFLAG_AREA_ADDRS;
   expected |= TLVFLAG_IS_NEIGHS;    expected |= TLVFLAG_IS_NEIGHS;
   if ((lsp->lsp_header->lsp_bits & 3) == 3)     /* a level 2 LSP */  
     expected |= TLVFLAG_PARTITION_DESIG_LEVEL2_IS;  
   expected |= TLVFLAG_NLPID;    expected |= TLVFLAG_NLPID;
   if (area->dynhostname)    if (area->dynhostname)
     expected |= TLVFLAG_DYN_HOSTNAME;      expected |= TLVFLAG_DYN_HOSTNAME;
Line 400  lsp_update_data (struct isis_lsp *lsp, struct stream * Line 516  lsp_update_data (struct isis_lsp *lsp, struct stream *
   expected |= TLVFLAG_IPV6_REACHABILITY;    expected |= TLVFLAG_IPV6_REACHABILITY;
 #endif /* HAVE_IPV6 */  #endif /* HAVE_IPV6 */
   
  retval = parse_tlvs (area->area_tag, lsp->pdu->data +  retval = parse_tlvs (area->area_tag, STREAM_DATA (lsp->pdu) +
                       ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN,                       ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN,
                       ntohs (lsp->lsp_header->pdu_len) - ISIS_FIXED_HDR_LEN                       ntohs (lsp->lsp_header->pdu_len) -
                       - ISIS_LSP_HDR_LEN, &expected, &found, &lsp->tlv_data);                       ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN,
                        &expected, &found, &lsp->tlv_data,
                        NULL);
   if (retval != ISIS_OK)
     {
       zlog_warn ("Could not parse LSP");
       return;
     }
   
  if (found & TLVFLAG_DYN_HOSTNAME)  if ((found & TLVFLAG_DYN_HOSTNAME) && (area->dynhostname))
     {      {
      if (area->dynhostname)      isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname,
        isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname,                         (lsp->lsp_header->lsp_bits & LSPBIT_IST) ==
                           (lsp->lsp_header->lsp_bits & LSPBIT_IST) ==                          IS_LEVEL_1_AND_2 ? IS_LEVEL_2 : IS_LEVEL_1);
                           IS_LEVEL_1_AND_2 ? IS_LEVEL_2 : 
                           (lsp->lsp_header->lsp_bits & LSPBIT_IST)); 
     }      }
   
     return;
 }  }
   
 void  void
lsp_update (struct isis_lsp *lsp, struct isis_link_state_hdr *lsp_hdr,lsp_update (struct isis_lsp *lsp, struct stream *stream,
            struct stream *stream, struct isis_area *area, int level)            struct isis_area *area, int level)
 {  {
   dnode_t *dnode = NULL;    dnode_t *dnode = NULL;
   
  /* Remove old LSP from LSP database. */  /* Remove old LSP from database. This is required since the
    * lsp_update_data will free the lsp->pdu (which has the key, lsp_id)
    * and will update it with the new data in the stream. */
   dnode = dict_lookup (area->lspdb[level - 1], lsp->lsp_header->lsp_id);    dnode = dict_lookup (area->lspdb[level - 1], lsp->lsp_header->lsp_id);
   if (dnode)    if (dnode)
     dnode_destroy (dict_delete (area->lspdb[level - 1], dnode));      dnode_destroy (dict_delete (area->lspdb[level - 1], dnode));
   
   /* free the old lsp data */  
   XFREE (MTYPE_STREAM_DATA, lsp->pdu);  
   lsp_clear_data (lsp);  
   
   /* rebuild the lsp data */    /* rebuild the lsp data */
  lsp_update_data (lsp, stream, area);  lsp_update_data (lsp, stream, area, level);
   
  /* set the new values for lsp header */  /* insert the lsp back into the database */
  memcpy (lsp->lsp_header, lsp_hdr, ISIS_LSP_HDR_LEN);  lsp_insert (lsp, area->lspdb[level - 1]);
 
  if (dnode) 
    lsp_insert (lsp, area->lspdb[level - 1]); 
 }  }
   
 /* creation of LSP directly from what we received */  /* creation of LSP directly from what we received */
 struct isis_lsp *  struct isis_lsp *
 lsp_new_from_stream_ptr (struct stream *stream,  lsp_new_from_stream_ptr (struct stream *stream,
                          u_int16_t pdu_len, struct isis_lsp *lsp0,                           u_int16_t pdu_len, struct isis_lsp *lsp0,
                         struct isis_area *area)                         struct isis_area *area, int level)
 {  {
   struct isis_lsp *lsp;    struct isis_lsp *lsp;
   
   lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp));    lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp));
  lsp_update_data (lsp, stream, area);  lsp_update_data (lsp, stream, area, level);
   
   if (lsp0 == NULL)    if (lsp0 == NULL)
     {      {
Line 472  lsp_new_from_stream_ptr (struct stream *stream, Line 589  lsp_new_from_stream_ptr (struct stream *stream,
 }  }
   
 struct isis_lsp *  struct isis_lsp *
lsp_new (u_char * lsp_id, u_int16_t rem_lifetime, u_int32_t seq_num,lsp_new(struct isis_area *area, u_char * lsp_id,
         u_int8_t lsp_bits, u_int16_t checksum, int level)        u_int16_t rem_lifetime, u_int32_t seq_num,
         u_int8_t lsp_bits, u_int16_t checksum, int level)
 {  {
   struct isis_lsp *lsp;    struct isis_lsp *lsp;
   
   lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp));    lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp));
  if (!lsp)  lsp->area = area;
    {
      /* FIXME: set lspdbol bit */  lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu);
      zlog_warn ("lsp_new(): out of memory"); 
      return NULL; 
    } 
#ifdef LSP_MEMORY_PREASSIGN 
  lsp->pdu = stream_new (1514); /*Should be minimal mtu? yup... */ 
#else 
  /* We need to do realloc on TLVs additions */ 
  lsp->pdu = malloc (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); 
#endif /* LSP_MEMORY_PREASSIGN */ 
   if (LSP_FRAGMENT (lsp_id) == 0)    if (LSP_FRAGMENT (lsp_id) == 0)
     lsp->lspu.frags = list_new ();      lsp->lspu.frags = list_new ();
   lsp->isis_header = (struct isis_fixed_hdr *) (STREAM_DATA (lsp->pdu));    lsp->isis_header = (struct isis_fixed_hdr *) (STREAM_DATA (lsp->pdu));
Line 497  lsp_new (u_char * lsp_id, u_int16_t rem_lifetime, u_in Line 606  lsp_new (u_char * lsp_id, u_int16_t rem_lifetime, u_in
     (STREAM_DATA (lsp->pdu) + ISIS_FIXED_HDR_LEN);      (STREAM_DATA (lsp->pdu) + ISIS_FIXED_HDR_LEN);
   
   /* at first we fill the FIXED HEADER */    /* at first we fill the FIXED HEADER */
  (level == 1) ? fill_fixed_hdr (lsp->isis_header, L1_LINK_STATE) :  (level == IS_LEVEL_1) ? fill_fixed_hdr (lsp->isis_header, L1_LINK_STATE) :
     fill_fixed_hdr (lsp->isis_header, L2_LINK_STATE);      fill_fixed_hdr (lsp->isis_header, L2_LINK_STATE);
   
   /* now for the LSP HEADER */    /* now for the LSP HEADER */
Line 514  lsp_new (u_char * lsp_id, u_int16_t rem_lifetime, u_in Line 623  lsp_new (u_char * lsp_id, u_int16_t rem_lifetime, u_in
   stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);    stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
   
   if (isis->debugs & DEBUG_EVENTS)    if (isis->debugs & DEBUG_EVENTS)
    zlog_debug ("New LSP with ID %s-%02x-%02x seqnum %08x",    zlog_debug ("New LSP with ID %s-%02x-%02x len %d seqnum %08x",
                 sysid_print (lsp_id), LSP_PSEUDO_ID (lsp->lsp_header->lsp_id),                  sysid_print (lsp_id), LSP_PSEUDO_ID (lsp->lsp_header->lsp_id),
                 LSP_FRAGMENT (lsp->lsp_header->lsp_id),                  LSP_FRAGMENT (lsp->lsp_header->lsp_id),
                   ntohl (lsp->lsp_header->pdu_len),
                 ntohl (lsp->lsp_header->seq_num));                  ntohl (lsp->lsp_header->seq_num));
   
   return lsp;    return lsp;
Line 526  void Line 636  void
 lsp_insert (struct isis_lsp *lsp, dict_t * lspdb)  lsp_insert (struct isis_lsp *lsp, dict_t * lspdb)
 {  {
   dict_alloc_insert (lspdb, lsp->lsp_header->lsp_id, lsp);    dict_alloc_insert (lspdb, lsp->lsp_header->lsp_id, lsp);
     if (lsp->lsp_header->seq_num != 0)
       {
         isis_spf_schedule (lsp->area, lsp->level);
   #ifdef HAVE_IPV6
         isis_spf_schedule6 (lsp->area, lsp->level);
   #endif
       }
 }  }
   
 /*  /*
Line 562  lsp_build_list_nonzero_ht (u_char * start_id, u_char * Line 679  lsp_build_list_nonzero_ht (u_char * start_id, u_char *
 }  }
   
 /*  /*
 * Build a list of all LSPs bounded by start and stop ids * Build a list of num_lsps LSPs bounded by start_id and stop_id.
  */   */
 void  void
lsp_build_list (u_char * start_id, u_char * stop_id,lsp_build_list (u_char * start_id, u_char * stop_id, u_char num_lsps,
                 struct list *list, dict_t * lspdb)                  struct list *list, dict_t * lspdb)
 {  {
     u_char count;
   dnode_t *first, *last, *curr;    dnode_t *first, *last, *curr;
   
   first = dict_lower_bound (lspdb, start_id);    first = dict_lower_bound (lspdb, start_id);
Line 579  lsp_build_list (u_char * start_id, u_char * stop_id, Line 697  lsp_build_list (u_char * start_id, u_char * stop_id,
   curr = first;    curr = first;
   
   listnode_add (list, first->dict_data);    listnode_add (list, first->dict_data);
     count = 1;
   
   while (curr)    while (curr)
     {      {
       curr = dict_next (lspdb, curr);        curr = dict_next (lspdb, curr);
       if (curr)        if (curr)
        listnode_add (list, curr->dict_data);        {
      if (curr == last)          listnode_add (list, curr->dict_data);
        break;          count++;
         }
       if (count == num_lsps || curr == last)
         break;
     }      }
   
   return;    return;
Line 596  lsp_build_list (u_char * start_id, u_char * stop_id, Line 718  lsp_build_list (u_char * start_id, u_char * stop_id,
  * Build a list of LSPs with SSN flag set for the given circuit   * Build a list of LSPs with SSN flag set for the given circuit
  */   */
 void  void
lsp_build_list_ssn (struct isis_circuit *circuit, struct list *list,lsp_build_list_ssn (struct isis_circuit *circuit, u_char num_lsps,
                    dict_t * lspdb)                    struct list *list, dict_t * lspdb)
 {  {
   dnode_t *dnode, *next;    dnode_t *dnode, *next;
   struct isis_lsp *lsp;    struct isis_lsp *lsp;
     u_char count = 0;
   
   dnode = dict_first (lspdb);    dnode = dict_first (lspdb);
   while (dnode != NULL)    while (dnode != NULL)
Line 608  lsp_build_list_ssn (struct isis_circuit *circuit, stru Line 731  lsp_build_list_ssn (struct isis_circuit *circuit, stru
       next = dict_next (lspdb, dnode);        next = dict_next (lspdb, dnode);
       lsp = dnode_get (dnode);        lsp = dnode_get (dnode);
       if (ISIS_CHECK_FLAG (lsp->SSNflags, circuit))        if (ISIS_CHECK_FLAG (lsp->SSNflags, circuit))
        listnode_add (list, lsp);        {
           listnode_add (list, lsp);
           ++count;
         }
       if (count == num_lsps)
         break;
       dnode = next;        dnode = next;
     }      }
   
Line 622  lsp_set_time (struct isis_lsp *lsp) Line 750  lsp_set_time (struct isis_lsp *lsp)
   
   if (lsp->lsp_header->rem_lifetime == 0)    if (lsp->lsp_header->rem_lifetime == 0)
     {      {
      if (lsp->age_out != 0)      if (lsp->age_out > 0)
        lsp->age_out--;        lsp->age_out--;
       return;        return;
     }      }
   
   /* If we are turning 0 */  
   /* ISO 10589 - 7.3.16.4 first paragraph */  
   
   if (ntohs (lsp->lsp_header->rem_lifetime) == 1)  
     {  
       /* 7.3.16.4 a) set SRM flags on all */  
       ISIS_FLAGS_SET_ALL (lsp->SRMflags);  
       /* 7.3.16.4 b) retain only the header FIXME  */  
       /* 7.3.16.4 c) record the time to purge FIXME (other way to do it) */  
     }  
   
   lsp->lsp_header->rem_lifetime =    lsp->lsp_header->rem_lifetime =
     htons (ntohs (lsp->lsp_header->rem_lifetime) - 1);      htons (ntohs (lsp->lsp_header->rem_lifetime) - 1);
 }  }
Line 654  lspid_print (u_char * lsp_id, u_char * trg, char dynho Line 771  lspid_print (u_char * lsp_id, u_char * trg, char dynho
     dyn = NULL;      dyn = NULL;
   
   if (dyn)    if (dyn)
    sprintf ((char *)id, "%.14s", dyn->name.name);      sprintf ((char *)id, "%.14s", dyn->name.name);
  else if (!memcmp (isis->sysid, lsp_id, ISIS_SYS_ID_LEN) & dynhost)  else if (!memcmp (isis->sysid, lsp_id, ISIS_SYS_ID_LEN) && dynhost)
    sprintf ((char *)id, "%.14s", unix_hostname ());      sprintf ((char *)id, "%.14s", unix_hostname ());
   else    else
     {  
       memcpy (id, sysid_print (lsp_id), 15);        memcpy (id, sysid_print (lsp_id), 15);
     }  
   if (frag)    if (frag)
     sprintf ((char *)trg, "%s.%02x-%02x", id, LSP_PSEUDO_ID (lsp_id),      sprintf ((char *)trg, "%s.%02x-%02x", id, LSP_PSEUDO_ID (lsp_id),
              LSP_FRAGMENT (lsp_id));               LSP_FRAGMENT (lsp_id));
Line 692  lsp_bits2string (u_char * lsp_bits) Line 807  lsp_bits2string (u_char * lsp_bits)
 }  }
   
 /* this function prints the lsp on show isis database */  /* this function prints the lsp on show isis database */
static voidvoid
lsp_print (dnode_t * node, struct vty *vty, char dynhost)lsp_print (struct isis_lsp *lsp, struct vty *vty, char dynhost)
 {  {
   struct isis_lsp *lsp = dnode_get (node);  
   u_char LSPid[255];    u_char LSPid[255];
     char age_out[8];
   
   lspid_print (lsp->lsp_header->lsp_id, LSPid, dynhost, 1);    lspid_print (lsp->lsp_header->lsp_id, LSPid, dynhost, 1);
  vty_out (vty, "%-21s%c   ", LSPid, lsp->own_lsp ? '*' : ' ');  vty_out (vty, "%-21s%c  ", LSPid, lsp->own_lsp ? '*' : ' ');
  vty_out (vty, "0x%08x   ", ntohl (lsp->lsp_header->seq_num));  vty_out (vty, "%5u   ", ntohs (lsp->lsp_header->pdu_len));
  vty_out (vty, "0x%04x      ", ntohs (lsp->lsp_header->checksum));  vty_out (vty, "0x%08x  ", ntohl (lsp->lsp_header->seq_num));
  vty_out (vty, "0x%04x  ", ntohs (lsp->lsp_header->checksum));
   if (ntohs (lsp->lsp_header->rem_lifetime) == 0)    if (ntohs (lsp->lsp_header->rem_lifetime) == 0)
    vty_out (vty, " (%2u)", lsp->age_out);    {
       snprintf (age_out, 8, "(%u)", lsp->age_out);
       age_out[7] = '\0';
       vty_out (vty, "%7s   ", age_out);
     }
   else    else
    vty_out (vty, "%5u", ntohs (lsp->lsp_header->rem_lifetime));    vty_out (vty, " %5u    ", ntohs (lsp->lsp_header->rem_lifetime));
  vty_out (vty, "%s%s",
  vty_out (vty, "         %s%s",           lsp_bits2string (&lsp->lsp_header->lsp_bits), VTY_NEWLINE);
           lsp_bits2string (&lsp->lsp_header->lsp_bits), VTY_NEWLINE); 
 }  }
   
static voidvoid
lsp_print_detail (dnode_t * node, struct vty *vty, char dynhost)lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
 {  {
   struct isis_lsp *lsp = dnode_get (node);  
   struct area_addr *area_addr;    struct area_addr *area_addr;
   int i;    int i;
   struct listnode *lnode;    struct listnode *lnode;
Line 736  lsp_print_detail (dnode_t * node, struct vty *vty, cha Line 853  lsp_print_detail (dnode_t * node, struct vty *vty, cha
   u_char ipv4_address[20];    u_char ipv4_address[20];
   
   lspid_print (lsp->lsp_header->lsp_id, LSPid, dynhost, 1);    lspid_print (lsp->lsp_header->lsp_id, LSPid, dynhost, 1);
  lsp_print (node, vty, dynhost);  lsp_print (lsp, vty, dynhost);
   
   /* for all area address */    /* for all area address */
   if (lsp->tlv_data.area_addrs)    if (lsp->tlv_data.area_addrs)
Line 756  lsp_print_detail (dnode_t * node, struct vty *vty, cha Line 873  lsp_print_detail (dnode_t * node, struct vty *vty, cha
             {              {
             case NLPID_IP:              case NLPID_IP:
             case NLPID_IPV6:              case NLPID_IPV6:
              vty_out (vty, "  NLPID:        0x%X%s",              vty_out (vty, "  NLPID       : 0x%X%s",
                        lsp->tlv_data.nlpids->nlpids[i], VTY_NEWLINE);                         lsp->tlv_data.nlpids->nlpids[i], VTY_NEWLINE);
               break;                break;
             default:              default:
              vty_out (vty, "  NLPID:        %s%s", "unknown", VTY_NEWLINE);              vty_out (vty, "  NLPID       : %s%s", "unknown", VTY_NEWLINE);
               break;                break;
             }              }
         }          }
Line 769  lsp_print_detail (dnode_t * node, struct vty *vty, cha Line 886  lsp_print_detail (dnode_t * node, struct vty *vty, cha
   /* for the hostname tlv */    /* for the hostname tlv */
   if (lsp->tlv_data.hostname)    if (lsp->tlv_data.hostname)
     {      {
      memset (hostname, 0, sizeof (hostname));      bzero (hostname, sizeof (hostname));
       memcpy (hostname, lsp->tlv_data.hostname->name,        memcpy (hostname, lsp->tlv_data.hostname->name,
               lsp->tlv_data.hostname->namelen);                lsp->tlv_data.hostname->namelen);
      vty_out (vty, "  Hostname: %s%s", hostname, VTY_NEWLINE);      vty_out (vty, "  Hostname    : %s%s", hostname, VTY_NEWLINE);
     }      }
   
  if (lsp->tlv_data.ipv4_addrs)  /* authentication tlv */
    for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_addrs, lnode, ipv4_addr))  if (lsp->tlv_data.auth_info.type != ISIS_PASSWD_TYPE_UNUSED)
      {    {
        memcpy (ipv4_address, inet_ntoa (*ipv4_addr), sizeof (ipv4_address));      if (lsp->tlv_data.auth_info.type == ISIS_PASSWD_TYPE_HMAC_MD5)
        vty_out (vty, "  IP:        %s%s", ipv4_address, VTY_NEWLINE);        vty_out (vty, "  Auth type   : md5%s", VTY_NEWLINE);
      }      else if (lsp->tlv_data.auth_info.type == ISIS_PASSWD_TYPE_CLEARTXT)
         vty_out (vty, "  Auth type   : clear text%s", VTY_NEWLINE);
     }
   
   /* TE router id */    /* TE router id */
   if (lsp->tlv_data.router_id)    if (lsp->tlv_data.router_id)
     {      {
       memcpy (ipv4_address, inet_ntoa (lsp->tlv_data.router_id->id),        memcpy (ipv4_address, inet_ntoa (lsp->tlv_data.router_id->id),
               sizeof (ipv4_address));                sizeof (ipv4_address));
      vty_out (vty, "  Router ID: %s%s", ipv4_address, VTY_NEWLINE);      vty_out (vty, "  Router ID   : %s%s", ipv4_address, VTY_NEWLINE);
     }      }
   
     if (lsp->tlv_data.ipv4_addrs)
       for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_addrs, lnode, ipv4_addr))
         {
           memcpy (ipv4_address, inet_ntoa (*ipv4_addr), sizeof (ipv4_address));
           vty_out (vty, "  IPv4 Address: %s%s", ipv4_address, VTY_NEWLINE);
         }
   
   /* for the IS neighbor tlv */    /* for the IS neighbor tlv */
   if (lsp->tlv_data.is_neighs)    if (lsp->tlv_data.is_neighs)
     for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, lnode, is_neigh))      for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, lnode, is_neigh))
       {        {
         lspid_print (is_neigh->neigh_id, LSPid, dynhost, 0);          lspid_print (is_neigh->neigh_id, LSPid, dynhost, 0);
        vty_out (vty, "  Metric: %-10d IS %s%s",        vty_out (vty, "  Metric      : %-8d IS            : %s%s",
                  is_neigh->metrics.metric_default, LSPid, VTY_NEWLINE);                   is_neigh->metrics.metric_default, LSPid, VTY_NEWLINE);
       }        }
       
Line 808  lsp_print_detail (dnode_t * node, struct vty *vty, cha Line 934  lsp_print_detail (dnode_t * node, struct vty *vty, cha
               sizeof (ipv4_reach_prefix));                sizeof (ipv4_reach_prefix));
       memcpy (ipv4_reach_mask, inet_ntoa (ipv4_reach->mask),        memcpy (ipv4_reach_mask, inet_ntoa (ipv4_reach->mask),
               sizeof (ipv4_reach_mask));                sizeof (ipv4_reach_mask));
      vty_out (vty, "  Metric: %-10d IP-Internal %s %s%s",      vty_out (vty, "  Metric      : %-8d IPv4-Internal : %s %s%s",
                ipv4_reach->metrics.metric_default, ipv4_reach_prefix,                 ipv4_reach->metrics.metric_default, ipv4_reach_prefix,
                ipv4_reach_mask, VTY_NEWLINE);                 ipv4_reach_mask, VTY_NEWLINE);
     }      }
Line 822  lsp_print_detail (dnode_t * node, struct vty *vty, cha Line 948  lsp_print_detail (dnode_t * node, struct vty *vty, cha
               sizeof (ipv4_reach_prefix));                sizeof (ipv4_reach_prefix));
       memcpy (ipv4_reach_mask, inet_ntoa (ipv4_reach->mask),        memcpy (ipv4_reach_mask, inet_ntoa (ipv4_reach->mask),
               sizeof (ipv4_reach_mask));                sizeof (ipv4_reach_mask));
      vty_out (vty, "  Metric: %-10d IP-External %s %s%s",      vty_out (vty, "  Metric      : %-8d IPv4-External : %s %s%s",
                ipv4_reach->metrics.metric_default, ipv4_reach_prefix,                 ipv4_reach->metrics.metric_default, ipv4_reach_prefix,
                ipv4_reach_mask, VTY_NEWLINE);                 ipv4_reach_mask, VTY_NEWLINE);
     }      }
Line 836  lsp_print_detail (dnode_t * node, struct vty *vty, cha Line 962  lsp_print_detail (dnode_t * node, struct vty *vty, cha
       memcpy (in6.s6_addr, ipv6_reach->prefix,        memcpy (in6.s6_addr, ipv6_reach->prefix,
               PSIZE (ipv6_reach->prefix_len));                PSIZE (ipv6_reach->prefix_len));
       inet_ntop (AF_INET6, &in6, (char *)buff, BUFSIZ);        inet_ntop (AF_INET6, &in6, (char *)buff, BUFSIZ);
      if ((ipv6_reach->control_info &&      if ((ipv6_reach->control_info &
            CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL)             CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL)
        vty_out (vty, "  Metric: %-10d IPv6-Internal %s/%d%s",        vty_out (vty, "  Metric      : %-8d IPv6-Internal : %s/%d%s",
                  ntohl (ipv6_reach->metric),                   ntohl (ipv6_reach->metric),
                  buff, ipv6_reach->prefix_len, VTY_NEWLINE);                   buff, ipv6_reach->prefix_len, VTY_NEWLINE);
       else        else
        vty_out (vty, "  Metric: %-10d IPv6-External %s/%d%s",        vty_out (vty, "  Metric      : %-8d IPv6-External : %s/%d%s",
                  ntohl (ipv6_reach->metric),                   ntohl (ipv6_reach->metric),
                  buff, ipv6_reach->prefix_len, VTY_NEWLINE);                   buff, ipv6_reach->prefix_len, VTY_NEWLINE);
     }      }
Line 852  lsp_print_detail (dnode_t * node, struct vty *vty, cha Line 978  lsp_print_detail (dnode_t * node, struct vty *vty, cha
   if (lsp->tlv_data.te_is_neighs)    if (lsp->tlv_data.te_is_neighs)
     for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, lnode, te_is_neigh))      for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, lnode, te_is_neigh))
     {      {
       uint32_t metric;  
       memcpy (&metric, te_is_neigh->te_metric, 3);  
       lspid_print (te_is_neigh->neigh_id, LSPid, dynhost, 0);        lspid_print (te_is_neigh->neigh_id, LSPid, dynhost, 0);
      vty_out (vty, "  Metric: %-10d IS-Extended %s%s",      vty_out (vty, "  Metric      : %-8d IS-Extended   : %s%s",
               ntohl (metric << 8), LSPid, VTY_NEWLINE);               GET_TE_METRIC(te_is_neigh), LSPid, VTY_NEWLINE);
     }      }
   
   /* TE IPv4 tlv */    /* TE IPv4 tlv */
Line 865  lsp_print_detail (dnode_t * node, struct vty *vty, cha Line 989  lsp_print_detail (dnode_t * node, struct vty *vty, cha
                                te_ipv4_reach))                                 te_ipv4_reach))
     {      {
       /* FIXME: There should be better way to output this stuff. */        /* FIXME: There should be better way to output this stuff. */
      vty_out (vty, "  Metric: %-10d IP-Extended %s/%d%s",      vty_out (vty, "  Metric      : %-8d IPv4-Extended : %s/%d%s",
                ntohl (te_ipv4_reach->te_metric),                 ntohl (te_ipv4_reach->te_metric),
                inet_ntoa (newprefix2inaddr (&te_ipv4_reach->prefix_start,                 inet_ntoa (newprefix2inaddr (&te_ipv4_reach->prefix_start,
                                             te_ipv4_reach->control)),                                              te_ipv4_reach->control)),
                te_ipv4_reach->control & 0x3F, VTY_NEWLINE);                 te_ipv4_reach->control & 0x3F, VTY_NEWLINE);
     }      }
     vty_out (vty, "%s", VTY_NEWLINE);
   
   return;    return;
 }  }
Line 883  lsp_print_all (struct vty *vty, dict_t * lspdb, char d Line 1008  lsp_print_all (struct vty *vty, dict_t * lspdb, char d
   dnode_t *node = dict_first (lspdb), *next;    dnode_t *node = dict_first (lspdb), *next;
   int lsp_count = 0;    int lsp_count = 0;
   
   /* print the title, for both modes */  
   vty_out (vty, "LSP ID                   LSP Seq Num  LSP Checksum "  
            "LSP Holdtime ATT/P/OL%s", VTY_NEWLINE);  
   
   if (detail == ISIS_UI_LEVEL_BRIEF)    if (detail == ISIS_UI_LEVEL_BRIEF)
     {      {
       while (node != NULL)        while (node != NULL)
Line 894  lsp_print_all (struct vty *vty, dict_t * lspdb, char d Line 1015  lsp_print_all (struct vty *vty, dict_t * lspdb, char d
           /* I think it is unnecessary, so I comment it out */            /* I think it is unnecessary, so I comment it out */
           /* dict_contains (lspdb, node); */            /* dict_contains (lspdb, node); */
           next = dict_next (lspdb, node);            next = dict_next (lspdb, node);
          lsp_print (node, vty, dynhost);          lsp_print (dnode_get (node), vty, dynhost);
           node = next;            node = next;
           lsp_count++;            lsp_count++;
         }          }
Line 904  lsp_print_all (struct vty *vty, dict_t * lspdb, char d Line 1025  lsp_print_all (struct vty *vty, dict_t * lspdb, char d
       while (node != NULL)        while (node != NULL)
         {          {
           next = dict_next (lspdb, node);            next = dict_next (lspdb, node);
          lsp_print_detail (node, vty, dynhost);          lsp_print_detail (dnode_get (node), vty, dynhost);
           node = next;            node = next;
           lsp_count++;            lsp_count++;
         }          }
Line 914  lsp_print_all (struct vty *vty, dict_t * lspdb, char d Line 1035  lsp_print_all (struct vty *vty, dict_t * lspdb, char d
 }  }
   
 #define FRAG_THOLD(S,T) \  #define FRAG_THOLD(S,T) \
((STREAM_SIZE(S)*T)/100)  ((STREAM_SIZE(S)*T)/100)
   
 /* stream*, area->lsp_frag_threshold, increment */  /* stream*, area->lsp_frag_threshold, increment */
 #define FRAG_NEEDED(S,T,I) \  #define FRAG_NEEDED(S,T,I) \
Line 933  lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, Line 1054  lsp_tlv_fit (struct isis_lsp *lsp, struct list **from,
   if (!FRAG_NEEDED (lsp->pdu, frag_thold, listcount (*from) * tlvsize + 2))    if (!FRAG_NEEDED (lsp->pdu, frag_thold, listcount (*from) * tlvsize + 2))
     {      {
       tlv_build_func (*from, lsp->pdu);        tlv_build_func (*from, lsp->pdu);
      *to = *from;      if (listcount (*to) != 0)
      *from = NULL;        {
           struct listnode *node, *nextnode;
           void *elem;
 
           for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem))
             {
               listnode_add (*to, elem);
               list_delete_node (*from, node);
             }
         }
       else
         {
           list_free (*to);
           *to = *from;
           *from = NULL;
         }
     }      }
   else if (!FRAG_NEEDED (lsp->pdu, frag_thold, tlvsize + 2))    else if (!FRAG_NEEDED (lsp->pdu, frag_thold, tlvsize + 2))
     {      {
       /* fit all we can */        /* fit all we can */
       count = FRAG_THOLD (lsp->pdu, frag_thold) - 2 -        count = FRAG_THOLD (lsp->pdu, frag_thold) - 2 -
         (STREAM_SIZE (lsp->pdu) - STREAM_REMAIN (lsp->pdu));          (STREAM_SIZE (lsp->pdu) - STREAM_REMAIN (lsp->pdu));
      if (count)      count = count / tlvsize;
        count = count / tlvsize;      if (count > (int)listcount (*from))
         count = listcount (*from);
       for (i = 0; i < count; i++)        for (i = 0; i < count; i++)
         {          {
           listnode_add (*to, listgetdata (listhead (*from)));            listnode_add (*to, listgetdata (listhead (*from)));
Line 954  lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, Line 1091  lsp_tlv_fit (struct isis_lsp *lsp, struct list **from,
   return;    return;
 }  }
   
   static u_int16_t
   lsp_rem_lifetime (struct isis_area *area, int level)
   {
     u_int16_t rem_lifetime;
   
     /* Add jitter to configured LSP lifetime */
     rem_lifetime = isis_jitter (area->max_lsp_lifetime[level - 1],
                                 MAX_AGE_JITTER);
   
     /* No jitter if the max refresh will be less than configure gen interval */
     /* N.B. this calucation is acceptable since rem_lifetime is in [332,65535] at
      * this point */
     if (area->lsp_gen_interval[level - 1] > (rem_lifetime - 300))
       rem_lifetime = area->max_lsp_lifetime[level - 1];
   
     return rem_lifetime;
   }
   
   static u_int16_t
   lsp_refresh_time (struct isis_lsp *lsp, u_int16_t rem_lifetime)
   {
     struct isis_area *area = lsp->area;
     int level = lsp->level;
     u_int16_t refresh_time;
   
     /* Add jitter to LSP refresh time */
     refresh_time = isis_jitter (area->lsp_refresh[level - 1],
                                 MAX_LSP_GEN_JITTER);
   
     /* RFC 4444 : make sure the refresh time is at least less than 300
      * of the remaining lifetime and more than gen interval */
     if (refresh_time <= area->lsp_gen_interval[level - 1] ||
         refresh_time > (rem_lifetime - 300))
       refresh_time = rem_lifetime - 300;
   
     /* In cornercases, refresh_time might be <= lsp_gen_interval, however
      * we accept this violation to satisfy refresh_time <= rem_lifetime - 300 */
   
     return refresh_time;
   }
   
 static struct isis_lsp *  static struct isis_lsp *
 lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, struct isis_area *area,  lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, struct isis_area *area,
                int level)                 int level)
Line 963  lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, Line 1141  lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0,
   
   memcpy (frag_id, lsp0->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 1);    memcpy (frag_id, lsp0->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 1);
   LSP_FRAGMENT (frag_id) = frag_num;    LSP_FRAGMENT (frag_id) = frag_num;
     /* FIXME add authentication TLV for fragment LSPs */
   lsp = lsp_search (frag_id, area->lspdb[level - 1]);    lsp = lsp_search (frag_id, area->lspdb[level - 1]);
   if (lsp)    if (lsp)
     {      {
      /*      /* Clear the TLVs */
       * Clear the TLVs, but inherit the authinfo 
       */ 
       lsp_clear_data (lsp);        lsp_clear_data (lsp);
       if (lsp0->tlv_data.auth_info.type)  
         {  
           memcpy (&lsp->tlv_data.auth_info, &lsp->tlv_data.auth_info,  
                   sizeof (struct isis_passwd));  
           tlv_add_authinfo (lsp->tlv_data.auth_info.type,  
                             lsp->tlv_data.auth_info.len,  
                             lsp->tlv_data.auth_info.passwd, lsp->pdu);  
         }  
       return lsp;        return lsp;
     }      }
  lsp = lsp_new (frag_id, area->max_lsp_lifetime[level - 1], 0, area->is_type,  lsp = lsp_new (area, frag_id, ntohs(lsp0->lsp_header->rem_lifetime), 0,
                 0, level);                 lsp_bits_generate (level, area->overload_bit,
                  area->attached_bit), 0, level);
   lsp->area = area;
   lsp->own_lsp = 1;    lsp->own_lsp = 1;
   lsp_insert (lsp, area->lspdb[level - 1]);    lsp_insert (lsp, area->lspdb[level - 1]);
   listnode_add (lsp0->lspu.frags, lsp);    listnode_add (lsp0->lspu.frags, lsp);
   lsp->lspu.zero_lsp = lsp0;    lsp->lspu.zero_lsp = lsp0;
  /*  return lsp;
   * Copy the authinfo from zero LSP}
   */
  if (lsp0->tlv_data.auth_info.type)static void
 lsp_build_ext_reach_ipv4(struct isis_lsp *lsp, struct isis_area *area,
                          struct tlvs *tlv_data)
 {
   struct route_table *er_table;
   struct route_node *rn;
   struct prefix_ipv4 *ipv4;
   struct isis_ext_info *info;
   struct ipv4_reachability *ipreach;
   struct te_ipv4_reachability *te_ipreach;
 
   er_table = get_ext_reach(area, AF_INET, lsp->level);
   if (!er_table)
     return;
 
   for (rn = route_top(er_table); rn; rn = route_next(rn))
     {      {
      memcpy (&lsp->tlv_data.auth_info, &lsp->tlv_data.auth_info,      if (!rn->info)
              sizeof (struct isis_passwd));        continue;
      tlv_add_authinfo (lsp->tlv_data.auth_info.type,
                        lsp->tlv_data.auth_info.len,      ipv4 = (struct prefix_ipv4*)&rn->p;
                        lsp->tlv_data.auth_info.passwd, lsp->pdu);      info = rn->info;
       if (area->oldmetric)
         {
           if (tlv_data->ipv4_ext_reachs == NULL)
             {
               tlv_data->ipv4_ext_reachs = list_new();
               tlv_data->ipv4_ext_reachs->del = free_tlv;
             }
           ipreach = XMALLOC(MTYPE_ISIS_TLV, sizeof(*ipreach));
 
           ipreach->prefix.s_addr = ipv4->prefix.s_addr;
           masklen2ip(ipv4->prefixlen, &ipreach->mask);
           ipreach->prefix.s_addr &= ipreach->mask.s_addr;
 
           if ((info->metric & 0x3f) != info->metric)
             ipreach->metrics.metric_default = 0x3f;
           else
             ipreach->metrics.metric_default = info->metric;
           ipreach->metrics.metric_expense = METRICS_UNSUPPORTED;
           ipreach->metrics.metric_error = METRICS_UNSUPPORTED;
           ipreach->metrics.metric_delay = METRICS_UNSUPPORTED;
           listnode_add(tlv_data->ipv4_ext_reachs, ipreach);
         }
       if (area->newmetric)
         {
           if (tlv_data->te_ipv4_reachs == NULL)
             {
               tlv_data->te_ipv4_reachs = list_new();
               tlv_data->te_ipv4_reachs->del = free_tlv;
             }
           te_ipreach =
               XCALLOC(MTYPE_ISIS_TLV,
                       sizeof(*te_ipreach) - 1 + PSIZE(ipv4->prefixlen));
           if (info->metric > MAX_WIDE_PATH_METRIC)
             te_ipreach->te_metric = htonl(MAX_WIDE_PATH_METRIC);
           else
             te_ipreach->te_metric = htonl(info->metric);
           te_ipreach->control = ipv4->prefixlen & 0x3f;
           memcpy(&te_ipreach->prefix_start, &ipv4->prefix.s_addr,
                  PSIZE(ipv4->prefixlen));
           listnode_add(tlv_data->te_ipv4_reachs, te_ipreach);
         }
     }      }
   return lsp;  
 }  }
   
   static void
   lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, struct isis_area *area,
                            struct tlvs *tlv_data)
   {
     struct route_table *er_table;
     struct route_node *rn;
     struct prefix_ipv6 *ipv6;
     struct isis_ext_info *info;
     struct ipv6_reachability *ip6reach;
   
     er_table = get_ext_reach(area, AF_INET6, lsp->level);
     if (!er_table)
       return;
   
     for (rn = route_top(er_table); rn; rn = route_next(rn))
       {
         if (!rn->info)
           continue;
   
         ipv6 = (struct prefix_ipv6*)&rn->p;
         info = rn->info;
   
         if (tlv_data->ipv6_reachs == NULL)
           {
             tlv_data->ipv6_reachs = list_new();
             tlv_data->ipv6_reachs->del = free_tlv;
           }
         ip6reach = XCALLOC(MTYPE_ISIS_TLV, sizeof(*ip6reach));
         if (info->metric > MAX_WIDE_PATH_METRIC)
           ip6reach->metric = htonl(MAX_WIDE_PATH_METRIC);
         else
           ip6reach->metric = htonl(info->metric);
         ip6reach->control_info = DISTRIBUTION_EXTERNAL;
         ip6reach->prefix_len = ipv6->prefixlen;
         memcpy(ip6reach->prefix, ipv6->prefix.s6_addr, sizeof(ip6reach->prefix));
         listnode_add(tlv_data->ipv6_reachs, ip6reach);
       }
   }
   
   static void
   lsp_build_ext_reach (struct isis_lsp *lsp, struct isis_area *area,
                        struct tlvs *tlv_data)
   {
     lsp_build_ext_reach_ipv4(lsp, area, tlv_data);
     lsp_build_ext_reach_ipv6(lsp, area, tlv_data);
   }
   
 /*  /*
  * Builds the LSP data part. This func creates a new frag whenever    * Builds the LSP data part. This func creates a new frag whenever 
  * area->lsp_frag_threshold is exceeded.   * area->lsp_frag_threshold is exceeded.
  */   */
 static void  static void
lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)lsp_build (struct isis_lsp *lsp, struct isis_area *area)
 {  {
   struct is_neigh *is_neigh;    struct is_neigh *is_neigh;
   struct te_is_neigh *te_is_neigh;    struct te_is_neigh *te_is_neigh;
Line 1017  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis Line 1290  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis
   struct te_ipv4_reachability *te_ipreach;    struct te_ipv4_reachability *te_ipreach;
   struct isis_adjacency *nei;    struct isis_adjacency *nei;
 #ifdef HAVE_IPV6  #ifdef HAVE_IPV6
  struct prefix_ipv6 *ipv6, *ip6prefix;  struct prefix_ipv6 *ipv6, ip6prefix;
   struct ipv6_reachability *ip6reach;    struct ipv6_reachability *ip6reach;
 #endif /* HAVE_IPV6 */  #endif /* HAVE_IPV6 */
   struct tlvs tlv_data;    struct tlvs tlv_data;
   struct isis_lsp *lsp0 = lsp;    struct isis_lsp *lsp0 = lsp;
   struct isis_passwd *passwd;  
   struct in_addr *routerid;    struct in_addr *routerid;
     uint32_t expected = 0, found = 0;
     uint32_t metric;
     u_char zero_id[ISIS_SYS_ID_LEN + 1];
     int retval = ISIS_OK;
     char buf[BUFSIZ];
   
     lsp_debug("ISIS (%s): Constructing local system LSP for level %d", area->area_tag, level);
   
   /*    /*
      * Building the zero lsp
      */
     memset (zero_id, 0, ISIS_SYS_ID_LEN + 1);
   
     /* Reset stream endp. Stream is always there and on every LSP refresh only
      * TLV part of it is overwritten. So we must seek past header we will not
      * touch. */
     stream_reset (lsp->pdu);
     stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
   
     /*
      * Add the authentication info if its present
      */
     lsp_auth_add (lsp);
   
     /*
    * First add the tlvs related to area     * First add the tlvs related to area
    */     */
   
Line 1033  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis Line 1328  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis
   if (lsp->tlv_data.area_addrs == NULL)    if (lsp->tlv_data.area_addrs == NULL)
     lsp->tlv_data.area_addrs = list_new ();      lsp->tlv_data.area_addrs = list_new ();
   list_add_list (lsp->tlv_data.area_addrs, area->area_addrs);    list_add_list (lsp->tlv_data.area_addrs, area->area_addrs);
     if (listcount (lsp->tlv_data.area_addrs) > 0)
       tlv_add_area_addrs (lsp->tlv_data.area_addrs, lsp->pdu);
   
   /* Protocols Supported */    /* Protocols Supported */
   if (area->ip_circuits > 0    if (area->ip_circuits > 0
 #ifdef HAVE_IPV6  #ifdef HAVE_IPV6
Line 1044  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis Line 1342  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis
       lsp->tlv_data.nlpids->count = 0;        lsp->tlv_data.nlpids->count = 0;
       if (area->ip_circuits > 0)        if (area->ip_circuits > 0)
         {          {
             lsp_debug("ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs", area->area_tag);
           lsp->tlv_data.nlpids->count++;            lsp->tlv_data.nlpids->count++;
           lsp->tlv_data.nlpids->nlpids[0] = NLPID_IP;            lsp->tlv_data.nlpids->nlpids[0] = NLPID_IP;
         }          }
 #ifdef HAVE_IPV6  #ifdef HAVE_IPV6
       if (area->ipv6_circuits > 0)        if (area->ipv6_circuits > 0)
         {          {
             lsp_debug("ISIS (%s): Found IPv6 circuit, adding IPv6 to NLPIDs", area->area_tag);
           lsp->tlv_data.nlpids->count++;            lsp->tlv_data.nlpids->count++;
           lsp->tlv_data.nlpids->nlpids[lsp->tlv_data.nlpids->count - 1] =            lsp->tlv_data.nlpids->nlpids[lsp->tlv_data.nlpids->count - 1] =
             NLPID_IPV6;              NLPID_IPV6;
         }          }
 #endif /* HAVE_IPV6 */  #endif /* HAVE_IPV6 */
         tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu);
     }      }
   
   /* Dynamic Hostname */    /* Dynamic Hostname */
   if (area->dynhostname)    if (area->dynhostname)
     {      {
         const char *hostname = unix_hostname();
         size_t hostname_len = strlen(hostname);
   
       lsp->tlv_data.hostname = XMALLOC (MTYPE_ISIS_TLV,        lsp->tlv_data.hostname = XMALLOC (MTYPE_ISIS_TLV,
                                         sizeof (struct hostname));                                          sizeof (struct hostname));
   
      memcpy (lsp->tlv_data.hostname->name, unix_hostname (),      strncpy((char *)lsp->tlv_data.hostname->name, hostname,
              strlen (unix_hostname ()));              sizeof(lsp->tlv_data.hostname->name));
      lsp->tlv_data.hostname->namelen = strlen (unix_hostname ());      if (hostname_len <= MAX_TLV_LEN)
    }        lsp->tlv_data.hostname->namelen = hostname_len;
       else
         lsp->tlv_data.hostname->namelen = MAX_TLV_LEN;
   
  /*      lsp_debug("ISIS (%s): Adding dynamic hostname '%.*s'", area->area_tag,
   * Building the zero lsp                lsp->tlv_data.hostname->namelen, lsp->tlv_data.hostname->name);
   */      tlv_add_dynamic_hostname (lsp->tlv_data.hostname, lsp->pdu);
    }
  /* Reset stream endp. Stream is always there and on every LSP refresh only  else
   * TLV part of it is overwritten. So we must seek past header we will not 
   * touch. */ 
  stream_reset (lsp->pdu); 
  stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); 
 
  /* 
   * Add the authentication info if its present 
   */ 
  (level == 1) ? (passwd = &area->area_passwd) : 
    (passwd = &area->domain_passwd); 
  if (passwd->type) 
     {      {
      memcpy (&lsp->tlv_data.auth_info, passwd, sizeof (struct isis_passwd));      lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)", area->area_tag);
      tlv_add_authinfo (passwd->type, passwd->len, passwd->passwd, lsp->pdu); 
     }      }
   if (lsp->tlv_data.nlpids)  
     tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu);  
   if (lsp->tlv_data.hostname)  
     tlv_add_dynamic_hostname (lsp->tlv_data.hostname, lsp->pdu);  
   if (lsp->tlv_data.area_addrs && listcount (lsp->tlv_data.area_addrs) > 0)  
     tlv_add_area_addrs (lsp->tlv_data.area_addrs, lsp->pdu);  
   
   /* IPv4 address and TE router ID TLVs. In case of the first one we don't    /* IPv4 address and TE router ID TLVs. In case of the first one we don't
    * follow "C" vendor, but "J" vendor behavior - one IPv4 address is put into     * follow "C" vendor, but "J" vendor behavior - one IPv4 address is put into
    * LSP and this address is same as router id. */     * LSP and this address is same as router id. */
  if (router_id_zebra.s_addr != 0)  if (isis->router_id != 0)
     {      {
         inet_ntop(AF_INET, &isis->router_id, buf, sizeof(buf));
         lsp_debug("ISIS (%s): Adding router ID %s as IPv4 tlv.", area->area_tag, buf);
       if (lsp->tlv_data.ipv4_addrs == NULL)        if (lsp->tlv_data.ipv4_addrs == NULL)
         {          {
           lsp->tlv_data.ipv4_addrs = list_new ();            lsp->tlv_data.ipv4_addrs = list_new ();
Line 1106  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis Line 1397  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis
         }          }
   
       routerid = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct in_addr));        routerid = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct in_addr));
      routerid->s_addr = router_id_zebra.s_addr;      routerid->s_addr = isis->router_id;
       listnode_add (lsp->tlv_data.ipv4_addrs, routerid);        listnode_add (lsp->tlv_data.ipv4_addrs, routerid);
       tlv_add_in_addr (routerid, lsp->pdu, IPV4_ADDR);        tlv_add_in_addr (routerid, lsp->pdu, IPV4_ADDR);
   
Line 1114  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis Line 1405  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis
        * TLV's are in use. */         * TLV's are in use. */
       if (area->newmetric)        if (area->newmetric)
         {          {
             lsp_debug("ISIS (%s): Adding router ID also as TE router ID tlv.", area->area_tag);
           lsp->tlv_data.router_id = XMALLOC (MTYPE_ISIS_TLV,            lsp->tlv_data.router_id = XMALLOC (MTYPE_ISIS_TLV,
                                              sizeof (struct in_addr));                                               sizeof (struct in_addr));
          lsp->tlv_data.router_id->id.s_addr = router_id_zebra.s_addr;          lsp->tlv_data.router_id->id.s_addr = isis->router_id;
          tlv_add_in_addr (&lsp->tlv_data.router_id->id, lsp->pdu, TE_ROUTER_ID);          tlv_add_in_addr (&lsp->tlv_data.router_id->id, lsp->pdu,
                            TE_ROUTER_ID);
         }          }
     }      }
     else
       {
         lsp_debug("ISIS (%s): Router ID is unset. Not adding tlv.", area->area_tag);
       }
   
   memset (&tlv_data, 0, sizeof (struct tlvs));    memset (&tlv_data, 0, sizeof (struct tlvs));
   
 #ifdef TOPOLOGY_GENERATE  #ifdef TOPOLOGY_GENERATE
   /* If topology exists (and we create topology for level 1 only), create    /* If topology exists (and we create topology for level 1 only), create
    * (hardcoded) link to topology. */     * (hardcoded) link to topology. */
  if (area->topology && level == 1)  if (area->topology && level == IS_LEVEL_1)
     {      {
       if (tlv_data.is_neighs == NULL)        if (tlv_data.is_neighs == NULL)
         {          {
Line 1146  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis Line 1443  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis
     }      }
 #endif /* TOPOLOGY_GENERATE */  #endif /* TOPOLOGY_GENERATE */
   
     lsp_debug("ISIS (%s): Adding circuit specific information.", area->area_tag);
   
   /*    /*
    * Then build lists of tlvs related to circuits     * Then build lists of tlvs related to circuits
    */     */
   for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit))    for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit))
     {      {
         if (!circuit->interface)
           lsp_debug("ISIS (%s): Processing %s circuit %p with unknown interface",
                     area->area_tag, circuit_type2string(circuit->circ_type), circuit);
         else
           lsp_debug("ISIS (%s): Processing %s circuit %s",
                     area->area_tag, circuit_type2string(circuit->circ_type), circuit->interface->name);
   
       if (circuit->state != C_STATE_UP)        if (circuit->state != C_STATE_UP)
        continue;        {
           lsp_debug("ISIS (%s): Circuit is not up, ignoring.", area->area_tag);
           continue;
         }
   
       /*        /*
        * Add IPv4 internal reachability of this circuit         * Add IPv4 internal reachability of this circuit
Line 1160  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis Line 1469  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis
       if (circuit->ip_router && circuit->ip_addrs &&        if (circuit->ip_router && circuit->ip_addrs &&
           circuit->ip_addrs->count > 0)            circuit->ip_addrs->count > 0)
         {          {
             lsp_debug("ISIS (%s): Circuit has IPv4 active, adding respective TLVs.", area->area_tag);
           if (area->oldmetric)            if (area->oldmetric)
             {              {
               if (tlv_data.ipv4_int_reachs == NULL)                if (tlv_data.ipv4_int_reachs == NULL)
Line 1175  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis Line 1485  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis
                   masklen2ip (ipv4->prefixlen, &ipreach->mask);                    masklen2ip (ipv4->prefixlen, &ipreach->mask);
                   ipreach->prefix.s_addr = ((ipreach->mask.s_addr) &                    ipreach->prefix.s_addr = ((ipreach->mask.s_addr) &
                                             (ipv4->prefix.s_addr));                                              (ipv4->prefix.s_addr));
                     inet_ntop(AF_INET, &ipreach->prefix.s_addr, buf, sizeof(buf));
                     lsp_debug("ISIS (%s): Adding old-style IP reachability for %s/%d",
                               area->area_tag, buf, ipv4->prefixlen);
                   listnode_add (tlv_data.ipv4_int_reachs, ipreach);                    listnode_add (tlv_data.ipv4_int_reachs, ipreach);
                 }                  }
               tlv_data.ipv4_int_reachs->del = free_tlv;  
             }              }
           if (area->newmetric)            if (area->newmetric)
             {              {
Line 1201  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis Line 1513  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis
                   te_ipreach->control = (ipv4->prefixlen & 0x3F);                    te_ipreach->control = (ipv4->prefixlen & 0x3F);
                   memcpy (&te_ipreach->prefix_start, &ipv4->prefix.s_addr,                    memcpy (&te_ipreach->prefix_start, &ipv4->prefix.s_addr,
                           (ipv4->prefixlen + 7)/8);                            (ipv4->prefixlen + 7)/8);
                     inet_ntop(AF_INET, &ipv4->prefix.s_addr, buf, sizeof(buf));
                     lsp_debug("ISIS (%s): Adding te-style IP reachability for %s/%d",
                               area->area_tag, buf, ipv4->prefixlen);
                   listnode_add (tlv_data.te_ipv4_reachs, te_ipreach);                    listnode_add (tlv_data.te_ipv4_reachs, te_ipreach);
                 }                  }
             }              }
         }          }
   
 #ifdef HAVE_IPV6  #ifdef HAVE_IPV6
       /*        /*
        * Add IPv6 reachability of this circuit         * Add IPv6 reachability of this circuit
Line 1231  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis Line 1547  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis
   
               ip6reach->control_info = 0;                ip6reach->control_info = 0;
               ip6reach->prefix_len = ipv6->prefixlen;                ip6reach->prefix_len = ipv6->prefixlen;
              memcpy (&ip6prefix, &ipv6, sizeof(ip6prefix));              memcpy(&ip6prefix, ipv6, sizeof(ip6prefix));
              apply_mask_ipv6 (ip6prefix);              apply_mask_ipv6(&ip6prefix);
              memcpy (ip6reach->prefix, ip6prefix->prefix.s6_addr,
               inet_ntop(AF_INET6, &ip6prefix.prefix.s6_addr, buf, sizeof(buf));
               lsp_debug("ISIS (%s): Adding IPv6 reachability for %s/%d",
                         area->area_tag, buf, ipv6->prefixlen);
 
               memcpy (ip6reach->prefix, ip6prefix.prefix.s6_addr,
                       sizeof (ip6reach->prefix));                        sizeof (ip6reach->prefix));
               listnode_add (tlv_data.ipv6_reachs, ip6reach);                listnode_add (tlv_data.ipv6_reachs, ip6reach);
             }              }
Line 1243  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis Line 1564  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis
       switch (circuit->circ_type)        switch (circuit->circ_type)
         {          {
         case CIRCUIT_T_BROADCAST:          case CIRCUIT_T_BROADCAST:
          if (level & circuit->circuit_is_type)          if (level & circuit->is_type)
             {              {
               if (area->oldmetric)                if (area->oldmetric)
                 {                  {
Line 1253  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis Line 1574  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis
                       tlv_data.is_neighs->del = free_tlv;                        tlv_data.is_neighs->del = free_tlv;
                     }                      }
                   is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));                    is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
                  if (level == 1)                  if (level == IS_LEVEL_1)
                     memcpy (is_neigh->neigh_id,                      memcpy (is_neigh->neigh_id,
                             circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);                              circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
                   else                    else
                     memcpy (is_neigh->neigh_id,                      memcpy (is_neigh->neigh_id,
                             circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);                              circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
                   is_neigh->metrics = circuit->metrics[level - 1];                    is_neigh->metrics = circuit->metrics[level - 1];
                  listnode_add (tlv_data.is_neighs, is_neigh);                  if (!memcmp (is_neigh->neigh_id, zero_id,
                  tlv_data.is_neighs->del = free_tlv;                               ISIS_SYS_ID_LEN + 1))
                     {
                       XFREE (MTYPE_ISIS_TLV, is_neigh);
                       lsp_debug("ISIS (%s): No DIS for circuit, not adding old-style IS neighbor.",
                                 area->area_tag);
                     }
                   else
                     {
                       listnode_add (tlv_data.is_neighs, is_neigh);
                       lsp_debug("ISIS (%s): Adding DIS %s.%02x as old-style neighbor",
                                 area->area_tag, sysid_print(is_neigh->neigh_id),
                                 LSP_PSEUDO_ID(is_neigh->neigh_id));
                     }
                 }                  }
               if (area->newmetric)                if (area->newmetric)
                 {                  {
                   uint32_t metric;  
   
                   if (tlv_data.te_is_neighs == NULL)                    if (tlv_data.te_is_neighs == NULL)
                     {                      {
                       tlv_data.te_is_neighs = list_new ();                        tlv_data.te_is_neighs = list_new ();
Line 1274  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis Line 1605  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis
                     }                      }
                   te_is_neigh = XCALLOC (MTYPE_ISIS_TLV,                    te_is_neigh = XCALLOC (MTYPE_ISIS_TLV,
                                          sizeof (struct te_is_neigh));                                           sizeof (struct te_is_neigh));
                  if (level == 1)                  if (level == IS_LEVEL_1)
                     memcpy (te_is_neigh->neigh_id,                      memcpy (te_is_neigh->neigh_id,
                             circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);                              circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
                   else                    else
                     memcpy (te_is_neigh->neigh_id,                      memcpy (te_is_neigh->neigh_id,
                             circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);                              circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
                   if (area->oldmetric)                    if (area->oldmetric)
                    metric =                    metric = circuit->metrics[level - 1].metric_default;
                      ((htonl(circuit->metrics[level - 1].metric_default) >> 8) 
                              & 0xffffff); 
                   else                    else
                    metric = ((htonl(*circuit->te_metric) >> 8) & 0xffffff);                    metric = circuit->te_metric[level - 1];
                  SET_TE_METRIC(te_is_neigh, metric);
                  memcpy (te_is_neigh->te_metric, &metric, 3);                  if (!memcmp (te_is_neigh->neigh_id, zero_id,
                  listnode_add (tlv_data.te_is_neighs, te_is_neigh);                               ISIS_SYS_ID_LEN + 1))
                     {
                       XFREE (MTYPE_ISIS_TLV, te_is_neigh);
                       lsp_debug("ISIS (%s): No DIS for circuit, not adding te-style IS neighbor.",
                                 area->area_tag);
                     }
                   else
                     {
                       listnode_add (tlv_data.te_is_neighs, te_is_neigh);
                       lsp_debug("ISIS (%s): Adding DIS %s.%02x as te-style neighbor",
                                 area->area_tag, sysid_print(te_is_neigh->neigh_id),
                                 LSP_PSEUDO_ID(te_is_neigh->neigh_id));
                     }
                 }                  }
             }              }
             else
               {
                 lsp_debug("ISIS (%s): Circuit is not active for current level. Not adding IS neighbors",
                           area->area_tag);
               }
           break;            break;
         case CIRCUIT_T_P2P:          case CIRCUIT_T_P2P:
           nei = circuit->u.p2p.neighbor;            nei = circuit->u.p2p.neighbor;
Line 1307  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis Line 1653  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis
                   memcpy (is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN);                    memcpy (is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN);
                   is_neigh->metrics = circuit->metrics[level - 1];                    is_neigh->metrics = circuit->metrics[level - 1];
                   listnode_add (tlv_data.is_neighs, is_neigh);                    listnode_add (tlv_data.is_neighs, is_neigh);
                     lsp_debug("ISIS (%s): Adding old-style is reach for %s", area->area_tag,
                               sysid_print(is_neigh->neigh_id));
                 }                  }
               if (area->newmetric)                if (area->newmetric)
                 {                  {
Line 1320  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis Line 1668  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis
                   te_is_neigh = XCALLOC (MTYPE_ISIS_TLV,                    te_is_neigh = XCALLOC (MTYPE_ISIS_TLV,
                                          sizeof (struct te_is_neigh));                                           sizeof (struct te_is_neigh));
                   memcpy (te_is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN);                    memcpy (te_is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN);
                  metric = ((htonl(*circuit->te_metric) >> 8) & 0xffffff);                  metric = circuit->te_metric[level - 1];
                  memcpy (te_is_neigh->te_metric, &metric, 3);                  SET_TE_METRIC(te_is_neigh, metric);
                   listnode_add (tlv_data.te_is_neighs, te_is_neigh);                    listnode_add (tlv_data.te_is_neighs, te_is_neigh);
                     lsp_debug("ISIS (%s): Adding te-style is reach for %s", area->area_tag,
                               sysid_print(te_is_neigh->neigh_id));
                 }                  }
             }              }
             else
               {
                 lsp_debug("ISIS (%s): No adjacency for given level on this circuit. Not adding IS neighbors",
                 area->area_tag);
               }
           break;            break;
        case CIRCUIT_T_STATIC_IN:        case CIRCUIT_T_LOOPBACK:
          zlog_warn ("lsp_area_create: unsupported circuit type");          break;
          break; 
        case CIRCUIT_T_STATIC_OUT: 
          zlog_warn ("lsp_area_create: unsupported circuit type"); 
          break; 
        case CIRCUIT_T_DA: 
          zlog_warn ("lsp_area_create: unsupported circuit type"); 
          break; 
         default:          default:
           zlog_warn ("lsp_area_create: unknown circuit type");            zlog_warn ("lsp_area_create: unknown circuit type");
         }          }
     }      }
   
     lsp_build_ext_reach(lsp, area, &tlv_data);
   
     lsp_debug("ISIS (%s): LSP construction is complete. Serializing...", area->area_tag);
   
   while (tlv_data.ipv4_int_reachs && listcount (tlv_data.ipv4_int_reachs))    while (tlv_data.ipv4_int_reachs && listcount (tlv_data.ipv4_int_reachs))
     {      {
       if (lsp->tlv_data.ipv4_int_reachs == NULL)        if (lsp->tlv_data.ipv4_int_reachs == NULL)
Line 1347  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis Line 1699  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis
       lsp_tlv_fit (lsp, &tlv_data.ipv4_int_reachs,        lsp_tlv_fit (lsp, &tlv_data.ipv4_int_reachs,
                    &lsp->tlv_data.ipv4_int_reachs,                     &lsp->tlv_data.ipv4_int_reachs,
                    IPV4_REACH_LEN, area->lsp_frag_threshold,                     IPV4_REACH_LEN, area->lsp_frag_threshold,
                   tlv_add_ipv4_reachs);                   tlv_add_ipv4_int_reachs);
       if (tlv_data.ipv4_int_reachs && listcount (tlv_data.ipv4_int_reachs))        if (tlv_data.ipv4_int_reachs && listcount (tlv_data.ipv4_int_reachs))
         lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,          lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
                              lsp0, area, level);                               lsp0, area, level);
     }      }
   
     while (tlv_data.ipv4_ext_reachs && listcount (tlv_data.ipv4_ext_reachs))
       {
         if (lsp->tlv_data.ipv4_ext_reachs == NULL)
           lsp->tlv_data.ipv4_ext_reachs = list_new ();
         lsp_tlv_fit (lsp, &tlv_data.ipv4_ext_reachs,
                      &lsp->tlv_data.ipv4_ext_reachs,
                      IPV4_REACH_LEN, area->lsp_frag_threshold,
                      tlv_add_ipv4_ext_reachs);
         if (tlv_data.ipv4_ext_reachs && listcount (tlv_data.ipv4_ext_reachs))
           lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
                                lsp0, area, level);
       }
   
   /* FIXME: We pass maximum te_ipv4_reachability length to the lsp_tlv_fit()    /* FIXME: We pass maximum te_ipv4_reachability length to the lsp_tlv_fit()
    * for now. lsp_tlv_fit() needs to be fixed to deal with variable length     * for now. lsp_tlv_fit() needs to be fixed to deal with variable length
    * TLVs (sub TLVs!). */     * TLVs (sub TLVs!). */
Line 1361  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis Line 1727  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis
         lsp->tlv_data.te_ipv4_reachs = list_new ();          lsp->tlv_data.te_ipv4_reachs = list_new ();
       lsp_tlv_fit (lsp, &tlv_data.te_ipv4_reachs,        lsp_tlv_fit (lsp, &tlv_data.te_ipv4_reachs,
                    &lsp->tlv_data.te_ipv4_reachs,                     &lsp->tlv_data.te_ipv4_reachs,
                   9, area->lsp_frag_threshold, tlv_add_te_ipv4_reachs);                   TE_IPV4_REACH_LEN, area->lsp_frag_threshold,
                    tlv_add_te_ipv4_reachs);
       if (tlv_data.te_ipv4_reachs && listcount (tlv_data.te_ipv4_reachs))        if (tlv_data.te_ipv4_reachs && listcount (tlv_data.te_ipv4_reachs))
         lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,          lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
                              lsp0, area, level);                               lsp0, area, level);
Line 1406  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis Line 1773  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis
         lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,          lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
                              lsp0, area, level);                               lsp0, area, level);
     }      }
     lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
   
   free_tlvs (&tlv_data);    free_tlvs (&tlv_data);
   
     /* Validate the LSP */
     retval = parse_tlvs (area->area_tag, STREAM_DATA (lsp->pdu) +
                          ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN,
                          stream_get_endp (lsp->pdu) -
                          ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN,
                          &expected, &found, &tlv_data, NULL);
     assert (retval == ISIS_OK);
   
   return;    return;
 }  }
   
 /*  /*
 * 7.3.7 Generation on non-pseudonode LSPs * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs
  */   */
static intint
lsp_generate_non_pseudo (struct isis_area *area, int level)lsp_generate (struct isis_area *area, int level)
 {  {
   struct isis_lsp *oldlsp, *newlsp;    struct isis_lsp *oldlsp, *newlsp;
   u_int32_t seq_num = 0;    u_int32_t seq_num = 0;
   u_char lspid[ISIS_SYS_ID_LEN + 2];    u_char lspid[ISIS_SYS_ID_LEN + 2];
     u_int16_t rem_lifetime, refresh_time;
   
     if ((area == NULL) || (area->is_type & level) != level)
       return ISIS_ERROR;
   
   memset (&lspid, 0, ISIS_SYS_ID_LEN + 2);    memset (&lspid, 0, ISIS_SYS_ID_LEN + 2);
   memcpy (&lspid, isis->sysid, ISIS_SYS_ID_LEN);    memcpy (&lspid, isis->sysid, ISIS_SYS_ID_LEN);
   
   /* only builds the lsp if the area shares the level */    /* only builds the lsp if the area shares the level */
  if ((area->is_type & level) == level)  oldlsp = lsp_search (lspid, area->lspdb[level - 1]);
   if (oldlsp)
     {      {
      oldlsp = lsp_search (lspid, area->lspdb[level - 1]);      /* FIXME: we should actually initiate a purge */
      if (oldlsp)      seq_num = ntohl (oldlsp->lsp_header->seq_num);
        {      lsp_search_and_destroy (oldlsp->lsp_header->lsp_id,
          seq_num = ntohl (oldlsp->lsp_header->seq_num);                              area->lspdb[level - 1]);
          lsp_search_and_destroy (oldlsp->lsp_header->lsp_id, 
                                  area->lspdb[level - 1]); 
          /* FIXME: we should actually initiate a purge */ 
        } 
      newlsp = lsp_new (lspid, area->max_lsp_lifetime[level - 1], seq_num, 
                        area->is_type, 0, level); 
      newlsp->own_lsp = 1; 
 
      lsp_insert (newlsp, area->lspdb[level - 1]); 
      /* build_lsp_data (newlsp, area); */ 
      lsp_build_nonpseudo (newlsp, area); 
      /* time to calculate our checksum */ 
      lsp_seqnum_update (newlsp); 
     }      }
     rem_lifetime = lsp_rem_lifetime (area, level);
     newlsp = lsp_new (area, lspid, rem_lifetime, seq_num,
                       area->is_type | area->overload_bit | area->attached_bit,
                       0, level);
     newlsp->area = area;
     newlsp->own_lsp = 1;
   
  /* DEBUG_ADJ_PACKETS */  lsp_insert (newlsp, area->lspdb[level - 1]);
  if (isis->debugs & DEBUG_ADJ_PACKETS)  /* build_lsp_data (newlsp, area); */
   lsp_build (newlsp, area);
   /* time to calculate our checksum */
   lsp_seqnum_update (newlsp);
   newlsp->last_generated = time(NULL);
   lsp_set_all_srmflags (newlsp);
 
   refresh_time = lsp_refresh_time (newlsp, rem_lifetime);
 
   THREAD_TIMER_OFF (area->t_lsp_refresh[level - 1]);
   area->lsp_regenerate_pending[level - 1] = 0;
   if (level == IS_LEVEL_1)
     THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
                      lsp_l1_refresh, area, refresh_time);
   else if (level == IS_LEVEL_2)
     THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
                      lsp_l2_refresh, area, refresh_time);
 
   if (isis->debugs & DEBUG_UPDATE_PACKETS)
     {      {
      /* FIXME: is this place right? fix missing info */      zlog_debug ("ISIS-Upd (%s): Building L%d LSP %s, len %d, "
      zlog_debug ("ISIS-Upd (%s): Building L%d LSP", area->area_tag, level);                  "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us",
                   area->area_tag, level,
                   rawlspid_print (newlsp->lsp_header->lsp_id),
                   ntohl (newlsp->lsp_header->pdu_len),
                   ntohl (newlsp->lsp_header->seq_num),
                   ntohs (newlsp->lsp_header->checksum),
                   ntohs (newlsp->lsp_header->rem_lifetime),
                   refresh_time);
     }      }
     sched_debug("ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.",
                 area->area_tag, level);
   
   return ISIS_OK;    return ISIS_OK;
 }  }
   
 /*  /*
 * 7.3.9 Generation of level 1 LSPs (non-pseudonode) * Search own LSPs, update holding time and set SRM
  */   */
 int  
 lsp_l1_generate (struct isis_area *area)  
 {  
   THREAD_TIMER_ON (master, area->t_lsp_refresh[0], lsp_refresh_l1, area,  
                    MAX_LSP_GEN_INTERVAL);  
   
   return lsp_generate_non_pseudo (area, 1);  
 }  
   
 /*  
  * 7.3.9 Generation of level 2 LSPs (non-pseudonode)  
  */  
 int  
 lsp_l2_generate (struct isis_area *area)  
 {  
   THREAD_TIMER_ON (master, area->t_lsp_refresh[1], lsp_refresh_l2, area,  
                    MAX_LSP_GEN_INTERVAL);  
   
   return lsp_generate_non_pseudo (area, 2);  
 }  
   
 static int  static int
lsp_non_pseudo_regenerate (struct isis_area *area, int level)lsp_regenerate (struct isis_area *area, int level)
 {  {
  dict_t *lspdb = area->lspdb[level - 1];  dict_t *lspdb;
   struct isis_lsp *lsp, *frag;    struct isis_lsp *lsp, *frag;
   struct listnode *node;    struct listnode *node;
   u_char lspid[ISIS_SYS_ID_LEN + 2];    u_char lspid[ISIS_SYS_ID_LEN + 2];
     u_int16_t rem_lifetime, refresh_time;
   
     if ((area == NULL) || (area->is_type & level) != level)
       return ISIS_ERROR;
   
     lspdb = area->lspdb[level - 1];
   
   memset (lspid, 0, ISIS_SYS_ID_LEN + 2);    memset (lspid, 0, ISIS_SYS_ID_LEN + 2);
   memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN);    memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN);
   
Line 1495  lsp_non_pseudo_regenerate (struct isis_area *area, int Line 1882  lsp_non_pseudo_regenerate (struct isis_area *area, int
   
   if (!lsp)    if (!lsp)
     {      {
      zlog_err      zlog_err ("ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
        ("ISIS-Upd (%s): lsp_non_pseudo_regenerate(): no L%d LSP found!",                area->area_tag, level);
         area->area_tag, level); 
 
       return ISIS_ERROR;        return ISIS_ERROR;
     }      }
   
   lsp_clear_data (lsp);    lsp_clear_data (lsp);
  lsp_build_nonpseudo (lsp, area);  lsp_build (lsp, area);
  lsp->lsp_header->rem_lifetime = htons (isis_jitter  lsp->lsp_header->lsp_bits = lsp_bits_generate (level, area->overload_bit,
                                         (area->max_lsp_lifetime[level - 1],                                                 area->attached_bit);
                                          MAX_AGE_JITTER));  rem_lifetime = lsp_rem_lifetime (area, level);
   lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
   lsp_seqnum_update (lsp);    lsp_seqnum_update (lsp);
   
  if (isis->debugs & DEBUG_UPDATE_PACKETS)  lsp->last_generated = time (NULL);
   lsp_set_all_srmflags (lsp);
   for (ALL_LIST_ELEMENTS_RO (lsp->lspu.frags, node, frag))
     {      {
      zlog_debug ("ISIS-Upd (%s): refreshing our L%d LSP %s, "      frag->lsp_header->lsp_bits = lsp_bits_generate (level,
                  "seq 0x%08x, cksum 0x%04x lifetime %us",                                                      area->overload_bit,
                  area->area_tag,                                                      area->attached_bit);
                  level,      /* Set the lifetime values of all the fragments to the same value,
                  rawlspid_print (lsp->lsp_header->lsp_id),       * so that no fragment expires before the lsp is refreshed.
                  ntohl (lsp->lsp_header->seq_num),       */
                  ntohs (lsp->lsp_header->checksum),      frag->lsp_header->rem_lifetime = htons (rem_lifetime);
                  ntohs (lsp->lsp_header->rem_lifetime));      lsp_set_all_srmflags (frag);
     }      }
   
  lsp->last_generated = time (NULL);  refresh_time = lsp_refresh_time (lsp, rem_lifetime);
   if (level == IS_LEVEL_1)
     THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
                      lsp_l1_refresh, area, refresh_time);
   else if (level == IS_LEVEL_2)
     THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
                      lsp_l2_refresh, area, refresh_time);
   area->lsp_regenerate_pending[level - 1] = 0;    area->lsp_regenerate_pending[level - 1] = 0;
  ISIS_FLAGS_SET_ALL (lsp->SRMflags);
  for (ALL_LIST_ELEMENTS_RO (lsp->lspu.frags, node, frag))  if (isis->debugs & DEBUG_UPDATE_PACKETS)
     {      {
      frag->lsp_header->rem_lifetime = htons (isis_jitter      zlog_debug ("ISIS-Upd (%s): Refreshing our L%d LSP %s, len %d, "
                                              (area->                  "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us",
                                               max_lsp_lifetime[level - 1],                  area->area_tag, level,
                                               MAX_AGE_JITTER));                  rawlspid_print (lsp->lsp_header->lsp_id),
      ISIS_FLAGS_SET_ALL (frag->SRMflags);                  ntohl (lsp->lsp_header->pdu_len),
                   ntohl (lsp->lsp_header->seq_num),
                   ntohs (lsp->lsp_header->checksum),
                   ntohs (lsp->lsp_header->rem_lifetime),
                   refresh_time);
     }      }
     sched_debug("ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to non-pending.",
                 area->area_tag, level);
   
   if (area->ip_circuits)  
     isis_spf_schedule (area, level);  
 #ifdef HAVE_IPV6  
   if (area->ipv6_circuits)  
     isis_spf_schedule6 (area, level);  
 #endif  
   return ISIS_OK;    return ISIS_OK;
 }  }
   
 /*  /*
 * Done at least every MAX_LSP_GEN_INTERVAL. Search own LSPs, update holding * Something has changed or periodic refresh -> regenerate LSP
 * time and set SRM 
  */   */
intstatic int
lsp_refresh_l1 (struct thread *thread)lsp_l1_refresh (struct thread *thread)
 {  {
   struct isis_area *area;    struct isis_area *area;
   unsigned long ref_time;  
   
   area = THREAD_ARG (thread);    area = THREAD_ARG (thread);
   assert (area);    assert (area);
   
   area->t_lsp_refresh[0] = NULL;    area->t_lsp_refresh[0] = NULL;
  if (area->is_type & IS_LEVEL_1)  area->lsp_regenerate_pending[0] = 0;
    lsp_non_pseudo_regenerate (area, 1); 
   
  ref_time = area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ?  if ((area->is_type & IS_LEVEL_1) == 0)
    MAX_LSP_GEN_INTERVAL : area->lsp_refresh[0];    return ISIS_ERROR;
   
  THREAD_TIMER_ON (master, area->t_lsp_refresh[0], lsp_refresh_l1, area,  sched_debug("ISIS (%s): LSP L1 refresh timer expired. Refreshing LSP...", area->area_tag);
                   isis_jitter (ref_time, MAX_AGE_JITTER));  return lsp_regenerate (area, IS_LEVEL_1);
 
  return ISIS_OK; 
 }  }
   
intstatic int
lsp_refresh_l2 (struct thread *thread)lsp_l2_refresh (struct thread *thread)
 {  {
   struct isis_area *area;    struct isis_area *area;
   unsigned long ref_time;  
   
   area = THREAD_ARG (thread);    area = THREAD_ARG (thread);
   assert (area);    assert (area);
   
   area->t_lsp_refresh[1] = NULL;    area->t_lsp_refresh[1] = NULL;
  if (area->is_type & IS_LEVEL_2)  area->lsp_regenerate_pending[1] = 0;
    lsp_non_pseudo_regenerate (area, 2); 
   
  ref_time = area->lsp_refresh[1] > MAX_LSP_GEN_INTERVAL ?  if ((area->is_type & IS_LEVEL_2) == 0)
    MAX_LSP_GEN_INTERVAL : area->lsp_refresh[1];    return ISIS_ERROR;
   
  THREAD_TIMER_ON (master, area->t_lsp_refresh[1], lsp_refresh_l2, area,  sched_debug("ISIS (%s): LSP L2 refresh timer expired. Refreshing LSP...", area->area_tag);
                   isis_jitter (ref_time, MAX_AGE_JITTER));  return lsp_regenerate (area, IS_LEVEL_2);
 
  return ISIS_OK; 
 }  }
   
 /*  
  * Something has changed -> regenerate LSP  
  */  
   
 static int  
 lsp_l1_regenerate (struct thread *thread)  
 {  
   struct isis_area *area;  
   
   area = THREAD_ARG (thread);  
   area->lsp_regenerate_pending[0] = 0;  
   
   return lsp_non_pseudo_regenerate (area, 1);  
 }  
   
 static int  
 lsp_l2_regenerate (struct thread *thread)  
 {  
   struct isis_area *area;  
   
   area = THREAD_ARG (thread);  
   area->lsp_regenerate_pending[1] = 0;  
   
   return lsp_non_pseudo_regenerate (area, 2);  
 }  
   
 int  int
lsp_regenerate_schedule (struct isis_area *area)lsp_regenerate_schedule (struct isis_area *area, int level, int all_pseudo)
 {  {
   struct isis_lsp *lsp;    struct isis_lsp *lsp;
   u_char id[ISIS_SYS_ID_LEN + 2];    u_char id[ISIS_SYS_ID_LEN + 2];
   time_t now, diff;    time_t now, diff;
     long timeout;
     struct listnode *cnode;
     struct isis_circuit *circuit;
     int lvl;
   
     if (area == NULL)
       return ISIS_ERROR;
   
     sched_debug("ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs",
               area->area_tag, circuit_t2string(level), all_pseudo ? "" : "not ");
   
   memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);    memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
   LSP_PSEUDO_ID (id) = LSP_FRAGMENT (id) = 0;    LSP_PSEUDO_ID (id) = LSP_FRAGMENT (id) = 0;
   now = time (NULL);    now = time (NULL);
  /*
   * First level 1  for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++)
   */ 
  if (area->is_type & IS_LEVEL_1) 
     {      {
      lsp = lsp_search (id, area->lspdb[0]);      if (!((level & lvl) && (area->is_type & lvl)))
      if (!lsp || area->lsp_regenerate_pending[0])        continue;
        goto L2;
       sched_debug("ISIS (%s): Checking whether L%d needs to be scheduled",
                   area->area_tag, lvl);
 
       if (area->lsp_regenerate_pending[lvl - 1])
         {
           struct timeval remain = thread_timer_remain(area->t_lsp_refresh[lvl - 1]);
           sched_debug("ISIS (%s): Regeneration is already pending, nothing todo."
                       " (Due in %lld.%03lld seconds)", area->area_tag,
                       (long long)remain.tv_sec, (long long)remain.tv_usec / 1000);
           continue;
         }
 
       lsp = lsp_search (id, area->lspdb[lvl - 1]);
       if (!lsp)
         {
           sched_debug("ISIS (%s): We do not have any LSPs to regenerate, nothing todo.",
                       area->area_tag);
           continue;
         }
 
       /*        /*
        * Throttle avoidance         * Throttle avoidance
        */         */
         sched_debug("ISIS (%s): Will schedule regen timer. Last run was: %lld, Now is: %lld",
                     area->area_tag, (long long)lsp->last_generated, (long long)now);
         THREAD_TIMER_OFF (area->t_lsp_refresh[lvl - 1]);
       diff = now - lsp->last_generated;        diff = now - lsp->last_generated;
      if (diff < MIN_LSP_GEN_INTERVAL)      if (diff < area->lsp_gen_interval[lvl - 1])
        {        {
          area->lsp_regenerate_pending[0] = 1;          timeout = 1000 * (area->lsp_gen_interval[lvl - 1] - diff);
          area->t_lsp_l1_regenerate=thread_add_timer (master, lsp_l1_regenerate, area,          sched_debug("ISIS (%s): Scheduling in %ld ms to match configured lsp_gen_interval",
                            MIN_LSP_GEN_INTERVAL - diff);                      area->area_tag, timeout);
          goto L2;        }
        } 
       else        else
        lsp_non_pseudo_regenerate (area, 1);        {
           /*
            * lsps are not regenerated if lsp_regenerate function is called
            * directly. However if the lsp_regenerate call is queued for
            * later execution it works.
            */
           timeout = 100;
           sched_debug("ISIS (%s): Last generation was more than lsp_gen_interval ago."
                       " Scheduling for execution in %ld ms.", area->area_tag, timeout);
         }
 
       area->lsp_regenerate_pending[lvl - 1] = 1;
       if (lvl == IS_LEVEL_1)
         {
           THREAD_TIMER_MSEC_ON(master, area->t_lsp_refresh[lvl - 1],
                                lsp_l1_refresh, area, timeout);
         }
       else if (lvl == IS_LEVEL_2)
         {
           THREAD_TIMER_MSEC_ON(master, area->t_lsp_refresh[lvl - 1],
                                lsp_l2_refresh, area, timeout);
         }
     }      }
  /*
   * then 2  if (all_pseudo)
   */ 
L2: 
  if (area->is_type & IS_LEVEL_2) 
     {      {
      lsp = lsp_search (id, area->lspdb[1]);      for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit))
      if (!lsp || area->lsp_regenerate_pending[1])        lsp_regenerate_schedule_pseudo (circuit, level);
        return ISIS_OK; 
      /* 
       * Throttle avoidance 
       */ 
      diff = now - lsp->last_generated; 
      if (diff < MIN_LSP_GEN_INTERVAL) 
        { 
          area->lsp_regenerate_pending[1] = 1; 
          area->t_lsp_l2_regenerate=thread_add_timer (master, lsp_l2_regenerate, area, 
                            MIN_LSP_GEN_INTERVAL - diff); 
          return ISIS_OK; 
        } 
      else 
        lsp_non_pseudo_regenerate (area, 2); 
     }      }
   
   return ISIS_OK;    return ISIS_OK;
Line 1691  lsp_build_pseudo (struct isis_lsp *lsp, struct isis_ci Line 2085  lsp_build_pseudo (struct isis_lsp *lsp, struct isis_ci
   struct es_neigh *es_neigh;    struct es_neigh *es_neigh;
   struct list *adj_list;    struct list *adj_list;
   struct listnode *node;    struct listnode *node;
  struct isis_passwd *passwd;  struct isis_area *area = circuit->area;
   
  assert (circuit);  lsp_debug("ISIS (%s): Constructing pseudo LSP %s for interface %s level %d",
  assert (circuit->circ_type == CIRCUIT_T_BROADCAST);            area->area_tag, rawlspid_print(lsp->lsp_header->lsp_id),
             circuit->interface->name, level);
   
   if (!circuit->u.bc.is_dr[level - 1])  
     return;                     /* we are not DIS on this circuit */  
   
   lsp->level = level;    lsp->level = level;
  if (level == 1)  /* RFC3787  section 4 SHOULD not set overload bit in pseudo LSPs */
    lsp->lsp_header->lsp_bits |= IS_LEVEL_1;  lsp->lsp_header->lsp_bits = lsp_bits_generate (level, 0,
  else                                                 circuit->area->attached_bit);
    lsp->lsp_header->lsp_bits |= IS_LEVEL_2; 
   
   /*    /*
    * add self to IS neighbours      * add self to IS neighbours 
Line 1719  lsp_build_pseudo (struct isis_lsp *lsp, struct isis_ci Line 2110  lsp_build_pseudo (struct isis_lsp *lsp, struct isis_ci
   
       memcpy (&is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN);        memcpy (&is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN);
       listnode_add (lsp->tlv_data.is_neighs, is_neigh);        listnode_add (lsp->tlv_data.is_neighs, is_neigh);
         lsp_debug("ISIS (%s): Adding %s.%02x as old-style neighbor (self)",
                   area->area_tag, sysid_print(is_neigh->neigh_id),
                   LSP_PSEUDO_ID(is_neigh->neigh_id));
     }      }
   if (circuit->area->newmetric)    if (circuit->area->newmetric)
     {      {
Line 1731  lsp_build_pseudo (struct isis_lsp *lsp, struct isis_ci Line 2125  lsp_build_pseudo (struct isis_lsp *lsp, struct isis_ci
   
       memcpy (&te_is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN);        memcpy (&te_is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN);
       listnode_add (lsp->tlv_data.te_is_neighs, te_is_neigh);        listnode_add (lsp->tlv_data.te_is_neighs, te_is_neigh);
         lsp_debug("ISIS (%s): Adding %s.%02x as te-style neighbor (self)",
                   area->area_tag, sysid_print(te_is_neigh->neigh_id),
                   LSP_PSEUDO_ID(te_is_neigh->neigh_id));
     }      }
   
   adj_list = list_new ();    adj_list = list_new ();
Line 1738  lsp_build_pseudo (struct isis_lsp *lsp, struct isis_ci Line 2135  lsp_build_pseudo (struct isis_lsp *lsp, struct isis_ci
   
   for (ALL_LIST_ELEMENTS_RO (adj_list, node, adj))    for (ALL_LIST_ELEMENTS_RO (adj_list, node, adj))
     {      {
      if (adj->circuit_t & level)      if (adj->level & level)
         {          {
          if ((level == 1 && adj->sys_type == ISIS_SYSTYPE_L1_IS) ||          if ((level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_L1_IS) ||
              (level == 1 && adj->sys_type == ISIS_SYSTYPE_L2_IS &&              (level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_L2_IS &&
               adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||                adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
              (level == 2 && adj->sys_type == ISIS_SYSTYPE_L2_IS))              (level == IS_LEVEL_2 && adj->sys_type == ISIS_SYSTYPE_L2_IS))
             {              {
               /* an IS neighbour -> add it */                /* an IS neighbour -> add it */
               if (circuit->area->oldmetric)                if (circuit->area->oldmetric)
Line 1752  lsp_build_pseudo (struct isis_lsp *lsp, struct isis_ci Line 2149  lsp_build_pseudo (struct isis_lsp *lsp, struct isis_ci
   
                   memcpy (&is_neigh->neigh_id, adj->sysid, ISIS_SYS_ID_LEN);                    memcpy (&is_neigh->neigh_id, adj->sysid, ISIS_SYS_ID_LEN);
                   listnode_add (lsp->tlv_data.is_neighs, is_neigh);                    listnode_add (lsp->tlv_data.is_neighs, is_neigh);
                     lsp_debug("ISIS (%s): Adding %s.%02x as old-style neighbor (peer)",
                               area->area_tag, sysid_print(is_neigh->neigh_id),
                               LSP_PSEUDO_ID(is_neigh->neigh_id));
                 }                  }
               if (circuit->area->newmetric)                if (circuit->area->newmetric)
                 {                  {
Line 1759  lsp_build_pseudo (struct isis_lsp *lsp, struct isis_ci Line 2159  lsp_build_pseudo (struct isis_lsp *lsp, struct isis_ci
                                          sizeof (struct te_is_neigh));                                           sizeof (struct te_is_neigh));
                   memcpy (&te_is_neigh->neigh_id, adj->sysid, ISIS_SYS_ID_LEN);                    memcpy (&te_is_neigh->neigh_id, adj->sysid, ISIS_SYS_ID_LEN);
                   listnode_add (lsp->tlv_data.te_is_neighs, te_is_neigh);                    listnode_add (lsp->tlv_data.te_is_neighs, te_is_neigh);
                     lsp_debug("ISIS (%s): Adding %s.%02x as te-style neighbor (peer)",
                               area->area_tag, sysid_print(te_is_neigh->neigh_id),
                               LSP_PSEUDO_ID(te_is_neigh->neigh_id));
                 }                  }
             }              }
          else if (level == 1 && adj->sys_type == ISIS_SYSTYPE_ES)          else if (level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_ES)
             {              {
               /* an ES neigbour add it, if we are building level 1 LSP */                /* an ES neigbour add it, if we are building level 1 LSP */
               /* FIXME: the tlv-format is hard to use here */                /* FIXME: the tlv-format is hard to use here */
Line 1774  lsp_build_pseudo (struct isis_lsp *lsp, struct isis_ci Line 2177  lsp_build_pseudo (struct isis_lsp *lsp, struct isis_ci
                               
               memcpy (&es_neigh->first_es_neigh, adj->sysid, ISIS_SYS_ID_LEN);                memcpy (&es_neigh->first_es_neigh, adj->sysid, ISIS_SYS_ID_LEN);
               listnode_add (lsp->tlv_data.es_neighs, es_neigh);                listnode_add (lsp->tlv_data.es_neighs, es_neigh);
                 lsp_debug("ISIS (%s): Adding %s as ES neighbor (peer)",
                           area->area_tag, sysid_print(es_neigh->first_es_neigh));
             }              }
             else
               {
                 lsp_debug("ISIS (%s): Ignoring neighbor %s, level does not match",
                           area->area_tag, sysid_print(adj->sysid));
               }
         }          }
         else
           {
             lsp_debug("ISIS (%s): Ignoring neighbor %s, level does not intersect",
                       area->area_tag, sysid_print(adj->sysid));
           }
     }      }
     list_delete (adj_list);
   
     lsp_debug("ISIS (%s): Pseudo LSP construction is complete.", area->area_tag);
   
   /* Reset endp of stream to overwrite only TLV part of it. */    /* Reset endp of stream to overwrite only TLV part of it. */
   stream_reset (lsp->pdu);    stream_reset (lsp->pdu);
   stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);    stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
Line 1785  lsp_build_pseudo (struct isis_lsp *lsp, struct isis_ci Line 2203  lsp_build_pseudo (struct isis_lsp *lsp, struct isis_ci
   /*    /*
    * Add the authentication info if it's present     * Add the authentication info if it's present
    */     */
  (level == 1) ? (passwd = &circuit->area->area_passwd) :  lsp_auth_add (lsp);
    (passwd = &circuit->area->domain_passwd); 
  if (passwd->type) 
    { 
      memcpy (&lsp->tlv_data.auth_info, passwd, sizeof (struct isis_passwd)); 
      tlv_add_authinfo (passwd->type, passwd->len, passwd->passwd, lsp->pdu); 
    } 
   
   if (lsp->tlv_data.is_neighs && listcount (lsp->tlv_data.is_neighs) > 0)    if (lsp->tlv_data.is_neighs && listcount (lsp->tlv_data.is_neighs) > 0)
     tlv_add_is_neighs (lsp->tlv_data.is_neighs, lsp->pdu);      tlv_add_is_neighs (lsp->tlv_data.is_neighs, lsp->pdu);
Line 1803  lsp_build_pseudo (struct isis_lsp *lsp, struct isis_ci Line 2215  lsp_build_pseudo (struct isis_lsp *lsp, struct isis_ci
     tlv_add_is_neighs (lsp->tlv_data.es_neighs, lsp->pdu);      tlv_add_is_neighs (lsp->tlv_data.es_neighs, lsp->pdu);
   
   lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));    lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
   fletcher_checksum (STREAM_DATA (lsp->pdu) + 12,  
                    ntohs (lsp->lsp_header->pdu_len) - 12, 12);  
   
  list_delete (adj_list);  /* Recompute authentication and checksum information */
   lsp_auth_update (lsp);
   fletcher_checksum(STREAM_DATA (lsp->pdu) + 12,
                     ntohs (lsp->lsp_header->pdu_len) - 12, 12);
   
   return;    return;
 }  }
   
   int
   lsp_generate_pseudo (struct isis_circuit *circuit, int level)
   {
     dict_t *lspdb = circuit->area->lspdb[level - 1];
     struct isis_lsp *lsp;
     u_char lsp_id[ISIS_SYS_ID_LEN + 2];
     u_int16_t rem_lifetime, refresh_time;
   
     if ((circuit->is_type & level) != level ||
         (circuit->state != C_STATE_UP) ||
         (circuit->circ_type != CIRCUIT_T_BROADCAST) ||
         (circuit->u.bc.is_dr[level - 1] == 0))
       return ISIS_ERROR;
   
     memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
     LSP_FRAGMENT (lsp_id) = 0;
     LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id;
   
     /*
      * If for some reason have a pseudo LSP in the db already -> regenerate
      */
     if (lsp_search (lsp_id, lspdb))
       return lsp_regenerate_schedule_pseudo (circuit, level);
   
     rem_lifetime = lsp_rem_lifetime (circuit->area, level);
     /* RFC3787  section 4 SHOULD not set overload bit in pseudo LSPs */
     lsp = lsp_new (circuit->area, lsp_id, rem_lifetime, 1,
                    circuit->area->is_type | circuit->area->attached_bit,
                    0, level);
     lsp->area = circuit->area;
   
     lsp_build_pseudo (lsp, circuit, level);
   
     lsp->own_lsp = 1;
     lsp_insert (lsp, lspdb);
     lsp_set_all_srmflags (lsp);
   
     refresh_time = lsp_refresh_time (lsp, rem_lifetime);
     THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
     circuit->lsp_regenerate_pending[level - 1] = 0;
     if (level == IS_LEVEL_1)
       THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
                        lsp_l1_refresh_pseudo, circuit, refresh_time);
     else if (level == IS_LEVEL_2)
       THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
                        lsp_l2_refresh_pseudo, circuit, refresh_time);
   
     if (isis->debugs & DEBUG_UPDATE_PACKETS)
       {
         zlog_debug ("ISIS-Upd (%s): Building L%d Pseudo LSP %s, len %d, "
                     "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us",
                     circuit->area->area_tag, level,
                     rawlspid_print (lsp->lsp_header->lsp_id),
                     ntohl (lsp->lsp_header->pdu_len),
                     ntohl (lsp->lsp_header->seq_num),
                     ntohs (lsp->lsp_header->checksum),
                     ntohs (lsp->lsp_header->rem_lifetime),
                     refresh_time);
       }
   
     return ISIS_OK;
   }
   
 static int  static int
lsp_pseudo_regenerate (struct isis_circuit *circuit, int level)lsp_regenerate_pseudo (struct isis_circuit *circuit, int level)
 {  {
   dict_t *lspdb = circuit->area->lspdb[level - 1];    dict_t *lspdb = circuit->area->lspdb[level - 1];
   struct isis_lsp *lsp;    struct isis_lsp *lsp;
   u_char lsp_id[ISIS_SYS_ID_LEN + 2];    u_char lsp_id[ISIS_SYS_ID_LEN + 2];
     u_int16_t rem_lifetime, refresh_time;
   
     if ((circuit->is_type & level) != level ||
         (circuit->state != C_STATE_UP) ||
         (circuit->circ_type != CIRCUIT_T_BROADCAST) ||
         (circuit->u.bc.is_dr[level - 1] == 0))
       return ISIS_ERROR;
   
   memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN);    memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
   LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id;    LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id;
   LSP_FRAGMENT (lsp_id) = 0;    LSP_FRAGMENT (lsp_id) = 0;
Line 1826  lsp_pseudo_regenerate (struct isis_circuit *circuit, i Line 2309  lsp_pseudo_regenerate (struct isis_circuit *circuit, i
   
   if (!lsp)    if (!lsp)
     {      {
      zlog_err ("lsp_pseudo_regenerate(): no l%d LSP %s found!", level,      zlog_err ("lsp_regenerate_pseudo: no l%d LSP %s found!",
                rawlspid_print (lsp_id));                level, rawlspid_print (lsp_id));
       return ISIS_ERROR;        return ISIS_ERROR;
     }      }
   lsp_clear_data (lsp);    lsp_clear_data (lsp);
   
   lsp_build_pseudo (lsp, circuit, level);    lsp_build_pseudo (lsp, circuit, level);
   
  lsp->lsp_header->rem_lifetime =  /* RFC3787  section 4 SHOULD not set overload bit in pseudo LSPs */
    htons (isis_jitter (circuit->area->max_lsp_lifetime[level - 1],  lsp->lsp_header->lsp_bits = lsp_bits_generate (level, 0,
                        MAX_AGE_JITTER));                                                 circuit->area->attached_bit);
  rem_lifetime = lsp_rem_lifetime (circuit->area, level);
   lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
   lsp_inc_seqnum (lsp, 0);    lsp_inc_seqnum (lsp, 0);
     lsp->last_generated = time (NULL);
     lsp_set_all_srmflags (lsp);
   
     refresh_time = lsp_refresh_time (lsp, rem_lifetime);
     if (level == IS_LEVEL_1)
       THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
                        lsp_l1_refresh_pseudo, circuit, refresh_time);
     else if (level == IS_LEVEL_2)
       THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
                        lsp_l2_refresh_pseudo, circuit, refresh_time);
   
   if (isis->debugs & DEBUG_UPDATE_PACKETS)    if (isis->debugs & DEBUG_UPDATE_PACKETS)
     {      {
      zlog_debug ("ISIS-Upd (%s): refreshing pseudo LSP L%d %s",      zlog_debug ("ISIS-Upd (%s): Refreshing L%d Pseudo LSP %s, len %d, "
                  circuit->area->area_tag, level,                  "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us",
                  rawlspid_print (lsp->lsp_header->lsp_id));                  circuit->area->area_tag, level,
                   rawlspid_print (lsp->lsp_header->lsp_id),
                   ntohl (lsp->lsp_header->pdu_len),
                   ntohl (lsp->lsp_header->seq_num),
                   ntohs (lsp->lsp_header->checksum),
                   ntohs (lsp->lsp_header->rem_lifetime),
                   refresh_time);
     }      }
   
   lsp->last_generated = time (NULL);  
   ISIS_FLAGS_SET_ALL (lsp->SRMflags);  
   
   return ISIS_OK;    return ISIS_OK;
 }  }
   
int/*
  * Something has changed or periodic refresh -> regenerate pseudo LSP
  */
 static int
 lsp_l1_refresh_pseudo (struct thread *thread)  lsp_l1_refresh_pseudo (struct thread *thread)
 {  {
   struct isis_circuit *circuit;    struct isis_circuit *circuit;
  int retval;  u_char id[ISIS_SYS_ID_LEN + 2];
  unsigned long ref_time; 
   
   circuit = THREAD_ARG (thread);    circuit = THREAD_ARG (thread);
   
   if (!circuit->u.bc.is_dr[0])  
     return ISIS_ERROR;          /* FIXME: purge and such */  
   
   circuit->u.bc.t_refresh_pseudo_lsp[0] = NULL;    circuit->u.bc.t_refresh_pseudo_lsp[0] = NULL;
     circuit->lsp_regenerate_pending[0] = 0;
   
  retval = lsp_pseudo_regenerate (circuit, 1);  if ((circuit->u.bc.is_dr[0] == 0) ||
       (circuit->is_type & IS_LEVEL_1) == 0)
     {
       memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
       LSP_PSEUDO_ID (id) = circuit->circuit_id;
       LSP_FRAGMENT (id) = 0;
       lsp_purge_pseudo (id, circuit, IS_LEVEL_1);
       return ISIS_ERROR;
     }
   
  ref_time = circuit->area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ?  return lsp_regenerate_pseudo (circuit, IS_LEVEL_1);
    MAX_LSP_GEN_INTERVAL : circuit->area->lsp_refresh[0]; 
 
  THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[0], 
                   lsp_l1_refresh_pseudo, circuit, 
                   isis_jitter (ref_time, MAX_AGE_JITTER)); 
 
  return retval; 
 }  }
   
intstatic int
lsp_l1_pseudo_generate (struct isis_circuit *circuit) 
{ 
  struct isis_lsp *lsp; 
  u_char id[ISIS_SYS_ID_LEN + 2]; 
  unsigned long ref_time; 
 
  memcpy (id, isis->sysid, ISIS_SYS_ID_LEN); 
  LSP_FRAGMENT (id) = 0; 
  LSP_PSEUDO_ID (id) = circuit->circuit_id; 
 
  /* 
   * If for some reason have a pseudo LSP in the db already -> regenerate 
   */ 
  if (lsp_search (id, circuit->area->lspdb[0])) 
    return lsp_pseudo_regenerate (circuit, 1); 
  lsp = lsp_new (id, circuit->area->max_lsp_lifetime[0], 
                 1, circuit->area->is_type, 0, 1); 
 
  lsp_build_pseudo (lsp, circuit, 1); 
 
  lsp->own_lsp = 1; 
  lsp_insert (lsp, circuit->area->lspdb[0]); 
  ISIS_FLAGS_SET_ALL (lsp->SRMflags); 
 
  ref_time = circuit->area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ? 
    MAX_LSP_GEN_INTERVAL : circuit->area->lsp_refresh[0]; 
 
  THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[0], 
                   lsp_l1_refresh_pseudo, circuit, 
                   isis_jitter (ref_time, MAX_AGE_JITTER)); 
 
  return lsp_regenerate_schedule (circuit->area); 
} 
 
int 
 lsp_l2_refresh_pseudo (struct thread *thread)  lsp_l2_refresh_pseudo (struct thread *thread)
 {  {
   struct isis_circuit *circuit;    struct isis_circuit *circuit;
  int retval;  u_char id[ISIS_SYS_ID_LEN + 2];
  unsigned long ref_time;
   circuit = THREAD_ARG (thread);    circuit = THREAD_ARG (thread);
   
   if (!circuit->u.bc.is_dr[1])  
     return ISIS_ERROR;          /* FIXME: purge and such */  
   
   circuit->u.bc.t_refresh_pseudo_lsp[1] = NULL;    circuit->u.bc.t_refresh_pseudo_lsp[1] = NULL;
     circuit->lsp_regenerate_pending[1] = 0;
   
  retval = lsp_pseudo_regenerate (circuit, 2);  if ((circuit->u.bc.is_dr[1] == 0) ||
       (circuit->is_type & IS_LEVEL_2) == 0)
     {
       memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
       LSP_PSEUDO_ID (id) = circuit->circuit_id;
       LSP_FRAGMENT (id) = 0;
       lsp_purge_pseudo (id, circuit, IS_LEVEL_2);
       return ISIS_ERROR;
     }
   
  ref_time = circuit->area->lsp_refresh[1] > MAX_LSP_GEN_INTERVAL ?  return lsp_regenerate_pseudo (circuit, IS_LEVEL_2);
    MAX_LSP_GEN_INTERVAL : circuit->area->lsp_refresh[1]; 
 
  THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[1], 
                   lsp_l2_refresh_pseudo, circuit, 
                   isis_jitter (ref_time, MAX_AGE_JITTER)); 
 
  return retval; 
 }  }
   
 int  int
lsp_l2_pseudo_generate (struct isis_circuit *circuit)lsp_regenerate_schedule_pseudo (struct isis_circuit *circuit, int level)
 {  {
   struct isis_lsp *lsp;    struct isis_lsp *lsp;
  u_char id[ISIS_SYS_ID_LEN + 2];  u_char lsp_id[ISIS_SYS_ID_LEN + 2];
  unsigned long ref_time;  time_t now, diff;
   long timeout;
   int lvl;
   struct isis_area *area = circuit->area;
   
  memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);  if (circuit == NULL ||
  LSP_FRAGMENT (id) = 0;      circuit->circ_type != CIRCUIT_T_BROADCAST ||
  LSP_PSEUDO_ID (id) = circuit->circuit_id;      circuit->state != C_STATE_UP)
     return ISIS_OK;
   
  if (lsp_search (id, circuit->area->lspdb[1]))  sched_debug("ISIS (%s): Scheduling regeneration of %s pseudo LSP for interface %s",
    return lsp_pseudo_regenerate (circuit, 2);              area->area_tag, circuit_t2string(level), circuit->interface->name);
   
  lsp = lsp_new (id, circuit->area->max_lsp_lifetime[1],  memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
                 1, circuit->area->is_type, 0, 2);  LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id;
   LSP_FRAGMENT (lsp_id) = 0;
   now = time (NULL);
   
  lsp_build_pseudo (lsp, circuit, 2);  for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++)
     {
       sched_debug("ISIS (%s): Checking whether L%d pseudo LSP needs to be scheduled",
                   area->area_tag, lvl);
   
  ref_time = circuit->area->lsp_refresh[1] > MAX_LSP_GEN_INTERVAL ?      if (!((level & lvl) && (circuit->is_type & lvl)))
    MAX_LSP_GEN_INTERVAL : circuit->area->lsp_refresh[1];        {
           sched_debug("ISIS (%s): Level is not active on circuit",
                       area->area_tag);
           continue;
         }
   
         if (circuit->u.bc.is_dr[lvl - 1] == 0)
           {
             sched_debug("ISIS (%s): This IS is not DR, nothing to do.",
                         area->area_tag);
             continue;
           }
   
  lsp->own_lsp = 1;      if (circuit->lsp_regenerate_pending[lvl - 1])
  lsp_insert (lsp, circuit->area->lspdb[1]);        {
  ISIS_FLAGS_SET_ALL (lsp->SRMflags);          struct timeval remain =
                   thread_timer_remain(circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
           sched_debug("ISIS (%s): Regenerate is already pending, nothing todo."
                       " (Due in %lld.%03lld seconds)", area->area_tag,
                       (long long)remain.tv_sec, (long long)remain.tv_usec/1000);
           continue;
         }
   
  THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[1],      lsp = lsp_search (lsp_id, circuit->area->lspdb[lvl - 1]);
                   lsp_l2_refresh_pseudo, circuit,      if (!lsp)
                   isis_jitter (ref_time, MAX_AGE_JITTER));        {
           sched_debug("ISIS (%s): Pseudonode LSP does not exist yet, nothing to regenerate.",
                       area->area_tag);
           continue;
         }
   
  return lsp_regenerate_schedule (circuit->area);      /*
        * Throttle avoidance
        */
       sched_debug("ISIS (%s): Will schedule PSN regen timer. Last run was: %lld, Now is: %lld",
                   area->area_tag, (long long)lsp->last_generated, (long long) now);
       THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
       diff = now - lsp->last_generated;
       if (diff < circuit->area->lsp_gen_interval[lvl - 1])
         {
           timeout = 1000 * (circuit->area->lsp_gen_interval[lvl - 1] - diff);
           sched_debug("ISIS (%s): Sechduling in %ld ms to match configured lsp_gen_interval",
                       area->area_tag, timeout);
         }
       else
         {
           timeout = 100;
           sched_debug("ISIS (%s): Last generation was more than lsp_gen_interval ago."
                       " Scheduling for execution in %ld ms.", area->area_tag, timeout);
         }
 
       circuit->lsp_regenerate_pending[lvl - 1] = 1;
 
       if (lvl == IS_LEVEL_1)
         {
           THREAD_TIMER_MSEC_ON(master,
                                circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1],
                                lsp_l1_refresh_pseudo, circuit, timeout);
         }
       else if (lvl == IS_LEVEL_2)
         {
           THREAD_TIMER_MSEC_ON(master,
                                circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1],
                                lsp_l2_refresh_pseudo, circuit, timeout);
         }
     }
 
   return ISIS_OK;
 }  }
   
 /*  /*
Line 1988  lsp_tick (struct thread *thread) Line 2515  lsp_tick (struct thread *thread)
   struct listnode *lspnode, *cnode;    struct listnode *lspnode, *cnode;
   dnode_t *dnode, *dnode_next;    dnode_t *dnode, *dnode_next;
   int level;    int level;
     u_int16_t rem_lifetime;
   
   lsp_list = list_new ();    lsp_list = list_new ();
   
Line 2003  lsp_tick (struct thread *thread) Line 2531  lsp_tick (struct thread *thread)
   for (level = 0; level < ISIS_LEVELS; level++)    for (level = 0; level < ISIS_LEVELS; level++)
     {      {
       if (area->lspdb[level] && dict_count (area->lspdb[level]) > 0)        if (area->lspdb[level] && dict_count (area->lspdb[level]) > 0)
        {        {
          dnode = dict_first (area->lspdb[level]);          for (dnode = dict_first (area->lspdb[level]);
          while (dnode != NULL)               dnode != NULL; dnode = dnode_next)
            {            {
              dnode_next = dict_next (area->lspdb[level], dnode);              dnode_next = dict_next (area->lspdb[level], dnode);
              lsp = dnode_get (dnode);              lsp = dnode_get (dnode);
              lsp_set_time (lsp); 
              if (lsp->age_out == 0) 
                { 
   
                  zlog_debug ("ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out",              /*
                              area->area_tag,               * The lsp rem_lifetime is kept at 0 for MaxAge or
                              lsp->level,               * ZeroAgeLifetime depending on explicit purge or
                              rawlspid_print (lsp->lsp_header->lsp_id),               * natural age out. So schedule spf only once when
                              ntohl (lsp->lsp_header->seq_num));               * the first time rem_lifetime becomes 0.
                */
               rem_lifetime = ntohs(lsp->lsp_header->rem_lifetime);
               lsp_set_time (lsp);
 
               /*
                * Schedule may run spf which should be done only after
                * the lsp rem_lifetime becomes 0 for the first time.
                * ISO 10589 - 7.3.16.4 first paragraph.
                */
               if (rem_lifetime == 1 && lsp->lsp_header->seq_num != 0)
                 {
                   /* 7.3.16.4 a) set SRM flags on all */
                   lsp_set_all_srmflags (lsp);
                   /* 7.3.16.4 b) retain only the header FIXME  */
                   /* 7.3.16.4 c) record the time to purge FIXME */
                   /* run/schedule spf */
                   /* isis_spf_schedule is called inside lsp_destroy() below;
                    * so it is not needed here. */
                   /* isis_spf_schedule (lsp->area, lsp->level); */
                 }
 
               if (lsp->age_out == 0)
                 {
                   zlog_debug ("ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out",
                               area->area_tag,
                               lsp->level,
                               rawlspid_print (lsp->lsp_header->lsp_id),
                               ntohl (lsp->lsp_header->seq_num));
 #ifdef TOPOLOGY_GENERATE  #ifdef TOPOLOGY_GENERATE
                  if (lsp->from_topology)                  if (lsp->from_topology)
                    THREAD_TIMER_OFF (lsp->t_lsp_top_ref);                    THREAD_TIMER_OFF (lsp->t_lsp_top_ref);
 #endif /* TOPOLOGY_GENERATE */  #endif /* TOPOLOGY_GENERATE */
                  lsp_destroy (lsp);                  lsp_destroy (lsp);
                  dict_delete (area->lspdb[level], dnode);                  lsp = NULL;
                }                  dict_delete_free (area->lspdb[level], dnode);
              else if (flags_any_set (lsp->SRMflags))                }
                listnode_add (lsp_list, lsp);              else if (flags_any_set (lsp->SRMflags))
              dnode = dnode_next;                listnode_add (lsp_list, lsp);
            }            }
   
          /*          /*
           * Send LSPs on circuits indicated by the SRMflags           * Send LSPs on circuits indicated by the SRMflags
           */           */
          if (listcount (lsp_list) > 0)          if (listcount (lsp_list) > 0)
            {            {
               for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit))                for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit))
                {                {
                   int diff = time (NULL) - circuit->lsp_queue_last_cleared;
                   if (circuit->lsp_queue == NULL ||
                       diff < MIN_LSP_TRANS_INTERVAL)
                     continue;
                   for (ALL_LIST_ELEMENTS_RO (lsp_list, lspnode, lsp))                    for (ALL_LIST_ELEMENTS_RO (lsp_list, lspnode, lsp))
                    {                    {
                      if (ISIS_CHECK_FLAG (lsp->SRMflags, circuit))                      if (circuit->upadjcount[lsp->level - 1] &&
                        {                          ISIS_CHECK_FLAG (lsp->SRMflags, circuit))
                          /* FIXME: if same or elder lsp is already in lsp                        {
                           * queue */                          /* Add the lsp only if it is not already in lsp
                          listnode_add (circuit->lsp_queue, lsp);                           * queue */
                          thread_add_event (master, send_lsp, circuit, 0);                          if (! listnode_lookup (circuit->lsp_queue, lsp))
                        }                            {
                    }                              listnode_add (circuit->lsp_queue, lsp);
                }                              thread_add_event (master, send_lsp, circuit, 0);
            }                            }
          list_delete_all_node (lsp_list);                        }
        }                    }
                 }
               list_delete_all_node (lsp_list);
             }
         }
     }      }
   
   list_delete (lsp_list);    list_delete (lsp_list);
Line 2059  lsp_tick (struct thread *thread) Line 2620  lsp_tick (struct thread *thread)
 }  }
   
 void  void
lsp_purge_dr (u_char * id, struct isis_circuit *circuit, int level)lsp_purge_pseudo (u_char * id, struct isis_circuit *circuit, int level)
 {  {
   struct isis_lsp *lsp;    struct isis_lsp *lsp;
     u_int16_t seq_num;
     u_int8_t lsp_bits;
   
   lsp = lsp_search (id, circuit->area->lspdb[level - 1]);    lsp = lsp_search (id, circuit->area->lspdb[level - 1]);
     if (!lsp)
       return;
   
  if (lsp && lsp->purged == 0)  /* store old values */
    {  seq_num = lsp->lsp_header->seq_num;
      lsp->lsp_header->rem_lifetime = htons (0);  lsp_bits = lsp->lsp_header->lsp_bits;
      lsp->lsp_header->pdu_len = 
        htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); 
      lsp->purged = 0; 
      fletcher_checksum (STREAM_DATA (lsp->pdu) + 12, 
                       ntohs (lsp->lsp_header->pdu_len) - 12, 12); 
      ISIS_FLAGS_SET_ALL (lsp->SRMflags); 
    } 
   
     /* reset stream */
     lsp_clear_data (lsp);
     stream_reset (lsp->pdu);
   
     /* update header */
     lsp->lsp_header->pdu_len = htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
     memcpy (lsp->lsp_header->lsp_id, id, ISIS_SYS_ID_LEN + 2);
     lsp->lsp_header->checksum = 0;
     lsp->lsp_header->seq_num = seq_num;
     lsp->lsp_header->rem_lifetime = 0;
     lsp->lsp_header->lsp_bits = lsp_bits;
     lsp->level = level;
     lsp->age_out = lsp->area->max_lsp_lifetime[level-1];
     stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
   
     /*
      * Add and update the authentication info if its present
      */
     lsp_auth_add (lsp);
     lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
     lsp_auth_update (lsp);
     fletcher_checksum(STREAM_DATA (lsp->pdu) + 12,
                       ntohs (lsp->lsp_header->pdu_len) - 12, 12);
   
     lsp_set_all_srmflags (lsp);
   
   return;    return;
 }  }
   
Line 2084  lsp_purge_dr (u_char * id, struct isis_circuit *circui Line 2668  lsp_purge_dr (u_char * id, struct isis_circuit *circui
  * -> Do as in 7.3.16.4   * -> Do as in 7.3.16.4
  */   */
 void  void
lsp_purge_non_exist (struct isis_link_state_hdr *lsp_hdr,lsp_purge_non_exist (int level,
                      struct isis_link_state_hdr *lsp_hdr,
                      struct isis_area *area)                       struct isis_area *area)
 {  {
   struct isis_lsp *lsp;    struct isis_lsp *lsp;
Line 2092  lsp_purge_non_exist (struct isis_link_state_hdr *lsp_h Line 2677  lsp_purge_non_exist (struct isis_link_state_hdr *lsp_h
   /*    /*
    * We need to create the LSP to be purged      * We need to create the LSP to be purged 
    */     */
   zlog_debug ("LSP PURGE NON EXIST");  
   lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp));    lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp));
  /*FIXME: BUG BUG BUG! the lsp doesn't exist here! */  lsp->area = area;
  /*did smt here, maybe good probably not */  lsp->level = level;
  lsp->level = ((lsp_hdr->lsp_bits & LSPBIT_IST) == IS_LEVEL_1) ? 1 : 2;  lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu);
  lsp->pdu = stream_new (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); 
   lsp->isis_header = (struct isis_fixed_hdr *) STREAM_DATA (lsp->pdu);    lsp->isis_header = (struct isis_fixed_hdr *) STREAM_DATA (lsp->pdu);
  fill_fixed_hdr (lsp->isis_header, (lsp->level == 1) ? L1_LINK_STATE  fill_fixed_hdr (lsp->isis_header, (lsp->level == IS_LEVEL_1) ? L1_LINK_STATE
                   : L2_LINK_STATE);                    : L2_LINK_STATE);
   lsp->lsp_header = (struct isis_link_state_hdr *) (STREAM_DATA (lsp->pdu) +    lsp->lsp_header = (struct isis_link_state_hdr *) (STREAM_DATA (lsp->pdu) +
                                                     ISIS_FIXED_HDR_LEN);                                                      ISIS_FIXED_HDR_LEN);
   memcpy (lsp->lsp_header, lsp_hdr, ISIS_LSP_HDR_LEN);    memcpy (lsp->lsp_header, lsp_hdr, ISIS_LSP_HDR_LEN);
     stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
   
   /*    /*
    * Retain only LSP header  
    */  
   lsp->lsp_header->pdu_len = htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);  
   /*  
    * Set the remaining lifetime to 0     * Set the remaining lifetime to 0
    */     */
   lsp->lsp_header->rem_lifetime = 0;    lsp->lsp_header->rem_lifetime = 0;
   
   /*    /*
      * Add and update the authentication info if its present
      */
     lsp_auth_add (lsp);
     lsp_auth_update (lsp);
   
     /*
      * Update the PDU length to header plus any authentication TLV.
      */
     lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
   
     /*
    * Put the lsp into LSPdb     * Put the lsp into LSPdb
    */     */
   lsp_insert (lsp, area->lspdb[lsp->level - 1]);    lsp_insert (lsp, area->lspdb[lsp->level - 1]);
Line 2121  lsp_purge_non_exist (struct isis_link_state_hdr *lsp_h Line 2713  lsp_purge_non_exist (struct isis_link_state_hdr *lsp_h
   /*    /*
    * Send in to whole area     * Send in to whole area
    */     */
  ISIS_FLAGS_SET_ALL (lsp->SRMflags);  lsp_set_all_srmflags (lsp);
   
   return;    return;
 }  }
   
   void lsp_set_all_srmflags (struct isis_lsp *lsp)
   {
     struct listnode *node;
     struct isis_circuit *circuit;
   
     assert (lsp);
   
     ISIS_FLAGS_CLEAR_ALL(lsp->SRMflags);
   
     if (lsp->area)
       {
         struct list *circuit_list = lsp->area->circuit_list;
         for (ALL_LIST_ELEMENTS_RO (circuit_list, node, circuit))
           {
             ISIS_SET_FLAG(lsp->SRMflags, circuit);
           }
       }
   }
   
 #ifdef TOPOLOGY_GENERATE  #ifdef TOPOLOGY_GENERATE
 static int  static int
 top_lsp_refresh (struct thread *thread)  top_lsp_refresh (struct thread *thread)
 {  {
   struct isis_lsp *lsp;    struct isis_lsp *lsp;
  unsigned long ref_time;  u_int16_t rem_lifetime;
   
   lsp = THREAD_ARG (thread);    lsp = THREAD_ARG (thread);
   assert (lsp);    assert (lsp);
Line 2140  top_lsp_refresh (struct thread *thread) Line 2751  top_lsp_refresh (struct thread *thread)
   
   lsp_seqnum_update (lsp);    lsp_seqnum_update (lsp);
   
  ISIS_FLAGS_SET_ALL (lsp->SRMflags);  lsp_set_all_srmflags (lsp);
   if (isis->debugs & DEBUG_UPDATE_PACKETS)    if (isis->debugs & DEBUG_UPDATE_PACKETS)
     {      {
       zlog_debug ("ISIS-Upd (): refreshing Topology L1 %s",        zlog_debug ("ISIS-Upd (): refreshing Topology L1 %s",
Line 2150  top_lsp_refresh (struct thread *thread) Line 2761  top_lsp_refresh (struct thread *thread)
   isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname,    isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname,
                      IS_LEVEL_1);                       IS_LEVEL_1);
   
  lsp->lsp_header->rem_lifetime =  lsp->lsp_header->lsp_bits = lsp_bits_generate (lsp->level,
    htons (isis_jitter (lsp->area->max_lsp_lifetime[0], MAX_AGE_JITTER));                                                 lsp->area->overload_bit,
                                                  lsp->area->attached_bit);
   rem_lifetime = lsp_rem_lifetime (lsp->area, IS_LEVEL_1);
   lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
   
  ref_time = lsp->area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ?  /* refresh_time = lsp_refresh_time (lsp, rem_lifetime); */
    MAX_LSP_GEN_INTERVAL : lsp->area->lsp_refresh[0]; 
 
   THREAD_TIMER_ON (master, lsp->t_lsp_top_ref, top_lsp_refresh, lsp,    THREAD_TIMER_ON (master, lsp->t_lsp_top_ref, top_lsp_refresh, lsp,
                   isis_jitter (ref_time, MAX_LSP_GEN_JITTER));                   lsp->area->lsp_refresh[0]);
   
   return ISIS_OK;    return ISIS_OK;
 }  }
Line 2170  generate_topology_lsps (struct isis_area *area) Line 2782  generate_topology_lsps (struct isis_area *area)
   struct arc *arc;    struct arc *arc;
   u_char lspid[ISIS_SYS_ID_LEN + 2];    u_char lspid[ISIS_SYS_ID_LEN + 2];
   struct isis_lsp *lsp;    struct isis_lsp *lsp;
  unsigned long ref_time;  u_int16_t rem_lifetime, refresh_time;
   
   /* first we find the maximal node */    /* first we find the maximal node */
   for (ALL_LIST_ELEMENTS_RO (area->topology, node, arc))    for (ALL_LIST_ELEMENTS_RO (area->topology, node, arc))
  {    {
    if (arc->from_node > max)      if (arc->from_node > max)
      max = arc->from_node;        max = arc->from_node;
    if (arc->to_node > max)      if (arc->to_node > max)
      max = arc->to_node;        max = arc->to_node;
  }    }
   
   for (i = 1; i < (max + 1); i++)    for (i = 1; i < (max + 1); i++)
     {      {
Line 2189  generate_topology_lsps (struct isis_area *area) Line 2801  generate_topology_lsps (struct isis_area *area)
       lspid[ISIS_SYS_ID_LEN - 1] = (i & 0xFF);        lspid[ISIS_SYS_ID_LEN - 1] = (i & 0xFF);
       lspid[ISIS_SYS_ID_LEN - 2] = ((i >> 8) & 0xFF);        lspid[ISIS_SYS_ID_LEN - 2] = ((i >> 8) & 0xFF);
   
      lsp = lsp_new (lspid, isis_jitter (area->max_lsp_lifetime[0],      rem_lifetime = lsp_rem_lifetime (area, IS_LEVEL_1);
                     MAX_AGE_JITTER), 1, IS_LEVEL_1, 0, 1);      lsp = lsp_new (area, lspid, rem_lifetime, 1,
                      IS_LEVEL_1 | area->overload_bit | area->attached_bit,
                      0, 1);
       if (!lsp)        if (!lsp)
         return;          return;
       lsp->from_topology = 1;        lsp->from_topology = 1;
       lsp->area = area;  
   
       /* Creating LSP data based on topology info. */        /* Creating LSP data based on topology info. */
       build_topology_lsp_data (lsp, area, i);        build_topology_lsp_data (lsp, area, i);
Line 2203  generate_topology_lsps (struct isis_area *area) Line 2816  generate_topology_lsps (struct isis_area *area)
       /* Take care of inserting dynamic hostname into cache. */        /* Take care of inserting dynamic hostname into cache. */
       isis_dynhn_insert (lspid, lsp->tlv_data.hostname, IS_LEVEL_1);        isis_dynhn_insert (lspid, lsp->tlv_data.hostname, IS_LEVEL_1);
   
      ref_time = area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ?      refresh_time = lsp_refresh_time (lsp, rem_lifetime);
        MAX_LSP_GEN_INTERVAL : area->lsp_refresh[0]; 
 
       THREAD_TIMER_ON (master, lsp->t_lsp_top_ref, top_lsp_refresh, lsp,        THREAD_TIMER_ON (master, lsp->t_lsp_top_ref, top_lsp_refresh, lsp,
                       isis_jitter (ref_time, MAX_LSP_GEN_JITTER));                       refresh_time);
      ISIS_FLAGS_SET_ALL (lsp->SRMflags);      lsp_set_all_srmflags (lsp);
       lsp_insert (lsp, area->lspdb[0]);        lsp_insert (lsp, area->lspdb[0]);
     }      }
 }  }
Line 2325  build_topology_lsp_data (struct isis_lsp *lsp, struct  Line 2936  build_topology_lsp_data (struct isis_lsp *lsp, struct 
   
       if (area->newmetric)        if (area->newmetric)
         {          {
           uint32_t metric;  
   
           if (tlv_data.te_is_neighs == NULL)            if (tlv_data.te_is_neighs == NULL)
             {              {
               tlv_data.te_is_neighs = list_new ();                tlv_data.te_is_neighs = list_new ();
Line 2337  build_topology_lsp_data (struct isis_lsp *lsp, struct  Line 2946  build_topology_lsp_data (struct isis_lsp *lsp, struct 
                   ISIS_SYS_ID_LEN);                    ISIS_SYS_ID_LEN);
           te_is_neigh->neigh_id[ISIS_SYS_ID_LEN - 1] = (to_lsp & 0xFF);            te_is_neigh->neigh_id[ISIS_SYS_ID_LEN - 1] = (to_lsp & 0xFF);
           te_is_neigh->neigh_id[ISIS_SYS_ID_LEN - 2] = ((to_lsp >> 8) & 0xFF);            te_is_neigh->neigh_id[ISIS_SYS_ID_LEN - 2] = ((to_lsp >> 8) & 0xFF);
          metric = ((htonl(arc->distance) >> 8) & 0xffffff);          SET_TE_METRIC(te_is_neigh, arc->distance);
          memcpy (te_is_neigh->te_metric, &metric, 3); 
           listnode_add (tlv_data.te_is_neighs, te_is_neigh);            listnode_add (tlv_data.te_is_neighs, te_is_neigh);
         }          }
     }      }

Removed from v.1.1  
changed lines
  Added in v.1.1.1.4


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