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

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

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