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:
parent
cc3567fabf
commit
41c258daf3
|
@ -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,
|
||||
|
|
119
epan/proto.c
119
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue