Annotation of qemu/roms/ipxe/src/net/tcp/iscsi.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (C) 2006 Michael Brown <[email protected]>.
        !             3:  *
        !             4:  * This program is free software; you can redistribute it and/or
        !             5:  * modify it under the terms of the GNU General Public License as
        !             6:  * published by the Free Software Foundation; either version 2 of the
        !             7:  * License, or any later version.
        !             8:  *
        !             9:  * This program is distributed in the hope that it will be useful, but
        !            10:  * WITHOUT ANY WARRANTY; without even the implied warranty of
        !            11:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
        !            12:  * General Public License for more details.
        !            13:  *
        !            14:  * You should have received a copy of the GNU General Public License
        !            15:  * along with this program; if not, write to the Free Software
        !            16:  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
        !            17:  */
        !            18: 
        !            19: FILE_LICENCE ( GPL2_OR_LATER );
        !            20: 
        !            21: #include <stddef.h>
        !            22: #include <string.h>
        !            23: #include <stdlib.h>
        !            24: #include <stdio.h>
        !            25: #include <errno.h>
        !            26: #include <assert.h>
        !            27: #include <byteswap.h>
        !            28: #include <ipxe/vsprintf.h>
        !            29: #include <ipxe/socket.h>
        !            30: #include <ipxe/iobuf.h>
        !            31: #include <ipxe/uri.h>
        !            32: #include <ipxe/xfer.h>
        !            33: #include <ipxe/open.h>
        !            34: #include <ipxe/scsi.h>
        !            35: #include <ipxe/process.h>
        !            36: #include <ipxe/uaccess.h>
        !            37: #include <ipxe/tcpip.h>
        !            38: #include <ipxe/settings.h>
        !            39: #include <ipxe/features.h>
        !            40: #include <ipxe/base16.h>
        !            41: #include <ipxe/base64.h>
        !            42: #include <ipxe/ibft.h>
        !            43: #include <ipxe/iscsi.h>
        !            44: 
        !            45: /** @file
        !            46:  *
        !            47:  * iSCSI protocol
        !            48:  *
        !            49:  */
        !            50: 
        !            51: FEATURE ( FEATURE_PROTOCOL, "iSCSI", DHCP_EB_FEATURE_ISCSI, 1 );
        !            52: 
        !            53: /* Disambiguate the various error causes */
        !            54: #define EACCES_INCORRECT_TARGET_USERNAME \
        !            55:        __einfo_error ( EINFO_EACCES_INCORRECT_TARGET_USERNAME )
        !            56: #define EINFO_EACCES_INCORRECT_TARGET_USERNAME \
        !            57:        __einfo_uniqify ( EINFO_EACCES, 0x01, "Incorrect target username" )
        !            58: #define EACCES_INCORRECT_TARGET_PASSWORD \
        !            59:        __einfo_error ( EINFO_EACCES_INCORRECT_TARGET_PASSWORD )
        !            60: #define EINFO_EACCES_INCORRECT_TARGET_PASSWORD \
        !            61:        __einfo_uniqify ( EINFO_EACCES, 0x02, "Incorrect target password" )
        !            62: #define EINVAL_ROOT_PATH_TOO_SHORT \
        !            63:        __einfo_error ( EINFO_EINVAL_ROOT_PATH_TOO_SHORT )
        !            64: #define EINFO_EINVAL_ROOT_PATH_TOO_SHORT \
        !            65:        __einfo_uniqify ( EINFO_EINVAL, 0x01, "Root path too short" )
        !            66: #define EINVAL_BAD_CREDENTIAL_MIX \
        !            67:        __einfo_error ( EINFO_EINVAL_BAD_CREDENTIAL_MIX )
        !            68: #define EINFO_EINVAL_BAD_CREDENTIAL_MIX \
        !            69:        __einfo_uniqify ( EINFO_EINVAL, 0x02, "Bad credential mix" )
        !            70: #define EINVAL_NO_ROOT_PATH \
        !            71:        __einfo_error ( EINFO_EINVAL_NO_ROOT_PATH )
        !            72: #define EINFO_EINVAL_NO_ROOT_PATH \
        !            73:        __einfo_uniqify ( EINFO_EINVAL, 0x03, "No root path" )
        !            74: #define EINVAL_NO_TARGET_IQN \
        !            75:        __einfo_error ( EINFO_EINVAL_NO_TARGET_IQN )
        !            76: #define EINFO_EINVAL_NO_TARGET_IQN \
        !            77:        __einfo_uniqify ( EINFO_EINVAL, 0x04, "No target IQN" )
        !            78: #define EINVAL_NO_INITIATOR_IQN \
        !            79:        __einfo_error ( EINFO_EINVAL_NO_INITIATOR_IQN )
        !            80: #define EINFO_EINVAL_NO_INITIATOR_IQN \
        !            81:        __einfo_uniqify ( EINFO_EINVAL, 0x05, "No initiator IQN" )
        !            82: #define EIO_TARGET_UNAVAILABLE \
        !            83:        __einfo_error ( EINFO_EIO_TARGET_UNAVAILABLE )
        !            84: #define EINFO_EIO_TARGET_UNAVAILABLE \
        !            85:        __einfo_uniqify ( EINFO_EIO, 0x01, "Target not currently operational" )
        !            86: #define EIO_TARGET_NO_RESOURCES \
        !            87:        __einfo_error ( EINFO_EIO_TARGET_NO_RESOURCES )
        !            88: #define EINFO_EIO_TARGET_NO_RESOURCES \
        !            89:        __einfo_uniqify ( EINFO_EIO, 0x02, "Target out of resources" )
        !            90: #define ENOTSUP_INITIATOR_STATUS \
        !            91:        __einfo_error ( EINFO_ENOTSUP_INITIATOR_STATUS )
        !            92: #define EINFO_ENOTSUP_INITIATOR_STATUS \
        !            93:        __einfo_uniqify ( EINFO_ENOTSUP, 0x01, "Unsupported initiator status" )
        !            94: #define ENOTSUP_OPCODE \
        !            95:        __einfo_error ( EINFO_ENOTSUP_OPCODE )
        !            96: #define EINFO_ENOTSUP_OPCODE \
        !            97:        __einfo_uniqify ( EINFO_ENOTSUP, 0x02, "Unsupported opcode" )
        !            98: #define ENOTSUP_DISCOVERY \
        !            99:        __einfo_error ( EINFO_ENOTSUP_DISCOVERY )
        !           100: #define EINFO_ENOTSUP_DISCOVERY \
        !           101:        __einfo_uniqify ( EINFO_ENOTSUP, 0x03, "Discovery not supported" )
        !           102: #define ENOTSUP_TARGET_STATUS \
        !           103:        __einfo_error ( EINFO_ENOTSUP_TARGET_STATUS )
        !           104: #define EINFO_ENOTSUP_TARGET_STATUS \
        !           105:        __einfo_uniqify ( EINFO_ENOTSUP, 0x04, "Unsupported target status" )
        !           106: #define ENOTSUP_NOP_IN \
        !           107:        __einfo_error ( EINFO_ENOTSUP_NOP_IN )
        !           108: #define EINFO_ENOTSUP_NOP_IN \
        !           109:        __einfo_uniqify ( EINFO_ENOTSUP, 0x05, "Unsupported NOP-In received" )
        !           110: #define EPERM_INITIATOR_AUTHENTICATION \
        !           111:        __einfo_error ( EINFO_EPERM_INITIATOR_AUTHENTICATION )
        !           112: #define EINFO_EPERM_INITIATOR_AUTHENTICATION \
        !           113:        __einfo_uniqify ( EINFO_EPERM, 0x01, "Initiator authentication failed" )
        !           114: #define EPERM_INITIATOR_AUTHORISATION \
        !           115:        __einfo_error ( EINFO_EPERM_INITIATOR_AUTHORISATION )
        !           116: #define EINFO_EPERM_INITIATOR_AUTHORISATION \
        !           117:        __einfo_uniqify ( EINFO_EPERM, 0x02, "Initiator not authorised" )
        !           118: #define EPROTO_INVALID_CHAP_ALGORITHM \
        !           119:        __einfo_error ( EINFO_EPROTO_INVALID_CHAP_ALGORITHM )
        !           120: #define EINFO_EPROTO_INVALID_CHAP_ALGORITHM \
        !           121:        __einfo_uniqify ( EINFO_EPROTO, 0x01, "Invalid CHAP algorithm" )
        !           122: #define EPROTO_INVALID_CHAP_IDENTIFIER \
        !           123:        __einfo_error ( EINFO_EPROTO_INVALID_CHAP_IDENTIFIER )
        !           124: #define EINFO_EPROTO_INVALID_CHAP_IDENTIFIER \
        !           125:        __einfo_uniqify ( EINFO_EPROTO, 0x02, "Invalid CHAP identifier" )
        !           126: #define EPROTO_INVALID_LARGE_BINARY \
        !           127:        __einfo_error ( EINFO_EPROTO_INVALID_LARGE_BINARY )
        !           128: #define EINFO_EPROTO_INVALID_LARGE_BINARY \
        !           129:        __einfo_uniqify ( EINFO_EPROTO, 0x03, "Invalid large binary" )
        !           130: #define EPROTO_INVALID_CHAP_RESPONSE \
        !           131:        __einfo_error ( EINFO_EPROTO_INVALID_CHAP_RESPONSE )
        !           132: #define EINFO_EPROTO_INVALID_CHAP_RESPONSE \
        !           133:        __einfo_uniqify ( EINFO_EPROTO, 0x04, "Invalid CHAP response" )
        !           134: 
        !           135: static void iscsi_start_tx ( struct iscsi_session *iscsi );
        !           136: static void iscsi_start_login ( struct iscsi_session *iscsi );
        !           137: static void iscsi_start_data_out ( struct iscsi_session *iscsi,
        !           138:                                   unsigned int datasn );
        !           139: 
        !           140: /**
        !           141:  * Finish receiving PDU data into buffer
        !           142:  *
        !           143:  * @v iscsi            iSCSI session
        !           144:  */
        !           145: static void iscsi_rx_buffered_data_done ( struct iscsi_session *iscsi ) {
        !           146:        free ( iscsi->rx_buffer );
        !           147:        iscsi->rx_buffer = NULL;
        !           148: }
        !           149: 
        !           150: /**
        !           151:  * Receive PDU data into buffer
        !           152:  *
        !           153:  * @v iscsi            iSCSI session
        !           154:  * @v data             Data to receive
        !           155:  * @v len              Length of data
        !           156:  * @ret rc             Return status code
        !           157:  *
        !           158:  * This can be used when the RX PDU type handler wishes to buffer up
        !           159:  * all received data and process the PDU as a single unit.  The caller
        !           160:  * is repsonsible for calling iscsi_rx_buffered_data_done() after
        !           161:  * processing the data.
        !           162:  */
        !           163: static int iscsi_rx_buffered_data ( struct iscsi_session *iscsi,
        !           164:                                    const void *data, size_t len ) {
        !           165: 
        !           166:        /* Allocate buffer on first call */
        !           167:        if ( ! iscsi->rx_buffer ) {
        !           168:                iscsi->rx_buffer = malloc ( iscsi->rx_len );
        !           169:                if ( ! iscsi->rx_buffer )
        !           170:                        return -ENOMEM;
        !           171:        }
        !           172: 
        !           173:        /* Copy data to buffer */
        !           174:        assert ( ( iscsi->rx_offset + len ) <= iscsi->rx_len );
        !           175:        memcpy ( ( iscsi->rx_buffer + iscsi->rx_offset ), data, len );
        !           176: 
        !           177:        return 0;
        !           178: }
        !           179: 
        !           180: /**
        !           181:  * Free iSCSI session
        !           182:  *
        !           183:  * @v refcnt           Reference counter
        !           184:  */
        !           185: static void iscsi_free ( struct refcnt *refcnt ) {
        !           186:        struct iscsi_session *iscsi =
        !           187:                container_of ( refcnt, struct iscsi_session, refcnt );
        !           188: 
        !           189:        free ( iscsi->initiator_iqn );
        !           190:        free ( iscsi->target_address );
        !           191:        free ( iscsi->target_iqn );
        !           192:        free ( iscsi->initiator_username );
        !           193:        free ( iscsi->initiator_password );
        !           194:        free ( iscsi->target_username );
        !           195:        free ( iscsi->target_password );
        !           196:        chap_finish ( &iscsi->chap );
        !           197:        iscsi_rx_buffered_data_done ( iscsi );
        !           198:        free ( iscsi->command );
        !           199:        free ( iscsi );
        !           200: }
        !           201: 
        !           202: /**
        !           203:  * Shut down iSCSI interface
        !           204:  *
        !           205:  * @v iscsi            iSCSI session
        !           206:  * @v rc               Reason for close
        !           207:  */
        !           208: static void iscsi_close ( struct iscsi_session *iscsi, int rc ) {
        !           209: 
        !           210:        /* A TCP graceful close is still an error from our point of view */
        !           211:        if ( rc == 0 )
        !           212:                rc = -ECONNRESET;
        !           213: 
        !           214:        DBGC ( iscsi, "iSCSI %p closed: %s\n", iscsi, strerror ( rc ) );
        !           215: 
        !           216:        /* Stop transmission process */
        !           217:        process_del ( &iscsi->process );
        !           218: 
        !           219:        /* Shut down interfaces */
        !           220:        intf_shutdown ( &iscsi->socket, rc );
        !           221:        intf_shutdown ( &iscsi->control, rc );
        !           222:        intf_shutdown ( &iscsi->data, rc );
        !           223: }
        !           224: 
        !           225: /**
        !           226:  * Assign new iSCSI initiator task tag
        !           227:  *
        !           228:  * @v iscsi            iSCSI session
        !           229:  */
        !           230: static void iscsi_new_itt ( struct iscsi_session *iscsi ) {
        !           231:        static uint16_t itt_idx;
        !           232: 
        !           233:        iscsi->itt = ( ISCSI_TAG_MAGIC | (++itt_idx) );
        !           234: }
        !           235: 
        !           236: /**
        !           237:  * Open iSCSI transport-layer connection
        !           238:  *
        !           239:  * @v iscsi            iSCSI session
        !           240:  * @ret rc             Return status code
        !           241:  */
        !           242: static int iscsi_open_connection ( struct iscsi_session *iscsi ) {
        !           243:        struct sockaddr_tcpip target;
        !           244:        int rc;
        !           245: 
        !           246:        assert ( iscsi->tx_state == ISCSI_TX_IDLE );
        !           247:        assert ( iscsi->rx_state == ISCSI_RX_BHS );
        !           248:        assert ( iscsi->rx_offset == 0 );
        !           249: 
        !           250:        /* Open socket */
        !           251:        memset ( &target, 0, sizeof ( target ) );
        !           252:        target.st_port = htons ( iscsi->target_port );
        !           253:        if ( ( rc = xfer_open_named_socket ( &iscsi->socket, SOCK_STREAM,
        !           254:                                             ( struct sockaddr * ) &target,
        !           255:                                             iscsi->target_address,
        !           256:                                             NULL ) ) != 0 ) {
        !           257:                DBGC ( iscsi, "iSCSI %p could not open socket: %s\n",
        !           258:                       iscsi, strerror ( rc ) );
        !           259:                return rc;
        !           260:        }
        !           261: 
        !           262:        /* Enter security negotiation phase */
        !           263:        iscsi->status = ( ISCSI_STATUS_SECURITY_NEGOTIATION_PHASE |
        !           264:                          ISCSI_STATUS_STRINGS_SECURITY );
        !           265:        if ( iscsi->target_username )
        !           266:                iscsi->status |= ISCSI_STATUS_AUTH_REVERSE_REQUIRED;
        !           267: 
        !           268:        /* Assign new ISID */
        !           269:        iscsi->isid_iana_qual = ( random() & 0xffff );
        !           270: 
        !           271:        /* Assign fresh initiator task tag */
        !           272:        iscsi_new_itt ( iscsi );
        !           273: 
        !           274:        /* Initiate login */
        !           275:        iscsi_start_login ( iscsi );
        !           276: 
        !           277:        return 0;
        !           278: }
        !           279: 
        !           280: /**
        !           281:  * Close iSCSI transport-layer connection
        !           282:  *
        !           283:  * @v iscsi            iSCSI session
        !           284:  * @v rc               Reason for close
        !           285:  *
        !           286:  * Closes the transport-layer connection and resets the session state
        !           287:  * ready to attempt a fresh login.
        !           288:  */
        !           289: static void iscsi_close_connection ( struct iscsi_session *iscsi, int rc ) {
        !           290: 
        !           291:        /* Close all data transfer interfaces */
        !           292:        intf_restart ( &iscsi->socket, rc );
        !           293: 
        !           294:        /* Clear connection status */
        !           295:        iscsi->status = 0;
        !           296: 
        !           297:        /* Reset TX and RX state machines */
        !           298:        iscsi->tx_state = ISCSI_TX_IDLE;
        !           299:        iscsi->rx_state = ISCSI_RX_BHS;
        !           300:        iscsi->rx_offset = 0;
        !           301: 
        !           302:        /* Free any temporary dynamically allocated memory */
        !           303:        chap_finish ( &iscsi->chap );
        !           304:        iscsi_rx_buffered_data_done ( iscsi );
        !           305: }
        !           306: 
        !           307: /**
        !           308:  * Mark iSCSI SCSI operation as complete
        !           309:  *
        !           310:  * @v iscsi            iSCSI session
        !           311:  * @v rc               Return status code
        !           312:  * @v rsp              SCSI response, if any
        !           313:  *
        !           314:  * Note that iscsi_scsi_done() will not close the connection, and must
        !           315:  * therefore be called only when the internal state machines are in an
        !           316:  * appropriate state, otherwise bad things may happen on the next call
        !           317:  * to iscsi_scsi_command().  The general rule is to call
        !           318:  * iscsi_scsi_done() only at the end of receiving a PDU; at this point
        !           319:  * the TX and RX engines should both be idle.
        !           320:  */
        !           321: static void iscsi_scsi_done ( struct iscsi_session *iscsi, int rc,
        !           322:                              struct scsi_rsp *rsp ) {
        !           323:        uint32_t itt = iscsi->itt;
        !           324: 
        !           325:        assert ( iscsi->tx_state == ISCSI_TX_IDLE );
        !           326: 
        !           327:        /* Clear command */
        !           328:        free ( iscsi->command );
        !           329:        iscsi->command = NULL;
        !           330: 
        !           331:        /* Send SCSI response, if any */
        !           332:        scsi_response ( &iscsi->data, rsp );
        !           333: 
        !           334:        /* Close SCSI command, if this is still the same command.  (It
        !           335:         * is possible that the command interface has already been
        !           336:         * closed as a result of the SCSI response we sent.)
        !           337:         */
        !           338:        if ( iscsi->itt == itt )
        !           339:                intf_restart ( &iscsi->data, rc );
        !           340: }
        !           341: 
        !           342: /****************************************************************************
        !           343:  *
        !           344:  * iSCSI SCSI command issuing
        !           345:  *
        !           346:  */
        !           347: 
        !           348: /**
        !           349:  * Build iSCSI SCSI command BHS
        !           350:  *
        !           351:  * @v iscsi            iSCSI session
        !           352:  *
        !           353:  * We don't currently support bidirectional commands (i.e. with both
        !           354:  * Data-In and Data-Out segments); these would require providing code
        !           355:  * to generate an AHS, and there doesn't seem to be any need for it at
        !           356:  * the moment.
        !           357:  */
        !           358: static void iscsi_start_command ( struct iscsi_session *iscsi ) {
        !           359:        struct iscsi_bhs_scsi_command *command = &iscsi->tx_bhs.scsi_command;
        !           360: 
        !           361:        assert ( ! ( iscsi->command->data_in && iscsi->command->data_out ) );
        !           362: 
        !           363:        /* Construct BHS and initiate transmission */
        !           364:        iscsi_start_tx ( iscsi );
        !           365:        command->opcode = ISCSI_OPCODE_SCSI_COMMAND;
        !           366:        command->flags = ( ISCSI_FLAG_FINAL |
        !           367:                           ISCSI_COMMAND_ATTR_SIMPLE );
        !           368:        if ( iscsi->command->data_in )
        !           369:                command->flags |= ISCSI_COMMAND_FLAG_READ;
        !           370:        if ( iscsi->command->data_out )
        !           371:                command->flags |= ISCSI_COMMAND_FLAG_WRITE;
        !           372:        /* lengths left as zero */
        !           373:        memcpy ( &command->lun, &iscsi->command->lun,
        !           374:                 sizeof ( command->lun ) );
        !           375:        command->itt = htonl ( iscsi->itt );
        !           376:        command->exp_len = htonl ( iscsi->command->data_in_len |
        !           377:                                   iscsi->command->data_out_len );
        !           378:        command->cmdsn = htonl ( iscsi->cmdsn );
        !           379:        command->expstatsn = htonl ( iscsi->statsn + 1 );
        !           380:        memcpy ( &command->cdb, &iscsi->command->cdb, sizeof ( command->cdb ));
        !           381:        DBGC2 ( iscsi, "iSCSI %p start " SCSI_CDB_FORMAT " %s %#zx\n",
        !           382:                iscsi, SCSI_CDB_DATA ( command->cdb ),
        !           383:                ( iscsi->command->data_in ? "in" : "out" ),
        !           384:                ( iscsi->command->data_in ?
        !           385:                  iscsi->command->data_in_len :
        !           386:                  iscsi->command->data_out_len ) );
        !           387: }
        !           388: 
        !           389: /**
        !           390:  * Receive data segment of an iSCSI SCSI response PDU
        !           391:  *
        !           392:  * @v iscsi            iSCSI session
        !           393:  * @v data             Received data
        !           394:  * @v len              Length of received data
        !           395:  * @v remaining                Data remaining after this data
        !           396:  * @ret rc             Return status code
        !           397:  */
        !           398: static int iscsi_rx_scsi_response ( struct iscsi_session *iscsi,
        !           399:                                    const void *data, size_t len,
        !           400:                                    size_t remaining ) {
        !           401:        struct iscsi_bhs_scsi_response *response
        !           402:                = &iscsi->rx_bhs.scsi_response;
        !           403:        struct scsi_rsp rsp;
        !           404:        uint32_t residual_count;
        !           405:        int rc;
        !           406: 
        !           407:        /* Buffer up the PDU data */
        !           408:        if ( ( rc = iscsi_rx_buffered_data ( iscsi, data, len ) ) != 0 ) {
        !           409:                DBGC ( iscsi, "iSCSI %p could not buffer login response: %s\n",
        !           410:                       iscsi, strerror ( rc ) );
        !           411:                return rc;
        !           412:        }
        !           413:        if ( remaining )
        !           414:                return 0;
        !           415: 
        !           416:        /* Parse SCSI response and discard buffer */
        !           417:        memset ( &rsp, 0, sizeof ( rsp ) );
        !           418:        rsp.status = response->status;
        !           419:        residual_count = ntohl ( response->residual_count );
        !           420:        if ( response->flags & ISCSI_DATA_FLAG_OVERFLOW ) {
        !           421:                rsp.overrun = residual_count;
        !           422:        } else if ( response->flags & ISCSI_DATA_FLAG_UNDERFLOW ) {
        !           423:                rsp.overrun = -(residual_count);
        !           424:        }
        !           425:        if ( ISCSI_DATA_LEN ( response->lengths ) )
        !           426:                memcpy ( &rsp.sense, ( iscsi->rx_buffer + 2 ),
        !           427:                         sizeof ( rsp.sense ) );
        !           428:        iscsi_rx_buffered_data_done ( iscsi );
        !           429: 
        !           430:        /* Check for errors */
        !           431:        if ( response->response != ISCSI_RESPONSE_COMMAND_COMPLETE )
        !           432:                return -EIO;
        !           433: 
        !           434:        /* Mark as completed */
        !           435:        iscsi_scsi_done ( iscsi, 0, &rsp );
        !           436:        return 0;
        !           437: }
        !           438: 
        !           439: /**
        !           440:  * Receive data segment of an iSCSI data-in PDU
        !           441:  *
        !           442:  * @v iscsi            iSCSI session
        !           443:  * @v data             Received data
        !           444:  * @v len              Length of received data
        !           445:  * @v remaining                Data remaining after this data
        !           446:  * @ret rc             Return status code
        !           447:  */
        !           448: static int iscsi_rx_data_in ( struct iscsi_session *iscsi,
        !           449:                              const void *data, size_t len,
        !           450:                              size_t remaining ) {
        !           451:        struct iscsi_bhs_data_in *data_in = &iscsi->rx_bhs.data_in;
        !           452:        unsigned long offset;
        !           453: 
        !           454:        /* Copy data to data-in buffer */
        !           455:        offset = ntohl ( data_in->offset ) + iscsi->rx_offset;
        !           456:        assert ( iscsi->command != NULL );
        !           457:        assert ( iscsi->command->data_in );
        !           458:        assert ( ( offset + len ) <= iscsi->command->data_in_len );
        !           459:        copy_to_user ( iscsi->command->data_in, offset, data, len );
        !           460: 
        !           461:        /* Wait for whole SCSI response to arrive */
        !           462:        if ( remaining )
        !           463:                return 0;
        !           464: 
        !           465:        /* Mark as completed if status is present */
        !           466:        if ( data_in->flags & ISCSI_DATA_FLAG_STATUS ) {
        !           467:                assert ( ( offset + len ) == iscsi->command->data_in_len );
        !           468:                assert ( data_in->flags & ISCSI_FLAG_FINAL );
        !           469:                /* iSCSI cannot return an error status via a data-in */
        !           470:                iscsi_scsi_done ( iscsi, 0, NULL );
        !           471:        }
        !           472: 
        !           473:        return 0;
        !           474: }
        !           475: 
        !           476: /**
        !           477:  * Receive data segment of an iSCSI R2T PDU
        !           478:  *
        !           479:  * @v iscsi            iSCSI session
        !           480:  * @v data             Received data
        !           481:  * @v len              Length of received data
        !           482:  * @v remaining                Data remaining after this data
        !           483:  * @ret rc             Return status code
        !           484:  */
        !           485: static int iscsi_rx_r2t ( struct iscsi_session *iscsi,
        !           486:                          const void *data __unused, size_t len __unused,
        !           487:                          size_t remaining __unused ) {
        !           488:        struct iscsi_bhs_r2t *r2t = &iscsi->rx_bhs.r2t;
        !           489: 
        !           490:        /* Record transfer parameters and trigger first data-out */
        !           491:        iscsi->ttt = ntohl ( r2t->ttt );
        !           492:        iscsi->transfer_offset = ntohl ( r2t->offset );
        !           493:        iscsi->transfer_len = ntohl ( r2t->len );
        !           494:        iscsi_start_data_out ( iscsi, 0 );
        !           495: 
        !           496:        return 0;
        !           497: }
        !           498: 
        !           499: /**
        !           500:  * Build iSCSI data-out BHS
        !           501:  *
        !           502:  * @v iscsi            iSCSI session
        !           503:  * @v datasn           Data sequence number within the transfer
        !           504:  *
        !           505:  */
        !           506: static void iscsi_start_data_out ( struct iscsi_session *iscsi,
        !           507:                                   unsigned int datasn ) {
        !           508:        struct iscsi_bhs_data_out *data_out = &iscsi->tx_bhs.data_out;
        !           509:        unsigned long offset;
        !           510:        unsigned long remaining;
        !           511:        unsigned long len;
        !           512: 
        !           513:        /* We always send 512-byte Data-Out PDUs; this removes the
        !           514:         * need to worry about the target's MaxRecvDataSegmentLength.
        !           515:         */
        !           516:        offset = datasn * 512;
        !           517:        remaining = iscsi->transfer_len - offset;
        !           518:        len = remaining;
        !           519:        if ( len > 512 )
        !           520:                len = 512;
        !           521: 
        !           522:        /* Construct BHS and initiate transmission */
        !           523:        iscsi_start_tx ( iscsi );
        !           524:        data_out->opcode = ISCSI_OPCODE_DATA_OUT;
        !           525:        if ( len == remaining )
        !           526:                data_out->flags = ( ISCSI_FLAG_FINAL );
        !           527:        ISCSI_SET_LENGTHS ( data_out->lengths, 0, len );
        !           528:        data_out->lun = iscsi->command->lun;
        !           529:        data_out->itt = htonl ( iscsi->itt );
        !           530:        data_out->ttt = htonl ( iscsi->ttt );
        !           531:        data_out->expstatsn = htonl ( iscsi->statsn + 1 );
        !           532:        data_out->datasn = htonl ( datasn );
        !           533:        data_out->offset = htonl ( iscsi->transfer_offset + offset );
        !           534:        DBGC ( iscsi, "iSCSI %p start data out DataSN %#x len %#lx\n",
        !           535:               iscsi, datasn, len );
        !           536: }
        !           537: 
        !           538: /**
        !           539:  * Complete iSCSI data-out PDU transmission
        !           540:  *
        !           541:  * @v iscsi            iSCSI session
        !           542:  *
        !           543:  */
        !           544: static void iscsi_data_out_done ( struct iscsi_session *iscsi ) {
        !           545:        struct iscsi_bhs_data_out *data_out = &iscsi->tx_bhs.data_out;
        !           546: 
        !           547:        /* If we haven't reached the end of the sequence, start
        !           548:         * sending the next data-out PDU.
        !           549:         */
        !           550:        if ( ! ( data_out->flags & ISCSI_FLAG_FINAL ) )
        !           551:                iscsi_start_data_out ( iscsi, ntohl ( data_out->datasn ) + 1 );
        !           552: }
        !           553: 
        !           554: /**
        !           555:  * Send iSCSI data-out data segment
        !           556:  *
        !           557:  * @v iscsi            iSCSI session
        !           558:  * @ret rc             Return status code
        !           559:  */
        !           560: static int iscsi_tx_data_out ( struct iscsi_session *iscsi ) {
        !           561:        struct iscsi_bhs_data_out *data_out = &iscsi->tx_bhs.data_out;
        !           562:        struct io_buffer *iobuf;
        !           563:        unsigned long offset;
        !           564:        size_t len;
        !           565: 
        !           566:        offset = ntohl ( data_out->offset );
        !           567:        len = ISCSI_DATA_LEN ( data_out->lengths );
        !           568: 
        !           569:        assert ( iscsi->command != NULL );
        !           570:        assert ( iscsi->command->data_out );
        !           571:        assert ( ( offset + len ) <= iscsi->command->data_out_len );
        !           572: 
        !           573:        iobuf = xfer_alloc_iob ( &iscsi->socket, len );
        !           574:        if ( ! iobuf )
        !           575:                return -ENOMEM;
        !           576:        
        !           577:        copy_from_user ( iob_put ( iobuf, len ),
        !           578:                         iscsi->command->data_out, offset, len );
        !           579: 
        !           580:        return xfer_deliver_iob ( &iscsi->socket, iobuf );
        !           581: }
        !           582: 
        !           583: /**
        !           584:  * Receive data segment of an iSCSI NOP-In
        !           585:  *
        !           586:  * @v iscsi            iSCSI session
        !           587:  * @v data             Received data
        !           588:  * @v len              Length of received data
        !           589:  * @v remaining                Data remaining after this data
        !           590:  * @ret rc             Return status code
        !           591:  */
        !           592: static int iscsi_rx_nop_in ( struct iscsi_session *iscsi,
        !           593:                             const void *data __unused, size_t len __unused,
        !           594:                             size_t remaining __unused ) {
        !           595:        struct iscsi_nop_in *nop_in = &iscsi->rx_bhs.nop_in;
        !           596: 
        !           597:        DBGC2 ( iscsi, "iSCSI %p received NOP-In\n", iscsi );
        !           598: 
        !           599:        /* We don't currently have the ability to respond to NOP-Ins
        !           600:         * sent as ping requests, but we can happily accept NOP-Ins
        !           601:         * sent merely to update CmdSN.
        !           602:         */
        !           603:        if ( nop_in->ttt != htonl ( ISCSI_TAG_RESERVED ) ) {
        !           604:                DBGC ( iscsi, "iSCSI %p received unsupported NOP-In with TTT "
        !           605:                       "%08x\n", iscsi, ntohl ( nop_in->ttt ) );
        !           606:                return -ENOTSUP_NOP_IN;
        !           607:        }
        !           608: 
        !           609:        return 0;
        !           610: }
        !           611: 
        !           612: /****************************************************************************
        !           613:  *
        !           614:  * iSCSI login
        !           615:  *
        !           616:  */
        !           617: 
        !           618: /**
        !           619:  * Build iSCSI login request strings
        !           620:  *
        !           621:  * @v iscsi            iSCSI session
        !           622:  *
        !           623:  * These are the initial set of strings sent in the first login
        !           624:  * request PDU.  We want the following settings:
        !           625:  *
        !           626:  *     HeaderDigest=None
        !           627:  *     DataDigest=None
        !           628:  *     MaxConnections is irrelevant; we make only one connection anyway [4]
        !           629:  *     InitialR2T=Yes [1]
        !           630:  *     ImmediateData is irrelevant; we never send immediate data [4]
        !           631:  *     MaxRecvDataSegmentLength=8192 (default; we don't care) [3]
        !           632:  *     MaxBurstLength=262144 (default; we don't care) [3]
        !           633:  *     FirstBurstLength=262144 (default; we don't care)
        !           634:  *     DefaultTime2Wait=0 [2]
        !           635:  *     DefaultTime2Retain=0 [2]
        !           636:  *     MaxOutstandingR2T=1
        !           637:  *     DataPDUInOrder=Yes
        !           638:  *     DataSequenceInOrder=Yes
        !           639:  *     ErrorRecoveryLevel=0
        !           640:  *
        !           641:  * [1] InitialR2T has an OR resolution function, so the target may
        !           642:  * force us to use it.  We therefore simplify our logic by always
        !           643:  * using it.
        !           644:  *
        !           645:  * [2] These ensure that we can safely start a new task once we have
        !           646:  * reconnected after a failure, without having to manually tidy up
        !           647:  * after the old one.
        !           648:  *
        !           649:  * [3] We are quite happy to use the RFC-defined default values for
        !           650:  * these parameters, but some targets (notably OpenSolaris)
        !           651:  * incorrectly assume a default value of zero, so we explicitly
        !           652:  * specify the default values.
        !           653:  *
        !           654:  * [4] We are quite happy to use the RFC-defined default values for
        !           655:  * these parameters, but some targets (notably a QNAP TS-639Pro) fail
        !           656:  * unless they are supplied, so we explicitly specify the default
        !           657:  * values.
        !           658:  */
        !           659: static int iscsi_build_login_request_strings ( struct iscsi_session *iscsi,
        !           660:                                               void *data, size_t len ) {
        !           661:        unsigned int used = 0;
        !           662:        const char *auth_method;
        !           663: 
        !           664:        if ( iscsi->status & ISCSI_STATUS_STRINGS_SECURITY ) {
        !           665:                /* Default to allowing no authentication */
        !           666:                auth_method = "None";
        !           667:                /* If we have a credential to supply, permit CHAP */
        !           668:                if ( iscsi->initiator_username )
        !           669:                        auth_method = "CHAP,None";
        !           670:                /* If we have a credential to check, force CHAP */
        !           671:                if ( iscsi->target_username )
        !           672:                        auth_method = "CHAP";
        !           673:                used += ssnprintf ( data + used, len - used,
        !           674:                                    "InitiatorName=%s%c"
        !           675:                                    "TargetName=%s%c"
        !           676:                                    "SessionType=Normal%c"
        !           677:                                    "AuthMethod=%s%c",
        !           678:                                    iscsi->initiator_iqn, 0,
        !           679:                                    iscsi->target_iqn, 0, 0,
        !           680:                                    auth_method, 0 );
        !           681:        }
        !           682: 
        !           683:        if ( iscsi->status & ISCSI_STATUS_STRINGS_CHAP_ALGORITHM ) {
        !           684:                used += ssnprintf ( data + used, len - used, "CHAP_A=5%c", 0 );
        !           685:        }
        !           686:        
        !           687:        if ( ( iscsi->status & ISCSI_STATUS_STRINGS_CHAP_RESPONSE ) ) {
        !           688:                char buf[ base16_encoded_len ( iscsi->chap.response_len ) + 1 ];
        !           689:                assert ( iscsi->initiator_username != NULL );
        !           690:                base16_encode ( iscsi->chap.response, iscsi->chap.response_len,
        !           691:                                buf );
        !           692:                used += ssnprintf ( data + used, len - used,
        !           693:                                    "CHAP_N=%s%cCHAP_R=0x%s%c",
        !           694:                                    iscsi->initiator_username, 0, buf, 0 );
        !           695:        }
        !           696: 
        !           697:        if ( ( iscsi->status & ISCSI_STATUS_STRINGS_CHAP_CHALLENGE ) ) {
        !           698:                size_t challenge_len = ( sizeof ( iscsi->chap_challenge ) - 1 );
        !           699:                char buf[ base16_encoded_len ( challenge_len ) + 1 ];
        !           700:                base16_encode ( ( iscsi->chap_challenge + 1 ), challenge_len,
        !           701:                                buf );
        !           702:                used += ssnprintf ( data + used, len - used,
        !           703:                                    "CHAP_I=%d%cCHAP_C=0x%s%c",
        !           704:                                    iscsi->chap_challenge[0], 0, buf, 0 );
        !           705:        }
        !           706: 
        !           707:        if ( iscsi->status & ISCSI_STATUS_STRINGS_OPERATIONAL ) {
        !           708:                used += ssnprintf ( data + used, len - used,
        !           709:                                    "HeaderDigest=None%c"
        !           710:                                    "DataDigest=None%c"
        !           711:                                    "MaxConnections=1%c"
        !           712:                                    "InitialR2T=Yes%c"
        !           713:                                    "ImmediateData=No%c"
        !           714:                                    "MaxRecvDataSegmentLength=8192%c"
        !           715:                                    "MaxBurstLength=262144%c"
        !           716:                                    "DefaultTime2Wait=0%c"
        !           717:                                    "DefaultTime2Retain=0%c"
        !           718:                                    "MaxOutstandingR2T=1%c"
        !           719:                                    "DataPDUInOrder=Yes%c"
        !           720:                                    "DataSequenceInOrder=Yes%c"
        !           721:                                    "ErrorRecoveryLevel=0%c",
        !           722:                                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
        !           723:        }
        !           724: 
        !           725:        return used;
        !           726: }
        !           727: 
        !           728: /**
        !           729:  * Build iSCSI login request BHS
        !           730:  *
        !           731:  * @v iscsi            iSCSI session
        !           732:  */
        !           733: static void iscsi_start_login ( struct iscsi_session *iscsi ) {
        !           734:        struct iscsi_bhs_login_request *request = &iscsi->tx_bhs.login_request;
        !           735:        int len;
        !           736: 
        !           737:        switch ( iscsi->status & ISCSI_LOGIN_CSG_MASK ) {
        !           738:        case ISCSI_LOGIN_CSG_SECURITY_NEGOTIATION:
        !           739:                DBGC ( iscsi, "iSCSI %p entering security negotiation\n",
        !           740:                       iscsi );
        !           741:                break;
        !           742:        case ISCSI_LOGIN_CSG_OPERATIONAL_NEGOTIATION:
        !           743:                DBGC ( iscsi, "iSCSI %p entering operational negotiation\n",
        !           744:                       iscsi );
        !           745:                break;
        !           746:        default:
        !           747:                assert ( 0 );
        !           748:        }
        !           749: 
        !           750:        /* Construct BHS and initiate transmission */
        !           751:        iscsi_start_tx ( iscsi );
        !           752:        request->opcode = ( ISCSI_OPCODE_LOGIN_REQUEST |
        !           753:                            ISCSI_FLAG_IMMEDIATE );
        !           754:        request->flags = ( ( iscsi->status & ISCSI_STATUS_PHASE_MASK ) |
        !           755:                           ISCSI_LOGIN_FLAG_TRANSITION );
        !           756:        /* version_max and version_min left as zero */
        !           757:        len = iscsi_build_login_request_strings ( iscsi, NULL, 0 );
        !           758:        ISCSI_SET_LENGTHS ( request->lengths, 0, len );
        !           759:        request->isid_iana_en = htonl ( ISCSI_ISID_IANA |
        !           760:                                        IANA_EN_FEN_SYSTEMS );
        !           761:        request->isid_iana_qual = htons ( iscsi->isid_iana_qual );
        !           762:        /* tsih left as zero */
        !           763:        request->itt = htonl ( iscsi->itt );
        !           764:        /* cid left as zero */
        !           765:        request->cmdsn = htonl ( iscsi->cmdsn );
        !           766:        request->expstatsn = htonl ( iscsi->statsn + 1 );
        !           767: }
        !           768: 
        !           769: /**
        !           770:  * Complete iSCSI login request PDU transmission
        !           771:  *
        !           772:  * @v iscsi            iSCSI session
        !           773:  *
        !           774:  */
        !           775: static void iscsi_login_request_done ( struct iscsi_session *iscsi ) {
        !           776: 
        !           777:        /* Clear any "strings to send" flags */
        !           778:        iscsi->status &= ~ISCSI_STATUS_STRINGS_MASK;
        !           779: 
        !           780:        /* Free any dynamically allocated storage used for login */
        !           781:        chap_finish ( &iscsi->chap );
        !           782: }
        !           783: 
        !           784: /**
        !           785:  * Transmit data segment of an iSCSI login request PDU
        !           786:  *
        !           787:  * @v iscsi            iSCSI session
        !           788:  * @ret rc             Return status code
        !           789:  *
        !           790:  * For login requests, the data segment consists of the login strings.
        !           791:  */
        !           792: static int iscsi_tx_login_request ( struct iscsi_session *iscsi ) {
        !           793:        struct iscsi_bhs_login_request *request = &iscsi->tx_bhs.login_request;
        !           794:        struct io_buffer *iobuf;
        !           795:        size_t len;
        !           796: 
        !           797:        len = ISCSI_DATA_LEN ( request->lengths );
        !           798:        iobuf = xfer_alloc_iob ( &iscsi->socket, len );
        !           799:        if ( ! iobuf )
        !           800:                return -ENOMEM;
        !           801:        iob_put ( iobuf, len );
        !           802:        iscsi_build_login_request_strings ( iscsi, iobuf->data, len );
        !           803:        return xfer_deliver_iob ( &iscsi->socket, iobuf );
        !           804: }
        !           805: 
        !           806: /**
        !           807:  * Calculate maximum length of decoded large binary value
        !           808:  *
        !           809:  * @v encoded          Encoded large binary value
        !           810:  * @v max_raw_len      Maximum length of raw data
        !           811:  */
        !           812: static inline size_t
        !           813: iscsi_large_binary_decoded_max_len ( const char *encoded ) {
        !           814:        return ( strlen ( encoded ) ); /* Decoding never expands data */
        !           815: }
        !           816: 
        !           817: /**
        !           818:  * Decode large binary value
        !           819:  *
        !           820:  * @v encoded          Encoded large binary value
        !           821:  * @v raw              Raw data
        !           822:  * @ret len            Length of raw data, or negative error
        !           823:  */
        !           824: static int iscsi_large_binary_decode ( const char *encoded, uint8_t *raw ) {
        !           825: 
        !           826:        if ( encoded[0] != '0' )
        !           827:                return -EPROTO_INVALID_LARGE_BINARY;
        !           828: 
        !           829:        switch ( encoded[1] ) {
        !           830:        case 'x' :
        !           831:        case 'X' :
        !           832:                return base16_decode ( ( encoded + 2 ), raw );
        !           833:        case 'b' :
        !           834:        case 'B' :
        !           835:                return base64_decode ( ( encoded + 2 ), raw );
        !           836:        default:
        !           837:                return -EPROTO_INVALID_LARGE_BINARY;
        !           838:        }
        !           839: }
        !           840: 
        !           841: /**
        !           842:  * Handle iSCSI TargetAddress text value
        !           843:  *
        !           844:  * @v iscsi            iSCSI session
        !           845:  * @v value            TargetAddress value
        !           846:  * @ret rc             Return status code
        !           847:  */
        !           848: static int iscsi_handle_targetaddress_value ( struct iscsi_session *iscsi,
        !           849:                                              const char *value ) {
        !           850:        char *separator;
        !           851: 
        !           852:        DBGC ( iscsi, "iSCSI %p will redirect to %s\n", iscsi, value );
        !           853: 
        !           854:        /* Replace target address */
        !           855:        free ( iscsi->target_address );
        !           856:        iscsi->target_address = strdup ( value );
        !           857:        if ( ! iscsi->target_address )
        !           858:                return -ENOMEM;
        !           859: 
        !           860:        /* Replace target port */
        !           861:        iscsi->target_port = htons ( ISCSI_PORT );
        !           862:        separator = strchr ( iscsi->target_address, ':' );
        !           863:        if ( separator ) {
        !           864:                *separator = '\0';
        !           865:                iscsi->target_port = strtoul ( ( separator + 1 ), NULL, 0 );
        !           866:        }
        !           867: 
        !           868:        return 0;
        !           869: }
        !           870: 
        !           871: /**
        !           872:  * Handle iSCSI AuthMethod text value
        !           873:  *
        !           874:  * @v iscsi            iSCSI session
        !           875:  * @v value            AuthMethod value
        !           876:  * @ret rc             Return status code
        !           877:  */
        !           878: static int iscsi_handle_authmethod_value ( struct iscsi_session *iscsi,
        !           879:                                           const char *value ) {
        !           880: 
        !           881:        /* If server requests CHAP, send the CHAP_A string */
        !           882:        if ( strcmp ( value, "CHAP" ) == 0 ) {
        !           883:                DBGC ( iscsi, "iSCSI %p initiating CHAP authentication\n",
        !           884:                       iscsi );
        !           885:                iscsi->status |= ( ISCSI_STATUS_STRINGS_CHAP_ALGORITHM |
        !           886:                                   ISCSI_STATUS_AUTH_FORWARD_REQUIRED );
        !           887:        }
        !           888: 
        !           889:        return 0;
        !           890: }
        !           891: 
        !           892: /**
        !           893:  * Handle iSCSI CHAP_A text value
        !           894:  *
        !           895:  * @v iscsi            iSCSI session
        !           896:  * @v value            CHAP_A value
        !           897:  * @ret rc             Return status code
        !           898:  */
        !           899: static int iscsi_handle_chap_a_value ( struct iscsi_session *iscsi,
        !           900:                                       const char *value ) {
        !           901: 
        !           902:        /* We only ever offer "5" (i.e. MD5) as an algorithm, so if
        !           903:         * the server responds with anything else it is a protocol
        !           904:         * violation.
        !           905:         */
        !           906:        if ( strcmp ( value, "5" ) != 0 ) {
        !           907:                DBGC ( iscsi, "iSCSI %p got invalid CHAP algorithm \"%s\"\n",
        !           908:                       iscsi, value );
        !           909:                return -EPROTO_INVALID_CHAP_ALGORITHM;
        !           910:        }
        !           911: 
        !           912:        return 0;
        !           913: }
        !           914: 
        !           915: /**
        !           916:  * Handle iSCSI CHAP_I text value
        !           917:  *
        !           918:  * @v iscsi            iSCSI session
        !           919:  * @v value            CHAP_I value
        !           920:  * @ret rc             Return status code
        !           921:  */
        !           922: static int iscsi_handle_chap_i_value ( struct iscsi_session *iscsi,
        !           923:                                       const char *value ) {
        !           924:        unsigned int identifier;
        !           925:        char *endp;
        !           926:        int rc;
        !           927: 
        !           928:        /* The CHAP identifier is an integer value */
        !           929:        identifier = strtoul ( value, &endp, 0 );
        !           930:        if ( *endp != '\0' ) {
        !           931:                DBGC ( iscsi, "iSCSI %p saw invalid CHAP identifier \"%s\"\n",
        !           932:                       iscsi, value );
        !           933:                return -EPROTO_INVALID_CHAP_IDENTIFIER;
        !           934:        }
        !           935: 
        !           936:        /* Prepare for CHAP with MD5 */
        !           937:        chap_finish ( &iscsi->chap );
        !           938:        if ( ( rc = chap_init ( &iscsi->chap, &md5_algorithm ) ) != 0 ) {
        !           939:                DBGC ( iscsi, "iSCSI %p could not initialise CHAP: %s\n",
        !           940:                       iscsi, strerror ( rc ) );
        !           941:                return rc;
        !           942:        }
        !           943: 
        !           944:        /* Identifier and secret are the first two components of the
        !           945:         * challenge.
        !           946:         */
        !           947:        chap_set_identifier ( &iscsi->chap, identifier );
        !           948:        if ( iscsi->initiator_password ) {
        !           949:                chap_update ( &iscsi->chap, iscsi->initiator_password,
        !           950:                              strlen ( iscsi->initiator_password ) );
        !           951:        }
        !           952: 
        !           953:        return 0;
        !           954: }
        !           955: 
        !           956: /**
        !           957:  * Handle iSCSI CHAP_C text value
        !           958:  *
        !           959:  * @v iscsi            iSCSI session
        !           960:  * @v value            CHAP_C value
        !           961:  * @ret rc             Return status code
        !           962:  */
        !           963: static int iscsi_handle_chap_c_value ( struct iscsi_session *iscsi,
        !           964:                                       const char *value ) {
        !           965:        uint8_t buf[ iscsi_large_binary_decoded_max_len ( value ) ];
        !           966:        unsigned int i;
        !           967:        size_t len;
        !           968:        int rc;
        !           969: 
        !           970:        /* Process challenge */
        !           971:        rc = iscsi_large_binary_decode ( value, buf );
        !           972:        if ( rc < 0 ) {
        !           973:                DBGC ( iscsi, "iSCSI %p invalid CHAP challenge \"%s\": %s\n",
        !           974:                       iscsi, value, strerror ( rc ) );
        !           975:                return rc;
        !           976:        }
        !           977:        len = rc;
        !           978:        chap_update ( &iscsi->chap, buf, len );
        !           979: 
        !           980:        /* Build CHAP response */
        !           981:        DBGC ( iscsi, "iSCSI %p sending CHAP response\n", iscsi );
        !           982:        chap_respond ( &iscsi->chap );
        !           983:        iscsi->status |= ISCSI_STATUS_STRINGS_CHAP_RESPONSE;
        !           984: 
        !           985:        /* Send CHAP challenge, if applicable */
        !           986:        if ( iscsi->target_username ) {
        !           987:                iscsi->status |= ISCSI_STATUS_STRINGS_CHAP_CHALLENGE;
        !           988:                /* Generate CHAP challenge data */
        !           989:                for ( i = 0 ; i < sizeof ( iscsi->chap_challenge ) ; i++ ) {
        !           990:                        iscsi->chap_challenge[i] = random();
        !           991:                }
        !           992:        }
        !           993: 
        !           994:        return 0;
        !           995: }
        !           996: 
        !           997: /**
        !           998:  * Handle iSCSI CHAP_N text value
        !           999:  *
        !          1000:  * @v iscsi            iSCSI session
        !          1001:  * @v value            CHAP_N value
        !          1002:  * @ret rc             Return status code
        !          1003:  */
        !          1004: static int iscsi_handle_chap_n_value ( struct iscsi_session *iscsi,
        !          1005:                                       const char *value ) {
        !          1006: 
        !          1007:        /* The target username isn't actually involved at any point in
        !          1008:         * the authentication process; it merely serves to identify
        !          1009:         * which password the target is using to generate the CHAP
        !          1010:         * response.  We unnecessarily verify that the username is as
        !          1011:         * expected, in order to provide mildly helpful diagnostics if
        !          1012:         * the target is supplying the wrong username/password
        !          1013:         * combination.
        !          1014:         */
        !          1015:        if ( iscsi->target_username &&
        !          1016:             ( strcmp ( iscsi->target_username, value ) != 0 ) ) {
        !          1017:                DBGC ( iscsi, "iSCSI %p target username \"%s\" incorrect "
        !          1018:                       "(wanted \"%s\")\n",
        !          1019:                       iscsi, value, iscsi->target_username );
        !          1020:                return -EACCES_INCORRECT_TARGET_USERNAME;
        !          1021:        }
        !          1022: 
        !          1023:        return 0;
        !          1024: }
        !          1025: 
        !          1026: /**
        !          1027:  * Handle iSCSI CHAP_R text value
        !          1028:  *
        !          1029:  * @v iscsi            iSCSI session
        !          1030:  * @v value            CHAP_R value
        !          1031:  * @ret rc             Return status code
        !          1032:  */
        !          1033: static int iscsi_handle_chap_r_value ( struct iscsi_session *iscsi,
        !          1034:                                       const char *value ) {
        !          1035:        uint8_t buf[ iscsi_large_binary_decoded_max_len ( value ) ];
        !          1036:        size_t len;
        !          1037:        int rc;
        !          1038: 
        !          1039:        /* Generate CHAP response for verification */
        !          1040:        chap_finish ( &iscsi->chap );
        !          1041:        if ( ( rc = chap_init ( &iscsi->chap, &md5_algorithm ) ) != 0 ) {
        !          1042:                DBGC ( iscsi, "iSCSI %p could not initialise CHAP: %s\n",
        !          1043:                       iscsi, strerror ( rc ) );
        !          1044:                return rc;
        !          1045:        }
        !          1046:        chap_set_identifier ( &iscsi->chap, iscsi->chap_challenge[0] );
        !          1047:        if ( iscsi->target_password ) {
        !          1048:                chap_update ( &iscsi->chap, iscsi->target_password,
        !          1049:                              strlen ( iscsi->target_password ) );
        !          1050:        }
        !          1051:        chap_update ( &iscsi->chap, &iscsi->chap_challenge[1],
        !          1052:                      ( sizeof ( iscsi->chap_challenge ) - 1 ) );
        !          1053:        chap_respond ( &iscsi->chap );
        !          1054: 
        !          1055:        /* Process response */
        !          1056:        rc = iscsi_large_binary_decode ( value, buf );
        !          1057:        if ( rc < 0 ) {
        !          1058:                DBGC ( iscsi, "iSCSI %p invalid CHAP response \"%s\": %s\n",
        !          1059:                       iscsi, value, strerror ( rc ) );
        !          1060:                return rc;
        !          1061:        }
        !          1062:        len = rc;
        !          1063: 
        !          1064:        /* Check CHAP response */
        !          1065:        if ( len != iscsi->chap.response_len ) {
        !          1066:                DBGC ( iscsi, "iSCSI %p invalid CHAP response length\n",
        !          1067:                       iscsi );
        !          1068:                return -EPROTO_INVALID_CHAP_RESPONSE;
        !          1069:        }
        !          1070:        if ( memcmp ( buf, iscsi->chap.response, len ) != 0 ) {
        !          1071:                DBGC ( iscsi, "iSCSI %p incorrect CHAP response \"%s\"\n",
        !          1072:                       iscsi, value );
        !          1073:                return -EACCES_INCORRECT_TARGET_PASSWORD;
        !          1074:        }
        !          1075: 
        !          1076:        /* Mark session as authenticated */
        !          1077:        iscsi->status |= ISCSI_STATUS_AUTH_REVERSE_OK;
        !          1078: 
        !          1079:        return 0;
        !          1080: }
        !          1081: 
        !          1082: /** An iSCSI text string that we want to handle */
        !          1083: struct iscsi_string_type {
        !          1084:        /** String key
        !          1085:         *
        !          1086:         * This is the portion up to and including the "=" sign,
        !          1087:         * e.g. "InitiatorName=", "CHAP_A=", etc.
        !          1088:         */
        !          1089:        const char *key;
        !          1090:        /** Handle iSCSI string value
        !          1091:         *
        !          1092:         * @v iscsi             iSCSI session
        !          1093:         * @v value             iSCSI string value
        !          1094:         * @ret rc              Return status code
        !          1095:         */
        !          1096:        int ( * handle ) ( struct iscsi_session *iscsi, const char *value );
        !          1097: };
        !          1098: 
        !          1099: /** iSCSI text strings that we want to handle */
        !          1100: static struct iscsi_string_type iscsi_string_types[] = {
        !          1101:        { "TargetAddress=", iscsi_handle_targetaddress_value },
        !          1102:        { "AuthMethod=", iscsi_handle_authmethod_value },
        !          1103:        { "CHAP_A=", iscsi_handle_chap_a_value },
        !          1104:        { "CHAP_I=", iscsi_handle_chap_i_value },
        !          1105:        { "CHAP_C=", iscsi_handle_chap_c_value },
        !          1106:        { "CHAP_N=", iscsi_handle_chap_n_value },
        !          1107:        { "CHAP_R=", iscsi_handle_chap_r_value },
        !          1108:        { NULL, NULL }
        !          1109: };
        !          1110: 
        !          1111: /**
        !          1112:  * Handle iSCSI string
        !          1113:  *
        !          1114:  * @v iscsi            iSCSI session
        !          1115:  * @v string           iSCSI string (in "key=value" format)
        !          1116:  * @ret rc             Return status code
        !          1117:  */
        !          1118: static int iscsi_handle_string ( struct iscsi_session *iscsi,
        !          1119:                                 const char *string ) {
        !          1120:        struct iscsi_string_type *type;
        !          1121:        size_t key_len;
        !          1122:        int rc;
        !          1123: 
        !          1124:        for ( type = iscsi_string_types ; type->key ; type++ ) {
        !          1125:                key_len = strlen ( type->key );
        !          1126:                if ( strncmp ( string, type->key, key_len ) != 0 )
        !          1127:                        continue;
        !          1128:                DBGC ( iscsi, "iSCSI %p handling %s\n", iscsi, string );
        !          1129:                if ( ( rc = type->handle ( iscsi,
        !          1130:                                           ( string + key_len ) ) ) != 0 ) {
        !          1131:                        DBGC ( iscsi, "iSCSI %p could not handle %s: %s\n",
        !          1132:                               iscsi, string, strerror ( rc ) );
        !          1133:                        return rc;
        !          1134:                }
        !          1135:                return 0;
        !          1136:        }
        !          1137:        DBGC ( iscsi, "iSCSI %p ignoring %s\n", iscsi, string );
        !          1138:        return 0;
        !          1139: }
        !          1140: 
        !          1141: /**
        !          1142:  * Handle iSCSI strings
        !          1143:  *
        !          1144:  * @v iscsi            iSCSI session
        !          1145:  * @v string           iSCSI string buffer
        !          1146:  * @v len              Length of string buffer
        !          1147:  * @ret rc             Return status code
        !          1148:  */
        !          1149: static int iscsi_handle_strings ( struct iscsi_session *iscsi,
        !          1150:                                  const char *strings, size_t len ) {
        !          1151:        size_t string_len;
        !          1152:        int rc;
        !          1153: 
        !          1154:        /* Handle each string in turn, taking care not to overrun the
        !          1155:         * data buffer in case of badly-terminated data.
        !          1156:         */
        !          1157:        while ( 1 ) {
        !          1158:                string_len = ( strnlen ( strings, len ) + 1 );
        !          1159:                if ( string_len > len )
        !          1160:                        break;
        !          1161:                if ( ( rc = iscsi_handle_string ( iscsi, strings ) ) != 0 )
        !          1162:                        return rc;
        !          1163:                strings += string_len;
        !          1164:                len -= string_len;
        !          1165:        }
        !          1166:        return 0;
        !          1167: }
        !          1168: 
        !          1169: /**
        !          1170:  * Convert iSCSI response status to return status code
        !          1171:  *
        !          1172:  * @v status_class     iSCSI status class
        !          1173:  * @v status_detail    iSCSI status detail
        !          1174:  * @ret rc             Return status code
        !          1175:  */
        !          1176: static int iscsi_status_to_rc ( unsigned int status_class,
        !          1177:                                unsigned int status_detail ) {
        !          1178:        switch ( status_class ) {
        !          1179:        case ISCSI_STATUS_INITIATOR_ERROR :
        !          1180:                switch ( status_detail ) {
        !          1181:                case ISCSI_STATUS_INITIATOR_ERROR_AUTHENTICATION :
        !          1182:                        return -EPERM_INITIATOR_AUTHENTICATION;
        !          1183:                case ISCSI_STATUS_INITIATOR_ERROR_AUTHORISATION :
        !          1184:                        return -EPERM_INITIATOR_AUTHORISATION;
        !          1185:                case ISCSI_STATUS_INITIATOR_ERROR_NOT_FOUND :
        !          1186:                case ISCSI_STATUS_INITIATOR_ERROR_REMOVED :
        !          1187:                        return -ENODEV;
        !          1188:                default :
        !          1189:                        return -ENOTSUP_INITIATOR_STATUS;
        !          1190:                }
        !          1191:        case ISCSI_STATUS_TARGET_ERROR :
        !          1192:                switch ( status_detail ) {
        !          1193:                case ISCSI_STATUS_TARGET_ERROR_UNAVAILABLE:
        !          1194:                        return -EIO_TARGET_UNAVAILABLE;
        !          1195:                case ISCSI_STATUS_TARGET_ERROR_NO_RESOURCES:
        !          1196:                        return -EIO_TARGET_NO_RESOURCES;
        !          1197:                default:
        !          1198:                        return -ENOTSUP_TARGET_STATUS;
        !          1199:                }
        !          1200:        default :
        !          1201:                return -EINVAL;
        !          1202:        }
        !          1203: }
        !          1204: 
        !          1205: /**
        !          1206:  * Receive data segment of an iSCSI login response PDU
        !          1207:  *
        !          1208:  * @v iscsi            iSCSI session
        !          1209:  * @v data             Received data
        !          1210:  * @v len              Length of received data
        !          1211:  * @v remaining                Data remaining after this data
        !          1212:  * @ret rc             Return status code
        !          1213:  */
        !          1214: static int iscsi_rx_login_response ( struct iscsi_session *iscsi,
        !          1215:                                     const void *data, size_t len,
        !          1216:                                     size_t remaining ) {
        !          1217:        struct iscsi_bhs_login_response *response
        !          1218:                = &iscsi->rx_bhs.login_response;
        !          1219:        int rc;
        !          1220: 
        !          1221:        /* Buffer up the PDU data */
        !          1222:        if ( ( rc = iscsi_rx_buffered_data ( iscsi, data, len ) ) != 0 ) {
        !          1223:                DBGC ( iscsi, "iSCSI %p could not buffer login response: %s\n",
        !          1224:                       iscsi, strerror ( rc ) );
        !          1225:                return rc;
        !          1226:        }
        !          1227:        if ( remaining )
        !          1228:                return 0;
        !          1229: 
        !          1230:        /* Process string data and discard string buffer */
        !          1231:        if ( ( rc = iscsi_handle_strings ( iscsi, iscsi->rx_buffer,
        !          1232:                                           iscsi->rx_len ) ) != 0 )
        !          1233:                return rc;
        !          1234:        iscsi_rx_buffered_data_done ( iscsi );
        !          1235: 
        !          1236:        /* Check for login redirection */
        !          1237:        if ( response->status_class == ISCSI_STATUS_REDIRECT ) {
        !          1238:                DBGC ( iscsi, "iSCSI %p redirecting to new server\n", iscsi );
        !          1239:                iscsi_close_connection ( iscsi, 0 );
        !          1240:                if ( ( rc = iscsi_open_connection ( iscsi ) ) != 0 ) {
        !          1241:                        DBGC ( iscsi, "iSCSI %p could not redirect: %s\n ",
        !          1242:                               iscsi, strerror ( rc ) );
        !          1243:                        return rc;
        !          1244:                }
        !          1245:                return 0;
        !          1246:        }
        !          1247: 
        !          1248:        /* Check for fatal errors */
        !          1249:        if ( response->status_class != 0 ) {
        !          1250:                DBGC ( iscsi, "iSCSI login failure: class %02x detail %02x\n",
        !          1251:                       response->status_class, response->status_detail );
        !          1252:                rc = iscsi_status_to_rc ( response->status_class,
        !          1253:                                          response->status_detail );
        !          1254:                return rc;
        !          1255:        }
        !          1256: 
        !          1257:        /* Handle login transitions */
        !          1258:        if ( response->flags & ISCSI_LOGIN_FLAG_TRANSITION ) {
        !          1259:                iscsi->status &= ~( ISCSI_STATUS_PHASE_MASK |
        !          1260:                                    ISCSI_STATUS_STRINGS_MASK );
        !          1261:                switch ( response->flags & ISCSI_LOGIN_NSG_MASK ) {
        !          1262:                case ISCSI_LOGIN_NSG_OPERATIONAL_NEGOTIATION:
        !          1263:                        iscsi->status |=
        !          1264:                                ( ISCSI_STATUS_OPERATIONAL_NEGOTIATION_PHASE |
        !          1265:                                  ISCSI_STATUS_STRINGS_OPERATIONAL );
        !          1266:                        break;
        !          1267:                case ISCSI_LOGIN_NSG_FULL_FEATURE_PHASE:
        !          1268:                        iscsi->status |= ISCSI_STATUS_FULL_FEATURE_PHASE;
        !          1269:                        break;
        !          1270:                default:
        !          1271:                        DBGC ( iscsi, "iSCSI %p got invalid response flags "
        !          1272:                               "%02x\n", iscsi, response->flags );
        !          1273:                        return -EIO;
        !          1274:                }
        !          1275:        }
        !          1276: 
        !          1277:        /* Send next login request PDU if we haven't reached the full
        !          1278:         * feature phase yet.
        !          1279:         */
        !          1280:        if ( ( iscsi->status & ISCSI_STATUS_PHASE_MASK ) !=
        !          1281:             ISCSI_STATUS_FULL_FEATURE_PHASE ) {
        !          1282:                iscsi_start_login ( iscsi );
        !          1283:                return 0;
        !          1284:        }
        !          1285: 
        !          1286:        /* Check that target authentication was successful (if required) */
        !          1287:        if ( ( iscsi->status & ISCSI_STATUS_AUTH_REVERSE_REQUIRED ) &&
        !          1288:             ! ( iscsi->status & ISCSI_STATUS_AUTH_REVERSE_OK ) ) {
        !          1289:                DBGC ( iscsi, "iSCSI %p nefarious target tried to bypass "
        !          1290:                       "authentication\n", iscsi );
        !          1291:                return -EPROTO;
        !          1292:        }
        !          1293: 
        !          1294:        /* Notify SCSI layer of window change */
        !          1295:        DBGC ( iscsi, "iSCSI %p entering full feature phase\n", iscsi );
        !          1296:        xfer_window_changed ( &iscsi->control );
        !          1297: 
        !          1298:        return 0;
        !          1299: }
        !          1300: 
        !          1301: /****************************************************************************
        !          1302:  *
        !          1303:  * iSCSI to socket interface
        !          1304:  *
        !          1305:  */
        !          1306: 
        !          1307: /**
        !          1308:  * Start up a new TX PDU
        !          1309:  *
        !          1310:  * @v iscsi            iSCSI session
        !          1311:  *
        !          1312:  * This initiates the process of sending a new PDU.  Only one PDU may
        !          1313:  * be in transit at any one time.
        !          1314:  */
        !          1315: static void iscsi_start_tx ( struct iscsi_session *iscsi ) {
        !          1316: 
        !          1317:        assert ( iscsi->tx_state == ISCSI_TX_IDLE );
        !          1318:        assert ( ! process_running ( &iscsi->process ) );
        !          1319:        
        !          1320:        /* Initialise TX BHS */
        !          1321:        memset ( &iscsi->tx_bhs, 0, sizeof ( iscsi->tx_bhs ) );
        !          1322: 
        !          1323:        /* Flag TX engine to start transmitting */
        !          1324:        iscsi->tx_state = ISCSI_TX_BHS;
        !          1325: 
        !          1326:        /* Start transmission process */
        !          1327:        process_add ( &iscsi->process );
        !          1328: }
        !          1329: 
        !          1330: /**
        !          1331:  * Transmit nothing
        !          1332:  *
        !          1333:  * @v iscsi            iSCSI session
        !          1334:  * @ret rc             Return status code
        !          1335:  */
        !          1336: static int iscsi_tx_nothing ( struct iscsi_session *iscsi __unused ) {
        !          1337:        return 0;
        !          1338: }
        !          1339: 
        !          1340: /**
        !          1341:  * Transmit basic header segment of an iSCSI PDU
        !          1342:  *
        !          1343:  * @v iscsi            iSCSI session
        !          1344:  * @ret rc             Return status code
        !          1345:  */
        !          1346: static int iscsi_tx_bhs ( struct iscsi_session *iscsi ) {
        !          1347:        return xfer_deliver_raw ( &iscsi->socket,  &iscsi->tx_bhs,
        !          1348:                                  sizeof ( iscsi->tx_bhs ) );
        !          1349: }
        !          1350: 
        !          1351: /**
        !          1352:  * Transmit data segment of an iSCSI PDU
        !          1353:  *
        !          1354:  * @v iscsi            iSCSI session
        !          1355:  * @ret rc             Return status code
        !          1356:  * 
        !          1357:  * Handle transmission of part of a PDU data segment.  iscsi::tx_bhs
        !          1358:  * will be valid when this is called.
        !          1359:  */
        !          1360: static int iscsi_tx_data ( struct iscsi_session *iscsi ) {
        !          1361:        struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
        !          1362: 
        !          1363:        switch ( common->opcode & ISCSI_OPCODE_MASK ) {
        !          1364:        case ISCSI_OPCODE_DATA_OUT:
        !          1365:                return iscsi_tx_data_out ( iscsi );
        !          1366:        case ISCSI_OPCODE_LOGIN_REQUEST:
        !          1367:                return iscsi_tx_login_request ( iscsi );
        !          1368:        default:
        !          1369:                /* Nothing to send in other states */
        !          1370:                return 0;
        !          1371:        }
        !          1372: }
        !          1373: 
        !          1374: /**
        !          1375:  * Transmit data padding of an iSCSI PDU
        !          1376:  *
        !          1377:  * @v iscsi            iSCSI session
        !          1378:  * @ret rc             Return status code
        !          1379:  * 
        !          1380:  * Handle transmission of any data padding in a PDU data segment.
        !          1381:  * iscsi::tx_bhs will be valid when this is called.
        !          1382:  */
        !          1383: static int iscsi_tx_data_padding ( struct iscsi_session *iscsi ) {
        !          1384:        static const char pad[] = { '\0', '\0', '\0' };
        !          1385:        struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
        !          1386:        size_t pad_len;
        !          1387:        
        !          1388:        pad_len = ISCSI_DATA_PAD_LEN ( common->lengths );
        !          1389:        if ( ! pad_len )
        !          1390:                return 0;
        !          1391: 
        !          1392:        return xfer_deliver_raw ( &iscsi->socket, pad, pad_len );
        !          1393: }
        !          1394: 
        !          1395: /**
        !          1396:  * Complete iSCSI PDU transmission
        !          1397:  *
        !          1398:  * @v iscsi            iSCSI session
        !          1399:  *
        !          1400:  * Called when a PDU has been completely transmitted and the TX state
        !          1401:  * machine is about to enter the idle state.  iscsi::tx_bhs will be
        !          1402:  * valid for the just-completed PDU when this is called.
        !          1403:  */
        !          1404: static void iscsi_tx_done ( struct iscsi_session *iscsi ) {
        !          1405:        struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
        !          1406: 
        !          1407:        /* Stop transmission process */
        !          1408:        process_del ( &iscsi->process );
        !          1409: 
        !          1410:        switch ( common->opcode & ISCSI_OPCODE_MASK ) {
        !          1411:        case ISCSI_OPCODE_DATA_OUT:
        !          1412:                iscsi_data_out_done ( iscsi );
        !          1413:        case ISCSI_OPCODE_LOGIN_REQUEST:
        !          1414:                iscsi_login_request_done ( iscsi );
        !          1415:        default:
        !          1416:                /* No action */
        !          1417:                break;
        !          1418:        }
        !          1419: }
        !          1420: 
        !          1421: /**
        !          1422:  * Transmit iSCSI PDU
        !          1423:  *
        !          1424:  * @v iscsi            iSCSI session
        !          1425:  * @v buf              Temporary data buffer
        !          1426:  * @v len              Length of temporary data buffer
        !          1427:  * 
        !          1428:  * Constructs data to be sent for the current TX state
        !          1429:  */
        !          1430: static void iscsi_tx_step ( struct process *process ) {
        !          1431:        struct iscsi_session *iscsi =
        !          1432:                container_of ( process, struct iscsi_session, process );
        !          1433:        struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
        !          1434:        int ( * tx ) ( struct iscsi_session *iscsi );
        !          1435:        enum iscsi_tx_state next_state;
        !          1436:        size_t tx_len;
        !          1437:        int rc;
        !          1438: 
        !          1439:        /* Select fragment to transmit */
        !          1440:        while ( 1 ) {
        !          1441:                switch ( iscsi->tx_state ) {
        !          1442:                case ISCSI_TX_BHS:
        !          1443:                        tx = iscsi_tx_bhs;
        !          1444:                        tx_len = sizeof ( iscsi->tx_bhs );
        !          1445:                        next_state = ISCSI_TX_AHS;
        !          1446:                        break;
        !          1447:                case ISCSI_TX_AHS:
        !          1448:                        tx = iscsi_tx_nothing;
        !          1449:                        tx_len = 0;
        !          1450:                        next_state = ISCSI_TX_DATA;
        !          1451:                        break;
        !          1452:                case ISCSI_TX_DATA:
        !          1453:                        tx = iscsi_tx_data;
        !          1454:                        tx_len = ISCSI_DATA_LEN ( common->lengths );
        !          1455:                        next_state = ISCSI_TX_DATA_PADDING;
        !          1456:                        break;
        !          1457:                case ISCSI_TX_DATA_PADDING:
        !          1458:                        tx = iscsi_tx_data_padding;
        !          1459:                        tx_len = ISCSI_DATA_PAD_LEN ( common->lengths );
        !          1460:                        next_state = ISCSI_TX_IDLE;
        !          1461:                        break;
        !          1462:                case ISCSI_TX_IDLE:
        !          1463:                        /* Stop processing */
        !          1464:                        iscsi_tx_done ( iscsi );
        !          1465:                        return;
        !          1466:                default:
        !          1467:                        assert ( 0 );
        !          1468:                        return;
        !          1469:                }
        !          1470: 
        !          1471:                /* Check for window availability, if needed */
        !          1472:                if ( tx_len && ( xfer_window ( &iscsi->socket ) == 0 ) ) {
        !          1473:                        /* Cannot transmit at this point; stop processing */
        !          1474:                        return;
        !          1475:                }
        !          1476: 
        !          1477:                /* Transmit data */
        !          1478:                if ( ( rc = tx ( iscsi ) ) != 0 ) {
        !          1479:                        DBGC ( iscsi, "iSCSI %p could not transmit: %s\n",
        !          1480:                               iscsi, strerror ( rc ) );
        !          1481:                        /* Transmission errors are fatal */
        !          1482:                        iscsi_close ( iscsi, rc );
        !          1483:                        return;
        !          1484:                }
        !          1485: 
        !          1486:                /* Move to next state */
        !          1487:                iscsi->tx_state = next_state;
        !          1488:        }
        !          1489: }
        !          1490: 
        !          1491: /**
        !          1492:  * Receive basic header segment of an iSCSI PDU
        !          1493:  *
        !          1494:  * @v iscsi            iSCSI session
        !          1495:  * @v data             Received data
        !          1496:  * @v len              Length of received data
        !          1497:  * @v remaining                Data remaining after this data
        !          1498:  * @ret rc             Return status code
        !          1499:  *
        !          1500:  * This fills in iscsi::rx_bhs with the data from the BHS portion of
        !          1501:  * the received PDU.
        !          1502:  */
        !          1503: static int iscsi_rx_bhs ( struct iscsi_session *iscsi, const void *data,
        !          1504:                          size_t len, size_t remaining __unused ) {
        !          1505:        memcpy ( &iscsi->rx_bhs.bytes[iscsi->rx_offset], data, len );
        !          1506:        if ( ( iscsi->rx_offset + len ) >= sizeof ( iscsi->rx_bhs ) ) {
        !          1507:                DBGC2 ( iscsi, "iSCSI %p received PDU opcode %#x len %#x\n",
        !          1508:                        iscsi, iscsi->rx_bhs.common.opcode,
        !          1509:                        ISCSI_DATA_LEN ( iscsi->rx_bhs.common.lengths ) );
        !          1510:        }
        !          1511:        return 0;
        !          1512: }
        !          1513: 
        !          1514: /**
        !          1515:  * Discard portion of an iSCSI PDU.
        !          1516:  *
        !          1517:  * @v iscsi            iSCSI session
        !          1518:  * @v data             Received data
        !          1519:  * @v len              Length of received data
        !          1520:  * @v remaining                Data remaining after this data
        !          1521:  * @ret rc             Return status code
        !          1522:  *
        !          1523:  * This discards data from a portion of a received PDU.
        !          1524:  */
        !          1525: static int iscsi_rx_discard ( struct iscsi_session *iscsi __unused,
        !          1526:                              const void *data __unused, size_t len __unused,
        !          1527:                              size_t remaining __unused ) {
        !          1528:        /* Do nothing */
        !          1529:        return 0;
        !          1530: }
        !          1531: 
        !          1532: /**
        !          1533:  * Receive data segment of an iSCSI PDU
        !          1534:  *
        !          1535:  * @v iscsi            iSCSI session
        !          1536:  * @v data             Received data
        !          1537:  * @v len              Length of received data
        !          1538:  * @v remaining                Data remaining after this data
        !          1539:  * @ret rc             Return status code
        !          1540:  *
        !          1541:  * Handle processing of part of a PDU data segment.  iscsi::rx_bhs
        !          1542:  * will be valid when this is called.
        !          1543:  */
        !          1544: static int iscsi_rx_data ( struct iscsi_session *iscsi, const void *data,
        !          1545:                           size_t len, size_t remaining ) {
        !          1546:        struct iscsi_bhs_common_response *response
        !          1547:                = &iscsi->rx_bhs.common_response;
        !          1548: 
        !          1549:        /* Update cmdsn and statsn */
        !          1550:        iscsi->cmdsn = ntohl ( response->expcmdsn );
        !          1551:        iscsi->statsn = ntohl ( response->statsn );
        !          1552: 
        !          1553:        switch ( response->opcode & ISCSI_OPCODE_MASK ) {
        !          1554:        case ISCSI_OPCODE_LOGIN_RESPONSE:
        !          1555:                return iscsi_rx_login_response ( iscsi, data, len, remaining );
        !          1556:        case ISCSI_OPCODE_SCSI_RESPONSE:
        !          1557:                return iscsi_rx_scsi_response ( iscsi, data, len, remaining );
        !          1558:        case ISCSI_OPCODE_DATA_IN:
        !          1559:                return iscsi_rx_data_in ( iscsi, data, len, remaining );
        !          1560:        case ISCSI_OPCODE_R2T:
        !          1561:                return iscsi_rx_r2t ( iscsi, data, len, remaining );
        !          1562:        case ISCSI_OPCODE_NOP_IN:
        !          1563:                return iscsi_rx_nop_in ( iscsi, data, len, remaining );
        !          1564:        default:
        !          1565:                if ( remaining )
        !          1566:                        return 0;
        !          1567:                DBGC ( iscsi, "iSCSI %p unknown opcode %02x\n", iscsi,
        !          1568:                       response->opcode );
        !          1569:                return -ENOTSUP_OPCODE;
        !          1570:        }
        !          1571: }
        !          1572: 
        !          1573: /**
        !          1574:  * Receive new data
        !          1575:  *
        !          1576:  * @v iscsi            iSCSI session
        !          1577:  * @v iobuf            I/O buffer
        !          1578:  * @v meta             Data transfer metadata
        !          1579:  * @ret rc             Return status code
        !          1580:  *
        !          1581:  * This handles received PDUs.  The receive strategy is to fill in
        !          1582:  * iscsi::rx_bhs with the contents of the BHS portion of the PDU,
        !          1583:  * throw away any AHS portion, and then process each part of the data
        !          1584:  * portion as it arrives.  The data processing routine therefore
        !          1585:  * always has a full copy of the BHS available, even for portions of
        !          1586:  * the data in different packets to the BHS.
        !          1587:  */
        !          1588: static int iscsi_socket_deliver ( struct iscsi_session *iscsi,
        !          1589:                                  struct io_buffer *iobuf,
        !          1590:                                  struct xfer_metadata *meta __unused ) {
        !          1591:        struct iscsi_bhs_common *common = &iscsi->rx_bhs.common;
        !          1592:        int ( * rx ) ( struct iscsi_session *iscsi, const void *data,
        !          1593:                       size_t len, size_t remaining );
        !          1594:        enum iscsi_rx_state next_state;
        !          1595:        size_t frag_len;
        !          1596:        size_t remaining;
        !          1597:        int rc;
        !          1598: 
        !          1599:        while ( 1 ) {
        !          1600:                switch ( iscsi->rx_state ) {
        !          1601:                case ISCSI_RX_BHS:
        !          1602:                        rx = iscsi_rx_bhs;
        !          1603:                        iscsi->rx_len = sizeof ( iscsi->rx_bhs );
        !          1604:                        next_state = ISCSI_RX_AHS;                      
        !          1605:                        break;
        !          1606:                case ISCSI_RX_AHS:
        !          1607:                        rx = iscsi_rx_discard;
        !          1608:                        iscsi->rx_len = 4 * ISCSI_AHS_LEN ( common->lengths );
        !          1609:                        next_state = ISCSI_RX_DATA;
        !          1610:                        break;
        !          1611:                case ISCSI_RX_DATA:
        !          1612:                        rx = iscsi_rx_data;
        !          1613:                        iscsi->rx_len = ISCSI_DATA_LEN ( common->lengths );
        !          1614:                        next_state = ISCSI_RX_DATA_PADDING;
        !          1615:                        break;
        !          1616:                case ISCSI_RX_DATA_PADDING:
        !          1617:                        rx = iscsi_rx_discard;
        !          1618:                        iscsi->rx_len = ISCSI_DATA_PAD_LEN ( common->lengths );
        !          1619:                        next_state = ISCSI_RX_BHS;
        !          1620:                        break;
        !          1621:                default:
        !          1622:                        assert ( 0 );
        !          1623:                        rc = -EINVAL;
        !          1624:                        goto done;
        !          1625:                }
        !          1626: 
        !          1627:                frag_len = iscsi->rx_len - iscsi->rx_offset;
        !          1628:                if ( frag_len > iob_len ( iobuf ) )
        !          1629:                        frag_len = iob_len ( iobuf );
        !          1630:                remaining = iscsi->rx_len - iscsi->rx_offset - frag_len;
        !          1631:                if ( ( rc = rx ( iscsi, iobuf->data, frag_len,
        !          1632:                                 remaining ) ) != 0 ) {
        !          1633:                        DBGC ( iscsi, "iSCSI %p could not process received "
        !          1634:                               "data: %s\n", iscsi, strerror ( rc ) );
        !          1635:                        goto done;
        !          1636:                }
        !          1637: 
        !          1638:                iscsi->rx_offset += frag_len;
        !          1639:                iob_pull ( iobuf, frag_len );
        !          1640: 
        !          1641:                /* If all the data for this state has not yet been
        !          1642:                 * received, stay in this state for now.
        !          1643:                 */
        !          1644:                if ( iscsi->rx_offset != iscsi->rx_len ) {
        !          1645:                        rc = 0;
        !          1646:                        goto done;
        !          1647:                }
        !          1648: 
        !          1649:                iscsi->rx_state = next_state;
        !          1650:                iscsi->rx_offset = 0;
        !          1651:        }
        !          1652: 
        !          1653:  done:
        !          1654:        /* Free I/O buffer */
        !          1655:        free_iob ( iobuf );
        !          1656: 
        !          1657:        /* Destroy session on error */
        !          1658:        if ( rc != 0 )
        !          1659:                iscsi_close ( iscsi, rc );
        !          1660: 
        !          1661:        return rc;
        !          1662: }
        !          1663: 
        !          1664: /**
        !          1665:  * Handle redirection event
        !          1666:  *
        !          1667:  * @v iscsi            iSCSI session
        !          1668:  * @v type             Location type
        !          1669:  * @v args             Remaining arguments depend upon location type
        !          1670:  * @ret rc             Return status code
        !          1671:  */
        !          1672: static int iscsi_vredirect ( struct iscsi_session *iscsi, int type,
        !          1673:                             va_list args ) {
        !          1674:        va_list tmp;
        !          1675:        struct sockaddr *peer;
        !          1676: 
        !          1677:        /* Intercept redirects to a LOCATION_SOCKET and record the IP
        !          1678:         * address for the iBFT.  This is a bit of a hack, but avoids
        !          1679:         * inventing an ioctl()-style call to retrieve the socket
        !          1680:         * address from a data-xfer interface.
        !          1681:         */
        !          1682:        if ( type == LOCATION_SOCKET ) {
        !          1683:                va_copy ( tmp, args );
        !          1684:                ( void ) va_arg ( tmp, int ); /* Discard "semantics" */
        !          1685:                peer = va_arg ( tmp, struct sockaddr * );
        !          1686:                memcpy ( &iscsi->target_sockaddr, peer,
        !          1687:                         sizeof ( iscsi->target_sockaddr ) );
        !          1688:                va_end ( tmp );
        !          1689:        }
        !          1690: 
        !          1691:        return xfer_vreopen ( &iscsi->socket, type, args );
        !          1692: }
        !          1693: 
        !          1694: /** iSCSI socket interface operations */
        !          1695: static struct interface_operation iscsi_socket_operations[] = {
        !          1696:        INTF_OP ( xfer_deliver, struct iscsi_session *, iscsi_socket_deliver ),
        !          1697:        INTF_OP ( xfer_vredirect, struct iscsi_session *, iscsi_vredirect ),
        !          1698:        INTF_OP ( intf_close, struct iscsi_session *, iscsi_close ),
        !          1699: };
        !          1700: 
        !          1701: /** iSCSI socket interface descriptor */
        !          1702: static struct interface_descriptor iscsi_socket_desc =
        !          1703:        INTF_DESC ( struct iscsi_session, socket, iscsi_socket_operations );
        !          1704: 
        !          1705: /****************************************************************************
        !          1706:  *
        !          1707:  * iSCSI command issuing
        !          1708:  *
        !          1709:  */
        !          1710: 
        !          1711: /**
        !          1712:  * Check iSCSI flow-control window
        !          1713:  *
        !          1714:  * @v iscsi            iSCSI session
        !          1715:  * @ret len            Length of window
        !          1716:  */
        !          1717: static size_t iscsi_scsi_window ( struct iscsi_session *iscsi ) {
        !          1718: 
        !          1719:        if ( ( ( iscsi->status & ISCSI_STATUS_PHASE_MASK ) ==
        !          1720:               ISCSI_STATUS_FULL_FEATURE_PHASE ) &&
        !          1721:             ( iscsi->command == NULL ) ) {
        !          1722:                /* We cannot handle concurrent commands */
        !          1723:                return 1;
        !          1724:        } else {
        !          1725:                return 0;
        !          1726:        }
        !          1727: }
        !          1728: 
        !          1729: /**
        !          1730:  * Issue iSCSI SCSI command
        !          1731:  *
        !          1732:  * @v iscsi            iSCSI session
        !          1733:  * @v parent           Parent interface
        !          1734:  * @v command          SCSI command
        !          1735:  * @ret tag            Command tag, or negative error
        !          1736:  */
        !          1737: static int iscsi_scsi_command ( struct iscsi_session *iscsi,
        !          1738:                                struct interface *parent,
        !          1739:                                struct scsi_cmd *command ) {
        !          1740: 
        !          1741:        /* This iSCSI implementation cannot handle multiple concurrent
        !          1742:         * commands or commands arriving before login is complete.
        !          1743:         */
        !          1744:        if ( iscsi_scsi_window ( iscsi ) == 0 ) {
        !          1745:                DBGC ( iscsi, "iSCSI %p cannot handle concurrent commands\n",
        !          1746:                       iscsi );
        !          1747:                return -EOPNOTSUPP;
        !          1748:        }
        !          1749: 
        !          1750:        /* Store command */
        !          1751:        iscsi->command = malloc ( sizeof ( *command ) );
        !          1752:        if ( ! iscsi->command )
        !          1753:                return -ENOMEM;
        !          1754:        memcpy ( iscsi->command, command, sizeof ( *command ) );
        !          1755: 
        !          1756:        /* Assign new ITT */
        !          1757:        iscsi_new_itt ( iscsi );
        !          1758: 
        !          1759:        /* Start sending command */
        !          1760:        iscsi_start_command ( iscsi );
        !          1761: 
        !          1762:        /* Attach to parent interface and return */
        !          1763:        intf_plug_plug ( &iscsi->data, parent );
        !          1764:        return iscsi->itt;
        !          1765: }
        !          1766: 
        !          1767: /** iSCSI SCSI command-issuing interface operations */
        !          1768: static struct interface_operation iscsi_control_op[] = {
        !          1769:        INTF_OP ( scsi_command, struct iscsi_session *, iscsi_scsi_command ),
        !          1770:        INTF_OP ( xfer_window, struct iscsi_session *, iscsi_scsi_window ),
        !          1771:        INTF_OP ( intf_close, struct iscsi_session *, iscsi_close ),
        !          1772:        INTF_OP ( acpi_describe, struct iscsi_session *, ibft_describe ),
        !          1773: };
        !          1774: 
        !          1775: /** iSCSI SCSI command-issuing interface descriptor */
        !          1776: static struct interface_descriptor iscsi_control_desc =
        !          1777:        INTF_DESC ( struct iscsi_session, control, iscsi_control_op );
        !          1778: 
        !          1779: /**
        !          1780:  * Close iSCSI command
        !          1781:  *
        !          1782:  * @v iscsi            iSCSI session
        !          1783:  * @v rc               Reason for close
        !          1784:  */
        !          1785: static void iscsi_command_close ( struct iscsi_session *iscsi, int rc ) {
        !          1786: 
        !          1787:        /* Restart interface */
        !          1788:        intf_restart ( &iscsi->data, rc );
        !          1789: 
        !          1790:        /* Treat unsolicited command closures mid-command as fatal,
        !          1791:         * because we have no code to handle partially-completed PDUs.
        !          1792:         */
        !          1793:        if ( iscsi->command != NULL )
        !          1794:                iscsi_close ( iscsi, ( ( rc == 0 ) ? -ECANCELED : rc ) );
        !          1795: }
        !          1796: 
        !          1797: /** iSCSI SCSI command interface operations */
        !          1798: static struct interface_operation iscsi_data_op[] = {
        !          1799:        INTF_OP ( intf_close, struct iscsi_session *, iscsi_command_close ),
        !          1800: };
        !          1801: 
        !          1802: /** iSCSI SCSI command interface descriptor */
        !          1803: static struct interface_descriptor iscsi_data_desc =
        !          1804:        INTF_DESC ( struct iscsi_session, data, iscsi_data_op );
        !          1805: 
        !          1806: /****************************************************************************
        !          1807:  *
        !          1808:  * Instantiator
        !          1809:  *
        !          1810:  */
        !          1811: 
        !          1812: /** iSCSI root path components (as per RFC4173) */
        !          1813: enum iscsi_root_path_component {
        !          1814:        RP_SERVERNAME = 0,
        !          1815:        RP_PROTOCOL,
        !          1816:        RP_PORT,
        !          1817:        RP_LUN,
        !          1818:        RP_TARGETNAME,
        !          1819:        NUM_RP_COMPONENTS
        !          1820: };
        !          1821: 
        !          1822: /** iSCSI initiator IQN setting */
        !          1823: struct setting initiator_iqn_setting __setting ( SETTING_SANBOOT_EXTRA ) = {
        !          1824:        .name = "initiator-iqn",
        !          1825:        .description = "iSCSI initiator name",
        !          1826:        .tag = DHCP_ISCSI_INITIATOR_IQN,
        !          1827:        .type = &setting_type_string,
        !          1828: };
        !          1829: 
        !          1830: /** iSCSI reverse username setting */
        !          1831: struct setting reverse_username_setting __setting ( SETTING_AUTH_EXTRA ) = {
        !          1832:        .name = "reverse-username",
        !          1833:        .description = "Reverse user name",
        !          1834:        .tag = DHCP_EB_REVERSE_USERNAME,
        !          1835:        .type = &setting_type_string,
        !          1836: };
        !          1837: 
        !          1838: /** iSCSI reverse password setting */
        !          1839: struct setting reverse_password_setting __setting ( SETTING_AUTH_EXTRA ) = {
        !          1840:        .name = "reverse-password",
        !          1841:        .description = "Reverse password",
        !          1842:        .tag = DHCP_EB_REVERSE_PASSWORD,
        !          1843:        .type = &setting_type_string,
        !          1844: };
        !          1845: 
        !          1846: /**
        !          1847:  * Parse iSCSI root path
        !          1848:  *
        !          1849:  * @v iscsi            iSCSI session
        !          1850:  * @v root_path                iSCSI root path (as per RFC4173)
        !          1851:  * @ret rc             Return status code
        !          1852:  */
        !          1853: static int iscsi_parse_root_path ( struct iscsi_session *iscsi,
        !          1854:                                   const char *root_path ) {
        !          1855:        char rp_copy[ strlen ( root_path ) + 1 ];
        !          1856:        char *rp_comp[NUM_RP_COMPONENTS];
        !          1857:        char *rp = rp_copy;
        !          1858:        int i = 0;
        !          1859:        int rc;
        !          1860: 
        !          1861:        /* Split root path into component parts */
        !          1862:        strcpy ( rp_copy, root_path );
        !          1863:        while ( 1 ) {
        !          1864:                rp_comp[i++] = rp;
        !          1865:                if ( i == NUM_RP_COMPONENTS )
        !          1866:                        break;
        !          1867:                for ( ; *rp != ':' ; rp++ ) {
        !          1868:                        if ( ! *rp ) {
        !          1869:                                DBGC ( iscsi, "iSCSI %p root path \"%s\" "
        !          1870:                                       "too short\n", iscsi, root_path );
        !          1871:                                return -EINVAL_ROOT_PATH_TOO_SHORT;
        !          1872:                        }
        !          1873:                }
        !          1874:                *(rp++) = '\0';
        !          1875:        }
        !          1876: 
        !          1877:        /* Use root path components to configure iSCSI session */
        !          1878:        iscsi->target_address = strdup ( rp_comp[RP_SERVERNAME] );
        !          1879:        if ( ! iscsi->target_address )
        !          1880:                return -ENOMEM;
        !          1881:        iscsi->target_port = strtoul ( rp_comp[RP_PORT], NULL, 10 );
        !          1882:        if ( ! iscsi->target_port )
        !          1883:                iscsi->target_port = ISCSI_PORT;
        !          1884:        if ( ( rc = scsi_parse_lun ( rp_comp[RP_LUN], &iscsi->lun ) ) != 0 ) {
        !          1885:                DBGC ( iscsi, "iSCSI %p invalid LUN \"%s\"\n",
        !          1886:                       iscsi, rp_comp[RP_LUN] );
        !          1887:                return rc;
        !          1888:        }
        !          1889:        iscsi->target_iqn = strdup ( rp_comp[RP_TARGETNAME] );
        !          1890:        if ( ! iscsi->target_iqn )
        !          1891:                return -ENOMEM;
        !          1892: 
        !          1893:        return 0;
        !          1894: }
        !          1895: 
        !          1896: /**
        !          1897:  * Fetch iSCSI settings
        !          1898:  *
        !          1899:  * @v iscsi            iSCSI session
        !          1900:  * @ret rc             Return status code
        !          1901:  */
        !          1902: static int iscsi_fetch_settings ( struct iscsi_session *iscsi ) {
        !          1903:        char *hostname;
        !          1904:        union uuid uuid;
        !          1905:        int len;
        !          1906: 
        !          1907:        /* Fetch relevant settings.  Don't worry about freeing on
        !          1908:         * error, since iscsi_free() will take care of that anyway.
        !          1909:         */
        !          1910:        if ( ( len = fetch_string_setting_copy ( NULL, &username_setting,
        !          1911:                                          &iscsi->initiator_username ) ) < 0 ) {
        !          1912:                DBGC ( iscsi, "iSCSI %p could not fetch username: %s\n",
        !          1913:                       iscsi, strerror ( len ) );
        !          1914:                return len;
        !          1915:        }
        !          1916:        if ( ( len = fetch_string_setting_copy ( NULL, &password_setting,
        !          1917:                                          &iscsi->initiator_password ) ) < 0 ) {
        !          1918:                DBGC ( iscsi, "iSCSI %p could not fetch password: %s\n",
        !          1919:                       iscsi, strerror ( len ) );
        !          1920:                return len;
        !          1921:        }
        !          1922:        if ( ( len = fetch_string_setting_copy( NULL, &reverse_username_setting,
        !          1923:                                             &iscsi->target_username ) ) < 0 ) {
        !          1924:                DBGC ( iscsi, "iSCSI %p could not fetch reverse username: %s\n",
        !          1925:                       iscsi, strerror ( len ) );
        !          1926:                return len;
        !          1927:        }
        !          1928:        if ( ( len = fetch_string_setting_copy( NULL, &reverse_password_setting,
        !          1929:                                             &iscsi->target_password ) ) < 0 ) {
        !          1930:                DBGC ( iscsi, "iSCSI %p could not fetch reverse password: %s\n",
        !          1931:                       iscsi, strerror ( len ) );
        !          1932:                return len;
        !          1933:        }
        !          1934: 
        !          1935:        /* Find a suitable initiator name */
        !          1936:        if ( ( len = fetch_string_setting_copy ( NULL, &initiator_iqn_setting,
        !          1937:                                               &iscsi->initiator_iqn ) ) < 0 ) {
        !          1938:                DBGC ( iscsi, "iSCSI %p could not fetch initiator IQN: %s\n",
        !          1939:                       iscsi, strerror ( len ) );
        !          1940:                return len;
        !          1941:        }
        !          1942:        if ( iscsi->initiator_iqn )
        !          1943:                return 0;
        !          1944:        if ( ( len = fetch_string_setting_copy ( NULL, &hostname_setting,
        !          1945:                                                &hostname ) ) < 0 ) {
        !          1946:                DBGC ( iscsi, "iSCSI %p could not fetch hostname: %s\n",
        !          1947:                       iscsi, strerror ( len ) );
        !          1948:                return len;
        !          1949:        }
        !          1950:        if ( hostname ) {
        !          1951:                len = asprintf ( &iscsi->initiator_iqn,
        !          1952:                                 ISCSI_DEFAULT_IQN_PREFIX ":%s", hostname );
        !          1953:                free ( hostname );
        !          1954:                if ( len < 0 ) {
        !          1955:                        DBGC ( iscsi, "iSCSI %p could not allocate initiator "
        !          1956:                               "IQN\n", iscsi );
        !          1957:                        return -ENOMEM;
        !          1958:                }
        !          1959:                assert ( iscsi->initiator_iqn );
        !          1960:                return 0;
        !          1961:        }
        !          1962:        if ( ( len = fetch_uuid_setting ( NULL, &uuid_setting, &uuid ) ) < 0 ) {
        !          1963:                DBGC ( iscsi, "iSCSI %p has no suitable initiator IQN\n",
        !          1964:                       iscsi );
        !          1965:                return -EINVAL_NO_INITIATOR_IQN;
        !          1966:        }
        !          1967:        if ( ( len = asprintf ( &iscsi->initiator_iqn,
        !          1968:                                ISCSI_DEFAULT_IQN_PREFIX ":%s",
        !          1969:                                uuid_ntoa ( &uuid ) ) ) < 0 ) {
        !          1970:                DBGC ( iscsi, "iSCSI %p could not allocate initiator IQN\n",
        !          1971:                       iscsi );
        !          1972:                return -ENOMEM;
        !          1973:        }
        !          1974:        assert ( iscsi->initiator_iqn );
        !          1975: 
        !          1976:        return 0;
        !          1977: }
        !          1978: 
        !          1979: 
        !          1980: /**
        !          1981:  * Check iSCSI authentication details
        !          1982:  *
        !          1983:  * @v iscsi            iSCSI session
        !          1984:  * @ret rc             Return status code
        !          1985:  */
        !          1986: static int iscsi_check_auth ( struct iscsi_session *iscsi ) {
        !          1987: 
        !          1988:        /* Check for invalid authentication combinations */
        !          1989:        if ( ( /* Initiator username without password (or vice-versa) */
        !          1990:                ( !! iscsi->initiator_username ) ^
        !          1991:                ( !! iscsi->initiator_password ) ) ||
        !          1992:             ( /* Target username without password (or vice-versa) */
        !          1993:                ( !! iscsi->target_username ) ^
        !          1994:                ( !! iscsi->target_password ) ) ||
        !          1995:             ( /* Target (reverse) without initiator (forward) */
        !          1996:                ( iscsi->target_username &&
        !          1997:                  ( ! iscsi->initiator_username ) ) ) ) {
        !          1998:                DBGC ( iscsi, "iSCSI %p invalid credentials: initiator "
        !          1999:                       "%sname,%spw, target %sname,%spw\n", iscsi,
        !          2000:                       ( iscsi->initiator_username ? "" : "no " ),
        !          2001:                       ( iscsi->initiator_password ? "" : "no " ),
        !          2002:                       ( iscsi->target_username ? "" : "no " ),
        !          2003:                       ( iscsi->target_password ? "" : "no " ) );
        !          2004:                return -EINVAL_BAD_CREDENTIAL_MIX;
        !          2005:        }
        !          2006: 
        !          2007:        return 0;
        !          2008: }
        !          2009: 
        !          2010: /**
        !          2011:  * Open iSCSI URI
        !          2012:  *
        !          2013:  * @v parent           Parent interface
        !          2014:  * @v uri              URI
        !          2015:  * @ret rc             Return status code
        !          2016:  */
        !          2017: static int iscsi_open ( struct interface *parent, struct uri *uri ) {
        !          2018:        struct iscsi_session *iscsi;
        !          2019:        int rc;
        !          2020: 
        !          2021:        /* Sanity check */
        !          2022:        if ( ! uri->opaque ) {
        !          2023:                rc = -EINVAL_NO_ROOT_PATH;
        !          2024:                goto err_sanity_uri;
        !          2025:        }
        !          2026: 
        !          2027:        /* Allocate and initialise structure */
        !          2028:        iscsi = zalloc ( sizeof ( *iscsi ) );
        !          2029:        if ( ! iscsi ) {
        !          2030:                rc = -ENOMEM;
        !          2031:                goto err_zalloc;
        !          2032:        }
        !          2033:        ref_init ( &iscsi->refcnt, iscsi_free );
        !          2034:        intf_init ( &iscsi->control, &iscsi_control_desc, &iscsi->refcnt );
        !          2035:        intf_init ( &iscsi->data, &iscsi_data_desc, &iscsi->refcnt );
        !          2036:        intf_init ( &iscsi->socket, &iscsi_socket_desc, &iscsi->refcnt );
        !          2037:        process_init_stopped ( &iscsi->process, iscsi_tx_step,
        !          2038:                               &iscsi->refcnt );
        !          2039: 
        !          2040:        /* Parse root path */
        !          2041:        if ( ( rc = iscsi_parse_root_path ( iscsi, uri->opaque ) ) != 0 )
        !          2042:                goto err_parse_root_path;
        !          2043:        /* Set fields not specified by root path */
        !          2044:        if ( ( rc = iscsi_fetch_settings ( iscsi ) ) != 0 )
        !          2045:                goto err_fetch_settings;
        !          2046:        /* Validate authentication */
        !          2047:        if ( ( rc = iscsi_check_auth ( iscsi ) ) != 0 )
        !          2048:                goto err_check_auth;
        !          2049: 
        !          2050:        /* Sanity checks */
        !          2051:        if ( ! iscsi->target_address ) {
        !          2052:                DBGC ( iscsi, "iSCSI %p does not yet support discovery\n",
        !          2053:                       iscsi );
        !          2054:                rc = -ENOTSUP_DISCOVERY;
        !          2055:                goto err_sanity_address;
        !          2056:        }
        !          2057:        if ( ! iscsi->target_iqn ) {
        !          2058:                DBGC ( iscsi, "iSCSI %p no target address supplied in %s\n",
        !          2059:                       iscsi, uri->opaque );
        !          2060:                rc = -EINVAL_NO_TARGET_IQN;
        !          2061:                goto err_sanity_iqn;
        !          2062:        }
        !          2063:        DBGC ( iscsi, "iSCSI %p initiator %s\n",iscsi, iscsi->initiator_iqn );
        !          2064:        DBGC ( iscsi, "iSCSI %p target %s %s\n",
        !          2065:               iscsi, iscsi->target_address, iscsi->target_iqn );
        !          2066: 
        !          2067:        /* Open socket */
        !          2068:        if ( ( rc = iscsi_open_connection ( iscsi ) ) != 0 )
        !          2069:                goto err_open_connection;
        !          2070: 
        !          2071:        /* Attach SCSI device to parent interface */
        !          2072:        if ( ( rc = scsi_open ( parent, &iscsi->control,
        !          2073:                                &iscsi->lun ) ) != 0 ) {
        !          2074:                DBGC ( iscsi, "iSCSI %p could not create SCSI device: %s\n",
        !          2075:                       iscsi, strerror ( rc ) );
        !          2076:                goto err_scsi_open;
        !          2077:        }
        !          2078: 
        !          2079:        /* Mortalise self, and return */
        !          2080:        ref_put ( &iscsi->refcnt );
        !          2081:        return 0;
        !          2082:        
        !          2083:  err_scsi_open:
        !          2084:  err_open_connection:
        !          2085:  err_sanity_iqn:
        !          2086:  err_sanity_address:
        !          2087:  err_check_auth:
        !          2088:  err_fetch_settings:
        !          2089:  err_parse_root_path:
        !          2090:        iscsi_close ( iscsi, rc );
        !          2091:        ref_put ( &iscsi->refcnt );
        !          2092:  err_zalloc:
        !          2093:  err_sanity_uri:
        !          2094:        return rc;
        !          2095: }
        !          2096: 
        !          2097: /** iSCSI URI opener */
        !          2098: struct uri_opener iscsi_uri_opener __uri_opener = {
        !          2099:        .scheme = "iscsi",
        !          2100:        .open = iscsi_open,
        !          2101: };

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.