Initial c661x version
[keystone-rtos/ibl.git] / src / driver / eth / tftp.c
1 /**
2  *   @file  tftp.c
3  *
4  *   @brief   
5  *      The file implements the NET Module TFTP functionality.
6  *
7  *  \par
8  *  NOTE:
9  *      (C) Copyright 2008, Texas Instruments, Inc.
10  * 
11  *  Redistribution and use in source and binary forms, with or without 
12  *  modification, are permitted provided that the following conditions 
13  *  are met:
14  *
15  *    Redistributions of source code must retain the above copyright 
16  *    notice, this list of conditions and the following disclaimer.
17  *
18  *    Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the 
20  *    documentation and/or other materials provided with the   
21  *    distribution.
22  *
23  *    Neither the name of Texas Instruments Incorporated nor the names of
24  *    its contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
28  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
29  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
31  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
32  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
33  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
36  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
37  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38  *
39  *  \par
40 */
41 #include "types.h"
42 #include "iblloc.h"
43 #include "net.h"
44 #include "netif.h"
45 #include "timer.h"
46 #include "stream.h"
47 #include <string.h>
48 #include "net_osal.h"
51 /**********************************************************************
52  *************************** LOCAL Structures *************************
53  **********************************************************************/
55 /**
56  * @brief 
57  *  The structure describes the TFTP State
58  *
59  * @details
60  *  The TFTP client can be in one of the following states which are
61  *  described in this structure.
62  */
63 typedef enum TFTP_STATE
64 {
65     /**
66      * @brief   This is the initial state of the TFTP client during startup
67      * In this state the TFTP client has sent out the READ Request and has
68      * not yet received a data packet in acknowledgment.
69      */        
70     READ_REQUEST    = 0x1,
72     /**
73      * @brief   This is the data receive state of the TFTP client in which
74      * the TFTP client is receiving data packets from the TFTP server.
75      */    
76     DATA_RECEIVE
77 }TFTP_STATE;
79 /**
80  * @brief 
81  *  The structure describes the TFTP Master Control Block.
82  *
83  * @details
84  *  The TFTP Master control block stores information used by the
85  *  TFTP module.
86  */
87 typedef struct TFTP_MCB
88 {
89     /**
90      * @brief   This describes the state of the TFTP client.
91      */
92     TFTP_STATE   state;
94     /**
95      * @brief   This is the IP Address of the server from where the file
96      * is downloaded.
97      */
98     IPN         server_ip;
100     /**
101      * @brief   This is the TFTP socket which is used to communicate
102      * with the UDP module.
103      */
104     Int32        sock;
106     /**
107      * @brief   This is the TFTP Timer handle which is used to handle
108      * retransmissions of the READ REQUEST.
109      */
110     Int32       timer;
112     /**
113      * @brief   This is the name of the file which is being downloaded.
114      * File Names are typically exchanged through the BOOTP protocol 
115      * where the max file name length is 64. 
116      */    
117     Uint8       filename[64];
119     /**
120      * @brief   This is the block number we expect.
121      */
122     Uint16      block_num;
124     /**
125      * @brief   This is a generic buffer used by the TFTP module,
126      */
127     Uint8       buffer[TFTP_DATA_SIZE + TFTPHEADER_SIZE];
129     /**
130      * @brief   Number of retransmission done.
131      */
132     Uint32      num_retransmits;
133 }TFTP_MCB;
135 /**********************************************************************
136  *************************** GLOBAL Variables *************************
137  **********************************************************************/
139 /**
140  * @brief   This is the global master control block for the TFTP
141  * module and keeps track of all the information regarding TFTP. 
142  */
143 TFTP_MCB   tftpmcb;
145 /**********************************************************************
146  **************************** TFTP Functions **************************
147  **********************************************************************/
149 /**
150  *  @b Description
151  *  @n  
152  *      The function cleans up the TFTP Client. This can be called 
153  *      on an ERROR or SUCCESSFUL exit.
154  *
155  *  @retval
156  *      Not Applicable.
157  */
158 static void tftp_cleanup (void)
160     /* Close any open timers. */
161     timer_delete (tftpmcb.timer);
162     tftpmcb.timer = -1;
164     /* Close the UDP Sockets. */
165     udp_sock_close (tftpmcb.sock);
167     /* Close the STREAM module */
168     stream_close ();
169     return;        
172 /**
173  *  @b Description
174  *  @n  
175  *      The function creates the TFTP read request and populates it 
176  *      in the internal TFTP buffer.
177  *
178  *  @retval
179  *      Size of the TFTP Read Request.
180  */
181 static Int32 tftp_create_read_req (Uint8* filename)
183     Uint16* ptr_op;
184     Int32   index = 0;
186     /* Create the Read Request: Populate the Request op type */
187     ptr_op = (Uint16 *)&tftpmcb.buffer[0];
188     *ptr_op = htons(TFTP_OPCODE_RRQ);
190     /* Copy the file name */
191     index = 0;
192     while (filename[index] != 0)
193     {
194         tftpmcb.buffer[index + 2] = filename[index];
195         index++;
196     }
198     /* Null Terminate the file name. */
199     tftpmcb.buffer[index + 2] = 0;
200     index = index + 3;
202     /* Copy the transfer mode. */
203     tftpmcb.buffer[index++] = (Uint8)'o';
204     tftpmcb.buffer[index++] = (Uint8)'c';
205     tftpmcb.buffer[index++] = (Uint8)'t';
206     tftpmcb.buffer[index++] = (Uint8)'e';
207     tftpmcb.buffer[index++] = (Uint8)'t';
208     tftpmcb.buffer[index++] = (Uint8)0;
210     /* Return the size of the read request */
211     return index;
214 /**
215  *  @b Description
216  *  @n  
217  *      The function is used to send an ACK back to TFTP Server.
218  *
219  *  @retval
220  *      Not Applicable
221  */
222 static void tftp_send_ack(void) 
224     TFTPHDR* ptr_tftphdr;
226     /* Initialize the data buffer. */ 
227     netMemset ((void *)&tftpmcb.buffer[0], 0, TFTP_DATA_SIZE + TFTPHEADER_SIZE);
229     /* Create an ACK packet which is to be sent out. Get the pointer to the
230      * TFTP Header. */
231     ptr_tftphdr = (TFTPHDR *)&tftpmcb.buffer[0];
232     ptr_tftphdr->opcode = htons (TFTP_OPCODE_ACK);
233     ptr_tftphdr->block  = htons (tftpmcb.block_num);
235     /* The packet has been populated; send it to the server; this transfer is now done
236      * over the data socket. */
237     udp_sock_send (tftpmcb.sock, (Uint8 *)ptr_tftphdr, TFTPHEADER_SIZE);
239     /* Increment the block number. */
240     tftpmcb.block_num++;
241     return;
244 /**
245  *  @b Description
246  *  @n  
247  *      The function is the timer expiration for TFTP.
248  *
249  *  @retval
250  *      Not Applicable
251  */
252 static void tftp_timer_expiry (void)
254     Int32 len;
256     /* Determine the state of the TFTP. */
257     if (tftpmcb.state == READ_REQUEST)
258     {
259         /* We were sending out READ Request and have not received a response 
260          * Increment the number of retransmissions which have been done. */
261         tftpmcb.num_retransmits++;
263         /* Check if we have exceeded the max allowed? */
264         if (tftpmcb.num_retransmits > MAX_TFTP_RETRANSMITS)
265         {
266             /* FATAL Error: We need to close the TFTP Client and signal Error to the NET Boot Module. */
267             mprintf ("Error: TFTP READ REQ Retransmissions have exceeded\n");
268             tftp_cleanup ();
269             net_set_error();
270             return;
271         }
273         /* Create the TFTP Read Request */
274         len = tftp_create_read_req (&tftpmcb.filename[0]);
276         /* Send out the READ Request again. */
277         udp_sock_send (tftpmcb.sock, (Uint8 *)&tftpmcb.buffer[0], len);
278     }
279     else
280     {
281         /* We were receiving data from the TFTP Server and there was a timeout. This can 
282          * happen only if we have not received any data from the TFTP server. */
283         mprintf ("Error: TFTP server is down; no packet received.\n");
284         tftp_cleanup();
285         net_set_error();
286         return;
287     }
288     return;
291 /**
292  *  @b Description
293  *  @n  
294  *      This is a call back function registered with the UDP module to 
295  *      be invoked when a TFTP packet is received.
296  *
297  *  @param[in]  sock
298  *      This is the socket handle on which packet was received.
299  *  @param[in]  ptr_data
300  *      This is the pointer to the TFTP data payload.
301  *  @param[in]  num_bytes
302  *      This is the number of bytes of TFTP data received.
303  *
304  *  @retval
305  *      Success -   0
306  *  @retval
307  *      Error   -   <0
308  */
309 static Int32 tftp_receive (Int32 sock, Uint8* ptr_data, Int32 num_bytes)
311     TFTPHDR*    ptr_tftphdr;
312     UDPHDR*     ptr_udphdr;
313     Uint16      src_port;
314     SOCKET      socket;
316     /* Get the pointer to the TFTP Header. */
317     ptr_tftphdr = (TFTPHDR *)ptr_data;
319     /* Process the received packet depending on the type of packet received */
320     switch (ntohs(ptr_tftphdr->opcode))
321     {
322         case TFTP_OPCODE_DATA:
323         {
324             /* Is this the first data packet we have received? */
325             if (tftpmcb.state == READ_REQUEST)
326             {
327                 /* YES. In this case the socket on which the request was sent has completed
328                  * its job. Lets shut it down and open another one for the data transfers. */
329                 udp_sock_close (sock);
331                 /* We need to get the source port from where the data was received. 
332                  *  This information is present in the UDP layer. This is required to
333                  *  open the data socket. */
334                 ptr_udphdr = (UDPHDR *)(ptr_data - sizeof(UDPHDR));
335                 src_port   = ntohs(ptr_udphdr->SrcPort);
337                 /* Populate the socket structure and register this with the UDP module. */
338                 socket.local_port       = 1234;
339                 socket.remote_port      = src_port;
340                 socket.remote_address   = tftpmcb.server_ip;
341                 socket.app_fn           = tftp_receive;
343                 /* Move to the DATA State. */
344                 tftpmcb.state           = DATA_RECEIVE;
345                 tftpmcb.num_retransmits = 0;
347                 /* Close the timer.  */
348                 timer_delete (tftpmcb.timer);
349                 tftpmcb.timer = -1;
351                 /* Open the TFTP data socket. */
352                 tftpmcb.sock = udp_sock_open (&socket);
353                 if (tftpmcb.sock < 0)
354                 {
355                     /* Error: Data Socket open failed. */
356                     mprintf ("Error: TFTP Data Socket Open Failed\n");
357                     tftp_cleanup();
358                     net_set_error();
359                     return -1;
360                 }
361             }
363             /* We are in the DATA State: Start the TFTP Server Keep Alive Timer. This timer
364              * keeps track of the TFTP Server and ensures it does not die behind us. This will
365              * help detect that error. */
366             timer_delete (tftpmcb.timer);
367             tftpmcb.timer = timer_add (TFTP_SERVER_TIMEOUT, tftp_timer_expiry);
368             if (tftpmcb.timer < 0)
369             {
370                 /* Timer creation failed. */
371                 mprintf ("Error: TFTP Timer creation failed\n");
372                 tftp_cleanup();
373                 net_set_error();
374                 return -1;
375             }
377             /* Received a data block. Ensure that the block number matches what we expect! */
378             if (ntohs(ptr_tftphdr->block) != tftpmcb.block_num)
379             {
380                 /* There is a block number mismatch. This could occur if the ACK we sent was lost. 
381                  * Increment the number of retransmissions. */
382                 tftpmcb.num_retransmits++;
383                 if (tftpmcb.num_retransmits > MAX_TFTP_RETRANSMITS)
384                 {
385                     /* OK; we resent the ACK multiple times & the server still kept sending the
386                      * same packet back. We just give up now. */
387                     mprintf ("Error: TFTP ACK Retransmits Exceeded\n");
388                     tftp_cleanup();
389                     net_set_error();
390                     return -1;
391                 }
393                 /* We need to send out the ACK for the previous 'block' */
394                 tftpmcb.block_num = tftpmcb.block_num - 1;
396                 /* Send the ACK out again. */
397                 tftp_send_ack ();
399                 /* We dont need to process this packet since we had already picked it up. */
400                 return 0;
401             }
403             /* The packet looks good. Reset the number of retransmissions. */
404             tftpmcb.num_retransmits = 0;
406             /* Pass the received data packet to the STREAM Module. 
407              *  We need to skip the TFTP Header. */
408             if (stream_write ((ptr_data + TFTPHEADER_SIZE), (num_bytes - TFTPHEADER_SIZE)) == 0)
409             {
410                 /* Packet has been copied successfully into the STREAM Buffer. */
411                 tftp_send_ack();
412             }
413             else
414             {
415                 /* Packet could not be copied; let the server retransmit the packet
416                  * because we did not send the ACK. */
417             }
419             /* Determine if the TFTP file transfer is complete or not? 
420              *  If the received number of bytes is less than the TFTP Data Size this 
421              *  indicates that the transfer is successfully completed. */
422             if (num_bytes < (TFTP_DATA_SIZE + TFTPHEADER_SIZE))
423             {
424                 /* Successfully downloaded the file */
425                 tftp_cleanup();
426             }
427             break;
428         }
429         default:
430         {
431             /* Control comes here for ERROR, ACK and WRQ which are all indicate 
432              * failure. ERROR packet is the only expected failure which is mentioned
433              * in the RFC. All other packets are violation of the RFC. Both these
434              * cases are handled similarly. */
435             mprintf ("Error: TFTP Error Packet Received\n");
436             tftp_cleanup();
437             net_set_error();
439             /* Return Error. */
440             return -1;
441         }
442     }
443     return 0;
446 /**
447  *  @b Description
448  *  @n  
449  *       The function gets a file from the TFTP Server. The function
450  *       simply initiates the transfer. Successful completion of this
451  *       API does not gurantee that the file was downloaded.
452  *
453  *  @param[in]  server_ip
454  *      TFTP Server IP address from where the file is downloaded.
455  *  @param[in]  filename
456  *      Name of the file to be downloaded.
457  *
458  *  @retval
459  *      Success -   0
460  *  @retval
461  *      Error   -   <0
462  */
463 Int32 tftp_get_file (IPN server_ip, Int8* filename)
465     SOCKET  socket;
466     Int32   index = 0;
468     /* Basic Validations: Ensure the parameters passed are correct. */
469     if ((server_ip == 0) || (filename == NULL))
470     {
471         /* Error: Invalid parameters passed. Stop the network boot module. */
472         net_set_error();
473         return -1;
474     }
476     /* Open the stream module. */
477     if (stream_open (TFTP_DATA_SIZE) < 0)
478     {
479         /* Error: Unable to open the stream device. */
480         net_set_error();
481         return -1;
482     }
484     /* Initialize the TFTP MCB at this stage... */
485     netMemset ((void *)&tftpmcb, 0, sizeof(TFTP_MCB));
487     /* Populate the socket structure and register this with the UDP module. */
488     socket.local_port       = 1234;
489     socket.remote_port      = TFTP_SERVER_PORT;
490     socket.remote_address   = server_ip;
491     socket.app_fn           = tftp_receive;
493     /* Open the TFTP Control socket. */
494     tftpmcb.sock = udp_sock_open (&socket);
495     if (tftpmcb.sock < 0)
496     {
497         /* ERROR: UDP Socket could not be opened. */        
498         stream_close();
499         net_set_error();
500         return -1;
501     }
503     /* Remember the parameters passed to the TFTP. */
504     tftpmcb.server_ip = server_ip;
506     /* Copy the file name over...  */
507     while (filename[index] != 0)
508     {
509         tftpmcb.filename[index] = filename[index];
510         index++;
511     }
513     /* Initialize the block number expected. */
514     tftpmcb.block_num = 1;
516     /* Create the TFTP Read Request. */
517     index = tftp_create_read_req ((Uint8 *)filename);
519     /* Initialize the TFTP Client state */
520     tftpmcb.state = READ_REQUEST;
522     /* Initialize the TFTP Timer. */
523     tftpmcb.timer = timer_add (TFTP_TIMEOUT, tftp_timer_expiry);
524     if (tftpmcb.timer < 0)
525     {
526         /* Error: TFTP Timer Creation Failed. TFTP is not operational. */
527         mprintf ("Error: TFTP Timer Creation Failed\n");
528         tftp_cleanup ();
529         net_set_error();
530         return -1;
531     }
533     /* The packet has been populated; send it to the server. */
534     udp_sock_send (tftpmcb.sock, (Uint8 *)&tftpmcb.buffer[0], index);
535  
536     /* Send out the TFTP Read request. */
537     return 0;