Index: sys/dev/iscsi/iscsi.h =================================================================== RCS file: /cvsroot/src/sys/dev/iscsi/iscsi.h,v retrieving revision 1.4 diff -p -u -r1.4 iscsi.h --- sys/dev/iscsi/iscsi.h 15 Jun 2016 04:30:30 -0000 1.4 +++ sys/dev/iscsi/iscsi.h 28 Nov 2023 05:50:44 -0000 @@ -1,4 +1,4 @@ -/* $NetBSD: iscsi.h,v 1.4 2016/06/15 04:30:30 mlelstv Exp $ */ +/* $NetBSD: iscsi.h,v 1.5 2023/11/25 10:08:27 mlelstv Exp $ */ /*- * Copyright (c) 2004,2006,2011 The NetBSD Foundation, Inc. @@ -54,6 +54,13 @@ typedef enum { Indicates SRP authentication (for future use). */ +typedef enum { + ISCSI_CHAP_MD5 = 5, + ISCSI_CHAP_SHA1 = 6, + ISCSI_CHAP_SHA256 = 7, + ISCSI_CHAP_SHA3_256 = 8 +} iscsi_chap_types_t; + typedef struct { unsigned int mutual_auth:1; unsigned int is_secure:1; Index: sys/dev/iscsi/iscsi_globals.h =================================================================== RCS file: /cvsroot/src/sys/dev/iscsi/iscsi_globals.h,v retrieving revision 1.27 diff -p -u -r1.27 iscsi_globals.h --- sys/dev/iscsi/iscsi_globals.h 13 Sep 2022 13:09:16 -0000 1.27 +++ sys/dev/iscsi/iscsi_globals.h 28 Nov 2023 05:50:44 -0000 @@ -1,4 +1,4 @@ -/* $NetBSD: iscsi_globals.h,v 1.27 2022/09/13 13:09:16 mlelstv Exp $ */ +/* $NetBSD: iscsi_globals.h,v 1.28 2023/11/25 10:08:27 mlelstv Exp $ */ /*- * Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc. @@ -135,11 +135,10 @@ /* Connection state */ typedef enum { - /* first three correspond to CSG/NSG coding */ ST_SEC_NEG = 0, /* security negotiation phase */ - ST_OP_NEG = 1, /* operational negotiation phase */ + ST_SEC_FIN = 1, /* switch from SEC after mutual CHAP */ + ST_OP_NEG = 2, /* operational negotiation phase */ ST_FULL_FEATURE = 3, /* full feature phase */ - /* rest is internal */ ST_WINDING_DOWN = 4, /* connection termination initiated, logging out */ ST_LOGOUT_SENT = 5, /* logout has been sent */ ST_SETTLING = 6, /* waiting for things to settle down */ Index: sys/dev/iscsi/iscsi_ioctl.c =================================================================== RCS file: /cvsroot/src/sys/dev/iscsi/iscsi_ioctl.c,v retrieving revision 1.33 diff -p -u -r1.33 iscsi_ioctl.c --- sys/dev/iscsi/iscsi_ioctl.c 13 Sep 2022 13:09:16 -0000 1.33 +++ sys/dev/iscsi/iscsi_ioctl.c 28 Nov 2023 05:50:44 -0000 @@ -1,4 +1,4 @@ -/* $NetBSD: iscsi_ioctl.c,v 1.33 2022/09/13 13:09:16 mlelstv Exp $ */ +/* $NetBSD: iscsi_ioctl.c,v 1.34 2023/11/25 10:08:27 mlelstv Exp $ */ /*- * Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc. @@ -728,18 +728,11 @@ create_connection(iscsi_login_parameters } rc = get_socket(par->socket, &conn->c_sock); - fd_close(par->socket); + if (rc != EBADF) + fd_close(par->socket); if (rc) { DEBOUT(("Invalid socket %d\n", par->socket)); - - callout_destroy(&conn->c_timeout); - rw_destroy(&conn->c_sock_rw); - cv_destroy(&conn->c_idle_cv); - cv_destroy(&conn->c_ccb_cv); - cv_destroy(&conn->c_pdu_cv); - cv_destroy(&conn->c_conn_cv); - mutex_destroy(&conn->c_lock); free(conn, M_DEVBUF); par->status = ISCSI_STATUS_INVALID_SOCKET; return rc; @@ -901,11 +894,13 @@ recreate_connection(iscsi_login_paramete DEBOUT(("Too many connections (max = %d, curr = %d)\n", sess->s_MaxConnections, sess->s_active_connections)); - /* Always close the desecriptor */ - fd_close(par->socket); + /* Close the desecriptor */ + rc = EIO; + if (fd_getfile(par->socket) != NULL) + rc = fd_close(par->socket); par->status = ISCSI_STATUS_MAXED_CONNECTIONS; - return EIO; + return rc; } rw_enter(&conn->c_sock_rw, RW_WRITER); @@ -915,7 +910,8 @@ recreate_connection(iscsi_login_paramete } rc = get_socket(par->socket, &conn->c_sock); rw_exit(&conn->c_sock_rw); - fd_close(par->socket); + if (rc != EBADF) + fd_close(par->socket); if (rc) { DEBOUT(("Invalid socket %d\n", par->socket)); @@ -1739,19 +1735,23 @@ iscsi_cleanup_thread(void *par) * the send/recv threads have been killed */ DEBC(conn, 5, ("Cleanup: Waiting for threads to exit\n")); + + mutex_enter(&conn->c_lock); while (conn->c_sendproc || conn->c_rcvproc) - kpause("threads", false, hz, NULL); + kpause("threads", false, hz, &conn->c_lock); for (s=1; conn->c_usecount > 0 && s < 3; ++s) - kpause("usecount", false, hz, NULL); + kpause("usecount", false, hz, &conn->c_lock); if (conn->c_usecount > 0) { DEBC(conn, 5, ("Cleanup: %d CCBs busy\n", conn->c_usecount)); + mutex_exit(&conn->c_lock); /* retry later */ mutex_enter(&iscsi_cleanup_mtx); TAILQ_INSERT_HEAD(&iscsi_cleanupc_list, conn, c_connections); continue; } + mutex_exit(&conn->c_lock); KASSERT(!conn->c_in_session); @@ -1838,7 +1838,7 @@ iscsi_cleanup_thread(void *par) conn->c_timedout = TOUT_NONE; } - /* Go to sleep, but wake up every 30 seconds to + /* Go to sleep, but wake up every 120 seconds to * check for dead event handlers */ rc = cv_timedwait(&iscsi_cleanup_cv, &iscsi_cleanup_mtx, (TAILQ_FIRST(&event_handlers)) ? 120 * hz : 0); Index: sys/dev/iscsi/iscsi_send.c =================================================================== RCS file: /cvsroot/src/sys/dev/iscsi/iscsi_send.c,v retrieving revision 1.39 diff -p -u -r1.39 iscsi_send.c --- sys/dev/iscsi/iscsi_send.c 13 Sep 2022 13:09:16 -0000 1.39 +++ sys/dev/iscsi/iscsi_send.c 28 Nov 2023 05:50:44 -0000 @@ -1,4 +1,4 @@ -/* $NetBSD: iscsi_send.c,v 1.39 2022/09/13 13:09:16 mlelstv Exp $ */ +/* $NetBSD: iscsi_send.c,v 1.40 2023/11/25 10:08:27 mlelstv Exp $ */ /*- * Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc. @@ -34,7 +34,6 @@ #include #include #include -#include /*#define LUN_1 1 */ @@ -242,10 +241,6 @@ reassign_tasks(connection_t *oldconn) /* reset timeouts */ ccb->ccb_num_timeouts = 0; - /* fixup reference counts */ - oldconn->c_usecount--; - atomic_inc_uint(&conn->c_usecount); - DEBC(conn, 1, ("CCB %p: Copied PDU %p to %p\n", ccb, opdu, pdu)); @@ -255,9 +250,17 @@ reassign_tasks(connection_t *oldconn) /* and free the old PDU */ free_pdu(opdu); - /* put ready CCB into waiting list of new connection */ mutex_enter(&conn->c_lock); + + /* fixup reference counts */ + mutex_enter(&oldconn->c_lock); + oldconn->c_usecount--; + conn->c_usecount++; + mutex_exit(&oldconn->c_lock); + + /* put ready CCB into waiting list of new connection */ suspend_ccb(ccb, TRUE); + mutex_exit(&conn->c_lock); } @@ -683,6 +686,11 @@ init_login_pdu(connection_t *conn, ccb_t NEXT_PHASE(c_phase); } + DEB(99, ("InitLoginPdu: Flags=%x Phase=%x->%x\n", + hpdu->pduh_Flags, + (hpdu->pduh_Flags >> CSG_SHIFT) & SG_MASK, + hpdu->pduh_Flags & SG_MASK)); + memcpy(isid, &iscsi_InitiatorISID, 6); isid->TSIH = conn->c_session->s_TSIH; @@ -748,6 +756,27 @@ negotiate_login(connection_t *conn, pdu_ break; case SG_LOGIN_OPERATIONAL_NEGOTIATION: + + if (conn->c_state == ST_SEC_FIN) { + + /* + * Both sides announced to continue with + * operational negotation, but this is the + * last target packet from mutual CHAP + * that needs to be validated. + */ + rc = assemble_security_parameters(conn, tx_ccb, rx_pdu, tx_pdu); + if (rc) + break; + + /* + * Response was valid, drop (security) parameters + * so that we start negotiating operational + * parameters. + */ + rx_pdu->pdu_temp_data = NULL; + } + rc = assemble_negotiation_parameters(conn, tx_ccb, rx_pdu, tx_pdu); break; @@ -1699,13 +1728,22 @@ ccb_timeout(ccb_t *ccb) DEBC(conn, 0, ("ccb_timeout: num=%d total=%d disp=%d\n", ccb->ccb_num_timeouts+1, ccb->ccb_total_tries, ccb->ccb_disp)); + /* + * XXX can we time out after connection is closed ? + */ + if (conn == NULL) { + wake_ccb(ccb, ISCSI_STATUS_TIMEOUT); + return; + } + if (++ccb->ccb_num_timeouts > MAX_CCB_TIMEOUTS || ccb->ccb_total_tries > MAX_CCB_TRIES || ccb->ccb_disp <= CCBDISP_FREE || !ccb->ccb_session->s_ErrorRecoveryLevel) { wake_ccb(ccb, ISCSI_STATUS_TIMEOUT); - handle_connection_error(conn, ISCSI_STATUS_TIMEOUT, RECOVER_CONNECTION); + handle_connection_error(conn, + ISCSI_STATUS_TIMEOUT, RECOVER_CONNECTION); } else { if (ccb->ccb_data_in && ccb->ccb_xfer_len < ccb->ccb_data_len) { /* request resend of all missing data */ Index: sys/dev/iscsi/iscsi_text.c =================================================================== RCS file: /cvsroot/src/sys/dev/iscsi/iscsi_text.c,v retrieving revision 1.13 diff -p -u -r1.13 iscsi_text.c --- sys/dev/iscsi/iscsi_text.c 21 Apr 2019 11:45:08 -0000 1.13 +++ sys/dev/iscsi/iscsi_text.c 28 Nov 2023 05:50:45 -0000 @@ -1,4 +1,4 @@ -/* $NetBSD: iscsi_text.c,v 1.13 2019/04/21 11:45:08 maya Exp $ */ +/* $NetBSD: iscsi_text.c,v 1.14 2023/11/25 10:08:27 mlelstv Exp $ */ /*- * Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc. @@ -133,7 +133,7 @@ typedef struct STATIC key_entry_t entries[] = { {"AuthMethod", T_AUTH, 0}, - {"CHAP_A", T_NUM, 5}, + {"CHAP_A", T_NUM, ISCSI_CHAP_MD5}, {"CHAP_C", T_BIGNUM, 0}, {"CHAP_I", T_NUM, 0}, {"CHAP_N", T_STRING, 0}, @@ -170,14 +170,14 @@ STATIC key_entry_t entries[] = { /* a negotiation parameter: key and values (there may be more than 1 for lists) */ typedef struct { - text_key_t key; /* the key */ - int list_num; /* number of elements in list, doubles as */ - bool hex_bignums; /* whether to encode in hex or base64 */ - /* data size for large numeric values */ + text_key_t key; /* the key */ + int list_num; /* number of elements in list, doubles as */ + /* data size for large numeric values */ + bool hex_bignums; /* whether to encode in hex or base64 */ union { - uint32_t nval[MAX_LIST]; /* numeric or enumeration values */ - uint8_t *sval; /* string or data pointer */ + uint32_t nval[MAX_LIST];/* numeric or enumeration values */ + uint8_t *sval; /* string or data pointer */ } val; } negotiation_parameter_t; @@ -220,7 +220,6 @@ typedef struct /*****************************************************************************/ - STATIC void chap_md5_response(uint8_t *buffer, uint8_t identifier, uint8_t *secret, uint8_t *challenge, int challenge_size) @@ -234,7 +233,6 @@ chap_md5_response(uint8_t *buffer, uint8 MD5Final(buffer, &md5); } - /*****************************************************************************/ /* @@ -322,6 +320,7 @@ get_bignumval(uint8_t *buf, negotiation_ } buf++; par->list_num = dp - par->val.sval; + par->hex_bignums = true; } else if (buf[0] == '0' && (buf[1] == 'b' || buf[1] == 'B')) { buf = base64_decode(&buf[2], par->val.sval, &par->list_num); } else { @@ -340,12 +339,13 @@ get_bignumval(uint8_t *buf, negotiation_ * Parameter: * buf The buffer pointer * pval The pointer to the result. + * sep Separator to next value. * * Returns: The pointer to the next parameter, NULL on error. */ STATIC uint8_t * -get_numval(uint8_t *buf, uint32_t *pval) +get_numval(uint8_t *buf, uint32_t *pval, const uint8_t sep) { uint32_t val = 0; char c; @@ -389,11 +389,11 @@ STATIC uint8_t * get_range(uint8_t *buf, uint32_t *pval1, uint32_t *pval2) { - if ((buf = get_numval(buf, pval1)) == NULL) + if ((buf = get_numval(buf, pval1, '~')) == NULL) return NULL; if (!*buf) return NULL; - if ((buf = get_numval(buf, pval2)) == NULL) + if ((buf = get_numval(buf, pval2, '~')) == NULL) return NULL; return buf; } @@ -539,6 +539,7 @@ get_parameter(uint8_t *buf, negotiation_ par->key = i; par->list_num = 1; + par->hex_bignums = false; /* set by get_bignumval */ if (i > MAX_KEY) { DEBOUT(("get_parameter: unrecognized key <%s>\n", buf)); @@ -556,7 +557,7 @@ get_parameter(uint8_t *buf, negotiation_ switch (entries[i].val) { case T_NUM: - bp = get_numval(bp, &par->val.nval[0]); + bp = get_numval(bp, &par->val.nval[0], '\0'); break; case T_BIGNUM: @@ -927,6 +928,12 @@ complete_pars(negotiation_state_t *state DEB(10, ("complete_pars: n=%d, len=%d\n", state->num_pars, len)); + if (len == 0) { + pdu->pdu_temp_data = NULL; + pdu->pdu_temp_data_len = 0; + return 0; + } + if ((bp = malloc(len, M_TEMP, M_WAITOK)) == NULL) { DEBOUT(("*** Out of memory in complete_pars\n")); return ISCSI_STATUS_NO_RESOURCES; @@ -1313,7 +1320,6 @@ assemble_login_parameters(connection_t * return (next) ? 0 : -1; } - /* * assemble_security_parameters: * Assemble the security negotiation parameters. @@ -1342,6 +1348,7 @@ assemble_security_parameters(connection_ int challenge_size = 0; uint8_t *response = NULL; int response_size = 0; + bool challenge_hex = iscsi_hex_bignums; state->num_pars = 0; next = 0; @@ -1385,7 +1392,7 @@ assemble_security_parameters(connection_ case K_Auth_CHAP_Algorithm: if (state->auth_state != AUTH_CHAP_ALG_SENT || - rxp.val.nval[0] != 5) { + rxp.val.nval[0] != ISCSI_CHAP_MD5) { DEBOUT(("Bad algorithm, auth_state = %d, alg %d\n", state->auth_state, rxp.val.nval[0])); return ISCSI_STATUS_NEGOTIATION_ERROR; @@ -1400,6 +1407,8 @@ assemble_security_parameters(connection_ } challenge = rxp.val.sval; challenge_size = rxp.list_num; + /* respond in the same format as the challenge */ + challenge_hex = rxp.hex_bignums; break; case K_Auth_CHAP_Identifier: @@ -1428,8 +1437,11 @@ assemble_security_parameters(connection_ } response = rxp.val.sval; response_size = rxp.list_num; - if (response_size != CHAP_MD5_SIZE) + if (response_size != CHAP_MD5_SIZE) { + DEBOUT(("CHAP Response, bad size %d\n", + response_size)); return ISCSI_STATUS_NEGOTIATION_ERROR; + } break; default: @@ -1446,7 +1458,7 @@ assemble_security_parameters(connection_ return ISCSI_STATUS_NEGOTIATION_ERROR; case AUTH_METHOD_SELECTED: - set_key_n(state, K_Auth_CHAP_Algorithm, 5); + set_key_n(state, K_Auth_CHAP_Algorithm, ISCSI_CHAP_MD5); state->auth_state = AUTH_CHAP_ALG_SENT; next = -1; break; @@ -1461,12 +1473,15 @@ assemble_security_parameters(connection_ set_key_s(state, K_Auth_CHAP_Name, state->user_name); - chap_md5_response(state->temp_buf, identifier, state->password, - challenge, challenge_size); + chap_md5_response(state->temp_buf, identifier, + state->password, challenge, challenge_size); cpar = set_key_s(state, K_Auth_CHAP_Response, state->temp_buf); - if (cpar != NULL) + if (cpar != NULL) { cpar->list_num = CHAP_MD5_SIZE; + /* respond in same format as challenge */ + cpar->hex_bignums = challenge_hex; + } if (par->auth_info.mutual_auth) { if (!state->target_password[0]) { @@ -1481,9 +1496,14 @@ assemble_security_parameters(connection_ state->temp_buf[CHAP_MD5_SIZE]); cpar = set_key_s(state, K_Auth_CHAP_Challenge, &state->temp_buf[CHAP_MD5_SIZE + 1]); - if (cpar != NULL) + if (cpar != NULL) { cpar->list_num = CHAP_CHALLENGE_LEN; - next = -1; + /* use same format as target challenge */ + cpar->hex_bignums = challenge_hex; + } + + /* transitional state */ + conn->c_state = ST_SEC_FIN; } state->auth_state = AUTH_CHAP_RSP_SENT; break; @@ -1496,12 +1516,13 @@ assemble_security_parameters(connection_ } chap_md5_response(state->temp_buf, - state->temp_buf[CHAP_MD5_SIZE], - state->password, - &state->temp_buf[CHAP_MD5_SIZE + 1], - CHAP_CHALLENGE_LEN); + state->temp_buf[CHAP_MD5_SIZE], + state->target_password, + &state->temp_buf[CHAP_MD5_SIZE + 1], + CHAP_CHALLENGE_LEN); - if (memcmp(state->temp_buf, response, response_size)) { + if (response_size > sizeof(state->temp_buf) || + memcmp(state->temp_buf, response, response_size)) { DEBOUT(("Mutual authentication mismatch\n")); return ISCSI_STATUS_AUTHENTICATION_FAILED; } @@ -1533,9 +1554,9 @@ set_first_opnegs(connection_t *conn, neg iscsi_login_parameters_t *lpar = conn->c_login_par; negotiation_parameter_t *cpar; - /* Digests - suggest None,CRC32C unless the user forces a value */ + /* Digests - suggest None,CRC32C unless the user forces a value */ cpar = set_key_n(state, K_HeaderDigest, - (lpar->is_present.HeaderDigest) ? lpar->HeaderDigest : 0); + (lpar->is_present.HeaderDigest) ? lpar->HeaderDigest : 0); if (cpar != NULL && !lpar->is_present.HeaderDigest) { cpar->list_num = 2; cpar->val.nval[1] = 1; @@ -1557,16 +1578,19 @@ set_first_opnegs(connection_t *conn, neg /* First connection only */ if (!conn->c_session->s_TSIH) { state->ErrorRecoveryLevel = - (lpar->is_present.ErrorRecoveryLevel) ? lpar->ErrorRecoveryLevel - : 2; + (lpar->is_present.ErrorRecoveryLevel) ? + lpar->ErrorRecoveryLevel : 2; /* - Negotiate InitialR2T to FALSE and ImmediateData to TRUE, should - be slightly more efficient than the default InitialR2T=TRUE. + * Negotiate InitialR2T to FALSE and ImmediateData to + * TRUE, should be slightly more efficient than the + * default InitialR2T=TRUE. */ state->InitialR2T = FALSE; state->ImmediateData = TRUE; - /* We don't really care about this, so don't negotiate by default */ + /* We don't really care about this, so don't negotiate + * by default + */ state->MaxBurstLength = entries[K_MaxBurstLength].defval; state->FirstBurstLength = entries[K_FirstBurstLength].defval; state->MaxOutstandingR2T = entries[K_MaxOutstandingR2T].defval; @@ -1625,7 +1649,7 @@ assemble_negotiation_parameters(connecti DEBC(conn, 10, ("AsmNegParams: connState=%d, MRDSL=%d\n", conn->c_state, state->MaxRecvDataSegmentLength)); - if (conn->c_state == ST_SEC_NEG) { + if (conn->c_state == ST_SEC_NEG || conn->c_state == ST_SEC_FIN) { conn->c_state = ST_OP_NEG; set_first_opnegs(conn, state); } @@ -1709,6 +1733,7 @@ assemble_send_targets(pdu_t *pdu, uint8_ par.key = K_SendTargets; par.list_num = 1; par.val.sval = val; + par.hex_bignums = false; len = parameter_size(&par); @@ -1719,8 +1744,10 @@ assemble_send_targets(pdu_t *pdu, uint8_ pdu->pdu_temp_data = buf; pdu->pdu_temp_data_len = len; - if (put_parameter(buf, len, &par) == 0) + if (put_parameter(buf, len, &par) == 0) { + DEBOUT(("trying to put zero sized buffer\n")); return ISCSI_STATUS_PARAMETER_INVALID; + } return 0; } Index: sys/dev/iscsi/iscsi_utils.c =================================================================== RCS file: /cvsroot/src/sys/dev/iscsi/iscsi_utils.c,v retrieving revision 1.28 diff -p -u -r1.28 iscsi_utils.c --- sys/dev/iscsi/iscsi_utils.c 13 Sep 2022 13:09:16 -0000 1.28 +++ sys/dev/iscsi/iscsi_utils.c 28 Nov 2023 05:50:45 -0000 @@ -1,4 +1,4 @@ -/* $NetBSD: iscsi_utils.c,v 1.28 2022/09/13 13:09:16 mlelstv Exp $ */ +/* $NetBSD: iscsi_utils.c,v 1.29 2023/11/25 10:08:27 mlelstv Exp $ */ /*- * Copyright (c) 2004,2005,2006,2008 The NetBSD Foundation, Inc. @@ -235,7 +235,9 @@ get_ccb(connection_t *conn, bool waitok) ccb->ccb_disp = CCBDISP_NOWAIT; ccb->ccb_connection = conn; ccb->ccb_num_timeouts = 0; - atomic_inc_uint(&conn->c_usecount); + mutex_enter(&conn->c_lock); + conn->c_usecount++; + mutex_exit(&conn->c_lock); DEBC(conn, 15, ( "get_ccb: ccb = %p, usecount = %d\n", @@ -264,8 +266,10 @@ free_ccb(ccb_t *ccb) KASSERT((ccb->ccb_flags & CCBF_WAITQUEUE) == 0); - atomic_dec_uint(&conn->c_usecount); ccb->ccb_connection = NULL; + mutex_enter(&conn->c_lock); + conn->c_usecount--; + mutex_exit(&conn->c_lock); if (ccb->ccb_disp > CCBDISP_NOWAIT) { DEBOUT(("Freeing CCB with disp %d\n",ccb->ccb_disp));