1*fcf3ce44SJohn Forte /*
2*fcf3ce44SJohn Forte  * CDDL HEADER START
3*fcf3ce44SJohn Forte  *
4*fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5*fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6*fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7*fcf3ce44SJohn Forte  *
8*fcf3ce44SJohn Forte  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*fcf3ce44SJohn Forte  * or http://www.opensolaris.org/os/licensing.
10*fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11*fcf3ce44SJohn Forte  * and limitations under the License.
12*fcf3ce44SJohn Forte  *
13*fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14*fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16*fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17*fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18*fcf3ce44SJohn Forte  *
19*fcf3ce44SJohn Forte  * CDDL HEADER END
20*fcf3ce44SJohn Forte  */
21*fcf3ce44SJohn Forte /*
22*fcf3ce44SJohn Forte  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*fcf3ce44SJohn Forte  * Use is subject to license terms.
24*fcf3ce44SJohn Forte  *
25*fcf3ce44SJohn Forte  * iSCSI Software Initiator
26*fcf3ce44SJohn Forte  */
27*fcf3ce44SJohn Forte 
28*fcf3ce44SJohn Forte #include <sys/socket.h>		/* networking stuff */
29*fcf3ce44SJohn Forte #include <sys/strsubr.h>	/* networking stuff */
30*fcf3ce44SJohn Forte #include <netinet/tcp.h>	/* TCP_NODELAY */
31*fcf3ce44SJohn Forte #include <sys/socketvar.h>	/* _ALLOC_SLEEP */
32*fcf3ce44SJohn Forte #include <sys/pathname.h>	/* declares:	lookupname */
33*fcf3ce44SJohn Forte #include <sys/fs/snode.h>	/* defines:	VTOS */
34*fcf3ce44SJohn Forte #include <sys/fs/dv_node.h>	/* declares:	devfs_lookupname */
35*fcf3ce44SJohn Forte #include <netinet/in.h>
36*fcf3ce44SJohn Forte #include "iscsi.h"
37*fcf3ce44SJohn Forte 
38*fcf3ce44SJohn Forte /*
39*fcf3ce44SJohn Forte  * This is a high level description of the default
40*fcf3ce44SJohn Forte  * iscsi_net transport interfaces.  These are used
41*fcf3ce44SJohn Forte  * to create, send, recv, and close standard TCP/IP
42*fcf3ce44SJohn Forte  * messages.  In addition there are extensions to send
43*fcf3ce44SJohn Forte  * and recv iSCSI PDU data.
44*fcf3ce44SJohn Forte  *
45*fcf3ce44SJohn Forte  * NOTE: It would be very easy for an iSCSI HBA vendor
46*fcf3ce44SJohn Forte  * to register their own functions over the top of
47*fcf3ce44SJohn Forte  * the default interfaces.  This would allow an iSCSI
48*fcf3ce44SJohn Forte  * HBA to use the same iscsiadm management interfaces
49*fcf3ce44SJohn Forte  * and the Solaris iSCSI session / connection management.
50*fcf3ce44SJohn Forte  * The current problem with this approach is we only
51*fcf3ce44SJohn Forte  * allow one one registered transport table.  This
52*fcf3ce44SJohn Forte  * would be pretty easy to correct although will require
53*fcf3ce44SJohn Forte  * additional CLI changes to manage multiple interfaces.
54*fcf3ce44SJohn Forte  * If a vendor can present compelling performance data,
55*fcf3ce44SJohn Forte  * then Sun will be willing to enhance this support for
56*fcf3ce44SJohn Forte  * multiple interface tables and better CLI management.
57*fcf3ce44SJohn Forte  *
58*fcf3ce44SJohn Forte  * The following listing describes the iscsi_net
59*fcf3ce44SJohn Forte  * entry points:
60*fcf3ce44SJohn Forte  *
61*fcf3ce44SJohn Forte  *   socket            - Creates TCP/IP socket connection.  In the
62*fcf3ce44SJohn Forte  *                       default implementation creates a sonode
63*fcf3ce44SJohn Forte  *                       via the sockfs kernel layer.
64*fcf3ce44SJohn Forte  *   bind              - Performs standard TCP/IP BSD operation.  In
65*fcf3ce44SJohn Forte  *                       the default implementation this only act
66*fcf3ce44SJohn Forte  *                       as a soft binding based on the IP and routing
67*fcf3ce44SJohn Forte  *	                 tables.  It would be preferred if this was
68*fcf3ce44SJohn Forte  *	                 a hard binding but that is currently not
69*fcf3ce44SJohn Forte  *	                 possible with Solaris's networking stack.
70*fcf3ce44SJohn Forte  *   connect           - Performs standard TCP/IP BSD operation.  This
71*fcf3ce44SJohn Forte  *                       establishes the TCP SYN to the peer IP address.
72*fcf3ce44SJohn Forte  *   listen            - Performs standard TCP/IP BSD operation.  This
73*fcf3ce44SJohn Forte  *                       listens for incoming peer connections.
74*fcf3ce44SJohn Forte  *   accept            - Performs standard TCP/IP BSD operation.  This
75*fcf3ce44SJohn Forte  *                       accepts incoming peer connections.
76*fcf3ce44SJohn Forte  *   shutdown          - This disconnects the TCP/IP connection while
77*fcf3ce44SJohn Forte  *                       maintaining the resources.
78*fcf3ce44SJohn Forte  *   close             - This disconnects the TCP/IP connection and
79*fcf3ce44SJohn Forte  *                       releases the resources.
80*fcf3ce44SJohn Forte  *
81*fcf3ce44SJohn Forte  *   getsockopt        - Gets socket option for specified socket.
82*fcf3ce44SJohn Forte  *   setsockopt        - Sets socket option for specified socket.
83*fcf3ce44SJohn Forte  *
84*fcf3ce44SJohn Forte  *      The current socket options that are used by the initiator
85*fcf3ce44SJohn Forte  *      are listed below.
86*fcf3ce44SJohn Forte  *
87*fcf3ce44SJohn Forte  *        TCP_CONN_NOTIFY_THRESHOLD
88*fcf3ce44SJohn Forte  *        TCP_CONN_ABORT_THRESHOLD
89*fcf3ce44SJohn Forte  *        TCP_ABORT_THRESHOLD
90*fcf3ce44SJohn Forte  *        TCP_NODELAY
91*fcf3ce44SJohn Forte  *        SO_RCVBUF
92*fcf3ce44SJohn Forte  *        SO_SNDBUF
93*fcf3ce44SJohn Forte  *
94*fcf3ce44SJohn Forte  *   iscsi_net_poll    - Poll socket interface for a specified amount
95*fcf3ce44SJohn Forte  *                       of data.  If data not received in timeout
96*fcf3ce44SJohn Forte  *                       period fail request.
97*fcf3ce44SJohn Forte  *   iscsi_net_sendmsg - Send message on socket connection
98*fcf3ce44SJohn Forte  *   iscsi_net_recvmsg - Receive message on socket connection
99*fcf3ce44SJohn Forte  *
100*fcf3ce44SJohn Forte  *   iscsi_net_sendpdu - Send iSCSI PDU on socket connection
101*fcf3ce44SJohn Forte  *   iscsi_net_recvhdr - Receive iSCSI header on socket connection
102*fcf3ce44SJohn Forte  *   iscsi_net_recvdata - Receive iSCSI data on socket connection
103*fcf3ce44SJohn Forte  *
104*fcf3ce44SJohn Forte  *     The iSCSI interfaces have the below optional flags.
105*fcf3ce44SJohn Forte  *
106*fcf3ce44SJohn Forte  *       ISCSI_NET_HEADER_DIGEST - The interface should either
107*fcf3ce44SJohn Forte  *				generate or validate the iSCSI
108*fcf3ce44SJohn Forte  *				header digest CRC.
109*fcf3ce44SJohn Forte  *       ISCSI_NET_DATA_DIGESt   - The interface should either
110*fcf3ce44SJohn Forte  *                              generate or validate the iSCSI
111*fcf3ce44SJohn Forte  *                              data digest CRC.
112*fcf3ce44SJohn Forte  */
113*fcf3ce44SJohn Forte 
114*fcf3ce44SJohn Forte 
115*fcf3ce44SJohn Forte /* global */
116*fcf3ce44SJohn Forte iscsi_network_t *iscsi_net;
117*fcf3ce44SJohn Forte 
118*fcf3ce44SJohn Forte /* consts */
119*fcf3ce44SJohn Forte 
120*fcf3ce44SJohn Forte /*
121*fcf3ce44SJohn Forte  * This table is used for quick validation of incoming
122*fcf3ce44SJohn Forte  * iSCSI PDU opcodes.  A value of '0' in the table below
123*fcf3ce44SJohn Forte  * indicated that the opcode is invalid for an iSCSI
124*fcf3ce44SJohn Forte  * initiator to receive.
125*fcf3ce44SJohn Forte  */
126*fcf3ce44SJohn Forte const int   is_incoming_opcode_invalid[256] = {
127*fcf3ce44SJohn Forte 	/*		0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F */
128*fcf3ce44SJohn Forte 	/* 0x0X */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
129*fcf3ce44SJohn Forte 	/* 0x1X */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
130*fcf3ce44SJohn Forte 	/* 0x2X */	0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
131*fcf3ce44SJohn Forte 	/* 0x3X */	1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
132*fcf3ce44SJohn Forte 	/* 0x4X */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
133*fcf3ce44SJohn Forte 	/* 0x5X */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
134*fcf3ce44SJohn Forte 	/* 0x6X */	0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
135*fcf3ce44SJohn Forte 	/* 0x7X */	1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
136*fcf3ce44SJohn Forte 	/* 0x8X */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
137*fcf3ce44SJohn Forte 	/* 0x9X */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
138*fcf3ce44SJohn Forte 	/* 0xAX */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
139*fcf3ce44SJohn Forte 	/* 0xBX */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
140*fcf3ce44SJohn Forte 	/* 0xCX */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
141*fcf3ce44SJohn Forte 	/* 0xDX */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
142*fcf3ce44SJohn Forte 	/* 0xEX */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
143*fcf3ce44SJohn Forte 	/* 0xFX */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
144*fcf3ce44SJohn Forte };
145*fcf3ce44SJohn Forte 
146*fcf3ce44SJohn Forte /* prototypes */
147*fcf3ce44SJohn Forte static void * iscsi_net_socket(int domain, int type, int protocol);
148*fcf3ce44SJohn Forte static int iscsi_net_bind(void *socket, struct sockaddr *
149*fcf3ce44SJohn Forte     name, int name_len, int backlog, int flags);
150*fcf3ce44SJohn Forte static int iscsi_net_connect(void *socket, struct sockaddr *
151*fcf3ce44SJohn Forte     name, int name_len, int fflag, int flags);
152*fcf3ce44SJohn Forte static int iscsi_net_listen(void *socket, int backlog);
153*fcf3ce44SJohn Forte static void * iscsi_net_accept(void *socket, struct sockaddr *addr,
154*fcf3ce44SJohn Forte     int *addr_len);
155*fcf3ce44SJohn Forte static int iscsi_net_getsockname(void *socket);
156*fcf3ce44SJohn Forte static int iscsi_net_getsockopt(void *socket, int level,
157*fcf3ce44SJohn Forte     int option_name, void *option_val, int *option_len, int flags);
158*fcf3ce44SJohn Forte static int iscsi_net_setsockopt(void *socket, int level,
159*fcf3ce44SJohn Forte     int option_name, void *option_val, int option_len);
160*fcf3ce44SJohn Forte static int iscsi_net_shutdown(void *socket, int how);
161*fcf3ce44SJohn Forte static void iscsi_net_close(void *socket);
162*fcf3ce44SJohn Forte 
163*fcf3ce44SJohn Forte static size_t iscsi_net_poll(void *socket, clock_t timeout);
164*fcf3ce44SJohn Forte static size_t iscsi_net_sendmsg(void *socket, struct msghdr *msg);
165*fcf3ce44SJohn Forte static size_t iscsi_net_recvmsg(void *socket,
166*fcf3ce44SJohn Forte     struct msghdr *msg, int timeout);
167*fcf3ce44SJohn Forte 
168*fcf3ce44SJohn Forte static iscsi_status_t iscsi_net_sendpdu(void *socket, iscsi_hdr_t *ihp,
169*fcf3ce44SJohn Forte     char *data, int flags);
170*fcf3ce44SJohn Forte static iscsi_status_t iscsi_net_recvdata(void *socket, iscsi_hdr_t *ihp,
171*fcf3ce44SJohn Forte     char *data, int max_data_length, int timeout, int flags);
172*fcf3ce44SJohn Forte static iscsi_status_t iscsi_net_recvhdr(void *socket, iscsi_hdr_t *ihp,
173*fcf3ce44SJohn Forte     int header_length, int timeout, int flags);
174*fcf3ce44SJohn Forte 
175*fcf3ce44SJohn Forte static void iscsi_net_set_preconnect_options(void *socket);
176*fcf3ce44SJohn Forte static void iscsi_net_set_postconnect_options(void *socket);
177*fcf3ce44SJohn Forte 
178*fcf3ce44SJohn Forte /*
179*fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
180*fcf3ce44SJohn Forte  * | network interface registration functions                           |
181*fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
182*fcf3ce44SJohn Forte  */
183*fcf3ce44SJohn Forte 
184*fcf3ce44SJohn Forte /*
185*fcf3ce44SJohn Forte  * iscsi_net_init - initialize network interface
186*fcf3ce44SJohn Forte  */
187*fcf3ce44SJohn Forte void
188*fcf3ce44SJohn Forte iscsi_net_init()
189*fcf3ce44SJohn Forte {
190*fcf3ce44SJohn Forte 	iscsi_net = kmem_zalloc(sizeof (*iscsi_net), KM_SLEEP);
191*fcf3ce44SJohn Forte 
192*fcf3ce44SJohn Forte 	iscsi_net->socket	= iscsi_net_socket;
193*fcf3ce44SJohn Forte 
194*fcf3ce44SJohn Forte 	iscsi_net->bind		= iscsi_net_bind;
195*fcf3ce44SJohn Forte 	iscsi_net->connect	= iscsi_net_connect;
196*fcf3ce44SJohn Forte 	iscsi_net->listen	= iscsi_net_listen;
197*fcf3ce44SJohn Forte 	iscsi_net->accept	= iscsi_net_accept;
198*fcf3ce44SJohn Forte 	iscsi_net->shutdown	= iscsi_net_shutdown;
199*fcf3ce44SJohn Forte 	iscsi_net->close	= iscsi_net_close;
200*fcf3ce44SJohn Forte 
201*fcf3ce44SJohn Forte 	iscsi_net->getsockname	= iscsi_net_getsockname;
202*fcf3ce44SJohn Forte 	iscsi_net->getsockopt	= iscsi_net_getsockopt;
203*fcf3ce44SJohn Forte 	iscsi_net->setsockopt	= iscsi_net_setsockopt;
204*fcf3ce44SJohn Forte 
205*fcf3ce44SJohn Forte 	iscsi_net->poll		= iscsi_net_poll;
206*fcf3ce44SJohn Forte 	iscsi_net->sendmsg	= iscsi_net_sendmsg;
207*fcf3ce44SJohn Forte 	iscsi_net->recvmsg	= iscsi_net_recvmsg;
208*fcf3ce44SJohn Forte 
209*fcf3ce44SJohn Forte 	iscsi_net->sendpdu	= iscsi_net_sendpdu;
210*fcf3ce44SJohn Forte 	iscsi_net->recvhdr	= iscsi_net_recvhdr;
211*fcf3ce44SJohn Forte 	iscsi_net->recvdata	= iscsi_net_recvdata;
212*fcf3ce44SJohn Forte }
213*fcf3ce44SJohn Forte 
214*fcf3ce44SJohn Forte /*
215*fcf3ce44SJohn Forte  * iscsi_net_fini - release network interface
216*fcf3ce44SJohn Forte  */
217*fcf3ce44SJohn Forte void
218*fcf3ce44SJohn Forte iscsi_net_fini()
219*fcf3ce44SJohn Forte {
220*fcf3ce44SJohn Forte 	kmem_free(iscsi_net, sizeof (*iscsi_net));
221*fcf3ce44SJohn Forte 	iscsi_net = NULL;
222*fcf3ce44SJohn Forte }
223*fcf3ce44SJohn Forte 
224*fcf3ce44SJohn Forte 
225*fcf3ce44SJohn Forte /*
226*fcf3ce44SJohn Forte  * iscsi_net_set_preconnect_options -
227*fcf3ce44SJohn Forte  */
228*fcf3ce44SJohn Forte static void
229*fcf3ce44SJohn Forte iscsi_net_set_preconnect_options(void *socket)
230*fcf3ce44SJohn Forte {
231*fcf3ce44SJohn Forte 	int ret = 0;
232*fcf3ce44SJohn Forte 	ret += iscsi_net->setsockopt(socket, IPPROTO_TCP,
233*fcf3ce44SJohn Forte 	    TCP_CONN_NOTIFY_THRESHOLD, (char *)&iscsi_net->tweaks.
234*fcf3ce44SJohn Forte 	    conn_notify_threshold, sizeof (int));
235*fcf3ce44SJohn Forte 	ret += iscsi_net->setsockopt(socket, IPPROTO_TCP,
236*fcf3ce44SJohn Forte 	    TCP_CONN_ABORT_THRESHOLD, (char *)&iscsi_net->tweaks.
237*fcf3ce44SJohn Forte 	    conn_abort_threshold, sizeof (int));
238*fcf3ce44SJohn Forte 	ret += iscsi_net->setsockopt(socket, IPPROTO_TCP, TCP_ABORT_THRESHOLD,
239*fcf3ce44SJohn Forte 	    (char *)&iscsi_net->tweaks.abort_threshold, sizeof (int));
240*fcf3ce44SJohn Forte 	if (ret != 0) {
241*fcf3ce44SJohn Forte 		cmn_err(CE_NOTE, "iscsi connection failed to set socket option"
242*fcf3ce44SJohn Forte 		    "TCP_CONN_NOTIFY_THRESHOLD, TCP_CONN_ABORT_THRESHOLD or "
243*fcf3ce44SJohn Forte 		    "TCP_ABORT_THRESHOLD");
244*fcf3ce44SJohn Forte 	}
245*fcf3ce44SJohn Forte }
246*fcf3ce44SJohn Forte 
247*fcf3ce44SJohn Forte /*
248*fcf3ce44SJohn Forte  * iscsi_net_set_postconnect_options -
249*fcf3ce44SJohn Forte  */
250*fcf3ce44SJohn Forte static void
251*fcf3ce44SJohn Forte iscsi_net_set_postconnect_options(void *socket)
252*fcf3ce44SJohn Forte {
253*fcf3ce44SJohn Forte 	int ret = 0;
254*fcf3ce44SJohn Forte 	ret += iscsi_net->setsockopt(socket, IPPROTO_TCP, TCP_NODELAY,
255*fcf3ce44SJohn Forte 	    (char *)&iscsi_net->tweaks.nodelay, sizeof (int));
256*fcf3ce44SJohn Forte 	ret += iscsi_net->setsockopt(socket, SOL_SOCKET, SO_RCVBUF,
257*fcf3ce44SJohn Forte 	    (char *)&iscsi_net->tweaks.rcvbuf, sizeof (int));
258*fcf3ce44SJohn Forte 	ret += iscsi_net->setsockopt(socket, SOL_SOCKET, SO_SNDBUF,
259*fcf3ce44SJohn Forte 	    (char *)&iscsi_net->tweaks.sndbuf, sizeof (int));
260*fcf3ce44SJohn Forte 	if (ret != 0) {
261*fcf3ce44SJohn Forte 		cmn_err(CE_NOTE, "iscsi connection failed to set socket option"
262*fcf3ce44SJohn Forte 		    "TCP_NODELAY, SO_RCVBUF or SO_SNDBUF");
263*fcf3ce44SJohn Forte 	}
264*fcf3ce44SJohn Forte }
265*fcf3ce44SJohn Forte 
266*fcf3ce44SJohn Forte 
267*fcf3ce44SJohn Forte /*
268*fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
269*fcf3ce44SJohn Forte  * | register network interfaces                                        |
270*fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
271*fcf3ce44SJohn Forte  */
272*fcf3ce44SJohn Forte 
273*fcf3ce44SJohn Forte /*
274*fcf3ce44SJohn Forte  * iscsi_net_socket - create socket
275*fcf3ce44SJohn Forte  */
276*fcf3ce44SJohn Forte static void *
277*fcf3ce44SJohn Forte iscsi_net_socket(int domain, int type, int protocol)
278*fcf3ce44SJohn Forte {
279*fcf3ce44SJohn Forte 	vnode_t		*dvp		= NULL,
280*fcf3ce44SJohn Forte 	    *vp		= NULL;
281*fcf3ce44SJohn Forte 	struct snode	*csp		= NULL;
282*fcf3ce44SJohn Forte 	int		err		= 0;
283*fcf3ce44SJohn Forte 	major_t		maj;
284*fcf3ce44SJohn Forte 
285*fcf3ce44SJohn Forte 	/* ---- solookup: start ---- */
286*fcf3ce44SJohn Forte 	if ((vp = solookup(domain, type, protocol, NULL, &err)) == NULL) {
287*fcf3ce44SJohn Forte 
288*fcf3ce44SJohn Forte 		/*
289*fcf3ce44SJohn Forte 		 * solookup calls sogetvp if the vp is not found in
290*fcf3ce44SJohn Forte 		 * the cache.  Since the call to sogetvp is hardwired
291*fcf3ce44SJohn Forte 		 * to use USERSPACE and declared static we'll do the
292*fcf3ce44SJohn Forte 		 * work here instead.
293*fcf3ce44SJohn Forte 		 */
294*fcf3ce44SJohn Forte 		err = lookupname(type == SOCK_STREAM ? "/dev/tcp" : "/dev/udp",
295*fcf3ce44SJohn Forte 		    UIO_SYSSPACE, FOLLOW, NULLVPP, &vp);
296*fcf3ce44SJohn Forte 		if (err)
297*fcf3ce44SJohn Forte 			return (NULL);
298*fcf3ce44SJohn Forte 
299*fcf3ce44SJohn Forte 		/* ---- check that it is the correct vnode ---- */
300*fcf3ce44SJohn Forte 		if (vp->v_type != VCHR) {
301*fcf3ce44SJohn Forte 			VN_RELE(vp);
302*fcf3ce44SJohn Forte 			return (NULL);
303*fcf3ce44SJohn Forte 		}
304*fcf3ce44SJohn Forte 
305*fcf3ce44SJohn Forte 		csp = VTOS(VTOS(vp)->s_commonvp);
306*fcf3ce44SJohn Forte 		if (!(csp->s_flag & SDIPSET)) {
307*fcf3ce44SJohn Forte 			char    *pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
308*fcf3ce44SJohn Forte 			err = ddi_dev_pathname(vp->v_rdev, S_IFCHR,
309*fcf3ce44SJohn Forte 			    pathname);
310*fcf3ce44SJohn Forte 			if (err == 0) {
311*fcf3ce44SJohn Forte 				err = devfs_lookupname(pathname, NULLVPP,
312*fcf3ce44SJohn Forte 				    &dvp);
313*fcf3ce44SJohn Forte 			}
314*fcf3ce44SJohn Forte 			VN_RELE(vp);
315*fcf3ce44SJohn Forte 			kmem_free(pathname, MAXPATHLEN);
316*fcf3ce44SJohn Forte 			if (err != 0) {
317*fcf3ce44SJohn Forte 				return (NULL);
318*fcf3ce44SJohn Forte 			}
319*fcf3ce44SJohn Forte 			vp = dvp;
320*fcf3ce44SJohn Forte 		}
321*fcf3ce44SJohn Forte 
322*fcf3ce44SJohn Forte 		maj = getmajor(vp->v_rdev);
323*fcf3ce44SJohn Forte 		if (!STREAMSTAB(maj)) {
324*fcf3ce44SJohn Forte 			VN_RELE(vp);
325*fcf3ce44SJohn Forte 			return (NULL);
326*fcf3ce44SJohn Forte 		}
327*fcf3ce44SJohn Forte 	}
328*fcf3ce44SJohn Forte 	/* ---- solookup: end ---- */
329*fcf3ce44SJohn Forte 	return (socreate(vp, domain, type, protocol, SOV_DEFAULT, NULL, &err));
330*fcf3ce44SJohn Forte }
331*fcf3ce44SJohn Forte 
332*fcf3ce44SJohn Forte /*
333*fcf3ce44SJohn Forte  * iscsi_net_bind - bind socket to a specific sockaddr
334*fcf3ce44SJohn Forte  */
335*fcf3ce44SJohn Forte static int
336*fcf3ce44SJohn Forte iscsi_net_bind(void *socket, struct sockaddr *name, int name_len,
337*fcf3ce44SJohn Forte 	int backlog, int flags)
338*fcf3ce44SJohn Forte {
339*fcf3ce44SJohn Forte 	return (sobind((struct sonode *)socket, name, name_len,
340*fcf3ce44SJohn Forte 	    backlog, flags));
341*fcf3ce44SJohn Forte }
342*fcf3ce44SJohn Forte 
343*fcf3ce44SJohn Forte /*
344*fcf3ce44SJohn Forte  * iscsi_net_connect - connect socket to peer sockaddr
345*fcf3ce44SJohn Forte  */
346*fcf3ce44SJohn Forte static int
347*fcf3ce44SJohn Forte iscsi_net_connect(void *socket, struct sockaddr *name, int name_len,
348*fcf3ce44SJohn Forte 	int fflag, int flags)
349*fcf3ce44SJohn Forte {
350*fcf3ce44SJohn Forte 	int rval;
351*fcf3ce44SJohn Forte 
352*fcf3ce44SJohn Forte 	iscsi_net_set_preconnect_options(socket);
353*fcf3ce44SJohn Forte 	rval = soconnect((struct sonode *)socket, name,
354*fcf3ce44SJohn Forte 	    name_len, fflag, flags);
355*fcf3ce44SJohn Forte 	iscsi_net_set_postconnect_options(socket);
356*fcf3ce44SJohn Forte 
357*fcf3ce44SJohn Forte 	return (rval);
358*fcf3ce44SJohn Forte }
359*fcf3ce44SJohn Forte 
360*fcf3ce44SJohn Forte /*
361*fcf3ce44SJohn Forte  * iscsi_net_listen - listen to socket for peer connections
362*fcf3ce44SJohn Forte  */
363*fcf3ce44SJohn Forte static int
364*fcf3ce44SJohn Forte iscsi_net_listen(void *socket, int backlog)
365*fcf3ce44SJohn Forte {
366*fcf3ce44SJohn Forte 	return (solisten((struct sonode *)socket, backlog));
367*fcf3ce44SJohn Forte }
368*fcf3ce44SJohn Forte 
369*fcf3ce44SJohn Forte /*
370*fcf3ce44SJohn Forte  * iscsi_net_accept - accept peer socket connections
371*fcf3ce44SJohn Forte  */
372*fcf3ce44SJohn Forte static void *
373*fcf3ce44SJohn Forte iscsi_net_accept(void *socket, struct sockaddr *addr, int *addr_len)
374*fcf3ce44SJohn Forte {
375*fcf3ce44SJohn Forte 	struct sonode *listening_socket;
376*fcf3ce44SJohn Forte 
377*fcf3ce44SJohn Forte 	(void) soaccept((struct sonode *)socket,
378*fcf3ce44SJohn Forte 	    ((struct sonode *)socket)->so_flag,
379*fcf3ce44SJohn Forte 	    &listening_socket);
380*fcf3ce44SJohn Forte 	if (listening_socket != NULL) {
381*fcf3ce44SJohn Forte 		bcopy(listening_socket->so_faddr_sa, addr,
382*fcf3ce44SJohn Forte 		    (socklen_t)listening_socket->so_faddr_len);
383*fcf3ce44SJohn Forte 		*addr_len = listening_socket->so_faddr_len;
384*fcf3ce44SJohn Forte 	} else {
385*fcf3ce44SJohn Forte 		*addr_len = 0;
386*fcf3ce44SJohn Forte 	}
387*fcf3ce44SJohn Forte 
388*fcf3ce44SJohn Forte 	return ((void *)listening_socket);
389*fcf3ce44SJohn Forte }
390*fcf3ce44SJohn Forte 
391*fcf3ce44SJohn Forte /*
392*fcf3ce44SJohn Forte  * iscsi_net_getsockname -
393*fcf3ce44SJohn Forte  */
394*fcf3ce44SJohn Forte static int
395*fcf3ce44SJohn Forte iscsi_net_getsockname(void *socket)
396*fcf3ce44SJohn Forte {
397*fcf3ce44SJohn Forte 	return (sogetsockname((struct sonode *)socket));
398*fcf3ce44SJohn Forte }
399*fcf3ce44SJohn Forte 
400*fcf3ce44SJohn Forte /*
401*fcf3ce44SJohn Forte  * iscsi_net_getsockopt - get value of option on socket
402*fcf3ce44SJohn Forte  */
403*fcf3ce44SJohn Forte static int
404*fcf3ce44SJohn Forte iscsi_net_getsockopt(void *socket, int level, int option_name,
405*fcf3ce44SJohn Forte 	void *option_val, int *option_len, int flags)
406*fcf3ce44SJohn Forte {
407*fcf3ce44SJohn Forte 	return (sogetsockopt((struct sonode *)socket, level,
408*fcf3ce44SJohn Forte 	    option_name, option_val, (socklen_t *)option_len,
409*fcf3ce44SJohn Forte 	    flags));
410*fcf3ce44SJohn Forte }
411*fcf3ce44SJohn Forte 
412*fcf3ce44SJohn Forte /*
413*fcf3ce44SJohn Forte  * iscsi_net_setsockopt - set value for option on socket
414*fcf3ce44SJohn Forte  */
415*fcf3ce44SJohn Forte static int
416*fcf3ce44SJohn Forte iscsi_net_setsockopt(void *socket, int level, int option_name,
417*fcf3ce44SJohn Forte 	void *option_val, int option_len)
418*fcf3ce44SJohn Forte {
419*fcf3ce44SJohn Forte 	return (sosetsockopt((struct sonode *)socket, level,
420*fcf3ce44SJohn Forte 	    option_name, option_val, option_len));
421*fcf3ce44SJohn Forte }
422*fcf3ce44SJohn Forte 
423*fcf3ce44SJohn Forte /*
424*fcf3ce44SJohn Forte  * iscsi_net_shutdown - shutdown socket connection
425*fcf3ce44SJohn Forte  */
426*fcf3ce44SJohn Forte static int
427*fcf3ce44SJohn Forte iscsi_net_shutdown(void *socket, int how)
428*fcf3ce44SJohn Forte {
429*fcf3ce44SJohn Forte 	return (soshutdown((struct sonode *)socket, how));
430*fcf3ce44SJohn Forte }
431*fcf3ce44SJohn Forte 
432*fcf3ce44SJohn Forte /*
433*fcf3ce44SJohn Forte  * iscsi_net_close - shutdown socket connection and release resources
434*fcf3ce44SJohn Forte  */
435*fcf3ce44SJohn Forte static void
436*fcf3ce44SJohn Forte iscsi_net_close(void *socket)
437*fcf3ce44SJohn Forte {
438*fcf3ce44SJohn Forte 	vnode_t *vp = SOTOV((struct sonode *)socket);
439*fcf3ce44SJohn Forte 	(void) soshutdown((struct sonode *)socket, 2);
440*fcf3ce44SJohn Forte 	(void) VOP_CLOSE(vp, 0, 1, 0, kcred, NULL);
441*fcf3ce44SJohn Forte 	VN_RELE(vp);
442*fcf3ce44SJohn Forte }
443*fcf3ce44SJohn Forte 
444*fcf3ce44SJohn Forte /*
445*fcf3ce44SJohn Forte  * iscsi_net_poll - poll socket for data
446*fcf3ce44SJohn Forte  */
447*fcf3ce44SJohn Forte static size_t
448*fcf3ce44SJohn Forte iscsi_net_poll(void *socket, clock_t timeout)
449*fcf3ce44SJohn Forte {
450*fcf3ce44SJohn Forte 	int pflag;
451*fcf3ce44SJohn Forte 	uchar_t pri;
452*fcf3ce44SJohn Forte 	rval_t rval;
453*fcf3ce44SJohn Forte 
454*fcf3ce44SJohn Forte 	pri = 0;
455*fcf3ce44SJohn Forte 	pflag = MSG_ANY;
456*fcf3ce44SJohn Forte 	return (kstrgetmsg(SOTOV((struct sonode *)socket), NULL, NULL,
457*fcf3ce44SJohn Forte 	    &pri, &pflag, timeout, &rval));
458*fcf3ce44SJohn Forte }
459*fcf3ce44SJohn Forte 
460*fcf3ce44SJohn Forte /*
461*fcf3ce44SJohn Forte  * iscsi_net_sendmsg - send message on socket
462*fcf3ce44SJohn Forte  */
463*fcf3ce44SJohn Forte /* ARGSUSED */
464*fcf3ce44SJohn Forte static size_t
465*fcf3ce44SJohn Forte iscsi_net_sendmsg(void *socket, struct msghdr *msg)
466*fcf3ce44SJohn Forte {
467*fcf3ce44SJohn Forte 	int i = 0;
468*fcf3ce44SJohn Forte 	int total_len = 0;
469*fcf3ce44SJohn Forte 	struct uio uio;
470*fcf3ce44SJohn Forte 
471*fcf3ce44SJohn Forte 	/* Initialization of the uio structure. */
472*fcf3ce44SJohn Forte 	bzero(&uio, sizeof (uio));
473*fcf3ce44SJohn Forte 	uio.uio_iov = msg->msg_iov;
474*fcf3ce44SJohn Forte 	uio.uio_iovcnt = msg->msg_iovlen;
475*fcf3ce44SJohn Forte 	uio.uio_segflg  = UIO_SYSSPACE;
476*fcf3ce44SJohn Forte 
477*fcf3ce44SJohn Forte 	for (i = 0; i < msg->msg_iovlen; i++) {
478*fcf3ce44SJohn Forte 		total_len += (msg->msg_iov)[i].iov_len;
479*fcf3ce44SJohn Forte 	}
480*fcf3ce44SJohn Forte 	uio.uio_resid = total_len;
481*fcf3ce44SJohn Forte 
482*fcf3ce44SJohn Forte 	(void) sosendmsg((struct sonode *)socket, msg, &uio);
483*fcf3ce44SJohn Forte 	DTRACE_PROBE2(sosendmsg, size_t, total_len, size_t, uio.uio_resid);
484*fcf3ce44SJohn Forte 	return (total_len - uio.uio_resid);
485*fcf3ce44SJohn Forte }
486*fcf3ce44SJohn Forte 
487*fcf3ce44SJohn Forte /*
488*fcf3ce44SJohn Forte  * iscsi_net_recvmsg - receive message on socket
489*fcf3ce44SJohn Forte  */
490*fcf3ce44SJohn Forte /* ARGSUSED */
491*fcf3ce44SJohn Forte static size_t
492*fcf3ce44SJohn Forte iscsi_net_recvmsg(void *socket, struct msghdr *msg, int timeout)
493*fcf3ce44SJohn Forte {
494*fcf3ce44SJohn Forte 	int		idx;
495*fcf3ce44SJohn Forte 	int		total_len   = 0;
496*fcf3ce44SJohn Forte 	struct uio	uio;
497*fcf3ce44SJohn Forte 	uchar_t		pri	    = 0;
498*fcf3ce44SJohn Forte 	int		prflag	    = MSG_ANY;
499*fcf3ce44SJohn Forte 	rval_t		rval;
500*fcf3ce44SJohn Forte 	struct sonode	*sonode	    = (struct sonode *)socket;
501*fcf3ce44SJohn Forte 
502*fcf3ce44SJohn Forte 	/* Initialization of the uio structure. */
503*fcf3ce44SJohn Forte 	bzero(&uio, sizeof (uio));
504*fcf3ce44SJohn Forte 	uio.uio_iov	    = msg->msg_iov;
505*fcf3ce44SJohn Forte 	uio.uio_iovcnt	    = msg->msg_iovlen;
506*fcf3ce44SJohn Forte 	uio.uio_segflg	    = UIO_SYSSPACE;
507*fcf3ce44SJohn Forte 
508*fcf3ce44SJohn Forte 	for (idx = 0; idx < msg->msg_iovlen; idx++) {
509*fcf3ce44SJohn Forte 		total_len += (msg->msg_iov)[idx].iov_len;
510*fcf3ce44SJohn Forte 	}
511*fcf3ce44SJohn Forte 	uio.uio_resid = total_len;
512*fcf3ce44SJohn Forte 
513*fcf3ce44SJohn Forte 	/* If timeout requested on receive */
514*fcf3ce44SJohn Forte 	if (timeout > 0) {
515*fcf3ce44SJohn Forte 		boolean_t   loopback = B_FALSE;
516*fcf3ce44SJohn Forte 
517*fcf3ce44SJohn Forte 		/* And this isn't a loopback connection */
518*fcf3ce44SJohn Forte 		if (sonode->so_laddr.soa_sa->sa_family == AF_INET) {
519*fcf3ce44SJohn Forte 			struct sockaddr_in *lin =
520*fcf3ce44SJohn Forte 			    (struct sockaddr_in *)sonode->so_laddr.soa_sa;
521*fcf3ce44SJohn Forte 			struct sockaddr_in *fin =
522*fcf3ce44SJohn Forte 			    (struct sockaddr_in *)sonode->so_faddr.soa_sa;
523*fcf3ce44SJohn Forte 
524*fcf3ce44SJohn Forte 			if ((lin->sin_family == fin->sin_family) &&
525*fcf3ce44SJohn Forte 			    (bcmp(&lin->sin_addr, &fin->sin_addr,
526*fcf3ce44SJohn Forte 			    sizeof (struct in_addr)) == 0)) {
527*fcf3ce44SJohn Forte 				loopback = B_TRUE;
528*fcf3ce44SJohn Forte 			}
529*fcf3ce44SJohn Forte 		} else {
530*fcf3ce44SJohn Forte 			struct sockaddr_in6 *lin6 =
531*fcf3ce44SJohn Forte 			    (struct sockaddr_in6 *)sonode->so_laddr.soa_sa;
532*fcf3ce44SJohn Forte 			struct sockaddr_in6 *fin6 =
533*fcf3ce44SJohn Forte 			    (struct sockaddr_in6 *)sonode->so_faddr.soa_sa;
534*fcf3ce44SJohn Forte 
535*fcf3ce44SJohn Forte 			if ((lin6->sin6_family == fin6->sin6_family) &&
536*fcf3ce44SJohn Forte 			    (bcmp(&lin6->sin6_addr, &fin6->sin6_addr,
537*fcf3ce44SJohn Forte 			    sizeof (struct in6_addr)) == 0)) {
538*fcf3ce44SJohn Forte 				loopback = B_TRUE;
539*fcf3ce44SJohn Forte 			}
540*fcf3ce44SJohn Forte 		}
541*fcf3ce44SJohn Forte 
542*fcf3ce44SJohn Forte 		if (loopback == B_FALSE) {
543*fcf3ce44SJohn Forte 			/*
544*fcf3ce44SJohn Forte 			 * Then poll device for up to the timeout
545*fcf3ce44SJohn Forte 			 * period or the requested data is received.
546*fcf3ce44SJohn Forte 			 */
547*fcf3ce44SJohn Forte 			if (kstrgetmsg(SOTOV(sonode),
548*fcf3ce44SJohn Forte 			    NULL, NULL, &pri, &prflag, timeout * 1000,
549*fcf3ce44SJohn Forte 			    &rval) == ETIME) {
550*fcf3ce44SJohn Forte 				return (0);
551*fcf3ce44SJohn Forte 			}
552*fcf3ce44SJohn Forte 		}
553*fcf3ce44SJohn Forte 	}
554*fcf3ce44SJohn Forte 
555*fcf3ce44SJohn Forte 	/*
556*fcf3ce44SJohn Forte 	 * Receive the requested data.  Block until all
557*fcf3ce44SJohn Forte 	 * data is received.
558*fcf3ce44SJohn Forte 	 *
559*fcf3ce44SJohn Forte 	 * resid occurs only when the connection is
560*fcf3ce44SJohn Forte 	 * disconnected.  In that case it will return
561*fcf3ce44SJohn Forte 	 * the amount of data that was not received.
562*fcf3ce44SJohn Forte 	 * In general this is the total amount we
563*fcf3ce44SJohn Forte 	 * requested.
564*fcf3ce44SJohn Forte 	 */
565*fcf3ce44SJohn Forte 	(void) sorecvmsg((struct sonode *)socket, msg, &uio);
566*fcf3ce44SJohn Forte 	DTRACE_PROBE2(sorecvmsg, size_t, total_len, size_t, uio.uio_resid);
567*fcf3ce44SJohn Forte 	return (total_len - uio.uio_resid);
568*fcf3ce44SJohn Forte }
569*fcf3ce44SJohn Forte 
570*fcf3ce44SJohn Forte /*
571*fcf3ce44SJohn Forte  * iscsi_net_sendpdu - send iscsi pdu on socket
572*fcf3ce44SJohn Forte  */
573*fcf3ce44SJohn Forte static iscsi_status_t
574*fcf3ce44SJohn Forte iscsi_net_sendpdu(void *socket, iscsi_hdr_t *ihp, char *data, int flags)
575*fcf3ce44SJohn Forte {
576*fcf3ce44SJohn Forte 	uint32_t	pad;
577*fcf3ce44SJohn Forte 	uint32_t	crc_hdr;
578*fcf3ce44SJohn Forte 	uint32_t	crc_data;
579*fcf3ce44SJohn Forte 	uint32_t	pad_len;
580*fcf3ce44SJohn Forte 	uint32_t	data_len;
581*fcf3ce44SJohn Forte 	iovec_t		iovec[ISCSI_MAX_IOVEC];
582*fcf3ce44SJohn Forte 	int		iovlen = 0;
583*fcf3ce44SJohn Forte 	size_t		total_len = 0;
584*fcf3ce44SJohn Forte 	size_t		send_len;
585*fcf3ce44SJohn Forte 	struct msghdr	msg;
586*fcf3ce44SJohn Forte 
587*fcf3ce44SJohn Forte 	ASSERT(socket != NULL);
588*fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
589*fcf3ce44SJohn Forte 
590*fcf3ce44SJohn Forte 	/*
591*fcf3ce44SJohn Forte 	 * Let's send the header first.  'hlength' is in 32-bit
592*fcf3ce44SJohn Forte 	 * quantities, so we need to multiply by four to get bytes
593*fcf3ce44SJohn Forte 	 */
594*fcf3ce44SJohn Forte 	ASSERT(iovlen < ISCSI_MAX_IOVEC);
595*fcf3ce44SJohn Forte 	iovec[iovlen].iov_base = (void *)ihp;
596*fcf3ce44SJohn Forte 	iovec[iovlen].iov_len  = sizeof (*ihp) + ihp->hlength * 4;
597*fcf3ce44SJohn Forte 	total_len += sizeof (*ihp) + ihp->hlength * 4;
598*fcf3ce44SJohn Forte 	iovlen++;
599*fcf3ce44SJohn Forte 
600*fcf3ce44SJohn Forte 	/* Let's transmit the header digest if we have to. */
601*fcf3ce44SJohn Forte 	if ((flags & ISCSI_NET_HEADER_DIGEST) != 0) {
602*fcf3ce44SJohn Forte 		ASSERT(iovlen < ISCSI_MAX_IOVEC);
603*fcf3ce44SJohn Forte 		/*
604*fcf3ce44SJohn Forte 		 * Converting the calculated CRC via htonl is not
605*fcf3ce44SJohn Forte 		 * necessary because iscsi_crc32c calculates
606*fcf3ce44SJohn Forte 		 * the value as it expects to be written
607*fcf3ce44SJohn Forte 		 */
608*fcf3ce44SJohn Forte 		crc_hdr = iscsi_crc32c((char *)ihp,
609*fcf3ce44SJohn Forte 		    sizeof (iscsi_hdr_t) + ihp->hlength * 4);
610*fcf3ce44SJohn Forte 
611*fcf3ce44SJohn Forte 		iovec[iovlen].iov_base = (void *)&crc_hdr;
612*fcf3ce44SJohn Forte 		iovec[iovlen].iov_len  = sizeof (crc_hdr);
613*fcf3ce44SJohn Forte 		total_len += sizeof (crc_hdr);
614*fcf3ce44SJohn Forte 		iovlen++;
615*fcf3ce44SJohn Forte 	}
616*fcf3ce44SJohn Forte 
617*fcf3ce44SJohn Forte 	/* Let's transmit the data if any. */
618*fcf3ce44SJohn Forte 	data_len = ntoh24(ihp->dlength);
619*fcf3ce44SJohn Forte 
620*fcf3ce44SJohn Forte 	if (data_len) {
621*fcf3ce44SJohn Forte 
622*fcf3ce44SJohn Forte 		ASSERT(iovlen < ISCSI_MAX_IOVEC);
623*fcf3ce44SJohn Forte 		iovec[iovlen].iov_base = (void *)data;
624*fcf3ce44SJohn Forte 		iovec[iovlen].iov_len  = data_len;
625*fcf3ce44SJohn Forte 		total_len += data_len;
626*fcf3ce44SJohn Forte 		iovlen++;
627*fcf3ce44SJohn Forte 
628*fcf3ce44SJohn Forte 		pad_len = ((ISCSI_PAD_WORD_LEN -
629*fcf3ce44SJohn Forte 		    (data_len & (ISCSI_PAD_WORD_LEN - 1))) &
630*fcf3ce44SJohn Forte 		    (ISCSI_PAD_WORD_LEN - 1));
631*fcf3ce44SJohn Forte 
632*fcf3ce44SJohn Forte 		/* Let's transmit the data pad if any. */
633*fcf3ce44SJohn Forte 		if (pad_len) {
634*fcf3ce44SJohn Forte 
635*fcf3ce44SJohn Forte 			ASSERT(iovlen < ISCSI_MAX_IOVEC);
636*fcf3ce44SJohn Forte 			pad = 0;
637*fcf3ce44SJohn Forte 			iovec[iovlen].iov_base = (void *)&pad;
638*fcf3ce44SJohn Forte 			iovec[iovlen].iov_len  = pad_len;
639*fcf3ce44SJohn Forte 			total_len += pad_len;
640*fcf3ce44SJohn Forte 			iovlen++;
641*fcf3ce44SJohn Forte 		}
642*fcf3ce44SJohn Forte 
643*fcf3ce44SJohn Forte 		/* Let's transmit the data digest if we have to. */
644*fcf3ce44SJohn Forte 		if ((flags & ISCSI_NET_DATA_DIGEST) != 0) {
645*fcf3ce44SJohn Forte 
646*fcf3ce44SJohn Forte 			ASSERT(iovlen < ISCSI_MAX_IOVEC);
647*fcf3ce44SJohn Forte 			/*
648*fcf3ce44SJohn Forte 			 * Converting the calculated CRC via htonl is not
649*fcf3ce44SJohn Forte 			 * necessary because iscsi_crc32c calculates the
650*fcf3ce44SJohn Forte 			 * value as it expects to be written
651*fcf3ce44SJohn Forte 			 */
652*fcf3ce44SJohn Forte 			crc_data = iscsi_crc32c(data, data_len);
653*fcf3ce44SJohn Forte 			crc_data = iscsi_crc32c_continued(
654*fcf3ce44SJohn Forte 			    (char *)&pad, pad_len, crc_data);
655*fcf3ce44SJohn Forte 
656*fcf3ce44SJohn Forte 			iovec[iovlen].iov_base = (void *)&crc_data;
657*fcf3ce44SJohn Forte 			iovec[iovlen].iov_len  = sizeof (crc_data);
658*fcf3ce44SJohn Forte 			total_len += sizeof (crc_data);
659*fcf3ce44SJohn Forte 			iovlen++;
660*fcf3ce44SJohn Forte 		}
661*fcf3ce44SJohn Forte 	}
662*fcf3ce44SJohn Forte 
663*fcf3ce44SJohn Forte 	DTRACE_PROBE4(tx, void *, socket, iovec_t *, &iovec[0],
664*fcf3ce44SJohn Forte 	    int, iovlen, int, total_len);
665*fcf3ce44SJohn Forte 
666*fcf3ce44SJohn Forte 	/* Initialization of the message header. */
667*fcf3ce44SJohn Forte 	bzero(&msg, sizeof (msg));
668*fcf3ce44SJohn Forte 	msg.msg_iov	= &iovec[0];
669*fcf3ce44SJohn Forte 	msg.msg_flags	= MSG_WAITALL;
670*fcf3ce44SJohn Forte 	msg.msg_iovlen	= iovlen;
671*fcf3ce44SJohn Forte 
672*fcf3ce44SJohn Forte 	send_len = iscsi_net->sendmsg((struct sonode *)socket, &msg);
673*fcf3ce44SJohn Forte 	DTRACE_PROBE2(sendmsg, size_t, total_len, size_t, send_len);
674*fcf3ce44SJohn Forte 	if (total_len != send_len) {
675*fcf3ce44SJohn Forte 		return (ISCSI_STATUS_TCP_TX_ERROR);
676*fcf3ce44SJohn Forte 	}
677*fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
678*fcf3ce44SJohn Forte }
679*fcf3ce44SJohn Forte 
680*fcf3ce44SJohn Forte /*
681*fcf3ce44SJohn Forte  * iscsi_net_recvhdr - receive iscsi hdr on socket
682*fcf3ce44SJohn Forte  */
683*fcf3ce44SJohn Forte static iscsi_status_t
684*fcf3ce44SJohn Forte iscsi_net_recvhdr(void *socket, iscsi_hdr_t *ihp, int header_length,
685*fcf3ce44SJohn Forte     int timeout, int flags)
686*fcf3ce44SJohn Forte {
687*fcf3ce44SJohn Forte 	iovec_t		    iov[ISCSI_MAX_IOVEC];
688*fcf3ce44SJohn Forte 	int		    iovlen		= 1;
689*fcf3ce44SJohn Forte 	int		    total_len		= 0;
690*fcf3ce44SJohn Forte 	uint32_t	    crc_actual		= 0;
691*fcf3ce44SJohn Forte 	uint32_t	    crc_calculated	= 0;
692*fcf3ce44SJohn Forte 	char		    *adhdr		= NULL;
693*fcf3ce44SJohn Forte 	int		    adhdr_length	= 0;
694*fcf3ce44SJohn Forte 	struct msghdr	    msg;
695*fcf3ce44SJohn Forte 	size_t		    recv_len;
696*fcf3ce44SJohn Forte 
697*fcf3ce44SJohn Forte 	ASSERT(socket != NULL);
698*fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
699*fcf3ce44SJohn Forte 
700*fcf3ce44SJohn Forte 	if (header_length < sizeof (iscsi_hdr_t)) {
701*fcf3ce44SJohn Forte 		ASSERT(FALSE);
702*fcf3ce44SJohn Forte 		return (ISCSI_STATUS_INTERNAL_ERROR);
703*fcf3ce44SJohn Forte 	}
704*fcf3ce44SJohn Forte 
705*fcf3ce44SJohn Forte 	/*
706*fcf3ce44SJohn Forte 	 * Receive primary header
707*fcf3ce44SJohn Forte 	 */
708*fcf3ce44SJohn Forte 	iov[0].iov_base = (char *)ihp;
709*fcf3ce44SJohn Forte 	iov[0].iov_len = sizeof (iscsi_hdr_t);
710*fcf3ce44SJohn Forte 
711*fcf3ce44SJohn Forte 	bzero(&msg, sizeof (msg));
712*fcf3ce44SJohn Forte 	msg.msg_iov	= iov;
713*fcf3ce44SJohn Forte 	msg.msg_flags	= MSG_WAITALL;
714*fcf3ce44SJohn Forte 	msg.msg_iovlen	= iovlen;
715*fcf3ce44SJohn Forte 
716*fcf3ce44SJohn Forte 	recv_len = iscsi_net->recvmsg(socket, &msg, timeout);
717*fcf3ce44SJohn Forte 	if (recv_len != sizeof (iscsi_hdr_t)) {
718*fcf3ce44SJohn Forte 		return (ISCSI_STATUS_TCP_RX_ERROR);
719*fcf3ce44SJohn Forte 	}
720*fcf3ce44SJohn Forte 
721*fcf3ce44SJohn Forte 	DTRACE_PROBE2(rx_hdr, void *, socket, iovec_t *iop, &iov[0]);
722*fcf3ce44SJohn Forte 
723*fcf3ce44SJohn Forte 	/* verify incoming opcode is a valid operation */
724*fcf3ce44SJohn Forte 	if (is_incoming_opcode_invalid[ihp->opcode]) {
725*fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%p) protocol error - "
726*fcf3ce44SJohn Forte 		    "received an unsupported opcode:0x%02x",
727*fcf3ce44SJohn Forte 		    socket, ihp->opcode);
728*fcf3ce44SJohn Forte 		return (ISCSI_STATUS_PROTOCOL_ERROR);
729*fcf3ce44SJohn Forte 	}
730*fcf3ce44SJohn Forte 
731*fcf3ce44SJohn Forte 	/*
732*fcf3ce44SJohn Forte 	 * Setup receipt of additional header
733*fcf3ce44SJohn Forte 	 */
734*fcf3ce44SJohn Forte 	if (ihp->hlength > 0) {
735*fcf3ce44SJohn Forte 		adhdr = ((char *)ihp) + sizeof (iscsi_hdr_t);
736*fcf3ce44SJohn Forte 		adhdr_length = header_length - sizeof (iscsi_hdr_t);
737*fcf3ce44SJohn Forte 		/* make sure enough space is available for adhdr */
738*fcf3ce44SJohn Forte 		if (ihp->hlength > adhdr_length) {
739*fcf3ce44SJohn Forte 			ASSERT(FALSE);
740*fcf3ce44SJohn Forte 			return (ISCSI_STATUS_INTERNAL_ERROR);
741*fcf3ce44SJohn Forte 		}
742*fcf3ce44SJohn Forte 
743*fcf3ce44SJohn Forte 		ASSERT(iovlen < ISCSI_MAX_IOVEC);
744*fcf3ce44SJohn Forte 		iov[iovlen].iov_base = adhdr;
745*fcf3ce44SJohn Forte 		iov[iovlen].iov_len = adhdr_length;
746*fcf3ce44SJohn Forte 		total_len += adhdr_length;
747*fcf3ce44SJohn Forte 		iovlen++;
748*fcf3ce44SJohn Forte 	}
749*fcf3ce44SJohn Forte 
750*fcf3ce44SJohn Forte 	/*
751*fcf3ce44SJohn Forte 	 * Setup receipt of header digest if enabled and connection
752*fcf3ce44SJohn Forte 	 * is in full feature mode.
753*fcf3ce44SJohn Forte 	 */
754*fcf3ce44SJohn Forte 	if ((flags & ISCSI_NET_HEADER_DIGEST) != 0) {
755*fcf3ce44SJohn Forte 		ASSERT(iovlen < ISCSI_MAX_IOVEC);
756*fcf3ce44SJohn Forte 		iov[iovlen].iov_base = (char *)&crc_actual;
757*fcf3ce44SJohn Forte 		iov[iovlen].iov_len = sizeof (uint32_t);
758*fcf3ce44SJohn Forte 		total_len += sizeof (uint32_t);
759*fcf3ce44SJohn Forte 		iovlen++;
760*fcf3ce44SJohn Forte 	}
761*fcf3ce44SJohn Forte 
762*fcf3ce44SJohn Forte 	/*
763*fcf3ce44SJohn Forte 	 * Read additional header and/or header digest if pieces
764*fcf3ce44SJohn Forte 	 * are available
765*fcf3ce44SJohn Forte 	 */
766*fcf3ce44SJohn Forte 	if (iovlen > 1) {
767*fcf3ce44SJohn Forte 
768*fcf3ce44SJohn Forte 		bzero(&msg, sizeof (msg));
769*fcf3ce44SJohn Forte 		msg.msg_iov	= iov;
770*fcf3ce44SJohn Forte 		msg.msg_flags	= MSG_WAITALL;
771*fcf3ce44SJohn Forte 		msg.msg_iovlen	= iovlen;
772*fcf3ce44SJohn Forte 
773*fcf3ce44SJohn Forte 		recv_len = iscsi_net->recvmsg(socket, &msg, timeout);
774*fcf3ce44SJohn Forte 		if (recv_len != total_len) {
775*fcf3ce44SJohn Forte 			return (ISCSI_STATUS_TCP_RX_ERROR);
776*fcf3ce44SJohn Forte 		}
777*fcf3ce44SJohn Forte 
778*fcf3ce44SJohn Forte 		DTRACE_PROBE4(rx_adhdr_digest, void *, socket,
779*fcf3ce44SJohn Forte 		    iovec_t *iop, &iov[0], int, iovlen, int, total_len);
780*fcf3ce44SJohn Forte 
781*fcf3ce44SJohn Forte 		/*
782*fcf3ce44SJohn Forte 		 * Verify header digest if enabled and connection
783*fcf3ce44SJohn Forte 		 * is in full feature mode
784*fcf3ce44SJohn Forte 		 */
785*fcf3ce44SJohn Forte 		if ((flags & ISCSI_NET_HEADER_DIGEST) != 0) {
786*fcf3ce44SJohn Forte 			crc_calculated = iscsi_crc32c((uchar_t *)ihp,
787*fcf3ce44SJohn Forte 			    sizeof (iscsi_hdr_t) + ihp->hlength * 4);
788*fcf3ce44SJohn Forte 
789*fcf3ce44SJohn Forte 			/*
790*fcf3ce44SJohn Forte 			 * Converting actual CRC read via ntohl is not
791*fcf3ce44SJohn Forte 			 * necessary because iscsi_crc32c calculates the
792*fcf3ce44SJohn Forte 			 * value as it expect to be read
793*fcf3ce44SJohn Forte 			 */
794*fcf3ce44SJohn Forte 			if (crc_calculated != crc_actual) {
795*fcf3ce44SJohn Forte 				/* Invalid Header Digest */
796*fcf3ce44SJohn Forte 				cmn_err(CE_WARN, "iscsi connection(%p) "
797*fcf3ce44SJohn Forte 				    "protocol error - encountered a header "
798*fcf3ce44SJohn Forte 				    "digest error expected:0x%08x "
799*fcf3ce44SJohn Forte 				    "received:0x%08x", socket,
800*fcf3ce44SJohn Forte 				    crc_calculated, crc_actual);
801*fcf3ce44SJohn Forte 				return (ISCSI_STATUS_HEADER_DIGEST_ERROR);
802*fcf3ce44SJohn Forte 			}
803*fcf3ce44SJohn Forte 		}
804*fcf3ce44SJohn Forte 	}
805*fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
806*fcf3ce44SJohn Forte }
807*fcf3ce44SJohn Forte 
808*fcf3ce44SJohn Forte 
809*fcf3ce44SJohn Forte /*
810*fcf3ce44SJohn Forte  * iscsi_net_recvdata - receive iscsi data payload from socket
811*fcf3ce44SJohn Forte  */
812*fcf3ce44SJohn Forte static iscsi_status_t
813*fcf3ce44SJohn Forte iscsi_net_recvdata(void *socket, iscsi_hdr_t *ihp, char *data,
814*fcf3ce44SJohn Forte     int max_data_length, int timeout, int flags)
815*fcf3ce44SJohn Forte {
816*fcf3ce44SJohn Forte 	struct iovec	iov[3];
817*fcf3ce44SJohn Forte 	int		iovlen			= 1;
818*fcf3ce44SJohn Forte 	int		total_len		= 0;
819*fcf3ce44SJohn Forte 	int		dlength			= 0;
820*fcf3ce44SJohn Forte 	int		pad_len			= 0;
821*fcf3ce44SJohn Forte 	uint8_t		pad[ISCSI_PAD_WORD_LEN];
822*fcf3ce44SJohn Forte 	uint32_t	crc_calculated		= 0;
823*fcf3ce44SJohn Forte 	uint32_t	crc_actual		= 0;
824*fcf3ce44SJohn Forte 	struct msghdr	msg;
825*fcf3ce44SJohn Forte 	size_t		recv_len;
826*fcf3ce44SJohn Forte 
827*fcf3ce44SJohn Forte 	ASSERT(socket != NULL);
828*fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
829*fcf3ce44SJohn Forte 	ASSERT(data != NULL);
830*fcf3ce44SJohn Forte 
831*fcf3ce44SJohn Forte 	/* short hand dlength */
832*fcf3ce44SJohn Forte 	dlength = ntoh24(ihp->dlength);
833*fcf3ce44SJohn Forte 
834*fcf3ce44SJohn Forte 	/* verify dlength is valid */
835*fcf3ce44SJohn Forte 	if (dlength > max_data_length) {
836*fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%p) protocol error - "
837*fcf3ce44SJohn Forte 		    "invalid data lengths itt:0x%x received:0x%x "
838*fcf3ce44SJohn Forte 		    "max expected:0x%x", socket, ihp->itt,
839*fcf3ce44SJohn Forte 		    dlength, max_data_length);
840*fcf3ce44SJohn Forte 		return (ISCSI_STATUS_PROTOCOL_ERROR);
841*fcf3ce44SJohn Forte 	}
842*fcf3ce44SJohn Forte 
843*fcf3ce44SJohn Forte 	if (dlength) {
844*fcf3ce44SJohn Forte 
845*fcf3ce44SJohn Forte 		/* calculate pad */
846*fcf3ce44SJohn Forte 		pad_len = ((ISCSI_PAD_WORD_LEN -
847*fcf3ce44SJohn Forte 		    (dlength & (ISCSI_PAD_WORD_LEN - 1))) &
848*fcf3ce44SJohn Forte 		    (ISCSI_PAD_WORD_LEN - 1));
849*fcf3ce44SJohn Forte 
850*fcf3ce44SJohn Forte 		/* setup data iovec */
851*fcf3ce44SJohn Forte 		iov[0].iov_base	= (char *)data;
852*fcf3ce44SJohn Forte 		iov[0].iov_len	= dlength;
853*fcf3ce44SJohn Forte 		total_len	= dlength;
854*fcf3ce44SJohn Forte 
855*fcf3ce44SJohn Forte 		/* if pad setup pad iovec */
856*fcf3ce44SJohn Forte 		if (pad_len) {
857*fcf3ce44SJohn Forte 			iov[iovlen].iov_base	= (char *)&pad;
858*fcf3ce44SJohn Forte 			iov[iovlen].iov_len	= pad_len;
859*fcf3ce44SJohn Forte 			total_len		+= pad_len;
860*fcf3ce44SJohn Forte 			iovlen++;
861*fcf3ce44SJohn Forte 		}
862*fcf3ce44SJohn Forte 
863*fcf3ce44SJohn Forte 		/* setup data digest */
864*fcf3ce44SJohn Forte 		if ((flags & ISCSI_NET_DATA_DIGEST) != 0) {
865*fcf3ce44SJohn Forte 			iov[iovlen].iov_base	= (char *)&crc_actual;
866*fcf3ce44SJohn Forte 			iov[iovlen].iov_len	= sizeof (crc_actual);
867*fcf3ce44SJohn Forte 			total_len		+= sizeof (crc_actual);
868*fcf3ce44SJohn Forte 			iovlen++;
869*fcf3ce44SJohn Forte 		}
870*fcf3ce44SJohn Forte 
871*fcf3ce44SJohn Forte 		bzero(&msg, sizeof (msg));
872*fcf3ce44SJohn Forte 		msg.msg_iov	= iov;
873*fcf3ce44SJohn Forte 		msg.msg_flags	= MSG_WAITALL;
874*fcf3ce44SJohn Forte 		msg.msg_iovlen	= iovlen;
875*fcf3ce44SJohn Forte 
876*fcf3ce44SJohn Forte 		recv_len = iscsi_net->recvmsg(socket, &msg, timeout);
877*fcf3ce44SJohn Forte 		if (recv_len != total_len) {
878*fcf3ce44SJohn Forte 			return (ISCSI_STATUS_TCP_RX_ERROR);
879*fcf3ce44SJohn Forte 		}
880*fcf3ce44SJohn Forte 
881*fcf3ce44SJohn Forte 		DTRACE_PROBE4(rx_data, void *, socket, iovec_t *iop,
882*fcf3ce44SJohn Forte 		    &iov[0], int, iovlen, int, total_len);
883*fcf3ce44SJohn Forte 
884*fcf3ce44SJohn Forte 		/* verify data digest is present */
885*fcf3ce44SJohn Forte 		if ((flags & ISCSI_NET_DATA_DIGEST) != 0) {
886*fcf3ce44SJohn Forte 
887*fcf3ce44SJohn Forte 			crc_calculated = iscsi_crc32c(data, dlength);
888*fcf3ce44SJohn Forte 			crc_calculated = iscsi_crc32c_continued(
889*fcf3ce44SJohn Forte 			    (char *)&pad, pad_len, crc_calculated);
890*fcf3ce44SJohn Forte 
891*fcf3ce44SJohn Forte 			/*
892*fcf3ce44SJohn Forte 			 * Converting actual CRC read via ntohl is not
893*fcf3ce44SJohn Forte 			 * necessary because iscsi_crc32c calculates the
894*fcf3ce44SJohn Forte 			 * value as it expects to be read
895*fcf3ce44SJohn Forte 			 */
896*fcf3ce44SJohn Forte 			if (crc_calculated != crc_actual) {
897*fcf3ce44SJohn Forte 				cmn_err(CE_WARN, "iscsi connection(%p) "
898*fcf3ce44SJohn Forte 				    "protocol error - encountered a data "
899*fcf3ce44SJohn Forte 				    "digest error itt:0x%x expected:0x%08x "
900*fcf3ce44SJohn Forte 				    "received:0x%08x", socket,
901*fcf3ce44SJohn Forte 				    ihp->itt, crc_calculated, crc_actual);
902*fcf3ce44SJohn Forte 				return (ISCSI_STATUS_DATA_DIGEST_ERROR);
903*fcf3ce44SJohn Forte 			}
904*fcf3ce44SJohn Forte 		}
905*fcf3ce44SJohn Forte 	}
906*fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
907*fcf3ce44SJohn Forte }
908