/* * 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 #ifdef DHCHAP_SUPPORT #include #include #include #include #include #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 */