Diff for /embedaddon/quagga/isisd/isis_lsp.c between versions 1.1.1.1 and 1.1.1.2

version 1.1.1.1, 2012/02/21 17:26:11 version 1.1.1.2, 2012/10/09 09:22:28
Line 34 Line 34
 #include "hash.h"  #include "hash.h"
 #include "if.h"  #include "if.h"
 #include "checksum.h"  #include "checksum.h"
   #include "md5.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 47
 #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 55
 #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 90  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 109  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 256  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 273  lsp_compare (char *areatag, struct isis_lsp *lsp, u_in Line 275  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 290  lsp_compare (char *areatag, struct isis_lsp *lsp, u_in Line 292  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 305  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,
               (caddr_t) &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 398  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 441  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 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  return lsp_bits;
                       - ISIS_LSP_HDR_LEN, &expected, &found, &tlvs); 
  if (retval || !(found & TLVFLAG_AUTH_INFO)) 
    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 483  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 500  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 484  lsp_new (u_char * lsp_id, u_int16_t rem_lifetime, u_in Line 585  lsp_new (u_char * lsp_id, u_int16_t rem_lifetime, u_in
       zlog_warn ("lsp_new(): out of memory");        zlog_warn ("lsp_new(): out of memory");
       return NULL;        return NULL;
     }      }
#ifdef LSP_MEMORY_PREASSIGN  /* FIXME: Should be minimal mtu? */
  lsp->pdu = stream_new (1514);    /*Should be minimal mtu? yup... */  lsp->pdu = stream_new (1500);
#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 594  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 611  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 624  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 667  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 685  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 706  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 719  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 738  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 759  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 795  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 841  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 861  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 874  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 922  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 936  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 838  lsp_print_detail (dnode_t * node, struct vty *vty, cha Line 952  lsp_print_detail (dnode_t * node, struct vty *vty, cha
       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 966  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 977  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 996  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 1003  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 1013  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 1023  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 1042  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 1079  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 */
     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;
   
     assert (area->lsp_gen_interval[level - 1] < refresh_time);
   
     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 1126  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 (frag_id, ntohs(lsp0->lsp_header->rem_lifetime), 0,
                 0, level);                 lsp_bits_generate (level, area->overload_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;
   /*  
    * Copy the authinfo from zero 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;
 }  }
   
Line 1005  lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, Line 1149  lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0,
  * 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 1022  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis Line 1166  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis
 #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;
   
   /*    /*
      * 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 1196  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 1055  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis Line 1221  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis
             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)
     {      {
Line 1065  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis Line 1233  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis
       memcpy (lsp->tlv_data.hostname->name, unix_hostname (),        memcpy (lsp->tlv_data.hostname->name, unix_hostname (),
               strlen (unix_hostname ()));                strlen (unix_hostname ()));
       lsp->tlv_data.hostname->namelen = strlen (unix_hostname ());        lsp->tlv_data.hostname->namelen = strlen (unix_hostname ());
         tlv_add_dynamic_hostname (lsp->tlv_data.hostname, lsp->pdu);
     }      }
   
   /*  
    * Building the zero lsp  
    */  
   
   /* 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  
    */  
   (level == 1) ? (passwd = &area->area_passwd) :  
     (passwd = &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.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)
     {      {
       if (lsp->tlv_data.ipv4_addrs == NULL)        if (lsp->tlv_data.ipv4_addrs == NULL)
         {          {
Line 1106  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis Line 1248  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 1116  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis Line 1258  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis
         {          {
           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);
         }          }
     }      }
   
Line 1126  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis Line 1269  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis
 #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 1177  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis Line 1320  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis
                                             (ipv4->prefix.s_addr));                                              (ipv4->prefix.s_addr));
                   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 1205  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis Line 1347  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis
                 }                  }
             }              }
         }          }
   
 #ifdef HAVE_IPV6  #ifdef HAVE_IPV6
       /*        /*
        * Add IPv6 reachability of this circuit         * Add IPv6 reachability of this circuit
Line 1243  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis Line 1386  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 1396  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);
                   else
                     listnode_add (tlv_data.is_neighs, is_neigh);
                 }                  }
               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 1418  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);
                   else
                     listnode_add (tlv_data.te_is_neighs, te_is_neigh);
                 }                  }
             }              }
           break;            break;
Line 1320  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis Line 1465  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);
                 }                  }
             }              }
           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");
         }          }
Line 1352  lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis Line 1490  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);
     }      }
   
   /* 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 1500  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 1546  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 (lspid, rem_lifetime, seq_num,
                       area->is_type | area->overload_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);
   lsp_set_all_srmflags (newlsp);
 
   refresh_time = lsp_refresh_time (newlsp, rem_lifetime);
   THREAD_TIMER_OFF (area->t_lsp_refresh[level - 1]);
   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);
     }      }
   
   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 = area->lspdb[level - 1];
   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;
   
   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 1647  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],  rem_lifetime = lsp_rem_lifetime (area, level);
                                          MAX_AGE_JITTER));  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,      /* Set the lifetime values of all the fragments to the same value,
                  level,       * so that no fragment expires before the lsp is refreshed.
                  rawlspid_print (lsp->lsp_header->lsp_id),       */
                  ntohl (lsp->lsp_header->seq_num),      frag->lsp_header->rem_lifetime = htons (rem_lifetime);
                  ntohs (lsp->lsp_header->checksum),      lsp_set_all_srmflags (frag);
                  ntohs (lsp->lsp_header->rem_lifetime)); 
     }      }
   
  lsp->last_generated = time (NULL);  refresh_time = lsp_refresh_time (lsp, rem_lifetime);
  area->lsp_regenerate_pending[level - 1] = 0;  if (level == IS_LEVEL_1)
  ISIS_FLAGS_SET_ALL (lsp->SRMflags);    THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
  for (ALL_LIST_ELEMENTS_RO (lsp->lspu.frags, node, frag))                     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)
     {      {
      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);
     }      }
   
   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,  return lsp_regenerate (area, IS_LEVEL_1);
                   isis_jitter (ref_time, MAX_AGE_JITTER)); 
 
  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,  return lsp_regenerate (area, IS_LEVEL_2);
                   isis_jitter (ref_time, MAX_AGE_JITTER)); 
 
  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;
     struct listnode *cnode;
     struct isis_circuit *circuit;
     int lvl;
   
     if (area == NULL)
       return ISIS_ERROR;
   
   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;
       if (area->lsp_regenerate_pending[lvl - 1])
         continue;
 
       lsp = lsp_search (id, area->lspdb[lvl - 1]);
       if (!lsp)
         continue;
 
       /*        /*
        * Throttle avoidance         * Throttle avoidance
        */         */
         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;          area->lsp_regenerate_pending[lvl - 1] = 1;
          area->t_lsp_l1_regenerate=thread_add_timer (master, lsp_l1_regenerate, area,          if (lvl == IS_LEVEL_1)
                            MIN_LSP_GEN_INTERVAL - diff);            THREAD_TIMER_ON (master, area->t_lsp_refresh[lvl - 1],
          goto L2;                             lsp_l1_refresh, area,
        }                             area->lsp_gen_interval[lvl - 1] - diff);
           else if (lvl == IS_LEVEL_2)
             THREAD_TIMER_ON (master, area->t_lsp_refresh[lvl - 1],
                              lsp_l2_refresh, area,
                              area->lsp_gen_interval[lvl - 1] - diff);
         }
       else        else
        lsp_non_pseudo_regenerate (area, 1);        {
           lsp_regenerate (area, lvl);
         }
     }      }
  /*
   * 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 1811  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;  
   
   assert (circuit);  
   assert (circuit->circ_type == CIRCUIT_T_BROADCAST);  
   
   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 
    lsp->lsp_header->lsp_bits |= IS_LEVEL_2; 
   
   /*    /*
    * add self to IS neighbours      * add self to IS neighbours 
Line 1738  lsp_build_pseudo (struct isis_lsp *lsp, struct isis_ci Line 1849  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 1761  lsp_build_pseudo (struct isis_lsp *lsp, struct isis_ci Line 1872  lsp_build_pseudo (struct isis_lsp *lsp, struct isis_ci
                   listnode_add (lsp->tlv_data.te_is_neighs, te_is_neigh);                    listnode_add (lsp->tlv_data.te_is_neighs, te_is_neigh);
                 }                  }
             }              }
          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 1777  lsp_build_pseudo (struct isis_lsp *lsp, struct isis_ci Line 1888  lsp_build_pseudo (struct isis_lsp *lsp, struct isis_ci
             }              }
         }          }
     }      }
     list_delete (adj_list);
   
   /* 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);
Line 1785  lsp_build_pseudo (struct isis_lsp *lsp, struct isis_ci Line 1897  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 1909  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 (lsp_id, rem_lifetime, 1, circuit->area->is_type, 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 2001  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));  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;
   int lvl;
   
  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]))  memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
    return lsp_pseudo_regenerate (circuit, 2);  LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id;
   LSP_FRAGMENT (lsp_id) = 0;
   now = time (NULL);
   
  lsp = lsp_new (id, circuit->area->max_lsp_lifetime[1],  for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++)
                 1, circuit->area->is_type, 0, 2);    {
       if (!((level & lvl) && (circuit->is_type & lvl)))
         continue;
   
  lsp_build_pseudo (lsp, circuit, 2);      if (circuit->u.bc.is_dr[lvl - 1] == 0 ||
           circuit->lsp_regenerate_pending[lvl - 1])
         continue;
   
  ref_time = circuit->area->lsp_refresh[1] > MAX_LSP_GEN_INTERVAL ?      lsp = lsp_search (lsp_id, circuit->area->lspdb[lvl - 1]);
    MAX_LSP_GEN_INTERVAL : circuit->area->lsp_refresh[1];      if (!lsp)
         continue;
   
         /*
          * Throttle avoidance
          */
         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])
           {
             circuit->lsp_regenerate_pending[lvl - 1] = 1;
             if (lvl == IS_LEVEL_1)
               THREAD_TIMER_ON (master,
                                circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1],
                                lsp_l1_refresh_pseudo, circuit,
                                circuit->area->lsp_gen_interval[lvl - 1] - diff);
             else if (lvl == IS_LEVEL_2)
               THREAD_TIMER_ON (master,
                                circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1],
                                lsp_l2_refresh_pseudo, circuit,
                                circuit->area->lsp_gen_interval[lvl - 1] - diff);
           }
         else
           {
             lsp_regenerate_pseudo (circuit, lvl);
           }
       }
   
  lsp->own_lsp = 1;  return ISIS_OK;
  lsp_insert (lsp, circuit->area->lspdb[1]); 
  ISIS_FLAGS_SET_ALL (lsp->SRMflags); 
 
  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 lsp_regenerate_schedule (circuit->area); 
 }  }
   
 /*  /*
Line 1988  lsp_tick (struct thread *thread) Line 2166  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 2182  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 2271  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 2092  lsp_purge_non_exist (struct isis_link_state_hdr *lsp_h Line 2327  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 = ((lsp_hdr->lsp_bits & LSPBIT_IST) == IS_LEVEL_1) ?
  lsp->level = ((lsp_hdr->lsp_bits & LSPBIT_IST) == IS_LEVEL_1) ? 1 : 2;    IS_LEVEL_1 : IS_LEVEL_2;
  lsp->pdu = stream_new (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);  /* FIXME: Should be minimal mtu? */
   lsp->pdu = stream_new (1500);
   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 2365  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, refresh_time;
   
   lsp = THREAD_ARG (thread);    lsp = THREAD_ARG (thread);
   assert (lsp);    assert (lsp);
Line 2140  top_lsp_refresh (struct thread *thread) Line 2403  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 2413  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 (level,
    htons (isis_jitter (lsp->area->max_lsp_lifetime[0], MAX_AGE_JITTER));                                                 lsp->area->overload_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 2433  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 2452  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 (lspid, rem_lifetime, 1, IS_LEVEL_1 | area->overload_bit,
                      0, 1);
       if (!lsp)        if (!lsp)
         return;          return;
       lsp->from_topology = 1;  
       lsp->area = area;        lsp->area = area;
         lsp->from_topology = 1;
   
       /* 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 2467  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 2587  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 2597  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.1.1  
changed lines
  Added in v.1.1.1.2


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