Add preference for placement of AH payload, at same level or in subtree.
[obnox/wireshark/wip.git] / packet-tftp.c
1 /* packet-tftp.c
2  * Routines for tftp packet dissection
3  *
4  * Richard Sharpe <rsharpe@ns.aus.com>
5  * Craig Newell <CraigN@cheque.uq.edu.au>
6  *      RFC2347 TFTP Option Extension
7  *
8  * $Id: packet-tftp.c,v 1.12 2000/05/31 05:07:50 guy Exp $
9  *
10  * Ethereal - Network traffic analyzer
11  * By Gerald Combs <gerald@zing.org>
12  * Copyright 1998 Gerald Combs
13  *
14  * Copied from packet-bootp.c
15  * 
16  * This program is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU General Public License
18  * as published by the Free Software Foundation; either version 2
19  * of the License, or (at your option) any later version.
20  * 
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  * 
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
29  */
30
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 #ifdef HAVE_SYS_TYPES_H
36 # include <sys/types.h>
37 #endif
38
39 #ifdef HAVE_NETINET_IN_H
40 # include <netinet/in.h>
41 #endif
42
43 #include <glib.h>
44 #include "packet.h"
45
46 static int proto_tftp = -1;
47 static int hf_tftp_type = -1;
48 static int hf_tftp_error_code = -1;
49
50 static gint ett_tftp = -1;
51
52 #define RRQ     1
53 #define WRQ     2
54 #define DATA    3
55 #define ACK     4
56 #define ERROR   5
57 #define OACK    6
58
59 char *tftp_opcodes[8] = {
60   "Unknown Request",
61   "Read Request",
62   "Write Request",
63   "Data Packet",
64   "Acknowledgement",
65   "Error Code",
66   "Option Acknowledgement",
67   "Unknown Request"
68 };
69
70 char *tftp_errors[8] = {
71   "Not defined",
72   "File not found",
73   "Access violation",
74   "Disk full or allocation exceeded",
75   "Illegal TFTP Operation",
76   "Unknown transfer ID",
77   "File already exists",
78   "No such user"
79 };
80
81 void
82 dissect_tftp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
83 {
84         proto_tree      *tftp_tree;
85         proto_item      *ti;
86         u_int           i1;
87
88         if (check_col(fd, COL_PROTOCOL))
89                 col_add_str(fd, COL_PROTOCOL, "TFTP");
90
91         if (check_col(fd, COL_INFO)) {
92
93           i1 = pntohs(&pd[offset]);
94           col_add_fstr(fd, COL_INFO, "TFTP %s", i1 <= OACK ? tftp_opcodes[i1 % 8] : "Unknown Request");
95
96         }
97
98         if (tree) {
99
100           ti = proto_tree_add_item(tree, proto_tftp, NullTVB, offset, END_OF_FRAME, FALSE);
101           tftp_tree = proto_item_add_subtree(ti, ett_tftp);
102
103           i1 = pntohs(pd+offset);
104           proto_tree_add_uint_hidden(tftp_tree, hf_tftp_type, NullTVB, offset, 2, i1);
105             
106           switch (i1) {
107           case RRQ:
108             proto_tree_add_text(tftp_tree, NullTVB, offset, 2, "Read Request");
109             offset += 2;
110             i1 = strlen(pd+offset);
111             proto_tree_add_text(tftp_tree, NullTVB, offset, i1+1, "Source File: %s", pd+offset);
112             offset += i1 + 1;
113             i1 = strlen(pd+offset);
114             proto_tree_add_text(tftp_tree, NullTVB, offset, i1+1, "Type: %s",pd+offset);
115             offset += i1 + 1;
116             while (offset < pi.captured_len) {
117               int i2;
118               i1 = strlen(pd+offset);                   /* length of option */
119               i2 = strlen(pd+offset+i1+1);              /* length of value */
120               proto_tree_add_text(tftp_tree, NullTVB, offset, i1+i2+2, "Option: %s = %s", 
121                 pd+offset, pd+offset+i1+1);
122               offset += i1 + i2 + 2;
123             }
124             break;
125           case WRQ:
126             proto_tree_add_text(tftp_tree, NullTVB, offset, 2, "Write Request");
127             offset += 2;
128             i1 = strlen(pd+offset);
129             proto_tree_add_text(tftp_tree, NullTVB, offset, i1+1, "Destination File: %s", pd+offset);
130             offset += i1 + 1;
131             i1 = strlen(pd+offset);
132             proto_tree_add_text(tftp_tree, NullTVB, offset, i1+1, "Type: %s",pd+offset);
133             offset += i1 + 1;
134             while (offset < pi.captured_len) {
135               int i2;
136               i1 = strlen(pd+offset);                   /* length of option */
137               i2 = strlen(pd+offset+i1+1);              /* length of value */
138               proto_tree_add_text(tftp_tree, NullTVB, offset, i1+i2+2, "Option: %s = %s", 
139                 pd+offset, pd+offset+i1+1);
140               offset += i1 + i2 + 2;
141             }
142             break;
143           case DATA:
144             proto_tree_add_text(tftp_tree, NullTVB, offset, 2, "Data Packet");
145             offset += 2;
146             i1 = pntohs(pd+offset);
147             proto_tree_add_text(tftp_tree, NullTVB, offset, 2, "Block = %u", i1);
148             offset += 2;
149             proto_tree_add_text(tftp_tree, NullTVB, offset, END_OF_FRAME,
150                 "Data (%d bytes)", END_OF_FRAME);
151             break;
152           case ACK:
153             proto_tree_add_text(tftp_tree, NullTVB, offset, 2, "Acknowledgement");
154             offset += 2;
155             i1 = pntohs(pd+offset);
156             proto_tree_add_text(tftp_tree, NullTVB, offset, END_OF_FRAME, "Block = %u", i1);
157             break;
158           case ERROR:
159             proto_tree_add_text(tftp_tree, NullTVB, offset, 2, "Error Code");
160             offset += 2;
161             i1 = pntohs(pd+offset);
162             proto_tree_add_uint_hidden(tftp_tree, hf_tftp_error_code, NullTVB, offset, 2, i1);
163             proto_tree_add_text(tftp_tree, NullTVB, offset, 2, "Code = %s", tftp_errors[i1 % 8]);
164             offset += 2;
165             proto_tree_add_text(tftp_tree, NullTVB, offset, END_OF_FRAME, "Error Message: %s", pd + offset);
166             break;
167           case OACK:
168             proto_tree_add_text(tftp_tree, NullTVB, offset, 2, "Option Acknowledgement");
169             offset += 2;
170             while (offset < pi.captured_len) {
171               int i2;
172               i1 = strlen(pd+offset);                   /* length of option */
173               i2 = strlen(pd+offset+i1+1);              /* length of value */
174               proto_tree_add_text(tftp_tree, NullTVB, offset, i1+i2+2, "Option: %s = %s", 
175                 pd+offset, pd+offset+i1+1);
176               offset += i1 + i2 + 2;
177             }
178             break;
179           default:
180             proto_tree_add_text(tftp_tree, NullTVB, offset, 2, "Unknown TFTP Request: %0X.", i1);
181             offset += 2;
182             proto_tree_add_text(tftp_tree, NullTVB, offset, END_OF_FRAME,
183                 "Data (%d bytes)", END_OF_FRAME);
184             break;
185           }
186
187         }
188 }
189
190 void
191 proto_register_tftp(void)
192 {
193
194   static hf_register_info hf[] = {
195     { &hf_tftp_type,
196       { "Type",               "tftp.type",
197         FT_UINT16, BASE_DEC, NULL, 0x0,
198         "TFTP message type" }},
199
200     { &hf_tftp_error_code,
201       { "Error code",         "tftp.error.code",
202         FT_UINT16, BASE_DEC, NULL, 0x0,
203         "Error code in case of TFTP error message" }}
204   };
205   static gint *ett[] = {
206     &ett_tftp,
207   };
208
209   proto_tftp = proto_register_protocol("Trivial File Transfer Protocol", "tftp");
210   proto_register_field_array(proto_tftp, hf, array_length(hf));
211   proto_register_subtree_array(ett, array_length(ett));
212 }