print-tftp.c revision 313537
117680Spst/*
239297Sfenner * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
317680Spst *	The Regents of the University of California.  All rights reserved.
417680Spst *
517680Spst * Redistribution and use in source and binary forms, with or without
617680Spst * modification, are permitted provided that: (1) source code distributions
717680Spst * retain the above copyright notice and this paragraph in its entirety, (2)
817680Spst * distributions including binary code include the above copyright notice and
917680Spst * this paragraph in its entirety in the documentation or other materials
1017680Spst * provided with the distribution, and (3) all advertising materials mentioning
1117680Spst * features or use of this software display the following acknowledgement:
1217680Spst * ``This product includes software developed by the University of California,
1317680Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1417680Spst * the University nor the names of its contributors may be used to endorse
1517680Spst * or promote products derived from this software without specific prior
1617680Spst * written permission.
1717680Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1817680Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1917680Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2017680Spst */
2117680Spst
22313537Sglebius/* \summary: Trivial File Transfer Protocol (TFTP) printer */
23313537Sglebius
2456893Sfenner#ifdef HAVE_CONFIG_H
2556893Sfenner#include "config.h"
2656893Sfenner#endif
2756893Sfenner
28313537Sglebius#include <netdissect-stdinc.h>
2917680Spst
3017680Spst#include <string.h>
3117680Spst
32313537Sglebius#include "netdissect.h"
33127668Sbms#include "extract.h"
3417680Spst
35276788Sdelphij/*
36276788Sdelphij * Trivial File Transfer Protocol (IEN-133)
37276788Sdelphij */
38276788Sdelphij
39276788Sdelphij/*
40276788Sdelphij * Packet types.
41276788Sdelphij */
42276788Sdelphij#define	RRQ	01			/* read request */
43276788Sdelphij#define	WRQ	02			/* write request */
44276788Sdelphij#define	DATA	03			/* data packet */
45276788Sdelphij#define	ACK	04			/* acknowledgement */
46276788Sdelphij#define	TFTP_ERROR	05			/* error code */
47276788Sdelphij#define OACK	06			/* option acknowledgement */
48276788Sdelphij
49276788Sdelphijstruct	tftphdr {
50276788Sdelphij	unsigned short	th_opcode;		/* packet type */
51276788Sdelphij	union {
52276788Sdelphij		unsigned short	tu_block;	/* block # */
53276788Sdelphij		unsigned short	tu_code;	/* error code */
54276788Sdelphij		char	tu_stuff[1];	/* request packet stuff */
55276788Sdelphij	} th_u;
56276788Sdelphij	char	th_data[1];		/* data or error string */
57276788Sdelphij};
58276788Sdelphij
59276788Sdelphij#define	th_block	th_u.tu_block
60276788Sdelphij#define	th_code		th_u.tu_code
61276788Sdelphij#define	th_stuff	th_u.tu_stuff
62276788Sdelphij#define	th_msg		th_data
63276788Sdelphij
64276788Sdelphij/*
65276788Sdelphij * Error codes.
66276788Sdelphij */
67276788Sdelphij#define	EUNDEF		0		/* not defined */
68276788Sdelphij#define	ENOTFOUND	1		/* file not found */
69276788Sdelphij#define	EACCESS		2		/* access violation */
70276788Sdelphij#define	ENOSPACE	3		/* disk full or allocation exceeded */
71276788Sdelphij#define	EBADOP		4		/* illegal TFTP operation */
72276788Sdelphij#define	EBADID		5		/* unknown transfer ID */
73276788Sdelphij#define	EEXISTS		6		/* file already exists */
74276788Sdelphij#define	ENOUSER		7		/* no such user */
75276788Sdelphij
76276788Sdelphijstatic const char tstr[] = " [|tftp]";
77276788Sdelphij
7817680Spst/* op code to string mapping */
79276788Sdelphijstatic const struct tok op2str[] = {
8017680Spst	{ RRQ,		"RRQ" },	/* read request */
8117680Spst	{ WRQ,		"WRQ" },	/* write request */
8217680Spst	{ DATA,		"DATA" },	/* data packet */
8317680Spst	{ ACK,		"ACK" },	/* acknowledgement */
84190207Srpaulo	{ TFTP_ERROR,	"ERROR" },	/* error code */
85172683Smlaier	{ OACK,		"OACK" },	/* option acknowledgement */
8617680Spst	{ 0,		NULL }
8717680Spst};
8817680Spst
8917680Spst/* error code to string mapping */
90276788Sdelphijstatic const struct tok err2str[] = {
9117680Spst	{ EUNDEF,	"EUNDEF" },	/* not defined */
9217680Spst	{ ENOTFOUND,	"ENOTFOUND" },	/* file not found */
9317680Spst	{ EACCESS,	"EACCESS" },	/* access violation */
9417680Spst	{ ENOSPACE,	"ENOSPACE" },	/* disk full or allocation exceeded */
9517680Spst	{ EBADOP,	"EBADOP" },	/* illegal TFTP operation */
9617680Spst	{ EBADID,	"EBADID" },	/* unknown transfer ID */
9717680Spst	{ EEXISTS,	"EEXISTS" },	/* file already exists */
9817680Spst	{ ENOUSER,	"ENOUSER" },	/* no such user */
9917680Spst	{ 0,		NULL }
10017680Spst};
10117680Spst
10217680Spst/*
10317680Spst * Print trivial file transfer program requests
10417680Spst */
10517680Spstvoid
106276788Sdelphijtftp_print(netdissect_options *ndo,
107276788Sdelphij           register const u_char *bp, u_int length)
10817680Spst{
10917680Spst	register const struct tftphdr *tp;
11017680Spst	register const char *cp;
11117680Spst	register const u_char *p;
112313537Sglebius	register int opcode;
113313537Sglebius	u_int ui;
11417680Spst
11517680Spst	tp = (const struct tftphdr *)bp;
11617680Spst
11717680Spst	/* Print length */
118276788Sdelphij	ND_PRINT((ndo, " %d", length));
11917680Spst
12017680Spst	/* Print tftp request type */
121313537Sglebius	if (length < 2)
122313537Sglebius		goto trunc;
123276788Sdelphij	ND_TCHECK(tp->th_opcode);
124127668Sbms	opcode = EXTRACT_16BITS(&tp->th_opcode);
12517680Spst	cp = tok2str(op2str, "tftp-#%d", opcode);
126313537Sglebius	length -= 2;
127276788Sdelphij	ND_PRINT((ndo, " %s", cp));
12817680Spst	/* Bail if bogus opcode */
12917680Spst	if (*cp == 't')
13017680Spst		return;
13117680Spst
13217680Spst	switch (opcode) {
13317680Spst
13417680Spst	case RRQ:
13517680Spst	case WRQ:
136313537Sglebius		p = (const u_char *)tp->th_stuff;
137313537Sglebius		if (length == 0)
138313537Sglebius			goto trunc;
139276788Sdelphij		ND_PRINT((ndo, " "));
140313537Sglebius		/* Print filename */
141313537Sglebius		ND_PRINT((ndo, "\""));
142313537Sglebius		ui = fn_printztn(ndo, p, length, ndo->ndo_snapend);
143313537Sglebius		ND_PRINT((ndo, "\""));
144313537Sglebius		if (ui == 0)
145313537Sglebius			goto trunc;
146313537Sglebius		p += ui;
147313537Sglebius		length -= ui;
148127668Sbms
149313537Sglebius		/* Print the mode - RRQ and WRQ only */
150313537Sglebius		if (length == 0)
151313537Sglebius			goto trunc;	/* no mode */
152313537Sglebius		ND_PRINT((ndo, " "));
153313537Sglebius		ui = fn_printztn(ndo, p, length, ndo->ndo_snapend);
154313537Sglebius		if (ui == 0)
155313537Sglebius			goto trunc;
156313537Sglebius		p += ui;
157313537Sglebius		length -= ui;
158313537Sglebius
159313537Sglebius		/* Print options, if any */
160313537Sglebius		while (length != 0) {
161313537Sglebius			ND_TCHECK(*p);
162313537Sglebius			if (*p != '\0')
163276788Sdelphij				ND_PRINT((ndo, " "));
164313537Sglebius			ui = fn_printztn(ndo, p, length, ndo->ndo_snapend);
165313537Sglebius			if (ui == 0)
166313537Sglebius				goto trunc;
167313537Sglebius			p += ui;
168313537Sglebius			length -= ui;
169127668Sbms		}
170313537Sglebius		break;
171276788Sdelphij
172313537Sglebius	case OACK:
173313537Sglebius		p = (const u_char *)tp->th_stuff;
174313537Sglebius		/* Print options */
175313537Sglebius		while (length != 0) {
176313537Sglebius			ND_TCHECK(*p);
177313537Sglebius			if (*p != '\0')
178313537Sglebius				ND_PRINT((ndo, " "));
179313537Sglebius			ui = fn_printztn(ndo, p, length, ndo->ndo_snapend);
180313537Sglebius			if (ui == 0)
181313537Sglebius				goto trunc;
182313537Sglebius			p += ui;
183313537Sglebius			length -= ui;
184313537Sglebius		}
18517680Spst		break;
18617680Spst
18717680Spst	case ACK:
18817680Spst	case DATA:
189313537Sglebius		if (length < 2)
190313537Sglebius			goto trunc;	/* no block number */
191276788Sdelphij		ND_TCHECK(tp->th_block);
192276788Sdelphij		ND_PRINT((ndo, " block %d", EXTRACT_16BITS(&tp->th_block)));
19317680Spst		break;
19417680Spst
195190207Srpaulo	case TFTP_ERROR:
19617680Spst		/* Print error code string */
197313537Sglebius		if (length < 2)
198313537Sglebius			goto trunc;	/* no error code */
199276788Sdelphij		ND_TCHECK(tp->th_code);
200313537Sglebius		ND_PRINT((ndo, " %s", tok2str(err2str, "tftp-err-#%d \"",
201276788Sdelphij				       EXTRACT_16BITS(&tp->th_code))));
202313537Sglebius		length -= 2;
20317680Spst		/* Print error message string */
204313537Sglebius		if (length == 0)
205313537Sglebius			goto trunc;	/* no error message */
206313537Sglebius		ND_PRINT((ndo, " \""));
207313537Sglebius		ui = fn_printztn(ndo, (const u_char *)tp->th_data, length, ndo->ndo_snapend);
208276788Sdelphij		ND_PRINT((ndo, "\""));
209313537Sglebius		if (ui == 0)
21017680Spst			goto trunc;
21117680Spst		break;
21217680Spst
21317680Spst	default:
21417680Spst		/* We shouldn't get here */
215276788Sdelphij		ND_PRINT((ndo, "(unknown #%d)", opcode));
21617680Spst		break;
21717680Spst	}
21817680Spst	return;
21917680Spsttrunc:
220276788Sdelphij	ND_PRINT((ndo, "%s", tstr));
22117680Spst	return;
22217680Spst}
223