Annotation of embedaddon/quagga/isisd/isis_lsp.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * IS-IS Rout(e)ing protocol - isis_lsp.c
        !             3:  *                             LSP 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 "linklist.h"
        !            27: #include "thread.h"
        !            28: #include "vty.h"
        !            29: #include "stream.h"
        !            30: #include "memory.h"
        !            31: #include "log.h"
        !            32: #include "prefix.h"
        !            33: #include "command.h"
        !            34: #include "hash.h"
        !            35: #include "if.h"
        !            36: #include "checksum.h"
        !            37: 
        !            38: #include "isisd/dict.h"
        !            39: #include "isisd/isis_constants.h"
        !            40: #include "isisd/isis_common.h"
        !            41: #include "isisd/isis_circuit.h"
        !            42: #include "isisd/isisd.h"
        !            43: #include "isisd/isis_tlv.h"
        !            44: #include "isisd/isis_lsp.h"
        !            45: #include "isisd/isis_pdu.h"
        !            46: #include "isisd/isis_dynhn.h"
        !            47: #include "isisd/isis_misc.h"
        !            48: #include "isisd/isis_flags.h"
        !            49: #include "isisd/isis_csm.h"
        !            50: #include "isisd/isis_adjacency.h"
        !            51: #include "isisd/isis_spf.h"
        !            52: 
        !            53: #ifdef TOPOLOGY_GENERATE
        !            54: #include "spgrid.h"
        !            55: #endif
        !            56: 
        !            57: #define LSP_MEMORY_PREASSIGN
        !            58: 
        !            59: extern struct isis *isis;
        !            60: extern struct thread_master *master;
        !            61: extern struct in_addr router_id_zebra;
        !            62: 
        !            63: /* staticly assigned vars for printing purposes */
        !            64: char lsp_bits_string[200];     /* FIXME: enough ? */
        !            65: 
        !            66: int
        !            67: lsp_id_cmp (u_char * id1, u_char * id2)
        !            68: {
        !            69:   return memcmp (id1, id2, ISIS_SYS_ID_LEN + 2);
        !            70: }
        !            71: 
        !            72: dict_t *
        !            73: lsp_db_init (void)
        !            74: {
        !            75:   dict_t *dict;
        !            76: 
        !            77:   dict = dict_create (DICTCOUNT_T_MAX, (dict_comp_t) lsp_id_cmp);
        !            78: 
        !            79:   return dict;
        !            80: }
        !            81: 
        !            82: struct isis_lsp *
        !            83: lsp_search (u_char * id, dict_t * lspdb)
        !            84: {
        !            85:   dnode_t *node;
        !            86: 
        !            87: #ifdef EXTREME_DEBUG
        !            88:   dnode_t *dn;
        !            89: 
        !            90:   zlog_debug ("searching db");
        !            91:   for (dn = dict_first (lspdb); dn; dn = dict_next (lspdb, dn))
        !            92:     {
        !            93:       zlog_debug ("%s\t%pX", rawlspid_print ((char *) dnode_getkey (dn)),
        !            94:                  dnode_get (dn));
        !            95:     }
        !            96: #endif /* EXTREME DEBUG */
        !            97: 
        !            98:   node = dict_lookup (lspdb, id);
        !            99: 
        !           100:   if (node)
        !           101:     return (struct isis_lsp *) dnode_get (node);
        !           102: 
        !           103:   return NULL;
        !           104: }
        !           105: 
        !           106: static void
        !           107: lsp_clear_data (struct isis_lsp *lsp)
        !           108: {
        !           109:   if (!lsp)
        !           110:     return;
        !           111: 
        !           112:   if (lsp->own_lsp)
        !           113:     {
        !           114:       if (lsp->tlv_data.nlpids)
        !           115:        XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.nlpids);
        !           116:       if (lsp->tlv_data.hostname)
        !           117:        XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.hostname);
        !           118:     }
        !           119:   if (lsp->tlv_data.is_neighs)
        !           120:     list_delete (lsp->tlv_data.is_neighs);
        !           121:   if (lsp->tlv_data.te_is_neighs)
        !           122:     list_delete (lsp->tlv_data.te_is_neighs);
        !           123:   if (lsp->tlv_data.area_addrs)
        !           124:     list_delete (lsp->tlv_data.area_addrs);
        !           125:   if (lsp->tlv_data.es_neighs)
        !           126:     list_delete (lsp->tlv_data.es_neighs);
        !           127:   if (lsp->tlv_data.ipv4_addrs)
        !           128:     list_delete (lsp->tlv_data.ipv4_addrs);
        !           129:   if (lsp->tlv_data.ipv4_int_reachs)
        !           130:     list_delete (lsp->tlv_data.ipv4_int_reachs);
        !           131:   if (lsp->tlv_data.ipv4_ext_reachs)
        !           132:     list_delete (lsp->tlv_data.ipv4_ext_reachs);
        !           133:   if (lsp->tlv_data.te_ipv4_reachs)
        !           134:     list_delete (lsp->tlv_data.te_ipv4_reachs);
        !           135: #ifdef HAVE_IPV6
        !           136:   if (lsp->tlv_data.ipv6_addrs)
        !           137:     list_delete (lsp->tlv_data.ipv6_addrs);
        !           138:   if (lsp->tlv_data.ipv6_reachs)
        !           139:     list_delete (lsp->tlv_data.ipv6_reachs);
        !           140: #endif /* HAVE_IPV6 */
        !           141: 
        !           142:   memset (&lsp->tlv_data, 0, sizeof (struct tlvs));
        !           143: 
        !           144:   return;
        !           145: }
        !           146: 
        !           147: static void
        !           148: lsp_destroy (struct isis_lsp *lsp)
        !           149: {
        !           150:   if (!lsp)
        !           151:     return;
        !           152: 
        !           153:   lsp_clear_data (lsp);
        !           154: 
        !           155:   if (LSP_FRAGMENT (lsp->lsp_header->lsp_id) == 0 && lsp->lspu.frags)
        !           156:     {
        !           157:       list_delete (lsp->lspu.frags);
        !           158:     }
        !           159: 
        !           160:   if (lsp->pdu)
        !           161:     stream_free (lsp->pdu);
        !           162:   XFREE (MTYPE_ISIS_LSP, lsp);
        !           163: }
        !           164: 
        !           165: void
        !           166: lsp_db_destroy (dict_t * lspdb)
        !           167: {
        !           168:   dnode_t *dnode, *next;
        !           169:   struct isis_lsp *lsp;
        !           170: 
        !           171:   dnode = dict_first (lspdb);
        !           172:   while (dnode)
        !           173:     {
        !           174:       next = dict_next (lspdb, dnode);
        !           175:       lsp = dnode_get (dnode);
        !           176:       lsp_destroy (lsp);
        !           177:       dict_delete_free (lspdb, dnode);
        !           178:       dnode = next;
        !           179:     }
        !           180: 
        !           181:   dict_free (lspdb);
        !           182: 
        !           183:   return;
        !           184: }
        !           185: 
        !           186: /*
        !           187:  * Remove all the frags belonging to the given lsp
        !           188:  */
        !           189: static void
        !           190: lsp_remove_frags (struct list *frags, dict_t * lspdb)
        !           191: {
        !           192:   dnode_t *dnode;
        !           193:   struct listnode *lnode, *lnnode;
        !           194:   struct isis_lsp *lsp;
        !           195: 
        !           196:   for (ALL_LIST_ELEMENTS (frags, lnode, lnnode, lsp))
        !           197:     {
        !           198:       dnode = dict_lookup (lspdb, lsp->lsp_header->lsp_id);
        !           199:       lsp_destroy (lsp);
        !           200:       dnode_destroy (dict_delete (lspdb, dnode));
        !           201:     }
        !           202: 
        !           203:   list_delete_all_node (frags);
        !           204: 
        !           205:   return;
        !           206: }
        !           207: 
        !           208: void
        !           209: lsp_search_and_destroy (u_char * id, dict_t * lspdb)
        !           210: {
        !           211:   dnode_t *node;
        !           212:   struct isis_lsp *lsp;
        !           213: 
        !           214:   node = dict_lookup (lspdb, id);
        !           215:   if (node)
        !           216:     {
        !           217:       node = dict_delete (lspdb, node);
        !           218:       lsp = dnode_get (node);
        !           219:       /*
        !           220:        * If this is a zero lsp, remove all the frags now 
        !           221:        */
        !           222:       if (LSP_FRAGMENT (lsp->lsp_header->lsp_id) == 0)
        !           223:        {
        !           224:          if (lsp->lspu.frags)
        !           225:            lsp_remove_frags (lsp->lspu.frags, lspdb);
        !           226:        }
        !           227:       else
        !           228:        {
        !           229:          /* 
        !           230:           * else just remove this frag, from the zero lsps' frag list
        !           231:           */
        !           232:          if (lsp->lspu.zero_lsp && lsp->lspu.zero_lsp->lspu.frags)
        !           233:            listnode_delete (lsp->lspu.zero_lsp->lspu.frags, lsp);
        !           234:        }
        !           235:       lsp_destroy (lsp);
        !           236:       dnode_destroy (node);
        !           237:     }
        !           238: }
        !           239: 
        !           240: /*
        !           241:  * Compares a LSP to given values
        !           242:  * Params are given in net order
        !           243:  */
        !           244: int
        !           245: lsp_compare (char *areatag, struct isis_lsp *lsp, u_int32_t seq_num,
        !           246:             u_int16_t checksum, u_int16_t rem_lifetime)
        !           247: {
        !           248:   /* no point in double ntohl on seqnum */
        !           249:   if (lsp->lsp_header->seq_num == seq_num &&
        !           250:       lsp->lsp_header->checksum == checksum &&
        !           251:       /*comparing with 0, no need to do ntohl */
        !           252:       ((lsp->lsp_header->rem_lifetime == 0 && rem_lifetime == 0) ||
        !           253:        (lsp->lsp_header->rem_lifetime != 0 && rem_lifetime != 0)))
        !           254:     {
        !           255:       if (isis->debugs & DEBUG_SNP_PACKETS)
        !           256:        {
        !           257:          zlog_debug ("ISIS-Snp (%s): LSP %s seq 0x%08x, cksum 0x%04x,"
        !           258:                      " lifetime %us",
        !           259:                      areatag,
        !           260:                      rawlspid_print (lsp->lsp_header->lsp_id),
        !           261:                      ntohl (lsp->lsp_header->seq_num),
        !           262:                      ntohs (lsp->lsp_header->checksum),
        !           263:                      ntohs (lsp->lsp_header->rem_lifetime));
        !           264:          zlog_debug ("ISIS-Snp (%s):         is equal to ours seq 0x%08x,"
        !           265:                      " cksum 0x%04x, lifetime %us",
        !           266:                      areatag,
        !           267:                      ntohl (seq_num), ntohs (checksum), ntohs (rem_lifetime));
        !           268:        }
        !           269:       return LSP_EQUAL;
        !           270:     }
        !           271: 
        !           272:   if (ntohl (seq_num) >= ntohl (lsp->lsp_header->seq_num))
        !           273:     {
        !           274:       if (isis->debugs & DEBUG_SNP_PACKETS)
        !           275:        {
        !           276:          zlog_debug ("ISIS-Snp (%s): LSP %s seq 0x%08x, cksum 0x%04x,"
        !           277:                      " lifetime %us",
        !           278:                      areatag,
        !           279:                      rawlspid_print (lsp->lsp_header->lsp_id),
        !           280:                      ntohl (seq_num), ntohs (checksum), ntohs (rem_lifetime));
        !           281:          zlog_debug ("ISIS-Snp (%s):       is newer than ours seq 0x%08x, "
        !           282:                      "cksum 0x%04x, lifetime %us",
        !           283:                      areatag,
        !           284:                      ntohl (lsp->lsp_header->seq_num),
        !           285:                      ntohs (lsp->lsp_header->checksum),
        !           286:                      ntohs (lsp->lsp_header->rem_lifetime));
        !           287:        }
        !           288:       return LSP_NEWER;
        !           289:     }
        !           290:   if (isis->debugs & DEBUG_SNP_PACKETS)
        !           291:     {
        !           292:       zlog_debug
        !           293:        ("ISIS-Snp (%s): LSP %s seq 0x%08x, cksum 0x%04x, lifetime %us",
        !           294:         areatag, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (seq_num),
        !           295:         ntohs (checksum), ntohs (rem_lifetime));
        !           296:       zlog_debug ("ISIS-Snp (%s):       is older than ours seq 0x%08x,"
        !           297:                  " cksum 0x%04x, lifetime %us", areatag,
        !           298:                  ntohl (lsp->lsp_header->seq_num),
        !           299:                  ntohs (lsp->lsp_header->checksum),
        !           300:                  ntohs (lsp->lsp_header->rem_lifetime));
        !           301:     }
        !           302: 
        !           303:   return LSP_OLDER;
        !           304: }
        !           305: 
        !           306: void
        !           307: lsp_inc_seqnum (struct isis_lsp *lsp, u_int32_t seq_num)
        !           308: {
        !           309:   u_int32_t newseq;
        !           310: 
        !           311:   if (seq_num == 0 || ntohl (lsp->lsp_header->seq_num) > seq_num)
        !           312:     newseq = ntohl (lsp->lsp_header->seq_num) + 1;
        !           313:   else
        !           314:     newseq = seq_num++;
        !           315: 
        !           316:   lsp->lsp_header->seq_num = htonl (newseq);
        !           317:   fletcher_checksum (STREAM_DATA (lsp->pdu) + 12,
        !           318:                   ntohs (lsp->lsp_header->pdu_len) - 12, 12);
        !           319: 
        !           320:   return;
        !           321: }
        !           322: 
        !           323: /*
        !           324:  * Genetates checksum for LSP and its frags
        !           325:  */
        !           326: static void
        !           327: lsp_seqnum_update (struct isis_lsp *lsp0)
        !           328: {
        !           329:   struct isis_lsp *lsp;
        !           330:   struct listnode *node;
        !           331: 
        !           332:   lsp_inc_seqnum (lsp0, 0);
        !           333: 
        !           334:   if (!lsp0->lspu.frags)
        !           335:     return;
        !           336: 
        !           337:   for (ALL_LIST_ELEMENTS_RO (lsp0->lspu.frags, node, lsp))
        !           338:     lsp_inc_seqnum (lsp, 0);
        !           339: 
        !           340:   return;
        !           341: }
        !           342: 
        !           343: int
        !           344: isis_lsp_authinfo_check (struct stream *stream, struct isis_area *area,
        !           345:                         int pdulen, struct isis_passwd *passwd)
        !           346: {
        !           347:   uint32_t expected = 0, found;
        !           348:   struct tlvs tlvs;
        !           349:   int retval = 0;
        !           350: 
        !           351:   expected |= TLVFLAG_AUTH_INFO;
        !           352:   retval = parse_tlvs (area->area_tag, stream->data +
        !           353:                       ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN,
        !           354:                       pdulen - ISIS_FIXED_HDR_LEN
        !           355:                       - ISIS_LSP_HDR_LEN, &expected, &found, &tlvs);
        !           356:   if (retval || !(found & TLVFLAG_AUTH_INFO))
        !           357:     return 1;                  /* Auth fail (parsing failed or no auth-tlv) */
        !           358: 
        !           359:   return authentication_check (passwd, &tlvs.auth_info);
        !           360: }
        !           361: 
        !           362: static void
        !           363: lsp_update_data (struct isis_lsp *lsp, struct stream *stream,
        !           364:                 struct isis_area *area)
        !           365: {
        !           366:   uint32_t expected = 0, found;
        !           367:   int retval;
        !           368: 
        !           369:   /* copying only the relevant part of our stream */
        !           370:   lsp->pdu = stream_dup (stream);
        !           371:   
        !           372:   /* setting pointers to the correct place */
        !           373:   lsp->isis_header = (struct isis_fixed_hdr *) (STREAM_DATA (lsp->pdu));
        !           374:   lsp->lsp_header = (struct isis_link_state_hdr *) (STREAM_DATA (lsp->pdu) +
        !           375:                                                    ISIS_FIXED_HDR_LEN);
        !           376:   lsp->age_out = ZERO_AGE_LIFETIME;
        !           377:   lsp->installed = time (NULL);
        !           378:   /*
        !           379:    * Get LSP data i.e. TLVs
        !           380:    */
        !           381:   expected |= TLVFLAG_AUTH_INFO;
        !           382:   expected |= TLVFLAG_AREA_ADDRS;
        !           383:   expected |= TLVFLAG_IS_NEIGHS;
        !           384:   if ((lsp->lsp_header->lsp_bits & 3) == 3)    /* a level 2 LSP */
        !           385:     expected |= TLVFLAG_PARTITION_DESIG_LEVEL2_IS;
        !           386:   expected |= TLVFLAG_NLPID;
        !           387:   if (area->dynhostname)
        !           388:     expected |= TLVFLAG_DYN_HOSTNAME;
        !           389:   if (area->newmetric)
        !           390:     {
        !           391:       expected |= TLVFLAG_TE_IS_NEIGHS;
        !           392:       expected |= TLVFLAG_TE_IPV4_REACHABILITY;
        !           393:       expected |= TLVFLAG_TE_ROUTER_ID;
        !           394:     }
        !           395:   expected |= TLVFLAG_IPV4_ADDR;
        !           396:   expected |= TLVFLAG_IPV4_INT_REACHABILITY;
        !           397:   expected |= TLVFLAG_IPV4_EXT_REACHABILITY;
        !           398: #ifdef HAVE_IPV6
        !           399:   expected |= TLVFLAG_IPV6_ADDR;
        !           400:   expected |= TLVFLAG_IPV6_REACHABILITY;
        !           401: #endif /* HAVE_IPV6 */
        !           402: 
        !           403:   retval = parse_tlvs (area->area_tag, lsp->pdu->data +
        !           404:                       ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN,
        !           405:                       ntohs (lsp->lsp_header->pdu_len) - ISIS_FIXED_HDR_LEN
        !           406:                       - ISIS_LSP_HDR_LEN, &expected, &found, &lsp->tlv_data);
        !           407: 
        !           408:   if (found & TLVFLAG_DYN_HOSTNAME)
        !           409:     {
        !           410:       if (area->dynhostname)
        !           411:        isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname,
        !           412:                           (lsp->lsp_header->lsp_bits & LSPBIT_IST) ==
        !           413:                           IS_LEVEL_1_AND_2 ? IS_LEVEL_2 :
        !           414:                           (lsp->lsp_header->lsp_bits & LSPBIT_IST));
        !           415:     }
        !           416: 
        !           417: }
        !           418: 
        !           419: void
        !           420: lsp_update (struct isis_lsp *lsp, struct isis_link_state_hdr *lsp_hdr,
        !           421:            struct stream *stream, struct isis_area *area, int level)
        !           422: {
        !           423:   dnode_t *dnode = NULL;
        !           424: 
        !           425:   /* Remove old LSP from LSP database. */
        !           426:   dnode = dict_lookup (area->lspdb[level - 1], lsp->lsp_header->lsp_id);
        !           427:   if (dnode)
        !           428:     dnode_destroy (dict_delete (area->lspdb[level - 1], dnode));
        !           429: 
        !           430:   /* free the old lsp data */
        !           431:   XFREE (MTYPE_STREAM_DATA, lsp->pdu);
        !           432:   lsp_clear_data (lsp);
        !           433: 
        !           434:   /* rebuild the lsp data */
        !           435:   lsp_update_data (lsp, stream, area);
        !           436: 
        !           437:   /* set the new values for lsp header */
        !           438:   memcpy (lsp->lsp_header, lsp_hdr, ISIS_LSP_HDR_LEN);
        !           439: 
        !           440:   if (dnode)
        !           441:     lsp_insert (lsp, area->lspdb[level - 1]);
        !           442: }
        !           443: 
        !           444: /* creation of LSP directly from what we received */
        !           445: struct isis_lsp *
        !           446: lsp_new_from_stream_ptr (struct stream *stream,
        !           447:                         u_int16_t pdu_len, struct isis_lsp *lsp0,
        !           448:                         struct isis_area *area)
        !           449: {
        !           450:   struct isis_lsp *lsp;
        !           451: 
        !           452:   lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp));
        !           453:   lsp_update_data (lsp, stream, area);
        !           454: 
        !           455:   if (lsp0 == NULL)
        !           456:     {
        !           457:       /*
        !           458:        * zero lsp -> create the list for fragments
        !           459:        */
        !           460:       lsp->lspu.frags = list_new ();
        !           461:     }
        !           462:   else
        !           463:     {
        !           464:       /*
        !           465:        * a fragment -> set the backpointer and add this to zero lsps frag list
        !           466:        */
        !           467:       lsp->lspu.zero_lsp = lsp0;
        !           468:       listnode_add (lsp0->lspu.frags, lsp);
        !           469:     }
        !           470: 
        !           471:   return lsp;
        !           472: }
        !           473: 
        !           474: struct isis_lsp *
        !           475: lsp_new (u_char * lsp_id, u_int16_t rem_lifetime, u_int32_t seq_num,
        !           476:         u_int8_t lsp_bits, u_int16_t checksum, int level)
        !           477: {
        !           478:   struct isis_lsp *lsp;
        !           479: 
        !           480:   lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp));
        !           481:   if (!lsp)
        !           482:     {
        !           483:       /* FIXME: set lspdbol bit */
        !           484:       zlog_warn ("lsp_new(): out of memory");
        !           485:       return NULL;
        !           486:     }
        !           487: #ifdef LSP_MEMORY_PREASSIGN
        !           488:   lsp->pdu = stream_new (1514);        /*Should be minimal mtu? yup... */
        !           489: #else
        !           490:   /* We need to do realloc on TLVs additions */
        !           491:   lsp->pdu = malloc (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
        !           492: #endif /* LSP_MEMORY_PREASSIGN */
        !           493:   if (LSP_FRAGMENT (lsp_id) == 0)
        !           494:     lsp->lspu.frags = list_new ();
        !           495:   lsp->isis_header = (struct isis_fixed_hdr *) (STREAM_DATA (lsp->pdu));
        !           496:   lsp->lsp_header = (struct isis_link_state_hdr *)
        !           497:     (STREAM_DATA (lsp->pdu) + ISIS_FIXED_HDR_LEN);
        !           498: 
        !           499:   /* at first we fill the FIXED HEADER */
        !           500:   (level == 1) ? fill_fixed_hdr (lsp->isis_header, L1_LINK_STATE) :
        !           501:     fill_fixed_hdr (lsp->isis_header, L2_LINK_STATE);
        !           502: 
        !           503:   /* now for the LSP HEADER */
        !           504:   /* Minimal LSP PDU size */
        !           505:   lsp->lsp_header->pdu_len = htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
        !           506:   memcpy (lsp->lsp_header->lsp_id, lsp_id, ISIS_SYS_ID_LEN + 2);
        !           507:   lsp->lsp_header->checksum = checksum;        /* Provided in network order */
        !           508:   lsp->lsp_header->seq_num = htonl (seq_num);
        !           509:   lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
        !           510:   lsp->lsp_header->lsp_bits = lsp_bits;
        !           511:   lsp->level = level;
        !           512:   lsp->age_out = ZERO_AGE_LIFETIME;
        !           513: 
        !           514:   stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
        !           515: 
        !           516:   if (isis->debugs & DEBUG_EVENTS)
        !           517:     zlog_debug ("New LSP with ID %s-%02x-%02x seqnum %08x",
        !           518:                sysid_print (lsp_id), LSP_PSEUDO_ID (lsp->lsp_header->lsp_id),
        !           519:                LSP_FRAGMENT (lsp->lsp_header->lsp_id),
        !           520:                ntohl (lsp->lsp_header->seq_num));
        !           521: 
        !           522:   return lsp;
        !           523: }
        !           524: 
        !           525: void
        !           526: lsp_insert (struct isis_lsp *lsp, dict_t * lspdb)
        !           527: {
        !           528:   dict_alloc_insert (lspdb, lsp->lsp_header->lsp_id, lsp);
        !           529: }
        !           530: 
        !           531: /*
        !           532:  * Build a list of LSPs with non-zero ht bounded by start and stop ids
        !           533:  */
        !           534: void
        !           535: lsp_build_list_nonzero_ht (u_char * start_id, u_char * stop_id,
        !           536:                           struct list *list, dict_t * lspdb)
        !           537: {
        !           538:   dnode_t *first, *last, *curr;
        !           539: 
        !           540:   first = dict_lower_bound (lspdb, start_id);
        !           541:   if (!first)
        !           542:     return;
        !           543: 
        !           544:   last = dict_upper_bound (lspdb, stop_id);
        !           545: 
        !           546:   curr = first;
        !           547: 
        !           548:   if (((struct isis_lsp *) (curr->dict_data))->lsp_header->rem_lifetime)
        !           549:     listnode_add (list, first->dict_data);
        !           550: 
        !           551:   while (curr)
        !           552:     {
        !           553:       curr = dict_next (lspdb, curr);
        !           554:       if (curr &&
        !           555:          ((struct isis_lsp *) (curr->dict_data))->lsp_header->rem_lifetime)
        !           556:        listnode_add (list, curr->dict_data);
        !           557:       if (curr == last)
        !           558:        break;
        !           559:     }
        !           560: 
        !           561:   return;
        !           562: }
        !           563: 
        !           564: /*
        !           565:  * Build a list of all LSPs bounded by start and stop ids
        !           566:  */
        !           567: void
        !           568: lsp_build_list (u_char * start_id, u_char * stop_id,
        !           569:                struct list *list, dict_t * lspdb)
        !           570: {
        !           571:   dnode_t *first, *last, *curr;
        !           572: 
        !           573:   first = dict_lower_bound (lspdb, start_id);
        !           574:   if (!first)
        !           575:     return;
        !           576: 
        !           577:   last = dict_upper_bound (lspdb, stop_id);
        !           578: 
        !           579:   curr = first;
        !           580: 
        !           581:   listnode_add (list, first->dict_data);
        !           582: 
        !           583:   while (curr)
        !           584:     {
        !           585:       curr = dict_next (lspdb, curr);
        !           586:       if (curr)
        !           587:        listnode_add (list, curr->dict_data);
        !           588:       if (curr == last)
        !           589:        break;
        !           590:     }
        !           591: 
        !           592:   return;
        !           593: }
        !           594: 
        !           595: /*
        !           596:  * Build a list of LSPs with SSN flag set for the given circuit
        !           597:  */
        !           598: void
        !           599: lsp_build_list_ssn (struct isis_circuit *circuit, struct list *list,
        !           600:                    dict_t * lspdb)
        !           601: {
        !           602:   dnode_t *dnode, *next;
        !           603:   struct isis_lsp *lsp;
        !           604: 
        !           605:   dnode = dict_first (lspdb);
        !           606:   while (dnode != NULL)
        !           607:     {
        !           608:       next = dict_next (lspdb, dnode);
        !           609:       lsp = dnode_get (dnode);
        !           610:       if (ISIS_CHECK_FLAG (lsp->SSNflags, circuit))
        !           611:        listnode_add (list, lsp);
        !           612:       dnode = next;
        !           613:     }
        !           614: 
        !           615:   return;
        !           616: }
        !           617: 
        !           618: static void
        !           619: lsp_set_time (struct isis_lsp *lsp)
        !           620: {
        !           621:   assert (lsp);
        !           622: 
        !           623:   if (lsp->lsp_header->rem_lifetime == 0)
        !           624:     {
        !           625:       if (lsp->age_out != 0)
        !           626:        lsp->age_out--;
        !           627:       return;
        !           628:     }
        !           629: 
        !           630:   /* If we are turning 0 */
        !           631:   /* ISO 10589 - 7.3.16.4 first paragraph */
        !           632: 
        !           633:   if (ntohs (lsp->lsp_header->rem_lifetime) == 1)
        !           634:     {
        !           635:       /* 7.3.16.4 a) set SRM flags on all */
        !           636:       ISIS_FLAGS_SET_ALL (lsp->SRMflags);
        !           637:       /* 7.3.16.4 b) retain only the header FIXME  */
        !           638:       /* 7.3.16.4 c) record the time to purge FIXME (other way to do it) */
        !           639:     }
        !           640: 
        !           641:   lsp->lsp_header->rem_lifetime =
        !           642:     htons (ntohs (lsp->lsp_header->rem_lifetime) - 1);
        !           643: }
        !           644: 
        !           645: static void
        !           646: lspid_print (u_char * lsp_id, u_char * trg, char dynhost, char frag)
        !           647: {
        !           648:   struct isis_dynhn *dyn = NULL;
        !           649:   u_char id[SYSID_STRLEN];
        !           650: 
        !           651:   if (dynhost)
        !           652:     dyn = dynhn_find_by_id (lsp_id);
        !           653:   else
        !           654:     dyn = NULL;
        !           655: 
        !           656:   if (dyn)
        !           657:     sprintf ((char *)id, "%.14s", dyn->name.name);
        !           658:   else if (!memcmp (isis->sysid, lsp_id, ISIS_SYS_ID_LEN) & dynhost)
        !           659:     sprintf ((char *)id, "%.14s", unix_hostname ());
        !           660:   else
        !           661:     {
        !           662:       memcpy (id, sysid_print (lsp_id), 15);
        !           663:     }
        !           664:   if (frag)
        !           665:     sprintf ((char *)trg, "%s.%02x-%02x", id, LSP_PSEUDO_ID (lsp_id),
        !           666:             LSP_FRAGMENT (lsp_id));
        !           667:   else
        !           668:     sprintf ((char *)trg, "%s.%02x", id, LSP_PSEUDO_ID (lsp_id));
        !           669: }
        !           670: 
        !           671: /* Convert the lsp attribute bits to attribute string */
        !           672: const char *
        !           673: lsp_bits2string (u_char * lsp_bits)
        !           674: {
        !           675:   char *pos = lsp_bits_string;
        !           676: 
        !           677:   if (!*lsp_bits)
        !           678:     return " none";
        !           679: 
        !           680:   /* we only focus on the default metric */
        !           681:   pos += sprintf (pos, "%d/",
        !           682:                  ISIS_MASK_LSP_ATT_DEFAULT_BIT (*lsp_bits) ? 1 : 0);
        !           683: 
        !           684:   pos += sprintf (pos, "%d/",
        !           685:                  ISIS_MASK_LSP_PARTITION_BIT (*lsp_bits) ? 1 : 0);
        !           686: 
        !           687:   pos += sprintf (pos, "%d", ISIS_MASK_LSP_OL_BIT (*lsp_bits) ? 1 : 0);
        !           688: 
        !           689:   *(pos) = '\0';
        !           690: 
        !           691:   return lsp_bits_string;
        !           692: }
        !           693: 
        !           694: /* this function prints the lsp on show isis database */
        !           695: static void
        !           696: lsp_print (dnode_t * node, struct vty *vty, char dynhost)
        !           697: {
        !           698:   struct isis_lsp *lsp = dnode_get (node);
        !           699:   u_char LSPid[255];
        !           700: 
        !           701:   lspid_print (lsp->lsp_header->lsp_id, LSPid, dynhost, 1);
        !           702:   vty_out (vty, "%-21s%c   ", LSPid, lsp->own_lsp ? '*' : ' ');
        !           703:   vty_out (vty, "0x%08x   ", ntohl (lsp->lsp_header->seq_num));
        !           704:   vty_out (vty, "0x%04x      ", ntohs (lsp->lsp_header->checksum));
        !           705: 
        !           706:   if (ntohs (lsp->lsp_header->rem_lifetime) == 0)
        !           707:     vty_out (vty, " (%2u)", lsp->age_out);
        !           708:   else
        !           709:     vty_out (vty, "%5u", ntohs (lsp->lsp_header->rem_lifetime));
        !           710: 
        !           711:   vty_out (vty, "         %s%s",
        !           712:           lsp_bits2string (&lsp->lsp_header->lsp_bits), VTY_NEWLINE);
        !           713: }
        !           714: 
        !           715: static void
        !           716: lsp_print_detail (dnode_t * node, struct vty *vty, char dynhost)
        !           717: {
        !           718:   struct isis_lsp *lsp = dnode_get (node);
        !           719:   struct area_addr *area_addr;
        !           720:   int i;
        !           721:   struct listnode *lnode;
        !           722:   struct is_neigh *is_neigh;
        !           723:   struct te_is_neigh *te_is_neigh;
        !           724:   struct ipv4_reachability *ipv4_reach;
        !           725:   struct in_addr *ipv4_addr;
        !           726:   struct te_ipv4_reachability *te_ipv4_reach;
        !           727: #ifdef HAVE_IPV6
        !           728:   struct ipv6_reachability *ipv6_reach;
        !           729:   struct in6_addr in6;
        !           730:   u_char buff[BUFSIZ];
        !           731: #endif
        !           732:   u_char LSPid[255];
        !           733:   u_char hostname[255];
        !           734:   u_char ipv4_reach_prefix[20];
        !           735:   u_char ipv4_reach_mask[20];
        !           736:   u_char ipv4_address[20];
        !           737: 
        !           738:   lspid_print (lsp->lsp_header->lsp_id, LSPid, dynhost, 1);
        !           739:   lsp_print (node, vty, dynhost);
        !           740: 
        !           741:   /* for all area address */
        !           742:   if (lsp->tlv_data.area_addrs)
        !           743:     for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.area_addrs, lnode, area_addr))
        !           744:       {
        !           745:        vty_out (vty, "  Area Address: %s%s",
        !           746:                 isonet_print (area_addr->area_addr, area_addr->addr_len),
        !           747:                 VTY_NEWLINE);
        !           748:       }
        !           749:   
        !           750:   /* for the nlpid tlv */
        !           751:   if (lsp->tlv_data.nlpids)
        !           752:     {
        !           753:       for (i = 0; i < lsp->tlv_data.nlpids->count; i++)
        !           754:        {
        !           755:          switch (lsp->tlv_data.nlpids->nlpids[i])
        !           756:            {
        !           757:            case NLPID_IP:
        !           758:            case NLPID_IPV6:
        !           759:              vty_out (vty, "  NLPID:        0x%X%s",
        !           760:                       lsp->tlv_data.nlpids->nlpids[i], VTY_NEWLINE);
        !           761:              break;
        !           762:            default:
        !           763:              vty_out (vty, "  NLPID:        %s%s", "unknown", VTY_NEWLINE);
        !           764:              break;
        !           765:            }
        !           766:        }
        !           767:     }
        !           768: 
        !           769:   /* for the hostname tlv */
        !           770:   if (lsp->tlv_data.hostname)
        !           771:     {
        !           772:       memset (hostname, 0, sizeof (hostname));
        !           773:       memcpy (hostname, lsp->tlv_data.hostname->name,
        !           774:              lsp->tlv_data.hostname->namelen);
        !           775:       vty_out (vty, "  Hostname: %s%s", hostname, VTY_NEWLINE);
        !           776:     }
        !           777: 
        !           778:   if (lsp->tlv_data.ipv4_addrs)
        !           779:     for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_addrs, lnode, ipv4_addr))
        !           780:       {
        !           781:        memcpy (ipv4_address, inet_ntoa (*ipv4_addr), sizeof (ipv4_address));
        !           782:        vty_out (vty, "  IP:        %s%s", ipv4_address, VTY_NEWLINE);
        !           783:       }
        !           784: 
        !           785:   /* TE router id */
        !           786:   if (lsp->tlv_data.router_id)
        !           787:     {
        !           788:       memcpy (ipv4_address, inet_ntoa (lsp->tlv_data.router_id->id),
        !           789:              sizeof (ipv4_address));
        !           790:       vty_out (vty, "  Router ID: %s%s", ipv4_address, VTY_NEWLINE);
        !           791:     }
        !           792: 
        !           793:   /* for the IS neighbor tlv */
        !           794:   if (lsp->tlv_data.is_neighs)
        !           795:     for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, lnode, is_neigh))
        !           796:       {
        !           797:        lspid_print (is_neigh->neigh_id, LSPid, dynhost, 0);
        !           798:        vty_out (vty, "  Metric: %-10d IS %s%s",
        !           799:                 is_neigh->metrics.metric_default, LSPid, VTY_NEWLINE);
        !           800:       }
        !           801:   
        !           802:   /* for the internal reachable tlv */
        !           803:   if (lsp->tlv_data.ipv4_int_reachs)
        !           804:     for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_int_reachs, lnode,
        !           805:                               ipv4_reach))
        !           806:     {
        !           807:       memcpy (ipv4_reach_prefix, inet_ntoa (ipv4_reach->prefix),
        !           808:              sizeof (ipv4_reach_prefix));
        !           809:       memcpy (ipv4_reach_mask, inet_ntoa (ipv4_reach->mask),
        !           810:              sizeof (ipv4_reach_mask));
        !           811:       vty_out (vty, "  Metric: %-10d IP-Internal %s %s%s",
        !           812:               ipv4_reach->metrics.metric_default, ipv4_reach_prefix,
        !           813:               ipv4_reach_mask, VTY_NEWLINE);
        !           814:     }
        !           815: 
        !           816:   /* for the external reachable tlv */
        !           817:   if (lsp->tlv_data.ipv4_ext_reachs)
        !           818:     for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_ext_reachs, lnode, 
        !           819:                               ipv4_reach))
        !           820:     {
        !           821:       memcpy (ipv4_reach_prefix, inet_ntoa (ipv4_reach->prefix),
        !           822:              sizeof (ipv4_reach_prefix));
        !           823:       memcpy (ipv4_reach_mask, inet_ntoa (ipv4_reach->mask),
        !           824:              sizeof (ipv4_reach_mask));
        !           825:       vty_out (vty, "  Metric: %-10d IP-External %s %s%s",
        !           826:               ipv4_reach->metrics.metric_default, ipv4_reach_prefix,
        !           827:               ipv4_reach_mask, VTY_NEWLINE);
        !           828:     }
        !           829:   
        !           830:   /* IPv6 tlv */
        !           831: #ifdef HAVE_IPV6
        !           832:   if (lsp->tlv_data.ipv6_reachs)
        !           833:     for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs, lnode, ipv6_reach))
        !           834:     {
        !           835:       memset (&in6, 0, sizeof (in6));
        !           836:       memcpy (in6.s6_addr, ipv6_reach->prefix,
        !           837:              PSIZE (ipv6_reach->prefix_len));
        !           838:       inet_ntop (AF_INET6, &in6, (char *)buff, BUFSIZ);
        !           839:       if ((ipv6_reach->control_info &&
        !           840:           CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL)
        !           841:        vty_out (vty, "  Metric: %-10d IPv6-Internal %s/%d%s",
        !           842:                 ntohl (ipv6_reach->metric),
        !           843:                 buff, ipv6_reach->prefix_len, VTY_NEWLINE);
        !           844:       else
        !           845:        vty_out (vty, "  Metric: %-10d IPv6-External %s/%d%s",
        !           846:                 ntohl (ipv6_reach->metric),
        !           847:                 buff, ipv6_reach->prefix_len, VTY_NEWLINE);
        !           848:     }
        !           849: #endif
        !           850: 
        !           851:   /* TE IS neighbor tlv */
        !           852:   if (lsp->tlv_data.te_is_neighs)
        !           853:     for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, lnode, te_is_neigh))
        !           854:     {
        !           855:       uint32_t metric;
        !           856:       memcpy (&metric, te_is_neigh->te_metric, 3);
        !           857:       lspid_print (te_is_neigh->neigh_id, LSPid, dynhost, 0);
        !           858:       vty_out (vty, "  Metric: %-10d IS-Extended %s%s",
        !           859:               ntohl (metric << 8), LSPid, VTY_NEWLINE);
        !           860:     }
        !           861: 
        !           862:   /* TE IPv4 tlv */
        !           863:   if (lsp->tlv_data.te_ipv4_reachs)
        !           864:     for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs, lnode,
        !           865:                               te_ipv4_reach))
        !           866:     {
        !           867:       /* FIXME: There should be better way to output this stuff. */
        !           868:       vty_out (vty, "  Metric: %-10d IP-Extended %s/%d%s",
        !           869:               ntohl (te_ipv4_reach->te_metric),
        !           870:               inet_ntoa (newprefix2inaddr (&te_ipv4_reach->prefix_start,
        !           871:                                            te_ipv4_reach->control)),
        !           872:               te_ipv4_reach->control & 0x3F, VTY_NEWLINE);
        !           873:     }
        !           874: 
        !           875:   return;
        !           876: }
        !           877: 
        !           878: /* print all the lsps info in the local lspdb */
        !           879: int
        !           880: lsp_print_all (struct vty *vty, dict_t * lspdb, char detail, char dynhost)
        !           881: {
        !           882: 
        !           883:   dnode_t *node = dict_first (lspdb), *next;
        !           884:   int lsp_count = 0;
        !           885: 
        !           886:   /* print the title, for both modes */
        !           887:   vty_out (vty, "LSP ID                   LSP Seq Num  LSP Checksum "
        !           888:           "LSP Holdtime ATT/P/OL%s", VTY_NEWLINE);
        !           889: 
        !           890:   if (detail == ISIS_UI_LEVEL_BRIEF)
        !           891:     {
        !           892:       while (node != NULL)
        !           893:        {
        !           894:          /* I think it is unnecessary, so I comment it out */
        !           895:          /* dict_contains (lspdb, node); */
        !           896:          next = dict_next (lspdb, node);
        !           897:          lsp_print (node, vty, dynhost);
        !           898:          node = next;
        !           899:          lsp_count++;
        !           900:        }
        !           901:     }
        !           902:   else if (detail == ISIS_UI_LEVEL_DETAIL)
        !           903:     {
        !           904:       while (node != NULL)
        !           905:        {
        !           906:          next = dict_next (lspdb, node);
        !           907:          lsp_print_detail (node, vty, dynhost);
        !           908:          node = next;
        !           909:          lsp_count++;
        !           910:        }
        !           911:     }
        !           912: 
        !           913:   return lsp_count;
        !           914: }
        !           915: 
        !           916: #define FRAG_THOLD(S,T) \
        !           917: ((STREAM_SIZE(S)*T)/100)
        !           918: 
        !           919: /* stream*, area->lsp_frag_threshold, increment */
        !           920: #define FRAG_NEEDED(S,T,I) \
        !           921:   (STREAM_SIZE(S)-STREAM_REMAIN(S)+(I) > FRAG_THOLD(S,T))
        !           922: 
        !           923: /* FIXME: It shouldn't be necessary to pass tlvsize here, TLVs can have
        !           924:  * variable length (TE TLVs, sub TLVs). */
        !           925: static void
        !           926: lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to,
        !           927:             int tlvsize, int frag_thold,
        !           928:             int tlv_build_func (struct list *, struct stream *))
        !           929: {
        !           930:   int count, i;
        !           931: 
        !           932:   /* can we fit all ? */
        !           933:   if (!FRAG_NEEDED (lsp->pdu, frag_thold, listcount (*from) * tlvsize + 2))
        !           934:     {
        !           935:       tlv_build_func (*from, lsp->pdu);
        !           936:       *to = *from;
        !           937:       *from = NULL;
        !           938:     }
        !           939:   else if (!FRAG_NEEDED (lsp->pdu, frag_thold, tlvsize + 2))
        !           940:     {
        !           941:       /* fit all we can */
        !           942:       count = FRAG_THOLD (lsp->pdu, frag_thold) - 2 -
        !           943:        (STREAM_SIZE (lsp->pdu) - STREAM_REMAIN (lsp->pdu));
        !           944:       if (count)
        !           945:        count = count / tlvsize;
        !           946:       for (i = 0; i < count; i++)
        !           947:        {
        !           948:          listnode_add (*to, listgetdata (listhead (*from)));
        !           949:          listnode_delete (*from, listgetdata (listhead (*from)));
        !           950:        }
        !           951:       tlv_build_func (*to, lsp->pdu);
        !           952:     }
        !           953:   lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
        !           954:   return;
        !           955: }
        !           956: 
        !           957: static struct isis_lsp *
        !           958: lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, struct isis_area *area,
        !           959:               int level)
        !           960: {
        !           961:   struct isis_lsp *lsp;
        !           962:   u_char frag_id[ISIS_SYS_ID_LEN + 2];
        !           963: 
        !           964:   memcpy (frag_id, lsp0->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 1);
        !           965:   LSP_FRAGMENT (frag_id) = frag_num;
        !           966:   lsp = lsp_search (frag_id, area->lspdb[level - 1]);
        !           967:   if (lsp)
        !           968:     {
        !           969:       /*
        !           970:        * Clear the TLVs, but inherit the authinfo
        !           971:        */
        !           972:       lsp_clear_data (lsp);
        !           973:       if (lsp0->tlv_data.auth_info.type)
        !           974:        {
        !           975:          memcpy (&lsp->tlv_data.auth_info, &lsp->tlv_data.auth_info,
        !           976:                  sizeof (struct isis_passwd));
        !           977:          tlv_add_authinfo (lsp->tlv_data.auth_info.type,
        !           978:                            lsp->tlv_data.auth_info.len,
        !           979:                            lsp->tlv_data.auth_info.passwd, lsp->pdu);
        !           980:        }
        !           981:       return lsp;
        !           982:     }
        !           983:   lsp = lsp_new (frag_id, area->max_lsp_lifetime[level - 1], 0, area->is_type,
        !           984:                 0, level);
        !           985:   lsp->own_lsp = 1;
        !           986:   lsp_insert (lsp, area->lspdb[level - 1]);
        !           987:   listnode_add (lsp0->lspu.frags, lsp);
        !           988:   lsp->lspu.zero_lsp = lsp0;
        !           989:   /*
        !           990:    * Copy the authinfo from zero LSP
        !           991:    */
        !           992:   if (lsp0->tlv_data.auth_info.type)
        !           993:     {
        !           994:       memcpy (&lsp->tlv_data.auth_info, &lsp->tlv_data.auth_info,
        !           995:              sizeof (struct isis_passwd));
        !           996:       tlv_add_authinfo (lsp->tlv_data.auth_info.type,
        !           997:                        lsp->tlv_data.auth_info.len,
        !           998:                        lsp->tlv_data.auth_info.passwd, lsp->pdu);
        !           999:     }
        !          1000:   return lsp;
        !          1001: }
        !          1002: 
        !          1003: /*
        !          1004:  * Builds the LSP data part. This func creates a new frag whenever 
        !          1005:  * area->lsp_frag_threshold is exceeded.
        !          1006:  */
        !          1007: static void
        !          1008: lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)
        !          1009: {
        !          1010:   struct is_neigh *is_neigh;
        !          1011:   struct te_is_neigh *te_is_neigh;
        !          1012:   struct listnode *node, *ipnode;
        !          1013:   int level = lsp->level;
        !          1014:   struct isis_circuit *circuit;
        !          1015:   struct prefix_ipv4 *ipv4;
        !          1016:   struct ipv4_reachability *ipreach;
        !          1017:   struct te_ipv4_reachability *te_ipreach;
        !          1018:   struct isis_adjacency *nei;
        !          1019: #ifdef HAVE_IPV6
        !          1020:   struct prefix_ipv6 *ipv6, *ip6prefix;
        !          1021:   struct ipv6_reachability *ip6reach;
        !          1022: #endif /* HAVE_IPV6 */
        !          1023:   struct tlvs tlv_data;
        !          1024:   struct isis_lsp *lsp0 = lsp;
        !          1025:   struct isis_passwd *passwd;
        !          1026:   struct in_addr *routerid;
        !          1027: 
        !          1028:   /*
        !          1029:    * First add the tlvs related to area
        !          1030:    */
        !          1031: 
        !          1032:   /* Area addresses */
        !          1033:   if (lsp->tlv_data.area_addrs == NULL)
        !          1034:     lsp->tlv_data.area_addrs = list_new ();
        !          1035:   list_add_list (lsp->tlv_data.area_addrs, area->area_addrs);
        !          1036:   /* Protocols Supported */
        !          1037:   if (area->ip_circuits > 0
        !          1038: #ifdef HAVE_IPV6
        !          1039:       || area->ipv6_circuits > 0
        !          1040: #endif /* HAVE_IPV6 */
        !          1041:     )
        !          1042:     {
        !          1043:       lsp->tlv_data.nlpids = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct nlpids));
        !          1044:       lsp->tlv_data.nlpids->count = 0;
        !          1045:       if (area->ip_circuits > 0)
        !          1046:        {
        !          1047:          lsp->tlv_data.nlpids->count++;
        !          1048:          lsp->tlv_data.nlpids->nlpids[0] = NLPID_IP;
        !          1049:        }
        !          1050: #ifdef HAVE_IPV6
        !          1051:       if (area->ipv6_circuits > 0)
        !          1052:        {
        !          1053:          lsp->tlv_data.nlpids->count++;
        !          1054:          lsp->tlv_data.nlpids->nlpids[lsp->tlv_data.nlpids->count - 1] =
        !          1055:            NLPID_IPV6;
        !          1056:        }
        !          1057: #endif /* HAVE_IPV6 */
        !          1058:     }
        !          1059:   /* Dynamic Hostname */
        !          1060:   if (area->dynhostname)
        !          1061:     {
        !          1062:       lsp->tlv_data.hostname = XMALLOC (MTYPE_ISIS_TLV,
        !          1063:                                        sizeof (struct hostname));
        !          1064: 
        !          1065:       memcpy (lsp->tlv_data.hostname->name, unix_hostname (),
        !          1066:              strlen (unix_hostname ()));
        !          1067:       lsp->tlv_data.hostname->namelen = strlen (unix_hostname ());
        !          1068:     }
        !          1069: 
        !          1070:   /*
        !          1071:    * Building the zero lsp
        !          1072:    */
        !          1073: 
        !          1074:   /* Reset stream endp. Stream is always there and on every LSP refresh only
        !          1075:    * TLV part of it is overwritten. So we must seek past header we will not
        !          1076:    * touch. */
        !          1077:   stream_reset (lsp->pdu);
        !          1078:   stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
        !          1079: 
        !          1080:   /*
        !          1081:    * Add the authentication info if its present
        !          1082:    */
        !          1083:   (level == 1) ? (passwd = &area->area_passwd) :
        !          1084:     (passwd = &area->domain_passwd);
        !          1085:   if (passwd->type)
        !          1086:     {
        !          1087:       memcpy (&lsp->tlv_data.auth_info, passwd, sizeof (struct isis_passwd));
        !          1088:       tlv_add_authinfo (passwd->type, passwd->len, passwd->passwd, lsp->pdu);
        !          1089:     }
        !          1090:   if (lsp->tlv_data.nlpids)
        !          1091:     tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu);
        !          1092:   if (lsp->tlv_data.hostname)
        !          1093:     tlv_add_dynamic_hostname (lsp->tlv_data.hostname, lsp->pdu);
        !          1094:   if (lsp->tlv_data.area_addrs && listcount (lsp->tlv_data.area_addrs) > 0)
        !          1095:     tlv_add_area_addrs (lsp->tlv_data.area_addrs, lsp->pdu);
        !          1096: 
        !          1097:   /* IPv4 address and TE router ID TLVs. In case of the first one we don't
        !          1098:    * follow "C" vendor, but "J" vendor behavior - one IPv4 address is put into
        !          1099:    * LSP and this address is same as router id. */
        !          1100:   if (router_id_zebra.s_addr != 0)
        !          1101:     {
        !          1102:       if (lsp->tlv_data.ipv4_addrs == NULL)
        !          1103:        {
        !          1104:          lsp->tlv_data.ipv4_addrs = list_new ();
        !          1105:          lsp->tlv_data.ipv4_addrs->del = free_tlv;
        !          1106:        }
        !          1107: 
        !          1108:       routerid = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct in_addr));
        !          1109:       routerid->s_addr = router_id_zebra.s_addr;
        !          1110:       listnode_add (lsp->tlv_data.ipv4_addrs, routerid);
        !          1111:       tlv_add_in_addr (routerid, lsp->pdu, IPV4_ADDR);
        !          1112: 
        !          1113:       /* Exactly same data is put into TE router ID TLV, but only if new style
        !          1114:        * TLV's are in use. */
        !          1115:       if (area->newmetric)
        !          1116:        {
        !          1117:          lsp->tlv_data.router_id = XMALLOC (MTYPE_ISIS_TLV,
        !          1118:                                             sizeof (struct in_addr));
        !          1119:          lsp->tlv_data.router_id->id.s_addr = router_id_zebra.s_addr;
        !          1120:          tlv_add_in_addr (&lsp->tlv_data.router_id->id, lsp->pdu, TE_ROUTER_ID);
        !          1121:        }
        !          1122:     }
        !          1123: 
        !          1124:   memset (&tlv_data, 0, sizeof (struct tlvs));
        !          1125: 
        !          1126: #ifdef TOPOLOGY_GENERATE
        !          1127:   /* If topology exists (and we create topology for level 1 only), create
        !          1128:    * (hardcoded) link to topology. */
        !          1129:   if (area->topology && level == 1)
        !          1130:     {
        !          1131:       if (tlv_data.is_neighs == NULL)
        !          1132:        {
        !          1133:          tlv_data.is_neighs = list_new ();
        !          1134:          tlv_data.is_neighs->del = free_tlv;
        !          1135:        }
        !          1136:       is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
        !          1137: 
        !          1138:       memcpy (&is_neigh->neigh_id, area->topology_baseis, ISIS_SYS_ID_LEN);
        !          1139:       is_neigh->neigh_id[ISIS_SYS_ID_LEN - 1] = (1 & 0xFF);
        !          1140:       is_neigh->neigh_id[ISIS_SYS_ID_LEN - 2] = ((1 >> 8) & 0xFF);
        !          1141:       is_neigh->metrics.metric_default = 0x01;
        !          1142:       is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED;
        !          1143:       is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED;
        !          1144:       is_neigh->metrics.metric_error = METRICS_UNSUPPORTED;
        !          1145:       listnode_add (tlv_data.is_neighs, is_neigh);
        !          1146:     }
        !          1147: #endif /* TOPOLOGY_GENERATE */
        !          1148: 
        !          1149:   /*
        !          1150:    * Then build lists of tlvs related to circuits
        !          1151:    */
        !          1152:   for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit))
        !          1153:     {
        !          1154:       if (circuit->state != C_STATE_UP)
        !          1155:        continue;
        !          1156: 
        !          1157:       /*
        !          1158:        * Add IPv4 internal reachability of this circuit
        !          1159:        */
        !          1160:       if (circuit->ip_router && circuit->ip_addrs &&
        !          1161:          circuit->ip_addrs->count > 0)
        !          1162:        {
        !          1163:          if (area->oldmetric)
        !          1164:            {
        !          1165:              if (tlv_data.ipv4_int_reachs == NULL)
        !          1166:                {
        !          1167:                  tlv_data.ipv4_int_reachs = list_new ();
        !          1168:                  tlv_data.ipv4_int_reachs->del = free_tlv;
        !          1169:                }
        !          1170:              for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, ipnode, ipv4))
        !          1171:                {
        !          1172:                  ipreach =
        !          1173:                    XMALLOC (MTYPE_ISIS_TLV, sizeof (struct ipv4_reachability));
        !          1174:                  ipreach->metrics = circuit->metrics[level - 1];
        !          1175:                  masklen2ip (ipv4->prefixlen, &ipreach->mask);
        !          1176:                  ipreach->prefix.s_addr = ((ipreach->mask.s_addr) &
        !          1177:                                            (ipv4->prefix.s_addr));
        !          1178:                  listnode_add (tlv_data.ipv4_int_reachs, ipreach);
        !          1179:                }
        !          1180:              tlv_data.ipv4_int_reachs->del = free_tlv;
        !          1181:            }
        !          1182:          if (area->newmetric)
        !          1183:            {
        !          1184:              if (tlv_data.te_ipv4_reachs == NULL)
        !          1185:                {
        !          1186:                  tlv_data.te_ipv4_reachs = list_new ();
        !          1187:                  tlv_data.te_ipv4_reachs->del = free_tlv;
        !          1188:                }
        !          1189:              for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, ipnode, ipv4))
        !          1190:                {
        !          1191:                  /* FIXME All this assumes that we have no sub TLVs. */
        !          1192:                  te_ipreach = XCALLOC (MTYPE_ISIS_TLV,
        !          1193:                                        sizeof (struct te_ipv4_reachability) +
        !          1194:                                        ((ipv4->prefixlen + 7)/8) - 1);
        !          1195: 
        !          1196:                  if (area->oldmetric)
        !          1197:                    te_ipreach->te_metric = htonl (circuit->metrics[level - 1].metric_default);
        !          1198:                  else
        !          1199:                    te_ipreach->te_metric = htonl (circuit->te_metric[level - 1]);
        !          1200: 
        !          1201:                  te_ipreach->control = (ipv4->prefixlen & 0x3F);
        !          1202:                  memcpy (&te_ipreach->prefix_start, &ipv4->prefix.s_addr,
        !          1203:                          (ipv4->prefixlen + 7)/8);
        !          1204:                  listnode_add (tlv_data.te_ipv4_reachs, te_ipreach);
        !          1205:                }
        !          1206:            }
        !          1207:        }
        !          1208: #ifdef HAVE_IPV6
        !          1209:       /*
        !          1210:        * Add IPv6 reachability of this circuit
        !          1211:        */
        !          1212:       if (circuit->ipv6_router && circuit->ipv6_non_link &&
        !          1213:          circuit->ipv6_non_link->count > 0)
        !          1214:        {
        !          1215: 
        !          1216:          if (tlv_data.ipv6_reachs == NULL)
        !          1217:            {
        !          1218:              tlv_data.ipv6_reachs = list_new ();
        !          1219:              tlv_data.ipv6_reachs->del = free_tlv;
        !          1220:            }
        !          1221:           for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, ipnode, ipv6))
        !          1222:            {
        !          1223:              ip6reach =
        !          1224:                XCALLOC (MTYPE_ISIS_TLV, sizeof (struct ipv6_reachability));
        !          1225: 
        !          1226:              if (area->oldmetric)
        !          1227:                ip6reach->metric =
        !          1228:                          htonl (circuit->metrics[level - 1].metric_default);
        !          1229:              else
        !          1230:                  ip6reach->metric = htonl (circuit->te_metric[level - 1]);
        !          1231: 
        !          1232:              ip6reach->control_info = 0;
        !          1233:              ip6reach->prefix_len = ipv6->prefixlen;
        !          1234:              memcpy (&ip6prefix, &ipv6, sizeof(ip6prefix));
        !          1235:              apply_mask_ipv6 (ip6prefix);
        !          1236:              memcpy (ip6reach->prefix, ip6prefix->prefix.s6_addr,
        !          1237:                      sizeof (ip6reach->prefix));
        !          1238:              listnode_add (tlv_data.ipv6_reachs, ip6reach);
        !          1239:            }
        !          1240:        }
        !          1241: #endif /* HAVE_IPV6 */
        !          1242: 
        !          1243:       switch (circuit->circ_type)
        !          1244:        {
        !          1245:        case CIRCUIT_T_BROADCAST:
        !          1246:          if (level & circuit->circuit_is_type)
        !          1247:            {
        !          1248:              if (area->oldmetric)
        !          1249:                {
        !          1250:                  if (tlv_data.is_neighs == NULL)
        !          1251:                    {
        !          1252:                      tlv_data.is_neighs = list_new ();
        !          1253:                      tlv_data.is_neighs->del = free_tlv;
        !          1254:                    }
        !          1255:                  is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
        !          1256:                  if (level == 1)
        !          1257:                    memcpy (is_neigh->neigh_id,
        !          1258:                            circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
        !          1259:                  else
        !          1260:                    memcpy (is_neigh->neigh_id,
        !          1261:                            circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
        !          1262:                  is_neigh->metrics = circuit->metrics[level - 1];
        !          1263:                  listnode_add (tlv_data.is_neighs, is_neigh);
        !          1264:                  tlv_data.is_neighs->del = free_tlv;
        !          1265:                }
        !          1266:              if (area->newmetric)
        !          1267:                {
        !          1268:                  uint32_t metric;
        !          1269: 
        !          1270:                  if (tlv_data.te_is_neighs == NULL)
        !          1271:                    {
        !          1272:                      tlv_data.te_is_neighs = list_new ();
        !          1273:                      tlv_data.te_is_neighs->del = free_tlv;
        !          1274:                    }
        !          1275:                  te_is_neigh = XCALLOC (MTYPE_ISIS_TLV,
        !          1276:                                         sizeof (struct te_is_neigh));
        !          1277:                  if (level == 1)
        !          1278:                    memcpy (te_is_neigh->neigh_id,
        !          1279:                            circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
        !          1280:                  else
        !          1281:                    memcpy (te_is_neigh->neigh_id,
        !          1282:                            circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
        !          1283:                  if (area->oldmetric)
        !          1284:                    metric =
        !          1285:                      ((htonl(circuit->metrics[level - 1].metric_default) >> 8)
        !          1286:                              & 0xffffff);
        !          1287:                  else
        !          1288:                    metric = ((htonl(*circuit->te_metric) >> 8) & 0xffffff);
        !          1289: 
        !          1290:                  memcpy (te_is_neigh->te_metric, &metric, 3);
        !          1291:                  listnode_add (tlv_data.te_is_neighs, te_is_neigh);
        !          1292:                }
        !          1293:            }
        !          1294:          break;
        !          1295:        case CIRCUIT_T_P2P:
        !          1296:          nei = circuit->u.p2p.neighbor;
        !          1297:          if (nei && (level & nei->circuit_t))
        !          1298:            {
        !          1299:              if (area->oldmetric)
        !          1300:                {
        !          1301:                  if (tlv_data.is_neighs == NULL)
        !          1302:                    {
        !          1303:                      tlv_data.is_neighs = list_new ();
        !          1304:                      tlv_data.is_neighs->del = free_tlv;
        !          1305:                    }
        !          1306:                  is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
        !          1307:                  memcpy (is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN);
        !          1308:                  is_neigh->metrics = circuit->metrics[level - 1];
        !          1309:                  listnode_add (tlv_data.is_neighs, is_neigh);
        !          1310:                }
        !          1311:              if (area->newmetric)
        !          1312:                {
        !          1313:                  uint32_t metric;
        !          1314: 
        !          1315:                  if (tlv_data.te_is_neighs == NULL)
        !          1316:                    {
        !          1317:                      tlv_data.te_is_neighs = list_new ();
        !          1318:                      tlv_data.te_is_neighs->del = free_tlv;
        !          1319:                    }
        !          1320:                  te_is_neigh = XCALLOC (MTYPE_ISIS_TLV,
        !          1321:                                         sizeof (struct te_is_neigh));
        !          1322:                  memcpy (te_is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN);
        !          1323:                  metric = ((htonl(*circuit->te_metric) >> 8) & 0xffffff);
        !          1324:                  memcpy (te_is_neigh->te_metric, &metric, 3);
        !          1325:                  listnode_add (tlv_data.te_is_neighs, te_is_neigh);
        !          1326:                }
        !          1327:            }
        !          1328:          break;
        !          1329:        case CIRCUIT_T_STATIC_IN:
        !          1330:          zlog_warn ("lsp_area_create: unsupported circuit type");
        !          1331:          break;
        !          1332:        case CIRCUIT_T_STATIC_OUT:
        !          1333:          zlog_warn ("lsp_area_create: unsupported circuit type");
        !          1334:          break;
        !          1335:        case CIRCUIT_T_DA:
        !          1336:          zlog_warn ("lsp_area_create: unsupported circuit type");
        !          1337:          break;
        !          1338:        default:
        !          1339:          zlog_warn ("lsp_area_create: unknown circuit type");
        !          1340:        }
        !          1341:     }
        !          1342: 
        !          1343:   while (tlv_data.ipv4_int_reachs && listcount (tlv_data.ipv4_int_reachs))
        !          1344:     {
        !          1345:       if (lsp->tlv_data.ipv4_int_reachs == NULL)
        !          1346:        lsp->tlv_data.ipv4_int_reachs = list_new ();
        !          1347:       lsp_tlv_fit (lsp, &tlv_data.ipv4_int_reachs,
        !          1348:                   &lsp->tlv_data.ipv4_int_reachs,
        !          1349:                   IPV4_REACH_LEN, area->lsp_frag_threshold,
        !          1350:                   tlv_add_ipv4_reachs);
        !          1351:       if (tlv_data.ipv4_int_reachs && listcount (tlv_data.ipv4_int_reachs))
        !          1352:        lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
        !          1353:                             lsp0, area, level);
        !          1354:     }
        !          1355:   /* FIXME: We pass maximum te_ipv4_reachability length to the lsp_tlv_fit()
        !          1356:    * for now. lsp_tlv_fit() needs to be fixed to deal with variable length
        !          1357:    * TLVs (sub TLVs!). */
        !          1358:   while (tlv_data.te_ipv4_reachs && listcount (tlv_data.te_ipv4_reachs))
        !          1359:     {
        !          1360:       if (lsp->tlv_data.te_ipv4_reachs == NULL)
        !          1361:        lsp->tlv_data.te_ipv4_reachs = list_new ();
        !          1362:       lsp_tlv_fit (lsp, &tlv_data.te_ipv4_reachs,
        !          1363:                   &lsp->tlv_data.te_ipv4_reachs,
        !          1364:                   9, area->lsp_frag_threshold, tlv_add_te_ipv4_reachs);
        !          1365:       if (tlv_data.te_ipv4_reachs && listcount (tlv_data.te_ipv4_reachs))
        !          1366:        lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
        !          1367:                             lsp0, area, level);
        !          1368:     }
        !          1369: 
        !          1370: #ifdef  HAVE_IPV6
        !          1371:   while (tlv_data.ipv6_reachs && listcount (tlv_data.ipv6_reachs))
        !          1372:     {
        !          1373:       if (lsp->tlv_data.ipv6_reachs == NULL)
        !          1374:        lsp->tlv_data.ipv6_reachs = list_new ();
        !          1375:       lsp_tlv_fit (lsp, &tlv_data.ipv6_reachs,
        !          1376:                   &lsp->tlv_data.ipv6_reachs,
        !          1377:                   IPV6_REACH_LEN, area->lsp_frag_threshold,
        !          1378:                   tlv_add_ipv6_reachs);
        !          1379:       if (tlv_data.ipv6_reachs && listcount (tlv_data.ipv6_reachs))
        !          1380:        lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
        !          1381:                             lsp0, area, level);
        !          1382:     }
        !          1383: #endif /* HAVE_IPV6 */
        !          1384: 
        !          1385:   while (tlv_data.is_neighs && listcount (tlv_data.is_neighs))
        !          1386:     {
        !          1387:       if (lsp->tlv_data.is_neighs == NULL)
        !          1388:        lsp->tlv_data.is_neighs = list_new ();
        !          1389:       lsp_tlv_fit (lsp, &tlv_data.is_neighs,
        !          1390:                   &lsp->tlv_data.is_neighs,
        !          1391:                   IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
        !          1392:                   tlv_add_is_neighs);
        !          1393:       if (tlv_data.is_neighs && listcount (tlv_data.is_neighs))
        !          1394:        lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
        !          1395:                             lsp0, area, level);
        !          1396:     }
        !          1397: 
        !          1398:   while (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs))
        !          1399:     {
        !          1400:       if (lsp->tlv_data.te_is_neighs == NULL)
        !          1401:        lsp->tlv_data.te_is_neighs = list_new ();
        !          1402:       lsp_tlv_fit (lsp, &tlv_data.te_is_neighs, &lsp->tlv_data.te_is_neighs,
        !          1403:                   IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
        !          1404:                   tlv_add_te_is_neighs);
        !          1405:       if (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs))
        !          1406:        lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
        !          1407:                             lsp0, area, level);
        !          1408:     }
        !          1409: 
        !          1410:   free_tlvs (&tlv_data);
        !          1411:   return;
        !          1412: }
        !          1413: 
        !          1414: /*
        !          1415:  * 7.3.7 Generation on non-pseudonode LSPs
        !          1416:  */
        !          1417: static int
        !          1418: lsp_generate_non_pseudo (struct isis_area *area, int level)
        !          1419: {
        !          1420:   struct isis_lsp *oldlsp, *newlsp;
        !          1421:   u_int32_t seq_num = 0;
        !          1422:   u_char lspid[ISIS_SYS_ID_LEN + 2];
        !          1423: 
        !          1424:   memset (&lspid, 0, ISIS_SYS_ID_LEN + 2);
        !          1425:   memcpy (&lspid, isis->sysid, ISIS_SYS_ID_LEN);
        !          1426: 
        !          1427:   /* only builds the lsp if the area shares the level */
        !          1428:   if ((area->is_type & level) == level)
        !          1429:     {
        !          1430:       oldlsp = lsp_search (lspid, area->lspdb[level - 1]);
        !          1431:       if (oldlsp)
        !          1432:        {
        !          1433:          seq_num = ntohl (oldlsp->lsp_header->seq_num);
        !          1434:          lsp_search_and_destroy (oldlsp->lsp_header->lsp_id,
        !          1435:                                  area->lspdb[level - 1]);
        !          1436:          /* FIXME: we should actually initiate a purge */
        !          1437:        }
        !          1438:       newlsp = lsp_new (lspid, area->max_lsp_lifetime[level - 1], seq_num,
        !          1439:                        area->is_type, 0, level);
        !          1440:       newlsp->own_lsp = 1;
        !          1441: 
        !          1442:       lsp_insert (newlsp, area->lspdb[level - 1]);
        !          1443:       /* build_lsp_data (newlsp, area); */
        !          1444:       lsp_build_nonpseudo (newlsp, area);
        !          1445:       /* time to calculate our checksum */
        !          1446:       lsp_seqnum_update (newlsp);
        !          1447:     }
        !          1448: 
        !          1449:   /* DEBUG_ADJ_PACKETS */
        !          1450:   if (isis->debugs & DEBUG_ADJ_PACKETS)
        !          1451:     {
        !          1452:       /* FIXME: is this place right? fix missing info */
        !          1453:       zlog_debug ("ISIS-Upd (%s): Building L%d LSP", area->area_tag, level);
        !          1454:     }
        !          1455: 
        !          1456:   return ISIS_OK;
        !          1457: }
        !          1458: 
        !          1459: /*
        !          1460:  * 7.3.9 Generation of level 1 LSPs (non-pseudonode)
        !          1461:  */
        !          1462: int
        !          1463: lsp_l1_generate (struct isis_area *area)
        !          1464: {
        !          1465:   THREAD_TIMER_ON (master, area->t_lsp_refresh[0], lsp_refresh_l1, area,
        !          1466:                   MAX_LSP_GEN_INTERVAL);
        !          1467: 
        !          1468:   return lsp_generate_non_pseudo (area, 1);
        !          1469: }
        !          1470: 
        !          1471: /*
        !          1472:  * 7.3.9 Generation of level 2 LSPs (non-pseudonode)
        !          1473:  */
        !          1474: int
        !          1475: lsp_l2_generate (struct isis_area *area)
        !          1476: {
        !          1477:   THREAD_TIMER_ON (master, area->t_lsp_refresh[1], lsp_refresh_l2, area,
        !          1478:                   MAX_LSP_GEN_INTERVAL);
        !          1479: 
        !          1480:   return lsp_generate_non_pseudo (area, 2);
        !          1481: }
        !          1482: 
        !          1483: static int
        !          1484: lsp_non_pseudo_regenerate (struct isis_area *area, int level)
        !          1485: {
        !          1486:   dict_t *lspdb = area->lspdb[level - 1];
        !          1487:   struct isis_lsp *lsp, *frag;
        !          1488:   struct listnode *node;
        !          1489:   u_char lspid[ISIS_SYS_ID_LEN + 2];
        !          1490: 
        !          1491:   memset (lspid, 0, ISIS_SYS_ID_LEN + 2);
        !          1492:   memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN);
        !          1493: 
        !          1494:   lsp = lsp_search (lspid, lspdb);
        !          1495: 
        !          1496:   if (!lsp)
        !          1497:     {
        !          1498:       zlog_err
        !          1499:        ("ISIS-Upd (%s): lsp_non_pseudo_regenerate(): no L%d LSP found!",
        !          1500:         area->area_tag, level);
        !          1501: 
        !          1502:       return ISIS_ERROR;
        !          1503:     }
        !          1504: 
        !          1505:   lsp_clear_data (lsp);
        !          1506:   lsp_build_nonpseudo (lsp, area);
        !          1507:   lsp->lsp_header->rem_lifetime = htons (isis_jitter
        !          1508:                                         (area->max_lsp_lifetime[level - 1],
        !          1509:                                          MAX_AGE_JITTER));
        !          1510:   lsp_seqnum_update (lsp);
        !          1511: 
        !          1512:   if (isis->debugs & DEBUG_UPDATE_PACKETS)
        !          1513:     {
        !          1514:       zlog_debug ("ISIS-Upd (%s): refreshing our L%d LSP %s, "
        !          1515:                  "seq 0x%08x, cksum 0x%04x lifetime %us",
        !          1516:                  area->area_tag,
        !          1517:                  level,
        !          1518:                  rawlspid_print (lsp->lsp_header->lsp_id),
        !          1519:                  ntohl (lsp->lsp_header->seq_num),
        !          1520:                  ntohs (lsp->lsp_header->checksum),
        !          1521:                  ntohs (lsp->lsp_header->rem_lifetime));
        !          1522:     }
        !          1523: 
        !          1524:   lsp->last_generated = time (NULL);
        !          1525:   area->lsp_regenerate_pending[level - 1] = 0;
        !          1526:   ISIS_FLAGS_SET_ALL (lsp->SRMflags);
        !          1527:   for (ALL_LIST_ELEMENTS_RO (lsp->lspu.frags, node, frag))
        !          1528:     {
        !          1529:       frag->lsp_header->rem_lifetime = htons (isis_jitter
        !          1530:                                              (area->
        !          1531:                                               max_lsp_lifetime[level - 1],
        !          1532:                                               MAX_AGE_JITTER));
        !          1533:       ISIS_FLAGS_SET_ALL (frag->SRMflags);
        !          1534:     }
        !          1535: 
        !          1536:   if (area->ip_circuits)
        !          1537:     isis_spf_schedule (area, level);
        !          1538: #ifdef HAVE_IPV6
        !          1539:   if (area->ipv6_circuits)
        !          1540:     isis_spf_schedule6 (area, level);
        !          1541: #endif
        !          1542:   return ISIS_OK;
        !          1543: }
        !          1544: 
        !          1545: /*
        !          1546:  * Done at least every MAX_LSP_GEN_INTERVAL. Search own LSPs, update holding
        !          1547:  * time and set SRM
        !          1548:  */
        !          1549: int
        !          1550: lsp_refresh_l1 (struct thread *thread)
        !          1551: {
        !          1552:   struct isis_area *area;
        !          1553:   unsigned long ref_time;
        !          1554: 
        !          1555:   area = THREAD_ARG (thread);
        !          1556:   assert (area);
        !          1557: 
        !          1558:   area->t_lsp_refresh[0] = NULL;
        !          1559:   if (area->is_type & IS_LEVEL_1)
        !          1560:     lsp_non_pseudo_regenerate (area, 1);
        !          1561: 
        !          1562:   ref_time = area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ?
        !          1563:     MAX_LSP_GEN_INTERVAL : area->lsp_refresh[0];
        !          1564: 
        !          1565:   THREAD_TIMER_ON (master, area->t_lsp_refresh[0], lsp_refresh_l1, area,
        !          1566:                   isis_jitter (ref_time, MAX_AGE_JITTER));
        !          1567: 
        !          1568:   return ISIS_OK;
        !          1569: }
        !          1570: 
        !          1571: int
        !          1572: lsp_refresh_l2 (struct thread *thread)
        !          1573: {
        !          1574:   struct isis_area *area;
        !          1575:   unsigned long ref_time;
        !          1576: 
        !          1577:   area = THREAD_ARG (thread);
        !          1578:   assert (area);
        !          1579: 
        !          1580:   area->t_lsp_refresh[1] = NULL;
        !          1581:   if (area->is_type & IS_LEVEL_2)
        !          1582:     lsp_non_pseudo_regenerate (area, 2);
        !          1583: 
        !          1584:   ref_time = area->lsp_refresh[1] > MAX_LSP_GEN_INTERVAL ?
        !          1585:     MAX_LSP_GEN_INTERVAL : area->lsp_refresh[1];
        !          1586: 
        !          1587:   THREAD_TIMER_ON (master, area->t_lsp_refresh[1], lsp_refresh_l2, area,
        !          1588:                   isis_jitter (ref_time, MAX_AGE_JITTER));
        !          1589: 
        !          1590:   return ISIS_OK;
        !          1591: }
        !          1592: 
        !          1593: /*
        !          1594:  * Something has changed -> regenerate LSP
        !          1595:  */
        !          1596: 
        !          1597: static int
        !          1598: lsp_l1_regenerate (struct thread *thread)
        !          1599: {
        !          1600:   struct isis_area *area;
        !          1601: 
        !          1602:   area = THREAD_ARG (thread);
        !          1603:   area->lsp_regenerate_pending[0] = 0;
        !          1604: 
        !          1605:   return lsp_non_pseudo_regenerate (area, 1);
        !          1606: }
        !          1607: 
        !          1608: static int
        !          1609: lsp_l2_regenerate (struct thread *thread)
        !          1610: {
        !          1611:   struct isis_area *area;
        !          1612: 
        !          1613:   area = THREAD_ARG (thread);
        !          1614:   area->lsp_regenerate_pending[1] = 0;
        !          1615: 
        !          1616:   return lsp_non_pseudo_regenerate (area, 2);
        !          1617: }
        !          1618: 
        !          1619: int
        !          1620: lsp_regenerate_schedule (struct isis_area *area)
        !          1621: {
        !          1622:   struct isis_lsp *lsp;
        !          1623:   u_char id[ISIS_SYS_ID_LEN + 2];
        !          1624:   time_t now, diff;
        !          1625:   memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
        !          1626:   LSP_PSEUDO_ID (id) = LSP_FRAGMENT (id) = 0;
        !          1627:   now = time (NULL);
        !          1628:   /*
        !          1629:    * First level 1
        !          1630:    */
        !          1631:   if (area->is_type & IS_LEVEL_1)
        !          1632:     {
        !          1633:       lsp = lsp_search (id, area->lspdb[0]);
        !          1634:       if (!lsp || area->lsp_regenerate_pending[0])
        !          1635:        goto L2;
        !          1636:       /*
        !          1637:        * Throttle avoidance
        !          1638:        */
        !          1639:       diff = now - lsp->last_generated;
        !          1640:       if (diff < MIN_LSP_GEN_INTERVAL)
        !          1641:        {
        !          1642:          area->lsp_regenerate_pending[0] = 1;
        !          1643:          area->t_lsp_l1_regenerate=thread_add_timer (master, lsp_l1_regenerate, area,
        !          1644:                            MIN_LSP_GEN_INTERVAL - diff);
        !          1645:          goto L2;
        !          1646:        }
        !          1647:       else
        !          1648:        lsp_non_pseudo_regenerate (area, 1);
        !          1649:     }
        !          1650:   /*
        !          1651:    * then 2
        !          1652:    */
        !          1653: L2:
        !          1654:   if (area->is_type & IS_LEVEL_2)
        !          1655:     {
        !          1656:       lsp = lsp_search (id, area->lspdb[1]);
        !          1657:       if (!lsp || area->lsp_regenerate_pending[1])
        !          1658:        return ISIS_OK;
        !          1659:       /*
        !          1660:        * Throttle avoidance
        !          1661:        */
        !          1662:       diff = now - lsp->last_generated;
        !          1663:       if (diff < MIN_LSP_GEN_INTERVAL)
        !          1664:        {
        !          1665:          area->lsp_regenerate_pending[1] = 1;
        !          1666:          area->t_lsp_l2_regenerate=thread_add_timer (master, lsp_l2_regenerate, area,
        !          1667:                            MIN_LSP_GEN_INTERVAL - diff);
        !          1668:          return ISIS_OK;
        !          1669:        }
        !          1670:       else
        !          1671:        lsp_non_pseudo_regenerate (area, 2);
        !          1672:     }
        !          1673: 
        !          1674:   return ISIS_OK;
        !          1675: }
        !          1676: 
        !          1677: /*
        !          1678:  * Funcs for pseudonode LSPs
        !          1679:  */
        !          1680: 
        !          1681: /*
        !          1682:  * 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs 
        !          1683:  */
        !          1684: static void
        !          1685: lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit,
        !          1686:                  int level)
        !          1687: {
        !          1688:   struct isis_adjacency *adj;
        !          1689:   struct is_neigh *is_neigh;
        !          1690:   struct te_is_neigh *te_is_neigh;
        !          1691:   struct es_neigh *es_neigh;
        !          1692:   struct list *adj_list;
        !          1693:   struct listnode *node;
        !          1694:   struct isis_passwd *passwd;
        !          1695: 
        !          1696:   assert (circuit);
        !          1697:   assert (circuit->circ_type == CIRCUIT_T_BROADCAST);
        !          1698: 
        !          1699:   if (!circuit->u.bc.is_dr[level - 1])
        !          1700:     return;                    /* we are not DIS on this circuit */
        !          1701: 
        !          1702:   lsp->level = level;
        !          1703:   if (level == 1)
        !          1704:     lsp->lsp_header->lsp_bits |= IS_LEVEL_1;
        !          1705:   else
        !          1706:     lsp->lsp_header->lsp_bits |= IS_LEVEL_2;
        !          1707: 
        !          1708:   /*
        !          1709:    * add self to IS neighbours 
        !          1710:    */
        !          1711:   if (circuit->area->oldmetric)
        !          1712:     {
        !          1713:       if (lsp->tlv_data.is_neighs == NULL)
        !          1714:        {
        !          1715:          lsp->tlv_data.is_neighs = list_new ();
        !          1716:          lsp->tlv_data.is_neighs->del = free_tlv;
        !          1717:        }
        !          1718:       is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
        !          1719: 
        !          1720:       memcpy (&is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN);
        !          1721:       listnode_add (lsp->tlv_data.is_neighs, is_neigh);
        !          1722:     }
        !          1723:   if (circuit->area->newmetric)
        !          1724:     {
        !          1725:       if (lsp->tlv_data.te_is_neighs == NULL)
        !          1726:        {
        !          1727:          lsp->tlv_data.te_is_neighs = list_new ();
        !          1728:          lsp->tlv_data.te_is_neighs->del = free_tlv;
        !          1729:        }
        !          1730:       te_is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct te_is_neigh));
        !          1731: 
        !          1732:       memcpy (&te_is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN);
        !          1733:       listnode_add (lsp->tlv_data.te_is_neighs, te_is_neigh);
        !          1734:     }
        !          1735: 
        !          1736:   adj_list = list_new ();
        !          1737:   isis_adj_build_up_list (circuit->u.bc.adjdb[level - 1], adj_list);
        !          1738: 
        !          1739:   for (ALL_LIST_ELEMENTS_RO (adj_list, node, adj))
        !          1740:     {
        !          1741:       if (adj->circuit_t & level)
        !          1742:        {
        !          1743:          if ((level == 1 && adj->sys_type == ISIS_SYSTYPE_L1_IS) ||
        !          1744:              (level == 1 && adj->sys_type == ISIS_SYSTYPE_L2_IS &&
        !          1745:              adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
        !          1746:              (level == 2 && adj->sys_type == ISIS_SYSTYPE_L2_IS))
        !          1747:            {
        !          1748:              /* an IS neighbour -> add it */
        !          1749:              if (circuit->area->oldmetric)
        !          1750:                {
        !          1751:                  is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
        !          1752: 
        !          1753:                  memcpy (&is_neigh->neigh_id, adj->sysid, ISIS_SYS_ID_LEN);
        !          1754:                  listnode_add (lsp->tlv_data.is_neighs, is_neigh);
        !          1755:                }
        !          1756:              if (circuit->area->newmetric)
        !          1757:                {
        !          1758:                  te_is_neigh = XCALLOC (MTYPE_ISIS_TLV,
        !          1759:                                         sizeof (struct te_is_neigh));
        !          1760:                  memcpy (&te_is_neigh->neigh_id, adj->sysid, ISIS_SYS_ID_LEN);
        !          1761:                  listnode_add (lsp->tlv_data.te_is_neighs, te_is_neigh);
        !          1762:                }
        !          1763:            }
        !          1764:          else if (level == 1 && adj->sys_type == ISIS_SYSTYPE_ES)
        !          1765:            {
        !          1766:              /* an ES neigbour add it, if we are building level 1 LSP */
        !          1767:              /* FIXME: the tlv-format is hard to use here */
        !          1768:              if (lsp->tlv_data.es_neighs == NULL)
        !          1769:                {
        !          1770:                  lsp->tlv_data.es_neighs = list_new ();
        !          1771:                  lsp->tlv_data.es_neighs->del = free_tlv;
        !          1772:                }
        !          1773:              es_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct es_neigh));
        !          1774:              
        !          1775:              memcpy (&es_neigh->first_es_neigh, adj->sysid, ISIS_SYS_ID_LEN);
        !          1776:              listnode_add (lsp->tlv_data.es_neighs, es_neigh);
        !          1777:            }
        !          1778:        }
        !          1779:     }
        !          1780: 
        !          1781:   /* Reset endp of stream to overwrite only TLV part of it. */
        !          1782:   stream_reset (lsp->pdu);
        !          1783:   stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
        !          1784: 
        !          1785:   /*
        !          1786:    * Add the authentication info if it's present
        !          1787:    */
        !          1788:   (level == 1) ? (passwd = &circuit->area->area_passwd) :
        !          1789:     (passwd = &circuit->area->domain_passwd);
        !          1790:   if (passwd->type)
        !          1791:     {
        !          1792:       memcpy (&lsp->tlv_data.auth_info, passwd, sizeof (struct isis_passwd));
        !          1793:       tlv_add_authinfo (passwd->type, passwd->len, passwd->passwd, lsp->pdu);
        !          1794:     }
        !          1795: 
        !          1796:   if (lsp->tlv_data.is_neighs && listcount (lsp->tlv_data.is_neighs) > 0)
        !          1797:     tlv_add_is_neighs (lsp->tlv_data.is_neighs, lsp->pdu);
        !          1798: 
        !          1799:   if (lsp->tlv_data.te_is_neighs && listcount (lsp->tlv_data.te_is_neighs) > 0)
        !          1800:     tlv_add_te_is_neighs (lsp->tlv_data.te_is_neighs, lsp->pdu);
        !          1801: 
        !          1802:   if (lsp->tlv_data.es_neighs && listcount (lsp->tlv_data.es_neighs) > 0)
        !          1803:     tlv_add_is_neighs (lsp->tlv_data.es_neighs, lsp->pdu);
        !          1804: 
        !          1805:   lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
        !          1806:   fletcher_checksum (STREAM_DATA (lsp->pdu) + 12,
        !          1807:                   ntohs (lsp->lsp_header->pdu_len) - 12, 12);
        !          1808: 
        !          1809:   list_delete (adj_list);
        !          1810: 
        !          1811:   return;
        !          1812: }
        !          1813: 
        !          1814: static int
        !          1815: lsp_pseudo_regenerate (struct isis_circuit *circuit, int level)
        !          1816: {
        !          1817:   dict_t *lspdb = circuit->area->lspdb[level - 1];
        !          1818:   struct isis_lsp *lsp;
        !          1819:   u_char lsp_id[ISIS_SYS_ID_LEN + 2];
        !          1820: 
        !          1821:   memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
        !          1822:   LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id;
        !          1823:   LSP_FRAGMENT (lsp_id) = 0;
        !          1824: 
        !          1825:   lsp = lsp_search (lsp_id, lspdb);
        !          1826: 
        !          1827:   if (!lsp)
        !          1828:     {
        !          1829:       zlog_err ("lsp_pseudo_regenerate(): no l%d LSP %s found!", level,
        !          1830:                rawlspid_print (lsp_id));
        !          1831:       return ISIS_ERROR;
        !          1832:     }
        !          1833:   lsp_clear_data (lsp);
        !          1834: 
        !          1835:   lsp_build_pseudo (lsp, circuit, level);
        !          1836: 
        !          1837:   lsp->lsp_header->rem_lifetime =
        !          1838:     htons (isis_jitter (circuit->area->max_lsp_lifetime[level - 1],
        !          1839:                        MAX_AGE_JITTER));
        !          1840: 
        !          1841:   lsp_inc_seqnum (lsp, 0);
        !          1842: 
        !          1843:   if (isis->debugs & DEBUG_UPDATE_PACKETS)
        !          1844:     {
        !          1845:       zlog_debug ("ISIS-Upd (%s): refreshing pseudo LSP L%d %s",
        !          1846:                  circuit->area->area_tag, level,
        !          1847:                  rawlspid_print (lsp->lsp_header->lsp_id));
        !          1848:     }
        !          1849: 
        !          1850:   lsp->last_generated = time (NULL);
        !          1851:   ISIS_FLAGS_SET_ALL (lsp->SRMflags);
        !          1852: 
        !          1853:   return ISIS_OK;
        !          1854: }
        !          1855: 
        !          1856: int
        !          1857: lsp_l1_refresh_pseudo (struct thread *thread)
        !          1858: {
        !          1859:   struct isis_circuit *circuit;
        !          1860:   int retval;
        !          1861:   unsigned long ref_time;
        !          1862: 
        !          1863:   circuit = THREAD_ARG (thread);
        !          1864: 
        !          1865:   if (!circuit->u.bc.is_dr[0])
        !          1866:     return ISIS_ERROR;         /* FIXME: purge and such */
        !          1867: 
        !          1868:   circuit->u.bc.t_refresh_pseudo_lsp[0] = NULL;
        !          1869: 
        !          1870:   retval = lsp_pseudo_regenerate (circuit, 1);
        !          1871: 
        !          1872:   ref_time = circuit->area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ?
        !          1873:     MAX_LSP_GEN_INTERVAL : circuit->area->lsp_refresh[0];
        !          1874: 
        !          1875:   THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[0],
        !          1876:                   lsp_l1_refresh_pseudo, circuit,
        !          1877:                   isis_jitter (ref_time, MAX_AGE_JITTER));
        !          1878: 
        !          1879:   return retval;
        !          1880: }
        !          1881: 
        !          1882: int
        !          1883: lsp_l1_pseudo_generate (struct isis_circuit *circuit)
        !          1884: {
        !          1885:   struct isis_lsp *lsp;
        !          1886:   u_char id[ISIS_SYS_ID_LEN + 2];
        !          1887:   unsigned long ref_time;
        !          1888: 
        !          1889:   memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
        !          1890:   LSP_FRAGMENT (id) = 0;
        !          1891:   LSP_PSEUDO_ID (id) = circuit->circuit_id;
        !          1892: 
        !          1893:   /*
        !          1894:    * If for some reason have a pseudo LSP in the db already -> regenerate
        !          1895:    */
        !          1896:   if (lsp_search (id, circuit->area->lspdb[0]))
        !          1897:     return lsp_pseudo_regenerate (circuit, 1);
        !          1898:   lsp = lsp_new (id, circuit->area->max_lsp_lifetime[0],
        !          1899:                 1, circuit->area->is_type, 0, 1);
        !          1900: 
        !          1901:   lsp_build_pseudo (lsp, circuit, 1);
        !          1902: 
        !          1903:   lsp->own_lsp = 1;
        !          1904:   lsp_insert (lsp, circuit->area->lspdb[0]);
        !          1905:   ISIS_FLAGS_SET_ALL (lsp->SRMflags);
        !          1906: 
        !          1907:   ref_time = circuit->area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ?
        !          1908:     MAX_LSP_GEN_INTERVAL : circuit->area->lsp_refresh[0];
        !          1909: 
        !          1910:   THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[0],
        !          1911:                   lsp_l1_refresh_pseudo, circuit,
        !          1912:                   isis_jitter (ref_time, MAX_AGE_JITTER));
        !          1913: 
        !          1914:   return lsp_regenerate_schedule (circuit->area);
        !          1915: }
        !          1916: 
        !          1917: int
        !          1918: lsp_l2_refresh_pseudo (struct thread *thread)
        !          1919: {
        !          1920:   struct isis_circuit *circuit;
        !          1921:   int retval;
        !          1922:   unsigned long ref_time;
        !          1923:   circuit = THREAD_ARG (thread);
        !          1924: 
        !          1925:   if (!circuit->u.bc.is_dr[1])
        !          1926:     return ISIS_ERROR;         /* FIXME: purge and such */
        !          1927: 
        !          1928:   circuit->u.bc.t_refresh_pseudo_lsp[1] = NULL;
        !          1929: 
        !          1930:   retval = lsp_pseudo_regenerate (circuit, 2);
        !          1931: 
        !          1932:   ref_time = circuit->area->lsp_refresh[1] > MAX_LSP_GEN_INTERVAL ?
        !          1933:     MAX_LSP_GEN_INTERVAL : circuit->area->lsp_refresh[1];
        !          1934: 
        !          1935:   THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[1],
        !          1936:                   lsp_l2_refresh_pseudo, circuit,
        !          1937:                   isis_jitter (ref_time, MAX_AGE_JITTER));
        !          1938: 
        !          1939:   return retval;
        !          1940: }
        !          1941: 
        !          1942: int
        !          1943: lsp_l2_pseudo_generate (struct isis_circuit *circuit)
        !          1944: {
        !          1945:   struct isis_lsp *lsp;
        !          1946:   u_char id[ISIS_SYS_ID_LEN + 2];
        !          1947:   unsigned long ref_time;
        !          1948: 
        !          1949:   memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
        !          1950:   LSP_FRAGMENT (id) = 0;
        !          1951:   LSP_PSEUDO_ID (id) = circuit->circuit_id;
        !          1952: 
        !          1953:   if (lsp_search (id, circuit->area->lspdb[1]))
        !          1954:     return lsp_pseudo_regenerate (circuit, 2);
        !          1955: 
        !          1956:   lsp = lsp_new (id, circuit->area->max_lsp_lifetime[1],
        !          1957:                 1, circuit->area->is_type, 0, 2);
        !          1958: 
        !          1959:   lsp_build_pseudo (lsp, circuit, 2);
        !          1960: 
        !          1961:   ref_time = circuit->area->lsp_refresh[1] > MAX_LSP_GEN_INTERVAL ?
        !          1962:     MAX_LSP_GEN_INTERVAL : circuit->area->lsp_refresh[1];
        !          1963: 
        !          1964: 
        !          1965:   lsp->own_lsp = 1;
        !          1966:   lsp_insert (lsp, circuit->area->lspdb[1]);
        !          1967:   ISIS_FLAGS_SET_ALL (lsp->SRMflags);
        !          1968: 
        !          1969:   THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[1],
        !          1970:                   lsp_l2_refresh_pseudo, circuit,
        !          1971:                   isis_jitter (ref_time, MAX_AGE_JITTER));
        !          1972: 
        !          1973:   return lsp_regenerate_schedule (circuit->area);
        !          1974: }
        !          1975: 
        !          1976: /*
        !          1977:  * Walk through LSPs for an area
        !          1978:  *  - set remaining lifetime
        !          1979:  *  - set LSPs with SRMflag set for sending
        !          1980:  */
        !          1981: int
        !          1982: lsp_tick (struct thread *thread)
        !          1983: {
        !          1984:   struct isis_area *area;
        !          1985:   struct isis_circuit *circuit;
        !          1986:   struct isis_lsp *lsp;
        !          1987:   struct list *lsp_list;
        !          1988:   struct listnode *lspnode, *cnode;
        !          1989:   dnode_t *dnode, *dnode_next;
        !          1990:   int level;
        !          1991: 
        !          1992:   lsp_list = list_new ();
        !          1993: 
        !          1994:   area = THREAD_ARG (thread);
        !          1995:   assert (area);
        !          1996:   area->t_tick = NULL;
        !          1997:   THREAD_TIMER_ON (master, area->t_tick, lsp_tick, area, 1);
        !          1998: 
        !          1999:   /*
        !          2000:    * Build a list of LSPs with (any) SRMflag set
        !          2001:    * and removed the ones that have aged out
        !          2002:    */
        !          2003:   for (level = 0; level < ISIS_LEVELS; level++)
        !          2004:     {
        !          2005:       if (area->lspdb[level] && dict_count (area->lspdb[level]) > 0)
        !          2006:        {
        !          2007:          dnode = dict_first (area->lspdb[level]);
        !          2008:          while (dnode != NULL)
        !          2009:            {
        !          2010:              dnode_next = dict_next (area->lspdb[level], dnode);
        !          2011:              lsp = dnode_get (dnode);
        !          2012:              lsp_set_time (lsp);
        !          2013:              if (lsp->age_out == 0)
        !          2014:                {
        !          2015: 
        !          2016:                  zlog_debug ("ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out",
        !          2017:                              area->area_tag,
        !          2018:                              lsp->level,
        !          2019:                              rawlspid_print (lsp->lsp_header->lsp_id),
        !          2020:                              ntohl (lsp->lsp_header->seq_num));
        !          2021: #ifdef TOPOLOGY_GENERATE
        !          2022:                  if (lsp->from_topology)
        !          2023:                    THREAD_TIMER_OFF (lsp->t_lsp_top_ref);
        !          2024: #endif /* TOPOLOGY_GENERATE */
        !          2025:                  lsp_destroy (lsp);
        !          2026:                  dict_delete (area->lspdb[level], dnode);
        !          2027:                }
        !          2028:              else if (flags_any_set (lsp->SRMflags))
        !          2029:                listnode_add (lsp_list, lsp);
        !          2030:              dnode = dnode_next;
        !          2031:            }
        !          2032: 
        !          2033:          /*
        !          2034:           * Send LSPs on circuits indicated by the SRMflags
        !          2035:           */
        !          2036:          if (listcount (lsp_list) > 0)
        !          2037:            {
        !          2038:               for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit))
        !          2039:                {
        !          2040:                   for (ALL_LIST_ELEMENTS_RO (lsp_list, lspnode, lsp))
        !          2041:                    {
        !          2042:                      if (ISIS_CHECK_FLAG (lsp->SRMflags, circuit))
        !          2043:                        {
        !          2044:                          /* FIXME: if same or elder lsp is already in lsp
        !          2045:                           * queue */
        !          2046:                          listnode_add (circuit->lsp_queue, lsp);
        !          2047:                          thread_add_event (master, send_lsp, circuit, 0);
        !          2048:                        }
        !          2049:                    }
        !          2050:                }
        !          2051:            }
        !          2052:          list_delete_all_node (lsp_list);
        !          2053:        }
        !          2054:     }
        !          2055: 
        !          2056:   list_delete (lsp_list);
        !          2057: 
        !          2058:   return ISIS_OK;
        !          2059: }
        !          2060: 
        !          2061: void
        !          2062: lsp_purge_dr (u_char * id, struct isis_circuit *circuit, int level)
        !          2063: {
        !          2064:   struct isis_lsp *lsp;
        !          2065: 
        !          2066:   lsp = lsp_search (id, circuit->area->lspdb[level - 1]);
        !          2067: 
        !          2068:   if (lsp && lsp->purged == 0)
        !          2069:     {
        !          2070:       lsp->lsp_header->rem_lifetime = htons (0);
        !          2071:       lsp->lsp_header->pdu_len =
        !          2072:        htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
        !          2073:       lsp->purged = 0;
        !          2074:       fletcher_checksum (STREAM_DATA (lsp->pdu) + 12,
        !          2075:                       ntohs (lsp->lsp_header->pdu_len) - 12, 12);
        !          2076:       ISIS_FLAGS_SET_ALL (lsp->SRMflags);
        !          2077:     }
        !          2078: 
        !          2079:   return;
        !          2080: }
        !          2081: 
        !          2082: /*
        !          2083:  * Purge own LSP that is received and we don't have. 
        !          2084:  * -> Do as in 7.3.16.4
        !          2085:  */
        !          2086: void
        !          2087: lsp_purge_non_exist (struct isis_link_state_hdr *lsp_hdr,
        !          2088:                     struct isis_area *area)
        !          2089: {
        !          2090:   struct isis_lsp *lsp;
        !          2091: 
        !          2092:   /*
        !          2093:    * We need to create the LSP to be purged 
        !          2094:    */
        !          2095:   zlog_debug ("LSP PURGE NON EXIST");
        !          2096:   lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp));
        !          2097:   /*FIXME: BUG BUG BUG! the lsp doesn't exist here! */
        !          2098:   /*did smt here, maybe good probably not */
        !          2099:   lsp->level = ((lsp_hdr->lsp_bits & LSPBIT_IST) == IS_LEVEL_1) ? 1 : 2;
        !          2100:   lsp->pdu = stream_new (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
        !          2101:   lsp->isis_header = (struct isis_fixed_hdr *) STREAM_DATA (lsp->pdu);
        !          2102:   fill_fixed_hdr (lsp->isis_header, (lsp->level == 1) ? L1_LINK_STATE
        !          2103:                  : L2_LINK_STATE);
        !          2104:   lsp->lsp_header = (struct isis_link_state_hdr *) (STREAM_DATA (lsp->pdu) +
        !          2105:                                                    ISIS_FIXED_HDR_LEN);
        !          2106:   memcpy (lsp->lsp_header, lsp_hdr, ISIS_LSP_HDR_LEN);
        !          2107: 
        !          2108:   /*
        !          2109:    * Retain only LSP header
        !          2110:    */
        !          2111:   lsp->lsp_header->pdu_len = htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
        !          2112:   /*
        !          2113:    * Set the remaining lifetime to 0
        !          2114:    */
        !          2115:   lsp->lsp_header->rem_lifetime = 0;
        !          2116:   /*
        !          2117:    * Put the lsp into LSPdb
        !          2118:    */
        !          2119:   lsp_insert (lsp, area->lspdb[lsp->level - 1]);
        !          2120: 
        !          2121:   /*
        !          2122:    * Send in to whole area
        !          2123:    */
        !          2124:   ISIS_FLAGS_SET_ALL (lsp->SRMflags);
        !          2125: 
        !          2126:   return;
        !          2127: }
        !          2128: 
        !          2129: #ifdef TOPOLOGY_GENERATE
        !          2130: static int
        !          2131: top_lsp_refresh (struct thread *thread)
        !          2132: {
        !          2133:   struct isis_lsp *lsp;
        !          2134:   unsigned long ref_time;
        !          2135: 
        !          2136:   lsp = THREAD_ARG (thread);
        !          2137:   assert (lsp);
        !          2138: 
        !          2139:   lsp->t_lsp_top_ref = NULL;
        !          2140: 
        !          2141:   lsp_seqnum_update (lsp);
        !          2142: 
        !          2143:   ISIS_FLAGS_SET_ALL (lsp->SRMflags);
        !          2144:   if (isis->debugs & DEBUG_UPDATE_PACKETS)
        !          2145:     {
        !          2146:       zlog_debug ("ISIS-Upd (): refreshing Topology L1 %s",
        !          2147:                  rawlspid_print (lsp->lsp_header->lsp_id));
        !          2148:     }
        !          2149:   /* Refresh dynamic hostname in the cache. */
        !          2150:   isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname,
        !          2151:                     IS_LEVEL_1);
        !          2152: 
        !          2153:   lsp->lsp_header->rem_lifetime =
        !          2154:     htons (isis_jitter (lsp->area->max_lsp_lifetime[0], MAX_AGE_JITTER));
        !          2155: 
        !          2156:   ref_time = lsp->area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ?
        !          2157:     MAX_LSP_GEN_INTERVAL : lsp->area->lsp_refresh[0];
        !          2158: 
        !          2159:   THREAD_TIMER_ON (master, lsp->t_lsp_top_ref, top_lsp_refresh, lsp,
        !          2160:                   isis_jitter (ref_time, MAX_LSP_GEN_JITTER));
        !          2161: 
        !          2162:   return ISIS_OK;
        !          2163: }
        !          2164: 
        !          2165: void
        !          2166: generate_topology_lsps (struct isis_area *area)
        !          2167: {
        !          2168:   struct listnode *node;
        !          2169:   int i, max = 0;
        !          2170:   struct arc *arc;
        !          2171:   u_char lspid[ISIS_SYS_ID_LEN + 2];
        !          2172:   struct isis_lsp *lsp;
        !          2173:   unsigned long ref_time;
        !          2174: 
        !          2175:   /* first we find the maximal node */
        !          2176:   for (ALL_LIST_ELEMENTS_RO (area->topology, node, arc))
        !          2177:   {
        !          2178:     if (arc->from_node > max)
        !          2179:       max = arc->from_node;
        !          2180:     if (arc->to_node > max)
        !          2181:       max = arc->to_node;
        !          2182:   }
        !          2183: 
        !          2184:   for (i = 1; i < (max + 1); i++)
        !          2185:     {
        !          2186:       memcpy (lspid, area->topology_baseis, ISIS_SYS_ID_LEN);
        !          2187:       LSP_PSEUDO_ID (lspid) = 0x00;
        !          2188:       LSP_FRAGMENT (lspid) = 0x00;
        !          2189:       lspid[ISIS_SYS_ID_LEN - 1] = (i & 0xFF);
        !          2190:       lspid[ISIS_SYS_ID_LEN - 2] = ((i >> 8) & 0xFF);
        !          2191: 
        !          2192:       lsp = lsp_new (lspid, isis_jitter (area->max_lsp_lifetime[0],
        !          2193:                     MAX_AGE_JITTER), 1, IS_LEVEL_1, 0, 1);
        !          2194:       if (!lsp)
        !          2195:        return;
        !          2196:       lsp->from_topology = 1;
        !          2197:       lsp->area = area;
        !          2198: 
        !          2199:       /* Creating LSP data based on topology info. */
        !          2200:       build_topology_lsp_data (lsp, area, i);
        !          2201:       /* Checksum is also calculated here. */
        !          2202:       lsp_seqnum_update (lsp);
        !          2203:       /* Take care of inserting dynamic hostname into cache. */
        !          2204:       isis_dynhn_insert (lspid, lsp->tlv_data.hostname, IS_LEVEL_1);
        !          2205: 
        !          2206:       ref_time = area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ?
        !          2207:        MAX_LSP_GEN_INTERVAL : area->lsp_refresh[0];
        !          2208: 
        !          2209:       THREAD_TIMER_ON (master, lsp->t_lsp_top_ref, top_lsp_refresh, lsp,
        !          2210:                       isis_jitter (ref_time, MAX_LSP_GEN_JITTER));
        !          2211:       ISIS_FLAGS_SET_ALL (lsp->SRMflags);
        !          2212:       lsp_insert (lsp, area->lspdb[0]);
        !          2213:     }
        !          2214: }
        !          2215: 
        !          2216: void
        !          2217: remove_topology_lsps (struct isis_area *area)
        !          2218: {
        !          2219:   struct isis_lsp *lsp;
        !          2220:   dnode_t *dnode, *dnode_next;
        !          2221: 
        !          2222:   dnode = dict_first (area->lspdb[0]);
        !          2223:   while (dnode != NULL)
        !          2224:     {
        !          2225:       dnode_next = dict_next (area->lspdb[0], dnode);
        !          2226:       lsp = dnode_get (dnode);
        !          2227:       if (lsp->from_topology)
        !          2228:        {
        !          2229:          THREAD_TIMER_OFF (lsp->t_lsp_top_ref);
        !          2230:          lsp_destroy (lsp);
        !          2231:          dict_delete (area->lspdb[0], dnode);
        !          2232:        }
        !          2233:       dnode = dnode_next;
        !          2234:     }
        !          2235: }
        !          2236: 
        !          2237: void
        !          2238: build_topology_lsp_data (struct isis_lsp *lsp, struct isis_area *area,
        !          2239:                         int lsp_top_num)
        !          2240: {
        !          2241:   struct listnode *node;
        !          2242:   struct arc *arc;
        !          2243:   struct is_neigh *is_neigh;
        !          2244:   struct te_is_neigh *te_is_neigh;
        !          2245:   char buff[200];
        !          2246:   struct tlvs tlv_data;
        !          2247:   struct isis_lsp *lsp0 = lsp;
        !          2248: 
        !          2249:   /* Add area addresses. FIXME: Is it needed at all? */
        !          2250:   if (lsp->tlv_data.area_addrs == NULL)
        !          2251:     lsp->tlv_data.area_addrs = list_new ();
        !          2252:   list_add_list (lsp->tlv_data.area_addrs, area->area_addrs);
        !          2253: 
        !          2254:   if (lsp->tlv_data.nlpids == NULL)
        !          2255:     lsp->tlv_data.nlpids = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct nlpids));
        !          2256:   lsp->tlv_data.nlpids->count = 1;
        !          2257:   lsp->tlv_data.nlpids->nlpids[0] = NLPID_IP;
        !          2258: 
        !          2259:   if (area->dynhostname)
        !          2260:     {
        !          2261:       lsp->tlv_data.hostname = XMALLOC (MTYPE_ISIS_TLV,
        !          2262:                                        sizeof (struct hostname));
        !          2263:       memset (buff, 0x00, 200);
        !          2264:       sprintf (buff, "%s%d", area->topology_basedynh ? area->topology_basedynh :
        !          2265:               "feedme", lsp_top_num);
        !          2266:       memcpy (lsp->tlv_data.hostname->name, buff, strlen (buff));
        !          2267:       lsp->tlv_data.hostname->namelen = strlen (buff);
        !          2268:     }
        !          2269: 
        !          2270:   if (lsp->tlv_data.nlpids)
        !          2271:     tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu);
        !          2272:   if (lsp->tlv_data.hostname)
        !          2273:     tlv_add_dynamic_hostname (lsp->tlv_data.hostname, lsp->pdu);
        !          2274:   if (lsp->tlv_data.area_addrs && listcount (lsp->tlv_data.area_addrs) > 0)
        !          2275:     tlv_add_area_addrs (lsp->tlv_data.area_addrs, lsp->pdu);
        !          2276: 
        !          2277:   memset (&tlv_data, 0, sizeof (struct tlvs));
        !          2278:   if (tlv_data.is_neighs == NULL)
        !          2279:     {
        !          2280:       tlv_data.is_neighs = list_new ();
        !          2281:       tlv_data.is_neighs->del = free_tlv;
        !          2282:     }
        !          2283: 
        !          2284:   /* Add reachability for this IS for simulated 1. */
        !          2285:   if (lsp_top_num == 1)
        !          2286:     {
        !          2287:       is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
        !          2288: 
        !          2289:       memcpy (&is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN);
        !          2290:       LSP_PSEUDO_ID (is_neigh->neigh_id) = 0x00;
        !          2291:       /* Metric MUST NOT be 0, unless it's not alias TLV. */
        !          2292:       is_neigh->metrics.metric_default = 0x01;
        !          2293:       is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED;
        !          2294:       is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED;
        !          2295:       is_neigh->metrics.metric_error = METRICS_UNSUPPORTED;
        !          2296:       listnode_add (tlv_data.is_neighs, is_neigh);
        !          2297:     }
        !          2298: 
        !          2299:   /* Add IS reachabilities. */
        !          2300:   for (ALL_LIST_ELEMENTS_RO (area->topology, node, arc))
        !          2301:     {
        !          2302:       int to_lsp = 0;
        !          2303:       
        !          2304:       if ((lsp_top_num != arc->from_node) && (lsp_top_num != arc->to_node))
        !          2305:        continue;
        !          2306: 
        !          2307:       if (lsp_top_num == arc->from_node)
        !          2308:        to_lsp = arc->to_node;
        !          2309:       else
        !          2310:        to_lsp = arc->from_node;
        !          2311: 
        !          2312:       if (area->oldmetric)
        !          2313:        {
        !          2314:          is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
        !          2315: 
        !          2316:          memcpy (&is_neigh->neigh_id, area->topology_baseis, ISIS_SYS_ID_LEN);
        !          2317:          is_neigh->neigh_id[ISIS_SYS_ID_LEN - 1] = (to_lsp & 0xFF);
        !          2318:          is_neigh->neigh_id[ISIS_SYS_ID_LEN - 2] = ((to_lsp >> 8) & 0xFF);
        !          2319:          is_neigh->metrics.metric_default = arc->distance;
        !          2320:          is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED;
        !          2321:          is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED;
        !          2322:          is_neigh->metrics.metric_error = METRICS_UNSUPPORTED;
        !          2323:          listnode_add (tlv_data.is_neighs, is_neigh);
        !          2324:        }
        !          2325: 
        !          2326:       if (area->newmetric)
        !          2327:        {
        !          2328:          uint32_t metric;
        !          2329: 
        !          2330:          if (tlv_data.te_is_neighs == NULL)
        !          2331:            {
        !          2332:              tlv_data.te_is_neighs = list_new ();
        !          2333:              tlv_data.te_is_neighs->del = free_tlv;
        !          2334:            }
        !          2335:          te_is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct te_is_neigh));
        !          2336:          memcpy (&te_is_neigh->neigh_id, area->topology_baseis,
        !          2337:                  ISIS_SYS_ID_LEN);
        !          2338:          te_is_neigh->neigh_id[ISIS_SYS_ID_LEN - 1] = (to_lsp & 0xFF);
        !          2339:          te_is_neigh->neigh_id[ISIS_SYS_ID_LEN - 2] = ((to_lsp >> 8) & 0xFF);
        !          2340:          metric = ((htonl(arc->distance) >> 8) & 0xffffff);
        !          2341:          memcpy (te_is_neigh->te_metric, &metric, 3);
        !          2342:          listnode_add (tlv_data.te_is_neighs, te_is_neigh);
        !          2343:        }
        !          2344:     }
        !          2345: 
        !          2346:   while (tlv_data.is_neighs && listcount (tlv_data.is_neighs))
        !          2347:     {
        !          2348:       if (lsp->tlv_data.is_neighs == NULL)
        !          2349:        lsp->tlv_data.is_neighs = list_new ();
        !          2350:       lsp_tlv_fit (lsp, &tlv_data.is_neighs, &lsp->tlv_data.is_neighs,
        !          2351:                   IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
        !          2352:                   tlv_add_is_neighs);
        !          2353:       if (tlv_data.is_neighs && listcount (tlv_data.is_neighs))
        !          2354:         lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
        !          2355:                             lsp0, area, IS_LEVEL_1);
        !          2356:     }
        !          2357: 
        !          2358:   while (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs))
        !          2359:     {
        !          2360:       if (lsp->tlv_data.te_is_neighs == NULL)
        !          2361:        lsp->tlv_data.te_is_neighs = list_new ();
        !          2362:       lsp_tlv_fit (lsp, &tlv_data.te_is_neighs, &lsp->tlv_data.te_is_neighs,
        !          2363:                   IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
        !          2364:                   tlv_add_te_is_neighs);
        !          2365:       if (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs))
        !          2366:        lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
        !          2367:                             lsp0, area, IS_LEVEL_1);
        !          2368:     }
        !          2369: 
        !          2370:   free_tlvs (&tlv_data);
        !          2371:   return;
        !          2372: }
        !          2373: #endif /* TOPOLOGY_GENERATE */

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