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 /* 2263528ae4SJames Moore * Copyright 2009 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 71*dedec472SJack Meng static void idm_set_ini_preconnect_options(idm_so_conn_t *sc, 72*dedec472SJack 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; 397a6d42e7dSPeter Dunlap idm_addr_list_t *ipaddr; 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 689*dedec472SJack 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()); 699*dedec472SJack Meng if (boot_conn == B_FALSE) { 700*dedec472SJack Meng (void) ksocket_setsockopt(sc->ic_so, IPPROTO_TCP, 701*dedec472SJack Meng TCP_CONN_ABORT_THRESHOLD, (char *)&conn_abort, sizeof (int), 702*dedec472SJack Meng CRED()); 703*dedec472SJack Meng (void) ksocket_setsockopt(sc->ic_so, IPPROTO_TCP, 704*dedec472SJack Meng TCP_ABORT_THRESHOLD, 705*dedec472SJack Meng (char *)&abort, sizeof (int), CRED()); 706*dedec472SJack 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 */ 873*dedec472SJack 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 */ 10520f1702c5SYu Xiangning 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); 10550f1702c5SYu Xiangning 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 1065a6d42e7dSPeter Dunlap while (!so_conn->ic_rx_thread_running || !so_conn->ic_tx_thread_running) 1066a6d42e7dSPeter Dunlap cv_wait(&ic->ic_cv, &ic->ic_mutex); 1067a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_mutex); 1068a6d42e7dSPeter Dunlap } 1069a6d42e7dSPeter Dunlap 1070a6d42e7dSPeter Dunlap /* 1071a6d42e7dSPeter Dunlap * idm_so_conn_disconnect() 1072a6d42e7dSPeter Dunlap * Shutdown the socket connection and stop the thread 1073a6d42e7dSPeter Dunlap */ 1074a6d42e7dSPeter Dunlap static void 1075a6d42e7dSPeter Dunlap idm_so_conn_disconnect(idm_conn_t *ic) 1076a6d42e7dSPeter Dunlap { 1077a6d42e7dSPeter Dunlap idm_so_conn_t *so_conn; 1078a6d42e7dSPeter Dunlap 1079a6d42e7dSPeter Dunlap so_conn = ic->ic_transport_private; 1080a6d42e7dSPeter Dunlap 1081a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_mutex); 1082a6d42e7dSPeter Dunlap so_conn->ic_rx_thread_running = B_FALSE; 1083a6d42e7dSPeter Dunlap so_conn->ic_tx_thread_running = B_FALSE; 1084a6d42e7dSPeter Dunlap /* We need to wakeup the TX thread */ 1085a6d42e7dSPeter Dunlap mutex_enter(&so_conn->ic_tx_mutex); 1086a6d42e7dSPeter Dunlap cv_signal(&so_conn->ic_tx_cv); 1087a6d42e7dSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 1088a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_mutex); 1089a6d42e7dSPeter Dunlap 1090a6d42e7dSPeter Dunlap /* This should wakeup the RX thread if it is sleeping */ 1091a6d42e7dSPeter Dunlap idm_soshutdown(so_conn->ic_so); 1092a6d42e7dSPeter Dunlap 1093a6d42e7dSPeter Dunlap thread_join(so_conn->ic_tx_thread_did); 1094a6d42e7dSPeter Dunlap thread_join(so_conn->ic_rx_thread_did); 1095a6d42e7dSPeter Dunlap } 1096a6d42e7dSPeter Dunlap 1097a6d42e7dSPeter Dunlap /* 1098a6d42e7dSPeter Dunlap * idm_so_tgt_svc_create() 1099a6d42e7dSPeter Dunlap * Establish a service on an IP address and port. idm_svc_req_t contains 1100a6d42e7dSPeter Dunlap * the service parameters. 1101a6d42e7dSPeter Dunlap */ 1102a6d42e7dSPeter Dunlap /*ARGSUSED*/ 1103a6d42e7dSPeter Dunlap static idm_status_t 1104a6d42e7dSPeter Dunlap idm_so_tgt_svc_create(idm_svc_req_t *sr, idm_svc_t *is) 1105a6d42e7dSPeter Dunlap { 1106a6d42e7dSPeter Dunlap idm_so_svc_t *so_svc; 1107a6d42e7dSPeter Dunlap 1108a6d42e7dSPeter Dunlap so_svc = kmem_zalloc(sizeof (idm_so_svc_t), KM_SLEEP); 1109a6d42e7dSPeter Dunlap 1110a6d42e7dSPeter Dunlap /* Set the new sockets service in svc handle */ 1111a6d42e7dSPeter Dunlap is->is_so_svc = (void *)so_svc; 1112a6d42e7dSPeter Dunlap 1113a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 1114a6d42e7dSPeter Dunlap } 1115a6d42e7dSPeter Dunlap 1116a6d42e7dSPeter Dunlap /* 1117a6d42e7dSPeter Dunlap * idm_so_tgt_svc_destroy() 1118a6d42e7dSPeter Dunlap * Teardown sockets resources allocated in idm_so_tgt_svc_create() 1119a6d42e7dSPeter Dunlap */ 1120a6d42e7dSPeter Dunlap static void 1121a6d42e7dSPeter Dunlap idm_so_tgt_svc_destroy(idm_svc_t *is) 1122a6d42e7dSPeter Dunlap { 1123a6d42e7dSPeter Dunlap /* the socket will have been torn down; free the service */ 1124a6d42e7dSPeter Dunlap kmem_free(is->is_so_svc, sizeof (idm_so_svc_t)); 1125a6d42e7dSPeter Dunlap } 1126a6d42e7dSPeter Dunlap 1127a6d42e7dSPeter Dunlap /* 1128a6d42e7dSPeter Dunlap * idm_so_tgt_svc_online() 1129a6d42e7dSPeter Dunlap * Launch a watch thread on the svc allocated in idm_so_tgt_svc_create() 1130a6d42e7dSPeter Dunlap */ 1131a6d42e7dSPeter Dunlap 1132a6d42e7dSPeter Dunlap static idm_status_t 1133a6d42e7dSPeter Dunlap idm_so_tgt_svc_online(idm_svc_t *is) 1134a6d42e7dSPeter Dunlap { 1135a6d42e7dSPeter Dunlap idm_so_svc_t *so_svc; 1136a6d42e7dSPeter Dunlap idm_svc_req_t *sr = &is->is_svc_req; 1137a6d42e7dSPeter Dunlap struct sockaddr_in6 sin6_ip; 1138a6d42e7dSPeter Dunlap const uint32_t on = 1; 1139a6d42e7dSPeter Dunlap const uint32_t off = 0; 1140a6d42e7dSPeter Dunlap 1141a6d42e7dSPeter Dunlap mutex_enter(&is->is_mutex); 1142a6d42e7dSPeter Dunlap so_svc = (idm_so_svc_t *)is->is_so_svc; 1143a6d42e7dSPeter Dunlap 1144a6d42e7dSPeter Dunlap /* 1145a6d42e7dSPeter Dunlap * Try creating an IPv6 socket first 1146a6d42e7dSPeter Dunlap */ 1147a6d42e7dSPeter Dunlap if ((so_svc->is_so = idm_socreate(PF_INET6, SOCK_STREAM, 0)) == NULL) { 1148a6d42e7dSPeter Dunlap mutex_exit(&is->is_mutex); 1149a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 1150a6d42e7dSPeter Dunlap } else { 1151a6d42e7dSPeter Dunlap bzero(&sin6_ip, sizeof (sin6_ip)); 1152a6d42e7dSPeter Dunlap sin6_ip.sin6_family = AF_INET6; 1153a6d42e7dSPeter Dunlap sin6_ip.sin6_port = htons(sr->sr_port); 1154a6d42e7dSPeter Dunlap sin6_ip.sin6_addr = in6addr_any; 1155a6d42e7dSPeter Dunlap 11560f1702c5SYu Xiangning (void) ksocket_setsockopt(so_svc->is_so, SOL_SOCKET, 11570f1702c5SYu Xiangning SO_REUSEADDR, (char *)&on, sizeof (on), CRED()); 1158a6d42e7dSPeter Dunlap /* 1159a6d42e7dSPeter Dunlap * Turn off SO_MAC_EXEMPT so future sobinds succeed 1160a6d42e7dSPeter Dunlap */ 11610f1702c5SYu Xiangning (void) ksocket_setsockopt(so_svc->is_so, SOL_SOCKET, 11620f1702c5SYu Xiangning SO_MAC_EXEMPT, (char *)&off, sizeof (off), CRED()); 1163a6d42e7dSPeter Dunlap 11640f1702c5SYu Xiangning if (ksocket_bind(so_svc->is_so, (struct sockaddr *)&sin6_ip, 11650f1702c5SYu Xiangning sizeof (sin6_ip), CRED()) != 0) { 1166a6d42e7dSPeter Dunlap mutex_exit(&is->is_mutex); 1167a6d42e7dSPeter Dunlap idm_sodestroy(so_svc->is_so); 1168a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 1169a6d42e7dSPeter Dunlap } 1170a6d42e7dSPeter Dunlap } 1171a6d42e7dSPeter Dunlap 1172a6d42e7dSPeter Dunlap idm_set_tgt_connect_options(so_svc->is_so); 1173a6d42e7dSPeter Dunlap 11740f1702c5SYu Xiangning if (ksocket_listen(so_svc->is_so, 5, CRED()) != 0) { 1175a6d42e7dSPeter Dunlap mutex_exit(&is->is_mutex); 1176a6d42e7dSPeter Dunlap idm_soshutdown(so_svc->is_so); 1177a6d42e7dSPeter Dunlap idm_sodestroy(so_svc->is_so); 1178a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 1179a6d42e7dSPeter Dunlap } 1180a6d42e7dSPeter Dunlap 1181a6d42e7dSPeter Dunlap /* Launch a watch thread */ 1182a6d42e7dSPeter Dunlap so_svc->is_thread = thread_create(NULL, 0, idm_so_svc_port_watcher, 1183a6d42e7dSPeter Dunlap is, 0, &p0, TS_RUN, minclsyspri); 1184a6d42e7dSPeter Dunlap 1185a6d42e7dSPeter Dunlap if (so_svc->is_thread == NULL) { 1186a6d42e7dSPeter Dunlap /* Failure to launch; teardown the socket */ 1187a6d42e7dSPeter Dunlap mutex_exit(&is->is_mutex); 1188a6d42e7dSPeter Dunlap idm_soshutdown(so_svc->is_so); 1189a6d42e7dSPeter Dunlap idm_sodestroy(so_svc->is_so); 1190a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 1191a6d42e7dSPeter Dunlap } 11920f1702c5SYu Xiangning ksocket_hold(so_svc->is_so); 1193a6d42e7dSPeter Dunlap /* Wait for the port watcher thread to start */ 1194a6d42e7dSPeter Dunlap while (!so_svc->is_thread_running) 1195a6d42e7dSPeter Dunlap cv_wait(&is->is_cv, &is->is_mutex); 1196a6d42e7dSPeter Dunlap mutex_exit(&is->is_mutex); 1197a6d42e7dSPeter Dunlap 1198a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 1199a6d42e7dSPeter Dunlap } 1200a6d42e7dSPeter Dunlap 1201a6d42e7dSPeter Dunlap /* 1202a6d42e7dSPeter Dunlap * idm_so_tgt_svc_offline 1203a6d42e7dSPeter Dunlap * 1204a6d42e7dSPeter Dunlap * Stop listening on the IP address and port identified by idm_svc_t. 1205a6d42e7dSPeter Dunlap */ 1206a6d42e7dSPeter Dunlap static void 1207a6d42e7dSPeter Dunlap idm_so_tgt_svc_offline(idm_svc_t *is) 1208a6d42e7dSPeter Dunlap { 1209a6d42e7dSPeter Dunlap idm_so_svc_t *so_svc; 1210a6d42e7dSPeter Dunlap mutex_enter(&is->is_mutex); 1211a6d42e7dSPeter Dunlap so_svc = (idm_so_svc_t *)is->is_so_svc; 1212a6d42e7dSPeter Dunlap so_svc->is_thread_running = B_FALSE; 1213a6d42e7dSPeter Dunlap mutex_exit(&is->is_mutex); 1214a6d42e7dSPeter Dunlap 1215a6d42e7dSPeter Dunlap /* 12160f1702c5SYu Xiangning * Teardown socket 1217a6d42e7dSPeter Dunlap */ 12180f1702c5SYu Xiangning idm_sodestroy(so_svc->is_so); 1219a6d42e7dSPeter Dunlap 1220a6d42e7dSPeter Dunlap /* 1221a6d42e7dSPeter Dunlap * Now we expect the port watcher thread to terminate 1222a6d42e7dSPeter Dunlap */ 1223a6d42e7dSPeter Dunlap thread_join(so_svc->is_thread_did); 1224a6d42e7dSPeter Dunlap } 1225a6d42e7dSPeter Dunlap 1226a6d42e7dSPeter Dunlap /* 1227a6d42e7dSPeter Dunlap * Watch thread for target service connection establishment. 1228a6d42e7dSPeter Dunlap */ 1229a6d42e7dSPeter Dunlap void 1230a6d42e7dSPeter Dunlap idm_so_svc_port_watcher(void *arg) 1231a6d42e7dSPeter Dunlap { 1232a6d42e7dSPeter Dunlap idm_svc_t *svc = arg; 12330f1702c5SYu Xiangning ksocket_t new_so; 1234a6d42e7dSPeter Dunlap idm_conn_t *ic; 1235a6d42e7dSPeter Dunlap idm_status_t idmrc; 1236a6d42e7dSPeter Dunlap idm_so_svc_t *so_svc; 1237a6d42e7dSPeter Dunlap int rc; 1238a6d42e7dSPeter Dunlap const uint32_t off = 0; 12390f1702c5SYu Xiangning struct sockaddr_in6 t_addr; 12400f1702c5SYu Xiangning socklen_t t_addrlen; 1241a6d42e7dSPeter Dunlap 12420f1702c5SYu Xiangning bzero(&t_addr, sizeof (struct sockaddr_in6)); 12430f1702c5SYu Xiangning t_addrlen = sizeof (struct sockaddr_in6); 1244a6d42e7dSPeter Dunlap mutex_enter(&svc->is_mutex); 1245a6d42e7dSPeter Dunlap 1246a6d42e7dSPeter Dunlap so_svc = svc->is_so_svc; 1247a6d42e7dSPeter Dunlap so_svc->is_thread_running = B_TRUE; 1248a6d42e7dSPeter Dunlap so_svc->is_thread_did = so_svc->is_thread->t_did; 1249a6d42e7dSPeter Dunlap 1250a6d42e7dSPeter Dunlap cv_signal(&svc->is_cv); 1251a6d42e7dSPeter Dunlap 1252a6d42e7dSPeter Dunlap IDM_SVC_LOG(CE_NOTE, "iSCSI service (%p/%d) online", (void *)svc, 1253a6d42e7dSPeter Dunlap svc->is_svc_req.sr_port); 1254a6d42e7dSPeter Dunlap 1255a6d42e7dSPeter Dunlap while (so_svc->is_thread_running) { 1256a6d42e7dSPeter Dunlap mutex_exit(&svc->is_mutex); 1257a6d42e7dSPeter Dunlap 12580f1702c5SYu Xiangning if ((rc = ksocket_accept(so_svc->is_so, 12590f1702c5SYu Xiangning (struct sockaddr *)&t_addr, &t_addrlen, 12600f1702c5SYu Xiangning &new_so, CRED())) != 0) { 1261a6d42e7dSPeter Dunlap mutex_enter(&svc->is_mutex); 1262a6d42e7dSPeter Dunlap if (rc == ECONNABORTED) 1263a6d42e7dSPeter Dunlap continue; 1264a6d42e7dSPeter Dunlap /* Connection problem */ 1265a6d42e7dSPeter Dunlap break; 1266a6d42e7dSPeter Dunlap } 1267a6d42e7dSPeter Dunlap /* 1268a6d42e7dSPeter Dunlap * Turn off SO_MAC_EXEMPT so future sobinds succeed 1269a6d42e7dSPeter Dunlap */ 12700f1702c5SYu Xiangning (void) ksocket_setsockopt(new_so, SOL_SOCKET, SO_MAC_EXEMPT, 12710f1702c5SYu Xiangning (char *)&off, sizeof (off), CRED()); 1272a6d42e7dSPeter Dunlap 1273a6d42e7dSPeter Dunlap idmrc = idm_svc_conn_create(svc, IDM_TRANSPORT_TYPE_SOCKETS, 1274a6d42e7dSPeter Dunlap &ic); 1275a6d42e7dSPeter Dunlap if (idmrc != IDM_STATUS_SUCCESS) { 1276a6d42e7dSPeter Dunlap /* Drop connection */ 1277a6d42e7dSPeter Dunlap idm_soshutdown(new_so); 1278a6d42e7dSPeter Dunlap idm_sodestroy(new_so); 1279a6d42e7dSPeter Dunlap mutex_enter(&svc->is_mutex); 1280a6d42e7dSPeter Dunlap continue; 1281a6d42e7dSPeter Dunlap } 1282a6d42e7dSPeter Dunlap 1283a6d42e7dSPeter Dunlap idmrc = idm_so_tgt_conn_create(ic, new_so); 1284a6d42e7dSPeter Dunlap if (idmrc != IDM_STATUS_SUCCESS) { 1285a6d42e7dSPeter Dunlap idm_svc_conn_destroy(ic); 1286a6d42e7dSPeter Dunlap idm_soshutdown(new_so); 1287a6d42e7dSPeter Dunlap idm_sodestroy(new_so); 1288a6d42e7dSPeter Dunlap mutex_enter(&svc->is_mutex); 1289a6d42e7dSPeter Dunlap continue; 1290a6d42e7dSPeter Dunlap } 1291a6d42e7dSPeter Dunlap 1292a6d42e7dSPeter Dunlap /* 1293a6d42e7dSPeter Dunlap * Kick the state machine. At CS_S3_XPT_UP the state machine 1294a6d42e7dSPeter Dunlap * will notify the client (target) about the new connection. 1295a6d42e7dSPeter Dunlap */ 1296a6d42e7dSPeter Dunlap idm_conn_event(ic, CE_CONNECT_ACCEPT, NULL); 1297a6d42e7dSPeter Dunlap 1298a6d42e7dSPeter Dunlap mutex_enter(&svc->is_mutex); 1299a6d42e7dSPeter Dunlap } 13000f1702c5SYu Xiangning ksocket_rele(so_svc->is_so); 1301a6d42e7dSPeter Dunlap so_svc->is_thread_running = B_FALSE; 1302a6d42e7dSPeter Dunlap mutex_exit(&svc->is_mutex); 1303a6d42e7dSPeter Dunlap 1304a6d42e7dSPeter Dunlap IDM_SVC_LOG(CE_NOTE, "iSCSI service (%p/%d) offline", (void *)svc, 1305a6d42e7dSPeter Dunlap svc->is_svc_req.sr_port); 1306a6d42e7dSPeter Dunlap 1307a6d42e7dSPeter Dunlap thread_exit(); 1308a6d42e7dSPeter Dunlap } 1309a6d42e7dSPeter Dunlap 1310a6d42e7dSPeter Dunlap /* 1311a6d42e7dSPeter Dunlap * idm_so_free_task_rsrc() stops any ongoing processing of the task and 1312a6d42e7dSPeter Dunlap * frees resources associated with the task. 1313a6d42e7dSPeter Dunlap * 1314a6d42e7dSPeter Dunlap * It's not clear that this should return idm_status_t. What do we do 1315a6d42e7dSPeter Dunlap * if it fails? 1316a6d42e7dSPeter Dunlap */ 1317a6d42e7dSPeter Dunlap static idm_status_t 1318a6d42e7dSPeter Dunlap idm_so_free_task_rsrc(idm_task_t *idt) 1319a6d42e7dSPeter Dunlap { 1320a6d42e7dSPeter Dunlap idm_buf_t *idb; 1321a6d42e7dSPeter Dunlap 132230e7468fSPeter Dunlap /* 132330e7468fSPeter Dunlap * There is nothing to cleanup on initiator connections 132430e7468fSPeter Dunlap */ 132530e7468fSPeter Dunlap if (IDM_CONN_ISINI(idt->idt_ic)) 132630e7468fSPeter Dunlap return (IDM_STATUS_SUCCESS); 132730e7468fSPeter Dunlap 1328a6d42e7dSPeter Dunlap /* 1329a6d42e7dSPeter Dunlap * If this is a target connection, call idm_buf_rx_from_ini_done for 1330a6d42e7dSPeter Dunlap * any buffer on the "outbufv" list with idb->idb_in_transport==B_TRUE. 1331a6d42e7dSPeter Dunlap * 1332a6d42e7dSPeter Dunlap * In addition, remove any buffers associated with this task from 1333a6d42e7dSPeter Dunlap * the ic_tx_list. We'll do this by walking the idt_inbufv list, but 1334a6d42e7dSPeter Dunlap * items don't actually get removed from that list (and completion 1335a6d42e7dSPeter Dunlap * routines called) until idm_task_cleanup. 1336a6d42e7dSPeter Dunlap */ 1337a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 1338a6d42e7dSPeter Dunlap 1339a6d42e7dSPeter Dunlap for (idb = list_head(&idt->idt_outbufv); idb != NULL; 1340a6d42e7dSPeter Dunlap idb = list_next(&idt->idt_outbufv, idb)) { 1341a6d42e7dSPeter Dunlap if (idb->idb_in_transport) { 1342a6d42e7dSPeter Dunlap /* 1343a6d42e7dSPeter Dunlap * idm_buf_rx_from_ini_done releases idt->idt_mutex 1344a6d42e7dSPeter Dunlap */ 1345a668b114SPriya Krishnan DTRACE_ISCSI_8(xfer__done, idm_conn_t *, idt->idt_ic, 1346a668b114SPriya Krishnan uintptr_t, idb->idb_buf, 1347a668b114SPriya Krishnan uint32_t, idb->idb_bufoffset, 1348a668b114SPriya Krishnan uint64_t, 0, uint32_t, 0, uint32_t, 0, 1349a668b114SPriya Krishnan uint32_t, idb->idb_xfer_len, 1350a668b114SPriya Krishnan int, XFER_BUF_RX_FROM_INI); 1351a6d42e7dSPeter Dunlap idm_buf_rx_from_ini_done(idt, idb, IDM_STATUS_ABORTED); 1352a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 1353a6d42e7dSPeter Dunlap } 1354a6d42e7dSPeter Dunlap } 1355a6d42e7dSPeter Dunlap 1356a6d42e7dSPeter Dunlap for (idb = list_head(&idt->idt_inbufv); idb != NULL; 1357a6d42e7dSPeter Dunlap idb = list_next(&idt->idt_inbufv, idb)) { 1358a6d42e7dSPeter Dunlap /* 1359a6d42e7dSPeter Dunlap * We want to remove these items from the tx_list as well, 1360a6d42e7dSPeter Dunlap * but knowing it's in the idt_inbufv list is not a guarantee 1361a6d42e7dSPeter Dunlap * that it's in the tx_list. If it's on the tx list then 1362a6d42e7dSPeter Dunlap * let idm_sotx_thread() clean it up. 1363a6d42e7dSPeter Dunlap */ 1364a6d42e7dSPeter Dunlap if (idb->idb_in_transport && !idb->idb_tx_thread) { 1365a6d42e7dSPeter Dunlap /* 1366a6d42e7dSPeter Dunlap * idm_buf_tx_to_ini_done releases idt->idt_mutex 1367a6d42e7dSPeter Dunlap */ 1368a668b114SPriya Krishnan DTRACE_ISCSI_8(xfer__done, idm_conn_t *, idt->idt_ic, 1369a668b114SPriya Krishnan uintptr_t, idb->idb_buf, 1370a668b114SPriya Krishnan uint32_t, idb->idb_bufoffset, 1371a668b114SPriya Krishnan uint64_t, 0, uint32_t, 0, uint32_t, 0, 1372a668b114SPriya Krishnan uint32_t, idb->idb_xfer_len, 1373a668b114SPriya Krishnan int, XFER_BUF_TX_TO_INI); 1374a6d42e7dSPeter Dunlap idm_buf_tx_to_ini_done(idt, idb, IDM_STATUS_ABORTED); 1375a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 1376a6d42e7dSPeter Dunlap } 1377a6d42e7dSPeter Dunlap } 1378a6d42e7dSPeter Dunlap 1379a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1380a6d42e7dSPeter Dunlap 1381a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 1382a6d42e7dSPeter Dunlap } 1383a6d42e7dSPeter Dunlap 1384a6d42e7dSPeter Dunlap /* 1385a6d42e7dSPeter Dunlap * idm_so_negotiate_key_values() validates the key values for this connection 1386a6d42e7dSPeter Dunlap */ 1387a6d42e7dSPeter Dunlap /* ARGSUSED */ 1388a6d42e7dSPeter Dunlap static kv_status_t 1389a6d42e7dSPeter Dunlap idm_so_negotiate_key_values(idm_conn_t *it, nvlist_t *request_nvl, 1390a6d42e7dSPeter Dunlap nvlist_t *response_nvl, nvlist_t *negotiated_nvl) 1391a6d42e7dSPeter Dunlap { 1392a6d42e7dSPeter Dunlap /* All parameters are negotiated at the iscsit level */ 1393a6d42e7dSPeter Dunlap return (KV_HANDLED); 1394a6d42e7dSPeter Dunlap } 1395a6d42e7dSPeter Dunlap 1396a6d42e7dSPeter Dunlap /* 1397a6d42e7dSPeter Dunlap * idm_so_notice_key_values() activates the negotiated key values for 1398a6d42e7dSPeter Dunlap * this connection. 1399a6d42e7dSPeter Dunlap */ 140030e7468fSPeter Dunlap static void 1401a6d42e7dSPeter Dunlap idm_so_notice_key_values(idm_conn_t *it, nvlist_t *negotiated_nvl) 1402a6d42e7dSPeter Dunlap { 1403a6d42e7dSPeter Dunlap char *nvp_name; 1404a6d42e7dSPeter Dunlap nvpair_t *nvp; 1405a6d42e7dSPeter Dunlap nvpair_t *next_nvp; 1406a6d42e7dSPeter Dunlap int nvrc; 1407a6d42e7dSPeter Dunlap idm_status_t idm_status; 1408a6d42e7dSPeter Dunlap const idm_kv_xlate_t *ikvx; 140956261083SCharles Ting uint64_t num_val; 1410a6d42e7dSPeter Dunlap 1411a6d42e7dSPeter Dunlap for (nvp = nvlist_next_nvpair(negotiated_nvl, NULL); 1412a6d42e7dSPeter Dunlap nvp != NULL; nvp = next_nvp) { 1413a6d42e7dSPeter Dunlap next_nvp = nvlist_next_nvpair(negotiated_nvl, nvp); 1414a6d42e7dSPeter Dunlap nvp_name = nvpair_name(nvp); 1415a6d42e7dSPeter Dunlap 1416a6d42e7dSPeter Dunlap ikvx = idm_lookup_kv_xlate(nvp_name, strlen(nvp_name)); 1417a6d42e7dSPeter Dunlap switch (ikvx->ik_key_id) { 1418a6d42e7dSPeter Dunlap case KI_HEADER_DIGEST: 1419a6d42e7dSPeter Dunlap case KI_DATA_DIGEST: 1420a6d42e7dSPeter Dunlap idm_status = idm_so_handle_digest(it, nvp, ikvx); 1421a6d42e7dSPeter Dunlap ASSERT(idm_status == 0); 1422a6d42e7dSPeter Dunlap 1423a6d42e7dSPeter Dunlap /* Remove processed item from negotiated_nvl list */ 1424a6d42e7dSPeter Dunlap nvrc = nvlist_remove_all( 1425a6d42e7dSPeter Dunlap negotiated_nvl, ikvx->ik_key_name); 1426a6d42e7dSPeter Dunlap ASSERT(nvrc == 0); 1427a6d42e7dSPeter Dunlap break; 142856261083SCharles Ting case KI_MAX_RECV_DATA_SEGMENT_LENGTH: 142956261083SCharles Ting /* 143056261083SCharles Ting * Just pass the value down to idm layer. 143156261083SCharles Ting * No need to remove it from negotiated_nvl list here. 143256261083SCharles Ting */ 143356261083SCharles Ting nvrc = nvpair_value_uint64(nvp, &num_val); 143456261083SCharles Ting ASSERT(nvrc == 0); 143556261083SCharles Ting it->ic_conn_params.max_xmit_dataseglen = 143656261083SCharles Ting (uint32_t)num_val; 143756261083SCharles Ting break; 1438a6d42e7dSPeter Dunlap default: 1439a6d42e7dSPeter Dunlap break; 1440a6d42e7dSPeter Dunlap } 1441a6d42e7dSPeter Dunlap } 1442a6d42e7dSPeter Dunlap } 1443a6d42e7dSPeter Dunlap 144456261083SCharles Ting /* 144556261083SCharles Ting * idm_so_declare_key_values() declares the key values for this connection 144656261083SCharles Ting */ 144756261083SCharles Ting /* ARGSUSED */ 144856261083SCharles Ting static kv_status_t 144956261083SCharles Ting idm_so_declare_key_values(idm_conn_t *it, nvlist_t *config_nvl, 145056261083SCharles Ting nvlist_t *outgoing_nvl) 145156261083SCharles Ting { 145256261083SCharles Ting char *nvp_name; 145356261083SCharles Ting nvpair_t *nvp; 145456261083SCharles Ting nvpair_t *next_nvp; 145556261083SCharles Ting kv_status_t kvrc; 145656261083SCharles Ting int nvrc = 0; 145756261083SCharles Ting const idm_kv_xlate_t *ikvx; 145856261083SCharles Ting uint64_t num_val; 145956261083SCharles Ting 146056261083SCharles Ting for (nvp = nvlist_next_nvpair(config_nvl, NULL); 146156261083SCharles Ting nvp != NULL && nvrc == 0; nvp = next_nvp) { 146256261083SCharles Ting next_nvp = nvlist_next_nvpair(config_nvl, nvp); 146356261083SCharles Ting nvp_name = nvpair_name(nvp); 146456261083SCharles Ting 146556261083SCharles Ting ikvx = idm_lookup_kv_xlate(nvp_name, strlen(nvp_name)); 146656261083SCharles Ting switch (ikvx->ik_key_id) { 146756261083SCharles Ting case KI_MAX_RECV_DATA_SEGMENT_LENGTH: 146856261083SCharles Ting if ((nvrc = nvpair_value_uint64(nvp, &num_val)) != 0) { 146956261083SCharles Ting break; 147056261083SCharles Ting } 147156261083SCharles Ting if (outgoing_nvl && 147256261083SCharles Ting (nvrc = nvlist_add_uint64(outgoing_nvl, 147356261083SCharles Ting nvp_name, num_val)) != 0) { 147456261083SCharles Ting break; 147556261083SCharles Ting } 147656261083SCharles Ting it->ic_conn_params.max_recv_dataseglen = 147756261083SCharles Ting (uint32_t)num_val; 147856261083SCharles Ting break; 147956261083SCharles Ting default: 148056261083SCharles Ting break; 148156261083SCharles Ting } 148256261083SCharles Ting } 148356261083SCharles Ting kvrc = idm_nvstat_to_kvstat(nvrc); 148456261083SCharles Ting return (kvrc); 148556261083SCharles Ting } 1486a6d42e7dSPeter Dunlap 1487a6d42e7dSPeter Dunlap static idm_status_t 1488a6d42e7dSPeter Dunlap idm_so_handle_digest(idm_conn_t *it, nvpair_t *digest_choice, 1489a6d42e7dSPeter Dunlap const idm_kv_xlate_t *ikvx) 1490a6d42e7dSPeter Dunlap { 1491a6d42e7dSPeter Dunlap int nvrc; 1492a6d42e7dSPeter Dunlap char *digest_choice_string; 1493a6d42e7dSPeter Dunlap 1494a6d42e7dSPeter Dunlap nvrc = nvpair_value_string(digest_choice, 1495a6d42e7dSPeter Dunlap &digest_choice_string); 1496a6d42e7dSPeter Dunlap ASSERT(nvrc == 0); 1497a6d42e7dSPeter Dunlap if (strcasecmp(digest_choice_string, "crc32c") == 0) { 1498a6d42e7dSPeter Dunlap switch (ikvx->ik_key_id) { 1499a6d42e7dSPeter Dunlap case KI_HEADER_DIGEST: 1500a6d42e7dSPeter Dunlap it->ic_conn_flags |= IDM_CONN_HEADER_DIGEST; 1501a6d42e7dSPeter Dunlap break; 1502a6d42e7dSPeter Dunlap case KI_DATA_DIGEST: 1503a6d42e7dSPeter Dunlap it->ic_conn_flags |= IDM_CONN_DATA_DIGEST; 1504a6d42e7dSPeter Dunlap break; 1505a6d42e7dSPeter Dunlap default: 1506a6d42e7dSPeter Dunlap ASSERT(0); 1507a6d42e7dSPeter Dunlap break; 1508a6d42e7dSPeter Dunlap } 1509a6d42e7dSPeter Dunlap } else if (strcasecmp(digest_choice_string, "none") == 0) { 1510a6d42e7dSPeter Dunlap switch (ikvx->ik_key_id) { 1511a6d42e7dSPeter Dunlap case KI_HEADER_DIGEST: 1512a6d42e7dSPeter Dunlap it->ic_conn_flags &= ~IDM_CONN_HEADER_DIGEST; 1513a6d42e7dSPeter Dunlap break; 1514a6d42e7dSPeter Dunlap case KI_DATA_DIGEST: 1515a6d42e7dSPeter Dunlap it->ic_conn_flags &= ~IDM_CONN_DATA_DIGEST; 1516a6d42e7dSPeter Dunlap break; 1517a6d42e7dSPeter Dunlap default: 1518a6d42e7dSPeter Dunlap ASSERT(0); 1519a6d42e7dSPeter Dunlap break; 1520a6d42e7dSPeter Dunlap } 1521a6d42e7dSPeter Dunlap } else { 1522a6d42e7dSPeter Dunlap ASSERT(0); 1523a6d42e7dSPeter Dunlap } 1524a6d42e7dSPeter Dunlap 1525a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 1526a6d42e7dSPeter Dunlap } 1527a6d42e7dSPeter Dunlap 1528a6d42e7dSPeter Dunlap 1529a6d42e7dSPeter Dunlap /* 1530a6d42e7dSPeter Dunlap * idm_so_conn_is_capable() verifies that the passed connection is provided 1531a6d42e7dSPeter Dunlap * for by the sockets interface. 1532a6d42e7dSPeter Dunlap */ 1533a6d42e7dSPeter Dunlap /* ARGSUSED */ 1534a6d42e7dSPeter Dunlap static boolean_t 1535a6d42e7dSPeter Dunlap idm_so_conn_is_capable(idm_conn_req_t *ic, idm_transport_caps_t *caps) 1536a6d42e7dSPeter Dunlap { 1537a6d42e7dSPeter Dunlap return (B_TRUE); 1538a6d42e7dSPeter Dunlap } 1539a6d42e7dSPeter Dunlap 1540a6d42e7dSPeter Dunlap /* 1541a6d42e7dSPeter Dunlap * idm_so_rx_datain() validates the Data Sequence number of the PDU. The 1542a6d42e7dSPeter Dunlap * idm_sorecv_scsidata() function invoked earlier actually reads the data 1543a6d42e7dSPeter Dunlap * off the socket into the appropriate buffers. 1544a6d42e7dSPeter Dunlap */ 1545a6d42e7dSPeter Dunlap static void 1546a6d42e7dSPeter Dunlap idm_so_rx_datain(idm_conn_t *ic, idm_pdu_t *pdu) 1547a6d42e7dSPeter Dunlap { 1548a6d42e7dSPeter Dunlap iscsi_data_hdr_t *bhs; 1549a6d42e7dSPeter Dunlap idm_task_t *idt; 1550a6d42e7dSPeter Dunlap idm_buf_t *idb; 1551a6d42e7dSPeter Dunlap uint32_t datasn; 1552a6d42e7dSPeter Dunlap size_t offset; 1553a6d42e7dSPeter Dunlap iscsi_hdr_t *ihp = (iscsi_hdr_t *)pdu->isp_hdr; 1554a6d42e7dSPeter Dunlap iscsi_data_rsp_hdr_t *idrhp = (iscsi_data_rsp_hdr_t *)ihp; 1555a6d42e7dSPeter Dunlap 1556a6d42e7dSPeter Dunlap ASSERT(ic != NULL); 1557a6d42e7dSPeter Dunlap ASSERT(pdu != NULL); 1558a6d42e7dSPeter Dunlap 1559a6d42e7dSPeter Dunlap bhs = (iscsi_data_hdr_t *)pdu->isp_hdr; 1560a6d42e7dSPeter Dunlap datasn = ntohl(bhs->datasn); 1561a6d42e7dSPeter Dunlap offset = ntohl(bhs->offset); 1562a6d42e7dSPeter Dunlap 1563a6d42e7dSPeter Dunlap ASSERT(bhs->opcode == ISCSI_OP_SCSI_DATA_RSP); 1564a6d42e7dSPeter Dunlap 1565a6d42e7dSPeter Dunlap /* 1566a6d42e7dSPeter Dunlap * Look up the task corresponding to the initiator task tag 1567a6d42e7dSPeter Dunlap * to get the buffers affiliated with the task. 1568a6d42e7dSPeter Dunlap */ 1569a6d42e7dSPeter Dunlap idt = idm_task_find(ic, bhs->itt, bhs->ttt); 1570a6d42e7dSPeter Dunlap if (idt == NULL) { 1571a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, "idm_so_rx_datain: failed to find task"); 1572a6d42e7dSPeter Dunlap idm_pdu_rx_protocol_error(ic, pdu); 1573a6d42e7dSPeter Dunlap return; 1574a6d42e7dSPeter Dunlap } 1575a6d42e7dSPeter Dunlap 1576a6d42e7dSPeter Dunlap idb = pdu->isp_sorx_buf; 1577a6d42e7dSPeter Dunlap if (idb == NULL) { 1578a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, 1579a6d42e7dSPeter Dunlap "idm_so_rx_datain: failed to find buffer"); 1580a6d42e7dSPeter Dunlap idm_task_rele(idt); 1581a6d42e7dSPeter Dunlap idm_pdu_rx_protocol_error(ic, pdu); 1582a6d42e7dSPeter Dunlap return; 1583a6d42e7dSPeter Dunlap } 1584a6d42e7dSPeter Dunlap 1585a6d42e7dSPeter Dunlap /* 1586a6d42e7dSPeter Dunlap * DataSN values should be sequential and should not have any gaps or 1587a6d42e7dSPeter Dunlap * repetitions. Check the DataSN with the one stored in the task. 1588a6d42e7dSPeter Dunlap */ 1589a6d42e7dSPeter Dunlap if (datasn == idt->idt_exp_datasn) { 1590a6d42e7dSPeter Dunlap idt->idt_exp_datasn++; /* keep track of DataSN received */ 1591a6d42e7dSPeter Dunlap } else { 1592a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, "idm_so_rx_datain: datasn out of order"); 1593a6d42e7dSPeter Dunlap idm_task_rele(idt); 1594a6d42e7dSPeter Dunlap idm_pdu_rx_protocol_error(ic, pdu); 1595a6d42e7dSPeter Dunlap return; 1596a6d42e7dSPeter Dunlap } 1597a6d42e7dSPeter Dunlap 1598a6d42e7dSPeter Dunlap /* 1599a6d42e7dSPeter Dunlap * PDUs in a sequence should be in continuously increasing 1600a6d42e7dSPeter Dunlap * address offset 1601a6d42e7dSPeter Dunlap */ 1602a6d42e7dSPeter Dunlap if (offset != idb->idb_exp_offset) { 1603a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, "idm_so_rx_datain: unexpected offset"); 160430e7468fSPeter Dunlap idm_task_rele(idt); 1605a6d42e7dSPeter Dunlap idm_pdu_rx_protocol_error(ic, pdu); 1606a6d42e7dSPeter Dunlap return; 1607a6d42e7dSPeter Dunlap } 1608a6d42e7dSPeter Dunlap /* Expected next relative buffer offset */ 1609a6d42e7dSPeter Dunlap idb->idb_exp_offset += n2h24(bhs->dlength); 161030e7468fSPeter Dunlap idt->idt_rx_bytes += n2h24(bhs->dlength); 161130e7468fSPeter Dunlap 161230e7468fSPeter Dunlap idm_task_rele(idt); 1613a6d42e7dSPeter Dunlap 1614a6d42e7dSPeter Dunlap /* 1615a6d42e7dSPeter Dunlap * For now call scsi_rsp which will process the data rsp 1616a6d42e7dSPeter Dunlap * Revisit, need to provide an explicit client entry point for 1617a6d42e7dSPeter Dunlap * phase collapse completions. 1618a6d42e7dSPeter Dunlap */ 1619a6d42e7dSPeter Dunlap if (((ihp->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_SCSI_DATA_RSP) && 1620a6d42e7dSPeter Dunlap (idrhp->flags & ISCSI_FLAG_DATA_STATUS)) { 1621a6d42e7dSPeter Dunlap (*ic->ic_conn_ops.icb_rx_scsi_rsp)(ic, pdu); 1622a6d42e7dSPeter Dunlap } 1623a6d42e7dSPeter Dunlap 1624a6d42e7dSPeter Dunlap idm_pdu_complete(pdu, IDM_STATUS_SUCCESS); 1625a6d42e7dSPeter Dunlap } 1626a6d42e7dSPeter Dunlap 1627a6d42e7dSPeter Dunlap /* 1628a6d42e7dSPeter Dunlap * The idm_so_rx_dataout() function is used by the iSCSI target to read 1629a6d42e7dSPeter Dunlap * data from the Data-Out PDU sent by the iSCSI initiator. 1630a6d42e7dSPeter Dunlap * 1631a6d42e7dSPeter Dunlap * This function gets the Initiator Task Tag from the PDU BHS and looks up the 1632a6d42e7dSPeter Dunlap * task to get the buffers associated with the PDU. A PDU might span buffers. 1633a6d42e7dSPeter Dunlap * The data is then read into the respective buffer. 1634a6d42e7dSPeter Dunlap */ 1635a6d42e7dSPeter Dunlap static void 1636a6d42e7dSPeter Dunlap idm_so_rx_dataout(idm_conn_t *ic, idm_pdu_t *pdu) 1637a6d42e7dSPeter Dunlap { 1638a6d42e7dSPeter Dunlap 1639a6d42e7dSPeter Dunlap iscsi_data_hdr_t *bhs; 1640a6d42e7dSPeter Dunlap idm_task_t *idt; 1641a6d42e7dSPeter Dunlap idm_buf_t *idb; 1642a6d42e7dSPeter Dunlap size_t offset; 1643a6d42e7dSPeter Dunlap 1644a6d42e7dSPeter Dunlap ASSERT(ic != NULL); 1645a6d42e7dSPeter Dunlap ASSERT(pdu != NULL); 1646a6d42e7dSPeter Dunlap 1647a6d42e7dSPeter Dunlap bhs = (iscsi_data_hdr_t *)pdu->isp_hdr; 1648a6d42e7dSPeter Dunlap offset = ntohl(bhs->offset); 1649a6d42e7dSPeter Dunlap ASSERT(bhs->opcode == ISCSI_OP_SCSI_DATA); 1650a6d42e7dSPeter Dunlap 1651a6d42e7dSPeter Dunlap /* 1652a6d42e7dSPeter Dunlap * Look up the task corresponding to the initiator task tag 1653a6d42e7dSPeter Dunlap * to get the buffers affiliated with the task. 1654a6d42e7dSPeter Dunlap */ 1655a6d42e7dSPeter Dunlap idt = idm_task_find(ic, bhs->itt, bhs->ttt); 1656a6d42e7dSPeter Dunlap if (idt == NULL) { 1657a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, 1658a6d42e7dSPeter Dunlap "idm_so_rx_dataout: failed to find task"); 1659a6d42e7dSPeter Dunlap idm_pdu_rx_protocol_error(ic, pdu); 1660a6d42e7dSPeter Dunlap return; 1661a6d42e7dSPeter Dunlap } 1662a6d42e7dSPeter Dunlap 1663a6d42e7dSPeter Dunlap idb = pdu->isp_sorx_buf; 1664a6d42e7dSPeter Dunlap if (idb == NULL) { 1665a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, 1666a6d42e7dSPeter Dunlap "idm_so_rx_dataout: failed to find buffer"); 1667a6d42e7dSPeter Dunlap idm_task_rele(idt); 1668a6d42e7dSPeter Dunlap idm_pdu_rx_protocol_error(ic, pdu); 1669a6d42e7dSPeter Dunlap return; 1670a6d42e7dSPeter Dunlap } 1671a6d42e7dSPeter Dunlap 1672a6d42e7dSPeter Dunlap /* Keep track of data transferred - check data offsets */ 1673a6d42e7dSPeter Dunlap if (offset != idb->idb_exp_offset) { 1674a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_NOTE, "idm_so_rx_dataout: offset out of seq: " 1675a6d42e7dSPeter Dunlap "%ld, %d", offset, idb->idb_exp_offset); 1676a6d42e7dSPeter Dunlap idm_task_rele(idt); 1677a6d42e7dSPeter Dunlap idm_pdu_rx_protocol_error(ic, pdu); 1678a6d42e7dSPeter Dunlap return; 1679a6d42e7dSPeter Dunlap } 1680a6d42e7dSPeter Dunlap /* Expected next relative offset */ 1681a6d42e7dSPeter Dunlap idb->idb_exp_offset += ntoh24(bhs->dlength); 168230e7468fSPeter Dunlap idt->idt_rx_bytes += n2h24(bhs->dlength); 1683a6d42e7dSPeter Dunlap 1684a6d42e7dSPeter Dunlap /* 1685a6d42e7dSPeter Dunlap * Call the buffer callback when the transfer is complete 1686a6d42e7dSPeter Dunlap * 1687a6d42e7dSPeter Dunlap * The connection state machine should only abort tasks after 1688a6d42e7dSPeter Dunlap * shutting down the connection so we are assured that there 1689a6d42e7dSPeter Dunlap * won't be a simultaneous attempt to abort this task at the 1690a6d42e7dSPeter Dunlap * same time as we are processing this PDU (due to a connection 1691a6d42e7dSPeter Dunlap * state change). 1692a6d42e7dSPeter Dunlap */ 1693a6d42e7dSPeter Dunlap if (bhs->flags & ISCSI_FLAG_FINAL) { 1694a6d42e7dSPeter Dunlap /* 1695a6d42e7dSPeter Dunlap * We only want to call idm_buf_rx_from_ini_done once 1696a6d42e7dSPeter Dunlap * per transfer. It's possible that this task has 1697a6d42e7dSPeter Dunlap * already been aborted in which case 1698a6d42e7dSPeter Dunlap * idm_so_free_task_rsrc will call idm_buf_rx_from_ini_done 1699a6d42e7dSPeter Dunlap * for each buffer with idb_in_transport==B_TRUE. To 1700a6d42e7dSPeter Dunlap * close this window and ensure that this doesn't happen, 1701a6d42e7dSPeter Dunlap * we'll clear idb->idb_in_transport now while holding 1702a6d42e7dSPeter Dunlap * the task mutex. This is only really an issue for 1703a6d42e7dSPeter Dunlap * SCSI task abort -- if tasks were being aborted because 1704a6d42e7dSPeter Dunlap * of a connection state change the state machine would 1705a6d42e7dSPeter Dunlap * have already stopped the receive thread. 1706a6d42e7dSPeter Dunlap */ 1707a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 1708a6d42e7dSPeter Dunlap 1709a6d42e7dSPeter Dunlap /* 1710a6d42e7dSPeter Dunlap * Release the task hold here (obtained in idm_task_find) 1711a6d42e7dSPeter Dunlap * because the task may complete synchronously during 1712a6d42e7dSPeter Dunlap * idm_buf_rx_from_ini_done. Since we still have an active 1713a6d42e7dSPeter Dunlap * buffer we know there is at least one additional hold on idt. 1714a6d42e7dSPeter Dunlap */ 1715a6d42e7dSPeter Dunlap idm_task_rele(idt); 1716a6d42e7dSPeter Dunlap 1717a6d42e7dSPeter Dunlap /* 1718a6d42e7dSPeter Dunlap * idm_buf_rx_from_ini_done releases idt->idt_mutex 1719a6d42e7dSPeter Dunlap */ 1720a668b114SPriya Krishnan DTRACE_ISCSI_8(xfer__done, idm_conn_t *, idt->idt_ic, 1721a668b114SPriya Krishnan uintptr_t, idb->idb_buf, uint32_t, idb->idb_bufoffset, 1722a668b114SPriya Krishnan uint64_t, 0, uint32_t, 0, uint32_t, 0, 1723a668b114SPriya Krishnan uint32_t, idb->idb_xfer_len, 1724a668b114SPriya Krishnan int, XFER_BUF_RX_FROM_INI); 1725a6d42e7dSPeter Dunlap idm_buf_rx_from_ini_done(idt, idb, IDM_STATUS_SUCCESS); 1726a6d42e7dSPeter Dunlap idm_pdu_complete(pdu, IDM_STATUS_SUCCESS); 1727a6d42e7dSPeter Dunlap return; 1728a6d42e7dSPeter Dunlap } 1729a6d42e7dSPeter Dunlap 1730a6d42e7dSPeter Dunlap idm_task_rele(idt); 1731a6d42e7dSPeter Dunlap idm_pdu_complete(pdu, IDM_STATUS_SUCCESS); 1732a6d42e7dSPeter Dunlap } 1733a6d42e7dSPeter Dunlap 1734a6d42e7dSPeter Dunlap /* 1735a6d42e7dSPeter Dunlap * The idm_so_rx_rtt() function is used by the iSCSI initiator to handle 1736a6d42e7dSPeter Dunlap * the R2T PDU sent by the iSCSI target indicating that it is ready to 1737a6d42e7dSPeter Dunlap * accept data. This gets the Initiator Task Tag (itt) from the PDU BHS 1738a6d42e7dSPeter Dunlap * and looks up the task in the task tree using the itt to get the output 1739a6d42e7dSPeter Dunlap * buffers associated the task. The R2T PDU contains the offset of the 1740a6d42e7dSPeter Dunlap * requested data and the data length. This function then constructs a 1741a6d42e7dSPeter Dunlap * sequence of iSCSI PDUs and outputs the requested data. Each Data-Out 1742a6d42e7dSPeter Dunlap * PDU is associated with the R2T by the Target Transfer Tag (ttt). 1743a6d42e7dSPeter Dunlap */ 174430e7468fSPeter Dunlap 1745a6d42e7dSPeter Dunlap static void 1746a6d42e7dSPeter Dunlap idm_so_rx_rtt(idm_conn_t *ic, idm_pdu_t *pdu) 1747a6d42e7dSPeter Dunlap { 1748a6d42e7dSPeter Dunlap idm_task_t *idt; 1749a6d42e7dSPeter Dunlap idm_buf_t *idb; 1750a6d42e7dSPeter Dunlap iscsi_rtt_hdr_t *rtt_hdr; 1751a6d42e7dSPeter Dunlap uint32_t data_offset; 175230e7468fSPeter Dunlap uint32_t data_length; 1753a6d42e7dSPeter Dunlap 1754a6d42e7dSPeter Dunlap ASSERT(ic != NULL); 1755a6d42e7dSPeter Dunlap ASSERT(pdu != NULL); 1756a6d42e7dSPeter Dunlap 1757a6d42e7dSPeter Dunlap rtt_hdr = (iscsi_rtt_hdr_t *)pdu->isp_hdr; 1758a6d42e7dSPeter Dunlap data_offset = ntohl(rtt_hdr->data_offset); 175930e7468fSPeter Dunlap data_length = ntohl(rtt_hdr->data_length); 1760a6d42e7dSPeter Dunlap idt = idm_task_find(ic, rtt_hdr->itt, rtt_hdr->ttt); 1761a6d42e7dSPeter Dunlap 1762a6d42e7dSPeter Dunlap if (idt == NULL) { 1763a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, "idm_so_rx_rtt: could not find task"); 1764a6d42e7dSPeter Dunlap idm_pdu_rx_protocol_error(ic, pdu); 1765a6d42e7dSPeter Dunlap return; 1766a6d42e7dSPeter Dunlap } 1767a6d42e7dSPeter Dunlap 1768a6d42e7dSPeter Dunlap /* Find the buffer bound to the task by the iSCSI initiator */ 1769a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 1770a6d42e7dSPeter Dunlap idb = idm_buf_find(&idt->idt_outbufv, data_offset); 1771a6d42e7dSPeter Dunlap if (idb == NULL) { 1772a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1773a6d42e7dSPeter Dunlap idm_task_rele(idt); 1774a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, "idm_so_rx_rtt: could not find buffer"); 1775a6d42e7dSPeter Dunlap idm_pdu_rx_protocol_error(ic, pdu); 1776a6d42e7dSPeter Dunlap return; 1777a6d42e7dSPeter Dunlap } 1778a6d42e7dSPeter Dunlap 177930e7468fSPeter Dunlap /* return buffer contains this data */ 178030e7468fSPeter Dunlap if (data_offset + data_length > idb->idb_buflen) { 178130e7468fSPeter Dunlap /* Overflow */ 178230e7468fSPeter Dunlap mutex_exit(&idt->idt_mutex); 178330e7468fSPeter Dunlap idm_task_rele(idt); 178430e7468fSPeter Dunlap IDM_CONN_LOG(CE_WARN, "idm_so_rx_rtt: read from outside " 178530e7468fSPeter Dunlap "buffer"); 178630e7468fSPeter Dunlap idm_pdu_rx_protocol_error(ic, pdu); 178730e7468fSPeter Dunlap return; 178830e7468fSPeter Dunlap } 178930e7468fSPeter Dunlap 179030e7468fSPeter Dunlap idt->idt_r2t_ttt = rtt_hdr->ttt; 179130e7468fSPeter Dunlap idt->idt_exp_datasn = 0; 179230e7468fSPeter Dunlap 179330e7468fSPeter Dunlap idm_so_send_rtt_data(ic, idt, idb, data_offset, 179430e7468fSPeter Dunlap ntohl(rtt_hdr->data_length)); 1795a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1796a6d42e7dSPeter Dunlap 1797a6d42e7dSPeter Dunlap idm_pdu_complete(pdu, IDM_STATUS_SUCCESS); 1798a6d42e7dSPeter Dunlap idm_task_rele(idt); 1799a6d42e7dSPeter Dunlap 1800a6d42e7dSPeter Dunlap } 1801a6d42e7dSPeter Dunlap 1802a6d42e7dSPeter Dunlap idm_status_t 1803a6d42e7dSPeter Dunlap idm_sorecvdata(idm_conn_t *ic, idm_pdu_t *pdu) 1804a6d42e7dSPeter Dunlap { 1805a6d42e7dSPeter Dunlap uint8_t pad[ISCSI_PAD_WORD_LEN]; 1806a6d42e7dSPeter Dunlap int pad_len; 1807a6d42e7dSPeter Dunlap uint32_t data_digest_crc; 1808a6d42e7dSPeter Dunlap uint32_t crc_calculated; 1809a6d42e7dSPeter Dunlap int total_len; 1810a6d42e7dSPeter Dunlap idm_so_conn_t *so_conn; 1811a6d42e7dSPeter Dunlap 1812a6d42e7dSPeter Dunlap so_conn = ic->ic_transport_private; 1813a6d42e7dSPeter Dunlap 1814a6d42e7dSPeter Dunlap pad_len = ((ISCSI_PAD_WORD_LEN - 1815a6d42e7dSPeter Dunlap (pdu->isp_datalen & (ISCSI_PAD_WORD_LEN - 1))) & 1816a6d42e7dSPeter Dunlap (ISCSI_PAD_WORD_LEN - 1)); 1817a6d42e7dSPeter Dunlap 1818a6d42e7dSPeter Dunlap ASSERT(pdu->isp_iovlen < (PDU_MAX_IOVLEN - 2)); /* pad + data digest */ 1819a6d42e7dSPeter Dunlap 1820a6d42e7dSPeter Dunlap total_len = pdu->isp_datalen; 1821a6d42e7dSPeter Dunlap 1822a6d42e7dSPeter Dunlap if (pad_len) { 1823a6d42e7dSPeter Dunlap pdu->isp_iov[pdu->isp_iovlen].iov_base = (char *)&pad; 1824a6d42e7dSPeter Dunlap pdu->isp_iov[pdu->isp_iovlen].iov_len = pad_len; 1825a6d42e7dSPeter Dunlap total_len += pad_len; 1826a6d42e7dSPeter Dunlap pdu->isp_iovlen++; 1827a6d42e7dSPeter Dunlap } 1828a6d42e7dSPeter Dunlap 1829a6d42e7dSPeter Dunlap /* setup data digest */ 1830a6d42e7dSPeter Dunlap if ((ic->ic_conn_flags & IDM_CONN_DATA_DIGEST) != 0) { 1831a6d42e7dSPeter Dunlap pdu->isp_iov[pdu->isp_iovlen].iov_base = 1832a6d42e7dSPeter Dunlap (char *)&data_digest_crc; 1833a6d42e7dSPeter Dunlap pdu->isp_iov[pdu->isp_iovlen].iov_len = 1834a6d42e7dSPeter Dunlap sizeof (data_digest_crc); 1835a6d42e7dSPeter Dunlap total_len += sizeof (data_digest_crc); 1836a6d42e7dSPeter Dunlap pdu->isp_iovlen++; 1837a6d42e7dSPeter Dunlap } 1838a6d42e7dSPeter Dunlap 183930e7468fSPeter Dunlap pdu->isp_data = (uint8_t *)(uintptr_t)pdu->isp_iov[0].iov_base; 184030e7468fSPeter Dunlap 1841a6d42e7dSPeter Dunlap if (idm_iov_sorecv(so_conn->ic_so, &pdu->isp_iov[0], 1842a6d42e7dSPeter Dunlap pdu->isp_iovlen, total_len) != 0) { 1843a6d42e7dSPeter Dunlap return (IDM_STATUS_IO); 1844a6d42e7dSPeter Dunlap } 1845a6d42e7dSPeter Dunlap 1846a6d42e7dSPeter Dunlap if ((ic->ic_conn_flags & IDM_CONN_DATA_DIGEST) != 0) { 1847a6d42e7dSPeter Dunlap crc_calculated = idm_crc32c(pdu->isp_data, 1848a6d42e7dSPeter Dunlap pdu->isp_datalen); 1849a6d42e7dSPeter Dunlap if (pad_len) { 1850a6d42e7dSPeter Dunlap crc_calculated = idm_crc32c_continued((char *)&pad, 1851a6d42e7dSPeter Dunlap pad_len, crc_calculated); 1852a6d42e7dSPeter Dunlap } 1853a6d42e7dSPeter Dunlap if (crc_calculated != data_digest_crc) { 1854a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, 1855a6d42e7dSPeter Dunlap "idm_sorecvdata: " 1856a6d42e7dSPeter Dunlap "CRC error: actual 0x%x, calc 0x%x", 1857a6d42e7dSPeter Dunlap data_digest_crc, crc_calculated); 1858a6d42e7dSPeter Dunlap 1859a6d42e7dSPeter Dunlap /* Invalid Data Digest */ 1860a6d42e7dSPeter Dunlap return (IDM_STATUS_DATA_DIGEST); 1861a6d42e7dSPeter Dunlap } 1862a6d42e7dSPeter Dunlap } 1863a6d42e7dSPeter Dunlap 1864a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 1865a6d42e7dSPeter Dunlap } 1866a6d42e7dSPeter Dunlap 1867a6d42e7dSPeter Dunlap /* 1868a6d42e7dSPeter Dunlap * idm_sorecv_scsidata() is used to receive scsi data from the socket. The 1869a6d42e7dSPeter Dunlap * Data-type PDU header must be read into the idm_pdu_t structure prior to 1870a6d42e7dSPeter Dunlap * calling this function. 1871a6d42e7dSPeter Dunlap */ 1872a6d42e7dSPeter Dunlap idm_status_t 1873a6d42e7dSPeter Dunlap idm_sorecv_scsidata(idm_conn_t *ic, idm_pdu_t *pdu) 1874a6d42e7dSPeter Dunlap { 1875a6d42e7dSPeter Dunlap iscsi_data_hdr_t *bhs; 1876a6d42e7dSPeter Dunlap idm_task_t *task; 1877a6d42e7dSPeter Dunlap uint32_t offset; 1878a6d42e7dSPeter Dunlap uint8_t opcode; 1879a6d42e7dSPeter Dunlap uint32_t dlength; 1880a6d42e7dSPeter Dunlap list_t *buflst; 1881a6d42e7dSPeter Dunlap uint32_t xfer_bytes; 1882a6d42e7dSPeter Dunlap idm_status_t status; 1883a6d42e7dSPeter Dunlap 1884a6d42e7dSPeter Dunlap ASSERT(ic != NULL); 1885a6d42e7dSPeter Dunlap ASSERT(pdu != NULL); 1886a6d42e7dSPeter Dunlap 1887a6d42e7dSPeter Dunlap bhs = (iscsi_data_hdr_t *)pdu->isp_hdr; 1888a6d42e7dSPeter Dunlap 1889a6d42e7dSPeter Dunlap offset = ntohl(bhs->offset); 1890a6d42e7dSPeter Dunlap opcode = bhs->opcode; 1891a6d42e7dSPeter Dunlap dlength = n2h24(bhs->dlength); 1892a6d42e7dSPeter Dunlap 1893a6d42e7dSPeter Dunlap ASSERT((opcode == ISCSI_OP_SCSI_DATA_RSP) || 1894a6d42e7dSPeter Dunlap (opcode == ISCSI_OP_SCSI_DATA)); 1895a6d42e7dSPeter Dunlap 1896a6d42e7dSPeter Dunlap /* 1897a6d42e7dSPeter Dunlap * Successful lookup implicitly gets a "hold" on the task. This 1898a6d42e7dSPeter Dunlap * hold must be released before leaving this function. At one 1899a6d42e7dSPeter Dunlap * point we were caching this task context and retaining the hold 1900a6d42e7dSPeter Dunlap * but it turned out to be very difficult to release the hold properly. 1901a6d42e7dSPeter Dunlap * The task can be aborted and the connection shutdown between this 1902a6d42e7dSPeter Dunlap * call and the subsequent expected call to idm_so_rx_datain/ 1903a6d42e7dSPeter Dunlap * idm_so_rx_dataout (in which case those functions are not called). 1904a6d42e7dSPeter Dunlap * Releasing the hold in the PDU callback doesn't work well either 1905a6d42e7dSPeter Dunlap * because the whole task may be completed by then at which point 1906a6d42e7dSPeter Dunlap * it is too late to release the hold -- for better or worse this 1907a6d42e7dSPeter Dunlap * code doesn't wait on the refcnts during normal operation. 1908a6d42e7dSPeter Dunlap * idm_task_find() is very fast and it is not a huge burden if we 1909a6d42e7dSPeter Dunlap * have to do it twice. 1910a6d42e7dSPeter Dunlap */ 1911a6d42e7dSPeter Dunlap task = idm_task_find(ic, bhs->itt, bhs->ttt); 1912a6d42e7dSPeter Dunlap if (task == NULL) { 1913a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, 1914a6d42e7dSPeter Dunlap "idm_sorecv_scsidata: could not find task"); 1915a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 1916a6d42e7dSPeter Dunlap } 1917a6d42e7dSPeter Dunlap 1918a6d42e7dSPeter Dunlap mutex_enter(&task->idt_mutex); 1919a6d42e7dSPeter Dunlap buflst = (opcode == ISCSI_OP_SCSI_DATA_RSP) ? 1920a6d42e7dSPeter Dunlap &task->idt_inbufv : &task->idt_outbufv; 1921a6d42e7dSPeter Dunlap pdu->isp_sorx_buf = idm_buf_find(buflst, offset); 1922a6d42e7dSPeter Dunlap mutex_exit(&task->idt_mutex); 1923a6d42e7dSPeter Dunlap 1924a6d42e7dSPeter Dunlap if (pdu->isp_sorx_buf == NULL) { 1925a6d42e7dSPeter Dunlap idm_task_rele(task); 1926a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, "idm_sorecv_scsidata: could not find " 1927a6d42e7dSPeter Dunlap "buffer for offset %x opcode=%x", 1928a6d42e7dSPeter Dunlap offset, opcode); 1929a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 1930a6d42e7dSPeter Dunlap } 1931a6d42e7dSPeter Dunlap 1932a6d42e7dSPeter Dunlap xfer_bytes = idm_fill_iov(pdu, pdu->isp_sorx_buf, offset, dlength); 1933a6d42e7dSPeter Dunlap ASSERT(xfer_bytes != 0); 1934a6d42e7dSPeter Dunlap if (xfer_bytes != dlength) { 1935a6d42e7dSPeter Dunlap idm_task_rele(task); 1936a6d42e7dSPeter Dunlap /* 1937a6d42e7dSPeter Dunlap * Buffer overflow, connection error. The PDU data is still 1938a6d42e7dSPeter Dunlap * sitting in the socket so we can't use the connection 1939a6d42e7dSPeter Dunlap * again until that data is drained. 1940a6d42e7dSPeter Dunlap */ 1941a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 1942a6d42e7dSPeter Dunlap } 1943a6d42e7dSPeter Dunlap 1944a6d42e7dSPeter Dunlap status = idm_sorecvdata(ic, pdu); 1945a6d42e7dSPeter Dunlap 1946a6d42e7dSPeter Dunlap idm_task_rele(task); 1947a6d42e7dSPeter Dunlap 1948a6d42e7dSPeter Dunlap return (status); 1949a6d42e7dSPeter Dunlap } 1950a6d42e7dSPeter Dunlap 1951a6d42e7dSPeter Dunlap static uint32_t 1952a6d42e7dSPeter Dunlap idm_fill_iov(idm_pdu_t *pdu, idm_buf_t *idb, uint32_t ro, uint32_t dlength) 1953a6d42e7dSPeter Dunlap { 1954a6d42e7dSPeter Dunlap uint32_t buf_ro = ro - idb->idb_bufoffset; 1955a6d42e7dSPeter Dunlap uint32_t xfer_len = min(dlength, idb->idb_buflen - buf_ro); 1956a6d42e7dSPeter Dunlap 1957a6d42e7dSPeter Dunlap ASSERT(ro >= idb->idb_bufoffset); 1958a6d42e7dSPeter Dunlap 1959a6d42e7dSPeter Dunlap pdu->isp_iov[pdu->isp_iovlen].iov_base = 1960a6d42e7dSPeter Dunlap (caddr_t)idb->idb_buf + buf_ro; 1961a6d42e7dSPeter Dunlap pdu->isp_iov[pdu->isp_iovlen].iov_len = xfer_len; 1962a6d42e7dSPeter Dunlap pdu->isp_iovlen++; 1963a6d42e7dSPeter Dunlap 1964a6d42e7dSPeter Dunlap return (xfer_len); 1965a6d42e7dSPeter Dunlap } 1966a6d42e7dSPeter Dunlap 1967a6d42e7dSPeter Dunlap int 1968a6d42e7dSPeter Dunlap idm_sorecv_nonscsidata(idm_conn_t *ic, idm_pdu_t *pdu) 1969a6d42e7dSPeter Dunlap { 1970a6d42e7dSPeter Dunlap pdu->isp_data = kmem_alloc(pdu->isp_datalen, KM_SLEEP); 1971a6d42e7dSPeter Dunlap ASSERT(pdu->isp_data != NULL); 1972a6d42e7dSPeter Dunlap 1973a6d42e7dSPeter Dunlap pdu->isp_databuflen = pdu->isp_datalen; 1974a6d42e7dSPeter Dunlap pdu->isp_iov[0].iov_base = (caddr_t)pdu->isp_data; 1975a6d42e7dSPeter Dunlap pdu->isp_iov[0].iov_len = pdu->isp_datalen; 1976a6d42e7dSPeter Dunlap pdu->isp_iovlen = 1; 1977a6d42e7dSPeter Dunlap /* 1978a6d42e7dSPeter Dunlap * Since we are associating a new data buffer with this received 1979a6d42e7dSPeter Dunlap * PDU we need to set a specific callback to free the data 1980a6d42e7dSPeter Dunlap * after the PDU is processed. 1981a6d42e7dSPeter Dunlap */ 1982a6d42e7dSPeter Dunlap pdu->isp_flags |= IDM_PDU_ADDL_DATA; 1983a6d42e7dSPeter Dunlap pdu->isp_callback = idm_sorx_addl_pdu_cb; 1984a6d42e7dSPeter Dunlap 1985a6d42e7dSPeter Dunlap return (idm_sorecvdata(ic, pdu)); 1986a6d42e7dSPeter Dunlap } 1987a6d42e7dSPeter Dunlap 1988a6d42e7dSPeter Dunlap void 1989a6d42e7dSPeter Dunlap idm_sorx_thread(void *arg) 1990a6d42e7dSPeter Dunlap { 1991a6d42e7dSPeter Dunlap boolean_t conn_failure = B_FALSE; 1992a6d42e7dSPeter Dunlap idm_conn_t *ic = (idm_conn_t *)arg; 1993a6d42e7dSPeter Dunlap idm_so_conn_t *so_conn; 1994a6d42e7dSPeter Dunlap idm_pdu_t *pdu; 1995a6d42e7dSPeter Dunlap idm_status_t rc; 1996a6d42e7dSPeter Dunlap 1997a6d42e7dSPeter Dunlap idm_conn_hold(ic); 1998a6d42e7dSPeter Dunlap 1999a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_mutex); 2000a6d42e7dSPeter Dunlap 2001a6d42e7dSPeter Dunlap so_conn = ic->ic_transport_private; 2002a6d42e7dSPeter Dunlap so_conn->ic_rx_thread_running = B_TRUE; 2003a6d42e7dSPeter Dunlap so_conn->ic_rx_thread_did = so_conn->ic_rx_thread->t_did; 2004a6d42e7dSPeter Dunlap cv_signal(&ic->ic_cv); 2005a6d42e7dSPeter Dunlap 2006a6d42e7dSPeter Dunlap while (so_conn->ic_rx_thread_running) { 2007a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_mutex); 2008a6d42e7dSPeter Dunlap 2009a6d42e7dSPeter Dunlap /* 2010a6d42e7dSPeter Dunlap * Get PDU with default header size (large enough for 2011a6d42e7dSPeter Dunlap * BHS plus any anticipated AHS). PDU from 2012a6d42e7dSPeter Dunlap * the cache will have all values set correctly 2013a6d42e7dSPeter Dunlap * for sockets RX including callback. 2014a6d42e7dSPeter Dunlap */ 2015a6d42e7dSPeter Dunlap pdu = kmem_cache_alloc(idm.idm_sorx_pdu_cache, KM_SLEEP); 2016a6d42e7dSPeter Dunlap pdu->isp_ic = ic; 2017a6d42e7dSPeter Dunlap pdu->isp_flags = 0; 2018a6d42e7dSPeter Dunlap pdu->isp_transport_hdrlen = 0; 2019a6d42e7dSPeter Dunlap 2020a6d42e7dSPeter Dunlap if ((rc = idm_sorecvhdr(ic, pdu)) != 0) { 2021a6d42e7dSPeter Dunlap /* 2022a6d42e7dSPeter Dunlap * Call idm_pdu_complete so that we call the callback 2023a6d42e7dSPeter Dunlap * and ensure any memory allocated in idm_sorecvhdr 2024a6d42e7dSPeter Dunlap * gets freed up. 2025a6d42e7dSPeter Dunlap */ 2026a6d42e7dSPeter Dunlap idm_pdu_complete(pdu, IDM_STATUS_FAIL); 2027a6d42e7dSPeter Dunlap 2028a6d42e7dSPeter Dunlap /* 2029a6d42e7dSPeter Dunlap * If ic_rx_thread_running is still set then 2030a6d42e7dSPeter Dunlap * this is some kind of connection problem 2031a6d42e7dSPeter Dunlap * on the socket. In this case we want to 2032a6d42e7dSPeter Dunlap * generate an event. Otherwise some other 2033a6d42e7dSPeter Dunlap * thread closed the socket due to another 2034a6d42e7dSPeter Dunlap * issue in which case we don't need to 2035a6d42e7dSPeter Dunlap * generate an event. 2036a6d42e7dSPeter Dunlap */ 2037a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_mutex); 2038a6d42e7dSPeter Dunlap if (so_conn->ic_rx_thread_running) { 2039a6d42e7dSPeter Dunlap conn_failure = B_TRUE; 2040a6d42e7dSPeter Dunlap so_conn->ic_rx_thread_running = B_FALSE; 2041a6d42e7dSPeter Dunlap } 2042a6d42e7dSPeter Dunlap 2043a6d42e7dSPeter Dunlap continue; 2044a6d42e7dSPeter Dunlap } 2045a6d42e7dSPeter Dunlap 2046a6d42e7dSPeter Dunlap /* 2047a6d42e7dSPeter Dunlap * Header has been read and validated. Now we need 2048a6d42e7dSPeter Dunlap * to read the PDU data payload (if present). SCSI data 2049a6d42e7dSPeter Dunlap * need to be transferred from the socket directly into 2050a6d42e7dSPeter Dunlap * the associated transfer buffer for the SCSI task. 2051a6d42e7dSPeter Dunlap */ 2052a6d42e7dSPeter Dunlap if (pdu->isp_datalen != 0) { 2053a6d42e7dSPeter Dunlap if ((IDM_PDU_OPCODE(pdu) == ISCSI_OP_SCSI_DATA) || 2054a6d42e7dSPeter Dunlap (IDM_PDU_OPCODE(pdu) == ISCSI_OP_SCSI_DATA_RSP)) { 2055a6d42e7dSPeter Dunlap rc = idm_sorecv_scsidata(ic, pdu); 2056a6d42e7dSPeter Dunlap /* 2057a6d42e7dSPeter Dunlap * All SCSI errors are fatal to the 2058a6d42e7dSPeter Dunlap * connection right now since we have no 2059a6d42e7dSPeter Dunlap * place to put the data. What we need 2060a6d42e7dSPeter Dunlap * is some kind of sink to dispose of unwanted 2061a6d42e7dSPeter Dunlap * SCSI data. For example an invalid task tag 2062a6d42e7dSPeter Dunlap * should not kill the connection (although 2063a6d42e7dSPeter Dunlap * we may want to drop the connection). 2064a6d42e7dSPeter Dunlap */ 2065a6d42e7dSPeter Dunlap } else { 2066a6d42e7dSPeter Dunlap /* 2067a6d42e7dSPeter Dunlap * Not data PDUs so allocate a buffer for the 2068a6d42e7dSPeter Dunlap * data segment and read the remaining data. 2069a6d42e7dSPeter Dunlap */ 2070a6d42e7dSPeter Dunlap rc = idm_sorecv_nonscsidata(ic, pdu); 2071a6d42e7dSPeter Dunlap } 2072a6d42e7dSPeter Dunlap if (rc != 0) { 2073a6d42e7dSPeter Dunlap /* 2074a6d42e7dSPeter Dunlap * Call idm_pdu_complete so that we call the 2075a6d42e7dSPeter Dunlap * callback and ensure any memory allocated 2076a6d42e7dSPeter Dunlap * in idm_sorecvhdr gets freed up. 2077a6d42e7dSPeter Dunlap */ 2078a6d42e7dSPeter Dunlap idm_pdu_complete(pdu, IDM_STATUS_FAIL); 2079a6d42e7dSPeter Dunlap 2080a6d42e7dSPeter Dunlap /* 2081a6d42e7dSPeter Dunlap * If ic_rx_thread_running is still set then 2082a6d42e7dSPeter Dunlap * this is some kind of connection problem 2083a6d42e7dSPeter Dunlap * on the socket. In this case we want to 2084a6d42e7dSPeter Dunlap * generate an event. Otherwise some other 2085a6d42e7dSPeter Dunlap * thread closed the socket due to another 2086a6d42e7dSPeter Dunlap * issue in which case we don't need to 2087a6d42e7dSPeter Dunlap * generate an event. 2088a6d42e7dSPeter Dunlap */ 2089a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_mutex); 2090a6d42e7dSPeter Dunlap if (so_conn->ic_rx_thread_running) { 2091a6d42e7dSPeter Dunlap conn_failure = B_TRUE; 2092a6d42e7dSPeter Dunlap so_conn->ic_rx_thread_running = B_FALSE; 2093a6d42e7dSPeter Dunlap } 2094a6d42e7dSPeter Dunlap continue; 2095a6d42e7dSPeter Dunlap } 2096a6d42e7dSPeter Dunlap } 2097a6d42e7dSPeter Dunlap 2098a6d42e7dSPeter Dunlap /* 2099a6d42e7dSPeter Dunlap * Process RX PDU 2100a6d42e7dSPeter Dunlap */ 2101a6d42e7dSPeter Dunlap idm_pdu_rx(ic, pdu); 2102a6d42e7dSPeter Dunlap 2103a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_mutex); 2104a6d42e7dSPeter Dunlap } 2105a6d42e7dSPeter Dunlap 2106a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_mutex); 2107a6d42e7dSPeter Dunlap 2108a6d42e7dSPeter Dunlap /* 2109a6d42e7dSPeter Dunlap * If we dropped out of the RX processing loop because of 2110a6d42e7dSPeter Dunlap * a socket problem or other connection failure (including 2111a6d42e7dSPeter Dunlap * digest errors) then we need to generate a state machine 2112a6d42e7dSPeter Dunlap * event to shut the connection down. 2113a6d42e7dSPeter Dunlap * If the state machine is already in, for example, INIT_ERROR, this 2114a6d42e7dSPeter Dunlap * event will get dropped, and the TX thread will never be notified 2115a6d42e7dSPeter Dunlap * to shut down. To be safe, we'll just notify it here. 2116a6d42e7dSPeter Dunlap */ 2117a6d42e7dSPeter Dunlap if (conn_failure) { 2118a6d42e7dSPeter Dunlap if (so_conn->ic_tx_thread_running) { 2119a6d42e7dSPeter Dunlap so_conn->ic_tx_thread_running = B_FALSE; 2120a6d42e7dSPeter Dunlap mutex_enter(&so_conn->ic_tx_mutex); 2121a6d42e7dSPeter Dunlap cv_signal(&so_conn->ic_tx_cv); 2122a6d42e7dSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 2123a6d42e7dSPeter Dunlap } 2124a6d42e7dSPeter Dunlap 2125a6d42e7dSPeter Dunlap idm_conn_event(ic, CE_TRANSPORT_FAIL, rc); 2126a6d42e7dSPeter Dunlap } 2127a6d42e7dSPeter Dunlap 2128a6d42e7dSPeter Dunlap idm_conn_rele(ic); 2129a6d42e7dSPeter Dunlap 2130a6d42e7dSPeter Dunlap thread_exit(); 2131a6d42e7dSPeter Dunlap } 2132a6d42e7dSPeter Dunlap 2133a6d42e7dSPeter Dunlap /* 2134a6d42e7dSPeter Dunlap * idm_so_tx 2135a6d42e7dSPeter Dunlap * 2136a6d42e7dSPeter Dunlap * This is the implementation of idm_transport_ops_t's it_tx_pdu entry 2137a6d42e7dSPeter Dunlap * point. By definition, it is supposed to be fast. So, simply queue 2138a6d42e7dSPeter Dunlap * the entry and return. The real work is done by idm_i_so_tx() via 2139a6d42e7dSPeter Dunlap * idm_sotx_thread(). 2140a6d42e7dSPeter Dunlap */ 2141a6d42e7dSPeter Dunlap 2142a6d42e7dSPeter Dunlap static void 2143a6d42e7dSPeter Dunlap idm_so_tx(idm_conn_t *ic, idm_pdu_t *pdu) 2144a6d42e7dSPeter Dunlap { 2145a6d42e7dSPeter Dunlap idm_so_conn_t *so_conn = ic->ic_transport_private; 2146a6d42e7dSPeter Dunlap 2147a6d42e7dSPeter Dunlap ASSERT(pdu->isp_ic == ic); 2148a6d42e7dSPeter Dunlap mutex_enter(&so_conn->ic_tx_mutex); 2149a6d42e7dSPeter Dunlap 2150a6d42e7dSPeter Dunlap if (!so_conn->ic_tx_thread_running) { 2151a6d42e7dSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 2152a6d42e7dSPeter Dunlap idm_pdu_complete(pdu, IDM_STATUS_ABORTED); 2153a6d42e7dSPeter Dunlap return; 2154a6d42e7dSPeter Dunlap } 2155a6d42e7dSPeter Dunlap 2156a6d42e7dSPeter Dunlap list_insert_tail(&so_conn->ic_tx_list, (void *)pdu); 2157a6d42e7dSPeter Dunlap cv_signal(&so_conn->ic_tx_cv); 2158a6d42e7dSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 2159a6d42e7dSPeter Dunlap } 2160a6d42e7dSPeter Dunlap 2161a6d42e7dSPeter Dunlap static idm_status_t 2162a6d42e7dSPeter Dunlap idm_i_so_tx(idm_pdu_t *pdu) 2163a6d42e7dSPeter Dunlap { 2164a6d42e7dSPeter Dunlap idm_conn_t *ic = pdu->isp_ic; 2165a6d42e7dSPeter Dunlap idm_status_t status = IDM_STATUS_SUCCESS; 2166a6d42e7dSPeter Dunlap uint8_t pad[ISCSI_PAD_WORD_LEN]; 2167a6d42e7dSPeter Dunlap int pad_len; 2168a6d42e7dSPeter Dunlap uint32_t hdr_digest_crc; 2169a6d42e7dSPeter Dunlap uint32_t data_digest_crc = 0; 2170a6d42e7dSPeter Dunlap int total_len = 0; 2171a6d42e7dSPeter Dunlap int iovlen = 0; 2172a6d42e7dSPeter Dunlap struct iovec iov[6]; 2173a6d42e7dSPeter Dunlap idm_so_conn_t *so_conn; 2174a6d42e7dSPeter Dunlap 2175a6d42e7dSPeter Dunlap so_conn = ic->ic_transport_private; 2176a6d42e7dSPeter Dunlap 2177a6d42e7dSPeter Dunlap /* Setup BHS */ 2178a6d42e7dSPeter Dunlap iov[iovlen].iov_base = (caddr_t)pdu->isp_hdr; 2179a6d42e7dSPeter Dunlap iov[iovlen].iov_len = pdu->isp_hdrlen; 2180a6d42e7dSPeter Dunlap total_len += iov[iovlen].iov_len; 2181a6d42e7dSPeter Dunlap iovlen++; 2182a6d42e7dSPeter Dunlap 2183a6d42e7dSPeter Dunlap /* Setup header digest */ 2184a6d42e7dSPeter Dunlap if (((pdu->isp_flags & IDM_PDU_LOGIN_TX) == 0) && 2185a6d42e7dSPeter Dunlap (ic->ic_conn_flags & IDM_CONN_HEADER_DIGEST)) { 2186a6d42e7dSPeter Dunlap hdr_digest_crc = idm_crc32c(pdu->isp_hdr, pdu->isp_hdrlen); 2187a6d42e7dSPeter Dunlap 2188a6d42e7dSPeter Dunlap iov[iovlen].iov_base = (caddr_t)&hdr_digest_crc; 2189a6d42e7dSPeter Dunlap iov[iovlen].iov_len = sizeof (hdr_digest_crc); 2190a6d42e7dSPeter Dunlap total_len += iov[iovlen].iov_len; 2191a6d42e7dSPeter Dunlap iovlen++; 2192a6d42e7dSPeter Dunlap } 2193a6d42e7dSPeter Dunlap 2194a6d42e7dSPeter Dunlap /* Setup the data */ 2195a6d42e7dSPeter Dunlap if (pdu->isp_datalen) { 2196a6d42e7dSPeter Dunlap idm_task_t *idt; 2197a6d42e7dSPeter Dunlap idm_buf_t *idb; 2198a6d42e7dSPeter Dunlap iscsi_data_hdr_t *ihp; 2199a6d42e7dSPeter Dunlap ihp = (iscsi_data_hdr_t *)pdu->isp_hdr; 2200a6d42e7dSPeter Dunlap /* Write of immediate data */ 2201a6d42e7dSPeter Dunlap if (ic->ic_ffp && 2202a6d42e7dSPeter Dunlap (ihp->opcode == ISCSI_OP_SCSI_CMD || 2203a6d42e7dSPeter Dunlap ihp->opcode == ISCSI_OP_SCSI_DATA)) { 2204a6d42e7dSPeter Dunlap idt = idm_task_find(ic, ihp->itt, ihp->ttt); 2205a6d42e7dSPeter Dunlap if (idt) { 2206a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 2207a6d42e7dSPeter Dunlap idb = idm_buf_find(&idt->idt_outbufv, 0); 2208a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 220930e7468fSPeter Dunlap /* 221030e7468fSPeter Dunlap * If the initiator call to idm_buf_alloc 221130e7468fSPeter Dunlap * failed then we can get to this point 221230e7468fSPeter Dunlap * without a bound buffer. The associated 221330e7468fSPeter Dunlap * connection failure will clean things up 221430e7468fSPeter Dunlap * later. It would be nice to come up with 221530e7468fSPeter Dunlap * a cleaner way to handle this. In 221630e7468fSPeter Dunlap * particular it seems absurd to look up 221730e7468fSPeter Dunlap * the task and the buffer just to update 221830e7468fSPeter Dunlap * this counter. 221930e7468fSPeter Dunlap */ 222030e7468fSPeter Dunlap if (idb) 222130e7468fSPeter Dunlap idb->idb_xfer_len += pdu->isp_datalen; 222230e7468fSPeter Dunlap idm_task_rele(idt); 2223a6d42e7dSPeter Dunlap } 2224a6d42e7dSPeter Dunlap } 2225a6d42e7dSPeter Dunlap 2226a6d42e7dSPeter Dunlap iov[iovlen].iov_base = (caddr_t)pdu->isp_data; 2227a6d42e7dSPeter Dunlap iov[iovlen].iov_len = pdu->isp_datalen; 2228a6d42e7dSPeter Dunlap total_len += iov[iovlen].iov_len; 2229a6d42e7dSPeter Dunlap iovlen++; 2230a6d42e7dSPeter Dunlap } 2231a6d42e7dSPeter Dunlap 2232a6d42e7dSPeter Dunlap /* Setup the data pad if necessary */ 2233a6d42e7dSPeter Dunlap pad_len = ((ISCSI_PAD_WORD_LEN - 2234a6d42e7dSPeter Dunlap (pdu->isp_datalen & (ISCSI_PAD_WORD_LEN - 1))) & 2235a6d42e7dSPeter Dunlap (ISCSI_PAD_WORD_LEN - 1)); 2236a6d42e7dSPeter Dunlap 2237a6d42e7dSPeter Dunlap if (pad_len) { 2238a6d42e7dSPeter Dunlap bzero(pad, sizeof (pad)); 2239a6d42e7dSPeter Dunlap iov[iovlen].iov_base = (void *)&pad; 2240a6d42e7dSPeter Dunlap iov[iovlen].iov_len = pad_len; 2241a6d42e7dSPeter Dunlap total_len += iov[iovlen].iov_len; 2242a6d42e7dSPeter Dunlap iovlen++; 2243a6d42e7dSPeter Dunlap } 2244a6d42e7dSPeter Dunlap 2245a6d42e7dSPeter Dunlap /* 2246a6d42e7dSPeter Dunlap * Setup the data digest if enabled. Data-digest is not sent 2247a6d42e7dSPeter Dunlap * for login-phase PDUs. 2248a6d42e7dSPeter Dunlap */ 2249a6d42e7dSPeter Dunlap if ((ic->ic_conn_flags & IDM_CONN_DATA_DIGEST) && 2250a6d42e7dSPeter Dunlap ((pdu->isp_flags & IDM_PDU_LOGIN_TX) == 0) && 2251a6d42e7dSPeter Dunlap (pdu->isp_datalen || pad_len)) { 2252a6d42e7dSPeter Dunlap /* 2253a6d42e7dSPeter Dunlap * RFC3720/10.2.3: A zero-length Data Segment also 2254a6d42e7dSPeter Dunlap * implies a zero-length data digest. 2255a6d42e7dSPeter Dunlap */ 2256a6d42e7dSPeter Dunlap if (pdu->isp_datalen) { 2257a6d42e7dSPeter Dunlap data_digest_crc = idm_crc32c(pdu->isp_data, 2258a6d42e7dSPeter Dunlap pdu->isp_datalen); 2259a6d42e7dSPeter Dunlap } 2260a6d42e7dSPeter Dunlap if (pad_len) { 2261a6d42e7dSPeter Dunlap data_digest_crc = idm_crc32c_continued(&pad, 2262a6d42e7dSPeter Dunlap pad_len, data_digest_crc); 2263a6d42e7dSPeter Dunlap } 2264a6d42e7dSPeter Dunlap 2265a6d42e7dSPeter Dunlap iov[iovlen].iov_base = (caddr_t)&data_digest_crc; 2266a6d42e7dSPeter Dunlap iov[iovlen].iov_len = sizeof (data_digest_crc); 2267a6d42e7dSPeter Dunlap total_len += iov[iovlen].iov_len; 2268a6d42e7dSPeter Dunlap iovlen++; 2269a6d42e7dSPeter Dunlap } 2270a6d42e7dSPeter Dunlap 2271a6d42e7dSPeter Dunlap /* Transmit the PDU */ 2272a6d42e7dSPeter Dunlap if (idm_iov_sosend(so_conn->ic_so, &iov[0], iovlen, 2273a6d42e7dSPeter Dunlap total_len) != 0) { 2274a6d42e7dSPeter Dunlap /* Set error status */ 2275a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, 2276a6d42e7dSPeter Dunlap "idm_so_tx: failed to transmit the PDU, so: %p ic: %p " 2277a6d42e7dSPeter Dunlap "data: %p", (void *) so_conn->ic_so, (void *) ic, 2278a6d42e7dSPeter Dunlap (void *) pdu->isp_data); 2279a6d42e7dSPeter Dunlap status = IDM_STATUS_IO; 2280a6d42e7dSPeter Dunlap } 2281a6d42e7dSPeter Dunlap 2282a6d42e7dSPeter Dunlap /* 2283a6d42e7dSPeter Dunlap * Success does not mean that the PDU actually reached the 2284a6d42e7dSPeter Dunlap * remote node since it could get dropped along the way. 2285a6d42e7dSPeter Dunlap */ 2286a6d42e7dSPeter Dunlap idm_pdu_complete(pdu, status); 2287a6d42e7dSPeter Dunlap 2288a6d42e7dSPeter Dunlap return (status); 2289a6d42e7dSPeter Dunlap } 2290a6d42e7dSPeter Dunlap 2291a6d42e7dSPeter Dunlap /* 2292a6d42e7dSPeter Dunlap * The idm_so_buf_tx_to_ini() is used by the target iSCSI layer to transmit the 2293a6d42e7dSPeter Dunlap * Data-In PDUs using sockets. Based on the negotiated MaxRecvDataSegmentLength, 2294a6d42e7dSPeter Dunlap * the buffer is segmented into a sequence of Data-In PDUs, ordered by DataSN. 2295a6d42e7dSPeter Dunlap * A target can invoke this function multiple times for a single read command 2296a6d42e7dSPeter Dunlap * (identified by the same ITT) to split the input into several sequences. 2297a6d42e7dSPeter Dunlap * 2298a6d42e7dSPeter Dunlap * DataSN starts with 0 for the first data PDU of an input command and advances 2299a6d42e7dSPeter Dunlap * by 1 for each subsequent data PDU. Each sequence will have its own F bit, 2300a6d42e7dSPeter Dunlap * which is set to 1 for the last data PDU of a sequence. 2301a6d42e7dSPeter Dunlap * 2302a6d42e7dSPeter Dunlap * Scope for Prototype build: 2303a6d42e7dSPeter Dunlap * The data PDUs within a sequence will be sent in order with the buffer offset 2304a6d42e7dSPeter Dunlap * in increasing order. i.e. initiator and target must have negotiated the 2305a6d42e7dSPeter Dunlap * "DataPDUInOrder" to "Yes". The order between sequences is not enforced. 2306a6d42e7dSPeter Dunlap * 2307a6d42e7dSPeter Dunlap * Caller holds idt->idt_mutex 2308a6d42e7dSPeter Dunlap */ 2309a6d42e7dSPeter Dunlap static idm_status_t 2310a6d42e7dSPeter Dunlap idm_so_buf_tx_to_ini(idm_task_t *idt, idm_buf_t *idb) 2311a6d42e7dSPeter Dunlap { 2312a6d42e7dSPeter Dunlap idm_so_conn_t *so_conn = idb->idb_ic->ic_transport_private; 2313a6d42e7dSPeter Dunlap idm_pdu_t tmppdu; 2314a6d42e7dSPeter Dunlap 2315a6d42e7dSPeter Dunlap ASSERT(mutex_owned(&idt->idt_mutex)); 2316a6d42e7dSPeter Dunlap 2317a6d42e7dSPeter Dunlap /* 2318a6d42e7dSPeter Dunlap * Put the idm_buf_t on the tx queue. It will be transmitted by 2319a6d42e7dSPeter Dunlap * idm_sotx_thread. 2320a6d42e7dSPeter Dunlap */ 2321a6d42e7dSPeter Dunlap mutex_enter(&so_conn->ic_tx_mutex); 2322a6d42e7dSPeter Dunlap 2323a668b114SPriya Krishnan DTRACE_ISCSI_8(xfer__start, idm_conn_t *, idt->idt_ic, 2324a668b114SPriya Krishnan uintptr_t, idb->idb_buf, uint32_t, idb->idb_bufoffset, 2325a668b114SPriya Krishnan uint64_t, 0, uint32_t, 0, uint32_t, 0, 2326a668b114SPriya Krishnan uint32_t, idb->idb_xfer_len, int, XFER_BUF_TX_TO_INI); 2327a668b114SPriya Krishnan 2328a6d42e7dSPeter Dunlap if (!so_conn->ic_tx_thread_running) { 2329a6d42e7dSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 2330a6d42e7dSPeter Dunlap /* 2331a6d42e7dSPeter Dunlap * Don't release idt->idt_mutex since we're supposed to hold 2332a6d42e7dSPeter Dunlap * in when calling idm_buf_tx_to_ini_done 2333a6d42e7dSPeter Dunlap */ 2334a668b114SPriya Krishnan DTRACE_ISCSI_8(xfer__done, idm_conn_t *, idt->idt_ic, 2335a668b114SPriya Krishnan uintptr_t, idb->idb_buf, uint32_t, idb->idb_bufoffset, 2336a668b114SPriya Krishnan uint64_t, 0, uint32_t, 0, uint32_t, 0, 2337a668b114SPriya Krishnan uint32_t, idb->idb_xfer_len, 2338a668b114SPriya Krishnan int, XFER_BUF_TX_TO_INI); 2339a6d42e7dSPeter Dunlap idm_buf_tx_to_ini_done(idt, idb, IDM_STATUS_ABORTED); 2340a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 2341a6d42e7dSPeter Dunlap } 2342a6d42e7dSPeter Dunlap 2343a6d42e7dSPeter Dunlap /* 2344a6d42e7dSPeter Dunlap * Build a template for the data PDU headers we will use so that 2345a6d42e7dSPeter Dunlap * the SN values will stay consistent with other PDU's we are 2346a6d42e7dSPeter Dunlap * transmitting like R2T and SCSI status. 2347a6d42e7dSPeter Dunlap */ 2348a6d42e7dSPeter Dunlap bzero(&idb->idb_data_hdr_tmpl, sizeof (iscsi_hdr_t)); 2349a6d42e7dSPeter Dunlap tmppdu.isp_hdr = &idb->idb_data_hdr_tmpl; 2350a6d42e7dSPeter Dunlap (*idt->idt_ic->ic_conn_ops.icb_build_hdr)(idt, &tmppdu, 2351a6d42e7dSPeter Dunlap ISCSI_OP_SCSI_DATA_RSP); 2352a6d42e7dSPeter Dunlap idb->idb_tx_thread = B_TRUE; 2353a6d42e7dSPeter Dunlap list_insert_tail(&so_conn->ic_tx_list, (void *)idb); 2354a6d42e7dSPeter Dunlap cv_signal(&so_conn->ic_tx_cv); 2355a6d42e7dSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 2356a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 2357a6d42e7dSPeter Dunlap 2358a6d42e7dSPeter Dunlap /* 2359a6d42e7dSPeter Dunlap * Returning success here indicates the transfer was successfully 2360a6d42e7dSPeter Dunlap * dispatched -- it does not mean that the transfer completed 2361a6d42e7dSPeter Dunlap * successfully. 2362a6d42e7dSPeter Dunlap */ 2363a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 2364a6d42e7dSPeter Dunlap } 2365a6d42e7dSPeter Dunlap 2366a6d42e7dSPeter Dunlap /* 2367a6d42e7dSPeter Dunlap * The idm_so_buf_rx_from_ini() is used by the target iSCSI layer to specify the 2368a6d42e7dSPeter Dunlap * data blocks it is ready to receive from the initiator in response to a WRITE 2369a6d42e7dSPeter Dunlap * SCSI command. The target iSCSI layer passes the information about the desired 2370a6d42e7dSPeter Dunlap * data blocks to the initiator in one R2T PDU. The receiving buffer, the buffer 2371a6d42e7dSPeter Dunlap * offset and datalen are passed via the 'idb' argument. 2372a6d42e7dSPeter Dunlap * 2373a6d42e7dSPeter Dunlap * Scope for Prototype build: 2374a6d42e7dSPeter Dunlap * R2Ts are required for any Data-Out PDU, i.e. initiator and target must have 2375a6d42e7dSPeter Dunlap * negotiated the "InitialR2T" to "Yes". 2376a6d42e7dSPeter Dunlap * 2377a6d42e7dSPeter Dunlap * Caller holds idt->idt_mutex 2378a6d42e7dSPeter Dunlap */ 2379a6d42e7dSPeter Dunlap static idm_status_t 2380a6d42e7dSPeter Dunlap idm_so_buf_rx_from_ini(idm_task_t *idt, idm_buf_t *idb) 2381a6d42e7dSPeter Dunlap { 2382a6d42e7dSPeter Dunlap idm_pdu_t *pdu; 2383a6d42e7dSPeter Dunlap iscsi_rtt_hdr_t *rtt; 2384a6d42e7dSPeter Dunlap 2385a6d42e7dSPeter Dunlap ASSERT(mutex_owned(&idt->idt_mutex)); 2386a6d42e7dSPeter Dunlap 2387a668b114SPriya Krishnan DTRACE_ISCSI_8(xfer__start, idm_conn_t *, idt->idt_ic, 2388a668b114SPriya Krishnan uintptr_t, idb->idb_buf, uint32_t, idb->idb_bufoffset, 2389a668b114SPriya Krishnan uint64_t, 0, uint32_t, 0, uint32_t, 0, 2390a668b114SPriya Krishnan uint32_t, idb->idb_xfer_len, int, XFER_BUF_RX_FROM_INI); 2391a668b114SPriya Krishnan 2392a6d42e7dSPeter Dunlap pdu = kmem_cache_alloc(idm.idm_sotx_pdu_cache, KM_SLEEP); 2393a6d42e7dSPeter Dunlap pdu->isp_ic = idt->idt_ic; 2394a6d42e7dSPeter Dunlap bzero(pdu->isp_hdr, sizeof (iscsi_rtt_hdr_t)); 2395a6d42e7dSPeter Dunlap 2396a6d42e7dSPeter Dunlap /* iSCSI layer fills the TTT, ITT, StatSN, ExpCmdSN, MaxCmdSN */ 2397a6d42e7dSPeter Dunlap (*idt->idt_ic->ic_conn_ops.icb_build_hdr)(idt, pdu, ISCSI_OP_RTT_RSP); 2398a6d42e7dSPeter Dunlap 2399a6d42e7dSPeter Dunlap /* set the rttsn, rtt.flags, rtt.data_offset and rtt.data_length */ 2400a6d42e7dSPeter Dunlap rtt = (iscsi_rtt_hdr_t *)(pdu->isp_hdr); 2401a6d42e7dSPeter Dunlap 2402a6d42e7dSPeter Dunlap rtt->opcode = ISCSI_OP_RTT_RSP; 2403a6d42e7dSPeter Dunlap rtt->flags = ISCSI_FLAG_FINAL; 2404a6d42e7dSPeter Dunlap rtt->data_offset = htonl(idb->idb_bufoffset); 2405a6d42e7dSPeter Dunlap rtt->data_length = htonl(idb->idb_xfer_len); 2406a6d42e7dSPeter Dunlap rtt->rttsn = htonl(idt->idt_exp_rttsn++); 2407a6d42e7dSPeter Dunlap 2408a6d42e7dSPeter Dunlap /* Keep track of buffer offsets */ 2409a6d42e7dSPeter Dunlap idb->idb_exp_offset = idb->idb_bufoffset; 2410a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 2411a6d42e7dSPeter Dunlap 2412a6d42e7dSPeter Dunlap /* 241363528ae4SJames Moore * Transmit the PDU. 2414a6d42e7dSPeter Dunlap */ 241563528ae4SJames Moore idm_pdu_tx(pdu); 2416a6d42e7dSPeter Dunlap 2417a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 2418a6d42e7dSPeter Dunlap } 2419a6d42e7dSPeter Dunlap 2420a6d42e7dSPeter Dunlap static idm_status_t 2421a6d42e7dSPeter Dunlap idm_so_buf_alloc(idm_buf_t *idb, uint64_t buflen) 2422a6d42e7dSPeter Dunlap { 2423cf8c0ebaSPeter Dunlap if ((buflen > IDM_SO_BUF_CACHE_LB) && (buflen <= IDM_SO_BUF_CACHE_UB)) { 2424cf8c0ebaSPeter Dunlap idb->idb_buf = kmem_cache_alloc(idm.idm_so_128k_buf_cache, 2425cf8c0ebaSPeter Dunlap KM_NOSLEEP); 2426cf8c0ebaSPeter Dunlap idb->idb_buf_private = idm.idm_so_128k_buf_cache; 2427cf8c0ebaSPeter Dunlap } else { 2428cf8c0ebaSPeter Dunlap idb->idb_buf = kmem_alloc(buflen, KM_NOSLEEP); 2429cf8c0ebaSPeter Dunlap idb->idb_buf_private = NULL; 2430cf8c0ebaSPeter Dunlap } 2431cf8c0ebaSPeter Dunlap 2432a6d42e7dSPeter Dunlap if (idb->idb_buf == NULL) { 2433a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_NOTE, 2434a6d42e7dSPeter Dunlap "idm_so_buf_alloc: failed buffer allocation"); 2435a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 2436a6d42e7dSPeter Dunlap } 2437cf8c0ebaSPeter Dunlap 2438a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 2439a6d42e7dSPeter Dunlap } 2440a6d42e7dSPeter Dunlap 2441a6d42e7dSPeter Dunlap /* ARGSUSED */ 2442a6d42e7dSPeter Dunlap static idm_status_t 2443a6d42e7dSPeter Dunlap idm_so_buf_setup(idm_buf_t *idb) 2444a6d42e7dSPeter Dunlap { 244530e7468fSPeter Dunlap /* Ensure bufalloc'd flag is unset */ 244630e7468fSPeter Dunlap idb->idb_bufalloc = B_FALSE; 244730e7468fSPeter Dunlap 2448a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 2449a6d42e7dSPeter Dunlap } 2450a6d42e7dSPeter Dunlap 2451a6d42e7dSPeter Dunlap /* ARGSUSED */ 2452a6d42e7dSPeter Dunlap static void 2453a6d42e7dSPeter Dunlap idm_so_buf_teardown(idm_buf_t *idb) 2454a6d42e7dSPeter Dunlap { 2455a6d42e7dSPeter Dunlap /* nothing to do here */ 2456a6d42e7dSPeter Dunlap } 2457a6d42e7dSPeter Dunlap 2458a6d42e7dSPeter Dunlap static void 2459a6d42e7dSPeter Dunlap idm_so_buf_free(idm_buf_t *idb) 2460a6d42e7dSPeter Dunlap { 2461cf8c0ebaSPeter Dunlap if (idb->idb_buf_private == NULL) { 2462cf8c0ebaSPeter Dunlap kmem_free(idb->idb_buf, idb->idb_buflen); 2463cf8c0ebaSPeter Dunlap } else { 2464cf8c0ebaSPeter Dunlap kmem_cache_free(idb->idb_buf_private, idb->idb_buf); 2465cf8c0ebaSPeter Dunlap } 2466a6d42e7dSPeter Dunlap } 2467a6d42e7dSPeter Dunlap 246830e7468fSPeter Dunlap static void 246930e7468fSPeter Dunlap idm_so_send_rtt_data(idm_conn_t *ic, idm_task_t *idt, idm_buf_t *idb, 247030e7468fSPeter Dunlap uint32_t offset, uint32_t length) 247130e7468fSPeter Dunlap { 247230e7468fSPeter Dunlap idm_so_conn_t *so_conn = ic->ic_transport_private; 247330e7468fSPeter Dunlap idm_pdu_t tmppdu; 247430e7468fSPeter Dunlap idm_buf_t *rtt_buf; 247530e7468fSPeter Dunlap 247630e7468fSPeter Dunlap ASSERT(mutex_owned(&idt->idt_mutex)); 247730e7468fSPeter Dunlap 247830e7468fSPeter Dunlap /* 247930e7468fSPeter Dunlap * Allocate a buffer to represent the RTT transfer. We could further 248030e7468fSPeter Dunlap * optimize this by allocating the buffers internally from an rtt 248130e7468fSPeter Dunlap * specific buffer cache since this is socket-specific code but for 248230e7468fSPeter Dunlap * now we will keep it simple. 248330e7468fSPeter Dunlap */ 248430e7468fSPeter Dunlap rtt_buf = idm_buf_alloc(ic, (uint8_t *)idb->idb_buf + offset, length); 248530e7468fSPeter Dunlap if (rtt_buf == NULL) { 248630e7468fSPeter Dunlap /* 248730e7468fSPeter Dunlap * If we're in FFP then the failure was likely a resource 248830e7468fSPeter Dunlap * allocation issue and we should close the connection by 248930e7468fSPeter Dunlap * sending a CE_TRANSPORT_FAIL event. 249030e7468fSPeter Dunlap * 249130e7468fSPeter Dunlap * If we're not in FFP then idm_buf_alloc will always 249230e7468fSPeter Dunlap * fail and the state is transitioning to "complete" anyway 249330e7468fSPeter Dunlap * so we won't bother to send an event. 249430e7468fSPeter Dunlap */ 249530e7468fSPeter Dunlap mutex_enter(&ic->ic_state_mutex); 249630e7468fSPeter Dunlap if (ic->ic_ffp) 249730e7468fSPeter Dunlap idm_conn_event_locked(ic, CE_TRANSPORT_FAIL, 249830e7468fSPeter Dunlap NULL, CT_NONE); 249930e7468fSPeter Dunlap mutex_exit(&ic->ic_state_mutex); 250030e7468fSPeter Dunlap return; 250130e7468fSPeter Dunlap } 250230e7468fSPeter Dunlap 250330e7468fSPeter Dunlap rtt_buf->idb_buf_cb = NULL; 250430e7468fSPeter Dunlap rtt_buf->idb_cb_arg = NULL; 250530e7468fSPeter Dunlap rtt_buf->idb_bufoffset = offset; 250630e7468fSPeter Dunlap rtt_buf->idb_xfer_len = length; 250730e7468fSPeter Dunlap rtt_buf->idb_ic = idt->idt_ic; 250830e7468fSPeter Dunlap rtt_buf->idb_task_binding = idt; 250930e7468fSPeter Dunlap 251030e7468fSPeter Dunlap /* 251130e7468fSPeter Dunlap * Put the idm_buf_t on the tx queue. It will be transmitted by 251230e7468fSPeter Dunlap * idm_sotx_thread. 251330e7468fSPeter Dunlap */ 251430e7468fSPeter Dunlap mutex_enter(&so_conn->ic_tx_mutex); 251530e7468fSPeter Dunlap 251630e7468fSPeter Dunlap if (!so_conn->ic_tx_thread_running) { 251730e7468fSPeter Dunlap idm_buf_free(rtt_buf); 251830e7468fSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 251930e7468fSPeter Dunlap return; 252030e7468fSPeter Dunlap } 252130e7468fSPeter Dunlap 252230e7468fSPeter Dunlap /* 252330e7468fSPeter Dunlap * This new buffer represents an additional reference on the task 252430e7468fSPeter Dunlap */ 252530e7468fSPeter Dunlap idm_task_hold(idt); 252630e7468fSPeter Dunlap 252730e7468fSPeter Dunlap /* 252830e7468fSPeter Dunlap * Build a template for the data PDU headers we will use so that 252930e7468fSPeter Dunlap * the SN values will stay consistent with other PDU's we are 253030e7468fSPeter Dunlap * transmitting like R2T and SCSI status. 253130e7468fSPeter Dunlap */ 253230e7468fSPeter Dunlap bzero(&rtt_buf->idb_data_hdr_tmpl, sizeof (iscsi_hdr_t)); 253330e7468fSPeter Dunlap tmppdu.isp_hdr = &rtt_buf->idb_data_hdr_tmpl; 253430e7468fSPeter Dunlap (*idt->idt_ic->ic_conn_ops.icb_build_hdr)(idt, &tmppdu, 253530e7468fSPeter Dunlap ISCSI_OP_SCSI_DATA); 253630e7468fSPeter Dunlap rtt_buf->idb_tx_thread = B_TRUE; 253730e7468fSPeter Dunlap rtt_buf->idb_in_transport = B_TRUE; 253830e7468fSPeter Dunlap list_insert_tail(&so_conn->ic_tx_list, (void *)rtt_buf); 253930e7468fSPeter Dunlap cv_signal(&so_conn->ic_tx_cv); 254030e7468fSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 254130e7468fSPeter Dunlap } 254230e7468fSPeter Dunlap 254330e7468fSPeter Dunlap static void 254430e7468fSPeter Dunlap idm_so_send_rtt_data_done(idm_task_t *idt, idm_buf_t *idb) 254530e7468fSPeter Dunlap { 254630e7468fSPeter Dunlap /* 254730e7468fSPeter Dunlap * Don't worry about status -- we assume any error handling 254830e7468fSPeter Dunlap * is performed by the caller (idm_sotx_thread). 254930e7468fSPeter Dunlap */ 255030e7468fSPeter Dunlap idb->idb_in_transport = B_FALSE; 255130e7468fSPeter Dunlap idm_task_rele(idt); 255230e7468fSPeter Dunlap idm_buf_free(idb); 255330e7468fSPeter Dunlap } 255430e7468fSPeter Dunlap 255530e7468fSPeter Dunlap static idm_status_t 255630e7468fSPeter Dunlap idm_so_send_buf_region(idm_task_t *idt, idm_buf_t *idb, 2557a6d42e7dSPeter Dunlap uint32_t buf_region_offset, uint32_t buf_region_length) 2558a6d42e7dSPeter Dunlap { 2559a6d42e7dSPeter Dunlap idm_conn_t *ic; 2560a6d42e7dSPeter Dunlap uint32_t max_dataseglen; 2561a6d42e7dSPeter Dunlap size_t remainder, chunk; 2562a6d42e7dSPeter Dunlap uint32_t data_offset = buf_region_offset; 2563a6d42e7dSPeter Dunlap iscsi_data_hdr_t *bhs; 2564a6d42e7dSPeter Dunlap idm_pdu_t *pdu; 256530e7468fSPeter Dunlap idm_status_t tx_status; 2566a6d42e7dSPeter Dunlap 2567a6d42e7dSPeter Dunlap ASSERT(mutex_owned(&idt->idt_mutex)); 2568a6d42e7dSPeter Dunlap 2569a6d42e7dSPeter Dunlap ic = idt->idt_ic; 2570a6d42e7dSPeter Dunlap 257156261083SCharles Ting max_dataseglen = ic->ic_conn_params.max_xmit_dataseglen; 2572a6d42e7dSPeter Dunlap remainder = buf_region_length; 2573a6d42e7dSPeter Dunlap 2574a6d42e7dSPeter Dunlap while (remainder) { 2575a6d42e7dSPeter Dunlap if (idt->idt_state != TASK_ACTIVE) { 2576a6d42e7dSPeter Dunlap ASSERT((idt->idt_state != TASK_IDLE) && 2577a6d42e7dSPeter Dunlap (idt->idt_state != TASK_COMPLETE)); 2578a6d42e7dSPeter Dunlap return (IDM_STATUS_ABORTED); 2579a6d42e7dSPeter Dunlap } 2580a6d42e7dSPeter Dunlap 2581a6d42e7dSPeter Dunlap /* check to see if we need to chunk the data */ 2582a6d42e7dSPeter Dunlap if (remainder > max_dataseglen) { 2583a6d42e7dSPeter Dunlap chunk = max_dataseglen; 2584a6d42e7dSPeter Dunlap } else { 2585a6d42e7dSPeter Dunlap chunk = remainder; 2586a6d42e7dSPeter Dunlap } 2587a6d42e7dSPeter Dunlap 2588a6d42e7dSPeter Dunlap /* Data PDU headers will always be sizeof (iscsi_hdr_t) */ 2589a6d42e7dSPeter Dunlap pdu = kmem_cache_alloc(idm.idm_sotx_pdu_cache, KM_SLEEP); 2590a6d42e7dSPeter Dunlap pdu->isp_ic = ic; 2591a6d42e7dSPeter Dunlap 2592a6d42e7dSPeter Dunlap /* 259330e7468fSPeter Dunlap * We've already built a build a header template 2594a6d42e7dSPeter Dunlap * to use during the transfer. Use this template so that 2595a6d42e7dSPeter Dunlap * the SN values stay consistent with any unrelated PDU's 2596a6d42e7dSPeter Dunlap * being transmitted. 2597a6d42e7dSPeter Dunlap */ 259830e7468fSPeter Dunlap bcopy(&idb->idb_data_hdr_tmpl, pdu->isp_hdr, 259930e7468fSPeter Dunlap sizeof (iscsi_hdr_t)); 2600a6d42e7dSPeter Dunlap 2601a6d42e7dSPeter Dunlap /* 2602a6d42e7dSPeter Dunlap * Set DataSN, data offset, and flags in BHS 2603a6d42e7dSPeter Dunlap * For the prototype build, A = 0, S = 0, U = 0 2604a6d42e7dSPeter Dunlap */ 2605a6d42e7dSPeter Dunlap bhs = (iscsi_data_hdr_t *)(pdu->isp_hdr); 2606a6d42e7dSPeter Dunlap 2607a6d42e7dSPeter Dunlap bhs->datasn = htonl(idt->idt_exp_datasn++); 2608a6d42e7dSPeter Dunlap 2609a6d42e7dSPeter Dunlap hton24(bhs->dlength, chunk); 2610a6d42e7dSPeter Dunlap bhs->offset = htonl(idb->idb_bufoffset + data_offset); 2611a6d42e7dSPeter Dunlap 2612a6d42e7dSPeter Dunlap if (chunk == remainder) { 2613a6d42e7dSPeter Dunlap bhs->flags = ISCSI_FLAG_FINAL; /* F bit set to 1 */ 2614a6d42e7dSPeter Dunlap } 2615a6d42e7dSPeter Dunlap 2616a668b114SPriya Krishnan /* Instrument the data-send DTrace probe. */ 2617a668b114SPriya Krishnan if (IDM_PDU_OPCODE(pdu) == ISCSI_OP_SCSI_DATA_RSP) { 2618a668b114SPriya Krishnan DTRACE_ISCSI_2(data__send, 2619a668b114SPriya Krishnan idm_conn_t *, idt->idt_ic, 2620a668b114SPriya Krishnan iscsi_data_rsp_hdr_t *, 2621a668b114SPriya Krishnan (iscsi_data_rsp_hdr_t *)pdu->isp_hdr); 2622a668b114SPriya Krishnan } 2623a6d42e7dSPeter Dunlap /* setup data */ 2624a6d42e7dSPeter Dunlap pdu->isp_data = (uint8_t *)idb->idb_buf + data_offset; 2625a6d42e7dSPeter Dunlap pdu->isp_datalen = (uint_t)chunk; 2626a6d42e7dSPeter Dunlap remainder -= chunk; 2627a6d42e7dSPeter Dunlap data_offset += chunk; 2628a6d42e7dSPeter Dunlap 2629a6d42e7dSPeter Dunlap /* 2630a6d42e7dSPeter Dunlap * Now that we're done working with idt_exp_datasn, 2631a6d42e7dSPeter Dunlap * idt->idt_state and idb->idb_bufoffset we can release 2632a6d42e7dSPeter Dunlap * the task lock -- don't want to hold it across the 2633a6d42e7dSPeter Dunlap * call to idm_i_so_tx since we could block. 2634a6d42e7dSPeter Dunlap */ 2635a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 2636a6d42e7dSPeter Dunlap 2637a6d42e7dSPeter Dunlap /* 2638a6d42e7dSPeter Dunlap * Transmit the PDU. Call the internal routine directly 2639a6d42e7dSPeter Dunlap * as there is already implicit ordering. 2640a6d42e7dSPeter Dunlap */ 264130e7468fSPeter Dunlap if ((tx_status = idm_i_so_tx(pdu)) != IDM_STATUS_SUCCESS) { 264230e7468fSPeter Dunlap mutex_enter(&idt->idt_mutex); 264330e7468fSPeter Dunlap return (tx_status); 264430e7468fSPeter Dunlap } 2645a6d42e7dSPeter Dunlap 2646a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 264730e7468fSPeter Dunlap idt->idt_tx_bytes += chunk; 2648a6d42e7dSPeter Dunlap } 2649a6d42e7dSPeter Dunlap 2650a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 2651a6d42e7dSPeter Dunlap } 2652a6d42e7dSPeter Dunlap 2653a6d42e7dSPeter Dunlap /* 2654a6d42e7dSPeter Dunlap * TX PDU cache 2655a6d42e7dSPeter Dunlap */ 2656a6d42e7dSPeter Dunlap /* ARGSUSED */ 2657a6d42e7dSPeter Dunlap int 2658a6d42e7dSPeter Dunlap idm_sotx_pdu_constructor(void *hdl, void *arg, int flags) 2659a6d42e7dSPeter Dunlap { 2660a6d42e7dSPeter Dunlap idm_pdu_t *pdu = hdl; 2661a6d42e7dSPeter Dunlap 2662a6d42e7dSPeter Dunlap bzero(pdu, sizeof (idm_pdu_t)); 2663a6d42e7dSPeter Dunlap pdu->isp_hdr = (iscsi_hdr_t *)(pdu + 1); /* Ptr arithmetic */ 2664a6d42e7dSPeter Dunlap pdu->isp_hdrlen = sizeof (iscsi_hdr_t); 2665a6d42e7dSPeter Dunlap pdu->isp_callback = idm_sotx_cache_pdu_cb; 2666a6d42e7dSPeter Dunlap pdu->isp_magic = IDM_PDU_MAGIC; 2667a6d42e7dSPeter Dunlap bzero(pdu->isp_hdr, sizeof (iscsi_hdr_t)); 2668a6d42e7dSPeter Dunlap 2669a6d42e7dSPeter Dunlap return (0); 2670a6d42e7dSPeter Dunlap } 2671a6d42e7dSPeter Dunlap 2672a6d42e7dSPeter Dunlap /* ARGSUSED */ 2673a6d42e7dSPeter Dunlap void 2674a6d42e7dSPeter Dunlap idm_sotx_cache_pdu_cb(idm_pdu_t *pdu, idm_status_t status) 2675a6d42e7dSPeter Dunlap { 2676a6d42e7dSPeter Dunlap /* reset values between use */ 2677a6d42e7dSPeter Dunlap pdu->isp_datalen = 0; 2678a6d42e7dSPeter Dunlap 2679a6d42e7dSPeter Dunlap kmem_cache_free(idm.idm_sotx_pdu_cache, pdu); 2680a6d42e7dSPeter Dunlap } 2681a6d42e7dSPeter Dunlap 2682a6d42e7dSPeter Dunlap /* 2683a6d42e7dSPeter Dunlap * RX PDU cache 2684a6d42e7dSPeter Dunlap */ 2685a6d42e7dSPeter Dunlap /* ARGSUSED */ 2686a6d42e7dSPeter Dunlap int 2687a6d42e7dSPeter Dunlap idm_sorx_pdu_constructor(void *hdl, void *arg, int flags) 2688a6d42e7dSPeter Dunlap { 2689a6d42e7dSPeter Dunlap idm_pdu_t *pdu = hdl; 2690a6d42e7dSPeter Dunlap 2691a6d42e7dSPeter Dunlap bzero(pdu, sizeof (idm_pdu_t)); 2692a6d42e7dSPeter Dunlap pdu->isp_magic = IDM_PDU_MAGIC; 2693a6d42e7dSPeter Dunlap pdu->isp_hdr = (iscsi_hdr_t *)(pdu + 1); /* Ptr arithmetic */ 2694a6d42e7dSPeter Dunlap pdu->isp_callback = idm_sorx_cache_pdu_cb; 2695a6d42e7dSPeter Dunlap 2696a6d42e7dSPeter Dunlap return (0); 2697a6d42e7dSPeter Dunlap } 2698a6d42e7dSPeter Dunlap 2699a6d42e7dSPeter Dunlap /* ARGSUSED */ 2700a6d42e7dSPeter Dunlap static void 2701a6d42e7dSPeter Dunlap idm_sorx_cache_pdu_cb(idm_pdu_t *pdu, idm_status_t status) 2702a6d42e7dSPeter Dunlap { 2703a6d42e7dSPeter Dunlap pdu->isp_iovlen = 0; 2704a6d42e7dSPeter Dunlap pdu->isp_sorx_buf = 0; 2705a6d42e7dSPeter Dunlap kmem_cache_free(idm.idm_sorx_pdu_cache, pdu); 2706a6d42e7dSPeter Dunlap } 2707a6d42e7dSPeter Dunlap 2708a6d42e7dSPeter Dunlap static void 2709a6d42e7dSPeter Dunlap idm_sorx_addl_pdu_cb(idm_pdu_t *pdu, idm_status_t status) 2710a6d42e7dSPeter Dunlap { 2711a6d42e7dSPeter Dunlap /* 2712a6d42e7dSPeter Dunlap * We had to modify our cached RX PDU with a longer header buffer 2713a6d42e7dSPeter Dunlap * and/or a longer data buffer. Release the new buffers and fix 2714a6d42e7dSPeter Dunlap * the fields back to what we would expect for a cached RX PDU. 2715a6d42e7dSPeter Dunlap */ 2716a6d42e7dSPeter Dunlap if (pdu->isp_flags & IDM_PDU_ADDL_HDR) { 2717a6d42e7dSPeter Dunlap kmem_free(pdu->isp_hdr, pdu->isp_hdrlen); 2718a6d42e7dSPeter Dunlap } 2719a6d42e7dSPeter Dunlap if (pdu->isp_flags & IDM_PDU_ADDL_DATA) { 2720a6d42e7dSPeter Dunlap kmem_free(pdu->isp_data, pdu->isp_datalen); 2721a6d42e7dSPeter Dunlap } 2722a6d42e7dSPeter Dunlap pdu->isp_hdr = (iscsi_hdr_t *)(pdu + 1); 2723a6d42e7dSPeter Dunlap pdu->isp_hdrlen = sizeof (iscsi_hdr_t); 2724a6d42e7dSPeter Dunlap pdu->isp_data = NULL; 2725a6d42e7dSPeter Dunlap pdu->isp_datalen = 0; 2726a6d42e7dSPeter Dunlap pdu->isp_sorx_buf = 0; 2727a6d42e7dSPeter Dunlap pdu->isp_callback = idm_sorx_cache_pdu_cb; 2728a6d42e7dSPeter Dunlap idm_sorx_cache_pdu_cb(pdu, status); 2729a6d42e7dSPeter Dunlap } 2730a6d42e7dSPeter Dunlap 2731a6d42e7dSPeter Dunlap /* 2732a6d42e7dSPeter Dunlap * This thread is only active when I/O is queued for transmit 2733a6d42e7dSPeter Dunlap * because the socket is busy. 2734a6d42e7dSPeter Dunlap */ 2735a6d42e7dSPeter Dunlap void 2736a6d42e7dSPeter Dunlap idm_sotx_thread(void *arg) 2737a6d42e7dSPeter Dunlap { 2738a6d42e7dSPeter Dunlap idm_conn_t *ic = arg; 2739a6d42e7dSPeter Dunlap idm_tx_obj_t *object, *next; 2740a6d42e7dSPeter Dunlap idm_so_conn_t *so_conn; 2741a6d42e7dSPeter Dunlap idm_status_t status = IDM_STATUS_SUCCESS; 2742a6d42e7dSPeter Dunlap 2743a6d42e7dSPeter Dunlap idm_conn_hold(ic); 2744a6d42e7dSPeter Dunlap 2745a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_mutex); 2746a6d42e7dSPeter Dunlap so_conn = ic->ic_transport_private; 2747a6d42e7dSPeter Dunlap so_conn->ic_tx_thread_running = B_TRUE; 2748a6d42e7dSPeter Dunlap so_conn->ic_tx_thread_did = so_conn->ic_tx_thread->t_did; 2749a6d42e7dSPeter Dunlap cv_signal(&ic->ic_cv); 2750a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_mutex); 2751a6d42e7dSPeter Dunlap 2752a6d42e7dSPeter Dunlap mutex_enter(&so_conn->ic_tx_mutex); 2753a6d42e7dSPeter Dunlap 2754a6d42e7dSPeter Dunlap while (so_conn->ic_tx_thread_running) { 2755a6d42e7dSPeter Dunlap while (list_is_empty(&so_conn->ic_tx_list)) { 2756a6d42e7dSPeter Dunlap DTRACE_PROBE1(soconn__tx__sleep, idm_conn_t *, ic); 2757a6d42e7dSPeter Dunlap cv_wait(&so_conn->ic_tx_cv, &so_conn->ic_tx_mutex); 2758a6d42e7dSPeter Dunlap DTRACE_PROBE1(soconn__tx__wakeup, idm_conn_t *, ic); 2759a6d42e7dSPeter Dunlap 2760a6d42e7dSPeter Dunlap if (!so_conn->ic_tx_thread_running) { 2761a6d42e7dSPeter Dunlap goto tx_bail; 2762a6d42e7dSPeter Dunlap } 2763a6d42e7dSPeter Dunlap } 2764a6d42e7dSPeter Dunlap 2765a6d42e7dSPeter Dunlap object = (idm_tx_obj_t *)list_head(&so_conn->ic_tx_list); 2766a6d42e7dSPeter Dunlap list_remove(&so_conn->ic_tx_list, object); 2767a6d42e7dSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 2768a6d42e7dSPeter Dunlap 2769a6d42e7dSPeter Dunlap switch (object->idm_tx_obj_magic) { 2770a6d42e7dSPeter Dunlap case IDM_PDU_MAGIC: 2771a6d42e7dSPeter Dunlap DTRACE_PROBE2(soconn__tx__pdu, idm_conn_t *, ic, 2772a6d42e7dSPeter Dunlap idm_pdu_t *, (idm_pdu_t *)object); 2773a6d42e7dSPeter Dunlap 2774a6d42e7dSPeter Dunlap status = idm_i_so_tx((idm_pdu_t *)object); 2775a6d42e7dSPeter Dunlap break; 2776a6d42e7dSPeter Dunlap 2777a6d42e7dSPeter Dunlap case IDM_BUF_MAGIC: { 2778a6d42e7dSPeter Dunlap idm_buf_t *idb = (idm_buf_t *)object; 2779a6d42e7dSPeter Dunlap idm_task_t *idt = idb->idb_task_binding; 2780a6d42e7dSPeter Dunlap 2781a6d42e7dSPeter Dunlap DTRACE_PROBE2(soconn__tx__buf, idm_conn_t *, ic, 2782a6d42e7dSPeter Dunlap idm_buf_t *, idb); 2783a6d42e7dSPeter Dunlap 2784a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 2785a6d42e7dSPeter Dunlap status = idm_so_send_buf_region(idt, 278630e7468fSPeter Dunlap idb, 0, idb->idb_xfer_len); 2787a6d42e7dSPeter Dunlap 2788a6d42e7dSPeter Dunlap /* 2789a6d42e7dSPeter Dunlap * TX thread owns the buffer so we expect it to 2790a6d42e7dSPeter Dunlap * be "in transport" 2791a6d42e7dSPeter Dunlap */ 2792a6d42e7dSPeter Dunlap ASSERT(idb->idb_in_transport); 279330e7468fSPeter Dunlap if (IDM_CONN_ISTGT(ic)) { 279430e7468fSPeter Dunlap /* 279530e7468fSPeter Dunlap * idm_buf_tx_to_ini_done releases 279630e7468fSPeter Dunlap * idt->idt_mutex 279730e7468fSPeter Dunlap */ 2798a668b114SPriya Krishnan DTRACE_ISCSI_8(xfer__done, 2799a668b114SPriya Krishnan idm_conn_t *, idt->idt_ic, 2800a668b114SPriya Krishnan uintptr_t, idb->idb_buf, 2801a668b114SPriya Krishnan uint32_t, idb->idb_bufoffset, 2802a668b114SPriya Krishnan uint64_t, 0, uint32_t, 0, uint32_t, 0, 2803a668b114SPriya Krishnan uint32_t, idb->idb_xfer_len, 2804a668b114SPriya Krishnan int, XFER_BUF_TX_TO_INI); 280530e7468fSPeter Dunlap idm_buf_tx_to_ini_done(idt, idb, status); 280630e7468fSPeter Dunlap } else { 280730e7468fSPeter Dunlap idm_so_send_rtt_data_done(idt, idb); 280830e7468fSPeter Dunlap mutex_exit(&idt->idt_mutex); 280930e7468fSPeter Dunlap } 2810a6d42e7dSPeter Dunlap break; 2811a6d42e7dSPeter Dunlap } 2812a6d42e7dSPeter Dunlap 2813a6d42e7dSPeter Dunlap default: 2814a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, "idm_sotx_thread: Unknown magic " 2815a6d42e7dSPeter Dunlap "(0x%08x)", object->idm_tx_obj_magic); 2816a6d42e7dSPeter Dunlap status = IDM_STATUS_FAIL; 2817a6d42e7dSPeter Dunlap } 2818a6d42e7dSPeter Dunlap 2819a6d42e7dSPeter Dunlap mutex_enter(&so_conn->ic_tx_mutex); 2820a6d42e7dSPeter Dunlap 2821a6d42e7dSPeter Dunlap if (status != IDM_STATUS_SUCCESS) { 2822a6d42e7dSPeter Dunlap so_conn->ic_tx_thread_running = B_FALSE; 2823a6d42e7dSPeter Dunlap idm_conn_event(ic, CE_TRANSPORT_FAIL, status); 2824a6d42e7dSPeter Dunlap } 2825a6d42e7dSPeter Dunlap } 2826a6d42e7dSPeter Dunlap 2827a6d42e7dSPeter Dunlap /* 2828a6d42e7dSPeter Dunlap * Before we leave, we need to abort every item remaining in the 2829a6d42e7dSPeter Dunlap * TX list. 2830a6d42e7dSPeter Dunlap */ 2831a6d42e7dSPeter Dunlap 2832a6d42e7dSPeter Dunlap tx_bail: 2833a6d42e7dSPeter Dunlap object = (idm_tx_obj_t *)list_head(&so_conn->ic_tx_list); 2834a6d42e7dSPeter Dunlap 2835a6d42e7dSPeter Dunlap while (object != NULL) { 2836a6d42e7dSPeter Dunlap next = list_next(&so_conn->ic_tx_list, object); 2837a6d42e7dSPeter Dunlap 2838a6d42e7dSPeter Dunlap list_remove(&so_conn->ic_tx_list, object); 2839a6d42e7dSPeter Dunlap switch (object->idm_tx_obj_magic) { 2840a6d42e7dSPeter Dunlap case IDM_PDU_MAGIC: 2841a6d42e7dSPeter Dunlap idm_pdu_complete((idm_pdu_t *)object, 2842a6d42e7dSPeter Dunlap IDM_STATUS_ABORTED); 2843a6d42e7dSPeter Dunlap break; 2844a6d42e7dSPeter Dunlap 2845a6d42e7dSPeter Dunlap case IDM_BUF_MAGIC: { 2846a6d42e7dSPeter Dunlap idm_buf_t *idb = (idm_buf_t *)object; 2847a6d42e7dSPeter Dunlap idm_task_t *idt = idb->idb_task_binding; 2848a6d42e7dSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 2849a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 2850a6d42e7dSPeter Dunlap /* 2851a6d42e7dSPeter Dunlap * TX thread owns the buffer so we expect it to 2852a6d42e7dSPeter Dunlap * be "in transport" 2853a6d42e7dSPeter Dunlap */ 2854a6d42e7dSPeter Dunlap ASSERT(idb->idb_in_transport); 285530e7468fSPeter Dunlap if (IDM_CONN_ISTGT(ic)) { 285630e7468fSPeter Dunlap /* 285730e7468fSPeter Dunlap * idm_buf_tx_to_ini_done releases 285830e7468fSPeter Dunlap * idt->idt_mutex 285930e7468fSPeter Dunlap */ 2860a668b114SPriya Krishnan DTRACE_ISCSI_8(xfer__done, 2861a668b114SPriya Krishnan idm_conn_t *, idt->idt_ic, 2862a668b114SPriya Krishnan uintptr_t, idb->idb_buf, 2863a668b114SPriya Krishnan uint32_t, idb->idb_bufoffset, 2864a668b114SPriya Krishnan uint64_t, 0, uint32_t, 0, uint32_t, 0, 2865a668b114SPriya Krishnan uint32_t, idb->idb_xfer_len, 2866a668b114SPriya Krishnan int, XFER_BUF_TX_TO_INI); 286730e7468fSPeter Dunlap idm_buf_tx_to_ini_done(idt, idb, 286830e7468fSPeter Dunlap IDM_STATUS_ABORTED); 286930e7468fSPeter Dunlap } else { 287030e7468fSPeter Dunlap idm_so_send_rtt_data_done(idt, idb); 287130e7468fSPeter Dunlap mutex_exit(&idt->idt_mutex); 287230e7468fSPeter Dunlap } 2873a6d42e7dSPeter Dunlap mutex_enter(&so_conn->ic_tx_mutex); 2874a6d42e7dSPeter Dunlap break; 2875a6d42e7dSPeter Dunlap } 2876a6d42e7dSPeter Dunlap default: 2877a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, 2878a6d42e7dSPeter Dunlap "idm_sotx_thread: Unexpected magic " 2879a6d42e7dSPeter Dunlap "(0x%08x)", object->idm_tx_obj_magic); 2880a6d42e7dSPeter Dunlap } 2881a6d42e7dSPeter Dunlap 2882a6d42e7dSPeter Dunlap object = next; 2883a6d42e7dSPeter Dunlap } 2884a6d42e7dSPeter Dunlap 2885a6d42e7dSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 2886a6d42e7dSPeter Dunlap idm_conn_rele(ic); 2887a6d42e7dSPeter Dunlap thread_exit(); 2888a6d42e7dSPeter Dunlap /*NOTREACHED*/ 2889a6d42e7dSPeter Dunlap } 2890aff4bce5Syi zhang - Sun Microsystems - Beijing China 2891aff4bce5Syi zhang - Sun Microsystems - Beijing China static void 2892aff4bce5Syi zhang - Sun Microsystems - Beijing China idm_so_socket_set_nonblock(struct sonode *node) 2893aff4bce5Syi zhang - Sun Microsystems - Beijing China { 2894aff4bce5Syi zhang - Sun Microsystems - Beijing China (void) VOP_SETFL(node->so_vnode, node->so_flag, 2895aff4bce5Syi zhang - Sun Microsystems - Beijing China (node->so_state | FNONBLOCK), CRED(), NULL); 2896aff4bce5Syi zhang - Sun Microsystems - Beijing China } 2897aff4bce5Syi zhang - Sun Microsystems - Beijing China 2898aff4bce5Syi zhang - Sun Microsystems - Beijing China static void 2899aff4bce5Syi zhang - Sun Microsystems - Beijing China idm_so_socket_set_block(struct sonode *node) 2900aff4bce5Syi zhang - Sun Microsystems - Beijing China { 2901aff4bce5Syi zhang - Sun Microsystems - Beijing China (void) VOP_SETFL(node->so_vnode, node->so_flag, 2902aff4bce5Syi zhang - Sun Microsystems - Beijing China (node->so_state & (~FNONBLOCK)), CRED(), NULL); 2903aff4bce5Syi zhang - Sun Microsystems - Beijing China } 2904bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 2905bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 2906bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* 2907bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * Called by kernel sockets when the connection has been accepted or 2908bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * rejected. In early volo, a "disconnect" callback was sent instead of 2909bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * "connectfailed", so we check for both. 2910bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States */ 2911bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* ARGSUSED */ 2912bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States void 2913bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States idm_so_timed_socket_connect_cb(ksocket_t ks, 2914bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States ksocket_callback_event_t ev, void *arg, uintptr_t info) 2915bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States { 2916bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States idm_so_timed_socket_t *itp = arg; 2917bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States ASSERT(itp != NULL); 2918bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States ASSERT(ev == KSOCKET_EV_CONNECTED || 2919bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States ev == KSOCKET_EV_CONNECTFAILED || 2920bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States ev == KSOCKET_EV_DISCONNECTED); 2921bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 2922bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States mutex_enter(&idm_so_timed_socket_mutex); 2923bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States itp->it_callback_called = B_TRUE; 2924bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States if (ev == KSOCKET_EV_CONNECTED) { 2925bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States itp->it_socket_error_code = 0; 2926bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } else { 2927bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* Make sure the error code is non-zero on error */ 2928bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States if (info == 0) 2929bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States info = ECONNRESET; 2930bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States itp->it_socket_error_code = (int)info; 2931bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 2932bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States cv_signal(&itp->it_cv); 2933bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States mutex_exit(&idm_so_timed_socket_mutex); 2934bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 2935bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 2936bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States int 2937bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States idm_so_timed_socket_connect(ksocket_t ks, 2938bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States struct sockaddr_storage *sa, int sa_sz, int login_max_usec) 2939bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States { 2940bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States clock_t conn_login_max; 2941bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States int rc, nonblocking, rval; 2942bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States idm_so_timed_socket_t it; 2943bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States ksocket_callbacks_t ks_cb; 2944bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 2945bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States conn_login_max = ddi_get_lbolt() + drv_usectohz(login_max_usec); 2946bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 2947bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* 2948bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * Set to non-block socket mode, with callback on connect 2949bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * Early volo used "disconnected" instead of "connectfailed", 2950bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * so set callback to look for both. 2951bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States */ 2952bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States bzero(&it, sizeof (it)); 2953bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States ks_cb.ksock_cb_flags = KSOCKET_CB_CONNECTED | 2954bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States KSOCKET_CB_CONNECTFAILED | KSOCKET_CB_DISCONNECTED; 2955bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States ks_cb.ksock_cb_connected = idm_so_timed_socket_connect_cb; 2956bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States ks_cb.ksock_cb_connectfailed = idm_so_timed_socket_connect_cb; 2957bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States ks_cb.ksock_cb_disconnected = idm_so_timed_socket_connect_cb; 2958bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States cv_init(&it.it_cv, NULL, CV_DEFAULT, NULL); 2959bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States rc = ksocket_setcallbacks(ks, &ks_cb, &it, CRED()); 2960bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States if (rc != 0) 2961bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States return (rc); 2962bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 2963bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* Set to non-blocking mode */ 2964bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States nonblocking = 1; 2965bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States rc = ksocket_ioctl(ks, FIONBIO, (intptr_t)&nonblocking, &rval, 2966bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States CRED()); 2967bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States if (rc != 0) 2968bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States goto cleanup; 2969bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 2970bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States bzero(&it, sizeof (it)); 2971bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States for (;;) { 2972bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* 2973bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * Warning -- in a loopback scenario, the call to 2974bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * the connect_cb can occur inside the call to 2975bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * ksocket_connect. Do not hold the mutex around the 2976bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * call to ksocket_connect. 2977bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States */ 2978bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States rc = ksocket_connect(ks, (struct sockaddr *)sa, sa_sz, CRED()); 2979bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States if (rc == 0 || rc == EISCONN) { 2980bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* socket success or already success */ 2981bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States rc = 0; 2982bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States break; 2983bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 2984bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States if ((rc != EINPROGRESS) && (rc != EALREADY)) { 2985bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States break; 2986bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 2987bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 2988bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* TCP connect still in progress. See if out of time. */ 2989bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States if (ddi_get_lbolt() > conn_login_max) { 2990bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* 2991bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * Connection retry timeout, 2992bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * failed connect to target. 2993bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States */ 2994bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States rc = ETIMEDOUT; 2995bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States break; 2996bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 2997bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 2998bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* 2999bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * TCP connect still in progress. Sleep until callback. 3000bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * Do NOT go to sleep if the callback already occurred! 3001bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States */ 3002bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States mutex_enter(&idm_so_timed_socket_mutex); 3003bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States if (!it.it_callback_called) { 3004bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States (void) cv_timedwait(&it.it_cv, 3005bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States &idm_so_timed_socket_mutex, conn_login_max); 3006bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3007bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States if (it.it_callback_called) { 3008bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States rc = it.it_socket_error_code; 3009bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States mutex_exit(&idm_so_timed_socket_mutex); 3010bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States break; 3011bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3012bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* If timer expires, go call ksocket_connect one last time. */ 3013bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States mutex_exit(&idm_so_timed_socket_mutex); 3014bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3015bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 3016bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* resume blocking mode */ 3017bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States nonblocking = 0; 3018bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States (void) ksocket_ioctl(ks, FIONBIO, (intptr_t)&nonblocking, &rval, 3019bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States CRED()); 3020bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States cleanup: 3021bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States ksocket_setcallbacks(ks, NULL, NULL, CRED()); 3022bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States cv_destroy(&it.it_cv); 3023bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States if (rc != 0) { 3024bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States idm_soshutdown(ks); 3025bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3026bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States return (rc); 3027bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3028bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 3029bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 3030bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States void 3031bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States idm_addr_to_sa(idm_addr_t *dportal, struct sockaddr_storage *sa) 3032bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States { 3033bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States int dp_addr_size; 3034bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States struct sockaddr_in *sin; 3035bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States struct sockaddr_in6 *sin6; 3036bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 3037bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* Build sockaddr_storage for this portal (idm_addr_t) */ 3038bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States bzero(sa, sizeof (*sa)); 3039bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States dp_addr_size = dportal->a_addr.i_insize; 3040bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States if (dp_addr_size == sizeof (struct in_addr)) { 3041bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* IPv4 */ 3042bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States sa->ss_family = AF_INET; 3043bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States sin = (struct sockaddr_in *)sa; 3044bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States sin->sin_port = htons(dportal->a_port); 3045bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States bcopy(&dportal->a_addr.i_addr.in4, 3046bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States &sin->sin_addr, sizeof (struct in_addr)); 3047bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } else if (dp_addr_size == sizeof (struct in6_addr)) { 3048bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* IPv6 */ 3049bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States sa->ss_family = AF_INET6; 3050bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States sin6 = (struct sockaddr_in6 *)sa; 3051bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States sin6->sin6_port = htons(dportal->a_port); 3052bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States bcopy(&dportal->a_addr.i_addr.in6, 3053bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States &sin6->sin6_addr, sizeof (struct in6_addr)); 3054bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } else { 3055bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States ASSERT(0); 3056bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3057bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3058bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 3059bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 3060bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* 3061bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * return a human-readable form of a sockaddr_storage, in the form 3062bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * [ip-address]:port. This is used in calls to logging functions. 3063bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * If several calls to idm_sa_ntop are made within the same invocation 3064bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * of a logging function, then each one needs its own buf. 3065bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States */ 3066bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States const char * 3067bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States idm_sa_ntop(const struct sockaddr_storage *sa, 3068bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States char *buf, size_t size) 3069bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States { 3070bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States static const char bogus_ip[] = "[0].-1"; 3071bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States char tmp[INET6_ADDRSTRLEN]; 3072bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 3073bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States switch (sa->ss_family) { 3074bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States case AF_INET6: 3075bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States { 3076bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States const struct sockaddr_in6 *in6 = 3077bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States (const struct sockaddr_in6 *) sa; 3078bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 3079bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States if (inet_ntop(in6->sin6_family, 3080bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States &in6->sin6_addr, tmp, sizeof (tmp)) == NULL) { 3081bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States goto err; 3082bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3083bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States if (strlen(tmp) + sizeof ("[].65535") > size) { 3084bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States goto err; 3085bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3086bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* struct sockaddr_storage gets port info from v4 loc */ 3087bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States (void) snprintf(buf, size, "[%s].%u", tmp, 3088bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States ntohs(in6->sin6_port)); 3089bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States return (buf); 3090bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3091bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States case AF_INET: 3092bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States { 3093bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States const struct sockaddr_in *in = 3094bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States (const struct sockaddr_in *) sa; 3095bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 3096bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States if (inet_ntop(in->sin_family, &in->sin_addr, 3097bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States tmp, sizeof (tmp)) == NULL) { 3098bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States goto err; 3099bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3100bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States if (strlen(tmp) + sizeof ("[].65535") > size) { 3101bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States goto err; 3102bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3103bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States (void) snprintf(buf, size, "[%s].%u", tmp, 3104bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States ntohs(in->sin_port)); 3105bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States return (buf); 3106bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3107bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States default: 3108bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States break; 3109bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3110bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States err: 3111bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States (void) snprintf(buf, size, "%s", bogus_ip); 3112bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States return (buf); 3113bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States } 3114