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

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

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