int tftp_process_read(struct udp_pcb *upcb, struct ip_addr *to, int to_port, char* FileName) { tftp_connection_args *args = NULL; /* If Could not open the file which will be transmitted */ if (file_fopen(&file_SD, &efs1.myFs, FileName, 'r') != 0) { tftp_send_error_message(upcb, to, to_port, TFTP_ERR_FILE_NOT_FOUND); tftp_cleanup_rd(upcb, args); return 0; } /* This function is called from a callback, * therefore, interrupts are disabled, * therefore, we can use regular malloc. */ args = mem_malloc(sizeof *args); /* If we aren't able to allocate memory for a "tftp_connection_args" */ if (!args) { /* unable to allocate memory for tftp args */ tftp_send_error_message(upcb, to, to_port, TFTP_ERR_NOTDEFINED); /* no need to use tftp_cleanup_rd because no "tftp_connection_args" struct has been malloc'd */ tftp_cleanup_rd(upcb, args); return 0; } /* initialize connection structure */ args->op = TFTP_RRQ; args->to_ip.addr = to->addr; args->to_port = to_port; args->block = 1; /* block number starts at 1 (not 0) according to RFC1350 */ args->tot_bytes = 0; /* set callback for receives on this UDP PCB (Protocol Control Block) */ udp_recv(upcb, rrq_recv_callback, args); /* initiate the transaction by sending the first block of data * further blocks will be sent when ACKs are received * - the receive callbacks need to get the proper state */ tftp_send_next_block(upcb, args, to, to_port); return 1; }
/** * @brief processes tftp read operation * @param upcb: pointer on udp pcb * @param to: pointer on remote IP address * @param to_port: pointer on remote udp port * @param FileName: pointer on filename to be read * @retval error code */ int tftp_process_read(struct udp_pcb *upcb, const ip_addr_t *to, unsigned short to_port, char* FileName) { tftp_connection_args *args = NULL; char *path = malloc(strlen(FileName) + sizeof(TFTPD_PATH) + 1); if(!path) return 0; strcpy(path, TFTPD_PATH); strcat(path, FileName); /* If Could not open the file which will be transmitted */ if (f_open(&file_SD, (const TCHAR*)path, FA_READ) != FR_OK) { tftp_send_error_message(upcb, to, to_port, TFTP_ERR_FILE_NOT_FOUND); tftp_cleanup_rd(upcb, args); return 0; } args = mem_malloc(sizeof *args); /* If we aren't able to allocate memory for a "tftp_connection_args" */ if (!args) { /* unable to allocate memory for tftp args */ tftp_send_error_message(upcb, to, to_port, TFTP_ERR_NOTDEFINED); /* no need to use tftp_cleanup_rd because no "tftp_connection_args" struct has been malloc'd */ tftp_cleanup_rd(upcb, args); return 0; } /* initialize connection structure */ args->op = TFTP_RRQ; args->to_ip.addr = to->addr; args->to_port = to_port; args->block = 1; /* block number starts at 1 (not 0) according to RFC1350 */ args->tot_bytes = 0; /* set callback for receives on this UDP PCB */ udp_recv(upcb, rrq_recv_callback, args); /* initiate the transaction by sending the first block of data, further blocks will be sent when ACKs are received */ tftp_send_next_block(upcb, args, to, to_port); return 1; }
/** * @brief processes tftp write operation * @param upcb: pointer on upd pcb * @param to: pointer on remote IP address * @param to_port: pointer on remote udp port * @param FileName: pointer on filename to be written * @retval error code */ int tftp_process_write(struct udp_pcb *upcb, const ip_addr_t *to, unsigned short to_port, char *FileName) { tftp_connection_args *args = NULL; char *path = malloc(strlen(FileName) + sizeof(TFTPD_PATH) + 1); if(!path) return 0; strcpy(path, TFTPD_PATH); strcat(path, FileName); /* Can not create file */ if (f_open(&file_CR, (const TCHAR*)FileName, FA_CREATE_ALWAYS|FA_WRITE) != FR_OK) { tftp_send_error_message(upcb, to, to_port, TFTP_ERR_NOTDEFINED); tftp_cleanup_wr(upcb, args); return 0; } args = mem_malloc(sizeof *args); if (!args) { tftp_send_error_message(upcb, to, to_port, TFTP_ERR_NOTDEFINED); tftp_cleanup_wr(upcb, args); return 0; } args->op = TFTP_WRQ; args->to_ip.addr = to->addr; args->to_port = to_port; /* the block # used as a positive response to a WRQ is _always_ 0!!! (see RFC1350) */ args->block = 0; args->tot_bytes = 0; /* set callback for receives on this UDP PCB */ udp_recv(upcb, wrq_recv_callback, args); /* initiate the write transaction by sending the first ack */ tftp_send_ack_packet(upcb, to, to_port, args->block); return 0; }
int tftp_process_write(struct udp_pcb *upcb, struct ip_addr *to, int to_port, char *FileName) { tftp_connection_args *args = NULL; /* If Could not open the file which will be transmitted */ if (file_fopen(&file_CR, &efs2.myFs, FileName, 'w') != 0) { tftp_send_error_message(upcb, to, to_port, TFTP_ERR_FILE_ALREADY_EXISTS); tftp_cleanup_wr(upcb, args); return 0; } /* This function is called from a callback, * therefore interrupts are disabled, * therefore we can use regular malloc */ args = mem_malloc(sizeof *args); if (!args) { tftp_send_error_message(upcb, to, to_port, TFTP_ERR_NOTDEFINED); tftp_cleanup_wr(upcb, args); return 0; } args->op = TFTP_WRQ; args->to_ip.addr = to->addr; args->to_port = to_port; /* the block # used as a positive response to a WRQ is _always_ 0!!! (see RFC1350) */ args->block = 0; args->tot_bytes = 0; /* set callback for receives on this UDP PCB (Protocol Control Block) */ udp_recv(upcb, wrq_recv_callback, args); /* initiate the write transaction by sending the first ack */ tftp_send_ack_packet(upcb, to, to_port, args->block); return 0; }
/** * @brief processes the tftp request on port 69 * @param pkt_buf: pointer on received pbuf * @param ip_addr: pointer on source IP address * @param port: pointer on source udp port * @retval None */ void process_tftp_request(struct pbuf *pkt_buf, struct ip_addr *addr, u16_t port) { tftp_opcode op = tftp_decode_op(pkt_buf->payload); char FileName[30]; struct udp_pcb *upcb; err_t err; /* create new UDP PCB structure */ upcb = udp_new(); if (!upcb) { /* Error creating PCB. Out of Memory */ return; } /* bind to port 0 to receive next available free port */ /* NOTE: This is how TFTP works. There is a UDP PCB for the standard port * 69 which al transactions begin communication on, however all subsequent * transactions for a given "stream" occur on another port! */ err = udp_bind(upcb, IP_ADDR_ANY, 0); if (err != ERR_OK) { /* Unable to bind to port */ return; } switch (op) { case TFTP_RRQ:/* TFTP RRQ (read request) */ { /* Read the name of the file asked by the client to be sent from the SD card */ tftp_extract_filename(FileName, pkt_buf->payload); _CONSOLE(LogId, "TFTP_RRQ:%s\n", FileName); /* could not open filesystem */ if (f_mount(&filesystem, "", 0) != FR_OK) { return; } /* could not open the selected directory */ if (f_opendir(&dir_1, "/") != FR_OK) { return; } /* Start the TFTP read mode*/ tftp_process_read(upcb, addr, port, FileName); break; } case TFTP_WRQ: /* TFTP WRQ (write request) */ { /* Read the name of the file asked by the client to be received and writen in the SD card */ tftp_extract_filename(FileName, pkt_buf->payload); _CONSOLE(LogId, "TFTP_WRQ:%s\n", FileName); /* Could not open filesystem */ if (f_mount(&filesystem, "", 0) != FR_OK) { return; } /* If Could not open the selected directory */ if (f_opendir(&dir_2, "/") != FR_OK) { return; } /* Start the TFTP write mode*/ tftp_process_write(upcb, addr, port, FileName); break; } default: /* TFTP unknown request op */ /* send generic access violation message */ tftp_send_error_message(upcb, addr, port, TFTP_ERR_ACCESS_VIOLATION); udp_remove(upcb); break; } }
/** * @brief receive callback during tftp write operation (not on standard port 69) * @param arg: pointer on argument passed to callback * @param udp_pcb: pointer on the udp pcb * @param pkt_buf: pointer on the received pbuf * @param addr: pointer on remote IP address * @param port: pointer on remote port * @retval None */ void wrq_recv_callback(void *arg, struct udp_pcb *upcb, struct pbuf *pkt_buf, struct ip_addr *addr, u16_t port) { tftp_connection_args *args = (tftp_connection_args *)arg; int n = 0; /* we expect to receive only one pbuf (pbuf size should be configured > max TFTP frame size */ if (pkt_buf->len != pkt_buf->tot_len) { return; } /* Does this packet have any valid data to write? */ if ((pkt_buf->len > TFTP_DATA_PKT_HDR_LEN) && (tftp_extract_block(pkt_buf->payload) == (args->block + 1))) { /* write the received data to the file */ memcpy((char*)TempBuffer, (char*)pkt_buf->payload + TFTP_DATA_PKT_HDR_LEN, pkt_buf->len - TFTP_DATA_PKT_HDR_LEN); f_write(&file_CR, (char*)TempBuffer, pkt_buf->len - TFTP_DATA_PKT_HDR_LEN, (UINT*)&n); if (n <= 0) { tftp_send_error_message(upcb, addr, port, TFTP_ERR_FILE_NOT_FOUND); /* close the connection */ tftp_cleanup_wr(upcb, args); /* close the connection */ } /* update our block number to match the block number just received */ args->block++; /* update total bytes */ (args->tot_bytes) += (pkt_buf->len - TFTP_DATA_PKT_HDR_LEN); } else if (tftp_extract_block(pkt_buf->payload) == (args->block + 1)) { /* update our block number to match the block number just received */ args->block++; } /* Send the appropriate ACK pkt (the block number sent in the ACK pkt echoes * the block number of the DATA pkt we just received - see RFC1350) * NOTE!: If the DATA pkt we received did not have the appropriate block * number, then the args->block (our block number) is never updated and * we simply send "duplicate ACK" which has the same block number as the * last ACK pkt we sent. This lets the host know that we are still waiting * on block number args->block+1. */ tftp_send_ack_packet(upcb, addr, port, args->block); /* If the last write returned less than the maximum TFTP data pkt length, * then we've received the whole file and so we can quit (this is how TFTP * signals the end of a transfer!) */ if (pkt_buf->len < TFTP_DATA_PKT_LEN_MAX) { tftp_cleanup_wr(upcb, args); pbuf_free(pkt_buf); } else { pbuf_free(pkt_buf); return; } }
/* for each new request (data in p->payload) from addr:port, * create a new port to serve the response, and start the response * process */ void process_tftp_request(struct pbuf *pkt_buf, struct ip_addr *addr, u16_t port) { tftp_opcode op = tftp_decode_op(pkt_buf->payload); char FileName[30]; struct udp_pcb *upcb; err_t err; u32_t IPaddress; u8_t iptxt[20]; volatile u8_t iptab[4]; IPaddress = addr->addr; printf("\n\rTFTP RRQ (read request) from: %d.%d.%d.%d\n\r", (u8_t)(IPaddress), (u8_t)(IPaddress >> 8),(u8_t)(IPaddress >> 16),(u8_t)(IPaddress >> 24)); /* read its IP address */ iptab[0] = (u8_t)(IPaddress >> 24); iptab[1] = (u8_t)(IPaddress >> 16); iptab[2] = (u8_t)(IPaddress >> 8); iptab[3] = (u8_t)(IPaddress); sprintf((char*)iptxt, "TFTP: %d.%d.%d.%d ", iptab[3], iptab[2], iptab[1], iptab[0]); LCD_DisplayStringLine(Line7, iptxt); /* create new UDP PCB structure */ upcb = udp_new(); if (!upcb) { /* Error creating PCB. Out of Memory */ return; } /* bind to port 0 to receive next available free port */ /* NOTE: This is how TFTP works. There is a UDP PCB for the standard port * 69 which al transactions begin communication on, however, _all_ subsequent * transactions for a given "stream" occur on another port! */ err = udp_bind(upcb, IP_ADDR_ANY, 0); if (err != ERR_OK) { /* Unable to bind to port */ return; } switch (op) { case TFTP_RRQ: /* TFTP RRQ (read request) */ /* Read the name of the file asked by the client to be sent from the SD card */ tftp_extract_filename(FileName, pkt_buf->payload); printf("\n\rTFTP RRQ (read request)"); printf("\n\rONLY EFS filesystem(NTFS in WinXp) is support"); /* If Could not open filesystem */ if (efs_init(&efs1, 0) != 0) { printf("\n\rIf Could not open filesystem"); return; } printf("\n\rCould open filesystem\n\r"); /* If Could not open the selected directory */ if (ls_openDir(&list1, &(efs1.myFs), "/") != 0) { printf("\n\rIf Could not open the selected directory"); return; } /* Start the TFTP read mode*/ printf("\n\rStart the TFTP read mode...."); tftp_process_read(upcb, addr, port, FileName); break; case TFTP_WRQ: /* TFTP WRQ (write request) */ /* Read the name of the file asked by the client to received and writen in the SD card */ tftp_extract_filename(FileName, pkt_buf->payload); /* If Could not open filesystem */ if (efs_init(&efs2, 0) != 0) { return; } /* If Could not open the selected directory */ if (ls_openDir(&list2, &(efs2.myFs), "/") != 0) { return; } /* Start the TFTP write mode*/ tftp_process_write(upcb, addr, port, FileName); break; default: /* sEndTransfera generic access violation message */ tftp_send_error_message(upcb, addr, port, TFTP_ERR_ACCESS_VIOLATION); /* TFTP unknown request op */ /* no need to use tftp_cleanup_wr because no "tftp_connection_args" struct has been malloc'd */ udp_remove(upcb); break; } }
void wrq_recv_callback(void *_args, struct udp_pcb *upcb, struct pbuf *pkt_buf, struct ip_addr *addr, u16_t port) { tftp_connection_args *args = (tftp_connection_args *)_args; int n = 0; if (pkt_buf->len != pkt_buf->tot_len) { return; } /* Does this packet have any valid data to write? */ if ((pkt_buf->len > TFTP_DATA_PKT_HDR_LEN) && (tftp_extract_block(pkt_buf->payload) == (args->block + 1))) { /* write the received data to the file */ n = file_write(&file_CR, pkt_buf->len - TFTP_DATA_PKT_HDR_LEN, (euint8*)pkt_buf->payload + TFTP_DATA_PKT_HDR_LEN); if (n <= 0) { tftp_send_error_message(upcb, addr, port, TFTP_ERR_FILE_NOT_FOUND); /* close the connection */ tftp_cleanup_wr(upcb, args); /* close the connection */ } /* update our block number to match the block number just received */ args->block++; /* update total bytes */ (args->tot_bytes) += (pkt_buf->len - TFTP_DATA_PKT_HDR_LEN); /* This is a valid pkt but it has no data. This would occur if the file being written is an exact multiple of 512 bytes. In this case, the args->block value must still be updated, but we can skip everything else. */ } else if (tftp_extract_block(pkt_buf->payload) == (args->block + 1)) { /* update our block number to match the block number just received */ args->block++; } /* SEndTransferthe appropriate ACK pkt (the block number sent in the ACK pkt echoes * the block number of the DATA pkt we just received - see RFC1350) * NOTE!: If the DATA pkt we received did not have the appropriate block * number, then the args->block (our block number) is never updated and * we simply sEndTransfera "duplicate ACK" which has the same block number as the * last ACK pkt we sent. This lets the host know that we are still waiting * on block number args->block+1. */ tftp_send_ack_packet(upcb, addr, port, args->block); /* If the last write returned less than the maximum TFTP data pkt length, * then we've received the whole file and so we can quit (this is how TFTP * signals the EndTransferof a transfer!) */ if (pkt_buf->len < TFTP_DATA_PKT_LEN_MAX) { tftp_cleanup_wr(upcb, args); pbuf_free(pkt_buf); } else { pbuf_free(pkt_buf); return; } }
/* for each new request (data in p->payload) from addr:port, * create a new port to serve the response, and start the response * process */ void process_tftp_request(struct pbuf *pkt_buf, struct ip_addr *addr, u16_t port) { tftp_opcode op = tftp_decode_op(pkt_buf->payload); char FileName[30]; struct udp_pcb *upcb; err_t err; /* create new UDP PCB structure */ upcb = udp_new(); if (!upcb) { /* Error creating PCB. Out of Memory */ return; } /* bind to port 0 to receive next available free port */ /* NOTE: This is how TFTP works. There is a UDP PCB for the standard port * 69 which al transactions begin communication on, however, _all_ subsequent * transactions for a given "stream" occur on another port! */ err = udp_bind(upcb, IP_ADDR_ANY, 0); if (err != ERR_OK) { /* Unable to bind to port */ return; } switch (op) { case TFTP_RRQ: /* TFTP RRQ (read request) */ /* Read the name of the file asked by the client to be sent from the SD card */ tftp_extract_filename(FileName, pkt_buf->payload); /* If Could not open filesystem */ if (efs_init(&efs1, 0) != 0) { return; } /* If Could not open the selected directory */ if (ls_openDir(&list1, &(efs1.myFs), "/") != 0) { return; } /* Start the TFTP read mode*/ tftp_process_read(upcb, addr, port, FileName); break; case TFTP_WRQ: /* TFTP WRQ (write request) */ /* Read the name of the file asked by the client to received and writen in the SD card */ tftp_extract_filename(FileName, pkt_buf->payload); /* If Could not open filesystem */ if (efs_init(&efs2, 0) != 0) { return; } /* If Could not open the selected directory */ if (ls_openDir(&list2, &(efs2.myFs), "/") != 0) { return; } /* Start the TFTP write mode*/ tftp_process_write(upcb, addr, port, FileName); break; default: /* sEndTransfera generic access violation message */ tftp_send_error_message(upcb, addr, port, TFTP_ERR_ACCESS_VIOLATION); /* TFTP unknown request op */ /* no need to use tftp_cleanup_wr because no "tftp_connection_args" struct has been malloc'd */ udp_remove(upcb); break; } }