/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at
* http://www.opensource.org/licenses/cddl1.txt.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2004-2011 Emulex. All rights reserved.
* Use is subject to license terms.
*/
#include <emlxs.h>
#ifdef DHCHAP_SUPPORT
#include <md5.h>
#include <sha1.h>
#include <sys/sha1_consts.h>
#include <bignum.h>
#include <sys/time.h>
#define RAND
#ifndef ENABLE
#define ENABLE 1
#endif /* ENABLE */
#ifndef DISABLE
#define DISABLE 0
#endif /* DISABLE */
/* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
EMLXS_MSG_DEF(EMLXS_DHCHAP_C);
static char *emlxs_dhc_pstate_xlate(uint32_t state);
static char *emlxs_dhc_nstate_xlate(uint32_t state);
static uint32_t emlxs_check_dhgp(emlxs_port_t *port, NODELIST *ndlp,
uint32_t *dh_id, uint16_t cnt, uint32_t *dhgp_id);
static void emlxs_dhc_set_reauth_time(emlxs_port_t *port,
emlxs_node_t *ndlp, uint32_t status);
static void emlxs_auth_cfg_init(emlxs_hba_t *hba);
static void emlxs_auth_cfg_fini(emlxs_hba_t *hba);
static void emlxs_auth_cfg_read(emlxs_hba_t *hba);
static uint32_t emlxs_auth_cfg_parse(emlxs_hba_t *hba,
emlxs_auth_cfg_t *config, char *prop_str);
static emlxs_auth_cfg_t *emlxs_auth_cfg_get(emlxs_hba_t *hba,
uint8_t *lwwpn, uint8_t *rwwpn);
static emlxs_auth_cfg_t *emlxs_auth_cfg_create(emlxs_hba_t *hba,
uint8_t *lwwpn, uint8_t *rwwpn);
static void emlxs_auth_cfg_destroy(emlxs_hba_t *hba,
emlxs_auth_cfg_t *auth_cfg);
static void emlxs_auth_cfg_print(emlxs_hba_t *hba,
emlxs_auth_cfg_t *auth_cfg);
static void emlxs_auth_key_init(emlxs_hba_t *hba);
static void emlxs_auth_key_fini(emlxs_hba_t *hba);
static void emlxs_auth_key_read(emlxs_hba_t *hba);
static uint32_t emlxs_auth_key_parse(emlxs_hba_t *hba,
emlxs_auth_key_t *auth_key, char *prop_str);
static emlxs_auth_key_t *emlxs_auth_key_get(emlxs_hba_t *hba,
uint8_t *lwwpn, uint8_t *rwwpn);
static emlxs_auth_key_t *emlxs_auth_key_create(emlxs_hba_t *hba,
uint8_t *lwwpn, uint8_t *rwwpn);
static void emlxs_auth_key_destroy(emlxs_hba_t *hba,
emlxs_auth_key_t *auth_key);
static void emlxs_auth_key_print(emlxs_hba_t *hba,
emlxs_auth_key_t *auth_key);
static void emlxs_get_random_bytes(NODELIST *ndlp, uint8_t *rdn,
uint32_t len);
static emlxs_auth_cfg_t *emlxs_auth_cfg_find(emlxs_port_t *port,
uint8_t *rwwpn);
static emlxs_auth_key_t *emlxs_auth_key_find(emlxs_port_t *port,
uint8_t *rwwpn);
static void emlxs_dhc_auth_complete(emlxs_port_t *port,
emlxs_node_t *ndlp, uint32_t status);
static void emlxs_log_auth_event(emlxs_port_t *port, NODELIST *ndlp,
char *subclass, char *info);
static int emlxs_issue_auth_negotiate(emlxs_port_t *port,
emlxs_node_t *ndlp, uint8_t retry);
static void emlxs_cmpl_auth_negotiate_issue(fc_packet_t *pkt);
static uint32_t *emlxs_hash_rsp(emlxs_port_t *port,
emlxs_port_dhc_t *port_dhc, NODELIST *ndlp, uint32_t tran_id,
union challenge_val un_cval, uint8_t *dhval, uint32_t dhvallen);
static fc_packet_t *emlxs_prep_els_fc_pkt(emlxs_port_t *port,
uint32_t d_id, uint32_t cmd_size, uint32_t rsp_size,
uint32_t datalen, int32_t sleepflag);
static uint32_t *emlxs_hash_vrf(emlxs_port_t *port,
emlxs_port_dhc_t *port_dhc, NODELIST *ndlp, uint32_t tran_id,
union challenge_val un_cval);
static BIG_ERR_CODE
emlxs_interm_hash(emlxs_port_t *port, emlxs_port_dhc_t *port_dhc,
NODELIST *ndlp, void *hash_val, uint32_t tran_id,
union challenge_val un_cval, uint8_t *dhval, uint32_t *);
static BIG_ERR_CODE
emlxs_BIGNUM_get_pubkey(emlxs_port_t *port, emlxs_port_dhc_t *port_dhc,
NODELIST *ndlp, uint8_t *dhval, uint32_t *dhvallen,
uint32_t hash_size, uint32_t dhgp_id);
static BIG_ERR_CODE
emlxs_BIGNUM_get_dhval(emlxs_port_t *port, emlxs_port_dhc_t *port_dhc,
NODELIST *ndlp, uint8_t *dhval, uint32_t *dhval_len,
uint32_t dhgp_id, uint8_t *priv_key, uint32_t privkey_len);
static uint32_t *
emlxs_hash_verification(emlxs_port_t *port, emlxs_port_dhc_t *port_dhc,
NODELIST *ndlp, uint32_t tran_id, uint8_t *dhval,
uint32_t dhval_len, uint32_t flag, uint8_t *bi_cval);
static uint32_t *
emlxs_hash_get_R2(emlxs_port_t *port, emlxs_port_dhc_t *port_dhc,
NODELIST *ndlp, uint32_t tran_id, uint8_t *dhval,
uint32_t dhval_len, uint32_t flag, uint8_t *bi_cval);
static uint32_t emlxs_issue_auth_reject(emlxs_port_t *port,
NODELIST *ndlp, int retry, uint32_t *arg, uint8_t ReasonCode,
uint8_t ReasonCodeExplanation);
static uint32_t emlxs_disc_neverdev(emlxs_port_t *port, void *arg1,
void *arg2, void *arg3, void *arg4, uint32_t evt);
static uint32_t emlxs_rcv_auth_msg_unmapped_node(emlxs_port_t *port,
void *arg1, void *arg2, void *arg3, void *arg4, uint32_t evt);
static uint32_t emlxs_rcv_auth_msg_npr_node(emlxs_port_t *port,
void *arg1, void *arg2, void *arg3, void *arg4, uint32_t evt);
static uint32_t emlxs_cmpl_auth_msg_npr_node(emlxs_port_t *port,
void *arg1, void *arg2, void *arg3, void *arg4, uint32_t evt);
static uint32_t emlxs_rcv_auth_msg_auth_negotiate_issue(emlxs_port_t *port,
void *arg1, void *arg2, void *arg3, void *arg4, uint32_t evt);
static uint32_t emlxs_cmpl_auth_msg_auth_negotiate_issue(emlxs_port_t *port,
void *arg1, void *arg2, void *arg3, void *arg4, uint32_t evt);
static uint32_t emlxs_rcv_auth_msg_auth_negotiate_rcv(emlxs_port_t *port,
void *arg1, void *arg2, void *arg3, void *arg4, uint32_t evt);
static uint32_t emlxs_cmpl_auth_msg_auth_negotiate_rcv(emlxs_port_t *port,
void *arg1, void *arg2, void *arg3, void *arg4, uint32_t evt);
static uint32_t
emlxs_rcv_auth_msg_auth_negotiate_cmpl_wait4next(emlxs_port_t *port,
void *arg1, void *arg2, void *arg3, void *arg4, uint32_t evt);
static uint32_t
emlxs_cmpl_auth_msg_auth_negotiate_cmpl_wait4next(emlxs_port_t *port,
void *arg1, void *arg2, void *arg3, void *arg4, uint32_t evt);
static uint32_t
emlxs_rcv_auth_msg_dhchap_challenge_issue(emlxs_port_t *port, void *arg1,
void *arg2, void *arg3, void *arg4, uint32_t evt);
static uint32_t
emlxs_cmpl_auth_msg_dhchap_challenge_issue(emlxs_port_t *port, void *arg1,
void *arg2, void *arg3, void *arg4, uint32_t evt);
static uint32_t emlxs_rcv_auth_msg_dhchap_reply_issue(emlxs_port_t *port,
void *arg1, void *arg2, void *arg3, void *arg4, uint32_t evt);
static uint32_t emlxs_cmpl_auth_msg_dhchap_reply_issue(emlxs_port_t *port,
void *arg1, void *arg2, void *arg3, void *arg4, uint32_t evt);
static uint32_t
emlxs_rcv_auth_msg_dhchap_challenge_cmpl_wait4next(emlxs_port_t *port,
void *arg1, void *arg2, void *arg3, void *arg4, uint32_t evt);
static uint32_t
emlxs_cmpl_auth_msg_dhchap_challenge_cmpl_wait4next(emlxs_port_t *port,
void *arg1, void *arg2, void *arg3, void *arg4, uint32_t evt);
static uint32_t
emlxs_rcv_auth_msg_dhchap_reply_cmpl_wait4next(emlxs_port_t *port,
void *arg1, void *arg2, void *arg3, void *arg4, uint32_t evt);
static uint32_t
emlxs_cmpl_auth_msg_dhchap_reply_cmpl_wait4next(emlxs_port_t *port,
void *arg1, void *arg2, void *arg3, void *arg4, uint32_t evt);
static uint32_t emlxs_rcv_auth_msg_dhchap_success_issue(emlxs_port_t *port,
void *arg1, void *arg2, void *arg3, void *arg4, uint32_t evt);
static uint32_t
emlxs_cmpl_auth_msg_dhchap_success_issue(emlxs_port_t *port, void *arg1,
void *arg2, void *arg3, void *arg4, uint32_t evt);
static uint32_t
emlxs_rcv_auth_msg_dhchap_success_issue_wait4next(emlxs_port_t *port,
void *arg1, void *arg2, void *arg3, void *arg4, uint32_t evt);
static uint32_t
emlxs_cmpl_auth_msg_dhchap_success_issue_wait4next(emlxs_port_t *port,
void *arg1, void *arg2, void *arg3, void *arg4, uint32_t evt);
static uint32_t
emlxs_rcv_auth_msg_dhchap_success_cmpl_wait4next(emlxs_port_t *port,
void *arg1, void *arg2, void *arg3, void *arg4, uint32_t evt);
static uint32_t
emlxs_cmpl_auth_msg_dhchap_success_cmpl_wait4next(emlxs_port_t *port,
void *arg1, void *arg2, void *arg3, void *arg4, uint32_t evt);
static uint32_t emlxs_device_recov_unmapped_node(emlxs_port_t *port,
void *arg1, void *arg2, void *arg3, void *arg4, uint32_t evt);
static uint32_t emlxs_device_rm_npr_node(emlxs_port_t *port, void *arg1,
void *arg2, void *arg3, void *arg4, uint32_t evt);
static uint32_t emlxs_device_recov_npr_node(emlxs_port_t *port, void *arg1,
void *arg2, void *arg3, void *arg4, uint32_t evt);
static uint32_t emlxs_device_rem_auth(emlxs_port_t *port, void *arg1,
void *arg2, void *arg3, void *arg4, uint32_t evt);
static uint32_t emlxs_device_recov_auth(emlxs_port_t *port, void *arg1,
void *arg2, void *arg3, void *arg4, uint32_t evt);
static uint8_t emlxs_null_wwn[8] =
{0, 0, 0, 0, 0, 0, 0, 0};
static uint8_t emlxs_fabric_wwn[8] =
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
unsigned char dhgp1_pVal[] =
{0xEE, 0xAF, 0x0A, 0xB9, 0xAD, 0xB3, 0x8D, 0xD6, 0x9C, 0x33, 0xF8, 0x0A, 0xFA,
0x8F, 0xC5, 0xE8,
0x60, 0x72, 0x61, 0x87, 0x75, 0xFF, 0x3C, 0x0B, 0x9E, 0xA2, 0x31, 0x4C, 0x9C,
0x25, 0x65, 0x76,
0xD6, 0x74, 0xDF, 0x74, 0x96, 0xEA, 0x81, 0xD3, 0x38, 0x3B, 0x48, 0x13, 0xD6,
0x92, 0xC6, 0xE0,
0xE0, 0xD5, 0xD8, 0xE2, 0x50, 0xB9, 0x8B, 0xE4, 0x8E, 0x49, 0x5C, 0x1D, 0x60,
0x89, 0xDA, 0xD1,
0x5D, 0xC7, 0xD7, 0xB4, 0x61, 0x54, 0xD6, 0xB6, 0xCE, 0x8E, 0xF4, 0xAD, 0x69,
0xB1, 0x5D, 0x49,
0x82, 0x55, 0x9B, 0x29, 0x7B, 0xCF, 0x18, 0x85, 0xC5, 0x29, 0xF5, 0x66, 0x66,
0x0E, 0x57, 0xEC,
0x68, 0xED, 0xBC, 0x3C, 0x05, 0x72, 0x6C, 0xC0, 0x2F, 0xD4, 0xCB, 0xF4, 0x97,
0x6E, 0xAA, 0x9A,
0xFD, 0x51, 0x38, 0xFE, 0x83, 0x76, 0x43, 0x5B, 0x9F, 0xC6, 0x1D, 0x2F, 0xC0,
0xEB, 0x06, 0xE3,
};
unsigned char dhgp2_pVal[] =
{0xD7, 0x79, 0x46, 0x82, 0x6E, 0x81, 0x19, 0x14, 0xB3, 0x94, 0x01, 0xD5, 0x6A,
0x0A, 0x78, 0x43,
0xA8, 0xE7, 0x57, 0x5D, 0x73, 0x8C, 0x67, 0x2A, 0x09, 0x0A, 0xB1, 0x18, 0x7D,
0x69, 0x0D, 0xC4,
0x38, 0x72, 0xFC, 0x06, 0xA7, 0xB6, 0xA4, 0x3F, 0x3B, 0x95, 0xBE, 0xAE, 0xC7,
0xDF, 0x04, 0xB9,
0xD2, 0x42, 0xEB, 0xDC, 0x48, 0x11, 0x11, 0x28, 0x32, 0x16, 0xCE, 0x81, 0x6E,
0x00, 0x4B, 0x78,
0x6C, 0x5F, 0xCE, 0x85, 0x67, 0x80, 0xD4, 0x18, 0x37, 0xD9, 0x5A, 0xD7, 0x87,
0xA5, 0x0B, 0xBE,
0x90, 0xBD, 0x3A, 0x9C, 0x98, 0xAC, 0x0F, 0x5F, 0xC0, 0xDE, 0x74, 0x4B, 0x1C,
0xDE, 0x18, 0x91,
0x69, 0x08, 0x94, 0xBC, 0x1F, 0x65, 0xE0, 0x0D, 0xE1, 0x5B, 0x4B, 0x2A, 0xA6,
0xD8, 0x71, 0x00,
0xC9, 0xEC, 0xC2, 0x52, 0x7E, 0x45, 0xEB, 0x84, 0x9D, 0xEB, 0x14, 0xBB, 0x20,
0x49, 0xB1, 0x63,
0xEA, 0x04, 0x18, 0x7F, 0xD2, 0x7C, 0x1B, 0xD9, 0xC7, 0x95, 0x8C, 0xD4, 0x0C,
0xE7, 0x06, 0x7A,
0x9C, 0x02, 0x4F, 0x9B, 0x7C, 0x5A, 0x0B, 0x4F, 0x50, 0x03, 0x68, 0x61, 0x61,
0xF0, 0x60, 0x5B
};
unsigned char dhgp3_pVal[] =
{0x9D, 0xEF, 0x3C, 0xAF, 0xB9, 0x39, 0x27, 0x7A, 0xB1, 0xF1, 0x2A, 0x86, 0x17,
0xA4, 0x7B, 0xBB,
0xDB, 0xA5, 0x1D, 0xF4, 0x99, 0xAC, 0x4C, 0x80, 0xBE, 0xEE, 0xA9, 0x61, 0x4B,
0x19, 0xCC, 0x4D,
0x5F, 0x4F, 0x5F, 0x55, 0x6E, 0x27, 0xCB, 0xDE, 0x51, 0xC6, 0xA9, 0x4B, 0xE4,
0x60, 0x7A, 0x29,
0x15, 0x58, 0x90, 0x3B, 0xA0, 0xD0, 0xF8, 0x43, 0x80, 0xB6, 0x55, 0xBB, 0x9A,
0x22, 0xE8, 0xDC,
0xDF, 0x02, 0x8A, 0x7C, 0xEC, 0x67, 0xF0, 0xD0, 0x81, 0x34, 0xB1, 0xC8, 0xB9,
0x79, 0x89, 0x14,
0x9B, 0x60, 0x9E, 0x0B, 0xE3, 0xBA, 0xB6, 0x3D, 0x47, 0x54, 0x83, 0x81, 0xDB,
0xC5, 0xB1, 0xFC,
0x76, 0x4E, 0x3F, 0x4B, 0x53, 0xDD, 0x9D, 0xA1, 0x15, 0x8B, 0xFD, 0x3E, 0x2B,
0x9C, 0x8C, 0xF5,
0x6E, 0xDF, 0x01, 0x95, 0x39, 0x34, 0x96, 0x27, 0xDB, 0x2F, 0xD5, 0x3D, 0x24,
0xB7, 0xC4, 0x86,
0x65, 0x77, 0x2E, 0x43, 0x7D, 0x6C, 0x7F, 0x8C, 0xE4, 0x42, 0x73, 0x4A, 0xF7,
0xCC, 0xB7, 0xAE,
0x83, 0x7C, 0x26, 0x4A, 0xE3, 0xA9, 0xBE, 0xB8, 0x7F, 0x8A, 0x2F, 0xE9, 0xB8,
0xB5, 0x29, 0x2E,
0x5A, 0x02, 0x1F, 0xFF, 0x5E, 0x91, 0x47, 0x9E, 0x8C, 0xE7, 0xA2, 0x8C, 0x24,
0x42, 0xC6, 0xF3,
0x15, 0x18, 0x0F, 0x93, 0x49, 0x9A, 0x23, 0x4D, 0xCF, 0x76, 0xE3, 0xFE, 0xD1,
0x35, 0xF9, 0xBB
};
unsigned char dhgp4_pVal[] =
{0xAC, 0x6B, 0xDB, 0x41, 0x32, 0x4A, 0x9A, 0x9B, 0xF1, 0x66, 0xDE, 0x5E, 0x13,
0x89, 0x58, 0x2F,
0xAF, 0x72, 0xB6, 0x65, 0x19, 0x87, 0xEE, 0x07, 0xFC, 0x31, 0x92, 0x94, 0x3D,
0xB5, 0x60, 0x50,
0xA3, 0x73, 0x29, 0xCB, 0xB4, 0xA0, 0x99, 0xED, 0x81, 0x93, 0xE0, 0x75, 0x77,
0x67, 0xA1, 0x3D,
0xD5, 0x23, 0x12, 0xAB, 0x4B, 0x03, 0x31, 0x0D, 0xCD, 0x7F, 0x48, 0xA9, 0xDA,
0x04, 0xFD, 0x50,
0xE8, 0x08, 0x39, 0x69, 0xED, 0xB7, 0x67, 0xB0, 0xCF, 0x60, 0x95, 0x17, 0x9A,
0x16, 0x3A, 0xB3,
0x66, 0x1A, 0x05, 0xFB, 0xD5, 0xFA, 0xAA, 0xE8, 0x29, 0x18, 0xA9, 0x96, 0x2F,
0x0B, 0x93, 0xB8,
0x55, 0xF9, 0x79, 0x93, 0xEC, 0x97, 0x5E, 0xEA, 0xA8, 0x0D, 0x74, 0x0A, 0xDB,
0xF4, 0xFF, 0x74,
0x73, 0x59, 0xD0, 0x41, 0xD5, 0xC3, 0x3E, 0xA7, 0x1D, 0x28, 0x1E, 0x44, 0x6B,
0x14, 0x77, 0x3B,
0xCA, 0x97, 0xB4, 0x3A, 0x23, 0xFB, 0x80, 0x16, 0x76, 0xBD, 0x20, 0x7A, 0x43,
0x6C, 0x64, 0x81,
0xF1, 0xD2, 0xB9, 0x07, 0x87, 0x17, 0x46, 0x1A, 0x5B, 0x9D, 0x32, 0xE6, 0x88,
0xF8, 0x77, 0x48,
0x54, 0x45, 0x23, 0xB5, 0x24, 0xB0, 0xD5, 0x7D, 0x5E, 0xA7, 0x7A, 0x27, 0x75,
0xD2, 0xEC, 0xFA,
0x03, 0x2C, 0xFB, 0xDB, 0xF5, 0x2F, 0xB3, 0x78, 0x61, 0x60, 0x27, 0x90, 0x04,
0xE5, 0x7A, 0xE6,
0xAF, 0x87, 0x4E, 0x73, 0x03, 0xCE, 0x53, 0x29, 0x9C, 0xCC, 0x04, 0x1C, 0x7B,
0xC3, 0x08, 0xD8,
0x2A, 0x56, 0x98, 0xF3, 0xA8, 0xD0, 0xC3, 0x82, 0x71, 0xAE, 0x35, 0xF8, 0xE9,
0xDB, 0xFB, 0xB6,
0x94, 0xB5, 0xC8, 0x03, 0xD8, 0x9F, 0x7A, 0xE4, 0x35, 0xDE, 0x23, 0x6D, 0x52,
0x5F, 0x54, 0x75,
0x9B, 0x65, 0xE3, 0x72, 0xFC, 0xD6, 0x8E, 0xF2, 0x0F, 0xA7, 0x11, 0x1F, 0x9E,
0x4A, 0xFF, 0x73
};
/*
* myrand is used for test only, eventually it should be replaced by the random
* number. AND it is basically the private key.
*/
/* #define MYRAND */
#ifdef MYRAND
unsigned char myrand[] =
{0x11, 0x11, 0x22, 0x22,
0x33, 0x33, 0x44, 0x44,
0x55, 0x55, 0x66, 0x66,
0x77, 0x77, 0x88, 0x88,
0x99, 0x99, 0x00, 0x00};
#endif /* MYRAND */
/* Node Events */
#define NODE_EVENT_DEVICE_RM 0x0 /* Auth response timeout & fail */
#define NODE_EVENT_DEVICE_RECOVERY 0x1 /* Auth response timeout & recovery */
#define NODE_EVENT_RCV_AUTH_MSG 0x2 /* Unsolicited Auth received */
#define NODE_EVENT_CMPL_AUTH_MSG 0x3
#define NODE_EVENT_MAX_EVENT 0x4
emlxs_table_t emlxs_event_table[] =
{
{NODE_EVENT_DEVICE_RM, "DEVICE_REMOVE"},
{NODE_EVENT_DEVICE_RECOVERY, "DEVICE_RECOVERY"},
{NODE_EVENT_RCV_AUTH_MSG, "AUTH_MSG_RCVD"},
{NODE_EVENT_CMPL_AUTH_MSG, "AUTH_MSG_CMPL"},
}; /* emlxs_event_table() */
emlxs_table_t emlxs_pstate_table[] =
{
{ELX_FABRIC_STATE_UNKNOWN, "FABRIC_STATE_UNKNOWN"},
{ELX_FABRIC_AUTH_DISABLED, "FABRIC_AUTH_DISABLED"},
{ELX_FABRIC_AUTH_FAILED, "FABRIC_AUTH_FAILED"},
{ELX_FABRIC_AUTH_SUCCESS, "FABRIC_AUTH_SUCCESS"},
{ELX_FABRIC_IN_AUTH, "FABRIC_IN_AUTH"},
{ELX_FABRIC_IN_REAUTH, "FABRIC_IN_REAUTH"},
}; /* emlxs_pstate_table() */
emlxs_table_t emlxs_nstate_table[] =
{
{NODE_STATE_UNKNOWN, "STATE_UNKNOWN"},
{NODE_STATE_AUTH_DISABLED, "AUTH_DISABLED"},
{NODE_STATE_AUTH_FAILED, "AUTH_FAILED"},
{NODE_STATE_AUTH_SUCCESS, "AUTH_SUCCESS"},
{NODE_STATE_AUTH_NEGOTIATE_ISSUE, "NEGOTIATE_ISSUE"},
{NODE_STATE_AUTH_NEGOTIATE_RCV, "NEGOTIATE_RCV"},
{NODE_STATE_AUTH_NEGOTIATE_CMPL_WAIT4NEXT, "NEGOTIATE_CMPL"},
{NODE_STATE_DHCHAP_CHALLENGE_ISSUE, "DHCHAP_CHALLENGE_ISSUE"},
{NODE_STATE_DHCHAP_REPLY_ISSUE, "DHCHAP_REPLY_ISSUE"},
{NODE_STATE_DHCHAP_CHALLENGE_CMPL_WAIT4NEXT, "DHCHAP_CHALLENGE_CMPL"},
{NODE_STATE_DHCHAP_REPLY_CMPL_WAIT4NEXT, "DHCHAP_REPLY_CMPL"},
{NODE_STATE_DHCHAP_SUCCESS_ISSUE, "DHCHAP_SUCCESS_ISSUE"},
{NODE_STATE_DHCHAP_SUCCESS_ISSUE_WAIT4NEXT, "DHCHAP_SUCCESS_ISSUE_WAIT"},
{NODE_STATE_DHCHAP_SUCCESS_CMPL_WAIT4NEXT, "DHCHAP_SUCCESS_CMPL"},
}; /* emlxs_nstate_table() */
extern char *
emlxs_dhc_event_xlate(uint32_t state)
{
static char buffer[32];
uint32_t i;
uint32_t count;
count = sizeof (emlxs_event_table) / sizeof (emlxs_table_t);
for (i = 0; i < count; i++) {
if (state == emlxs_event_table[i].code) {
return (emlxs_event_table[i].string);
}
}
(void) snprintf(buffer, sizeof (buffer), "event=0x%x", state);
return (buffer);
} /* emlxs_dhc_event_xlate() */
extern void
emlxs_dhc_state(emlxs_port_t *port, emlxs_node_t *ndlp, uint32_t state,
uint32_t reason, uint32_t explaination)
{
emlxs_hba_t *hba = HBA;
emlxs_port_dhc_t *port_dhc = &port->port_dhc;
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
uint32_t pstate;
if ((state != NODE_STATE_NOCHANGE) && (node_dhc->state != state)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_state_msg,
"Node:0x%x %s --> %s", ndlp->nlp_DID,
emlxs_dhc_nstate_xlate(node_dhc->state),
emlxs_dhc_nstate_xlate(state));
node_dhc->prev_state = node_dhc->state;
node_dhc->state = (uint16_t)state;
/* Perform common functions based on state */
switch (state) {
case NODE_STATE_UNKNOWN:
case NODE_STATE_AUTH_DISABLED:
node_dhc->nlp_authrsp_tmo = 0;
node_dhc->nlp_authrsp_tmocnt = 0;
emlxs_dhc_set_reauth_time(port, ndlp, DISABLE);
break;
case NODE_STATE_AUTH_SUCCESS:
/* Record auth time */
if (ndlp->nlp_DID == FABRIC_DID) {
port_dhc->auth_time = DRV_TIME;
} else if (node_dhc->parent_auth_cfg) {
node_dhc->parent_auth_cfg->auth_time = DRV_TIME;
}
hba->rdn_flag = 0;
node_dhc->nlp_authrsp_tmo = 0;
if (node_dhc->flag & NLP_SET_REAUTH_TIME) {
emlxs_dhc_set_reauth_time(port, ndlp, ENABLE);
}
break;
default:
break;
}
/* Check for switch port */
if (ndlp->nlp_DID == FABRIC_DID) {
switch (state) {
case NODE_STATE_UNKNOWN:
pstate = ELX_FABRIC_STATE_UNKNOWN;
break;
case NODE_STATE_AUTH_DISABLED:
pstate = ELX_FABRIC_AUTH_DISABLED;
break;
case NODE_STATE_AUTH_FAILED:
pstate = ELX_FABRIC_AUTH_FAILED;
break;
case NODE_STATE_AUTH_SUCCESS:
pstate = ELX_FABRIC_AUTH_SUCCESS;
break;
/* Auth active */
default:
if (port_dhc->state ==
ELX_FABRIC_AUTH_SUCCESS) {
pstate = ELX_FABRIC_IN_REAUTH;
} else if (port_dhc->state !=
ELX_FABRIC_IN_REAUTH) {
pstate = ELX_FABRIC_IN_AUTH;
}
break;
}
if (port_dhc->state != pstate) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_state_msg,
"Port: %s --> %s",
emlxs_dhc_pstate_xlate(port_dhc->state),
emlxs_dhc_pstate_xlate(pstate));
port_dhc->state = pstate;
}
}
}
/* Update auth status */
mutex_enter(&hba->auth_lock);
emlxs_dhc_status(port, ndlp, reason, explaination);
mutex_exit(&hba->auth_lock);
return;
} /* emlxs_dhc_state() */
/* auth_lock must be held when calling this */
extern void
emlxs_dhc_status(emlxs_port_t *port, emlxs_node_t *ndlp, uint32_t reason,
uint32_t explaination)
{
emlxs_port_dhc_t *port_dhc;
emlxs_node_dhc_t *node_dhc;
dfc_auth_status_t *auth_status;
uint32_t drv_time;
if (!ndlp || !ndlp->nlp_active || ndlp->node_dhc.state ==
NODE_STATE_UNKNOWN) {
return;
}
port_dhc = &port->port_dhc;
node_dhc = &ndlp->node_dhc;
/* Get auth status object */
if (ndlp->nlp_DID == FABRIC_DID) {
auth_status = &port_dhc->auth_status;
} else if (node_dhc->parent_auth_cfg) {
auth_status = &node_dhc->parent_auth_cfg->auth_status;
} else {
/* No auth status to be updated */
return;
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_status_msg,
"Node:0x%x state=%s rsn=0x%x exp=0x%x (%x,%x)",
ndlp->nlp_DID, emlxs_dhc_nstate_xlate(node_dhc->state), reason,
explaination, auth_status->auth_state,
auth_status->auth_failReason);
/* Set state and auth_failReason */
switch (node_dhc->state) {
case NODE_STATE_UNKNOWN: /* Connection */
if (auth_status->auth_state != DFC_AUTH_STATE_FAILED) {
auth_status->auth_state = DFC_AUTH_STATE_OFF;
auth_status->auth_failReason = 0;
}
break;
case NODE_STATE_AUTH_DISABLED:
auth_status->auth_state = DFC_AUTH_STATE_OFF;
auth_status->auth_failReason = 0;
break;
case NODE_STATE_AUTH_FAILED:
/* Check failure reason and update if neccessary */
switch (reason) {
case AUTHRJT_FAILURE: /* 0x01 */
case AUTHRJT_LOGIC_ERR: /* 0x02 */
auth_status->auth_state = DFC_AUTH_STATE_FAILED;
auth_status->auth_failReason = DFC_AUTH_FAIL_REJECTED;
break;
case LSRJT_AUTH_REQUIRED: /* 0x03 */
switch (explaination) {
case LSEXP_AUTH_REQUIRED:
auth_status->auth_state = DFC_AUTH_STATE_FAILED;
auth_status->auth_failReason =
DFC_AUTH_FAIL_LS_RJT;
break;
default:
auth_status->auth_state = DFC_AUTH_STATE_FAILED;
auth_status->auth_failReason =
DFC_AUTH_FAIL_REJECTED;
}
break;
case LSRJT_AUTH_LOGICAL_BSY: /* 0x05 */
auth_status->auth_state = DFC_AUTH_STATE_FAILED;
auth_status->auth_failReason = DFC_AUTH_FAIL_BSY_LS_RJT;
break;
case LSRJT_AUTH_ELS_NOT_SUPPORTED: /* 0x0B */
auth_status->auth_state = DFC_AUTH_STATE_FAILED;
auth_status->auth_failReason = DFC_AUTH_FAIL_LS_RJT;
break;
case LSRJT_AUTH_NOT_LOGGED_IN: /* 0x09 */
auth_status->auth_state = DFC_AUTH_STATE_FAILED;
auth_status->auth_failReason = DFC_AUTH_FAIL_BSY_LS_RJT;
break;
}
/* Make sure the state is set to failed at this point */
if (auth_status->auth_state != DFC_AUTH_STATE_FAILED) {
auth_status->auth_state = DFC_AUTH_STATE_FAILED;
auth_status->auth_failReason = DFC_AUTH_FAIL_GENERIC;
}
break;
case NODE_STATE_AUTH_SUCCESS:
auth_status->auth_state = DFC_AUTH_STATE_ON;
auth_status->auth_failReason = 0;
break;
/* Authentication currently active */
default:
/* Set defaults */
auth_status->auth_state = DFC_AUTH_STATE_INP;
auth_status->auth_failReason = 0;
/* Check codes for exceptions */
switch (reason) {
case AUTHRJT_FAILURE: /* 0x01 */
switch (explaination) {
case AUTHEXP_AUTH_FAILED: /* 0x05 */
case AUTHEXP_BAD_PAYLOAD: /* 0x06 */
case AUTHEXP_BAD_PROTOCOL: /* 0x07 */
auth_status->auth_state = DFC_AUTH_STATE_FAILED;
auth_status->auth_failReason =
DFC_AUTH_FAIL_REJECTED;
break;
}
break;
case AUTHRJT_LOGIC_ERR: /* 0x02 */
switch (explaination) {
case AUTHEXP_MECH_UNUSABLE: /* 0x01 */
case AUTHEXP_DHGROUP_UNUSABLE: /* 0x02 */
case AUTHEXP_HASHFUNC_UNUSABLE: /* 0x03 */
case AUTHEXP_CONCAT_UNSUPP: /* 0x09 */
case AUTHEXP_BAD_PROTOVERS: /* 0x0A */
auth_status->auth_state = DFC_AUTH_STATE_FAILED;
auth_status->auth_failReason =
DFC_AUTH_FAIL_REJECTED;
break;
}
break;
case LSRJT_AUTH_REQUIRED: /* 0x03 */
switch (explaination) {
case LSEXP_AUTH_REQUIRED:
auth_status->auth_state = DFC_AUTH_STATE_FAILED;
auth_status->auth_failReason =
DFC_AUTH_FAIL_LS_RJT;
break;
}
break;
case LSRJT_AUTH_LOGICAL_BSY: /* 0x05 */
auth_status->auth_state = DFC_AUTH_STATE_FAILED;
auth_status->auth_failReason = DFC_AUTH_FAIL_BSY_LS_RJT;
break;
case LSRJT_AUTH_ELS_NOT_SUPPORTED: /* 0x0B */
auth_status->auth_state = DFC_AUTH_STATE_FAILED;
auth_status->auth_failReason = DFC_AUTH_FAIL_LS_RJT;
break;
case LSRJT_AUTH_NOT_LOGGED_IN: /* 0x09 */
auth_status->auth_state = DFC_AUTH_STATE_FAILED;
auth_status->auth_failReason = DFC_AUTH_FAIL_BSY_LS_RJT;
break;
}
break;
}
if (auth_status->auth_state != DFC_AUTH_STATE_ON) {
auth_status->time_until_next_auth = 0;
auth_status->localAuth = 0;
auth_status->remoteAuth = 0;
auth_status->group_priority = 0;
auth_status->hash_priority = 0;
auth_status->type_priority = 0;
} else {
switch (node_dhc->nlp_reauth_status) {
case NLP_HOST_REAUTH_ENABLED:
case NLP_HOST_REAUTH_IN_PROGRESS:
drv_time = DRV_TIME;
if (node_dhc->nlp_reauth_tmo > drv_time) {
auth_status->time_until_next_auth =
node_dhc->nlp_reauth_tmo - drv_time;
} else {
auth_status->time_until_next_auth = 0;
}
break;
case NLP_HOST_REAUTH_DISABLED:
default:
auth_status->time_until_next_auth = 0;
break;
}
if (node_dhc->flag & NLP_REMOTE_AUTH) {
auth_status->localAuth = 0;
auth_status->remoteAuth = 1;
} else {
auth_status->localAuth = 1;
auth_status->remoteAuth = 0;
}
auth_status->type_priority = DFC_AUTH_TYPE_DHCHAP;
switch (node_dhc->nlp_auth_dhgpid) {
case GROUP_NULL:
auth_status->group_priority = ELX_GROUP_NULL;
break;
case GROUP_1024:
auth_status->group_priority = ELX_GROUP_1024;
break;
case GROUP_1280:
auth_status->group_priority = ELX_GROUP_1280;
break;
case GROUP_1536:
auth_status->group_priority = ELX_GROUP_1536;
break;
case GROUP_2048:
auth_status->group_priority = ELX_GROUP_2048;
break;
}
switch (node_dhc->nlp_auth_hashid) {
case 0:
auth_status->hash_priority = 0;
break;
case AUTH_SHA1:
auth_status->hash_priority = ELX_SHA1;
break;
case AUTH_MD5:
auth_status->hash_priority = ELX_MD5;
break;
}
}
return;
} /* emlxs_dhc_status() */
static char *
emlxs_dhc_pstate_xlate(uint32_t state)
{
static char buffer[32];
uint32_t i;
uint32_t count;
count = sizeof (emlxs_pstate_table) / sizeof (emlxs_table_t);
for (i = 0; i < count; i++) {
if (state == emlxs_pstate_table[i].code) {
return (emlxs_pstate_table[i].string);
}
}
(void) snprintf(buffer, sizeof (buffer), "state=0x%x", state);
return (buffer);
} /* emlxs_dhc_pstate_xlate() */
static char *
emlxs_dhc_nstate_xlate(uint32_t state)
{
static char buffer[32];
uint32_t i;
uint32_t count;
count = sizeof (emlxs_nstate_table) / sizeof (emlxs_table_t);
for (i = 0; i < count; i++) {
if (state == emlxs_nstate_table[i].code) {
return (emlxs_nstate_table[i].string);
}
}
(void) snprintf(buffer, sizeof (buffer), "state=0x%x", state);
return (buffer);
} /* emlxs_dhc_nstate_xlate() */
static uint32_t
emlxs_check_dhgp(
emlxs_port_t *port,
NODELIST *ndlp,
uint32_t *dh_id,
uint16_t cnt,
uint32_t *dhgp_id)
{
uint32_t i, j, rc = 1;
uint32_t wnt;
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"dhgp: 0x%x, id[0..4]=0x%x 0x%x 0x%x 0x%x 0x%x pri[1]=0x%x",
cnt, dh_id[0], dh_id[1], dh_id[2], dh_id[3], dh_id[4],
node_dhc->auth_cfg.dh_group_priority[1]);
/*
* Here are the rules, as the responder We always try to select ours
* highest setup
*/
/* Check to see if there is any repeated dhgp in initiator's list */
/* If available, it is a invalid payload */
if (cnt >= 2) {
for (i = 0; i <= cnt - 2; i++) {
for (j = i + 1; j <= cnt - 1; j++) {
if (dh_id[i] == dh_id[j]) {
rc = 2;
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_detail_msg,
":Rpt dhid[%x]=%x dhid[%x]=%x",
i, dh_id[i], j, dh_id[j]);
break;
}
}
if (rc == 2) {
break;
}
}
if ((i == cnt - 1) && (j == cnt)) {
rc = 1;
}
if (rc == 2) {
/* duplicate invalid payload */
return (rc);
}
}
/* Check how many dhgps the responder specified */
wnt = 0;
while (node_dhc->auth_cfg.dh_group_priority[wnt] != 0xF) {
wnt++;
}
/* Determine the most suitable dhgp the responder should use */
for (i = 0; i < wnt; i++) {
for (j = 0; j < cnt; j++) {
if (node_dhc->auth_cfg.dh_group_priority[i] ==
dh_id[j]) {
rc = 0;
*dhgp_id =
node_dhc->auth_cfg.dh_group_priority[i];
break;
}
}
if (rc == 0) {
break;
}
}
if (i == wnt) {
/* no match */
rc = 1;
return (1);
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"check_dhgp: dhgp_id=0x%x", *dhgp_id);
return (rc);
} /* emlxs_check_dhgp */
static void
emlxs_get_random_bytes(
NODELIST *ndlp,
uint8_t *rdn,
uint32_t len)
{
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
hrtime_t now;
uint8_t sha1_digest[20];
SHA1_CTX sha1ctx;
now = gethrtime();
bzero(&sha1ctx, sizeof (SHA1_CTX));
SHA1Init(&sha1ctx);
SHA1Update(&sha1ctx, (void *) &node_dhc->auth_cfg.local_entity,
sizeof (NAME_TYPE));
SHA1Update(&sha1ctx, (void *) &now, sizeof (hrtime_t));
SHA1Final((void *) sha1_digest, &sha1ctx);
bcopy((void *) &sha1_digest[0], (void *) &rdn[0], len);
return;
} /* emlxs_get_random_bytes */
/* **************************** STATE MACHINE ************************** */
static void *emlxs_dhchap_action[] =
{
/* Action routine Event */
/* NODE_STATE_UNKNOWN 0x00 */
(void *) emlxs_disc_neverdev, /* DEVICE_RM */
(void *) emlxs_disc_neverdev, /* DEVICE_RECOVERY */
(void *) emlxs_disc_neverdev, /* RCV_AUTH_MSG */
(void *) emlxs_disc_neverdev, /* CMPL_AUTH_MSG */
/* NODE_STATE_AUTH_DISABLED 0x01 */
(void *) emlxs_disc_neverdev, /* DEVICE_RM */
(void *) emlxs_disc_neverdev, /* DEVICE_RECOVERY */
(void *) emlxs_disc_neverdev, /* RCV_AUTH_MSG */
(void *) emlxs_disc_neverdev, /* CMPL_AUTH_MSG */
/* NODE_STATE_AUTH_FAILED 0x02 */
(void *) emlxs_device_rm_npr_node, /* DEVICE_RM */
(void *) emlxs_device_recov_npr_node, /* DEVICE_RECOVERY */
(void *) emlxs_rcv_auth_msg_npr_node, /* RCV_AUTH_MSG */
(void *) emlxs_cmpl_auth_msg_npr_node, /* CMPL_AUTH_MSG */
/* NODE_STATE_AUTH_SUCCESS 0x03 */
(void *) emlxs_disc_neverdev, /* DEVICE_RM */
(void *) emlxs_device_recov_unmapped_node, /* DEVICE_RECOVERY */
(void *) emlxs_rcv_auth_msg_unmapped_node, /* RCV_AUTH_MSG */
(void *) emlxs_disc_neverdev, /* CMPL_AUTH_MSG */
/* NODE_STATE_AUTH_NEGOTIATE_ISSUE 0x04 */
(void *) emlxs_device_rem_auth, /* DEVICE_RM */
(void *) emlxs_device_recov_auth, /* DEVICE_RECOVERY */
(void *) emlxs_rcv_auth_msg_auth_negotiate_issue, /* RCV_AUTH_MSG */
(void *) emlxs_cmpl_auth_msg_auth_negotiate_issue, /* CMPL_AUTH_MSG */
/* NODE_STATE_AUTH_NEGOTIATE_RCV 0x05 */
(void *) emlxs_device_rem_auth, /* DEVICE_RM */
(void *) emlxs_device_recov_auth, /* DEVICE_RECOVERY */
(void *) emlxs_rcv_auth_msg_auth_negotiate_rcv, /* RCV_AUTH_MSG */
(void *) emlxs_cmpl_auth_msg_auth_negotiate_rcv, /* CMPL_AUTH_MSG */
/* NODE_STATE_AUTH_NEGOTIATE_CMPL_WAIT4NEXT 0x06 */
(void *) emlxs_device_rem_auth, /* DEVICE_RM */
(void *) emlxs_device_recov_auth, /* DEVICE_RECOVERY */
(void *) emlxs_rcv_auth_msg_auth_negotiate_cmpl_wait4next,
/* RCV_AUTH_MSG */
(void *) emlxs_cmpl_auth_msg_auth_negotiate_cmpl_wait4next,
/* CMPL_AUTH_MSG */
/* NODE_STATE_DHCHAP_CHALLENGE_ISSUE 0x07 */
(void *) emlxs_device_rem_auth, /* DEVICE_RM */
(void *) emlxs_device_recov_auth, /* DEVICE_RECOVERY */
(void *) emlxs_rcv_auth_msg_dhchap_challenge_issue, /* RCV_AUTH_MSG */
(void *) emlxs_cmpl_auth_msg_dhchap_challenge_issue, /* CMPL_AUTH_MSG */
/* NODE_STATE_DHCHAP_REPLY_ISSUE 0x08 */
(void *) emlxs_device_rem_auth, /* DEVICE_RM */
(void *) emlxs_device_recov_auth, /* DEVICE_RECOVERY */
(void *) emlxs_rcv_auth_msg_dhchap_reply_issue, /* RCV_AUTH_MSG */
(void *) emlxs_cmpl_auth_msg_dhchap_reply_issue, /* CMPL_AUTH_MSG */
/* NODE_STATE_DHCHAP_CHALLENGE_CMPL_WAIT4NEXT 0x09 */
(void *) emlxs_device_rem_auth, /* DEVICE_RM */
(void *) emlxs_device_recov_auth, /* DEVICE_RECOVERY */
(void *) emlxs_rcv_auth_msg_dhchap_challenge_cmpl_wait4next,
/* RCV_AUTH_MSG */
(void *) emlxs_cmpl_auth_msg_dhchap_challenge_cmpl_wait4next,
/* CMPL_AUTH_MSG */
/* NODE_STATE_DHCHAP_REPLY_CMPL_WAIT4NEXT 0x0A */
(void *) emlxs_device_rem_auth, /* DEVICE_RM */
(void *) emlxs_device_recov_auth, /* DEVICE_RECOVERY */
(void *) emlxs_rcv_auth_msg_dhchap_reply_cmpl_wait4next,
/* RCV_AUTH_MSG */
(void *) emlxs_cmpl_auth_msg_dhchap_reply_cmpl_wait4next,
/* CMPL_AUTH_MSG */
/* NODE_STATE_DHCHAP_SUCCESS_ISSUE 0x0B */
(void *) emlxs_device_rem_auth, /* DEVICE_RM */
(void *) emlxs_device_recov_auth, /* DEVICE_RECOVERY */
(void *) emlxs_rcv_auth_msg_dhchap_success_issue,
/* RCV_AUTH_MSG */
(void *) emlxs_cmpl_auth_msg_dhchap_success_issue,
/* CMPL_AUTH_MSG */
/* NODE_STATE_DHCHAP_SUCCESS_ISSUE_WAIT4NEXT 0x0C */
(void *) emlxs_device_rem_auth, /* DEVICE_RM */
(void *) emlxs_device_recov_auth, /* DEVICE_RECOVERY */
(void *) emlxs_rcv_auth_msg_dhchap_success_issue_wait4next,
/* RCV_AUTH_MSG */
(void *) emlxs_cmpl_auth_msg_dhchap_success_issue_wait4next,
/* CMPL_AUTH_MSG */
/* NODE_STATE_DHCHAP_SUCCESS_CMPL_WAIT4NEXT 0x0D */
(void *) emlxs_device_rem_auth, /* DEVICE_RM */
(void *) emlxs_device_recov_auth, /* DEVICE_RECOVERY */
(void *) emlxs_rcv_auth_msg_dhchap_success_cmpl_wait4next,
/* RCV_AUTH_MSG */
(void *) emlxs_cmpl_auth_msg_dhchap_success_cmpl_wait4next,
/* CMPL_AUTH_MSG */
}; /* emlxs_dhchap_action[] */
extern int
emlxs_dhchap_state_machine(emlxs_port_t *port, CHANNEL *cp,
IOCBQ *iocbq, MATCHMAP *mp,
NODELIST *ndlp, int evt)
{
emlxs_hba_t *hba = HBA;
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
uint32_t rc;
uint32_t(*func) (emlxs_port_t *, CHANNEL *, IOCBQ *, MATCHMAP *,
NODELIST *, uint32_t);
mutex_enter(&hba->dhc_lock);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_event_msg,
"%s: did=0x%x",
emlxs_dhc_event_xlate(evt), ndlp->nlp_DID);
node_dhc->disc_refcnt++;
func = (uint32_t(*) (emlxs_port_t *, CHANNEL *, IOCBQ *, MATCHMAP *,
NODELIST *, uint32_t))
emlxs_dhchap_action[(node_dhc->state * NODE_EVENT_MAX_EVENT) + evt];
rc = (func) (port, cp, iocbq, mp, ndlp, evt);
node_dhc->disc_refcnt--;
mutex_exit(&hba->dhc_lock);
return (rc);
} /* emlxs_dhchap_state_machine() */
/* ARGSUSED */
static uint32_t
emlxs_disc_neverdev(
emlxs_port_t *port,
/* CHANNEL * rp, */ void *arg1,
/* IOCBQ * iocbq, */ void *arg2,
/* MATCHMAP * mp, */ void *arg3,
/* NODELIST * ndlp */ void *arg4,
uint32_t evt)
{
NODELIST *ndlp = (NODELIST *) arg4;
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"disc_neverdev: did=0x%x.",
ndlp->nlp_DID);
emlxs_dhc_state(port, ndlp, NODE_STATE_UNKNOWN, 0, 0);
return (node_dhc->state);
} /* emlxs_disc_neverdev() */
/*
* ! emlxs_cmpl_dhchap_challenge_issue
*
* \pre \post \param cmdiocb \param rspiocb \return void
*
* \b Description: iocb_cmpl callback function. when the ELS DHCHAP_Challenge
* msg sent back got the ACC/RJT from initiator.
*
*/
static void
emlxs_cmpl_dhchap_challenge_issue(fc_packet_t *pkt)
{
emlxs_port_t *port = pkt->pkt_ulp_private;
emlxs_buf_t *sbp;
NODELIST *ndlp;
uint32_t did;
did = pkt->pkt_cmd_fhdr.d_id;
sbp = (emlxs_buf_t *)pkt->pkt_fca_private;
ndlp = sbp->node;
if (!ndlp) {
ndlp = emlxs_node_find_did(port, did, 1);
}
if (pkt->pkt_state != FC_PKT_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"cmpl_dhchap_challenge_issue: did=0x%x state=%x",
did, pkt->pkt_state);
} else {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"cmpl_dhchap_challenge_issue: did=0x%x. Succcess.",
did);
}
if (ndlp) {
if (pkt->pkt_state == FC_PKT_SUCCESS) {
(void) emlxs_dhchap_state_machine(port, NULL, NULL,
NULL, ndlp, NODE_EVENT_CMPL_AUTH_MSG);
}
}
emlxs_pkt_free(pkt);
return;
} /* emlxs_cmpl_dhchap_challenge_issue */
/*
* ! emlxs_cmpl_dhchap_success_issue
*
* \pre \post \param phba \param cmdiocb \param rspiocb \return void
*
* \b Description: iocb_cmpl callback function.
*
*/
static void
emlxs_cmpl_dhchap_success_issue(fc_packet_t *pkt)
{
emlxs_port_t *port = pkt->pkt_ulp_private;
NODELIST *ndlp;
uint32_t did;
emlxs_buf_t *sbp;
did = pkt->pkt_cmd_fhdr.d_id;
sbp = (emlxs_buf_t *)pkt->pkt_fca_private;
ndlp = sbp->node;
if (!ndlp) {
ndlp = emlxs_node_find_did(port, did, 1);
}
if (pkt->pkt_state != FC_PKT_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"cmpl_dhchap_success_issue: 0x%x %x. No retry.",
did, pkt->pkt_state);
} else {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"cmpl_dhchap_success_issue: did=0x%x. Succcess.",
did);
}
if (ndlp) {
if (pkt->pkt_state == FC_PKT_SUCCESS) {
(void) emlxs_dhchap_state_machine(port, NULL, NULL,
NULL, ndlp, NODE_EVENT_CMPL_AUTH_MSG);
}
}
emlxs_pkt_free(pkt);
return;
} /* emlxs_cmpl_dhchap_success_issue */
/*
* if rsp == NULL, this is only the DHCHAP_Success msg
*
* if rsp != NULL, DHCHAP_Success contains rsp to the challenge.
*/
/* ARGSUSED */
uint32_t
emlxs_issue_dhchap_success(
emlxs_port_t *port,
NODELIST *ndlp,
int retry,
uint8_t *rsp)
{
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
fc_packet_t *pkt;
uint32_t cmd_size;
uint32_t rsp_size;
uint8_t *pCmd;
uint16_t cmdsize;
DHCHAP_SUCCESS_HDR *ap;
uint8_t *tmp;
uint32_t len;
uint32_t ret;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"issue_dhchap_success: did=0x%x", ndlp->nlp_DID);
if (ndlp->nlp_DID == FABRIC_DID) {
if (node_dhc->nlp_auth_hashid == AUTH_MD5)
len = MD5_LEN;
else
len = SHA1_LEN;
} else {
len = (node_dhc->nlp_auth_hashid == AUTH_MD5) ?
MD5_LEN : SHA1_LEN;
}
if (rsp == NULL) {
cmdsize = sizeof (DHCHAP_SUCCESS_HDR);
} else {
cmdsize = sizeof (DHCHAP_SUCCESS_HDR) + len;
}
cmd_size = cmdsize;
rsp_size = 4;
if ((pkt = emlxs_prep_els_fc_pkt(port, ndlp->nlp_DID, cmd_size,
rsp_size, 0, KM_NOSLEEP)) == NULL) {
return (1);
}
pCmd = (uint8_t *)pkt->pkt_cmd;
ap = (DHCHAP_SUCCESS_HDR *)pCmd;
tmp = (uint8_t *)pCmd;
ap->auth_els_code = ELS_CMD_AUTH_CODE;
ap->auth_els_flags = 0x0;
ap->auth_msg_code = DHCHAP_SUCCESS;
ap->proto_version = 0x01;
/*
* In case of rsp == NULL meaning that this is DHCHAP_Success issued
* when Host is the initiator AND this DHCHAP_Success is issused in
* response to the bi-directional authentication, meaning Host
* authenticate another entity, therefore no more DHCHAP_Success
* expected. OR this DHCHAP_Success is issued by host when host is
* the responder BUT it is uni-directional auth, therefore no more
* DHCHAP_Success expected.
*
* In case of rsp != NULL it indicates this DHCHAP_Success is issued
* when host is the responder AND this DHCHAP_Success has reply
* embedded therefore the host expects DHCHAP_Success from other
* entity in transaction.
*/
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"issue_dhchap_success: 0x%x 0x%x 0x%x 0x%x 0x%x %p",
ndlp->nlp_DID, node_dhc->nlp_auth_hashid,
node_dhc->nlp_auth_tranid_rsp,
node_dhc->nlp_auth_tranid_ini, cmdsize, rsp);
if (rsp == NULL) {
ap->msg_len = LE_SWAP32(0x00000004);
ap->RspVal_len = 0x0;
node_dhc->fc_dhchap_success_expected = 0;
} else {
node_dhc->fc_dhchap_success_expected = 1;
ap->msg_len = LE_SWAP32(4 + len);
tmp += sizeof (DHCHAP_SUCCESS_HDR) - sizeof (uint32_t);
*(uint32_t *)tmp = LE_SWAP32(len);
tmp += sizeof (uint32_t);
bcopy((void *)rsp, (void *)tmp, len);
}
if (node_dhc->nlp_reauth_status == NLP_HOST_REAUTH_IN_PROGRESS) {
ap->tran_id = LE_SWAP32(node_dhc->nlp_auth_tranid_rsp);
} else {
if (node_dhc->nlp_auth_flag == 2) {
ap->tran_id =
LE_SWAP32(node_dhc->nlp_auth_tranid_rsp);
} else if (node_dhc->nlp_auth_flag == 1) {
ap->tran_id =
LE_SWAP32(node_dhc->nlp_auth_tranid_ini);
} else {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_debug_msg,
"is_dhch_success: (1) 0x%x 0x%x 0x%x 0x%x",
ndlp->nlp_DID, node_dhc->nlp_auth_flag,
node_dhc->nlp_auth_tranid_rsp,
node_dhc->nlp_auth_tranid_ini);
return (1);
}
}
pkt->pkt_comp = emlxs_cmpl_dhchap_success_issue;
ret = emlxs_pkt_send(pkt, 1);
if (ret != FC_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"issue_dhchap_success: Unable to send packet. 0x%x",
ret);
emlxs_pkt_free(pkt);
return (1);
}
return (0);
} /* emlxs_issue_dhchap_success */
/*
* ! emlxs_cmpl_auth_reject_issue
*
* \pre \post \param phba \param cmdiocb \param rspiocb \return void
*
* \b Description: iocb_cmpl callback function.
*
*/
static void
emlxs_cmpl_auth_reject_issue(fc_packet_t *pkt)
{
emlxs_port_t *port = pkt->pkt_ulp_private;
emlxs_buf_t *sbp;
NODELIST *ndlp;
uint32_t did;
did = pkt->pkt_cmd_fhdr.d_id;
sbp = (emlxs_buf_t *)pkt->pkt_fca_private;
ndlp = sbp->node;
if (!ndlp) {
ndlp = emlxs_node_find_did(port, did, 1);
}
if (pkt->pkt_state != FC_PKT_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"cmpl_auth_reject_issue: 0x%x %x. No retry.",
did, pkt->pkt_state);
} else {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"cmpl_auth_reject_issue: did=0x%x. Succcess.",
did);
}
if (ndlp) {
/* setup the new state */
emlxs_dhc_state(port, ndlp, NODE_STATE_AUTH_FAILED, 0, 0);
if (pkt->pkt_state == FC_PKT_SUCCESS) {
(void) emlxs_dhchap_state_machine(port, NULL, NULL,
NULL, ndlp, NODE_EVENT_CMPL_AUTH_MSG);
}
}
emlxs_pkt_free(pkt);
return;
} /* emlxs_cmpl_auth_reject_issue */
/*
* If Logical Error and Reason Code Explanation is "Restart Authentication
* Protocol" then the Transaction Identifier could be
* any value.
*/
/* ARGSUSED */
static uint32_t
emlxs_issue_auth_reject(
emlxs_port_t *port,
NODELIST *ndlp,
int retry,
uint32_t *arg,
uint8_t ReasonCode,
uint8_t ReasonCodeExplanation)
{
fc_packet_t *pkt;
uint32_t cmd_size;
uint32_t rsp_size;
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
uint16_t cmdsize;
AUTH_RJT *ap;
char info[64];
if (node_dhc->nlp_authrsp_tmo) {
node_dhc->nlp_authrsp_tmo = 0;
}
cmdsize = sizeof (AUTH_RJT);
cmd_size = cmdsize;
rsp_size = 4;
if ((pkt = emlxs_prep_els_fc_pkt(port, ndlp->nlp_DID, cmd_size,
rsp_size, 0, KM_NOSLEEP)) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"Auth reject failed: Unable to allocate pkt. 0x%x %x %x",
ndlp->nlp_DID, ReasonCode, ReasonCodeExplanation);
return (1);
}
ap = (AUTH_RJT *) pkt->pkt_cmd;
ap->auth_els_code = ELS_CMD_AUTH_CODE;
ap->auth_els_flags = 0x0;
ap->auth_msg_code = AUTH_REJECT;
ap->proto_version = 0x01;
ap->msg_len = LE_SWAP32(4);
if (node_dhc->nlp_auth_flag == 2) {
ap->tran_id = LE_SWAP32(node_dhc->nlp_auth_tranid_rsp);
} else if (node_dhc->nlp_auth_flag == 1) {
ap->tran_id = LE_SWAP32(node_dhc->nlp_auth_tranid_ini);
} else {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"Auth reject failed.Invalid flag=%d. 0x%x %x expl=%x",
ndlp->nlp_DID, node_dhc->nlp_auth_flag, ReasonCode,
ReasonCodeExplanation);
emlxs_pkt_free(pkt);
return (1);
}
ap->ReasonCode = ReasonCode;
ap->ReasonCodeExplanation = ReasonCodeExplanation;
pkt->pkt_comp = emlxs_cmpl_auth_reject_issue;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_debug_msg,
"Auth reject: did=0x%x reason=%x expl=%x",
ndlp->nlp_DID, ReasonCode, ReasonCodeExplanation);
if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"Auth reject failed. Unable to send pkt. 0x%x %x expl=%x",
ndlp->nlp_DID, node_dhc->nlp_auth_flag, ReasonCode,
ReasonCodeExplanation);
emlxs_pkt_free(pkt);
return (1);
}
(void) snprintf(info, sizeof (info),
"Auth-Reject: ReasonCode=0x%x, ReasonCodeExplanation=0x%x",
ReasonCode, ReasonCodeExplanation);
emlxs_log_auth_event(port, ndlp, "issue_auth_reject", info);
return (0);
} /* emlxs_issue_auth_reject */
static fc_packet_t *
emlxs_prep_els_fc_pkt(
emlxs_port_t *port,
uint32_t d_id,
uint32_t cmd_size,
uint32_t rsp_size,
uint32_t datalen,
int32_t sleepflag)
{
fc_packet_t *pkt;
/* simulate the ULP stack's fc_packet send out */
if (!(pkt = emlxs_pkt_alloc(port, cmd_size, rsp_size,
datalen, sleepflag))) {
return (NULL);
}
pkt->pkt_tran_type = FC_PKT_EXCHANGE;
pkt->pkt_timeout = 35;
/* Build the fc header */
pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(d_id);
pkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ;
pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
pkt->pkt_cmd_fhdr.f_ctl =
F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE;
pkt->pkt_cmd_fhdr.seq_id = 0;
pkt->pkt_cmd_fhdr.df_ctl = 0;
pkt->pkt_cmd_fhdr.seq_cnt = 0;
pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
pkt->pkt_cmd_fhdr.rx_id = 0xFFFF;
pkt->pkt_cmd_fhdr.ro = 0;
return ((fc_packet_t *)pkt);
} /* emlxs_prep_els_fc_pkt */
/*
* ! emlxs_issue_auth_negotiate
*
* \pre \post \param port \param ndlp \param retry \param flag \return
* int
*
* \b Description:
*
* The routine is invoked when host as the authentication initiator which
* issue the AUTH_ELS command AUTH_Negotiate to the other
* entity ndlp. When this Auth_Negotiate command is completed, the iocb_cmpl
* will get called as the solicited mbox cmd
* callback. Some switch only support NULL dhchap in which case negotiate
* should be modified to only have NULL DH specificed.
*
*/
/* ARGSUSED */
static int
emlxs_issue_auth_negotiate(
emlxs_port_t *port,
emlxs_node_t *ndlp,
uint8_t retry)
{
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
fc_packet_t *pkt;
uint32_t cmd_size;
uint32_t rsp_size;
uint16_t cmdsize;
AUTH_MSG_NEGOT_NULL_1 *null_ap1;
AUTH_MSG_NEGOT_NULL_2 *null_ap2;
uint32_t num_hs = 0;
uint8_t flag;
AUTH_MSG_NEGOT_1 *ap1;
AUTH_MSG_NEGOT_2 *ap2;
uint16_t para_len = 0;
uint16_t hash_wcnt = 0;
uint16_t dhgp_wcnt = 0;
emlxs_dhc_state(port, ndlp, NODE_STATE_AUTH_NEGOTIATE_ISSUE, 0, 0);
/* Full DH group support limit:2, only NULL group support limit:1 */
flag = (node_dhc->nlp_auth_limit == 2) ? 1 : 0;
/* first: determine the cmdsize based on the auth cfg parameters */
if (flag == 1) {
/* May be Full DH group + 2 hash may not be */
cmdsize = sizeof (AUTH_MSG_NEGOT_NULL);
cmdsize += 2 + 2; /* name tag: 2, name length: 2 */
cmdsize += 8; /* WWN: 8 */
cmdsize += 4; /* num of protocol: 4 */
cmdsize += 4; /* protocol parms length: 4 */
cmdsize += 4; /* protocol id: 4 */
para_len += 4;
cmdsize += 2 + 2; /* hashlist: tag: 2, count:2 */
para_len += 4;
if (node_dhc->auth_cfg.hash_priority[1] == 0x00) {
/* only one hash func */
cmdsize += 4;
num_hs = 1;
para_len += 4;
hash_wcnt = 1;
} else {
/* two hash funcs */
cmdsize += 4 + 4;
num_hs = 2;
para_len += 4 + 4;
hash_wcnt = 2;
}
cmdsize += 2 + 2;
para_len += 4;
if (node_dhc->auth_cfg.dh_group_priority[1] == 0xf) {
/* only one dhgp specified: could be NULL or non-NULL */
cmdsize += 4;
para_len += 4;
dhgp_wcnt = 1;
} else if (node_dhc->auth_cfg.dh_group_priority[2] == 0xf) {
/* two dhgps specified */
cmdsize += 4 + 4;
para_len += 4 + 4;
dhgp_wcnt = 2;
} else if (node_dhc->auth_cfg.dh_group_priority[3] == 0xf) {
/* three dhgps specified */
cmdsize += 4 + 4 + 4;
para_len += 4 + 4 + 4;
dhgp_wcnt = 3;
} else if (node_dhc->auth_cfg.dh_group_priority[4] == 0xf) {
/* four dhgps specified */
cmdsize += 4 + 4 + 4 + 4;
para_len += 4 + 4 + 4 + 4;
dhgp_wcnt = 4;
} else if (node_dhc->auth_cfg.dh_group_priority[5] == 0xf) {
cmdsize += 4 + 4 + 4 + 4 + 4;
para_len += 4 + 4 + 4 + 4 + 4;
dhgp_wcnt = 5;
}
} else {
cmdsize = sizeof (AUTH_MSG_NEGOT_NULL);
/*
* get the right payload size in byte: determined by config
* parameters
*/
cmdsize += 2 + 2 + 8; /* name tag:2, name length:2, name */
/* value content:8 */
cmdsize += 4; /* number of usable authentication */
/* protocols:4 */
cmdsize += 4; /* auth protocol params length: 4 */
cmdsize += 4; /* auth protocol identifier: 4 */
/* hash list infor */
cmdsize += 4; /* hashlist: tag:2, count:2 */
if (node_dhc->auth_cfg.hash_priority[1] == 0x00) {
cmdsize += 4; /* only one hash function provided */
num_hs = 1;
} else {
num_hs = 2;
cmdsize += 4 + 4; /* sha1: 4, md5: 4 */
}
/* dhgp list info */
/* since this is NULL DH group */
cmdsize += 4; /* dhgroup: tag:2, count:2 */
cmdsize += 4; /* set it to zero */
}
cmd_size = cmdsize;
rsp_size = 4;
if ((pkt = emlxs_prep_els_fc_pkt(port, ndlp->nlp_DID, cmd_size,
rsp_size, 0, KM_NOSLEEP)) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"issue_auth_negotiate: Unable to allocate pkt. 0x%x %d",
ndlp->nlp_DID, cmd_size);
return (1);
}
/* Fill in AUTH_MSG_NEGOT payload */
if (flag == 1) {
if (hash_wcnt == 1) {
ap1 = (AUTH_MSG_NEGOT_1 *)pkt->pkt_cmd;
ap1->auth_els_code = ELS_CMD_AUTH_CODE;
ap1->auth_els_flags = 0x00;
ap1->auth_msg_code = AUTH_NEGOTIATE;
ap1->proto_version = 0x01;
ap1->msg_len = LE_SWAP32(cmdsize -
sizeof (AUTH_MSG_NEGOT_NULL));
} else {
ap2 = (AUTH_MSG_NEGOT_2 *)pkt->pkt_cmd;
ap2->auth_els_code = ELS_CMD_AUTH_CODE;
ap2->auth_els_flags = 0x00;
ap2->auth_msg_code = AUTH_NEGOTIATE;
ap2->proto_version = 0x01;
ap2->msg_len = LE_SWAP32(cmdsize -
sizeof (AUTH_MSG_NEGOT_NULL));
}
} else {
if (node_dhc->auth_cfg.hash_priority[1] == 0x00) {
null_ap1 = (AUTH_MSG_NEGOT_NULL_1 *)pkt->pkt_cmd;
null_ap1->auth_els_code = ELS_CMD_AUTH_CODE;
null_ap1->auth_els_flags = 0x0;
null_ap1->auth_msg_code = AUTH_NEGOTIATE;
null_ap1->proto_version = 0x01;
null_ap1->msg_len = LE_SWAP32(cmdsize -
sizeof (AUTH_MSG_NEGOT_NULL));
} else {
null_ap2 = (AUTH_MSG_NEGOT_NULL_2 *)pkt->pkt_cmd;
null_ap2->auth_els_code = ELS_CMD_AUTH_CODE;
null_ap2->auth_els_flags = 0x0;
null_ap2->auth_msg_code = AUTH_NEGOTIATE;
null_ap2->proto_version = 0x01;
null_ap2->msg_len = LE_SWAP32(cmdsize -
sizeof (AUTH_MSG_NEGOT_NULL));
}
}
/*
* For host reauthentication heart beat, the tran_id is incremented
* by one for each heart beat being fired and round back to 1 when
* 0xffffffff is reached. tran_id 0 is reserved as the initial linkup
* authentication transaction id.
*/
/* responder flag:2, initiator flag:1 */
node_dhc->nlp_auth_flag = 2; /* ndlp is the always the auth */
/* responder */
if (node_dhc->nlp_reauth_status == NLP_HOST_REAUTH_IN_PROGRESS) {
if (node_dhc->nlp_auth_tranid_rsp == 0xffffffff) {
node_dhc->nlp_auth_tranid_rsp = 1;
} else {
node_dhc->nlp_auth_tranid_rsp++;
}
} else { /* !NLP_HOST_REAUTH_IN_PROGRESS */
node_dhc->nlp_auth_tranid_rsp = 0;
}
if (flag == 1) {
if (hash_wcnt == 1) {
ap1->tran_id =
LE_SWAP32(node_dhc->nlp_auth_tranid_rsp);
ap1->params.name_tag = AUTH_NAME_ID;
ap1->params.name_len = AUTH_NAME_LEN;
bcopy((void *)&port->wwpn,
(void *) &ap1->params.nodeName, sizeof (NAME_TYPE));
ap1->params.proto_num = AUTH_PROTO_NUM;
ap1->params.para_len = LE_SWAP32(para_len);
ap1->params.proto_id = AUTH_DHCHAP;
ap1->params.HashList_tag = HASH_LIST_TAG;
ap1->params.HashList_wcnt = LE_SWAP16(hash_wcnt);
ap1->params.HashList_value1 =
node_dhc->auth_cfg.hash_priority[0];
ap1->params.DHgIDList_tag = DHGID_LIST_TAG;
ap1->params.DHgIDList_wnt = LE_SWAP16(dhgp_wcnt);
switch (dhgp_wcnt) {
case 5:
ap1->params.DHgIDList_g4 =
(node_dhc->auth_cfg.dh_group_priority[4]);
ap1->params.DHgIDList_g3 =
(node_dhc->auth_cfg.dh_group_priority[3]);
ap1->params.DHgIDList_g2 =
(node_dhc->auth_cfg.dh_group_priority[2]);
ap1->params.DHgIDList_g1 =
(node_dhc->auth_cfg.dh_group_priority[1]);
ap1->params.DHgIDList_g0 =
(node_dhc->auth_cfg.dh_group_priority[0]);
break;
case 4:
ap1->params.DHgIDList_g3 =
(node_dhc->auth_cfg.dh_group_priority[3]);
ap1->params.DHgIDList_g2 =
(node_dhc->auth_cfg.dh_group_priority[2]);
ap1->params.DHgIDList_g1 =
(node_dhc->auth_cfg.dh_group_priority[1]);
ap1->params.DHgIDList_g0 =
(node_dhc->auth_cfg.dh_group_priority[0]);
break;
case 3:
ap1->params.DHgIDList_g2 =
(node_dhc->auth_cfg.dh_group_priority[2]);
ap1->params.DHgIDList_g1 =
(node_dhc->auth_cfg.dh_group_priority[1]);
ap1->params.DHgIDList_g0 =
(node_dhc->auth_cfg.dh_group_priority[0]);
break;
case 2:
ap1->params.DHgIDList_g1 =
(node_dhc->auth_cfg.dh_group_priority[1]);
ap1->params.DHgIDList_g0 =
(node_dhc->auth_cfg.dh_group_priority[0]);
break;
case 1:
ap1->params.DHgIDList_g0 =
(node_dhc->auth_cfg.dh_group_priority[0]);
break;
}
} else {
ap2->tran_id =
LE_SWAP32(node_dhc->nlp_auth_tranid_rsp);
ap2->params.name_tag = AUTH_NAME_ID;
ap2->params.name_len = AUTH_NAME_LEN;
bcopy((void *) &port->wwpn,
(void *) &ap2->params.nodeName, sizeof (NAME_TYPE));
ap2->params.proto_num = AUTH_PROTO_NUM;
ap2->params.para_len = LE_SWAP32(para_len);
ap2->params.proto_id = AUTH_DHCHAP;
ap2->params.HashList_tag = HASH_LIST_TAG;
ap2->params.HashList_wcnt = LE_SWAP16(hash_wcnt);
ap2->params.HashList_value1 =
(node_dhc->auth_cfg.hash_priority[0]);
ap2->params.HashList_value2 =
(node_dhc->auth_cfg.hash_priority[1]);
ap2->params.DHgIDList_tag = DHGID_LIST_TAG;
ap2->params.DHgIDList_wnt = LE_SWAP16(dhgp_wcnt);
switch (dhgp_wcnt) {
case 5:
ap2->params.DHgIDList_g4 =
(node_dhc->auth_cfg.dh_group_priority[4]);
ap2->params.DHgIDList_g3 =
(node_dhc->auth_cfg.dh_group_priority[3]);
ap2->params.DHgIDList_g2 =
(node_dhc->auth_cfg.dh_group_priority[2]);
ap2->params.DHgIDList_g1 =
(node_dhc->auth_cfg.dh_group_priority[1]);
ap2->params.DHgIDList_g0 =
(node_dhc->auth_cfg.dh_group_priority[0]);
break;
case 4:
ap2->params.DHgIDList_g3 =
(node_dhc->auth_cfg.dh_group_priority[3]);
ap2->params.DHgIDList_g2 =
(node_dhc->auth_cfg.dh_group_priority[2]);
ap2->params.DHgIDList_g1 =
(node_dhc->auth_cfg.dh_group_priority[1]);
ap2->params.DHgIDList_g0 =
(node_dhc->auth_cfg.dh_group_priority[0]);
break;
case 3:
ap2->params.DHgIDList_g2 =
(node_dhc->auth_cfg.dh_group_priority[2]);
ap2->params.DHgIDList_g1 =
(node_dhc->auth_cfg.dh_group_priority[1]);
ap2->params.DHgIDList_g0 =
(node_dhc->auth_cfg.dh_group_priority[0]);
break;
case 2:
ap2->params.DHgIDList_g1 =
(node_dhc->auth_cfg.dh_group_priority[1]);
ap2->params.DHgIDList_g0 =
(node_dhc->auth_cfg.dh_group_priority[0]);
break;
case 1:
ap2->params.DHgIDList_g0 =
(node_dhc->auth_cfg.dh_group_priority[0]);
break;
}
}
} else {
if (num_hs == 1) {
null_ap1->tran_id =
LE_SWAP32(node_dhc->nlp_auth_tranid_rsp);
null_ap1->params.name_tag = AUTH_NAME_ID;
null_ap1->params.name_len = AUTH_NAME_LEN;
bcopy((void *) &port->wwpn,
(void *) &null_ap1->params.nodeName,
sizeof (NAME_TYPE));
null_ap1->params.proto_num = AUTH_PROTO_NUM;
null_ap1->params.para_len = LE_SWAP32(0x00000014);
null_ap1->params.proto_id = AUTH_DHCHAP;
null_ap1->params.HashList_tag = HASH_LIST_TAG;
null_ap1->params.HashList_wcnt = LE_SWAP16(0x0001);
null_ap1->params.HashList_value1 =
(node_dhc->auth_cfg.hash_priority[0]);
null_ap1->params.DHgIDList_tag = DHGID_LIST_TAG;
null_ap1->params.DHgIDList_wnt = LE_SWAP16(0x0001);
null_ap1->params.DHgIDList_g0 = 0x0;
} else {
null_ap2->tran_id =
LE_SWAP32(node_dhc->nlp_auth_tranid_rsp);
null_ap2->params.name_tag = AUTH_NAME_ID;
null_ap2->params.name_len = AUTH_NAME_LEN;
bcopy((void *) &port->wwpn,
(void *) &null_ap2->params.nodeName,
sizeof (NAME_TYPE));
null_ap2->params.proto_num = AUTH_PROTO_NUM;
null_ap2->params.para_len = LE_SWAP32(0x00000018);
null_ap2->params.proto_id = AUTH_DHCHAP;
null_ap2->params.HashList_tag = HASH_LIST_TAG;
null_ap2->params.HashList_wcnt = LE_SWAP16(0x0002);
null_ap2->params.HashList_value1 =
(node_dhc->auth_cfg.hash_priority[0]);
null_ap2->params.HashList_value2 =
(node_dhc->auth_cfg.hash_priority[1]);
null_ap2->params.DHgIDList_tag = DHGID_LIST_TAG;
null_ap2->params.DHgIDList_wnt = LE_SWAP16(0x0001);
null_ap2->params.DHgIDList_g0 = 0x0;
}
}
pkt->pkt_comp = emlxs_cmpl_auth_negotiate_issue;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_debug_msg,
"issue_auth_negotiate: %x flag=%d size=%d hash=%x,%x tid=%x,%x",
ndlp->nlp_DID, flag, cmd_size,
node_dhc->auth_cfg.hash_priority[0],
node_dhc->auth_cfg.hash_priority[1],
node_dhc->nlp_auth_tranid_rsp, node_dhc->nlp_auth_tranid_ini);
if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
emlxs_pkt_free(pkt);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"issue_auth_negotiate: Unable to send pkt. did=0x%x",
ndlp->nlp_DID);
return (1);
}
return (0);
} /* emlxs_issue_auth_negotiate() */
/*
* ! emlxs_cmpl_auth_negotiate_issue
*
* \pre \post \param phba \param cmdiocb \param rspiocb \return void
*
* \b Description: iocb_cmpl callback function.
*
*/
static void
emlxs_cmpl_auth_negotiate_issue(fc_packet_t *pkt)
{
emlxs_port_t *port = pkt->pkt_ulp_private;
emlxs_buf_t *sbp;
NODELIST *ndlp;
emlxs_node_dhc_t *node_dhc;
uint32_t did;
did = pkt->pkt_cmd_fhdr.d_id;
sbp = (emlxs_buf_t *)pkt->pkt_fca_private;
ndlp = sbp->node;
node_dhc = &ndlp->node_dhc;
if (!ndlp) {
ndlp = emlxs_node_find_did(port, did, 1);
}
if (pkt->pkt_state != FC_PKT_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"cmpl_dhchap_negotiate_issue: 0x%x %x. Noretry.",
did, pkt->pkt_state);
} else {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"cmpl_dhchap_negotiate_issue: did=0x%x. Succcess.",
did);
}
if (ndlp) {
if (pkt->pkt_state == FC_PKT_SUCCESS) {
(void) emlxs_dhchap_state_machine(port, NULL, NULL,
NULL, ndlp, NODE_EVENT_CMPL_AUTH_MSG);
} else {
emlxs_dhc_set_reauth_time(port, ndlp, DISABLE);
emlxs_dhc_state(port, ndlp, NODE_STATE_AUTH_FAILED,
0, 0);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_debug_msg,
"Reauth disabled. did=0x%x state=%x",
ndlp->nlp_DID, node_dhc->state);
emlxs_dhc_auth_complete(port, ndlp, 1);
}
}
emlxs_pkt_free(pkt);
return;
} /* emlxs_cmpl_auth_negotiate_issue */
/*
* ! emlxs_cmpl_auth_msg_auth_negotiate_issue
*
* \pre \post \param port \param CHANNEL * rp \param arg \param evt
* \return uint32_t \b Description:
*
* This routine is invoked when the host receive the solicited ACC/RJT ELS
* cmd from an NxPort or FxPort that has received the ELS
* AUTH Negotiate msg from the host. in case of RJT, Auth_Negotiate should
* be retried in emlxs_cmpl_auth_negotiate_issue
* call. in case of ACC, the host must be the initiator because its current
* state could be "AUTH_NEGOTIATE_RCV" if it is the
* responder. Then the next stat = AUTH_NEGOTIATE_CMPL_WAIT4NEXT
*/
/* ARGSUSED */
static uint32_t
emlxs_cmpl_auth_msg_auth_negotiate_issue(
emlxs_port_t *port,
/* CHANNEL * rp, */ void *arg1,
/* IOCBQ * iocbq, */ void *arg2,
/* MATCHMAP * mp, */ void *arg3,
/* NODELIST * ndlp, */ void *arg4,
uint32_t evt)
{
NODELIST *ndlp = (NODELIST *)arg4;
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"cmpl_auth_msg_auth_negotiate_issue: did=0x%x",
ndlp->nlp_DID);
/* start the emlxs_dhc_authrsp_timeout timer */
if (node_dhc->nlp_authrsp_tmo == 0) {
node_dhc->nlp_authrsp_tmo = DRV_TIME +
node_dhc->auth_cfg.authentication_timeout;
}
/*
* The next state should be
* emlxs_rcv_auth_msg_auth_negotiate_cmpl_wait4next
*/
emlxs_dhc_state(port, ndlp, NODE_STATE_AUTH_NEGOTIATE_CMPL_WAIT4NEXT,
0, 0);
return (node_dhc->state);
} /* emlxs_cmpl_auth_msg_auth_negotiate_issue */
/*
* ! emlxs_rcv_auth_msg_auth_negotiate_issue
*
* \pre \post \param phba \param ndlp \param arg \param evt \return
* uint32_t \b Description:
*
* This routine is supported for HBA in either auth initiator mode or
* responder mode.
*
* This routine is invoked when the host receive an unsolicited ELS AUTH Msg
* from an NxPort or FxPort to which the host has just
* sent out an ELS AUTH negotiate msg. and the NxPort or FxPort also LS_ACC
* to the host's AUTH_Negotiate msg.
*
* If this unsolicited ELS auth msg is from the FxPort or a NxPort with a
* numerically lower WWPN, the host will be the winner in
* this authentication transaction initiation phase, the host as the
* initiator will send back ACC and then Auth_Reject message
* with the Reason Code 'Logical Error' and Reason Code Explanation'
* Authentication Transaction Already Started' and with the
* current state unchanged and mark itself as auth_initiator.
*
* Otherwise, the host will be the responder that will reply to the received
* AUTH_Negotiate message will ACC (or RJT?) and abort
* its own transaction upon receipt of the AUTH_Reject message. The new state
* will be "AUTH_NEGOTIATE_RCV" and mark the host as
* auth_responder.
*/
/* ARGSUSED */
static uint32_t
emlxs_rcv_auth_msg_auth_negotiate_issue(
emlxs_port_t *port,
/* CHANNEL * rp, */ void *arg1,
/* IOCBQ * iocbq, */ void *arg2,
/* MATCHMAP * mp, */ void *arg3,
/* NODELIST * ndlp */ void *arg4,
uint32_t evt)
{
NODELIST *ndlp = (NODELIST *)arg4;
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
IOCBQ *iocbq = (IOCBQ *) arg2;
uint8_t ReasonCode;
uint8_t ReasonCodeExplanation;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_auth_msg_auth_negotiate_issue: did=0x%x",
ndlp->nlp_DID);
/* Anyway we accept it first and then send auth_reject */
(void) emlxs_els_reply(port, iocbq, ELS_CMD_ACC, ELS_CMD_AUTH, 0, 0);
/* host is always the initiator and it should win */
ReasonCode = AUTHRJT_LOGIC_ERR;
ReasonCodeExplanation = AUTHEXP_AUTHTRAN_STARTED;
emlxs_dhc_state(port, ndlp, NODE_STATE_AUTH_NEGOTIATE_ISSUE,
ReasonCode, ReasonCodeExplanation);
(void) emlxs_issue_auth_reject(port, ndlp, 0, 0, ReasonCode,
ReasonCodeExplanation);
return (node_dhc->state);
} /* emlxs_rcv_auth_msg_auth_negotiate_issue */
/*
* ! emlxs_cmpl_dhchap_reply_issue
*
* \pre \post \param phba \param cmdiocb \param rspiocb \return void
*
* \b Description: iocb_cmpl callback function.
*
*/
static void
emlxs_cmpl_dhchap_reply_issue(fc_packet_t *pkt)
{
emlxs_port_t *port = pkt->pkt_ulp_private;
emlxs_buf_t *sbp;
NODELIST *ndlp;
uint32_t did;
did = pkt->pkt_cmd_fhdr.d_id;
sbp = (emlxs_buf_t *)pkt->pkt_fca_private;
ndlp = sbp->node;
if (!ndlp) {
ndlp = emlxs_node_find_did(port, did, 1);
}
if (pkt->pkt_state != FC_PKT_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"cmpl_dhchap_reply_issue: 0x%x %x. No retry.",
did, pkt->pkt_state);
} else {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"cmpl_dhchap_reply_issue: did=0x%x. Succcess.",
did);
}
if (ndlp) {
if (pkt->pkt_state == FC_PKT_SUCCESS) {
(void) emlxs_dhchap_state_machine(port, NULL, NULL,
NULL, ndlp, NODE_EVENT_CMPL_AUTH_MSG);
}
}
emlxs_pkt_free(pkt);
return;
} /* emlxs_cmpl_dhchap_reply_issue */
/*
* arg: the AUTH_Negotiate payload from the initiator. payload_len: the
* payload length
*
* We always send out the challenge parameter based on our preference
* order configured on the host side no matter what perference
* order looks like from auth_negotiate . In other words, if the host issue
* the challenge the host will make the decision as to
* what hash function, what dhgp_id is to be used.
*
* This challenge value should not be confused with the challenge value for
* bi-dir as part of reply when host is the initiator.
*/
/* ARGSUSED */
uint32_t
emlxs_issue_dhchap_challenge(
emlxs_port_t *port,
NODELIST *ndlp,
int retry,
void *arg,
uint32_t payload_len,
uint32_t hash_id,
uint32_t dhgp_id)
{
emlxs_hba_t *hba = HBA;
fc_packet_t *pkt;
uint32_t cmd_size;
uint32_t rsp_size;
uint16_t cmdsize = 0;
uint8_t *pCmd;
emlxs_port_dhc_t *port_dhc = &port->port_dhc;
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
DHCHAP_CHALL *chal;
uint8_t *tmp;
uint8_t random_number[20];
uint8_t dhval[256];
uint32_t dhval_len;
uint32_t tran_id;
BIG_ERR_CODE err = BIG_OK;
/*
* we assume the HBAnyware should configure the driver the right
* parameters for challenge. for now, we create our own challenge.
*/
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"issue_dhchap_challenge: did=0x%x hashlist=[%x,%x,%x,%x]",
ndlp->nlp_DID, node_dhc->auth_cfg.hash_priority[0],
node_dhc->auth_cfg.hash_priority[1],
node_dhc->auth_cfg.hash_priority[2],
node_dhc->auth_cfg.hash_priority[3]);
/*
* Here is my own challenge structure:
*
* 1: AUTH_MSG_HDR (12 bytes + 4 bytes + 8 bytes) 2: hasd_id (4
* bytes) 3: dhgp_id (4 bytes) 4: cval_len (4 bytes) 5: cval
* (20 bytes or 16 bytes: cval_len bytes) 6: dhval_len (4 bytes)
* 7: dhval (dhval_len bytes) all these information should be stored
* in port_dhc struct
*/
if (hash_id == AUTH_SHA1) {
cmdsize = (12 + 4 + 8) + (4 + 4 + 4) + 20 + 4;
} else if (hash_id == AUTH_MD5) {
cmdsize = (12 + 4 + 8) + (4 + 4 + 4) + 16 + 4;
} else {
return (1);
}
switch (dhgp_id) {
case GROUP_NULL:
break;
case GROUP_1024:
cmdsize += 128;
break;
case GROUP_1280:
cmdsize += 160;
break;
case GROUP_1536:
cmdsize += 192;
break;
case GROUP_2048:
cmdsize += 256;
break;
default:
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"issue_dhchap_challenge: Invalid dhgp_id=0x%x",
dhgp_id);
return (1);
}
cmd_size = cmdsize;
rsp_size = 4;
if ((pkt = emlxs_prep_els_fc_pkt(port, ndlp->nlp_DID, cmd_size,
rsp_size,
0, KM_NOSLEEP)) == NULL) {
return (1);
}
pCmd = (uint8_t *)pkt->pkt_cmd;
tmp = (uint8_t *)arg;
tmp += 8;
/* collect tran_id: this tran_id is set by the initiator */
tran_id = *(uint32_t *)tmp;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"issue_dhchap_challenge: 0x%x 0x%x 0x%x %d 0x%x 0x%x 0x%x",
ndlp->nlp_DID, node_dhc->nlp_auth_tranid_ini,
node_dhc->nlp_auth_tranid_rsp,
cmdsize, tran_id, hash_id, dhgp_id);
/* store the tran_id : ndlp is the initiator */
node_dhc->nlp_auth_tranid_ini = LE_SWAP32(tran_id);
tmp += sizeof (uint32_t);
chal = (DHCHAP_CHALL *)pCmd;
chal->cnul.msg_hdr.auth_els_code = ELS_CMD_AUTH_CODE;
chal->cnul.msg_hdr.auth_els_flags = 0x0;
chal->cnul.msg_hdr.auth_msg_code = DHCHAP_CHALLENGE;
chal->cnul.msg_hdr.proto_version = 0x01;
chal->cnul.msg_hdr.msg_len = LE_SWAP32(cmdsize - 12);
chal->cnul.msg_hdr.tran_id = tran_id;
chal->cnul.msg_hdr.name_tag = (AUTH_NAME_ID);
chal->cnul.msg_hdr.name_len = (AUTH_NAME_LEN);
bcopy((void *) &port->wwpn,
(void *) &chal->cnul.msg_hdr.nodeName, sizeof (NAME_TYPE));
chal->cnul.hash_id = hash_id;
chal->cnul.dhgp_id = dhgp_id;
chal->cnul.cval_len = ((chal->cnul.hash_id == AUTH_SHA1) ?
LE_SWAP32(SHA1_LEN) : LE_SWAP32(MD5_LEN));
tmp = (uint8_t *)pCmd;
tmp += sizeof (DHCHAP_CHALL_NULL);
#ifdef RAND
/* generate a random number as the challenge */
bzero(random_number, LE_SWAP32(chal->cnul.cval_len));
if (hba->rdn_flag == 1) {
emlxs_get_random_bytes(ndlp, random_number, 20);
} else {
(void) random_get_pseudo_bytes(random_number,
LE_SWAP32(chal->cnul.cval_len));
}
/*
* the host should store the challenge for later usage when later on
* host get the reply msg, host needs to verify it by using its old
* challenge, its private key as the input to the hash function. the
* challenge as the random_number should be stored in
* node_dhc->hrsp_cval[]
*/
if (ndlp->nlp_DID == FABRIC_DID) {
bcopy((void *) &random_number[0],
(void *) &node_dhc->hrsp_cval[0],
LE_SWAP32(chal->cnul.cval_len));
/* save another copy in partner's ndlp */
bcopy((void *) &random_number[0],
(void *) &node_dhc->nlp_auth_misc.hrsp_cval[0],
LE_SWAP32(chal->cnul.cval_len));
} else {
bcopy((void *) &random_number[0],
(void *) &node_dhc->nlp_auth_misc.hrsp_cval[0],
LE_SWAP32(chal->cnul.cval_len));
}
bcopy((void *) &random_number[0], (void *) tmp,
LE_SWAP32(chal->cnul.cval_len));
#endif /* RAND */
/* for test only hardcode the challenge value */
#ifdef MYRAND
if (ndlp->nlp_DID == FABRIC_DID) {
bcopy((void *) myrand, (void *) &node_dhc->hrsp_cval[0],
LE_SWAP32(chal->cnul.cval_len));
/* save another copy in partner's ndlp */
bcopy((void *) myrand,
(void *) &node_dhc->nlp_auth_misc.hrsp_cval[0],
LE_SWAP32(chal->cnul.cval_len));
} else {
bcopy((void *) myrand,
(void *) &node_dhc->nlp_auth_misc.hrsp_cval[0],
LE_SWAP32(chal->cnul.cval_len));
}
bcopy((void *) myrand, (void *) tmp,
LE_SWAP32(chal->cnul.cval_len));
#endif /* MYRAND */
if (ndlp->nlp_DID == FABRIC_DID) {
node_dhc->hrsp_cval_len = LE_SWAP32(chal->cnul.cval_len);
node_dhc->nlp_auth_misc.hrsp_cval_len =
LE_SWAP32(chal->cnul.cval_len);
} else {
node_dhc->nlp_auth_misc.hrsp_cval_len =
LE_SWAP32(chal->cnul.cval_len);
}
tmp += LE_SWAP32(chal->cnul.cval_len);
/*
* we need another random number as the private key x which will be
* used to compute the public key i.e. g^x mod p we intentionally set
* the length of private key as the same length of challenge. we have
* to store the private key in node_dhc->hrsp_priv_key[20].
*/
#ifdef RAND
if (dhgp_id != GROUP_NULL) {
bzero(random_number, LE_SWAP32(chal->cnul.cval_len));
if (hba->rdn_flag == 1) {
emlxs_get_random_bytes(ndlp, random_number, 20);
} else {
(void) random_get_pseudo_bytes(random_number,
LE_SWAP32(chal->cnul.cval_len));
}
if (ndlp->nlp_DID == FABRIC_DID) {
bcopy((void *) &random_number[0],
(void *) node_dhc->hrsp_priv_key,
LE_SWAP32(chal->cnul.cval_len));
bcopy((void *) &random_number[0],
(void *) node_dhc->nlp_auth_misc.hrsp_priv_key,
LE_SWAP32(chal->cnul.cval_len));
} else {
bcopy((void *) &random_number[0],
(void *) node_dhc->nlp_auth_misc.hrsp_priv_key,
LE_SWAP32(chal->cnul.cval_len));
}
}
#endif /* RAND */
#ifdef MYRAND
if (dhgp_id != GROUP_NULL) {
/* For test only we hardcode the priv_key here */
bcopy((void *) myrand, (void *) node_dhc->hrsp_priv_key,
LE_SWAP32(chal->cnul.cval_len));
if (ndlp->nlp_DID == FABRIC_DID) {
bcopy((void *) myrand,
(void *) node_dhc->hrsp_priv_key,
LE_SWAP32(chal->cnul.cval_len));
bcopy((void *) myrand,
(void *) node_dhc->nlp_auth_misc.hrsp_priv_key,
LE_SWAP32(chal->cnul.cval_len));
} else {
bcopy((void *) myrand,
(void *) node_dhc->nlp_auth_misc.hrsp_priv_key,
LE_SWAP32(chal->cnul.cval_len));
}
}
#endif /* MYRAND */
/* also store the hash function and dhgp_id being used in challenge. */
/* These information could be configurable through HBAnyware */
node_dhc->nlp_auth_hashid = hash_id;
node_dhc->nlp_auth_dhgpid = dhgp_id;
/*
* generate the DH value DH value is g^x mod p and it is also called
* public key in which g is 2, x is the random number ontained above.
* p is the dhgp3_pVal
*/
#ifdef MYRAND
/* to get (g^x mod p) with x private key */
if (dhgp_id != GROUP_NULL) {
err = emlxs_BIGNUM_get_dhval(port, port_dhc, ndlp, dhval,
&dhval_len, chal->cnul.dhgp_id,
myrand, LE_SWAP32(chal->cnul.cval_len));
if (err != BIG_OK) {
emlxs_pkt_free(pkt);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"issue_dhchap_challenge: error. 0x%x",
err);
return (1);
}
/* we are not going to use dhval and dhval_len */
/* *(uint32_t *)tmp = dhval_len; */
if (ndlp->nlp_DID == FABRIC_DID) {
*(uint32_t *)tmp =
LE_SWAP32(node_dhc->hrsp_pubkey_len);
} else {
*(uint32_t *)tmp =
LE_SWAP32(
node_dhc->nlp_auth_misc.hrsp_pubkey_len);
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"issue_dhchap_challenge: 0x%x: 0x%x 0x%x",
ndlp->nlp_DID, *(uint32_t *)tmp, dhval_len);
tmp += sizeof (uint32_t);
if (ndlp->nlp_DID == FABRIC_DID) {
bcopy((void *) node_dhc->hrsp_pub_key, (void *)tmp,
node_dhc->hrsp_pubkey_len);
} else {
bcopy((void *) node_dhc->nlp_auth_misc.hrsp_pub_key,
(void *)tmp,
node_dhc->nlp_auth_misc.hrsp_pubkey_len);
}
} else {
/* NULL DHCHAP */
*(uint32_t *)tmp = 0;
}
#endif /* MYRAND */
#ifdef RAND
/* to get (g^x mod p) with x private key */
if (dhgp_id != GROUP_NULL) {
err = emlxs_BIGNUM_get_dhval(port, port_dhc, ndlp, dhval,
&dhval_len, chal->cnul.dhgp_id,
random_number, LE_SWAP32(chal->cnul.cval_len));
if (err != BIG_OK) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"issue_dhchap_challenge: error. 0x%x",
err);
emlxs_pkt_free(pkt);
return (1);
}
/* we are not going to use dhval and dhval_len */
/* *(uint32_t *)tmp = dhval_len; */
if (ndlp->nlp_DID == FABRIC_DID) {
*(uint32_t *)tmp =
LE_SWAP32(node_dhc->hrsp_pubkey_len);
} else {
*(uint32_t *)tmp =
LE_SWAP32(
node_dhc->nlp_auth_misc.hrsp_pubkey_len);
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"issue_dhchap_challenge: did=0x%x: pubkey_len=0x%x",
ndlp->nlp_DID, *(uint32_t *)tmp);
tmp += sizeof (uint32_t);
if (ndlp->nlp_DID == FABRIC_DID) {
bcopy((void *) node_dhc->hrsp_pub_key, (void *)tmp,
node_dhc->hrsp_pubkey_len);
} else {
bcopy((void *) node_dhc->nlp_auth_misc.hrsp_pub_key,
(void *)tmp,
node_dhc->nlp_auth_misc.hrsp_pubkey_len);
}
} else {
/* NULL DHCHAP */
*(uint32_t *)tmp = 0;
}
#endif /* RAND */
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"issue_dhchap_challenge: 0x%x 0x%x 0x%x 0x%x 0x%x",
ndlp->nlp_DID, node_dhc->nlp_auth_tranid_ini,
node_dhc->nlp_auth_tranid_rsp,
chal->cnul.hash_id, chal->cnul.dhgp_id);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"issue_dhchap_challenge: 0x%x 0x%x 0x%x 0x%x",
ndlp->nlp_DID, tran_id, node_dhc->nlp_auth_hashid,
node_dhc->nlp_auth_dhgpid);
pkt->pkt_comp = emlxs_cmpl_dhchap_challenge_issue;
if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
emlxs_pkt_free(pkt);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"issue_dhchap_challenge: Unable to send fc packet.");
return (1);
}
return (0);
} /* emlxs_issue_dhchap_challenge */
/*
* DHCHAP_Reply msg
*/
/* ARGSUSED */
uint32_t
emlxs_issue_dhchap_reply(
emlxs_port_t *port,
NODELIST *ndlp,
int retry,
uint32_t *arg1, /* response */
uint8_t *dhval,
uint32_t dhval_len,
uint8_t *arg2, /* random number */
uint32_t arg2_len)
{
fc_packet_t *pkt;
uint32_t cmd_size;
uint32_t rsp_size;
uint16_t cmdsize = 0;
DHCHAP_REPLY_HDR *ap;
uint8_t *pCmd;
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
/* Header size */
cmdsize = sizeof (DHCHAP_REPLY_HDR);
/* Rsp value len size (4) + Response value size */
if (ndlp->nlp_DID == FABRIC_DID) {
if (node_dhc->hash_id == AUTH_MD5) {
cmdsize += 4 + MD5_LEN;
}
if (node_dhc->hash_id == AUTH_SHA1) {
cmdsize += 4 + SHA1_LEN;
}
} else {
if (node_dhc->nlp_auth_hashid == AUTH_MD5) {
cmdsize += 4 + MD5_LEN;
}
if (node_dhc->nlp_auth_hashid == AUTH_SHA1) {
cmdsize += 4 + SHA1_LEN;
}
}
/* DH value len size (4) + DH value size */
if (ndlp->nlp_DID == FABRIC_DID) {
switch (node_dhc->dhgp_id) {
case GROUP_NULL:
break;
case GROUP_1024:
case GROUP_1280:
case GROUP_1536:
case GROUP_2048:
default:
break;
}
}
cmdsize += 4 + dhval_len;
/* Challenge value len size (4) + Challenge value size */
if (node_dhc->auth_cfg.bidirectional == 0) {
cmdsize += 4;
} else {
if (ndlp->nlp_DID == FABRIC_DID) {
cmdsize += 4 + ((node_dhc->hash_id == AUTH_MD5) ?
MD5_LEN : SHA1_LEN);
} else {
cmdsize += 4 +
((node_dhc->nlp_auth_hashid == AUTH_MD5) ? MD5_LEN :
SHA1_LEN);
}
}
cmd_size = cmdsize;
rsp_size = 4;
if ((pkt = emlxs_prep_els_fc_pkt(port, ndlp->nlp_DID, cmd_size,
rsp_size, 0, KM_NOSLEEP)) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"issue_dhchap_reply failed: did=0x%x size=%x,%x",
ndlp->nlp_DID, cmd_size, rsp_size);
return (1);
}
pCmd = (uint8_t *)pkt->pkt_cmd;
ap = (DHCHAP_REPLY_HDR *)pCmd;
ap->auth_els_code = ELS_CMD_AUTH_CODE;
ap->auth_els_flags = 0x0;
ap->auth_msg_code = DHCHAP_REPLY;
ap->proto_version = 0x01;
ap->msg_len = LE_SWAP32(cmdsize - sizeof (DHCHAP_REPLY_HDR));
ap->tran_id = LE_SWAP32(node_dhc->nlp_auth_tranid_rsp);
pCmd = (uint8_t *)(pCmd + sizeof (DHCHAP_REPLY_HDR));
if (ndlp->nlp_DID == FABRIC_DID) {
if (node_dhc->hash_id == AUTH_MD5) {
*(uint32_t *)pCmd = LE_SWAP32(MD5_LEN);
} else {
*(uint32_t *)pCmd = LE_SWAP32(SHA1_LEN);
}
} else {
if (node_dhc->nlp_auth_hashid == AUTH_MD5) {
*(uint32_t *)pCmd = LE_SWAP32(MD5_LEN);
} else {
*(uint32_t *)pCmd = LE_SWAP32(SHA1_LEN);
}
}
pCmd = (uint8_t *)(pCmd + 4);
if (ndlp->nlp_DID == FABRIC_DID) {
if (node_dhc->hash_id == AUTH_MD5) {
bcopy((void *)arg1, pCmd, MD5_LEN);
pCmd = (uint8_t *)(pCmd + MD5_LEN);
} else {
bcopy((void *)arg1, (void *)pCmd, SHA1_LEN);
pCmd = (uint8_t *)(pCmd + SHA1_LEN);
}
} else {
if (node_dhc->nlp_auth_hashid == AUTH_MD5) {
bcopy((void *)arg1, pCmd, MD5_LEN);
pCmd = (uint8_t *)(pCmd + MD5_LEN);
} else {
bcopy((void *)arg1, (void *)pCmd, SHA1_LEN);
pCmd = (uint8_t *)(pCmd + SHA1_LEN);
}
}
*(uint32_t *)pCmd = LE_SWAP32(dhval_len);
if (dhval_len != 0) {
pCmd = (uint8_t *)(pCmd + 4);
switch (node_dhc->dhgp_id) {
case GROUP_NULL:
break;
case GROUP_1024:
case GROUP_1280:
case GROUP_1536:
case GROUP_2048:
default:
break;
}
/* elx_bcopy((void *)dhval, (void *)pCmd, dhval_len); */
/*
* The new DH parameter (g^y mod p) is stored in
* node_dhc->pub_key
*/
/* pubkey_len should be equal to dhval_len */
if (ndlp->nlp_DID == FABRIC_DID) {
bcopy((void *) node_dhc->pub_key, (void *)pCmd,
node_dhc->pubkey_len);
} else {
bcopy((void *) node_dhc->nlp_auth_misc.pub_key,
(void *)pCmd,
node_dhc->nlp_auth_misc.pubkey_len);
}
pCmd = (uint8_t *)(pCmd + dhval_len);
} else
pCmd = (uint8_t *)(pCmd + 4);
if (node_dhc->auth_cfg.bidirectional == 0) {
*(uint32_t *)pCmd = 0x0;
} else {
if (ndlp->nlp_DID == FABRIC_DID) {
if (node_dhc->hash_id == AUTH_MD5) {
*(uint32_t *)pCmd = LE_SWAP32(MD5_LEN);
pCmd = (uint8_t *)(pCmd + 4);
bcopy((void *)arg2, (void *)pCmd, arg2_len);
} else if (node_dhc->hash_id == AUTH_SHA1) {
*(uint32_t *)pCmd = LE_SWAP32(SHA1_LEN);
pCmd = (uint8_t *)(pCmd + 4);
/* store the challenge */
bcopy((void *)arg2, (void *)pCmd, arg2_len);
}
} else {
if (node_dhc->nlp_auth_hashid == AUTH_MD5) {
*(uint32_t *)pCmd = LE_SWAP32(MD5_LEN);
pCmd = (uint8_t *)(pCmd + 4);
bcopy((void *)arg2, (void *)pCmd, arg2_len);
} else if (node_dhc->nlp_auth_hashid == AUTH_SHA1) {
*(uint32_t *)pCmd = LE_SWAP32(SHA1_LEN);
pCmd = (uint8_t *)(pCmd + 4);
bcopy((void *)arg2, (void *)pCmd, arg2_len);
}
}
}
pkt->pkt_comp = emlxs_cmpl_dhchap_reply_issue;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"issue_dhchap_reply: did=0x%x (%x,%x,%x,%x,%x,%x)",
ndlp->nlp_DID, dhval_len, arg2_len, cmdsize,
node_dhc->hash_id, node_dhc->nlp_auth_hashid,
LE_SWAP32(ap->tran_id));
if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"issue_dhchap_reply failed: Unable to send packet.");
emlxs_pkt_free(pkt);
return (1);
}
return (0);
} /* emlxs_issue_dhchap_reply */
/*
* ! emlxs_rcv_auth_msg_auth_negotiate_cmpl_wait4next
*
* \pre \post \param phba \param ndlp \param arg \param evt \return
* uint32_t \b Description:
*
* This routine is invoked when the host received an unsolicted ELS AUTH MSG
* from an NxPort or FxPort which already replied (ACC)
* the ELS AUTH_Negotiate msg from the host. if msg is DHCHAP_Chellenge,
* based on the msg content (DHCHAP computation etc.,)
* the host send back ACC and 1. send back AUTH_Reject and set next state =
* NPR_NODE or 2. send back DHCHAP_Reply msg and set
* next state = DHCHAP_REPLY_ISSUE for bi-directional, the DHCHAP_Reply
* includes challenge from host. for uni-directional, no
* more challenge. if msg is AUTH_Reject or anything else, host send back
* ACC and set next state = NPR_NODE. And based on the
* reject code, host may need to retry negotiate with NULL DH only
*
* If the msg is AUTH_ELS cmd, cancel the nlp_authrsp_timeout timer immediately.
*
*/
/* ARGSUSED */
static uint32_t
emlxs_rcv_auth_msg_auth_negotiate_cmpl_wait4next(
emlxs_port_t *port,
/* CHANNEL * rp, */ void *arg1,
/* IOCBQ * iocbq, */ void *arg2,
/* MATCHMAP * mp, */ void *arg3,
/* NODELIST * ndlp */ void *arg4,
uint32_t evt)
{
emlxs_hba_t *hba = HBA;
emlxs_port_dhc_t *port_dhc = &port->port_dhc;
IOCBQ *iocbq = (IOCBQ *)arg2;
MATCHMAP *mp = (MATCHMAP *)arg3;
NODELIST *ndlp = (NODELIST *)arg4;
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
uint8_t *bp;
uint32_t *lp;
DHCHAP_CHALL_NULL *ncval;
uint16_t namelen;
uint32_t dhvallen;
uint8_t *tmp;
uint8_t ReasonCode;
uint8_t ReasonCodeExplanation;
union challenge_val un_cval;
uint8_t *dhval = NULL;
uint8_t random_number[20]; /* for both SHA1 and MD5 */
uint32_t *arg5 = NULL; /* response */
uint32_t tran_id; /* Transaction Identifier */
uint32_t arg2len = 0; /* len of new challenge for bidir auth */
AUTH_RJT *rjt;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_auth_msg_auth_negotiate_cmpl_wait4next: did=0x%x",
ndlp->nlp_DID);
emlxs_dhc_state(port, ndlp, NODE_STATE_DHCHAP_REPLY_ISSUE, 0, 0);
(void) emlxs_els_reply(port, iocbq, ELS_CMD_ACC, ELS_CMD_AUTH, 0, 0);
bp = mp->virt;
lp = (uint32_t *)bp;
/*
* 1. we process the DHCHAP_Challenge 2. ACC it first 3. based on the
* result of 1 we DHCHAP_Reply or AUTH_Reject
*/
ncval = (DHCHAP_CHALL_NULL *)((uint8_t *)lp);
if (ncval->msg_hdr.auth_els_code != ELS_CMD_AUTH_CODE) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_auth_msg_auth_negotiate_cmpl_wait4next: 0x%x %x",
ndlp->nlp_DID, ncval->msg_hdr.auth_els_code);
/* need to setup reason code/reason explanation code */
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_BAD_PROTOCOL;
goto AUTH_Reject;
}
if (ncval->msg_hdr.auth_msg_code == AUTH_REJECT) {
rjt = (AUTH_RJT *)((uint8_t *)lp);
ReasonCode = rjt->ReasonCode;
ReasonCodeExplanation = rjt->ReasonCodeExplanation;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_auth_msg_auth_negotiate_cmpl_wait4next: 0x%x.%x,%x",
ndlp->nlp_DID, ReasonCode, ReasonCodeExplanation);
switch (ReasonCode) {
case AUTHRJT_LOGIC_ERR:
switch (ReasonCodeExplanation) {
case AUTHEXP_MECH_UNUSABLE:
case AUTHEXP_DHGROUP_UNUSABLE:
case AUTHEXP_HASHFUNC_UNUSABLE:
ReasonCode = AUTHRJT_LOGIC_ERR;
ReasonCodeExplanation = AUTHEXP_RESTART_AUTH;
break;
case AUTHEXP_RESTART_AUTH:
/*
* Cancel the rsp timer if not cancelled yet.
* and restart auth tran now.
*/
if (node_dhc->nlp_authrsp_tmo != 0) {
node_dhc->nlp_authrsp_tmo = 0;
node_dhc->nlp_authrsp_tmocnt = 0;
}
if (emlxs_dhc_auth_start(port, ndlp, NULL,
NULL) != 0) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_debug_msg,
"Reauth timeout. failed. 0x%x %x",
ndlp->nlp_DID, node_dhc->state);
}
return (node_dhc->state);
default:
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_AUTH_FAILED;
break;
}
break;
case AUTHRJT_FAILURE:
default:
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_AUTH_FAILED;
break;
}
goto AUTH_Reject;
}
if (ncval->msg_hdr.auth_msg_code != DHCHAP_CHALLENGE) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_auth_msg_auth_negotiate_cmpl_wait4next: 0x%x.%x",
ndlp->nlp_DID, ncval->msg_hdr.auth_msg_code);
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_BAD_PROTOCOL;
goto AUTH_Reject;
}
tran_id = ncval->msg_hdr.tran_id;
if (LE_SWAP32(tran_id) != node_dhc->nlp_auth_tranid_rsp) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_auth_msg_auth_negotiate_cmpl_wait4next:0x%x %x!=%x",
ndlp->nlp_DID, LE_SWAP32(tran_id),
node_dhc->nlp_auth_tranid_rsp);
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_BAD_PAYLOAD;
goto AUTH_Reject;
}
node_dhc->nlp_authrsp_tmo = 0;
namelen = ncval->msg_hdr.name_len;
if (namelen == AUTH_NAME_LEN) {
/*
* store another copy of wwn of fabric/or nport used in
* AUTH_ELS cmd
*/
bcopy((void *)&ncval->msg_hdr.nodeName,
(void *)&node_dhc->nlp_auth_wwn, sizeof (NAME_TYPE));
}
/* Collect the challenge value */
tmp = (uint8_t *)((uint8_t *)lp + sizeof (DHCHAP_CHALL_NULL));
if (ncval->hash_id == AUTH_MD5) {
if (ncval->cval_len != LE_SWAP32(MD5_LEN)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_auth_msg_auth_negotiate_cmpl_wait4next:0x%x.%x!=%x",
ndlp->nlp_DID, ncval->cval_len, LE_SWAP32(MD5_LEN));
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_BAD_PAYLOAD;
goto AUTH_Reject;
}
bzero(un_cval.md5.val, sizeof (MD5_CVAL));
bcopy((void *)tmp, (void *)un_cval.md5.val,
sizeof (MD5_CVAL));
tmp += sizeof (MD5_CVAL);
arg2len = MD5_LEN;
} else if (ncval->hash_id == AUTH_SHA1) {
if (ncval->cval_len != LE_SWAP32(SHA1_LEN)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_auth_msg_auth_negotiate_cmpl_wait4next: 0x%x %x!=%x",
ndlp->nlp_DID, ncval->cval_len, LE_SWAP32(MD5_LEN));
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_BAD_PAYLOAD;
goto AUTH_Reject;
}
bzero(un_cval.sha1.val, sizeof (SHA1_CVAL));
bcopy((void *)tmp, (void *)un_cval.sha1.val,
sizeof (SHA1_CVAL));
tmp += sizeof (SHA1_CVAL);
arg2len = SHA1_LEN;
} else {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_auth_msg_auth_negotiate_cmpl_wait4next: 0x%x %x",
ndlp->nlp_DID, ncval->hash_id);
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_BAD_PAYLOAD;
goto AUTH_Reject;
}
/*
* store hash_id for later usage : hash_id is set by responder in its
* dhchap_challenge
*/
node_dhc->hash_id = ncval->hash_id;
/* always use this */
/* store another copy of the hash_id */
node_dhc->nlp_auth_hashid = ncval->hash_id;
/* store dhgp_id for later usage */
node_dhc->dhgp_id = ncval->dhgp_id;
/* store another copy of dhgp_id */
/* always use this */
node_dhc->nlp_auth_dhgpid = ncval->dhgp_id;
/*
* ndlp->nlp_auth_hashid, nlp_auth_dhgpid store the hashid and dhgpid
* when this very ndlp is the auth transaction responder (in other
* words, responder means that this ndlp is send the host the
* challenge. ndlp could be fffffe or another initiator or target
* nport.
*/
dhvallen = *((uint32_t *)(tmp));
switch (ncval->dhgp_id) {
case GROUP_NULL:
/* null DHCHAP only */
if (LE_SWAP32(dhvallen) != 0) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_auth_msg_auth_negotiate_cmpl_wait4next: 0x%x %x %x",
ndlp->nlp_DID, ncval->dhgp_id, LE_SWAP32(dhvallen));
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_BAD_PAYLOAD;
goto AUTH_Reject;
}
break;
case GROUP_1024:
case GROUP_1280:
case GROUP_1536:
case GROUP_2048:
/* Collect the DH Value */
tmp += sizeof (uint32_t);
dhval = (uint8_t *)kmem_zalloc(LE_SWAP32(dhvallen),
KM_NOSLEEP);
if (dhval == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_auth_msg_auth_negotiate_cmpl_wait4next: 0x%x %x %x",
ndlp->nlp_DID, ncval->dhgp_id, dhval);
ReasonCode = AUTHRJT_LOGIC_ERR;
ReasonCodeExplanation = AUTHEXP_RESTART_AUTH;
goto AUTH_Reject;
}
bcopy((void *)tmp, (void *)dhval, LE_SWAP32(dhvallen));
break;
default:
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_auth_msg_auth_negotiate_cmpl_wait4next: 0x%x %x.",
ndlp->nlp_DID, ncval->dhgp_id);
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_BAD_PAYLOAD;
goto AUTH_Reject;
}
/*
* Calculate the hash value, hash function, DH group, secret etc.
* could be stored in port_dhc.
*/
/* arg5 has the response with NULL or Full DH group support */
arg5 = (uint32_t *)emlxs_hash_rsp(port, port_dhc,
ndlp, tran_id, un_cval, dhval, LE_SWAP32(dhvallen));
/* Or should check ndlp->auth_cfg..... */
if (node_dhc->auth_cfg.bidirectional == 1) {
/* get arg2 here */
/*
* arg2 is the new challenge C2 from initiator if bi-dir auth
* is supported
*/
bzero(&random_number, sizeof (random_number));
if (hba->rdn_flag == 1) {
emlxs_get_random_bytes(ndlp, random_number, 20);
} else {
(void) random_get_pseudo_bytes(random_number, arg2len);
}
/* cache it for later verification usage */
if (ndlp->nlp_DID == FABRIC_DID) {
bcopy((void *)&random_number[0],
(void *)&node_dhc->bi_cval[0], arg2len);
node_dhc->bi_cval_len = arg2len;
/* save another copy in our partner's ndlp */
bcopy((void *)&random_number[0],
(void *)&node_dhc->nlp_auth_misc.bi_cval[0],
arg2len);
node_dhc->nlp_auth_misc.bi_cval_len = arg2len;
} else {
bcopy((void *)&random_number[0],
(void *)&node_dhc->nlp_auth_misc.bi_cval[0],
arg2len);
node_dhc->nlp_auth_misc.bi_cval_len = arg2len;
}
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_auth_msg_auth_negotiate_cmpl_wait4next:0x%x(%x,%x,%x,%x,%x)",
ndlp->nlp_DID, node_dhc->nlp_auth_tranid_rsp,
node_dhc->nlp_auth_tranid_ini,
ncval->hash_id, ncval->dhgp_id, dhvallen);
/* Issue ELS DHCHAP_Reply */
/*
* arg1 has the response, arg2 has the new challenge if needed (g^y
* mod p) is the pubkey: all are ready and to go
*/
/* return 0 success, otherwise failure */
if (emlxs_issue_dhchap_reply(port, ndlp, 0, arg5, dhval,
LE_SWAP32(dhvallen),
random_number, arg2len)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_auth_msg_auth_negotiate_cmpl_wait4next: 0x%x.failed.",
ndlp->nlp_DID);
kmem_free(dhval, LE_SWAP32(dhvallen));
ReasonCode = AUTHRJT_LOGIC_ERR;
ReasonCodeExplanation = AUTHEXP_RESTART_AUTH;
goto AUTH_Reject;
}
return (node_dhc->state);
AUTH_Reject:
emlxs_dhc_state(port, ndlp, NODE_STATE_AUTH_FAILED, ReasonCode,
ReasonCodeExplanation);
(void) emlxs_issue_auth_reject(port, ndlp, 0, 0, ReasonCode,
ReasonCodeExplanation);
emlxs_dhc_auth_complete(port, ndlp, 1);
return (node_dhc->state);
} /* emlxs_rcv_auth_msg_auth_negotiate_cmpl_wait4next */
/*
* This routine should be set to emlxs_disc_neverdev
*
*/
/* ARGSUSED */
static uint32_t
emlxs_cmpl_auth_msg_auth_negotiate_cmpl_wait4next(
emlxs_port_t *port,
/* CHANNEL * rp, */ void *arg1,
/* IOCBQ * iocbq, */ void *arg2,
/* MATCHMAP * mp, */ void *arg3,
/* NODELIST * ndlp */ void *arg4,
uint32_t evt)
{
NODELIST *ndlp = (NODELIST *)arg4;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"cmpl_auth_msg_auth_negotiate_cmpl_wait4next.0x%x. Not iplted.",
ndlp->nlp_DID);
return (0);
} /* emlxs_cmpl_auth_msg_auth_negotiate_cmpl_wait4next() */
/*
* ! emlxs_rcv_auth_msg_dhchap_reply_issue
*
* This routine is invoked when the host received an unsolicited ELS AUTH
* msg from an NxPort or FxPort into which the host has
* sent an ELS DHCHAP_Reply msg. since the host is the initiator and the
* AUTH transaction is in progress between host and the
* NxPort or FxPort, as a result, the host will send back ACC and AUTH_Reject
* and set the next state = NPR_NODE.
*
*/
/* ARGSUSED */
static uint32_t
emlxs_rcv_auth_msg_dhchap_reply_issue(
emlxs_port_t *port,
/* CHANNEL * rp, */ void *arg1,
/* IOCBQ * iocbq, */ void *arg2,
/* MATCHMAP * mp, */ void *arg3,
/* NODELIST * ndlp */ void *arg4,
uint32_t evt)
{
NODELIST *ndlp = (NODELIST *)arg4;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_auth_msg_dhchap_reply_issue called. 0x%x. Not implemented.",
ndlp->nlp_DID);
return (0);
} /* emlxs_rcv_auth_msg_dhchap_reply_issue */
/*
* ! emlxs_cmpl_auth_msg_dhchap_reply_issue
*
* This routine is invoked when
* the host received a solicited ACC/RJT from ELS command from an NxPort
* or FxPort that already received the ELS DHCHAP_Reply
* msg from the host. in case of ACC, next state = DHCHAP_REPLY_CMPL_WAIT4NEXT
* in case of RJT, next state = NPR_NODE
*/
/* ARGSUSED */
static uint32_t
emlxs_cmpl_auth_msg_dhchap_reply_issue(
emlxs_port_t *port,
/* CHANNEL * rp, */ void *arg1,
/* IOCBQ * iocbq, */ void *arg2,
/* MATCHMAP * mp, */ void *arg3,
/* NODELIST * ndlp */ void *arg4,
uint32_t evt)
{
NODELIST *ndlp = (NODELIST *) arg4;
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"cmpl_auth_msg_dhchap_reply_issue: did=0x%x",
ndlp->nlp_DID);
/* start the emlxs_dhc_authrsp_timeout timer now */
if (node_dhc->nlp_authrsp_tmo == 0) {
node_dhc->nlp_authrsp_tmo = DRV_TIME +
node_dhc->auth_cfg.authentication_timeout;
}
/*
* The next state should be
* emlxs_rcv_auth_msg_dhchap_reply_cmpl_wait4next
*/
emlxs_dhc_state(port, ndlp,
NODE_STATE_DHCHAP_REPLY_CMPL_WAIT4NEXT, 0, 0);
return (node_dhc->state);
} /* emlxs_cmpl_auth_msg_dhchap_reply_issue */
/*
* ! emlxs_rcv_auth_msg_dhchap_reply_cmpl_wait4next
*
* \pre \post \param phba \param ndlp \param arg \param evt \return
* uint32_t \b Description: This rountine is invoked
* when the host received an unsolicited ELS AUTH Msg from the NxPort or
* FxPort that already sent ACC back to the host after
* receipt of DHCHAP_Reply msg. In normal case, this unsolicited msg could
* be DHCHAP_Success msg.
*
* if msg is ELS DHCHAP_Success, based on the payload, host send back ACC and 1.
* for uni-directional, and set next state =
* REG_LOGIN. 2. for bi-directional, and host do some computations
* (hash etc) and send back either DHCHAP_Success Msg and set
* next state = DHCHAP_SUCCESS_ISSUE_WAIT4NEXT or AUTH_Reject and set next
* state = NPR_NODE. if msg is ELS AUTH_Reject, then
* send back ACC and set next state = NPR_NODE if msg is anything else, then
* RJT and set next state = NPR_NODE
*/
/* ARGSUSED */
static uint32_t
emlxs_rcv_auth_msg_dhchap_reply_cmpl_wait4next(
emlxs_port_t *port,
/* CHANNEL * rp, */ void *arg1,
/* IOCBQ * iocbq, */ void *arg2,
/* MATCHMAP * mp, */ void *arg3,
/* NODELIST * ndlp */ void *arg4,
uint32_t evt)
{
emlxs_port_dhc_t *port_dhc = &port->port_dhc;
IOCBQ *iocbq = (IOCBQ *)arg2;
MATCHMAP *mp = (MATCHMAP *)arg3;
NODELIST *ndlp = (NODELIST *)arg4;
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
uint8_t *bp;
uint32_t *lp;
DHCHAP_SUCCESS_HDR *dh_success;
uint8_t *tmp;
uint8_t rsp_size;
AUTH_RJT *auth_rjt;
uint32_t tran_id;
uint32_t *hash_val;
union challenge_val un_cval;
uint8_t ReasonCode;
uint8_t ReasonCodeExplanation;
char info[64];
bp = mp->virt;
lp = (uint32_t *)bp;
/*
* 1. we process the DHCHAP_Success or AUTH_Reject 2. ACC it first 3.
* based on the result of 1 we goto the next stage SCR etc.
*/
/* sp = (SERV_PARM *)((uint8_t *)lp + sizeof(uint32_t)); */
dh_success = (DHCHAP_SUCCESS_HDR *)((uint8_t *)lp);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_auth_msg_dhchap_reply_cmpl_wait4next: 0x%x 0x%x 0x%x",
ndlp->nlp_DID, dh_success->auth_els_code,
dh_success->auth_msg_code);
node_dhc->nlp_authrsp_tmo = 0;
(void) emlxs_els_reply(port, iocbq, ELS_CMD_ACC, ELS_CMD_AUTH, 0, 0);
if (dh_success->auth_msg_code == AUTH_REJECT) {
/* ACC it and retry etc. */
auth_rjt = (AUTH_RJT *) dh_success;
ReasonCode = auth_rjt->ReasonCode;
ReasonCodeExplanation = auth_rjt->ReasonCodeExplanation;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_auth_msg_dhchap_reply_cmpl_wait4next: 0x%x.(%x,%x)",
ndlp->nlp_DID, ReasonCode, ReasonCodeExplanation);
switch (ReasonCode) {
case AUTHRJT_LOGIC_ERR:
switch (ReasonCodeExplanation) {
case AUTHEXP_MECH_UNUSABLE:
case AUTHEXP_DHGROUP_UNUSABLE:
case AUTHEXP_HASHFUNC_UNUSABLE:
ReasonCode = AUTHRJT_LOGIC_ERR;
ReasonCodeExplanation = AUTHEXP_RESTART_AUTH;
break;
case AUTHEXP_RESTART_AUTH:
/*
* Cancel the rsp timer if not cancelled yet.
* and restart auth tran now.
*/
if (node_dhc->nlp_authrsp_tmo != 0) {
node_dhc->nlp_authrsp_tmo = 0;
node_dhc->nlp_authrsp_tmocnt = 0;
}
if (emlxs_dhc_auth_start(port, ndlp,
NULL, NULL) != 0) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_debug_msg,
"Reauth timeout.failed. 0x%x %x",
ndlp->nlp_DID, node_dhc->state);
}
return (node_dhc->state);
default:
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_AUTH_FAILED;
break;
}
break;
case AUTHRJT_FAILURE:
default:
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_AUTH_FAILED;
emlxs_dhc_state(port, ndlp, NODE_STATE_AUTH_FAILED,
ReasonCode, ReasonCodeExplanation);
goto out;
}
goto AUTH_Reject;
}
if (dh_success->auth_msg_code == DHCHAP_SUCCESS) {
/* Verify the tran_id */
tran_id = dh_success->tran_id;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_auth_msg_dhchap_reply_cmpl_wait4next: 0x%x 0x%x 0x%x 0x%x",
ndlp->nlp_DID, LE_SWAP32(tran_id),
node_dhc->nlp_auth_tranid_rsp,
node_dhc->nlp_auth_tranid_ini);
if (LE_SWAP32(tran_id) != node_dhc->nlp_auth_tranid_rsp) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_auth_msg_dhchap_reply_cmpl_wait4next:0x%x %x!=%x",
ndlp->nlp_DID, LE_SWAP32(tran_id),
node_dhc->nlp_auth_tranid_rsp);
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_BAD_PAYLOAD;
goto AUTH_Reject;
}
if (node_dhc->auth_cfg.bidirectional == 0) {
node_dhc->flag |=
(NLP_REMOTE_AUTH | NLP_SET_REAUTH_TIME);
emlxs_dhc_state(port, ndlp,
NODE_STATE_AUTH_SUCCESS, 0, 0);
emlxs_log_auth_event(port, ndlp,
"rcv_auth_msg_dhchap_reply_cmpl_wait4next",
"Host-initiated-unidir-auth-success");
emlxs_dhc_auth_complete(port, ndlp, 0);
} else {
/* bidir auth needed */
/* if (LE_SWAP32(dh_success->msg_len) > 4) { */
tmp = (uint8_t *)((uint8_t *)lp);
tmp += 8;
tran_id = *(uint32_t *)tmp;
tmp += 4;
rsp_size = *(uint32_t *)tmp;
tmp += 4;
/* tmp has the response from responder */
/*
* node_dhc->bi_cval has the bidir challenge value
* from initiator
*/
if (LE_SWAP32(rsp_size) == 16) {
bzero(un_cval.md5.val, LE_SWAP32(rsp_size));
if (ndlp->nlp_DID == FABRIC_DID)
bcopy((void *)node_dhc->bi_cval,
(void *)un_cval.md5.val,
LE_SWAP32(rsp_size));
else
bcopy(
(void *)node_dhc->nlp_auth_misc.bi_cval,
(void *)un_cval.md5.val,
LE_SWAP32(rsp_size));
} else if (LE_SWAP32(rsp_size) == 20) {
bzero(un_cval.sha1.val, LE_SWAP32(rsp_size));
if (ndlp->nlp_DID == FABRIC_DID)
bcopy((void *)node_dhc->bi_cval,
(void *)un_cval.sha1.val,
LE_SWAP32(rsp_size));
else
bcopy(
(void *)node_dhc->nlp_auth_misc.bi_cval,
(void *)un_cval.sha1.val,
LE_SWAP32(rsp_size));
}
/* verify the response */
/* NULL DHCHAP works for now */
/* for DH group as well */
/*
* Cai2 = H (C2 || ((g^x mod p)^y mod p) ) = H (C2 ||
* (g^xy mod p) )
*
* R = H (Ti || Km || Cai2) R ?= R2
*/
hash_val = emlxs_hash_vrf(port, port_dhc, ndlp,
tran_id, un_cval);
if (bcmp((void *)tmp, (void *)hash_val,
LE_SWAP32(rsp_size))) {
if (hash_val != NULL) {
/* not identical */
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_auth_msg_dhchap_reply_cmpl_wait4next: 0x%x.failed. %x",
ndlp->nlp_DID, *(uint32_t *)hash_val);
}
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_AUTH_FAILED;
goto AUTH_Reject;
}
emlxs_dhc_state(port, ndlp,
NODE_STATE_DHCHAP_SUCCESS_ISSUE_WAIT4NEXT, 0, 0);
/* send out DHCHAP_SUCCESS */
(void) emlxs_issue_dhchap_success(port, ndlp, 0, 0);
}
}
return (node_dhc->state);
AUTH_Reject:
emlxs_dhc_state(port, ndlp, NODE_STATE_AUTH_FAILED,
ReasonCode, ReasonCodeExplanation);
(void) emlxs_issue_auth_reject(port, ndlp, 0, 0, ReasonCode,
ReasonCodeExplanation);
emlxs_dhc_auth_complete(port, ndlp, 1);
return (node_dhc->state);
out:
(void) snprintf(info, sizeof (info),
"Auth Failed: ReasonCode=0x%x, ReasonCodeExplanation=0x%x",
ReasonCode, ReasonCodeExplanation);
emlxs_log_auth_event(port, ndlp,
"rcv_auth_msg_dhchap_reply_cmpl_wait4next", info);
emlxs_dhc_auth_complete(port, ndlp, 1);
return (node_dhc->state);
} /* emlxs_rcv_auth_msg_dhchap_reply_cmpl_wait4next */
/*
* This routine should be set to emlxs_disc_neverdev as it shouldnot happen.
*
*/
/* ARGSUSED */
static uint32_t
emlxs_cmpl_auth_msg_dhchap_reply_cmpl_wait4next(
emlxs_port_t *port,
/* CHANNEL * rp, */ void *arg1,
/* IOCBQ * iocbq, */ void *arg2,
/* MATCHMAP * mp, */ void *arg3,
/* NODELIST * ndlp */ void *arg4,
uint32_t evt)
{
NODELIST *ndlp = (NODELIST *)arg4;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"cmpl_auth_msg_dhchap_reply_cmpl_wait4next. 0x%x.Not ipleted.",
ndlp->nlp_DID);
return (0);
} /* emlxs_cmpl_auth_msg_dhchap_reply_cmpl_wait4next */
/*
* emlxs_rcv_auth_msg_dhchap_success_issue_wait4next
*
* This routine is supported
* for HBA in either auth initiator mode or responder mode.
*
* This routine is invoked when the host as the auth responder received
* an unsolicited ELS AUTH msg from the NxPort as the auth
* initiator that already received the ELS DHCHAP_Success.
*
* If the host is the auth initiator and since the AUTH transction is
* already in progress, therefore, any auth els msg should not
* happen and if happened, RJT and move to NPR_NODE.
*
* If the host is the auth reponder, this unsolicited els auth msg should
* be DHCHAP_Success for this bi-directional auth
* transaction. In which case, the host should send ACC back and move state
* to REG_LOGIN. If this unsolicited els auth msg is
* DHCHAP_Reject, which could mean that the auth failed, then host should
* send back ACC and set the next state to NPR_NODE.
*
*/
/* ARGSUSED */
static uint32_t
emlxs_rcv_auth_msg_dhchap_success_issue_wait4next(
emlxs_port_t *port,
/* CHANNEL * rp, */ void *arg1,
/* IOCBQ * iocbq, */ void *arg2,
/* MATCHMAP * mp, */ void *arg3,
/* NODELIST * ndlp */ void *arg4,
uint32_t evt)
{
NODELIST *ndlp = (NODELIST *) arg4;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_auth_msg_dhchap_success_issue_wait4next. 0x%x. Not iplted.",
ndlp->nlp_DID);
return (0);
} /* emlxs_rcv_auth_msg_dhchap_success_issue_wait4next */
/*
* ! emlxs_cmpl_auth_msg_dhchap_success_issue_wait4next
*
* This routine is invoked when
* the host as the auth initiator received an solicited ACC/RJT from the
* NxPort or FxPort that already received DHCHAP_Success
* Msg the host sent before. in case of ACC, set next state = REG_LOGIN.
* in case of RJT, set next state = NPR_NODE.
*
*/
/* ARGSUSED */
static uint32_t
emlxs_cmpl_auth_msg_dhchap_success_issue_wait4next(
emlxs_port_t *port,
/* CHANNEL * rp, */ void *arg1,
/* IOCBQ * iocbq, */ void *arg2,
/* MATCHMAP * mp, */ void *arg3,
/* NODELIST * ndlp */ void *arg4,
uint32_t evt)
{
NODELIST *ndlp = (NODELIST *)arg4;
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
/*
* Either host is the initiator and auth or (reauth bi-direct) is
* done, so start host reauth heartbeat timer now if host side reauth
* heart beat never get started. Or host is the responder and the
* other entity is done with its reauth heart beat with
* uni-directional auth. Anyway we start host side reauth heart beat
* timer now.
*/
node_dhc->flag &= ~NLP_REMOTE_AUTH;
node_dhc->flag |= NLP_SET_REAUTH_TIME;
emlxs_dhc_state(port, ndlp, NODE_STATE_AUTH_SUCCESS, 0, 0);
emlxs_log_auth_event(port, ndlp,
"cmpl_auth_msg_dhchap_success_issue_wait4next",
"Host-initiated-bidir-auth-success");
emlxs_dhc_auth_complete(port, ndlp, 0);
return (node_dhc->state);
} /* emlxs_cmpl_auth_msg_dhchap_success_issue_wait4next */
/*
* ! emlxs_cmpl_auth_msg_auth_negotiate_rcv
*
* This routine is invoked when
* the host received the solicited ACC/RJT ELS cmd from an FxPort or an
* NxPort that has received the ELS DHCHAP_Challenge.
* The host is the auth responder and the auth transaction is still in
* progress.
*
*/
/* ARGSUSED */
static uint32_t
emlxs_cmpl_auth_msg_auth_negotiate_rcv(
emlxs_port_t *port,
/* CHANNEL * rp, */ void *arg1,
/* IOCBQ * iocbq, */ void *arg2,
/* MATCHMAP * mp, */ void *arg3,
/* NODELIST * ndlp */ void *arg4,
uint32_t evt)
{
NODELIST *ndlp = (NODELIST *)arg4;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"cmpl_auth_msg_auth_negotiate_rcv called. 0x%x. Not implemented.",
ndlp->nlp_DID);
return (0);
} /* emlxs_cmpl_auth_msg_auth_negotiate_rcv */
/*
* ! emlxs_rcv_auth_msg_dhchap_challenge_issue
*
* \pre \post \param phba \param ndlp \param arg \param evt \return
* uint32_t \b Description: This routine should be
* emlxs_disc_neverdev. The host is the auth responder and the auth
* transaction is still in progress, any unsolicited els auth
* msg is unexpected and should not happen in normal case.
*
* If DHCHAP_Reject, ACC and next state = NPR_NODE. anything else, RJT and
* next state = NPR_NODE.
*/
/* ARGSUSED */
static uint32_t
emlxs_rcv_auth_msg_dhchap_challenge_issue(
emlxs_port_t *port,
/* CHANNEL * rp, */ void *arg1,
/* IOCBQ * iocbq, */ void *arg2,
/* MATCHMAP * mp, */ void *arg3,
/* NODELIST * ndlp */ void *arg4,
uint32_t evt)
{
NODELIST *ndlp = (NODELIST *)arg4;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_auth_msg_dhchap_challenge_issue called. 0x%x. Not iplted.",
ndlp->nlp_DID);
return (0);
} /* emlxs_rcv_auth_msg_dhchap_challenge_issue */
/*
* ! emlxs_cmpl_auth_msg_dhchap_challenge_issue
*
* \pre \post \param phba \param ndlp \param arg \param evt \return
* uint32_t \b Description: This routine is invoked when
* the host as the responder received the solicited response (ACC or RJT)
* from initiator to the DHCHAP_Challenge msg sent from
* host. In case of ACC, the next state = DHCHAP_CHALLENGE_CMPL_WAIT4NEXT
* In case of RJT, the next state = NPR_NODE.
*
*/
/* ARGSUSED */
static uint32_t
emlxs_cmpl_auth_msg_dhchap_challenge_issue(
emlxs_port_t *port,
/* CHANNEL * rp, */ void *arg1,
/* IOCBQ * iocbq, */ void *arg2,
/* MATCHMAP * mp, */ void *arg3,
/* NODELIST * ndlp */ void *arg4,
uint32_t evt)
{
NODELIST *ndlp = (NODELIST *)arg4;
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
/*
* The next state should be
* emlxs_rcv_auth_msg_dhchap_challenge_cmpl_wait4next
*/
emlxs_dhc_state(port, ndlp,
NODE_STATE_DHCHAP_CHALLENGE_CMPL_WAIT4NEXT, 0, 0);
/* Start the fc_authrsp_timeout timer */
if (node_dhc->nlp_authrsp_tmo == 0) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"cmpl_auth_msg_dhchap_challenge_issue: Starting authrsp timer.");
node_dhc->nlp_authrsp_tmo = DRV_TIME +
node_dhc->auth_cfg.authentication_timeout;
}
return (node_dhc->state);
} /* emlxs_cmpl_auth_msg_dhchap_challenge_issue */
/*
* ! emlxs_rcv_auth_msg_dhchap_challenge_cmpl_wait4next
*
* \pre \post \param phba \param ndlp \param arg \param evt \return
* uint32_t \b Description: This routine is invoked when
* the host as the auth responder received an unsolicited auth msg from the
* FxPort or NxPort that already sent ACC to the DHCH_
* Challenge it received. In normal case this unsolicited auth msg should
* be DHCHAP_Reply msg from the initiator.
*
* For DHCHAP_Reply msg, the host send back ACC and then do verification
* (hash?) and send back DHCHAP_Success and next state as
* DHCHAP_SUCCESS_ISSUE or DHCHAP_Reject and next state as NPR_NODE based on
* the verification result.
*
* For bi-directional auth transaction, Reply msg should have the new
* challenge value from the initiator. thus the Success msg
* sent out should have the corresponding Reply from the responder.
*
* For uni-directional, Reply msg received does not contains the new
* challenge and therefore the Success msg does not include the
* Reply msg.
*
* For DHCHAP_Reject, send ACC and moved to the next state NPR_NODE. For
* anything else, send RJT and moved to NPR_NODE.
*
*/
/* ARGSUSED */
static uint32_t
emlxs_rcv_auth_msg_dhchap_challenge_cmpl_wait4next(
emlxs_port_t *port,
/* CHANNEL * rp, */ void *arg1,
/* IOCBQ * iocbq, */ void *arg2,
/* MATCHMAP * mp, */ void *arg3,
/* NODELIST * ndlp */ void *arg4,
uint32_t evt)
{
emlxs_port_dhc_t *port_dhc = &port->port_dhc;
IOCBQ *iocbq = (IOCBQ *)arg2;
MATCHMAP *mp = (MATCHMAP *)arg3;
NODELIST *ndlp = (NODELIST *)arg4;
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
uint8_t *bp;
uint32_t *lp;
DHCHAP_REPLY_HDR *dh_reply;
uint8_t *tmp;
uint32_t rsp_len;
uint8_t rsp[20]; /* should cover SHA-1 and MD5's rsp */
uint32_t dhval_len;
uint8_t dhval[512];
uint32_t cval_len;
uint8_t cval[20];
uint32_t tran_id;
uint32_t *hash_val = NULL;
uint8_t ReasonCode;
uint8_t ReasonCodeExplanation;
AUTH_RJT *rjt;
/* ACC the ELS DHCHAP_Reply msg first */
(void) emlxs_els_reply(port, iocbq, ELS_CMD_ACC, ELS_CMD_AUTH, 0, 0);
bp = mp->virt;
lp = (uint32_t *)bp;
/*
* send back ELS AUTH_Reject or DHCHAP_Success msg based on the
* verification result. i.e., hash computation etc.
*/
dh_reply = (DHCHAP_REPLY_HDR *)((uint8_t *)lp);
tmp = (uint8_t *)((uint8_t *)lp);
tran_id = dh_reply->tran_id;
if (LE_SWAP32(tran_id) != node_dhc->nlp_auth_tranid_ini) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_auth_msg_dhchap_challenge_cmpl_wait4next:0x%x 0x%x 0x%x",
ndlp->nlp_DID, tran_id, node_dhc->nlp_auth_tranid_ini);
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_BAD_PROTOCOL;
goto Reject;
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_a_m_dhch_chll_cmpl_wait4next:0x%x 0x%x 0x%x 0x%x 0x%x",
ndlp->nlp_DID, tran_id, node_dhc->nlp_auth_tranid_ini,
node_dhc->nlp_auth_tranid_rsp, dh_reply->auth_msg_code);
/* cancel the nlp_authrsp_timeout timer and send out Auth_Reject */
if (node_dhc->nlp_authrsp_tmo) {
node_dhc->nlp_authrsp_tmo = 0;
}
if (dh_reply->auth_msg_code == AUTH_REJECT) {
rjt = (AUTH_RJT *)((uint8_t *)lp);
ReasonCode = rjt->ReasonCode;
ReasonCodeExplanation = rjt->ReasonCodeExplanation;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_a_msg_dhch_chall_cmpl_wait4next:RJT rcved:0x%x 0x%x",
ReasonCode, ReasonCodeExplanation);
switch (ReasonCode) {
case AUTHRJT_LOGIC_ERR:
switch (ReasonCodeExplanation) {
case AUTHEXP_MECH_UNUSABLE:
case AUTHEXP_DHGROUP_UNUSABLE:
case AUTHEXP_HASHFUNC_UNUSABLE:
ReasonCode = AUTHRJT_LOGIC_ERR;
ReasonCodeExplanation = AUTHEXP_RESTART_AUTH;
break;
case AUTHEXP_RESTART_AUTH:
/*
* Cancel the rsp timer if not cancelled yet.
* and restart auth tran now.
*/
if (node_dhc->nlp_authrsp_tmo != 0) {
node_dhc->nlp_authrsp_tmo = 0;
node_dhc->nlp_authrsp_tmocnt = 0;
}
if (emlxs_dhc_auth_start(port, ndlp,
NULL, NULL) != 0) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_debug_msg,
"Reauth timeout.Auth initfailed. 0x%x %x",
ndlp->nlp_DID, node_dhc->state);
}
return (node_dhc->state);
default:
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_AUTH_FAILED;
break;
}
break;
case AUTHRJT_FAILURE:
default:
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_AUTH_FAILED;
break;
}
goto Reject;
}
if (dh_reply->auth_msg_code == DHCHAP_REPLY) {
/* We must send out DHCHAP_Success msg and wait for ACC */
/* _AND_ if bi-dir auth, we have to wait for next */
/*
* Send back DHCHAP_Success or AUTH_Reject based on the
* verification result
*/
tmp += sizeof (DHCHAP_REPLY_HDR);
rsp_len = LE_SWAP32(*(uint32_t *)tmp);
tmp += sizeof (uint32_t);
/* collect the response data */
bcopy((void *)tmp, (void *)rsp, rsp_len);
tmp += rsp_len;
dhval_len = LE_SWAP32(*(uint32_t *)tmp);
tmp += sizeof (uint32_t);
if (dhval_len != 0) {
/* collect the DH value */
bcopy((void *)tmp, (void *)dhval, dhval_len);
tmp += dhval_len;
}
/*
* Check to see if there is any challenge for bi-dir auth in
* the reply msg
*/
cval_len = LE_SWAP32(*(uint32_t *)tmp);
if (cval_len != 0) {
/* collect challenge value */
tmp += sizeof (uint32_t);
bcopy((void *)tmp, (void *)cval, cval_len);
if (ndlp->nlp_DID == FABRIC_DID) {
node_dhc->nlp_auth_bidir = 1;
} else {
node_dhc->nlp_auth_bidir = 1;
}
} else {
node_dhc->nlp_auth_bidir = 0;
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_a_m_dhchap_challenge_cmpl_wait4next:Reply:%x %lx %x %x %x\n",
ndlp->nlp_DID, *(uint32_t *)rsp, rsp_len, dhval_len, cval_len);
/* Verify the response based on the hash func, dhgp_id etc. */
/*
* all the information needed are stored in
* node_dhc->hrsp_xxx or ndlp->nlp_auth_misc.
*/
/*
* Basically compare the rsp value with the computed hash
* value
*/
/* allocate hash_val first as rsp_len bytes */
/*
* we set bi-cval pointer as NULL because we are using
* node_dhc->hrsp_cval[]
*/
hash_val = emlxs_hash_verification(port, port_dhc, ndlp,
(tran_id), dhval, (dhval_len), 1, 0);
if (hash_val == NULL) {
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_AUTH_FAILED;
goto Reject;
}
if (bcmp((void *) rsp, (void *)hash_val, rsp_len)) {
/* not identical */
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_auth_msg_dhchap_challenge_cmpl_wait4next: Not authted(1).");
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_AUTH_FAILED;
goto Reject;
}
kmem_free(hash_val, rsp_len);
hash_val = NULL;
/* generate the reply based on the challenge received if any */
if ((cval_len) != 0) {
/*
* Cal R2 = H (Ti || Km || Ca2) Ca2 = H (C2 || ((g^y
* mod p)^x mod p) ) = H (C2 || (g^(x*y) mod p)) = H
* (C2 || seskey) Km is the password associated with
* responder. Here cval: C2 dhval: (g^y mod p)
*/
hash_val = emlxs_hash_get_R2(port, port_dhc,
ndlp, (tran_id), dhval,
(dhval_len), 1, cval);
if (hash_val == NULL) {
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_AUTH_FAILED;
goto Reject;
}
}
emlxs_dhc_state(port, ndlp,
NODE_STATE_DHCHAP_SUCCESS_ISSUE, 0, 0);
if (emlxs_issue_dhchap_success(port, ndlp, 0,
(uint8_t *)hash_val)) {
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_AUTH_FAILED;
goto Reject;
}
}
return (node_dhc->state);
Reject:
emlxs_dhc_state(port, ndlp, NODE_STATE_AUTH_FAILED,
ReasonCode, ReasonCodeExplanation);
(void) emlxs_issue_auth_reject(port, ndlp, 0, 0, ReasonCode,
ReasonCodeExplanation);
emlxs_dhc_auth_complete(port, ndlp, 1);
out:
return (node_dhc->state);
} /* emlxs_rcv_auth_msg_dhchap_challenge_cmpl_wait4next */
/*
* This routine should be emlxs_disc_neverdev.
*
*/
/* ARGSUSED */
static uint32_t
emlxs_cmpl_auth_msg_dhchap_challenge_cmpl_wait4next(
emlxs_port_t *port,
/* CHANNEL * rp, */ void *arg1,
/* IOCBQ * iocbq, */ void *arg2,
/* MATCHMAP * mp, */ void *arg3,
/* NODELIST * ndlp */ void *arg4,
uint32_t evt)
{
NODELIST *ndlp = (NODELIST *)arg4;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"cmpl_a_m_dhch_chall_cmpl_wait4next.0x%x. Not implemented.",
ndlp->nlp_DID);
return (0);
} /* emlxs_cmpl_auth_msg_dhchap_challenge_cmpl_wait4next */
/*
* ! emlxs_rcv_auth_msg_dhchap_success_issue
*
* \pre \post \param phba \param ndlp \param arg \param evt \return
* uint32_t \b Description:
*
* The host is the auth responder and the auth transaction is still in
* progress, any unsolicited els auth msg is unexpected and
* should not happen. If DHCHAP_Reject received, ACC back and move to next
* state NPR_NODE. anything else, RJT and move to
* NPR_NODE.
*/
/* ARGSUSED */
static uint32_t
emlxs_rcv_auth_msg_dhchap_success_issue(
emlxs_port_t *port,
/* CHANNEL * rp, */ void *arg1,
/* IOCBQ * iocbq, */ void *arg2,
/* MATCHMAP * mp, */ void *arg3,
/* NODELIST * ndlp */ void *arg4,
uint32_t evt)
{
NODELIST *ndlp = (NODELIST *)arg4;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_a_m_dhch_success_issue called. did=0x%x. Not implemented.",
ndlp->nlp_DID);
return (0);
} /* emlxs_rcv_auth_msg_dhchap_success_issue */
/*
* emlxs_cmpl_auth_msg_dhchap_success_issue
*
* This routine is invoked when
* host as the auth responder received the solicited response (ACC or RJT)
* from the initiator that received DHCHAP_ Success.
*
* For uni-dirctional authentication, we are done so the next state =
* REG_LOGIN for bi-directional authentication, we will expect
* DHCHAP_Success msg. so the next state = DHCHAP_SUCCESS_CMPL_WAIT4NEXT
* and start the emlxs_dhc_authrsp_timeout timer
*/
/* ARGSUSED */
static uint32_t
emlxs_cmpl_auth_msg_dhchap_success_issue(
emlxs_port_t *port,
/* CHANNEL * rp, */ void *arg1,
/* IOCBQ * iocbq, */ void *arg2,
/* MATCHMAP * mp, */ void *arg3,
/* NODELIST * ndlp */ void *arg4,
uint32_t evt)
{
NODELIST *ndlp = (NODELIST *)arg4;
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"cmpl_a_m_dhch_success_issue: did=0x%x auth_bidir=0x%x",
ndlp->nlp_DID, node_dhc->nlp_auth_bidir);
if (node_dhc->nlp_auth_bidir == 1) {
/* we would expect the bi-dir authentication result */
/*
* the next state should be
* emlxs_rcv_auth_msg_dhchap_success_cmpl_wait4next
*/
emlxs_dhc_state(port, ndlp,
NODE_STATE_DHCHAP_SUCCESS_CMPL_WAIT4NEXT, 0, 0);
/* start the emlxs_dhc_authrsp_timeout timer */
node_dhc->nlp_authrsp_tmo = DRV_TIME +
node_dhc->auth_cfg.authentication_timeout;
} else {
node_dhc->flag &= ~NLP_REMOTE_AUTH;
emlxs_dhc_state(port, ndlp, NODE_STATE_AUTH_SUCCESS, 0, 0);
emlxs_log_auth_event(port, ndlp,
"cmpl_auth_msg_dhchap_success_issue",
"Node-initiated-unidir-reauth-success");
emlxs_dhc_auth_complete(port, ndlp, 0);
}
return (node_dhc->state);
} /* emlxs_cmpl_auth_msg_dhchap_success_issue */
/* ARGSUSED */
static uint32_t
emlxs_device_recov_unmapped_node(
emlxs_port_t *port,
void *arg1,
void *arg2,
void *arg3,
void *arg4,
uint32_t evt)
{
NODELIST *ndlp = (NODELIST *)arg4;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"device_recov_unmapped_node called. 0x%x. Not implemented.",
ndlp->nlp_DID);
return (0);
} /* emlxs_device_recov_unmapped_node */
/* ARGSUSED */
static uint32_t
emlxs_device_rm_npr_node(
emlxs_port_t *port,
void *arg1,
void *arg2,
void *arg3,
void *arg4,
uint32_t evt)
{
NODELIST *ndlp = (NODELIST *)arg4;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"device_rm_npr_node called. 0x%x. Not implemented.",
ndlp->nlp_DID);
return (0);
} /* emlxs_device_rm_npr_node */
/* ARGSUSED */
static uint32_t
emlxs_device_recov_npr_node(
emlxs_port_t *port,
void *arg1,
void *arg2,
void *arg3,
void *arg4,
uint32_t evt)
{
NODELIST *ndlp = (NODELIST *)arg4;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"device_recov_npr_node called. 0x%x. Not implemented.",
ndlp->nlp_DID);
return (0);
} /* emlxs_device_recov_npr_node */
/* ARGSUSED */
static uint32_t
emlxs_device_rem_auth(
emlxs_port_t *port,
/* CHANNEL * rp, */ void *arg1,
/* IOCBQ * iocbq, */ void *arg2,
/* MATCHMAP * mp, */ void *arg3,
/* NODELIST * ndlp */ void *arg4,
uint32_t evt)
{
NODELIST *ndlp = (NODELIST *)arg4;
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"device_rem_auth: 0x%x.",
ndlp->nlp_DID);
emlxs_dhc_state(port, ndlp, NODE_STATE_UNKNOWN, 0, 0);
return (node_dhc->state);
} /* emlxs_device_rem_auth */
/*
* This routine is invoked when linkdown event happens during authentication
*/
/* ARGSUSED */
static uint32_t
emlxs_device_recov_auth(
emlxs_port_t *port,
/* CHANNEL * rp, */ void *arg1,
/* IOCBQ * iocbq, */ void *arg2,
/* MATCHMAP * mp, */ void *arg3,
/* NODELIST * ndlp */ void *arg4,
uint32_t evt)
{
NODELIST *ndlp = (NODELIST *)arg4;
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"device_recov_auth: 0x%x.",
ndlp->nlp_DID);
node_dhc->nlp_authrsp_tmo = 0;
emlxs_dhc_state(port, ndlp, NODE_STATE_AUTH_FAILED, 0, 0);
return (node_dhc->state);
} /* emlxs_device_recov_auth */
/*
* This routine is invoked when the host as the responder sent out the
* ELS DHCHAP_Success to the initiator, the initiator ACC
* it. AND then the host received an unsolicited auth msg from the initiator,
* this msg is supposed to be the ELS DHCHAP_Success
* msg for the bi-directional authentication.
*
* next state should be REG_LOGIN
*/
/* ARGSUSED */
static uint32_t
emlxs_rcv_auth_msg_dhchap_success_cmpl_wait4next(
emlxs_port_t *port,
/* CHANNEL * rp, */ void *arg1,
/* IOCBQ * iocbq, */ void *arg2,
/* MATCHMAP * mp, */ void *arg3,
/* NODELIST * ndlp */ void *arg4,
uint32_t evt)
{
IOCBQ *iocbq = (IOCBQ *)arg2;
MATCHMAP *mp = (MATCHMAP *)arg3;
NODELIST *ndlp = (NODELIST *)arg4;
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
uint8_t *bp;
uint32_t *lp;
DHCHAP_SUCCESS_HDR *dh_success;
AUTH_RJT *auth_rjt;
uint8_t ReasonCode;
uint8_t ReasonCodeExplanation;
bp = mp->virt;
lp = (uint32_t *)bp;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_auth_msg_dhchap_success_cmpl_wait4next: did=0x%x",
ndlp->nlp_DID);
dh_success = (DHCHAP_SUCCESS_HDR *)((uint8_t *)lp);
(void) emlxs_els_reply(port, iocbq, ELS_CMD_ACC, ELS_CMD_AUTH, 0, 0);
if (dh_success->auth_msg_code == AUTH_REJECT) {
/* ACC it and retry etc. */
auth_rjt = (AUTH_RJT *)dh_success;
ReasonCode = auth_rjt->ReasonCode;
ReasonCodeExplanation = auth_rjt->ReasonCodeExplanation;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_a_m_dhch_success_cmpl_wait4next:REJECT rvd. 0x%x 0x%x 0x%x",
ndlp->nlp_DID, ReasonCode, ReasonCodeExplanation);
switch (ReasonCode) {
case AUTHRJT_LOGIC_ERR:
switch (ReasonCodeExplanation) {
case AUTHEXP_MECH_UNUSABLE:
case AUTHEXP_DHGROUP_UNUSABLE:
case AUTHEXP_HASHFUNC_UNUSABLE:
ReasonCode = AUTHRJT_LOGIC_ERR;
ReasonCodeExplanation = AUTHEXP_RESTART_AUTH;
break;
case AUTHEXP_RESTART_AUTH:
/*
* Cancel the rsp timer if not cancelled yet.
* and restart auth tran now.
*/
if (node_dhc->nlp_authrsp_tmo != 0) {
node_dhc->nlp_authrsp_tmo = 0;
node_dhc->nlp_authrsp_tmocnt = 0;
}
if (emlxs_dhc_auth_start(port, ndlp,
NULL, NULL) != 0) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_debug_msg,
"Reauth timeout. Auth initfailed. 0x%x %x",
ndlp->nlp_DID, node_dhc->state);
}
return (node_dhc->state);
default:
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_AUTH_FAILED;
break;
}
break;
case AUTHRJT_FAILURE:
default:
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_AUTH_FAILED;
break;
}
goto Reject;
} else if (dh_success->auth_msg_code == DHCHAP_SUCCESS) {
if (LE_SWAP32(dh_success->tran_id) !=
node_dhc->nlp_auth_tranid_ini) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_a_m_dhch_success_cmpl_wait4next: 0x%x 0x%lx, 0x%lx",
ndlp->nlp_DID, dh_success->tran_id, node_dhc->nlp_auth_tranid_ini);
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_BAD_PROTOCOL;
goto Reject;
}
node_dhc->flag |= NLP_REMOTE_AUTH;
emlxs_dhc_state(port, ndlp, NODE_STATE_AUTH_SUCCESS, 0, 0);
emlxs_log_auth_event(port, ndlp,
"rcv_auth_msg_dhchap_success_cmpl_wait4next",
"Node-initiated-bidir-reauth-success");
emlxs_dhc_auth_complete(port, ndlp, 0);
} else {
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_BAD_PROTOCOL;
goto Reject;
}
return (node_dhc->state);
Reject:
emlxs_dhc_state(port, ndlp, NODE_STATE_AUTH_FAILED,
ReasonCode, ReasonCodeExplanation);
(void) emlxs_issue_auth_reject(port, ndlp, 0, 0, ReasonCode,
ReasonCodeExplanation);
emlxs_dhc_auth_complete(port, ndlp, 1);
out:
return (node_dhc->state);
} /* emlxs_rcv_auth_msg_dhchap_success_cmpl_wait4next */
/* ARGSUSED */
static uint32_t
emlxs_cmpl_auth_msg_dhchap_success_cmpl_wait4next(
emlxs_port_t *port,
/* CHANNEL * rp, */ void *arg1,
/* IOCBQ * iocbq, */ void *arg2,
/* MATCHMAP * mp, */ void *arg3,
/* NODELIST * ndlp */ void *arg4,
uint32_t evt)
{
return (0);
} /* emlxs_cmpl_auth_msg_dhchap_success_cmpl_wait4next */
/* ARGSUSED */
static uint32_t
emlxs_rcv_auth_msg_auth_negotiate_rcv(
emlxs_port_t *port,
/* CHANNEL * rp, */ void *arg1,
/* IOCBQ * iocbq, */ void *arg2,
/* MATCHMAP * mp, */ void *arg3,
/* NODELIST * ndlp */ void *arg4,
uint32_t evt)
{
NODELIST *ndlp = (NODELIST *)arg4;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_a_m_auth_negotiate_rcv called. did=0x%x. Not implemented.",
ndlp->nlp_DID);
return (0);
} /* emlxs_rcv_auth_msg_auth_negotiate_rcv */
/* ARGSUSED */
static uint32_t
emlxs_rcv_auth_msg_npr_node(
emlxs_port_t *port,
/* CHANNEL * rp, */ void *arg1,
/* IOCBQ * iocbq, */ void *arg2,
/* MATCHMAP * mp, */ void *arg3,
/* NODELIST * ndlp */ void *arg4,
uint32_t evt)
{
IOCBQ *iocbq = (IOCBQ *)arg2;
MATCHMAP *mp = (MATCHMAP *)arg3;
NODELIST *ndlp = (NODELIST *)arg4;
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
uint8_t *bp;
uint32_t *lp;
uint32_t msglen;
uint8_t *tmp;
AUTH_MSG_HDR *msg;
uint8_t *temp;
uint32_t rc, i, hs_id[2], dh_id[5];
/* from initiator */
uint32_t hash_id, dhgp_id; /* to be used by responder */
uint16_t num_hs = 0;
uint16_t num_dh = 0;
bp = mp->virt;
lp = (uint32_t *)bp;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_auth_msg_npr_node:");
/*
* 1. process the auth msg, should acc first no matter what. 2.
* return DHCHAP_Challenge for AUTH_Negotiate auth msg, AUTH_Reject
* for anything else.
*/
(void) emlxs_els_reply(port, iocbq, ELS_CMD_ACC, ELS_CMD_AUTH, 0, 0);
msg = (AUTH_MSG_HDR *)((uint8_t *)lp);
msglen = msg->msg_len;
tmp = ((uint8_t *)lp);
/* temp is used for error checking */
temp = (uint8_t *)((uint8_t *)lp);
/* Check the auth_els_code */
if (((*(uint32_t *)temp) & 0xFFFFFFFF) != LE_SWAP32(0x90000B01)) {
/* ReasonCode = AUTHRJT_FAILURE; */
/* ReasonCodeExplanation = AUTHEXP_BAD_PAYLOAD; */
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_auth_msg_npr_node: payload(1)=0x%x",
(*(uint32_t *)temp));
goto AUTH_Reject;
}
temp += 3 * sizeof (uint32_t);
/* Check name tag and name length */
if (((*(uint32_t *)temp) & 0xFFFFFFFF) != LE_SWAP32(0x00010008)) {
/* ReasonCode = AUTHRJT_FAILURE; */
/* ReasonCodeExplanation = AUTHEXP_BAD_PAYLOAD; */
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_auth_msg_npr_node: payload(2)=0x%x",
(*(uint32_t *)temp));
goto AUTH_Reject;
}
temp += sizeof (uint32_t) + 8;
/* Check proto_num */
if (((*(uint32_t *)temp) & 0xFFFFFFFF) != LE_SWAP32(0x00000001)) {
/* ReasonCode = AUTHRJT_FAILURE; */
/* ReasonCodeExplanation = AUTHEXP_BAD_PAYLOAD; */
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_auth_msg_npr_node: payload(3)=0x%x",
(*(uint32_t *)temp));
goto AUTH_Reject;
}
temp += sizeof (uint32_t);
/* Get para_len */
/* para_len = LE_SWAP32(*(uint32_t *)temp); */
temp += sizeof (uint32_t);
/* Check proto_id */
if (((*(uint32_t *)temp) & 0xFFFFFFFF) != AUTH_DHCHAP) {
/* ReasonCode = AUTHRJT_FAILURE; */
/* ReasonCodeExplanation = AUTHEXP_BAD_PROTOCOL; */
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_auth_msg_npr_node: payload(4)=0x%x",
(*(uint32_t *)temp));
goto AUTH_Reject;
}
temp += sizeof (uint32_t);
/* Check hashlist tag */
if ((LE_SWAP32(*(uint32_t *)temp) & 0xFFFF0000) >> 16 !=
LE_SWAP16(HASH_LIST_TAG)) {
/* ReasonCode = AUTHRJT_FAILURE; */
/* ReasonCodeExplanation = AUTHEXP_BAD_PAYLOAD; */
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_auth_msg_npr_node: payload(5)=0x%x",
(LE_SWAP32(*(uint32_t *)temp) & 0xFFFF0000) >> 16);
goto AUTH_Reject;
}
/* Get num_hs */
num_hs = LE_SWAP32(*(uint32_t *)temp) & 0x0000FFFF;
temp += sizeof (uint32_t);
/* Check HashList_value1 */
hs_id[0] = *(uint32_t *)temp;
if ((hs_id[0] != AUTH_MD5) && (hs_id[0] != AUTH_SHA1)) {
/* ReasonCode = AUTHRJT_LOGIC_ERR; */
/* ReasonCodeExplanation = AUTHEXP_HASHFUNC_UNUSABLE; */
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_auth_msg_npr_node: payload(6)=0x%x",
(*(uint32_t *)temp));
goto AUTH_Reject;
}
if (num_hs == 1) {
hs_id[1] = 0;
} else if (num_hs == 2) {
temp += sizeof (uint32_t);
hs_id[1] = *(uint32_t *)temp;
if ((hs_id[1] != AUTH_MD5) && (hs_id[1] != AUTH_SHA1)) {
/* ReasonCode = AUTHRJT_LOGIC_ERR; */
/* ReasonCodeExplanation = AUTHEXP_HASHFUNC_UNUSABLE; */
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_auth_msg_npr_node: payload(7)=0x%x",
(*(uint32_t *)temp));
goto AUTH_Reject;
}
if (hs_id[0] == hs_id[1]) {
/* ReasonCode = AUTHRJT_FAILURE; */
/* ReasonCodeExplanation = AUTHEXP_BAD_PAYLOAD; */
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_auth_msg_npr_node: payload(8)=0x%x",
(*(uint32_t *)temp));
goto AUTH_Reject;
}
} else {
/* ReasonCode = AUTHRJT_FAILURE; */
/* ReasonCodeExplanation = AUTHEXP_BAD_PAYLOAD; */
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_auth_msg_npr_node: payload(9)=0x%x",
(*(uint32_t *)(temp - sizeof (uint32_t))));
goto AUTH_Reject;
}
/* Which hash_id should we use */
if (num_hs == 1) {
/*
* We always use the highest priority specified by us if we
* match initiator's , Otherwise, we use the next higher we
* both have. CR 26238
*/
if (node_dhc->auth_cfg.hash_priority[0] == hs_id[0]) {
hash_id = node_dhc->auth_cfg.hash_priority[0];
} else if (node_dhc->auth_cfg.hash_priority[1] == hs_id[0]) {
hash_id = node_dhc->auth_cfg.hash_priority[1];
} else {
/* ReasonCode = AUTHRJT_LOGIC_ERR; */
/* ReasonCodeExplanation = AUTHEXP_HASHFUNC_UNUSABLE; */
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_auth_msg_npr_node: payload(10)=0x%lx",
(*(uint32_t *)temp));
goto AUTH_Reject;
}
} else {
/*
* Since the initiator specified two hashs, we always select
* our first one.
*/
hash_id = node_dhc->auth_cfg.hash_priority[0];
}
temp += sizeof (uint32_t);
/* Check DHgIDList_tag */
if ((LE_SWAP32(*(uint32_t *)temp) & 0xFFFF0000) >> 16 !=
LE_SWAP16(DHGID_LIST_TAG)) {
/* ReasonCode = AUTHRJT_FAILURE; */
/* ReasonCodeExplanation = AUTHEXP_BAD_PAYLOAD; */
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_auth_msg_npr_node: payload(11)=0x%lx",
(*(uint32_t *)temp));
goto AUTH_Reject;
}
/* Get num_dh */
num_dh = LE_SWAP32(*(uint32_t *)temp) & 0x0000FFFF;
if (num_dh == 0) {
/* ReasonCode = AUTHRJT_FAILURE; */
/* ReasonCodeExplanation = AUTHEXP_BAD_PAYLOAD; */
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_auth_msg_npr_node: payload(12)=0x%lx",
(*(uint32_t *)temp));
goto AUTH_Reject;
}
for (i = 0; i < num_dh; i++) {
temp += sizeof (uint32_t);
/* Check DHgIDList_g0 */
dh_id[i] = (*(uint32_t *)temp);
}
rc = emlxs_check_dhgp(port, ndlp, dh_id, num_dh, &dhgp_id);
if (rc == 1) {
/* ReasonCode = AUTHRJT_LOGIC_ERR; */
/* ReasonCodeExplanation = AUTHEXP_DHGROUP_UNUSABLE; */
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_auth_msg_npr_node: payload(13)=0x%lx",
(*(uint32_t *)temp));
goto AUTH_Reject;
} else if (rc == 2) {
/* ReasonCode = AUTHRJT_FAILURE; */
/* ReasonCodeExplanation = AUTHEXP_BAD_PAYLOAD; */
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"rcv_auth_msg_npr_node: payload(14)=0x%lx",
(*(uint32_t *)temp));
goto AUTH_Reject;
}
/* We should update the tran_id */
node_dhc->nlp_auth_tranid_ini = msg->tran_id;
if (msg->auth_msg_code == AUTH_NEGOTIATE) {
node_dhc->nlp_auth_flag = 1; /* ndlp is the initiator */
/* Send back the DHCHAP_Challenge with the proper paramaters */
if (emlxs_issue_dhchap_challenge(port, ndlp, 0, tmp,
LE_SWAP32(msglen),
hash_id, dhgp_id)) {
goto AUTH_Reject;
}
emlxs_dhc_state(port, ndlp,
NODE_STATE_DHCHAP_CHALLENGE_ISSUE, 0, 0);
} else {
goto AUTH_Reject;
}
return (node_dhc->state);
AUTH_Reject:
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_auth_msg_npr_node: AUTH_Reject it.");
return (node_dhc->state);
} /* emlxs_rcv_auth_msg_npr_node */
/* ARGSUSED */
static uint32_t
emlxs_cmpl_auth_msg_npr_node(
emlxs_port_t *port,
/* CHANNEL * rp, */ void *arg1,
/* IOCBQ * iocbq, */ void *arg2,
/* MATCHMAP * mp, */ void *arg3,
/* NODELIST * ndlp */ void *arg4,
uint32_t evt)
{
NODELIST *ndlp = (NODELIST *)arg4;
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
/*
* we donot cancel the nodev timeout here because we donot know if we
* can get the authentication restarted from other side once we got
* the new auth transaction kicked off we cancel nodev tmo
* immediately.
*/
/* we goto change the hba state back to where it used to be */
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"cmpl_auth_msg_npr_node: 0x%x 0x%x prev_state=0x%x\n",
ndlp->nlp_DID, node_dhc->state, node_dhc->prev_state);
return (node_dhc->state);
} /* emlxs_cmpl_auth_msg_npr_node */
/*
* ! emlxs_rcv_auth_msg_unmapped_node
*
* \pre \post \param phba \param ndlp \param arg \param evt \return
* uint32_t
*
* \b Description: This routine is invoked when the host received an
* unsolicited els authentication msg from the Fx_Port which is
* wellknown port 0xFFFFFE in unmapped state, or from Nx_Port which is
* in the unmapped state meaning that it is either a target
* which there is no scsi id associated with it or it could be another
* initiator. (end-to-end)
*
* For the Fabric F_Port (FFFFFE) we mark the port to the state in re_auth
* state without disruppting the traffic. Then the fabric
* will go through the authentication processes until it is done.
*
* most of the cases, the fabric should send us AUTH_Negotiate ELS msg. Once
* host received this auth_negotiate els msg, host
* should sent back ACC first and then send random challenge, plus DH value
* (i.e., host's publick key)
*
* Host side needs to store the challenge value and public key for later
* verification usage. (i.e., to verify the response from
* initiator)
*
* If two FC_Ports start the reauthentication transaction at the same time,
* one of the two authentication transactions shall be
* aborted. In case of Host and Fabric the Nx_Port shall remain the
* authentication initiator, while the Fx_Port shall become
* the authentication responder.
*
*/
/* ARGSUSED */
static uint32_t
emlxs_rcv_auth_msg_unmapped_node(
emlxs_port_t *port,
/* CHANNEL * rp, */ void *arg1,
/* IOCBQ * iocbq, */ void *arg2,
/* MATCHMAP * mp, */ void *arg3,
/* NODELIST * ndlp */ void *arg4,
uint32_t evt)
{
IOCBQ *iocbq = (IOCBQ *)arg2;
MATCHMAP *mp = (MATCHMAP *)arg3;
NODELIST *ndlp = (NODELIST *)arg4;
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
uint8_t *bp;
uint32_t *lp;
uint32_t msglen;
uint8_t *tmp;
uint8_t ReasonCode;
uint8_t ReasonCodeExplanation;
AUTH_MSG_HDR *msg;
uint8_t *temp;
uint32_t rc, i, hs_id[2], dh_id[5];
/* from initiator */
uint32_t hash_id, dhgp_id; /* to be used by responder */
uint16_t num_hs = 0;
uint16_t num_dh = 0;
/*
* 1. process the auth msg, should acc first no matter what. 2.
* return DHCHAP_Challenge for AUTH_Negotiate auth msg, AUTH_Reject
* for anything else.
*/
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_auth_msg_unmapped_node: Sending ACC: did=0x%x",
ndlp->nlp_DID);
(void) emlxs_els_reply(port, iocbq, ELS_CMD_ACC, ELS_CMD_AUTH, 0, 0);
bp = mp->virt;
lp = (uint32_t *)bp;
msg = (AUTH_MSG_HDR *)((uint8_t *)lp);
msglen = msg->msg_len;
tmp = ((uint8_t *)lp);
/* temp is used for error checking */
temp = (uint8_t *)((uint8_t *)lp);
/* Check the auth_els_code */
if (((*(uint32_t *)temp) & 0xFFFFFFFF) != LE_SWAP32(0x90000B01)) {
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_BAD_PAYLOAD;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_auth_msg_unmapped_node: payload(1)=0x%x",
(*(uint32_t *)temp));
goto AUTH_Reject;
}
temp += 3 * sizeof (uint32_t);
/* Check name tag and name length */
if (((*(uint32_t *)temp) & 0xFFFFFFFF) != LE_SWAP32(0x00010008)) {
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_BAD_PAYLOAD;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_auth_msg_unmapped_node: payload(2)=0x%x",
(*(uint32_t *)temp));
goto AUTH_Reject;
}
temp += sizeof (uint32_t) + 8;
/* Check proto_num */
if (((*(uint32_t *)temp) & 0xFFFFFFFF) != LE_SWAP32(0x00000001)) {
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_BAD_PAYLOAD;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_auth_msg_unmapped_node: payload(3)=0x%x",
(*(uint32_t *)temp));
goto AUTH_Reject;
}
temp += sizeof (uint32_t);
/* Get para_len */
/* para_len = *(uint32_t *)temp; */
temp += sizeof (uint32_t);
/* Check proto_id */
if (((*(uint32_t *)temp) & 0xFFFFFFFF) != AUTH_DHCHAP) {
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_BAD_PROTOCOL;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_auth_msg_unmapped_node: payload(4)=0x%x",
(*(uint32_t *)temp));
goto AUTH_Reject;
}
temp += sizeof (uint32_t);
/* Check hashlist tag */
if ((LE_SWAP32(*(uint32_t *)temp) & 0xFFFF0000) >> 16 !=
LE_SWAP16(HASH_LIST_TAG)) {
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_BAD_PAYLOAD;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_auth_msg_unmapped_node: payload(5)=0x%x",
(LE_SWAP32(*(uint32_t *)temp) & 0xFFFF0000) >> 16);
goto AUTH_Reject;
}
/* Get num_hs */
num_hs = LE_SWAP32(*(uint32_t *)temp) & 0x0000FFFF;
temp += sizeof (uint32_t);
/* Check HashList_value1 */
hs_id[0] = *(uint32_t *)temp;
if ((hs_id[0] != AUTH_MD5) && (hs_id[0] != AUTH_SHA1)) {
ReasonCode = AUTHRJT_LOGIC_ERR;
ReasonCodeExplanation = AUTHEXP_HASHFUNC_UNUSABLE;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_auth_msg_unmapped_node: payload(6)=0x%x",
(*(uint32_t *)temp));
goto AUTH_Reject;
}
if (num_hs == 1) {
hs_id[1] = 0;
} else if (num_hs == 2) {
temp += sizeof (uint32_t);
hs_id[1] = *(uint32_t *)temp;
if ((hs_id[1] != AUTH_MD5) && (hs_id[1] != AUTH_SHA1)) {
ReasonCode = AUTHRJT_LOGIC_ERR;
ReasonCodeExplanation = AUTHEXP_HASHFUNC_UNUSABLE;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_auth_msg_unmapped_node: payload(7)=0x%x",
(*(uint32_t *)temp));
goto AUTH_Reject;
}
if (hs_id[0] == hs_id[1]) {
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_BAD_PAYLOAD;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_auth_msg_unmapped_node: payload(8)=0x%x",
(*(uint32_t *)temp));
goto AUTH_Reject;
}
} else {
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_BAD_PAYLOAD;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_auth_msg_unmapped_node: payload(9)=0x%x",
(*(uint32_t *)(temp - sizeof (uint32_t))));
goto AUTH_Reject;
}
/* Which hash_id should we use */
if (num_hs == 1) {
/*
* We always use the highest priority specified by us if we
* match initiator's , Otherwise, we use the next higher we
* both have. CR 26238
*/
if (node_dhc->auth_cfg.hash_priority[0] == hs_id[0]) {
hash_id = node_dhc->auth_cfg.hash_priority[0];
} else if (node_dhc->auth_cfg.hash_priority[1] == hs_id[0]) {
hash_id = node_dhc->auth_cfg.hash_priority[1];
} else {
ReasonCode = AUTHRJT_LOGIC_ERR;
ReasonCodeExplanation = AUTHEXP_HASHFUNC_UNUSABLE;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_auth_msg_unmapped_node: pload(10)=0x%x",
(*(uint32_t *)temp));
goto AUTH_Reject;
}
} else {
/*
* Since the initiator specified two hashs, we always select
* our first one.
*/
hash_id = node_dhc->auth_cfg.hash_priority[0];
}
temp += sizeof (uint32_t);
/* Check DHgIDList_tag */
if ((LE_SWAP32(*(uint32_t *)temp) & 0xFFFF0000) >> 16 !=
LE_SWAP16(DHGID_LIST_TAG)) {
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_BAD_PAYLOAD;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_auth_msg_unmapped_node: payload(11)=0x%x",
(*(uint32_t *)temp));
goto AUTH_Reject;
}
/* Get num_dh */
num_dh = LE_SWAP32(*(uint32_t *)temp) & 0x0000FFFF;
if (num_dh == 0) {
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_BAD_PAYLOAD;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_auth_msg_unmapped_node: payload(12)=0x%x",
(*(uint32_t *)temp));
goto AUTH_Reject;
}
for (i = 0; i < num_dh; i++) {
temp += sizeof (uint32_t);
/* Check DHgIDList_g0 */
dh_id[i] = (*(uint32_t *)temp);
}
rc = emlxs_check_dhgp(port, ndlp, dh_id, num_dh, &dhgp_id);
if (rc == 1) {
ReasonCode = AUTHRJT_LOGIC_ERR;
ReasonCodeExplanation = AUTHEXP_DHGROUP_UNUSABLE;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_auth_msg_unmapped_node: payload(13)=0x%x",
(*(uint32_t *)temp));
goto AUTH_Reject;
} else if (rc == 2) {
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_BAD_PAYLOAD;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_auth_msg_unmapped_node: payload(14)=0x%x",
(*(uint32_t *)temp));
goto AUTH_Reject;
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_auth_msg_unmapped_node: 0x%x 0x%x 0x%x 0x%x 0x%x",
hash_id, dhgp_id, msg->auth_msg_code, msglen, msg->tran_id);
/*
* since ndlp is the initiator, tran_id is store in
* nlp_auth_tranid_ini
*/
node_dhc->nlp_auth_tranid_ini = LE_SWAP32(msg->tran_id);
if (msg->auth_msg_code == AUTH_NEGOTIATE) {
/*
* at this point, we know for sure we received the
* auth-negotiate msg from another entity, so cancel the
* auth-rsp timeout timer if we are expecting it. should
* never happen?
*/
node_dhc->nlp_auth_flag = 1;
if (node_dhc->nlp_authrsp_tmo) {
node_dhc->nlp_authrsp_tmo = 0;
}
/*
* If at this point, the host is doing reauthentication
* (reauth heart beat) to this ndlp, then Host should remain
* as the auth initiator, host should reply to the received
* AUTH_Negotiate message with an AUTH_Reject message with
* Reason Code 'Logical Error' and Reason Code Explanation
* 'Authentication Transaction Already Started'.
*/
if (node_dhc->nlp_reauth_status ==
NLP_HOST_REAUTH_IN_PROGRESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"rcv_auth_msg_unmapped_node: Ht reauth inprgress.");
ReasonCode = AUTHRJT_LOGIC_ERR;
ReasonCodeExplanation = AUTHEXP_AUTHTRAN_STARTED;
goto AUTH_Reject;
}
/* Send back the DHCHAP_Challenge with the proper paramaters */
if (emlxs_issue_dhchap_challenge(port, ndlp, 0, tmp,
LE_SWAP32(msglen),
hash_id, dhgp_id)) {
goto AUTH_Reject;
}
/* setup the proper state */
emlxs_dhc_state(port, ndlp,
NODE_STATE_DHCHAP_CHALLENGE_ISSUE, 0, 0);
} else {
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_BAD_PROTOCOL;
goto AUTH_Reject;
}
return (node_dhc->state);
AUTH_Reject:
emlxs_dhc_state(port, ndlp, NODE_STATE_AUTH_FAILED,
ReasonCode, ReasonCodeExplanation);
(void) emlxs_issue_auth_reject(port, ndlp, 0, 0, ReasonCode,
ReasonCodeExplanation);
emlxs_dhc_auth_complete(port, ndlp, 1);
return (node_dhc->state);
} /* emlxs_rcv_auth_msg_unmapped_node */
/*
* emlxs_hash_vrf for verification only the host is the initiator in
* the routine.
*/
/* ARGSUSED */
static uint32_t *
emlxs_hash_vrf(
emlxs_port_t *port,
emlxs_port_dhc_t *port_dhc,
NODELIST *ndlp,
uint32_t tran_id,
union challenge_val un_cval)
{
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
uint32_t dhgp_id;
uint32_t hash_id;
uint32_t *hash_val;
uint32_t hash_size;
MD5_CTX mdctx;
SHA1_CTX sha1ctx;
uint8_t sha1_digest[20];
uint8_t md5_digest[16];
uint8_t mytran_id = 0x00;
char *remote_key;
tran_id = (AUTH_TRAN_ID_MASK & tran_id);
mytran_id = (uint8_t)(LE_SWAP32(tran_id));
if (ndlp->nlp_DID == FABRIC_DID) {
remote_key = (char *)node_dhc->auth_key.remote_password;
hash_id = node_dhc->hash_id;
dhgp_id = node_dhc->dhgp_id;
} else {
remote_key = (char *)node_dhc->auth_key.remote_password;
hash_id = node_dhc->nlp_auth_hashid;
dhgp_id = node_dhc->nlp_auth_dhgpid;
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"hash_vrf: 0x%x 0x%x 0x%x tran_id=0x%x",
ndlp->nlp_DID, hash_id, dhgp_id, mytran_id);
if (dhgp_id == 0) {
/* NULL DHCHAP */
if (hash_id == AUTH_MD5) {
bzero(&mdctx, sizeof (MD5_CTX));
hash_size = MD5_LEN;
MD5Init(&mdctx);
/* Transaction Identifier T */
MD5Update(&mdctx, (unsigned char *) &mytran_id, 1);
MD5Update(&mdctx, (unsigned char *) remote_key,
node_dhc->auth_key.remote_password_length);
/* Augmented challenge: NULL DHCHAP i.e., Challenge */
MD5Update(&mdctx,
(unsigned char *)&(un_cval.md5.val[0]), MD5_LEN);
MD5Final((uint8_t *)md5_digest, &mdctx);
hash_val = (uint32_t *)kmem_alloc(hash_size,
KM_NOSLEEP);
if (hash_val == NULL) {
return (NULL);
} else {
bcopy((void *)&md5_digest,
(void *)hash_val, MD5_LEN);
}
/*
* emlxs_md5_digest_to_hex((uint8_t *)hash_val,
* output);
*/
}
if (hash_id == AUTH_SHA1) {
bzero(&sha1ctx, sizeof (SHA1_CTX));
hash_size = SHA1_LEN;
SHA1Init(&sha1ctx);
SHA1Update(&sha1ctx, (void *)&mytran_id, 1);
SHA1Update(&sha1ctx, (void *)remote_key,
node_dhc->auth_key.remote_password_length);
SHA1Update(&sha1ctx,
(void *)&(un_cval.sha1.val[0]), SHA1_LEN);
SHA1Final((void *)sha1_digest, &sha1ctx);
/*
* emlxs_sha1_digest_to_hex((uint8_t *)hash_val,
* output);
*/
hash_val = (uint32_t *)kmem_alloc(hash_size,
KM_NOSLEEP);
if (hash_val == NULL) {
return (NULL);
} else {
bcopy((void *)&sha1_digest,
(void *)hash_val, SHA1_LEN);
}
}
return ((uint32_t *)hash_val);
} else {
/* Verification of bi-dir auth for DH-CHAP group */
/* original challenge is node_dhc->bi_cval[] */
/* session key is node_dhc->ses_key[] */
/* That's IT */
/*
* H(bi_cval || ses_key) = C H(Ti || Km || C) = hash_val
*/
if (hash_id == AUTH_MD5) {
bzero(&mdctx, sizeof (MD5_CTX));
hash_size = MD5_LEN;
MD5Init(&mdctx);
MD5Update(&mdctx,
(void *)&(un_cval.md5.val[0]), MD5_LEN);
if (ndlp->nlp_DID == FABRIC_DID) {
MD5Update(&mdctx,
(void *)&node_dhc->ses_key[0],
node_dhc->seskey_len);
} else {
/* ses_key is obtained in emlxs_hash_rsp */
MD5Update(&mdctx,
(void *)&node_dhc->nlp_auth_misc.ses_key[0],
node_dhc->nlp_auth_misc.seskey_len);
}
MD5Final((void *)md5_digest, &mdctx);
MD5Init(&mdctx);
MD5Update(&mdctx, (void *)&mytran_id, 1);
MD5Update(&mdctx, (void *)remote_key,
node_dhc->auth_key.remote_password_length);
MD5Update(&mdctx, (void *)md5_digest, MD5_LEN);
MD5Final((void *)md5_digest, &mdctx);
hash_val = (uint32_t *)kmem_alloc(hash_size,
KM_NOSLEEP);
if (hash_val == NULL) {
return (NULL);
} else {
bcopy((void *)&md5_digest,
(void *)hash_val, MD5_LEN);
}
}
if (hash_id == AUTH_SHA1) {
bzero(&sha1ctx, sizeof (SHA1_CTX));
hash_size = SHA1_LEN;
SHA1Init(&sha1ctx);
SHA1Update(&sha1ctx,
(void *)&(un_cval.sha1.val[0]), SHA1_LEN);
if (ndlp->nlp_DID == FABRIC_DID) {
SHA1Update(&sha1ctx,
(void *)&node_dhc->ses_key[0],
node_dhc->seskey_len);
} else {
/* ses_key was obtained in emlxs_hash_rsp */
SHA1Update(&sha1ctx,
(void *)&node_dhc->nlp_auth_misc.ses_key[0],
node_dhc->nlp_auth_misc.seskey_len);
}
SHA1Final((void *)sha1_digest, &sha1ctx);
SHA1Init(&sha1ctx);
SHA1Update(&sha1ctx, (void *)&mytran_id, 1);
SHA1Update(&sha1ctx, (void *)remote_key,
node_dhc->auth_key.remote_password_length);
SHA1Update(&sha1ctx, (void *)sha1_digest, SHA1_LEN);
SHA1Final((void *)sha1_digest, &sha1ctx);
hash_val = (uint32_t *)kmem_alloc(hash_size,
KM_NOSLEEP);
if (hash_val == NULL) {
return (NULL);
} else {
bcopy((void *)&sha1_digest,
(void *)hash_val, SHA1_LEN);
}
}
return ((uint32_t *)hash_val);
}
} /* emlxs_hash_vrf */
/*
* If dhval == NULL, NULL DHCHAP else, DHCHAP group.
*
* This routine is used by the auth transaction initiator (Who does the
* auth-negotiate) to calculate the R1 (response) based on
* the dh value it received, its own random private key, the challenge it
* received, and Transaction id, as well as the password
* associated with this very initiator in the auth pair.
*/
uint32_t *
emlxs_hash_rsp(
emlxs_port_t *port,
emlxs_port_dhc_t *port_dhc,
NODELIST *ndlp,
uint32_t tran_id,
union challenge_val un_cval,
uint8_t *dhval,
uint32_t dhvallen)
{
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
uint32_t dhgp_id;
uint32_t hash_id;
uint32_t *hash_val;
uint32_t hash_size;
MD5_CTX mdctx;
SHA1_CTX sha1ctx;
uint8_t sha1_digest[20];
uint8_t md5_digest[16];
uint8_t Cai[20];
uint8_t mytran_id = 0x00;
char *mykey;
BIG_ERR_CODE err = BIG_OK;
if (ndlp->nlp_DID == FABRIC_DID) {
hash_id = node_dhc->hash_id;
dhgp_id = node_dhc->dhgp_id;
} else {
hash_id = node_dhc->nlp_auth_hashid;
dhgp_id = node_dhc->nlp_auth_dhgpid;
}
tran_id = (AUTH_TRAN_ID_MASK & tran_id);
mytran_id = (uint8_t)(LE_SWAP32(tran_id));
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"hash_rsp: 0x%x 0x%x 0x%x 0x%x dhvallen=0x%x",
ndlp->nlp_DID, hash_id, dhgp_id, mytran_id, dhvallen);
if (ndlp->nlp_DID == FABRIC_DID) {
mykey = (char *)node_dhc->auth_key.local_password;
} else {
mykey = (char *)node_dhc->auth_key.local_password;
}
if (dhval == NULL) {
/* NULL DHCHAP */
if (hash_id == AUTH_MD5) {
bzero(&mdctx, sizeof (MD5_CTX));
hash_size = MD5_LEN;
MD5Init(&mdctx);
MD5Update(&mdctx, (unsigned char *)&mytran_id, 1);
MD5Update(&mdctx, (unsigned char *)mykey,
node_dhc->auth_key.local_password_length);
MD5Update(&mdctx,
(unsigned char *)&(un_cval.md5.val[0]),
MD5_LEN);
MD5Final((uint8_t *)md5_digest, &mdctx);
hash_val = (uint32_t *)kmem_alloc(hash_size,
KM_NOSLEEP);
if (hash_val == NULL) {
return (NULL);
} else {
bcopy((void *)&md5_digest,
(void *)hash_val, MD5_LEN);
}
/*
* emlxs_md5_digest_to_hex((uint8_t *)hash_val,
* output);
*/
}
if (hash_id == AUTH_SHA1) {
bzero(&sha1ctx, sizeof (SHA1_CTX));
hash_size = SHA1_LEN;
SHA1Init(&sha1ctx);
SHA1Update(&sha1ctx, (void *)&mytran_id, 1);
SHA1Update(&sha1ctx, (void *)mykey,
node_dhc->auth_key.local_password_length);
SHA1Update(&sha1ctx,
(void *)&(un_cval.sha1.val[0]), SHA1_LEN);
SHA1Final((void *)sha1_digest, &sha1ctx);
/*
* emlxs_sha1_digest_to_hex((uint8_t *)hash_val,
* output);
*/
hash_val = (uint32_t *)kmem_alloc(hash_size,
KM_NOSLEEP);
if (hash_val == NULL) {
return (NULL);
} else {
bcopy((void *)&sha1_digest,
(void *)hash_val, SHA1_LEN);
}
}
return ((uint32_t *)hash_val);
} else {
/* process DH grops */
/*
* calculate interm hash value Ca1 Ca1 = H(C1 || (g^x mod
* p)^y mod p) in which C1 is the challenge received. g^x mod
* p is the dhval received y is the random number in 16 bytes
* for MD5, 20 bytes for SHA1 p is hardcoded value based on
* different DH groups.
*
* To calculate hash value R1 R1 = H (Ti || Kn || Cai) in which
* Ti is the transaction identifier Kn is the shared secret.
* Cai is the result from interm hash.
*
* g^y mod p is reserved in port_dhc as pubkey (public key).for
* bi-dir challenge is another random number. y is prikey
* (private key). ((g^x mod p)^y mod p) is sekey (session
* key)
*/
err = emlxs_interm_hash(port, port_dhc, ndlp,
(void *)&Cai, tran_id,
un_cval, dhval, &dhvallen);
if (err != BIG_OK) {
return (NULL);
}
if (hash_id == AUTH_MD5) {
bzero(&mdctx, sizeof (MD5_CTX));
hash_size = MD5_LEN;
MD5Init(&mdctx);
MD5Update(&mdctx, (unsigned char *)&mytran_id, 1);
MD5Update(&mdctx, (unsigned char *)mykey,
node_dhc->auth_key.local_password_length);
MD5Update(&mdctx, (unsigned char *)Cai, MD5_LEN);
MD5Final((uint8_t *)md5_digest, &mdctx);
hash_val = (uint32_t *)kmem_alloc(hash_size,
KM_NOSLEEP);
if (hash_val == NULL) {
return (NULL);
} else {
bcopy((void *)&md5_digest,
(void *)hash_val, MD5_LEN);
}
}
if (hash_id == AUTH_SHA1) {
bzero(&sha1ctx, sizeof (SHA1_CTX));
hash_size = SHA1_LEN;
SHA1Init(&sha1ctx);
SHA1Update(&sha1ctx, (void *)&mytran_id, 1);
SHA1Update(&sha1ctx, (void *)mykey,
node_dhc->auth_key.local_password_length);
SHA1Update(&sha1ctx, (void *)&Cai[0], SHA1_LEN);
SHA1Final((void *)sha1_digest, &sha1ctx);
hash_val = (uint32_t *)kmem_alloc(hash_size,
KM_NOSLEEP);
if (hash_val == NULL) {
return (NULL);
} else {
bcopy((void *)&sha1_digest,
(void *)hash_val, SHA1_LEN);
}
}
return ((uint32_t *)hash_val);
}
} /* emlxs_hash_rsp */
/*
* To get the augmented challenge Cai Stored in hash_val
*
* Cai = Hash (C1 || ((g^x mod p)^y mod p)) = Hash (C1 || (g^(x*y) mod p)
*
* C1:challenge received from the remote entity (g^x mod p): dh val
* received from the remote entity (remote entity's pubkey) y:
* random private key from the local entity Hash: hash function used in
* agreement. (g^(x*y) mod p): shared session key (aka
* shared secret) (g^y mod p): local entity's pubkey
*/
/* ARGSUSED */
BIG_ERR_CODE
emlxs_interm_hash(
emlxs_port_t *port,
emlxs_port_dhc_t *port_dhc,
NODELIST *ndlp,
void *hash_val,
uint32_t tran_id,
union challenge_val un_cval,
uint8_t *dhval,
uint32_t *dhvallen)
{
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
uint32_t dhgp_id;
uint32_t hash_id;
MD5_CTX mdctx;
SHA1_CTX sha1ctx;
uint8_t sha1_digest[20];
uint8_t md5_digest[16];
uint32_t hash_size;
BIG_ERR_CODE err = BIG_OK;
if (ndlp->nlp_DID == FABRIC_DID) {
hash_id = node_dhc->hash_id;
dhgp_id = node_dhc->dhgp_id;
} else {
hash_id = node_dhc->nlp_auth_hashid;
dhgp_id = node_dhc->nlp_auth_dhgpid;
}
if (hash_id == AUTH_MD5) {
bzero(&mdctx, sizeof (MD5_CTX));
hash_size = MD5_LEN;
MD5Init(&mdctx);
MD5Update(&mdctx,
(unsigned char *)&(un_cval.md5.val[0]), MD5_LEN);
/*
* get the pub key (g^y mod p) and session key (g^(x*y) mod
* p) and stored them in the partner's ndlp structure
*/
err = emlxs_BIGNUM_get_pubkey(port, port_dhc, ndlp,
dhval, dhvallen, hash_size, dhgp_id);
if (err != BIG_OK) {
return (err);
}
if (ndlp->nlp_DID == FABRIC_DID) {
MD5Update(&mdctx,
(unsigned char *)&node_dhc->ses_key[0],
node_dhc->seskey_len);
} else {
MD5Update(&mdctx,
(unsigned char *)&node_dhc->nlp_auth_misc.ses_key[0],
node_dhc->nlp_auth_misc.seskey_len);
}
MD5Final((uint8_t *)md5_digest, &mdctx);
bcopy((void *)&md5_digest, (void *)hash_val, MD5_LEN);
}
if (hash_id == AUTH_SHA1) {
bzero(&sha1ctx, sizeof (SHA1_CTX));
hash_size = SHA1_LEN;
SHA1Init(&sha1ctx);
SHA1Update(&sha1ctx, (void *)&(un_cval.sha1.val[0]), SHA1_LEN);
/* get the pub key and session key */
err = emlxs_BIGNUM_get_pubkey(port, port_dhc, ndlp,
dhval, dhvallen, hash_size, dhgp_id);
if (err != BIG_OK) {
return (err);
}
if (ndlp->nlp_DID == FABRIC_DID) {
SHA1Update(&sha1ctx, (void *)&node_dhc->ses_key[0],
node_dhc->seskey_len);
} else {
SHA1Update(&sha1ctx,
(void *)&node_dhc->nlp_auth_misc.ses_key[0],
node_dhc->nlp_auth_misc.seskey_len);
}
SHA1Final((void *)sha1_digest, &sha1ctx);
bcopy((void *)&sha1_digest, (void *)hash_val, SHA1_LEN);
}
return (err);
} /* emlxs_interm_hash */
/*
* This routine get the pubkey and session key. these pubkey and session
* key are stored in the partner's ndlp structure.
*/
/* ARGSUSED */
BIG_ERR_CODE
emlxs_BIGNUM_get_pubkey(
emlxs_port_t *port,
emlxs_port_dhc_t *port_dhc,
NODELIST *ndlp,
uint8_t *dhval,
uint32_t *dhvallen,
uint32_t hash_size,
uint32_t dhgp_id)
{
emlxs_hba_t *hba = HBA;
BIGNUM a, e, n, result;
uint32_t plen;
uint8_t random_number[20];
unsigned char *tmp = NULL;
BIGNUM g, result1;
#ifdef BIGNUM_CHUNK_32
uint8_t gen[] = {0x00, 0x00, 0x00, 0x02};
#else
uint8_t gen[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02};
#endif /* BIGNUM_CHUNK_32 */
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
BIG_ERR_CODE err = BIG_OK;
/*
* compute a^e mod n assume a < n, n odd, result->value at least as
* long as n->value.
*
* a is the public key received from responder. e is the private key
* generated by me. n is the wellknown modulus.
*/
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"BIGNUM_get_pubkey: 0x%x 0x%x 0x%x 0x%x",
ndlp->nlp_DID, *dhvallen, hash_size, dhgp_id);
/* size should be in the unit of (BIG_CHUNK_TYPE) words */
if (big_init(&a, CHARLEN2BIGNUMLEN(*dhvallen)) != BIG_OK) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"BIGNUM_get_pubkey: big_init failed. a size=%d",
CHARLEN2BIGNUMLEN(*dhvallen));
err = BIG_NO_MEM;
return (err);
}
/* a: (g^x mod p) */
/*
* dhval is in big-endian format. This call converts from
* byte-big-endian format to big number format (words in little
* endian order, but bytes within the words big endian)
*/
bytestring2bignum(&a, (unsigned char *)dhval, *dhvallen);
if (big_init(&e, CHARLEN2BIGNUMLEN(hash_size)) != BIG_OK) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"BIGNUM_get_pubkey: big_init failed. e size=%d",
CHARLEN2BIGNUMLEN(hash_size));
err = BIG_NO_MEM;
goto ret1;
}
#ifdef RAND
bzero(&random_number, hash_size);
/* to get random private key: y */
/* remember y is short lived private key */
if (hba->rdn_flag == 1) {
emlxs_get_random_bytes(ndlp, random_number, 20);
} else {
(void) random_get_pseudo_bytes(random_number, hash_size);
}
/* e: y */
bytestring2bignum(&e, (unsigned char *)random_number, hash_size);
#endif /* RAND */
#ifdef MYRAND
bytestring2bignum(&e, (unsigned char *)myrand, hash_size);
printf("myrand random_number as Y ================\n");
for (i = 0; i < 5; i++) {
for (j = 0; j < 4; j++) {
printf("%x", myrand[(i * 4) + j]);
}
printf("\n");
}
#endif /* MYRAND */
switch (dhgp_id) {
case GROUP_1024:
plen = 128;
tmp = dhgp1_pVal;
break;
case GROUP_1280:
plen = 160;
tmp = dhgp2_pVal;
break;
case GROUP_1536:
plen = 192;
tmp = dhgp3_pVal;
break;
case GROUP_2048:
plen = 256;
tmp = dhgp4_pVal;
break;
}
if (big_init(&n, CHARLEN2BIGNUMLEN(plen)) != BIG_OK) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"BIGNUM_get_pubkey: big_init failed. n size=%d",
CHARLEN2BIGNUMLEN(plen));
err = BIG_NO_MEM;
goto ret2;
}
bytestring2bignum(&n, (unsigned char *)tmp, plen);
if (big_init(&result, CHARLEN2BIGNUMLEN(512)) != BIG_OK) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"BIGNUM_get_pubkey: big_init failed. result size=%d",
CHARLEN2BIGNUMLEN(512));
err = BIG_NO_MEM;
goto ret3;
}
if (big_cmp_abs(&a, &n) > 0) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"BIGNUM_get_pubkey: big_cmp_abs error.");
err = BIG_GENERAL_ERR;
goto ret4;
}
/* perform computation on big numbers to get seskey */
/* a^e mod n */
/* i.e., (g^x mod p)^y mod p */
if (big_modexp(&result, &a, &e, &n, NULL) != BIG_OK) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"BIGNUM_get_pubkey: big_modexp result error");
err = BIG_NO_MEM;
goto ret4;
}
/* convert big number ses_key to bytestring */
if (ndlp->nlp_DID == FABRIC_DID) {
/*
* This call converts from big number format to
* byte-big-endian format. big number format is words in
* little endian order, but bytes within words in native byte
* order
*/
bignum2bytestring(node_dhc->ses_key, &result,
sizeof (BIG_CHUNK_TYPE) * (result.len));
node_dhc->seskey_len = sizeof (BIG_CHUNK_TYPE) * (result.len);
/* we can store another copy in ndlp */
bignum2bytestring(node_dhc->nlp_auth_misc.ses_key, &result,
sizeof (BIG_CHUNK_TYPE) * (result.len));
node_dhc->nlp_auth_misc.seskey_len =
sizeof (BIG_CHUNK_TYPE) * (result.len);
} else {
/* for end-to-end auth */
bignum2bytestring(node_dhc->nlp_auth_misc.ses_key, &result,
sizeof (BIG_CHUNK_TYPE) * (result.len));
node_dhc->nlp_auth_misc.seskey_len =
sizeof (BIG_CHUNK_TYPE) * (result.len);
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"BIGNUM_get_pubkey: after seskey cal: 0x%x 0x%x 0x%x",
node_dhc->nlp_auth_misc.seskey_len, result.size, result.len);
/* to get pub_key: g^y mod p, g is 2 */
if (big_init(&g, 1) != BIG_OK) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"BIGNUM_get_pubkey: big_init failed. g size=1");
err = BIG_NO_MEM;
goto ret4;
}
if (big_init(&result1, CHARLEN2BIGNUMLEN(512)) != BIG_OK) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"BIGNUM_get_pubkey: big_init failed. result1 size=%d",
CHARLEN2BIGNUMLEN(512));
err = BIG_NO_MEM;
goto ret5;
}
bytestring2bignum(&g,
(unsigned char *)&gen, sizeof (BIG_CHUNK_TYPE));
if (big_modexp(&result1, &g, &e, &n, NULL) != BIG_OK) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"BIGNUM_get_pubkey: big_modexp result1 error");
err = BIG_NO_MEM;
goto ret6;
}
/* convert big number pub_key to bytestring */
if (ndlp->nlp_DID == FABRIC_DID) {
bignum2bytestring(node_dhc->pub_key, &result1,
sizeof (BIG_CHUNK_TYPE) * (result1.len));
node_dhc->pubkey_len = (result1.len) * sizeof (BIG_CHUNK_TYPE);
/* save another copy in ndlp */
bignum2bytestring(node_dhc->nlp_auth_misc.pub_key, &result1,
sizeof (BIG_CHUNK_TYPE) * (result1.len));
node_dhc->nlp_auth_misc.pubkey_len =
(result1.len) * sizeof (BIG_CHUNK_TYPE);
} else {
/* for end-to-end auth */
bignum2bytestring(node_dhc->nlp_auth_misc.pub_key, &result1,
sizeof (BIG_CHUNK_TYPE) * (result1.len));
node_dhc->nlp_auth_misc.pubkey_len =
(result1.len) * sizeof (BIG_CHUNK_TYPE);
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"BIGNUM_get_pubkey: after pubkey cal: 0x%x 0x%x 0x%x",
node_dhc->nlp_auth_misc.pubkey_len, result1.size, result1.len);
ret6:
big_finish(&result1);
ret5:
big_finish(&g);
ret4:
big_finish(&result);
ret3:
big_finish(&n);
ret2:
big_finish(&e);
ret1:
big_finish(&a);
return (err);
} /* emlxs_BIGNUM_get_pubkey */
/*
* g^x mod p x is the priv_key g and p are wellknow based on dhgp_id
*/
/* ARGSUSED */
static BIG_ERR_CODE
emlxs_BIGNUM_get_dhval(
emlxs_port_t *port,
emlxs_port_dhc_t *port_dhc,
NODELIST *ndlp,
uint8_t *dhval,
uint32_t *dhval_len,
uint32_t dhgp_id,
uint8_t *priv_key,
uint32_t privkey_len)
{
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
BIGNUM g, e, n, result1;
uint32_t plen;
unsigned char *tmp = NULL;
#ifdef BIGNUM_CHUNK_32
uint8_t gen[] = {0x00, 0x00, 0x00, 0x02};
#else
uint8_t gen[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02};
#endif /* BIGNUM_CHUNK_32 */
BIG_ERR_CODE err = BIG_OK;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"BIGNUM_get_dhval: did=0x%x privkey_len=0x%x dhgp_id=0x%x",
ndlp->nlp_DID, privkey_len, dhgp_id);
if (big_init(&result1, CHARLEN2BIGNUMLEN(512)) != BIG_OK) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"BIGNUM_get_dhval: big_init failed. result1 size=%d",
CHARLEN2BIGNUMLEN(512));
err = BIG_NO_MEM;
return (err);
}
if (big_init(&g, 1) != BIG_OK) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"BIGNUM_get_dhval: big_init failed. g size=1");
err = BIG_NO_MEM;
goto ret1;
}
/* get g */
bytestring2bignum(&g, (unsigned char *)gen, sizeof (BIG_CHUNK_TYPE));
if (big_init(&e, CHARLEN2BIGNUMLEN(privkey_len)) != BIG_OK) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"BIGNUM_get_dhval: big_init failed. e size=%d",
CHARLEN2BIGNUMLEN(privkey_len));
err = BIG_NO_MEM;
goto ret2;
}
/* get x */
bytestring2bignum(&e, (unsigned char *)priv_key, privkey_len);
switch (dhgp_id) {
case GROUP_1024:
plen = 128;
tmp = dhgp1_pVal;
break;
case GROUP_1280:
plen = 160;
tmp = dhgp2_pVal;
break;
case GROUP_1536:
plen = 192;
tmp = dhgp3_pVal;
break;
case GROUP_2048:
plen = 256;
tmp = dhgp4_pVal;
break;
}
if (big_init(&n, CHARLEN2BIGNUMLEN(plen)) != BIG_OK) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"BIGNUM_get_dhval: big_init failed. n size=%d",
CHARLEN2BIGNUMLEN(plen));
err = BIG_NO_MEM;
goto ret3;
}
/* get p */
bytestring2bignum(&n, (unsigned char *)tmp, plen);
/* to cal: (g^x mod p) */
if (big_modexp(&result1, &g, &e, &n, NULL) != BIG_OK) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"BIGNUM_get_dhval: big_modexp result1 error");
err = BIG_GENERAL_ERR;
goto ret4;
}
/* convert big number pub_key to bytestring */
if (ndlp->nlp_DID == FABRIC_DID) {
bignum2bytestring(node_dhc->hrsp_pub_key, &result1,
sizeof (BIG_CHUNK_TYPE) * (result1.len));
node_dhc->hrsp_pubkey_len =
(result1.len) * sizeof (BIG_CHUNK_TYPE);
/* save another copy in partner's ndlp */
bignum2bytestring(node_dhc->nlp_auth_misc.hrsp_pub_key,
&result1,
sizeof (BIG_CHUNK_TYPE) * (result1.len));
node_dhc->nlp_auth_misc.hrsp_pubkey_len =
(result1.len) * sizeof (BIG_CHUNK_TYPE);
} else {
bignum2bytestring(node_dhc->nlp_auth_misc.hrsp_pub_key,
&result1,
sizeof (BIG_CHUNK_TYPE) * (result1.len));
node_dhc->nlp_auth_misc.hrsp_pubkey_len =
(result1.len) * sizeof (BIG_CHUNK_TYPE);
}
if (ndlp->nlp_DID == FABRIC_DID) {
bcopy((void *)node_dhc->hrsp_pub_key, (void *)dhval,
node_dhc->hrsp_pubkey_len);
} else {
bcopy((void *)node_dhc->nlp_auth_misc.hrsp_pub_key,
(void *)dhval,
node_dhc->nlp_auth_misc.hrsp_pubkey_len);
}
*(uint32_t *)dhval_len = (result1.len) * sizeof (BIG_CHUNK_TYPE);
ret4:
big_finish(&result1);
ret3:
big_finish(&e);
ret2:
big_finish(&n);
ret1:
big_finish(&g);
return (err);
} /* emlxs_BIGNUM_get_dhval */
/*
* to get ((g^y mod p)^x mod p) a^e mod n
*/
BIG_ERR_CODE
emlxs_BIGNUM_pubkey(
emlxs_port_t *port,
void *pubkey,
uint8_t *dhval, /* g^y mod p */
uint32_t dhvallen,
uint8_t *key, /* x */
uint32_t key_size,
uint32_t dhgp_id,
uint32_t *pubkeylen)
{
BIGNUM a, e, n, result;
uint32_t plen;
unsigned char *tmp = NULL;
BIG_ERR_CODE err = BIG_OK;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"BIGNUM_pubkey: dhvallen=0x%x dhgp_id=0x%x",
dhvallen, dhgp_id);
if (big_init(&a, CHARLEN2BIGNUMLEN(dhvallen)) != BIG_OK) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"BIGNUM_pubkey: big_init failed. a size=%d",
CHARLEN2BIGNUMLEN(dhvallen));
err = BIG_NO_MEM;
return (err);
}
/* get g^y mod p */
bytestring2bignum(&a, (unsigned char *)dhval, dhvallen);
if (big_init(&e, CHARLEN2BIGNUMLEN(key_size)) != BIG_OK) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"BIGNUM_pubkey: big_init failed. e size=%d",
CHARLEN2BIGNUMLEN(key_size));
err = BIG_NO_MEM;
goto ret1;
}
/* get x */
bytestring2bignum(&e, (unsigned char *)key, key_size);
switch (dhgp_id) {
case GROUP_1024:
plen = 128;
tmp = dhgp1_pVal;
break;
case GROUP_1280:
plen = 160;
tmp = dhgp2_pVal;
break;
case GROUP_1536:
plen = 192;
tmp = dhgp3_pVal;
break;
case GROUP_2048:
plen = 256;
tmp = dhgp4_pVal;
break;
}
if (big_init(&n, CHARLEN2BIGNUMLEN(plen)) != BIG_OK) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"BIGNUM_pubkey: big_init failed. n size=%d",
CHARLEN2BIGNUMLEN(plen));
err = BIG_NO_MEM;
goto ret2;
}
bytestring2bignum(&n, (unsigned char *)tmp, plen);
if (big_init(&result, CHARLEN2BIGNUMLEN(512)) != BIG_OK) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"BIGNUM_pubkey: big_init failed. result size=%d",
CHARLEN2BIGNUMLEN(512));
err = BIG_NO_MEM;
goto ret3;
}
if (big_cmp_abs(&a, &n) > 0) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"BIGNUM_pubkey: big_cmp_abs error");
err = BIG_GENERAL_ERR;
goto ret4;
}
if (big_modexp(&result, &a, &e, &n, NULL) != BIG_OK) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"BIGNUM_pubkey: big_modexp result error");
err = BIG_NO_MEM;
goto ret4;
}
bignum2bytestring(pubkey, &result,
sizeof (BIG_CHUNK_TYPE) * (result.len));
*pubkeylen = sizeof (BIG_CHUNK_TYPE) * (result.len);
/* This pubkey is actually session key */
ret4:
big_finish(&result);
ret3:
big_finish(&n);
ret2:
big_finish(&e);
ret1:
big_finish(&a);
return (err);
} /* emlxs_BIGNUM_pubkey */
/*
* key: x dhval: (g^y mod p) tran_id: Ti bi_cval: C2 hash_id: H dhgp_id: p/g
*
* Cai = H (C2 || ((g^y mod p)^x mod p) )
*
*/
/* ARGSUSED */
BIG_ERR_CODE
emlxs_hash_Cai(
emlxs_port_t *port,
emlxs_port_dhc_t *port_dhc,
NODELIST *ndlp,
void *Cai,
uint32_t hash_id,
uint32_t dhgp_id,
uint32_t tran_id,
uint8_t *cval,
uint32_t cval_len,
uint8_t *key,
uint8_t *dhval,
uint32_t dhvallen)
{
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
MD5_CTX mdctx;
SHA1_CTX sha1ctx;
uint8_t sha1_digest[20];
uint8_t md5_digest[16];
uint8_t pubkey[512];
uint32_t pubkey_len = 0;
uint32_t key_size;
BIG_ERR_CODE err = BIG_OK;
key_size = cval_len;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"hash_Cai: 0x%x 0x%x 0x%x 0x%x 0x%x",
ndlp->nlp_DID, hash_id, dhgp_id, tran_id, dhvallen);
if (hash_id == AUTH_MD5) {
bzero(&mdctx, sizeof (MD5_CTX));
MD5Init(&mdctx);
MD5Update(&mdctx, (unsigned char *)cval, cval_len);
/* this pubkey obtained is actually the session key */
/*
* pubkey: ((g^y mod p)^x mod p)
*/
err = emlxs_BIGNUM_pubkey(port, pubkey, dhval, dhvallen,
key, key_size, dhgp_id, &pubkey_len);
if (err != BIG_OK) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"hash_Cai: MD5 BIGNUM_pubkey error: 0x%x",
err);
err = BIG_GENERAL_ERR;
return (err);
}
if (pubkey_len == 0) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"hash_Cai: MD5 BIGNUM_pubkey error: len=0");
err = BIG_GENERAL_ERR;
return (err);
}
if (ndlp->nlp_DID == FABRIC_DID) {
bcopy((void *)pubkey,
(void *)node_dhc->hrsp_ses_key, pubkey_len);
node_dhc->hrsp_seskey_len = pubkey_len;
/* store extra copy */
bcopy((void *)pubkey,
(void *)node_dhc->nlp_auth_misc.hrsp_ses_key,
pubkey_len);
node_dhc->nlp_auth_misc.hrsp_seskey_len = pubkey_len;
} else {
bcopy((void *)pubkey,
(void *)node_dhc->nlp_auth_misc.hrsp_ses_key,
pubkey_len);
node_dhc->nlp_auth_misc.hrsp_seskey_len = pubkey_len;
}
MD5Update(&mdctx, (unsigned char *)pubkey, pubkey_len);
MD5Final((uint8_t *)md5_digest, &mdctx);
bcopy((void *)&md5_digest, (void *)Cai, MD5_LEN);
}
if (hash_id == AUTH_SHA1) {
bzero(&sha1ctx, sizeof (SHA1_CTX));
SHA1Init(&sha1ctx);
SHA1Update(&sha1ctx, (void *)cval, cval_len);
err = emlxs_BIGNUM_pubkey(port, pubkey, dhval, dhvallen,
key, key_size, dhgp_id, &pubkey_len);
if (err != BIG_OK) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"hash_Cai: SHA1 BIGNUM_pubkey error: 0x%x",
err);
err = BIG_GENERAL_ERR;
return (err);
}
if (pubkey_len == 0) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"hash_Cai: SA1 BUM_pubkey error: key_len=0");
err = BIG_GENERAL_ERR;
return (err);
}
if (ndlp->nlp_DID == FABRIC_DID) {
bcopy((void *)pubkey,
(void *)node_dhc->hrsp_ses_key,
pubkey_len);
node_dhc->hrsp_seskey_len = pubkey_len;
/* store extra copy */
bcopy((void *)pubkey,
(void *)node_dhc->nlp_auth_misc.hrsp_ses_key,
pubkey_len);
node_dhc->nlp_auth_misc.hrsp_seskey_len = pubkey_len;
} else {
bcopy((void *)pubkey,
(void *)node_dhc->nlp_auth_misc.hrsp_ses_key,
pubkey_len);
node_dhc->nlp_auth_misc.hrsp_seskey_len = pubkey_len;
}
SHA1Update(&sha1ctx, (void *)pubkey, pubkey_len);
SHA1Final((void *)sha1_digest, &sha1ctx);
bcopy((void *)&sha1_digest, (void *)Cai, SHA1_LEN);
}
return (err);
} /* emlxs_hash_Cai */
/*
* This routine is to verify the DHCHAP_Reply from initiator by the host
* as the responder.
*
* flag: 1: if host is the responder 0: if host is the initiator
*
* if bi_cval != NULL, this routine is used to calculate the response based
* on the challenge from initiator as part of
* DHCHAP_Reply for bi-dirctional authentication.
*
*/
/* ARGSUSED */
static uint32_t *
emlxs_hash_verification(
emlxs_port_t *port,
emlxs_port_dhc_t *port_dhc,
NODELIST *ndlp,
uint32_t tran_id,
uint8_t *dhval,
uint32_t dhval_len,
uint32_t flag, /* always 1 for now */
uint8_t *bi_cval)
{ /* always 0 for now */
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
uint32_t dhgp_id;
uint32_t hash_id;
uint32_t *hash_val = NULL;
uint32_t hash_size;
MD5_CTX mdctx;
SHA1_CTX sha1ctx;
uint8_t sha1_digest[20];
uint8_t md5_digest[16];
uint8_t Cai[20];
/* union challenge_val un_cval; */
uint8_t key[20];
uint8_t cval[20];
uint32_t cval_len;
uint8_t mytran_id = 0x00;
char *remote_key;
BIG_ERR_CODE err = BIG_OK;
tran_id = (AUTH_TRAN_ID_MASK & tran_id);
mytran_id = (uint8_t)(LE_SWAP32(tran_id));
if (ndlp->nlp_DID == FABRIC_DID) {
remote_key = (char *)node_dhc->auth_key.remote_password;
} else {
/*
* in case of end-to-end auth, this remote password should be
* the password associated with the remote entity. (i.e.,)
* for now it is actually local_password.
*/
remote_key = (char *)node_dhc->auth_key.remote_password;
}
if (flag == 0) {
dhgp_id = node_dhc->dhgp_id;
hash_id = node_dhc->hash_id;
} else {
dhgp_id = node_dhc->nlp_auth_dhgpid;
hash_id = node_dhc->nlp_auth_hashid;
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"hash_verification: 0x%x 0x%x hash_id=0x%x dhgp_id=0x%x",
ndlp->nlp_DID, mytran_id, hash_id, dhgp_id);
if (dhval_len == 0) {
/* NULL DHCHAP group */
if (hash_id == AUTH_MD5) {
bzero(&mdctx, sizeof (MD5_CTX));
hash_size = MD5_LEN;
MD5Init(&mdctx);
MD5Update(&mdctx, (unsigned char *)&mytran_id, 1);
if (ndlp->nlp_DID == FABRIC_DID) {
MD5Update(&mdctx,
(unsigned char *)remote_key,
node_dhc->auth_key.remote_password_length);
} else {
MD5Update(&mdctx,
(unsigned char *)remote_key,
node_dhc->auth_key.remote_password_length);
}
if (ndlp->nlp_DID == FABRIC_DID) {
MD5Update(&mdctx,
(unsigned char *)&node_dhc->hrsp_cval[0],
MD5_LEN);
} else {
MD5Update(&mdctx,
(unsigned char *)&node_dhc->nlp_auth_misc.hrsp_cval[0],
MD5_LEN);
}
MD5Final((uint8_t *)md5_digest, &mdctx);
hash_val = (uint32_t *)kmem_alloc(hash_size,
KM_NOSLEEP);
if (hash_val == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"hash_verification: alloc failed");
return (NULL);
} else {
bcopy((void *)md5_digest,
(void *)hash_val, MD5_LEN);
}
}
if (hash_id == AUTH_SHA1) {
bzero(&sha1ctx, sizeof (SHA1_CTX));
hash_size = SHA1_LEN;
SHA1Init(&sha1ctx);
SHA1Update(&sha1ctx, (void *)&mytran_id, 1);
if (ndlp->nlp_DID == FABRIC_DID) {
SHA1Update(&sha1ctx, (void *)remote_key,
node_dhc->auth_key.remote_password_length);
} else {
SHA1Update(&sha1ctx, (void *)remote_key,
node_dhc->auth_key.remote_password_length);
}
if (ndlp->nlp_DID == FABRIC_DID) {
SHA1Update(&sha1ctx,
(void *)&node_dhc->hrsp_cval[0],
SHA1_LEN);
} else {
SHA1Update(&sha1ctx,
(void *)&node_dhc->nlp_auth_misc.hrsp_cval[0],
SHA1_LEN);
}
SHA1Final((void *)sha1_digest, &sha1ctx);
hash_val = (uint32_t *)kmem_zalloc(hash_size,
KM_NOSLEEP);
if (hash_val == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"hash_verification: alloc failed");
return (NULL);
} else {
bcopy((void *)sha1_digest,
(void *)hash_val, SHA1_LEN);
}
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"hash_verification: hash_val=0x%x",
*(uint32_t *)hash_val);
return ((uint32_t *)hash_val);
} else {
/* DHCHAP group 1,2,3,4 */
/*
* host received (g^x mod p) as dhval host has its own
* private key y as node_dhc->hrsp_priv_key[] host has its
* original challenge c as node_dhc->hrsp_cval[]
*
* H(c || (g^x mod p)^y mod p) = Cai H(Ti || Km || Cai) =
* hash_val returned. Ti : tran_id, Km : shared secret, Cai:
* obtained above.
*/
if (hash_id == AUTH_MD5) {
if (ndlp->nlp_DID == FABRIC_DID) {
bcopy((void *)node_dhc->hrsp_priv_key,
(void *)key, MD5_LEN);
} else {
bcopy(
(void *)node_dhc->nlp_auth_misc.hrsp_priv_key,
(void *)key, MD5_LEN);
}
}
if (hash_id == AUTH_SHA1) {
if (ndlp->nlp_DID == FABRIC_DID) {
bcopy((void *)node_dhc->hrsp_priv_key,
(void *)key, SHA1_LEN);
} else {
bcopy(
(void *)node_dhc->nlp_auth_misc.hrsp_priv_key,
(void *)key, SHA1_LEN);
}
}
if (ndlp->nlp_DID == FABRIC_DID) {
bcopy((void *)node_dhc->hrsp_cval,
(void *)cval, node_dhc->hrsp_cval_len);
cval_len = node_dhc->hrsp_cval_len;
} else {
bcopy((void *)node_dhc->nlp_auth_misc.hrsp_cval,
(void *)cval,
node_dhc->nlp_auth_misc.hrsp_cval_len);
cval_len = node_dhc->nlp_auth_misc.hrsp_cval_len;
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"hash_verification: N-Null gp. 0x%x 0x%x",
ndlp->nlp_DID, cval_len);
err = emlxs_hash_Cai(port, port_dhc, ndlp, (void *)Cai,
hash_id, dhgp_id,
tran_id, cval, cval_len,
key, dhval, dhval_len);
if (err != BIG_OK) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"hash_verification: Cai error. ret=0x%x",
err);
return (NULL);
}
if (hash_id == AUTH_MD5) {
bzero(&mdctx, sizeof (MD5_CTX));
hash_size = MD5_LEN;
MD5Init(&mdctx);
MD5Update(&mdctx, (unsigned char *)&mytran_id, 1);
if (ndlp->nlp_DID == FABRIC_DID) {
MD5Update(&mdctx,
(unsigned char *)remote_key,
node_dhc->auth_key.remote_password_length);
} else {
MD5Update(&mdctx,
(unsigned char *)remote_key,
node_dhc->auth_key.remote_password_length);
}
MD5Update(&mdctx, (unsigned char *)Cai, MD5_LEN);
MD5Final((uint8_t *)md5_digest, &mdctx);
hash_val = (uint32_t *)kmem_zalloc(hash_size,
KM_NOSLEEP);
if (hash_val == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"hash_vf: alloc failed(Non-NULL dh)");
return (NULL);
} else {
bcopy((void *)&md5_digest,
(void *)hash_val, MD5_LEN);
}
}
if (hash_id == AUTH_SHA1) {
bzero(&sha1ctx, sizeof (SHA1_CTX));
hash_size = SHA1_LEN;
SHA1Init(&sha1ctx);
SHA1Update(&sha1ctx, (void *)&mytran_id, 1);
if (ndlp->nlp_DID == FABRIC_DID) {
SHA1Update(&sha1ctx, (void *)remote_key,
node_dhc->auth_key.remote_password_length);
} else {
SHA1Update(&sha1ctx, (void *)remote_key,
node_dhc->auth_key.remote_password_length);
}
SHA1Update(&sha1ctx, (void *)Cai, SHA1_LEN);
SHA1Final((void *)sha1_digest, &sha1ctx);
hash_val = (uint32_t *)kmem_zalloc(hash_size,
KM_NOSLEEP);
if (hash_val == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"hash_vf: val alloc failed (Non-NULL dh)");
return (NULL);
} else {
bcopy((void *)&sha1_digest,
(void *)hash_val, SHA1_LEN);
}
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"hash_verification: hash_val=0x%x",
*(uint32_t *)hash_val);
return ((uint32_t *)hash_val);
}
} /* emlxs_hash_verification */
/*
* When DHCHAP_Success msg was sent from responder to the initiator,
* with bi-directional authentication requested, the
* DHCHAP_Success contains the response R2 to the challenge C2 received.
*
* DHCHAP response R2: The value of R2 is computed using the hash function
* H() selected by the HashID parameter of the
* DHCHAP_Challenge msg, and the augmented challenge Ca2.
*
* NULL DH group: Ca2 = C2 Non NULL DH group: Ca2 = H(C2 ||
* (g^y mod p)^x mod p)) x is selected by the authentication responder
* which is the node_dhc->hrsp_priv_key[] (g^y mod p) is dhval received
* from authentication initiator.
*
* R2 = H(Ti || Km || Ca2) Ti is the least significant byte of the
* transaction id. Km is the secret associated with the
* authentication responder.
*
* emlxs_hash_get_R2 and emlxs_hash_verification could be mergerd into one
* function later.
*
*/
static uint32_t *
emlxs_hash_get_R2(
emlxs_port_t *port,
emlxs_port_dhc_t *port_dhc,
NODELIST *ndlp,
uint32_t tran_id,
uint8_t *dhval,
uint32_t dhval_len,
uint32_t flag, /* flag 1 rsponder or 0 initiator */
uint8_t *bi_cval)
{
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
uint32_t dhgp_id;
uint32_t hash_id;
uint32_t *hash_val = NULL;
uint32_t hash_size;
MD5_CTX mdctx;
SHA1_CTX sha1ctx;
uint8_t sha1_digest[20];
uint8_t md5_digest[16];
uint8_t Cai[20];
/* union challenge_val un_cval; */
uint8_t key[20];
uint32_t cval_len;
uint8_t mytran_id = 0x00;
char *mykey;
BIG_ERR_CODE err = BIG_OK;
if (ndlp->nlp_DID == FABRIC_DID) {
dhgp_id = node_dhc->nlp_auth_dhgpid;
hash_id = node_dhc->nlp_auth_hashid;
} else {
if (flag == 0) {
dhgp_id = node_dhc->dhgp_id;
hash_id = node_dhc->hash_id;
} else {
dhgp_id = node_dhc->nlp_auth_dhgpid;
hash_id = node_dhc->nlp_auth_hashid;
}
}
tran_id = (AUTH_TRAN_ID_MASK & tran_id);
mytran_id = (uint8_t)(LE_SWAP32(tran_id));
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_detail_msg,
"hash_get_R2:0x%x 0x%x dhgp_id=0x%x mytran_id=0x%x",
ndlp->nlp_DID, hash_id, dhgp_id, mytran_id);
if (ndlp->nlp_DID == FABRIC_DID) {
mykey = (char *)node_dhc->auth_key.local_password;
} else {
/* in case of end-to-end mykey should be remote_password */
mykey = (char *)node_dhc->auth_key.remote_password;
}
if (dhval_len == 0) {
/* NULL DHCHAP group */
if (hash_id == AUTH_MD5) {
bzero(&mdctx, sizeof (MD5_CTX));
hash_size = MD5_LEN;
MD5Init(&mdctx);
MD5Update(&mdctx, (unsigned char *)&mytran_id, 1);
if (ndlp->nlp_DID == FABRIC_DID) {
MD5Update(&mdctx, (unsigned char *)mykey,
node_dhc->auth_key.local_password_length);
} else {
MD5Update(&mdctx, (unsigned char *)mykey,
node_dhc->auth_key.remote_password_length);
}
MD5Update(&mdctx, (unsigned char *)bi_cval, MD5_LEN);
MD5Final((uint8_t *)md5_digest, &mdctx);
hash_val = (uint32_t *)kmem_alloc(hash_size,
KM_NOSLEEP);
if (hash_val == NULL) {
return (NULL);
} else {
bcopy((void *)md5_digest,
(void *)hash_val, MD5_LEN);
}
}
if (hash_id == AUTH_SHA1) {
bzero(&sha1ctx, sizeof (SHA1_CTX));
hash_size = SHA1_LEN;
SHA1Init(&sha1ctx);
SHA1Update(&sha1ctx, (void *)&mytran_id, 1);
if (ndlp->nlp_DID == FABRIC_DID) {
SHA1Update(&sha1ctx, (void *)mykey,
node_dhc->auth_key.local_password_length);
} else {
SHA1Update(&sha1ctx, (void *)mykey,
node_dhc->auth_key.remote_password_length);
}
SHA1Update(&sha1ctx, (void *)bi_cval, SHA1_LEN);
SHA1Final((void *)sha1_digest, &sha1ctx);
hash_val = (uint32_t *)kmem_alloc(hash_size,
KM_NOSLEEP);
if (hash_val == NULL) {
return (NULL);
} else {
bcopy((void *)sha1_digest,
(void *)hash_val, SHA1_LEN);
}
}
} else {
/* NON-NULL DHCHAP */
if (ndlp->nlp_DID == FABRIC_DID) {
if (hash_id == AUTH_MD5) {
bcopy((void *)node_dhc->hrsp_priv_key,
(void *)key, MD5_LEN);
}
if (hash_id == AUTH_SHA1) {
bcopy((void *)node_dhc->hrsp_priv_key,
(void *)key, SHA1_LEN);
}
cval_len = node_dhc->hrsp_cval_len;
} else {
if (hash_id == AUTH_MD5) {
bcopy(
(void *)node_dhc->nlp_auth_misc.hrsp_priv_key,
(void *)key, MD5_LEN);
}
if (hash_id == AUTH_SHA1) {
bcopy(
(void *)node_dhc->nlp_auth_misc.hrsp_priv_key,
(void *)key, SHA1_LEN);
}
cval_len = node_dhc->nlp_auth_misc.hrsp_cval_len;
}
/* use bi_cval here */
/*
* key: x dhval: (g^y mod p) tran_id: Ti bi_cval: C2 hash_id:
* H dhgp_id: p/g
*
* Cai = H (C2 || ((g^y mod p)^x mod p) )
*
* R2 = H (Ti || Km || Cai)
*/
err = emlxs_hash_Cai(port, port_dhc, ndlp, (void *)Cai,
hash_id, dhgp_id, tran_id, bi_cval, cval_len,
key, dhval, dhval_len);
if (err != BIG_OK) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"hash_get_R2: hash_Cai error. ret=0x%x",
err);
return (NULL);
}
if (hash_id == AUTH_MD5) {
bzero(&mdctx, sizeof (MD5_CTX));
hash_size = MD5_LEN;
MD5Init(&mdctx);
MD5Update(&mdctx, (unsigned char *) &mytran_id, 1);
/*
* Here we use the same key: mykey, note: this mykey
* should be the key associated with the
* authentication responder i.e. the remote key.
*/
if (ndlp->nlp_DID == FABRIC_DID)
MD5Update(&mdctx, (unsigned char *)mykey,
node_dhc->auth_key.local_password_length);
else
MD5Update(&mdctx, (unsigned char *)mykey,
node_dhc->auth_key.remote_password_length);
MD5Update(&mdctx, (unsigned char *)Cai, MD5_LEN);
MD5Final((uint8_t *)md5_digest, &mdctx);
hash_val = (uint32_t *)kmem_alloc(hash_size,
KM_NOSLEEP);
if (hash_val == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"hash_get_R2: hash_val MD5 alloc failed.");
return (NULL);
} else {
bcopy((void *)md5_digest,
(void *)hash_val, MD5_LEN);
}
}
if (hash_id == AUTH_SHA1) {
bzero(&sha1ctx, sizeof (SHA1_CTX));
hash_size = SHA1_LEN;
SHA1Init(&sha1ctx);
SHA1Update(&sha1ctx, (void *)&mytran_id, 1);
if (ndlp->nlp_DID == FABRIC_DID) {
SHA1Update(&sha1ctx, (void *)mykey,
node_dhc->auth_key.local_password_length);
} else {
SHA1Update(&sha1ctx, (void *)mykey,
node_dhc->auth_key.remote_password_length);
}
SHA1Update(&sha1ctx, (void *)Cai, SHA1_LEN);
SHA1Final((void *)sha1_digest, &sha1ctx);
hash_val = (uint32_t *)kmem_alloc(hash_size,
KM_NOSLEEP);
if (hash_val == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_error_msg,
"hash_get_R2: hash_val SHA1 alloc failed.");
return (NULL);
} else {
bcopy((void *)sha1_digest,
(void *)hash_val, SHA1_LEN);
}
}
}
return ((uint32_t *)hash_val);
} /* emlxs_hash_get_R2 */
static void
emlxs_log_auth_event(
emlxs_port_t *port,
NODELIST *ndlp,
char *subclass,
char *info)
{
emlxs_hba_t *hba = HBA;
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
nvlist_t *attr_list = NULL;
dev_info_t *dip = hba->dip;
emlxs_auth_cfg_t *auth_cfg;
char *tmp = "No_more_logging_information_available";
uint8_t lwwn[8];
uint8_t rwwn[8];
char *lwwn_str = NULL;
char *rwwn_str = NULL;
char ext_subclass[128];
char ext_class[32];
auth_cfg = &(node_dhc->auth_cfg);
if (info == NULL) {
info = tmp;
}
bcopy((void *) &auth_cfg->local_entity, (void *)lwwn, 8);
lwwn_str = (char *)kmem_zalloc(32, KM_NOSLEEP);
if (lwwn_str == NULL) {
return;
}
(void) snprintf(lwwn_str, 32, "%02X%02X%02X%02X%02X%02X%02X%02X",
lwwn[0], lwwn[1], lwwn[2], lwwn[3], lwwn[4], lwwn[5], lwwn[6],
lwwn[7]);
bcopy((void *)&auth_cfg->remote_entity, (void *)rwwn, 8);
rwwn_str = (char *)kmem_zalloc(32, KM_NOSLEEP);
if (rwwn_str == NULL) {
kmem_free(lwwn_str, 32);
return;
}
(void) snprintf(rwwn_str, 32, "%02X%02X%02X%02X%02X%02X%02X%02X",
rwwn[0], rwwn[1], rwwn[2], rwwn[3], rwwn[4], rwwn[5], rwwn[6],
rwwn[7]);
(void) snprintf(ext_subclass, sizeof (ext_subclass),
"ESC_%s_%s", DRIVER_NAME, subclass);
(void) snprintf(ext_class, sizeof (ext_class),
"EC_%s", DRIVER_NAME);
if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, KM_NOSLEEP)
== DDI_SUCCESS) {
if ((nvlist_add_uint32(attr_list, "instance",
ddi_get_instance(dip)) == DDI_SUCCESS) &&
(nvlist_add_string(attr_list, "lwwn",
lwwn_str) == DDI_SUCCESS) &&
(nvlist_add_string(attr_list, "rwwn",
rwwn_str) == DDI_SUCCESS) &&
(nvlist_add_string(attr_list, "Info",
info) == DDI_SUCCESS) &&
(nvlist_add_string(attr_list, "Class",
ext_class) == DDI_SUCCESS) &&
(nvlist_add_string(attr_list, "SubClass",
ext_subclass) == DDI_SUCCESS)) {
(void) ddi_log_sysevent(dip,
emlxs_strtoupper(DRIVER_NAME),
ext_class,
ext_subclass,
attr_list,
NULL,
DDI_NOSLEEP);
}
nvlist_free(attr_list);
attr_list = NULL;
}
kmem_free(lwwn_str, 32);
kmem_free(rwwn_str, 32);
return;
} /* emlxs_log_auth_event() */
/* **************************** AUTH DHC INTERFACE ************************* */
extern int
emlxs_dhc_auth_start(
emlxs_port_t *port,
emlxs_node_t *ndlp,
uint8_t *deferred_sbp,
uint8_t *deferred_ubp)
{
emlxs_hba_t *hba = HBA;
emlxs_config_t *cfg = &CFG;
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
emlxs_auth_cfg_t *auth_cfg;
emlxs_auth_key_t *auth_key;
uint32_t i;
uint32_t fabric;
uint32_t fabric_switch;
/* The ubp represents an unsolicted PLOGI */
/* The sbp represents a solicted PLOGI */
fabric = ((ndlp->nlp_DID & FABRIC_DID_MASK) == FABRIC_DID_MASK) ? 1 : 0;
fabric_switch = ((ndlp->nlp_DID == FABRIC_DID) ? 1 : 0);
/* Return is authentication is not enabled */
if (cfg[CFG_AUTH_ENABLE].current == 0) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_start_msg,
"Not started. Auth disabled. did=0x%x", ndlp->nlp_DID);
emlxs_dhc_state(port, ndlp, NODE_STATE_AUTH_DISABLED, 0, 0);
return (1);
}
if (port->vpi != 0 && cfg[CFG_AUTH_NPIV].current == 0) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_start_msg,
"Not started. NPIV auth disabled. did=0x%x", ndlp->nlp_DID);
emlxs_dhc_state(port, ndlp, NODE_STATE_AUTH_DISABLED, 0, 0);
return (1);
}
if (!fabric_switch && fabric) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_start_msg,
"Not started. FS auth disabled. did=0x%x", ndlp->nlp_DID);
emlxs_dhc_state(port, ndlp, NODE_STATE_AUTH_DISABLED, 0, 0);
return (1);
}
/* Return if fcsp support to this node is not enabled */
if (!fabric_switch && cfg[CFG_AUTH_E2E].current == 0) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_start_msg,
"Not started. E2E auth disabled. did=0x%x", ndlp->nlp_DID);
emlxs_dhc_state(port, ndlp, NODE_STATE_AUTH_DISABLED, 0, 0);
return (1);
}
if ((deferred_sbp && node_dhc->deferred_sbp) ||
(deferred_ubp && node_dhc->deferred_ubp)) {
/* Clear previous authentication */
emlxs_dhc_auth_stop(port, ndlp);
}
mutex_enter(&hba->auth_lock);
/* Intialize node */
node_dhc->parent_auth_cfg = NULL;
node_dhc->parent_auth_key = NULL;
/* Acquire auth configuration */
if (fabric_switch) {
auth_cfg = emlxs_auth_cfg_find(port,
(uint8_t *)emlxs_fabric_wwn);
auth_key = emlxs_auth_key_find(port,
(uint8_t *)emlxs_fabric_wwn);
} else {
auth_cfg = emlxs_auth_cfg_find(port,
(uint8_t *)&ndlp->nlp_portname);
auth_key = emlxs_auth_key_find(port,
(uint8_t *)&ndlp->nlp_portname);
}
if (!auth_cfg) {
mutex_exit(&hba->auth_lock);
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_start_msg,
"Not started. No auth cfg entry found. did=0x%x",
ndlp->nlp_DID);
emlxs_dhc_state(port, ndlp, NODE_STATE_AUTH_DISABLED, 0, 0);
return (1);
}
if (fabric_switch) {
auth_cfg->node = NULL;
} else {
node_dhc->parent_auth_cfg = auth_cfg;
auth_cfg->node = ndlp;
}
if (!auth_key) {
mutex_exit(&hba->auth_lock);
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_start_msg,
"Not started. No auth key entry found. did=0x%x",
ndlp->nlp_DID);
emlxs_dhc_state(port, ndlp, NODE_STATE_AUTH_DISABLED, 0, 0);
return (1);
}
if (fabric_switch) {
auth_key->node = NULL;
} else {
node_dhc->parent_auth_key = auth_key;
auth_key->node = ndlp;
}
/* Remote port does not support fcsp */
if (ndlp->sparm.cmn.fcsp_support == 0) {
switch (auth_cfg->authentication_mode) {
case AUTH_MODE_PASSIVE:
mutex_exit(&hba->auth_lock);
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_start_msg,
"Not started. Auth unsupported. did=0x%x",
ndlp->nlp_DID);
emlxs_dhc_state(port, ndlp,
NODE_STATE_AUTH_DISABLED, 0, 0);
return (1);
case AUTH_MODE_ACTIVE:
mutex_exit(&hba->auth_lock);
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_start_msg,
"Failed. Auth unsupported. did=0x%x",
ndlp->nlp_DID);
/*
* Save packet for deferred completion until
* authentication is complete
*/
ndlp->node_dhc.deferred_sbp = deferred_sbp;
ndlp->node_dhc.deferred_ubp = deferred_ubp;
goto failed;
case AUTH_MODE_DISABLED:
default:
mutex_exit(&hba->auth_lock);
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_start_msg,
"Not started. Auth mode=disabled. did=0x%x",
ndlp->nlp_DID);
emlxs_dhc_state(port, ndlp,
NODE_STATE_AUTH_DISABLED, 0, 0);
return (1);
}
} else { /* Remote port supports fcsp */
switch (auth_cfg->authentication_mode) {
case AUTH_MODE_PASSIVE:
case AUTH_MODE_ACTIVE:
/* start auth */
break;
case AUTH_MODE_DISABLED:
default:
mutex_exit(&hba->auth_lock);
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_start_msg,
"Failed. Auth mode=disabled. did=0x%x",
ndlp->nlp_DID);
/*
* Save packet for deferred completion until
* authentication is complete
*/
ndlp->node_dhc.deferred_sbp = deferred_sbp;
ndlp->node_dhc.deferred_ubp = deferred_ubp;
goto failed;
}
}
/* We have a GO for authentication */
/*
* Save pointers for deferred completion until authentication is
* complete
*/
node_dhc->deferred_sbp = deferred_sbp;
node_dhc->deferred_ubp = deferred_ubp;
bzero(&node_dhc->auth_cfg, sizeof (node_dhc->auth_cfg));
bzero(&node_dhc->auth_key, sizeof (node_dhc->auth_key));
/* Program node's auth cfg */
bcopy((uint8_t *)&port->wwpn,
(uint8_t *)&node_dhc->auth_cfg.local_entity, 8);
bcopy((uint8_t *)&ndlp->nlp_portname,
(uint8_t *)&node_dhc->auth_cfg.remote_entity, 8);
node_dhc->auth_cfg.authentication_timeout =
auth_cfg->authentication_timeout;
node_dhc->auth_cfg.authentication_mode =
auth_cfg->authentication_mode;
/*
* If remote password type is "ignore", then only unidirectional auth
* is allowed
*/
if (auth_key->remote_password_type == 3) {
node_dhc->auth_cfg.bidirectional = 0;
} else {
node_dhc->auth_cfg.bidirectional = auth_cfg->bidirectional;
}
node_dhc->auth_cfg.reauthenticate_time_interval =
auth_cfg->reauthenticate_time_interval;
for (i = 0; i < 4; i++) {
switch (auth_cfg->authentication_type_priority[i]) {
case ELX_DHCHAP:
node_dhc->auth_cfg.authentication_type_priority[i] =
AUTH_DHCHAP;
break;
case ELX_FCAP:
node_dhc->auth_cfg.authentication_type_priority[i] =
AUTH_FCAP;
break;
case ELX_FCPAP:
node_dhc->auth_cfg.authentication_type_priority[i] =
AUTH_FCPAP;
break;
case ELX_KERBEROS:
node_dhc->auth_cfg.authentication_type_priority[i] =
AUTH_KERBEROS;
break;
default:
node_dhc->auth_cfg.authentication_type_priority[i] =
0;
break;
}
switch (auth_cfg->hash_priority[i]) {
case ELX_SHA1:
node_dhc->auth_cfg.hash_priority[i] = AUTH_SHA1;
break;
case ELX_MD5:
node_dhc->auth_cfg.hash_priority[i] = AUTH_MD5;
break;
default:
node_dhc->auth_cfg.hash_priority[i] = 0;
break;
}
}
for (i = 0; i < 8; i++) {
switch (auth_cfg->dh_group_priority[i]) {
case ELX_GROUP_NULL:
node_dhc->auth_cfg.dh_group_priority[i] = GROUP_NULL;
break;
case ELX_GROUP_1024:
node_dhc->auth_cfg.dh_group_priority[i] = GROUP_1024;
break;
case ELX_GROUP_1280:
node_dhc->auth_cfg.dh_group_priority[i] = GROUP_1280;
break;
case ELX_GROUP_1536:
node_dhc->auth_cfg.dh_group_priority[i] = GROUP_1536;
break;
case ELX_GROUP_2048:
node_dhc->auth_cfg.dh_group_priority[i] = GROUP_2048;
break;
default:
node_dhc->auth_cfg.dh_group_priority[i] = 0xF;
break;
}
}
/* Program the node's key */
if (auth_key) {
bcopy((uint8_t *)auth_key,
(uint8_t *)&node_dhc->auth_key,
sizeof (emlxs_auth_key_t));
node_dhc->auth_key.next = NULL;
node_dhc->auth_key.prev = NULL;
bcopy((uint8_t *)&port->wwpn,
(uint8_t *)&node_dhc->auth_key.local_entity, 8);
bcopy((uint8_t *)&ndlp->nlp_portname,
(uint8_t *)&node_dhc->auth_key.remote_entity,
8);
}
mutex_exit(&hba->auth_lock);
node_dhc->nlp_auth_limit = 2;
node_dhc->nlp_fb_vendor = 1;
node_dhc->nlp_authrsp_tmocnt = 0;
node_dhc->nlp_authrsp_tmo = 0;
if (deferred_ubp) {
/* Acknowledge the unsolicited PLOGI */
/* This should trigger the other port to start authentication */
if (emlxs_ub_send_login_acc(port,
(fc_unsol_buf_t *)deferred_ubp) != FC_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_start_msg,
"Not started. Unable to send PLOGI ACC. did=0x%x",
ndlp->nlp_DID);
goto failed;
}
/* Start the auth rsp timer */
node_dhc->nlp_authrsp_tmo = DRV_TIME +
node_dhc->auth_cfg.authentication_timeout;
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_start_msg,
"Authrsp timer activated. did=0x%x",
ndlp->nlp_DID);
/* The next state should be emlxs_rcv_auth_msg_unmapped_node */
emlxs_dhc_state(port, ndlp, NODE_STATE_AUTH_SUCCESS, 0, 0);
} else {
node_dhc->nlp_auth_flag = 1; /* host is the initiator */
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_start_msg,
"Auth initiated. did=0x%x limit=%d sbp=%p",
ndlp->nlp_DID, node_dhc->nlp_auth_limit, deferred_sbp);
if (emlxs_issue_auth_negotiate(port, ndlp, 0)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_start_msg,
"Failed. Auth initiation failed. did=0x%x",
ndlp->nlp_DID);
goto failed;
}
}
return (0);
failed:
emlxs_dhc_state(port, ndlp, NODE_STATE_AUTH_FAILED, 0, 0);
/* Complete authentication with failed status */
emlxs_dhc_auth_complete(port, ndlp, 1);
return (0);
} /* emlxs_dhc_auth_start() */
/* This is called to indicate the driver has lost connection with this node */
extern void
emlxs_dhc_auth_stop(
emlxs_port_t *port,
emlxs_node_t *ndlp)
{
emlxs_port_dhc_t *port_dhc = &port->port_dhc;
emlxs_node_dhc_t *node_dhc;
uint32_t i;
if (port_dhc->state == ELX_FABRIC_STATE_UNKNOWN) {
/* Nothing to stop */
return;
}
if (ndlp) {
node_dhc = &ndlp->node_dhc;
if (node_dhc->state == NODE_STATE_UNKNOWN) {
/* Nothing to stop */
return;
}
if (ndlp->nlp_DID != FABRIC_DID) {
emlxs_dhc_state(port, ndlp, NODE_STATE_UNKNOWN, 0, 0);
}
emlxs_dhc_auth_complete(port, ndlp, 2);
} else { /* Lost connection to all nodes for this port */
rw_enter(&port->node_rwlock, RW_READER);
for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
ndlp = port->node_table[i];
if (!ndlp) {
continue;
}
node_dhc = &ndlp->node_dhc;
if (node_dhc->state == NODE_STATE_UNKNOWN) {
continue;
}
if (ndlp->nlp_DID != FABRIC_DID) {
emlxs_dhc_state(port, ndlp,
NODE_STATE_UNKNOWN, 0, 0);
}
emlxs_dhc_auth_complete(port, ndlp, 2);
}
rw_exit(&port->node_rwlock);
}
return;
} /* emlxs_dhc_auth_stop */
/* state = 0 - Successful completion. Continue connection to node */
/* state = 1 - Failed completion. Do not continue with connection to node */
/* state = 2 - Stopped completion. Do not continue with connection to node */
static void
emlxs_dhc_auth_complete(
emlxs_port_t *port,
emlxs_node_t *ndlp,
uint32_t status)
{
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
uint32_t fabric;
uint32_t fabric_switch;
fabric = ((ndlp->nlp_DID & FABRIC_DID_MASK) == FABRIC_DID_MASK) ? 1 : 0;
fabric_switch = ((ndlp->nlp_DID == FABRIC_DID) ? 1 : 0);
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_complete_msg,
"did=0x%x status=%d sbp=%p ubp=%p",
ndlp->nlp_DID, status, node_dhc->deferred_sbp,
node_dhc->deferred_ubp);
if (status == 1) {
if (fabric_switch) {
/* Virtual link down */
(void) emlxs_port_offline(port, 0xfeffffff);
} else if (!fabric) {
/* Port offline */
(void) emlxs_port_offline(port, ndlp->nlp_DID);
}
}
/* Send a LOGO if authentication was not successful */
if (status == 1) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_complete_msg,
"Sending LOGO to did=0x%x...",
ndlp->nlp_DID);
emlxs_send_logo(port, ndlp->nlp_DID);
}
/* Process deferred cmpl now */
emlxs_mb_deferred_cmpl(port, status,
(emlxs_buf_t *)node_dhc->deferred_sbp,
(fc_unsol_buf_t *)node_dhc->deferred_ubp, 0);
node_dhc->deferred_sbp = 0;
node_dhc->deferred_ubp = 0;
return;
} /* emlxs_dhc_auth_complete */
extern void
emlxs_dhc_attach(emlxs_hba_t *hba)
{
mutex_init(&hba->auth_lock, NULL, MUTEX_DRIVER, NULL);
mutex_init(&hba->dhc_lock, NULL, MUTEX_DRIVER, NULL);
emlxs_auth_cfg_init(hba);
emlxs_auth_key_init(hba);
hba->rdn_flag = 1;
return;
} /* emlxs_dhc_attach() */
extern void
emlxs_dhc_detach(emlxs_hba_t *hba)
{
emlxs_auth_cfg_fini(hba);
emlxs_auth_key_fini(hba);
mutex_destroy(&hba->dhc_lock);
mutex_destroy(&hba->auth_lock);
return;
} /* emlxs_dhc_detach() */
extern void
emlxs_dhc_init_sp(emlxs_port_t *port, uint32_t did, SERV_PARM *sp, char **msg)
{
emlxs_hba_t *hba = HBA;
emlxs_config_t *cfg = &CFG;
uint32_t fabric;
uint32_t fabric_switch;
emlxs_auth_cfg_t *auth_cfg = NULL;
emlxs_auth_key_t *auth_key = NULL;
fabric = ((did & FABRIC_DID_MASK) == FABRIC_DID_MASK) ? 1 : 0;
fabric_switch = ((did == FABRIC_DID) ? 1 : 0);
/* Return is authentication is not enabled */
if (cfg[CFG_AUTH_ENABLE].current == 0) {
sp->cmn.fcsp_support = 0;
bcopy("fcsp:Disabled (0)", (void *) &msg[0],
sizeof ("fcsp:Disabled (0)"));
return;
}
if (port->vpi != 0 && cfg[CFG_AUTH_NPIV].current == 0) {
sp->cmn.fcsp_support = 0;
bcopy("fcsp:Disabled (npiv)", (void *) &msg[0],
sizeof ("fcsp:Disabled (npiv)"));
return;
}
if (!fabric_switch && fabric) {
sp->cmn.fcsp_support = 0;
bcopy("fcsp:Disabled (fs)", (void *) &msg[0],
sizeof ("fcsp:Disabled (fs)"));
return;
}
/* Return if fcsp support to this node is not enabled */
if (!fabric_switch && cfg[CFG_AUTH_E2E].current == 0) {
sp->cmn.fcsp_support = 0;
bcopy("fcsp:Disabled (e2e)", (void *) &msg[0],
sizeof ("fcsp:Disabled (e2e)"));
return;
}
mutex_enter(&hba->auth_lock);
if (fabric_switch) {
auth_cfg = emlxs_auth_cfg_find(port,
(uint8_t *)emlxs_fabric_wwn);
auth_key = emlxs_auth_key_find(port,
(uint8_t *)emlxs_fabric_wwn);
if ((!auth_cfg) || (!auth_key)) {
sp->cmn.fcsp_support = 0;
bcopy("fcsp:Disabled (1)", (void *) &msg[0],
sizeof ("fcsp:Disabled (1)"));
mutex_exit(&hba->auth_lock);
return;
}
}
mutex_exit(&hba->auth_lock);
sp->cmn.fcsp_support = 1;
return;
} /* emlxs_dhc_init_sp() */
extern uint32_t
emlxs_dhc_verify_login(emlxs_port_t *port, uint32_t sid, SERV_PARM *sp)
{
emlxs_hba_t *hba = HBA;
emlxs_config_t *cfg = &CFG;
emlxs_auth_cfg_t *auth_cfg;
emlxs_auth_key_t *auth_key;
uint32_t fabric;
uint32_t fabric_switch;
fabric = ((sid & FABRIC_DID_MASK) == FABRIC_DID_MASK) ? 1 : 0;
fabric_switch = ((sid == FABRIC_DID) ? 1 : 0);
if (port->port_dhc.state == ELX_FABRIC_AUTH_FAILED) {
/* Reject login */
return (1);
}
/* Remote host supports FCSP */
if (sp->cmn.fcsp_support) {
/* Continue login */
return (0);
}
/* Auth disabled in host */
if (cfg[CFG_AUTH_ENABLE].current == 0) {
/* Continue login */
return (0);
}
/* Auth disabled for npiv */
if (port->vpi != 0 && cfg[CFG_AUTH_NPIV].current == 0) {
/* Continue login */
return (0);
}
if (!fabric_switch && fabric) {
/* Continue login */
return (0);
}
/* Auth disabled for p2p */
if (!fabric_switch && cfg[CFG_AUTH_E2E].current == 0) {
/* Continue login */
return (0);
}
/* Remote port does NOT support FCSP */
/* Host has FCSP enabled */
/* Now check to make sure auth mode for this port is also enabled */
mutex_enter(&hba->auth_lock);
/* Acquire auth configuration */
if (fabric_switch) {
auth_cfg = emlxs_auth_cfg_find(port,
(uint8_t *)emlxs_fabric_wwn);
auth_key = emlxs_auth_key_find(port,
(uint8_t *)emlxs_fabric_wwn);
} else {
auth_cfg = emlxs_auth_cfg_find(port,
(uint8_t *)&sp->portName);
auth_key = emlxs_auth_key_find(port,
(uint8_t *)&sp->portName);
}
if (auth_key && auth_cfg &&
(auth_cfg->authentication_mode == AUTH_MODE_ACTIVE)) {
mutex_exit(&hba->auth_lock);
/* Reject login */
return (1);
}
mutex_exit(&hba->auth_lock);
return (0);
} /* emlxs_dhc_verify_login() */
/*
* ! emlxs_dhc_reauth_timeout
*
* \pre \post \param phba \param arg1: \param arg2: ndlp to which the host
* is to be authenticated. \return void
*
* \b Description:
*
* Timeout handler for reauthentication heartbeat.
*
* The reauthentication heart beat will be triggered 1 min by default after
* the first authentication success. reauth_intval is
* configurable. if reauth_intval is set to zero, it means no reauth heart
* beat anymore.
*
* reauth heart beat will be triggered by IOCTL call from user space. Reauth
* heart beat will go through the authentication process
* all over again without causing IO traffic disruption. Initially it should
* be triggered after authentication success.
* Subsequently disable/enable reauth heart beat will be performed by
* HBAnyware or other utility.
*
*/
/* ARGSUSED */
extern void
emlxs_dhc_reauth_timeout(
emlxs_port_t *port,
void *arg1,
void *arg2)
{
emlxs_port_dhc_t *port_dhc = &port->port_dhc;
NODELIST *ndlp = (NODELIST *) arg2;
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
if (node_dhc->auth_cfg.reauthenticate_time_interval == 0) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_debug_msg,
"Reauth timeout. Reauth no longer enabled. 0x%x %x",
ndlp->nlp_DID, node_dhc->state);
emlxs_dhc_set_reauth_time(port, ndlp, DISABLE);
return;
}
/* This should not happen!! */
if (port_dhc->state == ELX_FABRIC_IN_AUTH) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_error_msg,
"Reauth timeout. Fabric in auth. Quiting. 0x%x %x",
ndlp->nlp_DID, node_dhc->state);
emlxs_dhc_set_reauth_time(port, ndlp, DISABLE);
return;
}
if (node_dhc->state != NODE_STATE_AUTH_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_debug_msg,
"Reauth timeout. Auth not done. Restarting. 0x%x %x",
ndlp->nlp_DID, node_dhc->state);
goto restart;
}
/*
* This might happen, the ndlp is doing reauthencation. meaning ndlp
* is being re-authenticated to the host. Thus not necessary to have
* host re-authenticated to the ndlp at this point because ndlp might
* support bi-directional auth. we can just simply donothing and
* restart the timer.
*/
if (port_dhc->state == ELX_FABRIC_IN_REAUTH) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_debug_msg,
"Reauth timeout. Fabric in reauth. Restarting. 0x%x %x",
ndlp->nlp_DID, node_dhc->state);
goto restart;
}
/*
* node's reauth heart beat is running already, cancel it first and
* then restart
*/
if (node_dhc->nlp_reauth_status == NLP_HOST_REAUTH_IN_PROGRESS) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_debug_msg,
"Reauth timeout. Fabric in reauth. Restarting. 0x%x %x",
ndlp->nlp_DID, node_dhc->state);
goto restart;
}
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_debug_msg,
"Reauth timeout. Auth initiated. did=0x%x",
ndlp->nlp_DID);
emlxs_dhc_set_reauth_time(port, ndlp, ENABLE);
node_dhc->nlp_reauth_status = NLP_HOST_REAUTH_IN_PROGRESS;
/* Attempt to restart authentication */
if (emlxs_dhc_auth_start(port, ndlp, NULL, NULL) != 0) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_debug_msg,
"Reauth timeout. Auth initiation failed. 0x%x %x",
ndlp->nlp_DID, node_dhc->state);
return;
}
return;
restart:
emlxs_dhc_set_reauth_time(port, ndlp, ENABLE);
return;
} /* emlxs_dhc_reauth_timeout */
static void
emlxs_dhc_set_reauth_time(
emlxs_port_t *port,
emlxs_node_t *ndlp,
uint32_t status)
{
emlxs_port_dhc_t *port_dhc = &port->port_dhc;
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
uint32_t drv_time;
uint32_t timeout;
uint32_t reauth_tmo;
time_t last_auth_time;
node_dhc->flag &= ~NLP_SET_REAUTH_TIME;
if ((status == ENABLE) &&
node_dhc->auth_cfg.reauthenticate_time_interval) {
timeout =
(60 * node_dhc->auth_cfg.reauthenticate_time_interval);
drv_time = DRV_TIME;
/* Get last successful auth time */
if (ndlp->nlp_DID == FABRIC_DID) {
last_auth_time = port_dhc->auth_time;
} else if (node_dhc->parent_auth_cfg) {
last_auth_time = node_dhc->parent_auth_cfg->auth_time;
} else {
last_auth_time = 0;
}
if (last_auth_time) {
reauth_tmo = last_auth_time + timeout;
/* Validate reauth_tmo */
if ((reauth_tmo < drv_time) ||
(reauth_tmo > drv_time + timeout)) {
reauth_tmo = drv_time + timeout;
}
} else {
reauth_tmo = drv_time + timeout;
}
node_dhc->nlp_reauth_tmo = reauth_tmo;
node_dhc->nlp_reauth_status = NLP_HOST_REAUTH_ENABLED;
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_debug_msg,
"Reauth enabled. did=0x%x state=%x tmo=%d,%d",
ndlp->nlp_DID, node_dhc->state,
node_dhc->auth_cfg.reauthenticate_time_interval,
(reauth_tmo - drv_time));
} else {
node_dhc->nlp_reauth_tmo = 0;
node_dhc->nlp_reauth_status = NLP_HOST_REAUTH_DISABLED;
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_debug_msg,
"Reauth disabled. did=0x%x state=%x",
ndlp->nlp_DID, node_dhc->state);
}
return;
} /* emlxs_dhc_set_reauth_time */
/* ARGSUSED */
extern void
emlxs_dhc_authrsp_timeout(
emlxs_port_t *port,
void *arg1,
void *arg2)
{
NODELIST *ndlp = (NODELIST *)arg1;
emlxs_node_dhc_t *node_dhc = &ndlp->node_dhc;
uint8_t ReasonCode;
uint8_t ReasonCodeExplanation;
node_dhc->nlp_authrsp_tmo = 0;
node_dhc->nlp_authrsp_tmocnt++;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_debug_msg,
"Authrsp timeout. did=0x%x count=%d",
ndlp->nlp_DID, node_dhc->nlp_authrsp_tmocnt);
/*
* According to the FC-SP spec v1.8 pp76.
*
* When the AUTH_TMO error is detected, the entity may: 1. Act as if the
* authentication transaction has failed and terminate the
* communication; or 2. Restart a new authentication transaction, by
* sending an AUTH_Reject msg with Reason Code `Logical Error' and
* Reason Code Explanation 'Restart Authentication Protocol', The
* action performed by the entity receiving such a AUTH_Reject should
* restart the authentication Transaction by sending a new
* AUTH_Negotiate. We plan to use 2 as the action for now.
*
*/
if (node_dhc->nlp_authrsp_tmocnt > 3) {
/* Generate a remove event for the nodelist entry */
(void) emlxs_dhchap_state_machine(port, NULL, NULL,
NULL, ndlp, NODE_EVENT_DEVICE_RM);
ReasonCode = AUTHRJT_FAILURE;
ReasonCodeExplanation = AUTHEXP_AUTH_FAILED;
} else {
/* Generate a recovery event for the nodelist entry */
(void) emlxs_dhchap_state_machine(port, NULL, NULL,
NULL, ndlp, NODE_EVENT_DEVICE_RECOVERY);
ReasonCode = AUTHRJT_LOGIC_ERR;
ReasonCodeExplanation = AUTHEXP_RESTART_AUTH;
}
emlxs_dhc_state(port, ndlp, NODE_STATE_AUTH_FAILED, ReasonCode,
ReasonCodeExplanation);
(void) emlxs_issue_auth_reject(port, ndlp, 0, 0, ReasonCode,
ReasonCodeExplanation);
emlxs_dhc_auth_complete(port, ndlp, 1);
/*
* It is expected the other party should restart the authentication
* transaction
*/
return;
} /* emlxs_dhc_authrsp_timeout() */
/* **************************** AUTH CFG MANAGEMENT ************************ */
/* auth_lock must be held */
static emlxs_auth_cfg_t *
emlxs_auth_cfg_find(emlxs_port_t *port, uint8_t *rwwpn)
{
emlxs_hba_t *hba = HBA;
emlxs_auth_cfg_t *auth_cfg;
if (rwwpn) {
/* lwwpn, rwwpn */
auth_cfg = emlxs_auth_cfg_get(hba,
(uint8_t *)&port->wwpn, (uint8_t *)rwwpn);
if (auth_cfg) {
emlxs_auth_cfg_print(hba, auth_cfg);
return (auth_cfg);
}
/* null, rwwpn */
auth_cfg = emlxs_auth_cfg_get(hba,
(uint8_t *)emlxs_null_wwn, (uint8_t *)rwwpn);
if (auth_cfg) {
emlxs_auth_cfg_print(hba, auth_cfg);
return (auth_cfg);
}
}
/* lwwpn, null */
auth_cfg = emlxs_auth_cfg_get(hba,
(uint8_t *)&port->wwpn, (uint8_t *)emlxs_null_wwn);
if (auth_cfg) {
emlxs_auth_cfg_print(hba, auth_cfg);
return (auth_cfg);
}
/* null, null */
return (&hba->auth_cfg);
} /* emlxs_auth_cfg_find() */
static void
emlxs_auth_cfg_init(emlxs_hba_t *hba)
{
emlxs_config_t *cfg = &CFG;
emlxs_auth_cfg_t *auth_cfg;
/* Destroy old table if one exists */
emlxs_auth_cfg_fini(hba);
mutex_enter(&hba->auth_lock);
/* Zero default entry */
auth_cfg = &hba->auth_cfg;
bzero(auth_cfg, sizeof (emlxs_auth_cfg_t));
auth_cfg->next = auth_cfg;
auth_cfg->prev = auth_cfg;
/* Configure the default entry */
auth_cfg->authentication_timeout =
cfg[CFG_AUTH_TMO].current;
auth_cfg->authentication_mode =
cfg[CFG_AUTH_MODE].current;
auth_cfg->bidirectional =
cfg[CFG_AUTH_BIDIR].current;
auth_cfg->authentication_type_priority[0] =
(cfg[CFG_AUTH_TYPE].current & 0xF000) >> 12;
auth_cfg->authentication_type_priority[1] =
(cfg[CFG_AUTH_TYPE].current & 0x0F00) >> 8;
auth_cfg->authentication_type_priority[2] =
(cfg[CFG_AUTH_TYPE].current & 0x00F0) >> 4;
auth_cfg->authentication_type_priority[3] =
(cfg[CFG_AUTH_TYPE].current & 0x000F);
auth_cfg->hash_priority[0] =
(cfg[CFG_AUTH_HASH].current & 0xF000) >> 12;
auth_cfg->hash_priority[1] =
(cfg[CFG_AUTH_HASH].current & 0x0F00) >> 8;
auth_cfg->hash_priority[2] =
(cfg[CFG_AUTH_HASH].current & 0x00F0) >> 4;
auth_cfg->hash_priority[3] =
(cfg[CFG_AUTH_HASH].current & 0x000F);
auth_cfg->dh_group_priority[0] =
(cfg[CFG_AUTH_GROUP].current & 0xF0000000) >> 28;
auth_cfg->dh_group_priority[1] =
(cfg[CFG_AUTH_GROUP].current & 0x0F000000) >> 24;
auth_cfg->dh_group_priority[2] =
(cfg[CFG_AUTH_GROUP].current & 0x00F00000) >> 20;
auth_cfg->dh_group_priority[3] =
(cfg[CFG_AUTH_GROUP].current & 0x000F0000) >> 16;
auth_cfg->dh_group_priority[4] =
(cfg[CFG_AUTH_GROUP].current & 0x0000F000) >> 12;
auth_cfg->dh_group_priority[5] =
(cfg[CFG_AUTH_GROUP].current & 0x00000F00) >> 8;
auth_cfg->dh_group_priority[6] =
(cfg[CFG_AUTH_GROUP].current & 0x000000F0) >> 4;
auth_cfg->dh_group_priority[7] =
(cfg[CFG_AUTH_GROUP].current & 0x0000000F);
auth_cfg->reauthenticate_time_interval =
cfg[CFG_AUTH_INTERVAL].current;
emlxs_auth_cfg_read(hba);
mutex_exit(&hba->auth_lock);
return;
} /* emlxs_auth_cfg_init() */
static void
emlxs_auth_cfg_fini(emlxs_hba_t *hba)
{
emlxs_auth_cfg_t *auth_cfg = hba->auth_cfg.next;
emlxs_auth_cfg_t *next;
mutex_enter(&hba->auth_lock);
while (auth_cfg && auth_cfg != &hba->auth_cfg) {
next = auth_cfg->next;
emlxs_auth_cfg_destroy(hba, auth_cfg);
auth_cfg = next;
}
mutex_exit(&hba->auth_lock);
return;
} /* emlxs_auth_cfg_fini() */
static void
emlxs_auth_cfg_print(emlxs_hba_t *hba, emlxs_auth_cfg_t *auth_cfg)
{
emlxs_port_t *port = &PPORT;
char s_lwwpn[32];
char s_rwwpn[32];
/* Create and add new entry */
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_detail_msg,
"%s:%s:%x:%x:%x:%x%x%x%x:%x%x%x%x:%x%x%x%x%x%x%x%x:%x",
emlxs_wwn_xlate(s_lwwpn, sizeof (s_lwwpn),
(uint8_t *)&auth_cfg->local_entity),
emlxs_wwn_xlate(s_rwwpn, sizeof (s_rwwpn),
(uint8_t *)&auth_cfg->remote_entity),
auth_cfg->authentication_timeout,
auth_cfg->authentication_mode,
auth_cfg->bidirectional,
auth_cfg->authentication_type_priority[0],
auth_cfg->authentication_type_priority[1],
auth_cfg->authentication_type_priority[2],
auth_cfg->authentication_type_priority[3],
auth_cfg->hash_priority[0],
auth_cfg->hash_priority[1],
auth_cfg->hash_priority[2],
auth_cfg->hash_priority[3],
auth_cfg->dh_group_priority[0],
auth_cfg->dh_group_priority[1],
auth_cfg->dh_group_priority[2],
auth_cfg->dh_group_priority[3],
auth_cfg->dh_group_priority[4],
auth_cfg->dh_group_priority[5],
auth_cfg->dh_group_priority[6],
auth_cfg->dh_group_priority[7],
auth_cfg->reauthenticate_time_interval);
} /* emlxs_auth_cfg_print() */
/* auth_lock must be held */
static emlxs_auth_cfg_t *
emlxs_auth_cfg_get(emlxs_hba_t *hba, uint8_t *lwwpn, uint8_t *rwwpn)
{
emlxs_auth_cfg_t *auth_cfg;
if (!lwwpn || !rwwpn) {
return (NULL);
}
/* Check for default entry */
if ((bcmp(lwwpn, emlxs_null_wwn, 8) == 0) &&
(bcmp(rwwpn, emlxs_null_wwn, 8) == 0)) {
return (&hba->auth_cfg);
}
for (auth_cfg = hba->auth_cfg.next;
auth_cfg != &hba->auth_cfg; auth_cfg = auth_cfg->next) {
/* Find pwd entry for this local port */
/* Check for exact wwpn match */
if (bcmp((void *)&auth_cfg->local_entity,
(void *)lwwpn, 8) != 0) {
continue;
}
/* Find pwd entry for remote port */
/* Check for exact wwpn match */
if (bcmp((void *)&auth_cfg->remote_entity,
(void *)rwwpn, 8) != 0) {
continue;
}
return (auth_cfg);
}
return (NULL);
} /* emlxs_auth_cfg_get() */
/* auth_lock must be held */
static emlxs_auth_cfg_t *
emlxs_auth_cfg_create(emlxs_hba_t *hba, uint8_t *lwwpn, uint8_t *rwwpn)
{
emlxs_auth_cfg_t *auth_cfg;
/* First check if entry already exists */
auth_cfg = emlxs_auth_cfg_get(hba, lwwpn, rwwpn);
if (auth_cfg) {
return (auth_cfg);
}
/* Allocate entry */
auth_cfg = (emlxs_auth_cfg_t *)kmem_zalloc(sizeof (emlxs_auth_cfg_t),
KM_NOSLEEP);
if (!auth_cfg) {
return (NULL);
}
/* Add to list */
auth_cfg->next = &hba->auth_cfg;
auth_cfg->prev = hba->auth_cfg.prev;
hba->auth_cfg.prev->next = auth_cfg;
hba->auth_cfg.prev = auth_cfg;
hba->auth_cfg_count++;
/* Initialize name pair */
if (lwwpn) {
bcopy((void *)lwwpn, (void *)&auth_cfg->local_entity, 8);
}
if (rwwpn) {
bcopy((void *)rwwpn, (void *)&auth_cfg->remote_entity, 8);
}
auth_cfg->auth_status.auth_state = DFC_AUTH_STATE_OFF;
return (auth_cfg);
} /* emlxs_auth_cfg_create() */
/* auth_lock must be held */
static void
emlxs_auth_cfg_destroy(emlxs_hba_t *hba, emlxs_auth_cfg_t *auth_cfg)
{
if (!auth_cfg) {
return;
}
if (auth_cfg == &hba->auth_cfg) {
return;
}
/* Remove from list */
auth_cfg->next->prev = auth_cfg->prev;
auth_cfg->prev->next = auth_cfg->next;
hba->auth_cfg_count--;
/* Remove node binding */
if (auth_cfg->node &&
auth_cfg->node->nlp_active &&
(auth_cfg->node->node_dhc.parent_auth_cfg == auth_cfg)) {
auth_cfg->node->node_dhc.parent_auth_cfg = NULL;
}
bzero(auth_cfg, sizeof (emlxs_auth_cfg_t));
kmem_free(auth_cfg, sizeof (emlxs_auth_cfg_t));
return;
} /* emlxs_auth_cfg_destroy() */
/* auth_lock must be held */
static void
emlxs_auth_cfg_read(emlxs_hba_t *hba)
{
emlxs_port_t *port = &PPORT;
char **arrayp;
emlxs_auth_cfg_t auth_cfg;
emlxs_auth_cfg_t *auth_cfg2;
uint32_t cnt;
uint32_t rval;
char buffer[64];
char *prop_str;
uint32_t i;
/* Check for the per adapter setting */
(void) snprintf(buffer, sizeof (buffer), "%s%d-auth-cfgs", DRIVER_NAME,
hba->ddiinst);
cnt = 0;
arrayp = NULL;
rval = ddi_prop_lookup_string_array(DDI_DEV_T_ANY, hba->dip,
(DDI_PROP_DONTPASS),
buffer, &arrayp, &cnt);
if ((rval != DDI_PROP_SUCCESS) || !cnt || !arrayp) {
/* Check for the global setting */
cnt = 0;
arrayp = NULL;
rval = ddi_prop_lookup_string_array(DDI_DEV_T_ANY,
hba->dip, (DDI_PROP_DONTPASS),
"auth-cfgs", &arrayp, &cnt);
}
if ((rval != DDI_PROP_SUCCESS) || !cnt || !arrayp) {
return;
}
for (i = 0; i < cnt; i++) {
prop_str = arrayp[i];
if (prop_str == NULL) {
break;
}
/* parse the string */
if (emlxs_auth_cfg_parse(hba, &auth_cfg, prop_str) == 0) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_msg,
"Error parsing auth_cfgs property. entry=%d", i);
continue;
}
auth_cfg2 = emlxs_auth_cfg_create(hba,
(uint8_t *)&auth_cfg.local_entity,
(uint8_t *)&auth_cfg.remote_entity);
if (!auth_cfg2) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_msg,
"Out of memory parsing auth_cfgs property. ey=%d",
i);
return;
}
auth_cfg.next = auth_cfg2->next;
auth_cfg.prev = auth_cfg2->prev;
bcopy((uint8_t *)&auth_cfg,
(uint8_t *)auth_cfg2,
sizeof (emlxs_auth_cfg_t));
}
return;
} /* emlxs_auth_cfg_read() */
/* auth_lock must be held */
static uint32_t
emlxs_auth_cfg_parse(
emlxs_hba_t *hba,
emlxs_auth_cfg_t *auth_cfg,
char *prop_str)
{
emlxs_port_t *port = &PPORT;
emlxs_config_t *cfg = &CFG;
uint32_t errors = 0;
uint32_t c1;
uint8_t *np;
uint32_t j;
uint32_t i;
uint32_t sum;
char *s;
s = prop_str;
bzero(auth_cfg, sizeof (emlxs_auth_cfg_t));
/* Read local wwpn */
np = (uint8_t *)&auth_cfg->local_entity;
for (j = 0; j < 8; j++) {
c1 = *s++;
if ((c1 >= '0') && (c1 <= '9')) {
sum = ((c1 - '0') << 4);
} else if ((c1 >= 'a') && (c1 <= 'f')) {
sum = ((c1 - 'a' + 10) << 4);
} else if ((c1 >= 'A') && (c1 <= 'F')) {
sum = ((c1 - 'A' + 10) << 4);
} else {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Cfg err:Invalid LWWPN found. byte=%d hi_nibble=%c",
j, c1);
errors++;
}
c1 = *s++;
if ((c1 >= '0') && (c1 <= '9')) {
sum |= (c1 - '0');
} else if ((c1 >= 'a') && (c1 <= 'f')) {
sum |= (c1 - 'a' + 10);
} else if ((c1 >= 'A') && (c1 <= 'F')) {
sum |= (c1 - 'A' + 10);
} else {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Cfg err: Invalid LWWPN found. %d %c",
j, c1);
errors++;
}
*np++ = (uint8_t)sum;
}
if (*s++ != ':') {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Cfg err: Invalid delimiter after LWWPN.");
goto out;
}
/* Read remote wwpn */
np = (uint8_t *)&auth_cfg->remote_entity;
for (j = 0; j < 8; j++) {
c1 = *s++;
if ((c1 >= '0') && (c1 <= '9')) {
sum = ((c1 - '0') << 4);
} else if ((c1 >= 'a') && (c1 <= 'f')) {
sum = ((c1 - 'a' + 10) << 4);
} else if ((c1 >= 'A') && (c1 <= 'F')) {
sum = ((c1 - 'A' + 10) << 4);
} else {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Cfg err: Invalid RWWPN found.byte=%d hi_nibble=%c",
j, c1);
errors++;
}
c1 = *s++;
if ((c1 >= '0') && (c1 <= '9')) {
sum |= (c1 - '0');
} else if ((c1 >= 'a') && (c1 <= 'f')) {
sum |= (c1 - 'a' + 10);
} else if ((c1 >= 'A') && (c1 <= 'F')) {
sum |= (c1 - 'A' + 10);
} else {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Cfg err: Invalid RWWPN found. %d %c",
j, c1);
errors++;
}
*np++ = (uint8_t)sum;
}
if (*s++ != ':') {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Cfg err: Invalid delimiter after RWWPN.");
goto out;
}
/* Read auth_tov (%x) */
sum = 0;
do {
c1 = *s++;
if ((c1 >= '0') && (c1 <= '9')) {
sum = (sum << 4) + (c1 - '0');
} else if ((c1 >= 'a') && (c1 <= 'f')) {
sum = (sum << 4) + (c1 - 'a' + 10);
} else if ((c1 >= 'A') && (c1 <= 'F')) {
sum = (sum << 4) + (c1 - 'A' + 10);
} else {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Cfg err: Invalid auth_tov found. c=%c sum=%d",
c1, sum);
errors++;
}
} while (*s != ':' && *s != 0);
auth_cfg->authentication_timeout = sum;
if (*s++ != ':') {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Cfg err: Invalid delimiter after auth_tov.");
goto out;
}
/* Read auth_mode */
sum = 0;
do {
c1 = *s++;
if ((c1 >= '0') && (c1 <= '9')) {
sum = (sum << 4) + (c1 - '0');
} else if ((c1 >= 'a') && (c1 <= 'f')) {
sum = (sum << 4) + (c1 - 'a' + 10);
} else if ((c1 >= 'A') && (c1 <= 'F')) {
sum = (sum << 4) + (c1 - 'A' + 10);
} else {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Cfg err: Invalid auth_mode found. c=%c sum=%d",
c1, sum);
errors++;
}
} while (*s != ':' && *s != 0);
auth_cfg->authentication_mode = sum;
if (*s++ != ':') {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Config error: Invalid delimiter after auth_mode.");
goto out;
}
/* Read auth_bidir */
sum = 0;
do {
c1 = *s++;
if ((c1 >= '0') && (c1 <= '9')) {
sum = (sum << 4) + (c1 - '0');
} else if ((c1 >= 'a') && (c1 <= 'f')) {
sum = (sum << 4) + (c1 - 'a' + 10);
} else if ((c1 >= 'A') && (c1 <= 'F')) {
sum = (sum << 4) + (c1 - 'A' + 10);
} else {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Cfg err: Invalid auth_bidir found. c=%c sum=%d",
c1, sum);
errors++;
}
} while (*s != ':' && *s != 0);
auth_cfg->bidirectional = sum;
if (*s++ != ':') {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Cfg err: Invalid delimiter after auth_bidir.");
goto out;
}
/* Read type_priority[4] */
for (i = 0; i < 4; i++) {
c1 = *s++;
if ((c1 >= '0') && (c1 <= '9')) {
sum = (c1 - '0');
} else if ((c1 >= 'a') && (c1 <= 'f')) {
sum = (c1 - 'a' + 10);
} else if ((c1 >= 'A') && (c1 <= 'F')) {
sum = (c1 - 'A' + 10);
} else {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Cfg err: Invalid type_pty[%d] found. c=%c sum=%d",
i, c1, sum);
errors++;
}
auth_cfg->authentication_type_priority[i] = sum;
}
if (*s++ != ':') {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Cfg err: Invalid delimiter after type_priority.");
goto out;
}
/* Read hash_priority[4] */
for (i = 0; i < 4; i++) {
c1 = *s++;
if ((c1 >= '0') && (c1 <= '9')) {
sum = (c1 - '0');
} else if ((c1 >= 'a') && (c1 <= 'f')) {
sum = (c1 - 'a' + 10);
} else if ((c1 >= 'A') && (c1 <= 'F')) {
sum = (c1 - 'A' + 10);
} else {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Cfg err: Invalid hash_priority[%d] fd. %c %d",
i, c1, sum);
errors++;
}
auth_cfg->hash_priority[i] = sum;
}
if (*s++ != ':') {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Cfg err: Invalid delimiter after hash_priority.");
goto out;
}
/* Read group_priority[8] */
for (i = 0; i < 8; i++) {
c1 = *s++;
if ((c1 >= '0') && (c1 <= '9')) {
sum = (c1 - '0');
} else if ((c1 >= 'a') && (c1 <= 'f')) {
sum = (c1 - 'a' + 10);
} else if ((c1 >= 'A') && (c1 <= 'F')) {
sum = (c1 - 'A' + 10);
} else {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Cfg err: Invalid group_priority[%d] fd. %c %d",
i, c1, sum);
errors++;
}
auth_cfg->dh_group_priority[i] = sum;
}
if (*s++ != ':') {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Cfg err: Invalid delimiter after group_priority.");
goto out;
}
/* Read reauth_tov */
sum = 0;
do {
c1 = *s++;
if ((c1 >= '0') && (c1 <= '9')) {
sum = (sum << 4) + (c1 - '0');
} else if ((c1 >= 'a') && (c1 <= 'f')) {
sum = (sum << 4) + (c1 - 'a' + 10);
} else if ((c1 >= 'A') && (c1 <= 'F')) {
sum = (sum << 4) + (c1 - 'A' + 10);
} else {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Cfg err: Invalid reauth_tov found. c=%c sum=%d",
c1, sum);
errors++;
}
} while (*s != ':' && *s != 0);
auth_cfg->reauthenticate_time_interval = sum;
if (errors) {
goto out;
}
/* Verify values */
/* Check authentication_timeout */
if (auth_cfg->authentication_timeout < cfg[CFG_AUTH_TMO].low) {
auth_cfg->authentication_timeout = cfg[CFG_AUTH_TMO].current;
} else if (auth_cfg->authentication_timeout > cfg[CFG_AUTH_TMO].hi) {
auth_cfg->authentication_timeout = cfg[CFG_AUTH_TMO].current;
}
/* Check authentication_mode */
if (auth_cfg->authentication_mode < cfg[CFG_AUTH_MODE].low) {
auth_cfg->authentication_mode = cfg[CFG_AUTH_MODE].current;
} else if (auth_cfg->authentication_mode > cfg[CFG_AUTH_MODE].hi) {
auth_cfg->authentication_mode = cfg[CFG_AUTH_MODE].current;
}
/* Check bidirectional */
if (auth_cfg->bidirectional < cfg[CFG_AUTH_BIDIR].low) {
auth_cfg->bidirectional = cfg[CFG_AUTH_BIDIR].current;
} else if (auth_cfg->bidirectional > cfg[CFG_AUTH_BIDIR].hi) {
auth_cfg->bidirectional = cfg[CFG_AUTH_BIDIR].current;
}
/* Check authentication_type_priority and hash_priority */
for (i = 0; i < 4; i++) {
if (auth_cfg->authentication_type_priority[i] >
DFC_AUTH_TYPE_MAX) {
/* Set to current default */
auth_cfg->authentication_type_priority[i] =
hba->auth_cfg.authentication_type_priority[i];
}
if (auth_cfg->hash_priority[i] > DFC_AUTH_HASH_MAX) {
/* Set to current default */
auth_cfg->hash_priority[i] =
hba->auth_cfg.hash_priority[i];
}
}
/* Check dh_group_priority */
for (i = 0; i < 8; i++) {
if (auth_cfg->dh_group_priority[i] > DFC_AUTH_GROUP_MAX) {
/* Set to current default */
auth_cfg->dh_group_priority[i] =
hba->auth_cfg.dh_group_priority[i];
}
}
/* Check reauthenticate_time_interval */
if (auth_cfg->reauthenticate_time_interval <
cfg[CFG_AUTH_INTERVAL].low) {
auth_cfg->reauthenticate_time_interval =
cfg[CFG_AUTH_INTERVAL].current;
} else if (auth_cfg->reauthenticate_time_interval >
cfg[CFG_AUTH_INTERVAL].hi) {
auth_cfg->reauthenticate_time_interval =
cfg[CFG_AUTH_INTERVAL].current;
}
emlxs_auth_cfg_print(hba, auth_cfg);
out:
if (errors) {
bzero(auth_cfg, sizeof (emlxs_auth_cfg_t));
return (0);
}
return (1);
} /* emlxs_auth_cfg_parse() */
/* **************************** AUTH KEY MANAGEMENT ************************* */
/* auth_lock must be held */
extern emlxs_auth_key_t *
emlxs_auth_key_find(emlxs_port_t *port, uint8_t *rwwpn)
{
emlxs_hba_t *hba = HBA;
emlxs_auth_key_t *auth_key;
if (rwwpn) {
/* lwwpn, rwwpn */
auth_key = emlxs_auth_key_get(hba,
(uint8_t *)&port->wwpn, (uint8_t *)rwwpn);
if (auth_key) {
emlxs_auth_key_print(hba, auth_key);
return (auth_key);
}
/* null, rwwpn */
auth_key = emlxs_auth_key_get(hba,
(uint8_t *)emlxs_null_wwn, (uint8_t *)rwwpn);
if (auth_key) {
emlxs_auth_key_print(hba, auth_key);
return (auth_key);
}
}
/* lwwpn, null */
auth_key = emlxs_auth_key_get(hba,
(uint8_t *)&port->wwpn, (uint8_t *)emlxs_null_wwn);
if (auth_key) {
emlxs_auth_key_print(hba, auth_key);
return (auth_key);
}
return (NULL);
} /* emlxs_auth_key_find() */
static void
emlxs_auth_key_init(emlxs_hba_t *hba)
{
emlxs_auth_key_t *auth_key;
/* Destroy old table if one exists */
emlxs_auth_key_fini(hba);
mutex_enter(&hba->auth_lock);
/* Zero default entry */
auth_key = &hba->auth_key;
bzero(auth_key, sizeof (emlxs_auth_key_t));
auth_key->next = auth_key;
auth_key->prev = auth_key;
/* Configure the default entry */
auth_key->local_password_type = PASSWORD_TYPE_IGNORE;
auth_key->remote_password_type = PASSWORD_TYPE_IGNORE;
emlxs_auth_key_read(hba);
mutex_exit(&hba->auth_lock);
return;
} /* emlxs_auth_key_init() */
static void
emlxs_auth_key_fini(emlxs_hba_t *hba)
{
emlxs_auth_key_t *auth_key = hba->auth_key.next;
emlxs_auth_key_t *next;
mutex_enter(&hba->auth_lock);
while (auth_key && auth_key != &hba->auth_key) {
next = auth_key->next;
emlxs_auth_key_destroy(hba, auth_key);
auth_key = next;
}
mutex_exit(&hba->auth_lock);
return;
} /* emlxs_auth_key_fini() */
static void
emlxs_auth_key_print(emlxs_hba_t *hba, emlxs_auth_key_t *auth_key)
{
emlxs_port_t *port = &PPORT;
char s_lwwpn[32];
char s_rwwpn[32];
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_detail_msg,
"auth-key> %s:%s:%x:*%d chars*:%x:*%d chars*",
emlxs_wwn_xlate(s_lwwpn, sizeof (s_lwwpn),
(uint8_t *)&auth_key->local_entity),
emlxs_wwn_xlate(s_rwwpn, sizeof (s_rwwpn),
(uint8_t *)&auth_key->remote_entity),
auth_key->local_password_type, auth_key->local_password_length,
auth_key->remote_password_type, auth_key->remote_password_length);
return;
} /* emlxs_auth_key_print() */
/* auth_lock must be held */
static emlxs_auth_key_t *
emlxs_auth_key_get(emlxs_hba_t *hba, uint8_t *lwwpn, uint8_t *rwwpn)
{
emlxs_auth_key_t *auth_key;
if (!lwwpn || !rwwpn) {
return (NULL);
}
/* Check for default entry */
if ((bcmp(lwwpn, emlxs_null_wwn, 8) == 0) &&
(bcmp(rwwpn, emlxs_null_wwn, 8) == 0)) {
return (&hba->auth_key);
}
for (auth_key = hba->auth_key.next; auth_key !=
&hba->auth_key; auth_key = auth_key->next) {
/* Find pwd entry for this local port */
/* Check for exact wwpn match */
if (bcmp((void *)&auth_key->local_entity,
(void *)lwwpn, 8) != 0) {
continue;
}
/* Find pwd entry for remote port */
/* Check for exact wwpn match */
if (bcmp((void *)&auth_key->remote_entity,
(void *)rwwpn, 8) != 0) {
continue;
}
return (auth_key);
}
return (NULL);
} /* emlxs_auth_key_get() */
/* auth_lock must be held */
static emlxs_auth_key_t *
emlxs_auth_key_create(emlxs_hba_t *hba, uint8_t *lwwpn, uint8_t *rwwpn)
{
emlxs_auth_key_t *auth_key;
/* First check if entry already exists */
auth_key = emlxs_auth_key_get(hba, lwwpn, rwwpn);
if (auth_key) {
return (auth_key);
}
/* Allocate entry */
auth_key = (emlxs_auth_key_t *)kmem_zalloc(sizeof (emlxs_auth_key_t),
KM_NOSLEEP);
if (!auth_key) {
return (NULL);
}
/* Initialize name pair */
if (lwwpn) {
bcopy((void *)lwwpn, (void *)&auth_key->local_entity, 8);
}
if (rwwpn) {
bcopy((void *)rwwpn, (void *)&auth_key->remote_entity, 8);
}
/* Initialize type */
auth_key->local_password_type = PASSWORD_TYPE_IGNORE;
auth_key->remote_password_type = PASSWORD_TYPE_IGNORE;
/* Add to list */
auth_key->next = &hba->auth_key;
auth_key->prev = hba->auth_key.prev;
hba->auth_key.prev->next = auth_key;
hba->auth_key.prev = auth_key;
hba->auth_key_count++;
return (auth_key);
} /* emlxs_auth_key_create() */
/* auth_lock must be held */
static void
emlxs_auth_key_destroy(emlxs_hba_t *hba, emlxs_auth_key_t *auth_key)
{
if (!auth_key) {
return;
}
if (auth_key == &hba->auth_key) {
return;
}
/* Remove from list */
auth_key->next->prev = auth_key->prev;
auth_key->prev->next = auth_key->next;
hba->auth_key_count--;
/* Remove node binding */
if (auth_key->node &&
auth_key->node->nlp_active &&
(auth_key->node->node_dhc.parent_auth_key == auth_key)) {
auth_key->node->node_dhc.parent_auth_key = NULL;
}
bzero(auth_key, sizeof (emlxs_auth_key_t));
kmem_free(auth_key, sizeof (emlxs_auth_key_t));
return;
} /* emlxs_auth_key_destroy() */
/* auth_lock must be held */
static void
emlxs_auth_key_read(emlxs_hba_t *hba)
{
emlxs_port_t *port = &PPORT;
char **arrayp;
emlxs_auth_key_t auth_key;
emlxs_auth_key_t *auth_key2;
uint32_t cnt;
uint32_t rval;
char buffer[64];
char *prop_str;
uint32_t i;
/* Check for the per adapter setting */
(void) snprintf(buffer, sizeof (buffer), "%s%d-auth-keys", DRIVER_NAME,
hba->ddiinst);
cnt = 0;
arrayp = NULL;
rval = ddi_prop_lookup_string_array(DDI_DEV_T_ANY, hba->dip,
(DDI_PROP_DONTPASS),
buffer, &arrayp, &cnt);
if ((rval != DDI_PROP_SUCCESS) || !cnt || !arrayp) {
/* Check for the global setting */
cnt = 0;
arrayp = NULL;
rval = ddi_prop_lookup_string_array(DDI_DEV_T_ANY, hba->dip,
(DDI_PROP_DONTPASS),
"auth-keys", &arrayp, &cnt);
}
if ((rval != DDI_PROP_SUCCESS) || !cnt || !arrayp) {
return;
}
for (i = 0; i < cnt; i++) {
prop_str = arrayp[i];
if (prop_str == NULL) {
break;
}
/* parse the string */
if (emlxs_auth_key_parse(hba, &auth_key, prop_str) == 0) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_msg,
"Error parsing auth_keys property. entry=%d", i);
continue;
}
auth_key2 = emlxs_auth_key_create(hba,
(uint8_t *)&auth_key.local_entity,
(uint8_t *)&auth_key.remote_entity);
if (!auth_key2) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_msg,
"Out of memory parsing auth_keys property. %d",
i);
return;
}
auth_key.next = auth_key2->next;
auth_key.prev = auth_key2->prev;
bcopy((uint8_t *)&auth_key,
(uint8_t *)auth_key2, sizeof (emlxs_auth_key_t));
}
return;
} /* emlxs_auth_key_read() */
/* auth_lock must be held */
static uint32_t
emlxs_auth_key_parse(
emlxs_hba_t *hba,
emlxs_auth_key_t *auth_key,
char *prop_str)
{
emlxs_port_t *port = &PPORT;
uint32_t errors = 0;
uint32_t c1;
uint8_t *np;
uint32_t j;
uint32_t sum;
char *s;
s = prop_str;
bzero(auth_key, sizeof (emlxs_auth_key_t));
/* Read local wwpn */
np = (uint8_t *)&auth_key->local_entity;
for (j = 0; j < 8; j++) {
c1 = *s++;
if ((c1 >= '0') && (c1 <= '9')) {
sum = ((c1 - '0') << 4);
} else if ((c1 >= 'a') && (c1 <= 'f')) {
sum = ((c1 - 'a' + 10) << 4);
} else if ((c1 >= 'A') && (c1 <= 'F')) {
sum = ((c1 - 'A' + 10) << 4);
} else {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Cfg err: Invalid LWWPN found. %d %c",
j, c1);
errors++;
}
c1 = *s++;
if ((c1 >= '0') && (c1 <= '9')) {
sum |= (c1 - '0');
} else if ((c1 >= 'a') && (c1 <= 'f')) {
sum |= (c1 - 'a' + 10);
} else if ((c1 >= 'A') && (c1 <= 'F')) {
sum |= (c1 - 'A' + 10);
} else {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Cfg err: Invalid LWWPN found. %d %c",
j, c1);
errors++;
}
*np++ = (uint8_t)sum;
}
if (*s++ != ':') {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Cfg err: Invalid delimiter after LWWPN.");
goto out;
}
/* Read remote wwpn */
np = (uint8_t *)&auth_key->remote_entity;
for (j = 0; j < 8; j++) {
c1 = *s++;
if ((c1 >= '0') && (c1 <= '9')) {
sum = ((c1 - '0') << 4);
} else if ((c1 >= 'a') && (c1 <= 'f')) {
sum = ((c1 - 'a' + 10) << 4);
} else if ((c1 >= 'A') && (c1 <= 'F')) {
sum = ((c1 - 'A' + 10) << 4);
} else {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Cfg err: Invalid RWWPN found.%d %c",
j, c1);
errors++;
}
c1 = *s++;
if ((c1 >= '0') && (c1 <= '9')) {
sum |= (c1 - '0');
} else if ((c1 >= 'a') && (c1 <= 'f')) {
sum |= (c1 - 'a' + 10);
} else if ((c1 >= 'A') && (c1 <= 'F')) {
sum |= (c1 - 'A' + 10);
} else {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Cfg err: Invalid RWWPN found. %d %c",
j, c1);
errors++;
}
*np++ = (uint8_t)sum;
}
if (*s++ != ':') {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Cfg err: Invalid delimiter after RWWPN.");
goto out;
}
/* Read lpwd type (%x) */
sum = 0;
do {
c1 = *s++;
if ((c1 >= '0') && (c1 <= '9')) {
sum = (sum << 4) + (c1 - '0');
} else if ((c1 >= 'a') && (c1 <= 'f')) {
sum = (sum << 4) + (c1 - 'a' + 10);
} else if ((c1 >= 'A') && (c1 <= 'F')) {
sum = (sum << 4) + (c1 - 'A' + 10);
} else {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Cfg err: Invalid lpwd type found. %c %d",
c1, sum);
errors++;
}
} while (*s != ':' && *s != 0);
auth_key->local_password_type = (uint16_t)sum;
if (*s++ != ':') {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Cfg err: Invalid delimiter after lpwd type.");
goto out;
}
/* Read lpwd */
np = (uint8_t *)&auth_key->local_password;
j = 0;
switch (auth_key->local_password_type) {
case 1: /* ACSII */
while (*s != ':' && *s != 0) {
*np++ = *s++;
j++;
}
break;
case 2: /* Hex */
do {
c1 = *s++;
if ((c1 >= '0') && (c1 <= '9')) {
sum = ((c1 - '0') << 4);
} else if ((c1 >= 'a') && (c1 <= 'f')) {
sum = ((c1 - 'a' + 10) << 4);
} else if ((c1 >= 'A') && (c1 <= 'F')) {
sum = ((c1 - 'A' + 10) << 4);
} else {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Cfg err: Invalid lpwd found. %d %c",
j, c1);
errors++;
}
c1 = *s++;
if ((c1 >= '0') && (c1 <= '9')) {
sum |= (c1 - '0');
} else if ((c1 >= 'a') && (c1 <= 'f')) {
sum |= (c1 - 'a' + 10);
} else if ((c1 >= 'A') && (c1 <= 'F')) {
sum |= (c1 - 'A' + 10);
} else {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Cfg err: Invalid lpwd found. %d %c",
j, c1);
errors++;
}
*np++ = (uint8_t)sum;
j++;
} while (*s != ':' && *s != 0);
break;
case 0: /* Ignore */
case 3: /* Ignore */
break;
default:
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Config error: Invalid lpwd type found. type=%x",
auth_key->local_password_type);
errors++;
goto out;
}
auth_key->local_password_length = (uint16_t)j;
if (*s++ != ':') {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Config error: Invalid delimiter after lpwd.");
goto out;
}
/* Read rpwd type (%x) */
sum = 0;
do {
c1 = *s++;
if ((c1 >= '0') && (c1 <= '9')) {
sum = (sum << 4) + (c1 - '0');
} else if ((c1 >= 'a') && (c1 <= 'f')) {
sum = (sum << 4) + (c1 - 'a' + 10);
} else if ((c1 >= 'A') && (c1 <= 'F')) {
sum = (sum << 4) + (c1 - 'A' + 10);
} else {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Config error: Invalid rpwd type found. %c %d",
c1, sum);
errors++;
}
} while (*s != ':' && *s != 0);
auth_key->remote_password_type = (uint16_t)sum;
if (*s++ != ':') {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Config error: Invalid delimiter after rpwd type.");
goto out;
}
/* Read rpwd */
np = (uint8_t *)&auth_key->remote_password;
j = 0;
switch (auth_key->remote_password_type) {
case 1: /* ACSII */
while (*s != ':' && *s != 0) {
*np++ = *s++;
j++;
}
break;
case 2: /* Hex */
do {
c1 = *s++;
if ((c1 >= '0') && (c1 <= '9')) {
sum = ((c1 - '0') << 4);
} else if ((c1 >= 'a') && (c1 <= 'f')) {
sum = ((c1 - 'a' + 10) << 4);
} else if ((c1 >= 'A') && (c1 <= 'F')) {
sum = ((c1 - 'A' + 10) << 4);
} else {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Cfg err: Invalid rpwd found. %d %c",
j, c1);
errors++;
}
c1 = *s++;
if ((c1 >= '0') && (c1 <= '9')) {
sum |= (c1 - '0');
} else if ((c1 >= 'a') && (c1 <= 'f')) {
sum |= (c1 - 'a' + 10);
} else if ((c1 >= 'A') && (c1 <= 'F')) {
sum |= (c1 - 'A' + 10);
} else {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Cfg err: Invalid rpwd found. %d %c",
j, c1);
errors++;
}
*np++ = (uint8_t)sum;
j++;
} while (*s != ':' && *s != 0);
break;
case 0: /* Ignore */
case 3: /* Ignore */
break;
default:
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_attach_debug_msg,
"Cfg error: Invalid rpwd type found. type=%x",
auth_key->remote_password_type);
errors++;
goto out;
}
auth_key->remote_password_length = (uint16_t)j;
if (errors) {
goto out;
}
/* Verify values */
if (auth_key->local_password_type == 0 ||
auth_key->local_password_type > 3 ||
auth_key->local_password_length == 0) {
auth_key->local_password_type = 3;
auth_key->local_password_length = 0;
bzero(auth_key->local_password,
sizeof (auth_key->local_password));
}
if (auth_key->remote_password_type == 0 ||
auth_key->remote_password_type > 3 ||
auth_key->remote_password_length == 0) {
auth_key->remote_password_type = 3;
auth_key->remote_password_length = 0;
bzero(auth_key->remote_password,
sizeof (auth_key->remote_password));
}
/* Display entry */
emlxs_auth_key_print(hba, auth_key);
out:
if (errors) {
bzero(auth_key, sizeof (emlxs_auth_key_t));
return (0);
}
return (1);
} /* emlxs_auth_key_parse() */
/* ************************** AUTH DFCLIB SUPPORT *********************** */
/* Provides DFC support for emlxs_dfc_init_auth() */
extern uint32_t
emlxs_dhc_init_auth(emlxs_hba_t *hba, uint8_t *lwwpn, uint8_t *rwwpn)
{
emlxs_port_t *port = &PPORT;
emlxs_config_t *cfg = &CFG;
NODELIST *ndlp;
uint32_t vpi;
char s_wwpn[64];
/* Return is authentication is not enabled */
if (cfg[CFG_AUTH_ENABLE].current == 0) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_debug_msg,
"dhc_init_auth. Auth disabled.");
return (DFC_AUTH_AUTHENTICATION_DISABLED);
}
/* Scan for lwwpn match */
for (vpi = 0; vpi < MAX_VPORTS; vpi++) {
port = &VPORT(vpi);
if (!(port->flag & EMLXS_PORT_BOUND)) {
continue;
}
if (bcmp((uint8_t *)&port->wwpn, lwwpn, 8) == 0) {
break;
}
}
if (vpi == MAX_VPORTS) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_dfc_error_msg,
"dhc_init_auth: lwwpn not found. %s",
emlxs_wwn_xlate(s_wwpn, sizeof (s_wwpn), lwwpn));
return (DFC_AUTH_WWN_NOT_FOUND);
}
if (bcmp(rwwpn, emlxs_fabric_wwn, 8) == 0) {
/* Scan for fabric node */
if ((ndlp = emlxs_node_find_did(port, FABRIC_DID, 1)) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_dfc_error_msg,
"dhc_init_auth: fabric node not found.");
return (DFC_AUTH_WWN_NOT_FOUND);
}
} else {
/* Scan for rwwpn match */
if ((ndlp = emlxs_node_find_wwpn(port, rwwpn, 1)) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_dfc_error_msg,
"dhc_init_auth: rwwpn not found. %s",
emlxs_wwn_xlate(s_wwpn, sizeof (s_wwpn), rwwpn));
return (DFC_AUTH_WWN_NOT_FOUND);
}
}
if ((ndlp->nlp_DID != FABRIC_DID) &&
((port->port_dhc.state != ELX_FABRIC_AUTH_SUCCESS))) {
return (DFC_IO_ERROR);
}
if (ndlp->node_dhc.state >= NODE_STATE_AUTH_NEGOTIATE_ISSUE) {
return (DFC_AUTH_AUTHENTICATION_GOINGON);
}
if (ndlp->node_dhc.state == NODE_STATE_AUTH_SUCCESS) {
ndlp->node_dhc.nlp_reauth_status = NLP_HOST_REAUTH_IN_PROGRESS;
}
/* Attempt to start authentication */
if (emlxs_dhc_auth_start(port, ndlp, NULL, NULL) != 0) {
return (DFC_IO_ERROR);
}
return (0);
} /* emlxs_dhc_init_auth() */
/* Provides DFC support for emlxs_dfc_get_auth_cfg() */
extern uint32_t
emlxs_dhc_get_auth_cfg(emlxs_hba_t *hba, dfc_fcsp_config_t *fcsp_cfg)
{
emlxs_port_t *port = &PPORT;
emlxs_config_t *cfg = &CFG;
char s_lwwpn[64];
char s_rwwpn[64];
emlxs_auth_cfg_t *auth_cfg;
uint32_t i;
/* Return is authentication is not enabled */
if (cfg[CFG_AUTH_ENABLE].current == 0) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_debug_msg,
"dhc_get_auth_cfg. Auth disabled.");
return (DFC_AUTH_AUTHENTICATION_DISABLED);
}
mutex_enter(&hba->auth_lock);
auth_cfg = emlxs_auth_cfg_get(hba,
(uint8_t *)&fcsp_cfg->lwwpn, (uint8_t *)&fcsp_cfg->rwwpn);
if (!auth_cfg) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_dfc_error_msg,
"dhc_get_auth_cfg: entry not found. %s:%s",
emlxs_wwn_xlate(s_lwwpn, sizeof (s_lwwpn),
(uint8_t *)&fcsp_cfg->lwwpn),
emlxs_wwn_xlate(s_rwwpn, sizeof (s_rwwpn),
(uint8_t *)&fcsp_cfg->rwwpn));
mutex_exit(&hba->auth_lock);
return (DFC_AUTH_NOT_CONFIGURED);
}
fcsp_cfg->auth_tov = auth_cfg->authentication_timeout;
fcsp_cfg->auth_mode = auth_cfg->authentication_mode;
fcsp_cfg->auth_bidir = auth_cfg->bidirectional;
for (i = 0; i < 4; i++) {
fcsp_cfg->type_priority[i] =
auth_cfg->authentication_type_priority[i];
fcsp_cfg->hash_priority[i] =
auth_cfg->hash_priority[i];
}
for (i = 0; i < 8; i++) {
fcsp_cfg->group_priority[i] = auth_cfg->dh_group_priority[i];
}
fcsp_cfg->reauth_tov = auth_cfg->reauthenticate_time_interval;
mutex_exit(&hba->auth_lock);
return (0);
} /* emlxs_dhc_get_auth_cfg() */
/* Provides DFC support for emlxs_dfc_set_auth_cfg() */
extern uint32_t
emlxs_dhc_add_auth_cfg(
emlxs_hba_t *hba,
dfc_fcsp_config_t *fcsp_cfg,
dfc_password_t *dfc_pwd)
{
emlxs_port_t *port = &PPORT;
emlxs_config_t *cfg = &CFG;
emlxs_auth_cfg_t *auth_cfg;
emlxs_auth_key_t *auth_key;
uint32_t i;
NODELIST *ndlp;
/* Return if authentication is not enabled */
if (cfg[CFG_AUTH_ENABLE].current == 0) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_debug_msg,
"dhc_add_auth_cfg. Auth disabled.");
return (DFC_AUTH_AUTHENTICATION_DISABLED);
}
mutex_enter(&hba->auth_lock);
auth_key = emlxs_auth_key_get(hba,
(uint8_t *)&fcsp_cfg->lwwpn, (uint8_t *)&fcsp_cfg->rwwpn);
if (auth_key &&
(auth_key->local_password_type == PASSWORD_TYPE_ASCII ||
auth_key->local_password_type == PASSWORD_TYPE_BINARY)) {
/* Verify local password */
if ((auth_key->local_password_length != dfc_pwd->length) ||
(auth_key->local_password_type != dfc_pwd->type) ||
bcmp(dfc_pwd->password, auth_key->local_password,
dfc_pwd->length)) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_dfc_error_msg,
"dhc_add_auth_cfg: Invalid local password.");
mutex_exit(&hba->auth_lock);
return (DFC_AUTH_COMPARE_FAILED);
}
}
/* Create entry */
auth_cfg = emlxs_auth_cfg_create(hba,
(uint8_t *)&fcsp_cfg->lwwpn,
(uint8_t *)&fcsp_cfg->rwwpn);
if (!auth_cfg) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_dfc_error_msg,
"dhc_add_auth_cfg: Out of memory.");
mutex_exit(&hba->auth_lock);
return (DFC_SYSRES_ERROR);
}
/* Init entry */
auth_cfg->authentication_timeout = fcsp_cfg->auth_tov;
auth_cfg->authentication_mode = fcsp_cfg->auth_mode;
auth_cfg->bidirectional = fcsp_cfg->auth_bidir;
for (i = 0; i < 4; i++) {
auth_cfg->authentication_type_priority[i] =
fcsp_cfg->type_priority[i];
auth_cfg->hash_priority[i] =
fcsp_cfg->hash_priority[i];
}
for (i = 0; i < 8; i++) {
auth_cfg->dh_group_priority[i] = fcsp_cfg->group_priority[i];
}
auth_cfg->reauthenticate_time_interval = fcsp_cfg->reauth_tov;
emlxs_auth_cfg_print(hba, auth_cfg);
/* Cancel old reauth to restart the new one if necessary */
/* Scan for lwwpn match */
for (i = 0; i < MAX_VPORTS; i++) {
port = &VPORT(i);
if (!(port->flag & EMLXS_PORT_BOUND)) {
continue;
}
if (bcmp((uint8_t *)&fcsp_cfg->lwwpn,
(uint8_t *)&port->wwpn, 8)) {
continue;
}
/* Port match found */
if (bcmp((uint8_t *)&fcsp_cfg->rwwpn,
emlxs_fabric_wwn, 8) == 0) {
/* Scan for fabric node */
if ((ndlp = emlxs_node_find_did(port,
FABRIC_DID, 1)) == NULL) {
break;
}
} else {
/* Scan for rwwpn match */
if ((ndlp = emlxs_node_find_wwpn(port,
(uint8_t *)&fcsp_cfg->rwwpn, 1)) == NULL) {
break;
}
}
emlxs_dhc_set_reauth_time(port, ndlp, ENABLE);
break;
}
mutex_exit(&hba->auth_lock);
return (0);
} /* emlxs_dhc_add_auth_cfg() */
/* Provides DFC support for emlxs_dfc_set_auth_cfg() */
extern uint32_t
emlxs_dhc_delete_auth_cfg(
emlxs_hba_t *hba,
dfc_fcsp_config_t *fcsp_cfg,
dfc_password_t *dfc_pwd)
{
emlxs_port_t *port = &PPORT;
emlxs_config_t *cfg = &CFG;
char s_lwwpn[64];
char s_rwwpn[64];
emlxs_auth_key_t *auth_key;
emlxs_auth_cfg_t *auth_cfg;
/* Return is authentication is not enabled */
if (cfg[CFG_AUTH_ENABLE].current == 0) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_debug_msg,
"dhc_delete_auth_cfg. Auth disabled.");
return (DFC_AUTH_AUTHENTICATION_DISABLED);
}
mutex_enter(&hba->auth_lock);
auth_key = emlxs_auth_key_get(hba,
(uint8_t *)&fcsp_cfg->lwwpn,
(uint8_t *)&fcsp_cfg->rwwpn);
if (auth_key &&
(auth_key->local_password_type == PASSWORD_TYPE_ASCII ||
auth_key->local_password_type ==
PASSWORD_TYPE_BINARY)) {
/* Verify local password */
if ((auth_key->local_password_length != dfc_pwd->length) ||
(auth_key->local_password_type != dfc_pwd->type) ||
bcmp(dfc_pwd->password,
auth_key->local_password,
dfc_pwd->length)) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_dfc_error_msg,
"dhc_delete_auth_cfg: Ivld local pwd.");
mutex_exit(&hba->auth_lock);
return (DFC_AUTH_COMPARE_FAILED);
}
}
auth_cfg = emlxs_auth_cfg_get(hba,
(uint8_t *)&fcsp_cfg->lwwpn, (uint8_t *)&fcsp_cfg->rwwpn);
if (!auth_cfg) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_dfc_error_msg,
"dhc_delete_auth_cfg: entry not found. %s:%s",
emlxs_wwn_xlate(s_lwwpn, sizeof (s_lwwpn),
(uint8_t *)&fcsp_cfg->lwwpn),
emlxs_wwn_xlate(s_rwwpn, sizeof (s_rwwpn),
(uint8_t *)&fcsp_cfg->rwwpn));
mutex_exit(&hba->auth_lock);
return (DFC_AUTH_WWN_NOT_FOUND);
}
/* Destroy cfg entry */
emlxs_auth_cfg_destroy(hba, auth_cfg);
/* Destroy pwd entry */
emlxs_auth_key_destroy(hba, auth_key);
mutex_exit(&hba->auth_lock);
return (0);
} /* emlxs_dhc_delete_auth_cfg() */
/* Provides DFC support for emlxs_dfc_get_auth_key() */
extern uint32_t
emlxs_dhc_get_auth_key(emlxs_hba_t *hba, dfc_auth_password_t *dfc_auth_pwd)
{
emlxs_port_t *port = &PPORT;
emlxs_config_t *cfg = &CFG;
char s_lwwpn[64];
char s_rwwpn[64];
emlxs_auth_key_t *auth_key;
/* Return is authentication is not enabled */
if (cfg[CFG_AUTH_ENABLE].current == 0) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_debug_msg,
"dhc_get_auth_key. Auth disabled.");
return (DFC_AUTH_AUTHENTICATION_DISABLED);
}
mutex_enter(&hba->auth_lock);
auth_key = emlxs_auth_key_get(hba,
(uint8_t *)&dfc_auth_pwd->lwwpn,
(uint8_t *)&dfc_auth_pwd->rwwpn);
if (!auth_key) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_dfc_error_msg,
"dhc_get_auth_key: entry not found. %s:%s",
emlxs_wwn_xlate(s_lwwpn, sizeof (s_lwwpn),
(uint8_t *)&dfc_auth_pwd->lwwpn),
emlxs_wwn_xlate(s_rwwpn, sizeof (s_rwwpn),
(uint8_t *)&dfc_auth_pwd->rwwpn));
mutex_exit(&hba->auth_lock);
return (DFC_AUTH_NOT_CONFIGURED);
}
dfc_auth_pwd->lpw.length = auth_key->local_password_length;
dfc_auth_pwd->lpw.type = auth_key->local_password_type;
/*
* bcopy(auth_key->local_password, dfc_auth_pwd->lpw.password,
* dfc_auth_pwd->lpw.length);
*/
dfc_auth_pwd->rpw.length = auth_key->remote_password_length;
dfc_auth_pwd->rpw.type = auth_key->remote_password_type;
/*
* bcopy(auth_key->remote_password, dfc_auth_pwd->rpw.password,
* dfc_auth_pwd->rpw.length);
*/
dfc_auth_pwd->lpw_new.length = auth_key->local_password_length;
dfc_auth_pwd->lpw_new.type = auth_key->local_password_type;
/*
* bcopy(auth_key->local_password, dfc_auth_pwd->lpw_new.password,
* dfc_auth_pwd->lpw_new.length);
*/
dfc_auth_pwd->rpw_new.length = auth_key->remote_password_length;
dfc_auth_pwd->rpw_new.type = auth_key->remote_password_type;
/*
* bcopy(auth_key->remote_password, dfc_auth_pwd->rpw_new.password,
* dfc_auth_pwd->rpw_new.length);
*/
mutex_exit(&hba->auth_lock);
return (0);
} /* emlxs_dhc_get_auth_key() */
/* Provides DFC support for emlxs_dfc_set_auth_key() */
extern uint32_t
emlxs_dhc_set_auth_key(emlxs_hba_t *hba, dfc_auth_password_t *dfc_pwd)
{
emlxs_port_t *port = &PPORT;
emlxs_config_t *cfg = &CFG;
emlxs_auth_key_t *auth_key;
uint32_t length;
/* Return is authentication is not enabled */
if (cfg[CFG_AUTH_ENABLE].current == 0) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_debug_msg,
"dhc_set_auth_key. Auth disabled.");
return (DFC_AUTH_AUTHENTICATION_DISABLED);
}
/* Check to make sure localpwd does not equal to remotepwd */
/* if they are given in the same time, if not, see below */
if ((dfc_pwd->lpw_new.type == PASSWORD_TYPE_ASCII ||
dfc_pwd->lpw_new.type == PASSWORD_TYPE_BINARY) &&
(dfc_pwd->rpw_new.type == PASSWORD_TYPE_ASCII ||
dfc_pwd->rpw_new.type == PASSWORD_TYPE_BINARY)) {
if (bcmp(dfc_pwd->lpw_new.password,
dfc_pwd->rpw_new.password,
dfc_pwd->lpw_new.length) == 0) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_debug_msg,
"dhc_set_auth_key. nlpwd==nrpwd");
return (DFC_AUTH_LOCAL_REMOTE_PWD_EQUAL);
}
}
mutex_enter(&hba->auth_lock);
auth_key = emlxs_auth_key_get(hba,
(uint8_t *)&dfc_pwd->lwwpn,
(uint8_t *)&dfc_pwd->rwwpn);
/* If entry does not exist, then create entry */
if (!auth_key) {
auth_key = emlxs_auth_key_create(hba,
(uint8_t *)&dfc_pwd->lwwpn,
(uint8_t *)&dfc_pwd->rwwpn);
if (!auth_key) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_dfc_error_msg,
"dhc_set_auth_key: Out of memory.");
mutex_exit(&hba->auth_lock);
return (DFC_SYSRES_ERROR);
}
}
/* Check if a new local password is provided */
if (dfc_pwd->lpw_new.type == PASSWORD_TYPE_ASCII ||
dfc_pwd->lpw_new.type == PASSWORD_TYPE_BINARY) {
/* Check if current password should be checked */
if (auth_key->local_password_type == PASSWORD_TYPE_ASCII ||
auth_key->local_password_type == PASSWORD_TYPE_BINARY) {
/* Verify current local password */
if ((auth_key->local_password_length !=
dfc_pwd->lpw.length) ||
(auth_key->local_password_type !=
dfc_pwd->lpw.type) ||
bcmp(dfc_pwd->lpw.password,
auth_key->local_password,
dfc_pwd->lpw.length)) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_dfc_error_msg,
"dhc_set_auth_key: Invalid local password.");
mutex_exit(&hba->auth_lock);
return (DFC_AUTH_COMPARE_FAILED);
}
}
/*
* Make sure the new local pwd is not equal to the current
* remote pwd if any
*/
if (auth_key->remote_password_type == PASSWORD_TYPE_ASCII ||
auth_key->remote_password_type == PASSWORD_TYPE_BINARY) {
if ((auth_key->remote_password_length ==
dfc_pwd->lpw_new.length) &&
(bcmp(dfc_pwd->lpw_new.password,
auth_key->remote_password,
dfc_pwd->lpw_new.length) == 0)) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_dfc_error_msg,
"dhc_set_auth_key: nlpwd==crpwd");
mutex_exit(&hba->auth_lock);
return (DFC_AUTH_LOCAL_REMOTE_PWD_EQUAL);
}
}
/* Update local entry */
auth_key->local_password_length = dfc_pwd->lpw_new.length;
auth_key->local_password_type = dfc_pwd->lpw_new.type;
bzero(auth_key->local_password,
sizeof (auth_key->local_password));
length = min(dfc_pwd->lpw_new.length,
sizeof (auth_key->local_password));
bcopy(dfc_pwd->lpw_new.password,
auth_key->local_password, length);
}
/* Check if a new remote password is provided */
if (dfc_pwd->rpw_new.type == PASSWORD_TYPE_ASCII ||
dfc_pwd->rpw_new.type == PASSWORD_TYPE_BINARY) {
/* Check if current password should be checked */
if (auth_key->remote_password_type == PASSWORD_TYPE_ASCII ||
auth_key->remote_password_type == PASSWORD_TYPE_BINARY) {
/* Verify current remote password */
if ((auth_key->remote_password_length !=
dfc_pwd->rpw.length) ||
(auth_key->remote_password_type !=
dfc_pwd->rpw.type) ||
bcmp(dfc_pwd->rpw.password,
auth_key->remote_password,
dfc_pwd->rpw.length)) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_dfc_error_msg,
"dhc_set_auth_key: Invalid remote password.");
mutex_exit(&hba->auth_lock);
return (DFC_AUTH_COMPARE_FAILED);
}
}
/*
* Make sure the new remote pwd is not equal to the current
* local pwd if any
*/
if (auth_key->local_password_type == PASSWORD_TYPE_ASCII ||
auth_key->local_password_type == PASSWORD_TYPE_BINARY) {
if ((auth_key->local_password_length ==
dfc_pwd->rpw_new.length) &&
(bcmp(dfc_pwd->rpw_new.password,
auth_key->local_password,
dfc_pwd->rpw_new.length) == 0)) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_dfc_error_msg,
"dhc_set_auth_key: nrpwd==clpwd");
mutex_exit(&hba->auth_lock);
return (DFC_AUTH_LOCAL_REMOTE_PWD_EQUAL);
}
}
/* Update remote entry */
auth_key->remote_password_length = dfc_pwd->rpw_new.length;
auth_key->remote_password_type = dfc_pwd->rpw_new.type;
bzero(auth_key->remote_password,
sizeof (auth_key->remote_password));
length = min(dfc_pwd->rpw_new.length, 128);
bcopy(dfc_pwd->rpw_new.password,
auth_key->remote_password, length);
}
/* Update dfc local entry */
dfc_pwd->lpw.length = auth_key->local_password_length;
dfc_pwd->lpw.type = auth_key->local_password_type;
bzero(dfc_pwd->lpw.password, sizeof (dfc_pwd->lpw.password));
length = min(auth_key->local_password_length,
sizeof (dfc_pwd->lpw.password));
bcopy(auth_key->local_password, dfc_pwd->lpw.password, length);
/* Update dfc remote entry */
dfc_pwd->rpw.length = auth_key->remote_password_length;
dfc_pwd->rpw.type = auth_key->remote_password_type;
bzero(dfc_pwd->rpw.password, sizeof (dfc_pwd->rpw.password));
length = min(auth_key->remote_password_length,
sizeof (dfc_pwd->rpw.password));
bcopy(auth_key->remote_password, dfc_pwd->rpw.password, length);
emlxs_auth_key_print(hba, auth_key);
mutex_exit(&hba->auth_lock);
return (0);
} /* emlxs_dhc_set_auth_key() */
/* Provides DFC support for emlxs_dfc_get_auth_status() */
extern uint32_t
emlxs_dhc_get_auth_status(emlxs_hba_t *hba, dfc_auth_status_t *fcsp_status)
{
emlxs_port_t *port = &PPORT;
emlxs_config_t *cfg = &CFG;
char s_lwwpn[64];
char s_rwwpn[64];
emlxs_auth_cfg_t *auth_cfg;
dfc_auth_status_t *auth_status;
NODELIST *ndlp;
uint32_t rc;
time_t auth_time;
uint32_t update;
/* Return is authentication is not enabled */
if (cfg[CFG_AUTH_ENABLE].current == 0) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcsp_debug_msg,
"dhc_get_auth_status. Auth disabled.");
return (DFC_AUTH_AUTHENTICATION_DISABLED);
}
mutex_enter(&hba->auth_lock);
auth_cfg = emlxs_auth_cfg_get(hba, (uint8_t *)&fcsp_status->lwwpn,
(uint8_t *)&fcsp_status->rwwpn);
if (!auth_cfg) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
"dhc_get_auth_status: entry not found. %s:%s",
emlxs_wwn_xlate(s_lwwpn, sizeof (s_lwwpn),
(uint8_t *)&fcsp_status->lwwpn),
emlxs_wwn_xlate(s_rwwpn, sizeof (s_rwwpn),
(uint8_t *)&fcsp_status->rwwpn));
mutex_exit(&hba->auth_lock);
return (DFC_AUTH_NOT_CONFIGURED);
}
if (bcmp((uint8_t *)&fcsp_status->rwwpn,
(uint8_t *)emlxs_fabric_wwn, 8) == 0) {
auth_status = &port->port_dhc.auth_status;
auth_time = port->port_dhc.auth_time;
ndlp = emlxs_node_find_did(port, FABRIC_DID, 1);
} else {
auth_status = &auth_cfg->auth_status;
auth_time = auth_cfg->auth_time;
ndlp = auth_cfg->node;
}
update = 0;
/* Check if node is still available */
if (ndlp && ndlp->nlp_active) {
emlxs_dhc_status(port, ndlp, 0, 0);
update = 1;
} else {
rc = DFC_AUTH_WWN_NOT_FOUND;
}
if (update) {
fcsp_status->auth_state = auth_status->auth_state;
fcsp_status->auth_failReason = auth_status->auth_failReason;
fcsp_status->type_priority = auth_status->type_priority;
fcsp_status->group_priority = auth_status->group_priority;
fcsp_status->hash_priority = auth_status->hash_priority;
fcsp_status->localAuth = auth_status->localAuth;
fcsp_status->remoteAuth = auth_status->remoteAuth;
fcsp_status->time_from_last_auth = DRV_TIME - auth_time;
fcsp_status->time_until_next_auth =
auth_status->time_until_next_auth;
rc = 0;
} else {
rc = DFC_AUTH_WWN_NOT_FOUND;
}
mutex_exit(&hba->auth_lock);
return (rc);
} /* emlxs_dhc_get_auth_status() */
/* Provides DFC support for emlxs_dfc_get_auth_list() */
/* auth_lock must be held when calling. */
/* fcsp_cfg must be large enough to hold hba->auth_cfg_count entries */
extern uint32_t
emlxs_dhc_get_auth_cfg_table(emlxs_hba_t *hba, dfc_fcsp_config_t *fcsp_cfg)
{
emlxs_port_t *port = &PPORT;
emlxs_config_t *cfg = &CFG;
emlxs_auth_cfg_t *auth_cfg;
uint32_t i;
/* Return if authentication is not enabled */
if (cfg[CFG_AUTH_ENABLE].current == 0) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_debug_msg,
"dhc_get_auth_cfg_table. Auth disabled.");
return (DFC_AUTH_AUTHENTICATION_DISABLED);
}
for (auth_cfg = hba->auth_cfg.next;
auth_cfg != &hba->auth_cfg;
auth_cfg = auth_cfg->next) {
bcopy((uint8_t *)&auth_cfg->local_entity,
(uint8_t *)&fcsp_cfg->lwwpn, 8);
bcopy((uint8_t *)&auth_cfg->remote_entity,
(uint8_t *)&fcsp_cfg->rwwpn, 8);
fcsp_cfg->auth_tov = auth_cfg->authentication_timeout;
fcsp_cfg->auth_mode = auth_cfg->authentication_mode;
fcsp_cfg->auth_bidir = auth_cfg->bidirectional;
for (i = 0; i < 4; i++) {
fcsp_cfg->type_priority[i] =
auth_cfg->authentication_type_priority[i];
fcsp_cfg->hash_priority[i] =
auth_cfg->hash_priority[i];
}
for (i = 0; i < 8; i++) {
fcsp_cfg->group_priority[i] =
auth_cfg->dh_group_priority[i];
}
fcsp_cfg->reauth_tov = auth_cfg->reauthenticate_time_interval;
fcsp_cfg++;
}
return (0);
} /* emlxs_dhc_get_auth_cfg_table() */
/* Provides DFC support for emlxs_dfc_get_auth_list() */
/* auth_lock must be held when calling. */
/* auth_pwd must be large enough to hold hba->auth_key_count entries */
extern uint32_t
emlxs_dhc_get_auth_key_table(emlxs_hba_t *hba, dfc_auth_password_t *auth_pwd)
{
emlxs_port_t *port = &PPORT;
emlxs_config_t *cfg = &CFG;
emlxs_auth_key_t *auth_key;
/* Return if authentication is not enabled */
if (cfg[CFG_AUTH_ENABLE].current == 0) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_fcsp_debug_msg,
"dhc_get_auth_key_table. Auth disabled.");
return (DFC_AUTH_AUTHENTICATION_DISABLED);
}
for (auth_key = hba->auth_key.next;
auth_key != &hba->auth_key;
auth_key = auth_key->next) {
bcopy((uint8_t *)&auth_key->local_entity,
(uint8_t *)&auth_pwd->lwwpn, 8);
bcopy((uint8_t *)&auth_key->remote_entity,
(uint8_t *)&auth_pwd->rwwpn, 8);
auth_pwd->lpw.length = auth_key->local_password_length;
auth_pwd->lpw.type = auth_key->local_password_type;
/*
* bcopy(auth_key->local_password, auth_pwd->lpw.password,
* auth_pwd->lpw.length);
*/
auth_pwd->rpw.length = auth_key->remote_password_length;
auth_pwd->rpw.type = auth_key->remote_password_type;
/*
* bcopy(auth_key->remote_password, auth_pwd->rpw.password,
* auth_pwd->rpw.length);
*/
auth_pwd->lpw_new.length = auth_key->local_password_length;
auth_pwd->lpw_new.type = auth_key->local_password_type;
/*
* bcopy(auth_key->local_password,
* auth_pwd->lpw_new.password, auth_pwd->lpw_new.length);
*/
auth_pwd->rpw_new.length = auth_key->remote_password_length;
auth_pwd->rpw_new.type = auth_key->remote_password_type;
/*
* bcopy(auth_key->remote_password,
* auth_pwd->rpw_new.password, auth_pwd->rpw_new.length);
*/
auth_pwd++;
}
return (0);
} /* emlxs_dhc_get_auth_key_table() */
#endif /* DHCHAP_SUPPORT */