diff options
Diffstat (limited to 'isisd/isis_pdu.c')
| -rw-r--r-- | isisd/isis_pdu.c | 5301 |
1 files changed, 2600 insertions, 2701 deletions
diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index a41581ff02..dfb01fc02b 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -1,23 +1,23 @@ /* - * IS-IS Rout(e)ing protocol - isis_pdu.c + * IS-IS Rout(e)ing protocol - isis_pdu.c * PDU processing * * Copyright (C) 2001,2002 Sampo Saaristo - * Tampere University of Technology + * Tampere University of Technology * Institute of Communications Engineering * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public Licenseas published by the Free - * Software Foundation; either version 2 of the License, or (at your option) + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public Licenseas published by the Free + * Software Foundation; either version 2 of the License, or (at your option) * any later version. * - * This program is distributed in the hope that it will be useful,but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * This program is distributed in the hope that it will be useful,but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ @@ -62,9 +62,8 @@ #endif /* PNBBY */ /* Utility mask array. */ -static const u_char maskbit[] = { - 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff -}; +static const u_char maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0, + 0xf8, 0xfc, 0xfe, 0xff}; /* * HELPER FUNCS @@ -73,23 +72,21 @@ static const u_char maskbit[] = { /* * Compares two sets of area addresses */ -static int -area_match (struct list *left, struct list *right) +static int area_match(struct list *left, struct list *right) { - struct area_addr *addr1, *addr2; - struct listnode *node1, *node2; - - for (ALL_LIST_ELEMENTS_RO (left, node1, addr1)) - { - for (ALL_LIST_ELEMENTS_RO (right, node2, addr2)) - { - if (addr1->addr_len == addr2->addr_len && - !memcmp (addr1->area_addr, addr2->area_addr, (int) addr1->addr_len)) - return 1; /* match */ - } - } + struct area_addr *addr1, *addr2; + struct listnode *node1, *node2; + + for (ALL_LIST_ELEMENTS_RO(left, node1, addr1)) { + for (ALL_LIST_ELEMENTS_RO(right, node2, addr2)) { + if (addr1->addr_len == addr2->addr_len + && !memcmp(addr1->area_addr, addr2->area_addr, + (int)addr1->addr_len)) + return 1; /* match */ + } + } - return 0; /* mismatch */ + return 0; /* mismatch */ } /* @@ -99,29 +96,28 @@ area_match (struct list *left, struct list *right) * return 0 the IIH's IP is not in the IS's subnetwork * 1 the IIH's IP is in the IS's subnetwork */ -static int -ip_same_subnet (struct prefix_ipv4 *ip1, struct in_addr *ip2) +static int ip_same_subnet(struct prefix_ipv4 *ip1, struct in_addr *ip2) { - u_char *addr1, *addr2; - int shift, offset, offsetloop; - int len; + u_char *addr1, *addr2; + int shift, offset, offsetloop; + int len; - addr1 = (u_char *) & ip1->prefix.s_addr; - addr2 = (u_char *) & ip2->s_addr; - len = ip1->prefixlen; + addr1 = (u_char *)&ip1->prefix.s_addr; + addr2 = (u_char *)&ip2->s_addr; + len = ip1->prefixlen; - shift = len % PNBBY; - offsetloop = offset = len / PNBBY; + shift = len % PNBBY; + offsetloop = offset = len / PNBBY; - while (offsetloop--) - if (addr1[offsetloop] != addr2[offsetloop]) - return 0; + while (offsetloop--) + if (addr1[offsetloop] != addr2[offsetloop]) + return 0; - if (shift) - if (maskbit[shift] & (addr1[offset] ^ addr2[offset])) - return 0; + if (shift) + if (maskbit[shift] & (addr1[offset] ^ addr2[offset])) + return 0; - return 1; /* match */ + return 1; /* match */ } /* @@ -131,258 +127,240 @@ ip_same_subnet (struct prefix_ipv4 *ip1, struct in_addr *ip2) * return 0 no match; * 1 match; */ -static int -ip_match (struct list *left, struct list *right) +static int ip_match(struct list *left, struct list *right) { - struct prefix_ipv4 *ip1; - struct in_addr *ip2; - struct listnode *node1, *node2; - - if ((left == NULL) || (right == NULL)) - return 0; - - for (ALL_LIST_ELEMENTS_RO (left, node1, ip1)) - { - for (ALL_LIST_ELEMENTS_RO (right, node2, ip2)) - { - if (ip_same_subnet (ip1, ip2)) - { - return 1; /* match */ + struct prefix_ipv4 *ip1; + struct in_addr *ip2; + struct listnode *node1, *node2; + + if ((left == NULL) || (right == NULL)) + return 0; + + for (ALL_LIST_ELEMENTS_RO(left, node1, ip1)) { + for (ALL_LIST_ELEMENTS_RO(right, node2, ip2)) { + if (ip_same_subnet(ip1, ip2)) { + return 1; /* match */ + } + } } - } - - } - return 0; + return 0; } /* - * Checks whether we should accept a PDU of given level + * Checks whether we should accept a PDU of given level */ -static int -accept_level (int level, int circuit_t) +static int accept_level(int level, int circuit_t) { - int retval = ((circuit_t & level) == level); /* simple approach */ + int retval = ((circuit_t & level) == level); /* simple approach */ - return retval; + return retval; } /* * Verify authentication information * Support cleartext and HMAC MD5 authentication */ -static int -authentication_check (struct isis_passwd *remote, struct isis_passwd *local, - struct stream *stream, uint32_t auth_tlv_offset) +static int authentication_check(struct isis_passwd *remote, + struct isis_passwd *local, + struct stream *stream, uint32_t auth_tlv_offset) { - unsigned char digest[ISIS_AUTH_MD5_SIZE]; - - /* Auth fail () - passwd type mismatch */ - if (local->type != remote->type) - return ISIS_ERROR; - - switch (local->type) - { - /* No authentication required */ - case ISIS_PASSWD_TYPE_UNUSED: - break; - - /* Cleartext (ISO 10589) */ - case ISIS_PASSWD_TYPE_CLEARTXT: - /* Auth fail () - passwd len mismatch */ - if (remote->len != local->len) - return ISIS_ERROR; - return memcmp (local->passwd, remote->passwd, local->len); - - /* HMAC MD5 (RFC 3567) */ - case ISIS_PASSWD_TYPE_HMAC_MD5: - /* Auth fail () - passwd len mismatch */ - if (remote->len != ISIS_AUTH_MD5_SIZE) - return ISIS_ERROR; - /* Set the authentication value to 0 before the check */ - memset (STREAM_DATA (stream) + auth_tlv_offset + 3, 0, - ISIS_AUTH_MD5_SIZE); - /* Compute the digest */ - hmac_md5 (STREAM_DATA (stream), stream_get_endp (stream), - (unsigned char *) &(local->passwd), local->len, - (unsigned char *) &digest); - /* Copy back the authentication value after the check */ - memcpy (STREAM_DATA (stream) + auth_tlv_offset + 3, - remote->passwd, ISIS_AUTH_MD5_SIZE); - return memcmp (digest, remote->passwd, ISIS_AUTH_MD5_SIZE); - - default: - zlog_err ("Unsupported authentication type"); - return ISIS_ERROR; - } - - /* Authentication pass when no authentication is configured */ - return ISIS_OK; + unsigned char digest[ISIS_AUTH_MD5_SIZE]; + + /* Auth fail () - passwd type mismatch */ + if (local->type != remote->type) + return ISIS_ERROR; + + switch (local->type) { + /* No authentication required */ + case ISIS_PASSWD_TYPE_UNUSED: + break; + + /* Cleartext (ISO 10589) */ + case ISIS_PASSWD_TYPE_CLEARTXT: + /* Auth fail () - passwd len mismatch */ + if (remote->len != local->len) + return ISIS_ERROR; + return memcmp(local->passwd, remote->passwd, local->len); + + /* HMAC MD5 (RFC 3567) */ + case ISIS_PASSWD_TYPE_HMAC_MD5: + /* Auth fail () - passwd len mismatch */ + if (remote->len != ISIS_AUTH_MD5_SIZE) + return ISIS_ERROR; + /* Set the authentication value to 0 before the check */ + memset(STREAM_DATA(stream) + auth_tlv_offset + 3, 0, + ISIS_AUTH_MD5_SIZE); + /* Compute the digest */ + hmac_md5(STREAM_DATA(stream), stream_get_endp(stream), + (unsigned char *)&(local->passwd), local->len, + (unsigned char *)&digest); + /* Copy back the authentication value after the check */ + memcpy(STREAM_DATA(stream) + auth_tlv_offset + 3, + remote->passwd, ISIS_AUTH_MD5_SIZE); + return memcmp(digest, remote->passwd, ISIS_AUTH_MD5_SIZE); + + default: + zlog_err("Unsupported authentication type"); + return ISIS_ERROR; + } + + /* Authentication pass when no authentication is configured */ + return ISIS_OK; } -static int -lsp_authentication_check (struct stream *stream, struct isis_area *area, - int level, struct isis_passwd *passwd) +static int lsp_authentication_check(struct stream *stream, + struct isis_area *area, int level, + struct isis_passwd *passwd) { - struct isis_link_state_hdr *hdr; - uint32_t expected = 0, found = 0, auth_tlv_offset = 0; - uint16_t checksum, rem_lifetime, pdu_len; - struct tlvs tlvs; - int retval = ISIS_OK; - - hdr = (struct isis_link_state_hdr *) (STREAM_PNT (stream)); - pdu_len = ntohs (hdr->pdu_len); - expected |= TLVFLAG_AUTH_INFO; - auth_tlv_offset = stream_get_getp (stream) + ISIS_LSP_HDR_LEN; - retval = parse_tlvs (area->area_tag, STREAM_PNT (stream) + ISIS_LSP_HDR_LEN, - pdu_len - ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN, - &expected, &found, &tlvs, &auth_tlv_offset); - - if (retval != ISIS_OK) - { - zlog_err ("ISIS-Upd (%s): Parse failed L%d LSP %s, seq 0x%08x, " - "cksum 0x%04x, lifetime %us, len %u", - area->area_tag, level, rawlspid_print (hdr->lsp_id), - ntohl (hdr->seq_num), ntohs (hdr->checksum), - ntohs (hdr->rem_lifetime), pdu_len); - if ((isis->debugs & DEBUG_UPDATE_PACKETS) && - (isis->debugs & DEBUG_PACKET_DUMP)) - zlog_dump_data (STREAM_DATA (stream), stream_get_endp (stream)); - return retval; - } + struct isis_link_state_hdr *hdr; + uint32_t expected = 0, found = 0, auth_tlv_offset = 0; + uint16_t checksum, rem_lifetime, pdu_len; + struct tlvs tlvs; + int retval = ISIS_OK; + + hdr = (struct isis_link_state_hdr *)(STREAM_PNT(stream)); + pdu_len = ntohs(hdr->pdu_len); + expected |= TLVFLAG_AUTH_INFO; + auth_tlv_offset = stream_get_getp(stream) + ISIS_LSP_HDR_LEN; + retval = parse_tlvs(area->area_tag, + STREAM_PNT(stream) + ISIS_LSP_HDR_LEN, + pdu_len - ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN, + &expected, &found, &tlvs, &auth_tlv_offset); + + if (retval != ISIS_OK) { + zlog_err( + "ISIS-Upd (%s): Parse failed L%d LSP %s, seq 0x%08x, " + "cksum 0x%04x, lifetime %us, len %u", + area->area_tag, level, rawlspid_print(hdr->lsp_id), + ntohl(hdr->seq_num), ntohs(hdr->checksum), + ntohs(hdr->rem_lifetime), pdu_len); + if ((isis->debugs & DEBUG_UPDATE_PACKETS) + && (isis->debugs & DEBUG_PACKET_DUMP)) + zlog_dump_data(STREAM_DATA(stream), + stream_get_endp(stream)); + return retval; + } - if (!(found & TLVFLAG_AUTH_INFO)) - { - zlog_err ("No authentication tlv in LSP"); - return ISIS_ERROR; - } + if (!(found & TLVFLAG_AUTH_INFO)) { + zlog_err("No authentication tlv in LSP"); + return ISIS_ERROR; + } - if (tlvs.auth_info.type != ISIS_PASSWD_TYPE_CLEARTXT && - tlvs.auth_info.type != ISIS_PASSWD_TYPE_HMAC_MD5) - { - zlog_err ("Unknown authentication type in LSP"); - return ISIS_ERROR; - } + if (tlvs.auth_info.type != ISIS_PASSWD_TYPE_CLEARTXT + && tlvs.auth_info.type != ISIS_PASSWD_TYPE_HMAC_MD5) { + zlog_err("Unknown authentication type in LSP"); + return ISIS_ERROR; + } - /* - * RFC 5304 set checksum and remaining lifetime to zero before - * verification and reset to old values after verification. - */ - checksum = hdr->checksum; - rem_lifetime = hdr->rem_lifetime; - hdr->checksum = 0; - hdr->rem_lifetime = 0; - retval = authentication_check (&tlvs.auth_info, passwd, stream, - auth_tlv_offset); - hdr->checksum = checksum; - hdr->rem_lifetime = rem_lifetime; - - return retval; + /* + * RFC 5304 set checksum and remaining lifetime to zero before + * verification and reset to old values after verification. + */ + checksum = hdr->checksum; + rem_lifetime = hdr->rem_lifetime; + hdr->checksum = 0; + hdr->rem_lifetime = 0; + retval = authentication_check(&tlvs.auth_info, passwd, stream, + auth_tlv_offset); + hdr->checksum = checksum; + hdr->rem_lifetime = rem_lifetime; + + return retval; } /* * Processing helper functions */ -static void -del_addr (void *val) +static void del_addr(void *val) { - XFREE (MTYPE_ISIS_TMP, val); + XFREE(MTYPE_ISIS_TMP, val); } -static void -tlvs_to_adj_area_addrs (struct tlvs *tlvs, struct isis_adjacency *adj) +static void tlvs_to_adj_area_addrs(struct tlvs *tlvs, + struct isis_adjacency *adj) { - struct listnode *node; - struct area_addr *area_addr, *malloced; + struct listnode *node; + struct area_addr *area_addr, *malloced; - if (adj->area_addrs) - { - adj->area_addrs->del = del_addr; - list_delete (adj->area_addrs); - } - adj->area_addrs = list_new (); - if (tlvs->area_addrs) - { - for (ALL_LIST_ELEMENTS_RO (tlvs->area_addrs, node, area_addr)) - { - malloced = XMALLOC (MTYPE_ISIS_TMP, sizeof (struct area_addr)); - memcpy (malloced, area_addr, sizeof (struct area_addr)); - listnode_add (adj->area_addrs, malloced); - } - } + if (adj->area_addrs) { + adj->area_addrs->del = del_addr; + list_delete(adj->area_addrs); + } + adj->area_addrs = list_new(); + if (tlvs->area_addrs) { + for (ALL_LIST_ELEMENTS_RO(tlvs->area_addrs, node, area_addr)) { + malloced = XMALLOC(MTYPE_ISIS_TMP, + sizeof(struct area_addr)); + memcpy(malloced, area_addr, sizeof(struct area_addr)); + listnode_add(adj->area_addrs, malloced); + } + } } -static int -tlvs_to_adj_nlpids (struct tlvs *tlvs, struct isis_adjacency *adj) +static int tlvs_to_adj_nlpids(struct tlvs *tlvs, struct isis_adjacency *adj) { - int i; - struct nlpids *tlv_nlpids; + int i; + struct nlpids *tlv_nlpids; - if (tlvs->nlpids) - { + if (tlvs->nlpids) { - tlv_nlpids = tlvs->nlpids; - if (tlv_nlpids->count > array_size (adj->nlpids.nlpids)) - return 1; + tlv_nlpids = tlvs->nlpids; + if (tlv_nlpids->count > array_size(adj->nlpids.nlpids)) + return 1; - adj->nlpids.count = tlv_nlpids->count; + adj->nlpids.count = tlv_nlpids->count; - for (i = 0; i < tlv_nlpids->count; i++) - { - adj->nlpids.nlpids[i] = tlv_nlpids->nlpids[i]; + for (i = 0; i < tlv_nlpids->count; i++) { + adj->nlpids.nlpids[i] = tlv_nlpids->nlpids[i]; + } } - } - return 0; + return 0; } -static void -tlvs_to_adj_ipv4_addrs (struct tlvs *tlvs, struct isis_adjacency *adj) +static void tlvs_to_adj_ipv4_addrs(struct tlvs *tlvs, + struct isis_adjacency *adj) { - struct listnode *node; - struct in_addr *ipv4_addr, *malloced; + struct listnode *node; + struct in_addr *ipv4_addr, *malloced; - if (adj->ipv4_addrs) - { - adj->ipv4_addrs->del = del_addr; - list_delete (adj->ipv4_addrs); - } - adj->ipv4_addrs = list_new (); - if (tlvs->ipv4_addrs) - { - for (ALL_LIST_ELEMENTS_RO (tlvs->ipv4_addrs, node, ipv4_addr)) - { - malloced = XMALLOC (MTYPE_ISIS_TMP, sizeof (struct in_addr)); - memcpy (malloced, ipv4_addr, sizeof (struct in_addr)); - listnode_add (adj->ipv4_addrs, malloced); - } - } + if (adj->ipv4_addrs) { + adj->ipv4_addrs->del = del_addr; + list_delete(adj->ipv4_addrs); + } + adj->ipv4_addrs = list_new(); + if (tlvs->ipv4_addrs) { + for (ALL_LIST_ELEMENTS_RO(tlvs->ipv4_addrs, node, ipv4_addr)) { + malloced = + XMALLOC(MTYPE_ISIS_TMP, sizeof(struct in_addr)); + memcpy(malloced, ipv4_addr, sizeof(struct in_addr)); + listnode_add(adj->ipv4_addrs, malloced); + } + } } -static void -tlvs_to_adj_ipv6_addrs (struct tlvs *tlvs, struct isis_adjacency *adj) +static void tlvs_to_adj_ipv6_addrs(struct tlvs *tlvs, + struct isis_adjacency *adj) { - struct listnode *node; - struct in6_addr *ipv6_addr, *malloced; - - if (adj->ipv6_addrs) - { - adj->ipv6_addrs->del = del_addr; - list_delete (adj->ipv6_addrs); - } - adj->ipv6_addrs = list_new (); - if (tlvs->ipv6_addrs) - { - for (ALL_LIST_ELEMENTS_RO (tlvs->ipv6_addrs, node, ipv6_addr)) - { - malloced = XMALLOC (MTYPE_ISIS_TMP, sizeof (struct in6_addr)); - memcpy (malloced, ipv6_addr, sizeof (struct in6_addr)); - listnode_add (adj->ipv6_addrs, malloced); - } - } + struct listnode *node; + struct in6_addr *ipv6_addr, *malloced; + if (adj->ipv6_addrs) { + adj->ipv6_addrs->del = del_addr; + list_delete(adj->ipv6_addrs); + } + adj->ipv6_addrs = list_new(); + if (tlvs->ipv6_addrs) { + for (ALL_LIST_ELEMENTS_RO(tlvs->ipv6_addrs, node, ipv6_addr)) { + malloced = XMALLOC(MTYPE_ISIS_TMP, + sizeof(struct in6_addr)); + memcpy(malloced, ipv6_addr, sizeof(struct in6_addr)); + listnode_add(adj->ipv6_addrs, malloced); + } + } } /* - * RECEIVE SIDE + * RECEIVE SIDE */ /* @@ -391,576 +369,552 @@ tlvs_to_adj_ipv6_addrs (struct tlvs *tlvs, struct isis_adjacency *adj) * Section 8.2.5 - Receiving point-to-point IIH PDUs * */ -static int -process_p2p_hello (struct isis_circuit *circuit) +static int process_p2p_hello(struct isis_circuit *circuit) { - int retval = ISIS_OK; - struct isis_p2p_hello_hdr *hdr; - struct isis_adjacency *adj; - u_int32_t expected = 0, found = 0, auth_tlv_offset = 0; - uint16_t pdu_len; - struct tlvs tlvs; - int v4_usable = 0, v6_usable = 0; - - if (isis->debugs & DEBUG_ADJ_PACKETS) - { - zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH on %s, cirType %s, cirID %u", - circuit->area->area_tag, circuit->interface->name, - circuit_t2string (circuit->is_type), circuit->circuit_id); - if (isis->debugs & DEBUG_PACKET_DUMP) - zlog_dump_data (STREAM_DATA (circuit->rcv_stream), - stream_get_endp (circuit->rcv_stream)); - } - - if (circuit->circ_type != CIRCUIT_T_P2P) - { - zlog_warn ("p2p hello on non p2p circuit"); - return ISIS_WARNING; - } - - if ((stream_get_endp (circuit->rcv_stream) - - stream_get_getp (circuit->rcv_stream)) < ISIS_P2PHELLO_HDRLEN) - { - zlog_warn ("Packet too short"); - return ISIS_WARNING; - } + int retval = ISIS_OK; + struct isis_p2p_hello_hdr *hdr; + struct isis_adjacency *adj; + u_int32_t expected = 0, found = 0, auth_tlv_offset = 0; + uint16_t pdu_len; + struct tlvs tlvs; + int v4_usable = 0, v6_usable = 0; + + if (isis->debugs & DEBUG_ADJ_PACKETS) { + zlog_debug( + "ISIS-Adj (%s): Rcvd P2P IIH on %s, cirType %s, cirID %u", + circuit->area->area_tag, circuit->interface->name, + circuit_t2string(circuit->is_type), + circuit->circuit_id); + if (isis->debugs & DEBUG_PACKET_DUMP) + zlog_dump_data(STREAM_DATA(circuit->rcv_stream), + stream_get_endp(circuit->rcv_stream)); + } - /* 8.2.5.1 PDU acceptance tests */ + if (circuit->circ_type != CIRCUIT_T_P2P) { + zlog_warn("p2p hello on non p2p circuit"); + return ISIS_WARNING; + } - /* 8.2.5.1 a) external domain untrue */ - /* FIXME: not useful at all? */ + if ((stream_get_endp(circuit->rcv_stream) + - stream_get_getp(circuit->rcv_stream)) + < ISIS_P2PHELLO_HDRLEN) { + zlog_warn("Packet too short"); + return ISIS_WARNING; + } - /* 8.2.5.1 b) ID Length mismatch */ - /* checked at the handle_pdu */ + /* 8.2.5.1 PDU acceptance tests */ - /* 8.2.5.2 IIH PDU Processing */ + /* 8.2.5.1 a) external domain untrue */ + /* FIXME: not useful at all? */ - /* 8.2.5.2 a) 1) Maximum Area Addresses */ - /* Already checked, and can also be ommited */ + /* 8.2.5.1 b) ID Length mismatch */ + /* checked at the handle_pdu */ - /* - * Get the header - */ - hdr = (struct isis_p2p_hello_hdr *) STREAM_PNT (circuit->rcv_stream); - pdu_len = ntohs (hdr->pdu_len); + /* 8.2.5.2 IIH PDU Processing */ - if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_P2PHELLO_HDRLEN) || - pdu_len > ISO_MTU(circuit) || - pdu_len > stream_get_endp (circuit->rcv_stream)) - { - zlog_warn ("ISIS-Adj (%s): Rcvd P2P IIH from (%s) with " - "invalid pdu length %d", - circuit->area->area_tag, circuit->interface->name, pdu_len); - return ISIS_WARNING; - } + /* 8.2.5.2 a) 1) Maximum Area Addresses */ + /* Already checked, and can also be ommited */ - /* - * Set the stream endp to PDU length, ignoring additional padding - * introduced by transport chips. - */ - if (pdu_len < stream_get_endp (circuit->rcv_stream)) - stream_set_endp (circuit->rcv_stream, pdu_len); - - stream_forward_getp (circuit->rcv_stream, ISIS_P2PHELLO_HDRLEN); - - /* - * Lets get the TLVS now - */ - expected |= TLVFLAG_AREA_ADDRS; - expected |= TLVFLAG_AUTH_INFO; - expected |= TLVFLAG_NLPID; - expected |= TLVFLAG_IPV4_ADDR; - expected |= TLVFLAG_IPV6_ADDR; - - auth_tlv_offset = stream_get_getp (circuit->rcv_stream); - retval = parse_tlvs (circuit->area->area_tag, - STREAM_PNT (circuit->rcv_stream), - pdu_len - ISIS_P2PHELLO_HDRLEN - ISIS_FIXED_HDR_LEN, - &expected, &found, &tlvs, &auth_tlv_offset); - - if (retval > ISIS_WARNING) - { - zlog_warn ("parse_tlvs() failed"); - free_tlvs (&tlvs); - return retval; - }; + /* + * Get the header + */ + hdr = (struct isis_p2p_hello_hdr *)STREAM_PNT(circuit->rcv_stream); + pdu_len = ntohs(hdr->pdu_len); - if (!(found & TLVFLAG_AREA_ADDRS)) - { - zlog_warn ("No Area addresses TLV in P2P IS to IS hello"); - free_tlvs (&tlvs); - return ISIS_WARNING; - } - - if (!(found & TLVFLAG_NLPID)) - { - zlog_warn ("No supported protocols TLV in P2P IS to IS hello"); - free_tlvs (&tlvs); - return ISIS_WARNING; - } - - /* 8.2.5.1 c) Authentication */ - if (circuit->passwd.type) - { - if (!(found & TLVFLAG_AUTH_INFO) || - authentication_check (&tlvs.auth_info, &circuit->passwd, - circuit->rcv_stream, auth_tlv_offset)) - { - isis_event_auth_failure (circuit->area->area_tag, - "P2P hello authentication failure", - hdr->source_id); - free_tlvs (&tlvs); - return ISIS_OK; - } - } - - /* - * check if it's own interface ip match iih ip addrs - */ - if (found & TLVFLAG_IPV4_ADDR) - { - if (ip_match (circuit->ip_addrs, tlvs.ipv4_addrs)) - v4_usable = 1; - else - zlog_warn ("ISIS-Adj: IPv4 addresses present but no overlap " - "in P2P IIH from %s\n", circuit->interface->name); - } - if (found & TLVFLAG_IPV6_ADDR) - { - /* TBA: check that we have a linklocal ourselves? */ - struct listnode *node; - struct in6_addr *ip; - for (ALL_LIST_ELEMENTS_RO (tlvs.ipv6_addrs, node, ip)) - if (IN6_IS_ADDR_LINKLOCAL (ip)) - { - v6_usable = 1; - break; - } - - if (!v6_usable) - zlog_warn ("ISIS-Adj: IPv6 addresses present but no link-local " - "in P2P IIH from %s\n", circuit->interface->name); - } - - if (!(found & (TLVFLAG_IPV4_ADDR | TLVFLAG_IPV6_ADDR))) - zlog_warn ("ISIS-Adj: neither IPv4 nor IPv6 addr in P2P IIH from %s\n", - circuit->interface->name); + if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_P2PHELLO_HDRLEN) + || pdu_len > ISO_MTU(circuit) + || pdu_len > stream_get_endp(circuit->rcv_stream)) { + zlog_warn( + "ISIS-Adj (%s): Rcvd P2P IIH from (%s) with " + "invalid pdu length %d", + circuit->area->area_tag, circuit->interface->name, + pdu_len); + return ISIS_WARNING; + } - if (!v6_usable && !v4_usable) - { - free_tlvs (&tlvs); - return ISIS_WARNING; - } + /* + * Set the stream endp to PDU length, ignoring additional padding + * introduced by transport chips. + */ + if (pdu_len < stream_get_endp(circuit->rcv_stream)) + stream_set_endp(circuit->rcv_stream, pdu_len); + + stream_forward_getp(circuit->rcv_stream, ISIS_P2PHELLO_HDRLEN); + + /* + * Lets get the TLVS now + */ + expected |= TLVFLAG_AREA_ADDRS; + expected |= TLVFLAG_AUTH_INFO; + expected |= TLVFLAG_NLPID; + expected |= TLVFLAG_IPV4_ADDR; + expected |= TLVFLAG_IPV6_ADDR; + + auth_tlv_offset = stream_get_getp(circuit->rcv_stream); + retval = parse_tlvs(circuit->area->area_tag, + STREAM_PNT(circuit->rcv_stream), + pdu_len - ISIS_P2PHELLO_HDRLEN - ISIS_FIXED_HDR_LEN, + &expected, &found, &tlvs, &auth_tlv_offset); + + if (retval > ISIS_WARNING) { + zlog_warn("parse_tlvs() failed"); + free_tlvs(&tlvs); + return retval; + }; + + if (!(found & TLVFLAG_AREA_ADDRS)) { + zlog_warn("No Area addresses TLV in P2P IS to IS hello"); + free_tlvs(&tlvs); + return ISIS_WARNING; + } - /* - * it's own p2p IIH PDU - discard - */ - if (!memcmp (hdr->source_id, isis->sysid, ISIS_SYS_ID_LEN)) - { - zlog_warn ("ISIS-Adj (%s): it's own IIH PDU - discarded", - circuit->area->area_tag); - free_tlvs (&tlvs); - return ISIS_WARNING; - } + if (!(found & TLVFLAG_NLPID)) { + zlog_warn("No supported protocols TLV in P2P IS to IS hello"); + free_tlvs(&tlvs); + return ISIS_WARNING; + } - /* - * My interpertation of the ISO, if no adj exists we will create one for - * the circuit - */ - adj = circuit->u.p2p.neighbor; - /* If an adjacency exists, check it is with the source of the hello - * packets */ - if (adj) - { - if (memcmp(hdr->source_id, adj->sysid, ISIS_SYS_ID_LEN)) - { - zlog_debug("hello source and adjacency do not match, set adj down\n"); - isis_adj_state_change (adj, ISIS_ADJ_DOWN, "adj do not exist"); - return 0; - } - } - if (!adj || adj->level != hdr->circuit_t) - { - if (!adj) - { - adj = isis_new_adj (hdr->source_id, NULL, hdr->circuit_t, circuit); - if (adj == NULL) - return ISIS_ERROR; - } - else - { - adj->level = hdr->circuit_t; - } - circuit->u.p2p.neighbor = adj; - /* Build lsp with the new neighbor entry when a new - * adjacency is formed. Set adjacency circuit type to - * IIH PDU header circuit type before lsp is regenerated - * when an adjacency is up. This will result in the new - * adjacency entry getting added to the lsp tlv neighbor list. - */ - adj->circuit_t = hdr->circuit_t; - isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL); - adj->sys_type = ISIS_SYSTYPE_UNKNOWN; - } + /* 8.2.5.1 c) Authentication */ + if (circuit->passwd.type) { + if (!(found & TLVFLAG_AUTH_INFO) + || authentication_check(&tlvs.auth_info, &circuit->passwd, + circuit->rcv_stream, + auth_tlv_offset)) { + isis_event_auth_failure( + circuit->area->area_tag, + "P2P hello authentication failure", + hdr->source_id); + free_tlvs(&tlvs); + return ISIS_OK; + } + } - /* 8.2.6 Monitoring point-to-point adjacencies */ - adj->hold_time = ntohs (hdr->hold_time); - adj->last_upd = time (NULL); + /* + * check if it's own interface ip match iih ip addrs + */ + if (found & TLVFLAG_IPV4_ADDR) { + if (ip_match(circuit->ip_addrs, tlvs.ipv4_addrs)) + v4_usable = 1; + else + zlog_warn( + "ISIS-Adj: IPv4 addresses present but no overlap " + "in P2P IIH from %s\n", + circuit->interface->name); + } + if (found & TLVFLAG_IPV6_ADDR) { + /* TBA: check that we have a linklocal ourselves? */ + struct listnode *node; + struct in6_addr *ip; + for (ALL_LIST_ELEMENTS_RO(tlvs.ipv6_addrs, node, ip)) + if (IN6_IS_ADDR_LINKLOCAL(ip)) { + v6_usable = 1; + break; + } + + if (!v6_usable) + zlog_warn( + "ISIS-Adj: IPv6 addresses present but no link-local " + "in P2P IIH from %s\n", + circuit->interface->name); + } - /* we do this now because the adj may not survive till the end... */ - tlvs_to_adj_area_addrs (&tlvs, adj); + if (!(found & (TLVFLAG_IPV4_ADDR | TLVFLAG_IPV6_ADDR))) + zlog_warn( + "ISIS-Adj: neither IPv4 nor IPv6 addr in P2P IIH from %s\n", + circuit->interface->name); - /* which protocol are spoken ??? */ - if (tlvs_to_adj_nlpids (&tlvs, adj)) - { - free_tlvs (&tlvs); - return ISIS_WARNING; - } + if (!v6_usable && !v4_usable) { + free_tlvs(&tlvs); + return ISIS_WARNING; + } - /* we need to copy addresses to the adj */ - if (found & TLVFLAG_IPV4_ADDR) - tlvs_to_adj_ipv4_addrs (&tlvs, adj); - - /* Update MPLS TE Remote IP address parameter if possible */ - if (IS_MPLS_TE(isisMplsTE) && circuit->mtc && IS_CIRCUIT_TE(circuit->mtc)) - if (adj->ipv4_addrs != NULL && listcount(adj->ipv4_addrs) != 0) - { - struct in_addr *ip_addr; - ip_addr = (struct in_addr *)listgetdata ((struct listnode *)listhead (adj->ipv4_addrs)); - set_circuitparams_rmt_ipaddr (circuit->mtc, *ip_addr); - } - - if (found & TLVFLAG_IPV6_ADDR) - tlvs_to_adj_ipv6_addrs (&tlvs, adj); - - /* lets take care of the expiry */ - THREAD_TIMER_OFF (adj->t_expire); - THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj, - (long) adj->hold_time); - - /* 8.2.5.2 a) a match was detected */ - if (area_match (circuit->area->area_addrs, tlvs.area_addrs)) - { - /* 8.2.5.2 a) 2) If the system is L1 - table 5 */ - if (circuit->area->is_type == IS_LEVEL_1) - { - switch (hdr->circuit_t) - { - case IS_LEVEL_1: - case IS_LEVEL_1_AND_2: - if (adj->adj_state != ISIS_ADJ_UP) - { - /* (4) adj state up */ - isis_adj_state_change (adj, ISIS_ADJ_UP, NULL); - /* (5) adj usage level 1 */ - adj->adj_usage = ISIS_ADJ_LEVEL1; - } - else if (adj->adj_usage == ISIS_ADJ_LEVEL1) - { - ; /* accept */ - } - break; - case IS_LEVEL_2: - if (adj->adj_state != ISIS_ADJ_UP) - { - /* (7) reject - wrong system type event */ - zlog_warn ("wrongSystemType"); - free_tlvs (&tlvs); - return ISIS_WARNING; /* Reject */ - } - else if (adj->adj_usage == ISIS_ADJ_LEVEL1) - { - /* (6) down - wrong system */ - isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System"); - } - break; - } + /* + * it's own p2p IIH PDU - discard + */ + if (!memcmp(hdr->source_id, isis->sysid, ISIS_SYS_ID_LEN)) { + zlog_warn("ISIS-Adj (%s): it's own IIH PDU - discarded", + circuit->area->area_tag); + free_tlvs(&tlvs); + return ISIS_WARNING; } - /* 8.2.5.2 a) 3) If the system is L1L2 - table 6 */ - if (circuit->area->is_type == IS_LEVEL_1_AND_2) - { - switch (hdr->circuit_t) - { - case IS_LEVEL_1: - if (adj->adj_state != ISIS_ADJ_UP) - { - /* (6) adj state up */ - isis_adj_state_change (adj, ISIS_ADJ_UP, NULL); - /* (7) adj usage level 1 */ - adj->adj_usage = ISIS_ADJ_LEVEL1; - } - else if (adj->adj_usage == ISIS_ADJ_LEVEL1) - { - ; /* accept */ - } - else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) || - (adj->adj_usage == ISIS_ADJ_LEVEL2)) - { - /* (8) down - wrong system */ - isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System"); - } - break; - case IS_LEVEL_2: - if (adj->adj_state != ISIS_ADJ_UP) - { - /* (6) adj state up */ - isis_adj_state_change (adj, ISIS_ADJ_UP, NULL); - /* (9) adj usage level 2 */ - adj->adj_usage = ISIS_ADJ_LEVEL2; - } - else if ((adj->adj_usage == ISIS_ADJ_LEVEL1) || - (adj->adj_usage == ISIS_ADJ_LEVEL1AND2)) - { - /* (8) down - wrong system */ - isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System"); - } - else if (adj->adj_usage == ISIS_ADJ_LEVEL2) - { - ; /* Accept */ - } - break; - case IS_LEVEL_1_AND_2: - if (adj->adj_state != ISIS_ADJ_UP) - { - /* (6) adj state up */ - isis_adj_state_change (adj, ISIS_ADJ_UP, NULL); - /* (10) adj usage level 1 */ - adj->adj_usage = ISIS_ADJ_LEVEL1AND2; - } - else if ((adj->adj_usage == ISIS_ADJ_LEVEL1) || - (adj->adj_usage == ISIS_ADJ_LEVEL2)) - { - /* (8) down - wrong system */ - isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System"); + /* + * My interpertation of the ISO, if no adj exists we will create one for + * the circuit + */ + adj = circuit->u.p2p.neighbor; + /* If an adjacency exists, check it is with the source of the hello + * packets */ + if (adj) { + if (memcmp(hdr->source_id, adj->sysid, ISIS_SYS_ID_LEN)) { + zlog_debug( + "hello source and adjacency do not match, set adj down\n"); + isis_adj_state_change(adj, ISIS_ADJ_DOWN, + "adj do not exist"); + return 0; } - else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2) - { - ; /* Accept */ + } + if (!adj || adj->level != hdr->circuit_t) { + if (!adj) { + adj = isis_new_adj(hdr->source_id, NULL, hdr->circuit_t, + circuit); + if (adj == NULL) + return ISIS_ERROR; + } else { + adj->level = hdr->circuit_t; } - break; - } + circuit->u.p2p.neighbor = adj; + /* Build lsp with the new neighbor entry when a new + * adjacency is formed. Set adjacency circuit type to + * IIH PDU header circuit type before lsp is regenerated + * when an adjacency is up. This will result in the new + * adjacency entry getting added to the lsp tlv neighbor list. + */ + adj->circuit_t = hdr->circuit_t; + isis_adj_state_change(adj, ISIS_ADJ_INITIALIZING, NULL); + adj->sys_type = ISIS_SYSTYPE_UNKNOWN; } - /* 8.2.5.2 a) 4) If the system is L2 - table 7 */ - if (circuit->area->is_type == IS_LEVEL_2) - { - switch (hdr->circuit_t) - { - case IS_LEVEL_1: - if (adj->adj_state != ISIS_ADJ_UP) - { - /* (5) reject - wrong system type event */ - zlog_warn ("wrongSystemType"); - free_tlvs (&tlvs); - return ISIS_WARNING; /* Reject */ - } - else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) || - (adj->adj_usage == ISIS_ADJ_LEVEL2)) - { - /* (6) down - wrong system */ - isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System"); - } - break; - case IS_LEVEL_1_AND_2: - case IS_LEVEL_2: - if (adj->adj_state != ISIS_ADJ_UP) - { - /* (7) adj state up */ - isis_adj_state_change (adj, ISIS_ADJ_UP, NULL); - /* (8) adj usage level 2 */ - adj->adj_usage = ISIS_ADJ_LEVEL2; - } - else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2) - { - /* (6) down - wrong system */ - isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System"); - } - else if (adj->adj_usage == ISIS_ADJ_LEVEL2) - { - ; /* Accept */ - } - break; - } + /* 8.2.6 Monitoring point-to-point adjacencies */ + adj->hold_time = ntohs(hdr->hold_time); + adj->last_upd = time(NULL); + + /* we do this now because the adj may not survive till the end... */ + tlvs_to_adj_area_addrs(&tlvs, adj); + + /* which protocol are spoken ??? */ + if (tlvs_to_adj_nlpids(&tlvs, adj)) { + free_tlvs(&tlvs); + return ISIS_WARNING; } - } - /* 8.2.5.2 b) if no match was detected */ - else if (listcount (circuit->area->area_addrs) > 0) - { - if (circuit->area->is_type == IS_LEVEL_1) - { - /* 8.2.5.2 b) 1) is_type L1 and adj is not up */ - if (adj->adj_state != ISIS_ADJ_UP) - { - isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch"); - /* 8.2.5.2 b) 2)is_type L1 and adj is up */ - } - else - { - isis_adj_state_change (adj, ISIS_ADJ_DOWN, - "Down - Area Mismatch"); - } - } - /* 8.2.5.2 b 3 If the system is L2 or L1L2 - table 8 */ - else - { - switch (hdr->circuit_t) - { - case IS_LEVEL_1: - if (adj->adj_state != ISIS_ADJ_UP) - { - /* (6) reject - Area Mismatch event */ - zlog_warn ("AreaMismatch"); - free_tlvs (&tlvs); - return ISIS_WARNING; /* Reject */ - } - else if (adj->adj_usage == ISIS_ADJ_LEVEL1) - { - /* (7) down - area mismatch */ - isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch"); + /* we need to copy addresses to the adj */ + if (found & TLVFLAG_IPV4_ADDR) + tlvs_to_adj_ipv4_addrs(&tlvs, adj); + + /* Update MPLS TE Remote IP address parameter if possible */ + if (IS_MPLS_TE(isisMplsTE) && circuit->mtc + && IS_CIRCUIT_TE(circuit->mtc)) + if (adj->ipv4_addrs != NULL + && listcount(adj->ipv4_addrs) != 0) { + struct in_addr *ip_addr; + ip_addr = (struct in_addr *)listgetdata( + (struct listnode *)listhead(adj->ipv4_addrs)); + set_circuitparams_rmt_ipaddr(circuit->mtc, *ip_addr); } - else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) || - (adj->adj_usage == ISIS_ADJ_LEVEL2)) - { - /* (7) down - wrong system */ - isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System"); + + if (found & TLVFLAG_IPV6_ADDR) + tlvs_to_adj_ipv6_addrs(&tlvs, adj); + + /* lets take care of the expiry */ + THREAD_TIMER_OFF(adj->t_expire); + THREAD_TIMER_ON(master, adj->t_expire, isis_adj_expire, adj, + (long)adj->hold_time); + + /* 8.2.5.2 a) a match was detected */ + if (area_match(circuit->area->area_addrs, tlvs.area_addrs)) { + /* 8.2.5.2 a) 2) If the system is L1 - table 5 */ + if (circuit->area->is_type == IS_LEVEL_1) { + switch (hdr->circuit_t) { + case IS_LEVEL_1: + case IS_LEVEL_1_AND_2: + if (adj->adj_state != ISIS_ADJ_UP) { + /* (4) adj state up */ + isis_adj_state_change(adj, ISIS_ADJ_UP, + NULL); + /* (5) adj usage level 1 */ + adj->adj_usage = ISIS_ADJ_LEVEL1; + } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) { + ; /* accept */ + } + break; + case IS_LEVEL_2: + if (adj->adj_state != ISIS_ADJ_UP) { + /* (7) reject - wrong system type event + */ + zlog_warn("wrongSystemType"); + free_tlvs(&tlvs); + return ISIS_WARNING; /* Reject */ + } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) { + /* (6) down - wrong system */ + isis_adj_state_change(adj, + ISIS_ADJ_DOWN, + "Wrong System"); + } + break; + } } - break; - case IS_LEVEL_1_AND_2: - case IS_LEVEL_2: - if (adj->adj_state != ISIS_ADJ_UP) - { - /* (8) adj state up */ - isis_adj_state_change (adj, ISIS_ADJ_UP, NULL); - /* (9) adj usage level 2 */ - adj->adj_usage = ISIS_ADJ_LEVEL2; + + /* 8.2.5.2 a) 3) If the system is L1L2 - table 6 */ + if (circuit->area->is_type == IS_LEVEL_1_AND_2) { + switch (hdr->circuit_t) { + case IS_LEVEL_1: + if (adj->adj_state != ISIS_ADJ_UP) { + /* (6) adj state up */ + isis_adj_state_change(adj, ISIS_ADJ_UP, + NULL); + /* (7) adj usage level 1 */ + adj->adj_usage = ISIS_ADJ_LEVEL1; + } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) { + ; /* accept */ + } else if ((adj->adj_usage + == ISIS_ADJ_LEVEL1AND2) + || (adj->adj_usage + == ISIS_ADJ_LEVEL2)) { + /* (8) down - wrong system */ + isis_adj_state_change(adj, + ISIS_ADJ_DOWN, + "Wrong System"); + } + break; + case IS_LEVEL_2: + if (adj->adj_state != ISIS_ADJ_UP) { + /* (6) adj state up */ + isis_adj_state_change(adj, ISIS_ADJ_UP, + NULL); + /* (9) adj usage level 2 */ + adj->adj_usage = ISIS_ADJ_LEVEL2; + } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1) + || (adj->adj_usage + == ISIS_ADJ_LEVEL1AND2)) { + /* (8) down - wrong system */ + isis_adj_state_change(adj, + ISIS_ADJ_DOWN, + "Wrong System"); + } else if (adj->adj_usage == ISIS_ADJ_LEVEL2) { + ; /* Accept */ + } + break; + case IS_LEVEL_1_AND_2: + if (adj->adj_state != ISIS_ADJ_UP) { + /* (6) adj state up */ + isis_adj_state_change(adj, ISIS_ADJ_UP, + NULL); + /* (10) adj usage level 1 */ + adj->adj_usage = ISIS_ADJ_LEVEL1AND2; + } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1) + || (adj->adj_usage + == ISIS_ADJ_LEVEL2)) { + /* (8) down - wrong system */ + isis_adj_state_change(adj, + ISIS_ADJ_DOWN, + "Wrong System"); + } else if (adj->adj_usage + == ISIS_ADJ_LEVEL1AND2) { + ; /* Accept */ + } + break; + } } - else if (adj->adj_usage == ISIS_ADJ_LEVEL1) - { - /* (7) down - wrong system */ - isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System"); + + /* 8.2.5.2 a) 4) If the system is L2 - table 7 */ + if (circuit->area->is_type == IS_LEVEL_2) { + switch (hdr->circuit_t) { + case IS_LEVEL_1: + if (adj->adj_state != ISIS_ADJ_UP) { + /* (5) reject - wrong system type event + */ + zlog_warn("wrongSystemType"); + free_tlvs(&tlvs); + return ISIS_WARNING; /* Reject */ + } else if ((adj->adj_usage + == ISIS_ADJ_LEVEL1AND2) + || (adj->adj_usage + == ISIS_ADJ_LEVEL2)) { + /* (6) down - wrong system */ + isis_adj_state_change(adj, + ISIS_ADJ_DOWN, + "Wrong System"); + } + break; + case IS_LEVEL_1_AND_2: + case IS_LEVEL_2: + if (adj->adj_state != ISIS_ADJ_UP) { + /* (7) adj state up */ + isis_adj_state_change(adj, ISIS_ADJ_UP, + NULL); + /* (8) adj usage level 2 */ + adj->adj_usage = ISIS_ADJ_LEVEL2; + } else if (adj->adj_usage + == ISIS_ADJ_LEVEL1AND2) { + /* (6) down - wrong system */ + isis_adj_state_change(adj, + ISIS_ADJ_DOWN, + "Wrong System"); + } else if (adj->adj_usage == ISIS_ADJ_LEVEL2) { + ; /* Accept */ + } + break; + } } - else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2) - { - if (hdr->circuit_t == IS_LEVEL_2) - { - /* (7) down - wrong system */ - isis_adj_state_change (adj, ISIS_ADJ_DOWN, - "Wrong System"); - } - else - { - /* (7) down - area mismatch */ - isis_adj_state_change (adj, ISIS_ADJ_DOWN, - "Area Mismatch"); - } + } + /* 8.2.5.2 b) if no match was detected */ + else if (listcount(circuit->area->area_addrs) > 0) { + if (circuit->area->is_type == IS_LEVEL_1) { + /* 8.2.5.2 b) 1) is_type L1 and adj is not up */ + if (adj->adj_state != ISIS_ADJ_UP) { + isis_adj_state_change(adj, ISIS_ADJ_DOWN, + "Area Mismatch"); + /* 8.2.5.2 b) 2)is_type L1 and adj is up */ + } else { + isis_adj_state_change(adj, ISIS_ADJ_DOWN, + "Down - Area Mismatch"); + } } - else if (adj->adj_usage == ISIS_ADJ_LEVEL2) - { - ; /* Accept */ + /* 8.2.5.2 b 3 If the system is L2 or L1L2 - table 8 */ + else { + switch (hdr->circuit_t) { + case IS_LEVEL_1: + if (adj->adj_state != ISIS_ADJ_UP) { + /* (6) reject - Area Mismatch event */ + zlog_warn("AreaMismatch"); + free_tlvs(&tlvs); + return ISIS_WARNING; /* Reject */ + } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) { + /* (7) down - area mismatch */ + isis_adj_state_change(adj, + ISIS_ADJ_DOWN, + "Area Mismatch"); + + } else if ((adj->adj_usage + == ISIS_ADJ_LEVEL1AND2) + || (adj->adj_usage + == ISIS_ADJ_LEVEL2)) { + /* (7) down - wrong system */ + isis_adj_state_change(adj, + ISIS_ADJ_DOWN, + "Wrong System"); + } + break; + case IS_LEVEL_1_AND_2: + case IS_LEVEL_2: + if (adj->adj_state != ISIS_ADJ_UP) { + /* (8) adj state up */ + isis_adj_state_change(adj, ISIS_ADJ_UP, + NULL); + /* (9) adj usage level 2 */ + adj->adj_usage = ISIS_ADJ_LEVEL2; + } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) { + /* (7) down - wrong system */ + isis_adj_state_change(adj, + ISIS_ADJ_DOWN, + "Wrong System"); + } else if (adj->adj_usage + == ISIS_ADJ_LEVEL1AND2) { + if (hdr->circuit_t == IS_LEVEL_2) { + /* (7) down - wrong system */ + isis_adj_state_change( + adj, ISIS_ADJ_DOWN, + "Wrong System"); + } else { + /* (7) down - area mismatch */ + isis_adj_state_change( + adj, ISIS_ADJ_DOWN, + "Area Mismatch"); + } + } else if (adj->adj_usage == ISIS_ADJ_LEVEL2) { + ; /* Accept */ + } + break; + } } - break; - } + } else { + /* down - area mismatch */ + isis_adj_state_change(adj, ISIS_ADJ_DOWN, "Area Mismatch"); + } + /* 8.2.5.2 c) if the action was up - comparing circuit IDs */ + /* FIXME - Missing parts */ + + /* some of my own understanding of the ISO, why the heck does + * it not say what should I change the system_type to... + */ + switch (adj->adj_usage) { + case ISIS_ADJ_LEVEL1: + adj->sys_type = ISIS_SYSTYPE_L1_IS; + break; + case ISIS_ADJ_LEVEL2: + adj->sys_type = ISIS_SYSTYPE_L2_IS; + break; + case ISIS_ADJ_LEVEL1AND2: + adj->sys_type = ISIS_SYSTYPE_L2_IS; + break; + case ISIS_ADJ_NONE: + adj->sys_type = ISIS_SYSTYPE_UNKNOWN; + break; } - } - else - { - /* down - area mismatch */ - isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch"); - } - /* 8.2.5.2 c) if the action was up - comparing circuit IDs */ - /* FIXME - Missing parts */ - - /* some of my own understanding of the ISO, why the heck does - * it not say what should I change the system_type to... - */ - switch (adj->adj_usage) - { - case ISIS_ADJ_LEVEL1: - adj->sys_type = ISIS_SYSTYPE_L1_IS; - break; - case ISIS_ADJ_LEVEL2: - adj->sys_type = ISIS_SYSTYPE_L2_IS; - break; - case ISIS_ADJ_LEVEL1AND2: - adj->sys_type = ISIS_SYSTYPE_L2_IS; - break; - case ISIS_ADJ_NONE: - adj->sys_type = ISIS_SYSTYPE_UNKNOWN; - break; - } - if (isis->debugs & DEBUG_ADJ_PACKETS) - { - zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s," - " cir id %02d, length %d", - circuit->area->area_tag, circuit->interface->name, - circuit_t2string (circuit->is_type), - circuit->circuit_id, pdu_len); - } + if (isis->debugs & DEBUG_ADJ_PACKETS) { + zlog_debug( + "ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s," + " cir id %02d, length %d", + circuit->area->area_tag, circuit->interface->name, + circuit_t2string(circuit->is_type), circuit->circuit_id, + pdu_len); + } - free_tlvs (&tlvs); + free_tlvs(&tlvs); - return retval; + return retval; } /* * Process IS-IS LAN Level 1/2 Hello PDU */ -static int -process_lan_hello (int level, struct isis_circuit *circuit, const u_char *ssnpa) +static int process_lan_hello(int level, struct isis_circuit *circuit, + const u_char *ssnpa) { - int retval = ISIS_OK; - struct isis_lan_hello_hdr hdr; - struct isis_adjacency *adj; - u_int32_t expected = 0, found = 0, auth_tlv_offset = 0; - struct tlvs tlvs; - u_char *snpa; - struct listnode *node; - int v4_usable = 0, v6_usable = 0; - - if (isis->debugs & DEBUG_ADJ_PACKETS) - { - zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH on %s, cirType %s, " - "cirID %u", - circuit->area->area_tag, level, circuit->interface->name, - circuit_t2string (circuit->is_type), circuit->circuit_id); - if (isis->debugs & DEBUG_PACKET_DUMP) - zlog_dump_data (STREAM_DATA (circuit->rcv_stream), - stream_get_endp (circuit->rcv_stream)); - } + int retval = ISIS_OK; + struct isis_lan_hello_hdr hdr; + struct isis_adjacency *adj; + u_int32_t expected = 0, found = 0, auth_tlv_offset = 0; + struct tlvs tlvs; + u_char *snpa; + struct listnode *node; + int v4_usable = 0, v6_usable = 0; + + if (isis->debugs & DEBUG_ADJ_PACKETS) { + zlog_debug( + "ISIS-Adj (%s): Rcvd L%d LAN IIH on %s, cirType %s, " + "cirID %u", + circuit->area->area_tag, level, + circuit->interface->name, + circuit_t2string(circuit->is_type), + circuit->circuit_id); + if (isis->debugs & DEBUG_PACKET_DUMP) + zlog_dump_data(STREAM_DATA(circuit->rcv_stream), + stream_get_endp(circuit->rcv_stream)); + } - if (circuit->circ_type != CIRCUIT_T_BROADCAST) - { - zlog_warn ("lan hello on non broadcast circuit"); - return ISIS_WARNING; - } + if (circuit->circ_type != CIRCUIT_T_BROADCAST) { + zlog_warn("lan hello on non broadcast circuit"); + return ISIS_WARNING; + } - if ((stream_get_endp (circuit->rcv_stream) - - stream_get_getp (circuit->rcv_stream)) < ISIS_LANHELLO_HDRLEN) - { - zlog_warn ("Packet too short"); - return ISIS_WARNING; - } + if ((stream_get_endp(circuit->rcv_stream) + - stream_get_getp(circuit->rcv_stream)) + < ISIS_LANHELLO_HDRLEN) { + zlog_warn("Packet too short"); + return ISIS_WARNING; + } - if (circuit->ext_domain) - { - zlog_debug ("level %d LAN Hello received over circuit with " - "externalDomain = true", level); - return ISIS_WARNING; - } + if (circuit->ext_domain) { + zlog_debug( + "level %d LAN Hello received over circuit with " + "externalDomain = true", + level); + return ISIS_WARNING; + } - if (!accept_level (level, circuit->is_type)) - { - if (isis->debugs & DEBUG_ADJ_PACKETS) - { - zlog_debug ("ISIS-Adj (%s): Interface level mismatch, %s", - circuit->area->area_tag, circuit->interface->name); + if (!accept_level(level, circuit->is_type)) { + if (isis->debugs & DEBUG_ADJ_PACKETS) { + zlog_debug( + "ISIS-Adj (%s): Interface level mismatch, %s", + circuit->area->area_tag, + circuit->interface->name); + } + return ISIS_WARNING; } - return ISIS_WARNING; - } #if 0 /* Cisco's debug message compatability */ @@ -974,313 +928,301 @@ process_lan_hello (int level, struct isis_circuit *circuit, const u_char *ssnpa) return ISIS_WARNING; } #endif - /* - * Fill the header - */ - hdr.circuit_t = stream_getc (circuit->rcv_stream); - stream_get (hdr.source_id, circuit->rcv_stream, ISIS_SYS_ID_LEN); - hdr.hold_time = stream_getw (circuit->rcv_stream); - hdr.pdu_len = stream_getw (circuit->rcv_stream); - hdr.prio = stream_getc (circuit->rcv_stream); - stream_get (hdr.lan_id, circuit->rcv_stream, ISIS_SYS_ID_LEN + 1); - - if (hdr.pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_LANHELLO_HDRLEN) || - hdr.pdu_len > ISO_MTU(circuit) || - hdr.pdu_len > stream_get_endp (circuit->rcv_stream)) - { - zlog_warn ("ISIS-Adj (%s): Rcvd LAN IIH from (%s) with " - "invalid pdu length %d", - circuit->area->area_tag, circuit->interface->name, - hdr.pdu_len); - return ISIS_WARNING; - } + /* + * Fill the header + */ + hdr.circuit_t = stream_getc(circuit->rcv_stream); + stream_get(hdr.source_id, circuit->rcv_stream, ISIS_SYS_ID_LEN); + hdr.hold_time = stream_getw(circuit->rcv_stream); + hdr.pdu_len = stream_getw(circuit->rcv_stream); + hdr.prio = stream_getc(circuit->rcv_stream); + stream_get(hdr.lan_id, circuit->rcv_stream, ISIS_SYS_ID_LEN + 1); + + if (hdr.pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_LANHELLO_HDRLEN) + || hdr.pdu_len > ISO_MTU(circuit) + || hdr.pdu_len > stream_get_endp(circuit->rcv_stream)) { + zlog_warn( + "ISIS-Adj (%s): Rcvd LAN IIH from (%s) with " + "invalid pdu length %d", + circuit->area->area_tag, circuit->interface->name, + hdr.pdu_len); + return ISIS_WARNING; + } - /* - * Set the stream endp to PDU length, ignoring additional padding - * introduced by transport chips. - */ - if (hdr.pdu_len < stream_get_endp (circuit->rcv_stream)) - stream_set_endp (circuit->rcv_stream, hdr.pdu_len); - - if (hdr.circuit_t != IS_LEVEL_1 && - hdr.circuit_t != IS_LEVEL_2 && - hdr.circuit_t != IS_LEVEL_1_AND_2 && - (level & hdr.circuit_t) == 0) - { - zlog_err ("Level %d LAN Hello with Circuit Type %d", level, - hdr.circuit_t); - return ISIS_ERROR; - } + /* + * Set the stream endp to PDU length, ignoring additional padding + * introduced by transport chips. + */ + if (hdr.pdu_len < stream_get_endp(circuit->rcv_stream)) + stream_set_endp(circuit->rcv_stream, hdr.pdu_len); + + if (hdr.circuit_t != IS_LEVEL_1 && hdr.circuit_t != IS_LEVEL_2 + && hdr.circuit_t != IS_LEVEL_1_AND_2 + && (level & hdr.circuit_t) == 0) { + zlog_err("Level %d LAN Hello with Circuit Type %d", level, + hdr.circuit_t); + return ISIS_ERROR; + } - /* - * Then get the tlvs - */ - expected |= TLVFLAG_AUTH_INFO; - expected |= TLVFLAG_AREA_ADDRS; - expected |= TLVFLAG_LAN_NEIGHS; - expected |= TLVFLAG_NLPID; - expected |= TLVFLAG_IPV4_ADDR; - expected |= TLVFLAG_IPV6_ADDR; - - auth_tlv_offset = stream_get_getp (circuit->rcv_stream); - retval = parse_tlvs (circuit->area->area_tag, - STREAM_PNT (circuit->rcv_stream), - hdr.pdu_len - ISIS_LANHELLO_HDRLEN - ISIS_FIXED_HDR_LEN, - &expected, &found, &tlvs, - &auth_tlv_offset); - - if (retval > ISIS_WARNING) - { - zlog_warn ("parse_tlvs() failed"); - goto out; - } + /* + * Then get the tlvs + */ + expected |= TLVFLAG_AUTH_INFO; + expected |= TLVFLAG_AREA_ADDRS; + expected |= TLVFLAG_LAN_NEIGHS; + expected |= TLVFLAG_NLPID; + expected |= TLVFLAG_IPV4_ADDR; + expected |= TLVFLAG_IPV6_ADDR; + + auth_tlv_offset = stream_get_getp(circuit->rcv_stream); + retval = parse_tlvs( + circuit->area->area_tag, STREAM_PNT(circuit->rcv_stream), + hdr.pdu_len - ISIS_LANHELLO_HDRLEN - ISIS_FIXED_HDR_LEN, + &expected, &found, &tlvs, &auth_tlv_offset); + + if (retval > ISIS_WARNING) { + zlog_warn("parse_tlvs() failed"); + goto out; + } - if (!(found & TLVFLAG_AREA_ADDRS)) - { - zlog_warn ("No Area addresses TLV in Level %d LAN IS to IS hello", - level); - retval = ISIS_WARNING; - goto out; - } + if (!(found & TLVFLAG_AREA_ADDRS)) { + zlog_warn( + "No Area addresses TLV in Level %d LAN IS to IS hello", + level); + retval = ISIS_WARNING; + goto out; + } - if (!(found & TLVFLAG_NLPID)) - { - zlog_warn ("No supported protocols TLV in Level %d LAN IS to IS hello", - level); - retval = ISIS_WARNING; - goto out; - } + if (!(found & TLVFLAG_NLPID)) { + zlog_warn( + "No supported protocols TLV in Level %d LAN IS to IS hello", + level); + retval = ISIS_WARNING; + goto out; + } - /* Verify authentication, either cleartext of HMAC MD5 */ - if (circuit->passwd.type) - { - if (!(found & TLVFLAG_AUTH_INFO) || - authentication_check (&tlvs.auth_info, &circuit->passwd, - circuit->rcv_stream, auth_tlv_offset)) - { - isis_event_auth_failure (circuit->area->area_tag, - "LAN hello authentication failure", - hdr.source_id); - retval = ISIS_WARNING; - goto out; - } - } + /* Verify authentication, either cleartext of HMAC MD5 */ + if (circuit->passwd.type) { + if (!(found & TLVFLAG_AUTH_INFO) + || authentication_check(&tlvs.auth_info, &circuit->passwd, + circuit->rcv_stream, + auth_tlv_offset)) { + isis_event_auth_failure( + circuit->area->area_tag, + "LAN hello authentication failure", + hdr.source_id); + retval = ISIS_WARNING; + goto out; + } + } - if (!memcmp (hdr.source_id, isis->sysid, ISIS_SYS_ID_LEN)) - { - zlog_warn ("ISIS-Adj (%s): duplicate system ID on interface %s", - circuit->area->area_tag, circuit->interface->name); - return ISIS_WARNING; - } + if (!memcmp(hdr.source_id, isis->sysid, ISIS_SYS_ID_LEN)) { + zlog_warn("ISIS-Adj (%s): duplicate system ID on interface %s", + circuit->area->area_tag, circuit->interface->name); + return ISIS_WARNING; + } - /* - * Accept the level 1 adjacency only if a match between local and - * remote area addresses is found - */ - if (listcount (circuit->area->area_addrs) == 0 || - (level == IS_LEVEL_1 && - area_match (circuit->area->area_addrs, tlvs.area_addrs) == 0)) - { - if (isis->debugs & DEBUG_ADJ_PACKETS) - { - zlog_debug ("ISIS-Adj (%s): Area mismatch, level %d IIH on %s", - circuit->area->area_tag, level, - circuit->interface->name); + /* + * Accept the level 1 adjacency only if a match between local and + * remote area addresses is found + */ + if (listcount(circuit->area->area_addrs) == 0 + || (level == IS_LEVEL_1 + && area_match(circuit->area->area_addrs, tlvs.area_addrs) + == 0)) { + if (isis->debugs & DEBUG_ADJ_PACKETS) { + zlog_debug( + "ISIS-Adj (%s): Area mismatch, level %d IIH on %s", + circuit->area->area_tag, level, + circuit->interface->name); + } + retval = ISIS_OK; + goto out; } - retval = ISIS_OK; - goto out; - } - /* - * it's own IIH PDU - discard silently - */ - if (!memcmp (circuit->u.bc.snpa, ssnpa, ETH_ALEN)) - { - zlog_debug ("ISIS-Adj (%s): it's own IIH PDU - discarded", - circuit->area->area_tag); + /* + * it's own IIH PDU - discard silently + */ + if (!memcmp(circuit->u.bc.snpa, ssnpa, ETH_ALEN)) { + zlog_debug("ISIS-Adj (%s): it's own IIH PDU - discarded", + circuit->area->area_tag); - retval = ISIS_OK; - goto out; - } + retval = ISIS_OK; + goto out; + } - /* - * check if it's own interface ip match iih ip addrs - */ - if (found & TLVFLAG_IPV4_ADDR) - { - if (ip_match (circuit->ip_addrs, tlvs.ipv4_addrs)) - v4_usable = 1; - else - zlog_warn ("ISIS-Adj: IPv4 addresses present but no overlap " - "in LAN IIH from %s\n", circuit->interface->name); - } - if (found & TLVFLAG_IPV6_ADDR) - { - /* TBA: check that we have a linklocal ourselves? */ - struct listnode *node; - struct in6_addr *ip; - for (ALL_LIST_ELEMENTS_RO (tlvs.ipv6_addrs, node, ip)) - if (IN6_IS_ADDR_LINKLOCAL (ip)) - { - v6_usable = 1; - break; - } - - if (!v6_usable) - zlog_warn ("ISIS-Adj: IPv6 addresses present but no link-local " - "in LAN IIH from %s\n", circuit->interface->name); - } + /* + * check if it's own interface ip match iih ip addrs + */ + if (found & TLVFLAG_IPV4_ADDR) { + if (ip_match(circuit->ip_addrs, tlvs.ipv4_addrs)) + v4_usable = 1; + else + zlog_warn( + "ISIS-Adj: IPv4 addresses present but no overlap " + "in LAN IIH from %s\n", + circuit->interface->name); + } + if (found & TLVFLAG_IPV6_ADDR) { + /* TBA: check that we have a linklocal ourselves? */ + struct listnode *node; + struct in6_addr *ip; + for (ALL_LIST_ELEMENTS_RO(tlvs.ipv6_addrs, node, ip)) + if (IN6_IS_ADDR_LINKLOCAL(ip)) { + v6_usable = 1; + break; + } + + if (!v6_usable) + zlog_warn( + "ISIS-Adj: IPv6 addresses present but no link-local " + "in LAN IIH from %s\n", + circuit->interface->name); + } - if (!(found & (TLVFLAG_IPV4_ADDR | TLVFLAG_IPV6_ADDR))) - zlog_warn ("ISIS-Adj: neither IPv4 nor IPv6 addr in LAN IIH from %s\n", - circuit->interface->name); + if (!(found & (TLVFLAG_IPV4_ADDR | TLVFLAG_IPV6_ADDR))) + zlog_warn( + "ISIS-Adj: neither IPv4 nor IPv6 addr in LAN IIH from %s\n", + circuit->interface->name); - if (!v6_usable && !v4_usable) - { - free_tlvs (&tlvs); - return ISIS_WARNING; - } + if (!v6_usable && !v4_usable) { + free_tlvs(&tlvs); + return ISIS_WARNING; + } - adj = isis_adj_lookup (hdr.source_id, circuit->u.bc.adjdb[level - 1]); - if ((adj == NULL) || (memcmp(adj->snpa, ssnpa, ETH_ALEN)) || - (adj->level != level)) - { - if (!adj) - { - /* - * Do as in 8.4.2.5 - */ - adj = isis_new_adj (hdr.source_id, ssnpa, level, circuit); - if (adj == NULL) - { - retval = ISIS_ERROR; - goto out; - } - } - else - { - if (ssnpa) { - memcpy (adj->snpa, ssnpa, 6); - } else { - memset (adj->snpa, ' ', 6); - } - adj->level = level; - } - isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL); - - if (level == IS_LEVEL_1) - adj->sys_type = ISIS_SYSTYPE_L1_IS; - else - adj->sys_type = ISIS_SYSTYPE_L2_IS; - list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]); - isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1], - circuit->u.bc.lan_neighs[level - 1]); - } + adj = isis_adj_lookup(hdr.source_id, circuit->u.bc.adjdb[level - 1]); + if ((adj == NULL) || (memcmp(adj->snpa, ssnpa, ETH_ALEN)) + || (adj->level != level)) { + if (!adj) { + /* + * Do as in 8.4.2.5 + */ + adj = isis_new_adj(hdr.source_id, ssnpa, level, + circuit); + if (adj == NULL) { + retval = ISIS_ERROR; + goto out; + } + } else { + if (ssnpa) { + memcpy(adj->snpa, ssnpa, 6); + } else { + memset(adj->snpa, ' ', 6); + } + adj->level = level; + } + isis_adj_state_change(adj, ISIS_ADJ_INITIALIZING, NULL); - if(adj->dis_record[level-1].dis==ISIS_IS_DIS) - switch (level) - { - case 1: - if (memcmp (circuit->u.bc.l1_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1)) - { - thread_add_event (master, isis_event_dis_status_change, circuit, 0); - memcpy (&circuit->u.bc.l1_desig_is, hdr.lan_id, - ISIS_SYS_ID_LEN + 1); - } - break; - case 2: - if (memcmp (circuit->u.bc.l2_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1)) - { - thread_add_event (master, isis_event_dis_status_change, circuit, 0); - memcpy (&circuit->u.bc.l2_desig_is, hdr.lan_id, - ISIS_SYS_ID_LEN + 1); - } - break; - } - - adj->hold_time = hdr.hold_time; - adj->last_upd = time (NULL); - adj->prio[level - 1] = hdr.prio; - - memcpy (adj->lanid, hdr.lan_id, ISIS_SYS_ID_LEN + 1); - - tlvs_to_adj_area_addrs (&tlvs, adj); - - /* which protocol are spoken ??? */ - if (tlvs_to_adj_nlpids (&tlvs, adj)) - { - retval = ISIS_WARNING; - goto out; - } + if (level == IS_LEVEL_1) + adj->sys_type = ISIS_SYSTYPE_L1_IS; + else + adj->sys_type = ISIS_SYSTYPE_L2_IS; + list_delete_all_node(circuit->u.bc.lan_neighs[level - 1]); + isis_adj_build_neigh_list(circuit->u.bc.adjdb[level - 1], + circuit->u.bc.lan_neighs[level - 1]); + } - /* we need to copy addresses to the adj */ - if (found & TLVFLAG_IPV4_ADDR) - tlvs_to_adj_ipv4_addrs (&tlvs, adj); + if (adj->dis_record[level - 1].dis == ISIS_IS_DIS) + switch (level) { + case 1: + if (memcmp(circuit->u.bc.l1_desig_is, hdr.lan_id, + ISIS_SYS_ID_LEN + 1)) { + thread_add_event(master, + isis_event_dis_status_change, + circuit, 0); + memcpy(&circuit->u.bc.l1_desig_is, hdr.lan_id, + ISIS_SYS_ID_LEN + 1); + } + break; + case 2: + if (memcmp(circuit->u.bc.l2_desig_is, hdr.lan_id, + ISIS_SYS_ID_LEN + 1)) { + thread_add_event(master, + isis_event_dis_status_change, + circuit, 0); + memcpy(&circuit->u.bc.l2_desig_is, hdr.lan_id, + ISIS_SYS_ID_LEN + 1); + } + break; + } - if (found & TLVFLAG_IPV6_ADDR) - tlvs_to_adj_ipv6_addrs (&tlvs, adj); + adj->hold_time = hdr.hold_time; + adj->last_upd = time(NULL); + adj->prio[level - 1] = hdr.prio; - adj->circuit_t = hdr.circuit_t; + memcpy(adj->lanid, hdr.lan_id, ISIS_SYS_ID_LEN + 1); - /* lets take care of the expiry */ - THREAD_TIMER_OFF (adj->t_expire); - THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj, - (long) adj->hold_time); + tlvs_to_adj_area_addrs(&tlvs, adj); - /* - * If the snpa for this circuit is found from LAN Neighbours TLV - * we have two-way communication -> adjacency can be put to state "up" - */ + /* which protocol are spoken ??? */ + if (tlvs_to_adj_nlpids(&tlvs, adj)) { + retval = ISIS_WARNING; + goto out; + } - if (found & TLVFLAG_LAN_NEIGHS) - { - if (adj->adj_state != ISIS_ADJ_UP) - { - for (ALL_LIST_ELEMENTS_RO (tlvs.lan_neighs, node, snpa)) - { - if (!memcmp (snpa, circuit->u.bc.snpa, ETH_ALEN)) - { - isis_adj_state_change (adj, ISIS_ADJ_UP, - "own SNPA found in LAN Neighbours TLV"); - } - } - } - else - { - int found = 0; - for (ALL_LIST_ELEMENTS_RO (tlvs.lan_neighs, node, snpa)) - if (!memcmp (snpa, circuit->u.bc.snpa, ETH_ALEN)) - { - found = 1; - break; - } - if (found == 0) - isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, - "own SNPA not found in LAN Neighbours TLV"); - } - } - else if (adj->adj_state == ISIS_ADJ_UP) - { - isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, - "no LAN Neighbours TLV found"); - } + /* we need to copy addresses to the adj */ + if (found & TLVFLAG_IPV4_ADDR) + tlvs_to_adj_ipv4_addrs(&tlvs, adj); + + if (found & TLVFLAG_IPV6_ADDR) + tlvs_to_adj_ipv6_addrs(&tlvs, adj); + + adj->circuit_t = hdr.circuit_t; + + /* lets take care of the expiry */ + THREAD_TIMER_OFF(adj->t_expire); + THREAD_TIMER_ON(master, adj->t_expire, isis_adj_expire, adj, + (long)adj->hold_time); + + /* + * If the snpa for this circuit is found from LAN Neighbours TLV + * we have two-way communication -> adjacency can be put to state "up" + */ + + if (found & TLVFLAG_LAN_NEIGHS) { + if (adj->adj_state != ISIS_ADJ_UP) { + for (ALL_LIST_ELEMENTS_RO(tlvs.lan_neighs, node, + snpa)) { + if (!memcmp(snpa, circuit->u.bc.snpa, + ETH_ALEN)) { + isis_adj_state_change( + adj, ISIS_ADJ_UP, + "own SNPA found in LAN Neighbours TLV"); + } + } + } else { + int found = 0; + for (ALL_LIST_ELEMENTS_RO(tlvs.lan_neighs, node, snpa)) + if (!memcmp(snpa, circuit->u.bc.snpa, + ETH_ALEN)) { + found = 1; + break; + } + if (found == 0) + isis_adj_state_change( + adj, ISIS_ADJ_INITIALIZING, + "own SNPA not found in LAN Neighbours TLV"); + } + } else if (adj->adj_state == ISIS_ADJ_UP) { + isis_adj_state_change(adj, ISIS_ADJ_INITIALIZING, + "no LAN Neighbours TLV found"); + } out: - if (isis->debugs & DEBUG_ADJ_PACKETS) - { - zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH from %s on %s, cirType %s, " - "cirID %u, length %zd", - circuit->area->area_tag, - level, snpa_print (ssnpa), circuit->interface->name, - circuit_t2string (circuit->is_type), - circuit->circuit_id, - stream_get_endp (circuit->rcv_stream)); - } + if (isis->debugs & DEBUG_ADJ_PACKETS) { + zlog_debug( + "ISIS-Adj (%s): Rcvd L%d LAN IIH from %s on %s, cirType %s, " + "cirID %u, length %zd", + circuit->area->area_tag, level, snpa_print(ssnpa), + circuit->interface->name, + circuit_t2string(circuit->is_type), circuit->circuit_id, + stream_get_endp(circuit->rcv_stream)); + } - free_tlvs (&tlvs); + free_tlvs(&tlvs); - return retval; + return retval; } /* @@ -1288,363 +1230,361 @@ out: * ISO - 10589 * Section 7.3.15.1 - Action on receipt of a link state PDU */ -static int -process_lsp (int level, struct isis_circuit *circuit, const u_char *ssnpa) +static int process_lsp(int level, struct isis_circuit *circuit, + const u_char *ssnpa) { - struct isis_link_state_hdr *hdr; - struct isis_adjacency *adj = NULL; - struct isis_lsp *lsp, *lsp0 = NULL; - int retval = ISIS_OK, comp = 0; - u_char lspid[ISIS_SYS_ID_LEN + 2]; - struct isis_passwd *passwd; - uint16_t pdu_len; - int lsp_confusion; - - if (isis->debugs & DEBUG_UPDATE_PACKETS) - { - zlog_debug ("ISIS-Upd (%s): Rcvd L%d LSP on %s, cirType %s, cirID %u", - circuit->area->area_tag, level, circuit->interface->name, - circuit_t2string (circuit->is_type), circuit->circuit_id); - if (isis->debugs & DEBUG_PACKET_DUMP) - zlog_dump_data (STREAM_DATA (circuit->rcv_stream), - stream_get_endp (circuit->rcv_stream)); - } - - if ((stream_get_endp (circuit->rcv_stream) - - stream_get_getp (circuit->rcv_stream)) < ISIS_LSP_HDR_LEN) - { - zlog_warn ("Packet too short"); - return ISIS_WARNING; - } + struct isis_link_state_hdr *hdr; + struct isis_adjacency *adj = NULL; + struct isis_lsp *lsp, *lsp0 = NULL; + int retval = ISIS_OK, comp = 0; + u_char lspid[ISIS_SYS_ID_LEN + 2]; + struct isis_passwd *passwd; + uint16_t pdu_len; + int lsp_confusion; + + if (isis->debugs & DEBUG_UPDATE_PACKETS) { + zlog_debug( + "ISIS-Upd (%s): Rcvd L%d LSP on %s, cirType %s, cirID %u", + circuit->area->area_tag, level, + circuit->interface->name, + circuit_t2string(circuit->is_type), + circuit->circuit_id); + if (isis->debugs & DEBUG_PACKET_DUMP) + zlog_dump_data(STREAM_DATA(circuit->rcv_stream), + stream_get_endp(circuit->rcv_stream)); + } - /* Reference the header */ - hdr = (struct isis_link_state_hdr *) STREAM_PNT (circuit->rcv_stream); - pdu_len = ntohs (hdr->pdu_len); + if ((stream_get_endp(circuit->rcv_stream) + - stream_get_getp(circuit->rcv_stream)) + < ISIS_LSP_HDR_LEN) { + zlog_warn("Packet too short"); + return ISIS_WARNING; + } - /* lsp length check */ - if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN) || - pdu_len > ISO_MTU(circuit) || - pdu_len > stream_get_endp (circuit->rcv_stream)) - { - zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP length %d", - circuit->area->area_tag, - rawlspid_print (hdr->lsp_id), pdu_len); + /* Reference the header */ + hdr = (struct isis_link_state_hdr *)STREAM_PNT(circuit->rcv_stream); + pdu_len = ntohs(hdr->pdu_len); - return ISIS_WARNING; - } - - /* - * Set the stream endp to PDU length, ignoring additional padding - * introduced by transport chips. - */ - if (pdu_len < stream_get_endp (circuit->rcv_stream)) - stream_set_endp (circuit->rcv_stream, pdu_len); + /* lsp length check */ + if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN) + || pdu_len > ISO_MTU(circuit) + || pdu_len > stream_get_endp(circuit->rcv_stream)) { + zlog_debug("ISIS-Upd (%s): LSP %s invalid LSP length %d", + circuit->area->area_tag, rawlspid_print(hdr->lsp_id), + pdu_len); - if (isis->debugs & DEBUG_UPDATE_PACKETS) - { - zlog_debug ("ISIS-Upd (%s): Rcvd L%d LSP %s, seq 0x%08x, cksum 0x%04x, " - "lifetime %us, len %u, on %s", - circuit->area->area_tag, - level, - rawlspid_print (hdr->lsp_id), - ntohl (hdr->seq_num), - ntohs (hdr->checksum), - ntohs (hdr->rem_lifetime), - pdu_len, - circuit->interface->name); - } - - /* lsp is_type check */ - if ((hdr->lsp_bits & IS_LEVEL_1_AND_2) != IS_LEVEL_1 && - (hdr->lsp_bits & IS_LEVEL_1_AND_2) != IS_LEVEL_1_AND_2) - { - zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP is type %x", - circuit->area->area_tag, - rawlspid_print (hdr->lsp_id), hdr->lsp_bits); - /* continue as per RFC1122 Be liberal in what you accept, and - * conservative in what you send */ - } - - /* Checksum sanity check - FIXME: move to correct place */ - /* 12 = sysid+pdu+remtime */ - if (iso_csum_verify (STREAM_PNT (circuit->rcv_stream) + 4, - pdu_len - 12, &hdr->checksum)) - { - zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP checksum 0x%04x", - circuit->area->area_tag, - rawlspid_print (hdr->lsp_id), ntohs (hdr->checksum)); + return ISIS_WARNING; + } - return ISIS_WARNING; - } + /* + * Set the stream endp to PDU length, ignoring additional padding + * introduced by transport chips. + */ + if (pdu_len < stream_get_endp(circuit->rcv_stream)) + stream_set_endp(circuit->rcv_stream, pdu_len); + + if (isis->debugs & DEBUG_UPDATE_PACKETS) { + zlog_debug( + "ISIS-Upd (%s): Rcvd L%d LSP %s, seq 0x%08x, cksum 0x%04x, " + "lifetime %us, len %u, on %s", + circuit->area->area_tag, level, + rawlspid_print(hdr->lsp_id), ntohl(hdr->seq_num), + ntohs(hdr->checksum), ntohs(hdr->rem_lifetime), pdu_len, + circuit->interface->name); + } - /* 7.3.15.1 a) 1 - external domain circuit will discard lsps */ - if (circuit->ext_domain) - { - zlog_debug - ("ISIS-Upd (%s): LSP %s received at level %d over circuit with " - "externalDomain = true", circuit->area->area_tag, - rawlspid_print (hdr->lsp_id), level); + /* lsp is_type check */ + if ((hdr->lsp_bits & IS_LEVEL_1_AND_2) != IS_LEVEL_1 + && (hdr->lsp_bits & IS_LEVEL_1_AND_2) != IS_LEVEL_1_AND_2) { + zlog_debug("ISIS-Upd (%s): LSP %s invalid LSP is type %x", + circuit->area->area_tag, rawlspid_print(hdr->lsp_id), + hdr->lsp_bits); + /* continue as per RFC1122 Be liberal in what you accept, and + * conservative in what you send */ + } - return ISIS_WARNING; - } + /* Checksum sanity check - FIXME: move to correct place */ + /* 12 = sysid+pdu+remtime */ + if (iso_csum_verify(STREAM_PNT(circuit->rcv_stream) + 4, pdu_len - 12, + &hdr->checksum)) { + zlog_debug("ISIS-Upd (%s): LSP %s invalid LSP checksum 0x%04x", + circuit->area->area_tag, rawlspid_print(hdr->lsp_id), + ntohs(hdr->checksum)); - /* 7.3.15.1 a) 2,3 - manualL2OnlyMode not implemented */ - if (!accept_level (level, circuit->is_type)) - { - zlog_debug ("ISIS-Upd (%s): LSP %s received at level %d over circuit of" - " type %s", - circuit->area->area_tag, - rawlspid_print (hdr->lsp_id), - level, circuit_t2string (circuit->is_type)); + return ISIS_WARNING; + } - return ISIS_WARNING; - } + /* 7.3.15.1 a) 1 - external domain circuit will discard lsps */ + if (circuit->ext_domain) { + zlog_debug( + "ISIS-Upd (%s): LSP %s received at level %d over circuit with " + "externalDomain = true", + circuit->area->area_tag, rawlspid_print(hdr->lsp_id), + level); - /* 7.3.15.1 a) 4 - need to make sure IDLength matches */ + return ISIS_WARNING; + } - /* 7.3.15.1 a) 5 - maximum area match, can be ommited since we only use 3 */ + /* 7.3.15.1 a) 2,3 - manualL2OnlyMode not implemented */ + if (!accept_level(level, circuit->is_type)) { + zlog_debug( + "ISIS-Upd (%s): LSP %s received at level %d over circuit of" + " type %s", + circuit->area->area_tag, rawlspid_print(hdr->lsp_id), + level, circuit_t2string(circuit->is_type)); - /* 7.3.15.1 a) 7 - password check */ - (level == IS_LEVEL_1) ? (passwd = &circuit->area->area_passwd) : - (passwd = &circuit->area->domain_passwd); - if (passwd->type) - { - if (lsp_authentication_check (circuit->rcv_stream, circuit->area, - level, passwd)) - { - isis_event_auth_failure (circuit->area->area_tag, - "LSP authentication failure", hdr->lsp_id); - return ISIS_WARNING; + return ISIS_WARNING; } - } - /* Find the LSP in our database and compare it to this Link State header */ - lsp = lsp_search (hdr->lsp_id, circuit->area->lspdb[level - 1]); - if (lsp) - comp = lsp_compare (circuit->area->area_tag, lsp, hdr->seq_num, - hdr->checksum, hdr->rem_lifetime); - if (lsp && (lsp->own_lsp)) - goto dontcheckadj; - - /* 7.3.15.1 a) 6 - Must check that we have an adjacency of the same level */ - /* for broadcast circuits, snpa should be compared */ - - if (circuit->circ_type == CIRCUIT_T_BROADCAST) - { - adj = isis_adj_lookup_snpa (ssnpa, circuit->u.bc.adjdb[level - 1]); - if (!adj) - { - zlog_debug ("(%s): DS ======= LSP %s, seq 0x%08x, cksum 0x%04x, " - "lifetime %us on %s", - circuit->area->area_tag, - rawlspid_print (hdr->lsp_id), - ntohl (hdr->seq_num), - ntohs (hdr->checksum), - ntohs (hdr->rem_lifetime), circuit->interface->name); - return ISIS_WARNING; /* Silently discard */ + + /* 7.3.15.1 a) 4 - need to make sure IDLength matches */ + + /* 7.3.15.1 a) 5 - maximum area match, can be ommited since we only use + * 3 */ + + /* 7.3.15.1 a) 7 - password check */ + (level == IS_LEVEL_1) ? (passwd = &circuit->area->area_passwd) + : (passwd = &circuit->area->domain_passwd); + if (passwd->type) { + if (lsp_authentication_check(circuit->rcv_stream, circuit->area, + level, passwd)) { + isis_event_auth_failure(circuit->area->area_tag, + "LSP authentication failure", + hdr->lsp_id); + return ISIS_WARNING; + } } - } - /* for non broadcast, we just need to find same level adj */ - else - { - /* If no adj, or no sharing of level */ - if (!circuit->u.p2p.neighbor) - { - return ISIS_OK; /* Silently discard */ + /* Find the LSP in our database and compare it to this Link State header + */ + lsp = lsp_search(hdr->lsp_id, circuit->area->lspdb[level - 1]); + if (lsp) + comp = lsp_compare(circuit->area->area_tag, lsp, hdr->seq_num, + hdr->checksum, hdr->rem_lifetime); + if (lsp && (lsp->own_lsp)) + goto dontcheckadj; + + /* 7.3.15.1 a) 6 - Must check that we have an adjacency of the same + * level */ + /* for broadcast circuits, snpa should be compared */ + + if (circuit->circ_type == CIRCUIT_T_BROADCAST) { + adj = isis_adj_lookup_snpa(ssnpa, + circuit->u.bc.adjdb[level - 1]); + if (!adj) { + zlog_debug( + "(%s): DS ======= LSP %s, seq 0x%08x, cksum 0x%04x, " + "lifetime %us on %s", + circuit->area->area_tag, + rawlspid_print(hdr->lsp_id), + ntohl(hdr->seq_num), ntohs(hdr->checksum), + ntohs(hdr->rem_lifetime), + circuit->interface->name); + return ISIS_WARNING; /* Silently discard */ + } } - else - { - if (((level == IS_LEVEL_1) && - (circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL2)) || - ((level == IS_LEVEL_2) && - (circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL1))) - return ISIS_WARNING; /* Silently discard */ + /* for non broadcast, we just need to find same level adj */ + else { + /* If no adj, or no sharing of level */ + if (!circuit->u.p2p.neighbor) { + return ISIS_OK; /* Silently discard */ + } else { + if (((level == IS_LEVEL_1) + && (circuit->u.p2p.neighbor->adj_usage + == ISIS_ADJ_LEVEL2)) + || ((level == IS_LEVEL_2) + && (circuit->u.p2p.neighbor->adj_usage + == ISIS_ADJ_LEVEL1))) + return ISIS_WARNING; /* Silently discard */ + } } - } dontcheckadj: - /* 7.3.15.1 a) 7 - Passwords for level 1 - not implemented */ - - /* 7.3.15.1 a) 8 - Passwords for level 2 - not implemented */ - - /* 7.3.15.1 a) 9 - OriginatingLSPBufferSize - not implemented FIXME: do it */ - - /* 7.3.16.2 - If this is an LSP from another IS with identical seq_num but - * wrong checksum, initiate a purge. */ - if (lsp - && (lsp->lsp_header->seq_num == hdr->seq_num) - && (lsp->lsp_header->checksum != hdr->checksum)) - { - zlog_warn("ISIS-Upd (%s): LSP %s seq 0x%08x with confused checksum received.", - circuit->area->area_tag, rawlspid_print(hdr->lsp_id), - ntohl(hdr->seq_num)); - hdr->rem_lifetime = 0; - lsp_confusion = 1; - } - else - lsp_confusion = 0; - - /* 7.3.15.1 b) - If the remaining life time is 0, we perform 7.3.16.4 */ - if (hdr->rem_lifetime == 0) - { - if (!lsp) - { - /* 7.3.16.4 a) 1) No LSP in db -> send an ack, but don't save */ - /* only needed on explicit update, eg - p2p */ - if (circuit->circ_type == CIRCUIT_T_P2P) - ack_lsp (hdr, circuit, level); - return retval; /* FIXME: do we need a purge? */ - } - else - { - if (memcmp (hdr->lsp_id, isis->sysid, ISIS_SYS_ID_LEN)) - { - /* LSP by some other system -> do 7.3.16.4 b) */ - /* 7.3.16.4 b) 1) */ - if (comp == LSP_NEWER) - { - lsp_update (lsp, circuit->rcv_stream, circuit->area, level); - /* ii */ - lsp_set_all_srmflags (lsp); - /* v */ - ISIS_FLAGS_CLEAR_ALL (lsp->SSNflags); /* FIXME: OTHER than c */ - - /* For the case of lsp confusion, flood the purge back to its - * originator so that it can react. Otherwise, don't reflood - * through incoming circuit as usual */ - if (!lsp_confusion) - { - /* iii */ - ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); - /* iv */ - if (circuit->circ_type != CIRCUIT_T_BROADCAST) - ISIS_SET_FLAG (lsp->SSNflags, circuit); - } - } /* 7.3.16.4 b) 2) */ - else if (comp == LSP_EQUAL) - { - /* i */ - ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); - /* ii */ - if (circuit->circ_type != CIRCUIT_T_BROADCAST) - ISIS_SET_FLAG (lsp->SSNflags, circuit); - } /* 7.3.16.4 b) 3) */ - else - { - ISIS_SET_FLAG (lsp->SRMflags, circuit); - ISIS_CLEAR_FLAG (lsp->SSNflags, circuit); + /* 7.3.15.1 a) 7 - Passwords for level 1 - not implemented */ + + /* 7.3.15.1 a) 8 - Passwords for level 2 - not implemented */ + + /* 7.3.15.1 a) 9 - OriginatingLSPBufferSize - not implemented FIXME: do + * it */ + + /* 7.3.16.2 - If this is an LSP from another IS with identical seq_num + * but + * wrong checksum, initiate a purge. */ + if (lsp && (lsp->lsp_header->seq_num == hdr->seq_num) + && (lsp->lsp_header->checksum != hdr->checksum)) { + zlog_warn( + "ISIS-Upd (%s): LSP %s seq 0x%08x with confused checksum received.", + circuit->area->area_tag, rawlspid_print(hdr->lsp_id), + ntohl(hdr->seq_num)); + hdr->rem_lifetime = 0; + lsp_confusion = 1; + } else + lsp_confusion = 0; + + /* 7.3.15.1 b) - If the remaining life time is 0, we perform 7.3.16.4 */ + if (hdr->rem_lifetime == 0) { + if (!lsp) { + /* 7.3.16.4 a) 1) No LSP in db -> send an ack, but don't + * save */ + /* only needed on explicit update, eg - p2p */ + if (circuit->circ_type == CIRCUIT_T_P2P) + ack_lsp(hdr, circuit, level); + return retval; /* FIXME: do we need a purge? */ + } else { + if (memcmp(hdr->lsp_id, isis->sysid, ISIS_SYS_ID_LEN)) { + /* LSP by some other system -> do 7.3.16.4 b) */ + /* 7.3.16.4 b) 1) */ + if (comp == LSP_NEWER) { + lsp_update(lsp, circuit->rcv_stream, + circuit->area, level); + /* ii */ + lsp_set_all_srmflags(lsp); + /* v */ + ISIS_FLAGS_CLEAR_ALL( + lsp + ->SSNflags); /* FIXME: + OTHER + than c + */ + + /* For the case of lsp confusion, flood + * the purge back to its + * originator so that it can react. + * Otherwise, don't reflood + * through incoming circuit as usual */ + if (!lsp_confusion) { + /* iii */ + ISIS_CLEAR_FLAG(lsp->SRMflags, + circuit); + /* iv */ + if (circuit->circ_type + != CIRCUIT_T_BROADCAST) + ISIS_SET_FLAG( + lsp->SSNflags, + circuit); + } + } /* 7.3.16.4 b) 2) */ + else if (comp == LSP_EQUAL) { + /* i */ + ISIS_CLEAR_FLAG(lsp->SRMflags, circuit); + /* ii */ + if (circuit->circ_type + != CIRCUIT_T_BROADCAST) + ISIS_SET_FLAG(lsp->SSNflags, + circuit); + } /* 7.3.16.4 b) 3) */ + else { + ISIS_SET_FLAG(lsp->SRMflags, circuit); + ISIS_CLEAR_FLAG(lsp->SSNflags, circuit); + } + } else if (lsp->lsp_header->rem_lifetime != 0) { + /* our own LSP -> 7.3.16.4 c) */ + if (comp == LSP_NEWER) { + lsp_inc_seqnum(lsp, + ntohl(hdr->seq_num)); + lsp_set_all_srmflags(lsp); + } else { + ISIS_SET_FLAG(lsp->SRMflags, circuit); + ISIS_CLEAR_FLAG(lsp->SSNflags, circuit); + } + if (isis->debugs & DEBUG_UPDATE_PACKETS) + zlog_debug( + "ISIS-Upd (%s): (1) re-originating LSP %s new " + "seq 0x%08x", + circuit->area->area_tag, + rawlspid_print(hdr->lsp_id), + ntohl(lsp->lsp_header + ->seq_num)); + } } - } - else if (lsp->lsp_header->rem_lifetime != 0) - { - /* our own LSP -> 7.3.16.4 c) */ - if (comp == LSP_NEWER) - { - lsp_inc_seqnum (lsp, ntohl (hdr->seq_num)); - lsp_set_all_srmflags (lsp); - } - else - { - ISIS_SET_FLAG (lsp->SRMflags, circuit); - ISIS_CLEAR_FLAG (lsp->SSNflags, circuit); - } - if (isis->debugs & DEBUG_UPDATE_PACKETS) - zlog_debug ("ISIS-Upd (%s): (1) re-originating LSP %s new " - "seq 0x%08x", circuit->area->area_tag, - rawlspid_print (hdr->lsp_id), - ntohl (lsp->lsp_header->seq_num)); - } - } - return retval; - } - /* 7.3.15.1 c) - If this is our own lsp and we don't have it initiate a - * purge */ - if (memcmp (hdr->lsp_id, isis->sysid, ISIS_SYS_ID_LEN) == 0) - { - if (!lsp) - { - /* 7.3.16.4: initiate a purge */ - lsp_purge_non_exist(level, hdr, circuit->area); - return ISIS_OK; + return retval; } - /* 7.3.15.1 d) - If this is our own lsp and we have it */ - - /* In 7.3.16.1, If an Intermediate system R somewhere in the domain - * has information that the current sequence number for source S is - * "greater" than that held by S, ... */ - - if (ntohl (hdr->seq_num) > ntohl (lsp->lsp_header->seq_num)) - { - /* 7.3.16.1 */ - lsp_inc_seqnum (lsp, ntohl (hdr->seq_num)); - if (isis->debugs & DEBUG_UPDATE_PACKETS) - zlog_debug ("ISIS-Upd (%s): (2) re-originating LSP %s new seq " - "0x%08x", circuit->area->area_tag, - rawlspid_print (hdr->lsp_id), - ntohl (lsp->lsp_header->seq_num)); - } - /* If the received LSP is older or equal, - * resend the LSP which will act as ACK */ - lsp_set_all_srmflags (lsp); - } - else - { - /* 7.3.15.1 e) - This lsp originated on another system */ - - /* 7.3.15.1 e) 1) LSP newer than the one in db or no LSP in db */ - if ((!lsp || comp == LSP_NEWER)) - { - /* - * If this lsp is a frag, need to see if we have zero lsp present - */ - if (LSP_FRAGMENT (hdr->lsp_id) != 0) - { - memcpy (lspid, hdr->lsp_id, ISIS_SYS_ID_LEN + 1); - LSP_FRAGMENT (lspid) = 0; - lsp0 = lsp_search (lspid, circuit->area->lspdb[level - 1]); - if (!lsp0) - { - zlog_debug ("Got lsp frag, while zero lsp not in database"); - return ISIS_OK; + /* 7.3.15.1 c) - If this is our own lsp and we don't have it initiate a + * purge */ + if (memcmp(hdr->lsp_id, isis->sysid, ISIS_SYS_ID_LEN) == 0) { + if (!lsp) { + /* 7.3.16.4: initiate a purge */ + lsp_purge_non_exist(level, hdr, circuit->area); + return ISIS_OK; + } + /* 7.3.15.1 d) - If this is our own lsp and we have it */ + + /* In 7.3.16.1, If an Intermediate system R somewhere in the + * domain + * has information that the current sequence number for source S + * is + * "greater" than that held by S, ... */ + + if (ntohl(hdr->seq_num) > ntohl(lsp->lsp_header->seq_num)) { + /* 7.3.16.1 */ + lsp_inc_seqnum(lsp, ntohl(hdr->seq_num)); + if (isis->debugs & DEBUG_UPDATE_PACKETS) + zlog_debug( + "ISIS-Upd (%s): (2) re-originating LSP %s new seq " + "0x%08x", + circuit->area->area_tag, + rawlspid_print(hdr->lsp_id), + ntohl(lsp->lsp_header->seq_num)); + } + /* If the received LSP is older or equal, + * resend the LSP which will act as ACK */ + lsp_set_all_srmflags(lsp); + } else { + /* 7.3.15.1 e) - This lsp originated on another system */ + + /* 7.3.15.1 e) 1) LSP newer than the one in db or no LSP in db + */ + if ((!lsp || comp == LSP_NEWER)) { + /* + * If this lsp is a frag, need to see if we have zero + * lsp present + */ + if (LSP_FRAGMENT(hdr->lsp_id) != 0) { + memcpy(lspid, hdr->lsp_id, ISIS_SYS_ID_LEN + 1); + LSP_FRAGMENT(lspid) = 0; + lsp0 = lsp_search( + lspid, circuit->area->lspdb[level - 1]); + if (!lsp0) { + zlog_debug( + "Got lsp frag, while zero lsp not in database"); + return ISIS_OK; + } + } + /* i */ + if (!lsp) { + lsp = lsp_new_from_stream_ptr( + circuit->rcv_stream, pdu_len, lsp0, + circuit->area, level); + lsp_insert(lsp, + circuit->area->lspdb[level - 1]); + } else /* exists, so we overwrite */ + { + lsp_update(lsp, circuit->rcv_stream, + circuit->area, level); + } + /* ii */ + lsp_set_all_srmflags(lsp); + /* iii */ + ISIS_CLEAR_FLAG(lsp->SRMflags, circuit); + + /* iv */ + if (circuit->circ_type != CIRCUIT_T_BROADCAST) + ISIS_SET_FLAG(lsp->SSNflags, circuit); + /* FIXME: v) */ + } + /* 7.3.15.1 e) 2) LSP equal to the one in db */ + else if (comp == LSP_EQUAL) { + ISIS_CLEAR_FLAG(lsp->SRMflags, circuit); + lsp_update(lsp, circuit->rcv_stream, circuit->area, + level); + if (circuit->circ_type != CIRCUIT_T_BROADCAST) + ISIS_SET_FLAG(lsp->SSNflags, circuit); + } + /* 7.3.15.1 e) 3) LSP older than the one in db */ + else { + ISIS_SET_FLAG(lsp->SRMflags, circuit); + ISIS_CLEAR_FLAG(lsp->SSNflags, circuit); } - } - /* i */ - if (!lsp) - { - lsp = lsp_new_from_stream_ptr (circuit->rcv_stream, - pdu_len, lsp0, - circuit->area, level); - lsp_insert (lsp, circuit->area->lspdb[level - 1]); - } - else /* exists, so we overwrite */ - { - lsp_update (lsp, circuit->rcv_stream, circuit->area, level); - } - /* ii */ - lsp_set_all_srmflags (lsp); - /* iii */ - ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); - - /* iv */ - if (circuit->circ_type != CIRCUIT_T_BROADCAST) - ISIS_SET_FLAG (lsp->SSNflags, circuit); - /* FIXME: v) */ - } - /* 7.3.15.1 e) 2) LSP equal to the one in db */ - else if (comp == LSP_EQUAL) - { - ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); - lsp_update (lsp, circuit->rcv_stream, circuit->area, level); - if (circuit->circ_type != CIRCUIT_T_BROADCAST) - ISIS_SET_FLAG (lsp->SSNflags, circuit); - } - /* 7.3.15.1 e) 3) LSP older than the one in db */ - else - { - ISIS_SET_FLAG (lsp->SRMflags, circuit); - ISIS_CLEAR_FLAG (lsp->SSNflags, circuit); } - } - return retval; + return retval; } /* @@ -1653,1535 +1593,1494 @@ dontcheckadj: * Section 7.3.15.2 - Action on receipt of a sequence numbers PDU */ -static int -process_snp (int snp_type, int level, struct isis_circuit *circuit, - const u_char *ssnpa) +static int process_snp(int snp_type, int level, struct isis_circuit *circuit, + const u_char *ssnpa) { - int retval = ISIS_OK; - int cmp, own_lsp; - char typechar = ' '; - uint16_t pdu_len; - struct isis_adjacency *adj; - struct isis_complete_seqnum_hdr *chdr = NULL; - struct isis_partial_seqnum_hdr *phdr = NULL; - uint32_t found = 0, expected = 0, auth_tlv_offset = 0; - struct isis_lsp *lsp; - struct lsp_entry *entry; - struct listnode *node, *nnode; - struct listnode *node2, *nnode2; - struct tlvs tlvs; - struct list *lsp_list = NULL; - struct isis_passwd *passwd; - - if (snp_type == ISIS_SNP_CSNP_FLAG) - { - /* getting the header info */ - typechar = 'C'; - chdr = - (struct isis_complete_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream); - stream_forward_getp (circuit->rcv_stream, ISIS_CSNP_HDRLEN); - pdu_len = ntohs (chdr->pdu_len); - if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_CSNP_HDRLEN) || - pdu_len > ISO_MTU(circuit) || - pdu_len > stream_get_endp (circuit->rcv_stream)) - { - zlog_warn ("Received a CSNP with bogus length %d", pdu_len); - return ISIS_WARNING; - } - } - else - { - typechar = 'P'; - phdr = - (struct isis_partial_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream); - stream_forward_getp (circuit->rcv_stream, ISIS_PSNP_HDRLEN); - pdu_len = ntohs (phdr->pdu_len); - if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_PSNP_HDRLEN) || - pdu_len > ISO_MTU(circuit) || - pdu_len > stream_get_endp (circuit->rcv_stream)) - { - zlog_warn ("Received a PSNP with bogus length %d", pdu_len); - return ISIS_WARNING; + int retval = ISIS_OK; + int cmp, own_lsp; + char typechar = ' '; + uint16_t pdu_len; + struct isis_adjacency *adj; + struct isis_complete_seqnum_hdr *chdr = NULL; + struct isis_partial_seqnum_hdr *phdr = NULL; + uint32_t found = 0, expected = 0, auth_tlv_offset = 0; + struct isis_lsp *lsp; + struct lsp_entry *entry; + struct listnode *node, *nnode; + struct listnode *node2, *nnode2; + struct tlvs tlvs; + struct list *lsp_list = NULL; + struct isis_passwd *passwd; + + if (snp_type == ISIS_SNP_CSNP_FLAG) { + /* getting the header info */ + typechar = 'C'; + chdr = (struct isis_complete_seqnum_hdr *)STREAM_PNT( + circuit->rcv_stream); + stream_forward_getp(circuit->rcv_stream, ISIS_CSNP_HDRLEN); + pdu_len = ntohs(chdr->pdu_len); + if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_CSNP_HDRLEN) + || pdu_len > ISO_MTU(circuit) + || pdu_len > stream_get_endp(circuit->rcv_stream)) { + zlog_warn("Received a CSNP with bogus length %d", + pdu_len); + return ISIS_WARNING; + } + } else { + typechar = 'P'; + phdr = (struct isis_partial_seqnum_hdr *)STREAM_PNT( + circuit->rcv_stream); + stream_forward_getp(circuit->rcv_stream, ISIS_PSNP_HDRLEN); + pdu_len = ntohs(phdr->pdu_len); + if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_PSNP_HDRLEN) + || pdu_len > ISO_MTU(circuit) + || pdu_len > stream_get_endp(circuit->rcv_stream)) { + zlog_warn("Received a PSNP with bogus length %d", + pdu_len); + return ISIS_WARNING; + } } - } - /* - * Set the stream endp to PDU length, ignoring additional padding - * introduced by transport chips. - */ - if (pdu_len < stream_get_endp (circuit->rcv_stream)) - stream_set_endp (circuit->rcv_stream, pdu_len); + /* + * Set the stream endp to PDU length, ignoring additional padding + * introduced by transport chips. + */ + if (pdu_len < stream_get_endp(circuit->rcv_stream)) + stream_set_endp(circuit->rcv_stream, pdu_len); - /* 7.3.15.2 a) 1 - external domain circuit will discard snp pdu */ - if (circuit->ext_domain) - { - - zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, " - "skipping: circuit externalDomain = true", - circuit->area->area_tag, - level, typechar, circuit->interface->name); + /* 7.3.15.2 a) 1 - external domain circuit will discard snp pdu */ + if (circuit->ext_domain) { - return ISIS_OK; - } + zlog_debug( + "ISIS-Snp (%s): Rcvd L%d %cSNP on %s, " + "skipping: circuit externalDomain = true", + circuit->area->area_tag, level, typechar, + circuit->interface->name); - /* 7.3.15.2 a) 2,3 - manualL2OnlyMode not implemented */ - if (!accept_level (level, circuit->is_type)) - { - - zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, " - "skipping: circuit type %s does not match level %d", - circuit->area->area_tag, - level, - typechar, - circuit->interface->name, - circuit_t2string (circuit->is_type), level); - - return ISIS_OK; - } - - /* 7.3.15.2 a) 4 - not applicable for CSNP only PSNPs on broadcast */ - if ((snp_type == ISIS_SNP_PSNP_FLAG) && - (circuit->circ_type == CIRCUIT_T_BROADCAST) && - (!circuit->u.bc.is_dr[level - 1])) - { - zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s, " - "skipping: we are not the DIS", - circuit->area->area_tag, - level, - typechar, snpa_print (ssnpa), circuit->interface->name); - - return ISIS_OK; - } + return ISIS_OK; + } - /* 7.3.15.2 a) 5 - need to make sure IDLength matches - already checked */ + /* 7.3.15.2 a) 2,3 - manualL2OnlyMode not implemented */ + if (!accept_level(level, circuit->is_type)) { - /* 7.3.15.2 a) 6 - maximum area match, can be ommited since we only use 3 - * - already checked */ + zlog_debug( + "ISIS-Snp (%s): Rcvd L%d %cSNP on %s, " + "skipping: circuit type %s does not match level %d", + circuit->area->area_tag, level, typechar, + circuit->interface->name, + circuit_t2string(circuit->is_type), level); - /* 7.3.15.2 a) 7 - Must check that we have an adjacency of the same level */ - /* for broadcast circuits, snpa should be compared */ - /* FIXME : Do we need to check SNPA? */ - if (circuit->circ_type == CIRCUIT_T_BROADCAST) - { - if (snp_type == ISIS_SNP_CSNP_FLAG) - { - adj = - isis_adj_lookup (chdr->source_id, circuit->u.bc.adjdb[level - 1]); - } - else - { - /* a psnp on a broadcast, how lovely of Juniper :) */ - adj = - isis_adj_lookup (phdr->source_id, circuit->u.bc.adjdb[level - 1]); + return ISIS_OK; } - if (!adj) - return ISIS_OK; /* Silently discard */ - } - else - { - if (!circuit->u.p2p.neighbor) - { - zlog_warn ("no p2p neighbor on circuit %s", circuit->interface->name); - return ISIS_OK; /* Silently discard */ - } - } - - /* 7.3.15.2 a) 8 - Passwords for level 1 - not implemented */ - /* 7.3.15.2 a) 9 - Passwords for level 2 - not implemented */ + /* 7.3.15.2 a) 4 - not applicable for CSNP only PSNPs on broadcast */ + if ((snp_type == ISIS_SNP_PSNP_FLAG) + && (circuit->circ_type == CIRCUIT_T_BROADCAST) + && (!circuit->u.bc.is_dr[level - 1])) { + zlog_debug( + "ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s, " + "skipping: we are not the DIS", + circuit->area->area_tag, level, typechar, + snpa_print(ssnpa), circuit->interface->name); + + return ISIS_OK; + } - memset (&tlvs, 0, sizeof (struct tlvs)); + /* 7.3.15.2 a) 5 - need to make sure IDLength matches - already checked + */ + + /* 7.3.15.2 a) 6 - maximum area match, can be ommited since we only use + * 3 + * - already checked */ + + /* 7.3.15.2 a) 7 - Must check that we have an adjacency of the same + * level */ + /* for broadcast circuits, snpa should be compared */ + /* FIXME : Do we need to check SNPA? */ + if (circuit->circ_type == CIRCUIT_T_BROADCAST) { + if (snp_type == ISIS_SNP_CSNP_FLAG) { + adj = isis_adj_lookup(chdr->source_id, + circuit->u.bc.adjdb[level - 1]); + } else { + /* a psnp on a broadcast, how lovely of Juniper :) */ + adj = isis_adj_lookup(phdr->source_id, + circuit->u.bc.adjdb[level - 1]); + } + if (!adj) + return ISIS_OK; /* Silently discard */ + } else { + if (!circuit->u.p2p.neighbor) { + zlog_warn("no p2p neighbor on circuit %s", + circuit->interface->name); + return ISIS_OK; /* Silently discard */ + } + } - /* parse the SNP */ - expected |= TLVFLAG_LSP_ENTRIES; - expected |= TLVFLAG_AUTH_INFO; + /* 7.3.15.2 a) 8 - Passwords for level 1 - not implemented */ - auth_tlv_offset = stream_get_getp (circuit->rcv_stream); - retval = parse_tlvs (circuit->area->area_tag, - STREAM_PNT (circuit->rcv_stream), - pdu_len - stream_get_getp (circuit->rcv_stream), - &expected, &found, &tlvs, &auth_tlv_offset); + /* 7.3.15.2 a) 9 - Passwords for level 2 - not implemented */ - if (retval > ISIS_WARNING) - { - zlog_warn ("something went very wrong processing SNP"); - free_tlvs (&tlvs); - return retval; - } + memset(&tlvs, 0, sizeof(struct tlvs)); - if (level == IS_LEVEL_1) - passwd = &circuit->area->area_passwd; - else - passwd = &circuit->area->domain_passwd; + /* parse the SNP */ + expected |= TLVFLAG_LSP_ENTRIES; + expected |= TLVFLAG_AUTH_INFO; - if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_RECV)) - { - if (passwd->type) - { - if (!(found & TLVFLAG_AUTH_INFO) || - authentication_check (&tlvs.auth_info, passwd, - circuit->rcv_stream, auth_tlv_offset)) - { - isis_event_auth_failure (circuit->area->area_tag, - "SNP authentication" " failure", - phdr ? phdr->source_id : - chdr->source_id); - free_tlvs (&tlvs); - return ISIS_OK; - } - } - } + auth_tlv_offset = stream_get_getp(circuit->rcv_stream); + retval = parse_tlvs(circuit->area->area_tag, + STREAM_PNT(circuit->rcv_stream), + pdu_len - stream_get_getp(circuit->rcv_stream), + &expected, &found, &tlvs, &auth_tlv_offset); - /* debug isis snp-packets */ - if (isis->debugs & DEBUG_SNP_PACKETS) - { - zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s", - circuit->area->area_tag, - level, - typechar, snpa_print (ssnpa), circuit->interface->name); - if (tlvs.lsp_entries) - { - for (ALL_LIST_ELEMENTS_RO (tlvs.lsp_entries, node, entry)) - { - zlog_debug ("ISIS-Snp (%s): %cSNP entry %s, seq 0x%08x," - " cksum 0x%04x, lifetime %us", - circuit->area->area_tag, - typechar, - rawlspid_print (entry->lsp_id), - ntohl (entry->seq_num), - ntohs (entry->checksum), ntohs (entry->rem_lifetime)); - } + if (retval > ISIS_WARNING) { + zlog_warn("something went very wrong processing SNP"); + free_tlvs(&tlvs); + return retval; } - } - /* 7.3.15.2 b) Actions on LSP_ENTRIES reported */ - if (tlvs.lsp_entries) - { - for (ALL_LIST_ELEMENTS_RO (tlvs.lsp_entries, node, entry)) - { - lsp = lsp_search (entry->lsp_id, circuit->area->lspdb[level - 1]); - own_lsp = !memcmp (entry->lsp_id, isis->sysid, ISIS_SYS_ID_LEN); - if (lsp) - { - /* 7.3.15.2 b) 1) is this LSP newer */ - cmp = lsp_compare (circuit->area->area_tag, lsp, entry->seq_num, - entry->checksum, entry->rem_lifetime); - /* 7.3.15.2 b) 2) if it equals, clear SRM on p2p */ - if (cmp == LSP_EQUAL) - { - /* if (circuit->circ_type != CIRCUIT_T_BROADCAST) */ - ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); - } - /* 7.3.15.2 b) 3) if it is older, clear SSN and set SRM */ - else if (cmp == LSP_OLDER) - { - ISIS_CLEAR_FLAG (lsp->SSNflags, circuit); - ISIS_SET_FLAG (lsp->SRMflags, circuit); - } - /* 7.3.15.2 b) 4) if it is newer, set SSN and clear SRM on p2p */ - else - { - if (own_lsp) - { - lsp_inc_seqnum (lsp, ntohl (entry->seq_num)); - ISIS_SET_FLAG (lsp->SRMflags, circuit); - } - else - { - ISIS_SET_FLAG (lsp->SSNflags, circuit); - /* if (circuit->circ_type != CIRCUIT_T_BROADCAST) */ - ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); - } - } - } + if (level == IS_LEVEL_1) + passwd = &circuit->area->area_passwd; else - { - /* 7.3.15.2 b) 5) if it was not found, and all of those are not 0, - * insert it and set SSN on it */ - if (entry->rem_lifetime && entry->checksum && entry->seq_num && - memcmp (entry->lsp_id, isis->sysid, ISIS_SYS_ID_LEN)) - { - lsp = lsp_new(circuit->area, entry->lsp_id, - ntohs(entry->rem_lifetime), - 0, 0, entry->checksum, level); - lsp_insert (lsp, circuit->area->lspdb[level - 1]); - ISIS_FLAGS_CLEAR_ALL (lsp->SRMflags); - ISIS_SET_FLAG (lsp->SSNflags, circuit); - } - } - } - } + passwd = &circuit->area->domain_passwd; + + if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_RECV)) { + if (passwd->type) { + if (!(found & TLVFLAG_AUTH_INFO) + || authentication_check(&tlvs.auth_info, passwd, + circuit->rcv_stream, + auth_tlv_offset)) { + isis_event_auth_failure(circuit->area->area_tag, + "SNP authentication" + " failure", + phdr ? phdr->source_id + : chdr->source_id); + free_tlvs(&tlvs); + return ISIS_OK; + } + } + } - /* 7.3.15.2 c) on CSNP set SRM for all in range which were not reported */ - if (snp_type == ISIS_SNP_CSNP_FLAG) - { - /* - * Build a list from our own LSP db bounded with - * start_lsp_id and stop_lsp_id - */ - lsp_list = list_new (); - lsp_build_list_nonzero_ht (chdr->start_lsp_id, chdr->stop_lsp_id, - lsp_list, circuit->area->lspdb[level - 1]); - - /* Fixme: Find a better solution */ - if (tlvs.lsp_entries) - { - for (ALL_LIST_ELEMENTS (tlvs.lsp_entries, node, nnode, entry)) - { - for (ALL_LIST_ELEMENTS (lsp_list, node2, nnode2, lsp)) - { - if (lsp_id_cmp (lsp->lsp_header->lsp_id, entry->lsp_id) == 0) - { - list_delete_node (lsp_list, node2); - break; + /* debug isis snp-packets */ + if (isis->debugs & DEBUG_SNP_PACKETS) { + zlog_debug("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s", + circuit->area->area_tag, level, typechar, + snpa_print(ssnpa), circuit->interface->name); + if (tlvs.lsp_entries) { + for (ALL_LIST_ELEMENTS_RO(tlvs.lsp_entries, node, + entry)) { + zlog_debug( + "ISIS-Snp (%s): %cSNP entry %s, seq 0x%08x," + " cksum 0x%04x, lifetime %us", + circuit->area->area_tag, typechar, + rawlspid_print(entry->lsp_id), + ntohl(entry->seq_num), + ntohs(entry->checksum), + ntohs(entry->rem_lifetime)); + } } - } - } } - /* on remaining LSPs we set SRM (neighbor knew not of) */ - for (ALL_LIST_ELEMENTS_RO (lsp_list, node, lsp)) - ISIS_SET_FLAG (lsp->SRMflags, circuit); - /* lets free it */ - list_delete (lsp_list); - } + /* 7.3.15.2 b) Actions on LSP_ENTRIES reported */ + if (tlvs.lsp_entries) { + for (ALL_LIST_ELEMENTS_RO(tlvs.lsp_entries, node, entry)) { + lsp = lsp_search(entry->lsp_id, + circuit->area->lspdb[level - 1]); + own_lsp = !memcmp(entry->lsp_id, isis->sysid, + ISIS_SYS_ID_LEN); + if (lsp) { + /* 7.3.15.2 b) 1) is this LSP newer */ + cmp = lsp_compare(circuit->area->area_tag, lsp, + entry->seq_num, + entry->checksum, + entry->rem_lifetime); + /* 7.3.15.2 b) 2) if it equals, clear SRM on p2p + */ + if (cmp == LSP_EQUAL) { + /* if (circuit->circ_type != + * CIRCUIT_T_BROADCAST) */ + ISIS_CLEAR_FLAG(lsp->SRMflags, circuit); + } + /* 7.3.15.2 b) 3) if it is older, clear SSN and + set SRM */ + else if (cmp == LSP_OLDER) { + ISIS_CLEAR_FLAG(lsp->SSNflags, circuit); + ISIS_SET_FLAG(lsp->SRMflags, circuit); + } + /* 7.3.15.2 b) 4) if it is newer, set SSN and + clear SRM on p2p */ + else { + if (own_lsp) { + lsp_inc_seqnum( + lsp, + ntohl(entry->seq_num)); + ISIS_SET_FLAG(lsp->SRMflags, + circuit); + } else { + ISIS_SET_FLAG(lsp->SSNflags, + circuit); + /* if (circuit->circ_type != + * CIRCUIT_T_BROADCAST) */ + ISIS_CLEAR_FLAG(lsp->SRMflags, + circuit); + } + } + } else { + /* 7.3.15.2 b) 5) if it was not found, and all + * of those are not 0, + * insert it and set SSN on it */ + if (entry->rem_lifetime && entry->checksum + && entry->seq_num + && memcmp(entry->lsp_id, isis->sysid, + ISIS_SYS_ID_LEN)) { + lsp = lsp_new( + circuit->area, entry->lsp_id, + ntohs(entry->rem_lifetime), 0, + 0, entry->checksum, level); + lsp_insert(lsp, + circuit->area + ->lspdb[level - 1]); + ISIS_FLAGS_CLEAR_ALL(lsp->SRMflags); + ISIS_SET_FLAG(lsp->SSNflags, circuit); + } + } + } + } + + /* 7.3.15.2 c) on CSNP set SRM for all in range which were not reported + */ + if (snp_type == ISIS_SNP_CSNP_FLAG) { + /* + * Build a list from our own LSP db bounded with + * start_lsp_id and stop_lsp_id + */ + lsp_list = list_new(); + lsp_build_list_nonzero_ht(chdr->start_lsp_id, chdr->stop_lsp_id, + lsp_list, + circuit->area->lspdb[level - 1]); + + /* Fixme: Find a better solution */ + if (tlvs.lsp_entries) { + for (ALL_LIST_ELEMENTS(tlvs.lsp_entries, node, nnode, + entry)) { + for (ALL_LIST_ELEMENTS(lsp_list, node2, nnode2, + lsp)) { + if (lsp_id_cmp(lsp->lsp_header->lsp_id, + entry->lsp_id) + == 0) { + list_delete_node(lsp_list, + node2); + break; + } + } + } + } + /* on remaining LSPs we set SRM (neighbor knew not of) */ + for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp)) + ISIS_SET_FLAG(lsp->SRMflags, circuit); + /* lets free it */ + list_delete(lsp_list); + } - free_tlvs (&tlvs); - return retval; + free_tlvs(&tlvs); + return retval; } -static int -process_csnp (int level, struct isis_circuit *circuit, const u_char *ssnpa) +static int process_csnp(int level, struct isis_circuit *circuit, + const u_char *ssnpa) { - if (isis->debugs & DEBUG_SNP_PACKETS) - { - zlog_debug ("ISIS-Snp (%s): Rcvd L%d CSNP on %s, cirType %s, cirID %u", - circuit->area->area_tag, level, circuit->interface->name, - circuit_t2string (circuit->is_type), circuit->circuit_id); - if (isis->debugs & DEBUG_PACKET_DUMP) - zlog_dump_data (STREAM_DATA (circuit->rcv_stream), - stream_get_endp (circuit->rcv_stream)); - } + if (isis->debugs & DEBUG_SNP_PACKETS) { + zlog_debug( + "ISIS-Snp (%s): Rcvd L%d CSNP on %s, cirType %s, cirID %u", + circuit->area->area_tag, level, + circuit->interface->name, + circuit_t2string(circuit->is_type), + circuit->circuit_id); + if (isis->debugs & DEBUG_PACKET_DUMP) + zlog_dump_data(STREAM_DATA(circuit->rcv_stream), + stream_get_endp(circuit->rcv_stream)); + } - /* Sanity check - FIXME: move to correct place */ - if ((stream_get_endp (circuit->rcv_stream) - - stream_get_getp (circuit->rcv_stream)) < ISIS_CSNP_HDRLEN) - { - zlog_warn ("Packet too short ( < %d)", ISIS_CSNP_HDRLEN); - return ISIS_WARNING; - } + /* Sanity check - FIXME: move to correct place */ + if ((stream_get_endp(circuit->rcv_stream) + - stream_get_getp(circuit->rcv_stream)) + < ISIS_CSNP_HDRLEN) { + zlog_warn("Packet too short ( < %d)", ISIS_CSNP_HDRLEN); + return ISIS_WARNING; + } - return process_snp (ISIS_SNP_CSNP_FLAG, level, circuit, ssnpa); + return process_snp(ISIS_SNP_CSNP_FLAG, level, circuit, ssnpa); } -static int -process_psnp (int level, struct isis_circuit *circuit, const u_char *ssnpa) +static int process_psnp(int level, struct isis_circuit *circuit, + const u_char *ssnpa) { - if (isis->debugs & DEBUG_SNP_PACKETS) - { - zlog_debug ("ISIS-Snp (%s): Rcvd L%d PSNP on %s, cirType %s, cirID %u", - circuit->area->area_tag, level, circuit->interface->name, - circuit_t2string (circuit->is_type), circuit->circuit_id); - if (isis->debugs & DEBUG_PACKET_DUMP) - zlog_dump_data (STREAM_DATA (circuit->rcv_stream), - stream_get_endp (circuit->rcv_stream)); - } + if (isis->debugs & DEBUG_SNP_PACKETS) { + zlog_debug( + "ISIS-Snp (%s): Rcvd L%d PSNP on %s, cirType %s, cirID %u", + circuit->area->area_tag, level, + circuit->interface->name, + circuit_t2string(circuit->is_type), + circuit->circuit_id); + if (isis->debugs & DEBUG_PACKET_DUMP) + zlog_dump_data(STREAM_DATA(circuit->rcv_stream), + stream_get_endp(circuit->rcv_stream)); + } - if ((stream_get_endp (circuit->rcv_stream) - - stream_get_getp (circuit->rcv_stream)) < ISIS_PSNP_HDRLEN) - { - zlog_warn ("Packet too short ( < %d)", ISIS_PSNP_HDRLEN); - return ISIS_WARNING; - } + if ((stream_get_endp(circuit->rcv_stream) + - stream_get_getp(circuit->rcv_stream)) + < ISIS_PSNP_HDRLEN) { + zlog_warn("Packet too short ( < %d)", ISIS_PSNP_HDRLEN); + return ISIS_WARNING; + } - return process_snp (ISIS_SNP_PSNP_FLAG, level, circuit, ssnpa); + return process_snp(ISIS_SNP_PSNP_FLAG, level, circuit, ssnpa); } /* * PDU Dispatcher */ -static int -isis_handle_pdu (struct isis_circuit *circuit, u_char * ssnpa) +static int isis_handle_pdu(struct isis_circuit *circuit, u_char *ssnpa) { - struct isis_fixed_hdr *hdr; + struct isis_fixed_hdr *hdr; - int retval = ISIS_OK; + int retval = ISIS_OK; - /* - * Let's first read data from stream to the header - */ - hdr = (struct isis_fixed_hdr *) STREAM_DATA (circuit->rcv_stream); + /* + * Let's first read data from stream to the header + */ + hdr = (struct isis_fixed_hdr *)STREAM_DATA(circuit->rcv_stream); - if ((hdr->idrp != ISO10589_ISIS) && (hdr->idrp != ISO9542_ESIS)) - { - zlog_err ("Not an IS-IS or ES-IS packet IDRP=%02x", hdr->idrp); - return ISIS_ERROR; - } + if ((hdr->idrp != ISO10589_ISIS) && (hdr->idrp != ISO9542_ESIS)) { + zlog_err("Not an IS-IS or ES-IS packet IDRP=%02x", hdr->idrp); + return ISIS_ERROR; + } - /* now we need to know if this is an ISO 9542 packet and - * take real good care of it, waaa! - */ - if (hdr->idrp == ISO9542_ESIS) - { - zlog_err ("No support for ES-IS packet IDRP=%02x", hdr->idrp); - return ISIS_ERROR; - } - stream_set_getp (circuit->rcv_stream, ISIS_FIXED_HDR_LEN); + /* now we need to know if this is an ISO 9542 packet and + * take real good care of it, waaa! + */ + if (hdr->idrp == ISO9542_ESIS) { + zlog_err("No support for ES-IS packet IDRP=%02x", hdr->idrp); + return ISIS_ERROR; + } + stream_set_getp(circuit->rcv_stream, ISIS_FIXED_HDR_LEN); - /* - * and then process it - */ + /* + * and then process it + */ - if (hdr->length < ISIS_MINIMUM_FIXED_HDR_LEN) - { - zlog_err ("Fixed header length = %d", hdr->length); - return ISIS_ERROR; - } + if (hdr->length < ISIS_MINIMUM_FIXED_HDR_LEN) { + zlog_err("Fixed header length = %d", hdr->length); + return ISIS_ERROR; + } - if (hdr->version1 != 1) - { - zlog_warn ("Unsupported ISIS version %u", hdr->version1); - return ISIS_WARNING; - } - /* either 6 or 0 */ - if ((hdr->id_len != 0) && (hdr->id_len != ISIS_SYS_ID_LEN)) - { - zlog_err - ("IDFieldLengthMismatch: ID Length field in a received PDU %u, " - "while the parameter for this IS is %u", hdr->id_len, - ISIS_SYS_ID_LEN); - return ISIS_ERROR; - } + if (hdr->version1 != 1) { + zlog_warn("Unsupported ISIS version %u", hdr->version1); + return ISIS_WARNING; + } + /* either 6 or 0 */ + if ((hdr->id_len != 0) && (hdr->id_len != ISIS_SYS_ID_LEN)) { + zlog_err( + "IDFieldLengthMismatch: ID Length field in a received PDU %u, " + "while the parameter for this IS is %u", + hdr->id_len, ISIS_SYS_ID_LEN); + return ISIS_ERROR; + } - if (hdr->version2 != 1) - { - zlog_warn ("Unsupported ISIS version %u", hdr->version2); - return ISIS_WARNING; - } + if (hdr->version2 != 1) { + zlog_warn("Unsupported ISIS version %u", hdr->version2); + return ISIS_WARNING; + } - if (circuit->is_passive) - { - zlog_warn ("Received ISIS PDU on passive circuit %s", - circuit->interface->name); - return ISIS_WARNING; - } + if (circuit->is_passive) { + zlog_warn("Received ISIS PDU on passive circuit %s", + circuit->interface->name); + return ISIS_WARNING; + } - /* either 3 or 0 */ - if ((hdr->max_area_addrs != 0) - && (hdr->max_area_addrs != isis->max_area_addrs)) - { - zlog_err ("maximumAreaAddressesMismatch: maximumAreaAdresses in a " - "received PDU %u while the parameter for this IS is %u", - hdr->max_area_addrs, isis->max_area_addrs); - return ISIS_ERROR; - } + /* either 3 or 0 */ + if ((hdr->max_area_addrs != 0) + && (hdr->max_area_addrs != isis->max_area_addrs)) { + zlog_err( + "maximumAreaAddressesMismatch: maximumAreaAdresses in a " + "received PDU %u while the parameter for this IS is %u", + hdr->max_area_addrs, isis->max_area_addrs); + return ISIS_ERROR; + } - switch (hdr->pdu_type) - { - case L1_LAN_HELLO: - retval = process_lan_hello (ISIS_LEVEL1, circuit, ssnpa); - break; - case L2_LAN_HELLO: - retval = process_lan_hello (ISIS_LEVEL2, circuit, ssnpa); - break; - case P2P_HELLO: - retval = process_p2p_hello (circuit); - break; - case L1_LINK_STATE: - retval = process_lsp (ISIS_LEVEL1, circuit, ssnpa); - break; - case L2_LINK_STATE: - retval = process_lsp (ISIS_LEVEL2, circuit, ssnpa); - break; - case L1_COMPLETE_SEQ_NUM: - retval = process_csnp (ISIS_LEVEL1, circuit, ssnpa); - break; - case L2_COMPLETE_SEQ_NUM: - retval = process_csnp (ISIS_LEVEL2, circuit, ssnpa); - break; - case L1_PARTIAL_SEQ_NUM: - retval = process_psnp (ISIS_LEVEL1, circuit, ssnpa); - break; - case L2_PARTIAL_SEQ_NUM: - retval = process_psnp (ISIS_LEVEL2, circuit, ssnpa); - break; - default: - return ISIS_ERROR; - } + switch (hdr->pdu_type) { + case L1_LAN_HELLO: + retval = process_lan_hello(ISIS_LEVEL1, circuit, ssnpa); + break; + case L2_LAN_HELLO: + retval = process_lan_hello(ISIS_LEVEL2, circuit, ssnpa); + break; + case P2P_HELLO: + retval = process_p2p_hello(circuit); + break; + case L1_LINK_STATE: + retval = process_lsp(ISIS_LEVEL1, circuit, ssnpa); + break; + case L2_LINK_STATE: + retval = process_lsp(ISIS_LEVEL2, circuit, ssnpa); + break; + case L1_COMPLETE_SEQ_NUM: + retval = process_csnp(ISIS_LEVEL1, circuit, ssnpa); + break; + case L2_COMPLETE_SEQ_NUM: + retval = process_csnp(ISIS_LEVEL2, circuit, ssnpa); + break; + case L1_PARTIAL_SEQ_NUM: + retval = process_psnp(ISIS_LEVEL1, circuit, ssnpa); + break; + case L2_PARTIAL_SEQ_NUM: + retval = process_psnp(ISIS_LEVEL2, circuit, ssnpa); + break; + default: + return ISIS_ERROR; + } - return retval; + return retval; } -int -isis_receive (struct thread *thread) +int isis_receive(struct thread *thread) { - struct isis_circuit *circuit; - u_char ssnpa[ETH_ALEN]; - int retval; + struct isis_circuit *circuit; + u_char ssnpa[ETH_ALEN]; + int retval; - /* - * Get the circuit - */ - circuit = THREAD_ARG (thread); - assert (circuit); + /* + * Get the circuit + */ + circuit = THREAD_ARG(thread); + assert(circuit); - circuit->t_read = NULL; + circuit->t_read = NULL; - isis_circuit_stream(circuit, &circuit->rcv_stream); + isis_circuit_stream(circuit, &circuit->rcv_stream); - retval = circuit->rx (circuit, ssnpa); + retval = circuit->rx(circuit, ssnpa); - if (retval == ISIS_OK) - retval = isis_handle_pdu (circuit, ssnpa); + if (retval == ISIS_OK) + retval = isis_handle_pdu(circuit, ssnpa); - /* - * prepare for next packet. - */ - if (!circuit->is_passive) - isis_circuit_prepare (circuit); + /* + * prepare for next packet. + */ + if (!circuit->is_passive) + isis_circuit_prepare(circuit); - return retval; + return retval; } - /* filling of the fixed isis header */ -void -fill_fixed_hdr (struct isis_fixed_hdr *hdr, u_char pdu_type) +/* filling of the fixed isis header */ +void fill_fixed_hdr(struct isis_fixed_hdr *hdr, u_char pdu_type) { - memset (hdr, 0, sizeof (struct isis_fixed_hdr)); - - hdr->idrp = ISO10589_ISIS; - - switch (pdu_type) - { - case L1_LAN_HELLO: - case L2_LAN_HELLO: - hdr->length = ISIS_LANHELLO_HDRLEN; - break; - case P2P_HELLO: - hdr->length = ISIS_P2PHELLO_HDRLEN; - break; - case L1_LINK_STATE: - case L2_LINK_STATE: - hdr->length = ISIS_LSP_HDR_LEN; - break; - case L1_COMPLETE_SEQ_NUM: - case L2_COMPLETE_SEQ_NUM: - hdr->length = ISIS_CSNP_HDRLEN; - break; - case L1_PARTIAL_SEQ_NUM: - case L2_PARTIAL_SEQ_NUM: - hdr->length = ISIS_PSNP_HDRLEN; - break; - default: - zlog_warn ("fill_fixed_hdr(): unknown pdu type %d", pdu_type); - return; - } - hdr->length += ISIS_FIXED_HDR_LEN; - hdr->pdu_type = pdu_type; - hdr->version1 = 1; - hdr->id_len = 0; /* ISIS_SYS_ID_LEN - 0==6 */ - hdr->version2 = 1; - hdr->max_area_addrs = 0; /* isis->max_area_addrs - 0==3 */ + memset(hdr, 0, sizeof(struct isis_fixed_hdr)); + + hdr->idrp = ISO10589_ISIS; + + switch (pdu_type) { + case L1_LAN_HELLO: + case L2_LAN_HELLO: + hdr->length = ISIS_LANHELLO_HDRLEN; + break; + case P2P_HELLO: + hdr->length = ISIS_P2PHELLO_HDRLEN; + break; + case L1_LINK_STATE: + case L2_LINK_STATE: + hdr->length = ISIS_LSP_HDR_LEN; + break; + case L1_COMPLETE_SEQ_NUM: + case L2_COMPLETE_SEQ_NUM: + hdr->length = ISIS_CSNP_HDRLEN; + break; + case L1_PARTIAL_SEQ_NUM: + case L2_PARTIAL_SEQ_NUM: + hdr->length = ISIS_PSNP_HDRLEN; + break; + default: + zlog_warn("fill_fixed_hdr(): unknown pdu type %d", pdu_type); + return; + } + hdr->length += ISIS_FIXED_HDR_LEN; + hdr->pdu_type = pdu_type; + hdr->version1 = 1; + hdr->id_len = 0; /* ISIS_SYS_ID_LEN - 0==6 */ + hdr->version2 = 1; + hdr->max_area_addrs = 0; /* isis->max_area_addrs - 0==3 */ } /* - * SEND SIDE + * SEND SIDE */ -static void -fill_fixed_hdr_andstream (struct isis_fixed_hdr *hdr, u_char pdu_type, - struct stream *stream) +static void fill_fixed_hdr_andstream(struct isis_fixed_hdr *hdr, + u_char pdu_type, struct stream *stream) { - fill_fixed_hdr (hdr, pdu_type); - - stream_putc (stream, hdr->idrp); - stream_putc (stream, hdr->length); - stream_putc (stream, hdr->version1); - stream_putc (stream, hdr->id_len); - stream_putc (stream, hdr->pdu_type); - stream_putc (stream, hdr->version2); - stream_putc (stream, hdr->reserved); - stream_putc (stream, hdr->max_area_addrs); - - return; + fill_fixed_hdr(hdr, pdu_type); + + stream_putc(stream, hdr->idrp); + stream_putc(stream, hdr->length); + stream_putc(stream, hdr->version1); + stream_putc(stream, hdr->id_len); + stream_putc(stream, hdr->pdu_type); + stream_putc(stream, hdr->version2); + stream_putc(stream, hdr->reserved); + stream_putc(stream, hdr->max_area_addrs); + + return; } -int -send_hello (struct isis_circuit *circuit, int level) +int send_hello(struct isis_circuit *circuit, int level) { - struct isis_fixed_hdr fixed_hdr; - struct isis_lan_hello_hdr hello_hdr; - struct isis_p2p_hello_hdr p2p_hello_hdr; - unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; - size_t len_pointer, length, auth_tlv_offset = 0; - u_int32_t interval; - int retval; - - if (circuit->is_passive) - return ISIS_OK; - - if (circuit->interface->mtu == 0) - { - zlog_warn ("circuit has zero MTU"); - return ISIS_WARNING; - } - - isis_circuit_stream(circuit, &circuit->snd_stream); - - if (circuit->circ_type == CIRCUIT_T_BROADCAST) - if (level == IS_LEVEL_1) - fill_fixed_hdr_andstream (&fixed_hdr, L1_LAN_HELLO, - circuit->snd_stream); - else - fill_fixed_hdr_andstream (&fixed_hdr, L2_LAN_HELLO, - circuit->snd_stream); - else - fill_fixed_hdr_andstream (&fixed_hdr, P2P_HELLO, circuit->snd_stream); - - /* - * Fill LAN Level 1 or 2 Hello PDU header - */ - memset (&hello_hdr, 0, sizeof (struct isis_lan_hello_hdr)); - interval = circuit->hello_multiplier[level - 1] * - circuit->hello_interval[level - 1]; - if (interval > USHRT_MAX) - interval = USHRT_MAX; - hello_hdr.circuit_t = circuit->is_type; - memcpy (hello_hdr.source_id, isis->sysid, ISIS_SYS_ID_LEN); - hello_hdr.hold_time = htons ((u_int16_t) interval); - - hello_hdr.pdu_len = 0; /* Update the PDU Length later */ - len_pointer = stream_get_endp (circuit->snd_stream) + 3 + ISIS_SYS_ID_LEN; - - /* copy the shared part of the hello to the p2p hello if needed */ - if (circuit->circ_type == CIRCUIT_T_P2P) - { - memcpy (&p2p_hello_hdr, &hello_hdr, 5 + ISIS_SYS_ID_LEN); - p2p_hello_hdr.local_id = circuit->circuit_id; - /* FIXME: need better understanding */ - stream_put (circuit->snd_stream, &p2p_hello_hdr, ISIS_P2PHELLO_HDRLEN); - } - else - { - hello_hdr.prio = circuit->priority[level - 1]; - if (level == IS_LEVEL_1) - { - memcpy (hello_hdr.lan_id, circuit->u.bc.l1_desig_is, - ISIS_SYS_ID_LEN + 1); + struct isis_fixed_hdr fixed_hdr; + struct isis_lan_hello_hdr hello_hdr; + struct isis_p2p_hello_hdr p2p_hello_hdr; + unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; + size_t len_pointer, length, auth_tlv_offset = 0; + u_int32_t interval; + int retval; + + if (circuit->is_passive) + return ISIS_OK; + + if (circuit->interface->mtu == 0) { + zlog_warn("circuit has zero MTU"); + return ISIS_WARNING; } - else if (level == IS_LEVEL_2) - { - memcpy (hello_hdr.lan_id, circuit->u.bc.l2_desig_is, - ISIS_SYS_ID_LEN + 1); - } - stream_put (circuit->snd_stream, &hello_hdr, ISIS_LANHELLO_HDRLEN); - } - - /* - * Then the variable length part. - */ - - /* add circuit password */ - switch (circuit->passwd.type) - { - /* Cleartext */ - case ISIS_PASSWD_TYPE_CLEARTXT: - if (tlv_add_authinfo (circuit->passwd.type, circuit->passwd.len, - circuit->passwd.passwd, circuit->snd_stream)) - return ISIS_WARNING; - break; - - /* HMAC MD5 */ - case ISIS_PASSWD_TYPE_HMAC_MD5: - /* Remember where TLV is written so we can later overwrite the MD5 hash */ - auth_tlv_offset = stream_get_endp (circuit->snd_stream); - memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE); - if (tlv_add_authinfo (circuit->passwd.type, ISIS_AUTH_MD5_SIZE, - hmac_md5_hash, circuit->snd_stream)) - return ISIS_WARNING; - break; - - default: - break; - } - - /* Area Addresses TLV */ - if (listcount (circuit->area->area_addrs) == 0) - return ISIS_WARNING; - if (tlv_add_area_addrs (circuit->area->area_addrs, circuit->snd_stream)) - return ISIS_WARNING; - - /* LAN Neighbors TLV */ - if (circuit->circ_type == CIRCUIT_T_BROADCAST) - { - if (level == IS_LEVEL_1 && circuit->u.bc.lan_neighs[0] && - listcount (circuit->u.bc.lan_neighs[0]) > 0) - if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[0], - circuit->snd_stream)) - return ISIS_WARNING; - if (level == IS_LEVEL_2 && circuit->u.bc.lan_neighs[1] && - listcount (circuit->u.bc.lan_neighs[1]) > 0) - if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[1], - circuit->snd_stream)) - return ISIS_WARNING; - } - - /* Protocols Supported TLV */ - if (circuit->nlpids.count > 0) - if (tlv_add_nlpid (&circuit->nlpids, circuit->snd_stream)) - return ISIS_WARNING; - /* IP interface Address TLV */ - if (circuit->ip_router && circuit->ip_addrs && - listcount (circuit->ip_addrs) > 0) - if (tlv_add_ip_addrs (circuit->ip_addrs, circuit->snd_stream)) - return ISIS_WARNING; - /* IPv6 Interface Address TLV */ - if (circuit->ipv6_router && circuit->ipv6_link && - listcount (circuit->ipv6_link) > 0) - if (tlv_add_ipv6_addrs (circuit->ipv6_link, circuit->snd_stream)) - return ISIS_WARNING; + isis_circuit_stream(circuit, &circuit->snd_stream); - if (circuit->pad_hellos) - if (tlv_add_padding (circuit->snd_stream)) - return ISIS_WARNING; + if (circuit->circ_type == CIRCUIT_T_BROADCAST) + if (level == IS_LEVEL_1) + fill_fixed_hdr_andstream(&fixed_hdr, L1_LAN_HELLO, + circuit->snd_stream); + else + fill_fixed_hdr_andstream(&fixed_hdr, L2_LAN_HELLO, + circuit->snd_stream); + else + fill_fixed_hdr_andstream(&fixed_hdr, P2P_HELLO, + circuit->snd_stream); + + /* + * Fill LAN Level 1 or 2 Hello PDU header + */ + memset(&hello_hdr, 0, sizeof(struct isis_lan_hello_hdr)); + interval = circuit->hello_multiplier[level - 1] + * circuit->hello_interval[level - 1]; + if (interval > USHRT_MAX) + interval = USHRT_MAX; + hello_hdr.circuit_t = circuit->is_type; + memcpy(hello_hdr.source_id, isis->sysid, ISIS_SYS_ID_LEN); + hello_hdr.hold_time = htons((u_int16_t)interval); + + hello_hdr.pdu_len = 0; /* Update the PDU Length later */ + len_pointer = + stream_get_endp(circuit->snd_stream) + 3 + ISIS_SYS_ID_LEN; + + /* copy the shared part of the hello to the p2p hello if needed */ + if (circuit->circ_type == CIRCUIT_T_P2P) { + memcpy(&p2p_hello_hdr, &hello_hdr, 5 + ISIS_SYS_ID_LEN); + p2p_hello_hdr.local_id = circuit->circuit_id; + /* FIXME: need better understanding */ + stream_put(circuit->snd_stream, &p2p_hello_hdr, + ISIS_P2PHELLO_HDRLEN); + } else { + hello_hdr.prio = circuit->priority[level - 1]; + if (level == IS_LEVEL_1) { + memcpy(hello_hdr.lan_id, circuit->u.bc.l1_desig_is, + ISIS_SYS_ID_LEN + 1); + } else if (level == IS_LEVEL_2) { + memcpy(hello_hdr.lan_id, circuit->u.bc.l2_desig_is, + ISIS_SYS_ID_LEN + 1); + } + stream_put(circuit->snd_stream, &hello_hdr, + ISIS_LANHELLO_HDRLEN); + } - length = stream_get_endp (circuit->snd_stream); - /* Update PDU length */ - stream_putw_at (circuit->snd_stream, len_pointer, (u_int16_t) length); + /* + * Then the variable length part. + */ + + /* add circuit password */ + switch (circuit->passwd.type) { + /* Cleartext */ + case ISIS_PASSWD_TYPE_CLEARTXT: + if (tlv_add_authinfo(circuit->passwd.type, circuit->passwd.len, + circuit->passwd.passwd, + circuit->snd_stream)) + return ISIS_WARNING; + break; + + /* HMAC MD5 */ + case ISIS_PASSWD_TYPE_HMAC_MD5: + /* Remember where TLV is written so we can later overwrite the + * MD5 hash */ + auth_tlv_offset = stream_get_endp(circuit->snd_stream); + memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE); + if (tlv_add_authinfo(circuit->passwd.type, ISIS_AUTH_MD5_SIZE, + hmac_md5_hash, circuit->snd_stream)) + return ISIS_WARNING; + break; + + default: + break; + } - /* For HMAC MD5 we need to compute the md5 hash and store it */ - if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5) - { - hmac_md5 (STREAM_DATA (circuit->snd_stream), - stream_get_endp (circuit->snd_stream), - (unsigned char *) &circuit->passwd.passwd, circuit->passwd.len, - (unsigned char *) &hmac_md5_hash); - /* Copy the hash into the stream */ - memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3, - hmac_md5_hash, ISIS_AUTH_MD5_SIZE); - } + /* Area Addresses TLV */ + if (listcount(circuit->area->area_addrs) == 0) + return ISIS_WARNING; + if (tlv_add_area_addrs(circuit->area->area_addrs, circuit->snd_stream)) + return ISIS_WARNING; + + /* LAN Neighbors TLV */ + if (circuit->circ_type == CIRCUIT_T_BROADCAST) { + if (level == IS_LEVEL_1 && circuit->u.bc.lan_neighs[0] + && listcount(circuit->u.bc.lan_neighs[0]) > 0) + if (tlv_add_lan_neighs(circuit->u.bc.lan_neighs[0], + circuit->snd_stream)) + return ISIS_WARNING; + if (level == IS_LEVEL_2 && circuit->u.bc.lan_neighs[1] + && listcount(circuit->u.bc.lan_neighs[1]) > 0) + if (tlv_add_lan_neighs(circuit->u.bc.lan_neighs[1], + circuit->snd_stream)) + return ISIS_WARNING; + } - if (isis->debugs & DEBUG_ADJ_PACKETS) - { - if (circuit->circ_type == CIRCUIT_T_BROADCAST) - { - zlog_debug ("ISIS-Adj (%s): Sending L%d LAN IIH on %s, length %zd", - circuit->area->area_tag, level, circuit->interface->name, - length); + /* Protocols Supported TLV */ + if (circuit->nlpids.count > 0) + if (tlv_add_nlpid(&circuit->nlpids, circuit->snd_stream)) + return ISIS_WARNING; + /* IP interface Address TLV */ + if (circuit->ip_router && circuit->ip_addrs + && listcount(circuit->ip_addrs) > 0) + if (tlv_add_ip_addrs(circuit->ip_addrs, circuit->snd_stream)) + return ISIS_WARNING; + + /* IPv6 Interface Address TLV */ + if (circuit->ipv6_router && circuit->ipv6_link + && listcount(circuit->ipv6_link) > 0) + if (tlv_add_ipv6_addrs(circuit->ipv6_link, circuit->snd_stream)) + return ISIS_WARNING; + + if (circuit->pad_hellos) + if (tlv_add_padding(circuit->snd_stream)) + return ISIS_WARNING; + + length = stream_get_endp(circuit->snd_stream); + /* Update PDU length */ + stream_putw_at(circuit->snd_stream, len_pointer, (u_int16_t)length); + + /* For HMAC MD5 we need to compute the md5 hash and store it */ + if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5) { + hmac_md5(STREAM_DATA(circuit->snd_stream), + stream_get_endp(circuit->snd_stream), + (unsigned char *)&circuit->passwd.passwd, + circuit->passwd.len, (unsigned char *)&hmac_md5_hash); + /* Copy the hash into the stream */ + memcpy(STREAM_DATA(circuit->snd_stream) + auth_tlv_offset + 3, + hmac_md5_hash, ISIS_AUTH_MD5_SIZE); } - else - { - zlog_debug ("ISIS-Adj (%s): Sending P2P IIH on %s, length %zd", - circuit->area->area_tag, circuit->interface->name, - length); + + if (isis->debugs & DEBUG_ADJ_PACKETS) { + if (circuit->circ_type == CIRCUIT_T_BROADCAST) { + zlog_debug( + "ISIS-Adj (%s): Sending L%d LAN IIH on %s, length %zd", + circuit->area->area_tag, level, + circuit->interface->name, length); + } else { + zlog_debug( + "ISIS-Adj (%s): Sending P2P IIH on %s, length %zd", + circuit->area->area_tag, + circuit->interface->name, length); + } + if (isis->debugs & DEBUG_PACKET_DUMP) + zlog_dump_data(STREAM_DATA(circuit->snd_stream), + stream_get_endp(circuit->snd_stream)); } - if (isis->debugs & DEBUG_PACKET_DUMP) - zlog_dump_data (STREAM_DATA (circuit->snd_stream), - stream_get_endp (circuit->snd_stream)); - } - retval = circuit->tx (circuit, level); - if (retval != ISIS_OK) - zlog_err ("ISIS-Adj (%s): Send L%d IIH on %s failed", - circuit->area->area_tag, level, circuit->interface->name); + retval = circuit->tx(circuit, level); + if (retval != ISIS_OK) + zlog_err("ISIS-Adj (%s): Send L%d IIH on %s failed", + circuit->area->area_tag, level, + circuit->interface->name); - return retval; + return retval; } -int -send_lan_l1_hello (struct thread *thread) +int send_lan_l1_hello(struct thread *thread) { - struct isis_circuit *circuit; - int retval; - - circuit = THREAD_ARG (thread); - assert (circuit); - circuit->u.bc.t_send_lan_hello[0] = NULL; - - if (!(circuit->area->is_type & IS_LEVEL_1)) - { - zlog_warn ("ISIS-Hello (%s): Trying to send L1 IIH in L2-only area", - circuit->area->area_tag); - return 1; - } + struct isis_circuit *circuit; + int retval; + + circuit = THREAD_ARG(thread); + assert(circuit); + circuit->u.bc.t_send_lan_hello[0] = NULL; + + if (!(circuit->area->is_type & IS_LEVEL_1)) { + zlog_warn( + "ISIS-Hello (%s): Trying to send L1 IIH in L2-only area", + circuit->area->area_tag); + return 1; + } - if (circuit->u.bc.run_dr_elect[0]) - isis_dr_elect (circuit, 1); + if (circuit->u.bc.run_dr_elect[0]) + isis_dr_elect(circuit, 1); - retval = send_hello (circuit, 1); + retval = send_hello(circuit, 1); - /* set next timer thread */ - THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[0], - send_lan_l1_hello, circuit, - isis_jitter (circuit->hello_interval[0], IIH_JITTER)); + /* set next timer thread */ + THREAD_TIMER_ON(master, circuit->u.bc.t_send_lan_hello[0], + send_lan_l1_hello, circuit, + isis_jitter(circuit->hello_interval[0], IIH_JITTER)); - return retval; + return retval; } -int -send_lan_l2_hello (struct thread *thread) +int send_lan_l2_hello(struct thread *thread) { - struct isis_circuit *circuit; - int retval; + struct isis_circuit *circuit; + int retval; - circuit = THREAD_ARG (thread); - assert (circuit); - circuit->u.bc.t_send_lan_hello[1] = NULL; + circuit = THREAD_ARG(thread); + assert(circuit); + circuit->u.bc.t_send_lan_hello[1] = NULL; - if (!(circuit->area->is_type & IS_LEVEL_2)) - { - zlog_warn ("ISIS-Hello (%s): Trying to send L2 IIH in L1 area", - circuit->area->area_tag); - return 1; - } + if (!(circuit->area->is_type & IS_LEVEL_2)) { + zlog_warn("ISIS-Hello (%s): Trying to send L2 IIH in L1 area", + circuit->area->area_tag); + return 1; + } - if (circuit->u.bc.run_dr_elect[1]) - isis_dr_elect (circuit, 2); + if (circuit->u.bc.run_dr_elect[1]) + isis_dr_elect(circuit, 2); - retval = send_hello (circuit, 2); + retval = send_hello(circuit, 2); - /* set next timer thread */ - THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[1], - send_lan_l2_hello, circuit, - isis_jitter (circuit->hello_interval[1], IIH_JITTER)); + /* set next timer thread */ + THREAD_TIMER_ON(master, circuit->u.bc.t_send_lan_hello[1], + send_lan_l2_hello, circuit, + isis_jitter(circuit->hello_interval[1], IIH_JITTER)); - return retval; + return retval; } -int -send_p2p_hello (struct thread *thread) +int send_p2p_hello(struct thread *thread) { - struct isis_circuit *circuit; + struct isis_circuit *circuit; - circuit = THREAD_ARG (thread); - assert (circuit); - circuit->u.p2p.t_send_p2p_hello = NULL; + circuit = THREAD_ARG(thread); + assert(circuit); + circuit->u.p2p.t_send_p2p_hello = NULL; - send_hello (circuit, 1); + send_hello(circuit, 1); - /* set next timer thread */ - THREAD_TIMER_ON (master, circuit->u.p2p.t_send_p2p_hello, send_p2p_hello, - circuit, isis_jitter (circuit->hello_interval[1], - IIH_JITTER)); + /* set next timer thread */ + THREAD_TIMER_ON(master, circuit->u.p2p.t_send_p2p_hello, send_p2p_hello, + circuit, + isis_jitter(circuit->hello_interval[1], IIH_JITTER)); - return ISIS_OK; + return ISIS_OK; } -static int -build_csnp (int level, u_char * start, u_char * stop, struct list *lsps, - struct isis_circuit *circuit) +static int build_csnp(int level, u_char *start, u_char *stop, struct list *lsps, + struct isis_circuit *circuit) { - struct isis_fixed_hdr fixed_hdr; - struct isis_passwd *passwd; - unsigned long lenp; - u_int16_t length; - unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; - unsigned long auth_tlv_offset = 0; - int retval = ISIS_OK; - - isis_circuit_stream(circuit, &circuit->snd_stream); - - if (level == IS_LEVEL_1) - fill_fixed_hdr_andstream (&fixed_hdr, L1_COMPLETE_SEQ_NUM, - circuit->snd_stream); - else - fill_fixed_hdr_andstream (&fixed_hdr, L2_COMPLETE_SEQ_NUM, - circuit->snd_stream); - - /* - * Fill Level 1 or 2 Complete Sequence Numbers header - */ - - lenp = stream_get_endp (circuit->snd_stream); - stream_putw (circuit->snd_stream, 0); /* PDU length - when we know it */ - /* no need to send the source here, it is always us if we csnp */ - stream_put (circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN); - /* with zero circuit id - ref 9.10, 9.11 */ - stream_putc (circuit->snd_stream, 0x00); - - stream_put (circuit->snd_stream, start, ISIS_SYS_ID_LEN + 2); - stream_put (circuit->snd_stream, stop, ISIS_SYS_ID_LEN + 2); - - /* - * And TLVs - */ - if (level == IS_LEVEL_1) - passwd = &circuit->area->area_passwd; - else - passwd = &circuit->area->domain_passwd; - - if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND)) - { - switch (passwd->type) - { - /* Cleartext */ - case ISIS_PASSWD_TYPE_CLEARTXT: - if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT, passwd->len, - passwd->passwd, circuit->snd_stream)) - return ISIS_WARNING; - break; - - /* HMAC MD5 */ - case ISIS_PASSWD_TYPE_HMAC_MD5: - /* Remember where TLV is written so we can later overwrite the MD5 hash */ - auth_tlv_offset = stream_get_endp (circuit->snd_stream); - memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE); - if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5, ISIS_AUTH_MD5_SIZE, - hmac_md5_hash, circuit->snd_stream)) - return ISIS_WARNING; - break; - - default: - break; - } - } - - retval = tlv_add_lsp_entries (lsps, circuit->snd_stream); - if (retval != ISIS_OK) - return retval; - - length = (u_int16_t) stream_get_endp (circuit->snd_stream); - /* Update PU length */ - stream_putw_at (circuit->snd_stream, lenp, length); + struct isis_fixed_hdr fixed_hdr; + struct isis_passwd *passwd; + unsigned long lenp; + u_int16_t length; + unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; + unsigned long auth_tlv_offset = 0; + int retval = ISIS_OK; + + isis_circuit_stream(circuit, &circuit->snd_stream); + + if (level == IS_LEVEL_1) + fill_fixed_hdr_andstream(&fixed_hdr, L1_COMPLETE_SEQ_NUM, + circuit->snd_stream); + else + fill_fixed_hdr_andstream(&fixed_hdr, L2_COMPLETE_SEQ_NUM, + circuit->snd_stream); + + /* + * Fill Level 1 or 2 Complete Sequence Numbers header + */ + + lenp = stream_get_endp(circuit->snd_stream); + stream_putw(circuit->snd_stream, 0); /* PDU length - when we know it */ + /* no need to send the source here, it is always us if we csnp */ + stream_put(circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN); + /* with zero circuit id - ref 9.10, 9.11 */ + stream_putc(circuit->snd_stream, 0x00); + + stream_put(circuit->snd_stream, start, ISIS_SYS_ID_LEN + 2); + stream_put(circuit->snd_stream, stop, ISIS_SYS_ID_LEN + 2); + + /* + * And TLVs + */ + if (level == IS_LEVEL_1) + passwd = &circuit->area->area_passwd; + else + passwd = &circuit->area->domain_passwd; + + if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND)) { + switch (passwd->type) { + /* Cleartext */ + case ISIS_PASSWD_TYPE_CLEARTXT: + if (tlv_add_authinfo(ISIS_PASSWD_TYPE_CLEARTXT, + passwd->len, passwd->passwd, + circuit->snd_stream)) + return ISIS_WARNING; + break; + + /* HMAC MD5 */ + case ISIS_PASSWD_TYPE_HMAC_MD5: + /* Remember where TLV is written so we can later + * overwrite the MD5 hash */ + auth_tlv_offset = stream_get_endp(circuit->snd_stream); + memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE); + if (tlv_add_authinfo(ISIS_PASSWD_TYPE_HMAC_MD5, + ISIS_AUTH_MD5_SIZE, hmac_md5_hash, + circuit->snd_stream)) + return ISIS_WARNING; + break; + + default: + break; + } + } - /* For HMAC MD5 we need to compute the md5 hash and store it */ - if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND) && - passwd->type == ISIS_PASSWD_TYPE_HMAC_MD5) - { - hmac_md5 (STREAM_DATA (circuit->snd_stream), - stream_get_endp(circuit->snd_stream), - (unsigned char *) &passwd->passwd, passwd->len, - (unsigned char *) &hmac_md5_hash); - /* Copy the hash into the stream */ - memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3, - hmac_md5_hash, ISIS_AUTH_MD5_SIZE); - } + retval = tlv_add_lsp_entries(lsps, circuit->snd_stream); + if (retval != ISIS_OK) + return retval; + + length = (u_int16_t)stream_get_endp(circuit->snd_stream); + /* Update PU length */ + stream_putw_at(circuit->snd_stream, lenp, length); + + /* For HMAC MD5 we need to compute the md5 hash and store it */ + if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND) + && passwd->type == ISIS_PASSWD_TYPE_HMAC_MD5) { + hmac_md5(STREAM_DATA(circuit->snd_stream), + stream_get_endp(circuit->snd_stream), + (unsigned char *)&passwd->passwd, passwd->len, + (unsigned char *)&hmac_md5_hash); + /* Copy the hash into the stream */ + memcpy(STREAM_DATA(circuit->snd_stream) + auth_tlv_offset + 3, + hmac_md5_hash, ISIS_AUTH_MD5_SIZE); + } - return retval; + return retval; } /* * Count the maximum number of lsps that can be accomodated by a given size. */ -static uint16_t -get_max_lsp_count (uint16_t size) +static uint16_t get_max_lsp_count(uint16_t size) { - uint16_t tlv_count; - uint16_t lsp_count; - uint16_t remaining_size; + uint16_t tlv_count; + uint16_t lsp_count; + uint16_t remaining_size; - /* First count the full size TLVs */ - tlv_count = size / MAX_LSP_ENTRIES_TLV_SIZE; - lsp_count = tlv_count * (MAX_LSP_ENTRIES_TLV_SIZE / LSP_ENTRIES_LEN); + /* First count the full size TLVs */ + tlv_count = size / MAX_LSP_ENTRIES_TLV_SIZE; + lsp_count = tlv_count * (MAX_LSP_ENTRIES_TLV_SIZE / LSP_ENTRIES_LEN); - /* The last TLV, if any */ - remaining_size = size % MAX_LSP_ENTRIES_TLV_SIZE; - if (remaining_size - 2 >= LSP_ENTRIES_LEN) - lsp_count += (remaining_size - 2) / LSP_ENTRIES_LEN; + /* The last TLV, if any */ + remaining_size = size % MAX_LSP_ENTRIES_TLV_SIZE; + if (remaining_size - 2 >= LSP_ENTRIES_LEN) + lsp_count += (remaining_size - 2) / LSP_ENTRIES_LEN; - return lsp_count; + return lsp_count; } /* * Calculate the length of Authentication Info. TLV. */ -static uint16_t -auth_tlv_length (int level, struct isis_circuit *circuit) +static uint16_t auth_tlv_length(int level, struct isis_circuit *circuit) { - struct isis_passwd *passwd; - uint16_t length; - - if (level == IS_LEVEL_1) - passwd = &circuit->area->area_passwd; - else - passwd = &circuit->area->domain_passwd; - - /* Also include the length of TLV header */ - length = AUTH_INFO_HDRLEN; - if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND)) - { - switch (passwd->type) - { - /* Cleartext */ - case ISIS_PASSWD_TYPE_CLEARTXT: - length += passwd->len; - break; - - /* HMAC MD5 */ - case ISIS_PASSWD_TYPE_HMAC_MD5: - length += ISIS_AUTH_MD5_SIZE; - break; - - default: - break; - } - } + struct isis_passwd *passwd; + uint16_t length; + + if (level == IS_LEVEL_1) + passwd = &circuit->area->area_passwd; + else + passwd = &circuit->area->domain_passwd; + + /* Also include the length of TLV header */ + length = AUTH_INFO_HDRLEN; + if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND)) { + switch (passwd->type) { + /* Cleartext */ + case ISIS_PASSWD_TYPE_CLEARTXT: + length += passwd->len; + break; + + /* HMAC MD5 */ + case ISIS_PASSWD_TYPE_HMAC_MD5: + length += ISIS_AUTH_MD5_SIZE; + break; + + default: + break; + } + } - return length; + return length; } /* * Calculate the maximum number of lsps that can be accomodated in a CSNP/PSNP. */ -static uint16_t -max_lsps_per_snp (int snp_type, int level, struct isis_circuit *circuit) +static uint16_t max_lsps_per_snp(int snp_type, int level, + struct isis_circuit *circuit) { - int snp_hdr_len; - int auth_tlv_len; - uint16_t lsp_count; - - snp_hdr_len = ISIS_FIXED_HDR_LEN; - if (snp_type == ISIS_SNP_CSNP_FLAG) - snp_hdr_len += ISIS_CSNP_HDRLEN; - else - snp_hdr_len += ISIS_PSNP_HDRLEN; - - auth_tlv_len = auth_tlv_length (level, circuit); - lsp_count = get_max_lsp_count ( - stream_get_size (circuit->snd_stream) - snp_hdr_len - auth_tlv_len); - return lsp_count; + int snp_hdr_len; + int auth_tlv_len; + uint16_t lsp_count; + + snp_hdr_len = ISIS_FIXED_HDR_LEN; + if (snp_type == ISIS_SNP_CSNP_FLAG) + snp_hdr_len += ISIS_CSNP_HDRLEN; + else + snp_hdr_len += ISIS_PSNP_HDRLEN; + + auth_tlv_len = auth_tlv_length(level, circuit); + lsp_count = get_max_lsp_count(stream_get_size(circuit->snd_stream) + - snp_hdr_len - auth_tlv_len); + return lsp_count; } /* * FIXME: support multiple CSNPs */ -int -send_csnp (struct isis_circuit *circuit, int level) +int send_csnp(struct isis_circuit *circuit, int level) { - u_char start[ISIS_SYS_ID_LEN + 2]; - u_char stop[ISIS_SYS_ID_LEN + 2]; - struct list *list = NULL; - struct listnode *node; - struct isis_lsp *lsp; - u_char num_lsps, loop = 1; - int i, retval = ISIS_OK; + u_char start[ISIS_SYS_ID_LEN + 2]; + u_char stop[ISIS_SYS_ID_LEN + 2]; + struct list *list = NULL; + struct listnode *node; + struct isis_lsp *lsp; + u_char num_lsps, loop = 1; + int i, retval = ISIS_OK; + + if (circuit->area->lspdb[level - 1] == NULL + || dict_count(circuit->area->lspdb[level - 1]) == 0) + return retval; + + memset(start, 0x00, ISIS_SYS_ID_LEN + 2); + memset(stop, 0xff, ISIS_SYS_ID_LEN + 2); + + num_lsps = max_lsps_per_snp(ISIS_SNP_CSNP_FLAG, level, circuit); + + while (loop) { + list = list_new(); + lsp_build_list(start, stop, num_lsps, list, + circuit->area->lspdb[level - 1]); + /* + * Update the stop lsp_id before encoding this CSNP. + */ + if (listcount(list) < num_lsps) { + memset(stop, 0xff, ISIS_SYS_ID_LEN + 2); + } else { + node = listtail(list); + lsp = listgetdata(node); + memcpy(stop, lsp->lsp_header->lsp_id, + ISIS_SYS_ID_LEN + 2); + } - if (circuit->area->lspdb[level - 1] == NULL || - dict_count (circuit->area->lspdb[level - 1]) == 0) - return retval; + retval = build_csnp(level, start, stop, list, circuit); + if (retval != ISIS_OK) { + zlog_err("ISIS-Snp (%s): Build L%d CSNP on %s failed", + circuit->area->area_tag, level, + circuit->interface->name); + list_delete(list); + return retval; + } - memset (start, 0x00, ISIS_SYS_ID_LEN + 2); - memset (stop, 0xff, ISIS_SYS_ID_LEN + 2); + if (isis->debugs & DEBUG_SNP_PACKETS) { + zlog_debug( + "ISIS-Snp (%s): Sending L%d CSNP on %s, length %zd", + circuit->area->area_tag, level, + circuit->interface->name, + stream_get_endp(circuit->snd_stream)); + for (ALL_LIST_ELEMENTS_RO(list, node, lsp)) { + zlog_debug( + "ISIS-Snp (%s): CSNP entry %s, seq 0x%08x," + " cksum 0x%04x, lifetime %us", + circuit->area->area_tag, + rawlspid_print(lsp->lsp_header->lsp_id), + ntohl(lsp->lsp_header->seq_num), + ntohs(lsp->lsp_header->checksum), + ntohs(lsp->lsp_header->rem_lifetime)); + } + if (isis->debugs & DEBUG_PACKET_DUMP) + zlog_dump_data( + STREAM_DATA(circuit->snd_stream), + stream_get_endp(circuit->snd_stream)); + } - num_lsps = max_lsps_per_snp (ISIS_SNP_CSNP_FLAG, level, circuit); + retval = circuit->tx(circuit, level); + if (retval != ISIS_OK) { + zlog_err("ISIS-Snp (%s): Send L%d CSNP on %s failed", + circuit->area->area_tag, level, + circuit->interface->name); + list_delete(list); + return retval; + } - while (loop) - { - list = list_new (); - lsp_build_list (start, stop, num_lsps, list, - circuit->area->lspdb[level - 1]); - /* - * Update the stop lsp_id before encoding this CSNP. - */ - if (listcount (list) < num_lsps) - { - memset (stop, 0xff, ISIS_SYS_ID_LEN + 2); - } - else - { - node = listtail (list); - lsp = listgetdata (node); - memcpy (stop, lsp->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 2); - } - - retval = build_csnp (level, start, stop, list, circuit); - if (retval != ISIS_OK) - { - zlog_err ("ISIS-Snp (%s): Build L%d CSNP on %s failed", - circuit->area->area_tag, level, circuit->interface->name); - list_delete (list); - return retval; - } - - if (isis->debugs & DEBUG_SNP_PACKETS) - { - zlog_debug ("ISIS-Snp (%s): Sending L%d CSNP on %s, length %zd", - circuit->area->area_tag, level, circuit->interface->name, - stream_get_endp (circuit->snd_stream)); - for (ALL_LIST_ELEMENTS_RO (list, node, lsp)) - { - zlog_debug ("ISIS-Snp (%s): CSNP entry %s, seq 0x%08x," - " cksum 0x%04x, lifetime %us", - circuit->area->area_tag, - rawlspid_print (lsp->lsp_header->lsp_id), - ntohl (lsp->lsp_header->seq_num), - ntohs (lsp->lsp_header->checksum), - ntohs (lsp->lsp_header->rem_lifetime)); - } - if (isis->debugs & DEBUG_PACKET_DUMP) - zlog_dump_data (STREAM_DATA (circuit->snd_stream), - stream_get_endp (circuit->snd_stream)); - } - - retval = circuit->tx (circuit, level); - if (retval != ISIS_OK) - { - zlog_err ("ISIS-Snp (%s): Send L%d CSNP on %s failed", - circuit->area->area_tag, level, - circuit->interface->name); - list_delete (list); - return retval; - } - - /* - * Start lsp_id of the next CSNP should be one plus the - * stop lsp_id in this current CSNP. - */ - memcpy (start, stop, ISIS_SYS_ID_LEN + 2); - loop = 0; - for (i = ISIS_SYS_ID_LEN + 1; i >= 0; --i) - { - if (start[i] < (u_char)0xff) - { - start[i] += 1; - loop = 1; - break; - } - } - memset (stop, 0xff, ISIS_SYS_ID_LEN + 2); - list_delete (list); - } + /* + * Start lsp_id of the next CSNP should be one plus the + * stop lsp_id in this current CSNP. + */ + memcpy(start, stop, ISIS_SYS_ID_LEN + 2); + loop = 0; + for (i = ISIS_SYS_ID_LEN + 1; i >= 0; --i) { + if (start[i] < (u_char)0xff) { + start[i] += 1; + loop = 1; + break; + } + } + memset(stop, 0xff, ISIS_SYS_ID_LEN + 2); + list_delete(list); + } - return retval; + return retval; } -int -send_l1_csnp (struct thread *thread) +int send_l1_csnp(struct thread *thread) { - struct isis_circuit *circuit; - int retval = ISIS_OK; + struct isis_circuit *circuit; + int retval = ISIS_OK; - circuit = THREAD_ARG (thread); - assert (circuit); + circuit = THREAD_ARG(thread); + assert(circuit); - circuit->t_send_csnp[0] = NULL; + circuit->t_send_csnp[0] = NULL; - if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[0]) - { - send_csnp (circuit, 1); - } - /* set next timer thread */ - THREAD_TIMER_ON (master, circuit->t_send_csnp[0], send_l1_csnp, circuit, - isis_jitter (circuit->csnp_interval[0], CSNP_JITTER)); + if (circuit->circ_type == CIRCUIT_T_BROADCAST + && circuit->u.bc.is_dr[0]) { + send_csnp(circuit, 1); + } + /* set next timer thread */ + THREAD_TIMER_ON(master, circuit->t_send_csnp[0], send_l1_csnp, circuit, + isis_jitter(circuit->csnp_interval[0], CSNP_JITTER)); - return retval; + return retval; } -int -send_l2_csnp (struct thread *thread) +int send_l2_csnp(struct thread *thread) { - struct isis_circuit *circuit; - int retval = ISIS_OK; + struct isis_circuit *circuit; + int retval = ISIS_OK; - circuit = THREAD_ARG (thread); - assert (circuit); + circuit = THREAD_ARG(thread); + assert(circuit); - circuit->t_send_csnp[1] = NULL; + circuit->t_send_csnp[1] = NULL; - if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[1]) - { - send_csnp (circuit, 2); - } - /* set next timer thread */ - THREAD_TIMER_ON (master, circuit->t_send_csnp[1], send_l2_csnp, circuit, - isis_jitter (circuit->csnp_interval[1], CSNP_JITTER)); + if (circuit->circ_type == CIRCUIT_T_BROADCAST + && circuit->u.bc.is_dr[1]) { + send_csnp(circuit, 2); + } + /* set next timer thread */ + THREAD_TIMER_ON(master, circuit->t_send_csnp[1], send_l2_csnp, circuit, + isis_jitter(circuit->csnp_interval[1], CSNP_JITTER)); - return retval; + return retval; } -static int -build_psnp (int level, struct isis_circuit *circuit, struct list *lsps) +static int build_psnp(int level, struct isis_circuit *circuit, + struct list *lsps) { - struct isis_fixed_hdr fixed_hdr; - unsigned long lenp; - u_int16_t length; - struct isis_lsp *lsp; - struct isis_passwd *passwd; - struct listnode *node; - unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; - unsigned long auth_tlv_offset = 0; - int retval = ISIS_OK; - - isis_circuit_stream(circuit, &circuit->snd_stream); - - if (level == IS_LEVEL_1) - fill_fixed_hdr_andstream (&fixed_hdr, L1_PARTIAL_SEQ_NUM, - circuit->snd_stream); - else - fill_fixed_hdr_andstream (&fixed_hdr, L2_PARTIAL_SEQ_NUM, - circuit->snd_stream); - - /* - * Fill Level 1 or 2 Partial Sequence Numbers header - */ - lenp = stream_get_endp (circuit->snd_stream); - stream_putw (circuit->snd_stream, 0); /* PDU length - when we know it */ - stream_put (circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN); - stream_putc (circuit->snd_stream, circuit->idx); - - /* - * And TLVs - */ - - if (level == IS_LEVEL_1) - passwd = &circuit->area->area_passwd; - else - passwd = &circuit->area->domain_passwd; - - if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND)) - { - switch (passwd->type) - { - /* Cleartext */ - case ISIS_PASSWD_TYPE_CLEARTXT: - if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT, passwd->len, - passwd->passwd, circuit->snd_stream)) - return ISIS_WARNING; - break; - - /* HMAC MD5 */ - case ISIS_PASSWD_TYPE_HMAC_MD5: - /* Remember where TLV is written so we can later overwrite the MD5 hash */ - auth_tlv_offset = stream_get_endp (circuit->snd_stream); - memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE); - if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5, ISIS_AUTH_MD5_SIZE, - hmac_md5_hash, circuit->snd_stream)) - return ISIS_WARNING; - break; - - default: - break; - } - } - - retval = tlv_add_lsp_entries (lsps, circuit->snd_stream); - if (retval != ISIS_OK) - return retval; - - if (isis->debugs & DEBUG_SNP_PACKETS) - { - for (ALL_LIST_ELEMENTS_RO (lsps, node, lsp)) - { - zlog_debug ("ISIS-Snp (%s): PSNP entry %s, seq 0x%08x," - " cksum 0x%04x, lifetime %us", - circuit->area->area_tag, - rawlspid_print (lsp->lsp_header->lsp_id), - ntohl (lsp->lsp_header->seq_num), - ntohs (lsp->lsp_header->checksum), - ntohs (lsp->lsp_header->rem_lifetime)); - } - } + struct isis_fixed_hdr fixed_hdr; + unsigned long lenp; + u_int16_t length; + struct isis_lsp *lsp; + struct isis_passwd *passwd; + struct listnode *node; + unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; + unsigned long auth_tlv_offset = 0; + int retval = ISIS_OK; + + isis_circuit_stream(circuit, &circuit->snd_stream); + + if (level == IS_LEVEL_1) + fill_fixed_hdr_andstream(&fixed_hdr, L1_PARTIAL_SEQ_NUM, + circuit->snd_stream); + else + fill_fixed_hdr_andstream(&fixed_hdr, L2_PARTIAL_SEQ_NUM, + circuit->snd_stream); + + /* + * Fill Level 1 or 2 Partial Sequence Numbers header + */ + lenp = stream_get_endp(circuit->snd_stream); + stream_putw(circuit->snd_stream, 0); /* PDU length - when we know it */ + stream_put(circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN); + stream_putc(circuit->snd_stream, circuit->idx); + + /* + * And TLVs + */ + + if (level == IS_LEVEL_1) + passwd = &circuit->area->area_passwd; + else + passwd = &circuit->area->domain_passwd; + + if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND)) { + switch (passwd->type) { + /* Cleartext */ + case ISIS_PASSWD_TYPE_CLEARTXT: + if (tlv_add_authinfo(ISIS_PASSWD_TYPE_CLEARTXT, + passwd->len, passwd->passwd, + circuit->snd_stream)) + return ISIS_WARNING; + break; + + /* HMAC MD5 */ + case ISIS_PASSWD_TYPE_HMAC_MD5: + /* Remember where TLV is written so we can later + * overwrite the MD5 hash */ + auth_tlv_offset = stream_get_endp(circuit->snd_stream); + memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE); + if (tlv_add_authinfo(ISIS_PASSWD_TYPE_HMAC_MD5, + ISIS_AUTH_MD5_SIZE, hmac_md5_hash, + circuit->snd_stream)) + return ISIS_WARNING; + break; + + default: + break; + } + } - length = (u_int16_t) stream_get_endp (circuit->snd_stream); - /* Update PDU length */ - stream_putw_at (circuit->snd_stream, lenp, length); + retval = tlv_add_lsp_entries(lsps, circuit->snd_stream); + if (retval != ISIS_OK) + return retval; + + if (isis->debugs & DEBUG_SNP_PACKETS) { + for (ALL_LIST_ELEMENTS_RO(lsps, node, lsp)) { + zlog_debug( + "ISIS-Snp (%s): PSNP entry %s, seq 0x%08x," + " cksum 0x%04x, lifetime %us", + circuit->area->area_tag, + rawlspid_print(lsp->lsp_header->lsp_id), + ntohl(lsp->lsp_header->seq_num), + ntohs(lsp->lsp_header->checksum), + ntohs(lsp->lsp_header->rem_lifetime)); + } + } - /* For HMAC MD5 we need to compute the md5 hash and store it */ - if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND) && - passwd->type == ISIS_PASSWD_TYPE_HMAC_MD5) - { - hmac_md5 (STREAM_DATA (circuit->snd_stream), - stream_get_endp(circuit->snd_stream), - (unsigned char *) &passwd->passwd, passwd->len, - (unsigned char *) &hmac_md5_hash); - /* Copy the hash into the stream */ - memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3, - hmac_md5_hash, ISIS_AUTH_MD5_SIZE); - } + length = (u_int16_t)stream_get_endp(circuit->snd_stream); + /* Update PDU length */ + stream_putw_at(circuit->snd_stream, lenp, length); + + /* For HMAC MD5 we need to compute the md5 hash and store it */ + if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND) + && passwd->type == ISIS_PASSWD_TYPE_HMAC_MD5) { + hmac_md5(STREAM_DATA(circuit->snd_stream), + stream_get_endp(circuit->snd_stream), + (unsigned char *)&passwd->passwd, passwd->len, + (unsigned char *)&hmac_md5_hash); + /* Copy the hash into the stream */ + memcpy(STREAM_DATA(circuit->snd_stream) + auth_tlv_offset + 3, + hmac_md5_hash, ISIS_AUTH_MD5_SIZE); + } - return ISIS_OK; + return ISIS_OK; } /* * 7.3.15.4 action on expiration of partial SNP interval * level 1 */ -static int -send_psnp (int level, struct isis_circuit *circuit) +static int send_psnp(int level, struct isis_circuit *circuit) { - struct isis_lsp *lsp; - struct list *list = NULL; - struct listnode *node; - u_char num_lsps; - int retval = ISIS_OK; + struct isis_lsp *lsp; + struct list *list = NULL; + struct listnode *node; + u_char num_lsps; + int retval = ISIS_OK; - if (circuit->circ_type == CIRCUIT_T_BROADCAST && - circuit->u.bc.is_dr[level - 1]) - return ISIS_OK; + if (circuit->circ_type == CIRCUIT_T_BROADCAST + && circuit->u.bc.is_dr[level - 1]) + return ISIS_OK; - if (circuit->area->lspdb[level - 1] == NULL || - dict_count (circuit->area->lspdb[level - 1]) == 0) - return ISIS_OK; + if (circuit->area->lspdb[level - 1] == NULL + || dict_count(circuit->area->lspdb[level - 1]) == 0) + return ISIS_OK; - if (! circuit->snd_stream) - return ISIS_ERROR; + if (!circuit->snd_stream) + return ISIS_ERROR; - num_lsps = max_lsps_per_snp (ISIS_SNP_PSNP_FLAG, level, circuit); + num_lsps = max_lsps_per_snp(ISIS_SNP_PSNP_FLAG, level, circuit); - while (1) - { - list = list_new (); - lsp_build_list_ssn (circuit, num_lsps, list, - circuit->area->lspdb[level - 1]); - - if (listcount (list) == 0) - { - list_delete (list); - return ISIS_OK; - } - - retval = build_psnp (level, circuit, list); - if (retval != ISIS_OK) - { - zlog_err ("ISIS-Snp (%s): Build L%d PSNP on %s failed", - circuit->area->area_tag, level, circuit->interface->name); - list_delete (list); - return retval; - } - - if (isis->debugs & DEBUG_SNP_PACKETS) - { - zlog_debug ("ISIS-Snp (%s): Sending L%d PSNP on %s, length %zd", - circuit->area->area_tag, level, - circuit->interface->name, - stream_get_endp (circuit->snd_stream)); - if (isis->debugs & DEBUG_PACKET_DUMP) - zlog_dump_data (STREAM_DATA (circuit->snd_stream), - stream_get_endp (circuit->snd_stream)); - } - - retval = circuit->tx (circuit, level); - if (retval != ISIS_OK) - { - zlog_err ("ISIS-Snp (%s): Send L%d PSNP on %s failed", - circuit->area->area_tag, level, - circuit->interface->name); - list_delete (list); - return retval; - } - - /* - * sending succeeded, we can clear SSN flags of this circuit - * for the LSPs in list - */ - for (ALL_LIST_ELEMENTS_RO (list, node, lsp)) - ISIS_CLEAR_FLAG (lsp->SSNflags, circuit); - list_delete (list); - } + while (1) { + list = list_new(); + lsp_build_list_ssn(circuit, num_lsps, list, + circuit->area->lspdb[level - 1]); + + if (listcount(list) == 0) { + list_delete(list); + return ISIS_OK; + } + + retval = build_psnp(level, circuit, list); + if (retval != ISIS_OK) { + zlog_err("ISIS-Snp (%s): Build L%d PSNP on %s failed", + circuit->area->area_tag, level, + circuit->interface->name); + list_delete(list); + return retval; + } + + if (isis->debugs & DEBUG_SNP_PACKETS) { + zlog_debug( + "ISIS-Snp (%s): Sending L%d PSNP on %s, length %zd", + circuit->area->area_tag, level, + circuit->interface->name, + stream_get_endp(circuit->snd_stream)); + if (isis->debugs & DEBUG_PACKET_DUMP) + zlog_dump_data( + STREAM_DATA(circuit->snd_stream), + stream_get_endp(circuit->snd_stream)); + } + + retval = circuit->tx(circuit, level); + if (retval != ISIS_OK) { + zlog_err("ISIS-Snp (%s): Send L%d PSNP on %s failed", + circuit->area->area_tag, level, + circuit->interface->name); + list_delete(list); + return retval; + } - return retval; + /* + * sending succeeded, we can clear SSN flags of this circuit + * for the LSPs in list + */ + for (ALL_LIST_ELEMENTS_RO(list, node, lsp)) + ISIS_CLEAR_FLAG(lsp->SSNflags, circuit); + list_delete(list); + } + + return retval; } -int -send_l1_psnp (struct thread *thread) +int send_l1_psnp(struct thread *thread) { - struct isis_circuit *circuit; - int retval = ISIS_OK; + struct isis_circuit *circuit; + int retval = ISIS_OK; - circuit = THREAD_ARG (thread); - assert (circuit); + circuit = THREAD_ARG(thread); + assert(circuit); - circuit->t_send_psnp[0] = NULL; + circuit->t_send_psnp[0] = NULL; - send_psnp (1, circuit); - /* set next timer thread */ - THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit, - isis_jitter (circuit->psnp_interval[0], PSNP_JITTER)); + send_psnp(1, circuit); + /* set next timer thread */ + THREAD_TIMER_ON(master, circuit->t_send_psnp[0], send_l1_psnp, circuit, + isis_jitter(circuit->psnp_interval[0], PSNP_JITTER)); - return retval; + return retval; } /* * 7.3.15.4 action on expiration of partial SNP interval * level 2 */ -int -send_l2_psnp (struct thread *thread) +int send_l2_psnp(struct thread *thread) { - struct isis_circuit *circuit; - int retval = ISIS_OK; + struct isis_circuit *circuit; + int retval = ISIS_OK; - circuit = THREAD_ARG (thread); - assert (circuit); + circuit = THREAD_ARG(thread); + assert(circuit); - circuit->t_send_psnp[1] = NULL; + circuit->t_send_psnp[1] = NULL; - send_psnp (2, circuit); + send_psnp(2, circuit); - /* set next timer thread */ - THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit, - isis_jitter (circuit->psnp_interval[1], PSNP_JITTER)); + /* set next timer thread */ + THREAD_TIMER_ON(master, circuit->t_send_psnp[1], send_l2_psnp, circuit, + isis_jitter(circuit->psnp_interval[1], PSNP_JITTER)); - return retval; + return retval; } /* * ISO 10589 - 7.3.14.3 */ -int -send_lsp (struct thread *thread) +int send_lsp(struct thread *thread) { - struct isis_circuit *circuit; - struct isis_lsp *lsp; - struct listnode *node; - int clear_srm = 1; - int retval = ISIS_OK; - - circuit = THREAD_ARG (thread); - assert (circuit); - - if (!circuit->lsp_queue) - return ISIS_OK; - - node = listhead (circuit->lsp_queue); - - /* - * Handle case where there are no LSPs on the queue. This can - * happen, for instance, if an adjacency goes down before this - * thread gets a chance to run. - */ - if (!node) - return ISIS_OK; - - /* - * Delete LSP from lsp_queue. If it's still in queue, it is assumed - * as 'transmit pending', but send_lsp may never be called again. - * Retry will happen because SRM flag will not be cleared. - */ - lsp = listgetdata(node); - list_delete_node (circuit->lsp_queue, node); - - /* Set the last-cleared time if the queue is empty. */ - /* TODO: Is is possible that new lsps keep being added to the queue - * that the queue is never empty? */ - if (list_isempty (circuit->lsp_queue)) - circuit->lsp_queue_last_cleared = time (NULL); - - if (circuit->state != C_STATE_UP || circuit->is_passive == 1) - goto out; - - /* - * Do not send if levels do not match - */ - if (!(lsp->level & circuit->is_type)) - goto out; - - /* - * Do not send if we do not have adjacencies in state up on the circuit - */ - if (circuit->upadjcount[lsp->level - 1] == 0) - goto out; - - /* stream_copy will assert and stop program execution if LSP is larger than - * the circuit's MTU. So handle and log this case here. */ - if (stream_get_endp(lsp->pdu) > stream_get_size(circuit->snd_stream)) - { - zlog_err("ISIS-Upd (%s): Can't send L%d LSP %s, seq 0x%08x," - " cksum 0x%04x, lifetime %us on %s. LSP Size is %zu" - " while interface stream size is %zu.", - circuit->area->area_tag, lsp->level, - rawlspid_print(lsp->lsp_header->lsp_id), - ntohl(lsp->lsp_header->seq_num), - ntohs(lsp->lsp_header->checksum), - ntohs(lsp->lsp_header->rem_lifetime), - circuit->interface->name, - stream_get_endp(lsp->pdu), - stream_get_size(circuit->snd_stream)); - if (isis->debugs & DEBUG_PACKET_DUMP) - zlog_dump_data(STREAM_DATA(lsp->pdu), stream_get_endp(lsp->pdu)); - retval = ISIS_ERROR; - goto out; - } - - /* copy our lsp to the send buffer */ - stream_copy (circuit->snd_stream, lsp->pdu); + struct isis_circuit *circuit; + struct isis_lsp *lsp; + struct listnode *node; + int clear_srm = 1; + int retval = ISIS_OK; + + circuit = THREAD_ARG(thread); + assert(circuit); + + if (!circuit->lsp_queue) + return ISIS_OK; + + node = listhead(circuit->lsp_queue); + + /* + * Handle case where there are no LSPs on the queue. This can + * happen, for instance, if an adjacency goes down before this + * thread gets a chance to run. + */ + if (!node) + return ISIS_OK; + + /* + * Delete LSP from lsp_queue. If it's still in queue, it is assumed + * as 'transmit pending', but send_lsp may never be called again. + * Retry will happen because SRM flag will not be cleared. + */ + lsp = listgetdata(node); + list_delete_node(circuit->lsp_queue, node); + + /* Set the last-cleared time if the queue is empty. */ + /* TODO: Is is possible that new lsps keep being added to the queue + * that the queue is never empty? */ + if (list_isempty(circuit->lsp_queue)) + circuit->lsp_queue_last_cleared = time(NULL); + + if (circuit->state != C_STATE_UP || circuit->is_passive == 1) + goto out; + + /* + * Do not send if levels do not match + */ + if (!(lsp->level & circuit->is_type)) + goto out; + + /* + * Do not send if we do not have adjacencies in state up on the circuit + */ + if (circuit->upadjcount[lsp->level - 1] == 0) + goto out; + + /* stream_copy will assert and stop program execution if LSP is larger + * than + * the circuit's MTU. So handle and log this case here. */ + if (stream_get_endp(lsp->pdu) > stream_get_size(circuit->snd_stream)) { + zlog_err( + "ISIS-Upd (%s): Can't send L%d LSP %s, seq 0x%08x," + " cksum 0x%04x, lifetime %us on %s. LSP Size is %zu" + " while interface stream size is %zu.", + circuit->area->area_tag, lsp->level, + rawlspid_print(lsp->lsp_header->lsp_id), + ntohl(lsp->lsp_header->seq_num), + ntohs(lsp->lsp_header->checksum), + ntohs(lsp->lsp_header->rem_lifetime), + circuit->interface->name, stream_get_endp(lsp->pdu), + stream_get_size(circuit->snd_stream)); + if (isis->debugs & DEBUG_PACKET_DUMP) + zlog_dump_data(STREAM_DATA(lsp->pdu), + stream_get_endp(lsp->pdu)); + retval = ISIS_ERROR; + goto out; + } - if (isis->debugs & DEBUG_UPDATE_PACKETS) - { - zlog_debug - ("ISIS-Upd (%s): Sending L%d LSP %s, seq 0x%08x, cksum 0x%04x," - " lifetime %us on %s", circuit->area->area_tag, lsp->level, - rawlspid_print (lsp->lsp_header->lsp_id), - ntohl (lsp->lsp_header->seq_num), - ntohs (lsp->lsp_header->checksum), - ntohs (lsp->lsp_header->rem_lifetime), - circuit->interface->name); - if (isis->debugs & DEBUG_PACKET_DUMP) - zlog_dump_data (STREAM_DATA (circuit->snd_stream), - stream_get_endp (circuit->snd_stream)); - } + /* copy our lsp to the send buffer */ + stream_copy(circuit->snd_stream, lsp->pdu); + + if (isis->debugs & DEBUG_UPDATE_PACKETS) { + zlog_debug( + "ISIS-Upd (%s): Sending L%d LSP %s, seq 0x%08x, cksum 0x%04x," + " lifetime %us on %s", + circuit->area->area_tag, lsp->level, + rawlspid_print(lsp->lsp_header->lsp_id), + ntohl(lsp->lsp_header->seq_num), + ntohs(lsp->lsp_header->checksum), + ntohs(lsp->lsp_header->rem_lifetime), + circuit->interface->name); + if (isis->debugs & DEBUG_PACKET_DUMP) + zlog_dump_data(STREAM_DATA(circuit->snd_stream), + stream_get_endp(circuit->snd_stream)); + } - clear_srm = 0; - retval = circuit->tx (circuit, lsp->level); - if (retval != ISIS_OK) - { - zlog_err ("ISIS-Upd (%s): Send L%d LSP on %s failed %s", - circuit->area->area_tag, lsp->level, - circuit->interface->name, - (retval == ISIS_WARNING) ? "temporarily" : "permanently"); - } + clear_srm = 0; + retval = circuit->tx(circuit, lsp->level); + if (retval != ISIS_OK) { + zlog_err("ISIS-Upd (%s): Send L%d LSP on %s failed %s", + circuit->area->area_tag, lsp->level, + circuit->interface->name, + (retval == ISIS_WARNING) ? "temporarily" + : "permanently"); + } out: - if (clear_srm - || (retval == ISIS_OK && circuit->circ_type == CIRCUIT_T_BROADCAST) - || (retval != ISIS_OK && retval != ISIS_WARNING)) - { - /* SRM flag will trigger retransmission. We will not retransmit if we - * encountered a fatal error. - * On success, they should only be cleared if it's a broadcast circuit. - * On a P2P circuit, we will wait for the ack from the neighbor to clear - * the fag. - */ - ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); - } + if (clear_srm + || (retval == ISIS_OK && circuit->circ_type == CIRCUIT_T_BROADCAST) + || (retval != ISIS_OK && retval != ISIS_WARNING)) { + /* SRM flag will trigger retransmission. We will not retransmit + * if we + * encountered a fatal error. + * On success, they should only be cleared if it's a broadcast + * circuit. + * On a P2P circuit, we will wait for the ack from the neighbor + * to clear + * the fag. + */ + ISIS_CLEAR_FLAG(lsp->SRMflags, circuit); + } - return retval; + return retval; } -int -ack_lsp (struct isis_link_state_hdr *hdr, struct isis_circuit *circuit, - int level) +int ack_lsp(struct isis_link_state_hdr *hdr, struct isis_circuit *circuit, + int level) { - unsigned long lenp; - int retval; - u_int16_t length; - struct isis_fixed_hdr fixed_hdr; - - isis_circuit_stream(circuit, &circuit->snd_stream); - - // fill_llc_hdr (stream); - if (level == IS_LEVEL_1) - fill_fixed_hdr_andstream (&fixed_hdr, L1_PARTIAL_SEQ_NUM, - circuit->snd_stream); - else - fill_fixed_hdr_andstream (&fixed_hdr, L2_PARTIAL_SEQ_NUM, - circuit->snd_stream); - - - lenp = stream_get_endp (circuit->snd_stream); - stream_putw (circuit->snd_stream, 0); /* PDU length */ - stream_put (circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN); - stream_putc (circuit->snd_stream, circuit->idx); - stream_putc (circuit->snd_stream, 9); /* code */ - stream_putc (circuit->snd_stream, 16); /* len */ - - stream_putw (circuit->snd_stream, ntohs (hdr->rem_lifetime)); - stream_put (circuit->snd_stream, hdr->lsp_id, ISIS_SYS_ID_LEN + 2); - stream_putl (circuit->snd_stream, ntohl (hdr->seq_num)); - stream_putw (circuit->snd_stream, ntohs (hdr->checksum)); - - length = (u_int16_t) stream_get_endp (circuit->snd_stream); - /* Update PDU length */ - stream_putw_at (circuit->snd_stream, lenp, length); - - retval = circuit->tx (circuit, level); - if (retval != ISIS_OK) - zlog_err ("ISIS-Upd (%s): Send L%d LSP PSNP on %s failed", - circuit->area->area_tag, level, - circuit->interface->name); - - return retval; + unsigned long lenp; + int retval; + u_int16_t length; + struct isis_fixed_hdr fixed_hdr; + + isis_circuit_stream(circuit, &circuit->snd_stream); + + // fill_llc_hdr (stream); + if (level == IS_LEVEL_1) + fill_fixed_hdr_andstream(&fixed_hdr, L1_PARTIAL_SEQ_NUM, + circuit->snd_stream); + else + fill_fixed_hdr_andstream(&fixed_hdr, L2_PARTIAL_SEQ_NUM, + circuit->snd_stream); + + + lenp = stream_get_endp(circuit->snd_stream); + stream_putw(circuit->snd_stream, 0); /* PDU length */ + stream_put(circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN); + stream_putc(circuit->snd_stream, circuit->idx); + stream_putc(circuit->snd_stream, 9); /* code */ + stream_putc(circuit->snd_stream, 16); /* len */ + + stream_putw(circuit->snd_stream, ntohs(hdr->rem_lifetime)); + stream_put(circuit->snd_stream, hdr->lsp_id, ISIS_SYS_ID_LEN + 2); + stream_putl(circuit->snd_stream, ntohl(hdr->seq_num)); + stream_putw(circuit->snd_stream, ntohs(hdr->checksum)); + + length = (u_int16_t)stream_get_endp(circuit->snd_stream); + /* Update PDU length */ + stream_putw_at(circuit->snd_stream, lenp, length); + + retval = circuit->tx(circuit, level); + if (retval != ISIS_OK) + zlog_err("ISIS-Upd (%s): Send L%d LSP PSNP on %s failed", + circuit->area->area_tag, level, + circuit->interface->name); + + return retval; } |
