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); }
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; }