From patchwork Fri Dec 3 11:09:42 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ronnie sahlberg X-Patchwork-Id: 74111 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id B8CF3B70AA for ; Fri, 3 Dec 2010 22:18:15 +1100 (EST) Received: from localhost ([127.0.0.1]:41906 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1POTeV-00038g-Qw for incoming@patchwork.ozlabs.org; Fri, 03 Dec 2010 06:18:12 -0500 Received: from [140.186.70.92] (port=58665 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1POTXS-0001JJ-8a for qemu-devel@nongnu.org; Fri, 03 Dec 2010 06:10:55 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1POTXQ-0002aE-FU for qemu-devel@nongnu.org; Fri, 03 Dec 2010 06:10:54 -0500 Received: from mail-yx0-f173.google.com ([209.85.213.173]:61819) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1POTXQ-0002Wo-AZ for qemu-devel@nongnu.org; Fri, 03 Dec 2010 06:10:52 -0500 Received: by mail-yx0-f173.google.com with SMTP id 31so5074889yxl.4 for ; Fri, 03 Dec 2010 03:10:52 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:received:from:to:cc:subject :date:message-id:x-mailer:in-reply-to:references; bh=ACRNH//P+9nl/COq1eKIbeJ1eTtGdpfc20ZbidqMy6k=; b=jEf6T2K/xWhhjubA0KB9uqR976hEfVe0rCUhPGBk8dAgj3e8heMRS2twJT8dT+SXTY hXSN0960Jm7ZnD9FWAQonR2uiDkRoAoiH+AUAlaQnZP4X7Fuqe/mNE8mJfR/vjL/G6eR IOuXtf+Cm3mPl7sRzSmm3PD2e6Yitt5eUtpgQ= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; b=yDUkznqSprKHAgQk8hmI6CmQgj1QGMc8ypoEI+pQJFhk0eFlJ2DXjIp+Uj90xthZeo P6kSVAqIZxA+V4kudnVXx3biLVjDtbU6qcs4gvMB/qv9af3U2HYd8g+YEqynj+7jR0eu wGlF54zh6j7mdbephGeRX1+kL6b/6mtT9RwtM= Received: by 10.151.9.4 with SMTP id m4mr3673541ybi.77.1291374651960; Fri, 03 Dec 2010 03:10:51 -0800 (PST) Received: from ronniesahlberg@gmail.com (CPE-121-216-183-74.lnse2.ken.bigpond.net.au [121.216.183.74]) by mx.google.com with ESMTPS id n63sm1000734yha.20.2010.12.03.03.10.48 (version=TLSv1/SSLv3 cipher=RC4-MD5); Fri, 03 Dec 2010 03:10:51 -0800 (PST) Received: by ronniesahlberg@gmail.com (sSMTP sendmail emulation); Fri, 03 Dec 2010 22:10:23 +1100 From: ronniesahlberg@gmail.com To: qemu-devel@nongnu.org Date: Fri, 3 Dec 2010 22:09:42 +1100 Message-Id: <1291374593-17448-4-git-send-email-ronniesahlberg@gmail.com> X-Mailer: git-send-email 1.7.3.1 In-Reply-To: <1291374593-17448-1-git-send-email-ronniesahlberg@gmail.com> References: <1291374593-17448-1-git-send-email-ronniesahlberg@gmail.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) Cc: Ronnie Sahlberg Subject: [Qemu-devel] [PATCH 03/14] ./block/iscsi/login.c X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Ronnie Sahlberg iscsi client library : login.c This file contains functions associated with loggign in to a target, negotiating session parameters and logging out from a target. Login negitiation is currently limited in scope and functionality but can log in successfully to TGTD targets and other basic targets. One main missing feature is CHAP and authenticated logins. This missing feature does not render the iscsi support useless, but is planned for future additions to the library. ... ./block/iscsi/ contains a copy of a general purpose iscsi client library which is aimed at providing a clientside api for iscsi for both qemu/kvm as well as otther scsi related utilities. As such, there is need to make merging across various consumers, qemu/kvm being one of many here, as easy as possible when features are added to the library. As such, no consumer/qemu specific code is used in this library as well as coding guidelined might not be adhered to 100% It is the intention that this library will be useful for many and that iscsi use spawned from this will flourish. Signed-off-by: Ronnie Sahlberg --- block/iscsi/login.c | 374 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 374 insertions(+), 0 deletions(-) create mode 100644 block/iscsi/login.c diff --git a/block/iscsi/login.c b/block/iscsi/login.c new file mode 100644 index 0000000..acafad0 --- /dev/null +++ b/block/iscsi/login.c @@ -0,0 +1,374 @@ +/* + Copyright (C) 2010 by Ronnie Sahlberg + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include "iscsi.h" +#include "iscsi-private.h" + +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->is_loggedin != 0) { + iscsi_set_error(iscsi, "Trying to login while already logged " + "in."); + return -1; + } + + switch (iscsi->session_type) { + case ISCSI_SESSION_DISCOVERY: + case ISCSI_SESSION_NORMAL: + break; + default: + iscsi_set_error(iscsi, "trying to login without setting " + "session type."); + return -2; + } + + pdu = iscsi_allocate_pdu(iscsi, ISCSI_PDU_LOGIN_REQUEST, + ISCSI_PDU_LOGIN_RESPONSE); + if (pdu == NULL) { + iscsi_set_error(iscsi, "Out-of-memory: Failed to allocate " + "login pdu."); + return -3; + } + + /* 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) { + iscsi_set_error(iscsi, "Out-of-memory: asprintf failed."); + iscsi_free_pdu(iscsi, pdu); + return -4; + } + ret = iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, + strlen(str)+1); + free(str); + if (ret != 0) { + iscsi_set_error(iscsi, "Out-of-memory: pdu add data failed."); + iscsi_free_pdu(iscsi, pdu); + return -5; + } + + /* optional alias */ + if (iscsi->alias) { + if (asprintf(&str, "InitiatorAlias=%s", iscsi->alias) == -1) { + iscsi_set_error(iscsi, "Out-of-memory: asprintf " + "failed."); + iscsi_free_pdu(iscsi, pdu); + return -6; + } + ret = iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, + strlen(str)+1); + free(str); + if (ret != 0) { + iscsi_set_error(iscsi, "Out-of-memory: pdu add data " + "failed."); + iscsi_free_pdu(iscsi, pdu); + return -7; + } + } + + /* target name */ + if (iscsi->session_type == ISCSI_SESSION_NORMAL) { + if (iscsi->target_name == NULL) { + iscsi_set_error(iscsi, "Trying normal connect but " + "target name not set."); + iscsi_free_pdu(iscsi, pdu); + return -8; + } + + if (asprintf(&str, "TargetName=%s", iscsi->target_name) == -1) { + iscsi_set_error(iscsi, "Out-of-memory: asprintf " + "failed."); + iscsi_free_pdu(iscsi, pdu); + return -9; + } + ret = iscsi_pdu_add_data(iscsi, pdu, (unsigned char *)str, + strlen(str)+1); + free(str); + if (ret != 0) { + iscsi_set_error(iscsi, "Out-of-memory: pdu add data " + "failed."); + iscsi_free_pdu(iscsi, pdu); + return -10; + } + } + + /* session type */ + switch (iscsi->session_type) { + case ISCSI_SESSION_DISCOVERY: + str = (char *)"SessionType=Discovery"; + break; + case ISCSI_SESSION_NORMAL: + str = (char *)"SessionType=Normal"; + break; + default: + iscsi_set_error(iscsi, "Can not handle sessions %d yet.", + iscsi->session_type); + return -11; + } + 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_free_pdu(iscsi, pdu); + return -12; + } + + switch (iscsi->want_header_digest) { + case ISCSI_HEADER_DIGEST_NONE: + str = (char *)"HeaderDigest=None"; + break; + case ISCSI_HEADER_DIGEST_NONE_CRC32C: + str = (char *)"HeaderDigest=None,CRC32C"; + break; + case ISCSI_HEADER_DIGEST_CRC32C_NONE: + str = (char *)"HeaderDigest=CRC32C,None"; + break; + case ISCSI_HEADER_DIGEST_CRC32C: + str = (char *)"HeaderDigest=CRC32C"; + break; + } + + 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_free_pdu(iscsi, pdu); + return -13; + } + str = (char *)"DataDigest=None"; + 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_free_pdu(iscsi, pdu); + return -15; + } + str = (char *)"InitialR2T=Yes"; + 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_free_pdu(iscsi, pdu); + return -16; + } + str = (char *)"ImmediateData=Yes"; + 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_free_pdu(iscsi, pdu); + return -17; + } + str = (char *)"MaxBurstLength=262144"; + 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_free_pdu(iscsi, pdu); + return -18; + } + str = (char *)"FirstBurstLength=262144"; + 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_free_pdu(iscsi, pdu); + return -19; + } + str = (char *)"MaxRecvDataSegmentLength=262144"; + 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_free_pdu(iscsi, pdu); + return -20; + } + str = (char *)"DataPDUInOrder=Yes"; + 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_free_pdu(iscsi, pdu); + return -21; + } + str = (char *)"DataSequenceInOrder=Yes"; + 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_free_pdu(iscsi, pdu); + return -22; + } + + + 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 " + "pdu."); + iscsi_free_pdu(iscsi, pdu); + return -23; + } + + return 0; +} + +int +iscsi_process_login_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, + const unsigned char *hdr, int size) +{ + int status; + + if (size < ISCSI_HEADER_SIZE) { + iscsi_set_error(iscsi, "dont have enough data to read status " + "from login reply"); + return -1; + } + + status = ntohs(*(uint16_t *)&hdr[36]); + if (status != 0) { + pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, + pdu->private_data); + return 0; + } + + iscsi->statsn = ntohs(*(uint16_t *)&hdr[24]); + + /* 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 + */ + /* skip past the header */ + hdr += ISCSI_HEADER_SIZE; + size -= ISCSI_HEADER_SIZE; + + while (size > 0) { + int len; + + len = strlen((char *)hdr); + + if (len == 0) { + break; + } + + if (len > size) { + iscsi_set_error(iscsi, "len > size when parsing " + "login data %d>%d", len, size); + pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, + pdu->private_data); + return -1; + } + + /* parse the strings */ + if (!strncmp((char *)hdr, "HeaderDigest=", 13)) { + if (!strcmp((char *)hdr + 13, "CRC32C")) { + iscsi->header_digest + = ISCSI_HEADER_DIGEST_CRC32C; + } else { + iscsi->header_digest + = ISCSI_HEADER_DIGEST_NONE; + } + } + + hdr += len + 1; + size -= len + 1; + } + + + iscsi->is_loggedin = 1; + pdu->callback(iscsi, SCSI_STATUS_GOOD, NULL, pdu->private_data); + + return 0; +} + + +int +iscsi_logout_async(struct iscsi_context *iscsi, iscsi_command_cb cb, + void *private_data) +{ + struct iscsi_pdu *pdu; + + if (iscsi->is_loggedin == 0) { + iscsi_set_error(iscsi, "Trying to logout while not logged in."); + return -1; + } + + pdu = iscsi_allocate_pdu(iscsi, ISCSI_PDU_LOGOUT_REQUEST, + ISCSI_PDU_LOGOUT_RESPONSE); + if (pdu == NULL) { + iscsi_set_error(iscsi, "Out-of-memory: Failed to allocate " + "logout pdu."); + return -2; + } + + /* logout request has the immediate flag set */ + iscsi_pdu_set_immediate(pdu); + + /* flags : close the session */ + iscsi_pdu_set_pduflags(pdu, 0x80); + + + 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 " + "logout pdu."); + iscsi_free_pdu(iscsi, pdu); + return -3; + } + + return 0; +} + +int +iscsi_process_logout_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, +const unsigned char *hdr, int size) +{ + iscsi->is_loggedin = 0; + pdu->callback(iscsi, SCSI_STATUS_GOOD, NULL, pdu->private_data); + + return 0; +} + +int +iscsi_set_session_type(struct iscsi_context *iscsi, + enum iscsi_session_type session_type) +{ + if (iscsi->is_loggedin) { + iscsi_set_error(iscsi, "trying to set session type while " + "logged in"); + return -2; + } + + iscsi->session_type = session_type; + + return 0; +}