static gboolean dissect_ses_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree) { /* must check that this really is a ses packet */ int offset = 0; guint8 type; int len_len; guint16 len; /* first, check do we have at least 4 bytes (type+length) */ if (tvb_length(tvb) < 2) return FALSE; /* no */ /* can we recognize session PDU ? Return FALSE if not */ /* get SPDU type */ type = tvb_get_guint8(tvb, offset); /* check SPDU type */ if (match_strval(type, ses_vals) == NULL) { return FALSE; /* no, it isn't a session PDU */ } /* can we recognize the second session PDU if the first one was * a Give Tokens PDU? Return FALSE if not */ if(tvb_bytes_exist(tvb, 2, 2) && type == SES_GIVE_TOKENS) { /* get SPDU type */ type = tvb_get_guint8(tvb, offset+2); /* check SPDU type */ if (match_strval(type, ses_vals) == NULL) { return FALSE; /* no, it isn't a session PDU */ } } /* some Siemens SIMATIC protocols also use COTP, and shouldn't be * misinterpreted as SES. * the starter in this case is fixed to 0x32 (SES_MINOR_SYNC_ACK for SES), * so if the parameter type is unknown, it's probably SIMATIC */ if(type == 0x32 && tvb_length(tvb) >= 3) { type = tvb_get_guint8(tvb, offset+2); if (match_strval(type, param_vals) == NULL) { return FALSE; /* it's probably a SIMATIC protocol */ } } /* OK,let's check SPDU length */ /* get length of SPDU */ len = get_item_len(tvb, offset+1, &len_len); /* add header length */ len+=len_len; /* do we have enough bytes ? */ if (tvb_length(tvb) < len) return FALSE; /* no */ dissect_ses(tvb, pinfo, parent_tree); return TRUE; }
/* * Check whether the control field of the packet looks valid. */ gboolean check_xdlc_control(tvbuff_t *tvb, int offset, const value_string *u_modifier_short_vals_cmd, const value_string *u_modifier_short_vals_resp, gboolean is_response, gboolean is_extended _U_) { guint16 control; if (!tvb_bytes_exist(tvb, offset, 1)) return FALSE; /* not enough data to check */ switch (tvb_get_guint8(tvb, offset) & 0x03) { case XDLC_S: /* * Supervisory frame. * No fields to check for validity here. */ return TRUE; case XDLC_U: /* * Unnumbered frame. * * XXX - is this two octets, with a P/F bit, in HDLC extended * operation? It's one octet in LLC, even though the control * field of I and S frames is a 2-byte extended-operation field * in LLC. Given that there are no sequence numbers in the * control field of a U frame, there doesn't appear to be any * need for it to be 2 bytes in extended operation. */ if (u_modifier_short_vals_cmd == NULL) u_modifier_short_vals_cmd = modifier_short_vals_cmd; if (u_modifier_short_vals_resp == NULL) u_modifier_short_vals_resp = modifier_short_vals_resp; control = tvb_get_guint8(tvb, offset); if (is_response) { if (match_strval(control & XDLC_U_MODIFIER_MASK, u_modifier_short_vals_resp) == NULL) return FALSE; /* unknown modifier */ } else { if (match_strval(control & XDLC_U_MODIFIER_MASK, u_modifier_short_vals_cmd) == NULL) return FALSE; /* unknown modifier */ } return TRUE; default: /* * Information frame. * No fields to check for validity here. */ return TRUE; } }
/*--- dissect_qsig_arg ------------------------------------------------------*/ static int dissect_qsig_arg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { int offset; rose_ctx_t *rctx; gint32 opcode = 0, service; const qsig_op_t *op_ptr; const gchar *p; proto_item *ti, *ti_tmp; proto_tree *qsig_tree; offset = 0; rctx = get_rose_ctx(pinfo->private_data); DISSECTOR_ASSERT(rctx); if (rctx->d.pdu != 1) /* invoke */ return offset; if (rctx->d.code == 0) { /* local */ opcode = rctx->d.code_local; op_ptr = get_op(opcode); } else if (rctx->d.code == 1) { /* global */ op_ptr = g_hash_table_lookup(qsig_oid2op_hashtable, rctx->d.code_global); if (op_ptr) opcode = op_ptr->opcode; } else { return offset; } if (!op_ptr) return offset; service = get_service(opcode); ti = proto_tree_add_item(tree, proto_qsig, tvb, offset, tvb_length(tvb), ENC_NA); qsig_tree = proto_item_add_subtree(ti, ett_qsig); proto_tree_add_uint(qsig_tree, hf_qsig_operation, tvb, 0, 0, opcode); p = match_strval(opcode, VALS(qsig_str_operation)); if (p) { proto_item_append_text(ti, ": %s", p); proto_item_append_text(rctx->d.code_item, " - %s", p); if (rctx->apdu_depth >= 0) proto_item_append_text(proto_item_get_parent_nth(proto_tree_get_parent(tree), rctx->apdu_depth), " %s", p); } ti_tmp = proto_tree_add_uint(qsig_tree, hf_qsig_service, tvb, 0, 0, service); p = match_strval(service, VALS(qsig_str_service_name)); if (p) proto_item_append_text(ti_tmp, " - %s", p); if (op_ptr->arg_pdu) offset = op_ptr->arg_pdu(tvb, pinfo, qsig_tree); else if (tvb_length_remaining(tvb, offset) > 0) { proto_tree_add_text(qsig_tree, tvb, offset, -1, "UNSUPPORTED ARGUMENT TYPE (QSIG)"); offset += tvb_length_remaining(tvb, offset); } return offset; }
/* check to see if the message is an exclusive message send to host */ static gboolean csm_to_host(guint16 fc, guint16 ct) { if (fc == 0x0000) { return (match_strval(ct, exclusive_to_host_ct_vals) != NULL); } else { return (match_strval(fc, exclusive_to_host_vals) != NULL); } }
static void dissect_operation_tlv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset, gint length_count) { proto_item *ti; proto_tree *oper_tree; guint type, length; while (tvb_reported_length_remaining(tvb, offset) >= TLV_TL_LENGTH) { ti = proto_tree_add_text(tree, tvb, offset, length_count, "Operation TLV"); oper_tree = proto_item_add_subtree(ti, ett_forces_lfbselect_tlv_type_operation); type = tvb_get_ntohs(tvb,offset); ti = proto_tree_add_item(oper_tree, hf_forces_lfbselect_tlv_type_operation_type, tvb, offset, 2, ENC_BIG_ENDIAN); if (match_strval(type, operation_type_vals) == NULL) expert_add_info_format(pinfo, ti, PI_PROTOCOL, PI_WARN, "Bogus: ForCES Operation TLV (Type:0x%04x) is not supported", type); length = tvb_get_ntohs(tvb, offset+2); proto_tree_add_uint_format(oper_tree, hf_forces_lfbselect_tlv_type_operation_length, tvb, offset+2, 2, length, "Length: %u Bytes", length); dissect_path_data_tlv(tvb, pinfo, oper_tree, offset+TLV_TL_LENGTH); if (length == 0) break; offset += length; } }
static gboolean is_armagetronad_packet(tvbuff_t * tvb) { gint offset = 0; /* For each message in the frame */ while (tvb_length_remaining(tvb, offset) > 2) { gint data_len = tvb_get_ntohs(tvb, offset + 4) * 2; #if 0 /* * If the descriptor_id is not in the table it's possibly * because the protocol evoluated, losing synchronization * with the table, that's why we don't consider that as * a heuristic */ if (!match_strval(tvb_get_ntohs(tvb, offset), descriptors)) /* DescriptorID not found in the table */ return FALSE; #endif if (!tvb_bytes_exist(tvb, offset + 6, data_len)) /* Advertised length too long */ return FALSE; offset += 6 + data_len; } /* The packed should end with a 2 bytes ID */ return tvb_length_remaining(tvb, offset) == 2; }
static const char* spx_conn_ctrl(guint8 ctrl) { const char *p; static const value_string conn_vals[] = { { 0x00, "Data, No Ack Required" }, { SPX_EOM, "End-of-Message" }, { SPX_ATTN, "Attention" }, { SPX_SEND_ACK, "Acknowledgment Required"}, { SPX_SEND_ACK|SPX_EOM, "Send Ack: End Message"}, { SPX_SYS_PACKET, "System Packet"}, { SPX_SYS_PACKET|SPX_SEND_ACK, "System Packet: Send Ack"}, { 0x00, NULL } }; p = match_strval((ctrl & 0xf0), conn_vals ); if (p) { return p; } else { return "Unknown"; } }
const char *ipprotostr(const int proto) { const char *s; if ((s = match_strval(proto, ipproto_val)) != NULL) return s; s = "Unknown"; #ifdef HAVE_GETPROTOBYNUMBER /* * XXX - have another flag for resolving network-layer * protocol names? */ if (g_resolv_flags != 0) { static char buf[128]; struct protoent *pe; pe = getprotobynumber(proto); if (pe) { g_strlcpy(buf, pe->p_name, sizeof(buf)); s = buf; } } #endif return s; }
/* dissect_oicq - dissects oicq packet data * tvb - tvbuff for packet data (IN) * pinfo - packet info * proto_tree - resolved protocol tree */ static int dissect_oicq(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *oicq_tree; proto_item *ti; int offset = 0; /* Make sure this packet is for us. */ /* heuristic: OICQ iff (([0] == STX) && ([3/4] == <valid_command>) ) */ /* (Supposedly each OICQ message ends with an ETX so a test for */ /* same could also be part of the heuristic). */ if ( (match_strval(tvb_get_guint8(tvb, 0), oicq_flag_vals) == NULL) || (match_strval(tvb_get_ntohs(tvb, 3), oicq_command_vals) == NULL) ) return 0; col_set_str(pinfo->cinfo, COL_PROTOCOL, "OICQ"); col_set_str(pinfo->cinfo, COL_INFO, "OICQ Protocol "); if (tree) { ti = proto_tree_add_item(tree, proto_oicq, tvb, 0, -1, FALSE); oicq_tree = proto_item_add_subtree(ti, ett_oicq); proto_tree_add_item(oicq_tree, hf_oicq_flag, tvb, offset, 1, FALSE); offset += 1; proto_tree_add_item(oicq_tree, hf_oicq_version, tvb, offset, 2, FALSE); offset += 2; proto_tree_add_item(oicq_tree, hf_oicq_command, tvb, offset, 2, FALSE); offset += 2; proto_tree_add_item(oicq_tree, hf_oicq_seq, tvb, offset, 2, FALSE); offset += 2; proto_tree_add_item(oicq_tree, hf_oicq_qqid, tvb, offset, 4, FALSE); offset += 4; proto_tree_add_item(oicq_tree, hf_oicq_data, tvb, offset, -1, FALSE); } return tvb_length(tvb); }
/* Tries to match val against each element in the value_string array vs. Returns the associated string ptr on a match. Formats val with fmt, and returns the resulting string, on failure. */ const gchar* val_to_str(guint32 val, const value_string *vs, const char *fmt) { const gchar *ret; g_assert(fmt != NULL); ret = match_strval(val, vs); if (ret != NULL) return ret; return ep_strdup_printf(fmt, val); }
/* Tries to match val against each element in the value_string array vs. Returns the associated string ptr on a match. Returns 'unknown_str', on failure. */ const gchar* val_to_str_const(const guint32 val, const value_string *vs, const char *unknown_str) { const gchar *ret; g_assert(unknown_str != NULL); ret = match_strval(val, vs); if (ret != NULL) return ret; return unknown_str; }
/* Code to actually dissect the packets */ static int dissect_llrp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_item *ti; proto_tree *llrp_tree; guint16 type; guint32 len; guint offset = 0; /* Check that there's enough data */ if (tvb_reported_length(tvb) < LLRP_LEN_MIN) return 0; /* Make entries in Protocol column and Info column on summary display */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "LLRP"); col_set_str(pinfo->cinfo, COL_INFO, "LLRP Message"); type = tvb_get_ntohs(tvb, offset) & 0x03FF; col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)", val_to_str(type, message_types, "Unknown Type: %d")); ti = proto_tree_add_item(tree, proto_llrp, tvb, offset, -1, ENC_NA); llrp_tree = proto_item_add_subtree(ti, ett_llrp); proto_tree_add_item(llrp_tree, hf_llrp_version, tvb, offset, 1, ENC_NA); proto_tree_add_item(llrp_tree, hf_llrp_type, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; ti = proto_tree_add_item(llrp_tree, hf_llrp_length, tvb, offset, 4, ENC_BIG_ENDIAN); len = tvb_get_ntohl(tvb, offset); if (len > tvb_reported_length(tvb)) { expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_ERROR, "Incorrect length field: claimed %u, but only have %u.", len, tvb_reported_length(tvb)); } offset += 4; proto_tree_add_item(llrp_tree, hf_llrp_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; if (match_strval(type, message_types)) dissect_llrp_message(tvb, pinfo, llrp_tree, type, offset); return tvb_length(tvb); }
/*--- dissect_qsig_err ------------------------------------------------------*/ static int dissect_qsig_err(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { int offset; rose_ctx_t *rctx; gint32 errcode; const qsig_err_t *err_ptr; const gchar *p; proto_item *ti; proto_tree *qsig_tree; offset = 0; rctx = get_rose_ctx(pinfo->private_data); DISSECTOR_ASSERT(rctx); if (rctx->d.pdu != 3) /* returnError */ return offset; if (rctx->d.code != 0) /* local */ return offset; errcode = rctx->d.code_local; err_ptr = get_err(errcode); if (!err_ptr) return offset; ti = proto_tree_add_item(tree, proto_qsig, tvb, offset, tvb_length(tvb), ENC_NA); qsig_tree = proto_item_add_subtree(ti, ett_qsig); proto_tree_add_uint(qsig_tree, hf_qsig_error, tvb, 0, 0, errcode); p = match_strval(errcode, VALS(qsig_str_error)); if (p) { proto_item_append_text(ti, ": %s", p); proto_item_append_text(rctx->d.code_item, " - %s", p); if (rctx->apdu_depth >= 0) proto_item_append_text(proto_item_get_parent_nth(proto_tree_get_parent(tree), rctx->apdu_depth), " %s", p); } if (err_ptr->err_pdu) offset = err_ptr->err_pdu(tvb, pinfo, qsig_tree); else if (tvb_length_remaining(tvb, offset) > 0) { proto_tree_add_text(qsig_tree, tvb, offset, -1, "UNSUPPORTED ERROR TYPE (QSIG)"); offset += tvb_length_remaining(tvb, offset); } return offset; }
/* Code to actually dissect the packets - UDP */ static gint dissect_laplink_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { int offset = 0; proto_item *ti; proto_tree *laplink_tree; guint32 udp_ident; const gchar *udp_ident_string; /* * Make sure the identifier is reasonable. */ if (!tvb_bytes_exist(tvb, offset, 4)) return 0; /* not enough bytes to check */ udp_ident = tvb_get_ntohl(tvb, offset); udp_ident_string = match_strval(udp_ident, laplink_udp_magic); if (udp_ident_string == NULL) return 0; /* unknown */ /* Make entries in Protocol column and Info column on summary display */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "Laplink"); if (check_col(pinfo->cinfo, COL_INFO)) col_add_str(pinfo->cinfo, COL_INFO, udp_ident_string); if (tree){ ti = proto_tree_add_item(tree, proto_laplink, tvb, 0, -1, ENC_NA); laplink_tree = proto_item_add_subtree(ti, ett_laplink); proto_tree_add_uint(laplink_tree, hf_laplink_udp_ident, tvb, offset, 4, udp_ident); offset += 4; proto_tree_add_item(laplink_tree, hf_laplink_udp_name, tvb, offset, -1, ENC_ASCII|ENC_NA); } return tvb_length(tvb); }
/* Dissector for xcsl */ static void dissect_xcsl_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { guint offset = 0; gint length_remaining; guint8 idx; gboolean request; guint8 par; guint8 str[MAXLEN]; guint8 result; const gchar *code; guint len; gint next_offset; proto_item *xcsl_item = NULL; proto_tree *xcsl_tree = NULL; /* color support */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "Xcsl"); col_clear(pinfo->cinfo, COL_INFO); /* Create display tree for the xcsl protocol */ if (tree) { xcsl_item = proto_tree_add_item(tree, proto_xcsl,tvb, offset, -1, FALSE); xcsl_tree = proto_item_add_subtree(xcsl_item, ett_xcsl); } /* reset idx */ idx = 0; /* reset the parameter count */ par = 0; /* switch whether it concerns a command or an answer */ request = FALSE; while (tvb_reported_length_remaining(tvb, offset) != 0) { length_remaining = tvb_ensure_length_remaining(tvb, offset); if ( length_remaining == -1 ) { return; } /* get next item */ if (!(get_next_item(tvb, offset, length_remaining, str, &next_offset, &len))) { /* do not continue when get_next_item returns false */ return; } /* do not add to the tree when the string is of zero length */ if ( strlen(str) == 0 ) { offset = next_offset + 1; continue; } /* Xcsl (Call Specification Language) protocol in brief : * * Request : * * <xcsl-version>;<transaction-id>;<command>;[parameter1;parameter2;parameter3;....] * * Reply : * * <xcsl-version>;transaction-id;<result>;[answer data;answer data];... * * If result is one or more digits, this is determined as a Reply. * * Example : * * --> xcsl-1.0;1000;offhook;+31356871234 * <-- xcsl-1.0;1000;0 <- success * * --> xcsl-1.0;1001;dial;+31356871234;+31356875678 * <-- xcsl-1.0;1001;0 <- success * * * index : 0 1 2 3 4 * * Index 2 represents the return code (see the xcsl_action_vals[] definitions) * */ /* One by one go through each item ';' separated */ switch (idx) { /* This is the protocol item */ case 0: proto_tree_add_item(tree, hf_xcsl_protocol_version, tvb, offset, len, FALSE); break; /* This should be the transaction ID, if non-digit, it is treated as info */ case 1: if ( isdigit(str[0]) ) { proto_tree_add_item(tree, hf_xcsl_transaction_id, tvb, offset, len, FALSE); } else { proto_tree_add_item(tree, hf_xcsl_information, tvb, offset, len, FALSE); } if (check_col(pinfo->cinfo, COL_INFO)) col_append_fstr(pinfo->cinfo, COL_INFO, "%s ",str); break; /* Starting with non-digit -> Command, if it starts with a digit -> reply */ case 2: if ( isdigit(str[0]) ) { request = FALSE; result = atoi(str); if ( result >= XCSL_NONE ) { result = XCSL_UNDEFINED; } code = match_strval(result, xcsl_action_vals); /* Print result code and description */ xcsl_item = proto_tree_add_item(tree, hf_xcsl_result, tvb, offset, len, FALSE); proto_item_append_text(xcsl_item, " (%s)", code); if (result != 0 && check_col(pinfo->cinfo, COL_INFO)) col_append_fstr(pinfo->cinfo, COL_INFO, "[%s] ", code); } else { request = TRUE; proto_tree_add_item(tree, hf_xcsl_command, tvb, offset, len, FALSE); if (check_col(pinfo->cinfo, COL_INFO)) col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", str); } break; /* This is a command parameter */ default: proto_tree_add_item(tree, hf_xcsl_parameter, tvb, offset, len, FALSE); if (check_col(pinfo->cinfo, COL_INFO)) { if ( request == TRUE ) { col_append_fstr(pinfo->cinfo, COL_INFO, ": %s ",str); } else { if (par == 0) { col_append_fstr(pinfo->cinfo, COL_INFO, "reply: %s ",str); } else { col_append_fstr(pinfo->cinfo, COL_INFO, ": %s ",str); } } } /* increment the parameter count */ par++; break; } offset = next_offset + 1; idx++; } return; }
static int dissect_ddtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *ddtp_tree = NULL; proto_item *ti; /* * If we don't recognize the version number, don't dissect this. */ if (tvb_length(tvb) >= 4) { if (match_strval(tvb_get_ntohl(tvb, 0), vals_ddtp_version) == NULL) return 0; } /* Indicate what kind of message this is. */ col_set_str (pinfo->cinfo, COL_PROTOCOL, "DDTP"); /* In case we throw an exception below. */ col_clear (pinfo->cinfo, COL_INFO); if (tree) { ti = proto_tree_add_item(tree, proto_ddtp, tvb, 0, -1, FALSE); ddtp_tree = proto_item_add_subtree(ti, ett_ddtp); proto_tree_add_item(ddtp_tree, hf_ddtp_version, tvb, 0, 4, FALSE); proto_tree_add_item(ddtp_tree, hf_ddtp_encrypt, tvb, 4, 4, FALSE); proto_tree_add_item(ddtp_tree, hf_ddtp_hostid, tvb, 8, 4, FALSE); } if (tvb_get_ntohl(tvb, 4) == DDTP_ENCRYPT_PLAINTEXT) { if (tree) proto_tree_add_item(ddtp_tree, hf_ddtp_msgtype, tvb, 12, 4, FALSE); switch (tvb_get_ntohl(tvb, 12)) { case DDTP_MESSAGE_ERROR : col_set_str(pinfo->cinfo, COL_INFO, "Message Error"); break; case DDTP_UPDATE_QUERY : col_set_str(pinfo->cinfo, COL_INFO, "Update Query"); if (tree) { proto_tree_add_item(ddtp_tree, hf_ddtp_opcode, tvb, 16, 4, FALSE); proto_tree_add_item(ddtp_tree, hf_ddtp_ipaddr, tvb, 20, 4, FALSE); } break; case DDTP_UPDATE_REPLY : col_set_str(pinfo->cinfo, COL_INFO, "Update Reply"); if (tree) { proto_tree_add_item(ddtp_tree, hf_ddtp_status, tvb, 16, 4, FALSE); } break; case DDTP_ALIVE_QUERY : col_set_str(pinfo->cinfo, COL_INFO, "Alive Query"); if (tree) { proto_tree_add_text(ddtp_tree, tvb, 16, 4, "Dummy : %u", tvb_get_ntohl(tvb, 16)); } break; case DDTP_ALIVE_REPLY : col_set_str(pinfo->cinfo, COL_INFO, "Alive Reply"); if (tree) { proto_tree_add_text(ddtp_tree, tvb, 16, 4, "Dummy : %u", tvb_get_ntohl(tvb, 16)); } break; default : col_set_str(pinfo->cinfo, COL_INFO, "Unknown type"); if (tree) { proto_tree_add_text(ddtp_tree, tvb, 12, 4, "Unknown type : %u", tvb_get_ntohl(tvb, 12)); } } } else { col_set_str(pinfo->cinfo, COL_INFO, "Encrypted payload"); } return tvb_length(tvb); }
void ethertype(guint16 etype, tvbuff_t *tvb, int offset_after_etype, packet_info *pinfo, proto_tree *tree, proto_tree *fh_tree, int etype_id, int trailer_id, int fcs_len) { const char *description; tvbuff_t *volatile next_tvb; guint length_before; gint captured_length, reported_length; volatile gboolean dissector_found = FALSE; const char *volatile saved_proto; void *pd_save; /* Add the Ethernet type to the protocol tree */ if (tree) { proto_tree_add_uint(fh_tree, etype_id, tvb, offset_after_etype - 2, 2, etype); } /* Get the captured length and reported length of the data after the Ethernet type. */ captured_length = tvb_length_remaining(tvb, offset_after_etype); reported_length = tvb_reported_length_remaining(tvb, offset_after_etype); /* Remember how much data there is after the Ethernet type, including any trailer and FCS. */ length_before = reported_length; /* Construct a tvbuff for the payload after the Ethernet type. If the FCS length is positive, remove the FCS. (If it's zero, there's no FCS; if it's negative, we don't know whether there's an FCS, so we'll guess based on the length of the trailer.) */ if (fcs_len > 0) { if (captured_length >= 0 && reported_length >= 0) { if (reported_length >= fcs_len) reported_length -= fcs_len; if (captured_length > reported_length) captured_length = reported_length; } } next_tvb = tvb_new_subset(tvb, offset_after_etype, captured_length, reported_length); pinfo->ethertype = etype; /* Look for sub-dissector, and call it if found. Catch exceptions, so that if the reported length of "next_tvb" was reduced by some dissector before an exception was thrown, we can still put in an item for the trailer. */ saved_proto = pinfo->current_proto; pd_save = pinfo->private_data; TRY { dissector_found = dissector_try_uint(ethertype_dissector_table, etype, next_tvb, pinfo, tree); } CATCH(BoundsError) { /* Somebody threw BoundsError, which means that: 1) a dissector was found, so we don't need to dissect the payload as data or update the protocol or info columns; 2) dissecting the payload found that the packet was cut off by a snapshot length before the end of the payload. The trailer comes after the payload, so *all* of the trailer is cut off, and we'll just get another BoundsError if we add the trailer. Therefore, we just rethrow the exception so it gets reported; we don't dissect the trailer or do anything else. */ RETHROW; } CATCH(OutOfMemoryError) { RETHROW; } CATCH_ALL { /* Somebody threw an exception other than BoundsError, which means that a dissector was found, so we don't need to dissect the payload as data or update the protocol or info columns. We just show the exception and then drive on to show the trailer, after noting that a dissector was found and restoring the protocol value that was in effect before we called the subdissector. */ show_exception(next_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE); /* Restore the private_data structure in case one of the * called dissectors modified it (and, due to the exception, * was unable to restore it). */ pinfo->private_data = pd_save; dissector_found = TRUE; pinfo->current_proto = saved_proto; } ENDTRY; if (!dissector_found) { /* No sub-dissector found. Label rest of packet as "Data" */ call_dissector(data_handle,next_tvb, pinfo, tree); /* Label protocol */ col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "0x%04x", etype); description = match_strval(etype, etype_vals); if (description) { col_add_str(pinfo->cinfo, COL_INFO, description); } } add_dix_trailer(pinfo, tree, fh_tree, trailer_id, tvb, next_tvb, offset_after_etype, length_before, fcs_len); }
void dissect_sss_reply(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ncp_tree, guint8 subfunc, ncp_req_hash_value *request_value) { guint32 foffset=0; guint32 subverb=0; guint32 msg_length=0; guint32 return_code=0; guint32 number_of_items=0; gint32 length_of_string=0; guint32 i = 0; const gchar *str; proto_tree *atree; proto_item *aitem; proto_item *expert_item; foffset = 8; col_set_str(pinfo->cinfo, COL_PROTOCOL, "NSSS"); if (tvb_length_remaining(tvb, foffset)<4) { return; } aitem = proto_tree_add_text(ncp_tree, tvb, foffset, -1, "Function: %s", val_to_str(subfunc, sss_func_enum, "val_to_str")); atree = proto_item_add_subtree(aitem, ett_sss); switch (subfunc) { case 1: proto_tree_add_item(atree, hf_flags, tvb, foffset, 4, ENC_LITTLE_ENDIAN); foffset += 4; proto_tree_add_item(atree, hf_sss_version, tvb, foffset, 4, ENC_LITTLE_ENDIAN); foffset += 4; break; case 2: if (request_value) { subverb = request_value->req_nds_flags; str = match_strval(subverb, sss_verb_enum); if (str) { proto_tree_add_text(atree, tvb, foffset, tvb_length_remaining(tvb, foffset), "Verb: %s", str); } } proto_tree_add_item(atree, hf_length, tvb, foffset, 4, ENC_LITTLE_ENDIAN); msg_length = tvb_get_letohl(tvb, foffset); return_code = tvb_get_ntohl(tvb, foffset+msg_length); foffset += 4; proto_tree_add_item(atree, hf_frag_handle, tvb, foffset, 4, ENC_LITTLE_ENDIAN); foffset += 4; msg_length -= 4; if ((tvb_get_letohl(tvb, foffset-4)==0xffffffff) && (msg_length > 4)) { foffset += 4; return_code = tvb_get_letohl(tvb, foffset); str = match_strval(return_code, sss_errors_enum); if (str) { expert_item = proto_tree_add_item(atree, hf_return_code, tvb, foffset, 4, ENC_LITTLE_ENDIAN); expert_add_info_format(pinfo, expert_item, PI_RESPONSE_CODE, PI_ERROR, "SSS Error: %s", str); if (check_col(pinfo->cinfo, COL_INFO)) { col_add_fstr(pinfo->cinfo, COL_INFO, "R Error - %s", val_to_str(return_code, sss_errors_enum, "Unknown (%d)")); } foffset+=4; } else { proto_tree_add_text(atree, tvb, foffset, 4, "Return Code: Success (0x00000000)"); if (tvb_length_remaining(tvb, foffset) > 8) { foffset += 4; if (request_value && subverb == 6) { foffset += 4; number_of_items = tvb_get_letohl(tvb, foffset); foffset += 8; for (i=0; i<number_of_items; i++) { length_of_string = find_delimiter(tvb, foffset); if (length_of_string > tvb_length_remaining(tvb, foffset)) { return; } foffset = sss_string(tvb, hf_secret, atree, foffset, TRUE, length_of_string); if (tvb_length_remaining(tvb, foffset) < 8) { return; } foffset++; } } else { proto_tree_add_item(atree, hf_enc_data, tvb, foffset, tvb_length_remaining(tvb, foffset), ENC_NA); } } } } else { proto_tree_add_text(atree, tvb, foffset, 4, "Return Code: Success (0x00000000)"); if (tvb_length_remaining(tvb, foffset) > 8) { foffset += 4; proto_tree_add_item(atree, hf_enc_data, tvb, foffset, tvb_length_remaining(tvb, foffset), ENC_NA); } } break; case 3: break; default: break; } }
static void dissect_ncp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean is_tcp) { proto_tree *ncp_tree = NULL; proto_item *ti; struct ncp_ip_header ncpiph; struct ncp_ip_rqhdr ncpiphrq; guint16 ncp_burst_seqno, ncp_ack_seqno; guint16 flags = 0; proto_tree *flags_tree = NULL; int hdr_offset = 0; int commhdr = 0; int offset = 0; gint length_remaining; tvbuff_t *next_tvb; guint32 testvar = 0, ncp_burst_command, burst_len, burst_off, burst_file; guint8 subfunction; guint32 nw_connection = 0, data_offset; guint16 data_len = 0; guint16 missing_fraglist_count = 0; mncp_rhash_value *request_value = NULL; conversation_t *conversation; proto_item *expert_item; col_set_str(pinfo->cinfo, COL_PROTOCOL, "NCP"); col_clear(pinfo->cinfo, COL_INFO); hdr_offset = 0; ncp_hdr = &header; commhdr = hdr_offset; ti = proto_tree_add_item(tree, proto_ncp, tvb, 0, -1, FALSE); ncp_tree = proto_item_add_subtree(ti, ett_ncp); if (is_tcp) { if (tvb_get_ntohl(tvb, hdr_offset) != NCPIP_RQST && tvb_get_ntohl(tvb, hdr_offset) != NCPIP_RPLY) commhdr += 1; /* Get NCPIP Header data */ ncpiph.signature = tvb_get_ntohl(tvb, commhdr); proto_tree_add_uint(ncp_tree, hf_ncp_ip_sig, tvb, commhdr, 4, ncpiph.signature); ncpiph.length = (0x7fffffff & tvb_get_ntohl(tvb, commhdr+4)); proto_tree_add_uint(ncp_tree, hf_ncp_ip_length, tvb, commhdr+4, 4, ncpiph.length); commhdr += 8; if (ncpiph.signature == NCPIP_RQST) { ncpiphrq.version = tvb_get_ntohl(tvb, commhdr); proto_tree_add_uint(ncp_tree, hf_ncp_ip_ver, tvb, commhdr, 4, ncpiphrq.version); commhdr += 4; ncpiphrq.rplybufsize = tvb_get_ntohl(tvb, commhdr); proto_tree_add_uint(ncp_tree, hf_ncp_ip_rplybufsize, tvb, commhdr, 4, ncpiphrq.rplybufsize); commhdr += 4; } /* Check to see if this is a valid offset, otherwise increment for packet signature */ if (match_strval(tvb_get_ntohs(tvb, commhdr), ncp_type_vals)==NULL) { /* Check to see if we have a valid type after packet signature length */ if (match_strval(tvb_get_ntohs(tvb, commhdr+8), ncp_type_vals)!=NULL) { proto_tree_add_item(ncp_tree, hf_ncp_ip_packetsig, tvb, commhdr, 8, FALSE); commhdr += 8; } } } else { /* Initialize this structure, we use it below */ memset(&ncpiph, 0, sizeof(ncpiph)); } header.type = tvb_get_ntohs(tvb, commhdr); header.sequence = tvb_get_guint8(tvb, commhdr+2); header.conn_low = tvb_get_guint8(tvb, commhdr+3); header.task = tvb_get_guint8(tvb, commhdr+4); header.conn_high = tvb_get_guint8(tvb, commhdr+5); proto_tree_add_uint(ncp_tree, hf_ncp_type, tvb, commhdr, 2, header.type); nw_connection = (header.conn_high*256)+header.conn_low; /* Ok, we need to track the conversation so that we can * determine if a new server session is occuring for this * connection. */ conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_NCP, (guint32) pinfo->srcport, (guint32) pinfo->destport, 0); if ((ncpiph.length & 0x80000000) || ncpiph.signature == NCPIP_RPLY) { /* First time through we will record the initial connection and task * values */ if (!pinfo->fd->flags.visited) { if (conversation != NULL) { /* find the record telling us the * request made that caused this * reply */ request_value = mncp_hash_lookup(conversation, nw_connection, header.task); /* if for some reason we have no * conversation in our hash, create * one */ if (request_value == NULL) { request_value = mncp_hash_insert(conversation, nw_connection, header.task, pinfo); } } else { /* It's not part of any conversation * - create a new one. */ conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_NCP, (guint32) pinfo->srcport, (guint32) pinfo->destport, 0); request_value = mncp_hash_insert(conversation, nw_connection, header.task, pinfo); } /* If this is a request packet then we * might have a new task */ if (ncpiph.signature == NCPIP_RPLY) { /* Now on reply packets we have to * use the state of the original * request packet, so look up the * request value and check the task number */ request_value = mncp_hash_lookup(conversation, nw_connection, header.task); } } else { /* Get request value data */ request_value = mncp_hash_lookup(conversation, nw_connection, header.task); if (request_value) { if ((request_value->session_start_packet_num == pinfo->fd->num) && ncp_echo_conn) { expert_add_info_format(pinfo, NULL, PI_RESPONSE_CODE, PI_CHAT, "Detected New Server Session. Connection %d, Task %d", nw_connection, header.task); } } } } else { if (!pinfo->fd->flags.visited) { if (conversation != NULL) { /* find the record telling us the * request made that caused this * reply */ request_value = mncp_hash_lookup(conversation, nw_connection, header.task); /* if for some reason we have no * conversation in our hash, create * one */ if (request_value == NULL) { request_value = mncp_hash_insert(conversation, nw_connection, header.task, pinfo); } } else { /* It's not part of any conversation * - create a new one. */ conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_NCP, (guint32) pinfo->srcport, (guint32) pinfo->destport, 0); request_value = mncp_hash_insert(conversation, nw_connection, header.task, pinfo); } /* find the record telling us the request * made that caused this reply */ } else { request_value = mncp_hash_lookup(conversation, nw_connection, header.task); if (request_value) { if ((request_value->session_start_packet_num == pinfo->fd->num) && ncp_echo_conn) { expert_add_info_format(pinfo, NULL, PI_RESPONSE_CODE, PI_CHAT, "Detected New Server Session. Connection %d, Task %d", nw_connection, header.task); } } } } tap_queue_packet(ncp_tap.hdr, pinfo, ncp_hdr); if (check_col(pinfo->cinfo, COL_INFO)) { col_add_str(pinfo->cinfo, COL_INFO, val_to_str(header.type, ncp_type_vals, "Unknown type (0x%04x)")); } /* * Process the packet-type-specific header. */ switch (header.type) { case NCP_BROADCAST_SLOT: /* Server Broadcast */ proto_tree_add_uint(ncp_tree, hf_ncp_seq, tvb, commhdr + 2, 1, header.sequence); proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection); proto_tree_add_item(ncp_tree, hf_ncp_task, tvb, commhdr + 4, 1, FALSE); proto_tree_add_item(ncp_tree, hf_ncp_oplock_flag, tvb, commhdr + 9, 1, tvb_get_guint8(tvb, commhdr+9)); proto_tree_add_item(ncp_tree, hf_ncp_oplock_handle, tvb, commhdr + 10, 4, FALSE); if ((tvb_get_guint8(tvb, commhdr+9)==0x24) && ncp_echo_file) { expert_add_info_format(pinfo, NULL, PI_RESPONSE_CODE, PI_CHAT, "Server requesting station to clear oplock on handle - %08x", tvb_get_ntohl(tvb, commhdr+10)); } break; case NCP_LIP_ECHO: /* Lip Echo Packet */ proto_tree_add_item(ncp_tree, hf_lip_echo, tvb, commhdr, 13, FALSE); break; case NCP_BURST_MODE_XFER: /* Packet Burst Packet */ /* * XXX - we should keep track of whether there's a burst * outstanding on a connection and, if not, treat the * beginning of the data as a burst header. * * The burst header contains: * * 4 bytes of little-endian function number: * 1 = read, 2 = write; * * 4 bytes of file handle; * * 8 reserved bytes; * * 4 bytes of big-endian file offset; * * 4 bytes of big-endian byte count. * * The data follows for a burst write operation. * * The first packet of a burst read reply contains: * * 4 bytes of little-endian result code: * 0: No error * 1: Initial error * 2: I/O error * 3: No data read; * * 4 bytes of returned byte count (big-endian?). * * The data follows. * * Each burst of a write request is responded to with a * burst packet with a 2-byte little-endian result code: * * 0: Write successful * 4: Write error */ flags = tvb_get_guint8(tvb, commhdr + 2); ti = proto_tree_add_uint(ncp_tree, hf_ncp_system_flags, tvb, commhdr + 2, 1, flags); flags_tree = proto_item_add_subtree(ti, ett_ncp_system_flags); proto_tree_add_item(flags_tree, hf_ncp_system_flags_abt, tvb, commhdr + 2, 1, FALSE); if (flags & ABT) { proto_item_append_text(ti, " ABT"); } flags&=(~( ABT )); proto_tree_add_item(flags_tree, hf_ncp_system_flags_bsy, tvb, commhdr + 2, 1, FALSE); if (flags & BSY) { proto_item_append_text(ti, " BSY"); } flags&=(~( BSY )); proto_tree_add_item(flags_tree, hf_ncp_system_flags_eob, tvb, commhdr + 2, 1, FALSE); if (flags & EOB) { proto_item_append_text(ti, " EOB"); } flags&=(~( EOB )); proto_tree_add_item(flags_tree, hf_ncp_system_flags_lst, tvb, commhdr + 2, 1, FALSE); if (flags & LST) { proto_item_append_text(ti, " LST"); } flags&=(~( LST )); proto_tree_add_item(flags_tree, hf_ncp_system_flags_sys, tvb, commhdr + 2, 1, FALSE); if (flags & SYS) { proto_item_append_text(ti, " SYS"); } flags&=(~( SYS )); proto_tree_add_item(ncp_tree, hf_ncp_stream_type, tvb, commhdr + 3, 1, FALSE); proto_tree_add_item(ncp_tree, hf_ncp_src_connection, tvb, commhdr + 4, 4, FALSE); proto_tree_add_item(ncp_tree, hf_ncp_dst_connection, tvb, commhdr + 8, 4, FALSE); proto_tree_add_item(ncp_tree, hf_ncp_packet_seqno, tvb, commhdr + 12, 4, FALSE); proto_tree_add_item(ncp_tree, hf_ncp_delay_time, tvb, commhdr + 16, 4, FALSE); ncp_burst_seqno = tvb_get_ntohs(tvb, commhdr+20); proto_tree_add_item(ncp_tree, hf_ncp_burst_seqno, tvb, commhdr + 20, 2, FALSE); ncp_ack_seqno = tvb_get_ntohs(tvb, commhdr+22); proto_tree_add_item(ncp_tree, hf_ncp_ack_seqno, tvb, commhdr + 22, 2, FALSE); proto_tree_add_item(ncp_tree, hf_ncp_burst_len, tvb, commhdr + 24, 4, FALSE); data_offset = tvb_get_ntohl(tvb, commhdr + 28); proto_tree_add_uint(ncp_tree, hf_ncp_data_offset, tvb, commhdr + 28, 4, data_offset); data_len = tvb_get_ntohs(tvb, commhdr + 32); proto_tree_add_uint(ncp_tree, hf_ncp_data_bytes, tvb, commhdr + 32, 2, data_len); missing_fraglist_count = tvb_get_ntohs(tvb, commhdr + 34); proto_tree_add_item(ncp_tree, hf_ncp_missing_fraglist_count, tvb, commhdr + 34, 2, FALSE); offset = commhdr + 36; if (!(flags & SYS) && ncp_burst_seqno == ncp_ack_seqno && data_offset == 0) { /* * This is either a Burst Read or Burst Write * command. The data length includes the burst * mode header, plus any data in the command * (there shouldn't be any in a read, but there * might be some in a write). */ if (data_len < 4) return; ncp_burst_command = tvb_get_ntohl(tvb, offset); proto_tree_add_item(ncp_tree, hf_ncp_burst_command, tvb, offset, 4, FALSE); offset += 4; data_len -= 4; if (data_len < 4) return; burst_file = tvb_get_ntohl(tvb, offset); proto_tree_add_item(ncp_tree, hf_ncp_burst_file_handle, tvb, offset, 4, FALSE); offset += 4; data_len -= 4; if (data_len < 8) return; proto_tree_add_item(ncp_tree, hf_ncp_burst_reserved, tvb, offset, 8, FALSE); offset += 8; data_len -= 8; if (data_len < 4) return; burst_off = tvb_get_ntohl(tvb, offset); proto_tree_add_uint(ncp_tree, hf_ncp_burst_offset, tvb, offset, 4, burst_off); offset += 4; data_len -= 4; if (data_len < 4) return; burst_len = tvb_get_ntohl(tvb, offset); proto_tree_add_uint(ncp_tree, hf_ncp_burst_len, tvb, offset, 4, burst_len); offset += 4; data_len -= 4; if (check_col(pinfo->cinfo, COL_INFO)) { col_add_fstr(pinfo->cinfo, COL_INFO, "%s %d bytes starting at offset %d in file 0x%08x", val_to_str(ncp_burst_command, burst_command, "Unknown (0x%08x)"), burst_len, burst_off, burst_file); } break; } else { if (tvb_get_guint8(tvb, commhdr + 2) & 0x10) { col_set_str(pinfo->cinfo, COL_INFO, "End of Burst"); } } break; case NCP_ALLOCATE_SLOT: /* Allocate Slot Request */ length_remaining = tvb_length_remaining(tvb, commhdr + 4); if (length_remaining > 4) { testvar = tvb_get_ntohl(tvb, commhdr+4); if (testvar == 0x4c495020) { proto_tree_add_item(ncp_tree, hf_lip_echo, tvb, commhdr+4, 13, FALSE); break; } } /* otherwise fall through */ case NCP_POSITIVE_ACK: /* Positive Acknowledgement */ case NCP_SERVICE_REQUEST: /* Server NCP Request */ case NCP_SERVICE_REPLY: /* Server NCP Reply */ case NCP_WATCHDOG: /* Watchdog Packet */ case NCP_DEALLOCATE_SLOT: /* Deallocate Slot Request */ default: proto_tree_add_uint(ncp_tree, hf_ncp_seq, tvb, commhdr + 2, 1, header.sequence); proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection); proto_tree_add_item(ncp_tree, hf_ncp_task, tvb, commhdr + 4, 1, FALSE); break; } /* * Process the packet body. */ switch (header.type) { case NCP_ALLOCATE_SLOT: /* Allocate Slot Request */ length_remaining = tvb_length_remaining(tvb, commhdr + 4); if (length_remaining > 4) { testvar = tvb_get_ntohl(tvb, commhdr+4); if (testvar == 0x4c495020) { proto_tree_add_text(ncp_tree, tvb, commhdr, -1, "Lip Echo Packet"); /*break;*/ } } next_tvb = tvb_new_subset_remaining(tvb, commhdr); dissect_ncp_request(next_tvb, pinfo, nw_connection, header.sequence, header.type, ncp_tree); break; case NCP_DEALLOCATE_SLOT: /* Deallocate Slot Request */ next_tvb = tvb_new_subset_remaining(tvb, commhdr); dissect_ncp_request(next_tvb, pinfo, nw_connection, header.sequence, header.type, ncp_tree); break; case NCP_SERVICE_REQUEST: /* Server NCP Request */ case NCP_BROADCAST_SLOT: /* Server Broadcast Packet */ next_tvb = tvb_new_subset_remaining(tvb, commhdr); if (tvb_get_guint8(tvb, commhdr+6) == 0x68) { subfunction = tvb_get_guint8(tvb, commhdr+7); switch (subfunction) { case 0x02: /* NDS Frag Packet to decode */ dissect_nds_request(next_tvb, pinfo, nw_connection, header.sequence, header.type, ncp_tree); break; case 0x01: /* NDS Ping */ dissect_ping_req(next_tvb, pinfo, nw_connection, header.sequence, header.type, ncp_tree); break; default: dissect_ncp_request(next_tvb, pinfo, nw_connection, header.sequence, header.type, ncp_tree); break; } } else { dissect_ncp_request(next_tvb, pinfo, nw_connection, header.sequence, header.type, ncp_tree); } break; case NCP_SERVICE_REPLY: /* Server NCP Reply */ next_tvb = tvb_new_subset_remaining(tvb, commhdr); nds_defrag(next_tvb, pinfo, nw_connection, header.sequence, header.type, ncp_tree, &ncp_tap); break; case NCP_POSITIVE_ACK: /* Positive Acknowledgement */ /* * XXX - this used to call "nds_defrag()", which would * clear out "frags". Was that the right thing to * do? */ next_tvb = tvb_new_subset_remaining(tvb, commhdr); dissect_ncp_reply(next_tvb, pinfo, nw_connection, header.sequence, header.type, ncp_tree, &ncp_tap); break; case NCP_WATCHDOG: /* Watchdog Packet */ /* * XXX - should the completion code be interpreted as * it is in "packet-ncp2222.inc"? If so, this * packet should be handled by "dissect_ncp_reply()". */ proto_tree_add_item(ncp_tree, hf_ncp_completion_code, tvb, commhdr + 6, 1, TRUE); proto_tree_add_item(ncp_tree, hf_ncp_connection_status, tvb, commhdr + 7, 1, TRUE); proto_tree_add_item(ncp_tree, hf_ncp_slot, tvb, commhdr + 8, 1, TRUE); proto_tree_add_item(ncp_tree, hf_ncp_control_code, tvb, commhdr + 9, 1, TRUE); /* * Display the rest of the packet as data. */ if (tvb_offset_exists(tvb, commhdr + 10)) { call_dissector(data_handle, tvb_new_subset_remaining(tvb, commhdr + 10), pinfo, ncp_tree); } break; case NCP_BURST_MODE_XFER: /* Packet Burst Packet */ if (flags & SYS) { /* * System packet; show missing fragments if there * are any. */ while (missing_fraglist_count != 0) { proto_tree_add_item(ncp_tree, hf_ncp_missing_data_offset, tvb, offset, 4, FALSE); offset += 4; proto_tree_add_item(ncp_tree, hf_ncp_missing_data_count, tvb, offset, 2, FALSE); offset += 2; missing_fraglist_count--; } } else { /* * XXX - do this by using -1 and -1 as the length * arguments to "tvb_new_subset()" and then calling * "tvb_set_reported_length()"? That'll throw an * exception if "data_len" goes past the reported * length of the packet, but that's arguably a * feature in this case. */ length_remaining = tvb_length_remaining(tvb, offset); if (length_remaining > data_len) length_remaining = data_len; if (data_len != 0) { call_dissector(data_handle, tvb_new_subset(tvb, offset, length_remaining, data_len), pinfo, ncp_tree); } } break; case NCP_LIP_ECHO: /* LIP Echo Packet */ proto_tree_add_text(ncp_tree, tvb, commhdr, -1, "Lip Echo Packet"); break; default: expert_item = proto_tree_add_text(ncp_tree, tvb, commhdr + 6, -1, "%s packets not supported yet", val_to_str(header.type, ncp_type_vals, "Unknown type (0x%04x)")); if (ncp_echo_err) { expert_add_info_format(pinfo, expert_item, PI_UNDECODED, PI_NOTE, "%s packets not supported yet", val_to_str(header.type, ncp_type_vals, "Unknown type (0x%04x)")); } break; } }
static void dissect_pw_cesopsn( tvbuff_t * tvb_original ,packet_info * pinfo ,proto_tree * tree ,pwc_demux_type_t demux) { const int encaps_size = 4; /*RTP header in encapsulation is not supported yet*/ gint packet_size; gint payload_size; gint padding_size; pwc_packet_properties_t properties; packet_size = tvb_reported_length_remaining(tvb_original, 0); /* * FIXME * "4" below should be replaced by something like "min_packet_size_this_dissector" * Also call to dissect_try_cw_first_nibble() should be moved before this block */ if (packet_size < 4) /* 4 is smallest size which may be sensible (for PWACH dissector) */ { if (tree) { proto_item *item; item = proto_tree_add_item(tree, proto, tvb_original, 0, -1, ENC_NA); expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR, "PW packet size (%d) is too small to carry sensible information" ,(int)packet_size); } if (check_col(pinfo->cinfo, COL_PROTOCOL)) { col_set_str(pinfo->cinfo, COL_PROTOCOL, shortname); } col_set_str(pinfo->cinfo, COL_INFO, "Malformed: PW packet is too small"); return; } switch (demux) { case PWC_DEMUX_MPLS: if (dissect_try_cw_first_nibble(tvb_original, pinfo, tree)) { return; } break; case PWC_DEMUX_UDP: break; default: DISSECTOR_ASSERT_NOT_REACHED(); return; } /* check how "good" is this packet */ /* also decide payload length from packet size and CW */ properties = PWC_PACKET_PROPERTIES_T_INITIALIZER; if (0 != (tvb_get_guint8(tvb_original, 0) & 0xf0 /*bits03*/)) { properties |= PWC_CW_BAD_BITS03; } if (0 != (tvb_get_guint8(tvb_original, 1) & 0xc0 /*frag*/)) { properties |= PWC_CW_BAD_FRAG; } { /* RFC5086: * [LEN (bits (10 to 15) MAY be used to carry the length of the CESoPSN * packet (defined as the size of the CESoPSN header + the payload size) * if it is less than 64 bytes, and MUST be set to zero otherwise. * Note: If fixed RTP header is used in the encapsulation, it is * considered part of the CESoPSN header.] * * Note that this differs from RFC4385's definition of length: * [ If the MPLS payload is less than 64 bytes, the length field * MUST be set to the length of the PW payload...] * * We will use RFC5086's definition here. */ int cw_len; gint payload_size_from_packet; cw_len = tvb_get_guint8(tvb_original, 1) & 0x3f; payload_size_from_packet = packet_size - encaps_size; if (cw_len != 0) { gint payload_size_from_cw; payload_size_from_cw = cw_len - encaps_size; /* * Assumptions for error case, * will be overwritten if no errors found: */ payload_size = payload_size_from_packet; padding_size = 0; if (payload_size_from_cw < 0) { properties |= PWC_CW_BAD_PAYLEN_LT_0; } else if (payload_size_from_cw > payload_size_from_packet) { properties |= PWC_CW_BAD_PAYLEN_GT_PACKET; } else if (payload_size_from_packet >= 64) { properties |= PWC_CW_BAD_LEN_MUST_BE_0; } else /* ok */ { payload_size = payload_size_from_cw; padding_size = payload_size_from_packet - payload_size_from_cw; /* >=0 */ } } else { payload_size = payload_size_from_packet; padding_size = 0; } } { guint8 cw_lm; cw_lm = tvb_get_guint8(tvb_original, 0) & 0x0b /*l+mod*/; if (NULL == match_strval(cw_lm, vals_cw_lm)) { properties |= PWC_CW_SUSPECT_LM; } { guint8 l_bit, m_bits; l_bit = (cw_lm & 0x08) >> 3; m_bits = (cw_lm & 0x03) >> 0; if ((l_bit == 0 && m_bits == 0x0) /*CESoPSN data packet - normal situation*/ ||(l_bit == 0 && m_bits == 0x2) /*CESoPSN data packet - RDI on the AC*/ ) { if ((payload_size == 0) || ((payload_size % 8) != 0)) { properties |= PWC_PAY_SIZE_BAD; } } else if (l_bit == 1 && m_bits == 0x0) /*TDM data is invalid; payload MAY be omitted*/ { /*allow any size of payload*/ } else /*reserved combinations*/ { /*allow any size of payload*/ } } } /* fill up columns*/ if (check_col(pinfo->cinfo, COL_PROTOCOL)) { col_set_str(pinfo->cinfo, COL_PROTOCOL, shortname); } if (check_col(pinfo->cinfo, COL_INFO)) { col_clear(pinfo->cinfo, COL_INFO); if (properties & PWC_ANYOF_CW_BAD) { col_append_str(pinfo->cinfo, COL_INFO, "CW:Bad, "); } else if (properties & PWC_ANYOF_CW_SUSPECT) { col_append_str(pinfo->cinfo, COL_INFO, "CW:Suspect, "); } if (properties & PWC_PAY_SIZE_BAD) { col_append_str(pinfo->cinfo, COL_INFO, "Payload size:Bad, "); } col_append_fstr(pinfo->cinfo, COL_INFO, "TDM octets:%d", (int)payload_size); if (padding_size != 0) { col_append_fstr(pinfo->cinfo, COL_INFO, ", Padding:%d", (int)padding_size); } } { proto_item* item; item = proto_tree_add_item(tree, proto, tvb_original, 0, -1, ENC_NA); pwc_item_append_cw(item,tvb_get_ntohl(tvb_original, 0),TRUE); pwc_item_append_text_n_items(item,(int)payload_size,"octet"); { proto_tree* tree2; tree2 = proto_item_add_subtree(item, ett); { tvbuff_t* tvb; proto_item* item2; tvb = tvb_new_subset(tvb_original, 0, PWC_SIZEOF_CW, PWC_SIZEOF_CW); item2 = proto_tree_add_item(tree2, hf_cw, tvb, 0, -1, ENC_NA); pwc_item_append_cw(item2,tvb_get_ntohl(tvb, 0),FALSE); { proto_tree* tree3; tree3 = proto_item_add_subtree(item, ett); { proto_item* item3; if (properties & PWC_CW_BAD_BITS03) /*display only if value is wrong*/ { item3 = proto_tree_add_item(tree3, hf_cw_bits03, tvb, 0, 1, ENC_BIG_ENDIAN); expert_add_info_format(pinfo, item3, PI_MALFORMED, PI_ERROR ,"Bits 0..3 of Control Word must be 0"); } item3 = proto_tree_add_item(tree3, hf_cw_lm, tvb, 0, 1, ENC_BIG_ENDIAN); if (properties & PWC_CW_SUSPECT_LM) { expert_add_info_format(pinfo, item3, PI_UNDECODED, PI_WARN ,"Reserved combination of L and Modifier bits"); } proto_tree_add_item(tree3, hf_cw_r, tvb, 0, 1, ENC_BIG_ENDIAN); item3 = proto_tree_add_item(tree3, hf_cw_frg, tvb, 1, 1, ENC_BIG_ENDIAN); if (properties & PWC_CW_BAD_FRAG) { expert_add_info_format(pinfo, item3, PI_MALFORMED, PI_ERROR ,"Fragmentation of payload is not allowed" " for basic CESoPSN mode"); } item3 = proto_tree_add_item(tree3, hf_cw_len, tvb, 1, 1, ENC_BIG_ENDIAN); if (properties & PWC_CW_BAD_PAYLEN_LT_0) { expert_add_info_format(pinfo, item3, PI_MALFORMED, PI_ERROR ,"Bad Length: too small, must be > %d" ,(int)encaps_size); } if (properties & PWC_CW_BAD_PAYLEN_GT_PACKET) { expert_add_info_format(pinfo, item3, PI_MALFORMED, PI_ERROR ,"Bad Length: must be <= than PSN packet size (%d)" ,(int)packet_size); } if (properties & PWC_CW_BAD_LEN_MUST_BE_0) { expert_add_info_format(pinfo, item3, PI_MALFORMED, PI_ERROR ,"Bad Length: must be 0 if CESoPSN packet size (%d) is > 64" ,(int)packet_size); } proto_tree_add_item(tree3, hf_cw_seq, tvb, 2, 2, ENC_BIG_ENDIAN); } } } } /* payload */ if (payload_size == 0) { if (properties & PWC_PAY_SIZE_BAD) { expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR ,"CESoPSN payload: none found. Size of payload must be <> 0"); } else { expert_add_info_format(pinfo, item, PI_UNDECODED, PI_NOTE ,"CESoPSN payload: omitted to conserve bandwidth"); } } else { proto_tree* tree2; tree2 = proto_item_add_subtree(item, ett); { proto_item* item2; tvbuff_t* tvb; tvb = tvb_new_subset(tvb_original, PWC_SIZEOF_CW, payload_size, payload_size); item2 = proto_tree_add_item(tree2, hf_payload, tvb, 0, -1, ENC_NA); pwc_item_append_text_n_items(item2,(int)payload_size,"octet"); if (properties & PWC_PAY_SIZE_BAD) { expert_add_info_format(pinfo, item2, PI_MALFORMED, PI_ERROR ,"CESoPSN packet payload size must be multiple of 8"); } tree2 = proto_item_add_subtree(item2, ett); call_dissector(data_handle, tvb, pinfo, tree2); item2 = proto_tree_add_int(tree2, hf_payload_l, tvb, 0, 0 ,(int)payload_size); /* allow filtering */ PROTO_ITEM_SET_HIDDEN(item2); } } /* padding */ if (padding_size > 0) { proto_tree* tree2; tree2 = proto_item_add_subtree(item, ett); { tvbuff_t* tvb; tvb = tvb_new_subset(tvb_original, PWC_SIZEOF_CW + payload_size, padding_size, -1); call_dissector(pw_padding_handle, tvb, pinfo, tree2); } } } return; }
guint16 dissect_cbs_message_identifier(tvbuff_t *tvb, proto_tree *tree, guint16 offset) { guint16 msg_id; const char *msg_id_string = NULL; msg_id = tvb_get_ntohs(tvb, offset); msg_id_string = match_strval(msg_id, message_id_values); if (msg_id_string == NULL) { if (msg_id < 1000) { msg_id_string = "Message ID to be allocated by GSMA"; } else if (msg_id < 4096) { msg_id_string = "Message ID intended for standardization in future versions of 3GPP TS 23.041"; } else if (msg_id < 4224) { msg_id_string = "Message ID reserved for Cell Broadcast Data Download (unsecured) to the SIM "; } else if (msg_id < 4352) { msg_id_string = "Message ID reserved for Cell Broadcast Data Download (secured) to the SIM "; } else if (msg_id < 4360) { msg_id_string = "ETWS CBS Message Identifier for future extension"; } else if (msg_id < 4400) { msg_id_string = "CMAS CBS Message Identifier for future extension"; } else if (msg_id < 6400) { msg_id_string = "CBS Message Identifier for future PWS use"; } else if (msg_id < 40960) { msg_id_string = "Intended for standardization in future versions of 3GPP TS 23.041"; } else if (msg_id < 43500) { msg_id_string = "Message ID in PLMN operator specific range"; } else if (msg_id < 43530) { msg_id_string = "Traffic Information Traffic Master UK"; } else if (msg_id < 43585) { msg_id_string = "Traffic information Mannesmann Telecommerce"; } else if (msg_id < 45056) { msg_id_string = "Message ID in PLMN operator specific range"; } else { msg_id_string = "Message ID intended as PLMN operator specific range in future versions of 3GPP TS 23.041"; } } proto_tree_add_uint_format_value(tree, hf_gsm_cbs_message_identifier, tvb, offset, 2, msg_id, "%s (%d)", msg_id_string, msg_id); return 2; }
static int dissect_bvlc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_item *ti; proto_item *ti_bdt; proto_item *ti_fdt; proto_tree *bvlc_tree; proto_tree *bdt_tree; /* Broadcast Distribution Table */ proto_tree *fdt_tree; /* Foreign Device Table */ gint offset; guint8 bvlc_type; guint8 bvlc_function; guint16 bvlc_length; guint16 packet_length; guint npdu_length; guint length_remaining; guint16 bvlc_result; tvbuff_t *next_tvb; offset = 0; bvlc_type = tvb_get_guint8(tvb, offset); /* * Simple sanity check - make sure the type is one we know about. */ if (match_strval(bvlc_type, bvlc_types) == NULL) return 0; col_set_str(pinfo->cinfo, COL_PROTOCOL, "BVLC"); col_set_str(pinfo->cinfo, COL_INFO, "BACnet Virtual Link Control"); bvlc_function = tvb_get_guint8(tvb, offset+1); packet_length = tvb_get_ntohs(tvb, offset+2); length_remaining = tvb_reported_length_remaining(tvb, offset); if (bvlc_function > 0x08) { /* We have a constant header length of BVLC of 4 in every * BVLC-packet forewarding an NPDU. Beware: Changes in the * BACnet-IP-standard may break this. * At the moment, no functions above 0x0b * exist (Addendum 135a to ANSI/ASHRAE 135-1995 - BACnet) */ bvlc_length = 4; } else if(bvlc_function == 0x04) { /* 4 Bytes + 6 Bytes for B/IP Address of Originating Device */ bvlc_length = 10; } else { /* BVLC-packets with function below 0x09 contain * routing-level data (e.g. Broadcast Distribution) * but no NPDU for BACnet, so bvlc_length goes up to the end * of the captured frame. */ bvlc_length = packet_length; } if (tree) { if (bvlc_length < 4) { proto_tree_add_text(tree, tvb, 2, 2, "Bogus length: %d", bvlc_length); return tvb_reported_length(tvb); /* XXX - reject? */ } ti = proto_tree_add_item(tree, proto_bvlc, tvb, 0, bvlc_length, ENC_NA); bvlc_tree = proto_item_add_subtree(ti, ett_bvlc); proto_tree_add_uint(bvlc_tree, hf_bvlc_type, tvb, offset, 1, bvlc_type); offset ++; proto_tree_add_uint(bvlc_tree, hf_bvlc_function, tvb, offset, 1, bvlc_function); offset ++; if (length_remaining != packet_length) proto_tree_add_uint_format_value(bvlc_tree, hf_bvlc_length, tvb, offset, 2, bvlc_length, "%d of %d bytes (invalid length - expected %d bytes)", bvlc_length, packet_length, length_remaining); else proto_tree_add_uint_format_value(bvlc_tree, hf_bvlc_length, tvb, offset, 2, bvlc_length, "%d of %d bytes BACnet packet length", bvlc_length, packet_length); offset += 2; switch (bvlc_function) { case 0x00: /* BVLC-Result */ bvlc_result = tvb_get_ntohs(tvb, offset); /* I dont know why the result code is encoded in 4 nibbles, * but only using one: 0x00r0. Shifting left 4 bits. */ /* We should bitmask the result correctly when we have a * packet to dissect, see README.developer, 1.6.2, FID */ proto_tree_add_uint_format_value(bvlc_tree, hf_bvlc_result, tvb, offset, 2, bvlc_result,"0x%04x (%s)", bvlc_result, val_to_str(bvlc_result, bvlc_result_names, "Unknown")); offset += 2; break; case 0x01: /* Write-Broadcast-Distribution-Table */ case 0x03: /* Read-Broadcast-Distribution-Table-Ack */ /* List of BDT Entries: N*10-octet */ ti_bdt = proto_tree_add_item(bvlc_tree, proto_bvlc, tvb, offset, bvlc_length-4, ENC_NA); bdt_tree = proto_item_add_subtree(ti_bdt, ett_bdt); /* List of BDT Entries: N*10-octet */ while ((bvlc_length - offset) > 9) { proto_tree_add_item(bdt_tree, hf_bvlc_bdt_ip, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item(bdt_tree, hf_bvlc_bdt_port, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(bdt_tree, hf_bvlc_bdt_mask, tvb, offset, 4, ENC_NA); offset += 4; } /* We check this if we get a BDT-packet somewhere */ break; case 0x02: /* Read-Broadcast-Distribution-Table */ /* nothing to do here */ break; case 0x05: /* Register-Foreign-Device */ /* Time-to-Live 2-octets T, Time-to-Live T, in seconds */ proto_tree_add_item(bvlc_tree, hf_bvlc_reg_ttl, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; break; case 0x06: /* Read-Foreign-Device-Table */ /* nothing to do here */ break; case 0x07: /* Read-Foreign-Device-Table-Ack */ /* List of FDT Entries: N*10-octet */ /* N indicates the number of entries in the FDT whose * contents are being returned. Each returned entry * consists of the 6-octet B/IP address of the registrant; * the 2-octet Time-to-Live value supplied at the time of * registration; and a 2-octet value representing the * number of seconds remaining before the BBMD will purge * the registrant's FDT entry if no re-registration occurs. */ ti_fdt = proto_tree_add_item(bvlc_tree, proto_bvlc, tvb, offset, bvlc_length -4, ENC_NA); fdt_tree = proto_item_add_subtree(ti_fdt, ett_fdt); /* List of FDT Entries: N*10-octet */ while ((bvlc_length - offset) > 9) { proto_tree_add_item(fdt_tree, hf_bvlc_fdt_ip, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item(fdt_tree, hf_bvlc_fdt_port, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(fdt_tree, hf_bvlc_fdt_ttl, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(fdt_tree, hf_bvlc_fdt_timeout, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; } /* We check this if we get a FDT-packet somewhere */ break; case 0x08: /* Delete-Foreign-Device-Table-Entry */ /* FDT Entry: 6-octets */ proto_tree_add_item(bvlc_tree, hf_bvlc_fdt_ip, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item(bvlc_tree, hf_bvlc_fdt_port, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; break; /* We check this if we get a FDT-packet somewhere */ case 0x04: /* Forwarded-NPDU * Why is this 0x04? It would have been a better * idea to append all forewarded NPDUs at the * end of the function table in the B/IP-standard! */ /* proto_tree_add_bytes_format(); */ proto_tree_add_item(bvlc_tree, hf_bvlc_fwd_ip, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item(bvlc_tree, hf_bvlc_fwd_port, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; default:/* Distribute-Broadcast-To-Network * Original-Unicast-NPDU * Original-Broadcast-NPDU * Going to the next dissector... */ break; } } /* Ok, no routing information BVLC packet. Dissect as * BACnet NPDU */ npdu_length = packet_length - bvlc_length; next_tvb = tvb_new_subset(tvb,bvlc_length,-1,npdu_length); /* Code from Guy Harris */ if (!dissector_try_uint(bvlc_dissector_table, bvlc_function, next_tvb, pinfo, tree)) { /* Unknown function - dissect the paylod as data */ call_dissector(data_handle,next_tvb, pinfo, tree); } return tvb_reported_length(tvb); }
/* Code to actually dissect the packets */ static int dissect_mbtcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { /* Set up structures needed to add the protocol subtree and manage it */ mbtcp_hdr mh; proto_item *mi, *mf; proto_tree *mbtcp_tree, *modbus_tree, *group_tree; int offset, group_offset, packet_type; guint i; gint packet_len, payload_start, payload_len; const char *func_string = ""; const char *pkt_type_str = ""; const char *err_str = ""; guint32 byte_cnt, group_byte_cnt, group_word_cnt; guint32 packet_num; /* num to uniquely identify different mbtcp * packets in one packet */ guint8 exception_code; gboolean exception_returned; guint8 fc; mh.transaction_id = tvb_get_ntohs(tvb, 0); mh.protocol_id = tvb_get_ntohs(tvb, 2); mh.len = tvb_get_ntohs(tvb, 4); mh.mdbs_hdr.unit_id = tvb_get_guint8(tvb, 6); mh.mdbs_hdr.function_code = tvb_get_guint8(tvb, 7); /* check that it actually looks like Modbus/TCP */ /* protocol id == 0 */ if( mh.protocol_id != 0 ){ return 0; } /* length is at least 2 (unit_id + function_code) */ if( mh.len < 2 ){ return 0; } /* function code is in the set 1-24, 40, 125-127. * Note that function code is only 7 bits. */ fc=mh.mdbs_hdr.function_code&0x7f; if(!match_strval(fc, function_code_vals)) return 0; /* Make entries in Protocol column on summary display */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "Modbus/TCP"); col_clear(pinfo->cinfo, COL_INFO); /* Make entries in Info column on summary display */ offset = 0; if ( mh.mdbs_hdr.function_code & 0x80 ) { exception_code = tvb_get_guint8(tvb, offset + sizeof(mbtcp_hdr)); mh.mdbs_hdr.function_code ^= 0x80; exception_returned = TRUE; } else { exception_code = 0; exception_returned = FALSE; } func_string = val_to_str(mh.mdbs_hdr.function_code, function_code_vals, "Unknown function (%u)"); if (check_col(pinfo->cinfo, COL_INFO)) { packet_type = classify_packet(pinfo); switch ( packet_type ) { case QUERY_PACKET : pkt_type_str="query"; break; case RESPONSE_PACKET : pkt_type_str="response"; break; case CANNOT_CLASSIFY : err_str="Unable to classify as query or response."; pkt_type_str="unknown"; break; default : break; } if ( exception_returned ) err_str="Exception returned "; col_add_fstr(pinfo->cinfo, COL_INFO, "%8s [%2u pkt(s)]: trans: %5u; unit: %3u, func: %3u: %s. %s", pkt_type_str, 1, mh.transaction_id, (unsigned char) mh.mdbs_hdr.unit_id, (unsigned char) mh.mdbs_hdr.function_code, func_string, err_str); } /* build up protocol tree and iterate over multiple packets */ packet_num = 0; while (1) { packet_type = classify_packet(pinfo); packet_len = sizeof(mbtcp_hdr) - sizeof(modbus_hdr) + mh.len; /* if a tree exists, perform operations to add fields to it */ if (tree) { mi = proto_tree_add_protocol_format(tree, proto_mbtcp, tvb, offset, packet_len, "Modbus/TCP"); mbtcp_tree = proto_item_add_subtree(mi, ett_mbtcp); /* Add items to protocol tree specific to Modbus/TCP */ proto_tree_add_uint(mbtcp_tree, hf_mbtcp_transid, tvb, offset, 2, mh.transaction_id); proto_tree_add_uint(mbtcp_tree, hf_mbtcp_protid, tvb, offset + 2, 2, mh.protocol_id); proto_tree_add_uint(mbtcp_tree, hf_mbtcp_len, tvb, offset + 4, 2, mh.len); proto_tree_add_uint(mbtcp_tree, hf_mbtcp_unitid, tvb, offset + 6, 1, mh.mdbs_hdr.unit_id); /* Add items to protocol tree specific to Modbus generic */ mf = proto_tree_add_text(mbtcp_tree, tvb, offset + 7, mh.len - 1, "Modbus"); modbus_tree = proto_item_add_subtree(mf, ett_modbus_hdr); mi = proto_tree_add_uint(modbus_tree, hf_mbtcp_functioncode, tvb, offset + 7, 1, mh.mdbs_hdr.function_code); /** detail payload as a function of exception/function code */ func_string = val_to_str(mh.mdbs_hdr.function_code, function_code_vals, "Unknown function"); payload_start = offset + 8; payload_len = mh.len - sizeof(modbus_hdr); if (exception_returned) { proto_item_set_text(mi, "function %u: %s. Exception: %s", mh.mdbs_hdr.function_code, func_string, val_to_str(exception_code, exception_code_vals, "Unknown exception code (%u)")); proto_tree_add_uint(modbus_tree, hf_modbus_exceptioncode, tvb, payload_start, 1, exception_code); } else { proto_item_set_text(mi, "function %u: %s", mh.mdbs_hdr.function_code, func_string); switch (mh.mdbs_hdr.function_code) { case READ_COILS: case READ_INPUT_DISCRETES: if (packet_type == QUERY_PACKET) { proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE); proto_tree_add_item(modbus_tree, hf_modbus_bitcnt, tvb, payload_start + 2, 2, FALSE); } else if (packet_type == RESPONSE_PACKET) { byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start); proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start, 1, byte_cnt); proto_tree_add_text(modbus_tree, tvb, payload_start + 1, byte_cnt, "Data"); } break; case READ_MULT_REGS: case READ_INPUT_REGS: if (packet_type == QUERY_PACKET) { proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE); proto_tree_add_item(modbus_tree, hf_modbus_wordcnt, tvb, payload_start + 2, 2, FALSE); } else if (packet_type == RESPONSE_PACKET) { byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start); proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start, 1, byte_cnt); proto_tree_add_text(modbus_tree, tvb, payload_start + 1, byte_cnt, "Data"); } break; case WRITE_COIL: if (packet_type == QUERY_PACKET) { proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE); proto_tree_add_text(modbus_tree, tvb, payload_start + 2, 1, "Data"); proto_tree_add_text(modbus_tree, tvb, payload_start + 3, 1, "Padding"); } else if (packet_type == RESPONSE_PACKET) { proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE); proto_tree_add_text(modbus_tree, tvb, payload_start + 2, 1, "Data"); proto_tree_add_text(modbus_tree, tvb, payload_start + 3, 1, "Padding"); } break; case WRITE_SINGLE_REG: if (packet_type == QUERY_PACKET) { proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE); proto_tree_add_text(modbus_tree, tvb, payload_start + 2, 2, "Data"); } else if (packet_type == RESPONSE_PACKET) { proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE); proto_tree_add_text(modbus_tree, tvb, payload_start + 2, 2, "Data"); } break; case READ_EXCEPT_STAT: if (packet_type == RESPONSE_PACKET) proto_tree_add_text(modbus_tree, tvb, payload_start, 1, "Data"); break; case FORCE_MULT_COILS: if (packet_type == QUERY_PACKET) { proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE); proto_tree_add_item(modbus_tree, hf_modbus_bitcnt, tvb, payload_start + 2, 2, FALSE); byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start + 4); proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start + 4, 1, byte_cnt); proto_tree_add_text(modbus_tree, tvb, payload_start + 5, byte_cnt, "Data"); } else if (packet_type == RESPONSE_PACKET) { proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE); proto_tree_add_item(modbus_tree, hf_modbus_bitcnt, tvb, payload_start + 2, 2, FALSE); } break; case WRITE_MULT_REGS: if (packet_type == QUERY_PACKET) { proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE); proto_tree_add_item(modbus_tree, hf_modbus_wordcnt, tvb, payload_start + 2, 2, FALSE); byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start + 4); proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start + 4, 1, byte_cnt); proto_tree_add_text(modbus_tree, tvb, payload_start + 5, byte_cnt, "Data"); } else if (packet_type == RESPONSE_PACKET) { proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE); proto_tree_add_item(modbus_tree, hf_modbus_wordcnt, tvb, payload_start + 2, 2, FALSE); } break; case READ_GENL_REF: if (packet_type == QUERY_PACKET) { byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start); proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start, 1, byte_cnt); /* add subtrees to describe each group of packet */ group_offset = payload_start + 1; for (i = 0; i < byte_cnt / 7; i++) { mi = proto_tree_add_text( modbus_tree, tvb, group_offset, 7, "Group %u", i); group_tree = proto_item_add_subtree(mi, ett_group_hdr); proto_tree_add_item(group_tree, hf_modbus_reftype, tvb, group_offset, 1, FALSE); proto_tree_add_item(group_tree, hf_modbus_lreference, tvb, group_offset + 1, 4, FALSE); proto_tree_add_item(group_tree, hf_modbus_wordcnt, tvb, group_offset + 5, 2, FALSE); group_offset += 7; } } else if (packet_type == RESPONSE_PACKET) { byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start); proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start, 1, byte_cnt); /* add subtrees to describe each group of packet */ group_offset = payload_start + 1; i = 0; while (byte_cnt > 0) { group_byte_cnt = (guint32)tvb_get_guint8(tvb, group_offset); mi = proto_tree_add_text( modbus_tree, tvb, group_offset, group_byte_cnt + 1, "Group %u", i); group_tree = proto_item_add_subtree(mi, ett_group_hdr); proto_tree_add_uint(group_tree, hf_modbus_bytecnt, tvb, group_offset, 1, group_byte_cnt); proto_tree_add_item(group_tree, hf_modbus_reftype, tvb, group_offset + 1, 1, FALSE); proto_tree_add_text(group_tree, tvb, group_offset + 2, group_byte_cnt - 1, "Data"); group_offset += (group_byte_cnt + 1); byte_cnt -= (group_byte_cnt + 1); i++; } } break; case WRITE_GENL_REF: if ((packet_type == QUERY_PACKET) || (packet_type == RESPONSE_PACKET)) { byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start); proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start, 1, byte_cnt); /* add subtrees to describe each group of packet */ group_offset = payload_start + 1; i = 0; while (byte_cnt > 0) { group_word_cnt = tvb_get_ntohs(tvb, group_offset + 5); group_byte_cnt = (2 * group_word_cnt) + 7; mi = proto_tree_add_text( modbus_tree, tvb, group_offset, group_byte_cnt, "Group %u", i); group_tree = proto_item_add_subtree(mi, ett_group_hdr); proto_tree_add_item(group_tree, hf_modbus_reftype, tvb, group_offset, 1, FALSE); proto_tree_add_item(group_tree, hf_modbus_lreference, tvb, group_offset + 1, 4, FALSE); proto_tree_add_uint(group_tree, hf_modbus_wordcnt, tvb, group_offset + 5, 2, group_word_cnt); proto_tree_add_text(group_tree, tvb, group_offset + 7, group_byte_cnt - 7, "Data"); group_offset += group_byte_cnt; byte_cnt -= group_byte_cnt; i++; } } break; case MASK_WRITE_REG: if ((packet_type == QUERY_PACKET) || (packet_type == RESPONSE_PACKET)) { proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE); proto_tree_add_item(modbus_tree, hf_modbus_andmask, tvb, payload_start + 2, 2, FALSE); proto_tree_add_item(modbus_tree, hf_modbus_ormask, tvb, payload_start + 4, 2, FALSE); } break; case READ_WRITE_REG: if (packet_type == QUERY_PACKET) { proto_tree_add_item(modbus_tree, hf_modbus_readref, tvb, payload_start, 2, FALSE); proto_tree_add_item(modbus_tree, hf_modbus_readwordcnt, tvb, payload_start + 2, 2, FALSE); proto_tree_add_item(modbus_tree, hf_modbus_writeref, tvb, payload_start + 4, 2, FALSE); proto_tree_add_item(modbus_tree, hf_modbus_writewordcnt, tvb, payload_start + 6, 2, FALSE); byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start + 8); proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start + 8, 1, byte_cnt); proto_tree_add_text(modbus_tree, tvb, payload_start + 9, byte_cnt, "Data"); } else if (packet_type == RESPONSE_PACKET) { byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start); proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start, 1, byte_cnt); proto_tree_add_text(modbus_tree, tvb, payload_start + 1, byte_cnt, "Data"); } break; case READ_FIFO_QUEUE: if (packet_type == QUERY_PACKET) proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE); else if (packet_type == RESPONSE_PACKET) { byte_cnt = (guint32)tvb_get_ntohs(tvb, payload_start); proto_tree_add_uint(modbus_tree, hf_modbus_lbytecnt, tvb, payload_start, 2, byte_cnt); proto_tree_add_item(modbus_tree, hf_modbus_wordcnt, tvb, payload_start + 2, 2, FALSE); proto_tree_add_text(modbus_tree, tvb, payload_start + 4, byte_cnt - 2, "Data"); } break; case DIAGNOSTICS: case PROGRAM_484: case POLL_484: case GET_COMM_EVENT_CTRS: case GET_COMM_EVENT_LOG: case PROGRAM_584_984: case POLL_584_984: case REPORT_SLAVE_ID: case PROGRAM_884_U84: case RESET_COMM_LINK: case PROGRAM_CONCEPT: case FIRMWARE_REPLACE: case PROGRAM_584_984_2: case REPORT_LOCAL_ADDR_MB: /* these function codes are not part of the Modbus/TCP specification */ default: if (payload_len > 0) proto_tree_add_text(modbus_tree, tvb, payload_start, payload_len, "Data"); break; } } } /* move onto next packet (if there) */ offset += packet_len; packet_num++; if (tvb_reported_length_remaining(tvb, offset) > 0) { /* load header structure for next packet */ mh.transaction_id = tvb_get_ntohs(tvb, offset+0); mh.protocol_id = tvb_get_ntohs(tvb, offset+2); mh.len = tvb_get_ntohs(tvb, offset+4); mh.mdbs_hdr.unit_id = tvb_get_guint8(tvb, offset+6); mh.mdbs_hdr.function_code = tvb_get_guint8(tvb, offset+7); if ( mh.mdbs_hdr.function_code & 0x80 ) { exception_code = tvb_get_guint8(tvb, offset + sizeof(mbtcp_hdr)); mh.mdbs_hdr.function_code ^= 0x80; exception_returned = TRUE; } else exception_returned = FALSE; } else break; } return tvb_length(tvb); }
/* Code to actually dissect the packets */ static void dissect_cmpp_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { /* Set up structures needed to add the protocol subtree and manage it */ proto_item *ti; proto_tree *cmpp_tree; guint command_id; guint tvb_len; guint total_length; const gchar *command_str; /* Header command string */ /* Get the length of the PDU */ tvb_len = tvb_length(tvb); /* if the length of the tvb is shorder then the cmpp header length exit */ if (tvb_len < CMPP_FIX_HEADER_LENGTH) return; total_length = tvb_get_ntohl(tvb, 0); /* Get the pdu length */ command_id = tvb_get_ntohl(tvb, 4); /* get the pdu command id */ if (match_strval(command_id, vals_command_Id) == NULL) { /* Should never happen: we checked this in dissect_cmpp() */ return; } command_str = val_to_str(command_id, vals_command_Id, "(Unknown CMPP Operation 0x%08X)"); /* tvb has less data then the PDU Header status, return */ if (tvb_len < total_length) { /* Should never happen: TCP should have desegmented for us */ return; } /* Make entries in Protocol column and Info column on summary display */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "CMPP"); col_append_fstr(pinfo->cinfo, COL_INFO, "%s. ", command_str); if (tree) { ti = proto_tree_add_item(tree, proto_cmpp, tvb, 0, -1, ENC_NA); cmpp_tree = proto_item_add_subtree(ti, ett_cmpp); /* Add the fix header informations to the tree */ cmpp_uint4(cmpp_tree, tvb, hf_cmpp_Total_Length, 0); cmpp_uint4(cmpp_tree, tvb, hf_cmpp_Command_Id, 4); cmpp_uint4(cmpp_tree, tvb, hf_cmpp_Sequence_Id, 8); switch(command_id) { case CMPP_CONNECT: cmpp_connect(cmpp_tree, tvb); break; case CMPP_CONNECT_RESP: cmpp_connect_resp(cmpp_tree, tvb); break; /* CMPP_TERMINATE and CMPP_TERMINATE_RESP don't have msg body */ case CMPP_TERMINATE: case CMPP_TERMINATE_RESP: break; case CMPP_SUBMIT: cmpp_submit(cmpp_tree, tvb); break; case CMPP_SUBMIT_RESP: cmpp_submit_resp(cmpp_tree, tvb); break; case CMPP_DELIVER: cmpp_deliver(cmpp_tree, tvb); break; case CMPP_DELIVER_RESP: cmpp_deliver_resp(cmpp_tree, tvb); break; default: /* Implement the rest of the protocol here */ break; } } }
static int dissect_aodv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_item *ti = NULL; proto_tree *aodv_tree = NULL; gboolean is_ipv6; guint8 type; /* Make entries in Protocol column and Info column on summary display */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "AODV"); col_clear(pinfo->cinfo, COL_INFO); /* Is this running over IPv6? */ is_ipv6 = (pinfo->src.type == AT_IPv6); /* Check the type of AODV packet. */ type = tvb_get_guint8(tvb, 0); if (match_strval(type, type_vals) == NULL) { /* * We assume this is not an AODV packet. */ return 0; } col_add_str(pinfo->cinfo, COL_INFO, val_to_str(type, type_vals, "Unknown AODV Packet Type (%u)")); if (tree) { ti = proto_tree_add_protocol_format(tree, proto_aodv, tvb, 0, -1, "Ad hoc On-demand Distance Vector Routing Protocol, %s", val_to_str(type, type_vals, "Unknown AODV Packet Type (%u)")); aodv_tree = proto_item_add_subtree(ti, ett_aodv); proto_tree_add_uint(aodv_tree, hf_aodv_type, tvb, 0, 1, type); } switch (type) { case RREQ: dissect_aodv_rreq(tvb, pinfo, aodv_tree, ti, is_ipv6); break; case RREP: dissect_aodv_rrep(tvb, pinfo, aodv_tree, ti, is_ipv6); break; case RERR: dissect_aodv_rerr(tvb, pinfo, aodv_tree, is_ipv6); break; case RREP_ACK: break; case DRAFT_01_V6_RREQ: dissect_aodv_draft_01_v6_rreq(tvb, pinfo, aodv_tree, ti); break; case DRAFT_01_V6_RREP: dissect_aodv_draft_01_v6_rrep(tvb, pinfo, aodv_tree, ti); break; case DRAFT_01_V6_RERR: dissect_aodv_draft_01_v6_rerr(tvb, pinfo, aodv_tree); break; case DRAFT_01_V6_RREP_ACK: break; default: proto_tree_add_text(aodv_tree, tvb, 0, -1, "Unknown AODV Packet Type (%u)", type); } return tvb_length(tvb); }
static void dissect_aarp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { guint16 ar_hrd; guint16 ar_pro; guint8 ar_hln; guint8 ar_pln; guint16 ar_op; proto_tree *aarp_tree; proto_item *ti; const gchar *op_str; int sha_offset, spa_offset, tha_offset, tpa_offset; const guint8 *sha_val, *spa_val, *tha_val, *tpa_val; gchar *sha_str, *spa_str, *tha_str, *tpa_str; col_set_str(pinfo->cinfo, COL_PROTOCOL, "AARP"); col_clear(pinfo->cinfo, COL_INFO); ar_hrd = tvb_get_ntohs(tvb, AR_HRD); ar_pro = tvb_get_ntohs(tvb, AR_PRO); ar_hln = tvb_get_guint8(tvb, AR_HLN); ar_pln = tvb_get_guint8(tvb, AR_PLN); ar_op = tvb_get_ntohs(tvb, AR_OP); /* Get the offsets of the addresses. */ sha_offset = MIN_AARP_HEADER_SIZE; spa_offset = sha_offset + ar_hln; tha_offset = spa_offset + ar_pln; tpa_offset = tha_offset + ar_hln; /* Extract the addresses. */ sha_val = tvb_get_ptr(tvb, sha_offset, ar_hln); sha_str = aarphrdaddr_to_str(sha_val, ar_hln, ar_hrd); spa_val = tvb_get_ptr(tvb, spa_offset, ar_pln); spa_str = aarpproaddr_to_str(spa_val, ar_pln, ar_pro); tha_val = tvb_get_ptr(tvb, tha_offset, ar_hln); tha_str = aarphrdaddr_to_str(tha_val, ar_hln, ar_hrd); tpa_val = tvb_get_ptr(tvb, tpa_offset, ar_pln); tpa_str = aarpproaddr_to_str(tpa_val, ar_pln, ar_pro); switch (ar_op) { case AARP_REQUEST: case AARP_REQUEST_SWAPPED: col_add_fstr(pinfo->cinfo, COL_INFO, "Who has %s? Tell %s", tpa_str, spa_str); break; case AARP_REPLY: case AARP_REPLY_SWAPPED: col_add_fstr(pinfo->cinfo, COL_INFO, "%s is at %s", spa_str, sha_str); break; case AARP_PROBE: case AARP_PROBE_SWAPPED: col_add_fstr(pinfo->cinfo, COL_INFO, "Is there a %s", tpa_str); break; default: col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown AARP opcode 0x%04x", ar_op); break; } if (tree) { if ((op_str = match_strval(ar_op, op_vals))) ti = proto_tree_add_protocol_format(tree, proto_aarp, tvb, 0, MIN_AARP_HEADER_SIZE + 2*ar_hln + 2*ar_pln, "AppleTalk Address Resolution Protocol (%s)", op_str); else ti = proto_tree_add_protocol_format(tree, proto_aarp, tvb, 0, MIN_AARP_HEADER_SIZE + 2*ar_hln + 2*ar_pln, "AppleTalk Address Resolution Protocol (opcode 0x%04x)", ar_op); aarp_tree = proto_item_add_subtree(ti, ett_aarp); proto_tree_add_uint(aarp_tree, hf_aarp_hard_type, tvb, AR_HRD, 2, ar_hrd); proto_tree_add_uint(aarp_tree, hf_aarp_proto_type, tvb, AR_PRO, 2, ar_pro); proto_tree_add_uint(aarp_tree, hf_aarp_hard_size, tvb, AR_HLN, 1, ar_hln); proto_tree_add_uint(aarp_tree, hf_aarp_proto_size, tvb, AR_PLN, 1, ar_pln); proto_tree_add_uint(aarp_tree, hf_aarp_opcode, tvb, AR_OP, 2, ar_op); if (ar_hln != 0) { proto_tree_add_item(aarp_tree, AARP_HW_IS_ETHER(ar_hrd, ar_hln) ? hf_aarp_src_hw_mac : hf_aarp_src_hw, tvb, sha_offset, ar_hln, FALSE); } if (ar_pln != 0) { if (AARP_PRO_IS_ATALK(ar_pro, ar_pln)) { proto_tree_add_bytes_format_value(aarp_tree, hf_aarp_src_proto_id, tvb, spa_offset, ar_pln, spa_val, "%s", spa_str); } else { proto_tree_add_bytes_format_value(aarp_tree, hf_aarp_src_proto, tvb, spa_offset, ar_pln, spa_val, "%s", spa_str); } } if (ar_hln != 0) { proto_tree_add_item(aarp_tree, AARP_HW_IS_ETHER(ar_hrd, ar_hln) ? hf_aarp_dst_hw_mac : hf_aarp_dst_hw, tvb, tha_offset, ar_hln, FALSE); } if (ar_pln != 0) { if (AARP_PRO_IS_ATALK(ar_pro, ar_pln)) { proto_tree_add_bytes_format_value(aarp_tree, hf_aarp_dst_proto_id, tvb, tpa_offset, ar_pln, tpa_val, "%s", tpa_str); } else { proto_tree_add_bytes_format_value(aarp_tree, hf_aarp_dst_proto, tvb, tpa_offset, ar_pln, tpa_val, "%s", tpa_str); } } } }
static int dissect_slimp3(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { const char *opcode_str; proto_tree *slimp3_tree = NULL; proto_item *ti = NULL, *hidden_item; gint i1; gint offset = 0; guint16 opcode; guchar lcd_char; char lcd_str[MAX_LCD_STR_LEN + 1]; int to_server = FALSE; int old_protocol = FALSE; address tmp_addr; gboolean in_str; int lcd_strlen; /* * If it doesn't begin with a known opcode, reject it, so that * traffic that happens to be do or from one of our ports * doesn't get misidentified as SliMP3 traffic. */ if (!tvb_bytes_exist(tvb, offset, 1)) return 0; /* not even an opcode */ opcode = tvb_get_guint8(tvb, offset); opcode_str = match_strval(opcode, slimp3_opcode_vals); if (opcode_str == NULL) return 0; col_set_str(pinfo->cinfo, COL_PROTOCOL, "SliMP3"); if (check_col(pinfo->cinfo, COL_INFO)) { col_add_str(pinfo->cinfo, COL_INFO, opcode_str); } if (tree) { ti = proto_tree_add_item(tree, proto_slimp3, tvb, offset, -1, ENC_NA); slimp3_tree = proto_item_add_subtree(ti, ett_slimp3); proto_tree_add_uint(slimp3_tree, hf_slimp3_opcode, tvb, offset, 1, opcode); } /* The new protocol (v1.3 and later) uses an IANA-assigned port number. * It usually uses the same number for both sizes of the conversation, so * the port numbers can't always be used to determine client and server. * The new protocol places the clients MAC address in the packet, so that * is used to identify packets originating at the client. */ if ((pinfo->destport == UDP_PORT_SLIMP3_V2) && (pinfo->srcport == UDP_PORT_SLIMP3_V2)) { SET_ADDRESS(&tmp_addr, AT_ETHER, 6, tvb_get_ptr(tvb, offset+12, 6)); to_server = ADDRESSES_EQUAL(&tmp_addr, &pinfo->dl_src); } else if (pinfo->destport == UDP_PORT_SLIMP3_V2) { to_server = TRUE; } else if (pinfo->srcport == UDP_PORT_SLIMP3_V2) { to_server = FALSE; } if (pinfo->destport == UDP_PORT_SLIMP3_V1) { to_server = TRUE; old_protocol = TRUE; } else if (pinfo->srcport == UDP_PORT_SLIMP3_V1) { to_server = FALSE; old_protocol = TRUE; } switch (opcode) { case SLIMP3_IR: /* IR code * * [0] 'i' as in "IR" * [1] 0x00 * [2..5] player's time since startup in ticks @625 KHz * [6] IR code id, ff=JVC, 02=SLIMP3 * [7] number of meaningful bits - 16 for JVC, 32 for SLIMP3 * [8..11] the 32-bit IR code * [12..17] reserved */ if (tree) { hidden_item = proto_tree_add_item(slimp3_tree, hf_slimp3_ir, tvb, offset+8, 4, ENC_BIG_ENDIAN); PROTO_ITEM_SET_HIDDEN(hidden_item); i1 = tvb_get_ntohl(tvb, offset+2); proto_tree_add_text(slimp3_tree, tvb, offset+2, 4, "Uptime: %u sec (%u ticks)", i1/625000, i1); i1 = tvb_get_guint8(tvb, offset+6); proto_tree_add_text(slimp3_tree, tvb, offset+6, 1, "Code identifier: 0x%0x: %s", i1, val_to_str(i1, slimp3_ir_types, "Unknown")); proto_tree_add_text(slimp3_tree, tvb, offset+7, 1, "Code bits: %d", tvb_get_guint8(tvb, offset+7)); i1 = tvb_get_ntohl(tvb, offset+8); /* Check the code to figure out which remote is being used. */ if (tvb_get_guint8(tvb, offset+6) == 0x02 && tvb_get_guint8(tvb, offset+7) == 32) { /* This is the custom SLIMP3 remote. */ proto_tree_add_text(slimp3_tree, tvb, offset+8, 4, "Infrared Code: %s: 0x%0x", val_to_str(i1, slimp3_ir_codes_slimp3, "Unknown"), i1); } else if (tvb_get_guint8(tvb, offset+6) == 0xff && tvb_get_guint8(tvb, offset+7) == 16) { /* This is a JVC DVD player remote */ proto_tree_add_text(slimp3_tree, tvb, offset+8, 4, "Infrared Code: %s: 0x%0x", val_to_str(i1, slimp3_ir_codes_jvc, "Unknown"), i1); } else { /* Unknown code; just write it */ proto_tree_add_text(slimp3_tree, tvb, offset+8, 4, "Infrared Code: 0x%0x", i1); } } if (check_col(pinfo->cinfo, COL_INFO)) { i1 = tvb_get_ntohl(tvb, offset+8); if (tvb_get_guint8(tvb, offset+6) == 0x02 && tvb_get_guint8(tvb, offset+7) == 32) { col_append_fstr(pinfo->cinfo, COL_INFO, ", SLIMP3: %s", val_to_str(i1, slimp3_ir_codes_slimp3, "Unknown (0x%0x)")); } else if (tvb_get_guint8(tvb, offset+6) == 0xff && tvb_get_guint8(tvb, offset+7) == 16) { col_append_fstr(pinfo->cinfo, COL_INFO, ", JVC: %s", val_to_str(i1, slimp3_ir_codes_jvc, "Unknown (0x%0x)")); } else { /* Unknown code; just write it */ col_append_fstr(pinfo->cinfo, COL_INFO, ", 0x%0x", i1); } } break; case SLIMP3_DISPLAY: if (tree) { hidden_item = proto_tree_add_item(slimp3_tree, hf_slimp3_display, tvb, offset, 1, ENC_BIG_ENDIAN); PROTO_ITEM_SET_HIDDEN(hidden_item); /* Loop through the commands */ i1 = 18; in_str = FALSE; lcd_strlen = 0; while (i1 < tvb_reported_length_remaining(tvb, offset)) { switch(tvb_get_guint8(tvb, offset + i1)) { case 0: in_str = FALSE; lcd_strlen = 0; proto_tree_add_text(slimp3_tree, tvb, offset + i1, 2, "Delay (%d ms)", tvb_get_guint8(tvb, offset + i1 + 1)); i1 += 2; break; case 3: lcd_char = tvb_get_guint8(tvb, offset + i1 + 1); if (!isprint(lcd_char)) lcd_char = '.'; if (ti && in_str) { lcd_strlen += 2; proto_item_append_text(ti, "%c", lcd_char); proto_item_set_len(ti, lcd_strlen); } else { ti = proto_tree_add_text(slimp3_tree, tvb, offset + i1, 2, "String: %c", lcd_char); in_str = TRUE; lcd_strlen = 2; } i1 += 2; break; case 2: in_str = FALSE; lcd_strlen = 0; ti = proto_tree_add_text(slimp3_tree, tvb, offset + i1, 2, "Command: %s", val_to_str(tvb_get_guint8(tvb, offset + i1 + 1), slimp3_display_commands, "Unknown (0x%0x)")); if ((tvb_get_guint8(tvb, offset + i1 + 1) & 0xf0) == 0x30) { proto_item_append_text(ti, ": %s", val_to_str(tvb_get_guint8(tvb, offset + i1 + 2), slimp3_display_fset8, "Unknown (0x%0x)")); i1 += 2; } i1 += 2; break; default: proto_tree_add_text(slimp3_tree, tvb, offset + i1, 2, "Unknown 0x%0x, 0x%0x", tvb_get_guint8(tvb, offset + i1), tvb_get_guint8(tvb, offset + i1 + 1)); i1 += 2; break; } } } if (check_col(pinfo->cinfo, COL_INFO)) { i1 = 18; lcd_strlen = 0; while (tvb_offset_exists(tvb, offset + i1) && lcd_strlen < MAX_LCD_STR_LEN) { switch (tvb_get_guint8(tvb, offset + i1)) { case 0: lcd_str[lcd_strlen++] = '.'; break; case 2: lcd_str[lcd_strlen++] = '|'; if (tvb_offset_exists(tvb, offset + i1 + 1) && (tvb_get_guint8(tvb, offset + i1 + 1) & 0xf0) == 0x30) i1 += 2; break; case 3: if (tvb_offset_exists(tvb, offset + i1 + 1)) { if (lcd_strlen < 1 || lcd_str[lcd_strlen-1] != ' ' || tvb_get_guint8(tvb, offset + i1 + 1) != ' ') { lcd_char = tvb_get_guint8(tvb, offset + i1 + 1); lcd_str[lcd_strlen++] = isprint(lcd_char) ? lcd_char : '.'; } } } i1 += 2; } lcd_str[lcd_strlen] = '\0'; if (lcd_strlen > 0) col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", lcd_str); } break; case SLIMP3_CONTROL: if (tree) { hidden_item = proto_tree_add_item(slimp3_tree, hf_slimp3_control, tvb, offset+1, 1, ENC_BIG_ENDIAN); PROTO_ITEM_SET_HIDDEN(hidden_item); proto_tree_add_text(slimp3_tree, tvb, offset+1, 1, "Command: %s", val_to_str(tvb_get_guint8(tvb, offset+1), slimp3_stream_control, "Unknown (0x%0x)")); } if (check_col(pinfo->cinfo, COL_INFO)) { col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", val_to_str(tvb_get_guint8(tvb, offset+1), slimp3_stream_control, "Unknown (0x%0x)")); } break; case SLIMP3_HELLO: if (tree) { hidden_item = proto_tree_add_item(slimp3_tree, hf_slimp3_hello, tvb, offset+1, 1, ENC_BIG_ENDIAN); PROTO_ITEM_SET_HIDDEN(hidden_item); if (to_server) { guint8 fw_ver = 0; /* Hello response; client->server */ proto_tree_add_text(slimp3_tree, tvb, offset, 1, "Hello Response (Client --> Server)"); proto_tree_add_text(slimp3_tree, tvb, offset+1, 1, "Device ID: %d", tvb_get_guint8(tvb, offset+1)); fw_ver = tvb_get_guint8(tvb, offset+2); proto_tree_add_text(slimp3_tree, tvb, offset+2, 1, "Firmware Revision: %d.%d (0x%0x)", fw_ver>>4, fw_ver & 0xf, fw_ver); } else { /* Hello request; server->client */ proto_tree_add_text(slimp3_tree, tvb, offset, 1, "Hello Request (Server --> Client)"); } } break; case SLIMP3_I2C: if (tree) { hidden_item = proto_tree_add_item(slimp3_tree, hf_slimp3_i2c, tvb, offset, 1, ENC_BIG_ENDIAN); PROTO_ITEM_SET_HIDDEN(hidden_item); if (to_server) { /* Hello response; client->server */ proto_tree_add_text(slimp3_tree, tvb, offset, -1, "I2C Response (Client --> Server)"); } else { /* Hello request; server->client */ proto_tree_add_text(slimp3_tree, tvb, offset, -1, "I2C Request (Server --> Client)"); } } if (check_col(pinfo->cinfo, COL_INFO)) { if (to_server) { col_append_str(pinfo->cinfo, COL_INFO, ", Response"); } else { col_append_str(pinfo->cinfo, COL_INFO, ", Request"); } } break; case SLIMP3_DATA_REQ: if (tree) { hidden_item = proto_tree_add_item(slimp3_tree, hf_slimp3_data_request, tvb, offset, 1, ENC_BIG_ENDIAN); PROTO_ITEM_SET_HIDDEN(hidden_item); proto_tree_add_text(slimp3_tree, tvb, offset+2, 2, "Requested offset: %d bytes.", tvb_get_ntohs(tvb, offset+2)*2); } if (check_col(pinfo->cinfo, COL_INFO)) { col_append_fstr(pinfo->cinfo, COL_INFO, ", Offset: %d bytes", tvb_get_ntohs(tvb, offset+2)*2); } break; case SLIMP3_DATA: /* MPEG data (v1.3 and later) * * [0] 'm' * [1..5] reserved * [6..7] Write pointer (in words) * [8..9] reserved * [10..11] Sequence number * [12..17] reserved * [18..] MPEG data */ if (tree) { hidden_item = proto_tree_add_item(slimp3_tree, hf_slimp3_data, tvb, offset, 1, ENC_BIG_ENDIAN); PROTO_ITEM_SET_HIDDEN(hidden_item); if (old_protocol) { proto_tree_add_text(slimp3_tree, tvb, offset, -1, "Length: %d bytes", tvb_reported_length_remaining(tvb, offset+18)); proto_tree_add_text(slimp3_tree, tvb, offset+2, 2, "Buffer offset: %d bytes.", tvb_get_ntohs(tvb, offset+2) * 2); } else { proto_tree_add_text(slimp3_tree, tvb, offset+1, 1, "Command: %s", val_to_str(tvb_get_guint8(tvb, offset+1), slimp3_mpg_control, "Unknown (0x%0x)")); proto_tree_add_text(slimp3_tree, tvb, offset, -1, "Length: %d bytes", tvb_reported_length_remaining(tvb, offset+18)); proto_tree_add_text(slimp3_tree, tvb, offset+6, 2, "Write Pointer: %d", tvb_get_ntohs(tvb, offset+6) * 2); proto_tree_add_text(slimp3_tree, tvb, offset+10, 2, "Sequence: %d", tvb_get_ntohs(tvb, offset+10)); } } if (check_col(pinfo->cinfo, COL_INFO)) { if (old_protocol) { col_append_fstr(pinfo->cinfo, COL_INFO, ", Length: %d bytes, Offset: %d bytes.", tvb_reported_length_remaining(tvb, offset+18), tvb_get_ntohs(tvb, offset+2) * 2); } else { col_append_fstr(pinfo->cinfo, COL_INFO, ", %s, %d bytes at %d, Sequence: %d", val_to_str(tvb_get_guint8(tvb, offset+1), slimp3_mpg_control, "Unknown (0x%0x)"), tvb_reported_length_remaining(tvb, offset+18), tvb_get_ntohs(tvb, offset+6) * 2, tvb_get_ntohs(tvb, offset+10)); } } break; case SLIMP3_DISC_REQ: if (tree) { guint8 fw_ver; hidden_item = proto_tree_add_item(slimp3_tree, hf_slimp3_discover_request, tvb, offset, 1, ENC_BIG_ENDIAN); PROTO_ITEM_SET_HIDDEN(hidden_item); proto_tree_add_text(slimp3_tree, tvb, offset+1, 1, "Device ID: %d.", tvb_get_guint8(tvb, offset+1)); fw_ver = tvb_get_guint8(tvb, offset+2); proto_tree_add_text(slimp3_tree, tvb, offset+2, 1, "Firmware Revision: %d.%d (0x%0x)", fw_ver>>4, fw_ver & 0xf, fw_ver); } if (check_col(pinfo->cinfo, COL_INFO)) { guint8 fw_ver = tvb_get_guint8(tvb, offset+2); col_append_fstr(pinfo->cinfo, COL_INFO, ", Device ID: %d. Firmware: %d.%d", tvb_get_guint8(tvb, offset+1), fw_ver>>4, fw_ver & 0xf); }
/* * RFC 2225 ATMARP - it's just like ARP, except where it isn't. */ static void dissect_atmarp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { guint16 ar_hrd; guint16 ar_pro; guint8 ar_shtl; guint8 ar_shl; guint8 ar_sstl; guint8 ar_ssl; guint16 ar_op; guint8 ar_spln; guint8 ar_thtl; guint8 ar_thl; guint8 ar_tstl; guint8 ar_tsl; guint8 ar_tpln; int tot_len; proto_tree *arp_tree; proto_item *ti; const gchar *op_str; int sha_offset, ssa_offset, spa_offset; int tha_offset, tsa_offset, tpa_offset; const guint8 *sha_val, *ssa_val, *spa_val; const guint8 *tha_val, *tsa_val, *tpa_val; const gchar *sha_str, *ssa_str, *spa_str; const gchar *tha_str, *tsa_str, *tpa_str; proto_tree *tl_tree; proto_item *tl; /* Override the setting to "ARP/RARP". */ pinfo->current_proto = "ATMARP"; ar_hrd = tvb_get_ntohs(tvb, ATM_AR_HRD); ar_pro = tvb_get_ntohs(tvb, ATM_AR_PRO); ar_shtl = tvb_get_guint8(tvb, ATM_AR_SHTL); ar_shl = ar_shtl & ATMARP_LEN_MASK; ar_sstl = tvb_get_guint8(tvb, ATM_AR_SSTL); ar_ssl = ar_sstl & ATMARP_LEN_MASK; ar_op = tvb_get_ntohs(tvb, AR_OP); ar_spln = tvb_get_guint8(tvb, ATM_AR_SPLN); ar_thtl = tvb_get_guint8(tvb, ATM_AR_THTL); ar_thl = ar_thtl & ATMARP_LEN_MASK; ar_tstl = tvb_get_guint8(tvb, ATM_AR_TSTL); ar_tsl = ar_tstl & ATMARP_LEN_MASK; ar_tpln = tvb_get_guint8(tvb, ATM_AR_TPLN); tot_len = MIN_ATMARP_HEADER_SIZE + ar_shl + ar_ssl + ar_spln + ar_thl + ar_tsl + ar_tpln; /* Adjust the length of this tvbuff to include only the ARP datagram. Our caller may use that to determine how much of its packet was padding. */ tvb_set_reported_length(tvb, tot_len); /* Extract the addresses. */ sha_offset = MIN_ATMARP_HEADER_SIZE; if (ar_shl != 0) { sha_val = tvb_get_ptr(tvb, sha_offset, ar_shl); sha_str = atmarpnum_to_str(sha_val, ar_shtl); } else { sha_val = NULL; sha_str = "<No address>"; } ssa_offset = sha_offset + ar_shl; if (ar_ssl != 0) { ssa_val = tvb_get_ptr(tvb, ssa_offset, ar_ssl); ssa_str = atmarpsubaddr_to_str(ssa_val, ar_sstl); } else { ssa_val = NULL; ssa_str = NULL; } spa_offset = ssa_offset + ar_ssl; spa_val = tvb_get_ptr(tvb, spa_offset, ar_spln); spa_str = arpproaddr_to_str(spa_val, ar_spln, ar_pro); tha_offset = spa_offset + ar_spln; if (ar_thl != 0) { tha_val = tvb_get_ptr(tvb, tha_offset, ar_thl); tha_str = atmarpnum_to_str(tha_val, ar_thtl); } else { tha_val = NULL; tha_str = "<No address>"; } tsa_offset = tha_offset + ar_thl; if (ar_tsl != 0) { tsa_val = tvb_get_ptr(tvb, tsa_offset, ar_tsl); tsa_str = atmarpsubaddr_to_str(tsa_val, ar_tstl); } else { tsa_val = NULL; tsa_str = NULL; } tpa_offset = tsa_offset + ar_tsl; tpa_val = tvb_get_ptr(tvb, tpa_offset, ar_tpln); tpa_str = arpproaddr_to_str(tpa_val, ar_tpln, ar_pro); if (check_col(pinfo->cinfo, COL_PROTOCOL)) { switch (ar_op) { case ARPOP_REQUEST: case ARPOP_REPLY: case ATMARPOP_NAK: default: col_set_str(pinfo->cinfo, COL_PROTOCOL, "ATMARP"); break; case ARPOP_RREQUEST: case ARPOP_RREPLY: col_set_str(pinfo->cinfo, COL_PROTOCOL, "ATMRARP"); break; case ARPOP_IREQUEST: case ARPOP_IREPLY: col_set_str(pinfo->cinfo, COL_PROTOCOL, "Inverse ATMARP"); break; } } if (check_col(pinfo->cinfo, COL_INFO)) { switch (ar_op) { case ARPOP_REQUEST: col_add_fstr(pinfo->cinfo, COL_INFO, "Who has %s? Tell %s", tpa_str, spa_str); break; case ARPOP_REPLY: col_add_fstr(pinfo->cinfo, COL_INFO, "%s is at %s%s%s", spa_str, sha_str, ((ssa_str != NULL) ? "," : ""), ((ssa_str != NULL) ? ssa_str : "")); break; case ARPOP_IREQUEST: col_add_fstr(pinfo->cinfo, COL_INFO, "Who is %s%s%s? Tell %s%s%s", tha_str, ((tsa_str != NULL) ? "," : ""), ((tsa_str != NULL) ? tsa_str : ""), sha_str, ((ssa_str != NULL) ? "," : ""), ((ssa_str != NULL) ? ssa_str : "")); break; case ARPOP_IREPLY: col_add_fstr(pinfo->cinfo, COL_INFO, "%s%s%s is at %s", sha_str, ((ssa_str != NULL) ? "," : ""), ((ssa_str != NULL) ? ssa_str : ""), spa_str); break; case ATMARPOP_NAK: col_add_fstr(pinfo->cinfo, COL_INFO, "I don't know where %s is", spa_str); break; default: col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown ATMARP opcode 0x%04x", ar_op); break; } } if (tree) { if ((op_str = match_strval(ar_op, atmop_vals))) ti = proto_tree_add_protocol_format(tree, proto_arp, tvb, 0, tot_len, "ATM Address Resolution Protocol (%s)", op_str); else ti = proto_tree_add_protocol_format(tree, proto_arp, tvb, 0, tot_len, "ATM Address Resolution Protocol (opcode 0x%04x)", ar_op); arp_tree = proto_item_add_subtree(ti, ett_arp); proto_tree_add_uint(arp_tree, hf_arp_hard_type, tvb, ATM_AR_HRD, 2, ar_hrd); proto_tree_add_uint(arp_tree, hf_arp_proto_type, tvb, ATM_AR_PRO, 2,ar_pro); tl = proto_tree_add_text(arp_tree, tvb, ATM_AR_SHTL, 1, "Sender ATM number type/length: %s/%u", (ar_shtl & ATMARP_IS_E164 ? "E.164" : "ATM Forum NSAPA"), ar_shl); tl_tree = proto_item_add_subtree(tl, ett_atmarp_tl); proto_tree_add_boolean(tl_tree, hf_atmarp_sht, tvb, ATM_AR_SHTL, 1, ar_shtl); proto_tree_add_uint(tl_tree, hf_atmarp_shl, tvb, ATM_AR_SHTL, 1, ar_shtl); tl = proto_tree_add_text(arp_tree, tvb, ATM_AR_SSTL, 1, "Sender ATM subaddress type/length: %s/%u", (ar_sstl & ATMARP_IS_E164 ? "E.164" : "ATM Forum NSAPA"), ar_ssl); tl_tree = proto_item_add_subtree(tl, ett_atmarp_tl); proto_tree_add_boolean(tl_tree, hf_atmarp_sst, tvb, ATM_AR_SSTL, 1, ar_sstl); proto_tree_add_uint(tl_tree, hf_atmarp_ssl, tvb, ATM_AR_SSTL, 1, ar_sstl); proto_tree_add_uint(arp_tree, hf_arp_opcode, tvb, AR_OP, 2, ar_op); proto_tree_add_uint(arp_tree, hf_atmarp_spln, tvb, ATM_AR_SPLN, 1, ar_spln); tl = proto_tree_add_text(arp_tree, tvb, ATM_AR_THTL, 1, "Target ATM number type/length: %s/%u", (ar_thtl & ATMARP_IS_E164 ? "E.164" : "ATM Forum NSAPA"), ar_thl); tl_tree = proto_item_add_subtree(tl, ett_atmarp_tl); proto_tree_add_boolean(tl_tree, hf_atmarp_tht, tvb, ATM_AR_THTL, 1, ar_thtl); proto_tree_add_uint(tl_tree, hf_atmarp_thl, tvb, ATM_AR_THTL, 1, ar_thtl); tl = proto_tree_add_text(arp_tree, tvb, ATM_AR_TSTL, 1, "Target ATM subaddress type/length: %s/%u", (ar_tstl & ATMARP_IS_E164 ? "E.164" : "ATM Forum NSAPA"), ar_tsl); tl_tree = proto_item_add_subtree(tl, ett_atmarp_tl); proto_tree_add_boolean(tl_tree, hf_atmarp_tst, tvb, ATM_AR_TSTL, 1, ar_tstl); proto_tree_add_uint(tl_tree, hf_atmarp_tsl, tvb, ATM_AR_TSTL, 1, ar_tstl); proto_tree_add_uint(arp_tree, hf_atmarp_tpln, tvb, ATM_AR_TPLN, 1, ar_tpln); if (ar_shl != 0) dissect_atm_number(tvb, sha_offset, ar_shtl, hf_atmarp_src_atm_num_e164, hf_atmarp_src_atm_num_nsap, arp_tree); if (ar_ssl != 0) proto_tree_add_bytes_format(arp_tree, hf_atmarp_src_atm_subaddr, tvb, ssa_offset, ar_ssl, ssa_val, "Sender ATM subaddress: %s", ssa_str); if (ar_spln != 0) { proto_tree_add_item(arp_tree, ARP_PRO_IS_IPv4(ar_pro, ar_spln) ? hf_arp_src_proto_ipv4 : hf_arp_src_proto, tvb, spa_offset, ar_spln, FALSE); } if (ar_thl != 0) dissect_atm_number(tvb, tha_offset, ar_thtl, hf_atmarp_dst_atm_num_e164, hf_atmarp_dst_atm_num_nsap, arp_tree); if (ar_tsl != 0) proto_tree_add_bytes_format(arp_tree, hf_atmarp_dst_atm_subaddr, tvb, tsa_offset, ar_tsl, tsa_val, "Target ATM subaddress: %s", tsa_str); if (ar_tpln != 0) { proto_tree_add_item(arp_tree, ARP_PRO_IS_IPv4(ar_pro, ar_tpln) ? hf_arp_dst_proto_ipv4 : hf_arp_dst_proto, tvb, tpa_offset, ar_tpln, FALSE); } } }
static void dissect_arp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { guint16 ar_hrd; guint16 ar_pro; guint8 ar_hln; guint8 ar_pln; guint16 ar_op; int tot_len; proto_tree *arp_tree = NULL; proto_item *ti, *item; const gchar *op_str; int sha_offset, spa_offset, tha_offset, tpa_offset; const guint8 *spa_val, *tpa_val; gboolean is_gratuitous; gboolean duplicate_detected = FALSE; guint32 duplicate_ip = 0; /* Call it ARP, for now, so that if we throw an exception before we decide whether it's ARP or RARP or IARP or ATMARP, it shows up in the packet list as ARP. Clear the Info column so that, if we throw an exception, it shows up as a short or malformed ARP frame. */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "ARP"); col_clear(pinfo->cinfo, COL_INFO); /* Hardware Address Type */ ar_hrd = tvb_get_ntohs(tvb, AR_HRD); if (ar_hrd == ARPHRD_ATM2225) { call_dissector(atmarp_handle, tvb, pinfo, tree); return; } /* Protocol Address Type */ ar_pro = tvb_get_ntohs(tvb, AR_PRO); /* Hardware Address Size */ ar_hln = tvb_get_guint8(tvb, AR_HLN); /* Protocol Address Size */ ar_pln = tvb_get_guint8(tvb, AR_PLN); /* Operation */ ar_op = tvb_get_ntohs(tvb, AR_OP); tot_len = MIN_ARP_HEADER_SIZE + ar_hln*2 + ar_pln*2; /* Adjust the length of this tvbuff to include only the ARP datagram. Our caller may use that to determine how much of its packet was padding. */ tvb_set_reported_length(tvb, tot_len); if (check_col(pinfo->cinfo, COL_PROTOCOL)) { switch (ar_op) { case ARPOP_REQUEST: if (global_arp_detect_request_storm) { request_seen(pinfo); } /* FALLTHRU */ case ARPOP_REPLY: default: col_set_str(pinfo->cinfo, COL_PROTOCOL, "ARP"); break; case ARPOP_RREQUEST: case ARPOP_RREPLY: col_set_str(pinfo->cinfo, COL_PROTOCOL, "RARP"); break; case ARPOP_IREQUEST: case ARPOP_IREPLY: col_set_str(pinfo->cinfo, COL_PROTOCOL, "Inverse ARP"); break; } } /* Get the offsets of the addresses. */ /* Source Hardware Address */ sha_offset = MIN_ARP_HEADER_SIZE; /* Source Protocol Address */ spa_offset = sha_offset + ar_hln; /* Target Hardware Address */ tha_offset = spa_offset + ar_pln; /* Target Protocol Address */ tpa_offset = tha_offset + ar_hln; if ((ar_op == ARPOP_REPLY || ar_op == ARPOP_REQUEST) && ARP_HW_IS_ETHER(ar_hrd, ar_hln) && ARP_PRO_IS_IPv4(ar_pro, ar_pln)) { /* inform resolv.c module of the new discovered addresses */ guint32 ip; const guint8 *mac; /* Add sender address if sender MAC address is neither a broadcast/ multicast address nor an all-zero address and if sender IP address isn't all zeroes. */ ip = tvb_get_ipv4(tvb, spa_offset); mac = tvb_get_ptr(tvb, sha_offset, 6); if ((mac[0] & 0x01) == 0 && memcmp(mac, mac_allzero, 6) != 0 && ip != 0) { add_ether_byip(ip, mac); if (global_arp_detect_duplicate_ip_addresses) { duplicate_detected = check_for_duplicate_addresses(pinfo, tree, tvb, mac, ip, &duplicate_ip); } } /* Add target address if target MAC address is neither a broadcast/ multicast address nor an all-zero address and if target IP address isn't all zeroes. */ /* Do not add target address if the packet is a Request. According to the RFC, target addresses in requests have no meaning */ ip = tvb_get_ipv4(tvb, tpa_offset); mac = tvb_get_ptr(tvb, tha_offset, 6); if ((mac[0] & 0x01) == 0 && memcmp(mac, mac_allzero, 6) != 0 && ip != 0 && ar_op != ARPOP_REQUEST) { add_ether_byip(ip, mac); if (global_arp_detect_duplicate_ip_addresses) { duplicate_detected = check_for_duplicate_addresses(pinfo, tree, tvb, mac, ip, &duplicate_ip); } } } if (!tree && !check_col(pinfo->cinfo, COL_INFO)) { /* We're not building a protocol tree and we're not setting the Info column, so we don't have any more work to do. */ return; } spa_val = tvb_get_ptr(tvb, spa_offset, ar_pln); tpa_val = tvb_get_ptr(tvb, tpa_offset, ar_pln); /* ARP requests/replies with the same sender and target protocol address are flagged as "gratuitous ARPs", i.e. ARPs sent out as, in effect, an announcement that the machine has MAC address XX:XX:XX:XX:XX:XX and IPv4 address YY.YY.YY.YY. Requests are to provoke complaints if some other machine has the same IPv4 address, replies are used to announce relocation of network address, like in failover solutions. */ if (((ar_op == ARPOP_REQUEST) || (ar_op == ARPOP_REPLY)) && (memcmp(spa_val, tpa_val, ar_pln) == 0)) is_gratuitous = TRUE; else is_gratuitous = FALSE; if (check_col(pinfo->cinfo, COL_INFO)) { switch (ar_op) { case ARPOP_REQUEST: if (is_gratuitous) col_add_fstr(pinfo->cinfo, COL_INFO, "Gratuitous ARP for %s (Request)", arpproaddr_to_str(tpa_val, ar_pln, ar_pro)); else col_add_fstr(pinfo->cinfo, COL_INFO, "Who has %s? Tell %s", arpproaddr_to_str(tpa_val, ar_pln, ar_pro), arpproaddr_to_str(spa_val, ar_pln, ar_pro)); break; case ARPOP_REPLY: if (is_gratuitous) col_add_fstr(pinfo->cinfo, COL_INFO, "Gratuitous ARP for %s (Reply)", arpproaddr_to_str(spa_val, ar_pln, ar_pro)); else col_add_fstr(pinfo->cinfo, COL_INFO, "%s is at %s", arpproaddr_to_str(spa_val, ar_pln, ar_pro), tvb_arphrdaddr_to_str(tvb, sha_offset, ar_hln, ar_hrd)); break; case ARPOP_RREQUEST: case ARPOP_IREQUEST: col_add_fstr(pinfo->cinfo, COL_INFO, "Who is %s? Tell %s", tvb_arphrdaddr_to_str(tvb, tha_offset, ar_hln, ar_hrd), tvb_arphrdaddr_to_str(tvb, sha_offset, ar_hln, ar_hrd)); break; case ARPOP_RREPLY: col_add_fstr(pinfo->cinfo, COL_INFO, "%s is at %s", tvb_arphrdaddr_to_str(tvb, tha_offset, ar_hln, ar_hrd), arpproaddr_to_str(tpa_val, ar_pln, ar_pro)); break; case ARPOP_IREPLY: col_add_fstr(pinfo->cinfo, COL_INFO, "%s is at %s", tvb_arphrdaddr_to_str(tvb, sha_offset, ar_hln, ar_hrd), arpproaddr_to_str(spa_val, ar_pln, ar_pro)); break; default: col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown ARP opcode 0x%04x", ar_op); break; } } if (tree) { if ((op_str = match_strval(ar_op, op_vals))) { if (is_gratuitous && (ar_op == ARPOP_REQUEST)) op_str = "request/gratuitous ARP"; if (is_gratuitous && (ar_op == ARPOP_REPLY)) op_str = "reply/gratuitous ARP"; ti = proto_tree_add_protocol_format(tree, proto_arp, tvb, 0, tot_len, "Address Resolution Protocol (%s)", op_str); } else ti = proto_tree_add_protocol_format(tree, proto_arp, tvb, 0, tot_len, "Address Resolution Protocol (opcode 0x%04x)", ar_op); arp_tree = proto_item_add_subtree(ti, ett_arp); proto_tree_add_uint(arp_tree, hf_arp_hard_type, tvb, AR_HRD, 2, ar_hrd); proto_tree_add_uint(arp_tree, hf_arp_proto_type, tvb, AR_PRO, 2, ar_pro); proto_tree_add_uint(arp_tree, hf_arp_hard_size, tvb, AR_HLN, 1, ar_hln); proto_tree_add_uint(arp_tree, hf_arp_proto_size, tvb, AR_PLN, 1, ar_pln); proto_tree_add_uint(arp_tree, hf_arp_opcode, tvb, AR_OP, 2, ar_op); item = proto_tree_add_boolean(arp_tree, hf_arp_isgratuitous, tvb, 0, 0, is_gratuitous); PROTO_ITEM_SET_GENERATED(item); if (ar_hln != 0) { proto_tree_add_item(arp_tree, ARP_HW_IS_ETHER(ar_hrd, ar_hln) ? hf_arp_src_hw_mac : hf_arp_src_hw, tvb, sha_offset, ar_hln, FALSE); } if (ar_pln != 0) { proto_tree_add_item(arp_tree, ARP_PRO_IS_IPv4(ar_pro, ar_pln) ? hf_arp_src_proto_ipv4 : hf_arp_src_proto, tvb, spa_offset, ar_pln, FALSE); } if (ar_hln != 0) { proto_tree_add_item(arp_tree, ARP_HW_IS_ETHER(ar_hrd, ar_hln) ? hf_arp_dst_hw_mac : hf_arp_dst_hw, tvb, tha_offset, ar_hln, FALSE); } if (ar_pln != 0) { proto_tree_add_item(arp_tree, ARP_PRO_IS_IPv4(ar_pro, ar_pln) ? hf_arp_dst_proto_ipv4 : hf_arp_dst_proto, tvb, tpa_offset, ar_pln, FALSE); } } if (global_arp_detect_request_storm) { check_for_storm_count(tvb, pinfo, arp_tree); } if (duplicate_detected) { /* Also indicate in info column */ if (check_col(pinfo->cinfo, COL_INFO)) { col_append_fstr(pinfo->cinfo, COL_INFO, " (duplicate use of %s detected!)", arpproaddr_to_str((guint8*)&duplicate_ip, 4, ETHERTYPE_IP)); } } }
void dissect_nmas_reply(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ncp_tree, guint8 func _U_, guint8 subfunc, ncp_req_hash_value *request_value) { guint32 foffset=0, roffset=0; guint32 subverb=0; guint8 msgverb=0; guint32 msg_length=0; guint32 return_code=0, encrypt_error=0; proto_tree *atree; proto_item *aitem; proto_item *expert_item; const gchar *str; foffset = 8; if (request_value) { subverb = request_value->req_nds_flags; msgverb = request_value->nds_request_verb; } col_set_str(pinfo->cinfo, COL_PROTOCOL, "NMAS"); if (tvb_reported_length_remaining(tvb, foffset)<4) { return; } aitem = proto_tree_add_text(ncp_tree, tvb, foffset, -1, "Packet Type: %s", val_to_str(subfunc, nmas_func_enum, "Unknown (0x%02x)")); atree = proto_item_add_subtree(aitem, ett_nmas); switch (subfunc) { case 1: proto_tree_add_item(atree, hf_ping_flags, tvb, foffset, 4, ENC_LITTLE_ENDIAN); foffset += 4; proto_tree_add_item(atree, hf_nmas_version, tvb, foffset, 4, ENC_LITTLE_ENDIAN); foffset += 4; break; case 2: proto_tree_add_text(atree, tvb, foffset, -1, "Verb: %s", val_to_str(subverb, nmas_subverb_enum, "Unknown (%u)")); proto_tree_add_item(atree, hf_length, tvb, foffset, 4, ENC_LITTLE_ENDIAN); msg_length = tvb_get_letohl(tvb, foffset); foffset +=4; proto_tree_add_item(atree, hf_frag_handle, tvb, foffset, 4, ENC_LITTLE_ENDIAN); /* Check for a fragment packet */ if (tvb_get_letohl(tvb, foffset)!=0xffffffff) { break; } foffset += 4; return_code = tvb_get_letohl(tvb, foffset); roffset = foffset; foffset += 4; msg_length -= 8; if (return_code == 0 && msg_length > 0) { switch (subverb) { case 0: /* Fragmented Ping */ proto_tree_add_item(atree, hf_ping_flags, tvb, foffset, 4, ENC_LITTLE_ENDIAN); foffset += 4; proto_tree_add_item(atree, hf_nmas_version, tvb, foffset, 4, ENC_LITTLE_ENDIAN); foffset += 4; break; case 2: /* Client Put Data */ proto_tree_add_item(atree, hf_squeue_bytes, tvb, foffset, 4, ENC_LITTLE_ENDIAN); foffset += 4; proto_tree_add_item(atree, hf_cqueue_bytes, tvb, foffset, 4, ENC_LITTLE_ENDIAN); foffset += 4; break; case 4: /* Client Get Data */ proto_tree_add_item(atree, hf_opaque, tvb, foffset, msg_length, ENC_NA); foffset += msg_length; break; case 6: /* Client Get User NDS Credentials */ proto_tree_add_item(atree, hf_num_creds, tvb, foffset, 4, ENC_LITTLE_ENDIAN); foffset += 4; proto_tree_add_item(atree, hf_cred_type, tvb, foffset, 4, ENC_LITTLE_ENDIAN); foffset += 4; proto_tree_add_item(atree, hf_login_state, tvb, foffset, 4, ENC_LITTLE_ENDIAN); foffset += 4; msg_length -= 12; proto_tree_add_item(atree, hf_enc_cred, tvb, foffset, msg_length, ENC_NA); foffset += msg_length; break; case 8: /* Login Store Management */ proto_tree_add_text(atree, tvb, foffset, -1, "Subverb: %s", val_to_str(msgverb, nmas_lsmverb_enum, "Unknown (%u)")); switch(msgverb) { /* The data within these structures is all encrypted. */ case 1: case 3: case 5: case 7: case 9: proto_tree_add_item(atree, hf_enc_data, tvb, foffset, msg_length, ENC_NA); foffset += msg_length; break; default: break; } break; case 10: /* Writable Object Check */ proto_tree_add_item(atree, hf_nmas_version, tvb, foffset, 4, ENC_LITTLE_ENDIAN); foffset += 4; break; case 1242: /* Message Handler */ proto_tree_add_text(atree, tvb, foffset, -1, "Subverb: %s", val_to_str(msgverb, nmas_msgverb_enum, "Unknown (%u)")); switch(msgverb) { case 1: msg_length = tvb_get_ntohl(tvb, foffset); proto_tree_add_item(atree, hf_length, tvb, foffset, 4, ENC_BIG_ENDIAN); foffset += 4; proto_tree_add_item(atree, hf_data, tvb, foffset, msg_length, ENC_NA); foffset += msg_length; break; case 3: proto_tree_add_item(atree, hf_session_ident, tvb, foffset, 4, ENC_BIG_ENDIAN); foffset += 4; break; case 5: /* No Op */ break; case 7: encrypt_error = tvb_get_ntohl(tvb, foffset); str = match_strval(encrypt_error, nmas_errors_enum); if (str) { col_add_fstr(pinfo->cinfo, COL_INFO, "R Payload Error - %s", str); expert_item = proto_tree_add_item(atree, hf_encrypt_error, tvb, foffset, 4, ENC_BIG_ENDIAN); expert_add_info_format(pinfo, expert_item, PI_RESPONSE_CODE, PI_ERROR, "NMAS Payload Error: %s", str); } else { proto_tree_add_item(atree, hf_opaque, tvb, foffset, msg_length, ENC_NA); } foffset += msg_length; break; case 9: /* No Op */ break; default: break; } break; default: break; } } str = match_strval(return_code, nmas_errors_enum); if (str) { expert_item = proto_tree_add_item(atree, hf_return_code, tvb, roffset, 4, ENC_LITTLE_ENDIAN); expert_add_info_format(pinfo, expert_item, PI_RESPONSE_CODE, PI_ERROR, "NMAS Error: 0x%08x %s", return_code, str); col_add_fstr(pinfo->cinfo, COL_INFO, "R Error - %s", str); } else { if (return_code!=0) { expert_item = proto_tree_add_item(atree, hf_return_code, tvb, roffset, 4, ENC_LITTLE_ENDIAN); expert_add_info_format(pinfo, expert_item, PI_RESPONSE_CODE, PI_ERROR, "NMAS Error: 0x%08x is unknown", return_code); if (check_col(pinfo->cinfo, COL_INFO)) { col_add_fstr(pinfo->cinfo, COL_INFO, "R Unknown NMAS Error - 0x%08x", return_code); } } } if (return_code == 0) { proto_tree_add_text(atree, tvb, roffset, 4, "Return Code: Success (0x00000000)"); } break; case 3: break; default: break; } }