root/ar5315_microredboot/microredboot/ecos/packages/redboot/current/src/net/bootp.c

Revision 12368, 9.5 kB (checked in by BrainSlayer, 5 months ago)

tftp server added, supports wiligear, ubiquiti and dd-wrt webflash format

Line 
1 //==========================================================================
2 //
3 //      net/bootp.c
4 //
5 //      Stand-alone minimal BOOTP support for RedBoot
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 // Copyright (C) 2002, 2003 Gary Thomas
13 //
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
17 //
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21 // for more details.
22 //
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 //
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
33 //
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
36 //
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //==========================================================================
42 //#####DESCRIPTIONBEGIN####
43 //
44 // Author(s):    gthomas
45 // Contributors: gthomas
46 // Date:         2000-07-14
47 // Purpose:     
48 // Description: 
49 //             
50 // This code is part of RedBoot (tm).
51 //
52 //####DESCRIPTIONEND####
53 //
54 //==========================================================================
55
56 #include <redboot.h>
57 #include <net/net.h>
58 #include <net/bootp.h>
59
60 #define SHOULD_BE_RANDOM  0x12345555
61
62 /* How many milliseconds to wait before retrying the request */
63 #define RETRY_TIME  2000
64 #define MAX_RETRIES    8
65
66 static bootp_header_t *bp_info;
67
68 #ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
69 static const unsigned char dhcpCookie[] = { 99, 130, 83, 99 };
70 static const unsigned char dhcpEnd[] = { 255 };
71 static const unsigned char dhcpDiscover[] = { 53, 1, 1 };
72 static const unsigned char dhcpRequest[] = { 53, 1, 3 };
73 static const unsigned char dhcpRequestIP[] = { 50, 4 };
74 static const unsigned char dhcpParamRequestList[] = { 55, 3, 1, 3, 6 };
75
76 static enum {
77         DHCP_NONE = 0,
78         DHCP_DISCOVER,
79         DHCP_OFFER,
80         DHCP_REQUEST,
81         DHCP_ACK
82 } dhcpState;
83 #endif
84
85 static void
86 bootp_handler(udp_socket_t * skt, char *buf, int len,
87               ip_route_t * src_route, word src_port)
88 {
89         bootp_header_t *b;
90 #ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
91         unsigned char *p, expected = 0;
92 #endif
93
94         b = (bootp_header_t *) buf;
95         if (bp_info) {
96                 memset(bp_info, 0, sizeof *bp_info);
97                 if (len > sizeof *bp_info)
98                         len = sizeof *bp_info;
99                 memcpy(bp_info, b, len);
100         }
101         // Only accept pure REPLY responses
102         if (b->bp_op != BOOTREPLY)
103                 return;
104
105         // Must be sent to me, as well!
106         if (memcmp(b->bp_chaddr, __local_enet_addr, 6))
107                 return;
108
109 #ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
110         p = b->bp_vend;
111         if (memcmp(p, dhcpCookie, sizeof(dhcpCookie)))
112                 return;
113         p += 4;
114
115         // Find the DHCP Message Type tag
116         while (*p != TAG_DHCP_MESS_TYPE) {
117                 p += p[1] + 2;
118                 if (p >= (unsigned char *)b + sizeof(*bp_info))
119                         return;
120         }
121
122         p += 2;
123
124         switch (dhcpState) {
125         case DHCP_DISCOVER:
126                 // The discover message has been sent, only accept an offer reply
127                 if (*p == DHCP_MESS_TYPE_OFFER) {
128                         dhcpState = DHCP_OFFER;
129                         return;
130                 } else {
131                         expected = DHCP_MESS_TYPE_OFFER;
132                 }
133                 break;
134         case DHCP_REQUEST:
135                 // The request message has been sent, only accept an ack reply
136                 if (*p == DHCP_MESS_TYPE_ACK) {
137                         dhcpState = DHCP_ACK;
138                         return;
139                 } else {
140                         expected = DHCP_MESS_TYPE_ACK;
141                 }
142                 break;
143         case DHCP_NONE:
144         case DHCP_OFFER:
145         case DHCP_ACK:
146                 // Quitely ignore these - they indicate repeated message from server
147                 return;
148         }
149         // See if we've been NAK'd - if so, give up and try again
150         if (*p == DHCP_MESS_TYPE_NAK) {
151                 dhcpState = DHCP_NONE;
152                 return;
153         }
154         diag_printf("DHCP reply: %d, not %d\n", (int)*p, (int)expected);
155         return;
156 #else
157         // Simple BOOTP - this is all there is!
158         memcpy(__local_ip_addr, &b->bp_yiaddr, 4);
159 #endif
160 }
161
162 #define AddOption(p,d) do {memcpy(p,d,sizeof d); p += sizeof d;} while (0)
163
164 /*
165  * Find our IP address and copy to __local_ip_addr.
166  * Return zero if successful, -1 if not.
167  */
168 int __bootp_find_local_ip(bootp_header_t * info)
169 {
170         udp_socket_t udp_skt;
171         bootp_header_t b;
172         ip_route_t r;
173         int retry;
174         unsigned long start;
175         ip_addr_t saved_ip_addr;
176 #ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
177         unsigned char *p;
178         int oldState;
179 #endif
180         int txSize;
181         bool abort = false;
182         static int xid = SHOULD_BE_RANDOM;
183
184 #ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
185         dhcpState = DHCP_NONE;
186 #endif
187
188         // Where we want the results saved
189         bp_info = info;
190         // Preserve any IP address we currently have, just in case
191         memcpy(saved_ip_addr, __local_ip_addr, sizeof(__local_ip_addr));
192
193         // fill out route for a broadcast
194         r.ip_addr[0] = 255;
195         r.ip_addr[1] = 255;
196         r.ip_addr[2] = 255;
197         r.ip_addr[3] = 255;
198         r.enet_addr[0] = 255;
199         r.enet_addr[1] = 255;
200         r.enet_addr[2] = 255;
201         r.enet_addr[3] = 255;
202         r.enet_addr[4] = 255;
203         r.enet_addr[5] = 255;
204
205         // setup a socket listener for bootp replies
206         __udp_install_listener(&udp_skt, IPPORT_BOOTPC, bootp_handler);
207
208         retry = MAX_RETRIES;
209         while (!abort && (retry-- > 0)) {
210                 start = MS_TICKS();
211
212                 // Build up the BOOTP/DHCP request
213                 memset(&b, 0, sizeof(b));
214                 b.bp_op = BOOTREQUEST;
215                 b.bp_htype = HTYPE_ETHERNET;
216                 b.bp_hlen = 6;
217                 b.bp_xid = xid++;
218                 memcpy(b.bp_chaddr, __local_enet_addr, 6);
219                 memset(__local_ip_addr, 0, sizeof(__local_ip_addr));
220
221 #ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
222                 p = b.bp_vend;
223                 switch (dhcpState) {
224                 case DHCP_NONE:
225                 case DHCP_DISCOVER:
226                         AddOption(p, dhcpCookie);
227                         AddOption(p, dhcpDiscover);
228                         AddOption(p, dhcpParamRequestList);
229                         AddOption(p, dhcpEnd);
230                         dhcpState = DHCP_DISCOVER;
231                         break;
232                 case DHCP_OFFER:
233                         retry = MAX_RETRIES;
234                 case DHCP_REQUEST:
235                         b.bp_xid = bp_info->bp_xid;     // Match what server sent
236                         AddOption(p, dhcpCookie);
237                         AddOption(p, dhcpRequest);
238                         AddOption(p, dhcpRequestIP);
239                         memcpy(p, &bp_info->bp_yiaddr, 4);
240                         p += 4; // Ask for the address just given
241                         AddOption(p, dhcpParamRequestList);
242                         AddOption(p, dhcpEnd);
243                         dhcpState = DHCP_REQUEST;
244                         memset(&b.bp_yiaddr, 0xFF, 4);
245                         memset(&b.bp_siaddr, 0xFF, 4);
246                         memset(&b.bp_yiaddr, 0x00, 4);
247                         memset(&b.bp_siaddr, 0x00, 4);
248                         break;
249                 case DHCP_ACK:
250                         // Ignore these states (they won't happen)
251                         break;
252                 }
253
254                 // Some servers insist on a minimum amount of "vendor" data
255                 if (p < &b.bp_vend[BP_MIN_VEND_SIZE])
256                         p = &b.bp_vend[BP_MIN_VEND_SIZE];
257                 txSize = p - (unsigned char *)&b;
258                 oldState = dhcpState;
259 #else
260                 txSize = sizeof(b);
261 #endif
262
263                 __udp_send((char *)&b, txSize, &r, IPPORT_BOOTPS,
264                            IPPORT_BOOTPC);
265
266                 do {
267                         __enet_poll();
268 #ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
269                         if (dhcpState != oldState) {
270                                 if (dhcpState == DHCP_ACK) {
271                                         unsigned char *end;
272                                         int optlen;
273                                         // Address information has now arrived!
274                                         memcpy(__local_ip_addr,
275                                                &bp_info->bp_yiaddr, 4);
276 #ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
277                                         memcpy(__local_ip_gate,
278                                                &bp_info->bp_giaddr, 4);
279 #endif
280                                         p = bp_info->bp_vend + 4;
281                                         end =
282                                             (unsigned char *)bp_info +
283                                             sizeof(*bp_info);
284                                         while (p < end) {
285                                                 unsigned char tag = *p;
286                                                 if (tag == TAG_END)
287                                                         break;
288                                                 if (tag == TAG_PAD)
289                                                         optlen = 1;
290                                                 else {
291                                                         optlen = p[1];
292                                                         p += 2;
293                                                         switch (tag) {
294 #ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
295                                                         case TAG_SUBNET_MASK:   // subnet mask
296                                                                 memcpy
297                                                                     (__local_ip_mask,
298                                                                      p, 4);
299                                                                 break;
300                                                         case TAG_GATEWAY:       // router
301                                                                 memcpy
302                                                                     (__local_ip_gate,
303                                                                      p, 4);
304                                                                 break;
305 #endif
306 #ifdef CYGPKG_REDBOOT_NETWORKING_DNS
307                                                         case TAG_DOMAIN_SERVER:
308 //                              diag_printf(" DNS server found!\n");
309                                                                 memcpy
310                                                                     (&__bootp_dns_addr,
311                                                                      p, 4);
312                                                                 __bootp_dns_set
313                                                                     = 1;
314                                                                 break;
315 #endif
316                                                         default:
317                                                                 break;
318                                                         }
319                                                 }
320                                                 p += optlen;
321                                         }
322                                         __udp_remove_listener(IPPORT_BOOTPC);
323                                         return 0;
324                                 } else {
325                                         break;  // State changed, handle it
326                                 }
327                         }
328 #else
329                         // All done, if address response has arrived
330                         if (__local_ip_addr[0] || __local_ip_addr[1] ||
331                             __local_ip_addr[2] || __local_ip_addr[3]) {
332                                 /* success */
333                                 __udp_remove_listener(IPPORT_BOOTPC);
334                                 return 0;
335                         }
336 #endif
337                         if (_rb_break(1)) {
338                                 // The user typed ^C on the console
339                                 abort = true;
340                                 break;
341                         }
342                         MS_TICKS_DELAY();       // Count for ^C test
343                 } while ((MS_TICKS_DELAY() - start) < RETRY_TIME);
344
345                 // Warn the user that we're polling for BOOTP info
346                 if (retry == (MAX_RETRIES - 1)) {
347                         diag_printf("... waiting for BOOTP information\n");
348                 }
349         }
350
351         // timed out
352         __udp_remove_listener(IPPORT_BOOTPC);
353         // Restore any previous IP address
354         memcpy(__local_ip_addr, saved_ip_addr, sizeof(__local_ip_addr));
355         return -1;
356 }
Note: See TracBrowser for help on using the browser.