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