1a6d42e7dSPeter Dunlap /* 2a6d42e7dSPeter Dunlap * CDDL HEADER START 3a6d42e7dSPeter Dunlap * 4a6d42e7dSPeter Dunlap * The contents of this file are subject to the terms of the 5a6d42e7dSPeter Dunlap * Common Development and Distribution License (the "License"). 6a6d42e7dSPeter Dunlap * You may not use this file except in compliance with the License. 7a6d42e7dSPeter Dunlap * 8a6d42e7dSPeter Dunlap * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9a6d42e7dSPeter Dunlap * or http://www.opensolaris.org/os/licensing. 10a6d42e7dSPeter Dunlap * See the License for the specific language governing permissions 11a6d42e7dSPeter Dunlap * and limitations under the License. 12a6d42e7dSPeter Dunlap * 13a6d42e7dSPeter Dunlap * When distributing Covered Code, include this CDDL HEADER in each 14a6d42e7dSPeter Dunlap * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15a6d42e7dSPeter Dunlap * If applicable, add the following below this CDDL HEADER, with the 16a6d42e7dSPeter Dunlap * fields enclosed by brackets "[]" replaced with your own identifying 17a6d42e7dSPeter Dunlap * information: Portions Copyright [yyyy] [name of copyright owner] 18a6d42e7dSPeter Dunlap * 19a6d42e7dSPeter Dunlap * CDDL HEADER END 20a6d42e7dSPeter Dunlap */ 21a6d42e7dSPeter Dunlap /* 22*e97fb153SPeter Cudhea - Sun Microsystems - Burlington, MA United States * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23a6d42e7dSPeter Dunlap * Use is subject to license terms. 24a6d42e7dSPeter Dunlap */ 25a6d42e7dSPeter Dunlap 26a6d42e7dSPeter Dunlap #include <sys/conf.h> 27a6d42e7dSPeter Dunlap #include <sys/stat.h> 28a6d42e7dSPeter Dunlap #include <sys/file.h> 29a6d42e7dSPeter Dunlap #include <sys/ddi.h> 30a6d42e7dSPeter Dunlap #include <sys/sunddi.h> 31a6d42e7dSPeter Dunlap #include <sys/modctl.h> 32a6d42e7dSPeter Dunlap #include <sys/priv.h> 33a6d42e7dSPeter Dunlap #include <sys/cpuvar.h> 34a6d42e7dSPeter Dunlap #include <sys/socket.h> 35a6d42e7dSPeter Dunlap #include <sys/strsubr.h> 36a6d42e7dSPeter Dunlap #include <sys/sysmacros.h> 37a6d42e7dSPeter Dunlap #include <sys/sdt.h> 38a6d42e7dSPeter Dunlap #include <netinet/tcp.h> 39a6d42e7dSPeter Dunlap #include <inet/tcp.h> 40a6d42e7dSPeter Dunlap #include <sys/socketvar.h> 41a6d42e7dSPeter Dunlap #include <sys/pathname.h> 42a6d42e7dSPeter Dunlap #include <sys/fs/snode.h> 43a6d42e7dSPeter Dunlap #include <sys/fs/dv_node.h> 44a6d42e7dSPeter Dunlap #include <sys/vnode.h> 45a6d42e7dSPeter Dunlap #include <netinet/in.h> 46a6d42e7dSPeter Dunlap #include <net/if.h> 47a6d42e7dSPeter Dunlap #include <sys/sockio.h> 480f1702c5SYu Xiangning #include <sys/ksocket.h> 49bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States #include <sys/filio.h> /* FIONBIO */ 5056261083SCharles Ting #include <sys/iscsi_protocol.h> 51a6d42e7dSPeter Dunlap #include <sys/idm/idm.h> 52a6d42e7dSPeter Dunlap #include <sys/idm/idm_so.h> 53a6d42e7dSPeter Dunlap #include <sys/idm/idm_text.h> 54a6d42e7dSPeter Dunlap 55aff4bce5Syi zhang - Sun Microsystems - Beijing China #define IN_PROGRESS_DELAY 1 56aff4bce5Syi zhang - Sun Microsystems - Beijing China 57a6d42e7dSPeter Dunlap /* 58a6d42e7dSPeter Dunlap * in6addr_any is currently all zeroes, but use the macro in case this 59a6d42e7dSPeter Dunlap * ever changes. 60a6d42e7dSPeter Dunlap */ 61e42a0851Speter dunlap static const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; 62a6d42e7dSPeter Dunlap 63a6d42e7dSPeter Dunlap static void idm_sorx_cache_pdu_cb(idm_pdu_t *pdu, idm_status_t status); 64a6d42e7dSPeter Dunlap static void idm_sorx_addl_pdu_cb(idm_pdu_t *pdu, idm_status_t status); 65a6d42e7dSPeter Dunlap static void idm_sotx_cache_pdu_cb(idm_pdu_t *pdu, idm_status_t status); 66a6d42e7dSPeter Dunlap 670f1702c5SYu Xiangning static idm_status_t idm_so_conn_create_common(idm_conn_t *ic, ksocket_t new_so); 68a6d42e7dSPeter Dunlap static void idm_so_conn_destroy_common(idm_conn_t *ic); 69a6d42e7dSPeter Dunlap static void idm_so_conn_connect_common(idm_conn_t *ic); 70a6d42e7dSPeter Dunlap 71dedec472SJack Meng static void idm_set_ini_preconnect_options(idm_so_conn_t *sc, 72dedec472SJack Meng boolean_t boot_conn); 73a6d42e7dSPeter Dunlap static void idm_set_ini_postconnect_options(idm_so_conn_t *sc); 740f1702c5SYu Xiangning static void idm_set_tgt_connect_options(ksocket_t so); 75a6d42e7dSPeter Dunlap static idm_status_t idm_i_so_tx(idm_pdu_t *pdu); 76a6d42e7dSPeter Dunlap 77a6d42e7dSPeter Dunlap static idm_status_t idm_sorecvdata(idm_conn_t *ic, idm_pdu_t *pdu); 7830e7468fSPeter Dunlap static void idm_so_send_rtt_data(idm_conn_t *ic, idm_task_t *idt, 7930e7468fSPeter Dunlap idm_buf_t *idb, uint32_t offset, uint32_t length); 8030e7468fSPeter Dunlap static void idm_so_send_rtt_data_done(idm_task_t *idt, idm_buf_t *idb); 8130e7468fSPeter Dunlap static idm_status_t idm_so_send_buf_region(idm_task_t *idt, 82a6d42e7dSPeter Dunlap idm_buf_t *idb, uint32_t buf_region_offset, uint32_t buf_region_length); 83a6d42e7dSPeter Dunlap 84a6d42e7dSPeter Dunlap static uint32_t idm_fill_iov(idm_pdu_t *pdu, idm_buf_t *idb, 85a6d42e7dSPeter Dunlap uint32_t ro, uint32_t dlength); 86a6d42e7dSPeter Dunlap 87a6d42e7dSPeter Dunlap static idm_status_t idm_so_handle_digest(idm_conn_t *it, 88a6d42e7dSPeter Dunlap nvpair_t *digest_choice, const idm_kv_xlate_t *ikvx); 89a6d42e7dSPeter Dunlap 90aff4bce5Syi zhang - Sun Microsystems - Beijing China static void idm_so_socket_set_nonblock(struct sonode *node); 91aff4bce5Syi zhang - Sun Microsystems - Beijing China static void idm_so_socket_set_block(struct sonode *node); 92aff4bce5Syi zhang - Sun Microsystems - Beijing China 93a6d42e7dSPeter Dunlap /* 94a6d42e7dSPeter Dunlap * Transport ops prototypes 95a6d42e7dSPeter Dunlap */ 96a6d42e7dSPeter Dunlap static void idm_so_tx(idm_conn_t *ic, idm_pdu_t *pdu); 97a6d42e7dSPeter Dunlap static idm_status_t idm_so_buf_tx_to_ini(idm_task_t *idt, idm_buf_t *idb); 98a6d42e7dSPeter Dunlap static idm_status_t idm_so_buf_rx_from_ini(idm_task_t *idt, idm_buf_t *idb); 99a6d42e7dSPeter Dunlap static void idm_so_rx_datain(idm_conn_t *ic, idm_pdu_t *pdu); 100a6d42e7dSPeter Dunlap static void idm_so_rx_rtt(idm_conn_t *ic, idm_pdu_t *pdu); 101a6d42e7dSPeter Dunlap static void idm_so_rx_dataout(idm_conn_t *ic, idm_pdu_t *pdu); 102a6d42e7dSPeter Dunlap static idm_status_t idm_so_free_task_rsrc(idm_task_t *idt); 103a6d42e7dSPeter Dunlap static kv_status_t idm_so_negotiate_key_values(idm_conn_t *it, 104a6d42e7dSPeter Dunlap nvlist_t *request_nvl, nvlist_t *response_nvl, nvlist_t *negotiated_nvl); 10530e7468fSPeter Dunlap static void idm_so_notice_key_values(idm_conn_t *it, 106a6d42e7dSPeter Dunlap nvlist_t *negotiated_nvl); 10756261083SCharles Ting static kv_status_t idm_so_declare_key_values(idm_conn_t *it, 10856261083SCharles Ting nvlist_t *config_nvl, nvlist_t *outgoing_nvl); 109a6d42e7dSPeter Dunlap static boolean_t idm_so_conn_is_capable(idm_conn_req_t *ic, 110a6d42e7dSPeter Dunlap idm_transport_caps_t *caps); 111a6d42e7dSPeter Dunlap static idm_status_t idm_so_buf_alloc(idm_buf_t *idb, uint64_t buflen); 112a6d42e7dSPeter Dunlap static void idm_so_buf_free(idm_buf_t *idb); 113a6d42e7dSPeter Dunlap static idm_status_t idm_so_buf_setup(idm_buf_t *idb); 114a6d42e7dSPeter Dunlap static void idm_so_buf_teardown(idm_buf_t *idb); 115a6d42e7dSPeter Dunlap static idm_status_t idm_so_tgt_svc_create(idm_svc_req_t *sr, idm_svc_t *is); 116a6d42e7dSPeter Dunlap static void idm_so_tgt_svc_destroy(idm_svc_t *is); 117a6d42e7dSPeter Dunlap static idm_status_t idm_so_tgt_svc_online(idm_svc_t *is); 118a6d42e7dSPeter Dunlap static void idm_so_tgt_svc_offline(idm_svc_t *is); 119a6d42e7dSPeter Dunlap static void idm_so_tgt_conn_destroy(idm_conn_t *ic); 120a6d42e7dSPeter Dunlap static idm_status_t idm_so_tgt_conn_connect(idm_conn_t *ic); 121a6d42e7dSPeter Dunlap static void idm_so_conn_disconnect(idm_conn_t *ic); 122a6d42e7dSPeter Dunlap static idm_status_t idm_so_ini_conn_create(idm_conn_req_t *cr, idm_conn_t *ic); 123a6d42e7dSPeter Dunlap static void idm_so_ini_conn_destroy(idm_conn_t *ic); 124a6d42e7dSPeter Dunlap static idm_status_t idm_so_ini_conn_connect(idm_conn_t *ic); 125a6d42e7dSPeter Dunlap 126a6d42e7dSPeter Dunlap /* 127a6d42e7dSPeter Dunlap * IDM Native Sockets transport operations 128a6d42e7dSPeter Dunlap */ 129a6d42e7dSPeter Dunlap static 130a6d42e7dSPeter Dunlap idm_transport_ops_t idm_so_transport_ops = { 131a6d42e7dSPeter Dunlap idm_so_tx, /* it_tx_pdu */ 132a6d42e7dSPeter Dunlap idm_so_buf_tx_to_ini, /* it_buf_tx_to_ini */ 133a6d42e7dSPeter Dunlap idm_so_buf_rx_from_ini, /* it_buf_rx_from_ini */ 134a6d42e7dSPeter Dunlap idm_so_rx_datain, /* it_rx_datain */ 135a6d42e7dSPeter Dunlap idm_so_rx_rtt, /* it_rx_rtt */ 136a6d42e7dSPeter Dunlap idm_so_rx_dataout, /* it_rx_dataout */ 137a6d42e7dSPeter Dunlap NULL, /* it_alloc_conn_rsrc */ 138a6d42e7dSPeter Dunlap NULL, /* it_free_conn_rsrc */ 139a6d42e7dSPeter Dunlap NULL, /* it_tgt_enable_datamover */ 140a6d42e7dSPeter Dunlap NULL, /* it_ini_enable_datamover */ 141a6d42e7dSPeter Dunlap NULL, /* it_conn_terminate */ 142a6d42e7dSPeter Dunlap idm_so_free_task_rsrc, /* it_free_task_rsrc */ 143a6d42e7dSPeter Dunlap idm_so_negotiate_key_values, /* it_negotiate_key_values */ 144a6d42e7dSPeter Dunlap idm_so_notice_key_values, /* it_notice_key_values */ 145a6d42e7dSPeter Dunlap idm_so_conn_is_capable, /* it_conn_is_capable */ 146a6d42e7dSPeter Dunlap idm_so_buf_alloc, /* it_buf_alloc */ 147a6d42e7dSPeter Dunlap idm_so_buf_free, /* it_buf_free */ 148a6d42e7dSPeter Dunlap idm_so_buf_setup, /* it_buf_setup */ 149a6d42e7dSPeter Dunlap idm_so_buf_teardown, /* it_buf_teardown */ 150a6d42e7dSPeter Dunlap idm_so_tgt_svc_create, /* it_tgt_svc_create */ 151a6d42e7dSPeter Dunlap idm_so_tgt_svc_destroy, /* it_tgt_svc_destroy */ 152a6d42e7dSPeter Dunlap idm_so_tgt_svc_online, /* it_tgt_svc_online */ 153a6d42e7dSPeter Dunlap idm_so_tgt_svc_offline, /* it_tgt_svc_offline */ 154a6d42e7dSPeter Dunlap idm_so_tgt_conn_destroy, /* it_tgt_conn_destroy */ 155a6d42e7dSPeter Dunlap idm_so_tgt_conn_connect, /* it_tgt_conn_connect */ 156a6d42e7dSPeter Dunlap idm_so_conn_disconnect, /* it_tgt_conn_disconnect */ 157a6d42e7dSPeter Dunlap idm_so_ini_conn_create, /* it_ini_conn_create */ 158a6d42e7dSPeter Dunlap idm_so_ini_conn_destroy, /* it_ini_conn_destroy */ 159a6d42e7dSPeter Dunlap idm_so_ini_conn_connect, /* it_ini_conn_connect */ 16056261083SCharles Ting idm_so_conn_disconnect, /* it_ini_conn_disconnect */ 16156261083SCharles Ting idm_so_declare_key_values /* it_declare_key_values */ 162a6d42e7dSPeter Dunlap }; 163a6d42e7dSPeter Dunlap 164bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States kmutex_t idm_so_timed_socket_mutex; 165a6d42e7dSPeter Dunlap /* 166a6d42e7dSPeter Dunlap * idm_so_init() 167a6d42e7dSPeter Dunlap * Sockets transport initialization 168a6d42e7dSPeter Dunlap */ 169a6d42e7dSPeter Dunlap void 170a6d42e7dSPeter Dunlap idm_so_init(idm_transport_t *it) 171a6d42e7dSPeter Dunlap { 172a6d42e7dSPeter Dunlap /* Cache for IDM Data and R2T Transmit PDU's */ 173a6d42e7dSPeter Dunlap idm.idm_sotx_pdu_cache = kmem_cache_create("idm_tx_pdu_cache", 174a6d42e7dSPeter Dunlap sizeof (idm_pdu_t) + sizeof (iscsi_hdr_t), 8, 175a6d42e7dSPeter Dunlap &idm_sotx_pdu_constructor, NULL, NULL, NULL, NULL, KM_SLEEP); 176a6d42e7dSPeter Dunlap 177a6d42e7dSPeter Dunlap /* Cache for IDM Receive PDU's */ 178a6d42e7dSPeter Dunlap idm.idm_sorx_pdu_cache = kmem_cache_create("idm_rx_pdu_cache", 179a6d42e7dSPeter Dunlap sizeof (idm_pdu_t) + IDM_SORX_CACHE_HDRLEN, 8, 180a6d42e7dSPeter Dunlap &idm_sorx_pdu_constructor, NULL, NULL, NULL, NULL, KM_SLEEP); 181a6d42e7dSPeter Dunlap 182cf8c0ebaSPeter Dunlap /* 128k buffer cache */ 183cf8c0ebaSPeter Dunlap idm.idm_so_128k_buf_cache = kmem_cache_create("idm_128k_buf_cache", 184cf8c0ebaSPeter Dunlap IDM_SO_BUF_CACHE_UB, 8, NULL, NULL, NULL, NULL, NULL, KM_SLEEP); 185cf8c0ebaSPeter Dunlap 186a6d42e7dSPeter Dunlap /* Set the sockets transport ops */ 187a6d42e7dSPeter Dunlap it->it_ops = &idm_so_transport_ops; 188bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 189bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States mutex_init(&idm_so_timed_socket_mutex, NULL, MUTEX_DEFAULT, NULL); 190bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 191a6d42e7dSPeter Dunlap } 192a6d42e7dSPeter Dunlap 193a6d42e7dSPeter Dunlap /* 194a6d42e7dSPeter Dunlap * idm_so_fini() 195a6d42e7dSPeter Dunlap * Sockets transport teardown 196a6d42e7dSPeter Dunlap */ 197a6d42e7dSPeter Dunlap void 198a6d42e7dSPeter Dunlap idm_so_fini(void) 199a6d42e7dSPeter Dunlap { 200cf8c0ebaSPeter Dunlap kmem_cache_destroy(idm.idm_so_128k_buf_cache); 201a6d42e7dSPeter Dunlap kmem_cache_destroy(idm.idm_sotx_pdu_cache); 202a6d42e7dSPeter Dunlap kmem_cache_destroy(idm.idm_sorx_pdu_cache); 203bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States mutex_destroy(&idm_so_timed_socket_mutex); 204a6d42e7dSPeter Dunlap } 205a6d42e7dSPeter Dunlap 2060f1702c5SYu Xiangning ksocket_t 207a6d42e7dSPeter Dunlap idm_socreate(int domain, int type, int protocol) 208a6d42e7dSPeter Dunlap { 2090f1702c5SYu Xiangning ksocket_t ks; 210a6d42e7dSPeter Dunlap 2110f1702c5SYu Xiangning if (!ksocket_socket(&ks, domain, type, protocol, KSOCKET_NOSLEEP, 2120f1702c5SYu Xiangning CRED())) { 2130f1702c5SYu Xiangning return (ks); 2140f1702c5SYu Xiangning } else { 2150f1702c5SYu Xiangning return (NULL); 216a6d42e7dSPeter Dunlap } 217a6d42e7dSPeter Dunlap } 218a6d42e7dSPeter Dunlap 219a6d42e7dSPeter Dunlap /* 220a6d42e7dSPeter Dunlap * idm_soshutdown will disconnect the socket and prevent subsequent PDU 221a6d42e7dSPeter Dunlap * reception and transmission. The sonode still exists but its state 222a6d42e7dSPeter Dunlap * gets modified to indicate it is no longer connected. Calls to 223a6d42e7dSPeter Dunlap * idm_sorecv/idm_iov_sorecv will return so idm_soshutdown can be used 224a6d42e7dSPeter Dunlap * regain control of a thread stuck in idm_sorecv. 225a6d42e7dSPeter Dunlap */ 226a6d42e7dSPeter Dunlap void 2270f1702c5SYu Xiangning idm_soshutdown(ksocket_t so) 228a6d42e7dSPeter Dunlap { 2290f1702c5SYu Xiangning (void) ksocket_shutdown(so, SHUT_RDWR, CRED()); 230a6d42e7dSPeter Dunlap } 231a6d42e7dSPeter Dunlap 232a6d42e7dSPeter Dunlap /* 233a6d42e7dSPeter Dunlap * idm_sodestroy releases all resources associated with a socket previously 234a6d42e7dSPeter Dunlap * created with idm_socreate. The socket must be shutdown using 235a6d42e7dSPeter Dunlap * idm_soshutdown before the socket is destroyed with idm_sodestroy, 236a6d42e7dSPeter Dunlap * otherwise undefined behavior will result. 237a6d42e7dSPeter Dunlap */ 238a6d42e7dSPeter Dunlap void 2390f1702c5SYu Xiangning idm_sodestroy(ksocket_t ks) 240a6d42e7dSPeter Dunlap { 2410f1702c5SYu Xiangning (void) ksocket_close(ks, CRED()); 242a6d42e7dSPeter Dunlap } 243a6d42e7dSPeter Dunlap 244e42a0851Speter dunlap /* 245e42a0851Speter dunlap * Function to compare two addresses in sockaddr_storage format 246e42a0851Speter dunlap */ 247e42a0851Speter dunlap 248e42a0851Speter dunlap int 249e42a0851Speter dunlap idm_ss_compare(const struct sockaddr_storage *cmp_ss1, 250e42a0851Speter dunlap const struct sockaddr_storage *cmp_ss2, 251bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States boolean_t v4_mapped_as_v4, 252bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States boolean_t compare_ports) 253e42a0851Speter dunlap { 254e42a0851Speter dunlap struct sockaddr_storage mapped_v4_ss1, mapped_v4_ss2; 255e42a0851Speter dunlap const struct sockaddr_storage *ss1, *ss2; 256e42a0851Speter dunlap struct in_addr *in1, *in2; 257e42a0851Speter dunlap struct in6_addr *in61, *in62; 258e42a0851Speter dunlap int i; 259e42a0851Speter dunlap 260e42a0851Speter dunlap /* 261e42a0851Speter dunlap * Normalize V4-mapped IPv6 addresses into V4 format if 262e42a0851Speter dunlap * v4_mapped_as_v4 is B_TRUE. 263e42a0851Speter dunlap */ 264e42a0851Speter dunlap ss1 = cmp_ss1; 265e42a0851Speter dunlap ss2 = cmp_ss2; 266e42a0851Speter dunlap if (v4_mapped_as_v4 && (ss1->ss_family == AF_INET6)) { 267e42a0851Speter dunlap in61 = &((struct sockaddr_in6 *)ss1)->sin6_addr; 268e42a0851Speter dunlap if (IN6_IS_ADDR_V4MAPPED(in61)) { 269e42a0851Speter dunlap bzero(&mapped_v4_ss1, sizeof (mapped_v4_ss1)); 270e42a0851Speter dunlap mapped_v4_ss1.ss_family = AF_INET; 271e42a0851Speter dunlap ((struct sockaddr_in *)&mapped_v4_ss1)->sin_port = 272e42a0851Speter dunlap ((struct sockaddr_in *)ss1)->sin_port; 273e42a0851Speter dunlap IN6_V4MAPPED_TO_INADDR(in61, 274e42a0851Speter dunlap &((struct sockaddr_in *)&mapped_v4_ss1)->sin_addr); 275e42a0851Speter dunlap ss1 = &mapped_v4_ss1; 276e42a0851Speter dunlap } 277e42a0851Speter dunlap } 278e42a0851Speter dunlap ss2 = cmp_ss2; 279e42a0851Speter dunlap if (v4_mapped_as_v4 && (ss2->ss_family == AF_INET6)) { 280e42a0851Speter dunlap in62 = &((struct sockaddr_in6 *)ss2)->sin6_addr; 281e42a0851Speter dunlap if (IN6_IS_ADDR_V4MAPPED(in62)) { 282e42a0851Speter dunlap bzero(&mapped_v4_ss2, sizeof (mapped_v4_ss2)); 283e42a0851Speter dunlap mapped_v4_ss2.ss_family = AF_INET; 284e42a0851Speter dunlap ((struct sockaddr_in *)&mapped_v4_ss2)->sin_port = 285e42a0851Speter dunlap ((struct sockaddr_in *)ss2)->sin_port; 286e42a0851Speter dunlap IN6_V4MAPPED_TO_INADDR(in62, 287e42a0851Speter dunlap &((struct sockaddr_in *)&mapped_v4_ss2)->sin_addr); 288e42a0851Speter dunlap ss2 = &mapped_v4_ss2; 289e42a0851Speter dunlap } 290e42a0851Speter dunlap } 291e42a0851Speter dunlap 292e42a0851Speter dunlap /* 293e42a0851Speter dunlap * Compare ports, then address family, then ip address 294e42a0851Speter dunlap */ 295bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States if (compare_ports && 296bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States (((struct sockaddr_in *)ss1)->sin_port != 297bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States ((struct sockaddr_in *)ss2)->sin_port)) { 298e42a0851Speter dunlap if (((struct sockaddr_in *)ss1)->sin_port > 299e42a0851Speter dunlap ((struct sockaddr_in *)ss2)->sin_port) 300e42a0851Speter dunlap return (1); 301e42a0851Speter dunlap else 302e42a0851Speter dunlap return (-1); 303e42a0851Speter dunlap } 304e42a0851Speter dunlap 305e42a0851Speter dunlap /* 306e42a0851Speter dunlap * ports are the same 307e42a0851Speter dunlap */ 308e42a0851Speter dunlap if (ss1->ss_family != ss2->ss_family) { 309e42a0851Speter dunlap if (ss1->ss_family == AF_INET) 310e42a0851Speter dunlap return (1); 311e42a0851Speter dunlap else 312e42a0851Speter dunlap return (-1); 313e42a0851Speter dunlap } 314e42a0851Speter dunlap 315e42a0851Speter dunlap /* 316e42a0851Speter dunlap * address families are the same 317e42a0851Speter dunlap */ 318e42a0851Speter dunlap if (ss1->ss_family == AF_INET) { 319e42a0851Speter dunlap in1 = &((struct sockaddr_in *)ss1)->sin_addr; 320e42a0851Speter dunlap in2 = &((struct sockaddr_in *)ss2)->sin_addr; 321e42a0851Speter dunlap 322e42a0851Speter dunlap if (in1->s_addr > in2->s_addr) 323e42a0851Speter dunlap return (1); 324e42a0851Speter dunlap else if (in1->s_addr < in2->s_addr) 325e42a0851Speter dunlap return (-1); 326e42a0851Speter dunlap else 327e42a0851Speter dunlap return (0); 328e42a0851Speter dunlap } else if (ss1->ss_family == AF_INET6) { 329e42a0851Speter dunlap in61 = &((struct sockaddr_in6 *)ss1)->sin6_addr; 330e42a0851Speter dunlap in62 = &((struct sockaddr_in6 *)ss2)->sin6_addr; 331e42a0851Speter dunlap 332e42a0851Speter dunlap for (i = 0; i < 4; i++) { 333e42a0851Speter dunlap if (in61->s6_addr32[i] > in62->s6_addr32[i]) 334e42a0851Speter dunlap return (1); 335e42a0851Speter dunlap else if (in61->s6_addr32[i] < in62->s6_addr32[i]) 336e42a0851Speter dunlap return (-1); 337e42a0851Speter dunlap } 338e42a0851Speter dunlap return (0); 339e42a0851Speter dunlap } 340e42a0851Speter dunlap 341e42a0851Speter dunlap return (1); 342e42a0851Speter dunlap } 343e42a0851Speter dunlap 344a6d42e7dSPeter Dunlap /* 345a6d42e7dSPeter Dunlap * IP address filter functions to flag addresses that should not 346a6d42e7dSPeter Dunlap * go out to initiators through discovery. 347a6d42e7dSPeter Dunlap */ 348a6d42e7dSPeter Dunlap static boolean_t 349a6d42e7dSPeter Dunlap idm_v4_addr_okay(struct in_addr *in_addr) 350a6d42e7dSPeter Dunlap { 351a6d42e7dSPeter Dunlap in_addr_t addr = ntohl(in_addr->s_addr); 352a6d42e7dSPeter Dunlap 353a6d42e7dSPeter Dunlap if ((INADDR_NONE == addr) || 354a6d42e7dSPeter Dunlap (IN_MULTICAST(addr)) || 355a6d42e7dSPeter Dunlap ((addr >> IN_CLASSA_NSHIFT) == 0) || 356a6d42e7dSPeter Dunlap ((addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)) { 357a6d42e7dSPeter Dunlap return (B_FALSE); 358a6d42e7dSPeter Dunlap } 359a6d42e7dSPeter Dunlap return (B_TRUE); 360a6d42e7dSPeter Dunlap } 361a6d42e7dSPeter Dunlap 362a6d42e7dSPeter Dunlap static boolean_t 363a6d42e7dSPeter Dunlap idm_v6_addr_okay(struct in6_addr *addr6) 364a6d42e7dSPeter Dunlap { 365a6d42e7dSPeter Dunlap 366a6d42e7dSPeter Dunlap if ((IN6_IS_ADDR_UNSPECIFIED(addr6)) || 367a6d42e7dSPeter Dunlap (IN6_IS_ADDR_LOOPBACK(addr6)) || 368a6d42e7dSPeter Dunlap (IN6_IS_ADDR_MULTICAST(addr6)) || 369a6d42e7dSPeter Dunlap (IN6_IS_ADDR_V4MAPPED(addr6)) || 370a6d42e7dSPeter Dunlap (IN6_IS_ADDR_V4COMPAT(addr6)) || 371a6d42e7dSPeter Dunlap (IN6_IS_ADDR_LINKLOCAL(addr6))) { 372a6d42e7dSPeter Dunlap return (B_FALSE); 373a6d42e7dSPeter Dunlap } 374a6d42e7dSPeter Dunlap return (B_TRUE); 375a6d42e7dSPeter Dunlap } 376a6d42e7dSPeter Dunlap 377a6d42e7dSPeter Dunlap /* 378a6d42e7dSPeter Dunlap * idm_get_ipaddr will retrieve a list of IP Addresses which the host is 379a6d42e7dSPeter Dunlap * configured with by sending down a sequence of kernel ioctl to IP STREAMS. 380a6d42e7dSPeter Dunlap */ 381a6d42e7dSPeter Dunlap int 382a6d42e7dSPeter Dunlap idm_get_ipaddr(idm_addr_list_t **ipaddr_p) 383a6d42e7dSPeter Dunlap { 3840f1702c5SYu Xiangning ksocket_t so4, so6; 385a6d42e7dSPeter Dunlap struct lifnum lifn; 386a6d42e7dSPeter Dunlap struct lifconf lifc; 387a6d42e7dSPeter Dunlap struct lifreq *lp; 388a6d42e7dSPeter Dunlap int rval; 389a6d42e7dSPeter Dunlap int numifs; 390a6d42e7dSPeter Dunlap int bufsize; 391a6d42e7dSPeter Dunlap void *buf; 392a6d42e7dSPeter Dunlap int i, j, n, rc; 393a6d42e7dSPeter Dunlap struct sockaddr_storage ss; 394a6d42e7dSPeter Dunlap struct sockaddr_in *sin; 395a6d42e7dSPeter Dunlap struct sockaddr_in6 *sin6; 396a6d42e7dSPeter Dunlap idm_addr_t *ip; 397fcc214c3SCharles Ting idm_addr_list_t *ipaddr = NULL; 398a6d42e7dSPeter Dunlap int size_ipaddr; 399a6d42e7dSPeter Dunlap 400a6d42e7dSPeter Dunlap *ipaddr_p = NULL; 401a6d42e7dSPeter Dunlap size_ipaddr = 0; 402a6d42e7dSPeter Dunlap buf = NULL; 403a6d42e7dSPeter Dunlap 404a6d42e7dSPeter Dunlap /* create an ipv4 and ipv6 UDP socket */ 405a6d42e7dSPeter Dunlap if ((so6 = idm_socreate(PF_INET6, SOCK_DGRAM, 0)) == NULL) 406a6d42e7dSPeter Dunlap return (0); 407a6d42e7dSPeter Dunlap if ((so4 = idm_socreate(PF_INET, SOCK_DGRAM, 0)) == NULL) { 408a6d42e7dSPeter Dunlap idm_sodestroy(so6); 409a6d42e7dSPeter Dunlap return (0); 410a6d42e7dSPeter Dunlap } 411a6d42e7dSPeter Dunlap 412a6d42e7dSPeter Dunlap 413a6d42e7dSPeter Dunlap retry_count: 414a6d42e7dSPeter Dunlap /* snapshot the current number of interfaces */ 415a6d42e7dSPeter Dunlap lifn.lifn_family = PF_UNSPEC; 416a6d42e7dSPeter Dunlap lifn.lifn_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES; 417a6d42e7dSPeter Dunlap lifn.lifn_count = 0; 4180f1702c5SYu Xiangning /* use vp6 for ioctls with unspecified families by default */ 4190f1702c5SYu Xiangning if (ksocket_ioctl(so6, SIOCGLIFNUM, (intptr_t)&lifn, &rval, CRED()) 4200f1702c5SYu Xiangning != 0) { 421a6d42e7dSPeter Dunlap goto cleanup; 422a6d42e7dSPeter Dunlap } 423a6d42e7dSPeter Dunlap 424a6d42e7dSPeter Dunlap numifs = lifn.lifn_count; 425a6d42e7dSPeter Dunlap if (numifs <= 0) { 426a6d42e7dSPeter Dunlap goto cleanup; 427a6d42e7dSPeter Dunlap } 428a6d42e7dSPeter Dunlap 429a6d42e7dSPeter Dunlap /* allocate extra room in case more interfaces appear */ 430a6d42e7dSPeter Dunlap numifs += 10; 431a6d42e7dSPeter Dunlap 432a6d42e7dSPeter Dunlap /* get the interface names and ip addresses */ 433a6d42e7dSPeter Dunlap bufsize = numifs * sizeof (struct lifreq); 434a6d42e7dSPeter Dunlap buf = kmem_alloc(bufsize, KM_SLEEP); 435a6d42e7dSPeter Dunlap 436a6d42e7dSPeter Dunlap lifc.lifc_family = AF_UNSPEC; 437a6d42e7dSPeter Dunlap lifc.lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES; 438a6d42e7dSPeter Dunlap lifc.lifc_len = bufsize; 439a6d42e7dSPeter Dunlap lifc.lifc_buf = buf; 4400f1702c5SYu Xiangning rc = ksocket_ioctl(so6, SIOCGLIFCONF, (intptr_t)&lifc, &rval, CRED()); 441a6d42e7dSPeter Dunlap if (rc != 0) { 442a6d42e7dSPeter Dunlap goto cleanup; 443a6d42e7dSPeter Dunlap } 444a6d42e7dSPeter Dunlap /* if our extra room is used up, try again */ 445a6d42e7dSPeter Dunlap if (bufsize <= lifc.lifc_len) { 446a6d42e7dSPeter Dunlap kmem_free(buf, bufsize); 447a6d42e7dSPeter Dunlap buf = NULL; 448a6d42e7dSPeter Dunlap goto retry_count; 449a6d42e7dSPeter Dunlap } 450a6d42e7dSPeter Dunlap /* calc actual number of ifconfs */ 451a6d42e7dSPeter Dunlap n = lifc.lifc_len / sizeof (struct lifreq); 452a6d42e7dSPeter Dunlap 453a6d42e7dSPeter Dunlap /* get ip address */ 454a6d42e7dSPeter Dunlap if (n > 0) { 455a6d42e7dSPeter Dunlap size_ipaddr = sizeof (idm_addr_list_t) + 456a6d42e7dSPeter Dunlap (n - 1) * sizeof (idm_addr_t); 457a6d42e7dSPeter Dunlap ipaddr = kmem_zalloc(size_ipaddr, KM_SLEEP); 458a6d42e7dSPeter Dunlap } else { 459a6d42e7dSPeter Dunlap goto cleanup; 460a6d42e7dSPeter Dunlap } 461a6d42e7dSPeter Dunlap 462a6d42e7dSPeter Dunlap /* 463a6d42e7dSPeter Dunlap * Examine the array of interfaces and filter uninteresting ones 464a6d42e7dSPeter Dunlap */ 465a6d42e7dSPeter Dunlap for (i = 0, j = 0, lp = lifc.lifc_req; i < n; i++, lp++) { 466a6d42e7dSPeter Dunlap 467a6d42e7dSPeter Dunlap /* 468a6d42e7dSPeter Dunlap * Copy the address as the SIOCGLIFFLAGS ioctl is destructive 469a6d42e7dSPeter Dunlap */ 470a6d42e7dSPeter Dunlap ss = lp->lifr_addr; 471a6d42e7dSPeter Dunlap /* 472a6d42e7dSPeter Dunlap * fetch the flags using the socket of the correct family 473a6d42e7dSPeter Dunlap */ 474a6d42e7dSPeter Dunlap switch (ss.ss_family) { 475a6d42e7dSPeter Dunlap case AF_INET: 4760f1702c5SYu Xiangning rc = ksocket_ioctl(so4, SIOCGLIFFLAGS, (intptr_t)lp, 4770f1702c5SYu Xiangning &rval, CRED()); 478a6d42e7dSPeter Dunlap break; 479a6d42e7dSPeter Dunlap case AF_INET6: 4800f1702c5SYu Xiangning rc = ksocket_ioctl(so6, SIOCGLIFFLAGS, (intptr_t)lp, 4810f1702c5SYu Xiangning &rval, CRED()); 482a6d42e7dSPeter Dunlap break; 483a6d42e7dSPeter Dunlap default: 484a6d42e7dSPeter Dunlap continue; 485a6d42e7dSPeter Dunlap } 486a6d42e7dSPeter Dunlap if (rc == 0) { 487a6d42e7dSPeter Dunlap /* 488a6d42e7dSPeter Dunlap * If we got the flags, skip uninteresting 489a6d42e7dSPeter Dunlap * interfaces based on flags 490a6d42e7dSPeter Dunlap */ 491a6d42e7dSPeter Dunlap if ((lp->lifr_flags & IFF_UP) != IFF_UP) 492a6d42e7dSPeter Dunlap continue; 493a6d42e7dSPeter Dunlap if (lp->lifr_flags & 494a6d42e7dSPeter Dunlap (IFF_ANYCAST|IFF_NOLOCAL|IFF_DEPRECATED)) 495a6d42e7dSPeter Dunlap continue; 496a6d42e7dSPeter Dunlap } 497a6d42e7dSPeter Dunlap 498a6d42e7dSPeter Dunlap /* save ip address */ 499a6d42e7dSPeter Dunlap ip = &ipaddr->al_addrs[j]; 500a6d42e7dSPeter Dunlap switch (ss.ss_family) { 501a6d42e7dSPeter Dunlap case AF_INET: 502a6d42e7dSPeter Dunlap sin = (struct sockaddr_in *)&ss; 503a6d42e7dSPeter Dunlap if (!idm_v4_addr_okay(&sin->sin_addr)) 504a6d42e7dSPeter Dunlap continue; 505a6d42e7dSPeter Dunlap ip->a_addr.i_addr.in4 = sin->sin_addr; 506a6d42e7dSPeter Dunlap ip->a_addr.i_insize = sizeof (struct in_addr); 507a6d42e7dSPeter Dunlap break; 508a6d42e7dSPeter Dunlap case AF_INET6: 509a6d42e7dSPeter Dunlap sin6 = (struct sockaddr_in6 *)&ss; 510a6d42e7dSPeter Dunlap if (!idm_v6_addr_okay(&sin6->sin6_addr)) 511a6d42e7dSPeter Dunlap continue; 512a6d42e7dSPeter Dunlap ip->a_addr.i_addr.in6 = sin6->sin6_addr; 513a6d42e7dSPeter Dunlap ip->a_addr.i_insize = sizeof (struct in6_addr); 514a6d42e7dSPeter Dunlap break; 515a6d42e7dSPeter Dunlap default: 516a6d42e7dSPeter Dunlap continue; 517a6d42e7dSPeter Dunlap } 518a6d42e7dSPeter Dunlap j++; 519a6d42e7dSPeter Dunlap } 520a6d42e7dSPeter Dunlap 521a6d42e7dSPeter Dunlap if (j == 0) { 522a6d42e7dSPeter Dunlap /* no valid ifaddr */ 523a6d42e7dSPeter Dunlap kmem_free(ipaddr, size_ipaddr); 524a6d42e7dSPeter Dunlap size_ipaddr = 0; 525a6d42e7dSPeter Dunlap ipaddr = NULL; 526a6d42e7dSPeter Dunlap } else { 527a6d42e7dSPeter Dunlap ipaddr->al_out_cnt = j; 528a6d42e7dSPeter Dunlap } 529a6d42e7dSPeter Dunlap 530a6d42e7dSPeter Dunlap 531a6d42e7dSPeter Dunlap cleanup: 532a6d42e7dSPeter Dunlap idm_sodestroy(so6); 533a6d42e7dSPeter Dunlap idm_sodestroy(so4); 534a6d42e7dSPeter Dunlap 535a6d42e7dSPeter Dunlap if (buf != NULL) 536a6d42e7dSPeter Dunlap kmem_free(buf, bufsize); 537a6d42e7dSPeter Dunlap 538a6d42e7dSPeter Dunlap *ipaddr_p = ipaddr; 539a6d42e7dSPeter Dunlap return (size_ipaddr); 540a6d42e7dSPeter Dunlap } 541a6d42e7dSPeter Dunlap 542a6d42e7dSPeter Dunlap int 5430f1702c5SYu Xiangning idm_sorecv(ksocket_t so, void *msg, size_t len) 544a6d42e7dSPeter Dunlap { 545a6d42e7dSPeter Dunlap iovec_t iov; 546a6d42e7dSPeter Dunlap 547a6d42e7dSPeter Dunlap ASSERT(so != NULL); 548a6d42e7dSPeter Dunlap ASSERT(len != 0); 549a6d42e7dSPeter Dunlap 550a6d42e7dSPeter Dunlap /* 551a6d42e7dSPeter Dunlap * Fill in iovec and receive data 552a6d42e7dSPeter Dunlap */ 553a6d42e7dSPeter Dunlap iov.iov_base = msg; 554a6d42e7dSPeter Dunlap iov.iov_len = len; 555a6d42e7dSPeter Dunlap 556a6d42e7dSPeter Dunlap return (idm_iov_sorecv(so, &iov, 1, len)); 557a6d42e7dSPeter Dunlap } 558a6d42e7dSPeter Dunlap 559a6d42e7dSPeter Dunlap /* 560a6d42e7dSPeter Dunlap * idm_sosendto - Sends a buffered data on a non-connected socket. 561a6d42e7dSPeter Dunlap * 562a6d42e7dSPeter Dunlap * This function puts the data provided on the wire by calling sosendmsg. 563a6d42e7dSPeter Dunlap * It will return only when all the data has been sent or if an error 564a6d42e7dSPeter Dunlap * occurs. 565a6d42e7dSPeter Dunlap * 566a6d42e7dSPeter Dunlap * Returns 0 for success, the socket errno value if sosendmsg fails, and 567a6d42e7dSPeter Dunlap * -1 if sosendmsg returns success but uio_resid != 0 568a6d42e7dSPeter Dunlap */ 569a6d42e7dSPeter Dunlap int 5700f1702c5SYu Xiangning idm_sosendto(ksocket_t so, void *buff, size_t len, 571a6d42e7dSPeter Dunlap struct sockaddr *name, socklen_t namelen) 572a6d42e7dSPeter Dunlap { 573a6d42e7dSPeter Dunlap struct msghdr msg; 574a6d42e7dSPeter Dunlap struct iovec iov[1]; 575a6d42e7dSPeter Dunlap int error; 5760f1702c5SYu Xiangning size_t sent = 0; 577a6d42e7dSPeter Dunlap 578a6d42e7dSPeter Dunlap iov[0].iov_base = buff; 579a6d42e7dSPeter Dunlap iov[0].iov_len = len; 580a6d42e7dSPeter Dunlap 581a6d42e7dSPeter Dunlap /* Initialization of the message header. */ 582a6d42e7dSPeter Dunlap bzero(&msg, sizeof (msg)); 583a6d42e7dSPeter Dunlap msg.msg_iov = iov; 584a6d42e7dSPeter Dunlap msg.msg_iovlen = 1; 585a6d42e7dSPeter Dunlap msg.msg_name = name; 586a6d42e7dSPeter Dunlap msg.msg_namelen = namelen; 587a6d42e7dSPeter Dunlap 5880f1702c5SYu Xiangning if ((error = ksocket_sendmsg(so, &msg, 0, &sent, CRED())) == 0) { 589a6d42e7dSPeter Dunlap /* Data sent */ 5900f1702c5SYu Xiangning if (sent == len) { 591a6d42e7dSPeter Dunlap /* All data sent. Success. */ 592a6d42e7dSPeter Dunlap return (0); 593a6d42e7dSPeter Dunlap } else { 594a6d42e7dSPeter Dunlap /* Not all data was sent. Failure */ 595a6d42e7dSPeter Dunlap return (-1); 596a6d42e7dSPeter Dunlap } 597a6d42e7dSPeter Dunlap } 598a6d42e7dSPeter Dunlap 599a6d42e7dSPeter Dunlap /* Send failed */ 600a6d42e7dSPeter Dunlap return (error); 601a6d42e7dSPeter Dunlap } 602a6d42e7dSPeter Dunlap 603a6d42e7dSPeter Dunlap /* 604a6d42e7dSPeter Dunlap * idm_iov_sosend - Sends an iovec on a connection. 605a6d42e7dSPeter Dunlap * 606a6d42e7dSPeter Dunlap * This function puts the data provided on the wire by calling sosendmsg. 607a6d42e7dSPeter Dunlap * It will return only when all the data has been sent or if an error 608a6d42e7dSPeter Dunlap * occurs. 609a6d42e7dSPeter Dunlap * 610a6d42e7dSPeter Dunlap * Returns 0 for success, the socket errno value if sosendmsg fails, and 611a6d42e7dSPeter Dunlap * -1 if sosendmsg returns success but uio_resid != 0 612a6d42e7dSPeter Dunlap */ 613a6d42e7dSPeter Dunlap int 6140f1702c5SYu Xiangning idm_iov_sosend(ksocket_t so, iovec_t *iop, int iovlen, size_t total_len) 615a6d42e7dSPeter Dunlap { 616a6d42e7dSPeter Dunlap struct msghdr msg; 617a6d42e7dSPeter Dunlap int error; 6180f1702c5SYu Xiangning size_t sent = 0; 619a6d42e7dSPeter Dunlap 620a6d42e7dSPeter Dunlap ASSERT(iop != NULL); 621a6d42e7dSPeter Dunlap 622a6d42e7dSPeter Dunlap /* Initialization of the message header. */ 623a6d42e7dSPeter Dunlap bzero(&msg, sizeof (msg)); 624a6d42e7dSPeter Dunlap msg.msg_iov = iop; 625a6d42e7dSPeter Dunlap msg.msg_iovlen = iovlen; 626a6d42e7dSPeter Dunlap 6270f1702c5SYu Xiangning if ((error = ksocket_sendmsg(so, &msg, 0, &sent, CRED())) 6280f1702c5SYu Xiangning == 0) { 629a6d42e7dSPeter Dunlap /* Data sent */ 6300f1702c5SYu Xiangning if (sent == total_len) { 631a6d42e7dSPeter Dunlap /* All data sent. Success. */ 632a6d42e7dSPeter Dunlap return (0); 633a6d42e7dSPeter Dunlap } else { 634a6d42e7dSPeter Dunlap /* Not all data was sent. Failure */ 635a6d42e7dSPeter Dunlap return (-1); 636a6d42e7dSPeter Dunlap } 637a6d42e7dSPeter Dunlap } 638a6d42e7dSPeter Dunlap 639a6d42e7dSPeter Dunlap /* Send failed */ 640a6d42e7dSPeter Dunlap return (error); 641a6d42e7dSPeter Dunlap } 642a6d42e7dSPeter Dunlap 643a6d42e7dSPeter Dunlap /* 644a6d42e7dSPeter Dunlap * idm_iov_sorecv - Receives an iovec from a connection 645a6d42e7dSPeter Dunlap * 646a6d42e7dSPeter Dunlap * This function gets the data asked for from the socket. It will return 647a6d42e7dSPeter Dunlap * only when all the requested data has been retrieved or if an error 648a6d42e7dSPeter Dunlap * occurs. 649a6d42e7dSPeter Dunlap * 650a6d42e7dSPeter Dunlap * Returns 0 for success, the socket errno value if sorecvmsg fails, and 651a6d42e7dSPeter Dunlap * -1 if sorecvmsg returns success but uio_resid != 0 652a6d42e7dSPeter Dunlap */ 653a6d42e7dSPeter Dunlap int 6540f1702c5SYu Xiangning idm_iov_sorecv(ksocket_t so, iovec_t *iop, int iovlen, size_t total_len) 655a6d42e7dSPeter Dunlap { 656a6d42e7dSPeter Dunlap struct msghdr msg; 657a6d42e7dSPeter Dunlap int error; 6580f1702c5SYu Xiangning size_t recv; 6590f1702c5SYu Xiangning int flags; 660a6d42e7dSPeter Dunlap 661a6d42e7dSPeter Dunlap ASSERT(iop != NULL); 662a6d42e7dSPeter Dunlap 663a6d42e7dSPeter Dunlap /* Initialization of the message header. */ 664a6d42e7dSPeter Dunlap bzero(&msg, sizeof (msg)); 665a6d42e7dSPeter Dunlap msg.msg_iov = iop; 666a6d42e7dSPeter Dunlap msg.msg_iovlen = iovlen; 6670f1702c5SYu Xiangning flags = MSG_WAITALL; 668a6d42e7dSPeter Dunlap 6690f1702c5SYu Xiangning if ((error = ksocket_recvmsg(so, &msg, flags, &recv, CRED())) 6700f1702c5SYu Xiangning == 0) { 671a6d42e7dSPeter Dunlap /* Received data */ 6720f1702c5SYu Xiangning if (recv == total_len) { 673a6d42e7dSPeter Dunlap /* All requested data received. Success */ 674a6d42e7dSPeter Dunlap return (0); 675a6d42e7dSPeter Dunlap } else { 676a6d42e7dSPeter Dunlap /* 677a6d42e7dSPeter Dunlap * Not all data was received. The connection has 678a6d42e7dSPeter Dunlap * probably failed. 679a6d42e7dSPeter Dunlap */ 680a6d42e7dSPeter Dunlap return (-1); 681a6d42e7dSPeter Dunlap } 682a6d42e7dSPeter Dunlap } 683a6d42e7dSPeter Dunlap 684a6d42e7dSPeter Dunlap /* Receive failed */ 685a6d42e7dSPeter Dunlap return (error); 686a6d42e7dSPeter Dunlap } 687a6d42e7dSPeter Dunlap 688a6d42e7dSPeter Dunlap static void 689dedec472SJack Meng idm_set_ini_preconnect_options(idm_so_conn_t *sc, boolean_t boot_conn) 690a6d42e7dSPeter Dunlap { 691a6d42e7dSPeter Dunlap int conn_abort = 10000; 692a6d42e7dSPeter Dunlap int conn_notify = 2000; 693a6d42e7dSPeter Dunlap int abort = 30000; 694a6d42e7dSPeter Dunlap 695a6d42e7dSPeter Dunlap /* Pre-connect socket options */ 6960f1702c5SYu Xiangning (void) ksocket_setsockopt(sc->ic_so, IPPROTO_TCP, 6970f1702c5SYu Xiangning TCP_CONN_NOTIFY_THRESHOLD, (char *)&conn_notify, sizeof (int), 6980f1702c5SYu Xiangning CRED()); 699dedec472SJack Meng if (boot_conn == B_FALSE) { 700dedec472SJack Meng (void) ksocket_setsockopt(sc->ic_so, IPPROTO_TCP, 701dedec472SJack Meng TCP_CONN_ABORT_THRESHOLD, (char *)&conn_abort, sizeof (int), 702dedec472SJack Meng CRED()); 703dedec472SJack Meng (void) ksocket_setsockopt(sc->ic_so, IPPROTO_TCP, 704dedec472SJack Meng TCP_ABORT_THRESHOLD, 705dedec472SJack Meng (char *)&abort, sizeof (int), CRED()); 706dedec472SJack Meng } 707a6d42e7dSPeter Dunlap } 708a6d42e7dSPeter Dunlap 709a6d42e7dSPeter Dunlap static void 710a6d42e7dSPeter Dunlap idm_set_ini_postconnect_options(idm_so_conn_t *sc) 711a6d42e7dSPeter Dunlap { 712a6d42e7dSPeter Dunlap int32_t rcvbuf = IDM_RCVBUF_SIZE; 713a6d42e7dSPeter Dunlap int32_t sndbuf = IDM_SNDBUF_SIZE; 714a6d42e7dSPeter Dunlap const int on = 1; 715a6d42e7dSPeter Dunlap 716a6d42e7dSPeter Dunlap /* Set postconnect options */ 7170f1702c5SYu Xiangning (void) ksocket_setsockopt(sc->ic_so, IPPROTO_TCP, TCP_NODELAY, 7180f1702c5SYu Xiangning (char *)&on, sizeof (int), CRED()); 7190f1702c5SYu Xiangning (void) ksocket_setsockopt(sc->ic_so, SOL_SOCKET, SO_RCVBUF, 7200f1702c5SYu Xiangning (char *)&rcvbuf, sizeof (int), CRED()); 7210f1702c5SYu Xiangning (void) ksocket_setsockopt(sc->ic_so, SOL_SOCKET, SO_SNDBUF, 7220f1702c5SYu Xiangning (char *)&sndbuf, sizeof (int), CRED()); 723a6d42e7dSPeter Dunlap } 724a6d42e7dSPeter Dunlap 725a6d42e7dSPeter Dunlap static void 7260f1702c5SYu Xiangning idm_set_tgt_connect_options(ksocket_t ks) 727a6d42e7dSPeter Dunlap { 728a6d42e7dSPeter Dunlap int32_t rcvbuf = IDM_RCVBUF_SIZE; 729a6d42e7dSPeter Dunlap int32_t sndbuf = IDM_SNDBUF_SIZE; 730a6d42e7dSPeter Dunlap const int on = 1; 731a6d42e7dSPeter Dunlap 732a6d42e7dSPeter Dunlap /* Set connect options */ 7330f1702c5SYu Xiangning (void) ksocket_setsockopt(ks, SOL_SOCKET, SO_RCVBUF, 7340f1702c5SYu Xiangning (char *)&rcvbuf, sizeof (int), CRED()); 7350f1702c5SYu Xiangning (void) ksocket_setsockopt(ks, SOL_SOCKET, SO_SNDBUF, 7360f1702c5SYu Xiangning (char *)&sndbuf, sizeof (int), CRED()); 7370f1702c5SYu Xiangning (void) ksocket_setsockopt(ks, IPPROTO_TCP, TCP_NODELAY, 7380f1702c5SYu Xiangning (char *)&on, sizeof (on), CRED()); 739a6d42e7dSPeter Dunlap } 740a6d42e7dSPeter Dunlap 741a6d42e7dSPeter Dunlap static uint32_t 742a6d42e7dSPeter Dunlap n2h24(const uchar_t *ptr) 743a6d42e7dSPeter Dunlap { 744a6d42e7dSPeter Dunlap return ((ptr[0] << 16) | (ptr[1] << 8) | ptr[2]); 745a6d42e7dSPeter Dunlap } 746a6d42e7dSPeter Dunlap 747a6d42e7dSPeter Dunlap 748a6d42e7dSPeter Dunlap static idm_status_t 749a6d42e7dSPeter Dunlap idm_sorecvhdr(idm_conn_t *ic, idm_pdu_t *pdu) 750a6d42e7dSPeter Dunlap { 751a6d42e7dSPeter Dunlap iscsi_hdr_t *bhs; 752a6d42e7dSPeter Dunlap uint32_t hdr_digest_crc; 753a6d42e7dSPeter Dunlap uint32_t crc_calculated; 754a6d42e7dSPeter Dunlap void *new_hdr; 755a6d42e7dSPeter Dunlap int ahslen = 0; 756a6d42e7dSPeter Dunlap int total_len = 0; 757a6d42e7dSPeter Dunlap int iovlen = 0; 758a6d42e7dSPeter Dunlap struct iovec iov[2]; 759a6d42e7dSPeter Dunlap idm_so_conn_t *so_conn; 760a6d42e7dSPeter Dunlap int rc; 761a6d42e7dSPeter Dunlap 762a6d42e7dSPeter Dunlap so_conn = ic->ic_transport_private; 763a6d42e7dSPeter Dunlap 764a6d42e7dSPeter Dunlap /* 765a6d42e7dSPeter Dunlap * Read BHS 766a6d42e7dSPeter Dunlap */ 767a6d42e7dSPeter Dunlap bhs = pdu->isp_hdr; 768a6d42e7dSPeter Dunlap rc = idm_sorecv(so_conn->ic_so, pdu->isp_hdr, sizeof (iscsi_hdr_t)); 769a6d42e7dSPeter Dunlap if (rc != IDM_STATUS_SUCCESS) { 770a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 771a6d42e7dSPeter Dunlap } 772a6d42e7dSPeter Dunlap 773a6d42e7dSPeter Dunlap /* 774a6d42e7dSPeter Dunlap * Check actual AHS length against the amount available in the buffer 775a6d42e7dSPeter Dunlap */ 776a6d42e7dSPeter Dunlap pdu->isp_hdrlen = sizeof (iscsi_hdr_t) + 777a6d42e7dSPeter Dunlap (bhs->hlength * sizeof (uint32_t)); 778a6d42e7dSPeter Dunlap pdu->isp_datalen = n2h24(bhs->dlength); 77956261083SCharles Ting if (ic->ic_conn_type == CONN_TYPE_TGT && 78056261083SCharles Ting pdu->isp_datalen > ic->ic_conn_params.max_recv_dataseglen) { 78156261083SCharles Ting IDM_CONN_LOG(CE_WARN, 78256261083SCharles Ting "idm_sorecvhdr: exceeded the max data segment length"); 78356261083SCharles Ting return (IDM_STATUS_FAIL); 78456261083SCharles Ting } 785a6d42e7dSPeter Dunlap if (bhs->hlength > IDM_SORX_CACHE_AHSLEN) { 786a6d42e7dSPeter Dunlap /* Allocate a new header segment and change the callback */ 787a6d42e7dSPeter Dunlap new_hdr = kmem_alloc(pdu->isp_hdrlen, KM_SLEEP); 788a6d42e7dSPeter Dunlap bcopy(pdu->isp_hdr, new_hdr, sizeof (iscsi_hdr_t)); 789a6d42e7dSPeter Dunlap pdu->isp_hdr = new_hdr; 790a6d42e7dSPeter Dunlap pdu->isp_flags |= IDM_PDU_ADDL_HDR; 791a6d42e7dSPeter Dunlap 792a6d42e7dSPeter Dunlap /* 793a6d42e7dSPeter Dunlap * This callback will restore the expected values after 794a6d42e7dSPeter Dunlap * the RX PDU has been processed. 795a6d42e7dSPeter Dunlap */ 796a6d42e7dSPeter Dunlap pdu->isp_callback = idm_sorx_addl_pdu_cb; 797a6d42e7dSPeter Dunlap } 798a6d42e7dSPeter Dunlap 799a6d42e7dSPeter Dunlap /* 800a6d42e7dSPeter Dunlap * Setup receipt of additional header and header digest (if enabled). 801a6d42e7dSPeter Dunlap */ 802a6d42e7dSPeter Dunlap if (bhs->hlength > 0) { 803a6d42e7dSPeter Dunlap iov[iovlen].iov_base = (caddr_t)(pdu->isp_hdr + 1); 804a6d42e7dSPeter Dunlap ahslen = pdu->isp_hdrlen - sizeof (iscsi_hdr_t); 805a6d42e7dSPeter Dunlap iov[iovlen].iov_len = ahslen; 806a6d42e7dSPeter Dunlap total_len += iov[iovlen].iov_len; 807a6d42e7dSPeter Dunlap iovlen++; 808a6d42e7dSPeter Dunlap } 809a6d42e7dSPeter Dunlap 810a6d42e7dSPeter Dunlap if (ic->ic_conn_flags & IDM_CONN_HEADER_DIGEST) { 811a6d42e7dSPeter Dunlap iov[iovlen].iov_base = (caddr_t)&hdr_digest_crc; 812a6d42e7dSPeter Dunlap iov[iovlen].iov_len = sizeof (hdr_digest_crc); 813a6d42e7dSPeter Dunlap total_len += iov[iovlen].iov_len; 814a6d42e7dSPeter Dunlap iovlen++; 815a6d42e7dSPeter Dunlap } 816a6d42e7dSPeter Dunlap 817a6d42e7dSPeter Dunlap if ((iovlen != 0) && 818a6d42e7dSPeter Dunlap (idm_iov_sorecv(so_conn->ic_so, &iov[0], iovlen, 819a6d42e7dSPeter Dunlap total_len) != 0)) { 820a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 821a6d42e7dSPeter Dunlap } 822a6d42e7dSPeter Dunlap 823a6d42e7dSPeter Dunlap /* 824a6d42e7dSPeter Dunlap * Validate header digest if enabled 825a6d42e7dSPeter Dunlap */ 826a6d42e7dSPeter Dunlap if (ic->ic_conn_flags & IDM_CONN_HEADER_DIGEST) { 827a6d42e7dSPeter Dunlap crc_calculated = idm_crc32c(pdu->isp_hdr, 828a6d42e7dSPeter Dunlap sizeof (iscsi_hdr_t) + ahslen); 829a6d42e7dSPeter Dunlap if (crc_calculated != hdr_digest_crc) { 830a6d42e7dSPeter Dunlap /* Invalid Header Digest */ 831a6d42e7dSPeter Dunlap return (IDM_STATUS_HEADER_DIGEST); 832a6d42e7dSPeter Dunlap } 833a6d42e7dSPeter Dunlap } 834a6d42e7dSPeter Dunlap 835a6d42e7dSPeter Dunlap return (0); 836a6d42e7dSPeter Dunlap } 837a6d42e7dSPeter Dunlap 838a6d42e7dSPeter Dunlap /* 839a6d42e7dSPeter Dunlap * idm_so_ini_conn_create() 840a6d42e7dSPeter Dunlap * Allocate the sockets transport connection resources. 841a6d42e7dSPeter Dunlap */ 842a6d42e7dSPeter Dunlap static idm_status_t 843a6d42e7dSPeter Dunlap idm_so_ini_conn_create(idm_conn_req_t *cr, idm_conn_t *ic) 844a6d42e7dSPeter Dunlap { 8450f1702c5SYu Xiangning ksocket_t so; 846a6d42e7dSPeter Dunlap idm_so_conn_t *so_conn; 847a6d42e7dSPeter Dunlap idm_status_t idmrc; 848a6d42e7dSPeter Dunlap 849a6d42e7dSPeter Dunlap so = idm_socreate(cr->cr_domain, cr->cr_type, 850a6d42e7dSPeter Dunlap cr->cr_protocol); 851a6d42e7dSPeter Dunlap if (so == NULL) { 852a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 853a6d42e7dSPeter Dunlap } 854a6d42e7dSPeter Dunlap 855a6d42e7dSPeter Dunlap /* Bind the socket if configured to do so */ 856a6d42e7dSPeter Dunlap if (cr->cr_bound) { 8570f1702c5SYu Xiangning if (ksocket_bind(so, &cr->cr_bound_addr.sin, 8580f1702c5SYu Xiangning SIZEOF_SOCKADDR(&cr->cr_bound_addr.sin), CRED()) != 0) { 859a6d42e7dSPeter Dunlap idm_sodestroy(so); 860a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 861a6d42e7dSPeter Dunlap } 862a6d42e7dSPeter Dunlap } 863a6d42e7dSPeter Dunlap 864a6d42e7dSPeter Dunlap idmrc = idm_so_conn_create_common(ic, so); 865a6d42e7dSPeter Dunlap if (idmrc != IDM_STATUS_SUCCESS) { 866a6d42e7dSPeter Dunlap idm_soshutdown(so); 867a6d42e7dSPeter Dunlap idm_sodestroy(so); 868a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 869a6d42e7dSPeter Dunlap } 870a6d42e7dSPeter Dunlap 871a6d42e7dSPeter Dunlap so_conn = ic->ic_transport_private; 872a6d42e7dSPeter Dunlap /* Set up socket options */ 873dedec472SJack Meng idm_set_ini_preconnect_options(so_conn, cr->cr_boot_conn); 874a6d42e7dSPeter Dunlap 875a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 876a6d42e7dSPeter Dunlap } 877a6d42e7dSPeter Dunlap 878a6d42e7dSPeter Dunlap /* 879a6d42e7dSPeter Dunlap * idm_so_ini_conn_destroy() 880a6d42e7dSPeter Dunlap * Tear down the sockets transport connection resources. 881a6d42e7dSPeter Dunlap */ 882a6d42e7dSPeter Dunlap static void 883a6d42e7dSPeter Dunlap idm_so_ini_conn_destroy(idm_conn_t *ic) 884a6d42e7dSPeter Dunlap { 885a6d42e7dSPeter Dunlap idm_so_conn_destroy_common(ic); 886a6d42e7dSPeter Dunlap } 887a6d42e7dSPeter Dunlap 888a6d42e7dSPeter Dunlap /* 889a6d42e7dSPeter Dunlap * idm_so_ini_conn_connect() 890a6d42e7dSPeter Dunlap * Establish the connection referred to by the handle previously allocated via 891a6d42e7dSPeter Dunlap * idm_so_ini_conn_create(). 892a6d42e7dSPeter Dunlap */ 893a6d42e7dSPeter Dunlap static idm_status_t 894a6d42e7dSPeter Dunlap idm_so_ini_conn_connect(idm_conn_t *ic) 895a6d42e7dSPeter Dunlap { 896a6d42e7dSPeter Dunlap idm_so_conn_t *so_conn; 897aff4bce5Syi zhang - Sun Microsystems - Beijing China struct sonode *node = NULL; 898aff4bce5Syi zhang - Sun Microsystems - Beijing China int rc; 899aff4bce5Syi zhang - Sun Microsystems - Beijing China clock_t lbolt, conn_login_max, conn_login_interval; 900aff4bce5Syi zhang - Sun Microsystems - Beijing China boolean_t nonblock; 901a6d42e7dSPeter Dunlap 902a6d42e7dSPeter Dunlap so_conn = ic->ic_transport_private; 903aff4bce5Syi zhang - Sun Microsystems - Beijing China nonblock = ic->ic_conn_params.nonblock_socket; 904aff4bce5Syi zhang - Sun Microsystems - Beijing China conn_login_max = ic->ic_conn_params.conn_login_max; 905aff4bce5Syi zhang - Sun Microsystems - Beijing China conn_login_interval = ddi_get_lbolt() + 906aff4bce5Syi zhang - Sun Microsystems - Beijing China SEC_TO_TICK(ic->ic_conn_params.conn_login_interval); 907aff4bce5Syi zhang - Sun Microsystems - Beijing China 908aff4bce5Syi zhang - Sun Microsystems - Beijing China if (nonblock == B_TRUE) { 909aff4bce5Syi zhang - Sun Microsystems - Beijing China node = ((struct sonode *)(so_conn->ic_so)); 910aff4bce5Syi zhang - Sun Microsystems - Beijing China /* Set to none block socket mode */ 911aff4bce5Syi zhang - Sun Microsystems - Beijing China idm_so_socket_set_nonblock(node); 912aff4bce5Syi zhang - Sun Microsystems - Beijing China do { 913aff4bce5Syi zhang - Sun Microsystems - Beijing China rc = ksocket_connect(so_conn->ic_so, 914aff4bce5Syi zhang - Sun Microsystems - Beijing China &ic->ic_ini_dst_addr.sin, 915aff4bce5Syi zhang - Sun Microsystems - Beijing China (SIZEOF_SOCKADDR(&ic->ic_ini_dst_addr.sin)), 916aff4bce5Syi zhang - Sun Microsystems - Beijing China CRED()); 917aff4bce5Syi zhang - Sun Microsystems - Beijing China if (rc == 0 || rc == EISCONN) { 918aff4bce5Syi zhang - Sun Microsystems - Beijing China /* socket success or already success */ 919aff4bce5Syi zhang - Sun Microsystems - Beijing China rc = IDM_STATUS_SUCCESS; 920aff4bce5Syi zhang - Sun Microsystems - Beijing China break; 921aff4bce5Syi zhang - Sun Microsystems - Beijing China } 922aff4bce5Syi zhang - Sun Microsystems - Beijing China if ((rc == ETIMEDOUT) || (rc == ECONNREFUSED) || 923aff4bce5Syi zhang - Sun Microsystems - Beijing China (rc == ECONNRESET)) { 924aff4bce5Syi zhang - Sun Microsystems - Beijing China /* socket connection timeout or refuse */ 925aff4bce5Syi zhang - Sun Microsystems - Beijing China break; 926aff4bce5Syi zhang - Sun Microsystems - Beijing China } 927aff4bce5Syi zhang - Sun Microsystems - Beijing China lbolt = ddi_get_lbolt(); 928aff4bce5Syi zhang - Sun Microsystems - Beijing China if (lbolt > conn_login_max) { 929aff4bce5Syi zhang - Sun Microsystems - Beijing China /* 930aff4bce5Syi zhang - Sun Microsystems - Beijing China * Connection retry timeout, 931aff4bce5Syi zhang - Sun Microsystems - Beijing China * failed connect to target. 932aff4bce5Syi zhang - Sun Microsystems - Beijing China */ 933aff4bce5Syi zhang - Sun Microsystems - Beijing China break; 934aff4bce5Syi zhang - Sun Microsystems - Beijing China } 935aff4bce5Syi zhang - Sun Microsystems - Beijing China if (lbolt < conn_login_interval) { 936aff4bce5Syi zhang - Sun Microsystems - Beijing China if ((rc == EINPROGRESS) || (rc == EALREADY)) { 937aff4bce5Syi zhang - Sun Microsystems - Beijing China /* TCP connect still in progress */ 938aff4bce5Syi zhang - Sun Microsystems - Beijing China delay(SEC_TO_TICK(IN_PROGRESS_DELAY)); 939aff4bce5Syi zhang - Sun Microsystems - Beijing China continue; 940aff4bce5Syi zhang - Sun Microsystems - Beijing China } else { 941aff4bce5Syi zhang - Sun Microsystems - Beijing China delay(conn_login_interval - lbolt); 942aff4bce5Syi zhang - Sun Microsystems - Beijing China } 943aff4bce5Syi zhang - Sun Microsystems - Beijing China } 944aff4bce5Syi zhang - Sun Microsystems - Beijing China conn_login_interval = ddi_get_lbolt() + 945aff4bce5Syi zhang - Sun Microsystems - Beijing China SEC_TO_TICK(ic->ic_conn_params.conn_login_interval); 946aff4bce5Syi zhang - Sun Microsystems - Beijing China } while (rc != 0); 947aff4bce5Syi zhang - Sun Microsystems - Beijing China /* resume to nonblock mode */ 948aff4bce5Syi zhang - Sun Microsystems - Beijing China if (rc == IDM_STATUS_SUCCESS) { 949aff4bce5Syi zhang - Sun Microsystems - Beijing China idm_so_socket_set_block(node); 950aff4bce5Syi zhang - Sun Microsystems - Beijing China } 951aff4bce5Syi zhang - Sun Microsystems - Beijing China } else { 952aff4bce5Syi zhang - Sun Microsystems - Beijing China rc = ksocket_connect(so_conn->ic_so, &ic->ic_ini_dst_addr.sin, 953aff4bce5Syi zhang - Sun Microsystems - Beijing China (SIZEOF_SOCKADDR(&ic->ic_ini_dst_addr.sin)), CRED()); 954aff4bce5Syi zhang - Sun Microsystems - Beijing China } 955a6d42e7dSPeter Dunlap 956aff4bce5Syi zhang - Sun Microsystems - Beijing China if (rc != 0) { 957a6d42e7dSPeter Dunlap idm_soshutdown(so_conn->ic_so); 958a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 959a6d42e7dSPeter Dunlap } 960a6d42e7dSPeter Dunlap 961a6d42e7dSPeter Dunlap idm_so_conn_connect_common(ic); 962a6d42e7dSPeter Dunlap 963a6d42e7dSPeter Dunlap idm_set_ini_postconnect_options(so_conn); 964a6d42e7dSPeter Dunlap 965a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 966a6d42e7dSPeter Dunlap } 967a6d42e7dSPeter Dunlap 968a6d42e7dSPeter Dunlap idm_status_t 9690f1702c5SYu Xiangning idm_so_tgt_conn_create(idm_conn_t *ic, ksocket_t new_so) 970a6d42e7dSPeter Dunlap { 971a6d42e7dSPeter Dunlap idm_status_t idmrc; 972a6d42e7dSPeter Dunlap 973a6d42e7dSPeter Dunlap idmrc = idm_so_conn_create_common(ic, new_so); 974a6d42e7dSPeter Dunlap 975a6d42e7dSPeter Dunlap return (idmrc); 976a6d42e7dSPeter Dunlap } 977a6d42e7dSPeter Dunlap 978a6d42e7dSPeter Dunlap static void 979a6d42e7dSPeter Dunlap idm_so_tgt_conn_destroy(idm_conn_t *ic) 980a6d42e7dSPeter Dunlap { 981a6d42e7dSPeter Dunlap idm_so_conn_destroy_common(ic); 982a6d42e7dSPeter Dunlap } 983a6d42e7dSPeter Dunlap 984a6d42e7dSPeter Dunlap /* 985a6d42e7dSPeter Dunlap * idm_so_tgt_conn_connect() 986a6d42e7dSPeter Dunlap * Establish the connection in ic, passed from idm_tgt_conn_finish(), which 987a6d42e7dSPeter Dunlap * is invoked from the SM as a result of an inbound connection request. 988a6d42e7dSPeter Dunlap */ 989a6d42e7dSPeter Dunlap static idm_status_t 990a6d42e7dSPeter Dunlap idm_so_tgt_conn_connect(idm_conn_t *ic) 991a6d42e7dSPeter Dunlap { 992a6d42e7dSPeter Dunlap idm_so_conn_connect_common(ic); 993a6d42e7dSPeter Dunlap 994a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 995a6d42e7dSPeter Dunlap } 996a6d42e7dSPeter Dunlap 997a6d42e7dSPeter Dunlap static idm_status_t 9980f1702c5SYu Xiangning idm_so_conn_create_common(idm_conn_t *ic, ksocket_t new_so) 999a6d42e7dSPeter Dunlap { 1000a6d42e7dSPeter Dunlap idm_so_conn_t *so_conn; 1001a6d42e7dSPeter Dunlap 1002a6d42e7dSPeter Dunlap so_conn = kmem_zalloc(sizeof (idm_so_conn_t), KM_SLEEP); 1003a6d42e7dSPeter Dunlap so_conn->ic_so = new_so; 1004a6d42e7dSPeter Dunlap 1005a6d42e7dSPeter Dunlap ic->ic_transport_private = so_conn; 1006a6d42e7dSPeter Dunlap ic->ic_transport_hdrlen = 0; 1007a6d42e7dSPeter Dunlap 1008a6d42e7dSPeter Dunlap /* Set the scoreboarding flag on this connection */ 1009a6d42e7dSPeter Dunlap ic->ic_conn_flags |= IDM_CONN_USE_SCOREBOARD; 101056261083SCharles Ting ic->ic_conn_params.max_recv_dataseglen = 101156261083SCharles Ting ISCSI_DEFAULT_MAX_RECV_SEG_LEN; 101256261083SCharles Ting ic->ic_conn_params.max_xmit_dataseglen = 101356261083SCharles Ting ISCSI_DEFAULT_MAX_XMIT_SEG_LEN; 1014a6d42e7dSPeter Dunlap 1015a6d42e7dSPeter Dunlap /* 1016a6d42e7dSPeter Dunlap * Initialize tx thread mutex and list 1017a6d42e7dSPeter Dunlap */ 1018a6d42e7dSPeter Dunlap mutex_init(&so_conn->ic_tx_mutex, NULL, MUTEX_DEFAULT, NULL); 1019a6d42e7dSPeter Dunlap cv_init(&so_conn->ic_tx_cv, NULL, CV_DEFAULT, NULL); 1020a6d42e7dSPeter Dunlap list_create(&so_conn->ic_tx_list, sizeof (idm_pdu_t), 1021a6d42e7dSPeter Dunlap offsetof(idm_pdu_t, idm_tx_link)); 1022a6d42e7dSPeter Dunlap 1023a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 1024a6d42e7dSPeter Dunlap } 1025a6d42e7dSPeter Dunlap 1026a6d42e7dSPeter Dunlap static void 1027a6d42e7dSPeter Dunlap idm_so_conn_destroy_common(idm_conn_t *ic) 1028a6d42e7dSPeter Dunlap { 1029a6d42e7dSPeter Dunlap idm_so_conn_t *so_conn = ic->ic_transport_private; 1030a6d42e7dSPeter Dunlap 1031a6d42e7dSPeter Dunlap ic->ic_transport_private = NULL; 1032a6d42e7dSPeter Dunlap idm_sodestroy(so_conn->ic_so); 1033a6d42e7dSPeter Dunlap list_destroy(&so_conn->ic_tx_list); 1034a6d42e7dSPeter Dunlap mutex_destroy(&so_conn->ic_tx_mutex); 1035a6d42e7dSPeter Dunlap cv_destroy(&so_conn->ic_tx_cv); 1036a6d42e7dSPeter Dunlap 1037a6d42e7dSPeter Dunlap kmem_free(so_conn, sizeof (idm_so_conn_t)); 1038a6d42e7dSPeter Dunlap } 1039a6d42e7dSPeter Dunlap 1040a6d42e7dSPeter Dunlap static void 1041a6d42e7dSPeter Dunlap idm_so_conn_connect_common(idm_conn_t *ic) 1042a6d42e7dSPeter Dunlap { 1043a6d42e7dSPeter Dunlap idm_so_conn_t *so_conn; 10440f1702c5SYu Xiangning struct sockaddr_in6 t_addr; 10450f1702c5SYu Xiangning socklen_t t_addrlen = 0; 1046a6d42e7dSPeter Dunlap 1047a6d42e7dSPeter Dunlap so_conn = ic->ic_transport_private; 10480f1702c5SYu Xiangning bzero(&t_addr, sizeof (struct sockaddr_in6)); 10490f1702c5SYu Xiangning t_addrlen = sizeof (struct sockaddr_in6); 1050a6d42e7dSPeter Dunlap 1051a6d42e7dSPeter Dunlap /* Set the local and remote addresses in the idm conn handle */ 1052aedf2b3bSsrivijitha dugganapalli (void) ksocket_getsockname(so_conn->ic_so, (struct sockaddr *)&t_addr, 10530f1702c5SYu Xiangning &t_addrlen, CRED()); 10540f1702c5SYu Xiangning bcopy(&t_addr, &ic->ic_laddr, t_addrlen); 1055aedf2b3bSsrivijitha dugganapalli (void) ksocket_getpeername(so_conn->ic_so, (struct sockaddr *)&t_addr, 10560f1702c5SYu Xiangning &t_addrlen, CRED()); 10570f1702c5SYu Xiangning bcopy(&t_addr, &ic->ic_raddr, t_addrlen); 1058a6d42e7dSPeter Dunlap 1059a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_mutex); 1060a6d42e7dSPeter Dunlap so_conn->ic_tx_thread = thread_create(NULL, 0, idm_sotx_thread, ic, 0, 1061a6d42e7dSPeter Dunlap &p0, TS_RUN, minclsyspri); 1062a6d42e7dSPeter Dunlap so_conn->ic_rx_thread = thread_create(NULL, 0, idm_sorx_thread, ic, 0, 1063a6d42e7dSPeter Dunlap &p0, TS_RUN, minclsyspri); 1064a6d42e7dSPeter Dunlap 1065*e97fb153SPeter Cudhea - Sun Microsystems - Burlington, MA United States while (so_conn->ic_rx_thread_did == 0 || 1066*e97fb153SPeter Cudhea - Sun Microsystems - Burlington, MA United States so_conn->ic_tx_thread_did == 0) 1067a6d42e7dSPeter Dunlap cv_wait(&ic->ic_cv, &ic->ic_mutex); 1068a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_mutex); 1069a6d42e7dSPeter Dunlap } 1070a6d42e7dSPeter Dunlap 1071a6d42e7dSPeter Dunlap /* 1072a6d42e7dSPeter Dunlap * idm_so_conn_disconnect() 1073a6d42e7dSPeter Dunlap * Shutdown the socket connection and stop the thread 1074a6d42e7dSPeter Dunlap */ 1075a6d42e7dSPeter Dunlap static void 1076a6d42e7dSPeter Dunlap idm_so_conn_disconnect(idm_conn_t *ic) 1077a6d42e7dSPeter Dunlap { 1078a6d42e7dSPeter Dunlap idm_so_conn_t *so_conn; 1079a6d42e7dSPeter Dunlap 1080a6d42e7dSPeter Dunlap so_conn = ic->ic_transport_private; 1081a6d42e7dSPeter Dunlap 1082a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_mutex); 1083a6d42e7dSPeter Dunlap so_conn->ic_rx_thread_running = B_FALSE; 1084a6d42e7dSPeter Dunlap so_conn->ic_tx_thread_running = B_FALSE; 1085a6d42e7dSPeter Dunlap /* We need to wakeup the TX thread */ 1086a6d42e7dSPeter Dunlap mutex_enter(&so_conn->ic_tx_mutex); 1087a6d42e7dSPeter Dunlap cv_signal(&so_conn->ic_tx_cv); 1088a6d42e7dSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 1089a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_mutex); 1090a6d42e7dSPeter Dunlap 1091a6d42e7dSPeter Dunlap /* This should wakeup the RX thread if it is sleeping */ 1092a6d42e7dSPeter Dunlap idm_soshutdown(so_conn->ic_so); 1093a6d42e7dSPeter Dunlap 1094a6d42e7dSPeter Dunlap thread_join(so_conn->ic_tx_thread_did); 1095a6d42e7dSPeter Dunlap thread_join(so_conn->ic_rx_thread_did); 1096a6d42e7dSPeter Dunlap } 1097a6d42e7dSPeter Dunlap 1098a6d42e7dSPeter Dunlap /* 1099a6d42e7dSPeter Dunlap * idm_so_tgt_svc_create() 1100a6d42e7dSPeter Dunlap * Establish a service on an IP address and port. idm_svc_req_t contains 1101a6d42e7dSPeter Dunlap * the service parameters. 1102a6d42e7dSPeter Dunlap */ 1103a6d42e7dSPeter Dunlap /*ARGSUSED*/ 1104a6d42e7dSPeter Dunlap static idm_status_t 1105a6d42e7dSPeter Dunlap idm_so_tgt_svc_create(idm_svc_req_t *sr, idm_svc_t *is) 1106a6d42e7dSPeter Dunlap { 1107a6d42e7dSPeter Dunlap idm_so_svc_t *so_svc; 1108a6d42e7dSPeter Dunlap 1109a6d42e7dSPeter Dunlap so_svc = kmem_zalloc(sizeof (idm_so_svc_t), KM_SLEEP); 1110a6d42e7dSPeter Dunlap 1111a6d42e7dSPeter Dunlap /* Set the new sockets service in svc handle */ 1112a6d42e7dSPeter Dunlap is->is_so_svc = (void *)so_svc; 1113a6d42e7dSPeter Dunlap 1114a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 1115a6d42e7dSPeter Dunlap } 1116a6d42e7dSPeter Dunlap 1117a6d42e7dSPeter Dunlap /* 1118a6d42e7dSPeter Dunlap * idm_so_tgt_svc_destroy() 1119a6d42e7dSPeter Dunlap * Teardown sockets resources allocated in idm_so_tgt_svc_create() 1120a6d42e7dSPeter Dunlap */ 1121a6d42e7dSPeter Dunlap static void 1122a6d42e7dSPeter Dunlap idm_so_tgt_svc_destroy(idm_svc_t *is) 1123a6d42e7dSPeter Dunlap { 1124a6d42e7dSPeter Dunlap /* the socket will have been torn down; free the service */ 1125a6d42e7dSPeter Dunlap kmem_free(is->is_so_svc, sizeof (idm_so_svc_t)); 1126a6d42e7dSPeter Dunlap } 1127a6d42e7dSPeter Dunlap 1128a6d42e7dSPeter Dunlap /* 1129a6d42e7dSPeter Dunlap * idm_so_tgt_svc_online() 1130a6d42e7dSPeter Dunlap * Launch a watch thread on the svc allocated in idm_so_tgt_svc_create() 1131a6d42e7dSPeter Dunlap */ 1132a6d42e7dSPeter Dunlap 1133a6d42e7dSPeter Dunlap static idm_status_t 1134a6d42e7dSPeter Dunlap idm_so_tgt_svc_online(idm_svc_t *is) 1135a6d42e7dSPeter Dunlap { 1136a6d42e7dSPeter Dunlap idm_so_svc_t *so_svc; 1137a6d42e7dSPeter Dunlap idm_svc_req_t *sr = &is->is_svc_req; 1138a6d42e7dSPeter Dunlap struct sockaddr_in6 sin6_ip; 1139a6d42e7dSPeter Dunlap const uint32_t on = 1; 1140a6d42e7dSPeter Dunlap const uint32_t off = 0; 1141a6d42e7dSPeter Dunlap 1142a6d42e7dSPeter Dunlap mutex_enter(&is->is_mutex); 1143a6d42e7dSPeter Dunlap so_svc = (idm_so_svc_t *)is->is_so_svc; 1144a6d42e7dSPeter Dunlap 1145a6d42e7dSPeter Dunlap /* 1146a6d42e7dSPeter Dunlap * Try creating an IPv6 socket first 1147a6d42e7dSPeter Dunlap */ 1148a6d42e7dSPeter Dunlap if ((so_svc->is_so = idm_socreate(PF_INET6, SOCK_STREAM, 0)) == NULL) { 1149a6d42e7dSPeter Dunlap mutex_exit(&is->is_mutex); 1150a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 1151a6d42e7dSPeter Dunlap } else { 1152a6d42e7dSPeter Dunlap bzero(&sin6_ip, sizeof (sin6_ip)); 1153a6d42e7dSPeter Dunlap sin6_ip.sin6_family = AF_INET6; 1154a6d42e7dSPeter Dunlap sin6_ip.sin6_port = htons(sr->sr_port); 1155a6d42e7dSPeter Dunlap sin6_ip.sin6_addr = in6addr_any; 1156a6d42e7dSPeter Dunlap 11570f1702c5SYu Xiangning (void) ksocket_setsockopt(so_svc->is_so, SOL_SOCKET, 11580f1702c5SYu Xiangning SO_REUSEADDR, (char *)&on, sizeof (on), CRED()); 1159a6d42e7dSPeter Dunlap /* 1160a6d42e7dSPeter Dunlap * Turn off SO_MAC_EXEMPT so future sobinds succeed 1161a6d42e7dSPeter Dunlap */ 11620f1702c5SYu Xiangning (void) ksocket_setsockopt(so_svc->is_so, SOL_SOCKET, 11630f1702c5SYu Xiangning SO_MAC_EXEMPT, (char *)&off, sizeof (off), CRED()); 1164a6d42e7dSPeter Dunlap 11650f1702c5SYu Xiangning if (ksocket_bind(so_svc->is_so, (struct sockaddr *)&sin6_ip, 11660f1702c5SYu Xiangning sizeof (sin6_ip), CRED()) != 0) { 1167a6d42e7dSPeter Dunlap mutex_exit(&is->is_mutex); 1168a6d42e7dSPeter Dunlap idm_sodestroy(so_svc->is_so); 1169a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 1170a6d42e7dSPeter Dunlap } 1171a6d42e7dSPeter Dunlap } 1172a6d42e7dSPeter Dunlap 1173a6d42e7dSPeter Dunlap idm_set_tgt_connect_options(so_svc->is_so); 1174a6d42e7dSPeter Dunlap 11750f1702c5SYu Xiangning if (ksocket_listen(so_svc->is_so, 5, CRED()) != 0) { 1176a6d42e7dSPeter Dunlap mutex_exit(&is->is_mutex); 1177a6d42e7dSPeter Dunlap idm_soshutdown(so_svc->is_so); 1178a6d42e7dSPeter Dunlap idm_sodestroy(so_svc->is_so); 1179a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 1180a6d42e7dSPeter Dunlap } 1181a6d42e7dSPeter Dunlap 1182a6d42e7dSPeter Dunlap /* Launch a watch thread */ 1183a6d42e7dSPeter Dunlap so_svc->is_thread = thread_create(NULL, 0, idm_so_svc_port_watcher, 1184a6d42e7dSPeter Dunlap is, 0, &p0, TS_RUN, minclsyspri); 1185a6d42e7dSPeter Dunlap 1186a6d42e7dSPeter Dunlap if (so_svc->is_thread == NULL) { 1187a6d42e7dSPeter Dunlap /* Failure to launch; teardown the socket */ 1188a6d42e7dSPeter Dunlap mutex_exit(&is->is_mutex); 1189a6d42e7dSPeter Dunlap idm_soshutdown(so_svc->is_so); 1190a6d42e7dSPeter Dunlap idm_sodestroy(so_svc->is_so); 1191a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 1192a6d42e7dSPeter Dunlap } 11930f1702c5SYu Xiangning ksocket_hold(so_svc->is_so); 1194a6d42e7dSPeter Dunlap /* Wait for the port watcher thread to start */ 1195a6d42e7dSPeter Dunlap while (!so_svc->is_thread_running) 1196a6d42e7dSPeter Dunlap cv_wait(&is->is_cv, &is->is_mutex); 1197a6d42e7dSPeter Dunlap mutex_exit(&is->is_mutex); 1198a6d42e7dSPeter Dunlap 1199a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 1200a6d42e7dSPeter Dunlap } 1201a6d42e7dSPeter Dunlap 1202a6d42e7dSPeter Dunlap /* 1203a6d42e7dSPeter Dunlap * idm_so_tgt_svc_offline 1204a6d42e7dSPeter Dunlap * 1205a6d42e7dSPeter Dunlap * Stop listening on the IP address and port identified by idm_svc_t. 1206a6d42e7dSPeter Dunlap */ 1207a6d42e7dSPeter Dunlap static void 1208a6d42e7dSPeter Dunlap idm_so_tgt_svc_offline(idm_svc_t *is) 1209a6d42e7dSPeter Dunlap { 1210a6d42e7dSPeter Dunlap idm_so_svc_t *so_svc; 1211a6d42e7dSPeter Dunlap mutex_enter(&is->is_mutex); 1212a6d42e7dSPeter Dunlap so_svc = (idm_so_svc_t *)is->is_so_svc; 1213a6d42e7dSPeter Dunlap so_svc->is_thread_running = B_FALSE; 1214a6d42e7dSPeter Dunlap mutex_exit(&is->is_mutex); 1215a6d42e7dSPeter Dunlap 1216a6d42e7dSPeter Dunlap /* 12170f1702c5SYu Xiangning * Teardown socket 1218a6d42e7dSPeter Dunlap */ 12190f1702c5SYu Xiangning idm_sodestroy(so_svc->is_so); 1220a6d42e7dSPeter Dunlap 1221a6d42e7dSPeter Dunlap /* 1222a6d42e7dSPeter Dunlap * Now we expect the port watcher thread to terminate 1223a6d42e7dSPeter Dunlap */ 1224a6d42e7dSPeter Dunlap thread_join(so_svc->is_thread_did); 1225a6d42e7dSPeter Dunlap } 1226a6d42e7dSPeter Dunlap 1227a6d42e7dSPeter Dunlap /* 1228a6d42e7dSPeter Dunlap * Watch thread for target service connection establishment. 1229a6d42e7dSPeter Dunlap */ 1230a6d42e7dSPeter Dunlap void 1231a6d42e7dSPeter Dunlap idm_so_svc_port_watcher(void *arg) 1232a6d42e7dSPeter Dunlap { 1233a6d42e7dSPeter Dunlap idm_svc_t *svc = arg; 12340f1702c5SYu Xiangning ksocket_t new_so; 1235a6d42e7dSPeter Dunlap idm_conn_t *ic; 1236a6d42e7dSPeter Dunlap idm_status_t idmrc; 1237a6d42e7dSPeter Dunlap idm_so_svc_t *so_svc; 1238a6d42e7dSPeter Dunlap int rc; 1239a6d42e7dSPeter Dunlap const uint32_t off = 0; 12400f1702c5SYu Xiangning struct sockaddr_in6 t_addr; 12410f1702c5SYu Xiangning socklen_t t_addrlen; 1242a6d42e7dSPeter Dunlap 12430f1702c5SYu Xiangning bzero(&t_addr, sizeof (struct sockaddr_in6)); 12440f1702c5SYu Xiangning t_addrlen = sizeof (struct sockaddr_in6); 1245a6d42e7dSPeter Dunlap mutex_enter(&svc->is_mutex); 1246a6d42e7dSPeter Dunlap 1247a6d42e7dSPeter Dunlap so_svc = svc->is_so_svc; 1248a6d42e7dSPeter Dunlap so_svc->is_thread_running = B_TRUE; 1249a6d42e7dSPeter Dunlap so_svc->is_thread_did = so_svc->is_thread->t_did; 1250a6d42e7dSPeter Dunlap 1251a6d42e7dSPeter Dunlap cv_signal(&svc->is_cv); 1252a6d42e7dSPeter Dunlap 1253a6d42e7dSPeter Dunlap IDM_SVC_LOG(CE_NOTE, "iSCSI service (%p/%d) online", (void *)svc, 1254a6d42e7dSPeter Dunlap svc->is_svc_req.sr_port); 1255a6d42e7dSPeter Dunlap 1256a6d42e7dSPeter Dunlap while (so_svc->is_thread_running) { 1257a6d42e7dSPeter Dunlap mutex_exit(&svc->is_mutex); 1258a6d42e7dSPeter Dunlap 12590f1702c5SYu Xiangning if ((rc = ksocket_accept(so_svc->is_so, 12600f1702c5SYu Xiangning (struct sockaddr *)&t_addr, &t_addrlen, 12610f1702c5SYu Xiangning &new_so, CRED())) != 0) { 1262a6d42e7dSPeter Dunlap mutex_enter(&svc->is_mutex); 1263a6d42e7dSPeter Dunlap if (rc == ECONNABORTED) 1264a6d42e7dSPeter Dunlap continue; 1265a6d42e7dSPeter Dunlap /* Connection problem */ 1266a6d42e7dSPeter Dunlap break; 1267a6d42e7dSPeter Dunlap } 1268a6d42e7dSPeter Dunlap /* 1269a6d42e7dSPeter Dunlap * Turn off SO_MAC_EXEMPT so future sobinds succeed 1270a6d42e7dSPeter Dunlap */ 12710f1702c5SYu Xiangning (void) ksocket_setsockopt(new_so, SOL_SOCKET, SO_MAC_EXEMPT, 12720f1702c5SYu Xiangning (char *)&off, sizeof (off), CRED()); 1273a6d42e7dSPeter Dunlap 1274a6d42e7dSPeter Dunlap idmrc = idm_svc_conn_create(svc, IDM_TRANSPORT_TYPE_SOCKETS, 1275a6d42e7dSPeter Dunlap &ic); 1276a6d42e7dSPeter Dunlap if (idmrc != IDM_STATUS_SUCCESS) { 1277a6d42e7dSPeter Dunlap /* Drop connection */ 1278a6d42e7dSPeter Dunlap idm_soshutdown(new_so); 1279a6d42e7dSPeter Dunlap idm_sodestroy(new_so); 1280a6d42e7dSPeter Dunlap mutex_enter(&svc->is_mutex); 1281a6d42e7dSPeter Dunlap continue; 1282a6d42e7dSPeter Dunlap } 1283a6d42e7dSPeter Dunlap 1284a6d42e7dSPeter Dunlap idmrc = idm_so_tgt_conn_create(ic, new_so); 1285a6d42e7dSPeter Dunlap if (idmrc != IDM_STATUS_SUCCESS) { 1286a6d42e7dSPeter Dunlap idm_svc_conn_destroy(ic); 1287a6d42e7dSPeter Dunlap idm_soshutdown(new_so); 1288a6d42e7dSPeter Dunlap idm_sodestroy(new_so); 1289a6d42e7dSPeter Dunlap mutex_enter(&svc->is_mutex); 1290a6d42e7dSPeter Dunlap continue; 1291a6d42e7dSPeter Dunlap } 1292a6d42e7dSPeter Dunlap 1293a6d42e7dSPeter Dunlap /* 1294a6d42e7dSPeter Dunlap * Kick the state machine. At CS_S3_XPT_UP the state machine 1295a6d42e7dSPeter Dunlap * will notify the client (target) about the new connection. 1296a6d42e7dSPeter Dunlap */ 1297a6d42e7dSPeter Dunlap idm_conn_event(ic, CE_CONNECT_ACCEPT, NULL); 1298a6d42e7dSPeter Dunlap 1299a6d42e7dSPeter Dunlap mutex_enter(&svc->is_mutex); 1300a6d42e7dSPeter Dunlap } 13010f1702c5SYu Xiangning ksocket_rele(so_svc->is_so); 1302a6d42e7dSPeter Dunlap so_svc->is_thread_running = B_FALSE; 1303a6d42e7dSPeter Dunlap mutex_exit(&svc->is_mutex); 1304a6d42e7dSPeter Dunlap 1305a6d42e7dSPeter Dunlap IDM_SVC_LOG(CE_NOTE, "iSCSI service (%p/%d) offline", (void *)svc, 1306a6d42e7dSPeter Dunlap svc->is_svc_req.sr_port); 1307a6d42e7dSPeter Dunlap 1308a6d42e7dSPeter Dunlap thread_exit(); 1309a6d42e7dSPeter Dunlap } 1310a6d42e7dSPeter Dunlap 1311a6d42e7dSPeter Dunlap /* 1312a6d42e7dSPeter Dunlap * idm_so_free_task_rsrc() stops any ongoing processing of the task and 1313a6d42e7dSPeter Dunlap * frees resources associated with the task. 1314a6d42e7dSPeter Dunlap * 1315a6d42e7dSPeter Dunlap * It's not clear that this should return idm_status_t. What do we do 1316a6d42e7dSPeter Dunlap * if it fails? 1317a6d42e7dSPeter Dunlap */ 1318a6d42e7dSPeter Dunlap static idm_status_t 1319a6d42e7dSPeter Dunlap idm_so_free_task_rsrc(idm_task_t *idt) 1320a6d42e7dSPeter Dunlap { 132192adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States idm_buf_t *idb, *next_idb; 1322a6d42e7dSPeter Dunlap 132330e7468fSPeter Dunlap /* 132430e7468fSPeter Dunlap * There is nothing to cleanup on initiator connections 132530e7468fSPeter Dunlap */ 132630e7468fSPeter Dunlap if (IDM_CONN_ISINI(idt->idt_ic)) 132730e7468fSPeter Dunlap return (IDM_STATUS_SUCCESS); 132830e7468fSPeter Dunlap 1329a6d42e7dSPeter Dunlap /* 1330a6d42e7dSPeter Dunlap * If this is a target connection, call idm_buf_rx_from_ini_done for 1331a6d42e7dSPeter Dunlap * any buffer on the "outbufv" list with idb->idb_in_transport==B_TRUE. 1332a6d42e7dSPeter Dunlap * 1333a6d42e7dSPeter Dunlap * In addition, remove any buffers associated with this task from 1334a6d42e7dSPeter Dunlap * the ic_tx_list. We'll do this by walking the idt_inbufv list, but 1335a6d42e7dSPeter Dunlap * items don't actually get removed from that list (and completion 1336a6d42e7dSPeter Dunlap * routines called) until idm_task_cleanup. 1337a6d42e7dSPeter Dunlap */ 1338a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 1339a6d42e7dSPeter Dunlap 134092adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States for (idb = list_head(&idt->idt_outbufv); idb != NULL; idb = next_idb) { 134192adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States next_idb = list_next(&idt->idt_outbufv, idb); 1342a6d42e7dSPeter Dunlap if (idb->idb_in_transport) { 1343a6d42e7dSPeter Dunlap /* 1344a6d42e7dSPeter Dunlap * idm_buf_rx_from_ini_done releases idt->idt_mutex 1345a6d42e7dSPeter Dunlap */ 1346a668b114SPriya Krishnan DTRACE_ISCSI_8(xfer__done, idm_conn_t *, idt->idt_ic, 1347a668b114SPriya Krishnan uintptr_t, idb->idb_buf, 1348a668b114SPriya Krishnan uint32_t, idb->idb_bufoffset, 1349a668b114SPriya Krishnan uint64_t, 0, uint32_t, 0, uint32_t, 0, 1350a668b114SPriya Krishnan uint32_t, idb->idb_xfer_len, 1351a668b114SPriya Krishnan int, XFER_BUF_RX_FROM_INI); 1352a6d42e7dSPeter Dunlap idm_buf_rx_from_ini_done(idt, idb, IDM_STATUS_ABORTED); 1353a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 1354a6d42e7dSPeter Dunlap } 1355a6d42e7dSPeter Dunlap } 1356a6d42e7dSPeter Dunlap 135792adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States for (idb = list_head(&idt->idt_inbufv); idb != NULL; idb = next_idb) { 135892adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States next_idb = list_next(&idt->idt_inbufv, idb); 1359a6d42e7dSPeter Dunlap /* 1360a6d42e7dSPeter Dunlap * We want to remove these items from the tx_list as well, 1361a6d42e7dSPeter Dunlap * but knowing it's in the idt_inbufv list is not a guarantee 1362a6d42e7dSPeter Dunlap * that it's in the tx_list. If it's on the tx list then 1363a6d42e7dSPeter Dunlap * let idm_sotx_thread() clean it up. 1364a6d42e7dSPeter Dunlap */ 1365a6d42e7dSPeter Dunlap if (idb->idb_in_transport && !idb->idb_tx_thread) { 1366a6d42e7dSPeter Dunlap /* 1367a6d42e7dSPeter Dunlap * idm_buf_tx_to_ini_done releases idt->idt_mutex 1368a6d42e7dSPeter Dunlap */ 1369a668b114SPriya Krishnan DTRACE_ISCSI_8(xfer__done, idm_conn_t *, idt->idt_ic, 1370a668b114SPriya Krishnan uintptr_t, idb->idb_buf, 1371a668b114SPriya Krishnan uint32_t, idb->idb_bufoffset, 1372a668b114SPriya Krishnan uint64_t, 0, uint32_t, 0, uint32_t, 0, 1373a668b114SPriya Krishnan uint32_t, idb->idb_xfer_len, 1374a668b114SPriya Krishnan int, XFER_BUF_TX_TO_INI); 1375a6d42e7dSPeter Dunlap idm_buf_tx_to_ini_done(idt, idb, IDM_STATUS_ABORTED); 1376a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 1377a6d42e7dSPeter Dunlap } 1378a6d42e7dSPeter Dunlap } 1379a6d42e7dSPeter Dunlap 1380a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1381a6d42e7dSPeter Dunlap 1382a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 1383a6d42e7dSPeter Dunlap } 1384a6d42e7dSPeter Dunlap 1385a6d42e7dSPeter Dunlap /* 1386a6d42e7dSPeter Dunlap * idm_so_negotiate_key_values() validates the key values for this connection 1387a6d42e7dSPeter Dunlap */ 1388a6d42e7dSPeter Dunlap /* ARGSUSED */ 1389a6d42e7dSPeter Dunlap static kv_status_t 1390a6d42e7dSPeter Dunlap idm_so_negotiate_key_values(idm_conn_t *it, nvlist_t *request_nvl, 1391a6d42e7dSPeter Dunlap nvlist_t *response_nvl, nvlist_t *negotiated_nvl) 1392a6d42e7dSPeter Dunlap { 1393a6d42e7dSPeter Dunlap /* All parameters are negotiated at the iscsit level */ 1394a6d42e7dSPeter Dunlap return (KV_HANDLED); 1395a6d42e7dSPeter Dunlap } 1396a6d42e7dSPeter Dunlap 1397a6d42e7dSPeter Dunlap /* 1398a6d42e7dSPeter Dunlap * idm_so_notice_key_values() activates the negotiated key values for 1399a6d42e7dSPeter Dunlap * this connection. 1400a6d42e7dSPeter Dunlap */ 140130e7468fSPeter Dunlap static void 1402a6d42e7dSPeter Dunlap idm_so_notice_key_values(idm_conn_t *it, nvlist_t *negotiated_nvl) 1403a6d42e7dSPeter Dunlap { 1404a6d42e7dSPeter Dunlap char *nvp_name; 1405a6d42e7dSPeter Dunlap nvpair_t *nvp; 1406a6d42e7dSPeter Dunlap nvpair_t *next_nvp; 1407a6d42e7dSPeter Dunlap int nvrc; 1408a6d42e7dSPeter Dunlap idm_status_t idm_status; 1409a6d42e7dSPeter Dunlap const idm_kv_xlate_t *ikvx; 141056261083SCharles Ting uint64_t num_val; 1411a6d42e7dSPeter Dunlap 1412a6d42e7dSPeter Dunlap for (nvp = nvlist_next_nvpair(negotiated_nvl, NULL); 1413a6d42e7dSPeter Dunlap nvp != NULL; nvp = next_nvp) { 1414a6d42e7dSPeter Dunlap next_nvp = nvlist_next_nvpair(negotiated_nvl, nvp); 1415a6d42e7dSPeter Dunlap nvp_name = nvpair_name(nvp); 1416a6d42e7dSPeter Dunlap 1417a6d42e7dSPeter Dunlap ikvx = idm_lookup_kv_xlate(nvp_name, strlen(nvp_name)); 1418a6d42e7dSPeter Dunlap switch (ikvx->ik_key_id) { 1419a6d42e7dSPeter Dunlap case KI_HEADER_DIGEST: 1420a6d42e7dSPeter Dunlap case KI_DATA_DIGEST: 1421a6d42e7dSPeter Dunlap idm_status = idm_so_handle_digest(it, nvp, ikvx); 1422a6d42e7dSPeter Dunlap ASSERT(idm_status == 0); 1423a6d42e7dSPeter Dunlap 1424a6d42e7dSPeter Dunlap /* Remove processed item from negotiated_nvl list */ 1425a6d42e7dSPeter Dunlap nvrc = nvlist_remove_all( 1426a6d42e7dSPeter Dunlap negotiated_nvl, ikvx->ik_key_name); 1427a6d42e7dSPeter Dunlap ASSERT(nvrc == 0); 1428a6d42e7dSPeter Dunlap break; 142956261083SCharles Ting case KI_MAX_RECV_DATA_SEGMENT_LENGTH: 143056261083SCharles Ting /* 143156261083SCharles Ting * Just pass the value down to idm layer. 143256261083SCharles Ting * No need to remove it from negotiated_nvl list here. 143356261083SCharles Ting */ 143456261083SCharles Ting nvrc = nvpair_value_uint64(nvp, &num_val); 143556261083SCharles Ting ASSERT(nvrc == 0); 143656261083SCharles Ting it->ic_conn_params.max_xmit_dataseglen = 143756261083SCharles Ting (uint32_t)num_val; 143856261083SCharles Ting break; 1439a6d42e7dSPeter Dunlap default: 1440a6d42e7dSPeter Dunlap break; 1441a6d42e7dSPeter Dunlap } 1442a6d42e7dSPeter Dunlap } 1443a6d42e7dSPeter Dunlap } 1444a6d42e7dSPeter Dunlap 144556261083SCharles Ting /* 144656261083SCharles Ting * idm_so_declare_key_values() declares the key values for this connection 144756261083SCharles Ting */ 144856261083SCharles Ting /* ARGSUSED */ 144956261083SCharles Ting static kv_status_t 145056261083SCharles Ting idm_so_declare_key_values(idm_conn_t *it, nvlist_t *config_nvl, 145156261083SCharles Ting nvlist_t *outgoing_nvl) 145256261083SCharles Ting { 145356261083SCharles Ting char *nvp_name; 145456261083SCharles Ting nvpair_t *nvp; 145556261083SCharles Ting nvpair_t *next_nvp; 145656261083SCharles Ting kv_status_t kvrc; 145756261083SCharles Ting int nvrc = 0; 145856261083SCharles Ting const idm_kv_xlate_t *ikvx; 145956261083SCharles Ting uint64_t num_val; 146056261083SCharles Ting 146156261083SCharles Ting for (nvp = nvlist_next_nvpair(config_nvl, NULL); 146256261083SCharles Ting nvp != NULL && nvrc == 0; nvp = next_nvp) { 146356261083SCharles Ting next_nvp = nvlist_next_nvpair(config_nvl, nvp); 146456261083SCharles Ting nvp_name = nvpair_name(nvp); 146556261083SCharles Ting 146656261083SCharles Ting ikvx = idm_lookup_kv_xlate(nvp_name, strlen(nvp_name)); 146756261083SCharles Ting switch (ikvx->ik_key_id) { 146856261083SCharles Ting case KI_MAX_RECV_DATA_SEGMENT_LENGTH: 146956261083SCharles Ting if ((nvrc = nvpair_value_uint64(nvp, &num_val)) != 0) { 147056261083SCharles Ting break; 147156261083SCharles Ting } 147256261083SCharles Ting if (outgoing_nvl && 147356261083SCharles Ting (nvrc = nvlist_add_uint64(outgoing_nvl, 147456261083SCharles Ting nvp_name, num_val)) != 0) { 147556261083SCharles Ting break; 147656261083SCharles Ting } 147756261083SCharles Ting it->ic_conn_params.max_recv_dataseglen = 147856261083SCharles Ting (uint32_t)num_val; 147956261083SCharles Ting break; 148056261083SCharles Ting default: 148156261083SCharles Ting break; 148256261083SCharles Ting } 148356261083SCharles Ting } 148456261083SCharles Ting kvrc = idm_nvstat_to_kvstat(nvrc); 148556261083SCharles Ting return (kvrc); 148656261083SCharles Ting } 1487a6d42e7dSPeter Dunlap 1488a6d42e7dSPeter Dunlap static idm_status_t 1489a6d42e7dSPeter Dunlap idm_so_handle_digest(idm_conn_t *it, nvpair_t *digest_choice, 1490a6d42e7dSPeter Dunlap const idm_kv_xlate_t *ikvx) 1491a6d42e7dSPeter Dunlap { 1492a6d42e7dSPeter Dunlap int nvrc; 1493a6d42e7dSPeter Dunlap char *digest_choice_string; 1494a6d42e7dSPeter Dunlap 1495a6d42e7dSPeter Dunlap nvrc = nvpair_value_string(digest_choice, 1496a6d42e7dSPeter Dunlap &digest_choice_string); 1497a6d42e7dSPeter Dunlap ASSERT(nvrc == 0); 1498a6d42e7dSPeter Dunlap if (strcasecmp(digest_choice_string, "crc32c") == 0) { 1499a6d42e7dSPeter Dunlap switch (ikvx->ik_key_id) { 1500a6d42e7dSPeter Dunlap case KI_HEADER_DIGEST: 1501a6d42e7dSPeter Dunlap it->ic_conn_flags |= IDM_CONN_HEADER_DIGEST; 1502a6d42e7dSPeter Dunlap break; 1503a6d42e7dSPeter Dunlap case KI_DATA_DIGEST: 1504a6d42e7dSPeter Dunlap it->ic_conn_flags |= IDM_CONN_DATA_DIGEST; 1505a6d42e7dSPeter Dunlap break; 1506a6d42e7dSPeter Dunlap default: 1507a6d42e7dSPeter Dunlap ASSERT(0); 1508a6d42e7dSPeter Dunlap break; 1509a6d42e7dSPeter Dunlap } 1510a6d42e7dSPeter Dunlap } else if (strcasecmp(digest_choice_string, "none") == 0) { 1511a6d42e7dSPeter Dunlap switch (ikvx->ik_key_id) { 1512a6d42e7dSPeter Dunlap case KI_HEADER_DIGEST: 1513a6d42e7dSPeter Dunlap it->ic_conn_flags &= ~IDM_CONN_HEADER_DIGEST; 1514a6d42e7dSPeter Dunlap break; 1515a6d42e7dSPeter Dunlap case KI_DATA_DIGEST: 1516a6d42e7dSPeter Dunlap it->ic_conn_flags &= ~IDM_CONN_DATA_DIGEST; 1517a6d42e7dSPeter Dunlap break; 1518a6d42e7dSPeter Dunlap default: 1519a6d42e7dSPeter Dunlap ASSERT(0); 1520a6d42e7dSPeter Dunlap break; 1521a6d42e7dSPeter Dunlap } 1522a6d42e7dSPeter Dunlap } else { 1523a6d42e7dSPeter Dunlap ASSERT(0); 1524a6d42e7dSPeter Dunlap } 1525a6d42e7dSPeter Dunlap 1526a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 1527a6d42e7dSPeter Dunlap } 1528a6d42e7dSPeter Dunlap 1529a6d42e7dSPeter Dunlap 1530a6d42e7dSPeter Dunlap /* 1531a6d42e7dSPeter Dunlap * idm_so_conn_is_capable() verifies that the passed connection is provided 1532a6d42e7dSPeter Dunlap * for by the sockets interface. 1533a6d42e7dSPeter Dunlap */ 1534a6d42e7dSPeter Dunlap /* ARGSUSED */ 1535a6d42e7dSPeter Dunlap static boolean_t 1536a6d42e7dSPeter Dunlap idm_so_conn_is_capable(idm_conn_req_t *ic, idm_transport_caps_t *caps) 1537a6d42e7dSPeter Dunlap { 1538a6d42e7dSPeter Dunlap return (B_TRUE); 1539a6d42e7dSPeter Dunlap } 1540a6d42e7dSPeter Dunlap 1541a6d42e7dSPeter Dunlap /* 1542a6d42e7dSPeter Dunlap * idm_so_rx_datain() validates the Data Sequence number of the PDU. The 1543a6d42e7dSPeter Dunlap * idm_sorecv_scsidata() function invoked earlier actually reads the data 1544a6d42e7dSPeter Dunlap * off the socket into the appropriate buffers. 1545a6d42e7dSPeter Dunlap */ 1546a6d42e7dSPeter Dunlap static void 1547a6d42e7dSPeter Dunlap idm_so_rx_datain(idm_conn_t *ic, idm_pdu_t *pdu) 1548a6d42e7dSPeter Dunlap { 1549a6d42e7dSPeter Dunlap iscsi_data_hdr_t *bhs; 1550a6d42e7dSPeter Dunlap idm_task_t *idt; 1551a6d42e7dSPeter Dunlap idm_buf_t *idb; 1552a6d42e7dSPeter Dunlap uint32_t datasn; 1553a6d42e7dSPeter Dunlap size_t offset; 1554a6d42e7dSPeter Dunlap iscsi_hdr_t *ihp = (iscsi_hdr_t *)pdu->isp_hdr; 1555a6d42e7dSPeter Dunlap iscsi_data_rsp_hdr_t *idrhp = (iscsi_data_rsp_hdr_t *)ihp; 1556a6d42e7dSPeter Dunlap 1557a6d42e7dSPeter Dunlap ASSERT(ic != NULL); 1558a6d42e7dSPeter Dunlap ASSERT(pdu != NULL); 1559a6d42e7dSPeter Dunlap 1560a6d42e7dSPeter Dunlap bhs = (iscsi_data_hdr_t *)pdu->isp_hdr; 1561a6d42e7dSPeter Dunlap datasn = ntohl(bhs->datasn); 1562a6d42e7dSPeter Dunlap offset = ntohl(bhs->offset); 1563a6d42e7dSPeter Dunlap 1564a6d42e7dSPeter Dunlap ASSERT(bhs->opcode == ISCSI_OP_SCSI_DATA_RSP); 1565a6d42e7dSPeter Dunlap 1566a6d42e7dSPeter Dunlap /* 1567a6d42e7dSPeter Dunlap * Look up the task corresponding to the initiator task tag 1568a6d42e7dSPeter Dunlap * to get the buffers affiliated with the task. 1569a6d42e7dSPeter Dunlap */ 1570a6d42e7dSPeter Dunlap idt = idm_task_find(ic, bhs->itt, bhs->ttt); 1571a6d42e7dSPeter Dunlap if (idt == NULL) { 1572a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, "idm_so_rx_datain: failed to find task"); 1573a6d42e7dSPeter Dunlap idm_pdu_rx_protocol_error(ic, pdu); 1574a6d42e7dSPeter Dunlap return; 1575a6d42e7dSPeter Dunlap } 1576a6d42e7dSPeter Dunlap 1577a6d42e7dSPeter Dunlap idb = pdu->isp_sorx_buf; 1578a6d42e7dSPeter Dunlap if (idb == NULL) { 1579a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, 1580a6d42e7dSPeter Dunlap "idm_so_rx_datain: failed to find buffer"); 1581a6d42e7dSPeter Dunlap idm_task_rele(idt); 1582a6d42e7dSPeter Dunlap idm_pdu_rx_protocol_error(ic, pdu); 1583a6d42e7dSPeter Dunlap return; 1584a6d42e7dSPeter Dunlap } 1585a6d42e7dSPeter Dunlap 1586a6d42e7dSPeter Dunlap /* 1587a6d42e7dSPeter Dunlap * DataSN values should be sequential and should not have any gaps or 1588a6d42e7dSPeter Dunlap * repetitions. Check the DataSN with the one stored in the task. 1589a6d42e7dSPeter Dunlap */ 1590a6d42e7dSPeter Dunlap if (datasn == idt->idt_exp_datasn) { 1591a6d42e7dSPeter Dunlap idt->idt_exp_datasn++; /* keep track of DataSN received */ 1592a6d42e7dSPeter Dunlap } else { 1593a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, "idm_so_rx_datain: datasn out of order"); 1594a6d42e7dSPeter Dunlap idm_task_rele(idt); 1595a6d42e7dSPeter Dunlap idm_pdu_rx_protocol_error(ic, pdu); 1596a6d42e7dSPeter Dunlap return; 1597a6d42e7dSPeter Dunlap } 1598a6d42e7dSPeter Dunlap 1599a6d42e7dSPeter Dunlap /* 1600a6d42e7dSPeter Dunlap * PDUs in a sequence should be in continuously increasing 1601a6d42e7dSPeter Dunlap * address offset 1602a6d42e7dSPeter Dunlap */ 1603a6d42e7dSPeter Dunlap if (offset != idb->idb_exp_offset) { 1604a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, "idm_so_rx_datain: unexpected offset"); 160530e7468fSPeter Dunlap idm_task_rele(idt); 1606a6d42e7dSPeter Dunlap idm_pdu_rx_protocol_error(ic, pdu); 1607a6d42e7dSPeter Dunlap return; 1608a6d42e7dSPeter Dunlap } 1609a6d42e7dSPeter Dunlap /* Expected next relative buffer offset */ 1610a6d42e7dSPeter Dunlap idb->idb_exp_offset += n2h24(bhs->dlength); 161130e7468fSPeter Dunlap idt->idt_rx_bytes += n2h24(bhs->dlength); 161230e7468fSPeter Dunlap 161330e7468fSPeter Dunlap idm_task_rele(idt); 1614a6d42e7dSPeter Dunlap 1615a6d42e7dSPeter Dunlap /* 1616a6d42e7dSPeter Dunlap * For now call scsi_rsp which will process the data rsp 1617a6d42e7dSPeter Dunlap * Revisit, need to provide an explicit client entry point for 1618a6d42e7dSPeter Dunlap * phase collapse completions. 1619a6d42e7dSPeter Dunlap */ 1620a6d42e7dSPeter Dunlap if (((ihp->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_SCSI_DATA_RSP) && 1621a6d42e7dSPeter Dunlap (idrhp->flags & ISCSI_FLAG_DATA_STATUS)) { 1622a6d42e7dSPeter Dunlap (*ic->ic_conn_ops.icb_rx_scsi_rsp)(ic, pdu); 1623a6d42e7dSPeter Dunlap } 1624a6d42e7dSPeter Dunlap 1625a6d42e7dSPeter Dunlap idm_pdu_complete(pdu, IDM_STATUS_SUCCESS); 1626a6d42e7dSPeter Dunlap } 1627a6d42e7dSPeter Dunlap 1628a6d42e7dSPeter Dunlap /* 1629a6d42e7dSPeter Dunlap * The idm_so_rx_dataout() function is used by the iSCSI target to read 1630a6d42e7dSPeter Dunlap * data from the Data-Out PDU sent by the iSCSI initiator. 1631a6d42e7dSPeter Dunlap * 1632a6d42e7dSPeter Dunlap * This function gets the Initiator Task Tag from the PDU BHS and looks up the 1633a6d42e7dSPeter Dunlap * task to get the buffers associated with the PDU. A PDU might span buffers. 1634a6d42e7dSPeter Dunlap * The data is then read into the respective buffer. 1635a6d42e7dSPeter Dunlap */ 1636a6d42e7dSPeter Dunlap static void 1637a6d42e7dSPeter Dunlap idm_so_rx_dataout(idm_conn_t *ic, idm_pdu_t *pdu) 1638a6d42e7dSPeter Dunlap { 1639a6d42e7dSPeter Dunlap 1640a6d42e7dSPeter Dunlap iscsi_data_hdr_t *bhs; 1641a6d42e7dSPeter Dunlap idm_task_t *idt; 1642a6d42e7dSPeter Dunlap idm_buf_t *idb; 1643a6d42e7dSPeter Dunlap size_t offset; 1644a6d42e7dSPeter Dunlap 1645a6d42e7dSPeter Dunlap ASSERT(ic != NULL); 1646a6d42e7dSPeter Dunlap ASSERT(pdu != NULL); 1647a6d42e7dSPeter Dunlap 1648a6d42e7dSPeter Dunlap bhs = (iscsi_data_hdr_t *)pdu->isp_hdr; 1649a6d42e7dSPeter Dunlap offset = ntohl(bhs->offset); 1650a6d42e7dSPeter Dunlap ASSERT(bhs->opcode == ISCSI_OP_SCSI_DATA); 1651a6d42e7dSPeter Dunlap 1652a6d42e7dSPeter Dunlap /* 1653a6d42e7dSPeter Dunlap * Look up the task corresponding to the initiator task tag 1654a6d42e7dSPeter Dunlap * to get the buffers affiliated with the task. 1655a6d42e7dSPeter Dunlap */ 1656a6d42e7dSPeter Dunlap idt = idm_task_find(ic, bhs->itt, bhs->ttt); 1657a6d42e7dSPeter Dunlap if (idt == NULL) { 1658a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, 1659a6d42e7dSPeter Dunlap "idm_so_rx_dataout: failed to find task"); 1660a6d42e7dSPeter Dunlap idm_pdu_rx_protocol_error(ic, pdu); 1661a6d42e7dSPeter Dunlap return; 1662a6d42e7dSPeter Dunlap } 1663a6d42e7dSPeter Dunlap 1664a6d42e7dSPeter Dunlap idb = pdu->isp_sorx_buf; 1665a6d42e7dSPeter Dunlap if (idb == NULL) { 1666a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, 1667a6d42e7dSPeter Dunlap "idm_so_rx_dataout: failed to find buffer"); 1668a6d42e7dSPeter Dunlap idm_task_rele(idt); 1669a6d42e7dSPeter Dunlap idm_pdu_rx_protocol_error(ic, pdu); 1670a6d42e7dSPeter Dunlap return; 1671a6d42e7dSPeter Dunlap } 1672a6d42e7dSPeter Dunlap 1673a6d42e7dSPeter Dunlap /* Keep track of data transferred - check data offsets */ 1674a6d42e7dSPeter Dunlap if (offset != idb->idb_exp_offset) { 1675a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_NOTE, "idm_so_rx_dataout: offset out of seq: " 1676a6d42e7dSPeter Dunlap "%ld, %d", offset, idb->idb_exp_offset); 1677a6d42e7dSPeter Dunlap idm_task_rele(idt); 1678a6d42e7dSPeter Dunlap idm_pdu_rx_protocol_error(ic, pdu); 1679a6d42e7dSPeter Dunlap return; 1680a6d42e7dSPeter Dunlap } 1681a6d42e7dSPeter Dunlap /* Expected next relative offset */ 1682a6d42e7dSPeter Dunlap idb->idb_exp_offset += ntoh24(bhs->dlength); 168330e7468fSPeter Dunlap idt->idt_rx_bytes += n2h24(bhs->dlength); 1684a6d42e7dSPeter Dunlap 1685a6d42e7dSPeter Dunlap /* 1686a6d42e7dSPeter Dunlap * Call the buffer callback when the transfer is complete 1687a6d42e7dSPeter Dunlap * 1688a6d42e7dSPeter Dunlap * The connection state machine should only abort tasks after 1689a6d42e7dSPeter Dunlap * shutting down the connection so we are assured that there 1690a6d42e7dSPeter Dunlap * won't be a simultaneous attempt to abort this task at the 1691a6d42e7dSPeter Dunlap * same time as we are processing this PDU (due to a connection 1692a6d42e7dSPeter Dunlap * state change). 1693a6d42e7dSPeter Dunlap */ 1694a6d42e7dSPeter Dunlap if (bhs->flags & ISCSI_FLAG_FINAL) { 1695a6d42e7dSPeter Dunlap /* 1696a6d42e7dSPeter Dunlap * We only want to call idm_buf_rx_from_ini_done once 1697a6d42e7dSPeter Dunlap * per transfer. It's possible that this task has 1698a6d42e7dSPeter Dunlap * already been aborted in which case 1699a6d42e7dSPeter Dunlap * idm_so_free_task_rsrc will call idm_buf_rx_from_ini_done 1700a6d42e7dSPeter Dunlap * for each buffer with idb_in_transport==B_TRUE. To 1701a6d42e7dSPeter Dunlap * close this window and ensure that this doesn't happen, 1702a6d42e7dSPeter Dunlap * we'll clear idb->idb_in_transport now while holding 1703a6d42e7dSPeter Dunlap * the task mutex. This is only really an issue for 1704a6d42e7dSPeter Dunlap * SCSI task abort -- if tasks were being aborted because 1705a6d42e7dSPeter Dunlap * of a connection state change the state machine would 1706a6d42e7dSPeter Dunlap * have already stopped the receive thread. 1707a6d42e7dSPeter Dunlap */ 1708a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 1709a6d42e7dSPeter Dunlap 1710a6d42e7dSPeter Dunlap /* 1711a6d42e7dSPeter Dunlap * Release the task hold here (obtained in idm_task_find) 1712a6d42e7dSPeter Dunlap * because the task may complete synchronously during 1713a6d42e7dSPeter Dunlap * idm_buf_rx_from_ini_done. Since we still have an active 1714a6d42e7dSPeter Dunlap * buffer we know there is at least one additional hold on idt. 1715a6d42e7dSPeter Dunlap */ 1716a6d42e7dSPeter Dunlap idm_task_rele(idt); 1717a6d42e7dSPeter Dunlap 1718a6d42e7dSPeter Dunlap /* 1719a6d42e7dSPeter Dunlap * idm_buf_rx_from_ini_done releases idt->idt_mutex 1720a6d42e7dSPeter Dunlap */ 1721a668b114SPriya Krishnan DTRACE_ISCSI_8(xfer__done, idm_conn_t *, idt->idt_ic, 1722a668b114SPriya Krishnan uintptr_t, idb->idb_buf, uint32_t, idb->idb_bufoffset, 1723a668b114SPriya Krishnan uint64_t, 0, uint32_t, 0, uint32_t, 0, 1724a668b114SPriya Krishnan uint32_t, idb->idb_xfer_len, 1725a668b114SPriya Krishnan int, XFER_BUF_RX_FROM_INI); 1726a6d42e7dSPeter Dunlap idm_buf_rx_from_ini_done(idt, idb, IDM_STATUS_SUCCESS); 1727a6d42e7dSPeter Dunlap idm_pdu_complete(pdu, IDM_STATUS_SUCCESS); 1728a6d42e7dSPeter Dunlap return; 1729a6d42e7dSPeter Dunlap } 1730a6d42e7dSPeter Dunlap 1731a6d42e7dSPeter Dunlap idm_task_rele(idt); 1732a6d42e7dSPeter Dunlap idm_pdu_complete(pdu, IDM_STATUS_SUCCESS); 1733a6d42e7dSPeter Dunlap } 1734a6d42e7dSPeter Dunlap 1735a6d42e7dSPeter Dunlap /* 1736a6d42e7dSPeter Dunlap * The idm_so_rx_rtt() function is used by the iSCSI initiator to handle 1737a6d42e7dSPeter Dunlap * the R2T PDU sent by the iSCSI target indicating that it is ready to 1738a6d42e7dSPeter Dunlap * accept data. This gets the Initiator Task Tag (itt) from the PDU BHS 1739a6d42e7dSPeter Dunlap * and looks up the task in the task tree using the itt to get the output 1740a6d42e7dSPeter Dunlap * buffers associated the task. The R2T PDU contains the offset of the 1741a6d42e7dSPeter Dunlap * requested data and the data length. This function then constructs a 1742a6d42e7dSPeter Dunlap * sequence of iSCSI PDUs and outputs the requested data. Each Data-Out 1743a6d42e7dSPeter Dunlap * PDU is associated with the R2T by the Target Transfer Tag (ttt). 1744a6d42e7dSPeter Dunlap */ 174530e7468fSPeter Dunlap 1746a6d42e7dSPeter Dunlap static void 1747a6d42e7dSPeter Dunlap idm_so_rx_rtt(idm_conn_t *ic, idm_pdu_t *pdu) 1748a6d42e7dSPeter Dunlap { 1749a6d42e7dSPeter Dunlap idm_task_t *idt; 1750a6d42e7dSPeter Dunlap idm_buf_t *idb; 1751a6d42e7dSPeter Dunlap iscsi_rtt_hdr_t *rtt_hdr; 1752a6d42e7dSPeter Dunlap uint32_t data_offset; 175330e7468fSPeter Dunlap uint32_t data_length; 1754a6d42e7dSPeter Dunlap 1755a6d42e7dSPeter Dunlap ASSERT(ic != NULL); 1756a6d42e7dSPeter Dunlap ASSERT(pdu != NULL); 1757a6d42e7dSPeter Dunlap 1758a6d42e7dSPeter Dunlap rtt_hdr = (iscsi_rtt_hdr_t *)pdu->isp_hdr; 1759a6d42e7dSPeter Dunlap data_offset = ntohl(rtt_hdr->data_offset); 176030e7468fSPeter Dunlap data_length = ntohl(rtt_hdr->data_length); 1761a6d42e7dSPeter Dunlap idt = idm_task_find(ic, rtt_hdr->itt, rtt_hdr->ttt); 1762a6d42e7dSPeter Dunlap 1763a6d42e7dSPeter Dunlap if (idt == NULL) { 1764a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, "idm_so_rx_rtt: could not find task"); 1765a6d42e7dSPeter Dunlap idm_pdu_rx_protocol_error(ic, pdu); 1766a6d42e7dSPeter Dunlap return; 1767a6d42e7dSPeter Dunlap } 1768a6d42e7dSPeter Dunlap 1769a6d42e7dSPeter Dunlap /* Find the buffer bound to the task by the iSCSI initiator */ 1770a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 1771a6d42e7dSPeter Dunlap idb = idm_buf_find(&idt->idt_outbufv, data_offset); 1772a6d42e7dSPeter Dunlap if (idb == NULL) { 1773a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1774a6d42e7dSPeter Dunlap idm_task_rele(idt); 1775a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, "idm_so_rx_rtt: could not find buffer"); 1776a6d42e7dSPeter Dunlap idm_pdu_rx_protocol_error(ic, pdu); 1777a6d42e7dSPeter Dunlap return; 1778a6d42e7dSPeter Dunlap } 1779a6d42e7dSPeter Dunlap 178030e7468fSPeter Dunlap /* return buffer contains this data */ 178130e7468fSPeter Dunlap if (data_offset + data_length > idb->idb_buflen) { 178230e7468fSPeter Dunlap /* Overflow */ 178330e7468fSPeter Dunlap mutex_exit(&idt->idt_mutex); 178430e7468fSPeter Dunlap idm_task_rele(idt); 178530e7468fSPeter Dunlap IDM_CONN_LOG(CE_WARN, "idm_so_rx_rtt: read from outside " 178630e7468fSPeter Dunlap "buffer"); 178730e7468fSPeter Dunlap idm_pdu_rx_protocol_error(ic, pdu); 178830e7468fSPeter Dunlap return; 178930e7468fSPeter Dunlap } 179030e7468fSPeter Dunlap 179130e7468fSPeter Dunlap idt->idt_r2t_ttt = rtt_hdr->ttt; 179230e7468fSPeter Dunlap idt->idt_exp_datasn = 0; 179330e7468fSPeter Dunlap 179430e7468fSPeter Dunlap idm_so_send_rtt_data(ic, idt, idb, data_offset, 179530e7468fSPeter Dunlap ntohl(rtt_hdr->data_length)); 1796a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1797a6d42e7dSPeter Dunlap 1798a6d42e7dSPeter Dunlap idm_pdu_complete(pdu, IDM_STATUS_SUCCESS); 1799a6d42e7dSPeter Dunlap idm_task_rele(idt); 1800a6d42e7dSPeter Dunlap 1801a6d42e7dSPeter Dunlap } 1802a6d42e7dSPeter Dunlap 1803a6d42e7dSPeter Dunlap idm_status_t 1804a6d42e7dSPeter Dunlap idm_sorecvdata(idm_conn_t *ic, idm_pdu_t *pdu) 1805a6d42e7dSPeter Dunlap { 1806a6d42e7dSPeter Dunlap uint8_t pad[ISCSI_PAD_WORD_LEN]; 1807a6d42e7dSPeter Dunlap int pad_len; 1808a6d42e7dSPeter Dunlap uint32_t data_digest_crc; 1809a6d42e7dSPeter Dunlap uint32_t crc_calculated; 1810a6d42e7dSPeter Dunlap int total_len; 1811a6d42e7dSPeter Dunlap idm_so_conn_t *so_conn; 1812a6d42e7dSPeter Dunlap 1813a6d42e7dSPeter Dunlap so_conn = ic->ic_transport_private; 1814a6d42e7dSPeter Dunlap 1815a6d42e7dSPeter Dunlap pad_len = ((ISCSI_PAD_WORD_LEN - 1816a6d42e7dSPeter Dunlap (pdu->isp_datalen & (ISCSI_PAD_WORD_LEN - 1))) & 1817a6d42e7dSPeter Dunlap (ISCSI_PAD_WORD_LEN - 1)); 1818a6d42e7dSPeter Dunlap 1819a6d42e7dSPeter Dunlap ASSERT(pdu->isp_iovlen < (PDU_MAX_IOVLEN - 2)); /* pad + data digest */ 1820a6d42e7dSPeter Dunlap 1821a6d42e7dSPeter Dunlap total_len = pdu->isp_datalen; 1822a6d42e7dSPeter Dunlap 1823a6d42e7dSPeter Dunlap if (pad_len) { 1824a6d42e7dSPeter Dunlap pdu->isp_iov[pdu->isp_iovlen].iov_base = (char *)&pad; 1825a6d42e7dSPeter Dunlap pdu->isp_iov[pdu->isp_iovlen].iov_len = pad_len; 1826a6d42e7dSPeter Dunlap total_len += pad_len; 1827a6d42e7dSPeter Dunlap pdu->isp_iovlen++; 1828a6d42e7dSPeter Dunlap } 1829a6d42e7dSPeter Dunlap 1830a6d42e7dSPeter Dunlap /* setup data digest */ 1831a6d42e7dSPeter Dunlap if ((ic->ic_conn_flags & IDM_CONN_DATA_DIGEST) != 0) { 1832a6d42e7dSPeter Dunlap pdu->isp_iov[pdu->isp_iovlen].iov_base = 1833a6d42e7dSPeter Dunlap (char *)&data_digest_crc; 1834a6d42e7dSPeter Dunlap pdu->isp_iov[pdu->isp_iovlen].iov_len = 1835a6d42e7dSPeter Dunlap sizeof (data_digest_crc); 1836a6d42e7dSPeter Dunlap total_len += sizeof (data_digest_crc); 1837a6d42e7dSPeter Dunlap pdu->isp_iovlen++; 1838a6d42e7dSPeter Dunlap } 1839a6d42e7dSPeter Dunlap 184030e7468fSPeter Dunlap pdu->isp_data = (uint8_t *)(uintptr_t)pdu->isp_iov[0].iov_base; 184130e7468fSPeter Dunlap 1842a6d42e7dSPeter Dunlap if (idm_iov_sorecv(so_conn->ic_so, &pdu->isp_iov[0], 1843a6d42e7dSPeter Dunlap pdu->isp_iovlen, total_len) != 0) { 1844a6d42e7dSPeter Dunlap return (IDM_STATUS_IO); 1845a6d42e7dSPeter Dunlap } 1846a6d42e7dSPeter Dunlap 1847a6d42e7dSPeter Dunlap if ((ic->ic_conn_flags & IDM_CONN_DATA_DIGEST) != 0) { 1848a6d42e7dSPeter Dunlap crc_calculated = idm_crc32c(pdu->isp_data, 1849a6d42e7dSPeter Dunlap pdu->isp_datalen); 1850a6d42e7dSPeter Dunlap if (pad_len) { 1851a6d42e7dSPeter Dunlap crc_calculated = idm_crc32c_continued((char *)&pad, 1852a6d42e7dSPeter Dunlap pad_len, crc_calculated); 1853a6d42e7dSPeter Dunlap } 1854a6d42e7dSPeter Dunlap if (crc_calculated != data_digest_crc) { 1855a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, 1856a6d42e7dSPeter Dunlap "idm_sorecvdata: " 1857a6d42e7dSPeter Dunlap "CRC error: actual 0x%x, calc 0x%x", 1858a6d42e7dSPeter Dunlap data_digest_crc, crc_calculated); 1859a6d42e7dSPeter Dunlap 1860a6d42e7dSPeter Dunlap /* Invalid Data Digest */ 1861a6d42e7dSPeter Dunlap return (IDM_STATUS_DATA_DIGEST); 1862a6d42e7dSPeter Dunlap } 1863a6d42e7dSPeter Dunlap } 1864a6d42e7dSPeter Dunlap 1865a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 1866a6d42e7dSPeter Dunlap } 1867a6d42e7dSPeter Dunlap 1868a6d42e7dSPeter Dunlap /* 1869a6d42e7dSPeter Dunlap * idm_sorecv_scsidata() is used to receive scsi data from the socket. The 1870a6d42e7dSPeter Dunlap * Data-type PDU header must be read into the idm_pdu_t structure prior to 1871a6d42e7dSPeter Dunlap * calling this function. 1872a6d42e7dSPeter Dunlap */ 1873a6d42e7dSPeter Dunlap idm_status_t 1874a6d42e7dSPeter Dunlap idm_sorecv_scsidata(idm_conn_t *ic, idm_pdu_t *pdu) 1875a6d42e7dSPeter Dunlap { 1876a6d42e7dSPeter Dunlap iscsi_data_hdr_t *bhs; 1877a6d42e7dSPeter Dunlap idm_task_t *task; 1878a6d42e7dSPeter Dunlap uint32_t offset; 1879a6d42e7dSPeter Dunlap uint8_t opcode; 1880a6d42e7dSPeter Dunlap uint32_t dlength; 1881a6d42e7dSPeter Dunlap list_t *buflst; 1882a6d42e7dSPeter Dunlap uint32_t xfer_bytes; 1883a6d42e7dSPeter Dunlap idm_status_t status; 1884a6d42e7dSPeter Dunlap 1885a6d42e7dSPeter Dunlap ASSERT(ic != NULL); 1886a6d42e7dSPeter Dunlap ASSERT(pdu != NULL); 1887a6d42e7dSPeter Dunlap 1888a6d42e7dSPeter Dunlap bhs = (iscsi_data_hdr_t *)pdu->isp_hdr; 1889a6d42e7dSPeter Dunlap 1890a6d42e7dSPeter Dunlap offset = ntohl(bhs->offset); 1891a6d42e7dSPeter Dunlap opcode = bhs->opcode; 1892a6d42e7dSPeter Dunlap dlength = n2h24(bhs->dlength); 1893a6d42e7dSPeter Dunlap 1894a6d42e7dSPeter Dunlap ASSERT((opcode == ISCSI_OP_SCSI_DATA_RSP) || 1895a6d42e7dSPeter Dunlap (opcode == ISCSI_OP_SCSI_DATA)); 1896a6d42e7dSPeter Dunlap 1897a6d42e7dSPeter Dunlap /* 1898a6d42e7dSPeter Dunlap * Successful lookup implicitly gets a "hold" on the task. This 1899a6d42e7dSPeter Dunlap * hold must be released before leaving this function. At one 1900a6d42e7dSPeter Dunlap * point we were caching this task context and retaining the hold 1901a6d42e7dSPeter Dunlap * but it turned out to be very difficult to release the hold properly. 1902a6d42e7dSPeter Dunlap * The task can be aborted and the connection shutdown between this 1903a6d42e7dSPeter Dunlap * call and the subsequent expected call to idm_so_rx_datain/ 1904a6d42e7dSPeter Dunlap * idm_so_rx_dataout (in which case those functions are not called). 1905a6d42e7dSPeter Dunlap * Releasing the hold in the PDU callback doesn't work well either 1906a6d42e7dSPeter Dunlap * because the whole task may be completed by then at which point 1907a6d42e7dSPeter Dunlap * it is too late to release the hold -- for better or worse this 1908a6d42e7dSPeter Dunlap * code doesn't wait on the refcnts during normal operation. 1909a6d42e7dSPeter Dunlap * idm_task_find() is very fast and it is not a huge burden if we 1910a6d42e7dSPeter Dunlap * have to do it twice. 1911a6d42e7dSPeter Dunlap */ 1912a6d42e7dSPeter Dunlap task = idm_task_find(ic, bhs->itt, bhs->ttt); 1913a6d42e7dSPeter Dunlap if (task == NULL) { 1914a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, 1915a6d42e7dSPeter Dunlap "idm_sorecv_scsidata: could not find task"); 1916a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 1917a6d42e7dSPeter Dunlap } 1918a6d42e7dSPeter Dunlap 1919a6d42e7dSPeter Dunlap mutex_enter(&task->idt_mutex); 1920a6d42e7dSPeter Dunlap buflst = (opcode == ISCSI_OP_SCSI_DATA_RSP) ? 1921a6d42e7dSPeter Dunlap &task->idt_inbufv : &task->idt_outbufv; 1922a6d42e7dSPeter Dunlap pdu->isp_sorx_buf = idm_buf_find(buflst, offset); 1923a6d42e7dSPeter Dunlap mutex_exit(&task->idt_mutex); 1924a6d42e7dSPeter Dunlap 1925a6d42e7dSPeter Dunlap if (pdu->isp_sorx_buf == NULL) { 1926a6d42e7dSPeter Dunlap idm_task_rele(task); 1927a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, "idm_sorecv_scsidata: could not find " 1928a6d42e7dSPeter Dunlap "buffer for offset %x opcode=%x", 1929a6d42e7dSPeter Dunlap offset, opcode); 1930a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 1931a6d42e7dSPeter Dunlap } 1932a6d42e7dSPeter Dunlap 1933a6d42e7dSPeter Dunlap xfer_bytes = idm_fill_iov(pdu, pdu->isp_sorx_buf, offset, dlength); 1934a6d42e7dSPeter Dunlap ASSERT(xfer_bytes != 0); 1935a6d42e7dSPeter Dunlap if (xfer_bytes != dlength) { 1936a6d42e7dSPeter Dunlap idm_task_rele(task); 1937a6d42e7dSPeter Dunlap /* 1938a6d42e7dSPeter Dunlap * Buffer overflow, connection error. The PDU data is still 1939a6d42e7dSPeter Dunlap * sitting in the socket so we can't use the connection 1940a6d42e7dSPeter Dunlap * again until that data is drained. 1941a6d42e7dSPeter Dunlap */ 1942a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 1943a6d42e7dSPeter Dunlap } 1944a6d42e7dSPeter Dunlap 1945a6d42e7dSPeter Dunlap status = idm_sorecvdata(ic, pdu); 1946a6d42e7dSPeter Dunlap 1947a6d42e7dSPeter Dunlap idm_task_rele(task); 1948a6d42e7dSPeter Dunlap 1949a6d42e7dSPeter Dunlap return (status); 1950a6d42e7dSPeter Dunlap } 1951a6d42e7dSPeter Dunlap 1952a6d42e7dSPeter Dunlap static uint32_t 1953a6d42e7dSPeter Dunlap idm_fill_iov(idm_pdu_t *pdu, idm_buf_t *idb, uint32_t ro, uint32_t dlength) 1954a6d42e7dSPeter Dunlap { 1955a6d42e7dSPeter Dunlap uint32_t buf_ro = ro - idb->idb_bufoffset; 1956a6d42e7dSPeter Dunlap uint32_t xfer_len = min(dlength, idb->idb_buflen - buf_ro); 1957a6d42e7dSPeter Dunlap 1958a6d42e7dSPeter Dunlap ASSERT(ro >= idb->idb_bufoffset); 1959a6d42e7dSPeter Dunlap 1960a6d42e7dSPeter Dunlap pdu->isp_iov[pdu->isp_iovlen].iov_base = 1961a6d42e7dSPeter Dunlap (caddr_t)idb->idb_buf + buf_ro; 1962a6d42e7dSPeter Dunlap pdu->isp_iov[pdu->isp_iovlen].iov_len = xfer_len; 1963a6d42e7dSPeter Dunlap pdu->isp_iovlen++; 1964a6d42e7dSPeter Dunlap 1965a6d42e7dSPeter Dunlap return (xfer_len); 1966a6d42e7dSPeter Dunlap } 1967a6d42e7dSPeter Dunlap 1968a6d42e7dSPeter Dunlap int 1969a6d42e7dSPeter Dunlap idm_sorecv_nonscsidata(idm_conn_t *ic, idm_pdu_t *pdu) 1970a6d42e7dSPeter Dunlap { 1971a6d42e7dSPeter Dunlap pdu->isp_data = kmem_alloc(pdu->isp_datalen, KM_SLEEP); 1972a6d42e7dSPeter Dunlap ASSERT(pdu->isp_data != NULL); 1973a6d42e7dSPeter Dunlap 1974a6d42e7dSPeter Dunlap pdu->isp_databuflen = pdu->isp_datalen; 1975a6d42e7dSPeter Dunlap pdu->isp_iov[0].iov_base = (caddr_t)pdu->isp_data; 1976a6d42e7dSPeter Dunlap pdu->isp_iov[0].iov_len = pdu->isp_datalen; 1977a6d42e7dSPeter Dunlap pdu->isp_iovlen = 1; 1978a6d42e7dSPeter Dunlap /* 1979a6d42e7dSPeter Dunlap * Since we are associating a new data buffer with this received 1980a6d42e7dSPeter Dunlap * PDU we need to set a specific callback to free the data 1981a6d42e7dSPeter Dunlap * after the PDU is processed. 1982a6d42e7dSPeter Dunlap */ 1983a6d42e7dSPeter Dunlap pdu->isp_flags |= IDM_PDU_ADDL_DATA; 1984a6d42e7dSPeter Dunlap pdu->isp_callback = idm_sorx_addl_pdu_cb; 1985a6d42e7dSPeter Dunlap 1986a6d42e7dSPeter Dunlap return (idm_sorecvdata(ic, pdu)); 1987a6d42e7dSPeter Dunlap } 1988a6d42e7dSPeter Dunlap 1989a6d42e7dSPeter Dunlap void 1990a6d42e7dSPeter Dunlap idm_sorx_thread(void *arg) 1991a6d42e7dSPeter Dunlap { 1992a6d42e7dSPeter Dunlap boolean_t conn_failure = B_FALSE; 1993a6d42e7dSPeter Dunlap idm_conn_t *ic = (idm_conn_t *)arg; 1994a6d42e7dSPeter Dunlap idm_so_conn_t *so_conn; 1995a6d42e7dSPeter Dunlap idm_pdu_t *pdu; 1996a6d42e7dSPeter Dunlap idm_status_t rc; 1997a6d42e7dSPeter Dunlap 1998a6d42e7dSPeter Dunlap idm_conn_hold(ic); 1999a6d42e7dSPeter Dunlap 2000a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_mutex); 2001a6d42e7dSPeter Dunlap 2002a6d42e7dSPeter Dunlap so_conn = ic->ic_transport_private; 2003a6d42e7dSPeter Dunlap so_conn->ic_rx_thread_running = B_TRUE; 2004a6d42e7dSPeter Dunlap so_conn->ic_rx_thread_did = so_conn->ic_rx_thread->t_did; 2005a6d42e7dSPeter Dunlap cv_signal(&ic->ic_cv); 2006a6d42e7dSPeter Dunlap 2007a6d42e7dSPeter Dunlap while (so_conn->ic_rx_thread_running) { 2008a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_mutex); 2009a6d42e7dSPeter Dunlap 2010a6d42e7dSPeter Dunlap /* 2011a6d42e7dSPeter Dunlap * Get PDU with default header size (large enough for 2012a6d42e7dSPeter Dunlap * BHS plus any anticipated AHS). PDU from 2013a6d42e7dSPeter Dunlap * the cache will have all values set correctly 2014a6d42e7dSPeter Dunlap * for sockets RX including callback. 2015a6d42e7dSPeter Dunlap */ 2016a6d42e7dSPeter Dunlap pdu = kmem_cache_alloc(idm.idm_sorx_pdu_cache, KM_SLEEP); 2017a6d42e7dSPeter Dunlap pdu->isp_ic = ic; 2018a6d42e7dSPeter Dunlap pdu->isp_flags = 0; 2019a6d42e7dSPeter Dunlap pdu->isp_transport_hdrlen = 0; 2020a6d42e7dSPeter Dunlap 2021a6d42e7dSPeter Dunlap if ((rc = idm_sorecvhdr(ic, pdu)) != 0) { 2022a6d42e7dSPeter Dunlap /* 2023a6d42e7dSPeter Dunlap * Call idm_pdu_complete so that we call the callback 2024a6d42e7dSPeter Dunlap * and ensure any memory allocated in idm_sorecvhdr 2025a6d42e7dSPeter Dunlap * gets freed up. 2026a6d42e7dSPeter Dunlap */ 2027a6d42e7dSPeter Dunlap idm_pdu_complete(pdu, IDM_STATUS_FAIL); 2028a6d42e7dSPeter Dunlap 2029a6d42e7dSPeter Dunlap /* 2030a6d42e7dSPeter Dunlap * If ic_rx_thread_running is still set then 2031a6d42e7dSPeter Dunlap * this is some kind of connection problem 2032a6d42e7dSPeter Dunlap * on the socket. In this case we want to 2033a6d42e7dSPeter Dunlap * generate an event. Otherwise some other 2034a6d42e7dSPeter Dunlap * thread closed the socket due to another 2035a6d42e7dSPeter Dunlap * issue in which case we don't need to 2036a6d42e7dSPeter Dunlap * generate an event. 2037a6d42e7dSPeter Dunlap */ 2038a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_mutex); 2039a6d42e7dSPeter Dunlap if (so_conn->ic_rx_thread_running) { 2040a6d42e7dSPeter Dunlap conn_failure = B_TRUE; 2041a6d42e7dSPeter Dunlap so_conn->ic_rx_thread_running = B_FALSE; 2042a6d42e7dSPeter Dunlap } 2043a6d42e7dSPeter Dunlap 2044a6d42e7dSPeter Dunlap continue; 2045a6d42e7dSPeter Dunlap } 2046a6d42e7dSPeter Dunlap 2047a6d42e7dSPeter Dunlap /* 2048a6d42e7dSPeter Dunlap * Header has been read and validated. Now we need 2049a6d42e7dSPeter Dunlap * to read the PDU data payload (if present). SCSI data 2050a6d42e7dSPeter Dunlap * need to be transferred from the socket directly into 2051a6d42e7dSPeter Dunlap * the associated transfer buffer for the SCSI task. 2052a6d42e7dSPeter Dunlap */ 2053a6d42e7dSPeter Dunlap if (pdu->isp_datalen != 0) { 2054a6d42e7dSPeter Dunlap if ((IDM_PDU_OPCODE(pdu) == ISCSI_OP_SCSI_DATA) || 2055a6d42e7dSPeter Dunlap (IDM_PDU_OPCODE(pdu) == ISCSI_OP_SCSI_DATA_RSP)) { 2056a6d42e7dSPeter Dunlap rc = idm_sorecv_scsidata(ic, pdu); 2057a6d42e7dSPeter Dunlap /* 2058a6d42e7dSPeter Dunlap * All SCSI errors are fatal to the 2059a6d42e7dSPeter Dunlap * connection right now since we have no 2060a6d42e7dSPeter Dunlap * place to put the data. What we need 2061a6d42e7dSPeter Dunlap * is some kind of sink to dispose of unwanted 2062a6d42e7dSPeter Dunlap * SCSI data. For example an invalid task tag 2063a6d42e7dSPeter Dunlap * should not kill the connection (although 2064a6d42e7dSPeter Dunlap * we may want to drop the connection). 2065a6d42e7dSPeter Dunlap */ 2066a6d42e7dSPeter Dunlap } else { 2067a6d42e7dSPeter Dunlap /* 2068a6d42e7dSPeter Dunlap * Not data PDUs so allocate a buffer for the 2069a6d42e7dSPeter Dunlap * data segment and read the remaining data. 2070a6d42e7dSPeter Dunlap */ 2071a6d42e7dSPeter Dunlap rc = idm_sorecv_nonscsidata(ic, pdu); 2072a6d42e7dSPeter Dunlap } 2073a6d42e7dSPeter Dunlap if (rc != 0) { 2074a6d42e7dSPeter Dunlap /* 2075a6d42e7dSPeter Dunlap * Call idm_pdu_complete so that we call the 2076a6d42e7dSPeter Dunlap * callback and ensure any memory allocated 2077a6d42e7dSPeter Dunlap * in idm_sorecvhdr gets freed up. 2078a6d42e7dSPeter Dunlap */ 2079a6d42e7dSPeter Dunlap idm_pdu_complete(pdu, IDM_STATUS_FAIL); 2080a6d42e7dSPeter Dunlap 2081a6d42e7dSPeter Dunlap /* 2082a6d42e7dSPeter Dunlap * If ic_rx_thread_running is still set then 2083a6d42e7dSPeter Dunlap * this is some kind of connection problem 2084a6d42e7dSPeter Dunlap * on the socket. In this case we want to 2085a6d42e7dSPeter Dunlap * generate an event. Otherwise some other 2086a6d42e7dSPeter Dunlap * thread closed the socket due to another 2087a6d42e7dSPeter Dunlap * issue in which case we don't need to 2088a6d42e7dSPeter Dunlap * generate an event. 2089a6d42e7dSPeter Dunlap */ 2090a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_mutex); 2091a6d42e7dSPeter Dunlap if (so_conn->ic_rx_thread_running) { 2092a6d42e7dSPeter Dunlap conn_failure = B_TRUE; 2093a6d42e7dSPeter Dunlap so_conn->ic_rx_thread_running = B_FALSE; 2094a6d42e7dSPeter Dunlap } 2095a6d42e7dSPeter Dunlap continue; 2096a6d42e7dSPeter Dunlap } 2097a6d42e7dSPeter Dunlap } 2098a6d42e7dSPeter Dunlap 2099a6d42e7dSPeter Dunlap /* 2100a6d42e7dSPeter Dunlap * Process RX PDU 2101a6d42e7dSPeter Dunlap */ 2102a6d42e7dSPeter Dunlap idm_pdu_rx(ic, pdu); 2103a6d42e7dSPeter Dunlap 2104a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_mutex); 2105a6d42e7dSPeter Dunlap } 2106a6d42e7dSPeter Dunlap 2107a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_mutex); 2108a6d42e7dSPeter Dunlap 2109a6d42e7dSPeter Dunlap /* 2110a6d42e7dSPeter Dunlap * If we dropped out of the RX processing loop because of 2111a6d42e7dSPeter Dunlap * a socket problem or other connection failure (including 2112a6d42e7dSPeter Dunlap * digest errors) then we need to generate a state machine 2113a6d42e7dSPeter Dunlap * event to shut the connection down. 2114a6d42e7dSPeter Dunlap * If the state machine is already in, for example, INIT_ERROR, this 2115a6d42e7dSPeter Dunlap * event will get dropped, and the TX thread will never be notified 2116a6d42e7dSPeter Dunlap * to shut down. To be safe, we'll just notify it here. 2117a6d42e7dSPeter Dunlap */ 2118a6d42e7dSPeter Dunlap if (conn_failure) { 2119a6d42e7dSPeter Dunlap if (so_conn->ic_tx_thread_running) { 2120a6d42e7dSPeter Dunlap so_conn->ic_tx_thread_running = B_FALSE; 2121a6d42e7dSPeter Dunlap mutex_enter(&so_conn->ic_tx_mutex); 2122a6d42e7dSPeter Dunlap cv_signal(&so_conn->ic_tx_cv); 2123a6d42e7dSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 2124a6d42e7dSPeter Dunlap } 2125a6d42e7dSPeter Dunlap 2126a6d42e7dSPeter Dunlap idm_conn_event(ic, CE_TRANSPORT_FAIL, rc); 2127a6d42e7dSPeter Dunlap } 2128a6d42e7dSPeter Dunlap 2129a6d42e7dSPeter Dunlap idm_conn_rele(ic); 2130a6d42e7dSPeter Dunlap 2131a6d42e7dSPeter Dunlap thread_exit(); 2132a6d42e7dSPeter Dunlap } 2133a6d42e7dSPeter Dunlap 2134a6d42e7dSPeter Dunlap /* 2135a6d42e7dSPeter Dunlap * idm_so_tx 2136a6d42e7dSPeter Dunlap * 2137a6d42e7dSPeter Dunlap * This is the implementation of idm_transport_ops_t's it_tx_pdu entry 2138a6d42e7dSPeter Dunlap * point. By definition, it is supposed to be fast. So, simply queue 2139a6d42e7dSPeter Dunlap * the entry and return. The real work is done by idm_i_so_tx() via 2140a6d42e7dSPeter Dunlap * idm_sotx_thread(). 2141a6d42e7dSPeter Dunlap */ 2142a6d42e7dSPeter Dunlap 2143a6d42e7dSPeter Dunlap static void 2144a6d42e7dSPeter Dunlap idm_so_tx(idm_conn_t *ic, idm_pdu_t *pdu) 2145a6d42e7dSPeter Dunlap { 2146a6d42e7dSPeter Dunlap idm_so_conn_t *so_conn = ic->ic_transport_private; 2147a6d42e7dSPeter Dunlap 2148a6d42e7dSPeter Dunlap ASSERT(pdu->isp_ic == ic); 2149a6d42e7dSPeter Dunlap mutex_enter(&so_conn->ic_tx_mutex); 2150a6d42e7dSPeter Dunlap 2151a6d42e7dSPeter Dunlap if (!so_conn->ic_tx_thread_running) { 2152a6d42e7dSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 2153a6d42e7dSPeter Dunlap idm_pdu_complete(pdu, IDM_STATUS_ABORTED); 2154a6d42e7dSPeter Dunlap return; 2155a6d42e7dSPeter Dunlap } 2156a6d42e7dSPeter Dunlap 2157a6d42e7dSPeter Dunlap list_insert_tail(&so_conn->ic_tx_list, (void *)pdu); 2158a6d42e7dSPeter Dunlap cv_signal(&so_conn->ic_tx_cv); 2159a6d42e7dSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 2160a6d42e7dSPeter Dunlap } 2161a6d42e7dSPeter Dunlap 2162a6d42e7dSPeter Dunlap static idm_status_t 2163a6d42e7dSPeter Dunlap idm_i_so_tx(idm_pdu_t *pdu) 2164a6d42e7dSPeter Dunlap { 2165a6d42e7dSPeter Dunlap idm_conn_t *ic = pdu->isp_ic; 2166a6d42e7dSPeter Dunlap idm_status_t status = IDM_STATUS_SUCCESS; 2167a6d42e7dSPeter Dunlap uint8_t pad[ISCSI_PAD_WORD_LEN]; 2168a6d42e7dSPeter Dunlap int pad_len; 2169a6d42e7dSPeter Dunlap uint32_t hdr_digest_crc; 2170a6d42e7dSPeter Dunlap uint32_t data_digest_crc = 0; 2171a6d42e7dSPeter Dunlap int total_len = 0; 2172a6d42e7dSPeter Dunlap int iovlen = 0; 2173a6d42e7dSPeter Dunlap struct iovec iov[6]; 2174a6d42e7dSPeter Dunlap idm_so_conn_t *so_conn; 2175a6d42e7dSPeter Dunlap 2176a6d42e7dSPeter Dunlap so_conn = ic->ic_transport_private; 2177a6d42e7dSPeter Dunlap 2178a6d42e7dSPeter Dunlap /* Setup BHS */ 2179a6d42e7dSPeter Dunlap iov[iovlen].iov_base = (caddr_t)pdu->isp_hdr; 2180a6d42e7dSPeter Dunlap iov[iovlen].iov_len = pdu->isp_hdrlen; 2181a6d42e7dSPeter Dunlap total_len += iov[iovlen].iov_len; 2182a6d42e7dSPeter Dunlap iovlen++; 2183a6d42e7dSPeter Dunlap 2184a6d42e7dSPeter Dunlap /* Setup header digest */ 2185a6d42e7dSPeter Dunlap if (((pdu->isp_flags & IDM_PDU_LOGIN_TX) == 0) && 2186a6d42e7dSPeter Dunlap (ic->ic_conn_flags & IDM_CONN_HEADER_DIGEST)) { 2187a6d42e7dSPeter Dunlap hdr_digest_crc = idm_crc32c(pdu->isp_hdr, pdu->isp_hdrlen); 2188a6d42e7dSPeter Dunlap 2189a6d42e7dSPeter Dunlap iov[iovlen].iov_base = (caddr_t)&hdr_digest_crc; 2190a6d42e7dSPeter Dunlap iov[iovlen].iov_len = sizeof (hdr_digest_crc); 2191a6d42e7dSPeter Dunlap total_len += iov[iovlen].iov_len; 2192a6d42e7dSPeter Dunlap iovlen++; 2193a6d42e7dSPeter Dunlap } 2194a6d42e7dSPeter Dunlap 2195a6d42e7dSPeter Dunlap /* Setup the data */ 2196a6d42e7dSPeter Dunlap if (pdu->isp_datalen) { 2197a6d42e7dSPeter Dunlap idm_task_t *idt; 2198a6d42e7dSPeter Dunlap idm_buf_t *idb; 2199a6d42e7dSPeter Dunlap iscsi_data_hdr_t *ihp; 2200a6d42e7dSPeter Dunlap ihp = (iscsi_data_hdr_t *)pdu->isp_hdr; 2201a6d42e7dSPeter Dunlap /* Write of immediate data */ 2202a6d42e7dSPeter Dunlap if (ic->ic_ffp && 2203a6d42e7dSPeter Dunlap (ihp->opcode == ISCSI_OP_SCSI_CMD || 2204a6d42e7dSPeter Dunlap ihp->opcode == ISCSI_OP_SCSI_DATA)) { 2205a6d42e7dSPeter Dunlap idt = idm_task_find(ic, ihp->itt, ihp->ttt); 2206a6d42e7dSPeter Dunlap if (idt) { 2207a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 2208a6d42e7dSPeter Dunlap idb = idm_buf_find(&idt->idt_outbufv, 0); 2209a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 221030e7468fSPeter Dunlap /* 221130e7468fSPeter Dunlap * If the initiator call to idm_buf_alloc 221230e7468fSPeter Dunlap * failed then we can get to this point 221330e7468fSPeter Dunlap * without a bound buffer. The associated 221430e7468fSPeter Dunlap * connection failure will clean things up 221530e7468fSPeter Dunlap * later. It would be nice to come up with 221630e7468fSPeter Dunlap * a cleaner way to handle this. In 221730e7468fSPeter Dunlap * particular it seems absurd to look up 221830e7468fSPeter Dunlap * the task and the buffer just to update 221930e7468fSPeter Dunlap * this counter. 222030e7468fSPeter Dunlap */ 222130e7468fSPeter Dunlap if (idb) 222230e7468fSPeter Dunlap idb->idb_xfer_len += pdu->isp_datalen; 222330e7468fSPeter Dunlap idm_task_rele(idt); 2224a6d42e7dSPeter Dunlap } 2225a6d42e7dSPeter Dunlap } 2226a6d42e7dSPeter Dunlap 2227a6d42e7dSPeter Dunlap iov[iovlen].iov_base = (caddr_t)pdu->isp_data; 2228a6d42e7dSPeter Dunlap iov[iovlen].iov_len = pdu->isp_datalen; 2229a6d42e7dSPeter Dunlap total_len += iov[iovlen].iov_len; 2230a6d42e7dSPeter Dunlap iovlen++; 2231a6d42e7dSPeter Dunlap } 2232a6d42e7dSPeter Dunlap 2233a6d42e7dSPeter Dunlap /* Setup the data pad if necessary */ 2234a6d42e7dSPeter Dunlap pad_len = ((ISCSI_PAD_WORD_LEN - 2235a6d42e7dSPeter Dunlap (pdu->isp_datalen & (ISCSI_PAD_WORD_LEN - 1))) & 2236a6d42e7dSPeter Dunlap (ISCSI_PAD_WORD_LEN - 1)); 2237a6d42e7dSPeter Dunlap 2238a6d42e7dSPeter Dunlap if (pad_len) { 2239a6d42e7dSPeter Dunlap bzero(pad, sizeof (pad)); 2240a6d42e7dSPeter Dunlap iov[iovlen].iov_base = (void *)&pad; 2241a6d42e7dSPeter Dunlap iov[iovlen].iov_len = pad_len; 2242a6d42e7dSPeter Dunlap total_len += iov[iovlen].iov_len; 2243a6d42e7dSPeter Dunlap iovlen++; 2244a6d42e7dSPeter Dunlap } 2245a6d42e7dSPeter Dunlap 2246a6d42e7dSPeter Dunlap /* 2247a6d42e7dSPeter Dunlap * Setup the data digest if enabled. Data-digest is not sent 2248a6d42e7dSPeter Dunlap * for login-phase PDUs. 2249a6d42e7dSPeter Dunlap */ 2250a6d42e7dSPeter Dunlap if ((ic->ic_conn_flags & IDM_CONN_DATA_DIGEST) && 2251a6d42e7dSPeter Dunlap ((pdu->isp_flags & IDM_PDU_LOGIN_TX) == 0) && 2252a6d42e7dSPeter Dunlap (pdu->isp_datalen || pad_len)) { 2253a6d42e7dSPeter Dunlap /* 2254a6d42e7dSPeter Dunlap * RFC3720/10.2.3: A zero-length Data Segment also 2255a6d42e7dSPeter Dunlap * implies a zero-length data digest. 2256a6d42e7dSPeter Dunlap */ 2257a6d42e7dSPeter Dunlap if (pdu->isp_datalen) { 2258a6d42e7dSPeter Dunlap data_digest_crc = idm_crc32c(pdu->isp_data, 2259a6d42e7dSPeter Dunlap pdu->isp_datalen); 2260a6d42e7dSPeter Dunlap } 2261a6d42e7dSPeter Dunlap if (pad_len) { 2262a6d42e7dSPeter Dunlap data_digest_crc = idm_crc32c_continued(&pad, 2263a6d42e7dSPeter Dunlap pad_len, data_digest_crc); 2264a6d42e7dSPeter Dunlap } 2265a6d42e7dSPeter Dunlap 2266a6d42e7dSPeter Dunlap iov[iovlen].iov_base = (caddr_t)&data_digest_crc; 2267a6d42e7dSPeter Dunlap iov[iovlen].iov_len = sizeof (data_digest_crc); 2268a6d42e7dSPeter Dunlap total_len += iov[iovlen].iov_len; 2269a6d42e7dSPeter Dunlap iovlen++; 2270a6d42e7dSPeter Dunlap } 2271a6d42e7dSPeter Dunlap 2272a6d42e7dSPeter Dunlap /* Transmit the PDU */ 2273a6d42e7dSPeter Dunlap if (idm_iov_sosend(so_conn->ic_so, &iov[0], iovlen, 2274a6d42e7dSPeter Dunlap total_len) != 0) { 2275a6d42e7dSPeter Dunlap /* Set error status */ 2276a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, 2277a6d42e7dSPeter Dunlap "idm_so_tx: failed to transmit the PDU, so: %p ic: %p " 2278a6d42e7dSPeter Dunlap "data: %p", (void *) so_conn->ic_so, (void *) ic, 2279a6d42e7dSPeter Dunlap (void *) pdu->isp_data); 2280a6d42e7dSPeter Dunlap status = IDM_STATUS_IO; 2281a6d42e7dSPeter Dunlap } 2282a6d42e7dSPeter Dunlap 2283a6d42e7dSPeter Dunlap /* 2284a6d42e7dSPeter Dunlap * Success does not mean that the PDU actually reached the 2285a6d42e7dSPeter Dunlap * remote node since it could get dropped along the way. 2286a6d42e7dSPeter Dunlap */ 2287a6d42e7dSPeter Dunlap idm_pdu_complete(pdu, status); 2288a6d42e7dSPeter Dunlap 2289a6d42e7dSPeter Dunlap return (status); 2290a6d42e7dSPeter Dunlap } 2291a6d42e7dSPeter Dunlap 2292a6d42e7dSPeter Dunlap /* 2293a6d42e7dSPeter Dunlap * The idm_so_buf_tx_to_ini() is used by the target iSCSI layer to transmit the 2294a6d42e7dSPeter Dunlap * Data-In PDUs using sockets. Based on the negotiated MaxRecvDataSegmentLength, 2295a6d42e7dSPeter Dunlap * the buffer is segmented into a sequence of Data-In PDUs, ordered by DataSN. 2296a6d42e7dSPeter Dunlap * A target can invoke this function multiple times for a single read command 2297a6d42e7dSPeter Dunlap * (identified by the same ITT) to split the input into several sequences. 2298a6d42e7dSPeter Dunlap * 2299a6d42e7dSPeter Dunlap * DataSN starts with 0 for the first data PDU of an input command and advances 2300a6d42e7dSPeter Dunlap * by 1 for each subsequent data PDU. Each sequence will have its own F bit, 2301a6d42e7dSPeter Dunlap * which is set to 1 for the last data PDU of a sequence. 230260220f10SPriya Krishnan * If the initiator supports phase collapse, the status bit must be set along 230360220f10SPriya Krishnan * with the F bit to indicate that the status is shipped together with the last 230460220f10SPriya Krishnan * Data-In PDU. 2305a6d42e7dSPeter Dunlap * 2306a6d42e7dSPeter Dunlap * The data PDUs within a sequence will be sent in order with the buffer offset 2307a6d42e7dSPeter Dunlap * in increasing order. i.e. initiator and target must have negotiated the 2308a6d42e7dSPeter Dunlap * "DataPDUInOrder" to "Yes". The order between sequences is not enforced. 2309a6d42e7dSPeter Dunlap * 2310a6d42e7dSPeter Dunlap * Caller holds idt->idt_mutex 2311a6d42e7dSPeter Dunlap */ 2312a6d42e7dSPeter Dunlap static idm_status_t 2313a6d42e7dSPeter Dunlap idm_so_buf_tx_to_ini(idm_task_t *idt, idm_buf_t *idb) 2314a6d42e7dSPeter Dunlap { 2315a6d42e7dSPeter Dunlap idm_so_conn_t *so_conn = idb->idb_ic->ic_transport_private; 2316a6d42e7dSPeter Dunlap idm_pdu_t tmppdu; 2317a6d42e7dSPeter Dunlap 2318a6d42e7dSPeter Dunlap ASSERT(mutex_owned(&idt->idt_mutex)); 2319a6d42e7dSPeter Dunlap 2320a6d42e7dSPeter Dunlap /* 2321a6d42e7dSPeter Dunlap * Put the idm_buf_t on the tx queue. It will be transmitted by 2322a6d42e7dSPeter Dunlap * idm_sotx_thread. 2323a6d42e7dSPeter Dunlap */ 2324a6d42e7dSPeter Dunlap mutex_enter(&so_conn->ic_tx_mutex); 2325a6d42e7dSPeter Dunlap 2326a668b114SPriya Krishnan DTRACE_ISCSI_8(xfer__start, idm_conn_t *, idt->idt_ic, 2327a668b114SPriya Krishnan uintptr_t, idb->idb_buf, uint32_t, idb->idb_bufoffset, 2328a668b114SPriya Krishnan uint64_t, 0, uint32_t, 0, uint32_t, 0, 2329a668b114SPriya Krishnan uint32_t, idb->idb_xfer_len, int, XFER_BUF_TX_TO_INI); 2330a668b114SPriya Krishnan 2331a6d42e7dSPeter Dunlap if (!so_conn->ic_tx_thread_running) { 2332a6d42e7dSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 2333a6d42e7dSPeter Dunlap /* 2334a6d42e7dSPeter Dunlap * Don't release idt->idt_mutex since we're supposed to hold 2335a6d42e7dSPeter Dunlap * in when calling idm_buf_tx_to_ini_done 2336a6d42e7dSPeter Dunlap */ 2337a668b114SPriya Krishnan DTRACE_ISCSI_8(xfer__done, idm_conn_t *, idt->idt_ic, 2338a668b114SPriya Krishnan uintptr_t, idb->idb_buf, uint32_t, idb->idb_bufoffset, 2339a668b114SPriya Krishnan uint64_t, 0, uint32_t, 0, uint32_t, 0, 2340a668b114SPriya Krishnan uint32_t, idb->idb_xfer_len, 2341a668b114SPriya Krishnan int, XFER_BUF_TX_TO_INI); 2342a6d42e7dSPeter Dunlap idm_buf_tx_to_ini_done(idt, idb, IDM_STATUS_ABORTED); 2343a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 2344a6d42e7dSPeter Dunlap } 2345a6d42e7dSPeter Dunlap 2346a6d42e7dSPeter Dunlap /* 2347a6d42e7dSPeter Dunlap * Build a template for the data PDU headers we will use so that 2348a6d42e7dSPeter Dunlap * the SN values will stay consistent with other PDU's we are 2349a6d42e7dSPeter Dunlap * transmitting like R2T and SCSI status. 2350a6d42e7dSPeter Dunlap */ 2351a6d42e7dSPeter Dunlap bzero(&idb->idb_data_hdr_tmpl, sizeof (iscsi_hdr_t)); 2352a6d42e7dSPeter Dunlap tmppdu.isp_hdr = &idb->idb_data_hdr_tmpl; 2353a6d42e7dSPeter Dunlap (*idt->idt_ic->ic_conn_ops.icb_build_hdr)(idt, &tmppdu, 2354a6d42e7dSPeter Dunlap ISCSI_OP_SCSI_DATA_RSP); 2355a6d42e7dSPeter Dunlap idb->idb_tx_thread = B_TRUE; 2356a6d42e7dSPeter Dunlap list_insert_tail(&so_conn->ic_tx_list, (void *)idb); 2357a6d42e7dSPeter Dunlap cv_signal(&so_conn->ic_tx_cv); 2358a6d42e7dSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 2359a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 2360a6d42e7dSPeter Dunlap 2361a6d42e7dSPeter Dunlap /* 2362a6d42e7dSPeter Dunlap * Returning success here indicates the transfer was successfully 2363a6d42e7dSPeter Dunlap * dispatched -- it does not mean that the transfer completed 2364a6d42e7dSPeter Dunlap * successfully. 2365a6d42e7dSPeter Dunlap */ 2366a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 2367a6d42e7dSPeter Dunlap } 2368a6d42e7dSPeter Dunlap 2369a6d42e7dSPeter Dunlap /* 2370a6d42e7dSPeter Dunlap * The idm_so_buf_rx_from_ini() is used by the target iSCSI layer to specify the 2371a6d42e7dSPeter Dunlap * data blocks it is ready to receive from the initiator in response to a WRITE 2372a6d42e7dSPeter Dunlap * SCSI command. The target iSCSI layer passes the information about the desired 2373a6d42e7dSPeter Dunlap * data blocks to the initiator in one R2T PDU. The receiving buffer, the buffer 2374a6d42e7dSPeter Dunlap * offset and datalen are passed via the 'idb' argument. 2375a6d42e7dSPeter Dunlap * 2376a6d42e7dSPeter Dunlap * Scope for Prototype build: 2377a6d42e7dSPeter Dunlap * R2Ts are required for any Data-Out PDU, i.e. initiator and target must have 2378a6d42e7dSPeter Dunlap * negotiated the "InitialR2T" to "Yes". 2379a6d42e7dSPeter Dunlap * 2380a6d42e7dSPeter Dunlap * Caller holds idt->idt_mutex 2381a6d42e7dSPeter Dunlap */ 2382a6d42e7dSPeter Dunlap static idm_status_t 2383a6d42e7dSPeter Dunlap idm_so_buf_rx_from_ini(idm_task_t *idt, idm_buf_t *idb) 2384a6d42e7dSPeter Dunlap { 2385a6d42e7dSPeter Dunlap idm_pdu_t *pdu; 2386a6d42e7dSPeter Dunlap iscsi_rtt_hdr_t *rtt; 2387a6d42e7dSPeter Dunlap 2388a6d42e7dSPeter Dunlap ASSERT(mutex_owned(&idt->idt_mutex)); 2389a6d42e7dSPeter Dunlap 2390a668b114SPriya Krishnan DTRACE_ISCSI_8(xfer__start, idm_conn_t *, idt->idt_ic, 2391a668b114SPriya Krishnan uintptr_t, idb->idb_buf, uint32_t, idb->idb_bufoffset, 2392a668b114SPriya Krishnan uint64_t, 0, uint32_t, 0, uint32_t, 0, 2393a668b114SPriya Krishnan uint32_t, idb->idb_xfer_len, int, XFER_BUF_RX_FROM_INI); 2394a668b114SPriya Krishnan 2395a6d42e7dSPeter Dunlap pdu = kmem_cache_alloc(idm.idm_sotx_pdu_cache, KM_SLEEP); 2396a6d42e7dSPeter Dunlap pdu->isp_ic = idt->idt_ic; 239760220f10SPriya Krishnan pdu->isp_flags = 0; /* initialize isp_flags */ 2398a6d42e7dSPeter Dunlap bzero(pdu->isp_hdr, sizeof (iscsi_rtt_hdr_t)); 2399a6d42e7dSPeter Dunlap 2400a6d42e7dSPeter Dunlap /* iSCSI layer fills the TTT, ITT, StatSN, ExpCmdSN, MaxCmdSN */ 2401a6d42e7dSPeter Dunlap (*idt->idt_ic->ic_conn_ops.icb_build_hdr)(idt, pdu, ISCSI_OP_RTT_RSP); 2402a6d42e7dSPeter Dunlap 2403a6d42e7dSPeter Dunlap /* set the rttsn, rtt.flags, rtt.data_offset and rtt.data_length */ 2404a6d42e7dSPeter Dunlap rtt = (iscsi_rtt_hdr_t *)(pdu->isp_hdr); 2405a6d42e7dSPeter Dunlap 2406a6d42e7dSPeter Dunlap rtt->opcode = ISCSI_OP_RTT_RSP; 2407a6d42e7dSPeter Dunlap rtt->flags = ISCSI_FLAG_FINAL; 2408a6d42e7dSPeter Dunlap rtt->data_offset = htonl(idb->idb_bufoffset); 2409a6d42e7dSPeter Dunlap rtt->data_length = htonl(idb->idb_xfer_len); 2410a6d42e7dSPeter Dunlap rtt->rttsn = htonl(idt->idt_exp_rttsn++); 2411a6d42e7dSPeter Dunlap 2412a6d42e7dSPeter Dunlap /* Keep track of buffer offsets */ 2413a6d42e7dSPeter Dunlap idb->idb_exp_offset = idb->idb_bufoffset; 2414a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 2415a6d42e7dSPeter Dunlap 2416a6d42e7dSPeter Dunlap /* 241763528ae4SJames Moore * Transmit the PDU. 2418a6d42e7dSPeter Dunlap */ 241963528ae4SJames Moore idm_pdu_tx(pdu); 2420a6d42e7dSPeter Dunlap 2421a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 2422a6d42e7dSPeter Dunlap } 2423a6d42e7dSPeter Dunlap 2424a6d42e7dSPeter Dunlap static idm_status_t 2425a6d42e7dSPeter Dunlap idm_so_buf_alloc(idm_buf_t *idb, uint64_t buflen) 2426a6d42e7dSPeter Dunlap { 2427cf8c0ebaSPeter Dunlap if ((buflen > IDM_SO_BUF_CACHE_LB) && (buflen <= IDM_SO_BUF_CACHE_UB)) { 2428cf8c0ebaSPeter Dunlap idb->idb_buf = kmem_cache_alloc(idm.idm_so_128k_buf_cache, 2429cf8c0ebaSPeter Dunlap KM_NOSLEEP); 2430cf8c0ebaSPeter Dunlap idb->idb_buf_private = idm.idm_so_128k_buf_cache; 2431cf8c0ebaSPeter Dunlap } else { 2432cf8c0ebaSPeter Dunlap idb->idb_buf = kmem_alloc(buflen, KM_NOSLEEP); 2433cf8c0ebaSPeter Dunlap idb->idb_buf_private = NULL; 2434cf8c0ebaSPeter Dunlap } 2435cf8c0ebaSPeter Dunlap 2436a6d42e7dSPeter Dunlap if (idb->idb_buf == NULL) { 2437a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_NOTE, 2438a6d42e7dSPeter Dunlap "idm_so_buf_alloc: failed buffer allocation"); 2439a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 2440a6d42e7dSPeter Dunlap } 2441cf8c0ebaSPeter Dunlap 2442a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 2443a6d42e7dSPeter Dunlap } 2444a6d42e7dSPeter Dunlap 2445a6d42e7dSPeter Dunlap /* ARGSUSED */ 2446a6d42e7dSPeter Dunlap static idm_status_t 2447a6d42e7dSPeter Dunlap idm_so_buf_setup(idm_buf_t *idb) 2448a6d42e7dSPeter Dunlap { 244930e7468fSPeter Dunlap /* Ensure bufalloc'd flag is unset */ 245030e7468fSPeter Dunlap idb->idb_bufalloc = B_FALSE; 245130e7468fSPeter Dunlap 2452a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 2453a6d42e7dSPeter Dunlap } 2454a6d42e7dSPeter Dunlap 2455a6d42e7dSPeter Dunlap /* ARGSUSED */ 2456a6d42e7dSPeter Dunlap static void 2457a6d42e7dSPeter Dunlap idm_so_buf_teardown(idm_buf_t *idb) 2458a6d42e7dSPeter Dunlap { 2459a6d42e7dSPeter Dunlap /* nothing to do here */ 2460a6d42e7dSPeter Dunlap } 2461a6d42e7dSPeter Dunlap 2462a6d42e7dSPeter Dunlap static void 2463a6d42e7dSPeter Dunlap idm_so_buf_free(idm_buf_t *idb) 2464a6d42e7dSPeter Dunlap { 2465cf8c0ebaSPeter Dunlap if (idb->idb_buf_private == NULL) { 2466cf8c0ebaSPeter Dunlap kmem_free(idb->idb_buf, idb->idb_buflen); 2467cf8c0ebaSPeter Dunlap } else { 2468cf8c0ebaSPeter Dunlap kmem_cache_free(idb->idb_buf_private, idb->idb_buf); 2469cf8c0ebaSPeter Dunlap } 2470a6d42e7dSPeter Dunlap } 2471a6d42e7dSPeter Dunlap 247230e7468fSPeter Dunlap static void 247330e7468fSPeter Dunlap idm_so_send_rtt_data(idm_conn_t *ic, idm_task_t *idt, idm_buf_t *idb, 247430e7468fSPeter Dunlap uint32_t offset, uint32_t length) 247530e7468fSPeter Dunlap { 247630e7468fSPeter Dunlap idm_so_conn_t *so_conn = ic->ic_transport_private; 247730e7468fSPeter Dunlap idm_pdu_t tmppdu; 247830e7468fSPeter Dunlap idm_buf_t *rtt_buf; 247930e7468fSPeter Dunlap 248030e7468fSPeter Dunlap ASSERT(mutex_owned(&idt->idt_mutex)); 248130e7468fSPeter Dunlap 248230e7468fSPeter Dunlap /* 248330e7468fSPeter Dunlap * Allocate a buffer to represent the RTT transfer. We could further 248430e7468fSPeter Dunlap * optimize this by allocating the buffers internally from an rtt 248530e7468fSPeter Dunlap * specific buffer cache since this is socket-specific code but for 248630e7468fSPeter Dunlap * now we will keep it simple. 248730e7468fSPeter Dunlap */ 248830e7468fSPeter Dunlap rtt_buf = idm_buf_alloc(ic, (uint8_t *)idb->idb_buf + offset, length); 248930e7468fSPeter Dunlap if (rtt_buf == NULL) { 249030e7468fSPeter Dunlap /* 249130e7468fSPeter Dunlap * If we're in FFP then the failure was likely a resource 249230e7468fSPeter Dunlap * allocation issue and we should close the connection by 249330e7468fSPeter Dunlap * sending a CE_TRANSPORT_FAIL event. 249430e7468fSPeter Dunlap * 249530e7468fSPeter Dunlap * If we're not in FFP then idm_buf_alloc will always 249630e7468fSPeter Dunlap * fail and the state is transitioning to "complete" anyway 249730e7468fSPeter Dunlap * so we won't bother to send an event. 249830e7468fSPeter Dunlap */ 249930e7468fSPeter Dunlap mutex_enter(&ic->ic_state_mutex); 250030e7468fSPeter Dunlap if (ic->ic_ffp) 250130e7468fSPeter Dunlap idm_conn_event_locked(ic, CE_TRANSPORT_FAIL, 250230e7468fSPeter Dunlap NULL, CT_NONE); 250330e7468fSPeter Dunlap mutex_exit(&ic->ic_state_mutex); 250430e7468fSPeter Dunlap return; 250530e7468fSPeter Dunlap } 250630e7468fSPeter Dunlap 250730e7468fSPeter Dunlap rtt_buf->idb_buf_cb = NULL; 250830e7468fSPeter Dunlap rtt_buf->idb_cb_arg = NULL; 250930e7468fSPeter Dunlap rtt_buf->idb_bufoffset = offset; 251030e7468fSPeter Dunlap rtt_buf->idb_xfer_len = length; 251130e7468fSPeter Dunlap rtt_buf->idb_ic = idt->idt_ic; 251230e7468fSPeter Dunlap rtt_buf->idb_task_binding = idt; 251330e7468fSPeter Dunlap 251430e7468fSPeter Dunlap /* 251530e7468fSPeter Dunlap * Put the idm_buf_t on the tx queue. It will be transmitted by 251630e7468fSPeter Dunlap * idm_sotx_thread. 251730e7468fSPeter Dunlap */ 251830e7468fSPeter Dunlap mutex_enter(&so_conn->ic_tx_mutex); 251930e7468fSPeter Dunlap 252030e7468fSPeter Dunlap if (!so_conn->ic_tx_thread_running) { 252130e7468fSPeter Dunlap idm_buf_free(rtt_buf); 252230e7468fSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 252330e7468fSPeter Dunlap return; 252430e7468fSPeter Dunlap } 252530e7468fSPeter Dunlap 252630e7468fSPeter Dunlap /* 252730e7468fSPeter Dunlap * This new buffer represents an additional reference on the task 252830e7468fSPeter Dunlap */ 252930e7468fSPeter Dunlap idm_task_hold(idt); 253030e7468fSPeter Dunlap 253130e7468fSPeter Dunlap /* 253230e7468fSPeter Dunlap * Build a template for the data PDU headers we will use so that 253330e7468fSPeter Dunlap * the SN values will stay consistent with other PDU's we are 253430e7468fSPeter Dunlap * transmitting like R2T and SCSI status. 253530e7468fSPeter Dunlap */ 253630e7468fSPeter Dunlap bzero(&rtt_buf->idb_data_hdr_tmpl, sizeof (iscsi_hdr_t)); 253730e7468fSPeter Dunlap tmppdu.isp_hdr = &rtt_buf->idb_data_hdr_tmpl; 253830e7468fSPeter Dunlap (*idt->idt_ic->ic_conn_ops.icb_build_hdr)(idt, &tmppdu, 253930e7468fSPeter Dunlap ISCSI_OP_SCSI_DATA); 254030e7468fSPeter Dunlap rtt_buf->idb_tx_thread = B_TRUE; 254130e7468fSPeter Dunlap rtt_buf->idb_in_transport = B_TRUE; 254230e7468fSPeter Dunlap list_insert_tail(&so_conn->ic_tx_list, (void *)rtt_buf); 254330e7468fSPeter Dunlap cv_signal(&so_conn->ic_tx_cv); 254430e7468fSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 254530e7468fSPeter Dunlap } 254630e7468fSPeter Dunlap 254730e7468fSPeter Dunlap static void 254830e7468fSPeter Dunlap idm_so_send_rtt_data_done(idm_task_t *idt, idm_buf_t *idb) 254930e7468fSPeter Dunlap { 255030e7468fSPeter Dunlap /* 255130e7468fSPeter Dunlap * Don't worry about status -- we assume any error handling 255230e7468fSPeter Dunlap * is performed by the caller (idm_sotx_thread). 255330e7468fSPeter Dunlap */ 255430e7468fSPeter Dunlap idb->idb_in_transport = B_FALSE; 255530e7468fSPeter Dunlap idm_task_rele(idt); 255630e7468fSPeter Dunlap idm_buf_free(idb); 255730e7468fSPeter Dunlap } 255830e7468fSPeter Dunlap 255930e7468fSPeter Dunlap static idm_status_t 256030e7468fSPeter Dunlap idm_so_send_buf_region(idm_task_t *idt, idm_buf_t *idb, 2561a6d42e7dSPeter Dunlap uint32_t buf_region_offset, uint32_t buf_region_length) 2562a6d42e7dSPeter Dunlap { 2563a6d42e7dSPeter Dunlap idm_conn_t *ic; 2564a6d42e7dSPeter Dunlap uint32_t max_dataseglen; 2565a6d42e7dSPeter Dunlap size_t remainder, chunk; 2566a6d42e7dSPeter Dunlap uint32_t data_offset = buf_region_offset; 2567a6d42e7dSPeter Dunlap iscsi_data_hdr_t *bhs; 2568a6d42e7dSPeter Dunlap idm_pdu_t *pdu; 256930e7468fSPeter Dunlap idm_status_t tx_status; 2570a6d42e7dSPeter Dunlap 2571a6d42e7dSPeter Dunlap ASSERT(mutex_owned(&idt->idt_mutex)); 2572a6d42e7dSPeter Dunlap 2573a6d42e7dSPeter Dunlap ic = idt->idt_ic; 2574a6d42e7dSPeter Dunlap 257556261083SCharles Ting max_dataseglen = ic->ic_conn_params.max_xmit_dataseglen; 2576a6d42e7dSPeter Dunlap remainder = buf_region_length; 2577a6d42e7dSPeter Dunlap 2578a6d42e7dSPeter Dunlap while (remainder) { 2579a6d42e7dSPeter Dunlap if (idt->idt_state != TASK_ACTIVE) { 2580a6d42e7dSPeter Dunlap ASSERT((idt->idt_state != TASK_IDLE) && 2581a6d42e7dSPeter Dunlap (idt->idt_state != TASK_COMPLETE)); 2582a6d42e7dSPeter Dunlap return (IDM_STATUS_ABORTED); 2583a6d42e7dSPeter Dunlap } 2584a6d42e7dSPeter Dunlap 2585a6d42e7dSPeter Dunlap /* check to see if we need to chunk the data */ 2586a6d42e7dSPeter Dunlap if (remainder > max_dataseglen) { 2587a6d42e7dSPeter Dunlap chunk = max_dataseglen; 2588a6d42e7dSPeter Dunlap } else { 2589a6d42e7dSPeter Dunlap chunk = remainder; 2590a6d42e7dSPeter Dunlap } 2591a6d42e7dSPeter Dunlap 2592a6d42e7dSPeter Dunlap /* Data PDU headers will always be sizeof (iscsi_hdr_t) */ 2593a6d42e7dSPeter Dunlap pdu = kmem_cache_alloc(idm.idm_sotx_pdu_cache, KM_SLEEP); 2594a6d42e7dSPeter Dunlap pdu->isp_ic = ic; 259560220f10SPriya Krishnan pdu->isp_flags = 0; /* initialize isp_flags */ 2596a6d42e7dSPeter Dunlap 2597a6d42e7dSPeter Dunlap /* 259830e7468fSPeter Dunlap * We've already built a build a header template 2599a6d42e7dSPeter Dunlap * to use during the transfer. Use this template so that 2600a6d42e7dSPeter Dunlap * the SN values stay consistent with any unrelated PDU's 2601a6d42e7dSPeter Dunlap * being transmitted. 2602a6d42e7dSPeter Dunlap */ 260330e7468fSPeter Dunlap bcopy(&idb->idb_data_hdr_tmpl, pdu->isp_hdr, 260430e7468fSPeter Dunlap sizeof (iscsi_hdr_t)); 2605a6d42e7dSPeter Dunlap 2606a6d42e7dSPeter Dunlap /* 2607a6d42e7dSPeter Dunlap * Set DataSN, data offset, and flags in BHS 2608a6d42e7dSPeter Dunlap * For the prototype build, A = 0, S = 0, U = 0 2609a6d42e7dSPeter Dunlap */ 2610a6d42e7dSPeter Dunlap bhs = (iscsi_data_hdr_t *)(pdu->isp_hdr); 2611a6d42e7dSPeter Dunlap 2612a6d42e7dSPeter Dunlap bhs->datasn = htonl(idt->idt_exp_datasn++); 2613a6d42e7dSPeter Dunlap 2614a6d42e7dSPeter Dunlap hton24(bhs->dlength, chunk); 2615a6d42e7dSPeter Dunlap bhs->offset = htonl(idb->idb_bufoffset + data_offset); 2616a6d42e7dSPeter Dunlap 261760220f10SPriya Krishnan /* setup data */ 261860220f10SPriya Krishnan pdu->isp_data = (uint8_t *)idb->idb_buf + data_offset; 261960220f10SPriya Krishnan pdu->isp_datalen = (uint_t)chunk; 262060220f10SPriya Krishnan 2621a6d42e7dSPeter Dunlap if (chunk == remainder) { 2622a6d42e7dSPeter Dunlap bhs->flags = ISCSI_FLAG_FINAL; /* F bit set to 1 */ 262360220f10SPriya Krishnan /* Piggyback the status with the last data PDU */ 262460220f10SPriya Krishnan if (idt->idt_flags & IDM_TASK_PHASECOLLAPSE_REQ) { 262560220f10SPriya Krishnan pdu->isp_flags |= IDM_PDU_SET_STATSN | 262660220f10SPriya Krishnan IDM_PDU_ADVANCE_STATSN; 262760220f10SPriya Krishnan (*idt->idt_ic->ic_conn_ops.icb_update_statsn) 262860220f10SPriya Krishnan (idt, pdu); 262960220f10SPriya Krishnan idt->idt_flags |= 263060220f10SPriya Krishnan IDM_TASK_PHASECOLLAPSE_SUCCESS; 263160220f10SPriya Krishnan 263260220f10SPriya Krishnan } 2633a6d42e7dSPeter Dunlap } 2634a6d42e7dSPeter Dunlap 263560220f10SPriya Krishnan remainder -= chunk; 263660220f10SPriya Krishnan data_offset += chunk; 263760220f10SPriya Krishnan 2638a668b114SPriya Krishnan /* Instrument the data-send DTrace probe. */ 2639a668b114SPriya Krishnan if (IDM_PDU_OPCODE(pdu) == ISCSI_OP_SCSI_DATA_RSP) { 2640a668b114SPriya Krishnan DTRACE_ISCSI_2(data__send, 2641a668b114SPriya Krishnan idm_conn_t *, idt->idt_ic, 2642a668b114SPriya Krishnan iscsi_data_rsp_hdr_t *, 2643a668b114SPriya Krishnan (iscsi_data_rsp_hdr_t *)pdu->isp_hdr); 2644a668b114SPriya Krishnan } 2645a6d42e7dSPeter Dunlap 2646a6d42e7dSPeter Dunlap /* 2647a6d42e7dSPeter Dunlap * Now that we're done working with idt_exp_datasn, 2648a6d42e7dSPeter Dunlap * idt->idt_state and idb->idb_bufoffset we can release 2649a6d42e7dSPeter Dunlap * the task lock -- don't want to hold it across the 2650a6d42e7dSPeter Dunlap * call to idm_i_so_tx since we could block. 2651a6d42e7dSPeter Dunlap */ 2652a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 2653a6d42e7dSPeter Dunlap 2654a6d42e7dSPeter Dunlap /* 2655a6d42e7dSPeter Dunlap * Transmit the PDU. Call the internal routine directly 2656a6d42e7dSPeter Dunlap * as there is already implicit ordering. 2657a6d42e7dSPeter Dunlap */ 265830e7468fSPeter Dunlap if ((tx_status = idm_i_so_tx(pdu)) != IDM_STATUS_SUCCESS) { 265930e7468fSPeter Dunlap mutex_enter(&idt->idt_mutex); 266030e7468fSPeter Dunlap return (tx_status); 266130e7468fSPeter Dunlap } 2662a6d42e7dSPeter Dunlap 2663a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 266430e7468fSPeter Dunlap idt->idt_tx_bytes += chunk; 2665a6d42e7dSPeter Dunlap } 2666a6d42e7dSPeter Dunlap 2667a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 2668a6d42e7dSPeter Dunlap } 2669a6d42e7dSPeter Dunlap 2670a6d42e7dSPeter Dunlap /* 2671a6d42e7dSPeter Dunlap * TX PDU cache 2672a6d42e7dSPeter Dunlap */ 2673a6d42e7dSPeter Dunlap /* ARGSUSED */ 2674a6d42e7dSPeter Dunlap int 2675a6d42e7dSPeter Dunlap idm_sotx_pdu_constructor(void *hdl, void *arg, int flags) 2676a6d42e7dSPeter Dunlap { 2677a6d42e7dSPeter Dunlap idm_pdu_t *pdu = hdl; 2678a6d42e7dSPeter Dunlap 2679a6d42e7dSPeter Dunlap bzero(pdu, sizeof (idm_pdu_t)); 2680a6d42e7dSPeter Dunlap pdu->isp_hdr = (iscsi_hdr_t *)(pdu + 1); /* Ptr arithmetic */ 2681a6d42e7dSPeter Dunlap pdu->isp_hdrlen = sizeof (iscsi_hdr_t); 2682a6d42e7dSPeter Dunlap pdu->isp_callback = idm_sotx_cache_pdu_cb; 2683a6d42e7dSPeter Dunlap pdu->isp_magic = IDM_PDU_MAGIC; 2684a6d42e7dSPeter Dunlap bzero(pdu->isp_hdr, sizeof (iscsi_hdr_t)); 2685a6d42e7dSPeter Dunlap 2686a6d42e7dSPeter Dunlap return (0); 2687a6d42e7dSPeter Dunlap } 2688a6d42e7dSPeter Dunlap 2689a6d42e7dSPeter Dunlap /* ARGSUSED */ 2690a6d42e7dSPeter Dunlap void 2691a6d42e7dSPeter Dunlap idm_sotx_cache_pdu_cb(idm_pdu_t *pdu, idm_status_t status) 2692a6d42e7dSPeter Dunlap { 2693a6d42e7dSPeter Dunlap /* reset values between use */ 2694a6d42e7dSPeter Dunlap pdu->isp_datalen = 0; 2695a6d42e7dSPeter Dunlap 2696a6d42e7dSPeter Dunlap kmem_cache_free(idm.idm_sotx_pdu_cache, pdu); 2697a6d42e7dSPeter Dunlap } 2698a6d42e7dSPeter Dunlap 2699a6d42e7dSPeter Dunlap /* 2700a6d42e7dSPeter Dunlap * RX PDU cache 2701a6d42e7dSPeter Dunlap */ 2702a6d42e7dSPeter Dunlap /* ARGSUSED */ 2703a6d42e7dSPeter Dunlap int 2704a6d42e7dSPeter Dunlap idm_sorx_pdu_constructor(void *hdl, void *arg, int flags) 2705a6d42e7dSPeter Dunlap { 2706a6d42e7dSPeter Dunlap idm_pdu_t *pdu = hdl; 2707a6d42e7dSPeter Dunlap 2708a6d42e7dSPeter Dunlap bzero(pdu, sizeof (idm_pdu_t)); 2709a6d42e7dSPeter Dunlap pdu->isp_magic = IDM_PDU_MAGIC; 2710a6d42e7dSPeter Dunlap pdu->isp_hdr = (iscsi_hdr_t *)(pdu + 1); /* Ptr arithmetic */ 2711a6d42e7dSPeter Dunlap pdu->isp_callback = idm_sorx_cache_pdu_cb; 2712a6d42e7dSPeter Dunlap 2713a6d42e7dSPeter Dunlap return (0); 2714a6d42e7dSPeter Dunlap } 2715a6d42e7dSPeter Dunlap 2716a6d42e7dSPeter Dunlap /* ARGSUSED */ 2717a6d42e7dSPeter Dunlap static void 2718a6d42e7dSPeter Dunlap idm_sorx_cache_pdu_cb(idm_pdu_t *pdu, idm_status_t status) 2719a6d42e7dSPeter Dunlap { 2720a6d42e7dSPeter Dunlap pdu->isp_iovlen = 0; 2721a6d42e7dSPeter Dunlap pdu->isp_sorx_buf = 0; 2722a6d42e7dSPeter Dunlap kmem_cache_free(idm.idm_sorx_pdu_cache, pdu); 2723a6d42e7dSPeter Dunlap } 2724a6d42e7dSPeter Dunlap 2725a6d42e7dSPeter Dunlap static void 2726a6d42e7dSPeter Dunlap idm_sorx_addl_pdu_cb(idm_pdu_t *pdu, idm_status_t status) 2727a6d42e7dSPeter Dunlap { 2728a6d42e7dSPeter Dunlap /* 2729a6d42e7dSPeter Dunlap * We had to modify our cached RX PDU with a longer header buffer 2730a6d42e7dSPeter Dunlap * and/or a longer data buffer. Release the new buffers and fix 2731a6d42e7dSPeter Dunlap * the fields back to what we would expect for a cached RX PDU. 2732a6d42e7dSPeter Dunlap */ 2733a6d42e7dSPeter Dunlap if (pdu->isp_flags & IDM_PDU_ADDL_HDR) { 2734a6d42e7dSPeter Dunlap kmem_free(pdu->isp_hdr, pdu->isp_hdrlen); 2735a6d42e7dSPeter Dunlap } 2736a6d42e7dSPeter Dunlap if (pdu->isp_flags & IDM_PDU_ADDL_DATA) { 2737a6d42e7dSPeter Dunlap kmem_free(pdu->isp_data, pdu->isp_datalen); 2738a6d42e7dSPeter Dunlap } 2739a6d42e7dSPeter Dunlap pdu->isp_hdr = (iscsi_hdr_t *)(pdu + 1); 2740a6d42e7dSPeter Dunlap pdu->isp_hdrlen = sizeof (iscsi_hdr_t); 2741a6d42e7dSPeter Dunlap pdu->isp_data = NULL; 2742a6d42e7dSPeter Dunlap pdu->isp_datalen = 0; 2743a6d42e7dSPeter Dunlap pdu->isp_sorx_buf = 0; 2744a6d42e7dSPeter Dunlap pdu->isp_callback = idm_sorx_cache_pdu_cb; 2745a6d42e7dSPeter Dunlap idm_sorx_cache_pdu_cb(pdu, status); 2746a6d42e7dSPeter Dunlap } 2747a6d42e7dSPeter Dunlap 2748a6d42e7dSPeter Dunlap /* 2749a6d42e7dSPeter Dunlap * This thread is only active when I/O is queued for transmit 2750a6d42e7dSPeter Dunlap * because the socket is busy. 2751a6d42e7dSPeter Dunlap */ 2752a6d42e7dSPeter Dunlap void 2753a6d42e7dSPeter Dunlap idm_sotx_thread(void *arg) 2754a6d42e7dSPeter Dunlap { 2755a6d42e7dSPeter Dunlap idm_conn_t *ic = arg; 2756a6d42e7dSPeter Dunlap idm_tx_obj_t *object, *next; 2757a6d42e7dSPeter Dunlap idm_so_conn_t *so_conn; 2758a6d42e7dSPeter Dunlap idm_status_t status = IDM_STATUS_SUCCESS; 2759a6d42e7dSPeter Dunlap 2760a6d42e7dSPeter Dunlap idm_conn_hold(ic); 2761a6d42e7dSPeter Dunlap 2762a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_mutex); 2763a6d42e7dSPeter Dunlap so_conn = ic->ic_transport_private; 2764a6d42e7dSPeter Dunlap so_conn->ic_tx_thread_running = B_TRUE; 2765a6d42e7dSPeter Dunlap so_conn->ic_tx_thread_did = so_conn->ic_tx_thread->t_did; 2766a6d42e7dSPeter Dunlap cv_signal(&ic->ic_cv); 2767a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_mutex); 2768a6d42e7dSPeter Dunlap 2769a6d42e7dSPeter Dunlap mutex_enter(&so_conn->ic_tx_mutex); 2770a6d42e7dSPeter Dunlap 2771a6d42e7dSPeter Dunlap while (so_conn->ic_tx_thread_running) { 2772a6d42e7dSPeter Dunlap while (list_is_empty(&so_conn->ic_tx_list)) { 2773a6d42e7dSPeter Dunlap DTRACE_PROBE1(soconn__tx__sleep, idm_conn_t *, ic); 2774a6d42e7dSPeter Dunlap cv_wait(&so_conn->ic_tx_cv, &so_conn->ic_tx_mutex); 2775a6d42e7dSPeter Dunlap DTRACE_PROBE1(soconn__tx__wakeup, idm_conn_t *, ic); 2776a6d42e7dSPeter Dunlap 2777a6d42e7dSPeter Dunlap if (!so_conn->ic_tx_thread_running) { 2778a6d42e7dSPeter Dunlap goto tx_bail; 2779a6d42e7dSPeter Dunlap } 2780a6d42e7dSPeter Dunlap } 2781a6d42e7dSPeter Dunlap 2782a6d42e7dSPeter Dunlap object = (idm_tx_obj_t *)list_head(&so_conn->ic_tx_list); 2783a6d42e7dSPeter Dunlap list_remove(&so_conn->ic_tx_list, object); 2784a6d42e7dSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 2785a6d42e7dSPeter Dunlap 2786a6d42e7dSPeter Dunlap switch (object->idm_tx_obj_magic) { 278760220f10SPriya Krishnan case IDM_PDU_MAGIC: { 278860220f10SPriya Krishnan idm_pdu_t *pdu = (idm_pdu_t *)object; 2789a6d42e7dSPeter Dunlap DTRACE_PROBE2(soconn__tx__pdu, idm_conn_t *, ic, 2790a6d42e7dSPeter Dunlap idm_pdu_t *, (idm_pdu_t *)object); 2791a6d42e7dSPeter Dunlap 279260220f10SPriya Krishnan if (pdu->isp_flags & IDM_PDU_SET_STATSN) { 279360220f10SPriya Krishnan /* No IDM task */ 279460220f10SPriya Krishnan (ic->ic_conn_ops.icb_update_statsn)(NULL, pdu); 279560220f10SPriya Krishnan } 2796a6d42e7dSPeter Dunlap status = idm_i_so_tx((idm_pdu_t *)object); 2797a6d42e7dSPeter Dunlap break; 279860220f10SPriya Krishnan } 2799a6d42e7dSPeter Dunlap case IDM_BUF_MAGIC: { 2800a6d42e7dSPeter Dunlap idm_buf_t *idb = (idm_buf_t *)object; 2801a6d42e7dSPeter Dunlap idm_task_t *idt = idb->idb_task_binding; 2802a6d42e7dSPeter Dunlap 2803a6d42e7dSPeter Dunlap DTRACE_PROBE2(soconn__tx__buf, idm_conn_t *, ic, 2804a6d42e7dSPeter Dunlap idm_buf_t *, idb); 2805a6d42e7dSPeter Dunlap 2806a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 2807a6d42e7dSPeter Dunlap status = idm_so_send_buf_region(idt, 280830e7468fSPeter Dunlap idb, 0, idb->idb_xfer_len); 2809a6d42e7dSPeter Dunlap 2810a6d42e7dSPeter Dunlap /* 2811a6d42e7dSPeter Dunlap * TX thread owns the buffer so we expect it to 2812a6d42e7dSPeter Dunlap * be "in transport" 2813a6d42e7dSPeter Dunlap */ 2814a6d42e7dSPeter Dunlap ASSERT(idb->idb_in_transport); 281530e7468fSPeter Dunlap if (IDM_CONN_ISTGT(ic)) { 281630e7468fSPeter Dunlap /* 281730e7468fSPeter Dunlap * idm_buf_tx_to_ini_done releases 281830e7468fSPeter Dunlap * idt->idt_mutex 281930e7468fSPeter Dunlap */ 2820a668b114SPriya Krishnan DTRACE_ISCSI_8(xfer__done, 2821a668b114SPriya Krishnan idm_conn_t *, idt->idt_ic, 2822a668b114SPriya Krishnan uintptr_t, idb->idb_buf, 2823a668b114SPriya Krishnan uint32_t, idb->idb_bufoffset, 2824a668b114SPriya Krishnan uint64_t, 0, uint32_t, 0, uint32_t, 0, 2825a668b114SPriya Krishnan uint32_t, idb->idb_xfer_len, 2826a668b114SPriya Krishnan int, XFER_BUF_TX_TO_INI); 282730e7468fSPeter Dunlap idm_buf_tx_to_ini_done(idt, idb, status); 282830e7468fSPeter Dunlap } else { 282930e7468fSPeter Dunlap idm_so_send_rtt_data_done(idt, idb); 283030e7468fSPeter Dunlap mutex_exit(&idt->idt_mutex); 283130e7468fSPeter Dunlap } 2832a6d42e7dSPeter Dunlap break; 2833a6d42e7dSPeter Dunlap } 2834a6d42e7dSPeter Dunlap 2835a6d42e7dSPeter Dunlap default: 2836a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, "idm_sotx_thread: Unknown magic " 2837a6d42e7dSPeter Dunlap "(0x%08x)", object->idm_tx_obj_magic); 2838a6d42e7dSPeter Dunlap status = IDM_STATUS_FAIL; 2839a6d42e7dSPeter Dunlap } 2840a6d42e7dSPeter Dunlap 2841a6d42e7dSPeter Dunlap mutex_enter(&so_conn->ic_tx_mutex); 2842a6d42e7dSPeter Dunlap 2843a6d42e7dSPeter Dunlap if (status != IDM_STATUS_SUCCESS) { 2844a6d42e7dSPeter Dunlap so_conn->ic_tx_thread_running = B_FALSE; 2845a6d42e7dSPeter Dunlap idm_conn_event(ic, CE_TRANSPORT_FAIL, status); 2846a6d42e7dSPeter Dunlap } 2847a6d42e7dSPeter Dunlap } 2848a6d42e7dSPeter Dunlap 2849a6d42e7dSPeter Dunlap /* 2850a6d42e7dSPeter Dunlap * Before we leave, we need to abort every item remaining in the 2851a6d42e7dSPeter Dunlap * TX list. 2852a6d42e7dSPeter Dunlap */ 2853a6d42e7dSPeter Dunlap 2854a6d42e7dSPeter Dunlap tx_bail: 2855a6d42e7dSPeter Dunlap object = (idm_tx_obj_t *)list_head(&so_conn->ic_tx_list); 2856a6d42e7dSPeter Dunlap 2857a6d42e7dSPeter Dunlap while (object != NULL) { 2858a6d42e7dSPeter Dunlap next = list_next(&so_conn->ic_tx_list, object); 2859a6d42e7dSPeter Dunlap 2860a6d42e7dSPeter Dunlap list_remove(&so_conn->ic_tx_list, object); 2861a6d42e7dSPeter Dunlap switch (object->idm_tx_obj_magic) { 2862a6d42e7dSPeter Dunlap case IDM_PDU_MAGIC: 2863a6d42e7dSPeter Dunlap idm_pdu_complete((idm_pdu_t *)object, 2864a6d42e7dSPeter Dunlap IDM_STATUS_ABORTED); 2865a6d42e7dSPeter Dunlap break; 2866a6d42e7dSPeter Dunlap 2867a6d42e7dSPeter Dunlap case IDM_BUF_MAGIC: { 2868a6d42e7dSPeter Dunlap idm_buf_t *idb = (idm_buf_t *)object; 2869a6d42e7dSPeter Dunlap idm_task_t *idt = idb->idb_task_binding; 2870a6d42e7dSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 2871a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 2872a6d42e7dSPeter Dunlap /* 2873a6d42e7dSPeter Dunlap * TX thread owns the buffer so we expect it to 2874a6d42e7dSPeter Dunlap * be "in transport" 2875a6d42e7dSPeter Dunlap */ 2876a6d42e7dSPeter Dunlap ASSERT(idb->idb_in_transport); 287730e7468fSPeter Dunlap if (IDM_CONN_ISTGT(ic)) { 287830e7468fSPeter Dunlap /* 287930e7468fSPeter Dunlap * idm_buf_tx_to_ini_done releases 288030e7468fSPeter Dunlap * idt->idt_mutex 288130e7468fSPeter Dunlap */ 2882a668b114SPriya Krishnan DTRACE_ISCSI_8(xfer__done, 2883a668b114SPriya Krishnan idm_conn_t *, idt->idt_ic, 2884a668b114SPriya Krishnan uintptr_t, idb->idb_buf, 2885a668b114SPriya Krishnan uint32_t, idb->idb_bufoffset, 2886a668b114SPriya Krishnan uint64_t, 0, uint32_t, 0, uint32_t, 0, 2887a668b114SPriya Krishnan uint32_t, idb->idb_xfer_len, 2888a668b114SPriya Krishnan int, XFER_BUF_TX_TO_INI); 288930e7468fSPeter Dunlap idm_buf_tx_to_ini_done(idt, idb, 289030e7468fSPeter Dunlap IDM_STATUS_ABORTED); 289130e7468fSPeter Dunlap } else { 289230e7468fSPeter Dunlap idm_so_send_rtt_data_done(idt, idb); 289330e7468fSPeter Dunlap mutex_exit(&idt->idt_mutex); 289430e7468fSPeter Dunlap } 2895a6d42e7dSPeter Dunlap mutex_enter(&so_conn->ic_tx_mutex); 2896a6d42e7dSPeter Dunlap break; 2897a6d42e7dSPeter Dunlap } 2898a6d42e7dSPeter Dunlap default: 2899a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, 2900a6d42e7dSPeter Dunlap "idm_sotx_thread: Unexpected magic " 2901a6d42e7dSPeter Dunlap "(0x%08x)", object->idm_tx_obj_magic); 2902a6d42e7dSPeter Dunlap } 2903a6d42e7dSPeter Dunlap 2904a6d42e7dSPeter Dunlap object = next; 2905a6d42e7dSPeter Dunlap } 2906a6d42e7dSPeter Dunlap 2907a6d42e7dSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 2908a6d42e7dSPeter Dunlap idm_conn_rele(ic); 2909a6d42e7dSPeter Dunlap thread_exit(); 2910a6d42e7dSPeter Dunlap /*NOTREACHED*/ 2911a6d42e7dSPeter Dunlap } 2912aff4bce5Syi zhang - Sun Microsystems - Beijing China 2913aff4bce5Syi zhang - Sun Microsystems - Beijing China static void 2914aff4bce5Syi zhang - Sun Microsystems - Beijing China idm_so_socket_set_nonblock(struct sonode *node) 2915aff4bce5Syi zhang - Sun Microsystems - Beijing China { 2916aff4bce5Syi zhang - Sun Microsystems - Beijing China (void) VOP_SETFL(node->so_vnode, node->so_flag, 2917aff4bce5Syi zhang - Sun Microsystems - Beijing China (node->so_state | FNONBLOCK), CRED(), NULL); 2918aff4bce5Syi zhang - Sun Microsystems - Beijing China } 2919aff4bce5Syi zhang - Sun Microsystems - Beijing China 2920aff4bce5Syi zhang - Sun Microsystems - Beijing China static void 2921aff4bce5Syi zhang - Sun Microsystems - Beijing China idm_so_socket_set_block(struct sonode *node) 2922aff4bce5Syi zhang - Sun Microsystems - Beijing China { 2923aff4bce5Syi zhang - Sun Microsystems - Beijing China (void) VOP_SETFL(node->so_vnode, node->so_flag, 2924aff4bce5Syi zhang - Sun Microsystems - Beijing China (node->so_state & (~FNONBLOCK)), CRED(), NULL); 2925aff4bce5Syi zhang - Sun Microsystems - Beijing China } 2926bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 2927bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 2928bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* 2929bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * Called by kernel sockets when the connection has been accepted or 2930bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * rejected. In early volo, a "disconnect" callback was sent instead of 2931bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * "connectfailed", so we check for both. 2932bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States */ 2933bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* ARGSUSED */ 2934bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States void 2935bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States idm_so_timed_socket_connect_cb(ksocket_t ks, 2936bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States ksocket_callback_event_t ev, void *arg, uintptr_t info) 2937bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States { 2938bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States idm_so_timed_socket_t *itp = arg; 2939bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States ASSERT(itp != NULL); 2940bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States ASSERT(ev == KSOCKET_EV_CONNECTED || 2941bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States ev == KSOCKET_EV_CONNECTFAILED || 2942bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States ev == KSOCKET_EV_DISCONNECTED); 2943bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 2944bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States mutex_enter(&idm_so_timed_socket_mutex); 2945bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States itp->it_callback_called = B_TRUE; 2946bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States if (ev == KSOCKET_EV_CONNECTED) { 2947bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States itp->it_socket_error_code = 0; 2948bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } else { 2949bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* Make sure the error code is non-zero on error */ 2950bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States if (info == 0) 2951bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States info = ECONNRESET; 2952bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States itp->it_socket_error_code = (int)info; 2953bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 2954bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States cv_signal(&itp->it_cv); 2955bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States mutex_exit(&idm_so_timed_socket_mutex); 2956bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 2957bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 2958bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States int 2959bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States idm_so_timed_socket_connect(ksocket_t ks, 2960bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States struct sockaddr_storage *sa, int sa_sz, int login_max_usec) 2961bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States { 2962bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States clock_t conn_login_max; 2963bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States int rc, nonblocking, rval; 2964bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States idm_so_timed_socket_t it; 2965bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States ksocket_callbacks_t ks_cb; 2966bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 2967bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States conn_login_max = ddi_get_lbolt() + drv_usectohz(login_max_usec); 2968bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 2969bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* 2970bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * Set to non-block socket mode, with callback on connect 2971bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * Early volo used "disconnected" instead of "connectfailed", 2972bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * so set callback to look for both. 2973bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States */ 2974bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States bzero(&it, sizeof (it)); 2975bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States ks_cb.ksock_cb_flags = KSOCKET_CB_CONNECTED | 2976bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States KSOCKET_CB_CONNECTFAILED | KSOCKET_CB_DISCONNECTED; 2977bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States ks_cb.ksock_cb_connected = idm_so_timed_socket_connect_cb; 2978bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States ks_cb.ksock_cb_connectfailed = idm_so_timed_socket_connect_cb; 2979bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States ks_cb.ksock_cb_disconnected = idm_so_timed_socket_connect_cb; 2980bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States cv_init(&it.it_cv, NULL, CV_DEFAULT, NULL); 2981bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States rc = ksocket_setcallbacks(ks, &ks_cb, &it, CRED()); 2982bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States if (rc != 0) 2983bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States return (rc); 2984bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 2985bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* Set to non-blocking mode */ 2986bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States nonblocking = 1; 2987bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States rc = ksocket_ioctl(ks, FIONBIO, (intptr_t)&nonblocking, &rval, 2988bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States CRED()); 2989bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States if (rc != 0) 2990bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States goto cleanup; 2991bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 2992bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States bzero(&it, sizeof (it)); 2993bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States for (;;) { 2994bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* 2995bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * Warning -- in a loopback scenario, the call to 2996bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * the connect_cb can occur inside the call to 2997bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * ksocket_connect. Do not hold the mutex around the 2998bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * call to ksocket_connect. 2999bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States */ 3000bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States rc = ksocket_connect(ks, (struct sockaddr *)sa, sa_sz, CRED()); 3001bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States if (rc == 0 || rc == EISCONN) { 3002bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* socket success or already success */ 3003bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States rc = 0; 3004bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States break; 3005bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3006bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States if ((rc != EINPROGRESS) && (rc != EALREADY)) { 3007bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States break; 3008bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3009bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 3010bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* TCP connect still in progress. See if out of time. */ 3011bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States if (ddi_get_lbolt() > conn_login_max) { 3012bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* 3013bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * Connection retry timeout, 3014bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * failed connect to target. 3015bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States */ 3016bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States rc = ETIMEDOUT; 3017bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States break; 3018bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3019bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 3020bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* 3021bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * TCP connect still in progress. Sleep until callback. 3022bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * Do NOT go to sleep if the callback already occurred! 3023bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States */ 3024bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States mutex_enter(&idm_so_timed_socket_mutex); 3025bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States if (!it.it_callback_called) { 3026bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States (void) cv_timedwait(&it.it_cv, 3027bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States &idm_so_timed_socket_mutex, conn_login_max); 3028bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3029bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States if (it.it_callback_called) { 3030bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States rc = it.it_socket_error_code; 3031bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States mutex_exit(&idm_so_timed_socket_mutex); 3032bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States break; 3033bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3034bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* If timer expires, go call ksocket_connect one last time. */ 3035bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States mutex_exit(&idm_so_timed_socket_mutex); 3036bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3037bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 3038bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* resume blocking mode */ 3039bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States nonblocking = 0; 3040aedf2b3bSsrivijitha dugganapalli (void) ksocket_ioctl(ks, FIONBIO, (intptr_t)&nonblocking, &rval, 3041bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States CRED()); 3042bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States cleanup: 3043aedf2b3bSsrivijitha dugganapalli (void) ksocket_setcallbacks(ks, NULL, NULL, CRED()); 3044bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States cv_destroy(&it.it_cv); 3045bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States if (rc != 0) { 3046bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States idm_soshutdown(ks); 3047bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3048bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States return (rc); 3049bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3050bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 3051bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 3052bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States void 3053bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States idm_addr_to_sa(idm_addr_t *dportal, struct sockaddr_storage *sa) 3054bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States { 3055bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States int dp_addr_size; 3056bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States struct sockaddr_in *sin; 3057bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States struct sockaddr_in6 *sin6; 3058bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 3059bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* Build sockaddr_storage for this portal (idm_addr_t) */ 3060bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States bzero(sa, sizeof (*sa)); 3061bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States dp_addr_size = dportal->a_addr.i_insize; 3062bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States if (dp_addr_size == sizeof (struct in_addr)) { 3063bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* IPv4 */ 3064bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States sa->ss_family = AF_INET; 3065bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States sin = (struct sockaddr_in *)sa; 3066bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States sin->sin_port = htons(dportal->a_port); 3067bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States bcopy(&dportal->a_addr.i_addr.in4, 3068bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States &sin->sin_addr, sizeof (struct in_addr)); 3069bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } else if (dp_addr_size == sizeof (struct in6_addr)) { 3070bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* IPv6 */ 3071bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States sa->ss_family = AF_INET6; 3072bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States sin6 = (struct sockaddr_in6 *)sa; 3073bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States sin6->sin6_port = htons(dportal->a_port); 3074bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States bcopy(&dportal->a_addr.i_addr.in6, 3075bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States &sin6->sin6_addr, sizeof (struct in6_addr)); 3076bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } else { 3077bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States ASSERT(0); 3078bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3079bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3080bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 3081bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 3082bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* 3083bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * return a human-readable form of a sockaddr_storage, in the form 3084bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * [ip-address]:port. This is used in calls to logging functions. 3085bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * If several calls to idm_sa_ntop are made within the same invocation 3086bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * of a logging function, then each one needs its own buf. 3087bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States */ 3088bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States const char * 3089bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States idm_sa_ntop(const struct sockaddr_storage *sa, 3090bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States char *buf, size_t size) 3091bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States { 3092bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States static const char bogus_ip[] = "[0].-1"; 3093bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States char tmp[INET6_ADDRSTRLEN]; 3094bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 3095bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States switch (sa->ss_family) { 3096bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States case AF_INET6: 3097bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States { 3098bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States const struct sockaddr_in6 *in6 = 3099bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States (const struct sockaddr_in6 *) sa; 3100bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 3101bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States if (inet_ntop(in6->sin6_family, 3102bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States &in6->sin6_addr, tmp, sizeof (tmp)) == NULL) { 3103bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States goto err; 3104bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3105bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States if (strlen(tmp) + sizeof ("[].65535") > size) { 3106bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States goto err; 3107bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3108bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* struct sockaddr_storage gets port info from v4 loc */ 3109bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States (void) snprintf(buf, size, "[%s].%u", tmp, 3110bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States ntohs(in6->sin6_port)); 3111bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States return (buf); 3112bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3113bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States case AF_INET: 3114bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States { 3115bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States const struct sockaddr_in *in = 3116bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States (const struct sockaddr_in *) sa; 3117bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 3118bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States if (inet_ntop(in->sin_family, &in->sin_addr, 3119bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States tmp, sizeof (tmp)) == NULL) { 3120bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States goto err; 3121bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3122bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States if (strlen(tmp) + sizeof ("[].65535") > size) { 3123bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States goto err; 3124bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3125bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States (void) snprintf(buf, size, "[%s].%u", tmp, 3126bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States ntohs(in->sin_port)); 3127bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States return (buf); 3128bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3129bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States default: 3130bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States break; 3131bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3132bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States err: 3133bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States (void) snprintf(buf, size, "%s", bogus_ip); 3134bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States return (buf); 3135bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3136