uint_32 TFTP_open ( pointer ft_data /* [IN] the address and filename of the bootimage */ ) { /* Body */ TFTP_DATA_STRUCT_PTR tftp; sockaddr_in local_addr; char_ptr str_ptr; uchar_ptr packet; uint_32 sock; uint_32 error; uint_32 fn_len, fm_len; uint_32 pkt_len; tftp = (TFTP_DATA_STRUCT_PTR) ft_data; /* Get a socket */ sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock == RTCS_SOCKET_ERROR) { return RTCSERR_TFTP_SOCKET; } /* Endif */ /* Must be initialized in order for TFTP_close to be able to release socket and memory */ TFTP_config.SOCK = sock; TFTP_config.RRQ_PTR = NULL; /* Bind it */ local_addr.sin_family = AF_INET; local_addr.sin_port = 0; local_addr.sin_addr.s_addr = INADDR_ANY; error = bind(sock, &local_addr, sizeof(local_addr)); if (error != RTCS_OK) { TFTP_close(); return error; } /* Endif */ if ( (tftp->FILENAME == NULL) || (tftp->FILEMODE == NULL) ){ TFTP_close(); return TFTPERR_FILE_NOT_FOUND; } /* Endif */ /* Prepare a read request (RRQ) */ str_ptr = tftp->FILENAME; while (*str_ptr++) {}; fn_len = str_ptr - tftp->FILENAME; str_ptr = tftp->FILEMODE; while (*str_ptr++) {}; fm_len = str_ptr - tftp->FILEMODE; pkt_len = 2 + fn_len + fm_len; packet = RTCS_mem_alloc(pkt_len); if (packet == NULL) { TFTP_close(); return RTCSERR_TFTP_RRQ_ALLOC; } /* Endif */ _mem_set_type(packet, MEM_TYPE_TFTP_PACKET); TFTP_config.RRQ_PTR = packet; htons(packet, TFTPOP_RRQ); _mem_copy(tftp->FILENAME, &packet[ 2], fn_len); _mem_copy(tftp->FILEMODE, &packet[fn_len+2], fm_len); /* Send the RRQ */ TFTP_config.SOCK = sock; TFTP_config.SADDR.sin_family = AF_INET; TFTP_config.SADDR.sin_port = IPPORT_TFTP; TFTP_config.SADDR.sin_addr.s_addr = tftp->SERVER; TFTP_timeout_init(&TFTP_config.TIMEOUT); error = sendto(sock, packet, pkt_len, 0, &TFTP_config.SADDR, sizeof(TFTP_config.SADDR)); if (error != pkt_len) { TFTP_close(); return RTCSERR_TFTP_RRQ_SEND; } /* Endif */ /* Initialize the TFTP client */ TFTP_config.RRQ_PTR = packet; TFTP_config.RRQ_LEN = pkt_len; TFTP_config.LAST = FALSE; htons(TFTP_config.ACK.OP, TFTPOP_ACK); htons(TFTP_config.ACK.BLOCK, 0); return RTCS_OK; } /* Endbody */
void TFTPSRV_service_request ( TFTPSRV_STATE_STRUCT_PTR tftpsrv_ptr /* [IN/OUT] The TFTP Server state */ ) { /* Body */ TFTP_TRANS_STRUCT_PTR trans_ptr; sockaddr_in sockaddr_t; int32_t pkt_len, i; uint32_t error; char *filename, *filemode; uint16_t sockaddrlen, pkt_op; /* receive the datagram */ sockaddrlen = sizeof(sockaddr_t); pkt_len = recvfrom(tftpsrv_ptr->SRV_SOCK, tftpsrv_ptr->BUFFER, TFTP_MAX_MESSAGE_SIZE, 0, (sockaddr *)&sockaddr_t, &sockaddrlen); if (pkt_len == RTCS_ERROR) { return; } /* Endif */ /* limit the number of concurrent transactions */ if (tftpsrv_ptr->NUM_TRANSACTIONS >= TFTPSRV_MAX_TRANSACTIONS) { TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_busy, sockaddr_t); return; } /* Endif */ /* parse the request; extract op, filename and filemode */ i = 2; filename = (char *)tftpsrv_ptr->BUFFER + i; for (; i<pkt_len; i++) { if (tftpsrv_ptr->BUFFER[i] == '\0') break; } /* Endfor */ i++; filemode = (char *)tftpsrv_ptr->BUFFER + i; for (; i<pkt_len; i++) { if (tftpsrv_ptr->BUFFER[i] == '\0') break; } /* Endfor */ if (i >= pkt_len) { TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_op, sockaddr_t); return; } /* Endif */ pkt_op = mqx_ntohs(tftpsrv_ptr->BUFFER); /* allocate state for the new transaction */ trans_ptr = RTCS_mem_alloc_zero(sizeof(TFTP_TRANS_STRUCT)); if (trans_ptr == NULL) { TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_srv, sockaddr_t); return; } /* Endif */ _mem_set_type(trans_ptr, MEM_TYPE_TFTP_TRANS_STRUCT); /* validate the requested operation */ switch (pkt_op) { case TFTPOP_RRQ: trans_ptr->RECV_OP = TFTPOP_ACK; trans_ptr->SEND_OP = TFTPOP_DATA; break; case TFTPOP_WRQ: trans_ptr->RECV_OP = TFTPOP_DATA; trans_ptr->SEND_OP = TFTPOP_ACK; break; default: TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_op, sockaddr_t); _mem_free(trans_ptr); return; } /* Endswitch */ /* open the requested file */ error = TFTPSRV_open_device(pkt_op, filename, filemode, &trans_ptr->TRANS_FILE_PTR); if (error) { switch (error) { case RTCS_EACCES: TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_accvio, sockaddr_t); break; case RTCS_ENOENT: TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_nofile, sockaddr_t); break; case RTCS_EEXIST: TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_exists, sockaddr_t); break; default: TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_srv, sockaddr_t); break; } /* Endswitch */ _mem_free(trans_ptr); return; } /* Endif */ /* create a socket for the new transaction */ trans_ptr->SOCK = socket(PF_INET, SOCK_DGRAM, 0); if (trans_ptr->SOCK == RTCS_SOCKET_ERROR) { TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_srv, sockaddr_t); RTCS_io_close(trans_ptr->TRANS_FILE_PTR); _mem_free(trans_ptr); return; } /* Endif */ trans_ptr->ADDR.sin_family = sockaddr_t.sin_family; trans_ptr->ADDR.sin_port = sockaddr_t.sin_port; trans_ptr->ADDR.sin_addr.s_addr = sockaddr_t.sin_addr.s_addr; sockaddr_t.sin_family = AF_INET; sockaddr_t.sin_port = 0; sockaddr_t.sin_addr.s_addr = INADDR_ANY; error = bind(trans_ptr->SOCK, (const sockaddr *)&sockaddr_t, sizeof(sockaddr_t)); if (error != RTCS_OK) { TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_srv, sockaddr_t); shutdown(trans_ptr->SOCK, 0); RTCS_io_close(trans_ptr->TRANS_FILE_PTR); _mem_free(trans_ptr); return; } /* Endif */ /* build the first packet */ trans_ptr->BLOCK = 0; switch (trans_ptr->SEND_OP) { case TFTPOP_DATA: TFTPSRV_build_DATA(trans_ptr); break; case TFTPOP_ACK: TFTPSRV_build_ACK(trans_ptr); trans_ptr->EXIT = FALSE; break; } /* Endswitch */ if (trans_ptr->SEND_SIZE < sizeof(TFTP_HEADER)) { TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_srv, sockaddr_t); shutdown(trans_ptr->SOCK, 0); RTCS_io_close(trans_ptr->TRANS_FILE_PTR); _mem_free(trans_ptr); return; } /* Endif */ /* send the first packet */ TFTPSRV_timer_start(tftpsrv_ptr, trans_ptr, TFTP_timeout_init(&trans_ptr->XMIT_TIMER)); TFTPSRV_send(trans_ptr); tftpsrv_ptr->SOCKETS[tftpsrv_ptr->NUM_TRANSACTIONS] = trans_ptr->SOCK; tftpsrv_ptr->TRANS_PTRS[tftpsrv_ptr->NUM_TRANSACTIONS] = trans_ptr; tftpsrv_ptr->NUM_TRANSACTIONS++; } /* Endbody */