/* packet-isis-lsp.c
* Routines for decoding isis lsp packets and their CLVs
*
- * $Id: packet-isis-lsp.c,v 1.42 2003/04/29 16:57:05 guy Exp $
+ * $Id: packet-isis-lsp.c,v 1.43 2003/05/15 06:35:02 guy Exp $
* Stuart Stanley <stuarts@mxmail.net>
*
* Ethereal - Network traffic analyzer
static int hf_isis_lsp_is_type = -1;
static gint ett_isis_lsp = -1;
+static gint ett_isis_lsp_checksum = -1;
static gint ett_isis_lsp_info = -1;
static gint ett_isis_lsp_att = -1;
static gint ett_isis_lsp_clv_area_addr = -1;
ctrl_info = tvb_get_guint8(tvb, offset+4);
bit_length = ctrl_info & 0x3f;
byte_length = (bit_length + 7) / 8;
- tvb_memcpy (tvb, prefix, offset+5, byte_length);
+ if (byte_length > sizeof(prefix)) {
+ isis_dissect_unknown(tvb, tree, offset,
+ "IPv4 prefix has an invalid length: %d bytes", byte_length );
+ return;
+ }
+ tvb_memcpy (tvb, prefix, offset+5, byte_length);
metric = tvb_get_ntohl(tvb, offset);
subclvs_len = 0;
if ((ctrl_info & 0x40) != 0)
if (!tree) return;
- memset (prefix.s6_addr, 0, 16);
-
while (length > 0) {
+ memset (prefix.s6_addr, 0, 16);
ctrl_info = tvb_get_guint8(tvb, offset+4);
bit_length = tvb_get_guint8(tvb, offset+5);
byte_length = (bit_length + 7) / 8;
- tvb_memcpy (tvb, prefix.s6_addr, offset+6, byte_length);
+ if (byte_length > sizeof(prefix)) {
+ isis_dissect_unknown(tvb, tree, offset,
+ "IPv6 prefix has an invalid length: %d bytes", byte_length );
+ return;
+ }
+ tvb_memcpy (tvb, prefix.s6_addr, offset+6, byte_length);
metric = tvb_get_ntohl(tvb, offset);
subclvs_len = 0;
if ((ctrl_info & 0x20) != 0)
isis_dissect_isis_lsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset,
int lsp_type, int header_length, int id_length)
{
- proto_item *ti, *to, *ta;
- proto_tree *lsp_tree = NULL, *info_tree, *att_tree;
- guint16 pdu_length;
+ proto_item *ti, *to, *ta, *tc;
+ proto_tree *lsp_tree = NULL, *info_tree, *att_tree, *check_tree;
+ guint16 pdu_length, checksum, cacl_checksum=0;
guint8 lsp_info, lsp_att;
- int len;
+ int len, offset_checksum;
if (tree) {
ti = proto_tree_add_text(tree, tvb, offset, -1,
tvb_get_ntohs(tvb, offset));
}
offset += 2;
+ offset_checksum = offset;
if (tree) {
proto_tree_add_text(lsp_tree, tvb, offset, id_length + 2,
offset += 4;
if (tree) {
- /* XXX -> we could validate the cksum here! */
- proto_tree_add_uint(lsp_tree, hf_isis_lsp_checksum, tvb,
- offset, 2, tvb_get_ntohs(tvb, offset));
+ checksum = tvb_get_ntohs(tvb, offset);
+ tc = proto_tree_add_uint(lsp_tree, hf_isis_lsp_checksum, tvb, offset, 2, tvb_get_ntohs(tvb, offset));
+ check_tree = proto_item_add_subtree(tc, ett_isis_lsp_checksum);
+
+ switch (check_and_get_checksum(tvb, offset_checksum, pdu_length-12, checksum, offset, &cacl_checksum)) {
+ case NO_CKSUM :
+ proto_tree_add_text(check_tree, tvb, offset, 2,
+ "Checksum control disabled");
+ break;
+ case DATA_MISSING :
+ isis_dissect_unknown(tvb, tree, offset,
+ "packet length %d went beyond packet",
+ tvb_length_remaining(tvb, offset_checksum));
+ break;
+ case CKSUM_NOT_OK :
+ proto_tree_add_text(check_tree, tvb, offset, 2,
+ "Checksum error: 0x%04x expected", cacl_checksum);
+ break;
+ case CKSUM_OK :
+ proto_tree_add_text(check_tree, tvb, offset, 2,
+ "Checksum OK");
+ break;
+ default :
+ g_message("'check_and_get_checksum' returned an invalid value");
+ }
}
offset += 2;
};
static gint *ett[] = {
&ett_isis_lsp,
+ &ett_isis_lsp_checksum,
&ett_isis_lsp_info,
&ett_isis_lsp_att,
&ett_isis_lsp_clv_area_addr,
* Routines for ISO/OSI network and transport protocol packet disassembly
* Main entrance point and common functions
*
- * $Id: packet-osi.c,v 1.60 2003/04/29 17:56:48 guy Exp $
+ * $Id: packet-osi.c,v 1.61 2003/05/15 06:35:02 guy Exp $
* Laurent Deniel <laurent.deniel@free.fr>
* Ralf Schneider <Ralf.Schneider@t-online.de>
*
len -= seglen;
}
if (c0 != 0 || c1 != 0)
- return( CKSUM_NOT_OK ); /* XXX - what should the checksum be? */
+ return( CKSUM_NOT_OK ); /* XXX - what should the checksum field be? */
else
return( CKSUM_OK );
}
+cksum_status_t
+check_and_get_checksum( tvbuff_t *tvb, int offset, guint len, guint checksum, int offset_check, guint16* result) {
+ const gchar *buffer;
+ guint available_len;
+ const guint8 *p;
+ guint8 discard = 0;
+ guint32 c0, c1, factor;
+ guint seglen, initlen = len;
+ guint i;
+ int block, x, y;
+
+ if ( 0 == checksum )
+ return( NO_CKSUM );
+
+ available_len = tvb_length_remaining( tvb, offset );
+ offset_check -= offset;
+ if ( ( available_len < len ) || ( offset_check < 0 ) || ( (guint)(offset_check+2) > len ) )
+ return( DATA_MISSING );
+
+ buffer = tvb_get_ptr( tvb, offset, len );
+ block = offset_check / 5803;
+
+ /*
+ * The maximum values of c0 and c1 will occur if all bytes have the
+ * value 255; if so, then c0 will be len*255 and c1 will be
+ * (len*255 + (len-1)*255 + ... + 255), which is
+ * (len + (len - 1) + ... + 1)*255, or 255*(len*(len + 1))/2.
+ * This means it can overflow if "len" is 5804 or greater.
+ *
+ * (A+B) mod 255 = ((A mod 255) + (B mod 255) mod 255, so
+ * we can solve this by taking c0 and c1 mod 255 every
+ * 5803 bytes.
+ */
+ p = buffer;
+ c0 = 0;
+ c1 = 0;
+
+ while (len != 0) {
+ seglen = len;
+ if ( block-- == 0 ) {
+ seglen = offset_check % 5803;
+ discard = 1;
+ } else if ( seglen > 5803 )
+ seglen = 5803;
+ for (i = 0; i < seglen; i++) {
+ c0 = c0 + *(p++);
+ c1 += c0;
+ }
+ if ( discard ) {
+ /*
+ * This works even if (offset_check % 5803) == 5802
+ */
+ p += 2;
+ c1 += 2*c0;
+ len -= 2;
+ discard = 0;
+ }
+
+ c0 = c0 % 255;
+ c1 = c1 % 255;
+
+ len -= seglen;
+ }
+
+ factor = ( initlen - offset_check ) * c0;
+ x = factor - c0 - c1;
+ y = c1 - factor - 1;
+
+ /*
+ * This algorithm uses the 8 bits one's complement arithmetic.
+ * Therefore, we must correct an effect produced
+ * by the "standard" arithmetic (two's complement)
+ */
+
+ if (x < 0 ) x--;
+ if (y > 0 ) y++;
+
+ x %= 255;
+ y %= 255;
+
+ if (x == 0) x = 0xFF;
+ if (y == 0) y = 0x01;
+
+ *result = ( x << 8 ) | ( y & 0xFF );
+
+ if (*result != checksum)
+ return( CKSUM_NOT_OK ); /* XXX - what should the checksum field be? */
+ else
+ return( CKSUM_OK );
+}
+
+
+
/* main entry point */
/*