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

version 1.1, 2012/02/21 17:26:11 version 1.1.1.4, 2016/11/02 10:09:10
Line 33 Line 33
 #include "prefix.h"  #include "prefix.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/include-netbsd/iso.h"  #include "isisd/include-netbsd/iso.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_adjacency.h"  #include "isisd/isis_adjacency.h"
 #include "isisd/isis_circuit.h"  #include "isisd/isis_circuit.h"
 #include "isisd/isis_network.h"  #include "isisd/isis_network.h"
 #include "isisd/isis_misc.h"  #include "isisd/isis_misc.h"
 #include "isisd/isis_dr.h"  #include "isisd/isis_dr.h"
 #include "isisd/isis_flags.h"  
 #include "isisd/isis_tlv.h"  #include "isisd/isis_tlv.h"
 #include "isisd/isisd.h"  #include "isisd/isisd.h"
 #include "isisd/isis_dynhn.h"  #include "isisd/isis_dynhn.h"
Line 53 Line 54
 #include "isisd/isis_csm.h"  #include "isisd/isis_csm.h"
 #include "isisd/isis_events.h"  #include "isisd/isis_events.h"
   
 extern struct thread_master *master;  
 extern struct isis *isis;  
   
 #define ISIS_MINIMUM_FIXED_HDR_LEN 15  #define ISIS_MINIMUM_FIXED_HDR_LEN 15
 #define ISIS_MIN_PDU_LEN           13   /* partial seqnum pdu with id_len=2 */  #define ISIS_MIN_PDU_LEN           13   /* partial seqnum pdu with id_len=2 */
   
Line 168  accept_level (int level, int circuit_t) Line 166  accept_level (int level, int circuit_t)
   return retval;    return retval;
 }  }
   
int/*
authentication_check (struct isis_passwd *one, struct isis_passwd *theother) * Verify authentication information
  * Support cleartext and HMAC MD5 authentication
  */
 static int
 authentication_check (struct isis_passwd *remote, struct isis_passwd *local,
                       struct stream *stream, uint32_t auth_tlv_offset)
 {  {
  if (one->type != theother->type)  unsigned char digest[ISIS_AUTH_MD5_SIZE];
 
   /* Auth fail () - passwd type mismatch */
   if (local->type != remote->type)
     return ISIS_ERROR;
 
   switch (local->type)
   {
     /* No authentication required */
     case ISIS_PASSWD_TYPE_UNUSED:
       break;
 
     /* Cleartext (ISO 10589) */
     case ISIS_PASSWD_TYPE_CLEARTXT:
       /* Auth fail () - passwd len mismatch */
       if (remote->len != local->len)
         return ISIS_ERROR;
       return memcmp (local->passwd, remote->passwd, local->len);
 
     /* HMAC MD5 (RFC 3567) */
     case ISIS_PASSWD_TYPE_HMAC_MD5:
       /* Auth fail () - passwd len mismatch */
       if (remote->len != ISIS_AUTH_MD5_SIZE)
         return ISIS_ERROR;
       /* Set the authentication value to 0 before the check */
       memset (STREAM_DATA (stream) + auth_tlv_offset + 3, 0,
               ISIS_AUTH_MD5_SIZE);
       /* Compute the digest */
       hmac_md5 (STREAM_DATA (stream), stream_get_endp (stream),
                 (unsigned char *) &(local->passwd), local->len,
                 (unsigned char *) &digest);
       /* Copy back the authentication value after the check */
       memcpy (STREAM_DATA (stream) + auth_tlv_offset + 3,
               remote->passwd, ISIS_AUTH_MD5_SIZE);
       return memcmp (digest, remote->passwd, ISIS_AUTH_MD5_SIZE);
 
     default:
       zlog_err ("Unsupported authentication type");
       return ISIS_ERROR;
   }
 
   /* Authentication pass when no authentication is configured */
   return ISIS_OK;
 }
 
 static int
 lsp_authentication_check (struct stream *stream, struct isis_area *area,
                           int level, struct isis_passwd *passwd)
 {
   struct isis_link_state_hdr *hdr;
   uint32_t expected = 0, found = 0, auth_tlv_offset = 0;
   uint16_t checksum, rem_lifetime, pdu_len;
   struct tlvs tlvs;
   int retval = ISIS_OK;
 
   hdr = (struct isis_link_state_hdr *) (STREAM_PNT (stream));
   pdu_len = ntohs (hdr->pdu_len);
   expected |= TLVFLAG_AUTH_INFO;
   auth_tlv_offset = stream_get_getp (stream) + ISIS_LSP_HDR_LEN;
   retval = parse_tlvs (area->area_tag, STREAM_PNT (stream) + ISIS_LSP_HDR_LEN,
                        pdu_len - ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN,
                        &expected, &found, &tlvs, &auth_tlv_offset);
 
   if (retval != ISIS_OK)
     {      {
      zlog_warn ("Unsupported authentication type %d", theother->type);      zlog_err ("ISIS-Upd (%s): Parse failed L%d LSP %s, seq 0x%08x, "
      return 1;                      /* Auth fail (different authentication types) */                "cksum 0x%04x, lifetime %us, len %u",
                 area->area_tag, level, rawlspid_print (hdr->lsp_id),
                 ntohl (hdr->seq_num), ntohs (hdr->checksum),
                 ntohs (hdr->rem_lifetime), pdu_len);
       if ((isis->debugs & DEBUG_UPDATE_PACKETS) &&
           (isis->debugs & DEBUG_PACKET_DUMP))
         zlog_dump_data (STREAM_DATA (stream), stream_get_endp (stream));
       return retval;
     }      }
  switch (one->type)
   if (!(found & TLVFLAG_AUTH_INFO))
     {      {
    case ISIS_PASSWD_TYPE_CLEARTXT:      zlog_err ("No authentication tlv in LSP");
      if (one->len != theother->len)      return ISIS_ERROR;
        return 1;               /* Auth fail () - passwd len mismatch */ 
      return memcmp (one->passwd, theother->passwd, one->len); 
      break; 
    default: 
      zlog_warn ("Unsupported authentication type"); 
      break; 
     }      }
  return 0;                      /* Auth pass */
   if (tlvs.auth_info.type != ISIS_PASSWD_TYPE_CLEARTXT &&
       tlvs.auth_info.type != ISIS_PASSWD_TYPE_HMAC_MD5)
     {
       zlog_err ("Unknown authentication type in LSP");
       return ISIS_ERROR;
     }
 
   /*
    * RFC 5304 set checksum and remaining lifetime to zero before
    * verification and reset to old values after verification.
    */
   checksum = hdr->checksum;
   rem_lifetime = hdr->rem_lifetime;
   hdr->checksum = 0;
   hdr->rem_lifetime = 0;
   retval = authentication_check (&tlvs.auth_info, passwd, stream,
                                  auth_tlv_offset);
   hdr->checksum = checksum;
   hdr->rem_lifetime = rem_lifetime;
 
   return retval;
 }  }
   
 /*  /*
  * Processing helper functions   * Processing helper functions
  */   */
 static void  static void
   del_addr (void *val)
   {
     XFREE (MTYPE_ISIS_TMP, val);
   }
   
   static void
   tlvs_to_adj_area_addrs (struct tlvs *tlvs, struct isis_adjacency *adj)
   {
     struct listnode *node;
     struct area_addr *area_addr, *malloced;
   
     if (adj->area_addrs)
       {
         adj->area_addrs->del = del_addr;
         list_delete (adj->area_addrs);
       }
     adj->area_addrs = list_new ();
     if (tlvs->area_addrs)
       {
         for (ALL_LIST_ELEMENTS_RO (tlvs->area_addrs, node, area_addr))
         {
           malloced = XMALLOC (MTYPE_ISIS_TMP, sizeof (struct area_addr));
           memcpy (malloced, area_addr, sizeof (struct area_addr));
           listnode_add (adj->area_addrs, malloced);
         }
       }
   }
   
   static int
 tlvs_to_adj_nlpids (struct tlvs *tlvs, struct isis_adjacency *adj)  tlvs_to_adj_nlpids (struct tlvs *tlvs, struct isis_adjacency *adj)
 {  {
   int i;    int i;
Line 203  tlvs_to_adj_nlpids (struct tlvs *tlvs, struct isis_adj Line 321  tlvs_to_adj_nlpids (struct tlvs *tlvs, struct isis_adj
     {      {
   
       tlv_nlpids = tlvs->nlpids;        tlv_nlpids = tlvs->nlpids;
         if (tlv_nlpids->count > array_size (adj->nlpids.nlpids))
           return 1;
   
       adj->nlpids.count = tlv_nlpids->count;        adj->nlpids.count = tlv_nlpids->count;
   
Line 211  tlvs_to_adj_nlpids (struct tlvs *tlvs, struct isis_adj Line 331  tlvs_to_adj_nlpids (struct tlvs *tlvs, struct isis_adj
           adj->nlpids.nlpids[i] = tlv_nlpids->nlpids[i];            adj->nlpids.nlpids[i] = tlv_nlpids->nlpids[i];
         }          }
     }      }
     return 0;
 }  }
   
 static void  static void
 del_ip_addr (void *val)  
 {  
   XFREE (MTYPE_ISIS_TMP, val);  
 }  
   
 static void  
 tlvs_to_adj_ipv4_addrs (struct tlvs *tlvs, struct isis_adjacency *adj)  tlvs_to_adj_ipv4_addrs (struct tlvs *tlvs, struct isis_adjacency *adj)
 {  {
   struct listnode *node;    struct listnode *node;
Line 227  tlvs_to_adj_ipv4_addrs (struct tlvs *tlvs, struct isis Line 342  tlvs_to_adj_ipv4_addrs (struct tlvs *tlvs, struct isis
   
   if (adj->ipv4_addrs)    if (adj->ipv4_addrs)
     {      {
      adj->ipv4_addrs->del = del_ip_addr;      adj->ipv4_addrs->del = del_addr;
       list_delete (adj->ipv4_addrs);        list_delete (adj->ipv4_addrs);
     }      }
   adj->ipv4_addrs = list_new ();    adj->ipv4_addrs = list_new ();
Line 251  tlvs_to_adj_ipv6_addrs (struct tlvs *tlvs, struct isis Line 366  tlvs_to_adj_ipv6_addrs (struct tlvs *tlvs, struct isis
   
   if (adj->ipv6_addrs)    if (adj->ipv6_addrs)
     {      {
      adj->ipv6_addrs->del = del_ip_addr;      adj->ipv6_addrs->del = del_addr;
       list_delete (adj->ipv6_addrs);        list_delete (adj->ipv6_addrs);
     }      }
   adj->ipv6_addrs = list_new ();    adj->ipv6_addrs = list_new ();
Line 284  process_p2p_hello (struct isis_circuit *circuit) Line 399  process_p2p_hello (struct isis_circuit *circuit)
   int retval = ISIS_OK;    int retval = ISIS_OK;
   struct isis_p2p_hello_hdr *hdr;    struct isis_p2p_hello_hdr *hdr;
   struct isis_adjacency *adj;    struct isis_adjacency *adj;
  u_int32_t expected = 0, found;  u_int32_t expected = 0, found = 0, auth_tlv_offset = 0;
   uint16_t pdu_len;
   struct tlvs tlvs;    struct tlvs tlvs;
     int v4_usable = 0, v6_usable = 0;
   
     if (isis->debugs & DEBUG_ADJ_PACKETS)
       {
         zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH on %s, cirType %s, cirID %u",
                     circuit->area->area_tag, circuit->interface->name,
                     circuit_t2string (circuit->is_type), circuit->circuit_id);
         if (isis->debugs & DEBUG_PACKET_DUMP)
           zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
                           stream_get_endp (circuit->rcv_stream));
       }
   
     if (circuit->circ_type != CIRCUIT_T_P2P)
       {
         zlog_warn ("p2p hello on non p2p circuit");
         return ISIS_WARNING;
       }
   
   if ((stream_get_endp (circuit->rcv_stream) -    if ((stream_get_endp (circuit->rcv_stream) -
        stream_get_getp (circuit->rcv_stream)) < ISIS_P2PHELLO_HDRLEN)         stream_get_getp (circuit->rcv_stream)) < ISIS_P2PHELLO_HDRLEN)
     {      {
Line 311  process_p2p_hello (struct isis_circuit *circuit) Line 444  process_p2p_hello (struct isis_circuit *circuit)
    * Get the header     * Get the header
    */     */
   hdr = (struct isis_p2p_hello_hdr *) STREAM_PNT (circuit->rcv_stream);    hdr = (struct isis_p2p_hello_hdr *) STREAM_PNT (circuit->rcv_stream);
  circuit->rcv_stream->getp += ISIS_P2PHELLO_HDRLEN;  pdu_len = ntohs (hdr->pdu_len);
   
  /*  hdr.circuit_t = stream_getc (stream);  if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_P2PHELLO_HDRLEN) ||
     stream_get (hdr.source_id, stream, ISIS_SYS_ID_LEN);      pdu_len > ISO_MTU(circuit) ||
     hdr.hold_time = stream_getw (stream);      pdu_len > stream_get_endp (circuit->rcv_stream))
     hdr.pdu_len   = stream_getw (stream);    {
     hdr.local_id  = stream_getc (stream); */      zlog_warn ("ISIS-Adj (%s): Rcvd P2P IIH from (%s) with "
                  "invalid pdu length %d",
                  circuit->area->area_tag, circuit->interface->name, pdu_len);
       return ISIS_WARNING;
     }
   
   /*    /*
   * My interpertation of the ISO, if no adj exists we will create one for    * Set the stream endp to PDU length, ignoring additional padding
   * the circuit   * introduced by transport chips.
    */     */
     if (pdu_len < stream_get_endp (circuit->rcv_stream))
       stream_set_endp (circuit->rcv_stream, pdu_len);
   
  if (isis->debugs & DEBUG_ADJ_PACKETS)  stream_forward_getp (circuit->rcv_stream, ISIS_P2PHELLO_HDRLEN);
    { 
      zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s," 
                  " cir id %02d, length %d", 
                  circuit->area->area_tag, circuit->interface->name, 
                  circuit_t2string (circuit->circuit_is_type), 
                  circuit->circuit_id, ntohs (hdr->pdu_len)); 
    } 
   
   adj = circuit->u.p2p.neighbor;  
   if (!adj)  
     {  
       adj = isis_new_adj (hdr->source_id, NULL, 0, circuit);  
       if (adj == NULL)  
         return ISIS_ERROR;  
       circuit->u.p2p.neighbor = adj;  
       isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL);  
       adj->sys_type = ISIS_SYSTYPE_UNKNOWN;  
     }  
   
   /* 8.2.6 Monitoring point-to-point adjacencies */  
   adj->hold_time = ntohs (hdr->hold_time);  
   adj->last_upd = time (NULL);  
   
   /*    /*
    * Lets get the TLVS now     * Lets get the TLVS now
    */     */
Line 357  process_p2p_hello (struct isis_circuit *circuit) Line 474  process_p2p_hello (struct isis_circuit *circuit)
   expected |= TLVFLAG_IPV4_ADDR;    expected |= TLVFLAG_IPV4_ADDR;
   expected |= TLVFLAG_IPV6_ADDR;    expected |= TLVFLAG_IPV6_ADDR;
   
     auth_tlv_offset = stream_get_getp (circuit->rcv_stream);
   retval = parse_tlvs (circuit->area->area_tag,    retval = parse_tlvs (circuit->area->area_tag,
                        STREAM_PNT (circuit->rcv_stream),                         STREAM_PNT (circuit->rcv_stream),
                       ntohs (hdr->pdu_len) - ISIS_P2PHELLO_HDRLEN                       pdu_len - ISIS_P2PHELLO_HDRLEN - ISIS_FIXED_HDR_LEN,
                       - ISIS_FIXED_HDR_LEN, &expected, &found, &tlvs);                       &expected, &found, &tlvs, &auth_tlv_offset);
   
   if (retval > ISIS_WARNING)    if (retval > ISIS_WARNING)
     {      {
         zlog_warn ("parse_tlvs() failed");
       free_tlvs (&tlvs);        free_tlvs (&tlvs);
       return retval;        return retval;
     };      };
   
     if (!(found & TLVFLAG_AREA_ADDRS))
       {
         zlog_warn ("No Area addresses TLV in P2P IS to IS hello");
         free_tlvs (&tlvs);
         return ISIS_WARNING;
       }
   
     if (!(found & TLVFLAG_NLPID))
       {
         zlog_warn ("No supported protocols TLV in P2P IS to IS hello");
         free_tlvs (&tlvs);
         return ISIS_WARNING;
       }
   
   /* 8.2.5.1 c) Authentication */    /* 8.2.5.1 c) Authentication */
   if (circuit->passwd.type)    if (circuit->passwd.type)
     {      {
       if (!(found & TLVFLAG_AUTH_INFO) ||        if (!(found & TLVFLAG_AUTH_INFO) ||
          authentication_check (&circuit->passwd, &tlvs.auth_info))          authentication_check (&tlvs.auth_info, &circuit->passwd,
                                 circuit->rcv_stream, auth_tlv_offset))
         {
           isis_event_auth_failure (circuit->area->area_tag,
                                    "P2P hello authentication failure",
                                    hdr->source_id);
           free_tlvs (&tlvs);
           return ISIS_OK;
         }
     }
 
   /*
    * check if it's own interface ip match iih ip addrs
    */
   if (found & TLVFLAG_IPV4_ADDR)
     {
       if (ip_match (circuit->ip_addrs, tlvs.ipv4_addrs))
         v4_usable = 1;
       else
         zlog_warn ("ISIS-Adj: IPv4 addresses present but no overlap "
                    "in P2P IIH from %s\n", circuit->interface->name);
     }
 #ifndef HAVE_IPV6
   else /* !(found & TLVFLAG_IPV4_ADDR) */
     zlog_warn ("ISIS-Adj: no IPv4 in P2P IIH from %s "
                "(this isisd has no IPv6)\n", circuit->interface->name);
 
 #else
   if (found & TLVFLAG_IPV6_ADDR)
     {
       /* TBA: check that we have a linklocal ourselves? */
       struct listnode *node;
       struct in6_addr *ip;
       for (ALL_LIST_ELEMENTS_RO (tlvs.ipv6_addrs, node, ip))
         if (IN6_IS_ADDR_LINKLOCAL (ip))
           {
             v6_usable = 1;
             break;
           }
 
       if (!v6_usable)
         zlog_warn ("ISIS-Adj: IPv6 addresses present but no link-local "
                    "in P2P IIH from %s\n", circuit->interface->name);
     }
 
   if (!(found & (TLVFLAG_IPV4_ADDR | TLVFLAG_IPV6_ADDR)))
     zlog_warn ("ISIS-Adj: neither IPv4 nor IPv6 addr in P2P IIH from %s\n",
                circuit->interface->name);
 #endif
 
   if (!v6_usable && !v4_usable)
     {
       free_tlvs (&tlvs);
       return ISIS_WARNING;
     }
 
   /*
    * it's own p2p IIH PDU - discard
    */
   if (!memcmp (hdr->source_id, isis->sysid, ISIS_SYS_ID_LEN))
     {
       zlog_warn ("ISIS-Adj (%s): it's own IIH PDU - discarded",
                   circuit->area->area_tag);
       free_tlvs (&tlvs);
       return ISIS_WARNING;
     }
 
   /*
    * My interpertation of the ISO, if no adj exists we will create one for
    * the circuit
    */
   adj = circuit->u.p2p.neighbor;
   /* If an adjacency exists, check it is with the source of the hello
    * packets */
   if (adj)
     {
       if (memcmp(hdr->source_id, adj->sysid, ISIS_SYS_ID_LEN))
         {          {
          isis_event_auth_failure (circuit->area->area_tag,          zlog_debug("hello source and adjacency do not match, set adj down\n");
                                   "P2P hello authentication failure",          isis_adj_state_change (adj, ISIS_ADJ_DOWN, "adj do not exist");
                                   hdr->source_id);          return 0;
          return ISIS_OK;        }
        } 
     }      }
     if (!adj || adj->level != hdr->circuit_t)
       {
         if (!adj)
           {
             adj = isis_new_adj (hdr->source_id, NULL, hdr->circuit_t, circuit);
             if (adj == NULL)
               return ISIS_ERROR;
           }
         else
           {
             adj->level = hdr->circuit_t;
           }
         circuit->u.p2p.neighbor = adj;
         /* Build lsp with the new neighbor entry when a new
          * adjacency is formed. Set adjacency circuit type to
          * IIH PDU header circuit type before lsp is regenerated
          * when an adjacency is up. This will result in the new
          * adjacency entry getting added to the lsp tlv neighbor list.
          */
         adj->circuit_t = hdr->circuit_t;
         isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL);
         adj->sys_type = ISIS_SYSTYPE_UNKNOWN;
       }
   
     /* 8.2.6 Monitoring point-to-point adjacencies */
     adj->hold_time = ntohs (hdr->hold_time);
     adj->last_upd = time (NULL);
   
   /* we do this now because the adj may not survive till the end... */    /* we do this now because the adj may not survive till the end... */
     tlvs_to_adj_area_addrs (&tlvs, adj);
   
     /* which protocol are spoken ??? */
     if (tlvs_to_adj_nlpids (&tlvs, adj))
       {
         free_tlvs (&tlvs);
         return ISIS_WARNING;
       }
   
   /* we need to copy addresses to the adj */    /* we need to copy addresses to the adj */
  tlvs_to_adj_ipv4_addrs (&tlvs, adj);  if (found & TLVFLAG_IPV4_ADDR)
     tlvs_to_adj_ipv4_addrs (&tlvs, adj);
   
 #ifdef HAVE_IPV6  #ifdef HAVE_IPV6
  tlvs_to_adj_ipv6_addrs (&tlvs, adj);  if (found & TLVFLAG_IPV6_ADDR)
     tlvs_to_adj_ipv6_addrs (&tlvs, adj);
 #endif /* HAVE_IPV6 */  #endif /* HAVE_IPV6 */
   
   /* lets take care of the expiry */    /* lets take care of the expiry */
Line 422  process_p2p_hello (struct isis_circuit *circuit) Line 667  process_p2p_hello (struct isis_circuit *circuit)
                 {                  {
                   /* (7) reject - wrong system type event */                    /* (7) reject - wrong system type event */
                   zlog_warn ("wrongSystemType");                    zlog_warn ("wrongSystemType");
                     free_tlvs (&tlvs);
                   return ISIS_WARNING;  /* Reject */                    return ISIS_WARNING;  /* Reject */
                 }                  }
               else if (adj->adj_usage == ISIS_ADJ_LEVEL1)                else if (adj->adj_usage == ISIS_ADJ_LEVEL1)
Line 508  process_p2p_hello (struct isis_circuit *circuit) Line 754  process_p2p_hello (struct isis_circuit *circuit)
                 {                  {
                   /* (5) reject - wrong system type event */                    /* (5) reject - wrong system type event */
                   zlog_warn ("wrongSystemType");                    zlog_warn ("wrongSystemType");
                     free_tlvs (&tlvs);
                   return ISIS_WARNING;  /* Reject */                    return ISIS_WARNING;  /* Reject */
                 }                  }
               else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||                else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
Line 540  process_p2p_hello (struct isis_circuit *circuit) Line 787  process_p2p_hello (struct isis_circuit *circuit)
         }          }
     }      }
   /* 8.2.5.2 b) if no match was detected */    /* 8.2.5.2 b) if no match was detected */
  else  else if (listcount (circuit->area->area_addrs) > 0)
     {      {
       if (circuit->area->is_type == IS_LEVEL_1)        if (circuit->area->is_type == IS_LEVEL_1)
         {          {
Line 566  process_p2p_hello (struct isis_circuit *circuit) Line 813  process_p2p_hello (struct isis_circuit *circuit)
                 {                  {
                   /* (6) reject - Area Mismatch event */                    /* (6) reject - Area Mismatch event */
                   zlog_warn ("AreaMismatch");                    zlog_warn ("AreaMismatch");
                     free_tlvs (&tlvs);
                   return ISIS_WARNING;  /* Reject */                    return ISIS_WARNING;  /* Reject */
                 }                  }
               else if (adj->adj_usage == ISIS_ADJ_LEVEL1)                else if (adj->adj_usage == ISIS_ADJ_LEVEL1)
Line 618  process_p2p_hello (struct isis_circuit *circuit) Line 866  process_p2p_hello (struct isis_circuit *circuit)
             }              }
         }          }
     }      }
     else
       {
         /* down - area mismatch */
         isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch");
       }
   /* 8.2.5.2 c) if the action was up - comparing circuit IDs */    /* 8.2.5.2 c) if the action was up - comparing circuit IDs */
   /* FIXME - Missing parts */    /* FIXME - Missing parts */
   
Line 640  process_p2p_hello (struct isis_circuit *circuit) Line 893  process_p2p_hello (struct isis_circuit *circuit)
       break;        break;
     }      }
   
   adj->circuit_t = hdr->circuit_t;  
   adj->level = hdr->circuit_t;  
   
     if (isis->debugs & DEBUG_ADJ_PACKETS)
       {
         zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s,"
                     " cir id %02d, length %d",
                     circuit->area->area_tag, circuit->interface->name,
                     circuit_t2string (circuit->is_type),
                     circuit->circuit_id, pdu_len);
       }
   
   free_tlvs (&tlvs);    free_tlvs (&tlvs);
   
   return retval;    return retval;
Line 652  process_p2p_hello (struct isis_circuit *circuit) Line 912  process_p2p_hello (struct isis_circuit *circuit)
  * Process IS-IS LAN Level 1/2 Hello PDU   * Process IS-IS LAN Level 1/2 Hello PDU
  */   */
 static int  static int
process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)process_lan_hello (int level, struct isis_circuit *circuit, const u_char *ssnpa)
 {  {
   int retval = ISIS_OK;    int retval = ISIS_OK;
   struct isis_lan_hello_hdr hdr;    struct isis_lan_hello_hdr hdr;
   struct isis_adjacency *adj;    struct isis_adjacency *adj;
  u_int32_t expected = 0, found;  u_int32_t expected = 0, found = 0, auth_tlv_offset = 0;
   struct tlvs tlvs;    struct tlvs tlvs;
   u_char *snpa;    u_char *snpa;
   struct listnode *node;    struct listnode *node;
     int v4_usable = 0, v6_usable = 0;
   
     if (isis->debugs & DEBUG_ADJ_PACKETS)
       {
         zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH on %s, cirType %s, "
                     "cirID %u",
                     circuit->area->area_tag, level, circuit->interface->name,
                     circuit_t2string (circuit->is_type), circuit->circuit_id);
         if (isis->debugs & DEBUG_PACKET_DUMP)
           zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
                           stream_get_endp (circuit->rcv_stream));
       }
   
     if (circuit->circ_type != CIRCUIT_T_BROADCAST)
       {
         zlog_warn ("lan hello on non broadcast circuit");
         return ISIS_WARNING;
       }
   
   if ((stream_get_endp (circuit->rcv_stream) -    if ((stream_get_endp (circuit->rcv_stream) -
        stream_get_getp (circuit->rcv_stream)) < ISIS_LANHELLO_HDRLEN)         stream_get_getp (circuit->rcv_stream)) < ISIS_LANHELLO_HDRLEN)
     {      {
Line 676  process_lan_hello (int level, struct isis_circuit *cir Line 954  process_lan_hello (int level, struct isis_circuit *cir
       return ISIS_WARNING;        return ISIS_WARNING;
     }      }
   
  if (!accept_level (level, circuit->circuit_is_type))  if (!accept_level (level, circuit->is_type))
     {      {
       if (isis->debugs & DEBUG_ADJ_PACKETS)        if (isis->debugs & DEBUG_ADJ_PACKETS)
         {          {
Line 708  process_lan_hello (int level, struct isis_circuit *cir Line 986  process_lan_hello (int level, struct isis_circuit *cir
   hdr.prio = stream_getc (circuit->rcv_stream);    hdr.prio = stream_getc (circuit->rcv_stream);
   stream_get (hdr.lan_id, circuit->rcv_stream, ISIS_SYS_ID_LEN + 1);    stream_get (hdr.lan_id, circuit->rcv_stream, ISIS_SYS_ID_LEN + 1);
   
  if (hdr.circuit_t != IS_LEVEL_1 && hdr.circuit_t != IS_LEVEL_2 &&  if (hdr.pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_LANHELLO_HDRLEN) ||
      hdr.circuit_t != IS_LEVEL_1_AND_2)      hdr.pdu_len > ISO_MTU(circuit) ||
       hdr.pdu_len > stream_get_endp (circuit->rcv_stream))
     {      {
      zlog_warn ("Level %d LAN Hello with Circuit Type %d", level,      zlog_warn ("ISIS-Adj (%s): Rcvd LAN IIH from (%s) with "
                 hdr.circuit_t);                 "invalid pdu length %d",
                  circuit->area->area_tag, circuit->interface->name,
                  hdr.pdu_len);
       return ISIS_WARNING;
     }
 
   /*
    * Set the stream endp to PDU length, ignoring additional padding
    * introduced by transport chips.
    */
   if (hdr.pdu_len < stream_get_endp (circuit->rcv_stream))
     stream_set_endp (circuit->rcv_stream, hdr.pdu_len);
 
   if (hdr.circuit_t != IS_LEVEL_1 &&
       hdr.circuit_t != IS_LEVEL_2 &&
       hdr.circuit_t != IS_LEVEL_1_AND_2 &&
       (level & hdr.circuit_t) == 0)
     {
       zlog_err ("Level %d LAN Hello with Circuit Type %d", level,
                 hdr.circuit_t);
       return ISIS_ERROR;        return ISIS_ERROR;
     }      }
   
   /*    /*
    * Then get the tlvs     * Then get the tlvs
    */     */
Line 725  process_lan_hello (int level, struct isis_circuit *cir Line 1024  process_lan_hello (int level, struct isis_circuit *cir
   expected |= TLVFLAG_IPV4_ADDR;    expected |= TLVFLAG_IPV4_ADDR;
   expected |= TLVFLAG_IPV6_ADDR;    expected |= TLVFLAG_IPV6_ADDR;
   
     auth_tlv_offset = stream_get_getp (circuit->rcv_stream);
   retval = parse_tlvs (circuit->area->area_tag,    retval = parse_tlvs (circuit->area->area_tag,
                       STREAM_PNT (circuit->rcv_stream),                       STREAM_PNT (circuit->rcv_stream),
                       hdr.pdu_len - ISIS_LANHELLO_HDRLEN -                       hdr.pdu_len - ISIS_LANHELLO_HDRLEN - ISIS_FIXED_HDR_LEN,
                       ISIS_FIXED_HDR_LEN, &expected, &found, &tlvs);                       &expected, &found, &tlvs,
                        &auth_tlv_offset);
   
   if (retval > ISIS_WARNING)    if (retval > ISIS_WARNING)
     {      {
Line 744  process_lan_hello (int level, struct isis_circuit *cir Line 1045  process_lan_hello (int level, struct isis_circuit *cir
       goto out;        goto out;
     }      }
   
     if (!(found & TLVFLAG_NLPID))
       {
         zlog_warn ("No supported protocols TLV in Level %d LAN IS to IS hello",
                    level);
         retval = ISIS_WARNING;
         goto out;
       }
   
     /* Verify authentication, either cleartext of HMAC MD5 */
   if (circuit->passwd.type)    if (circuit->passwd.type)
     {      {
       if (!(found & TLVFLAG_AUTH_INFO) ||        if (!(found & TLVFLAG_AUTH_INFO) ||
          authentication_check (&circuit->passwd, &tlvs.auth_info))          authentication_check (&tlvs.auth_info, &circuit->passwd,
        {                                circuit->rcv_stream, auth_tlv_offset))
          isis_event_auth_failure (circuit->area->area_tag,        {
                                   "LAN hello authentication failure",          isis_event_auth_failure (circuit->area->area_tag,
                                   hdr.source_id);                                   "LAN hello authentication failure",
          retval = ISIS_WARNING;                                   hdr.source_id);
          goto out;          retval = ISIS_WARNING;
        }          goto out;
         }
     }      }
   
     if (!memcmp (hdr.source_id, isis->sysid, ISIS_SYS_ID_LEN))
       {
         zlog_warn ("ISIS-Adj (%s): duplicate system ID on interface %s",
                    circuit->area->area_tag, circuit->interface->name);
         return ISIS_WARNING;
       }
   
   /*    /*
    * Accept the level 1 adjacency only if a match between local and     * Accept the level 1 adjacency only if a match between local and
    * remote area addresses is found     * remote area addresses is found
    */     */
  if (level == 1 && !area_match (circuit->area->area_addrs, tlvs.area_addrs))  if (listcount (circuit->area->area_addrs) == 0 ||
       (level == IS_LEVEL_1 &&
        area_match (circuit->area->area_addrs, tlvs.area_addrs) == 0))
     {      {
       if (isis->debugs & DEBUG_ADJ_PACKETS)        if (isis->debugs & DEBUG_ADJ_PACKETS)
         {          {
Line 788  process_lan_hello (int level, struct isis_circuit *cir Line 1108  process_lan_hello (int level, struct isis_circuit *cir
   /*    /*
    * check if it's own interface ip match iih ip addrs     * check if it's own interface ip match iih ip addrs
    */     */
  if (!(found & TLVFLAG_IPV4_ADDR)  if (found & TLVFLAG_IPV4_ADDR)
      || !ip_match (circuit->ip_addrs, tlvs.ipv4_addrs)) 
     {      {
      zlog_debug      if (ip_match (circuit->ip_addrs, tlvs.ipv4_addrs))
        ("ISIS-Adj: No usable IP interface addresses in LAN IIH from %s\n",        v4_usable = 1;
         circuit->interface->name);      else
      retval = ISIS_WARNING;        zlog_warn ("ISIS-Adj: IPv4 addresses present but no overlap "
      goto out;                   "in LAN IIH from %s\n", circuit->interface->name);
     }      }
   #ifndef HAVE_IPV6
     else /* !(found & TLVFLAG_IPV4_ADDR) */
       zlog_warn ("ISIS-Adj: no IPv4 in LAN IIH from %s "
                  "(this isisd has no IPv6)\n", circuit->interface->name);
   
  adj = isis_adj_lookup (hdr.source_id, circuit->u.bc.adjdb[level - 1]);#else
  if (!adj)  if (found & TLVFLAG_IPV6_ADDR)
     {      {
      /*      /* TBA: check that we have a linklocal ourselves? */
       * Do as in 8.4.2.5      struct listnode *node;
       */      struct in6_addr *ip;
      adj = isis_new_adj (hdr.source_id, ssnpa, level, circuit);      for (ALL_LIST_ELEMENTS_RO (tlvs.ipv6_addrs, node, ip))
      if (adj == NULL)        if (IN6_IS_ADDR_LINKLOCAL (ip))
        {          {
          retval = ISIS_ERROR;            v6_usable = 1;
          goto out;            break;
        }          }
   
      adj->level = level;      if (!v6_usable)
         zlog_warn ("ISIS-Adj: IPv6 addresses present but no link-local "
                    "in LAN IIH from %s\n", circuit->interface->name);
     }
 
   if (!(found & (TLVFLAG_IPV4_ADDR | TLVFLAG_IPV6_ADDR)))
     zlog_warn ("ISIS-Adj: neither IPv4 nor IPv6 addr in LAN IIH from %s\n",
                circuit->interface->name);
 #endif
 
   if (!v6_usable && !v4_usable)
     {
       free_tlvs (&tlvs);
       return ISIS_WARNING;
     }
 
 
   adj = isis_adj_lookup (hdr.source_id, circuit->u.bc.adjdb[level - 1]);
   if ((adj == NULL) || (memcmp(adj->snpa, ssnpa, ETH_ALEN)) ||
       (adj->level != level))
     {
       if (!adj)
         {
           /*
            * Do as in 8.4.2.5
            */
           adj = isis_new_adj (hdr.source_id, ssnpa, level, circuit);
           if (adj == NULL)
             {
               retval = ISIS_ERROR;
               goto out;
             }
         }
       else
         {
           if (ssnpa) {
             memcpy (adj->snpa, ssnpa, 6);
           } else {
             memset (adj->snpa, ' ', 6);
           }
           adj->level = level;
         }
       isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL);        isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL);
   
      if (level == 1)      if (level == IS_LEVEL_1)
        {          adj->sys_type = ISIS_SYSTYPE_L1_IS;
          adj->sys_type = ISIS_SYSTYPE_L1_IS; 
        } 
       else        else
        {          adj->sys_type = ISIS_SYSTYPE_L2_IS;
          adj->sys_type = ISIS_SYSTYPE_L2_IS; 
        } 
       list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]);        list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]);
       isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1],        isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1],
                                 circuit->u.bc.lan_neighs[level - 1]);                                 circuit->u.bc.lan_neighs[level - 1]);
     }      }
   
   if(adj->dis_record[level-1].dis==ISIS_IS_DIS)    if(adj->dis_record[level-1].dis==ISIS_IS_DIS)
Line 833  process_lan_hello (int level, struct isis_circuit *cir Line 1193  process_lan_hello (int level, struct isis_circuit *cir
       case 1:        case 1:
         if (memcmp (circuit->u.bc.l1_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1))          if (memcmp (circuit->u.bc.l1_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1))
           {            {
            thread_add_event (master, isis_event_dis_status_change, circuit, 0);            thread_add_event (master, isis_event_dis_status_change, circuit, 0);
             memcpy (&circuit->u.bc.l1_desig_is, hdr.lan_id,              memcpy (&circuit->u.bc.l1_desig_is, hdr.lan_id,
                     ISIS_SYS_ID_LEN + 1);                      ISIS_SYS_ID_LEN + 1);
           }            }
Line 841  process_lan_hello (int level, struct isis_circuit *cir Line 1201  process_lan_hello (int level, struct isis_circuit *cir
       case 2:        case 2:
         if (memcmp (circuit->u.bc.l2_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1))          if (memcmp (circuit->u.bc.l2_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1))
           {            {
            thread_add_event (master, isis_event_dis_status_change, circuit, 0);            thread_add_event (master, isis_event_dis_status_change, circuit, 0);
             memcpy (&circuit->u.bc.l2_desig_is, hdr.lan_id,              memcpy (&circuit->u.bc.l2_desig_is, hdr.lan_id,
                     ISIS_SYS_ID_LEN + 1);                      ISIS_SYS_ID_LEN + 1);
           }            }
Line 854  process_lan_hello (int level, struct isis_circuit *cir Line 1214  process_lan_hello (int level, struct isis_circuit *cir
   
   memcpy (adj->lanid, hdr.lan_id, ISIS_SYS_ID_LEN + 1);    memcpy (adj->lanid, hdr.lan_id, ISIS_SYS_ID_LEN + 1);
   
     tlvs_to_adj_area_addrs (&tlvs, adj);
   
   /* which protocol are spoken ??? */    /* which protocol are spoken ??? */
  if (found & TLVFLAG_NLPID)  if (tlvs_to_adj_nlpids (&tlvs, adj))
    tlvs_to_adj_nlpids (&tlvs, adj);    {
       retval = ISIS_WARNING;
       goto out;
     }
   
   /* we need to copy addresses to the adj */    /* we need to copy addresses to the adj */
   if (found & TLVFLAG_IPV4_ADDR)    if (found & TLVFLAG_IPV4_ADDR)
Line 872  process_lan_hello (int level, struct isis_circuit *cir Line 1237  process_lan_hello (int level, struct isis_circuit *cir
   /* lets take care of the expiry */    /* lets take care of the expiry */
   THREAD_TIMER_OFF (adj->t_expire);    THREAD_TIMER_OFF (adj->t_expire);
   THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj,    THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj,
                   (long) adj->hold_time);                   (long) adj->hold_time);
   
   /*    /*
    * If the snpa for this circuit is found from LAN Neighbours TLV     * If the snpa for this circuit is found from LAN Neighbours TLV
Line 880  process_lan_hello (int level, struct isis_circuit *cir Line 1245  process_lan_hello (int level, struct isis_circuit *cir
    */     */
   
   if (found & TLVFLAG_LAN_NEIGHS)    if (found & TLVFLAG_LAN_NEIGHS)
     {
       if (adj->adj_state != ISIS_ADJ_UP)
     {      {
      if (adj->adj_state != ISIS_ADJ_UP)      for (ALL_LIST_ELEMENTS_RO (tlvs.lan_neighs, node, snpa))
        {      {
          for (ALL_LIST_ELEMENTS_RO (tlvs.lan_neighs, node, snpa))        if (!memcmp (snpa, circuit->u.bc.snpa, ETH_ALEN))
            if (!memcmp (snpa, circuit->u.bc.snpa, ETH_ALEN))        {
            {          isis_adj_state_change (adj, ISIS_ADJ_UP,
              isis_adj_state_change (adj, ISIS_ADJ_UP,                                 "own SNPA found in LAN Neighbours TLV");
                                     "own SNPA found in LAN Neighbours TLV");        }
            }      }
        } 
     }      }
       else
       {
         int found = 0;
         for (ALL_LIST_ELEMENTS_RO (tlvs.lan_neighs, node, snpa))
           if (!memcmp (snpa, circuit->u.bc.snpa, ETH_ALEN))
           {
             found = 1;
             break;
           }
         if (found == 0)
           isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING,
                                  "own SNPA not found in LAN Neighbours TLV");
       }
     }
     else if (adj->adj_state == ISIS_ADJ_UP)
     {
       isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING,
                              "no LAN Neighbours TLV found");
     }
   
 out:  out:
   /* DEBUG_ADJ_PACKETS */  
   if (isis->debugs & DEBUG_ADJ_PACKETS)    if (isis->debugs & DEBUG_ADJ_PACKETS)
     {      {
       /* FIXME: is this place right? fix missing info */  
       zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH from %s on %s, cirType %s, "        zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH from %s on %s, cirType %s, "
                  "cirID %u, length %ld",                  "cirID %u, length %zd",
                   circuit->area->area_tag,                    circuit->area->area_tag,
                   level, snpa_print (ssnpa), circuit->interface->name,                    level, snpa_print (ssnpa), circuit->interface->name,
                  circuit_t2string (circuit->circuit_is_type),                  circuit_t2string (circuit->is_type),
                   circuit->circuit_id,                    circuit->circuit_id,
                  /* FIXME: use %z when we stop supporting old compilers. */                  stream_get_endp (circuit->rcv_stream));
                  (unsigned long) stream_get_endp (circuit->rcv_stream)); 
     }      }
   
   free_tlvs (&tlvs);    free_tlvs (&tlvs);
Line 918  out: Line 1300  out:
  * Section 7.3.15.1 - Action on receipt of a link state PDU   * Section 7.3.15.1 - Action on receipt of a link state PDU
  */   */
 static int  static int
process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa)process_lsp (int level, struct isis_circuit *circuit, const u_char *ssnpa)
 {  {
   struct isis_link_state_hdr *hdr;    struct isis_link_state_hdr *hdr;
   struct isis_adjacency *adj = NULL;    struct isis_adjacency *adj = NULL;
Line 926  process_lsp (int level, struct isis_circuit *circuit,  Line 1308  process_lsp (int level, struct isis_circuit *circuit, 
   int retval = ISIS_OK, comp = 0;    int retval = ISIS_OK, comp = 0;
   u_char lspid[ISIS_SYS_ID_LEN + 2];    u_char lspid[ISIS_SYS_ID_LEN + 2];
   struct isis_passwd *passwd;    struct isis_passwd *passwd;
     uint16_t pdu_len;
     int lsp_confusion;
   
  /* Sanity check - FIXME: move to correct place */  if (isis->debugs & DEBUG_UPDATE_PACKETS)
     {
       zlog_debug ("ISIS-Upd (%s): Rcvd L%d LSP on %s, cirType %s, cirID %u",
                   circuit->area->area_tag, level, circuit->interface->name,
                   circuit_t2string (circuit->is_type), circuit->circuit_id);
       if (isis->debugs & DEBUG_PACKET_DUMP)
         zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
                         stream_get_endp (circuit->rcv_stream));
     }
 
   if ((stream_get_endp (circuit->rcv_stream) -    if ((stream_get_endp (circuit->rcv_stream) -
        stream_get_getp (circuit->rcv_stream)) < ISIS_LSP_HDR_LEN)         stream_get_getp (circuit->rcv_stream)) < ISIS_LSP_HDR_LEN)
     {      {
Line 937  process_lsp (int level, struct isis_circuit *circuit,  Line 1330  process_lsp (int level, struct isis_circuit *circuit, 
   
   /* Reference the header   */    /* Reference the header   */
   hdr = (struct isis_link_state_hdr *) STREAM_PNT (circuit->rcv_stream);    hdr = (struct isis_link_state_hdr *) STREAM_PNT (circuit->rcv_stream);
     pdu_len = ntohs (hdr->pdu_len);
   
     /* lsp length check */
     if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN) ||
         pdu_len > ISO_MTU(circuit) ||
         pdu_len > stream_get_endp (circuit->rcv_stream))
       {
         zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP length %d",
                     circuit->area->area_tag,
                     rawlspid_print (hdr->lsp_id), pdu_len);
   
         return ISIS_WARNING;
       }
   
     /*
      * Set the stream endp to PDU length, ignoring additional padding
      * introduced by transport chips.
      */
     if (pdu_len < stream_get_endp (circuit->rcv_stream))
       stream_set_endp (circuit->rcv_stream, pdu_len);
   
   if (isis->debugs & DEBUG_UPDATE_PACKETS)    if (isis->debugs & DEBUG_UPDATE_PACKETS)
     {      {
       zlog_debug ("ISIS-Upd (%s): Rcvd L%d LSP %s, seq 0x%08x, cksum 0x%04x, "        zlog_debug ("ISIS-Upd (%s): Rcvd L%d LSP %s, seq 0x%08x, cksum 0x%04x, "
                  "lifetime %us, len %lu, on %s",                  "lifetime %us, len %u, on %s",
                   circuit->area->area_tag,                    circuit->area->area_tag,
                   level,                    level,
                   rawlspid_print (hdr->lsp_id),                    rawlspid_print (hdr->lsp_id),
                   ntohl (hdr->seq_num),                    ntohl (hdr->seq_num),
                   ntohs (hdr->checksum),                    ntohs (hdr->checksum),
                   ntohs (hdr->rem_lifetime),                    ntohs (hdr->rem_lifetime),
                  /* FIXME: use %z when we stop supporting old compilers. */                  pdu_len,
                  (unsigned long) stream_get_endp (circuit->rcv_stream),  
                   circuit->interface->name);                    circuit->interface->name);
     }      }
   
  assert (ntohs (hdr->pdu_len) > ISIS_LSP_HDR_LEN);  /* lsp is_type check */
   if ((hdr->lsp_bits & IS_LEVEL_1_AND_2) != IS_LEVEL_1 &&
       (hdr->lsp_bits & IS_LEVEL_1_AND_2) != IS_LEVEL_1_AND_2)
     {
       zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP is type %x",
                   circuit->area->area_tag,
                   rawlspid_print (hdr->lsp_id), hdr->lsp_bits);
       /* continue as per RFC1122 Be liberal in what you accept, and
        * conservative in what you send */
     }
   
   /* Checksum sanity check - FIXME: move to correct place */    /* Checksum sanity check - FIXME: move to correct place */
   /* 12 = sysid+pdu+remtime */    /* 12 = sysid+pdu+remtime */
   if (iso_csum_verify (STREAM_PNT (circuit->rcv_stream) + 4,    if (iso_csum_verify (STREAM_PNT (circuit->rcv_stream) + 4,
                       ntohs (hdr->pdu_len) - 12, &hdr->checksum))                       pdu_len - 12, &hdr->checksum))
     {      {
       zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP checksum 0x%04x",        zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP checksum 0x%04x",
                   circuit->area->area_tag,                    circuit->area->area_tag,
Line 979  process_lsp (int level, struct isis_circuit *circuit,  Line 1400  process_lsp (int level, struct isis_circuit *circuit, 
     }      }
   
   /* 7.3.15.1 a) 2,3 - manualL2OnlyMode not implemented */    /* 7.3.15.1 a) 2,3 - manualL2OnlyMode not implemented */
  if (!accept_level (level, circuit->circuit_is_type))  if (!accept_level (level, circuit->is_type))
     {      {
       zlog_debug ("ISIS-Upd (%s): LSP %s received at level %d over circuit of"        zlog_debug ("ISIS-Upd (%s): LSP %s received at level %d over circuit of"
                   " type %s",                    " type %s",
                   circuit->area->area_tag,                    circuit->area->area_tag,
                   rawlspid_print (hdr->lsp_id),                    rawlspid_print (hdr->lsp_id),
                  level, circuit_t2string (circuit->circuit_is_type));                  level, circuit_t2string (circuit->is_type));
   
       return ISIS_WARNING;        return ISIS_WARNING;
     }      }
Line 995  process_lsp (int level, struct isis_circuit *circuit,  Line 1416  process_lsp (int level, struct isis_circuit *circuit, 
   /* 7.3.15.1 a) 5 - maximum area match, can be ommited since we only use 3 */    /* 7.3.15.1 a) 5 - maximum area match, can be ommited since we only use 3 */
   
   /* 7.3.15.1 a) 7 - password check */    /* 7.3.15.1 a) 7 - password check */
  (level == ISIS_LEVEL1) ? (passwd = &circuit->area->area_passwd) :  (level == IS_LEVEL_1) ? (passwd = &circuit->area->area_passwd) :
    (passwd = &circuit->area->domain_passwd);                          (passwd = &circuit->area->domain_passwd);
   if (passwd->type)    if (passwd->type)
     {      {
      if (isis_lsp_authinfo_check (circuit->rcv_stream, circuit->area,      if (lsp_authentication_check (circuit->rcv_stream, circuit->area,
                                   ntohs (hdr->pdu_len), passwd))                                    level, passwd))
         {          {
           isis_event_auth_failure (circuit->area->area_tag,            isis_event_auth_failure (circuit->area->area_tag,
                                    "LSP authentication failure", hdr->lsp_id);                                     "LSP authentication failure", hdr->lsp_id);
Line 1021  process_lsp (int level, struct isis_circuit *circuit,  Line 1442  process_lsp (int level, struct isis_circuit *circuit, 
   
   /* 7.3.15.1 a) 6 - Must check that we have an adjacency of the same level  */    /* 7.3.15.1 a) 6 - Must check that we have an adjacency of the same level  */
   /* for broadcast circuits, snpa should be compared */    /* for broadcast circuits, snpa should be compared */
   /* FIXME : Point To Point */  
   
   if (circuit->circ_type == CIRCUIT_T_BROADCAST)    if (circuit->circ_type == CIRCUIT_T_BROADCAST)
     {      {
Line 1038  process_lsp (int level, struct isis_circuit *circuit,  Line 1458  process_lsp (int level, struct isis_circuit *circuit, 
           return ISIS_WARNING;  /* Silently discard */            return ISIS_WARNING;  /* Silently discard */
         }          }
     }      }
   
   /* for non broadcast, we just need to find same level adj */    /* for non broadcast, we just need to find same level adj */
   else    else
     {      {
Line 1049  process_lsp (int level, struct isis_circuit *circuit,  Line 1468  process_lsp (int level, struct isis_circuit *circuit, 
         }          }
       else        else
         {          {
          if (((level == 1) &&          if (((level == IS_LEVEL_1) &&
                (circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL2)) ||                 (circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL2)) ||
              ((level == 2) &&              ((level == IS_LEVEL_2) &&
                (circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL1)))                 (circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL1)))
             return ISIS_WARNING;        /* Silently discard */              return ISIS_WARNING;        /* Silently discard */
             adj = circuit->u.p2p.neighbor;
         }          }
     }      }
   
 dontcheckadj:  dontcheckadj:
   /* 7.3.15.1 a) 7 - Passwords for level 1 - not implemented  */    /* 7.3.15.1 a) 7 - Passwords for level 1 - not implemented  */
   
Line 1063  dontcheckadj: Line 1484  dontcheckadj:
   
   /* 7.3.15.1 a) 9 - OriginatingLSPBufferSize - not implemented  FIXME: do it */    /* 7.3.15.1 a) 9 - OriginatingLSPBufferSize - not implemented  FIXME: do it */
   
     /* 7.3.16.2 - If this is an LSP from another IS with identical seq_num but
      *            wrong checksum, initiate a purge. */
     if (lsp
         && (lsp->lsp_header->seq_num == hdr->seq_num)
         && (lsp->lsp_header->checksum != hdr->checksum))
       {
         zlog_warn("ISIS-Upd (%s): LSP %s seq 0x%08x with confused checksum received.",
                   circuit->area->area_tag, rawlspid_print(hdr->lsp_id),
                   ntohl(hdr->seq_num));
         hdr->rem_lifetime = 0;
         lsp_confusion = 1;
       }
     else
       lsp_confusion = 0;
   
   /* 7.3.15.1 b) - If the remaining life time is 0, we perform 7.3.16.4 */    /* 7.3.15.1 b) - If the remaining life time is 0, we perform 7.3.16.4 */
   if (hdr->rem_lifetime == 0)    if (hdr->rem_lifetime == 0)
     {      {
Line 1082  dontcheckadj: Line 1518  dontcheckadj:
               /* 7.3.16.4 b) 1)  */                /* 7.3.16.4 b) 1)  */
               if (comp == LSP_NEWER)                if (comp == LSP_NEWER)
                 {                  {
                  lsp_update (lsp, hdr, circuit->rcv_stream, circuit->area,                  lsp_update (lsp, circuit->rcv_stream, circuit->area, level);
                              level); 
                   /* ii */                    /* ii */
                  ISIS_FLAGS_SET_ALL (lsp->SRMflags);                  lsp_set_all_srmflags (lsp);
                  /* iii */ 
                  ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); 
                   /* v */                    /* v */
                   ISIS_FLAGS_CLEAR_ALL (lsp->SSNflags); /* FIXME: OTHER than c */                    ISIS_FLAGS_CLEAR_ALL (lsp->SSNflags); /* FIXME: OTHER than c */
                   /* iv */  
                   if (circuit->circ_type != CIRCUIT_T_BROADCAST)  
                     ISIS_SET_FLAG (lsp->SSNflags, circuit);  
   
                     /* For the case of lsp confusion, flood the purge back to its
                      * originator so that it can react. Otherwise, don't reflood
                      * through incoming circuit as usual */
                     if (!lsp_confusion)
                       {
                         /* iii */
                         ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
                         /* iv */
                         if (circuit->circ_type != CIRCUIT_T_BROADCAST)
                           ISIS_SET_FLAG (lsp->SSNflags, circuit);
                       }
                 }               /* 7.3.16.4 b) 2) */                  }               /* 7.3.16.4 b) 2) */
               else if (comp == LSP_EQUAL)                else if (comp == LSP_EQUAL)
                 {                  {
Line 1109  dontcheckadj: Line 1550  dontcheckadj:
                   ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);                    ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
                 }                  }
             }              }
          else          else if (lsp->lsp_header->rem_lifetime != 0)
            {            {
              /* our own LSP -> 7.3.16.4 c) */              /* our own LSP -> 7.3.16.4 c) */
              if (LSP_PSEUDO_ID (lsp->lsp_header->lsp_id) !=              if (comp == LSP_NEWER)
                  circuit->circuit_id                {
                  || (LSP_PSEUDO_ID (lsp->lsp_header->lsp_id) ==                  lsp_inc_seqnum (lsp, ntohl (hdr->seq_num));
                      circuit->circuit_id                  lsp_set_all_srmflags (lsp);
                      && circuit->u.bc.is_dr[level - 1] == 1))                }
                {              else
                  lsp->lsp_header->seq_num = htonl (ntohl (hdr->seq_num) + 1);                {
                  if (isis->debugs & DEBUG_UPDATE_PACKETS)                  ISIS_SET_FLAG (lsp->SRMflags, circuit);
                    zlog_debug ("LSP LEN: %d",                  ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
                                ntohs (lsp->lsp_header->pdu_len));                }
                  fletcher_checksum (STREAM_DATA (lsp->pdu) + 12,              if (isis->debugs & DEBUG_UPDATE_PACKETS)
                                   ntohs (lsp->lsp_header->pdu_len) - 12, 12);                zlog_debug ("ISIS-Upd (%s): (1) re-originating LSP %s new "
                  ISIS_FLAGS_SET_ALL (lsp->SRMflags);                            "seq 0x%08x", circuit->area->area_tag,
                  if (isis->debugs & DEBUG_UPDATE_PACKETS)                            rawlspid_print (hdr->lsp_id),
                    zlog_debug ("ISIS-Upd (%s): (1) re-originating LSP %s new "                            ntohl (lsp->lsp_header->seq_num));
                                "seq 0x%08x", circuit->area->area_tag,            }
                                rawlspid_print (hdr->lsp_id), 
                                ntohl (lsp->lsp_header->seq_num)); 
                  lsp->lsp_header->rem_lifetime = 
                    htons (isis_jitter 
                           (circuit->area->max_lsp_lifetime[level - 1], 
                            MAX_AGE_JITTER)); 
                } 
              else 
                { 
                  /* Got purge for own pseudo-lsp, and we are not DR  */ 
                  lsp_purge_dr (lsp->lsp_header->lsp_id, circuit, level); 
                } 
            } 
         }          }
       return retval;        return retval;
     }      }
Line 1151  dontcheckadj: Line 1579  dontcheckadj:
       if (!lsp)        if (!lsp)
         {          {
           /* 7.3.16.4: initiate a purge */            /* 7.3.16.4: initiate a purge */
          lsp_purge_non_exist (hdr, circuit->area);          lsp_purge_non_exist(level, hdr, circuit->area);
           return ISIS_OK;            return ISIS_OK;
         }          }
       /* 7.3.15.1 d) - If this is our own lsp and we have it */        /* 7.3.15.1 d) - If this is our own lsp and we have it */
Line 1160  dontcheckadj: Line 1588  dontcheckadj:
        * has information that the current sequence number for source S is         * has information that the current sequence number for source S is
        * "greater" than that held by S, ... */         * "greater" than that held by S, ... */
   
      else if (ntohl (hdr->seq_num) > ntohl (lsp->lsp_header->seq_num))      if (ntohl (hdr->seq_num) > ntohl (lsp->lsp_header->seq_num))
         {          {
           /* 7.3.16.1  */            /* 7.3.16.1  */
          lsp->lsp_header->seq_num = htonl (ntohl (hdr->seq_num) + 1);          lsp_inc_seqnum (lsp, ntohl (hdr->seq_num));
 
          fletcher_checksum (STREAM_DATA (lsp->pdu) + 12, 
                           ntohs (lsp->lsp_header->pdu_len) - 12, 12); 
 
          ISIS_FLAGS_SET_ALL (lsp->SRMflags); 
           if (isis->debugs & DEBUG_UPDATE_PACKETS)            if (isis->debugs & DEBUG_UPDATE_PACKETS)
             zlog_debug ("ISIS-Upd (%s): (2) re-originating LSP %s new seq "              zlog_debug ("ISIS-Upd (%s): (2) re-originating LSP %s new seq "
                         "0x%08x", circuit->area->area_tag,                          "0x%08x", circuit->area->area_tag,
                         rawlspid_print (hdr->lsp_id),                          rawlspid_print (hdr->lsp_id),
                         ntohl (lsp->lsp_header->seq_num));                          ntohl (lsp->lsp_header->seq_num));
           lsp->lsp_header->rem_lifetime =  
             htons (isis_jitter  
                    (circuit->area->max_lsp_lifetime[level - 1],  
                     MAX_AGE_JITTER));  
         }          }
         /* If the received LSP is older or equal,
          * resend the LSP which will act as ACK */
         lsp_set_all_srmflags (lsp);
     }      }
   else    else
     {      {
Line 1187  dontcheckadj: Line 1609  dontcheckadj:
       /* 7.3.15.1 e) 1) LSP newer than the one in db or no LSP in db */        /* 7.3.15.1 e) 1) LSP newer than the one in db or no LSP in db */
       if ((!lsp || comp == LSP_NEWER))        if ((!lsp || comp == LSP_NEWER))
         {          {
           /* i */  
           if (lsp)  
             {  
 #ifdef EXTREME_DEBUG  
               zlog_debug ("level %d number is - %ld", level,  
                           circuit->area->lspdb[level - 1]->dict_nodecount);  
 #endif /* EXTREME DEBUG */  
               lsp_search_and_destroy (hdr->lsp_id,  
                                       circuit->area->lspdb[level - 1]);  
               /* exists, so we overwrite */  
 #ifdef EXTREME_DEBUG  
               zlog_debug ("level %d number is - %ld", level,  
                           circuit->area->lspdb[level - 1]->dict_nodecount);  
 #endif /* EXTREME DEBUG */  
             }  
           /*            /*
            * If this lsp is a frag, need to see if we have zero lsp present             * If this lsp is a frag, need to see if we have zero lsp present
            */             */
Line 1212  dontcheckadj: Line 1619  dontcheckadj:
               lsp0 = lsp_search (lspid, circuit->area->lspdb[level - 1]);                lsp0 = lsp_search (lspid, circuit->area->lspdb[level - 1]);
               if (!lsp0)                if (!lsp0)
                 {                  {
                  zlog_debug ("Got lsp frag, while zero lsp not database");                  zlog_debug ("Got lsp frag, while zero lsp not in database");
                   return ISIS_OK;                    return ISIS_OK;
                 }                  }
             }              }
          lsp =          /* i */
            lsp_new_from_stream_ptr (circuit->rcv_stream,          if (!lsp)
                                     ntohs (hdr->pdu_len), lsp0,            {
                                     circuit->area);              lsp = lsp_new_from_stream_ptr (circuit->rcv_stream,
          lsp->level = level;                                             pdu_len, lsp0,
          lsp->adj = adj;                                             circuit->area, level);
          lsp_insert (lsp, circuit->area->lspdb[level - 1]);              lsp_insert (lsp, circuit->area->lspdb[level - 1]);
             }
           else /* exists, so we overwrite */
             {
               lsp_update (lsp, circuit->rcv_stream, circuit->area, level);
             }
           /* ii */            /* ii */
          ISIS_FLAGS_SET_ALL (lsp->SRMflags);          lsp_set_all_srmflags (lsp);
           /* iii */            /* iii */
           ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);            ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
   
Line 1237  dontcheckadj: Line 1649  dontcheckadj:
       else if (comp == LSP_EQUAL)        else if (comp == LSP_EQUAL)
         {          {
           ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);            ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
          lsp_update (lsp, hdr, circuit->rcv_stream, circuit->area, level);          lsp_update (lsp, circuit->rcv_stream, circuit->area, level);
           if (circuit->circ_type != CIRCUIT_T_BROADCAST)            if (circuit->circ_type != CIRCUIT_T_BROADCAST)
            {            ISIS_SET_FLAG (lsp->SSNflags, circuit);
              ISIS_SET_FLAG (lsp->SSNflags, circuit); 
            } 
         }          }
       /* 7.3.15.1 e) 3) LSP older than the one in db */        /* 7.3.15.1 e) 3) LSP older than the one in db */
       else        else
Line 1250  dontcheckadj: Line 1660  dontcheckadj:
           ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);            ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
         }          }
     }      }
   if (lsp)  
     lsp->adj = adj;  
   return retval;    return retval;
 }  }
   
Line 1263  dontcheckadj: Line 1671  dontcheckadj:
   
 static int  static int
 process_snp (int snp_type, int level, struct isis_circuit *circuit,  process_snp (int snp_type, int level, struct isis_circuit *circuit,
             u_char * ssnpa)             const u_char *ssnpa)
 {  {
   int retval = ISIS_OK;    int retval = ISIS_OK;
   int cmp, own_lsp;    int cmp, own_lsp;
   char typechar = ' ';    char typechar = ' ';
  int len;  uint16_t pdu_len;
   struct isis_adjacency *adj;    struct isis_adjacency *adj;
   struct isis_complete_seqnum_hdr *chdr = NULL;    struct isis_complete_seqnum_hdr *chdr = NULL;
   struct isis_partial_seqnum_hdr *phdr = NULL;    struct isis_partial_seqnum_hdr *phdr = NULL;
  uint32_t found = 0, expected = 0;  uint32_t found = 0, expected = 0, auth_tlv_offset = 0;
   struct isis_lsp *lsp;    struct isis_lsp *lsp;
   struct lsp_entry *entry;    struct lsp_entry *entry;
   struct listnode *node, *nnode;    struct listnode *node, *nnode;
Line 1287  process_snp (int snp_type, int level, struct isis_circ Line 1695  process_snp (int snp_type, int level, struct isis_circ
       typechar = 'C';        typechar = 'C';
       chdr =        chdr =
         (struct isis_complete_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream);          (struct isis_complete_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream);
      circuit->rcv_stream->getp += ISIS_CSNP_HDRLEN;      stream_forward_getp (circuit->rcv_stream, ISIS_CSNP_HDRLEN);
      len = ntohs (chdr->pdu_len);      pdu_len = ntohs (chdr->pdu_len);
      if (len < ISIS_CSNP_HDRLEN)      if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_CSNP_HDRLEN) ||
           pdu_len > ISO_MTU(circuit) ||
           pdu_len > stream_get_endp (circuit->rcv_stream))
         {          {
          zlog_warn ("Received a CSNP with bogus length!");          zlog_warn ("Received a CSNP with bogus length %d", pdu_len);
          return ISIS_OK;          return ISIS_WARNING;
         }          }
     }      }
   else    else
Line 1300  process_snp (int snp_type, int level, struct isis_circ Line 1710  process_snp (int snp_type, int level, struct isis_circ
       typechar = 'P';        typechar = 'P';
       phdr =        phdr =
         (struct isis_partial_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream);          (struct isis_partial_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream);
      circuit->rcv_stream->getp += ISIS_PSNP_HDRLEN;      stream_forward_getp (circuit->rcv_stream, ISIS_PSNP_HDRLEN);
      len = ntohs (phdr->pdu_len);      pdu_len = ntohs (phdr->pdu_len);
      if (len < ISIS_PSNP_HDRLEN)      if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_PSNP_HDRLEN) ||
           pdu_len > ISO_MTU(circuit) ||
           pdu_len > stream_get_endp (circuit->rcv_stream))
         {          {
          zlog_warn ("Received a CSNP with bogus length!");          zlog_warn ("Received a PSNP with bogus length %d", pdu_len);
          return ISIS_OK;          return ISIS_WARNING;
         }          }
     }      }
   
     /*
      * Set the stream endp to PDU length, ignoring additional padding
      * introduced by transport chips.
      */
     if (pdu_len < stream_get_endp (circuit->rcv_stream))
       stream_set_endp (circuit->rcv_stream, pdu_len);
   
   /* 7.3.15.2 a) 1 - external domain circuit will discard snp pdu */    /* 7.3.15.2 a) 1 - external domain circuit will discard snp pdu */
   if (circuit->ext_domain)    if (circuit->ext_domain)
     {      {
Line 1322  process_snp (int snp_type, int level, struct isis_circ Line 1741  process_snp (int snp_type, int level, struct isis_circ
     }      }
   
   /* 7.3.15.2 a) 2,3 - manualL2OnlyMode not implemented */    /* 7.3.15.2 a) 2,3 - manualL2OnlyMode not implemented */
  if (!accept_level (level, circuit->circuit_is_type))  if (!accept_level (level, circuit->is_type))
     {      {
   
       zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "        zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "
Line 1331  process_snp (int snp_type, int level, struct isis_circ Line 1750  process_snp (int snp_type, int level, struct isis_circ
                   level,                    level,
                   typechar,                    typechar,
                   circuit->interface->name,                    circuit->interface->name,
                  circuit_t2string (circuit->circuit_is_type), level);                  circuit_t2string (circuit->is_type), level);
   
       return ISIS_OK;        return ISIS_OK;
     }      }
   
   /* 7.3.15.2 a) 4 - not applicable for CSNP  only PSNPs on broadcast */    /* 7.3.15.2 a) 4 - not applicable for CSNP  only PSNPs on broadcast */
   if ((snp_type == ISIS_SNP_PSNP_FLAG) &&    if ((snp_type == ISIS_SNP_PSNP_FLAG) &&
      (circuit->circ_type == CIRCUIT_T_BROADCAST))      (circuit->circ_type == CIRCUIT_T_BROADCAST) &&
       (!circuit->u.bc.is_dr[level - 1]))
     {      {
      if (!circuit->u.bc.is_dr[level - 1])      zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s, "
        {                  "skipping: we are not the DIS",
                   circuit->area->area_tag,
                   level,
                   typechar, snpa_print (ssnpa), circuit->interface->name);
   
          zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s, "      return ISIS_OK;
                      "skipping: we are not the DIS", 
                      circuit->area->area_tag, 
                      level, 
                      typechar, snpa_print (ssnpa), circuit->interface->name); 
 
          return ISIS_OK; 
        } 
     }      }
   
   /* 7.3.15.2 a) 5 - need to make sure IDLength matches - already checked */    /* 7.3.15.2 a) 5 - need to make sure IDLength matches - already checked */
Line 1380  process_snp (int snp_type, int level, struct isis_circ Line 1796  process_snp (int snp_type, int level, struct isis_circ
   else    else
     {      {
       if (!circuit->u.p2p.neighbor)        if (!circuit->u.p2p.neighbor)
        return ISIS_OK;         /* Silently discard */      {
         zlog_warn ("no p2p neighbor on circuit %s", circuit->interface->name);
         return ISIS_OK;         /* Silently discard */
       }
     }      }
   
   /* 7.3.15.2 a) 8 - Passwords for level 1 - not implemented  */    /* 7.3.15.2 a) 8 - Passwords for level 1 - not implemented  */
Line 1392  process_snp (int snp_type, int level, struct isis_circ Line 1811  process_snp (int snp_type, int level, struct isis_circ
   /* parse the SNP */    /* parse the SNP */
   expected |= TLVFLAG_LSP_ENTRIES;    expected |= TLVFLAG_LSP_ENTRIES;
   expected |= TLVFLAG_AUTH_INFO;    expected |= TLVFLAG_AUTH_INFO;
   
     auth_tlv_offset = stream_get_getp (circuit->rcv_stream);
   retval = parse_tlvs (circuit->area->area_tag,    retval = parse_tlvs (circuit->area->area_tag,
                        STREAM_PNT (circuit->rcv_stream),                         STREAM_PNT (circuit->rcv_stream),
                       len - circuit->rcv_stream->getp,                       pdu_len - stream_get_getp (circuit->rcv_stream),
                       &expected, &found, &tlvs);                       &expected, &found, &tlvs, &auth_tlv_offset);
   
   if (retval > ISIS_WARNING)    if (retval > ISIS_WARNING)
     {      {
Line 1404  process_snp (int snp_type, int level, struct isis_circ Line 1825  process_snp (int snp_type, int level, struct isis_circ
       return retval;        return retval;
     }      }
   
  if (level == 1)  if (level == IS_LEVEL_1)
     passwd = &circuit->area->area_passwd;      passwd = &circuit->area->area_passwd;
   else    else
     passwd = &circuit->area->domain_passwd;      passwd = &circuit->area->domain_passwd;
Line 1412  process_snp (int snp_type, int level, struct isis_circ Line 1833  process_snp (int snp_type, int level, struct isis_circ
   if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_RECV))    if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_RECV))
     {      {
       if (passwd->type)        if (passwd->type)
        {        {
          if (!(found & TLVFLAG_AUTH_INFO) ||          if (!(found & TLVFLAG_AUTH_INFO) ||
              authentication_check (passwd, &tlvs.auth_info))              authentication_check (&tlvs.auth_info, passwd,
            {                                    circuit->rcv_stream, auth_tlv_offset))
              isis_event_auth_failure (circuit->area->area_tag,            {
                                       "SNP authentication" " failure",              isis_event_auth_failure (circuit->area->area_tag,
                                       phdr ? phdr->source_id : chdr->source_id);                                       "SNP authentication" " failure",
              return ISIS_OK;                                       phdr ? phdr->source_id :
            }                                       chdr->source_id);
        }              free_tlvs (&tlvs);
               return ISIS_OK;
             }
         }
     }      }
   
   /* debug isis snp-packets */    /* debug isis snp-packets */
Line 1461  process_snp (int snp_type, int level, struct isis_circ Line 1885  process_snp (int snp_type, int level, struct isis_circ
             /* 7.3.15.2 b) 2) if it equals, clear SRM on p2p */              /* 7.3.15.2 b) 2) if it equals, clear SRM on p2p */
             if (cmp == LSP_EQUAL)              if (cmp == LSP_EQUAL)
               {                {
                if (circuit->circ_type != CIRCUIT_T_BROADCAST)                /* if (circuit->circ_type != CIRCUIT_T_BROADCAST) */
                  ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);                ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
                /* 7.3.15.2 b) 3) if it is older, clear SSN and set SRM */ 
               }                }
               /* 7.3.15.2 b) 3) if it is older, clear SSN and set SRM */
             else if (cmp == LSP_OLDER)              else if (cmp == LSP_OLDER)
               {                {
                 ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);                  ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
                 ISIS_SET_FLAG (lsp->SRMflags, circuit);                  ISIS_SET_FLAG (lsp->SRMflags, circuit);
               }                }
               /* 7.3.15.2 b) 4) if it is newer, set SSN and clear SRM on p2p */
             else              else
               {                {
                 /* 7.3.15.2 b) 4) if it is newer, set SSN and clear SRM  
                  * on p2p */  
                 if (own_lsp)                  if (own_lsp)
                   {                    {
                     lsp_inc_seqnum (lsp, ntohl (entry->seq_num));                      lsp_inc_seqnum (lsp, ntohl (entry->seq_num));
Line 1482  process_snp (int snp_type, int level, struct isis_circ Line 1905  process_snp (int snp_type, int level, struct isis_circ
                 else                  else
                   {                    {
                     ISIS_SET_FLAG (lsp->SSNflags, circuit);                      ISIS_SET_FLAG (lsp->SSNflags, circuit);
                    if (circuit->circ_type != CIRCUIT_T_BROADCAST)                    /* if (circuit->circ_type != CIRCUIT_T_BROADCAST) */
                      ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);                    ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
                   }                    }
               }                }
           }            }
Line 1494  process_snp (int snp_type, int level, struct isis_circ Line 1917  process_snp (int snp_type, int level, struct isis_circ
             if (entry->rem_lifetime && entry->checksum && entry->seq_num &&              if (entry->rem_lifetime && entry->checksum && entry->seq_num &&
                 memcmp (entry->lsp_id, isis->sysid, ISIS_SYS_ID_LEN))                  memcmp (entry->lsp_id, isis->sysid, ISIS_SYS_ID_LEN))
               {                {
                lsp = lsp_new (entry->lsp_id, ntohs (entry->rem_lifetime),                lsp = lsp_new(circuit->area, entry->lsp_id,
                               0, 0, entry->checksum, level);                              ntohs(entry->rem_lifetime),
                               0, 0, entry->checksum, level);
                 lsp_insert (lsp, circuit->area->lspdb[level - 1]);                  lsp_insert (lsp, circuit->area->lspdb[level - 1]);
                   ISIS_FLAGS_CLEAR_ALL (lsp->SRMflags);
                 ISIS_SET_FLAG (lsp->SSNflags, circuit);                  ISIS_SET_FLAG (lsp->SSNflags, circuit);
               }                }
           }            }
Line 1507  process_snp (int snp_type, int level, struct isis_circ Line 1932  process_snp (int snp_type, int level, struct isis_circ
   if (snp_type == ISIS_SNP_CSNP_FLAG)    if (snp_type == ISIS_SNP_CSNP_FLAG)
     {      {
       /*        /*
       * Build a list from our own LSP db bounded with start_ and stop_lsp_id       * Build a list from our own LSP db bounded with
        * start_lsp_id and stop_lsp_id
        */         */
       lsp_list = list_new ();        lsp_list = list_new ();
       lsp_build_list_nonzero_ht (chdr->start_lsp_id, chdr->stop_lsp_id,        lsp_build_list_nonzero_ht (chdr->start_lsp_id, chdr->stop_lsp_id,
Line 1530  process_snp (int snp_type, int level, struct isis_circ Line 1956  process_snp (int snp_type, int level, struct isis_circ
         }          }
       /* on remaining LSPs we set SRM (neighbor knew not of) */        /* on remaining LSPs we set SRM (neighbor knew not of) */
       for (ALL_LIST_ELEMENTS_RO (lsp_list, node, lsp))        for (ALL_LIST_ELEMENTS_RO (lsp_list, node, lsp))
       {  
         ISIS_SET_FLAG (lsp->SRMflags, circuit);          ISIS_SET_FLAG (lsp->SRMflags, circuit);
       }  
       /* lets free it */        /* lets free it */
      list_free (lsp_list);      list_delete (lsp_list);
 
     }      }
   
   free_tlvs (&tlvs);    free_tlvs (&tlvs);
Line 1542  process_snp (int snp_type, int level, struct isis_circ Line 1967  process_snp (int snp_type, int level, struct isis_circ
 }  }
   
 static int  static int
process_csnp (int level, struct isis_circuit *circuit, u_char * ssnpa)process_csnp (int level, struct isis_circuit *circuit, const u_char *ssnpa)
 {  {
     if (isis->debugs & DEBUG_SNP_PACKETS)
       {
         zlog_debug ("ISIS-Snp (%s): Rcvd L%d CSNP on %s, cirType %s, cirID %u",
                     circuit->area->area_tag, level, circuit->interface->name,
                     circuit_t2string (circuit->is_type), circuit->circuit_id);
         if (isis->debugs & DEBUG_PACKET_DUMP)
           zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
                           stream_get_endp (circuit->rcv_stream));
       }
   
   /* Sanity check - FIXME: move to correct place */    /* Sanity check - FIXME: move to correct place */
   if ((stream_get_endp (circuit->rcv_stream) -    if ((stream_get_endp (circuit->rcv_stream) -
        stream_get_getp (circuit->rcv_stream)) < ISIS_CSNP_HDRLEN)         stream_get_getp (circuit->rcv_stream)) < ISIS_CSNP_HDRLEN)
Line 1556  process_csnp (int level, struct isis_circuit *circuit, Line 1991  process_csnp (int level, struct isis_circuit *circuit,
 }  }
   
 static int  static int
process_psnp (int level, struct isis_circuit *circuit, u_char * ssnpa)process_psnp (int level, struct isis_circuit *circuit, const u_char *ssnpa)
 {  {
     if (isis->debugs & DEBUG_SNP_PACKETS)
       {
         zlog_debug ("ISIS-Snp (%s): Rcvd L%d PSNP on %s, cirType %s, cirID %u",
                     circuit->area->area_tag, level, circuit->interface->name,
                     circuit_t2string (circuit->is_type), circuit->circuit_id);
         if (isis->debugs & DEBUG_PACKET_DUMP)
           zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
                           stream_get_endp (circuit->rcv_stream));
       }
   
   if ((stream_get_endp (circuit->rcv_stream) -    if ((stream_get_endp (circuit->rcv_stream) -
        stream_get_getp (circuit->rcv_stream)) < ISIS_PSNP_HDRLEN)         stream_get_getp (circuit->rcv_stream)) < ISIS_PSNP_HDRLEN)
     {      {
      zlog_warn ("Packet too short");      zlog_warn ("Packet too short ( < %d)", ISIS_PSNP_HDRLEN);
       return ISIS_WARNING;        return ISIS_WARNING;
     }      }
   
Line 1569  process_psnp (int level, struct isis_circuit *circuit, Line 2014  process_psnp (int level, struct isis_circuit *circuit,
 }  }
   
 /*  /*
  * Process ISH  
  * ISO - 10589  
  * Section 8.2.2 - Receiving ISH PDUs by an intermediate system  
  * FIXME: sample packet dump, need to figure 0x81 - looks like NLPid  
  *           0x82       0x15    0x01    0x00    0x04    0x01    0x2c    0x59  
  *           0x38       0x08    0x47    0x00    0x01    0x00    0x02    0x00  
  *           0x03       0x00    0x81    0x01    0xcc  
  */  
 static int  
 process_is_hello (struct isis_circuit *circuit)  
 {  
   struct isis_adjacency *adj;  
   int retval = ISIS_OK;  
   u_char neigh_len;  
   u_char *sysid;  
   
   /* In this point in time we are not yet able to handle is_hellos  
    * on lan - Sorry juniper...  
    */  
   if (circuit->circ_type == CIRCUIT_T_BROADCAST)  
     return retval;  
   
   neigh_len = stream_getc (circuit->rcv_stream);  
   sysid = STREAM_PNT (circuit->rcv_stream) + neigh_len - 1 - ISIS_SYS_ID_LEN;  
   adj = circuit->u.p2p.neighbor;  
   if (!adj)  
     {  
       /* 8.2.2 */  
       adj = isis_new_adj (sysid, NULL, 0, circuit);  
       if (adj == NULL)  
         return ISIS_ERROR;  
   
       isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL);  
       adj->sys_type = ISIS_SYSTYPE_UNKNOWN;  
       circuit->u.p2p.neighbor = adj;  
     }  
   /* 8.2.2 a) */  
   if ((adj->adj_state == ISIS_ADJ_UP) && memcmp (adj->sysid, sysid,  
                                                  ISIS_SYS_ID_LEN))  
     {  
       /* 8.2.2 a) 1) FIXME: adjStateChange(down) event */  
       /* 8.2.2 a) 2) delete the adj */  
       XFREE (MTYPE_ISIS_ADJACENCY, adj);  
       /* 8.2.2 a) 3) create a new adj */  
       adj = isis_new_adj (sysid, NULL, 0, circuit);  
       if (adj == NULL)  
         return ISIS_ERROR;  
   
       /* 8.2.2 a) 3) i */  
       isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL);  
       /* 8.2.2 a) 3) ii */  
       adj->sys_type = ISIS_SYSTYPE_UNKNOWN;  
       /* 8.2.2 a) 4) quite meaningless */  
     }  
   /* 8.2.2 b) ignore on condition */  
   if ((adj->adj_state == ISIS_ADJ_INITIALIZING) &&  
       (adj->sys_type == ISIS_SYSTYPE_IS))  
     {  
       /* do nothing */  
     }  
   else  
     {  
       /* 8.2.2 c) respond with a p2p IIH */  
       send_hello (circuit, 1);  
     }  
   /* 8.2.2 d) type is IS */  
   adj->sys_type = ISIS_SYSTYPE_IS;  
   /* 8.2.2 e) FIXME: Circuit type of? */  
   
   return retval;  
 }  
   
 /*  
  * PDU Dispatcher   * PDU Dispatcher
  */   */
   
Line 1649  static int Line 2021  static int
 isis_handle_pdu (struct isis_circuit *circuit, u_char * ssnpa)  isis_handle_pdu (struct isis_circuit *circuit, u_char * ssnpa)
 {  {
   struct isis_fixed_hdr *hdr;    struct isis_fixed_hdr *hdr;
   struct esis_fixed_hdr *esis_hdr;  
   
   int retval = ISIS_OK;    int retval = ISIS_OK;
   
Line 1660  isis_handle_pdu (struct isis_circuit *circuit, u_char  Line 2031  isis_handle_pdu (struct isis_circuit *circuit, u_char 
   
   if ((hdr->idrp != ISO10589_ISIS) && (hdr->idrp != ISO9542_ESIS))    if ((hdr->idrp != ISO10589_ISIS) && (hdr->idrp != ISO9542_ESIS))
     {      {
      zlog_warn ("Not an IS-IS or ES-IS packet IDRP=%02x", hdr->idrp);      zlog_err ("Not an IS-IS or ES-IS packet IDRP=%02x", hdr->idrp);
       return ISIS_ERROR;        return ISIS_ERROR;
     }      }
   
Line 1669  isis_handle_pdu (struct isis_circuit *circuit, u_char  Line 2040  isis_handle_pdu (struct isis_circuit *circuit, u_char 
    */     */
   if (hdr->idrp == ISO9542_ESIS)    if (hdr->idrp == ISO9542_ESIS)
     {      {
      esis_hdr = (struct esis_fixed_hdr *) STREAM_DATA (circuit->rcv_stream);      zlog_err ("No support for ES-IS packet IDRP=%02x", hdr->idrp);
      stream_set_getp (circuit->rcv_stream, ESIS_FIXED_HDR_LEN);      return ISIS_ERROR;
      /* FIXME: Need to do some acceptence tests */ 
      /* example length... */ 
      switch (esis_hdr->pdu_type) 
        { 
        case ESH_PDU: 
          /* FIXME */ 
          break; 
        case ISH_PDU: 
          zlog_debug ("AN ISH PDU!!"); 
          retval = process_is_hello (circuit); 
          break; 
        default: 
          return ISIS_ERROR; 
        } 
      return retval; 
     }      }
  else  stream_set_getp (circuit->rcv_stream, ISIS_FIXED_HDR_LEN);
    {
      stream_set_getp (circuit->rcv_stream, ISIS_FIXED_HDR_LEN); 
    } 
   /*    /*
    * and then process it     * and then process it
    */     */
Line 1721  isis_handle_pdu (struct isis_circuit *circuit, u_char  Line 2075  isis_handle_pdu (struct isis_circuit *circuit, u_char 
       zlog_warn ("Unsupported ISIS version %u", hdr->version2);        zlog_warn ("Unsupported ISIS version %u", hdr->version2);
       return ISIS_WARNING;        return ISIS_WARNING;
     }      }
   
     if (circuit->is_passive)
       {
         zlog_warn ("Received ISIS PDU on passive circuit %s",
                    circuit->interface->name);
         return ISIS_WARNING;
       }
   
   /* either 3 or 0 */    /* either 3 or 0 */
   if ((hdr->max_area_addrs != 0)    if ((hdr->max_area_addrs != 0)
       && (hdr->max_area_addrs != isis->max_area_addrs))        && (hdr->max_area_addrs != isis->max_area_addrs))
Line 1781  isis_receive (struct thread *thread) Line 2143  isis_receive (struct thread *thread)
   circuit = THREAD_ARG (thread);    circuit = THREAD_ARG (thread);
   assert (circuit);    assert (circuit);
   
  if (!circuit->area)  isis_circuit_stream(circuit, &circuit->rcv_stream);
    return ISIS_OK; 
   
   if (circuit->rcv_stream == NULL)  
     circuit->rcv_stream = stream_new (ISO_MTU (circuit));  
   else  
     stream_reset (circuit->rcv_stream);  
   
   retval = circuit->rx (circuit, ssnpa);    retval = circuit->rx (circuit, ssnpa);
   circuit->t_read = NULL;    circuit->t_read = NULL;
   
Line 1798  isis_receive (struct thread *thread) Line 2154  isis_receive (struct thread *thread)
   /*     /* 
    * prepare for next packet.      * prepare for next packet. 
    */     */
  THREAD_READ_ON (master, circuit->t_read, isis_receive, circuit,  if (!circuit->is_passive)
                  circuit->fd);  {
     THREAD_READ_ON (master, circuit->t_read, isis_receive, circuit,
                     circuit->fd);
   }
   
   return retval;    return retval;
 }  }
Line 1820  isis_receive (struct thread *thread) Line 2179  isis_receive (struct thread *thread)
   
   circuit->t_read = NULL;    circuit->t_read = NULL;
   
  if (circuit->rcv_stream == NULL)  isis_circuit_stream(circuit, &circuit->rcv_stream);
    circuit->rcv_stream = stream_new (ISO_MTU (circuit)); 
  else 
    stream_reset (circuit->rcv_stream); 
   
   retval = circuit->rx (circuit, ssnpa);    retval = circuit->rx (circuit, ssnpa);
   
Line 1833  isis_receive (struct thread *thread) Line 2189  isis_receive (struct thread *thread)
   /*     /* 
    * prepare for next packet.      * prepare for next packet. 
    */     */
  circuit->t_read = thread_add_timer_msec (master, isis_receive, circuit,  if (!circuit->is_passive)
                                           listcount  {
                                           (circuit->area->circuit_list) *    circuit->t_read = thread_add_timer_msec (master, isis_receive, circuit,
                                           100);                                             listcount
                                              (circuit->area->circuit_list) *
                                              100);
   }
   
   return retval;    return retval;
 }  }
Line 1911  send_hello (struct isis_circuit *circuit, int level) Line 2270  send_hello (struct isis_circuit *circuit, int level)
   struct isis_fixed_hdr fixed_hdr;    struct isis_fixed_hdr fixed_hdr;
   struct isis_lan_hello_hdr hello_hdr;    struct isis_lan_hello_hdr hello_hdr;
   struct isis_p2p_hello_hdr p2p_hello_hdr;    struct isis_p2p_hello_hdr p2p_hello_hdr;
  unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
   size_t len_pointer, length, auth_tlv_offset = 0;
   u_int32_t interval;    u_int32_t interval;
   unsigned long len_pointer, length;  
   int retval;    int retval;
   
     if (circuit->is_passive)
       return ISIS_OK;
   
   if (circuit->interface->mtu == 0)    if (circuit->interface->mtu == 0)
     {      {
       zlog_warn ("circuit has zero MTU");        zlog_warn ("circuit has zero MTU");
       return ISIS_WARNING;        return ISIS_WARNING;
     }      }
   
  if (!circuit->snd_stream)  isis_circuit_stream(circuit, &circuit->snd_stream);
    circuit->snd_stream = stream_new (ISO_MTU (circuit)); 
  else 
    stream_reset (circuit->snd_stream); 
   
   if (circuit->circ_type == CIRCUIT_T_BROADCAST)    if (circuit->circ_type == CIRCUIT_T_BROADCAST)
    if (level == 1)    if (level == IS_LEVEL_1)
       fill_fixed_hdr_andstream (&fixed_hdr, L1_LAN_HELLO,        fill_fixed_hdr_andstream (&fixed_hdr, L1_LAN_HELLO,
                                 circuit->snd_stream);                                  circuit->snd_stream);
     else      else
Line 1943  send_hello (struct isis_circuit *circuit, int level) Line 2302  send_hello (struct isis_circuit *circuit, int level)
   memset (&hello_hdr, 0, sizeof (struct isis_lan_hello_hdr));    memset (&hello_hdr, 0, sizeof (struct isis_lan_hello_hdr));
   interval = circuit->hello_multiplier[level - 1] *    interval = circuit->hello_multiplier[level - 1] *
     circuit->hello_interval[level - 1];      circuit->hello_interval[level - 1];
   /* If we are the DIS then hello interval is divided by three, as is the hold-timer */  
   if (circuit->u.bc.is_dr[level - 1])  
     interval=interval/3;  
   if (interval > USHRT_MAX)    if (interval > USHRT_MAX)
     interval = USHRT_MAX;      interval = USHRT_MAX;
  hello_hdr.circuit_t = circuit->circuit_is_type;  hello_hdr.circuit_t = circuit->is_type;
   memcpy (hello_hdr.source_id, isis->sysid, ISIS_SYS_ID_LEN);    memcpy (hello_hdr.source_id, isis->sysid, ISIS_SYS_ID_LEN);
   hello_hdr.hold_time = htons ((u_int16_t) interval);    hello_hdr.hold_time = htons ((u_int16_t) interval);
   
Line 1965  send_hello (struct isis_circuit *circuit, int level) Line 2321  send_hello (struct isis_circuit *circuit, int level)
     }      }
   else    else
     {      {
      hello_hdr.prio = circuit->u.bc.priority[level - 1];      hello_hdr.prio = circuit->priority[level - 1];
      if (level == 1 && circuit->u.bc.l1_desig_is)      if (level == IS_LEVEL_1)
         {          {
           memcpy (hello_hdr.lan_id, circuit->u.bc.l1_desig_is,            memcpy (hello_hdr.lan_id, circuit->u.bc.l1_desig_is,
                   ISIS_SYS_ID_LEN + 1);                    ISIS_SYS_ID_LEN + 1);
         }          }
      else if (level == 2 && circuit->u.bc.l2_desig_is)      else if (level == IS_LEVEL_2)
         {          {
           memcpy (hello_hdr.lan_id, circuit->u.bc.l2_desig_is,            memcpy (hello_hdr.lan_id, circuit->u.bc.l2_desig_is,
                   ISIS_SYS_ID_LEN + 1);                    ISIS_SYS_ID_LEN + 1);
Line 1980  send_hello (struct isis_circuit *circuit, int level) Line 2336  send_hello (struct isis_circuit *circuit, int level)
     }      }
   
   /*    /*
   * Then the variable length part    * Then the variable length part.
    */     */
   
   /* add circuit password */    /* add circuit password */
  if (circuit->passwd.type)  switch (circuit->passwd.type)
    if (tlv_add_authinfo (circuit->passwd.type, circuit->passwd.len,  {
                          circuit->passwd.passwd, circuit->snd_stream))    /* Cleartext */
      return ISIS_WARNING;    case ISIS_PASSWD_TYPE_CLEARTXT:
       if (tlv_add_authinfo (circuit->passwd.type, circuit->passwd.len,
                             circuit->passwd.passwd, circuit->snd_stream))
         return ISIS_WARNING;
       break;
 
     /* HMAC MD5 */
     case ISIS_PASSWD_TYPE_HMAC_MD5:
       /* Remember where TLV is written so we can later overwrite the MD5 hash */
       auth_tlv_offset = stream_get_endp (circuit->snd_stream);
       memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
       if (tlv_add_authinfo (circuit->passwd.type, ISIS_AUTH_MD5_SIZE,
                             hmac_md5_hash, circuit->snd_stream))
         return ISIS_WARNING;
       break;
 
     default:
       break;
   }
 
   /*  Area Addresses TLV */    /*  Area Addresses TLV */
  assert (circuit->area);  if (listcount (circuit->area->area_addrs) == 0)
  if (circuit->area->area_addrs && circuit->area->area_addrs->count > 0)    return ISIS_WARNING;
    if (tlv_add_area_addrs (circuit->area->area_addrs, circuit->snd_stream))  if (tlv_add_area_addrs (circuit->area->area_addrs, circuit->snd_stream))
      return ISIS_WARNING;    return ISIS_WARNING;
   
   /*  LAN Neighbors TLV */    /*  LAN Neighbors TLV */
   if (circuit->circ_type == CIRCUIT_T_BROADCAST)    if (circuit->circ_type == CIRCUIT_T_BROADCAST)
     {      {
      if (level == 1 && circuit->u.bc.lan_neighs[0]->count > 0)      if (level == IS_LEVEL_1 && circuit->u.bc.lan_neighs[0] &&
           listcount (circuit->u.bc.lan_neighs[0]) > 0)
         if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[0],          if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[0],
                                 circuit->snd_stream))                                  circuit->snd_stream))
           return ISIS_WARNING;            return ISIS_WARNING;
      if (level == 2 && circuit->u.bc.lan_neighs[1]->count > 0)      if (level == IS_LEVEL_2 && circuit->u.bc.lan_neighs[1] &&
           listcount (circuit->u.bc.lan_neighs[1]) > 0)
         if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[1],          if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[1],
                                 circuit->snd_stream))                                  circuit->snd_stream))
           return ISIS_WARNING;            return ISIS_WARNING;
Line 2011  send_hello (struct isis_circuit *circuit, int level) Line 2389  send_hello (struct isis_circuit *circuit, int level)
     if (tlv_add_nlpid (&circuit->nlpids, circuit->snd_stream))      if (tlv_add_nlpid (&circuit->nlpids, circuit->snd_stream))
       return ISIS_WARNING;        return ISIS_WARNING;
   /* IP interface Address TLV */    /* IP interface Address TLV */
  if (circuit->ip_router && circuit->ip_addrs && circuit->ip_addrs->count > 0)  if (circuit->ip_router && circuit->ip_addrs &&
       listcount (circuit->ip_addrs) > 0)
     if (tlv_add_ip_addrs (circuit->ip_addrs, circuit->snd_stream))      if (tlv_add_ip_addrs (circuit->ip_addrs, circuit->snd_stream))
       return ISIS_WARNING;        return ISIS_WARNING;
   
 #ifdef HAVE_IPV6  #ifdef HAVE_IPV6
   /* IPv6 Interface Address TLV */    /* IPv6 Interface Address TLV */
   if (circuit->ipv6_router && circuit->ipv6_link &&    if (circuit->ipv6_router && circuit->ipv6_link &&
      circuit->ipv6_link->count > 0)      listcount (circuit->ipv6_link) > 0)
     if (tlv_add_ipv6_addrs (circuit->ipv6_link, circuit->snd_stream))      if (tlv_add_ipv6_addrs (circuit->ipv6_link, circuit->snd_stream))
       return ISIS_WARNING;        return ISIS_WARNING;
 #endif /* HAVE_IPV6 */  #endif /* HAVE_IPV6 */
   
  if (circuit->u.bc.pad_hellos)  if (circuit->pad_hellos)
     if (tlv_add_padding (circuit->snd_stream))      if (tlv_add_padding (circuit->snd_stream))
       return ISIS_WARNING;        return ISIS_WARNING;
   
Line 2031  send_hello (struct isis_circuit *circuit, int level) Line 2410  send_hello (struct isis_circuit *circuit, int level)
   /* Update PDU length */    /* Update PDU length */
   stream_putw_at (circuit->snd_stream, len_pointer, (u_int16_t) length);    stream_putw_at (circuit->snd_stream, len_pointer, (u_int16_t) length);
   
  retval = circuit->tx (circuit, level);  /* For HMAC MD5 we need to compute the md5 hash and store it */
  if (retval)  if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5)
    zlog_warn ("sending of LAN Level %d Hello failed", level);    {
       hmac_md5 (STREAM_DATA (circuit->snd_stream),
                 stream_get_endp (circuit->snd_stream),
                 (unsigned char *) &circuit->passwd.passwd, circuit->passwd.len,
                 (unsigned char *) &hmac_md5_hash);
       /* Copy the hash into the stream */
       memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3,
               hmac_md5_hash, ISIS_AUTH_MD5_SIZE);
     }
   
   /* DEBUG_ADJ_PACKETS */  
   if (isis->debugs & DEBUG_ADJ_PACKETS)    if (isis->debugs & DEBUG_ADJ_PACKETS)
     {      {
       if (circuit->circ_type == CIRCUIT_T_BROADCAST)        if (circuit->circ_type == CIRCUIT_T_BROADCAST)
         {          {
          zlog_debug ("ISIS-Adj (%s): Sent L%d LAN IIH on %s, length %ld",          zlog_debug ("ISIS-Adj (%s): Sending L%d LAN IIH on %s, length %zd",
                       circuit->area->area_tag, level, circuit->interface->name,                        circuit->area->area_tag, level, circuit->interface->name,
                      /* FIXME: use %z when we stop supporting old compilers. */                      length);
                      (unsigned long) STREAM_SIZE (circuit->snd_stream)); 
         }          }
       else        else
         {          {
          zlog_debug ("ISIS-Adj (%s): Sent P2P IIH on %s, length %ld",          zlog_debug ("ISIS-Adj (%s): Sending P2P IIH on %s, length %zd",
                       circuit->area->area_tag, circuit->interface->name,                        circuit->area->area_tag, circuit->interface->name,
                      /* FIXME: use %z when we stop supporting old compilers. */                      length);
                      (unsigned long) STREAM_SIZE (circuit->snd_stream)); 
         }          }
         if (isis->debugs & DEBUG_PACKET_DUMP)
           zlog_dump_data (STREAM_DATA (circuit->snd_stream),
                           stream_get_endp (circuit->snd_stream));
     }      }
   
     retval = circuit->tx (circuit, level);
     if (retval != ISIS_OK)
       zlog_err ("ISIS-Adj (%s): Send L%d IIH on %s failed",
                 circuit->area->area_tag, level, circuit->interface->name);
   
   return retval;    return retval;
 }  }
   
 static int  
 send_lan_hello (struct isis_circuit *circuit, int level)  
 {  
   return send_hello (circuit, level);  
 }  
   
 int  int
 send_lan_l1_hello (struct thread *thread)  send_lan_l1_hello (struct thread *thread)
 {  {
   struct isis_circuit *circuit;    struct isis_circuit *circuit;
   int retval;    int retval;
   unsigned long next_hello;  
   
   circuit = THREAD_ARG (thread);    circuit = THREAD_ARG (thread);
   assert (circuit);    assert (circuit);
   
   if (!circuit->area) {  
     return ISIS_OK;  
   }  
   
   /* Pseudonode sends hellos three times more than the other nodes */  
   if (circuit->u.bc.is_dr[0])  
     next_hello=circuit->hello_interval[0]/3+1;  
   else  
     next_hello=circuit->hello_interval[0];  
   
   circuit->u.bc.t_send_lan_hello[0] = NULL;    circuit->u.bc.t_send_lan_hello[0] = NULL;
   
     if (!(circuit->area->is_type & IS_LEVEL_1))
       {
         zlog_warn ("ISIS-Hello (%s): Trying to send L1 IIH in L2-only area",
                    circuit->area->area_tag);
         return 1;
       }
   
   if (circuit->u.bc.run_dr_elect[0])    if (circuit->u.bc.run_dr_elect[0])
     retval = isis_dr_elect (circuit, 1);      retval = isis_dr_elect (circuit, 1);
   
  retval = send_lan_hello (circuit, 1);  retval = send_hello (circuit, 1);
   
   /* set next timer thread */    /* set next timer thread */
   THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[0],    THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[0],
                    send_lan_l1_hello, circuit,                     send_lan_l1_hello, circuit,
                  isis_jitter (next_hello, IIH_JITTER));                   isis_jitter (circuit->hello_interval[0], IIH_JITTER));
   
   return retval;    return retval;
 }  }
Line 2103  send_lan_l2_hello (struct thread *thread) Line 2484  send_lan_l2_hello (struct thread *thread)
 {  {
   struct isis_circuit *circuit;    struct isis_circuit *circuit;
   int retval;    int retval;
   unsigned long next_hello;  
   
   circuit = THREAD_ARG (thread);    circuit = THREAD_ARG (thread);
   assert (circuit);    assert (circuit);
   
   if (!circuit->area) {  
     return ISIS_OK;  
   }  
   
   /* Pseudonode sends hellos three times more than the other nodes */  
   if (circuit->u.bc.is_dr[1])  
     next_hello=circuit->hello_interval[1]/3+1;  
   else  
     next_hello=circuit->hello_interval[1];  
   
   circuit->u.bc.t_send_lan_hello[1] = NULL;    circuit->u.bc.t_send_lan_hello[1] = NULL;
   
     if (!(circuit->area->is_type & IS_LEVEL_2))
       {
         zlog_warn ("ISIS-Hello (%s): Trying to send L2 IIH in L1 area",
                    circuit->area->area_tag);
         return 1;
       }
   
   if (circuit->u.bc.run_dr_elect[1])    if (circuit->u.bc.run_dr_elect[1])
     retval = isis_dr_elect (circuit, 2);      retval = isis_dr_elect (circuit, 2);
   
  retval = send_lan_hello (circuit, 2);  retval = send_hello (circuit, 2);
   
   /* set next timer thread */    /* set next timer thread */
   THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[1],    THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[1],
                    send_lan_l2_hello, circuit,                     send_lan_l2_hello, circuit,
                  isis_jitter (next_hello, IIH_JITTER));                   isis_jitter (circuit->hello_interval[1], IIH_JITTER));
   
   return retval;    return retval;
 }  }
Line 2158  build_csnp (int level, u_char * start, u_char * stop,  Line 2534  build_csnp (int level, u_char * start, u_char * stop, 
 {  {
   struct isis_fixed_hdr fixed_hdr;    struct isis_fixed_hdr fixed_hdr;
   struct isis_passwd *passwd;    struct isis_passwd *passwd;
   int retval = ISIS_OK;  
   unsigned long lenp;    unsigned long lenp;
   u_int16_t length;    u_int16_t length;
     unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
     unsigned long auth_tlv_offset = 0;
     int retval = ISIS_OK;
   
  if (level == 1)  isis_circuit_stream(circuit, &circuit->snd_stream);
 
   if (level == IS_LEVEL_1)
     fill_fixed_hdr_andstream (&fixed_hdr, L1_COMPLETE_SEQ_NUM,      fill_fixed_hdr_andstream (&fixed_hdr, L1_COMPLETE_SEQ_NUM,
                               circuit->snd_stream);                                circuit->snd_stream);
   else    else
Line 2186  build_csnp (int level, u_char * start, u_char * stop,  Line 2566  build_csnp (int level, u_char * start, u_char * stop, 
   /*    /*
    * And TLVs     * And TLVs
    */     */
  if (level == 1)  if (level == IS_LEVEL_1)
     passwd = &circuit->area->area_passwd;      passwd = &circuit->area->area_passwd;
   else    else
     passwd = &circuit->area->domain_passwd;      passwd = &circuit->area->domain_passwd;
   
   if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND))    if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND))
    if (passwd->type)  {
      retval = tlv_add_authinfo (passwd->type, passwd->len,    switch (passwd->type)
                                 passwd->passwd, circuit->snd_stream); 
 
  if (!retval && lsps) 
     {      {
      retval = tlv_add_lsp_entries (lsps, circuit->snd_stream);      /* Cleartext */
       case ISIS_PASSWD_TYPE_CLEARTXT:
         if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT, passwd->len,
                               passwd->passwd, circuit->snd_stream))
           return ISIS_WARNING;
         break;
 
         /* HMAC MD5 */
       case ISIS_PASSWD_TYPE_HMAC_MD5:
         /* Remember where TLV is written so we can later overwrite the MD5 hash */
         auth_tlv_offset = stream_get_endp (circuit->snd_stream);
         memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
         if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5, ISIS_AUTH_MD5_SIZE,
                               hmac_md5_hash, circuit->snd_stream))
           return ISIS_WARNING;
         break;
 
       default:
         break;
     }      }
     }
   
     retval = tlv_add_lsp_entries (lsps, circuit->snd_stream);
     if (retval != ISIS_OK)
       return retval;
   
   length = (u_int16_t) stream_get_endp (circuit->snd_stream);    length = (u_int16_t) stream_get_endp (circuit->snd_stream);
   assert (length >= ISIS_CSNP_HDRLEN);  
   /* Update PU length */    /* Update PU length */
   stream_putw_at (circuit->snd_stream, lenp, length);    stream_putw_at (circuit->snd_stream, lenp, length);
   
     /* For HMAC MD5 we need to compute the md5 hash and store it */
     if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND) &&
         passwd->type == ISIS_PASSWD_TYPE_HMAC_MD5)
       {
         hmac_md5 (STREAM_DATA (circuit->snd_stream),
                   stream_get_endp(circuit->snd_stream),
                   (unsigned char *) &passwd->passwd, passwd->len,
                   (unsigned char *) &hmac_md5_hash);
         /* Copy the hash into the stream */
         memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3,
                 hmac_md5_hash, ISIS_AUTH_MD5_SIZE);
       }
   
   return retval;    return retval;
 }  }
   
 /*  /*
    * Count the maximum number of lsps that can be accomodated by a given size.
    */
   static uint16_t
   get_max_lsp_count (uint16_t size)
   {
     uint16_t tlv_count;
     uint16_t lsp_count;
     uint16_t remaining_size;
   
     /* First count the full size TLVs */
     tlv_count = size / MAX_LSP_ENTRIES_TLV_SIZE;
     lsp_count = tlv_count * (MAX_LSP_ENTRIES_TLV_SIZE / LSP_ENTRIES_LEN);
   
     /* The last TLV, if any */
     remaining_size = size % MAX_LSP_ENTRIES_TLV_SIZE;
     if (remaining_size - 2 >= LSP_ENTRIES_LEN)
       lsp_count += (remaining_size - 2) / LSP_ENTRIES_LEN;
   
     return lsp_count;
   }
   
   /*
    * Calculate the length of Authentication Info. TLV.
    */
   static uint16_t
   auth_tlv_length (int level, struct isis_circuit *circuit)
   {
     struct isis_passwd *passwd;
     uint16_t length;
   
     if (level == IS_LEVEL_1)
       passwd = &circuit->area->area_passwd;
     else
       passwd = &circuit->area->domain_passwd;
   
     /* Also include the length of TLV header */
     length = AUTH_INFO_HDRLEN;
     if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND))
     {
       switch (passwd->type)
       {
         /* Cleartext */
         case ISIS_PASSWD_TYPE_CLEARTXT:
           length += passwd->len;
           break;
   
           /* HMAC MD5 */
         case ISIS_PASSWD_TYPE_HMAC_MD5:
           length += ISIS_AUTH_MD5_SIZE;
           break;
   
         default:
           break;
       }
     }
   
     return length;
   }
   
   /*
    * Calculate the maximum number of lsps that can be accomodated in a CSNP/PSNP.
    */
   static uint16_t
   max_lsps_per_snp (int snp_type, int level, struct isis_circuit *circuit)
   {
     int snp_hdr_len;
     int auth_tlv_len;
     uint16_t lsp_count;
   
     snp_hdr_len = ISIS_FIXED_HDR_LEN;
     if (snp_type == ISIS_SNP_CSNP_FLAG)
       snp_hdr_len += ISIS_CSNP_HDRLEN;
     else
       snp_hdr_len += ISIS_PSNP_HDRLEN;
   
     auth_tlv_len = auth_tlv_length (level, circuit);
     lsp_count = get_max_lsp_count (
         stream_get_size (circuit->snd_stream) - snp_hdr_len - auth_tlv_len);
     return lsp_count;
   }
   
   /*
  * FIXME: support multiple CSNPs   * FIXME: support multiple CSNPs
  */   */
   
 int  int
 send_csnp (struct isis_circuit *circuit, int level)  send_csnp (struct isis_circuit *circuit, int level)
 {  {
   int retval = ISIS_OK;  
   u_char start[ISIS_SYS_ID_LEN + 2];    u_char start[ISIS_SYS_ID_LEN + 2];
   u_char stop[ISIS_SYS_ID_LEN + 2];    u_char stop[ISIS_SYS_ID_LEN + 2];
   struct list *list = NULL;    struct list *list = NULL;
   struct listnode *node;    struct listnode *node;
   struct isis_lsp *lsp;    struct isis_lsp *lsp;
     u_char num_lsps, loop = 1;
     int i, retval = ISIS_OK;
   
     if (circuit->area->lspdb[level - 1] == NULL ||
         dict_count (circuit->area->lspdb[level - 1]) == 0)
       return retval;
   
   memset (start, 0x00, ISIS_SYS_ID_LEN + 2);    memset (start, 0x00, ISIS_SYS_ID_LEN + 2);
   memset (stop, 0xff, ISIS_SYS_ID_LEN + 2);    memset (stop, 0xff, ISIS_SYS_ID_LEN + 2);
   
  if (circuit->area->lspdb[level - 1] &&  num_lsps = max_lsps_per_snp (ISIS_SNP_CSNP_FLAG, level, circuit);
      dict_count (circuit->area->lspdb[level - 1]) > 0)
   while (loop)
     {      {
       list = list_new ();        list = list_new ();
      lsp_build_list (start, stop, list, circuit->area->lspdb[level - 1]);      lsp_build_list (start, stop, num_lsps, list,
                      circuit->area->lspdb[level - 1]);
      if (circuit->snd_stream == NULL)      /*
        circuit->snd_stream = stream_new (ISO_MTU (circuit));       * Update the stop lsp_id before encoding this CSNP.
        */
       if (listcount (list) < num_lsps)
         {
           memset (stop, 0xff, ISIS_SYS_ID_LEN + 2);
         }
       else        else
        stream_reset (circuit->snd_stream);        {
           node = listtail (list);
           lsp = listgetdata (node);
           memcpy (stop, lsp->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 2);
         }
   
       retval = build_csnp (level, start, stop, list, circuit);        retval = build_csnp (level, start, stop, list, circuit);
         if (retval != ISIS_OK)
           {
             zlog_err ("ISIS-Snp (%s): Build L%d CSNP on %s failed",
                       circuit->area->area_tag, level, circuit->interface->name);
             list_delete (list);
             return retval;
           }
   
       if (isis->debugs & DEBUG_SNP_PACKETS)        if (isis->debugs & DEBUG_SNP_PACKETS)
        {        {
          zlog_debug ("ISIS-Snp (%s): Sent L%d CSNP on %s, length %ld",          zlog_debug ("ISIS-Snp (%s): Sending L%d CSNP on %s, length %zd",
                     circuit->area->area_tag, level, circuit->interface->name,                      circuit->area->area_tag, level, circuit->interface->name,
                     /* FIXME: use %z when we stop supporting old compilers. */                      stream_get_endp (circuit->snd_stream));
                     (unsigned long) STREAM_SIZE (circuit->snd_stream));          for (ALL_LIST_ELEMENTS_RO (list, node, lsp))
          for (ALL_LIST_ELEMENTS_RO (list, node, lsp))            {
          {              zlog_debug ("ISIS-Snp (%s):         CSNP entry %s, seq 0x%08x,"
            zlog_debug ("ISIS-Snp (%s):         CSNP entry %s, seq 0x%08x,"                          " cksum 0x%04x, lifetime %us",
                        " cksum 0x%04x, lifetime %us",                          circuit->area->area_tag,
                        circuit->area->area_tag,                          rawlspid_print (lsp->lsp_header->lsp_id),
                        rawlspid_print (lsp->lsp_header->lsp_id),                          ntohl (lsp->lsp_header->seq_num),
                        ntohl (lsp->lsp_header->seq_num),                          ntohs (lsp->lsp_header->checksum),
                        ntohs (lsp->lsp_header->checksum),                          ntohs (lsp->lsp_header->rem_lifetime));
                        ntohs (lsp->lsp_header->rem_lifetime));            }
          }          if (isis->debugs & DEBUG_PACKET_DUMP)
        }            zlog_dump_data (STREAM_DATA (circuit->snd_stream),
                             stream_get_endp (circuit->snd_stream));
         }
   
      list_delete (list);      retval = circuit->tx (circuit, level);
       if (retval != ISIS_OK)
         {
           zlog_err ("ISIS-Snp (%s): Send L%d CSNP on %s failed",
                     circuit->area->area_tag, level,
                     circuit->interface->name);
           list_delete (list);
           return retval;
         }
   
      if (retval == ISIS_OK)      /*
        retval = circuit->tx (circuit, level);       * Start lsp_id of the next CSNP should be one plus the
        * stop lsp_id in this current CSNP.
        */
       memcpy (start, stop, ISIS_SYS_ID_LEN + 2);
       loop = 0;
       for (i = ISIS_SYS_ID_LEN + 1; i >= 0; --i)
         {
           if (start[i] < (u_char)0xff)
             {
               start[i] += 1;
               loop = 1;
               break;
             }
         }
       memset (stop, 0xff, ISIS_SYS_ID_LEN + 2);
       list_delete (list);
     }      }
   
   return retval;    return retval;
 }  }
   
Line 2314  build_psnp (int level, struct isis_circuit *circuit, s Line 2857  build_psnp (int level, struct isis_circuit *circuit, s
   struct isis_fixed_hdr fixed_hdr;    struct isis_fixed_hdr fixed_hdr;
   unsigned long lenp;    unsigned long lenp;
   u_int16_t length;    u_int16_t length;
   int retval = 0;  
   struct isis_lsp *lsp;    struct isis_lsp *lsp;
   struct isis_passwd *passwd;    struct isis_passwd *passwd;
   struct listnode *node;    struct listnode *node;
     unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
     unsigned long auth_tlv_offset = 0;
     int retval = ISIS_OK;
   
  if (level == 1)  isis_circuit_stream(circuit, &circuit->snd_stream);
 
   if (level == IS_LEVEL_1)
     fill_fixed_hdr_andstream (&fixed_hdr, L1_PARTIAL_SEQ_NUM,      fill_fixed_hdr_andstream (&fixed_hdr, L1_PARTIAL_SEQ_NUM,
                               circuit->snd_stream);                                circuit->snd_stream);
   else    else
Line 2338  build_psnp (int level, struct isis_circuit *circuit, s Line 2885  build_psnp (int level, struct isis_circuit *circuit, s
    * And TLVs     * And TLVs
    */     */
   
  if (level == 1)  if (level == IS_LEVEL_1)
     passwd = &circuit->area->area_passwd;      passwd = &circuit->area->area_passwd;
   else    else
     passwd = &circuit->area->domain_passwd;      passwd = &circuit->area->domain_passwd;
   
   if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND))    if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND))
    if (passwd->type)  {
      retval = tlv_add_authinfo (passwd->type, passwd->len,    switch (passwd->type)
                                 passwd->passwd, circuit->snd_stream); 
 
  if (!retval && lsps) 
     {      {
      retval = tlv_add_lsp_entries (lsps, circuit->snd_stream);      /* Cleartext */
       case ISIS_PASSWD_TYPE_CLEARTXT:
         if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT, passwd->len,
                               passwd->passwd, circuit->snd_stream))
           return ISIS_WARNING;
         break;
 
         /* HMAC MD5 */
       case ISIS_PASSWD_TYPE_HMAC_MD5:
         /* Remember where TLV is written so we can later overwrite the MD5 hash */
         auth_tlv_offset = stream_get_endp (circuit->snd_stream);
         memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
         if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5, ISIS_AUTH_MD5_SIZE,
                               hmac_md5_hash, circuit->snd_stream))
           return ISIS_WARNING;
         break;
 
       default:
         break;
     }      }
     }
   
     retval = tlv_add_lsp_entries (lsps, circuit->snd_stream);
     if (retval != ISIS_OK)
       return retval;
   
   if (isis->debugs & DEBUG_SNP_PACKETS)    if (isis->debugs & DEBUG_SNP_PACKETS)
     {      {
       for (ALL_LIST_ELEMENTS_RO (lsps, node, lsp))        for (ALL_LIST_ELEMENTS_RO (lsps, node, lsp))
Line 2368  build_psnp (int level, struct isis_circuit *circuit, s Line 2935  build_psnp (int level, struct isis_circuit *circuit, s
     }      }
   
   length = (u_int16_t) stream_get_endp (circuit->snd_stream);    length = (u_int16_t) stream_get_endp (circuit->snd_stream);
   assert (length >= ISIS_PSNP_HDRLEN);  
   /* Update PDU length */    /* Update PDU length */
   stream_putw_at (circuit->snd_stream, lenp, length);    stream_putw_at (circuit->snd_stream, lenp, length);
   
     /* For HMAC MD5 we need to compute the md5 hash and store it */
     if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND) &&
         passwd->type == ISIS_PASSWD_TYPE_HMAC_MD5)
       {
         hmac_md5 (STREAM_DATA (circuit->snd_stream),
                   stream_get_endp(circuit->snd_stream),
                   (unsigned char *) &passwd->passwd, passwd->len,
                   (unsigned char *) &hmac_md5_hash);
         /* Copy the hash into the stream */
         memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3,
                 hmac_md5_hash, ISIS_AUTH_MD5_SIZE);
       }
   
   return ISIS_OK;    return ISIS_OK;
 }  }
   
Line 2382  build_psnp (int level, struct isis_circuit *circuit, s Line 2961  build_psnp (int level, struct isis_circuit *circuit, s
 static int  static int
 send_psnp (int level, struct isis_circuit *circuit)  send_psnp (int level, struct isis_circuit *circuit)
 {  {
   int retval = ISIS_OK;  
   struct isis_lsp *lsp;    struct isis_lsp *lsp;
   struct list *list = NULL;    struct list *list = NULL;
   struct listnode *node;    struct listnode *node;
     u_char num_lsps;
     int retval = ISIS_OK;
   
  if ((circuit->circ_type == CIRCUIT_T_BROADCAST &&  if (circuit->circ_type == CIRCUIT_T_BROADCAST &&
       !circuit->u.bc.is_dr[level - 1]) ||      circuit->u.bc.is_dr[level - 1])
      circuit->circ_type != CIRCUIT_T_BROADCAST)    return ISIS_OK;
    { 
   
      if (circuit->area->lspdb[level - 1] &&  if (circuit->area->lspdb[level - 1] == NULL ||
          dict_count (circuit->area->lspdb[level - 1]) > 0)      dict_count (circuit->area->lspdb[level - 1]) == 0)
        {    return ISIS_OK;
          list = list_new (); 
          lsp_build_list_ssn (circuit, list, circuit->area->lspdb[level - 1]); 
   
          if (listcount (list) > 0)  if (! circuit->snd_stream)
            {    return ISIS_ERROR;
              if (circuit->snd_stream == NULL) 
                circuit->snd_stream = stream_new (ISO_MTU (circuit)); 
              else 
                stream_reset (circuit->snd_stream); 
   
     num_lsps = max_lsps_per_snp (ISIS_SNP_PSNP_FLAG, level, circuit);
   
              if (isis->debugs & DEBUG_SNP_PACKETS)  while (1)
                zlog_debug ("ISIS-Snp (%s): Sent L%d PSNP on %s, length %ld",    {
                            circuit->area->area_tag, level,      list = list_new ();
                            circuit->interface->name,      lsp_build_list_ssn (circuit, num_lsps, list,
                            /* FIXME: use %z when we stop supporting old                          circuit->area->lspdb[level - 1]);
                             * compilers. */ 
                            (unsigned long) STREAM_SIZE (circuit->snd_stream)); 
   
              retval = build_psnp (level, circuit, list);      if (listcount (list) == 0)
              if (retval == ISIS_OK)        {
                retval = circuit->tx (circuit, level);          list_delete (list);
           return ISIS_OK;
         }
   
              if (retval == ISIS_OK)      retval = build_psnp (level, circuit, list);
                {      if (retval != ISIS_OK)
                  /*        {
                   * sending succeeded, we can clear SSN flags of this circuit          zlog_err ("ISIS-Snp (%s): Build L%d PSNP on %s failed",
                   * for the LSPs in list                    circuit->area->area_tag, level, circuit->interface->name);
                   */          list_delete (list);
                  for (ALL_LIST_ELEMENTS_RO (list, node, lsp))          return retval;
                    ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);        }
                }
            }      if (isis->debugs & DEBUG_SNP_PACKETS)
          list_delete (list);        {
        }          zlog_debug ("ISIS-Snp (%s): Sending L%d PSNP on %s, length %zd",
                       circuit->area->area_tag, level,
                       circuit->interface->name,
                       stream_get_endp (circuit->snd_stream));
           if (isis->debugs & DEBUG_PACKET_DUMP)
             zlog_dump_data (STREAM_DATA (circuit->snd_stream),
                             stream_get_endp (circuit->snd_stream));
         }
 
       retval = circuit->tx (circuit, level);
       if (retval != ISIS_OK)
         {
           zlog_err ("ISIS-Snp (%s): Send L%d PSNP on %s failed",
                     circuit->area->area_tag, level,
                     circuit->interface->name);
           list_delete (list);
           return retval;
         }
 
       /*
        * sending succeeded, we can clear SSN flags of this circuit
        * for the LSPs in list
        */
       for (ALL_LIST_ELEMENTS_RO (list, node, lsp))
         ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
       list_delete (list);
     }      }
   
   return retval;    return retval;
Line 2488  send_lsp (struct thread *thread) Line 3087  send_lsp (struct thread *thread)
   struct isis_circuit *circuit;    struct isis_circuit *circuit;
   struct isis_lsp *lsp;    struct isis_lsp *lsp;
   struct listnode *node;    struct listnode *node;
  int retval = 0;  int clear_srm = 1;
   int retval = ISIS_OK;
   
   circuit = THREAD_ARG (thread);    circuit = THREAD_ARG (thread);
   assert (circuit);    assert (circuit);
   
  if (circuit->state == C_STATE_UP)  if (!circuit->lsp_queue)
    {    return ISIS_OK;
      lsp = listgetdata ((node = listhead (circuit->lsp_queue))); 
   
      /*  node = listhead (circuit->lsp_queue);
       * Do not send if levels do not match 
       */ 
      if (!(lsp->level & circuit->circuit_is_type)) 
        goto dontsend; 
   
      /*  /*
       * Do not send if we do not have adjacencies in state up on the circuit   * Handle case where there are no LSPs on the queue. This can
       */   * happen, for instance, if an adjacency goes down before this
      if (circuit->upadjcount[lsp->level - 1] == 0)   * thread gets a chance to run.
        goto dontsend;   */
      /* only send if it needs sending */  if (!node)
      if ((time (NULL) - lsp->last_sent) >=    return ISIS_OK;
          circuit->area->lsp_gen_interval[lsp->level - 1]) 
        { 
   
          if (isis->debugs & DEBUG_UPDATE_PACKETS)  /*
            {   * Delete LSP from lsp_queue. If it's still in queue, it is assumed
              zlog_debug   * as 'transmit pending', but send_lsp may never be called again.
                ("ISIS-Upd (%s): Sent L%d LSP %s, seq 0x%08x, cksum 0x%04x,"   * Retry will happen because SRM flag will not be cleared.
                 " lifetime %us on %s", circuit->area->area_tag, lsp->level,   */
                 rawlspid_print (lsp->lsp_header->lsp_id),  lsp = listgetdata(node);
                 ntohl (lsp->lsp_header->seq_num),  list_delete_node (circuit->lsp_queue, node);
                 ntohs (lsp->lsp_header->checksum), 
                 ntohs (lsp->lsp_header->rem_lifetime), 
                 circuit->interface->name); 
            } 
          /* copy our lsp to the send buffer */ 
          stream_copy (circuit->snd_stream, lsp->pdu); 
   
          retval = circuit->tx (circuit, lsp->level);  /* Set the last-cleared time if the queue is empty. */
   /* TODO: Is is possible that new lsps keep being added to the queue
    * that the queue is never empty? */
   if (list_isempty (circuit->lsp_queue))
     circuit->lsp_queue_last_cleared = time (NULL);
   
          /*  if (circuit->state != C_STATE_UP || circuit->is_passive == 1)
           * If the sending succeeded, we can del the lsp from circuits    goto out;
           * lsp_queue 
           */ 
          if (retval == ISIS_OK) 
            { 
              list_delete_node (circuit->lsp_queue, node); 
   
              /*  /*
               * On broadcast circuits also the SRMflag can be cleared   * Do not send if levels do not match
               */   */
              if (circuit->circ_type == CIRCUIT_T_BROADCAST)  if (!(lsp->level & circuit->is_type))
                ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);    goto out;
   
              if (flags_any_set (lsp->SRMflags) == 0)  /*
                {   * Do not send if we do not have adjacencies in state up on the circuit
                  /*   */
                   * need to remember when we were last sent  if (circuit->upadjcount[lsp->level - 1] == 0)
                   */    goto out;
                  lsp->last_sent = time (NULL);
                }  /* stream_copy will assert and stop program execution if LSP is larger than
            }   * the circuit's MTU. So handle and log this case here. */
          else  if (stream_get_endp(lsp->pdu) > stream_get_size(circuit->snd_stream))
            {    {
              zlog_debug ("sending of level %d link state failed", lsp->level);      zlog_err("ISIS-Upd (%s): Can't send L%d LSP %s, seq 0x%08x,"
            }               " cksum 0x%04x, lifetime %us on %s. LSP Size is %zu"
        }               " while interface stream size is %zu.",
      else               circuit->area->area_tag, lsp->level,
        {               rawlspid_print(lsp->lsp_header->lsp_id),
          /* my belief is that if it wasn't his time, the lsp can be removed               ntohl(lsp->lsp_header->seq_num),
           * from the queue               ntohs(lsp->lsp_header->checksum),
           */               ntohs(lsp->lsp_header->rem_lifetime),
        dontsend:               circuit->interface->name,
          list_delete_node (circuit->lsp_queue, node);               stream_get_endp(lsp->pdu),
        }               stream_get_size(circuit->snd_stream));
#if 0      if (isis->debugs & DEBUG_PACKET_DUMP)
      /*        zlog_dump_data(STREAM_DATA(lsp->pdu), stream_get_endp(lsp->pdu));
       * If there are still LSPs send next one after lsp-interval (33 msecs)      retval = ISIS_ERROR;
       goto out;
     }
 
   /* copy our lsp to the send buffer */
   stream_copy (circuit->snd_stream, lsp->pdu);
 
   if (isis->debugs & DEBUG_UPDATE_PACKETS)
     {
       zlog_debug
         ("ISIS-Upd (%s): Sending L%d LSP %s, seq 0x%08x, cksum 0x%04x,"
          " lifetime %us on %s", circuit->area->area_tag, lsp->level,
          rawlspid_print (lsp->lsp_header->lsp_id),
          ntohl (lsp->lsp_header->seq_num),
          ntohs (lsp->lsp_header->checksum),
          ntohs (lsp->lsp_header->rem_lifetime),
          circuit->interface->name);
       if (isis->debugs & DEBUG_PACKET_DUMP)
         zlog_dump_data (STREAM_DATA (circuit->snd_stream),
                         stream_get_endp (circuit->snd_stream));
     }
 
   clear_srm = 0;
   retval = circuit->tx (circuit, lsp->level);
   if (retval != ISIS_OK)
     {
       zlog_err ("ISIS-Upd (%s): Send L%d LSP on %s failed %s",
                 circuit->area->area_tag, lsp->level,
                 circuit->interface->name,
                 (retval == ISIS_WARNING) ? "temporarily" : "permanently");
     }
 
 out:
   if (clear_srm
       || (retval == ISIS_OK && circuit->circ_type == CIRCUIT_T_BROADCAST)
       || (retval != ISIS_OK && retval != ISIS_WARNING))
     {
       /* SRM flag will trigger retransmission. We will not retransmit if we
        * encountered a fatal error.
        * On success, they should only be cleared if it's a broadcast circuit.
        * On a P2P circuit, we will wait for the ack from the neighbor to clear
        * the fag.
        */         */
      if (listcount (circuit->lsp_queue) > 0)      ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
        thread_add_timer (master, send_lsp, circuit, 1); 
#endif 
     }      }
   
   return retval;    return retval;
Line 2585  ack_lsp (struct isis_link_state_hdr *hdr, struct isis_ Line 3210  ack_lsp (struct isis_link_state_hdr *hdr, struct isis_
   u_int16_t length;    u_int16_t length;
   struct isis_fixed_hdr fixed_hdr;    struct isis_fixed_hdr fixed_hdr;
   
  if (!circuit->snd_stream)  isis_circuit_stream(circuit, &circuit->snd_stream);
    circuit->snd_stream = stream_new (ISO_MTU (circuit)); 
  else 
    stream_reset (circuit->snd_stream); 
   
//  fill_llc_hdr (stream);  //  fill_llc_hdr (stream);
  if (level == 1)  if (level == IS_LEVEL_1)
     fill_fixed_hdr_andstream (&fixed_hdr, L1_PARTIAL_SEQ_NUM,      fill_fixed_hdr_andstream (&fixed_hdr, L1_PARTIAL_SEQ_NUM,
                               circuit->snd_stream);                                circuit->snd_stream);
   else    else
Line 2616  ack_lsp (struct isis_link_state_hdr *hdr, struct isis_ Line 3238  ack_lsp (struct isis_link_state_hdr *hdr, struct isis_
   stream_putw_at (circuit->snd_stream, lenp, length);    stream_putw_at (circuit->snd_stream, lenp, length);
   
   retval = circuit->tx (circuit, level);    retval = circuit->tx (circuit, level);
     if (retval != ISIS_OK)
       zlog_err ("ISIS-Upd (%s): Send L%d LSP PSNP on %s failed",
                 circuit->area->area_tag, level,
                 circuit->interface->name);
   
   return retval;    return retval;
 }  }
   

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


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