示例#1
0
文件: login.c 项目: jpocas/libiscsi
static int
iscsi_login_add_chap_username(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
	char str[MAX_STRING_SIZE+1];

	if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_SECNEG
	|| iscsi->secneg_phase != ISCSI_LOGIN_SECNEG_PHASE_SEND_RESPONSE) {
		return 0;
	}

	strncpy(str,"CHAP_N=",MAX_STRING_SIZE);
	if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str))
	    != 0) {
		iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed.");
		return -1;
	}
	if (iscsi_pdu_add_data(iscsi, pdu,
			       (unsigned char *)iscsi->user,
			       strlen(iscsi->user) +1) != 0) {
		iscsi_set_error(iscsi, "Out-of-memory: pdu add data "
				"failed.");
		return -1;
	}

	return 0;
}
示例#2
0
文件: login.c 项目: jpocas/libiscsi
static int
iscsi_login_add_targetname(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
	char str[MAX_STRING_SIZE+1];

	/* We only send TargetName during opneg or the first leg of secneg */
	if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG
	&& iscsi->secneg_phase != ISCSI_LOGIN_SECNEG_PHASE_OFFER_CHAP) {
		return 0;
	}

	if (!iscsi->target_name[0]) {
		iscsi_set_error(iscsi, "Trying normal connect but "
				"target name not set.");
		return -1;
	}

	if (snprintf(str, MAX_STRING_SIZE, "TargetName=%s", iscsi->target_name) == -1) {
		iscsi_set_error(iscsi, "Out-of-memory: aprintf failed.");
		return -1;
	}

	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.");
		return -1;
	}
	return 0;
}
示例#3
0
文件: login.c 项目: jpocas/libiscsi
static int
iscsi_login_add_sessiontype(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
	char str[MAX_STRING_SIZE+1];

	/* We only send TargetName during opneg or the first leg of secneg */
	if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG
	&& iscsi->secneg_phase != ISCSI_LOGIN_SECNEG_PHASE_OFFER_CHAP) {
		return 0;
	}

	switch (iscsi->session_type) {
	case ISCSI_SESSION_DISCOVERY:
		strncpy(str,"SessionType=Discovery",MAX_STRING_SIZE);
		break;
	case ISCSI_SESSION_NORMAL:
		strncpy(str,"SessionType=Normal",MAX_STRING_SIZE);
		break;
	default:
		iscsi_set_error(iscsi, "Can not handle sessions %d yet.",
				iscsi->session_type);
		return -1;
	}
	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.");
		return -1;
	}

	return 0;
}
示例#4
0
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;
}
示例#5
0
文件: nop.c 项目: HSchroeder/ccan
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 == NULL) {
		printf("trying to send nop-out on NULL context\n");
		return -1;
	}

	if (iscsi->is_loggedin == 0) {
		printf("trying send nop-out while not logged in\n");
		return -2;
	}

	pdu = iscsi_allocate_pdu(iscsi, ISCSI_PDU_NOP_OUT, ISCSI_PDU_NOP_IN);
	if (pdu == NULL) {
		printf("Failed to allocate nop-out pdu\n");
		return -3;
	}

	/* immediate flag */
	iscsi_pdu_set_immediate(pdu);

	/* flags */
	iscsi_pdu_set_pduflags(pdu, 0x80);

	/* ttt */
	iscsi_pdu_set_ttt(pdu, 0xffffffff);

	/* lun */
	iscsi_pdu_set_lun(pdu, 2);

	/* cmdsn is not increased if Immediate delivery*/
	iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn);
	pdu->cmdsn = iscsi->cmdsn;
//	iscsi->cmdsn++;

	pdu->callback     = cb;
	pdu->private_data = private_data;

	if (iscsi_pdu_add_data(iscsi, pdu, data, len) != 0) {
		printf("Failed to add outdata to nop-out\n");
		iscsi_free_pdu(iscsi, pdu);
		return -4;
	}


	if (iscsi_queue_pdu(iscsi, pdu) != 0) {
		printf("failed to queue iscsi nop-out pdu\n");
		iscsi_free_pdu(iscsi, pdu);
		return -5;
	}

	return 0;
}
示例#6
0
文件: login.c 项目: jpocas/libiscsi
static int
iscsi_login_add_authalgorithm(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
	char str[MAX_STRING_SIZE+1];

	if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_SECNEG
	|| iscsi->secneg_phase != ISCSI_LOGIN_SECNEG_PHASE_SELECT_ALGORITHM) {
		return 0;
	}

	strncpy(str,"CHAP_A=5",MAX_STRING_SIZE);
	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.");
		return -1;
	}

	return 0;
}
示例#7
0
文件: login.c 项目: jpocas/libiscsi
static int
iscsi_login_add_authmethod(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
	char str[MAX_STRING_SIZE+1];

	if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_SECNEG
	|| iscsi->secneg_phase != ISCSI_LOGIN_SECNEG_PHASE_OFFER_CHAP) {
		return 0;
	}

	strncpy(str,"AuthMethod=CHAP,None",MAX_STRING_SIZE);
	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.");
		return -1;
	}

	return 0;
}
示例#8
0
文件: login.c 项目: jpocas/libiscsi
static int
iscsi_login_add_errorrecoverylevel(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
	char str[MAX_STRING_SIZE+1];

	/* We only send ErrorRecoveryLevel during opneg */
	if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG) {
		return 0;
	}

	strncpy(str,"ErrorRecoveryLevel=0",MAX_STRING_SIZE);
	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.");
		return -1;
	}

	return 0;
}
示例#9
0
文件: login.c 项目: jpocas/libiscsi
static int
iscsi_login_add_datasequenceinorder(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
	char str[MAX_STRING_SIZE+1];

	/* We only send DataSequenceInOrder during opneg */
	if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG) {
		return 0;
	}

	strncpy(str,"DataSequenceInOrder=Yes",MAX_STRING_SIZE);
	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.");
		return -1;
	}

	return 0;
}
示例#10
0
文件: login.c 项目: jpocas/libiscsi
static int
iscsi_login_add_maxrecvdatasegmentlength(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
	char str[MAX_STRING_SIZE+1];

	/* We only send MaxRecvDataSegmentLength during opneg */
	if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG) {
		return 0;
	}

	if (snprintf(str, MAX_STRING_SIZE, "MaxRecvDataSegmentLength=%d", iscsi->initiator_max_recv_data_segment_length) == -1) {
		iscsi_set_error(iscsi, "Out-of-memory: aprintf failed.");
		return -1;
	}

	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.");
		return -1;
	}
	return 0;
}
示例#11
0
文件: login.c 项目: jpocas/libiscsi
static int
iscsi_login_add_alias(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
	char str[MAX_STRING_SIZE+1];

	/* We only send InitiatorAlias during opneg or the first leg of secneg */
	if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG
	&& iscsi->secneg_phase != ISCSI_LOGIN_SECNEG_PHASE_OFFER_CHAP) {
		return 0;
	}

	if (snprintf(str, MAX_STRING_SIZE, "InitiatorAlias=%s", iscsi->alias) == -1) {
		iscsi_set_error(iscsi, "Out-of-memory: aprintf failed.");
		return -1;
	}

	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.");
		return -1;
	}
	return 0;
}
示例#12
0
文件: login.c 项目: jpocas/libiscsi
static int
iscsi_login_add_immediatedata(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
	char str[MAX_STRING_SIZE+1];

	/* We only send ImmediateData during opneg */
	if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG) {
		return 0;
	}

	if (snprintf(str, MAX_STRING_SIZE, "ImmediateData=%s", iscsi->want_immediate_data == ISCSI_IMMEDIATE_DATA_NO ?
		       "No" : "Yes") == -1) {
		iscsi_set_error(iscsi, "Out-of-memory: aprintf failed.");
		return -1;
	}

	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.");
		return -1;
	}

	return 0;
}
示例#13
0
文件: login.c 项目: jpocas/libiscsi
static int
iscsi_login_add_initialr2t(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
	char str[MAX_STRING_SIZE+1];

	/* We only send InitialR2T during opneg */
	if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG) {
		return 0;
	}

	if (snprintf(str, MAX_STRING_SIZE, "InitialR2T=%s", iscsi->want_initial_r2t == ISCSI_INITIAL_R2T_NO ?
		       "No" : "Yes") == -1) {
		iscsi_set_error(iscsi, "Out-of-memory: aprintf failed.");
		return -1;
	}

	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.");
		return -1;
	}

	return 0;
}
示例#14
0
文件: login.c 项目: jpocas/libiscsi
static int
iscsi_login_add_headerdigest(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
	char str[MAX_STRING_SIZE+1];

	/* We only send HeaderDigest during opneg */
	if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_OPNEG) {
		return 0;
	}

	switch (iscsi->want_header_digest) {
	case ISCSI_HEADER_DIGEST_NONE:
		strncpy(str,"HeaderDigest=None",MAX_STRING_SIZE);
		break;
	case ISCSI_HEADER_DIGEST_NONE_CRC32C:
		strncpy(str,"HeaderDigest=None,CRC32C",MAX_STRING_SIZE);
		break;
	case ISCSI_HEADER_DIGEST_CRC32C_NONE:
		strncpy(str,"HeaderDigest=CRC32C,None",MAX_STRING_SIZE);
		break;
	case ISCSI_HEADER_DIGEST_CRC32C:
		strncpy(str,"HeaderDigest=CRC32C",MAX_STRING_SIZE);
		break;
	default:
		iscsi_set_error(iscsi, "invalid header digest value");
		return -1;
	}

	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.");
		return -1;
	}

	return 0;
}
示例#15
0
文件: login.c 项目: jpocas/libiscsi
static int
iscsi_login_add_chap_response(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
{
	char str[MAX_STRING_SIZE+1];
	char * strp;
	unsigned char c, cc[2];
	unsigned char digest[16];
	gcry_md_hd_t ctx;
	int i;

	if (iscsi->current_phase != ISCSI_PDU_LOGIN_CSG_SECNEG
	|| iscsi->secneg_phase != ISCSI_LOGIN_SECNEG_PHASE_SEND_RESPONSE) {
		return 0;
	}

	gcry_md_open(&ctx, GCRY_MD_MD5, 0);
	if (!ctx) {
		iscsi_set_error(iscsi, "Cannot create MD5 algorithm");
		return -1;
	}

	if (!iscsi->chap_c[0]) {
		iscsi_set_error(iscsi, "No CHAP challenge found");
		return -1;
	}
	gcry_md_putc(ctx, iscsi->chap_i);
	gcry_md_write(ctx, (unsigned char *)iscsi->passwd, strlen(iscsi->passwd));

	strp = iscsi->chap_c;
	while (*strp != 0) {
		c = (h2i(strp[0]) << 4) | h2i(strp[1]);
		strp += 2;
		gcry_md_putc(ctx, c);
	}
	memcpy(digest, gcry_md_read(ctx, 0), sizeof(digest));
	gcry_md_close(ctx);

	strncpy(str,"CHAP_R=0x",MAX_STRING_SIZE);
	if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str))
	    != 0) {
		iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed.");
		return -1;
	}

	for (i=0; i<16; i++) {
		c = digest[i];
		cc[0] = i2h((c >> 4)&0x0f);
		cc[1] = i2h((c     )&0x0f);
		if (iscsi_pdu_add_data(iscsi, pdu, &cc[0], 2) != 0) {
			iscsi_set_error(iscsi, "Out-of-memory: pdu add data "
				"failed.");
			return -1;
		}
	}
	c = 0;
	if (iscsi_pdu_add_data(iscsi, pdu, &c, 1) != 0) {
		iscsi_set_error(iscsi, "Out-of-memory: pdu add data "
			"failed.");
		return -1;
	}

	return 0;
}
示例#16
0
static int iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun, struct scsi_task *task, iscsi_command_cb cb, struct iscsi_data *data, void *private_data)
{
    struct iscsi_pdu *pdu;
    struct iscsi_scsi_cbdata *scsi_cbdata;
    int flags;

    if (iscsi == NULL) {
        printf("trying to send command on NULL context\n");
        scsi_free_scsi_task(task);
        return -1;
    }

    if (iscsi->session_type != ISCSI_SESSION_NORMAL) {
        printf("Trying to send command on discovery session\n");
        scsi_free_scsi_task(task);
        return -2;
    }

    if (iscsi->is_loggedin == 0) {
        printf("Trying to send command while not logged in\n");
        scsi_free_scsi_task(task);
        return -3;
    }

    scsi_cbdata = malloc(sizeof(struct iscsi_scsi_cbdata));
    if (scsi_cbdata == NULL) {
        printf("failed to allocate scsi cbdata\n");
        scsi_free_scsi_task(task);
        return -4;
    }
    bzero(scsi_cbdata, sizeof(struct iscsi_scsi_cbdata));
    scsi_cbdata->task         = task;
    scsi_cbdata->callback     = cb;
    scsi_cbdata->private_data = private_data;

    pdu = iscsi_allocate_pdu(iscsi, ISCSI_PDU_SCSI_REQUEST, ISCSI_PDU_SCSI_RESPONSE);
    if (pdu == NULL) {
        printf("Failed to allocate text pdu\n");
        iscsi_free_scsi_cbdata(scsi_cbdata);
        return -5;
    }
    pdu->scsi_cbdata = scsi_cbdata;

    /* flags */
    flags = ISCSI_PDU_SCSI_FINAL|ISCSI_PDU_SCSI_ATTR_SIMPLE;
    switch (task->xfer_dir) {
    case SCSI_XFER_NONE:
        break;
    case SCSI_XFER_READ:
        flags |= ISCSI_PDU_SCSI_READ;
        break;
    case SCSI_XFER_WRITE:
        flags |= ISCSI_PDU_SCSI_WRITE;
        if (data == NULL) {
            printf("DATA-OUT command but data == NULL\n");
            iscsi_free_pdu(iscsi, pdu);
            return -5;
        }
        if (data->size != task->expxferlen) {
            printf("data size:%d is not same as expected data transfer length:%d\n", data->size, task->expxferlen);
            iscsi_free_pdu(iscsi, pdu);
            return -7;
        }
        if (iscsi_pdu_add_data(iscsi, pdu, data->data, data->size) != 0) {
            printf("Failed to add outdata to the pdu\n");
            iscsi_free_pdu(iscsi, pdu);
            return -6;
        }

        break;
    }
    iscsi_pdu_set_pduflags(pdu, flags);

    /* lun */
    iscsi_pdu_set_lun(pdu, lun);

    /* expxferlen */
    iscsi_pdu_set_expxferlen(pdu, task->expxferlen);

    /* cmdsn */
    iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn);
    pdu->cmdsn = iscsi->cmdsn;
    iscsi->cmdsn++;

    /* exp statsn */
    iscsi_pdu_set_expstatsn(pdu, iscsi->statsn+1);

    /* cdb */
    iscsi_pdu_set_cdb(pdu, task);

    pdu->callback     = iscsi_scsi_response_cb;
    pdu->private_data = scsi_cbdata;

    if (iscsi_queue_pdu(iscsi, pdu) != 0) {
        printf("failed to queue iscsi scsi pdu\n");
        iscsi_free_pdu(iscsi, pdu);
        return -6;
    }

    return 0;
}
示例#17
0
文件: nop.c 项目: sahlberg/libiscsi
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;
}
示例#18
0
文件: login.c 项目: stewartsmith/ccan
int iscsi_login_async(struct iscsi_context *iscsi, iscsi_command_cb cb, void *private_data)
{
	struct iscsi_pdu *pdu;
	char *str;
	int ret;

	if (iscsi == NULL) {
		printf("trying to login on NULL context\n");
		return -1;
	}

	if (iscsi->is_loggedin != 0) {
		printf("trying to login while already logged in\n");
		return -2;
	}

	switch (iscsi->session_type) {
	case ISCSI_SESSION_DISCOVERY:
	case ISCSI_SESSION_NORMAL:
		break;
	default:
		printf("trying to login without setting session type\n");
		return -3;
	}

	pdu = iscsi_allocate_pdu(iscsi, ISCSI_PDU_LOGIN_REQUEST, ISCSI_PDU_LOGIN_RESPONSE);
	if (pdu == NULL) {
		printf("Failed to allocate login pdu\n");
		return -4;
	}

	/* login request */
	iscsi_pdu_set_immediate(pdu);

	/* flags */
	iscsi_pdu_set_pduflags(pdu, ISCSI_PDU_LOGIN_TRANSIT|ISCSI_PDU_LOGIN_CSG_OPNEG|ISCSI_PDU_LOGIN_NSG_FF);


	/* initiator name */
	if (asprintf(&str, "InitiatorName=%s", iscsi->initiator_name) == -1) {
		printf("asprintf failed\n");
		iscsi_free_pdu(iscsi, pdu);
		return -5;
	}
	ret = iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1);
	free(str);
	if (ret != 0) {
		printf("pdu add data failed\n");
		iscsi_free_pdu(iscsi, pdu);
		return -6;
	}

	/* optional alias */
	if (iscsi->alias) {
		if (asprintf(&str, "InitiatorAlias=%s", iscsi->alias) == -1) {
			printf("asprintf failed\n");
			iscsi_free_pdu(iscsi, pdu);
			return -7;
		}
		ret = iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1);
		free(str);
		if (ret != 0) {
			printf("pdu add data failed\n");
			iscsi_free_pdu(iscsi, pdu);
			return -8;
		}
	}

	/* target name */
	if (iscsi->session_type == ISCSI_SESSION_NORMAL) {
		if (iscsi->target_name == NULL) {
			printf("trying normal connect but target name not set\n");
			iscsi_free_pdu(iscsi, pdu);
			return -9;
		}

		if (asprintf(&str, "TargetName=%s", iscsi->target_name) == -1) {
			printf("asprintf failed\n");
			iscsi_free_pdu(iscsi, pdu);
			return -10;
		}
		ret = iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1);
		free(str);
		if (ret != 0) {
			printf("pdu add data failed\n");
			iscsi_free_pdu(iscsi, pdu);
			return -11;
		}
	}

	/* session type */
	switch (iscsi->session_type) {
	case ISCSI_SESSION_DISCOVERY:
		str = "SessionType=Discovery";
		break;
	case ISCSI_SESSION_NORMAL:
		str = "SessionType=Normal";
		break;
	default:
		printf("can not handle sessions %d yet\n", iscsi->session_type);
		return -12;
	}
	if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) {
		printf("pdu add data failed\n");
		iscsi_free_pdu(iscsi, pdu);
		return -13;
	}

	str = "HeaderDigest=None";
	if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) {
		printf("pdu add data failed\n");
		iscsi_free_pdu(iscsi, pdu);
		return -14;
	}
	str = "DataDigest=None";
	if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) {
		printf("pdu add data failed\n");
		iscsi_free_pdu(iscsi, pdu);
		return -15;
	}
	str = "InitialR2T=Yes";
	if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) {
		printf("pdu add data failed\n");
		iscsi_free_pdu(iscsi, pdu);
		return -16;
	}
	str = "ImmediateData=Yes";
	if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) {
		printf("pdu add data failed\n");
		iscsi_free_pdu(iscsi, pdu);
		return -17;
	}
	str = "MaxBurstLength=262144";
	if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) {
		printf("pdu add data failed\n");
		iscsi_free_pdu(iscsi, pdu);
		return -18;
	}
	str = "FirstBurstLength=262144";
	if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) {
		printf("pdu add data failed\n");
		iscsi_free_pdu(iscsi, pdu);
		return -19;
	}
	str = "MaxRecvDataSegmentLength=262144";
	if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) {
		printf("pdu add data failed\n");
		iscsi_free_pdu(iscsi, pdu);
		return -20;
	}
	str = "DataPDUInOrder=Yes";
	if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) {
		printf("pdu add data failed\n");
		iscsi_free_pdu(iscsi, pdu);
		return -21;
	}
	str = "DataSequenceInOrder=Yes";
	if (iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, strlen(str)+1) != 0) {
		printf("pdu add data failed\n");
		iscsi_free_pdu(iscsi, pdu);
		return -22;
	}


	pdu->callback     = cb;
	pdu->private_data = private_data;

	if (iscsi_queue_pdu(iscsi, pdu) != 0) {
		printf("failed to queue iscsi login pdu\n");
		iscsi_free_pdu(iscsi, pdu);
		return -23;
	}

	return 0;
}