diff options
author | Subbaiah Venkata <svenkata@google.com> | 2012-03-27 23:48:05 -0700 |
---|---|---|
committer | Avneesh Sachdev <avneesh@opensourcerouting.org> | 2012-04-07 13:54:37 -0700 |
commit | e38e0df01ad305ad48ecf816b52fa99fd3f2a4e1 (patch) | |
tree | ad565c3d656c0d5b74a1a3a80f1774bef938b1b4 /isisd/isis_pdu.c | |
parent | 3f045a08812525505e165deea99a79447b44506b (diff) |
isisd: couple of bug fixes
Diffstat (limited to 'isisd/isis_pdu.c')
-rw-r--r-- | isisd/isis_pdu.c | 138 |
1 files changed, 94 insertions, 44 deletions
diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index fe943bba..497fad20 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -62,7 +62,7 @@ #endif /* PNBBY */ /* Utility mask array. */ -static const u_char maskbit[] = { +static u_char maskbit[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; @@ -225,16 +225,16 @@ lsp_authentication_check (struct stream *stream, struct isis_area *area, { struct isis_link_state_hdr *hdr; uint32_t expected = 0, found = 0, auth_tlv_offset = 0; - uint16_t checksum, rem_lifetime; + 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, - ntohs (hdr->pdu_len) - ISIS_FIXED_HDR_LEN - - ISIS_LSP_HDR_LEN, + pdu_len - ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN, &expected, &found, &tlvs, &auth_tlv_offset); if (retval != ISIS_OK) @@ -243,7 +243,7 @@ lsp_authentication_check (struct stream *stream, struct isis_area *area, "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), ntohs (hdr->pdu_len)); + 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)); @@ -397,6 +397,7 @@ process_p2p_hello (struct isis_circuit *circuit) 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; if (isis->debugs & DEBUG_ADJ_PACKETS) @@ -439,24 +440,27 @@ process_p2p_hello (struct isis_circuit *circuit) * Get the header */ hdr = (struct isis_p2p_hello_hdr *) STREAM_PNT (circuit->rcv_stream); - stream_forward_getp (circuit->rcv_stream, ISIS_P2PHELLO_HDRLEN); - - /* hdr.circuit_t = stream_getc (stream); - stream_get (hdr.source_id, stream, ISIS_SYS_ID_LEN); - hdr.hold_time = stream_getw (stream); - hdr.pdu_len = stream_getw (stream); - hdr.local_id = stream_getc (stream); */ + pdu_len = ntohs (hdr->pdu_len); - if (ntohs (hdr->pdu_len) > ISO_MTU(circuit)) + if (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, - ntohs (hdr->pdu_len)); + circuit->area->area_tag, circuit->interface->name, 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); + + stream_forward_getp (circuit->rcv_stream, ISIS_P2PHELLO_HDRLEN); + + /* * Lets get the TLVS now */ expected |= TLVFLAG_AREA_ADDRS; @@ -468,9 +472,8 @@ process_p2p_hello (struct isis_circuit *circuit) auth_tlv_offset = stream_get_getp (circuit->rcv_stream); retval = parse_tlvs (circuit->area->area_tag, STREAM_PNT (circuit->rcv_stream), - ntohs (hdr->pdu_len) - ISIS_P2PHELLO_HDRLEN - - ISIS_FIXED_HDR_LEN, &expected, &found, &tlvs, - &auth_tlv_offset); + pdu_len - ISIS_P2PHELLO_HDRLEN - ISIS_FIXED_HDR_LEN, + &expected, &found, &tlvs, &auth_tlv_offset); if (retval > ISIS_WARNING) { @@ -821,7 +824,7 @@ process_p2p_hello (struct isis_circuit *circuit) " cir id %02d, length %d", circuit->area->area_tag, circuit->interface->name, circuit_t2string (circuit->is_type), - circuit->circuit_id, ntohs (hdr->pdu_len)); + circuit->circuit_id, pdu_len); } free_tlvs (&tlvs); @@ -906,15 +909,23 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa) hdr.prio = stream_getc (circuit->rcv_stream); stream_get (hdr.lan_id, circuit->rcv_stream, ISIS_SYS_ID_LEN + 1); - if (hdr.pdu_len > ISO_MTU(circuit)) + if (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); - hdr.pdu_len = stream_get_endp (circuit->rcv_stream); + 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 && @@ -1167,6 +1178,7 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa) int retval = ISIS_OK, comp = 0; u_char lspid[ISIS_SYS_ID_LEN + 2]; struct isis_passwd *passwd; + uint16_t pdu_len; if (isis->debugs & DEBUG_UPDATE_PACKETS) { @@ -1187,6 +1199,26 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa) /* Reference the header */ hdr = (struct isis_link_state_hdr *) STREAM_PNT (circuit->rcv_stream); + pdu_len = ntohs (hdr->pdu_len); + + /* lsp length check */ + if (pdu_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); + + 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) { @@ -1198,24 +1230,25 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa) ntohl (hdr->seq_num), ntohs (hdr->checksum), ntohs (hdr->rem_lifetime), - ntohs (hdr->pdu_len), + pdu_len, circuit->interface->name); } - if (ntohs (hdr->pdu_len) <= ISIS_LSP_HDR_LEN || - ntohs (hdr->pdu_len) > ISO_MTU(circuit)) + /* 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 length %d", + zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP is type %x", circuit->area->area_tag, - rawlspid_print (hdr->lsp_id), ntohs (hdr->pdu_len)); - - return ISIS_WARNING; + 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, - ntohs (hdr->pdu_len) - 12, &hdr->checksum)) + pdu_len - 12, &hdr->checksum)) { zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP checksum 0x%04x", circuit->area->area_tag, @@ -1403,17 +1436,19 @@ dontcheckadj: * has information that the current sequence number for source S is * "greater" than that held by S, ... */ - else if (ntohl (hdr->seq_num) > ntohl (lsp->lsp_header->seq_num)) + if (ntohl (hdr->seq_num) > ntohl (lsp->lsp_header->seq_num)) { /* 7.3.16.1 */ lsp_inc_seqnum (lsp, ntohl (hdr->seq_num)); - lsp_set_all_srmflags (lsp); 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 { @@ -1440,7 +1475,7 @@ dontcheckadj: if (!lsp) { lsp = lsp_new_from_stream_ptr (circuit->rcv_stream, - ntohs (hdr->pdu_len), lsp0, + pdu_len, lsp0, circuit->area, level); lsp_insert (lsp, circuit->area->lspdb[level - 1]); } @@ -1489,7 +1524,7 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, int retval = ISIS_OK; int cmp, own_lsp; char typechar = ' '; - unsigned int len; + uint16_t pdu_len; struct isis_adjacency *adj; struct isis_complete_seqnum_hdr *chdr = NULL; struct isis_partial_seqnum_hdr *phdr = NULL; @@ -1508,12 +1543,14 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, typechar = 'C'; chdr = (struct isis_complete_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream); - circuit->rcv_stream->getp += ISIS_CSNP_HDRLEN; - len = ntohs (chdr->pdu_len); - if (len < ISIS_CSNP_HDRLEN || len > ISO_MTU(circuit)) + stream_forward_getp (circuit->rcv_stream, ISIS_CSNP_HDRLEN); + pdu_len = ntohs (chdr->pdu_len); + if (pdu_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", len); - return ISIS_OK; + zlog_warn ("Received a CSNP with bogus length %d", pdu_len); + return ISIS_WARNING; } } else @@ -1521,15 +1558,24 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, typechar = 'P'; phdr = (struct isis_partial_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream); - circuit->rcv_stream->getp += ISIS_PSNP_HDRLEN; - len = ntohs (phdr->pdu_len); - if (len < ISIS_PSNP_HDRLEN || len > ISO_MTU(circuit)) + stream_forward_getp (circuit->rcv_stream, ISIS_PSNP_HDRLEN); + pdu_len = ntohs (phdr->pdu_len); + if (pdu_len < ISIS_PSNP_HDRLEN || + pdu_len > ISO_MTU(circuit) || + pdu_len > stream_get_endp (circuit->rcv_stream)) { - zlog_warn ("Received a CSNP with bogus length %d", len); - return ISIS_OK; + zlog_warn ("Received a CSNP 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); + /* 7.3.15.2 a) 1 - external domain circuit will discard snp pdu */ if (circuit->ext_domain) { @@ -1617,7 +1663,7 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, auth_tlv_offset = stream_get_getp (circuit->rcv_stream); retval = parse_tlvs (circuit->area->area_tag, STREAM_PNT (circuit->rcv_stream), - len - circuit->rcv_stream->getp, + pdu_len - stream_get_getp (circuit->rcv_stream), &expected, &found, &tlvs, &auth_tlv_offset); if (retval > ISIS_WARNING) @@ -2585,6 +2631,7 @@ max_lsps_per_snp (int snp_type, int level, struct isis_circuit *circuit) 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; } /* @@ -2862,6 +2909,9 @@ send_psnp (int level, struct isis_circuit *circuit) dict_count (circuit->area->lspdb[level - 1]) == 0) return ISIS_OK; + if (! circuit->snd_stream) + return ISIS_ERROR; + num_lsps = max_lsps_per_snp (ISIS_SNP_PSNP_FLAG, level, circuit); while (1) |