Exemple #1
0
static int
dissect_msnip_gm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset)
{
	guint8 count;

	/* group count */
	count = tvb_get_guint8(tvb, offset);
	proto_tree_add_uint(parent_tree, hf_count, tvb, offset, 1, count);
	offset += 1;

	/* checksum */
	igmp_checksum(parent_tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 0);
	offset += 2;

	/* holdtime */
	proto_tree_add_uint(parent_tree, hf_holdtime, tvb, offset, 4, count);
	offset += 4;

	while (count--) {
		proto_tree *tree;
		proto_item *item;
		guint32 maddr;
		guint8 masklen;
		int old_offset = offset;

		item = proto_tree_add_item(parent_tree, hf_groups,
				tvb, offset, -1, ENC_NA);
		tree = proto_item_add_subtree(item, ett_groups);

		/* multicast group */
		maddr = tvb_get_ipv4(tvb, offset);
		proto_tree_add_ipv4(tree, hf_maddr, tvb, offset, 4,
			maddr);
		offset += 4;

		/* mask length */
		masklen = tvb_get_guint8(tvb, offset);
		proto_tree_add_uint(tree, hf_mask, tvb,
			offset, 1, masklen);
		offset += 1;

		/* skip 3 unused bytes */
		offset += 3;

		if (item) {
			proto_item_set_text(item,"Group: %s/%d",
				ip_to_str((guint8 *)&maddr), masklen);

			proto_item_set_len(item, offset-old_offset);
		}
	}

	return offset;
}
Exemple #2
0
static int
dissect_mrdisc_mrst(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset)
{
	/* skip reserved byte */
	offset += 1;

	/* checksum */
	igmp_checksum(parent_tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 0);
	offset += 2;

	return offset;
}
Exemple #3
0
static int
dissect_msnip_rmr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset)
{
	guint8 count;

	/* group count */
	count = tvb_get_guint8(tvb, offset);
	proto_tree_add_uint(parent_tree, hf_count, tvb, offset, 1, count);
	offset += 1;

	/* checksum */
	igmp_checksum(parent_tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 0);
	offset += 2;

	while (count--) {
		proto_tree *tree;
		proto_item *item;
		guint8 rec_type;
		guint32 maddr;
		int old_offset = offset;

		item = proto_tree_add_item(parent_tree, hf_groups,
				tvb, offset, -1, ENC_NA);
		tree = proto_item_add_subtree(item, ett_groups);

		/* record type */
		rec_type = tvb_get_guint8(tvb, offset);
		proto_tree_add_uint(tree, hf_rec_type, tvb, offset, 1, rec_type);
		offset += 1;

		/* skip 3 unused bytes */
		offset += 3;

		/* multicast group */
		maddr = tvb_get_ipv4(tvb, offset);
		proto_tree_add_ipv4(tree, hf_maddr, tvb, offset, 4,
			maddr);
		offset += 4;

		if (item) {
			proto_item_set_text(item,"Group: %s %s",
				ip_to_str((guint8 *)&maddr),
				val_to_str(rec_type, msnip_rec_types,
					"Unknown Type:0x%02x"));

			proto_item_set_len(item, offset-old_offset);
		}
	}

	return offset;
}
Exemple #4
0
static int
dissect_msnip_is(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset)
{

	/* skip reserved byte */
	offset += 1;

	/* checksum */
	igmp_checksum(parent_tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 0);
	offset += 2;

	/* 16 bit holdtime */
	proto_tree_add_uint(parent_tree, hf_holdtime16, tvb, offset, 2, tvb_get_ntohs(tvb, offset));
	offset += 2;

	/* Generation ID */
	proto_tree_add_uint(parent_tree, hf_genid, tvb, offset, 2, tvb_get_ntohs(tvb, offset));
	offset += 2;

	return offset;
}
/* This function is only called from the IGMP dissector */
int
dissect_rgmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset)
{
    proto_tree *tree;
    proto_item *item;
    guint8 type;

    if (!proto_is_protocol_enabled(find_protocol_by_id(proto_rgmp))) {
        /* we are not enabled, skip entire packet to be nice
           to the igmp layer. (so clicking on IGMP will display the data)
           */
        return offset + tvb_length_remaining(tvb, offset);
    }

    item = proto_tree_add_item(parent_tree, proto_rgmp, tvb, offset, -1, ENC_NA);
    tree = proto_item_add_subtree(item, ett_rgmp);

    col_set_str(pinfo->cinfo, COL_PROTOCOL, "RGMP");
    col_clear(pinfo->cinfo, COL_INFO);

    type = tvb_get_guint8(tvb, offset);
    if (check_col(pinfo->cinfo, COL_INFO)) {
        col_add_str(pinfo->cinfo, COL_INFO,
                    val_to_str(type, rgmp_types, "Unknown Type: 0x%02x"));
    }
    proto_tree_add_uint(tree, hf_type, tvb, offset, 1, type);
    offset += 1;

    /* reserved */

    offset += 1;

    igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 0);
    offset += 2;

    proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, ENC_BIG_ENDIAN);
    offset += 4;

    return offset;
}
Exemple #6
0
/* This function is only called from the IGMP dissector */
int
dissect_igap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset)
{
    proto_tree *tree;
    proto_item *item;
    guint8 type, tsecs, subtype, asize, msize;
    guchar account[ACCOUNT_SIZE+1], message[MESSAGE_SIZE+1];

    if (!proto_is_protocol_enabled(find_protocol_by_id(proto_igap))) {
        /* we are not enabled, skip entire packet to be nice
           to the igmp layer. (so clicking on IGMP will display the data)
           */
        return offset + tvb_length_remaining(tvb, offset);
    }

    item = proto_tree_add_item(parent_tree, proto_igap, tvb, offset, -1, ENC_NA);
    tree = proto_item_add_subtree(item, ett_igap);

    col_set_str(pinfo->cinfo, COL_PROTOCOL, "IGAP");
    col_clear(pinfo->cinfo, COL_INFO);

    type = tvb_get_guint8(tvb, offset);
        col_add_str(pinfo->cinfo, COL_INFO,
                     val_to_str(type, igap_types, "Unknown Type: 0x%02x"));
    proto_tree_add_uint(tree, hf_type, tvb, offset, 1, type);
    offset += 1;

    tsecs = tvb_get_guint8(tvb, offset);
    proto_tree_add_uint_format_value(tree, hf_max_resp, tvb, offset, 1, tsecs,
        "%.1f sec (0x%02x)", tsecs * 0.1, tsecs);
    offset += 1;

    igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 0);
    offset += 2;

    proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, ENC_BIG_ENDIAN);
    offset += 4;

    proto_tree_add_uint(tree, hf_version, tvb, offset, 1,
        tvb_get_guint8(tvb, offset));
    offset += 1;

    subtype = tvb_get_guint8(tvb, offset);
    proto_tree_add_uint(tree, hf_subtype, tvb, offset, 1, subtype);
    offset += 2;

    proto_tree_add_uint(tree, hf_challengeid, tvb, offset, 1,
        tvb_get_guint8(tvb, offset));
    offset += 1;

    asize = tvb_get_guint8(tvb, offset);
    proto_tree_add_uint(tree, hf_asize, tvb, offset, 1, asize);
    offset += 1;

    msize = tvb_get_guint8(tvb, offset);
    proto_tree_add_uint(tree, hf_msize, tvb, offset, 1, msize);
    offset += 3;

    if (asize > 0) {
        if (asize > ACCOUNT_SIZE) {
            /* Bogus account size.
               XXX - flag this? */
            asize = ACCOUNT_SIZE;
        }
        tvb_memcpy(tvb, account, offset, asize);
        account[asize] = '\0';
        proto_tree_add_string(tree, hf_account, tvb, offset, asize, account);
    }
    offset += ACCOUNT_SIZE;

    if (msize > 0) {
        if (msize > MESSAGE_SIZE) {
            /* Bogus message size.
               XXX - flag this? */
            msize = MESSAGE_SIZE;
        }
        tvb_memcpy(tvb, message, offset, msize);
        switch (subtype) {
        case IGAP_SUBTYPE_PASSWORD_JOIN:
        case IGAP_SUBTYPE_PASSWORD_LEAVE:
            /* Challenge field is user's password */
            message[msize] = '\0';
            proto_tree_add_string(tree, hf_igap_user_password, tvb, offset, msize, message);
            break;
        case IGAP_SUBTYPE_CHALLENGE_RESPONSE_JOIN:
        case IGAP_SUBTYPE_CHALLENGE_RESPONSE_LEAVE:
            /* Challenge field is the results of MD5 calculation */
            proto_tree_add_item(tree, hf_igap_result_of_md5_calculation, tvb, offset, msize, ENC_NA);
            break;
        case IGAP_SUBTYPE_CHALLENGE:
            /* Challenge field is the challenge value */
            proto_tree_add_item(tree, hf_igap_challenge, tvb, offset, msize, ENC_NA);
            break;
        case IGAP_SUBTYPE_AUTH_MESSAGE:
            /* Challenge field indicates the result of the authenticaion */
            proto_tree_add_uint(tree, hf_igap_authentication_result, tvb, offset, msize, message[0]);
            break;
        case IGAP_SUBTYPE_ACCOUNTING_MESSAGE:
            /* Challenge field indicates the accounting status */
            proto_tree_add_uint(tree, hf_igap_accounting_status, tvb, offset, msize, message[0]);
            break;
        default:
            proto_tree_add_item(tree, hf_igap_unknown_message, tvb, offset, msize, ENC_NA);
        }
    }
    offset += MESSAGE_SIZE;

    if (item) proto_item_set_len(item, offset);
    return offset;
}
Exemple #7
0
static int
dissect_dvmrp_v1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset)
{
	guint8 code;
	guint8 af=2; /* default */

	/* version */
	proto_tree_add_uint(parent_tree, hf_version, tvb, 0, 0, 1);

	/* type of command */
	proto_tree_add_uint(parent_tree, hf_type, tvb, offset, 1, 0x13);
	offset += 1;

	/* code */
	code = tvb_get_guint8(tvb, offset);
	proto_tree_add_uint(parent_tree, hf_code_v1, tvb, offset, 1, code);
	offset += 1;
	col_add_fstr(pinfo->cinfo, COL_INFO,
			"V%d %s",1 ,val_to_str(code, code_v1,
				"Unknown Type:0x%02x"));

	/* checksum */
	igmp_checksum(parent_tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 0);
	offset += 2;

	/* decode all the v1 commands */
	while (tvb_reported_length_remaining(tvb, offset) > 0) {
		proto_tree *tree;
		proto_item *item;
		guint8 cmd,count;
		int old_offset = offset;

		item = proto_tree_add_item(parent_tree, hf_commands,
				tvb, offset, -1, ENC_NA);
		tree = proto_item_add_subtree(item, ett_commands);

		cmd = tvb_get_guint8(tvb, offset);
		proto_tree_add_uint(tree, hf_command, tvb,
			offset, 1, cmd);
		offset += 1;

		switch (cmd){
		case V1_COMMAND_NULL:
			offset += 1; /* skip ignored/pad byte*/
			if (item) {
				proto_item_set_text(item, "Command: NULL");
			}
			break;
		case V1_COMMAND_AFI:
			af = tvb_get_guint8(tvb, offset);
			proto_tree_add_uint(tree, hf_afi, tvb,
				offset, 1, af);
			offset += 1;
			if (item) {
				proto_item_set_text(item, "%s: %s",
					val_to_str(cmd, command, "Unknown Command:0x%02x"),
					val_to_str(af, afi, "Unknown Family:0x%02x")
				);
			}
			break;
		case V1_COMMAND_SUBNETMASK:
			count = tvb_get_guint8(tvb, offset);
			proto_tree_add_uint(tree, hf_count, tvb,
				offset, 1, count);
			offset += 1;
			if (count) { /* must be 0 or 1 */
				proto_tree_add_item(tree, hf_netmask,
					tvb, offset, 4, ENC_BIG_ENDIAN);
				if (item) {
					proto_item_set_text(item, "%s: %d.%d.%d.%d",
						val_to_str(cmd, command, "Unknown Command:0x%02x"),
						tvb_get_guint8(tvb, offset),
						tvb_get_guint8(tvb, offset+1),
						tvb_get_guint8(tvb, offset+2),
						tvb_get_guint8(tvb, offset+3));
				}
				offset += 4;
			} else {
				if (item) {
					proto_item_set_text(item, "%s: <no mask supplied>",
						val_to_str(cmd, command, "Unknown Command:0x%02x"));
				}
			}
			break;
		case V1_COMMAND_METRIC:
			proto_tree_add_item(tree, hf_metric, tvb,
				offset, 1, ENC_BIG_ENDIAN);
			if (item) {
				proto_item_set_text(item, "%s: %d",
					val_to_str(cmd, command, "Unknown Command:0x%02x"),
					tvb_get_guint8(tvb, offset));
			}
			offset += 1;
			break;
		case V1_COMMAND_FLAGS0:
			count = tvb_get_guint8(tvb, offset);
			proto_tree_add_boolean(tree, hf_dest_unr, tvb, offset, 1, count);
			proto_tree_add_boolean(tree, hf_split_horiz, tvb, offset, 1, count);
			if (item) {
				proto_item_set_text(item, "%s: 0x%02x",
					val_to_str(cmd, command, "Unknown Command:0x%02x"), count);
			}
			offset += 1;
			break;
		case V1_COMMAND_INFINITY:
			proto_tree_add_item(tree, hf_infinity, tvb,
				offset, 1, ENC_BIG_ENDIAN);
			if (item) {
				proto_item_set_text(item, "%s: %d",
					val_to_str(cmd, command, "Unknown Command:0x%02x"), tvb_get_guint8(tvb, offset));
			}
			offset += 1;
			break;
		case V1_COMMAND_DA:
		case V1_COMMAND_RDA: /* same as DA */
			count = tvb_get_guint8(tvb, offset);
			proto_tree_add_uint(tree, hf_count, tvb,
				offset, 1, count);
			offset += 1;
			while (count--) {
				proto_tree_add_item(tree, hf_daddr,
					tvb, offset, 4, ENC_BIG_ENDIAN);
				offset += 4;
			}
			if (item) {
				proto_item_set_text(item, "%s",
					val_to_str(cmd, command, "Unknown Command:0x%02x"));
			}
			break;
		case V1_COMMAND_NMR:
			count = tvb_get_guint8(tvb, offset);
			proto_tree_add_uint(tree, hf_count, tvb,
				offset, 1, count);
			offset += 1;
			while (count--) {
				proto_tree_add_item(tree, hf_maddr,
					tvb, offset, 4, ENC_BIG_ENDIAN);
				offset += 4;
				proto_tree_add_item(tree, hf_hold, tvb,
					offset, 4, ENC_BIG_ENDIAN);
				offset += 4;
			}
			if (item) {
				proto_item_set_text(item, "%s",
					val_to_str(cmd, command, "Unknown Command:0x%02x"));
			}
			break;
		case V1_COMMAND_NMR_CANCEL:
			count = tvb_get_guint8(tvb, offset);
			proto_tree_add_uint(tree, hf_count, tvb,
				offset, 1, count);
			offset += 1;
			while (count--) {
				proto_tree_add_item(tree, hf_maddr,
					tvb, offset, 4, ENC_BIG_ENDIAN);
				offset += 4;
			}
			if (item) {
				proto_item_set_text(item, "%s",
					val_to_str(cmd, command, "Unknown Command:0x%02x"));
			}
			break;
		}

		proto_item_set_len(item, offset-old_offset);
	}

	return offset;
}
Exemple #8
0
static int
dissect_dvmrp_v3(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset)
{
	guint8 code;

	/* version */
	proto_tree_add_uint(parent_tree, hf_version, tvb, 0, 0, 3);

	/* type of command */
	proto_tree_add_uint(parent_tree, hf_type, tvb, offset, 1, 0x13);
	offset += 1;

	/* code */
	code = tvb_get_guint8(tvb, offset);
	proto_tree_add_uint(parent_tree, hf_code_v3, tvb, offset, 1, code);
	offset += 1;
	col_add_fstr(pinfo->cinfo, COL_INFO,
			"V%d %s",3 ,val_to_str(code, code_v3,
				"Unknown Type:0x%02x"));

	/* checksum */
	igmp_checksum(parent_tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 0);
	offset += 2;

	/* skip unused byte */
	offset += 1;

	/* PROBE and NEIGHBORS 2 packets have capabilities flags, unused
	   for other packets */
	if (code==DVMRP_V3_PROBE || code==DVMRP_V3_NEIGHBORS_2) {
		static const int * capabilities[] = {
			&hf_cap_netmask,
			&hf_cap_snmp,
			&hf_cap_mtrace,
			&hf_cap_genid,
			&hf_cap_prune,
			&hf_cap_leaf,
			NULL
		};

		proto_tree_add_bitmask(parent_tree, tvb, offset, hf_capabilities,
			       ett_capabilities, capabilities, ENC_NA);
	}
	offset += 1;

	/* minor version */
	proto_tree_add_item(parent_tree, hf_min_ver, tvb, offset, 1, ENC_BIG_ENDIAN);
	offset += 1;

	/* major version */
	proto_tree_add_item(parent_tree, hf_maj_ver, tvb, offset, 1, ENC_BIG_ENDIAN);
	offset += 1;

	switch (code) {
	case DVMRP_V3_PROBE:
		/* generation id */
		proto_tree_add_item(parent_tree, hf_genid, tvb,
			offset, 4, ENC_BIG_ENDIAN);
		offset += 4;
		while (tvb_reported_length_remaining(tvb, offset)>=4) {
			proto_tree_add_item(parent_tree, hf_neighbor,
				tvb, offset, 4, ENC_BIG_ENDIAN);
			offset += 4;
		}
		break;
	case DVMRP_V3_REPORT:
		offset = dissect_v3_report(tvb, parent_tree, offset);
		break;
	case DVMRP_V3_PRUNE:
		/* source address */
		proto_tree_add_item(parent_tree, hf_saddr,
			tvb, offset, 4, ENC_BIG_ENDIAN);
		offset += 4;
		/* group address */
		proto_tree_add_item(parent_tree, hf_maddr,
			tvb, offset, 4, ENC_BIG_ENDIAN);
		offset += 4;
		/* prune lifetime */
		proto_tree_add_item(parent_tree, hf_life,
			tvb, offset, 4, ENC_BIG_ENDIAN);
		offset += 4;
		/* source netmask */
		if (tvb_reported_length_remaining(tvb, offset)>=4) {
			proto_tree_add_item(parent_tree, hf_netmask,
				tvb, offset, 4, ENC_BIG_ENDIAN);
			offset += 4;
		}
		break;
	case DVMRP_V3_GRAFT:
		/* source address */
		proto_tree_add_item(parent_tree, hf_saddr,
			tvb, offset, 4, ENC_BIG_ENDIAN);
		offset += 4;
		/* group address */
		proto_tree_add_item(parent_tree, hf_maddr,
			tvb, offset, 4, ENC_BIG_ENDIAN);
		offset += 4;
		/* source netmask */
		if (tvb_reported_length_remaining(tvb, offset)>=4) {
			proto_tree_add_item(parent_tree, hf_netmask,
				tvb, offset, 4, ENC_BIG_ENDIAN);
			offset += 4;
		}
		break;
	case DVMRP_V3_GRAFT_ACK:
		/* source address */
		proto_tree_add_item(parent_tree, hf_saddr,
			tvb, offset, 4, ENC_BIG_ENDIAN);
		offset += 4;
		/* group address */
		proto_tree_add_item(parent_tree, hf_maddr,
			tvb, offset, 4, ENC_BIG_ENDIAN);
		offset += 4;
		/* source netmask */
		if (tvb_reported_length_remaining(tvb, offset)>=4) {
			proto_tree_add_item(parent_tree, hf_netmask,
				tvb, offset, 4, ENC_BIG_ENDIAN);
			offset += 4;
		}
		break;
	case DVMRP_V3_ASK_NEIGHBORS:
	case DVMRP_V3_NEIGHBORS:
		/* XXX - obsolete, and the draft doesn't describe them */
		break;
	case DVMRP_V3_ASK_NEIGHBORS_2:
		/* No data */
		break;
	case DVMRP_V3_NEIGHBORS_2:
		while (tvb_reported_length_remaining(tvb, offset)>=12) {
			guint8 neighbor_count;

			/* local address */
			proto_tree_add_item(parent_tree, hf_local,
				tvb, offset, 4, ENC_BIG_ENDIAN);
			offset += 4;
			/* Metric */
			proto_tree_add_item(parent_tree, hf_metric,
				tvb, offset, 1, ENC_BIG_ENDIAN);
			offset += 1;
			/* Threshold */
			proto_tree_add_item(parent_tree, hf_threshold,
				tvb, offset, 1, ENC_BIG_ENDIAN);
			offset += 1;
			/* Flags */
			{
				proto_tree *tree;
				proto_item *item;

				item = proto_tree_add_item(parent_tree, hf_flags,
					tvb, offset, 1, ENC_NA);
				tree = proto_item_add_subtree(item, ett_flags);

				proto_tree_add_item(tree, hf_flag_tunnel, tvb,
					offset, 1, ENC_BIG_ENDIAN);
				proto_tree_add_item(tree, hf_flag_srcroute, tvb,
					offset, 1, ENC_BIG_ENDIAN);
				proto_tree_add_item(tree, hf_flag_down, tvb,
					offset, 1, ENC_BIG_ENDIAN);
				proto_tree_add_item(tree, hf_flag_disabled, tvb,
					offset, 1, ENC_BIG_ENDIAN);
				proto_tree_add_item(tree, hf_flag_querier, tvb,
					offset, 1, ENC_BIG_ENDIAN);
				proto_tree_add_item(tree, hf_flag_leaf, tvb,
					offset, 1, ENC_BIG_ENDIAN);
			}
			offset += 1;
			/* Neighbor count */
			neighbor_count = tvb_get_guint8(tvb, offset);
			proto_tree_add_item(parent_tree, hf_ncount,
				tvb, offset, 1, ENC_BIG_ENDIAN);
			offset += 1;

			while ((tvb_reported_length_remaining(tvb, offset)>=4)
				&& (neighbor_count>0)) {
				proto_tree_add_item(parent_tree, hf_neighbor,
					tvb, offset, 4, ENC_BIG_ENDIAN);
				offset += 4;
				neighbor_count--;
			}
		}
		break;
	}

	return offset;
}
Exemple #9
0
static int
dissect_mrdisc_mra(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset)
{
	guint16 num;

	/* Advertising Interval */
	proto_tree_add_item(parent_tree, hf_advint, tvb, offset, 1, ENC_BIG_ENDIAN);
	offset += 1;

	/* checksum */
	igmp_checksum(parent_tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 0);
	offset += 2;

	/* skip unused bytes */
	offset += 2;

	/* number of options */
	num = tvb_get_ntohs(tvb, offset);
	proto_tree_add_uint(parent_tree, hf_numopts, tvb,
		offset, 2, num);
	offset += 2;

	/* process any options */
	while (num--) {
		proto_tree *tree;
		proto_item *item;
		guint8 type,len;
		int old_offset = offset;

		item = proto_tree_add_item(parent_tree, hf_options,
			tvb, offset, -1, ENC_NA);
		tree = proto_item_add_subtree(item, ett_options);

		type = tvb_get_guint8(tvb, offset);
		proto_tree_add_uint(tree, hf_option, tvb, offset, 1, type);
		offset += 1;

		len = tvb_get_guint8(tvb, offset);
		proto_tree_add_uint(tree, hf_option_len, tvb, offset, 1, len);
		offset += 1;

		switch (type) {
		case MRDISC_QI:
			if (item) {
				proto_item_set_text(item,"Option: %s == %d",
					val_to_str(type, mrdisc_options, "unknown %x"),
					tvb_get_ntohs(tvb, offset));
			}

			if (len != 2)
				THROW(ReportedBoundsError);
			proto_tree_add_item(tree, hf_qi, tvb, offset, len,
				ENC_BIG_ENDIAN);
			offset += len;
			break;
		case MRDISC_RV:
			if (item) {
				proto_item_set_text(item,"Option: %s == %d",
					val_to_str(type, mrdisc_options, "unknown %x"),
					tvb_get_ntohs(tvb, offset));
			}

			if (len != 2)
				THROW(ReportedBoundsError);
			proto_tree_add_item(tree, hf_rv, tvb, offset, len,
				ENC_BIG_ENDIAN);
			offset += len;
			break;
		default:
			if (item) {
				proto_item_set_text(item,"Option: unknown");
			}

			proto_tree_add_item(tree, hf_option_bytes,
				tvb, offset, len, ENC_NA);
			offset += len;
		}
		if (item) {
			proto_item_set_len(item, offset-old_offset);
		}
	}

	return offset;
}