Index: ecos/packages/net/common/current/ChangeLog =================================================================== RCS file: /cvs/ecos/ecos-opt/net/net/common/current/ChangeLog,v retrieving revision 1.86 diff -u -5 -p -r1.86 ChangeLog --- ecos/packages/net/common/current/ChangeLog 3 Jul 2009 12:40:25 -0000 1.86 +++ ecos/packages/net/common/current/ChangeLog 17 Sep 2009 23:00:48 -0000 @@ -1,5 +1,10 @@ +2009-09-17 Jay Foster + + * src/dhcp_prot.c (do_dhcp): Fix packet parsing for DHCP servers + that do not terminate the options with an END tag. + 2009-06-23 Rene Schipp von Branitz Nielsen * src/ifaddrs.c (getifaddrs): If socket() call for IPv6 fails, a stray pointer was freed. Index: ecos/packages/net/common/current/src/dhcp_prot.c =================================================================== RCS file: /cvs/ecos/ecos-opt/net/net/common/current/src/dhcp_prot.c,v retrieving revision 1.21 diff -u -5 -p -r1.21 dhcp_prot.c --- ecos/packages/net/common/current/src/dhcp_prot.c 29 Jan 2009 17:49:57 -0000 1.21 +++ ecos/packages/net/common/current/src/dhcp_prot.c 17 Sep 2009 23:00:49 -0000 @@ -669,11 +669,11 @@ do_dhcp(const char *intf, struct bootp * struct timeval tv; struct timeout_state timeout_scratch; cyg_uint8 oldstate = *pstate; cyg_uint8 msgtype = 0, seen_bootp_reply = 0; unsigned int length; - + int pktlen; cyg_uint32 xid; #define CHECK_XID() ( /* and other details */ \ received->bp_xid != xid || /* not the same transaction */ \ received->bp_htype != xmit->bp_htype || /* not the same ESA type */ \ @@ -845,12 +845,13 @@ do_dhcp(const char *intf, struct bootp * // 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) { + pktlen = recvfrom(s, received, sizeof(struct bootp), 0, + (struct sockaddr *)&rx_addr, &addrlen); + if (pktlen < 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; @@ -864,10 +865,17 @@ do_dhcp(const char *intf, struct bootp * break; } *pstate = DHCPSTATE_INIT; // to retransmit break; } + /* Some DHCP servers don't terminate the options list with + * an END tag. Append one if we can. + */ + if (pktlen < sizeof(struct bootp)) + { + ((unsigned char *)received)[pktlen] = TAG_END; + } // 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 ) @@ -954,21 +962,29 @@ do_dhcp(const char *intf, struct bootp * // 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) { + pktlen = recvfrom(s, received, sizeof(struct bootp), 0, + (struct sockaddr *)&rx_addr, &addrlen); + if (pktlen < 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; } + /* Some DHCP servers don't terminate the options list with + * an END tag. Append one if we can. + */ + if (pktlen < sizeof(struct bootp)) + { + ((unsigned char *)received)[pktlen] = TAG_END; + } // 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 ) @@ -1100,12 +1116,13 @@ do_dhcp(const char *intf, struct bootp * // 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) { + pktlen = recvfrom(s, received, sizeof(struct bootp), 0, + (struct sockaddr *)&rx_addr, &addrlen); + if (pktlen < 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 @@ -1115,10 +1132,17 @@ do_dhcp(const char *intf, struct bootp * break; } *pstate = DHCPSTATE_RENEWING; break; } + /* Some DHCP servers don't terminate the options list with + * an END tag. Append one if we can. + */ + if (pktlen < sizeof(struct bootp)) + { + ((unsigned char *)received)[pktlen] = TAG_END; + } // 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 ) @@ -1208,12 +1232,13 @@ do_dhcp(const char *intf, struct bootp * // 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) { + pktlen = recvfrom(s, received, sizeof(struct bootp), 0, + (struct sockaddr *)&rx_addr, &addrlen); + if (pktlen < 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 @@ -1223,10 +1248,17 @@ do_dhcp(const char *intf, struct bootp * break; } *pstate = DHCPSTATE_REBINDING; break; } + /* Some DHCP servers don't terminate the options list with + * an END tag. Append one if we can. + */ + if (pktlen < sizeof(struct bootp)) + { + ((unsigned char *)received)[pktlen] = TAG_END; + } // 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 )