/* * Function for AVP dissector. */ static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree) { gint offset; guint16 avp_code; guint16 avp_flags; guint32 avp_length; guint16 avp_type; guint32 vendor_id; guint32 avp_hdr_length; guint32 avp_data_length, result_code; guint32 padding; gint32 buffer_length; tvbuff_t *group_tvb; tvbuff_t *eap_tvb; tvbuff_t *encap_tvb; proto_tree *single_avp_tree; proto_tree *avp_eap_tree; proto_tree *avp_encap_tree; offset = 0; buffer_length = tvb_reported_length(tvb); /* Go through all AVPs */ while (buffer_length > 0) { avp_code = tvb_get_ntohs(tvb, offset); avp_flags = tvb_get_ntohs(tvb, offset + 2); avp_data_length = tvb_get_ntohs(tvb, offset + 4); /* Check AVP flags for vendor specific AVP */ if (avp_flags & PANA_AVP_FLAG_V) { vendor_id = tvb_get_ntohl(tvb, 8); avp_hdr_length = 12; } else { vendor_id = 0; avp_hdr_length = 8; } avp_length = avp_hdr_length + avp_data_length; /* Check AVP type */ avp_type = pana_avp_get_type(avp_code, vendor_id); /* Check padding */ padding = (4 - (avp_length % 4)) % 4; single_avp_tree = proto_tree_add_subtree_format(avp_tree, tvb, offset, avp_length + padding, ett_pana_avp_info, NULL, "%s (%s) length: %d bytes (%d padded bytes)", val_to_str(avp_code, avp_code_names, "Unknown (%d)"), val_to_str(avp_type, avp_type_names, "Unknown (%d)"), avp_length, avp_length + padding); /* AVP Code */ proto_tree_add_uint_format_value(single_avp_tree, hf_pana_avp_code, tvb, offset, 2, avp_code, "%s (%u)", val_to_str(avp_code, avp_code_names, "Unknown (%d)"), avp_code); offset += 2; /* AVP Flags */ dissect_pana_avp_flags(single_avp_tree, tvb, offset, avp_flags); offset += 2; /* AVP Length */ proto_tree_add_item(single_avp_tree, hf_pana_avp_data_length, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; /* Reserved */ proto_tree_add_item(single_avp_tree, hf_pana_avp_reserved, tvb, offset, 2, ENC_NA); offset += 2; if (avp_flags & PANA_AVP_FLAG_V) { /* Vendor ID */ proto_tree_add_item(single_avp_tree, hf_pana_avp_vendorid, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; } if (! (avp_flags & PANA_AVP_FLAG_V)) { /* AVP Value */ switch(avp_type) { case PANA_GROUPED: { proto_tree *avp_group_tree; avp_group_tree = proto_tree_add_subtree(single_avp_tree, tvb, offset, avp_data_length, ett_pana_avp, NULL, "Grouped AVP"); group_tvb = tvb_new_subset(tvb, offset, MIN(avp_data_length, tvb_reported_length(tvb)-offset), avp_data_length); dissect_avps(group_tvb, pinfo, avp_group_tree); break; } case PANA_UTF8STRING: { proto_tree_add_item(single_avp_tree, hf_pana_avp_data_string, tvb, offset, avp_data_length, ENC_UTF_8|ENC_NA); break; } case PANA_OCTET_STRING: { proto_tree_add_item(single_avp_tree, hf_pana_avp_data_bytes, tvb, offset, avp_data_length, ENC_NA); break; } case PANA_INTEGER32: { proto_tree_add_item(single_avp_tree, hf_pana_avp_data_int32, tvb, offset, 4, ENC_BIG_ENDIAN); break; } case PANA_UNSIGNED32: { proto_tree_add_item(single_avp_tree, hf_pana_avp_data_uint32, tvb, offset, 4, ENC_BIG_ENDIAN); break; } case PANA_INTEGER64: { proto_tree_add_item(single_avp_tree, hf_pana_avp_data_int64, tvb, offset, 8, ENC_BIG_ENDIAN); break; } case PANA_UNSIGNED64: { proto_tree_add_item(single_avp_tree, hf_pana_avp_data_uint64, tvb, offset, 8, ENC_BIG_ENDIAN); break; } case PANA_ENUMERATED: { proto_tree_add_item(single_avp_tree, hf_pana_avp_data_enumerated, tvb, offset, 4, ENC_BIG_ENDIAN); break; } case PANA_RESULT_CODE: { result_code = tvb_get_ntohl(tvb, offset); proto_tree_add_uint_format(single_avp_tree, hf_pana_avp_code, tvb, offset, avp_data_length, result_code, "Value: %d (%s)", result_code, val_to_str(result_code, avp_code_names, "Unknown (%d)")); break; } case PANA_EAP: { avp_eap_tree = proto_tree_add_subtree(single_avp_tree, tvb, offset, avp_data_length, ett_pana_avp, NULL, "AVP Value (EAP packet)"); eap_tvb = tvb_new_subset_length(tvb, offset, avp_data_length); DISSECTOR_ASSERT_HINT(eap_handle, "EAP Dissector not available"); call_dissector(eap_handle, eap_tvb, pinfo, avp_eap_tree); break; } case PANA_ENCAPSULATED: { avp_encap_tree = proto_tree_add_subtree(single_avp_tree, tvb, offset, avp_data_length, ett_pana_avp, NULL, "AVP Value (PANA packet)"); encap_tvb = tvb_new_subset_length(tvb, offset, avp_data_length); dissect_pana_pdu(encap_tvb, pinfo, avp_encap_tree); break; } } } offset += avp_data_length + padding; /* Update the buffer length */ buffer_length -= avp_length + padding; } }
/* * Function for AVP dissector. */ static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree) { gint offset; guint16 avp_code; guint16 avp_flags; guint16 avp_length; guint16 avp_type; guint32 vendor_id; guint16 avp_hdr_length; guint16 avp_data_length; guint16 padding; guint16 buffer_length; int bad_avp = FALSE; tvbuff_t *group_tvb; tvbuff_t *eap_tvb; proto_item *single_avp_item; proto_tree *single_avp_tree; proto_item *avp_group_item; proto_tree *avp_group_tree; proto_item *avp_eap_item; proto_tree *avp_eap_tree; offset = 0; buffer_length = tvb_reported_length(tvb); /* Go through all AVPs */ while (buffer_length > 0) { avp_code = tvb_get_ntohs(tvb, offset); avp_flags = tvb_get_ntohs(tvb, offset + 2); avp_length = tvb_get_ntohs(tvb, offset + 4); /* Check AVP flags for vendor specific AVP */ if (avp_flags & PANA_AVP_FLAG_V) { vendor_id = tvb_get_ntohl(tvb, 8); avp_hdr_length = 12; } else { vendor_id = 0; avp_hdr_length = 8; } /* Check AVP type */ avp_type = pana_avp_get_type(avp_code, vendor_id); /* Check AVP length */ if (avp_length < avp_hdr_length) { single_avp_item = proto_tree_add_text(avp_tree, tvb, offset, avp_length, "%s (%s) length: %d bytes (shorter than header length %d)", val_to_str(avp_code, avp_code_names, "Unknown (%d)"), val_to_str(avp_type, avp_type_names, "Unknown (%d)"), avp_length, avp_hdr_length); single_avp_tree = proto_item_add_subtree(single_avp_item, ett_pana_avp_info); if (single_avp_tree != NULL) { /* AVP Code */ proto_tree_add_uint_format_value(single_avp_tree, hf_pana_avp_code, tvb, offset, 2, avp_code, "%s (%u)", val_to_str(avp_code, avp_code_names, "Unknown (%d)"), avp_code); offset += 2; /* AVP Flags */ dissect_pana_avp_flags(single_avp_tree, tvb, offset, avp_flags); offset += 2; /* AVP Length */ proto_tree_add_item(single_avp_tree, hf_pana_avp_length, tvb, offset, 2, FALSE); offset += 2; } return; } /* Check AVP flags */ if (avp_flags & PANA_AVP_FLAG_RES) bad_avp = TRUE; /* Check padding */ padding = (4 - (avp_length % 4)) % 4; single_avp_item = proto_tree_add_text(avp_tree, tvb, offset, avp_length + padding, "%s (%s) length: %d bytes (%d padded bytes)", val_to_str(avp_code, avp_code_names, "Unknown (%d)"), val_to_str(avp_type, avp_type_names, "Unknown (%d)"), avp_length, avp_length + padding); single_avp_tree = proto_item_add_subtree(single_avp_item, ett_pana_avp_info); /* AVP data length */ avp_data_length = avp_length - avp_hdr_length; if (single_avp_tree != NULL) { /* AVP Code */ proto_tree_add_uint_format_value(single_avp_tree, hf_pana_avp_code, tvb, offset, 2, avp_code, "%s (%u)", val_to_str(avp_code, avp_code_names, "Unknown (%d)"), avp_code); } offset += 2; if (single_avp_tree != NULL) { /* AVP Flags */ dissect_pana_avp_flags(single_avp_tree, tvb, offset, avp_flags); } offset += 2; if (single_avp_tree != NULL) { /* AVP Length */ proto_tree_add_item(single_avp_tree, hf_pana_avp_length, tvb, offset, 2, FALSE); } offset += 2; if (single_avp_tree != NULL) { /* Reserved */ proto_tree_add_item(single_avp_tree, hf_pana_avp_reserved, tvb, offset, 2, FALSE); } offset += 2; if (avp_flags & PANA_AVP_FLAG_V) { if (single_avp_tree != NULL) { /* Vendor ID */ proto_tree_add_item(single_avp_tree, hf_pana_avp_vendorid, tvb, offset, 4, FALSE); } offset += 4; } if (avp_flags & PANA_AVP_FLAG_V) { /* AVP Value */ switch(avp_type) { case PANA_GROUPED: { avp_group_item = proto_tree_add_text(single_avp_tree, tvb, offset, avp_data_length, "Grouped AVP"); avp_group_tree = proto_item_add_subtree(avp_group_item, ett_pana_avp); group_tvb = tvb_new_subset(tvb, offset, MIN(avp_data_length, tvb_length(tvb)-offset), avp_data_length); if (avp_group_tree != NULL) { dissect_avps(group_tvb, pinfo, avp_group_tree); } break; } case PANA_UTF8STRING: { const guint8 *data; data = tvb_get_ptr(tvb, offset, avp_data_length); proto_tree_add_string_format(single_avp_tree, hf_pana_avp_data_string, tvb, offset, avp_data_length, data, "UTF8String: %*.*s", avp_data_length, avp_data_length, data); break; } case PANA_OCTET_STRING: { proto_tree_add_bytes_format(single_avp_tree, hf_pana_avp_data_bytes, tvb, offset, avp_data_length, tvb_get_ptr(tvb, offset, avp_data_length), "Hex Data Highlighted Below"); break; } case PANA_INTEGER32: { proto_tree_add_item(single_avp_tree, hf_pana_avp_data_int32, tvb, offset, 4, FALSE); break; } case PANA_UNSIGNED32: { proto_tree_add_item(single_avp_tree, hf_pana_avp_data_uint32, tvb, offset, 4, FALSE); break; } case PANA_INTEGER64: { proto_tree_add_item(single_avp_tree, hf_pana_avp_data_int64, tvb, offset, 8, FALSE); break; } case PANA_UNSIGNED64: { proto_tree_add_item(single_avp_tree, hf_pana_avp_data_uint64, tvb, offset, 8, FALSE); break; } case PANA_ENUMERATED: { proto_tree_add_item(single_avp_tree, hf_pana_avp_data_enumerated, tvb, offset, 4, FALSE); break; } case PANA_RESULT_CODE: { proto_tree_add_text(single_avp_tree, tvb, offset, avp_data_length, "Value: %d (%s)", tvb_get_ntohl(tvb, offset), val_to_str(tvb_get_ntohs(tvb, offset), avp_code_names, "Unknown (%d)")); break; } case PANA_EAP: { avp_eap_item = proto_tree_add_text(single_avp_tree, tvb, offset, avp_data_length, "AVP Value (EAP packet)"); avp_eap_tree = proto_item_add_subtree(avp_eap_item, ett_pana_avp); eap_tvb = tvb_new_subset(tvb, offset, avp_data_length, avp_data_length); if (eap_handle != NULL) { call_dissector(eap_handle, eap_tvb, pinfo, avp_eap_tree); } break; } } } offset += avp_data_length + padding; /* Update the buffer length */ buffer_length -= avp_length + padding; } }