#include #include #include #include "ftpd.h" #include "mem.h" #include "rtc.h" #include "ff.h" #include "serial_debug.h" #include "netconf.h" int cable_connect = 1; int datarecv_flag = 0; static __attribute__ ((aligned (4)))char buffer_x[DATACONNECT_BUFFER_SIZE-1]; struct ftpd_msgstate *fsm; static FIL sfil; FIL *fil = &sfil; static void send_msg(struct tcp_pcb *pcb, struct ftpd_msgstate *fsm, char *msg, ...); static const char *month_table[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dez" }; static void sfifo_flush(sfifo_t *f) { f->readpos = 0; f->writepos = 0; } static int32_t sfifo_init(sfifo_t *f, uint32_t size) { memset(f, 0, sizeof(sfifo_t)); f->size = size; sfifo_flush(f); f->buffer = (void *)mem_malloc(f->size); if (f->buffer == NULL) { PDU_DEBUGF(PDU_FTP_MSG_DEBUG,("mem_malloc error! [%d, %s]\r\n", __LINE__, __FUNCTION__)); return -1; } return 0; } static void sfifo_close(sfifo_t *f) { if(f->buffer) { mem_free(f->buffer); } sfifo_flush(f); } static int32_t sfifo_write(sfifo_t *f, const void *_buf, uint32_t len) { int32_t total = 0; uint32_t i = 0; const char *buf = (const char *)_buf; if(!f->buffer) { return -1; } total = sfifo_space(f); if(len > total) { len = total; } else { total = len; } i = f->writepos; if(i + len > f->size) { memcpy(f->buffer + i, buf, f->size - i); buf += f->size - i; len -= f->size - i; i = 0; } memcpy(f->buffer + i, buf, len); f->writepos = i + len; return total; } static void ftpd_dataerr(void *arg, err_t err) { struct ftpd_datastate *fsd = arg; /* if (fsd != NULL) { sfifo_close(&fsd->fifo); mem_free(fsd); } */ if (fsm->datafs != NULL) { sfifo_close(&fsm->datafs->fifo); mem_free(fsm->datafs); fsm->datafs = NULL; } if (fsm->listenpcb) { tcp_close(fsm->listenpcb); } fsd->msgfs->state = FTPD_IDLE; } static void ftpd_dataclose(struct tcp_pcb *pcb, struct ftpd_datastate *fsd) { tcp_arg(pcb, NULL); tcp_sent(pcb, NULL); tcp_recv(pcb, NULL); fsd->msgfs->datafs = NULL; sfifo_close(&fsd->fifo); mem_free(fsd); tcp_close(pcb); if (fsm->listenpcb) { tcp_close(fsm->listenpcb); } } static void send_data(struct tcp_pcb *pcb, struct ftpd_datastate *fsd) { err_t err; u16_t len; int i; if (sfifo_used(&fsd->fifo) > 0) { if (tcp_sndbuf(pcb) < sfifo_used(&fsd->fifo)) { len = tcp_sndbuf(pcb); } else { len = (u16_t)sfifo_used(&fsd->fifo); } i = fsd->fifo.readpos; if ((i + len) > fsd->fifo.size) { err = tcp_write(pcb, fsd->fifo.buffer + i, (u16_t)(fsd->fifo.size - i), 1); if (err != ERR_OK) { return; } len -= fsd->fifo.size - i; fsd->fifo.readpos = 0; i = 0; } err = tcp_write(pcb, fsd->fifo.buffer + i, len, 1); if (err != ERR_OK) { return; } fsd->fifo.readpos += len; } } static void send_file(struct ftpd_datastate *fsd, struct tcp_pcb *pcb) { FRESULT rc; if (!fsd->connected) { return; } if (fsd->fil) { UINT len; if (sfifo_space(&fsd->fifo) < (DATACONNECT_BUFFER_SIZE - 2)) { send_data(pcb, fsd); return; } rc = f_read(fsd->fil, buffer_x, sizeof (buffer_x), &len); if (rc || (len == 0)) { f_close(fsd->fil); fsd->fil = NULL; return; } sfifo_write(&fsd->fifo, buffer_x, len); send_data(pcb, fsd); if (sfifo_used(&fsd->fifo) < 1024) { send_data(pcb, fsd); return; } rc = f_read(fsd->fil, buffer_x, sfifo_space(&fsd->fifo), &len); if (rc || (len == 0)) { f_close(fsd->fil); fsd->fil = NULL; return; } sfifo_write(&fsd->fifo, buffer_x, len); } else { struct ftpd_msgstate *fsm; struct tcp_pcb *msgpcb; if (sfifo_used(&fsd->fifo) > 0) { send_data(pcb, fsd); return; } fsm = fsd->msgfs; msgpcb = fsd->msgpcb; f_close(fsd->fil); fsd->fil = NULL; ftpd_dataclose(pcb, fsd); fsm->datapcb = NULL; fsm->datafs = NULL; fsm->state = FTPD_IDLE; send_msg(msgpcb, fsm, msg226); } return; } static void send_next_directory(struct ftpd_datastate *fsd, struct tcp_pcb *pcb, int shortlist) { FRESULT rc; int len; char buffer_y[128]; RTC_TimeTypeDef RTC_TimeStructure; RTC_DateTypeDef RTC_DateStructure; while (1) { if (fsd->fno == NULL) { fsd->fno = mem_malloc(sizeof(FILINFO)); if (fsd->fno == NULL) { PDU_DEBUGF(PDU_FTP_MSG_DEBUG, ("mem_malloc error! [%d, %s]\r\n", __LINE__, __FUNCTION__)); return; } rc = f_readdir(fsd->dir, fsd->fno); if (rc || !fsd->fno->fname[0]) { return; /* Error or end of dir */ } if (shortlist) { len = sprintf(buffer_y, "%8lu %s\r\n", fsd->fno->fsize, fsd->fno->fname); sfifo_write(&fsd->fifo, buffer_y, len); send_data(pcb, fsd); mem_free(fsd->fno); fsd->fno = NULL; } else { RTC_GetTime(RTC_Format_BIN, &RTC_TimeStructure); RTC_GetDate(RTC_Format_BIN, &RTC_DateStructure); len = sprintf(buffer_y, "-rw-rw-rw- 1 enlogic ftp %11ld %s %02i %02i:%02i %s\r\n", fsd->fno->fsize, month_table[RTC_DateStructure.RTC_Month], RTC_DateStructure.RTC_WeekDay, RTC_TimeStructure.RTC_Hours, RTC_TimeStructure.RTC_Minutes, fsd->fno->fname); if (fsd->fno->fattrib & AM_DIR) { buffer_y[0] = 'd'; } sfifo_write(&fsd->fifo, buffer_y, len); send_data(pcb, fsd); mem_free(fsd->fno); fsd->fno = NULL; } } else { struct ftpd_msgstate *fsm; struct tcp_pcb *msgpcb; if (sfifo_used(&fsd->fifo) > 0) { send_data(pcb, fsd); return; } fsm = fsd->msgfs; msgpcb = fsd->msgpcb; mem_free(fsd->fno); fsd->dir = NULL; fsd->fno = NULL; ftpd_dataclose(pcb, fsd); fsm->datapcb = NULL; fsm->datafs = NULL; fsm->state = FTPD_IDLE; send_msg(msgpcb, fsm, msg226); return; } } } static err_t ftpd_datasent(void *arg, struct tcp_pcb *pcb, u16_t len) { struct ftpd_datastate *fsd = arg; switch (fsd->msgfs->state) { case FTPD_LIST: send_next_directory(fsd, pcb, 0); break; case FTPD_NLST: send_next_directory(fsd, pcb, 1); break; case FTPD_RETR: send_file(fsd, pcb); break; default: break; } return ERR_OK; } static err_t ftpd_datarecv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) { struct ftpd_datastate *fsd = arg; if (err == ERR_OK && p != NULL) { struct pbuf *q; u16_t tot_len = 0; for (q = p; q != NULL; q = q->next) { UINT len; f_write(fsd->fil, q->payload, q->len, &len); tot_len += len; if (len != q->len) break; } tcp_recved(pcb, tot_len); pbuf_free(p); datarecv_flag = 1; } if (err == ERR_OK && p == NULL) { struct ftpd_msgstate *fsm; struct tcp_pcb *msgpcb; fsm = fsd->msgfs; msgpcb = fsd->msgpcb; f_close(fsd->fil); fsd->fil = NULL; ftpd_dataclose(pcb, fsd); fsm->datapcb = NULL; fsm->datafs = NULL; fsm->state = FTPD_IDLE; send_msg(msgpcb, fsm, msg226); datarecv_flag = 0; } return ERR_OK; } static err_t ftpd_dataconnected(void *arg, struct tcp_pcb *pcb, err_t err) { struct ftpd_datastate *fsd = arg; fsd->msgfs->datapcb = pcb; fsd->connected = 1; tcp_recv(pcb, ftpd_datarecv); tcp_sent(pcb, ftpd_datasent); tcp_err(pcb, ftpd_dataerr); switch (fsd->msgfs->state) { case FTPD_LIST: send_next_directory(fsd, pcb, 0); break; case FTPD_NLST: send_next_directory(fsd, pcb, 1); break; case FTPD_RETR: send_file(fsd, pcb); break; default: break; } return ERR_OK; } static err_t ftpd_dataaccept(void *arg, struct tcp_pcb *pcb, err_t err) { struct ftpd_datastate *fsd = arg; fsd->msgfs->datapcb = pcb; fsd->connected = 1; tcp_recv(pcb, ftpd_datarecv); tcp_sent(pcb, ftpd_datasent); tcp_err(pcb, ftpd_dataerr); switch (fsd->msgfs->state) { case FTPD_LIST: send_next_directory(fsd, pcb, 0); break; case FTPD_NLST: send_next_directory(fsd, pcb, 1); break; case FTPD_RETR: send_file(fsd, pcb); break; default: break; } return ERR_OK; } static int open_dataconnection(struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) { if (fsm->passive) { fsm->passive = 0; return 0; } if (fsm->datafs != NULL) { mem_free(fsm->datafs); fsm->datafs = NULL; } fsm->datafs = mem_malloc(sizeof(struct ftpd_datastate)); if (fsm->datafs == NULL) { PDU_DEBUGF(PDU_FTP_MSG_DEBUG, ("mem_malloc error! [%d, %s]\r\n", __LINE__, __FUNCTION__)); send_msg(pcb, fsm, msg451); return 1; } memset(fsm->datafs, 0, sizeof(struct ftpd_datastate)); fsm->datafs->msgfs = fsm; fsm->datafs->msgpcb = pcb; if (sfifo_init(&fsm->datafs->fifo, DATACONNECT_BUFFER_SIZE) < 0) { return -1; } fsm->datapcb = tcp_new(); tcp_bind(fsm->datapcb, &pcb->local_ip, 20); tcp_arg(fsm->datapcb, fsm->datafs); if ( ERR_OK != tcp_connect(fsm->datapcb, &fsm->dataip, fsm->dataport, ftpd_dataconnected)) { return -1; } return 0; } static void cmd_user(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) { send_msg(pcb, fsm, msg331); fsm->state = FTPD_PASS; } static void cmd_port(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) { int nr; unsigned pHi, pLo; unsigned ip[4]; nr = sscanf(arg, "%u,%u,%u,%u,%u,%u", &(ip[0]), &(ip[1]), &(ip[2]), &(ip[3]), &pHi, &pLo); if (nr != 6) { send_msg(pcb, fsm, msg501); } else { IP4_ADDR(&fsm->dataip, (u8_t) ip[0], (u8_t) ip[1], (u8_t) ip[2], (u8_t) ip[3]); fsm->dataport = ((u32_t) pHi << 8) + (u32_t)pLo; send_msg(pcb, fsm, msg200); } } static void cmd_quit(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) { send_msg(pcb, fsm, msg221); fsm->state = FTPD_QUIT; } static void cmd_pwd(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) { char path[32] = {0}; char *ptr = NULL; if (!f_getcwd(path, sizeof(path))) { ptr = strchr(path, ':'); ptr ++; send_msg(pcb, fsm, msg257PWD, ptr); } } static void cmd_list_common(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm, int shortlist) { FRESULT rc; DIR *dir; dir = mem_malloc(sizeof(DIR)); if (dir == NULL) { PDU_DEBUGF(PDU_FTP_MSG_DEBUG, ("mem_malloc error! [%d, %s]\r\n", __LINE__, __FUNCTION__)); return; } rc = f_opendir(dir, ""); if (rc) { return; } if (open_dataconnection(pcb, fsm) != 0) { mem_free(dir); dir = NULL; return; } fsm->datafs->dir = dir; fsm->datafs->fno = NULL; if (shortlist != 0) { fsm->state = FTPD_NLST; } else { fsm->state = FTPD_LIST; } send_msg(pcb, fsm, msg150); } static void cmd_nlst(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) { cmd_list_common(arg, pcb, fsm, 1); } static void cmd_list(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) { cmd_list_common(arg, pcb, fsm, 0); } static void cmd_syst(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) { send_msg(pcb, fsm, msg214SYST, "Windows NT"); } static void cmd_type(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) { send_msg(pcb, fsm, msg200); } static void cmd_mode(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) { send_msg(pcb, fsm, msg502); } static void cmd_rnfr(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) { if (arg == NULL) { send_msg(pcb, fsm, msg501); return; } if (*arg == '\0') { send_msg(pcb, fsm, msg501); return; } if (fsm->renamefrom) { mem_free(fsm->renamefrom); } fsm->renamefrom = mem_malloc(strlen(arg) + 1); if (fsm->renamefrom == NULL) { PDU_DEBUGF(PDU_FTP_MSG_DEBUG,("mem_malloc error! [%d, %s]\r\n", __LINE__, __FUNCTION__)); send_msg(pcb, fsm, msg451); return; } strcpy(fsm->renamefrom, arg); fsm->state = FTPD_RNFR; send_msg(pcb, fsm, msg350); } static void cmd_rnto(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) { if (fsm->state != FTPD_RNFR) { send_msg(pcb, fsm, msg503); return; } fsm->state = FTPD_IDLE; if (arg == NULL) { send_msg(pcb, fsm, msg501); return; } if (*arg == '\0') { send_msg(pcb, fsm, msg501); return; } if (!f_rename(fsm->renamefrom, arg)) { send_msg(pcb, fsm, msg250); } else { send_msg(pcb, fsm, msg450); } } static void cmd_mkd(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) { if (arg == NULL) { send_msg(pcb, fsm, msg501); return; } if (*arg == '\0') { send_msg(pcb, fsm, msg501); return; } if (!f_mkdir(arg)) { send_msg(pcb, fsm, msg257, arg); } else { send_msg(pcb, fsm, msg550); } } static void cmd_pass(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) { send_msg(pcb, fsm, msg230); f_chdir("/"); fsm->state = FTPD_IDLE; } static void cmd_cwd(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) { if (!f_chdir(arg)) { send_msg(pcb, fsm, msg250); } else { send_msg(pcb, fsm, msg550); } } static void cmd_cdup(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) { if (!f_chdir(arg)) { send_msg(pcb, fsm, msg250); } else { send_msg(pcb, fsm, msg550); } } static void cmd_retr(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) { FRESULT rc; rc = f_open(fil, arg, FA_READ); if (rc) { send_msg(pcb, fsm, msg550); return; } send_msg(pcb, fsm, msg150recv, arg, strlen(arg)); if (open_dataconnection(pcb, fsm) != 0) { f_close(fil); return; } fsm->datafs->fil = fil; fsm->state = FTPD_RETR; } static void cmd_stor(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) { FRESULT rc; rc = f_open(fil, arg, FA_WRITE | FA_CREATE_ALWAYS); if (rc) { send_msg(pcb, fsm, msg550); return; } send_msg(pcb, fsm, msg150stor, arg); if (open_dataconnection(pcb, fsm) != 0) { f_close(fil); return; } fsm->datafs->fil = fil; fsm->state = FTPD_STOR; } static void cmd_size(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) { send_msg(pcb, fsm, msg213); } static void cmd_appe(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) { send_msg(pcb, fsm, msg213); } static void cmd_pasv(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) { static u16_t port = 4096; static u16_t start_port = 4096; struct tcp_pcb *temppcb; if (fsm->datafs != NULL) { mem_free(fsm->datafs); fsm->datafs = NULL; } fsm->datafs = mem_malloc(sizeof(struct ftpd_datastate)); if (fsm->datafs == NULL) { PDU_DEBUGF(PDU_FTP_MSG_DEBUG, ("mem_malloc error! [%d, %s]\r\n", __LINE__, __FUNCTION__)); send_msg(pcb, fsm, msg451); return; } memset(fsm->datafs, 0, sizeof(struct ftpd_datastate)); if (fsm->datapcb != NULL) { tcp_close(fsm->datapcb); } fsm->datapcb = tcp_new(); if (!fsm->datapcb) { mem_free(fsm->datafs); send_msg(pcb, fsm, msg451); return; } if (sfifo_init(&fsm->datafs->fifo, DATACONNECT_BUFFER_SIZE) < 0) { return ; } start_port = port; while (1) { err_t err; if(++port > 0x4fff) { port = 4096; } fsm->dataport = port; err = tcp_bind(fsm->datapcb, &pcb->local_ip, fsm->dataport); if (err == ERR_OK) { break; } if (start_port == port) { err = ERR_CLSD; } if (err == ERR_USE) { continue; } if (err != ERR_OK) { ftpd_dataclose(fsm->datapcb, fsm->datafs); fsm->datapcb = NULL; fsm->datafs = NULL; return; } } temppcb = tcp_listen(fsm->datapcb); if (!temppcb) { printf(" tmppcb fails \r\n"); ftpd_dataclose(fsm->datapcb, fsm->datafs); fsm->datapcb = NULL; fsm->datafs = NULL; return; } fsm->listenpcb = temppcb; fsm->passive = 1; fsm->datafs->connected = 0; fsm->datafs->msgfs = fsm; fsm->datafs->msgpcb = pcb; tcp_arg(fsm->listenpcb, fsm->datafs); tcp_accept(fsm->listenpcb, ftpd_dataaccept); send_msg(pcb, fsm, msg227, ip4_addr1(&pcb->local_ip), ip4_addr2(&pcb->local_ip), ip4_addr3(&pcb->local_ip), ip4_addr4(&pcb->local_ip), (fsm->dataport >> 8) & 0xff, (fsm->dataport) & 0xff); } static void cmd_abrt(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) { tcp_arg(fsm->datapcb, NULL); tcp_sent(fsm->datapcb, NULL); tcp_recv(fsm->datapcb, NULL); tcp_abort(pcb); fsm->state = FTPD_IDLE; } static void cmd_dele(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) { FILINFO finfo; if (arg == NULL) { send_msg(pcb, fsm, msg501); return; } if (*arg == '\0') { send_msg(pcb, fsm, msg501); return; } if (f_stat(arg, &finfo)) { send_msg(pcb, fsm, msg550); return; } if (!f_unlink(arg)) { send_msg(pcb, fsm, msg250); } else { send_msg(pcb, fsm, msg550); } } static void cmd_rmd(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) { cmd_dele(arg, pcb, fsm); } static void cmd_noop(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) { send_msg(pcb, fsm, msg200); } static struct ftpd_command ftpd_commands[] = { "USER", cmd_user, "PASS", cmd_pass, "PORT", cmd_port, "QUIT", cmd_quit, "BYE", cmd_quit, "CWD", cmd_cwd, "CDUP", cmd_cdup, "PWD", cmd_pwd, "XPWD", cmd_pwd, "NLST", cmd_nlst, "LIST", cmd_list, "RETR", cmd_retr, "STOR", cmd_stor, "NOOP", cmd_noop, "SYST", cmd_syst, "ABOR", cmd_abrt, "TYPE", cmd_type, "MODE", cmd_mode, "RNFR", cmd_rnfr, "RNTO", cmd_rnto, "MKD", cmd_mkd, "XMKD", cmd_mkd, "RMD", cmd_rmd, "XRMD", cmd_rmd, "DELE", cmd_dele, "PASV", cmd_pasv, "SIZE", cmd_size, "APPE", cmd_appe, NULL }; static void send_msgdata(struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) { err_t err; u16_t len; if (sfifo_used(&fsm->fifo) > 0) { int i; if (tcp_sndbuf(pcb) < sfifo_used(&fsm->fifo)) { len = tcp_sndbuf(pcb); } else { len = (u16_t) sfifo_used(&fsm->fifo); } i = fsm->fifo.readpos; if ((i + len) > fsm->fifo.size) { err = tcp_write(pcb, fsm->fifo.buffer + i, (u16_t)(fsm->fifo.size - i), 1); if (err != ERR_OK) { PDU_DEBUGF(PDU_FTP_MSG_DEBUG, ("send_msgdata: error writing!\n")); return; } len -= fsm->fifo.size - i; fsm->fifo.readpos = 0; i = 0; } err = tcp_write(pcb, fsm->fifo.buffer + i, len, 1); if (err != ERR_OK) { PDU_DEBUGF(PDU_FTP_MSG_DEBUG, ("send_msgdata: error writing!\n")); return; } fsm->fifo.readpos += len; } } static void send_msg(struct tcp_pcb *pcb, struct ftpd_msgstate *fsm, char *msg, ...) { va_list arg; char buffer[SFIFO_MAX_BUFFER_SIZE]; int len; va_start(arg, msg); vsprintf(buffer, msg, arg); va_end(arg); strcat(buffer, "\r\n"); len = strlen(buffer); if (sfifo_space(&fsm->fifo) < len) { return; } sfifo_write(&fsm->fifo, buffer, len); send_msgdata(pcb, fsm); } static void ftpd_msgerr(void *arg, err_t err) { struct ftpd_msgstate *fsm = arg; if (fsm == NULL) { return; } if (fsm->datafs) { ftpd_dataclose(fsm->datapcb, fsm->datafs); } sfifo_close(&fsm->fifo); mem_free(fsm); } static void ftpd_msgclose(struct tcp_pcb *pcb, struct ftpd_msgstate *fsm) { tcp_arg(pcb, NULL); tcp_sent(pcb, NULL); tcp_recv(pcb, NULL); if (fsm->datafs) { ftpd_dataclose(fsm->datapcb, fsm->datafs); } sfifo_close(&fsm->fifo); mem_free(fsm); tcp_arg(pcb, NULL); tcp_close(pcb); } static err_t ftpd_msgsent(void *arg, struct tcp_pcb *pcb, u16_t len) { struct ftpd_msgstate *fsm = arg; if (pcb->state > ESTABLISHED) { return ERR_OK; } if ((sfifo_used(&fsm->fifo) == 0) && (fsm->state == FTPD_QUIT)) { ftpd_msgclose(pcb, fsm); } send_msgdata(pcb, fsm); return ERR_OK; } static err_t ftpd_msgrecv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) { char *text = NULL; struct ftpd_msgstate *fsm = arg; if (err == ERR_OK && p != NULL) { tcp_recved(pcb, p->tot_len); text = mem_malloc(p->tot_len + 1); if (text) { char cmd[5]; struct pbuf *q; char *pt = text; struct ftpd_command *ftpd_cmd; for (q = p; q != NULL; q = q->next) { memcpy(pt, q->payload, q->len); pt += q->len; } *pt = '\0'; pt = &text[strlen(text) - 1]; while (((*pt == '\r') || (*pt == '\n')) && pt >= text) { *pt-- = '\0'; } PDU_DEBUGF(PDU_FTP_MSG_DEBUG, ("query: %s \r\n", text)); if (!strncmp(text, "CWD", 3) || !strncmp(text, "MKD", 3) || !strncmp(text, "RMD", 3)) { strncpy(cmd, text, 3); for (pt = cmd; (pt < &cmd[3]); pt++) *pt = toupper(*pt); } else { strncpy(cmd, text, 4); for (pt = cmd; (pt < &cmd[4]); pt++) *pt = toupper(*pt); } *pt = '\0'; for (ftpd_cmd = ftpd_commands; ftpd_cmd->cmd != NULL; ftpd_cmd++) { if (!strcmp(ftpd_cmd->cmd, cmd)) { break; } } if (strlen(text) < (strlen(cmd) + 1)) { pt = ""; } else { pt = &text[strlen(cmd) + 1]; } if (ftpd_cmd->func) { ftpd_cmd->func(pt, pcb, fsm); } else { send_msg(pcb, fsm, msg502); } mem_free(text); } pbuf_free(p); } return ERR_OK; } static err_t ftpd_msgpoll(void *arg, struct tcp_pcb *pcb) { struct ftpd_msgstate *fsm = arg; if (fsm == NULL) { return ERR_OK; } if (fsm->datafs) { if (fsm->datafs->connected) { switch (fsm->state) { case FTPD_LIST: send_next_directory(fsm->datafs, fsm->datapcb, 0); break; case FTPD_NLST: send_next_directory(fsm->datafs, fsm->datapcb, 1); break; case FTPD_RETR: send_file(fsm->datafs, fsm->datapcb); break; default: break; } } } if (cable_connect == 0 && datarecv_flag == 1) { ftpd_msgclose(pcb, fsm); /* if (fsm->listenpcb) { tcp_close(fsm->listenpcb); } */ } return ERR_OK; } static err_t ftpd_msgaccept(void *arg, struct tcp_pcb *pcb, err_t err) { fsm = mem_malloc(sizeof(struct ftpd_msgstate)); if (fsm == NULL) { PDU_DEBUGF(PDU_FTP_MSG_DEBUG, ("ftpd_msgaccept: Out of memory \r\n")); return ERR_MEM; } memset(fsm, 0, sizeof(struct ftpd_msgstate)); if (sfifo_init(&fsm->fifo, SFIFO_MAX_BUFFER_SIZE) < 0) { PDU_DEBUGF(PDU_FTP_MSG_DEBUG, ("ftpd msgaccept: Out of memory \r\n")); return ERR_MEM; } fsm->state = FTPD_IDLE; tcp_arg(pcb, fsm); tcp_recv(pcb, ftpd_msgrecv); tcp_sent(pcb, ftpd_msgsent); tcp_err(pcb, ftpd_msgerr); tcp_poll(pcb, ftpd_msgpoll, 1); send_msg(pcb, fsm, msg220); return ERR_OK; } static void ftpd_init(void) { struct tcp_pcb *pcb; pcb = tcp_new(); tcp_bind(pcb, IP_ADDR_ANY, 21); pcb = tcp_listen(pcb); tcp_accept(pcb, ftpd_msgaccept); for (;;) { vTaskDelay(250); } } void Ftp_task(void *pvArg) { LwIP_DHCP_wait(); ftpd_init(); }