]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - keystone-rtos/ibl.git/blob - src/driver/eth/bootp.c
6a360f08608bfc337e7ebd7b848a1fb2ec0f1435
[keystone-rtos/ibl.git] / src / driver / eth / bootp.c
1 /**
2  *   @file  bootp.c
3  *
4  *   @brief   
5  *      The file implements the NET Module BOOTP functionality.
6  *
7  *  \par
8  *  NOTE:
9  *      (C) Copyright 2008, Texas Instruments, Inc.
10  *
11  *  \par
12  */
13 #include "types.h"
14 #include "iblloc.h"
15 #include "net.h"
16 #include "netif.h"
17 #include "timer.h"
18 #include "stream.h"
19 #include <string.h>
22 /**********************************************************************
23  *************************** LOCAL Structures *************************
24  **********************************************************************/
26 /**
27  * @brief 
28  *  The structure describes the BOOTP Master Control Block.
29  *
30  * @details
31  *  The BOOTP Master control block stores information used by the
32  *  BOOTP module.
33  */
34 typedef struct BOOTP_MCB
35 {
36     /**
37      * @brief   This is the BOOTP header which is populated and sent across
38      * to the server.
39      */
40     BOOTPHDR    boothdr;
42     /**
43      * @brief   This is the BOOTP handle to the UDP socket.
44      */
45     Int32       sock;
47     /**
48      * @brief   This is the number of BOOTP requests sent out.
49      */
50     Int32       num_request;
52     /**
53      * @brief   This is the BOOTP timer handle.
54      */
55     Int32       bootp_timer;
57     /**
58      * @brief   The optional application call back when the 
59      *          bootp file name and IP address has been received. 
60      */
61     void (*asyncComplete)(void *);
63 }BOOTP_MCB;
65 /**********************************************************************
66  *************************** GLOBAL Variables *************************
67  **********************************************************************/
69 /**
70  * @brief   This is the global master control block for the BOOTP module
71  * and stores all the necessary information.
72  */
73 BOOTP_MCB   bootpmcb;
75 /**********************************************************************
76  **************************** BOOTP Functions *************************
77  **********************************************************************/
79 /** 
80  *  @b Description
81  *  @n  
82  *      This is a call back function registered with the TIMER module
83  *      to be called if there is a timeout and no BOOTP reply is 
84  *      received.
85  *
86  *  @retval
87  *      Not Applicable.
88  */
89 static void bootp_tmr_expiry (void)
90 {
91     BOOTPHDR*   ptr_bootphdr;
93     /* Get the pointer to the BOOTP Header. */
94     ptr_bootphdr = &bootpmcb.boothdr;
96     /* Populate the BOOTP header with all the information we have. */
97     ptr_bootphdr->op        = BOOTP_OP_REQUEST;
98     ptr_bootphdr->htype     = BOOTP_HTYPE_ETHERNET;
99     ptr_bootphdr->hlen      = 6;
100     ptr_bootphdr->xid       = htonl(0x1);
101     memcpy ((void *)&ptr_bootphdr->chaddr, (void *)&netmcb.net_device.mac_address[0], 6);
103     /* The packet has been populated; send it to the server. */
104     udp_sock_send (bootpmcb.sock, (Uint8 *)ptr_bootphdr, sizeof(BOOTPHDR));
106     /* Increment the number of requests sent out. */
107     bootpmcb.num_request++;
109     /* We need to delete the current timer and create another with the backoff strategy. */
110     timer_delete (bootpmcb.bootp_timer);
112     /* Check if we have exceeded the max. permissible? */
113     if (bootpmcb.num_request > BOOTP_MAX_RETRIES)
114     {
115         /* Error: Maximum retransmissions have been exceeded; indicate error. */
116         mprintf ("BOOTP Failure: Max Retransmissions exceeded\n");
117         net_set_error ();
118         udp_sock_close(bootpmcb.sock);
119         return;
120     }
122     /* Create the new backoff timer. */
123     bootpmcb.bootp_timer = timer_add (BOOTP_SEED_TIMEOUT*bootpmcb.num_request, bootp_tmr_expiry);
124     if (bootpmcb.bootp_timer < 0)
125     {
126         /* Error: Unable to create the new backoff timer; indicate error. */
127         mprintf ("BOOTP Failure: Backoff timer failed\n");
128         net_set_error ();
129         stream_close();
130         udp_sock_close(bootpmcb.sock);
131         return;
132     }
133     return;
136 /** 
137  *  @b Description
138  *  @n  
139  *      This is a call back function registered with the UDP module to 
140  *      be invoked when a BOOTP packet is received.
141  *
142  *  @param[in]  sock
143  *      This is the socket handle on which packet was received.
144  *  @param[in]  ptr_data
145  *      This is the pointer to the BOOTP data payload.
146  *  @param[in]  num_bytes
147  *      This is the number of bytes of BOOTP data received.
148  *
149  *  @retval
150  *      Success -   0
151  *  @retval
152  *      Error   -   <0
153  */
154 static Int32 bootp_receive (Int32 sock, Uint8* ptr_data, Int32 num_bytes)
156     BOOTPHDR*   ptr_bootphdr;
157     Int32       index = 0;
158     IPN         subnetmask = BOOTP_DEFAULT_MASK;
159     IPN         defaultRouter = 0;
160     IPN         serverIP      = 0;
162     /* Received a BOOTP packet from the UDP stack. */
163     ptr_bootphdr = (BOOTPHDR *)ptr_data;
165     /* Check if this is a BOOTP reply packet? */
166     if (ptr_bootphdr->op != BOOTP_OP_REPLY)
167         return -1;
169     /* Ensure the transaction id matches the one we sent out. */
170     if (ptr_bootphdr->xid != bootpmcb.boothdr.xid)
171         return -1;
173     /* Ensure the MAC Address matches our MAC Address */
174     if ((ptr_bootphdr->chaddr[0] != netmcb.net_device.mac_address[0]) || 
175         (ptr_bootphdr->chaddr[1] != netmcb.net_device.mac_address[1]) ||
176         (ptr_bootphdr->chaddr[2] != netmcb.net_device.mac_address[2]) ||
177         (ptr_bootphdr->chaddr[3] != netmcb.net_device.mac_address[3]) ||
178         (ptr_bootphdr->chaddr[4] != netmcb.net_device.mac_address[4]) ||
179         (ptr_bootphdr->chaddr[5] != netmcb.net_device.mac_address[5]))
180     {
181         /* The MAC Address do not match. Ignore the reply packet */
182         return -1;
183     }
185     /* Cycle through the options; we are only interested in retreiving the SUBNET Mask option
186      * Since we need to configure the routing table. */
187     while (index < 64)
188     {
189         /* Get the option tag and process it appropriately. */
190         switch (ptr_bootphdr->options[index])
191         {
192             case 0x0:
193             {
194                 /* Padding option. Skip this. */
195                 index++;
196                 break;
197             }
198             case 0x1:
199             {
200                 /* SUBNET option. Got it! We dont need to parse anymore. */
201                 subnetmask = ((ptr_bootphdr->options[index+2] << 24) | 
202                               (ptr_bootphdr->options[index+3] << 16) |
203                               (ptr_bootphdr->options[index+4] << 8)  | 
204                               (ptr_bootphdr->options[index+5]));
206                 /* Jump to the next option. */
207                 index = index + ptr_bootphdr->options[index + 1] + 2;
208                 break;
209             }
210             case 0x3:
211             {
212                 /* ROUTER option. Got it! We dont need to parse anymore. */
213                 defaultRouter = ((ptr_bootphdr->options[index+2] << 24) | 
214                                  (ptr_bootphdr->options[index+3] << 16) |
215                                  (ptr_bootphdr->options[index+4] << 8)  | 
216                                  (ptr_bootphdr->options[index+5]));
218                 /* Jump to the next option. */
219                 index = index + ptr_bootphdr->options[index + 1] + 2;
220                 break;
221             }
222             case 150:
223             {
224                 /* TFTP Server IP Address: */
225                 serverIP = ((ptr_bootphdr->options[index+2] << 24) | 
226                             (ptr_bootphdr->options[index+3] << 16) |
227                             (ptr_bootphdr->options[index+4] << 8)  | 
228                             (ptr_bootphdr->options[index+5]));
230                 /* Convert to host order; so that it is in SYNC with "siaddr" field below. */
231                 serverIP = ntohl(serverIP);
233                 /* Jump to the next option. */
234                 index = index + ptr_bootphdr->options[index + 1] + 2;
235                 break;
236             }
237             case 0xFF:
238             {
239                 /* End option. Terminate the loop. */
240                 index = 64;
241                 break;
242             }
243             default:
244             {
245                 /* Any other option is not handled; but we need to skip it */
246                 index = index + ptr_bootphdr->options[index + 1] + 2;
247                 break;
248             }
249         }
250     }
252     /* The BOOTP Reply looks good. Kill the BOOTP timer. */
253     timer_delete (bootpmcb.bootp_timer);
255     /* Check if we have received the TFTP Server IP address or not? If not we assume
256      * that the TFTP Server and BOOTP Server address are one and the same. */
257     if (serverIP == 0x0)
258         serverIP = ptr_bootphdr->siaddr;
260     /* We have all the information with us from the BOOTP Reply Packet. 
261      *  a) IP Address
262      *  b) Subnet Mask
263      *  c) TFTP File Name.
264      *  d) TFTP Server IP
265      * Lets configure the IPv4 Routing Table with the appropriate information and
266      * also configure the global netdevice structure. */
267     netmcb.net_device.ip_address = ptr_bootphdr->yiaddr;
269     if (netmcb.net_device.use_bootp_server_ip == TRUE)
270         netmcb.net_device.server_ip  = serverIP;
272     netmcb.net_device.net_mask   = htonl(subnetmask);
273     ip_add_route (FLG_RT_NETWORK, netmcb.net_device.ip_address, netmcb.net_device.net_mask, 0);
275     if (netmcb.net_device.use_bootp_file_name == TRUE)
276         memcpy (netmcb.net_device.file_name, ptr_bootphdr->file, sizeof(netmcb.net_device.file_name));
278     /* Check if we had received a default router? */
279     if (defaultRouter != 0)
280         ip_add_route (FLG_RT_DEFAULT, 0x0, 0x0, htonl(defaultRouter));
282     /* DEBUG Message: */
283     mprintf ("*****************************\n");
284     mprintf ("BOOTP Complete\n");
285     mprintf ("    IP Address    : 0x%x\n", ntohl(netmcb.net_device.ip_address));
286     mprintf ("    Net Mask      : 0x%x\n", subnetmask);
287     mprintf ("    Default Router: 0x%x\n", defaultRouter);
288     mprintf ("    Server IP     : 0x%x\n", ntohl(serverIP));
289     mprintf ("    File Name     : %s\n",   ptr_bootphdr->file);
290     mprintf ("*****************************\n");
292     /* Close the BOOTP sockets. */
293     stream_close();
294     udp_sock_close (sock);
296     /* Optional call back with bootp params */
297     if (bootpmcb.asyncComplete != NULL)  
298         (*bootpmcb.asyncComplete)((void *)&netmcb.net_device);
300     /* Initiate the TFTP Transfer. */
301     tftp_get_file (netmcb.net_device.server_ip, (char *)netmcb.net_device.file_name);
303     /* BOOTP Reply has been processed. */ 
304     return 0;
307 /** 
308  *  @b Description
309  *  @n  
310  *       The function is used to initialize the BOOTP client.
311  *
312  *  @retval
313  *      Not Applicable.
314  */
315 void bootp_init (void (*asyncComplete)(void *))
317     BOOTPHDR*   ptr_bootphdr;
318     SOCKET      socket;
320     /* Initialize the BOOT MCB */ 
321     memset ((void *)&bootpmcb, 0, sizeof(BOOTP_MCB));
323     bootpmcb.asyncComplete = asyncComplete;
326     /* Populate the socket structure and register this with the UDP module. */
327     socket.local_port       = BOOTP_CLIENT_PORT;
328     socket.remote_port      = BOOTP_SERVER_PORT;
329     socket.remote_address   = 0xFFFFFFFF;
330     socket.app_fn           = bootp_receive;
332     /* Open the BOOTP socket. */
333     bootpmcb.sock = udp_sock_open (&socket);
334     if (bootpmcb.sock < 0)
335     {
336         /* Error: Socket could not be opened. */
337         mprintf ("ERROR: BOOTP SOCK Open Failed\n");
338         net_set_error ();
339         return;
340     }
342     /* Open the stream to receive packets */
343     stream_open(TFTP_DATA_SIZE);
345     /* Get the pointer to the BOOTP Header. */
346     ptr_bootphdr = &bootpmcb.boothdr;
348     /* Populate the BOOTP header with all the information we have. */
349     ptr_bootphdr->op        = BOOTP_OP_REQUEST;
350     ptr_bootphdr->htype     = BOOTP_HTYPE_ETHERNET;
351     ptr_bootphdr->hlen      = 6;
352     ptr_bootphdr->xid       = htonl(0x1);
353     memcpy ((void *)&ptr_bootphdr->chaddr, (void *)&netmcb.net_device.mac_address[0], 6);
355     /* The packet has been populated; send it to the server. */
356     udp_sock_send (bootpmcb.sock, (Uint8 *)ptr_bootphdr, sizeof(BOOTPHDR));
358     /* Increment the number of requests sent out. */
359     bootpmcb.num_request++;
361     /* Create the BOOTP Timer; if timer creation fails then BOOTP Retransmissions 
362      * will not work and so we treat this as a fatal error. */
363     bootpmcb.bootp_timer = timer_add (BOOTP_SEED_TIMEOUT, bootp_tmr_expiry);
364     if (bootpmcb.bootp_timer < 0)
365     {
366         /* Error: Timer could not be created; we need to close the socket and signal error. */
367         mprintf ("ERROR: BOOTP ADD Timer Failed\n");
368         stream_close();
369         udp_sock_close (bootpmcb.sock);
370         net_set_error ();
371         return;
372     }
373     return;