1234285Sdim/*
2234285Sdim * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
3234285Sdim *	The Regents of the University of California.  All rights reserved.
4234285Sdim *
5234285Sdim * Redistribution and use in source and binary forms, with or without
6234285Sdim * modification, are permitted provided that: (1) source code distributions
7234285Sdim * retain the above copyright notice and this paragraph in its entirety, (2)
8234285Sdim * distributions including binary code include the above copyright notice and
9234285Sdim * this paragraph in its entirety in the documentation or other materials
10234285Sdim * provided with the distribution, and (3) all advertising materials mentioning
11234285Sdim * features or use of this software display the following acknowledgement:
12234285Sdim * ``This product includes software developed by the University of California,
13234285Sdim * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14234285Sdim * the University nor the names of its contributors may be used to endorse
15234285Sdim * or promote products derived from this software without specific prior
16234285Sdim * written permission.
17234285Sdim * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18234285Sdim * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19234285Sdim * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20234285Sdim *
21249423Sdim * Format and print trivial file transfer protocol packets.
22234285Sdim */
23234285Sdim
24249423Sdim#ifndef lint
25234285Sdimstatic const char rcsid[] _U_ =
26234285Sdim    "@(#) $Header: /tcpdump/master/tcpdump/print-tftp.c,v 1.39 2008-04-11 16:47:38 gianluca Exp $ (LBL)";
27234285Sdim#endif
28234285Sdim
29234285Sdim#ifdef HAVE_CONFIG_H
30234285Sdim#include "config.h"
31234285Sdim#endif
32234285Sdim
33234285Sdim#include <tcpdump-stdinc.h>
34234285Sdim
35234285Sdim#ifdef SEGSIZE
36234285Sdim#undef SEGSIZE					/* SINIX sucks */
37234285Sdim#endif
38234285Sdim
39234285Sdim#include <stdio.h>
40234285Sdim#include <string.h>
41234285Sdim
42234285Sdim#include "interface.h"
43234285Sdim#include "addrtoname.h"
44234285Sdim#include "extract.h"
45234285Sdim#include "tftp.h"
46234285Sdim
47234285Sdim/* op code to string mapping */
48234285Sdimstatic struct tok op2str[] = {
49234285Sdim	{ RRQ,		"RRQ" },	/* read request */
50234285Sdim	{ WRQ,		"WRQ" },	/* write request */
51234285Sdim	{ DATA,		"DATA" },	/* data packet */
52234285Sdim	{ ACK,		"ACK" },	/* acknowledgement */
53239462Sdim	{ TFTP_ERROR,	"ERROR" },	/* error code */
54239462Sdim	{ OACK,		"OACK" },	/* option acknowledgement */
55239462Sdim	{ 0,		NULL }
56234285Sdim};
57234285Sdim
58234285Sdim/* error code to string mapping */
59234285Sdimstatic struct tok err2str[] = {
60239462Sdim	{ EUNDEF,	"EUNDEF" },	/* not defined */
61234285Sdim	{ ENOTFOUND,	"ENOTFOUND" },	/* file not found */
62234285Sdim	{ EACCESS,	"EACCESS" },	/* access violation */
63234285Sdim	{ ENOSPACE,	"ENOSPACE" },	/* disk full or allocation exceeded */
64234285Sdim	{ EBADOP,	"EBADOP" },	/* illegal TFTP operation */
65234285Sdim	{ EBADID,	"EBADID" },	/* unknown transfer ID */
66234285Sdim	{ EEXISTS,	"EEXISTS" },	/* file already exists */
67234285Sdim	{ ENOUSER,	"ENOUSER" },	/* no such user */
68234285Sdim	{ 0,		NULL }
69234285Sdim};
70239462Sdim
71239462Sdim/*
72239462Sdim * Print trivial file transfer program requests
73239462Sdim */
74239462Sdimvoid
75234285Sdimtftp_print(register const u_char *bp, u_int length)
76234285Sdim{
77234285Sdim	register const struct tftphdr *tp;
78234285Sdim	register const char *cp;
79234285Sdim	register const u_char *p;
80234285Sdim	register int opcode, i;
81234285Sdim	static char tstr[] = " [|tftp]";
82234285Sdim
83234285Sdim	tp = (const struct tftphdr *)bp;
84234285Sdim
85234285Sdim	/* Print length */
86234285Sdim	printf(" %d", length);
87234285Sdim
88234285Sdim	/* Print tftp request type */
89234285Sdim	TCHECK(tp->th_opcode);
90234285Sdim	opcode = EXTRACT_16BITS(&tp->th_opcode);
91234285Sdim	cp = tok2str(op2str, "tftp-#%d", opcode);
92234285Sdim	printf(" %s", cp);
93234285Sdim	/* Bail if bogus opcode */
94234285Sdim	if (*cp == 't')
95239462Sdim		return;
96234285Sdim
97234285Sdim	switch (opcode) {
98234285Sdim
99234285Sdim	case RRQ:
100234285Sdim	case WRQ:
101234285Sdim	case OACK:
102239462Sdim		p = (u_char *)tp->th_stuff;
103234285Sdim		putchar(' ');
104234285Sdim		/* Print filename or first option */
105234285Sdim		if (opcode != OACK)
106234285Sdim			putchar('"');
107234285Sdim		i = fn_print(p, snapend);
108234285Sdim		if (opcode != OACK)
109234285Sdim			putchar('"');
110234285Sdim
111234285Sdim		/* Print the mode (RRQ and WRQ only) and any options */
112234285Sdim		while ((p = (const u_char *)strchr((const char *)p, '\0')) != NULL) {
113234285Sdim			if (length <= (u_int)(p - (const u_char *)&tp->th_block))
114234285Sdim				break;
115234285Sdim			p++;
116234285Sdim			if (*p != '\0') {
117234285Sdim				putchar(' ');
118234285Sdim				fn_print(p, snapend);
119234285Sdim			}
120234285Sdim		}
121234285Sdim
122234285Sdim		if (i)
123234285Sdim			goto trunc;
124234285Sdim		break;
125234285Sdim
126234285Sdim	case ACK:
127239462Sdim	case DATA:
128234285Sdim		TCHECK(tp->th_block);
129234285Sdim		printf(" block %d", EXTRACT_16BITS(&tp->th_block));
130234285Sdim		break;
131234285Sdim
132234285Sdim	case TFTP_ERROR:
133234285Sdim		/* Print error code string */
134234285Sdim		TCHECK(tp->th_code);
135234285Sdim		printf(" %s \"", tok2str(err2str, "tftp-err-#%d \"",
136234285Sdim				       EXTRACT_16BITS(&tp->th_code)));
137234285Sdim		/* Print error message string */
138234285Sdim		i = fn_print((const u_char *)tp->th_data, snapend);
139234285Sdim		putchar('"');
140234285Sdim		if (i)
141234285Sdim			goto trunc;
142234285Sdim		break;
143234285Sdim
144234285Sdim	default:
145234285Sdim		/* We shouldn't get here */
146		printf("(unknown #%d)", opcode);
147		break;
148	}
149	return;
150trunc:
151	fputs(tstr, stdout);
152	return;
153}
154