Exemplo n.º 1
0
static void vsfip_dhcpc_input(void *param, struct vsfip_buffer_t *buf)
{
	struct vsfip_dhcpc_t *dhcpc = (struct vsfip_dhcpc_t *)param;
	struct vsfip_netif_t *netif = dhcpc->netif;
	struct vsfip_dhcphead_t *head;
	uint8_t optlen;
	uint8_t *optptr;

	head = (struct vsfip_dhcphead_t *)buf->app.buffer;
	if ((head->op != DHCP_TOCLIENT) ||
		(head->magic != SYS_TO_BE_U32(DHCP_MAGIC)) ||
		memcmp(head->chaddr, netif->macaddr.addr.s_addr_buf,
				netif->macaddr.size) ||
		(head->xid != dhcpc->xid))
	{
		goto exit;
	}

	optlen = vsfip_dhcp_get_opt(buf, DHCPOPT_MSGTYPE, &optptr);
	if (optlen != DHCPOPT_MSGTYPE_LEN)
	{
		goto exit;
	}

	switch (optptr[0])
	{
	case DHCPOP_OFFER:
		dhcpc->ipaddr.size = 4;
		dhcpc->ipaddr.addr.s_addr = head->yiaddr;
		vsfsm_post_evt(&dhcpc->sm, VSFIP_DHCP_EVT_SEND_REQUEST);
		break;
	case DHCPOP_ACK:
		optlen = vsfip_dhcp_get_opt(buf, DHCPOPT_LEASE_TIME, &optptr);
		dhcpc->leasetime = (4 == optlen) ? GET_BE_U32(optptr) : 0;
		optlen = vsfip_dhcp_get_opt(buf, DHCPOPT_RENEW_TIME, &optptr);
		dhcpc->renew_time = (4 == optlen) ? GET_BE_U32(optptr) : 0;
		optlen = vsfip_dhcp_get_opt(buf, DHCPOPT_REBINDING_TIME, &optptr);
		dhcpc->rebinding_time = (4 == optlen) ? GET_BE_U32(optptr) : 0;
		optlen = vsfip_dhcp_get_opt(buf, DHCPOPT_SUBNETMASK, &optptr);
		dhcpc->netmask.size = optlen;
		dhcpc->netmask.addr.s_addr = (4 == optlen) ? *(uint32_t *)optptr : 0;
		optlen = vsfip_dhcp_get_opt(buf, DHCPOPT_ROUTER, &optptr);
		dhcpc->gw.size = optlen;
		dhcpc->gw.addr.s_addr = (4 == optlen) ? *(uint32_t *)optptr : 0;
		optlen = vsfip_dhcp_get_opt(buf, DHCPOPT_DNSSERVER, &optptr);
		dhcpc->dns[0].size = dhcpc->dns[1].size = 0;
		if (optlen >= 4)
		{
			dhcpc->dns[0].size = 4;
			dhcpc->dns[0].addr.s_addr = *(uint32_t *)optptr;
			if (optlen >= 8)
			{
				dhcpc->dns[1].size = 4;
				dhcpc->dns[1].addr.s_addr = *(uint32_t *)(optptr + 4);
			}
		}

		vsfsm_post_evt(&dhcpc->sm, VSFIP_DHCP_EVT_READY);
		break;
	}

exit:
	vsfip_buffer_release(buf);
}
Exemplo n.º 2
0
static vsf_err_t vsf_mal2scsi_execute(struct vsfscsi_lun_t *lun, uint8_t *CDB,
							uint8_t CDB_size, uint32_t size)
{
	struct vsf_mal2scsi_t *mal2scsi = (struct vsf_mal2scsi_t *)lun->param;
	struct vsfscsi_transact_t *transact = &lun->dev->transact;
	struct vsfmal_t *mal = mal2scsi->malstream.mal;
	uint8_t group_code = CDB[0] & 0xE0, cmd_code = CDB[0] & 0x1F;
	uint8_t *pbuf;

	if (transact->lun != NULL)
	{
		return VSFERR_FAIL;
	}

	// check user_handler first
	if (mal2scsi->vendor_handlers != NULL)
	{
		struct vsfscsi_handler_t *handler =
				vsfscsi_get_handler(mal2scsi->vendor_handlers, CDB[0]);
		if (handler != NULL)
		{
			return handler->handler(lun, CDB);
		}
	}

	if (!mal2scsi->malstream.mal_ready || (transact->lun != NULL))
	{
		goto exit_not_ready;
	}

	switch (group_code)
	{
	case SCSI_GROUPCODE6:
		switch (cmd_code)
		{
		case SCSI_CMDCODE_MODE_SELECT:
		case SCSI_CMDCODE_TEST_UNIT_READY:
		case SCSI_CMDCODE_VERIFY:
		case SCSI_CMDCODE_FORMAT_UNIT:
		case SCSI_CMDCODE_START_STOP_UNIT:
		case SCSI_CMDCODE_ALLOW_MEDIUM_REMOVAL:
			break;
		case SCSI_CMDCODE_REQUEST_SENSE:
			pbuf = vsf_mal2scsi_prepare_transact(lun, 18, false, true);
			if (NULL == pbuf)
			{
				goto exit_not_ready;
			}

			pbuf[0] = 0x70;
			pbuf[2] = lun->sensekey;
			pbuf[7] = 0x0A;
			pbuf[12] = lun->asc;
			transact->data_size = min(CDB[4], 18);
			break;
		case SCSI_CMDCODE_READ:
			transact->LBA = GET_BE_U16(&CDB[2]);
			transact->data_size = CDB[4];
			goto do_mal_read;
			break;
		case SCSI_CMDCODE_WRITE:
			transact->LBA = GET_BE_U16(&CDB[2]);
			transact->data_size = CDB[4];
			goto do_mal_write;
			break;
		case SCSI_CMDCODE_INQUIRY:
			if (CDB[1] & 1)
			{
				// When the EVPD bit is set to one,
				// the PAGE CODE field specifies which page of
				// vital product data information the device server shall return
				if (CDB[2] != 0)
				{
					goto exit_invalid_field_in_command;
				}

				// 0x00: Supported VPD Pages
				pbuf = vsf_mal2scsi_prepare_transact(lun, 5, false, true);
				if (NULL == pbuf)
				{
					goto exit_not_ready;
				}
			}
			else
			{
				struct vsf_mal2scsi_cparam_t *cparam =
							(struct vsf_mal2scsi_cparam_t *)&mal2scsi->cparam;

				if (CDB[2] != 0)
				{
					// If the PAGE CODE field is not set to zero
					// when the EVPD bit is set to zero,
					// the command shall be terminated with CHECK CONDITION status,
					// with the sense key set to ILLEGAL REQUEST,
					// and the additional sense code set to INVALID FIELD IN CDB.
					goto exit_invalid_field_in_command;
				}

				// If the EVPD bit is set to zero,
				// the device server shall return the standard INQUIRY data.
				pbuf = vsf_mal2scsi_prepare_transact(lun, 36, false, true);
				if (NULL == pbuf)
				{
					goto exit_not_ready;
				}

				pbuf[0] = cparam->type;
				if (cparam->removable)
				{
					pbuf[1] = 0x80;
				}
				pbuf[3] = 2;
				pbuf[4] = 31;
				pbuf += 8;
				memcpy(pbuf, cparam->vendor, sizeof(cparam->vendor));
				pbuf += sizeof(cparam->vendor);
				memcpy(pbuf, cparam->product, sizeof(cparam->product));
				pbuf += sizeof(cparam->product);
				memcpy(pbuf, cparam->revision, sizeof(cparam->revision));
			}
			break;
		case SCSI_CMDCODE_MODE_SENSE:
			pbuf = vsf_mal2scsi_prepare_transact(lun, 4, false, true);
			if (NULL == pbuf)
			{
				goto exit_not_ready;
			}

			pbuf[0] = 3;
			break;
		default:
			goto exit_invalid_command;
		}
		break;
	case SCSI_GROUPCODE10_1:
		switch (cmd_code)
		{
		case SCSI_CMDCODE_READ_FORMAT_CAPACITIES:
			pbuf = vsf_mal2scsi_prepare_transact(lun, 12, false, true);
			if (NULL == pbuf)
			{
				goto exit_not_ready;
			}

			pbuf[3] = 8;
			SET_BE_U32(&pbuf[4], mal->cap.block_num);
			SET_BE_U32(&pbuf[8], mal->cap.block_size);
			pbuf[8] = 2;
			break;
		case SCSI_CMDCODE_READ_CAPACITY:
			pbuf = vsf_mal2scsi_prepare_transact(lun, 8, false, true);
			if (NULL == pbuf)
			{
				goto exit_not_ready;
			}

			SET_BE_U32(&pbuf[0], mal->cap.block_num - 1);
			SET_BE_U32(&pbuf[4], mal->cap.block_size);
			break;
		case SCSI_CMDCODE_READ:
			transact->LBA = GET_BE_U32(&CDB[2]);
			transact->data_size = GET_BE_U16(&CDB[7]);
			goto do_mal_read;
			break;
		case SCSI_CMDCODE_WRITE:
			transact->LBA = GET_BE_U32(&CDB[2]);
			transact->data_size = GET_BE_U16(&CDB[7]);
			goto do_mal_write;
			break;
		default:
			goto exit_invalid_command;
		}
		break;
	case SCSI_GROUPCODE10_2:
		switch (cmd_code)
		{
		case SCSI_CMDCODE_MODE_SELECT:
			break;
		case SCSI_CMDCODE_MODE_SENSE:
			break;
		default:
			goto exit_invalid_command;
		}
		break;
	case SCSI_GROUPCODE16:
		switch (cmd_code)
		{
		case SCSI_CMDCODE_READ:
			transact->LBA = GET_BE_U64(&CDB[2]);
			transact->data_size = GET_BE_U32(&CDB[10]);

		do_mal_read:
			transact->LBA *= mal->cap.block_size;
			transact->data_size *= mal->cap.block_size;
			pbuf = vsf_mal2scsi_prepare_transact(lun, transact->data_size,
													false, false);
			if (NULL == pbuf)
			{
				goto exit_not_ready;
			}

			vsf_malstream_read(&mal2scsi->malstream, transact->LBA,
									transact->data_size);
			break;
		case SCSI_CMDCODE_WRITE:
			transact->LBA = GET_BE_U64(&CDB[2]);
			transact->data_size = GET_BE_U32(&CDB[10]);

		do_mal_write:
			transact->LBA *= mal->cap.block_size;
			transact->data_size *= mal->cap.block_size;
			pbuf = vsf_mal2scsi_prepare_transact(lun, transact->data_size,
													true, false);
			if (NULL == pbuf)
			{
				goto exit_not_ready;
			}

			vsf_malstream_write(&mal2scsi->malstream, transact->LBA,
									transact->data_size);
			break;
		default:
			goto exit_invalid_command;
		}
		break;
	case SCSI_GROUPCODE12:
		switch (cmd_code)
		{
		case SCSI_CMDCODE_READ:
			transact->LBA = GET_BE_U32(&CDB[2]);
			transact->data_size = GET_BE_U32(&CDB[6]);
			goto do_mal_read;
			break;
		case SCSI_CMDCODE_WRITE:
			transact->LBA = GET_BE_U32(&CDB[2]);
			transact->data_size = GET_BE_U32(&CDB[6]);
			goto do_mal_write;
			break;
		default:
			goto exit_invalid_command;
		}
		break;
	default:
		goto exit_invalid_command;
	}

	lun->sensekey = SCSI_SENSEKEY_NO_SENSE;
	lun->asc = SCSI_ASC_NONE;
	if (transact->lun->stream != NULL)
	{
		if (transact->lun->stream->op == &bufstream_op)
		{
			stream_connect_tx(transact->lun->stream);
		}
	}
	return VSFERR_NONE;
exit_invalid_command:
	lun->sensekey = SCSI_SENSEKEY_ILLEGAL_REQUEST;
	lun->asc = SCSI_ASC_INVALID_COMMAND;
	return VSFERR_FAIL;
exit_invalid_field_in_command:
	lun->sensekey = SCSI_SENSEKEY_ILLEGAL_REQUEST;
	lun->asc = SCSI_ASC_INVALID_FIELD_IN_COMMAND;
	return VSFERR_FAIL;
exit_not_ready:
	lun->sensekey = SCSI_SENSEKEY_NOT_READY;
	lun->asc = SCSI_ASC_NONE;
	return VSFERR_FAIL;
}