📄 tftp.c
字号:
} case TFTP_EV_PACKET_ERROR: { print_tftp_error(data); state->state = TFTP_ST_FINISHED; break; } default: { // Illegal event in this state ev_err(state->state, event); break; } } break; }////////////////////////////////////////////////////////////////////////////////// Receive blocks state//////////////////////////////////////////////////////////////////////////////// case TFTP_ST_RECEIVE: { switch (event) { case TFTP_EV_PACKET_DATA: { int const block = ntohs(*(u16 *)(data->ev_packet_x.data + TFTP_BLOCK_OFFSET)); // Make sure this is the packet we are expecting if (NEXT_BLOCK(state->block) == block) { //and add it to the total received received_block(state, data); /* * Here we check to see what the "actual" data size is. * If we don't in fact have 512 bytes we transition to * the finished state. */ if (data->ev_packet_x.length < TFTP_DATA_SIZE + TFTP_HEADER_SIZE) { state->state = TFTP_ST_FINISHED; } } //if it's a repeat, re-acknowledge it else if (state->block == block) { BLOCK_ERROR("+"); // tftp server resent packet (probably didn't get // previous ack) so we ack it again if (retry(state)) { tftpack(state->block, state->conn); // Stay in receive state } else { // Too many retries BLOCK_ERROR("!"); state->state = TFTP_ST_FINISHED; } break; } else { // out of sync packet (this should never happen) BLOCK_ERROR("X"); if (retry(state)) { // Don't send ACK here // Stay in receive state } else { // Too many retries BLOCK_ERROR("!"); state->state = TFTP_ST_FINISHED; } break; } break; } case TFTP_EV_TIMEOUT: { BLOCK_ERROR("."); if (retry(state)) { // Didn't receive our last block ACK or TFTP_ACK_WRQ tftpack(state->block, state->conn); // stay in receive state } else { // Too many retries BLOCK_ERROR("!"); state->state = TFTP_ST_FINISHED; } break; } case TFTP_EV_PACKET_ERROR: { print_tftp_error(data); state->state = TFTP_ST_FINISHED; break; } case TFTP_EV_PACKET_WRQ: { // Hopefully, we are in server mode if (state->block == 0) { // Must have missed our last ACK BLOCK_ERROR("W"); tftpack(TFTP_ACK_WRQ, state->conn); } else { itc_printf("ERROR: Unexpected WRQ\r\n"); state->state = TFTP_ST_FINISHED; } break; } default: { // Illegal event in this state ev_err(state->state, event); break; } } break; }////////////////////////////////////////////////////////////////////////////////// Server request state//////////////////////////////////////////////////////////////////////////////// case TFTP_ST_SERVER: { switch (event) { case TFTP_EV_PACKET_WRQ: { state->start_time = get_time_timer(); BLOCK_INDICATOR("W"); tftpack(TFTP_ACK_WRQ, state->conn); state->state = TFTP_ST_RECEIVE; break; } case TFTP_EV_PACKET_ERROR: { print_tftp_error(data); state->state = TFTP_ST_FINISHED; break; } case TFTP_EV_TIMEOUT: { BLOCK_ERROR("."); break; } default: { // Illegal event in this state ev_err(state->state, event); break; } } break; }////////////////////////////////////////////////////////////////////////////////// Finished state//////////////////////////////////////////////////////////////////////////////// case TFTP_ST_FINISHED: { // Nothing to do! itc_printf("%s: We're finished!\r\n", __FUNCTION__); break; }////////////////////////////////////////////////////////////////////////////////// Unknown state//////////////////////////////////////////////////////////////////////////////// default: { // Unknown state ev_err(state->state, event); break; } } return state->state == TFTP_ST_FINISHED;}////////////////////////////////////////////////////////////////////////////////// tftp_type_to_event// PURPOSE: Convert a TFTP packet type into the appropriate state machine event// PARAMS: (IN) u16 - TFTP packet type// RETURNS tftp_events - event code////////////////////////////////////////////////////////////////////////////////static inline tftp_eventstftp_type_to_event(u16 tftp_type){ switch (tftp_type) { case TFTP_OP_RRQ: return TFTP_EV_PACKET_RRQ; case TFTP_OP_WRQ: return TFTP_EV_PACKET_WRQ; case TFTP_OP_DATA: return TFTP_EV_PACKET_DATA; case TFTP_OP_ACK: return TFTP_EV_PACKET_ACK; case TFTP_OP_ERROR: return TFTP_EV_PACKET_ERROR; default: return TFTP_EV_PACKET_UNKNOWN; }}////////////////////////////////////////////////////////////////////////////////// tftp_sm_loop// PURPOSE: Send packet and timeout events into state machine// PARAMS: (IN/OUT) state - state data// (IN) event - initial event to send to the state machine// (with NULL data pointer)// RETURNS: file length or -1 for error////////////////////////////////////////////////////////////////////////////////static inttftp_sm_loop(tftp_state_data *state, tftp_events event){ u8 buf[MAX_PACKET_SIZE]; //we want the packet to be u16 aligned after the headers (42 bytes) u8 * const packet = (u8 *)(buf + sizeof(u16) - (((u32)buf + UDPIP_HEADER_SIZE) % sizeof(u16))); u8 * const udp_data = packet + UDPIP_HEADER_SIZE; int tftp_timeout; int done = 0; u32 elapsed; tftp_ev_data data; /* * Flush the Ethernet chip of data; any data that is there now is invalid */ flush_ethernet(); // Send the initial event to the state machine done = tftp_sm(state, event, NULL); // Loop until the state machine reaches the finished state tftp_timeout = get_time_timer () + TFTP_TIMEOUT_PERIOD; while (!done) { int size; if ((size = udp_recvfrom(&state->conn, packet, TFTP_DATA_SIZE + TFTP_HEADER_SIZE + UDPIP_HEADER_SIZE, &state->conn)) < 0) { // Problem receiving block; may be timeout if (tftp_timeout < get_time_timer()) { done = tftp_sm(state, TFTP_EV_TIMEOUT, NULL); // Reset the timeout tftp_timeout = get_time_timer() + TFTP_TIMEOUT_PERIOD; } } else { data.ev_packet_x.data = udp_data; data.ev_packet_x.length = (u16) size; done = tftp_sm(state, tftp_type_to_event( ntohs(*(u16 *)(udp_data + TFTP_TYPE_OFFSET))), &data); // Reset the timeout tftp_timeout = get_time_timer() + TFTP_TIMEOUT_PERIOD; } } /* * We are done, so we should clean up after ourselves. */ rx_ethernet_off(); flush_ethernet(); show_received(state, 1); elapsed = MAX(1, get_time_timer() - state->start_time); itc_printf("\r\nDownloaded %i bytes at %i kB/s\r\n", state->file_length, (state->file_length / 1024) / elapsed); // Calling retry here actually changes the retry count, which means that // in the pathological case of the transfer succeeding after exactly // TFTP_RETRIES-1 tries, we will erroneously return failure. return retry(state) ? state->file_length : -1;}////////////////////////////////////////////////////////////////////////////////// tftplisten// PURPOSE: Listens for a TFTP connection to receive an MS bin file// PARAMS: (IN) u8 *dest - memory location to put downloaded bin file in// RETURNS: Size of upload in bytes.////////////////////////////////////////////////////////////////////////////////inttftplisten(u8 *dest){ tftp_state_data state; itc_printf("Awaiting file send: "); // Initialize state variable memset8((u8 *)&state, 0, sizeof(state)); //state.state = TFTP_ST_INIT; state.dest = dest; // Start the state machine return tftp_sm_loop(&state, TFTP_EV_BEGIN_TX);}////////////////////////////////////////////////////////////////////////////////// tftpget// PURPOSE: downloads a file via tftp. Server to download determined externally.// PARAMS: (IN) char * file - file to request.// (IN) u8 * dest - buffer to store file.// RETURNS int - size of download in bytes.////////////////////////////////////////////////////////////////////////////////inttftpget(char const *file, u8 *dest){ tftp_state_data state; itc_printf("Downloading %s: ", file); // Initialize state variables memset8((u8 *)&state, 0, sizeof(state)); //state.state = TFTP_ST_INIT; state.dest = dest; state.file_name = file; // Start the state machine return tftp_sm_loop(&state, TFTP_EV_BEGIN_RX);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -