This is the mail archive of the
ecos-patches@sources.redhat.com
mailing list for the eCos project.
Tweak DHCP sends, and remove dhcp_copy
- From: Jonathan Larmour <jlarmour at redhat dot com>
- To: ecos-patches at sources dot redhat dot com
- Date: Thu, 4 Jul 2002 19:02:53 +0100
- Subject: Tweak DHCP sends, and remove dhcp_copy
Index: ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/common/current/ChangeLog,v
retrieving revision 1.6
diff -u -5 -p -r1.6 ChangeLog
--- ChangeLog 20 Jun 2002 22:05:58 -0000 1.6
+++ ChangeLog 4 Jul 2002 18:02:52 -0000
@@ -1,5 +1,12 @@
+2002-07-04 Jonathan Larmour <jlarmour@redhat.com>
+
+ * src/dhcp_prot.c (_dhcp_copy): Remove. Unnecessary as we can never
+ receive a packet longer than sizeof(struct bootp)
+ (do_dhcp): Also set giaddr to 0 before sends.
+ Verify length of received packets, especially to check for truncation.
+
2002-06-20 Gary Thomas <gary@chez-thomas.org>
* src/inet_ntop.c: Fix build error when used with newer compilers.
2002-06-05 Gary Thomas <gary@chez-thomas.org>
Index: src/dhcp_prot.c
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/common/current/src/dhcp_prot.c,v
retrieving revision 1.3
diff -u -5 -p -r1.3 dhcp_prot.c
--- src/dhcp_prot.c 5 Jun 2002 13:16:29 -0000 1.3
+++ src/dhcp_prot.c 4 Jul 2002 18:02:52 -0000
@@ -510,30 +510,10 @@ static void set_default_dhcp_tags( struc
// Explicitly specify our max message size.
set_fixed_tag( xmit, TAG_DHCP_MAX_MSGSZ, BP_MINPKTSZ, 2 );
}
-//
-// Make a copy of a BOOTP/DHCP record. Note that this can
-// be [somewhat] arbitrarily long, thus it needs to be allocated
-// dynamically. Reset certain fields within the record that are
-// supposed to only be returned by the server.
-//
-static struct bootp *
-_dhcp_copy(struct bootp *xmit, int xlen)
-{
- struct bootp *xmit2;
- xmit2 = (struct bootp *)cyg_net_malloc(xlen, 0, 0);
- if (xmit2) {
- bcopy(xmit, xmit2, xlen);
- xmit2->bp_yiaddr.s_addr = 0;
- xmit2->bp_siaddr.s_addr = 0;
- xmit2->bp_hops = 0;
- }
- return xmit2;
-}
-
// ------------------------------------------------------------------------
// the DHCP state machine - this does all the work
int
do_dhcp(const char *intf, struct bootp *res,
@@ -564,11 +544,11 @@ do_dhcp(const char *intf, struct bootp *
// when we are happy with them. So we always transmit from the
// existing state.
struct bootp rx_local;
struct bootp *received = &rx_local;
struct bootp *xmit = res;
- struct bootp *xmit2 = (struct bootp *)NULL;
+ struct bootp xmit2;
int xlen;
// First, get a socket on the interface in question. But Zeroth, if
// needs be, bring it to the half-up broadcast only state if needs be.
@@ -741,19 +721,24 @@ do_dhcp(const char *intf, struct bootp *
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...
@@ -805,17 +790,16 @@ do_dhcp(const char *intf, struct bootp *
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);
- if ((xmit2 = _dhcp_copy(xmit, xlen)) == (struct bootp *)NULL) {
- *pstate = DHCPSTATE_FAILED;
- break;
- }
- if(sendto(s, xmit2, xlen, 0,
+ // 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;
}
@@ -838,19 +822,24 @@ do_dhcp(const char *intf, struct bootp *
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...
@@ -945,15 +934,14 @@ do_dhcp(const char *intf, struct bootp *
// 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);
- if ((xmit2 = _dhcp_copy(xmit, xlen)) == (struct bootp *)NULL) {
- *pstate = DHCPSTATE_FAILED;
- break;
- }
- if(sendto(s, xmit2, xlen, 0,
+ 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;
@@ -983,19 +971,24 @@ do_dhcp(const char *intf, struct bootp *
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;
if ( CHECK_XID() ) // not the same transaction;
break; // listen again...
if ( 0 == received->bp_siaddr.s_addr ) {
// then fill in from the options...
@@ -1050,16 +1043,15 @@ do_dhcp(const char *intf, struct bootp *
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);
- if ((xmit2 = _dhcp_copy(xmit, xlen)) == (struct bootp *)NULL) {
- *pstate = DHCPSTATE_FAILED;
- break;
- }
- if(sendto(s, xmit2, xlen, 0,
+ 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;
}
@@ -1087,19 +1079,24 @@ do_dhcp(const char *intf, struct bootp *
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...
@@ -1199,16 +1196,15 @@ do_dhcp(const char *intf, struct bootp *
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);
- if ((xmit2 = _dhcp_copy(xmit, xlen)) == (struct bootp *)NULL) {
- *pstate = DHCPSTATE_FAILED;
- break;
- }
- if(sendto(s, xmit2, xlen, 0,
+ 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;
@@ -1219,15 +1215,10 @@ do_dhcp(const char *intf, struct bootp *
default:
no_lease( lease );
close(s);
return false;
- }
- // Clean up temporary buffer(s)
- if (xmit2) {
- cyg_net_free(xmit2, 0);
- xmit2 = (struct bootp *)NULL;
}
}
/* NOTREACHED */
return false;
}