[lib][tftp] Move tftp from inetsrv and apply review changes.

From https://codereview.chromium.org/1346853002
This commit is contained in:
Carlos Pizano
2015-09-16 18:21:57 -07:00
parent ac406077ae
commit d0d5f33bfc
5 changed files with 59 additions and 29 deletions

View File

@@ -29,11 +29,11 @@
#include <compiler.h> #include <compiler.h>
#include <kernel/thread.h> #include <kernel/thread.h>
#include <lib/minip.h> #include <lib/minip.h>
#include <lib/tftp.h>
#include <lib/cksum.h> #include <lib/cksum.h>
#include <platform.h> #include <platform.h>
#include "inetsrv.h" #include "inetsrv.h"
#include "tftp.h"
static int chargen_worker(void *socket) static int chargen_worker(void *socket)
{ {

View File

@@ -4,10 +4,11 @@ MODULE := $(LOCAL_DIR)
MODULE_SRCS += \ MODULE_SRCS += \
$(LOCAL_DIR)/inetsrv.c \ $(LOCAL_DIR)/inetsrv.c \
$(LOCAL_DIR)/tftp.c \
MODULE_DEPS := \ MODULE_DEPS := \
lib/cksum \ lib/cksum \
lib/minip \ lib/minip \
lib/tftp \
include make/module.mk include make/module.mk

14
lib/tftp/rules.mk Normal file
View File

@@ -0,0 +1,14 @@
LOCAL_DIR := $(GET_LOCAL_DIR)
MODULE := $(LOCAL_DIR)
MODULE_DEPS := \
lib/minip \
lib/cksum
GLOBAL_INCLUDES += $(LOCAL_DIR)/include
MODULE_SRCS += \
$(LOCAL_DIR)/tftp.c \
include make/module.mk

View File

@@ -23,6 +23,7 @@
#include <err.h> #include <err.h>
#include <trace.h> #include <trace.h>
#include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <list.h> #include <list.h>
@@ -32,9 +33,9 @@
#include <lib/cksum.h> #include <lib/cksum.h>
#include <platform.h> #include <platform.h>
#include "tftp.h" #include <lib/tftp.h>
#define TFTP_BUFSIZE 512 #define LOCAL_TRACE 0
// TFTP Opcodes: // TFTP Opcodes:
#define TFTP_OPCODE_RRQ 1UL #define TFTP_OPCODE_RRQ 1UL
@@ -60,7 +61,8 @@
static struct list_node tftp_list = LIST_INITIAL_VALUE(tftp_list); static struct list_node tftp_list = LIST_INITIAL_VALUE(tftp_list);
// Represents tftp jobs in progress or possible. // Represents tftp jobs and clients of them. If |socket| is not null the
// job is in progress and members below it are valid.
typedef struct { typedef struct {
struct list_node list; struct list_node list;
// Registration info. // Registration info.
@@ -78,35 +80,42 @@ uint16_t next_port = 2224;
static void send_ack(udp_socket_t* socket, uint16_t count) static void send_ack(udp_socket_t* socket, uint16_t count)
{ {
// Packet is [4][count].
status_t st; status_t st;
uint16_t ack[] = {htons(TFTP_OPCODE_ACK), htons(count)}; uint16_t ack[] = {htons(TFTP_OPCODE_ACK), htons(count)};
st = udp_send(ack, sizeof(ack), socket); st = udp_send(ack, sizeof(ack), socket);
if (st < 0) if (st < 0) {
TRACEF("send_ack failed: %d\n", st); LTRACEF("send_ack failed: %d\n", st);
}
}
static void send_error(udp_socket_t* socket, uint16_t code)
{
// Packet is [5][error code][error in ascii-string][0].
status_t st;
uint16_t ncode = htons(code);
uint16_t err[] = {htons(TFTP_OPCODE_ERROR), ncode,
0x7245, 0x2072, 0x3030 + ncode, 0 };
st = udp_send(err, sizeof(err), socket);
if (st < 0) {
LTRACEF("send_err failed: %d\n", st);
}
} }
static void end_transfer(tftp_job_t* job) static void end_transfer(tftp_job_t* job)
{ {
udp_close(job->socket); udp_close(job->socket);
job->socket = NULL; job->socket = NULL;
job->src_addr = 0UL;
job->callback(NULL, 0UL, job->arg); job->callback(NULL, 0UL, job->arg);
} }
static void send_error(udp_socket_t* socket, uint16_t code)
{
status_t st;
uint16_t ncode = htons(code);
uint16_t err[] = {htons(TFTP_OPCODE_ERROR), ncode,
0x7245, 0x2072, 0x3030 + ncode, 0 };
st = udp_send(err, sizeof(err), socket);
if (st < 0)
TRACEF("send_err failed: %d\n", st);
}
static void udp_wrq_callback(void *data, size_t len, static void udp_wrq_callback(void *data, size_t len,
uint32_t srcaddr, uint16_t srcport, uint32_t srcaddr, uint16_t srcport,
void *arg) void *arg)
{ {
// Packet is [3][count][data]. All packets but the last have 512
// bytes of data, including zero data.
char* data_c = data; char* data_c = data;
tftp_job_t* job = arg; tftp_job_t* job = arg;
job->pkt_count++; job->pkt_count++;
@@ -123,14 +132,14 @@ static void udp_wrq_callback(void *data, size_t len,
} }
if ((srcaddr != job->src_addr) || (srcport != job->src_port)) { if ((srcaddr != job->src_addr) || (srcport != job->src_port)) {
TRACEF("invalid source\n"); LTRACEF("invalid source\n");
send_error(job->socket, TFTP_ERROR_UNKNOWN_XFER); send_error(job->socket, TFTP_ERROR_UNKNOWN_XFER);
end_transfer(job); end_transfer(job);
return; return;
} }
if (RD_U16(data_c) != htons(TFTP_OPCODE_DATA)) { if (RD_U16(data_c) != htons(TFTP_OPCODE_DATA)) {
TRACEF("invalid opcode\n"); LTRACEF("invalid opcode\n");
send_error(job->socket, TFTP_ERROR_ILLEGAL_OP); send_error(job->socket, TFTP_ERROR_ILLEGAL_OP);
end_transfer(job); end_transfer(job);
return; return;
@@ -138,12 +147,14 @@ static void udp_wrq_callback(void *data, size_t len,
send_ack(job->socket, job->pkt_count); send_ack(job->socket, job->pkt_count);
if (job->callback(&data_c[4], len, job->arg) < 0) { if (job->callback(&data_c[4], len - 4, job->arg) < 0) {
// The client wants to abort. // The client wants to abort.
send_error(job->socket, TFTP_ERROR_FULL); send_error(job->socket, TFTP_ERROR_FULL);
end_transfer(job); end_transfer(job);
} }
// 512 bytes payload plus 4 of fixed header. The last packet.
// has always less than 512 bytes of payload.
if (len != 516) { if (len != 516) {
end_transfer(job); end_transfer(job);
} }
@@ -151,6 +162,7 @@ static void udp_wrq_callback(void *data, size_t len,
static tftp_job_t* get_job_by_name(const char* file_name) static tftp_job_t* get_job_by_name(const char* file_name)
{ {
DEBUG_ASSERT(file_name);
tftp_job_t *entry; tftp_job_t *entry;
list_for_every_entry(&tftp_list, entry, tftp_job_t, list) { list_for_every_entry(&tftp_list, entry, tftp_job_t, list) {
if (strcmp(entry->file_name, file_name) == 0) { if (strcmp(entry->file_name, file_name) == 0) {
@@ -171,7 +183,7 @@ static void udp_svc_callback(void *data, size_t len,
st = udp_open(srcaddr, next_port, srcport, &socket); st = udp_open(srcaddr, next_port, srcport, &socket);
if (st < 0) { if (st < 0) {
TRACEF("error opening send socket %d\n", st); LTRACEF("error opening send socket %d\n", st);
return; return;
} }
@@ -180,7 +192,7 @@ static void udp_svc_callback(void *data, size_t len,
if (opcode != TFTP_OPCODE_WRQ) if (opcode != TFTP_OPCODE_WRQ)
{ {
// Operation not suported. // Operation not suported.
TRACEF("op not supported, opcode: %d\n", opcode); LTRACEF("op not supported, opcode: %d\n", opcode);
send_error(socket, TFTP_ERROR_ACCESS); send_error(socket, TFTP_ERROR_ACCESS);
udp_close(socket); udp_close(socket);
return; return;
@@ -192,7 +204,7 @@ static void udp_svc_callback(void *data, size_t len,
if (!job) { if (!job) {
// Nobody claims to handle that file. // Nobody claims to handle that file.
TRACEF("no client registered for file\n"); LTRACEF("no client registered for file\n");
send_error(socket, TFTP_ERROR_UNKNOWN_XFER); send_error(socket, TFTP_ERROR_UNKNOWN_XFER);
udp_close(socket); udp_close(socket);
return; return;
@@ -202,15 +214,15 @@ static void udp_svc_callback(void *data, size_t len,
// There is already an ongoing job. // There is already an ongoing job.
// TODO: garbage collect the existing one if too long since the // TODO: garbage collect the existing one if too long since the
// last packet was processed. // last packet was processed.
TRACEF("existing job in progress\n"); LTRACEF("existing job in progress\n");
send_error(socket, TFTP_ERROR_EXISTS); send_error(socket, TFTP_ERROR_EXISTS);
udp_close(socket); udp_close(socket);
return; return;
} }
TRACEF("write op accepted, port %d\n", srcport); LTRACEF("write op accepted, port %d\n", srcport);
// Request accepted. The rest of the transfer happens between // Request accepted. The rest of the transfer happens between
// next_port <----> srcport via |udp_wrq_callback|. // next_port <----> srcport via udp_wrq_callback().
job->socket = socket; job->socket = socket;
job->src_addr = srcaddr; job->src_addr = srcaddr;
@@ -219,7 +231,7 @@ static void udp_svc_callback(void *data, size_t len,
st = udp_listen(next_port, &udp_wrq_callback, job); st = udp_listen(next_port, &udp_wrq_callback, job);
if (st < 0) { if (st < 0) {
TRACEF("error listening on port\n"); LTRACEF("error listening on port\n");
return; return;
} }
@@ -229,6 +241,9 @@ static void udp_svc_callback(void *data, size_t len,
int tftp_set_write_client(const char* file_name, tftp_callback_t cb, void* arg) int tftp_set_write_client(const char* file_name, tftp_callback_t cb, void* arg)
{ {
DEBUG_ASSERT(file_name);
DEBUG_ASSERT(cb);
tftp_job_t *job; tftp_job_t *job;
list_for_every_entry(&tftp_list, job, tftp_job_t, list) { list_for_every_entry(&tftp_list, job, tftp_job_t, list) {
@@ -255,7 +270,7 @@ static unsigned long test_crc = 0UL;
int test_tftp_client(void* data, size_t len, void* arg) { int test_tftp_client(void* data, size_t len, void* arg) {
if (!data) { if (!data) {
TRACEF("--test transfer done-- crc32 = %lu\n", test_crc); printf("--test transfer done-- crc32 = %lu\n", test_crc);
test_crc = 0UL; test_crc = 0UL;
} }