00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 FILE_LICENCE ( GPL2_OR_LATER );
00020
00021 #include <stddef.h>
00022 #include <string.h>
00023 #include <stdlib.h>
00024 #include <stdio.h>
00025 #include <errno.h>
00026 #include <assert.h>
00027 #include <byteswap.h>
00028 #include <gpxe/vsprintf.h>
00029 #include <gpxe/socket.h>
00030 #include <gpxe/xfer.h>
00031 #include <gpxe/open.h>
00032 #include <gpxe/scsi.h>
00033 #include <gpxe/process.h>
00034 #include <gpxe/uaccess.h>
00035 #include <gpxe/tcpip.h>
00036 #include <gpxe/settings.h>
00037 #include <gpxe/features.h>
00038 #include <gpxe/iscsi.h>
00039
00040
00041
00042
00043
00044
00045
00046 FEATURE ( FEATURE_PROTOCOL, "iSCSI", DHCP_EB_FEATURE_ISCSI, 1 );
00047
00048
00049 #define EACCES_INCORRECT_TARGET_USERNAME ( EACCES | EUNIQ_01 )
00050 #define EACCES_INCORRECT_TARGET_PASSWORD ( EACCES | EUNIQ_02 )
00051 #define ENOTSUP_INITIATOR_STATUS ( ENOTSUP | EUNIQ_01 )
00052 #define ENOTSUP_OPCODE ( ENOTSUP | EUNIQ_02 )
00053 #define ENOTSUP_DISCOVERY ( ENOTSUP | EUNIQ_03 )
00054 #define EPERM_INITIATOR_AUTHENTICATION ( EPERM | EUNIQ_01 )
00055 #define EPERM_INITIATOR_AUTHORISATION ( EPERM | EUNIQ_02 )
00056 #define EPROTO_INVALID_CHAP_ALGORITHM ( EPROTO | EUNIQ_01 )
00057 #define EPROTO_INVALID_CHAP_IDENTIFIER ( EPROTO | EUNIQ_02 )
00058 #define EPROTO_INVALID_CHAP_CHALLENGE ( EPROTO | EUNIQ_03 )
00059 #define EPROTO_INVALID_CHAP_RESPONSE ( EPROTO | EUNIQ_04 )
00060
00061
00062 static char *iscsi_explicit_initiator_iqn;
00063
00064
00065 static char *iscsi_default_initiator_iqn;
00066
00067
00068 static char *iscsi_initiator_username;
00069
00070
00071 static char *iscsi_initiator_password;
00072
00073
00074 static char *iscsi_target_username;
00075
00076
00077 static char *iscsi_target_password;
00078
00079 static void iscsi_start_tx ( struct iscsi_session *iscsi );
00080 static void iscsi_start_login ( struct iscsi_session *iscsi );
00081 static void iscsi_start_data_out ( struct iscsi_session *iscsi,
00082 unsigned int datasn );
00083
00084
00085
00086
00087
00088
00089 static void iscsi_rx_buffered_data_done ( struct iscsi_session *iscsi ) {
00090 free ( iscsi->rx_buffer );
00091 iscsi->rx_buffer = NULL;
00092 }
00093
00094
00095
00096
00097
00098
00099 static void iscsi_free ( struct refcnt *refcnt ) {
00100 struct iscsi_session *iscsi =
00101 container_of ( refcnt, struct iscsi_session, refcnt );
00102
00103 free ( iscsi->target_address );
00104 free ( iscsi->target_iqn );
00105 free ( iscsi->initiator_username );
00106 free ( iscsi->initiator_password );
00107 free ( iscsi->target_username );
00108 free ( iscsi->target_password );
00109 chap_finish ( &iscsi->chap );
00110 iscsi_rx_buffered_data_done ( iscsi );
00111 free ( iscsi );
00112 }
00113
00114
00115
00116
00117
00118
00119
00120 static int iscsi_open_connection ( struct iscsi_session *iscsi ) {
00121 struct sockaddr_tcpip target;
00122 int rc;
00123
00124 assert ( iscsi->tx_state == ISCSI_TX_IDLE );
00125 assert ( iscsi->rx_state == ISCSI_RX_BHS );
00126 assert ( iscsi->rx_offset == 0 );
00127
00128
00129 memset ( &target, 0, sizeof ( target ) );
00130 target.st_port = htons ( iscsi->target_port );
00131 if ( ( rc = xfer_open_named_socket ( &iscsi->socket, SOCK_STREAM,
00132 ( struct sockaddr * ) &target,
00133 iscsi->target_address,
00134 NULL ) ) != 0 ) {
00135 DBGC ( iscsi, "iSCSI %p could not open socket: %s\n",
00136 iscsi, strerror ( rc ) );
00137 return rc;
00138 }
00139
00140
00141 iscsi->status = ( ISCSI_STATUS_SECURITY_NEGOTIATION_PHASE |
00142 ISCSI_STATUS_STRINGS_SECURITY );
00143 if ( iscsi->target_username )
00144 iscsi->status |= ISCSI_STATUS_AUTH_REVERSE_REQUIRED;
00145
00146
00147 iscsi->itt++;
00148
00149
00150 iscsi_start_login ( iscsi );
00151
00152 return 0;
00153 }
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164 static void iscsi_close_connection ( struct iscsi_session *iscsi, int rc ) {
00165
00166
00167 xfer_close ( &iscsi->socket, rc );
00168
00169
00170 iscsi->status = 0;
00171
00172
00173 iscsi->tx_state = ISCSI_TX_IDLE;
00174 iscsi->rx_state = ISCSI_RX_BHS;
00175 iscsi->rx_offset = 0;
00176
00177
00178 chap_finish ( &iscsi->chap );
00179 iscsi_rx_buffered_data_done ( iscsi );
00180 }
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195 static void iscsi_scsi_done ( struct iscsi_session *iscsi, int rc ) {
00196
00197 assert ( iscsi->tx_state == ISCSI_TX_IDLE );
00198 assert ( iscsi->command != NULL );
00199
00200 iscsi->command->rc = rc;
00201 iscsi->command = NULL;
00202 }
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220 static void iscsi_start_command ( struct iscsi_session *iscsi ) {
00221 struct iscsi_bhs_scsi_command *command = &iscsi->tx_bhs.scsi_command;
00222
00223 assert ( ! ( iscsi->command->data_in && iscsi->command->data_out ) );
00224
00225
00226 iscsi_start_tx ( iscsi );
00227 command->opcode = ISCSI_OPCODE_SCSI_COMMAND;
00228 command->flags = ( ISCSI_FLAG_FINAL |
00229 ISCSI_COMMAND_ATTR_SIMPLE );
00230 if ( iscsi->command->data_in )
00231 command->flags |= ISCSI_COMMAND_FLAG_READ;
00232 if ( iscsi->command->data_out )
00233 command->flags |= ISCSI_COMMAND_FLAG_WRITE;
00234
00235 command->lun = iscsi->lun;
00236 command->itt = htonl ( ++iscsi->itt );
00237 command->exp_len = htonl ( iscsi->command->data_in_len |
00238 iscsi->command->data_out_len );
00239 command->cmdsn = htonl ( iscsi->cmdsn );
00240 command->expstatsn = htonl ( iscsi->statsn + 1 );
00241 memcpy ( &command->cdb, &iscsi->command->cdb, sizeof ( command->cdb ));
00242 DBGC2 ( iscsi, "iSCSI %p start " SCSI_CDB_FORMAT " %s %#zx\n",
00243 iscsi, SCSI_CDB_DATA ( command->cdb ),
00244 ( iscsi->command->data_in ? "in" : "out" ),
00245 ( iscsi->command->data_in ?
00246 iscsi->command->data_in_len :
00247 iscsi->command->data_out_len ) );
00248 }
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259 static int iscsi_rx_scsi_response ( struct iscsi_session *iscsi,
00260 const void *data, size_t len,
00261 size_t remaining ) {
00262 struct iscsi_bhs_scsi_response *response
00263 = &iscsi->rx_bhs.scsi_response;
00264 int sense_offset;
00265
00266
00267 sense_offset = ISCSI_SENSE_RESPONSE_CODE_OFFSET - iscsi->rx_offset;
00268 if ( ( sense_offset >= 0 ) && len ) {
00269 iscsi->command->sense_response =
00270 * ( ( char * ) data + sense_offset );
00271 }
00272
00273
00274 if ( remaining )
00275 return 0;
00276
00277
00278 iscsi->command->status = response->status;
00279
00280
00281 if ( response->response != ISCSI_RESPONSE_COMMAND_COMPLETE )
00282 return -EIO;
00283
00284
00285 iscsi_scsi_done ( iscsi, 0 );
00286 return 0;
00287 }
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298 static int iscsi_rx_data_in ( struct iscsi_session *iscsi,
00299 const void *data, size_t len,
00300 size_t remaining ) {
00301 struct iscsi_bhs_data_in *data_in = &iscsi->rx_bhs.data_in;
00302 unsigned long offset;
00303
00304
00305 offset = ntohl ( data_in->offset ) + iscsi->rx_offset;
00306 assert ( iscsi->command != NULL );
00307 assert ( iscsi->command->data_in );
00308 assert ( ( offset + len ) <= iscsi->command->data_in_len );
00309 copy_to_user ( iscsi->command->data_in, offset, data, len );
00310
00311
00312 if ( remaining )
00313 return 0;
00314
00315
00316 if ( data_in->flags & ISCSI_DATA_FLAG_STATUS ) {
00317 assert ( ( offset + len ) == iscsi->command->data_in_len );
00318 assert ( data_in->flags & ISCSI_FLAG_FINAL );
00319 iscsi->command->status = data_in->status;
00320
00321 iscsi_scsi_done ( iscsi, 0 );
00322 }
00323
00324 return 0;
00325 }
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336 static int iscsi_rx_r2t ( struct iscsi_session *iscsi,
00337 const void *data __unused, size_t len __unused,
00338 size_t remaining __unused ) {
00339 struct iscsi_bhs_r2t *r2t = &iscsi->rx_bhs.r2t;
00340
00341
00342 iscsi->ttt = ntohl ( r2t->ttt );
00343 iscsi->transfer_offset = ntohl ( r2t->offset );
00344 iscsi->transfer_len = ntohl ( r2t->len );
00345 iscsi_start_data_out ( iscsi, 0 );
00346
00347 return 0;
00348 }
00349
00350
00351
00352
00353
00354
00355
00356
00357 static void iscsi_start_data_out ( struct iscsi_session *iscsi,
00358 unsigned int datasn ) {
00359 struct iscsi_bhs_data_out *data_out = &iscsi->tx_bhs.data_out;
00360 unsigned long offset;
00361 unsigned long remaining;
00362 unsigned long len;
00363
00364
00365
00366
00367 offset = datasn * 512;
00368 remaining = iscsi->transfer_len - offset;
00369 len = remaining;
00370 if ( len > 512 )
00371 len = 512;
00372
00373
00374 iscsi_start_tx ( iscsi );
00375 data_out->opcode = ISCSI_OPCODE_DATA_OUT;
00376 if ( len == remaining )
00377 data_out->flags = ( ISCSI_FLAG_FINAL );
00378 ISCSI_SET_LENGTHS ( data_out->lengths, 0, len );
00379 data_out->lun = iscsi->lun;
00380 data_out->itt = htonl ( iscsi->itt );
00381 data_out->ttt = htonl ( iscsi->ttt );
00382 data_out->expstatsn = htonl ( iscsi->statsn + 1 );
00383 data_out->datasn = htonl ( datasn );
00384 data_out->offset = htonl ( iscsi->transfer_offset + offset );
00385 DBGC ( iscsi, "iSCSI %p start data out DataSN %#x len %#lx\n",
00386 iscsi, datasn, len );
00387 }
00388
00389
00390
00391
00392
00393
00394
00395 static void iscsi_data_out_done ( struct iscsi_session *iscsi ) {
00396 struct iscsi_bhs_data_out *data_out = &iscsi->tx_bhs.data_out;
00397
00398
00399
00400
00401 if ( ! ( data_out->flags & ISCSI_FLAG_FINAL ) )
00402 iscsi_start_data_out ( iscsi, ntohl ( data_out->datasn ) + 1 );
00403 }
00404
00405
00406
00407
00408
00409
00410
00411 static int iscsi_tx_data_out ( struct iscsi_session *iscsi ) {
00412 struct iscsi_bhs_data_out *data_out = &iscsi->tx_bhs.data_out;
00413 struct io_buffer *iobuf;
00414 unsigned long offset;
00415 size_t len;
00416
00417 offset = ntohl ( data_out->offset );
00418 len = ISCSI_DATA_LEN ( data_out->lengths );
00419
00420 assert ( iscsi->command != NULL );
00421 assert ( iscsi->command->data_out );
00422 assert ( ( offset + len ) <= iscsi->command->data_out_len );
00423
00424 iobuf = xfer_alloc_iob ( &iscsi->socket, len );
00425 if ( ! iobuf )
00426 return -ENOMEM;
00427
00428 copy_from_user ( iob_put ( iobuf, len ),
00429 iscsi->command->data_out, offset, len );
00430
00431 return xfer_deliver_iob ( &iscsi->socket, iobuf );
00432 }
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481 static int iscsi_build_login_request_strings ( struct iscsi_session *iscsi,
00482 void *data, size_t len ) {
00483 unsigned int used = 0;
00484 unsigned int i;
00485 const char *auth_method;
00486
00487 if ( iscsi->status & ISCSI_STATUS_STRINGS_SECURITY ) {
00488
00489 auth_method = "None";
00490
00491 if ( iscsi->initiator_username )
00492 auth_method = "CHAP,None";
00493
00494 if ( iscsi->target_username )
00495 auth_method = "CHAP";
00496 used += ssnprintf ( data + used, len - used,
00497 "InitiatorName=%s%c"
00498 "TargetName=%s%c"
00499 "SessionType=Normal%c"
00500 "AuthMethod=%s%c",
00501 iscsi_initiator_iqn(), 0,
00502 iscsi->target_iqn, 0, 0,
00503 auth_method, 0 );
00504 }
00505
00506 if ( iscsi->status & ISCSI_STATUS_STRINGS_CHAP_ALGORITHM ) {
00507 used += ssnprintf ( data + used, len - used, "CHAP_A=5%c", 0 );
00508 }
00509
00510 if ( ( iscsi->status & ISCSI_STATUS_STRINGS_CHAP_RESPONSE ) ) {
00511 assert ( iscsi->initiator_username != NULL );
00512 used += ssnprintf ( data + used, len - used,
00513 "CHAP_N=%s%cCHAP_R=0x",
00514 iscsi->initiator_username, 0 );
00515 for ( i = 0 ; i < iscsi->chap.response_len ; i++ ) {
00516 used += ssnprintf ( data + used, len - used, "%02x",
00517 iscsi->chap.response[i] );
00518 }
00519 used += ssnprintf ( data + used, len - used, "%c", 0 );
00520 }
00521
00522 if ( ( iscsi->status & ISCSI_STATUS_STRINGS_CHAP_CHALLENGE ) ) {
00523 used += ssnprintf ( data + used, len - used,
00524 "CHAP_I=%d%cCHAP_C=0x",
00525 iscsi->chap_challenge[0], 0 );
00526 for ( i = 1 ; i < sizeof ( iscsi->chap_challenge ) ; i++ ) {
00527 used += ssnprintf ( data + used, len - used, "%02x",
00528 iscsi->chap_challenge[i] );
00529 }
00530 used += ssnprintf ( data + used, len - used, "%c", 0 );
00531 }
00532
00533 if ( iscsi->status & ISCSI_STATUS_STRINGS_OPERATIONAL ) {
00534 used += ssnprintf ( data + used, len - used,
00535 "HeaderDigest=None%c"
00536 "DataDigest=None%c"
00537 "MaxConnections=1%c"
00538 "InitialR2T=Yes%c"
00539 "ImmediateData=No%c"
00540 "MaxRecvDataSegmentLength=8192%c"
00541 "MaxBurstLength=262144%c"
00542 "DefaultTime2Wait=0%c"
00543 "DefaultTime2Retain=0%c"
00544 "MaxOutstandingR2T=1%c"
00545 "DataPDUInOrder=Yes%c"
00546 "DataSequenceInOrder=Yes%c"
00547 "ErrorRecoveryLevel=0%c",
00548 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
00549 }
00550
00551 return used;
00552 }
00553
00554
00555
00556
00557
00558
00559 static void iscsi_start_login ( struct iscsi_session *iscsi ) {
00560 struct iscsi_bhs_login_request *request = &iscsi->tx_bhs.login_request;
00561 int len;
00562
00563
00564 iscsi_start_tx ( iscsi );
00565 request->opcode = ( ISCSI_OPCODE_LOGIN_REQUEST |
00566 ISCSI_FLAG_IMMEDIATE );
00567 request->flags = ( ( iscsi->status & ISCSI_STATUS_PHASE_MASK ) |
00568 ISCSI_LOGIN_FLAG_TRANSITION );
00569
00570 len = iscsi_build_login_request_strings ( iscsi, NULL, 0 );
00571 ISCSI_SET_LENGTHS ( request->lengths, 0, len );
00572 request->isid_iana_en = htonl ( ISCSI_ISID_IANA |
00573 IANA_EN_FEN_SYSTEMS );
00574
00575 request->tsih = htons ( iscsi->tsih );
00576 request->itt = htonl ( iscsi->itt );
00577
00578 request->cmdsn = htonl ( iscsi->cmdsn );
00579 request->expstatsn = htonl ( iscsi->statsn + 1 );
00580 }
00581
00582
00583
00584
00585
00586
00587
00588 static void iscsi_login_request_done ( struct iscsi_session *iscsi ) {
00589
00590
00591 iscsi->status &= ~ISCSI_STATUS_STRINGS_MASK;
00592
00593
00594 chap_finish ( &iscsi->chap );
00595 }
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605 static int iscsi_tx_login_request ( struct iscsi_session *iscsi ) {
00606 struct iscsi_bhs_login_request *request = &iscsi->tx_bhs.login_request;
00607 struct io_buffer *iobuf;
00608 size_t len;
00609
00610 len = ISCSI_DATA_LEN ( request->lengths );
00611 iobuf = xfer_alloc_iob ( &iscsi->socket, len );
00612 if ( ! iobuf )
00613 return -ENOMEM;
00614 iob_put ( iobuf, len );
00615 iscsi_build_login_request_strings ( iscsi, iobuf->data, len );
00616 return xfer_deliver_iob ( &iscsi->socket, iobuf );
00617 }
00618
00619
00620
00621
00622
00623
00624
00625
00626 static int iscsi_handle_targetaddress_value ( struct iscsi_session *iscsi,
00627 const char *value ) {
00628 char *separator;
00629
00630 DBGC ( iscsi, "iSCSI %p will redirect to %s\n", iscsi, value );
00631
00632
00633 free ( iscsi->target_address );
00634 iscsi->target_address = strdup ( value );
00635 if ( ! iscsi->target_address )
00636 return -ENOMEM;
00637
00638
00639 iscsi->target_port = htons ( ISCSI_PORT );
00640 separator = strchr ( iscsi->target_address, ':' );
00641 if ( separator ) {
00642 *separator = '\0';
00643 iscsi->target_port = strtoul ( ( separator + 1 ), NULL, 0 );
00644 }
00645
00646 return 0;
00647 }
00648
00649
00650
00651
00652
00653
00654
00655
00656 static int iscsi_handle_authmethod_value ( struct iscsi_session *iscsi,
00657 const char *value ) {
00658
00659
00660 if ( strcmp ( value, "CHAP" ) == 0 ) {
00661 DBGC ( iscsi, "iSCSI %p initiating CHAP authentication\n",
00662 iscsi );
00663 iscsi->status |= ( ISCSI_STATUS_STRINGS_CHAP_ALGORITHM |
00664 ISCSI_STATUS_AUTH_FORWARD_REQUIRED );
00665 }
00666
00667 return 0;
00668 }
00669
00670
00671
00672
00673
00674
00675
00676
00677 static int iscsi_handle_chap_a_value ( struct iscsi_session *iscsi,
00678 const char *value ) {
00679
00680
00681
00682
00683
00684 if ( strcmp ( value, "5" ) != 0 ) {
00685 DBGC ( iscsi, "iSCSI %p got invalid CHAP algorithm \"%s\"\n",
00686 iscsi, value );
00687 return -EPROTO_INVALID_CHAP_ALGORITHM;
00688 }
00689
00690 return 0;
00691 }
00692
00693
00694
00695
00696
00697
00698
00699
00700 static int iscsi_handle_chap_i_value ( struct iscsi_session *iscsi,
00701 const char *value ) {
00702 unsigned int identifier;
00703 char *endp;
00704 int rc;
00705
00706
00707 identifier = strtoul ( value, &endp, 0 );
00708 if ( *endp != '\0' ) {
00709 DBGC ( iscsi, "iSCSI %p saw invalid CHAP identifier \"%s\"\n",
00710 iscsi, value );
00711 return -EPROTO_INVALID_CHAP_IDENTIFIER;
00712 }
00713
00714
00715 chap_finish ( &iscsi->chap );
00716 if ( ( rc = chap_init ( &iscsi->chap, &md5_algorithm ) ) != 0 ) {
00717 DBGC ( iscsi, "iSCSI %p could not initialise CHAP: %s\n",
00718 iscsi, strerror ( rc ) );
00719 return rc;
00720 }
00721
00722
00723
00724
00725 chap_set_identifier ( &iscsi->chap, identifier );
00726 if ( iscsi->initiator_password ) {
00727 chap_update ( &iscsi->chap, iscsi->initiator_password,
00728 strlen ( iscsi->initiator_password ) );
00729 }
00730
00731 return 0;
00732 }
00733
00734
00735
00736
00737
00738
00739
00740
00741 static int iscsi_handle_chap_c_value ( struct iscsi_session *iscsi,
00742 const char *value ) {
00743 char buf[3];
00744 char *endp;
00745 uint8_t byte;
00746 unsigned int i;
00747
00748
00749 if ( ( value[0] != '0' ) || ( value[1] != 'x' ) ) {
00750 DBGC ( iscsi, "iSCSI %p saw invalid CHAP challenge \"%s\"\n",
00751 iscsi, value );
00752 return -EPROTO_INVALID_CHAP_CHALLENGE;
00753 }
00754 value += 2;
00755
00756
00757 for ( ; ( value[0] && value[1] ) ; value += 2 ) {
00758 memcpy ( buf, value, 2 );
00759 buf[2] = 0;
00760 byte = strtoul ( buf, &endp, 16 );
00761 if ( *endp != '\0' ) {
00762 DBGC ( iscsi, "iSCSI %p saw invalid CHAP challenge "
00763 "byte \"%s\"\n", iscsi, buf );
00764 return -EPROTO_INVALID_CHAP_CHALLENGE;
00765 }
00766 chap_update ( &iscsi->chap, &byte, sizeof ( byte ) );
00767 }
00768
00769
00770 DBGC ( iscsi, "iSCSI %p sending CHAP response\n", iscsi );
00771 chap_respond ( &iscsi->chap );
00772 iscsi->status |= ISCSI_STATUS_STRINGS_CHAP_RESPONSE;
00773
00774
00775 if ( iscsi->target_username ) {
00776 iscsi->status |= ISCSI_STATUS_STRINGS_CHAP_CHALLENGE;
00777
00778 for ( i = 0 ; i < sizeof ( iscsi->chap_challenge ) ; i++ ) {
00779 iscsi->chap_challenge[i] = random();
00780 }
00781 }
00782
00783 return 0;
00784 }
00785
00786
00787
00788
00789
00790
00791
00792
00793 static int iscsi_handle_chap_n_value ( struct iscsi_session *iscsi,
00794 const char *value ) {
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804 if ( iscsi->target_username &&
00805 ( strcmp ( iscsi->target_username, value ) != 0 ) ) {
00806 DBGC ( iscsi, "iSCSI %p target username \"%s\" incorrect "
00807 "(wanted \"%s\")\n",
00808 iscsi, value, iscsi->target_username );
00809 return -EACCES_INCORRECT_TARGET_USERNAME;
00810 }
00811
00812 return 0;
00813 }
00814
00815
00816
00817
00818
00819
00820
00821
00822 static int iscsi_handle_chap_r_value ( struct iscsi_session *iscsi,
00823 const char *value ) {
00824 char buf[3];
00825 char *endp;
00826 uint8_t byte;
00827 unsigned int i;
00828 int rc;
00829
00830
00831 chap_finish ( &iscsi->chap );
00832 if ( ( rc = chap_init ( &iscsi->chap, &md5_algorithm ) ) != 0 ) {
00833 DBGC ( iscsi, "iSCSI %p could not initialise CHAP: %s\n",
00834 iscsi, strerror ( rc ) );
00835 return rc;
00836 }
00837 chap_set_identifier ( &iscsi->chap, iscsi->chap_challenge[0] );
00838 if ( iscsi->target_password ) {
00839 chap_update ( &iscsi->chap, iscsi->target_password,
00840 strlen ( iscsi->target_password ) );
00841 }
00842 chap_update ( &iscsi->chap, &iscsi->chap_challenge[1],
00843 ( sizeof ( iscsi->chap_challenge ) - 1 ) );
00844 chap_respond ( &iscsi->chap );
00845
00846
00847 if ( ( value[0] != '0' ) || ( value[1] != 'x' ) ) {
00848 DBGC ( iscsi, "iSCSI %p saw invalid CHAP response \"%s\"\n",
00849 iscsi, value );
00850 return -EPROTO_INVALID_CHAP_RESPONSE;
00851 }
00852 value += 2;
00853
00854
00855 if ( strlen ( value ) != ( 2 * iscsi->chap.response_len ) ) {
00856 DBGC ( iscsi, "iSCSI %p invalid CHAP response length\n",
00857 iscsi );
00858 return -EPROTO_INVALID_CHAP_RESPONSE;
00859 }
00860
00861
00862 for ( i = 0 ; ( value[0] && value[1] ) ; value += 2, i++ ) {
00863 memcpy ( buf, value, 2 );
00864 buf[2] = 0;
00865 byte = strtoul ( buf, &endp, 16 );
00866 if ( *endp != '\0' ) {
00867 DBGC ( iscsi, "iSCSI %p saw invalid CHAP response "
00868 "byte \"%s\"\n", iscsi, buf );
00869 return -EPROTO_INVALID_CHAP_RESPONSE;
00870 }
00871 if ( byte != iscsi->chap.response[i] ) {
00872 DBGC ( iscsi, "iSCSI %p saw incorrect CHAP "
00873 "response\n", iscsi );
00874 return -EACCES_INCORRECT_TARGET_PASSWORD;
00875 }
00876 }
00877 assert ( i == iscsi->chap.response_len );
00878
00879
00880 iscsi->status |= ISCSI_STATUS_AUTH_REVERSE_OK;
00881
00882 return 0;
00883 }
00884
00885
00886 struct iscsi_string_type {
00887
00888
00889
00890
00891
00892 const char *key;
00893
00894
00895
00896
00897
00898
00899 int ( * handle ) ( struct iscsi_session *iscsi, const char *value );
00900 };
00901
00902
00903 static struct iscsi_string_type iscsi_string_types[] = {
00904 { "TargetAddress=", iscsi_handle_targetaddress_value },
00905 { "AuthMethod=", iscsi_handle_authmethod_value },
00906 { "CHAP_A=", iscsi_handle_chap_a_value },
00907 { "CHAP_I=", iscsi_handle_chap_i_value },
00908 { "CHAP_C=", iscsi_handle_chap_c_value },
00909 { "CHAP_N=", iscsi_handle_chap_n_value },
00910 { "CHAP_R=", iscsi_handle_chap_r_value },
00911 { NULL, NULL }
00912 };
00913
00914
00915
00916
00917
00918
00919
00920
00921 static int iscsi_handle_string ( struct iscsi_session *iscsi,
00922 const char *string ) {
00923 struct iscsi_string_type *type;
00924 size_t key_len;
00925 int rc;
00926
00927 for ( type = iscsi_string_types ; type->key ; type++ ) {
00928 key_len = strlen ( type->key );
00929 if ( strncmp ( string, type->key, key_len ) != 0 )
00930 continue;
00931 DBGC ( iscsi, "iSCSI %p handling %s\n", iscsi, string );
00932 if ( ( rc = type->handle ( iscsi,
00933 ( string + key_len ) ) ) != 0 ) {
00934 DBGC ( iscsi, "iSCSI %p could not handle %s: %s\n",
00935 iscsi, string, strerror ( rc ) );
00936 return rc;
00937 }
00938 return 0;
00939 }
00940 DBGC ( iscsi, "iSCSI %p ignoring %s\n", iscsi, string );
00941 return 0;
00942 }
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952 static int iscsi_handle_strings ( struct iscsi_session *iscsi,
00953 const char *strings, size_t len ) {
00954 size_t string_len;
00955 int rc;
00956
00957
00958
00959
00960 while ( 1 ) {
00961 string_len = ( strnlen ( strings, len ) + 1 );
00962 if ( string_len > len )
00963 break;
00964 if ( ( rc = iscsi_handle_string ( iscsi, strings ) ) != 0 )
00965 return rc;
00966 strings += string_len;
00967 len -= string_len;
00968 }
00969 return 0;
00970 }
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985 static int iscsi_rx_buffered_data ( struct iscsi_session *iscsi,
00986 const void *data, size_t len ) {
00987
00988
00989 if ( ! iscsi->rx_buffer ) {
00990 iscsi->rx_buffer = malloc ( iscsi->rx_len );
00991 if ( ! iscsi->rx_buffer )
00992 return -ENOMEM;
00993 }
00994
00995
00996 assert ( ( iscsi->rx_offset + len ) <= iscsi->rx_len );
00997 memcpy ( ( iscsi->rx_buffer + iscsi->rx_offset ), data, len );
00998
00999 return 0;
01000 }
01001
01002
01003
01004
01005
01006
01007
01008
01009 static int iscsi_status_to_rc ( unsigned int status_class,
01010 unsigned int status_detail ) {
01011 switch ( status_class ) {
01012 case ISCSI_STATUS_INITIATOR_ERROR :
01013 switch ( status_detail ) {
01014 case ISCSI_STATUS_INITIATOR_ERROR_AUTHENTICATION :
01015 return -EPERM_INITIATOR_AUTHENTICATION;
01016 case ISCSI_STATUS_INITIATOR_ERROR_AUTHORISATION :
01017 return -EPERM_INITIATOR_AUTHORISATION;
01018 case ISCSI_STATUS_INITIATOR_ERROR_NOT_FOUND :
01019 case ISCSI_STATUS_INITIATOR_ERROR_REMOVED :
01020 return -ENODEV;
01021 default :
01022 return -ENOTSUP_INITIATOR_STATUS;
01023 }
01024 case ISCSI_STATUS_TARGET_ERROR :
01025 return -EIO;
01026 default :
01027 return -EINVAL;
01028 }
01029 }
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040 static int iscsi_rx_login_response ( struct iscsi_session *iscsi,
01041 const void *data, size_t len,
01042 size_t remaining ) {
01043 struct iscsi_bhs_login_response *response
01044 = &iscsi->rx_bhs.login_response;
01045 int rc;
01046
01047
01048 if ( ( rc = iscsi_rx_buffered_data ( iscsi, data, len ) ) != 0 ) {
01049 DBGC ( iscsi, "iSCSI %p could not buffer login response: %s\n",
01050 iscsi, strerror ( rc ) );
01051 return rc;
01052 }
01053 if ( remaining )
01054 return 0;
01055
01056
01057 if ( ( rc = iscsi_handle_strings ( iscsi, iscsi->rx_buffer,
01058 iscsi->rx_len ) ) != 0 )
01059 return rc;
01060 iscsi_rx_buffered_data_done ( iscsi );
01061
01062
01063 if ( response->status_class == ISCSI_STATUS_REDIRECT ) {
01064 DBGC ( iscsi, "iSCSI %p redirecting to new server\n", iscsi );
01065 iscsi_close_connection ( iscsi, 0 );
01066 if ( ( rc = iscsi_open_connection ( iscsi ) ) != 0 ) {
01067 DBGC ( iscsi, "iSCSI %p could not redirect: %s\n ",
01068 iscsi, strerror ( rc ) );
01069 return rc;
01070 }
01071 return 0;
01072 }
01073
01074
01075 if ( response->status_class != 0 ) {
01076 DBGC ( iscsi, "iSCSI login failure: class %02x detail %02x\n",
01077 response->status_class, response->status_detail );
01078 rc = iscsi_status_to_rc ( response->status_class,
01079 response->status_detail );
01080 iscsi->instant_rc = rc;
01081 return rc;
01082 }
01083
01084
01085 if ( response->flags & ISCSI_LOGIN_FLAG_TRANSITION ) {
01086 iscsi->status &= ~( ISCSI_STATUS_PHASE_MASK |
01087 ISCSI_STATUS_STRINGS_MASK );
01088 switch ( response->flags & ISCSI_LOGIN_NSG_MASK ) {
01089 case ISCSI_LOGIN_NSG_OPERATIONAL_NEGOTIATION:
01090 iscsi->status |=
01091 ( ISCSI_STATUS_OPERATIONAL_NEGOTIATION_PHASE |
01092 ISCSI_STATUS_STRINGS_OPERATIONAL );
01093 break;
01094 case ISCSI_LOGIN_NSG_FULL_FEATURE_PHASE:
01095 iscsi->status |= ISCSI_STATUS_FULL_FEATURE_PHASE;
01096 break;
01097 default:
01098 DBGC ( iscsi, "iSCSI %p got invalid response flags "
01099 "%02x\n", iscsi, response->flags );
01100 return -EIO;
01101 }
01102 }
01103
01104
01105
01106
01107 if ( ( iscsi->status & ISCSI_STATUS_PHASE_MASK ) !=
01108 ISCSI_STATUS_FULL_FEATURE_PHASE ) {
01109 iscsi_start_login ( iscsi );
01110 return 0;
01111 }
01112
01113
01114 if ( ( iscsi->status & ISCSI_STATUS_AUTH_REVERSE_REQUIRED ) &&
01115 ! ( iscsi->status & ISCSI_STATUS_AUTH_REVERSE_OK ) ) {
01116 DBGC ( iscsi, "iSCSI %p nefarious target tried to bypass "
01117 "authentication\n", iscsi );
01118 return -EPROTO;
01119 }
01120
01121
01122 iscsi->retry_count = 0;
01123
01124
01125 iscsi->tsih = ntohl ( response->tsih );
01126
01127
01128 iscsi_start_command ( iscsi );
01129
01130 return 0;
01131 }
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147 static void iscsi_start_tx ( struct iscsi_session *iscsi ) {
01148 assert ( iscsi->tx_state == ISCSI_TX_IDLE );
01149
01150
01151 memset ( &iscsi->tx_bhs, 0, sizeof ( iscsi->tx_bhs ) );
01152
01153
01154 iscsi->tx_state = ISCSI_TX_BHS;
01155 }
01156
01157
01158
01159
01160
01161
01162
01163 static int iscsi_tx_nothing ( struct iscsi_session *iscsi __unused ) {
01164 return 0;
01165 }
01166
01167
01168
01169
01170
01171
01172
01173 static int iscsi_tx_bhs ( struct iscsi_session *iscsi ) {
01174 return xfer_deliver_raw ( &iscsi->socket, &iscsi->tx_bhs,
01175 sizeof ( iscsi->tx_bhs ) );
01176 }
01177
01178
01179
01180
01181
01182
01183
01184
01185
01186
01187 static int iscsi_tx_data ( struct iscsi_session *iscsi ) {
01188 struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
01189
01190 switch ( common->opcode & ISCSI_OPCODE_MASK ) {
01191 case ISCSI_OPCODE_DATA_OUT:
01192 return iscsi_tx_data_out ( iscsi );
01193 case ISCSI_OPCODE_LOGIN_REQUEST:
01194 return iscsi_tx_login_request ( iscsi );
01195 default:
01196
01197 return 0;
01198 }
01199 }
01200
01201
01202
01203
01204
01205
01206
01207
01208
01209
01210 static int iscsi_tx_data_padding ( struct iscsi_session *iscsi ) {
01211 static const char pad[] = { '\0', '\0', '\0' };
01212 struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
01213 size_t pad_len;
01214
01215 pad_len = ISCSI_DATA_PAD_LEN ( common->lengths );
01216 if ( ! pad_len )
01217 return 0;
01218
01219 return xfer_deliver_raw ( &iscsi->socket, pad, pad_len );
01220 }
01221
01222
01223
01224
01225
01226
01227
01228
01229
01230
01231 static void iscsi_tx_done ( struct iscsi_session *iscsi ) {
01232 struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
01233
01234 switch ( common->opcode & ISCSI_OPCODE_MASK ) {
01235 case ISCSI_OPCODE_DATA_OUT:
01236 iscsi_data_out_done ( iscsi );
01237 case ISCSI_OPCODE_LOGIN_REQUEST:
01238 iscsi_login_request_done ( iscsi );
01239 default:
01240
01241 break;
01242 }
01243 }
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254 static void iscsi_tx_step ( struct process *process ) {
01255 struct iscsi_session *iscsi =
01256 container_of ( process, struct iscsi_session, process );
01257 struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
01258 int ( * tx ) ( struct iscsi_session *iscsi );
01259 enum iscsi_tx_state next_state;
01260 size_t tx_len;
01261 int rc;
01262
01263
01264 while ( 1 ) {
01265 switch ( iscsi->tx_state ) {
01266 case ISCSI_TX_IDLE:
01267
01268 return;
01269 case ISCSI_TX_BHS:
01270 tx = iscsi_tx_bhs;
01271 tx_len = sizeof ( iscsi->tx_bhs );
01272 next_state = ISCSI_TX_AHS;
01273 break;
01274 case ISCSI_TX_AHS:
01275 tx = iscsi_tx_nothing;
01276 tx_len = 0;
01277 next_state = ISCSI_TX_DATA;
01278 break;
01279 case ISCSI_TX_DATA:
01280 tx = iscsi_tx_data;
01281 tx_len = ISCSI_DATA_LEN ( common->lengths );
01282 next_state = ISCSI_TX_DATA_PADDING;
01283 break;
01284 case ISCSI_TX_DATA_PADDING:
01285 tx = iscsi_tx_data_padding;
01286 tx_len = ISCSI_DATA_PAD_LEN ( common->lengths );
01287 next_state = ISCSI_TX_IDLE;
01288 break;
01289 default:
01290 assert ( 0 );
01291 return;
01292 }
01293
01294
01295 if ( tx_len && ( xfer_window ( &iscsi->socket ) == 0 ) ) {
01296
01297 return;
01298 }
01299
01300
01301 if ( ( rc = tx ( iscsi ) ) != 0 ) {
01302 DBGC ( iscsi, "iSCSI %p could not transmit: %s\n",
01303 iscsi, strerror ( rc ) );
01304 return;
01305 }
01306
01307
01308 iscsi->tx_state = next_state;
01309 if ( next_state == ISCSI_TX_IDLE )
01310 iscsi_tx_done ( iscsi );
01311 }
01312 }
01313
01314
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326 static int iscsi_rx_bhs ( struct iscsi_session *iscsi, const void *data,
01327 size_t len, size_t remaining __unused ) {
01328 memcpy ( &iscsi->rx_bhs.bytes[iscsi->rx_offset], data, len );
01329 if ( ( iscsi->rx_offset + len ) >= sizeof ( iscsi->rx_bhs ) ) {
01330 DBGC2 ( iscsi, "iSCSI %p received PDU opcode %#x len %#x\n",
01331 iscsi, iscsi->rx_bhs.common.opcode,
01332 ISCSI_DATA_LEN ( iscsi->rx_bhs.common.lengths ) );
01333 }
01334 return 0;
01335 }
01336
01337
01338
01339
01340
01341
01342
01343
01344
01345
01346
01347
01348 static int iscsi_rx_discard ( struct iscsi_session *iscsi __unused,
01349 const void *data __unused, size_t len __unused,
01350 size_t remaining __unused ) {
01351
01352 return 0;
01353 }
01354
01355
01356
01357
01358
01359
01360
01361
01362
01363
01364
01365
01366
01367 static int iscsi_rx_data ( struct iscsi_session *iscsi, const void *data,
01368 size_t len, size_t remaining ) {
01369 struct iscsi_bhs_common_response *response
01370 = &iscsi->rx_bhs.common_response;
01371
01372
01373 iscsi->cmdsn = ntohl ( response->expcmdsn );
01374 iscsi->statsn = ntohl ( response->statsn );
01375
01376 switch ( response->opcode & ISCSI_OPCODE_MASK ) {
01377 case ISCSI_OPCODE_LOGIN_RESPONSE:
01378 return iscsi_rx_login_response ( iscsi, data, len, remaining );
01379 case ISCSI_OPCODE_SCSI_RESPONSE:
01380 return iscsi_rx_scsi_response ( iscsi, data, len, remaining );
01381 case ISCSI_OPCODE_DATA_IN:
01382 return iscsi_rx_data_in ( iscsi, data, len, remaining );
01383 case ISCSI_OPCODE_R2T:
01384 return iscsi_rx_r2t ( iscsi, data, len, remaining );
01385 default:
01386 if ( remaining )
01387 return 0;
01388 DBGC ( iscsi, "iSCSI %p unknown opcode %02x\n", iscsi,
01389 response->opcode );
01390 return -ENOTSUP_OPCODE;
01391 }
01392 }
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404
01405
01406
01407
01408
01409 static int iscsi_socket_deliver_raw ( struct xfer_interface *socket,
01410 const void *data, size_t len ) {
01411 struct iscsi_session *iscsi =
01412 container_of ( socket, struct iscsi_session, socket );
01413 struct iscsi_bhs_common *common = &iscsi->rx_bhs.common;
01414 int ( * rx ) ( struct iscsi_session *iscsi, const void *data,
01415 size_t len, size_t remaining );
01416 enum iscsi_rx_state next_state;
01417 size_t frag_len;
01418 size_t remaining;
01419 int rc;
01420
01421 while ( 1 ) {
01422 switch ( iscsi->rx_state ) {
01423 case ISCSI_RX_BHS:
01424 rx = iscsi_rx_bhs;
01425 iscsi->rx_len = sizeof ( iscsi->rx_bhs );
01426 next_state = ISCSI_RX_AHS;
01427 break;
01428 case ISCSI_RX_AHS:
01429 rx = iscsi_rx_discard;
01430 iscsi->rx_len = 4 * ISCSI_AHS_LEN ( common->lengths );
01431 next_state = ISCSI_RX_DATA;
01432 break;
01433 case ISCSI_RX_DATA:
01434 rx = iscsi_rx_data;
01435 iscsi->rx_len = ISCSI_DATA_LEN ( common->lengths );
01436 next_state = ISCSI_RX_DATA_PADDING;
01437 break;
01438 case ISCSI_RX_DATA_PADDING:
01439 rx = iscsi_rx_discard;
01440 iscsi->rx_len = ISCSI_DATA_PAD_LEN ( common->lengths );
01441 next_state = ISCSI_RX_BHS;
01442 break;
01443 default:
01444 assert ( 0 );
01445 return -EINVAL;
01446 }
01447
01448 frag_len = iscsi->rx_len - iscsi->rx_offset;
01449 if ( frag_len > len )
01450 frag_len = len;
01451 remaining = iscsi->rx_len - iscsi->rx_offset - frag_len;
01452 if ( ( rc = rx ( iscsi, data, frag_len, remaining ) ) != 0 ) {
01453 DBGC ( iscsi, "iSCSI %p could not process received "
01454 "data: %s\n", iscsi, strerror ( rc ) );
01455 iscsi_close_connection ( iscsi, rc );
01456 iscsi_scsi_done ( iscsi, rc );
01457 return rc;
01458 }
01459
01460 iscsi->rx_offset += frag_len;
01461 data += frag_len;
01462 len -= frag_len;
01463
01464
01465
01466
01467 if ( iscsi->rx_offset != iscsi->rx_len )
01468 return 0;
01469
01470 iscsi->rx_state = next_state;
01471 iscsi->rx_offset = 0;
01472 }
01473
01474 return 0;
01475 }
01476
01477
01478
01479
01480
01481
01482
01483
01484 static void iscsi_socket_close ( struct xfer_interface *socket, int rc ) {
01485 struct iscsi_session *iscsi =
01486 container_of ( socket, struct iscsi_session, socket );
01487
01488
01489 if ( ! rc )
01490 rc = -ECONNRESET;
01491
01492
01493 iscsi_close_connection ( iscsi, rc );
01494
01495
01496 if ( ++iscsi->retry_count <= ISCSI_MAX_RETRIES ) {
01497 DBGC ( iscsi, "iSCSI %p retrying connection (retry #%d)\n",
01498 iscsi, iscsi->retry_count );
01499 if ( ( rc = iscsi_open_connection ( iscsi ) ) != 0 ) {
01500 DBGC ( iscsi, "iSCSI %p could not reconnect: %s\n",
01501 iscsi, strerror ( rc ) );
01502 iscsi_scsi_done ( iscsi, rc );
01503 }
01504 } else {
01505 DBGC ( iscsi, "iSCSI %p retry count exceeded\n", iscsi );
01506 iscsi->instant_rc = rc;
01507 iscsi_scsi_done ( iscsi, rc );
01508 }
01509 }
01510
01511
01512
01513
01514
01515
01516
01517
01518
01519 static int iscsi_vredirect ( struct xfer_interface *socket, int type,
01520 va_list args ) {
01521 struct iscsi_session *iscsi =
01522 container_of ( socket, struct iscsi_session, socket );
01523 va_list tmp;
01524 struct sockaddr *peer;
01525
01526
01527
01528
01529
01530
01531 if ( type == LOCATION_SOCKET ) {
01532 va_copy ( tmp, args );
01533 ( void ) va_arg ( tmp, int );
01534 peer = va_arg ( tmp, struct sockaddr * );
01535 memcpy ( &iscsi->target_sockaddr, peer,
01536 sizeof ( iscsi->target_sockaddr ) );
01537 va_end ( tmp );
01538 }
01539
01540 return xfer_vreopen ( socket, type, args );
01541 }
01542
01543
01544
01545 static struct xfer_interface_operations iscsi_socket_operations = {
01546 .close = iscsi_socket_close,
01547 .vredirect = iscsi_vredirect,
01548 .window = unlimited_xfer_window,
01549 .alloc_iob = default_xfer_alloc_iob,
01550 .deliver_iob = xfer_deliver_as_raw,
01551 .deliver_raw = iscsi_socket_deliver_raw,
01552 };
01553
01554
01555
01556
01557
01558
01559
01560
01561
01562
01563
01564
01565
01566
01567
01568 static int iscsi_command ( struct scsi_device *scsi,
01569 struct scsi_command *command ) {
01570 struct iscsi_session *iscsi =
01571 container_of ( scsi->backend, struct iscsi_session, refcnt );
01572 int rc;
01573
01574
01575 if ( iscsi->instant_rc )
01576 return iscsi->instant_rc;
01577
01578
01579 iscsi->command = command;
01580
01581
01582 if ( iscsi->status ) {
01583 iscsi_start_command ( iscsi );
01584 } else {
01585 if ( ( rc = iscsi_open_connection ( iscsi ) ) != 0 ) {
01586 iscsi->command = NULL;
01587 return rc;
01588 }
01589 }
01590
01591 return 0;
01592 }
01593
01594
01595
01596
01597
01598
01599 void iscsi_detach ( struct scsi_device *scsi ) {
01600 struct iscsi_session *iscsi =
01601 container_of ( scsi->backend, struct iscsi_session, refcnt );
01602
01603 xfer_nullify ( &iscsi->socket );
01604 iscsi_close_connection ( iscsi, 0 );
01605 process_del ( &iscsi->process );
01606 scsi->command = scsi_detached_command;
01607 ref_put ( scsi->backend );
01608 scsi->backend = NULL;
01609 }
01610
01611
01612
01613
01614
01615
01616
01617
01618 enum iscsi_root_path_component {
01619 RP_LITERAL = 0,
01620 RP_SERVERNAME,
01621 RP_PROTOCOL,
01622 RP_PORT,
01623 RP_LUN,
01624 RP_TARGETNAME,
01625 NUM_RP_COMPONENTS
01626 };
01627
01628
01629
01630
01631
01632
01633
01634
01635 static int iscsi_parse_root_path ( struct iscsi_session *iscsi,
01636 const char *root_path ) {
01637 char rp_copy[ strlen ( root_path ) + 1 ];
01638 char *rp_comp[NUM_RP_COMPONENTS];
01639 char *rp = rp_copy;
01640 int i = 0;
01641 int rc;
01642
01643
01644 strcpy ( rp_copy, root_path );
01645 while ( 1 ) {
01646 rp_comp[i++] = rp;
01647 if ( i == NUM_RP_COMPONENTS )
01648 break;
01649 for ( ; *rp != ':' ; rp++ ) {
01650 if ( ! *rp ) {
01651 DBGC ( iscsi, "iSCSI %p root path \"%s\" "
01652 "too short\n", iscsi, root_path );
01653 return -EINVAL;
01654 }
01655 }
01656 *(rp++) = '\0';
01657 }
01658
01659
01660 iscsi->target_address = strdup ( rp_comp[RP_SERVERNAME] );
01661 if ( ! iscsi->target_address )
01662 return -ENOMEM;
01663 iscsi->target_port = strtoul ( rp_comp[RP_PORT], NULL, 10 );
01664 if ( ! iscsi->target_port )
01665 iscsi->target_port = ISCSI_PORT;
01666 if ( ( rc = scsi_parse_lun ( rp_comp[RP_LUN], &iscsi->lun ) ) != 0 ) {
01667 DBGC ( iscsi, "iSCSI %p invalid LUN \"%s\"\n",
01668 iscsi, rp_comp[RP_LUN] );
01669 return rc;
01670 }
01671 iscsi->target_iqn = strdup ( rp_comp[RP_TARGETNAME] );
01672 if ( ! iscsi->target_iqn )
01673 return -ENOMEM;
01674
01675 return 0;
01676 }
01677
01678
01679
01680
01681
01682
01683
01684
01685
01686
01687
01688 static int iscsi_set_auth ( struct iscsi_session *iscsi,
01689 const char *initiator_username,
01690 const char *initiator_password,
01691 const char *target_username,
01692 const char *target_password ) {
01693
01694
01695 if ( initiator_username || initiator_password ||
01696 target_username || target_password ) {
01697
01698
01699 if ( ! ( initiator_username && initiator_password ) )
01700 goto invalid_auth;
01701
01702
01703 iscsi->initiator_username = strdup ( initiator_username );
01704 if ( ! iscsi->initiator_username )
01705 return -ENOMEM;
01706 iscsi->initiator_password = strdup ( initiator_password );
01707 if ( ! iscsi->initiator_password )
01708 return -ENOMEM;
01709
01710
01711 if ( target_username || target_password ) {
01712
01713
01714 if ( ! ( target_username && target_password ) )
01715 goto invalid_auth;
01716
01717
01718 iscsi->target_username = strdup ( target_username );
01719 if ( ! iscsi->target_username )
01720 return -ENOMEM;
01721 iscsi->target_password = strdup ( target_password );
01722 if ( ! iscsi->target_password )
01723 return -ENOMEM;
01724 }
01725 }
01726
01727 return 0;
01728
01729 invalid_auth:
01730 DBGC ( iscsi, "iSCSI %p invalid credentials: initiator "
01731 "%sname,%spw, target %sname,%spw\n", iscsi,
01732 ( initiator_username ? "" : "no " ),
01733 ( initiator_password ? "" : "no " ),
01734 ( target_username ? "" : "no " ),
01735 ( target_password ? "" : "no " ) );
01736 return -EINVAL;
01737 }
01738
01739
01740
01741
01742
01743
01744
01745
01746 int iscsi_attach ( struct scsi_device *scsi, const char *root_path ) {
01747 struct iscsi_session *iscsi;
01748 int rc;
01749
01750
01751 iscsi = zalloc ( sizeof ( *iscsi ) );
01752 if ( ! iscsi )
01753 return -ENOMEM;
01754 iscsi->refcnt.free = iscsi_free;
01755 xfer_init ( &iscsi->socket, &iscsi_socket_operations, &iscsi->refcnt );
01756 process_init ( &iscsi->process, iscsi_tx_step, &iscsi->refcnt );
01757
01758
01759 if ( ( rc = iscsi_parse_root_path ( iscsi, root_path ) ) != 0 )
01760 goto err;
01761
01762 if ( ( rc = iscsi_set_auth ( iscsi,
01763 iscsi_initiator_username,
01764 iscsi_initiator_password,
01765 iscsi_target_username,
01766 iscsi_target_password ) ) != 0 )
01767 goto err;
01768
01769
01770 if ( ! iscsi->target_address ) {
01771 DBGC ( iscsi, "iSCSI %p does not yet support discovery\n",
01772 iscsi );
01773 rc = -ENOTSUP_DISCOVERY;
01774 goto err;
01775 }
01776 if ( ! iscsi->target_iqn ) {
01777 DBGC ( iscsi, "iSCSI %p no target address supplied in %s\n",
01778 iscsi, root_path );
01779 rc = -EINVAL;
01780 goto err;
01781 }
01782
01783
01784 scsi->backend = ref_get ( &iscsi->refcnt );
01785 scsi->command = iscsi_command;
01786 ref_put ( &iscsi->refcnt );
01787 return 0;
01788
01789 err:
01790 ref_put ( &iscsi->refcnt );
01791 return rc;
01792 }
01793
01794
01795
01796
01797
01798
01799
01800
01801 struct setting initiator_iqn_setting __setting = {
01802 .name = "initiator-iqn",
01803 .description = "iSCSI initiator name",
01804 .tag = DHCP_ISCSI_INITIATOR_IQN,
01805 .type = &setting_type_string,
01806 };
01807
01808
01809 struct setting reverse_username_setting __setting = {
01810 .name = "reverse-username",
01811 .description = "Reverse user name",
01812 .tag = DHCP_EB_REVERSE_USERNAME,
01813 .type = &setting_type_string,
01814 };
01815
01816
01817 struct setting reverse_password_setting __setting = {
01818 .name = "reverse-password",
01819 .description = "Reverse password",
01820 .tag = DHCP_EB_REVERSE_PASSWORD,
01821 .type = &setting_type_string,
01822 };
01823
01824
01825 struct iscsi_string_setting {
01826
01827 struct setting *setting;
01828
01829 char **string;
01830
01831 const char *prefix;
01832 };
01833
01834
01835 static struct iscsi_string_setting iscsi_string_settings[] = {
01836 {
01837 .setting = &initiator_iqn_setting,
01838 .string = &iscsi_explicit_initiator_iqn,
01839 .prefix = "",
01840 },
01841 {
01842 .setting = &username_setting,
01843 .string = &iscsi_initiator_username,
01844 .prefix = "",
01845 },
01846 {
01847 .setting = &password_setting,
01848 .string = &iscsi_initiator_password,
01849 .prefix = "",
01850 },
01851 {
01852 .setting = &reverse_username_setting,
01853 .string = &iscsi_target_username,
01854 .prefix = "",
01855 },
01856 {
01857 .setting = &reverse_password_setting,
01858 .string = &iscsi_target_password,
01859 .prefix = "",
01860 },
01861 {
01862 .setting = &hostname_setting,
01863 .string = &iscsi_default_initiator_iqn,
01864 .prefix = "iqn.2000-01.org.etherboot:",
01865 },
01866 };
01867
01868
01869
01870
01871
01872
01873
01874 static int apply_iscsi_string_setting ( struct iscsi_string_setting *setting ){
01875 size_t prefix_len;
01876 int setting_len;
01877 size_t len;
01878 int check_len;
01879 char *p;
01880
01881
01882 free ( *setting->string );
01883 *setting->string = NULL;
01884
01885
01886 prefix_len = strlen ( setting->prefix );
01887 setting_len = fetch_setting_len ( NULL, setting->setting );
01888 if ( setting_len < 0 ) {
01889
01890 return 0;
01891 }
01892 len = ( prefix_len + setting_len + 1 );
01893 p = *setting->string = malloc ( len );
01894 if ( ! p )
01895 return -ENOMEM;
01896
01897
01898 strcpy ( p, setting->prefix );
01899 check_len = fetch_string_setting ( NULL, setting->setting,
01900 ( p + prefix_len ),
01901 ( len - prefix_len ) );
01902 assert ( check_len == setting_len );
01903
01904 return 0;
01905 }
01906
01907
01908
01909
01910
01911
01912 static int apply_iscsi_settings ( void ) {
01913 struct iscsi_string_setting *setting;
01914 unsigned int i;
01915 int rc;
01916
01917 for ( i = 0 ; i < ( sizeof ( iscsi_string_settings ) /
01918 sizeof ( iscsi_string_settings[0] ) ) ; i++ ) {
01919 setting = &iscsi_string_settings[i];
01920 if ( ( rc = apply_iscsi_string_setting ( setting ) ) != 0 ) {
01921 DBG ( "iSCSI could not apply setting %s\n",
01922 setting->setting->name );
01923 return rc;
01924 }
01925 }
01926
01927 return 0;
01928 }
01929
01930
01931 struct settings_applicator iscsi_settings_applicator __settings_applicator = {
01932 .apply = apply_iscsi_settings,
01933 };
01934
01935
01936
01937
01938
01939
01940
01941
01942
01943
01944
01945
01946
01947 const char * iscsi_initiator_iqn ( void ) {
01948
01949 if ( iscsi_explicit_initiator_iqn )
01950 return iscsi_explicit_initiator_iqn;
01951 if ( iscsi_default_initiator_iqn )
01952 return iscsi_default_initiator_iqn;
01953 return "iqn.2000-09.org.etherboot:UNKNOWN";
01954 }