tftpd: PXE server said to need to support "tsize" option

(by Pascal Bellard <pascal.bellard AT ads-lu.com>).
 Conditional on blocksize option && tftpd support.

function                                             old     new   delta
tftp_protocol                                       1488    1670    +182
tftp_get_option                                        -     102    +102
tftpd_main                                           494     538     +44
tftp_main                                            252     254      +2
tftp_get_blksize                                      97       -     -97
------------------------------------------------------------------------------
(add/remove: 1/1 grow/shrink: 3/0 up/down: 330/-97)           Total: 233 bytes
This commit is contained in:
Denis Vlasenko 2008-06-16 07:12:19 +00:00
parent f45c4f41b7
commit 8474cd38f3

View File

@ -39,7 +39,7 @@
#define TFTP_ERROR 5 #define TFTP_ERROR 5
#define TFTP_OACK 6 #define TFTP_OACK 6
/* error codes sent over network (we use only 0, 3 and 8) */ /* error codes sent over network (we use only 0, 1, 3 and 8) */
/* generic (error message is included in the packet) */ /* generic (error message is included in the packet) */
#define ERR_UNSPEC 0 #define ERR_UNSPEC 0
#define ERR_NOFILE 1 #define ERR_NOFILE 1
@ -121,9 +121,8 @@ static int tftp_blksize_check(const char *blksize_str, int maxsize)
return blksize; return blksize;
} }
static char *tftp_get_blksize(char *buf, int len) static char *tftp_get_option(const char *option, char *buf, int len)
{ {
#define option "blksize"
int opt_val = 0; int opt_val = 0;
int opt_found = 0; int opt_found = 0;
int k; int k;
@ -155,7 +154,6 @@ static char *tftp_get_blksize(char *buf, int len)
} }
return NULL; return NULL;
#undef option
} }
#endif #endif
@ -163,13 +161,21 @@ static char *tftp_get_blksize(char *buf, int len)
static int tftp_protocol( static int tftp_protocol(
len_and_sockaddr *our_lsa, len_and_sockaddr *our_lsa,
len_and_sockaddr *peer_lsa, len_and_sockaddr *peer_lsa,
const char *local_file, const char *local_file
USE_TFTP(const char *remote_file,) USE_TFTP(, const char *remote_file)
int blksize) USE_FEATURE_TFTP_BLOCKSIZE(USE_TFTPD(, void *tsize))
USE_FEATURE_TFTP_BLOCKSIZE(, int blksize))
{ {
#if !ENABLE_TFTP #if !ENABLE_TFTP
#define remote_file NULL #define remote_file NULL
#endif #endif
#if !(ENABLE_FEATURE_TFTP_BLOCKSIZE && ENABLE_TFTPD)
#define tsize NULL
#endif
#if !ENABLE_FEATURE_TFTP_BLOCKSIZE
enum { blksize = TFTP_BLKSIZE_DEFAULT };
#endif
struct pollfd pfd[1]; struct pollfd pfd[1];
#define socket_fd (pfd[0].fd) #define socket_fd (pfd[0].fd)
int len; int len;
@ -243,17 +249,16 @@ static int tftp_protocol(
if (NOT_LONE_DASH(local_file)) if (NOT_LONE_DASH(local_file))
local_fd = xopen(local_file, open_mode); local_fd = xopen(local_file, open_mode);
} else { } else {
local_fd = open_or_warn(local_file, open_mode); local_fd = open(local_file, open_mode);
if (local_fd < 0) { if (local_fd < 0) {
/*error_pkt_reason = ERR_NOFILE/ERR_ACCESS?*/ error_pkt_reason = ERR_NOFILE;
strcpy((char*)error_pkt_str, "can't open file"); strcpy((char*)error_pkt_str, "can't open file");
goto send_err_pkt; goto send_err_pkt;
} }
} }
if (!ENABLE_TFTP || our_lsa) { if (!ENABLE_TFTP || our_lsa) {
#if ENABLE_FEATURE_TFTP_BLOCKSIZE if (blksize != TFTP_BLKSIZE_DEFAULT || tsize) {
if (blksize != TFTP_BLKSIZE_DEFAULT) {
/* Create and send OACK packet. */ /* Create and send OACK packet. */
/* For the download case, block_nr is still 1 - /* For the download case, block_nr is still 1 -
* we expect 1st ACK from peer to be for (block_nr-1), * we expect 1st ACK from peer to be for (block_nr-1),
@ -261,10 +266,8 @@ static int tftp_protocol(
opcode = TFTP_OACK; opcode = TFTP_OACK;
goto add_blksize_opt; goto add_blksize_opt;
} }
#endif } else {
} /* Removing it, or using if() statement instead of #if may lead to
else {
/* Removing it, or using if() statement instead may lead to
* "warning: null argument where non-null required": */ * "warning: null argument where non-null required": */
#if ENABLE_TFTP #if ENABLE_TFTP
/* tftp */ /* tftp */
@ -298,7 +301,6 @@ static int tftp_protocol(
strcpy(cp, "octet"); strcpy(cp, "octet");
cp += sizeof("octet"); cp += sizeof("octet");
#if ENABLE_FEATURE_TFTP_BLOCKSIZE
if (blksize == TFTP_BLKSIZE_DEFAULT) if (blksize == TFTP_BLKSIZE_DEFAULT)
goto send_pkt; goto send_pkt;
@ -307,17 +309,26 @@ static int tftp_protocol(
bb_error_msg("remote filename is too long"); bb_error_msg("remote filename is too long");
goto ret; goto ret;
} }
want_option_ack = 1; USE_FEATURE_TFTP_BLOCKSIZE(want_option_ack = 1;)
#endif
#endif /* ENABLE_TFTP */ #endif /* ENABLE_TFTP */
#if ENABLE_FEATURE_TFTP_BLOCKSIZE
add_blksize_opt: add_blksize_opt:
/* add "blksize", <nul>, blksize, <nul> */ #if ENABLE_TFTPD
strcpy(cp, "blksize"); if (tsize) {
cp += sizeof("blksize"); struct stat st;
cp += snprintf(cp, 6, "%d", blksize) + 1; /* add "tsize", <nul>, size, <nul> */
strcpy(cp, "tsize");
cp += sizeof("tsize");
fstat(local_fd, &st);
cp += snprintf(cp, 10, "%u", (int) st.st_size) + 1;
}
#endif #endif
if (blksize != TFTP_BLKSIZE_DEFAULT) {
/* add "blksize", <nul>, blksize, <nul> */
strcpy(cp, "blksize");
cp += sizeof("blksize");
cp += snprintf(cp, 6, "%d", blksize) + 1;
}
/* First packet is built, so skip packet generation */ /* First packet is built, so skip packet generation */
goto send_pkt; goto send_pkt;
} }
@ -418,9 +429,8 @@ static int tftp_protocol(
#if ENABLE_DEBUG_TFTP #if ENABLE_DEBUG_TFTP
fprintf(stderr, "received %d bytes: %04x %04x\n", len, opcode, recv_blk); fprintf(stderr, "received %d bytes: %04x %04x\n", len, opcode, recv_blk);
#endif #endif
if (opcode == TFTP_ERROR) { if (opcode == TFTP_ERROR) {
static const char errcode_str[] = static const char errcode_str[] ALIGN1 =
"\0" "\0"
"file not found\0" "file not found\0"
"access violation\0" "access violation\0"
@ -450,7 +460,7 @@ static int tftp_protocol(
/* server seems to support options */ /* server seems to support options */
char *res; char *res;
res = tftp_get_blksize(&rbuf[2], len - 2); res = tftp_get_option("blksize", &rbuf[2], len - 2);
if (res) { if (res) {
blksize = tftp_blksize_check(res, blksize); blksize = tftp_blksize_check(res, blksize);
if (blksize < 0) { if (blksize < 0) {
@ -533,6 +543,8 @@ static int tftp_protocol(
xsendto(socket_fd, error_pkt, 4 + 1 + strlen((char*)error_pkt_str), xsendto(socket_fd, error_pkt, 4 + 1 + strlen((char*)error_pkt_str),
&peer_lsa->u.sa, peer_lsa->len); &peer_lsa->u.sa, peer_lsa->len);
return EXIT_FAILURE; return EXIT_FAILURE;
#undef remote_file
#undef tsize
} }
#if ENABLE_TFTP #if ENABLE_TFTP
@ -545,8 +557,8 @@ int tftp_main(int argc ATTRIBUTE_UNUSED, char **argv)
const char *remote_file = NULL; const char *remote_file = NULL;
#if ENABLE_FEATURE_TFTP_BLOCKSIZE #if ENABLE_FEATURE_TFTP_BLOCKSIZE
const char *blksize_str = TFTP_BLKSIZE_DEFAULT_STR; const char *blksize_str = TFTP_BLKSIZE_DEFAULT_STR;
#endif
int blksize; int blksize;
#endif
int result; int result;
int port; int port;
USE_GETPUT(int opt;) USE_GETPUT(int opt;)
@ -572,8 +584,6 @@ int tftp_main(int argc ATTRIBUTE_UNUSED, char **argv)
//bb_error_msg("bad block size"); //bb_error_msg("bad block size");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
#else
blksize = TFTP_BLKSIZE_DEFAULT;
#endif #endif
if (!local_file) if (!local_file)
@ -594,9 +604,11 @@ int tftp_main(int argc ATTRIBUTE_UNUSED, char **argv)
#endif #endif
result = tftp_protocol( result = tftp_protocol(
NULL /* our_lsa*/, peer_lsa, NULL /*our_lsa*/, peer_lsa,
local_file, remote_file, local_file, remote_file
blksize); USE_FEATURE_TFTP_BLOCKSIZE(USE_TFTPD(, NULL /*tsize*/))
USE_FEATURE_TFTP_BLOCKSIZE(, blksize)
);
if (result != EXIT_SUCCESS && NOT_LONE_DASH(local_file) && CMD_GET(opt)) { if (result != EXIT_SUCCESS && NOT_LONE_DASH(local_file) && CMD_GET(opt)) {
unlink(local_file); unlink(local_file);
@ -630,7 +642,8 @@ int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv)
char *local_file, *mode; char *local_file, *mode;
const char *error_msg; const char *error_msg;
int opt, result, opcode; int opt, result, opcode;
int blksize = TFTP_BLKSIZE_DEFAULT; USE_FEATURE_TFTP_BLOCKSIZE(int blksize = TFTP_BLKSIZE_DEFAULT;)
USE_FEATURE_TFTP_BLOCKSIZE(char *tsize = NULL;)
INIT_G(); INIT_G();
@ -676,7 +689,7 @@ int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv)
char *opt_str = mode + sizeof("octet"); char *opt_str = mode + sizeof("octet");
int opt_len = block_buf + result - opt_str; int opt_len = block_buf + result - opt_str;
if (opt_len > 0) { if (opt_len > 0) {
res = tftp_get_blksize(opt_str, opt_len); res = tftp_get_option("blksize", opt_str, opt_len);
if (res) { if (res) {
blksize = tftp_blksize_check(res, 65564); blksize = tftp_blksize_check(res, 65564);
if (blksize < 0) { if (blksize < 0) {
@ -685,6 +698,8 @@ int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv)
goto do_proto; goto do_proto;
} }
} }
/* did client ask us about file size? */
tsize = tftp_get_option("tsize", opt_str, opt_len);
} }
} }
#endif #endif
@ -701,16 +716,17 @@ int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv)
USE_GETPUT(option_mask32 |= TFTP_OPT_PUT;) /* will send file's data */ USE_GETPUT(option_mask32 |= TFTP_OPT_PUT;) /* will send file's data */
} }
close(STDIN_FILENO); /* close old, possibly wildcard socket */
/* tftp_protocol() will create new one, bound to particular local IP */
/* NB: if error_pkt_str or error_pkt_reason is set up, /* NB: if error_pkt_str or error_pkt_reason is set up,
* tftp_protocol() just sends one error pkt and returns */ * tftp_protocol() just sends one error pkt and returns */
do_proto: do_proto:
close(STDIN_FILENO); /* close old, possibly wildcard socket */
/* tftp_protocol() will create new one, bound to particular local IP */
result = tftp_protocol( result = tftp_protocol(
our_lsa, peer_lsa, our_lsa, peer_lsa,
local_file, USE_TFTP(NULL /*remote_file*/,) local_file USE_TFTP(, NULL /*remote_file*/)
blksize USE_FEATURE_TFTP_BLOCKSIZE(, tsize)
USE_FEATURE_TFTP_BLOCKSIZE(, blksize)
); );
return result; return result;