/*************************************************************************************** File: tftps.c Date: 7.10.2002 Version: 0.1 Author: Jari Lahti (jari@violasystems.com) Description: This file implements TFTP protocol server Version Info: 7.10.2002 - First version (Jari Lahti) ***************************************************************************************/ #include "opentcp.h" UINT8 tftpsapp_init = 0; /* TFTPS states */ #define TFTPS_STATE_ENABLED 1 #define TFTPS_STATE_CONNECTED 2 /* TFTP Error codes */ #define TFTP_NOTDEFINED 0 /* Not Definet Error */ #define TFTP_ACCESSVIOLATION 2 /* Access Violation Error */ #define TFTP_ILLEGALOPERATION 4 /* Not supported Opcode */ /* TFTP Opcodes */ #define TFTP_OPCODE_WRQ 2 /* Packet is Write Request */ #define TFTP_OPCODE_DATA 3 /* Data Packet */ #define TFTP_OPCODE_ACK 4 /* ACK Packet */ #define TFTP_OPCODE_ERROR 5 /* Error Packet */ struct { UINT8 state; INT8 sochandle; UINT16 tmrhandle; UINT32 remip; UINT16 remport; UINT16 blocknumber; UINT32 bytecount; UINT8 retries; } Tftps; /******************************************************************************** Function: init_tftps Parameters: void Return val: INT8 - (>=0) OK (-1) Error Date: 7.19.2002 Desc: This function should be called before the TFTP Server application is used to set the operating parameters of it *********************************************************************************/ INT8 init_tftps (void) { /* Already initialized? */ if(tftpsapp_init) return(1); /* Get socket handle */ Tftps.sochandle = udp_getsocket(0, tftps_eventlistener, UDP_OPT_SEND_CS | UDP_OPT_CHECK_CS); if(Tftps.sochandle < 0) return(-1); /* Put it to listening mode */ if( udp_open(Tftps.sochandle, TFTPS_SERVERPORT) < 0 ) return(-1); /* Get timer handle */ Tftps.tmrhandle = get_timer(); Tftps.state = TFTPS_STATE_ENABLED; Tftps.remip = 0; Tftps.remport = 0; Tftps.retries = 0; Tftps.blocknumber = 0; Tftps.bytecount = 0; tftpsapp_init = 1; return(1); } /******************************************************************************** Function: tftps_run Parameters: void Return val: void Date: 7.10.2002 Desc: The main thread of TFTP server that should be called periodically *********************************************************************************/ void tftps_run (void) { if(tftpsapp_init == 0) return; /* Check for timeouts */ if(Tftps.state == TFTPS_STATE_CONNECTED) { if(check_timer(Tftps.tmrhandle) == 0) TFTP_DeleteSocket(); } } INT32 tftps_eventlistener (INT8 cbhandle, UINT8 event, UINT32 remip, UINT16 remport, UINT16 bufindex, UINT16 dlen) { UINT16 opcode; UINT16 i; UINT8 ch; UINT16 u16temp; UINT8 fname[TFTPS_FILENAME_MAXLEN]; if(tftpsapp_init == 0) return(-1); if(cbhandle != Tftps.sochandle) return(-1); /* If we are on other state than enabled, check that we are talking with the same gyu */ if( Tftps.state != TFTPS_STATE_ENABLED) { if(remip != Tftps.remip) return(-1); if(remport != Tftps.remport) return(-1); } if(dlen < 2) return(-1); /* Bind socket */ Tftps.remip = remip; Tftps.remport = remport; /* Get information */ NETWORK_RECEIVE_INITIALIZE(bufindex); opcode = RECEIVE_NETWORK_B(); opcode <<= 8; opcode |= RECEIVE_NETWORK_B(); dlen -= 2; /* Process it */ switch(opcode) { case TFTP_OPCODE_WRQ: /* Write request? */ /* Get filename */ fname[0] = '\0'; for(i=0; i= TFTPS_FILENAME_MAXLEN) { TFTP_SendError(TFTP_NOTDEFINED); TFTP_DeleteSocket(); return(1); } ch = RECEIVE_NETWORK_B(); fname[i] = ch; if(ch == '\0') { i++; break; } } dlen -= i; /* Check here the filename */ if( otcp_bufsearch(&fname[0], TFTPS_FILENAME_MAXLEN, (UINT8*)"ws100.upn",0) < 0 ) { TFTP_SendError(TFTP_ACCESSVIOLATION); TFTP_DeleteSocket(); return(1); } /* Check mode, only octet mode is supported */ if(dlen < 6) { TFTP_SendError(TFTP_NOTDEFINED); TFTP_DeleteSocket(); return(1); } if( (RECEIVE_NETWORK_B() != 'o') || (RECEIVE_NETWORK_B() != 'c') || (RECEIVE_NETWORK_B() != 't') || (RECEIVE_NETWORK_B() != 'e') || (RECEIVE_NETWORK_B() != 't') || (RECEIVE_NETWORK_B() != '\0') ) { TFTP_SendError(TFTP_NOTDEFINED); TFTP_DeleteSocket(); return(1); } /* All OK, send ACK */ Tftps.state = TFTPS_STATE_CONNECTED; Tftps.blocknumber = 0; Tftps.bytecount = 0; Tftps.retries = TFTPS_DEF_RETRIES; init_timer(Tftps.tmrhandle, TFTPS_TIMEOUT*TIMERTIC); TFTP_SendAck(); Tftps.blocknumber++; return(1); case TFTP_OPCODE_DATA: /* Data Packet ? */ if(Tftps.state != TFTPS_STATE_CONNECTED) { TFTP_SendError(TFTP_NOTDEFINED); TFTP_DeleteSocket(); return(1); } if(dlen < 2) { TFTP_SendError(TFTP_NOTDEFINED); TFTP_DeleteSocket(); return(1); } /* Get block number */ u16temp = RECEIVE_NETWORK_B(); u16temp <<= 8; u16temp |= RECEIVE_NETWORK_B(); dlen -= 2; if( (u16temp < Tftps.blocknumber) && (Tftps.blocknumber > 0) ) { /* Duplicate msg, send ACK again */ if( Tftps.retries > 0 ) { Tftps.retries--; Tftps.blocknumber--; TFTP_SendAck(); Tftps.blocknumber++; } else { TFTP_SendError(TFTP_NOTDEFINED); TFTP_DeleteSocket(); } return(1); } if( u16temp != Tftps.blocknumber ) { /* Something really wrong */ TFTP_SendError(TFTP_NOTDEFINED); TFTP_DeleteSocket(); return(1); } /* Read the data here with RECEIVE_NETWORK_B() */ if( dlen < 512 ) { /* Other side Wants to close */ TFTP_SendAck(); TFTP_DeleteSocket(); return(1); } /* All OK */ Tftps.retries = TFTPS_DEF_RETRIES; init_timer(Tftps.tmrhandle, TFTPS_TIMEOUT*TIMERTIC); TFTP_SendAck(); Tftps.blocknumber++; return(1); case TFTP_OPCODE_ERROR: TFTP_DeleteSocket(); return(1); default: /* Unsupported Opcode, Send error */ TFTP_SendError(TFTP_ILLEGALOPERATION); TFTP_DeleteSocket(); return(1); } } void TFTP_SendAck (void) { /* Send a TFTP ACK packet */ OTCP_TXBUF[UDP_APP_OFFSET + 0] = 0; /* Opcode */ OTCP_TXBUF[UDP_APP_OFFSET + 1] = 4; OTCP_TXBUF[UDP_APP_OFFSET + 2] = (UINT8)(Tftps.blocknumber >> 8); OTCP_TXBUF[UDP_APP_OFFSET + 3] = (UINT8)Tftps.blocknumber; udp_send(Tftps.sochandle, Tftps.remip, Tftps.remport, &OTCP_TXBUF[UDP_APP_OFFSET], NETWORK_TX_BUFFER_SIZE - UDP_APP_OFFSET, 4); } void TFTP_SendError (UINT8 errno ) { /* Send TFTP Error -packet */ OTCP_TXBUF[UDP_APP_OFFSET + 0] = 0; /* Opcode */ OTCP_TXBUF[UDP_APP_OFFSET + 1] = 5; OTCP_TXBUF[UDP_APP_OFFSET + 2] = (UINT8)(Tftps.blocknumber >> 8); OTCP_TXBUF[UDP_APP_OFFSET + 3] = (UINT8)Tftps.blocknumber; OTCP_TXBUF[UDP_APP_OFFSET + 4] = errno; OTCP_TXBUF[UDP_APP_OFFSET + 5] = '\0'; OTCP_TXBUF[UDP_APP_OFFSET + 6] = 0; udp_send(Tftps.sochandle, Tftps.remip, Tftps.remport, &OTCP_TXBUF[UDP_APP_OFFSET], NETWORK_TX_BUFFER_SIZE - UDP_APP_OFFSET, 7); } void TFTP_DeleteSocket (void) { /* Clear Socket Data */ Tftps.blocknumber = 0; Tftps.state = TFTPS_STATE_ENABLED; Tftps.retries = 0; Tftps.remip = 0; Tftps.remport = 0; } /* EOF */