Make the "Save only marked frames" button in the "Save As..." dialog box
[obnox/wireshark/wip.git] / packet-tftp.c
index bc9e11b09acfec490fad605c5be6328a7b1c1902..5aec3d5bdf1aae28e8dc65a8c720bcb5bcf3421f 100644 (file)
@@ -5,10 +5,10 @@
  * Craig Newell <CraigN@cheque.uq.edu.au>
  *     RFC2347 TFTP Option Extension
  *
- * $Id: packet-tftp.c,v 1.17 2000/11/13 08:58:17 guy Exp $
+ * $Id: packet-tftp.c,v 1.33 2001/12/03 03:59:40 guy Exp $
  *
  * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@zing.org>
+ * By Gerald Combs <gerald@ethereal.com>
  * Copyright 1998 Gerald Combs
  *
  * Copied from packet-bootp.c
@@ -55,23 +55,25 @@ static int hf_tftp_error_string = -1;
 
 static gint ett_tftp = -1;
 
+static dissector_handle_t tftp_handle;
+
 #define UDP_PORT_TFTP    69
 
-#define        RRQ     1
-#define        WRQ     2
-#define        DATA    3
-#define        ACK     4
-#define        ERROR   5
-#define OACK   6
+#define        TFTP_RRQ        1
+#define        TFTP_WRQ        2
+#define        TFTP_DATA       3
+#define        TFTP_ACK        4
+#define        TFTP_ERROR      5
+#define        TFTP_OACK       6
 
 static const value_string tftp_opcode_vals[] = {
-  { RRQ,   "Read Request" },
-  { WRQ,   "Write Request" },
-  { DATA,  "Data Packet" },
-  { ACK,   "Acknowledgement" },
-  { ERROR, "Error Code" },
-  { OACK,  "Option Acknowledgement" },
-  { 0,     NULL }
+  { TFTP_RRQ,   "Read Request" },
+  { TFTP_WRQ,   "Write Request" },
+  { TFTP_DATA,  "Data Packet" },
+  { TFTP_ACK,   "Acknowledgement" },
+  { TFTP_ERROR, "Error Code" },
+  { TFTP_OACK,  "Option Acknowledgement" },
+  { 0,          NULL }
 };
 
 static const value_string tftp_error_code_vals[] = {
@@ -91,14 +93,13 @@ static void tftp_dissect_options(tvbuff_t *tvb, int offset, proto_tree *tree);
 static void
 dissect_tftp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
-       proto_tree      *tftp_tree;
+       proto_tree      *tftp_tree = NULL;
        proto_item      *ti;
        conversation_t  *conversation;
        gint            offset = 0;
        guint16         opcode;
        u_int           i1;
-
-       CHECK_DISPLAY_AS_DATA(proto_tftp, tvb, pinfo, tree);
+       guint16         error;
 
        /*
         * The first TFTP packet goes to the TFTP port; the second one
@@ -108,31 +109,34 @@ dissect_tftp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
         * and ports.
         *
         * If this packet went to the TFTP port, we check to see if
-        * there's already a conversation with the source IP address
-        * and port of this packet, the destination IP address of this
-        * packet, and any destination UDP port.  If not, we create
-        * one, with a wildcard UDP port, and give it the TFTP dissector
-        * as a dissector.
+        * there's already a conversation with one address/port pair
+        * matching the source IP address and port of this packet,
+        * the other address matching the destination IP address of this
+        * packet, and any destination port.
+        *
+        * If not, we create one, with its address 1/port 1 pair being
+        * the source address/port of this packet, its address 2 being
+        * the destination address of this packet, and its port 2 being
+        * wildcarded, and give it the TFTP dissector as a dissector.
         */
        if (pinfo->destport == UDP_PORT_TFTP) {
          conversation = find_conversation(&pinfo->src, &pinfo->dst, PT_UDP,
-                                          pinfo->srcport, 0, NO_DST_PORT);
+                                          pinfo->srcport, 0, NO_PORT_B);
          if (conversation == NULL) {
            conversation = conversation_new(&pinfo->src, &pinfo->dst, PT_UDP,
-                                           pinfo->srcport, 0, NULL,
-                                           NO_DST_PORT);
-           conversation_set_dissector(conversation, dissect_tftp);
+                                           pinfo->srcport, 0, NO_PORT2);
+           conversation_set_dissector(conversation, tftp_handle);
          }
        }
 
        if (check_col(pinfo->fd, COL_PROTOCOL))
-               col_add_str(pinfo->fd, COL_PROTOCOL, "TFTP");
+               col_set_str(pinfo->fd, COL_PROTOCOL, "TFTP");
 
        opcode = tvb_get_ntohs(tvb, offset);
 
        if (check_col(pinfo->fd, COL_INFO)) {
 
-         col_add_fstr(pinfo->fd, COL_INFO, "TFTP %s",
+         col_add_fstr(pinfo->fd, COL_INFO, "%s",
            val_to_str(opcode, tftp_opcode_vals, "Unknown (0x%04x)"));
 
        }
@@ -145,64 +149,127 @@ dissect_tftp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 
          proto_tree_add_uint(tftp_tree, hf_tftp_opcode, tvb,
                            offset, 2, opcode);
-         offset += 2;
+       }
+       offset += 2;
            
-         switch (opcode) {
-         case RRQ:
-           i1 = tvb_strnlen(tvb, offset, -1);
+       switch (opcode) {
+
+       case TFTP_RRQ:
+         i1 = tvb_strsize(tvb, offset);
+         if (tree) {
            proto_tree_add_item(tftp_tree, hf_tftp_source_file,
-                           tvb, offset, i1 + 1, FALSE);
-           offset += i1 + 1;
+                           tvb, offset, i1, FALSE);
+         }
+         if (check_col(pinfo->fd, COL_INFO)) {
+           col_append_fstr(pinfo->fd, COL_INFO, ", File: %s",
+                           tvb_get_ptr(tvb, offset, i1));
+         }
+         offset += i1;
 
-           i1 = tvb_strnlen(tvb, offset, -1);
+         i1 = tvb_strsize(tvb, offset);
+         if (tree) {
            ti = proto_tree_add_item(tftp_tree, hf_tftp_transfer_type,
-                           tvb, offset, i1 + 1, FALSE);
-           offset += i1 + 1;
+                           tvb, offset, i1, FALSE);
+         }
+         if (check_col(pinfo->fd, COL_INFO)) {
+           col_append_fstr(pinfo->fd, COL_INFO, ", Transfer type: %s",
+                           tvb_get_ptr(tvb, offset, i1));
+         }
+         offset += i1;
 
+         if (tree)
            tftp_dissect_options(tvb, offset, tftp_tree);
-           break;
-         case WRQ:
-           i1 = tvb_strnlen(tvb, offset, -1);
+         break;
+
+       case TFTP_WRQ:
+         i1 = tvb_strsize(tvb, offset);
+         if (tree) {
            proto_tree_add_item(tftp_tree, hf_tftp_destination_file,
-                           tvb, offset, i1 + 1, FALSE);
-           offset += i1 + 1;
+                           tvb, offset, i1, FALSE);
+         }
+         if (check_col(pinfo->fd, COL_INFO)) {
+           col_append_fstr(pinfo->fd, COL_INFO, ", File: %s",
+                           tvb_get_ptr(tvb, offset, i1));
+         }
+         offset += i1;
 
-           i1 = tvb_strnlen(tvb, offset, -1);
+         i1 = tvb_strsize(tvb, offset);
+         if (tree) {
            ti = proto_tree_add_item(tftp_tree, hf_tftp_transfer_type,
-                           tvb, offset, i1 + 1, FALSE);
-           offset += i1 + 1;
+                           tvb, offset, i1, FALSE);
+         }
+         if (check_col(pinfo->fd, COL_INFO)) {
+           col_append_fstr(pinfo->fd, COL_INFO, ", Transfer type: %s",
+                           tvb_get_ptr(tvb, offset, i1));
+         }
+         offset += i1;
 
+         if (tree)
            tftp_dissect_options(tvb, offset, tftp_tree);
-           break;
-         case DATA:
+         break;
+
+       case TFTP_DATA:
+         if (tree) {
            proto_tree_add_item(tftp_tree, hf_tftp_blocknum, tvb, offset, 2,
                            FALSE);
-           offset += 2;
+         }
+         if (check_col(pinfo->fd, COL_INFO)) {
+           col_append_fstr(pinfo->fd, COL_INFO, ", Block: %i",
+                           tvb_get_ntohs(tvb, offset));
+         }
+         offset += 2;
 
+         if (tree) {
            proto_tree_add_text(tftp_tree, tvb, offset, tvb_length_remaining(tvb, offset),
                "Data (%d bytes)", tvb_length_remaining(tvb, offset));
-           break;
-         case ACK:
+         }
+         break;
+
+       case TFTP_ACK:
+         if (tree) {
            proto_tree_add_item(tftp_tree, hf_tftp_blocknum, tvb, offset, 2,
                            FALSE);
-           break;
-         case ERROR:
-           proto_tree_add_item(tftp_tree, hf_tftp_error_code, tvb, offset, 2,
-                           FALSE);
-           offset += 2;
+         }
+         if (check_col(pinfo->fd, COL_INFO)) {
+           col_append_fstr(pinfo->fd, COL_INFO, ", Block: %i",
+                           tvb_get_ntohs(tvb, offset));
+         }
+         break;
+
+       case TFTP_ERROR:
+         error = tvb_get_ntohs(tvb, offset);
+         if (tree) {
+           proto_tree_add_uint(tftp_tree, hf_tftp_error_code, tvb, offset, 2,
+                           error);
+         }
+         if (check_col(pinfo->fd, COL_INFO)) {
+           col_append_fstr(pinfo->fd, COL_INFO, ", Code: %s",
+                           val_to_str(error, tftp_error_code_vals, "Unknown (%u)"));
+         }
+         offset += 2;
 
-           i1 = tvb_strnlen(tvb, offset, -1);
+         i1 = tvb_strsize(tvb, offset);
+         if (tree) {
            proto_tree_add_item(tftp_tree, hf_tftp_error_string, tvb, offset,
-               i1 + 1, FALSE);
-           break;
-         case OACK:
+               i1, FALSE);
+         }
+         if (check_col(pinfo->fd, COL_INFO)) {
+           col_append_fstr(pinfo->fd, COL_INFO, ", Message: %s",
+                           tvb_get_ptr(tvb, offset, i1));
+         }
+         break;
+
+       case TFTP_OACK:
+         if (tree)
            tftp_dissect_options(tvb, offset, tftp_tree);
-           break;
-         default:
+         break;
+
+       default:
+         if (tree) {
            proto_tree_add_text(tftp_tree, tvb, offset, tvb_length_remaining(tvb, offset),
                "Data (%d bytes)", tvb_length_remaining(tvb, offset));
-           break;
          }
+         break;
 
        }
 }
@@ -210,16 +277,18 @@ dissect_tftp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 static void
 tftp_dissect_options(tvbuff_t *tvb, int offset, proto_tree *tree)
 {
-       int i1, i2;
+       int option_len, value_len;
+       int value_offset;
 
        while (tvb_offset_exists(tvb, offset)) {
-         i1 = tvb_strnlen(tvb, offset, -1);    /* length of option */
-         i2 = tvb_strnlen(tvb, offset+i1+1, -1);       /* length of value */
-         proto_tree_add_text(tree, tvb, offset, i1+i2+2,
-                 "Option: %.*s = %.*s",
-                 i1, tvb_get_ptr(tvb, offset, i1),
-                 i2, tvb_get_ptr(tvb, offset+i1+1, i2));
-         offset += i1 + i2 + 2;
+         option_len = tvb_strsize(tvb, offset);        /* length of option */
+         value_offset = offset + option_len;
+         value_len = tvb_strsize(tvb, value_offset);   /* length of value */
+         proto_tree_add_text(tree, tvb, offset, option_len+value_len,
+                 "Option: %s = %s",
+                 tvb_get_ptr(tvb, offset, option_len),
+                 tvb_get_ptr(tvb, value_offset, value_len));
+         offset += option_len + value_len;
        }
 }
 
@@ -230,49 +299,52 @@ proto_register_tftp(void)
     { &hf_tftp_opcode,
       { "Opcode",            "tftp.opcode",
        FT_UINT16, BASE_DEC, VALS(tftp_opcode_vals), 0x0,
-       "TFTP message type" }},
+       "TFTP message type", HFILL }},
 
     { &hf_tftp_source_file,
       { "Source File",       "tftp.source_file",
        FT_STRINGZ, BASE_DEC, NULL, 0x0,
-       "TFTP source file name" }},
+       "TFTP source file name", HFILL }},
 
     { &hf_tftp_destination_file,
       { "DESTINATION File",   "tftp.destination_file",
        FT_STRINGZ, BASE_DEC, NULL, 0x0,
-       "TFTP source file name" }},
+       "TFTP source file name", HFILL }},
 
     { &hf_tftp_transfer_type,
       { "Type",                      "tftp.type",
        FT_STRINGZ, BASE_DEC, NULL, 0x0,
-       "TFTP transfer type" }},
+       "TFTP transfer type", HFILL }},
 
     { &hf_tftp_blocknum,
       { "Block",              "tftp.block",
        FT_UINT16, BASE_DEC, NULL, 0x0,
-       "Block number" }},
+       "Block number", HFILL }},
 
     { &hf_tftp_error_code,
       { "Error code",         "tftp.error.code",
        FT_UINT16, BASE_DEC, VALS(tftp_error_code_vals), 0x0,
-       "Error code in case of TFTP error message" }},
+       "Error code in case of TFTP error message", HFILL }},
 
     { &hf_tftp_error_string,
       { "Error message",      "tftp.error.message",
        FT_STRINGZ, BASE_DEC, NULL, 0x0,
-       "Error string in case of TFTP error message" }}
+       "Error string in case of TFTP error message", HFILL }}
   };
   static gint *ett[] = {
     &ett_tftp,
   };
 
-  proto_tftp = proto_register_protocol("Trivial File Transfer Protocol", "tftp");
+  proto_tftp = proto_register_protocol("Trivial File Transfer Protocol",
+                                      "TFTP", "tftp");
   proto_register_field_array(proto_tftp, hf, array_length(hf));
   proto_register_subtree_array(ett, array_length(ett));
+
+  tftp_handle = create_dissector_handle(dissect_tftp, proto_tftp);
 }
 
 void
 proto_reg_handoff_tftp(void)
 {
-  dissector_add("udp.port", UDP_PORT_TFTP, dissect_tftp);
+  dissector_add("udp.port", UDP_PORT_TFTP, tftp_handle);
 }