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#ifndef lint
25static const char rcsid[] _U_ =
26    "@(#) $Header: /tcpdump/master/tcpdump/print-tftp.c,v 1.37 2003/11/16 09:36:40 guy Exp $ (LBL)";
27#endif
28
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
33#include <tcpdump-stdinc.h>
34
35#ifdef SEGSIZE
36#undef SEGSIZE					/* SINIX sucks */
37#endif
38#include <arpa/tftp.h>
39
40#include <stdio.h>
41#include <string.h>
42
43#include "interface.h"
44#include "addrtoname.h"
45#include "extract.h"
46
47/* op code to string mapping */
48static struct tok op2str[] = {
49	{ RRQ,		"RRQ" },	/* read request */
50	{ WRQ,		"WRQ" },	/* write request */
51	{ DATA,		"DATA" },	/* data packet */
52	{ ACK,		"ACK" },	/* acknowledgement */
53	{ ERROR,	"ERROR" },	/* error code */
54	{ 0,		NULL }
55};
56
57/* error code to string mapping */
58static struct tok err2str[] = {
59	{ EUNDEF,	"EUNDEF" },	/* not defined */
60	{ ENOTFOUND,	"ENOTFOUND" },	/* file not found */
61	{ EACCESS,	"EACCESS" },	/* access violation */
62	{ ENOSPACE,	"ENOSPACE" },	/* disk full or allocation exceeded */
63	{ EBADOP,	"EBADOP" },	/* illegal TFTP operation */
64	{ EBADID,	"EBADID" },	/* unknown transfer ID */
65	{ EEXISTS,	"EEXISTS" },	/* file already exists */
66	{ ENOUSER,	"ENOUSER" },	/* no such user */
67	{ 0,		NULL }
68};
69
70/*
71 * Print trivial file transfer program requests
72 */
73void
74tftp_print(register const u_char *bp, u_int length)
75{
76	register const struct tftphdr *tp;
77	register const char *cp;
78	register const u_char *p;
79	register int opcode, i;
80	static char tstr[] = " [|tftp]";
81
82	tp = (const struct tftphdr *)bp;
83
84	/* Print length */
85	printf(" %d", length);
86
87	/* Print tftp request type */
88	TCHECK(tp->th_opcode);
89	opcode = EXTRACT_16BITS(&tp->th_opcode);
90	cp = tok2str(op2str, "tftp-#%d", opcode);
91	printf(" %s", cp);
92	/* Bail if bogus opcode */
93	if (*cp == 't')
94		return;
95
96	switch (opcode) {
97
98	case RRQ:
99	case WRQ:
100		/*
101		 * XXX Not all arpa/tftp.h's specify th_stuff as any
102		 * array; use address of th_block instead
103		 */
104#ifdef notdef
105		p = (u_char *)tp->th_stuff;
106#else
107		p = (u_char *)&tp->th_block;
108#endif
109		fputs(" \"", stdout);
110		i = fn_print(p, snapend);
111		putchar('"');
112
113		/* Print the mode and any options */
114		while ((p = (const u_char *)strchr((const char *)p, '\0')) != NULL) {
115			if (length <= (u_int)(p - (const u_char *)&tp->th_block))
116				break;
117			p++;
118			if (*p != '\0') {
119				putchar(' ');
120				fn_print(p, snapend);
121			}
122		}
123
124		if (i)
125			goto trunc;
126		break;
127
128	case ACK:
129	case DATA:
130		TCHECK(tp->th_block);
131		printf(" block %d", EXTRACT_16BITS(&tp->th_block));
132		break;
133
134	case ERROR:
135		/* Print error code string */
136		TCHECK(tp->th_code);
137		printf(" %s ", tok2str(err2str, "tftp-err-#%d \"",
138				       EXTRACT_16BITS(&tp->th_code)));
139		/* Print error message string */
140		i = fn_print((const u_char *)tp->th_data, snapend);
141		putchar('"');
142		if (i)
143			goto trunc;
144		break;
145
146	default:
147		/* We shouldn't get here */
148		printf("(unknown #%d)", opcode);
149		break;
150	}
151	return;
152trunc:
153	fputs(tstr, stdout);
154	return;
155}
156