[build] Move various pointer assignments after their length checks

When performing a length check on untrusted received data, it is
preferable to assign the corresponding typed pointer only after
validating that the length is sufficient to contain the dereferenced
pointer type.  This allows the compiler to catch any unintended
dereferences before the length check has taken place, and so hardens
the code against future potential changes.

This pattern of assigning the pointer only after the corresponding
length check is already fairly widespread, but there are still large
swathes of older code that use the less safe idiom of assigning the
pointer first (generally as part of the variable declaration).

Move an assortment of pointer assignments after their corresponding
length checks, and fix the few harmless premature dereferences that
were discovered in the process (e.g. using a potentially non-existent
IPv4 source address as a debug colour stream identifier).

This is not intended to be a comprehensive update of all such pointer
assignments, merely an improvement of those sites where assignments
are easily identifiable and trivially hardened.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
diff --git a/src/drivers/block/srp.c b/src/drivers/block/srp.c
index f0ef574..f552ac8 100644
--- a/src/drivers/block/srp.c
+++ b/src/drivers/block/srp.c
@@ -335,7 +335,7 @@
  */
 static int srp_login_rsp ( struct srp_device *srpdev,
 			   const void *data, size_t len ) {
-	const struct srp_login_rsp *login_rsp = data;
+	const struct srp_login_rsp *login_rsp;
 
 	/* Sanity check */
 	if ( len < sizeof ( *login_rsp ) ) {
@@ -343,6 +343,7 @@
 		       srpdev, len );
 		return -EINVAL;
 	}
+	login_rsp = data;
 	DBGC ( srpdev, "SRP %p tag %08x LOGIN_RSP:\n",
 	       srpdev, ntohl ( login_rsp->tag.dwords[1] ) );
 	DBGC_HDA ( srpdev, 0, data, len );
@@ -367,7 +368,7 @@
  */
 static int srp_login_rej ( struct srp_device *srpdev,
 			   const void *data, size_t len ) {
-	const struct srp_login_rej *login_rej = data;
+	const struct srp_login_rej *login_rej;
 	uint32_t reason;
 
 	/* Sanity check */
@@ -376,6 +377,7 @@
 		       srpdev, len );
 		return -EINVAL;
 	}
+	login_rej = data;
 	reason = ntohl ( login_rej->reason );
 	DBGC ( srpdev, "SRP %p tag %08x LOGIN_REJ reason %08x:\n",
 	       srpdev, ntohl ( login_rej->tag.dwords[1] ), reason );
@@ -656,7 +658,7 @@
 static int srpdev_deliver ( struct srp_device *srpdev,
 			    struct io_buffer *iobuf,
 			    struct xfer_metadata *meta __unused ) {
-	struct srp_common *common = iobuf->data;
+	struct srp_common *common;
 	int ( * type ) ( struct srp_device *srp, const void *data, size_t len );
 	int rc;
 
@@ -667,6 +669,7 @@
 		rc = -EINVAL;
 		goto err;
 	}
+	common = iobuf->data;
 
 	/* Determine IU type */
 	switch ( common->type ) {
diff --git a/src/drivers/net/iphone.c b/src/drivers/net/iphone.c
index d35737c..661922c 100644
--- a/src/drivers/net/iphone.c
+++ b/src/drivers/net/iphone.c
@@ -807,16 +807,17 @@
  * @v iobuf		I/O buffer
  */
 static void imux_rx_tcp ( struct imux *imux, struct io_buffer *iobuf ) {
-	struct imux_header_tcp *tcp = iobuf->data;
+	struct imux_header_tcp *tcp;
 	size_t len = iob_len ( iobuf );
 	int rc;
 
 	/* Sanity check */
 	if ( len < sizeof ( *tcp ) ) {
 		DBGC ( imux, "IMUX %p malformed TCP message:\n", imux );
-		DBGC_HDA ( imux, 0, tcp, len );
+		DBGC_HDA ( imux, 0, iobuf->data, len );
 		goto error;
 	}
+	tcp = iobuf->data;
 
 	/* Ignore unexpected packets */
 	if ( tcp->tcp.dest != htons ( imux->port ) ) {
@@ -867,7 +868,7 @@
 static void imux_in_complete ( struct usb_endpoint *ep,
 			       struct io_buffer *iobuf, int rc ) {
 	struct imux *imux = container_of ( ep, struct imux, usbnet.in );
-	struct imux_header *hdr = iobuf->data;
+	struct imux_header *hdr;
 	size_t len = iob_len ( iobuf );
 
 	/* Ignore packets cancelled when the endpoint closes */
@@ -884,9 +885,10 @@
 	/* Sanity check */
 	if ( len < sizeof ( *hdr ) ) {
 		DBGC ( imux, "IMUX %p malformed message:\n", imux );
-		DBGC_HDA ( imux, 0, hdr, len );
+		DBGC_HDA ( imux, 0, iobuf->data, len );
 		goto drop;
 	}
+	hdr = iobuf->data;
 
 	/* Record input sequence */
 	imux->in_seq = ntohs ( hdr->in_seq );
diff --git a/src/drivers/net/netvsc.c b/src/drivers/net/netvsc.c
index 681aa54..8726eec 100644
--- a/src/drivers/net/netvsc.c
+++ b/src/drivers/net/netvsc.c
@@ -137,7 +137,7 @@
 static int
 netvsc_initialised ( struct netvsc_device *netvsc, const void *data,
 		     size_t len ) {
-	const struct netvsc_init_completion *cmplt = data;
+	const struct netvsc_init_completion *cmplt;
 
 	/* Check completion */
 	if ( len < sizeof ( *cmplt ) ) {
@@ -145,6 +145,7 @@
 		       "completion (%zd bytes)\n", netvsc->name, len );
 		return -EINVAL;
 	}
+	cmplt = data;
 	if ( cmplt->header.type != cpu_to_le32 ( NETVSC_INIT_CMPLT ) ) {
 		DBGC ( netvsc, "NETVSC %s unexpected initialisation completion "
 		       "type %d\n", netvsc->name,
@@ -226,7 +227,7 @@
  */
 static int netvsc_rx_established_buffer ( struct netvsc_device *netvsc,
 					  const void *data, size_t len ) {
-	const struct netvsc_rx_establish_buffer_completion *cmplt = data;
+	const struct netvsc_rx_establish_buffer_completion *cmplt;
 
 	/* Check completion */
 	if ( len < sizeof ( *cmplt ) ) {
@@ -234,6 +235,7 @@
 		       "bytes)\n", netvsc->name, len );
 		return -EINVAL;
 	}
+	cmplt = data;
 	if ( cmplt->header.type != cpu_to_le32 ( NETVSC_RX_ESTABLISH_CMPLT ) ) {
 		DBGC ( netvsc, "NETVSC %s unexpected buffer completion type "
 		       "%d\n", netvsc->name, le32_to_cpu ( cmplt->header.type));
@@ -320,7 +322,7 @@
 			      struct list_head *list ) {
 	struct rndis_device *rndis = vmbus_get_drvdata ( vmdev );
 	struct netvsc_device *netvsc = rndis->priv;
-	const struct netvsc_rndis_message *msg = data;
+	const struct netvsc_rndis_message *msg;
 	struct io_buffer *iobuf;
 	struct io_buffer *tmp;
 	int rc;
@@ -332,6 +334,7 @@
 		rc = -EINVAL;
 		goto err_sanity;
 	}
+	msg = data;
 	if ( msg->header.type != cpu_to_le32 ( NETVSC_RNDIS_MSG ) ) {
 		DBGC ( netvsc, "NETVSC %s received unexpected RNDIS packet "
 		       "type %d\n", netvsc->name,
diff --git a/src/net/aoe.c b/src/net/aoe.c
index edeb818..86911ab 100644
--- a/src/net/aoe.c
+++ b/src/net/aoe.c
@@ -285,7 +285,7 @@
 static int aoecmd_rx ( struct aoe_command *aoecmd, struct io_buffer *iobuf,
 		       const void *ll_source ) {
 	struct aoe_device *aoedev = aoecmd->aoedev;
-	struct aoehdr *aoehdr = iobuf->data;
+	struct aoehdr *aoehdr;
 	int rc;
 
 	/* Sanity check */
@@ -296,6 +296,7 @@
 		rc = -EINVAL;
 		goto done;
 	}
+	aoehdr = iobuf->data;
 	if ( ( ntohs ( aoehdr->major ) != aoedev->major ) ||
 	     ( aoehdr->minor != aoedev->minor ) ) {
 		DBGC ( aoedev, "AoE %s/%08x received response for incorrect "
@@ -876,7 +877,7 @@
 		    const void *ll_dest __unused,
 		    const void *ll_source,
 		    unsigned int flags __unused ) {
-	struct aoehdr *aoehdr = iobuf->data;
+	struct aoehdr *aoehdr;
 	struct aoe_command *aoecmd;
 	int rc;
 
@@ -887,6 +888,7 @@
 		rc = -EINVAL;
 		goto err_sanity;
 	}
+	aoehdr = iobuf->data;
 	if ( ( aoehdr->ver_flags & AOE_VERSION_MASK ) != AOE_VERSION ) {
 		DBG ( "AoE received packet for unsupported protocol version "
 		      "%02x\n", ( aoehdr->ver_flags & AOE_VERSION_MASK ) );
diff --git a/src/net/arp.c b/src/net/arp.c
index 2bf3c12..243f862 100644
--- a/src/net/arp.c
+++ b/src/net/arp.c
@@ -136,7 +136,7 @@
 		    const void *ll_dest __unused,
 		    const void *ll_source __unused,
 		    unsigned int flags __unused ) {
-	struct arphdr *arphdr = iobuf->data;
+	struct arphdr *arphdr;
 	struct arp_net_protocol *arp_net_protocol;
 	struct net_protocol *net_protocol;
 	struct ll_protocol *ll_protocol;
@@ -144,7 +144,12 @@
 	int rc;
 
 	/* Sanity check */
-	if ( ( len < sizeof ( *arphdr ) ) || ( len < arp_len ( arphdr ) ) ) {
+	if ( len < sizeof ( *arphdr ) ) {
+		rc = -EINVAL;
+		goto done;
+	}
+	arphdr = iobuf->data;
+	if ( len < arp_len ( arphdr ) ) {
 		rc = -EINVAL;
 		goto done;
 	}
diff --git a/src/net/eth_slow.c b/src/net/eth_slow.c
index e4c78ac..21d6219 100644
--- a/src/net/eth_slow.c
+++ b/src/net/eth_slow.c
@@ -284,13 +284,14 @@
 			 const void *ll_dest __unused,
 			 const void *ll_source __unused,
 			 unsigned int flags __unused ) {
-	union eth_slow_packet *eth_slow = iobuf->data;
+	union eth_slow_packet *eth_slow;
 
 	/* Sanity checks */
 	if ( iob_len ( iobuf ) < sizeof ( *eth_slow ) ) {
 		free_iob ( iobuf );
 		return -EINVAL;
 	}
+	eth_slow = iobuf->data;
 
 	/* Strip any trailing padding */
 	iob_unput ( iobuf, ( iob_len ( iobuf ) - sizeof ( *eth_slow ) ) );
diff --git a/src/net/ethernet.c b/src/net/ethernet.c
index 60219b9..069adb3 100644
--- a/src/net/ethernet.c
+++ b/src/net/ethernet.c
@@ -102,7 +102,7 @@
 int eth_pull ( struct net_device *netdev __unused, struct io_buffer *iobuf,
 	       const void **ll_dest, const void **ll_source,
 	       uint16_t *net_proto, unsigned int *flags ) {
-	struct ethhdr *ethhdr = iobuf->data;
+	struct ethhdr *ethhdr;
 	uint16_t *llc_proto;
 
 	/* Sanity check.  While in theory we could receive a one-byte
@@ -115,6 +115,7 @@
 		      iob_len ( iobuf ) );
 		return -EINVAL;
 	}
+	ethhdr = iobuf->data;
 
 	/* Strip off Ethernet header */
 	iob_pull ( iobuf, sizeof ( *ethhdr ) );
diff --git a/src/net/fc.c b/src/net/fc.c
index 2e80702..a6c7fd1 100644
--- a/src/net/fc.c
+++ b/src/net/fc.c
@@ -858,7 +858,7 @@
  */
 static int fc_port_deliver ( struct fc_port *port, struct io_buffer *iobuf,
 			     struct xfer_metadata *meta ) {
-	struct fc_frame_header *fchdr = iobuf->data;
+	struct fc_frame_header *fchdr;
 	unsigned int xchg_id;
 	struct fc_exchange *xchg;
 	int rc;
@@ -870,6 +870,7 @@
 		rc = -EINVAL;
 		goto err_sanity;
 	}
+	fchdr = iobuf->data;
 
 	/* Verify local port ID */
 	if ( ( memcmp ( &fchdr->d_id, &port->port_id,
diff --git a/src/net/fcels.c b/src/net/fcels.c
index 5fc27ce..d97d256 100644
--- a/src/net/fcels.c
+++ b/src/net/fcels.c
@@ -159,9 +159,9 @@
 static int fc_els_rx ( struct fc_els *els,
 		       struct io_buffer *iobuf,
 		       struct xfer_metadata *meta ) {
-	struct fc_els_frame_common *frame = iobuf->data;
 	struct sockaddr_fc *src = ( ( struct sockaddr_fc * ) meta->src );
 	struct sockaddr_fc *dest = ( ( struct sockaddr_fc * ) meta->dest );
+	struct fc_els_frame_common *frame;
 	size_t len = iob_len ( iobuf );
 	int rc;
 
@@ -169,10 +169,11 @@
 	if ( len < sizeof ( *frame ) ) {
 		DBGC ( els, FCELS_FMT " received underlength frame:\n",
 		       FCELS_ARGS ( els ) );
-		DBGC_HDA ( els, 0, frame, len );
+		DBGC_HDA ( els, 0, iobuf->data, len );
 		rc = -EINVAL;
 		goto done;
 	}
+	frame = iobuf->data;
 	if ( ! src ) {
 		DBGC ( els, FCELS_FMT " received frame missing source "
 		       "address:\n", FCELS_ARGS ( els ) );
@@ -493,7 +494,7 @@
  * @ret rc		Return status code
  */
 static int fc_els_flogi_rx ( struct fc_els *els, void *data, size_t len ) {
-	struct fc_login_frame *flogi = data;
+	struct fc_login_frame *flogi;
 	int has_fabric;
 	int rc;
 
@@ -504,6 +505,7 @@
 		DBGC_HDA ( els, 0, data, len );
 		return -EINVAL;
 	}
+	flogi = data;
 
 	/* Extract parameters */
 	has_fabric = ( flogi->common.flags & htons ( FC_LOGIN_F_PORT ) );
@@ -633,7 +635,7 @@
  * @ret rc		Return status code
  */
 static int fc_els_plogi_rx ( struct fc_els *els, void *data, size_t len ) {
-	struct fc_login_frame *plogi = data;
+	struct fc_login_frame *plogi;
 	struct fc_peer *peer;
 	int rc;
 
@@ -645,6 +647,7 @@
 		rc = -EINVAL;
 		goto err_sanity;
 	}
+	plogi = data;
 	if ( ! fc_link_ok ( &els->port->link ) ) {
 		DBGC ( els, FCELS_FMT " received while port link is down\n",
 		       FCELS_ARGS ( els ) );
@@ -815,7 +818,7 @@
  */
 static int fc_els_logo_rx_request ( struct fc_els *els, void *data,
 				    size_t len ) {
-	struct fc_logout_request_frame *logo = data;
+	struct fc_logout_request_frame *logo;
 	int rc;
 
 	/* Sanity check */
@@ -825,6 +828,7 @@
 		DBGC_HDA ( els, 0, data, len );
 		return -EINVAL;
 	}
+	logo = data;
 
 	DBGC ( els, FCELS_FMT " has port %s as %s\n", FCELS_ARGS ( els ),
 	       fc_ntoa ( &logo->port_wwn ), fc_id_ntoa ( &logo->port_id ) );
@@ -1009,7 +1013,7 @@
 	struct {
 		struct fc_prli_frame frame;
 		uint8_t param[descriptor->param_len];
-	} __attribute__ (( packed )) *prli = data;
+	} __attribute__ (( packed )) *prli;
 	struct fc_ulp *ulp;
 	int rc;
 
@@ -1021,6 +1025,7 @@
 		rc = -EINVAL;
 		goto err_sanity;
 	}
+	prli = data;
 
 	DBGC ( els, FCELS_FMT " has parameters:\n", FCELS_ARGS ( els ) );
 	DBGC_HDA ( els, 0, prli->param, sizeof ( prli->param ) );
@@ -1095,15 +1100,16 @@
 	const struct {
 		struct fc_prli_frame frame;
 		uint8_t param[descriptor->param_len];
-	} __attribute__ (( packed )) *prli = data;
-
-	/* Check for PRLI */
-	if ( prli->frame.command != FC_ELS_PRLI )
-		return -EINVAL;
+	} __attribute__ (( packed )) *prli;
 
 	/* Check for sufficient length to contain service parameter page */
 	if ( len < sizeof ( *prli ) )
 		return -EINVAL;
+	prli = data;
+
+	/* Check for PRLI */
+	if ( prli->frame.command != FC_ELS_PRLI )
+		return -EINVAL;
 
 	/* Check for upper-layer protocol type */
 	if ( prli->frame.page.type != descriptor->type )
@@ -1282,13 +1288,21 @@
  */
 static int fc_els_echo_rx_response ( struct fc_els *els, void *data,
 				     size_t len ) {
-	struct fc_echo_request_frame *echo = data;
+	struct fc_echo_request_frame *echo;
 
 	DBGC ( els, FCELS_FMT "\n", FCELS_ARGS ( els ) );
 
+	/* Sanity check */
+	if ( len != sizeof ( *echo ) ) {
+		DBGC ( els, FCELS_FMT " received underlength echo response\n",
+		       FCELS_ARGS ( els ) );
+		DBGC_HDA ( els, 0, data, len );
+		return -EIO;
+	}
+	echo = data;
+
 	/* Check response is correct */
-	if ( ( len != sizeof ( *echo ) ) ||
-	     ( echo->magic != htonl ( FC_ECHO_MAGIC ) ) ) {
+	if ( echo->magic != htonl ( FC_ECHO_MAGIC ) ) {
 		DBGC ( els, FCELS_FMT " received bad echo response\n",
 		       FCELS_ARGS ( els ) );
 		DBGC_HDA ( els, 0, data, len );
diff --git a/src/net/fcns.c b/src/net/fcns.c
index be4dfea..2b966d5 100644
--- a/src/net/fcns.c
+++ b/src/net/fcns.c
@@ -106,7 +106,7 @@
 static int fc_ns_query_deliver ( struct fc_ns_query *query,
 				 struct io_buffer *iobuf,
 				 struct xfer_metadata *meta __unused ) {
-	union fc_ns_response *resp = iobuf->data;
+	union fc_ns_response *resp;
 	struct fc_port_id *peer_port_id;
 	int rc;
 
@@ -117,6 +117,7 @@
 		rc = -EINVAL;
 		goto done;
 	}
+	resp = iobuf->data;
 
 	/* Handle response */
 	switch ( ntohs ( resp->ct.code ) ) {
diff --git a/src/net/fcp.c b/src/net/fcp.c
index 5bb6ebf..3332720 100644
--- a/src/net/fcp.c
+++ b/src/net/fcp.c
@@ -508,7 +508,7 @@
 				  struct io_buffer *iobuf,
 				  struct xfer_metadata *meta __unused ) {
 	struct fcp_device *fcpdev = fcpcmd->fcpdev;
-	struct fcp_xfer_rdy *xfer_rdy = iobuf->data;
+	struct fcp_xfer_rdy *xfer_rdy;
 	int rc;
 
 	/* Sanity checks */
@@ -519,6 +519,7 @@
 		rc = -EPROTO;
 		goto done;
 	}
+	xfer_rdy = iobuf->data;
 	if ( ntohl ( xfer_rdy->offset ) != fcpcmd->offset ) {
 		/* We do not advertise out-of-order delivery */
 		DBGC ( fcpdev, "FCP %p xchg %04x cannot support out-of-order "
diff --git a/src/net/icmp.c b/src/net/icmp.c
index 740b424..19d282e 100644
--- a/src/net/icmp.c
+++ b/src/net/icmp.c
@@ -140,9 +140,13 @@
 static int icmp_tx_echo_reply ( struct io_buffer *iobuf,
 				struct sockaddr_tcpip *st_dest,
 				struct icmp_echo_protocol *echo_protocol ) {
-	struct icmp_echo *echo = iobuf->data;
+	struct icmp_echo *echo;
 	int rc;
 
+	/* Sanity check: should have already been checked by receiver */
+	assert ( iob_len ( iobuf ) >= sizeof ( *echo ) );
+	echo = iobuf->data;
+
 	/* Set type */
 	echo->icmp.type = echo_protocol->reply;
 
@@ -166,7 +170,7 @@
 int icmp_rx_echo_request ( struct io_buffer *iobuf,
 			   struct sockaddr_tcpip *st_src,
 			   struct icmp_echo_protocol *echo_protocol ) {
-	struct icmp_echo *echo = iobuf->data;
+	struct icmp_echo *echo;
 	int rc;
 
 	/* Sanity check */
@@ -177,6 +181,7 @@
 		free_iob ( iobuf );
 		return -EINVAL;
 	}
+	echo = iobuf->data;
 	DBGC ( icmpcol ( st_src ), "ICMP RX echo request id %04x seq %04x\n",
 	       ntohs ( echo->ident ), ntohs ( echo->sequence ) );
 
@@ -196,7 +201,7 @@
  */
 int icmp_rx_echo_reply ( struct io_buffer *iobuf,
 			 struct sockaddr_tcpip *st_src ) {
-	struct icmp_echo *echo = iobuf->data;
+	struct icmp_echo *echo;
 	int rc;
 
 	/* Sanity check */
@@ -207,6 +212,7 @@
 		free_iob ( iobuf );
 		return -EINVAL;
 	}
+	echo = iobuf->data;
 	DBGC ( icmpcol ( st_src ), "ICMP RX echo reply id %04x seq %04x\n",
 	       ntohs ( echo->ident ), ntohs ( echo->sequence ) );
 
diff --git a/src/net/icmpv4.c b/src/net/icmpv4.c
index ffcc4b3..9698028 100644
--- a/src/net/icmpv4.c
+++ b/src/net/icmpv4.c
@@ -54,7 +54,7 @@
 		       struct sockaddr_tcpip *st_src,
 		       struct sockaddr_tcpip *st_dest __unused,
 		       uint16_t pshdr_csum __unused ) {
-	struct icmp_header *icmp = iobuf->data;
+	struct icmp_header *icmp;
 	size_t len = iob_len ( iobuf );
 	unsigned int csum;
 	unsigned int type;
@@ -67,6 +67,7 @@
 		rc = -EINVAL;
 		goto discard;
 	}
+	icmp = iobuf->data;
 
 	/* Verify checksum */
 	csum = tcpip_chksum ( icmp, len );
diff --git a/src/net/icmpv6.c b/src/net/icmpv6.c
index 5331b81..20bf5ff 100644
--- a/src/net/icmpv6.c
+++ b/src/net/icmpv6.c
@@ -181,7 +181,7 @@
 		       struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum ) {
 	struct sockaddr_in6 *sin6_src = ( ( struct sockaddr_in6 * ) st_src );
 	struct sockaddr_in6 *sin6_dest = ( ( struct sockaddr_in6 * ) st_dest );
-	struct icmp_header *icmp = iobuf->data;
+	struct icmp_header *icmp;
 	size_t len = iob_len ( iobuf );
 	struct icmpv6_handler *handler;
 	unsigned int csum;
@@ -194,6 +194,7 @@
 		rc = -EINVAL;
 		goto done;
 	}
+	icmp = iobuf->data;
 
 	/* Verify checksum */
 	csum = tcpip_continue_chksum ( pshdr_csum, icmp, len );
diff --git a/src/net/ipv4.c b/src/net/ipv4.c
index bda8bae..75ea008 100644
--- a/src/net/ipv4.c
+++ b/src/net/ipv4.c
@@ -635,7 +635,7 @@
 		     const void *ll_dest __unused,
 		     const void *ll_source __unused,
 		     unsigned int flags ) {
-	struct iphdr *iphdr = iobuf->data;
+	struct iphdr *iphdr;
 	size_t hdrlen;
 	size_t len;
 	union {
@@ -660,10 +660,11 @@
 
 	/* Sanity check the IPv4 header */
 	if ( iob_len ( iobuf ) < sizeof ( *iphdr ) ) {
-		DBGC ( iphdr->src, "IPv4 packet too short at %zd bytes (min "
+		DBGC ( netdev, "IPv4 packet too short at %zd bytes (min "
 		       "%zd bytes)\n", iob_len ( iobuf ), sizeof ( *iphdr ) );
 		goto err_header;
 	}
+	iphdr = iobuf->data;
 	if ( ( iphdr->verhdrlen & IP_MASK_VER ) != IP_VER ) {
 		DBGC ( iphdr->src, "IPv4 version %#02x not supported\n",
 		       iphdr->verhdrlen );
diff --git a/src/net/ipv6.c b/src/net/ipv6.c
index 6d76958..7a96cbb 100644
--- a/src/net/ipv6.c
+++ b/src/net/ipv6.c
@@ -651,7 +651,7 @@
 		     const void *ll_dest __unused,
 		     const void *ll_source __unused,
 		     unsigned int flags __unused ) {
-	struct ipv6_header *iphdr = iobuf->data;
+	struct ipv6_header *iphdr;
 	union ipv6_extension_header *ext;
 	union {
 		struct sockaddr_in6 sin6;
@@ -676,12 +676,12 @@
 
 	/* Sanity check the IPv6 header */
 	if ( iob_len ( iobuf ) < sizeof ( *iphdr ) ) {
-		DBGC ( ipv6col ( &iphdr->src ), "IPv6 packet too short at %zd "
-		       "bytes (min %zd bytes)\n", iob_len ( iobuf ),
-		       sizeof ( *iphdr ) );
+		DBGC ( netdev, "IPv6 packet too short at %zd bytes (min %zd "
+		       "bytes)\n", iob_len ( iobuf ), sizeof ( *iphdr ) );
 		rc = -EINVAL_LEN;
 		goto err_header;
 	}
+	iphdr = iobuf->data;
 	if ( ( iphdr->ver_tc_label & htonl ( IPV6_MASK_VER ) ) !=
 	     htonl ( IPV6_VER ) ) {
 		DBGC ( ipv6col ( &iphdr->src ), "IPv6 version %#08x not "
diff --git a/src/net/ping.c b/src/net/ping.c
index 5782813..7d7c874 100644
--- a/src/net/ping.c
+++ b/src/net/ping.c
@@ -102,13 +102,14 @@
  * @ret rc		Return status code
  */
 int ping_rx ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src ) {
-	struct icmp_echo *echo = iobuf->data;
+	struct icmp_echo *echo;
 	struct ping_connection *ping;
 	struct xfer_metadata meta;
 	int rc;
 
 	/* Sanity check: should already have been checked by ICMP layer */
 	assert ( iob_len ( iobuf ) >= sizeof ( *echo ) );
+	echo = iobuf->data;
 
 	/* Identify connection */
 	ping = ping_demux ( ntohs ( echo->ident ) );
diff --git a/src/net/tcp.c b/src/net/tcp.c
index f08db52..85e1ceb 100644
--- a/src/net/tcp.c
+++ b/src/net/tcp.c
@@ -1411,7 +1411,7 @@
 		    struct sockaddr_tcpip *st_src,
 		    struct sockaddr_tcpip *st_dest __unused,
 		    uint16_t pshdr_csum ) {
-	struct tcp_header *tcphdr = iobuf->data;
+	struct tcp_header *tcphdr;
 	struct tcp_connection *tcp;
 	struct tcp_options options;
 	size_t hlen;
@@ -1436,6 +1436,7 @@
 		rc = -EINVAL;
 		goto discard;
 	}
+	tcphdr = iobuf->data;
 	hlen = ( ( tcphdr->hlen & TCP_MASK_HLEN ) / 16 ) * 4;
 	if ( hlen < sizeof ( *tcphdr ) ) {
 		DBG ( "TCP header too short at %zd bytes (min %zd bytes)\n",
diff --git a/src/net/udp.c b/src/net/udp.c
index 41aba2f..1619381 100644
--- a/src/net/udp.c
+++ b/src/net/udp.c
@@ -258,7 +258,7 @@
 		    struct net_device *netdev __unused,
 		    struct sockaddr_tcpip *st_src,
 		    struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum ) {
-	struct udp_header *udphdr = iobuf->data;
+	struct udp_header *udphdr;
 	struct udp_connection *udp;
 	struct xfer_metadata meta;
 	size_t ulen;
@@ -269,10 +269,10 @@
 	if ( iob_len ( iobuf ) < sizeof ( *udphdr ) ) {
 		DBG ( "UDP packet too short at %zd bytes (min %zd bytes)\n",
 		      iob_len ( iobuf ), sizeof ( *udphdr ) );
-		
 		rc = -EINVAL;
 		goto done;
 	}
+	udphdr = iobuf->data;
 	ulen = ntohs ( udphdr->len );
 	if ( ulen < sizeof ( *udphdr ) ) {
 		DBG ( "UDP length too short at %zd bytes "
diff --git a/src/net/udp/dhcpv6.c b/src/net/udp/dhcpv6.c
index 43a569d..8e00724 100644
--- a/src/net/udp/dhcpv6.c
+++ b/src/net/udp/dhcpv6.c
@@ -844,7 +844,7 @@
 		       struct xfer_metadata *meta ) {
 	struct settings *parent = netdev_settings ( dhcpv6->netdev );
 	struct sockaddr_in6 *src = ( ( struct sockaddr_in6 * ) meta->src );
-	struct dhcpv6_header *dhcphdr = iobuf->data;
+	struct dhcpv6_header *dhcphdr;
 	struct dhcpv6_option_list options;
 	const union dhcpv6_any_option *option;
 	int rc;
@@ -857,6 +857,7 @@
 		rc = -EINVAL;
 		goto done;
 	}
+	dhcphdr = iobuf->data;
 	assert ( src != NULL );
 	assert ( src->sin6_family == AF_INET6 );
 	DBGC ( dhcpv6, "DHCPv6 %s received %s from %s\n",
diff --git a/src/net/udp/dns.c b/src/net/udp/dns.c
index 3f53675..5891611 100644
--- a/src/net/udp/dns.c
+++ b/src/net/udp/dns.c
@@ -669,9 +669,9 @@
 static int dns_xfer_deliver ( struct dns_request *dns,
 			      struct io_buffer *iobuf,
 			      struct xfer_metadata *meta __unused ) {
-	struct dns_header *response = iobuf->data;
 	struct dns_header *query = &dns->buf.query;
 	unsigned int qtype = dns->question->qtype;
+	struct dns_header *response;
 	struct dns_name buf;
 	union dns_rr *rr;
 	int offset;
@@ -688,6 +688,7 @@
 		rc = -EINVAL;
 		goto done;
 	}
+	response = iobuf->data;
 
 	/* Check response ID matches query ID */
 	if ( response->id != query->id ) {
diff --git a/src/net/udp/tftp.c b/src/net/udp/tftp.c
index d25c065..7cc720f 100644
--- a/src/net/udp/tftp.c
+++ b/src/net/udp/tftp.c
@@ -720,7 +720,7 @@
  * @ret rc		Return status code
  */
 static int tftp_rx_oack ( struct tftp_request *tftp, void *buf, size_t len ) {
-	struct tftp_oack *oack = buf;
+	struct tftp_oack *oack;
 	char *end = buf + len;
 	char *name;
 	char *value;
@@ -734,6 +734,7 @@
 		rc = -EINVAL;
 		goto done;
 	}
+	oack = buf;
 
 	/* Process each option in turn */
 	for ( name = oack->data ; name < end ; name = next ) {
@@ -797,7 +798,7 @@
  */
 static int tftp_rx_data ( struct tftp_request *tftp,
 			  struct io_buffer *iobuf ) {
-	struct tftp_data *data = iobuf->data;
+	struct tftp_data *data;
 	struct xfer_metadata meta;
 	unsigned int block;
 	off_t offset;
@@ -811,6 +812,7 @@
 		rc = -EINVAL;
 		goto done;
 	}
+	data = iobuf->data;
 
 	/* Calculate block number */
 	block = ( ( bitmap_first_gap ( &tftp->bitmap ) + 1 ) & ~0xffff );
@@ -899,7 +901,7 @@
  * @ret rc		Return status code
  */
 static int tftp_rx_error ( struct tftp_request *tftp, void *buf, size_t len ) {
-	struct tftp_error *error = buf;
+	struct tftp_error *error;
 	int rc;
 
 	/* Sanity check */
@@ -908,6 +910,7 @@
 		       "length %zd\n", tftp, len );
 		return -EINVAL;
 	}
+	error = buf;
 
 	DBGC ( tftp, "TFTP %p received ERROR packet with code %d, message "
 	       "\"%s\"\n", tftp, ntohs ( error->errcode ), error->errmsg );
@@ -933,7 +936,7 @@
 		     struct io_buffer *iobuf,
 		     struct xfer_metadata *meta ) {
 	struct sockaddr_tcpip *st_src;
-	struct tftp_common *common = iobuf->data;
+	struct tftp_common *common;
 	size_t len = iob_len ( iobuf );
 	int rc = -EINVAL;
 
@@ -946,6 +949,7 @@
 		       "%zd\n", tftp, len );
 		goto done;
 	}
+	common = iobuf->data;
 	if ( ! meta->src ) {
 		DBGC ( tftp, "TFTP %p received packet without source port\n",
 		       tftp );
diff --git a/src/net/vlan.c b/src/net/vlan.c
index f7697a9..47e869b 100644
--- a/src/net/vlan.c
+++ b/src/net/vlan.c
@@ -233,7 +233,7 @@
 static int vlan_rx ( struct io_buffer *iobuf, struct net_device *trunk,
 		     const void *ll_dest, const void *ll_source,
 		     unsigned int flags __unused ) {
-	struct vlan_header *vlanhdr = iobuf->data;
+	struct vlan_header *vlanhdr;
 	struct net_device *netdev;
 	struct ll_protocol *ll_protocol;
 	uint8_t ll_dest_copy[ETH_ALEN];
@@ -248,6 +248,7 @@
 		rc = -EINVAL;
 		goto err_sanity;
 	}
+	vlanhdr = iobuf->data;
 
 	/* Identify VLAN device */
 	tag = VLAN_TAG ( ntohs ( vlanhdr->tci ) );