int iscsi_discovery_async(struct iscsi_context *iscsi, iscsi_command_cb cb, void *private_data) { struct iscsi_pdu *pdu; char *str; if (iscsi->session_type != ISCSI_SESSION_DISCOVERY) { iscsi_set_error(iscsi, "Trying to do discovery on " "non-discovery session."); return -1; } pdu = iscsi_allocate_pdu(iscsi, ISCSI_PDU_TEXT_REQUEST, ISCSI_PDU_TEXT_RESPONSE, iscsi_itt_post_increment(iscsi), ISCSI_PDU_DROP_ON_RECONNECT); if (pdu == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to allocate " "text pdu."); return -1; } /* immediate */ iscsi_pdu_set_immediate(pdu); /* cmdsn is not increased if Immediate delivery*/ iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn); /* flags */ iscsi_pdu_set_pduflags(pdu, ISCSI_PDU_TEXT_FINAL); /* target transfer tag */ iscsi_pdu_set_ttt(pdu, 0xffffffff); /* sendtargets */ str = (char *)"SendTargets=All"; if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) { iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); iscsi->drv->free_pdu(iscsi, pdu); return -1; } pdu->callback = cb; pdu->private_data = private_data; if (iscsi_queue_pdu(iscsi, pdu) != 0) { iscsi_set_error(iscsi, "Out-of-memory: failed to queue iscsi " "text pdu."); iscsi->drv->free_pdu(iscsi, pdu); return -1; } return 0; }
int iscsi_task_mgmt_async(struct iscsi_context *iscsi, int lun, enum iscsi_task_mgmt_funcs function, uint32_t ritt, uint32_t rcmdsn, iscsi_command_cb cb, void *private_data) { struct iscsi_pdu *pdu; if (iscsi->is_loggedin == 0) { iscsi_set_error(iscsi, "trying to send task-mgmt while not " "logged in"); return -1; } pdu = iscsi_allocate_pdu(iscsi, ISCSI_PDU_SCSI_TASK_MANAGEMENT_REQUEST, ISCSI_PDU_SCSI_TASK_MANAGEMENT_RESPONSE, iscsi_itt_post_increment(iscsi), ISCSI_PDU_DROP_ON_RECONNECT); if (pdu == NULL) { iscsi_set_error(iscsi, "Failed to allocate task mgmt pdu"); return -1; } /* immediate flag */ iscsi_pdu_set_immediate(pdu); /* flags */ iscsi_pdu_set_pduflags(pdu, 0x80 | function); /* lun */ iscsi_pdu_set_lun(pdu, lun); /* ritt */ iscsi_pdu_set_ritt(pdu, ritt); /* cmdsn is not increased if Immediate delivery*/ iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn); /* rcmdsn */ iscsi_pdu_set_rcmdsn(pdu, rcmdsn); pdu->callback = cb; pdu->private_data = private_data; if (iscsi_queue_pdu(iscsi, pdu) != 0) { iscsi_set_error(iscsi, "failed to queue iscsi taskmgmt pdu"); iscsi->t->free_pdu(iscsi, pdu); return -1; } return 0; }
int iscsi_nop_out_async(struct iscsi_context *iscsi, iscsi_command_cb cb, unsigned char *data, int len, void *private_data) { struct iscsi_pdu *pdu; if (iscsi->old_iscsi || iscsi->pending_reconnect) { ISCSI_LOG(iscsi, (iscsi->nops_in_flight > 1) ? 1 : 6, "NOP Out Send NOT SEND while reconnecting (nops_in_flight: %d, iscsi->maxcmdsn %08x, iscsi->expcmdsn %08x)", iscsi->nops_in_flight, iscsi->maxcmdsn, iscsi->expcmdsn); return 0; } if (iscsi->is_loggedin == 0) { iscsi_set_error(iscsi, "trying to send nop-out while not " "logged in"); return -1; } pdu = iscsi_allocate_pdu(iscsi, ISCSI_PDU_NOP_OUT, ISCSI_PDU_NOP_IN, iscsi_itt_post_increment(iscsi), ISCSI_PDU_DROP_ON_RECONNECT); if (pdu == NULL) { iscsi_set_error(iscsi, "Failed to allocate nop-out pdu"); return -1; } /* flags */ iscsi_pdu_set_pduflags(pdu, 0x80); /* ttt */ iscsi_pdu_set_ttt(pdu, 0xffffffff); /* lun */ iscsi_pdu_set_lun(pdu, 0); /* cmdsn */ iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn++); pdu->callback = cb; pdu->private_data = private_data; if (data != NULL && len > 0) { if (iscsi_pdu_add_data(iscsi, pdu, data, len) != 0) { iscsi_set_error(iscsi, "Failed to add outdata to nop-out"); iscsi->drv->free_pdu(iscsi, pdu); return -1; } } if (iscsi_queue_pdu(iscsi, pdu) != 0) { iscsi_set_error(iscsi, "failed to queue iscsi nop-out pdu"); iscsi->drv->free_pdu(iscsi, pdu); return -1; } iscsi->nops_in_flight++; ISCSI_LOG(iscsi, (iscsi->nops_in_flight > 1) ? 1 : 6, "NOP Out Send (nops_in_flight: %d, pdu->cmdsn %08x, pdu->itt %08x, pdu->ttt %08x, iscsi->maxcmdsn %08x, iscsi->expcmdsn %08x)", iscsi->nops_in_flight, pdu->cmdsn, pdu->itt, 0xffffffff, iscsi->maxcmdsn, iscsi->expcmdsn); return 0; }
struct iscsi_pdu * iscsi_allocate_pdu(struct iscsi_context *iscsi, enum iscsi_opcode opcode, enum iscsi_opcode response_opcode) { return iscsi_allocate_pdu_with_itt_flags(iscsi, opcode, response_opcode, iscsi_itt_post_increment(iscsi), 0); }
int iscsi_process_login_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, struct iscsi_in_pdu *in) { uint32_t status, maxcmdsn, expcmdsn; char *ptr = (char *)in->data; int size = in->data_pos; status = scsi_get_uint16(&in->hdr[36]); iscsi->statsn = scsi_get_uint16(&in->hdr[24]); maxcmdsn = scsi_get_uint32(&in->hdr[32]); if (iscsi_serial32_compare(maxcmdsn, iscsi->maxcmdsn) > 0) { iscsi->maxcmdsn = maxcmdsn; } expcmdsn = scsi_get_uint32(&in->hdr[28]); if (iscsi_serial32_compare(expcmdsn, iscsi->expcmdsn) > 0) { iscsi->expcmdsn = expcmdsn; } /* XXX here we should parse the data returned in case the target * renegotiated some some parameters. * we should also do proper handshaking if the target is not yet * prepared to transition to the next stage */ while (size > 0) { char *end; int len; end = memchr(ptr, 0, size); if (end == NULL) { iscsi_set_error(iscsi, "NUL not found after offset %ld " "when parsing login data", (long)((unsigned char *)ptr - in->data)); pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data); return -1; } len = end - ptr; if (len == 0) { break; } /* parse the strings */ if (!strncmp(ptr, "TargetAddress=", 14)) { strncpy(iscsi->target_address,ptr+14,MAX_STRING_SIZE); } if (!strncmp(ptr, "HeaderDigest=", 13)) { if (!strcmp(ptr + 13, "CRC32C")) { iscsi->want_header_digest = ISCSI_HEADER_DIGEST_CRC32C; } else { iscsi->want_header_digest = ISCSI_HEADER_DIGEST_NONE; } } if (!strncmp(ptr, "FirstBurstLength=", 17)) { iscsi->first_burst_length = strtol(ptr + 17, NULL, 10); } if (!strncmp(ptr, "InitialR2T=", 11)) { if (!strcmp(ptr + 11, "No")) { iscsi->use_initial_r2t = ISCSI_INITIAL_R2T_NO; } else { iscsi->use_initial_r2t = ISCSI_INITIAL_R2T_YES; } } if (!strncmp(ptr, "ImmediateData=", 14)) { if (!strcmp(ptr + 14, "No")) { iscsi->use_immediate_data = ISCSI_IMMEDIATE_DATA_NO; } else if (iscsi->want_immediate_data == ISCSI_IMMEDIATE_DATA_NO) { /* If we negotiated NO, it doesnt matter what * the target said. ImmediateData is NO. */ iscsi->use_immediate_data = ISCSI_IMMEDIATE_DATA_NO; } else { iscsi->use_immediate_data = ISCSI_IMMEDIATE_DATA_YES; } } if (!strncmp(ptr, "MaxBurstLength=", 15)) { iscsi->max_burst_length = strtol(ptr + 15, NULL, 10); } if (!strncmp(ptr, "MaxRecvDataSegmentLength=", 25)) { iscsi->target_max_recv_data_segment_length = strtol(ptr + 25, NULL, 10); } if (!strncmp(ptr, "AuthMethod=", 11)) { if (!strcmp(ptr + 11, "CHAP")) { iscsi->secneg_phase = ISCSI_LOGIN_SECNEG_PHASE_SELECT_ALGORITHM; } } if (!strncmp(ptr, "CHAP_A=", 7)) { iscsi->chap_a = atoi(ptr+7); iscsi->secneg_phase = ISCSI_LOGIN_SECNEG_PHASE_SEND_RESPONSE; } if (!strncmp(ptr, "CHAP_I=", 7)) { iscsi->chap_i = atoi(ptr+7); iscsi->secneg_phase = ISCSI_LOGIN_SECNEG_PHASE_SEND_RESPONSE; } if (!strncmp(ptr, "CHAP_C=0x", 9)) { strncpy(iscsi->chap_c,ptr+9,MAX_STRING_SIZE); iscsi->secneg_phase = ISCSI_LOGIN_SECNEG_PHASE_SEND_RESPONSE; } ptr += len + 1; size -= len + 1; } if (status == SCSI_STATUS_REDIRECT && iscsi->target_address[0]) { ISCSI_LOG(iscsi, 2, "target requests redirect to %s",iscsi->target_address); pdu->callback(iscsi, SCSI_STATUS_REDIRECT, NULL, pdu->private_data); return 0; } if (status != 0) { iscsi_set_error(iscsi, "Failed to log in to target. Status: %s(%d)", login_error_str(status), status); pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data); return 0; } if (in->hdr[1] & ISCSI_PDU_LOGIN_TRANSIT) { iscsi->current_phase = (in->hdr[1] & ISCSI_PDU_LOGIN_NSG_FF) << 2; } if ((in->hdr[1] & ISCSI_PDU_LOGIN_TRANSIT) && (in->hdr[1] & ISCSI_PDU_LOGIN_NSG_FF) == ISCSI_PDU_LOGIN_NSG_FF) { iscsi->is_loggedin = 1; iscsi_itt_post_increment(iscsi); iscsi->header_digest = iscsi->want_header_digest; ISCSI_LOG(iscsi, 2, "login successful"); pdu->callback(iscsi, SCSI_STATUS_GOOD, NULL, pdu->private_data); } else { if (iscsi_login_async(iscsi, pdu->callback, pdu->private_data) != 0) { iscsi_set_error(iscsi, "Failed to send continuation login pdu"); pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data); } } return 0; }