mirror of https://github.com/ipxe/ipxe.git
Update DHCP to use data-xfer interface (not yet tested).
parent
f77815f2b1
commit
07dc294de8
|
@ -194,7 +194,7 @@ int nvo_register ( struct nvo_block *nvo ) {
|
|||
return 0;
|
||||
|
||||
err:
|
||||
free_dhcp_options ( nvo->options );
|
||||
dhcpopt_put ( nvo->options );
|
||||
nvo->options = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
@ -208,7 +208,7 @@ void nvo_unregister ( struct nvo_block *nvo ) {
|
|||
|
||||
if ( nvo->options ) {
|
||||
unregister_dhcp_options ( nvo->options );
|
||||
free_dhcp_options ( nvo->options );
|
||||
dhcpopt_put ( nvo->options );
|
||||
nvo->options = NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,9 +10,10 @@
|
|||
#include <stdint.h>
|
||||
#include <gpxe/list.h>
|
||||
#include <gpxe/in.h>
|
||||
#include <gpxe/udp.h>
|
||||
#include <gpxe/async.h>
|
||||
#include <gpxe/retry.h>
|
||||
#include <gpxe/refcnt.h>
|
||||
|
||||
struct net_device;
|
||||
struct job_interface;
|
||||
|
||||
/** BOOTP/DHCP server port */
|
||||
#define BOOTPS_PORT 67
|
||||
|
@ -312,6 +313,8 @@ struct dhcp_option {
|
|||
|
||||
/** A DHCP options block */
|
||||
struct dhcp_option_block {
|
||||
/** Reference counter */
|
||||
struct refcnt refcnt;
|
||||
/** List of option blocks */
|
||||
struct list_head list;
|
||||
/** Option block raw data */
|
||||
|
@ -413,6 +416,13 @@ struct dhcphdr {
|
|||
/** DHCP magic cookie */
|
||||
#define DHCP_MAGIC_COOKIE 0x63825363UL
|
||||
|
||||
/** DHCP minimum packet length
|
||||
*
|
||||
* This is the mandated minimum packet length that a DHCP participant
|
||||
* must be prepared to receive.
|
||||
*/
|
||||
#define DHCP_MIN_LEN 552
|
||||
|
||||
/** DHCP packet option block fill order
|
||||
*
|
||||
* This is the order in which option blocks are filled when
|
||||
|
@ -448,30 +458,27 @@ struct dhcp_packet {
|
|||
struct dhcp_option_block options[NUM_OPT_BLOCKS];
|
||||
};
|
||||
|
||||
struct udp_connection {};
|
||||
/**
|
||||
* Get reference to DHCP options block
|
||||
*
|
||||
* @v options DHCP options block
|
||||
* @ret options DHCP options block
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) struct dhcp_option_block *
|
||||
dhcpopt_get ( struct dhcp_option_block *options ) {
|
||||
ref_get ( &options->refcnt );
|
||||
return options;
|
||||
}
|
||||
|
||||
/** A DHCP session */
|
||||
struct dhcp_session {
|
||||
/** UDP connection for this session */
|
||||
struct udp_connection udp;
|
||||
|
||||
/** Network device being configured */
|
||||
struct net_device *netdev;
|
||||
|
||||
/** Options obtained from server */
|
||||
struct dhcp_option_block *options;
|
||||
|
||||
/** State of the session
|
||||
*
|
||||
* This is a value for the @c DHCP_MESSAGE_TYPE option
|
||||
* (e.g. @c DHCPDISCOVER).
|
||||
*/
|
||||
int state;
|
||||
/** Asynchronous operation for this DHCP session */
|
||||
struct async async;
|
||||
/** Retransmission timer */
|
||||
struct retry_timer timer;
|
||||
};
|
||||
/**
|
||||
* Drop reference to DHCP options block
|
||||
*
|
||||
* @v options DHCP options block
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
dhcpopt_put ( struct dhcp_option_block *options ) {
|
||||
ref_put ( &options->refcnt );
|
||||
}
|
||||
|
||||
extern unsigned long dhcp_num_option ( struct dhcp_option *option );
|
||||
extern void dhcp_ipv4_option ( struct dhcp_option *option,
|
||||
|
@ -485,7 +492,6 @@ extern void unregister_dhcp_options ( struct dhcp_option_block *options );
|
|||
extern void init_dhcp_options ( struct dhcp_option_block *options,
|
||||
void *data, size_t max_len );
|
||||
extern struct dhcp_option_block * alloc_dhcp_options ( size_t max_len );
|
||||
extern void free_dhcp_options ( struct dhcp_option_block *options );
|
||||
extern struct dhcp_option *
|
||||
set_dhcp_option ( struct dhcp_option_block *options, unsigned int tag,
|
||||
const void *data, size_t len );
|
||||
|
@ -506,6 +512,7 @@ extern int create_dhcp_packet ( struct net_device *netdev, uint8_t msgtype,
|
|||
struct dhcp_packet *dhcppkt );
|
||||
extern int copy_dhcp_packet_options ( struct dhcp_packet *dhcppkt,
|
||||
struct dhcp_option_block *options );
|
||||
extern int start_dhcp ( struct dhcp_session *dhcp, struct async *parent );
|
||||
extern int start_dhcp ( struct job_interface *job, struct net_device *netdev,
|
||||
int (*register_options) ( struct dhcp_option_block * ));
|
||||
|
||||
#endif /* _GPXE_DHCP_H */
|
||||
|
|
|
@ -115,6 +115,8 @@ struct xfer_metadata {
|
|||
struct sockaddr *src;
|
||||
/** Destination socket address, or NULL */
|
||||
struct sockaddr *dest;
|
||||
/** Network device, or NULL */
|
||||
struct net_device *netdev;
|
||||
};
|
||||
|
||||
/** Basis positions for seek() events */
|
||||
|
|
|
@ -280,6 +280,7 @@ void register_dhcp_options ( struct dhcp_option_block *options ) {
|
|||
if ( options->priority > existing->priority )
|
||||
break;
|
||||
}
|
||||
dhcpopt_get ( options );
|
||||
list_add_tail ( &options->list, &existing->list );
|
||||
}
|
||||
|
||||
|
@ -290,6 +291,7 @@ void register_dhcp_options ( struct dhcp_option_block *options ) {
|
|||
*/
|
||||
void unregister_dhcp_options ( struct dhcp_option_block *options ) {
|
||||
list_del ( &options->list );
|
||||
dhcpopt_put ( options );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -337,15 +339,6 @@ struct dhcp_option_block * alloc_dhcp_options ( size_t max_len ) {
|
|||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free DHCP options block
|
||||
*
|
||||
* @v options DHCP option block
|
||||
*/
|
||||
void free_dhcp_options ( struct dhcp_option_block *options ) {
|
||||
free ( options );
|
||||
}
|
||||
|
||||
/**
|
||||
* Resize a DHCP option
|
||||
*
|
||||
|
|
|
@ -183,17 +183,16 @@ static void udp_close ( struct udp_connection *udp, int rc ) {
|
|||
* @v iobuf I/O buffer
|
||||
* @v src_port Source port, or 0 to use default
|
||||
* @v dest Destination address, or NULL to use default
|
||||
* @v netdev Network device, or NULL to use default
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int udp_tx ( struct udp_connection *udp, struct io_buffer *iobuf,
|
||||
unsigned int src_port, struct sockaddr_tcpip *dest ) {
|
||||
unsigned int src_port, struct sockaddr_tcpip *dest,
|
||||
struct net_device *netdev ) {
|
||||
struct udp_header *udphdr;
|
||||
struct net_device *netdev = NULL;
|
||||
size_t len;
|
||||
int rc;
|
||||
|
||||
#warning "netdev?"
|
||||
|
||||
/* Check we can accommodate the header */
|
||||
if ( ( rc = iob_ensure_headroom ( iobuf, UDP_MAX_HLEN ) ) != 0 ) {
|
||||
free_iob ( iobuf );
|
||||
|
@ -394,6 +393,7 @@ static int udp_xfer_deliver_iob ( struct xfer_interface *xfer,
|
|||
container_of ( xfer, struct udp_connection, xfer );
|
||||
struct sockaddr_tcpip *src;
|
||||
struct sockaddr_tcpip *dest = NULL;
|
||||
struct net_device *netdev = NULL;
|
||||
unsigned int src_port = 0;
|
||||
|
||||
/* Apply xfer metadata */
|
||||
|
@ -402,10 +402,11 @@ static int udp_xfer_deliver_iob ( struct xfer_interface *xfer,
|
|||
if ( src )
|
||||
src_port = src->st_port;
|
||||
dest = ( struct sockaddr_tcpip * ) meta->dest;
|
||||
netdev = meta->netdev;
|
||||
}
|
||||
|
||||
/* Transmit data, if possible */
|
||||
udp_tx ( udp, iobuf, src_port, dest );
|
||||
udp_tx ( udp, iobuf, src_port, dest, netdev );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -17,12 +17,16 @@
|
|||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <byteswap.h>
|
||||
#include <gpxe/if_ether.h>
|
||||
#include <gpxe/netdevice.h>
|
||||
#include <gpxe/udp.h>
|
||||
#include <gpxe/xfer.h>
|
||||
#include <gpxe/open.h>
|
||||
#include <gpxe/job.h>
|
||||
#include <gpxe/retry.h>
|
||||
#include <gpxe/dhcp.h>
|
||||
|
||||
/** @file
|
||||
|
@ -387,7 +391,6 @@ static void merge_dhcp_field ( struct dhcp_option_block *options,
|
|||
/**
|
||||
* Parse DHCP packet and construct DHCP options block
|
||||
*
|
||||
* @v dhcp DHCP session
|
||||
* @v dhcphdr DHCP packet
|
||||
* @v len Length of DHCP packet
|
||||
* @ret options DHCP options block, or NULL
|
||||
|
@ -407,8 +410,7 @@ static void merge_dhcp_field ( struct dhcp_option_block *options,
|
|||
* options block; it is the responsibility of the caller to eventually
|
||||
* free this memory.
|
||||
*/
|
||||
static struct dhcp_option_block * dhcp_parse ( struct dhcp_session *dhcp,
|
||||
struct dhcphdr *dhcphdr,
|
||||
static struct dhcp_option_block * dhcp_parse ( const struct dhcphdr *dhcphdr,
|
||||
size_t len ) {
|
||||
struct dhcp_option_block *options;
|
||||
size_t options_len;
|
||||
|
@ -443,8 +445,8 @@ static struct dhcp_option_block * dhcp_parse ( struct dhcp_session *dhcp,
|
|||
/* Allocate empty options block of required size */
|
||||
options = alloc_dhcp_options ( options_len );
|
||||
if ( ! options ) {
|
||||
DBGC ( dhcp, "DHCP %p could not allocate %d-byte option "
|
||||
"block\n", dhcp, options_len );
|
||||
DBG ( "DHCP could not allocate %d-byte option block\n",
|
||||
options_len );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -488,12 +490,45 @@ static struct dhcp_option_block * dhcp_parse ( struct dhcp_session *dhcp,
|
|||
*
|
||||
*/
|
||||
|
||||
static inline struct dhcp_session *
|
||||
udp_to_dhcp ( struct udp_connection *conn ) {
|
||||
return container_of ( conn, struct dhcp_session, udp );
|
||||
}
|
||||
/** A DHCP session */
|
||||
struct dhcp_session {
|
||||
/** Reference counter */
|
||||
struct refcnt refcnt;
|
||||
/** Job control interface */
|
||||
struct job_interface job;
|
||||
/** Data transfer interface */
|
||||
struct xfer_interface xfer;
|
||||
|
||||
#if 0
|
||||
/** Network device being configured */
|
||||
struct net_device *netdev;
|
||||
/** Option block registration routine */
|
||||
int ( * register_options ) ( struct dhcp_option_block *options );
|
||||
|
||||
/** State of the session
|
||||
*
|
||||
* This is a value for the @c DHCP_MESSAGE_TYPE option
|
||||
* (e.g. @c DHCPDISCOVER).
|
||||
*/
|
||||
int state;
|
||||
/** Options obtained from server */
|
||||
struct dhcp_option_block *options;
|
||||
/** Retransmission timer */
|
||||
struct retry_timer timer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Free DHCP session
|
||||
*
|
||||
* @v refcnt Reference counter
|
||||
*/
|
||||
static void dhcp_free ( struct refcnt *refcnt ) {
|
||||
struct dhcp_session *dhcp =
|
||||
container_of ( refcnt, struct dhcp_session, refcnt );
|
||||
|
||||
netdev_put ( dhcp->netdev );
|
||||
dhcpopt_put ( dhcp->options );
|
||||
free ( dhcp );
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark DHCP session as complete
|
||||
|
@ -501,50 +536,38 @@ udp_to_dhcp ( struct udp_connection *conn ) {
|
|||
* @v dhcp DHCP session
|
||||
* @v rc Return status code
|
||||
*/
|
||||
static void dhcp_done ( struct dhcp_session *dhcp, int rc ) {
|
||||
static void dhcp_finished ( struct dhcp_session *dhcp, int rc ) {
|
||||
|
||||
/* Free up options if we failed */
|
||||
if ( rc != 0 ) {
|
||||
if ( dhcp->options ) {
|
||||
free_dhcp_options ( dhcp->options );
|
||||
dhcp->options = NULL;
|
||||
}
|
||||
}
|
||||
/* Block futher incoming messages */
|
||||
job_nullify ( &dhcp->job );
|
||||
xfer_nullify ( &dhcp->xfer );
|
||||
|
||||
/* Stop retry timer */
|
||||
stop_timer ( &dhcp->timer );
|
||||
|
||||
/* Close UDP connection */
|
||||
udp_close ( &dhcp->udp );
|
||||
|
||||
/* Mark async operation as complete */
|
||||
async_done ( &dhcp->async, rc );
|
||||
/* Free resources and close interfaces */
|
||||
xfer_close ( &dhcp->xfer, rc );
|
||||
job_done ( &dhcp->job, rc );
|
||||
}
|
||||
|
||||
/** Address for transmitting DHCP requests */
|
||||
static union {
|
||||
struct sockaddr_tcpip st;
|
||||
struct sockaddr_in sin;
|
||||
} sa_dhcp_server = {
|
||||
.sin = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_addr.s_addr = INADDR_BROADCAST,
|
||||
.sin_port = htons ( BOOTPS_PORT ),
|
||||
},
|
||||
};
|
||||
/****************************************************************************
|
||||
*
|
||||
* Data transfer interface
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Transmit DHCP request
|
||||
*
|
||||
* @v conn UDP connection
|
||||
* @v buf Temporary data buffer
|
||||
* @v len Length of temporary data buffer
|
||||
* @v dhcp DHCP session
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int dhcp_senddata ( struct udp_connection *conn,
|
||||
void *buf, size_t len ) {
|
||||
struct dhcp_session *dhcp = udp_to_dhcp ( conn );
|
||||
static int dhcp_send_request ( struct dhcp_session *dhcp ) {
|
||||
struct xfer_metadata meta = {
|
||||
.netdev = dhcp->netdev,
|
||||
};
|
||||
struct dhcp_packet dhcppkt;
|
||||
struct io_buffer *iobuf;
|
||||
int rc;
|
||||
|
||||
DBGC ( dhcp, "DHCP %p transmitting %s\n",
|
||||
|
@ -553,12 +576,23 @@ static int dhcp_senddata ( struct udp_connection *conn,
|
|||
assert ( ( dhcp->state == DHCPDISCOVER ) ||
|
||||
( dhcp->state == DHCPREQUEST ) );
|
||||
|
||||
/* Start retry timer. Do this first so that failures to
|
||||
* transmit will be retried.
|
||||
*/
|
||||
start_timer ( &dhcp->timer );
|
||||
|
||||
/* Allocate buffer for packet */
|
||||
iobuf = xfer_alloc_iob ( &dhcp->xfer, DHCP_MIN_LEN );
|
||||
if ( ! iobuf )
|
||||
return -ENOMEM;
|
||||
|
||||
/* Create DHCP packet in temporary buffer */
|
||||
if ( ( rc = create_dhcp_packet ( dhcp->netdev, dhcp->state, buf, len,
|
||||
if ( ( rc = create_dhcp_packet ( dhcp->netdev, dhcp->state,
|
||||
iobuf->data, iob_tailroom ( iobuf ),
|
||||
&dhcppkt ) ) != 0 ) {
|
||||
DBGC ( dhcp, "DHCP %p could not create DHCP packet: %s\n",
|
||||
dhcp, strerror ( rc ) );
|
||||
return rc;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Copy in options common to all requests */
|
||||
|
@ -566,7 +600,7 @@ static int dhcp_senddata ( struct udp_connection *conn,
|
|||
&dhcp_request_options ) ) != 0){
|
||||
DBGC ( dhcp, "DHCP %p could not set common DHCP options: %s\n",
|
||||
dhcp, strerror ( rc ) );
|
||||
return rc;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Copy any required options from previous server repsonse */
|
||||
|
@ -576,36 +610,30 @@ static int dhcp_senddata ( struct udp_connection *conn,
|
|||
DHCP_SERVER_IDENTIFIER ) ) != 0 ) {
|
||||
DBGC ( dhcp, "DHCP %p could not set server identifier "
|
||||
"option: %s\n", dhcp, strerror ( rc ) );
|
||||
return rc;
|
||||
goto done;
|
||||
}
|
||||
if ( ( rc = copy_dhcp_packet_option ( &dhcppkt, dhcp->options,
|
||||
DHCP_EB_YIADDR,
|
||||
DHCP_REQUESTED_ADDRESS ) ) != 0 ) {
|
||||
DBGC ( dhcp, "DHCP %p could not set requested address "
|
||||
"option: %s\n", dhcp, strerror ( rc ) );
|
||||
return rc;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* Transmit the packet */
|
||||
if ( ( rc = udp_sendto_via ( conn, &sa_dhcp_server.st, dhcp->netdev,
|
||||
dhcppkt.dhcphdr, dhcppkt.len ) ) != 0 ) {
|
||||
iob_put ( iobuf, dhcppkt.len );
|
||||
rc = xfer_deliver_iob_meta ( &dhcp->xfer, iobuf, &meta );
|
||||
iobuf = NULL;
|
||||
if ( rc != 0 ) {
|
||||
DBGC ( dhcp, "DHCP %p could not transmit UDP packet: %s\n",
|
||||
dhcp, strerror ( rc ) );
|
||||
return rc;
|
||||
goto done;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transmit DHCP request
|
||||
*
|
||||
* @v dhcp DHCP session
|
||||
*/
|
||||
static void dhcp_send_request ( struct dhcp_session *dhcp ) {
|
||||
start_timer ( &dhcp->timer );
|
||||
udp_senddata ( &dhcp->udp );
|
||||
done:
|
||||
free_iob ( iobuf );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -619,7 +647,7 @@ static void dhcp_timer_expired ( struct retry_timer *timer, int fail ) {
|
|||
container_of ( timer, struct dhcp_session, timer );
|
||||
|
||||
if ( fail ) {
|
||||
dhcp_done ( dhcp, -ETIMEDOUT );
|
||||
dhcp_finished ( dhcp, -ETIMEDOUT );
|
||||
} else {
|
||||
dhcp_send_request ( dhcp );
|
||||
}
|
||||
|
@ -628,17 +656,17 @@ static void dhcp_timer_expired ( struct retry_timer *timer, int fail ) {
|
|||
/**
|
||||
* Receive new data
|
||||
*
|
||||
* @v udp UDP connection
|
||||
* @v xfer Data transfer interface
|
||||
* @v iobuf I/O buffer
|
||||
* @v data Received data
|
||||
* @v len Length of received data
|
||||
* @v st_src Partially-filled source address
|
||||
* @v st_dest Partially-filled destination address
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int dhcp_newdata ( struct udp_connection *conn, void *data, size_t len,
|
||||
struct sockaddr_tcpip *st_src __unused,
|
||||
struct sockaddr_tcpip *st_dest __unused ) {
|
||||
struct dhcp_session *dhcp = udp_to_dhcp ( conn );
|
||||
struct dhcphdr *dhcphdr = data;
|
||||
static int dhcp_deliver_raw ( struct xfer_interface *xfer,
|
||||
const void *data, size_t len ) {
|
||||
struct dhcp_session *dhcp =
|
||||
container_of ( xfer, struct dhcp_session, xfer );
|
||||
const struct dhcphdr *dhcphdr = data;
|
||||
struct dhcp_option_block *options;
|
||||
unsigned int msgtype;
|
||||
|
||||
|
@ -651,7 +679,7 @@ static int dhcp_newdata ( struct udp_connection *conn, void *data, size_t len,
|
|||
};
|
||||
|
||||
/* Parse packet and create options structure */
|
||||
options = dhcp_parse ( dhcp, dhcphdr, len );
|
||||
options = dhcp_parse ( dhcphdr, len );
|
||||
if ( ! options ) {
|
||||
DBGC ( dhcp, "DHCP %p could not parse DHCP packet\n", dhcp );
|
||||
return -EINVAL;
|
||||
|
@ -682,58 +710,120 @@ static int dhcp_newdata ( struct udp_connection *conn, void *data, size_t len,
|
|||
/* Stop timer and update stored options */
|
||||
stop_timer ( &dhcp->timer );
|
||||
if ( dhcp->options )
|
||||
free_dhcp_options ( dhcp->options );
|
||||
dhcpopt_put ( dhcp->options );
|
||||
dhcp->options = options;
|
||||
|
||||
/* Transmit next packet, or terminate session */
|
||||
if ( dhcp->state < DHCPACK ) {
|
||||
dhcp_send_request ( dhcp );
|
||||
} else {
|
||||
dhcp_done ( dhcp, 0 );
|
||||
dhcp->register_options ( dhcp->options );
|
||||
dhcp_finished ( dhcp, 0 );
|
||||
}
|
||||
return 0;
|
||||
|
||||
out_discard:
|
||||
free_dhcp_options ( options );
|
||||
dhcpopt_put ( options );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** DHCP UDP operations */
|
||||
static struct udp_operations dhcp_udp_operations = {
|
||||
.senddata = dhcp_senddata,
|
||||
.newdata = dhcp_newdata,
|
||||
/** DHCP data transfer interface operations */
|
||||
static struct xfer_interface_operations dhcp_xfer_operations = {
|
||||
.close = ignore_xfer_close,
|
||||
.vredirect = xfer_vopen,
|
||||
.request = ignore_xfer_request,
|
||||
.seek = ignore_xfer_seek,
|
||||
.deliver_iob = xfer_deliver_as_raw,
|
||||
.deliver_raw = dhcp_deliver_raw,
|
||||
};
|
||||
|
||||
/**
|
||||
* Initiate DHCP on a network interface
|
||||
/****************************************************************************
|
||||
*
|
||||
* @v dhcp DHCP session
|
||||
* @v parent Parent asynchronous operation
|
||||
* @ret rc Return status code
|
||||
* Job control interface
|
||||
*
|
||||
* If the DHCP operation completes successfully, the
|
||||
* dhcp_session::options field will be filled in with the resulting
|
||||
* options block. The caller takes responsibility for eventually
|
||||
* calling free_dhcp_options().
|
||||
*/
|
||||
int start_dhcp ( struct dhcp_session *dhcp, struct async *parent ) {
|
||||
int rc;
|
||||
|
||||
/* Initialise DHCP session */
|
||||
dhcp->udp.udp_op = &dhcp_udp_operations;
|
||||
dhcp->timer.expired = dhcp_timer_expired;
|
||||
dhcp->state = DHCPDISCOVER;
|
||||
/**
|
||||
* Handle kill() event received via job control interface
|
||||
*
|
||||
* @v job DHCP job control interface
|
||||
*/
|
||||
static void dhcp_job_kill ( struct job_interface *job ) {
|
||||
struct dhcp_session *dhcp =
|
||||
container_of ( job, struct dhcp_session, job );
|
||||
|
||||
/* Bind to local port */
|
||||
if ( ( rc = udp_open ( &dhcp->udp, htons ( BOOTPC_PORT ) ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* Proof of concept: just send a single DHCPDISCOVER */
|
||||
dhcp_send_request ( dhcp );
|
||||
|
||||
async_init ( &dhcp->async, &default_async_operations, parent );
|
||||
return 0;
|
||||
/* Terminate DHCP session */
|
||||
dhcp_finished ( dhcp, -ECANCELED );
|
||||
}
|
||||
|
||||
/** DHCP job control interface operations */
|
||||
static struct job_interface_operations dhcp_job_operations = {
|
||||
.start = ignore_job_start,
|
||||
.done = ignore_job_done,
|
||||
.kill = dhcp_job_kill,
|
||||
.progress = ignore_job_progress,
|
||||
};
|
||||
|
||||
#endif
|
||||
/****************************************************************************
|
||||
*
|
||||
* Instantiator
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Start DHCP on a network device
|
||||
*
|
||||
* @v job Job control interface
|
||||
* @v netdev Network device
|
||||
* @v register_options DHCP option block registration routine
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* Starts DHCP on the specified network device. If successful, the @c
|
||||
* register_options() routine will be called with the acquired
|
||||
* options.
|
||||
*/
|
||||
int start_dhcp ( struct job_interface *job, struct net_device *netdev,
|
||||
int ( * register_options ) ( struct dhcp_option_block * ) ) {
|
||||
static struct sockaddr_in server = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_addr.s_addr = INADDR_BROADCAST,
|
||||
.sin_port = htons ( BOOTPS_PORT ),
|
||||
};
|
||||
static struct sockaddr_in client = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_port = htons ( BOOTPC_PORT ),
|
||||
};
|
||||
struct dhcp_session *dhcp;
|
||||
int rc;
|
||||
|
||||
/* Allocate and initialise structure */
|
||||
dhcp = malloc ( sizeof ( *dhcp ) );
|
||||
if ( ! dhcp )
|
||||
return -ENOMEM;
|
||||
memset ( dhcp, 0, sizeof ( *dhcp ) );
|
||||
dhcp->refcnt.free = dhcp_free;
|
||||
job_init ( &dhcp->job, &dhcp_job_operations, &dhcp->refcnt );
|
||||
xfer_init ( &dhcp->xfer, &dhcp_xfer_operations, &dhcp->refcnt );
|
||||
dhcp->netdev = netdev_get ( netdev );
|
||||
dhcp->register_options = register_options;
|
||||
dhcp->timer.expired = dhcp_timer_expired;
|
||||
|
||||
/* Instantiate child objects and attach to our interfaces */
|
||||
if ( ( rc = xfer_open_socket ( &dhcp->xfer, SOCK_DGRAM,
|
||||
( struct sockaddr * ) &server,
|
||||
( struct sockaddr * ) &client ) ) != 0 )
|
||||
goto err;
|
||||
|
||||
/* Start timer to initiate initial DHCPREQUEST */
|
||||
start_timer ( &dhcp->timer );
|
||||
|
||||
/* Attach parent interface, mortalise self, and return */
|
||||
job_plug_plug ( &dhcp->job, job );
|
||||
ref_put ( &dhcp->refcnt );
|
||||
return 0;
|
||||
|
||||
err:
|
||||
dhcp_finished ( dhcp, rc );
|
||||
ref_put ( &dhcp->refcnt );
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -261,7 +261,7 @@ int test_dhcp ( struct net_device *netdev ) {
|
|||
out:
|
||||
/* Unregister and free DHCP options */
|
||||
unregister_dhcp_options ( dhcp.options );
|
||||
free_dhcp_options ( dhcp.options );
|
||||
dhcpopt_put ( dhcp.options );
|
||||
out_no_options:
|
||||
out_no_del_ipv4:
|
||||
return rc;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <byteswap.h>
|
||||
#include <gpxe/in.h>
|
||||
#include <gpxe/ip.h>
|
||||
|
@ -34,6 +35,12 @@
|
|||
*
|
||||
*/
|
||||
|
||||
int dhcp ( struct net_device *netdev ) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
/* Avoid dragging in dns.o */
|
||||
struct sockaddr_tcpip nameserver;
|
||||
|
||||
|
@ -63,7 +70,7 @@ int dhcp ( struct net_device *netdev ) {
|
|||
/* Free up any previously-acquired options */
|
||||
if ( dhcp_options ) {
|
||||
unregister_dhcp_options ( dhcp_options );
|
||||
free_dhcp_options ( dhcp_options );
|
||||
dhcpopt_put ( dhcp_options );
|
||||
dhcp_options = NULL;
|
||||
}
|
||||
|
||||
|
@ -108,3 +115,5 @@ int dhcp ( struct net_device *netdev ) {
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue