1 /*==========================================================================
5 // DHCP protocol implementation for DHCP client
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 // Copyright (C) 2003 Andrew Lunn
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //==========================================================================
42 //#####DESCRIPTIONBEGIN####
45 // Contributors: gthomas, andrew.lunn@ascom.ch
47 // Purpose: DHCP support
50 //####DESCRIPTIONEND####
52 //========================================================================*/
54 #include <pkgconf/system.h>
55 #include <pkgconf/net.h>
57 #ifdef CYGPKG_NET_DHCP
59 #ifdef CYGPKG_NET_SNTP
60 #include <pkgconf/net_sntp.h>
61 #endif /* CYGPKG_NET_SNTP */
64 #define perror( txt ) // nothing
71 #include <cyg/infra/cyg_ass.h>
74 #include <net/if_var.h>
75 #include <netinet6/in6_var.h>
78 extern int cyg_arc4random(void);
80 #ifdef CYGOPT_NET_DHCP_OPTION_HOST_NAME
81 static char dhcp_hostname[CYGNUM_NET_DHCP_OPTION_HOST_NAME_LEN+1];
83 // Set the hostname used by the DHCP TAG_HOST_NAME option. We
84 // copy the callers name into a private buffer, since we don't
85 // know the context in which the callers hostname was allocated.
86 void dhcp_set_hostname(char *hostname)
88 CYG_ASSERT( (strlen(hostname)<=CYGNUM_NET_DHCP_OPTION_HOST_NAME_LEN), "dhcp hostname too long" );
89 strncpy(dhcp_hostname, hostname, CYGNUM_NET_DHCP_OPTION_HOST_NAME_LEN);
93 /* Forward reference prototypes. */
94 static int unset_tag( struct bootp *ppkt, unsigned char tag );
96 // ------------------------------------------------------------------------
97 // Returns a pointer to the end of dhcp message (or NULL if invalid)
98 // meaning the address of the byte *after* the TAG_END token in the vendor
101 static unsigned char *
102 scan_dhcp_size( struct bootp *ppkt )
106 op = &ppkt->bp_vend[0];
107 // First check for the cookie!
112 CYG_FAIL( "Bad DHCP cookie" );
117 // This will only scan the options field.
118 while (*op != TAG_END) {
119 if ( *op == TAG_PAD ) {
124 if ( op > &ppkt->bp_vend[BP_VEND_LEN-1] ) {
125 CYG_FAIL( "Oversize DHCP packet in dhcp_size" );
129 // Check op has not gone wild
130 CYG_ASSERT( op > (unsigned char *)(&ppkt[0]), "op pointer underflow!" );
131 // Compare op with non-existent "next" struct bootp in the array.
132 CYG_ASSERT( op < (unsigned char *)(&ppkt[1]), "op pointer overflow!" );
133 return op + 1; // Address of first invalid byte
136 // ------------------------------------------------------------------------
137 // Get the actual packet size of an initialized buffer
140 dhcp_size( struct bootp *ppkt )
144 op = scan_dhcp_size( ppkt );
146 return (op - (unsigned char *)ppkt);
150 // ------------------------------------------------------------------------
151 // Get the actual packet size of an initialized buffer
152 // This will also pad the packet with 0 if length is less
153 // than BP_STD_TX_MINPKTSZ.
156 dhcp_size_for_send( struct bootp *ppkt )
160 op = scan_dhcp_size( ppkt );
161 if ( !op ) return 0; // Better not scribble!
162 // Zero extra bytes until the packet is large enough.
163 for ( ; op < (((unsigned char *)ppkt) + BP_STD_TX_MINPKTSZ); op++ )
165 return (op - (unsigned char *)ppkt);
168 // ------------------------------------------------------------------------
169 // Insert/set an option value in an initialized buffer
172 set_fixed_tag( struct bootp *ppkt,
179 // Initially this will only scan the options field.
181 op = &ppkt->bp_vend[4];
182 while (*op != TAG_END) {
183 if ( op > &ppkt->bp_vend[BP_VEND_LEN-1] ) {
184 CYG_FAIL( "Oversize DHCP packet in set_fixed_tag" );
187 if (*op == tag) // Found it...
189 if ( *op == TAG_PAD ) {
196 if (*op == tag) { // Found it...
197 /* There are three possibilities:
201 * For 1, just overwrite the existing option data.
202 * For 2, overwrite the existing option data and pullup the
203 * remaining option data (if any).
204 * For 3, pullup any remaining option data to remove the option
205 * and then add the option to the end.
206 * For simplicity, for case 2 and 3, we just call unset_tag()
207 * and re-add the option to the end.
209 if ( *(op+1) != len ) {
210 /* Remove existing option entry. */
211 unset_tag(ppkt, tag);
212 /* Adjust the op pointer to re-add at the end. */
213 op = scan_dhcp_size(ppkt);
214 CYG_ASSERT(op!=NULL, "Invalid options size in set_fixed_tag" );
216 CYG_ASSERT(*op==TAG_END, "Missing TAG_END in set_fixed_tag");
217 if ( op + len + 2 > &ppkt->bp_vend[BP_VEND_LEN-1] ) {
218 CYG_FAIL( "Oversize DHCP packet in set_fixed_tag replace" );
223 *(op + len + 2) = TAG_END;
226 else { // overwrite the end tag and install a new one
227 if ( op + len + 2 > &ppkt->bp_vend[BP_VEND_LEN-1] ) {
228 CYG_FAIL( "Oversize DHCP packet in set_fixed_tag append" );
233 *(op + len + 2) = TAG_END;
235 // and insert the value. Net order is BE.
236 op += len + 2 - 1; // point to end of value
237 while ( len-- > 0 ) {
238 *op-- = (unsigned char)(value & 255);
245 set_variable_tag( struct bootp *ppkt,
252 // Initially this will only scan the options field.
253 op = &ppkt->bp_vend[4];
254 while (*op != TAG_END) {
255 if ( op > &ppkt->bp_vend[BP_VEND_LEN-1] ) {
256 CYG_FAIL( "Oversize DHCP packet in set_variable_tag" );
259 if (*op == tag) // Found it...
261 if ( *op == TAG_PAD ) {
268 if (*op == tag) { // Found it...
269 /* There are three possibilities:
273 * For 1, just overwrite the existing option data.
274 * For 2, overwrite the existing option data and pullup the
275 * remaining option data (if any).
276 * For 3, pullup any remaining option data to remove the option
277 * and then add the option to the end.
278 * For simplicity, for case 2 and 3, we just call unset_tag()
279 * and re-add the option to the end.
281 if ( *(op+1) != len ) {
282 /* Remove existing option entry. */
283 unset_tag(ppkt, tag);
284 /* Adjust the op pointer to re-add at the end. */
285 op = scan_dhcp_size(ppkt);
286 CYG_ASSERT(op!=NULL, "Invalid options size in set_variable_tag" );
288 CYG_ASSERT(*op==TAG_END, "Missing TAG_END in set_variable_tag");
289 if ( op + len + 2 > &ppkt->bp_vend[BP_VEND_LEN-1] ) {
290 CYG_FAIL( "Oversize DHCP packet in set_variable_tag replace" );
295 *(op + len + 2) = TAG_END;
298 else { // overwrite the end tag and install a new one
299 if ( op + len + 2 > &ppkt->bp_vend[BP_VEND_LEN-1] ) {
300 CYG_FAIL( "Oversize DHCP packet in set_variable_tag append" );
305 *(op + len + 2) = TAG_END;
307 // and insert the value. No order is implied.
308 op += 2; // point to start of value
309 while ( len-- > 0 ) {
316 unset_tag( struct bootp *ppkt,
319 unsigned char *op, *nextp = 0, *killp = 0;
321 // Initially this will only scan the options field.
323 op = &ppkt->bp_vend[4];
324 while (*op != TAG_END) {
325 if ( op > &ppkt->bp_vend[BP_VEND_LEN-1] ) {
326 CYG_FAIL( "Oversize DHCP packet in unset_tag" );
329 if (*op == tag) { // Found it...
330 killp = op; // item to kill
331 nextp = op + *(op+1)+2; // next item address
333 if ( *op == TAG_PAD ) {
343 // Obliterate the found op by copying down: *op is the end.
344 while( nextp <= op ) // <= to copy the TAG_END too.
350 // ------------------------------------------------------------------------
351 // Bring up an interface enough to broadcast, before we know who we are
354 bring_half_up(const char *intf, struct ifreq *ifrp )
359 struct sockaddr_in *addrp;
360 struct ecos_rtentry route;
363 // Ensure clean slate
364 cyg_route_reinit(); // Force any existing routes to be forgotten
366 s = socket(AF_INET, SOCK_DGRAM, 0);
372 if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one))) {
373 perror("setsockopt");
377 addrp = (struct sockaddr_in *) &ifrp->ifr_addr;
378 memset(addrp, 0, sizeof(*addrp));
379 addrp->sin_family = AF_INET;
380 addrp->sin_len = sizeof(*addrp);
382 addrp->sin_addr.s_addr = INADDR_ANY;
384 strcpy(ifrp->ifr_name, intf);
385 if (ioctl(s, SIOCSIFADDR, ifrp)) { /* set ifnet address */
386 perror("SIOCSIFADDR");
390 if (ioctl(s, SIOCSIFNETMASK, ifrp)) { /* set net addr mask */
391 perror("SIOCSIFNETMASK");
395 /* the broadcast address is 255.255.255.255 */
396 memset(&addrp->sin_addr, 255, sizeof(addrp->sin_addr));
397 if (ioctl(s, SIOCSIFBRDADDR, ifrp)) { /* set broadcast addr */
398 perror("SIOCSIFBRDADDR");
402 ifrp->ifr_flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING;
403 if (ioctl(s, SIOCSIFFLAGS, ifrp)) { /* set ifnet flags */
404 perror("SIOCSIFFLAGS up");
408 if (ioctl(s, SIOCGIFHWADDR, ifrp) < 0) { /* get MAC address */
409 perror("SIOCGIFHWADDR 1");
414 addrp->sin_family = AF_INET;
416 addrp->sin_len = sizeof(*addrp); // Size of address
418 /* the broadcast address is 255.255.255.255 */
419 memset(&addrp->sin_addr, 255, sizeof(addrp->sin_addr));
420 memset(&route, 0, sizeof(route));
421 memcpy(&route.rt_gateway, addrp, sizeof(*addrp));
423 addrp->sin_addr.s_addr = INADDR_ANY;
424 memcpy(&route.rt_dst, addrp, sizeof(*addrp));
425 memcpy(&route.rt_genmask, addrp, sizeof(*addrp));
427 route.rt_dev = ifrp->ifr_name;
428 route.rt_flags = RTF_UP|RTF_GATEWAY;
431 if (ioctl(s, SIOCADDRT, &route)) { /* add route */
432 if (errno != EEXIST) {
433 perror("SIOCADDRT 3");
446 // ------------------------------------------------------------------------
447 // DHCP retransmission timeouts and number of tries
449 // To work better with simulated failures (or real ones!) so that the rest
450 // of the system is tested, rather than DHCP renewal failures pulling
451 // everything down, we try a little more zealously than the RFC suggests.
453 static unsigned char timeout_random = 0;
455 struct timeout_state {
460 static inline void reset_timeout( struct timeval *ptv, struct timeout_state *pstate )
463 pstate->countdown = 4; // initial fast retries
464 pstate->secs = 3 + (timeout_random & 3);
466 ptv->tv_usec = 65536 * (2 + (timeout_random & 3)); // 0.1 - 0.3S, about
469 static inline int next_timeout( struct timeval *ptv, struct timeout_state *pstate )
471 if ( 0 < pstate->countdown-- )
473 if ( 0 == ptv->tv_sec )
474 ptv->tv_sec = pstate->secs;
477 pstate->secs = ptv->tv_sec * 2 - 2 + (timeout_random & 3);
478 pstate->countdown = 2; // later fast retries
481 // If longer, too many tries...
482 return pstate->secs < CYGNUM_NET_DHCP_MIN_RETRY_TIME;
485 // ------------------------------------------------------------------------
486 // Lease expiry and alarms to notify it
488 static cyg_alarm_t alarm_function;
490 static void alarm_function(cyg_handle_t alarm, cyg_addrword_t data)
492 struct dhcp_lease *lease = (struct dhcp_lease *)data;
493 lease->which |= lease->next;
494 if ( lease->needs_attention )
495 cyg_semaphore_post( lease->needs_attention );
497 // Step the lease on into its next state of being alarmed ;-)
498 if ( lease->next & DHCP_LEASE_EX ) {
499 cyg_alarm_disable( alarm );
501 else if ( lease->next & DHCP_LEASE_T2 ) {
502 lease->next = DHCP_LEASE_EX;
503 cyg_alarm_initialize( lease->alarm, lease->expiry, 0 );
504 cyg_alarm_enable( lease->alarm );
506 else if ( lease->next & DHCP_LEASE_T1 ) {
507 lease->next = DHCP_LEASE_T2;
508 cyg_alarm_initialize( lease->alarm, lease->t2, 0 );
509 cyg_alarm_enable( lease->alarm );
513 static inline void no_lease( struct dhcp_lease *lease )
515 if ( lease->alarm ) {
516 // Already set: delete this.
517 cyg_alarm_disable( lease->alarm );
518 cyg_alarm_delete( lease->alarm );
523 static inline void new_lease( struct bootp *bootp, struct dhcp_lease *lease )
525 cyg_tick_count_t now = cyg_current_time();
526 cyg_tick_count_t then;
528 cyg_uint32 expiry_then;
529 cyg_resolution_t resolution =
530 cyg_clock_get_resolution(cyg_real_time_clock());
534 // Silence any jabbering from past lease on this interface
536 lease->which = lease->next = 0;
537 cyg_clock_to_counter(cyg_real_time_clock(), &h);
538 cyg_alarm_create( h, alarm_function, (cyg_addrword_t)lease,
539 &lease->alarm, &lease->alarm_obj );
541 // extract the lease time and scale it &c to now.
542 length = sizeof(tag);
543 if(!get_bootp_option( bootp, TAG_DHCP_LEASE_TIME, &tag ,&length))
546 if ( 0xffffffff == tag ) {
547 lease->expiry = 0xffffffff;
548 lease->t2 = 0xffffffff;
549 lease->t1 = 0xffffffff;
550 return; // it's an infinite lease, hurrah!
553 then = (cyg_uint64)(ntohl(tag));
556 then *= 1000000000; // into nS - we know there is room in a tick_count_t
557 then = (then / resolution.dividend) * resolution.divisor; // into system ticks
558 lease->expiry = now + then;
559 length = sizeof(tag);
560 if (get_bootp_option( bootp, TAG_DHCP_REBIND_TIME, &tag, &length ))
561 then = (cyg_uint64)(ntohl(tag));
563 then = expiry_then - expiry_then/4;
564 then *= 1000000000; // into nS - we know there is room in a tick_count_t
565 then = (then / resolution.dividend) * resolution.divisor; // into system ticks
566 lease->t2 = now + then;
568 length = sizeof(tag);
569 if (get_bootp_option( bootp, TAG_DHCP_RENEWAL_TIME, &tag, &length ))
570 then = (cyg_uint64)(ntohl(tag));
572 then = expiry_then/2;
573 then *= 1000000000; // into nS - we know there is room in a tick_count_t
574 then = (then / resolution.dividend) * resolution.divisor; // into system ticks
575 lease->t1 = now + then;
577 #if 0 // for testing this mechanism
578 lease->expiry = now + 5000; // 1000 here makes for failure in the DHCP test
579 lease->t2 = now + 3500;
580 lease->t1 = now + 2500;
583 #ifdef CYGDBG_NET_DHCP_CHATTER
584 diag_printf("new_lease:\n");
585 diag_printf(" expiry = %d\n",lease->expiry);
586 diag_printf(" t1 = %d\n",lease->t1);
587 diag_printf(" t2 = %d\n",lease->t2);
590 lease->next = DHCP_LEASE_T1;
592 cyg_alarm_initialize( lease->alarm, lease->t1, 0 );
593 cyg_alarm_enable( lease->alarm );
596 // ------------------------------------------------------------------------
597 // Set all the tags we want to use when sending a packet.
598 // This has expanded to a large, explicit set to interwork better
599 // with a variety of DHCP servers.
601 static void set_default_dhcp_tags( struct bootp *xmit )
603 // Explicitly request full set of params that are default for LINUX
604 // dhcp servers, but not default for others. This is rather arbitrary,
605 // but it preserves behaviour for people using those servers.
606 // Perhaps configury of this set will be needed in future?
609 static cyg_uint8 req_list[] = {
610 #ifdef CYGOPT_NET_DHCP_PARM_REQ_LIST_REPLACE
611 CYGOPT_NET_DHCP_PARM_REQ_LIST_REPLACE ,
613 TAG_DHCP_SERVER_ID , // DHCP server id: 10.16.19.66
614 TAG_DHCP_LEASE_TIME , // DHCP time 51: 60
615 TAG_DHCP_RENEWAL_TIME , // DHCP time 58: 30
616 TAG_DHCP_REBIND_TIME , // DHCP time 59: 52
617 TAG_SUBNET_MASK , // subnet mask: 255.255.255.0
618 TAG_GATEWAY , // gateway: 10.16.19.66
619 TAG_DOMAIN_SERVER , // domain server: 10.16.19.66
620 TAG_DOMAIN_NAME , // domain name: hmt10.cambridge.redhat.com
621 TAG_IP_BROADCAST , // IP broadcast: 10.16.19.255
623 #ifdef CYGNUM_NET_SNTP_UNICAST_MAXDHCP
624 TAG_NTP_SERVER , // NTP Server Addresses(es)
626 #ifdef CYGOPT_NET_DHCP_PARM_REQ_LIST_ADDITIONAL
627 CYGOPT_NET_DHCP_PARM_REQ_LIST_ADDITIONAL ,
631 if ( req_list[0] ) // So that one may easily turn it all off by configury
632 set_variable_tag( xmit, TAG_DHCP_PARM_REQ_LIST,
633 &req_list[0], sizeof( req_list ) );
635 #ifdef CYGOPT_NET_DHCP_OPTION_HOST_NAME
637 int nlen = strlen(dhcp_hostname);
640 set_variable_tag( xmit, TAG_HOST_NAME, dhcp_hostname, nlen + 1);
643 #ifdef CYGOPT_NET_DHCP_OPTION_DHCP_CLIENTID_MAC
645 cyg_uint8 id[16+1]; /* sizeof bp_chaddr[] + 1 */
647 id[0] = 1; /* 1-byte hardware type: 1=ethernet. */
648 CYG_ASSERT( xmit->bp_hlen<=(sizeof(id)-1), "HW address invalid" );
649 memcpy(&id[1], &xmit->bp_chaddr, xmit->bp_hlen);
650 set_variable_tag( xmit, TAG_DHCP_CLIENTID, id, xmit->bp_hlen+1);
654 // Explicitly specify our max message size.
655 set_fixed_tag( xmit, TAG_DHCP_MAX_MSGSZ, BP_MINPKTSZ, 2 );
658 // ------------------------------------------------------------------------
659 // the DHCP state machine - this does all the work
662 do_dhcp(const char *intf, struct bootp *res,
663 cyg_uint8 *pstate, struct dhcp_lease *lease)
666 struct sockaddr_in cli_addr, broadcast_addr, server_addr, rx_addr;
670 unsigned char mincookie[] = {99,130,83,99,255} ;
672 struct timeout_state timeout_scratch;
673 cyg_uint8 oldstate = *pstate;
674 cyg_uint8 msgtype = 0, seen_bootp_reply = 0;
679 #define CHECK_XID() ( /* and other details */ \
680 received->bp_xid != xid || /* not the same transaction */ \
681 received->bp_htype != xmit->bp_htype || /* not the same ESA type */ \
682 received->bp_hlen != xmit->bp_hlen || /* not the same length */ \
683 bcmp( &received->bp_chaddr, &xmit->bp_chaddr, xmit->bp_hlen ) \
686 // IMPORTANT: xmit is the same as res throughout this; *received is a
687 // scratch buffer for reception; its contents are always copied to res
688 // when we are happy with them. So we always transmit from the
690 struct bootp rx_local;
691 struct bootp *received = &rx_local;
692 struct bootp *xmit = res;
696 // First, get a socket on the interface in question. But Zeroth, if
697 // needs be, bring it to the half-up broadcast only state if needs be.
699 if ( DHCPSTATE_INIT == oldstate
700 || DHCPSTATE_FAILED == oldstate
702 // either explicit init state or the beginning of time or retry
703 if ( ! bring_half_up( intf, &ifr ) )
706 *pstate = DHCPSTATE_INIT;
707 lease->which = lease->next = 0;
710 s = socket(AF_INET, SOCK_DGRAM, 0);
716 if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one))) {
717 perror("setsockopt");
721 memset((char *) &cli_addr, 0, sizeof(cli_addr));
722 cli_addr.sin_family = AF_INET;
723 cli_addr.sin_len = sizeof(cli_addr);
724 cli_addr.sin_addr.s_addr = htonl(INADDR_ANY);
725 cli_addr.sin_port = htons(IPPORT_BOOTPC);
727 memset((char *) &broadcast_addr, 0, sizeof(broadcast_addr));
728 broadcast_addr.sin_family = AF_INET;
729 broadcast_addr.sin_len = sizeof(broadcast_addr);
730 broadcast_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
731 broadcast_addr.sin_port = htons(IPPORT_BOOTPS);
733 memset((char *) &server_addr, 0, sizeof(server_addr));
734 server_addr.sin_family = AF_INET;
735 server_addr.sin_len = sizeof(server_addr);
736 server_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST); // overwrite later
737 server_addr.sin_port = htons(IPPORT_BOOTPS);
739 if(bind(s, (struct sockaddr *) &cli_addr, sizeof(cli_addr)) < 0) {
740 perror("bind error");
743 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) {
744 perror("setsockopt SO_REUSEADDR");
747 if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one))) {
748 perror("setsockopt SO_REUSEPORT");
752 // Now, we can launch into the DHCP state machine. I think this will
753 // be the neatest way to do it; it returns from within the switch arms
754 // when all is well, or utterly failed.
756 reset_timeout( &tv, &timeout_scratch );
758 // Choose a new XID: first get the ESA as a basis:
759 strcpy(&ifr.ifr_name[0], intf);
760 if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0) {
761 perror("SIOCGIFHWADDR 2");
765 // Choose from scratch depending on ifr_hwaddr...[]
766 xid = ifr.ifr_hwaddr.sa_data[5];
767 xid |= (ifr.ifr_hwaddr.sa_data[4]) << 8;
768 xid |= (ifr.ifr_hwaddr.sa_data[3]) << 16;
769 xid |= (ifr.ifr_hwaddr.sa_data[2]) << 24;
770 xid ^= (cyg_arc4random() & 0xffff0000);
772 // Avoid adjacent ESAs colliding by increment
773 #define NEW_XID(_xid) CYG_MACRO_START (_xid)+= 0x10000; CYG_MACRO_END
777 // If we are active rather than in the process of shutting down,
778 // check for any lease expiry every time round, so that alarms
779 // *can* change the course of events even when already renewing,
781 if ( DHCPSTATE_DO_RELEASE != *pstate
782 && DHCPSTATE_NOTBOUND != *pstate
783 && DHCPSTATE_FAILED != *pstate ) {
784 cyg_uint8 lease_state;
786 cyg_scheduler_lock();
787 lease_state = lease->which;
788 lease->which = 0; // flag that we have noticed it
789 cyg_scheduler_unlock();
791 if ( lease_state & DHCP_LEASE_EX ) {
792 // then the lease has expired completely!
793 *pstate = DHCPSTATE_NOTBOUND;
795 else if ( lease_state & DHCP_LEASE_T2 ) {
797 reset_timeout( &tv, &timeout_scratch ); // next conversation
798 *pstate = DHCPSTATE_REBINDING;
800 else if ( lease_state & DHCP_LEASE_T1 ) {
802 reset_timeout( &tv, &timeout_scratch ); // next conversation
803 *pstate = DHCPSTATE_RENEWING;
811 // Send the DHCPDISCOVER packet
813 // Fill in the BOOTP request - DHCPDISCOVER packet
814 bzero(xmit, sizeof(*xmit));
815 xmit->bp_op = BOOTREQUEST;
816 xmit->bp_htype = HTYPE_ETHERNET;
817 xmit->bp_hlen = IFHWADDRLEN;
819 xmit->bp_secs = cyg_current_time() / 100;
820 xmit->bp_flags = htons(0x8000); // BROADCAST FLAG
821 bcopy(ifr.ifr_hwaddr.sa_data, &xmit->bp_chaddr, xmit->bp_hlen);
822 bcopy(mincookie, xmit->bp_vend, sizeof(mincookie));
824 // remove the next line to test ability to handle bootp packets.
825 set_fixed_tag( xmit, TAG_DHCP_MESS_TYPE, DHCPDISCOVER, 1 );
826 // Set all the tags we want to use when sending a packet
827 set_default_dhcp_tags( xmit );
829 #ifdef CYGDBG_NET_DHCP_CHATTER
830 diag_printf( "---------DHCPSTATE_INIT sending:\n" );
831 show_bootp( intf, xmit );
833 if(sendto(s, xmit, dhcp_size_for_send(xmit), 0,
834 (struct sockaddr *)&broadcast_addr, sizeof(broadcast_addr)) < 0) {
835 *pstate = DHCPSTATE_FAILED;
839 seen_bootp_reply = 0;
840 *pstate = DHCPSTATE_SELECTING;
843 case DHCPSTATE_SELECTING:
844 // This is a separate state so that we can listen again
845 // *without* retransmitting.
847 // listen for the DHCPOFFER reply
849 setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
851 addrlen = sizeof(rx_addr);
852 if (recvfrom(s, received, sizeof(struct bootp), 0,
853 (struct sockaddr *)&rx_addr, &addrlen) < 0) {
854 // No packet arrived (this time)
855 if ( seen_bootp_reply ) { // then already have a bootp reply
856 // Save the good packet in *xmit
857 bcopy( received, xmit, dhcp_size(received) );
858 *pstate = DHCPSTATE_BOOTP_FALLBACK;
859 NEW_XID( xid ); // Happy to advance, so new XID
860 reset_timeout( &tv, &timeout_scratch );
863 // go to the next larger timeout and re-send:
864 if ( ! next_timeout( &tv, &timeout_scratch ) ) {
865 *pstate = DHCPSTATE_FAILED;
868 *pstate = DHCPSTATE_INIT; // to retransmit
871 // Check for well-formed packet with correct termination (not truncated)
872 length = dhcp_size( received );
873 #ifdef CYGDBG_NET_DHCP_CHATTER
874 diag_printf( "---------DHCPSTATE_SELECTING received:\n" );
876 diag_printf( "WARNING! malformed or truncated packet\n" );
877 diag_printf( "...rx_addr is family %d, addr %08x, port %d\n",
879 rx_addr.sin_addr.s_addr,
881 show_bootp( intf, received );
885 if ( CHECK_XID() ) // XID and ESA matches?
886 break; // listen again...
888 if ( 0 == received->bp_siaddr.s_addr ) {
889 // then fill in from the options...
890 length = sizeof(received->bp_siaddr.s_addr);
891 get_bootp_option( received, TAG_DHCP_SERVER_ID,
892 &received->bp_siaddr.s_addr,
896 // see if it was a DHCP reply or a bootp reply; it could be
898 length = sizeof(msgtype);
899 if ( get_bootp_option( received, TAG_DHCP_MESS_TYPE, &msgtype,
901 if ( DHCPOFFER == msgtype ) { // all is well
902 // Save the good packet in *xmit
903 bcopy( received, xmit, dhcp_size(received) );
904 // we like the packet, so reset the timeout for next time
905 reset_timeout( &tv, &timeout_scratch );
906 *pstate = DHCPSTATE_REQUESTING;
907 NEW_XID( xid ); // Happy to advance, so new XID
910 else // No TAG_DHCP_MESS_TYPE entry so it's a bootp reply
911 seen_bootp_reply = 1; // (keep the bootp packet in received)
913 // If none of the above state changes occurred, we got a packet
914 // that "should not happen", OR we have a bootp reply in our
915 // hand; so listen again with the same timeout, without
916 // retrying the send, in the hope of getting a DHCP reply.
919 case DHCPSTATE_REQUESTING:
920 // Just send what you got with a DHCPREQUEST in the message type.
921 // then wait for an ACK in DHCPSTATE_REQUEST_RECV.
923 // Fill in the BOOTP request - DHCPREQUEST packet
925 xmit->bp_op = BOOTREQUEST;
926 xmit->bp_flags = htons(0x8000); // BROADCAST FLAG
928 set_fixed_tag( xmit, TAG_DHCP_MESS_TYPE, DHCPREQUEST, 1 );
929 // Set all the tags we want to use when sending a packet
930 set_default_dhcp_tags( xmit );
931 // And this will be a new one:
932 set_fixed_tag( xmit, TAG_DHCP_REQ_IP, ntohl(xmit->bp_yiaddr.s_addr), 4 );
934 #ifdef CYGDBG_NET_DHCP_CHATTER
935 diag_printf( "---------DHCPSTATE_REQUESTING sending:\n" );
936 show_bootp( intf, xmit );
938 // Send back a [modified] copy. Note that some fields are explicitly
939 // cleared, as per the RFC. We need the copy because these fields are
940 // still useful to us (and currently stored in the 'result' structure)
941 xlen = dhcp_size_for_send( xmit );
942 bcopy( xmit, &xmit2, xlen );
943 xmit2.bp_yiaddr.s_addr = xmit2.bp_siaddr.s_addr = xmit2.bp_giaddr.s_addr = 0;
945 if(sendto(s, &xmit2, xlen, 0,
946 (struct sockaddr *)&broadcast_addr, sizeof(broadcast_addr)) < 0) {
947 *pstate = DHCPSTATE_FAILED;
951 *pstate = DHCPSTATE_REQUEST_RECV;
954 case DHCPSTATE_REQUEST_RECV:
955 // wait for an ACK or a NACK - retry by going back to
956 // DHCPSTATE_REQUESTING; NACK means go back to INIT.
958 setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
960 addrlen = sizeof(rx_addr);
961 if (recvfrom(s, received, sizeof(struct bootp), 0,
962 (struct sockaddr *)&rx_addr, &addrlen) < 0) {
964 // go to the next larger timeout and re-send:
965 if ( ! next_timeout( &tv, &timeout_scratch ) ) {
966 *pstate = DHCPSTATE_FAILED;
969 *pstate = DHCPSTATE_REQUESTING;
972 // Check for well-formed packet with correct termination (not truncated)
973 length = dhcp_size( received );
974 #ifdef CYGDBG_NET_DHCP_CHATTER
975 diag_printf( "---------DHCPSTATE_REQUEST_RECV received:\n" );
977 diag_printf( "WARNING! malformed or truncated packet\n" );
978 diag_printf( "...rx_addr is family %d, addr %08x, port %d\n",
980 rx_addr.sin_addr.s_addr,
982 show_bootp( intf, received );
986 if ( CHECK_XID() ) // not the same transaction;
987 break; // listen again...
989 if ( 0 == received->bp_siaddr.s_addr ) {
990 // then fill in from the options...
991 length = sizeof(received->bp_siaddr.s_addr );
992 get_bootp_option( received, TAG_DHCP_SERVER_ID,
993 &received->bp_siaddr.s_addr,
997 // check it was a DHCP reply
998 length = sizeof(msgtype);
999 if ( get_bootp_option( received, TAG_DHCP_MESS_TYPE, &msgtype,
1001 if ( DHCPACK == msgtype // Same offer & server?
1002 && received->bp_yiaddr.s_addr == xmit->bp_yiaddr.s_addr
1003 && received->bp_siaddr.s_addr == xmit->bp_siaddr.s_addr) {
1004 // we like the packet, so reset the timeout for next time
1005 reset_timeout( &tv, &timeout_scratch );
1006 // Record the new lease and set up timers &c
1007 new_lease( received, lease );
1008 *pstate = DHCPSTATE_BOUND;
1011 if ( DHCPNAK == msgtype // Same server?
1012 && received->bp_siaddr.s_addr == xmit->bp_siaddr.s_addr) {
1014 *pstate = DHCPSTATE_INIT; // So back the start of the rigmarole.
1015 NEW_XID( xid ); // Unhappy to advance, so new XID
1016 reset_timeout( &tv, &timeout_scratch );
1019 // otherwise it's something else, maybe another offer, or a bogus
1020 // NAK from someone we are not asking!
1021 // Just listen again, which implicitly discards it.
1025 case DHCPSTATE_BOUND:
1027 // We are happy now, we have our address.
1029 // All done with socket
1033 // Re-initialize the interface with the new state
1034 if ( DHCPSTATE_BOUND != oldstate ) {
1035 // Then need to go down and up
1036 do_dhcp_down_net( intf, res, &oldstate, lease ); // oldstate used
1037 if ( 0 != oldstate ) {
1038 // Then not called from init_all_network_interfaces()
1039 // so we must initialize the interface ourselves
1040 if (!init_net(intf, res)) {
1041 do_dhcp_down_net( intf, res, pstate, lease );
1042 *pstate = DHCPSTATE_FAILED;
1048 // Otherwise, nothing whatsoever to do...
1051 case DHCPSTATE_RENEWING:
1052 // Just send what you got with a DHCPREQUEST in the message
1053 // type UNICAST straight to the server. Then wait for an ACK.
1055 // Fill in the BOOTP request - DHCPREQUEST packet
1057 xmit->bp_op = BOOTREQUEST;
1058 xmit->bp_flags = htons(0); // No BROADCAST FLAG
1059 // Use the *client* address here:
1060 xmit->bp_ciaddr.s_addr = xmit->bp_yiaddr.s_addr;
1062 set_fixed_tag( xmit, TAG_DHCP_MESS_TYPE, DHCPREQUEST, 1 );
1063 // These must not be set in this context
1064 unset_tag( xmit, TAG_DHCP_REQ_IP );
1065 unset_tag( xmit, TAG_DHCP_SERVER_ID );
1066 // Set all the tags we want to use when sending a packet
1067 set_default_dhcp_tags( xmit );
1069 // Set unicast address to *server*
1070 server_addr.sin_addr.s_addr = res->bp_siaddr.s_addr;
1072 #ifdef CYGDBG_NET_DHCP_CHATTER
1073 diag_printf( "---------DHCPSTATE_RENEWING sending:\n" );
1074 diag_printf( "UNICAST to family %d, addr %08x, port %d\n",
1075 server_addr.sin_family,
1076 server_addr.sin_addr.s_addr,
1077 server_addr.sin_port );
1078 show_bootp( intf, xmit );
1081 // Send back a [modified] copy. Note that some fields are explicitly
1082 // cleared, as per the RFC. We need the copy because these fields are
1083 // still useful to us (and currently stored in the 'result' structure)
1084 xlen = dhcp_size_for_send(xmit);
1085 bcopy( xmit, &xmit2, xlen );
1086 xmit2.bp_yiaddr.s_addr = xmit2.bp_siaddr.s_addr = xmit2.bp_giaddr.s_addr = 0;
1088 if(sendto(s, &xmit2, xlen, 0,
1089 // UNICAST address of the server:
1090 (struct sockaddr *)&server_addr,
1091 sizeof(server_addr)) < 0) {
1092 *pstate = DHCPSTATE_FAILED;
1096 *pstate = DHCPSTATE_RENEW_RECV;
1099 case DHCPSTATE_RENEW_RECV:
1100 // wait for an ACK or a NACK - retry by going back to
1101 // DHCPSTATE_RENEWING; NACK means go to NOTBOUND.
1102 // No answer means just wait for T2, to broadcast.
1104 setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
1106 addrlen = sizeof(rx_addr);
1107 if (recvfrom(s, received, sizeof(struct bootp), 0,
1108 (struct sockaddr *)&rx_addr, &addrlen) < 0) {
1109 // No packet arrived
1110 // go to the next larger timeout and re-send:
1111 if ( ! next_timeout( &tv, &timeout_scratch ) ) {
1112 // If we timed out completely, just give up until T2
1113 // expires - retain the lease meanwhile. The normal
1114 // lease mechanism will invoke REBINDING as and when
1116 *pstate = DHCPSTATE_BOUND;
1119 *pstate = DHCPSTATE_RENEWING;
1122 // Check for well-formed packet with correct termination (not truncated)
1123 length = dhcp_size( received );
1124 #ifdef CYGDBG_NET_DHCP_CHATTER
1125 diag_printf( "---------DHCPSTATE_RENEW_RECV received:\n" );
1127 diag_printf( "WARNING! malformed or truncated packet\n" );
1128 diag_printf( "...rx_addr is family %d, addr %08x, port %d\n",
1130 rx_addr.sin_addr.s_addr,
1132 show_bootp( intf, received );
1136 if ( CHECK_XID() ) // not the same transaction;
1137 break; // listen again...
1139 if ( 0 == received->bp_siaddr.s_addr ) {
1140 // then fill in from the options...
1141 length = sizeof(received->bp_siaddr.s_addr);
1142 get_bootp_option( received, TAG_DHCP_SERVER_ID,
1143 &received->bp_siaddr.s_addr,
1147 // check it was a DHCP reply
1148 length = sizeof(msgtype);
1149 if ( get_bootp_option( received, TAG_DHCP_MESS_TYPE, &msgtype,
1151 if ( DHCPACK == msgtype // Same offer?
1152 && received->bp_yiaddr.s_addr == xmit->bp_yiaddr.s_addr) {
1153 // we like the packet, so reset the timeout for next time
1154 reset_timeout( &tv, &timeout_scratch );
1155 // Record the new lease and set up timers &c
1156 new_lease( received, lease );
1157 *pstate = DHCPSTATE_BOUND;
1160 if ( DHCPNAK == msgtype ) { // we're bounced!
1161 *pstate = DHCPSTATE_NOTBOUND; // So quit out.
1164 // otherwise it's something else, maybe another offer.
1165 // Just listen again, which implicitly discards it.
1169 case DHCPSTATE_REBINDING:
1170 // Just send what you got with a DHCPREQUEST in the message type.
1171 // Then wait for an ACK. This one is BROADCAST.
1173 // Fill in the BOOTP request - DHCPREQUEST packet
1175 xmit->bp_op = BOOTREQUEST;
1176 xmit->bp_flags = htons(0); // no BROADCAST FLAG
1177 // Use the *client* address here:
1178 xmit->bp_ciaddr.s_addr = xmit->bp_yiaddr.s_addr;
1180 set_fixed_tag( xmit, TAG_DHCP_MESS_TYPE, DHCPREQUEST, 1 );
1181 // These must not be set in this context
1182 unset_tag( xmit, TAG_DHCP_REQ_IP );
1183 unset_tag( xmit, TAG_DHCP_SERVER_ID );
1184 // Set all the tags we want to use when sending a packet
1185 set_default_dhcp_tags( xmit );
1187 #ifdef CYGDBG_NET_DHCP_CHATTER
1188 diag_printf( "---------DHCPSTATE_REBINDING sending:\n" );
1189 show_bootp( intf, xmit );
1191 // Send back a [modified] copy. Note that some fields are explicitly
1192 // cleared, as per the RFC. We need the copy because these fields are
1193 // still useful to us (and currently stored in the 'result' structure)
1194 xlen = dhcp_size_for_send( xmit );
1195 bcopy( xmit, &xmit2, xlen );
1196 xmit2.bp_yiaddr.s_addr = xmit2.bp_siaddr.s_addr = xmit2.bp_giaddr.s_addr = 0;
1198 if(sendto(s, &xmit2, xlen, 0,
1199 (struct sockaddr *)&broadcast_addr, sizeof(broadcast_addr)) < 0) {
1200 *pstate = DHCPSTATE_FAILED;
1204 *pstate = DHCPSTATE_REBIND_RECV;
1207 case DHCPSTATE_REBIND_RECV:
1208 // wait for an ACK or a NACK - retry by going back to
1209 // DHCPSTATE_REBINDING; NACK means go to NOTBOUND.
1210 // No answer means just wait for expiry; we tried!
1212 setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
1214 addrlen = sizeof(rx_addr);
1215 if (recvfrom(s, received, sizeof(struct bootp), 0,
1216 (struct sockaddr *)&rx_addr, &addrlen) < 0) {
1217 // No packet arrived
1218 // go to the next larger timeout and re-send:
1219 if ( ! next_timeout( &tv, &timeout_scratch ) ) {
1220 // If we timed out completely, just give up until EX
1221 // expires - retain the lease meanwhile. The normal
1222 // lease mechanism will invoke NOTBOUND state as and
1224 *pstate = DHCPSTATE_BOUND;
1227 *pstate = DHCPSTATE_REBINDING;
1230 // Check for well-formed packet with correct termination (not truncated)
1231 length = dhcp_size( received );
1232 #ifdef CYGDBG_NET_DHCP_CHATTER
1233 diag_printf( "---------DHCPSTATE_REBIND_RECV received:\n" );
1235 diag_printf( "WARNING! malformed or truncated packet\n" );
1236 diag_printf( "...rx_addr is family %d, addr %08x, port %d\n",
1238 rx_addr.sin_addr.s_addr,
1240 show_bootp( intf, received );
1244 if ( CHECK_XID() ) // not the same transaction;
1245 break; // listen again...
1247 if ( 0 == received->bp_siaddr.s_addr ) {
1248 // then fill in from the options...
1249 unsigned int length = sizeof(received->bp_siaddr.s_addr );
1250 get_bootp_option( received, TAG_DHCP_SERVER_ID,
1251 &received->bp_siaddr.s_addr,
1255 // check it was a DHCP reply
1256 length = sizeof(msgtype);
1257 if ( get_bootp_option( received, TAG_DHCP_MESS_TYPE, &msgtype,
1259 if ( DHCPACK == msgtype // Same offer?
1260 && received->bp_yiaddr.s_addr == xmit->bp_yiaddr.s_addr) {
1261 // we like the packet, so reset the timeout for next time
1262 reset_timeout( &tv, &timeout_scratch );
1263 // Record the new lease and set up timers &c
1264 new_lease( received, lease );
1265 *pstate = DHCPSTATE_BOUND;
1268 else if ( DHCPNAK == msgtype ) { // we're bounced!
1269 *pstate = DHCPSTATE_NOTBOUND; // So back the start of the rigmarole.
1272 // otherwise it's something else, maybe another offer.
1273 // Just listen again, which implicitly discards it.
1277 case DHCPSTATE_BOOTP_FALLBACK:
1278 // All done with socket
1282 // And no lease should have become active, but JIC
1284 // Re-initialize the interface with the new state
1285 if ( DHCPSTATE_BOOTP_FALLBACK != oldstate ) {
1286 // Then need to go down and up
1287 do_dhcp_down_net( intf, res, &oldstate, lease ); // oldstate used
1288 if ( 0 != oldstate ) {
1289 // Then not called from init_all_network_interfaces()
1290 // so we must initialize the interface ourselves
1291 if (!init_net(intf, res)) {
1292 do_dhcp_down_net( intf, res, pstate, lease );
1293 *pstate = DHCPSTATE_FAILED;
1299 // Otherwise, nothing whatsoever to do...
1302 case DHCPSTATE_NOTBOUND:
1303 // All done with socket
1307 // Leave interface up so app can tidy.
1310 case DHCPSTATE_FAILED:
1311 // All done with socket
1315 // Unconditionally down the interface.
1316 do_dhcp_down_net( intf, res, &oldstate, lease );
1319 case DHCPSTATE_DO_RELEASE:
1320 // We have been forced here by external means, to release the
1321 // lease for graceful shutdown.
1323 // Just send what you got with a DHCPRELEASE in the message
1324 // type UNICAST straight to the server. No ACK. Then go to
1328 xmit->bp_op = BOOTREQUEST;
1329 xmit->bp_flags = htons(0); // no BROADCAST FLAG
1330 // Use the *client* address here:
1331 xmit->bp_ciaddr.s_addr = xmit->bp_yiaddr.s_addr;
1333 set_fixed_tag( xmit, TAG_DHCP_MESS_TYPE, DHCPRELEASE, 1 );
1335 // Set unicast address to *server*
1336 server_addr.sin_addr.s_addr = res->bp_siaddr.s_addr;
1338 #ifdef CYGDBG_NET_DHCP_CHATTER
1339 diag_printf( "---------DHCPSTATE_DO_RELEASE sending:\n" );
1340 diag_printf( "UNICAST to family %d, addr %08x, port %d\n",
1341 server_addr.sin_family,
1342 server_addr.sin_addr.s_addr,
1343 server_addr.sin_port );
1344 show_bootp( intf, xmit );
1346 // Send back a [modified] copy. Note that some fields are explicitly
1347 // cleared, as per the RFC. We need the copy because these fields are
1348 // still useful to us (and currently stored in the 'result' structure)
1349 xlen = dhcp_size_for_send( xmit );
1350 bcopy( xmit, &xmit2, xlen );
1351 xmit2.bp_yiaddr.s_addr = xmit2.bp_siaddr.s_addr = xmit2.bp_giaddr.s_addr = 0;
1353 if(sendto(s, &xmit2, xlen, 0,
1354 // UNICAST address of the server:
1355 (struct sockaddr *)&server_addr,
1356 sizeof(server_addr)) < 0) {
1357 *pstate = DHCPSTATE_FAILED;
1361 *pstate = DHCPSTATE_NOTBOUND;
1377 // ------------------------------------------------------------------------
1378 // Bring an interface down, failed to initialize it or lease is expired
1379 // Also part of normal startup, bring down for proper reinitialization
1382 do_dhcp_down_net(const char *intf, struct bootp *res,
1383 cyg_uint8 *pstate, struct dhcp_lease *lease)
1385 struct sockaddr_in *addrp;
1388 int retcode = false;
1390 // Ensure clean slate
1391 cyg_route_reinit(); // Force any existing routes to be forgotten
1393 s = socket(AF_INET, SOCK_DGRAM, 0);
1399 addrp = (struct sockaddr_in *) &ifr.ifr_addr;
1401 // Remove any existing address
1402 if ( DHCPSTATE_FAILED == *pstate
1403 || DHCPSTATE_INIT == *pstate
1405 // it was configured for broadcast only, "half-up"
1406 memset(addrp, 0, sizeof(*addrp));
1407 addrp->sin_family = AF_INET;
1408 addrp->sin_len = sizeof(*addrp);
1409 addrp->sin_port = 0;
1410 addrp->sin_addr.s_addr = INADDR_ANY;
1413 // get the specific address that was used
1414 strcpy(ifr.ifr_name, intf);
1415 if (ioctl(s, SIOCGIFADDR, &ifr)) {
1416 perror("SIOCGIFADDR 1");
1421 strcpy(ifr.ifr_name, intf);
1422 if (ioctl(s, SIOCDIFADDR, &ifr)) { /* delete IF addr */
1423 perror("SIOCDIFADDR1");
1429 struct if_laddrreq iflr;
1431 s6 = socket(AF_INET6, SOCK_DGRAM, 0);
1433 perror("socket AF_INET6");
1437 // Now delete the ipv6 addr
1438 memset(&iflr,0,sizeof(iflr));
1439 strcpy(iflr.iflr_name, intf);
1440 if (!ioctl(s6, SIOCGLIFADDR, &iflr)) {
1442 strcpy(iflr.iflr_name, intf);
1443 if (ioctl(s6, SIOCDLIFADDR, &ifr)) { /* delete IF addr */
1444 perror("SIOCDIFADDR_IN61");
1451 // Shut down interface so it can be reinitialized
1452 ifr.ifr_flags &= ~(IFF_UP | IFF_RUNNING);
1453 if (ioctl(s, SIOCSIFFLAGS, &ifr)) { /* set ifnet flags */
1454 perror("SIOCSIFFLAGS down");
1459 if ( 0 != *pstate ) // preserve initial state
1460 *pstate = DHCPSTATE_INIT;
1470 // ------------------------------------------------------------------------
1471 // Release (relinquish) a leased address - if we have one - and bring down
1474 do_dhcp_release(const char *intf, struct bootp *res,
1475 cyg_uint8 *pstate, struct dhcp_lease *lease)
1478 && DHCPSTATE_INIT != *pstate
1479 && DHCPSTATE_NOTBOUND != *pstate
1480 && DHCPSTATE_FAILED != *pstate
1481 && DHCPSTATE_BOOTP_FALLBACK != *pstate ) {
1482 *pstate = DHCPSTATE_DO_RELEASE;
1483 do_dhcp( intf, res, pstate, lease ); // to send the release packet
1484 cyg_thread_delay( 100 ); // to let it leave the building
1489 // ------------------------------------------------------------------------
1491 #endif // CYGPKG_NET_DHCP