139213Sgibbs/*
239213Sgibbs * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
371752Sken *	The Regents of the University of California.  All rights reserved.
439213Sgibbs *
539213Sgibbs * Redistribution and use in source and binary forms, with or without
639213Sgibbs * modification, are permitted provided that: (1) source code distributions
739213Sgibbs * retain the above copyright notice and this paragraph in its entirety, (2)
839213Sgibbs * distributions including binary code include the above copyright notice and
939213Sgibbs * this paragraph in its entirety in the documentation or other materials
1039213Sgibbs * provided with the distribution, and (3) all advertising materials mentioning
1139213Sgibbs * features or use of this software display the following acknowledgement:
1239213Sgibbs * ``This product includes software developed by the University of California,
1339213Sgibbs * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1439213Sgibbs * the University nor the names of its contributors may be used to endorse
1539213Sgibbs * or promote products derived from this software without specific prior
1639213Sgibbs * written permission.
1739213Sgibbs * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1839213Sgibbs * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1939213Sgibbs * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2039213Sgibbs */
2139213Sgibbs
2239213Sgibbs/* \summary: Trivial File Transfer Protocol (TFTP) printer */
2339213Sgibbs
2439213Sgibbs#include <sys/cdefs.h>
2539213Sgibbs#ifndef lint
2639213Sgibbs__RCSID("$NetBSD: print-tftp.c,v 1.9 2023/08/17 20:19:40 christos Exp $");
2750477Speter#endif
2839213Sgibbs
2939213Sgibbs#ifdef HAVE_CONFIG_H
3039213Sgibbs#include <config.h>
3139213Sgibbs#endif
3239213Sgibbs
3339213Sgibbs#include "netdissect-stdinc.h"
3439213Sgibbs
3539213Sgibbs#include "netdissect.h"
3639213Sgibbs#include "extract.h"
3739213Sgibbs
3839213Sgibbs/*
3939213Sgibbs * Trivial File Transfer Protocol (IEN-133)
4039213Sgibbs */
4139213Sgibbs
4239213Sgibbs/*
4339213Sgibbs * Packet types.
4439213Sgibbs */
4539213Sgibbs#define	RRQ	01			/* read request */
4639213Sgibbs#define	WRQ	02			/* write request */
4739213Sgibbs#define	DATA	03			/* data packet */
4839213Sgibbs#define	ACK	04			/* acknowledgement */
4940020Sken#define	TFTP_ERROR	05			/* error code */
5039213Sgibbs#define OACK	06			/* option acknowledgement */
5139213Sgibbs
5239213Sgibbs/*
5339213Sgibbs * Error codes.
5460041Sphk */
5551836Sphk#define	EUNDEF		0		/* not defined */
5651836Sphk#define	ENOTFOUND	1		/* file not found */
5739213Sgibbs#define	EACCESS		2		/* access violation */
5839213Sgibbs#define	ENOSPACE	3		/* disk full or allocation exceeded */
59105421Snjl#define	EBADOP		4		/* illegal TFTP operation */
6060422Sken#define	EBADID		5		/* unknown transfer ID */
6139213Sgibbs#define	EEXISTS		6		/* file already exists */
6239213Sgibbs#define	ENOUSER		7		/* no such user */
6339213Sgibbs
6439213Sgibbs
6539213Sgibbs/* op code to string mapping */
6639213Sgibbsstatic const struct tok op2str[] = {
6739213Sgibbs	{ RRQ,		"RRQ" },	/* read request */
6839213Sgibbs	{ WRQ,		"WRQ" },	/* write request */
6939213Sgibbs	{ DATA,		"DATA" },	/* data packet */
7039213Sgibbs	{ ACK,		"ACK" },	/* acknowledgement */
7139213Sgibbs	{ TFTP_ERROR,	"ERROR" },	/* error code */
7239213Sgibbs	{ OACK,		"OACK" },	/* option acknowledgement */
7339213Sgibbs	{ 0,		NULL }
7439213Sgibbs};
7539213Sgibbs
7639213Sgibbs/* error code to string mapping */
7739213Sgibbsstatic const struct tok err2str[] = {
7839213Sgibbs	{ EUNDEF,	"EUNDEF" },	/* not defined */
7939213Sgibbs	{ ENOTFOUND,	"ENOTFOUND" },	/* file not found */
8039213Sgibbs	{ EACCESS,	"EACCESS" },	/* access violation */
8139213Sgibbs	{ ENOSPACE,	"ENOSPACE" },	/* disk full or allocation exceeded */
8239213Sgibbs	{ EBADOP,	"EBADOP" },	/* illegal TFTP operation */
8339213Sgibbs	{ EBADID,	"EBADID" },	/* unknown transfer ID */
8439213Sgibbs	{ EEXISTS,	"EEXISTS" },	/* file already exists */
8539213Sgibbs	{ ENOUSER,	"ENOUSER" },	/* no such user */
8639213Sgibbs	{ 0,		NULL }
8739213Sgibbs};
8839213Sgibbs
8939213Sgibbs/*
9039213Sgibbs * Print trivial file transfer program requests
9139213Sgibbs */
9239213Sgibbsvoid
9339213Sgibbstftp_print(netdissect_options *ndo,
9439213Sgibbs           const u_char *bp, u_int length)
9539213Sgibbs{
9639213Sgibbs	const char *cp;
9739213Sgibbs	u_int opcode;
9839213Sgibbs	u_int ui;
9939213Sgibbs
10039213Sgibbs	ndo->ndo_protocol = "tftp";
10139213Sgibbs
10239213Sgibbs	/* Print protocol */
10339213Sgibbs	nd_print_protocol_caps(ndo);
10439213Sgibbs	/* Print length */
10539213Sgibbs	ND_PRINT(", length %u", length);
10639213Sgibbs
10739213Sgibbs	/* Print tftp request type */
10839213Sgibbs	if (length < 2)
10939213Sgibbs		goto trunc;
11039213Sgibbs	opcode = GET_BE_U_2(bp);
11139213Sgibbs	cp = tok2str(op2str, "tftp-#%u", opcode);
11239213Sgibbs	ND_PRINT(", %s", cp);
11339213Sgibbs	/* Bail if bogus opcode */
11439213Sgibbs	if (*cp == 't')
11539213Sgibbs		return;
11639213Sgibbs	bp += 2;
11739213Sgibbs	length -= 2;
11839213Sgibbs
11939213Sgibbs	switch (opcode) {
12039213Sgibbs
12139213Sgibbs	case RRQ:
12239213Sgibbs	case WRQ:
12339213Sgibbs		if (length == 0)
12439213Sgibbs			goto trunc;
12539213Sgibbs		ND_PRINT(" ");
12639213Sgibbs		/* Print filename */
12746581Sken		ND_PRINT("\"");
12859249Sphk		ui = nd_printztn(ndo, bp, length, ndo->ndo_snapend);
12960938Sjake		ND_PRINT("\"");
13039213Sgibbs		if (ui == 0)
13139213Sgibbs			goto trunc;
13239213Sgibbs		bp += ui;
13339213Sgibbs		length -= ui;
13460938Sjake
13539213Sgibbs		/* Print the mode - RRQ and WRQ only */
13639213Sgibbs		if (length == 0)
13739213Sgibbs			goto trunc;	/* no mode */
138104456Sphk		ND_PRINT(" ");
139104880Sphk		ui = nd_printztn(ndo, bp, length, ndo->ndo_snapend);
14039213Sgibbs		if (ui == 0)
14139213Sgibbs			goto trunc;
14239213Sgibbs		bp += ui;
14339213Sgibbs		length -= ui;
14439213Sgibbs
14539213Sgibbs		/* Print options, if any */
14639213Sgibbs		while (length != 0) {
14739213Sgibbs			if (GET_U_1(bp) != '\0')
14839213Sgibbs				ND_PRINT(" ");
14939213Sgibbs			ui = nd_printztn(ndo, bp, length, ndo->ndo_snapend);
15039213Sgibbs			if (ui == 0)
15139213Sgibbs				goto trunc;
15239213Sgibbs			bp += ui;
15339213Sgibbs			length -= ui;
15439213Sgibbs		}
15539213Sgibbs		break;
15639213Sgibbs
15739213Sgibbs	case OACK:
15839213Sgibbs		/* Print options */
15939213Sgibbs		while (length != 0) {
16039213Sgibbs			if (GET_U_1(bp) != '\0')
16139213Sgibbs				ND_PRINT(" ");
16254451Sken			ui = nd_printztn(ndo, bp, length, ndo->ndo_snapend);
16339213Sgibbs			if (ui == 0)
16440262Sken				goto trunc;
16540262Sken			bp += ui;
16667752Sken			length -= ui;
16767752Sken		}
16867752Sken		break;
16967752Sken
17040262Sken	case ACK:
17140262Sken	case DATA:
17239213Sgibbs		if (length < 2)
17339213Sgibbs			goto trunc;	/* no block number */
17439213Sgibbs		ND_PRINT(" block %u", GET_BE_U_2(bp));
17539213Sgibbs		break;
17639213Sgibbs
17739213Sgibbs	case TFTP_ERROR:
17839213Sgibbs		/* Print error code string */
17939213Sgibbs		if (length < 2)
18039213Sgibbs			goto trunc;	/* no error code */
18139213Sgibbs		ND_PRINT(" %s", tok2str(err2str, "tftp-err-#%u \"",
18239213Sgibbs				       GET_BE_U_2(bp)));
18339213Sgibbs		bp += 2;
18439213Sgibbs		length -= 2;
18539213Sgibbs		/* Print error message string */
18639213Sgibbs		if (length == 0)
18739213Sgibbs			goto trunc;	/* no error message */
18839213Sgibbs		ND_PRINT(" \"");
18939213Sgibbs		ui = nd_printztn(ndo, bp, length, ndo->ndo_snapend);
19040603Sken		ND_PRINT("\"");
19139213Sgibbs		if (ui == 0)
19239213Sgibbs			goto trunc;
19339213Sgibbs		break;
19439213Sgibbs
19539213Sgibbs	default:
19639213Sgibbs		/* We shouldn't get here */
19739213Sgibbs		ND_PRINT("(unknown #%u)", opcode);
19839213Sgibbs		break;
19939213Sgibbs	}
20039213Sgibbs	return;
20139213Sgibbstrunc:
20242531Seivind	nd_print_trunc(ndo);
20339213Sgibbs}
20439213Sgibbs