示例#1
0
文件: srp.c 项目: 1stMaster/syslinux
/**
 * Handle SRP login rejection
 *
 * @v srp		SRP device
 * @v iobuf		I/O buffer
 * @ret rc		Return status code
 */
static int srp_login_rej ( struct srp_device *srp, struct io_buffer *iobuf ) {
	struct srp_login_rej *login_rej = iobuf->data;
	int rc;

	DBGC2 ( srp, "SRP %p RX login rejection tag %08x%08x\n",
		srp, ntohl ( login_rej->tag.dwords[0] ),
		ntohl ( login_rej->tag.dwords[1] ) );

	/* Sanity check */
	if ( iob_len ( iobuf ) < sizeof ( *login_rej ) ) {
		DBGC ( srp, "SRP %p RX login rejection too short (%zd "
		       "bytes)\n", srp, iob_len ( iobuf ) );
		rc = -EINVAL;
		goto out;
	}

	/* Login rejection always indicates an error */
	DBGC ( srp, "SRP %p login rejected (reason %08x)\n",
	       srp, ntohl ( login_rej->reason ) );
	rc = -EPERM;

 out:
	free_iob ( iobuf );
	return rc;
}
示例#2
0
文件: srp.c 项目: 1stMaster/syslinux
/**
 * Handle SRP login response
 *
 * @v srp		SRP device
 * @v iobuf		I/O buffer
 * @ret rc		Return status code
 */
static int srp_login_rsp ( struct srp_device *srp, struct io_buffer *iobuf ) {
	struct srp_login_rsp *login_rsp = iobuf->data;
	int rc;

	DBGC2 ( srp, "SRP %p RX login response tag %08x%08x\n",
		srp, ntohl ( login_rsp->tag.dwords[0] ),
		ntohl ( login_rsp->tag.dwords[1] ) );

	/* Sanity check */
	if ( iob_len ( iobuf ) < sizeof ( *login_rsp ) ) {
		DBGC ( srp, "SRP %p RX login response too short (%zd bytes)\n",
		       srp, iob_len ( iobuf ) );
		rc = -EINVAL;
		goto out;
	}

	DBGC ( srp, "SRP %p logged in\n", srp );

	/* Mark as logged in */
	srp->state |= SRP_STATE_LOGGED_IN;

	/* Reset error counter */
	srp->retry_count = 0;

	/* Issue pending command */
	srp_cmd ( srp );

	rc = 0;
 out:
	free_iob ( iobuf );
	return rc;
}
示例#3
0
文件: iobuf.c 项目: 42wim/ipxe
/**
 * Concatenate I/O buffers into a single buffer
 *
 * @v list	List of I/O buffers
 * @ret iobuf	Concatenated I/O buffer, or NULL on allocation failure
 *
 * After a successful concatenation, the list will be empty.
 */
struct io_buffer * iob_concatenate ( struct list_head *list ) {
	struct io_buffer *iobuf;
	struct io_buffer *tmp;
	struct io_buffer *concatenated;
	size_t len = 0;

	/* If the list contains only a single entry, avoid an
	 * unnecessary additional allocation.
	 */
	if ( list_is_singular ( list ) ) {
		iobuf = list_first_entry ( list, struct io_buffer, list );
		INIT_LIST_HEAD ( list );
		return iobuf;
	}

	/* Calculate total length */
	list_for_each_entry ( iobuf, list, list )
		len += iob_len ( iobuf );

	/* Allocate new I/O buffer */
	concatenated = alloc_iob_raw ( len, __alignof__ ( *iobuf ), 0 );
	if ( ! concatenated )
		return NULL;

	/* Move data to new I/O buffer */
	list_for_each_entry_safe ( iobuf, tmp, list, list ) {
		list_del ( &iobuf->list );
		memcpy ( iob_put ( concatenated, iob_len ( iobuf ) ),
			 iobuf->data, iob_len ( iobuf ) );
		free_iob ( iobuf );
	}
示例#4
0
文件: rhine.c 项目: 42wim/ipxe
/**
 * Transmit packet
 *
 * @v netdev		Network device
 * @v iobuf		I/O buffer
 * @ret rc		Return status code
 */
static int rhine_transmit ( struct net_device *netdev,
                            struct io_buffer *iobuf ) {
	struct rhine_nic *rhn = netdev->priv;
	struct rhine_descriptor *desc;
	physaddr_t address;
	unsigned int tx_idx;

	/* Get next transmit descriptor */
	if ( ( rhn->tx.prod - rhn->tx.cons ) >= RHINE_TXDESC_NUM )
		return -ENOBUFS;
	tx_idx = ( rhn->tx.prod++ % RHINE_TXDESC_NUM );
	desc = &rhn->tx.desc[tx_idx];

	/* Pad and align packet */
	iob_pad ( iobuf, ETH_ZLEN );
	address = virt_to_bus ( iobuf->data );

	/* Populate transmit descriptor */
	desc->buffer = cpu_to_le32 ( address );
	desc->des1 = cpu_to_le32 ( RHINE_DES1_IC | RHINE_TDES1_STP |
				   RHINE_TDES1_EDP | RHINE_DES1_CHAIN |
				   RHINE_DES1_SIZE ( iob_len ( iobuf ) ) );
	wmb();
	desc->des0 = cpu_to_le32 ( RHINE_DES0_OWN );
	wmb();

	/* Notify card that there are packets ready to transmit */
	writeb ( ( rhn->cr1 | RHINE_CR1_TXPOLL ), rhn->regs + RHINE_CR1 );

	DBGC2 ( rhn, "RHINE %p TX %d is [%llx,%llx)\n", rhn, tx_idx,
		( ( unsigned long long ) address ),
		( ( unsigned long long ) address + iob_len ( iobuf ) ) );

	return 0;
}
示例#5
0
/**
 * Encapsulate and encrypt a packet using CCMP
 *
 * @v crypto	CCMP cryptosystem
 * @v iob	I/O buffer containing cleartext packet
 * @ret eiob	I/O buffer containing encrypted packet
 */
struct io_buffer * ccmp_encrypt ( struct net80211_crypto *crypto,
				  struct io_buffer *iob )
{
	struct ccmp_ctx *ctx = crypto->priv;
	struct ieee80211_frame *hdr = iob->data;
	struct io_buffer *eiob;
	const int hdrlen = IEEE80211_TYP_FRAME_HEADER_LEN;
	int datalen = iob_len ( iob ) - hdrlen;
	struct ccmp_head head;
	struct ccmp_nonce nonce;
	struct ccmp_aad aad;
	u8 mic[8], tx_pn[6];
	void *edata, *emic;

	ctx->tx_seq++;
	u64_to_pn ( ctx->tx_seq, tx_pn, PN_LSB );

	/* Allocate memory */
	eiob = alloc_iob ( iob_len ( iob ) + CCMP_HEAD_LEN + CCMP_MIC_LEN );
	if ( ! eiob )
		return NULL;

	/* Copy frame header */
	memcpy ( iob_put ( eiob, hdrlen ), iob->data, hdrlen );
	hdr = eiob->data;
	hdr->fc |= IEEE80211_FC_PROTECTED;

	/* Fill in packet number and extended IV */
	memcpy ( head.pn_lo, tx_pn, 2 );
	memcpy ( head.pn_hi, tx_pn + 2, 4 );
	head.kid = 0x20;	/* have Extended IV, key ID 0 */
	head._rsvd = 0;
	memcpy ( iob_put ( eiob, sizeof ( head ) ), &head, sizeof ( head ) );

	/* Form nonce */
	nonce.prio = 0;
	memcpy ( nonce.a2, hdr->addr2, ETH_ALEN );
	u64_to_pn ( ctx->tx_seq, nonce.pn, PN_MSB );

	/* Form additional authentication data */
	aad.fc = hdr->fc & CCMP_AAD_FC_MASK;
	memcpy ( aad.a1, hdr->addr1, 3 * ETH_ALEN ); /* all 3 at once */
	aad.seq = hdr->seq & CCMP_AAD_SEQ_MASK;

	/* Calculate MIC over the data */
	ccmp_cbc_mac ( ctx, &nonce, iob->data + hdrlen, datalen, &aad, mic );

	/* Copy and encrypt data and MIC */
	edata = iob_put ( eiob, datalen );
	emic = iob_put ( eiob, CCMP_MIC_LEN );
	ccmp_ctr_xor ( ctx, &nonce,
		       iob->data + hdrlen, edata, datalen,
		       mic, emic );

	/* Done! */
	DBGC2 ( ctx, "WPA-CCMP %p: encrypted packet %p -> %p\n", ctx,
		iob, eiob );

	return eiob;
}
示例#6
0
文件: acm.c 项目: dell-asm-ci/ipxe
/**
 * Complete interrupt transfer
 *
 * @v ep		USB endpoint
 * @v iobuf		I/O buffer
 * @v rc		Completion status code
 */
static void acm_intr_complete ( struct usb_endpoint *ep,
				struct io_buffer *iobuf, int rc ) {
	struct acm_device *acm = container_of ( ep, struct acm_device,
						usbnet.intr );
	struct rndis_device *rndis = acm->rndis;
	struct usb_setup_packet *message;

	/* Profile completions */
	profile_start ( &acm_intr_profiler );

	/* Ignore packets cancelled when the endpoint closes */
	if ( ! ep->open )
		goto ignore;

	/* Drop packets with errors */
	if ( rc != 0 ) {
		DBGC ( acm, "ACM %p interrupt failed: %s\n",
		       acm, strerror ( rc ) );
		DBGC_HDA ( acm, 0, iobuf->data, iob_len ( iobuf ) );
		goto error;
	}

	/* Extract message header */
	if ( iob_len ( iobuf ) < sizeof ( *message ) ) {
		DBGC ( acm, "ACM %p underlength interrupt:\n", acm );
		DBGC_HDA ( acm, 0, iobuf->data, iob_len ( iobuf ) );
		rc = -EINVAL;
		goto error;
	}
	message = iobuf->data;

	/* Parse message header */
	switch ( message->request ) {

	case cpu_to_le16 ( CDC_RESPONSE_AVAILABLE ) :
	case cpu_to_le16 ( 0x0001 ) : /* qemu seems to use this value */
		acm->responded = 1;
		break;

	default:
		DBGC ( acm, "ACM %p unrecognised interrupt:\n", acm );
		DBGC_HDA ( acm, 0, iobuf->data, iob_len ( iobuf ) );
		rc = -ENOTSUP;
		goto error;
	}

	/* Free I/O buffer */
	free_iob ( iobuf );
	profile_stop ( &acm_intr_profiler );

	return;

 error:
	rndis_rx_err ( rndis, iob_disown ( iobuf ), rc );
 ignore:
	free_iob ( iobuf );
	return;
}
示例#7
0
/**
 * Complete bulk IN transfer
 *
 * @v ep		USB endpoint
 * @v iobuf		I/O buffer
 * @v rc		Completion status code
 */
static void smsc95xx_in_complete ( struct usb_endpoint *ep,
				   struct io_buffer *iobuf, int rc ) {
	struct smsc95xx_device *smsc95xx =
		container_of ( ep, struct smsc95xx_device, usbnet.in );
	struct net_device *netdev = smsc95xx->netdev;
	struct smsc95xx_rx_header *header;

	/* Profile completions */
	profile_start ( &smsc95xx_in_profiler );

	/* Ignore packets cancelled when the endpoint closes */
	if ( ! ep->open ) {
		free_iob ( iobuf );
		return;
	}

	/* Record USB errors against the network device */
	if ( rc != 0 ) {
		DBGC ( smsc95xx, "SMSC95XX %p bulk IN failed: %s\n",
		       smsc95xx, strerror ( rc ) );
		goto err;
	}

	/* Sanity check */
	if ( iob_len ( iobuf ) < ( sizeof ( *header ) + 4 /* CRC */ ) ) {
		DBGC ( smsc95xx, "SMSC95XX %p underlength bulk IN\n",
		       smsc95xx );
		DBGC_HDA ( smsc95xx, 0, iobuf->data, iob_len ( iobuf ) );
		rc = -EINVAL;
		goto err;
	}

	/* Strip header and CRC */
	header = iobuf->data;
	iob_pull ( iobuf, sizeof ( *header ) );
	iob_unput ( iobuf, 4 /* CRC */ );

	/* Check for errors */
	if ( header->command & cpu_to_le32 ( SMSC95XX_RX_RUNT |
					     SMSC95XX_RX_LATE |
					     SMSC95XX_RX_CRC ) ) {
		DBGC ( smsc95xx, "SMSC95XX %p receive error (%08x):\n",
		       smsc95xx, le32_to_cpu ( header->command ) );
		DBGC_HDA ( smsc95xx, 0, iobuf->data, iob_len ( iobuf ) );
		rc = -EIO;
		goto err;
	}

	/* Hand off to network stack */
	netdev_rx ( netdev, iob_disown ( iobuf ) );

	profile_stop ( &smsc95xx_in_profiler );
	return;

 err:
	/* Hand off to network stack */
	netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
}
示例#8
0
文件: legacy.c 项目: B-Rich/serialice
static int legacy_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
    struct nic *nic = netdev->priv;
    struct ethhdr *ethhdr;

    DBG ( "Transmitting %zd bytes\n", iob_len ( iobuf ) );
    iob_pad ( iobuf, ETH_ZLEN );
    ethhdr = iobuf->data;
    iob_pull ( iobuf, sizeof ( *ethhdr ) );
    nic->nic_op->transmit ( nic, ( const char * ) ethhdr->h_dest,
                            ntohs ( ethhdr->h_protocol ),
                            iob_len ( iobuf ), iobuf->data );
    netdev_tx_complete ( netdev, iobuf );
    return 0;
}
示例#9
0
/** 
 * e1000_transmit - Transmit a packet
 *
 * @v netdev	Network device
 * @v iobuf	I/O buffer
 *
 * @ret rc       Returns 0 on success, negative on failure
 */
static int
e1000_transmit ( struct net_device *netdev, struct io_buffer *iobuf )
{
	struct e1000_adapter *adapter = netdev_priv( netdev );
	struct e1000_hw *hw = &adapter->hw;
	uint32_t tx_curr = adapter->tx_tail;
	struct e1000_tx_desc *tx_curr_desc;

	DBG ("e1000_transmit\n");
	
	if ( adapter->tx_fill_ctr == NUM_TX_DESC ) {
		DBG ("TX overflow\n");
		return -ENOBUFS;
	}

	/* Save pointer to iobuf we have been given to transmit,
	   netdev_tx_complete() will need it later
	 */
	adapter->tx_iobuf[tx_curr] = iobuf;

	tx_curr_desc = ( void * ) ( adapter->tx_base ) + 
		       ( tx_curr * sizeof ( *adapter->tx_base ) ); 

	DBG ( "tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) );
	DBG ( "tx_curr_desc + 16 = %#08lx\n", virt_to_bus ( tx_curr_desc ) + 16 );
	DBG ( "iobuf->data = %#08lx\n", virt_to_bus ( iobuf->data ) );

	/* Add the packet to TX ring
	 */
 	tx_curr_desc->buffer_addr = 
		virt_to_bus ( iobuf->data );
	tx_curr_desc->lower.data = 
		E1000_TXD_CMD_RPS  | E1000_TXD_CMD_EOP |
		E1000_TXD_CMD_IFCS | iob_len ( iobuf );
	tx_curr_desc->upper.data = 0;
	
	DBG ( "TX fill: %d tx_curr: %d addr: %#08lx len: %zd\n", adapter->tx_fill_ctr, 
	      tx_curr, virt_to_bus ( iobuf->data ), iob_len ( iobuf ) );
	      
	/* Point to next free descriptor */
	adapter->tx_tail = ( adapter->tx_tail + 1 ) % NUM_TX_DESC;
	adapter->tx_fill_ctr++;

	/* Write new tail to NIC, making packet available for transmit
	 */
	wmb();
	E1000_WRITE_REG ( hw, TDT, adapter->tx_tail );

	return 0;
}
示例#10
0
文件: dm96xx.c 项目: dell-asm-ci/ipxe
/**
 * Complete bulk IN transfer
 *
 * @v ep		USB endpoint
 * @v iobuf		I/O buffer
 * @v rc		Completion status code
 */
static void dm96xx_in_complete ( struct usb_endpoint *ep,
				 struct io_buffer *iobuf, int rc ) {
	struct dm96xx_device *dm96xx = container_of ( ep, struct dm96xx_device,
						      usbnet.in );
	struct net_device *netdev = dm96xx->netdev;
	struct dm96xx_rx_header *header;

	/* Ignore packets cancelled when the endpoint closes */
	if ( ! ep->open ) {
		free_iob ( iobuf );
		return;
	}

	/* Record USB errors against the network device */
	if ( rc != 0 ) {
		DBGC ( dm96xx, "DM96XX %p bulk IN failed: %s\n",
		       dm96xx, strerror ( rc ) );
		goto err;
	}

	/* Sanity check */
	if ( iob_len ( iobuf ) < ( sizeof ( *header ) + 4 /* CRC */ ) ) {
		DBGC ( dm96xx, "DM96XX %p underlength bulk IN\n", dm96xx );
		DBGC_HDA ( dm96xx, 0, iobuf->data, iob_len ( iobuf ) );
		rc = -EINVAL;
		goto err;
	}

	/* Strip header and CRC */
	header = iobuf->data;
	iob_pull ( iobuf, sizeof ( *header ) );
	iob_unput ( iobuf, 4 /* CRC */ );

	/* Check status */
	if ( header->rsr & ~DM96XX_RSR_MF ) {
		DBGC ( dm96xx, "DM96XX %p receive error %02x:\n",
		       dm96xx, header->rsr );
		DBGC_HDA ( dm96xx, 0, iobuf->data, iob_len ( iobuf ) );
		rc = -EIO;
		goto err;
	}

	/* Hand off to network stack */
	netdev_rx ( netdev, iob_disown ( iobuf ) );
	return;

 err:
	/* Hand off to network stack */
	netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
}
示例#11
0
文件: gdbudp.c 项目: 3a9LL/panda
static void gdbudp_send ( const char *buf, size_t len ) {
	struct io_buffer *iob;
	struct ethhdr *ethhdr;
	struct iphdr *iphdr;
	struct udp_header *udphdr;

	/* Check that we are connected */
	if ( dest_addr.sin_port == 0 ) {
		return;
	}

	gdbudp_ensure_netdev_open ( netdev );

	iob = alloc_iob ( sizeof ( *ethhdr ) + sizeof ( *iphdr ) + sizeof ( *udphdr ) + len );
	if ( !iob ) {
		return;
	}

	/* Payload */
	iob_reserve ( iob, sizeof ( *ethhdr ) + sizeof ( *iphdr ) + sizeof ( *udphdr ) );
	memcpy ( iob_put ( iob, len ), buf, len );

	/* UDP header */
	udphdr = iob_push ( iob, sizeof ( *udphdr ) );
	udphdr->src = source_addr.sin_port;
	udphdr->dest = dest_addr.sin_port;
	udphdr->len = htons ( iob_len ( iob ) );
	udphdr->chksum = 0; /* optional and we are not using it */

	/* IP header */
	iphdr = iob_push ( iob, sizeof ( *iphdr ) );
	memset ( iphdr, 0, sizeof ( *iphdr ) );
	iphdr->verhdrlen = ( IP_VER | ( sizeof ( *iphdr ) / 4 ) );
	iphdr->service = IP_TOS;
	iphdr->len = htons ( iob_len ( iob ) );	
	iphdr->ttl = IP_TTL;
	iphdr->protocol = IP_UDP;
	iphdr->dest.s_addr = dest_addr.sin_addr.s_addr;
	iphdr->src.s_addr = source_addr.sin_addr.s_addr;
	iphdr->chksum = tcpip_chksum ( iphdr, sizeof ( *iphdr ) );

	/* Ethernet header */
	ethhdr = iob_push ( iob, sizeof ( *ethhdr ) );
	memcpy ( ethhdr->h_dest, dest_eth, ETH_ALEN );
	memcpy ( ethhdr->h_source, netdev->ll_addr, ETH_ALEN );
	ethhdr->h_protocol = htons ( ETH_P_IP );

	netdev_tx ( netdev, iob );
}
示例#12
0
文件: b44.c 项目: 1stMaster/syslinux
/** Transmit packet
 *
 * @v netdev	Network device
 * @v iobuf	I/O buffer
 * @ret rc	Return status code
 */
static int b44_transmit(struct net_device *netdev, struct io_buffer *iobuf)
{
	struct b44_private *bp = netdev_priv(netdev);
	u32 cur = bp->tx_cur;
	u32 ctrl;

	/* Check for TX ring overflow */
	if (bp->tx[cur].ctrl) {
		DBG("tx overflow\n");
		return -ENOBUFS;
	}

	/* Will call netdev_tx_complete() on the iobuf later */
	bp->tx_iobuf[cur] = iobuf;

	/* Set up TX descriptor */
	ctrl = (iob_len(iobuf) & DESC_CTRL_LEN) |
	    DESC_CTRL_IOC | DESC_CTRL_SOF | DESC_CTRL_EOF;

	if (cur == B44_RING_LAST)
		ctrl |= DESC_CTRL_EOT;

	bp->tx[cur].ctrl = cpu_to_le32(ctrl);
	bp->tx[cur].addr = cpu_to_le32(VIRT_TO_B44(iobuf->data));

	/* Update next available descriptor index */
	cur = ring_next(cur);
	bp->tx_cur = cur;
	wmb();

	/* Tell card that a new TX descriptor is ready */
	bw32(bp, B44_DMATX_PTR, cur * sizeof(struct dma_desc));
	return 0;
}
示例#13
0
文件: acm.c 项目: dell-asm-ci/ipxe
/**
 * Transmit packet
 *
 * @v rndis		RNDIS device
 * @v iobuf		I/O buffer
 * @ret rc		Return status code
 */
static int acm_transmit ( struct rndis_device *rndis,
			  struct io_buffer *iobuf ) {
	struct acm_device *acm = rndis->priv;
	struct rndis_header *header = iobuf->data;

	/* Sanity check */
	assert ( iob_len ( iobuf ) >= sizeof ( *header ) );
	assert ( iob_len ( iobuf ) == le32_to_cpu ( header->len ) );

	/* Transmit packet via appropriate mechanism */
	if ( header->type == cpu_to_le32 ( RNDIS_PACKET_MSG ) ) {
		return acm_out_transmit ( acm, iobuf );
	} else {
		return acm_control_transmit ( acm, iobuf );
	}
}
示例#14
0
文件: eth_slow.c 项目: 3a9LL/panda
/**
 * Dump LACP packet
 *
 * @v iobuf		I/O buffer
 * @v netdev		Network device
 * @v label		"RX" or "TX"
 */
static void eth_slow_lacp_dump ( struct io_buffer *iobuf,
				 struct net_device *netdev,
				 const char *label ) {
	union eth_slow_packet *eth_slow = iobuf->data;
	struct eth_slow_lacp *lacp = &eth_slow->lacp;

	DBGC ( netdev,
	       "SLOW %s %s LACP actor (%04x,%s,%04x,%02x,%04x) [%s]\n",
	       netdev->name, label, ntohs ( lacp->actor.system_priority ),
	       eth_ntoa ( lacp->actor.system ),
	       ntohs ( lacp->actor.key ),
	       ntohs ( lacp->actor.port_priority ),
	       ntohs ( lacp->actor.port ),
	       eth_slow_lacp_state_name ( lacp->actor.state ) );
	DBGC ( netdev,
	       "SLOW %s %s LACP partner (%04x,%s,%04x,%02x,%04x) [%s]\n",
	       netdev->name, label, ntohs ( lacp->partner.system_priority ),
	       eth_ntoa ( lacp->partner.system ),
	       ntohs ( lacp->partner.key ),
	       ntohs ( lacp->partner.port_priority ),
	       ntohs ( lacp->partner.port ),
	       eth_slow_lacp_state_name ( lacp->partner.state ) );
	DBGC ( netdev, "SLOW %s %s LACP collector %04x (%d us)\n",
	       netdev->name, label, ntohs ( lacp->collector.max_delay ),
	       ( ntohs ( lacp->collector.max_delay ) * 10 ) );
	DBGC2_HDA ( netdev, 0, iobuf->data, iob_len ( iobuf ) );
}
示例#15
0
文件: xfer.c 项目: baloo/ipxe
/**
 * Deliver datagram
 *
 * @v intf		Data transfer interface
 * @v iobuf		Datagram I/O buffer
 * @v meta		Data transfer metadata
 * @ret rc		Return status code
 */
int xfer_deliver ( struct interface *intf,
		   struct io_buffer *iobuf,
		   struct xfer_metadata *meta ) {
	struct interface *dest;
	xfer_deliver_TYPE ( void * ) *op =
		intf_get_dest_op ( intf, xfer_deliver, &dest );
	void *object = intf_object ( dest );
	int rc;

	DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " deliver %zd\n",
	       INTF_INTF_DBG ( intf, dest ), iob_len ( iobuf ) );

	if ( op ) {
		rc = op ( object, iobuf, meta );
	} else {
		/* Default is to discard the I/O buffer */
		free_iob ( iobuf );
		rc = -EPIPE;
	}

	if ( rc != 0 ) {
		DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT
		       " deliver failed: %s\n",
		       INTF_INTF_DBG ( intf, dest ), strerror ( rc ) );
	}

	intf_put ( dest );
	return rc;
}
示例#16
0
文件: nii.c 项目: baloo/ipxe
/**
 * Transmit packet
 *
 * @v netdev		Network device
 * @v iobuf		I/O buffer
 * @ret rc		Return status code
 */
static int nii_transmit ( struct net_device *netdev,
			  struct io_buffer *iobuf ) {
	struct nii_nic *nii = netdev->priv;
	PXE_CPB_TRANSMIT cpb;
	int stat;
	int rc;

	/* Defer the packet if there is already a transmission in progress */
	if ( nii->txbuf ) {
		netdev_tx_defer ( netdev, iobuf );
		return 0;
	}

	/* Construct parameter block */
	memset ( &cpb, 0, sizeof ( cpb ) );
	cpb.FrameAddr = virt_to_bus ( iobuf->data );
	cpb.DataLen = iob_len ( iobuf );
	cpb.MediaheaderLen = netdev->ll_protocol->ll_header_len;

	/* Transmit packet */
	if ( ( stat = nii_issue_cpb ( nii, PXE_OPCODE_TRANSMIT, &cpb,
				      sizeof ( cpb ) ) ) < 0 ) {
		rc = -EIO_STAT ( stat );
		DBGC ( nii, "NII %s could not transmit: %s\n",
		       nii->dev.name, strerror ( rc ) );
		return rc;
	}
	nii->txbuf = iobuf;

	return 0;
}
示例#17
0
/**
 * Handle received data
 *
 * @v downloader	Downloader
 * @v iobuf		Datagram I/O buffer
 * @v meta		Data transfer metadata
 * @ret rc		Return status code
 */
static int downloader_xfer_deliver ( struct downloader *downloader,
				     struct io_buffer *iobuf,
				     struct xfer_metadata *meta ) {
	size_t len;
	size_t max;
	int rc;

	/* Calculate new buffer position */
	if ( meta->flags & XFER_FL_ABS_OFFSET )
		downloader->pos = 0;
	downloader->pos += meta->offset;

	/* Ensure that we have enough buffer space for this data */
	len = iob_len ( iobuf );
	max = ( downloader->pos + len );
	if ( ( rc = downloader_ensure_size ( downloader, max ) ) != 0 )
		goto done;

	/* Copy data to buffer */
	copy_to_user ( downloader->image->data, downloader->pos,
		       iobuf->data, len );

	/* Update current buffer position */
	downloader->pos += len;

 done:
	free_iob ( iobuf );
	if ( rc != 0 )
		downloader_finished ( downloader, rc );
	return rc;
}
示例#18
0
文件: srp.c 项目: 1stMaster/syslinux
/**
 * Transmit SRP SCSI command
 *
 * @v srp		SRP device
 */
static void srp_cmd ( struct srp_device *srp ) {
	struct io_buffer *iobuf;
	struct srp_cmd *cmd;
	struct srp_memory_descriptor *data_out;
	struct srp_memory_descriptor *data_in;
	int rc;

	assert ( srp->state & SRP_STATE_LOGGED_IN );

	/* Allocate I/O buffer */
	iobuf = xfer_alloc_iob ( &srp->socket, SRP_MAX_I_T_IU_LEN );
	if ( ! iobuf ) {
		rc = -ENOMEM;
		goto err;
	}

	/* Construct base portion */
	cmd = iob_put ( iobuf, sizeof ( *cmd ) );
	memset ( cmd, 0, sizeof ( *cmd ) );
	cmd->type = SRP_CMD;
	cmd->tag.dwords[1] = htonl ( ++srp_tag );
	cmd->lun = srp->lun;
	memcpy ( &cmd->cdb, &srp->command->cdb, sizeof ( cmd->cdb ) );

	/* Construct data-out descriptor, if present */
	if ( srp->command->data_out ) {
		cmd->data_buffer_formats |= SRP_CMD_DO_FMT_DIRECT;
		data_out = iob_put ( iobuf, sizeof ( *data_out ) );
		data_out->address =
		    cpu_to_be64 ( user_to_phys ( srp->command->data_out, 0 ) );
		data_out->handle = ntohl ( srp->memory_handle );
		data_out->len = ntohl ( srp->command->data_out_len );
	}

	/* Construct data-in descriptor, if present */
	if ( srp->command->data_in ) {
		cmd->data_buffer_formats |= SRP_CMD_DI_FMT_DIRECT;
		data_in = iob_put ( iobuf, sizeof ( *data_in ) );
		data_in->address =
		     cpu_to_be64 ( user_to_phys ( srp->command->data_in, 0 ) );
		data_in->handle = ntohl ( srp->memory_handle );
		data_in->len = ntohl ( srp->command->data_in_len );
	}

	DBGC2 ( srp, "SRP %p TX SCSI command tag %08x%08x\n", srp,
		ntohl ( cmd->tag.dwords[0] ), ntohl ( cmd->tag.dwords[1] ) );
	DBGC2_HDA ( srp, 0, iobuf->data, iob_len ( iobuf ) );

	/* Send IU */
	if ( ( rc = xfer_deliver_iob ( &srp->socket, iobuf ) ) != 0 ) {
		DBGC ( srp, "SRP %p could not send command: %s\n",
		       srp, strerror ( rc ) );
		goto err;
	}

	return;

 err:
	srp_fail ( srp, rc );
}
示例#19
0
文件: efi_download.c 项目: 42wim/ipxe
/**
 * Process received data
 *
 * @v file		Data transfer file
 * @v iobuf		I/O buffer
 * @v meta		Data transfer metadata
 * @ret rc		Return status code
 */
static int efi_download_deliver_iob ( struct efi_download_file *file,
				      struct io_buffer *iobuf,
				      struct xfer_metadata *meta ) {
	EFI_STATUS efirc;
	size_t len = iob_len ( iobuf );
	int rc;

	/* Calculate new buffer position */
	if ( meta->flags & XFER_FL_ABS_OFFSET )
		file->pos = 0;
	file->pos += meta->offset;

	/* Call out to the data handler */
	if ( ( efirc = file->data_callback ( file->context, iobuf->data,
					     len, file->pos ) ) != 0 ) {
		rc = -EEFI ( efirc );
		goto err_callback;
	}

	/* Update current buffer position */
	file->pos += len;

	/* Success */
	rc = 0;

 err_callback:
	free_iob ( iobuf );
	return rc;
}
示例#20
0
文件: snpnet.c 项目: eatnumber1/ipxe
/**
 * Transmit packet
 *
 * @v netdev		Network device
 * @v iobuf		I/O buffer
 * @ret rc		Return status code
 */
static int snpnet_transmit ( struct net_device *netdev,
                             struct io_buffer *iobuf ) {
    struct snp_nic *snp = netdev_priv ( netdev );
    EFI_STATUS efirc;
    int rc;

    /* Defer the packet if there is already a transmission in progress */
    if ( snp->txbuf ) {
        netdev_tx_defer ( netdev, iobuf );
        return 0;
    }

    /* Transmit packet */
    if ( ( efirc = snp->snp->Transmit ( snp->snp, 0, iob_len ( iobuf ),
                                        iobuf->data, NULL, NULL,
                                        NULL ) ) != 0 ) {
        rc = -EEFI ( efirc );
        DBGC ( snp, "SNP %s could not transmit: %s\n",
               netdev->name, strerror ( rc ) );
        return rc;
    }
    snp->txbuf = iobuf;

    return 0;
}
示例#21
0
/**
 * Add received data to data transfer buffer
 *
 * @v xferbuf		Data transfer buffer
 * @v iobuf		I/O buffer
 * @v meta		Data transfer metadata
 * @ret rc		Return status code
 */
int xferbuf_deliver ( struct xfer_buffer *xferbuf, struct io_buffer *iobuf,
		      struct xfer_metadata *meta ) {
	size_t len = iob_len ( iobuf );
	size_t pos;
	int rc;

	/* Start profiling */
	profile_start ( &xferbuf_deliver_profiler );

	/* Calculate new buffer position */
	pos = xferbuf->pos;
	if ( meta->flags & XFER_FL_ABS_OFFSET )
		pos = 0;
	pos += meta->offset;

	/* Write data to buffer */
	if ( ( rc = xferbuf_write ( xferbuf, pos, iobuf->data, len ) ) != 0 )
		goto done;

	/* Update current buffer position */
	xferbuf->pos = ( pos + len );

 done:
	free_iob ( iobuf );
	profile_stop ( &xferbuf_deliver_profiler );
	return rc;
}
示例#22
0
文件: srp.c 项目: 1stMaster/syslinux
/**
 * Handle SRP SCSI response
 *
 * @v srp		SRP device
 * @v iobuf		I/O buffer
 * @ret rc		Returns status code
 */
static int srp_rsp ( struct srp_device *srp, struct io_buffer *iobuf ) {
	struct srp_rsp *rsp = iobuf->data;
	int rc;

	DBGC2 ( srp, "SRP %p RX SCSI response tag %08x%08x\n", srp,
		ntohl ( rsp->tag.dwords[0] ), ntohl ( rsp->tag.dwords[1] ) );

	/* Sanity check */
	if ( iob_len ( iobuf ) < sizeof ( *rsp ) ) {
		DBGC ( srp, "SRP %p RX SCSI response too short (%zd bytes)\n",
		       srp, iob_len ( iobuf ) );
		rc = -EINVAL;
		goto out;
	}

	/* Report SCSI errors */
	if ( rsp->status != 0 ) {
		DBGC ( srp, "SRP %p response status %02x\n",
		       srp, rsp->status );
		if ( srp_rsp_sense_data ( rsp ) ) {
			DBGC ( srp, "SRP %p sense data:\n", srp );
			DBGC_HDA ( srp, 0, srp_rsp_sense_data ( rsp ),
				   srp_rsp_sense_data_len ( rsp ) );
		}
	}
	if ( rsp->valid & ( SRP_RSP_VALID_DOUNDER | SRP_RSP_VALID_DOOVER ) ) {
		DBGC ( srp, "SRP %p response data-out %srun by %#x bytes\n",
		       srp, ( ( rsp->valid & SRP_RSP_VALID_DOUNDER )
			      ? "under" : "over" ),
		       ntohl ( rsp->data_out_residual_count ) );
	}
	if ( rsp->valid & ( SRP_RSP_VALID_DIUNDER | SRP_RSP_VALID_DIOVER ) ) {
		DBGC ( srp, "SRP %p response data-in %srun by %#x bytes\n",
		       srp, ( ( rsp->valid & SRP_RSP_VALID_DIUNDER )
			      ? "under" : "over" ),
		       ntohl ( rsp->data_in_residual_count ) );
	}
	srp->command->status = rsp->status;

	/* Mark SCSI command as complete */
	srp_scsi_done ( srp, 0 );

	rc = 0;
 out:
	free_iob ( iobuf );
	return rc;
}
示例#23
0
/**
 * Transmit packet
 *
 * @v netdev		Network device
 * @v iobuf		I/O buffer
 * @ret rc		Return status code
 */
static int myson_transmit ( struct net_device *netdev,
			    struct io_buffer *iobuf ) {
	struct myson_nic *myson = netdev->priv;
	struct myson_descriptor *tx;
	unsigned int tx_idx;
	physaddr_t address;

	/* Check address is usable by card */
	address = virt_to_bus ( iobuf->data );
	if ( ! myson_address_ok ( address ) ) {
		DBGC ( myson, "MYSON %p cannot support 64-bit TX buffer "
		       "address\n", myson );
		return -ENOTSUP;
	}

	/* Get next transmit descriptor */
	if ( ( myson->tx.prod - myson->tx.cons ) >= MYSON_NUM_TX_DESC ) {
		DBGC ( myson, "MYSON %p out of transmit descriptors\n",
		       myson );
		return -ENOBUFS;
	}
	tx_idx = ( myson->tx.prod++ % MYSON_NUM_TX_DESC );
	tx = &myson->tx.desc[tx_idx];

	/* Populate transmit descriptor */
	tx->address = cpu_to_le32 ( address );
	tx->control = cpu_to_le32 ( MYSON_TX_CTRL_IC | MYSON_TX_CTRL_LD |
				    MYSON_TX_CTRL_FD | MYSON_TX_CTRL_CRC |
				    MYSON_TX_CTRL_PAD | MYSON_TX_CTRL_RTLC |
				    MYSON_TX_CTRL_PKTS ( iob_len ( iobuf ) ) |
				    MYSON_TX_CTRL_TBS ( iob_len ( iobuf ) ) );
	wmb();
	tx->status = cpu_to_le32 ( MYSON_TX_STAT_OWN );
	wmb();

	/* Notify card that there are packets ready to transmit */
	writel ( 0, myson->regs + MYSON_TXPDR );

	DBGC2 ( myson, "MYSON %p TX %d is [%llx,%llx)\n", myson, tx_idx,
		( ( unsigned long long ) address ),
		( ( unsigned long long ) address + iob_len ( iobuf ) ) );

	return 0;
}
示例#24
0
static int rtl818x_tx(struct net80211_device *dev, struct io_buffer *iob)
{
	struct rtl818x_priv *priv = dev->priv;
	struct rtl818x_tx_desc *entry;
	u32 tx_flags;
	u16 plcp_len = 0;
	int len = iob_len(iob);

	tx_flags = RTL818X_TX_DESC_FLAG_OWN | RTL818X_TX_DESC_FLAG_FS |
		RTL818X_TX_DESC_FLAG_LS | (priv->hw_rate << 24) | len;

	if (priv->r8185) {
		tx_flags |= RTL818X_TX_DESC_FLAG_DMA |
			    RTL818X_TX_DESC_FLAG_NO_ENC;
	} else {
		unsigned int remainder;

		plcp_len = DIV_ROUND_UP(16 * (len + 4),
					(dev->rates[dev->rate] * 2) / 10);
		remainder = (16 * (len + 4)) %
			    ((dev->rates[dev->rate] * 2) / 10);

		if (remainder > 0 && remainder <= 6)
			plcp_len |= 1 << 15;
	}

	entry = &priv->tx_ring[priv->tx_prod];

	if (dev->phy_flags & NET80211_PHY_USE_PROTECTION) {
		tx_flags |= RTL818X_TX_DESC_FLAG_CTS;
		tx_flags |= priv->hw_rtscts_rate << 19;
		entry->rts_duration = net80211_cts_duration(dev, len);
	} else {
		entry->rts_duration = 0;
	}

	if (entry->flags & RTL818X_TX_DESC_FLAG_OWN) {
		/* card hasn't processed the old packet yet! */
		return -EBUSY;
	}

	priv->tx_buf[priv->tx_prod] = iob;
	priv->tx_prod = (priv->tx_prod + 1) % RTL818X_TX_RING_SIZE;

	entry->plcp_len = cpu_to_le16(plcp_len);
	entry->tx_buf = cpu_to_le32(virt_to_bus(iob->data));
	entry->frame_len = cpu_to_le32(len);
	entry->flags2 = /* alternate retry rate in 100kbps << 4 */ 0;
	entry->retry_limit = RTL818X_MAX_RETRIES;
	entry->flags = cpu_to_le32(tx_flags);

	rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << 5));

	return 0;
}
示例#25
0
/**
 * Complete interrupt transfer
 *
 * @v ep		USB endpoint
 * @v iobuf		I/O buffer
 * @v rc		Completion status code
 */
static void smsc95xx_intr_complete ( struct usb_endpoint *ep,
				     struct io_buffer *iobuf, int rc ) {
	struct smsc95xx_device *smsc95xx =
		container_of ( ep, struct smsc95xx_device, usbnet.intr );
	struct net_device *netdev = smsc95xx->netdev;
	struct smsc95xx_interrupt *intr;

	/* Profile completions */
	profile_start ( &smsc95xx_intr_profiler );

	/* Ignore packets cancelled when the endpoint closes */
	if ( ! ep->open )
		goto done;

	/* Record USB errors against the network device */
	if ( rc != 0 ) {
		DBGC ( smsc95xx, "SMSC95XX %p interrupt failed: %s\n",
		       smsc95xx, strerror ( rc ) );
		DBGC_HDA ( smsc95xx, 0, iobuf->data, iob_len ( iobuf ) );
		netdev_rx_err ( netdev, NULL, rc );
		goto done;
	}

	/* Extract interrupt data */
	if ( iob_len ( iobuf ) != sizeof ( *intr ) ) {
		DBGC ( smsc95xx, "SMSC95XX %p malformed interrupt\n",
		       smsc95xx );
		DBGC_HDA ( smsc95xx, 0, iobuf->data, iob_len ( iobuf ) );
		netdev_rx_err ( netdev, NULL, rc );
		goto done;
	}
	intr = iobuf->data;

	/* Record interrupt status */
	smsc95xx->int_sts = le32_to_cpu ( intr->int_sts );
	profile_stop ( &smsc95xx_intr_profiler );

 done:
	/* Free I/O buffer */
	free_iob ( iobuf );
}
示例#26
0
文件: netfront.c 项目: pipcet/ipxe
/**
 * Transmit packet
 *
 * @v netdev		Network device
 * @v iobuf		I/O buffer
 * @ret rc		Return status code
 */
static int netfront_transmit ( struct net_device *netdev,
			       struct io_buffer *iobuf ) {
	struct netfront_nic *netfront = netdev->priv;
	struct xen_device *xendev = netfront->xendev;
	struct netif_tx_request *request;
	int notify;
	int rc;

	/* Check that we have space in the ring */
	if ( netfront_ring_is_full ( &netfront->tx ) ) {
		DBGC ( netfront, "NETFRONT %s out of transmit descriptors\n",
		       xendev->key );
		return -ENOBUFS;
	}

	/* Add to descriptor ring */
	request = RING_GET_REQUEST ( &netfront->tx_fring,
				     netfront->tx_fring.req_prod_pvt );
	if ( ( rc = netfront_push ( netfront, &netfront->tx, iobuf,
				    &request->id, &request->gref ) ) != 0 ) {
		return rc;
	}
	request->offset = ( virt_to_phys ( iobuf->data ) & ( PAGE_SIZE - 1 ) );
	request->flags = NETTXF_data_validated;
	request->size = iob_len ( iobuf );
	DBGC2 ( netfront, "NETFRONT %s TX id %d ref %d is %#08lx+%zx\n",
		xendev->key, request->id, request->gref,
		virt_to_phys ( iobuf->data ), iob_len ( iobuf ) );

	/* Consume descriptor */
	netfront->tx_fring.req_prod_pvt++;

	/* Push new descriptor and notify backend if applicable */
	RING_PUSH_REQUESTS_AND_CHECK_NOTIFY ( &netfront->tx_fring, notify );
	if ( notify )
		netfront_send_event ( netfront );

	return 0;
}
示例#27
0
文件: eth_slow.c 项目: 3a9LL/panda
/**
 * Dump marker packet
 *
 * @v iobuf		I/O buffer
 * @v netdev		Network device
 * @v label		"RX" or "TX"
 */
static void eth_slow_marker_dump ( struct io_buffer *iobuf,
				   struct net_device *netdev,
				   const char *label ) {
	union eth_slow_packet *eth_slow = iobuf->data;
	struct eth_slow_marker *marker = &eth_slow->marker;

	DBGC ( netdev, "SLOW %s %s marker %s port %04x system %s xact %08x\n",
	       netdev->name, label,
	       eth_slow_marker_tlv_name ( marker->marker.tlv.type ),
	       ntohs ( marker->marker.port ),
	       eth_ntoa ( marker->marker.system ),
	       ntohl ( marker->marker.xact ) );
	DBGC2_HDA ( netdev, 0, iobuf->data, iob_len ( iobuf ) );
}
示例#28
0
文件: dm96xx.c 项目: dell-asm-ci/ipxe
/**
 * Complete interrupt transfer
 *
 * @v ep		USB endpoint
 * @v iobuf		I/O buffer
 * @v rc		Completion status code
 */
static void dm96xx_intr_complete ( struct usb_endpoint *ep,
				   struct io_buffer *iobuf, int rc ) {
	struct dm96xx_device *dm96xx = container_of ( ep, struct dm96xx_device,
						      usbnet.intr );
	struct net_device *netdev = dm96xx->netdev;
	struct dm96xx_interrupt *intr;
	size_t len = iob_len ( iobuf );

	/* Ignore packets cancelled when the endpoint closes */
	if ( ! ep->open )
		goto done;

	/* Record USB errors against the network device */
	if ( rc != 0 ) {
		DBGC ( dm96xx, "DM96XX %p interrupt failed: %s\n",
		       dm96xx, strerror ( rc ) );
		DBGC_HDA ( dm96xx, 0, iobuf->data, iob_len ( iobuf ) );
		netdev_rx_err ( netdev, NULL, rc );
		goto done;
	}

	/* Extract message header */
	if ( len < sizeof ( *intr ) ) {
		DBGC ( dm96xx, "DM96XX %p underlength interrupt:\n", dm96xx );
		DBGC_HDA ( dm96xx, 0, iobuf->data, iob_len ( iobuf ) );
		netdev_rx_err ( netdev, NULL, -EINVAL );
		goto done;
	}
	intr = iobuf->data;

	/* Update link status */
	dm96xx_link_nsr ( dm96xx, intr->nsr );

 done:
	/* Free I/O buffer */
	free_iob ( iobuf );
}
示例#29
0
文件: srp.c 项目: 1stMaster/syslinux
/**
 * Initiate SRP login
 *
 * @v srp		SRP device
 */
static void srp_login ( struct srp_device *srp ) {
	struct io_buffer *iobuf;
	struct srp_login_req *login_req;
	int rc;

	assert ( ! ( srp->state & SRP_STATE_SOCKET_OPEN ) );

	/* Open underlying socket */
	if ( ( rc = srp->transport->connect ( srp ) ) != 0 ) {
		DBGC ( srp, "SRP %p could not open socket: %s\n",
		       srp, strerror ( rc ) );
		goto err;
	}
	srp->state |= SRP_STATE_SOCKET_OPEN;

	/* Allocate I/O buffer */
	iobuf = xfer_alloc_iob ( &srp->socket, sizeof ( *login_req ) );
	if ( ! iobuf ) {
		rc = -ENOMEM;
		goto err;
	}

	/* Construct login request IU */
	login_req = iob_put ( iobuf, sizeof ( *login_req ) );
	memset ( login_req, 0, sizeof ( *login_req ) );
	login_req->type = SRP_LOGIN_REQ;
	login_req->tag.dwords[1] = htonl ( ++srp_tag );
	login_req->max_i_t_iu_len = htonl ( SRP_MAX_I_T_IU_LEN );
	login_req->required_buffer_formats = SRP_LOGIN_REQ_FMT_DDBD;
	memcpy ( &login_req->port_ids, &srp->port_ids,
		 sizeof ( login_req->port_ids ) );

	DBGC2 ( srp, "SRP %p TX login request tag %08x%08x\n",
		srp, ntohl ( login_req->tag.dwords[0] ),
		ntohl ( login_req->tag.dwords[1] ) );
	DBGC2_HDA ( srp, 0, iobuf->data, iob_len ( iobuf ) );

	/* Send login request IU */
	if ( ( rc = xfer_deliver_iob ( &srp->socket, iobuf ) ) != 0 ) {
		DBGC ( srp, "SRP %p could not send login request: %s\n",
		       srp, strerror ( rc ) );
		goto err;
	}

	return;

 err:
	srp_fail ( srp, rc );
}
示例#30
0
文件: pxe_udp.c 项目: 3a9LL/panda
/**
 * Receive PXE UDP data
 *
 * @v pxe_udp			PXE UDP connection
 * @v iobuf			I/O buffer
 * @v meta			Data transfer metadata
 * @ret rc			Return status code
 *
 * Receives a packet as part of the current pxenv_udp_read()
 * operation.
 */
static int pxe_udp_deliver ( struct pxe_udp_connection *pxe_udp,
			     struct io_buffer *iobuf,
			     struct xfer_metadata *meta ) {
	struct s_PXENV_UDP_READ *pxenv_udp_read = pxe_udp->pxenv_udp_read;
	struct sockaddr_in *sin_src;
	struct sockaddr_in *sin_dest;
	userptr_t buffer;
	size_t len;
	int rc = 0;

	if ( ! pxenv_udp_read ) {
		DBG ( "PXE discarded UDP packet\n" );
		rc = -ENOBUFS;
		goto done;
	}

	/* Copy packet to buffer and record length */
	buffer = real_to_user ( pxenv_udp_read->buffer.segment,
				pxenv_udp_read->buffer.offset );
	len = iob_len ( iobuf );
	if ( len > pxenv_udp_read->buffer_size )
		len = pxenv_udp_read->buffer_size;
	copy_to_user ( buffer, 0, iobuf->data, len );
	pxenv_udp_read->buffer_size = len;

	/* Fill in source/dest information */
	assert ( meta );
	sin_src = ( struct sockaddr_in * ) meta->src;
	assert ( sin_src );
	assert ( sin_src->sin_family == AF_INET );
	pxenv_udp_read->src_ip = sin_src->sin_addr.s_addr;
	pxenv_udp_read->s_port = sin_src->sin_port;
	sin_dest = ( struct sockaddr_in * ) meta->dest;
	assert ( sin_dest );
	assert ( sin_dest->sin_family == AF_INET );
	pxenv_udp_read->dest_ip = sin_dest->sin_addr.s_addr;
	pxenv_udp_read->d_port = sin_dest->sin_port;

	/* Mark as received */
	pxe_udp->pxenv_udp_read = NULL;

 done:
	free_iob ( iobuf );
	return rc;
}