diff --git a/epan/dissectors/packet-scsi.c b/epan/dissectors/packet-scsi.c index f2e5a5737a..c3bf1ebe35 100644 --- a/epan/dissectors/packet-scsi.c +++ b/epan/dissectors/packet-scsi.c @@ -138,6 +138,7 @@ static int hf_scsi_release_flags = -1; static int hf_scsi_release_thirdpartyid = -1; static int hf_scsi_select_report = -1; static int hf_scsi_inq_add_len = -1; +static int hf_scsi_inq_peripheral = -1; static int hf_scsi_inq_qualifier = -1; static int hf_scsi_inq_vendor_id = -1; static int hf_scsi_inq_product_id = -1; @@ -181,6 +182,7 @@ static int hf_scsi_inq_tpc = -1; static int hf_scsi_inq_protect = -1; static int hf_scsi_inq_tpgs = -1; static int hf_scsi_inq_acaflags = -1; +static int hf_scsi_inq_rmbflags = -1; static int hf_scsi_inq_normaca = -1; static int hf_scsi_inq_hisup = -1; static int hf_scsi_inq_aerc = -1; @@ -210,7 +212,9 @@ static int hf_scsi_reassembled_in = -1; static gint ett_scsi = -1; static gint ett_scsi_page = -1; +static gint ett_scsi_inq_peripheral = -1; static gint ett_scsi_inq_acaflags = -1; +static gint ett_scsi_inq_rmbflags = -1; static gint ett_scsi_inq_sccsflags = -1; static gint ett_scsi_inq_bqueflags = -1; static gint ett_scsi_inq_reladrflags = -1; @@ -247,7 +251,6 @@ static const fragment_items scsi_frag_items = { }; - typedef guint32 scsi_cmnd_type; typedef guint32 scsi_device_type; @@ -1360,56 +1363,6 @@ static const value_string inq_rdf_vals[] = { { 0, NULL } }; -/* This dissects byte 3 of the SPC-3 standard INQ data (SPC-3 6.4.2) */ -static int -dissect_spc3_inq_acaflags(tvbuff_t *tvb, int offset, proto_tree *parent_tree) -{ - guint8 flags; - proto_item *item=NULL; - proto_tree *tree=NULL; - - if(parent_tree){ - item=proto_tree_add_item(parent_tree, hf_scsi_inq_acaflags, tvb, offset, 1, 0); - tree = proto_item_add_subtree (item, ett_scsi_inq_acaflags); - } - - flags=tvb_get_guint8 (tvb, offset); - - /* AERC (obsolete in spc3 and forward) */ - proto_tree_add_boolean(tree, hf_scsi_inq_aerc, tvb, offset, 1, flags); - if(flags&SCSI_INQ_ACAFLAGS_AERC){ - proto_item_append_text(item, " AERC"); - } - flags&=(~SCSI_INQ_ACAFLAGS_AERC); - - /* TRMTSK (obsolete in spc2 and forward) */ - proto_tree_add_boolean(tree, hf_scsi_inq_trmtsk, tvb, offset, 1, flags); - if(flags&SCSI_INQ_ACAFLAGS_TRMTSK){ - proto_item_append_text(item, " TrmTsk"); - } - flags&=(~SCSI_INQ_ACAFLAGS_TRMTSK); - - /* NormACA */ - proto_tree_add_boolean(tree, hf_scsi_inq_normaca, tvb, offset, 1, flags); - if(flags&SCSI_INQ_ACAFLAGS_NORMACA){ - proto_item_append_text(item, " NormACA"); - } - flags&=(~SCSI_INQ_ACAFLAGS_NORMACA); - - /* HiSup */ - proto_tree_add_boolean(tree, hf_scsi_inq_hisup, tvb, offset, 1, flags); - if(flags&SCSI_INQ_ACAFLAGS_HISUP){ - proto_item_append_text(item, " HiSup"); - } - flags&=(~SCSI_INQ_ACAFLAGS_HISUP); - - /* Response Data Format */ - proto_tree_add_item (tree, hf_scsi_inq_rdf, tvb, offset, 1, 0); - proto_item_append_text(item, " RDF:%s", val_to_str(flags&0x0f, inq_rdf_vals, "Unknown:%d")); - - offset+=1; - return offset; -} #define SCSI_INQ_SCCSFLAGS_SCCS 0x80 #define SCSI_INQ_SCCSFLAGS_ACC 0x40 @@ -1589,6 +1542,23 @@ dissect_spc3_inquiry (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 payload_len, scsi_task_data_t *cdata) { guint8 flags, i; + static const int *peripheal_fields[] = { + &hf_scsi_inq_qualifier, + &hf_scsi_inq_devtype, + NULL + }; + static const int *aca_fields[] = { + &hf_scsi_inq_aerc, /* obsolete in spc3 and forward */ + &hf_scsi_inq_trmtsk, /* obsolete in spc2 and forward */ + &hf_scsi_inq_normaca, + &hf_scsi_inq_hisup, + &hf_scsi_inq_rdf, + NULL + }; + static const int *rmb_fields[] = { + &hf_scsi_inq_rmb, + NULL + }; if (!isreq && (cdata == NULL || !(cdata->itlq->flags & 0x3)) && (tvb_length_remaining(tvb, offset)>=1) ) { @@ -1651,13 +1621,11 @@ dissect_spc3_inquiry (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, TRY_SCSI_CDB_ALLOC_LEN(pinfo, tvb, offset, cdata->itlq->alloc_len); /* Qualifier and DeviceType */ - proto_tree_add_item (tree, hf_scsi_inq_qualifier, tvb, offset, - 1, 0); - proto_tree_add_item (tree, hf_scsi_inq_devtype, tvb, offset, 1, 0); + proto_tree_add_bitmask(tree, tvb, offset, hf_scsi_inq_peripheral, ett_scsi_inq_peripheral, peripheal_fields, FALSE); offset+=1; /* RMB */ - proto_tree_add_item(tree, hf_scsi_inq_rmb, tvb, offset, 1, 0); + proto_tree_add_bitmask(tree, tvb, offset, hf_scsi_inq_rmbflags, ett_scsi_inq_rmbflags, rmb_fields, FALSE); offset+=1; /* Version */ @@ -1665,7 +1633,8 @@ dissect_spc3_inquiry (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, offset+=1; /* aca flags */ - offset=dissect_spc3_inq_acaflags(tvb, offset, tree); + proto_tree_add_bitmask(tree, tvb, offset, hf_scsi_inq_acaflags, ett_scsi_inq_acaflags, aca_fields, FALSE); + offset+=1; /* Additional Length */ SET_SCSI_DATA_END(tvb_get_guint8(tvb, offset)+offset); @@ -4275,8 +4244,11 @@ proto_register_scsi (void) {"Additional Length", "scsi.inquiry.add_len", FT_UINT8, BASE_DEC, NULL, 0, "", HFILL}}, { &hf_scsi_inq_qualifier, - {"Peripheral Qualifier", "scsi.inquiry.qualifier", FT_UINT8, BASE_HEX, + {"Qualifier", "scsi.inquiry.qualifier", FT_UINT8, BASE_HEX, VALS (scsi_qualifier_val), 0xE0, "", HFILL}}, + { &hf_scsi_inq_peripheral, + {"Peripheral", "scsi.inquiry.preipheral", FT_UINT8, BASE_HEX, + NULL, 0, "", HFILL}}, { &hf_scsi_inq_vendor_id, {"Vendor Id", "scsi.inquiry.vendor_id", FT_STRING, BASE_NONE, NULL, 0, "", HFILL}}, @@ -4290,7 +4262,7 @@ proto_register_scsi (void) {"Version Description", "scsi.inquiry.version_desc", FT_UINT16, BASE_HEX, VALS(scsi_verdesc_val), 0, "", HFILL}}, { &hf_scsi_inq_devtype, - {"Peripheral Device Type", "scsi.inquiry.devtype", FT_UINT8, BASE_HEX, + {"Device Type", "scsi.inquiry.devtype", FT_UINT8, BASE_HEX, VALS (scsi_devtype_val), SCSI_DEV_BITS, "", HFILL}}, { &hf_scsi_inq_rmb, {"Removable", "scsi.inquiry.removable", FT_BOOLEAN, 8, @@ -4349,6 +4321,9 @@ proto_register_scsi (void) { &hf_scsi_inq_acaflags, {"Flags", "scsi.inquiry.acaflags", FT_UINT8, BASE_HEX, NULL, 0, "", HFILL}}, + { &hf_scsi_inq_rmbflags, + {"Flags", "scsi.inquiry.rmbflags", FT_UINT8, BASE_HEX, NULL, 0, + "", HFILL}}, { &hf_scsi_inq_normaca, {"NormACA", "scsi.inquiry.normaca", FT_BOOLEAN, 8, TFS(&normaca_tfs), SCSI_INQ_ACAFLAGS_NORMACA, "", HFILL}}, @@ -4509,7 +4484,9 @@ proto_register_scsi (void) static gint *ett[] = { &ett_scsi, &ett_scsi_page, + &ett_scsi_inq_peripheral, &ett_scsi_inq_acaflags, + &ett_scsi_inq_rmbflags, &ett_scsi_inq_sccsflags, &ett_scsi_inq_bqueflags, &ett_scsi_inq_reladrflags, diff --git a/epan/proto.c b/epan/proto.c index ffc4227cbd..1cbcb19aac 100644 --- a/epan/proto.c +++ b/epan/proto.c @@ -5310,3 +5310,122 @@ proto_construct_match_selected_string(field_info *finfo, epan_dissect_t *edt) return NULL; return filter; } + + +/* This function will dissect a sequence of bytes that describe a + * bitmask. + * hf_hdr is a 8/16/24/32 bit integer that describes the bitmask to be dissected. + * This field will form an expansion under which the individual fields of the + * bitmask is dissected and displayed. + * This field must be of the type FT_[U]INT{8|16|24|32}. + * + * fields is an array of pointers to int that lists all the fields of the + * bitmask. These fields can be either of the type FT_BOOLEAN for flags + * or another integer of the same type/size as hf_hdr with a mask specified. + * This array is terminated by a NULL entry. + * + * FT_BOOLEAN bits that are set to 1 will have the name added to the expansion. + * FT_integer fields that have a value_string attached will have the + * matched string displayed on the expansion line. + */ +proto_item * +proto_tree_add_bitmask(proto_tree *parent_tree, tvbuff_t *tvb, int offset, int hf_hdr, gint ett, const int **fields, gboolean little_endian) +{ + proto_tree *tree=NULL; + proto_item *item=NULL; + header_field_info *hf_info; + int len=0; + guint32 value=0; + + hf_info=proto_registrar_get_nth(hf_hdr); + switch(hf_info->type){ + case FT_INT8: + case FT_UINT8: + len=1; + value=tvb_get_guint8(tvb, offset); + break; + case FT_INT16: + case FT_UINT16: + len=2; + if(little_endian){ + value=tvb_get_letohs(tvb, offset); + } else { + value=tvb_get_ntohs(tvb, offset); + } + break; + case FT_INT24: + case FT_UINT24: + len=3; + if(little_endian){ + value=tvb_get_letoh24(tvb, offset); + } else { + value=tvb_get_ntoh24(tvb, offset); + } + break; + case FT_INT32: + case FT_UINT32: + len=4; + if(little_endian){ + value=tvb_get_letohl(tvb, offset); + } else { + value=tvb_get_ntohl(tvb, offset); + } + break; + default: + g_assert_not_reached(); + } + + if(parent_tree){ + item=proto_tree_add_item(parent_tree, hf_hdr, tvb, offset, len, little_endian); + tree=proto_item_add_subtree(item, ett); + } + + while(*fields){ + header_field_info *hf_field; + guint32 tmpval, tmpmask; + + hf_field=proto_registrar_get_nth(**fields); + switch(hf_field->type){ + case FT_INT8: + case FT_UINT8: + case FT_INT16: + case FT_UINT16: + case FT_INT24: + case FT_UINT24: + case FT_INT32: + case FT_UINT32: + proto_tree_add_item(tree, **fields, tvb, offset, len, little_endian); + + /* Mask and shift out the value */ + tmpmask=hf_field->bitmask; + tmpval=value; + if(tmpmask){ + tmpval&=tmpmask; + while(!(tmpmask&0x00000001)){ + tmpval>>=1; + tmpmask>>=1; + } + } + /* Show the value_string content (if there is one) */ + if(hf_field->strings){ + proto_item_append_text(item, ", %s", val_to_str(tmpval, hf_field->strings, "Unknown")); + } + + break; + case FT_BOOLEAN: + proto_tree_add_item(tree, **fields, tvb, offset, len, little_endian); + /* if the flag is set, show the name */ + if(hf_field->bitmask&value){ + proto_item_append_text(item, ", %s", hf_field->name); + } + break; + default: + g_assert_not_reached(); + } + + fields++; + } + + return item; +} + diff --git a/epan/proto.h b/epan/proto.h index 361d5ecd01..fbc3b890e8 100644 --- a/epan/proto.h +++ b/epan/proto.h @@ -1554,4 +1554,8 @@ proto_construct_match_selected_string(field_info *finfo, epan_dissect_t *edt); extern field_info* proto_find_field_from_offset(proto_tree *tree, guint offset, tvbuff_t *tvb); + +extern proto_item * +proto_tree_add_bitmask(proto_tree *tree, tvbuff_t *tvb, int offset, int hf_hdr, gint ett, const int **fields, gboolean little_endian); + #endif /* proto.h */