?? dhcp_prot.c
字號:
if ( CHECK_XID() ) // not the same transaction;
break; // listen again...
if ( 0 == received->bp_siaddr.s_addr )
{
// then fill in from the options...
length = sizeof(received->bp_siaddr.s_addr);
get_bootp_option( received, TAG_DHCP_SERVER_ID,
&received->bp_siaddr.s_addr);
}
// check it was a DHCP reply
length = sizeof(msgtype);
if ( get_bootp_option( received, TAG_DHCP_MESS_TYPE, &msgtype) )
{
if ( DHCPACK == msgtype // Same offer?
&& received->bp_yiaddr.s_addr == xmit->bp_yiaddr.s_addr)
{
// we like the packet, so reset the timeout for next time
reset_timeout( &tv, &timeout_scratch );
// Record the new lease and set up timers &c
new_lease( received, lease );
*pstate = DHCPSTATE_BOUND;
break;
}
if ( DHCPNAK == msgtype )
{ // we're bounced!
*pstate = DHCPSTATE_NOTBOUND; // So quit out.
break;
}
// otherwise it's something else, maybe another offer.
// Just listen again, which implicitly discards it.
}
break;
case DHCPSTATE_REBINDING:
// Just send what you got with a DHCPREQUEST in the message type.
// Then wait for an ACK. This one is BROADCAST.
// Fill in the BOOTP request - DHCPREQUEST packet
xmit->bp_xid = xid;
xmit->bp_op = BOOTREQUEST;
xmit->bp_flags = htons(0); // no BROADCAST FLAG
// Use the *client* address here:
xmit->bp_ciaddr.s_addr = xmit->bp_yiaddr.s_addr;
set_fixed_tag( xmit, TAG_DHCP_MESS_TYPE, DHCPREQUEST, 1 );
// These must not be set in this context
unset_tag( xmit, TAG_DHCP_REQ_IP );
unset_tag( xmit, TAG_DHCP_SERVER_ID );
// Set all the tags we want to use when sending a packet
set_default_dhcp_tags( xmit );
#ifdef CYGDBG_NET_DHCP_CHATTER
diag_printf( "---------DHCPSTATE_REBINDING sending:\n" );
show_bootp( intf, xmit );
#endif
// Send back a [modified] copy. Note that some fields are explicitly
// cleared, as per the RFC. We need the copy because these fields are
// still useful to us (and currently stored in the 'result' structure)
xlen = dhcp_size_for_send( xmit );
bcopy( xmit, &xmit2, xlen );
xmit2.bp_yiaddr.s_addr = xmit2.bp_siaddr.s_addr = xmit2.bp_giaddr.s_addr = 0;
xmit2.bp_hops = 0;
if (sendto(s, &xmit2, xlen, 0,
(struct sockaddr *)&broadcast_addr, sizeof(broadcast_addr)) < 0)
{
*pstate = DHCPSTATE_FAILED;
break;
}
*pstate = DHCPSTATE_REBIND_RECV;
break;
case DHCPSTATE_REBIND_RECV:
// wait for an ACK or a NACK - retry by going back to
// DHCPSTATE_REBINDING; NACK means go to NOTBOUND.
// No answer means just wait for expiry; we tried!
setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
addrlen = sizeof(rx_addr);
if (recvfrom(s, received, sizeof(struct bootp), 0,
(struct sockaddr *)&rx_addr, &addrlen) < 0)
{
// No packet arrived
// go to the next larger timeout and re-send:
if ( ! next_timeout( &tv, &timeout_scratch ) )
{
// If we timed out completely, just give up until EX
// expires - retain the lease meanwhile. The normal
// lease mechanism will invoke NOTBOUND state as and
// when necessary.
*pstate = DHCPSTATE_BOUND;
break;
}
*pstate = DHCPSTATE_REBINDING;
break;
}
// Check for well-formed packet with correct termination (not truncated)
length = dhcp_size( received );
#ifdef CYGDBG_NET_DHCP_CHATTER
diag_printf( "---------DHCPSTATE_REBIND_RECV received:\n" );
if ( length <= 0 )
diag_printf( "WARNING! malformed or truncated packet\n" );
diag_printf( "...rx_addr is family %d, addr %08x, port %d\n",
rx_addr.sin_family,
rx_addr.sin_addr.s_addr,
rx_addr.sin_port );
show_bootp( intf, received );
#endif
if ( length <= 0 )
break;
if ( CHECK_XID() ) // not the same transaction;
break; // listen again...
if ( 0 == received->bp_siaddr.s_addr )
{
// then fill in from the options...
//int length = sizeof(received->bp_siaddr.s_addr );
get_bootp_option( received, TAG_DHCP_SERVER_ID,
&received->bp_siaddr.s_addr);
}
// check it was a DHCP reply
length = sizeof(msgtype);
if ( get_bootp_option( received, TAG_DHCP_MESS_TYPE, &msgtype) )
{
if ( DHCPACK == msgtype // Same offer?
&& received->bp_yiaddr.s_addr == xmit->bp_yiaddr.s_addr)
{
// we like the packet, so reset the timeout for next time
reset_timeout( &tv, &timeout_scratch );
// Record the new lease and set up timers &c
new_lease( received, lease );
*pstate = DHCPSTATE_BOUND;
break;
}
else if ( DHCPNAK == msgtype )
{ // we're bounced!
*pstate = DHCPSTATE_NOTBOUND; // So back the start of the rigmarole.
break;
}
// otherwise it's something else, maybe another offer.
// Just listen again, which implicitly discards it.
}
break;
case DHCPSTATE_BOOTP_FALLBACK:
// All done with socket
close(s);
// And no lease should have become active, but JIC
no_lease( lease );
// Re-initialize the interface with the new state
if ( DHCPSTATE_BOOTP_FALLBACK != oldstate )
{
// Then need to go down and up
do_dhcp_down_net( intf, res, &oldstate, lease ); // oldstate used
if ( 0 != oldstate )
{
// Then not called from init_all_network_interfaces()
// so we must initialize the interface ourselves
if (!init_net(intf, res))
{
do_dhcp_down_net( intf, res, pstate, lease );
*pstate = DHCPSTATE_FAILED;
return false;
}
}
}
// Otherwise, nothing whatsoever to do...
return true;
case DHCPSTATE_NOTBOUND:
// All done with socket
close(s);
// No lease active
no_lease( lease );
// Leave interface up so app can tidy.
return false;
case DHCPSTATE_FAILED:
// All done with socket
close(s);
// No lease active
no_lease( lease );
// Unconditionally down the interface.
do_dhcp_down_net( intf, res, &oldstate, lease );
return false;
case DHCPSTATE_DO_RELEASE:
// We have been forced here by external means, to release the
// lease for graceful shutdown.
// Just send what you got with a DHCPRELEASE in the message
// type UNICAST straight to the server. No ACK. Then go to
// NOTBOUND state.
NEW_XID( xid );
xmit->bp_xid = xid;
xmit->bp_op = BOOTREQUEST;
xmit->bp_flags = htons(0); // no BROADCAST FLAG
// Use the *client* address here:
xmit->bp_ciaddr.s_addr = xmit->bp_yiaddr.s_addr;
set_fixed_tag( xmit, TAG_DHCP_MESS_TYPE, DHCPRELEASE, 1 );
// Set unicast address to *server*
server_addr.sin_addr.s_addr = res->bp_siaddr.s_addr;
#ifdef CYGDBG_NET_DHCP_CHATTER
diag_printf( "---------DHCPSTATE_DO_RELEASE sending:\n" );
diag_printf( "UNICAST to family %d, addr %08x, port %d\n",
server_addr.sin_family,
server_addr.sin_addr.s_addr,
server_addr.sin_port );
show_bootp( intf, xmit );
#endif
// Send back a [modified] copy. Note that some fields are explicitly
// cleared, as per the RFC. We need the copy because these fields are
// still useful to us (and currently stored in the 'result' structure)
xlen = dhcp_size_for_send( xmit );
bcopy( xmit, &xmit2, xlen );
xmit2.bp_yiaddr.s_addr = xmit2.bp_siaddr.s_addr = xmit2.bp_giaddr.s_addr = 0;
xmit2.bp_hops = 0;
if (sendto(s, &xmit2, xlen, 0,
// UNICAST address of the server:
(struct sockaddr *)&server_addr,
sizeof(server_addr)) < 0)
{
*pstate = DHCPSTATE_FAILED;
break;
}
*pstate = DHCPSTATE_NOTBOUND;
break;
default:
no_lease( lease );
close(s);
return false;
}
}
/* NOTREACHED */
return false;
}
// ------------------------------------------------------------------------
// Bring an interface down, failed to initialize it or lease is expired
// Also part of normal startup, bring down for proper reinitialization
int
do_dhcp_down_net(const char *intf, struct bootp *res,
cyg_uint8 *pstate, struct dhcp_lease *lease)
{
struct sockaddr_in *addrp;
struct ifreq ifr;
int s;
// Ensure clean slate
route_reinit(); // Force any existing routes to be forgotten
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0)
{
perror("socket");
return false;
}
addrp = (struct sockaddr_in *) &ifr.ifr_addr;
// Remove any existing address
if ( DHCPSTATE_FAILED == *pstate
|| DHCPSTATE_INIT == *pstate
|| 0 == *pstate )
{
// it was configured for broadcast only, "half-up"
memset(addrp, 0, sizeof(*addrp));
addrp->sin_family = AF_INET;
addrp->sin_len = sizeof(*addrp);
addrp->sin_port = 0;
addrp->sin_addr.s_addr = INADDR_ANY;
}
else
{
// get the specific address that was used
strcpy(ifr.ifr_name, intf);
if (ioctl(s, SIOCGIFADDR, &ifr))
{
perror("SIOCGIFADDR 1");
return false;
}
}
strcpy(ifr.ifr_name, intf);
if (ioctl(s, SIOCDIFADDR, &ifr))
{ /* delete IF addr */
perror("SIOCDIFADDR1");
}
#ifdef INET6
{
int s6;
s6 = socket(AF_INET6, SOCK_DGRAM, 0);
if (s6 < 0)
{
perror("socket AF_INET6");
return false;
}
// Now delete the ipv6 addr
strcpy(ifr.ifr_name, intf);
if (ioctl(s6, SIOCGLIFADDR, &ifr))
{
perror("SIOCGIFADDR_IN6 1");
return false;
}
strcpy(ifr.ifr_name, intf);
if (ioctl(s6, SIOCDLIFADDR, &ifr))
{ /* delete IF addr */
perror("SIOCDIFADDR_IN61");
}
close(s6);
}
#endif /* IP6 */
// Shut down interface so it can be reinitialized
ifr.ifr_flags &= ~(IFF_UP | IFF_RUNNING);
if (ioctl(s, SIOCSIFFLAGS, &ifr))
{ /* set ifnet flags */
perror("SIOCSIFFLAGS down");
return false;
}
// All done with socket
close(s);
if ( 0 != *pstate ) // preserve initial state
*pstate = DHCPSTATE_INIT;
return true;
}
// ------------------------------------------------------------------------
// Release (relinquish) a leased address - if we have one - and bring down
// the interface.
int
do_dhcp_release(const char *intf, struct bootp *res,
cyg_uint8 *pstate, struct dhcp_lease *lease)
{
if ( 0 != *pstate
&& DHCPSTATE_INIT != *pstate
&& DHCPSTATE_NOTBOUND != *pstate
&& DHCPSTATE_FAILED != *pstate
&& DHCPSTATE_BOOTP_FALLBACK != *pstate )
{
*pstate = DHCPSTATE_DO_RELEASE;
do_dhcp( intf, res, pstate, lease ); // to send the release packet
cyg_thread_delay( 100 ); // to let it leave the building
}
return true;
}
// ------------------------------------------------------------------------
#endif // CYGPKG_NET_DHCP
// EOF dhcp_prot.c
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -