?? dhcp_prot.c
字號:
reset_timeout( &tv, &timeout_scratch ); // next conversation
*pstate = DHCPSTATE_RENEWING;
}
}
switch ( *pstate )
{
case DHCPSTATE_INIT:
// Send the DHCPDISCOVER packet
// Fill in the BOOTP request - DHCPDISCOVER packet
bzero(xmit, sizeof(*xmit));
xmit->bp_op = BOOTREQUEST;
xmit->bp_htype = HTYPE_ETHERNET;
xmit->bp_hlen = IFHWADDRLEN;
xmit->bp_xid = xid;
xmit->bp_secs = 0;
#ifdef ORIG_DHCP_CODE
xmit->bp_flags = htons(0x8000); // BROADCAST FLAG
#else
xmit->bp_flags = htons(0x0000); // orig val did not work, no BCAST FLAG
#endif
bcopy(ifr.ifr_hwaddr.sa_data, &xmit->bp_chaddr, xmit->bp_hlen);
bcopy(mincookie, xmit->bp_vend, sizeof(mincookie));
// remove the next line to test ability to handle bootp packets.
set_fixed_tag( xmit, TAG_DHCP_MESS_TYPE, DHCPDISCOVER, 1 );
// 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_INIT sending:\n" );
show_bootp( intf, xmit );
#endif
if (sendto(s, xmit, dhcp_size_for_send(xmit), 0,
(struct sockaddr *)&broadcast_addr, sizeof(broadcast_addr)) < 0)
{
*pstate = DHCPSTATE_FAILED;
break;
}
seen_bootp_reply = 0;
*pstate = DHCPSTATE_SELECTING;
break;
case DHCPSTATE_SELECTING:
// This is a separate state so that we can listen again
// *without* retransmitting.
// listen for the DHCPOFFER reply
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 (this time)
if ( seen_bootp_reply )
{ // then already have a bootp reply
// Save the good packet in *xmit
bcopy( received, xmit, dhcp_size(received) );
*pstate = DHCPSTATE_BOOTP_FALLBACK;
NEW_XID( xid ); // Happy to advance, so new XID
reset_timeout( &tv, &timeout_scratch );
break;
}
// go to the next larger timeout and re-send:
if ( ! next_timeout( &tv, &timeout_scratch ) )
{
*pstate = DHCPSTATE_FAILED;
break;
}
*pstate = DHCPSTATE_INIT; // to retransmit
break;
}
// Check for well-formed packet with correct termination (not truncated)
length = dhcp_size( received );
#ifdef CYGDBG_NET_DHCP_CHATTER
diag_printf( "---------DHCPSTATE_SELECTING 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() ) // XID and ESA matches?
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);
}
// see if it was a DHCP reply or a bootp reply; it could be
// either.
length = sizeof(msgtype);
if ( get_bootp_option( received, TAG_DHCP_MESS_TYPE, &msgtype) )
{
if ( DHCPOFFER == msgtype )
{ // all is well
// Save the good packet in *xmit
bcopy( received, xmit, dhcp_size(received) );
// we like the packet, so reset the timeout for next time
reset_timeout( &tv, &timeout_scratch );
*pstate = DHCPSTATE_REQUESTING;
NEW_XID( xid ); // Happy to advance, so new XID
}
}
else // No TAG_DHCP_MESS_TYPE entry so it's a bootp reply
seen_bootp_reply = 1; // (keep the bootp packet in received)
// If none of the above state changes occurred, we got a packet
// that "should not happen", OR we have a bootp reply in our
// hand; so listen again with the same timeout, without
// retrying the send, in the hope of getting a DHCP reply.
break;
case DHCPSTATE_REQUESTING:
// Just send what you got with a DHCPREQUEST in the message type.
// then wait for an ACK in DHCPSTATE_REQUEST_RECV.
// Fill in the BOOTP request - DHCPREQUEST packet
xmit->bp_xid = xid;
xmit->bp_op = BOOTREQUEST;
#ifdef ORIG_DHCP_CODE
xmit->bp_flags = htons(0x8000); // BROADCAST FLAG
#else
xmit->bp_flags = htons(0x0000); // orig val did not work
#endif
set_fixed_tag( xmit, TAG_DHCP_MESS_TYPE, DHCPREQUEST, 1 );
// Set all the tags we want to use when sending a packet
set_default_dhcp_tags( xmit );
// And this will be a new one:
set_fixed_tag( xmit, TAG_DHCP_REQ_IP, ntohl(xmit->bp_yiaddr.s_addr), 4 );
#ifdef CYGDBG_NET_DHCP_CHATTER
diag_printf( "---------DHCPSTATE_REQUESTING 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_REQUEST_RECV;
break;
case DHCPSTATE_REQUEST_RECV:
// wait for an ACK or a NACK - retry by going back to
// DHCPSTATE_REQUESTING; NACK means go back to INIT.
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 ) )
{
*pstate = DHCPSTATE_FAILED;
break;
}
*pstate = DHCPSTATE_REQUESTING;
break;
}
// Check for well-formed packet with correct termination (not truncated)
length = dhcp_size( received );
#ifdef CYGDBG_NET_DHCP_CHATTER
diag_printf( "---------DHCPSTATE_REQUEST_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...
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 & server?
&& received->bp_yiaddr.s_addr == xmit->bp_yiaddr.s_addr
&& received->bp_siaddr.s_addr == xmit->bp_siaddr.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 // Same server?
&& received->bp_siaddr.s_addr == xmit->bp_siaddr.s_addr)
{
// we're bounced!
*pstate = DHCPSTATE_INIT; // So back the start of the rigmarole.
NEW_XID( xid ); // Unhappy to advance, so new XID
reset_timeout( &tv, &timeout_scratch );
break;
}
// otherwise it's something else, maybe another offer, or a bogus
// NAK from someone we are not asking!
// Just listen again, which implicitly discards it.
}
break;
case DHCPSTATE_BOUND:
// We are happy now, we have our address.
// All done with socket
close(s);
// Re-initialize the interface with the new state
if ( DHCPSTATE_BOUND != 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_RENEWING:
// Just send what you got with a DHCPREQUEST in the message
// type UNICAST straight to the server. Then wait for an ACK.
// 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 );
// Set unicast address to *server*
server_addr.sin_addr.s_addr = res->bp_siaddr.s_addr;
#ifdef CYGDBG_NET_DHCP_CHATTER
diag_printf( "---------DHCPSTATE_RENEWING 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_RENEW_RECV;
break;
case DHCPSTATE_RENEW_RECV:
// wait for an ACK or a NACK - retry by going back to
// DHCPSTATE_RENEWING; NACK means go to NOTBOUND.
// No answer means just wait for T2, to broadcast.
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 T2
// expires - retain the lease meanwhile. The normal
// lease mechanism will invoke REBINDING as and when
// necessary.
*pstate = DHCPSTATE_BOUND;
break;
}
*pstate = DHCPSTATE_RENEWING;
break;
}
// Check for well-formed packet with correct termination (not truncated)
length = dhcp_size( received );
#ifdef CYGDBG_NET_DHCP_CHATTER
diag_printf( "---------DHCPSTATE_RENEW_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;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -