Annotation of embedaddon/quagga/isisd/isis_pdu.c, revision 1.1.1.2

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

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