📄 tftp.c
字号:
/*
* File: tftp.c
* Purpose: Trivial File Transfer Protocol driver for reading a file
* from a remote host.
*
* Notes: See RFC 1350
*
* Modifications:
*
*/
#include "src/include/dbug.h"
#include "src/uif/net/net.h"
#ifdef DBUG_NETWORK
/********************************************************************/
/* The one and only TFTP connection */
TFTP_Connection tcxn;
/* Progress Indicators */
char hash[] = {'-','\\','|','/'};
int ihash = 0;
/********************************************************************/
static int
tftp_rwrq (void)
{
NBUF *pNbuf;
RWRQ *rwrq;
int i, j, result;
pNbuf = nbuf_alloc();
if (pNbuf == NULL)
{
#if defined(DEBUG_PRINT)
printf("TFTP: tftp_rwrq() couldn't allocate Tx buffer\n");
#endif
return 0;
}
rwrq = (RWRQ *)&pNbuf->data[TFTP_HDR_OFFSET];
/* Indicate a R/WRQ */
rwrq->opcode = tcxn.dir;
/* Copy in filename */
strcpy(&rwrq->filename_mode[0], tcxn.file);
i = strlen(tcxn.file) + 1;
/* Indicate transfer type */
strcpy (&rwrq->filename_mode[i], OCTET);
for (j=0; j<3; ++j)
{
pNbuf->length = (uint16)(i + strlen(OCTET) + 1 + 2);
result = udp_send(tcxn.nif,
tcxn.server_ip,
tcxn.my_port,
tcxn.server_port,
pNbuf);
if (result == 1)
break;
}
if (result == 0)
nbuf_free(pNbuf);
return result;
}
/********************************************************************/
static int
tftp_ack (uint16 blocknum)
{
ACK *ack;
NBUF *pNbuf;
int i, result;
pNbuf = nbuf_alloc();
if (pNbuf == NULL)
{
#if defined(DEBUG_PRINT)
printf("TFTP: tftp_ack() couldn't allocate Tx buffer\n");
#endif
return 0;
}
ack = (ACK *)&pNbuf->data[TFTP_HDR_OFFSET];
ack->opcode = TFTP_ACK;
ack->blocknum = blocknum;
for (i=0; i<3; ++i)
{
pNbuf->length = 4;
result = udp_send(tcxn.nif,
tcxn.server_ip,
tcxn.my_port,
tcxn.server_port,
pNbuf);
if (result == 1)
break;
}
if (result == 0)
nbuf_free(pNbuf);
return result;
}
/********************************************************************/
static int
tftp_error (uint16 error_code, uint16 server_port)
{
ERROR *err;
NBUF *pNbuf;
int i, result;
pNbuf = nbuf_alloc();
if (pNbuf == NULL)
{
#if defined(DEBUG_PRINT)
printf("TFTP: tftp_error() couldn't allocate Tx buffer\n");
#endif
return 0;
}
err = (ERROR *)&pNbuf->data[TFTP_HDR_OFFSET];
err->opcode = TFTP_ERROR;
err->code = error_code;
err->msg[0] = '\0';
for (i=0; i<3; ++i)
{
pNbuf->length = 5;
result = udp_send(tcxn.nif,
tcxn.server_ip,
tcxn.my_port,
server_port,
pNbuf);
if (result == 1)
break;
}
if (result == 0)
nbuf_free(pNbuf);
return result;
}
/********************************************************************/
void
tftp_handler (NIF *nif, NBUF *pNbuf)
{
union TFTPpacket *tftp_pkt;
udp_frame_hdr *udpframe;
static int cnt;
(void) nif;
tftp_pkt = (union TFTPpacket *)&pNbuf->data[pNbuf->offset];
udpframe = (udp_frame_hdr *)&pNbuf->data[pNbuf->offset - UDP_HDR_SIZE];
switch (tftp_pkt->generic.opcode)
{
case TFTP_DATA:
/* Is this the expected block number? */
if (tftp_pkt->data.blocknum == tcxn.exp_blocknum)
{
/* Is this is the first data block received? */
if (tftp_pkt->data.blocknum == 1)
{
/* Save the server's transfer ID */
tcxn.server_port = UDP_SOURCE(udpframe);
/* Mark the connection as open */
tcxn.open = TRUE;
/* Start progress indicator */
board_putchar(hash[0]);
cnt = 0;
}
else
{
/* Check the server's transfer ID */
if (tcxn.server_port != UDP_SOURCE(udpframe))
{
#if defined(DEBUG_PRINT)
printf("TFTP: Invalid server port: %d\n", \
UDP_SOURCE(udpframe));
#endif
/* Send ERROR packet to source */
tftp_error(TFTP_ERR_TID, UDP_SOURCE(udpframe));
break;
}
}
/* Add the buffer to the TFTP queue */
queue_add(&tcxn.queue, (QNODE *)pNbuf);
/* Update number of the next block expected */
tcxn.exp_blocknum++;
/* Increment number of bytes received counter */
tcxn.bytes_recv += (pNbuf->length - 4);
/* Update progress indicator */
if (++cnt == 50)
{
ihash = (ihash + 1) % 4;
board_putchar(CTRL_BS);
board_putchar(hash[ihash]);
cnt = 0;
}
}
else
{
if (tftp_pkt->data.blocknum < tcxn.exp_blocknum)
{
/* Re-ACK this packet */
tftp_ack(tftp_pkt->data.blocknum);
}
#if defined(DEBUG_PRINT)
/* This is NOT the block expected */
printf("Exp: %d, ", tcxn.exp_blocknum);
printf("Rcv: %d\n", tftp_pkt->data.blocknum);
#endif
/* Free the network buffer */
nbuf_free(pNbuf);
}
break;
case TFTP_ERROR:
printf("\nTFTP Error #%d: ",tftp_pkt->error.code);
printf("%s\n",tftp_pkt->error.msg);
tcxn.error = TRUE;
/* Free the network buffer */
nbuf_free(pNbuf);
break;
case TFTP_ACK:
if (tftp_pkt->ack.blocknum == tcxn.exp_blocknum)
{
if (tftp_pkt->data.blocknum == 0)
{ /* This is the first ACK received */
/* Save the server's transfer ID */
tcxn.server_port = UDP_SOURCE(udpframe);
/* Mark the connection as open */
tcxn.open = TRUE;
}
else
{ /* Check the server's transfer ID */
if (tcxn.server_port != UDP_SOURCE(udpframe))
{
#if defined(DEBUG_PRINT)
printf("TFTP: Invalid server port: %d\n", \
UDP_SOURCE(udpframe));
#endif
/*Send ERROR packet to source */
tftp_error(TFTP_ERR_TID, UDP_SOURCE(udpframe));
break;
}
}
tcxn.exp_blocknum++;
}
else
{
#if defined(DEBUG_PRINT)
/* This is NOT the block number expected */
printf("ACK Exp: %d, ", tcxn.exp_blocknum);
printf("ACK Rcv: %d\n", tftp_pkt->ack.blocknum);
#endif
}
/* Free the network buffer */
nbuf_free(pNbuf);
break;
case TFTP_RRQ:
case TFTP_WRQ:
default:
/* Free the network buffer */
nbuf_free(pNbuf);
break;
}
}
/********************************************************************/
void
tftp_end (int success)
{
/*
* Following a successful transfer the caller should pass in
* TRUE, there should have been no ERROR packets received, and
* the connection should have been marked as closed by the
* tftp_in_char() routine.
*/
if (success && !tcxn.error && (tcxn.open == FALSE))
{
printf("\bTFTP transfer completed \n");
printf("Read %d bytes (%d blocks)\n", \
tcxn.bytes_recv, tcxn.exp_blocknum - 1);
}
else
{
/* Send error packet to stifle the server */
tftp_error(TFTP_ERR_ILL, tcxn.server_port);
printf("\bErrors in TFTP transfer.\n");
printf("Read %d bytes (%d blocks)\n", \
tcxn.bytes_recv, tcxn.exp_blocknum - 1);
}
/* Free up any buffers left in the queue */
while (!queue_isempty(&tcxn.queue))
nbuf_free((NBUF *)queue_remove(&tcxn.queue));
/* Free the UDP port */
udp_free_port(tcxn.my_port);
}
/********************************************************************/
int
tftp_write (NIF *nif, char *fn, IP_ADDR_P server, uint32 begin, uint32 end)
{
DATA *data;
NBUF *pNbuf;
uint32 i, retries, bytes_to_send;
uint16 blocknum, this_size;
uint8 success, *current;
int result;
if (fn == 0 || server == 0 || end < begin)
return 0;
/* Setup initial connection status */
tcxn.nif = nif;
tcxn.file = fn;
tcxn.server_ip[0] = server[0];
tcxn.server_ip[1] = server[1];
tcxn.server_ip[2] = server[2];
tcxn.server_ip[3] = server[3];
tcxn.server_port = UDP_PORT_TFTP;
tcxn.exp_blocknum = 0;
tcxn.dir = TFTP_WRQ;
tcxn.open = FALSE;
tcxn.bytes_sent = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -