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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [net/] [common/] [v2_0/] [src/] [dhcp_prot.c] - Blame information for rev 174

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
/*==========================================================================
2
//
3
//      dhcp_prot.c
4
//
5
//      DHCP protocol implementation for DHCP client
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
//
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 version.
16
//
17
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20
// for more details.
21
//
22
// You should have received a copy of the GNU General Public License along
23
// with eCos; if not, write to the Free Software Foundation, Inc.,
24
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25
//
26
// As a special exception, if other files instantiate templates or use macros
27
// or inline functions from this file, or you compile this file and link it
28
// with other works to produce a work based on this file, this file does not
29
// by itself cause the resulting work to be covered by the GNU General Public
30
// License. However the source code for this file must still be made available
31
// in accordance with section (3) of the GNU General Public License.
32
//
33
// This exception does not invalidate any other reasons why a work based on
34
// this file might be covered by the GNU General Public License.
35
//
36
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37
// at http://sources.redhat.com/ecos/ecos-license/
38
// -------------------------------------------
39
//####ECOSGPLCOPYRIGHTEND####
40
//==========================================================================
41
//#####DESCRIPTIONBEGIN####
42
//
43
// Author(s):   hmt
44
// Contributors: gthomas
45
// Date:        2000-07-01
46
// Purpose:     DHCP support
47
// Description:
48
//
49
//####DESCRIPTIONEND####
50
//
51
//========================================================================*/
52
 
53
#include <pkgconf/system.h>
54
#include <pkgconf/net.h>
55
 
56
#ifdef CYGPKG_NET_DHCP
57
 
58
#if 0
59
#define perror( txt ) // nothing
60
#endif
61
 
62
#include <network.h>
63
#include <dhcp.h>
64
#include <errno.h>
65
 
66
#include <cyg/infra/cyg_ass.h>
67
 
68
#ifdef INET6
69
#include <net/if_var.h>
70
#include <netinet6/in6_var.h>
71
#endif
72
 
73
// ------------------------------------------------------------------------
74
// Returns a pointer to the end of dhcp message (or NULL if invalid)
75
// meaning the address of the byte *after* the TAG_END token in the vendor
76
// data.
77
 
78
static unsigned char *
79
scan_dhcp_size( struct bootp *ppkt )
80
{
81
    unsigned char *op;
82
 
83
    op = &ppkt->bp_vend[0];
84
    // First check for the cookie!
85
    if ( op[0] !=  99 ||
86
         op[1] != 130 ||
87
         op[2] !=  83 ||
88
         op[3] !=  99 ) {
89
        CYG_FAIL( "Bad DHCP cookie" );
90
        return NULL;
91
    }
92
    op += 4;
93
    while (*op != TAG_END) {
94
        op += *(op+1)+2;
95
        if ( op > &ppkt->bp_vend[BP_VEND_LEN-1] ) {
96
            CYG_FAIL( "Oversize DHCP packet in dhcp_size" );
97
            return NULL;
98
        }
99
    }
100
    // Check op has not gone wild
101
    CYG_ASSERT( op > (unsigned char *)(&ppkt[0]), "op pointer underflow!" );
102
    // Compare op with non-existent "next" struct bootp in the array.
103
    CYG_ASSERT( op < (unsigned char *)(&ppkt[1]), "op pointer overflow!" );
104
    return op + 1; // Address of first invalid byte
105
}
106
 
107
// ------------------------------------------------------------------------
108
// Get the actual packet size of an initialized buffer
109
 
110
static int
111
dhcp_size( struct bootp *ppkt )
112
{
113
    unsigned char *op;
114
 
115
    op = scan_dhcp_size( ppkt );
116
    if ( !op ) return 0;
117
    return (op - (unsigned char *)ppkt);
118
}
119
 
120
 
121
// ------------------------------------------------------------------------
122
// Get the actual packet size of an initialized buffer
123
// This will also pad the packet with 0 if length is less
124
// than BP_STD_TX_MINPKTSZ.
125
 
126
static int
127
dhcp_size_for_send( struct bootp *ppkt )
128
{
129
    unsigned char *op;
130
 
131
    op = scan_dhcp_size( ppkt );
132
    if ( !op ) return 0; // Better not scribble!
133
    // Zero extra bytes until the packet is large enough.
134
    for ( ; op < (((unsigned char *)ppkt) + BP_STD_TX_MINPKTSZ); op++ )
135
        *op = 0;
136
    return (op - (unsigned char *)ppkt);
137
}
138
 
139
// ------------------------------------------------------------------------
140
// Insert/set an option value in an initialized buffer
141
 
142
static int
143
set_fixed_tag( struct bootp *ppkt,
144
               unsigned char tag,
145
               cyg_uint32 value,
146
               int len)
147
{
148
    unsigned char *op;
149
 
150
    // Initially this will only scan the options field.
151
 
152
    op = &ppkt->bp_vend[4];
153
    while (*op != TAG_END) {
154
        if ( op > &ppkt->bp_vend[BP_VEND_LEN-1] ) {
155
            CYG_FAIL( "Oversize DHCP packet in set_fixed_tag" );
156
            return false;
157
        }
158
        if (*op == tag)                 // Found it...
159
            break;
160
        op += *(op+1)+2;
161
    }
162
 
163
    if (*op == tag) { // Found it...
164
        if ( *(op+1) != len ) {
165
            CYG_FAIL( "Wrong size in set_fixed_tag" );
166
            return false;           // wrong size
167
        }
168
    }
169
    else { // overwrite the end tag and install a new one
170
        if ( op + len + 2 > &ppkt->bp_vend[BP_VEND_LEN-1] ) {
171
            CYG_FAIL( "Oversize DHCP packet in set_fixed_tag append" );
172
            return false;
173
        }
174
        *op = tag;
175
        *(op+1) = len;
176
        *(op + len + 2) = TAG_END;
177
    }
178
    // and insert the value.  Net order is BE.
179
    op += len + 2 - 1;              // point to end of value
180
    while ( len-- > 0 ) {
181
        *op-- = (unsigned char)(value & 255);
182
        value >>= 8;
183
    }
184
    return true;
185
}
186
 
187
// Note that this does not permit changing the size of an extant tag.
188
static int
189
set_variable_tag( struct bootp *ppkt,
190
               unsigned char tag,
191
               cyg_uint8 *pvalue,
192
               int len)
193
{
194
    unsigned char *op;
195
 
196
    // Initially this will only scan the options field.
197
    op = &ppkt->bp_vend[4];
198
    while (*op != TAG_END) {
199
        if ( op > &ppkt->bp_vend[BP_VEND_LEN-1] ) {
200
            CYG_FAIL( "Oversize DHCP packet in set_variable_tag" );
201
            return false;
202
        }
203
        if (*op == tag)                 // Found it...
204
            break;
205
        op += *(op+1)+2;
206
    }
207
 
208
    if (*op == tag) { // Found it...
209
        if ( *(op+1) != len ) {
210
            CYG_FAIL( "Wrong size in set_variable_tag" );
211
            return false;           // wrong size
212
        }
213
    }
214
    else { // overwrite the end tag and install a new one
215
        if ( op + len + 2 > &ppkt->bp_vend[BP_VEND_LEN-1] ) {
216
            CYG_FAIL( "Oversize DHCP packet in set_variable_tag append" );
217
            return false;
218
        }
219
        *op = tag;
220
        *(op+1) = len;
221
        *(op + len + 2) = TAG_END;
222
    }
223
    // and insert the value.  No order is implied.
224
    op += 2;               // point to start of value
225
    while ( len-- > 0 ) {
226
        *op++ = *pvalue++;
227
    }
228
    return true;
229
}
230
 
231
static int
232
unset_tag( struct bootp *ppkt,
233
           unsigned char tag )
234
{
235
    unsigned char *op, *nextp = 0, *killp = 0;
236
 
237
    // Initially this will only scan the options field.
238
 
239
    op = &ppkt->bp_vend[4];
240
    while (*op != TAG_END) {
241
        if ( op > &ppkt->bp_vend[BP_VEND_LEN-1] ) {
242
            CYG_FAIL( "Oversize DHCP packet in unset_tag" );
243
            return false;
244
        }
245
        if (*op == tag) {               // Found it...
246
            killp = op;                 // item to kill
247
            nextp = op + *(op+1)+2;     // next item address
248
        }
249
        op += *(op+1)+2;                // scan to the end
250
    }
251
 
252
    if ( !killp )
253
        return false;
254
 
255
    // Obliterate the found op by copying down: *op is the end.
256
    while( nextp <= op )                // <= to copy the TAG_END too.
257
        *killp++ = *nextp++;
258
 
259
    return true;
260
}
261
 
262
// ------------------------------------------------------------------------
263
// Bring up an interface enough to broadcast, before we know who we are
264
 
265
static int
266
bring_half_up(const char *intf, struct ifreq *ifrp )
267
{
268
    int s;
269
    int one = 1;
270
 
271
    struct sockaddr_in *addrp;
272
    struct ecos_rtentry route;
273
 
274
    // Ensure clean slate
275
    cyg_route_reinit();  // Force any existing routes to be forgotten
276
 
277
    s = socket(AF_INET, SOCK_DGRAM, 0);
278
    if (s < 0) {
279
        perror("socket");
280
        return false;
281
    }
282
 
283
    if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one))) {
284
        perror("setsockopt");
285
        return false;
286
    }
287
 
288
    addrp = (struct sockaddr_in *) &ifrp->ifr_addr;
289
    memset(addrp, 0, sizeof(*addrp));
290
    addrp->sin_family = AF_INET;
291
    addrp->sin_len = sizeof(*addrp);
292
    addrp->sin_port = 0;
293
    addrp->sin_addr.s_addr = INADDR_ANY;
294
 
295
    strcpy(ifrp->ifr_name, intf);
296
    if (ioctl(s, SIOCSIFADDR, ifrp)) { /* set ifnet address */
297
        perror("SIOCSIFADDR");
298
        return false;
299
    }
300
 
301
    if (ioctl(s, SIOCSIFNETMASK, ifrp)) { /* set net addr mask */
302
        perror("SIOCSIFNETMASK");
303
        return false;
304
    }
305
 
306
    /* the broadcast address is 255.255.255.255 */
307
    memset(&addrp->sin_addr, 255, sizeof(addrp->sin_addr));
308
    if (ioctl(s, SIOCSIFBRDADDR, ifrp)) { /* set broadcast addr */
309
        perror("SIOCSIFBRDADDR");
310
        return false;
311
    }
312
 
313
    ifrp->ifr_flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING;
314
    if (ioctl(s, SIOCSIFFLAGS, ifrp)) { /* set ifnet flags */
315
        perror("SIOCSIFFLAGS up");
316
        return false;
317
    }
318
 
319
    if (ioctl(s, SIOCGIFHWADDR, ifrp) < 0) { /* get MAC address */
320
        perror("SIOCGIFHWADDR 1");
321
        return false;
322
    }
323
 
324
    // Set up routing
325
    addrp->sin_family = AF_INET;
326
    addrp->sin_port = 0;
327
    addrp->sin_len = sizeof(*addrp);  // Size of address
328
 
329
    /* the broadcast address is 255.255.255.255 */
330
    memset(&addrp->sin_addr, 255, sizeof(addrp->sin_addr));
331
    memset(&route, 0, sizeof(route));
332
    memcpy(&route.rt_gateway, addrp, sizeof(*addrp));
333
 
334
    addrp->sin_addr.s_addr = INADDR_ANY;
335
    memcpy(&route.rt_dst, addrp, sizeof(*addrp));
336
    memcpy(&route.rt_genmask, addrp, sizeof(*addrp));
337
 
338
    route.rt_dev = ifrp->ifr_name;
339
    route.rt_flags = RTF_UP|RTF_GATEWAY;
340
    route.rt_metric = 0;
341
 
342
    if (ioctl(s, SIOCADDRT, &route)) { /* add route */
343
        if (errno != EEXIST) {
344
            perror("SIOCADDRT 3");
345
            return false;
346
        }
347
    }
348
 
349
    close(s);
350
 
351
    return true;
352
}
353
 
354
 
355
// ------------------------------------------------------------------------
356
// DHCP retransmission timeouts and number of tries
357
// 
358
// To work better with simulated failures (or real ones!) so that the rest
359
// of the system is tested, rather than DHCP renewal failures pulling
360
// everything down, we try a little more zealously than the RFC suggests.
361
 
362
static unsigned char timeout_random = 0;
363
 
364
struct timeout_state {
365
    unsigned int secs;
366
    int countdown;
367
};
368
 
369
static inline void reset_timeout( struct timeval *ptv, struct timeout_state *pstate )
370
{
371
    timeout_random++;
372
    pstate->countdown = 4; // initial fast retries
373
    pstate->secs = 3 + (timeout_random & 3);
374
    ptv->tv_sec = 0;
375
    ptv->tv_usec = 65536 * (2 + (timeout_random & 3)); // 0.1 - 0.3S, about
376
}
377
 
378
static inline int next_timeout( struct timeval *ptv, struct timeout_state *pstate )
379
{
380
    if ( 0 < pstate->countdown-- )
381
        return true;
382
    if ( 0 == ptv->tv_sec )
383
        ptv->tv_sec = pstate->secs;
384
    else {
385
        timeout_random++;
386
        pstate->secs = ptv->tv_sec * 2 - 2 + (timeout_random & 3);
387
        pstate->countdown = 2; // later fast retries
388
        ptv->tv_sec = 0;
389
    }
390
    return pstate->secs < 100; // If longer, too many tries...
391
}
392
 
393
// ------------------------------------------------------------------------
394
// Lease expiry and alarms to notify it
395
 
396
static cyg_alarm_t alarm_function;
397
 
398
static void alarm_function(cyg_handle_t alarm, cyg_addrword_t data)
399
{
400
    struct dhcp_lease *lease = (struct dhcp_lease *)data;
401
    lease->which |= lease->next;
402
    if ( lease->needs_attention )
403
        cyg_semaphore_post( lease->needs_attention );
404
 
405
    // Step the lease on into its next state of being alarmed ;-)
406
    if ( lease->next & DHCP_LEASE_EX ) {
407
        cyg_alarm_disable( alarm );
408
    }
409
    else if ( lease->next & DHCP_LEASE_T2 ) {
410
        lease->next = DHCP_LEASE_EX;
411
        cyg_alarm_initialize( lease->alarm, lease->expiry, 0 );
412
        cyg_alarm_enable( lease->alarm );
413
    }
414
    else if ( lease->next & DHCP_LEASE_T1 ) {
415
        lease->next = DHCP_LEASE_T2;
416
        cyg_alarm_initialize( lease->alarm, lease->t2, 0 );
417
        cyg_alarm_enable( lease->alarm );
418
    }
419
}
420
 
421
static inline void no_lease( struct dhcp_lease *lease )
422
{
423
    if ( lease->alarm ) {
424
        // Already set: delete this.
425
        cyg_alarm_disable( lease->alarm );
426
        cyg_alarm_delete( lease->alarm );
427
        lease->alarm = 0;
428
    }
429
}
430
 
431
static inline void new_lease( struct bootp *bootp, struct dhcp_lease *lease )
432
{
433
    cyg_tick_count_t now = cyg_current_time();
434
    cyg_tick_count_t then;
435
    cyg_uint32 tag = 0;
436
    cyg_uint32 expiry_then;
437
    cyg_resolution_t resolution =
438
        cyg_clock_get_resolution(cyg_real_time_clock());
439
    cyg_handle_t h;
440
    unsigned int length;
441
 
442
    // Silence any jabbering from past lease on this interface
443
    no_lease( lease );
444
    lease->which = lease->next = 0;
445
    cyg_clock_to_counter(cyg_real_time_clock(), &h);
446
    cyg_alarm_create( h, alarm_function, (cyg_addrword_t)lease,
447
                      &lease->alarm, &lease->alarm_obj );
448
 
449
    // extract the lease time and scale it &c to now.
450
    length = sizeof(tag);
451
    if(!get_bootp_option( bootp, TAG_DHCP_LEASE_TIME, &tag ,&length))
452
        tag = 0xffffffff;
453
 
454
    if ( 0xffffffff == tag ) {
455
        lease->expiry = 0xffffffffffffffff;
456
        lease->t2     = 0xffffffffffffffff;
457
        lease->t1     = 0xffffffffffffffff;
458
        return; // it's an infinite lease, hurrah!
459
    }
460
 
461
    then = (cyg_uint64)(ntohl(tag));
462
    expiry_then = then;
463
 
464
    then *= 1000000000; // into nS - we know there is room in a tick_count_t
465
    then = (then / resolution.dividend) * resolution.divisor; // into system ticks
466
    lease->expiry = now + then;
467
    length = sizeof(tag);
468
    if (get_bootp_option( bootp, TAG_DHCP_REBIND_TIME, &tag, &length ))
469
        then = (cyg_uint64)(ntohl(tag));
470
    else
471
        then = expiry_then - expiry_then/4;
472
    then *= 1000000000; // into nS - we know there is room in a tick_count_t
473
    then = (then / resolution.dividend) * resolution.divisor; // into system ticks
474
    lease->t2 = now + then;
475
 
476
    length = sizeof(tag);
477
    if (get_bootp_option( bootp, TAG_DHCP_RENEWAL_TIME, &tag, &length ))
478
        then = (cyg_uint64)(ntohl(tag));
479
    else
480
        then = expiry_then/2;
481
    then *= 1000000000; // into nS - we know there is room in a tick_count_t
482
    then = (then / resolution.dividend) * resolution.divisor; // into system ticks
483
    lease->t1 = now + then;
484
 
485
#if 0 // for testing this mechanism
486
    lease->expiry = now + 5000; // 1000 here makes for failure in the DHCP test
487
    lease->t2     = now + 3500;
488
    lease->t1     = now + 2500;
489
#endif
490
 
491
#ifdef CYGDBG_NET_DHCP_CHATTER
492
    diag_printf("new_lease:\n");
493
    diag_printf("  expiry = %d\n",lease->expiry);
494
    diag_printf("      t1 = %d\n",lease->t1);
495
    diag_printf("      t2 = %d\n",lease->t2);
496
#endif
497
 
498
    lease->next = DHCP_LEASE_T1;
499
 
500
    cyg_alarm_initialize( lease->alarm, lease->t1, 0 );
501
    cyg_alarm_enable( lease->alarm );
502
}
503
 
504
// ------------------------------------------------------------------------
505
// Set all the tags we want to use when sending a packet.
506
// This has expanded to a large, explicit set to interwork better
507
// with a variety of DHCP servers.
508
 
509
static void set_default_dhcp_tags( struct bootp *xmit )
510
{
511
    // Explicitly request full set of params that are default for LINUX
512
    // dhcp servers, but not default for others.  This is rather arbitrary,
513
    // but it preserves behaviour for people using those servers.
514
    // Perhaps configury of this set will be needed in future?
515
    //
516
    // Here's the set:
517
    static cyg_uint8 req_list[]  = {
518
#ifdef CYGOPT_NET_DHCP_PARM_REQ_LIST_REPLACE
519
        CYGOPT_NET_DHCP_PARM_REQ_LIST_REPLACE ,
520
#else
521
        TAG_DHCP_SERVER_ID    ,     //     DHCP server id: 10.16.19.66
522
        TAG_DHCP_LEASE_TIME   ,     //     DHCP time 51: 60
523
        TAG_DHCP_RENEWAL_TIME ,     //     DHCP time 58: 30
524
        TAG_DHCP_REBIND_TIME  ,     //     DHCP time 59: 52
525
        TAG_SUBNET_MASK       ,     //     subnet mask: 255.255.255.0
526
        TAG_GATEWAY           ,     //     gateway: 10.16.19.66
527
        TAG_DOMAIN_SERVER     ,     //     domain server: 10.16.19.66
528
        TAG_DOMAIN_NAME       ,     //     domain name: hmt10.cambridge.redhat.com
529
        TAG_IP_BROADCAST      ,     //     IP broadcast: 10.16.19.255
530
#endif
531
#ifdef CYGOPT_NET_DHCP_PARM_REQ_LIST_ADDITIONAL
532
        CYGOPT_NET_DHCP_PARM_REQ_LIST_ADDITIONAL ,
533
#endif
534
    };
535
 
536
    if ( req_list[0] ) // So that one may easily turn it all off by configury
537
        set_variable_tag( xmit, TAG_DHCP_PARM_REQ_LIST,
538
                          &req_list[0], sizeof( req_list ) );
539
 
540
    // Explicitly specify our max message size.
541
    set_fixed_tag( xmit, TAG_DHCP_MAX_MSGSZ, BP_MINPKTSZ, 2 );
542
}
543
 
544
// ------------------------------------------------------------------------
545
// the DHCP state machine - this does all the work
546
 
547
int
548
do_dhcp(const char *intf, struct bootp *res,
549
        cyg_uint8 *pstate, struct dhcp_lease *lease)
550
{
551
    struct ifreq ifr;
552
    struct sockaddr_in cli_addr, broadcast_addr, server_addr, rx_addr;
553
    int s, addrlen;
554
    int one = 1;
555
    unsigned char mincookie[] = {99,130,83,99,255} ;
556
    struct timeval tv;
557
    struct timeout_state timeout_scratch;
558
    cyg_uint8 oldstate = *pstate;
559
    cyg_uint8 msgtype = 0, seen_bootp_reply = 0;
560
    unsigned int length;
561
 
562
    cyg_uint32 xid;
563
 
564
#define CHECK_XID() (  /* and other details */                                  \
565
    received->bp_xid   != xid            || /* not the same transaction */      \
566
    received->bp_htype != xmit->bp_htype || /* not the same ESA type    */      \
567
    received->bp_hlen  != xmit->bp_hlen  || /* not the same length      */      \
568
    bcmp( &received->bp_chaddr, &xmit->bp_chaddr, xmit->bp_hlen )               \
569
    )
570
 
571
    // IMPORTANT: xmit is the same as res throughout this; *received is a
572
    // scratch buffer for reception; its contents are always copied to res
573
    // when we are happy with them.  So we always transmit from the
574
    // existing state.
575
    struct bootp rx_local;
576
    struct bootp *received = &rx_local;
577
    struct bootp *xmit = res;
578
    struct bootp xmit2;
579
    int xlen;
580
 
581
    // First, get a socket on the interface in question.  But Zeroth, if
582
    // needs be, bring it to the half-up broadcast only state if needs be.
583
 
584
    if ( DHCPSTATE_INIT      == oldstate
585
         || DHCPSTATE_FAILED == oldstate
586
         || 0                == oldstate ) {
587
        // either explicit init state or the beginning of time or retry
588
        if ( ! bring_half_up( intf, &ifr ) )
589
            return false;
590
 
591
        *pstate = DHCPSTATE_INIT;
592
    }
593
 
594
    s = socket(AF_INET, SOCK_DGRAM, 0);
595
    if (s < 0) {
596
        perror("socket");
597
        return false;
598
    }
599
 
600
    if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one))) {
601
        perror("setsockopt");
602
        return false;
603
    }
604
 
605
    memset((char *) &cli_addr, 0, sizeof(cli_addr));
606
    cli_addr.sin_family = AF_INET;
607
    cli_addr.sin_len = sizeof(cli_addr);
608
    cli_addr.sin_addr.s_addr = htonl(INADDR_ANY);
609
    cli_addr.sin_port = htons(IPPORT_BOOTPC);
610
 
611
    memset((char *) &broadcast_addr, 0, sizeof(broadcast_addr));
612
    broadcast_addr.sin_family = AF_INET;
613
    broadcast_addr.sin_len = sizeof(broadcast_addr);
614
    broadcast_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
615
    broadcast_addr.sin_port = htons(IPPORT_BOOTPS);
616
 
617
    memset((char *) &server_addr, 0, sizeof(server_addr));
618
    server_addr.sin_family = AF_INET;
619
    server_addr.sin_len = sizeof(server_addr);
620
    server_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST); // overwrite later
621
    server_addr.sin_port = htons(IPPORT_BOOTPS);
622
 
623
    if(bind(s, (struct sockaddr *) &cli_addr, sizeof(cli_addr)) < 0) {
624
        perror("bind error");
625
        return false;
626
    }
627
    if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) {
628
        perror("setsockopt SO_REUSEADDR");
629
        return false;
630
    }
631
    if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one))) {
632
        perror("setsockopt SO_REUSEPORT");
633
        return false;
634
    }
635
 
636
    // Now, we can launch into the DHCP state machine.  I think this will
637
    // be the neatest way to do it; it returns from within the switch arms
638
    // when all is well, or utterly failed.
639
 
640
    reset_timeout( &tv, &timeout_scratch );
641
 
642
    // Choose a new XID: first get the ESA as a basis:
643
    strcpy(&ifr.ifr_name[0], intf);
644
    if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0) {
645
        perror("SIOCGIFHWADDR 2");
646
        return false;
647
    }
648
 
649
    // Choose from scratch depending on ifr_hwaddr...[]
650
    xid = ifr.ifr_hwaddr.sa_data[5];
651
    xid |= (ifr.ifr_hwaddr.sa_data[4]) << 8;
652
    xid |= (ifr.ifr_hwaddr.sa_data[3]) << 16;
653
    xid |= (ifr.ifr_hwaddr.sa_data[2]) << 24;
654
    xid ^= (cyg_arc4random() & 0xffff0000);
655
 
656
    // Avoid adjacent ESAs colliding by increment
657
#define NEW_XID(_xid) CYG_MACRO_START (_xid)+= 0x10000; CYG_MACRO_END
658
 
659
    while ( 1 ) {
660
 
661
        // If we are active rather than in the process of shutting down,
662
        // check for any lease expiry every time round, so that alarms
663
        // *can* change the course of events even when already renewing,
664
        // for example.
665
        if ( DHCPSTATE_DO_RELEASE   != *pstate
666
             && DHCPSTATE_NOTBOUND  != *pstate
667
             && DHCPSTATE_FAILED    != *pstate ) {
668
            cyg_uint8 lease_state;
669
 
670
            cyg_scheduler_lock();
671
            lease_state = lease->which;
672
            lease->which = 0; // flag that we have noticed it
673
            cyg_scheduler_unlock();
674
 
675
            if ( lease_state & DHCP_LEASE_EX ) {
676
                // then the lease has expired completely!
677
                *pstate = DHCPSTATE_NOTBOUND;
678
            }
679
            else if ( lease_state & DHCP_LEASE_T2 ) {
680
                // Time to renew
681
                reset_timeout( &tv, &timeout_scratch ); // next conversation
682
                *pstate = DHCPSTATE_REBINDING;
683
            }
684
            else if ( lease_state & DHCP_LEASE_T1 ) {
685
                // Time to renew
686
                reset_timeout( &tv, &timeout_scratch ); // next conversation
687
                *pstate = DHCPSTATE_RENEWING;
688
            }
689
        }
690
 
691
        switch ( *pstate ) {
692
 
693
        case DHCPSTATE_INIT:
694
 
695
            // Send the DHCPDISCOVER packet
696
 
697
            // Fill in the BOOTP request - DHCPDISCOVER packet
698
            bzero(xmit, sizeof(*xmit));
699
            xmit->bp_op = BOOTREQUEST;
700
            xmit->bp_htype = HTYPE_ETHERNET;
701
            xmit->bp_hlen = IFHWADDRLEN;
702
            xmit->bp_xid = xid;
703
            xmit->bp_secs = 0;
704
            xmit->bp_flags = htons(0x8000); // BROADCAST FLAG
705
            bcopy(ifr.ifr_hwaddr.sa_data, &xmit->bp_chaddr, xmit->bp_hlen);
706
            bcopy(mincookie, xmit->bp_vend, sizeof(mincookie));
707
 
708
            // remove the next line to test ability to handle bootp packets.
709
            set_fixed_tag( xmit, TAG_DHCP_MESS_TYPE, DHCPDISCOVER, 1 );
710
            // Set all the tags we want to use when sending a packet
711
            set_default_dhcp_tags( xmit );
712
 
713
#ifdef CYGDBG_NET_DHCP_CHATTER
714
            diag_printf( "---------DHCPSTATE_INIT sending:\n" );
715
            show_bootp( intf, xmit );
716
#endif            
717
            if(sendto(s, xmit, dhcp_size_for_send(xmit), 0,
718
                      (struct sockaddr *)&broadcast_addr, sizeof(broadcast_addr)) < 0) {
719
                *pstate = DHCPSTATE_FAILED;
720
                break;
721
            }
722
 
723
            seen_bootp_reply = 0;
724
            *pstate = DHCPSTATE_SELECTING;
725
            break;
726
 
727
        case DHCPSTATE_SELECTING:
728
            // This is a separate state so that we can listen again
729
            // *without* retransmitting.
730
 
731
            // listen for the DHCPOFFER reply
732
 
733
            setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
734
 
735
            addrlen = sizeof(rx_addr);
736
            if (recvfrom(s, received, sizeof(struct bootp), 0,
737
                         (struct sockaddr *)&rx_addr, &addrlen) < 0) {
738
                // No packet arrived (this time)
739
                if ( seen_bootp_reply ) { // then already have a bootp reply
740
                    // Save the good packet in *xmit
741
                    bcopy( received, xmit, dhcp_size(received) );
742
                    *pstate = DHCPSTATE_BOOTP_FALLBACK;
743
                    NEW_XID( xid ); // Happy to advance, so new XID
744
                    reset_timeout( &tv, &timeout_scratch );
745
                    break;
746
                }
747
                // go to the next larger timeout and re-send:
748
                if ( ! next_timeout( &tv, &timeout_scratch ) ) {
749
                    *pstate = DHCPSTATE_FAILED;
750
                    break;
751
                }
752
                *pstate = DHCPSTATE_INIT; // to retransmit
753
                break;
754
            }
755
            // Check for well-formed packet with correct termination (not truncated)
756
            length = dhcp_size( received );
757
#ifdef CYGDBG_NET_DHCP_CHATTER
758
            diag_printf( "---------DHCPSTATE_SELECTING received:\n" );
759
            if ( length <= 0 )
760
                diag_printf( "WARNING! malformed or truncated packet\n" );
761
            diag_printf( "...rx_addr is family %d, addr %08x, port %d\n",
762
                         rx_addr.sin_family,
763
                         rx_addr.sin_addr.s_addr,
764
                         rx_addr.sin_port );
765
            show_bootp( intf, received );
766
#endif            
767
            if ( length <= 0 )
768
                break;
769
            if ( CHECK_XID() )          // XID and ESA matches?
770
                break;                  // listen again...
771
 
772
            if ( 0 == received->bp_siaddr.s_addr ) {
773
                // then fill in from the options...
774
                length = sizeof(received->bp_siaddr.s_addr);
775
                get_bootp_option( received, TAG_DHCP_SERVER_ID,
776
                                  &received->bp_siaddr.s_addr,
777
                                  &length);
778
            }
779
 
780
            // see if it was a DHCP reply or a bootp reply; it could be
781
            // either.
782
            length = sizeof(msgtype);
783
            if ( get_bootp_option( received, TAG_DHCP_MESS_TYPE, &msgtype,
784
                                   &length) ) {
785
                if ( DHCPOFFER == msgtype ) { // all is well
786
                    // Save the good packet in *xmit
787
                    bcopy( received, xmit, dhcp_size(received) );
788
                    // we like the packet, so reset the timeout for next time
789
                    reset_timeout( &tv, &timeout_scratch );
790
                    *pstate = DHCPSTATE_REQUESTING;
791
                    NEW_XID( xid ); // Happy to advance, so new XID
792
                }
793
            }
794
            else // No TAG_DHCP_MESS_TYPE entry so it's a bootp reply
795
                seen_bootp_reply = 1; // (keep the bootp packet in received)
796
 
797
            // If none of the above state changes occurred, we got a packet
798
            // that "should not happen", OR we have a bootp reply in our
799
            // hand; so listen again with the same timeout, without
800
            // retrying the send, in the hope of getting a DHCP reply.
801
            break;
802
 
803
        case DHCPSTATE_REQUESTING:
804
            // Just send what you got with a DHCPREQUEST in the message type.
805
            // then wait for an ACK in DHCPSTATE_REQUEST_RECV.
806
 
807
            // Fill in the BOOTP request - DHCPREQUEST packet
808
            xmit->bp_xid = xid;
809
            xmit->bp_op = BOOTREQUEST;
810
            xmit->bp_flags = htons(0x8000); // BROADCAST FLAG
811
 
812
            set_fixed_tag( xmit, TAG_DHCP_MESS_TYPE, DHCPREQUEST, 1 );
813
            // Set all the tags we want to use when sending a packet
814
            set_default_dhcp_tags( xmit );
815
            // And this will be a new one:
816
            set_fixed_tag( xmit, TAG_DHCP_REQ_IP, ntohl(xmit->bp_yiaddr.s_addr), 4 );
817
 
818
#ifdef CYGDBG_NET_DHCP_CHATTER
819
            diag_printf( "---------DHCPSTATE_REQUESTING sending:\n" );
820
            show_bootp( intf, xmit );
821
#endif            
822
            // Send back a [modified] copy.  Note that some fields are explicitly
823
            // cleared, as per the RFC.  We need the copy because these fields are
824
            // still useful to us (and currently stored in the 'result' structure)
825
            xlen = dhcp_size_for_send( xmit );
826
            bcopy( xmit, &xmit2, xlen );
827
            xmit2.bp_yiaddr.s_addr = xmit2.bp_siaddr.s_addr = xmit2.bp_giaddr.s_addr = 0;
828
            xmit2.bp_hops = 0;
829
            if(sendto(s, &xmit2, xlen, 0,
830
                      (struct sockaddr *)&broadcast_addr, sizeof(broadcast_addr)) < 0) {
831
                *pstate = DHCPSTATE_FAILED;
832
                break;
833
            }
834
 
835
            *pstate = DHCPSTATE_REQUEST_RECV;
836
            break;
837
 
838
        case DHCPSTATE_REQUEST_RECV:
839
            // wait for an ACK or a NACK - retry by going back to
840
            // DHCPSTATE_REQUESTING; NACK means go back to INIT.
841
 
842
            setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
843
 
844
            addrlen = sizeof(rx_addr);
845
            if (recvfrom(s, received, sizeof(struct bootp), 0,
846
                         (struct sockaddr *)&rx_addr, &addrlen) < 0) {
847
                // No packet arrived
848
                // go to the next larger timeout and re-send:
849
                if ( ! next_timeout( &tv, &timeout_scratch ) ) {
850
                    *pstate = DHCPSTATE_FAILED;
851
                    break;
852
                }
853
                *pstate = DHCPSTATE_REQUESTING;
854
                break;
855
            }
856
            // Check for well-formed packet with correct termination (not truncated)
857
            length = dhcp_size( received );
858
#ifdef CYGDBG_NET_DHCP_CHATTER
859
            diag_printf( "---------DHCPSTATE_REQUEST_RECV received:\n" );
860
            if ( length <= 0 )
861
                diag_printf( "WARNING! malformed or truncated packet\n" );
862
            diag_printf( "...rx_addr is family %d, addr %08x, port %d\n",
863
                         rx_addr.sin_family,
864
                         rx_addr.sin_addr.s_addr,
865
                         rx_addr.sin_port );
866
            show_bootp( intf, received );
867
#endif            
868
            if ( length <= 0 )
869
                break;
870
            if ( CHECK_XID() )          // not the same transaction;
871
                break;                  // listen again...
872
 
873
            if ( 0 == received->bp_siaddr.s_addr ) {
874
                // then fill in from the options...
875
                length = sizeof(received->bp_siaddr.s_addr );
876
                get_bootp_option( received, TAG_DHCP_SERVER_ID,
877
                                  &received->bp_siaddr.s_addr,
878
                                  &length);
879
            }
880
 
881
            // check it was a DHCP reply
882
            length = sizeof(msgtype);
883
            if ( get_bootp_option( received, TAG_DHCP_MESS_TYPE, &msgtype,
884
                                   &length) ) {
885
                if ( DHCPACK == msgtype // Same offer & server?
886
                     && received->bp_yiaddr.s_addr == xmit->bp_yiaddr.s_addr
887
                     && received->bp_siaddr.s_addr == xmit->bp_siaddr.s_addr) {
888
                    // we like the packet, so reset the timeout for next time
889
                    reset_timeout( &tv, &timeout_scratch );
890
                    // Record the new lease and set up timers &c
891
                    new_lease( received, lease );
892
                    *pstate = DHCPSTATE_BOUND;
893
                    break;
894
                }
895
                if ( DHCPNAK == msgtype // Same server?
896
                     && received->bp_siaddr.s_addr == xmit->bp_siaddr.s_addr) {
897
                    // we're bounced!
898
                    *pstate = DHCPSTATE_INIT;  // So back the start of the rigmarole.
899
                    NEW_XID( xid ); // Unhappy to advance, so new XID
900
                    reset_timeout( &tv, &timeout_scratch );
901
                    break;
902
                }
903
                // otherwise it's something else, maybe another offer, or a bogus
904
                // NAK from someone we are not asking!
905
                // Just listen again, which implicitly discards it.
906
            }
907
            break;
908
 
909
        case DHCPSTATE_BOUND:
910
 
911
            // We are happy now, we have our address.
912
 
913
            // All done with socket
914
            close(s);
915
 
916
            // Re-initialize the interface with the new state
917
            if ( DHCPSTATE_BOUND != oldstate ) {
918
                // Then need to go down and up
919
                do_dhcp_down_net( intf, res, &oldstate, lease ); // oldstate used
920
                if ( 0 != oldstate ) {
921
                    // Then not called from init_all_network_interfaces()
922
                    // so we must initialize the interface ourselves
923
                    if (!init_net(intf, res)) {
924
                        do_dhcp_down_net( intf, res, pstate, lease );
925
                        *pstate = DHCPSTATE_FAILED;
926
                        return false;
927
                    }
928
                }
929
            }
930
 
931
            // Otherwise, nothing whatsoever to do...
932
            return true;
933
 
934
        case DHCPSTATE_RENEWING:
935
            // Just send what you got with a DHCPREQUEST in the message
936
            // type UNICAST straight to the server.  Then wait for an ACK.
937
 
938
            // Fill in the BOOTP request - DHCPREQUEST packet
939
            xmit->bp_xid = xid;
940
            xmit->bp_op = BOOTREQUEST;
941
            xmit->bp_flags = htons(0); // No BROADCAST FLAG
942
            // Use the *client* address here:
943
            xmit->bp_ciaddr.s_addr = xmit->bp_yiaddr.s_addr;
944
 
945
            set_fixed_tag( xmit, TAG_DHCP_MESS_TYPE, DHCPREQUEST, 1 );
946
            // These must not be set in this context
947
            unset_tag( xmit, TAG_DHCP_REQ_IP );
948
            unset_tag( xmit, TAG_DHCP_SERVER_ID );
949
            // Set all the tags we want to use when sending a packet
950
            set_default_dhcp_tags( xmit );
951
 
952
            // Set unicast address to *server*
953
            server_addr.sin_addr.s_addr = res->bp_siaddr.s_addr;
954
 
955
#ifdef CYGDBG_NET_DHCP_CHATTER
956
            diag_printf( "---------DHCPSTATE_RENEWING sending:\n" );
957
            diag_printf( "UNICAST to family %d, addr %08x, port %d\n",
958
                         server_addr.sin_family,
959
                         server_addr.sin_addr.s_addr,
960
                         server_addr.sin_port );
961
            show_bootp( intf, xmit );
962
#endif            
963
 
964
            // Send back a [modified] copy.  Note that some fields are explicitly
965
            // cleared, as per the RFC.  We need the copy because these fields are
966
            // still useful to us (and currently stored in the 'result' structure)
967
            xlen = dhcp_size_for_send(xmit);
968
            bcopy( xmit, &xmit2, xlen );
969
            xmit2.bp_yiaddr.s_addr = xmit2.bp_siaddr.s_addr = xmit2.bp_giaddr.s_addr = 0;
970
            xmit2.bp_hops = 0;
971
            if(sendto(s, &xmit2, xlen, 0,
972
                       // UNICAST address of the server:
973
                      (struct sockaddr *)&server_addr,
974
                      sizeof(server_addr)) < 0) {
975
                *pstate = DHCPSTATE_FAILED;
976
                break;
977
            }
978
 
979
            *pstate = DHCPSTATE_RENEW_RECV;
980
            break;
981
 
982
        case DHCPSTATE_RENEW_RECV:
983
            // wait for an ACK or a NACK - retry by going back to
984
            // DHCPSTATE_RENEWING; NACK means go to NOTBOUND.
985
            // No answer means just wait for T2, to broadcast.
986
 
987
            setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
988
 
989
            addrlen = sizeof(rx_addr);
990
            if (recvfrom(s, received, sizeof(struct bootp), 0,
991
                         (struct sockaddr *)&rx_addr, &addrlen) < 0) {
992
                // No packet arrived
993
                // go to the next larger timeout and re-send:
994
                if ( ! next_timeout( &tv, &timeout_scratch ) ) {
995
                    // If we timed out completely, just give up until T2
996
                    // expires - retain the lease meanwhile.  The normal
997
                    // lease mechanism will invoke REBINDING as and when
998
                    // necessary.
999
                    *pstate = DHCPSTATE_BOUND;
1000
                    break;
1001
                }
1002
                *pstate = DHCPSTATE_RENEWING;
1003
                break;
1004
            }
1005
            // Check for well-formed packet with correct termination (not truncated)
1006
            length = dhcp_size( received );
1007
#ifdef CYGDBG_NET_DHCP_CHATTER
1008
            diag_printf( "---------DHCPSTATE_RENEW_RECV received:\n" );
1009
            if ( length <= 0 )
1010
                diag_printf( "WARNING! malformed or truncated packet\n" );
1011
            diag_printf( "...rx_addr is family %d, addr %08x, port %d\n",
1012
                         rx_addr.sin_family,
1013
                         rx_addr.sin_addr.s_addr,
1014
                         rx_addr.sin_port );
1015
            show_bootp( intf, received );
1016
#endif            
1017
            if ( length <= 0 )
1018
                break;
1019
            if ( CHECK_XID() )          // not the same transaction;
1020
                break;                  // listen again...
1021
 
1022
            if ( 0 == received->bp_siaddr.s_addr ) {
1023
                // then fill in from the options...
1024
                length = sizeof(received->bp_siaddr.s_addr);
1025
                get_bootp_option( received, TAG_DHCP_SERVER_ID,
1026
                                  &received->bp_siaddr.s_addr,
1027
                                  &length);
1028
            }
1029
 
1030
            // check it was a DHCP reply
1031
            length = sizeof(msgtype);
1032
            if ( get_bootp_option( received, TAG_DHCP_MESS_TYPE, &msgtype,
1033
                                   &length) ) {
1034
                if ( DHCPACK == msgtype  // Same offer?
1035
                     && received->bp_yiaddr.s_addr == xmit->bp_yiaddr.s_addr) {
1036
                    // we like the packet, so reset the timeout for next time
1037
                    reset_timeout( &tv, &timeout_scratch );
1038
                    // Record the new lease and set up timers &c
1039
                    new_lease( received, lease );
1040
                    *pstate = DHCPSTATE_BOUND;
1041
                    break;
1042
                }
1043
                if ( DHCPNAK == msgtype ) { // we're bounced!
1044
                    *pstate = DHCPSTATE_NOTBOUND;  // So quit out.
1045
                    break;
1046
                }
1047
                // otherwise it's something else, maybe another offer.
1048
                // Just listen again, which implicitly discards it.
1049
            }
1050
            break;
1051
 
1052
        case DHCPSTATE_REBINDING:
1053
            // Just send what you got with a DHCPREQUEST in the message type.
1054
            // Then wait for an ACK.  This one is BROADCAST.
1055
 
1056
            // Fill in the BOOTP request - DHCPREQUEST packet
1057
            xmit->bp_xid = xid;
1058
            xmit->bp_op = BOOTREQUEST;
1059
            xmit->bp_flags = htons(0); // no BROADCAST FLAG
1060
            // Use the *client* address here:
1061
            xmit->bp_ciaddr.s_addr = xmit->bp_yiaddr.s_addr;
1062
 
1063
            set_fixed_tag( xmit, TAG_DHCP_MESS_TYPE, DHCPREQUEST, 1 );
1064
            // These must not be set in this context
1065
            unset_tag( xmit, TAG_DHCP_REQ_IP );
1066
            unset_tag( xmit, TAG_DHCP_SERVER_ID );
1067
            // Set all the tags we want to use when sending a packet
1068
            set_default_dhcp_tags( xmit );
1069
 
1070
#ifdef CYGDBG_NET_DHCP_CHATTER
1071
            diag_printf( "---------DHCPSTATE_REBINDING sending:\n" );
1072
            show_bootp( intf, xmit );
1073
#endif            
1074
            // Send back a [modified] copy.  Note that some fields are explicitly
1075
            // cleared, as per the RFC.  We need the copy because these fields are
1076
            // still useful to us (and currently stored in the 'result' structure)
1077
            xlen = dhcp_size_for_send( xmit );
1078
            bcopy( xmit, &xmit2, xlen );
1079
            xmit2.bp_yiaddr.s_addr = xmit2.bp_siaddr.s_addr = xmit2.bp_giaddr.s_addr = 0;
1080
            xmit2.bp_hops = 0;
1081
            if(sendto(s, &xmit2, xlen, 0,
1082
                      (struct sockaddr *)&broadcast_addr, sizeof(broadcast_addr)) < 0) {
1083
                *pstate = DHCPSTATE_FAILED;
1084
                break;
1085
            }
1086
 
1087
            *pstate = DHCPSTATE_REBIND_RECV;
1088
            break;
1089
 
1090
        case DHCPSTATE_REBIND_RECV:
1091
            // wait for an ACK or a NACK - retry by going back to
1092
            // DHCPSTATE_REBINDING; NACK means go to NOTBOUND.
1093
            // No answer means just wait for expiry; we tried!
1094
 
1095
            setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
1096
 
1097
            addrlen = sizeof(rx_addr);
1098
            if (recvfrom(s, received, sizeof(struct bootp), 0,
1099
                         (struct sockaddr *)&rx_addr, &addrlen) < 0) {
1100
                // No packet arrived
1101
                // go to the next larger timeout and re-send:
1102
                if ( ! next_timeout( &tv, &timeout_scratch ) ) {
1103
                    // If we timed out completely, just give up until EX
1104
                    // expires - retain the lease meanwhile.  The normal
1105
                    // lease mechanism will invoke NOTBOUND state as and
1106
                    // when necessary.
1107
                    *pstate = DHCPSTATE_BOUND;
1108
                    break;
1109
                }
1110
                *pstate = DHCPSTATE_REBINDING;
1111
                break;
1112
            }
1113
            // Check for well-formed packet with correct termination (not truncated)
1114
            length = dhcp_size( received );
1115
#ifdef CYGDBG_NET_DHCP_CHATTER
1116
            diag_printf( "---------DHCPSTATE_REBIND_RECV received:\n" );
1117
            if ( length <= 0 )
1118
                diag_printf( "WARNING! malformed or truncated packet\n" );
1119
            diag_printf( "...rx_addr is family %d, addr %08x, port %d\n",
1120
                         rx_addr.sin_family,
1121
                         rx_addr.sin_addr.s_addr,
1122
                         rx_addr.sin_port );
1123
            show_bootp( intf, received );
1124
#endif            
1125
            if ( length <= 0 )
1126
                break;
1127
            if ( CHECK_XID() )          // not the same transaction;
1128
                break;                  // listen again...
1129
 
1130
            if ( 0 == received->bp_siaddr.s_addr ) {
1131
                // then fill in from the options...
1132
                int length = sizeof(received->bp_siaddr.s_addr );
1133
                get_bootp_option( received, TAG_DHCP_SERVER_ID,
1134
                                  &received->bp_siaddr.s_addr,
1135
                                  &length);
1136
            }
1137
 
1138
            // check it was a DHCP reply
1139
            length = sizeof(msgtype);
1140
            if ( get_bootp_option( received, TAG_DHCP_MESS_TYPE, &msgtype,
1141
                                   &length) ) {
1142
                if ( DHCPACK == msgtype  // Same offer?
1143
                     && received->bp_yiaddr.s_addr == xmit->bp_yiaddr.s_addr) {
1144
                    // we like the packet, so reset the timeout for next time
1145
                    reset_timeout( &tv, &timeout_scratch );
1146
                    // Record the new lease and set up timers &c
1147
                    new_lease( received, lease );
1148
                    *pstate = DHCPSTATE_BOUND;
1149
                    break;
1150
                }
1151
                else if ( DHCPNAK == msgtype ) { // we're bounced!
1152
                    *pstate = DHCPSTATE_NOTBOUND;  // So back the start of the rigmarole.
1153
                    break;
1154
                }
1155
                // otherwise it's something else, maybe another offer.
1156
                // Just listen again, which implicitly discards it.
1157
            }
1158
            break;
1159
 
1160
        case DHCPSTATE_BOOTP_FALLBACK:
1161
            // All done with socket
1162
            close(s);
1163
            // And no lease should have become active, but JIC
1164
            no_lease( lease );
1165
            // Re-initialize the interface with the new state
1166
            if ( DHCPSTATE_BOOTP_FALLBACK != oldstate ) {
1167
                // Then need to go down and up
1168
                do_dhcp_down_net( intf, res, &oldstate, lease ); // oldstate used
1169
                if ( 0 != oldstate ) {
1170
                    // Then not called from init_all_network_interfaces()
1171
                    // so we must initialize the interface ourselves
1172
                    if (!init_net(intf, res)) {
1173
                        do_dhcp_down_net( intf, res, pstate, lease );
1174
                        *pstate = DHCPSTATE_FAILED;
1175
                        return false;
1176
                    }
1177
                }
1178
            }
1179
 
1180
            // Otherwise, nothing whatsoever to do...
1181
            return true;
1182
 
1183
        case DHCPSTATE_NOTBOUND:
1184
            // All done with socket
1185
            close(s);
1186
            // No lease active
1187
            no_lease( lease );
1188
            // Leave interface up so app can tidy.
1189
            return false;
1190
 
1191
        case DHCPSTATE_FAILED:
1192
            // All done with socket
1193
            close(s);
1194
            // No lease active
1195
            no_lease( lease );
1196
            // Unconditionally down the interface.
1197
            do_dhcp_down_net( intf, res, &oldstate, lease );
1198
            return false;
1199
 
1200
        case DHCPSTATE_DO_RELEASE:
1201
            // We have been forced here by external means, to release the
1202
            // lease for graceful shutdown.
1203
 
1204
            // Just send what you got with a DHCPRELEASE in the message
1205
            // type UNICAST straight to the server.  No ACK.  Then go to
1206
            // NOTBOUND state.
1207
            NEW_XID( xid );
1208
            xmit->bp_xid = xid;
1209
            xmit->bp_op = BOOTREQUEST;
1210
            xmit->bp_flags = htons(0); // no BROADCAST FLAG
1211
            // Use the *client* address here:
1212
            xmit->bp_ciaddr.s_addr = xmit->bp_yiaddr.s_addr;
1213
 
1214
            set_fixed_tag( xmit, TAG_DHCP_MESS_TYPE, DHCPRELEASE, 1 );
1215
 
1216
            // Set unicast address to *server*
1217
            server_addr.sin_addr.s_addr = res->bp_siaddr.s_addr;
1218
 
1219
#ifdef CYGDBG_NET_DHCP_CHATTER
1220
            diag_printf( "---------DHCPSTATE_DO_RELEASE sending:\n" );
1221
            diag_printf( "UNICAST to family %d, addr %08x, port %d\n",
1222
                         server_addr.sin_family,
1223
                         server_addr.sin_addr.s_addr,
1224
                         server_addr.sin_port );
1225
            show_bootp( intf, xmit );
1226
#endif            
1227
            // Send back a [modified] copy.  Note that some fields are explicitly
1228
            // cleared, as per the RFC.  We need the copy because these fields are
1229
            // still useful to us (and currently stored in the 'result' structure)
1230
            xlen = dhcp_size_for_send( xmit );
1231
            bcopy( xmit, &xmit2, xlen );
1232
            xmit2.bp_yiaddr.s_addr = xmit2.bp_siaddr.s_addr = xmit2.bp_giaddr.s_addr = 0;
1233
            xmit2.bp_hops = 0;
1234
            if(sendto(s, &xmit2, xlen, 0,
1235
                       // UNICAST address of the server:
1236
                      (struct sockaddr *)&server_addr,
1237
                      sizeof(server_addr)) < 0) {
1238
                *pstate = DHCPSTATE_FAILED;
1239
                break;
1240
            }
1241
 
1242
            *pstate = DHCPSTATE_NOTBOUND;
1243
            break;
1244
 
1245
        default:
1246
            no_lease( lease );
1247
            close(s);
1248
            return false;
1249
        }
1250
    }
1251
    /* NOTREACHED */
1252
    return false;
1253
}
1254
 
1255
// ------------------------------------------------------------------------
1256
// Bring an interface down, failed to initialize it or lease is expired
1257
// Also part of normal startup, bring down for proper reinitialization
1258
 
1259
int
1260
do_dhcp_down_net(const char *intf, struct bootp *res,
1261
        cyg_uint8 *pstate, struct dhcp_lease *lease)
1262
{
1263
    struct sockaddr_in *addrp;
1264
    struct ifreq ifr;
1265
    int s;
1266
 
1267
    // Ensure clean slate
1268
    cyg_route_reinit();  // Force any existing routes to be forgotten
1269
 
1270
    s = socket(AF_INET, SOCK_DGRAM, 0);
1271
    if (s < 0) {
1272
        perror("socket");
1273
        return false;
1274
    }
1275
 
1276
    addrp = (struct sockaddr_in *) &ifr.ifr_addr;
1277
 
1278
    // Remove any existing address
1279
    if ( DHCPSTATE_FAILED  == *pstate
1280
         || DHCPSTATE_INIT == *pstate
1281
         || 0              == *pstate ) {
1282
        // it was configured for broadcast only, "half-up"
1283
        memset(addrp, 0, sizeof(*addrp));
1284
        addrp->sin_family = AF_INET;
1285
        addrp->sin_len = sizeof(*addrp);
1286
        addrp->sin_port = 0;
1287
        addrp->sin_addr.s_addr = INADDR_ANY;
1288
    }
1289
    else {
1290
        // get the specific address that was used
1291
        strcpy(ifr.ifr_name, intf);
1292
        if (ioctl(s, SIOCGIFADDR, &ifr)) {
1293
            perror("SIOCGIFADDR 1");
1294
            return false;
1295
        }
1296
    }
1297
 
1298
    strcpy(ifr.ifr_name, intf);
1299
    if (ioctl(s, SIOCDIFADDR, &ifr)) { /* delete IF addr */
1300
        perror("SIOCDIFADDR1");
1301
    }
1302
 
1303
#ifdef INET6
1304
    {
1305
      int s6;
1306
 
1307
      s6 = socket(AF_INET6, SOCK_DGRAM, 0);
1308
      if (s6 < 0) {
1309
        perror("socket AF_INET6");
1310
        return false;
1311
      }
1312
      // Now delete the ipv6 addr
1313
      strcpy(ifr.ifr_name, intf);
1314
      if (ioctl(s6, SIOCGLIFADDR, &ifr)) {
1315
        perror("SIOCGIFADDR_IN6 1");
1316
        return false;
1317
      }
1318
 
1319
      strcpy(ifr.ifr_name, intf);
1320
      if (ioctl(s6, SIOCDLIFADDR, &ifr)) { /* delete IF addr */
1321
        perror("SIOCDIFADDR_IN61");
1322
      }
1323
      close(s6);
1324
    }
1325
#endif /* IP6 */
1326
 
1327
    // Shut down interface so it can be reinitialized
1328
    ifr.ifr_flags &= ~(IFF_UP | IFF_RUNNING);
1329
    if (ioctl(s, SIOCSIFFLAGS, &ifr)) { /* set ifnet flags */
1330
        perror("SIOCSIFFLAGS down");
1331
        return false;
1332
    }
1333
 
1334
    // All done with socket
1335
    close(s);
1336
 
1337
    if ( 0 != *pstate ) // preserve initial state
1338
        *pstate = DHCPSTATE_INIT;
1339
 
1340
    return true;
1341
}
1342
 
1343
// ------------------------------------------------------------------------
1344
// Release (relinquish) a leased address - if we have one - and bring down
1345
// the interface.
1346
int
1347
do_dhcp_release(const char *intf, struct bootp *res,
1348
        cyg_uint8 *pstate, struct dhcp_lease *lease)
1349
{
1350
    if ( 0                           != *pstate
1351
         && DHCPSTATE_INIT           != *pstate
1352
         && DHCPSTATE_NOTBOUND       != *pstate
1353
         && DHCPSTATE_FAILED         != *pstate
1354
         && DHCPSTATE_BOOTP_FALLBACK != *pstate ) {
1355
        *pstate = DHCPSTATE_DO_RELEASE;
1356
        do_dhcp( intf, res, pstate, lease ); // to send the release packet
1357
        cyg_thread_delay( 100 );             // to let it leave the building
1358
    }
1359
    return true;
1360
}
1361
 
1362
// ------------------------------------------------------------------------
1363
 
1364
#endif // CYGPKG_NET_DHCP
1365
 
1366
// EOF dhcp_prot.c

powered by: WebSVN 2.1.0

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