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 */
35*6cefaae1SJack Meng #include <sys/bootconf.h>
36*6cefaae1SJack Meng #include <sys/bootprops.h>
37*6cefaae1SJack Meng 
38fcf3ce44SJohn Forte #include "iscsi.h"
39fcf3ce44SJohn Forte 
40fcf3ce44SJohn Forte /*
41fcf3ce44SJohn Forte  * This is a high level description of the default
42fcf3ce44SJohn Forte  * iscsi_net transport interfaces.  These are used
43fcf3ce44SJohn Forte  * to create, send, recv, and close standard TCP/IP
44fcf3ce44SJohn Forte  * messages.  In addition there are extensions to send
45fcf3ce44SJohn Forte  * and recv iSCSI PDU data.
46fcf3ce44SJohn Forte  *
47fcf3ce44SJohn Forte  * NOTE: It would be very easy for an iSCSI HBA vendor
48fcf3ce44SJohn Forte  * to register their own functions over the top of
49fcf3ce44SJohn Forte  * the default interfaces.  This would allow an iSCSI
50fcf3ce44SJohn Forte  * HBA to use the same iscsiadm management interfaces
51fcf3ce44SJohn Forte  * and the Solaris iSCSI session / connection management.
52fcf3ce44SJohn Forte  * The current problem with this approach is we only
53fcf3ce44SJohn Forte  * allow one one registered transport table.  This
54fcf3ce44SJohn Forte  * would be pretty easy to correct although will require
55fcf3ce44SJohn Forte  * additional CLI changes to manage multiple interfaces.
56fcf3ce44SJohn Forte  * If a vendor can present compelling performance data,
57fcf3ce44SJohn Forte  * then Sun will be willing to enhance this support for
58fcf3ce44SJohn Forte  * multiple interface tables and better CLI management.
59fcf3ce44SJohn Forte  *
60fcf3ce44SJohn Forte  * The following listing describes the iscsi_net
61fcf3ce44SJohn Forte  * entry points:
62fcf3ce44SJohn Forte  *
63fcf3ce44SJohn Forte  *   socket            - Creates TCP/IP socket connection.  In the
64fcf3ce44SJohn Forte  *                       default implementation creates a sonode
65fcf3ce44SJohn Forte  *                       via the sockfs kernel layer.
66fcf3ce44SJohn Forte  *   bind              - Performs standard TCP/IP BSD operation.  In
67fcf3ce44SJohn Forte  *                       the default implementation this only act
68fcf3ce44SJohn Forte  *                       as a soft binding based on the IP and routing
69fcf3ce44SJohn Forte  *	                 tables.  It would be preferred if this was
70fcf3ce44SJohn Forte  *	                 a hard binding but that is currently not
71fcf3ce44SJohn Forte  *	                 possible with Solaris's networking stack.
72fcf3ce44SJohn Forte  *   connect           - Performs standard TCP/IP BSD operation.  This
73fcf3ce44SJohn Forte  *                       establishes the TCP SYN to the peer IP address.
74fcf3ce44SJohn Forte  *   listen            - Performs standard TCP/IP BSD operation.  This
75fcf3ce44SJohn Forte  *                       listens for incoming peer connections.
76fcf3ce44SJohn Forte  *   accept            - Performs standard TCP/IP BSD operation.  This
77fcf3ce44SJohn Forte  *                       accepts incoming peer connections.
78fcf3ce44SJohn Forte  *   shutdown          - This disconnects the TCP/IP connection while
79fcf3ce44SJohn Forte  *                       maintaining the resources.
80fcf3ce44SJohn Forte  *   close             - This disconnects the TCP/IP connection and
81fcf3ce44SJohn Forte  *                       releases the resources.
82fcf3ce44SJohn Forte  *
83fcf3ce44SJohn Forte  *   getsockopt        - Gets socket option for specified socket.
84fcf3ce44SJohn Forte  *   setsockopt        - Sets socket option for specified socket.
85fcf3ce44SJohn Forte  *
86fcf3ce44SJohn Forte  *      The current socket options that are used by the initiator
87fcf3ce44SJohn Forte  *      are listed below.
88fcf3ce44SJohn Forte  *
89fcf3ce44SJohn Forte  *        TCP_CONN_NOTIFY_THRESHOLD
90fcf3ce44SJohn Forte  *        TCP_CONN_ABORT_THRESHOLD
91fcf3ce44SJohn Forte  *        TCP_ABORT_THRESHOLD
92fcf3ce44SJohn Forte  *        TCP_NODELAY
93fcf3ce44SJohn Forte  *        SO_RCVBUF
94fcf3ce44SJohn Forte  *        SO_SNDBUF
95fcf3ce44SJohn Forte  *
96fcf3ce44SJohn Forte  *   iscsi_net_poll    - Poll socket interface for a specified amount
97fcf3ce44SJohn Forte  *                       of data.  If data not received in timeout
98fcf3ce44SJohn Forte  *                       period fail request.
99fcf3ce44SJohn Forte  *   iscsi_net_sendmsg - Send message on socket connection
100fcf3ce44SJohn Forte  *   iscsi_net_recvmsg - Receive message on socket connection
101fcf3ce44SJohn Forte  *
102fcf3ce44SJohn Forte  *   iscsi_net_sendpdu - Send iSCSI PDU on socket connection
103fcf3ce44SJohn Forte  *   iscsi_net_recvhdr - Receive iSCSI header on socket connection
104fcf3ce44SJohn Forte  *   iscsi_net_recvdata - Receive iSCSI data on socket connection
105fcf3ce44SJohn Forte  *
106fcf3ce44SJohn Forte  *     The iSCSI interfaces have the below optional flags.
107fcf3ce44SJohn Forte  *
108fcf3ce44SJohn Forte  *       ISCSI_NET_HEADER_DIGEST - The interface should either
109fcf3ce44SJohn Forte  *				generate or validate the iSCSI
110fcf3ce44SJohn Forte  *				header digest CRC.
111fcf3ce44SJohn Forte  *       ISCSI_NET_DATA_DIGESt   - The interface should either
112fcf3ce44SJohn Forte  *                              generate or validate the iSCSI
113fcf3ce44SJohn Forte  *                              data digest CRC.
114fcf3ce44SJohn Forte  */
115fcf3ce44SJohn Forte 
116fcf3ce44SJohn Forte 
117fcf3ce44SJohn Forte /* global */
118fcf3ce44SJohn Forte iscsi_network_t *iscsi_net;
119fcf3ce44SJohn Forte 
120fcf3ce44SJohn Forte /* consts */
121fcf3ce44SJohn Forte 
122fcf3ce44SJohn Forte /*
123fcf3ce44SJohn Forte  * This table is used for quick validation of incoming
124fcf3ce44SJohn Forte  * iSCSI PDU opcodes.  A value of '0' in the table below
125fcf3ce44SJohn Forte  * indicated that the opcode is invalid for an iSCSI
126fcf3ce44SJohn Forte  * initiator to receive.
127fcf3ce44SJohn Forte  */
128fcf3ce44SJohn Forte const int   is_incoming_opcode_invalid[256] = {
129fcf3ce44SJohn Forte 	/*		0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F */
130fcf3ce44SJohn Forte 	/* 0x0X */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
131fcf3ce44SJohn Forte 	/* 0x1X */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
132fcf3ce44SJohn Forte 	/* 0x2X */	0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
133fcf3ce44SJohn Forte 	/* 0x3X */	1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
134fcf3ce44SJohn Forte 	/* 0x4X */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
135fcf3ce44SJohn Forte 	/* 0x5X */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
136fcf3ce44SJohn Forte 	/* 0x6X */	0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
137fcf3ce44SJohn Forte 	/* 0x7X */	1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
138fcf3ce44SJohn Forte 	/* 0x8X */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
139fcf3ce44SJohn Forte 	/* 0x9X */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
140fcf3ce44SJohn Forte 	/* 0xAX */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
141fcf3ce44SJohn Forte 	/* 0xBX */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
142fcf3ce44SJohn Forte 	/* 0xCX */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
143fcf3ce44SJohn Forte 	/* 0xDX */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
144fcf3ce44SJohn Forte 	/* 0xEX */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
145fcf3ce44SJohn Forte 	/* 0xFX */	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
146fcf3ce44SJohn Forte };
147*6cefaae1SJack Meng /*
148*6cefaae1SJack Meng  * Define macros to manipulate snode, vnode, and open device flags
149*6cefaae1SJack Meng  */
150*6cefaae1SJack Meng #define	VTYP_VALID(i)	(((i) == VCHR) || ((i) == VBLK))
151*6cefaae1SJack Meng #define	STYP_VALID(i)	(((i) == S_IFCHR) || ((i) == S_IFBLK))
152*6cefaae1SJack Meng #define	STYP_TO_VTYP(i)	(((i) == S_IFCHR) ? VCHR : VBLK)
153*6cefaae1SJack Meng 
154*6cefaae1SJack Meng #define	IP_4_BITS	32
155*6cefaae1SJack Meng #define	IP_6_BITS	128
156*6cefaae1SJack Meng 
157*6cefaae1SJack Meng extern int modrootloaded;
158*6cefaae1SJack Meng extern ib_boot_prop_t	*iscsiboot_prop;
159fcf3ce44SJohn Forte 
160fcf3ce44SJohn Forte /* prototypes */
161*6cefaae1SJack Meng 
162*6cefaae1SJack Meng /* for iSCSI boot */
163*6cefaae1SJack Meng static int net_up = 0;
164*6cefaae1SJack Meng static iscsi_status_t iscsi_net_interface();
165*6cefaae1SJack Meng static int iscsi_ldi_vp_from_name(char *path, vnode_t **vpp);
166*6cefaae1SJack Meng /* boot prototypes end */
167*6cefaae1SJack Meng 
168fcf3ce44SJohn Forte static void * iscsi_net_socket(int domain, int type, int protocol);
169fcf3ce44SJohn Forte static int iscsi_net_bind(void *socket, struct sockaddr *
170fcf3ce44SJohn Forte     name, int name_len, int backlog, int flags);
171fcf3ce44SJohn Forte static int iscsi_net_connect(void *socket, struct sockaddr *
172fcf3ce44SJohn Forte     name, int name_len, int fflag, int flags);
173fcf3ce44SJohn Forte static int iscsi_net_listen(void *socket, int backlog);
174fcf3ce44SJohn Forte static void * iscsi_net_accept(void *socket, struct sockaddr *addr,
175fcf3ce44SJohn Forte     int *addr_len);
176fcf3ce44SJohn Forte static int iscsi_net_getsockname(void *socket);
177fcf3ce44SJohn Forte static int iscsi_net_getsockopt(void *socket, int level,
178fcf3ce44SJohn Forte     int option_name, void *option_val, int *option_len, int flags);
179fcf3ce44SJohn Forte static int iscsi_net_setsockopt(void *socket, int level,
180fcf3ce44SJohn Forte     int option_name, void *option_val, int option_len);
181fcf3ce44SJohn Forte static int iscsi_net_shutdown(void *socket, int how);
182fcf3ce44SJohn Forte static void iscsi_net_close(void *socket);
183fcf3ce44SJohn Forte 
184fcf3ce44SJohn Forte static size_t iscsi_net_poll(void *socket, clock_t timeout);
185fcf3ce44SJohn Forte static size_t iscsi_net_sendmsg(void *socket, struct msghdr *msg);
186fcf3ce44SJohn Forte static size_t iscsi_net_recvmsg(void *socket,
187fcf3ce44SJohn Forte     struct msghdr *msg, int timeout);
188fcf3ce44SJohn Forte 
189fcf3ce44SJohn Forte static iscsi_status_t iscsi_net_sendpdu(void *socket, iscsi_hdr_t *ihp,
190fcf3ce44SJohn Forte     char *data, int flags);
191fcf3ce44SJohn Forte static iscsi_status_t iscsi_net_recvdata(void *socket, iscsi_hdr_t *ihp,
192fcf3ce44SJohn Forte     char *data, int max_data_length, int timeout, int flags);
193fcf3ce44SJohn Forte static iscsi_status_t iscsi_net_recvhdr(void *socket, iscsi_hdr_t *ihp,
194fcf3ce44SJohn Forte     int header_length, int timeout, int flags);
195fcf3ce44SJohn Forte 
196fcf3ce44SJohn Forte static void iscsi_net_set_preconnect_options(void *socket);
197fcf3ce44SJohn Forte static void iscsi_net_set_postconnect_options(void *socket);
198fcf3ce44SJohn Forte 
199fcf3ce44SJohn Forte /*
200fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
201fcf3ce44SJohn Forte  * | network interface registration functions                           |
202fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
203fcf3ce44SJohn Forte  */
204fcf3ce44SJohn Forte 
205fcf3ce44SJohn Forte /*
206fcf3ce44SJohn Forte  * iscsi_net_init - initialize network interface
207fcf3ce44SJohn Forte  */
208fcf3ce44SJohn Forte void
209fcf3ce44SJohn Forte iscsi_net_init()
210fcf3ce44SJohn Forte {
211fcf3ce44SJohn Forte 	iscsi_net = kmem_zalloc(sizeof (*iscsi_net), KM_SLEEP);
212fcf3ce44SJohn Forte 
213fcf3ce44SJohn Forte 	iscsi_net->socket	= iscsi_net_socket;
214fcf3ce44SJohn Forte 
215fcf3ce44SJohn Forte 	iscsi_net->bind		= iscsi_net_bind;
216fcf3ce44SJohn Forte 	iscsi_net->connect	= iscsi_net_connect;
217fcf3ce44SJohn Forte 	iscsi_net->listen	= iscsi_net_listen;
218fcf3ce44SJohn Forte 	iscsi_net->accept	= iscsi_net_accept;
219fcf3ce44SJohn Forte 	iscsi_net->shutdown	= iscsi_net_shutdown;
220fcf3ce44SJohn Forte 	iscsi_net->close	= iscsi_net_close;
221fcf3ce44SJohn Forte 
222fcf3ce44SJohn Forte 	iscsi_net->getsockname	= iscsi_net_getsockname;
223fcf3ce44SJohn Forte 	iscsi_net->getsockopt	= iscsi_net_getsockopt;
224fcf3ce44SJohn Forte 	iscsi_net->setsockopt	= iscsi_net_setsockopt;
225fcf3ce44SJohn Forte 
226fcf3ce44SJohn Forte 	iscsi_net->poll		= iscsi_net_poll;
227fcf3ce44SJohn Forte 	iscsi_net->sendmsg	= iscsi_net_sendmsg;
228fcf3ce44SJohn Forte 	iscsi_net->recvmsg	= iscsi_net_recvmsg;
229fcf3ce44SJohn Forte 
230fcf3ce44SJohn Forte 	iscsi_net->sendpdu	= iscsi_net_sendpdu;
231fcf3ce44SJohn Forte 	iscsi_net->recvhdr	= iscsi_net_recvhdr;
232fcf3ce44SJohn Forte 	iscsi_net->recvdata	= iscsi_net_recvdata;
233fcf3ce44SJohn Forte }
234fcf3ce44SJohn Forte 
235fcf3ce44SJohn Forte /*
236fcf3ce44SJohn Forte  * iscsi_net_fini - release network interface
237fcf3ce44SJohn Forte  */
238fcf3ce44SJohn Forte void
239fcf3ce44SJohn Forte iscsi_net_fini()
240fcf3ce44SJohn Forte {
241fcf3ce44SJohn Forte 	kmem_free(iscsi_net, sizeof (*iscsi_net));
242fcf3ce44SJohn Forte 	iscsi_net = NULL;
243fcf3ce44SJohn Forte }
244fcf3ce44SJohn Forte 
245fcf3ce44SJohn Forte 
246fcf3ce44SJohn Forte /*
247fcf3ce44SJohn Forte  * iscsi_net_set_preconnect_options -
248fcf3ce44SJohn Forte  */
249fcf3ce44SJohn Forte static void
250fcf3ce44SJohn Forte iscsi_net_set_preconnect_options(void *socket)
251fcf3ce44SJohn Forte {
252fcf3ce44SJohn Forte 	int ret = 0;
253fcf3ce44SJohn Forte 	ret += iscsi_net->setsockopt(socket, IPPROTO_TCP,
254fcf3ce44SJohn Forte 	    TCP_CONN_NOTIFY_THRESHOLD, (char *)&iscsi_net->tweaks.
255fcf3ce44SJohn Forte 	    conn_notify_threshold, sizeof (int));
256fcf3ce44SJohn Forte 	ret += iscsi_net->setsockopt(socket, IPPROTO_TCP,
257fcf3ce44SJohn Forte 	    TCP_CONN_ABORT_THRESHOLD, (char *)&iscsi_net->tweaks.
258fcf3ce44SJohn Forte 	    conn_abort_threshold, sizeof (int));
259fcf3ce44SJohn Forte 	ret += iscsi_net->setsockopt(socket, IPPROTO_TCP, TCP_ABORT_THRESHOLD,
260fcf3ce44SJohn Forte 	    (char *)&iscsi_net->tweaks.abort_threshold, sizeof (int));
261fcf3ce44SJohn Forte 	if (ret != 0) {
262fcf3ce44SJohn Forte 		cmn_err(CE_NOTE, "iscsi connection failed to set socket option"
263fcf3ce44SJohn Forte 		    "TCP_CONN_NOTIFY_THRESHOLD, TCP_CONN_ABORT_THRESHOLD or "
264fcf3ce44SJohn Forte 		    "TCP_ABORT_THRESHOLD");
265fcf3ce44SJohn Forte 	}
266fcf3ce44SJohn Forte }
267fcf3ce44SJohn Forte 
268fcf3ce44SJohn Forte /*
269fcf3ce44SJohn Forte  * iscsi_net_set_postconnect_options -
270fcf3ce44SJohn Forte  */
271fcf3ce44SJohn Forte static void
272fcf3ce44SJohn Forte iscsi_net_set_postconnect_options(void *socket)
273fcf3ce44SJohn Forte {
274fcf3ce44SJohn Forte 	int ret = 0;
275fcf3ce44SJohn Forte 	ret += iscsi_net->setsockopt(socket, IPPROTO_TCP, TCP_NODELAY,
276fcf3ce44SJohn Forte 	    (char *)&iscsi_net->tweaks.nodelay, sizeof (int));
277fcf3ce44SJohn Forte 	ret += iscsi_net->setsockopt(socket, SOL_SOCKET, SO_RCVBUF,
278fcf3ce44SJohn Forte 	    (char *)&iscsi_net->tweaks.rcvbuf, sizeof (int));
279fcf3ce44SJohn Forte 	ret += iscsi_net->setsockopt(socket, SOL_SOCKET, SO_SNDBUF,
280fcf3ce44SJohn Forte 	    (char *)&iscsi_net->tweaks.sndbuf, sizeof (int));
281fcf3ce44SJohn Forte 	if (ret != 0) {
282fcf3ce44SJohn Forte 		cmn_err(CE_NOTE, "iscsi connection failed to set socket option"
283fcf3ce44SJohn Forte 		    "TCP_NODELAY, SO_RCVBUF or SO_SNDBUF");
284fcf3ce44SJohn Forte 	}
285fcf3ce44SJohn Forte }
286fcf3ce44SJohn Forte 
287fcf3ce44SJohn Forte 
288fcf3ce44SJohn Forte /*
289fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
290fcf3ce44SJohn Forte  * | register network interfaces                                        |
291fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
292fcf3ce44SJohn Forte  */
293fcf3ce44SJohn Forte 
294fcf3ce44SJohn Forte /*
295fcf3ce44SJohn Forte  * iscsi_net_socket - create socket
296fcf3ce44SJohn Forte  */
297fcf3ce44SJohn Forte static void *
298fcf3ce44SJohn Forte iscsi_net_socket(int domain, int type, int protocol)
299fcf3ce44SJohn Forte {
300fcf3ce44SJohn Forte 	vnode_t		*dvp		= NULL,
301fcf3ce44SJohn Forte 	    *vp		= NULL;
302fcf3ce44SJohn Forte 	struct snode	*csp		= NULL;
303fcf3ce44SJohn Forte 	int		err		= 0;
304fcf3ce44SJohn Forte 	major_t		maj;
305fcf3ce44SJohn Forte 
306*6cefaae1SJack Meng 	if (!modrootloaded && !net_up && iscsiboot_prop) {
307*6cefaae1SJack Meng 		if (iscsi_net_interface() == ISCSI_STATUS_SUCCESS)
308*6cefaae1SJack Meng 			net_up = 1;
309*6cefaae1SJack Meng 	}
310*6cefaae1SJack Meng 
311fcf3ce44SJohn Forte 	/* ---- solookup: start ---- */
312fcf3ce44SJohn Forte 	if ((vp = solookup(domain, type, protocol, NULL, &err)) == NULL) {
313fcf3ce44SJohn Forte 
314fcf3ce44SJohn Forte 		/*
315fcf3ce44SJohn Forte 		 * solookup calls sogetvp if the vp is not found in
316fcf3ce44SJohn Forte 		 * the cache.  Since the call to sogetvp is hardwired
317fcf3ce44SJohn Forte 		 * to use USERSPACE and declared static we'll do the
318fcf3ce44SJohn Forte 		 * work here instead.
319fcf3ce44SJohn Forte 		 */
320*6cefaae1SJack Meng 		if (!modrootloaded) {
321*6cefaae1SJack Meng 			err = iscsi_ldi_vp_from_name("/devices/pseudo/tcp@0:"
322*6cefaae1SJack Meng 			    "tcp", &vp);
323*6cefaae1SJack Meng 		} else {
324*6cefaae1SJack Meng 			err = lookupname(type == SOCK_STREAM ? "/dev/tcp" :
325*6cefaae1SJack Meng 			    "/dev/udp", UIO_SYSSPACE, FOLLOW, NULLVPP, &vp);
326*6cefaae1SJack Meng 		}
327*6cefaae1SJack Meng 		if (err) {
328fcf3ce44SJohn Forte 			return (NULL);
329*6cefaae1SJack Meng 		}
330fcf3ce44SJohn Forte 
331fcf3ce44SJohn Forte 		/* ---- check that it is the correct vnode ---- */
332fcf3ce44SJohn Forte 		if (vp->v_type != VCHR) {
333fcf3ce44SJohn Forte 			VN_RELE(vp);
334fcf3ce44SJohn Forte 			return (NULL);
335fcf3ce44SJohn Forte 		}
336fcf3ce44SJohn Forte 
337fcf3ce44SJohn Forte 		csp = VTOS(VTOS(vp)->s_commonvp);
338fcf3ce44SJohn Forte 		if (!(csp->s_flag & SDIPSET)) {
339fcf3ce44SJohn Forte 			char    *pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
340fcf3ce44SJohn Forte 			err = ddi_dev_pathname(vp->v_rdev, S_IFCHR,
341fcf3ce44SJohn Forte 			    pathname);
342fcf3ce44SJohn Forte 			if (err == 0) {
343fcf3ce44SJohn Forte 				err = devfs_lookupname(pathname, NULLVPP,
344fcf3ce44SJohn Forte 				    &dvp);
345fcf3ce44SJohn Forte 			}
346fcf3ce44SJohn Forte 			VN_RELE(vp);
347fcf3ce44SJohn Forte 			kmem_free(pathname, MAXPATHLEN);
348fcf3ce44SJohn Forte 			if (err != 0) {
349fcf3ce44SJohn Forte 				return (NULL);
350fcf3ce44SJohn Forte 			}
351fcf3ce44SJohn Forte 			vp = dvp;
352fcf3ce44SJohn Forte 		}
353fcf3ce44SJohn Forte 
354fcf3ce44SJohn Forte 		maj = getmajor(vp->v_rdev);
355fcf3ce44SJohn Forte 		if (!STREAMSTAB(maj)) {
356fcf3ce44SJohn Forte 			VN_RELE(vp);
357fcf3ce44SJohn Forte 			return (NULL);
358fcf3ce44SJohn Forte 		}
359fcf3ce44SJohn Forte 	}
360fcf3ce44SJohn Forte 	/* ---- solookup: end ---- */
361fcf3ce44SJohn Forte 	return (socreate(vp, domain, type, protocol, SOV_DEFAULT, NULL, &err));
362fcf3ce44SJohn Forte }
363fcf3ce44SJohn Forte 
364fcf3ce44SJohn Forte /*
365fcf3ce44SJohn Forte  * iscsi_net_bind - bind socket to a specific sockaddr
366fcf3ce44SJohn Forte  */
367fcf3ce44SJohn Forte static int
368fcf3ce44SJohn Forte iscsi_net_bind(void *socket, struct sockaddr *name, int name_len,
369fcf3ce44SJohn Forte 	int backlog, int flags)
370fcf3ce44SJohn Forte {
371fcf3ce44SJohn Forte 	return (sobind((struct sonode *)socket, name, name_len,
372fcf3ce44SJohn Forte 	    backlog, flags));
373fcf3ce44SJohn Forte }
374fcf3ce44SJohn Forte 
375fcf3ce44SJohn Forte /*
376fcf3ce44SJohn Forte  * iscsi_net_connect - connect socket to peer sockaddr
377fcf3ce44SJohn Forte  */
378fcf3ce44SJohn Forte static int
379fcf3ce44SJohn Forte iscsi_net_connect(void *socket, struct sockaddr *name, int name_len,
380fcf3ce44SJohn Forte 	int fflag, int flags)
381fcf3ce44SJohn Forte {
382fcf3ce44SJohn Forte 	int rval;
383fcf3ce44SJohn Forte 
384fcf3ce44SJohn Forte 	iscsi_net_set_preconnect_options(socket);
385fcf3ce44SJohn Forte 	rval = soconnect((struct sonode *)socket, name,
386fcf3ce44SJohn Forte 	    name_len, fflag, flags);
387fcf3ce44SJohn Forte 	iscsi_net_set_postconnect_options(socket);
388fcf3ce44SJohn Forte 
389fcf3ce44SJohn Forte 	return (rval);
390fcf3ce44SJohn Forte }
391fcf3ce44SJohn Forte 
392fcf3ce44SJohn Forte /*
393fcf3ce44SJohn Forte  * iscsi_net_listen - listen to socket for peer connections
394fcf3ce44SJohn Forte  */
395fcf3ce44SJohn Forte static int
396fcf3ce44SJohn Forte iscsi_net_listen(void *socket, int backlog)
397fcf3ce44SJohn Forte {
398fcf3ce44SJohn Forte 	return (solisten((struct sonode *)socket, backlog));
399fcf3ce44SJohn Forte }
400fcf3ce44SJohn Forte 
401fcf3ce44SJohn Forte /*
402fcf3ce44SJohn Forte  * iscsi_net_accept - accept peer socket connections
403fcf3ce44SJohn Forte  */
404fcf3ce44SJohn Forte static void *
405fcf3ce44SJohn Forte iscsi_net_accept(void *socket, struct sockaddr *addr, int *addr_len)
406fcf3ce44SJohn Forte {
407fcf3ce44SJohn Forte 	struct sonode *listening_socket;
408fcf3ce44SJohn Forte 
409fcf3ce44SJohn Forte 	(void) soaccept((struct sonode *)socket,
410fcf3ce44SJohn Forte 	    ((struct sonode *)socket)->so_flag,
411fcf3ce44SJohn Forte 	    &listening_socket);
412fcf3ce44SJohn Forte 	if (listening_socket != NULL) {
413fcf3ce44SJohn Forte 		bcopy(listening_socket->so_faddr_sa, addr,
414fcf3ce44SJohn Forte 		    (socklen_t)listening_socket->so_faddr_len);
415fcf3ce44SJohn Forte 		*addr_len = listening_socket->so_faddr_len;
416fcf3ce44SJohn Forte 	} else {
417fcf3ce44SJohn Forte 		*addr_len = 0;
418fcf3ce44SJohn Forte 	}
419fcf3ce44SJohn Forte 
420fcf3ce44SJohn Forte 	return ((void *)listening_socket);
421fcf3ce44SJohn Forte }
422fcf3ce44SJohn Forte 
423fcf3ce44SJohn Forte /*
424fcf3ce44SJohn Forte  * iscsi_net_getsockname -
425fcf3ce44SJohn Forte  */
426fcf3ce44SJohn Forte static int
427fcf3ce44SJohn Forte iscsi_net_getsockname(void *socket)
428fcf3ce44SJohn Forte {
429fcf3ce44SJohn Forte 	return (sogetsockname((struct sonode *)socket));
430fcf3ce44SJohn Forte }
431fcf3ce44SJohn Forte 
432fcf3ce44SJohn Forte /*
433fcf3ce44SJohn Forte  * iscsi_net_getsockopt - get value of option on socket
434fcf3ce44SJohn Forte  */
435fcf3ce44SJohn Forte static int
436fcf3ce44SJohn Forte iscsi_net_getsockopt(void *socket, int level, int option_name,
437fcf3ce44SJohn Forte 	void *option_val, int *option_len, int flags)
438fcf3ce44SJohn Forte {
439fcf3ce44SJohn Forte 	return (sogetsockopt((struct sonode *)socket, level,
440fcf3ce44SJohn Forte 	    option_name, option_val, (socklen_t *)option_len,
441fcf3ce44SJohn Forte 	    flags));
442fcf3ce44SJohn Forte }
443fcf3ce44SJohn Forte 
444fcf3ce44SJohn Forte /*
445fcf3ce44SJohn Forte  * iscsi_net_setsockopt - set value for option on socket
446fcf3ce44SJohn Forte  */
447fcf3ce44SJohn Forte static int
448fcf3ce44SJohn Forte iscsi_net_setsockopt(void *socket, int level, int option_name,
449fcf3ce44SJohn Forte 	void *option_val, int option_len)
450fcf3ce44SJohn Forte {
451fcf3ce44SJohn Forte 	return (sosetsockopt((struct sonode *)socket, level,
452fcf3ce44SJohn Forte 	    option_name, option_val, option_len));
453fcf3ce44SJohn Forte }
454fcf3ce44SJohn Forte 
455fcf3ce44SJohn Forte /*
456fcf3ce44SJohn Forte  * iscsi_net_shutdown - shutdown socket connection
457fcf3ce44SJohn Forte  */
458fcf3ce44SJohn Forte static int
459fcf3ce44SJohn Forte iscsi_net_shutdown(void *socket, int how)
460fcf3ce44SJohn Forte {
461fcf3ce44SJohn Forte 	return (soshutdown((struct sonode *)socket, how));
462fcf3ce44SJohn Forte }
463fcf3ce44SJohn Forte 
464fcf3ce44SJohn Forte /*
465fcf3ce44SJohn Forte  * iscsi_net_close - shutdown socket connection and release resources
466fcf3ce44SJohn Forte  */
467fcf3ce44SJohn Forte static void
468fcf3ce44SJohn Forte iscsi_net_close(void *socket)
469fcf3ce44SJohn Forte {
470fcf3ce44SJohn Forte 	vnode_t *vp = SOTOV((struct sonode *)socket);
471fcf3ce44SJohn Forte 	(void) soshutdown((struct sonode *)socket, 2);
472fcf3ce44SJohn Forte 	(void) VOP_CLOSE(vp, 0, 1, 0, kcred, NULL);
473fcf3ce44SJohn Forte 	VN_RELE(vp);
474fcf3ce44SJohn Forte }
475fcf3ce44SJohn Forte 
476fcf3ce44SJohn Forte /*
477fcf3ce44SJohn Forte  * iscsi_net_poll - poll socket for data
478fcf3ce44SJohn Forte  */
479fcf3ce44SJohn Forte static size_t
480fcf3ce44SJohn Forte iscsi_net_poll(void *socket, clock_t timeout)
481fcf3ce44SJohn Forte {
482fcf3ce44SJohn Forte 	int pflag;
483fcf3ce44SJohn Forte 	uchar_t pri;
484fcf3ce44SJohn Forte 	rval_t rval;
485fcf3ce44SJohn Forte 
486fcf3ce44SJohn Forte 	pri = 0;
487fcf3ce44SJohn Forte 	pflag = MSG_ANY;
488fcf3ce44SJohn Forte 	return (kstrgetmsg(SOTOV((struct sonode *)socket), NULL, NULL,
489fcf3ce44SJohn Forte 	    &pri, &pflag, timeout, &rval));
490fcf3ce44SJohn Forte }
491fcf3ce44SJohn Forte 
492fcf3ce44SJohn Forte /*
493fcf3ce44SJohn Forte  * iscsi_net_sendmsg - send message on socket
494fcf3ce44SJohn Forte  */
495fcf3ce44SJohn Forte /* ARGSUSED */
496fcf3ce44SJohn Forte static size_t
497fcf3ce44SJohn Forte iscsi_net_sendmsg(void *socket, struct msghdr *msg)
498fcf3ce44SJohn Forte {
499fcf3ce44SJohn Forte 	int i = 0;
500fcf3ce44SJohn Forte 	int total_len = 0;
501fcf3ce44SJohn Forte 	struct uio uio;
502fcf3ce44SJohn Forte 
503fcf3ce44SJohn Forte 	/* Initialization of the uio structure. */
504fcf3ce44SJohn Forte 	bzero(&uio, sizeof (uio));
505fcf3ce44SJohn Forte 	uio.uio_iov = msg->msg_iov;
506fcf3ce44SJohn Forte 	uio.uio_iovcnt = msg->msg_iovlen;
507fcf3ce44SJohn Forte 	uio.uio_segflg  = UIO_SYSSPACE;
508fcf3ce44SJohn Forte 
509fcf3ce44SJohn Forte 	for (i = 0; i < msg->msg_iovlen; i++) {
510fcf3ce44SJohn Forte 		total_len += (msg->msg_iov)[i].iov_len;
511fcf3ce44SJohn Forte 	}
512fcf3ce44SJohn Forte 	uio.uio_resid = total_len;
513fcf3ce44SJohn Forte 
514fcf3ce44SJohn Forte 	(void) sosendmsg((struct sonode *)socket, msg, &uio);
515fcf3ce44SJohn Forte 	DTRACE_PROBE2(sosendmsg, size_t, total_len, size_t, uio.uio_resid);
516fcf3ce44SJohn Forte 	return (total_len - uio.uio_resid);
517fcf3ce44SJohn Forte }
518fcf3ce44SJohn Forte 
519fcf3ce44SJohn Forte /*
520fcf3ce44SJohn Forte  * iscsi_net_recvmsg - receive message on socket
521fcf3ce44SJohn Forte  */
522fcf3ce44SJohn Forte /* ARGSUSED */
523fcf3ce44SJohn Forte static size_t
524fcf3ce44SJohn Forte iscsi_net_recvmsg(void *socket, struct msghdr *msg, int timeout)
525fcf3ce44SJohn Forte {
526fcf3ce44SJohn Forte 	int		idx;
527fcf3ce44SJohn Forte 	int		total_len   = 0;
528fcf3ce44SJohn Forte 	struct uio	uio;
529fcf3ce44SJohn Forte 	uchar_t		pri	    = 0;
530fcf3ce44SJohn Forte 	int		prflag	    = MSG_ANY;
531fcf3ce44SJohn Forte 	rval_t		rval;
532fcf3ce44SJohn Forte 	struct sonode	*sonode	    = (struct sonode *)socket;
533fcf3ce44SJohn Forte 
534fcf3ce44SJohn Forte 	/* Initialization of the uio structure. */
535fcf3ce44SJohn Forte 	bzero(&uio, sizeof (uio));
536fcf3ce44SJohn Forte 	uio.uio_iov	    = msg->msg_iov;
537fcf3ce44SJohn Forte 	uio.uio_iovcnt	    = msg->msg_iovlen;
538fcf3ce44SJohn Forte 	uio.uio_segflg	    = UIO_SYSSPACE;
539fcf3ce44SJohn Forte 
540fcf3ce44SJohn Forte 	for (idx = 0; idx < msg->msg_iovlen; idx++) {
541fcf3ce44SJohn Forte 		total_len += (msg->msg_iov)[idx].iov_len;
542fcf3ce44SJohn Forte 	}
543fcf3ce44SJohn Forte 	uio.uio_resid = total_len;
544fcf3ce44SJohn Forte 
545fcf3ce44SJohn Forte 	/* If timeout requested on receive */
546fcf3ce44SJohn Forte 	if (timeout > 0) {
547fcf3ce44SJohn Forte 		boolean_t   loopback = B_FALSE;
548fcf3ce44SJohn Forte 
549fcf3ce44SJohn Forte 		/* And this isn't a loopback connection */
550fcf3ce44SJohn Forte 		if (sonode->so_laddr.soa_sa->sa_family == AF_INET) {
551fcf3ce44SJohn Forte 			struct sockaddr_in *lin =
552fcf3ce44SJohn Forte 			    (struct sockaddr_in *)sonode->so_laddr.soa_sa;
553fcf3ce44SJohn Forte 			struct sockaddr_in *fin =
554fcf3ce44SJohn Forte 			    (struct sockaddr_in *)sonode->so_faddr.soa_sa;
555fcf3ce44SJohn Forte 
556fcf3ce44SJohn Forte 			if ((lin->sin_family == fin->sin_family) &&
557fcf3ce44SJohn Forte 			    (bcmp(&lin->sin_addr, &fin->sin_addr,
558fcf3ce44SJohn Forte 			    sizeof (struct in_addr)) == 0)) {
559fcf3ce44SJohn Forte 				loopback = B_TRUE;
560fcf3ce44SJohn Forte 			}
561fcf3ce44SJohn Forte 		} else {
562fcf3ce44SJohn Forte 			struct sockaddr_in6 *lin6 =
563fcf3ce44SJohn Forte 			    (struct sockaddr_in6 *)sonode->so_laddr.soa_sa;
564fcf3ce44SJohn Forte 			struct sockaddr_in6 *fin6 =
565fcf3ce44SJohn Forte 			    (struct sockaddr_in6 *)sonode->so_faddr.soa_sa;
566fcf3ce44SJohn Forte 
567fcf3ce44SJohn Forte 			if ((lin6->sin6_family == fin6->sin6_family) &&
568fcf3ce44SJohn Forte 			    (bcmp(&lin6->sin6_addr, &fin6->sin6_addr,
569fcf3ce44SJohn Forte 			    sizeof (struct in6_addr)) == 0)) {
570fcf3ce44SJohn Forte 				loopback = B_TRUE;
571fcf3ce44SJohn Forte 			}
572fcf3ce44SJohn Forte 		}
573fcf3ce44SJohn Forte 
574fcf3ce44SJohn Forte 		if (loopback == B_FALSE) {
575fcf3ce44SJohn Forte 			/*
576fcf3ce44SJohn Forte 			 * Then poll device for up to the timeout
577fcf3ce44SJohn Forte 			 * period or the requested data is received.
578fcf3ce44SJohn Forte 			 */
579fcf3ce44SJohn Forte 			if (kstrgetmsg(SOTOV(sonode),
580fcf3ce44SJohn Forte 			    NULL, NULL, &pri, &prflag, timeout * 1000,
581fcf3ce44SJohn Forte 			    &rval) == ETIME) {
582fcf3ce44SJohn Forte 				return (0);
583fcf3ce44SJohn Forte 			}
584fcf3ce44SJohn Forte 		}
585fcf3ce44SJohn Forte 	}
586fcf3ce44SJohn Forte 
587fcf3ce44SJohn Forte 	/*
588fcf3ce44SJohn Forte 	 * Receive the requested data.  Block until all
589fcf3ce44SJohn Forte 	 * data is received.
590fcf3ce44SJohn Forte 	 *
591fcf3ce44SJohn Forte 	 * resid occurs only when the connection is
592fcf3ce44SJohn Forte 	 * disconnected.  In that case it will return
593fcf3ce44SJohn Forte 	 * the amount of data that was not received.
594fcf3ce44SJohn Forte 	 * In general this is the total amount we
595fcf3ce44SJohn Forte 	 * requested.
596fcf3ce44SJohn Forte 	 */
597fcf3ce44SJohn Forte 	(void) sorecvmsg((struct sonode *)socket, msg, &uio);
598fcf3ce44SJohn Forte 	DTRACE_PROBE2(sorecvmsg, size_t, total_len, size_t, uio.uio_resid);
599fcf3ce44SJohn Forte 	return (total_len - uio.uio_resid);
600fcf3ce44SJohn Forte }
601fcf3ce44SJohn Forte 
602fcf3ce44SJohn Forte /*
603fcf3ce44SJohn Forte  * iscsi_net_sendpdu - send iscsi pdu on socket
604fcf3ce44SJohn Forte  */
605fcf3ce44SJohn Forte static iscsi_status_t
606fcf3ce44SJohn Forte iscsi_net_sendpdu(void *socket, iscsi_hdr_t *ihp, char *data, int flags)
607fcf3ce44SJohn Forte {
608fcf3ce44SJohn Forte 	uint32_t	pad;
609fcf3ce44SJohn Forte 	uint32_t	crc_hdr;
610fcf3ce44SJohn Forte 	uint32_t	crc_data;
611fcf3ce44SJohn Forte 	uint32_t	pad_len;
612fcf3ce44SJohn Forte 	uint32_t	data_len;
613fcf3ce44SJohn Forte 	iovec_t		iovec[ISCSI_MAX_IOVEC];
614fcf3ce44SJohn Forte 	int		iovlen = 0;
615fcf3ce44SJohn Forte 	size_t		total_len = 0;
616fcf3ce44SJohn Forte 	size_t		send_len;
617fcf3ce44SJohn Forte 	struct msghdr	msg;
618fcf3ce44SJohn Forte 
619fcf3ce44SJohn Forte 	ASSERT(socket != NULL);
620fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
621fcf3ce44SJohn Forte 
622fcf3ce44SJohn Forte 	/*
623fcf3ce44SJohn Forte 	 * Let's send the header first.  'hlength' is in 32-bit
624fcf3ce44SJohn Forte 	 * quantities, so we need to multiply by four to get bytes
625fcf3ce44SJohn Forte 	 */
626fcf3ce44SJohn Forte 	ASSERT(iovlen < ISCSI_MAX_IOVEC);
627fcf3ce44SJohn Forte 	iovec[iovlen].iov_base = (void *)ihp;
628fcf3ce44SJohn Forte 	iovec[iovlen].iov_len  = sizeof (*ihp) + ihp->hlength * 4;
629fcf3ce44SJohn Forte 	total_len += sizeof (*ihp) + ihp->hlength * 4;
630fcf3ce44SJohn Forte 	iovlen++;
631fcf3ce44SJohn Forte 
632fcf3ce44SJohn Forte 	/* Let's transmit the header digest if we have to. */
633fcf3ce44SJohn Forte 	if ((flags & ISCSI_NET_HEADER_DIGEST) != 0) {
634fcf3ce44SJohn Forte 		ASSERT(iovlen < ISCSI_MAX_IOVEC);
635fcf3ce44SJohn Forte 		/*
636fcf3ce44SJohn Forte 		 * Converting the calculated CRC via htonl is not
637fcf3ce44SJohn Forte 		 * necessary because iscsi_crc32c calculates
638fcf3ce44SJohn Forte 		 * the value as it expects to be written
639fcf3ce44SJohn Forte 		 */
640fcf3ce44SJohn Forte 		crc_hdr = iscsi_crc32c((char *)ihp,
641fcf3ce44SJohn Forte 		    sizeof (iscsi_hdr_t) + ihp->hlength * 4);
642fcf3ce44SJohn Forte 
643fcf3ce44SJohn Forte 		iovec[iovlen].iov_base = (void *)&crc_hdr;
644fcf3ce44SJohn Forte 		iovec[iovlen].iov_len  = sizeof (crc_hdr);
645fcf3ce44SJohn Forte 		total_len += sizeof (crc_hdr);
646fcf3ce44SJohn Forte 		iovlen++;
647fcf3ce44SJohn Forte 	}
648fcf3ce44SJohn Forte 
649fcf3ce44SJohn Forte 	/* Let's transmit the data if any. */
650fcf3ce44SJohn Forte 	data_len = ntoh24(ihp->dlength);
651fcf3ce44SJohn Forte 
652fcf3ce44SJohn Forte 	if (data_len) {
653fcf3ce44SJohn Forte 
654fcf3ce44SJohn Forte 		ASSERT(iovlen < ISCSI_MAX_IOVEC);
655fcf3ce44SJohn Forte 		iovec[iovlen].iov_base = (void *)data;
656fcf3ce44SJohn Forte 		iovec[iovlen].iov_len  = data_len;
657fcf3ce44SJohn Forte 		total_len += data_len;
658fcf3ce44SJohn Forte 		iovlen++;
659fcf3ce44SJohn Forte 
660fcf3ce44SJohn Forte 		pad_len = ((ISCSI_PAD_WORD_LEN -
661fcf3ce44SJohn Forte 		    (data_len & (ISCSI_PAD_WORD_LEN - 1))) &
662fcf3ce44SJohn Forte 		    (ISCSI_PAD_WORD_LEN - 1));
663fcf3ce44SJohn Forte 
664fcf3ce44SJohn Forte 		/* Let's transmit the data pad if any. */
665fcf3ce44SJohn Forte 		if (pad_len) {
666fcf3ce44SJohn Forte 
667fcf3ce44SJohn Forte 			ASSERT(iovlen < ISCSI_MAX_IOVEC);
668fcf3ce44SJohn Forte 			pad = 0;
669fcf3ce44SJohn Forte 			iovec[iovlen].iov_base = (void *)&pad;
670fcf3ce44SJohn Forte 			iovec[iovlen].iov_len  = pad_len;
671fcf3ce44SJohn Forte 			total_len += pad_len;
672fcf3ce44SJohn Forte 			iovlen++;
673fcf3ce44SJohn Forte 		}
674fcf3ce44SJohn Forte 
675fcf3ce44SJohn Forte 		/* Let's transmit the data digest if we have to. */
676fcf3ce44SJohn Forte 		if ((flags & ISCSI_NET_DATA_DIGEST) != 0) {
677fcf3ce44SJohn Forte 
678fcf3ce44SJohn Forte 			ASSERT(iovlen < ISCSI_MAX_IOVEC);
679fcf3ce44SJohn Forte 			/*
680fcf3ce44SJohn Forte 			 * Converting the calculated CRC via htonl is not
681fcf3ce44SJohn Forte 			 * necessary because iscsi_crc32c calculates the
682fcf3ce44SJohn Forte 			 * value as it expects to be written
683fcf3ce44SJohn Forte 			 */
684fcf3ce44SJohn Forte 			crc_data = iscsi_crc32c(data, data_len);
685fcf3ce44SJohn Forte 			crc_data = iscsi_crc32c_continued(
686fcf3ce44SJohn Forte 			    (char *)&pad, pad_len, crc_data);
687fcf3ce44SJohn Forte 
688fcf3ce44SJohn Forte 			iovec[iovlen].iov_base = (void *)&crc_data;
689fcf3ce44SJohn Forte 			iovec[iovlen].iov_len  = sizeof (crc_data);
690fcf3ce44SJohn Forte 			total_len += sizeof (crc_data);
691fcf3ce44SJohn Forte 			iovlen++;
692fcf3ce44SJohn Forte 		}
693fcf3ce44SJohn Forte 	}
694fcf3ce44SJohn Forte 
695fcf3ce44SJohn Forte 	DTRACE_PROBE4(tx, void *, socket, iovec_t *, &iovec[0],
696fcf3ce44SJohn Forte 	    int, iovlen, int, total_len);
697fcf3ce44SJohn Forte 
698fcf3ce44SJohn Forte 	/* Initialization of the message header. */
699fcf3ce44SJohn Forte 	bzero(&msg, sizeof (msg));
700fcf3ce44SJohn Forte 	msg.msg_iov	= &iovec[0];
701fcf3ce44SJohn Forte 	msg.msg_flags	= MSG_WAITALL;
702fcf3ce44SJohn Forte 	msg.msg_iovlen	= iovlen;
703fcf3ce44SJohn Forte 
704fcf3ce44SJohn Forte 	send_len = iscsi_net->sendmsg((struct sonode *)socket, &msg);
705fcf3ce44SJohn Forte 	DTRACE_PROBE2(sendmsg, size_t, total_len, size_t, send_len);
706fcf3ce44SJohn Forte 	if (total_len != send_len) {
707fcf3ce44SJohn Forte 		return (ISCSI_STATUS_TCP_TX_ERROR);
708fcf3ce44SJohn Forte 	}
709fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
710fcf3ce44SJohn Forte }
711fcf3ce44SJohn Forte 
712fcf3ce44SJohn Forte /*
713fcf3ce44SJohn Forte  * iscsi_net_recvhdr - receive iscsi hdr on socket
714fcf3ce44SJohn Forte  */
715fcf3ce44SJohn Forte static iscsi_status_t
716fcf3ce44SJohn Forte iscsi_net_recvhdr(void *socket, iscsi_hdr_t *ihp, int header_length,
717fcf3ce44SJohn Forte     int timeout, int flags)
718fcf3ce44SJohn Forte {
719fcf3ce44SJohn Forte 	iovec_t		    iov[ISCSI_MAX_IOVEC];
720fcf3ce44SJohn Forte 	int		    iovlen		= 1;
721fcf3ce44SJohn Forte 	int		    total_len		= 0;
722fcf3ce44SJohn Forte 	uint32_t	    crc_actual		= 0;
723fcf3ce44SJohn Forte 	uint32_t	    crc_calculated	= 0;
724fcf3ce44SJohn Forte 	char		    *adhdr		= NULL;
725fcf3ce44SJohn Forte 	int		    adhdr_length	= 0;
726fcf3ce44SJohn Forte 	struct msghdr	    msg;
727fcf3ce44SJohn Forte 	size_t		    recv_len;
728fcf3ce44SJohn Forte 
729fcf3ce44SJohn Forte 	ASSERT(socket != NULL);
730fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
731fcf3ce44SJohn Forte 
732fcf3ce44SJohn Forte 	if (header_length < sizeof (iscsi_hdr_t)) {
733fcf3ce44SJohn Forte 		ASSERT(FALSE);
734fcf3ce44SJohn Forte 		return (ISCSI_STATUS_INTERNAL_ERROR);
735fcf3ce44SJohn Forte 	}
736fcf3ce44SJohn Forte 
737fcf3ce44SJohn Forte 	/*
738fcf3ce44SJohn Forte 	 * Receive primary header
739fcf3ce44SJohn Forte 	 */
740fcf3ce44SJohn Forte 	iov[0].iov_base = (char *)ihp;
741fcf3ce44SJohn Forte 	iov[0].iov_len = sizeof (iscsi_hdr_t);
742fcf3ce44SJohn Forte 
743fcf3ce44SJohn Forte 	bzero(&msg, sizeof (msg));
744fcf3ce44SJohn Forte 	msg.msg_iov	= iov;
745fcf3ce44SJohn Forte 	msg.msg_flags	= MSG_WAITALL;
746fcf3ce44SJohn Forte 	msg.msg_iovlen	= iovlen;
747fcf3ce44SJohn Forte 
748fcf3ce44SJohn Forte 	recv_len = iscsi_net->recvmsg(socket, &msg, timeout);
749fcf3ce44SJohn Forte 	if (recv_len != sizeof (iscsi_hdr_t)) {
750fcf3ce44SJohn Forte 		return (ISCSI_STATUS_TCP_RX_ERROR);
751fcf3ce44SJohn Forte 	}
752fcf3ce44SJohn Forte 
753fcf3ce44SJohn Forte 	DTRACE_PROBE2(rx_hdr, void *, socket, iovec_t *iop, &iov[0]);
754fcf3ce44SJohn Forte 
755fcf3ce44SJohn Forte 	/* verify incoming opcode is a valid operation */
756fcf3ce44SJohn Forte 	if (is_incoming_opcode_invalid[ihp->opcode]) {
757fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%p) protocol error - "
758fcf3ce44SJohn Forte 		    "received an unsupported opcode:0x%02x",
759fcf3ce44SJohn Forte 		    socket, ihp->opcode);
760fcf3ce44SJohn Forte 		return (ISCSI_STATUS_PROTOCOL_ERROR);
761fcf3ce44SJohn Forte 	}
762fcf3ce44SJohn Forte 
763fcf3ce44SJohn Forte 	/*
764fcf3ce44SJohn Forte 	 * Setup receipt of additional header
765fcf3ce44SJohn Forte 	 */
766fcf3ce44SJohn Forte 	if (ihp->hlength > 0) {
767fcf3ce44SJohn Forte 		adhdr = ((char *)ihp) + sizeof (iscsi_hdr_t);
768fcf3ce44SJohn Forte 		adhdr_length = header_length - sizeof (iscsi_hdr_t);
769fcf3ce44SJohn Forte 		/* make sure enough space is available for adhdr */
770fcf3ce44SJohn Forte 		if (ihp->hlength > adhdr_length) {
771fcf3ce44SJohn Forte 			ASSERT(FALSE);
772fcf3ce44SJohn Forte 			return (ISCSI_STATUS_INTERNAL_ERROR);
773fcf3ce44SJohn Forte 		}
774fcf3ce44SJohn Forte 
775fcf3ce44SJohn Forte 		ASSERT(iovlen < ISCSI_MAX_IOVEC);
776fcf3ce44SJohn Forte 		iov[iovlen].iov_base = adhdr;
777fcf3ce44SJohn Forte 		iov[iovlen].iov_len = adhdr_length;
778fcf3ce44SJohn Forte 		total_len += adhdr_length;
779fcf3ce44SJohn Forte 		iovlen++;
780fcf3ce44SJohn Forte 	}
781fcf3ce44SJohn Forte 
782fcf3ce44SJohn Forte 	/*
783fcf3ce44SJohn Forte 	 * Setup receipt of header digest if enabled and connection
784fcf3ce44SJohn Forte 	 * is in full feature mode.
785fcf3ce44SJohn Forte 	 */
786fcf3ce44SJohn Forte 	if ((flags & ISCSI_NET_HEADER_DIGEST) != 0) {
787fcf3ce44SJohn Forte 		ASSERT(iovlen < ISCSI_MAX_IOVEC);
788fcf3ce44SJohn Forte 		iov[iovlen].iov_base = (char *)&crc_actual;
789fcf3ce44SJohn Forte 		iov[iovlen].iov_len = sizeof (uint32_t);
790fcf3ce44SJohn Forte 		total_len += sizeof (uint32_t);
791fcf3ce44SJohn Forte 		iovlen++;
792fcf3ce44SJohn Forte 	}
793fcf3ce44SJohn Forte 
794fcf3ce44SJohn Forte 	/*
795fcf3ce44SJohn Forte 	 * Read additional header and/or header digest if pieces
796fcf3ce44SJohn Forte 	 * are available
797fcf3ce44SJohn Forte 	 */
798fcf3ce44SJohn Forte 	if (iovlen > 1) {
799fcf3ce44SJohn Forte 
800fcf3ce44SJohn Forte 		bzero(&msg, sizeof (msg));
801fcf3ce44SJohn Forte 		msg.msg_iov	= iov;
802fcf3ce44SJohn Forte 		msg.msg_flags	= MSG_WAITALL;
803fcf3ce44SJohn Forte 		msg.msg_iovlen	= iovlen;
804fcf3ce44SJohn Forte 
805fcf3ce44SJohn Forte 		recv_len = iscsi_net->recvmsg(socket, &msg, timeout);
806fcf3ce44SJohn Forte 		if (recv_len != total_len) {
807fcf3ce44SJohn Forte 			return (ISCSI_STATUS_TCP_RX_ERROR);
808fcf3ce44SJohn Forte 		}
809fcf3ce44SJohn Forte 
810fcf3ce44SJohn Forte 		DTRACE_PROBE4(rx_adhdr_digest, void *, socket,
811fcf3ce44SJohn Forte 		    iovec_t *iop, &iov[0], int, iovlen, int, total_len);
812fcf3ce44SJohn Forte 
813fcf3ce44SJohn Forte 		/*
814fcf3ce44SJohn Forte 		 * Verify header digest if enabled and connection
815fcf3ce44SJohn Forte 		 * is in full feature mode
816fcf3ce44SJohn Forte 		 */
817fcf3ce44SJohn Forte 		if ((flags & ISCSI_NET_HEADER_DIGEST) != 0) {
818fcf3ce44SJohn Forte 			crc_calculated = iscsi_crc32c((uchar_t *)ihp,
819fcf3ce44SJohn Forte 			    sizeof (iscsi_hdr_t) + ihp->hlength * 4);
820fcf3ce44SJohn Forte 
821fcf3ce44SJohn Forte 			/*
822fcf3ce44SJohn Forte 			 * Converting actual CRC read via ntohl is not
823fcf3ce44SJohn Forte 			 * necessary because iscsi_crc32c calculates the
824fcf3ce44SJohn Forte 			 * value as it expect to be read
825fcf3ce44SJohn Forte 			 */
826fcf3ce44SJohn Forte 			if (crc_calculated != crc_actual) {
827fcf3ce44SJohn Forte 				/* Invalid Header Digest */
828fcf3ce44SJohn Forte 				cmn_err(CE_WARN, "iscsi connection(%p) "
829fcf3ce44SJohn Forte 				    "protocol error - encountered a header "
830fcf3ce44SJohn Forte 				    "digest error expected:0x%08x "
831fcf3ce44SJohn Forte 				    "received:0x%08x", socket,
832fcf3ce44SJohn Forte 				    crc_calculated, crc_actual);
833fcf3ce44SJohn Forte 				return (ISCSI_STATUS_HEADER_DIGEST_ERROR);
834fcf3ce44SJohn Forte 			}
835fcf3ce44SJohn Forte 		}
836fcf3ce44SJohn Forte 	}
837fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
838fcf3ce44SJohn Forte }
839fcf3ce44SJohn Forte 
840fcf3ce44SJohn Forte 
841fcf3ce44SJohn Forte /*
842fcf3ce44SJohn Forte  * iscsi_net_recvdata - receive iscsi data payload from socket
843fcf3ce44SJohn Forte  */
844fcf3ce44SJohn Forte static iscsi_status_t
845fcf3ce44SJohn Forte iscsi_net_recvdata(void *socket, iscsi_hdr_t *ihp, char *data,
846fcf3ce44SJohn Forte     int max_data_length, int timeout, int flags)
847fcf3ce44SJohn Forte {
848fcf3ce44SJohn Forte 	struct iovec	iov[3];
849fcf3ce44SJohn Forte 	int		iovlen			= 1;
850fcf3ce44SJohn Forte 	int		total_len		= 0;
851fcf3ce44SJohn Forte 	int		dlength			= 0;
852fcf3ce44SJohn Forte 	int		pad_len			= 0;
853fcf3ce44SJohn Forte 	uint8_t		pad[ISCSI_PAD_WORD_LEN];
854fcf3ce44SJohn Forte 	uint32_t	crc_calculated		= 0;
855fcf3ce44SJohn Forte 	uint32_t	crc_actual		= 0;
856fcf3ce44SJohn Forte 	struct msghdr	msg;
857fcf3ce44SJohn Forte 	size_t		recv_len;
858fcf3ce44SJohn Forte 
859fcf3ce44SJohn Forte 	ASSERT(socket != NULL);
860fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
861fcf3ce44SJohn Forte 	ASSERT(data != NULL);
862fcf3ce44SJohn Forte 
863fcf3ce44SJohn Forte 	/* short hand dlength */
864fcf3ce44SJohn Forte 	dlength = ntoh24(ihp->dlength);
865fcf3ce44SJohn Forte 
866fcf3ce44SJohn Forte 	/* verify dlength is valid */
867fcf3ce44SJohn Forte 	if (dlength > max_data_length) {
868fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%p) protocol error - "
869fcf3ce44SJohn Forte 		    "invalid data lengths itt:0x%x received:0x%x "
870fcf3ce44SJohn Forte 		    "max expected:0x%x", socket, ihp->itt,
871fcf3ce44SJohn Forte 		    dlength, max_data_length);
872fcf3ce44SJohn Forte 		return (ISCSI_STATUS_PROTOCOL_ERROR);
873fcf3ce44SJohn Forte 	}
874fcf3ce44SJohn Forte 
875fcf3ce44SJohn Forte 	if (dlength) {
876fcf3ce44SJohn Forte 
877fcf3ce44SJohn Forte 		/* calculate pad */
878fcf3ce44SJohn Forte 		pad_len = ((ISCSI_PAD_WORD_LEN -
879fcf3ce44SJohn Forte 		    (dlength & (ISCSI_PAD_WORD_LEN - 1))) &
880fcf3ce44SJohn Forte 		    (ISCSI_PAD_WORD_LEN - 1));
881fcf3ce44SJohn Forte 
882fcf3ce44SJohn Forte 		/* setup data iovec */
883fcf3ce44SJohn Forte 		iov[0].iov_base	= (char *)data;
884fcf3ce44SJohn Forte 		iov[0].iov_len	= dlength;
885fcf3ce44SJohn Forte 		total_len	= dlength;
886fcf3ce44SJohn Forte 
887fcf3ce44SJohn Forte 		/* if pad setup pad iovec */
888fcf3ce44SJohn Forte 		if (pad_len) {
889fcf3ce44SJohn Forte 			iov[iovlen].iov_base	= (char *)&pad;
890fcf3ce44SJohn Forte 			iov[iovlen].iov_len	= pad_len;
891fcf3ce44SJohn Forte 			total_len		+= pad_len;
892fcf3ce44SJohn Forte 			iovlen++;
893fcf3ce44SJohn Forte 		}
894fcf3ce44SJohn Forte 
895fcf3ce44SJohn Forte 		/* setup data digest */
896fcf3ce44SJohn Forte 		if ((flags & ISCSI_NET_DATA_DIGEST) != 0) {
897fcf3ce44SJohn Forte 			iov[iovlen].iov_base	= (char *)&crc_actual;
898fcf3ce44SJohn Forte 			iov[iovlen].iov_len	= sizeof (crc_actual);
899fcf3ce44SJohn Forte 			total_len		+= sizeof (crc_actual);
900fcf3ce44SJohn Forte 			iovlen++;
901fcf3ce44SJohn Forte 		}
902fcf3ce44SJohn Forte 
903fcf3ce44SJohn Forte 		bzero(&msg, sizeof (msg));
904fcf3ce44SJohn Forte 		msg.msg_iov	= iov;
905fcf3ce44SJohn Forte 		msg.msg_flags	= MSG_WAITALL;
906fcf3ce44SJohn Forte 		msg.msg_iovlen	= iovlen;
907fcf3ce44SJohn Forte 
908fcf3ce44SJohn Forte 		recv_len = iscsi_net->recvmsg(socket, &msg, timeout);
909fcf3ce44SJohn Forte 		if (recv_len != total_len) {
910fcf3ce44SJohn Forte 			return (ISCSI_STATUS_TCP_RX_ERROR);
911fcf3ce44SJohn Forte 		}
912fcf3ce44SJohn Forte 
913fcf3ce44SJohn Forte 		DTRACE_PROBE4(rx_data, void *, socket, iovec_t *iop,
914fcf3ce44SJohn Forte 		    &iov[0], int, iovlen, int, total_len);
915fcf3ce44SJohn Forte 
916fcf3ce44SJohn Forte 		/* verify data digest is present */
917fcf3ce44SJohn Forte 		if ((flags & ISCSI_NET_DATA_DIGEST) != 0) {
918fcf3ce44SJohn Forte 
919fcf3ce44SJohn Forte 			crc_calculated = iscsi_crc32c(data, dlength);
920fcf3ce44SJohn Forte 			crc_calculated = iscsi_crc32c_continued(
921fcf3ce44SJohn Forte 			    (char *)&pad, pad_len, crc_calculated);
922fcf3ce44SJohn Forte 
923fcf3ce44SJohn Forte 			/*
924fcf3ce44SJohn Forte 			 * Converting actual CRC read via ntohl is not
925fcf3ce44SJohn Forte 			 * necessary because iscsi_crc32c calculates the
926fcf3ce44SJohn Forte 			 * value as it expects to be read
927fcf3ce44SJohn Forte 			 */
928fcf3ce44SJohn Forte 			if (crc_calculated != crc_actual) {
929fcf3ce44SJohn Forte 				cmn_err(CE_WARN, "iscsi connection(%p) "
930fcf3ce44SJohn Forte 				    "protocol error - encountered a data "
931fcf3ce44SJohn Forte 				    "digest error itt:0x%x expected:0x%08x "
932fcf3ce44SJohn Forte 				    "received:0x%08x", socket,
933fcf3ce44SJohn Forte 				    ihp->itt, crc_calculated, crc_actual);
934fcf3ce44SJohn Forte 				return (ISCSI_STATUS_DATA_DIGEST_ERROR);
935fcf3ce44SJohn Forte 			}
936fcf3ce44SJohn Forte 		}
937fcf3ce44SJohn Forte 	}
938fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
939fcf3ce44SJohn Forte }
940*6cefaae1SJack Meng 
941*6cefaae1SJack Meng /*
942*6cefaae1SJack Meng  * Convert a prefix length to a mask.
943*6cefaae1SJack Meng  */
944*6cefaae1SJack Meng static iscsi_status_t
945*6cefaae1SJack Meng iscsi_prefixlentomask(int prefixlen, int maxlen, uchar_t *mask)
946*6cefaae1SJack Meng {
947*6cefaae1SJack Meng 	if (prefixlen < 0 || prefixlen > maxlen || mask == NULL) {
948*6cefaae1SJack Meng 		return (ISCSI_STATUS_INTERNAL_ERROR);
949*6cefaae1SJack Meng 	}
950*6cefaae1SJack Meng 
951*6cefaae1SJack Meng 	while (prefixlen > 0) {
952*6cefaae1SJack Meng 		if (prefixlen >= 8) {
953*6cefaae1SJack Meng 			*mask = 0xff;
954*6cefaae1SJack Meng 			mask++;
955*6cefaae1SJack Meng 			prefixlen = prefixlen - 8;
956*6cefaae1SJack Meng 			continue;
957*6cefaae1SJack Meng 		}
958*6cefaae1SJack Meng 		*mask = *mask | (1 << (8 - prefixlen));
959*6cefaae1SJack Meng 		prefixlen--;
960*6cefaae1SJack Meng 	}
961*6cefaae1SJack Meng 	return (ISCSI_STATUS_SUCCESS);
962*6cefaae1SJack Meng }
963*6cefaae1SJack Meng 
964*6cefaae1SJack Meng static iscsi_status_t
965*6cefaae1SJack Meng iscsi_net_interface()
966*6cefaae1SJack Meng {
967*6cefaae1SJack Meng 	struct in_addr	braddr;
968*6cefaae1SJack Meng 	struct in_addr	subnet;
969*6cefaae1SJack Meng 	struct in_addr	myaddr;
970*6cefaae1SJack Meng 	struct in_addr	defgateway;
971*6cefaae1SJack Meng 	struct in6_addr myaddr6;
972*6cefaae1SJack Meng 	struct in6_addr subnet6;
973*6cefaae1SJack Meng 	uchar_t		mask_prefix = 0;
974*6cefaae1SJack Meng 	int		mask_bits   = 1;
975*6cefaae1SJack Meng 	TIUSER		*tiptr;
976*6cefaae1SJack Meng 	TIUSER		*tiptr6;
977*6cefaae1SJack Meng 	char		ifname[16]	= {0};
978*6cefaae1SJack Meng 	iscsi_status_t	status;
979*6cefaae1SJack Meng 
980*6cefaae1SJack Meng 	struct knetconfig dl_udp_netconf = {
981*6cefaae1SJack Meng 	    NC_TPI_CLTS,
982*6cefaae1SJack Meng 	    NC_INET,
983*6cefaae1SJack Meng 	    NC_UDP,
984*6cefaae1SJack Meng 	    0, };
985*6cefaae1SJack Meng 	struct knetconfig dl_udp6_netconf = {
986*6cefaae1SJack Meng 	    NC_TPI_CLTS,
987*6cefaae1SJack Meng 	    NC_INET6,
988*6cefaae1SJack Meng 	    NC_UDP,
989*6cefaae1SJack Meng 	    0, };
990*6cefaae1SJack Meng 
991*6cefaae1SJack Meng 	(void) strlcpy(ifname, rootfs.bo_ifname, sizeof (ifname));
992*6cefaae1SJack Meng 
993*6cefaae1SJack Meng 	if (iscsiboot_prop->boot_nic.sin_family == AF_INET) {
994*6cefaae1SJack Meng 		/*
995*6cefaae1SJack Meng 		 * Assumes only one linkage array element.
996*6cefaae1SJack Meng 		 */
997*6cefaae1SJack Meng 		dl_udp_netconf.knc_rdev =
998*6cefaae1SJack Meng 		    makedevice(clone_major, ddi_name_to_major("udp"));
999*6cefaae1SJack Meng 
1000*6cefaae1SJack Meng 		myaddr.s_addr =
1001*6cefaae1SJack Meng 		    iscsiboot_prop->boot_nic.nic_ip_u.u_in4.s_addr;
1002*6cefaae1SJack Meng 
1003*6cefaae1SJack Meng 		mask_prefix = iscsiboot_prop->boot_nic.sub_mask_prefix;
1004*6cefaae1SJack Meng 		(void) memset(&subnet.s_addr, 0, sizeof (subnet));
1005*6cefaae1SJack Meng 		status = iscsi_prefixlentomask(mask_prefix, IP_4_BITS,
1006*6cefaae1SJack Meng 		    (uchar_t *)&subnet.s_addr);
1007*6cefaae1SJack Meng 		if (status != ISCSI_STATUS_SUCCESS) {
1008*6cefaae1SJack Meng 			return (status);
1009*6cefaae1SJack Meng 		}
1010*6cefaae1SJack Meng 
1011*6cefaae1SJack Meng 		mask_bits = mask_bits << (IP_4_BITS - mask_prefix);
1012*6cefaae1SJack Meng 		mask_bits = mask_bits - 1;
1013*6cefaae1SJack Meng 		/*
1014*6cefaae1SJack Meng 		 * Set the last mask bits of the ip address with 1, then
1015*6cefaae1SJack Meng 		 * we can get the broadcast address.
1016*6cefaae1SJack Meng 		 */
1017*6cefaae1SJack Meng 		braddr.s_addr = myaddr.s_addr | mask_bits;
1018*6cefaae1SJack Meng 
1019*6cefaae1SJack Meng 		defgateway.s_addr =
1020*6cefaae1SJack Meng 		    iscsiboot_prop->boot_nic.nic_gw_u.u_in4.s_addr;
1021*6cefaae1SJack Meng 
1022*6cefaae1SJack Meng 		/* initialize interface */
1023*6cefaae1SJack Meng 		if (t_kopen((file_t *)NULL, dl_udp_netconf.knc_rdev,
1024*6cefaae1SJack Meng 		    FREAD|FWRITE, &tiptr, CRED()) == 0) {
1025*6cefaae1SJack Meng 			if (kdlifconfig(tiptr, AF_INET, &myaddr, &subnet,
1026*6cefaae1SJack Meng 			    &braddr, &defgateway, ifname)) {
1027*6cefaae1SJack Meng 				cmn_err(CE_WARN, "Failed to configure"
1028*6cefaae1SJack Meng 				    " iSCSI boot nic");
1029*6cefaae1SJack Meng 				(void) t_kclose(tiptr, 0);
1030*6cefaae1SJack Meng 				return (ISCSI_STATUS_INTERNAL_ERROR);
1031*6cefaae1SJack Meng 			}
1032*6cefaae1SJack Meng 		} else {
1033*6cefaae1SJack Meng 			cmn_err(CE_WARN, "Failed to configure"
1034*6cefaae1SJack Meng 			    " iSCSI boot nic");
1035*6cefaae1SJack Meng 			return (ISCSI_STATUS_INTERNAL_ERROR);
1036*6cefaae1SJack Meng 		}
1037*6cefaae1SJack Meng 		return (ISCSI_STATUS_SUCCESS);
1038*6cefaae1SJack Meng 	} else {
1039*6cefaae1SJack Meng 		dl_udp6_netconf.knc_rdev =
1040*6cefaae1SJack Meng 		    makedevice(clone_major, ddi_name_to_major("udp6"));
1041*6cefaae1SJack Meng 
1042*6cefaae1SJack Meng 		bcopy(&iscsiboot_prop->boot_nic.nic_ip_u.u_in6.s6_addr,
1043*6cefaae1SJack Meng 		    &myaddr6.s6_addr, 16);
1044*6cefaae1SJack Meng 
1045*6cefaae1SJack Meng 		(void) memset(&subnet6, 0, sizeof (subnet6));
1046*6cefaae1SJack Meng 		mask_prefix = iscsiboot_prop->boot_nic.sub_mask_prefix;
1047*6cefaae1SJack Meng 		status = iscsi_prefixlentomask(mask_prefix, IP_6_BITS,
1048*6cefaae1SJack Meng 		    (uchar_t *)&subnet6.s6_addr);
1049*6cefaae1SJack Meng 		if (status != ISCSI_STATUS_SUCCESS) {
1050*6cefaae1SJack Meng 			return (status);
1051*6cefaae1SJack Meng 		}
1052*6cefaae1SJack Meng 
1053*6cefaae1SJack Meng 		if (t_kopen((file_t *)NULL, dl_udp6_netconf.knc_rdev,
1054*6cefaae1SJack Meng 		    FREAD|FWRITE, &tiptr6, CRED()) == 0) {
1055*6cefaae1SJack Meng 			if (kdlifconfig(tiptr6, AF_INET6, &myaddr6,
1056*6cefaae1SJack Meng 			    &subnet6, NULL, NULL, ifname)) {
1057*6cefaae1SJack Meng 				cmn_err(CE_WARN, "Failed to configure"
1058*6cefaae1SJack Meng 				    " iSCSI boot nic");
1059*6cefaae1SJack Meng 				(void) t_kclose(tiptr, 0);
1060*6cefaae1SJack Meng 				return (ISCSI_STATUS_INTERNAL_ERROR);
1061*6cefaae1SJack Meng 			}
1062*6cefaae1SJack Meng 		} else {
1063*6cefaae1SJack Meng 			cmn_err(CE_WARN, "Failed to configure"
1064*6cefaae1SJack Meng 			    " iSCSI boot nic");
1065*6cefaae1SJack Meng 			return (ISCSI_STATUS_INTERNAL_ERROR);
1066*6cefaae1SJack Meng 		}
1067*6cefaae1SJack Meng 		return (ISCSI_STATUS_SUCCESS);
1068*6cefaae1SJack Meng 	}
1069*6cefaae1SJack Meng }
1070*6cefaae1SJack Meng 
1071*6cefaae1SJack Meng /*
1072*6cefaae1SJack Meng  * vp is needed to create the socket for the time being.
1073*6cefaae1SJack Meng  */
1074*6cefaae1SJack Meng static int
1075*6cefaae1SJack Meng iscsi_ldi_vp_from_name(char *path, vnode_t **vpp)
1076*6cefaae1SJack Meng {
1077*6cefaae1SJack Meng 	vnode_t		*vp = NULL;
1078*6cefaae1SJack Meng 	int		ret;
1079*6cefaae1SJack Meng 
1080*6cefaae1SJack Meng 	/* sanity check required input parameters */
1081*6cefaae1SJack Meng 	if ((path == NULL) || (vpp == NULL))
1082*6cefaae1SJack Meng 		return (EINVAL);
1083*6cefaae1SJack Meng 
1084*6cefaae1SJack Meng 	if (modrootloaded) {
1085*6cefaae1SJack Meng 		cred_t *saved_cred = curthread->t_cred;
1086*6cefaae1SJack Meng 
1087*6cefaae1SJack Meng 		/* we don't want lookupname to fail because of credentials */
1088*6cefaae1SJack Meng 		curthread->t_cred = kcred;
1089*6cefaae1SJack Meng 
1090*6cefaae1SJack Meng 		/*
1091*6cefaae1SJack Meng 		 * all lookups should be done in the global zone.  but
1092*6cefaae1SJack Meng 		 * lookupnameat() won't actually do this if an absolute
1093*6cefaae1SJack Meng 		 * path is passed in.  since the ldi interfaces require an
1094*6cefaae1SJack Meng 		 * absolute path we pass lookupnameat() a pointer to
1095*6cefaae1SJack Meng 		 * the character after the leading '/' and tell it to
1096*6cefaae1SJack Meng 		 * start searching at the current system root directory.
1097*6cefaae1SJack Meng 		 */
1098*6cefaae1SJack Meng 		ASSERT(*path == '/');
1099*6cefaae1SJack Meng 		ret = lookupnameat(path + 1, UIO_SYSSPACE, FOLLOW, NULLVPP,
1100*6cefaae1SJack Meng 		    &vp, rootdir);
1101*6cefaae1SJack Meng 
1102*6cefaae1SJack Meng 		/* restore this threads credentials */
1103*6cefaae1SJack Meng 		curthread->t_cred = saved_cred;
1104*6cefaae1SJack Meng 
1105*6cefaae1SJack Meng 		if (ret == 0) {
1106*6cefaae1SJack Meng 			if (!vn_matchops(vp, spec_getvnodeops()) ||
1107*6cefaae1SJack Meng 			    !VTYP_VALID(vp->v_type)) {
1108*6cefaae1SJack Meng 				VN_RELE(vp);
1109*6cefaae1SJack Meng 				return (ENXIO);
1110*6cefaae1SJack Meng 			}
1111*6cefaae1SJack Meng 		}
1112*6cefaae1SJack Meng 	}
1113*6cefaae1SJack Meng 
1114*6cefaae1SJack Meng 	if (vp == NULL) {
1115*6cefaae1SJack Meng 		dev_info_t	*dip;
1116*6cefaae1SJack Meng 		dev_t		dev;
1117*6cefaae1SJack Meng 		int		spec_type;
1118*6cefaae1SJack Meng 
1119*6cefaae1SJack Meng 		/*
1120*6cefaae1SJack Meng 		 * Root is not mounted, the minor node is not specified,
1121*6cefaae1SJack Meng 		 * or an OBP path has been specified.
1122*6cefaae1SJack Meng 		 */
1123*6cefaae1SJack Meng 
1124*6cefaae1SJack Meng 		/*
1125*6cefaae1SJack Meng 		 * Determine if path can be pruned to produce an
1126*6cefaae1SJack Meng 		 * OBP or devfs path for resolve_pathname.
1127*6cefaae1SJack Meng 		 */
1128*6cefaae1SJack Meng 		if (strncmp(path, "/devices/", 9) == 0)
1129*6cefaae1SJack Meng 			path += strlen("/devices");
1130*6cefaae1SJack Meng 
1131*6cefaae1SJack Meng 		/*
1132*6cefaae1SJack Meng 		 * if no minor node was specified the DEFAULT minor node
1133*6cefaae1SJack Meng 		 * will be returned.  if there is no DEFAULT minor node
1134*6cefaae1SJack Meng 		 * one will be fabricated of type S_IFCHR with the minor
1135*6cefaae1SJack Meng 		 * number equal to the instance number.
1136*6cefaae1SJack Meng 		 */
1137*6cefaae1SJack Meng 		ret = resolve_pathname(path, &dip, &dev, &spec_type);
1138*6cefaae1SJack Meng 		if (ret != 0)
1139*6cefaae1SJack Meng 			return (ENODEV);
1140*6cefaae1SJack Meng 
1141*6cefaae1SJack Meng 		ASSERT(STYP_VALID(spec_type));
1142*6cefaae1SJack Meng 		vp = makespecvp(dev, STYP_TO_VTYP(spec_type));
1143*6cefaae1SJack Meng 		spec_assoc_vp_with_devi(vp, dip);
1144*6cefaae1SJack Meng 		ddi_release_devi(dip);
1145*6cefaae1SJack Meng 	}
1146*6cefaae1SJack Meng 
1147*6cefaae1SJack Meng 	*vpp = vp;
1148*6cefaae1SJack Meng 	return (0);
1149*6cefaae1SJack Meng }
1150