/**
 * 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;
}
Exemple #2
0
/**
 * 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 );
}
Exemple #3
0
/**
 * Look up media-specific link-layer address in the ARP cache
 *
 * @v netdev		Network device
 * @v net_protocol	Network-layer protocol
 * @v dest_net_addr	Destination network-layer address
 * @v source_net_addr	Source network-layer address
 * @ret dest_ll_addr	Destination link layer address
 * @ret rc		Return status code
 *
 * This function will use the ARP cache to look up the link-layer
 * address for the link-layer protocol associated with the network
 * device and the given network-layer protocol and addresses.  If
 * found, the destination link-layer address will be filled in in @c
 * dest_ll_addr.
 *
 * If no address is found in the ARP cache, an ARP request will be
 * transmitted on the specified network device and -ENOENT will be
 * returned.
 */
int arp_resolve ( struct net_device *netdev, struct net_protocol *net_protocol,
		  const void *dest_net_addr, const void *source_net_addr,
		  void *dest_ll_addr ) {
	struct ll_protocol *ll_protocol = netdev->ll_protocol;
	const struct arp_entry *arp;
	struct io_buffer *iobuf;
	struct arphdr *arphdr;
	int rc;

	/* Look for existing entry in ARP table */
	arp = arp_find_entry ( ll_protocol, net_protocol, dest_net_addr );
	if ( arp ) {
		DBG ( "ARP cache hit: %s %s => %s %s\n",
		      net_protocol->name, net_protocol->ntoa ( arp->net_addr ),
		      ll_protocol->name, ll_protocol->ntoa ( arp->ll_addr ) );
		memcpy ( dest_ll_addr, arp->ll_addr, ll_protocol->ll_addr_len);
		return 0;
	}
	DBG ( "ARP cache miss: %s %s\n", net_protocol->name,
	      net_protocol->ntoa ( dest_net_addr ) );

	/* Allocate ARP packet */
	iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *arphdr ) +
			  2 * ( MAX_LL_ADDR_LEN + MAX_NET_ADDR_LEN ) );
	if ( ! iobuf )
		return -ENOMEM;
	iob_reserve ( iobuf, MAX_LL_HEADER_LEN );

	/* Build up ARP request */
	arphdr = iob_put ( iobuf, sizeof ( *arphdr ) );
	arphdr->ar_hrd = ll_protocol->ll_proto;
	arphdr->ar_hln = ll_protocol->ll_addr_len;
	arphdr->ar_pro = net_protocol->net_proto;
	arphdr->ar_pln = net_protocol->net_addr_len;
	arphdr->ar_op = htons ( ARPOP_REQUEST );
	memcpy ( iob_put ( iobuf, ll_protocol->ll_addr_len ),
		 netdev->ll_addr, ll_protocol->ll_addr_len );
	memcpy ( iob_put ( iobuf, net_protocol->net_addr_len ),
		 source_net_addr, net_protocol->net_addr_len );
	memset ( iob_put ( iobuf, ll_protocol->ll_addr_len ),
		 0, ll_protocol->ll_addr_len );
	memcpy ( iob_put ( iobuf, net_protocol->net_addr_len ),
		 dest_net_addr, net_protocol->net_addr_len );

	/* Transmit ARP request */
	if ( ( rc = net_tx ( iobuf, netdev, &arp_protocol,
			     netdev->ll_broadcast, netdev->ll_addr ) ) != 0 )
		return rc;

	return -ENOENT;
}
Exemple #4
0
/**
 * 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 );
	}
Exemple #5
0
/**
 * Add a file handle to the end of an I/O buffer
 *
 * @v io_buf            I/O buffer
 * @v fh                File handle
 * @ret size            Size of the data written
 */
size_t nfs_iob_add_fh ( struct io_buffer *io_buf, const struct nfs_fh *fh ) {
	size_t s;

	s = oncrpc_iob_add_int ( io_buf, fh->size );
	memcpy ( iob_put ( io_buf, fh->size ), &fh->fh, fh->size );

	return s + fh->size;
}
Exemple #6
0
/**
 * Transmit NDP packet with link-layer address option
 *
 * @v netdev		Network device
 * @v sin6_src		Source socket address
 * @v sin6_dest		Destination socket address
 * @v data		NDP header
 * @v len		Size of NDP header
 * @v option_type	NDP option type
 * @ret rc		Return status code
 */
static int ndp_tx_ll_addr ( struct net_device *netdev,
			    struct sockaddr_in6 *sin6_src,
			    struct sockaddr_in6 *sin6_dest,
			    const void *data, size_t len,
			    unsigned int option_type ) {
	struct sockaddr_tcpip *st_src =
		( ( struct sockaddr_tcpip * ) sin6_src );
	struct sockaddr_tcpip *st_dest =
		( ( struct sockaddr_tcpip * ) sin6_dest );
	struct ll_protocol *ll_protocol = netdev->ll_protocol;
	struct io_buffer *iobuf;
	struct ndp_ll_addr_option *ll_addr_opt;
	union ndp_header *ndp;
	size_t option_len;
	int rc;

	/* Allocate and populate buffer */
	option_len = ( ( sizeof ( *ll_addr_opt ) +
			 ll_protocol->ll_addr_len + NDP_OPTION_BLKSZ - 1 ) &
		       ~( NDP_OPTION_BLKSZ - 1 ) );
	iobuf = alloc_iob ( MAX_LL_NET_HEADER_LEN + len + option_len );
	if ( ! iobuf )
		return -ENOMEM;
	iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN );
	memcpy ( iob_put ( iobuf, len ), data, len );
	ll_addr_opt = iob_put ( iobuf, option_len );
	ll_addr_opt->header.type = option_type;
	ll_addr_opt->header.blocks = ( option_len / NDP_OPTION_BLKSZ );
	memcpy ( ll_addr_opt->ll_addr, netdev->ll_addr,
		 ll_protocol->ll_addr_len );
	ndp = iobuf->data;
	ndp->icmp.chksum = tcpip_chksum ( ndp, ( len + option_len ) );

	/* Transmit packet */
	if ( ( rc = tcpip_tx ( iobuf, &icmpv6_protocol, st_src, st_dest,
			       netdev, &ndp->icmp.chksum ) ) != 0 ) {
		DBGC ( netdev, "NDP could not transmit packet: %s\n",
		       strerror ( rc ) );
		return rc;
	}

	return 0;
}
Exemple #7
0
/**
 * e1000_process_rx_packets - process received packets
 *
 * @v netdev	network interface device structure
 **/
static void e1000e_process_rx_packets ( struct net_device *netdev )
{
	struct e1000_adapter *adapter = netdev_priv ( netdev );
	uint32_t i;
	uint32_t rx_status;
	uint32_t rx_len;
	uint32_t rx_err;
	struct e1000_rx_desc *rx_curr_desc;

	/* Process received packets
	 */
	while ( 1 ) {

		i = adapter->rx_curr;

		rx_curr_desc = ( void * )  ( adapter->rx_base ) +
				  ( i * sizeof ( *adapter->rx_base ) );
		rx_status = rx_curr_desc->status;

		DBG2 ( "Before DD Check RX_status: %#08x\n", rx_status );

		if ( ! ( rx_status & E1000_RXD_STAT_DD ) )
			break;

		if ( adapter->rx_iobuf[i] == NULL )
			break;

		DBG ( "E1000_RCTL = %#08x\n", E1000_READ_REG ( &adapter->hw, E1000_RCTL ) );

		rx_len = rx_curr_desc->length;

		DBG ( "Received packet, rx_curr: %d  rx_status: %#08x  rx_len: %d\n",
		      i, rx_status, rx_len );

		rx_err = rx_curr_desc->errors;

		iob_put ( adapter->rx_iobuf[i], rx_len );

		if ( rx_err & E1000_RXD_ERR_FRAME_ERR_MASK ) {

			netdev_rx_err ( netdev, adapter->rx_iobuf[i], -EINVAL );
			DBG ( "e1000_poll: Corrupted packet received!"
			      " rx_err: %#08x\n", rx_err );
		} else	{
			/* Add this packet to the receive queue. */
			netdev_rx ( netdev, adapter->rx_iobuf[i] );
		}
		adapter->rx_iobuf[i] = NULL;

		memset ( rx_curr_desc, 0, sizeof ( *rx_curr_desc ) );

		adapter->rx_curr = ( adapter->rx_curr + 1 ) % NUM_RX_DESC;
	}
}
Exemple #8
0
static void rtl818x_handle_rx(struct net80211_device *dev)
{
	struct rtl818x_priv *priv = dev->priv;
	unsigned int count = RTL818X_RX_RING_SIZE;

	while (count--) {
		struct rtl818x_rx_desc *entry = &priv->rx_ring[priv->rx_idx];
		struct io_buffer *iob = priv->rx_buf[priv->rx_idx];
		u32 flags = le32_to_cpu(entry->flags);

		if (flags & RTL818X_RX_DESC_FLAG_OWN)
			return;

		if (flags & (RTL818X_RX_DESC_FLAG_DMA_FAIL |
			     RTL818X_RX_DESC_FLAG_FOF |
			     RTL818X_RX_DESC_FLAG_RX_ERR)) {
			/* This is crappy hardware. The Linux driver
			   doesn't even log these. */
			goto done;
		} else if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR) {
			/* This is actually a corrupt packet. */
			DBG2("rtl818x RX:%d CRC fail: flags %08x\n",
			     priv->rx_idx, flags);
			net80211_rx_err(dev, NULL, EIO);
		} else {
			u32 flags2 = le32_to_cpu(entry->flags2);
			struct io_buffer *new_iob = alloc_iob(MAX_RX_SIZE);
			if (!new_iob) {
				net80211_rx_err(dev, NULL, ENOMEM);
				goto done;
			}

			DBGP("rtl818x RX:%d success: flags %08x %08x\n",
			     priv->rx_idx, flags, flags2);

			iob_put(iob, flags & 0xFFF);

			net80211_rx(dev, iob, (flags2 >> 8) & 0x7f,
				    rtl818x_rates[(flags >> 20) & 0xf]);

			iob = new_iob;
			priv->rx_buf[priv->rx_idx] = iob;
		}

	done:
		entry->rx_buf = cpu_to_le32(virt_to_bus(iob->data));
		entry->flags = cpu_to_le32(RTL818X_RX_DESC_FLAG_OWN | MAX_RX_SIZE);

		if (priv->rx_idx == RTL818X_RX_RING_SIZE - 1)
			entry->flags |= cpu_to_le32(RTL818X_RX_DESC_FLAG_EOR);

		priv->rx_idx = (priv->rx_idx + 1) % RTL818X_RX_RING_SIZE;
	}
}
Exemple #9
0
/**
 * Deliver datagram as raw data
 *
 * @v intf		Data transfer interface
 * @v data		Data
 * @v len		Length of data
 * @v meta		Data transfer metadata
 * @ret rc		Return status code
 */
int xfer_deliver_raw_meta ( struct interface *intf, const void *data,
			    size_t len, struct xfer_metadata *meta ) {
	struct io_buffer *iobuf;

	iobuf = xfer_alloc_iob ( intf, len );
	if ( ! iobuf )
		return -ENOMEM;

	memcpy ( iob_put ( iobuf, len ), data, len );
	return xfer_deliver ( intf, iobuf, meta );
}
Exemple #10
0
static void b44_process_rx_packets(struct b44_private *bp)
{
	struct io_buffer *iob;	/* received data */
	struct rx_header *rh;
	u32 pending, i;
	u16 len;

	pending = pending_rx_index(bp);

	for (i = bp->rx_cur; i != pending; i = ring_next(i)) {
		iob = bp->rx_iobuf[i];
		if (iob == NULL)
			break;

		rh = iob->data;
		len = le16_to_cpu(rh->len);

		/*
		 * Guard against incompletely written RX descriptors.
		 * Without this, things can get really slow!
		 */
		if (len == 0)
			break;

		/* Discard CRC that is generated by the card */
		len -= 4;

		/* Check for invalid packets and errors */
		if (len > RX_PKT_BUF_SZ - RX_PKT_OFFSET ||
		    (rh->flags & cpu_to_le16(RX_FLAG_ERRORS))) {
			DBG("rx error len=%d flags=%04x\n", len,
			                 cpu_to_le16(rh->flags));
			rh->len = 0;
			rh->flags = 0;
			netdev_rx_err(bp->netdev, iob, -EINVAL);
			continue;
		}

		/* Clear RX descriptor */
		rh->len = 0;
		rh->flags = 0;
		bp->rx_iobuf[i] = NULL;

		/* Hand off the IO buffer to the network stack */
		iob_reserve(iob, RX_PKT_OFFSET);
		iob_put(iob, len);
		netdev_rx(bp->netdev, iob);
	}
	bp->rx_cur = i;
	b44_rx_refill(bp, pending_rx_index(bp));
}
Exemple #11
0
/**
 * Transmit NDP neighbour solicitation/advertisement packet
 *
 * @v netdev		Network device
 * @v sin6_src		Source socket address
 * @v sin6_dest		Destination socket address
 * @v target		Neighbour target address
 * @v icmp_type		ICMPv6 type
 * @v flags		NDP flags
 * @v option_type	NDP option type
 * @ret rc		Return status code
 */
static int ndp_tx_neighbour ( struct net_device *netdev,
			      struct sockaddr_in6 *sin6_src,
			      struct sockaddr_in6 *sin6_dest,
			      const struct in6_addr *target,
			      unsigned int icmp_type,
			      unsigned int flags,
			      unsigned int option_type ) {
	struct sockaddr_tcpip *st_src =
		( ( struct sockaddr_tcpip * ) sin6_src );
	struct sockaddr_tcpip *st_dest =
		( ( struct sockaddr_tcpip * ) sin6_dest );
	struct ll_protocol *ll_protocol = netdev->ll_protocol;
	struct io_buffer *iobuf;
	struct ndp_neighbour_header *neigh;
	struct ndp_ll_addr_option *ll_addr_opt;
	size_t option_len;
	size_t len;
	int rc;

	/* Allocate and populate buffer */
	option_len = ( ( sizeof ( *ll_addr_opt ) +
			 ll_protocol->ll_addr_len + NDP_OPTION_BLKSZ - 1 ) &
		       ~( NDP_OPTION_BLKSZ - 1 ) );
	len = ( sizeof ( *neigh ) + option_len );
	iobuf = alloc_iob ( MAX_LL_NET_HEADER_LEN + len );
	if ( ! iobuf )
		return -ENOMEM;
	iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN );
	neigh = iob_put ( iobuf, len );
	memset ( neigh, 0, len );
	neigh->icmp.type = icmp_type;
	neigh->flags = flags;
	memcpy ( &neigh->target, target, sizeof ( neigh->target ) );
	ll_addr_opt = &neigh->option[0].ll_addr;
	ll_addr_opt->header.type = option_type;
	ll_addr_opt->header.blocks = ( option_len / NDP_OPTION_BLKSZ );
	memcpy ( ll_addr_opt->ll_addr, netdev->ll_addr,
		 ll_protocol->ll_addr_len );
	neigh->icmp.chksum = tcpip_chksum ( neigh, len );

	/* Transmit packet */
	if ( ( rc = tcpip_tx ( iobuf, &icmpv6_protocol, st_src, st_dest,
			       netdev, &neigh->icmp.chksum ) ) != 0 ) {
		DBGC ( netdev, "NDP could not transmit packet: %s\n",
		       strerror ( rc ) );
		return rc;
	}

	return 0;
}
Exemple #12
0
Fichier : nii.c Projet : baloo/ipxe
/**
 * Poll for received packets
 *
 * @v netdev		Network device
 */
static void nii_poll_rx ( struct net_device *netdev ) {
	struct nii_nic *nii = netdev->priv;
	PXE_CPB_RECEIVE cpb;
	PXE_DB_RECEIVE db;
	unsigned int quota;
	int stat;
	int rc;

	/* Retrieve up to NII_RX_QUOTA packets */
	for ( quota = NII_RX_QUOTA ; quota ; quota-- ) {

		/* Allocate buffer, if required */
		if ( ! nii->rxbuf ) {
			nii->rxbuf = alloc_iob ( nii->mtu );
			if ( ! nii->rxbuf ) {
				/* Leave for next poll */
				break;
			}
		}

		/* Construct parameter block */
		memset ( &cpb, 0, sizeof ( cpb ) );
		cpb.BufferAddr = virt_to_bus ( nii->rxbuf->data );
		cpb.BufferLen = iob_tailroom ( nii->rxbuf );

		/* Issue command */
		if ( ( stat = nii_issue_cpb_db ( nii, PXE_OPCODE_RECEIVE,
						 &cpb, sizeof ( cpb ),
						 &db, sizeof ( db ) ) ) < 0 ) {

			/* PXE_STATCODE_NO_DATA is just the usual "no packet"
			 * status indicator; ignore it.
			 */
			if ( stat == -PXE_STATCODE_NO_DATA )
				break;

			/* Anything else is an error */
			rc = -EIO_STAT ( stat );
			DBGC ( nii, "NII %s could not receive: %s\n",
			       nii->dev.name, strerror ( rc ) );
			netdev_rx_err ( netdev, NULL, rc );
			break;
		}

		/* Hand off to network stack */
		iob_put ( nii->rxbuf, db.FrameLen );
		netdev_rx ( netdev, nii->rxbuf );
		nii->rxbuf = NULL;
	}
}
Exemple #13
0
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 );
}
Exemple #14
0
/**
 * 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 );
}
Exemple #15
0
static void legacy_poll ( struct net_device *netdev ) {
    struct nic *nic = netdev->priv;
    struct io_buffer *iobuf;

    iobuf = alloc_iob ( ETH_FRAME_LEN );
    if ( ! iobuf )
        return;

    nic->packet = iobuf->data;
    if ( nic->nic_op->poll ( nic, 1 ) ) {
        DBG ( "Received %d bytes\n", nic->packetlen );
        iob_put ( iobuf, nic->packetlen );
        netdev_rx ( netdev, iobuf );
    } else {
        free_iob ( iobuf );
    }
}
Exemple #16
0
/**
 * Receive control packet
 *
 * @v acm		USB RNDIS device
 * @ret rc		Return status code
 */
static int acm_control_receive ( struct acm_device *acm ) {
	struct rndis_device *rndis = acm->rndis;
	struct usb_device *usb = acm->usb;
	struct io_buffer *iobuf;
	struct rndis_header *header;
	size_t mtu = ACM_RESPONSE_MTU;
	size_t len;
	int rc;

	/* Allocate I/O buffer */
	iobuf = alloc_iob ( mtu );
	if ( ! iobuf ) {
		rc = -ENOMEM;
		goto err_alloc;
	}

	/* Get encapsulated response */
	if ( ( rc = cdc_get_encapsulated_response ( usb, acm->usbnet.comms,
						    iobuf->data, mtu ) ) != 0 ){
		DBGC ( acm, "ACM %p could not get encapsulated response: %s\n",
		       acm, strerror ( rc ) );
		goto err_get_response;
	}

	/* Fix up buffer length */
	header = iobuf->data;
	len = le32_to_cpu ( header->len );
	if ( len > mtu ) {
		DBGC ( acm, "ACM %p overlength encapsulated response\n", acm );
		DBGC_HDA ( acm, 0, iobuf->data, mtu );
		rc = -EPROTO;
		goto err_len;
	}
	iob_put ( iobuf, len );

	/* Hand off to RNDIS */
	rndis_rx ( rndis, iob_disown ( iobuf ) );

	return 0;

 err_len:
 err_get_response:
	free_iob ( iobuf );
 err_alloc:
	return rc;
}
Exemple #17
0
/**
 * Poll for received packets
 *
 * @v netdev		Network device
 */
static void snpnet_poll_rx ( struct net_device *netdev ) {
    struct snp_nic *snp = netdev->priv;
    UINTN len;
    unsigned int quota;
    EFI_STATUS efirc;
    int rc;

    /* Retrieve up to SNP_RX_QUOTA packets */
    for ( quota = SNP_RX_QUOTA ; quota ; quota-- ) {

        /* Allocate buffer, if required */
        if ( ! snp->rxbuf ) {
            snp->rxbuf = alloc_iob ( snp->mtu );
            if ( ! snp->rxbuf ) {
                /* Leave for next poll */
                break;
            }
        }

        /* Receive packet */
        len = iob_tailroom ( snp->rxbuf );
        if ( ( efirc = snp->snp->Receive ( snp->snp, NULL, &len,
                                           snp->rxbuf->data, NULL,
                                           NULL, NULL ) ) != 0 ) {

            /* EFI_NOT_READY is just the usual "no packet"
             * status indication; ignore it.
             */
            if ( efirc == EFI_NOT_READY )
                break;

            /* Anything else is an error */
            rc = -EEFI ( efirc );
            DBGC ( snp, "SNP %s could not receive: %s\n",
                   netdev->name, strerror ( rc ) );
            netdev_rx_err ( netdev, NULL, rc );
            break;
        }

        /* Hand off to network stack */
        iob_put ( snp->rxbuf, len );
        netdev_rx ( netdev, snp->rxbuf );
        snp->rxbuf = NULL;
    }
}
Exemple #18
0
/** Poll for new packets */
static void af_packet_nic_poll ( struct net_device *netdev )
{
	struct af_packet_nic * nic = netdev->priv;
	struct pollfd pfd;
	struct io_buffer * iobuf;
	int r;

	pfd.fd = nic->fd;
	pfd.events = POLLIN;
	if (linux_poll(&pfd, 1, 0) == -1) {
		DBGC(nic, "af_packet %p poll failed (%s)\n",
		     nic, linux_strerror(linux_errno));
		return;
	}
	if ((pfd.revents & POLLIN) == 0)
		return;

	/* At this point we know there is at least one new packet to be read */

	iobuf = alloc_iob(RX_BUF_SIZE);
	if (! iobuf)
		goto allocfail;

	while ((r = linux_read(nic->fd, iobuf->data, RX_BUF_SIZE)) > 0) {
		DBGC2(nic, "af_packet %p read %d bytes\n", nic, r);

		iob_put(iobuf, r);
		netdev_rx(netdev, iobuf);

		iobuf = alloc_iob(RX_BUF_SIZE);
		if (! iobuf)
			goto allocfail;
	}

	free_iob(iobuf);
	return;

allocfail:
	DBGC(nic, "af_packet %p alloc_iob failed\n", nic);
}
Exemple #19
0
/**
 * Poll for received packets
 *
 * @v netdev		Network device
 */
static void rhine_poll_rx ( struct net_device *netdev ) {
	struct rhine_nic *rhn = netdev->priv;
	struct rhine_descriptor *desc;
	struct io_buffer *iobuf;
	unsigned int rx_idx;
	uint32_t des0;
	size_t len;

	/* Check for received packets */
	while ( rhn->rx.cons != rhn->rx.prod ) {

		/* Get next receive descriptor */
		rx_idx = ( rhn->rx.cons % RHINE_RXDESC_NUM );
		desc = &rhn->rx.desc[rx_idx];

		/* Stop if descriptor is still in use */
		if ( desc->des0 & cpu_to_le32 ( RHINE_DES0_OWN ) )
			return;

		/* Populate I/O buffer */
		iobuf = rhn->rx_iobuf[rx_idx];
		rhn->rx_iobuf[rx_idx] = NULL;
		des0 = le32_to_cpu ( desc->des0 );
		len = ( RHINE_DES0_GETSIZE ( des0 ) - 4 /* strip CRC */ );
		iob_put ( iobuf, len );

		/* Hand off to network stack */
		if ( des0 & RHINE_RDES0_RXOK ) {
			DBGC2 ( rhn, "RHINE %p RX %d complete (length %zd)\n",
				rhn, rx_idx, len );
			netdev_rx ( netdev, iobuf );
		} else {
			DBGC ( rhn, "RHINE %p RX %d error (length %zd, DES0 "
			       "%08x)\n", rhn, rx_idx, len, des0 );
			netdev_rx_err ( netdev, iobuf, -EIO );
		}
		rhn->rx.cons++;
	}
}
Exemple #20
0
/**
 * Poll for received packets
 *
 * @v netdev		Network device
 */
static void myson_poll_rx ( struct net_device *netdev ) {
	struct myson_nic *myson = netdev->priv;
	struct myson_descriptor *rx;
	struct io_buffer *iobuf;
	unsigned int rx_idx;
	size_t len;

	/* Check for received packets */
	while ( myson->rx.cons != myson->rx.prod ) {

		/* Get next receive descriptor */
		rx_idx = ( myson->rx.cons % MYSON_NUM_RX_DESC );
		rx = &myson->rx.desc[rx_idx];

		/* Stop if descriptor is still in use */
		if ( rx->status & MYSON_RX_STAT_OWN )
			return;

		/* Populate I/O buffer */
		iobuf = myson->rx_iobuf[rx_idx];
		myson->rx_iobuf[rx_idx] = NULL;
		len = MYSON_RX_STAT_FLNG ( le32_to_cpu ( rx->status ) );
		iob_put ( iobuf, len - 4 /* strip CRC */ );

		/* Hand off to network stack */
		if ( rx->status & cpu_to_le32 ( MYSON_RX_STAT_ES ) ) {
			DBGC ( myson, "MYSON %p RX %d error (length %zd, "
			       "status %08x)\n", myson, rx_idx, len,
			       le32_to_cpu ( rx->status ) );
			netdev_rx_err ( netdev, iobuf, -EIO );
		} else {
			DBGC2 ( myson, "MYSON %p RX %d complete (length "
				"%zd)\n", myson, rx_idx, len );
			netdev_rx ( netdev, iobuf );
		}
		myson->rx.cons++;
	}
}
Exemple #21
0
/**
 * Poll for received packets
 *
 * @v netdev		Network device
 */
static void netfront_poll_rx ( struct net_device *netdev ) {
	struct netfront_nic *netfront = netdev->priv;
	struct xen_device *xendev = netfront->xendev;
	struct netif_rx_response *response;
	struct io_buffer *iobuf;
	int status;
	size_t len;
	int rc;

	/* Consume any unconsumed responses */
	while ( RING_HAS_UNCONSUMED_RESPONSES ( &netfront->rx_fring ) ) {

		/* Get next response */
		response = RING_GET_RESPONSE ( &netfront->rx_fring,
					       netfront->rx_fring.rsp_cons++ );

		/* Retrieve from descriptor ring */
		iobuf = netfront_pull ( netfront, &netfront->rx, response->id );
		status = response->status;
		if ( status >= 0 ) {
			len = status;
			iob_reserve ( iobuf, response->offset );
			iob_put ( iobuf, len );
			DBGC2 ( netfront, "NETFRONT %s RX id %d complete "
				"%#08lx+%zx\n", xendev->key, response->id,
				virt_to_phys ( iobuf->data ), len );
			netdev_rx ( netdev, iobuf );
		} else {
			rc = -EIO_NETIF_RSP ( status );
			DBGC2 ( netfront, "NETFRONT %s RX id %d error %d: %s\n",
				xendev->key, response->id, status,
				strerror ( rc ) );
			netdev_rx_err ( netdev, iobuf, rc );
		}
	}
}
Exemple #22
0
/* PXENV_UNDI_TRANSMIT
 *
 * Status: working
 */
static PXENV_EXIT_t
pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT *undi_transmit ) {
	struct s_PXENV_UNDI_TBD tbd;
	struct DataBlk *datablk;
	struct io_buffer *iobuf;
	struct net_protocol *net_protocol;
	struct ll_protocol *ll_protocol;
	char destaddr[MAX_LL_ADDR_LEN];
	const void *ll_dest;
	size_t len;
	unsigned int i;
	int rc;

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

	/* Sanity check */
	if ( ! pxe_netdev ) {
		DBGC ( &pxe_netdev, "PXENV_UNDI_TRANSMIT called with no "
		       "network device\n" );
		undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_STATE;
		return PXENV_EXIT_FAILURE;
	}

	DBGC2 ( &pxe_netdev, "PXENV_UNDI_TRANSMIT" );

	/* Forcibly enable interrupts and freeze receive queue
	 * processing at this point, to work around callers that never
	 * call PXENV_UNDI_OPEN before attempting to use the UNDI API.
	 */
	if ( ! netdev_rx_frozen ( pxe_netdev ) ) {
		netdev_rx_freeze ( pxe_netdev );
		netdev_irq ( pxe_netdev, 1 );
	}

	/* Identify network-layer protocol */
	switch ( undi_transmit->Protocol ) {
	case P_IP:	net_protocol = &ipv4_protocol;	break;
	case P_ARP:	net_protocol = &arp_protocol;	break;
	case P_RARP:	net_protocol = &rarp_protocol;	break;
	case P_UNKNOWN:
		net_protocol = NULL;
		break;
	default:
		DBGC2 ( &pxe_netdev, " %02x invalid protocol\n",
			undi_transmit->Protocol );
		undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
		return PXENV_EXIT_FAILURE;
	}
	DBGC2 ( &pxe_netdev, " %s",
		( net_protocol ? net_protocol->name : "RAW" ) );

	/* Calculate total packet length */
	copy_from_real ( &tbd, undi_transmit->TBD.segment,
			 undi_transmit->TBD.offset, sizeof ( tbd ) );
	len = tbd.ImmedLength;
	DBGC2 ( &pxe_netdev, " %04x:%04x+%x", tbd.Xmit.segment, tbd.Xmit.offset,
		tbd.ImmedLength );
	for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) {
		datablk = &tbd.DataBlock[i];
		len += datablk->TDDataLen;
		DBGC2 ( &pxe_netdev, " %04x:%04x+%x",
			datablk->TDDataPtr.segment, datablk->TDDataPtr.offset,
			datablk->TDDataLen );
	}

	/* Allocate and fill I/O buffer */
	iobuf = alloc_iob ( MAX_LL_HEADER_LEN +
			    ( ( len > IOB_ZLEN ) ? len : IOB_ZLEN ) );
	if ( ! iobuf ) {
		DBGC2 ( &pxe_netdev, " could not allocate iobuf\n" );
		undi_transmit->Status = PXENV_STATUS_OUT_OF_RESOURCES;
		return PXENV_EXIT_FAILURE;
	}
	iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
	copy_from_real ( iob_put ( iobuf, tbd.ImmedLength ), tbd.Xmit.segment,
			 tbd.Xmit.offset, tbd.ImmedLength );
	for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) {
		datablk = &tbd.DataBlock[i];
		copy_from_real ( iob_put ( iobuf, datablk->TDDataLen ),
				 datablk->TDDataPtr.segment,
				 datablk->TDDataPtr.offset,
				 datablk->TDDataLen );
	}

	/* Add link-layer header, if required to do so */
	if ( net_protocol != NULL ) {

		/* Calculate destination address */
		ll_protocol = pxe_netdev->ll_protocol;
		if ( undi_transmit->XmitFlag == XMT_DESTADDR ) {
			copy_from_real ( destaddr,
					 undi_transmit->DestAddr.segment,
					 undi_transmit->DestAddr.offset,
					 ll_protocol->ll_addr_len );
			ll_dest = destaddr;
			DBGC2 ( &pxe_netdev, " DEST %s",
				ll_protocol->ntoa ( ll_dest ) );
		} else {
			ll_dest = pxe_netdev->ll_broadcast;
			DBGC2 ( &pxe_netdev, " BCAST" );
		}

		/* Add link-layer header */
		if ( ( rc = ll_protocol->push ( pxe_netdev, iobuf, ll_dest,
						pxe_netdev->ll_addr,
						net_protocol->net_proto ))!=0){
			DBGC2 ( &pxe_netdev, " could not add link-layer "
				"header: %s\n", strerror ( rc ) );
			free_iob ( iobuf );
			undi_transmit->Status = PXENV_STATUS ( rc );
			return PXENV_EXIT_FAILURE;
		}
	}

	/* Flag transmission as in-progress.  Do this before starting
	 * to transmit the packet, because the ISR may trigger before
	 * we return from netdev_tx().
	 */
	undi_tx_count++;

	/* Transmit packet */
	DBGC2 ( &pxe_netdev, "\n" );
	if ( ( rc = netdev_tx ( pxe_netdev, iobuf ) ) != 0 ) {
		DBGC2 ( &pxe_netdev, "PXENV_UNDI_TRANSMIT could not transmit: "
			"%s\n", strerror ( rc ) );
		undi_tx_count--;
		undi_transmit->Status = PXENV_STATUS ( rc );
		return PXENV_EXIT_FAILURE;
	}

	profile_stop ( &undi_tx_profiler );
	undi_transmit->Status = PXENV_STATUS_SUCCESS;
	return PXENV_EXIT_SUCCESS;
}
Exemple #23
0
/** 
 * e1000_poll - Poll for received packets
 *
 * @v netdev	Network device
 */
static void
e1000_poll ( struct net_device *netdev )
{
	struct e1000_adapter *adapter = netdev_priv( netdev );
	struct e1000_hw *hw = &adapter->hw;

	uint32_t icr;
	uint32_t tx_status;
	uint32_t rx_status;
	uint32_t rx_len;
	uint32_t rx_err;
	struct e1000_tx_desc *tx_curr_desc;
	struct e1000_rx_desc *rx_curr_desc;
	uint32_t i;

	DBGP ( "e1000_poll\n" );

	/* Acknowledge interrupts */
	icr = E1000_READ_REG ( hw, ICR );
	if ( ! icr )
		return;
		
        DBG ( "e1000_poll: intr_status = %#08x\n", icr );

	/* Check status of transmitted packets
	 */
	while ( ( i = adapter->tx_head ) != adapter->tx_tail ) {
			
		tx_curr_desc = ( void * )  ( adapter->tx_base ) + 
					   ( i * sizeof ( *adapter->tx_base ) ); 
					    		
		tx_status = tx_curr_desc->upper.data;

		/* if the packet at tx_head is not owned by hardware it is for us */
		if ( ! ( tx_status & E1000_TXD_STAT_DD ) )
			break;
		
		DBG ( "Sent packet. tx_head: %d tx_tail: %d tx_status: %#08x\n",
	    	      adapter->tx_head, adapter->tx_tail, tx_status );

		if ( tx_status & ( E1000_TXD_STAT_EC | E1000_TXD_STAT_LC | 
				   E1000_TXD_STAT_TU ) ) {
			netdev_tx_complete_err ( netdev, adapter->tx_iobuf[i], -EINVAL );
			DBG ( "Error transmitting packet, tx_status: %#08x\n",
			      tx_status );
		} else {
			netdev_tx_complete ( netdev, adapter->tx_iobuf[i] );
			DBG ( "Success transmitting packet, tx_status: %#08x\n",
			      tx_status );
		}

		/* Decrement count of used descriptors, clear this descriptor 
		 */
		adapter->tx_fill_ctr--;
		memset ( tx_curr_desc, 0, sizeof ( *tx_curr_desc ) );
		
		adapter->tx_head = ( adapter->tx_head + 1 ) % NUM_TX_DESC;		
	}
	
	/* Process received packets 
	 */
	while ( 1 ) {
	
		i = adapter->rx_curr;
		
		rx_curr_desc = ( void * )  ( adapter->rx_base ) + 
			          ( i * sizeof ( *adapter->rx_base ) ); 
		rx_status = rx_curr_desc->status;
		
		DBG2 ( "Before DD Check RX_status: %#08x\n", rx_status );
	
		if ( ! ( rx_status & E1000_RXD_STAT_DD ) )
			break;

		if ( adapter->rx_iobuf[i] == NULL )
			break;

		DBG ( "RCTL = %#08x\n", E1000_READ_REG ( &adapter->hw, RCTL ) );
	
		rx_len = rx_curr_desc->length;

                DBG ( "Received packet, rx_curr: %d  rx_status: %#08x  rx_len: %d\n",
                      i, rx_status, rx_len );

                rx_err = rx_curr_desc->errors;

		iob_put ( adapter->rx_iobuf[i], rx_len );

		if ( rx_err & E1000_RXD_ERR_FRAME_ERR_MASK ) {
		
			netdev_rx_err ( netdev, adapter->rx_iobuf[i], -EINVAL );
			DBG ( "e1000_poll: Corrupted packet received!"
			      " rx_err: %#08x\n", rx_err );
		} else 	{
			/* Add this packet to the receive queue. */
			netdev_rx ( netdev, adapter->rx_iobuf[i] );
		}
		adapter->rx_iobuf[i] = NULL;

		memset ( rx_curr_desc, 0, sizeof ( *rx_curr_desc ) );

		adapter->rx_curr = ( adapter->rx_curr + 1 ) % NUM_RX_DESC;
	}
	e1000_refill_rx_ring(adapter);
}
Exemple #24
0
/**
 * Send AoE command
 *
 * @v aoe		AoE session
 * @ret rc		Return status code
 *
 * This transmits an AoE command packet.  It does not wait for a
 * response.
 */
static int aoe_send_command ( struct aoe_session *aoe ) {
	struct ata_command *command = aoe->command;
	struct io_buffer *iobuf;
	struct aoehdr *aoehdr;
	union aoecmd *aoecmd;
	struct aoeata *aoeata;
	unsigned int count;
	unsigned int data_out_len;
	unsigned int aoecmdlen;

	/* Fail immediately if we have no netdev to send on */
	if ( ! aoe->netdev ) {
		aoe_done ( aoe, -ENETUNREACH );
		return -ENETUNREACH;
	}

	/* If we are transmitting anything that requires a response,
         * start the retransmission timer.  Do this before attempting
         * to allocate the I/O buffer, in case allocation itself
         * fails.
         */
	start_timer ( &aoe->timer );

	/* Calculate count and data_out_len for this subcommand */
	switch ( aoe->aoe_cmd_type ) {
	case AOE_CMD_ATA:
		count = command->cb.count.native;
		if ( count > AOE_MAX_COUNT )
			count = AOE_MAX_COUNT;
		data_out_len = ( command->data_out ?
				 ( count * ATA_SECTOR_SIZE ) : 0 );
		aoecmdlen = sizeof ( aoecmd->ata );
		break;
	case AOE_CMD_CONFIG:
		count = 0;
		data_out_len = 0;
		aoecmdlen = sizeof ( aoecmd->cfg );
		break;
	default:
		return -ENOTSUP;
	}

	/* Create outgoing I/O buffer */
	iobuf = alloc_iob ( ETH_HLEN + sizeof ( *aoehdr ) +
			    aoecmdlen + data_out_len );

	if ( ! iobuf )
		return -ENOMEM;
	iob_reserve ( iobuf, ETH_HLEN );
	aoehdr = iob_put ( iobuf, sizeof ( *aoehdr ) );
	aoecmd = iob_put ( iobuf, aoecmdlen );
	memset ( aoehdr, 0, ( sizeof ( *aoehdr ) + aoecmdlen ) );

	/* Fill AoE header */
	aoehdr->ver_flags = AOE_VERSION;
	aoehdr->major = htons ( aoe->major );
	aoehdr->minor = aoe->minor;
	aoehdr->command = aoe->aoe_cmd_type;
	aoehdr->tag = htonl ( ++aoe->tag );

	/* Fill AoE payload */
	switch ( aoe->aoe_cmd_type ) {
	case AOE_CMD_ATA:
		/* Fill AoE command */
		aoeata = &aoecmd->ata;
		linker_assert ( AOE_FL_DEV_HEAD	== ATA_DEV_SLAVE,
				__fix_ata_h__ );
		aoeata->aflags = ( ( command->cb.lba48 ? AOE_FL_EXTENDED : 0 )|
				   ( command->cb.device & ATA_DEV_SLAVE ) |
				   ( data_out_len ? AOE_FL_WRITE : 0 ) );
		aoeata->err_feat = command->cb.err_feat.bytes.cur;
		aoeata->count = count;
		aoeata->cmd_stat = command->cb.cmd_stat;
		aoeata->lba.u64 = cpu_to_le64 ( command->cb.lba.native );
		if ( ! command->cb.lba48 )
			aoeata->lba.bytes[3] |=
				( command->cb.device & ATA_DEV_MASK );

		/* Fill data payload */
		copy_from_user ( iob_put ( iobuf, data_out_len ),
				 command->data_out, aoe->command_offset,
				 data_out_len );
		break;
	case AOE_CMD_CONFIG:
		/* Nothing to do */
		break;
	default:
		assert ( 0 );
	}

	/* Send packet */
	return net_tx ( iobuf, aoe->netdev, &aoe_protocol, aoe->target );
}
Exemple #25
0
/**
 * UDP WRITE
 *
 * @v pxenv_udp_write			Pointer to a struct s_PXENV_UDP_WRITE
 * @v s_PXENV_UDP_WRITE::ip		Destination IP address
 * @v s_PXENV_UDP_WRITE::gw		Relay agent IP address, or 0.0.0.0
 * @v s_PXENV_UDP_WRITE::src_port	Source UDP port, or 0
 * @v s_PXENV_UDP_WRITE::dst_port	Destination UDP port
 * @v s_PXENV_UDP_WRITE::buffer_size	Length of the UDP payload
 * @v s_PXENV_UDP_WRITE::buffer		Address of the UDP payload
 * @ret #PXENV_EXIT_SUCCESS		Packet was transmitted successfully
 * @ret #PXENV_EXIT_FAILURE		Packet could not be transmitted
 * @ret s_PXENV_UDP_WRITE::Status	PXE status code
 * @err #PXENV_STATUS_UDP_CLOSED	UDP connection is not open
 * @err #PXENV_STATUS_UNDI_TRANSMIT_ERROR Could not transmit packet
 *
 * Transmits a single UDP packet.  A valid IP and UDP header will be
 * prepended to the payload in s_PXENV_UDP_WRITE::buffer; the buffer
 * should not contain precomputed IP and UDP headers, nor should it
 * contain space allocated for these headers.  The first byte of the
 * buffer will be transmitted as the first byte following the UDP
 * header.
 *
 * If s_PXENV_UDP_WRITE::gw is 0.0.0.0, normal IP routing will take
 * place.  See the relevant @ref pxe_routing "implementation note" for
 * more details.
 *
 * If s_PXENV_UDP_WRITE::src_port is 0, port 2069 will be used.
 *
 * You must have opened a UDP connection with pxenv_udp_open() before
 * calling pxenv_udp_write().
 *
 * On x86, you must set the s_PXE::StatusCallout field to a nonzero
 * value before calling this function in protected mode.  You cannot
 * call this function with a 32-bit stack segment.  (See the relevant
 * @ref pxe_x86_pmode16 "implementation note" for more details.)
 *
 * @note Etherboot currently ignores the s_PXENV_UDP_WRITE::gw
 * parameter.
 *
 */
PXENV_EXIT_t pxenv_udp_write ( struct s_PXENV_UDP_WRITE *pxenv_udp_write ) {
	struct sockaddr_in dest;
	struct xfer_metadata meta = {
		.src = ( struct sockaddr * ) &pxe_udp.local,
		.dest = ( struct sockaddr * ) &dest,
		.netdev = pxe_netdev,
	};
	size_t len;
	struct io_buffer *iobuf;
	userptr_t buffer;
	int rc;

	DBG ( "PXENV_UDP_WRITE" );

	/* Construct destination socket address */
	memset ( &dest, 0, sizeof ( dest ) );
	dest.sin_family = AF_INET;
	dest.sin_addr.s_addr = pxenv_udp_write->ip;
	dest.sin_port = pxenv_udp_write->dst_port;

	/* Set local (source) port.  PXE spec says source port is 2069
	 * if not specified.  Really, this ought to be set at UDP open
	 * time but hey, we didn't design this API.
	 */
	pxe_udp.local.sin_port = pxenv_udp_write->src_port;
	if ( ! pxe_udp.local.sin_port )
		pxe_udp.local.sin_port = htons ( 2069 );

	/* FIXME: we ignore the gateway specified, since we're
	 * confident of being able to do our own routing.  We should
	 * probably allow for multiple gateways.
	 */

	/* Allocate and fill data buffer */
	len = pxenv_udp_write->buffer_size;
	iobuf = xfer_alloc_iob ( &pxe_udp.xfer, len );
	if ( ! iobuf ) {
		DBG ( " out of memory\n" );
		pxenv_udp_write->Status = PXENV_STATUS_OUT_OF_RESOURCES;
		return PXENV_EXIT_FAILURE;
	}
	buffer = real_to_user ( pxenv_udp_write->buffer.segment,
				pxenv_udp_write->buffer.offset );
	copy_from_user ( iob_put ( iobuf, len ), buffer, 0, len );

	DBG ( " %04x:%04x+%x %d->%s:%d\n", pxenv_udp_write->buffer.segment,
	      pxenv_udp_write->buffer.offset, pxenv_udp_write->buffer_size,
	      ntohs ( pxenv_udp_write->src_port ),
	      inet_ntoa ( dest.sin_addr ),
	      ntohs ( pxenv_udp_write->dst_port ) );
	
	/* Transmit packet */
	if ( ( rc = xfer_deliver ( &pxe_udp.xfer, iobuf, &meta ) ) != 0 ) {
		DBG ( "PXENV_UDP_WRITE could not transmit: %s\n",
		      strerror ( rc ) );
		pxenv_udp_write->Status = PXENV_STATUS ( rc );
		return PXENV_EXIT_FAILURE;
	}

	pxenv_udp_write->Status = PXENV_STATUS_SUCCESS;
	return PXENV_EXIT_SUCCESS;
}

/**
 * UDP READ
 *
 * @v pxenv_udp_read			Pointer to a struct s_PXENV_UDP_READ
 * @v s_PXENV_UDP_READ::dest_ip		Destination IP address, or 0.0.0.0
 * @v s_PXENV_UDP_READ::d_port		Destination UDP port, or 0
 * @v s_PXENV_UDP_READ::buffer_size	Size of the UDP payload buffer
 * @v s_PXENV_UDP_READ::buffer		Address of the UDP payload buffer
 * @ret #PXENV_EXIT_SUCCESS		A packet has been received
 * @ret #PXENV_EXIT_FAILURE		No packet has been received
 * @ret s_PXENV_UDP_READ::Status	PXE status code
 * @ret s_PXENV_UDP_READ::src_ip	Source IP address
 * @ret s_PXENV_UDP_READ::dest_ip	Destination IP address
 * @ret s_PXENV_UDP_READ::s_port	Source UDP port
 * @ret s_PXENV_UDP_READ::d_port	Destination UDP port
 * @ret s_PXENV_UDP_READ::buffer_size	Length of UDP payload
 * @err #PXENV_STATUS_UDP_CLOSED	UDP connection is not open
 * @err #PXENV_STATUS_FAILURE		No packet was ready to read
 *
 * Receive a single UDP packet.  This is a non-blocking call; if no
 * packet is ready to read, the call will return instantly with
 * s_PXENV_UDP_READ::Status==PXENV_STATUS_FAILURE.
 *
 * If s_PXENV_UDP_READ::dest_ip is 0.0.0.0, UDP packets addressed to
 * any IP address will be accepted and may be returned to the caller.
 *
 * If s_PXENV_UDP_READ::d_port is 0, UDP packets addressed to any UDP
 * port will be accepted and may be returned to the caller.
 *
 * You must have opened a UDP connection with pxenv_udp_open() before
 * calling pxenv_udp_read().
 *
 * On x86, you must set the s_PXE::StatusCallout field to a nonzero
 * value before calling this function in protected mode.  You cannot
 * call this function with a 32-bit stack segment.  (See the relevant
 * @ref pxe_x86_pmode16 "implementation note" for more details.)
 *
 * @note The PXE specification (version 2.1) does not state that we
 * should fill in s_PXENV_UDP_READ::dest_ip and
 * s_PXENV_UDP_READ::d_port, but Microsoft Windows' NTLDR program
 * expects us to do so, and will fail if we don't.
 *
 */
PXENV_EXIT_t pxenv_udp_read ( struct s_PXENV_UDP_READ *pxenv_udp_read ) {
	struct in_addr dest_ip_wanted = { .s_addr = pxenv_udp_read->dest_ip };
	struct in_addr dest_ip;
	uint16_t d_port_wanted = pxenv_udp_read->d_port;
	uint16_t d_port;

	/* Try receiving a packet */
	pxe_udp.pxenv_udp_read = pxenv_udp_read;
	step();
	if ( pxe_udp.pxenv_udp_read ) {
		/* No packet received */
		DBG2 ( "PXENV_UDP_READ\n" );
		pxe_udp.pxenv_udp_read = NULL;
		goto no_packet;
	}
	dest_ip.s_addr = pxenv_udp_read->dest_ip;
	d_port = pxenv_udp_read->d_port;
	DBG ( "PXENV_UDP_READ" );

	/* Filter on destination address and/or port */
	if ( dest_ip_wanted.s_addr &&
	     ( dest_ip_wanted.s_addr != dest_ip.s_addr ) ) {
		DBG ( " wrong IP %s", inet_ntoa ( dest_ip ) );
		DBG ( " (wanted %s)\n", inet_ntoa ( dest_ip_wanted ) );
		goto no_packet;
	}
	if ( d_port_wanted && ( d_port_wanted != d_port ) ) {
		DBG ( " wrong port %d", htons ( d_port ) );
		DBG ( " (wanted %d)\n", htons ( d_port_wanted ) );
		goto no_packet;
	}

	DBG ( " %04x:%04x+%x %s:", pxenv_udp_read->buffer.segment,
	      pxenv_udp_read->buffer.offset, pxenv_udp_read->buffer_size,
	      inet_ntoa ( *( ( struct in_addr * ) &pxenv_udp_read->src_ip ) ));
	DBG ( "%d<-%s:%d\n",  ntohs ( pxenv_udp_read->s_port ),
	      inet_ntoa ( *( ( struct in_addr * ) &pxenv_udp_read->dest_ip ) ),
	      ntohs ( pxenv_udp_read->d_port ) );

	pxenv_udp_read->Status = PXENV_STATUS_SUCCESS;
	return PXENV_EXIT_SUCCESS;

 no_packet:
	pxenv_udp_read->Status = PXENV_STATUS_FAILURE;
	return PXENV_EXIT_FAILURE;
}
/**
 * Decrypt a packet using CCMP
 *
 * @v crypto	CCMP cryptosystem
 * @v eiob	I/O buffer containing encrypted packet
 * @ret iob	I/O buffer containing cleartext packet
 */
static struct io_buffer * ccmp_decrypt ( struct net80211_crypto *crypto,
					 struct io_buffer *eiob )
{
	struct ccmp_ctx *ctx = crypto->priv;
	struct ieee80211_frame *hdr;
	struct io_buffer *iob;
	const int hdrlen = IEEE80211_TYP_FRAME_HEADER_LEN;
	int datalen = iob_len ( eiob ) - hdrlen - CCMP_HEAD_LEN - CCMP_MIC_LEN;
	struct ccmp_head *head;
	struct ccmp_nonce nonce;
	struct ccmp_aad aad;
	u8 rx_pn[6], their_mic[8], our_mic[8];

	iob = alloc_iob ( hdrlen + datalen );
	if ( ! iob )
		return NULL;

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

	/* Check and update RX packet number */
	head = eiob->data + hdrlen;
	memcpy ( rx_pn, head->pn_lo, 2 );
	memcpy ( rx_pn + 2, head->pn_hi, 4 );

	if ( pn_to_u64 ( rx_pn ) <= ctx->rx_seq ) {
		DBGC ( ctx, "WPA-CCMP %p: packet received out of order "
		       "(%012llx <= %012llx)\n", ctx, pn_to_u64 ( rx_pn ),
		       ctx->rx_seq );
		free_iob ( iob );
		return NULL;
	}

	ctx->rx_seq = pn_to_u64 ( rx_pn );
	DBGC2 ( ctx, "WPA-CCMP %p: RX packet number %012llx\n", ctx, ctx->rx_seq );

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

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

	/* Copy-decrypt data and MIC */
	ccmp_ctr_xor ( ctx, &nonce, eiob->data + hdrlen + sizeof ( *head ),
		       iob_put ( iob, datalen ), datalen,
		       eiob->tail - CCMP_MIC_LEN, their_mic );

	/* Check MIC */
	ccmp_cbc_mac ( ctx, &nonce, iob->data + hdrlen, datalen, &aad,
		       our_mic );

	if ( memcmp ( their_mic, our_mic, CCMP_MIC_LEN ) != 0 ) {
		DBGC2 ( ctx, "WPA-CCMP %p: MIC failure\n", ctx );
		free_iob ( iob );
		return NULL;
	}

	DBGC2 ( ctx, "WPA-CCMP %p: decrypted packet %p -> %p\n", ctx,
		eiob, iob );

	return iob;
}