OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [redboot/] [current/] [src/] [net/] [bootp.c] - Blame information for rev 856

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
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, 2003 Free Software Foundation, Inc.
12
//
13
// eCos is free software; you can redistribute it and/or modify it under    
14
// the terms of the GNU General Public License as published by the Free     
15
// Software Foundation; either version 2 or (at your option) any later      
16
// version.                                                                 
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT      
19
// ANY 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        
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
26
//
27
// As a special exception, if other files instantiate templates or use      
28
// macros or inline functions from this file, or you compile this file      
29
// and link it with other works to produce a work based on this file,       
30
// this file does not by itself cause the resulting work to be covered by   
31
// the GNU General Public License. However the source code for this file    
32
// must still be made available in accordance with section (3) of the GNU   
33
// General Public License v2.                                               
34
//
35
// This exception does not invalidate any other reasons why a work based    
36
// on this file might be covered by the GNU General Public License.         
37
// -------------------------------------------                              
38
// ####ECOSGPLCOPYRIGHTEND####                                              
39
//==========================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):    gthomas
43
//               grant edwards
44
// Contributors: gthomas
45
//               grant edwards
46
// Date:         2011-03-18
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 RETRY_TIME_MS  2000
61
#define MAX_RETRIES    4
62
 
63
static unsigned xid;                   // transaction ID,  should be random/unique
64
static const ip_route_t broadcast = { {255, 255, 255, 255},
65
                                      {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} };
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 dhcpDiscover[] =         { 53, 1, 1 };
71
static const unsigned char dhcpRequest[] =          { 53, 1, 3 };
72
static const unsigned char dhcpRequestIP[] =        { 50, 4 };
73
static const unsigned char dhcpParamRequestList[] = { 55, 3, 1, 3, 6 };
74
static const unsigned char dhcpEnd[] =              { 255 };
75
#endif
76
 
77
// FSM states -- only NONE and DONE are used in BOOTP mode
78
static enum {
79
    DHCP_NONE = 0,
80
    DHCP_WAITING_FOR_OFFER,
81
    DHCP_WAITING_FOR_ACK,
82
    DHCP_DONE,
83
    DHCP_FAILED
84
} dhcpState;
85
 
86
#if !defined(CYGSEM_REDBOOT_NETWORKING_BOOTP_VERBOSE)
87
# define debug_printf(format, ...)     /* noop */
88
#else
89
# define debug_printf(format, ...)  diag_printf(format, ##__VA_ARGS__)
90
static const char *dhcpStateString[] =  { "NONE", "WAITING_FOR_OFFER", "WAITING_FOR_ACK", "DONE", "FAILED" };
91
# ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
92
static const char *dhcpTypeString[] =  { "0x00", "DISCOVER", "OFFER", "REQUEST", "0x04", "ACK", "NAK", "0x07" };
93
# endif
94
#endif
95
 
96
// parse network configuration from a DHCP ACK packet or BOOTP REPLY
97
static void
98
parseConfig(bootp_header_t *bp, int len)
99
{
100
#ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
101
    unsigned char  *end,
102
                   *p;
103
    int             optlen;
104
#endif
105
    memcpy(__local_ip_addr, &bp->bp_yiaddr, sizeof __local_ip_addr);
106
#ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
107
    memcpy(__local_ip_gate, &bp->bp_giaddr, sizeof __local_ip_gate);
108
#endif
109
 
110
#ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
111
 
112
    // are there option fields to parse?
113
    if (memcmp(bp->bp_vend, dhcpCookie, sizeof dhcpCookie))
114
        return;
115
 
116
    p = bp->bp_vend + 4;
117
    end = (unsigned char *)bp + len;
118
    while (p < end) {
119
        unsigned char tag = *p;
120
        if (tag == TAG_END)
121
            break;
122
        if (tag == TAG_PAD)
123
            optlen = 1;
124
        else {
125
            optlen = p[1];
126
            p += 2;
127
            switch (tag) {
128
# ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
129
            case TAG_SUBNET_MASK:
130
                memcpy(__local_ip_mask, p, sizeof __local_ip_mask);
131
                break;
132
            case TAG_GATEWAY:
133
                memcpy(__local_ip_gate, p, sizeof __local_ip_gate);
134
                break;
135
# endif
136
# ifdef CYGPKG_REDBOOT_NETWORKING_DNS
137
            case TAG_DOMAIN_SERVER:
138
                memcpy(&__bootp_dns_addr, p, sizeof __bootp_dns_addr);
139
                __bootp_dns_set = 1;
140
                break;
141
# endif
142
            default:
143
                break;
144
            }
145
        }
146
        p += optlen;
147
    }
148
#endif
149
}
150
 
151
// functions used to prepare BOOTP/DHCP tx packets
152
 
153
// basic BOOTP request
154
static void
155
prep_bootp_request(bootp_header_t *b)
156
{
157
    memset(b, 0, sizeof *b);
158
    b->bp_op = BOOTREQUEST;
159
    b->bp_htype = HTYPE_ETHERNET;
160
    b->bp_hlen = sizeof __local_enet_addr;
161
    b->bp_xid = xid;
162
    memcpy(b->bp_chaddr, __local_enet_addr, sizeof b->bp_chaddr);
163
}
164
 
165
#ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
166
 
167
# define AddOption(p,d) do {memcpy(p,d,sizeof d); p += sizeof d;} while (0)
168
 
169
// add DHCP DISCOVER fields to a basic BOOTP request
170
static int
171
prep_dhcp_discover(bootp_header_t *b)
172
{
173
    unsigned char  *p = b->bp_vend;
174
    AddOption(p, dhcpCookie);
175
    AddOption(p, dhcpDiscover);
176
    AddOption(p, dhcpParamRequestList);
177
    AddOption(p, dhcpEnd);
178
    if (p < &b->bp_vend[BP_MIN_VEND_SIZE])
179
        p = &b->bp_vend[BP_MIN_VEND_SIZE];
180
    return p - (unsigned char *)b;
181
}
182
 
183
// add DHCP REQUEST fields to a basic BOOTP request using data from supplied DHCP OFFER
184
static int
185
prep_dhcp_request(bootp_header_t *b, bootp_header_t *offer)
186
{
187
    unsigned char  *p = b->bp_vend;
188
    AddOption(p, dhcpCookie);
189
    AddOption(p, dhcpRequest);
190
    AddOption(p, dhcpRequestIP);
191
    memcpy(p, &offer->bp_yiaddr, dhcpRequestIP[1]);
192
    p += dhcpRequestIP[1];                            // Ask for the address just given
193
    AddOption(p, dhcpParamRequestList);
194
    AddOption(p, dhcpEnd);
195
    if (p < &b->bp_vend[BP_MIN_VEND_SIZE])
196
        p = &b->bp_vend[BP_MIN_VEND_SIZE];
197
    return p - (unsigned char *)b;
198
}
199
#endif
200
 
201
// Macro used to change state of BOOTP/DHCP state machine
202
#define NewDhcpState(state)  do {dhcpState = state; debug_printf("DHCP state: %s\n",dhcpStateString[state]);}while(0)
203
 
204
// send BOOTP REQUEST or DHCP DISCOVER
205
static void
206
bootp_start(void)
207
{
208
    int             txSize;
209
    bootp_header_t  b;
210
    // send out a BOOTP request or DHCP DISCOVER
211
    prep_bootp_request(&b);            // basic BOOTP request
212
#ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
213
    debug_printf("DHCP  send: DISCOVER\n");
214
    NewDhcpState(DHCP_WAITING_FOR_OFFER);
215
    txSize = prep_dhcp_discover(&b);   // make it into DHCP DISCOVER
216
#else
217
    debug_printf("BOOTP send: REQUEST\n");
218
    txSize = sizeof(b);
219
#endif
220
    __udp_send((char *)&b, txSize, (ip_route_t*)&broadcast, IPPORT_BOOTPS, IPPORT_BOOTPC);
221
}
222
 
223
// save packet for use by other commands
224
static void
225
save_packet(void *b, int len)
226
{
227
    memset(bp_info, 0, sizeof *bp_info);
228
    if ((unsigned)len > sizeof *bp_info)
229
        len = sizeof *bp_info;
230
    memcpy(bp_info, b, len);
231
}
232
 
233
// Handler for received BOOTP/DHCP packets
234
static void
235
bootp_handler(udp_socket_t *skt, char *buf, int len, ip_route_t *src_route,
236
              word src_port)
237
{
238
    bootp_header_t *b;
239
#ifdef CYGSEM_REDBOOT_NETWORKING_DHCP
240
    int             txSize;
241
    int             type;
242
    bootp_header_t  txpkt;
243
    unsigned        expected = 0;
244
#endif
245
 
246
    b = (bootp_header_t *) buf;
247
 
248
    // only accept BOOTP REPLY responses
249
    if (b->bp_op != BOOTREPLY)
250
        return;
251
 
252
    // must be sent to me
253
    if (memcmp(b->bp_chaddr, __local_enet_addr, b->bp_hlen))
254
        return;
255
 
256
    // verify XID
257
    if (b->bp_xid != xid)
258
        return;
259
 
260
#if !defined(CYGSEM_REDBOOT_NETWORKING_DHCP)
261
    // simple BOOTP - this is all there is!
262
    debug_printf("BOOTP recv: REPLY\n");
263
    if (dhcpState != DHCP_DONE) {
264
        save_packet(b, len);
265
        parseConfig(b, len);
266
        NewDhcpState(DHCP_DONE);
267
    }
268
#else
269
    // DHCP support is enabled...
270
 
271
    // Check to see that it's a DHCP packet with a DHCP type field
272
 
273
    type = -1;
274
    if (!memcmp(b->bp_vend, dhcpCookie, sizeof dhcpCookie)) {
275
        unsigned char *p = b->bp_vend + 4;
276
        while (p < (unsigned char *)b + len) {
277
            if (*p == TAG_DHCP_MESS_TYPE) {
278
                type = p[2];
279
                break;
280
            }
281
            p += p[1] + 2;
282
        }
283
    }
284
 
285
    if (type == -1) {
286
        // apparently we have a BOOTP (but not not DHCP) server
287
        debug_printf("DHCP  recv: BOOTP-REPLY -- falling back to BOOTP mode\n");
288
        if (dhcpState != DHCP_DONE) {
289
            save_packet(b, len);
290
            parseConfig(b, len);
291
            NewDhcpState(DHCP_DONE);
292
        }
293
        return;
294
    }
295
 
296
    // it's a real DHCP packet
297
    debug_printf("DHCP  recv: %s [%d]\n", dhcpTypeString[type], type);
298
 
299
    switch (dhcpState) {
300
    case DHCP_WAITING_FOR_OFFER:
301
        if (type == (expected = DHCP_MESS_TYPE_OFFER)) {
302
            prep_bootp_request(&txpkt);
303
            txSize = prep_dhcp_request(&txpkt, b);
304
            debug_printf("DHCP  send: REQUEST\n");
305
            NewDhcpState(DHCP_WAITING_FOR_ACK);
306
            __udp_send((char *)&txpkt, txSize, (ip_route_t *)&broadcast, IPPORT_BOOTPS, IPPORT_BOOTPC);
307
            return;
308
        }
309
        break;
310
 
311
    case DHCP_WAITING_FOR_ACK:
312
        if (type == (expected = DHCP_MESS_TYPE_ACK)) {
313
            save_packet(b, len);
314
            parseConfig(b, len);
315
            NewDhcpState(DHCP_DONE);
316
            return;
317
        }
318
        break;
319
 
320
    default:
321
        debug_printf("DHCP packet ignored\n");
322
        return;
323
    }
324
 
325
    if (type == DHCP_MESS_TYPE_NAK && dhcpState != DHCP_DONE) {
326
        NewDhcpState(DHCP_FAILED);
327
        return;
328
    }
329
 
330
    debug_printf("DHCP packet ignored -- expected %d[%s]\n", expected, dhcpTypeString[expected]);
331
#endif
332
}
333
 
334
 
335
// Request IP configuration via BOOTP/DHCP.
336
// Return zero if successful, -1 if not.
337
 
338
int
339
__bootp_find_local_ip(bootp_header_t *info)
340
{
341
    udp_socket_t    udp_skt;
342
    int             retry;
343
    unsigned long   start;
344
    ip_addr_t       saved_ip_addr;
345
 
346
    bp_info = info;
347
 
348
    diag_printf("\nRequesting IP conf via BOOTP/DHCP...\n");
349
 
350
    memcpy(&xid, __local_enet_addr, sizeof xid);
351
    xid ^= (__local_enet_addr[4]<<16) + __local_enet_addr[5];
352
    xid ^= (unsigned)&retry + (unsigned)&__bootp_find_local_ip;
353
 
354
    debug_printf("XID: %08x\n",xid);
355
 
356
    memcpy(saved_ip_addr, __local_ip_addr, sizeof __local_ip_addr);    // save our IP in case of failure
357
 
358
    NewDhcpState(DHCP_NONE);
359
 
360
    __udp_install_listener(&udp_skt, IPPORT_BOOTPC, bootp_handler);
361
 
362
    retry = MAX_RETRIES;
363
 
364
    while (retry > 0) {
365
        start = MS_TICKS();
366
        memset(__local_ip_addr, 0, sizeof(__local_ip_addr));
367
 
368
        // send bootp REQUEST or dhcp DISCOVER
369
        bootp_start();
370
 
371
        // wait for timeout, user-abort, or for receive packet handler to fail/succeed
372
        while ((MS_TICKS_DELAY() - start) < RETRY_TIME_MS) {
373
            __enet_poll();
374
            if (dhcpState == DHCP_FAILED)
375
                break;
376
            if (dhcpState == DHCP_DONE)
377
                goto done;
378
            if (_rb_break(1))          // did user hit ^C?
379
                goto failed;
380
            MS_TICKS_DELAY();
381
        }
382
        --retry;
383
        ++xid;
384
        diag_printf("TIMEOUT%s\n", retry ? ", retrying..." : "");
385
    }
386
 
387
failed:
388
    diag_printf("FAIL\n");
389
    __udp_remove_listener(IPPORT_BOOTPC);
390
    memcpy(__local_ip_addr, saved_ip_addr, sizeof __local_ip_addr);    // restore prev IP
391
    return -1;
392
 
393
done:
394
    diag_printf("OK\n");
395
    __udp_remove_listener(IPPORT_BOOTPC);
396
    return 0;
397
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.