1fcf3ce44SJohn Forte /*
2fcf3ce44SJohn Forte  * CDDL HEADER START
3fcf3ce44SJohn Forte  *
4fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7fcf3ce44SJohn Forte  *
8fcf3ce44SJohn Forte  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fcf3ce44SJohn Forte  * or http://www.opensolaris.org/os/licensing.
10fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11fcf3ce44SJohn Forte  * and limitations under the License.
12fcf3ce44SJohn Forte  *
13fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18fcf3ce44SJohn Forte  *
19fcf3ce44SJohn Forte  * CDDL HEADER END
20fcf3ce44SJohn Forte  */
21fcf3ce44SJohn Forte /*
22fcf3ce44SJohn Forte  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23fcf3ce44SJohn Forte  * Use is subject to license terms.
24fcf3ce44SJohn Forte  *
25fcf3ce44SJohn Forte  * iSCSI Software Initiator
26fcf3ce44SJohn Forte  */
27fcf3ce44SJohn Forte 
28fcf3ce44SJohn Forte #include <sys/socket.h>		/* networking stuff */
29fcf3ce44SJohn Forte #include <sys/strsubr.h>	/* networking stuff */
30fcf3ce44SJohn Forte #include <netinet/tcp.h>	/* TCP_NODELAY */
31fcf3ce44SJohn Forte #include <sys/socketvar.h>	/* _ALLOC_SLEEP */
32fcf3ce44SJohn Forte #include <sys/pathname.h>	/* declares:	lookupname */
33fcf3ce44SJohn Forte #include <sys/fs/snode.h>	/* defines:	VTOS */
34fcf3ce44SJohn Forte #include <sys/fs/dv_node.h>	/* declares:	devfs_lookupname */
356cefaae1SJack Meng #include <sys/bootconf.h>
366cefaae1SJack Meng #include <sys/bootprops.h>
37*0f1702c5SYu Xiangning #include <netinet/in.h>
38fcf3ce44SJohn Forte #include "iscsi.h"
39*0f1702c5SYu Xiangning #include <sys/ksocket.h>
40fcf3ce44SJohn Forte 
41fcf3ce44SJohn Forte /*
42fcf3ce44SJohn Forte  * This is a high level description of the default
43fcf3ce44SJohn Forte  * iscsi_net transport interfaces.  These are used
44fcf3ce44SJohn Forte  * to create, send, recv, and close standard TCP/IP
45fcf3ce44SJohn Forte  * messages.  In addition there are extensions to send
46fcf3ce44SJohn Forte  * and recv iSCSI PDU data.
47fcf3ce44SJohn Forte  *
48fcf3ce44SJohn Forte  * NOTE: It would be very easy for an iSCSI HBA vendor
49fcf3ce44SJohn Forte  * to register their own functions over the top of
50fcf3ce44SJohn Forte  * the default interfaces.  This would allow an iSCSI
51fcf3ce44SJohn Forte  * HBA to use the same iscsiadm management interfaces
52fcf3ce44SJohn Forte  * and the Solaris iSCSI session / connection management.
53fcf3ce44SJohn Forte  * The current problem with this approach is we only
54fcf3ce44SJohn Forte  * allow one one registered transport table.  This
55fcf3ce44SJohn Forte  * would be pretty easy to correct although will require
56fcf3ce44SJohn Forte  * additional CLI changes to manage multiple interfaces.
57fcf3ce44SJohn Forte  * If a vendor can present compelling performance data,
58fcf3ce44SJohn Forte  * then Sun will be willing to enhance this support for
59fcf3ce44SJohn Forte  * multiple interface tables and better CLI management.
60fcf3ce44SJohn Forte  *
61fcf3ce44SJohn Forte  * The following listing describes the iscsi_net
62fcf3ce44SJohn Forte  * entry points:
63fcf3ce44SJohn Forte  *
64*0f1702c5SYu Xiangning  *   socket	    - Creates TCP/IP socket connection.  In the
65*0f1702c5SYu Xiangning  *		       default implementation creates a sonode
66*0f1702c5SYu Xiangning  *		       via the sockfs kernel layer.
67*0f1702c5SYu Xiangning  *   bind	      - Performs standard TCP/IP BSD operation.  In
68*0f1702c5SYu Xiangning  *		       the default implementation this only act
69*0f1702c5SYu Xiangning  *		       as a soft binding based on the IP and routing
70*0f1702c5SYu Xiangning  *			 tables.  It would be preferred if this was
71*0f1702c5SYu Xiangning  *			 a hard binding but that is currently not
72*0f1702c5SYu Xiangning  *			 possible with Solaris's networking stack.
73*0f1702c5SYu Xiangning  *   connect	   - Performs standard TCP/IP BSD operation.  This
74*0f1702c5SYu Xiangning  *		       establishes the TCP SYN to the peer IP address.
75*0f1702c5SYu Xiangning  *   listen	    - Performs standard TCP/IP BSD operation.  This
76*0f1702c5SYu Xiangning  *		       listens for incoming peer connections.
77*0f1702c5SYu Xiangning  *   accept	    - Performs standard TCP/IP BSD operation.  This
78*0f1702c5SYu Xiangning  *		       accepts incoming peer connections.
79*0f1702c5SYu Xiangning  *   shutdown	  - This disconnects the TCP/IP connection while
80*0f1702c5SYu Xiangning  *		       maintaining the resources.
81*0f1702c5SYu Xiangning  *   close	     - This disconnects the TCP/IP connection and
82*0f1702c5SYu Xiangning  *		       releases the resources.
83fcf3ce44SJohn Forte  *
84*0f1702c5SYu Xiangning  *   getsockopt	- Gets socket option for specified socket.
85*0f1702c5SYu Xiangning  *   setsockopt	- Sets socket option for specified socket.
86fcf3ce44SJohn Forte  *
87fcf3ce44SJohn Forte  *      The current socket options that are used by the initiator
88fcf3ce44SJohn Forte  *      are listed below.
89fcf3ce44SJohn Forte  *
90*0f1702c5SYu Xiangning  *	TCP_CONN_NOTIFY_THRESHOLD
91*0f1702c5SYu Xiangning  *	TCP_CONN_ABORT_THRESHOLD
92*0f1702c5SYu Xiangning  *	TCP_ABORT_THRESHOLD
93*0f1702c5SYu Xiangning  *	TCP_NODELAY
94*0f1702c5SYu Xiangning  *	SO_RCVBUF
95*0f1702c5SYu Xiangning  *	SO_SNDBUF
96fcf3ce44SJohn Forte  *
97fcf3ce44SJohn Forte  *   iscsi_net_poll    - Poll socket interface for a specified amount
98*0f1702c5SYu Xiangning  *		       of data.  If data not received in timeout
99*0f1702c5SYu Xiangning  *		       period fail request.
100fcf3ce44SJohn Forte  *   iscsi_net_sendmsg - Send message on socket connection
101fcf3ce44SJohn Forte  *   iscsi_net_recvmsg - Receive message on socket connection
102fcf3ce44SJohn Forte  *
103fcf3ce44SJohn Forte  *   iscsi_net_sendpdu - Send iSCSI PDU on socket connection
104fcf3ce44SJohn Forte  *   iscsi_net_recvhdr - Receive iSCSI header on socket connection
105fcf3ce44SJohn Forte  *   iscsi_net_recvdata - Receive iSCSI data on socket connection
106fcf3ce44SJohn Forte  *
107fcf3ce44SJohn Forte  *     The iSCSI interfaces have the below optional flags.
108fcf3ce44SJohn Forte  *
109fcf3ce44SJohn Forte  *       ISCSI_NET_HEADER_DIGEST - The interface should either
110fcf3ce44SJohn Forte  *				generate or validate the iSCSI
111fcf3ce44SJohn Forte  *				header digest CRC.
112fcf3ce44SJohn Forte  *       ISCSI_NET_DATA_DIGESt   - The interface should either
113*0f1702c5SYu Xiangning  *			      generate or validate the iSCSI
114*0f1702c5SYu Xiangning  *			      data digest CRC.
115fcf3ce44SJohn Forte  */
116fcf3ce44SJohn Forte 
117fcf3ce44SJohn Forte 
118fcf3ce44SJohn Forte /* global */
119fcf3ce44SJohn Forte iscsi_network_t *iscsi_net;
120fcf3ce44SJohn Forte 
121fcf3ce44SJohn Forte /* consts */
122fcf3ce44SJohn Forte 
123fcf3ce44SJohn Forte /*
124fcf3ce44SJohn Forte  * This table is used for quick validation of incoming
125fcf3ce44SJohn Forte  * iSCSI PDU opcodes.  A value of '0' in the table below
126fcf3ce44SJohn Forte  * indicated that the opcode is invalid for an iSCSI
127fcf3ce44SJohn Forte  * initiator to receive.
128fcf3ce44SJohn Forte  */
129fcf3ce44SJohn Forte const int   is_incoming_opcode_invalid[256] = {
130fcf3ce44SJohn Forte 	/*		0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F */
131fcf3ce44SJohn Forte 	/* 0x0X */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
132fcf3ce44SJohn Forte 	/* 0x1X */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
133fcf3ce44SJohn Forte 	/* 0x2X */	0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
134fcf3ce44SJohn Forte 	/* 0x3X */	1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
135fcf3ce44SJohn Forte 	/* 0x4X */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
136fcf3ce44SJohn Forte 	/* 0x5X */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
137fcf3ce44SJohn Forte 	/* 0x6X */	0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
138fcf3ce44SJohn Forte 	/* 0x7X */	1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
139fcf3ce44SJohn Forte 	/* 0x8X */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
140fcf3ce44SJohn Forte 	/* 0x9X */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
141fcf3ce44SJohn Forte 	/* 0xAX */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
142fcf3ce44SJohn Forte 	/* 0xBX */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
143fcf3ce44SJohn Forte 	/* 0xCX */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
144fcf3ce44SJohn Forte 	/* 0xDX */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
145fcf3ce44SJohn Forte 	/* 0xEX */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
146fcf3ce44SJohn Forte 	/* 0xFX */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
147fcf3ce44SJohn Forte };
1486cefaae1SJack Meng 
1496cefaae1SJack Meng #define	IP_4_BITS	32
1506cefaae1SJack Meng #define	IP_6_BITS	128
1516cefaae1SJack Meng 
1526cefaae1SJack Meng extern int modrootloaded;
153*0f1702c5SYu Xiangning extern ib_boot_prop_t   *iscsiboot_prop;
154fcf3ce44SJohn Forte 
155fcf3ce44SJohn Forte /* prototypes */
1566cefaae1SJack Meng 
1576cefaae1SJack Meng /* for iSCSI boot */
1586cefaae1SJack Meng static int net_up = 0;
1596cefaae1SJack Meng static iscsi_status_t iscsi_net_interface();
1606cefaae1SJack Meng /* boot prototypes end */
1616cefaae1SJack Meng 
162fcf3ce44SJohn Forte static void * iscsi_net_socket(int domain, int type, int protocol);
163fcf3ce44SJohn Forte static int iscsi_net_bind(void *socket, struct sockaddr *
164fcf3ce44SJohn Forte     name, int name_len, int backlog, int flags);
165fcf3ce44SJohn Forte static int iscsi_net_connect(void *socket, struct sockaddr *
166fcf3ce44SJohn Forte     name, int name_len, int fflag, int flags);
167fcf3ce44SJohn Forte static int iscsi_net_listen(void *socket, int backlog);
168fcf3ce44SJohn Forte static void * iscsi_net_accept(void *socket, struct sockaddr *addr,
169fcf3ce44SJohn Forte     int *addr_len);
170*0f1702c5SYu Xiangning static int iscsi_net_getsockname(void *socket, struct sockaddr *, socklen_t *);
171fcf3ce44SJohn Forte static int iscsi_net_getsockopt(void *socket, int level,
172fcf3ce44SJohn Forte     int option_name, void *option_val, int *option_len, int flags);
173fcf3ce44SJohn Forte static int iscsi_net_setsockopt(void *socket, int level,
174fcf3ce44SJohn Forte     int option_name, void *option_val, int option_len);
175fcf3ce44SJohn Forte static int iscsi_net_shutdown(void *socket, int how);
176fcf3ce44SJohn Forte static void iscsi_net_close(void *socket);
177fcf3ce44SJohn Forte 
178fcf3ce44SJohn Forte static size_t iscsi_net_poll(void *socket, clock_t timeout);
179fcf3ce44SJohn Forte static size_t iscsi_net_sendmsg(void *socket, struct msghdr *msg);
180fcf3ce44SJohn Forte static size_t iscsi_net_recvmsg(void *socket,
181fcf3ce44SJohn Forte     struct msghdr *msg, int timeout);
182fcf3ce44SJohn Forte 
183fcf3ce44SJohn Forte static iscsi_status_t iscsi_net_sendpdu(void *socket, iscsi_hdr_t *ihp,
184fcf3ce44SJohn Forte     char *data, int flags);
185fcf3ce44SJohn Forte static iscsi_status_t iscsi_net_recvdata(void *socket, iscsi_hdr_t *ihp,
186fcf3ce44SJohn Forte     char *data, int max_data_length, int timeout, int flags);
187fcf3ce44SJohn Forte static iscsi_status_t iscsi_net_recvhdr(void *socket, iscsi_hdr_t *ihp,
188fcf3ce44SJohn Forte     int header_length, int timeout, int flags);
189fcf3ce44SJohn Forte 
190fcf3ce44SJohn Forte static void iscsi_net_set_preconnect_options(void *socket);
191fcf3ce44SJohn Forte static void iscsi_net_set_postconnect_options(void *socket);
192fcf3ce44SJohn Forte 
193fcf3ce44SJohn Forte /*
194fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
195*0f1702c5SYu Xiangning  * | network interface registration functions			   |
196fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
197fcf3ce44SJohn Forte  */
198fcf3ce44SJohn Forte 
199fcf3ce44SJohn Forte /*
200fcf3ce44SJohn Forte  * iscsi_net_init - initialize network interface
201fcf3ce44SJohn Forte  */
202fcf3ce44SJohn Forte void
203fcf3ce44SJohn Forte iscsi_net_init()
204fcf3ce44SJohn Forte {
205fcf3ce44SJohn Forte 	iscsi_net = kmem_zalloc(sizeof (*iscsi_net), KM_SLEEP);
206fcf3ce44SJohn Forte 
207fcf3ce44SJohn Forte 	iscsi_net->socket	= iscsi_net_socket;
208fcf3ce44SJohn Forte 
209fcf3ce44SJohn Forte 	iscsi_net->bind		= iscsi_net_bind;
210fcf3ce44SJohn Forte 	iscsi_net->connect	= iscsi_net_connect;
211fcf3ce44SJohn Forte 	iscsi_net->listen	= iscsi_net_listen;
212fcf3ce44SJohn Forte 	iscsi_net->accept	= iscsi_net_accept;
213fcf3ce44SJohn Forte 	iscsi_net->shutdown	= iscsi_net_shutdown;
214fcf3ce44SJohn Forte 	iscsi_net->close	= iscsi_net_close;
215fcf3ce44SJohn Forte 
216fcf3ce44SJohn Forte 	iscsi_net->getsockname	= iscsi_net_getsockname;
217fcf3ce44SJohn Forte 	iscsi_net->getsockopt	= iscsi_net_getsockopt;
218fcf3ce44SJohn Forte 	iscsi_net->setsockopt	= iscsi_net_setsockopt;
219fcf3ce44SJohn Forte 
220fcf3ce44SJohn Forte 	iscsi_net->poll		= iscsi_net_poll;
221fcf3ce44SJohn Forte 	iscsi_net->sendmsg	= iscsi_net_sendmsg;
222fcf3ce44SJohn Forte 	iscsi_net->recvmsg	= iscsi_net_recvmsg;
223fcf3ce44SJohn Forte 
224fcf3ce44SJohn Forte 	iscsi_net->sendpdu	= iscsi_net_sendpdu;
225fcf3ce44SJohn Forte 	iscsi_net->recvhdr	= iscsi_net_recvhdr;
226fcf3ce44SJohn Forte 	iscsi_net->recvdata	= iscsi_net_recvdata;
227fcf3ce44SJohn Forte }
228fcf3ce44SJohn Forte 
229fcf3ce44SJohn Forte /*
230fcf3ce44SJohn Forte  * iscsi_net_fini - release network interface
231fcf3ce44SJohn Forte  */
232fcf3ce44SJohn Forte void
233fcf3ce44SJohn Forte iscsi_net_fini()
234fcf3ce44SJohn Forte {
235fcf3ce44SJohn Forte 	kmem_free(iscsi_net, sizeof (*iscsi_net));
236fcf3ce44SJohn Forte 	iscsi_net = NULL;
237fcf3ce44SJohn Forte }
238fcf3ce44SJohn Forte 
239fcf3ce44SJohn Forte 
240fcf3ce44SJohn Forte /*
241fcf3ce44SJohn Forte  * iscsi_net_set_preconnect_options -
242fcf3ce44SJohn Forte  */
243fcf3ce44SJohn Forte static void
244fcf3ce44SJohn Forte iscsi_net_set_preconnect_options(void *socket)
245fcf3ce44SJohn Forte {
246fcf3ce44SJohn Forte 	int ret = 0;
247fcf3ce44SJohn Forte 	ret += iscsi_net->setsockopt(socket, IPPROTO_TCP,
248fcf3ce44SJohn Forte 	    TCP_CONN_NOTIFY_THRESHOLD, (char *)&iscsi_net->tweaks.
249fcf3ce44SJohn Forte 	    conn_notify_threshold, sizeof (int));
250fcf3ce44SJohn Forte 	ret += iscsi_net->setsockopt(socket, IPPROTO_TCP,
251fcf3ce44SJohn Forte 	    TCP_CONN_ABORT_THRESHOLD, (char *)&iscsi_net->tweaks.
252fcf3ce44SJohn Forte 	    conn_abort_threshold, sizeof (int));
253fcf3ce44SJohn Forte 	ret += iscsi_net->setsockopt(socket, IPPROTO_TCP, TCP_ABORT_THRESHOLD,
254fcf3ce44SJohn Forte 	    (char *)&iscsi_net->tweaks.abort_threshold, sizeof (int));
255fcf3ce44SJohn Forte 	if (ret != 0) {
256fcf3ce44SJohn Forte 		cmn_err(CE_NOTE, "iscsi connection failed to set socket option"
257fcf3ce44SJohn Forte 		    "TCP_CONN_NOTIFY_THRESHOLD, TCP_CONN_ABORT_THRESHOLD or "
258fcf3ce44SJohn Forte 		    "TCP_ABORT_THRESHOLD");
259fcf3ce44SJohn Forte 	}
260fcf3ce44SJohn Forte }
261fcf3ce44SJohn Forte 
262fcf3ce44SJohn Forte /*
263fcf3ce44SJohn Forte  * iscsi_net_set_postconnect_options -
264fcf3ce44SJohn Forte  */
265fcf3ce44SJohn Forte static void
266fcf3ce44SJohn Forte iscsi_net_set_postconnect_options(void *socket)
267fcf3ce44SJohn Forte {
268fcf3ce44SJohn Forte 	int ret = 0;
269fcf3ce44SJohn Forte 	ret += iscsi_net->setsockopt(socket, IPPROTO_TCP, TCP_NODELAY,
270fcf3ce44SJohn Forte 	    (char *)&iscsi_net->tweaks.nodelay, sizeof (int));
271fcf3ce44SJohn Forte 	ret += iscsi_net->setsockopt(socket, SOL_SOCKET, SO_RCVBUF,
272fcf3ce44SJohn Forte 	    (char *)&iscsi_net->tweaks.rcvbuf, sizeof (int));
273fcf3ce44SJohn Forte 	ret += iscsi_net->setsockopt(socket, SOL_SOCKET, SO_SNDBUF,
274fcf3ce44SJohn Forte 	    (char *)&iscsi_net->tweaks.sndbuf, sizeof (int));
275fcf3ce44SJohn Forte 	if (ret != 0) {
276fcf3ce44SJohn Forte 		cmn_err(CE_NOTE, "iscsi connection failed to set socket option"
277fcf3ce44SJohn Forte 		    "TCP_NODELAY, SO_RCVBUF or SO_SNDBUF");
278fcf3ce44SJohn Forte 	}
279fcf3ce44SJohn Forte }
280fcf3ce44SJohn Forte 
281fcf3ce44SJohn Forte 
282fcf3ce44SJohn Forte /*
283fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
284*0f1702c5SYu Xiangning  * | register network interfaces					|
285fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
286fcf3ce44SJohn Forte  */
287fcf3ce44SJohn Forte 
288fcf3ce44SJohn Forte /*
289fcf3ce44SJohn Forte  * iscsi_net_socket - create socket
290fcf3ce44SJohn Forte  */
291fcf3ce44SJohn Forte static void *
292fcf3ce44SJohn Forte iscsi_net_socket(int domain, int type, int protocol)
293fcf3ce44SJohn Forte {
294*0f1702c5SYu Xiangning 	ksocket_t	socket;
295*0f1702c5SYu Xiangning 	int 		err	= 0;
296fcf3ce44SJohn Forte 
2976cefaae1SJack Meng 	if (!modrootloaded && !net_up && iscsiboot_prop) {
2986cefaae1SJack Meng 		if (iscsi_net_interface() == ISCSI_STATUS_SUCCESS)
2996cefaae1SJack Meng 			net_up = 1;
3006cefaae1SJack Meng 	}
3016cefaae1SJack Meng 
302*0f1702c5SYu Xiangning 	err = ksocket_socket(&socket, domain, type, protocol, KSOCKET_SLEEP,
303*0f1702c5SYu Xiangning 	    CRED());
304*0f1702c5SYu Xiangning 	if (!err)
305*0f1702c5SYu Xiangning 		return ((void *)socket);
306*0f1702c5SYu Xiangning 	else
307*0f1702c5SYu Xiangning 		return (NULL);
308fcf3ce44SJohn Forte 
309fcf3ce44SJohn Forte }
310fcf3ce44SJohn Forte 
311fcf3ce44SJohn Forte /*
312fcf3ce44SJohn Forte  * iscsi_net_bind - bind socket to a specific sockaddr
313fcf3ce44SJohn Forte  */
314*0f1702c5SYu Xiangning /* ARGSUSED */
315fcf3ce44SJohn Forte static int
316fcf3ce44SJohn Forte iscsi_net_bind(void *socket, struct sockaddr *name, int name_len,
317fcf3ce44SJohn Forte 	int backlog, int flags)
318fcf3ce44SJohn Forte {
319*0f1702c5SYu Xiangning 	ksocket_t ks = (ksocket_t)socket;
320*0f1702c5SYu Xiangning 	int error;
321*0f1702c5SYu Xiangning 	error = ksocket_bind(ks, name, name_len, CRED());
322*0f1702c5SYu Xiangning 	if (error == 0 && backlog != 0)
323*0f1702c5SYu Xiangning 		error = ksocket_listen(ks, backlog, CRED());
324*0f1702c5SYu Xiangning 
325*0f1702c5SYu Xiangning 	return (error);
326fcf3ce44SJohn Forte }
327fcf3ce44SJohn Forte 
328fcf3ce44SJohn Forte /*
329fcf3ce44SJohn Forte  * iscsi_net_connect - connect socket to peer sockaddr
330fcf3ce44SJohn Forte  */
331*0f1702c5SYu Xiangning /* ARGSUSED */
332fcf3ce44SJohn Forte static int
333fcf3ce44SJohn Forte iscsi_net_connect(void *socket, struct sockaddr *name, int name_len,
334fcf3ce44SJohn Forte 	int fflag, int flags)
335fcf3ce44SJohn Forte {
336*0f1702c5SYu Xiangning 	ksocket_t ks = (ksocket_t)socket;
337fcf3ce44SJohn Forte 	int rval;
338fcf3ce44SJohn Forte 
339fcf3ce44SJohn Forte 	iscsi_net_set_preconnect_options(socket);
340*0f1702c5SYu Xiangning 	rval = ksocket_connect(ks, name, name_len, CRED());
341fcf3ce44SJohn Forte 	iscsi_net_set_postconnect_options(socket);
342fcf3ce44SJohn Forte 
343fcf3ce44SJohn Forte 	return (rval);
344fcf3ce44SJohn Forte }
345fcf3ce44SJohn Forte 
346fcf3ce44SJohn Forte /*
347fcf3ce44SJohn Forte  * iscsi_net_listen - listen to socket for peer connections
348fcf3ce44SJohn Forte  */
349fcf3ce44SJohn Forte static int
350fcf3ce44SJohn Forte iscsi_net_listen(void *socket, int backlog)
351fcf3ce44SJohn Forte {
352*0f1702c5SYu Xiangning 	ksocket_t ks = (ksocket_t)socket;
353*0f1702c5SYu Xiangning 	return (ksocket_listen(ks, backlog, CRED()));
354fcf3ce44SJohn Forte }
355fcf3ce44SJohn Forte 
356fcf3ce44SJohn Forte /*
357fcf3ce44SJohn Forte  * iscsi_net_accept - accept peer socket connections
358fcf3ce44SJohn Forte  */
359fcf3ce44SJohn Forte static void *
360fcf3ce44SJohn Forte iscsi_net_accept(void *socket, struct sockaddr *addr, int *addr_len)
361fcf3ce44SJohn Forte {
362*0f1702c5SYu Xiangning 	ksocket_t listen_ks;
363*0f1702c5SYu Xiangning 	ksocket_t ks = (ksocket_t)socket;
364fcf3ce44SJohn Forte 
365*0f1702c5SYu Xiangning 	ksocket_accept(ks, addr, (socklen_t *)addr_len, &listen_ks, CRED());
366*0f1702c5SYu Xiangning 
367*0f1702c5SYu Xiangning 	return ((void *)listen_ks);
368fcf3ce44SJohn Forte }
369fcf3ce44SJohn Forte 
370fcf3ce44SJohn Forte /*
371fcf3ce44SJohn Forte  * iscsi_net_getsockname -
372fcf3ce44SJohn Forte  */
373fcf3ce44SJohn Forte static int
374*0f1702c5SYu Xiangning iscsi_net_getsockname(void *socket, struct sockaddr *addr, socklen_t *addrlen)
375fcf3ce44SJohn Forte {
376*0f1702c5SYu Xiangning 	ksocket_t ks = (ksocket_t)socket;
377*0f1702c5SYu Xiangning 	return (ksocket_getsockname(ks, addr, addrlen, CRED()));
378fcf3ce44SJohn Forte }
379fcf3ce44SJohn Forte 
380fcf3ce44SJohn Forte /*
381fcf3ce44SJohn Forte  * iscsi_net_getsockopt - get value of option on socket
382fcf3ce44SJohn Forte  */
383*0f1702c5SYu Xiangning /* ARGSUSED */
384fcf3ce44SJohn Forte static int
385fcf3ce44SJohn Forte iscsi_net_getsockopt(void *socket, int level, int option_name,
386fcf3ce44SJohn Forte 	void *option_val, int *option_len, int flags)
387fcf3ce44SJohn Forte {
388*0f1702c5SYu Xiangning 	ksocket_t ks = (ksocket_t)socket;
389*0f1702c5SYu Xiangning 	return (ksocket_getsockopt(ks, level, option_name, option_val,
390*0f1702c5SYu Xiangning 	    option_len, CRED()));
391fcf3ce44SJohn Forte }
392fcf3ce44SJohn Forte 
393fcf3ce44SJohn Forte /*
394fcf3ce44SJohn Forte  * iscsi_net_setsockopt - set value for option on socket
395fcf3ce44SJohn Forte  */
396fcf3ce44SJohn Forte static int
397fcf3ce44SJohn Forte iscsi_net_setsockopt(void *socket, int level, int option_name,
398fcf3ce44SJohn Forte 	void *option_val, int option_len)
399fcf3ce44SJohn Forte {
400*0f1702c5SYu Xiangning 	ksocket_t ks = (ksocket_t)socket;
401*0f1702c5SYu Xiangning 	return (ksocket_setsockopt(ks, level, option_name, option_val,
402*0f1702c5SYu Xiangning 	    option_len, CRED()));
403fcf3ce44SJohn Forte }
404fcf3ce44SJohn Forte 
405fcf3ce44SJohn Forte /*
406fcf3ce44SJohn Forte  * iscsi_net_shutdown - shutdown socket connection
407fcf3ce44SJohn Forte  */
408fcf3ce44SJohn Forte static int
409fcf3ce44SJohn Forte iscsi_net_shutdown(void *socket, int how)
410fcf3ce44SJohn Forte {
411*0f1702c5SYu Xiangning 	ksocket_t ks = (ksocket_t)socket;
412*0f1702c5SYu Xiangning 	return (ksocket_shutdown(ks, how, CRED()));
413fcf3ce44SJohn Forte }
414fcf3ce44SJohn Forte 
415fcf3ce44SJohn Forte /*
416fcf3ce44SJohn Forte  * iscsi_net_close - shutdown socket connection and release resources
417fcf3ce44SJohn Forte  */
418fcf3ce44SJohn Forte static void
419fcf3ce44SJohn Forte iscsi_net_close(void *socket)
420fcf3ce44SJohn Forte {
421*0f1702c5SYu Xiangning 	ksocket_t ks = (ksocket_t)socket;
422*0f1702c5SYu Xiangning 	(void) ksocket_close(ks, CRED());
423fcf3ce44SJohn Forte }
424fcf3ce44SJohn Forte 
425fcf3ce44SJohn Forte /*
426fcf3ce44SJohn Forte  * iscsi_net_poll - poll socket for data
427fcf3ce44SJohn Forte  */
428*0f1702c5SYu Xiangning /* ARGSUSED */
429fcf3ce44SJohn Forte static size_t
430fcf3ce44SJohn Forte iscsi_net_poll(void *socket, clock_t timeout)
431fcf3ce44SJohn Forte {
432fcf3ce44SJohn Forte 	int pflag;
433*0f1702c5SYu Xiangning 	char msg[64];
434*0f1702c5SYu Xiangning 	size_t recv = 0;
435*0f1702c5SYu Xiangning 	struct timeval tl;
436*0f1702c5SYu Xiangning 	ksocket_t ks = (ksocket_t)socket;
437*0f1702c5SYu Xiangning 	/* timeout is millisecond */
438*0f1702c5SYu Xiangning 	tl.tv_sec = timeout / 1000;
439*0f1702c5SYu Xiangning 	tl.tv_usec = (timeout % 1000) * 1000;
440*0f1702c5SYu Xiangning 
441*0f1702c5SYu Xiangning 	(void) ksocket_setsockopt(ks, SOL_SOCKET, SO_RCVTIMEO, &tl,
442*0f1702c5SYu Xiangning 	    sizeof (struct timeval), CRED());
443fcf3ce44SJohn Forte 
444fcf3ce44SJohn Forte 	pflag = MSG_ANY;
445*0f1702c5SYu Xiangning 	bzero(msg, sizeof (msg));
446*0f1702c5SYu Xiangning 	return (ksocket_recv(ks, msg, sizeof (msg), pflag, &recv, CRED()));
447fcf3ce44SJohn Forte }
448fcf3ce44SJohn Forte 
449fcf3ce44SJohn Forte /*
450fcf3ce44SJohn Forte  * iscsi_net_sendmsg - send message on socket
451fcf3ce44SJohn Forte  */
452fcf3ce44SJohn Forte /* ARGSUSED */
453fcf3ce44SJohn Forte static size_t
454fcf3ce44SJohn Forte iscsi_net_sendmsg(void *socket, struct msghdr *msg)
455fcf3ce44SJohn Forte {
456*0f1702c5SYu Xiangning 	ksocket_t ks = (ksocket_t)socket;
457*0f1702c5SYu Xiangning 	size_t sent = 0;
458*0f1702c5SYu Xiangning 	int flag = msg->msg_flags;
459*0f1702c5SYu Xiangning 	(void) ksocket_sendmsg(ks, msg, flag, &sent, CRED());
460*0f1702c5SYu Xiangning 	DTRACE_PROBE1(ksocket_sendmsg, size_t, sent);
461*0f1702c5SYu Xiangning 	return (sent);
462fcf3ce44SJohn Forte }
463fcf3ce44SJohn Forte 
464fcf3ce44SJohn Forte /*
465fcf3ce44SJohn Forte  * iscsi_net_recvmsg - receive message on socket
466fcf3ce44SJohn Forte  */
467fcf3ce44SJohn Forte /* ARGSUSED */
468fcf3ce44SJohn Forte static size_t
469fcf3ce44SJohn Forte iscsi_net_recvmsg(void *socket, struct msghdr *msg, int timeout)
470fcf3ce44SJohn Forte {
471*0f1702c5SYu Xiangning 	int		prflag	    = msg->msg_flags;
472*0f1702c5SYu Xiangning 	ksocket_t	ks	    = (ksocket_t)socket;
473*0f1702c5SYu Xiangning 	size_t 		recv	    = 0;
474*0f1702c5SYu Xiangning 	struct timeval	tl;
475*0f1702c5SYu Xiangning 
476*0f1702c5SYu Xiangning 	tl.tv_sec = timeout;
477*0f1702c5SYu Xiangning 	tl.tv_usec = 0;
478*0f1702c5SYu Xiangning 
479*0f1702c5SYu Xiangning 	/* Set recv timeout */
480*0f1702c5SYu Xiangning 	if (ksocket_setsockopt(ks, SOL_SOCKET, SO_RCVTIMEO, &tl,
481*0f1702c5SYu Xiangning 	    sizeof (struct timeval), CRED()))
482*0f1702c5SYu Xiangning 		return (0);
483fcf3ce44SJohn Forte 	/*
484fcf3ce44SJohn Forte 	 * Receive the requested data.  Block until all
485*0f1702c5SYu Xiangning 	 * data is received or timeout.
486fcf3ce44SJohn Forte 	 */
487*0f1702c5SYu Xiangning 	ksocket_recvmsg(ks, msg, prflag, &recv, CRED());
488*0f1702c5SYu Xiangning 	DTRACE_PROBE1(ksocket_recvmsg, size_t, recv);
489*0f1702c5SYu Xiangning 	return (recv);
490fcf3ce44SJohn Forte }
491fcf3ce44SJohn Forte 
492fcf3ce44SJohn Forte /*
493fcf3ce44SJohn Forte  * iscsi_net_sendpdu - send iscsi pdu on socket
494fcf3ce44SJohn Forte  */
495fcf3ce44SJohn Forte static iscsi_status_t
496fcf3ce44SJohn Forte iscsi_net_sendpdu(void *socket, iscsi_hdr_t *ihp, char *data, int flags)
497fcf3ce44SJohn Forte {
498fcf3ce44SJohn Forte 	uint32_t	pad;
499fcf3ce44SJohn Forte 	uint32_t	crc_hdr;
500fcf3ce44SJohn Forte 	uint32_t	crc_data;
501fcf3ce44SJohn Forte 	uint32_t	pad_len;
502fcf3ce44SJohn Forte 	uint32_t	data_len;
503fcf3ce44SJohn Forte 	iovec_t		iovec[ISCSI_MAX_IOVEC];
504fcf3ce44SJohn Forte 	int		iovlen = 0;
505fcf3ce44SJohn Forte 	size_t		total_len = 0;
506fcf3ce44SJohn Forte 	size_t		send_len;
507fcf3ce44SJohn Forte 	struct msghdr	msg;
508fcf3ce44SJohn Forte 
509fcf3ce44SJohn Forte 	ASSERT(socket != NULL);
510fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
511fcf3ce44SJohn Forte 
512fcf3ce44SJohn Forte 	/*
513fcf3ce44SJohn Forte 	 * Let's send the header first.  'hlength' is in 32-bit
514fcf3ce44SJohn Forte 	 * quantities, so we need to multiply by four to get bytes
515fcf3ce44SJohn Forte 	 */
516fcf3ce44SJohn Forte 	ASSERT(iovlen < ISCSI_MAX_IOVEC);
517fcf3ce44SJohn Forte 	iovec[iovlen].iov_base = (void *)ihp;
518fcf3ce44SJohn Forte 	iovec[iovlen].iov_len  = sizeof (*ihp) + ihp->hlength * 4;
519fcf3ce44SJohn Forte 	total_len += sizeof (*ihp) + ihp->hlength * 4;
520fcf3ce44SJohn Forte 	iovlen++;
521fcf3ce44SJohn Forte 
522fcf3ce44SJohn Forte 	/* Let's transmit the header digest if we have to. */
523fcf3ce44SJohn Forte 	if ((flags & ISCSI_NET_HEADER_DIGEST) != 0) {
524fcf3ce44SJohn Forte 		ASSERT(iovlen < ISCSI_MAX_IOVEC);
525fcf3ce44SJohn Forte 		/*
526fcf3ce44SJohn Forte 		 * Converting the calculated CRC via htonl is not
527fcf3ce44SJohn Forte 		 * necessary because iscsi_crc32c calculates
528fcf3ce44SJohn Forte 		 * the value as it expects to be written
529fcf3ce44SJohn Forte 		 */
530fcf3ce44SJohn Forte 		crc_hdr = iscsi_crc32c((char *)ihp,
531fcf3ce44SJohn Forte 		    sizeof (iscsi_hdr_t) + ihp->hlength * 4);
532fcf3ce44SJohn Forte 
533fcf3ce44SJohn Forte 		iovec[iovlen].iov_base = (void *)&crc_hdr;
534fcf3ce44SJohn Forte 		iovec[iovlen].iov_len  = sizeof (crc_hdr);
535fcf3ce44SJohn Forte 		total_len += sizeof (crc_hdr);
536fcf3ce44SJohn Forte 		iovlen++;
537fcf3ce44SJohn Forte 	}
538fcf3ce44SJohn Forte 
539fcf3ce44SJohn Forte 	/* Let's transmit the data if any. */
540fcf3ce44SJohn Forte 	data_len = ntoh24(ihp->dlength);
541fcf3ce44SJohn Forte 
542fcf3ce44SJohn Forte 	if (data_len) {
543fcf3ce44SJohn Forte 
544fcf3ce44SJohn Forte 		ASSERT(iovlen < ISCSI_MAX_IOVEC);
545fcf3ce44SJohn Forte 		iovec[iovlen].iov_base = (void *)data;
546fcf3ce44SJohn Forte 		iovec[iovlen].iov_len  = data_len;
547fcf3ce44SJohn Forte 		total_len += data_len;
548fcf3ce44SJohn Forte 		iovlen++;
549fcf3ce44SJohn Forte 
550fcf3ce44SJohn Forte 		pad_len = ((ISCSI_PAD_WORD_LEN -
551fcf3ce44SJohn Forte 		    (data_len & (ISCSI_PAD_WORD_LEN - 1))) &
552fcf3ce44SJohn Forte 		    (ISCSI_PAD_WORD_LEN - 1));
553fcf3ce44SJohn Forte 
554fcf3ce44SJohn Forte 		/* Let's transmit the data pad if any. */
555fcf3ce44SJohn Forte 		if (pad_len) {
556fcf3ce44SJohn Forte 
557fcf3ce44SJohn Forte 			ASSERT(iovlen < ISCSI_MAX_IOVEC);
558fcf3ce44SJohn Forte 			pad = 0;
559fcf3ce44SJohn Forte 			iovec[iovlen].iov_base = (void *)&pad;
560fcf3ce44SJohn Forte 			iovec[iovlen].iov_len  = pad_len;
561fcf3ce44SJohn Forte 			total_len += pad_len;
562fcf3ce44SJohn Forte 			iovlen++;
563fcf3ce44SJohn Forte 		}
564fcf3ce44SJohn Forte 
565fcf3ce44SJohn Forte 		/* Let's transmit the data digest if we have to. */
566fcf3ce44SJohn Forte 		if ((flags & ISCSI_NET_DATA_DIGEST) != 0) {
567fcf3ce44SJohn Forte 
568fcf3ce44SJohn Forte 			ASSERT(iovlen < ISCSI_MAX_IOVEC);
569fcf3ce44SJohn Forte 			/*
570fcf3ce44SJohn Forte 			 * Converting the calculated CRC via htonl is not
571fcf3ce44SJohn Forte 			 * necessary because iscsi_crc32c calculates the
572fcf3ce44SJohn Forte 			 * value as it expects to be written
573fcf3ce44SJohn Forte 			 */
574fcf3ce44SJohn Forte 			crc_data = iscsi_crc32c(data, data_len);
575fcf3ce44SJohn Forte 			crc_data = iscsi_crc32c_continued(
576fcf3ce44SJohn Forte 			    (char *)&pad, pad_len, crc_data);
577fcf3ce44SJohn Forte 
578fcf3ce44SJohn Forte 			iovec[iovlen].iov_base = (void *)&crc_data;
579fcf3ce44SJohn Forte 			iovec[iovlen].iov_len  = sizeof (crc_data);
580fcf3ce44SJohn Forte 			total_len += sizeof (crc_data);
581fcf3ce44SJohn Forte 			iovlen++;
582fcf3ce44SJohn Forte 		}
583fcf3ce44SJohn Forte 	}
584fcf3ce44SJohn Forte 
585fcf3ce44SJohn Forte 	DTRACE_PROBE4(tx, void *, socket, iovec_t *, &iovec[0],
586fcf3ce44SJohn Forte 	    int, iovlen, int, total_len);
587fcf3ce44SJohn Forte 
588fcf3ce44SJohn Forte 	/* Initialization of the message header. */
589fcf3ce44SJohn Forte 	bzero(&msg, sizeof (msg));
590fcf3ce44SJohn Forte 	msg.msg_iov	= &iovec[0];
591fcf3ce44SJohn Forte 	msg.msg_flags	= MSG_WAITALL;
592fcf3ce44SJohn Forte 	msg.msg_iovlen	= iovlen;
593fcf3ce44SJohn Forte 
594*0f1702c5SYu Xiangning 	send_len = iscsi_net->sendmsg(socket, &msg);
595fcf3ce44SJohn Forte 	DTRACE_PROBE2(sendmsg, size_t, total_len, size_t, send_len);
596fcf3ce44SJohn Forte 	if (total_len != send_len) {
597fcf3ce44SJohn Forte 		return (ISCSI_STATUS_TCP_TX_ERROR);
598fcf3ce44SJohn Forte 	}
599fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
600fcf3ce44SJohn Forte }
601fcf3ce44SJohn Forte 
602fcf3ce44SJohn Forte /*
603fcf3ce44SJohn Forte  * iscsi_net_recvhdr - receive iscsi hdr on socket
604fcf3ce44SJohn Forte  */
605fcf3ce44SJohn Forte static iscsi_status_t
606fcf3ce44SJohn Forte iscsi_net_recvhdr(void *socket, iscsi_hdr_t *ihp, int header_length,
607fcf3ce44SJohn Forte     int timeout, int flags)
608fcf3ce44SJohn Forte {
609fcf3ce44SJohn Forte 	iovec_t		    iov[ISCSI_MAX_IOVEC];
610fcf3ce44SJohn Forte 	int		    iovlen		= 1;
611fcf3ce44SJohn Forte 	int		    total_len		= 0;
612fcf3ce44SJohn Forte 	uint32_t	    crc_actual		= 0;
613fcf3ce44SJohn Forte 	uint32_t	    crc_calculated	= 0;
614fcf3ce44SJohn Forte 	char		    *adhdr		= NULL;
615fcf3ce44SJohn Forte 	int		    adhdr_length	= 0;
616fcf3ce44SJohn Forte 	struct msghdr	    msg;
617fcf3ce44SJohn Forte 	size_t		    recv_len;
618fcf3ce44SJohn Forte 
619fcf3ce44SJohn Forte 	ASSERT(socket != NULL);
620fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
621fcf3ce44SJohn Forte 
622fcf3ce44SJohn Forte 	if (header_length < sizeof (iscsi_hdr_t)) {
623fcf3ce44SJohn Forte 		ASSERT(FALSE);
624fcf3ce44SJohn Forte 		return (ISCSI_STATUS_INTERNAL_ERROR);
625fcf3ce44SJohn Forte 	}
626fcf3ce44SJohn Forte 
627fcf3ce44SJohn Forte 	/*
628fcf3ce44SJohn Forte 	 * Receive primary header
629fcf3ce44SJohn Forte 	 */
630fcf3ce44SJohn Forte 	iov[0].iov_base = (char *)ihp;
631fcf3ce44SJohn Forte 	iov[0].iov_len = sizeof (iscsi_hdr_t);
632fcf3ce44SJohn Forte 
633fcf3ce44SJohn Forte 	bzero(&msg, sizeof (msg));
634fcf3ce44SJohn Forte 	msg.msg_iov	= iov;
635fcf3ce44SJohn Forte 	msg.msg_flags	= MSG_WAITALL;
636fcf3ce44SJohn Forte 	msg.msg_iovlen	= iovlen;
637fcf3ce44SJohn Forte 
638fcf3ce44SJohn Forte 	recv_len = iscsi_net->recvmsg(socket, &msg, timeout);
639fcf3ce44SJohn Forte 	if (recv_len != sizeof (iscsi_hdr_t)) {
640fcf3ce44SJohn Forte 		return (ISCSI_STATUS_TCP_RX_ERROR);
641fcf3ce44SJohn Forte 	}
642fcf3ce44SJohn Forte 
643fcf3ce44SJohn Forte 	DTRACE_PROBE2(rx_hdr, void *, socket, iovec_t *iop, &iov[0]);
644fcf3ce44SJohn Forte 
645fcf3ce44SJohn Forte 	/* verify incoming opcode is a valid operation */
646fcf3ce44SJohn Forte 	if (is_incoming_opcode_invalid[ihp->opcode]) {
647fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%p) protocol error - "
648fcf3ce44SJohn Forte 		    "received an unsupported opcode:0x%02x",
649fcf3ce44SJohn Forte 		    socket, ihp->opcode);
650fcf3ce44SJohn Forte 		return (ISCSI_STATUS_PROTOCOL_ERROR);
651fcf3ce44SJohn Forte 	}
652fcf3ce44SJohn Forte 
653fcf3ce44SJohn Forte 	/*
654fcf3ce44SJohn Forte 	 * Setup receipt of additional header
655fcf3ce44SJohn Forte 	 */
656fcf3ce44SJohn Forte 	if (ihp->hlength > 0) {
657fcf3ce44SJohn Forte 		adhdr = ((char *)ihp) + sizeof (iscsi_hdr_t);
658fcf3ce44SJohn Forte 		adhdr_length = header_length - sizeof (iscsi_hdr_t);
659fcf3ce44SJohn Forte 		/* make sure enough space is available for adhdr */
660fcf3ce44SJohn Forte 		if (ihp->hlength > adhdr_length) {
661fcf3ce44SJohn Forte 			ASSERT(FALSE);
662fcf3ce44SJohn Forte 			return (ISCSI_STATUS_INTERNAL_ERROR);
663fcf3ce44SJohn Forte 		}
664fcf3ce44SJohn Forte 
665fcf3ce44SJohn Forte 		ASSERT(iovlen < ISCSI_MAX_IOVEC);
666fcf3ce44SJohn Forte 		iov[iovlen].iov_base = adhdr;
667fcf3ce44SJohn Forte 		iov[iovlen].iov_len = adhdr_length;
668fcf3ce44SJohn Forte 		total_len += adhdr_length;
669fcf3ce44SJohn Forte 		iovlen++;
670fcf3ce44SJohn Forte 	}
671fcf3ce44SJohn Forte 
672fcf3ce44SJohn Forte 	/*
673fcf3ce44SJohn Forte 	 * Setup receipt of header digest if enabled and connection
674fcf3ce44SJohn Forte 	 * is in full feature mode.
675fcf3ce44SJohn Forte 	 */
676fcf3ce44SJohn Forte 	if ((flags & ISCSI_NET_HEADER_DIGEST) != 0) {
677fcf3ce44SJohn Forte 		ASSERT(iovlen < ISCSI_MAX_IOVEC);
678fcf3ce44SJohn Forte 		iov[iovlen].iov_base = (char *)&crc_actual;
679fcf3ce44SJohn Forte 		iov[iovlen].iov_len = sizeof (uint32_t);
680fcf3ce44SJohn Forte 		total_len += sizeof (uint32_t);
681fcf3ce44SJohn Forte 		iovlen++;
682fcf3ce44SJohn Forte 	}
683fcf3ce44SJohn Forte 
684fcf3ce44SJohn Forte 	/*
685fcf3ce44SJohn Forte 	 * Read additional header and/or header digest if pieces
686fcf3ce44SJohn Forte 	 * are available
687fcf3ce44SJohn Forte 	 */
688fcf3ce44SJohn Forte 	if (iovlen > 1) {
689fcf3ce44SJohn Forte 
690fcf3ce44SJohn Forte 		bzero(&msg, sizeof (msg));
691fcf3ce44SJohn Forte 		msg.msg_iov	= iov;
692fcf3ce44SJohn Forte 		msg.msg_flags	= MSG_WAITALL;
693fcf3ce44SJohn Forte 		msg.msg_iovlen	= iovlen;
694fcf3ce44SJohn Forte 
695fcf3ce44SJohn Forte 		recv_len = iscsi_net->recvmsg(socket, &msg, timeout);
696fcf3ce44SJohn Forte 		if (recv_len != total_len) {
697fcf3ce44SJohn Forte 			return (ISCSI_STATUS_TCP_RX_ERROR);
698fcf3ce44SJohn Forte 		}
699fcf3ce44SJohn Forte 
700fcf3ce44SJohn Forte 		DTRACE_PROBE4(rx_adhdr_digest, void *, socket,
701fcf3ce44SJohn Forte 		    iovec_t *iop, &iov[0], int, iovlen, int, total_len);
702fcf3ce44SJohn Forte 
703fcf3ce44SJohn Forte 		/*
704fcf3ce44SJohn Forte 		 * Verify header digest if enabled and connection
705fcf3ce44SJohn Forte 		 * is in full feature mode
706fcf3ce44SJohn Forte 		 */
707fcf3ce44SJohn Forte 		if ((flags & ISCSI_NET_HEADER_DIGEST) != 0) {
708fcf3ce44SJohn Forte 			crc_calculated = iscsi_crc32c((uchar_t *)ihp,
709fcf3ce44SJohn Forte 			    sizeof (iscsi_hdr_t) + ihp->hlength * 4);
710fcf3ce44SJohn Forte 
711fcf3ce44SJohn Forte 			/*
712fcf3ce44SJohn Forte 			 * Converting actual CRC read via ntohl is not
713fcf3ce44SJohn Forte 			 * necessary because iscsi_crc32c calculates the
714fcf3ce44SJohn Forte 			 * value as it expect to be read
715fcf3ce44SJohn Forte 			 */
716fcf3ce44SJohn Forte 			if (crc_calculated != crc_actual) {
717fcf3ce44SJohn Forte 				/* Invalid Header Digest */
718fcf3ce44SJohn Forte 				cmn_err(CE_WARN, "iscsi connection(%p) "
719fcf3ce44SJohn Forte 				    "protocol error - encountered a header "
720fcf3ce44SJohn Forte 				    "digest error expected:0x%08x "
721fcf3ce44SJohn Forte 				    "received:0x%08x", socket,
722fcf3ce44SJohn Forte 				    crc_calculated, crc_actual);
723fcf3ce44SJohn Forte 				return (ISCSI_STATUS_HEADER_DIGEST_ERROR);
724fcf3ce44SJohn Forte 			}
725fcf3ce44SJohn Forte 		}
726fcf3ce44SJohn Forte 	}
727fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
728fcf3ce44SJohn Forte }
729fcf3ce44SJohn Forte 
730fcf3ce44SJohn Forte 
731fcf3ce44SJohn Forte /*
732fcf3ce44SJohn Forte  * iscsi_net_recvdata - receive iscsi data payload from socket
733fcf3ce44SJohn Forte  */
734fcf3ce44SJohn Forte static iscsi_status_t
735fcf3ce44SJohn Forte iscsi_net_recvdata(void *socket, iscsi_hdr_t *ihp, char *data,
736fcf3ce44SJohn Forte     int max_data_length, int timeout, int flags)
737fcf3ce44SJohn Forte {
738fcf3ce44SJohn Forte 	struct iovec	iov[3];
739fcf3ce44SJohn Forte 	int		iovlen			= 1;
740fcf3ce44SJohn Forte 	int		total_len		= 0;
741fcf3ce44SJohn Forte 	int		dlength			= 0;
742fcf3ce44SJohn Forte 	int		pad_len			= 0;
743fcf3ce44SJohn Forte 	uint8_t		pad[ISCSI_PAD_WORD_LEN];
744fcf3ce44SJohn Forte 	uint32_t	crc_calculated		= 0;
745fcf3ce44SJohn Forte 	uint32_t	crc_actual		= 0;
746fcf3ce44SJohn Forte 	struct msghdr	msg;
747fcf3ce44SJohn Forte 	size_t		recv_len;
748fcf3ce44SJohn Forte 
749fcf3ce44SJohn Forte 	ASSERT(socket != NULL);
750fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
751fcf3ce44SJohn Forte 	ASSERT(data != NULL);
752fcf3ce44SJohn Forte 
753fcf3ce44SJohn Forte 	/* short hand dlength */
754fcf3ce44SJohn Forte 	dlength = ntoh24(ihp->dlength);
755fcf3ce44SJohn Forte 
756fcf3ce44SJohn Forte 	/* verify dlength is valid */
757fcf3ce44SJohn Forte 	if (dlength > max_data_length) {
758fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%p) protocol error - "
759fcf3ce44SJohn Forte 		    "invalid data lengths itt:0x%x received:0x%x "
760fcf3ce44SJohn Forte 		    "max expected:0x%x", socket, ihp->itt,
761fcf3ce44SJohn Forte 		    dlength, max_data_length);
762fcf3ce44SJohn Forte 		return (ISCSI_STATUS_PROTOCOL_ERROR);
763fcf3ce44SJohn Forte 	}
764fcf3ce44SJohn Forte 
765fcf3ce44SJohn Forte 	if (dlength) {
766fcf3ce44SJohn Forte 		/* calculate pad */
767fcf3ce44SJohn Forte 		pad_len = ((ISCSI_PAD_WORD_LEN -
768fcf3ce44SJohn Forte 		    (dlength & (ISCSI_PAD_WORD_LEN - 1))) &
769fcf3ce44SJohn Forte 		    (ISCSI_PAD_WORD_LEN - 1));
770fcf3ce44SJohn Forte 
771fcf3ce44SJohn Forte 		/* setup data iovec */
772fcf3ce44SJohn Forte 		iov[0].iov_base	= (char *)data;
773fcf3ce44SJohn Forte 		iov[0].iov_len	= dlength;
774fcf3ce44SJohn Forte 		total_len	= dlength;
775fcf3ce44SJohn Forte 
776fcf3ce44SJohn Forte 		/* if pad setup pad iovec */
777fcf3ce44SJohn Forte 		if (pad_len) {
778fcf3ce44SJohn Forte 			iov[iovlen].iov_base	= (char *)&pad;
779fcf3ce44SJohn Forte 			iov[iovlen].iov_len	= pad_len;
780fcf3ce44SJohn Forte 			total_len		+= pad_len;
781fcf3ce44SJohn Forte 			iovlen++;
782fcf3ce44SJohn Forte 		}
783fcf3ce44SJohn Forte 
784fcf3ce44SJohn Forte 		/* setup data digest */
785fcf3ce44SJohn Forte 		if ((flags & ISCSI_NET_DATA_DIGEST) != 0) {
786fcf3ce44SJohn Forte 			iov[iovlen].iov_base	= (char *)&crc_actual;
787fcf3ce44SJohn Forte 			iov[iovlen].iov_len	= sizeof (crc_actual);
788fcf3ce44SJohn Forte 			total_len		+= sizeof (crc_actual);
789fcf3ce44SJohn Forte 			iovlen++;
790fcf3ce44SJohn Forte 		}
791fcf3ce44SJohn Forte 
792fcf3ce44SJohn Forte 		bzero(&msg, sizeof (msg));
793fcf3ce44SJohn Forte 		msg.msg_iov	= iov;
794fcf3ce44SJohn Forte 		msg.msg_flags	= MSG_WAITALL;
795fcf3ce44SJohn Forte 		msg.msg_iovlen	= iovlen;
796fcf3ce44SJohn Forte 
797fcf3ce44SJohn Forte 		recv_len = iscsi_net->recvmsg(socket, &msg, timeout);
798fcf3ce44SJohn Forte 		if (recv_len != total_len) {
799fcf3ce44SJohn Forte 			return (ISCSI_STATUS_TCP_RX_ERROR);
800fcf3ce44SJohn Forte 		}
801fcf3ce44SJohn Forte 
802fcf3ce44SJohn Forte 		DTRACE_PROBE4(rx_data, void *, socket, iovec_t *iop,
803fcf3ce44SJohn Forte 		    &iov[0], int, iovlen, int, total_len);
804fcf3ce44SJohn Forte 
805fcf3ce44SJohn Forte 		/* verify data digest is present */
806fcf3ce44SJohn Forte 		if ((flags & ISCSI_NET_DATA_DIGEST) != 0) {
807fcf3ce44SJohn Forte 
808fcf3ce44SJohn Forte 			crc_calculated = iscsi_crc32c(data, dlength);
809fcf3ce44SJohn Forte 			crc_calculated = iscsi_crc32c_continued(
810fcf3ce44SJohn Forte 			    (char *)&pad, pad_len, crc_calculated);
811fcf3ce44SJohn Forte 
812fcf3ce44SJohn Forte 			/*
813fcf3ce44SJohn Forte 			 * Converting actual CRC read via ntohl is not
814fcf3ce44SJohn Forte 			 * necessary because iscsi_crc32c calculates the
815fcf3ce44SJohn Forte 			 * value as it expects to be read
816fcf3ce44SJohn Forte 			 */
817fcf3ce44SJohn Forte 			if (crc_calculated != crc_actual) {
818fcf3ce44SJohn Forte 				cmn_err(CE_WARN, "iscsi connection(%p) "
819fcf3ce44SJohn Forte 				    "protocol error - encountered a data "
820fcf3ce44SJohn Forte 				    "digest error itt:0x%x expected:0x%08x "
821fcf3ce44SJohn Forte 				    "received:0x%08x", socket,
822fcf3ce44SJohn Forte 				    ihp->itt, crc_calculated, crc_actual);
823fcf3ce44SJohn Forte 				return (ISCSI_STATUS_DATA_DIGEST_ERROR);
824fcf3ce44SJohn Forte 			}
825fcf3ce44SJohn Forte 		}
826fcf3ce44SJohn Forte 	}
827fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
828fcf3ce44SJohn Forte }
8296cefaae1SJack Meng 
8306cefaae1SJack Meng /*
8316cefaae1SJack Meng  * Convert a prefix length to a mask.
8326cefaae1SJack Meng  */
8336cefaae1SJack Meng static iscsi_status_t
8346cefaae1SJack Meng iscsi_prefixlentomask(int prefixlen, int maxlen, uchar_t *mask)
8356cefaae1SJack Meng {
8366cefaae1SJack Meng 	if (prefixlen < 0 || prefixlen > maxlen || mask == NULL) {
8376cefaae1SJack Meng 		return (ISCSI_STATUS_INTERNAL_ERROR);
8386cefaae1SJack Meng 	}
8396cefaae1SJack Meng 
8406cefaae1SJack Meng 	while (prefixlen > 0) {
8416cefaae1SJack Meng 		if (prefixlen >= 8) {
8426cefaae1SJack Meng 			*mask = 0xff;
8436cefaae1SJack Meng 			mask++;
8446cefaae1SJack Meng 			prefixlen = prefixlen - 8;
8456cefaae1SJack Meng 			continue;
8466cefaae1SJack Meng 		}
8476cefaae1SJack Meng 		*mask = *mask | (1 << (8 - prefixlen));
8486cefaae1SJack Meng 		prefixlen--;
8496cefaae1SJack Meng 	}
8506cefaae1SJack Meng 	return (ISCSI_STATUS_SUCCESS);
8516cefaae1SJack Meng }
8526cefaae1SJack Meng 
8536cefaae1SJack Meng static iscsi_status_t
8546cefaae1SJack Meng iscsi_net_interface()
8556cefaae1SJack Meng {
8566cefaae1SJack Meng 	struct in_addr	braddr;
8576cefaae1SJack Meng 	struct in_addr	subnet;
8586cefaae1SJack Meng 	struct in_addr	myaddr;
8596cefaae1SJack Meng 	struct in_addr	defgateway;
8606cefaae1SJack Meng 	struct in6_addr myaddr6;
8616cefaae1SJack Meng 	struct in6_addr subnet6;
8626cefaae1SJack Meng 	uchar_t		mask_prefix = 0;
8636cefaae1SJack Meng 	int		mask_bits   = 1;
8646cefaae1SJack Meng 	TIUSER		*tiptr;
8656cefaae1SJack Meng 	TIUSER		*tiptr6;
8666cefaae1SJack Meng 	char		ifname[16]	= {0};
8676cefaae1SJack Meng 	iscsi_status_t	status;
8686cefaae1SJack Meng 
8696cefaae1SJack Meng 	struct knetconfig dl_udp_netconf = {
8706cefaae1SJack Meng 	    NC_TPI_CLTS,
8716cefaae1SJack Meng 	    NC_INET,
8726cefaae1SJack Meng 	    NC_UDP,
8736cefaae1SJack Meng 	    0, };
8746cefaae1SJack Meng 	struct knetconfig dl_udp6_netconf = {
8756cefaae1SJack Meng 	    NC_TPI_CLTS,
8766cefaae1SJack Meng 	    NC_INET6,
8776cefaae1SJack Meng 	    NC_UDP,
8786cefaae1SJack Meng 	    0, };
8796cefaae1SJack Meng 
8806cefaae1SJack Meng 	(void) strlcpy(ifname, rootfs.bo_ifname, sizeof (ifname));
8816cefaae1SJack Meng 
8826cefaae1SJack Meng 	if (iscsiboot_prop->boot_nic.sin_family == AF_INET) {
8836cefaae1SJack Meng 		/*
8846cefaae1SJack Meng 		 * Assumes only one linkage array element.
8856cefaae1SJack Meng 		 */
8866cefaae1SJack Meng 		dl_udp_netconf.knc_rdev =
8876cefaae1SJack Meng 		    makedevice(clone_major, ddi_name_to_major("udp"));
8886cefaae1SJack Meng 
8896cefaae1SJack Meng 		myaddr.s_addr =
8906cefaae1SJack Meng 		    iscsiboot_prop->boot_nic.nic_ip_u.u_in4.s_addr;
8916cefaae1SJack Meng 
8926cefaae1SJack Meng 		mask_prefix = iscsiboot_prop->boot_nic.sub_mask_prefix;
8936cefaae1SJack Meng 		(void) memset(&subnet.s_addr, 0, sizeof (subnet));
8946cefaae1SJack Meng 		status = iscsi_prefixlentomask(mask_prefix, IP_4_BITS,
8956cefaae1SJack Meng 		    (uchar_t *)&subnet.s_addr);
8966cefaae1SJack Meng 		if (status != ISCSI_STATUS_SUCCESS) {
8976cefaae1SJack Meng 			return (status);
8986cefaae1SJack Meng 		}
8996cefaae1SJack Meng 
9006cefaae1SJack Meng 		mask_bits = mask_bits << (IP_4_BITS - mask_prefix);
9016cefaae1SJack Meng 		mask_bits = mask_bits - 1;
9026cefaae1SJack Meng 		/*
9036cefaae1SJack Meng 		 * Set the last mask bits of the ip address with 1, then
9046cefaae1SJack Meng 		 * we can get the broadcast address.
9056cefaae1SJack Meng 		 */
9066cefaae1SJack Meng 		braddr.s_addr = myaddr.s_addr | mask_bits;
9076cefaae1SJack Meng 
9086cefaae1SJack Meng 		defgateway.s_addr =
9096cefaae1SJack Meng 		    iscsiboot_prop->boot_nic.nic_gw_u.u_in4.s_addr;
9106cefaae1SJack Meng 
9116cefaae1SJack Meng 		/* initialize interface */
9126cefaae1SJack Meng 		if (t_kopen((file_t *)NULL, dl_udp_netconf.knc_rdev,
9136cefaae1SJack Meng 		    FREAD|FWRITE, &tiptr, CRED()) == 0) {
9146cefaae1SJack Meng 			if (kdlifconfig(tiptr, AF_INET, &myaddr, &subnet,
9156cefaae1SJack Meng 			    &braddr, &defgateway, ifname)) {
9166cefaae1SJack Meng 				cmn_err(CE_WARN, "Failed to configure"
9176cefaae1SJack Meng 				    " iSCSI boot nic");
9186cefaae1SJack Meng 				(void) t_kclose(tiptr, 0);
9196cefaae1SJack Meng 				return (ISCSI_STATUS_INTERNAL_ERROR);
9206cefaae1SJack Meng 			}
9216cefaae1SJack Meng 		} else {
9226cefaae1SJack Meng 			cmn_err(CE_WARN, "Failed to configure"
9236cefaae1SJack Meng 			    " iSCSI boot nic");
9246cefaae1SJack Meng 			return (ISCSI_STATUS_INTERNAL_ERROR);
9256cefaae1SJack Meng 		}
9266cefaae1SJack Meng 		return (ISCSI_STATUS_SUCCESS);
9276cefaae1SJack Meng 	} else {
9286cefaae1SJack Meng 		dl_udp6_netconf.knc_rdev =
9296cefaae1SJack Meng 		    makedevice(clone_major, ddi_name_to_major("udp6"));
9306cefaae1SJack Meng 
9316cefaae1SJack Meng 		bcopy(&iscsiboot_prop->boot_nic.nic_ip_u.u_in6.s6_addr,
9326cefaae1SJack Meng 		    &myaddr6.s6_addr, 16);
9336cefaae1SJack Meng 
9346cefaae1SJack Meng 		(void) memset(&subnet6, 0, sizeof (subnet6));
9356cefaae1SJack Meng 		mask_prefix = iscsiboot_prop->boot_nic.sub_mask_prefix;
9366cefaae1SJack Meng 		status = iscsi_prefixlentomask(mask_prefix, IP_6_BITS,
9376cefaae1SJack Meng 		    (uchar_t *)&subnet6.s6_addr);
9386cefaae1SJack Meng 		if (status != ISCSI_STATUS_SUCCESS) {
9396cefaae1SJack Meng 			return (status);
9406cefaae1SJack Meng 		}
9416cefaae1SJack Meng 
9426cefaae1SJack Meng 		if (t_kopen((file_t *)NULL, dl_udp6_netconf.knc_rdev,
9436cefaae1SJack Meng 		    FREAD|FWRITE, &tiptr6, CRED()) == 0) {
9446cefaae1SJack Meng 			if (kdlifconfig(tiptr6, AF_INET6, &myaddr6,
9456cefaae1SJack Meng 			    &subnet6, NULL, NULL, ifname)) {
9466cefaae1SJack Meng 				cmn_err(CE_WARN, "Failed to configure"
9476cefaae1SJack Meng 				    " iSCSI boot nic");
9486cefaae1SJack Meng 				(void) t_kclose(tiptr, 0);
9496cefaae1SJack Meng 				return (ISCSI_STATUS_INTERNAL_ERROR);
9506cefaae1SJack Meng 			}
9516cefaae1SJack Meng 		} else {
9526cefaae1SJack Meng 			cmn_err(CE_WARN, "Failed to configure"
9536cefaae1SJack Meng 			    " iSCSI boot nic");
9546cefaae1SJack Meng 			return (ISCSI_STATUS_INTERNAL_ERROR);
9556cefaae1SJack Meng 		}
9566cefaae1SJack Meng 		return (ISCSI_STATUS_SUCCESS);
9576cefaae1SJack Meng 	}
9586cefaae1SJack Meng }
959