create a nice helper to dissect bitmasks and implement some test useage of it in the scsi dissector

svn path=/trunk/; revision=20002
This commit is contained in:
Ronnie Sahlberg 2006-11-27 14:50:23 +00:00
parent cc3567fabf
commit 41c258daf3
3 changed files with 158 additions and 58 deletions

View File

@ -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,

View File

@ -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;
}

View File

@ -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 */