xref: /illumos-gate/usr/src/uts/common/io/idm/idm_so.c (revision 61dfa509)
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 /*
22e97fb153SPeter Cudhea - Sun Microsystems - Burlington, MA United States  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23a6d42e7dSPeter Dunlap  * Use is subject to license terms.
24a6d42e7dSPeter Dunlap  */
250f94976eSJeff Biseda /*
260f94976eSJeff Biseda  * Copyright (c) 2013 by Delphix. All rights reserved.
27*61dfa509SRick McNeal  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
282727bb05STim Kordas  * Copyright (c) 2017, Joyent, Inc.  All rights reserved.
290f94976eSJeff Biseda  */
30a6d42e7dSPeter Dunlap 
31a6d42e7dSPeter Dunlap #include <sys/conf.h>
32a6d42e7dSPeter Dunlap #include <sys/stat.h>
33a6d42e7dSPeter Dunlap #include <sys/file.h>
34a6d42e7dSPeter Dunlap #include <sys/ddi.h>
35a6d42e7dSPeter Dunlap #include <sys/sunddi.h>
36a6d42e7dSPeter Dunlap #include <sys/modctl.h>
37a6d42e7dSPeter Dunlap #include <sys/priv.h>
38a6d42e7dSPeter Dunlap #include <sys/cpuvar.h>
39a6d42e7dSPeter Dunlap #include <sys/socket.h>
40a6d42e7dSPeter Dunlap #include <sys/strsubr.h>
41a6d42e7dSPeter Dunlap #include <sys/sysmacros.h>
42a6d42e7dSPeter Dunlap #include <sys/sdt.h>
43a6d42e7dSPeter Dunlap #include <netinet/tcp.h>
44a6d42e7dSPeter Dunlap #include <inet/tcp.h>
45a6d42e7dSPeter Dunlap #include <sys/socketvar.h>
46a6d42e7dSPeter Dunlap #include <sys/pathname.h>
47a6d42e7dSPeter Dunlap #include <sys/fs/snode.h>
48a6d42e7dSPeter Dunlap #include <sys/fs/dv_node.h>
49a6d42e7dSPeter Dunlap #include <sys/vnode.h>
50a6d42e7dSPeter Dunlap #include <netinet/in.h>
51a6d42e7dSPeter Dunlap #include <net/if.h>
52a6d42e7dSPeter Dunlap #include <sys/sockio.h>
530f1702c5SYu Xiangning #include <sys/ksocket.h>
54bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States #include <sys/filio.h>		/* FIONBIO */
5556261083SCharles Ting #include <sys/iscsi_protocol.h>
56a6d42e7dSPeter Dunlap #include <sys/idm/idm.h>
57a6d42e7dSPeter Dunlap #include <sys/idm/idm_so.h>
58a6d42e7dSPeter Dunlap #include <sys/idm/idm_text.h>
59a6d42e7dSPeter Dunlap 
60aff4bce5Syi zhang - Sun Microsystems - Beijing China #define	IN_PROGRESS_DELAY	1
61aff4bce5Syi zhang - Sun Microsystems - Beijing China 
62a6d42e7dSPeter Dunlap /*
63a6d42e7dSPeter Dunlap  * in6addr_any is currently all zeroes, but use the macro in case this
64a6d42e7dSPeter Dunlap  * ever changes.
65a6d42e7dSPeter Dunlap  */
66e42a0851Speter dunlap static const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
67a6d42e7dSPeter Dunlap 
68a6d42e7dSPeter Dunlap static void idm_sorx_cache_pdu_cb(idm_pdu_t *pdu, idm_status_t status);
69a6d42e7dSPeter Dunlap static void idm_sorx_addl_pdu_cb(idm_pdu_t *pdu, idm_status_t status);
70a6d42e7dSPeter Dunlap static void idm_sotx_cache_pdu_cb(idm_pdu_t *pdu, idm_status_t status);
71a6d42e7dSPeter Dunlap 
720f1702c5SYu Xiangning static idm_status_t idm_so_conn_create_common(idm_conn_t *ic, ksocket_t new_so);
73a6d42e7dSPeter Dunlap static void idm_so_conn_destroy_common(idm_conn_t *ic);
74a6d42e7dSPeter Dunlap static void idm_so_conn_connect_common(idm_conn_t *ic);
75a6d42e7dSPeter Dunlap 
76dedec472SJack Meng static void idm_set_ini_preconnect_options(idm_so_conn_t *sc,
77dedec472SJack Meng     boolean_t boot_conn);
780f94976eSJeff Biseda static void idm_set_postconnect_options(ksocket_t so);
79a6d42e7dSPeter Dunlap static idm_status_t idm_i_so_tx(idm_pdu_t *pdu);
80a6d42e7dSPeter Dunlap 
81a6d42e7dSPeter Dunlap static idm_status_t idm_sorecvdata(idm_conn_t *ic, idm_pdu_t *pdu);
8230e7468fSPeter Dunlap static void idm_so_send_rtt_data(idm_conn_t *ic, idm_task_t *idt,
8330e7468fSPeter Dunlap     idm_buf_t *idb, uint32_t offset, uint32_t length);
8430e7468fSPeter Dunlap static void idm_so_send_rtt_data_done(idm_task_t *idt, idm_buf_t *idb);
8530e7468fSPeter Dunlap static idm_status_t idm_so_send_buf_region(idm_task_t *idt,
86a6d42e7dSPeter Dunlap     idm_buf_t *idb, uint32_t buf_region_offset, uint32_t buf_region_length);
87a6d42e7dSPeter Dunlap 
88a6d42e7dSPeter Dunlap static uint32_t idm_fill_iov(idm_pdu_t *pdu, idm_buf_t *idb,
89a6d42e7dSPeter Dunlap     uint32_t ro, uint32_t dlength);
90a6d42e7dSPeter Dunlap 
91a6d42e7dSPeter Dunlap static idm_status_t idm_so_handle_digest(idm_conn_t *it,
92a6d42e7dSPeter Dunlap     nvpair_t *digest_choice, const idm_kv_xlate_t *ikvx);
93a6d42e7dSPeter Dunlap 
94aff4bce5Syi zhang - Sun Microsystems - Beijing China static void idm_so_socket_set_nonblock(struct sonode *node);
95aff4bce5Syi zhang - Sun Microsystems - Beijing China static void idm_so_socket_set_block(struct sonode *node);
96aff4bce5Syi zhang - Sun Microsystems - Beijing China 
97a6d42e7dSPeter Dunlap /*
98a6d42e7dSPeter Dunlap  * Transport ops prototypes
99a6d42e7dSPeter Dunlap  */
100a6d42e7dSPeter Dunlap static void idm_so_tx(idm_conn_t *ic, idm_pdu_t *pdu);
101a6d42e7dSPeter Dunlap static idm_status_t idm_so_buf_tx_to_ini(idm_task_t *idt, idm_buf_t *idb);
102a6d42e7dSPeter Dunlap static idm_status_t idm_so_buf_rx_from_ini(idm_task_t *idt, idm_buf_t *idb);
103a6d42e7dSPeter Dunlap static void idm_so_rx_datain(idm_conn_t *ic, idm_pdu_t *pdu);
104a6d42e7dSPeter Dunlap static void idm_so_rx_rtt(idm_conn_t *ic, idm_pdu_t *pdu);
105a6d42e7dSPeter Dunlap static void idm_so_rx_dataout(idm_conn_t *ic, idm_pdu_t *pdu);
106a6d42e7dSPeter Dunlap static idm_status_t idm_so_free_task_rsrc(idm_task_t *idt);
107a6d42e7dSPeter Dunlap static kv_status_t idm_so_negotiate_key_values(idm_conn_t *it,
108a6d42e7dSPeter Dunlap     nvlist_t *request_nvl, nvlist_t *response_nvl, nvlist_t *negotiated_nvl);
10930e7468fSPeter Dunlap static void idm_so_notice_key_values(idm_conn_t *it,
110a6d42e7dSPeter Dunlap     nvlist_t *negotiated_nvl);
11156261083SCharles Ting static kv_status_t idm_so_declare_key_values(idm_conn_t *it,
11256261083SCharles Ting     nvlist_t *config_nvl, nvlist_t *outgoing_nvl);
113a6d42e7dSPeter Dunlap static boolean_t idm_so_conn_is_capable(idm_conn_req_t *ic,
114a6d42e7dSPeter Dunlap     idm_transport_caps_t *caps);
115a6d42e7dSPeter Dunlap static idm_status_t idm_so_buf_alloc(idm_buf_t *idb, uint64_t buflen);
116a6d42e7dSPeter Dunlap static void idm_so_buf_free(idm_buf_t *idb);
117a6d42e7dSPeter Dunlap static idm_status_t idm_so_buf_setup(idm_buf_t *idb);
118a6d42e7dSPeter Dunlap static void idm_so_buf_teardown(idm_buf_t *idb);
119a6d42e7dSPeter Dunlap static idm_status_t idm_so_tgt_svc_create(idm_svc_req_t *sr, idm_svc_t *is);
120a6d42e7dSPeter Dunlap static void idm_so_tgt_svc_destroy(idm_svc_t *is);
121a6d42e7dSPeter Dunlap static idm_status_t idm_so_tgt_svc_online(idm_svc_t *is);
122a6d42e7dSPeter Dunlap static void idm_so_tgt_svc_offline(idm_svc_t *is);
123a6d42e7dSPeter Dunlap static void idm_so_tgt_conn_destroy(idm_conn_t *ic);
124a6d42e7dSPeter Dunlap static idm_status_t idm_so_tgt_conn_connect(idm_conn_t *ic);
125a6d42e7dSPeter Dunlap static void idm_so_conn_disconnect(idm_conn_t *ic);
126a6d42e7dSPeter Dunlap static idm_status_t idm_so_ini_conn_create(idm_conn_req_t *cr, idm_conn_t *ic);
127a6d42e7dSPeter Dunlap static void idm_so_ini_conn_destroy(idm_conn_t *ic);
128a6d42e7dSPeter Dunlap static idm_status_t idm_so_ini_conn_connect(idm_conn_t *ic);
129a6d42e7dSPeter Dunlap 
130a6d42e7dSPeter Dunlap /*
131a6d42e7dSPeter Dunlap  * IDM Native Sockets transport operations
132a6d42e7dSPeter Dunlap  */
133a6d42e7dSPeter Dunlap static
134a6d42e7dSPeter Dunlap idm_transport_ops_t idm_so_transport_ops = {
135a6d42e7dSPeter Dunlap 	idm_so_tx,			/* it_tx_pdu */
136a6d42e7dSPeter Dunlap 	idm_so_buf_tx_to_ini,		/* it_buf_tx_to_ini */
137a6d42e7dSPeter Dunlap 	idm_so_buf_rx_from_ini,		/* it_buf_rx_from_ini */
138a6d42e7dSPeter Dunlap 	idm_so_rx_datain,		/* it_rx_datain */
139a6d42e7dSPeter Dunlap 	idm_so_rx_rtt,			/* it_rx_rtt */
140a6d42e7dSPeter Dunlap 	idm_so_rx_dataout,		/* it_rx_dataout */
141a6d42e7dSPeter Dunlap 	NULL,				/* it_alloc_conn_rsrc */
142a6d42e7dSPeter Dunlap 	NULL,				/* it_free_conn_rsrc */
143a6d42e7dSPeter Dunlap 	NULL,				/* it_tgt_enable_datamover */
144a6d42e7dSPeter Dunlap 	NULL,				/* it_ini_enable_datamover */
145a6d42e7dSPeter Dunlap 	NULL,				/* it_conn_terminate */
146a6d42e7dSPeter Dunlap 	idm_so_free_task_rsrc,		/* it_free_task_rsrc */
147a6d42e7dSPeter Dunlap 	idm_so_negotiate_key_values,	/* it_negotiate_key_values */
148a6d42e7dSPeter Dunlap 	idm_so_notice_key_values,	/* it_notice_key_values */
149a6d42e7dSPeter Dunlap 	idm_so_conn_is_capable,		/* it_conn_is_capable */
150a6d42e7dSPeter Dunlap 	idm_so_buf_alloc,		/* it_buf_alloc */
151a6d42e7dSPeter Dunlap 	idm_so_buf_free,		/* it_buf_free */
152a6d42e7dSPeter Dunlap 	idm_so_buf_setup,		/* it_buf_setup */
153a6d42e7dSPeter Dunlap 	idm_so_buf_teardown,		/* it_buf_teardown */
154a6d42e7dSPeter Dunlap 	idm_so_tgt_svc_create,		/* it_tgt_svc_create */
155a6d42e7dSPeter Dunlap 	idm_so_tgt_svc_destroy,		/* it_tgt_svc_destroy */
156a6d42e7dSPeter Dunlap 	idm_so_tgt_svc_online,		/* it_tgt_svc_online */
157a6d42e7dSPeter Dunlap 	idm_so_tgt_svc_offline,		/* it_tgt_svc_offline */
158a6d42e7dSPeter Dunlap 	idm_so_tgt_conn_destroy,	/* it_tgt_conn_destroy */
159a6d42e7dSPeter Dunlap 	idm_so_tgt_conn_connect,	/* it_tgt_conn_connect */
160a6d42e7dSPeter Dunlap 	idm_so_conn_disconnect,		/* it_tgt_conn_disconnect */
161a6d42e7dSPeter Dunlap 	idm_so_ini_conn_create,		/* it_ini_conn_create */
162a6d42e7dSPeter Dunlap 	idm_so_ini_conn_destroy,	/* it_ini_conn_destroy */
163a6d42e7dSPeter Dunlap 	idm_so_ini_conn_connect,	/* it_ini_conn_connect */
16456261083SCharles Ting 	idm_so_conn_disconnect,		/* it_ini_conn_disconnect */
16556261083SCharles Ting 	idm_so_declare_key_values	/* it_declare_key_values */
166a6d42e7dSPeter Dunlap };
167a6d42e7dSPeter Dunlap 
168bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States kmutex_t	idm_so_timed_socket_mutex;
1690f94976eSJeff Biseda 
1700f94976eSJeff Biseda int32_t idm_so_sndbuf = IDM_SNDBUF_SIZE;
1710f94976eSJeff Biseda int32_t idm_so_rcvbuf = IDM_RCVBUF_SIZE;
1720f94976eSJeff Biseda 
173a6d42e7dSPeter Dunlap /*
174a6d42e7dSPeter Dunlap  * idm_so_init()
175a6d42e7dSPeter Dunlap  * Sockets transport initialization
176a6d42e7dSPeter Dunlap  */
177a6d42e7dSPeter Dunlap void
idm_so_init(idm_transport_t * it)178a6d42e7dSPeter Dunlap idm_so_init(idm_transport_t *it)
179a6d42e7dSPeter Dunlap {
180a6d42e7dSPeter Dunlap 	/* Cache for IDM Data and R2T Transmit PDU's */
181a6d42e7dSPeter Dunlap 	idm.idm_sotx_pdu_cache = kmem_cache_create("idm_tx_pdu_cache",
182a6d42e7dSPeter Dunlap 	    sizeof (idm_pdu_t) + sizeof (iscsi_hdr_t), 8,
183a6d42e7dSPeter Dunlap 	    &idm_sotx_pdu_constructor, NULL, NULL, NULL, NULL, KM_SLEEP);
184a6d42e7dSPeter Dunlap 
185a6d42e7dSPeter Dunlap 	/* Cache for IDM Receive PDU's */
186a6d42e7dSPeter Dunlap 	idm.idm_sorx_pdu_cache = kmem_cache_create("idm_rx_pdu_cache",
187a6d42e7dSPeter Dunlap 	    sizeof (idm_pdu_t) + IDM_SORX_CACHE_HDRLEN, 8,
188a6d42e7dSPeter Dunlap 	    &idm_sorx_pdu_constructor, NULL, NULL, NULL, NULL, KM_SLEEP);
189a6d42e7dSPeter Dunlap 
190cf8c0ebaSPeter Dunlap 	/* 128k buffer cache */
191cf8c0ebaSPeter Dunlap 	idm.idm_so_128k_buf_cache = kmem_cache_create("idm_128k_buf_cache",
192cf8c0ebaSPeter Dunlap 	    IDM_SO_BUF_CACHE_UB, 8, NULL, NULL, NULL, NULL, NULL, KM_SLEEP);
193cf8c0ebaSPeter Dunlap 
194a6d42e7dSPeter Dunlap 	/* Set the sockets transport ops */
195a6d42e7dSPeter Dunlap 	it->it_ops = &idm_so_transport_ops;
196bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 
197bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	mutex_init(&idm_so_timed_socket_mutex, NULL, MUTEX_DEFAULT, NULL);
198bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 
199a6d42e7dSPeter Dunlap }
200a6d42e7dSPeter Dunlap 
201a6d42e7dSPeter Dunlap /*
202a6d42e7dSPeter Dunlap  * idm_so_fini()
203a6d42e7dSPeter Dunlap  * Sockets transport teardown
204a6d42e7dSPeter Dunlap  */
205a6d42e7dSPeter Dunlap void
idm_so_fini(void)206a6d42e7dSPeter Dunlap idm_so_fini(void)
207a6d42e7dSPeter Dunlap {
208cf8c0ebaSPeter Dunlap 	kmem_cache_destroy(idm.idm_so_128k_buf_cache);
209a6d42e7dSPeter Dunlap 	kmem_cache_destroy(idm.idm_sotx_pdu_cache);
210a6d42e7dSPeter Dunlap 	kmem_cache_destroy(idm.idm_sorx_pdu_cache);
211bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	mutex_destroy(&idm_so_timed_socket_mutex);
212a6d42e7dSPeter Dunlap }
213a6d42e7dSPeter Dunlap 
2140f1702c5SYu Xiangning ksocket_t
idm_socreate(int domain,int type,int protocol)215a6d42e7dSPeter Dunlap idm_socreate(int domain, int type, int protocol)
216a6d42e7dSPeter Dunlap {
2170f1702c5SYu Xiangning 	ksocket_t ks;
218a6d42e7dSPeter Dunlap 
2190f1702c5SYu Xiangning 	if (!ksocket_socket(&ks, domain, type, protocol, KSOCKET_NOSLEEP,
2200f1702c5SYu Xiangning 	    CRED())) {
2210f1702c5SYu Xiangning 		return (ks);
2220f1702c5SYu Xiangning 	} else {
2230f1702c5SYu Xiangning 		return (NULL);
224a6d42e7dSPeter Dunlap 	}
225a6d42e7dSPeter Dunlap }
226a6d42e7dSPeter Dunlap 
227a6d42e7dSPeter Dunlap /*
228a6d42e7dSPeter Dunlap  * idm_soshutdown will disconnect the socket and prevent subsequent PDU
229a6d42e7dSPeter Dunlap  * reception and transmission.  The sonode still exists but its state
230a6d42e7dSPeter Dunlap  * gets modified to indicate it is no longer connected.  Calls to
231a6d42e7dSPeter Dunlap  * idm_sorecv/idm_iov_sorecv will return so idm_soshutdown can be used
232a6d42e7dSPeter Dunlap  * regain control of a thread stuck in idm_sorecv.
233a6d42e7dSPeter Dunlap  */
234a6d42e7dSPeter Dunlap void
idm_soshutdown(ksocket_t so)2350f1702c5SYu Xiangning idm_soshutdown(ksocket_t so)
236a6d42e7dSPeter Dunlap {
2370f1702c5SYu Xiangning 	(void) ksocket_shutdown(so, SHUT_RDWR, CRED());
238a6d42e7dSPeter Dunlap }
239a6d42e7dSPeter Dunlap 
240a6d42e7dSPeter Dunlap /*
241a6d42e7dSPeter Dunlap  * idm_sodestroy releases all resources associated with a socket previously
242a6d42e7dSPeter Dunlap  * created with idm_socreate.  The socket must be shutdown using
243a6d42e7dSPeter Dunlap  * idm_soshutdown before the socket is destroyed with idm_sodestroy,
244a6d42e7dSPeter Dunlap  * otherwise undefined behavior will result.
245a6d42e7dSPeter Dunlap  */
246a6d42e7dSPeter Dunlap void
idm_sodestroy(ksocket_t ks)2470f1702c5SYu Xiangning idm_sodestroy(ksocket_t ks)
248a6d42e7dSPeter Dunlap {
2490f1702c5SYu Xiangning 	(void) ksocket_close(ks, CRED());
250a6d42e7dSPeter Dunlap }
251a6d42e7dSPeter Dunlap 
252e42a0851Speter dunlap /*
253e42a0851Speter dunlap  * Function to compare two addresses in sockaddr_storage format
254e42a0851Speter dunlap  */
255e42a0851Speter dunlap 
256e42a0851Speter dunlap int
idm_ss_compare(const struct sockaddr_storage * cmp_ss1,const struct sockaddr_storage * cmp_ss2,boolean_t v4_mapped_as_v4,boolean_t compare_ports)257e42a0851Speter dunlap idm_ss_compare(const struct sockaddr_storage *cmp_ss1,
258e42a0851Speter dunlap     const struct sockaddr_storage *cmp_ss2,
259bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States     boolean_t v4_mapped_as_v4,
260bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States     boolean_t compare_ports)
261e42a0851Speter dunlap {
262e42a0851Speter dunlap 	struct sockaddr_storage			mapped_v4_ss1, mapped_v4_ss2;
263e42a0851Speter dunlap 	const struct sockaddr_storage		*ss1, *ss2;
264e42a0851Speter dunlap 	struct in_addr				*in1, *in2;
265e42a0851Speter dunlap 	struct in6_addr				*in61, *in62;
266e42a0851Speter dunlap 	int i;
267e42a0851Speter dunlap 
268e42a0851Speter dunlap 	/*
269e42a0851Speter dunlap 	 * Normalize V4-mapped IPv6 addresses into V4 format if
270e42a0851Speter dunlap 	 * v4_mapped_as_v4 is B_TRUE.
271e42a0851Speter dunlap 	 */
272e42a0851Speter dunlap 	ss1 = cmp_ss1;
273e42a0851Speter dunlap 	ss2 = cmp_ss2;
274e42a0851Speter dunlap 	if (v4_mapped_as_v4 && (ss1->ss_family == AF_INET6)) {
275e42a0851Speter dunlap 		in61 = &((struct sockaddr_in6 *)ss1)->sin6_addr;
276e42a0851Speter dunlap 		if (IN6_IS_ADDR_V4MAPPED(in61)) {
277e42a0851Speter dunlap 			bzero(&mapped_v4_ss1, sizeof (mapped_v4_ss1));
278e42a0851Speter dunlap 			mapped_v4_ss1.ss_family = AF_INET;
279e42a0851Speter dunlap 			((struct sockaddr_in *)&mapped_v4_ss1)->sin_port =
280e42a0851Speter dunlap 			    ((struct sockaddr_in *)ss1)->sin_port;
281e42a0851Speter dunlap 			IN6_V4MAPPED_TO_INADDR(in61,
282e42a0851Speter dunlap 			    &((struct sockaddr_in *)&mapped_v4_ss1)->sin_addr);
283e42a0851Speter dunlap 			ss1 = &mapped_v4_ss1;
284e42a0851Speter dunlap 		}
285e42a0851Speter dunlap 	}
286e42a0851Speter dunlap 	ss2 = cmp_ss2;
287e42a0851Speter dunlap 	if (v4_mapped_as_v4 && (ss2->ss_family == AF_INET6)) {
288e42a0851Speter dunlap 		in62 = &((struct sockaddr_in6 *)ss2)->sin6_addr;
289e42a0851Speter dunlap 		if (IN6_IS_ADDR_V4MAPPED(in62)) {
290e42a0851Speter dunlap 			bzero(&mapped_v4_ss2, sizeof (mapped_v4_ss2));
291e42a0851Speter dunlap 			mapped_v4_ss2.ss_family = AF_INET;
292e42a0851Speter dunlap 			((struct sockaddr_in *)&mapped_v4_ss2)->sin_port =
293e42a0851Speter dunlap 			    ((struct sockaddr_in *)ss2)->sin_port;
294e42a0851Speter dunlap 			IN6_V4MAPPED_TO_INADDR(in62,
295e42a0851Speter dunlap 			    &((struct sockaddr_in *)&mapped_v4_ss2)->sin_addr);
296e42a0851Speter dunlap 			ss2 = &mapped_v4_ss2;
297e42a0851Speter dunlap 		}
298e42a0851Speter dunlap 	}
299e42a0851Speter dunlap 
300e42a0851Speter dunlap 	/*
301e42a0851Speter dunlap 	 * Compare ports, then address family, then ip address
302e42a0851Speter dunlap 	 */
303bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	if (compare_ports &&
304bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	    (((struct sockaddr_in *)ss1)->sin_port !=
305bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	    ((struct sockaddr_in *)ss2)->sin_port)) {
306e42a0851Speter dunlap 		if (((struct sockaddr_in *)ss1)->sin_port >
307e42a0851Speter dunlap 		    ((struct sockaddr_in *)ss2)->sin_port)
308e42a0851Speter dunlap 			return (1);
309e42a0851Speter dunlap 		else
310e42a0851Speter dunlap 			return (-1);
311e42a0851Speter dunlap 	}
312e42a0851Speter dunlap 
313e42a0851Speter dunlap 	/*
314e42a0851Speter dunlap 	 * ports are the same
315e42a0851Speter dunlap 	 */
316e42a0851Speter dunlap 	if (ss1->ss_family != ss2->ss_family) {
317e42a0851Speter dunlap 		if (ss1->ss_family == AF_INET)
318e42a0851Speter dunlap 			return (1);
319e42a0851Speter dunlap 		else
320e42a0851Speter dunlap 			return (-1);
321e42a0851Speter dunlap 	}
322e42a0851Speter dunlap 
323e42a0851Speter dunlap 	/*
324e42a0851Speter dunlap 	 * address families are the same
325e42a0851Speter dunlap 	 */
326e42a0851Speter dunlap 	if (ss1->ss_family == AF_INET) {
327e42a0851Speter dunlap 		in1 = &((struct sockaddr_in *)ss1)->sin_addr;
328e42a0851Speter dunlap 		in2 = &((struct sockaddr_in *)ss2)->sin_addr;
329e42a0851Speter dunlap 
330e42a0851Speter dunlap 		if (in1->s_addr > in2->s_addr)
331e42a0851Speter dunlap 			return (1);
332e42a0851Speter dunlap 		else if (in1->s_addr < in2->s_addr)
333e42a0851Speter dunlap 			return (-1);
334e42a0851Speter dunlap 		else
335e42a0851Speter dunlap 			return (0);
336e42a0851Speter dunlap 	} else if (ss1->ss_family == AF_INET6) {
337e42a0851Speter dunlap 		in61 = &((struct sockaddr_in6 *)ss1)->sin6_addr;
338e42a0851Speter dunlap 		in62 = &((struct sockaddr_in6 *)ss2)->sin6_addr;
339e42a0851Speter dunlap 
340e42a0851Speter dunlap 		for (i = 0; i < 4; i++) {
341e42a0851Speter dunlap 			if (in61->s6_addr32[i] > in62->s6_addr32[i])
342e42a0851Speter dunlap 				return (1);
343e42a0851Speter dunlap 			else if (in61->s6_addr32[i] < in62->s6_addr32[i])
344e42a0851Speter dunlap 				return (-1);
345e42a0851Speter dunlap 		}
346e42a0851Speter dunlap 		return (0);
347e42a0851Speter dunlap 	}
348e42a0851Speter dunlap 
349e42a0851Speter dunlap 	return (1);
350e42a0851Speter dunlap }
351e42a0851Speter dunlap 
352a6d42e7dSPeter Dunlap /*
353a6d42e7dSPeter Dunlap  * IP address filter functions to flag addresses that should not
354a6d42e7dSPeter Dunlap  * go out to initiators through discovery.
355a6d42e7dSPeter Dunlap  */
356a6d42e7dSPeter Dunlap static boolean_t
idm_v4_addr_okay(struct in_addr * in_addr)357a6d42e7dSPeter Dunlap idm_v4_addr_okay(struct in_addr *in_addr)
358a6d42e7dSPeter Dunlap {
359a6d42e7dSPeter Dunlap 	in_addr_t addr = ntohl(in_addr->s_addr);
360a6d42e7dSPeter Dunlap 
361a6d42e7dSPeter Dunlap 	if ((INADDR_NONE == addr) ||
362a6d42e7dSPeter Dunlap 	    (IN_MULTICAST(addr)) ||
363a6d42e7dSPeter Dunlap 	    ((addr >> IN_CLASSA_NSHIFT) == 0) ||
364a6d42e7dSPeter Dunlap 	    ((addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)) {
365a6d42e7dSPeter Dunlap 		return (B_FALSE);
366a6d42e7dSPeter Dunlap 	}
367a6d42e7dSPeter Dunlap 	return (B_TRUE);
368a6d42e7dSPeter Dunlap }
369a6d42e7dSPeter Dunlap 
370a6d42e7dSPeter Dunlap static boolean_t
idm_v6_addr_okay(struct in6_addr * addr6)371a6d42e7dSPeter Dunlap idm_v6_addr_okay(struct in6_addr *addr6)
372a6d42e7dSPeter Dunlap {
373a6d42e7dSPeter Dunlap 
374a6d42e7dSPeter Dunlap 	if ((IN6_IS_ADDR_UNSPECIFIED(addr6)) ||
375a6d42e7dSPeter Dunlap 	    (IN6_IS_ADDR_LOOPBACK(addr6)) ||
376a6d42e7dSPeter Dunlap 	    (IN6_IS_ADDR_MULTICAST(addr6)) ||
377a6d42e7dSPeter Dunlap 	    (IN6_IS_ADDR_V4MAPPED(addr6)) ||
378a6d42e7dSPeter Dunlap 	    (IN6_IS_ADDR_V4COMPAT(addr6)) ||
379a6d42e7dSPeter Dunlap 	    (IN6_IS_ADDR_LINKLOCAL(addr6))) {
380a6d42e7dSPeter Dunlap 		return (B_FALSE);
381a6d42e7dSPeter Dunlap 	}
382a6d42e7dSPeter Dunlap 	return (B_TRUE);
383a6d42e7dSPeter Dunlap }
384a6d42e7dSPeter Dunlap 
385a6d42e7dSPeter Dunlap /*
386a6d42e7dSPeter Dunlap  * idm_get_ipaddr will retrieve a list of IP Addresses which the host is
387a6d42e7dSPeter Dunlap  * configured with by sending down a sequence of kernel ioctl to IP STREAMS.
388a6d42e7dSPeter Dunlap  */
389a6d42e7dSPeter Dunlap int
idm_get_ipaddr(idm_addr_list_t ** ipaddr_p)390a6d42e7dSPeter Dunlap idm_get_ipaddr(idm_addr_list_t **ipaddr_p)
391a6d42e7dSPeter Dunlap {
3928e718be9SToomas Soome 	ksocket_t		so4, so6;
393a6d42e7dSPeter Dunlap 	struct lifnum		lifn;
394a6d42e7dSPeter Dunlap 	struct lifconf		lifc;
395a6d42e7dSPeter Dunlap 	struct lifreq		*lp;
396a6d42e7dSPeter Dunlap 	int			rval;
397a6d42e7dSPeter Dunlap 	int			numifs;
398a6d42e7dSPeter Dunlap 	int			bufsize;
399a6d42e7dSPeter Dunlap 	void			*buf;
400a6d42e7dSPeter Dunlap 	int			i, j, n, rc;
401a6d42e7dSPeter Dunlap 	struct sockaddr_storage	ss;
402a6d42e7dSPeter Dunlap 	struct sockaddr_in	*sin;
403a6d42e7dSPeter Dunlap 	struct sockaddr_in6	*sin6;
404a6d42e7dSPeter Dunlap 	idm_addr_t		*ip;
405fcc214c3SCharles Ting 	idm_addr_list_t		*ipaddr = NULL;
406a6d42e7dSPeter Dunlap 	int			size_ipaddr;
407a6d42e7dSPeter Dunlap 
408a6d42e7dSPeter Dunlap 	*ipaddr_p = NULL;
409a6d42e7dSPeter Dunlap 	size_ipaddr = 0;
410a6d42e7dSPeter Dunlap 	buf = NULL;
411a6d42e7dSPeter Dunlap 
412a6d42e7dSPeter Dunlap 	/* create an ipv4 and ipv6 UDP socket */
413a6d42e7dSPeter Dunlap 	if ((so6 = idm_socreate(PF_INET6, SOCK_DGRAM, 0)) == NULL)
414a6d42e7dSPeter Dunlap 		return (0);
415a6d42e7dSPeter Dunlap 	if ((so4 = idm_socreate(PF_INET, SOCK_DGRAM, 0)) == NULL) {
416a6d42e7dSPeter Dunlap 		idm_sodestroy(so6);
417a6d42e7dSPeter Dunlap 		return (0);
418a6d42e7dSPeter Dunlap 	}
419a6d42e7dSPeter Dunlap 
420a6d42e7dSPeter Dunlap 
421a6d42e7dSPeter Dunlap retry_count:
422a6d42e7dSPeter Dunlap 	/* snapshot the current number of interfaces */
423a6d42e7dSPeter Dunlap 	lifn.lifn_family = PF_UNSPEC;
424a6d42e7dSPeter Dunlap 	lifn.lifn_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES;
425a6d42e7dSPeter Dunlap 	lifn.lifn_count = 0;
4260f1702c5SYu Xiangning 	/* use vp6 for ioctls with unspecified families by default */
4270f1702c5SYu Xiangning 	if (ksocket_ioctl(so6, SIOCGLIFNUM, (intptr_t)&lifn, &rval, CRED())
4280f1702c5SYu Xiangning 	    != 0) {
429a6d42e7dSPeter Dunlap 		goto cleanup;
430a6d42e7dSPeter Dunlap 	}
431a6d42e7dSPeter Dunlap 
432a6d42e7dSPeter Dunlap 	numifs = lifn.lifn_count;
433a6d42e7dSPeter Dunlap 	if (numifs <= 0) {
434a6d42e7dSPeter Dunlap 		goto cleanup;
435a6d42e7dSPeter Dunlap 	}
436a6d42e7dSPeter Dunlap 
437a6d42e7dSPeter Dunlap 	/* allocate extra room in case more interfaces appear */
438a6d42e7dSPeter Dunlap 	numifs += 10;
439a6d42e7dSPeter Dunlap 
440a6d42e7dSPeter Dunlap 	/* get the interface names and ip addresses */
441a6d42e7dSPeter Dunlap 	bufsize = numifs * sizeof (struct lifreq);
442a6d42e7dSPeter Dunlap 	buf = kmem_alloc(bufsize, KM_SLEEP);
443a6d42e7dSPeter Dunlap 
444a6d42e7dSPeter Dunlap 	lifc.lifc_family = AF_UNSPEC;
445a6d42e7dSPeter Dunlap 	lifc.lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES;
446a6d42e7dSPeter Dunlap 	lifc.lifc_len = bufsize;
447a6d42e7dSPeter Dunlap 	lifc.lifc_buf = buf;
4480f1702c5SYu Xiangning 	rc = ksocket_ioctl(so6, SIOCGLIFCONF, (intptr_t)&lifc, &rval, CRED());
449a6d42e7dSPeter Dunlap 	if (rc != 0) {
450a6d42e7dSPeter Dunlap 		goto cleanup;
451a6d42e7dSPeter Dunlap 	}
452a6d42e7dSPeter Dunlap 	/* if our extra room is used up, try again */
453a6d42e7dSPeter Dunlap 	if (bufsize <= lifc.lifc_len) {
454a6d42e7dSPeter Dunlap 		kmem_free(buf, bufsize);
455a6d42e7dSPeter Dunlap 		buf = NULL;
456a6d42e7dSPeter Dunlap 		goto retry_count;
457a6d42e7dSPeter Dunlap 	}
458a6d42e7dSPeter Dunlap 	/* calc actual number of ifconfs */
459a6d42e7dSPeter Dunlap 	n = lifc.lifc_len / sizeof (struct lifreq);
460a6d42e7dSPeter Dunlap 
461a6d42e7dSPeter Dunlap 	/* get ip address */
462a6d42e7dSPeter Dunlap 	if (n > 0) {
463a6d42e7dSPeter Dunlap 		size_ipaddr = sizeof (idm_addr_list_t) +
464a6d42e7dSPeter Dunlap 		    (n - 1) * sizeof (idm_addr_t);
465a6d42e7dSPeter Dunlap 		ipaddr = kmem_zalloc(size_ipaddr, KM_SLEEP);
466a6d42e7dSPeter Dunlap 	} else {
467a6d42e7dSPeter Dunlap 		goto cleanup;
468a6d42e7dSPeter Dunlap 	}
469a6d42e7dSPeter Dunlap 
470a6d42e7dSPeter Dunlap 	/*
471a6d42e7dSPeter Dunlap 	 * Examine the array of interfaces and filter uninteresting ones
472a6d42e7dSPeter Dunlap 	 */
473a6d42e7dSPeter Dunlap 	for (i = 0, j = 0, lp = lifc.lifc_req; i < n; i++, lp++) {
474a6d42e7dSPeter Dunlap 
475a6d42e7dSPeter Dunlap 		/*
476a6d42e7dSPeter Dunlap 		 * Copy the address as the SIOCGLIFFLAGS ioctl is destructive
477a6d42e7dSPeter Dunlap 		 */
478a6d42e7dSPeter Dunlap 		ss = lp->lifr_addr;
479a6d42e7dSPeter Dunlap 		/*
480a6d42e7dSPeter Dunlap 		 * fetch the flags using the socket of the correct family
481a6d42e7dSPeter Dunlap 		 */
482a6d42e7dSPeter Dunlap 		switch (ss.ss_family) {
483a6d42e7dSPeter Dunlap 		case AF_INET:
4840f1702c5SYu Xiangning 			rc = ksocket_ioctl(so4, SIOCGLIFFLAGS, (intptr_t)lp,
4850f1702c5SYu Xiangning 			    &rval, CRED());
486a6d42e7dSPeter Dunlap 			break;
487a6d42e7dSPeter Dunlap 		case AF_INET6:
4880f1702c5SYu Xiangning 			rc = ksocket_ioctl(so6, SIOCGLIFFLAGS, (intptr_t)lp,
4890f1702c5SYu Xiangning 			    &rval, CRED());
490a6d42e7dSPeter Dunlap 			break;
491a6d42e7dSPeter Dunlap 		default:
492a6d42e7dSPeter Dunlap 			continue;
493a6d42e7dSPeter Dunlap 		}
494a6d42e7dSPeter Dunlap 		if (rc == 0) {
495a6d42e7dSPeter Dunlap 			/*
496a6d42e7dSPeter Dunlap 			 * If we got the flags, skip uninteresting
497a6d42e7dSPeter Dunlap 			 * interfaces based on flags
498a6d42e7dSPeter Dunlap 			 */
499a6d42e7dSPeter Dunlap 			if ((lp->lifr_flags & IFF_UP) != IFF_UP)
500a6d42e7dSPeter Dunlap 				continue;
501a6d42e7dSPeter Dunlap 			if (lp->lifr_flags &
502a6d42e7dSPeter Dunlap 			    (IFF_ANYCAST|IFF_NOLOCAL|IFF_DEPRECATED))
503a6d42e7dSPeter Dunlap 				continue;
504a6d42e7dSPeter Dunlap 		}
505a6d42e7dSPeter Dunlap 
506a6d42e7dSPeter Dunlap 		/* save ip address */
507a6d42e7dSPeter Dunlap 		ip = &ipaddr->al_addrs[j];
508a6d42e7dSPeter Dunlap 		switch (ss.ss_family) {
509a6d42e7dSPeter Dunlap 		case AF_INET:
510a6d42e7dSPeter Dunlap 			sin = (struct sockaddr_in *)&ss;
511a6d42e7dSPeter Dunlap 			if (!idm_v4_addr_okay(&sin->sin_addr))
512a6d42e7dSPeter Dunlap 				continue;
513a6d42e7dSPeter Dunlap 			ip->a_addr.i_addr.in4 = sin->sin_addr;
514a6d42e7dSPeter Dunlap 			ip->a_addr.i_insize = sizeof (struct in_addr);
515a6d42e7dSPeter Dunlap 			break;
516a6d42e7dSPeter Dunlap 		case AF_INET6:
517a6d42e7dSPeter Dunlap 			sin6 = (struct sockaddr_in6 *)&ss;
518a6d42e7dSPeter Dunlap 			if (!idm_v6_addr_okay(&sin6->sin6_addr))
519a6d42e7dSPeter Dunlap 				continue;
520a6d42e7dSPeter Dunlap 			ip->a_addr.i_addr.in6 = sin6->sin6_addr;
521a6d42e7dSPeter Dunlap 			ip->a_addr.i_insize = sizeof (struct in6_addr);
522a6d42e7dSPeter Dunlap 			break;
523a6d42e7dSPeter Dunlap 		default:
524a6d42e7dSPeter Dunlap 			continue;
525a6d42e7dSPeter Dunlap 		}
526a6d42e7dSPeter Dunlap 		j++;
527a6d42e7dSPeter Dunlap 	}
528a6d42e7dSPeter Dunlap 
529a6d42e7dSPeter Dunlap 	if (j == 0) {
530a6d42e7dSPeter Dunlap 		/* no valid ifaddr */
531a6d42e7dSPeter Dunlap 		kmem_free(ipaddr, size_ipaddr);
532a6d42e7dSPeter Dunlap 		size_ipaddr = 0;
533a6d42e7dSPeter Dunlap 		ipaddr = NULL;
534a6d42e7dSPeter Dunlap 	} else {
535a6d42e7dSPeter Dunlap 		ipaddr->al_out_cnt = j;
536a6d42e7dSPeter Dunlap 	}
537a6d42e7dSPeter Dunlap 
538a6d42e7dSPeter Dunlap 
539a6d42e7dSPeter Dunlap cleanup:
540a6d42e7dSPeter Dunlap 	idm_sodestroy(so6);
541a6d42e7dSPeter Dunlap 	idm_sodestroy(so4);
542a6d42e7dSPeter Dunlap 
543a6d42e7dSPeter Dunlap 	if (buf != NULL)
544a6d42e7dSPeter Dunlap 		kmem_free(buf, bufsize);
545a6d42e7dSPeter Dunlap 
546a6d42e7dSPeter Dunlap 	*ipaddr_p = ipaddr;
547a6d42e7dSPeter Dunlap 	return (size_ipaddr);
548a6d42e7dSPeter Dunlap }
549a6d42e7dSPeter Dunlap 
550a6d42e7dSPeter Dunlap int
idm_sorecv(ksocket_t so,void * msg,size_t len)5510f1702c5SYu Xiangning idm_sorecv(ksocket_t so, void *msg, size_t len)
552a6d42e7dSPeter Dunlap {
553a6d42e7dSPeter Dunlap 	iovec_t iov;
554a6d42e7dSPeter Dunlap 
555a6d42e7dSPeter Dunlap 	ASSERT(so != NULL);
556a6d42e7dSPeter Dunlap 	ASSERT(len != 0);
557a6d42e7dSPeter Dunlap 
558a6d42e7dSPeter Dunlap 	/*
559a6d42e7dSPeter Dunlap 	 * Fill in iovec and receive data
560a6d42e7dSPeter Dunlap 	 */
561a6d42e7dSPeter Dunlap 	iov.iov_base = msg;
562a6d42e7dSPeter Dunlap 	iov.iov_len = len;
563a6d42e7dSPeter Dunlap 
564a6d42e7dSPeter Dunlap 	return (idm_iov_sorecv(so, &iov, 1, len));
565a6d42e7dSPeter Dunlap }
566a6d42e7dSPeter Dunlap 
567a6d42e7dSPeter Dunlap /*
568a6d42e7dSPeter Dunlap  * idm_sosendto - Sends a buffered data on a non-connected socket.
569a6d42e7dSPeter Dunlap  *
570a6d42e7dSPeter Dunlap  * This function puts the data provided on the wire by calling sosendmsg.
571a6d42e7dSPeter Dunlap  * It will return only when all the data has been sent or if an error
572a6d42e7dSPeter Dunlap  * occurs.
573a6d42e7dSPeter Dunlap  *
574a6d42e7dSPeter Dunlap  * Returns 0 for success, the socket errno value if sosendmsg fails, and
575a6d42e7dSPeter Dunlap  * -1 if sosendmsg returns success but uio_resid != 0
576a6d42e7dSPeter Dunlap  */
577a6d42e7dSPeter Dunlap int
idm_sosendto(ksocket_t so,void * buff,size_t len,struct sockaddr * name,socklen_t namelen)5780f1702c5SYu Xiangning idm_sosendto(ksocket_t so, void *buff, size_t len,
579a6d42e7dSPeter Dunlap     struct sockaddr *name, socklen_t namelen)
580a6d42e7dSPeter Dunlap {
581a6d42e7dSPeter Dunlap 	struct msghdr		msg;
582a6d42e7dSPeter Dunlap 	struct iovec		iov[1];
583a6d42e7dSPeter Dunlap 	int			error;
5840f1702c5SYu Xiangning 	size_t			sent = 0;
585a6d42e7dSPeter Dunlap 
586a6d42e7dSPeter Dunlap 	iov[0].iov_base	= buff;
587a6d42e7dSPeter Dunlap 	iov[0].iov_len	= len;
588a6d42e7dSPeter Dunlap 
589a6d42e7dSPeter Dunlap 	/* Initialization of the message header. */
590a6d42e7dSPeter Dunlap 	bzero(&msg, sizeof (msg));
591a6d42e7dSPeter Dunlap 	msg.msg_iov	= iov;
592a6d42e7dSPeter Dunlap 	msg.msg_iovlen	= 1;
593a6d42e7dSPeter Dunlap 	msg.msg_name	= name;
594a6d42e7dSPeter Dunlap 	msg.msg_namelen	= namelen;
595a6d42e7dSPeter Dunlap 
5960f1702c5SYu Xiangning 	if ((error = ksocket_sendmsg(so, &msg, 0, &sent, CRED())) == 0) {
597a6d42e7dSPeter Dunlap 		/* Data sent */
5980f1702c5SYu Xiangning 		if (sent == len) {
599a6d42e7dSPeter Dunlap 			/* All data sent.  Success. */
600a6d42e7dSPeter Dunlap 			return (0);
601a6d42e7dSPeter Dunlap 		} else {
602a6d42e7dSPeter Dunlap 			/* Not all data was sent.  Failure */
603a6d42e7dSPeter Dunlap 			return (-1);
604a6d42e7dSPeter Dunlap 		}
605a6d42e7dSPeter Dunlap 	}
606a6d42e7dSPeter Dunlap 
607a6d42e7dSPeter Dunlap 	/* Send failed */
608a6d42e7dSPeter Dunlap 	return (error);
609a6d42e7dSPeter Dunlap }
610a6d42e7dSPeter Dunlap 
611a6d42e7dSPeter Dunlap /*
612a6d42e7dSPeter Dunlap  * idm_iov_sosend - Sends an iovec on a connection.
613a6d42e7dSPeter Dunlap  *
614a6d42e7dSPeter Dunlap  * This function puts the data provided on the wire by calling sosendmsg.
615a6d42e7dSPeter Dunlap  * It will return only when all the data has been sent or if an error
616a6d42e7dSPeter Dunlap  * occurs.
617a6d42e7dSPeter Dunlap  *
618a6d42e7dSPeter Dunlap  * Returns 0 for success, the socket errno value if sosendmsg fails, and
619a6d42e7dSPeter Dunlap  * -1 if sosendmsg returns success but uio_resid != 0
620a6d42e7dSPeter Dunlap  */
621a6d42e7dSPeter Dunlap int
idm_iov_sosend(ksocket_t so,iovec_t * iop,int iovlen,size_t total_len)6220f1702c5SYu Xiangning idm_iov_sosend(ksocket_t so, iovec_t *iop, int iovlen, size_t total_len)
623a6d42e7dSPeter Dunlap {
624a6d42e7dSPeter Dunlap 	struct msghdr		msg;
625a6d42e7dSPeter Dunlap 	int			error;
6268e718be9SToomas Soome 	size_t			sent = 0;
627a6d42e7dSPeter Dunlap 
628a6d42e7dSPeter Dunlap 	ASSERT(iop != NULL);
629a6d42e7dSPeter Dunlap 
630a6d42e7dSPeter Dunlap 	/* Initialization of the message header. */
631a6d42e7dSPeter Dunlap 	bzero(&msg, sizeof (msg));
632a6d42e7dSPeter Dunlap 	msg.msg_iov	= iop;
633a6d42e7dSPeter Dunlap 	msg.msg_iovlen	= iovlen;
634a6d42e7dSPeter Dunlap 
6350f1702c5SYu Xiangning 	if ((error = ksocket_sendmsg(so, &msg, 0, &sent, CRED()))
6360f1702c5SYu Xiangning 	    == 0) {
637a6d42e7dSPeter Dunlap 		/* Data sent */
6380f1702c5SYu Xiangning 		if (sent == total_len) {
639a6d42e7dSPeter Dunlap 			/* All data sent.  Success. */
640a6d42e7dSPeter Dunlap 			return (0);
641a6d42e7dSPeter Dunlap 		} else {
642a6d42e7dSPeter Dunlap 			/* Not all data was sent.  Failure */
643a6d42e7dSPeter Dunlap 			return (-1);
644a6d42e7dSPeter Dunlap 		}
645a6d42e7dSPeter Dunlap 	}
646a6d42e7dSPeter Dunlap 
647a6d42e7dSPeter Dunlap 	/* Send failed */
648a6d42e7dSPeter Dunlap 	return (error);
649a6d42e7dSPeter Dunlap }
650a6d42e7dSPeter Dunlap 
651a6d42e7dSPeter Dunlap /*
652a6d42e7dSPeter Dunlap  * idm_iov_sorecv - Receives an iovec from a connection
653a6d42e7dSPeter Dunlap  *
654a6d42e7dSPeter Dunlap  * This function gets the data asked for from the socket.  It will return
655a6d42e7dSPeter Dunlap  * only when all the requested data has been retrieved or if an error
656a6d42e7dSPeter Dunlap  * occurs.
657a6d42e7dSPeter Dunlap  *
658a6d42e7dSPeter Dunlap  * Returns 0 for success, the socket errno value if sorecvmsg fails, and
659a6d42e7dSPeter Dunlap  * -1 if sorecvmsg returns success but uio_resid != 0
660a6d42e7dSPeter Dunlap  */
661a6d42e7dSPeter Dunlap int
idm_iov_sorecv(ksocket_t so,iovec_t * iop,int iovlen,size_t total_len)6620f1702c5SYu Xiangning idm_iov_sorecv(ksocket_t so, iovec_t *iop, int iovlen, size_t total_len)
663a6d42e7dSPeter Dunlap {
664a6d42e7dSPeter Dunlap 	struct msghdr		msg;
665a6d42e7dSPeter Dunlap 	int			error;
6660f1702c5SYu Xiangning 	size_t			recv;
6678e718be9SToomas Soome 	int			flags;
668a6d42e7dSPeter Dunlap 
669a6d42e7dSPeter Dunlap 	ASSERT(iop != NULL);
670a6d42e7dSPeter Dunlap 
671a6d42e7dSPeter Dunlap 	/* Initialization of the message header. */
672a6d42e7dSPeter Dunlap 	bzero(&msg, sizeof (msg));
673a6d42e7dSPeter Dunlap 	msg.msg_iov	= iop;
674a6d42e7dSPeter Dunlap 	msg.msg_iovlen	= iovlen;
6750f1702c5SYu Xiangning 	flags		= MSG_WAITALL;
676a6d42e7dSPeter Dunlap 
6770f1702c5SYu Xiangning 	if ((error = ksocket_recvmsg(so, &msg, flags, &recv, CRED()))
6780f1702c5SYu Xiangning 	    == 0) {
679a6d42e7dSPeter Dunlap 		/* Received data */
6800f1702c5SYu Xiangning 		if (recv == total_len) {
681a6d42e7dSPeter Dunlap 			/* All requested data received.  Success */
682a6d42e7dSPeter Dunlap 			return (0);
683a6d42e7dSPeter Dunlap 		} else {
684a6d42e7dSPeter Dunlap 			/*
685a6d42e7dSPeter Dunlap 			 * Not all data was received.  The connection has
686a6d42e7dSPeter Dunlap 			 * probably failed.
687a6d42e7dSPeter Dunlap 			 */
688a6d42e7dSPeter Dunlap 			return (-1);
689a6d42e7dSPeter Dunlap 		}
690a6d42e7dSPeter Dunlap 	}
691a6d42e7dSPeter Dunlap 
692a6d42e7dSPeter Dunlap 	/* Receive failed */
693a6d42e7dSPeter Dunlap 	return (error);
694a6d42e7dSPeter Dunlap }
695a6d42e7dSPeter Dunlap 
696a6d42e7dSPeter Dunlap static void
idm_set_ini_preconnect_options(idm_so_conn_t * sc,boolean_t boot_conn)697dedec472SJack Meng idm_set_ini_preconnect_options(idm_so_conn_t *sc, boolean_t boot_conn)
698a6d42e7dSPeter Dunlap {
699a6d42e7dSPeter Dunlap 	int	conn_abort = 10000;
700a6d42e7dSPeter Dunlap 	int	conn_notify = 2000;
701a6d42e7dSPeter Dunlap 	int	abort = 30000;
702a6d42e7dSPeter Dunlap 
703a6d42e7dSPeter Dunlap 	/* Pre-connect socket options */
7040f1702c5SYu Xiangning 	(void) ksocket_setsockopt(sc->ic_so, IPPROTO_TCP,
7050f1702c5SYu Xiangning 	    TCP_CONN_NOTIFY_THRESHOLD, (char *)&conn_notify, sizeof (int),
7060f1702c5SYu Xiangning 	    CRED());
707dedec472SJack Meng 	if (boot_conn == B_FALSE) {
708dedec472SJack Meng 		(void) ksocket_setsockopt(sc->ic_so, IPPROTO_TCP,
709dedec472SJack Meng 		    TCP_CONN_ABORT_THRESHOLD, (char *)&conn_abort, sizeof (int),
710dedec472SJack Meng 		    CRED());
711dedec472SJack Meng 		(void) ksocket_setsockopt(sc->ic_so, IPPROTO_TCP,
712dedec472SJack Meng 		    TCP_ABORT_THRESHOLD,
713dedec472SJack Meng 		    (char *)&abort, sizeof (int), CRED());
714dedec472SJack Meng 	}
715a6d42e7dSPeter Dunlap }
716a6d42e7dSPeter Dunlap 
717a6d42e7dSPeter Dunlap static void
idm_set_postconnect_options(ksocket_t ks)7180f94976eSJeff Biseda idm_set_postconnect_options(ksocket_t ks)
719a6d42e7dSPeter Dunlap {
720a6d42e7dSPeter Dunlap 	const int	on = 1;
721a6d42e7dSPeter Dunlap 
722a6d42e7dSPeter Dunlap 	/* Set connect options */
7230f1702c5SYu Xiangning 	(void) ksocket_setsockopt(ks, SOL_SOCKET, SO_RCVBUF,
724f99db78fSChristopher Siden 	    (char *)&idm_so_rcvbuf, sizeof (idm_so_rcvbuf), CRED());
7250f1702c5SYu Xiangning 	(void) ksocket_setsockopt(ks, SOL_SOCKET, SO_SNDBUF,
726f99db78fSChristopher Siden 	    (char *)&idm_so_sndbuf, sizeof (idm_so_sndbuf), CRED());
7270f1702c5SYu Xiangning 	(void) ksocket_setsockopt(ks, IPPROTO_TCP, TCP_NODELAY,
7280f1702c5SYu Xiangning 	    (char *)&on, sizeof (on), CRED());
729a6d42e7dSPeter Dunlap }
730a6d42e7dSPeter Dunlap 
731a6d42e7dSPeter Dunlap static uint32_t
n2h24(const uchar_t * ptr)732a6d42e7dSPeter Dunlap n2h24(const uchar_t *ptr)
733a6d42e7dSPeter Dunlap {
734a6d42e7dSPeter Dunlap 	return ((ptr[0] << 16) | (ptr[1] << 8) | ptr[2]);
735a6d42e7dSPeter Dunlap }
736a6d42e7dSPeter Dunlap 
7372727bb05STim Kordas static boolean_t
idm_dataseglenokay(idm_conn_t * ic,idm_pdu_t * pdu)7382727bb05STim Kordas idm_dataseglenokay(idm_conn_t *ic, idm_pdu_t *pdu)
7392727bb05STim Kordas {
7402727bb05STim Kordas 	iscsi_hdr_t	*bhs;
7412727bb05STim Kordas 
7422727bb05STim Kordas 	if (ic->ic_conn_type == CONN_TYPE_TGT &&
7432727bb05STim Kordas 	    pdu->isp_datalen > ic->ic_conn_params.max_recv_dataseglen) {
7442727bb05STim Kordas 		IDM_CONN_LOG(CE_WARN,
7452727bb05STim Kordas 		    "idm_dataseglenokay: exceeded the max data segment length");
7462727bb05STim Kordas 		return (B_FALSE);
7472727bb05STim Kordas 	}
7482727bb05STim Kordas 
7492727bb05STim Kordas 	bhs = pdu->isp_hdr;
7502727bb05STim Kordas 	/*
7512727bb05STim Kordas 	 * Filter out any RFC3720 data-size violations.
7522727bb05STim Kordas 	 */
7532727bb05STim Kordas 	switch (IDM_PDU_OPCODE(pdu)) {
7542727bb05STim Kordas 	case ISCSI_OP_SCSI_TASK_MGT_MSG:
7552727bb05STim Kordas 	case ISCSI_OP_SCSI_TASK_MGT_RSP:
7562727bb05STim Kordas 	case ISCSI_OP_RTT_RSP:
7572727bb05STim Kordas 	case ISCSI_OP_LOGOUT_CMD:
7582727bb05STim Kordas 		/*
7592727bb05STim Kordas 		 * Data-segment not allowed and additional headers not allowed.
7602727bb05STim Kordas 		 * (both must be zero according to the RFC3720.)
7612727bb05STim Kordas 		 */
7622727bb05STim Kordas 		if (bhs->hlength != 0 || pdu->isp_datalen != 0)
7632727bb05STim Kordas 			return (B_FALSE);
7642727bb05STim Kordas 		break;
7652727bb05STim Kordas 	case ISCSI_OP_NOOP_OUT:
7662727bb05STim Kordas 	case ISCSI_OP_LOGIN_CMD:
7672727bb05STim Kordas 	case ISCSI_OP_TEXT_CMD:
7682727bb05STim Kordas 	case ISCSI_OP_SNACK_CMD:
7692727bb05STim Kordas 	case ISCSI_OP_NOOP_IN:
7702727bb05STim Kordas 	case ISCSI_OP_SCSI_RSP:
7712727bb05STim Kordas 	case ISCSI_OP_LOGIN_RSP:
7722727bb05STim Kordas 	case ISCSI_OP_TEXT_RSP:
7732727bb05STim Kordas 	case ISCSI_OP_SCSI_DATA_RSP:
7742727bb05STim Kordas 	case ISCSI_OP_LOGOUT_RSP:
7752727bb05STim Kordas 	case ISCSI_OP_ASYNC_EVENT:
7762727bb05STim Kordas 	case ISCSI_OP_REJECT_MSG:
7772727bb05STim Kordas 		/*
7782727bb05STim Kordas 		 * Additional headers not allowed.
7792727bb05STim Kordas 		 * (must be zero according to RFC3720.)
7802727bb05STim Kordas 		 */
7812727bb05STim Kordas 		if (bhs->hlength)
7822727bb05STim Kordas 			return (B_FALSE);
7832727bb05STim Kordas 		break;
7842727bb05STim Kordas 	case ISCSI_OP_SCSI_CMD:
7852727bb05STim Kordas 		/*
7862727bb05STim Kordas 		 * See RFC3720, section 10.3
7872727bb05STim Kordas 		 *
7882727bb05STim Kordas 		 * For pure read cmds, data-segment-length must be zero.
7892727bb05STim Kordas 		 * For non-final transfers, data-size must be even number of
7902727bb05STim Kordas 		 * 4-byte words.
7912727bb05STim Kordas 		 * For any transfer, an expected byte count must be provided.
7922727bb05STim Kordas 		 * For bidirectional transfers, an additional-header must be
7932727bb05STim Kordas 		 * provided (for the read byte-count.)
7942727bb05STim Kordas 		 */
7952727bb05STim Kordas 		if (pdu->isp_datalen) {
7962727bb05STim Kordas 			if ((bhs->flags & (ISCSI_FLAG_CMD_READ |
7972727bb05STim Kordas 			    ISCSI_FLAG_CMD_WRITE)) == ISCSI_FLAG_CMD_READ)
7982727bb05STim Kordas 				return (B_FALSE);
7992727bb05STim Kordas 			if ((bhs->flags & ISCSI_FLAG_FINAL) == 0 &&
8002727bb05STim Kordas 			    ((pdu->isp_datalen & 0x3) != 0))
8012727bb05STim Kordas 				return (B_FALSE);
8022727bb05STim Kordas 		}
8032727bb05STim Kordas 		if (bhs->flags & (ISCSI_FLAG_CMD_READ |
8042727bb05STim Kordas 		    ISCSI_FLAG_CMD_WRITE)) {
8052727bb05STim Kordas 			iscsi_scsi_cmd_hdr_t *cmdhdr =
8062727bb05STim Kordas 			    (iscsi_scsi_cmd_hdr_t *)bhs;
8072727bb05STim Kordas 			/*
8082727bb05STim Kordas 			 * we're transfering some data, we must have a
8092727bb05STim Kordas 			 * byte count
8102727bb05STim Kordas 			 */
8112727bb05STim Kordas 			if (cmdhdr->data_length == 0)
8122727bb05STim Kordas 				return (B_FALSE);
8132727bb05STim Kordas 		}
8142727bb05STim Kordas 		break;
8152727bb05STim Kordas 	case ISCSI_OP_SCSI_DATA:
8162727bb05STim Kordas 		/*
8172727bb05STim Kordas 		 * See RFC3720, section 10.7
8182727bb05STim Kordas 		 *
8192727bb05STim Kordas 		 * Additional headers aren't allowed, and the data-size must
8202727bb05STim Kordas 		 * be an even number of 4-byte words (unless the final bit
8212727bb05STim Kordas 		 * is set.)