Skip to content

Commit 12767d2

Browse files
committedSep 19, 2011
[dhcp] Use a random DHCP transaction identifier (xid)
iPXE currently uses the last four bytes of the MAC address as the DHCP transaction identifier. Reduce the probability of collisions by generating a random transaction identifier. Originally-implemented-by: Amos Kong <akong@redhat.com> Signed-off-by: Michael Brown <mcb30@ipxe.org>
1 parent 8b092f4 commit 12767d2

File tree

3 files changed

+36
-29
lines changed

3 files changed

+36
-29
lines changed
 

‎src/include/ipxe/dhcp.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -660,15 +660,18 @@ struct dhcphdr {
660660
/** Setting block name used for BootServerDHCP responses */
661661
#define PXEBS_SETTINGS_NAME "pxebs"
662662

663+
extern uint32_t dhcp_last_xid;
663664
extern unsigned int dhcp_chaddr ( struct net_device *netdev, void *chaddr,
664665
uint16_t *flags );
665666
extern int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
666667
struct net_device *netdev, uint8_t msgtype,
667-
const void *options, size_t options_len,
668-
void *data, size_t max_len );
668+
uint32_t xid, const void *options,
669+
size_t options_len, void *data,
670+
size_t max_len );
669671
extern int dhcp_create_request ( struct dhcp_packet *dhcppkt,
670672
struct net_device *netdev,
671-
unsigned int msgtype, struct in_addr ciaddr,
673+
unsigned int msgtype, uint32_t xid,
674+
struct in_addr ciaddr,
672675
void *data, size_t max_len );
673676
extern int start_dhcp ( struct interface *job, struct net_device *netdev );
674677
extern int start_pxebs ( struct interface *job, struct net_device *netdev,

‎src/net/fakedhcp.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,8 @@ int create_fakedhcpdiscover ( struct net_device *netdev,
114114
int rc;
115115

116116
if ( ( rc = dhcp_create_request ( &dhcppkt, netdev, DHCPDISCOVER,
117-
ciaddr, data, max_len ) ) != 0 ) {
117+
dhcp_last_xid, ciaddr, data,
118+
max_len ) ) != 0 ) {
118119
DBG ( "Could not create DHCPDISCOVER: %s\n",
119120
strerror ( rc ) );
120121
return rc;
@@ -139,7 +140,8 @@ int create_fakedhcpack ( struct net_device *netdev,
139140
int rc;
140141

141142
/* Create base DHCPACK packet */
142-
if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK, NULL, 0,
143+
if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK,
144+
dhcp_last_xid, NULL, 0,
143145
data, max_len ) ) != 0 ) {
144146
DBG ( "Could not create DHCPACK: %s\n", strerror ( rc ) );
145147
return rc;
@@ -190,7 +192,8 @@ int create_fakepxebsack ( struct net_device *netdev,
190192
}
191193

192194
/* Create base DHCPACK packet */
193-
if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK, NULL, 0,
195+
if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK,
196+
dhcp_last_xid, NULL, 0,
194197
data, max_len ) ) != 0 ) {
195198
DBG ( "Could not create PXE BS ACK: %s\n",
196199
strerror ( rc ) );

‎src/net/udp/dhcp.c

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,14 @@ struct setting use_cached_setting __setting ( SETTING_MISC ) = {
116116
.type = &setting_type_uint8,
117117
};
118118

119+
/**
120+
* Most recent DHCP transaction ID
121+
*
122+
* This is exposed for use by the fakedhcp code when reconstructing
123+
* DHCP packets for PXE NBPs.
124+
*/
125+
uint32_t dhcp_last_xid;
126+
119127
/**
120128
* Name a DHCP packet type
121129
*
@@ -137,23 +145,6 @@ static inline const char * dhcp_msgtype_name ( unsigned int msgtype ) {
137145
}
138146
}
139147

140-
/**
141-
* Calculate DHCP transaction ID for a network device
142-
*
143-
* @v netdev Network device
144-
* @ret xid DHCP XID
145-
*
146-
* Extract the least significant bits of the hardware address for use
147-
* as the transaction ID.
148-
*/
149-
static uint32_t dhcp_xid ( struct net_device *netdev ) {
150-
uint32_t xid;
151-
152-
memcpy ( &xid, ( netdev->ll_addr + netdev->ll_protocol->ll_addr_len
153-
- sizeof ( xid ) ), sizeof ( xid ) );
154-
return xid;
155-
}
156-
157148
/****************************************************************************
158149
*
159150
* DHCP session
@@ -219,6 +210,8 @@ struct dhcp_session {
219210
struct sockaddr_in local;
220211
/** State of the session */
221212
struct dhcp_session_state *state;
213+
/** Transaction ID (in network-endian order) */
214+
uint32_t xid;
222215

223216
/** Offered IP address */
224217
struct in_addr offer;
@@ -916,6 +909,7 @@ unsigned int dhcp_chaddr ( struct net_device *netdev, void *chaddr,
916909
* @v dhcppkt DHCP packet structure to fill in
917910
* @v netdev Network device
918911
* @v msgtype DHCP message type
912+
* @v xid Transaction ID (in network-endian order)
919913
* @v options Initial options to include (or NULL)
920914
* @v options_len Length of initial options
921915
* @v data Buffer for DHCP packet
@@ -927,7 +921,7 @@ unsigned int dhcp_chaddr ( struct net_device *netdev, void *chaddr,
927921
*/
928922
int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
929923
struct net_device *netdev, uint8_t msgtype,
930-
const void *options, size_t options_len,
924+
uint32_t xid, const void *options, size_t options_len,
931925
void *data, size_t max_len ) {
932926
struct dhcphdr *dhcphdr = data;
933927
int rc;
@@ -938,7 +932,7 @@ int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
938932

939933
/* Initialise DHCP packet content */
940934
memset ( dhcphdr, 0, max_len );
941-
dhcphdr->xid = dhcp_xid ( netdev );
935+
dhcphdr->xid = xid;
942936
dhcphdr->magic = htonl ( DHCP_MAGIC_COOKIE );
943937
dhcphdr->htype = ntohs ( netdev->ll_protocol->ll_proto );
944938
dhcphdr->op = dhcp_op[msgtype];
@@ -964,6 +958,7 @@ int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
964958
* @v dhcppkt DHCP packet structure to fill in
965959
* @v netdev Network device
966960
* @v msgtype DHCP message type
961+
* @v xid Transaction ID (in network-endian order)
967962
* @v ciaddr Client IP address
968963
* @v data Buffer for DHCP packet
969964
* @v max_len Size of DHCP packet buffer
@@ -974,7 +969,8 @@ int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
974969
*/
975970
int dhcp_create_request ( struct dhcp_packet *dhcppkt,
976971
struct net_device *netdev, unsigned int msgtype,
977-
struct in_addr ciaddr, void *data, size_t max_len ) {
972+
uint32_t xid, struct in_addr ciaddr,
973+
void *data, size_t max_len ) {
978974
struct dhcp_netdev_desc dhcp_desc;
979975
struct dhcp_client_id client_id;
980976
struct dhcp_client_uuid client_uuid;
@@ -985,7 +981,7 @@ int dhcp_create_request ( struct dhcp_packet *dhcppkt,
985981
int rc;
986982

987983
/* Create DHCP packet */
988-
if ( ( rc = dhcp_create_packet ( dhcppkt, netdev, msgtype,
984+
if ( ( rc = dhcp_create_packet ( dhcppkt, netdev, msgtype, xid,
989985
dhcp_request_options_data,
990986
sizeof ( dhcp_request_options_data ),
991987
data, max_len ) ) != 0 ) {
@@ -1099,7 +1095,8 @@ static int dhcp_tx ( struct dhcp_session *dhcp ) {
10991095

11001096
/* Create basic DHCP packet in temporary buffer */
11011097
if ( ( rc = dhcp_create_request ( &dhcppkt, dhcp->netdev, msgtype,
1102-
dhcp->local.sin_addr, iobuf->data,
1098+
dhcp->xid, dhcp->local.sin_addr,
1099+
iobuf->data,
11031100
iob_tailroom ( iobuf ) ) ) != 0 ) {
11041101
DBGC ( dhcp, "DHCP %p could not construct DHCP request: %s\n",
11051102
dhcp, strerror ( rc ) );
@@ -1187,7 +1184,7 @@ static int dhcp_deliver ( struct dhcp_session *dhcp,
11871184
&server_id, sizeof ( server_id ) );
11881185

11891186
/* Check for matching transaction ID */
1190-
if ( dhcphdr->xid != dhcp_xid ( dhcp->netdev ) ) {
1187+
if ( dhcphdr->xid != dhcp->xid ) {
11911188
DBGC ( dhcp, "DHCP %p %s from %s:%d has bad transaction "
11921189
"ID\n", dhcp, dhcp_msgtype_name ( msgtype ),
11931190
inet_ntoa ( peer->sin_addr ),
@@ -1311,6 +1308,10 @@ int start_dhcp ( struct interface *job, struct net_device *netdev ) {
13111308
dhcp->netdev = netdev_get ( netdev );
13121309
dhcp->local.sin_family = AF_INET;
13131310
dhcp->local.sin_port = htons ( BOOTPC_PORT );
1311+
dhcp->xid = random();
1312+
1313+
/* Store DHCP transaction ID for fakedhcp code */
1314+
dhcp_last_xid = dhcp->xid;
13141315

13151316
/* Instantiate child objects and attach to our interfaces */
13161317
if ( ( rc = xfer_open_socket ( &dhcp->xfer, SOCK_DGRAM, &dhcp_peer,

0 commit comments

Comments
 (0)