Esempio n. 1
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 );
}
Esempio n. 2
0
File: xfer.c Progetto: baloo/ipxe
/**
 * 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 );
}
Esempio n. 3
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 );
}
Esempio n. 4
0
File: xfer.c Progetto: baloo/ipxe
/**
 * Seek to position
 *
 * @v intf		Data transfer interface
 * @v offset		Offset to new position
 * @ret rc		Return status code
 */
int xfer_seek ( struct interface *intf, off_t offset ) {
	struct io_buffer *iobuf;
	struct xfer_metadata meta = {
		.flags = XFER_FL_ABS_OFFSET,
		.offset = offset,
	};

	DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " seek to %ld\n",
	       INTF_DBG ( intf ), offset );

	/* Allocate and send a zero-length data buffer */
	iobuf = xfer_alloc_iob ( intf, 0 );
	if ( ! iobuf )
		return -ENOMEM;

	return xfer_deliver ( intf, iobuf, &meta );
}
Esempio n. 5
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;
}