File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / isisd / isis_pdu.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:26:11 2012 UTC (12 years, 5 months ago) by misho
Branches: quagga, MAIN
CVS tags: v0_99_20_1, v0_99_20, HEAD
quagga

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

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