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

    1: /*
    2:  * IS-IS Rout(e)ing protocol - isis_pdu.c   
    3:  *                             PDU processing
    4:  *
    5:  * Copyright (C) 2001,2002   Sampo Saaristo
    6:  *                           Tampere University of Technology      
    7:  *                           Institute of Communications Engineering
    8:  *
    9:  * This program is free software; you can redistribute it and/or modify it 
   10:  * under the terms of the GNU General Public Licenseas published by the Free 
   11:  * Software Foundation; either version 2 of the License, or (at your option) 
   12:  * any later version.
   13:  *
   14:  * This program is distributed in the hope that it will be useful,but WITHOUT 
   15:  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
   16:  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
   17:  * more details.
   18: 
   19:  * You should have received a copy of the GNU General Public License along 
   20:  * with this program; if not, write to the Free Software Foundation, Inc., 
   21:  * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
   22:  */
   23: 
   24: #include <zebra.h>
   25: 
   26: #include "memory.h"
   27: #include "thread.h"
   28: #include "linklist.h"
   29: #include "log.h"
   30: #include "stream.h"
   31: #include "vty.h"
   32: #include "hash.h"
   33: #include "prefix.h"
   34: #include "if.h"
   35: #include "checksum.h"
   36: #include "md5.h"
   37: 
   38: #include "isisd/dict.h"
   39: #include "isisd/include-netbsd/iso.h"
   40: #include "isisd/isis_constants.h"
   41: #include "isisd/isis_common.h"
   42: #include "isisd/isis_flags.h"
   43: #include "isisd/isis_adjacency.h"
   44: #include "isisd/isis_circuit.h"
   45: #include "isisd/isis_network.h"
   46: #include "isisd/isis_misc.h"
   47: #include "isisd/isis_dr.h"
   48: #include "isisd/isis_tlv.h"
   49: #include "isisd/isisd.h"
   50: #include "isisd/isis_dynhn.h"
   51: #include "isisd/isis_lsp.h"
   52: #include "isisd/isis_pdu.h"
   53: #include "isisd/iso_checksum.h"
   54: #include "isisd/isis_csm.h"
   55: #include "isisd/isis_events.h"
   56: 
   57: #define ISIS_MINIMUM_FIXED_HDR_LEN 15
   58: #define ISIS_MIN_PDU_LEN           13	/* partial seqnum pdu with id_len=2 */
   59: 
   60: #ifndef PNBBY
   61: #define PNBBY 8
   62: #endif /* PNBBY */
   63: 
   64: /* Utility mask array. */
   65: static u_char maskbit[] = {
   66:   0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
   67: };
   68: 
   69: /*
   70:  * HELPER FUNCS
   71:  */
   72: 
   73: /*
   74:  * Compares two sets of area addresses
   75:  */
   76: static int
   77: area_match (struct list *left, struct list *right)
   78: {
   79:   struct area_addr *addr1, *addr2;
   80:   struct listnode *node1, *node2;
   81: 
   82:   for (ALL_LIST_ELEMENTS_RO (left, node1, addr1))
   83:   {
   84:     for (ALL_LIST_ELEMENTS_RO (right, node2, addr2))
   85:     {
   86:       if (addr1->addr_len == addr2->addr_len &&
   87: 	  !memcmp (addr1->area_addr, addr2->area_addr, (int) addr1->addr_len))
   88: 	return 1;		/* match */
   89:     }
   90:   }
   91: 
   92:   return 0;			/* mismatch */
   93: }
   94: 
   95: /*
   96:  * Check if ip2 is in the ip1's network (function like Prefix.h:prefix_match() )
   97:  * param ip1            the IS interface ip address structure
   98:  * param ip2            the IIH's ip address
   99:  * return  0            the IIH's IP is not in the IS's subnetwork
  100:  *         1            the IIH's IP is in the IS's subnetwork
  101:  */
  102: static int
  103: ip_same_subnet (struct prefix_ipv4 *ip1, struct in_addr *ip2)
  104: {
  105:   u_char *addr1, *addr2;
  106:   int shift, offset, offsetloop;
  107:   int len;
  108: 
  109:   addr1 = (u_char *) & ip1->prefix.s_addr;
  110:   addr2 = (u_char *) & ip2->s_addr;
  111:   len = ip1->prefixlen;
  112: 
  113:   shift = len % PNBBY;
  114:   offsetloop = offset = len / PNBBY;
  115: 
  116:   while (offsetloop--)
  117:     if (addr1[offsetloop] != addr2[offsetloop])
  118:       return 0;
  119: 
  120:   if (shift)
  121:     if (maskbit[shift] & (addr1[offset] ^ addr2[offset]))
  122:       return 0;
  123: 
  124:   return 1;			/* match  */
  125: }
  126: 
  127: /*
  128:  * Compares two set of ip addresses
  129:  * param left     the local interface's ip addresses
  130:  * param right    the iih interface's ip address
  131:  * return         0   no match;
  132:  *                1   match;
  133:  */
  134: static int
  135: ip_match (struct list *left, struct list *right)
  136: {
  137:   struct prefix_ipv4 *ip1;
  138:   struct in_addr *ip2;
  139:   struct listnode *node1, *node2;
  140: 
  141:   if ((left == NULL) || (right == NULL))
  142:     return 0;
  143:   
  144:   for (ALL_LIST_ELEMENTS_RO (left, node1, ip1))
  145:   {
  146:     for (ALL_LIST_ELEMENTS_RO (right, node2, ip2))
  147:     {
  148:       if (ip_same_subnet (ip1, ip2))
  149: 	{
  150: 	  return 1;		/* match */
  151: 	}
  152:     }
  153: 
  154:   }
  155:   return 0;
  156: }
  157: 
  158: /*
  159:  * Checks whether we should accept a PDU of given level 
  160:  */
  161: static int
  162: accept_level (int level, int circuit_t)
  163: {
  164:   int retval = ((circuit_t & level) == level);	/* simple approach */
  165: 
  166:   return retval;
  167: }
  168: 
  169: /*
  170:  * Verify authentication information
  171:  * Support cleartext and HMAC MD5 authentication
  172:  */
  173: static int
  174: authentication_check (struct isis_passwd *remote, struct isis_passwd *local,
  175:                       struct stream *stream, uint32_t auth_tlv_offset)
  176: {
  177:   unsigned char digest[ISIS_AUTH_MD5_SIZE];
  178: 
  179:   /* Auth fail () - passwd type mismatch */
  180:   if (local->type != remote->type)
  181:     return ISIS_ERROR;
  182: 
  183:   switch (local->type)
  184:   {
  185:     /* No authentication required */
  186:     case ISIS_PASSWD_TYPE_UNUSED:
  187:       break;
  188: 
  189:     /* Cleartext (ISO 10589) */
  190:     case ISIS_PASSWD_TYPE_CLEARTXT:
  191:       /* Auth fail () - passwd len mismatch */
  192:       if (remote->len != local->len)
  193:         return ISIS_ERROR;
  194:       return memcmp (local->passwd, remote->passwd, local->len);
  195: 
  196:     /* HMAC MD5 (RFC 3567) */
  197:     case ISIS_PASSWD_TYPE_HMAC_MD5:
  198:       /* Auth fail () - passwd len mismatch */
  199:       if (remote->len != ISIS_AUTH_MD5_SIZE)
  200:         return ISIS_ERROR;
  201:       /* Set the authentication value to 0 before the check */
  202:       memset (STREAM_DATA (stream) + auth_tlv_offset + 3, 0,
  203:               ISIS_AUTH_MD5_SIZE);
  204:       /* Compute the digest */
  205:       hmac_md5 (STREAM_DATA (stream), stream_get_endp (stream),
  206:                 (unsigned char *) &(local->passwd), local->len,
  207:                 (caddr_t) &digest);
  208:       /* Copy back the authentication value after the check */
  209:       memcpy (STREAM_DATA (stream) + auth_tlv_offset + 3,
  210:               remote->passwd, ISIS_AUTH_MD5_SIZE);
  211:       return memcmp (digest, remote->passwd, ISIS_AUTH_MD5_SIZE);
  212: 
  213:     default:
  214:       zlog_err ("Unsupported authentication type");
  215:       return ISIS_ERROR;
  216:   }
  217: 
  218:   /* Authentication pass when no authentication is configured */
  219:   return ISIS_OK;
  220: }
  221: 
  222: static int
  223: lsp_authentication_check (struct stream *stream, struct isis_area *area,
  224:                           int level, struct isis_passwd *passwd)
  225: {
  226:   struct isis_link_state_hdr *hdr;
  227:   uint32_t expected = 0, found = 0, auth_tlv_offset = 0;
  228:   uint16_t checksum, rem_lifetime, pdu_len;
  229:   struct tlvs tlvs;
  230:   int retval = ISIS_OK;
  231: 
  232:   hdr = (struct isis_link_state_hdr *) (STREAM_PNT (stream));
  233:   pdu_len = ntohs (hdr->pdu_len);
  234:   expected |= TLVFLAG_AUTH_INFO;
  235:   auth_tlv_offset = stream_get_getp (stream) + ISIS_LSP_HDR_LEN;
  236:   retval = parse_tlvs (area->area_tag, STREAM_PNT (stream) + ISIS_LSP_HDR_LEN,
  237:                        pdu_len - ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN,
  238:                        &expected, &found, &tlvs, &auth_tlv_offset);
  239: 
  240:   if (retval != ISIS_OK)
  241:     {
  242:       zlog_err ("ISIS-Upd (%s): Parse failed L%d LSP %s, seq 0x%08x, "
  243:                 "cksum 0x%04x, lifetime %us, len %u",
  244:                 area->area_tag, level, rawlspid_print (hdr->lsp_id),
  245:                 ntohl (hdr->seq_num), ntohs (hdr->checksum),
  246:                 ntohs (hdr->rem_lifetime), pdu_len);
  247:       if ((isis->debugs & DEBUG_UPDATE_PACKETS) &&
  248:           (isis->debugs & DEBUG_PACKET_DUMP))
  249:         zlog_dump_data (STREAM_DATA (stream), stream_get_endp (stream));
  250:       return retval;
  251:     }
  252: 
  253:   if (!(found & TLVFLAG_AUTH_INFO))
  254:     {
  255:       zlog_err ("No authentication tlv in LSP");
  256:       return ISIS_ERROR;
  257:     }
  258: 
  259:   if (tlvs.auth_info.type != ISIS_PASSWD_TYPE_CLEARTXT &&
  260:       tlvs.auth_info.type != ISIS_PASSWD_TYPE_HMAC_MD5)
  261:     {
  262:       zlog_err ("Unknown authentication type in LSP");
  263:       return ISIS_ERROR;
  264:     }
  265: 
  266:   /*
  267:    * RFC 5304 set checksum and remaining lifetime to zero before
  268:    * verification and reset to old values after verification.
  269:    */
  270:   checksum = hdr->checksum;
  271:   rem_lifetime = hdr->rem_lifetime;
  272:   hdr->checksum = 0;
  273:   hdr->rem_lifetime = 0;
  274:   retval = authentication_check (&tlvs.auth_info, passwd, stream,
  275:                                  auth_tlv_offset);
  276:   hdr->checksum = checksum;
  277:   hdr->rem_lifetime = rem_lifetime;
  278: 
  279:   return retval;
  280: }
  281: 
  282: /*
  283:  * Processing helper functions
  284:  */
  285: static void
  286: del_addr (void *val)
  287: {
  288:   XFREE (MTYPE_ISIS_TMP, val);
  289: }
  290: 
  291: static void
  292: tlvs_to_adj_area_addrs (struct tlvs *tlvs, struct isis_adjacency *adj)
  293: {
  294:   struct listnode *node;
  295:   struct area_addr *area_addr, *malloced;
  296: 
  297:   if (adj->area_addrs)
  298:     {
  299:       adj->area_addrs->del = del_addr;
  300:       list_delete (adj->area_addrs);
  301:     }
  302:   adj->area_addrs = list_new ();
  303:   if (tlvs->area_addrs)
  304:     {
  305:       for (ALL_LIST_ELEMENTS_RO (tlvs->area_addrs, node, area_addr))
  306:       {
  307: 	malloced = XMALLOC (MTYPE_ISIS_TMP, sizeof (struct area_addr));
  308: 	memcpy (malloced, area_addr, sizeof (struct area_addr));
  309: 	listnode_add (adj->area_addrs, malloced);
  310:       }
  311:     }
  312: }
  313: 
  314: static int
  315: tlvs_to_adj_nlpids (struct tlvs *tlvs, struct isis_adjacency *adj)
  316: {
  317:   int i;
  318:   struct nlpids *tlv_nlpids;
  319: 
  320:   if (tlvs->nlpids)
  321:     {
  322: 
  323:       tlv_nlpids = tlvs->nlpids;
  324:       if (tlv_nlpids->count > array_size (adj->nlpids.nlpids))
  325:         return 1;
  326: 
  327:       adj->nlpids.count = tlv_nlpids->count;
  328: 
  329:       for (i = 0; i < tlv_nlpids->count; i++)
  330: 	{
  331: 	  adj->nlpids.nlpids[i] = tlv_nlpids->nlpids[i];
  332: 	}
  333:     }
  334:   return 0;
  335: }
  336: 
  337: static void
  338: tlvs_to_adj_ipv4_addrs (struct tlvs *tlvs, struct isis_adjacency *adj)
  339: {
  340:   struct listnode *node;
  341:   struct in_addr *ipv4_addr, *malloced;
  342: 
  343:   if (adj->ipv4_addrs)
  344:     {
  345:       adj->ipv4_addrs->del = del_addr;
  346:       list_delete (adj->ipv4_addrs);
  347:     }
  348:   adj->ipv4_addrs = list_new ();
  349:   if (tlvs->ipv4_addrs)
  350:     {
  351:       for (ALL_LIST_ELEMENTS_RO (tlvs->ipv4_addrs, node, ipv4_addr))
  352:       {
  353: 	malloced = XMALLOC (MTYPE_ISIS_TMP, sizeof (struct in_addr));
  354: 	memcpy (malloced, ipv4_addr, sizeof (struct in_addr));
  355: 	listnode_add (adj->ipv4_addrs, malloced);
  356:       }
  357:     }
  358: }
  359: 
  360: #ifdef HAVE_IPV6
  361: static void
  362: tlvs_to_adj_ipv6_addrs (struct tlvs *tlvs, struct isis_adjacency *adj)
  363: {
  364:   struct listnode *node;
  365:   struct in6_addr *ipv6_addr, *malloced;
  366: 
  367:   if (adj->ipv6_addrs)
  368:     {
  369:       adj->ipv6_addrs->del = del_addr;
  370:       list_delete (adj->ipv6_addrs);
  371:     }
  372:   adj->ipv6_addrs = list_new ();
  373:   if (tlvs->ipv6_addrs)
  374:     {
  375:       for (ALL_LIST_ELEMENTS_RO (tlvs->ipv6_addrs, node, ipv6_addr))
  376:       {
  377: 	malloced = XMALLOC (MTYPE_ISIS_TMP, sizeof (struct in6_addr));
  378: 	memcpy (malloced, ipv6_addr, sizeof (struct in6_addr));
  379: 	listnode_add (adj->ipv6_addrs, malloced);
  380:       }
  381:     }
  382: 
  383: }
  384: #endif /* HAVE_IPV6 */
  385: 
  386: /*
  387:  *  RECEIVE SIDE                           
  388:  */
  389: 
  390: /*
  391:  * Process P2P IIH
  392:  * ISO - 10589
  393:  * Section 8.2.5 - Receiving point-to-point IIH PDUs
  394:  *
  395:  */
  396: static int
  397: process_p2p_hello (struct isis_circuit *circuit)
  398: {
  399:   int retval = ISIS_OK;
  400:   struct isis_p2p_hello_hdr *hdr;
  401:   struct isis_adjacency *adj;
  402:   u_int32_t expected = 0, found = 0, auth_tlv_offset = 0;
  403:   uint16_t pdu_len;
  404:   struct tlvs tlvs;
  405: 
  406:   if (isis->debugs & DEBUG_ADJ_PACKETS)
  407:     {
  408:       zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH on %s, cirType %s, cirID %u",
  409:                   circuit->area->area_tag, circuit->interface->name,
  410:                   circuit_t2string (circuit->is_type), circuit->circuit_id);
  411:       if (isis->debugs & DEBUG_PACKET_DUMP)
  412:         zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
  413:                         stream_get_endp (circuit->rcv_stream));
  414:     }
  415: 
  416:   if (circuit->circ_type != CIRCUIT_T_P2P)
  417:     {
  418:       zlog_warn ("p2p hello on non p2p circuit");
  419:       return ISIS_WARNING;
  420:     }
  421: 
  422:   if ((stream_get_endp (circuit->rcv_stream) -
  423:        stream_get_getp (circuit->rcv_stream)) < ISIS_P2PHELLO_HDRLEN)
  424:     {
  425:       zlog_warn ("Packet too short");
  426:       return ISIS_WARNING;
  427:     }
  428: 
  429:   /* 8.2.5.1 PDU acceptance tests */
  430: 
  431:   /* 8.2.5.1 a) external domain untrue */
  432:   /* FIXME: not useful at all?         */
  433: 
  434:   /* 8.2.5.1 b) ID Length mismatch */
  435:   /* checked at the handle_pdu     */
  436: 
  437:   /* 8.2.5.2 IIH PDU Processing */
  438: 
  439:   /* 8.2.5.2 a) 1) Maximum Area Addresses */
  440:   /* Already checked, and can also be ommited */
  441: 
  442:   /*
  443:    * Get the header
  444:    */
  445:   hdr = (struct isis_p2p_hello_hdr *) STREAM_PNT (circuit->rcv_stream);
  446:   pdu_len = ntohs (hdr->pdu_len);
  447: 
  448:   if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_P2PHELLO_HDRLEN) ||
  449:       pdu_len > ISO_MTU(circuit) ||
  450:       pdu_len > stream_get_endp (circuit->rcv_stream))
  451:     {
  452:       zlog_warn ("ISIS-Adj (%s): Rcvd P2P IIH from (%s) with "
  453:                  "invalid pdu length %d",
  454:                  circuit->area->area_tag, circuit->interface->name, pdu_len);
  455:       return ISIS_WARNING;
  456:     }
  457: 
  458:   /*
  459:    * Set the stream endp to PDU length, ignoring additional padding
  460:    * introduced by transport chips.
  461:    */
  462:   if (pdu_len < stream_get_endp (circuit->rcv_stream))
  463:     stream_set_endp (circuit->rcv_stream, pdu_len);
  464: 
  465:   stream_forward_getp (circuit->rcv_stream, ISIS_P2PHELLO_HDRLEN);
  466: 
  467:   /*
  468:    * Lets get the TLVS now
  469:    */
  470:   expected |= TLVFLAG_AREA_ADDRS;
  471:   expected |= TLVFLAG_AUTH_INFO;
  472:   expected |= TLVFLAG_NLPID;
  473:   expected |= TLVFLAG_IPV4_ADDR;
  474:   expected |= TLVFLAG_IPV6_ADDR;
  475: 
  476:   auth_tlv_offset = stream_get_getp (circuit->rcv_stream);
  477:   retval = parse_tlvs (circuit->area->area_tag,
  478: 		       STREAM_PNT (circuit->rcv_stream),
  479: 		       pdu_len - ISIS_P2PHELLO_HDRLEN - ISIS_FIXED_HDR_LEN,
  480:                        &expected, &found, &tlvs, &auth_tlv_offset);
  481: 
  482:   if (retval > ISIS_WARNING)
  483:     {
  484:       zlog_warn ("parse_tlvs() failed");
  485:       free_tlvs (&tlvs);
  486:       return retval;
  487:     };
  488: 
  489:   if (!(found & TLVFLAG_AREA_ADDRS))
  490:     {
  491:       zlog_warn ("No Area addresses TLV in P2P IS to IS hello");
  492:       free_tlvs (&tlvs);
  493:       return ISIS_WARNING;
  494:     }
  495: 
  496:   if (!(found & TLVFLAG_NLPID))
  497:     {
  498:       zlog_warn ("No supported protocols TLV in P2P IS to IS hello");
  499:       free_tlvs (&tlvs);
  500:       return ISIS_WARNING;
  501:     }
  502: 
  503:   /* 8.2.5.1 c) Authentication */
  504:   if (circuit->passwd.type)
  505:     {
  506:       if (!(found & TLVFLAG_AUTH_INFO) ||
  507:           authentication_check (&tlvs.auth_info, &circuit->passwd,
  508:                                 circuit->rcv_stream, auth_tlv_offset))
  509:         {
  510:           isis_event_auth_failure (circuit->area->area_tag,
  511:                                    "P2P hello authentication failure",
  512:                                    hdr->source_id);
  513:           free_tlvs (&tlvs);
  514:           return ISIS_OK;
  515:         }
  516:     }
  517: 
  518:   /*
  519:    * check if it's own interface ip match iih ip addrs
  520:    */
  521:   if ((found & TLVFLAG_IPV4_ADDR) == 0 ||
  522:       ip_match (circuit->ip_addrs, tlvs.ipv4_addrs) == 0)
  523:     {
  524:       zlog_warn ("ISIS-Adj: No usable IP interface addresses "
  525:                  "in LAN IIH from %s\n", circuit->interface->name);
  526:       free_tlvs (&tlvs);
  527:       return ISIS_WARNING;
  528:     }
  529: 
  530:   /*
  531:    * My interpertation of the ISO, if no adj exists we will create one for
  532:    * the circuit
  533:    */
  534:   adj = circuit->u.p2p.neighbor;
  535:   if (!adj || adj->level != hdr->circuit_t)
  536:     {
  537:       if (!adj)
  538:         {
  539:           adj = isis_new_adj (hdr->source_id, NULL, hdr->circuit_t, circuit);
  540:           if (adj == NULL)
  541:             return ISIS_ERROR;
  542:         }
  543:       else
  544:         {
  545:           adj->level = hdr->circuit_t;
  546:         }
  547:       circuit->u.p2p.neighbor = adj;
  548:       isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL);
  549:       adj->sys_type = ISIS_SYSTYPE_UNKNOWN;
  550:     }
  551: 
  552:   /* 8.2.6 Monitoring point-to-point adjacencies */
  553:   adj->hold_time = ntohs (hdr->hold_time);
  554:   adj->last_upd = time (NULL);
  555: 
  556:   /* we do this now because the adj may not survive till the end... */
  557:   tlvs_to_adj_area_addrs (&tlvs, adj);
  558: 
  559:   /* which protocol are spoken ??? */
  560:   if (tlvs_to_adj_nlpids (&tlvs, adj))
  561:     {
  562:       free_tlvs (&tlvs);
  563:       return ISIS_WARNING;
  564:     }
  565: 
  566:   /* we need to copy addresses to the adj */
  567:   if (found & TLVFLAG_IPV4_ADDR)
  568:     tlvs_to_adj_ipv4_addrs (&tlvs, adj);
  569: 
  570: #ifdef HAVE_IPV6
  571:   if (found & TLVFLAG_IPV6_ADDR)
  572:     tlvs_to_adj_ipv6_addrs (&tlvs, adj);
  573: #endif /* HAVE_IPV6 */
  574: 
  575:   /* lets take care of the expiry */
  576:   THREAD_TIMER_OFF (adj->t_expire);
  577:   THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj,
  578: 		   (long) adj->hold_time);
  579: 
  580:   /* 8.2.5.2 a) a match was detected */
  581:   if (area_match (circuit->area->area_addrs, tlvs.area_addrs))
  582:     {
  583:       /* 8.2.5.2 a) 2) If the system is L1 - table 5 */
  584:       if (circuit->area->is_type == IS_LEVEL_1)
  585: 	{
  586: 	  switch (hdr->circuit_t)
  587: 	    {
  588: 	    case IS_LEVEL_1:
  589: 	    case IS_LEVEL_1_AND_2:
  590: 	      if (adj->adj_state != ISIS_ADJ_UP)
  591: 		{
  592: 		  /* (4) adj state up */
  593: 		  isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
  594: 		  /* (5) adj usage level 1 */
  595: 		  adj->adj_usage = ISIS_ADJ_LEVEL1;
  596: 		}
  597: 	      else if (adj->adj_usage == ISIS_ADJ_LEVEL1)
  598: 		{
  599: 		  ;		/* accept */
  600: 		}
  601: 	      break;
  602: 	    case IS_LEVEL_2:
  603: 	      if (adj->adj_state != ISIS_ADJ_UP)
  604: 		{
  605: 		  /* (7) reject - wrong system type event */
  606: 		  zlog_warn ("wrongSystemType");
  607:                   free_tlvs (&tlvs);
  608: 		  return ISIS_WARNING;	/* Reject */
  609: 		}
  610: 	      else if (adj->adj_usage == ISIS_ADJ_LEVEL1)
  611: 		{
  612: 		  /* (6) down - wrong system */
  613: 		  isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
  614: 		}
  615: 	      break;
  616: 	    }
  617: 	}
  618: 
  619:       /* 8.2.5.2 a) 3) If the system is L1L2 - table 6 */
  620:       if (circuit->area->is_type == IS_LEVEL_1_AND_2)
  621: 	{
  622: 	  switch (hdr->circuit_t)
  623: 	    {
  624: 	    case IS_LEVEL_1:
  625: 	      if (adj->adj_state != ISIS_ADJ_UP)
  626: 		{
  627: 		  /* (6) adj state up */
  628: 		  isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
  629: 		  /* (7) adj usage level 1 */
  630: 		  adj->adj_usage = ISIS_ADJ_LEVEL1;
  631: 		}
  632: 	      else if (adj->adj_usage == ISIS_ADJ_LEVEL1)
  633: 		{
  634: 		  ;		/* accept */
  635: 		}
  636: 	      else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
  637: 		       (adj->adj_usage == ISIS_ADJ_LEVEL2))
  638: 		{
  639: 		  /* (8) down - wrong system */
  640: 		  isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
  641: 		}
  642: 	      break;
  643: 	    case IS_LEVEL_2:
  644: 	      if (adj->adj_state != ISIS_ADJ_UP)
  645: 		{
  646: 		  /* (6) adj state up */
  647: 		  isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
  648: 		  /* (9) adj usage level 2 */
  649: 		  adj->adj_usage = ISIS_ADJ_LEVEL2;
  650: 		}
  651: 	      else if ((adj->adj_usage == ISIS_ADJ_LEVEL1) ||
  652: 		       (adj->adj_usage == ISIS_ADJ_LEVEL1AND2))
  653: 		{
  654: 		  /* (8) down - wrong system */
  655: 		  isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
  656: 		}
  657: 	      else if (adj->adj_usage == ISIS_ADJ_LEVEL2)
  658: 		{
  659: 		  ;		/* Accept */
  660: 		}
  661: 	      break;
  662: 	    case IS_LEVEL_1_AND_2:
  663: 	      if (adj->adj_state != ISIS_ADJ_UP)
  664: 		{
  665: 		  /* (6) adj state up */
  666: 		  isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
  667: 		  /* (10) adj usage level 1 */
  668: 		  adj->adj_usage = ISIS_ADJ_LEVEL1AND2;
  669: 		}
  670: 	      else if ((adj->adj_usage == ISIS_ADJ_LEVEL1) ||
  671: 		       (adj->adj_usage == ISIS_ADJ_LEVEL2))
  672: 		{
  673: 		  /* (8) down - wrong system */
  674: 		  isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
  675: 		}
  676: 	      else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2)
  677: 		{
  678: 		  ;		/* Accept */
  679: 		}
  680: 	      break;
  681: 	    }
  682: 	}
  683: 
  684:       /* 8.2.5.2 a) 4) If the system is L2 - table 7 */
  685:       if (circuit->area->is_type == IS_LEVEL_2)
  686: 	{
  687: 	  switch (hdr->circuit_t)
  688: 	    {
  689: 	    case IS_LEVEL_1:
  690: 	      if (adj->adj_state != ISIS_ADJ_UP)
  691: 		{
  692: 		  /* (5) reject - wrong system type event */
  693: 		  zlog_warn ("wrongSystemType");
  694:                   free_tlvs (&tlvs);
  695: 		  return ISIS_WARNING;	/* Reject */
  696: 		}
  697: 	      else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
  698: 		       (adj->adj_usage == ISIS_ADJ_LEVEL2))
  699: 		{
  700: 		  /* (6) down - wrong system */
  701: 		  isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
  702: 		}
  703: 	      break;
  704: 	    case IS_LEVEL_1_AND_2:
  705: 	    case IS_LEVEL_2:
  706: 	      if (adj->adj_state != ISIS_ADJ_UP)
  707: 		{
  708: 		  /* (7) adj state up */
  709: 		  isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
  710: 		  /* (8) adj usage level 2 */
  711: 		  adj->adj_usage = ISIS_ADJ_LEVEL2;
  712: 		}
  713: 	      else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2)
  714: 		{
  715: 		  /* (6) down - wrong system */
  716: 		  isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
  717: 		}
  718: 	      else if (adj->adj_usage == ISIS_ADJ_LEVEL2)
  719: 		{
  720: 		  ;		/* Accept */
  721: 		}
  722: 	      break;
  723: 	    }
  724: 	}
  725:     }
  726:   /* 8.2.5.2 b) if no match was detected */
  727:   else if (listcount (circuit->area->area_addrs) > 0)
  728:     {
  729:       if (circuit->area->is_type == IS_LEVEL_1)
  730: 	{
  731: 	  /* 8.2.5.2 b) 1) is_type L1 and adj is not up */
  732: 	  if (adj->adj_state != ISIS_ADJ_UP)
  733: 	    {
  734: 	      isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch");
  735: 	      /* 8.2.5.2 b) 2)is_type L1 and adj is up */
  736: 	    }
  737: 	  else
  738: 	    {
  739: 	      isis_adj_state_change (adj, ISIS_ADJ_DOWN,
  740: 				     "Down - Area Mismatch");
  741: 	    }
  742: 	}
  743:       /* 8.2.5.2 b 3 If the system is L2 or L1L2 - table 8 */
  744:       else
  745: 	{
  746: 	  switch (hdr->circuit_t)
  747: 	    {
  748: 	    case IS_LEVEL_1:
  749: 	      if (adj->adj_state != ISIS_ADJ_UP)
  750: 		{
  751: 		  /* (6) reject - Area Mismatch event */
  752: 		  zlog_warn ("AreaMismatch");
  753:                   free_tlvs (&tlvs);
  754: 		  return ISIS_WARNING;	/* Reject */
  755: 		}
  756: 	      else if (adj->adj_usage == ISIS_ADJ_LEVEL1)
  757: 		{
  758: 		  /* (7) down - area mismatch */
  759: 		  isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch");
  760: 
  761: 		}
  762: 	      else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
  763: 		       (adj->adj_usage == ISIS_ADJ_LEVEL2))
  764: 		{
  765: 		  /* (7) down - wrong system */
  766: 		  isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
  767: 		}
  768: 	      break;
  769: 	    case IS_LEVEL_1_AND_2:
  770: 	    case IS_LEVEL_2:
  771: 	      if (adj->adj_state != ISIS_ADJ_UP)
  772: 		{
  773: 		  /* (8) adj state up */
  774: 		  isis_adj_state_change (adj, ISIS_ADJ_UP, NULL);
  775: 		  /* (9) adj usage level 2 */
  776: 		  adj->adj_usage = ISIS_ADJ_LEVEL2;
  777: 		}
  778: 	      else if (adj->adj_usage == ISIS_ADJ_LEVEL1)
  779: 		{
  780: 		  /* (7) down - wrong system */
  781: 		  isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System");
  782: 		}
  783: 	      else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2)
  784: 		{
  785: 		  if (hdr->circuit_t == IS_LEVEL_2)
  786: 		    {
  787: 		      /* (7) down - wrong system */
  788: 		      isis_adj_state_change (adj, ISIS_ADJ_DOWN,
  789: 					     "Wrong System");
  790: 		    }
  791: 		  else
  792: 		    {
  793: 		      /* (7) down - area mismatch */
  794: 		      isis_adj_state_change (adj, ISIS_ADJ_DOWN,
  795: 					     "Area Mismatch");
  796: 		    }
  797: 		}
  798: 	      else if (adj->adj_usage == ISIS_ADJ_LEVEL2)
  799: 		{
  800: 		  ;		/* Accept */
  801: 		}
  802: 	      break;
  803: 	    }
  804: 	}
  805:     }
  806:   else
  807:     {
  808:       /* down - area mismatch */
  809:       isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch");
  810:     }
  811:   /* 8.2.5.2 c) if the action was up - comparing circuit IDs */
  812:   /* FIXME - Missing parts */
  813: 
  814:   /* some of my own understanding of the ISO, why the heck does
  815:    * it not say what should I change the system_type to...
  816:    */
  817:   switch (adj->adj_usage)
  818:     {
  819:     case ISIS_ADJ_LEVEL1:
  820:       adj->sys_type = ISIS_SYSTYPE_L1_IS;
  821:       break;
  822:     case ISIS_ADJ_LEVEL2:
  823:       adj->sys_type = ISIS_SYSTYPE_L2_IS;
  824:       break;
  825:     case ISIS_ADJ_LEVEL1AND2:
  826:       adj->sys_type = ISIS_SYSTYPE_L2_IS;
  827:       break;
  828:     case ISIS_ADJ_NONE:
  829:       adj->sys_type = ISIS_SYSTYPE_UNKNOWN;
  830:       break;
  831:     }
  832: 
  833:   adj->circuit_t = hdr->circuit_t;
  834: 
  835:   if (isis->debugs & DEBUG_ADJ_PACKETS)
  836:     {
  837:       zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s,"
  838: 		  " cir id %02d, length %d",
  839: 		  circuit->area->area_tag, circuit->interface->name,
  840: 		  circuit_t2string (circuit->is_type),
  841: 		  circuit->circuit_id, pdu_len);
  842:     }
  843: 
  844:   free_tlvs (&tlvs);
  845: 
  846:   return retval;
  847: }
  848: 
  849: /*
  850:  * Process IS-IS LAN Level 1/2 Hello PDU
  851:  */
  852: static int
  853: process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)
  854: {
  855:   int retval = ISIS_OK;
  856:   struct isis_lan_hello_hdr hdr;
  857:   struct isis_adjacency *adj;
  858:   u_int32_t expected = 0, found = 0, auth_tlv_offset = 0;
  859:   struct tlvs tlvs;
  860:   u_char *snpa;
  861:   struct listnode *node;
  862: 
  863:   if (isis->debugs & DEBUG_ADJ_PACKETS)
  864:     {
  865:       zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH on %s, cirType %s, "
  866:                   "cirID %u",
  867:                   circuit->area->area_tag, level, circuit->interface->name,
  868:                   circuit_t2string (circuit->is_type), circuit->circuit_id);
  869:       if (isis->debugs & DEBUG_PACKET_DUMP)
  870:         zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
  871:                         stream_get_endp (circuit->rcv_stream));
  872:     }
  873: 
  874:   if (circuit->circ_type != CIRCUIT_T_BROADCAST)
  875:     {
  876:       zlog_warn ("lan hello on non broadcast circuit");
  877:       return ISIS_WARNING;
  878:     }
  879: 
  880:   if ((stream_get_endp (circuit->rcv_stream) -
  881:        stream_get_getp (circuit->rcv_stream)) < ISIS_LANHELLO_HDRLEN)
  882:     {
  883:       zlog_warn ("Packet too short");
  884:       return ISIS_WARNING;
  885:     }
  886: 
  887:   if (circuit->ext_domain)
  888:     {
  889:       zlog_debug ("level %d LAN Hello received over circuit with "
  890: 		  "externalDomain = true", level);
  891:       return ISIS_WARNING;
  892:     }
  893: 
  894:   if (!accept_level (level, circuit->is_type))
  895:     {
  896:       if (isis->debugs & DEBUG_ADJ_PACKETS)
  897: 	{
  898: 	  zlog_debug ("ISIS-Adj (%s): Interface level mismatch, %s",
  899: 		      circuit->area->area_tag, circuit->interface->name);
  900: 	}
  901:       return ISIS_WARNING;
  902:     }
  903: 
  904: #if 0
  905:   /* Cisco's debug message compatability */
  906:   if (!accept_level (level, circuit->area->is_type))
  907:     {
  908:       if (isis->debugs & DEBUG_ADJ_PACKETS)
  909: 	{
  910: 	  zlog_debug ("ISIS-Adj (%s): is type mismatch",
  911: 		      circuit->area->area_tag);
  912: 	}
  913:       return ISIS_WARNING;
  914:     }
  915: #endif
  916:   /*
  917:    * Fill the header
  918:    */
  919:   hdr.circuit_t = stream_getc (circuit->rcv_stream);
  920:   stream_get (hdr.source_id, circuit->rcv_stream, ISIS_SYS_ID_LEN);
  921:   hdr.hold_time = stream_getw (circuit->rcv_stream);
  922:   hdr.pdu_len = stream_getw (circuit->rcv_stream);
  923:   hdr.prio = stream_getc (circuit->rcv_stream);
  924:   stream_get (hdr.lan_id, circuit->rcv_stream, ISIS_SYS_ID_LEN + 1);
  925: 
  926:   if (hdr.pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_LANHELLO_HDRLEN) ||
  927:       hdr.pdu_len > ISO_MTU(circuit) ||
  928:       hdr.pdu_len > stream_get_endp (circuit->rcv_stream))
  929:     {
  930:       zlog_warn ("ISIS-Adj (%s): Rcvd LAN IIH from (%s) with "
  931:                  "invalid pdu length %d",
  932:                  circuit->area->area_tag, circuit->interface->name,
  933:                  hdr.pdu_len);
  934:       return ISIS_WARNING;
  935:     }
  936: 
  937:   /*
  938:    * Set the stream endp to PDU length, ignoring additional padding
  939:    * introduced by transport chips.
  940:    */
  941:   if (hdr.pdu_len < stream_get_endp (circuit->rcv_stream))
  942:     stream_set_endp (circuit->rcv_stream, hdr.pdu_len);
  943: 
  944:   if (hdr.circuit_t != IS_LEVEL_1 &&
  945:       hdr.circuit_t != IS_LEVEL_2 &&
  946:       hdr.circuit_t != IS_LEVEL_1_AND_2 &&
  947:       (level & hdr.circuit_t) == 0)
  948:     {
  949:       zlog_err ("Level %d LAN Hello with Circuit Type %d", level,
  950:                 hdr.circuit_t);
  951:       return ISIS_ERROR;
  952:     }
  953: 
  954:   /*
  955:    * Then get the tlvs
  956:    */
  957:   expected |= TLVFLAG_AUTH_INFO;
  958:   expected |= TLVFLAG_AREA_ADDRS;
  959:   expected |= TLVFLAG_LAN_NEIGHS;
  960:   expected |= TLVFLAG_NLPID;
  961:   expected |= TLVFLAG_IPV4_ADDR;
  962:   expected |= TLVFLAG_IPV6_ADDR;
  963: 
  964:   auth_tlv_offset = stream_get_getp (circuit->rcv_stream);
  965:   retval = parse_tlvs (circuit->area->area_tag,
  966:                        STREAM_PNT (circuit->rcv_stream),
  967:                        hdr.pdu_len - ISIS_LANHELLO_HDRLEN - ISIS_FIXED_HDR_LEN,
  968:                        &expected, &found, &tlvs,
  969:                        &auth_tlv_offset);
  970: 
  971:   if (retval > ISIS_WARNING)
  972:     {
  973:       zlog_warn ("parse_tlvs() failed");
  974:       goto out;
  975:     }
  976: 
  977:   if (!(found & TLVFLAG_AREA_ADDRS))
  978:     {
  979:       zlog_warn ("No Area addresses TLV in Level %d LAN IS to IS hello",
  980: 		 level);
  981:       retval = ISIS_WARNING;
  982:       goto out;
  983:     }
  984: 
  985:   if (!(found & TLVFLAG_NLPID))
  986:     {
  987:       zlog_warn ("No supported protocols TLV in Level %d LAN IS to IS hello",
  988: 		 level);
  989:       retval = ISIS_WARNING;
  990:       goto out;
  991:     }
  992: 
  993:   /* Verify authentication, either cleartext of HMAC MD5 */
  994:   if (circuit->passwd.type)
  995:     {
  996:       if (!(found & TLVFLAG_AUTH_INFO) ||
  997:           authentication_check (&tlvs.auth_info, &circuit->passwd,
  998:                                 circuit->rcv_stream, auth_tlv_offset))
  999:         {
 1000:           isis_event_auth_failure (circuit->area->area_tag,
 1001:                                    "LAN hello authentication failure",
 1002:                                    hdr.source_id);
 1003:           retval = ISIS_WARNING;
 1004:           goto out;
 1005:         }
 1006:     }
 1007: 
 1008:   if (!memcmp (hdr.source_id, isis->sysid, ISIS_SYS_ID_LEN))
 1009:     {
 1010:       zlog_warn ("ISIS-Adj (%s): duplicate system ID on interface %s",
 1011: 		 circuit->area->area_tag, circuit->interface->name);
 1012:       return ISIS_WARNING;
 1013:     }
 1014: 
 1015:   /*
 1016:    * Accept the level 1 adjacency only if a match between local and
 1017:    * remote area addresses is found
 1018:    */
 1019:   if (listcount (circuit->area->area_addrs) == 0 ||
 1020:       (level == IS_LEVEL_1 &&
 1021:        area_match (circuit->area->area_addrs, tlvs.area_addrs) == 0))
 1022:     {
 1023:       if (isis->debugs & DEBUG_ADJ_PACKETS)
 1024: 	{
 1025: 	  zlog_debug ("ISIS-Adj (%s): Area mismatch, level %d IIH on %s",
 1026: 		      circuit->area->area_tag, level,
 1027: 		      circuit->interface->name);
 1028: 	}
 1029:       retval = ISIS_OK;
 1030:       goto out;
 1031:     }
 1032: 
 1033:   /* 
 1034:    * it's own IIH PDU - discard silently 
 1035:    */
 1036:   if (!memcmp (circuit->u.bc.snpa, ssnpa, ETH_ALEN))
 1037:     {
 1038:       zlog_debug ("ISIS-Adj (%s): it's own IIH PDU - discarded",
 1039: 		  circuit->area->area_tag);
 1040: 
 1041:       retval = ISIS_OK;
 1042:       goto out;
 1043:     }
 1044: 
 1045:   /*
 1046:    * check if it's own interface ip match iih ip addrs
 1047:    */
 1048:   if ((found & TLVFLAG_IPV4_ADDR) == 0 ||
 1049:       ip_match (circuit->ip_addrs, tlvs.ipv4_addrs) == 0)
 1050:     {
 1051:       zlog_debug ("ISIS-Adj: No usable IP interface addresses "
 1052:                   "in LAN IIH from %s\n", circuit->interface->name);
 1053:       retval = ISIS_WARNING;
 1054:       goto out;
 1055:     }
 1056: 
 1057:   adj = isis_adj_lookup (hdr.source_id, circuit->u.bc.adjdb[level - 1]);
 1058:   if ((adj == NULL) || (memcmp(adj->snpa, ssnpa, ETH_ALEN)) ||
 1059:       (adj->level != level))
 1060:     {
 1061:       if (!adj)
 1062:         {
 1063:           /*
 1064:            * Do as in 8.4.2.5
 1065:            */
 1066:           adj = isis_new_adj (hdr.source_id, ssnpa, level, circuit);
 1067:           if (adj == NULL)
 1068:             {
 1069:               retval = ISIS_ERROR;
 1070:               goto out;
 1071:             }
 1072:         }
 1073:       else
 1074:         {
 1075:           if (ssnpa) {
 1076:             memcpy (adj->snpa, ssnpa, 6);
 1077:           } else {
 1078:             memset (adj->snpa, ' ', 6);
 1079:           }
 1080:           adj->level = level;
 1081:         }
 1082:       isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL);
 1083: 
 1084:       if (level == IS_LEVEL_1)
 1085:           adj->sys_type = ISIS_SYSTYPE_L1_IS;
 1086:       else
 1087:           adj->sys_type = ISIS_SYSTYPE_L2_IS;
 1088:       list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]);
 1089:       isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1],
 1090:                                  circuit->u.bc.lan_neighs[level - 1]);
 1091:     }
 1092: 
 1093:   if(adj->dis_record[level-1].dis==ISIS_IS_DIS)
 1094:     switch (level)
 1095:       {
 1096:       case 1:
 1097: 	if (memcmp (circuit->u.bc.l1_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1))
 1098: 	  {
 1099:             thread_add_event (master, isis_event_dis_status_change, circuit, 0);
 1100: 	    memcpy (&circuit->u.bc.l1_desig_is, hdr.lan_id,
 1101: 		    ISIS_SYS_ID_LEN + 1);
 1102: 	  }
 1103: 	break;
 1104:       case 2:
 1105: 	if (memcmp (circuit->u.bc.l2_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1))
 1106: 	  {
 1107:             thread_add_event (master, isis_event_dis_status_change, circuit, 0);
 1108: 	    memcpy (&circuit->u.bc.l2_desig_is, hdr.lan_id,
 1109: 		    ISIS_SYS_ID_LEN + 1);
 1110: 	  }
 1111: 	break;
 1112:       }
 1113: 
 1114:   adj->hold_time = hdr.hold_time;
 1115:   adj->last_upd = time (NULL);
 1116:   adj->prio[level - 1] = hdr.prio;
 1117: 
 1118:   memcpy (adj->lanid, hdr.lan_id, ISIS_SYS_ID_LEN + 1);
 1119: 
 1120:   tlvs_to_adj_area_addrs (&tlvs, adj);
 1121: 
 1122:   /* which protocol are spoken ??? */
 1123:   if (tlvs_to_adj_nlpids (&tlvs, adj))
 1124:     {
 1125:       retval = ISIS_WARNING;
 1126:       goto out;
 1127:     }
 1128: 
 1129:   /* we need to copy addresses to the adj */
 1130:   if (found & TLVFLAG_IPV4_ADDR)
 1131:     tlvs_to_adj_ipv4_addrs (&tlvs, adj);
 1132: 
 1133: #ifdef HAVE_IPV6
 1134:   if (found & TLVFLAG_IPV6_ADDR)
 1135:     tlvs_to_adj_ipv6_addrs (&tlvs, adj);
 1136: #endif /* HAVE_IPV6 */
 1137: 
 1138:   adj->circuit_t = hdr.circuit_t;
 1139: 
 1140:   /* lets take care of the expiry */
 1141:   THREAD_TIMER_OFF (adj->t_expire);
 1142:   THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj,
 1143:                    (long) adj->hold_time);
 1144: 
 1145:   /*
 1146:    * If the snpa for this circuit is found from LAN Neighbours TLV
 1147:    * we have two-way communication -> adjacency can be put to state "up"
 1148:    */
 1149: 
 1150:   if (found & TLVFLAG_LAN_NEIGHS)
 1151:   {
 1152:     if (adj->adj_state != ISIS_ADJ_UP)
 1153:     {
 1154:       for (ALL_LIST_ELEMENTS_RO (tlvs.lan_neighs, node, snpa))
 1155:       {
 1156:         if (!memcmp (snpa, circuit->u.bc.snpa, ETH_ALEN))
 1157:         {
 1158:           isis_adj_state_change (adj, ISIS_ADJ_UP,
 1159:                                  "own SNPA found in LAN Neighbours TLV");
 1160:         }
 1161:       }
 1162:     }
 1163:     else
 1164:     {
 1165:       int found = 0;
 1166:       for (ALL_LIST_ELEMENTS_RO (tlvs.lan_neighs, node, snpa))
 1167:         if (!memcmp (snpa, circuit->u.bc.snpa, ETH_ALEN))
 1168:         {
 1169:           found = 1;
 1170:           break;
 1171:         }
 1172:       if (found == 0)
 1173:         isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING,
 1174:                                "own SNPA not found in LAN Neighbours TLV");
 1175:     }
 1176:   }
 1177:   else if (adj->adj_state == ISIS_ADJ_UP)
 1178:   {
 1179:     isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING,
 1180:                            "no LAN Neighbours TLV found");
 1181:   }
 1182: 
 1183: out:
 1184:   if (isis->debugs & DEBUG_ADJ_PACKETS)
 1185:     {
 1186:       zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH from %s on %s, cirType %s, "
 1187: 		  "cirID %u, length %ld",
 1188: 		  circuit->area->area_tag,
 1189: 		  level, snpa_print (ssnpa), circuit->interface->name,
 1190: 		  circuit_t2string (circuit->is_type),
 1191: 		  circuit->circuit_id,
 1192: 		  stream_get_endp (circuit->rcv_stream));
 1193:     }
 1194: 
 1195:   free_tlvs (&tlvs);
 1196: 
 1197:   return retval;
 1198: }
 1199: 
 1200: /*
 1201:  * Process Level 1/2 Link State
 1202:  * ISO - 10589
 1203:  * Section 7.3.15.1 - Action on receipt of a link state PDU
 1204:  */
 1205: static int
 1206: process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa)
 1207: {
 1208:   struct isis_link_state_hdr *hdr;
 1209:   struct isis_adjacency *adj = NULL;
 1210:   struct isis_lsp *lsp, *lsp0 = NULL;
 1211:   int retval = ISIS_OK, comp = 0;
 1212:   u_char lspid[ISIS_SYS_ID_LEN + 2];
 1213:   struct isis_passwd *passwd;
 1214:   uint16_t pdu_len;
 1215: 
 1216:   if (isis->debugs & DEBUG_UPDATE_PACKETS)
 1217:     {
 1218:       zlog_debug ("ISIS-Upd (%s): Rcvd L%d LSP on %s, cirType %s, cirID %u",
 1219:                   circuit->area->area_tag, level, circuit->interface->name,
 1220:                   circuit_t2string (circuit->is_type), circuit->circuit_id);
 1221:       if (isis->debugs & DEBUG_PACKET_DUMP)
 1222:         zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
 1223:                         stream_get_endp (circuit->rcv_stream));
 1224:     }
 1225: 
 1226:   if ((stream_get_endp (circuit->rcv_stream) -
 1227:        stream_get_getp (circuit->rcv_stream)) < ISIS_LSP_HDR_LEN)
 1228:     {
 1229:       zlog_warn ("Packet too short");
 1230:       return ISIS_WARNING;
 1231:     }
 1232: 
 1233:   /* Reference the header   */
 1234:   hdr = (struct isis_link_state_hdr *) STREAM_PNT (circuit->rcv_stream);
 1235:   pdu_len = ntohs (hdr->pdu_len);
 1236: 
 1237:   /* lsp length check */
 1238:   if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN) ||
 1239:       pdu_len > ISO_MTU(circuit) ||
 1240:       pdu_len > stream_get_endp (circuit->rcv_stream))
 1241:     {
 1242:       zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP length %d",
 1243: 		  circuit->area->area_tag,
 1244: 		  rawlspid_print (hdr->lsp_id), pdu_len);
 1245: 
 1246:       return ISIS_WARNING;
 1247:     }
 1248: 
 1249:   /*
 1250:    * Set the stream endp to PDU length, ignoring additional padding
 1251:    * introduced by transport chips.
 1252:    */
 1253:   if (pdu_len < stream_get_endp (circuit->rcv_stream))
 1254:     stream_set_endp (circuit->rcv_stream, pdu_len);
 1255: 
 1256:   if (isis->debugs & DEBUG_UPDATE_PACKETS)
 1257:     {
 1258:       zlog_debug ("ISIS-Upd (%s): Rcvd L%d LSP %s, seq 0x%08x, cksum 0x%04x, "
 1259: 		  "lifetime %us, len %u, on %s",
 1260: 		  circuit->area->area_tag,
 1261: 		  level,
 1262: 		  rawlspid_print (hdr->lsp_id),
 1263: 		  ntohl (hdr->seq_num),
 1264: 		  ntohs (hdr->checksum),
 1265: 		  ntohs (hdr->rem_lifetime),
 1266: 		  pdu_len,
 1267: 		  circuit->interface->name);
 1268:     }
 1269: 
 1270:   /* lsp is_type check */
 1271:   if ((hdr->lsp_bits & IS_LEVEL_1_AND_2) != IS_LEVEL_1 &&
 1272:       (hdr->lsp_bits & IS_LEVEL_1_AND_2) != IS_LEVEL_1_AND_2)
 1273:     {
 1274:       zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP is type %x",
 1275: 		  circuit->area->area_tag,
 1276: 		  rawlspid_print (hdr->lsp_id), hdr->lsp_bits);
 1277:       /* continue as per RFC1122 Be liberal in what you accept, and
 1278:        * conservative in what you send */
 1279:     }
 1280: 
 1281:   /* Checksum sanity check - FIXME: move to correct place */
 1282:   /* 12 = sysid+pdu+remtime */
 1283:   if (iso_csum_verify (STREAM_PNT (circuit->rcv_stream) + 4,
 1284: 		       pdu_len - 12, &hdr->checksum))
 1285:     {
 1286:       zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP checksum 0x%04x",
 1287: 		  circuit->area->area_tag,
 1288: 		  rawlspid_print (hdr->lsp_id), ntohs (hdr->checksum));
 1289: 
 1290:       return ISIS_WARNING;
 1291:     }
 1292: 
 1293:   /* 7.3.15.1 a) 1 - external domain circuit will discard lsps */
 1294:   if (circuit->ext_domain)
 1295:     {
 1296:       zlog_debug
 1297: 	("ISIS-Upd (%s): LSP %s received at level %d over circuit with "
 1298: 	 "externalDomain = true", circuit->area->area_tag,
 1299: 	 rawlspid_print (hdr->lsp_id), level);
 1300: 
 1301:       return ISIS_WARNING;
 1302:     }
 1303: 
 1304:   /* 7.3.15.1 a) 2,3 - manualL2OnlyMode not implemented */
 1305:   if (!accept_level (level, circuit->is_type))
 1306:     {
 1307:       zlog_debug ("ISIS-Upd (%s): LSP %s received at level %d over circuit of"
 1308: 		  " type %s",
 1309: 		  circuit->area->area_tag,
 1310: 		  rawlspid_print (hdr->lsp_id),
 1311: 		  level, circuit_t2string (circuit->is_type));
 1312: 
 1313:       return ISIS_WARNING;
 1314:     }
 1315: 
 1316:   /* 7.3.15.1 a) 4 - need to make sure IDLength matches */
 1317: 
 1318:   /* 7.3.15.1 a) 5 - maximum area match, can be ommited since we only use 3 */
 1319: 
 1320:   /* 7.3.15.1 a) 7 - password check */
 1321:   (level == IS_LEVEL_1) ? (passwd = &circuit->area->area_passwd) :
 1322:                           (passwd = &circuit->area->domain_passwd);
 1323:   if (passwd->type)
 1324:     {
 1325:       if (lsp_authentication_check (circuit->rcv_stream, circuit->area,
 1326:                                     level, passwd))
 1327: 	{
 1328: 	  isis_event_auth_failure (circuit->area->area_tag,
 1329: 				   "LSP authentication failure", hdr->lsp_id);
 1330: 	  return ISIS_WARNING;
 1331: 	}
 1332:     }
 1333:   /* Find the LSP in our database and compare it to this Link State header */
 1334:   lsp = lsp_search (hdr->lsp_id, circuit->area->lspdb[level - 1]);
 1335:   if (lsp)
 1336:     comp = lsp_compare (circuit->area->area_tag, lsp, hdr->seq_num,
 1337: 			hdr->checksum, hdr->rem_lifetime);
 1338:   if (lsp && (lsp->own_lsp
 1339: #ifdef TOPOLOGY_GENERATE
 1340: 	      || lsp->from_topology
 1341: #endif /* TOPOLOGY_GENERATE */
 1342:       ))
 1343:     goto dontcheckadj;
 1344: 
 1345:   /* 7.3.15.1 a) 6 - Must check that we have an adjacency of the same level  */
 1346:   /* for broadcast circuits, snpa should be compared */
 1347: 
 1348:   if (circuit->circ_type == CIRCUIT_T_BROADCAST)
 1349:     {
 1350:       adj = isis_adj_lookup_snpa (ssnpa, circuit->u.bc.adjdb[level - 1]);
 1351:       if (!adj)
 1352: 	{
 1353: 	  zlog_debug ("(%s): DS ======= LSP %s, seq 0x%08x, cksum 0x%04x, "
 1354: 		      "lifetime %us on %s",
 1355: 		      circuit->area->area_tag,
 1356: 		      rawlspid_print (hdr->lsp_id),
 1357: 		      ntohl (hdr->seq_num),
 1358: 		      ntohs (hdr->checksum),
 1359: 		      ntohs (hdr->rem_lifetime), circuit->interface->name);
 1360: 	  return ISIS_WARNING;	/* Silently discard */
 1361: 	}
 1362:     }
 1363:   /* for non broadcast, we just need to find same level adj */
 1364:   else
 1365:     {
 1366:       /* If no adj, or no sharing of level */
 1367:       if (!circuit->u.p2p.neighbor)
 1368: 	{
 1369: 	  return ISIS_OK;	/* Silently discard */
 1370: 	}
 1371:       else
 1372: 	{
 1373: 	  if (((level == IS_LEVEL_1) &&
 1374: 	       (circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL2)) ||
 1375: 	      ((level == IS_LEVEL_2) &&
 1376: 	       (circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL1)))
 1377: 	    return ISIS_WARNING;	/* Silently discard */
 1378: 	  adj = circuit->u.p2p.neighbor;
 1379: 	}
 1380:     }
 1381: 
 1382: dontcheckadj:
 1383:   /* 7.3.15.1 a) 7 - Passwords for level 1 - not implemented  */
 1384: 
 1385:   /* 7.3.15.1 a) 8 - Passwords for level 2 - not implemented  */
 1386: 
 1387:   /* 7.3.15.1 a) 9 - OriginatingLSPBufferSize - not implemented  FIXME: do it */
 1388: 
 1389:   /* 7.3.15.1 b) - If the remaining life time is 0, we perform 7.3.16.4 */
 1390:   if (hdr->rem_lifetime == 0)
 1391:     {
 1392:       if (!lsp)
 1393: 	{
 1394: 	  /* 7.3.16.4 a) 1) No LSP in db -> send an ack, but don't save */
 1395: 	  /* only needed on explicit update, eg - p2p */
 1396: 	  if (circuit->circ_type == CIRCUIT_T_P2P)
 1397: 	    ack_lsp (hdr, circuit, level);
 1398: 	  return retval;	/* FIXME: do we need a purge? */
 1399: 	}
 1400:       else
 1401: 	{
 1402: 	  if (memcmp (hdr->lsp_id, isis->sysid, ISIS_SYS_ID_LEN))
 1403: 	    {
 1404: 	      /* LSP by some other system -> do 7.3.16.4 b) */
 1405: 	      /* 7.3.16.4 b) 1)  */
 1406: 	      if (comp == LSP_NEWER)
 1407: 		{
 1408:                   lsp_update (lsp, circuit->rcv_stream, circuit->area, level);
 1409: 		  /* ii */
 1410:                   lsp_set_all_srmflags (lsp);
 1411: 		  /* iii */
 1412: 		  ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
 1413: 		  /* v */
 1414: 		  ISIS_FLAGS_CLEAR_ALL (lsp->SSNflags);	/* FIXME: OTHER than c */
 1415: 		  /* iv */
 1416: 		  if (circuit->circ_type != CIRCUIT_T_BROADCAST)
 1417: 		    ISIS_SET_FLAG (lsp->SSNflags, circuit);
 1418: 
 1419: 		}		/* 7.3.16.4 b) 2) */
 1420: 	      else if (comp == LSP_EQUAL)
 1421: 		{
 1422: 		  /* i */
 1423: 		  ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
 1424: 		  /* ii */
 1425: 		  if (circuit->circ_type != CIRCUIT_T_BROADCAST)
 1426: 		    ISIS_SET_FLAG (lsp->SSNflags, circuit);
 1427: 		}		/* 7.3.16.4 b) 3) */
 1428: 	      else
 1429: 		{
 1430: 		  ISIS_SET_FLAG (lsp->SRMflags, circuit);
 1431: 		  ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
 1432: 		}
 1433: 	    }
 1434:           else if (lsp->lsp_header->rem_lifetime != 0)
 1435:             {
 1436:               /* our own LSP -> 7.3.16.4 c) */
 1437:               if (comp == LSP_NEWER)
 1438:                 {
 1439:                   lsp_inc_seqnum (lsp, ntohl (hdr->seq_num));
 1440:                   lsp_set_all_srmflags (lsp);
 1441:                 }
 1442:               else
 1443:                 {
 1444:                   ISIS_SET_FLAG (lsp->SRMflags, circuit);
 1445:                   ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
 1446:                 }
 1447:               if (isis->debugs & DEBUG_UPDATE_PACKETS)
 1448:                 zlog_debug ("ISIS-Upd (%s): (1) re-originating LSP %s new "
 1449:                             "seq 0x%08x", circuit->area->area_tag,
 1450:                             rawlspid_print (hdr->lsp_id),
 1451:                             ntohl (lsp->lsp_header->seq_num));
 1452:             }
 1453: 	}
 1454:       return retval;
 1455:     }
 1456:   /* 7.3.15.1 c) - If this is our own lsp and we don't have it initiate a 
 1457:    * purge */
 1458:   if (memcmp (hdr->lsp_id, isis->sysid, ISIS_SYS_ID_LEN) == 0)
 1459:     {
 1460:       if (!lsp)
 1461: 	{
 1462: 	  /* 7.3.16.4: initiate a purge */
 1463: 	  lsp_purge_non_exist (hdr, circuit->area);
 1464: 	  return ISIS_OK;
 1465: 	}
 1466:       /* 7.3.15.1 d) - If this is our own lsp and we have it */
 1467: 
 1468:       /* In 7.3.16.1, If an Intermediate system R somewhere in the domain
 1469:        * has information that the current sequence number for source S is
 1470:        * "greater" than that held by S, ... */
 1471: 
 1472:       if (ntohl (hdr->seq_num) > ntohl (lsp->lsp_header->seq_num))
 1473: 	{
 1474: 	  /* 7.3.16.1  */
 1475:           lsp_inc_seqnum (lsp, ntohl (hdr->seq_num));
 1476: 	  if (isis->debugs & DEBUG_UPDATE_PACKETS)
 1477: 	    zlog_debug ("ISIS-Upd (%s): (2) re-originating LSP %s new seq "
 1478: 			"0x%08x", circuit->area->area_tag,
 1479: 			rawlspid_print (hdr->lsp_id),
 1480: 			ntohl (lsp->lsp_header->seq_num));
 1481: 	}
 1482:       /* If the received LSP is older or equal,
 1483:        * resend the LSP which will act as ACK */
 1484:       lsp_set_all_srmflags (lsp);
 1485:     }
 1486:   else
 1487:     {
 1488:       /* 7.3.15.1 e) - This lsp originated on another system */
 1489: 
 1490:       /* 7.3.15.1 e) 1) LSP newer than the one in db or no LSP in db */
 1491:       if ((!lsp || comp == LSP_NEWER))
 1492: 	{
 1493: 	  /*
 1494: 	   * If this lsp is a frag, need to see if we have zero lsp present
 1495: 	   */
 1496: 	  if (LSP_FRAGMENT (hdr->lsp_id) != 0)
 1497: 	    {
 1498: 	      memcpy (lspid, hdr->lsp_id, ISIS_SYS_ID_LEN + 1);
 1499: 	      LSP_FRAGMENT (lspid) = 0;
 1500: 	      lsp0 = lsp_search (lspid, circuit->area->lspdb[level - 1]);
 1501: 	      if (!lsp0)
 1502: 		{
 1503: 		  zlog_debug ("Got lsp frag, while zero lsp not in database");
 1504: 		  return ISIS_OK;
 1505: 		}
 1506: 	    }
 1507: 	  /* i */
 1508: 	  if (!lsp)
 1509:             {
 1510: 	      lsp = lsp_new_from_stream_ptr (circuit->rcv_stream,
 1511:                                              pdu_len, lsp0,
 1512:                                              circuit->area, level);
 1513:               lsp_insert (lsp, circuit->area->lspdb[level - 1]);
 1514:             }
 1515:           else /* exists, so we overwrite */
 1516:             {
 1517:               lsp_update (lsp, circuit->rcv_stream, circuit->area, level);
 1518:             }
 1519: 	  /* ii */
 1520:           lsp_set_all_srmflags (lsp);
 1521: 	  /* iii */
 1522: 	  ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
 1523: 
 1524: 	  /* iv */
 1525: 	  if (circuit->circ_type != CIRCUIT_T_BROADCAST)
 1526: 	    ISIS_SET_FLAG (lsp->SSNflags, circuit);
 1527: 	  /* FIXME: v) */
 1528: 	}
 1529:       /* 7.3.15.1 e) 2) LSP equal to the one in db */
 1530:       else if (comp == LSP_EQUAL)
 1531: 	{
 1532: 	  ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
 1533: 	  lsp_update (lsp, circuit->rcv_stream, circuit->area, level);
 1534: 	  if (circuit->circ_type != CIRCUIT_T_BROADCAST)
 1535: 	    ISIS_SET_FLAG (lsp->SSNflags, circuit);
 1536: 	}
 1537:       /* 7.3.15.1 e) 3) LSP older than the one in db */
 1538:       else
 1539: 	{
 1540: 	  ISIS_SET_FLAG (lsp->SRMflags, circuit);
 1541: 	  ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
 1542: 	}
 1543:     }
 1544:   return retval;
 1545: }
 1546: 
 1547: /*
 1548:  * Process Sequence Numbers
 1549:  * ISO - 10589
 1550:  * Section 7.3.15.2 - Action on receipt of a sequence numbers PDU
 1551:  */
 1552: 
 1553: static int
 1554: process_snp (int snp_type, int level, struct isis_circuit *circuit,
 1555: 	     u_char * ssnpa)
 1556: {
 1557:   int retval = ISIS_OK;
 1558:   int cmp, own_lsp;
 1559:   char typechar = ' ';
 1560:   uint16_t pdu_len;
 1561:   struct isis_adjacency *adj;
 1562:   struct isis_complete_seqnum_hdr *chdr = NULL;
 1563:   struct isis_partial_seqnum_hdr *phdr = NULL;
 1564:   uint32_t found = 0, expected = 0, auth_tlv_offset = 0;
 1565:   struct isis_lsp *lsp;
 1566:   struct lsp_entry *entry;
 1567:   struct listnode *node, *nnode;
 1568:   struct listnode *node2, *nnode2;
 1569:   struct tlvs tlvs;
 1570:   struct list *lsp_list = NULL;
 1571:   struct isis_passwd *passwd;
 1572: 
 1573:   if (snp_type == ISIS_SNP_CSNP_FLAG)
 1574:     {
 1575:       /* getting the header info */
 1576:       typechar = 'C';
 1577:       chdr =
 1578: 	(struct isis_complete_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream);
 1579:       stream_forward_getp (circuit->rcv_stream, ISIS_CSNP_HDRLEN);
 1580:       pdu_len = ntohs (chdr->pdu_len);
 1581:       if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_CSNP_HDRLEN) ||
 1582:           pdu_len > ISO_MTU(circuit) ||
 1583:           pdu_len > stream_get_endp (circuit->rcv_stream))
 1584: 	{
 1585: 	  zlog_warn ("Received a CSNP with bogus length %d", pdu_len);
 1586: 	  return ISIS_WARNING;
 1587: 	}
 1588:     }
 1589:   else
 1590:     {
 1591:       typechar = 'P';
 1592:       phdr =
 1593: 	(struct isis_partial_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream);
 1594:       stream_forward_getp (circuit->rcv_stream, ISIS_PSNP_HDRLEN);
 1595:       pdu_len = ntohs (phdr->pdu_len);
 1596:       if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_PSNP_HDRLEN) ||
 1597:           pdu_len > ISO_MTU(circuit) ||
 1598:           pdu_len > stream_get_endp (circuit->rcv_stream))
 1599: 	{
 1600: 	  zlog_warn ("Received a CSNP with bogus length %d", pdu_len);
 1601: 	  return ISIS_WARNING;
 1602: 	}
 1603:     }
 1604: 
 1605:   /*
 1606:    * Set the stream endp to PDU length, ignoring additional padding
 1607:    * introduced by transport chips.
 1608:    */
 1609:   if (pdu_len < stream_get_endp (circuit->rcv_stream))
 1610:     stream_set_endp (circuit->rcv_stream, pdu_len);
 1611: 
 1612:   /* 7.3.15.2 a) 1 - external domain circuit will discard snp pdu */
 1613:   if (circuit->ext_domain)
 1614:     {
 1615: 
 1616:       zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "
 1617: 		  "skipping: circuit externalDomain = true",
 1618: 		  circuit->area->area_tag,
 1619: 		  level, typechar, circuit->interface->name);
 1620: 
 1621:       return ISIS_OK;
 1622:     }
 1623: 
 1624:   /* 7.3.15.2 a) 2,3 - manualL2OnlyMode not implemented */
 1625:   if (!accept_level (level, circuit->is_type))
 1626:     {
 1627: 
 1628:       zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "
 1629: 		  "skipping: circuit type %s does not match level %d",
 1630: 		  circuit->area->area_tag,
 1631: 		  level,
 1632: 		  typechar,
 1633: 		  circuit->interface->name,
 1634: 		  circuit_t2string (circuit->is_type), level);
 1635: 
 1636:       return ISIS_OK;
 1637:     }
 1638: 
 1639:   /* 7.3.15.2 a) 4 - not applicable for CSNP  only PSNPs on broadcast */
 1640:   if ((snp_type == ISIS_SNP_PSNP_FLAG) &&
 1641:       (circuit->circ_type == CIRCUIT_T_BROADCAST) &&
 1642:       (!circuit->u.bc.is_dr[level - 1]))
 1643:     {
 1644:       zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s, "
 1645:                   "skipping: we are not the DIS",
 1646:                   circuit->area->area_tag,
 1647:                   level,
 1648:                   typechar, snpa_print (ssnpa), circuit->interface->name);
 1649: 
 1650:       return ISIS_OK;
 1651:     }
 1652: 
 1653:   /* 7.3.15.2 a) 5 - need to make sure IDLength matches - already checked */
 1654: 
 1655:   /* 7.3.15.2 a) 6 - maximum area match, can be ommited since we only use 3
 1656:    * - already checked */
 1657: 
 1658:   /* 7.3.15.2 a) 7 - Must check that we have an adjacency of the same level  */
 1659:   /* for broadcast circuits, snpa should be compared */
 1660:   /* FIXME : Do we need to check SNPA? */
 1661:   if (circuit->circ_type == CIRCUIT_T_BROADCAST)
 1662:     {
 1663:       if (snp_type == ISIS_SNP_CSNP_FLAG)
 1664: 	{
 1665: 	  adj =
 1666: 	    isis_adj_lookup (chdr->source_id, circuit->u.bc.adjdb[level - 1]);
 1667: 	}
 1668:       else
 1669: 	{
 1670: 	  /* a psnp on a broadcast, how lovely of Juniper :) */
 1671: 	  adj =
 1672: 	    isis_adj_lookup (phdr->source_id, circuit->u.bc.adjdb[level - 1]);
 1673: 	}
 1674:       if (!adj)
 1675: 	return ISIS_OK;		/* Silently discard */
 1676:     }
 1677:   else
 1678:     {
 1679:       if (!circuit->u.p2p.neighbor)
 1680:       {
 1681:         zlog_warn ("no p2p neighbor on circuit %s", circuit->interface->name);
 1682:         return ISIS_OK;		/* Silently discard */
 1683:       }
 1684:     }
 1685: 
 1686:   /* 7.3.15.2 a) 8 - Passwords for level 1 - not implemented  */
 1687: 
 1688:   /* 7.3.15.2 a) 9 - Passwords for level 2 - not implemented  */
 1689: 
 1690:   memset (&tlvs, 0, sizeof (struct tlvs));
 1691: 
 1692:   /* parse the SNP */
 1693:   expected |= TLVFLAG_LSP_ENTRIES;
 1694:   expected |= TLVFLAG_AUTH_INFO;
 1695: 
 1696:   auth_tlv_offset = stream_get_getp (circuit->rcv_stream);
 1697:   retval = parse_tlvs (circuit->area->area_tag,
 1698: 		       STREAM_PNT (circuit->rcv_stream),
 1699: 		       pdu_len - stream_get_getp (circuit->rcv_stream),
 1700: 		       &expected, &found, &tlvs, &auth_tlv_offset);
 1701: 
 1702:   if (retval > ISIS_WARNING)
 1703:     {
 1704:       zlog_warn ("something went very wrong processing SNP");
 1705:       free_tlvs (&tlvs);
 1706:       return retval;
 1707:     }
 1708: 
 1709:   if (level == IS_LEVEL_1)
 1710:     passwd = &circuit->area->area_passwd;
 1711:   else
 1712:     passwd = &circuit->area->domain_passwd;
 1713: 
 1714:   if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_RECV))
 1715:     {
 1716:       if (passwd->type)
 1717:         {
 1718:           if (!(found & TLVFLAG_AUTH_INFO) ||
 1719:               authentication_check (&tlvs.auth_info, passwd,
 1720:                                     circuit->rcv_stream, auth_tlv_offset))
 1721:             {
 1722:               isis_event_auth_failure (circuit->area->area_tag,
 1723:                                        "SNP authentication" " failure",
 1724:                                        phdr ? phdr->source_id :
 1725:                                        chdr->source_id);
 1726:               free_tlvs (&tlvs);
 1727:               return ISIS_OK;
 1728:             }
 1729:         }
 1730:     }
 1731: 
 1732:   /* debug isis snp-packets */
 1733:   if (isis->debugs & DEBUG_SNP_PACKETS)
 1734:     {
 1735:       zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s",
 1736: 		  circuit->area->area_tag,
 1737: 		  level,
 1738: 		  typechar, snpa_print (ssnpa), circuit->interface->name);
 1739:       if (tlvs.lsp_entries)
 1740: 	{
 1741: 	  for (ALL_LIST_ELEMENTS_RO (tlvs.lsp_entries, node, entry))
 1742: 	  {
 1743: 	    zlog_debug ("ISIS-Snp (%s):         %cSNP entry %s, seq 0x%08x,"
 1744: 			" cksum 0x%04x, lifetime %us",
 1745: 			circuit->area->area_tag,
 1746: 			typechar,
 1747: 			rawlspid_print (entry->lsp_id),
 1748: 			ntohl (entry->seq_num),
 1749: 			ntohs (entry->checksum), ntohs (entry->rem_lifetime));
 1750: 	  }
 1751: 	}
 1752:     }
 1753: 
 1754:   /* 7.3.15.2 b) Actions on LSP_ENTRIES reported */
 1755:   if (tlvs.lsp_entries)
 1756:     {
 1757:       for (ALL_LIST_ELEMENTS_RO (tlvs.lsp_entries, node, entry))
 1758:       {
 1759: 	lsp = lsp_search (entry->lsp_id, circuit->area->lspdb[level - 1]);
 1760: 	own_lsp = !memcmp (entry->lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
 1761: 	if (lsp)
 1762: 	  {
 1763: 	    /* 7.3.15.2 b) 1) is this LSP newer */
 1764: 	    cmp = lsp_compare (circuit->area->area_tag, lsp, entry->seq_num,
 1765: 			       entry->checksum, entry->rem_lifetime);
 1766: 	    /* 7.3.15.2 b) 2) if it equals, clear SRM on p2p */
 1767: 	    if (cmp == LSP_EQUAL)
 1768: 	      {
 1769: 		/* if (circuit->circ_type != CIRCUIT_T_BROADCAST) */
 1770: 	        ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
 1771: 	      }
 1772: 	    /* 7.3.15.2 b) 3) if it is older, clear SSN and set SRM */
 1773: 	    else if (cmp == LSP_OLDER)
 1774: 	      {
 1775: 		ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
 1776: 		ISIS_SET_FLAG (lsp->SRMflags, circuit);
 1777: 	      }
 1778: 	    /* 7.3.15.2 b) 4) if it is newer, set SSN and clear SRM on p2p */
 1779: 	    else
 1780: 	      {
 1781: 		if (own_lsp)
 1782: 		  {
 1783: 		    lsp_inc_seqnum (lsp, ntohl (entry->seq_num));
 1784: 		    ISIS_SET_FLAG (lsp->SRMflags, circuit);
 1785: 		  }
 1786: 		else
 1787: 		  {
 1788: 		    ISIS_SET_FLAG (lsp->SSNflags, circuit);
 1789: 		    /* if (circuit->circ_type != CIRCUIT_T_BROADCAST) */
 1790: 		    ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
 1791: 		  }
 1792: 	      }
 1793: 	  }
 1794: 	else
 1795: 	  {
 1796: 	    /* 7.3.15.2 b) 5) if it was not found, and all of those are not 0, 
 1797: 	     * insert it and set SSN on it */
 1798: 	    if (entry->rem_lifetime && entry->checksum && entry->seq_num &&
 1799: 		memcmp (entry->lsp_id, isis->sysid, ISIS_SYS_ID_LEN))
 1800: 	      {
 1801: 		lsp = lsp_new (entry->lsp_id, ntohs (entry->rem_lifetime),
 1802: 			       0, 0, entry->checksum, level);
 1803: 		lsp->area = circuit->area;
 1804: 		lsp_insert (lsp, circuit->area->lspdb[level - 1]);
 1805: 		ISIS_FLAGS_CLEAR_ALL (lsp->SRMflags);
 1806: 		ISIS_SET_FLAG (lsp->SSNflags, circuit);
 1807: 	      }
 1808: 	  }
 1809:       }
 1810:     }
 1811: 
 1812:   /* 7.3.15.2 c) on CSNP set SRM for all in range which were not reported */
 1813:   if (snp_type == ISIS_SNP_CSNP_FLAG)
 1814:     {
 1815:       /*
 1816:        * Build a list from our own LSP db bounded with
 1817:        * start_lsp_id and stop_lsp_id
 1818:        */
 1819:       lsp_list = list_new ();
 1820:       lsp_build_list_nonzero_ht (chdr->start_lsp_id, chdr->stop_lsp_id,
 1821: 				 lsp_list, circuit->area->lspdb[level - 1]);
 1822: 
 1823:       /* Fixme: Find a better solution */
 1824:       if (tlvs.lsp_entries)
 1825: 	{
 1826: 	  for (ALL_LIST_ELEMENTS (tlvs.lsp_entries, node, nnode, entry))
 1827: 	  {
 1828: 	    for (ALL_LIST_ELEMENTS (lsp_list, node2, nnode2, lsp))
 1829: 	    {
 1830: 	      if (lsp_id_cmp (lsp->lsp_header->lsp_id, entry->lsp_id) == 0)
 1831: 		{
 1832: 		  list_delete_node (lsp_list, node2);
 1833: 		  break;
 1834: 		}
 1835: 	    }
 1836: 	  }
 1837: 	}
 1838:       /* on remaining LSPs we set SRM (neighbor knew not of) */
 1839:       for (ALL_LIST_ELEMENTS_RO (lsp_list, node, lsp))
 1840: 	ISIS_SET_FLAG (lsp->SRMflags, circuit);
 1841:       /* lets free it */
 1842:       list_delete (lsp_list);
 1843: 
 1844:     }
 1845: 
 1846:   free_tlvs (&tlvs);
 1847:   return retval;
 1848: }
 1849: 
 1850: static int
 1851: process_csnp (int level, struct isis_circuit *circuit, u_char * ssnpa)
 1852: {
 1853:   if (isis->debugs & DEBUG_SNP_PACKETS)
 1854:     {
 1855:       zlog_debug ("ISIS-Snp (%s): Rcvd L%d CSNP on %s, cirType %s, cirID %u",
 1856:                   circuit->area->area_tag, level, circuit->interface->name,
 1857:                   circuit_t2string (circuit->is_type), circuit->circuit_id);
 1858:       if (isis->debugs & DEBUG_PACKET_DUMP)
 1859:         zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
 1860:                         stream_get_endp (circuit->rcv_stream));
 1861:     }
 1862: 
 1863:   /* Sanity check - FIXME: move to correct place */
 1864:   if ((stream_get_endp (circuit->rcv_stream) -
 1865:        stream_get_getp (circuit->rcv_stream)) < ISIS_CSNP_HDRLEN)
 1866:     {
 1867:       zlog_warn ("Packet too short ( < %d)", ISIS_CSNP_HDRLEN);
 1868:       return ISIS_WARNING;
 1869:     }
 1870: 
 1871:   return process_snp (ISIS_SNP_CSNP_FLAG, level, circuit, ssnpa);
 1872: }
 1873: 
 1874: static int
 1875: process_psnp (int level, struct isis_circuit *circuit, u_char * ssnpa)
 1876: {
 1877:   if (isis->debugs & DEBUG_SNP_PACKETS)
 1878:     {
 1879:       zlog_debug ("ISIS-Snp (%s): Rcvd L%d PSNP on %s, cirType %s, cirID %u",
 1880:                   circuit->area->area_tag, level, circuit->interface->name,
 1881:                   circuit_t2string (circuit->is_type), circuit->circuit_id);
 1882:       if (isis->debugs & DEBUG_PACKET_DUMP)
 1883:         zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
 1884:                         stream_get_endp (circuit->rcv_stream));
 1885:     }
 1886: 
 1887:   if ((stream_get_endp (circuit->rcv_stream) -
 1888:        stream_get_getp (circuit->rcv_stream)) < ISIS_PSNP_HDRLEN)
 1889:     {
 1890:       zlog_warn ("Packet too short ( < %d)", ISIS_PSNP_HDRLEN);
 1891:       return ISIS_WARNING;
 1892:     }
 1893: 
 1894:   return process_snp (ISIS_SNP_PSNP_FLAG, level, circuit, ssnpa);
 1895: }
 1896: 
 1897: /*
 1898:  * Process ISH
 1899:  * ISO - 10589
 1900:  * Section 8.2.2 - Receiving ISH PDUs by an intermediate system
 1901:  * FIXME: sample packet dump, need to figure 0x81 - looks like NLPid
 1902:  *           0x82	0x15	0x01	0x00	0x04	0x01	0x2c	0x59
 1903:  *           0x38	0x08	0x47	0x00	0x01	0x00	0x02	0x00
 1904:  *           0x03	0x00	0x81	0x01	0xcc
 1905:  */
 1906: static int
 1907: process_is_hello (struct isis_circuit *circuit)
 1908: {
 1909:   struct isis_adjacency *adj;
 1910:   int retval = ISIS_OK;
 1911:   u_char neigh_len;
 1912:   u_char *sysid;
 1913: 
 1914:   if (isis->debugs & DEBUG_ADJ_PACKETS)
 1915:     {
 1916:       zlog_debug ("ISIS-Adj (%s): Rcvd ISH on %s, cirType %s, cirID %u",
 1917:                   circuit->area->area_tag, circuit->interface->name,
 1918:                   circuit_t2string (circuit->is_type), circuit->circuit_id);
 1919:       if (isis->debugs & DEBUG_PACKET_DUMP)
 1920:         zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
 1921:                         stream_get_endp (circuit->rcv_stream));
 1922:     }
 1923: 
 1924:   /* In this point in time we are not yet able to handle is_hellos
 1925:    * on lan - Sorry juniper...
 1926:    */
 1927:   if (circuit->circ_type == CIRCUIT_T_BROADCAST)
 1928:     return retval;
 1929: 
 1930:   neigh_len = stream_getc (circuit->rcv_stream);
 1931:   sysid = STREAM_PNT (circuit->rcv_stream) + neigh_len - 1 - ISIS_SYS_ID_LEN;
 1932:   adj = circuit->u.p2p.neighbor;
 1933:   if (!adj)
 1934:     {
 1935:       /* 8.2.2 */
 1936:       adj = isis_new_adj (sysid, NULL, 0, circuit);
 1937:       if (adj == NULL)
 1938: 	return ISIS_ERROR;
 1939: 
 1940:       isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL);
 1941:       adj->sys_type = ISIS_SYSTYPE_UNKNOWN;
 1942:       circuit->u.p2p.neighbor = adj;
 1943:     }
 1944:   /* 8.2.2 a) */
 1945:   if ((adj->adj_state == ISIS_ADJ_UP) && memcmp (adj->sysid, sysid,
 1946: 						 ISIS_SYS_ID_LEN))
 1947:     {
 1948:       /* 8.2.2 a) 1) FIXME: adjStateChange(down) event */
 1949:       /* 8.2.2 a) 2) delete the adj */
 1950:       XFREE (MTYPE_ISIS_ADJACENCY, adj);
 1951:       /* 8.2.2 a) 3) create a new adj */
 1952:       adj = isis_new_adj (sysid, NULL, 0, circuit);
 1953:       if (adj == NULL)
 1954: 	return ISIS_ERROR;
 1955: 
 1956:       /* 8.2.2 a) 3) i */
 1957:       isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL);
 1958:       /* 8.2.2 a) 3) ii */
 1959:       adj->sys_type = ISIS_SYSTYPE_UNKNOWN;
 1960:       /* 8.2.2 a) 4) quite meaningless */
 1961:     }
 1962:   /* 8.2.2 b) ignore on condition */
 1963:   if ((adj->adj_state == ISIS_ADJ_INITIALIZING) &&
 1964:       (adj->sys_type == ISIS_SYSTYPE_IS))
 1965:     {
 1966:       /* do nothing */
 1967:     }
 1968:   else
 1969:     {
 1970:       /* 8.2.2 c) respond with a p2p IIH */
 1971:       send_hello (circuit, 1);
 1972:     }
 1973:   /* 8.2.2 d) type is IS */
 1974:   adj->sys_type = ISIS_SYSTYPE_IS;
 1975:   /* 8.2.2 e) FIXME: Circuit type of? */
 1976: 
 1977:   return retval;
 1978: }
 1979: 
 1980: /*
 1981:  * PDU Dispatcher
 1982:  */
 1983: 
 1984: static int
 1985: isis_handle_pdu (struct isis_circuit *circuit, u_char * ssnpa)
 1986: {
 1987:   struct isis_fixed_hdr *hdr;
 1988: 
 1989:   int retval = ISIS_OK;
 1990: 
 1991:   /*
 1992:    * Let's first read data from stream to the header
 1993:    */
 1994:   hdr = (struct isis_fixed_hdr *) STREAM_DATA (circuit->rcv_stream);
 1995: 
 1996:   if ((hdr->idrp != ISO10589_ISIS) && (hdr->idrp != ISO9542_ESIS))
 1997:     {
 1998:       zlog_err ("Not an IS-IS or ES-IS packet IDRP=%02x", hdr->idrp);
 1999:       return ISIS_ERROR;
 2000:     }
 2001: 
 2002:   /* now we need to know if this is an ISO 9542 packet and
 2003:    * take real good care of it, waaa!
 2004:    */
 2005:   if (hdr->idrp == ISO9542_ESIS)
 2006:     {
 2007:       zlog_err ("No support for ES-IS packet IDRP=%02x", hdr->idrp);
 2008:       return ISIS_ERROR;
 2009:     }
 2010:   stream_set_getp (circuit->rcv_stream, ISIS_FIXED_HDR_LEN);
 2011: 
 2012:   /*
 2013:    * and then process it
 2014:    */
 2015: 
 2016:   if (hdr->length < ISIS_MINIMUM_FIXED_HDR_LEN)
 2017:     {
 2018:       zlog_err ("Fixed header length = %d", hdr->length);
 2019:       return ISIS_ERROR;
 2020:     }
 2021: 
 2022:   if (hdr->version1 != 1)
 2023:     {
 2024:       zlog_warn ("Unsupported ISIS version %u", hdr->version1);
 2025:       return ISIS_WARNING;
 2026:     }
 2027:   /* either 6 or 0 */
 2028:   if ((hdr->id_len != 0) && (hdr->id_len != ISIS_SYS_ID_LEN))
 2029:     {
 2030:       zlog_err
 2031: 	("IDFieldLengthMismatch: ID Length field in a received PDU  %u, "
 2032: 	 "while the parameter for this IS is %u", hdr->id_len,
 2033: 	 ISIS_SYS_ID_LEN);
 2034:       return ISIS_ERROR;
 2035:     }
 2036: 
 2037:   if (hdr->version2 != 1)
 2038:     {
 2039:       zlog_warn ("Unsupported ISIS version %u", hdr->version2);
 2040:       return ISIS_WARNING;
 2041:     }
 2042: 
 2043:   if (circuit->is_passive)
 2044:     {
 2045:       zlog_warn ("Received ISIS PDU on passive circuit %s",
 2046: 		 circuit->interface->name);
 2047:       return ISIS_WARNING;
 2048:     }
 2049: 
 2050:   /* either 3 or 0 */
 2051:   if ((hdr->max_area_addrs != 0)
 2052:       && (hdr->max_area_addrs != isis->max_area_addrs))
 2053:     {
 2054:       zlog_err ("maximumAreaAddressesMismatch: maximumAreaAdresses in a "
 2055: 		"received PDU %u while the parameter for this IS is %u",
 2056: 		hdr->max_area_addrs, isis->max_area_addrs);
 2057:       return ISIS_ERROR;
 2058:     }
 2059: 
 2060:   switch (hdr->pdu_type)
 2061:     {
 2062:     case L1_LAN_HELLO:
 2063:       retval = process_lan_hello (ISIS_LEVEL1, circuit, ssnpa);
 2064:       break;
 2065:     case L2_LAN_HELLO:
 2066:       retval = process_lan_hello (ISIS_LEVEL2, circuit, ssnpa);
 2067:       break;
 2068:     case P2P_HELLO:
 2069:       retval = process_p2p_hello (circuit);
 2070:       break;
 2071:     case L1_LINK_STATE:
 2072:       retval = process_lsp (ISIS_LEVEL1, circuit, ssnpa);
 2073:       break;
 2074:     case L2_LINK_STATE:
 2075:       retval = process_lsp (ISIS_LEVEL2, circuit, ssnpa);
 2076:       break;
 2077:     case L1_COMPLETE_SEQ_NUM:
 2078:       retval = process_csnp (ISIS_LEVEL1, circuit, ssnpa);
 2079:       break;
 2080:     case L2_COMPLETE_SEQ_NUM:
 2081:       retval = process_csnp (ISIS_LEVEL2, circuit, ssnpa);
 2082:       break;
 2083:     case L1_PARTIAL_SEQ_NUM:
 2084:       retval = process_psnp (ISIS_LEVEL1, circuit, ssnpa);
 2085:       break;
 2086:     case L2_PARTIAL_SEQ_NUM:
 2087:       retval = process_psnp (ISIS_LEVEL2, circuit, ssnpa);
 2088:       break;
 2089:     default:
 2090:       return ISIS_ERROR;
 2091:     }
 2092: 
 2093:   return retval;
 2094: }
 2095: 
 2096: #ifdef GNU_LINUX
 2097: int
 2098: isis_receive (struct thread *thread)
 2099: {
 2100:   struct isis_circuit *circuit;
 2101:   u_char ssnpa[ETH_ALEN];
 2102:   int retval;
 2103: 
 2104:   /*
 2105:    * Get the circuit 
 2106:    */
 2107:   circuit = THREAD_ARG (thread);
 2108:   assert (circuit);
 2109: 
 2110:   if (circuit->rcv_stream == NULL)
 2111:     circuit->rcv_stream = stream_new (ISO_MTU (circuit));
 2112:   else
 2113:     stream_reset (circuit->rcv_stream);
 2114: 
 2115:   retval = circuit->rx (circuit, ssnpa);
 2116:   circuit->t_read = NULL;
 2117: 
 2118:   if (retval == ISIS_OK)
 2119:     retval = isis_handle_pdu (circuit, ssnpa);
 2120: 
 2121:   /* 
 2122:    * prepare for next packet. 
 2123:    */
 2124:   if (!circuit->is_passive)
 2125:   {
 2126:     THREAD_READ_ON (master, circuit->t_read, isis_receive, circuit,
 2127:                     circuit->fd);
 2128:   }
 2129: 
 2130:   return retval;
 2131: }
 2132: 
 2133: #else
 2134: int
 2135: isis_receive (struct thread *thread)
 2136: {
 2137:   struct isis_circuit *circuit;
 2138:   u_char ssnpa[ETH_ALEN];
 2139:   int retval;
 2140: 
 2141:   /*
 2142:    * Get the circuit 
 2143:    */
 2144:   circuit = THREAD_ARG (thread);
 2145:   assert (circuit);
 2146: 
 2147:   circuit->t_read = NULL;
 2148: 
 2149:   if (circuit->rcv_stream == NULL)
 2150:     circuit->rcv_stream = stream_new (ISO_MTU (circuit));
 2151:   else
 2152:     stream_reset (circuit->rcv_stream);
 2153: 
 2154:   retval = circuit->rx (circuit, ssnpa);
 2155: 
 2156:   if (retval == ISIS_OK)
 2157:     retval = isis_handle_pdu (circuit, ssnpa);
 2158: 
 2159:   /* 
 2160:    * prepare for next packet. 
 2161:    */
 2162:   if (!circuit->is_passive)
 2163:   {
 2164:     circuit->t_read = thread_add_timer_msec (master, isis_receive, circuit,
 2165:   					     listcount
 2166: 					     (circuit->area->circuit_list) *
 2167: 					     100);
 2168:   }
 2169: 
 2170:   return retval;
 2171: }
 2172: 
 2173: #endif
 2174: 
 2175:  /* filling of the fixed isis header */
 2176: void
 2177: fill_fixed_hdr (struct isis_fixed_hdr *hdr, u_char pdu_type)
 2178: {
 2179:   memset (hdr, 0, sizeof (struct isis_fixed_hdr));
 2180: 
 2181:   hdr->idrp = ISO10589_ISIS;
 2182: 
 2183:   switch (pdu_type)
 2184:     {
 2185:     case L1_LAN_HELLO:
 2186:     case L2_LAN_HELLO:
 2187:       hdr->length = ISIS_LANHELLO_HDRLEN;
 2188:       break;
 2189:     case P2P_HELLO:
 2190:       hdr->length = ISIS_P2PHELLO_HDRLEN;
 2191:       break;
 2192:     case L1_LINK_STATE:
 2193:     case L2_LINK_STATE:
 2194:       hdr->length = ISIS_LSP_HDR_LEN;
 2195:       break;
 2196:     case L1_COMPLETE_SEQ_NUM:
 2197:     case L2_COMPLETE_SEQ_NUM:
 2198:       hdr->length = ISIS_CSNP_HDRLEN;
 2199:       break;
 2200:     case L1_PARTIAL_SEQ_NUM:
 2201:     case L2_PARTIAL_SEQ_NUM:
 2202:       hdr->length = ISIS_PSNP_HDRLEN;
 2203:       break;
 2204:     default:
 2205:       zlog_warn ("fill_fixed_hdr(): unknown pdu type %d", pdu_type);
 2206:       return;
 2207:     }
 2208:   hdr->length += ISIS_FIXED_HDR_LEN;
 2209:   hdr->pdu_type = pdu_type;
 2210:   hdr->version1 = 1;
 2211:   hdr->id_len = 0;		/* ISIS_SYS_ID_LEN -  0==6 */
 2212:   hdr->version2 = 1;
 2213:   hdr->max_area_addrs = 0;	/* isis->max_area_addrs -  0==3 */
 2214: }
 2215: 
 2216: /*
 2217:  * SEND SIDE                             
 2218:  */
 2219: static void
 2220: fill_fixed_hdr_andstream (struct isis_fixed_hdr *hdr, u_char pdu_type,
 2221: 			  struct stream *stream)
 2222: {
 2223:   fill_fixed_hdr (hdr, pdu_type);
 2224: 
 2225:   stream_putc (stream, hdr->idrp);
 2226:   stream_putc (stream, hdr->length);
 2227:   stream_putc (stream, hdr->version1);
 2228:   stream_putc (stream, hdr->id_len);
 2229:   stream_putc (stream, hdr->pdu_type);
 2230:   stream_putc (stream, hdr->version2);
 2231:   stream_putc (stream, hdr->reserved);
 2232:   stream_putc (stream, hdr->max_area_addrs);
 2233: 
 2234:   return;
 2235: }
 2236: 
 2237: int
 2238: send_hello (struct isis_circuit *circuit, int level)
 2239: {
 2240:   struct isis_fixed_hdr fixed_hdr;
 2241:   struct isis_lan_hello_hdr hello_hdr;
 2242:   struct isis_p2p_hello_hdr p2p_hello_hdr;
 2243:   unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
 2244:   unsigned long len_pointer, length, auth_tlv_offset = 0;
 2245:   u_int32_t interval;
 2246:   int retval;
 2247: 
 2248:   if (circuit->is_passive)
 2249:     return ISIS_OK;
 2250: 
 2251:   if (circuit->interface->mtu == 0)
 2252:     {
 2253:       zlog_warn ("circuit has zero MTU");
 2254:       return ISIS_WARNING;
 2255:     }
 2256: 
 2257:   if (!circuit->snd_stream)
 2258:     circuit->snd_stream = stream_new (ISO_MTU (circuit));
 2259:   else
 2260:     stream_reset (circuit->snd_stream);
 2261: 
 2262:   if (circuit->circ_type == CIRCUIT_T_BROADCAST)
 2263:     if (level == IS_LEVEL_1)
 2264:       fill_fixed_hdr_andstream (&fixed_hdr, L1_LAN_HELLO,
 2265: 				circuit->snd_stream);
 2266:     else
 2267:       fill_fixed_hdr_andstream (&fixed_hdr, L2_LAN_HELLO,
 2268: 				circuit->snd_stream);
 2269:   else
 2270:     fill_fixed_hdr_andstream (&fixed_hdr, P2P_HELLO, circuit->snd_stream);
 2271: 
 2272:   /*
 2273:    * Fill LAN Level 1 or 2 Hello PDU header
 2274:    */
 2275:   memset (&hello_hdr, 0, sizeof (struct isis_lan_hello_hdr));
 2276:   interval = circuit->hello_multiplier[level - 1] *
 2277:     circuit->hello_interval[level - 1];
 2278:   if (interval > USHRT_MAX)
 2279:     interval = USHRT_MAX;
 2280:   hello_hdr.circuit_t = circuit->is_type;
 2281:   memcpy (hello_hdr.source_id, isis->sysid, ISIS_SYS_ID_LEN);
 2282:   hello_hdr.hold_time = htons ((u_int16_t) interval);
 2283: 
 2284:   hello_hdr.pdu_len = 0;	/* Update the PDU Length later */
 2285:   len_pointer = stream_get_endp (circuit->snd_stream) + 3 + ISIS_SYS_ID_LEN;
 2286: 
 2287:   /* copy the shared part of the hello to the p2p hello if needed */
 2288:   if (circuit->circ_type == CIRCUIT_T_P2P)
 2289:     {
 2290:       memcpy (&p2p_hello_hdr, &hello_hdr, 5 + ISIS_SYS_ID_LEN);
 2291:       p2p_hello_hdr.local_id = circuit->circuit_id;
 2292:       /* FIXME: need better understanding */
 2293:       stream_put (circuit->snd_stream, &p2p_hello_hdr, ISIS_P2PHELLO_HDRLEN);
 2294:     }
 2295:   else
 2296:     {
 2297:       hello_hdr.prio = circuit->priority[level - 1];
 2298:       if (level == IS_LEVEL_1)
 2299: 	{
 2300: 	  memcpy (hello_hdr.lan_id, circuit->u.bc.l1_desig_is,
 2301: 		  ISIS_SYS_ID_LEN + 1);
 2302: 	}
 2303:       else if (level == IS_LEVEL_2)
 2304: 	{
 2305: 	  memcpy (hello_hdr.lan_id, circuit->u.bc.l2_desig_is,
 2306: 		  ISIS_SYS_ID_LEN + 1);
 2307: 	}
 2308:       stream_put (circuit->snd_stream, &hello_hdr, ISIS_LANHELLO_HDRLEN);
 2309:     }
 2310: 
 2311:   /*
 2312:    * Then the variable length part.
 2313:    */
 2314: 
 2315:   /* add circuit password */
 2316:   switch (circuit->passwd.type)
 2317:   {
 2318:     /* Cleartext */
 2319:     case ISIS_PASSWD_TYPE_CLEARTXT:
 2320:       if (tlv_add_authinfo (circuit->passwd.type, circuit->passwd.len,
 2321:                             circuit->passwd.passwd, circuit->snd_stream))
 2322:         return ISIS_WARNING;
 2323:       break;
 2324: 
 2325:     /* HMAC MD5 */
 2326:     case ISIS_PASSWD_TYPE_HMAC_MD5:
 2327:       /* Remember where TLV is written so we can later overwrite the MD5 hash */
 2328:       auth_tlv_offset = stream_get_endp (circuit->snd_stream);
 2329:       memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
 2330:       if (tlv_add_authinfo (circuit->passwd.type, ISIS_AUTH_MD5_SIZE,
 2331:                             hmac_md5_hash, circuit->snd_stream))
 2332:         return ISIS_WARNING;
 2333:       break;
 2334: 
 2335:     default:
 2336:       break;
 2337:   }
 2338: 
 2339:   /*  Area Addresses TLV */
 2340:   if (listcount (circuit->area->area_addrs) == 0)
 2341:     return ISIS_WARNING;
 2342:   if (tlv_add_area_addrs (circuit->area->area_addrs, circuit->snd_stream))
 2343:     return ISIS_WARNING;
 2344: 
 2345:   /*  LAN Neighbors TLV */
 2346:   if (circuit->circ_type == CIRCUIT_T_BROADCAST)
 2347:     {
 2348:       if (level == IS_LEVEL_1 && circuit->u.bc.lan_neighs[0] &&
 2349:           listcount (circuit->u.bc.lan_neighs[0]) > 0)
 2350: 	if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[0],
 2351: 				circuit->snd_stream))
 2352: 	  return ISIS_WARNING;
 2353:       if (level == IS_LEVEL_2 && circuit->u.bc.lan_neighs[1] &&
 2354:           listcount (circuit->u.bc.lan_neighs[1]) > 0)
 2355: 	if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[1],
 2356: 				circuit->snd_stream))
 2357: 	  return ISIS_WARNING;
 2358:     }
 2359: 
 2360:   /* Protocols Supported TLV */
 2361:   if (circuit->nlpids.count > 0)
 2362:     if (tlv_add_nlpid (&circuit->nlpids, circuit->snd_stream))
 2363:       return ISIS_WARNING;
 2364:   /* IP interface Address TLV */
 2365:   if (circuit->ip_router && circuit->ip_addrs &&
 2366:       listcount (circuit->ip_addrs) > 0)
 2367:     if (tlv_add_ip_addrs (circuit->ip_addrs, circuit->snd_stream))
 2368:       return ISIS_WARNING;
 2369: 
 2370: #ifdef HAVE_IPV6
 2371:   /* IPv6 Interface Address TLV */
 2372:   if (circuit->ipv6_router && circuit->ipv6_link &&
 2373:       listcount (circuit->ipv6_link) > 0)
 2374:     if (tlv_add_ipv6_addrs (circuit->ipv6_link, circuit->snd_stream))
 2375:       return ISIS_WARNING;
 2376: #endif /* HAVE_IPV6 */
 2377: 
 2378:   if (circuit->pad_hellos)
 2379:     if (tlv_add_padding (circuit->snd_stream))
 2380:       return ISIS_WARNING;
 2381: 
 2382:   length = stream_get_endp (circuit->snd_stream);
 2383:   /* Update PDU length */
 2384:   stream_putw_at (circuit->snd_stream, len_pointer, (u_int16_t) length);
 2385: 
 2386:   /* For HMAC MD5 we need to compute the md5 hash and store it */
 2387:   if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5)
 2388:     {
 2389:       hmac_md5 (STREAM_DATA (circuit->snd_stream),
 2390:                 stream_get_endp (circuit->snd_stream),
 2391:                 (unsigned char *) &circuit->passwd.passwd, circuit->passwd.len,
 2392:                 (caddr_t) &hmac_md5_hash);
 2393:       /* Copy the hash into the stream */
 2394:       memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3,
 2395:               hmac_md5_hash, ISIS_AUTH_MD5_SIZE);
 2396:     }
 2397: 
 2398:   if (isis->debugs & DEBUG_ADJ_PACKETS)
 2399:     {
 2400:       if (circuit->circ_type == CIRCUIT_T_BROADCAST)
 2401: 	{
 2402: 	  zlog_debug ("ISIS-Adj (%s): Sent L%d LAN IIH on %s, length %ld",
 2403: 		      circuit->area->area_tag, level, circuit->interface->name,
 2404: 		      /* FIXME: use %z when we stop supporting old compilers. */
 2405: 		      length);
 2406: 	}
 2407:       else
 2408: 	{
 2409: 	  zlog_debug ("ISIS-Adj (%s): Sent P2P IIH on %s, length %ld",
 2410: 		      circuit->area->area_tag, circuit->interface->name,
 2411: 		      /* FIXME: use %z when we stop supporting old compilers. */
 2412: 		      length);
 2413: 	}
 2414:       if (isis->debugs & DEBUG_PACKET_DUMP)
 2415:         zlog_dump_data (STREAM_DATA (circuit->snd_stream),
 2416:                         stream_get_endp (circuit->snd_stream));
 2417:     }
 2418: 
 2419:   retval = circuit->tx (circuit, level);
 2420:   if (retval != ISIS_OK)
 2421:     zlog_err ("ISIS-Adj (%s): Send L%d IIH on %s failed",
 2422:               circuit->area->area_tag, level, circuit->interface->name);
 2423: 
 2424:   return retval;
 2425: }
 2426: 
 2427: int
 2428: send_lan_l1_hello (struct thread *thread)
 2429: {
 2430:   struct isis_circuit *circuit;
 2431:   int retval;
 2432: 
 2433:   circuit = THREAD_ARG (thread);
 2434:   assert (circuit);
 2435:   circuit->u.bc.t_send_lan_hello[0] = NULL;
 2436: 
 2437:   if (circuit->u.bc.run_dr_elect[0])
 2438:     retval = isis_dr_elect (circuit, 1);
 2439: 
 2440:   retval = send_hello (circuit, 1);
 2441: 
 2442:   /* set next timer thread */
 2443:   THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[0],
 2444: 		   send_lan_l1_hello, circuit,
 2445: 		   isis_jitter (circuit->hello_interval[0], IIH_JITTER));
 2446: 
 2447:   return retval;
 2448: }
 2449: 
 2450: int
 2451: send_lan_l2_hello (struct thread *thread)
 2452: {
 2453:   struct isis_circuit *circuit;
 2454:   int retval;
 2455: 
 2456:   circuit = THREAD_ARG (thread);
 2457:   assert (circuit);
 2458:   circuit->u.bc.t_send_lan_hello[1] = NULL;
 2459: 
 2460:   if (circuit->u.bc.run_dr_elect[1])
 2461:     retval = isis_dr_elect (circuit, 2);
 2462: 
 2463:   retval = send_hello (circuit, 2);
 2464: 
 2465:   /* set next timer thread */
 2466:   THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[1],
 2467: 		   send_lan_l2_hello, circuit,
 2468: 		   isis_jitter (circuit->hello_interval[1], IIH_JITTER));
 2469: 
 2470:   return retval;
 2471: }
 2472: 
 2473: int
 2474: send_p2p_hello (struct thread *thread)
 2475: {
 2476:   struct isis_circuit *circuit;
 2477: 
 2478:   circuit = THREAD_ARG (thread);
 2479:   assert (circuit);
 2480:   circuit->u.p2p.t_send_p2p_hello = NULL;
 2481: 
 2482:   send_hello (circuit, 1);
 2483: 
 2484:   /* set next timer thread */
 2485:   THREAD_TIMER_ON (master, circuit->u.p2p.t_send_p2p_hello, send_p2p_hello,
 2486: 		   circuit, isis_jitter (circuit->hello_interval[1],
 2487: 					 IIH_JITTER));
 2488: 
 2489:   return ISIS_OK;
 2490: }
 2491: 
 2492: static int
 2493: build_csnp (int level, u_char * start, u_char * stop, struct list *lsps,
 2494: 	    struct isis_circuit *circuit)
 2495: {
 2496:   struct isis_fixed_hdr fixed_hdr;
 2497:   struct isis_passwd *passwd;
 2498:   unsigned long lenp;
 2499:   u_int16_t length;
 2500:   unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
 2501:   unsigned long auth_tlv_offset = 0;
 2502:   int retval = ISIS_OK;
 2503: 
 2504:   if (circuit->snd_stream == NULL)
 2505:     circuit->snd_stream = stream_new (ISO_MTU (circuit));
 2506:   else
 2507:     stream_reset (circuit->snd_stream);
 2508: 
 2509:   if (level == IS_LEVEL_1)
 2510:     fill_fixed_hdr_andstream (&fixed_hdr, L1_COMPLETE_SEQ_NUM,
 2511: 			      circuit->snd_stream);
 2512:   else
 2513:     fill_fixed_hdr_andstream (&fixed_hdr, L2_COMPLETE_SEQ_NUM,
 2514: 			      circuit->snd_stream);
 2515: 
 2516:   /*
 2517:    * Fill Level 1 or 2 Complete Sequence Numbers header
 2518:    */
 2519: 
 2520:   lenp = stream_get_endp (circuit->snd_stream);
 2521:   stream_putw (circuit->snd_stream, 0);	/* PDU length - when we know it */
 2522:   /* no need to send the source here, it is always us if we csnp */
 2523:   stream_put (circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN);
 2524:   /* with zero circuit id - ref 9.10, 9.11 */
 2525:   stream_putc (circuit->snd_stream, 0x00);
 2526: 
 2527:   stream_put (circuit->snd_stream, start, ISIS_SYS_ID_LEN + 2);
 2528:   stream_put (circuit->snd_stream, stop, ISIS_SYS_ID_LEN + 2);
 2529: 
 2530:   /*
 2531:    * And TLVs
 2532:    */
 2533:   if (level == IS_LEVEL_1)
 2534:     passwd = &circuit->area->area_passwd;
 2535:   else
 2536:     passwd = &circuit->area->domain_passwd;
 2537: 
 2538:   if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND))
 2539:   {
 2540:     switch (passwd->type)
 2541:     {
 2542:       /* Cleartext */
 2543:       case ISIS_PASSWD_TYPE_CLEARTXT:
 2544:         if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT, passwd->len,
 2545:                               passwd->passwd, circuit->snd_stream))
 2546:           return ISIS_WARNING;
 2547:         break;
 2548: 
 2549:         /* HMAC MD5 */
 2550:       case ISIS_PASSWD_TYPE_HMAC_MD5:
 2551:         /* Remember where TLV is written so we can later overwrite the MD5 hash */
 2552:         auth_tlv_offset = stream_get_endp (circuit->snd_stream);
 2553:         memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
 2554:         if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5, ISIS_AUTH_MD5_SIZE,
 2555:                               hmac_md5_hash, circuit->snd_stream))
 2556:           return ISIS_WARNING;
 2557:         break;
 2558: 
 2559:       default:
 2560:         break;
 2561:     }
 2562:   }
 2563: 
 2564:   retval = tlv_add_lsp_entries (lsps, circuit->snd_stream);
 2565:   if (retval != ISIS_OK)
 2566:     return retval;
 2567: 
 2568:   length = (u_int16_t) stream_get_endp (circuit->snd_stream);
 2569:   /* Update PU length */
 2570:   stream_putw_at (circuit->snd_stream, lenp, length);
 2571: 
 2572:   /* For HMAC MD5 we need to compute the md5 hash and store it */
 2573:   if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND) &&
 2574:       passwd->type == ISIS_PASSWD_TYPE_HMAC_MD5)
 2575:     {
 2576:       hmac_md5 (STREAM_DATA (circuit->snd_stream),
 2577:                 stream_get_endp(circuit->snd_stream),
 2578:                 (unsigned char *) &passwd->passwd, passwd->len,
 2579:                 (caddr_t) &hmac_md5_hash);
 2580:       /* Copy the hash into the stream */
 2581:       memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3,
 2582:               hmac_md5_hash, ISIS_AUTH_MD5_SIZE);
 2583:     }
 2584: 
 2585:   return retval;
 2586: }
 2587: 
 2588: /*
 2589:  * Count the maximum number of lsps that can be accomodated by a given size.
 2590:  */
 2591: static uint16_t
 2592: get_max_lsp_count (uint16_t size)
 2593: {
 2594:   uint16_t tlv_count;
 2595:   uint16_t lsp_count;
 2596:   uint16_t remaining_size;
 2597: 
 2598:   /* First count the full size TLVs */
 2599:   tlv_count = size / MAX_LSP_ENTRIES_TLV_SIZE;
 2600:   lsp_count = tlv_count * (MAX_LSP_ENTRIES_TLV_SIZE / LSP_ENTRIES_LEN);
 2601: 
 2602:   /* The last TLV, if any */
 2603:   remaining_size = size % MAX_LSP_ENTRIES_TLV_SIZE;
 2604:   if (remaining_size - 2 >= LSP_ENTRIES_LEN)
 2605:     lsp_count += (remaining_size - 2) / LSP_ENTRIES_LEN;
 2606: 
 2607:   return lsp_count;
 2608: }
 2609: 
 2610: /*
 2611:  * Calculate the length of Authentication Info. TLV.
 2612:  */
 2613: static uint16_t
 2614: auth_tlv_length (int level, struct isis_circuit *circuit)
 2615: {
 2616:   struct isis_passwd *passwd;
 2617:   uint16_t length;
 2618: 
 2619:   if (level == IS_LEVEL_1)
 2620:     passwd = &circuit->area->area_passwd;
 2621:   else
 2622:     passwd = &circuit->area->domain_passwd;
 2623: 
 2624:   /* Also include the length of TLV header */
 2625:   length = AUTH_INFO_HDRLEN;
 2626:   if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND))
 2627:   {
 2628:     switch (passwd->type)
 2629:     {
 2630:       /* Cleartext */
 2631:       case ISIS_PASSWD_TYPE_CLEARTXT:
 2632:         length += passwd->len;
 2633:         break;
 2634: 
 2635:         /* HMAC MD5 */
 2636:       case ISIS_PASSWD_TYPE_HMAC_MD5:
 2637:         length += ISIS_AUTH_MD5_SIZE;
 2638:         break;
 2639: 
 2640:       default:
 2641:         break;
 2642:     }
 2643:   }
 2644: 
 2645:   return length;
 2646: }
 2647: 
 2648: /*
 2649:  * Calculate the maximum number of lsps that can be accomodated in a CSNP/PSNP.
 2650:  */
 2651: static uint16_t
 2652: max_lsps_per_snp (int snp_type, int level, struct isis_circuit *circuit)
 2653: {
 2654:   int snp_hdr_len;
 2655:   int auth_tlv_len;
 2656:   uint16_t lsp_count;
 2657: 
 2658:   snp_hdr_len = ISIS_FIXED_HDR_LEN;
 2659:   if (snp_type == ISIS_SNP_CSNP_FLAG)
 2660:     snp_hdr_len += ISIS_CSNP_HDRLEN;
 2661:   else
 2662:     snp_hdr_len += ISIS_PSNP_HDRLEN;
 2663: 
 2664:   auth_tlv_len = auth_tlv_length (level, circuit);
 2665:   lsp_count = get_max_lsp_count (
 2666:       stream_get_size (circuit->snd_stream) - snp_hdr_len - auth_tlv_len);
 2667:   return lsp_count;
 2668: }
 2669: 
 2670: /*
 2671:  * FIXME: support multiple CSNPs
 2672:  */
 2673: 
 2674: int
 2675: send_csnp (struct isis_circuit *circuit, int level)
 2676: {
 2677:   u_char start[ISIS_SYS_ID_LEN + 2];
 2678:   u_char stop[ISIS_SYS_ID_LEN + 2];
 2679:   struct list *list = NULL;
 2680:   struct listnode *node;
 2681:   struct isis_lsp *lsp;
 2682:   u_char num_lsps, loop = 1;
 2683:   int i, retval = ISIS_OK;
 2684: 
 2685:   if (circuit->area->lspdb[level - 1] == NULL ||
 2686:       dict_count (circuit->area->lspdb[level - 1]) == 0)
 2687:     return retval;
 2688: 
 2689:   memset (start, 0x00, ISIS_SYS_ID_LEN + 2);
 2690:   memset (stop, 0xff, ISIS_SYS_ID_LEN + 2);
 2691: 
 2692:   num_lsps = max_lsps_per_snp (ISIS_SNP_CSNP_FLAG, level, circuit);
 2693: 
 2694:   while (loop)
 2695:     {
 2696:       list = list_new ();
 2697:       lsp_build_list (start, stop, num_lsps, list,
 2698:                       circuit->area->lspdb[level - 1]);
 2699:       /*
 2700:        * Update the stop lsp_id before encoding this CSNP.
 2701:        */
 2702:       if (listcount (list) < num_lsps)
 2703:         {
 2704:           memset (stop, 0xff, ISIS_SYS_ID_LEN + 2);
 2705:         }
 2706:       else
 2707:         {
 2708:           node = listtail (list);
 2709:           lsp = listgetdata (node);
 2710:           memcpy (stop, lsp->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 2);
 2711:         }
 2712: 
 2713:       retval = build_csnp (level, start, stop, list, circuit);
 2714:       if (retval != ISIS_OK)
 2715:         {
 2716:           zlog_err ("ISIS-Snp (%s): Build L%d CSNP on %s failed",
 2717:                     circuit->area->area_tag, level, circuit->interface->name);
 2718:           list_delete (list);
 2719:           return retval;
 2720:         }
 2721: 
 2722:       if (isis->debugs & DEBUG_SNP_PACKETS)
 2723:         {
 2724:           zlog_debug ("ISIS-Snp (%s): Sent L%d CSNP on %s, length %ld",
 2725:                       circuit->area->area_tag, level, circuit->interface->name,
 2726:                       stream_get_endp (circuit->snd_stream));
 2727:           for (ALL_LIST_ELEMENTS_RO (list, node, lsp))
 2728:             {
 2729:               zlog_debug ("ISIS-Snp (%s):         CSNP entry %s, seq 0x%08x,"
 2730:                           " cksum 0x%04x, lifetime %us",
 2731:                           circuit->area->area_tag,
 2732:                           rawlspid_print (lsp->lsp_header->lsp_id),
 2733:                           ntohl (lsp->lsp_header->seq_num),
 2734:                           ntohs (lsp->lsp_header->checksum),
 2735:                           ntohs (lsp->lsp_header->rem_lifetime));
 2736:             }
 2737:           if (isis->debugs & DEBUG_PACKET_DUMP)
 2738:             zlog_dump_data (STREAM_DATA (circuit->snd_stream),
 2739:                             stream_get_endp (circuit->snd_stream));
 2740:         }
 2741: 
 2742:       retval = circuit->tx (circuit, level);
 2743:       if (retval != ISIS_OK)
 2744:         {
 2745:           zlog_err ("ISIS-Snp (%s): Send L%d CSNP on %s failed",
 2746:                     circuit->area->area_tag, level,
 2747:                     circuit->interface->name);
 2748:           list_delete (list);
 2749:           return retval;
 2750:         }
 2751: 
 2752:       /*
 2753:        * Start lsp_id of the next CSNP should be one plus the
 2754:        * stop lsp_id in this current CSNP.
 2755:        */
 2756:       memcpy (start, stop, ISIS_SYS_ID_LEN + 2);
 2757:       loop = 0;
 2758:       for (i = ISIS_SYS_ID_LEN + 1; i >= 0; --i)
 2759:         {
 2760:           if (start[i] < (u_char)0xff)
 2761:             {
 2762:               start[i] += 1;
 2763:               loop = 1;
 2764:               break;
 2765:             }
 2766:         }
 2767:       memset (stop, 0xff, ISIS_SYS_ID_LEN + 2);
 2768:       list_delete (list);
 2769:     }
 2770: 
 2771:   return retval;
 2772: }
 2773: 
 2774: int
 2775: send_l1_csnp (struct thread *thread)
 2776: {
 2777:   struct isis_circuit *circuit;
 2778:   int retval = ISIS_OK;
 2779: 
 2780:   circuit = THREAD_ARG (thread);
 2781:   assert (circuit);
 2782: 
 2783:   circuit->t_send_csnp[0] = NULL;
 2784: 
 2785:   if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[0])
 2786:     {
 2787:       send_csnp (circuit, 1);
 2788:     }
 2789:   /* set next timer thread */
 2790:   THREAD_TIMER_ON (master, circuit->t_send_csnp[0], send_l1_csnp, circuit,
 2791: 		   isis_jitter (circuit->csnp_interval[0], CSNP_JITTER));
 2792: 
 2793:   return retval;
 2794: }
 2795: 
 2796: int
 2797: send_l2_csnp (struct thread *thread)
 2798: {
 2799:   struct isis_circuit *circuit;
 2800:   int retval = ISIS_OK;
 2801: 
 2802:   circuit = THREAD_ARG (thread);
 2803:   assert (circuit);
 2804: 
 2805:   circuit->t_send_csnp[1] = NULL;
 2806: 
 2807:   if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[1])
 2808:     {
 2809:       send_csnp (circuit, 2);
 2810:     }
 2811:   /* set next timer thread */
 2812:   THREAD_TIMER_ON (master, circuit->t_send_csnp[1], send_l2_csnp, circuit,
 2813: 		   isis_jitter (circuit->csnp_interval[1], CSNP_JITTER));
 2814: 
 2815:   return retval;
 2816: }
 2817: 
 2818: static int
 2819: build_psnp (int level, struct isis_circuit *circuit, struct list *lsps)
 2820: {
 2821:   struct isis_fixed_hdr fixed_hdr;
 2822:   unsigned long lenp;
 2823:   u_int16_t length;
 2824:   struct isis_lsp *lsp;
 2825:   struct isis_passwd *passwd;
 2826:   struct listnode *node;
 2827:   unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
 2828:   unsigned long auth_tlv_offset = 0;
 2829:   int retval = ISIS_OK;
 2830: 
 2831:   if (circuit->snd_stream == NULL)
 2832:     circuit->snd_stream = stream_new (ISO_MTU (circuit));
 2833:   else
 2834:     stream_reset (circuit->snd_stream);
 2835: 
 2836:   if (level == IS_LEVEL_1)
 2837:     fill_fixed_hdr_andstream (&fixed_hdr, L1_PARTIAL_SEQ_NUM,
 2838: 			      circuit->snd_stream);
 2839:   else
 2840:     fill_fixed_hdr_andstream (&fixed_hdr, L2_PARTIAL_SEQ_NUM,
 2841: 			      circuit->snd_stream);
 2842: 
 2843:   /*
 2844:    * Fill Level 1 or 2 Partial Sequence Numbers header
 2845:    */
 2846:   lenp = stream_get_endp (circuit->snd_stream);
 2847:   stream_putw (circuit->snd_stream, 0);	/* PDU length - when we know it */
 2848:   stream_put (circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN);
 2849:   stream_putc (circuit->snd_stream, circuit->idx);
 2850: 
 2851:   /*
 2852:    * And TLVs
 2853:    */
 2854: 
 2855:   if (level == IS_LEVEL_1)
 2856:     passwd = &circuit->area->area_passwd;
 2857:   else
 2858:     passwd = &circuit->area->domain_passwd;
 2859: 
 2860:   if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND))
 2861:   {
 2862:     switch (passwd->type)
 2863:     {
 2864:       /* Cleartext */
 2865:       case ISIS_PASSWD_TYPE_CLEARTXT:
 2866:         if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT, passwd->len,
 2867:                               passwd->passwd, circuit->snd_stream))
 2868:           return ISIS_WARNING;
 2869:         break;
 2870: 
 2871:         /* HMAC MD5 */
 2872:       case ISIS_PASSWD_TYPE_HMAC_MD5:
 2873:         /* Remember where TLV is written so we can later overwrite the MD5 hash */
 2874:         auth_tlv_offset = stream_get_endp (circuit->snd_stream);
 2875:         memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
 2876:         if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5, ISIS_AUTH_MD5_SIZE,
 2877:                               hmac_md5_hash, circuit->snd_stream))
 2878:           return ISIS_WARNING;
 2879:         break;
 2880: 
 2881:       default:
 2882:         break;
 2883:     }
 2884:   }
 2885: 
 2886:   retval = tlv_add_lsp_entries (lsps, circuit->snd_stream);
 2887:   if (retval != ISIS_OK)
 2888:     return retval;
 2889: 
 2890:   if (isis->debugs & DEBUG_SNP_PACKETS)
 2891:     {
 2892:       for (ALL_LIST_ELEMENTS_RO (lsps, node, lsp))
 2893:       {
 2894: 	zlog_debug ("ISIS-Snp (%s):         PSNP entry %s, seq 0x%08x,"
 2895: 		    " cksum 0x%04x, lifetime %us",
 2896: 		    circuit->area->area_tag,
 2897: 		    rawlspid_print (lsp->lsp_header->lsp_id),
 2898: 		    ntohl (lsp->lsp_header->seq_num),
 2899: 		    ntohs (lsp->lsp_header->checksum),
 2900: 		    ntohs (lsp->lsp_header->rem_lifetime));
 2901:       }
 2902:     }
 2903: 
 2904:   length = (u_int16_t) stream_get_endp (circuit->snd_stream);
 2905:   /* Update PDU length */
 2906:   stream_putw_at (circuit->snd_stream, lenp, length);
 2907: 
 2908:   /* For HMAC MD5 we need to compute the md5 hash and store it */
 2909:   if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND) &&
 2910:       passwd->type == ISIS_PASSWD_TYPE_HMAC_MD5)
 2911:     {
 2912:       hmac_md5 (STREAM_DATA (circuit->snd_stream),
 2913:                 stream_get_endp(circuit->snd_stream),
 2914:                 (unsigned char *) &passwd->passwd, passwd->len,
 2915:                 (caddr_t) &hmac_md5_hash);
 2916:       /* Copy the hash into the stream */
 2917:       memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3,
 2918:               hmac_md5_hash, ISIS_AUTH_MD5_SIZE);
 2919:     }
 2920: 
 2921:   return ISIS_OK;
 2922: }
 2923: 
 2924: /*
 2925:  *  7.3.15.4 action on expiration of partial SNP interval
 2926:  *  level 1
 2927:  */
 2928: static int
 2929: send_psnp (int level, struct isis_circuit *circuit)
 2930: {
 2931:   struct isis_lsp *lsp;
 2932:   struct list *list = NULL;
 2933:   struct listnode *node;
 2934:   u_char num_lsps;
 2935:   int retval = ISIS_OK;
 2936: 
 2937:   if (circuit->circ_type == CIRCUIT_T_BROADCAST &&
 2938:       circuit->u.bc.is_dr[level - 1])
 2939:     return ISIS_OK;
 2940: 
 2941:   if (circuit->area->lspdb[level - 1] == NULL ||
 2942:       dict_count (circuit->area->lspdb[level - 1]) == 0)
 2943:     return ISIS_OK;
 2944: 
 2945:   if (! circuit->snd_stream)
 2946:     return ISIS_ERROR;
 2947: 
 2948:   num_lsps = max_lsps_per_snp (ISIS_SNP_PSNP_FLAG, level, circuit);
 2949: 
 2950:   while (1)
 2951:     {
 2952:       list = list_new ();
 2953:       lsp_build_list_ssn (circuit, num_lsps, list,
 2954:                           circuit->area->lspdb[level - 1]);
 2955: 
 2956:       if (listcount (list) == 0)
 2957:         {
 2958:           list_delete (list);
 2959:           return ISIS_OK;
 2960:         }
 2961: 
 2962:       retval = build_psnp (level, circuit, list);
 2963:       if (retval != ISIS_OK)
 2964:         {
 2965:           zlog_err ("ISIS-Snp (%s): Build L%d PSNP on %s failed",
 2966:                     circuit->area->area_tag, level, circuit->interface->name);
 2967:           list_delete (list);
 2968:           return retval;
 2969:         }
 2970: 
 2971:       if (isis->debugs & DEBUG_SNP_PACKETS)
 2972:         {
 2973:           zlog_debug ("ISIS-Snp (%s): Sent L%d PSNP on %s, length %ld",
 2974:                       circuit->area->area_tag, level,
 2975:                       circuit->interface->name,
 2976:                       stream_get_endp (circuit->snd_stream));
 2977:           if (isis->debugs & DEBUG_PACKET_DUMP)
 2978:             zlog_dump_data (STREAM_DATA (circuit->snd_stream),
 2979:                             stream_get_endp (circuit->snd_stream));
 2980:         }
 2981: 
 2982:       retval = circuit->tx (circuit, level);
 2983:       if (retval != ISIS_OK)
 2984:         {
 2985:           zlog_err ("ISIS-Snp (%s): Send L%d PSNP on %s failed",
 2986:                     circuit->area->area_tag, level,
 2987:                     circuit->interface->name);
 2988:           list_delete (list);
 2989:           return retval;
 2990:         }
 2991: 
 2992:       /*
 2993:        * sending succeeded, we can clear SSN flags of this circuit
 2994:        * for the LSPs in list
 2995:        */
 2996:       for (ALL_LIST_ELEMENTS_RO (list, node, lsp))
 2997:         ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
 2998:       list_delete (list);
 2999:     }
 3000: 
 3001:   return retval;
 3002: }
 3003: 
 3004: int
 3005: send_l1_psnp (struct thread *thread)
 3006: {
 3007: 
 3008:   struct isis_circuit *circuit;
 3009:   int retval = ISIS_OK;
 3010: 
 3011:   circuit = THREAD_ARG (thread);
 3012:   assert (circuit);
 3013: 
 3014:   circuit->t_send_psnp[0] = NULL;
 3015: 
 3016:   send_psnp (1, circuit);
 3017:   /* set next timer thread */
 3018:   THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit,
 3019: 		   isis_jitter (circuit->psnp_interval[0], PSNP_JITTER));
 3020: 
 3021:   return retval;
 3022: }
 3023: 
 3024: /*
 3025:  *  7.3.15.4 action on expiration of partial SNP interval
 3026:  *  level 2
 3027:  */
 3028: int
 3029: send_l2_psnp (struct thread *thread)
 3030: {
 3031:   struct isis_circuit *circuit;
 3032:   int retval = ISIS_OK;
 3033: 
 3034:   circuit = THREAD_ARG (thread);
 3035:   assert (circuit);
 3036: 
 3037:   circuit->t_send_psnp[1] = NULL;
 3038: 
 3039:   send_psnp (2, circuit);
 3040: 
 3041:   /* set next timer thread */
 3042:   THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit,
 3043: 		   isis_jitter (circuit->psnp_interval[1], PSNP_JITTER));
 3044: 
 3045:   return retval;
 3046: }
 3047: 
 3048: /*
 3049:  * ISO 10589 - 7.3.14.3
 3050:  */
 3051: int
 3052: send_lsp (struct thread *thread)
 3053: {
 3054:   struct isis_circuit *circuit;
 3055:   struct isis_lsp *lsp;
 3056:   struct listnode *node;
 3057:   int retval = ISIS_OK;
 3058: 
 3059:   circuit = THREAD_ARG (thread);
 3060:   assert (circuit);
 3061: 
 3062:   if (circuit->state != C_STATE_UP || circuit->is_passive == 1)
 3063:   {
 3064:     return retval;
 3065:   }
 3066: 
 3067:   node = listhead (circuit->lsp_queue);
 3068: 
 3069:   /*
 3070:    * Handle case where there are no LSPs on the queue. This can
 3071:    * happen, for instance, if an adjacency goes down before this
 3072:    * thread gets a chance to run.
 3073:    */
 3074:   if (!node)
 3075:     {
 3076:       return retval;
 3077:     }
 3078: 
 3079:   lsp = listgetdata(node);
 3080: 
 3081:   /*
 3082:    * Do not send if levels do not match
 3083:    */
 3084:   if (!(lsp->level & circuit->is_type))
 3085:     {
 3086:       list_delete_node (circuit->lsp_queue, node);
 3087:       return retval;
 3088:     }
 3089: 
 3090:   /*
 3091:    * Do not send if we do not have adjacencies in state up on the circuit
 3092:    */
 3093:   if (circuit->upadjcount[lsp->level - 1] == 0)
 3094:     {
 3095:       list_delete_node (circuit->lsp_queue, node);
 3096:       return retval;
 3097:     }
 3098: 
 3099:   /* copy our lsp to the send buffer */
 3100:   stream_copy (circuit->snd_stream, lsp->pdu);
 3101: 
 3102:   if (isis->debugs & DEBUG_UPDATE_PACKETS)
 3103:     {
 3104:       zlog_debug
 3105:         ("ISIS-Upd (%s): Sent L%d LSP %s, seq 0x%08x, cksum 0x%04x,"
 3106:          " lifetime %us on %s", circuit->area->area_tag, lsp->level,
 3107:          rawlspid_print (lsp->lsp_header->lsp_id),
 3108:          ntohl (lsp->lsp_header->seq_num),
 3109:          ntohs (lsp->lsp_header->checksum),
 3110:          ntohs (lsp->lsp_header->rem_lifetime),
 3111:          circuit->interface->name);
 3112:       if (isis->debugs & DEBUG_PACKET_DUMP)
 3113:         zlog_dump_data (STREAM_DATA (circuit->snd_stream),
 3114:                         stream_get_endp (circuit->snd_stream));
 3115:     }
 3116: 
 3117:   retval = circuit->tx (circuit, lsp->level);
 3118:   if (retval != ISIS_OK)
 3119:     {
 3120:       zlog_err ("ISIS-Upd (%s): Send L%d LSP on %s failed",
 3121:                 circuit->area->area_tag, lsp->level,
 3122:                 circuit->interface->name);
 3123:       return retval;
 3124:     }
 3125: 
 3126:   /*
 3127:    * If the sending succeeded, we can del the lsp from circuits
 3128:    * lsp_queue
 3129:    */
 3130:   list_delete_node (circuit->lsp_queue, node);
 3131: 
 3132:   /* Set the last-cleared time if the queue is empty. */
 3133:   /* TODO: Is is possible that new lsps keep being added to the queue
 3134:    * that the queue is never empty? */
 3135:   if (list_isempty (circuit->lsp_queue))
 3136:     circuit->lsp_queue_last_cleared = time (NULL);
 3137: 
 3138:   /*
 3139:    * On broadcast circuits also the SRMflag can be cleared
 3140:    */
 3141:   if (circuit->circ_type == CIRCUIT_T_BROADCAST)
 3142:     ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
 3143: 
 3144:   return retval;
 3145: }
 3146: 
 3147: int
 3148: ack_lsp (struct isis_link_state_hdr *hdr, struct isis_circuit *circuit,
 3149: 	 int level)
 3150: {
 3151:   unsigned long lenp;
 3152:   int retval;
 3153:   u_int16_t length;
 3154:   struct isis_fixed_hdr fixed_hdr;
 3155: 
 3156:   if (!circuit->snd_stream)
 3157:     circuit->snd_stream = stream_new (ISO_MTU (circuit));
 3158:   else
 3159:     stream_reset (circuit->snd_stream);
 3160: 
 3161:   //  fill_llc_hdr (stream);
 3162:   if (level == IS_LEVEL_1)
 3163:     fill_fixed_hdr_andstream (&fixed_hdr, L1_PARTIAL_SEQ_NUM,
 3164: 			      circuit->snd_stream);
 3165:   else
 3166:     fill_fixed_hdr_andstream (&fixed_hdr, L2_PARTIAL_SEQ_NUM,
 3167: 			      circuit->snd_stream);
 3168: 
 3169: 
 3170:   lenp = stream_get_endp (circuit->snd_stream);
 3171:   stream_putw (circuit->snd_stream, 0);	/* PDU length  */
 3172:   stream_put (circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN);
 3173:   stream_putc (circuit->snd_stream, circuit->idx);
 3174:   stream_putc (circuit->snd_stream, 9);	/* code */
 3175:   stream_putc (circuit->snd_stream, 16);	/* len */
 3176: 
 3177:   stream_putw (circuit->snd_stream, ntohs (hdr->rem_lifetime));
 3178:   stream_put (circuit->snd_stream, hdr->lsp_id, ISIS_SYS_ID_LEN + 2);
 3179:   stream_putl (circuit->snd_stream, ntohl (hdr->seq_num));
 3180:   stream_putw (circuit->snd_stream, ntohs (hdr->checksum));
 3181: 
 3182:   length = (u_int16_t) stream_get_endp (circuit->snd_stream);
 3183:   /* Update PDU length */
 3184:   stream_putw_at (circuit->snd_stream, lenp, length);
 3185: 
 3186:   retval = circuit->tx (circuit, level);
 3187:   if (retval != ISIS_OK)
 3188:     zlog_err ("ISIS-Upd (%s): Send L%d LSP PSNP on %s failed",
 3189:               circuit->area->area_tag, level,
 3190:               circuit->interface->name);
 3191: 
 3192:   return retval;
 3193: }

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