+ size_t offset = 0;
+ guint32 plen;
+ guint32 available_bytes;
+/* guint32 noffset; */
+
+ /* Loop through the packet, dissecting multiple diameter messages */
+ do {
+ available_bytes = tvb_length_remaining(tvb, offset);
+ if (available_bytes < 4) {
+ g_warning("Diameter: Bailing because only %d bytes of packet are available",
+ available_bytes);
+ return; /* Bail. We can't even get our length */
+ }
+
+ /* get our packet length */
+ plen = tvb_get_ntohl(tvb, offset);
+ plen &= 0x00ffffff; /* get rid of the flags */
+
+ /*Desegmentation */
+ if (gbl_diameter_desegment) {
+ if (pinfo->can_desegment
+ && plen > available_bytes) {
+ pinfo->desegment_offset = offset;
+ pinfo->desegment_len = plen - available_bytes;
+/* g_warning("Diameter: Bailing for deseg because plen(%d) > available(%d)", */
+/* plen, available_bytes); */
+ return;
+ }
+ }
+
+ /* Otherwise, dissect our packet */
+ offset = dissect_diameter_common(tvb, offset, pinfo, tree);
+
+/* g_warning("dissected from %d to %d bytes out of %d (available was %d plen was %d)", */
+/* offset, noffset, tvb_length(tvb), available_bytes, plen); */
+/* offset=noffset; */
+ } while (offset < tvb_reported_length(tvb));
+
+} /* dissect_diameter_tcp */
+
+/*
+ * Call the mip_dissector, after saving our pinfo variables
+ * so it doesn't write to our column display.
+ */
+static void
+safe_dissect_mip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ size_t offset, size_t length)
+{
+ static dissector_handle_t mip_handle;
+ static int mipInitialized=FALSE;
+ tvbuff_t *mip_tvb;
+ address save_dl_src;
+ address save_dl_dst;
+ address save_net_src;
+ address save_net_dst;
+ address save_src;
+ address save_dst;
+ gboolean save_in_error_pkt;
+
+ if (!mipInitialized) {
+ mip_handle = find_dissector("mip");
+ mipInitialized=TRUE;
+ }
+
+ mip_tvb = tvb_new_subset(tvb, offset,
+ MIN(length, tvb_length(tvb)-offset),
+ length);
+
+ /* The contained packet is a MIP registration request;
+ dissect it with the MIP dissector. */
+ col_set_writable(pinfo->cinfo, FALSE);
+
+ /* Also, save the current values of the addresses, and restore
+ them when we're finished dissecting the contained packet, so
+ that the address columns in the summary don't reflect the
+ contained packet, but reflect this packet instead. */
+ save_dl_src = pinfo->dl_src;
+ save_dl_dst = pinfo->dl_dst;
+ save_net_src = pinfo->net_src;
+ save_net_dst = pinfo->net_dst;
+ save_src = pinfo->src;
+ save_dst = pinfo->dst;
+ save_in_error_pkt = pinfo->in_error_pkt;
+
+ call_dissector(mip_handle, mip_tvb, pinfo, tree);
+
+ /* Restore the "we're inside an error packet" flag. */
+ pinfo->in_error_pkt = save_in_error_pkt;
+ pinfo->dl_src = save_dl_src;
+ pinfo->dl_dst = save_dl_dst;
+ pinfo->net_src = save_net_src;
+ pinfo->net_dst = save_net_dst;
+ pinfo->src = save_src;
+ pinfo->dst = save_dst;
+
+
+} /* safe_dissect_mip */
+
+/*
+ * This function will dissect the AVPs in a diameter packet. It handles
+ * all normal types, and even recursively calls itself for grouped AVPs
+ */
+static void dissect_avps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *avp_tree)
+{
+ /* adds the attribute value pairs to the tree */
+ e_avphdr avph;
+ gchar avpTypeString[64];
+ gchar avpNameString[64];
+ gchar *valstr;
+ guint32 vendorId=0;
+ gchar vendorName[64];
+ int hdrLength;
+ int fixAmt;
+ proto_tree *avpi_tree;
+ size_t offset = 0;
+ tvbuff_t *group_tvb;
+ proto_tree *group_tree;
+ proto_item *grouptf;
+ proto_item *avptf;
+ char buffer[1024];
+ int BadPacket = FALSE;
+ guint32 avpLength;
+ guint8 flags;
+ proto_item *tf;
+ proto_tree *flags_tree;
+
+ gint32 packetLength;
+ size_t avpDataLength;
+ int avpType;
+ gchar flagstr[64] = "<None>";
+ gchar *fstr[] = {"RSVD7", "RSVD6", "RSVD5", "RSVD4", "RSVD3", "Protected", "Mandatory", "Vendor-Specific" };
+ gint i;
+ guint bpos;
+
+ packetLength = tvb_length(tvb);
+
+ /* Check for invalid packet lengths */
+ if (packetLength <= 0) {
+ proto_tree_add_text(avp_tree, tvb, offset, tvb_length(tvb),
+ "No Attribute Value Pairs Found");
+ return;
+ }
+
+ /* Spin around until we run out of packet */
+ while (packetLength > 0 ) {
+
+ /* Check for short packet */
+ if (packetLength < (long)MIN_AVP_SIZE) {
+ g_warning("Diameter: AVP Payload too short: %d bytes less than min size (%ld bytes))",
+ packetLength, (long)MIN_AVP_SIZE);
+ BadPacket = TRUE;
+ /* Don't even bother trying to parse a short packet. */
+ return;
+ }
+
+ /* Copy our header */
+ tvb_memcpy(tvb, (guint8*) &avph, offset, MIN((long)sizeof(avph),packetLength));
+
+ /* Fix the byte ordering */
+ avph.avp_code = g_ntohl(avph.avp_code);
+ avph.avp_flagsLength = g_ntohl(avph.avp_flagsLength);
+
+ flags = (avph.avp_flagsLength & 0xff000000) >> 24;
+ avpLength = avph.avp_flagsLength & 0x00ffffff;
+
+ /* Set up our flags string */
+ if (check_col(pinfo->cinfo, COL_INFO) || avp_tree) {
+ flagstr[0]=0;
+ for (i = 0; i < 8; i++) {
+ bpos = 1 << i;
+ if (flags & bpos) {
+ if (flagstr[0]) {
+ strcat(flagstr, ", ");
+ }
+ strcat(flagstr, fstr[i]);
+ }
+ }
+ if (strlen(flagstr) == 0) {
+ strcpy(flagstr,"<None>");
+ }
+ }
+
+ /* Dissect our vendor id if it exists and set hdr length */
+ if (flags & AVP_FLAGS_V) {
+ vendorId = g_ntohl(avph.avp_vendorId);
+ /* Vendor id */
+ hdrLength = sizeof(e_avphdr);
+ } else {
+ /* No vendor */
+ hdrLength = sizeof(e_avphdr) -
+ sizeof(guint32);
+ vendorId = 0;
+ }
+
+ if (vendorId) {
+ strcpy(vendorName,
+ diameter_vendor_to_str(vendorId, TRUE));
+ } else {
+ vendorName[0]='\0';
+ }
+
+ /* Check for bad length */
+ if (avpLength < MIN_AVP_SIZE ||
+ ((long)avpLength > packetLength)) {
+ g_warning("Diameter: AVP payload size invalid: avp_length: %ld bytes, "
+ "min: %ld bytes, packetLen: %d",
+ (long)avpLength, (long)MIN_AVP_SIZE,
+ packetLength);
+ BadPacket = TRUE;
+ }
+
+ /* Check for bad flags */
+ if (flags & AVP_FLAGS_RESERVED) {
+ g_warning("Diameter: Invalid AVP: Reserved bit set. flags = 0x%x,"
+ " resFl=0x%x",
+ flags, AVP_FLAGS_RESERVED);
+ /* For now, don't set bad packet, since I'm accidentally setting a wrong bit */
+ /* BadPacket = TRUE; */
+ }
+
+ /*
+ * Compute amount of byte-alignment fix (Diameter AVPs are sent on 4 byte
+ * boundries)
+ */
+ fixAmt = 4 - (avpLength % 4);
+ if (fixAmt == 4) fixAmt = 0;
+
+ /* shrink our packetLength */
+ packetLength = packetLength - (avpLength + fixAmt);
+
+ /* Check for out of bounds */
+ if (packetLength < 0) {
+ g_warning("Diameter: Bad AVP: Bad new length (%d bytes) ",
+ packetLength);
+ BadPacket = TRUE;
+ }
+
+ /* Make avp Name & type */
+ strcpy(avpTypeString, val_to_str(diameter_avp_get_type(avph.avp_code,vendorId),
+ TypeValues,
+ "Unknown-Type: 0x%08x"));
+ strcpy(avpNameString, diameter_avp_get_name(avph.avp_code, vendorId));
+
+ avptf = proto_tree_add_text(avp_tree, tvb,
+ offset, avpLength + fixAmt,
+ "%s (%s) l:0x%x (%d bytes) (%d padded bytes)",
+ avpNameString, avpTypeString, avpLength,
+ avpLength, avpLength+fixAmt);
+ avpi_tree = proto_item_add_subtree(avptf,
+ ett_diameter_avpinfo);
+
+ if (avpi_tree !=NULL) {
+ /* Command Code */
+ proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_code,
+ tvb, offset, 4, avph.avp_code, "AVP Code: %s", avpNameString);
+ offset += 4;
+
+ tf = proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_flags, tvb,
+ offset , 1, flags, "Flags: 0x%02x (%s)", flags,
+ flagstr);
+ flags_tree = proto_item_add_subtree(tf, ett_diameter_avp_flags);
+ proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_vendor_specific, tvb, offset, 1, flags);
+ proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_mandatory, tvb, offset, 1, flags);
+ proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_protected, tvb, offset, 1, flags);
+ proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved3, tvb, offset, 1, flags);
+ proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved4, tvb, offset, 1, flags);
+ proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved5, tvb, offset, 1, flags);
+ proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved6, tvb, offset, 1, flags);
+ proto_tree_add_boolean(flags_tree, hf_diameter_avp_flags_reserved7, tvb, offset, 1, flags);
+ offset += 1;
+
+ proto_tree_add_uint(avpi_tree, hf_diameter_avp_length,
+ tvb, offset, 3, avpLength);
+ offset += 3;
+
+ if (flags & AVP_FLAGS_V) {
+ proto_tree_add_uint_format(avpi_tree, hf_diameter_avp_vendor_id,
+ tvb, offset, 4, vendorId, vendorName);
+ offset += 4;
+ }
+
+ avpDataLength = avpLength - hdrLength;
+
+ /*
+ * If we've got a bad packet, just highlight the data. Don't try
+ * to parse it, and, don't move to next AVP.
+ */
+ if (BadPacket) {
+ offset -= hdrLength;
+ proto_tree_add_bytes_format(avpi_tree, hf_diameter_avp_data_bytes,
+ tvb, offset, tvb_length(tvb) - offset,
+ tvb_get_ptr(tvb, offset, tvb_length(tvb) - offset),
+ "Bad AVP (Suspect Data Not Dissected)");
+ return;
+ }
+
+ avpType=diameter_avp_get_type(avph.avp_code,vendorId);
+
+ switch(avpType) {
+ case DIAMETER_GROUPED:
+ sprintf(buffer, "%s Grouped AVPs", avpNameString);
+ /* Recursively call ourselves */
+ grouptf = proto_tree_add_text(avpi_tree,
+ tvb, offset, tvb_length(tvb),
+ buffer);
+
+ group_tree = proto_item_add_subtree(grouptf,
+ ett_diameter_avp);
+
+ group_tvb = tvb_new_subset(tvb, offset,
+ MIN(avpDataLength, tvb_length(tvb)-offset), avpDataLength);
+ if (group_tree != NULL) {
+ dissect_avps( group_tvb, pinfo, group_tree);
+ }