aboutsummaryrefslogtreecommitdiffstats
path: root/epan
diff options
context:
space:
mode:
authorMichael Mann <mmann78@netscape.net>2017-04-22 00:09:35 -0400
committerMichael Mann <mmann78@netscape.net>2017-04-24 20:27:03 +0000
commit6cbea5c01c636b1e4b2737e325addeb5ca32a11c (patch)
tree340994c75f4a2211e9430744335ff1879118a27d /epan
parent4b2ee367434572f288f1272cc4c1722a0c484798 (diff)
Convert BOOTP options into a dissector table.
This allows for much easier addition or overriding of options and use of Decode As. This includes adding heuristic dissector tables for vendor specific options. Change-Id: If52c00bbc23d89386ba3e777600f665609856de0 Reviewed-on: https://code.wireshark.org/review/21297 Petri-Dish: Michael Mann <mmann78@netscape.net> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Alexis La Goutte <alexis.lagoutte@gmail.com> Reviewed-by: Michael Mann <mmann78@netscape.net>
Diffstat (limited to 'epan')
-rw-r--r--epan/dissectors/packet-bootp.c2520
1 files changed, 1416 insertions, 1104 deletions
diff --git a/epan/dissectors/packet-bootp.c b/epan/dissectors/packet-bootp.c
index 1b23428317..500c12f5e5 100644
--- a/epan/dissectors/packet-bootp.c
+++ b/epan/dissectors/packet-bootp.c
@@ -612,7 +612,6 @@ static expert_field ei_bootp_mal_duid = EI_INIT;
static expert_field hf_bootp_opt_overload_file_end_missing = EI_INIT;
static expert_field hf_bootp_opt_overload_sname_end_missing = EI_INIT;
static expert_field hf_bootp_subopt_unknown_type = EI_INIT;
-static expert_field ei_bootp_option77_user_class_malformed = EI_INIT;
static expert_field ei_bootp_option_civic_location_bad_cattype = EI_INIT;
static expert_field ei_bootp_option_dhcp_name_service_invalid = EI_INIT;
static expert_field ei_bootp_option_sip_server_address_encoding = EI_INIT;
@@ -631,7 +630,21 @@ static expert_field ei_bootp_option_isns_ignored_bitfield = EI_INIT;
static expert_field ei_bootp_option242_avaya_l2qvlan_invalid = EI_INIT;
static expert_field ei_bootp_option242_avaya_vlantest_invalid = EI_INIT;
+static dissector_table_t bootp_option_table;
+static dissector_table_t bootp_enterprise_table;
+static heur_dissector_list_t bootp_vendor_id_subdissector;
+static heur_dissector_list_t bootp_vendor_info_subdissector;
static dissector_handle_t bootp_handle;
+static dissector_handle_t bootpopt_basic_handle;
+
+typedef struct bootp_option_data
+{
+ guchar option;
+ guint8 *overload;
+ tvbuff_t *orig_tvb;
+ const char *dhcp_type;
+ const guint8 *vendor_class_id;
+} bootp_option_data_t;
/* RFC2937 The Name Service Search Option for DHCP */
#define RFC2937_LOCAL_NAMING_INFORMATION 0
@@ -984,37 +997,11 @@ static const enum_val_t pkt_ccc_protocol_versions[] = {
static gint pkt_ccc_protocol_version = PACKETCABLE_CCC_RFC_3495;
static guint pkt_ccc_option = 122;
-
-static int dissect_vendor_pxeclient_suboption(packet_info *pinfo, proto_item *v_ti, proto_tree *v_tree,
- tvbuff_t *tvb, int optoff, int optend);
-static int dissect_vendor_cablelabs_suboption(packet_info *pinfo, proto_item *v_ti, proto_tree *v_tree,
- tvbuff_t *tvb, int optoff, int optend);
-static int dissect_vendor_bsdp_suboption(packet_info *pinfo, proto_item *v_ti, proto_tree *v_tree,
- tvbuff_t *tvb, int optoff, int optend);
-static gboolean test_encapsulated_vendor_options(tvbuff_t *tvb, int optoff, int optend);
-static int dissect_vendor_alcatel_suboption(packet_info *pinfo, proto_item *v_ti, proto_tree *v_tree,
- tvbuff_t *tvb, int optoff, int optend);
-static int dissect_netware_ip_suboption(packet_info *pinfo, proto_item *v_ti, proto_tree *v_tree,
- tvbuff_t *tvb, int optoff, int optend);
-static int dissect_vendor_tr111_suboption(packet_info *pinfo, proto_item *v_ti, proto_tree *v_tree,
- tvbuff_t *tvb, int optoff, int optend);
-static int bootp_dhcp_decode_agent_info(packet_info *pinfo, proto_item *v_ti, proto_tree *v_tree,
- tvbuff_t *tvb, int optoff, int optend);
-static void dissect_packetcable_mta_cap(proto_tree *v_tree, packet_info *pinfo, tvbuff_t *tvb,
- int voff, int len);
static void dissect_docsis_cm_cap(proto_tree *v_tree, tvbuff_t *tvb,
int voff, int len, gboolean opt125);
-static int dissect_packetcable_i05_ccc(packet_info *pinfo, proto_item *v_ti, proto_tree *v_tree,
- tvbuff_t *tvb, int optoff, int optend);
-static int dissect_packetcable_ietf_ccc(packet_info *pinfo, proto_item *v_ti, proto_tree *v_tree,
- tvbuff_t *tvb, int optoff, int optend, int revision);
-static int dissect_vendor_cl_suboption(packet_info *pinfo, proto_item *v_ti, proto_tree *v_tree,
- tvbuff_t *tvb, int optoff, int optend);
-static int dissect_vendor_generic_suboption(packet_info *pinfo, proto_item *v_ti, proto_tree *v_tree,
- tvbuff_t *tvb, int optoff, int optend);
-static int dissect_isns(packet_info *pinfo, proto_item *v_ti, proto_tree *v_tree,
- tvbuff_t *tvb, int optoff, int optlen);
-static void dissect_vendor_bsdp_boot_image(proto_tree *v_tree, tvbuff_t *tvb, int optoff);
+
+#define ARUBA_INSTANT_AP "ArubaInstantAP"
+#define ARUBA_AP "ArubaAP"
#define OPT53_DISCOVER "Discover"
/* http://www.iana.org/assignments/bootp-dhcp-parameters */
@@ -1215,6 +1202,9 @@ static const string_string option242_avaya_static_vals[] = {
/* bootp options administration */
#define BOOTP_OPT_NUM 256
+/* All of the options that have a "basic" type that can be handled by dissect_bootpopt_basic_type() */
+#define BOOTP_OPTION_BASICTYPE_RANGE "1-20,22-32,34-42,44-51,53-54,56-59,64-76,86-87,91-93,100-101,112-113,116,118,137-138,150,161,209-210,252"
+
/* Re-define structure. Values to be updated by bootp_init_protocol */
static struct opt_info bootp_opt[BOOTP_OPT_NUM];
@@ -1492,6 +1482,7 @@ typedef struct {
static uat_bootp_record_t *uat_bootp_records = NULL;
static uat_t *bootp_uat = NULL;
static guint num_bootp_records_uat = 0;
+static wmem_list_t *saved_uat_opts = NULL; /* List of previous options from UAT to "free" from dissection */
static void* uat_bootp_record_copy_cb(void* n, const void* o, size_t siz _U_) {
uat_bootp_record_t* new_record = (uat_bootp_record_t *)n;
@@ -1735,33 +1726,11 @@ bootp_handle_basic_types(packet_info *pinfo, proto_tree *tree, proto_item *item,
return consumed;
}
-/* Returns the number of bytes consumed by this option. */
static int
-bootp_option(tvbuff_t *tvb, packet_info *pinfo, proto_tree *bp_tree, proto_item *bp_item, int voff,
- int eoff, gboolean first_pass, gboolean *at_end, const char **dhcp_type_p,
- const guint8 **vendor_class_id_p, guint8 *overload_p)
+dissect_bootpopt_basic_type(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void* data)
{
struct opt_info *opt;
- enum field_type ftype;
- guchar code = tvb_get_guint8(tvb, voff);
- int optlen;
- guchar byte;
- int i, consumed, basictype_consumed;
- int optoff, optleft, optend;
- proto_tree *v_tree;
- proto_item *vti, *ti;
- guint8 protocol;
- guint8 algorithm;
- guint8 rdm;
- guint8 fqdn_flags;
- int o52voff, o52eoff;
- gboolean o52at_end;
- guint8 s_option;
- guint8 s_len;
- const guchar *dns_name;
- guint dns_name_len;
- gboolean option_handled = TRUE;
-
+ bootp_option_data_t *option_data = (bootp_option_data_t*)data;
struct basic_types_hfs default_hfs = {
&hf_bootp_option_value,
&hf_bootp_option_value_ip_address,
@@ -1776,6 +1745,29 @@ bootp_option(tvbuff_t *tvb, packet_info *pinfo, proto_tree *bp_tree, proto_item
&hf_bootp_option_value_u32
};
+ opt = bootp_get_opt(option_data->option);
+ if (opt == NULL)
+ return 0;
+
+ return bootp_handle_basic_types(pinfo, tree, tree, tvb, opt->ftype,
+ 0, tvb_reported_length(tvb), opt->phf, &default_hfs);
+}
+
+/* Returns the number of bytes consumed by this option. */
+static int
+bootp_option(tvbuff_t *tvb, packet_info *pinfo, proto_tree *bp_tree, int voff,
+ int eoff, gboolean first_pass, gboolean *at_end, const char **dhcp_type_p,
+ const guint8 **vendor_class_id_p, guint8 *overload_p)
+{
+ struct opt_info *opt;
+ guchar code = tvb_get_guint8(tvb, voff);
+ int optlen;
+ int i, consumed;
+ proto_tree *v_tree;
+ proto_item *vti, *ti_value;
+ tvbuff_t *option_tvb;
+ bootp_option_data_t option_data;
+
/* Options whose length isn't "optlen + 2". */
switch (code) {
@@ -1899,1134 +1891,1061 @@ bootp_option(tvbuff_t *tvb, packet_info *pinfo, proto_tree *bp_tree, proto_item
return consumed;
}
- /* function type may be overridden and that shouldn't be a 'saved' change */
- ftype = opt->ftype;
-
- optoff = voff+2;
-
vti = proto_tree_add_uint_format_value(bp_tree, hf_bootp_option_type,
tvb, voff, consumed, code, "(%d) %s", code, opt->text);
v_tree = proto_item_add_subtree(vti, ett_bootp_option);
proto_tree_add_item(v_tree, hf_bootp_option_length, tvb, voff+1, 1, ENC_BIG_ENDIAN);
- ti = proto_tree_add_item(v_tree, hf_bootp_option_value, tvb, voff+2, optlen, ENC_NA);
- PROTO_ITEM_SET_HIDDEN(ti);
+ ti_value = proto_tree_add_item(v_tree, hf_bootp_option_value, tvb, voff+2, optlen, ENC_NA);
+ PROTO_ITEM_SET_HIDDEN(ti_value);
- /* Special cases */
- switch (code) {
+ /* prepate data for dissector table */
+ option_tvb = tvb_new_subset_length(tvb, voff+2, optlen);
+ option_data.option = code;
+ option_data.overload = overload_p;
+ option_data.dhcp_type = *dhcp_type_p;
+ option_data.vendor_class_id = *vendor_class_id_p;
+ option_data.orig_tvb = tvb;
- case 21: /* Policy Filter */
- for (i = optoff, optleft = optlen;
- optleft > 0; i += 8, optleft -= 8) {
- if (optleft < 8) {
- expert_add_info_format(pinfo, vti, &ei_bootp_bad_length, "Option length isn't a multiple of 8");
- break;
- }
+ if (!dissector_try_uint_new(bootp_option_table, code, option_tvb, pinfo, v_tree, FALSE, &option_data)) {
+ /* hf_bootp_option_value is already in tree, just make it visible */
+ PROTO_ITEM_SET_VISIBLE(ti_value);
+ }
- proto_tree_add_item(v_tree, hf_bootp_option_policy_filter_ip, tvb, i, 4, ENC_BIG_ENDIAN);
- proto_tree_add_item(v_tree, hf_bootp_option_policy_filter_subnet_mask, tvb, i+4, 4, ENC_BIG_ENDIAN);
- }
- break;
+ return consumed;
+}
- case 33: /* Static Route */
- for (i = optoff, optleft = optlen;
- optleft > 0; i += 8, optleft -= 8) {
- if (optleft < 8) {
- expert_add_info_format(pinfo, vti, &ei_bootp_bad_length, "Option length isn't a multiple of 8");
- break;
- }
+static int
+dissect_bootpopt_policy_filter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
+{
+ int offset = 0;
- proto_tree_add_item(v_tree, hf_bootp_option_static_route_ip, tvb, i, 4, ENC_BIG_ENDIAN);
- proto_tree_add_item(v_tree, hf_bootp_option_static_route_router, tvb, i+4, 4, ENC_BIG_ENDIAN);
- }
- break;
+ while (tvb_reported_length_remaining(tvb, offset) >= 8) {
+ proto_tree_add_item(tree, hf_bootp_option_policy_filter_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+ proto_tree_add_item(tree, hf_bootp_option_policy_filter_subnet_mask, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+ }
+
+ if (tvb_reported_length_remaining(tvb, offset) > 0) {
+ expert_add_info_format(pinfo, tree, &ei_bootp_bad_length, "Option length isn't a multiple of 8");
+ }
+
+ return tvb_captured_length(tvb);
+}
+
+static int
+dissect_bootpopt_static_route(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
+{
+ int offset = 0;
- case 43: /* Vendor-Specific Info */
- s_option = tvb_get_guint8(tvb, optoff);
+ while (tvb_reported_length_remaining(tvb, offset) >= 8) {
+ proto_tree_add_item(tree, hf_bootp_option_static_route_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+ proto_tree_add_item(tree, hf_bootp_option_static_route_router, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+ }
+
+ if (tvb_reported_length_remaining(tvb, offset) > 0) {
+ expert_add_info_format(pinfo, tree, &ei_bootp_bad_length, "Option length isn't a multiple of 8");
+ }
- /* PXE protocol 2.1 as described in the Intel specs */
- if (*vendor_class_id_p != NULL &&
- strncmp((const gchar*)*vendor_class_id_p, "PXEClient", strlen("PXEClient")) == 0) {
- proto_item_append_text(vti, " (PXEClient)");
- v_tree = proto_item_add_subtree(vti, ett_bootp_option);
+ return tvb_captured_length(tvb);
+}
- optend = optoff + optlen;
- while (optoff < optend) {
- optoff = dissect_vendor_pxeclient_suboption(pinfo, vti, v_tree,
- tvb, optoff, optend);
+static int
+dissect_bootpopt_vendor_specific_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
+{
+ heur_dtbl_entry_t *hdtbl_entry;
+ proto_tree *vendor_tree;
+
+ if (!dissector_try_heuristic(bootp_vendor_info_subdissector, tvb, pinfo, tree, &hdtbl_entry, data)) {
+ /* Default Vendor-Specific Info.. display in bytes */
+ vendor_tree = proto_item_add_subtree(tree, ett_bootp_option);
+ proto_tree_add_item(vendor_tree, hf_bootp_option43_value, tvb, 0, tvb_reported_length(tvb), ENC_NA);
+ }
+
+ return tvb_captured_length(tvb);
+}
+
+static int
+dissect_bootpopt_option_overload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
+{
+ int offset = 0;
+ int suboffset, suboffset_end;
+ gboolean at_end;
+ bootp_option_data_t *option_data = (bootp_option_data_t*)data;
+ guint32 byte;
+
+ if (tvb_reported_length(tvb) < 1) {
+ expert_add_info_format(pinfo, tree, &ei_bootp_bad_length, "length isn't >= 1");
+ return 1;
+ }
+
+ proto_tree_add_item_ret_uint(tree, hf_bootp_option_option_overload, tvb, offset, 1, ENC_BIG_ENDIAN, &byte);
+
+ /* Just in case we find an option 52 in sname or file */
+ if ((*option_data->overload >= 1) && (*option_data->overload <= 3)) {
+ if (byte & OPT_OVERLOAD_SNAME) {
+ proto_item *oti;
+ proto_tree *overload_tree = proto_tree_add_subtree(tree, option_data->orig_tvb,
+ SERVER_NAME_OFFSET, SERVER_NAME_LEN, ett_bootp_server_hostname, &oti,
+ "Server host name option overload");
+ guint8 ignore_overload = 0;
+ suboffset = SERVER_NAME_OFFSET;
+ suboffset_end = SERVER_NAME_OFFSET + SERVER_NAME_LEN;
+ at_end = FALSE;
+ rfc3396_dns_domain_search_list.index_current_block = 0;
+ rfc3396_sip_server.index_current_block = 0;
+ while (suboffset < suboffset_end && !at_end) {
+ suboffset += bootp_option(option_data->orig_tvb, pinfo, overload_tree, suboffset,
+ suboffset_end, FALSE, &at_end,
+ &option_data->dhcp_type, &option_data->vendor_class_id,
+ &ignore_overload);
}
- } else if (*vendor_class_id_p != NULL &&
- ((strncmp((const gchar*)*vendor_class_id_p, "pktc", strlen("pktc")) == 0) ||
- (strncmp((const gchar*)*vendor_class_id_p, "docsis", strlen("docsis")) == 0) ||
- (strncmp((const gchar*)*vendor_class_id_p, "OpenCable2.0", strlen("OpenCable2.0")) == 0) ||
- (strncmp((const gchar*)*vendor_class_id_p, "CableHome", strlen("CableHome")) == 0))) {
- /* CableLabs standard - see www.cablelabs.com/projects */
- proto_item_append_text(vti, " (CableLabs)");
-
- optend = optoff + optlen;
- while (optoff < optend) {
- optoff = dissect_vendor_cablelabs_suboption(pinfo, vti, v_tree,
- tvb, optoff, optend);
+ if (!at_end)
+ {
+ expert_add_info(pinfo, oti, &hf_bootp_opt_overload_sname_end_missing);
}
- } else if (*vendor_class_id_p != NULL &&
- ((strncmp((const gchar*)*vendor_class_id_p, "ArubaAP", strlen("ArubaAP")) == 0) )) {
- /* Aruba AP */
- proto_item_append_text(vti, " (Aruba AP)");
- proto_tree_add_item(v_tree, hf_bootp_option43_arubaap_controllerip, tvb, optoff, optlen, ENC_ASCII|ENC_NA);
- } else if (*vendor_class_id_p != NULL &&
- ((strncmp((const gchar*)*vendor_class_id_p, "ArubaInstantAP", strlen("ArubaInstantAP")) == 0) )) {
- gint32 nameorglen, ampiplen;
- /* Aruba Instant AP */
- proto_item_append_text(vti, " (Aruba Instant AP)");
- vti = proto_tree_add_item(v_tree, hf_bootp_option43_arubaiap, tvb, optoff, optlen, ENC_ASCII|ENC_NA);
- v_tree = proto_item_add_subtree(vti, ett_bootp_option43_suboption);
- nameorglen = tvb_find_guint8(tvb, optoff, optlen, ',') - optoff;
- proto_tree_add_item(v_tree, hf_bootp_option43_arubaiap_nameorg, tvb, optoff, nameorglen, ENC_ASCII|ENC_NA);
- ampiplen = tvb_find_guint8(tvb, optoff+nameorglen+1, optlen-nameorglen-1, ',') - (optoff+nameorglen+1);
- proto_tree_add_item(v_tree, hf_bootp_option43_arubaiap_ampip, tvb, optoff+nameorglen+1, ampiplen, ENC_ASCII|ENC_NA);
- proto_tree_add_item(v_tree, hf_bootp_option43_arubaiap_password, tvb, optoff+nameorglen+1+ampiplen+1, optlen-(nameorglen+1+ampiplen+1), ENC_ASCII|ENC_NA);
- } else if (*vendor_class_id_p != NULL &&
- ((strncmp((const gchar*)*vendor_class_id_p, PACKETCABLE_BSDP, strlen(PACKETCABLE_BSDP)) == 0) )) {
- /* Apple BSDP */
- proto_item_append_text(vti, " (Boot Server Discovery Protocol (BSDP))");
-
- optend = optoff + optlen;
- while (optoff < optend) {
- optoff = dissect_vendor_bsdp_suboption(pinfo, vti, v_tree,
- tvb, optoff, optend);
+ }
+ if (byte & OPT_OVERLOAD_FILE) {
+ proto_item *oti;
+ proto_tree *overload_tree = proto_tree_add_subtree(tree, option_data->orig_tvb,
+ FILE_NAME_OFFSET, FILE_NAME_LEN, ett_bootp_filename_option, &oti,
+ "Boot file name option overload");
+ guint8 ignore_overload = 0;
+ suboffset = FILE_NAME_OFFSET;
+ suboffset_end = FILE_NAME_OFFSET + FILE_NAME_LEN;
+ at_end = FALSE;
+ rfc3396_dns_domain_search_list.index_current_block = 0;
+ rfc3396_sip_server.index_current_block = 0;
+ while (suboffset < suboffset_end && !at_end) {
+ suboffset += bootp_option(option_data->orig_tvb, pinfo, overload_tree, suboffset,
+ suboffset_end, FALSE, &at_end,
+ &option_data->dhcp_type, &option_data->vendor_class_id,
+ &ignore_overload);
}
- } else if ((s_option==58 || s_option==64 || s_option==65
- || s_option==66 || s_option==67)
- && test_encapsulated_vendor_options(tvb, optoff, optoff+optlen)) {
- /* Note that this is a rather weak (permissive) heuristic, */
- /* but since it comes last, I guess this is OK. */
- /* Add any stronger (less permissive) heuristics before this! */
- /* Alcatel-Lucent DHCP Extensions */
- proto_item_append_text(vti, " (Alcatel-Lucent)");
- optend = optoff + optlen;
- while (optoff < optend) {
- optoff = dissect_vendor_alcatel_suboption(pinfo, vti, v_tree,
- tvb, optoff, optend);
+ if (!at_end)
+ {
+ expert_add_info(pinfo, oti, &hf_bootp_opt_overload_file_end_missing);
}
- } else {
- /* Default Vendor-Specific Info.. display in bytes */
- proto_tree_add_item(v_tree, hf_bootp_option43_value, tvb, optoff, optlen, ENC_NA);
}
- break;
+ /* The final end option is not in overload */
+ *option_data->overload = 0;
+ }
- case 52: /* Option Overload */
- if (optlen < 1) {
- expert_add_info_format(pinfo, vti, &ei_bootp_bad_length, "length isn't >= 1");
- break;
- }
+ return tvb_captured_length(tvb);
+}
- byte = tvb_get_guint8(tvb, optoff);
- proto_tree_add_item(v_tree, *opt->phf, tvb, optoff, 1, ENC_BIG_ENDIAN);
-
- /* Just in case we find an option 52 in sname or file */
- if (voff > VENDOR_INFO_OFFSET && byte >= 1 && byte <= 3) {
- if (byte & OPT_OVERLOAD_FILE) {
- proto_item *oti;
- proto_tree_add_subtree(bp_tree, tvb,
- FILE_NAME_OFFSET, FILE_NAME_LEN, ett_bootp_filename_option, &oti,
- "Boot file name option overload");
- o52voff = FILE_NAME_OFFSET;
- o52eoff = FILE_NAME_OFFSET + FILE_NAME_LEN;
- o52at_end = FALSE;
- rfc3396_dns_domain_search_list.index_current_block = 0;
- rfc3396_sip_server.index_current_block = 0;
- while (o52voff < o52eoff && !o52at_end) {
- o52voff += bootp_option(tvb, pinfo, bp_tree, bp_item, o52voff,
- o52eoff, FALSE, &o52at_end,
- dhcp_type_p, vendor_class_id_p,
- overload_p);
- }
- if (!o52at_end)
- {
- expert_add_info(pinfo, oti, &hf_bootp_opt_overload_file_end_missing);
- }
- }
- if (byte & OPT_OVERLOAD_SNAME) {
- proto_item *oti;
- proto_tree_add_subtree(bp_tree, tvb,
- SERVER_NAME_OFFSET, SERVER_NAME_LEN, ett_bootp_server_hostname, &oti,
- "Server host name option overload");
- o52voff = SERVER_NAME_OFFSET;
- o52eoff = SERVER_NAME_OFFSET + SERVER_NAME_LEN;
- o52at_end = FALSE;
- rfc3396_dns_domain_search_list.index_current_block = 0;
- rfc3396_sip_server.index_current_block = 0;
- while (o52voff < o52eoff && !o52at_end) {
- o52voff += bootp_option(tvb, pinfo, bp_tree, bp_item, o52voff,
- o52eoff, FALSE, &o52at_end,
- dhcp_type_p, vendor_class_id_p,
- overload_p);
- }
- if (!o52at_end)
- {
- expert_add_info(pinfo, oti, &hf_bootp_opt_overload_sname_end_missing);
- }
- }
- /* The final end option is not in overload */
- *overload_p = 0;
- }
- break;
+static int
+dissect_bootpopt_dhcp(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void* data _U_)
+{
+ guint32 type;
- case 53:
- /* Show the message type name on the Message Type option, and in the protocol root */
- proto_item_append_text(vti, " (%s)", val_to_str(tvb_get_guint8(tvb, voff+2),
- opt53_text,
- "Unknown Message Type (0x%02x)"));
- proto_item_append_text(bp_item, " (%s)", val_to_str(tvb_get_guint8(tvb, voff+2),
- opt53_text,
- "Unknown Message Type (0x%02x)"));
- break;
+ proto_tree_add_item_ret_uint(tree, hf_bootp_option_dhcp, tvb, 0, 1, ENC_NA, &type);
+ /* Show the message type name on the Message Type option, and in the protocol root */
+ proto_item_append_text(tree, " (%s)", val_to_str(type, opt53_text, "Unknown Message Type (0x%02x)"));
+ proto_item_append_text(proto_item_get_parent(tree), " (%s)", val_to_str(type, opt53_text, "Unknown Message Type (0x%02x)"));
- case 55: /* Parameter Request List */
- for (i = 0; i < optlen; i++) {
- byte = tvb_get_guint8(tvb, optoff+i);
- proto_tree_add_uint_format_value(v_tree, hf_bootp_option_parameter_request_list_item,
- tvb, optoff+i, 1, byte, "(%d) %s", byte, bootp_get_opt_text(byte));
- }
- break;
+ return tvb_captured_length(tvb);
+}
- case 60: /* Vendor class identifier */
- /*
- * XXX - RFC 2132 says this is a string of octets;
- * should we check for non-printables?
- */
+static int
+dissect_bootpopt_param_request_list(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void* data _U_)
+{
+ int offset = 0;
+ guint8 byte;
+
+ while (tvb_reported_length_remaining(tvb, offset) > 0) {
+ byte = tvb_get_guint8(tvb, offset);
+ proto_tree_add_uint_format_value(tree, hf_bootp_option_parameter_request_list_item,
+ tvb, offset, 1, byte, "(%d) %s", byte, bootp_get_opt_text(byte));
+ offset++;
+ }
- proto_tree_add_item(v_tree, hf_bootp_option_vendor_class_id, tvb, optoff, consumed-2, ENC_ASCII|ENC_NA);
- if ((tvb_memeql(tvb, optoff, (const guint8*)PACKETCABLE_MTA_CAP10,
- (int)strlen(PACKETCABLE_MTA_CAP10)) == 0)
- ||
- (tvb_memeql(tvb, optoff, (const guint8*)PACKETCABLE_MTA_CAP15,
- (int)strlen(PACKETCABLE_MTA_CAP15)) == 0)
- ||
- (tvb_memeql(tvb, optoff, (const guint8*)PACKETCABLE_MTA_CAP20,
- (int)strlen(PACKETCABLE_MTA_CAP20)) == 0))
- {
- dissect_packetcable_mta_cap(v_tree, pinfo, tvb, optoff, optlen);
- } else
- if ((tvb_memeql(tvb, optoff, (const guint8*)PACKETCABLE_CM_CAP11,
- (int)strlen(PACKETCABLE_CM_CAP11)) == 0)
- ||
- (tvb_memeql(tvb, optoff, (const guint8*)PACKETCABLE_CM_CAP20,
- (int)strlen(PACKETCABLE_CM_CAP20)) == 0 ))
- {
- dissect_docsis_cm_cap(v_tree, tvb, optoff, optlen, FALSE);
- } else
- if (tvb_memeql(tvb, optoff, (const guint8*)PACKETCABLE_CM_CAP30,
- (int)strlen(PACKETCABLE_CM_CAP30)) == 0 )
- {
- proto_tree_add_item(v_tree, hf_bootp_option_vendor_class_data, tvb, optoff, optlen, ENC_ASCII|ENC_NA);
- } else
- if (tvb_memeql(tvb, optoff, (const guint8*)PACKETCABLE_BSDPD,
- (int)strlen(PACKETCABLE_BSDPD)) == 0 )
- {
- proto_tree_add_item(v_tree, hf_bootp_option_vendor_class_data, tvb, optoff+(int)strlen(PACKETCABLE_BSDPD), optlen-(int)strlen(PACKETCABLE_BSDPD), ENC_ASCII|ENC_NA);
- }
- break;
+ return tvb_captured_length(tvb);
+}
- case 61: /* Client Identifier */
- if (optlen > 0)
- byte = tvb_get_guint8(tvb, optoff);
- else
- byte = 0;
-
- /* We *MAY* use hwtype/hwaddr. If we have 7 bytes, I'll
- guess that the first is the hwtype, and the last 6
- are the hw addr */
- /* See http://www.iana.org/assignments/arp-parameters */
- /* RFC2132 9.14 Client-identifier has the following to say:
- A hardware type of 0 (zero) should be used when the value
- field contains an identifier other than a hardware address
- (e.g. a fully qualified domain name). */
-
- if (optlen == 7 && byte > 0 && byte < 48) {
- proto_tree_add_item(v_tree,
- hf_bootp_hw_type, tvb, optoff, 1,
- ENC_NA);
-
- if (byte == ARPHRD_ETHER || byte == ARPHRD_IEEE802)
- proto_tree_add_item(v_tree,
- hf_bootp_hw_ether_addr, tvb, optoff+1, 6,
- ENC_NA);
- else
- proto_tree_add_string(v_tree, hf_bootp_client_hardware_address, tvb, optoff+1, 6,
- tvb_arphrdaddr_to_str(tvb, optoff+1, 6, byte));
- } else if (optlen == 17 && byte == 0) {
- /* Identifier is a UUID */
- proto_tree_add_item(v_tree, hf_bootp_client_identifier_uuid, tvb, optoff + 1, 16, bootp_uuid_endian);
-
- /* From RFC 4361 paragraph 6.1 DHCPv4 Client Behavior:
- To send an RFC 3315-style binding identifier in a DHCPv4 'client
- identifier' option, the type of the 'client identifier' option is set
- to 255. */
- } else if (byte == 255) {
- guint16 duidtype;
- guint16 hwtype;
-
- /* The type field is immediately followed by the IAID, which is
- an opaque 32-bit quantity */
- proto_tree_add_string(v_tree, hf_bootp_client_id_iaid, tvb, optoff+1, 4,
- tvb_arphrdaddr_to_str(tvb, optoff+1, 4, byte));
- optoff = optoff + 5;
- duidtype = tvb_get_ntohs(tvb, optoff);
- proto_tree_add_item(v_tree, hf_bootp_client_id_duid_type, tvb, optoff, 2, ENC_BIG_ENDIAN);
- switch (duidtype) {
- case DUID_LLT:
- if (optlen < 8) {
- expert_add_info(pinfo, vti, &ei_bootp_mal_duid);
- break;
- }
- hwtype=tvb_get_ntohs(tvb, optoff + 2);
- proto_tree_add_item(v_tree, hf_bootp_client_identifier_duid_llt_hw_type,
- tvb, optoff + 2, 2, ENC_BIG_ENDIAN);
-
- /* XXX seconds since Jan 1 2000 */
- proto_tree_add_item(v_tree, hf_bootp_client_identifier_time, tvb, optoff + 4, 4, ENC_BIG_ENDIAN);
- if (optlen > 8) {
- proto_tree_add_string(v_tree, hf_bootp_client_identifier_link_layer_address, tvb, optoff + 8,
- optlen - 13, tvb_arphrdaddr_to_str(tvb, optoff+8, optlen-13, hwtype));
- }
- break;
- case DUID_EN:
- if (optlen < 6) {
- expert_add_info(pinfo, vti, &ei_bootp_mal_duid);
- break;
- }
- proto_tree_add_item(v_tree, hf_bootp_client_identifier_enterprise_num, tvb, optoff + 2, 4, ENC_BIG_ENDIAN);
- if (optlen > 6) {
- proto_tree_add_item(v_tree, hf_bootp_client_identifier, tvb, optoff + 6, optlen - 11, ENC_NA);
- }
- break;
- case DUID_LL:
- if (optlen < 4) {
- expert_add_info(pinfo, vti, &ei_bootp_mal_duid);
- break;
- }
- hwtype=tvb_get_ntohs(tvb, optoff + 2);
- proto_tree_add_item(v_tree, hf_bootp_client_identifier_duid_ll_hw_type,
- tvb, optoff + 2, 2, ENC_BIG_ENDIAN);
+static int
+dissect_bootpopt_vendor_class_identifier(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
+{
+ heur_dtbl_entry_t *hdtbl_entry;
- if (optlen > 4) {
- proto_tree_add_string(v_tree, hf_bootp_client_identifier_link_layer_address, tvb, optoff + 4,
- optlen - 9, tvb_arphrdaddr_to_str(tvb, optoff+4, optlen-9, hwtype));
- }
+ /*
+ * XXX - RFC 2132 says this is a string of octets;
+ * should we check for non-printables?
+ */
+ proto_tree_add_item(tree, hf_bootp_option_vendor_class_id, tvb, 0, tvb_reported_length(tvb), ENC_ASCII|ENC_NA);
+ dissector_try_heuristic(bootp_vendor_id_subdissector, tvb, pinfo, tree, &hdtbl_entry, data);
+
+ return tvb_captured_length(tvb);
+}
+
+static int
+dissect_bootpopt_client_identifier(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
+{
+ int offset = 0;
+ int length = tvb_reported_length(tvb);
+ guchar byte;
+
+ if (length > 0)
+ byte = tvb_get_guint8(tvb, offset);
+ else
+ byte = 0;
+
+ /* We *MAY* use hwtype/hwaddr. If we have 7 bytes, I'll
+ guess that the first is the hwtype, and the last 6
+ are the hw addr */
+ /* See http://www.iana.org/assignments/arp-parameters */
+ /* RFC2132 9.14 Client-identifier has the following to say:
+ A hardware type of 0 (zero) should be used when the value
+ field contains an identifier other than a hardware address
+ (e.g. a fully qualified domain name). */
+
+ if (length == 7 && byte > 0 && byte < 48) {
+ proto_tree_add_item(tree, hf_bootp_hw_type, tvb, offset, 1, ENC_NA);
+
+ if (byte == ARPHRD_ETHER || byte == ARPHRD_IEEE802)
+ proto_tree_add_item(tree, hf_bootp_hw_ether_addr, tvb, offset+1, 6, ENC_NA);
+ else
+ proto_tree_add_string(tree, hf_bootp_client_hardware_address, tvb, offset+1, 6,
+ tvb_arphrdaddr_to_str(tvb, offset+1, 6, byte));
+ } else if (length == 17 && byte == 0) {
+ /* Identifier is a UUID */
+ proto_tree_add_item(tree, hf_bootp_client_identifier_uuid, tvb, offset + 1, 16, bootp_uuid_endian);
+
+ /* From RFC 4361 paragraph 6.1 DHCPv4 Client Behavior:
+ To send an RFC 3315-style binding identifier in a DHCPv4 'client
+ identifier' option, the type of the 'client identifier' option is set
+ to 255. */
+ } else if (byte == 255) {
+ guint16 duidtype;
+ guint16 hwtype;
+
+ /* The type field is immediately followed by the IAID, which is
+ an opaque 32-bit quantity */
+ proto_tree_add_string(tree, hf_bootp_client_id_iaid, tvb, offset+1, 4,
+ tvb_arphrdaddr_to_str(tvb, offset+1, 4, byte));
+ offset += 5;
+ duidtype = tvb_get_ntohs(tvb, offset);
+ proto_tree_add_item(tree, hf_bootp_client_id_duid_type, tvb, offset, 2, ENC_BIG_ENDIAN);
+ switch (duidtype) {
+ case DUID_LLT:
+ if (length < 8) {
+ expert_add_info(pinfo, tree, &ei_bootp_mal_duid);
break;
}
- } else if (byte == 0 && optlen > 1) {
- /* identifier other than a hardware address (e.g. a fully qualified domain name) */
- proto_tree_add_item(v_tree, hf_bootp_client_identifier_type, tvb, optoff, 1, ENC_NA);
- proto_tree_add_item(v_tree, hf_bootp_client_identifier_undef, tvb, optoff+1, optlen-1, ENC_ASCII|ENC_NA);
- } else {
- /* otherwise, it's opaque data */
- }
- break;
- case 77: { /* User Class Information RFC 3004 */
- guchar user_class_instance_index;
- proto_item *vtix;
- proto_tree *o77_v_tree;
- if (optlen < 2) {
- expert_add_info_format(pinfo, v_tree, &ei_bootp_bad_length, "length isn't >= 2");
+ hwtype=tvb_get_ntohs(tvb, offset + 2);
+ proto_tree_add_item(tree, hf_bootp_client_identifier_duid_llt_hw_type,
+ tvb, offset + 2, 2, ENC_BIG_ENDIAN);
+
+ /* XXX seconds since Jan 1 2000 */
+ proto_tree_add_item(tree, hf_bootp_client_identifier_time, tvb, offset + 4, 4, ENC_BIG_ENDIAN);
+ if (length > 8) {
+ proto_tree_add_string(tree, hf_bootp_client_identifier_link_layer_address, tvb, offset + 8,
+ length - 13, tvb_arphrdaddr_to_str(tvb, offset+8, length-13, hwtype));
+ }
break;
- }
- optleft = optlen;
- for (user_class_instance_index = 0, i = 0, byte = tvb_get_guint8(tvb, optoff); i < optlen; byte = tvb_get_guint8(tvb, optoff + i), user_class_instance_index++) {
- /* Create subtree for instance of User Class. */
- vtix = proto_tree_add_uint_format_value(v_tree, hf_bootp_option77_user_class,
- tvb, optoff + i, byte + 1, user_class_instance_index, "[%d]", user_class_instance_index);
- o77_v_tree = proto_item_add_subtree(vtix, ett_bootp_option77_instance);
-
- /* Add length for instance of User Class. */
- proto_tree_add_item(o77_v_tree, hf_bootp_option77_user_class_length,
- tvb, optoff + i, 1, ENC_BIG_ENDIAN);
-
- if (byte == 0) {
- expert_add_info_format(pinfo, vtix, &ei_bootp_bad_length, "UC_Len_%u isn't >= 1 (UC_Len_%u = 0)", user_class_instance_index, user_class_instance_index);
+ case DUID_EN:
+ if (length < 6) {
+ expert_add_info(pinfo, tree, &ei_bootp_mal_duid);
break;
}
- optleft -= byte + 1;
- if (optleft < 0) {
- expert_add_info(pinfo, vtix, &ei_bootp_option77_user_class_malformed);
+ proto_tree_add_item(tree, hf_bootp_client_identifier_enterprise_num, tvb, offset + 2, 4, ENC_BIG_ENDIAN);
+ if (length > 6) {
+ proto_tree_add_item(tree, hf_bootp_client_identifier, tvb, offset + 6, length - 11, ENC_NA);
+ }
+ break;
+ case DUID_LL:
+ if (length < 4) {
+ expert_add_info(pinfo, tree, &ei_bootp_mal_duid);
break;
}
+ hwtype=tvb_get_ntohs(tvb, offset + 2);
+ proto_tree_add_item(tree, hf_bootp_client_identifier_duid_ll_hw_type,
+ tvb, offset + 2, 2, ENC_BIG_ENDIAN);
- /* Add data for instance of User Class. */
- proto_tree_add_item(o77_v_tree, hf_bootp_option77_user_class_data,
- tvb, optoff + i + 1, byte, ENC_NA);
-
- /* Slide to next instance of User Class if any. */
- i += byte + 1;
+ if (length > 4) {
+ proto_tree_add_string(tree, hf_bootp_client_identifier_link_layer_address, tvb, offset + 4,
+ length - 9, tvb_arphrdaddr_to_str(tvb, offset+4, length-9, hwtype));
+ }
+ break;
}
- break;
+ } else if (byte == 0 && length > 1) {
+ /* identifier other than a hardware address (e.g. a fully qualified domain name) */
+ proto_tree_add_item(tree, hf_bootp_client_identifier_type, tvb, offset, 1, ENC_NA);
+ proto_tree_add_item(tree, hf_bootp_client_identifier_undef, tvb, offset+1, length-1, ENC_ASCII|ENC_NA);
+ } else {
+ /* otherwise, it's opaque data */
}
- case 97: /* Client Identifier (UUID) */
- if (optlen > 0)
- byte = tvb_get_guint8(tvb, optoff);
- else
- byte = 0;
-
- /* We *MAY* use hwtype/hwaddr. If we have 7 bytes, I'll
- guess that the first is the hwtype, and the last 6
- are the hw addr */
- /* See http://www.iana.org/assignments/arp-parameters */
- /* RFC2132 9.14 Client-identifier has the following to say:
- A hardware type of 0 (zero) should be used when the value
- field contains an identifier other than a hardware address
- (e.g. a fully qualified domain name). */
-
- if (optlen == 7 && byte > 0 && byte < 48) {
- proto_tree_add_item(v_tree,
- hf_bootp_hw_type, tvb, optoff, 1,
- ENC_NA);
- if (byte == ARPHRD_ETHER || byte == ARPHRD_IEEE802)
- proto_tree_add_item(v_tree,
- hf_bootp_hw_ether_addr, tvb, optoff+1, 6,
- ENC_NA);
- else
- proto_tree_add_string(v_tree, hf_bootp_client_hardware_address, tvb, optoff+1, 6,
- tvb_arphrdaddr_to_str(tvb, optoff+1, 6, byte));
- } else if (optlen == 17 && byte == 0) {
- /* Identifier is a UUID */
- proto_tree_add_item(v_tree, hf_bootp_client_identifier_uuid, tvb, optoff + 1, 16, bootp_uuid_endian);
- } else {
- /* otherwise, it's opaque data */
- }
- break;
- case 63: /* NetWare/IP options (RFC 2242) */
+ return tvb_captured_length(tvb);
+}
- optend = optoff + optlen;
- while (optoff < optend)
- optoff = dissect_netware_ip_suboption(pinfo, vti, v_tree, tvb, optoff, optend);
- break;
+static int
+dissect_bootpopt_user_class_information(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
+{
+ guchar user_class_instance_index = 0;
+ int offset = 0;
+ guint32 class_length;
+ proto_item *vtix, *len_item;
+ proto_tree *o77_v_tree;
+ if (tvb_reported_length(tvb) < 2) {
+ expert_add_info_format(pinfo, tree, &ei_bootp_bad_length, "length isn't >= 2");
+ return 1;
+ }
+
+ while (tvb_reported_length_remaining(tvb, offset) > 0) {
+ /* Create subtree for instance of User Class. */
+ vtix = proto_tree_add_uint_format_value(tree, hf_bootp_option77_user_class,
+ tvb, offset, 1, user_class_instance_index, "[%d]", user_class_instance_index);
+ o77_v_tree = proto_item_add_subtree(vtix, ett_bootp_option77_instance);
- case 78: /* SLP Directory Agent Option RFC2610 Added by Greg Morris (gmorris@novell.com)*/
- if (optlen < 1) {
- expert_add_info_format(pinfo, vti, &ei_bootp_bad_length, "length isn't >= 1");
+ /* Add length for instance of User Class. */
+ len_item = proto_tree_add_item_ret_uint(o77_v_tree, hf_bootp_option77_user_class_length,
+ tvb, offset, 1, ENC_BIG_ENDIAN, &class_length);
+ proto_item_set_len(vtix, class_length+1);
+ offset += 1;
+
+ if (class_length == 0) {
+ expert_add_info_format(pinfo, len_item, &ei_bootp_bad_length, "UC_Len_%u isn't >= 1 (UC_Len_%u = 0)", user_class_instance_index, user_class_instance_index);
break;
}
- optleft = optlen;
- byte = tvb_get_guint8(tvb, optoff);
- proto_tree_add_item(v_tree, hf_bootp_option_slp_directory_agent_value, tvb, optoff, 1, ENC_BIG_ENDIAN);
- optoff++;
- optleft--;
- if (byte == 0x80) {
- if (optleft == 0)
- break;
- optoff++;
- optleft--;
- }
- for (i = optoff; optleft > 0; i += 4, optleft -= 4) {
- if (optleft < 4) {
- expert_add_info_format(pinfo, vti, &ei_bootp_bad_length, "Option length isn't a multiple of 4");
- break;
- }
+ /* Add data for instance of User Class. */
+ proto_tree_add_item(o77_v_tree, hf_bootp_option77_user_class_data, tvb, offset, class_length, ENC_NA);
+ offset += class_length;
+ user_class_instance_index++;
+ }
- proto_tree_add_item(v_tree, hf_bootp_option_slp_directory_agent_slpda_address, tvb, i, 4, ENC_BIG_ENDIAN);
- }
- break;
+ return tvb_captured_length(tvb);
+}
+
+static int
+dissect_bootpopt_slp_directory_agent(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
+{
+ int offset = 0;
+ guint32 byte;
- case 79: /* SLP Service Scope Option RFC2610 Added by Greg Morris (gmorris@novell.com)*/
- proto_tree_add_item(v_tree, hf_bootp_option_slp_service_scope_value, tvb, optoff, 1, ENC_BIG_ENDIAN);
+ if (tvb_reported_length(tvb) < 1) {
+ expert_add_info_format(pinfo, tree, &ei_bootp_bad_length, "length isn't >= 1");
+ return 1;
+ }
- optoff++;
- optleft = optlen - 1;
- proto_tree_add_item(v_tree, hf_bootp_option_slp_service_scope_string, tvb, optoff, optleft, ENC_ASCII|ENC_NA);
- break;
+ proto_tree_add_item_ret_uint(tree, hf_bootp_option_slp_directory_agent_value, tvb, offset, 1, ENC_BIG_ENDIAN, &byte);
+ offset++;
- case 81: /* Client Fully Qualified Domain Name */
- {
- static const int * fqdn_hf_flags[] = {
- &hf_bootp_fqdn_mbz,
- &hf_bootp_fqdn_n,
- &hf_bootp_fqdn_e,
- &hf_bootp_fqdn_o,
- &hf_bootp_fqdn_s,
- NULL
- };
-
- if (optlen < 3) {
- expert_add_info_format(pinfo, vti, &ei_bootp_bad_length, "length isn't >= 3");
- break;
- }
+ if (byte == 0x80) {
+ if (tvb_reported_length_remaining(tvb, offset) == 0)
+ return offset;
- fqdn_flags = tvb_get_guint8(tvb, optoff);
- proto_tree_add_bitmask(v_tree, tvb, optoff, hf_bootp_fqdn_flags,
- ett_bootp_fqdn_flags, fqdn_hf_flags, ENC_BIG_ENDIAN);
-
- /* XXX: use code from packet-dns for return code decoding */
- proto_tree_add_item(v_tree, hf_bootp_fqdn_rcode1, tvb, optoff+1, 1, ENC_BIG_ENDIAN);
- /* XXX: use code from packet-dns for return code decoding */
- proto_tree_add_item(v_tree, hf_bootp_fqdn_rcode2, tvb, optoff+2, 1, ENC_BIG_ENDIAN);
- if (optlen > 3) {
- if (fqdn_flags & F_FQDN_E) {
- get_dns_name(tvb, optoff+3, optlen-3, optoff+3, &dns_name, &dns_name_len);
- proto_tree_add_string(v_tree, hf_bootp_fqdn_name,
- tvb, optoff+3, optlen-3, format_text(wmem_packet_scope(), dns_name, dns_name_len));
- } else {
- proto_tree_add_item(v_tree, hf_bootp_fqdn_asciiname,
- tvb, optoff+3, optlen-3, ENC_ASCII|ENC_NA);
- }
- }
- }
- break;
+ offset++;
+ }
- case 82: /* Relay Agent Information Option */
- optend = optoff + optlen;
- while (optoff < optend)
- optoff = bootp_dhcp_decode_agent_info(pinfo, vti, v_tree, tvb, optoff, optend);
- break;
+ while (tvb_reported_length_remaining(tvb, offset) >= 4) {
+ proto_tree_add_item(tree, hf_bootp_option_slp_directory_agent_slpda_address, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+ }
- case 83: /* iSNS Option (RFC 4174) */
- optoff = dissect_isns(pinfo, vti, v_tree, tvb, optoff, optlen);
- break;
+ if (tvb_reported_length_remaining(tvb, offset) > 0) {
+ expert_add_info_format(pinfo, tree, &ei_bootp_bad_length, "Option length isn't a multiple of 4");
+ }
- case 85: /* Novell Servers (RFC 2241) */
- /* Option 85 can be sent as a string */
- /* Added by Greg Morris (gmorris[AT]novell.com) */
- if (novell_string) {
- proto_tree_add_item(v_tree, hf_bootp_option_novell_dss_string, tvb, optoff, optlen, ENC_ASCII|ENC_NA);
- } else{
- /* IP addresses */
- for (i = optoff, optleft = optlen; optleft > 0;
- i += 4, optleft -= 4) {
- if (optleft < 4) {
- expert_add_info_format(pinfo, vti, &ei_bootp_bad_length, "Option length isn't a multiple of 4");
- break;
- }
+ return tvb_captured_length(tvb);
+}
- proto_tree_add_item(v_tree, hf_bootp_option_novell_dss_ip, tvb, i, 4, ENC_BIG_ENDIAN);
- }
- }
- break;
+static int
+dissect_bootpopt_slp_service_scope(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void* data _U_)
+{
+ int offset = 0;
- case 94: { /* Client network interface identifier */
- guint8 id_type;
+ proto_tree_add_item(tree, hf_bootp_option_slp_service_scope_value, tvb, offset, 1, ENC_BIG_ENDIAN);
- id_type = tvb_get_guint8(tvb, optoff);
+ offset++;
+ proto_tree_add_item(tree, hf_bootp_option_slp_service_scope_string, tvb, offset, tvb_reported_length_remaining(tvb, offset), ENC_ASCII|ENC_NA);
- if (id_type == 0x01) {
- proto_tree_add_item(v_tree, hf_bootp_option_client_network_id_major_ver,
- tvb, optoff + 1, 1, ENC_LITTLE_ENDIAN);
- proto_tree_add_item(v_tree, hf_bootp_option_client_network_id_minor_ver,
- tvb, optoff + 2, 1, ENC_LITTLE_ENDIAN);
- }
+ return tvb_captured_length(tvb);
+}
- break;
+static int
+dissect_bootpopt_client_full_domain_name(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void* data _U_)
+{
+ static const int * fqdn_hf_flags[] = {
+ &hf_bootp_fqdn_mbz,
+ &hf_bootp_fqdn_n,
+ &hf_bootp_fqdn_e,
+ &hf_bootp_fqdn_o,
+ &hf_bootp_fqdn_s,
+ NULL
+ };
+ guint8 fqdn_flags;
+ int offset = 0, length = tvb_reported_length(tvb);
+ const guchar *dns_name;
+ guint dns_name_len;
+
+ if (length < 3) {
+ expert_add_info_format(pinfo, tree, &ei_bootp_bad_length, "length isn't >= 3");
+ return 1;
}
- case 90: /* DHCP Authentication */
- if (optlen < 11) {
- expert_add_info_format(pinfo, vti, &ei_bootp_bad_length, "length isn't >= 11");
- break;
+ fqdn_flags = tvb_get_guint8(tvb, offset);
+ proto_tree_add_bitmask(tree, tvb, offset, hf_bootp_fqdn_flags,
+ ett_bootp_fqdn_flags, fqdn_hf_flags, ENC_BIG_ENDIAN);
+
+ /* XXX: use code from packet-dns for return code decoding */
+ proto_tree_add_item(tree, hf_bootp_fqdn_rcode1, tvb, offset+1, 1, ENC_BIG_ENDIAN);
+ /* XXX: use code from packet-dns for return code decoding */
+ proto_tree_add_item(tree, hf_bootp_fqdn_rcode2, tvb, offset+2, 1, ENC_BIG_ENDIAN);
+
+ if (length > 3) {
+ if (fqdn_flags & F_FQDN_E) {
+ get_dns_name(tvb, offset+3, length-3, offset+3, &dns_name, &dns_name_len);
+ proto_tree_add_string(tree, hf_bootp_fqdn_name,
+ tvb, offset+3, length-3, format_text(wmem_packet_scope(), dns_name, dns_name_len));
+ } else {
+ proto_tree_add_item(tree, hf_bootp_fqdn_asciiname, tvb, offset+3, length-3, ENC_ASCII|ENC_NA);
}
- optleft = optlen;
- protocol = tvb_get_guint8(tvb, optoff);
+ }
- proto_tree_add_item(v_tree, hf_bootp_option_dhcp_authentication_protocol, tvb, optoff, 1, ENC_BIG_ENDIAN);
- optoff++;
- optleft--;
+ return tvb_captured_length(tvb);
+}
- algorithm = tvb_get_guint8(tvb, optoff);
- switch (protocol) {
+static int
+dissect_bootpopt_novell_servers(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void* data _U_)
+{
+ int offset = 0;
- case AUTHEN_PROTO_DELAYED_AUTHEN:
- proto_tree_add_item(v_tree, hf_bootp_option_dhcp_authentication_alg_delay, tvb, optoff, 1, ENC_BIG_ENDIAN);
- break;
+ /* Option 85 can be sent as a string */
+ /* Added by Greg Morris (gmorris[AT]novell.com) */
+ if (novell_string) {
+ proto_tree_add_item(tree, hf_bootp_option_novell_dss_string, tvb, offset, tvb_reported_length(tvb), ENC_ASCII|ENC_NA);
+ } else {
+ /* IP addresses */
+ while (tvb_reported_length_remaining(tvb, offset) >= 4) {
- default:
- proto_tree_add_item(v_tree, hf_bootp_option_dhcp_authentication_algorithm, tvb, optoff, 1, ENC_BIG_ENDIAN);
- break;
+ proto_tree_add_item(tree, hf_bootp_option_novell_dss_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
}
- optoff++;
- optleft--;
- rdm = tvb_get_guint8(tvb, optoff);
- proto_tree_add_item(v_tree, hf_bootp_option_dhcp_authentication_rdm, tvb, optoff, 1, ENC_BIG_ENDIAN);
- optoff++;
- optleft--;
+ if (tvb_reported_length_remaining(tvb, offset) > 0) {
+ expert_add_info_format(pinfo, tree, &ei_bootp_bad_length, "Option length isn't a multiple of 4");
+ }
+ }
- switch (rdm) {
+ return tvb_captured_length(tvb);
+}
- case AUTHEN_RDM_MONOTONIC_COUNTER:
- proto_tree_add_item(v_tree, hf_bootp_option_dhcp_authentication_rdm_replay_detection, tvb, optoff, 8, ENC_BIG_ENDIAN);
- break;
+static int
+dissect_bootpopt_dhcp_authentication(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
+{
+ int offset = 0;
+ bootp_option_data_t *option_data = (bootp_option_data_t*)data;
+ guint32 protocol, rdm;
+ guint8 algorithm;
+
+ if (tvb_reported_length(tvb) < 11) {
+ expert_add_info_format(pinfo, tree, &ei_bootp_bad_length, "length isn't >= 11");
+ return 1;
+ }
- default:
- proto_tree_add_item(v_tree, hf_bootp_option_dhcp_authentication_rdm_rdv, tvb, optoff, 8, ENC_ASCII|ENC_NA);
- break;
- }
- optoff += 8;
- optleft -= 8;
+ proto_tree_add_item_ret_uint(tree, hf_bootp_option_dhcp_authentication_protocol, tvb, offset, 1, ENC_BIG_ENDIAN, &protocol);
+ offset++;
- switch (protocol) {
+ algorithm = tvb_get_guint8(tvb, offset);
+ switch (protocol) {
- case AUTHEN_PROTO_DELAYED_AUTHEN:
- switch (algorithm) {
+ case AUTHEN_PROTO_DELAYED_AUTHEN:
+ proto_tree_add_item(tree, hf_bootp_option_dhcp_authentication_alg_delay, tvb, offset, 1, ENC_BIG_ENDIAN);
+ break;
- case AUTHEN_DELAYED_ALGO_HMAC_MD5:
- if (*dhcp_type_p && !strcmp(*dhcp_type_p, OPT53_DISCOVER)) {
- /* Discover has no Secret ID nor HMAC MD5 Hash */
- break;
- } else {
- if (optlen < 31) {
- expert_add_info_format(pinfo, vti, &ei_bootp_bad_length, "length isn't >= 31");
- break;
- }
+ default:
+ proto_tree_add_item(tree, hf_bootp_option_dhcp_authentication_algorithm, tvb, offset, 1, ENC_BIG_ENDIAN);
+ break;
+ }
+ offset++;
- proto_tree_add_item(v_tree, hf_bootp_option_dhcp_authentication_secret_id, tvb, optoff, 4, ENC_BIG_ENDIAN);
- optoff += 4;
- /*optleft -= 4;*/
- proto_tree_add_item(v_tree, hf_bootp_option_dhcp_authentication_hmac_md5_hash, tvb, optoff, 16, ENC_ASCII|ENC_NA);
- break;
- }
+ proto_tree_add_item_ret_uint(tree, hf_bootp_option_dhcp_authentication_rdm, tvb, offset, 1, ENC_BIG_ENDIAN, &rdm);
+ offset++;
- default:
- if (optleft == 0)
+ switch (rdm) {
+
+ case AUTHEN_RDM_MONOTONIC_COUNTER:
+ proto_tree_add_item(tree, hf_bootp_option_dhcp_authentication_rdm_replay_detection, tvb, offset, 8, ENC_BIG_ENDIAN);
+ break;
+
+ default:
+ proto_tree_add_item(tree, hf_bootp_option_dhcp_authentication_rdm_rdv, tvb, offset, 8, ENC_ASCII|ENC_NA);
+ break;
+ }
+ offset += 8;
+
+ switch (protocol) {
+
+ case AUTHEN_PROTO_DELAYED_AUTHEN:
+ switch (algorithm) {
+
+ case AUTHEN_DELAYED_ALGO_HMAC_MD5:
+ if (option_data->dhcp_type && !strcmp(option_data->dhcp_type, OPT53_DISCOVER)) {
+ /* Discover has no Secret ID nor HMAC MD5 Hash */
+ break;
+ } else {
+ if (tvb_reported_length_remaining(tvb, offset) < 31) {
+ expert_add_info_format(pinfo, tree, &ei_bootp_bad_length, "length isn't >= 31");
break;
+ }
- proto_tree_add_item(v_tree, hf_bootp_option_dhcp_authentication_information, tvb, optoff, optleft, ENC_ASCII|ENC_NA);
+ proto_tree_add_item(tree, hf_bootp_option_dhcp_authentication_secret_id, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+ proto_tree_add_item(tree, hf_bootp_option_dhcp_authentication_hmac_md5_hash, tvb, offset, 16, ENC_ASCII|ENC_NA);
break;
}
- break;
default:
- if (optleft == 0)
+ if (tvb_reported_length_remaining(tvb, offset) == 0)
break;
- proto_tree_add_item(v_tree, hf_bootp_option_dhcp_authentication_information, tvb, optoff, optleft, ENC_ASCII|ENC_NA);
+ proto_tree_add_item(tree, hf_bootp_option_dhcp_authentication_information, tvb, offset, tvb_reported_length_remaining(tvb, offset), ENC_ASCII|ENC_NA);
break;
}
break;
- case 99: /* civic location (RFC 4776) */
+ default:
+ if (tvb_reported_length_remaining(tvb, offset) == 0)
+ break;
- optleft = optlen;
- if (optleft >= 3)
- {
- proto_tree_add_item(v_tree, hf_bootp_option_civic_location_what, tvb, optoff, 1, ENC_BIG_ENDIAN);
- proto_tree_add_item(v_tree, hf_bootp_option_civic_location_country, tvb, optoff+1, 2, ENC_ASCII|ENC_NA);
- optleft = optleft - 3;
- optoff = optoff + 3;
+ proto_tree_add_item(tree, hf_bootp_option_dhcp_authentication_information, tvb, offset, tvb_reported_length_remaining(tvb, offset), ENC_ASCII|ENC_NA);
+ break;
+ }
- while (optleft >= 2)
- {
- int calength = tvb_get_guint8(tvb, optoff+1);
- proto_tree_add_item(v_tree, hf_bootp_option_civic_location_ca_type, tvb, optoff, 1, ENC_BIG_ENDIAN);
- proto_tree_add_item(v_tree, hf_bootp_option_civic_location_ca_length, tvb, optoff+1, 1, ENC_BIG_ENDIAN);
+ return tvb_captured_length(tvb);
+}
- optoff += 2;
- optleft -= 2;
+static int
+dissect_bootpopt_client_network_interface_id(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void* data _U_)
+{
+ int offset = 0;
+ guint8 id_type;
+
+ id_type = tvb_get_guint8(tvb, offset);
+ offset++;
+
+ if (id_type == 0x01) {
+ proto_tree_add_item(tree, hf_bootp_option_client_network_id_major_ver,
+ tvb, offset, 1, ENC_LITTLE_ENDIAN);
+ offset++;
+ proto_tree_add_item(tree, hf_bootp_option_client_network_id_minor_ver,
+ tvb, offset, 1, ENC_LITTLE_ENDIAN);
+ }
- if (calength == 0)
- continue;
+ return tvb_captured_length(tvb);
+}
- if (optleft >= calength)
- {
- proto_tree_add_item(v_tree, hf_bootp_option_civic_location_ca_value, tvb, optoff, calength, ENC_ASCII|ENC_NA);
+static int
+dissect_bootpopt_client_identifier_uuid(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void* data _U_)
+{
+ int offset = 0, length = tvb_reported_length(tvb);
+ guint8 byte;
- optoff = optoff + calength;
- optleft = optleft - calength;
- }
- else
- {
- optleft = 0;
- expert_add_info(pinfo, vti, &ei_bootp_option_civic_location_bad_cattype);
- }
- }
- }
- break;
+ if (length > 0)
+ byte = tvb_get_guint8(tvb, offset);
+ else
+ byte = 0;
+
+ /* We *MAY* use hwtype/hwaddr. If we have 7 bytes, I'll
+ guess that the first is the hwtype, and the last 6
+ are the hw addr */
+ /* See http://www.iana.org/assignments/arp-parameters */
+ /* RFC2132 9.14 Client-identifier has the following to say:
+ A hardware type of 0 (zero) should be used when the value
+ field contains an identifier other than a hardware address
+ (e.g. a fully qualified domain name). */
+
+ if (length == 7 && byte > 0 && byte < 48) {
+ proto_tree_add_item(tree, hf_bootp_hw_type, tvb, offset, 1, ENC_NA);
+ if (byte == ARPHRD_ETHER || byte == ARPHRD_IEEE802)
+ proto_tree_add_item(tree, hf_bootp_hw_ether_addr, tvb, offset+1, 6, ENC_NA);
+ else
+ proto_tree_add_string(tree, hf_bootp_client_hardware_address, tvb, offset+1, 6,
+ tvb_arphrdaddr_to_str(tvb, offset+1, 6, byte));
+ } else if (length == 17 && byte == 0) {
+ /* Identifier is a UUID */
+ proto_tree_add_item(tree, hf_bootp_client_identifier_uuid, tvb, offset + 1, 16, bootp_uuid_endian);
+ } else {
+ /* otherwise, it's opaque data */
+ }
- case 117: /* The Name Service Search Option for DHCP (RFC 2937) */
- if (optlen < 2) {
- expert_add_info_format(pinfo, vti, &ei_bootp_bad_length, "length isn't >= 2");
- } else if (optlen & 1) {
- expert_add_info_format(pinfo, vti, &ei_bootp_bad_length, "length (%u) isn't even number", optlen);
- } else {
- guint16 ns;
- for (i = 0, ns = tvb_get_ntohs(tvb, optoff); i < optlen; i += 2, ns = tvb_get_ntohs(tvb, optoff + i)) {
- switch (ns) {
- case RFC2937_LOCAL_NAMING_INFORMATION:
- proto_tree_add_string(v_tree, hf_bootp_option_dhcp_name_service_search_option, tvb, optoff + i, 2, "Local naming information (e.g., an /etc/hosts file on a UNIX machine) (0)");
- break;
- case RFC2937_DOMAIN_NAME_SERVER_OPTION:
- proto_tree_add_string(v_tree, hf_bootp_option_dhcp_name_service_search_option, tvb, optoff + i, 2, "Domain Name Server Option (6)");
- break;
- case RFC2937_NETWORK_INFORMATION_SERVERS_OPTION:
- proto_tree_add_string(v_tree, hf_bootp_option_dhcp_name_service_search_option, tvb, optoff + i, 2, "Network Information Servers Option (41)");
- break;
- case RFC2937_NETBIOS_OVER_TCP_IP_NAME_SERVER_OPTION:
- proto_tree_add_string(v_tree, hf_bootp_option_dhcp_name_service_search_option, tvb, optoff + i, 2, "NetBIOS over TCP/IP Name Server Option (44)");
- break;
- case RFC2937_NETWORK_INFORMATION_SERVICE_PLUS_SERVERS_OPTION:
- proto_tree_add_string(v_tree, hf_bootp_option_dhcp_name_service_search_option, tvb, optoff + i, 2, "Network Information Service+ Servers Option (65)");
- break;
- default:
- expert_add_info_format(pinfo, vti, &ei_bootp_option_dhcp_name_service_invalid,
- "Invalid Name Service (%u). RFC 2937 defines only 0, 6, 41, 44, and 65 as possible values.", ns);
- break;
- }
- }
- }
- break;
+ return tvb_captured_length(tvb);
+}
- case 119: { /* Dynamic Host Configuration Protocol (DHCP) Domain Search Option (RFC 3397) */
- /* Encoding Long Options in the Dynamic Host Configuration Protocol (DHCPv4) (RFC 3396) */
- /* Domain Names - Implementation And Specification (RFC 1035) */
- char tmpChar[BOOTP_MAX_NO_CHAR];
- rfc3396_dns_domain_search_list.index_current_block++;
- if (rfc3396_dns_domain_search_list.total_number_of_block > 1) {
- g_snprintf(tmpChar, BOOTP_MAX_NO_CHAR, "%u/%u", rfc3396_dns_domain_search_list.index_current_block, rfc3396_dns_domain_search_list.total_number_of_block);
- proto_tree_add_string(v_tree, hf_bootp_option_dhcp_dns_domain_search_list_rfc_3396_detected, tvb, optoff, optlen, tmpChar);
- if (rfc3396_dns_domain_search_list.index_current_block != rfc3396_dns_domain_search_list.total_number_of_block) {
- g_snprintf(tmpChar, BOOTP_MAX_NO_CHAR, "%u/%u", rfc3396_dns_domain_search_list.total_number_of_block, rfc3396_dns_domain_search_list.total_number_of_block);
- proto_tree_add_string(v_tree, hf_bootp_option_dhcp_dns_domain_search_list_refer_last_option, tvb, optoff, optlen, tmpChar);
- }
- }
+static int
+dissect_bootpopt_civic_location(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
+{
+ int offset = 0;
- if (rfc3396_dns_domain_search_list.tvb_composite == NULL && optlen) {
- /* We use composite tvb for managing RFC 3396 */
- rfc3396_dns_domain_search_list.tvb_composite = tvb_new_composite();
- }
+ if (tvb_reported_length(tvb) >= 3)
+ {
+ proto_tree_add_item(tree, hf_bootp_option_civic_location_what, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset++;
+ proto_tree_add_item(tree, hf_bootp_option_civic_location_country, tvb, offset, 2, ENC_ASCII|ENC_NA);
+ offset += 2;
- /* Concatenate the block before being interpreted for managing RFC 3396 */
- if (optlen)
- tvb_composite_append(rfc3396_dns_domain_search_list.tvb_composite, tvb_new_subset_length(tvb, optoff, optlen));
+ while (tvb_reported_length_remaining(tvb, offset) >= 2)
+ {
+ guint32 calength;
+ proto_tree_add_item(tree, hf_bootp_option_civic_location_ca_type, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset++;
+ proto_tree_add_item_ret_uint(tree, hf_bootp_option_civic_location_ca_length, tvb, offset, 1, ENC_BIG_ENDIAN, &calength);
+ offset++;
- if (rfc3396_dns_domain_search_list.index_current_block == rfc3396_dns_domain_search_list.total_number_of_block
- && rfc3396_dns_domain_search_list.tvb_composite) {
- /* Here, we are into the last (or unique) option 119. */
- /* We will display the information about fqdn */
- unsigned int consumedx = 0;
- unsigned int offset = 0;
- tvb_composite_finalize(rfc3396_dns_domain_search_list.tvb_composite);
+ if (calength == 0)
+ continue;
- while (offset < tvb_reported_length(rfc3396_dns_domain_search_list.tvb_composite)) {
- /* use the get_dns_name method that manages all techniques of RFC 1035 (compression pointer and so on) */
- consumedx = get_dns_name(rfc3396_dns_domain_search_list.tvb_composite, offset,
- tvb_reported_length(rfc3396_dns_domain_search_list.tvb_composite), 0, &dns_name, &dns_name_len);
- if (rfc3396_dns_domain_search_list.total_number_of_block == 1) {
- /* RFC 3396 is not used, so we can easily link the fqdn with v_tree. */
- proto_tree_add_string(v_tree, hf_bootp_option_dhcp_dns_domain_search_list_fqdn, tvb, optoff + offset, consumedx, dns_name);
- } else {
- /* RFC 3396 is used, so the option is split into several option 119. We don't link fqdn with v_tree. */
- proto_tree_add_string(v_tree, hf_bootp_option_dhcp_dns_domain_search_list_fqdn, tvb, 0, 0, dns_name);
- }
- offset += consumedx;
+ if (tvb_reported_length_remaining(tvb, offset) >= (int)calength)
+ {
+ proto_tree_add_item(tree, hf_bootp_option_civic_location_ca_value, tvb, offset, calength, ENC_ASCII|ENC_NA);
+ offset += calength;
}
- rfc3396_dns_domain_search_list.tvb_composite = NULL;
- }
- break;
- }
- case 120: { /* SIP Servers (RFC 3361) */
- /* Encoding Long Options in the Dynamic Host Configuration Protocol (DHCPv4) (RFC 3396) */
- /* Domain Names - Implementation And Specification (RFC 1035) */
- char tmpChar[BOOTP_MAX_NO_CHAR];
- rfc3396_sip_server.index_current_block++;
- if (rfc3396_sip_server.total_number_of_block > 1) {
- g_snprintf(tmpChar, BOOTP_MAX_NO_CHAR, "%u/%u", rfc3396_sip_server.index_current_block, rfc3396_sip_server.total_number_of_block);
- proto_tree_add_string(v_tree, hf_bootp_option_sip_server_rfc_3396_detected, tvb, optoff, optlen, tmpChar);
- if (rfc3396_sip_server.index_current_block != rfc3396_sip_server.total_number_of_block) {
- g_snprintf(tmpChar, BOOTP_MAX_NO_CHAR, "%u/%u", rfc3396_sip_server.total_number_of_block, rfc3396_sip_server.total_number_of_block);
- proto_tree_add_string(v_tree, hf_bootp_option_sip_server_refer_last_option, tvb, optoff, optlen, tmpChar);
+ else
+ {
+ expert_add_info(pinfo, tree, &ei_bootp_option_civic_location_bad_cattype);
+ break;
}
}
+ }
+
+ return tvb_captured_length(tvb);
+}
+
+static int
+dissect_bootpopt_name_server_search(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
+{
+ int offset = 0, length = tvb_reported_length(tvb);
+ guint16 ns;
+
+ if (length < 2) {
+ expert_add_info_format(pinfo, tree, &ei_bootp_bad_length, "length isn't >= 2");
+ return 1;
+ } else if (length & 1) {
+ expert_add_info_format(pinfo, tree, &ei_bootp_bad_length, "length (%u) isn't even number", length);
+ return 1;
+ }
- if (rfc3396_sip_server.tvb_composite == NULL && optlen) {
- /* We use composite tvb for managing RFC 3396 */
- rfc3396_sip_server.tvb_composite = tvb_new_composite();
+ while (tvb_reported_length_remaining(tvb, offset) > 0) {
+ ns = tvb_get_ntohs(tvb, offset);
+ /* XXX - Make this a value_string */
+ switch (ns) {
+ case RFC2937_LOCAL_NAMING_INFORMATION:
+ proto_tree_add_string(tree, hf_bootp_option_dhcp_name_service_search_option, tvb, offset, 2, "Local naming information (e.g., an /etc/hosts file on a UNIX machine) (0)");
+ break;
+ case RFC2937_DOMAIN_NAME_SERVER_OPTION:
+ proto_tree_add_string(tree, hf_bootp_option_dhcp_name_service_search_option, tvb, offset, 2, "Domain Name Server Option (6)");
+ break;
+ case RFC2937_NETWORK_INFORMATION_SERVERS_OPTION:
+ proto_tree_add_string(tree, hf_bootp_option_dhcp_name_service_search_option, tvb, offset, 2, "Network Information Servers Option (41)");
+ break;
+ case RFC2937_NETBIOS_OVER_TCP_IP_NAME_SERVER_OPTION:
+ proto_tree_add_string(tree, hf_bootp_option_dhcp_name_service_search_option, tvb, offset, 2, "NetBIOS over TCP/IP Name Server Option (44)");
+ break;
+ case RFC2937_NETWORK_INFORMATION_SERVICE_PLUS_SERVERS_OPTION:
+ proto_tree_add_string(tree, hf_bootp_option_dhcp_name_service_search_option, tvb, offset, 2, "Network Information Service+ Servers Option (65)");
+ break;
+ default:
+ expert_add_info_format(pinfo, tree, &ei_bootp_option_dhcp_name_service_invalid,
+ "Invalid Name Service (%u). RFC 2937 defines only 0, 6, 41, 44, and 65 as possible values.", ns);
+ break;
}
+ offset += 2;
+ }
- /* Concatenate the block before being interpreted for managing RFC 3396 */
- if (optlen)
- tvb_composite_append(rfc3396_sip_server.tvb_composite, tvb_new_subset_length(tvb, optoff, optlen));
+ return tvb_captured_length(tvb);
+}
- if (rfc3396_sip_server.index_current_block == rfc3396_sip_server.total_number_of_block
- && rfc3396_sip_server.tvb_composite) {
- /* Here, we are into the last (or unique) option 120. */
- /* We will display the information about SIP server */
- guint8 enc;
- unsigned int offset = 1; /* ignore enc */
- tvb_composite_finalize(rfc3396_sip_server.tvb_composite);
+static int
+dissect_bootpopt_dhcp_domain_search(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void* data _U_)
+{
+ int length = tvb_reported_length(tvb);
+ const guchar *dns_name;
+ guint dns_name_len;
- enc = tvb_get_guint8(rfc3396_sip_server.tvb_composite, 0);
- if (rfc3396_sip_server.total_number_of_block == 1) {
+ /* Encoding Long Options in the Dynamic Host Configuration Protocol (DHCPv4) (RFC 3396) */
+ /* Domain Names - Implementation And Specification (RFC 1035) */
+ rfc3396_dns_domain_search_list.index_current_block++;
+ if (rfc3396_dns_domain_search_list.total_number_of_block > 1) {
+ proto_tree_add_string(tree, hf_bootp_option_dhcp_dns_domain_search_list_rfc_3396_detected, tvb, 0, length,
+ wmem_strdup_printf(wmem_packet_scope(), "%u/%u", rfc3396_dns_domain_search_list.index_current_block, rfc3396_dns_domain_search_list.total_number_of_block));
+ if (rfc3396_dns_domain_search_list.index_current_block != rfc3396_dns_domain_search_list.total_number_of_block) {
+ proto_tree_add_string(tree, hf_bootp_option_dhcp_dns_domain_search_list_refer_last_option, tvb, 0, length,
+ wmem_strdup_printf(wmem_packet_scope(), "%u/%u", rfc3396_dns_domain_search_list.total_number_of_block, rfc3396_dns_domain_search_list.total_number_of_block));
+ }
+ }
+
+ if (rfc3396_dns_domain_search_list.tvb_composite == NULL && length) {
+ /* We use composite tvb for managing RFC 3396 */
+ rfc3396_dns_domain_search_list.tvb_composite = tvb_new_composite();
+ }
+
+ /* Concatenate the block before being interpreted for managing RFC 3396 */
+ if (length)
+ tvb_composite_append(rfc3396_dns_domain_search_list.tvb_composite, tvb_new_subset_length(tvb, 0, length));
+
+ if (rfc3396_dns_domain_search_list.index_current_block == rfc3396_dns_domain_search_list.total_number_of_block
+ && rfc3396_dns_domain_search_list.tvb_composite) {
+ /* Here, we are into the last (or unique) option 119. */
+ /* We will display the information about fqdn */
+ unsigned int consumedx = 0;
+ unsigned int composite_offset = 0;
+ tvb_composite_finalize(rfc3396_dns_domain_search_list.tvb_composite);
+
+ while (composite_offset < tvb_reported_length(rfc3396_dns_domain_search_list.tvb_composite)) {
+ /* use the get_dns_name method that manages all techniques of RFC 1035 (compression pointer and so on) */
+ consumedx = get_dns_name(rfc3396_dns_domain_search_list.tvb_composite, composite_offset,
+ tvb_reported_length(rfc3396_dns_domain_search_list.tvb_composite), 0, &dns_name, &dns_name_len);
+ if (rfc3396_dns_domain_search_list.total_number_of_block == 1) {
/* RFC 3396 is not used, so we can easily link the fqdn with v_tree. */
- proto_tree_add_uint(v_tree, hf_bootp_option_sip_server_enc, tvb, optoff, 1, enc);
+ proto_tree_add_string(tree, hf_bootp_option_dhcp_dns_domain_search_list_fqdn, tvb, composite_offset, consumedx, dns_name);
} else {
- /* RFC 3396 is used, so the option is split into several option 120. We don't link fqdn with v_tree. */
- proto_tree_add_uint(v_tree, hf_bootp_option_sip_server_enc, tvb, 0, 0, enc);
+ /* RFC 3396 is used, so the option is split into several option 119. We don't link fqdn with v_tree. */
+ proto_tree_add_string(tree, hf_bootp_option_dhcp_dns_domain_search_list_fqdn, tvb, 0, 0, dns_name);
}
+ composite_offset += consumedx;
+ }
+ rfc3396_dns_domain_search_list.tvb_composite = NULL;
+ }
- switch (enc) {
- case RFC_3361_ENC_FQDN: {
- unsigned int consumedx = 0;
- if (tvb_reported_length(rfc3396_sip_server.tvb_composite) < 3) {
- expert_add_info_format(pinfo, vti, &ei_bootp_bad_length, "length isn't >= 3 (len = %u)", tvb_reported_length(rfc3396_sip_server.tvb_composite));
- break;
- }
+ return tvb_captured_length(tvb);
+}
- while (offset < tvb_reported_length(rfc3396_sip_server.tvb_composite)) {
- /* use the get_dns_name method that manages all techniques of RFC 1035 (compression pointer and so on) */
- consumedx = get_dns_name(rfc3396_sip_server.tvb_composite, offset, tvb_reported_length(rfc3396_sip_server.tvb_composite),
- 1 /* ignore enc */, &dns_name, &dns_name_len);
-
- if (rfc3396_sip_server.total_number_of_block == 1) {
- /* RFC 3396 is not used, so we can easily link the fqdn with v_tree. */
- proto_tree_add_string(v_tree, hf_bootp_option_sip_server_name, tvb, optoff + offset, consumedx, dns_name);
- } else {
- /* RFC 3396 is used, so the option is split into several option 120. We don't link fqdn with v_tree. */
- proto_tree_add_string(v_tree, hf_bootp_option_sip_server_name, tvb, 0, 0, format_text(wmem_packet_scope(), dns_name, dns_name_len));
- }
- offset += consumedx;
- }
- rfc3396_sip_server.tvb_composite = NULL;
+static int
+dissect_bootpopt_sip_servers(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
+{
+ int length = tvb_reported_length(tvb);
+ const guchar *dns_name;
+ guint dns_name_len;
+
+ /* Encoding Long Options in the Dynamic Host Configuration Protocol (DHCPv4) (RFC 3396) */
+ /* Domain Names - Implementation And Specification (RFC 1035) */
+ rfc3396_sip_server.index_current_block++;
+ if (rfc3396_sip_server.total_number_of_block > 1) {
+ proto_tree_add_string(tree, hf_bootp_option_sip_server_rfc_3396_detected, tvb, 0, length,
+ wmem_strdup_printf(wmem_packet_scope(), "%u/%u", rfc3396_sip_server.index_current_block, rfc3396_sip_server.total_number_of_block));
+ if (rfc3396_sip_server.index_current_block != rfc3396_sip_server.total_number_of_block) {
+ proto_tree_add_string(tree, hf_bootp_option_sip_server_refer_last_option, tvb, 0, length,
+ wmem_strdup_printf(wmem_packet_scope(), "%u/%u", rfc3396_sip_server.total_number_of_block, rfc3396_sip_server.total_number_of_block));
+ }
+ }
+
+ if (rfc3396_sip_server.tvb_composite == NULL && length) {
+ /* We use composite tvb for managing RFC 3396 */
+ rfc3396_sip_server.tvb_composite = tvb_new_composite();
+ }
+
+ /* Concatenate the block before being interpreted for managing RFC 3396 */
+ if (length)
+ tvb_composite_append(rfc3396_sip_server.tvb_composite, tvb_new_subset_length(tvb, 0, length));
+
+ if (rfc3396_sip_server.index_current_block == rfc3396_sip_server.total_number_of_block
+ && rfc3396_sip_server.tvb_composite) {
+ /* Here, we are into the last (or unique) option 120. */
+ /* We will display the information about SIP server */
+ guint8 enc;
+ unsigned int composite_offset = 1; /* ignore enc */
+ tvb_composite_finalize(rfc3396_sip_server.tvb_composite);
+
+ enc = tvb_get_guint8(rfc3396_sip_server.tvb_composite, 0);
+ if (rfc3396_sip_server.total_number_of_block == 1) {
+ /* RFC 3396 is not used, so we can easily link the fqdn with tree. */
+ proto_tree_add_uint(tree, hf_bootp_option_sip_server_enc, tvb, 0, 1, enc);
+ } else {
+ /* RFC 3396 is used, so the option is split into several option 120. We don't link fqdn with tree. */
+ proto_tree_add_uint(tree, hf_bootp_option_sip_server_enc, tvb, 0, 0, enc);
+ }
+
+ switch (enc) {
+ case RFC_3361_ENC_FQDN: {
+ unsigned int consumedx = 0;
+ if (tvb_reported_length(rfc3396_sip_server.tvb_composite) < 3) {
+ expert_add_info_format(pinfo, tree, &ei_bootp_bad_length, "length isn't >= 3 (len = %u)", tvb_reported_length(rfc3396_sip_server.tvb_composite));
break;
}
- case RFC_3361_ENC_IPADDR:
- if (tvb_reported_length(rfc3396_sip_server.tvb_composite) < 5) {
- expert_add_info_format(pinfo, vti, &ei_bootp_bad_length, "length isn't >= 5 (len = %u)", tvb_reported_length(rfc3396_sip_server.tvb_composite));
- break;
- }
- /* x % 2^n == x & (2^n - 1) note : (assuming x is a positive integer) */
- if ((tvb_reported_length(rfc3396_sip_server.tvb_composite) - 1) & 3) {
- if (rfc3396_sip_server.total_number_of_block == 1)
- expert_add_info_format(pinfo, vti, &ei_bootp_bad_length, "length isn't a multiple of 4 plus 1 (len = %u).", tvb_reported_length(rfc3396_sip_server.tvb_composite));
- else
- expert_add_info_format(pinfo, vti, &ei_bootp_bad_length,
- "length isn't a multiple of 4 plus 1 (len = %u). For your information with RFC 3396, the length is the length sum of all options 120 into this BOOTP packet.",
- tvb_reported_length(rfc3396_sip_server.tvb_composite));
- break;
- }
- while (offset < tvb_reported_length(rfc3396_sip_server.tvb_composite)) {
- if (rfc3396_sip_server.total_number_of_block == 1) {
- /* RFC 3396 is not used, so we can easily link the fqdn with v_tree. */
- proto_tree_add_item(v_tree, hf_bootp_option_sip_server_address, rfc3396_sip_server.tvb_composite, offset, 4, ENC_BIG_ENDIAN);
- } else {
- /* RFC 3396 is used, so the option is split into several option 120. We don't link fqdn with v_tree. */
- /* Since we don't use the "numbered argument" as described by README.developer, we have to repeat the arguments :( */
- g_snprintf(tmpChar, BOOTP_MAX_NO_CHAR, "%u.%u.%u.%u (%u.%u.%u.%u)",
- tvb_get_guint8(rfc3396_sip_server.tvb_composite, offset),
- tvb_get_guint8(rfc3396_sip_server.tvb_composite, offset + 1),
- tvb_get_guint8(rfc3396_sip_server.tvb_composite, offset + 2),
- tvb_get_guint8(rfc3396_sip_server.tvb_composite, offset + 3),
- tvb_get_guint8(rfc3396_sip_server.tvb_composite, offset),
- tvb_get_guint8(rfc3396_sip_server.tvb_composite, offset + 1),
- tvb_get_guint8(rfc3396_sip_server.tvb_composite, offset + 2),
- tvb_get_guint8(rfc3396_sip_server.tvb_composite, offset + 3)
- );
- proto_tree_add_string(v_tree, hf_bootp_option_sip_server_address_stringz, tvb, 0, 0, tmpChar);
- }
- offset += 4;
+
+ while (composite_offset < tvb_reported_length(rfc3396_sip_server.tvb_composite)) {
+ /* use the get_dns_name method that manages all techniques of RFC 1035 (compression pointer and so on) */
+ consumedx = get_dns_name(rfc3396_sip_server.tvb_composite, composite_offset, tvb_reported_length(rfc3396_sip_server.tvb_composite),
+ 1 /* ignore enc */, &dns_name, &dns_name_len);
+
+ if (rfc3396_sip_server.total_number_of_block == 1) {
+ /* RFC 3396 is not used, so we can easily link the fqdn with v_tree. */
+ proto_tree_add_string(tree, hf_bootp_option_sip_server_name, tvb, composite_offset, consumedx, dns_name);
+ } else {
+ /* RFC 3396 is used, so the option is split into several option 120. We don't link fqdn with v_tree. */
+ proto_tree_add_string(tree, hf_bootp_option_sip_server_name, tvb, 0, 0, format_text(wmem_packet_scope(), dns_name, dns_name_len));
}
- break;
- default:
- expert_add_info_format(pinfo, vti, &ei_bootp_option_sip_server_address_encoding, "RFC 3361 defines only 0 and 1 for Encoding byte (Encoding = %u).", enc);
- break;
+ composite_offset += consumedx;
}
- }
- break;
- }
- case 121: /* Classless Static Route */
- case 249: { /* Classless Static Route (Microsoft) */
- int mask_width, significant_octets;
- optend = optoff + optlen;
- /* minimum length is 5 bytes */
- if (optlen < 5) {
- expert_add_info_format(pinfo, vti, &ei_bootp_bad_length, "length isn't >= 5");
+ rfc3396_sip_server.tvb_composite = NULL;
break;
}
- while (optoff < optend) {
- mask_width = tvb_get_guint8(tvb, optoff);
- /* mask_width <= 32 */
- if (mask_width > 32) {
- expert_add_info_format(pinfo, vti, &ei_bootp_option_classless_static_route, "Mask width (%d) > 32", mask_width);
+ case RFC_3361_ENC_IPADDR:
+ if (tvb_reported_length(rfc3396_sip_server.tvb_composite) < 5) {
+ expert_add_info_format(pinfo, tree, &ei_bootp_bad_length, "length isn't >= 5 (len = %u)", tvb_reported_length(rfc3396_sip_server.tvb_composite));
break;
}
- significant_octets = (mask_width + 7) / 8;
- vti = proto_tree_add_bytes_format(v_tree, hf_bootp_option_classless_static_route, tvb, optoff,
- 1 + significant_octets + 4, NULL,
- " ");
- optoff++;
- /* significant octets + router(4) */
- if (optend < optoff + significant_octets + 4) {
- expert_add_info_format(pinfo, vti, &ei_bootp_bad_length, "Remaining length (%d) < %d bytes", optend - optoff, significant_octets + 4);
+ /* x % 2^n == x & (2^n - 1) note : (assuming x is a positive integer) */
+ if ((tvb_reported_length(rfc3396_sip_server.tvb_composite) - 1) & 3) {
+ if (rfc3396_sip_server.total_number_of_block == 1)
+ expert_add_info_format(pinfo, tree, &ei_bootp_bad_length, "length isn't a multiple of 4 plus 1 (len = %u).", tvb_reported_length(rfc3396_sip_server.tvb_composite));
+ else
+ expert_add_info_format(pinfo, tree, &ei_bootp_bad_length,
+ "length isn't a multiple of 4 plus 1 (len = %u). For your information with RFC 3396, the length is the length sum of all options 120 into this BOOTP packet.",
+ tvb_reported_length(rfc3396_sip_server.tvb_composite));
break;
}
- if(mask_width == 0)
- proto_item_append_text(vti, "default");
- else {
- for(i = 0 ; i < significant_octets ; i++) {
- if (i > 0)
- proto_item_append_text(vti, ".");
- byte = tvb_get_guint8(tvb, optoff++);
- proto_item_append_text(vti, "%d", byte);
+ while (composite_offset < tvb_reported_length(rfc3396_sip_server.tvb_composite)) {
+ if (rfc3396_sip_server.total_number_of_block == 1) {
+ /* RFC 3396 is not used, so we can easily link the fqdn with v_tree. */
+ proto_tree_add_item(tree, hf_bootp_option_sip_server_address, rfc3396_sip_server.tvb_composite, composite_offset, 4, ENC_BIG_ENDIAN);
+ } else {
+ /* RFC 3396 is used, so the option is split into several option 120. We don't link fqdn with v_tree. */
+ /* Since we don't use the "numbered argument" as described by README.developer, we have to repeat the arguments :( */
+ proto_tree_add_string(tree, hf_bootp_option_sip_server_address_stringz, tvb, 0, 0,
+ wmem_strdup_printf(wmem_packet_scope(), "%u.%u.%u.%u (%u.%u.%u.%u)",
+ tvb_get_guint8(rfc3396_sip_server.tvb_composite, composite_offset),
+ tvb_get_guint8(rfc3396_sip_server.tvb_composite, composite_offset + 1),
+ tvb_get_guint8(rfc3396_sip_server.tvb_composite, composite_offset + 2),
+ tvb_get_guint8(rfc3396_sip_server.tvb_composite, composite_offset + 3),
+ tvb_get_guint8(rfc3396_sip_server.tvb_composite, composite_offset),
+ tvb_get_guint8(rfc3396_sip_server.tvb_composite, composite_offset + 1),
+ tvb_get_guint8(rfc3396_sip_server.tvb_composite, composite_offset + 2),
+ tvb_get_guint8(rfc3396_sip_server.tvb_composite, composite_offset + 3)));
}
- for(i = significant_octets ; i < 4 ; i++)
- proto_item_append_text(vti, ".0");
- proto_item_append_text(vti, "/%d", mask_width);
+ composite_offset += 4;
}
- proto_item_append_text(vti, "-%s", tvb_ip_to_str(tvb, optoff));
- optoff += 4;
+ break;
+ default:
+ expert_add_info_format(pinfo, tree, &ei_bootp_option_sip_server_address_encoding, "RFC 3361 defines only 0 and 1 for Encoding byte (Encoding = %u).", enc);
+ break;
}
- break;
}
- case 123: /* coordinate based location RFC 3825 or CableLabs DSS_ID */
- if (optlen == 16) {
- int c;
- unsigned char lci[16];
- struct rfc3825_location_fixpoint_t location_fp;
- struct rfc3825_location_decimal_t location;
-
- for (c=0; c < 16;c++)
- lci[c] = (unsigned char) tvb_get_guint8(tvb, optoff + c);
-
- /* convert lci encoding into fixpoint location */
- rfc3825_lci_to_fixpoint(lci, &location_fp);
-
- /* convert location from decimal to fixpoint */
- i = rfc3825_fixpoint_to_decimal(&location_fp, &location);
-
- if (i != RFC3825_NOERROR) {
- ti = proto_tree_add_uint(v_tree, hf_bootp_option_rfc3825_error, tvb, optoff, 1, i);
- proto_item_set_len(ti, optlen);
- } else {
- proto_tree_add_double_format_value(v_tree, hf_bootp_option_rfc3825_latitude, tvb, optoff, 5, location.latitude, "%15.10f", location.latitude);
- proto_tree_add_double_format_value(v_tree, hf_bootp_option_rfc3825_longitude, tvb, optoff+5, 5, location.longitude, "%15.10f", location.longitude);
- proto_tree_add_double_format_value(v_tree, hf_bootp_option_rfc3825_latitude_res, tvb, optoff, 1, location.latitude_res, "%15.10f", location.latitude_res);
- proto_tree_add_double_format_value(v_tree, hf_bootp_option_rfc3825_longitude_res, tvb, optoff+5, 1, location.longitude_res, "%15.10f", location.longitude_res);
- proto_tree_add_double_format_value(v_tree, hf_bootp_option_rfc3825_altitude, tvb, optoff+12, 4, location.altitude, "%15.10f", location.altitude);
- proto_tree_add_double_format_value(v_tree, hf_bootp_option_rfc3825_altitide_res, tvb, optoff+10, 2, location.altitude_res, "%15.10f", location.altitude_res);
- proto_tree_add_uint(v_tree, hf_bootp_option_rfc3825_altitude_type, tvb, optoff+10, 1, location.altitude_type);
- proto_tree_add_uint(v_tree, hf_bootp_option_rfc3825_map_datum, tvb, optoff+15, 1, location.datum_type);
- }
- } else if (optlen < 69) { /* CableLabs DSS_ID */
-
- proto_tree_add_item(v_tree, hf_bootp_option_cl_dss_id_option, tvb, optoff, 1, ENC_BIG_ENDIAN);
- proto_tree_add_item(v_tree, hf_bootp_option_cl_dss_id_len, tvb, optoff+1, 1, ENC_BIG_ENDIAN);
- s_len = tvb_get_guint8(tvb, optoff+1);
- proto_tree_add_item(v_tree, hf_bootp_option_cl_dss_id, tvb, optoff+2, s_len, ENC_ASCII|ENC_NA);
-
- if (optlen > s_len+2) { /* Second DSS_ID*/
+ return tvb_captured_length(tvb);
+}
- proto_tree_add_item(v_tree, hf_bootp_option_cl_dss_id_option, tvb, optoff+2+s_len, 1, ENC_BIG_ENDIAN);
- proto_tree_add_item(v_tree, hf_bootp_option_cl_dss_id_len, tvb, optoff+1+2+s_len, 1, ENC_BIG_ENDIAN);
- s_len = tvb_get_guint8(tvb, optoff+1+2+s_len);
- proto_tree_add_item(v_tree, hf_bootp_option_cl_dss_id, tvb, optoff+2+2+s_len, s_len, ENC_ASCII|ENC_NA);
+static int
+dissect_bootpopt_classless_static_route(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
+{
+ int offset = 0;
+ int i, mask_width, significant_octets;
+ proto_item* route_item;
+
+ /* minimum length is 5 bytes */
+ if (tvb_reported_length(tvb) < 5) {
+ expert_add_info_format(pinfo, tree, &ei_bootp_bad_length, "length isn't >= 5");
+ return 1;
+ }
+ while (tvb_reported_length_remaining(tvb, offset) > 0) {
+ mask_width = tvb_get_guint8(tvb, offset);
+ /* mask_width <= 32 */
+ if (mask_width > 32) {
+ expert_add_info_format(pinfo, tree, &ei_bootp_option_classless_static_route, "Mask width (%d) > 32", mask_width);
+ break;
+ }
+ significant_octets = (mask_width + 7) / 8;
+ route_item = proto_tree_add_bytes_format(tree, hf_bootp_option_classless_static_route, tvb, offset,
+ 1 + significant_octets + 4, NULL, " ");
+ offset++;
+ /* significant octets + router(4) */
+ if (tvb_reported_length_remaining(tvb, offset + significant_octets + 4) < 0) {
+ expert_add_info_format(pinfo, route_item, &ei_bootp_bad_length, "Remaining length (%d) < %d bytes", tvb_reported_length_remaining(tvb, offset), significant_octets + 4);
+ break;
+ }
+ if(mask_width == 0)
+ proto_item_append_text(route_item, "default");
+ else {
+ for(i = 0 ; i < significant_octets ; i++) {
+ if (i > 0)
+ proto_item_append_text(route_item, ".");
+ proto_item_append_text(route_item, "%d", tvb_get_guint8(tvb, offset++));
}
- } else {
- expert_add_info_format(pinfo, vti, &ei_bootp_bad_length, "Invalid length of DHCP option!");
+ for(i = significant_octets ; i < 4 ; i++)
+ proto_item_append_text(route_item, ".0");
+ proto_item_append_text(route_item, "/%d", mask_width);
}
- break;
+ proto_item_append_text(route_item, "-%s", tvb_ip_to_str(tvb, offset));
+ offset += 4;
+ }
- case 124: { /* V-I Vendor Class (RFC 3925) */
- int data_len;
+ return tvb_captured_length(tvb);
+}
- if (optlen == 1) {
- /* CableLab specific */
- proto_tree_add_item(v_tree, hf_bootp_option_vi_class_cl_address_mode, tvb, optoff, optlen, ENC_BIG_ENDIAN);
- break;
- }
+static int
+dissect_bootpopt_coordinate_based_location(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
+{
+ int offset = 0, length = tvb_reported_length(tvb);
+ proto_item* ti;
- optleft = optlen;
+ if (length == 16) {
+ int ret;
+ unsigned char lci[16];
+ struct rfc3825_location_fixpoint_t location_fp;
+ struct rfc3825_location_decimal_t location;
- while (optleft > 0) {
+ tvb_memcpy(tvb, lci, offset, 16);
- if (optleft < 5) {
- expert_add_info_format(pinfo, vti, &ei_bootp_bad_length, "length < 5");
- break;
- }
+ /* convert lci encoding into fixpoint location */
+ rfc3825_lci_to_fixpoint(lci, &location_fp);
- proto_tree_add_item(v_tree, hf_bootp_option_vi_class_enterprise, tvb, optoff, 4, ENC_BIG_ENDIAN);
- proto_tree_add_item(v_tree, hf_bootp_option_vi_class_data_length, tvb, optoff, 1, ENC_BIG_ENDIAN);
- data_len = tvb_get_guint8(tvb, optoff + 4);
+ /* convert location from decimal to fixpoint */
+ ret = rfc3825_fixpoint_to_decimal(&location_fp, &location);
- optoff += 5;
- optleft -= 5;
+ if (ret != RFC3825_NOERROR) {
+ ti = proto_tree_add_uint(tree, hf_bootp_option_rfc3825_error, tvb, offset, 1, ret);
+ proto_item_set_len(ti, length);
+ } else {
+ proto_tree_add_double_format_value(tree, hf_bootp_option_rfc3825_latitude, tvb, offset, 5, location.latitude, "%15.10f", location.latitude);
+ proto_tree_add_double_format_value(tree, hf_bootp_option_rfc3825_longitude, tvb, offset+5, 5, location.longitude, "%15.10f", location.longitude);
+ proto_tree_add_double_format_value(tree, hf_bootp_option_rfc3825_latitude_res, tvb, offset, 1, location.latitude_res, "%15.10f", location.latitude_res);
+ proto_tree_add_double_format_value(tree, hf_bootp_option_rfc3825_longitude_res, tvb, offset+5, 1, location.longitude_res, "%15.10f", location.longitude_res);
+ proto_tree_add_double_format_value(tree, hf_bootp_option_rfc3825_altitude, tvb, offset+12, 4, location.altitude, "%15.10f", location.altitude);
+ proto_tree_add_double_format_value(tree, hf_bootp_option_rfc3825_altitide_res, tvb, offset+10, 2, location.altitude_res, "%15.10f", location.altitude_res);
+ proto_tree_add_uint(tree, hf_bootp_option_rfc3825_altitude_type, tvb, offset+10, 1, location.altitude_type);
+ proto_tree_add_uint(tree, hf_bootp_option_rfc3825_map_datum, tvb, offset+15, 1, location.datum_type);
+ }
+ } else if (length < 69) { /* CableLabs DSS_ID */
+ int s_len;
- proto_tree_add_item(v_tree, hf_bootp_option_vi_class_data, tvb, optoff, data_len, ENC_ASCII|ENC_NA);
+ proto_tree_add_item(tree, hf_bootp_option_cl_dss_id_option, tvb, offset, 1, ENC_BIG_ENDIAN);
+ proto_tree_add_item(tree, hf_bootp_option_cl_dss_id_len, tvb, offset+1, 1, ENC_BIG_ENDIAN);
+ s_len = tvb_get_guint8(tvb, offset+1);
+ proto_tree_add_item(tree, hf_bootp_option_cl_dss_id, tvb, offset+2, s_len, ENC_ASCII|ENC_NA);
- /* look for next enterprise number */
- optoff += data_len;
- optleft -= data_len;
+ if (length > s_len+2) { /* Second DSS_ID*/
+
+ proto_tree_add_item(tree, hf_bootp_option_cl_dss_id_option, tvb, offset+2+s_len, 1, ENC_BIG_ENDIAN);
+ proto_tree_add_item(tree, hf_bootp_option_cl_dss_id_len, tvb, offset+1+2+s_len, 1, ENC_BIG_ENDIAN);
+ s_len = tvb_get_guint8(tvb, offset+1+2+s_len);
+ proto_tree_add_item(tree, hf_bootp_option_cl_dss_id, tvb, offset+2+2+s_len, s_len, ENC_ASCII|ENC_NA);
}
- break;
+ } else {
+ expert_add_info_format(pinfo, tree, &ei_bootp_bad_length, "Invalid length of DHCP option!");
}
- case 125: { /* V-I Vendor-specific Information (RFC 3925) */
- int enterprise = 0;
- int s_end = 0;
- int option_data_len = 0;
- proto_tree *e_tree = 0;
-
- optend = optoff + optlen;
- optleft = optlen;
+ return tvb_captured_length(tvb);
+}
- while (optleft > 0) {
+static int
+dissect_bootpopt_vi_vendor_class(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
+{
+ int offset = 0;
+ int data_len;
- if (optleft < 5) {
- expert_add_info_format(pinfo, vti, &ei_bootp_bad_length, "length < 5");
- break;
- }
+ if (tvb_reported_length(tvb) == 1) {
+ /* CableLab specific */
+ proto_tree_add_item(tree, hf_bootp_option_vi_class_cl_address_mode, tvb, 0, 1, ENC_BIG_ENDIAN);
+ return 1;
+ }
- enterprise = tvb_get_ntohl(tvb, optoff);
- vti = proto_tree_add_item(v_tree, hf_bootp_option125_enterprise, tvb, optoff, 4, ENC_BIG_ENDIAN);
- e_tree = proto_item_add_subtree(vti, ett_bootp_option);
+ while (tvb_reported_length_remaining(tvb, offset) >= 5) {
- optoff += 4;
- optleft -= 4;
+ proto_tree_add_item(tree, hf_bootp_option_vi_class_enterprise, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+ proto_tree_add_item(tree, hf_bootp_option_vi_class_data_length, tvb, offset, 1, ENC_BIG_ENDIAN);
+ data_len = tvb_get_guint8(tvb, offset);
+ offset += 1;
- proto_tree_add_item_ret_uint(e_tree, hf_bootp_option125_length, tvb, optoff, 1, ENC_NA, &option_data_len);
+ proto_tree_add_item(tree, hf_bootp_option_vi_class_data, tvb, offset, data_len, ENC_ASCII|ENC_NA);
- optoff += 1;
- optleft -= 1;
+ /* look for next enterprise number */
+ offset += data_len;
+ }
- s_end = optoff + option_data_len;
- if ( s_end > optend ) {
- expert_add_info_format(pinfo, vti, &ei_bootp_option125_enterprise_malformed, "no room left in option for enterprise %u data", enterprise);
- break;
- }
+ if (tvb_reported_length_remaining(tvb, offset) > 0) {
+ expert_add_info_format(pinfo, tree, &ei_bootp_bad_length, "length < 5");
+ }
- while (optoff < s_end) {
- switch (enterprise) {
+ return tvb_captured_length(tvb);
+}
- case 3561: /* ADSL Forum */
- optoff = dissect_vendor_tr111_suboption(pinfo, vti, e_tree, tvb, optoff, s_end);
- break;
+static int
+dissect_bootpopt_dhcp_captive_portal(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void* data _U_)
+{
+ proto_item *ti_cp;
+ ti_cp = proto_tree_add_item(tree, hf_bootp_option_captive_portal, tvb, 0, tvb_reported_length(tvb), ENC_ASCII|ENC_NA);
+ PROTO_ITEM_SET_URL(ti_cp);
- case 4491: /* CableLab */
- optoff = dissect_vendor_cl_suboption(pinfo, vti, e_tree, tvb, optoff, s_end);
- break;
+ return tvb_captured_length(tvb);
+}
- default:
- optoff = dissect_vendor_generic_suboption(pinfo, vti, e_tree, tvb, optoff, s_end);
- break;
- }
- }
- optleft -= option_data_len;
- }
- break;
- }
+static int
+dissect_bootpopt_6RD_option(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void* data _U_)
+{
+ int offset = 0;
- case 160: { /* DHCP Captive-Portal */
- proto_item *ti_cp;
- ti_cp = proto_tree_add_item(v_tree, hf_bootp_option_captive_portal, tvb, optoff, optlen, ENC_ASCII|ENC_NA);
- PROTO_ITEM_SET_URL(ti_cp);
- break;
+ if (tvb_reported_length(tvb) < 22) {
+ expert_add_info(pinfo, tree, &ei_bootp_option_6RD_malformed);
+ return 1;
}
-
- case 212: { /* 6RD option (RFC 5969) */
- if (optlen < 22) {
- expert_add_info(pinfo, vti, &ei_bootp_option_6RD_malformed);
- break;
+ proto_tree_add_item(tree, hf_bootp_option_6RD_ipv4_mask_len, tvb, offset, 1, ENC_BIG_ENDIAN);
+ proto_tree_add_item(tree, hf_bootp_option_6RD_prefix_len, tvb, offset+1, 1, ENC_BIG_ENDIAN);
+ proto_tree_add_item(tree, hf_bootp_option_6RD_prefix, tvb, offset+2, 16, ENC_NA);
+ proto_tree_add_item(tree, hf_bootp_option_6RD_border_relay_ip, tvb, offset+18, 4, ENC_BIG_ENDIAN);
+
+ /* More Border Relay IPv4 addresses included */
+ if (tvb_reported_length(tvb) > 22) {
+ offset += 22;
+ while (tvb_reported_length_remaining(tvb, offset) >= 4) {
+ proto_tree_add_item(tree, hf_bootp_option_6RD_border_relay_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
}
-
- proto_tree_add_item(v_tree, hf_bootp_option_6RD_ipv4_mask_len, tvb, optoff, 1, ENC_BIG_ENDIAN);
- proto_tree_add_item(v_tree, hf_bootp_option_6RD_prefix_len, tvb, optoff+1, 1, ENC_BIG_ENDIAN);
- proto_tree_add_item(v_tree, hf_bootp_option_6RD_prefix, tvb, optoff+2, 16, ENC_NA);
- proto_tree_add_item(v_tree, hf_bootp_option_6RD_border_relay_ip, tvb, optoff+18, 4, ENC_BIG_ENDIAN);
-
- /* More Border Relay IPv4 addresses included */
- if (optlen > 22) {
- optoff += 22;
- for (i = optoff, optleft = optlen - 22; optleft > 0; i += 4, optleft -= 4) {
- if (optleft < 4) {
- expert_add_info_format(pinfo, vti, &ei_bootp_bad_length, "Option length isn't a multiple of 4");
- break;
- }
-
- proto_tree_add_item(v_tree, hf_bootp_option_6RD_border_relay_ip, tvb, i, 4, ENC_BIG_ENDIAN);
- }
+ if (tvb_reported_length_remaining(tvb, offset) > 0) {
+ expert_add_info_format(pinfo, tree, &ei_bootp_bad_length, "Option length isn't a multiple of 4");
}
- break;
}
- case 242: { /* Avaya IP Telephone */
- proto_tree *o242avaya_v_tree;
- proto_item *avaya_ti;
- const guint8 *avaya_option = NULL;
- gchar *field = NULL;
- wmem_strbuf_t *avaya_param_buf = NULL;
+ return tvb_captured_length(tvb);
+}
- /* minimum length is 5 bytes */
- if (optlen < 5) {
- expert_add_info_format(pinfo, vti, &ei_bootp_bad_length, "Avaya IP Telephone option length isn't >= 5");
- optoff += optlen;
- break;
- }
- avaya_ti = proto_tree_add_item_ret_string(v_tree, hf_bootp_option242_avaya, tvb, optoff, optlen, ENC_ASCII|ENC_NA, wmem_packet_scope(), &avaya_option);
- o242avaya_v_tree = proto_item_add_subtree(avaya_ti, ett_bootp_option242_suboption);
- avaya_param_buf = wmem_strbuf_new(wmem_packet_scope(), "");
- for ( field = strtok((char*)avaya_option, ","); field; field = strtok(NULL, ",") ) {
- if (!strchr(field, '=')) {
- if (wmem_strbuf_get_len(avaya_param_buf) == 0) {
- expert_add_info_format(pinfo, vti, &hf_bootp_subopt_unknown_type, "ERROR, Unknown parameter %s", field);
- optoff += (int)strlen(field);
- break;
- }
- wmem_strbuf_append_printf(avaya_param_buf,",%s", field);
- }
- else {
- if (wmem_strbuf_get_len(avaya_param_buf) > 0) {
- dissect_vendor_avaya_param(o242avaya_v_tree, pinfo, vti, tvb, optoff, avaya_param_buf);
- optoff += (int)wmem_strbuf_get_len(avaya_param_buf) + 1;
- wmem_strbuf_truncate(avaya_param_buf, 0);
- }
- wmem_strbuf_append(avaya_param_buf, field);
+static int
+dissect_bootpopt_avaya_ip_telephone(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void* data _U_)
+{
+ int offset = 0;
+ proto_tree *o242avaya_v_tree;
+ proto_item *avaya_ti;
+ const guint8 *avaya_option = NULL;
+ gchar *field = NULL;
+ wmem_strbuf_t *avaya_param_buf = NULL;
+
+ /* minimum length is 5 bytes */
+ if (tvb_reported_length(tvb) < 5) {
+ expert_add_info_format(pinfo, tree, &ei_bootp_bad_length, "Avaya IP Telephone option length isn't >= 5");
+ return 1;
+ }
+ avaya_ti = proto_tree_add_item_ret_string(tree, hf_bootp_option242_avaya, tvb, offset, tvb_reported_length(tvb), ENC_ASCII|ENC_NA, wmem_packet_scope(), &avaya_option);
+ o242avaya_v_tree = proto_item_add_subtree(avaya_ti, ett_bootp_option242_suboption);
+ avaya_param_buf = wmem_strbuf_new(wmem_packet_scope(), "");
+ for ( field = strtok((char*)avaya_option, ","); field; field = strtok(NULL, ",") ) {
+ if (!strchr(field, '=')) {
+ if (wmem_strbuf_get_len(avaya_param_buf) == 0) {
+ expert_add_info_format(pinfo, avaya_ti, &hf_bootp_subopt_unknown_type, "ERROR, Unknown parameter %s", field);
+ offset += (int)strlen(field);
+ break;
}
+ wmem_strbuf_append_printf(avaya_param_buf,",%s", field);
}
- if (wmem_strbuf_get_len(avaya_param_buf) > 0) {
- dissect_vendor_avaya_param(o242avaya_v_tree, pinfo, vti, tvb, optoff, avaya_param_buf);
- }
- break;
- }
-
- default: /* not special */
- /* The PacketCable CCC option number can vary. If this is a CCC option,
- handle it as a special.
- */
- if (code == pkt_ccc_option) {
- ftype = special;
- proto_item_append_text(vti,
- "CableLabs Client Configuration (%d bytes)",
- optlen);
- optend = optoff + optlen;
- while (optoff < optend) {
- switch (pkt_ccc_protocol_version) {
-
- case PACKETCABLE_CCC_I05:
- optoff = dissect_packetcable_i05_ccc(pinfo, vti, v_tree, tvb, optoff, optend);
- break;
- case PACKETCABLE_CCC_DRAFT5:
- case PACKETCABLE_CCC_RFC_3495:
- optoff = dissect_packetcable_ietf_ccc(pinfo, vti, v_tree, tvb, optoff, optend, pkt_ccc_protocol_version);
- break;
- default: /* XXX Should we do something here? */
- break;
- }
+ else {
+ if (wmem_strbuf_get_len(avaya_param_buf) > 0) {
+ dissect_vendor_avaya_param(o242avaya_v_tree, pinfo, avaya_ti, tvb, offset, avaya_param_buf);
+ offset += (int)wmem_strbuf_get_len(avaya_param_buf) + 1;
+ wmem_strbuf_truncate(avaya_param_buf, 0);
}
- } else {
- option_handled = FALSE;
+ wmem_strbuf_append(avaya_param_buf, field);
}
-
- break;
}
-
- basictype_consumed = bootp_handle_basic_types(pinfo, v_tree, vti, tvb, ftype,
- optoff, optlen, opt->phf, &default_hfs);
-
- if ((basictype_consumed == 0) && (option_handled == FALSE) &&
- (opt->phf == NULL) && (optlen > 0)) {
- proto_tree_add_item(v_tree, hf_bootp_option_value, tvb, voff+2, optlen, ENC_NA);
+ if (wmem_strbuf_get_len(avaya_param_buf) > 0) {
+ dissect_vendor_avaya_param(o242avaya_v_tree, pinfo, avaya_ti, tvb, offset, avaya_param_buf);
}
- return consumed;
+ return tvb_captured_length(tvb);
}
static const value_string option82_suboption_vals[] = {
@@ -3222,6 +3141,18 @@ bootp_dhcp_decode_agent_info(packet_info *pinfo, proto_item *v_ti, proto_tree *v
return optoff;
}
+static int
+dissect_bootpopt_relay_agent_info(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void* data _U_)
+{
+ int offset = 0;
+
+ while (tvb_reported_length_remaining(tvb, offset) > 0) {
+ offset = bootp_dhcp_decode_agent_info(pinfo, tree, tree, tvb, offset, tvb_reported_length(tvb));
+ }
+
+ return tvb_captured_length(tvb);
+}
+
static const value_string option43_pxeclient_suboption_vals[] = {
{ 0, "Padding" },
{ 1, "PXE mtftp IP" },
@@ -3343,6 +3274,29 @@ dissect_vendor_pxeclient_suboption(packet_info *pinfo, proto_item *v_ti, proto_t
return optoff;
}
+static gboolean
+dissect_pxeclient_vendor_info_heur( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
+{
+ int offset = 0;
+ bootp_option_data_t *option_data = (bootp_option_data_t*)data;
+ proto_tree* vendor_tree;
+
+ /* PXE protocol 2.1 as described in the Intel specs */
+ if ((option_data->vendor_class_id == NULL) ||
+ (strncmp((const gchar*)option_data->vendor_class_id, "PXEClient", strlen("PXEClient")) != 0))
+ return FALSE;
+
+ proto_item_append_text(tree, " (PXEClient)");
+ vendor_tree = proto_item_add_subtree(tree, ett_bootp_option);
+
+ while (tvb_reported_length_remaining(tvb, offset) > 0) {
+ offset = dissect_vendor_pxeclient_suboption(pinfo, tree, vendor_tree,
+ tvb, offset, tvb_reported_length(tvb));
+ }
+
+ return TRUE;
+}
+
static void
dissect_vendor_avaya_param(proto_tree *tree, packet_info *pinfo, proto_item *vti,
tvbuff_t *tvb, int optoff, wmem_strbuf_t *avaya_param_buf)
@@ -3551,8 +3505,8 @@ rfc3825_fixpoint_to_decimal(struct rfc3825_location_fixpoint_t *fixpoint, struct
return RFC3825_NOERROR;
}
-static int dissect_isns(packet_info *pinfo, proto_item *v_ti, proto_tree *v_tree,
- tvbuff_t *tvb, int optoff, int optlen)
+static int
+dissect_bootpopt_isns(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
static const int *isns_functions_hf_flags[] = {
&hf_bootp_option_isns_functions_enabled,
@@ -3596,19 +3550,19 @@ static int dissect_isns(packet_info *pinfo, proto_item *v_ti, proto_tree *v_tree
guint16 function_flags, dd_access_flags, administrative_flags;
guint32 server_security_flags;
- proto_tree *tree;
+ proto_tree *server_tree;
proto_item *item;
- int optend, heartbeat_set = 0;
+ int length = tvb_reported_length(tvb);
+ int offset = 0, heartbeat_set = 0;
- if (optlen < 14) {
- expert_add_info_format(pinfo, v_ti, &ei_bootp_bad_length, "length must be >= 14");
- return optoff;
+ if (length < 14) {
+ expert_add_info_format(pinfo, tree, &ei_bootp_bad_length, "length must be >= 14");
+ return 1;
}
- optend = optoff + optlen;
- item = proto_tree_add_bitmask(v_tree, tvb, optoff, hf_bootp_option_isns_functions,
+ item = proto_tree_add_bitmask(tree, tvb, offset, hf_bootp_option_isns_functions,
ett_bootp_isns_functions, isns_functions_hf_flags, ENC_BIG_ENDIAN);
- function_flags = tvb_get_ntohs(tvb, optoff);
+ function_flags = tvb_get_ntohs(tvb, offset);
/* RFC 4174, section "2.1. iSNS Functions Field" specifies that if
* the field "Function Fields Enabled" is set to 0, then "the contents
* of all other iSNS Function fields MUST be ignored. We will display
@@ -3618,54 +3572,53 @@ static int dissect_isns(packet_info *pinfo, proto_item *v_ti, proto_tree *v_tree
if (ISNS_BITFIELD_NZ_MUST_BE_IGNORED(function_flags, F_ISNS_FUNCTIONS_ENABLED))
expert_add_info(pinfo, item, &ei_bootp_option_isns_ignored_bitfield);
- optoff += 2;
- item = proto_tree_add_bitmask(v_tree, tvb, optoff, hf_bootp_option_isns_discovery_domain_access,
+ offset += 2;
+ item = proto_tree_add_bitmask(tree, tvb, offset, hf_bootp_option_isns_discovery_domain_access,
ett_bootp_isns_discovery_domain_access, isns_dda_hf_flags, ENC_BIG_ENDIAN);
- dd_access_flags = tvb_get_ntohs(tvb, optoff);
+ dd_access_flags = tvb_get_ntohs(tvb, offset);
if (ISNS_BITFIELD_NZ_MUST_BE_IGNORED(dd_access_flags, F_ISNS_DD_ACCESS_ENABLED))
expert_add_info(pinfo, item, &ei_bootp_option_isns_ignored_bitfield);
- optoff += 2;
- administrative_flags = tvb_get_ntohs(tvb, optoff);
+ offset += 2;
+ administrative_flags = tvb_get_ntohs(tvb, offset);
if (administrative_flags & F_ISNS_ADMIN_FLAGS_ENABLED) {
if ((administrative_flags & F_ISNS_ADMIN_FLAGS_HEARTBEAT)) {
- if (optlen < 18) {
- expert_add_info_format(pinfo, v_ti, &ei_bootp_bad_length, "length must be >= 18");
- return optoff;
+ if (length < 18) {
+ expert_add_info_format(pinfo, tree, &ei_bootp_bad_length, "length must be >= 18");
+ return offset;
}
heartbeat_set = 1;
}
}
- item = proto_tree_add_bitmask(v_tree, tvb, optoff, hf_bootp_option_isns_administrative_flags,
+ item = proto_tree_add_bitmask(tree, tvb, offset, hf_bootp_option_isns_administrative_flags,
ett_bootp_isns_administrative_flags, isns_administrative_flags, ENC_BIG_ENDIAN);
if (ISNS_BITFIELD_NZ_MUST_BE_IGNORED(administrative_flags, F_ISNS_ADMIN_FLAGS_ENABLED))
expert_add_info(pinfo, item, &ei_bootp_option_isns_ignored_bitfield);
- optoff += 2;
- item = proto_tree_add_bitmask(v_tree, tvb, optoff, hf_bootp_option_isns_server_security_bitmap,
+ offset += 2;
+ item = proto_tree_add_bitmask(tree, tvb, offset, hf_bootp_option_isns_server_security_bitmap,
ett_bootp_isns_server_security_bitmap, isns_server_security_flags, ENC_BIG_ENDIAN);
- server_security_flags = tvb_get_ntohl(tvb, optoff);
+ server_security_flags = tvb_get_ntohl(tvb, offset);
if (ISNS_BITFIELD_NZ_MUST_BE_IGNORED(server_security_flags, F_ISNS_SRV_SEC_BITMAP_ENABLED))
expert_add_info(pinfo, item, &ei_bootp_option_isns_ignored_bitfield);
- optoff += 4;
+ offset += 4;
if (heartbeat_set) {
- proto_tree_add_item(v_tree, hf_bootp_option_isns_heartbeat_originator_addr,
- tvb, optoff, 4, ENC_BIG_ENDIAN);
- optoff += 4;
+ proto_tree_add_item(tree, hf_bootp_option_isns_heartbeat_originator_addr, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
}
- proto_tree_add_item(v_tree, hf_bootp_option_isns_primary_server_addr,
- tvb, optoff, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(tree, hf_bootp_option_isns_primary_server_addr, tvb, offset, 4, ENC_BIG_ENDIAN);
- optoff += 4;
- if (optoff < optend) {
- tree = proto_tree_add_subtree(v_tree, tvb, optoff, 0, ett_bootp_isns_secondary_server_addr,
+ offset += 4;
+ if (tvb_reported_length_remaining(tvb, offset) > 0) {
+ server_tree = proto_tree_add_subtree(tree, tvb, offset, 0, ett_bootp_isns_secondary_server_addr,
&item, "Secondary iSNS Servers");
- optoff += bootp_handle_basic_types(pinfo, tree, item, tvb, ipv4_list, optoff, optend - optoff,
+ bootp_handle_basic_types(pinfo, server_tree, item, tvb, ipv4_list, offset, tvb_reported_length_remaining(tvb, offset),
&hf_bootp_option_isns_secondary_server_addr_list, NULL);
}
- return optoff;
+
+ return tvb_captured_length(tvb);
}
static const value_string option43_cl_suboption_vals[] = {
@@ -3867,6 +3820,80 @@ dissect_vendor_cablelabs_suboption(packet_info *pinfo, proto_item *v_ti, proto_t
return optoff;
}
+static gboolean
+dissect_cablelabs_vendor_info_heur( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
+{
+ int offset = 0;
+ bootp_option_data_t *option_data = (bootp_option_data_t*)data;
+ proto_tree* vendor_tree;
+
+ if ((option_data->vendor_class_id != NULL) &&
+ ((strncmp((const gchar*)option_data->vendor_class_id, "pktc", strlen("pktc")) == 0) ||
+ (strncmp((const gchar*)option_data->vendor_class_id, "docsis", strlen("docsis")) == 0) ||
+ (strncmp((const gchar*)option_data->vendor_class_id, "OpenCable2.0", strlen("OpenCable2.0")) == 0) ||
+ (strncmp((const gchar*)option_data->vendor_class_id, "CableHome", strlen("CableHome")) == 0))) {
+ /* CableLabs standard - see www.cablelabs.com/projects */
+ proto_item_append_text(tree, " (CableLabs)");
+ vendor_tree = proto_item_add_subtree(tree, ett_bootp_option);
+
+ while (tvb_reported_length_remaining(tvb, offset) > 0) {
+ offset = dissect_vendor_cablelabs_suboption(pinfo, tree, vendor_tree,
+ tvb, offset, tvb_reported_length(tvb));
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+dissect_aruba_ap_vendor_info_heur( tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data)
+{
+ int offset = 0;
+ bootp_option_data_t *option_data = (bootp_option_data_t*)data;
+ proto_tree* vendor_tree;
+
+ if ((option_data->vendor_class_id == NULL) ||
+ (strncmp((const gchar*)option_data->vendor_class_id, ARUBA_AP, strlen(ARUBA_AP)) != 0))
+ return FALSE;
+
+ proto_item_append_text(tree, " (Aruba AP)");
+ vendor_tree = proto_item_add_subtree(tree, ett_bootp_option);
+
+ proto_tree_add_item(vendor_tree, hf_bootp_option43_arubaap_controllerip, tvb, offset, tvb_reported_length(tvb), ENC_ASCII|ENC_NA);
+ return TRUE;
+}
+
+static gboolean
+dissect_aruba_instant_ap_vendor_info_heur( tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data)
+{
+ int offset = 0;
+ int reported_len = tvb_reported_length(tvb);
+ bootp_option_data_t *option_data = (bootp_option_data_t*)data;
+ proto_tree* vendor_tree;
+ proto_item* vendor_item;
+ gint32 nameorglen, ampiplen;
+
+ /* Aruba Instant AP */
+ if ((option_data->vendor_class_id == NULL) ||
+ (strncmp((const gchar*)option_data->vendor_class_id, ARUBA_INSTANT_AP, strlen(ARUBA_INSTANT_AP)) != 0))
+ return FALSE;
+
+ proto_item_append_text(tree, " (Aruba Instant AP)");
+
+ vendor_item = proto_tree_add_item(tree, hf_bootp_option43_arubaiap, tvb, offset, reported_len, ENC_ASCII|ENC_NA);
+ vendor_tree = proto_item_add_subtree(vendor_item, ett_bootp_option43_suboption);
+ nameorglen = tvb_find_guint8(tvb, offset, tvb_reported_length(tvb), ',');
+ proto_tree_add_item(vendor_tree, hf_bootp_option43_arubaiap_nameorg, tvb, offset, nameorglen, ENC_ASCII|ENC_NA);
+ offset += (nameorglen+1);
+ ampiplen = tvb_find_guint8(tvb, offset, reported_len-nameorglen-1, ',') - offset;
+ proto_tree_add_item(vendor_tree, hf_bootp_option43_arubaiap_ampip, tvb, offset, ampiplen, ENC_ASCII|ENC_NA);
+ offset += (ampiplen+1);
+ proto_tree_add_item(vendor_tree, hf_bootp_option43_arubaiap_password, tvb, offset, tvb_reported_length_remaining(tvb, offset), ENC_ASCII|ENC_NA);
+
+ return TRUE;
+}
+
static const value_string option43_bsdp_suboption_vals[] = {
{ 1, "Message Type" },
{ 2, "Version" },
@@ -4005,6 +4032,30 @@ dissect_vendor_bsdp_suboption(packet_info *pinfo, proto_item *v_ti, proto_tree *
return optoff;
}
+static gboolean
+dissect_packetcable_bsdpd_vendor_info_heur( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
+{
+ int offset = 0;
+ bootp_option_data_t *option_data = (bootp_option_data_t*)data;
+ proto_tree* vendor_tree;
+
+ if ((option_data->vendor_class_id == NULL) ||
+ (strncmp((const gchar*)option_data->vendor_class_id, PACKETCABLE_BSDP, strlen(PACKETCABLE_BSDP)) != 0))
+ return FALSE;
+
+ /* Apple BSDP */
+ proto_item_append_text(tree, " (Boot Server Discovery Protocol (BSDP))");
+ vendor_tree = proto_item_add_subtree(tree, ett_bootp_option);
+
+ while (tvb_reported_length_remaining(tvb, offset) > 0) {
+ offset = dissect_vendor_bsdp_suboption(pinfo, tree, vendor_tree,
+ tvb, offset, tvb_reported_length(tvb));
+ }
+
+ return TRUE;
+}
+
+
static int
dissect_vendor_generic_suboption(packet_info *pinfo, proto_item *v_ti, proto_tree *v_tree,
tvbuff_t *tvb, int optoff, int optend)
@@ -4042,6 +4093,50 @@ dissect_vendor_generic_suboption(packet_info *pinfo, proto_item *v_ti, proto_tre
return suboptoff;
}
+
+static int
+dissect_bootpopt_vi_vendor_specific_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
+{
+ int offset = 0;
+ int enterprise = 0;
+ int s_end = 0;
+ int option_data_len = 0;
+ proto_item *vti;
+ proto_tree *e_tree;
+
+ while (tvb_reported_length_remaining(tvb, offset) >= 5) {
+
+ vti = proto_tree_add_item_ret_uint(tree, hf_bootp_option125_enterprise, tvb, offset, 4, ENC_BIG_ENDIAN, &enterprise);
+ e_tree = proto_item_add_subtree(vti, ett_bootp_option);
+ offset += 4;
+
+ proto_tree_add_item_ret_uint(e_tree, hf_bootp_option125_length, tvb, offset, 1, ENC_NA, &option_data_len);
+ offset += 1;
+
+ s_end = offset + option_data_len;
+ if ( tvb_reported_length_remaining(tvb, s_end) < 0 ) {
+ expert_add_info_format(pinfo, vti, &ei_bootp_option125_enterprise_malformed, "no room left in option for enterprise %u data", enterprise);
+ break;
+ }
+
+ while (offset < s_end) {
+ tvbuff_t *enterprise_tvb = tvb_new_subset_length(tvb, offset, option_data_len);
+ int bytes_dissected = dissector_try_uint(bootp_enterprise_table, enterprise, enterprise_tvb, pinfo, e_tree);
+ if (bytes_dissected == 0) {
+ offset = dissect_vendor_generic_suboption(pinfo, vti, e_tree, tvb, offset, s_end);
+ } else{
+ offset += bytes_dissected;
+ }
+ }
+ }
+
+ if (tvb_reported_length_remaining(tvb, offset) > 0) {
+ expert_add_info_format(pinfo, tree, &ei_bootp_bad_length, "length < 5");
+ }
+
+ return tvb_captured_length(tvb);
+}
+
static const value_string option43_alcatel_suboption_vals[] = {
{ 0, "Padding" },
{ 58, "Voice VLAN ID" },
@@ -4179,6 +4274,35 @@ dissect_vendor_alcatel_suboption(packet_info *pinfo, proto_item *v_ti, proto_tre
return optoff;
}
+static gboolean
+dissect_alcatel_lucent_vendor_info_heur( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
+{
+ int offset = 0;
+ guint8 s_option;
+ proto_tree* vendor_tree;
+
+ if (tvb_reported_length(tvb) < 1)
+ return FALSE;
+
+ s_option = tvb_get_guint8(tvb, offset);
+ if ((s_option==58 || s_option==64 || s_option==65
+ || s_option==66 || s_option==67)
+ && test_encapsulated_vendor_options(tvb, offset, tvb_reported_length(tvb))) {
+
+ /* Alcatel-Lucent DHCP Extensions */
+ proto_item_append_text(tree, " (Alcatel-Lucent)");
+ vendor_tree = proto_item_add_subtree(tree, ett_bootp_option);
+
+ while (tvb_reported_length_remaining(tvb, offset) > 0) {
+ offset = dissect_vendor_alcatel_suboption(pinfo, tree, vendor_tree,
+ tvb, offset, tvb_reported_length(tvb));
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
static const value_string option63_suboption_vals[] = {
{ 1, "NWIP does not exist on subnet" },
{ 2, "NWIP exists in options area" },
@@ -4274,6 +4398,18 @@ dissect_netware_ip_suboption(packet_info *pinfo, proto_item *v_ti, proto_tree *v
return optoff;
}
+static int
+dissect_bootpopt_netware_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
+{
+ int offset = 0;
+
+ while (tvb_reported_length_remaining(tvb, offset) > 0) {
+ offset = dissect_netware_ip_suboption(pinfo, tree, tree, tvb, offset, tvb_reported_length(tvb));
+ }
+
+ return tvb_captured_length(tvb);
+}
+
static const value_string option125_tr111_suboption_vals[] = {
{ 1, "DeviceManufacturerOUI" },
{ 2, "DeviceSerialNumber" },
@@ -4285,13 +4421,12 @@ static const value_string option125_tr111_suboption_vals[] = {
};
static int
-dissect_vendor_tr111_suboption(packet_info *pinfo, proto_item *v_ti, proto_tree *v_tree,
- tvbuff_t *tvb, int optoff, int optend)
+dissect_vendor_tr111_suboption(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
- int suboptoff = optoff;
+ int offset = 0;
proto_tree *o125_v_tree;
proto_item *vti, *ti;
- guint8 subopt, subopt_len;
+ guint8 subopt, subopt_len;
struct basic_types_hfs default_hfs = {
NULL,
@@ -4321,55 +4456,54 @@ dissect_vendor_tr111_suboption(packet_info *pinfo, proto_item *v_ti, proto_tree
/* 6 */ {"GatewayProductClass", string, &hf_bootp_option125_tr111_gateway_product_class},
};
- subopt = tvb_get_guint8(tvb, optoff);
- suboptoff++;
+ subopt = tvb_get_guint8(tvb, offset);
+ offset++;
- if (suboptoff >= optend) {
- expert_add_info_format(pinfo, v_ti, &ei_bootp_missing_subopt_length,
+ if (tvb_reported_length_remaining(tvb, offset) < 1) {
+ expert_add_info_format(pinfo, tree, &ei_bootp_missing_subopt_length,
"Suboption %d: no room left in option for suboption length", subopt);
- return (optend);
+ return offset;
}
- subopt_len = tvb_get_guint8(tvb, suboptoff);
- vti = proto_tree_add_uint_format_value(v_tree, hf_bootp_option125_tr111_suboption,
- tvb, optoff, subopt_len+2, subopt, "(%d) %s",
+ subopt_len = tvb_get_guint8(tvb, offset);
+ vti = proto_tree_add_uint_format_value(tree, hf_bootp_option125_tr111_suboption,
+ tvb, offset, subopt_len+2, subopt, "(%d) %s",
subopt, val_to_str_const(subopt, option125_tr111_suboption_vals, "Unknown"));
o125_v_tree = proto_item_add_subtree(vti, ett_bootp_option125_tr111_suboption);
- proto_tree_add_item(o125_v_tree, hf_bootp_suboption_length, tvb, suboptoff, 1, ENC_BIG_ENDIAN);
- suboptoff++;
+ proto_tree_add_item(o125_v_tree, hf_bootp_suboption_length, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset++;
- if (suboptoff+subopt_len > optend) {
+ if (tvb_reported_length_remaining(tvb, offset) < subopt_len) {
expert_add_info_format(pinfo, vti, &ei_bootp_missing_subopt_value,
"Suboption %d: no room left in option for suboption value", subopt);
- return (optend);
+ return offset;
}
- ti = proto_tree_add_item(v_tree, hf_bootp_option125_value, tvb, suboptoff, subopt_len, ENC_NA);
+ ti = proto_tree_add_item(tree, hf_bootp_option125_value, tvb, offset, subopt_len, ENC_NA);
PROTO_ITEM_SET_HIDDEN(ti);
if (subopt < array_length(o125_tr111_opt)) {
- if (bootp_handle_basic_types(pinfo, o125_v_tree, vti, tvb, o125_tr111_opt[subopt].ftype, suboptoff, subopt_len, o125_tr111_opt[subopt].phf, &default_hfs) == 0) {
+ if (bootp_handle_basic_types(pinfo, o125_v_tree, vti, tvb, o125_tr111_opt[subopt].ftype, offset, subopt_len, o125_tr111_opt[subopt].phf, &default_hfs) == 0) {
if (o125_tr111_opt[subopt].ftype == special) {
if (o125_tr111_opt[subopt].phf != NULL)
- proto_tree_add_item(v_tree, *o125_tr111_opt[subopt].phf, tvb, suboptoff, subopt_len, ENC_BIG_ENDIAN);
+ proto_tree_add_item(o125_v_tree, *o125_tr111_opt[subopt].phf, tvb, offset, subopt_len, ENC_BIG_ENDIAN);
else
- proto_tree_add_item(v_tree, hf_bootp_option125_value, tvb, suboptoff, subopt_len, ENC_NA);
+ proto_tree_add_item(o125_v_tree, hf_bootp_option125_value, tvb, offset, subopt_len, ENC_NA);
}
else if (o125_tr111_opt[subopt].ftype == oui) {
/* Get hex string. Expecting 6 characters. */
- gchar *oui_string = tvb_get_string_enc(wmem_packet_scope(), tvb, suboptoff, subopt_len, ENC_ASCII);
+ gchar *oui_string = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, subopt_len, ENC_ASCII);
/* Convert to OUI number. Only 3 bytes so no data lost in downcast. */
guint32 oui_number = (guint32)strtol(oui_string, NULL, 16);
/* Add item using oui_vals */
- proto_tree_add_uint(v_tree, *o125_tr111_opt[subopt].phf, tvb, suboptoff, subopt_len, oui_number);
+ proto_tree_add_uint(o125_v_tree, *o125_tr111_opt[subopt].phf, tvb, offset, subopt_len, oui_number);
} else if (o125_tr111_opt[subopt].phf == NULL)
- proto_tree_add_item(v_tree, hf_bootp_option125_value, tvb, suboptoff, subopt_len, ENC_NA);
+ proto_tree_add_item(o125_v_tree, hf_bootp_option125_value, tvb, offset, subopt_len, ENC_NA);
}
}
- optoff += (subopt_len + 2);
- return optoff;
+ return subopt_len + 2;
}
static const value_string option125_cl_suboption_vals[] = {
@@ -4390,11 +4524,10 @@ static const value_string pkt_mib_env_ind_opt_vals[] = {
};
static int
-dissect_vendor_cl_suboption(packet_info *pinfo, proto_item *v_ti, proto_tree *v_tree,
- tvbuff_t *tvb, int optoff, int optend)
+dissect_vendor_cl_suboption(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
- int suboptoff = optoff;
- guint8 subopt, subopt_len;
+ int offset = 0;
+ guint8 subopt, subopt_len;
proto_tree *o125_v_tree;
proto_item *vti;
@@ -4421,56 +4554,55 @@ dissect_vendor_cl_suboption(packet_info *pinfo, proto_item *v_ti, proto_tree *v_
/* 5 */ {"Modem Capabilities : ", special, &hf_bootp_option125_cl_modem_capabilities},
};
- subopt = tvb_get_guint8(tvb, optoff);
- suboptoff++;
+ subopt = tvb_get_guint8(tvb, offset);
+ offset++;
- if (suboptoff >= optend) {
- expert_add_info_format(pinfo, v_ti, &ei_bootp_missing_subopt_length,
+ if (tvb_reported_length_remaining(tvb, offset) < 1) {
+ expert_add_info_format(pinfo, tree, &ei_bootp_missing_subopt_length,
"Suboption %d: no room left in option for suboption length", subopt);
- return (optend);
+ return offset;
}
- subopt_len = tvb_get_guint8(tvb, suboptoff);
- vti = proto_tree_add_uint_format_value(v_tree, hf_bootp_option125_cl_suboption,
- tvb, optoff, subopt_len+2, subopt, "(%d) %s",
+ subopt_len = tvb_get_guint8(tvb, offset);
+ vti = proto_tree_add_uint_format_value(tree, hf_bootp_option125_cl_suboption,
+ tvb, offset, subopt_len+2, subopt, "(%d) %s",
subopt, val_to_str_const(subopt, option125_cl_suboption_vals, "Unknown"));
o125_v_tree = proto_item_add_subtree(vti, ett_bootp_option125_cl_suboption);
- proto_tree_add_item(o125_v_tree, hf_bootp_suboption_length, tvb, suboptoff, 1, ENC_BIG_ENDIAN);
- suboptoff++;
+ proto_tree_add_item(o125_v_tree, hf_bootp_suboption_length, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset++;
- if (suboptoff+subopt_len > optend) {
+ if (tvb_reported_length_remaining(tvb, offset) < subopt_len) {
expert_add_info_format(pinfo, vti, &ei_bootp_missing_subopt_value,
"Suboption %d: no room left in option for suboption value", subopt);
- return (optend);
+ return offset;
}
if (subopt < array_length(o125_cl_opt)) {
if (bootp_handle_basic_types(pinfo, o125_v_tree, vti, tvb, o125_cl_opt[subopt].ftype,
- suboptoff, subopt_len, o125_cl_opt[subopt].phf, &default_hfs) == 0) {
+ offset, subopt_len, o125_cl_opt[subopt].phf, &default_hfs) == 0) {
switch(o125_cl_opt[subopt].ftype) {
case special:
if (o125_cl_opt[subopt].phf != NULL)
- proto_tree_add_item(o125_v_tree, *o125_cl_opt[subopt].phf, tvb, suboptoff, subopt_len, ENC_BIG_ENDIAN);
+ proto_tree_add_item(o125_v_tree, *o125_cl_opt[subopt].phf, tvb, offset, subopt_len, ENC_BIG_ENDIAN);
else
- proto_tree_add_item(o125_v_tree, hf_bootp_option125_value, tvb, suboptoff, subopt_len, ENC_NA);
+ proto_tree_add_item(o125_v_tree, hf_bootp_option125_value, tvb, offset, subopt_len, ENC_NA);
switch(subopt){
case 5: /* Modem Capabilities */
- dissect_docsis_cm_cap(o125_v_tree, tvb, optoff, subopt_len+2, TRUE);
+ dissect_docsis_cm_cap(o125_v_tree, tvb, offset-2, subopt_len+2, TRUE);
break;
}
break;
default:
if (o125_cl_opt[subopt].phf == NULL)
- proto_tree_add_item(o125_v_tree, hf_bootp_option125_value, tvb, suboptoff, subopt_len, ENC_NA);
+ proto_tree_add_item(o125_v_tree, hf_bootp_option125_value, tvb, offset, subopt_len, ENC_NA);
break;
}
}
}
- optoff += (subopt_len + 2);
- return optoff;
+ return subopt_len + 2;
}
/* PacketCable Multimedia Terminal Adapter device capabilities (option 60).
@@ -4882,6 +5014,26 @@ dissect_packetcable_mta_cap(proto_tree *v_tree, packet_info *pinfo, tvbuff_t *tv
}
}
+static gboolean
+dissect_packetcable_mta_vendor_id_heur( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_ )
+{
+ guint8* vendor_id;
+
+ if (tvb_reported_length(tvb) < 8) {
+ return FALSE;
+ }
+
+ vendor_id = tvb_get_string_enc(wmem_packet_scope(), tvb, 0, 8, ENC_ASCII|ENC_NA);
+ if ((strcmp((const char*)vendor_id, PACKETCABLE_MTA_CAP10) == 0) ||
+ (strcmp((const char*)vendor_id, PACKETCABLE_MTA_CAP15) == 0) ||
+ (strcmp((const char*)vendor_id, PACKETCABLE_MTA_CAP20) == 0)) {
+ dissect_packetcable_mta_cap(tree, pinfo, tvb, 0, tvb_reported_length(tvb));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
/* DOCSIS Cable Modem device capabilities (option 60/option 125). */
#define DOCSIS_CM_CAP_TLV_OFF 12
@@ -5473,6 +5625,47 @@ dissect_docsis_cm_cap(proto_tree *v_tree, tvbuff_t *tvb, int voff, int len, gboo
}
}
+static gboolean
+dissect_packetcable_cm_vendor_id_heur( tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_ )
+{
+ guint8* vendor_id;
+
+ if (tvb_reported_length(tvb) < 10) {
+ return FALSE;
+ }
+
+ vendor_id = tvb_get_string_enc(wmem_packet_scope(), tvb, 0, 10, ENC_ASCII|ENC_NA);
+ if ((strcmp((const char*)vendor_id, PACKETCABLE_CM_CAP11) == 0) ||
+ (strcmp((const char*)vendor_id, PACKETCABLE_CM_CAP20) == 0)) {
+ dissect_docsis_cm_cap(tree, tvb, 0, tvb_reported_length(tvb), FALSE);
+ return TRUE;
+ }
+
+ if ((strcmp((const char*)vendor_id, PACKETCABLE_CM_CAP30) == 0)) {
+ proto_tree_add_item(tree, hf_bootp_option_vendor_class_data, tvb, 0, tvb_reported_length(tvb), ENC_ASCII|ENC_NA);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+dissect_packetcable_bsdpd_vendor_id_heur( tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_ )
+{
+ int vendor_id_len = (int)strlen(PACKETCABLE_BSDPD);
+ if ((int)tvb_reported_length(tvb) < vendor_id_len) {
+ return FALSE;
+ }
+
+ if (tvb_memeql(tvb, 0, (const guint8*)PACKETCABLE_BSDPD, vendor_id_len) == 0 ) {
+ proto_tree_add_item(tree, hf_bootp_option_vendor_class_data, tvb, vendor_id_len, tvb_reported_length_remaining(tvb, vendor_id_len), ENC_ASCII|ENC_NA);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
/* Definitions specific to PKT-SP-PROV-I05-021127 begin with "PKT_CCC_I05".
Definitions specific to IETF draft 5 and RFC 3495 begin with "PKT_CCC_IETF".
Shared definitions begin with "PKT_CCC".
@@ -5832,6 +6025,29 @@ dissect_packetcable_ietf_ccc(packet_info *pinfo, proto_item *v_ti, proto_tree *v
return suboptoff;
}
+static int
+dissect_bootpopt_packetcable_ccc(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void* data _U_)
+{
+ int offset = 0;
+
+ while (tvb_reported_length_remaining(tvb, offset) > 0) {
+ switch (pkt_ccc_protocol_version) {
+
+ case PACKETCABLE_CCC_I05:
+ offset = dissect_packetcable_i05_ccc(pinfo, tree, tree, tvb, offset, tvb_reported_length(tvb));
+ break;
+ case PACKETCABLE_CCC_DRAFT5:
+ case PACKETCABLE_CCC_RFC_3495:
+ offset = dissect_packetcable_ietf_ccc(pinfo, tree, tree, tvb, offset, tvb_reported_length(tvb), pkt_ccc_protocol_version);
+ break;
+ default: /* XXX Should we do something here? */
+ break;
+ }
+ }
+
+ return tvb_captured_length(tvb);
+}
+
#define BOOTREQUEST 1
#define BOOTREPLY 2
@@ -5924,7 +6140,7 @@ dissect_bootp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U
rfc3396_dns_domain_search_list.index_current_block = 0;
rfc3396_sip_server.index_current_block = 0;
while (tmpvoff < eoff && !at_end) {
- offset_delta = bootp_option(tvb, pinfo, NULL, NULL, tmpvoff, eoff, TRUE, &at_end,
+ offset_delta = bootp_option(tvb, pinfo, NULL, tmpvoff, eoff, TRUE, &at_end,
&dhcp_type, &vendor_class_id, &overload);
if (offset_delta <= 0) {
proto_tree_add_expert(bp_tree, pinfo, &ei_bootp_option_parse_err,
@@ -6064,7 +6280,7 @@ dissect_bootp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U
rfc3396_dns_domain_search_list.index_current_block = 0;
rfc3396_sip_server.index_current_block = 0;
while (voff < eoff && !at_end) {
- offset_delta = bootp_option(tvb, pinfo, bp_tree, bp_ti, voff, eoff, FALSE, &at_end,
+ offset_delta = bootp_option(tvb, pinfo, bp_tree, voff, eoff, FALSE, &at_end,
&dhcp_type, &vendor_class_id, &overload);
if (offset_delta <= 0) {
proto_tree_add_expert(bp_tree, pinfo, &ei_bootp_option_parse_err,
@@ -6095,15 +6311,42 @@ bootp_init_protocol(void)
/* first copy default_bootp_opt[] to bootp_opt[]. This resets all values to default */
memcpy(bootp_opt, default_bootp_opt, sizeof(bootp_opt));
+ if ((num_bootp_records_uat > 0) && (saved_uat_opts == NULL))
+ {
+ saved_uat_opts = wmem_list_new(NULL);
+ }
+
/* Now apply the custom options */
for (i = 0; i < num_bootp_records_uat; i++)
{
bootp_opt[uat_bootp_records[i].opt].text = wmem_strdup(wmem_file_scope(), uat_bootp_records[i].text);
bootp_opt[uat_bootp_records[i].opt].ftype = uat_bootp_records[i].ftype;
bootp_opt[uat_bootp_records[i].opt].phf = NULL;
+
+ /* Apply the custom option to the dissection table*/
+ dissector_change_uint("bootp.option", uat_bootp_records[i].opt, bootpopt_basic_handle);
+
+ /* Save the option so it can be cleared later */
+ wmem_list_append(saved_uat_opts, GUINT_TO_POINTER(uat_bootp_records[i].opt));
}
}
+static void
+bootp_clear_uat_bootpopt(gpointer data, gpointer user_data _U_)
+{
+ dissector_reset_uint("bootp.option", GPOINTER_TO_UINT(data));
+}
+
+static void
+bootp_cleanup_protocol(void)
+{
+ wmem_list_foreach(saved_uat_opts, bootp_clear_uat_bootpopt, NULL);
+
+ wmem_destroy_list(saved_uat_opts);
+ saved_uat_opts = NULL;
+}
+
+
/* TAP STAT INFO */
typedef enum
{
@@ -8626,7 +8869,6 @@ proto_register_bootp(void)
{ &hf_bootp_opt_overload_file_end_missing, { "bootp.option.option_overload.file_end_missing", PI_PROTOCOL, PI_ERROR, "file overload end option missing", EXPFILL }},
{ &hf_bootp_opt_overload_sname_end_missing, { "bootp.option.option_overload.sname_end_missing", PI_PROTOCOL, PI_ERROR, "sname overload end option missing", EXPFILL }},
{ &hf_bootp_subopt_unknown_type, { "bootp.subopt.unknown_type", PI_PROTOCOL, PI_ERROR, "ERROR, please report: Unknown subopt type handler", EXPFILL }},
- { &ei_bootp_option77_user_class_malformed, { "bootp.option.user_class.malformed", PI_PROTOCOL, PI_ERROR, "User Class Information: malformed option", EXPFILL }},
{ &ei_bootp_option_civic_location_bad_cattype, { "bootp.option.civic_location.bad_cattype", PI_PROTOCOL, PI_ERROR, "Error with CAType", EXPFILL }},
{ &ei_bootp_option_dhcp_name_service_invalid, { "bootp.option.dhcp_name_service.invalid", PI_PROTOCOL, PI_ERROR, "Invalid Name Service", EXPFILL }},
{ &ei_bootp_option_sip_server_address_encoding, { "bootp.option.sip_server_address.encoding", PI_PROTOCOL, PI_ERROR, "RFC 3361 defines only 0 and 1 for Encoding byte", EXPFILL }},
@@ -8669,8 +8911,7 @@ proto_register_bootp(void)
module_t *bootp_module;
expert_module_t* expert_bootp;
- proto_bootp = proto_register_protocol("Bootstrap Protocol", "BOOTP/DHCP",
- "bootp");
+ proto_bootp = proto_register_protocol("Bootstrap Protocol", "BOOTP/DHCP", "bootp");
proto_register_field_array(proto_bootp, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
bootp_dhcp_tap = register_tap("bootp");
@@ -8678,8 +8919,14 @@ proto_register_bootp(void)
expert_bootp = expert_register_protocol(proto_bootp);
expert_register_field_array(expert_bootp, ei, array_length(ei));
- /* register init routine to setup the custom bootp options */
+ bootp_option_table = register_dissector_table("bootp.option", "BOOTP Options", proto_bootp, FT_UINT8, BASE_DEC);
+ bootp_vendor_id_subdissector = register_heur_dissector_list("bootp.vendor_id", proto_bootp);
+ bootp_vendor_info_subdissector = register_heur_dissector_list("bootp.vendor_info", proto_bootp);
+ bootp_enterprise_table = register_dissector_table("bootp.enterprise", "V-I Vendor Specific Enterprise", proto_bootp, FT_UINT32, BASE_DEC);
+
+ /* register init/cleanup routine to handle the custom bootp options */
register_init_routine(&bootp_init_protocol);
+ register_cleanup_routine(&bootp_cleanup_protocol);
/* Allow dissector to find be found by name. */
bootp_handle = register_dissector("bootp", dissect_bootp, proto_bootp);
@@ -8740,7 +8987,72 @@ proto_register_bootp(void)
void
proto_reg_handoff_bootp(void)
{
+ range_t *bootopt_basictype_range;
+
dissector_add_uint_range_with_preference("udp.port", BOOTP_UDP_PORT_RANGE, bootp_handle);
+
+ /* Create dissection function handles for all BOOTP options */
+ bootpopt_basic_handle = create_dissector_handle( dissect_bootpopt_basic_type, -1 );
+ range_convert_str(wmem_epan_scope(), &bootopt_basictype_range, BOOTP_OPTION_BASICTYPE_RANGE, 0xFF);
+ dissector_add_uint_range("bootp.option", bootopt_basictype_range, bootpopt_basic_handle);
+
+ dissector_add_uint("bootp.option", 21, create_dissector_handle( dissect_bootpopt_policy_filter, -1 ));
+ dissector_add_uint("bootp.option", 33, create_dissector_handle( dissect_bootpopt_static_route, -1 ));
+ dissector_add_uint("bootp.option", 43, create_dissector_handle( dissect_bootpopt_vendor_specific_info, -1 ));
+ dissector_add_uint("bootp.option", 52, create_dissector_handle( dissect_bootpopt_option_overload, -1 ));
+ dissector_add_uint("bootp.option", 53, create_dissector_handle( dissect_bootpopt_dhcp, -1 ));
+ dissector_add_uint("bootp.option", 55, create_dissector_handle( dissect_bootpopt_param_request_list, -1 ));
+ dissector_add_uint("bootp.option", 60, create_dissector_handle( dissect_bootpopt_vendor_class_identifier, -1 ));
+ dissector_add_uint("bootp.option", 61, create_dissector_handle( dissect_bootpopt_client_identifier, -1 ));
+ dissector_add_uint("bootp.option", 63, create_dissector_handle( dissect_bootpopt_netware_ip, -1 ));
+ dissector_add_uint("bootp.option", 77, create_dissector_handle( dissect_bootpopt_user_class_information, -1 ));
+ dissector_add_uint("bootp.option", 78, create_dissector_handle( dissect_bootpopt_slp_directory_agent, -1 ));
+ dissector_add_uint("bootp.option", 79, create_dissector_handle( dissect_bootpopt_slp_service_scope, -1 ));
+ dissector_add_uint("bootp.option", 81, create_dissector_handle( dissect_bootpopt_client_full_domain_name, -1 ));
+ dissector_add_uint("bootp.option", 82, create_dissector_handle( dissect_bootpopt_relay_agent_info, -1 ));
+ dissector_add_uint("bootp.option", 83, create_dissector_handle( dissect_bootpopt_isns, -1 ));
+ dissector_add_uint("bootp.option", 85, create_dissector_handle( dissect_bootpopt_novell_servers, -1 ));
+ dissector_add_uint("bootp.option", 90, create_dissector_handle( dissect_bootpopt_dhcp_authentication, -1 ));
+ dissector_add_uint("bootp.option", 94, create_dissector_handle( dissect_bootpopt_client_network_interface_id, -1 ));
+ dissector_add_uint("bootp.option", 97, create_dissector_handle( dissect_bootpopt_client_identifier_uuid, -1 ));
+ dissector_add_uint("bootp.option", 99, create_dissector_handle( dissect_bootpopt_civic_location, -1 ));
+ dissector_add_uint("bootp.option", 117, create_dissector_handle( dissect_bootpopt_name_server_search, -1 ));
+ dissector_add_uint("bootp.option", 119, create_dissector_handle( dissect_bootpopt_dhcp_domain_search, -1 ));
+ dissector_add_uint("bootp.option", 120, create_dissector_handle( dissect_bootpopt_sip_servers, -1 ));
+ dissector_add_uint("bootp.option", 121, create_dissector_handle( dissect_bootpopt_classless_static_route, -1 ));
+ /* The PacketCable CCC option number can vary. Still handled through preference */
+ dissector_add_uint("bootp.option", 122, create_dissector_handle( dissect_bootpopt_packetcable_ccc, -1 ));
+
+ dissector_add_uint("bootp.option", 123, create_dissector_handle( dissect_bootpopt_coordinate_based_location, -1 ));
+ dissector_add_uint("bootp.option", 124, create_dissector_handle( dissect_bootpopt_vi_vendor_class, -1 ));
+ dissector_add_uint("bootp.option", 125, create_dissector_handle( dissect_bootpopt_vi_vendor_specific_info, -1 ));
+ dissector_add_uint("bootp.option", 160, create_dissector_handle( dissect_bootpopt_dhcp_captive_portal, -1 ));
+ dissector_add_uint("bootp.option", 212, create_dissector_handle( dissect_bootpopt_6RD_option, -1 ));
+ dissector_add_uint("bootp.option", 242, create_dissector_handle( dissect_bootpopt_avaya_ip_telephone, -1 ));
+ dissector_add_uint("bootp.option", 249, create_dissector_handle( dissect_bootpopt_classless_static_route, -1 ));
+
+ /* Create heuristic dissection for BOOTP vendor class id */
+ heur_dissector_add( "bootp.vendor_id", dissect_packetcable_mta_vendor_id_heur, "PacketCable MTA", "packetcable_mta_bootp", proto_bootp, HEURISTIC_ENABLE );
+ heur_dissector_add( "bootp.vendor_id", dissect_packetcable_cm_vendor_id_heur, "PacketCable CM", "packetcable_cm_bootp", proto_bootp, HEURISTIC_ENABLE );
+ heur_dissector_add( "bootp.vendor_id", dissect_packetcable_bsdpd_vendor_id_heur, "PacketCable BSDPD", "packetcable_bsdpd_bootp", proto_bootp, HEURISTIC_ENABLE );
+
+ /* Create heuristic dissection for BOOTP vendor specific information */
+
+ /* Note that this is a rather weak (permissive) heuristic,
+ it's put first so it ends up at the end of the list, I guess this is OK.
+ Add any stronger (less permissive) heuristics after this!
+ XXX - Should we just disable by default? */
+ heur_dissector_add( "bootp.vendor_info", dissect_alcatel_lucent_vendor_info_heur, "Alcatel-Lucent", "alcatel_lucent_bootp", proto_bootp, HEURISTIC_ENABLE );
+
+ heur_dissector_add( "bootp.vendor_info", dissect_pxeclient_vendor_info_heur, "PXEClient", "pxeclient_bootp", proto_bootp, HEURISTIC_ENABLE );
+ heur_dissector_add( "bootp.vendor_info", dissect_cablelabs_vendor_info_heur, "CableLabs", "cablelabs_bootp", proto_bootp, HEURISTIC_ENABLE );
+ heur_dissector_add( "bootp.vendor_info", dissect_aruba_ap_vendor_info_heur, ARUBA_AP, "aruba_ap_bootp", proto_bootp, HEURISTIC_ENABLE );
+ heur_dissector_add( "bootp.vendor_info", dissect_aruba_instant_ap_vendor_info_heur, ARUBA_INSTANT_AP, "aruba_instant_ap_bootp", proto_bootp, HEURISTIC_ENABLE );
+ heur_dissector_add( "bootp.vendor_info", dissect_packetcable_bsdpd_vendor_info_heur, "PacketCable BSDPD", "packetcable_bsdpd_info_bootp", proto_bootp, HEURISTIC_ENABLE );
+
+ /* Create dissection function handles for BOOTP Enterprise dissection */
+ dissector_add_uint("bootp.enterprise", 4491, create_dissector_handle( dissect_vendor_cl_suboption, -1 ));
+ dissector_add_uint("bootp.enterprise", 3561, create_dissector_handle( dissect_vendor_tr111_suboption, -1 ));
}
/*