您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

iscsi.c 32KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190
  1. /*
  2. * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
  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. #include <stddef.h>
  19. #include <string.h>
  20. #include <stdlib.h>
  21. #include <vsprintf.h>
  22. #include <errno.h>
  23. #include <assert.h>
  24. #include <byteswap.h>
  25. #include <gpxe/scsi.h>
  26. #include <gpxe/process.h>
  27. #include <gpxe/uaccess.h>
  28. #include <gpxe/iscsi.h>
  29. /** @file
  30. *
  31. * iSCSI protocol
  32. *
  33. */
  34. static void iscsi_start_tx ( struct iscsi_session *iscsi );
  35. static void iscsi_start_data_out ( struct iscsi_session *iscsi,
  36. unsigned int datasn );
  37. /**
  38. * Receive PDU data into buffer
  39. *
  40. * @v iscsi iSCSI session
  41. * @v data Data to receive
  42. * @v len Length of data
  43. * @ret rc Return status code
  44. *
  45. * This can be used when the RX PDU type handler wishes to buffer up
  46. * all received data and process the PDU as a single unit. The caller
  47. * is repsonsible for calling iscsi_rx_buffered_data_done() after
  48. * processing the data.
  49. */
  50. static int iscsi_rx_buffered_data ( struct iscsi_session *iscsi,
  51. const void *data, size_t len ) {
  52. /* Allocate buffer on first call */
  53. if ( ! iscsi->rx_buffer ) {
  54. iscsi->rx_buffer = malloc ( iscsi->rx_len );
  55. if ( ! iscsi->rx_buffer )
  56. return -ENOMEM;
  57. }
  58. /* Copy data to buffer */
  59. assert ( ( iscsi->rx_offset + len ) <= iscsi->rx_len );
  60. memcpy ( ( iscsi->rx_buffer + iscsi->rx_offset ), data, len );
  61. return 0;
  62. }
  63. /**
  64. * Finish receiving PDU data into buffer
  65. *
  66. * @v iscsi iSCSI session
  67. */
  68. static void iscsi_rx_buffered_data_done ( struct iscsi_session *iscsi ) {
  69. free ( iscsi->rx_buffer );
  70. iscsi->rx_buffer = NULL;
  71. }
  72. /**
  73. * Mark iSCSI operation as complete
  74. *
  75. * @v iscsi iSCSI session
  76. * @v rc Return status code
  77. *
  78. * Note that iscsi_done() will not close the connection, and must
  79. * therefore be called only when the internal state machines are in an
  80. * appropriate state, otherwise bad things may happen on the next call
  81. * to iscsi_issue(). The general rule is to call iscsi_done() only at
  82. * the end of receiving a PDU; at this point the TX and RX engines
  83. * should both be idle.
  84. */
  85. static void iscsi_done ( struct iscsi_session *iscsi, int rc ) {
  86. /* Clear current SCSI command */
  87. iscsi->command = NULL;
  88. /* Free any dynamically allocated memory */
  89. chap_finish ( &iscsi->chap );
  90. iscsi_rx_buffered_data_done ( iscsi );
  91. /* Mark asynchronous operation as complete */
  92. async_done ( &iscsi->aop, rc );
  93. }
  94. /**
  95. * Mark iSCSI operation as complete, and close TCP connection
  96. *
  97. * @v iscsi iSCSI session
  98. * @v rc Return status code
  99. */
  100. static void iscsi_close ( struct iscsi_session *iscsi, int rc ) {
  101. /* Clear session status */
  102. iscsi->status = 0;
  103. /* Close TCP connection */
  104. tcp_close ( &iscsi->tcp );
  105. /* Mark iSCSI operation as complete */
  106. iscsi_done ( iscsi, rc );
  107. }
  108. /****************************************************************************
  109. *
  110. * iSCSI SCSI command issuing
  111. *
  112. */
  113. /**
  114. * Build iSCSI SCSI command BHS
  115. *
  116. * @v iscsi iSCSI session
  117. *
  118. * We don't currently support bidirectional commands (i.e. with both
  119. * Data-In and Data-Out segments); these would require providing code
  120. * to generate an AHS, and there doesn't seem to be any need for it at
  121. * the moment.
  122. */
  123. static void iscsi_start_command ( struct iscsi_session *iscsi ) {
  124. struct iscsi_bhs_scsi_command *command = &iscsi->tx_bhs.scsi_command;
  125. assert ( ! ( iscsi->command->data_in && iscsi->command->data_out ) );
  126. /* Construct BHS and initiate transmission */
  127. iscsi_start_tx ( iscsi );
  128. command->opcode = ISCSI_OPCODE_SCSI_COMMAND;
  129. command->flags = ( ISCSI_FLAG_FINAL |
  130. ISCSI_COMMAND_ATTR_SIMPLE );
  131. if ( iscsi->command->data_in )
  132. command->flags |= ISCSI_COMMAND_FLAG_READ;
  133. if ( iscsi->command->data_out )
  134. command->flags |= ISCSI_COMMAND_FLAG_WRITE;
  135. /* lengths left as zero */
  136. command->lun = iscsi->lun;
  137. command->itt = htonl ( ++iscsi->itt );
  138. command->exp_len = htonl ( iscsi->command->data_in_len |
  139. iscsi->command->data_out_len );
  140. command->cmdsn = htonl ( iscsi->cmdsn );
  141. command->expstatsn = htonl ( iscsi->statsn + 1 );
  142. memcpy ( &command->cdb, &iscsi->command->cdb, sizeof ( command->cdb ));
  143. DBG ( "iSCSI %p start " SCSI_CDB_FORMAT " %s %#x\n",
  144. iscsi, SCSI_CDB_DATA ( command->cdb ),
  145. ( iscsi->command->data_in ? "in" : "out" ),
  146. ( iscsi->command->data_in ?
  147. iscsi->command->data_in_len : iscsi->command->data_out_len ) );
  148. }
  149. /**
  150. * Receive data segment of an iSCSI SCSI response PDU
  151. *
  152. * @v iscsi iSCSI session
  153. * @v data Received data
  154. * @v len Length of received data
  155. * @v remaining Data remaining after this data
  156. *
  157. */
  158. static void iscsi_rx_scsi_response ( struct iscsi_session *iscsi, void *data,
  159. size_t len, size_t remaining ) {
  160. struct iscsi_bhs_scsi_response *response
  161. = &iscsi->rx_bhs.scsi_response;
  162. int sense_offset;
  163. /* Capture the sense response code as it floats past, if present */
  164. sense_offset = ISCSI_SENSE_RESPONSE_CODE_OFFSET - iscsi->rx_offset;
  165. if ( ( sense_offset >= 0 ) && len ) {
  166. iscsi->command->sense_response =
  167. * ( ( char * ) data + sense_offset );
  168. }
  169. /* Wait for whole SCSI response to arrive */
  170. if ( remaining )
  171. return;
  172. /* Record SCSI status code */
  173. iscsi->command->status = response->status;
  174. /* Mark as completed, with error if applicable */
  175. if ( response->response == ISCSI_RESPONSE_COMMAND_COMPLETE ) {
  176. iscsi_done ( iscsi, 0 );
  177. } else {
  178. iscsi_done ( iscsi, -EIO );
  179. }
  180. }
  181. /**
  182. * Receive data segment of an iSCSI data-in PDU
  183. *
  184. * @v iscsi iSCSI session
  185. * @v data Received data
  186. * @v len Length of received data
  187. * @v remaining Data remaining after this data
  188. *
  189. */
  190. static void iscsi_rx_data_in ( struct iscsi_session *iscsi, void *data,
  191. size_t len, size_t remaining __unused ) {
  192. struct iscsi_bhs_data_in *data_in = &iscsi->rx_bhs.data_in;
  193. unsigned long offset;
  194. /* Copy data to data-in buffer */
  195. offset = ntohl ( data_in->offset ) + iscsi->rx_offset;
  196. assert ( iscsi->command != NULL );
  197. assert ( iscsi->command->data_in );
  198. assert ( ( offset + len ) <= iscsi->command->data_in_len );
  199. copy_to_user ( iscsi->command->data_in, offset, data, len );
  200. /* Record SCSI status, if present */
  201. if ( data_in->flags & ISCSI_DATA_FLAG_STATUS )
  202. iscsi->command->status = data_in->status;
  203. /* If this is the end, flag as complete */
  204. if ( ( offset + len ) == iscsi->command->data_in_len ) {
  205. assert ( data_in->flags & ISCSI_FLAG_FINAL );
  206. assert ( remaining == 0 );
  207. iscsi_done ( iscsi, 0 );
  208. }
  209. }
  210. /**
  211. * Receive data segment of an iSCSI R2T PDU
  212. *
  213. * @v iscsi iSCSI session
  214. * @v data Received data
  215. * @v len Length of received data
  216. * @v remaining Data remaining after this data
  217. *
  218. */
  219. static void iscsi_rx_r2t ( struct iscsi_session *iscsi, void *data __unused,
  220. size_t len __unused, size_t remaining __unused ) {
  221. struct iscsi_bhs_r2t *r2t = &iscsi->rx_bhs.r2t;
  222. /* Record transfer parameters and trigger first data-out */
  223. iscsi->ttt = ntohl ( r2t->ttt );
  224. iscsi->transfer_offset = ntohl ( r2t->offset );
  225. iscsi->transfer_len = ntohl ( r2t->len );
  226. iscsi_start_data_out ( iscsi, 0 );
  227. }
  228. /**
  229. * Build iSCSI data-out BHS
  230. *
  231. * @v iscsi iSCSI session
  232. * @v datasn Data sequence number within the transfer
  233. *
  234. */
  235. static void iscsi_start_data_out ( struct iscsi_session *iscsi,
  236. unsigned int datasn ) {
  237. struct iscsi_bhs_data_out *data_out = &iscsi->tx_bhs.data_out;
  238. unsigned long offset;
  239. unsigned long remaining;
  240. unsigned long len;
  241. /* We always send 512-byte Data-Out PDUs; this removes the
  242. * need to worry about the target's MaxRecvDataSegmentLength.
  243. */
  244. offset = datasn * 512;
  245. remaining = iscsi->transfer_len - offset;
  246. len = remaining;
  247. if ( len > 512 )
  248. len = 512;
  249. /* Construct BHS and initiate transmission */
  250. iscsi_start_tx ( iscsi );
  251. data_out->opcode = ISCSI_OPCODE_DATA_OUT;
  252. if ( len == remaining )
  253. data_out->flags = ( ISCSI_FLAG_FINAL );
  254. ISCSI_SET_LENGTHS ( data_out->lengths, 0, len );
  255. data_out->lun = iscsi->lun;
  256. data_out->itt = htonl ( iscsi->itt );
  257. data_out->ttt = htonl ( iscsi->ttt );
  258. data_out->expstatsn = htonl ( iscsi->statsn + 1 );
  259. data_out->datasn = htonl ( datasn );
  260. data_out->offset = htonl ( iscsi->transfer_offset + offset );
  261. DBG ( "iSCSI %p start data out DataSN %#x len %#lx\n",
  262. iscsi, datasn, len );
  263. }
  264. /**
  265. * Complete iSCSI data-out PDU transmission
  266. *
  267. * @v iscsi iSCSI session
  268. *
  269. */
  270. static void iscsi_data_out_done ( struct iscsi_session *iscsi ) {
  271. struct iscsi_bhs_data_out *data_out = &iscsi->tx_bhs.data_out;
  272. /* If we haven't reached the end of the sequence, start
  273. * sending the next data-out PDU.
  274. */
  275. if ( ! ( data_out->flags & ISCSI_FLAG_FINAL ) )
  276. iscsi_start_data_out ( iscsi, ntohl ( data_out->datasn ) + 1 );
  277. }
  278. /**
  279. * Send iSCSI data-out data segment
  280. *
  281. * @v iscsi iSCSI session
  282. * @v buf Temporary data buffer
  283. * @v len Length of temporary data buffer
  284. */
  285. static void iscsi_tx_data_out ( struct iscsi_session *iscsi,
  286. void *buf, size_t len ) {
  287. struct iscsi_bhs_data_out *data_out = &iscsi->tx_bhs.data_out;
  288. unsigned long offset;
  289. unsigned long remaining;
  290. offset = ( iscsi->transfer_offset + ntohl ( data_out->offset ) +
  291. iscsi->tx_offset );
  292. remaining = ( iscsi->tx_len - iscsi->tx_offset );
  293. assert ( iscsi->command != NULL );
  294. assert ( iscsi->command->data_out );
  295. assert ( ( offset + remaining ) <= iscsi->command->data_out_len );
  296. if ( remaining < len )
  297. len = remaining;
  298. copy_from_user ( buf, iscsi->command->data_out, offset, len );
  299. tcp_send ( &iscsi->tcp, buf, len );
  300. }
  301. /****************************************************************************
  302. *
  303. * iSCSI login
  304. *
  305. */
  306. /**
  307. * Version of snprintf() that accepts a signed buffer size
  308. *
  309. * @v buf Buffer into which to write the string
  310. * @v size Size of buffer
  311. * @v fmt Format string
  312. * @v args Arguments corresponding to the format string
  313. * @ret len Length of formatted string
  314. *
  315. * This is a utility function for iscsi_build_login_request_strings().
  316. */
  317. static int ssnprintf ( char *buf, ssize_t ssize, const char *fmt, ... ) {
  318. va_list args;
  319. int len;
  320. /* Treat negative buffer size as zero buffer size */
  321. if ( ssize < 0 )
  322. ssize = 0;
  323. /* Hand off to vsnprintf */
  324. va_start ( args, fmt );
  325. len = vsnprintf ( buf, ssize, fmt, args );
  326. va_end ( args );
  327. return len;
  328. }
  329. /**
  330. * Build iSCSI login request strings
  331. *
  332. * @v iscsi iSCSI session
  333. *
  334. * These are the initial set of strings sent in the first login
  335. * request PDU. We want the following settings:
  336. *
  337. * HeaderDigest=None
  338. * DataDigest=None
  339. * MaxConnections is irrelevant; we make only one connection anyway
  340. * InitialR2T=Yes [1]
  341. * ImmediateData is irrelevant; we never send immediate data
  342. * MaxRecvDataSegmentLength=8192 (default; we don't care)
  343. * MaxBurstLength=262144 (default; we don't care)
  344. * FirstBurstLength=262144 (default; we don't care)
  345. * DefaultTime2Wait=0 [2]
  346. * DefaultTime2Retain=0 [2]
  347. * MaxOutstandingR2T=1
  348. * DataPDUInOrder=Yes
  349. * DataSequenceInOrder=Yes
  350. * ErrorRecoveryLevel=0
  351. *
  352. * [1] InitialR2T has an OR resolution function, so the target may
  353. * force us to use it. We therefore simplify our logic by always
  354. * using it.
  355. *
  356. * [2] These ensure that we can safely start a new task once we have
  357. * reconnected after a failure, without having to manually tidy up
  358. * after the old one.
  359. */
  360. static int iscsi_build_login_request_strings ( struct iscsi_session *iscsi,
  361. void *data, size_t len ) {
  362. unsigned int used = 0;
  363. unsigned int i;
  364. if ( iscsi->status & ISCSI_STATUS_STRINGS_SECURITY ) {
  365. used += ssnprintf ( data + used, len - used,
  366. "InitiatorName=%s%c"
  367. "TargetName=%s%c"
  368. "SessionType=Normal%c"
  369. "AuthMethod=CHAP,None%c",
  370. iscsi->initiator, 0, iscsi->target, 0,
  371. 0, 0 );
  372. }
  373. if ( iscsi->status & ISCSI_STATUS_STRINGS_CHAP_ALGORITHM ) {
  374. used += ssnprintf ( data + used, len - used, "CHAP_A=5%c", 0 );
  375. }
  376. if ( iscsi->status & ISCSI_STATUS_STRINGS_CHAP_RESPONSE ) {
  377. used += ssnprintf ( data + used, len - used,
  378. "CHAP_N=%s%cCHAP_R=0x",
  379. iscsi->username, 0 );
  380. for ( i = 0 ; i < iscsi->chap.response_len ; i++ ) {
  381. used += ssnprintf ( data + used, len - used, "%02x",
  382. iscsi->chap.response[i] );
  383. }
  384. used += ssnprintf ( data + used, len - used, "%c", 0 );
  385. }
  386. if ( iscsi->status & ISCSI_STATUS_STRINGS_OPERATIONAL ) {
  387. used += ssnprintf ( data + used, len - used,
  388. "HeaderDigest=None%c"
  389. "DataDigest=None%c"
  390. "InitialR2T=Yes%c"
  391. "DefaultTime2Wait=0%c"
  392. "DefaultTime2Retain=0%c"
  393. "MaxOutstandingR2T=1%c"
  394. "DataPDUInOrder=Yes%c"
  395. "DataSequenceInOrder=Yes%c"
  396. "ErrorRecoveryLevel=0%c",
  397. 0, 0, 0, 0, 0, 0, 0, 0, 0 );
  398. }
  399. return used;
  400. }
  401. /**
  402. * Build iSCSI login request BHS
  403. *
  404. * @v iscsi iSCSI session
  405. */
  406. static void iscsi_start_login ( struct iscsi_session *iscsi ) {
  407. struct iscsi_bhs_login_request *request = &iscsi->tx_bhs.login_request;
  408. int len;
  409. /* Construct BHS and initiate transmission */
  410. iscsi_start_tx ( iscsi );
  411. request->opcode = ( ISCSI_OPCODE_LOGIN_REQUEST |
  412. ISCSI_FLAG_IMMEDIATE );
  413. request->flags = ( ( iscsi->status & ISCSI_STATUS_PHASE_MASK ) |
  414. ISCSI_LOGIN_FLAG_TRANSITION );
  415. /* version_max and version_min left as zero */
  416. len = iscsi_build_login_request_strings ( iscsi, NULL, 0 );
  417. ISCSI_SET_LENGTHS ( request->lengths, 0, len );
  418. request->isid_iana_en = htonl ( ISCSI_ISID_IANA |
  419. IANA_EN_FEN_SYSTEMS );
  420. /* isid_iana_qual left as zero */
  421. request->tsih = htons ( iscsi->tsih );
  422. request->itt = htonl ( iscsi->itt );
  423. /* cid left as zero */
  424. request->cmdsn = htonl ( iscsi->cmdsn );
  425. request->expstatsn = htonl ( iscsi->statsn + 1 );
  426. }
  427. /**
  428. * Complete iSCSI login request PDU transmission
  429. *
  430. * @v iscsi iSCSI session
  431. *
  432. */
  433. static void iscsi_login_request_done ( struct iscsi_session *iscsi ) {
  434. /* Clear any "strings to send" flags */
  435. iscsi->status &= ~ISCSI_STATUS_STRINGS_MASK;
  436. }
  437. /**
  438. * Transmit data segment of an iSCSI login request PDU
  439. *
  440. * @v iscsi iSCSI session
  441. * @v buf Temporary data buffer
  442. * @v len Length of temporary data buffer
  443. *
  444. * For login requests, the data segment consists of the login strings.
  445. */
  446. static void iscsi_tx_login_request ( struct iscsi_session *iscsi,
  447. void *buf, size_t len ) {
  448. len = iscsi_build_login_request_strings ( iscsi, buf, len );
  449. tcp_send ( &iscsi->tcp, buf + iscsi->tx_offset,
  450. len - iscsi->tx_offset );
  451. }
  452. /**
  453. * Handle iSCSI TargetAddress text value
  454. *
  455. * @v iscsi iSCSI session
  456. * @v value TargetAddress value
  457. */
  458. static void iscsi_handle_targetaddress_value ( struct iscsi_session *iscsi,
  459. const char *value ) {
  460. struct in_addr address;
  461. struct sockaddr_in *sin = ( struct sockaddr_in * ) &iscsi->tcp.peer;
  462. if ( inet_aton ( value, &address ) == 0 ) {
  463. DBG ( "iSCSI %p received invalid TargetAddress \"%s\"\n",
  464. iscsi, value );
  465. return;
  466. }
  467. DBG ( "iSCSI %p will redirect to %s\n", iscsi, value );
  468. sin->sin_addr = address;
  469. }
  470. /**
  471. * Handle iSCSI AuthMethod text value
  472. *
  473. * @v iscsi iSCSI session
  474. * @v value AuthMethod value
  475. */
  476. static void iscsi_handle_authmethod_value ( struct iscsi_session *iscsi,
  477. const char *value ) {
  478. /* If server requests CHAP, send the CHAP_A string */
  479. if ( strcmp ( value, "CHAP" ) == 0 ) {
  480. DBG ( "iSCSI %p initiating CHAP authentication\n", iscsi );
  481. iscsi->status |= ISCSI_STATUS_STRINGS_CHAP_ALGORITHM;
  482. }
  483. }
  484. /**
  485. * Handle iSCSI CHAP_A text value
  486. *
  487. * @v iscsi iSCSI session
  488. * @v value CHAP_A value
  489. */
  490. static void iscsi_handle_chap_a_value ( struct iscsi_session *iscsi,
  491. const char *value ) {
  492. int rc;
  493. /* We only ever offer "5" (i.e. MD5) as an algorithm, so if
  494. * the server responds with anything else it is a protocol
  495. * violation.
  496. */
  497. if ( strcmp ( value, "5" ) != 0 ) {
  498. DBG ( "iSCSI %p got invalid CHAP algorithm \"%s\"\n",
  499. iscsi, value );
  500. }
  501. /* Prepare for CHAP with MD5 */
  502. if ( ( rc = chap_init ( &iscsi->chap, &md5_algorithm ) ) != 0 ) {
  503. DBG ( "iSCSI %p could not initialise CHAP\n", iscsi );
  504. iscsi_close ( iscsi, rc );
  505. }
  506. }
  507. /**
  508. * Handle iSCSI CHAP_I text value
  509. *
  510. * @v iscsi iSCSI session
  511. * @v value CHAP_I value
  512. */
  513. static void iscsi_handle_chap_i_value ( struct iscsi_session *iscsi,
  514. const char *value ) {
  515. unsigned int identifier;
  516. char *endp;
  517. /* The CHAP identifier is an integer value */
  518. identifier = strtoul ( value, &endp, 0 );
  519. if ( *endp != '\0' ) {
  520. DBG ( "iSCSI %p saw invalid CHAP identifier \"%s\"\n",
  521. iscsi, value );
  522. }
  523. /* Identifier and secret are the first two components of the
  524. * challenge.
  525. */
  526. chap_set_identifier ( &iscsi->chap, identifier );
  527. chap_update ( &iscsi->chap, iscsi->password,
  528. strlen ( iscsi->password ) );
  529. }
  530. /**
  531. * Handle iSCSI CHAP_C text value
  532. *
  533. * @v iscsi iSCSI session
  534. * @v value CHAP_C value
  535. */
  536. static void iscsi_handle_chap_c_value ( struct iscsi_session *iscsi,
  537. const char *value ) {
  538. char buf[3];
  539. char *endp;
  540. uint8_t byte;
  541. /* Check and strip leading "0x" */
  542. if ( ( value[0] != '0' ) || ( value[1] != 'x' ) ) {
  543. DBG ( "iSCSI %p saw invalid CHAP challenge \"%s\"\n",
  544. iscsi, value );
  545. }
  546. value += 2;
  547. /* Process challenge an octet at a time */
  548. for ( ; ( value[0] && value[1] ) ; value += 2 ) {
  549. memcpy ( buf, value, 2 );
  550. buf[3] = 0;
  551. byte = strtoul ( buf, &endp, 16 );
  552. if ( *endp != '\0' ) {
  553. DBG ( "iSCSI %p saw invalid CHAP challenge byte "
  554. "\"%s\"\n", iscsi, buf );
  555. }
  556. chap_update ( &iscsi->chap, &byte, sizeof ( byte ) );
  557. }
  558. /* Build CHAP response */
  559. DBG ( "iSCSI %p sending CHAP response\n", iscsi );
  560. chap_respond ( &iscsi->chap );
  561. iscsi->status |= ISCSI_STATUS_STRINGS_CHAP_RESPONSE;
  562. }
  563. /** An iSCSI text string that we want to handle */
  564. struct iscsi_string_type {
  565. /** String key
  566. *
  567. * This is the portion up to and including the "=" sign,
  568. * e.g. "InitiatorName=", "CHAP_A=", etc.
  569. */
  570. const char *key;
  571. /** Handle iSCSI string value
  572. *
  573. * @v iscsi iSCSI session
  574. * @v value iSCSI string value
  575. */
  576. void ( * handle_value ) ( struct iscsi_session *iscsi,
  577. const char *value );
  578. };
  579. /** iSCSI text strings that we want to handle */
  580. struct iscsi_string_type iscsi_string_types[] = {
  581. { "TargetAddress=", iscsi_handle_targetaddress_value },
  582. { "AuthMethod=", iscsi_handle_authmethod_value },
  583. { "CHAP_A=", iscsi_handle_chap_a_value },
  584. { "CHAP_I=", iscsi_handle_chap_i_value },
  585. { "CHAP_C=", iscsi_handle_chap_c_value },
  586. { NULL, NULL }
  587. };
  588. /**
  589. * Handle iSCSI string
  590. *
  591. * @v iscsi iSCSI session
  592. * @v string iSCSI string (in "key=value" format)
  593. */
  594. static void iscsi_handle_string ( struct iscsi_session *iscsi,
  595. const char *string ) {
  596. struct iscsi_string_type *type;
  597. size_t key_len;
  598. for ( type = iscsi_string_types ; type->key ; type++ ) {
  599. key_len = strlen ( type->key );
  600. if ( strncmp ( string, type->key, key_len ) == 0 ) {
  601. DBG ( "iSCSI %p handling %s\n", iscsi, string );
  602. type->handle_value ( iscsi, ( string + key_len ) );
  603. return;
  604. }
  605. }
  606. DBG ( "iSCSI %p ignoring %s\n", iscsi, string );
  607. }
  608. /**
  609. * Handle iSCSI strings
  610. *
  611. * @v iscsi iSCSI session
  612. * @v string iSCSI string buffer
  613. * @v len Length of string buffer
  614. */
  615. static void iscsi_handle_strings ( struct iscsi_session *iscsi,
  616. const char *strings, size_t len ) {
  617. size_t string_len;
  618. /* Handle each string in turn, taking care not to overrun the
  619. * data buffer in case of badly-terminated data.
  620. */
  621. while ( 1 ) {
  622. string_len = ( strnlen ( strings, len ) + 1 );
  623. if ( string_len > len )
  624. break;
  625. iscsi_handle_string ( iscsi, strings );
  626. strings += string_len;
  627. len -= string_len;
  628. }
  629. }
  630. /**
  631. * Receive data segment of an iSCSI login response PDU
  632. *
  633. * @v iscsi iSCSI session
  634. * @v data Received data
  635. * @v len Length of received data
  636. * @v remaining Data remaining after this data
  637. *
  638. */
  639. static void iscsi_rx_login_response ( struct iscsi_session *iscsi, void *data,
  640. size_t len, size_t remaining ) {
  641. struct iscsi_bhs_login_response *response
  642. = &iscsi->rx_bhs.login_response;
  643. int rc;
  644. /* Buffer up the PDU data */
  645. if ( ( rc = iscsi_rx_buffered_data ( iscsi, data, len ) ) != 0 ) {
  646. DBG ( "iSCSI %p could not buffer login response\n", iscsi );
  647. iscsi_close ( iscsi, rc );
  648. return;
  649. }
  650. if ( remaining )
  651. return;
  652. /* Process string data and discard string buffer */
  653. iscsi_handle_strings ( iscsi, iscsi->rx_buffer, iscsi->rx_len );
  654. iscsi_rx_buffered_data_done ( iscsi );
  655. /* Check for login redirection */
  656. if ( response->status_class == ISCSI_STATUS_REDIRECT ) {
  657. DBG ( "iSCSI %p redirecting to new server\n", iscsi );
  658. iscsi_close ( iscsi, -EINPROGRESS );
  659. tcp_connect ( &iscsi->tcp );
  660. return;
  661. }
  662. /* Check for fatal errors */
  663. if ( response->status_class != 0 ) {
  664. printf ( "iSCSI login failure: class %02x detail %02x\n",
  665. response->status_class, response->status_detail );
  666. iscsi_close ( iscsi, -EPERM );
  667. return;
  668. }
  669. /* Handle login transitions */
  670. if ( response->flags & ISCSI_LOGIN_FLAG_TRANSITION ) {
  671. switch ( response->flags & ISCSI_LOGIN_NSG_MASK ) {
  672. case ISCSI_LOGIN_NSG_OPERATIONAL_NEGOTIATION:
  673. iscsi->status =
  674. ( ISCSI_STATUS_OPERATIONAL_NEGOTIATION_PHASE |
  675. ISCSI_STATUS_STRINGS_OPERATIONAL );
  676. break;
  677. case ISCSI_LOGIN_NSG_FULL_FEATURE_PHASE:
  678. iscsi->status = ISCSI_STATUS_FULL_FEATURE_PHASE;
  679. break;
  680. default:
  681. DBG ( "iSCSI %p got invalid response flags %02x\n",
  682. iscsi, response->flags );
  683. iscsi_close ( iscsi, -EIO );
  684. return;
  685. }
  686. }
  687. /* Send next login request PDU if we haven't reached the full
  688. * feature phase yet.
  689. */
  690. if ( ( iscsi->status & ISCSI_STATUS_PHASE_MASK ) !=
  691. ISCSI_STATUS_FULL_FEATURE_PHASE ) {
  692. iscsi_start_login ( iscsi );
  693. return;
  694. }
  695. /* Record TSIH for future reference */
  696. iscsi->tsih = ntohl ( response->tsih );
  697. /* Send the actual SCSI command */
  698. iscsi_start_command ( iscsi );
  699. }
  700. /****************************************************************************
  701. *
  702. * iSCSI to TCP interface
  703. *
  704. */
  705. static inline struct iscsi_session *
  706. tcp_to_iscsi ( struct tcp_connection *conn ) {
  707. return container_of ( conn, struct iscsi_session, tcp );
  708. }
  709. /**
  710. * Start up a new TX PDU
  711. *
  712. * @v iscsi iSCSI session
  713. *
  714. * This initiates the process of sending a new PDU. Only one PDU may
  715. * be in transit at any one time.
  716. */
  717. static void iscsi_start_tx ( struct iscsi_session *iscsi ) {
  718. assert ( iscsi->tx_state == ISCSI_TX_IDLE );
  719. /* Initialise TX BHS */
  720. memset ( &iscsi->tx_bhs, 0, sizeof ( iscsi->tx_bhs ) );
  721. /* Flag TX engine to start transmitting */
  722. iscsi->tx_state = ISCSI_TX_BHS;
  723. iscsi->tx_offset = 0;
  724. }
  725. /**
  726. * Transmit data segment of an iSCSI PDU
  727. *
  728. * @v iscsi iSCSI session
  729. * @v buf Temporary data buffer
  730. * @v len Length of temporary data buffer
  731. *
  732. * Handle transmission of part of a PDU data segment. iscsi::tx_bhs
  733. * will be valid when this is called.
  734. */
  735. static void iscsi_tx_data ( struct iscsi_session *iscsi,
  736. void *buf, size_t len ) {
  737. struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
  738. switch ( common->opcode & ISCSI_OPCODE_MASK ) {
  739. case ISCSI_OPCODE_DATA_OUT:
  740. iscsi_tx_data_out ( iscsi, buf, len );
  741. break;
  742. case ISCSI_OPCODE_LOGIN_REQUEST:
  743. iscsi_tx_login_request ( iscsi, buf, len );
  744. break;
  745. default:
  746. assert ( 0 );
  747. break;
  748. }
  749. }
  750. /**
  751. * Complete iSCSI PDU transmission
  752. *
  753. * @v iscsi iSCSI session
  754. *
  755. * Called when a PDU has been completely transmitted and the TX state
  756. * machine is about to enter the idle state. iscsi::tx_bhs will be
  757. * valid for the just-completed PDU when this is called.
  758. */
  759. static void iscsi_tx_done ( struct iscsi_session *iscsi ) {
  760. struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
  761. switch ( common->opcode & ISCSI_OPCODE_MASK ) {
  762. case ISCSI_OPCODE_DATA_OUT:
  763. iscsi_data_out_done ( iscsi );
  764. case ISCSI_OPCODE_LOGIN_REQUEST:
  765. iscsi_login_request_done ( iscsi );
  766. default:
  767. /* No action */
  768. break;
  769. }
  770. }
  771. /**
  772. * Handle TCP ACKs
  773. *
  774. * @v iscsi iSCSI session
  775. *
  776. * Updates iscsi->tx_offset and, if applicable, transitions to the
  777. * next TX state.
  778. */
  779. static void iscsi_acked ( struct tcp_connection *conn, size_t len ) {
  780. struct iscsi_session *iscsi = tcp_to_iscsi ( conn );
  781. struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
  782. enum iscsi_tx_state next_state;
  783. iscsi->tx_offset += len;
  784. while ( 1 ) {
  785. switch ( iscsi->tx_state ) {
  786. case ISCSI_TX_BHS:
  787. iscsi->tx_len = sizeof ( iscsi->tx_bhs );
  788. next_state = ISCSI_TX_AHS;
  789. break;
  790. case ISCSI_TX_AHS:
  791. iscsi->tx_len = 4 * ISCSI_AHS_LEN ( common->lengths );
  792. next_state = ISCSI_TX_DATA;
  793. break;
  794. case ISCSI_TX_DATA:
  795. iscsi->tx_len = ISCSI_DATA_LEN ( common->lengths );
  796. next_state = ISCSI_TX_DATA_PADDING;
  797. break;
  798. case ISCSI_TX_DATA_PADDING:
  799. iscsi->tx_len = ISCSI_DATA_PAD_LEN ( common->lengths );
  800. next_state = ISCSI_TX_IDLE;
  801. break;
  802. case ISCSI_TX_IDLE:
  803. return;
  804. default:
  805. assert ( 0 );
  806. return;
  807. }
  808. assert ( iscsi->tx_offset <= iscsi->tx_len );
  809. /* If the whole of the current portion has not yet
  810. * been acked, stay in this state for now.
  811. */
  812. if ( iscsi->tx_offset != iscsi->tx_len )
  813. return;
  814. /* Move to next state. Call iscsi_tx_done() when PDU
  815. * transmission is complete.
  816. */
  817. iscsi->tx_state = next_state;
  818. iscsi->tx_offset = 0;
  819. if ( next_state == ISCSI_TX_IDLE )
  820. iscsi_tx_done ( iscsi );
  821. }
  822. }
  823. /**
  824. * Transmit iSCSI PDU
  825. *
  826. * @v iscsi iSCSI session
  827. * @v buf Temporary data buffer
  828. * @v len Length of temporary data buffer
  829. *
  830. * Constructs data to be sent for the current TX state
  831. */
  832. static void iscsi_senddata ( struct tcp_connection *conn,
  833. void *buf, size_t len ) {
  834. struct iscsi_session *iscsi = tcp_to_iscsi ( conn );
  835. struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
  836. static const char pad[] = { '\0', '\0', '\0' };
  837. switch ( iscsi->tx_state ) {
  838. case ISCSI_TX_IDLE:
  839. /* Nothing to send */
  840. break;
  841. case ISCSI_TX_BHS:
  842. tcp_send ( conn, &iscsi->tx_bhs.bytes[iscsi->tx_offset],
  843. ( sizeof ( iscsi->tx_bhs ) - iscsi->tx_offset ) );
  844. break;
  845. case ISCSI_TX_AHS:
  846. /* We don't yet have an AHS transmission mechanism */
  847. assert ( 0 );
  848. break;
  849. case ISCSI_TX_DATA:
  850. iscsi_tx_data ( iscsi, buf, len );
  851. break;
  852. case ISCSI_TX_DATA_PADDING:
  853. tcp_send ( conn, pad, ( ISCSI_DATA_PAD_LEN ( common->lengths )
  854. - iscsi->tx_offset ) );
  855. break;
  856. default:
  857. assert ( 0 );
  858. break;
  859. }
  860. }
  861. /**
  862. * Receive data segment of an iSCSI PDU
  863. *
  864. * @v iscsi iSCSI session
  865. * @v data Received data
  866. * @v len Length of received data
  867. * @v remaining Data remaining after this data
  868. *
  869. * Handle processing of part of a PDU data segment. iscsi::rx_bhs
  870. * will be valid when this is called.
  871. */
  872. static void iscsi_rx_data ( struct iscsi_session *iscsi, void *data,
  873. size_t len, size_t remaining ) {
  874. struct iscsi_bhs_common_response *response
  875. = &iscsi->rx_bhs.common_response;
  876. /* Update cmdsn and statsn */
  877. iscsi->cmdsn = ntohl ( response->expcmdsn );
  878. iscsi->statsn = ntohl ( response->statsn );
  879. switch ( response->opcode & ISCSI_OPCODE_MASK ) {
  880. case ISCSI_OPCODE_LOGIN_RESPONSE:
  881. iscsi_rx_login_response ( iscsi, data, len, remaining );
  882. break;
  883. case ISCSI_OPCODE_SCSI_RESPONSE:
  884. iscsi_rx_scsi_response ( iscsi, data, len, remaining );
  885. break;
  886. case ISCSI_OPCODE_DATA_IN:
  887. iscsi_rx_data_in ( iscsi, data, len, remaining );
  888. break;
  889. case ISCSI_OPCODE_R2T:
  890. iscsi_rx_r2t ( iscsi, data, len, remaining );
  891. break;
  892. default:
  893. if ( remaining )
  894. return;
  895. printf ( "Unknown iSCSI opcode %02x\n", response->opcode );
  896. iscsi_done ( iscsi, -EOPNOTSUPP );
  897. break;
  898. }
  899. }
  900. /**
  901. * Discard portion of an iSCSI PDU.
  902. *
  903. * @v iscsi iSCSI session
  904. * @v data Received data
  905. * @v len Length of received data
  906. * @v remaining Data remaining after this data
  907. *
  908. * This discards data from a portion of a received PDU.
  909. */
  910. static void iscsi_rx_discard ( struct iscsi_session *iscsi __unused,
  911. void *data __unused, size_t len __unused,
  912. size_t remaining __unused ) {
  913. /* Do nothing */
  914. }
  915. /**
  916. * Receive basic header segment of an iSCSI PDU
  917. *
  918. * @v iscsi iSCSI session
  919. * @v data Received data
  920. * @v len Length of received data
  921. * @v remaining Data remaining after this data
  922. *
  923. * This fills in iscsi::rx_bhs with the data from the BHS portion of
  924. * the received PDU.
  925. */
  926. static void iscsi_rx_bhs ( struct iscsi_session *iscsi, void *data,
  927. size_t len, size_t remaining __unused ) {
  928. memcpy ( &iscsi->rx_bhs.bytes[iscsi->rx_offset], data, len );
  929. if ( ( iscsi->rx_offset + len ) >= sizeof ( iscsi->rx_bhs ) ) {
  930. DBG ( "iSCSI %p received PDU opcode %#x len %#lx\n",
  931. iscsi, iscsi->rx_bhs.common.opcode,
  932. ISCSI_DATA_LEN ( iscsi->rx_bhs.common.lengths ) );
  933. }
  934. }
  935. /**
  936. * Receive new data
  937. *
  938. * @v tcp TCP connection
  939. * @v data Received data
  940. * @v len Length of received data
  941. *
  942. * This handles received PDUs. The receive strategy is to fill in
  943. * iscsi::rx_bhs with the contents of the BHS portion of the PDU,
  944. * throw away any AHS portion, and then process each part of the data
  945. * portion as it arrives. The data processing routine therefore
  946. * always has a full copy of the BHS available, even for portions of
  947. * the data in different packets to the BHS.
  948. */
  949. static void iscsi_newdata ( struct tcp_connection *conn, void *data,
  950. size_t len ) {
  951. struct iscsi_session *iscsi = tcp_to_iscsi ( conn );
  952. struct iscsi_bhs_common *common = &iscsi->rx_bhs.common;
  953. void ( *process ) ( struct iscsi_session *iscsi, void *data,
  954. size_t len, size_t remaining );
  955. enum iscsi_rx_state next_state;
  956. size_t frag_len;
  957. size_t remaining;
  958. while ( 1 ) {
  959. switch ( iscsi->rx_state ) {
  960. case ISCSI_RX_BHS:
  961. process = iscsi_rx_bhs;
  962. iscsi->rx_len = sizeof ( iscsi->rx_bhs );
  963. next_state = ISCSI_RX_AHS;
  964. break;
  965. case ISCSI_RX_AHS:
  966. process = iscsi_rx_discard;
  967. iscsi->rx_len = 4 * ISCSI_AHS_LEN ( common->lengths );
  968. next_state = ISCSI_RX_DATA;
  969. break;
  970. case ISCSI_RX_DATA:
  971. process = iscsi_rx_data;
  972. iscsi->rx_len = ISCSI_DATA_LEN ( common->lengths );
  973. next_state = ISCSI_RX_DATA_PADDING;
  974. break;
  975. case ISCSI_RX_DATA_PADDING:
  976. process = iscsi_rx_discard;
  977. iscsi->rx_len = ISCSI_DATA_PAD_LEN ( common->lengths );
  978. next_state = ISCSI_RX_BHS;
  979. break;
  980. default:
  981. assert ( 0 );
  982. return;
  983. }
  984. frag_len = iscsi->rx_len - iscsi->rx_offset;
  985. if ( frag_len > len )
  986. frag_len = len;
  987. remaining = iscsi->rx_len - iscsi->rx_offset - frag_len;
  988. process ( iscsi, data, frag_len, remaining );
  989. iscsi->rx_offset += frag_len;
  990. data += frag_len;
  991. len -= frag_len;
  992. /* If all the data for this state has not yet been
  993. * received, stay in this state for now.
  994. */
  995. if ( iscsi->rx_offset != iscsi->rx_len )
  996. return;
  997. iscsi->rx_state = next_state;
  998. iscsi->rx_offset = 0;
  999. }
  1000. }
  1001. /**
  1002. * Handle TCP connection closure
  1003. *
  1004. * @v conn TCP connection
  1005. * @v status Error code, if any
  1006. *
  1007. */
  1008. static void iscsi_closed ( struct tcp_connection *conn, int status ) {
  1009. struct iscsi_session *iscsi = tcp_to_iscsi ( conn );
  1010. /* Clear session status */
  1011. iscsi->status = 0;
  1012. /* Retry connection if within the retry limit, otherwise fail */
  1013. if ( ++iscsi->retry_count <= ISCSI_MAX_RETRIES ) {
  1014. tcp_connect ( conn );
  1015. } else {
  1016. printf ( "iSCSI retry count exceeded\n" );
  1017. iscsi_done ( iscsi, status );
  1018. }
  1019. }
  1020. /**
  1021. * Handle TCP connection opening
  1022. *
  1023. * @v conn TCP connection
  1024. *
  1025. */
  1026. static void iscsi_connected ( struct tcp_connection *conn ) {
  1027. struct iscsi_session *iscsi = tcp_to_iscsi ( conn );
  1028. /* Set connected flag and reset retry count */
  1029. iscsi->status = ( ISCSI_STATUS_SECURITY_NEGOTIATION_PHASE |
  1030. ISCSI_STATUS_STRINGS_SECURITY );
  1031. iscsi->retry_count = 0;
  1032. /* Prepare to receive PDUs. */
  1033. iscsi->rx_state = ISCSI_RX_BHS;
  1034. iscsi->rx_offset = 0;
  1035. /* Assign fresh initiator task tag */
  1036. iscsi->itt++;
  1037. /* Start logging in */
  1038. iscsi_start_login ( iscsi );
  1039. }
  1040. /** iSCSI TCP operations */
  1041. static struct tcp_operations iscsi_tcp_operations = {
  1042. .closed = iscsi_closed,
  1043. .connected = iscsi_connected,
  1044. .acked = iscsi_acked,
  1045. .newdata = iscsi_newdata,
  1046. .senddata = iscsi_senddata,
  1047. };
  1048. /**
  1049. * Issue SCSI command via iSCSI session
  1050. *
  1051. * @v iscsi iSCSI session
  1052. * @v command SCSI command
  1053. * @ret aop Asynchronous operation for this SCSI command
  1054. */
  1055. struct async_operation * iscsi_issue ( struct iscsi_session *iscsi,
  1056. struct scsi_command *command ) {
  1057. assert ( iscsi->command == NULL );
  1058. iscsi->command = command;
  1059. if ( iscsi->status ) {
  1060. iscsi_start_command ( iscsi );
  1061. tcp_senddata ( &iscsi->tcp );
  1062. } else {
  1063. iscsi->tcp.tcp_op = &iscsi_tcp_operations;
  1064. tcp_connect ( &iscsi->tcp );
  1065. }
  1066. return &iscsi->aop;
  1067. }