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

Subversion Repositories openrisc

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

powered by: WebSVN 2.1.0

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