static gchar*
openais_a_tvb_format_stringzpad(tvbuff_t *tvb, const gint offset, const gint size)
{
#ifdef HAVE_TVB_FORMAT_STRINGZPAD
    return tvb_format_stringzpad(tvb, offset, size);
#else
    return tvb_get_ephemeral_string(tvb, offset, size);
#endif
}
Esempio n. 2
0
static void
dissect_udld(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
    proto_item *ti;
    proto_tree *udld_tree = NULL;
    int offset = 0;
    guint16 type;
    guint16 length;
    proto_item *tlvi;
    proto_tree *tlv_tree;
    int real_length;

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

    if (tree) {
    	proto_item *flags_ti;
	proto_tree *flags_tree;

        ti = proto_tree_add_item(tree, proto_udld, tvb, offset, -1, ENC_NA);
	udld_tree = proto_item_add_subtree(ti, ett_udld);

	/* UDLD header */
	proto_tree_add_item(udld_tree, hf_udld_version, tvb, offset, 1, ENC_BIG_ENDIAN);
	proto_tree_add_item(udld_tree, hf_udld_opcode, tvb, offset, 1, ENC_BIG_ENDIAN);
	offset += 1;
	flags_ti = proto_tree_add_item(udld_tree, hf_udld_flags, tvb, offset, 1, ENC_BIG_ENDIAN);
	flags_tree = proto_item_add_subtree(flags_ti, ett_udld_flags);
	proto_tree_add_item(flags_tree, hf_udld_flags_rt, tvb, offset, 1, ENC_BIG_ENDIAN);
	proto_tree_add_item(flags_tree, hf_udld_flags_rsy, tvb, offset, 1, ENC_BIG_ENDIAN);
	offset += 1;
	proto_tree_add_item(udld_tree, hf_udld_checksum, tvb, offset, 2, ENC_BIG_ENDIAN);
	offset += 2;
    } else {
	offset += 4; /* The version/opcode/flags/checksum fields from above */
    }

	while (tvb_reported_length_remaining(tvb, offset) != 0) {
	    type = tvb_get_ntohs(tvb, offset + TLV_TYPE);
	    length = tvb_get_ntohs(tvb, offset + TLV_LENGTH);
	    if (length < 4) {
		    if (tree) {
		    tlvi = proto_tree_add_text(udld_tree, tvb, offset, 4,
			"TLV with invalid length %u (< 4)",
			length);
		    tlv_tree = proto_item_add_subtree(tlvi, ett_udld_tlv);
		    proto_tree_add_uint(tlv_tree, hf_udld_tlvtype, tvb,
				offset + TLV_TYPE, 2, type);
		    proto_tree_add_uint(tlv_tree, hf_udld_tlvlength, tvb,
				offset + TLV_LENGTH, 2, length);
		    }
		    offset += 4;
		    break;
	    }

	    switch (type) {

	    case TYPE_DEVICE_ID:
		/* Device ID */

		if (check_col(pinfo->cinfo, COL_INFO))
		    col_append_fstr(pinfo->cinfo, COL_INFO,
				    "Device ID: %s  ",
				    tvb_format_stringzpad(tvb, offset + 4,
							  length - 4));

		if (tree) {
		    tlvi = proto_tree_add_text(udld_tree, tvb, offset,
				length, "Device ID: %s",
				tvb_format_stringzpad(tvb, offset + 4, length - 4));
		    tlv_tree = proto_item_add_subtree(tlvi, ett_udld_tlv);
		    proto_tree_add_uint(tlv_tree, hf_udld_tlvtype, tvb,
				offset + TLV_TYPE, 2, type);
		    proto_tree_add_uint(tlv_tree, hf_udld_tlvlength, tvb,
				offset + TLV_LENGTH, 2, length);
		    proto_tree_add_text(tlv_tree, tvb, offset + 4,
				length - 4, "Device ID: %s",
				tvb_format_stringzpad(tvb, offset + 4, length - 4));
		    }
		    offset += length;
		    break;

	    case TYPE_PORT_ID:
		real_length = length;
		if (tvb_get_guint8(tvb, offset + real_length) != 0x00) {
		    /* The length in the TLV doesn't appear to be the
		       length of the TLV, as the byte just past it
		       isn't the first byte of a 2-byte big-endian
		       small integer; make the length of the TLV the length
		       in the TLV, plus 4 bytes for the TLV type and length,
		       minus 1 because that's what makes one capture work. */
		    real_length = length + 3;
		}

		if (check_col(pinfo->cinfo, COL_INFO))
		    col_append_fstr(pinfo->cinfo, COL_INFO,
				    "Port ID: %s  ",
				    tvb_format_stringzpad(tvb, offset + 4, length - 4));

		if (tree) {
		    tlvi = proto_tree_add_text(udld_tree, tvb, offset,
			    real_length, "Port ID: %s",
			    tvb_format_text(tvb, offset + 4, real_length - 4));
		    tlv_tree = proto_item_add_subtree(tlvi, ett_udld_tlv);
		    proto_tree_add_uint(tlv_tree, hf_udld_tlvtype, tvb,
			    offset + TLV_TYPE, 2, type);
		    proto_tree_add_uint(tlv_tree, hf_udld_tlvlength, tvb,
			    offset + TLV_LENGTH, 2, length);
		    proto_tree_add_text(tlv_tree, tvb, offset + 4,
			    real_length - 4,
			    "Sent through Interface: %s",
			    tvb_format_text(tvb, offset + 4, real_length - 4));
		}
		offset += real_length;
		break;

	    case TYPE_ECHO:
	    case TYPE_MESSAGE_INTERVAL:
	    case TYPE_TIMEOUT_INTERVAL:
	    case TYPE_DEVICE_NAME:
	    case TYPE_SEQUENCE_NUMBER:
	    default:
		tlvi = proto_tree_add_text(udld_tree, tvb, offset,
			length, "Type: %s, length: %u",
			val_to_str(type, type_vals, "Unknown (0x%04x)"),
			length);
		tlv_tree = proto_item_add_subtree(tlvi, ett_udld_tlv);
		proto_tree_add_uint(tlv_tree, hf_udld_tlvtype, tvb,
			offset + TLV_TYPE, 2, type);
		proto_tree_add_uint(tlv_tree, hf_udld_tlvlength, tvb,
			offset + TLV_LENGTH, 2, length);
		if (length > 4) {
			proto_tree_add_text(tlv_tree, tvb, offset + 4,
				length - 4, "Data");
		} else {
			return;
		}
		offset += length;
	    }
	}

    call_dissector(data_handle, tvb_new_subset_remaining(tvb, offset), pinfo, udld_tree);
}
Esempio n. 3
0
static void dissect_tftp_message(tftp_conv_info_t *tftp_info,
                                 tvbuff_t *tvb, packet_info *pinfo,
                                 proto_tree *tree)
{
  proto_tree *tftp_tree;
  proto_item *ti;
  gint        offset    = 0;
  guint16     opcode;
  guint16     bytes;
  guint16     blocknum;
  guint       i1;
  guint16     error;
  tvbuff_t    *data_tvb = NULL;

  col_set_str(pinfo->cinfo, COL_PROTOCOL, "TFTP");

  /* Protocol root */
  ti = proto_tree_add_item(tree, proto_tftp, tvb, offset, -1, ENC_NA);
  tftp_tree = proto_item_add_subtree(ti, ett_tftp);

  /* Opcode */
  opcode = tvb_get_ntohs(tvb, offset);
  proto_tree_add_uint(tftp_tree, hf_tftp_opcode, tvb, offset, 2, opcode);
  col_add_str(pinfo->cinfo, COL_INFO,
              val_to_str(opcode, tftp_opcode_vals, "Unknown (0x%04x)"));
  offset += 2;

  /* read and write requests contain file names
     for other messages, we add the filenames from the conversation */
  if (opcode!=TFTP_RRQ && opcode!=TFTP_WRQ) {
    if (tftp_info->source_file) {
      ti = proto_tree_add_string(tftp_tree, hf_tftp_source_file, tvb,
          0, 0, tftp_info->source_file);
      PROTO_ITEM_SET_GENERATED(ti);
    }

    if (tftp_info->destination_file) {
      ti = proto_tree_add_string(tftp_tree, hf_tftp_destination_file, tvb,
          0, 0, tftp_info->destination_file);
      PROTO_ITEM_SET_GENERATED(ti);
    }
  }

  switch (opcode) {

  case TFTP_RRQ:
    i1 = tvb_strsize(tvb, offset);
    proto_tree_add_item(tftp_tree, hf_tftp_source_file,
                        tvb, offset, i1, ENC_ASCII|ENC_NA);

    tftp_info->source_file = tvb_get_string_enc(wmem_file_scope(), tvb, offset, i1, ENC_ASCII);
    /* we either have a source file name (for read requests) or a
       destination file name (for write requests) 
       when we set one of the names, we clear the other */
    tftp_info->destination_file = NULL;

    col_append_fstr(pinfo->cinfo, COL_INFO, ", File: %s",
                    tvb_format_stringzpad(tvb, offset, i1));

    offset += i1;

    i1 = tvb_strsize(tvb, offset);
    proto_tree_add_item(tftp_tree, hf_tftp_transfer_type,
                        tvb, offset, i1, ENC_ASCII|ENC_NA);

    col_append_fstr(pinfo->cinfo, COL_INFO, ", Transfer type: %s",
                    tvb_format_stringzpad(tvb, offset, i1));

    offset += i1;

    tftp_dissect_options(tvb, pinfo,  offset, tftp_tree,
                         opcode, tftp_info);
    break;

  case TFTP_WRQ:
    i1 = tvb_strsize(tvb, offset);
    proto_tree_add_item(tftp_tree, hf_tftp_destination_file,
                        tvb, offset, i1, ENC_ASCII|ENC_NA);

    tftp_info->destination_file =
      tvb_get_string_enc(wmem_file_scope(), tvb, offset, i1, ENC_ASCII);
    tftp_info->source_file = NULL; /* see above */

    col_append_fstr(pinfo->cinfo, COL_INFO, ", File: %s",
                    tvb_format_stringzpad(tvb, offset, i1));

    offset += i1;

    i1 = tvb_strsize(tvb, offset);
    proto_tree_add_item(tftp_tree, hf_tftp_transfer_type,
                        tvb, offset, i1, ENC_ASCII|ENC_NA);

    col_append_fstr(pinfo->cinfo, COL_INFO, ", Transfer type: %s",
                    tvb_format_stringzpad(tvb, offset, i1));

    offset += i1;

    tftp_dissect_options(tvb, pinfo, offset, tftp_tree,
                         opcode,  tftp_info);
    break;

  case TFTP_INFO:
    tftp_dissect_options(tvb, pinfo, offset, tftp_tree,
                         opcode,  tftp_info);
    break;

  case TFTP_DATA:
    blocknum = tvb_get_ntohs(tvb, offset);
    proto_tree_add_uint(tftp_tree, hf_tftp_blocknum, tvb, offset, 2,
                        blocknum);

    /* Sequence analysis on blocknums (first pass only) */
    if (!pinfo->fd->flags.visited) {
      if (blocknum > tftp_info->next_block_num) {
        /* There is a gap.  Don't try to recover from this. */
        tftp_info->next_block_num = blocknum + 1;
        tftp_info->blocks_missing = TRUE;
        /* TODO: add info to a result table for showing expert info in later passes */
      }
      else if (blocknum == tftp_info->next_block_num) {
        /* OK, inc what we expect next */
        tftp_info->next_block_num++;
      }
    }
    offset += 2;

    /* Show number of bytes in this block, and whether it is the end of the file */
    bytes = tvb_reported_length_remaining(tvb, offset);
    col_append_fstr(pinfo->cinfo, COL_INFO, ", Block: %i%s",
                    blocknum,
                    (bytes < tftp_info->blocksize)?" (last)":"" );

    /* Show data in tree */
    if (bytes > 0) {
      data_tvb = tvb_new_subset(tvb, offset, -1, bytes);
      call_dissector(data_handle, data_tvb, pinfo, tree);
    }

    /* If Export Object tap is listening, need to accumulate blocks info list
       to send to tap. But if already know there are blocks missing, there is no
       point in trying. */
    if (have_tap_listener(tftp_eo_tap) && !tftp_info->blocks_missing) {
      file_block_t *block;

      if (blocknum == 1) {
        /* Reset data for this conversation, freeing any accumulated blocks! */
        cleanup_tftp_blocks(tftp_info);
        tftp_info->next_tap_block_num = 1;
      }

      if (blocknum != tftp_info->next_tap_block_num) {
        /* Ignore.  Could be missing frames, or just clicking previous frame */
        return;
      }

      if (bytes > 0) {
        /* Create a block for this block */
        block = (file_block_t*)g_malloc(sizeof(file_block_t));
        block->length = bytes;
        block->data = tvb_memdup(NULL, data_tvb, 0, bytes);

        /* Add to the end of the list (does involve traversing whole list..) */
        tftp_info->block_list = g_slist_append(tftp_info->block_list, block);
        tftp_info->file_length += bytes;

        /* Look for next blocknum next time */
        tftp_info->next_tap_block_num++;
      }

      /* Tap export object only when reach end of file */
      if (bytes < tftp_info->blocksize) {
        tftp_eo_t        *eo_info;

        /* If don't have a filename, won't tap file info */
        if ((tftp_info->source_file == NULL) && (tftp_info->destination_file == NULL)) {
            cleanup_tftp_blocks(tftp_info);
            return;
        }

        /* Create the eo_info to pass to the listener */
        eo_info = wmem_new(wmem_packet_scope(), tftp_eo_t);

        /* Set filename */
        if (tftp_info->source_file) {
          eo_info->filename = g_strdup(tftp_info->source_file);
        }
        else if (tftp_info->destination_file) {
          eo_info->filename = g_strdup(tftp_info->destination_file);
        }

        /* Send block list, which will be combined and freed at tap. */
        eo_info->payload_len = tftp_info->file_length;
        eo_info->pkt_num = blocknum;
        eo_info->block_list = tftp_info->block_list;

        /* Send to tap */
        tap_queue_packet(tftp_eo_tap, pinfo, eo_info);

        /* Have sent, so forget list of blocks, and only pay attention if we
           get back to the first block again. */
        tftp_info->block_list = NULL;
        tftp_info->next_tap_block_num = 1;
      }
    }
    break;

  case TFTP_ACK:
    blocknum = tvb_get_ntohs(tvb, offset);
    proto_tree_add_uint(tftp_tree, hf_tftp_blocknum, tvb, offset, 2,
                        blocknum);

    col_append_fstr(pinfo->cinfo, COL_INFO, ", Block: %i",
                    blocknum);
    break;

  case TFTP_ERROR:
    error = tvb_get_ntohs(tvb, offset);
    proto_tree_add_uint(tftp_tree, hf_tftp_error_code, tvb, offset, 2,
                        error);

    col_append_fstr(pinfo->cinfo, COL_INFO, ", Code: %s",
                    val_to_str(error, tftp_error_code_vals, "Unknown (%u)"));

    offset += 2;

    i1 = tvb_strsize(tvb, offset);
    proto_tree_add_item(tftp_tree, hf_tftp_error_string, tvb, offset,
                        i1, ENC_ASCII|ENC_NA);

    col_append_fstr(pinfo->cinfo, COL_INFO, ", Message: %s",
                    tvb_format_stringzpad(tvb, offset, i1));

    expert_add_info(pinfo, NULL, &ei_tftp_blocksize_range);
    break;

  case TFTP_OACK:
    tftp_dissect_options(tvb, pinfo, offset, tftp_tree,
                         opcode, tftp_info);
    break;

  default:
    proto_tree_add_item(tftp_tree, hf_tftp_data, tvb, offset, -1, ENC_NA);
    break;

  }
}
static void
dissect_ppi_antenna(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
    /* The fixed values up front */
    guint32 version;
    guint length;
    gint  length_remaining;

    proto_tree *ppi_antenna_tree = NULL;
    proto_tree *present_tree = NULL;
    proto_tree *antennaflags_tree = NULL;
    proto_tree *pt, *my_pt;
    proto_item *ti = NULL;
    proto_item *antenna_line = NULL;


    /* bits */
    int bit;
    guint32 present, next_present;
    /* values actually read out, for displaying */
    guint8 gaindb;
    guint16 beamid;
    guint32 t_hbw, t_vbw, t_pgain, t_appspecific_num; /* temporary conversions */
    gdouble horizbw, vertbw, pgain;
    guint32 flags;
    gchar *curr_str;
    int offset = 0;

    /* Clear out stuff in the info column */
        col_clear(pinfo->cinfo,COL_INFO);

    /* pull out the first three fields of the BASE-GEOTAG-HEADER */
    version = tvb_get_guint8(tvb, offset);
    length  = tvb_get_letohs(tvb, offset+2);
    present = tvb_get_letohl(tvb, offset+4);

    /* Setup basic column info */
    if (check_col(pinfo->cinfo, COL_INFO))
        col_add_fstr(pinfo->cinfo, COL_INFO, "PPI Antenna info v%u, Length %u",
                     version, length);


    /* Create the basic dissection tree*/
    if (tree) {
        ti = proto_tree_add_protocol_format(tree, proto_ppi_antenna,
                                            tvb, 0, length, "Antenna: ");
        antenna_line = ti; /* save this for later, we will fill it in with more detail */

        ppi_antenna_tree= proto_item_add_subtree(ti, ett_ppi_antenna);
        proto_tree_add_uint(ppi_antenna_tree, hf_ppi_antenna_version,
                            tvb, offset, 1, version);
        proto_tree_add_item(ppi_antenna_tree, hf_ppi_antenna_pad,
                            tvb, offset + 1, 1, ENC_NA);
        ti = proto_tree_add_uint(ppi_antenna_tree, hf_ppi_antenna_length,
                                 tvb, offset + 2, 2, length);
    }
    /* We support v1 and v2 of Antenna tags (identical) */
    if (! (version == 1 || version == 2) ) {
        if (tree)
            proto_item_append_text(ti, "invalid version (got %d,  expected 1 or 2)", version);
        return;
    }

    length_remaining = length;
    /* minimum length check, should atleast be a fixed-size geotagging-base header*/
    if (length_remaining < PPI_GEOBASE_MIN_HEADER_LEN) {
        /*
         * Base-geotag-header (Radiotap lookalike) is shorter than the fixed-length portion
         * plus one "present" bitset.
         */
        if (tree)
            proto_item_append_text(ti, " (invalid - minimum length is 8)");
        return;
    }


    /* perform max length sanity checking */
    if (length > PPI_ANTENNA_MAXTAGLEN ) {
        if (tree)
            proto_item_append_text(ti, "Invalid PPI-Antenna length  (got %d, %d max\n)", length, PPI_ANTENNA_MAXTAGLEN);
        return;
    }


    /* Subtree for the "present flags" bitfield. */
    if (tree) {
        pt = proto_tree_add_uint(ppi_antenna_tree, hf_ppi_antenna_present, tvb, offset + 4, 4, present);
        present_tree = proto_item_add_subtree(pt, ett_ppi_antenna_present);

        proto_tree_add_item(present_tree, hf_ppi_antenna_present_flags, tvb, 4, 4, ENC_LITTLE_ENDIAN);
        proto_tree_add_item(present_tree, hf_ppi_antenna_present_gaindb, tvb, 4, 4, ENC_LITTLE_ENDIAN);
        proto_tree_add_item(present_tree, hf_ppi_antenna_present_horizbw, tvb, 4, 4, ENC_LITTLE_ENDIAN);
        proto_tree_add_item(present_tree, hf_ppi_antenna_present_vertbw, tvb, 4, 4, ENC_LITTLE_ENDIAN);
        proto_tree_add_item(present_tree, hf_ppi_antenna_present_pgain, tvb, 4, 4, ENC_LITTLE_ENDIAN);
        proto_tree_add_item(present_tree, hf_ppi_antenna_present_beamid, tvb, 4, 4, ENC_LITTLE_ENDIAN);
        proto_tree_add_item(present_tree, hf_ppi_antenna_present_serialnum, tvb, 4, 4, ENC_LITTLE_ENDIAN);
        proto_tree_add_item(present_tree, hf_ppi_antenna_present_modelname, tvb, 4, 4, ENC_LITTLE_ENDIAN);
        proto_tree_add_item(present_tree, hf_ppi_antenna_present_descstr, tvb, 4, 4, ENC_LITTLE_ENDIAN);
        proto_tree_add_item(present_tree, hf_ppi_antenna_present_appspecific_num, tvb, 4, 4, ENC_LITTLE_ENDIAN);
        proto_tree_add_item(present_tree, hf_ppi_antenna_present_appspecific_data, tvb, 4, 4, ENC_LITTLE_ENDIAN);

        proto_tree_add_item(present_tree, hf_ppi_antenna_present_ext, tvb, 4, 4, ENC_LITTLE_ENDIAN);
    }
    offset += PPI_GEOBASE_MIN_HEADER_LEN;
    length_remaining -= PPI_GEOBASE_MIN_HEADER_LEN;

    /* Now all of the fixed length, fixed location stuff is over. Loop over the bits */
    for (; present; present = next_present) {
        /* clear the least significant bit that is set */
        next_present = present & (present - 1);
        /* extract the least significant bit that is set */
        bit = BITNO_32(present ^ next_present);
        switch (bit) {
        case  PPI_ANTENNA_ANTFLAGS:
            if (length_remaining < 4)
                break;
            flags = tvb_get_letohl(tvb, offset);
            if (tree) {
                my_pt = proto_tree_add_uint(ppi_antenna_tree, hf_ppi_antenna_flags, tvb, offset , 4, flags);
                /*Add antenna_flags bitfields here */
                antennaflags_tree= proto_item_add_subtree(my_pt, ett_ppi_antennaflags);

                proto_tree_add_item(antennaflags_tree, hf_ppi_antennaflags_mimo, tvb, offset, 4, ENC_LITTLE_ENDIAN);
                proto_tree_add_item(antennaflags_tree, hf_ppi_antennaflags_horizpol, tvb, offset, 4, ENC_LITTLE_ENDIAN);
                proto_tree_add_item(antennaflags_tree, hf_ppi_antennaflags_vertpol, tvb, offset, 4, ENC_LITTLE_ENDIAN);
                proto_tree_add_item(antennaflags_tree, hf_ppi_antennaflags_circpol_l, tvb, offset, 4, ENC_LITTLE_ENDIAN);
                proto_tree_add_item(antennaflags_tree, hf_ppi_antennaflags_circpol_r, tvb, offset, 4, ENC_LITTLE_ENDIAN);
                proto_tree_add_item(antennaflags_tree, hf_ppi_antennaflags_steer_elec, tvb, offset, 4, ENC_LITTLE_ENDIAN);
                proto_tree_add_item(antennaflags_tree, hf_ppi_antennaflags_steer_mech, tvb, offset, 4, ENC_LITTLE_ENDIAN);
            }
            offset+=4;
            length_remaining-=4;
            break;
        case PPI_ANTENNA_GAINDB:
            if (length_remaining < 1)
                break;
            gaindb=  tvb_get_guint8(tvb, offset);
            if (tree) {
                proto_tree_add_uint(ppi_antenna_tree, hf_ppi_antenna_gaindb, tvb, offset, 1, gaindb);
                proto_item_append_text(antenna_line, " Gain: %d", gaindb);

            }
            offset+=1;
            length_remaining-=1;
            break;
        case  PPI_ANTENNA_HORIZBW:
            if (length_remaining < 4)
                break;
            t_hbw = tvb_get_letohl(tvb, offset);
            horizbw =  ppi_fixed3_6_to_gdouble(t_hbw);
            if (tree) {
                proto_tree_add_double(ppi_antenna_tree, hf_ppi_antenna_horizbw, tvb, offset, 4, horizbw);
                proto_item_append_text(antenna_line, " HorizBw: %f", horizbw);
            }
            offset+=4;
            length_remaining-=4;
            break;
        case  PPI_ANTENNA_VERTBW:
            if (length_remaining < 4)
                break;
            t_vbw = tvb_get_letohl(tvb, offset);
            vertbw =  ppi_fixed3_6_to_gdouble(t_vbw);
            if (tree) {
                proto_tree_add_double(ppi_antenna_tree, hf_ppi_antenna_vertbw, tvb, offset, 4, vertbw);
            }
            offset+=4;
            length_remaining-=4;
            break;
        case  PPI_ANTENNA_PGAIN:
            if (length_remaining < 4)
                break;
            t_pgain = tvb_get_letohl(tvb, offset);
            pgain   = ppi_fixed3_6_to_gdouble(t_pgain);
            if (tree) {
                proto_tree_add_double(ppi_antenna_tree, hf_ppi_antenna_pgain, tvb, offset, 4, pgain);
            }
            offset+=4;
            length_remaining-=4;
            break;
        case  PPI_ANTENNA_BEAMID:
            if (length_remaining < 2)
                break;
            beamid= tvb_get_letohs(tvb, offset); /* convert endianess */
            if (tree) {
                proto_tree_add_uint(ppi_antenna_tree, hf_ppi_antenna_beamid, tvb, offset, 2, beamid);
            }
            offset+=2;
            length_remaining-=2;
            break;
        case  PPI_ANTENNA_SERIALNUM:
            if (length_remaining < 32)
                break;
            if (tree) {
                proto_tree_add_item(ppi_antenna_tree, hf_ppi_antenna_serialnum, tvb, offset, 32, ENC_ASCII|ENC_NA);
            }
            offset+=32;
            length_remaining-=32;
            break;

        case  PPI_ANTENNA_MODELSTR:
            if (length_remaining < 32)
                break;
            if (tree) {
                /* proto_tree_add_item(ppi_antenna_tree, hf_ppi_antenna_modelname, tvb, offset, 32, ENC_ASCII|ENC_NA); */
                curr_str = tvb_format_stringzpad(tvb, offset, 32);
                proto_tree_add_string(ppi_antenna_tree, hf_ppi_antenna_modelname, tvb, offset, 32, curr_str);
                proto_item_append_text(antenna_line, " (%s)", curr_str);
            }
            offset+=32;
            length_remaining-=32;
            break;
        case  PPI_ANTENNA_DESCSTR:
            if (length_remaining < 32)
                break;
            if (tree) {
                /*proto_tree_add_item(ppi_antenna_tree, hf_ppi_antenna_descstr, tvb, offset, 32, ENC_ASCII|ENC_NA);*/
                curr_str = tvb_format_stringzpad(tvb, offset, 32);
                proto_tree_add_string(ppi_antenna_tree, hf_ppi_antenna_descstr, tvb, offset, 32, curr_str);
                proto_item_append_text(antenna_line, " (%s)", curr_str);
            }
            offset+=32;
            length_remaining-=32;
            break;
        case  PPI_ANTENNA_APPID:
            if (length_remaining < 4)
                break;
            t_appspecific_num  = tvb_get_letohl(tvb, offset); /* application specific parsers may switch on this later */
            if (tree) {
                proto_tree_add_uint(ppi_antenna_tree, hf_ppi_antenna_appspecific_num, tvb, offset, 4, t_appspecific_num);
            }
            offset+=4;
            length_remaining-=4;
            break;
        case  PPI_ANTENNA_APPDATA:
            if (length_remaining < 60)
                break;
            if (tree) {
                proto_tree_add_item(ppi_antenna_tree, hf_ppi_antenna_appspecific_data, tvb, offset, 60,  ENC_NA);
            }
            offset+=60;
            length_remaining-=60;
            break;
        default:
            /*
             * This indicates a field whose size we do not
             * know, so we cannot proceed.
             */
            proto_tree_add_text(ppi_antenna_tree, tvb, offset, 0,
                                "Error: PPI-ANTENNA: unknown bit (%d) set in present field.\n", bit);
            next_present = 0;
            continue;
        }

    };
    return;
}
Esempio n. 5
0
static void
dissect_ipxsap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
	proto_tree	*sap_tree, *s_tree;
	proto_item	*ti, *hidden_item;
	int		cursor;
	struct sap_query query;
	guint16		server_type;
	gchar		*server_name;
	guint16		server_port;
	guint16		intermediate_network;

	static const char	*sap_type[4] = { "General Query", "General Response",
		"Nearest Query", "Nearest Response" };

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

	query.query_type = tvb_get_ntohs(tvb, 0);
	query.server_type = tvb_get_ntohs(tvb, 2);

	if (check_col(pinfo->cinfo, COL_INFO)) {
		if (query.query_type >= 1 && query.query_type <= 4) {
			col_set_str(pinfo->cinfo, COL_INFO, sap_type[query.query_type - 1]);
		}
		else {
			col_set_str(pinfo->cinfo, COL_INFO, "Unknown Packet Type");
		}
	}

	if (tree) {
		ti = proto_tree_add_item(tree, proto_sap, tvb, 0, -1, ENC_NA);
		sap_tree = proto_item_add_subtree(ti, ett_ipxsap);

		if (query.query_type >= 1 && query.query_type <= 4) {
			proto_tree_add_text(sap_tree, tvb, 0, 2, "%s", sap_type[query.query_type - 1]);
			if ((query.query_type - 1) % 2) {
			  hidden_item = proto_tree_add_boolean(sap_tree,
						     hf_sap_response,
						     tvb, 0, 2, 1);
			} else {
			  hidden_item = proto_tree_add_boolean(sap_tree,
						     hf_sap_request,
						     tvb, 0, 2, 1);
			}
			PROTO_ITEM_SET_HIDDEN(hidden_item);
		}
		else {
			proto_tree_add_text(sap_tree, tvb, 0, 2,
					"Unknown SAP Packet Type %d", query.query_type);
		}

		if (query.query_type == IPX_SAP_GENERAL_RESPONSE ||
				query.query_type == IPX_SAP_NEAREST_RESPONSE) { /* responses */

			int available_length = tvb_reported_length(tvb);
			for (cursor =  2; (cursor + 64) <= available_length; cursor += 64) {
				server_type = tvb_get_ntohs(tvb, cursor);
				server_name = tvb_format_stringzpad(tvb, cursor+2, 48);

				ti = proto_tree_add_text(sap_tree, tvb, cursor+2, 48,
					"Server Name: %s", server_name);
				s_tree = proto_item_add_subtree(ti, ett_ipxsap_server);

				proto_tree_add_text(s_tree, tvb, cursor, 2, "Server Type: %s (0x%04X)",
				    val_to_str_ext_const(server_type, &novell_server_vals_ext, "Unknown"),
				    server_type);
				proto_tree_add_text(s_tree, tvb, cursor+50, 4, "Network: %s",
						ipxnet_to_string(tvb_get_ptr(tvb, cursor+50, 4)));
				proto_tree_add_text(s_tree, tvb, cursor+54, 6, "Node: %s",
						tvb_ether_to_str(tvb, cursor+54));
				server_port = tvb_get_ntohs(tvb, cursor+60);
				proto_tree_add_text(s_tree, tvb, cursor+60, 2, "Socket: %s (0x%04x)",
						socket_text(server_port),
						server_port);
				intermediate_network = tvb_get_ntohs(tvb, cursor+62);
				proto_tree_add_text(s_tree, tvb, cursor+62, 2,
						"Intermediate Networks: %d",
						intermediate_network);
			}
		}
		else {  /* queries */
			proto_tree_add_text(sap_tree, tvb, 2, 2, "Server Type: %s (0x%04X)",
				val_to_str_ext_const(query.server_type, &novell_server_vals_ext, "Unknown"),
				query.server_type);
		}
	}
}
Esempio n. 6
0
static void
dissect_ppi_gps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
    /* These are locals used for processing the current tvb */
    guint length;
    gint  length_remaining;
    int offset = 0;

    proto_tree *ppi_gps_tree = NULL;
    proto_tree *pt, *present_tree = NULL;
    proto_tree *my_pt, *gpsflags_flags_tree = NULL; /* used for DeviceType bitmask stuff */

    proto_item *ti = NULL;
    proto_item *gps_line = NULL;


    /* bits */
    int bit;
    guint32 present, next_present;
    /* values actually read out, for displaying */
    guint32 version, gpsflags_flags;
    gdouble lat, lon, alt, alt_gnd;
    nstime_t gps_timestamp;
    int gps_time_size, already_processed_fractime; /* we use this internally to track if this is a 4 or 8 byte wide timestamp */
    gdouble eph, epv, ept;
    gchar *curr_str;


    /* these are temporary intermediate values, used in the individual cases below */
    guint32 t_lat, t_lon, t_alt, t_alt_gnd;
    guint32 t_herr, t_verr, t_terr;
    guint32 t_appspecific_num;
    /* initialize the timestamp value(s) */
    gps_timestamp.secs = gps_timestamp.nsecs = already_processed_fractime = 0;

    /* Clear out stuff in the info column */
    col_clear(pinfo->cinfo,COL_INFO);

    /* pull out the first three fields of the BASE-GEOTAG-HEADER */
    version = tvb_get_guint8(tvb, offset);
    length  = tvb_get_letohs(tvb, offset+2);
    present = tvb_get_letohl(tvb, offset+4);

    /* Setup basic column info */
    col_add_fstr(pinfo->cinfo, COL_INFO, "PPI_GPS Capture v%u, Length %u", version, length);

    /* Create the basic dissection tree*/
    if (tree) {
        ti = proto_tree_add_protocol_format(tree, proto_ppi_gps, tvb, 0, length, "GPS:");
        gps_line = ti; /*we will make this more useful if we hit lon/lat later */
        ppi_gps_tree= proto_item_add_subtree(ti, ett_ppi_gps);
        proto_tree_add_uint(ppi_gps_tree, hf_ppi_gps_version, tvb, offset, 1, version);
        proto_tree_add_item(ppi_gps_tree, hf_ppi_gps_pad, tvb, offset + 1, 1, ENC_NA);
        ti = proto_tree_add_uint(ppi_gps_tree, hf_ppi_gps_length, tvb, offset + 2, 2, length);
    }

    /* We support v1 and v2 of GPS tags (identical) */
    if (! (version == 1 || version == 2) ) {
        if (tree)
            proto_item_append_text(ti, "invalid version (got %d,  expected 1 or 2)", version);
        return;
    }

    /* initialize the length of the actual tag contents */
    length_remaining = length;
    /* minimum length check, should atleast be a fixed-size geotagging-base header*/
    if (length_remaining < PPI_GEOBASE_MIN_HEADER_LEN) {
        /*
         * Base-geotag-header (Radiotap lookalike) is shorter than the fixed-length portion
         * plus one "present" bitset.
         */
        if (tree)
            proto_item_append_text(ti, " (invalid - minimum length is 8)");
        return;
    }

    /* perform tag-specific max length sanity checking */
    if (length > PPI_GPS_MAXTAGLEN ) {
        if (tree)
            proto_item_append_text(ti, "Invalid PPI-GPS length  (got %d, %d max\n)", length, PPI_GPS_MAXTAGLEN);
        return;
    }

    /* Subtree for the "present flags" bitfield. */
    if (tree) {
        pt = proto_tree_add_uint(ppi_gps_tree, hf_ppi_gps_present, tvb, offset + 4, 4, present);
        present_tree = proto_item_add_subtree(pt, ett_ppi_gps_present);

        proto_tree_add_item(present_tree, hf_ppi_gps_present_gpsflags_flags, tvb, 4, 4, ENC_LITTLE_ENDIAN);
        proto_tree_add_item(present_tree, hf_ppi_gps_present_lat, tvb, 4, 4, ENC_LITTLE_ENDIAN);
        proto_tree_add_item(present_tree, hf_ppi_gps_present_lon, tvb, 4, 4, ENC_LITTLE_ENDIAN);
        proto_tree_add_item(present_tree, hf_ppi_gps_present_alt, tvb, 4, 4, ENC_LITTLE_ENDIAN);
        proto_tree_add_item(present_tree, hf_ppi_gps_present_alt_gnd, tvb, 4, 4, ENC_LITTLE_ENDIAN);
        proto_tree_add_item(present_tree, hf_ppi_gps_present_gpstime, tvb, 4, 4, ENC_LITTLE_ENDIAN);
        proto_tree_add_item(present_tree, hf_ppi_gps_present_fractime, tvb, 4, 4, ENC_LITTLE_ENDIAN);
        proto_tree_add_item(present_tree, hf_ppi_gps_present_eph, tvb, 4, 4, ENC_LITTLE_ENDIAN);
        proto_tree_add_item(present_tree, hf_ppi_gps_present_epv, tvb, 4, 4, ENC_LITTLE_ENDIAN);
        proto_tree_add_item(present_tree, hf_ppi_gps_present_ept, tvb, 4, 4, ENC_LITTLE_ENDIAN);
        proto_tree_add_item(present_tree, hf_ppi_gps_present_descr, tvb, 4, 4, ENC_LITTLE_ENDIAN);
        proto_tree_add_item(present_tree, hf_ppi_gps_present_appspecific_num, tvb, 4, 4, ENC_LITTLE_ENDIAN);
        proto_tree_add_item(present_tree, hf_ppi_gps_present_appspecific_data, tvb, 4, 4, ENC_LITTLE_ENDIAN);
        proto_tree_add_item(present_tree, hf_ppi_gps_present_ext, tvb, 4, 4, ENC_LITTLE_ENDIAN);
    }
    offset += PPI_GEOBASE_MIN_HEADER_LEN;
    length_remaining -= PPI_GEOBASE_MIN_HEADER_LEN;

    /* The fixed BASE-GEOTAG-HEADER has been handled at this point. move on to the individual fields */
    for (; present; present = next_present) {
        /* clear the least significant bit that is set */
        next_present = present & (present - 1);
        /* extract the least significant bit that is set */
        bit = BITNO_32(present ^ next_present);
        switch (bit) {
        case PPI_GEOTAG_GPSFLAGS:
            if (length_remaining < 4)
                break;
            gpsflags_flags =   tvb_get_letohl(tvb, offset); /* retrieve 32-bit gpsflags bitmask (-not- present bitmask) */
            if (tree) {
                /* first we add the hex flags line */
                my_pt = proto_tree_add_uint(ppi_gps_tree, hf_ppi_gps_gpsflags_flags, tvb, offset , 4, gpsflags_flags);
                /* then we add a subtree */
                gpsflags_flags_tree = proto_item_add_subtree(my_pt, ett_ppi_gps_gpsflags_flags);
                /* to pin the individual bits on */
                proto_tree_add_item(gpsflags_flags_tree, hf_ppi_gps_gpsflags_flag0_nofix, tvb, offset, 4, ENC_LITTLE_ENDIAN);
                proto_tree_add_item(gpsflags_flags_tree, hf_ppi_gps_gpsflags_flag1_gpsfix, tvb, offset, 4, ENC_LITTLE_ENDIAN);
                proto_tree_add_item(gpsflags_flags_tree, hf_ppi_gps_gpsflags_flag2_diffgps, tvb, offset, 4, ENC_LITTLE_ENDIAN);
                proto_tree_add_item(gpsflags_flags_tree, hf_ppi_gps_gpsflags_flag3_PPS, tvb, offset, 4, ENC_LITTLE_ENDIAN);
                proto_tree_add_item(gpsflags_flags_tree, hf_ppi_gps_gpsflags_flag4_RTK, tvb, offset, 4, ENC_LITTLE_ENDIAN);
                proto_tree_add_item(gpsflags_flags_tree, hf_ppi_gps_gpsflags_flag5_floatRTK, tvb, offset, 4, ENC_LITTLE_ENDIAN);
                proto_tree_add_item(gpsflags_flags_tree, hf_ppi_gps_gpsflags_flag6_dead_reck, tvb, offset, 4, ENC_LITTLE_ENDIAN);
                proto_tree_add_item(gpsflags_flags_tree, hf_ppi_gps_gpsflags_flag7_manual, tvb, offset, 4, ENC_LITTLE_ENDIAN);
                proto_tree_add_item(gpsflags_flags_tree, hf_ppi_gps_gpsflags_flag8_sim, tvb, offset, 4, ENC_LITTLE_ENDIAN);
            }
            offset+=4;
            length_remaining-=4;
            break;
        case  PPI_GEOTAG_LAT:
            if (length_remaining < 4)
                break;
            t_lat = tvb_get_letohl(tvb, offset);
            lat =  ppi_fixed3_7_to_gdouble(t_lat);
            if (tree)
            {
                proto_tree_add_double(ppi_gps_tree, hf_ppi_gps_lat, tvb, offset, 4, lat);
                proto_item_append_text(gps_line, " Lat:%f ", lat);
            }
            offset+=4;
            length_remaining-=4;
            break;
        case  PPI_GEOTAG_LON:
            if (length_remaining < 4)
                break;
            t_lon = tvb_get_letohl(tvb, offset);
            lon =  ppi_fixed3_7_to_gdouble(t_lon);
            if (tree)
            {
                proto_tree_add_double(ppi_gps_tree, hf_ppi_gps_lon, tvb, offset, 4, lon);
                proto_item_append_text(gps_line, " Lon:%f ", lon);
            }
            offset+=4;
            length_remaining-=4;
            break;
        case  PPI_GEOTAG_ALT:
            if (length_remaining < 4)
                break;
            t_alt = tvb_get_letohl(tvb, offset);
            alt = ppi_fixed6_4_to_gdouble(t_alt);
            if (tree)
            {
                proto_tree_add_double(ppi_gps_tree, hf_ppi_gps_alt, tvb, offset, 4, alt);
                proto_item_append_text(gps_line, " Alt:%f ", alt);
            }
            offset+=4;
            length_remaining-=4;
            break;
        case  PPI_GEOTAG_ALT_G:
            if (length_remaining < 4)
                break;
            t_alt_gnd = tvb_get_letohl(tvb, offset);
            alt_gnd = ppi_fixed6_4_to_gdouble(t_alt_gnd);
            if (tree)
            {
                proto_tree_add_double(ppi_gps_tree, hf_ppi_gps_alt_gnd, tvb, offset, 4, alt_gnd);
                proto_item_append_text(gps_line, " Alt_g:%f ", alt_gnd);
            }
            offset+=4;
            length_remaining-=4;
            break;
        case  PPI_GEOTAG_GPSTIME:
            if (length_remaining < 4)
                break;
            gps_timestamp.secs =    tvb_get_letohl(tvb, offset);
            gps_timestamp.nsecs = 0;
            gps_time_size = 4;
            /* This is somewhat tricky, inside the GPSTIME case we test if the optional fractional time */
            /* is present. If so, we pull it out, and combine it with GPSTime. */
            /* If we do this, we set already_processed_fractime to avoid hitting it below */
            if (length_remaining < 4 && (present & PPI_GPS_MASK_FRACTIME))
                break;
            else if (present & PPI_GPS_MASK_FRACTIME) {
                gps_timestamp.nsecs =  tvb_get_letohl(tvb, offset + 4); /* manually offset seconds */
                already_processed_fractime = 1;
                gps_time_size = 8;
            }
            if (tree) {
                proto_tree_add_time(ppi_gps_tree, hf_ppi_gps_gpstime, tvb, offset, gps_time_size, &gps_timestamp);
            }
            offset += gps_time_size;
            length_remaining -= gps_time_size;
            break;
        case  PPI_GEOTAG_FRACTIONALTIME:
            if (length_remaining < 4)
                break;
            if (already_processed_fractime)
                break;
            break;
        case  PPI_GEOTAG_EPH:
            if (length_remaining < 4)
                break;
            t_herr = tvb_get_letohl(tvb, offset);
            eph  =  ppi_fixed3_6_to_gdouble(t_herr);
            if (tree)
                proto_tree_add_double(ppi_gps_tree, hf_ppi_gps_eph, tvb, offset, 4, eph);
            offset+=4;
            length_remaining-=4;
            break;
        case  PPI_GEOTAG_EPV:
            if (length_remaining < 4)
                break;
            t_verr = tvb_get_letohl(tvb, offset);
            epv  =  ppi_fixed3_6_to_gdouble(t_verr);
            if (tree)
                proto_tree_add_double(ppi_gps_tree, hf_ppi_gps_epv, tvb, offset, 4, epv);
            offset+=4;
            length_remaining-=4;
            break;
        case  PPI_GEOTAG_EPT:
            if (length_remaining < 4)
                break;
            t_terr = tvb_get_letohl(tvb, offset);
            ept  =  ppi_ns_counter_to_gdouble(t_terr);
            if (tree)
                proto_tree_add_double(ppi_gps_tree, hf_ppi_gps_ept, tvb, offset, 4, ept);
            offset+=4;
            length_remaining-=4;
            break;
        case  PPI_GEOTAG_DESCRIPTIONSTR:
            if (length_remaining < 32)
                break;
            if (tree)
            {
                /* proto_tree_add_item(ppi_gps_tree, hf_ppi_gps_descstr, tvb, offset, 32,  ENC_ASCII|ENC_NA); */
                curr_str = tvb_format_stringzpad(tvb, offset, 32); /* need to append_text this */
                proto_tree_add_string(ppi_gps_tree, hf_ppi_gps_descstr, tvb, offset, 32, curr_str);
                proto_item_append_text(gps_line, " (%s)", curr_str);
            }
            offset+=32;
            length_remaining-=32;
            break;
        case  PPI_GEOTAG_APPID:
            if (length_remaining < 4)
                break;
            t_appspecific_num  = tvb_get_letohl(tvb, offset); /* application specific parsers may switch on this later */
            if (tree) {
                proto_tree_add_uint(ppi_gps_tree, hf_ppi_gps_appspecific_num, tvb, offset, 4, t_appspecific_num);
            }
            offset+=4;
            length_remaining-=4;
            break;
        case  PPI_GEOTAG_APPDATA:
            if (length_remaining < 60)
                break;
            if (tree) {
                proto_tree_add_item(ppi_gps_tree, hf_ppi_gps_appspecific_data, tvb, offset, 60,  ENC_NA);
            }
            offset+=60;
            length_remaining-=60;
            break;

            /*
             * This indicates a field whose size we do not know, so we cannot proceed.
             */
        default:
            next_present = 0; /* this will terminate the loop */
            proto_tree_add_text(ppi_gps_tree, tvb, offset, 0,  "Error: PPI-GEOLOCATION-GPS: unknown bit (%d) set in present field.\n", bit);
            continue;
        } /* switch (bit) */

    } /* (for present..)*/

    /* If there was any post processing of the elements, it could happen here. */
    return;
}
Esempio n. 7
0
static void dissect_tftp_message(tftp_conv_info_t *tftp_info,
				 tvbuff_t *tvb, packet_info *pinfo,
				 proto_tree *tree)
{
	proto_tree	 *tftp_tree = NULL;
	proto_item	 *ti;
	gint		 offset = 0;
	guint16		 opcode;
	guint16		 bytes;
	guint16		 blocknum;
	guint		 i1;
	guint16	         error;

	col_set_str(pinfo->cinfo, COL_PROTOCOL, "TFTP");

	opcode = tvb_get_ntohs(tvb, offset);

	col_add_str(pinfo->cinfo, COL_INFO,
		    val_to_str(opcode, tftp_opcode_vals, "Unknown (0x%04x)"));

	if (tree) {
	  ti = proto_tree_add_item(tree, proto_tftp, tvb, offset, -1, ENC_NA);
	  tftp_tree = proto_item_add_subtree(ti, ett_tftp);

	  if (tftp_info->source_file) {
	    ti = proto_tree_add_string(tftp_tree, hf_tftp_source_file, tvb,
				       0, 0, tftp_info->source_file);
	    PROTO_ITEM_SET_GENERATED(ti);
	  }

	  if (tftp_info->destination_file) {
	    ti = proto_tree_add_string(tftp_tree, hf_tftp_destination_file, tvb,
				       0, 0, tftp_info->destination_file);
	    PROTO_ITEM_SET_GENERATED(ti);
	  }

	  proto_tree_add_uint(tftp_tree, hf_tftp_opcode, tvb,
			      offset, 2, opcode);
	}
	offset += 2;

	switch (opcode) {

	case TFTP_RRQ:
	  i1 = tvb_strsize(tvb, offset);
	  proto_tree_add_item(tftp_tree, hf_tftp_source_file,
			      tvb, offset, i1, ENC_ASCII|ENC_NA);

	  tftp_info->source_file = tvb_get_string(wmem_file_scope(), tvb, offset, i1);

	  col_append_fstr(pinfo->cinfo, COL_INFO, ", File: %s",
			  tvb_format_stringzpad(tvb, offset, i1));

	  offset += i1;

	  i1 = tvb_strsize(tvb, offset);
	  proto_tree_add_item(tftp_tree, hf_tftp_transfer_type,
			      tvb, offset, i1, ENC_ASCII|ENC_NA);

	  col_append_fstr(pinfo->cinfo, COL_INFO, ", Transfer type: %s",
			  tvb_format_stringzpad(tvb, offset, i1));

	  offset += i1;

	  tftp_dissect_options(tvb, pinfo,  offset, tftp_tree,
			       opcode, tftp_info);
	  break;

	case TFTP_WRQ:
	  i1 = tvb_strsize(tvb, offset);
	  proto_tree_add_item(tftp_tree, hf_tftp_destination_file,
			      tvb, offset, i1, ENC_ASCII|ENC_NA);

	  tftp_info->destination_file =
	    tvb_get_string(wmem_file_scope(), tvb, offset, i1);

	  col_append_fstr(pinfo->cinfo, COL_INFO, ", File: %s",
			  tvb_format_stringzpad(tvb, offset, i1));

	  offset += i1;

	  i1 = tvb_strsize(tvb, offset);
	  proto_tree_add_item(tftp_tree, hf_tftp_transfer_type,
			           tvb, offset, i1, ENC_ASCII|ENC_NA);

	  col_append_fstr(pinfo->cinfo, COL_INFO, ", Transfer type: %s",
			  tvb_format_stringzpad(tvb, offset, i1));

	  offset += i1;

	  tftp_dissect_options(tvb, pinfo, offset, tftp_tree,
			       opcode,  tftp_info);
	  break;

	case TFTP_INFO:
	  tftp_dissect_options(tvb, pinfo, offset, tftp_tree,
			       opcode,  tftp_info);
	  break;

	case TFTP_DATA:
	  blocknum = tvb_get_ntohs(tvb, offset);
	  proto_tree_add_uint(tftp_tree, hf_tftp_blocknum, tvb, offset, 2,
			      blocknum);

	  offset += 2;

	  bytes = tvb_reported_length_remaining(tvb, offset);

	  col_append_fstr(pinfo->cinfo, COL_INFO, ", Block: %i%s",
			  blocknum,
			  (bytes < tftp_info->blocksize)?" (last)":"" );

	  if (bytes != 0) {
	    tvbuff_t *data_tvb = tvb_new_subset(tvb, offset, -1, bytes);
	    call_dissector(data_handle, data_tvb, pinfo, tree);
	  }
	  break;

	case TFTP_ACK:
	  blocknum = tvb_get_ntohs(tvb, offset);
	  proto_tree_add_uint(tftp_tree, hf_tftp_blocknum, tvb, offset, 2,
			      blocknum);

	  col_append_fstr(pinfo->cinfo, COL_INFO, ", Block: %i",
			  blocknum);
	  break;

	case TFTP_ERROR:
	  error = tvb_get_ntohs(tvb, offset);
	  proto_tree_add_uint(tftp_tree, hf_tftp_error_code, tvb, offset, 2,
			      error);

	  col_append_fstr(pinfo->cinfo, COL_INFO, ", Code: %s",
			  val_to_str(error, tftp_error_code_vals, "Unknown (%u)"));

	  offset += 2;

	  i1 = tvb_strsize(tvb, offset);
	  proto_tree_add_item(tftp_tree, hf_tftp_error_string, tvb, offset,
			      i1, ENC_ASCII|ENC_NA);

	  col_append_fstr(pinfo->cinfo, COL_INFO, ", Message: %s",
			  tvb_format_stringzpad(tvb, offset, i1));

	  expert_add_info(pinfo, NULL, &ei_tftp_blocksize_range);
	  break;

	case TFTP_OACK:
	  tftp_dissect_options(tvb, pinfo, offset, tftp_tree,
			       opcode, tftp_info);
	  break;

	default:
	  proto_tree_add_text(tftp_tree, tvb, offset, -1,
			      "Data (%d bytes)", tvb_reported_length_remaining(tvb, offset));
	  break;

	}

  return;
}