195 lines
5.2 KiB
C
195 lines
5.2 KiB
C
/**
|
|
* @file tftp.c
|
|
* @brief tftp server
|
|
* @author Speetjens S.
|
|
*/
|
|
|
|
#include "tftp.h"
|
|
|
|
static const char* TAG = "tftp_server";
|
|
|
|
extern struct llfs_data_file* llfs_root;
|
|
|
|
static tftp_custom_file_t virt_file[] =
|
|
{
|
|
{.name = "index.txt",.data = NULL, .len = 0, .ofset = 0},
|
|
{.name = "virtImage.raw",.data = NULL, .len = 0, .ofset = 0}
|
|
};
|
|
|
|
int str_cat_str(char* dest, size_t dest_size, const char* src) {
|
|
int dest_len = strlen(dest);
|
|
int src_len = strlen(src);
|
|
if (dest_len + src_len > dest_size) {
|
|
return -1;
|
|
}
|
|
memcpy(dest + dest_len, src, src_len);
|
|
return 0;
|
|
}
|
|
|
|
int str_cat(char* dest, size_t dest_size, char c)
|
|
{
|
|
int dest_len = strlen(dest);
|
|
if (dest_len + 1 > dest_size) {
|
|
return -1;
|
|
}
|
|
dest[dest_len] = c;
|
|
dest[dest_len + 1] = '\0';
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief tftp helper functions
|
|
*/
|
|
|
|
/**
|
|
* @brief This function is called when a file is opened
|
|
* It should return a handle to the file or NULL if the file does not exist
|
|
* The handle contains a ptr to or the actual file data or a virtual file
|
|
*
|
|
* @param fname The name of the file to open
|
|
* @param mode Mode string from TFTP RFC
|
|
* @param write Flag indicating read (0) or write (!= 0) access
|
|
* @return void* File handle supplied to other functions
|
|
*/
|
|
void* tftp_open(const char* fname, const char* mode, u8_t write) {
|
|
LOG_INFO(TAG, "Opening %s", fname);
|
|
|
|
if (strcmp(fname, virt_file[0].name) == 0 && write == TFTP_READ) {
|
|
return &virt_file[0];
|
|
} else if (strcmp(fname, virt_file[1].name) == 0 && write != TFTP_READ) {
|
|
return &virt_file[1];
|
|
}
|
|
|
|
// TODO: waiting on Lorentz to finish creating f* functions for LLFS
|
|
return fopen(fname, write ? "wb" : "rb");
|
|
}
|
|
|
|
/**
|
|
* @brief This function is called when a file is closed
|
|
*
|
|
* @param handle The handle to the file to close
|
|
*/
|
|
void tftp_close(void* handle) {
|
|
LOG_INFO(TAG, "closing file");
|
|
if (handle == NULL) {
|
|
LOG_CRIT(TAG, "handle is null");
|
|
return;
|
|
}
|
|
if (handle == &virt_file[0] || handle == &virt_file[1]) {
|
|
return;
|
|
}
|
|
|
|
// TODO: waiting on Lorentz to finish creating f* functions for LLFS
|
|
fclose((FILE*)handle);
|
|
}
|
|
|
|
/**
|
|
* @brief This function is called when a file is read
|
|
* The virtual files are filtered out first
|
|
* then the file is trying to get read from the llfs
|
|
*
|
|
* @param handle File handle returned by open()
|
|
* @param buf Target buffer to copy read data to
|
|
* @param bytes Number of bytes to copy to buf
|
|
* @return int >= 0: Success; < 0: Error
|
|
*/
|
|
int tftp_read(void* handle, void* buf, int bytes) {
|
|
LOG_INFO(TAG, "reading file");
|
|
if (handle == NULL) {
|
|
LOG_CRIT(TAG, "handle is null");
|
|
return -1;
|
|
}
|
|
FILE* file = (FILE*)handle;
|
|
|
|
if (file == &virt_file[0]) {
|
|
// TODO: read index.txt using tftp_custom_file
|
|
LOG_CRIT(TAG, "Reading from index.txt is not implemented yet");
|
|
return -1;
|
|
|
|
} else if (file == &virt_file[1]) {
|
|
LOG_CRIT(TAG, "Exception: Trying to read a write only file");
|
|
return -1;
|
|
}
|
|
// TODO: waiting on Lorentz to finish creating f* functions for LLFS
|
|
fread(buf, sizeof(uint8_t), bytes, file);
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief This function is called when a file is written
|
|
*
|
|
* @param handle File handle returned by open()
|
|
* @param p PBUF adjusted such that payload pointer points to the beginning of write data.
|
|
* In other words, TFTP headers are stripped off.
|
|
* @return int >= 0: Success; < 0: Error
|
|
*/
|
|
int tftp_write(void* handle, struct pbuf* p) {
|
|
LOG_INFO(TAG, "Writing file");
|
|
LOG_DEBUG(TAG, "Not implemented yet");
|
|
}
|
|
|
|
/**
|
|
* @brief This function creates the file list for index.txt
|
|
*/
|
|
void init_index(void)
|
|
{
|
|
int len = 0;
|
|
// Add len of the virt files to the size
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
len += strlen(virt_file[i].name) + 1;
|
|
}
|
|
const struct llfs_data_file* root = llfs_root;
|
|
while(root != NULL) {
|
|
len += strlen(root->name) + 1;
|
|
root = root->next;
|
|
}
|
|
|
|
virt_file[0].data = malloc(len);
|
|
virt_file[0].len = len;
|
|
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
str_cat_str(virt_file[0].data, len, virt_file[i].name);
|
|
str_cat(virt_file[0].data, len, '\n');
|
|
}
|
|
root = llfs_root;
|
|
while(root != NULL) {
|
|
str_cat_str(virt_file[0].data, len, root->name);
|
|
str_cat(virt_file[0].data, len, '\n');
|
|
root = root->next;
|
|
}
|
|
}
|
|
|
|
struct tftp_context tftpContext_s = {
|
|
.open = tftp_open,
|
|
.close = tftp_close,
|
|
.read = tftp_read,
|
|
.write = tftp_write
|
|
};
|
|
|
|
/**
|
|
* @brief Initialize tftp server
|
|
*/
|
|
void tftp_server_init(void) {
|
|
LOG_INFO(TAG, "Initializing tftp server");
|
|
// init the index.txt virt_file
|
|
init_index();
|
|
|
|
// Init the tftp server
|
|
if (tftp_init(&tftpContext_s) != ERR_OK) {
|
|
LOG_FATAL(TAG, "Could not initialize tftp server");
|
|
return;
|
|
}
|
|
LOG_INFO(TAG, "tftp server initialized successfully");
|
|
}
|
|
|
|
void tftp_server_deinit(void) {
|
|
LOG_INFO(TAG, "Deinitializing tftp server");
|
|
tftp_cleanup();
|
|
LOG_INFO(TAG, "tftp server deinitialized successfully");
|
|
free(virt_file[0].data);
|
|
virt_file[0].data = NULL;
|
|
virt_file[0].len = 0;
|
|
virt_file[0].ofset = 0;
|
|
} |