1/*
2 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 *
21 * Format and print trivial file transfer protocol packets.
22 */
23
24#define NETDISSECT_REWORKED
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#endif
28
29#include <tcpdump-stdinc.h>
30
31#include <string.h>
32
33#include "interface.h"
34#include "extract.h"
35
36/*
37 * Trivial File Transfer Protocol (IEN-133)
38 */
39
40/*
41 * Packet types.
42 */
43#define	RRQ	01			/* read request */
44#define	WRQ	02			/* write request */
45#define	DATA	03			/* data packet */
46#define	ACK	04			/* acknowledgement */
47#define	TFTP_ERROR	05			/* error code */
48#define OACK	06			/* option acknowledgement */
49
50struct	tftphdr {
51	unsigned short	th_opcode;		/* packet type */
52	union {
53		unsigned short	tu_block;	/* block # */
54		unsigned short	tu_code;	/* error code */
55		char	tu_stuff[1];	/* request packet stuff */
56	} th_u;
57	char	th_data[1];		/* data or error string */
58};
59
60#define	th_block	th_u.tu_block
61#define	th_code		th_u.tu_code
62#define	th_stuff	th_u.tu_stuff
63#define	th_msg		th_data
64
65/*
66 * Error codes.
67 */
68#define	EUNDEF		0		/* not defined */
69#define	ENOTFOUND	1		/* file not found */
70#define	EACCESS		2		/* access violation */
71#define	ENOSPACE	3		/* disk full or allocation exceeded */
72#define	EBADOP		4		/* illegal TFTP operation */
73#define	EBADID		5		/* unknown transfer ID */
74#define	EEXISTS		6		/* file already exists */
75#define	ENOUSER		7		/* no such user */
76
77static const char tstr[] = " [|tftp]";
78
79/* op code to string mapping */
80static const struct tok op2str[] = {
81	{ RRQ,		"RRQ" },	/* read request */
82	{ WRQ,		"WRQ" },	/* write request */
83	{ DATA,		"DATA" },	/* data packet */
84	{ ACK,		"ACK" },	/* acknowledgement */
85	{ TFTP_ERROR,	"ERROR" },	/* error code */
86	{ OACK,		"OACK" },	/* option acknowledgement */
87	{ 0,		NULL }
88};
89
90/* error code to string mapping */
91static const struct tok err2str[] = {
92	{ EUNDEF,	"EUNDEF" },	/* not defined */
93	{ ENOTFOUND,	"ENOTFOUND" },	/* file not found */
94	{ EACCESS,	"EACCESS" },	/* access violation */
95	{ ENOSPACE,	"ENOSPACE" },	/* disk full or allocation exceeded */
96	{ EBADOP,	"EBADOP" },	/* illegal TFTP operation */
97	{ EBADID,	"EBADID" },	/* unknown transfer ID */
98	{ EEXISTS,	"EEXISTS" },	/* file already exists */
99	{ ENOUSER,	"ENOUSER" },	/* no such user */
100	{ 0,		NULL }
101};
102
103/*
104 * Print trivial file transfer program requests
105 */
106void
107tftp_print(netdissect_options *ndo,
108           register const u_char *bp, u_int length)
109{
110	register const struct tftphdr *tp;
111	register const char *cp;
112	register const u_char *p;
113	register int opcode, i;
114
115	tp = (const struct tftphdr *)bp;
116
117	/* Print length */
118	ND_PRINT((ndo, " %d", length));
119
120	/* Print tftp request type */
121	ND_TCHECK(tp->th_opcode);
122	opcode = EXTRACT_16BITS(&tp->th_opcode);
123	cp = tok2str(op2str, "tftp-#%d", opcode);
124	ND_PRINT((ndo, " %s", cp));
125	/* Bail if bogus opcode */
126	if (*cp == 't')
127		return;
128
129	switch (opcode) {
130
131	case RRQ:
132	case WRQ:
133	case OACK:
134		p = (u_char *)tp->th_stuff;
135		ND_PRINT((ndo, " "));
136		/* Print filename or first option */
137		if (opcode != OACK)
138			ND_PRINT((ndo, "\""));
139		i = fn_print(ndo, p, ndo->ndo_snapend);
140		if (opcode != OACK)
141			ND_PRINT((ndo, "\""));
142
143		/* Print the mode (RRQ and WRQ only) and any options */
144		while ((p = (const u_char *)strchr((const char *)p, '\0')) != NULL) {
145			if (length <= (u_int)(p - (const u_char *)&tp->th_block))
146				break;
147			p++;
148			if (*p != '\0') {
149				ND_PRINT((ndo, " "));
150				fn_print(ndo, p, ndo->ndo_snapend);
151			}
152		}
153
154		if (i)
155			goto trunc;
156		break;
157
158	case ACK:
159	case DATA:
160		ND_TCHECK(tp->th_block);
161		ND_PRINT((ndo, " block %d", EXTRACT_16BITS(&tp->th_block)));
162		break;
163
164	case TFTP_ERROR:
165		/* Print error code string */
166		ND_TCHECK(tp->th_code);
167		ND_PRINT((ndo, " %s \"", tok2str(err2str, "tftp-err-#%d \"",
168				       EXTRACT_16BITS(&tp->th_code))));
169		/* Print error message string */
170		i = fn_print(ndo, (const u_char *)tp->th_data, ndo->ndo_snapend);
171		ND_PRINT((ndo, "\""));
172		if (i)
173			goto trunc;
174		break;
175
176	default:
177		/* We shouldn't get here */
178		ND_PRINT((ndo, "(unknown #%d)", opcode));
179		break;
180	}
181	return;
182trunc:
183	ND_PRINT((ndo, "%s", tstr));
184	return;
185}
186