Emulex Logo
OneCoreā„¢ Storage SDK Release 11.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ocs_login.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011-2015, Emulex
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors
16  * may be used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  */
32 
33 /**
34  * @file
35  * Implements the iSCSI Login interface functions.
36  *
37  * This module queues requests when insufficient resources exist to send
38  * the request immediately.
39  */
40 
41 /*!
42 @defgroup login iSCSI login
43 */
44 
45 #include "ocs.h"
46 #include "ocs_iscsi.h"
47 #include "ocs_iscsi_spec.h"
48 #include "ocs_common.h"
49 #include "ocs_hal.h"
50 #include "ocs_iscsi_api.h"
51 #include "ocs_login.h"
52 #include "ocs_cxn.h"
53 #include "ocs_session.h"
54 #include "ocs_md5.h"
55 
56 #define OCS_TEXT_TIMEOUT_MS (1 * 1000) /* 1 second */
57 
59  {"SessionType", (KEY_FLAG_USE_LEADING | KEY_FLAG_SEND_INI |
61  {"InitiatorName", (KEY_FLAG_USE_LOGIN | KEY_FLAG_SEND_INI |
63  {"TargetName", (KEY_FLAG_USE_LOGIN | KEY_FLAG_SEND_BOTH |
66  {"TargetAddress", (KEY_FLAG_USE_LOGIN | KEY_FLAG_SEND_TGT |
69  {"InitiatorAlias", (KEY_FLAG_USE_LOGIN | KEY_FLAG_SEND_INI |
71  {"TargetAlias", (KEY_FLAG_USE_LOGIN | KEY_FLAG_SEND_TGT |
73  {"TargetPortalGroupTag", (KEY_FLAG_USE_LOGIN | KEY_FLAG_SEND_TGT |
75  {"AuthMethod", (KEY_FLAG_USE_LOGIN | KEY_FLAG_SEND_BOTH |
77 
78  {"HeaderDigest", (KEY_FLAG_USE_LOGIN | KEY_FLAG_SEND_BOTH |
81  {"DataDigest", (KEY_FLAG_USE_LOGIN | KEY_FLAG_SEND_BOTH |
84  {"MaxConnections", (KEY_FLAG_USE_LEADING | KEY_FLAG_SEND_BOTH |
87  {"SendTargets", (KEY_FLAG_USE_LOGIN | KEY_FLAG_SEND_INI |
90  {"InitialR2T", (KEY_FLAG_USE_LEADING | KEY_FLAG_SEND_BOTH |
92  {"ImmediateData", (KEY_FLAG_USE_LEADING | KEY_FLAG_SEND_BOTH |
94  {"MaxRecvDataSegmentLength", (KEY_FLAG_USE_LOGIN | KEY_FLAG_SEND_BOTH |
97  {"MaxBurstLength", (KEY_FLAG_USE_LEADING | KEY_FLAG_SEND_BOTH |
99  {"FirstBurstLength", (KEY_FLAG_USE_LEADING | KEY_FLAG_SEND_BOTH |
101  {"DefaultTime2Wait", (KEY_FLAG_USE_LEADING | KEY_FLAG_SEND_BOTH |
104  {"DefaultTime2Retain", (KEY_FLAG_USE_LEADING | KEY_FLAG_SEND_BOTH |
107  {"MaxOutstandingR2T", (KEY_FLAG_USE_LEADING | KEY_FLAG_SEND_BOTH |
110  {"DataPDUInOrder", (KEY_FLAG_USE_LEADING | KEY_FLAG_SEND_BOTH |
113  {"DataSequenceInOrder", (KEY_FLAG_USE_LEADING | KEY_FLAG_SEND_BOTH |
116  {"ErrorRecoveryLevel", (KEY_FLAG_USE_LEADING | KEY_FLAG_SEND_BOTH |
119  {"TaskReporting", (KEY_FLAG_USE_LEADING | KEY_FLAG_SEND_BOTH |
122 
123  {"OFMarker", (KEY_FLAG_USE_LOGIN | KEY_FLAG_SEND_BOTH |
126  {"IFMarker", (KEY_FLAG_USE_LOGIN | KEY_FLAG_SEND_BOTH |
129  {"OFMarkInt", (KEY_FLAG_USE_LOGIN | KEY_FLAG_SEND_BOTH |
132  {"IFMarkInt", (KEY_FLAG_USE_LOGIN | KEY_FLAG_SEND_BOTH |
135  {"CHAP_A", (KEY_FLAG_USE_LOGIN | KEY_FLAG_SEND_BOTH |
137  {"CHAP_I", (KEY_FLAG_USE_LOGIN | KEY_FLAG_SEND_BOTH |
139  {"CHAP_C", (KEY_FLAG_USE_LOGIN | KEY_FLAG_SEND_BOTH |
142  {"CHAP_N", (KEY_FLAG_USE_LOGIN | KEY_FLAG_SEND_BOTH |
144  {"CHAP_R", (KEY_FLAG_USE_LOGIN | KEY_FLAG_SEND_BOTH |
146 };
147 
148 /* Canned Text replies */
149 static const char chap[] = "CHAP";
150 static const char none[] = "None";
151 static const char crc32c[] = "CRC32C";
152 static const char yes[] = "Yes";
153 static const char no[] = "No";
154 static const char all[] = "All";
155 static const char rfc3720[] = "RFC3720";
156 static const char irrelevant[] = "Irrelevant";
157 
158 /* login buffer routines */
159 static int32_t ocs_iscsi_login_buffer_get(ocs_cxn_t *);
160 static void ocs_iscsi_login_buffer_free(ocs_cxn_t *);
161 
162 /* retry buffer routines */
163 static int32_t ocs_iscsi_login_retries_allocate(ocs_iscsi_t *iscsi);
164 static void ocs_iscsi_login_retries_free(ocs_iscsi_t *iscsi);
167 
168 /* common login callback */
169 int32_t ocs_iscsi_login_cb_free_lgn_mem(ocs_hal_io_t *io, ocs_cxn_t *cxn,
170  int32_t status,
171  ocs_ini_cmpl_fields_t *ini_fields,
172  void *ul_arg);
173 int32_t ocs_iscsi_login_cb_no_lgn_mem(ocs_hal_io_t *io, ocs_cxn_t *cxn,
174  int32_t status,
175  ocs_ini_cmpl_fields_t *ini_fields,
176  void *ul_arg);
177 
178 int32_t ocs_iscsi_login_tgt_nop_cb_free_lgn_mem(ocs_hal_io_t *io, ocs_cxn_t *cxn,
179  int32_t status,
180  ocs_ini_cmpl_fields_t *ini_fields,
181  void *ul_arg);
182 
183 int32_t ocs_iscsi_login_tgt_nop_cb_no_lgn_mem(ocs_hal_io_t *io, ocs_cxn_t *cxn,
184  int32_t status,
185  ocs_ini_cmpl_fields_t *ini_fields,
186  void *ul_arg);
187 
188 static void
189 ocs_iscsi_login_convert_bin_to_hexstring(uint8_t *bin, uint32_t nbytes,
190  char*str, uint32_t max_str);
191 
192 /**
193  * @ingroup login
194  * @brief Initialize the login and retry object used within the login module.
195  *
196  * @param iscsi Pointer to the iSCSI object.
197  *
198  * @return Returns 0 on success, or a non-zero value otherwise.
199  */
201 {
202  int32_t rc;
203 
204  ocs_lock_init(iscsi->os, &iscsi->lgn_queue_lock, "login_mem_lock[%d]", ocs_instance(iscsi->os));
207 
209  ocs_atomic_init(&iscsi->clusttgt.cnt, 0);
210  iscsi->clusttgt.ctgt_next = NULL;
211 
212  ocs_get_random_bytes(&iscsi->chap_ident,sizeof(iscsi->chap_ident));
213  if ((rc = ocs_iscsi_login_retries_allocate(iscsi))) {
214  ocs_log_err(iscsi->os, "ocs_iscsi_login_retries_allocate failed\n");
215  }
216 
217  return rc;
218 }
219 
220 
221 /**
222  * @ingroup login
223  * @brief Releases the login and retry object used within the login module.
224  *
225  * @param iscsi Pointer to the iSCSI object.
226  */
228 {
230  ocs_lock_free(&iscsi->lgn_queue_lock);
231 
233 }
234 
235 
236 /**
237  * @ingroup login
238  * @brief Checks to see if there are any retry or login IOs active on a
239  * connection.
240  *
241  * @param cxn Pointer to the connection object.
242  *
243  * @return Returns FALSE if nothing is active, or TRUE otherwise.
244  */
246 {
247  ocs_iscsi_t *iscsi = cxn->iscsi;
248  ocs_iscsi_lgn_retry_t *retry;
249  ocs_iscsi_lgn_retry_t *retry_next;
250  int in_use;
251  int32_t rc = FALSE;
252 
253  ocs_lock(&iscsi->lgn_queue_lock);
254  ocs_list_foreach_safe(&iscsi->login_retry_busy, retry, retry_next) {
255  if (cxn == retry->cxn) {
256  rc = TRUE;
257  break;
258  }
259  }
260  ocs_unlock(&iscsi->lgn_queue_lock);
261 
262  in_use = ocs_atomic_read(&cxn->login_mem_in_use);
263  if (in_use) {
264  rc = TRUE;
265  }
266 
267  return rc;
268 }
269 
270 /**
271  * @ingroup login
272  * @brief Frees any retry objects for the connection.
273  *
274  * @param cxn Pointer to the connection object.
275  */
278 {
279  ocs_iscsi_t *iscsi = cxn->iscsi;
280  ocs_iscsi_lgn_retry_t * retry;
281  ocs_iscsi_lgn_retry_t * next;
282 
283  ocs_lock(&iscsi->lgn_queue_lock);
284  if (!ocs_list_empty(&iscsi->login_retry_busy)) {
285  ocs_list_foreach_safe(&iscsi->login_retry_busy, retry, next) {
286  if (cxn == retry->cxn) {
287  /* Return buffers to the recv queue */
288  if (retry->hdr != NULL) {
289  ocs_iscsi_rx_buffers_free(iscsi, retry->hdr, retry->data);
290  }
291  ocs_list_remove(&iscsi->login_retry_busy, retry);
292  ocs_list_add_tail(&iscsi->login_retry_free, retry);
293  }
294  }
295  }
296  ocs_unlock(&iscsi->lgn_queue_lock);
297 
298  return OCS_HAL_RTN_SUCCESS;
299 }
300 
301 
302 /**
303  * @brief Get an available login buffer from the pre-allocated pool.
304  *
305  * @param cxn Pointer to the connection object.
306  *
307  * @return Returns 0 on success, or a non-zero value otherwise.
308  */
309 static int32_t ocs_iscsi_login_buffer_get(ocs_cxn_t *cxn)
310 {
311  int32_t rc = -1;
312  int value;
313 
314  value = ocs_atomic_add_return(&cxn->login_mem_in_use, 1);
315  if (value == 0) {
316  rc = 0;
317  } else {
318  (void)ocs_atomic_sub_return(&cxn->login_mem_in_use, 1);
319  }
320  return rc;
321 }
322 
323 /**
324  * @brief Return a login buffer to the pre-allocated pool.
325  *
326  * @param cxn Pointer to the connection object.
327  */
328 static void ocs_iscsi_login_buffer_free(ocs_cxn_t *cxn)
329 {
330  ocs_assert(cxn);
331  (void)ocs_atomic_sub_return(&cxn->login_mem_in_use, 1);
332 
333  if (cxn->cxn_state == CONN_STATE_LOGIN_FAILED) {
334  ocs_cxn_close(cxn, FALSE);
335  }
336 
337  /* call after memory is freed, so it doesn't show as active */
338  if (cxn->cxn_state == CONN_STATE_CLEANUP ||
339  cxn->cxn_state == CONN_STATE_LOGIN_FAILED ||
340  cxn->cxn_state == CONN_STATE_LOGOUT_REQUESTED) {
341  ocs_sm_post_event(&cxn->sm, OCS_EVT_IO_CMPL, NULL);
342  }
343 }
344 
345 
346 /**
347  * @brief Allocate the iSCSI retry buffers and add them to the pool.
348  *
349  * @param iscsi Pointer to the iSCSI object.
350  *
351  * @return Returns 0 on success, or a non-zero value otherwise.
352  */
353 static int32_t
355  uint32_t indx;
356 
357  iscsi->lgn_retry = ocs_malloc(iscsi->os, sizeof(ocs_iscsi_lgn_retry_t) *
359  OCS_M_ZERO | OCS_M_NOWAIT);
360  if (iscsi->lgn_retry == NULL) {
361  ocs_log_err(iscsi->os, "Failed to allocate login memory list\n");
362  return -ENOMEM;
363  }
364 
365  for (indx = 0; indx < OCS_ISCSI_LOGIN_RETRY_ENTRIES; indx++) {
366  ocs_list_add_tail(&iscsi->login_retry_free, &iscsi->lgn_retry[indx]);
367  }
368 
369  return 0;
370 }
371 
372 
373 /**
374  * @brief Free the iSCSI login retry buffers.
375  *
376  * @param iscsi Pointer to the iSCSI object.
377  */
378 static void
380  if (iscsi->lgn_retry != NULL) {
381  ocs_free(iscsi->os, iscsi->lgn_retry,
383  iscsi->lgn_retry = NULL;
384  }
385 
388 }
389 
390 
391 /**
392  * @ingroup login
393  * @brief Attempt to start a request on the retry queue.
394  *
395  * @par Description
396  * Since requests may be queued due to both lack of WRB or login memory,
397  * this function may be called from an IO completion.
398  *
399  * @param cxn Pointer to the connection object.
400  */
401 void
402 ocs_iscsi_login_retry(ocs_cxn_t *cxn) {
403  ocs_iscsi_t *iscsi = cxn->iscsi;
404  ocs_iscsi_lgn_retry_t * retry;
405  ocs_iscsi_lgn_retry_t * next;
406  ocs_iscsi_lgn_retry_t retry_local;
407  int32_t rc;
408 
409  /*
410  * Since there is only a single login payload buffer and we are only
411  * restarting requests for this connection, then break out of the loop
412  * after the first entry is attempted.
413  */
414  ocs_lock(&iscsi->lgn_queue_lock);
415  ocs_list_foreach_safe(&iscsi->login_retry_busy, retry, next) {
416  if (retry->cxn != cxn) {
417  continue;
418  }
419 
420  ocs_list_remove(&iscsi->login_retry_busy, retry);
421  retry_local = *retry;
422  ocs_list_add_tail(&iscsi->login_retry_free, retry);
423 
424  /* unlock in case we add back to the queue */
425  ocs_unlock(&iscsi->lgn_queue_lock);
426 
427  switch(retry_local.type) {
429  rc = ocs_iscsi_send_login(retry_local.cxn,
430  retry_local.is_discovery,
431  retry_local.virt_buffer);
432  break;
435  (retry_local.cxn, retry_local.itt);
436  break;
437 
439  rc = ocs_iscsi_send_async(retry_local.cxn,
440  retry_local.virt_buffer,
441  retry_local.data_len,
442  retry_local.reason,
443  retry_local.lun,
444  retry_local.param1,
445  retry_local.param2,
446  retry_local.param3);
447  break;
449  rc = ocs_iscsi_send_logout(retry_local.cxn,
450  retry_local.immediate,
451  retry_local.reason);
452  break;
454  rc = ocs_iscsi_send_logout_rsp(retry_local.cxn,
455  retry_local.reason,
456  retry_local.itt);
457  break;
459  rc = ocs_iscsi_send_nop_in(retry_local.cxn,
460  retry_local.lun,
461  retry_local.itt,
462  retry_local.ttt,
463  retry_local.virt_buffer,
464  retry_local.data_len);
465  break;
467  rc = ocs_iscsi_send_nop_out(retry_local.cxn,
468  retry_local.lun,
469  retry_local.itt,
470  retry_local.ttt,
471  retry_local.virt_buffer,
472  retry_local.data_len);
473  break;
475  rc = ocs_iscsi_send_reject(retry_local.cxn,
476  retry_local.virt_buffer,
477  retry_local.hdr_len,
478  retry_local.reason);
479  break;
481  rc = ocs_iscsi_recv_login_rsp(retry_local.cxn,
482  retry_local.hdr,
483  retry_local.hdr_len,
484  retry_local.data,
485  retry_local.data_len);
486  break;
488  rc = ocs_iscsi_recv_logout(retry_local.cxn,
489  retry_local.hdr,
490  retry_local.hdr_len);
491  break;
492  default:
493  rc = 0; /* try the next one */
494  ocs_log_test(iscsi->os, "Unhandled retry type %d\n",
495  retry_local.type);
496  }
497  ocs_lock(&iscsi->lgn_queue_lock);
498  if (rc != 0 &&
499  rc != OCS_LOGIN_REQUEST_QUEUED) {
500  ocs_log_test(iscsi->os, "failed sending retry request\n");
501  }
502  break;
503  }
504  ocs_unlock(&iscsi->lgn_queue_lock);
505 }
506 
507 
508 /**
509  * @brief Get an available retry buffer from the pre-allocated pool.
510  *
511  * @param iscsi Pointer to the iSCSI object.
512  *
513  * @return Pointer to retry object on success, or NULL otherwise.
514  */
516 {
517  ocs_iscsi_lgn_retry_t * rc = NULL;
518 
519  ocs_lock(&iscsi->lgn_queue_lock);
520  rc = ocs_list_get_head(&iscsi->login_retry_free);
521  if (NULL != rc) {
523  ocs_list_add_tail(&iscsi->login_retry_busy, rc);
524  rc->hdr = NULL;
525  rc->hdr_len = 0;
526  rc->data = NULL;
527  rc->data_len = 0;
528  } else {
529  ocs_log_err(iscsi->os, "failed to allocate a login retry buffer\n");
530  }
531  ocs_unlock(&iscsi->lgn_queue_lock);
532 
533  return rc;
534 }
535 
536 /**
537  * @brief Return a login retry buffer to the pre-allocated pool.
538  *
539  * @param iscsi Pointer to the iSCSI object.
540  * @param retry Pointer to the login retry object.
541  */
543 {
544  ocs_lock(&iscsi->lgn_queue_lock);
545  ocs_list_remove(&iscsi->login_retry_busy, retry);
546  ocs_list_add_tail(&iscsi->login_retry_free, retry);
547  ocs_unlock(&iscsi->lgn_queue_lock);
548 }
549 
550 
551 /**
552  * @brief Fill in the data segment length in a PDU header.
553  *
554  * @param dw Pointer to the dword in the BHS.
555  * @param count Data segment length.
556  */
557 static void
559 {
560  dw->data_segment_length[0] = (count >> 16) & 0xff;
561  dw->data_segment_length[1] = (count >> 8) & 0xff;
562  dw->data_segment_length[2] = count & 0xff;
563 }
564 
565 
566 /**
567  * @brief Find a key within the passed login text.
568  *
569  * @param key Pointer to the requested key.
570  * @param text Pointer to the text to search.
571  * @param length Length of the text buffer.
572  *
573  * @return Returns pointer to the value string for the key, or NULL if not found.
574  */
575 static char *
576 ocs_iscsi_login_find_key(char *key, char *text, unsigned int length)
577 {
578  unsigned int j, k, instring;
579  char *val;
580  char *p = text;
581 
582  if (key != NULL &&
583  text != NULL) {
584  for (instring = j = 0; j != length; j++) {
585  if(text[j] == 0) {
586  instring = 0;
587  continue;
588  }
589  if (instring++ == 0) {
590  p = &text[j];
591  }
592  if (text[j] == '=') {
593  text[j] = 0; /* Change to null terminated string */
594  if (ocs_strcmp(key, p) == 0) {
595  text[j] = '='; /* Change back to original string */
596  val = (char *)&text[++j];
597  for (k = j; k != length; k++) {
598  if (text[k] == 0)
599  break;
600  }
601  if (k == length || text[k] != 0)
602  val = NULL;
603  return (val);
604  }
605  text[j] = '='; /* Change back to original string */
606  }
607  }
608  }
609  return (NULL);
610 }
611 
612 
613 /**
614  * @brief Finds the next equal and null termination for the key.
615  *
616  * @param data Pointer to the payload data.
617  * @param data_len Length of the data received.
618  * @param pos Current position in the payload.
619  * @param equal_pos Returns the position of the equal sign.
620  * @param null_pos Returns the position of the null termination character
621  * (may include padding bytes).
622  *
623  * @return Returns enum for the key, or KEY_MAX if not recognized.
624  */
625 static ocs_login_key_t
627  uint32_t data_len,
628  uint32_t pos,
629  uint32_t *equal_pos,
630  uint32_t *null_pos)
631 {
633  uint32_t index;
634  uint32_t cmp_index;
635  uint8_t matches;
636 
637  *equal_pos = 0;
638  *null_pos = 0;
639  index = pos;
640  while (index < data_len) {
641  if (data[index] == '=' &&
642  *equal_pos == 0) {
643  *equal_pos = index;
644  }
645 
646  if (data[index] == '\0') {
647  *null_pos = index;
648  } else if (*null_pos != 0) {
649  break;
650  }
651  index++;
652  }
653 
654  /*
655  * Now convert the key text to the enum type
656  */
657  if (*equal_pos != 0) {
658  for (index = 0; index < KEY_MAX; index++) {
659  matches = TRUE;
660  cmp_index = 0;
661  while (matches && cmp_index < (*equal_pos - pos)) {
662  matches = (ocs_login_key_defs[index].key_name[cmp_index] ==
663  data[pos + cmp_index]);
664  cmp_index++;
665  }
666  /* Make sure we hit the end of the comparison string */
667  if (matches) {
668  matches = ocs_login_key_defs[index].key_name
669  [(*equal_pos - pos)] == '\0';
670  }
671 
672  /* If we still match - all is good */
673  if (matches) {
674  rc = index;
675  break;
676  }
677  }
678  }
679  return rc;
680 }
681 
682 
683 /**
684  * @brief Searches the list of comma-separated values for a specific value.
685  *
686  * @param text Pointer to the return from ocs_iscsi_login_find_key().
687  * @param value Pointer to the value to find.
688  *
689  * @return Returns 1 if found, or 0 if not found.
690  */
691 static int32_t
692 ocs_iscsi_login_find_value(char *text, const char *value)
693 {
694  unsigned int j;
695  char *p = text;
696  char orig_char;
697 
698  for (j = 0; j != strlen(text) + 1; j++) {
699  if (text[j] == ',' || text[j] == 0) {
700  orig_char = text[j];
701  text[j] = 0; /* Change to null terminated string */
702  if (ocs_strcmp(value, p) == 0) {
703  text[j] = orig_char; /* Change back to original string */
704  return 1;
705  }
706  text[j] = orig_char; /* Change back to original string */
707  p = &text[j+1];
708  }
709  }
710  return 0;
711 }
712 
713 
714 /**
715  * @brief Function to send iSCSI login keys.
716  *
717  * @param cxn Pointer to the connection object.
718  * @param key Login key to send.
719  * @param strptr Pointer of where to place output.
720  * @param avail_bytes Number of bytes remaining in the payload.
721  *
722  * @return Returns the number of bytes added to the payload.
723  */
724 static uint32_t
726  ocs_login_key_t key,
727  char *strptr,
728  uint32_t avail_bytes)
729 {
730  ocs_iscsi_t *iscsi = cxn->iscsi;
731  ocs_t *ocs = cxn->ocs;
732  ocs_session_t *session = cxn->session;
733  uint8_t has_text_reply = FALSE;
734  uint8_t has_int_reply = FALSE;
735  uint32_t int_reply = FALSE;
736  char *text_reply = NULL;
737  uint32_t rc = 0;
738  ocs_ip_address_t ip;
739  uint8_t req_chap;
740  char tmp_str[32];
741  uint32_t i;
742  char *tmp_tgt_name;
743  char challenge_str[OCS_CHAP_CHALLENGE_SIZE*2 + 3];
744 
745  if (cxn->lgn_parms_sent & (1l << key)) {
746  return rc;
747  }
748  switch (key) {
749  case KEY_AUTH_METHOD:
750  has_text_reply = TRUE;
751 
752  /* Figure out if we will accept CHAP or None */
753  if (cxn->is_ini_cxn) {
754  /* As Initiator, offer both Chap and None */
755  req_chap = FALSE;
756  } else {
757  req_chap = ocs_iscsi_tgt_require_chap
758  (cxn->ocs,
759  session->tgt_name,
760  (session->is_discovery_session ? OCS_SESSION_TYPE_DISCOVERY : OCS_SESSION_TYPE_NORMAL));
761  }
762 
763  /* No AuthMethod has been offered yet */
764  if ((cxn->lgn_parms_recv & (1l << KEY_AUTH_METHOD)) == 0) {
765  if (req_chap) {
766  text_reply = (char*)chap;
767  } else {
768  (void)ocs_snprintf(tmp_str, ARRAY_SIZE(tmp_str),
769  "%s,%s", chap, none);
770  text_reply = tmp_str;
771  }
772  } else {
773  /* If we get here, we did not reject the offer */
774  if (cxn->use_chap) {
775  text_reply = (char*)chap;
776 
777  /* Set the state since negotiation is done. */
778  cxn->chap_state = OCS_CHAP_STATE_CHAP_SELECTED;
779  } else {
780  text_reply = (char*)none;
781  }
782  }
783  break;
784 
785  case KEY_HEADER_DIGEST:
786  has_text_reply = TRUE;
787  if ((cxn->lgn_parms_recv & (1l << KEY_HEADER_DIGEST)) == 0) {
788  /* Key is not sent, send both if supported */
789  if (cxn->hdr_digest) {
790  (void)ocs_snprintf(tmp_str, ARRAY_SIZE(tmp_str),
791  "%s,%s", crc32c, none);
792  text_reply = tmp_str;
793  } else {
794  text_reply = (char*)none;
795  }
796  } else {
797  text_reply = (char*)(cxn->hdr_digest ? crc32c : none);
798  }
799  break;
800 
801  case KEY_DATA_DIGEST:
802  has_text_reply = TRUE;
803  if ((cxn->lgn_parms_recv & (1l << KEY_DATA_DIGEST)) == 0) {
804  /* Key is not sent, send both if supported */
805  if (cxn->data_digest) {
806  (void)ocs_snprintf(tmp_str, ARRAY_SIZE(tmp_str),
807  "%s,%s", crc32c, none);
808  text_reply = tmp_str;
809  } else {
810  text_reply = (char*)none;
811  }
812  } else {
813  text_reply = (char*)(cxn->data_digest ? crc32c : none);
814  }
815  break;
816 
817  case KEY_MAX_CONNECTIONS:
818  has_int_reply = TRUE;
819  int_reply = session->login_options.max_connections;
820  break;
821 
822  case KEY_SEND_TARGETS:
823  has_text_reply = TRUE;
824  text_reply = (char*)all;
825  break;
826 
827  case KEY_INITIAL_R2T:
828  has_text_reply = TRUE;
829  text_reply = (char*)(session->login_options.initial_r2t ? yes : no);
830  break;
831 
832  case KEY_IMMEDIATE_DATA:
833  has_text_reply = TRUE;
834  text_reply = (char*)(session->login_options.immediate_data ? yes : no);
835  break;
836 
838  /* No negotiation for this key, just send what we expect */
839  has_int_reply = TRUE;
840  cxn->max_rcv_dsl = OCS_ISCSI_LOGIN_MAX_RECV_DATA_SEG_LEN;
841  int_reply = cxn->max_rcv_dsl;
842  break;
843 
845  has_int_reply = TRUE;
846  int_reply = session->login_options.max_burst;
847  break;
848 
850  /*
851  * This key is Irrelevant when: InitialR2T=Yes and
852  * ImmediateData=No
853  */
854  if ((cxn->lgn_parms_recv & (1l << KEY_FIRST_BURST_LENGTH)) != 0 &&
855  (cxn->lgn_parms_recv & (1l << KEY_IMMEDIATE_DATA)) != 0 &&
856  session->login_options.initial_r2t != 0 &&
857  session->login_options.immediate_data == 0) {
858  has_text_reply = TRUE;
859  text_reply = (char*)irrelevant;
860  } else {
861  has_int_reply = TRUE;
862  int_reply = session->login_options.first_burst;
863  }
864  break;
865 
867  has_int_reply = TRUE;
868  int_reply = session->login_options.def_time_to_wait;
869  break;
870 
872  has_int_reply = TRUE;
873  int_reply = session->login_options.def_time_to_retain;
874  break;
875 
877  has_int_reply = TRUE;
878  int_reply = session->login_options.max_r2t;
879  break;
880 
882  has_text_reply = TRUE;
883  text_reply = (char*)(session->login_options.data_pdu_in_order ? yes : no);
884  break;
885 
887  has_text_reply = TRUE;
888  text_reply = (char*)(session->login_options.data_sequence_in_order ? yes : no);
889  break;
890 
892  has_int_reply = TRUE;
893  int_reply = session->login_options.error_recovery_level;
894  break;
895 
896  case KEY_TASK_REPORTING:
897  has_text_reply = TRUE;
898  text_reply = (char*)rfc3720;
899  break;
900 
901  case KEY_OF_MARKER:
902  has_text_reply = TRUE;
903  text_reply = (char*)no;
904  break;
905 
906  case KEY_IF_MARKER:
907  has_text_reply = TRUE;
908  text_reply = (char*)no;
909  break;
910 
911  case KEY_OF_MARK_INT:
912  case KEY_IF_MARK_INT:
913  if (cxn->lgn_parms_recv & (1l << key)) {
914  has_text_reply = TRUE;
915  text_reply = (char*)irrelevant;
916  }
917  break;
918 
920  has_int_reply = TRUE;
921  ip.ip_type = cxn->dest_ip_type;
922  ocs_memcpy(ip.ip_address, cxn->dest_ip, 16);
923  int_reply = ocs_iscsi_tgt_get_portal_group(cxn->ocs, session->tgt_name, &ip);
924  break;
925 
926  case KEY_TARGET_ALIAS:
927  i = 0;
928  while ((tmp_tgt_name = ocs_iscsi_tgt_get_names(ocs, i)) != NULL) {
929  if (ocs_strcmp(session->tgt_name, tmp_tgt_name) == 0) {
930  text_reply = ocs_iscsi_tgt_get_alias(ocs, i);
931  if (text_reply != NULL) {
932  has_text_reply = TRUE;
933  }
934  break;
935  }
936  i++;
937  }
938  break;
939  case KEY_INITIATOR_ALIAS:
940  text_reply = ocs_iscsi_ini_get_alias(ocs);
941  if (text_reply != NULL) {
942  has_text_reply = TRUE;
943  }
944  break;
945  case KEY_CHAP_ALGORITHM:
946  has_int_reply = TRUE;
947  int_reply = 5;
948  break;
949 
950  case KEY_CHAP_IDENTIFIER:
951  has_int_reply = TRUE;
952  cxn->chap_ident_sent = iscsi->chap_ident++;
953  int_reply = cxn->chap_ident_sent;
954  break;
955 
956  case KEY_CHAP_CHALLENGE:
957  /* Convert to ascii Hex */
959  (cxn->chap_challenge_sent, OCS_CHAP_CHALLENGE_SIZE,
960  challenge_str, ARRAY_SIZE(challenge_str));
961  has_text_reply = TRUE;
962  text_reply = challenge_str;
963  break;
964 
965  case KEY_CHAP_NAME:
966  has_text_reply = TRUE;
967  text_reply = cxn->chap_name_send;
968  break;
969 
970  case KEY_CHAP_RESPONSE:
971  has_text_reply = TRUE;
972  text_reply = cxn->chap_response;
973  break;
974 
975  /* ignore these keys are they are taken care of else where */
976  case KEY_TARGET_NAME:
977  case KEY_TARGET_ADDRESS:
978  case KEY_SESSION_TYPE:
979  case KEY_INITIATOR_NAME:
980  case KEY_MAX:
981  default:
982  break;
983  }
984 
985  /* Set the bitmask so that we know we have sent this key. */
986  cxn->lgn_parms_sent |= (1l << key);
987 
988  if (has_text_reply) {
989  rc = ocs_snprintf(strptr, avail_bytes, "%s=%s",
990  ocs_login_key_defs[key].key_name,
991  text_reply) + 1;
992  } else if(has_int_reply) {
993  rc = ocs_snprintf(strptr, avail_bytes, "%s=%d",
994  ocs_login_key_defs[key].key_name,
995  int_reply) + 1;
996  }
997  return rc;
998 }
999 
1000 /**
1001  * @brief Function to receive a login key and update the login structure.
1002  *
1003  * @param cxn Pointer to the connection object.
1004  * @param key Login key enum that was received.
1005  * @param value Value sent for the key.
1006  * @param status_detail Returns the status detail field if an error occurs.
1007  *
1008  * @return Returns 0 on success.
1009  */
1010 static int32_t
1012  ocs_login_key_t key,
1013  char *value,
1014  uint8_t *status_detail)
1015 {
1016  ocs_iscsi_t *iscsi = cxn->iscsi;
1017  ocs_session_t *session = cxn->session;
1018  int32_t rc = 0;
1019  unsigned long lvalue;
1020  uint8_t req_chap;
1021  uint8_t out_of_range = FALSE;
1022  uint8_t list_not_supported = FALSE;
1023  uint8_t invalid_boolean = FALSE;
1024 
1025  switch (key) {
1026  case KEY_AUTH_METHOD:
1027  /* Figure out if we will accept CHAP or None */
1028  if (cxn->is_ini_cxn) {
1029  /* As Initiator, accept both Chap and None */
1030  req_chap = FALSE;
1031  } else {
1032  req_chap = ocs_iscsi_tgt_require_chap
1033  (cxn->ocs,
1034  session->tgt_name,
1035  (session->is_discovery_session ? OCS_SESSION_TYPE_DISCOVERY : OCS_SESSION_TYPE_NORMAL));
1036  }
1037 
1038  /*
1039  * If the higher level SW requires CHAP and it wasn't offered,
1040  * then reject the login.
1041  */
1042  if (req_chap) {
1043  if (!ocs_iscsi_login_find_value(value, chap)) {
1044  ocs_log_test(iscsi->os, "CHAP is required and AuthMethod=CHAP was not offered\n");
1045  rc = -1;
1046  *status_detail = LOGIN_STATUS_DETAIL_INI_AUTHORIZATION;
1047  }
1048  }
1049 
1050  /*
1051  * We only support CHAP and None.
1052  */
1053  if (ocs_iscsi_login_find_value(value, chap)) {
1054  ocs_log_test(iscsi->os, "Cxn %s CHAP Enabled", cxn->display_name);
1055  cxn->use_chap = 1;
1056  /* Set the state if nogotiation is complete. */
1057  if ((cxn->lgn_parms_sent & (1l << KEY_AUTH_METHOD)) != 0) {
1058  cxn->chap_state = OCS_CHAP_STATE_CHAP_SELECTED;
1059  }
1060  } else if (!ocs_iscsi_login_find_value(value, none)) {
1061  list_not_supported = TRUE;
1062  }
1063  break;
1064 
1065  case KEY_HEADER_DIGEST:
1066  if (ocs_iscsi_login_find_value(value, crc32c)) {
1067  /* do nothing as this is our default */
1068  } else if (ocs_iscsi_login_find_value(value, none)) {
1069  if (cxn->hdr_digest == 1) {
1070  cxn->hdr_digest = 0;
1071  }
1072  } else {
1073  list_not_supported = TRUE;
1074  }
1075  break;
1076 
1077  case KEY_DATA_DIGEST:
1078  if (ocs_iscsi_login_find_value(value, crc32c)) {
1079  /* do nothing as this is our default */
1080  } else if (ocs_iscsi_login_find_value(value, none)) {
1081  if (cxn->data_digest == 1) {
1082  cxn->data_digest = 0;
1083  }
1084  } else {
1085  list_not_supported = TRUE;
1086  }
1087  break;
1088 
1089  case KEY_MAX_CONNECTIONS:
1090  lvalue = ocs_strtoul(value, NULL, 0);
1091  if (lvalue < 1 || lvalue > 65535) {
1092  out_of_range = TRUE;
1093  } else if (lvalue < session->login_options.max_connections) {
1094  session->login_options.max_connections = lvalue;
1095  }
1096  break;
1097 
1098  case KEY_SEND_TARGETS:
1099  break;
1100 
1101  case KEY_INITIAL_R2T:
1102  if (ocs_strcmp(value, yes) == 0) {
1103  if (session->login_options.initial_r2t == 0) {
1104  session->login_options.initial_r2t = 1;
1105  }
1106  } else if (ocs_strcmp(value, no) != 0) {
1107  invalid_boolean = TRUE;
1108  }
1109  break;
1110 
1111  case KEY_IMMEDIATE_DATA:
1112  if (ocs_strcmp(value, no) == 0) {
1113  if (session->login_options.immediate_data == 1) {
1114  session->login_options.immediate_data = 0;
1115  }
1116  } else if (ocs_strcmp(value, yes) != 0) {
1117  invalid_boolean = TRUE;
1118  }
1119  break;
1120 
1122  lvalue = ocs_strtoul(value, NULL, 0);
1123  if (lvalue < 512 || lvalue > 16777215) {
1124  out_of_range = TRUE;
1125  } else {
1126  /* Firmware only supports 17 bits */
1127  if (lvalue >= (1 << 17) - 1) {
1128  cxn->max_xmit_dsl = (1 << 17) - 1;
1129  } else {
1130  cxn->max_xmit_dsl = lvalue;
1131  }
1132 
1133  /* Must not set > 64K for FW */
1134  if (cxn->max_xmit_dsl > 65536) {
1135  cxn->max_xmit_dsl = 65536;
1136  }
1137 
1138  /* make sure it is a 4 byte multiple */
1139  cxn->max_xmit_dsl = cxn->max_xmit_dsl & ~(0x3);
1140  }
1141  break;
1142 
1143  case KEY_MAX_BURST_LENGTH:
1144  lvalue = ocs_strtoul(value, NULL, 0);
1145  if (lvalue < 512 || lvalue > 16777215) {
1146  out_of_range = TRUE;
1147  } else if (lvalue < session->login_options.max_burst) {
1148  /* Firmware only supports 19 bits */
1149  if (lvalue >= (1 << 19) - 1) {
1150  session->login_options.max_burst = (1 << 19) - 1;
1151  } else {
1152  session->login_options.max_burst = lvalue;
1153  }
1154  /* make sure it is a 4 byte multiple */
1155  session->login_options.max_burst =
1156  session->login_options.max_burst & ~(0x3);
1157 
1158  /* Adjust first burst if required, cannot be bigger */
1159  if (session->login_options.first_burst >
1160  session->login_options.max_burst) {
1161  session->login_options.first_burst =
1162  session->login_options.max_burst;
1163  }
1164  }
1165  break;
1166 
1168  /* Check for Irrelevant */
1169  if ((cxn->lgn_parms_recv & (1l << KEY_IMMEDIATE_DATA)) != 0 &&
1170  session->login_options.immediate_data == 0 &&
1171  ocs_strcmp(value, irrelevant) == 0) {
1172  /* okay, this key is irrelevant */
1173  } else {
1174  lvalue = ocs_strtoul(value, NULL, 0);
1175  if (lvalue < 512 || lvalue > 16777215) {
1176  out_of_range = TRUE;
1177  } else if (lvalue < session->login_options.first_burst &&
1178  lvalue != 0) {
1179  /* Firmware only supports 14 bits */
1180  if (lvalue >= (1 << 14) - 1) {
1181  session->login_options.first_burst = (1 << 14) - 1;
1182  } else {
1183  session->login_options.first_burst = lvalue;
1184  }
1185  /* make sure it is a 4 byte multiple */
1186  session->login_options.first_burst =
1187  session->login_options.first_burst & ~(0x3);
1188  }
1189  }
1190  break;
1191 
1193  lvalue = ocs_strtoul(value, NULL, 0);
1194  if (lvalue > 3600) {
1195  out_of_range = TRUE;
1196  } else if (lvalue < session->login_options.def_time_to_wait) {
1197  session->login_options.def_time_to_wait = lvalue;
1198  }
1199  break;
1200 
1202  lvalue = ocs_strtoul(value, NULL, 0);
1203  if (lvalue > 3600) {
1204  out_of_range = TRUE;
1205  } else if (lvalue < session->login_options.def_time_to_retain) {
1206  session->login_options.def_time_to_retain = lvalue;
1207  }
1208  break;
1209 
1211  lvalue = ocs_strtoul(value, NULL, 0);
1212  if (lvalue < 1 || lvalue > 65535) {
1213  out_of_range = TRUE;
1214  } else if (lvalue < session->login_options.max_r2t) {
1215  session->login_options.max_r2t = lvalue;
1216  }
1217  break;
1218 
1219  case KEY_DATA_PDU_IN_ORDER:
1220  if (ocs_strcmp(value, yes) == 0) {
1221  if (session->login_options.data_pdu_in_order == 0) {
1222  session->login_options.data_pdu_in_order = 1;
1223  }
1224  } else if (ocs_strcmp(value, no) != 0) {
1225  invalid_boolean = TRUE;
1226  }
1227  break;
1228 
1230  if (ocs_strcmp(value, yes) == 0) {
1231  if (session->login_options.data_sequence_in_order == 0) {
1232  session->login_options.data_sequence_in_order = 1;
1233  }
1234  } else if (ocs_strcmp(value, no) != 0) {
1235  invalid_boolean = TRUE;
1236  }
1237  break;
1238 
1240  lvalue = ocs_strtoul(value, NULL, 0);
1241  if (lvalue > 2) {
1242  out_of_range = TRUE;
1243  } else if (lvalue < session->login_options.error_recovery_level) {
1244  session->login_options.error_recovery_level = lvalue;
1245  }
1246  break;
1247 
1248  case KEY_TASK_REPORTING:
1249  if (ocs_iscsi_login_find_value(value, rfc3720)) {
1250  /* do nothing as this is our default */
1251  } else {
1252  list_not_supported = TRUE;
1253  }
1254  break;
1255 
1256  case KEY_CHAP_ALGORITHM:
1257  /*
1258  * We only support MD5.
1259  */
1260  if (!ocs_iscsi_login_find_value(value, "5")) {
1261  ocs_log_test(iscsi->os, "CHAP Algorithm 5 was not offered, other are not supported\n");
1262  rc = -1;
1263  *status_detail = LOGIN_STATUS_DETAIL_INI_MISSING_PARAM;
1264  }
1265  break;
1266 
1267  case KEY_CHAP_IDENTIFIER:
1268  lvalue = ocs_strtoul(value, NULL, 0);
1269  cxn->chap_ident_recv = lvalue;
1270  break;
1271 
1272  case KEY_CHAP_CHALLENGE:
1273  /* save string for later proccessing */
1274  cxn->chap_challenge_recv = value;
1275  break;
1276 
1277  case KEY_CHAP_RESPONSE:
1278  /* save string for later proccessing */
1279  cxn->chap_response = value;
1280  break;
1281 
1282  case KEY_CHAP_NAME:
1283  /* save string for later proccessing */
1284  cxn->chap_name_recv = value;
1285  break;
1286 
1288  /* Just validate the value range */
1289  lvalue = ocs_strtoul(value, NULL, 0);
1290  if (lvalue > 65535) {
1291  out_of_range = TRUE;
1292  }
1293  break;
1294 
1295  /* These keys are not supported - so we don't need to store */
1296  case KEY_OF_MARKER:
1297  case KEY_IF_MARKER:
1298  if (ocs_strcmp(value, yes) != 0 &&
1299  ocs_strcmp(value, no) != 0) {
1300  invalid_boolean = TRUE;
1301  }
1302  break;
1303 
1304  case KEY_OF_MARK_INT:
1305  case KEY_IF_MARK_INT:
1306  lvalue = ocs_strtoul(value, NULL, 0);
1307  if (lvalue < 1 || lvalue > 65535) {
1308  out_of_range = TRUE;
1309  }
1310  break;
1311 
1312  /* ignore these keys are they are taken care of else where */
1313  case KEY_SESSION_TYPE:
1314  case KEY_INITIATOR_NAME:
1315  case KEY_TARGET_NAME:
1316  case KEY_TARGET_ADDRESS:
1317  case KEY_INITIATOR_ALIAS:
1318  case KEY_TARGET_ALIAS:
1319 
1320  case KEY_MAX:
1321  default:
1322  break;
1323  }
1324 
1325  /*
1326  * Check to see if this key has already been negotiated. If so, then
1327  * reject with an initiator error.
1328  */
1329  if ((cxn->lgn_parms_recv & (1l << key)) != 0) {
1330  ocs_log_test(iscsi->os, "Key %s was negotiated multiple times\n",
1331  ocs_login_key_defs[key].key_name);
1332  rc = -1;
1333  *status_detail = LOGIN_STATUS_DETAIL_INI_MISC;
1334  } else {
1335  cxn->lgn_parms_recv |= (1l << key);
1336  if (out_of_range) {
1337  ocs_log_test(iscsi->os, "Key %s is out of range\n",
1338  ocs_login_key_defs[key].key_name);
1339  rc = -1;
1340  *status_detail = LOGIN_STATUS_DETAIL_INI_MISC;
1341  } else if (list_not_supported) {
1342  ocs_log_test(iscsi->os, "No supported list value found for key %s, value recv %s\n",
1343  ocs_login_key_defs[key].key_name,
1344  value);
1345  rc = -1;
1346  *status_detail = LOGIN_STATUS_DETAIL_INI_MISC;
1347  } else if (invalid_boolean) {
1348  ocs_log_test(iscsi->os, "Invalid boolean value for key %s, value recv %s\n",
1349  ocs_login_key_defs[key].key_name,
1350  value);
1351  rc = -1;
1352  *status_detail = LOGIN_STATUS_DETAIL_INI_MISC;
1353  }
1354  }
1355 
1356  return rc;
1357 }
1358 
1359 
1360 /**
1361  * @brief Convert a target name to a sport object.
1362  *
1363  * @param cxn Pointer to the connection object.
1364  * @param tgt_name Target name string.
1365  *
1366  * @return Pointer to a sport, or NULL if no match was found.
1367  */
1368 static ocs_sport_t*
1369 ocs_iscsi_login_convert_tgt_name(ocs_cxn_t *cxn, char *tgt_name)
1370 {
1371  ocs_sport_t *rval = NULL;
1372  ocs_t *ocs = cxn->ocs;
1373  uint32_t i;
1374  char *tmp_tgt_name;
1375 
1376  if (ocs_is_target_enabled()) {
1377  i = 0;
1378  while ((tmp_tgt_name = ocs_iscsi_tgt_get_names(ocs, i)) != NULL) {
1379  if (ocs_strcmp(tgt_name, tmp_tgt_name) == 0) {
1380  rval = &ocs->sport[i];
1381  break;
1382  }
1383  i++;
1384  }
1385  }
1386  return rval;
1387 }
1388 
1389 
1390 /**
1391  * @brief Function to validate the initial login PDU
1392  *
1393  * @param cxn Pointer to the connection object.
1394  * @param pi Pointer to the inbound PDU header.
1395  * @param status Returns the login status based on the received keys.
1396  * @param status_detail Returns the login status detail based on the received
1397  * keys.
1398  * @param data Pointer to the payload data.
1399  * @param data_len Length of the data received.
1400  *
1401  * @return Returns 0 on success.
1402  */
1403 static int32_t
1406  uint8_t *status,
1407  uint8_t *status_detail,
1408  char *data,
1409  uint32_t data_len)
1410 {
1411  ocs_iscsi_t *iscsi = cxn->iscsi;
1412  ocs_session_t *session;
1413  ocs_t *ocs = iscsi->os;
1414  ocs_sport_t *sport;
1415  uint8_t *isid_ptr;
1416  uint64_t isid;
1417  int32_t rc;
1418  uint32_t i;
1419  char *ini_name;
1420  char *tgt_name;
1421  char *sessType;
1422 
1423  /*
1424  * Verify the initiator name for all session
1425  */
1426  ini_name = ocs_iscsi_login_find_key(ocs_login_key_defs[KEY_INITIATOR_NAME].key_name,
1427  data, data_len);
1428  if (!ini_name) {
1429  ocs_log_test(ocs, "no Initiator name\n");
1430  *status = LOGIN_STATUS_INI_ERROR;
1431  *status_detail = LOGIN_STATUS_DETAIL_INI_MISC;
1432  return *status;
1433  }
1434 
1435  /* May be NULL for discovery sessions */
1436  tgt_name = ocs_iscsi_login_find_key(ocs_login_key_defs[KEY_TARGET_NAME].key_name,
1437  data, data_len);
1438 
1439  /* Convert the 48 bit isid from big endian */
1440  isid_ptr = (uint8_t*)&pi->isid_tsid_ptr.isid0;
1441  isid = 0;
1442  for (i = 0; i < 6; i++) {
1443  isid = (isid << 8) | isid_ptr[i];
1444  }
1445 
1446  /*
1447  * Attach to the session.
1448  */
1449  cxn->cid = ocs_be16toh(pi->cid);
1450  rc = ocs_session_cxn_new(cxn,
1451  (tgt_name == NULL ? ocs_iscsi_tgt_get_names(ocs, 0) : tgt_name),
1452  ini_name,
1453  isid,
1454  ocs_be16toh(pi->isid_tsid_ptr.tsid),
1455  ocs_be16toh(pi->cid),
1456  ocs_be32toh(pi->cmd_sn));
1457 
1458  if (rc == 1) { /* Session does not exist */
1459  ocs_log_test(ocs, "session 0x%x does not exist\n",
1460  ocs_be16toh(pi->isid_tsid_ptr.tsid));
1461  *status = LOGIN_STATUS_INI_ERROR;
1463  return *status;
1464  } else if (rc == 2) { /* exceed Max Cxn */
1465  ocs_log_test(ocs, "session 0x%x exceeded max connections\n",
1466  ocs_be16toh(pi->isid_tsid_ptr.tsid));
1467  *status = LOGIN_STATUS_INI_ERROR;
1468  *status_detail = LOGIN_STATUS_DETAIL_INI_TOO_MANY_CXN;
1469  return *status;
1470  } else if (rc == 3) { /* 3 - no resources */
1471  ocs_log_test(ocs, "session 0x%x out of resources\n",
1472  ocs_be16toh(pi->isid_tsid_ptr.tsid));
1473  *status = LOGIN_STATUS_TGT_ERROR;
1474  *status_detail = LOGIN_STATUS_DETAIL_TGT_OUT_OF_RSRC;
1475  return *status;
1476  } else if (rc != 0) {
1477  ocs_log_test(ocs, "session 0x%x unhandled error\n",
1478  ocs_be16toh(pi->isid_tsid_ptr.tsid));
1479  *status = LOGIN_STATUS_TGT_ERROR;
1480  *status_detail = LOGIN_STATUS_DETAIL_TGT_MISC;
1481  return *status;
1482  }
1483  session = cxn->session;
1484 
1485  /*
1486  * Verify the session type, initiator and target name
1487  */
1488  sessType = ocs_iscsi_login_find_key(ocs_login_key_defs[KEY_SESSION_TYPE].key_name,
1489  data, data_len);
1490  if (sessType) {
1491  if (ocs_strcmp(sessType, "Discovery") == 0) {
1492  session->is_discovery_session = 1;
1493  ocs_log_debug(ocs, "SessionType is Discovery\n");
1494  } else if (ocs_strcmp(sessType, "Normal") == 0) {
1495  /* Nothing to do... */
1496  } else {
1497  ocs_log_test(ocs, "Invalid session type\n");
1498  *status = LOGIN_STATUS_INI_ERROR;
1499  *status_detail = LOGIN_STATUS_DETAIL_INI_MISC;
1500  return *status;
1501  }
1502  } else if (cxn->is_leading_login) {
1503  ocs_log_test(ocs, "no session key on leading login\n");
1504  *status = LOGIN_STATUS_INI_ERROR;
1505  *status_detail = LOGIN_STATUS_DETAIL_INI_MISC;
1506  return *status;
1507  }
1508 
1509  /*
1510  * Verify the target name for Normal session
1511  */
1512  if (!session->is_discovery_session) {
1513  if (tgt_name == NULL) {
1514  ocs_log_test(ocs, "no target name\n");
1515  *status = LOGIN_STATUS_INI_ERROR;
1516  *status_detail = LOGIN_STATUS_DETAIL_INI_MISC;
1517  return *status;
1518  } else if ((sport = ocs_iscsi_login_convert_tgt_name(cxn, tgt_name)) == NULL) {
1519  ocs_log_test(ocs, "Target name mismatch, received %s\n", tgt_name);
1520  *status = LOGIN_STATUS_INI_ERROR;
1521  *status_detail = LOGIN_STATUS_DETAIL_INI_AUTHORIZATION;
1522  return *status;
1523  } else if (!ocs_iscsi_tgt_is_access_allowed(cxn->ocs, tgt_name, session->ini_name)) {
1524  ocs_log_test(ocs, "No access to target allowed\n");
1525  *status = LOGIN_STATUS_INI_ERROR;
1526  *status_detail = LOGIN_STATUS_DETAIL_INI_AUTHORIZATION;
1527  return *status;
1528  } else {
1529  /* When a cxn is established, we don't
1530  * know the target, so it is placed on
1531  * the first sport, move it to the
1532  * correct list if required
1533  */
1534  if (sport != cxn->sport) {
1535  ocs_sport_lock(cxn->sport);
1536  ocs_list_remove(&cxn->sport->node_list, cxn);
1537  ocs_sport_unlock(cxn->sport);
1538 
1539  cxn->sport = sport;
1540  ocs_sport_lock(sport);
1541  ocs_list_add_tail(&sport->node_list, cxn);
1542  ocs_sport_unlock(sport);
1543  }
1544  }
1545  }
1546 
1547  /*
1548  * Establish base command serial number stuff
1549  */
1550  if (*status == LOGIN_STATUS_SUCCESS) {
1551  /* ExpStatSn is only valid for connection recovery */
1552  if (ocs_be16toh(pi->isid_tsid_ptr.tsid) != 0) {
1553  cxn->stat_sn = ocs_be32toh(pi->exp_stat_sn);
1554  }
1555  cxn->cxn_state = CONN_STATE_LOGIN_PROGRESS;
1556  session->login_options.max_connections =
1557  ocs_iscsi_get_max_cxns(cxn->ocs, session->tgt_name, session->ini_name);
1558  if (cxn->is_leading_login) {
1559  ocs_session_exp_cmd_sn_set(cxn, ocs_be32toh(pi->cmd_sn));
1560  ocs_session_max_cmd_sn_upd(cxn->session);
1561  }
1562  }
1563  return *status;
1564 }
1565 
1566 /**
1567  * @brief Function to negotiate iSCSI keys.
1568  *
1569  * @param cxn Pointer to the connection object.
1570  * @param phase Login phase being negotiated.
1571  * @param status Returns the login status based on the received keys.
1572  * @param status_detail Returns the login status detail based on the received
1573  * keys.
1574  * @param recv Pointer to the payload data.
1575  * @param recv_len Length of the data received.
1576  * @param rsp Pointer to the the login response payload.
1577  * @param rsp_size Maximum size of the response.
1578  *
1579  * @return Returns the payload length.
1580  */
1581 static uint32_t
1583  uint8_t phase,
1584  uint8_t *status,
1585  uint8_t *status_detail,
1586  char *recv,
1587  uint32_t recv_len,
1588  char *rsp,
1589  uint32_t rsp_size)
1590 {
1591  ocs_iscsi_t *iscsi = cxn->iscsi;
1592  ocs_session_t *session = cxn->session;
1593  char *strptr = rsp;
1594  uint32_t lavail = rsp_size;
1595  uint32_t skip;
1596  uint32_t pos = 0;
1597  uint32_t equal_pos, null_pos;
1598  ocs_login_key_t key;
1599 
1600  *status = 0;
1601  *status_detail = 0;
1602 
1603  /*
1604  * Scan the keys in the payload. If a negotiated parameter is offered,
1605  * then send our response. Mark the parameters negoiated as we go.
1606  */
1607  while (pos < recv_len) {
1608  /*
1609  * Find where the '=' and null termination is for the current position
1610  */
1611  key = ocs_iscsi_login_locate_key_locations(recv, recv_len, pos,
1612  &equal_pos, &null_pos);
1613  if (equal_pos != 0 &&
1614  null_pos != 0) {
1615  if (key == KEY_MAX) {
1616  recv[equal_pos] = '\0';
1617  ocs_log_test(iscsi->os, "key %s not understood\n", &recv[pos]);
1618 
1619  /* Reply with not understood to the key */
1620  skip = ocs_snprintf(strptr, lavail,
1621  "%s=NotUnderstood", &recv[pos]) + 1;
1622  strptr += skip;
1623  lavail -= skip;
1624  /* Check that the key is sent the proper direction */
1625  /*
1626  * Test a special case for keys exceeding 63 characters,
1627  * which is a violation of spec.
1628  */
1629  } else if (equal_pos - pos > 63) {
1630  recv[equal_pos] = '\0';
1631  ocs_log_test(iscsi->os, "key %s is longer than 63 characters\n", &recv[pos]);
1632  *status = LOGIN_STATUS_INI_ERROR;
1633  *status_detail = LOGIN_STATUS_DETAIL_INI_MISC;
1634  /*
1635  * Test a special case for data exceeding 255
1636  * characters, which is a violation of spec.
1637  */
1638  } else if ((null_pos - equal_pos) > 255 &&
1639  !(ocs_login_key_defs[key].flags & KEY_FLAG_ALLOW_LARGE)) {
1640  recv[equal_pos] = '\0';
1641  ocs_log_test(iscsi->os, "key data for %s is longer than 255 characters\n",
1642  &recv[pos]);
1643  *status = LOGIN_STATUS_INI_ERROR;
1644  *status_detail = LOGIN_STATUS_DETAIL_INI_MISC;
1645  } else if ((!cxn->is_ini_cxn &&
1646  !(ocs_login_key_defs[key].flags & KEY_FLAG_SEND_INI)) ||
1647  (cxn->is_ini_cxn &&
1648  !(ocs_login_key_defs[key].flags & KEY_FLAG_SEND_TGT))) {
1649  ocs_log_test(iscsi->os, "key %s sent by wrong side\n",
1650  ocs_login_key_defs[key].key_name);
1651  *status = LOGIN_STATUS_INI_ERROR;
1652  *status_detail = LOGIN_STATUS_DETAIL_INI_MISC;
1653  /* Check that the key is sent in the right phase */
1654  } else if ((phase == LOGIN_STAGE_NEGOTIATE_SECURITY &&
1655  !(ocs_login_key_defs[key].flags & KEY_FLAG_PHASE_SEC)) ||
1657  !(ocs_login_key_defs[key].flags & KEY_FLAG_PHASE_OPER)) ||
1658  (phase == LOGIN_STAGE_FULL_FEATURE &&
1659  !(ocs_login_key_defs[key].flags & KEY_FLAG_PHASE_FFP))) {
1660  ocs_log_test(iscsi->os, "key %s sent in wrong phase\n",
1661  ocs_login_key_defs[key].key_name);
1662  *status = LOGIN_STATUS_INI_ERROR;
1663  *status_detail = LOGIN_STATUS_DETAIL_INI_MISC;
1664  /* Check the leading only keys */
1665  } else if (!cxn->is_leading_login &&
1666  (ocs_login_key_defs[key].flags & KEY_FLAG_USE_LEADING)) {
1667  ocs_log_test(iscsi->os, "Leading Login key %s sent on non-leading login\n",
1668  ocs_login_key_defs[key].key_name);
1669  *status = LOGIN_STATUS_INI_ERROR;
1670  *status_detail = LOGIN_STATUS_DETAIL_INI_MISC;
1671  /* Make sure that irrelevant keys are not sent for discovery */
1672  } else if (session->is_discovery_session &&
1673  !(ocs_login_key_defs[key].flags & KEY_FLAG_VALID_DISC)) {
1674  /* Reply with irrelevant to the key */
1675  ocs_log_test(iscsi->os, "key %s is irrelevant\n",
1676  ocs_login_key_defs[key].key_name);
1677 
1678  skip = ocs_snprintf(strptr, lavail,
1679  "%s=%s",
1680  ocs_login_key_defs[key].key_name,
1681  irrelevant) + 1;
1682  strptr += skip;
1683  lavail -= skip;
1684  } else {
1685  /* A good key, save the negotiated value and reply if needed*/
1686  if (ocs_iscsi_login_recv_key(cxn,
1687  key,
1688  &recv[equal_pos+1],
1689  status_detail)) {
1690  ocs_log_test(iscsi->os, "key %s negotiation error\n",
1691  ocs_login_key_defs[key].key_name);
1692 
1693  *status = LOGIN_STATUS_INI_ERROR;
1694  /* bad key - set reject */
1695  skip = ocs_snprintf(strptr, lavail,
1696  "%s=Reject",
1697  ocs_login_key_defs[key].key_name) + 1;
1698  strptr += skip;
1699  lavail -= skip;
1700  } else if ((ocs_login_key_defs[key].flags & KEY_FLAG_NEGOTIATE) &&
1701  ((cxn->is_ini_cxn &&
1702  (ocs_login_key_defs[key].flags & KEY_FLAG_SEND_INI)) ||
1703  (!cxn->is_ini_cxn &&
1704  (ocs_login_key_defs[key].flags & KEY_FLAG_SEND_TGT))) &&
1705  (cxn->lgn_parms_sent & (1l << key)) == 0) {
1706  skip = ocs_iscsi_login_send_key(cxn,
1707  key,
1708  strptr,
1709  lavail);
1710  strptr += skip;
1711  lavail -= skip;
1712  }
1713  }
1714  } else {
1715  ocs_log_test(iscsi->os, "no equal found in string %s\n", recv);
1716 
1717  /* Malformed payload */
1718  *status = LOGIN_STATUS_INI_ERROR;
1719  *status_detail = LOGIN_STATUS_DETAIL_INI_MISC;
1720  break;
1721  }
1722  pos = null_pos + 1;
1723  }
1724 
1725  return strptr - rsp;
1726 }
1727 
1728 
1729 /**
1730  * @brief Converts binary to an ASCII hex string.
1731  *
1732  * @param bin Pointer to the binary array.
1733  * @param nbytes Number of bytes to convert.
1734  * @param str Pointer to the output string.
1735  * @param max_str Maximum size string allowed.
1736  */
1737 static void
1738 ocs_iscsi_login_convert_bin_to_hexstring(uint8_t *bin, uint32_t nbytes,
1739  char*str, uint32_t max_str)
1740 {
1741  uint32_t i;
1742  uint32_t pos;
1743 
1744  /* Convert to ascii Hex */
1745  pos = ocs_snprintf(str, max_str, "0x");
1746  for (i = 0; i < nbytes; i++) {
1747  pos += ocs_snprintf(&str[pos], max_str - pos, "%02x", bin[i]);
1748  }
1749 }
1750 
1751 
1752 /**
1753  * @brief Function to negotiate CHAP keys.
1754  *
1755  * @param hex_str Pointer to the hex string.
1756  * @param bin Pointer to the binary array.
1757  * @param nbytes Number of bytes in the binary array.
1758  *
1759  * @return Returns the number of binary bytes converted.
1760  */
1761 static uint32_t
1762 ocs_iscsi_login_convert_hexstring_to_bin(char*hex_str, uint8_t *bin, uint32_t nbytes)
1763 {
1764  char *curr = hex_str;
1765  uint32_t nibbles = 0;
1766  uint32_t byte = 0;
1767  uint32_t rc = 0;
1768 
1769  /* skip over 0x prefex */
1770  if (*curr == '0' &&
1771  (*(curr + 1) == 'x' || *(curr + 1) == 'X')) {
1772  curr += 2;
1773  }
1774 
1775  /* Check for an odd length string which implies a leading 0 nibble */
1776  if ((ocs_strlen(curr) % 2) == 1) {
1777  nibbles = 1;
1778  }
1779 
1780  while(*curr != '\0') {
1781  if (*curr >= '0' && *curr <= '9') {
1782  byte = (byte << 4) + (*curr - '0');
1783  } else if (*curr >= 'A' && *curr <= 'F') {
1784  byte = (byte << 4) + ((*curr - 'A') + 10);
1785  } else if (*curr >= 'a' && *curr <= 'f') {
1786  byte = (byte << 4) + ((*curr - 'a') + 10);
1787  } else {
1788  return 0;
1789  }
1790  nibbles++;
1791  if (nibbles == 2) {
1792  bin[rc] = byte;
1793  rc++;
1794  nibbles = 0;
1795  }
1796  curr++;
1797  }
1798  return rc;
1799 }
1800 
1801 
1802 /**
1803  * @brief Function to negotiate CHAP keys on a target connection.
1804  *
1805  * @param cxn Pointer to the connection object.
1806  * @param status Returns the login status based on the received keys.
1807  * @param status_detail Returns the login status detail based on the received
1808  * keys.
1809  * @param rsp Pointer to the the login response payload.
1810  * @param rsp_size Maximum size of the response payload.
1811  * @param rsp_len Pointer to the current length of the response.
1812  *
1813  * @return Returns the value for the transition bit.
1814  */
1815 static int32_t
1817  uint8_t *status,
1818  uint8_t *status_detail,
1819  char *rsp,
1820  uint32_t rsp_size,
1821  uint32_t *rsp_len)
1822 {
1823  ocs_t *ocs = cxn->ocs;
1824  ocs_iscsi_t *iscsi = cxn->iscsi;
1825  ocs_session_t *session = cxn->session;
1826  uint32_t skip;
1827  int32_t rc = 0;
1828  ocs_chap_state_e new_state = cxn->chap_state;
1829  char response_str[16*2 + 3];
1830  uint8_t resp_bin[16];
1831  uint8_t *challenge_recv;
1832  char *username;
1833  char *secret;
1834  uint32_t secret_len;
1835  uint32_t nbytes;
1836  ocs_md5_ctx_t md5;
1837  uint8_t calc_resp[16];
1838  unsigned char id_data[1];
1839 
1840  switch (cxn->chap_state)
1841  {
1843  /* Make sure we don't let the login transistion happen */
1845  break;
1846 
1848  if ((cxn->lgn_parms_recv & (1l << KEY_CHAP_ALGORITHM)) != 0) {
1849  /* Reply to the algorithm */
1850  skip = ocs_iscsi_login_send_key(cxn,
1852  rsp + *rsp_len,
1853  rsp_size - *rsp_len);
1854  *rsp_len += skip;
1855 
1856  /* Send the identifier */
1857  skip = ocs_iscsi_login_send_key(cxn,
1859  rsp + *rsp_len,
1860  rsp_size - *rsp_len);
1861  *rsp_len += skip;
1862 
1863  /* Send the Challenge - 64 bytes */
1864  ocs_memset(cxn->chap_challenge_sent, 0, sizeof(cxn->chap_challenge_sent));
1865  ocs_get_random_bytes(cxn->chap_challenge_sent, OCS_CHAP_CHALLENGE_SIZE);
1866  skip = ocs_iscsi_login_send_key(cxn,
1868  rsp + *rsp_len,
1869  rsp_size - *rsp_len);
1870  *rsp_len += skip;
1872  } else {
1873  ocs_log_test(iscsi->os, "Chap algorithm not provided");
1874  *status = LOGIN_STATUS_INI_ERROR;
1875  *status_detail = LOGIN_STATUS_DETAIL_INI_MISSING_PARAM;
1876  }
1877  break;
1878 
1880  /* Note: algorithm is negotiated normally */
1881  if ((cxn->lgn_parms_recv & (1l << KEY_CHAP_NAME)) != 0 &&
1882  (cxn->lgn_parms_recv & (1l << KEY_CHAP_RESPONSE)) != 0) {
1883 
1884  /* Convert the response string back to binary */
1886  (cxn->chap_response, resp_bin, ARRAY_SIZE(resp_bin));
1887 
1888  /* Validate the response */
1889  secret = ocs_iscsi_get_chap_secret(ocs, cxn->chap_name_recv, OCS_CHAP_MODE_TARGET,
1890  OCS_CHAP_TYPE_INCOMING, &secret_len);
1891  if (secret == NULL) {
1892  ocs_log_err(ocs, "Incoming CHAP secret is not found\n");
1893  new_state = OCS_CHAP_STATE_COMPLETE;
1894  return rc;
1895  }
1896 
1897  ocs_md5_init(&md5);
1898  id_data[0] = cxn->chap_ident_sent;
1899  ocs_md5_update(&md5, id_data, 1);
1900  ocs_md5_update(&md5, (unsigned char *)secret, secret_len);
1901  ocs_md5_update(&md5, (unsigned char *)cxn->chap_challenge_sent, OCS_CHAP_CHALLENGE_SIZE);
1902  ocs_md5_final(calc_resp, &md5);
1903 
1904  ocs_log_debug(iscsi->os, "Cxn %s verifying incoming CHAP\n",
1905  cxn->display_name);
1906  /* validate response */
1907  if (ocs_memcmp(calc_resp, resp_bin, ARRAY_SIZE(calc_resp)) != 0) {
1908  ocs_log_err(iscsi->os, "Failed Chap authentication for user %s",
1909  cxn->chap_name_recv);
1910  *status = LOGIN_STATUS_INI_ERROR;
1911  *status_detail = LOGIN_STATUS_DETAIL_INI_AUTHENTICATION;
1912  } else if ((cxn->lgn_parms_recv & (1l << KEY_CHAP_IDENTIFIER)) != 0 &&
1913  (cxn->lgn_parms_recv & (1l << KEY_CHAP_CHALLENGE)) != 0) {
1914  uint32_t recv_size;
1915 
1916  /* Target authentication is being requested */
1917  ocs_log_debug(iscsi->os, "Cxn %s CHAP Sending Target authentication",
1918  cxn->display_name);
1919  username = ocs_iscsi_get_chap_name(ocs, session->is_discovery_session,
1921  if (username == NULL) {
1922  ocs_log_err(ocs, "Outgoing CHAP name is not registered\n");
1923  new_state = OCS_CHAP_STATE_COMPLETE;
1924  return rc;
1925  }
1926 
1927  secret = ocs_iscsi_get_chap_secret(ocs, username, OCS_CHAP_MODE_TARGET,
1928  OCS_CHAP_TYPE_OUTGOING, &secret_len);
1929  if (secret == NULL) {
1930  ocs_log_err(ocs, "Outgoing CHAP secret is not registered\n");
1931  new_state = OCS_CHAP_STATE_COMPLETE;
1932  return rc;
1933  }
1934 
1935  recv_size = ocs_strlen(cxn->chap_challenge_recv) / 2;
1936  challenge_recv = ocs_malloc(ocs, recv_size, OCS_M_NOWAIT);
1937  if (challenge_recv == NULL) {
1938  ocs_log_err(iscsi->os, "challenge_recv memalloc failed\n");
1939  new_state = OCS_CHAP_STATE_COMPLETE;
1940  return rc;
1941  }
1942 
1944  (cxn->chap_challenge_recv, challenge_recv, recv_size);
1945 
1946  ocs_md5_init(&md5);
1947  id_data[0] = cxn->chap_ident_recv;
1948  ocs_md5_update(&md5, id_data, 1);
1949  ocs_md5_update(&md5, (unsigned char *)secret, secret_len);
1950  ocs_md5_update(&md5, (unsigned char *)challenge_recv, nbytes);
1951  ocs_md5_final(calc_resp, &md5);
1952 
1953  /* send name and response keys */
1954  cxn->chap_name_send = username;
1955  skip = ocs_iscsi_login_send_key(cxn,
1956  KEY_CHAP_NAME,
1957  rsp + *rsp_len,
1958  rsp_size - *rsp_len);
1959  *rsp_len += skip;
1960 
1962  (calc_resp, ARRAY_SIZE(calc_resp),
1963  response_str, ARRAY_SIZE(response_str));
1964  cxn->chap_response = response_str;
1965  skip = ocs_iscsi_login_send_key(cxn,
1967  rsp + *rsp_len,
1968  rsp_size - *rsp_len);
1969  *rsp_len += skip;
1970  cxn->chap_response = NULL;
1971  ocs_free(ocs, challenge_recv, recv_size);
1973  } else {
1974  ocs_log_debug(ocs, "CHAP state moved to complete state\n");
1975  new_state = OCS_CHAP_STATE_COMPLETE;
1976  }
1977 
1978  rc = 1; /* transition phase */
1979  } else {
1980  ocs_log_test(iscsi->os, "Chap name or response not provided");
1981  *status = LOGIN_STATUS_INI_ERROR;
1982  *status_detail = LOGIN_STATUS_DETAIL_INI_MISSING_PARAM;
1983  }
1984  break;
1985 
1989  rc = 1; /* transition phase */
1990  break;
1991  }
1992 
1993  cxn->chap_state = new_state;
1994  return rc;
1995 }
1996 
1997 
1998 /**
1999  * @brief Function to negotiate CHAP keys on an initiator connection.
2000  *
2001  * @param cxn Pointer to the connection object.
2002  * @param status Returns the login status based on the received keys.
2003  * @param status_detail Returns the login status detail based on the received
2004  * keys.
2005  * @param rsp Pointer to the login response payload.
2006  * @param rsp_size Maximum size of the response payload.
2007  * @param rsp_len Pointer to the current length of the response.
2008  *
2009  * @return Returns the value for the transition bit.
2010  */
2011 static int32_t
2013  uint8_t *status,
2014  uint8_t *status_detail,
2015  char *rsp,
2016  uint32_t rsp_size,
2017  uint32_t *rsp_len)
2018 {
2019  ocs_t *ocs = cxn->ocs;
2020  ocs_iscsi_t *iscsi = cxn->iscsi;
2021  ocs_session_t *session = cxn->session;
2022  uint32_t skip;
2023  int32_t rc = 0;
2024  ocs_chap_state_e new_state = cxn->chap_state;
2025  char response_str[16*2 + 3];
2026  uint8_t resp_bin[16];
2027  uint8_t *challenge_recv;
2028  char *username;
2029  char *secret;
2030  uint32_t secret_len;
2031  uint32_t nbytes;
2032  ocs_md5_ctx_t md5;
2033  uint8_t calc_resp[16];
2034  unsigned char id_data[1];
2035 
2036  switch (cxn->chap_state)
2037  {
2039  /* send the supported algorithms */
2040  skip = ocs_iscsi_login_send_key(cxn,
2042  rsp + *rsp_len,
2043  rsp_size - *rsp_len);
2044  *rsp_len += skip;
2046  break;
2047 
2049  if ((cxn->lgn_parms_recv & (1l << KEY_CHAP_ALGORITHM)) != 0 &&
2050  (cxn->lgn_parms_recv & (1l << KEY_CHAP_IDENTIFIER)) != 0 &&
2051  (cxn->lgn_parms_recv & (1l << KEY_CHAP_CHALLENGE)) != 0) {
2052  uint32_t recv_size;
2053 
2054  username = ocs_iscsi_get_chap_name(ocs, session->is_discovery_session,
2057  if (username == NULL) {
2058  ocs_log_err(ocs, "Outgoing CHAP name is not registered\n");
2059  new_state = OCS_CHAP_STATE_COMPLETE;
2060  return rc;
2061  }
2062 
2063  secret = ocs_iscsi_get_chap_secret(ocs, username, OCS_CHAP_MODE_INITIATOR,
2064  OCS_CHAP_TYPE_OUTGOING, &secret_len);
2065  if (secret == NULL) {
2066  ocs_log_err(ocs, "Outgoing CHAP secret is not registered\n");
2067  new_state = OCS_CHAP_STATE_COMPLETE;
2068  return rc;
2069  }
2070 
2071  recv_size = ocs_strlen(cxn->chap_challenge_recv) / 2;
2072  challenge_recv = ocs_malloc(ocs, recv_size,
2073  OCS_M_NOWAIT);
2075  (cxn->chap_challenge_recv, challenge_recv, recv_size);
2076 
2077  ocs_md5_init(&md5);
2078  id_data[0] = cxn->chap_ident_recv;
2079  ocs_md5_update(&md5, id_data, 1);
2080  ocs_md5_update(&md5, (unsigned char *)secret, secret_len);
2081  ocs_md5_update(&md5, (unsigned char *)challenge_recv, nbytes);
2082  ocs_md5_final(calc_resp, &md5);
2083 
2084  /* send name and response keys */
2085  cxn->chap_name_send = username;
2086  skip = ocs_iscsi_login_send_key(cxn,
2087  KEY_CHAP_NAME,
2088  rsp + *rsp_len,
2089  rsp_size - *rsp_len);
2090  *rsp_len += skip;
2091 
2093  (calc_resp, ARRAY_SIZE(calc_resp),
2094  response_str, ARRAY_SIZE(response_str));
2095  cxn->chap_response = response_str;
2096  skip = ocs_iscsi_login_send_key(cxn,
2098  rsp + *rsp_len,
2099  rsp_size - *rsp_len);
2100  *rsp_len += skip;
2101  cxn->chap_response = NULL;
2102  ocs_free(ocs, challenge_recv, recv_size);
2103 
2104  /* Request target authentication */
2105 
2106  /* Send the identifier */
2107  skip = ocs_iscsi_login_send_key(cxn,
2109  rsp + *rsp_len,
2110  rsp_size - *rsp_len);
2111  *rsp_len += skip;
2112 
2113  /* Send the Challenge - 64 bytes */
2114  ocs_memset(cxn->chap_challenge_sent, 0, sizeof(cxn->chap_challenge_sent));
2115  ocs_get_random_bytes(cxn->chap_challenge_sent, OCS_CHAP_CHALLENGE_SIZE);
2116  skip = ocs_iscsi_login_send_key(cxn,
2118  rsp + *rsp_len,
2119  rsp_size - *rsp_len);
2120  *rsp_len += skip;
2122  } else {
2123  ocs_log_test(iscsi->os, "Chap algorithm, ID or challenge not provided");
2124  *status = LOGIN_STATUS_INI_ERROR;
2125  *status_detail = LOGIN_STATUS_DETAIL_INI_MISSING_PARAM;
2126  }
2127  break;
2128 
2130  /* Note: algorithm is negotiated normally */
2131  if ((cxn->lgn_parms_recv & (1l << KEY_CHAP_NAME)) != 0 &&
2132  (cxn->lgn_parms_recv & (1l << KEY_CHAP_RESPONSE)) != 0) {
2133  /* Convert the response string back to binary */
2135  (cxn->chap_response, resp_bin, ARRAY_SIZE(resp_bin));
2136 
2137  /* Validate the response */
2138  secret = ocs_iscsi_get_chap_secret(ocs, cxn->chap_name_recv, OCS_CHAP_MODE_INITIATOR,
2139  OCS_CHAP_TYPE_INCOMING, &secret_len);
2140  if (secret == NULL) {
2141  ocs_log_err(ocs, "Incoming CHAP secret is not found\n");
2142  new_state = OCS_CHAP_STATE_COMPLETE;
2143  return rc;
2144  }
2145 
2146  ocs_md5_init(&md5);
2147  id_data[0] = cxn->chap_ident_sent;
2148  ocs_md5_update(&md5, id_data, 1);
2149  ocs_md5_update(&md5, (unsigned char *)secret, secret_len);
2150  ocs_md5_update(&md5, (unsigned char *)cxn->chap_challenge_sent, OCS_CHAP_CHALLENGE_SIZE);
2151  ocs_md5_final(calc_resp, &md5);
2152 
2153  /* validate response */
2154  if (ocs_memcmp(calc_resp, resp_bin, ARRAY_SIZE(calc_resp)) != 0) {
2155  ocs_log_err(iscsi->os, "Failed Chap authentication for user %s",
2156  cxn->chap_name_recv);
2157  *status = LOGIN_STATUS_INI_ERROR;
2158  *status_detail = LOGIN_STATUS_DETAIL_INI_AUTHENTICATION;
2159  } else {
2160  new_state = OCS_CHAP_STATE_COMPLETE;
2161  }
2162  rc = 1; /* transition phase */
2163  } else {
2164  ocs_log_test(iscsi->os, "Chap name or response not provided");
2165  *status = LOGIN_STATUS_INI_ERROR;
2166  *status_detail = LOGIN_STATUS_DETAIL_INI_MISSING_PARAM;
2167  }
2168  break;
2169 
2173  rc = 1; /* transition phase */
2174  break;
2175  }
2176 
2177  cxn->chap_state = new_state;
2178  return rc;
2179 }
2180 
2181 /**
2182  * @brief Function to queue a receive request.
2183  *
2184  * @param cxn Pointer to the connection object.
2185  * @param type Type of request being queued.
2186  * @param hdr DMA memory information for the header.
2187  * @param hdr_len Length of the header received.
2188  * @param data DMA memory information for the data.
2189  * @param data_len Length of the data received.
2190  *
2191  * @return Returns 0 on success.
2192  */
2193 static int32_t
2196  ocs_hal_rq_buffer_t *hdr,
2197  uint32_t hdr_len,
2198  ocs_hal_rq_buffer_t *data,
2199  uint32_t data_len)
2200 {
2201  ocs_iscsi_t *iscsi = cxn->iscsi;
2202  ocs_iscsi_lgn_retry_t *lgn_retry;
2203  int32_t rc;
2204 
2205  if ((lgn_retry = ocs_iscsi_login_retry_get(iscsi)) == NULL) {
2206  ocs_log_err(iscsi->os, "No retry resources are available");
2207  ocs_cxn_close(cxn, TRUE);
2209  } else {
2210  lgn_retry->type = type;
2211  lgn_retry->cxn = cxn;
2212  lgn_retry->hdr = hdr;
2213  lgn_retry->hdr_len = hdr_len;
2214  lgn_retry->data = data;
2215  lgn_retry->data_len = data_len;
2217  }
2218  return rc;
2219 }
2220 
2221 
2222 
2223 /**
2224  * @ingroup login
2225  * @brief Does the initial checks and processing for the continue bit.
2226  *
2227  * @param cxn Pointer to the connection object.
2228  * @param hdr DMA memory information for the header.
2229  * @param data DMA memory information for the data.
2230  * @param data_len Length of the data received.
2231  * @param status Passes and returns the login status.
2232  * @param status_detail Passes and returns the login detailed status.
2233  * @param recv_ptr Returns the pointer to the receive data.
2234  * @param recv_len Returns the length of the received data.
2235  * @param resp_ptr Returns the pointer to the send payload.
2236  * @param resp_size Returns the size of the send payload.
2237  *
2238  * @return Pointer to the cbit object added.
2239  */
2240 static ocs_cxn_q_cbit_t *
2242  ocs_hal_rq_buffer_t *hdr,
2243  ocs_hal_rq_buffer_t *data,
2244  uint32_t data_len,
2245  uint8_t *status,
2246  uint8_t *status_detail,
2247  char **recv_ptr,
2248  uint32_t *recv_len,
2249  char **resp_ptr,
2250  uint32_t *resp_size)
2251 {
2252  ocs_iscsi_t *iscsi = cxn->iscsi;
2254  ocs_cxn_q_cbit_t *cbit_added = NULL;
2255 
2256  /*
2257  * Make sure that if we set the C bit, then no payload was received.
2258  */
2259  if (cxn->cbit_rsp_offset != 0 &&
2260  (data_len != 0 ||
2261  pi->c == 1)) {
2262  *status = LOGIN_STATUS_INI_ERROR;
2263  *status_detail = LOGIN_STATUS_DETAIL_INI_MISC;
2264  }
2265 
2266  /*
2267  * For continued parameter negotiations, we have to queue this buffer
2268  * until the entire message is received.
2269  */
2270  if (*status == LOGIN_STATUS_SUCCESS &&
2271  pi->c == 1) {
2272  cbit_added = ocs_malloc(cxn->ocs, sizeof(ocs_cxn_q_cbit_t), OCS_M_ZERO | OCS_M_NOWAIT);
2273  if (cbit_added == NULL) {
2274  ocs_log_test(iscsi->os, "Failed to allocate cbit object\n");
2275  *status = LOGIN_STATUS_TGT_ERROR;
2276  *status_detail = LOGIN_STATUS_DETAIL_TGT_MISC;
2277  } else if (data != NULL) {
2278  cbit_added->hdr = hdr;
2279  cbit_added->data = data;
2280  cbit_added->data_len = data_len;
2281  ocs_node_lock(cxn);
2282  ocs_list_add_tail(&cxn->cbit_list, cbit_added);
2283  ocs_node_unlock(cxn);
2284  }
2285  }
2286 
2287  /*
2288  * Handle the case where we have to put all the C bit buffers together
2289  * and the simple single buffer case.
2290  */
2291  if (*status == LOGIN_STATUS_SUCCESS &&
2292  pi->c == 0 &&
2293  cxn->cbit_rsp_offset == 0) {
2294  if (ocs_list_empty(&cxn->cbit_list)) {
2295  *recv_ptr = (data == NULL ? NULL : data->dma.virt);
2296  *recv_len = data_len;
2297  *resp_ptr = cxn->login_data_mem.virt;
2298  *resp_size = cxn->login_data_mem.size;
2299  } else {
2300  ocs_cxn_q_cbit_t *cbit;
2301 
2302  ocs_node_lock(cxn);
2303  /* Calculate the total size */
2304  cxn->cbit_recv_len = data_len;
2305  ocs_list_foreach(&cxn->cbit_list, cbit) {
2306  cxn->cbit_recv_len += cbit->data_len;
2307  }
2308 
2309  /* Allocate a single buffer to hold everything */
2310  cxn->cbit_recv = ocs_malloc(cxn->ocs, cxn->cbit_recv_len, OCS_M_ZERO | OCS_M_NOWAIT);
2311  cxn->cbit_rsp_alloc_size = cxn->cbit_recv_len + 1024;
2312  cxn->cbit_rsp = ocs_malloc(cxn->ocs, cxn->cbit_rsp_alloc_size, OCS_M_ZERO | OCS_M_NOWAIT);
2313  if (cxn->cbit_recv == NULL ||
2314  cxn->cbit_rsp == NULL) {
2315  ocs_log_err(iscsi->os, "Failed to allocate cbit buffers\n");
2316  *status = LOGIN_STATUS_TGT_ERROR;
2317  *status_detail = LOGIN_STATUS_DETAIL_TGT_MISC;
2319  } else {
2320  uint32_t offset = 0;
2321 
2322  /* Put all the c bit buffers together */
2323  ocs_list_foreach(&cxn->cbit_list, cbit) {
2324  ocs_memcpy(&cxn->cbit_recv[offset],
2325  cbit->data->dma.virt,
2326  cbit->data_len);
2327  offset += cbit->data_len;
2328  }
2329  ocs_memcpy(&cxn->cbit_recv[offset],
2330  data->dma.virt,
2331  data_len);
2332 
2333  cxn->cbit_rsp_len = 0;
2334  cxn->cbit_rsp_offset = 0;
2335  *recv_ptr = cxn->cbit_recv;
2336  *recv_len = cxn->cbit_recv_len;
2337  *resp_ptr = cxn->cbit_rsp;
2338  *resp_size = cxn->cbit_rsp_alloc_size;
2339  }
2340  ocs_node_unlock(cxn);
2341  }
2342  }
2343  return cbit_added;
2344 }
2345 
2346 /**
2347  * @ingroup login
2348  * @brief Copies the appropriate send data from the c bit processing.
2349  *
2350  * @param cxn Pointer to the connection object.
2351  * @param status Passes the login status.
2352  * @param len Passes and returns the length of the payload.
2353  */
2354 static void
2356  uint8_t status,
2357  uint32_t *len)
2358 {
2359  iscsi_login_response_hdr_t *po = (iscsi_login_response_hdr_t*)cxn->login_hdr_mem.virt;
2360 
2361  /* Save the response length */
2362  if (cxn->cbit_rsp_offset == 0) {
2363  cxn->cbit_rsp_len = *len;
2364  }
2365 
2366  /* Calculate the amount of data to send. Do not exceed 8K */
2367  if (cxn->cbit_rsp_len - cxn->cbit_rsp_offset > 8192) {
2368  *len = 8192;
2369  po->c = 1;
2370  } else {
2371  *len = cxn->cbit_rsp_len - cxn->cbit_rsp_offset;
2372  }
2373 
2374  /* set the data in the standard place */
2375  ocs_memcpy(cxn->login_data_mem.virt,
2376  &cxn->cbit_rsp[cxn->cbit_rsp_offset],
2377  *len);
2378 }
2379 
2380 /**
2381  * @ingroup login
2382  * @brief Backs out the adding of a cbit object on this connection.
2383  *
2384  * @param cxn Pointer to the connection object.
2385  * @param cbit Pointer to the C bit object that was added.
2386  */
2387 static void
2388 ocs_iscsi_cbit_backout(ocs_cxn_t *cxn,
2389  ocs_cxn_q_cbit_t *cbit)
2390 {
2391  if (cbit != NULL) {
2392  ocs_node_lock(cxn);
2393  ocs_list_remove(&cxn->cbit_list, cbit);
2394  ocs_node_unlock(cxn);
2395 
2396  ocs_free(cxn->ocs, cbit, sizeof(*cbit));
2397  }
2398 }
2399 
2400 
2401 /**
2402  * @ingroup login
2403  * @brief Sends the login parameters to the firmware.
2404  *
2405  * @param cxn Pointer to the connection object.
2406  *
2407  * @return Returns 0 on success.
2408  */
2409 void
2410 ocs_iscsi_cbit_cleanup(ocs_cxn_t *cxn)
2411 {
2412  ocs_iscsi_t *iscsi = cxn->iscsi;
2413  ocs_cxn_q_cbit_t *cbit;
2414 
2415  ocs_node_lock(cxn);
2416  if (cxn->cbit_recv != NULL) {
2417  ocs_free(cxn->ocs, cxn->cbit_recv, cxn->cbit_recv_len);
2418  cxn->cbit_recv = NULL;
2419  }
2420 
2421  if (cxn->cbit_rsp != NULL) {
2422  ocs_free(cxn->ocs, cxn->cbit_rsp, cxn->cbit_rsp_alloc_size);
2423  cxn->cbit_rsp = NULL;
2424  }
2425 
2426  cbit = ocs_list_get_head(&cxn->cbit_list);
2427  while (cbit != NULL) {
2428  ocs_list_remove_head(&cxn->cbit_list);
2429  ocs_iscsi_rx_buffers_free(iscsi, cbit->hdr, cbit->data);
2430  ocs_free(cxn->ocs, cbit, sizeof(*cbit));
2431  cbit = ocs_list_get_head(&cxn->cbit_list);
2432  }
2433  ocs_node_unlock(cxn);
2434 }
2435 
2436 
2437 /**
2438  * @ingroup login
2439  * @brief Function to process a login PDU on a target.
2440  *
2441  * @param cxn Pointer to the connection object.
2442  * @param hdr DMA memory information for the header.
2443  * @param hdr_len Length of the header received.
2444  * @param data DMA memory information for the data.
2445  * @param data_len Length of the data received.
2446  *
2447  * @return Returns 0 on success.
2448  */
2450 ocs_iscsi_recv_login(ocs_cxn_t *cxn,
2451  ocs_hal_rq_buffer_t *hdr,
2452  uint32_t hdr_len,
2453  ocs_hal_rq_buffer_t *data,
2454  uint32_t data_len)
2455 {
2456  ocs_t *ocs = cxn->ocs;
2457  ocs_iscsi_t *iscsi = cxn->iscsi;
2458  ocs_session_t *session = NULL;
2459  char * recv_ptr = NULL;
2460  uint32_t recv_len;
2461  char * resp_ptr = NULL;
2462  uint32_t resp_size;
2465  ocs_hal_io_t *hal_io;
2466  ocs_hal_io_param_t iparam;
2467  uint32_t len = 0;
2468  uint8_t status = LOGIN_STATUS_SUCCESS;
2469  uint8_t status_detail = 0;
2470  uint64_t lgn_parms_sent = cxn->lgn_parms_sent;
2471  uint64_t lgn_parms_recv = cxn->lgn_parms_recv;
2472  uint32_t skip;
2473  ocs_cxn_q_cbit_t *cbit_added = NULL;
2474 
2475  if (cxn->cxn_state != CONN_STATE_NEW_CONN &&
2476  cxn->cxn_state != CONN_STATE_LOGIN_PROGRESS) {
2477  ocs_log_test(iscsi->os, "called with connection state %d",
2478  cxn->cxn_state);
2479  ocs_cxn_close(cxn, TRUE);
2481  }
2482 
2483  hal_io = ocs_hal_io_alloc(iscsi->hal);
2484  if (hal_io == NULL) {
2485  return OCS_PDU_RTN_NO_RESOURCES;
2486  }
2487 
2488  /*
2489  * Allocate memory to hold the login response
2490  */
2491  if (ocs_iscsi_login_buffer_get(cxn)) {
2492  ocs_hal_io_free(iscsi->hal, hal_io);
2493  return OCS_PDU_RTN_NO_RESOURCES;
2494  }
2495  po = (iscsi_login_response_hdr_t*)cxn->login_hdr_mem.virt;
2496  ocs_memset(po, 0, sizeof (iscsi_login_response_hdr_t));
2497 
2498  ocs_log_info(iscsi->os,
2499  "CXN handle 0x%x state %d received csg %u nsg %u t %u c %u",
2500  cxn->conn_hdl, cxn->cxn_state, pi->csg, pi->nsg, pi->t, pi->c);
2501 
2502  /*
2503  * These will be overwritten below on transition to FFP
2504  */
2505  po->t = pi->t;
2506 
2507  /* Validate the initiator sent NSG value */
2508  if (pi->t == 1) {
2509  /* Tgt NSG cannot be bigger than offered by the initiator. */
2510  if (pi->csg == LOGIN_STAGE_NEGOTIATE_SECURITY) {
2511  /* Check if target supports negotiate security phase */
2512  if (!ocs->require_chap) {
2513  ocs_log_err(ocs, "Error! Target is not configured "
2514  "for initiator authentication\n");
2515  status = LOGIN_STATUS_INI_ERROR;
2517  } else if (pi->nsg == LOGIN_STAGE_NEGOTIATE_OPERATIONAL ||
2518  pi->nsg == LOGIN_STAGE_FULL_FEATURE) {
2520  } else {
2521  status = LOGIN_STATUS_INI_ERROR;
2522  status_detail = LOGIN_STATUS_DETAIL_INI_MISC;
2523  }
2524  } else if (pi->csg == LOGIN_STAGE_NEGOTIATE_OPERATIONAL) {
2525  /*
2526  * New cxn is expected to begin with CSG = NEGOTIATE_SECURITY if
2527  * the target is configured to negotiate security phase.
2528  */
2529  if (ocs->require_chap && (cxn->cxn_state == CONN_STATE_NEW_CONN)) {
2530  ocs_log_err(ocs, "Error! Target requires initiator authentication\n");
2531  status = LOGIN_STATUS_INI_ERROR;
2533  } else if (pi->nsg == LOGIN_STAGE_FULL_FEATURE) {
2534  po->nsg = LOGIN_STAGE_FULL_FEATURE;
2535  } else {
2536  status = LOGIN_STATUS_INI_ERROR;
2537  status_detail = LOGIN_STATUS_DETAIL_INI_MISC;
2538  }
2539  } else{
2540  status = LOGIN_STATUS_INI_ERROR;
2541  status_detail = LOGIN_STATUS_DETAIL_INI_MISC;
2542  }
2543  } else {
2544  po->nsg = 0;
2545  }
2546 
2547  /*
2548  * Verify the iSCSI version
2549  */
2550  if (pi->version_min != ISCSI_VERSION_MIN ||
2551  pi->version_max != ISCSI_VERSION_MAX) {
2552  ocs_log_test(iscsi->os, "Invalid iSCSI version\n");
2553  status = LOGIN_STATUS_INI_ERROR;
2555  }
2556 
2557  cbit_added = ocs_iscsi_cbit_pdu_setup(cxn, hdr, data, data_len,
2558  &status, &status_detail,
2559  &recv_ptr, &recv_len,
2560  &resp_ptr, &resp_size);
2561 
2562  /*
2563  * If c = 0, then the process the login, otherwise, wait for all the
2564  * login data to be received.
2565  */
2566  if (pi->c == 0 &&
2567  cxn->cbit_rsp_offset == 0) {
2568  /*
2569  * Do some initial checking if this is a brand new login
2570  */
2571  if (status == LOGIN_STATUS_SUCCESS &&
2572  cxn->cxn_state == CONN_STATE_NEW_CONN) {
2574  pi,
2575  &status,
2576  &status_detail,
2577  recv_ptr,
2578  recv_len);
2579 
2580  if (ocs_is_target_enabled()) {
2581  /* Call this here, so the target has access to the initiator name */
2582  ocs_scsi_new_initiator((ocs_node_t *) cxn);
2583  }
2584  }
2585  session = cxn->session;
2586 
2587  /* negotiate parameters if there are no errors so far */
2588  if (status == LOGIN_STATUS_SUCCESS) {
2589  len = ocs_iscsi_login_negotiate(cxn,
2590  pi->csg,
2591  &status,
2592  &status_detail,
2593  recv_ptr,
2594  recv_len,
2595  resp_ptr,
2596  resp_size);
2597  }
2598 
2599  /* Now negotiate any new keys we want */
2600  if (status == LOGIN_STATUS_SUCCESS) {
2601  uint32_t index;
2602  uint32_t skip;
2603 
2604  if (pi->csg == LOGIN_STAGE_NEGOTIATE_SECURITY) {
2605  skip = ocs_iscsi_login_send_key(cxn,
2607  resp_ptr + len,
2608  resp_size - len);
2609  len += skip;
2610  }
2611 
2612  for (index = 0; index < KEY_MAX; index++) {
2613  if ((ocs_login_key_defs[index].flags & KEY_FLAG_NEGOTIATE) != 0 &&
2614  (ocs_login_key_defs[index].flags & KEY_FLAG_DEFAULT) == 0 &&
2615  (!session->is_discovery_session ||
2616  (ocs_login_key_defs[index].flags & KEY_FLAG_VALID_DISC)) &&
2617 
2618  ((cxn->is_ini_cxn &&
2619  (ocs_login_key_defs[index].flags & KEY_FLAG_SEND_INI)) ||
2620  (!cxn->is_ini_cxn &&
2621  (ocs_login_key_defs[index].flags & KEY_FLAG_SEND_TGT))) &&
2622  (cxn->lgn_parms_sent & (1l << index)) == 0 &&
2623 
2625  (ocs_login_key_defs[index].flags & KEY_FLAG_PHASE_SEC)) ||
2627  (ocs_login_key_defs[index].flags & KEY_FLAG_PHASE_OPER)))) {
2628 
2629  skip = ocs_iscsi_login_send_key(cxn,
2630  index,
2631  resp_ptr + len,
2632  resp_size - len);
2633  len += skip;
2634  /* Do not allow transition if a new key is offered */
2635  po->t = 0;
2636  }
2637  }
2638  }
2639 
2640  /*
2641  * Send the target portal group key if we have not sent it and the
2642  * target name was given and was correct.
2643  */
2644  if (status == LOGIN_STATUS_SUCCESS &&
2645  (cxn->lgn_parms_recv & (1l << KEY_TARGET_NAME)) &&
2646  !(cxn->lgn_parms_sent & (1l << KEY_TARGET_PORTAL_GROUP_TAG))) {
2647  skip = ocs_iscsi_login_send_key(cxn,
2649  resp_ptr + len,
2650  resp_size - len);
2651  len += skip;
2652  }
2653 
2654  /*
2655  * Send the target alias key if we have not sent it and this is not a
2656  * discovery session.
2657  */
2658  if (status == LOGIN_STATUS_SUCCESS &&
2659  !session->is_discovery_session &&
2660  !(cxn->lgn_parms_sent & (1l << KEY_TARGET_ALIAS))) {
2661  skip = ocs_iscsi_login_send_key(cxn,
2663  resp_ptr + len,
2664  resp_size - len);
2665  len += skip;
2666  }
2667 
2668  /* If we are doing CHAP, do the negotiation */
2669  if (status == LOGIN_STATUS_SUCCESS &&
2671  cxn->chap_state != OCS_CHAP_STATE_NOT_SELECTED) {
2673  &status,
2674  &status_detail,
2675  resp_ptr,
2676  resp_size,
2677  &len);
2678  }
2679  }
2680 
2681  session = cxn->session;
2682  /* Copy the response to the c bit processing */
2683  if (status == LOGIN_STATUS_SUCCESS &&
2684  pi->c == 0 &&
2685  !ocs_list_empty(&cxn->cbit_list)) {
2686  ocs_iscsi_cbit_fill_buffer(cxn, status, &len);
2687  }
2688 
2689  po->csg = pi->csg;
2690  po->status = status;
2691  po->status_detail = status_detail;
2692  po->opcode = ISCSI_RESP_LOGIN;
2693  po->version_active = ISCSI_VERSION_MAX;
2694  po->version_max = ISCSI_VERSION_MAX;
2695  po->isid_tsid_ptr.isid0 = pi->isid_tsid_ptr.isid0;
2696  po->isid_tsid_ptr.isid1 = pi->isid_tsid_ptr.isid1;
2697  po->isid_tsid_ptr.isid2 = pi->isid_tsid_ptr.isid2;
2698  po->stat_sn = ocs_htobe32(cxn->stat_sn++);
2699  po->exp_cmd_sn = ocs_htobe32(ocs_session_exp_cmd_sn_get(cxn));
2700  po->max_cmd_sn = ocs_htobe32(ocs_session_max_cmd_sn_get(cxn));
2701  po->itt = pi->itt;
2702 
2703  /* Clear the reserved fields if the login is rejected */
2704  if (status != LOGIN_STATUS_SUCCESS) {
2705  po->t = 0;
2706  po->c = 0;
2707  po->csg = 0;
2708  po->nsg = 0;
2709 
2710  /* no need to send payload for errors */
2711  len = 0;
2712  }
2713 
2714  ocs_iscsi_login_set_dslen(&po->dw2, len);
2715 
2716  if (status == LOGIN_STATUS_SUCCESS &&
2717  po->t == 1 &&
2718  po->nsg == LOGIN_STAGE_FULL_FEATURE) {
2719  ocs_log_debug(iscsi->os, "Cxn %s transitioning to FFP, hdr_digest=%d, data_digest=%d",
2720  cxn->display_name, cxn->hdr_digest, cxn->data_digest);
2721  cxn->max_wr_xfer_size = session->login_options.max_burst;
2722  po->isid_tsid_ptr.tsid = ocs_htobe16(ocs_session_tsih_get(cxn));
2723 
2724  if (ocs_iscsi_send_context_udpate(cxn)) {
2725  ocs_log_test(iscsi->os, "send context update failed\n");
2726  po->status = LOGIN_STATUS_TGT_ERROR;
2727  po->status_detail = LOGIN_STATUS_DETAIL_TGT_OUT_OF_RSRC;
2728  }
2729  cxn->cxn_state = CONN_STATE_FULL_FEATURE;
2730  }
2731 
2732  iparam.unassisted.set_dm = TRUE;
2733  iparam.unassisted.incr_statsn = FALSE;
2734  iparam.unassisted.is_login = TRUE;
2735  iparam.unassisted.bhs = &cxn->login_hdr_mem;
2736  iparam.unassisted.payload1 = (len > 0 ? &cxn->login_data_mem : NULL);
2737  iparam.unassisted.payload2 = NULL;
2738  if (ocs_hal_io_send(iscsi->hal,
2740  hal_io,
2741  len,
2742  &iparam,
2743  cxn,
2745  cxn)) {
2746  /* Backout and free cbit buffers */
2747  ocs_iscsi_cbit_backout(cxn, cbit_added);
2748  ocs_hal_io_free(iscsi->hal, hal_io);
2750  cxn->lgn_parms_sent = lgn_parms_sent;
2751  cxn->lgn_parms_recv = lgn_parms_recv;
2752  return OCS_PDU_RTN_NO_RESOURCES;
2753  }
2754 
2755  /* Close the connection if an error was sent to the initiator. */
2756  if (po->status != LOGIN_STATUS_SUCCESS) {
2757  cxn->cxn_state = CONN_STATE_LOGIN_FAILED;
2758  }
2759 
2760  /* Update and cleanup the cbit for this connection */
2761  if (pi->c == 0 &&
2762  !ocs_list_empty(&cxn->cbit_list)) {
2763  cxn->cbit_rsp_offset += len;
2764 
2765  if (po->status != LOGIN_STATUS_SUCCESS ||
2766  cxn->cbit_rsp_offset == cxn->cbit_rsp_len) {
2767  /* Cleanup any cbit buffers */
2769  }
2770  }
2771 
2772  return (cbit_added == NULL ? OCS_PDU_RTN_PROCESSED : OCS_PDU_RTN_CBIT_QUEUED);
2773 }
2774 
2775 /**
2776  * @ingroup login
2777  * @brief Function to queue a send login request.
2778  *
2779  * @param cxn Pointer to the connection object.
2780  * @param itt Initiator task tag.
2781  *
2782  * @return Returns 0 on success.
2783  */
2784 static int32_t
2786  uint32_t itt)
2787 {
2788  ocs_iscsi_t *iscsi = cxn->iscsi;
2789  ocs_iscsi_lgn_retry_t *lgn_retry;
2790  int32_t rc;
2791 
2792  if ((lgn_retry = ocs_iscsi_login_retry_get(iscsi)) == NULL) {
2793  ocs_log_test(iscsi->os, "No retry resources are available");
2794  ocs_cxn_close(cxn, TRUE);
2796  } else {
2798  lgn_retry->cxn = cxn;
2799  lgn_retry->itt = itt;
2801  }
2802  return rc;
2803 }
2804 
2805 
2806 /**
2807  * @brief Function to send an login Response PDU (invalid during login).
2808  *
2809  * @param cxn Pointer to the connection object.
2810  * @param itt Initiator task tag of the received PDU.
2811  *
2812  * @return Returns 0 on success.
2813  */
2814 int32_t
2816  uint32_t itt)
2817 {
2818  ocs_iscsi_t *iscsi = cxn->iscsi;
2820  ocs_hal_io_t *hal_io;
2821  ocs_hal_io_param_t iparam;
2822  uint8_t *isid_ptr;
2823  uint64_t isid;
2824  uint32_t i;
2825 
2826  if (cxn->cxn_state != CONN_STATE_LOGIN_PROGRESS) {
2827  ocs_log_test(iscsi->os, "called with connection state %d",
2828  cxn->cxn_state);
2830  }
2831 
2832  hal_io = ocs_hal_io_alloc(iscsi->hal);
2833  if (hal_io == NULL) {
2834  return OCS_PDU_RTN_NO_RESOURCES;
2835  }
2836 
2837  po = (iscsi_login_response_hdr_t*)cxn->login_hdr_mem.virt;
2838  ocs_memset(po, 0, sizeof (iscsi_login_response_hdr_t));
2841  po->opcode = ISCSI_RESP_LOGIN;
2844  po->itt = ocs_htobe32(itt);
2845  po->stat_sn = ocs_htobe32(cxn->stat_sn);
2846  po->exp_cmd_sn = ocs_htobe32(ocs_session_exp_cmd_sn_get(cxn));
2847  po->max_cmd_sn = ocs_htobe32(ocs_session_max_cmd_sn_get(cxn));
2848 
2849  /* Convert the isid to big endian */
2850  isid_ptr = (uint8_t*)&po->isid_tsid_ptr.isid0;
2851  isid = ocs_session_isid_get(cxn);
2852  for (i = 0; i < 6; i++) {
2853  isid_ptr[i] = (isid >> (48 - ((i+1)*8))) & 0xff;
2854  }
2855 
2856  ocs_iscsi_login_set_dslen(&po->dw2, 0);
2857 
2858  iparam.unassisted.set_dm = TRUE;
2859  iparam.unassisted.incr_statsn = FALSE;
2860  iparam.unassisted.is_login = TRUE;
2861  iparam.unassisted.bhs = &cxn->login_hdr_mem;
2862  iparam.unassisted.payload1 = NULL;
2863  iparam.unassisted.payload2 = NULL;
2864  if (ocs_hal_io_send(iscsi->hal,
2866  hal_io,
2867  0,
2868  &iparam,
2869  cxn,
2871  cxn)) {
2872  ocs_hal_io_free(iscsi->hal, hal_io);
2874  }
2875  cxn->stat_sn++;
2876  return 0;
2877 }
2878 
2879 
2880 /**
2881  * @ingroup login
2882  * @brief Function to process a login response PDU.
2883  *
2884  * @param cxn Pointer to the connection object.
2885  * @param hdr DMA memory information for the header.
2886  * @param hdr_len Length of the header received.
2887  * @param data DMA memory information for the data.
2888  * @param data_len Length of the data received.
2889  *
2890  * @return Returns 0 on success.
2891  */
2892 int32_t
2894  ocs_hal_rq_buffer_t *hdr,
2895  uint32_t hdr_len,
2896  ocs_hal_rq_buffer_t *data,
2897  uint32_t data_len)
2898 {
2899  ocs_iscsi_t *iscsi = cxn->iscsi;
2900  ocs_session_t *session = cxn->session;
2901  char * recv_ptr;
2902  uint32_t recv_len;
2903  char * resp_ptr = NULL;
2904  uint32_t resp_size;
2907  ocs_hal_io_t *hal_io;
2908  ocs_hal_io_param_t iparam;
2909  uint32_t len = 0;
2910  uint8_t status = LOGIN_STATUS_SUCCESS;
2911  uint8_t status_detail = 0;
2912  uint64_t lgn_parms_sent = cxn->lgn_parms_sent;
2913  uint64_t lgn_parms_recv = cxn->lgn_parms_recv;
2914  ocs_cxn_q_cbit_t *cbit_added = NULL;
2915 
2916  if (cxn->cxn_state != CONN_STATE_NEW_CONN &&
2917  cxn->cxn_state != CONN_STATE_LOGIN_PROGRESS) {
2918  ocs_log_test(iscsi->os, "called with connection state %d",
2919  cxn->cxn_state);
2920  ocs_cxn_close(cxn, TRUE);
2921  return -1;
2922  }
2923 
2924  /* Check the status and bail if there is an error */
2925  if (pi->status != LOGIN_STATUS_SUCCESS) {
2926  ocs_log_test(iscsi->os, "Target returned error status 0x%x, detail 0x%x",
2927  pi->status, pi->status_detail);
2928  cxn->cxn_state = CONN_STATE_LOGIN_FAILED;
2929  ocs_cxn_close(cxn, FALSE);
2930  return -1;
2931  }
2932 
2933  hal_io = ocs_hal_io_alloc(iscsi->hal);
2934  if (hal_io == NULL) {
2935  return OCS_PDU_RTN_NO_RESOURCES;
2936  }
2937 
2938  /*
2939  * Allocate memory to hold the login payload
2940  */
2941  if (ocs_iscsi_login_buffer_get(cxn)) {
2942  ocs_hal_io_free(iscsi->hal, hal_io);
2943  return ocs_iscsi_recv_common_queue(cxn, OCS_RETRY_REQ_RECV_LOGIN_RSP, hdr, hdr_len, data, data_len);
2944  }
2945 
2946  po = (iscsi_login_cmd_hdr_t*)cxn->login_hdr_mem.virt;
2947  ocs_memset(po, 0, sizeof (iscsi_login_cmd_hdr_t));
2948  po->t = 1;
2949  if (pi->t == 1) {
2950  po->csg = pi->nsg;
2951  if (po->csg == LOGIN_STAGE_NEGOTIATE_SECURITY) {
2953  } else {
2954  po->nsg = LOGIN_STAGE_FULL_FEATURE;
2955  }
2956  } else {
2957  po->csg = pi->csg;
2958  po->nsg = pi->nsg;
2959  }
2960 
2961  ocs_log_debug(iscsi->os, "received csg %u nsg %u t %u c %u",
2962  pi->csg, pi->nsg, pi->t, pi->c);
2963 
2964 
2965  cbit_added = ocs_iscsi_cbit_pdu_setup(cxn, hdr, data, data_len,
2966  &status, &status_detail,
2967  &recv_ptr, &recv_len,
2968  &resp_ptr, &resp_size);
2969 
2970  /*
2971  * If c = 0, then the process the login, otherwise, wait for all the
2972  * login data to be received.
2973  */
2974  if (pi->c == 0 &&
2975  cxn->cbit_rsp_offset == 0) {
2976  /* negotiate parameters if there are no errors so far */
2977  if (status == LOGIN_STATUS_SUCCESS) {
2978  len = ocs_iscsi_login_negotiate(cxn,
2979  pi->csg,
2980  &status,
2981  &status_detail,
2982  recv_ptr,
2983  recv_len,
2984  resp_ptr,
2985  resp_size);
2986  }
2987 
2988  /* Now negotiate any new keys we want */
2989  if (status == LOGIN_STATUS_SUCCESS) {
2990  uint32_t index;
2991  uint32_t skip;
2992 
2993  for (index = 0; index < KEY_MAX; index++) {
2994  if ((ocs_login_key_defs[index].flags & KEY_FLAG_NEGOTIATE) != 0 &&
2995  (ocs_login_key_defs[index].flags & KEY_FLAG_DEFAULT) == 0 &&
2996  (!session->is_discovery_session ||
2997  (ocs_login_key_defs[index].flags & KEY_FLAG_VALID_DISC)) &&
2998 
2999  ((cxn->is_ini_cxn &&
3000  (ocs_login_key_defs[index].flags & KEY_FLAG_SEND_INI)) ||
3001  (!cxn->is_ini_cxn &&
3002  (ocs_login_key_defs[index].flags & KEY_FLAG_SEND_TGT))) &&
3003  (cxn->lgn_parms_sent & (1l << index)) == 0 &&
3004  ((po->csg == LOGIN_STAGE_NEGOTIATE_SECURITY &&
3005  (ocs_login_key_defs[index].flags & KEY_FLAG_PHASE_SEC)) ||
3006  (po->csg == LOGIN_STAGE_NEGOTIATE_OPERATIONAL &&
3007  (ocs_login_key_defs[index].flags & KEY_FLAG_PHASE_OPER)) ||
3008  (po->csg == LOGIN_STAGE_FULL_FEATURE &&
3009  (ocs_login_key_defs[index].flags & KEY_FLAG_PHASE_FFP)))) {
3010  skip = ocs_iscsi_login_send_key(cxn,
3011  index,
3012  resp_ptr + len,
3013  resp_size - len);
3014  len += skip;
3015  }
3016  }
3017  }
3018 
3019  /* If we are doing CHAP, do the negotiation */
3020  if (pi->csg == LOGIN_STAGE_NEGOTIATE_SECURITY &&
3021  cxn->chap_state != OCS_CHAP_STATE_NOT_SELECTED) {
3023  &status,
3024  &status_detail,
3025  resp_ptr,
3026  resp_size,
3027  &len);
3028  }
3029  }
3030 
3031  /* Only set the statSn value on the first login response */
3032  if (cxn->is_first_login_rsp) {
3033  cxn->is_first_login_rsp = 0;
3034  cxn->stat_sn = ocs_be32toh(pi->stat_sn);
3035  cxn->stat_sn++;
3036  } else {
3037  if (ocs_be32toh(pi->stat_sn) != cxn->stat_sn) {
3038  ocs_log_test(iscsi->os,
3039  "Expected stat_sn %d, but recv %d",
3040  cxn->stat_sn, ocs_be32toh(pi->stat_sn));
3041  }
3042  cxn->stat_sn++;
3043  }
3044 
3045  /* Copy the response to the c bit processing */
3046  if (status == LOGIN_STATUS_SUCCESS &&
3047  pi->c == 0 &&
3048  !ocs_list_empty(&cxn->cbit_list)) {
3049  ocs_iscsi_cbit_fill_buffer(cxn, status, &len);
3050  }
3051 
3052  po->opcode = ISCSI_CMD_LOGIN;
3053  po->immediate = 1;
3054  po->version_min = ISCSI_VERSION_MAX;
3055  po->version_max = ISCSI_VERSION_MAX;
3056  po->isid_tsid_ptr.isid0 = pi->isid_tsid_ptr.isid0;
3057  po->isid_tsid_ptr.isid1 = pi->isid_tsid_ptr.isid1;
3058  po->isid_tsid_ptr.isid2 = pi->isid_tsid_ptr.isid2;
3059  po->itt = ocs_htobe32(cxn->wq_index);
3060  po->cid = ocs_htobe16(cxn->cid);
3061  po->cmd_sn = ocs_htobe32(ocs_session_cmd_sn_get(cxn, 0));
3062  po->exp_stat_sn = ocs_htobe32(cxn->stat_sn);
3063 
3064  ocs_iscsi_login_set_dslen(&po->dw2, len);
3065 
3066  /* Check the status and bail if there is an error */
3067  if (status != LOGIN_STATUS_SUCCESS) {
3068  ocs_log_test(iscsi->os, "bad internal status, bailing");
3069  ocs_iscsi_cbit_backout(cxn, cbit_added);
3070  ocs_hal_io_free(iscsi->hal, hal_io);
3072  ocs_cxn_close(cxn, FALSE);
3073  return -1;
3074  }
3075 
3076  if (status == LOGIN_STATUS_SUCCESS &&
3077  pi->t == 1 &&
3078  pi->nsg == LOGIN_STAGE_FULL_FEATURE) {
3079  ocs_log_debug(iscsi->os, "Cxn %s transitioning to FFP, hdr_digest=%d, data_digest=%d",
3080  cxn->display_name, cxn->hdr_digest, cxn->data_digest);
3081  ocs_session_tsih_set(cxn, ocs_be16toh(pi->isid_tsid_ptr.tsid));
3082 
3083  /* Set the comamnd window */
3084  ocs_session_exp_cmd_sn_set(cxn, ocs_be32toh(pi->exp_cmd_sn));
3085  ocs_session_max_cmd_sn_set(cxn, ocs_be32toh(pi->max_cmd_sn));
3086  cxn->max_wr_xfer_size = session->login_options.max_burst;
3088 
3089  if (ocs_iscsi_send_context_udpate(cxn)) {
3090  ocs_log_test(iscsi->os, "send context update failed\n");
3091  status = LOGIN_STATUS_TGT_ERROR;
3092  }
3093  cxn->cxn_state = CONN_STATE_FULL_FEATURE;
3094  ocs_hal_io_free(iscsi->hal, hal_io);
3096  } else {
3097  iparam.unassisted.set_dm = TRUE;
3098  iparam.unassisted.incr_statsn = FALSE;
3099  iparam.unassisted.is_login = TRUE;
3100  iparam.unassisted.bhs = &cxn->login_hdr_mem;
3101  iparam.unassisted.payload1 = (len > 0 ? &cxn->login_data_mem : NULL);
3102  iparam.unassisted.payload2 = NULL;
3103  if (ocs_hal_io_send(iscsi->hal,
3105  hal_io,
3106  len,
3107  &iparam,
3108  cxn,
3110  cxn)) {
3111  ocs_iscsi_cbit_backout(cxn, cbit_added);
3112  ocs_hal_io_free(iscsi->hal, hal_io);
3114  cxn->lgn_parms_sent = lgn_parms_sent;
3115  cxn->lgn_parms_recv = lgn_parms_recv;
3116  return ocs_iscsi_recv_common_queue(cxn, OCS_RETRY_REQ_RECV_LOGIN_RSP, hdr, hdr_len, data, data_len);
3117  }
3118  }
3119 
3120  /* Update and cleanup the cbit for this connection */
3121  if (pi->c == 0 &&
3122  !ocs_list_empty(&cxn->cbit_list)) {
3123  cxn->cbit_rsp_offset += len;
3124 
3125  if (status != LOGIN_STATUS_SUCCESS ||
3126  cxn->cbit_rsp_offset == cxn->cbit_rsp_len) {
3127  /* Cleanup any cbit buffers */
3129  }
3130  }
3131 
3132  return (cbit_added == NULL ? 0 : OCS_LOGIN_REQUEST_QUEUED);
3133 }
3134 
3135 
3136 /**
3137  * @ingroup login
3138  * @brief Function to queue a send login request.
3139  *
3140  * @param cxn Pointer to the connection object.
3141  * @param is_discovery TRUE for a discovery session.
3142  * @param tgt_name Target name for a normal session.
3143  *
3144  * @return Returns 0 on success.
3145  */
3146 static int32_t
3148  bool is_discovery,
3149  char *tgt_name)
3150 {
3151  ocs_iscsi_t *iscsi = cxn->iscsi;
3152  ocs_iscsi_lgn_retry_t *lgn_retry;
3153  int32_t rc;
3154 
3155  if ((lgn_retry = ocs_iscsi_login_retry_get(iscsi)) == NULL) {
3156  ocs_log_test(iscsi->os, "No retry resources are available");
3157  ocs_cxn_close(cxn, TRUE);
3159  } else if (ocs_strlen(tgt_name) + 1 > ARRAY_SIZE(lgn_retry->virt_buffer)) {
3160  ocs_iscsi_login_retry_free(iscsi, lgn_retry);
3162  } else {
3163  lgn_retry->type = OCS_RETRY_REQ_SEND_LOGIN;
3164  lgn_retry->cxn = cxn;
3165  lgn_retry->is_discovery = is_discovery;
3166  ocs_strcpy(lgn_retry->virt_buffer, tgt_name);
3168  }
3169  return rc;
3170 }
3171 
3172 /**
3173  * @brief Function to send an initial login PDU.
3174  *
3175  * @param cxn Pointer to the connection object.
3176  * @param is_discovery TRUE for a discovery session.
3177  * @param tgt_name Target name for a normal session.
3178  *
3179  * @return Returns 0 on success.
3180  */
3181 int32_t
3182 ocs_iscsi_send_login(ocs_cxn_t *cxn,
3183  bool is_discovery,
3184  char *tgt_name)
3185 {
3186  ocs_iscsi_t *iscsi = cxn->iscsi;
3187  ocs_session_t *session = cxn->session;
3189  ocs_hal_io_t *hal_io;
3190  ocs_hal_io_param_t iparam;
3191  uint32_t len = 0;
3192  uint32_t index;
3193  uint32_t skip;
3194  uint64_t lgn_parms_sent = cxn->lgn_parms_sent;
3195  uint64_t lgn_parms_recv = cxn->lgn_parms_recv;
3196  uint8_t *isid_ptr;
3197  uint64_t isid;
3198  uint32_t i;
3199 
3200  if (cxn->cxn_state != CONN_STATE_NEW_CONN &&
3201  cxn->cxn_state != CONN_STATE_LOGIN_PROGRESS) {
3202  ocs_log_test(iscsi->os, "called with connection state %d", cxn->cxn_state);
3203  ocs_cxn_close(cxn, TRUE);
3205  }
3206 
3207  hal_io = ocs_hal_io_alloc(iscsi->hal);
3208  if (hal_io == NULL) {
3209  return OCS_PDU_RTN_NO_RESOURCES;
3210  }
3211 
3212  /*
3213  * Allocate memory to hold the login payload
3214  */
3215  if (ocs_iscsi_login_buffer_get(cxn)) {
3216  ocs_hal_io_free(iscsi->hal, hal_io);
3217  return ocs_iscsi_send_login_queue(cxn, is_discovery, tgt_name);
3218  }
3219 
3220  po = (iscsi_login_cmd_hdr_t*)cxn->login_hdr_mem.virt;
3221  ocs_memset(po, 0, sizeof (iscsi_login_cmd_hdr_t));
3222  po->t = 1;
3223 
3224  session->is_discovery_session = is_discovery;
3225  cxn->cid = cxn->wq_index;
3226  if (is_discovery) {
3229  skip = ocs_snprintf(((char *)cxn->login_data_mem.virt) + len,
3231  "%s=%s",
3232  ocs_login_key_defs[KEY_SESSION_TYPE].key_name,
3233  "Discovery") + 1;
3234  len += skip;
3235  } else {
3238  skip = ocs_snprintf(((char *)cxn->login_data_mem.virt) + len,
3240  "%s=%s",
3241  ocs_login_key_defs[KEY_SESSION_TYPE].key_name,
3242  "Normal") + 1;
3243  len += skip;
3244  }
3245 
3246  skip = ocs_snprintf(((char *)cxn->login_data_mem.virt) + len,
3248  "%s=%s",
3249  ocs_login_key_defs[KEY_INITIATOR_NAME].key_name,
3250  ocs_iscsi_ini_get_name(cxn->ocs)) + 1;
3251  len += skip;
3252 
3253  /*
3254  * Send the initiator alias key if this is not a discovery session.
3255  */
3256  if (!is_discovery) {
3257  skip = ocs_iscsi_login_send_key(cxn,
3259  ((char *)cxn->login_data_mem.virt) + len,
3261  len += skip;
3262  }
3263 
3264 
3265  if (!is_discovery) {
3266  skip = ocs_snprintf(((char *)cxn->login_data_mem.virt) + len,
3268  "%s=%s",
3269  ocs_login_key_defs[KEY_TARGET_NAME].key_name,
3270  tgt_name) + 1;
3271  len += skip;
3272 
3273  /* Add the authmethod key */
3274  skip = ocs_iscsi_login_send_key(cxn,
3276  ((char *)cxn->login_data_mem.virt) + len,
3278  len += skip;
3279  }
3280 
3281  /* Now negotiate any new keys we want */
3282  for (index = 0; index < KEY_MAX; index++) {
3283  if ((ocs_login_key_defs[index].flags & KEY_FLAG_NEGOTIATE) != 0 &&
3284  (!is_discovery ||
3285  (ocs_login_key_defs[index].flags & KEY_FLAG_VALID_DISC)) &&
3286 
3287  ((cxn->is_ini_cxn &&
3288  (ocs_login_key_defs[index].flags & KEY_FLAG_SEND_INI)) ||
3289  (!cxn->is_ini_cxn &&
3290  (ocs_login_key_defs[index].flags & KEY_FLAG_SEND_TGT))) &&
3291  (cxn->lgn_parms_sent & (1l << index)) == 0 &&
3293  (ocs_login_key_defs[index].flags & KEY_FLAG_PHASE_SEC)) ||
3295  (ocs_login_key_defs[index].flags & KEY_FLAG_PHASE_OPER)))) {
3296  skip = ocs_iscsi_login_send_key(cxn,
3297  index,
3298  ((char *)cxn->login_data_mem.virt) + len,
3300  len += skip;
3301  }
3302  }
3303 
3304  po->opcode = ISCSI_CMD_LOGIN;
3305  po->immediate = 1;
3308  po->itt = ocs_htobe32(cxn->wq_index);
3309  po->cid = ocs_htobe16(cxn->cid);
3310  po->cmd_sn = ocs_htobe32(ocs_session_cmd_sn_get(cxn, 0));
3311  po->exp_stat_sn = ocs_htobe32(cxn->stat_sn);
3312 
3313  /* Convert the isid to big endian */
3314  isid_ptr = (uint8_t*)&po->isid_tsid_ptr.isid0;
3315  isid = ocs_session_isid_get(cxn);
3316  for (i = 0; i < 6; i++) {
3317  isid_ptr[i] = (isid >> (48 - ((i+1)*8))) & 0xff;
3318  }
3319 
3320  ocs_iscsi_login_set_dslen(&po->dw2, len);
3321 
3322  iparam.unassisted.set_dm = TRUE;
3323  iparam.unassisted.incr_statsn = FALSE;
3324  iparam.unassisted.is_login = TRUE;
3325  iparam.unassisted.bhs = &cxn->login_hdr_mem;
3326  iparam.unassisted.payload1 = (len > 0 ? &cxn->login_data_mem : NULL);
3327  iparam.unassisted.payload2 = NULL;
3328  if (ocs_hal_io_send(iscsi->hal,
3330  hal_io,
3331  len,
3332  &iparam,
3333  cxn,
3335  cxn)) {
3336  ocs_hal_io_free(iscsi->hal, hal_io);
3338  cxn->lgn_parms_sent = lgn_parms_sent;
3339  cxn->lgn_parms_recv = lgn_parms_recv;
3340  return ocs_iscsi_send_login_queue(cxn, is_discovery, tgt_name);
3341  }
3342  cxn->cxn_state = CONN_STATE_LOGIN_PROGRESS;
3343  return 0;
3344 }
3345 
3346 /**
3347  * @brief Add iSCSI cluster target name and address
3348  *
3349  * @param cxn Pointer to the connection object.
3350  * @param resp_ptr Pointer to the start of the response buffer.
3351  * @param resp_size Size of the response buffer.
3352  * @param plen_orig Payload length added so far.
3353  *
3354  * @return Returns the number of bytes added to the payload.
3355  */
3356 uint32_t
3357 ocs_iscsi_add_cluster_tgt_keys(ocs_cxn_t *cxn, char *resp_ptr,
3358  uint32_t resp_size, uint32_t plen_orig)
3359 {
3360  ocs_t *ocs = cxn->ocs;
3361  ocs_iscsi_t *iscsi = &ocs->iscsi;
3362  uint32_t plen = plen_orig;
3363  int32_t skip;
3364  int32_t remaining_sz;
3365  int32_t key_sz;
3366  ocs_iscsi_cluster_tgt_t *ctgt = NULL;
3368 
3369  if (!ocs_atomic_read(&iscsi->clusttgt.cnt))
3370  return 0;
3371 
3372  iscsi->clusttgt.st_last = true;
3373  if (!iscsi->clusttgt.ctgt_next)
3374  ctgt = ocs_list_get_head(&iscsi->clusttgt.list);
3375  else
3376  ctgt = iscsi->clusttgt.ctgt_next;
3377  next = ctgt ? ocs_list_next(&iscsi->clusttgt.list, ctgt) : NULL;
3378  while (ctgt) {
3379  remaining_sz = resp_size - plen;
3380 
3381  key_sz = strlen(ocs_login_key_defs[KEY_TARGET_NAME].key_name);
3382  key_sz += strlen(ocs_login_key_defs[KEY_TARGET_ADDRESS].key_name);
3383  /* two bytes for '=' */
3384  key_sz += 2;
3385  key_sz += strlen(ctgt->tgt_name) + 1;
3386  key_sz += strlen(ctgt->tgt_addr) + 1;
3387  if (remaining_sz < key_sz) {
3388  ocs_log_debug(ocs, "No response buffer for more "
3389  "cluster target entries.\n");
3390  iscsi->clusttgt.ctgt_next = ctgt;
3391  iscsi->clusttgt.st_last = false;
3392  break;
3393  }
3394  skip = ocs_snprintf(resp_ptr + plen,
3395  remaining_sz,
3396  "%s=%s",
3397  ocs_login_key_defs[KEY_TARGET_NAME].key_name,
3398  ctgt->tgt_name) + 1;
3399  plen += skip;
3400 
3401  remaining_sz = resp_size - plen;
3402  skip = ocs_snprintf(resp_ptr + plen,
3403  remaining_sz,
3404  "%s=%s",
3405  ocs_login_key_defs[KEY_TARGET_ADDRESS].key_name,
3406  ctgt->tgt_addr) + 1;
3407  plen += skip;
3408 
3409  ctgt = next;
3410  next = ocs_list_next(&iscsi->clusttgt.list, ctgt);
3411  }
3412 
3413  return plen - plen_orig;
3414 }
3415 
3416 /**
3417  * @ingroup login
3418  * @brief Add targets to the sendTarget response.
3419  *
3420  * @param cxn Pointer to the connection object.
3421  * @param resp_ptr Pointer to the start of the response buffer.
3422  * @param resp_size Size of the response buffer.
3423  * @param plen_orig Payload length added so far.
3424  * @param tgt_name Target name to add.
3425  *
3426  * @return Returns the number of bytes added to the payload.
3427  */
3428 static int32_t
3429 ocs_iscsi_add_tgt_keys(ocs_cxn_t *cxn,
3430  char *resp_ptr,
3431  uint32_t resp_size,
3432  uint32_t plen_orig,
3433  char *tgt_name)
3434 {
3435  uint32_t plen = plen_orig;
3436  uint32_t skip;
3437  ocs_ip_address_t *ip;
3438  uint32_t portal_grp;
3439  uint32_t i;
3440  char ip_addr[80];
3441  char ip_addr_port[80];
3442 
3443  /* Format the target name key */
3444  skip = ocs_snprintf(resp_ptr + plen,
3445  resp_size - plen,
3446  "%s=%s",
3447  ocs_login_key_defs[KEY_TARGET_NAME].key_name,
3448  tgt_name) + 1;
3449  plen += skip;
3450 
3451  i = 0;
3452  while ((ip = ocs_iscsi_tgt_get_ip_address(cxn->ocs, tgt_name, i)) != NULL) {
3453  portal_grp = ocs_iscsi_tgt_get_portal_group(cxn->ocs, tgt_name, ip);
3454 
3455  format_ip_address(ip->ip_type, ip->ip_address, ip_addr, sizeof(ip_addr));
3456 
3457  if (ip->ip_type == OCS_IP_TYPE_V4 ||
3458  ip->ip_type == OCS_IP_TYPE_DHCP_V4) {
3459  /* Add the TCP Port and portal group to the string. */
3460  ocs_snprintf(ip_addr_port,
3461  sizeof(ip_addr_port),
3462  "%s:%d,%d",
3463  ip_addr,
3465  portal_grp);
3466  } else {
3467  /* Add braces and TCP Port and portal group to the string. */
3468  ocs_snprintf(ip_addr_port,
3469  sizeof(ip_addr_port),
3470  "[%s]:%d,%d",
3471  ip_addr,
3473  portal_grp);
3474  }
3475 
3476  /* Format the target address key */
3477  skip = ocs_snprintf(resp_ptr + plen,
3478  resp_size - plen,
3479  "%s=%s",
3480  ocs_login_key_defs[KEY_TARGET_ADDRESS].key_name,
3481  ip_addr_port) + 1;
3482  plen += skip;
3483  i++;
3484  }
3485  return plen - plen_orig;
3486 }
3487 
3488 
3489 /**
3490  * @brief This function is called to check for stalled text negotiations for a
3491  * connection on a target.
3492  *
3493  * @param arg Pointer to the connection object.
3494  */
3495 void
3497 {
3498  ocs_cxn_t *cxn = arg;
3499  ocs_session_t *session = cxn->session;
3500  iscsi_text_cmd_hdr_t *bhs = (iscsi_text_cmd_hdr_t*)cxn->text_hdr;
3501  uint32_t cmdsn = ocs_be32toh(bhs->cmd_sn);
3502  int32_t rc;
3503 
3504  if (cxn->ffp_is_neg_active) {
3505  /*
3506  * Attempt to back out the cmdSN, but this will only
3507  * work if no other commands have been received.
3508  */
3509  if (cmdsn + 1 == session->exp_cmd_sn) {
3510  session->exp_cmd_sn--;
3511  ocs_session_max_cmd_sn_upd(session);
3512  }
3513 
3514  ocs_log_test(cxn->ocs, "%s FFP Text timeout\n", cxn->display_name);
3515 
3516  /* reset the test negotiation */
3517  rc = ocs_iscsi_send_reject(cxn, cxn->text_hdr, 48,
3519  if (rc == 0 ||
3520  rc == OCS_LOGIN_REQUEST_QUEUED) {
3521  cxn->ffp_is_neg_active = FALSE;
3522  } else {
3523  /* retry again later */
3524  ocs_setup_timer(cxn->ocs, &cxn->ffp_timer,
3526  cxn,
3527  100, false);
3528  }
3529  }
3530 }
3531 
3532 /**
3533  * @ingroup login
3534  * @brief Function to process a text PDU.
3535  *
3536  * @param cxn Pointer to the connection object.
3537  * @param hdr DMA memory information for the header.
3538  * @param hdr_len Length of the header received.
3539  * @param data DMA memory information for the data.
3540  * @param data_len Length of the data received.
3541  * @param reject_reason Returns the reject reason.
3542  *
3543  * @return Returns 0 on success.
3544  */
3546 ocs_iscsi_recv_text(ocs_cxn_t *cxn,
3547  ocs_hal_rq_buffer_t *hdr,
3548  uint32_t hdr_len,
3549  ocs_hal_rq_buffer_t *data,
3550  uint32_t data_len,
3551  uint8_t *reject_reason)
3552 {
3553  ocs_iscsi_t *iscsi = cxn->iscsi;
3554  ocs_session_t *session = cxn->session;
3555  char * recv_ptr = NULL;
3556  uint32_t recv_len;
3557  char * resp_ptr = NULL;
3558  uint32_t resp_size;
3559  char *st = NULL;
3560  uint32_t plen = 0;
3561  iscsi_text_cmd_hdr_t *pi = (iscsi_text_cmd_hdr_t*)hdr->dma.virt;
3563  ocs_hal_io_t *hal_io;
3564  ocs_hal_io_param_t iparam;
3565  uint8_t status = LOGIN_STATUS_SUCCESS;
3566  uint8_t status_detail = 0;
3567  uint32_t skip;
3568  uint32_t ttt;
3569  ocs_cxn_q_cbit_t *cbit_added = NULL;
3570 
3571 
3572  if (cxn->cxn_state != CONN_STATE_FULL_FEATURE) {
3573  ocs_log_test(iscsi->os, "%s called with connection state not running", cxn->display_name);
3574  ocs_cxn_close(cxn, TRUE);
3576  }
3577 
3578  /* Cancel any pending text time on the connection */
3579  if (ocs_timer_pending(&cxn->ffp_timer)) {
3580  ocs_del_timer(&cxn->ffp_timer);
3581  }
3582  ocs_memcpy(cxn->text_hdr, pi, ARRAY_SIZE(cxn->text_hdr));
3583 
3584  /*
3585  * Check to see if both the C and F bits are set, this is an error
3586  * so reject the PDU. This also resets the negotiation.
3587  */
3588  if (pi->c == 1 &&
3589  pi->f == 1) {
3590  ocs_log_test(iscsi->os, "%s C=1 and F=1 Invalid - Reject PDU",
3591  cxn->display_name);
3592  *reject_reason = ISCSI_REJECT_REASON_PROTOCOL_ERR;
3593  return OCS_PDU_RTN_SEND_REJECT;
3594  }
3595 
3596  /*
3597  * Receiving an TTT of all F's resets the negotiation.
3598  */
3599  ttt = ocs_be32toh(pi->target_transfer_tag);
3600  if (ttt == 0xFFFFFFFF) {
3601  cxn->ffp_is_neg_active = FALSE;
3602  } else if (!cxn->ffp_is_neg_active) {
3603  ocs_log_test(iscsi->os, "%s TTT set with no negotiation active - Reject PDU",
3604  cxn->display_name);
3605  *reject_reason = ISCSI_REJECT_REASON_INVALID_PDU_FIELD;
3606  return OCS_PDU_RTN_SEND_REJECT;
3607  }
3608 
3609  /*
3610  * Text negotiation must carry the same ITT until complete. Verify
3611  * this is true.
3612  */
3613  if (cxn->ffp_is_neg_active) {
3614  if (ocs_be32toh(pi->itt) != cxn->ffp_itt) {
3615  ocs_log_test(iscsi->os, "%s negotiation active but TTT doesn't match - Reject PDU",
3616  cxn->display_name);
3617  *reject_reason = ISCSI_REJECT_REASON_PROTOCOL_ERR;
3618  return OCS_PDU_RTN_SEND_REJECT;
3619  }
3620  } else {
3621  cxn->ffp_is_neg_active = TRUE;
3622  cxn->ffp_itt = ocs_be32toh(pi->itt);
3623  cxn->lgn_parms_recv = 0;
3624  }
3625 
3626  hal_io = ocs_hal_io_alloc(iscsi->hal);
3627  if (hal_io == NULL) {
3628  return OCS_PDU_RTN_NO_RESOURCES;
3629  }
3630 
3631  /*
3632  * Allocate memory to hold the login payload
3633  */
3634  if (ocs_iscsi_login_buffer_get(cxn)) {
3635  ocs_hal_io_free(iscsi->hal, hal_io);
3636  return OCS_PDU_RTN_NO_RESOURCES;
3637  }
3638 
3639  po = (iscsi_text_response_hdr_t*)cxn->login_hdr_mem.virt;
3640  memset(po, 0, sizeof(iscsi_text_response_hdr_t));
3641 
3642  cbit_added = ocs_iscsi_cbit_pdu_setup(cxn, hdr, data, data_len,
3643  &status, &status_detail,
3644  &recv_ptr, &recv_len,
3645  &resp_ptr, &resp_size);
3646 
3647  /*
3648  * If c = 0, then the process the login, otherwise, wait for all the
3649  * login data to be received.
3650  */
3651  if (pi->c == 0 &&
3652  cxn->cbit_rsp_offset == 0) {
3653  /*
3654  * Do some initial checking if this is a brand new login
3655  */
3656  if (status == LOGIN_STATUS_SUCCESS) {
3657  plen = ocs_iscsi_login_negotiate(cxn,
3659  &status,
3660  &status_detail,
3661  recv_ptr,
3662  recv_len,
3663  resp_ptr,
3664  resp_size);
3665  }
3666  /*
3667  * If there is a negotiation error or a key besides
3668  * sendTargets on a discovery session, then send a reject PDU.
3669  */
3670  if (status != 0 ||
3671  (session->is_discovery_session &&
3672  (cxn->lgn_parms_recv & ~(1l << KEY_SEND_TARGETS)) != 0)) {
3673  ocs_iscsi_cbit_backout(cxn, cbit_added);
3674  ocs_hal_io_free(iscsi->hal, hal_io);
3676  ocs_log_test(iscsi->os, "%s Text on discovery session with non SendTarget key 0x%" PRIx64 ", status %d - Reject PDU",
3677  cxn->display_name,
3678  cxn->lgn_parms_recv, status);
3679  *reject_reason = ISCSI_REJECT_REASON_PROTOCOL_ERR;
3680  return OCS_PDU_RTN_SEND_REJECT;
3681  }
3682 
3683  st = ocs_iscsi_login_find_key(ocs_login_key_defs[KEY_SEND_TARGETS].key_name,
3684  recv_ptr, recv_len);
3685  if (pi->f == 1) {
3686  /*
3687  * Fill the response buffer
3688  */
3689  if (st) {
3690  uint32_t i;
3691  char *tgt_name;
3692 
3693  /*
3694  * Handle all three cases, return all targets, the
3695  * specified target or the logged in target.
3696  */
3697  if (ocs_strcmp(st, "All") == 0) {
3698  /* reject on normal sessions */
3699  if (!session->is_discovery_session) {
3700  ocs_log_test(iscsi->os, "%s All key invalid on normal sessions - Reject PDU",
3701  cxn->display_name);
3702  ocs_iscsi_cbit_backout(cxn, cbit_added);
3703  ocs_hal_io_free(iscsi->hal, hal_io);
3705  *reject_reason = ISCSI_REJECT_REASON_PROTOCOL_ERR;
3706  return OCS_PDU_RTN_SEND_REJECT;
3707  }
3708 
3709  i = 0;
3710  while ((tgt_name = ocs_iscsi_tgt_get_names(cxn->ocs, i)) != NULL) {
3711  skip = ocs_iscsi_add_tgt_keys(cxn,
3712  resp_ptr,
3713  resp_size,
3714  plen,
3715  tgt_name);
3716  plen += skip;
3717 
3718  i++;
3719  }
3720 
3721  /*
3722  * iSCSI cluster targets list will be added
3723  * in c-bit requests with
3724  * OCS_CLUST_TARGET_TTT.
3725  */
3726  if (pi->c == 0) {
3727  iscsi->clusttgt.send_en = true;
3728  iscsi->clusttgt.st_last = false;
3729  }
3730 
3731  } else if (ocs_strcmp(st, "") == 0) {
3732  /* Used logged in target - assume index 0 */
3733  tgt_name = ocs_iscsi_tgt_get_names(cxn->ocs, 0);
3734  skip = ocs_iscsi_add_tgt_keys(cxn,
3735  resp_ptr,
3736  resp_size,
3737  plen,
3738  tgt_name);
3739  plen += skip;
3740  } else {
3741  skip = ocs_iscsi_add_tgt_keys(cxn,
3742  resp_ptr,
3743  resp_size,
3744  plen,
3745  st);
3746  plen += skip;
3747  }
3748  }
3749  }
3750  }
3751 
3752  /* Copy the response to the c bit processing */
3753  if (status == LOGIN_STATUS_SUCCESS &&
3754  pi->c == 0 &&
3755  !ocs_list_empty(&cxn->cbit_list)) {
3756  ocs_iscsi_cbit_fill_buffer(cxn, status, &plen);
3757  }
3758 
3759  if (ocs_be32toh(pi->target_transfer_tag) == OCS_CLUST_TARGET_TTT) {
3760  skip = ocs_iscsi_add_cluster_tgt_keys(cxn,
3761  resp_ptr,
3762  resp_size,
3763  plen);
3764  plen += skip;
3765  }
3766 
3767  po->f = pi->f;
3768  if (po->f == 0) {
3769  po->target_transfer_tag = 0; /* can't be f's */
3770  } else {
3771  po->target_transfer_tag = 0xffffffff;
3772  }
3773 
3774  /*
3775  * Check iclusttgt list to send in multiples of 8K.
3776  * Update f-bit and c-bit to let initiator know for continue
3777  * requests till the last.
3778  */
3779  if (iscsi->clusttgt.send_en && ocs_atomic_read(&iscsi->clusttgt.cnt)) {
3780  if (!iscsi->clusttgt.st_last) {
3781  po->f = 0;
3782  po->c = 1;
3783  po->target_transfer_tag = ocs_htobe32(OCS_CLUST_TARGET_TTT);
3784  } else {
3785  po->f = 1;
3786  po->c = 0;
3787  iscsi->clusttgt.send_en = false;
3788  iscsi->clusttgt.ctgt_next = NULL;
3789  iscsi->clusttgt.st_last = true;
3790  po->target_transfer_tag = 0xffffffff;
3791  }
3792  }
3793 
3794  /* We cannot send any data if c=1 */
3795  if (pi->c == 1) {
3796  plen = 0;
3797  }
3798 
3799  po->opcode = ISCSI_RESP_TEXT;
3800  po->exp_cmd_sn = ocs_htobe32(ocs_session_exp_cmd_sn_get(cxn));
3801  po->max_cmd_sn = ocs_htobe32(ocs_session_max_cmd_sn_get(cxn));
3802  po->itt = pi->itt;
3803 
3804  ocs_iscsi_login_set_dslen(&po->dw2, plen);
3805 
3806  /*
3807  * If negotiation is complete and any parameter was received except
3808  * send targets, then send the new parameters to the FW.
3809  */
3810  if (po->f == 1) {
3811  cxn->ffp_is_neg_active = FALSE;
3812  if ((cxn->lgn_parms_recv & ~(1l << KEY_SEND_TARGETS)) != 0) {
3813  if (ocs_iscsi_send_context_udpate(cxn)) {
3814  ocs_log_test(iscsi->os, "send context update failed\n");
3815  ocs_iscsi_cbit_backout(cxn, cbit_added);
3816  ocs_hal_io_free(iscsi->hal, hal_io);
3818  return OCS_PDU_RTN_NO_RESOURCES;
3819  }
3820  }
3821  }
3822 
3823  iparam.unassisted.set_dm = TRUE;
3824  iparam.unassisted.incr_statsn = TRUE;
3825  iparam.unassisted.is_login = FALSE;
3826  iparam.unassisted.bhs = &cxn->login_hdr_mem;
3827  iparam.unassisted.payload1 = (plen > 0 ? &cxn->login_data_mem : NULL);
3828  iparam.unassisted.payload2 = NULL;
3829 
3830  if (ocs_hal_io_send(iscsi->hal,
3832  hal_io,
3833  plen,
3834  &iparam,
3835  cxn,
3837  cxn)) {
3838  ocs_iscsi_cbit_backout(cxn, cbit_added);
3839  ocs_hal_io_free(iscsi->hal, hal_io);
3841  return OCS_PDU_RTN_NO_RESOURCES;
3842  }
3843 
3844  /* Set the login timer if the negotiation is not complete */
3845  if (cxn->ffp_is_neg_active &&
3846  !ocs_timer_pending(&cxn->ffp_timer)) {
3847  ocs_setup_timer(cxn->ocs, &cxn->ffp_timer,
3849  cxn,
3850  OCS_TEXT_TIMEOUT_MS, false);
3851  }
3852 
3853  cxn->stat_sn++;
3854 
3855  /* Update and cleanup the cbit for this connection */
3856  if (pi->c == 0 &&
3857  !ocs_list_empty(&cxn->cbit_list)) {
3858  cxn->cbit_rsp_offset += plen;
3859 
3860  if (status != LOGIN_STATUS_SUCCESS ||
3861  cxn->cbit_rsp_offset == cxn->cbit_rsp_len) {
3862  /* Cleanup any cbit buffers */
3864  }
3865  }
3866 
3867  return (cbit_added == NULL ? OCS_PDU_RTN_PROCESSED : OCS_PDU_RTN_CBIT_QUEUED);
3868 }
3869 
3870 /**
3871  * @ingroup login
3872  * @brief Function to process a logout PDU.
3873  *
3874  * @param cxn Pointer to the connection object.
3875  * @param hdr DMA memory information for the header.
3876  * @param hdr_len Length of the header received.
3877  *
3878  * @return Returns 0 on success.
3879  */
3881 ocs_iscsi_recv_logout(ocs_cxn_t *cxn,
3882  ocs_hal_rq_buffer_t *hdr,
3883  uint32_t hdr_len)
3884 {
3885  ocs_iscsi_t *iscsi = cxn->iscsi;
3887  uint8_t response = LOGOUT_RESP_CONN_SESS_CLOSE_SUCCESS;
3888  uint8_t reason;
3889  uint16_t cid;
3891  int32_t send_rc;
3892  ocs_cxn_t *cxn_to_close;
3893  uint8_t send_rsp = FALSE;
3894 
3895  if (cxn->cxn_state != CONN_STATE_FULL_FEATURE) {
3896  ocs_log_test(iscsi->os, "called with connection state not running");
3897  ocs_cxn_close(cxn, TRUE);
3899  }
3900  pi = (iscsi_logout_cmd_hdr_t*)hdr->dma.virt;
3901  reason = pi->reason_code;
3902  cid = ocs_be16toh(pi->cid);
3903 
3904  if (reason == LOGOUT_REASON_CLOSE_SESS) {
3905  /* sends the logout response after IOs are aborted */
3906  cxn->send_logout_rsp = TRUE;
3907  cxn->logout_rsp = LOGOUT_RESP_CONN_SESS_CLOSE_SUCCESS;
3908  cxn->logout_itt = ocs_be32toh(pi->itt);
3909  ocs_session_close(cxn->session, FALSE);
3910  } else if (reason == LOGOUT_REASON_CLOSE_CONN) {
3911  cxn_to_close = ocs_session_cxn_find(cxn->session, cid);
3912 
3913  if (cxn_to_close == cxn) {
3914  /* sends the logout response after IOs are aborted */
3915  cxn->send_logout_rsp = TRUE;
3916  cxn->logout_rsp = LOGOUT_RESP_CONN_SESS_CLOSE_SUCCESS;
3917  cxn->logout_itt = ocs_be32toh(pi->itt);
3918  ocs_cxn_close(cxn, FALSE);
3919  } else if (cxn_to_close == NULL ) {
3920  response = LOGOUT_RESP_CID_NOT_FOUND;
3921  send_rsp = TRUE;
3922  } else {
3923  cxn_to_close->cxn_state = CONN_STATE_LOGOUT_REQUESTED;
3924  ocs_cxn_close(cxn_to_close, FALSE);
3925  send_rsp = TRUE;
3926  }
3927  } else if (reason == LOGOUT_REASON_CLOSE_CONN_FOR_RECOVERY) {
3929  send_rsp = TRUE;
3930  }
3931 
3932  if (send_rsp) {
3933  send_rc = ocs_iscsi_send_logout_rsp(cxn,
3934  response,
3935  ocs_be32toh(pi->itt));
3936 
3937  if (send_rc != 0 &&
3938  send_rc != OCS_LOGIN_REQUEST_QUEUED) {
3939  ocs_log_test(iscsi->os, "Failed sending logout response");
3941  }
3942  }
3943 
3944  return rc;
3945 }
3946 
3947 
3948 /**
3949  * @brief Function to queue a send logout request.
3950  *
3951  * @param cxn Pointer to the connection object.
3952  * @param immediate TRUE if sending as an immediate command.
3953  * @param reason_code The logout reason.
3954  *
3955  * @return Returns 0 on success.
3956  */
3957 static int32_t
3959  uint8_t immediate,
3960  uint8_t reason_code)
3961 {
3962  ocs_iscsi_t *iscsi = cxn->iscsi;
3963  ocs_iscsi_lgn_retry_t *lgn_retry;
3964  int32_t rc;
3965 
3966  if ((lgn_retry = ocs_iscsi_login_retry_get(iscsi)) == NULL) {
3967  ocs_log_test(iscsi->os, "No retry resources are available");
3968  ocs_cxn_close(cxn, TRUE);
3970  } else {
3971  lgn_retry->type = OCS_RETRY_REQ_SEND_LOGOUT;
3972  lgn_retry->cxn = cxn;
3973  lgn_retry->immediate = immediate;
3974  lgn_retry->reason = reason_code;
3976  }
3977  return rc;
3978 }
3979 
3980 
3981 /**
3982  * @ingroup login
3983  * @brief Function to send a logout PDU.
3984  *
3985  * @param cxn Pointer to the connection object.
3986  * @param immediate TRUE if sending as an immediate command.
3987  * @param reason_code Logout reason.
3988  *
3989  * @return Returns 0 on success.
3990  */
3991 int32_t
3992 ocs_iscsi_send_logout(ocs_cxn_t *cxn,
3993  uint8_t immediate,
3994  uint8_t reason_code)
3995 {
3996  ocs_iscsi_t *iscsi = cxn->iscsi;
3998  ocs_hal_io_t *hal_io;
3999  ocs_hal_io_param_t iparam;
4000 
4001  if (cxn->cxn_state != CONN_STATE_FULL_FEATURE) {
4002  ocs_log_test(iscsi->os, "called with connection state not running");
4003  ocs_cxn_close(cxn, TRUE);
4004  return -1;
4005  }
4006 
4007  hal_io = ocs_hal_io_alloc(iscsi->hal);
4008  if (hal_io == NULL) {
4009  return OCS_PDU_RTN_NO_RESOURCES;
4010  }
4011 
4012  po = (iscsi_logout_cmd_hdr_t*)cxn->login_hdr_mem.virt;
4013  memset(po, 0, sizeof (iscsi_logout_cmd_hdr_t));
4014 
4015  ocs_iscsi_login_set_dslen(&po->dw2, 0);
4016 
4017  ocs_log_debug(iscsi->os, "logout of a connection");
4018 
4019  po->opcode = ISCSI_CMD_LOGOUT;
4020  po->immediate = immediate;
4021  po->reason_code = reason_code;
4022  po->final = 1;
4023  /* itt is set in the SLI code */
4024  po->cid = ocs_htobe16(cxn->cid);
4025  po->cmd_sn = ocs_htobe32(ocs_session_cmd_sn_get(cxn, 0));
4026 
4027  iparam.unassisted.set_dm = FALSE;
4028  iparam.unassisted.incr_statsn = FALSE;
4029  iparam.unassisted.is_login = FALSE;
4030  iparam.unassisted.bhs = &cxn->login_hdr_mem;
4031  iparam.unassisted.payload1 = NULL;
4032  iparam.unassisted.payload2 = NULL;
4033  if (ocs_hal_io_send(iscsi->hal,
4035  hal_io,
4036  0,
4037  &iparam,
4038  cxn,
4040  cxn)) {
4041  ocs_hal_io_free(iscsi->hal, hal_io);
4042  return ocs_iscsi_send_logout_queue(cxn, immediate, reason_code);
4043  }
4044 
4045  cxn->cxn_state = CONN_STATE_IN_LOGOUT;
4046 
4047  return 0;
4048 }
4049 
4050 
4051 /**
4052  * @brief Function to queue a send logout response request
4053  *
4054  * @param cxn Pointer to the connection object.
4055  * @param response Logout response per the iSCSI specification.
4056  * @param itt Initiator task tag of the logout request.
4057  *
4058  * @return Returns 0 on success.
4059  */
4060 static int32_t
4062  uint8_t response,
4063  uint32_t itt)
4064 {
4065  ocs_iscsi_t *iscsi = cxn->iscsi;
4066  ocs_iscsi_lgn_retry_t *lgn_retry;
4067  int32_t rc;
4068 
4069  if ((lgn_retry = ocs_iscsi_login_retry_get(iscsi)) == NULL) {
4070  ocs_log_test(iscsi->os, "No retry resources are available");
4071  ocs_cxn_close(cxn, TRUE);
4073  } else {
4074  lgn_retry->type = OCS_RETRY_REQ_SEND_LOGOUT_RSP;
4075  lgn_retry->cxn = cxn;
4076  lgn_retry->reason = response;
4077  lgn_retry->itt = itt;
4079  }
4080  return rc;
4081 }
4082 
4083 
4084 /**
4085  * @ingroup login
4086  * @brief Function to send a logout response PDU.
4087  *
4088  * @param cxn Pointer to the connection object.
4089  * @param response Logout response per the iSCSI specification.
4090  * @param itt Initiator task tag of the logout request.
4091  *
4092  * @return Returns 0 on success.
4093  */
4094 int32_t
4096  uint8_t response,
4097  uint32_t itt)
4098 {
4099  ocs_iscsi_t *iscsi = cxn->iscsi;
4101  ocs_hal_io_t *hal_io;
4102  ocs_hal_io_param_t iparam;
4103 
4104  if (cxn->cxn_state != CONN_STATE_FULL_FEATURE &&
4105  cxn->cxn_state != CONN_STATE_LOGOUT_REQUESTED) {
4106  ocs_log_test(iscsi->os, "called with connection state not running");
4107  ocs_cxn_close(cxn, TRUE);
4108  return -1;
4109  }
4110 
4111  hal_io = ocs_hal_io_alloc(iscsi->hal);
4112  if (hal_io == NULL) {
4113  return OCS_PDU_RTN_NO_RESOURCES;
4114  }
4115 
4116  po = (iscsi_logout_response_hdr_t*)cxn->login_hdr_mem.virt;
4117  memset(po, 0, sizeof (iscsi_logout_response_hdr_t));
4118 
4119  ocs_iscsi_login_set_dslen(&po->dw2, 0);
4120 
4121  po->response = response;
4122  po->opcode = ISCSI_RESP_LOGOUT;
4123  po->final = 1;
4126  po->exp_cmd_sn = ocs_htobe32(ocs_session_exp_cmd_sn_get(cxn));
4127  po->max_cmd_sn = ocs_htobe32(ocs_session_max_cmd_sn_get(cxn));
4128  po->itt = ocs_htobe32(itt);
4129 
4130  iparam.unassisted.set_dm = TRUE;
4131  iparam.unassisted.incr_statsn = TRUE;
4132  iparam.unassisted.is_login = FALSE;
4133  iparam.unassisted.bhs = &cxn->login_hdr_mem;
4134  iparam.unassisted.payload1 = NULL;
4135  iparam.unassisted.payload2 = NULL;
4136  if (ocs_hal_io_send(iscsi->hal,
4138  hal_io,
4139  0,
4140  &iparam,
4141  cxn,
4143  cxn)) {
4144  ocs_hal_io_free(iscsi->hal, hal_io);
4145  return ocs_iscsi_send_logout_rsp_queue(cxn, response, itt);
4146  }
4147 
4148  cxn->stat_sn++;
4149  return 0;
4150 }
4151 
4152 /**
4153  * @ingroup login
4154  * @brief Handle logout response from a target.
4155  *
4156  * @param cxn Pointer to the connection object.
4157  * @param hdr DMA memory information for the header.
4158  * @param hdr_len Length of the header received.
4159  *
4160  * @return Returns 0 on success.
4161  */
4162 int32_t
4164  ocs_hal_rq_buffer_t *hdr,
4165  uint32_t hdr_len)
4166 {
4167  ocs_iscsi_t *iscsi = cxn->iscsi;
4168  iscsi_logout_response_hdr_t *logout_rsp;
4169 
4170  if (cxn->cxn_state != CONN_STATE_IN_LOGOUT) {
4171  ocs_log_test(iscsi->os, "called with connection state of %d",
4172  cxn->cxn_state);
4173  ocs_cxn_close(cxn, TRUE);
4174  return -1;
4175  }
4176 
4177  logout_rsp = (iscsi_logout_response_hdr_t*)hdr->dma.virt;
4178 
4179  ocs_log_test(iscsi->os, "logout response of %d", logout_rsp->response);
4180 
4181  ocs_cxn_close(cxn, FALSE);
4182 
4183  return (0);
4184 }
4185 
4186 
4187 /**
4188  * @brief Function to queue a send nop-out request.
4189  *
4190  * @param cxn Pointer to the connection object.
4191  * @param lun LUN for the PDU (Host byte order).
4192  * @param itt Initiator task tag (Host byte order).
4193  * @param ttt Target transfer tag (Host byte order).
4194  * @param data_ptr Pointer to the payload data (may be NULL).
4195  * @param data_len Length of the payload data.
4196  *
4197  * @return Returns 0 on success.
4198  */
4199 static int32_t
4201  uint64_t lun,
4202  uint32_t itt,
4203  uint32_t ttt,
4204  char *data_ptr,
4205  uint32_t data_len)
4206 {
4207  ocs_iscsi_t *iscsi = cxn->iscsi;
4208  ocs_iscsi_lgn_retry_t *lgn_retry;
4209  int32_t rc;
4210 
4211  lgn_retry = ocs_iscsi_login_retry_get(iscsi);
4212  if (!lgn_retry || !data_ptr || !data_len) {
4213  ocs_log_test(iscsi->os, "No retry resources are available");
4214  ocs_cxn_close(cxn, TRUE);
4216  } else if (data_len > ARRAY_SIZE(lgn_retry->virt_buffer)) {
4217  ocs_iscsi_login_retry_free(iscsi, lgn_retry);
4219  } else {
4220  lgn_retry->type = OCS_RETRY_REQ_SEND_NOP_OUT;
4221  lgn_retry->cxn = cxn;
4222  lgn_retry->lun = lun;
4223  lgn_retry->itt = itt;
4224  lgn_retry->ttt = ttt;
4225  lgn_retry->data_len = data_len;
4226  ocs_memcpy(lgn_retry->virt_buffer, data_ptr, data_len);
4228  }
4229  return rc;
4230 }
4231 
4232 
4233 /**
4234  * @ingroup login
4235  * @brief Send NOP-Out from an initiator.
4236  *
4237  * @par Description
4238  * Note: We do not handle more than one buffer of NOP data.
4239  *
4240  * @param cxn Pointer to the connection object.
4241  * @param lun LUN for the PDU (Host byte order).
4242  * @param itt Initiator task tag (Host byte order).
4243  * @param ttt Target transfer tag (Host byte order).
4244  * @param data_ptr Pointer to the payload data (may be NULL).
4245  * @param data_len Length of the payload data.
4246  *
4247  * @return Returns 0 on success.
4248  */
4249 int32_t
4250 ocs_iscsi_send_nop_out(ocs_cxn_t *cxn,
4251  uint64_t lun,
4252  uint32_t itt,
4253  uint32_t ttt,
4254  char *data_ptr,
4255  uint32_t data_len)
4256 {
4257  ocs_iscsi_t *iscsi = cxn->iscsi;
4258  iscsi_nopout_hdr_t *po;
4259  ocs_hal_io_t *hal_io;
4260  ocs_hal_io_param_t iparam;
4261 
4262  if (cxn->cxn_state != CONN_STATE_FULL_FEATURE) {
4263  ocs_log_test(iscsi->os, "called with connection state not running");
4264  ocs_cxn_close(cxn, TRUE);
4265  return -1;
4266  }
4267 
4268  /* If we can't return the entire payload, then discard it */
4269  if (data_len > OCS_ISCSI_LOGIN_PAYLOAD_SIZE) {
4270  data_len = 0;
4271  }
4272 
4273  hal_io = ocs_hal_io_alloc(iscsi->hal);
4274  if (hal_io == NULL) {
4275  return OCS_PDU_RTN_NO_RESOURCES;
4276  }
4277 
4278  if (data_len) {
4279  if (ocs_iscsi_login_buffer_get(cxn)) {
4280  ocs_hal_io_free(iscsi->hal, hal_io);
4281  return ocs_iscsi_send_nop_out_queue(cxn, lun, itt, ttt, data_ptr, data_len);
4282  }
4283  }
4284  iparam.ini_nop.bhs = &cxn->login_hdr_mem;
4285 
4286  po = (iscsi_nopout_hdr_t*)cxn->login_hdr_mem.virt;
4287  ocs_memset(po, 0, sizeof (*po));
4288 
4290  if (data_ptr && data_len) {
4291  ocs_memcpy(cxn->login_data_mem.virt, data_ptr, data_len);
4292  ocs_iscsi_login_set_dslen(&po->dw2, data_len);
4293  ocs_hal_io_add_sge(iscsi->hal, hal_io, cxn->login_data_mem.phys, data_len);
4294  }
4295 
4296  iparam.ini_nop.payload1 = NULL;
4297  iparam.ini_nop.payload2 = NULL;
4298 
4299  /*
4300  * Check the iSCSI command window to ensure that it is OK to send this
4301  * command.
4302  */
4303  if (ocs_session_is_window_open(cxn)) {
4304  /* No room in window, send as immediate command */
4305  po->immediate = 1;
4306  iparam.ini_nop.cmdsn = ocs_session_cmd_sn_get(cxn, 0);
4307  } else {
4308  /* Send as normal command */
4309  iparam.ini_nop.cmdsn = ocs_session_cmd_sn_get(cxn, 1);
4310  }
4311 
4312  po->opcode = ISCSI_CMD_NOOP;
4313  po->final = 1;
4314  po->lun.lun_64 = ocs_htobe64(lun);
4315  po->itt = ocs_htobe32(itt);
4316  po->ttt = ocs_htobe32(ttt);
4317  po->cmd_sn = ocs_htobe32(iparam.ini_nop.cmdsn);
4318  if (ocs_hal_io_send(iscsi->hal,
4320  hal_io,
4321  data_len,
4322  &iparam,
4323  cxn,
4324  (data_len ? ocs_iscsi_login_cb_free_lgn_mem :
4326  cxn)) {
4327  ocs_hal_io_free(iscsi->hal, hal_io);
4328  if (data_len) {
4330  }
4331  return ocs_iscsi_send_nop_out_queue(cxn, lun, itt, ttt, data_ptr, data_len);
4332  }
4333 
4334  /* Clear the idle count */
4335  cxn->idle_count = 0;
4336 
4337  return (0);
4338 }
4339 
4340 
4341 /**
4342  * @brief Function to queue a send nop-in request
4343  *
4344  * @param cxn pointer to the connection object
4345  * @param lun the lun for the PDU (Host byte order)
4346  * @param itt the initiator task tag (Host byte order)
4347  * @param ttt the target transfer tag (Host byte order)
4348  * @param data_ptr pointer to the payload data (may be NULL)
4349  * @param data_len length of the payload data
4350  *
4351  * @return Returns 0 on success.
4352  */
4353 static int32_t
4355  uint64_t lun,
4356  uint32_t itt,
4357  uint32_t ttt,
4358  char *data_ptr,
4359  uint32_t data_len)
4360 {
4361  ocs_iscsi_t *iscsi = cxn->iscsi;
4362  ocs_iscsi_lgn_retry_t *lgn_retry;
4363  int32_t rc;
4364 
4365  lgn_retry = ocs_iscsi_login_retry_get(iscsi);
4366  if (!lgn_retry || !data_ptr || !data_len) {
4367  ocs_log_test(iscsi->os, "No retry resources are available");
4368  ocs_cxn_close(cxn, TRUE);
4370  } else if (data_len > ARRAY_SIZE(lgn_retry->virt_buffer)) {
4371  ocs_iscsi_login_retry_free(iscsi, lgn_retry);
4373  } else {
4374  lgn_retry->type = OCS_RETRY_REQ_SEND_NOP_IN;
4375  lgn_retry->cxn = cxn;
4376  lgn_retry->lun = lun;
4377  lgn_retry->itt = itt;
4378  lgn_retry->ttt = ttt;
4379  lgn_retry->data_len = data_len;
4380  ocs_memcpy(lgn_retry->virt_buffer, data_ptr, data_len);
4382  }
4383  return rc;
4384 }
4385 
4386 
4387 /**
4388  * @ingroup login
4389  * @brief Send NOP-In from a target
4390  *
4391  * @par Description
4392  * Note: We do not handle more than one buffer of NOP data.
4393  *
4394  * @param cxn Pointer to the connection object.
4395  * @param lun LUN for the PDU (Host byte order).
4396  * @param itt Initiator task tag (Host byte order).
4397  * @param ttt Target transfer tag (Host byte order).
4398  * @param data_ptr Pointer to the payload data (may be NULL).
4399  * @param data_len Length of the payload data.
4400  *
4401  * @return Returns 0 on success.
4402  */
4403 int32_t
4404 ocs_iscsi_send_nop_in(ocs_cxn_t *cxn,
4405  uint64_t lun,
4406  uint32_t itt,
4407  uint32_t ttt,
4408  char *data_ptr,
4409  uint32_t data_len)
4410 {
4411  ocs_iscsi_t *iscsi = cxn->iscsi;
4412  iscsi_nopin_hdr_t *po;
4413  ocs_hal_io_t *hal_io;
4414  ocs_hal_io_param_t iparam;
4415 
4416  if (cxn->cxn_state != CONN_STATE_FULL_FEATURE) {
4417  ocs_log_test(iscsi->os, "called with connection state not running");
4418  ocs_cxn_close(cxn, TRUE);
4419  return -1;
4420  }
4421 
4422  /* If we can't return the entire payload, then discard it */
4423  if (data_len > OCS_ISCSI_LOGIN_PAYLOAD_SIZE) {
4424  data_len = 0;
4425  }
4426 
4427  hal_io = ocs_hal_io_alloc(iscsi->hal);
4428  if (hal_io == NULL) {
4429  return OCS_PDU_RTN_NO_RESOURCES;
4430  }
4431 
4432  /*
4433  * Allocate memory to hold the login payload
4434  */
4435  if (data_len) {
4436  if (ocs_iscsi_login_buffer_get(cxn)) {
4437  ocs_hal_io_free(iscsi->hal, hal_io);
4438  return ocs_iscsi_send_nop_in_queue(cxn, lun, itt, ttt, data_ptr,data_len);
4439  }
4440  }
4441 
4442  po = (iscsi_nopin_hdr_t*)cxn->login_hdr_mem.virt;
4443  ocs_memset(po, 0, sizeof (*po));
4444 
4445  if (data_ptr && data_len) {
4446  ocs_memcpy(cxn->login_data_mem.virt, data_ptr, data_len);
4447  ocs_iscsi_login_set_dslen(&po->dw2, data_len);
4448  }
4449 
4450  po->opcode = ISCSI_RESP_NOOP;
4451  po->final = 1;
4452  po->lun.lun_64 = ocs_htobe64(lun);
4453  po->itt = ocs_htobe32(itt);
4454  po->ttt = ocs_htobe32(ttt);
4455  po->expCmdSN = ocs_htobe32(ocs_session_exp_cmd_sn_get(cxn));
4456  po->maxCmdSN = ocs_htobe32(ocs_session_max_cmd_sn_get(cxn));
4457 
4458  iparam.unassisted.set_dm = TRUE;
4459  iparam.unassisted.incr_statsn = (itt == 0xFFFFFFFF ? 0 : 1);
4460  iparam.unassisted.is_login = FALSE;
4461  iparam.unassisted.bhs = &cxn->login_hdr_mem;
4462  iparam.unassisted.payload1 = (data_len > 0 ? &cxn->login_data_mem : NULL);
4463  iparam.unassisted.payload2 = NULL;
4464  if (ocs_hal_io_send(iscsi->hal,
4466  hal_io,
4467  data_len,
4468  &iparam,
4469  cxn,
4472  cxn)) {
4473  ocs_hal_io_free(iscsi->hal, hal_io);
4474  if (data_len) {
4476  }
4477  return ocs_iscsi_send_nop_in_queue(cxn, lun, itt, ttt, data_ptr,data_len);
4478  }
4479 
4480  /* Clear the idle count */
4481  cxn->idle_count = 0;
4482 
4483  return (0);
4484 }
4485 
4486 
4487 /**
4488  * @ingroup login
4489  * @brief Handle NOP-IN from a target.
4490  *
4491  * @par Description
4492  * @b Note: We do not handle more than one buffer of NOP data.
4493  *
4494  * @param cxn Pointer to the connection object.
4495  * @param hdr DMA memory information for the header.
4496  * @param hdr_len Length of the header received.
4497  * @param data DMA memory information for the data.
4498  * @param data_len length of the data received.
4499  *
4500  * @return Returns 0 on success.
4501  */
4502 int32_t
4503 ocs_iscsi_recv_nop_in(ocs_cxn_t *cxn,
4504  ocs_hal_rq_buffer_t *hdr,
4505  uint32_t hdr_len,
4506  ocs_hal_rq_buffer_t *data,
4507  uint32_t data_len)
4508 {
4509  ocs_iscsi_t *iscsi = cxn->iscsi;
4510  char *data_ptr = (data == NULL ? NULL : data->dma.virt);
4511  iscsi_nopout_hdr_t *pi;
4512  int32_t rc;
4513 
4514  if (cxn->cxn_state != CONN_STATE_FULL_FEATURE) {
4515  ocs_log_test(iscsi->os, "called with connection state not running");
4516  ocs_cxn_close(cxn, TRUE);
4517  return -1;
4518  }
4519 
4520  pi = (iscsi_nopout_hdr_t*)hdr->dma.virt;
4521 
4522  if (pi->ttt != 0xffffffff) {
4523  rc = ocs_iscsi_send_nop_out(cxn,
4524  ocs_be64toh(pi->lun.lun_64),
4525  0xffffffff,
4526  ocs_be32toh(pi->ttt),
4527  data_ptr,
4528  data_len);
4529  /*
4530  * Because the ping data was copied if the request is queued,
4531  * clear the status so that the buffer can be freed now.
4532  */
4533  if (rc == OCS_LOGIN_REQUEST_QUEUED) rc = 0;
4534 
4535  if (rc != 0) {
4536  ocs_log_test(iscsi->os, "sending nop-out failed\n");
4537  }
4538  }
4539 
4540  return (0);
4541 }
4542 
4543 
4544 /**
4545  * @ingroup login
4546  * @brief Handle NOP-OUT from an initiator.
4547  *
4548  * @par Description
4549  * @b Note: We do not handle more than one buffer of NOP data.
4550  *
4551  * @param cxn Pointer to the connection object.
4552  * @param hdr DMA memory information for the header.
4553  * @param hdr_len Length of the header received.
4554  * @param data DMA memory information for the data.
4555  * @param data_len Length of the data received.
4556  *
4557  * @return Returns 0 on success.
4558  */
4560 ocs_iscsi_recv_nop_out(ocs_cxn_t *cxn,
4561  ocs_hal_rq_buffer_t *hdr,
4562  uint32_t hdr_len,
4563  ocs_hal_rq_buffer_t *data,
4564  uint32_t data_len)
4565 {
4566  ocs_iscsi_t *iscsi = cxn->iscsi;
4567  char *data_ptr = (data == NULL ? NULL : data->dma.virt);
4568  iscsi_nopout_hdr_t *pi;
4569  int32_t rc;
4570 
4571  if (cxn->cxn_state != CONN_STATE_FULL_FEATURE) {
4572  ocs_log_test(iscsi->os, "called with connection state not running");
4573  ocs_cxn_close(cxn, TRUE);
4575  }
4576 
4577  pi = (iscsi_nopout_hdr_t*)hdr->dma.virt;
4578 
4579  if (pi->itt != 0xffffffff) {
4580  rc = ocs_iscsi_send_nop_in(cxn,
4581  ocs_be64toh(pi->lun.lun_64),
4582  ocs_be32toh(pi->itt),
4583  0xffffffff,
4584  data_ptr,
4585  data_len);
4586  /*
4587  * Because the ping data was copied if the request is queued,
4588  * clear the status so that the buffer can be freed now.
4589  */
4590  if (rc != 0 &&
4591  rc != OCS_LOGIN_REQUEST_QUEUED) {
4592  ocs_log_test(iscsi->os, "sending nop-in failed\n");
4594  }
4595  }
4596 
4597  return OCS_PDU_RTN_PROCESSED;
4598 }
4599 
4600 
4601 /**
4602  * @ingroup login
4603  * @brief Function to queue a send reject request.
4604  *
4605  * @param cxn Pointer to the connection object.
4606  * @param hdr Virtual memory information for the rejected header.
4607  * @param hdr_len Length of the header received.
4608  * @param reason The iSCSI reject reason.
4609  *
4610  * @return Returns 0 on success.
4611  */
4612 static int32_t
4614  void *hdr,
4615  uint32_t hdr_len,
4616  uint8_t reason)
4617 {
4618  ocs_iscsi_t *iscsi = cxn->iscsi;
4619  ocs_iscsi_lgn_retry_t *lgn_retry;
4620  int32_t rc;
4621 
4622  if ((lgn_retry = ocs_iscsi_login_retry_get(iscsi)) == NULL) {
4623  ocs_log_test(iscsi->os, "No retry resources are available");
4624  ocs_cxn_close(cxn, TRUE);
4626  } else if (hdr_len > ARRAY_SIZE(lgn_retry->virt_buffer)) {
4627  ocs_iscsi_login_retry_free(iscsi, lgn_retry);
4629  } else {
4630  lgn_retry->type = OCS_RETRY_REQ_SEND_REJECT;
4631  lgn_retry->cxn = cxn;
4632  lgn_retry->reason = reason;
4633  lgn_retry->hdr_len = hdr_len;
4634  ocs_memcpy(lgn_retry->virt_buffer, hdr, hdr_len);
4636  }
4637  return rc;
4638 }
4639 
4640 
4641 /**
4642  * @brief Sends a reject PDU for the supplied PDU header.
4643  *
4644  * @param cxn Pointer to the connection object.
4645  * @param hdr Virtual memory information for the rejected header.
4646  * @param hdr_len Length of the header received.
4647  * @param reason The iSCSI reject reason.
4648  *
4649  * @return Returns 0 on success.
4650  */
4651 int32_t
4652 ocs_iscsi_send_reject(ocs_cxn_t *cxn,
4653  void *hdr,
4654  uint32_t hdr_len,
4655  uint8_t reason)
4656 {
4657  ocs_iscsi_t *iscsi = cxn->iscsi;
4658  iscsi_bhs_t *bhs_hdr = hdr;
4659  iscsi_reject_hdr_t *reject;
4660  int32_t rc = 0;
4661  ocs_hal_io_t *hal_io;
4662  ocs_hal_io_param_t iparam;
4663  uint32_t data_sn = 0;
4664 
4665  if (cxn->cxn_state != CONN_STATE_FULL_FEATURE &&
4666  cxn->cxn_state != CONN_STATE_LOGOUT_REQUESTED) {
4667  ocs_log_test(iscsi->os, "called with connection state %d",
4668  cxn->cxn_state);
4669  ocs_cxn_close(cxn, TRUE);
4670  return -1;
4671  }
4672 
4673  hal_io = ocs_hal_io_alloc(iscsi->hal);
4674  if (hal_io == NULL) {
4675  return OCS_PDU_RTN_NO_RESOURCES;
4676  }
4677 
4678  /*
4679  * Allocate memory to hold the login payload
4680  */
4681  if (ocs_iscsi_login_buffer_get(cxn)) {
4682  ocs_hal_io_free(iscsi->hal, hal_io);
4683  return ocs_iscsi_send_reject_queue(cxn, hdr, hdr_len, reason);
4684  }
4685 
4686  if (bhs_hdr->opcode == ISCSI_CMD_DATA_OUT) {
4687  iscsi_data_out_hdr_t *data_out = hdr;
4688  data_sn = data_out->data_sn;
4689  }
4690 
4691  memset(cxn->login_hdr_mem.virt, 0, sizeof(iscsi_reject_hdr_t));
4692  reject = cxn->login_hdr_mem.virt;
4693  reject->opcode = ISCSI_RESP_REJECT;
4694  reject->final = 1;
4695  reject->reason = reason;
4696  reject->itt = 0xFFFFFFFF;
4697  reject->exp_cmd_sn = ocs_htobe32(ocs_session_exp_cmd_sn_get(cxn));
4698  reject->max_cmd_sn = ocs_htobe32(ocs_session_max_cmd_sn_get(cxn));
4699  reject->data_r2t_sn = data_sn;
4700 
4701  ocs_memcpy(cxn->login_data_mem.virt, bhs_hdr, hdr_len);
4702  ocs_iscsi_login_set_dslen(&reject->dw2, hdr_len);
4703 
4704  iparam.unassisted.set_dm = TRUE;
4705  iparam.unassisted.incr_statsn = 1;
4706  iparam.unassisted.is_login = FALSE;
4707  iparam.unassisted.bhs = &cxn->login_hdr_mem;
4708  iparam.unassisted.payload1 = &cxn->login_data_mem;
4709  iparam.unassisted.payload2 = NULL;
4710 
4711  if (ocs_hal_io_send(iscsi->hal,
4713  hal_io,
4714  hdr_len,
4715  &iparam,
4716  cxn,
4718  cxn)) {
4719  ocs_hal_io_free(iscsi->hal, hal_io);
4721  return ocs_iscsi_send_reject_queue(cxn, hdr, hdr_len, reason);
4722  }
4723  return rc;
4724 }
4725 
4726 /**
4727  * @ingroup login
4728  * @brief Function to queue an asynchronous request.
4729  *
4730  * @param cxn Pointer to the connection object.
4731  * @param payload Virtual memory containing the payload to send.
4732  * @param payload_len Length of the payload to send.
4733  * @param reason iSCSI asynchronous reason.
4734  * @param lun iSCSI LUN.
4735  * @param param1 Parameter 1 in the asynchronous PDU.
4736  * @param param2 Parameter 2 in the asynchronous PDU.
4737  * @param param3 Parameter 3 in the asynchronous PDU.
4738  *
4739  * @return Returns 0 on success.
4740  */
4741 static int32_t
4743  void *payload,
4744  uint32_t payload_len,
4745  uint8_t reason,
4746  uint64_t lun,
4747  uint16_t param1,
4748  uint16_t param2,
4749  uint16_t param3)
4750 {
4751  ocs_iscsi_t *iscsi = cxn->iscsi;
4752  ocs_iscsi_lgn_retry_t *lgn_retry;
4753  int32_t rc;
4754 
4755  if ((lgn_retry = ocs_iscsi_login_retry_get(iscsi)) == NULL) {
4756  ocs_log_test(iscsi->os, "No retry resources are available");
4757  ocs_cxn_close(cxn, TRUE);
4759  } else if (payload_len > ARRAY_SIZE(lgn_retry->virt_buffer)) {
4760  ocs_iscsi_login_retry_free(iscsi, lgn_retry);
4762  } else {
4763  lgn_retry->type = OCS_RETRY_REQ_SEND_ASYNC;
4764  lgn_retry->cxn = cxn;
4765  lgn_retry->data_len = payload_len;
4766  lgn_retry->reason = reason;
4767  lgn_retry->lun = lun;
4768  lgn_retry->param1 = param1;
4769  lgn_retry->param2 = param2;
4770  lgn_retry->param3 = param3;
4771  ocs_memcpy(lgn_retry->virt_buffer, payload, payload_len);
4773  }
4774  return rc;
4775 }
4776 
4777 /**
4778  * @brief Sends a asynchronous PDU with an optional payload.
4779  *
4780  * @param cxn Pointer to the connection object.
4781  * @param payload Virtual memory containing the payload to send.
4782  * @param payload_len Length of the payload to send.
4783  * @param reason The iSCSI asynchronous reason.
4784  * @param lun SCSI LUN.
4785  * @param param1 Parameter 1 in the asynchronous PDU.
4786  * @param param2 Parameter 2 in the asynchronous PDU.
4787  * @param param3 Parameter 3 in the asynchronous PDU.
4788  *
4789  * @return Returns 0 on success.
4790  */
4791 int32_t
4792 ocs_iscsi_send_async(ocs_cxn_t *cxn,
4793  void *payload,
4794  uint32_t payload_len,
4795  uint8_t reason,
4796  uint64_t lun,
4797  uint16_t param1,
4798  uint16_t param2,
4799  uint16_t param3)
4800 {
4801  ocs_iscsi_t *iscsi = cxn->iscsi;
4802  iscsi_async_hdr_t *async;
4803  int32_t rc = 0;
4804  ocs_hal_io_t *hal_io;
4805  ocs_hal_io_param_t iparam;
4806 
4807  if (cxn->cxn_state != CONN_STATE_FULL_FEATURE) {
4808  ocs_log_test(iscsi->os, "called with connection state %d",
4809  cxn->cxn_state);
4810  ocs_cxn_close(cxn, TRUE);
4811  return -1;
4812  }
4813 
4814  hal_io = ocs_hal_io_alloc(iscsi->hal);
4815  if (hal_io == NULL) {
4816  return OCS_PDU_RTN_NO_RESOURCES;
4817  }
4818 
4819  /*
4820  * Allocate memory to hold the login payload
4821  */
4822  if (payload_len) {
4823  if (ocs_iscsi_login_buffer_get(cxn)) {
4824  ocs_hal_io_free(iscsi->hal, hal_io);
4825  return ocs_iscsi_send_async_queue(cxn, payload, payload_len, reason,
4826  lun, param1, param2, param3);
4827  }
4828  }
4829 
4830  memset(cxn->login_hdr_mem.virt, 0, sizeof(iscsi_async_hdr_t));
4831  async = cxn->login_hdr_mem.virt;
4832  async->opcode = ISCSI_RESP_ASYNC;
4833  async->final = 1;
4834  async->lun.lun_64 = lun;
4835  async->rsvd3[0] = 0xFFFFFFFF; /* itt equivalent field */
4836  async->expCmdSN = ocs_htobe32(ocs_session_exp_cmd_sn_get(cxn));
4837  async->maxCmdSN = ocs_htobe32(ocs_session_max_cmd_sn_get(cxn));
4838  async->param1 = ocs_htobe16(param1);
4839  async->param2 = ocs_htobe16(param2);
4840  async->param3 = ocs_htobe16(param3);
4841  async->async_event = reason;
4842 
4843  if (payload_len > 0) {
4844  ocs_memcpy(cxn->login_data_mem.virt, payload, payload_len);
4845  ocs_iscsi_login_set_dslen(&async->dw2, payload_len);
4846  }
4847 
4848  iparam.unassisted.set_dm = TRUE;
4849  iparam.unassisted.incr_statsn = 1;
4850  iparam.unassisted.is_login = FALSE;
4851  iparam.unassisted.bhs = &cxn->login_hdr_mem;
4852  iparam.unassisted.payload1 = (payload_len > 0 ? &cxn->login_data_mem : NULL);
4853  iparam.unassisted.payload2 = NULL;
4854 
4855  if (ocs_hal_io_send(iscsi->hal,
4857  hal_io,
4858  payload_len,
4859  &iparam,
4860  cxn,
4861  (payload_len ? ocs_iscsi_login_cb_free_lgn_mem :
4863  cxn)) {
4864  ocs_hal_io_free(iscsi->hal, hal_io);
4865  if (payload_len) {
4867  }
4868  return ocs_iscsi_send_async_queue(cxn, payload, payload_len, reason,
4869  lun, param1, param2, param3);
4870  }
4871  cxn->stat_sn++;
4872  return rc;
4873 }
4874 
4875 /**
4876  * @brief Function to target NOP completions
4877  *
4878  * @param io Pointer to the io object.
4879  * @param cxn Pointer to the connection object.
4880  * @param status Status of the IO (1 = good).
4881  * @param ini_fields Pointer to the initiator completion fields.
4882  * @param ul_arg Pointer to the login memory structure.
4883  *
4884  * @return Returns 0 on success.
4885  */
4886 int32_t
4888  int32_t status,
4889  ocs_ini_cmpl_fields_t *ini_fields,
4890  void *ul_arg)
4891 {
4892  int32_t rc;
4893 
4894  rc = ocs_iscsi_login_cb_free_lgn_mem(io, cxn, status, ini_fields, ul_arg);
4895 
4897  return rc;
4898 }
4899 
4900 /**
4901  * @brief Function to target NOP completions.
4902  *
4903  * @param io Pointer to the io object.
4904  * @param cxn Pointer to the connection object.
4905  * @param status Status of the IO (1 = good).
4906  * @param ini_fields Pointer to the initiator completion fields.
4907  * @param ul_arg Pointer to the login memory structure.
4908  *
4909  * @return Returns 0 on success.
4910  */
4911 int32_t
4913  int32_t status,
4914  ocs_ini_cmpl_fields_t *ini_fields,
4915  void *ul_arg)
4916 {
4917  int32_t rc;
4918 
4919  rc = ocs_iscsi_login_cb_no_lgn_mem(io, cxn, status, ini_fields, ul_arg);
4920 
4922  return rc;
4923 }
4924 
4925 /**
4926  * @brief Function to free resources for login responses.
4927  *
4928  * @param io Pointer to the io object.
4929  * @param cxn Pointer to the connection object.
4930  * @param status Status of the IO (1 = good).
4931  * @param ini_fields Pointer to the initiator completion fields.
4932  * @param ul_arg Pointer to the login memory structure.
4933  *
4934  * @return Returns 0 on success.
4935  */
4936 int32_t
4938  int32_t status,
4939  ocs_ini_cmpl_fields_t *ini_fields,
4940  void *ul_arg)
4941 {
4942  ocs_iscsi_t *iscsi = cxn->iscsi;
4943 
4944  if (status != SLI_STATUS_SOL_CMD_CMPL_NORMAL &&
4945  status != SLI_STATUS_TCP_ACK_NOTIFY) {
4946  ocs_log_test(iscsi->os, "Invalid status %d\n", status);
4947  ocs_cxn_close(cxn, TRUE);
4948  }
4949 
4950  if (cxn->is_ini_cxn) {
4951  if (ini_fields != NULL &&
4952  status == SLI_STATUS_SOL_CMD_CMPL_NORMAL) {
4953  ocs_session_exp_cmd_sn_set(cxn, ini_fields->exp_cmdsn);
4954  ocs_session_cmd_window_set(cxn, ini_fields->cmd_window);
4955  }
4956  }
4957 
4958  ocs_hal_io_free(iscsi->hal, io);
4959 
4960  /* Check to see if there are items waiting for this buffer */
4961  if (!ocs_list_empty(&iscsi->login_retry_busy)) {
4962  ocs_iscsi_login_retry(cxn);
4963  }
4964  return 0;
4965 }
4966 
4967 int32_t
4969  int32_t status,
4970  ocs_ini_cmpl_fields_t *ini_fields,
4971  void *ul_arg)
4972 {
4973  /* Free the response buffer */
4975 
4976  return ocs_iscsi_login_cb_no_lgn_mem(io, cxn, status, ini_fields, ul_arg);
4977 }
4978 
4979 
4980 /*
4981  * vim:ts=4:sw=4:expandtab
4982  */
#define KEY_FLAG_SEND_TGT
Definition: ocs_login.h:46
static void ocs_session_max_cmd_sn_set(ocs_cxn_t *cxn, uint32_t max_cmd_sn)
Definition: ocs_session.h:174
static const char none[]
Definition: ocs_login.c:150
#define OCS_CHAP_MODE_INITIATOR
Definition: ocs_ioctl.h:276
#define OCS_ISCSI_LOGIN_DEFAULT_TIME_2_WAIT
Defines the iSCSI reject PDU header.
static void ocs_sport_unlock(ocs_sport_t *sport)
Definition: ocs_common.h:136
static int32_t ocs_iscsi_send_reject_queue(ocs_cxn_t *cxn, void *hdr, uint32_t hdr_len, uint8_t reason)
Function to queue a send reject request.
Definition: ocs_login.c:4613
ocs_login_key_t
enum identifying valid login keys.
Definition: ocs_login.h:64
int32_t ocs_iscsi_send_logout(ocs_cxn_t *cxn, uint8_t immediate, uint8_t reason_code)
Function to send a logout PDU.
Definition: ocs_login.c:3992
void ocs_iscsi_ffp_text_timeout(void *arg)
This function is called to check for stalled text negotiations for a connection on a target...
Definition: ocs_login.c:3496
Defines the iSCSI text command PDU header.
#define LOGIN_STAGE_NEGOTIATE_SECURITY
iscsi_isid_tsid_t isid_tsid_ptr
void ocs_iscsi_cbit_cleanup(ocs_cxn_t *cxn)
Sends the login parameters to the firmware.
Definition: ocs_login.c:2410
#define LOGIN_STAGE_FULL_FEATURE
int32_t ocs_iscsi_recv_login_rsp(ocs_cxn_t *cxn, ocs_hal_rq_buffer_t *hdr, uint32_t hdr_len, ocs_hal_rq_buffer_t *data, uint32_t data_len)
Function to process a login response PDU.
Definition: ocs_login.c:2893
ocs_lock_t lgn_queue_lock
Definition: ocs_iscsi.h:324
ocs_pdu_process_rtn_e ocs_iscsi_recv_login(ocs_cxn_t *cxn, ocs_hal_rq_buffer_t *hdr, uint32_t hdr_len, ocs_hal_rq_buffer_t *data, uint32_t data_len)
Function to process a login PDU on a target.
Definition: ocs_login.c:2450
uint32_t ocs_iscsi_tgt_is_access_allowed(ocs_t *ocs, char *tgt_name, char *ini_name)
Checks if this initiator is allowed access to a target.
int32_t ocs_iscsi_send_async(ocs_cxn_t *cxn, void *payload, uint32_t payload_len, uint8_t reason, uint64_t lun, uint16_t param1, uint16_t param2, uint16_t param3)
Sends a asynchronous PDU with an optional payload.
Definition: ocs_login.c:4792
static int32_t ocs_iscsi_send_login_rsp_invalid_during_login_queue(ocs_cxn_t *cxn, uint32_t itt)
Function to queue a send login request.
Definition: ocs_login.c:2785
ocs_ip_address_t * ocs_iscsi_tgt_get_ip_address(ocs_t *ocs, char *tgt_name, uint32_t index)
Returns the IP address of the target name based on the index.
int32_t ocs_iscsi_login_cb_no_lgn_mem(ocs_hal_io_t *io, ocs_cxn_t *cxn, int32_t status, ocs_ini_cmpl_fields_t *ini_fields, void *ul_arg)
Function to free resources for login responses.
Definition: ocs_login.c:4937
ocs_pdu_process_rtn_e
iSCSI PDU processing return codes
Definition: ocs_iscsi.h:99
Defines the iSCSI logout response PDU header.
int32_t ocs_iscsi_are_login_reqs_outstanding(ocs_cxn_t *cxn)
Checks to see if there are any retry or login IOs active on a connection.
Definition: ocs_login.c:245
#define OCS_LOGIN_ERROR_WRONG_STATE
Definition: ocs_login.h:132
static int32_t ocs_iscsi_login_negotiate_chap_tgt(ocs_cxn_t *cxn, uint8_t *status, uint8_t *status_detail, char *rsp, uint32_t rsp_size, uint32_t *rsp_len)
Function to negotiate CHAP keys on a target connection.
Definition: ocs_login.c:1816
ocs_hal_t * hal
Definition: ocs_iscsi.h:295
uint8_t data_segment_length[3]
uint32_t ocs_iscsi_tgt_get_portal_group(ocs_t *ocs, char *tgt_name, ocs_ip_address_t *ip_address)
Returns the portal group of an IP address of the target name.
int32_t ocs_iscsi_login_initialize(ocs_iscsi_t *iscsi)
Initialize the login and retry object used within the login module.
Definition: ocs_login.c:200
void ocs_iscsi_cluster_tgts_free(ocs_iscsi_t *iscsi)
iscsi cluster targets free
Definition: ocs_iscsi.c:2211
Defines the generic iSCSI basic header segment.
Defines the fields required to track the login keys during negotiation.
Definition: ocs_login.h:125
static const char all[]
Definition: ocs_login.c:154
ocs_dma_t * payload2
Definition: ocs_hal.h:523
static int32_t ocs_list_empty(ocs_list_t *list)
Test if a list is empty.
Definition: ocs_list.h:125
static void ocs_sport_lock(ocs_sport_t *sport)
Definition: ocs_common.h:131
static int32_t ocs_iscsi_login_buffer_get(ocs_cxn_t *)
Get an available login buffer from the pre-allocated pool.
Definition: ocs_login.c:309
static void ocs_iscsi_cbit_backout(ocs_cxn_t *cxn, ocs_cxn_q_cbit_t *cbit)
Backs out the adding of a cbit object on this connection.
Definition: ocs_login.c:2388
ocs_chap_state_e
Defines the state of the CHAP negotiation.
Definition: ocs_login.h:112
#define LOGIN_STATUS_SUCCESS
static const char irrelevant[]
Definition: ocs_login.c:156
#define KEY_FLAG_SEND_BOTH
Definition: ocs_login.h:47
int32_t ocs_iscsi_send_login(ocs_cxn_t *cxn, bool is_discovery, char *tgt_name)
Function to send an initial login PDU.
Definition: ocs_login.c:3182
static ocs_login_key_t ocs_iscsi_login_locate_key_locations(char *data, uint32_t data_len, uint32_t pos, uint32_t *equal_pos, uint32_t *null_pos)
Finds the next equal and null termination for the key.
Definition: ocs_login.c:626
static void * ocs_list_get_head(ocs_list_t *list)
Return the first item in the list.
Definition: ocs_list.h:292
ocs_dma_t * bhs
Definition: ocs_hal.h:521
#define OCS_CHAP_MODE_TARGET
Definition: ocs_ioctl.h:275
#define KEY_FLAG_PHASE_FFP
Definition: ocs_login.h:50
#define OCS_CLUST_TARGET_TTT
Definition: ocs_iscsi.h:252
ocs_hal_rq_buffer_t * data
Definition: ocs_iscsi.h:162
static uint32_t ocs_session_max_cmd_sn_get(ocs_cxn_t *cxn)
Definition: ocs_session.h:130
void ocs_session_max_cmd_sn_upd(ocs_session_t *session)
Updates the max_cmd_sn based on the number IOs available.
Definition: ocs_session.c:449
void ocs_md5_final(md5byte digest[16], ocs_md5_ctx_t *ctx)
Definition: ocs_md5.c:132
ocs_hal_rtn_e
defines common HAL return statuses.
Definition: ocs_hal.h:78
#define ISCSI_RESP_TEXT
const ocs_login_key_def_t ocs_login_key_defs[KEY_MAX]
Definition: ocs_login.c:58
ocs_hal_rtn_e ocs_hal_io_init_sges(ocs_hal_t *hal, ocs_hal_io_t *io, ocs_hal_io_type_e type, uint32_t offset)
Initialize the Scatter Gather List entries of an IO.
Definition: ocs_hal.c:5562
static int32_t ocs_iscsi_send_async_queue(ocs_cxn_t *cxn, void *payload, uint32_t payload_len, uint8_t reason, uint64_t lun, uint16_t param1, uint16_t param2, uint16_t param3)
Function to queue an asynchronous request.
Definition: ocs_login.c:4742
#define KEY_FLAG_ALLOW_LARGE
Definition: ocs_login.h:59
#define OCS_ISCSI_LOGIN_RETRY_ENTRIES
static ocs_sport_t * ocs_iscsi_login_convert_tgt_name(ocs_cxn_t *cxn, char *tgt_name)
Convert a target name to a sport object.
Definition: ocs_login.c:1369
ocs_iscsi_cluster_tgt_t * ctgt_next
Definition: ocs_iscsi.h:268
uint8_t is_login
Definition: ocs_hal.h:554
static void ocs_session_calc_cmd_window(ocs_cxn_t *cxn)
Definition: ocs_session.h:194
int32_t ocs_iscsi_login_tgt_nop_cb_free_lgn_mem(ocs_hal_io_t *io, ocs_cxn_t *cxn, int32_t status, ocs_ini_cmpl_fields_t *ini_fields, void *ul_arg)
Function to target NOP completions.
Definition: ocs_login.c:4887
#define OCS_ISCSI_LOGIN_PAYLOAD_SIZE
#define CONN_STATE_LOGIN_PROGRESS
ocs_pdu_process_rtn_e ocs_iscsi_recv_text(ocs_cxn_t *cxn, ocs_hal_rq_buffer_t *hdr, uint32_t hdr_len, ocs_hal_rq_buffer_t *data, uint32_t data_len, uint8_t *reject_reason)
Function to process a text PDU.
Definition: ocs_login.c:3546
char * ocs_iscsi_ini_get_name(ocs_t *ocs)
Return this initiator&#39;s name.
uint8_t ocs_iscsi_tgt_require_chap(ocs_t *ocs, char *tgt_name, ocs_session_type_e type)
Returns TRUE if CHAP is required for the session type.
static int32_t ocs_iscsi_send_nop_in_queue(ocs_cxn_t *cxn, uint64_t lun, uint32_t itt, uint32_t ttt, char *data_ptr, uint32_t data_len)
Function to queue a send nop-in request.
Definition: ocs_login.c:4354
uint32_t ocs_iscsi_add_cluster_tgt_keys(ocs_cxn_t *cxn, char *resp_ptr, uint32_t resp_size, uint32_t plen_orig)
Add iSCSI cluster target name and address.
Definition: ocs_login.c:3357
ocs_hal_rtn_e ocs_hal_io_add_sge(ocs_hal_t *hal, ocs_hal_io_t *io, uintptr_t addr, uint32_t length)
Add a Scatter Gather list Entry to an IO.
Definition: ocs_hal.c:5732
struct ocs_hal_io_param_t::@16 unassisted
iscsi_hdr_dw2_t dw2
void ocs_iscsi_login_teardown(ocs_iscsi_t *iscsi)
Releases the login and retry object used within the login module.
Definition: ocs_login.c:227
Defines the iSCSI logout PDU header.
static void ocs_iscsi_login_convert_bin_to_hexstring(uint8_t *bin, uint32_t nbytes, char *str, uint32_t max_str)
Converts binary to an ASCII hex string.
Definition: ocs_login.c:1738
static const char yes[]
Definition: ocs_login.c:152
#define ISCSI_RESP_NOOP
static uint32_t ocs_iscsi_login_send_key(ocs_cxn_t *cxn, ocs_login_key_t key, char *strptr, uint32_t avail_bytes)
Function to send iSCSI login keys.
Definition: ocs_login.c:725
int32_t ocs_iscsi_send_context_udpate(ocs_cxn_t *cxn)
Sends the login parameters to the FW.
#define CONN_STATE_NEW_CONN
int32_t ocs_iscsi_send_reject(ocs_cxn_t *cxn, void *hdr, uint32_t hdr_len, uint8_t reason)
Sends a reject PDU for the supplied PDU header.
Definition: ocs_login.c:4652
static int32_t ocs_iscsi_send_nop_out_queue(ocs_cxn_t *cxn, uint64_t lun, uint32_t itt, uint32_t ttt, char *data_ptr, uint32_t data_len)
Function to queue a send nop-out request.
Definition: ocs_login.c:4200
defines the parameters for an IO based on the IO type.
Definition: ocs_hal.h:501
#define LOGIN_STAGE_NEGOTIATE_OPERATIONAL
#define LOGIN_STATUS_DETAIL_INI_AUTHENTICATION
ocs_dma_t * payload1
Definition: ocs_hal.h:522
#define LOGIN_STATUS_DETAIL_INI_AUTHORIZATION
static int32_t ocs_iscsi_login_recv_key(ocs_cxn_t *cxn, ocs_login_key_t key, char *value, uint8_t *status_detail)
Function to receive a login key and update the login structure.
Definition: ocs_login.c:1011
struct ocs_hal_io_param_t::@12 ini_nop
static void * ocs_list_remove(ocs_list_t *list, void *item)
Remove an item from the list.
Definition: ocs_list.h:385
char * ocs_iscsi_tgt_get_names(ocs_t *ocs, uint32_t index)
Returns the target name based on the index.
ocs_ip_type_e ip_type
Definition: ocs_iscsi_api.h:75
#define OCS_LOGIN_ERROR_VIRT_ARRAY_TOO_SMALL
Definition: ocs_login.h:133
#define CONN_STATE_IN_LOGOUT
#define OCS_CHAP_TYPE_INCOMING
Definition: ocs_ioctl.h:273
#define KEY_FLAG_USE_LOGIN
Definition: ocs_login.h:54
ocs_hal_io_t * ocs_hal_io_alloc(ocs_hal_t *hal)
Allocate a HAL IO object.
Definition: ocs_hal.c:5170
Defines the iSCSI login response PDU header.
static int32_t ocs_iscsi_send_logout_rsp_queue(ocs_cxn_t *cxn, uint8_t response, uint32_t itt)
Function to queue a send logout response request.
Definition: ocs_login.c:4061
static ocs_iscsi_lgn_retry_t * ocs_iscsi_login_retry_get(ocs_iscsi_t *)
Get an available retry buffer from the pre-allocated pool.
Definition: ocs_login.c:515
#define ocs_list_init(head, type, link)
Definition: ocs_list.h:113
#define LOGIN_STATUS_DETAIL_INI_SESSION_NOT_EXIST
int32_t ocs_iscsi_send_nop_out(ocs_cxn_t *cxn, uint64_t lun, uint32_t itt, uint32_t ttt, char *data_ptr, uint32_t data_len)
Send NOP-Out from an initiator.
Definition: ocs_login.c:4250
char * ocs_iscsi_get_chap_name(ocs_t *ocs, uint8_t sess_type, uint32_t mode, uint32_t type)
Returns the CHAP user name of corresponding type.
static int32_t ocs_iscsi_login_negotiate_chap_ini(ocs_cxn_t *cxn, uint8_t *status, uint8_t *status_detail, char *rsp, uint32_t rsp_size, uint32_t *rsp_len)
Function to negotiate CHAP keys on an initiator connection.
Definition: ocs_login.c:2012
#define ISCSI_RESP_LOGIN
#define ISCSI_CMD_LOGOUT
#define KEY_FLAG_PHASE_ALL
Definition: ocs_login.h:52
iscsi_hdr_dw2_t dw2
static int32_t ocs_iscsi_login_find_value(char *text, const char *value)
Searches the list of comma-separated values for a specific value.
Definition: ocs_login.c:692
static ocs_cxn_q_cbit_t * ocs_iscsi_cbit_pdu_setup(ocs_cxn_t *cxn, ocs_hal_rq_buffer_t *hdr, ocs_hal_rq_buffer_t *data, uint32_t data_len, uint8_t *status, uint8_t *status_detail, char **recv_ptr, uint32_t *recv_len, char **resp_ptr, uint32_t *resp_size)
Does the initial checks and processing for the continue bit.
Definition: ocs_login.c:2241
static int32_t ocs_iscsi_login_retries_allocate(ocs_iscsi_t *iscsi)
Allocate the iSCSI retry buffers and add them to the pool.
Definition: ocs_login.c:354
static int32_t ocs_iscsi_send_logout_queue(ocs_cxn_t *cxn, uint8_t immediate, uint8_t reason_code)
Function to queue a send logout request.
Definition: ocs_login.c:3958
#define ocs_list_foreach_safe(list, item, nxt)
Iterate a linked list safely.
Definition: ocs_list.h:446
ocs_hal_rtn_e ocs_hal_io_send(ocs_hal_t *hal, ocs_hal_io_type_e type, ocs_hal_io_t *io, uint32_t len, ocs_hal_io_param_t *iparam, ocs_cxn_t *cxn, io_cb_t cb, void *arg)
Send a read, write, or response IO.
Definition: ocs_hal.c:5370
void ocs_target_io_aborted_nop_cmpl(ocs_cxn_t *cxn)
This function is called whenever a target NOP completes.
Definition: ocs_scsi.c:120
static int32_t ocs_iscsi_send_login_queue(ocs_cxn_t *cxn, bool is_discovery, char *tgt_name)
Function to queue a send login request.
Definition: ocs_login.c:3147
#define KEY_FLAG_NEGOTIATE
Definition: ocs_login.h:56
uint8_t ip_address[16]
Definition: ocs_iscsi_api.h:76
#define CONN_STATE_LOGOUT_REQUESTED
Defines the iSCSI header for the async PDU.
#define ISCSI_REJECT_REASON_INVALID_PDU_FIELD
#define ISCSI_CMD_NOOP
iSCSI object
Definition: ocs_iscsi.h:293
ocs_pdu_process_rtn_e ocs_iscsi_recv_nop_out(ocs_cxn_t *cxn, ocs_hal_rq_buffer_t *hdr, uint32_t hdr_len, ocs_hal_rq_buffer_t *data, uint32_t data_len)
Handle NOP-OUT from an initiator.
Definition: ocs_login.c:4560
static int32_t ocs_iscsi_add_tgt_keys(ocs_cxn_t *cxn, char *resp_ptr, uint32_t resp_size, uint32_t plen_orig, char *tgt_name)
Add targets to the sendTarget response.
Definition: ocs_login.c:3429
static void ocs_iscsi_login_buffer_free(ocs_cxn_t *)
Return a login buffer to the pre-allocated pool.
Definition: ocs_login.c:328
#define LOGIN_STATUS_INI_ERROR
int32_t ocs_scsi_new_initiator(ocs_node_t *node)
Receive notification of a new SCSI initiator node.
Definition: ocs_ramd.c:1027
#define KEY_FLAG_SEND_INI
Definition: ocs_login.h:45
Defines a wrapper for the RQ payload buffers so that we can place it back on the proper queue...
Definition: ocs_hal.h:694
iscsi_isid_tsid_t isid_tsid_ptr
#define CONN_STATE_LOGIN_FAILED
HAL IO object.
Definition: ocs_hal.h:471
ocs_pdu_process_rtn_e ocs_iscsi_recv_logout(ocs_cxn_t *cxn, ocs_hal_rq_buffer_t *hdr, uint32_t hdr_len)
Function to process a logout PDU.
Definition: ocs_login.c:3881
iscsi_hdr_dw2_t dw2
static void ocs_session_exp_cmd_sn_set(ocs_cxn_t *cxn, uint32_t exp_cmd_sn)
Definition: ocs_session.h:164
Defines the iSCSI AHS and data segment length in the PDU header.
ocs_os_handle_t os
Definition: ocs_iscsi.h:294
#define KEY_FLAG_DEFAULT
Definition: ocs_login.h:57
void ocs_md5_init(ocs_md5_ctx_t *ctx)
Definition: ocs_md5.c:70
Defines the iSCSI nop-out PDU header.
#define LOGOUT_REASON_CLOSE_CONN_FOR_RECOVERY
#define LOGIN_STATUS_DETAIL_TGT_MISC
void ocs_session_close(ocs_session_t *session, uint8_t reset)
Closes all connections on a session.
Definition: ocs_session.c:405
uint32_t ocs_instance(void *os)
Return the instance index of an opaque ocs structure.
Definition: ocs_driver.c:160
char * ocs_iscsi_get_chap_secret(ocs_t *ocs, char *name, uint32_t mode, uint32_t type, uint32_t *secret_len)
Returns the unenctypted CHAP secret for a specific user name. Note: Passwords should be at least 16 c...
int32_t ocs_iscsi_send_nop_in(ocs_cxn_t *cxn, uint64_t lun, uint32_t itt, uint32_t ttt, char *data_ptr, uint32_t data_len)
Send NOP-In from a target.
Definition: ocs_login.c:4404
#define ISCSI_REJECT_REASON_PROTOCOL_ERR
Defines the iSCSI text response PDU header.
void ocs_iscsi_rx_buffers_free(ocs_iscsi_t *iscsi, ocs_hal_rq_buffer_t *header, ocs_hal_rq_buffer_t *payload)
Add a receive buffer pair to the Receive Queue, if an error is received, then queue the buffer...
Definition: ocs_iscsi.c:4447
static uint32_t ocs_session_exp_cmd_sn_get(ocs_cxn_t *cxn)
Definition: ocs_session.h:122
static int32_t ocs_iscsi_login_check_first(ocs_cxn_t *cxn, iscsi_login_cmd_hdr_t *pi, uint8_t *status, uint8_t *status_detail, char *data, uint32_t data_len)
Function to validate the initial login PDU.
Definition: ocs_login.c:1404
int32_t ocs_iscsi_send_login_rsp_invalid_during_login(ocs_cxn_t *cxn, uint32_t itt)
Function to send an login Response PDU (invalid during login).
Definition: ocs_login.c:2815
static const char no[]
Definition: ocs_login.c:153
int ocs_sm_post_event(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
Post an event to a context.
Definition: ocs_sm.c:59
uint32_t opcode
#define ISCSI_REJECT_REASON_NEG_RESET
ocs_list_t login_retry_busy
Definition: ocs_iscsi.h:327
static void ocs_list_add_tail(ocs_list_t *list, void *item)
Add an item to the tail of the list.
Definition: ocs_list.h:263
#define OCS_LOGIN_NO_QUEUING_RESOURCES
Definition: ocs_login.h:135
void ocs_hal_io_free(ocs_hal_t *hal, ocs_hal_io_t *io)
Free a previously allocated HAL IO object.
Definition: ocs_hal.c:5231
#define LOGIN_STATUS_DETAIL_INI_MISSING_PARAM
static const char crc32c[]
Definition: ocs_login.c:151
#define OCS_TEXT_TIMEOUT_MS
Definition: ocs_login.c:56
static const char rfc3720[]
Definition: ocs_login.c:155
#define KEY_FLAG_PHASE_SEC
Definition: ocs_login.h:48
iscsi_hdr_dw2_t dw2
#define OCS_ISCSI_LOGIN_MAX_RECV_DATA_SEG_LEN
#define KEY_FLAG_USE_LEADING
Definition: ocs_login.h:53
#define ocs_list_remove_head(list)
Remove and return an item from the head of the list.
Definition: ocs_list.h:374
ocs_hal_rq_buffer_t * hdr
Definition: ocs_iscsi.h:160
static void ocs_iscsi_login_set_dslen(iscsi_hdr_dw2_t *dw, unsigned int count)
Fill in the data segment length in a PDU header.
Definition: ocs_login.c:558
void format_ip_address(ocs_ip_type_e ip_type, uint8_t *address, char *buffer, int size)
Format an IP address into a string.
Definition: ocs_iscsi.c:460
ocs_iscsi_cluster_sendtargets_t clusttgt
Definition: ocs_iscsi.h:348
#define ISCSI_VERSION_MAX
char * ocs_iscsi_ini_get_alias(ocs_t *ocs)
Returns the initiator alias.
static void ocs_node_lock(ocs_node_t *node)
Definition: ocs_common.h:432
#define ISCSI_CMD_DATA_OUT
#define ISCSI_RESP_LOGOUT
#define KEY_FLAG_PHASE_OPER
Definition: ocs_login.h:49
uint8_t set_dm
Definition: ocs_hal.h:553
void ocs_iscsi_login_retry(ocs_cxn_t *cxn)
Attempt to start a request on the retry queue.
Definition: ocs_login.c:402
int32_t ocs_iscsi_send_logout_rsp(ocs_cxn_t *cxn, uint8_t response, uint32_t itt)
Function to send a logout response PDU.
Definition: ocs_login.c:4095
defines a structure to contain the fields specific to an initiator IO completion. ...
Definition: ocs_hal.h:416
#define ocs_is_target_enabled()
static void * ocs_list_next(ocs_list_t *list, void *item)
Get the next item on the list.
Definition: ocs_list.h:339
#define ISCSI_RESP_REJECT
static uint64_t ocs_session_isid_get(ocs_cxn_t *cxn)
Definition: ocs_session.h:101
#define LOGOUT_RESP_CID_NOT_FOUND
int32_t ocs_iscsi_recv_logout_rsp(ocs_cxn_t *cxn, ocs_hal_rq_buffer_t *hdr, uint32_t hdr_len)
Handle logout response from a target.
Definition: ocs_login.c:4163
static uint32_t ocs_session_cmd_sn_get(ocs_cxn_t *cxn, uint32_t inc)
Definition: ocs_session.h:109
#define LOGOUT_RESP_CONN_RECOVERY_NOT_SUPPORTED
void ocs_md5_update(ocs_md5_ctx_t *ctx, md5byte const *buf, unsigned len)
Definition: ocs_md5.c:90
uint8_t chap_ident
Definition: ocs_iscsi.h:328
static void ocs_node_unlock(ocs_node_t *node)
Definition: ocs_common.h:437
#define ISCSI_RESP_ASYNC
#define LOGOUT_REASON_CLOSE_SESS
#define LOGIN_STATUS_DETAIL_INI_UNSUPPORTED_VERSION
Defines the iSCSI data-out PDU header.
#define KEY_FLAG_VALID_DISC
Definition: ocs_login.h:55
ocs_iscsi_retry_type_e
The types of requests that may be retried.
Definition: ocs_iscsi.h:130
static uint16_t ocs_session_tsih_get(ocs_cxn_t *cxn)
Definition: ocs_session.h:146
ocs_dma_t dma
Definition: ocs_hal.h:696
#define LOGIN_STATUS_DETAIL_INI_INVALID_DURING_LGN
static void ocs_session_tsih_set(ocs_cxn_t *cxn, uint16_t tsih)
Definition: ocs_session.h:208
#define KEY_FLAG_ALLOW_MULTI
Definition: ocs_login.h:58
ocs_iscsi_lgn_retry_t * lgn_retry
Definition: ocs_iscsi.h:325
int32_t ocs_iscsi_recv_nop_in(ocs_cxn_t *cxn, ocs_hal_rq_buffer_t *hdr, uint32_t hdr_len, ocs_hal_rq_buffer_t *data, uint32_t data_len)
Handle NOP-IN from a target.
Definition: ocs_login.c:4503
int32_t ocs_session_cxn_new(ocs_cxn_t *cxn, char *tgt_name, char *ini_name, uint64_t isid, uint16_t tsih, uint16_t cid, uint32_t cmd_sn)
Find an existing session or create a new one based on the login parameters.
Definition: ocs_session.c:187
#define LOGOUT_REASON_CLOSE_CONN
static int32_t ocs_iscsi_recv_common_queue(ocs_cxn_t *cxn, ocs_iscsi_retry_type_e type, ocs_hal_rq_buffer_t *hdr, uint32_t hdr_len, ocs_hal_rq_buffer_t *data, uint32_t data_len)
Function to queue a receive request.
Definition: ocs_login.c:2194
#define ocs_assert(cond,...)
Definition: ocs_debug.h:163
static void ocs_iscsi_cbit_fill_buffer(ocs_cxn_t *cxn, uint8_t status, uint32_t *len)
Copies the appropriate send data from the c bit processing.
Definition: ocs_login.c:2355
#define ISCSI_CMD_LOGIN
uint32_t cmdsn
Definition: ocs_hal.h:509
iscsi_hdr_dw2_t dw2
#define OCS_ISCSI_TCP_PORT
#define CONN_STATE_FULL_FEATURE
static uint32_t ocs_iscsi_login_convert_hexstring_to_bin(char *hex_str, uint8_t *bin, uint32_t nbytes)
Function to negotiate CHAP keys.
Definition: ocs_login.c:1762
ocs_list_t login_retry_free
Definition: ocs_iscsi.h:326
int32_t ocs_iscsi_login_tgt_nop_cb_no_lgn_mem(ocs_hal_io_t *io, ocs_cxn_t *cxn, int32_t status, ocs_ini_cmpl_fields_t *ini_fields, void *ul_arg)
Function to target NOP completions.
Definition: ocs_login.c:4912
#define OCS_LOGIN_REQUEST_QUEUED
Definition: ocs_login.h:134
uint32_t ocs_iscsi_get_max_cxns(ocs_t *ocs, char *tgt_name, char *ini_name)
Returns the maximum number of connections allowed per session.
uint8_t incr_statsn
Definition: ocs_hal.h:555
#define ocs_list_foreach(list, item)
Iterate a linked list.
Definition: ocs_list.h:428
structure wrapping an IP address together with it&#39;s type.
Definition: ocs_iscsi_api.h:74
uint64_t lun_64
static uint32_t ocs_iscsi_login_negotiate(ocs_cxn_t *cxn, uint8_t phase, uint8_t *status, uint8_t *status_detail, char *recv, uint32_t recv_len, char *rsp, uint32_t rsp_size)
Function to negotiate iSCSI keys.
Definition: ocs_login.c:1582
#define OCS_ISCSI_LOGIN_DEFAULT_TIME_2_RETAIN
#define LOGOUT_RESP_CONN_SESS_CLOSE_SUCCESS
#define LOGIN_STATUS_DETAIL_INI_MISC
int32_t ocs_iscsi_login_cb_free_lgn_mem(ocs_hal_io_t *io, ocs_cxn_t *cxn, int32_t status, ocs_ini_cmpl_fields_t *ini_fields, void *ul_arg)
Definition: ocs_login.c:4968
#define OCS_CHAP_CHALLENGE_SIZE
Definition: ocs_common.h:47
static char * ocs_iscsi_login_find_key(char *key, char *text, unsigned int length)
Find a key within the passed login text.
Definition: ocs_login.c:576
char tgt_name[OCS_MAX_ISCSI_NAME]
Definition: ocs_iscsi.h:245
#define KEY_FLAG_PHASE_SEC_OPER
Definition: ocs_login.h:51
uint32_t exp_cmdsn
Definition: ocs_hal.h:418
Defines the iSCSI nop-in PDU header.
#define ISCSI_VERSION_MIN
char * ocs_iscsi_tgt_get_alias(ocs_t *ocs, uint32_t index)
Returns the target alias based on the index.
int32_t ocs_cxn_close(ocs_cxn_t *cxn, uint8_t sendRst)
Issues a request to the HAL to close the connection.
Definition: ocs_cxn.c:1648
static void ocs_iscsi_login_retries_free(ocs_iscsi_t *iscsi)
Free the iSCSI login retry buffers.
Definition: ocs_login.c:379
object to queue login requests waiting for buffers
Definition: ocs_iscsi.h:146
ocs_cxn_t * ocs_session_cxn_find(ocs_session_t *session, uint16_t cid)
Locate a connection within a session based on the cid.
Definition: ocs_session.c:379
static const char chap[]
Definition: ocs_login.c:149
static void ocs_iscsi_login_retry_free(ocs_iscsi_t *, ocs_iscsi_lgn_retry_t *)
Return a login retry buffer to the pre-allocated pool.
Definition: ocs_login.c:542
#define LOGIN_STATUS_DETAIL_INI_TOO_MANY_CXN
#define LOGIN_STATUS_DETAIL_TGT_OUT_OF_RSRC
#define OCS_CHAP_TYPE_OUTGOING
Definition: ocs_ioctl.h:274
ocs_iscsi_retry_type_e type
Definition: ocs_iscsi.h:149
static void ocs_session_cmd_window_set(ocs_cxn_t *cxn, uint32_t cmd_window)
Definition: ocs_session.h:184
#define CONN_STATE_CLEANUP
static uint32_t ocs_session_is_window_open(ocs_cxn_t *cxn)
Definition: ocs_session.h:86
ocs_hal_rtn_e ocs_iscsi_login_cxn_cleanup(ocs_cxn_t *cxn)
Frees any retry objects for the connection.
Definition: ocs_login.c:277
Defines the iSCSI login PDU header.
#define LOGIN_STATUS_TGT_ERROR