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 /*
22bbe72583SJack Meng * Copyright 2010 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>
370f1702c5SYu Xiangning #include <netinet/in.h>
38fcf3ce44SJohn Forte #include "iscsi.h"
390f1702c5SYu 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 *
640f1702c5SYu Xiangning * socket - Creates TCP/IP socket connection. In the
650f1702c5SYu Xiangning * default implementation creates a sonode
660f1702c5SYu Xiangning * via the sockfs kernel layer.
670f1702c5SYu Xiangning * bind - Performs standard TCP/IP BSD operation. In
680f1702c5SYu Xiangning * the default implementation this only act
690f1702c5SYu Xiangning * as a soft binding based on the IP and routing
700f1702c5SYu Xiangning * tables. It would be preferred if this was
710f1702c5SYu Xiangning * a hard binding but that is currently not
720f1702c5SYu Xiangning * possible with Solaris's networking stack.
730f1702c5SYu Xiangning * connect - Performs standard TCP/IP BSD operation. This
740f1702c5SYu Xiangning * establishes the TCP SYN to the peer IP address.
750f1702c5SYu Xiangning * listen - Performs standard TCP/IP BSD operation. This
760f1702c5SYu Xiangning * listens for incoming peer connections.
770f1702c5SYu Xiangning * accept - Performs standard TCP/IP BSD operation. This
780f1702c5SYu Xiangning * accepts incoming peer connections.
790f1702c5SYu Xiangning * shutdown - This disconnects the TCP/IP connection while
800f1702c5SYu Xiangning * maintaining the resources.
810f1702c5SYu Xiangning * close - This disconnects the TCP/IP connection and
820f1702c5SYu Xiangning * releases the resources.
83fcf3ce44SJohn Forte *
840f1702c5SYu Xiangning * getsockopt - Gets socket option for specified socket.
850f1702c5SYu 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 *
900f1702c5SYu Xiangning * TCP_CONN_NOTIFY_THRESHOLD
910f1702c5SYu Xiangning * TCP_CONN_ABORT_THRESHOLD
920f1702c5SYu Xiangning * TCP_ABORT_THRESHOLD
930f1702c5SYu Xiangning * TCP_NODELAY
940f1702c5SYu Xiangning * SO_RCVBUF
950f1702c5SYu Xiangning * SO_SNDBUF
96fcf3ce44SJohn Forte *
97fcf3ce44SJohn Forte * iscsi_net_poll - Poll socket interface for a specified amount
980f1702c5SYu Xiangning * of data. If data not received in timeout
990f1702c5SYu 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
1130f1702c5SYu Xiangning * generate or validate the iSCSI
1140f1702c5SYu 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
1520f1702c5SYu Xiangning extern ib_boot_prop_t *iscsiboot_prop;
153fcf3ce44SJohn Forte
154fcf3ce44SJohn Forte /* prototypes */
155fcf3ce44SJohn Forte static void * iscsi_net_socket(int domain, int type, int protocol);
156fcf3ce44SJohn Forte static int iscsi_net_bind(void *socket, struct sockaddr *
157fcf3ce44SJohn Forte name, int name_len, int backlog, int flags);
158fcf3ce44SJohn Forte static int iscsi_net_connect(void *socket, struct sockaddr *
159fcf3ce44SJohn Forte name, int name_len, int fflag, int flags);
160fcf3ce44SJohn Forte static int iscsi_net_listen(void *socket, int backlog);
161fcf3ce44SJohn Forte static void * iscsi_net_accept(void *socket, struct sockaddr *addr,
162fcf3ce44SJohn Forte int *addr_len);
1630f1702c5SYu Xiangning static int iscsi_net_getsockname(void *socket, struct sockaddr *, socklen_t *);
164fcf3ce44SJohn Forte static int iscsi_net_getsockopt(void *socket, int level,
165fcf3ce44SJohn Forte int option_name, void *option_val, int *option_len, int flags);
166fcf3ce44SJohn Forte static int iscsi_net_setsockopt(void *socket, int level,
167fcf3ce44SJohn Forte int option_name, void *option_val, int option_len);
168fcf3ce44SJohn Forte static int iscsi_net_shutdown(void *socket, int how);
169fcf3ce44SJohn Forte static void iscsi_net_close(void *socket);
170fcf3ce44SJohn Forte
171fcf3ce44SJohn Forte static size_t iscsi_net_poll(void *socket, clock_t timeout);
172fcf3ce44SJohn Forte static size_t iscsi_net_sendmsg(void *socket, struct msghdr *msg);
173fcf3ce44SJohn Forte static size_t iscsi_net_recvmsg(void *socket,
174fcf3ce44SJohn Forte struct msghdr *msg, int timeout);
175fcf3ce44SJohn Forte
176fcf3ce44SJohn Forte static iscsi_status_t iscsi_net_sendpdu(void *socket, iscsi_hdr_t *ihp,
177fcf3ce44SJohn Forte char *data, int flags);
178fcf3ce44SJohn Forte static iscsi_status_t iscsi_net_recvdata(void *socket, iscsi_hdr_t *ihp,
179fcf3ce44SJohn Forte char *data, int max_data_length, int timeout, int flags);
180fcf3ce44SJohn Forte static iscsi_status_t iscsi_net_recvhdr(void *socket, iscsi_hdr_t *ihp,
181fcf3ce44SJohn Forte int header_length, int timeout, int flags);
182fcf3ce44SJohn Forte
1839ad4dd06SSheng-Liang Eric Zhang static void iscsi_net_set_connect_options(void *socket);
184fcf3ce44SJohn Forte
185fcf3ce44SJohn Forte /*
186fcf3ce44SJohn Forte * +--------------------------------------------------------------------+
1870f1702c5SYu Xiangning * | network interface registration functions |
188fcf3ce44SJohn Forte * +--------------------------------------------------------------------+
189fcf3ce44SJohn Forte */
190fcf3ce44SJohn Forte
191fcf3ce44SJohn Forte /*
192fcf3ce44SJohn Forte * iscsi_net_init - initialize network interface
193fcf3ce44SJohn Forte */
194fcf3ce44SJohn Forte void
iscsi_net_init()195fcf3ce44SJohn Forte iscsi_net_init()
196fcf3ce44SJohn Forte {
197fcf3ce44SJohn Forte iscsi_net = kmem_zalloc(sizeof (*iscsi_net), KM_SLEEP);
198fcf3ce44SJohn Forte
199fcf3ce44SJohn Forte iscsi_net->socket = iscsi_net_socket;
200fcf3ce44SJohn Forte
201fcf3ce44SJohn Forte iscsi_net->bind = iscsi_net_bind;
202fcf3ce44SJohn Forte iscsi_net->connect = iscsi_net_connect;
203fcf3ce44SJohn Forte iscsi_net->listen = iscsi_net_listen;
204fcf3ce44SJohn Forte iscsi_net->accept = iscsi_net_accept;
205fcf3ce44SJohn Forte iscsi_net->shutdown = iscsi_net_shutdown;
206fcf3ce44SJohn Forte iscsi_net->close = iscsi_net_close;
207fcf3ce44SJohn Forte
208fcf3ce44SJohn Forte iscsi_net->getsockname = iscsi_net_getsockname;
209fcf3ce44SJohn Forte iscsi_net->getsockopt = iscsi_net_getsockopt;
210fcf3ce44SJohn Forte iscsi_net->setsockopt = iscsi_net_setsockopt;
211fcf3ce44SJohn Forte
212fcf3ce44SJohn Forte iscsi_net->poll = iscsi_net_poll;
213fcf3ce44SJohn Forte iscsi_net->sendmsg = iscsi_net_sendmsg;
214fcf3ce44SJohn Forte iscsi_net->recvmsg = iscsi_net_recvmsg;
215fcf3ce44SJohn Forte
216fcf3ce44SJohn Forte iscsi_net->sendpdu = iscsi_net_sendpdu;
217fcf3ce44SJohn Forte iscsi_net->recvhdr = iscsi_net_recvhdr;
218fcf3ce44SJohn Forte iscsi_net->recvdata = iscsi_net_recvdata;
219fcf3ce44SJohn Forte }
220fcf3ce44SJohn Forte
221fcf3ce44SJohn Forte /*
222fcf3ce44SJohn Forte * iscsi_net_fini - release network interface
223fcf3ce44SJohn Forte */
224fcf3ce44SJohn Forte void
iscsi_net_fini()225fcf3ce44SJohn Forte iscsi_net_fini()
226fcf3ce44SJohn Forte {
227fcf3ce44SJohn Forte kmem_free(iscsi_net, sizeof (*iscsi_net));
228fcf3ce44SJohn Forte iscsi_net = NULL;
229fcf3ce44SJohn Forte }
230fcf3ce44SJohn Forte
231fcf3ce44SJohn Forte /*
2329ad4dd06SSheng-Liang Eric Zhang * iscsi_net_set_connect_options -
233fcf3ce44SJohn Forte */
234fcf3ce44SJohn Forte static void
iscsi_net_set_connect_options(void * socket)2359ad4dd06SSheng-Liang Eric Zhang iscsi_net_set_connect_options(void *socket)
236fcf3ce44SJohn Forte {
237fcf3ce44SJohn Forte int ret = 0;
238fcf3ce44SJohn Forte ret += iscsi_net->setsockopt(socket, IPPROTO_TCP,
239fcf3ce44SJohn Forte TCP_CONN_NOTIFY_THRESHOLD, (char *)&iscsi_net->tweaks.
240fcf3ce44SJohn Forte conn_notify_threshold, sizeof (int));
241fcf3ce44SJohn Forte ret += iscsi_net->setsockopt(socket, IPPROTO_TCP,
242fcf3ce44SJohn Forte TCP_CONN_ABORT_THRESHOLD, (char *)&iscsi_net->tweaks.
243fcf3ce44SJohn Forte conn_abort_threshold, sizeof (int));
244fcf3ce44SJohn Forte ret += iscsi_net->setsockopt(socket, IPPROTO_TCP, TCP_ABORT_THRESHOLD,
245fcf3ce44SJohn Forte (char *)&iscsi_net->tweaks.abort_threshold, sizeof (int));
246fcf3ce44SJohn Forte ret += iscsi_net->setsockopt(socket, IPPROTO_TCP, TCP_NODELAY,
247fcf3ce44SJohn Forte (char *)&iscsi_net->tweaks.nodelay, sizeof (int));
248fcf3ce44SJohn Forte ret += iscsi_net->setsockopt(socket, SOL_SOCKET, SO_RCVBUF,
249fcf3ce44SJohn Forte (char *)&iscsi_net->tweaks.rcvbuf, sizeof (int));
250fcf3ce44SJohn Forte ret += iscsi_net->setsockopt(socket, SOL_SOCKET, SO_SNDBUF,
251fcf3ce44SJohn Forte (char *)&iscsi_net->tweaks.sndbuf, sizeof (int));
252fcf3ce44SJohn Forte if (ret != 0) {
253fcf3ce44SJohn Forte cmn_err(CE_NOTE, "iscsi connection failed to set socket option"
2549ad4dd06SSheng-Liang Eric Zhang "TCP_CONN_NOTIFY_THRESHOLD, TCP_CONN_ABORT_THRESHOLD,"
2559ad4dd06SSheng-Liang Eric Zhang "TCP_ABORT_THRESHOLD, TCP_NODELAY, SO_RCVBUF or SO_SNDBUF");
256fcf3ce44SJohn Forte }
257fcf3ce44SJohn Forte }
258fcf3ce44SJohn Forte
259fcf3ce44SJohn Forte /*
260fcf3ce44SJohn Forte * +--------------------------------------------------------------------+
2610f1702c5SYu Xiangning * | register network interfaces |
262fcf3ce44SJohn Forte * +--------------------------------------------------------------------+
263fcf3ce44SJohn Forte */
264fcf3ce44SJohn Forte
265fcf3ce44SJohn Forte /*
266fcf3ce44SJohn Forte * iscsi_net_socket - create socket
267fcf3ce44SJohn Forte */
268fcf3ce44SJohn Forte static void *
iscsi_net_socket(int domain,int type,int protocol)269fcf3ce44SJohn Forte iscsi_net_socket(int domain, int type, int protocol)
270fcf3ce44SJohn Forte {
2710f1702c5SYu Xiangning ksocket_t socket;
272*7284664aSJoshua M. Clulow int err = 0;
273fcf3ce44SJohn Forte
2740f1702c5SYu Xiangning err = ksocket_socket(&socket, domain, type, protocol, KSOCKET_SLEEP,
2750f1702c5SYu Xiangning CRED());
2760f1702c5SYu Xiangning if (!err)
2770f1702c5SYu Xiangning return ((void *)socket);
2780f1702c5SYu Xiangning else
2790f1702c5SYu Xiangning return (NULL);
280fcf3ce44SJohn Forte
281fcf3ce44SJohn Forte }
282fcf3ce44SJohn Forte
283fcf3ce44SJohn Forte /*
284fcf3ce44SJohn Forte * iscsi_net_bind - bind socket to a specific sockaddr
285fcf3ce44SJohn Forte */
2860f1702c5SYu Xiangning /* ARGSUSED */
287fcf3ce44SJohn Forte static int
iscsi_net_bind(void * socket,struct sockaddr * name,int name_len,int backlog,int flags)288fcf3ce44SJohn Forte iscsi_net_bind(void *socket, struct sockaddr *name, int name_len,
289*7284664aSJoshua M. Clulow int backlog, int flags)
290fcf3ce44SJohn Forte {
2910f1702c5SYu Xiangning ksocket_t ks = (ksocket_t)socket;
2920f1702c5SYu Xiangning int error;
2930f1702c5SYu Xiangning error = ksocket_bind(ks, name, name_len, CRED());
2940f1702c5SYu Xiangning if (error == 0 && backlog != 0)
2950f1702c5SYu Xiangning error = ksocket_listen(ks, backlog, CRED());
2960f1702c5SYu Xiangning
2970f1702c5SYu Xiangning return (error);
298fcf3ce44SJohn Forte }
299fcf3ce44SJohn Forte
300fcf3ce44SJohn Forte /*
301fcf3ce44SJohn Forte * iscsi_net_connect - connect socket to peer sockaddr
302fcf3ce44SJohn Forte */
3030f1702c5SYu Xiangning /* ARGSUSED */
304fcf3ce44SJohn Forte static int
iscsi_net_connect(void * socket,struct sockaddr * name,int name_len,int fflag,int flags)305fcf3ce44SJohn Forte iscsi_net_connect(void *socket, struct sockaddr *name, int name_len,
306*7284664aSJoshua M. Clulow int fflag, int flags)
307fcf3ce44SJohn Forte {
3080f1702c5SYu Xiangning ksocket_t ks = (ksocket_t)socket;
309fcf3ce44SJohn Forte int rval;
310fcf3ce44SJohn Forte
3119ad4dd06SSheng-Liang Eric Zhang iscsi_net_set_connect_options(socket);
3120f1702c5SYu Xiangning rval = ksocket_connect(ks, name, name_len, CRED());
313fcf3ce44SJohn Forte
314fcf3ce44SJohn Forte return (rval);
315fcf3ce44SJohn Forte }
316fcf3ce44SJohn Forte
317fcf3ce44SJohn Forte /*
318fcf3ce44SJohn Forte * iscsi_net_listen - listen to socket for peer connections
319fcf3ce44SJohn Forte */
320fcf3ce44SJohn Forte static int
iscsi_net_listen(void * socket,int backlog)321fcf3ce44SJohn Forte iscsi_net_listen(void *socket, int backlog)
322fcf3ce44SJohn Forte {
3230f1702c5SYu Xiangning ksocket_t ks = (ksocket_t)socket;
3240f1702c5SYu Xiangning return (ksocket_listen(ks, backlog, CRED()));
325fcf3ce44SJohn Forte }
326fcf3ce44SJohn Forte
327fcf3ce44SJohn Forte /*
328fcf3ce44SJohn Forte * iscsi_net_accept - accept peer socket connections
329fcf3ce44SJohn Forte */
330fcf3ce44SJohn Forte static void *
iscsi_net_accept(void * socket,struct sockaddr * addr,int * addr_len)331fcf3ce44SJohn Forte iscsi_net_accept(void *socket, struct sockaddr *addr, int *addr_len)
332fcf3ce44SJohn Forte {
3330f1702c5SYu Xiangning ksocket_t listen_ks;
3340f1702c5SYu Xiangning ksocket_t ks = (ksocket_t)socket;
335fcf3ce44SJohn Forte
336c1374a13SSurya Prakki (void) ksocket_accept(ks, addr, (socklen_t *)addr_len, &listen_ks,
337c1374a13SSurya Prakki CRED());
3380f1702c5SYu Xiangning
3390f1702c5SYu Xiangning return ((void *)listen_ks);
340fcf3ce44SJohn Forte }
341fcf3ce44SJohn Forte
342fcf3ce44SJohn Forte /*
343fcf3ce44SJohn Forte * iscsi_net_getsockname -
344fcf3ce44SJohn Forte */
345fcf3ce44SJohn Forte static int
iscsi_net_getsockname(void * socket,struct sockaddr * addr,socklen_t * addrlen)3460f1702c5SYu Xiangning iscsi_net_getsockname(void *socket, struct sockaddr *addr, socklen_t *addrlen)
347fcf3ce44SJohn Forte {
3480f1702c5SYu Xiangning ksocket_t ks = (ksocket_t)socket;
3490f1702c5SYu Xiangning return (ksocket_getsockname(ks, addr, addrlen, CRED()));
350fcf3ce44SJohn Forte }
351fcf3ce44SJohn Forte
352fcf3ce44SJohn Forte /*
353fcf3ce44SJohn Forte * iscsi_net_getsockopt - get value of option on socket
354fcf3ce44SJohn Forte */
3550f1702c5SYu Xiangning /* ARGSUSED */
356fcf3ce44SJohn Forte static int
iscsi_net_getsockopt(void * socket,int level,int option_name,void * option_val,int * option_len,int flags)357fcf3ce44SJohn Forte iscsi_net_getsockopt(void *socket, int level, int option_name,
358*7284664aSJoshua M. Clulow void *option_val, int *option_len, int flags)
359fcf3ce44SJohn Forte {
3600f1702c5SYu Xiangning ksocket_t ks = (ksocket_t)socket;
3610f1702c5SYu Xiangning return (ksocket_getsockopt(ks, level, option_name, option_val,
3620f1702c5SYu Xiangning option_len, CRED()));
363fcf3ce44SJohn Forte }
364fcf3ce44SJohn Forte
365fcf3ce44SJohn Forte /*
366fcf3ce44SJohn Forte * iscsi_net_setsockopt - set value for option on socket
367fcf3ce44SJohn Forte */
368fcf3ce44SJohn Forte static int
iscsi_net_setsockopt(void * socket,int level,int option_name,void * option_val,int option_len)369fcf3ce44SJohn Forte iscsi_net_setsockopt(void *socket, int level, int option_name,
370*7284664aSJoshua M. Clulow void *option_val, int option_len)
371fcf3ce44SJohn Forte {
3720f1702c5SYu Xiangning ksocket_t ks = (ksocket_t)socket;
3730f1702c5SYu Xiangning return (ksocket_setsockopt(ks, level, option_name, option_val,
3740f1702c5SYu Xiangning option_len, CRED()));
375fcf3ce44SJohn Forte }
376fcf3ce44SJohn Forte
377fcf3ce44SJohn Forte /*
378fcf3ce44SJohn Forte * iscsi_net_shutdown - shutdown socket connection
379fcf3ce44SJohn Forte */
380fcf3ce44SJohn Forte static int
iscsi_net_shutdown(void * socket,int how)381fcf3ce44SJohn Forte iscsi_net_shutdown(void *socket, int how)
382fcf3ce44SJohn Forte {
3830f1702c5SYu Xiangning ksocket_t ks = (ksocket_t)socket;
3840f1702c5SYu Xiangning return (ksocket_shutdown(ks, how, CRED()));
385fcf3ce44SJohn Forte }
386fcf3ce44SJohn Forte
387fcf3ce44SJohn Forte /*
388fcf3ce44SJohn Forte * iscsi_net_close - shutdown socket connection and release resources
389fcf3ce44SJohn Forte */
390fcf3ce44SJohn Forte static void
iscsi_net_close(void * socket)391fcf3ce44SJohn Forte iscsi_net_close(void *socket)
392fcf3ce44SJohn Forte {
3930f1702c5SYu Xiangning ksocket_t ks = (ksocket_t)socket;
3940f1702c5SYu Xiangning (void) ksocket_close(ks, CRED());
395fcf3ce44SJohn Forte }
396fcf3ce44SJohn Forte
397fcf3ce44SJohn Forte /*
398fcf3ce44SJohn Forte * iscsi_net_poll - poll socket for data
399fcf3ce44SJohn Forte */
4000f1702c5SYu Xiangning /* ARGSUSED */
401fcf3ce44SJohn Forte static size_t
iscsi_net_poll(void * socket,clock_t timeout)402fcf3ce44SJohn Forte iscsi_net_poll(void *socket, clock_t timeout)
403fcf3ce44SJohn Forte {
404fcf3ce44SJohn Forte int pflag;
4050f1702c5SYu Xiangning char msg[64];
4060f1702c5SYu Xiangning size_t recv = 0;
4070f1702c5SYu Xiangning ksocket_t ks = (ksocket_t)socket;
4080f1702c5SYu Xiangning
409e5083e81Sshenjian if (get_udatamodel() == DATAMODEL_NONE ||
410e5083e81Sshenjian get_udatamodel() == DATAMODEL_NATIVE) {
411e5083e81Sshenjian struct timeval tl;
412e5083e81Sshenjian
413e5083e81Sshenjian /* timeout is millisecond */
414e5083e81Sshenjian tl.tv_sec = timeout / 1000;
415e5083e81Sshenjian tl.tv_usec = (timeout % 1000) * 1000;
416e5083e81Sshenjian if (ksocket_setsockopt(ks, SOL_SOCKET, SO_RCVTIMEO, &tl,
417e5083e81Sshenjian sizeof (struct timeval), CRED()))
418e5083e81Sshenjian return (0);
419e5083e81Sshenjian } else {
420e5083e81Sshenjian struct timeval32 tl;
421e5083e81Sshenjian
422e5083e81Sshenjian /* timeout is millisecond */
423e5083e81Sshenjian tl.tv_sec = timeout / 1000;
424e5083e81Sshenjian tl.tv_usec = (timeout % 1000) * 1000;
425e5083e81Sshenjian if (ksocket_setsockopt(ks, SOL_SOCKET, SO_RCVTIMEO, &tl,
426e5083e81Sshenjian sizeof (struct timeval32), CRED()))
427e5083e81Sshenjian return (0);
428e5083e81Sshenjian }
429fcf3ce44SJohn Forte
430fcf3ce44SJohn Forte pflag = MSG_ANY;
4310f1702c5SYu Xiangning bzero(msg, sizeof (msg));
4320f1702c5SYu Xiangning return (ksocket_recv(ks, msg, sizeof (msg), pflag, &recv, CRED()));
433fcf3ce44SJohn Forte }
434fcf3ce44SJohn Forte
435fcf3ce44SJohn Forte /*
436fcf3ce44SJohn Forte * iscsi_net_sendmsg - send message on socket
437fcf3ce44SJohn Forte */
438fcf3ce44SJohn Forte /* ARGSUSED */
439fcf3ce44SJohn Forte static size_t
iscsi_net_sendmsg(void * socket,struct msghdr * msg)440fcf3ce44SJohn Forte iscsi_net_sendmsg(void *socket, struct msghdr *msg)
441fcf3ce44SJohn Forte {
4420f1702c5SYu Xiangning ksocket_t ks = (ksocket_t)socket;
4430f1702c5SYu Xiangning size_t sent = 0;
4440f1702c5SYu Xiangning int flag = msg->msg_flags;
4450f1702c5SYu Xiangning (void) ksocket_sendmsg(ks, msg, flag, &sent, CRED());
4460f1702c5SYu Xiangning DTRACE_PROBE1(ksocket_sendmsg, size_t, sent);
4470f1702c5SYu Xiangning return (sent);
448fcf3ce44SJohn Forte }
449fcf3ce44SJohn Forte
450fcf3ce44SJohn Forte /*
451fcf3ce44SJohn Forte * iscsi_net_recvmsg - receive message on socket
452fcf3ce44SJohn Forte */
453fcf3ce44SJohn Forte /* ARGSUSED */
454fcf3ce44SJohn Forte static size_t
iscsi_net_recvmsg(void * socket,struct msghdr * msg,int timeout)455fcf3ce44SJohn Forte iscsi_net_recvmsg(void *socket, struct msghdr *msg, int timeout)
456fcf3ce44SJohn Forte {
4570f1702c5SYu Xiangning int prflag = msg->msg_flags;
4580f1702c5SYu Xiangning ksocket_t ks = (ksocket_t)socket;
459*7284664aSJoshua M. Clulow size_t recv = 0;
4600f1702c5SYu Xiangning
4610f1702c5SYu Xiangning /* Set recv timeout */
462e5083e81Sshenjian if (get_udatamodel() == DATAMODEL_NONE ||
463e5083e81Sshenjian get_udatamodel() == DATAMODEL_NATIVE) {
464e5083e81Sshenjian struct timeval tl;
465e5083e81Sshenjian
466e5083e81Sshenjian tl.tv_sec = timeout;
467e5083e81Sshenjian tl.tv_usec = 0;
468e5083e81Sshenjian if (ksocket_setsockopt(ks, SOL_SOCKET, SO_RCVTIMEO, &tl,
469e5083e81Sshenjian sizeof (struct timeval), CRED()))
470e5083e81Sshenjian return (0);
471e5083e81Sshenjian } else {
472e5083e81Sshenjian struct timeval32 tl;
473e5083e81Sshenjian
474e5083e81Sshenjian tl.tv_sec = timeout;
475e5083e81Sshenjian tl.tv_usec = 0;
476e5083e81Sshenjian if (ksocket_setsockopt(ks, SOL_SOCKET, SO_RCVTIMEO, &tl,
477e5083e81Sshenjian sizeof (struct timeval32), CRED()))
478e5083e81Sshenjian return (0);
479e5083e81Sshenjian }
480fcf3ce44SJohn Forte /*
481fcf3ce44SJohn Forte * Receive the requested data. Block until all
4820f1702c5SYu Xiangning * data is received or timeout.
483fcf3ce44SJohn Forte */
484912e288bSJack Meng ksocket_hold(ks);
485c1374a13SSurya Prakki (void) ksocket_recvmsg(ks, msg, prflag, &recv, CRED());
486912e288bSJack Meng ksocket_rele(ks);
4870f1702c5SYu Xiangning DTRACE_PROBE1(ksocket_recvmsg, size_t, recv);
4880f1702c5SYu Xiangning return (recv);
489fcf3ce44SJohn Forte }
490fcf3ce44SJohn Forte
491fcf3ce44SJohn Forte /*
492fcf3ce44SJohn Forte * iscsi_net_sendpdu - send iscsi pdu on socket
493fcf3ce44SJohn Forte */
494fcf3ce44SJohn Forte static iscsi_status_t
iscsi_net_sendpdu(void * socket,iscsi_hdr_t * ihp,char * data,int flags)495fcf3ce44SJohn Forte iscsi_net_sendpdu(void *socket, iscsi_hdr_t *ihp, char *data, int flags)
496fcf3ce44SJohn Forte {
497fcf3ce44SJohn Forte uint32_t pad;
498fcf3ce44SJohn Forte uint32_t crc_hdr;
499fcf3ce44SJohn Forte uint32_t crc_data;
500fcf3ce44SJohn Forte uint32_t pad_len;
501fcf3ce44SJohn Forte uint32_t data_len;
502fcf3ce44SJohn Forte iovec_t iovec[ISCSI_MAX_IOVEC];
503fcf3ce44SJohn Forte int iovlen = 0;
504fcf3ce44SJohn Forte size_t total_len = 0;
505fcf3ce44SJohn Forte size_t send_len;
506fcf3ce44SJohn Forte struct msghdr msg;
507fcf3ce44SJohn Forte
508fcf3ce44SJohn Forte ASSERT(socket != NULL);
509fcf3ce44SJohn Forte ASSERT(ihp != NULL);
510fcf3ce44SJohn Forte
511fcf3ce44SJohn Forte /*
512fcf3ce44SJohn Forte * Let's send the header first. 'hlength' is in 32-bit
513fcf3ce44SJohn Forte * quantities, so we need to multiply by four to get bytes
514fcf3ce44SJohn Forte */
515fcf3ce44SJohn Forte ASSERT(iovlen < ISCSI_MAX_IOVEC);
516fcf3ce44SJohn Forte iovec[iovlen].iov_base = (void *)ihp;
517fcf3ce44SJohn Forte iovec[iovlen].iov_len = sizeof (*ihp) + ihp->hlength * 4;
518fcf3ce44SJohn Forte total_len += sizeof (*ihp) + ihp->hlength * 4;
519fcf3ce44SJohn Forte iovlen++;
520fcf3ce44SJohn Forte
521fcf3ce44SJohn Forte /* Let's transmit the header digest if we have to. */
522fcf3ce44SJohn Forte if ((flags & ISCSI_NET_HEADER_DIGEST) != 0) {
523fcf3ce44SJohn Forte ASSERT(iovlen < ISCSI_MAX_IOVEC);
524fcf3ce44SJohn Forte /*
525fcf3ce44SJohn Forte * Converting the calculated CRC via htonl is not
526fcf3ce44SJohn Forte * necessary because iscsi_crc32c calculates
527fcf3ce44SJohn Forte * the value as it expects to be written
528fcf3ce44SJohn Forte */
529fcf3ce44SJohn Forte crc_hdr = iscsi_crc32c((char *)ihp,
530fcf3ce44SJohn Forte sizeof (iscsi_hdr_t) + ihp->hlength * 4);
531fcf3ce44SJohn Forte
532fcf3ce44SJohn Forte iovec[iovlen].iov_base = (void *)&crc_hdr;
533fcf3ce44SJohn Forte iovec[iovlen].iov_len = sizeof (crc_hdr);
534fcf3ce44SJohn Forte total_len += sizeof (crc_hdr);
535fcf3ce44SJohn Forte iovlen++;
536fcf3ce44SJohn Forte }
537fcf3ce44SJohn Forte
538fcf3ce44SJohn Forte /* Let's transmit the data if any. */
539fcf3ce44SJohn Forte data_len = ntoh24(ihp->dlength);
540fcf3ce44SJohn Forte
541fcf3ce44SJohn Forte if (data_len) {
542fcf3ce44SJohn Forte
543fcf3ce44SJohn Forte ASSERT(iovlen < ISCSI_MAX_IOVEC);
544fcf3ce44SJohn Forte iovec[iovlen].iov_base = (void *)data;
545fcf3ce44SJohn Forte iovec[iovlen].iov_len = data_len;
546fcf3ce44SJohn Forte total_len += data_len;
547fcf3ce44SJohn Forte iovlen++;
548fcf3ce44SJohn Forte
549fcf3ce44SJohn Forte pad_len = ((ISCSI_PAD_WORD_LEN -
550fcf3ce44SJohn Forte (data_len & (ISCSI_PAD_WORD_LEN - 1))) &
551fcf3ce44SJohn Forte (ISCSI_PAD_WORD_LEN - 1));
552fcf3ce44SJohn Forte
553fcf3ce44SJohn Forte /* Let's transmit the data pad if any. */
554fcf3ce44SJohn Forte if (pad_len) {
555fcf3ce44SJohn Forte
556fcf3ce44SJohn Forte ASSERT(iovlen < ISCSI_MAX_IOVEC);
557fcf3ce44SJohn Forte pad = 0;
558fcf3ce44SJohn Forte iovec[iovlen].iov_base = (void *)&pad;
559fcf3ce44SJohn Forte iovec[iovlen].iov_len = pad_len;
560fcf3ce44SJohn Forte total_len += pad_len;
561fcf3ce44SJohn Forte iovlen++;
562fcf3ce44SJohn Forte }
563fcf3ce44SJohn Forte
564fcf3ce44SJohn Forte /* Let's transmit the data digest if we have to. */
565fcf3ce44SJohn Forte if ((flags & ISCSI_NET_DATA_DIGEST) != 0) {
566fcf3ce44SJohn Forte
567fcf3ce44SJohn Forte ASSERT(iovlen < ISCSI_MAX_IOVEC);
568fcf3ce44SJohn Forte /*
569fcf3ce44SJohn Forte * Converting the calculated CRC via htonl is not
570fcf3ce44SJohn Forte * necessary because iscsi_crc32c calculates the
571fcf3ce44SJohn Forte * value as it expects to be written
572fcf3ce44SJohn Forte */
573fcf3ce44SJohn Forte crc_data = iscsi_crc32c(data, data_len);
574fcf3ce44SJohn Forte crc_data = iscsi_crc32c_continued(
575fcf3ce44SJohn Forte (char *)&pad, pad_len, crc_data);
576fcf3ce44SJohn Forte
577fcf3ce44SJohn Forte iovec[iovlen].iov_base = (void *)&crc_data;
578fcf3ce44SJohn Forte iovec[iovlen].iov_len = sizeof (crc_data);
579fcf3ce44SJohn Forte total_len += sizeof (crc_data);
580fcf3ce44SJohn Forte iovlen++;
581fcf3ce44SJohn Forte }
582fcf3ce44SJohn Forte }
583fcf3ce44SJohn Forte
584fcf3ce44SJohn Forte DTRACE_PROBE4(tx, void *, socket, iovec_t *, &iovec[0],
585fcf3ce44SJohn Forte int, iovlen, int, total_len);
586fcf3ce44SJohn Forte
587fcf3ce44SJohn Forte /* Initialization of the message header. */
588fcf3ce44SJohn Forte bzero(&msg, sizeof (msg));
589fcf3ce44SJohn Forte msg.msg_iov = &iovec[0];
590fcf3ce44SJohn Forte msg.msg_flags = MSG_WAITALL;
591fcf3ce44SJohn Forte msg.msg_iovlen = iovlen;
592fcf3ce44SJohn Forte
5930f1702c5SYu Xiangning send_len = iscsi_net->sendmsg(socket, &msg);
594fcf3ce44SJohn Forte DTRACE_PROBE2(sendmsg, size_t, total_len, size_t, send_len);
595fcf3ce44SJohn Forte if (total_len != send_len) {
596fcf3ce44SJohn Forte return (ISCSI_STATUS_TCP_TX_ERROR);
597fcf3ce44SJohn Forte }
598fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS);
599fcf3ce44SJohn Forte }
600fcf3ce44SJohn Forte
601fcf3ce44SJohn Forte /*
602fcf3ce44SJohn Forte * iscsi_net_recvhdr - receive iscsi hdr on socket
603fcf3ce44SJohn Forte */
604fcf3ce44SJohn Forte static iscsi_status_t
iscsi_net_recvhdr(void * socket,iscsi_hdr_t * ihp,int header_length,int timeout,int flags)605fcf3ce44SJohn Forte iscsi_net_recvhdr(void *socket, iscsi_hdr_t *ihp, int header_length,
606fcf3ce44SJohn Forte int timeout, int flags)
607fcf3ce44SJohn Forte {
608fcf3ce44SJohn Forte iovec_t iov[ISCSI_MAX_IOVEC];
609fcf3ce44SJohn Forte int iovlen = 1;
610fcf3ce44SJohn Forte int total_len = 0;
611fcf3ce44SJohn Forte uint32_t crc_actual = 0;
612fcf3ce44SJohn Forte uint32_t crc_calculated = 0;
613fcf3ce44SJohn Forte char *adhdr = NULL;
614fcf3ce44SJohn Forte int adhdr_length = 0;
615fcf3ce44SJohn Forte struct msghdr msg;
616fcf3ce44SJohn Forte size_t recv_len;
617fcf3ce44SJohn Forte
618fcf3ce44SJohn Forte ASSERT(socket != NULL);
619fcf3ce44SJohn Forte ASSERT(ihp != NULL);
620fcf3ce44SJohn Forte
621fcf3ce44SJohn Forte if (header_length < sizeof (iscsi_hdr_t)) {
622fcf3ce44SJohn Forte ASSERT(FALSE);
623fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
624fcf3ce44SJohn Forte }
625fcf3ce44SJohn Forte
626fcf3ce44SJohn Forte /*
627fcf3ce44SJohn Forte * Receive primary header
628fcf3ce44SJohn Forte */
629fcf3ce44SJohn Forte iov[0].iov_base = (char *)ihp;
630fcf3ce44SJohn Forte iov[0].iov_len = sizeof (iscsi_hdr_t);
631fcf3ce44SJohn Forte
632fcf3ce44SJohn Forte bzero(&msg, sizeof (msg));
633fcf3ce44SJohn Forte msg.msg_iov = iov;
634fcf3ce44SJohn Forte msg.msg_flags = MSG_WAITALL;
635fcf3ce44SJohn Forte msg.msg_iovlen = iovlen;
636fcf3ce44SJohn Forte
637fcf3ce44SJohn Forte recv_len = iscsi_net->recvmsg(socket, &msg, timeout);
638fcf3ce44SJohn Forte if (recv_len != sizeof (iscsi_hdr_t)) {
639fcf3ce44SJohn Forte return (ISCSI_STATUS_TCP_RX_ERROR);
640fcf3ce44SJohn Forte }
641fcf3ce44SJohn Forte
642fcf3ce44SJohn Forte DTRACE_PROBE2(rx_hdr, void *, socket, iovec_t *iop, &iov[0]);
643fcf3ce44SJohn Forte
644fcf3ce44SJohn Forte /* verify incoming opcode is a valid operation */
645fcf3ce44SJohn Forte if (is_incoming_opcode_invalid[ihp->opcode]) {
646fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%p) protocol error - "
647fcf3ce44SJohn Forte "received an unsupported opcode:0x%02x",
648fcf3ce44SJohn Forte socket, ihp->opcode);
649fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR);
650fcf3ce44SJohn Forte }
651fcf3ce44SJohn Forte
652fcf3ce44SJohn Forte /*
653fcf3ce44SJohn Forte * Setup receipt of additional header
654fcf3ce44SJohn Forte */
655fcf3ce44SJohn Forte if (ihp->hlength > 0) {
656fcf3ce44SJohn Forte adhdr = ((char *)ihp) + sizeof (iscsi_hdr_t);
657fcf3ce44SJohn Forte adhdr_length = header_length - sizeof (iscsi_hdr_t);
658fcf3ce44SJohn Forte /* make sure enough space is available for adhdr */
659fcf3ce44SJohn Forte if (ihp->hlength > adhdr_length) {
660fcf3ce44SJohn Forte ASSERT(FALSE);
661fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
662fcf3ce44SJohn Forte }
663fcf3ce44SJohn Forte
664fcf3ce44SJohn Forte ASSERT(iovlen < ISCSI_MAX_IOVEC);
665fcf3ce44SJohn Forte iov[iovlen].iov_base = adhdr;
666fcf3ce44SJohn Forte iov[iovlen].iov_len = adhdr_length;
667fcf3ce44SJohn Forte total_len += adhdr_length;
668fcf3ce44SJohn Forte iovlen++;
669fcf3ce44SJohn Forte }
670fcf3ce44SJohn Forte
671fcf3ce44SJohn Forte /*
672fcf3ce44SJohn Forte * Setup receipt of header digest if enabled and connection
673fcf3ce44SJohn Forte * is in full feature mode.
674fcf3ce44SJohn Forte */
675fcf3ce44SJohn Forte if ((flags & ISCSI_NET_HEADER_DIGEST) != 0) {
676fcf3ce44SJohn Forte ASSERT(iovlen < ISCSI_MAX_IOVEC);
677fcf3ce44SJohn Forte iov[iovlen].iov_base = (char *)&crc_actual;
678fcf3ce44SJohn Forte iov[iovlen].iov_len = sizeof (uint32_t);
679fcf3ce44SJohn Forte total_len += sizeof (uint32_t);
680fcf3ce44SJohn Forte iovlen++;
681fcf3ce44SJohn Forte }
682fcf3ce44SJohn Forte
683fcf3ce44SJohn Forte /*
684fcf3ce44SJohn Forte * Read additional header and/or header digest if pieces
685fcf3ce44SJohn Forte * are available
686fcf3ce44SJohn Forte */
687fcf3ce44SJohn Forte if (iovlen > 1) {
688fcf3ce44SJohn Forte
689fcf3ce44SJohn Forte bzero(&msg, sizeof (msg));
690fcf3ce44SJohn Forte msg.msg_iov = iov;
691fcf3ce44SJohn Forte msg.msg_flags = MSG_WAITALL;
692fcf3ce44SJohn Forte msg.msg_iovlen = iovlen;
693fcf3ce44SJohn Forte
694fcf3ce44SJohn Forte recv_len = iscsi_net->recvmsg(socket, &msg, timeout);
695fcf3ce44SJohn Forte if (recv_len != total_len) {
696fcf3ce44SJohn Forte return (ISCSI_STATUS_TCP_RX_ERROR);
697fcf3ce44SJohn Forte }
698fcf3ce44SJohn Forte
699fcf3ce44SJohn Forte DTRACE_PROBE4(rx_adhdr_digest, void *, socket,
700fcf3ce44SJohn Forte iovec_t *iop, &iov[0], int, iovlen, int, total_len);
701fcf3ce44SJohn Forte
702fcf3ce44SJohn Forte /*
703fcf3ce44SJohn Forte * Verify header digest if enabled and connection
704fcf3ce44SJohn Forte * is in full feature mode
705fcf3ce44SJohn Forte */
706fcf3ce44SJohn Forte if ((flags & ISCSI_NET_HEADER_DIGEST) != 0) {
707fcf3ce44SJohn Forte crc_calculated = iscsi_crc32c((uchar_t *)ihp,
708fcf3ce44SJohn Forte sizeof (iscsi_hdr_t) + ihp->hlength * 4);
709fcf3ce44SJohn Forte
710fcf3ce44SJohn Forte /*
711fcf3ce44SJohn Forte * Converting actual CRC read via ntohl is not
712fcf3ce44SJohn Forte * necessary because iscsi_crc32c calculates the
713fcf3ce44SJohn Forte * value as it expect to be read
714fcf3ce44SJohn Forte */
715fcf3ce44SJohn Forte if (crc_calculated != crc_actual) {
716fcf3ce44SJohn Forte /* Invalid Header Digest */
717fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%p) "
718fcf3ce44SJohn Forte "protocol error - encountered a header "
719fcf3ce44SJohn Forte "digest error expected:0x%08x "
720fcf3ce44SJohn Forte "received:0x%08x", socket,
721fcf3ce44SJohn Forte crc_calculated, crc_actual);
722fcf3ce44SJohn Forte return (ISCSI_STATUS_HEADER_DIGEST_ERROR);
723fcf3ce44SJohn Forte }
724fcf3ce44SJohn Forte }
725fcf3ce44SJohn Forte }
726fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS);
727fcf3ce44SJohn Forte }
728fcf3ce44SJohn Forte
729fcf3ce44SJohn Forte
730fcf3ce44SJohn Forte /*
731fcf3ce44SJohn Forte * iscsi_net_recvdata - receive iscsi data payload from socket
732fcf3ce44SJohn Forte */
733fcf3ce44SJohn Forte static iscsi_status_t
iscsi_net_recvdata(void * socket,iscsi_hdr_t * ihp,char * data,int max_data_length,int timeout,int flags)734fcf3ce44SJohn Forte iscsi_net_recvdata(void *socket, iscsi_hdr_t *ihp, char *data,
735fcf3ce44SJohn Forte int max_data_length, int timeout, int flags)
736fcf3ce44SJohn Forte {
737fcf3ce44SJohn Forte struct iovec iov[3];
738fcf3ce44SJohn Forte int iovlen = 1;
739fcf3ce44SJohn Forte int total_len = 0;
740fcf3ce44SJohn Forte int dlength = 0;
741fcf3ce44SJohn Forte int pad_len = 0;
742fcf3ce44SJohn Forte uint8_t pad[ISCSI_PAD_WORD_LEN];
743fcf3ce44SJohn Forte uint32_t crc_calculated = 0;
744fcf3ce44SJohn Forte uint32_t crc_actual = 0;
745fcf3ce44SJohn Forte struct msghdr msg;
746fcf3ce44SJohn Forte size_t recv_len;
747fcf3ce44SJohn Forte
748fcf3ce44SJohn Forte ASSERT(socket != NULL);
749fcf3ce44SJohn Forte ASSERT(ihp != NULL);
750fcf3ce44SJohn Forte ASSERT(data != NULL);
751fcf3ce44SJohn Forte
752fcf3ce44SJohn Forte /* short hand dlength */
753fcf3ce44SJohn Forte dlength = ntoh24(ihp->dlength);
754fcf3ce44SJohn Forte
755fcf3ce44SJohn Forte /* verify dlength is valid */
756fcf3ce44SJohn Forte if (dlength > max_data_length) {
757fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%p) protocol error - "
758fcf3ce44SJohn Forte "invalid data lengths itt:0x%x received:0x%x "
759fcf3ce44SJohn Forte "max expected:0x%x", socket, ihp->itt,
760fcf3ce44SJohn Forte dlength, max_data_length);
761fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR);
762fcf3ce44SJohn Forte }
763fcf3ce44SJohn Forte
764fcf3ce44SJohn Forte if (dlength) {
765fcf3ce44SJohn Forte /* calculate pad */
766fcf3ce44SJohn Forte pad_len = ((ISCSI_PAD_WORD_LEN -
767fcf3ce44SJohn Forte (dlength & (ISCSI_PAD_WORD_LEN - 1))) &
768fcf3ce44SJohn Forte (ISCSI_PAD_WORD_LEN - 1));
769fcf3ce44SJohn Forte
770fcf3ce44SJohn Forte /* setup data iovec */
771fcf3ce44SJohn Forte iov[0].iov_base = (char *)data;
772fcf3ce44SJohn Forte iov[0].iov_len = dlength;
773fcf3ce44SJohn Forte total_len = dlength;
774fcf3ce44SJohn Forte
775fcf3ce44SJohn Forte /* if pad setup pad iovec */
776fcf3ce44SJohn Forte if (pad_len) {
777fcf3ce44SJohn Forte iov[iovlen].iov_base = (char *)&pad;
778fcf3ce44SJohn Forte iov[iovlen].iov_len = pad_len;
779fcf3ce44SJohn Forte total_len += pad_len;
780fcf3ce44SJohn Forte iovlen++;
781fcf3ce44SJohn Forte }
782fcf3ce44SJohn Forte
783fcf3ce44SJohn Forte /* setup data digest */
784fcf3ce44SJohn Forte if ((flags & ISCSI_NET_DATA_DIGEST) != 0) {
785fcf3ce44SJohn Forte iov[iovlen].iov_base = (char *)&crc_actual;
786fcf3ce44SJohn Forte iov[iovlen].iov_len = sizeof (crc_actual);
787fcf3ce44SJohn Forte total_len += sizeof (crc_actual);
788fcf3ce44SJohn Forte iovlen++;
789fcf3ce44SJohn Forte }
790fcf3ce44SJohn Forte
791fcf3ce44SJohn Forte bzero(&msg, sizeof (msg));
792fcf3ce44SJohn Forte msg.msg_iov = iov;
793fcf3ce44SJohn Forte msg.msg_flags = MSG_WAITALL;
794fcf3ce44SJohn Forte msg.msg_iovlen = iovlen;
795fcf3ce44SJohn Forte
796fcf3ce44SJohn Forte recv_len = iscsi_net->recvmsg(socket, &msg, timeout);
797fcf3ce44SJohn Forte if (recv_len != total_len) {
798fcf3ce44SJohn Forte return (ISCSI_STATUS_TCP_RX_ERROR);
799fcf3ce44SJohn Forte }
800fcf3ce44SJohn Forte
801fcf3ce44SJohn Forte DTRACE_PROBE4(rx_data, void *, socket, iovec_t *iop,
802fcf3ce44SJohn Forte &iov[0], int, iovlen, int, total_len);
803fcf3ce44SJohn Forte
804fcf3ce44SJohn Forte /* verify data digest is present */
805fcf3ce44SJohn Forte if ((flags & ISCSI_NET_DATA_DIGEST) != 0) {
806fcf3ce44SJohn Forte
807fcf3ce44SJohn Forte crc_calculated = iscsi_crc32c(data, dlength);
808fcf3ce44SJohn Forte crc_calculated = iscsi_crc32c_continued(
809fcf3ce44SJohn Forte (char *)&pad, pad_len, crc_calculated);
810fcf3ce44SJohn Forte
811fcf3ce44SJohn Forte /*
812fcf3ce44SJohn Forte * Converting actual CRC read via ntohl is not
813fcf3ce44SJohn Forte * necessary because iscsi_crc32c calculates the
814fcf3ce44SJohn Forte * value as it expects to be read
815fcf3ce44SJohn Forte */
816fcf3ce44SJohn Forte if (crc_calculated != crc_actual) {
817fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%p) "
818fcf3ce44SJohn Forte "protocol error - encountered a data "
819fcf3ce44SJohn Forte "digest error itt:0x%x expected:0x%08x "
820fcf3ce44SJohn Forte "received:0x%08x", socket,
821fcf3ce44SJohn Forte ihp->itt, crc_calculated, crc_actual);
822fcf3ce44SJohn Forte return (ISCSI_STATUS_DATA_DIGEST_ERROR);
823fcf3ce44SJohn Forte }
824fcf3ce44SJohn Forte }
825fcf3ce44SJohn Forte }
826fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS);
827fcf3ce44SJohn Forte }
8286cefaae1SJack Meng
8296cefaae1SJack Meng /*
8306cefaae1SJack Meng * Convert a prefix length to a mask.
8316cefaae1SJack Meng */
8326cefaae1SJack Meng static iscsi_status_t
iscsi_prefixlentomask(int prefixlen,int maxlen,uchar_t * mask)8336cefaae1SJack Meng iscsi_prefixlentomask(int prefixlen, int maxlen, uchar_t *mask)
8346cefaae1SJack Meng {
8356cefaae1SJack Meng if (prefixlen < 0 || prefixlen > maxlen || mask == NULL) {
8366cefaae1SJack Meng return (ISCSI_STATUS_INTERNAL_ERROR);
8376cefaae1SJack Meng }
8386cefaae1SJack Meng
8396cefaae1SJack Meng while (prefixlen > 0) {
8406cefaae1SJack Meng if (prefixlen >= 8) {
8416cefaae1SJack Meng *mask = 0xff;
8426cefaae1SJack Meng mask++;
8436cefaae1SJack Meng prefixlen = prefixlen - 8;
8446cefaae1SJack Meng continue;
8456cefaae1SJack Meng }
8466cefaae1SJack Meng *mask = *mask | (1 << (8 - prefixlen));
8476cefaae1SJack Meng prefixlen--;
8486cefaae1SJack Meng }
8496cefaae1SJack Meng return (ISCSI_STATUS_SUCCESS);
8506cefaae1SJack Meng }
8516cefaae1SJack Meng
85230e7468fSPeter Dunlap iscsi_status_t
iscsi_net_interface(boolean_t reset)853bbe72583SJack Meng iscsi_net_interface(boolean_t reset)
8546cefaae1SJack Meng {
8556cefaae1SJack Meng struct in_addr braddr;
8566cefaae1SJack Meng struct in_addr subnet;
8576cefaae1SJack Meng struct in_addr myaddr;
8586cefaae1SJack Meng struct in_addr defgateway;
8596cefaae1SJack Meng struct in6_addr myaddr6;
8606cefaae1SJack Meng struct in6_addr subnet6;
8616cefaae1SJack Meng uchar_t mask_prefix = 0;
8626cefaae1SJack Meng int mask_bits = 1;
8636cefaae1SJack Meng TIUSER *tiptr;
8646cefaae1SJack Meng TIUSER *tiptr6;
8656cefaae1SJack Meng char ifname[16] = {0};
8666cefaae1SJack Meng iscsi_status_t status;
8676cefaae1SJack Meng
8686cefaae1SJack Meng struct knetconfig dl_udp_netconf = {
8696cefaae1SJack Meng NC_TPI_CLTS,
8706cefaae1SJack Meng NC_INET,
8716cefaae1SJack Meng NC_UDP,
8726cefaae1SJack Meng 0, };
8736cefaae1SJack Meng struct knetconfig dl_udp6_netconf = {
8746cefaae1SJack Meng NC_TPI_CLTS,
8756cefaae1SJack Meng NC_INET6,
8766cefaae1SJack Meng NC_UDP,
8776cefaae1SJack Meng 0, };
8786cefaae1SJack Meng
8796cefaae1SJack Meng (void) strlcpy(ifname, rootfs.bo_ifname, sizeof (ifname));
8806cefaae1SJack Meng
8816cefaae1SJack Meng if (iscsiboot_prop->boot_nic.sin_family == AF_INET) {
8826cefaae1SJack Meng /*
8836cefaae1SJack Meng * Assumes only one linkage array element.
8846cefaae1SJack Meng */
8856cefaae1SJack Meng dl_udp_netconf.knc_rdev =
8866cefaae1SJack Meng makedevice(clone_major, ddi_name_to_major("udp"));
8876cefaae1SJack Meng
8886cefaae1SJack Meng myaddr.s_addr =
8896cefaae1SJack Meng iscsiboot_prop->boot_nic.nic_ip_u.u_in4.s_addr;
8906cefaae1SJack Meng
8916cefaae1SJack Meng mask_prefix = iscsiboot_prop->boot_nic.sub_mask_prefix;
8926cefaae1SJack Meng (void) memset(&subnet.s_addr, 0, sizeof (subnet));
8936cefaae1SJack Meng status = iscsi_prefixlentomask(mask_prefix, IP_4_BITS,
8946cefaae1SJack Meng (uchar_t *)&subnet.s_addr);
8956cefaae1SJack Meng if (status != ISCSI_STATUS_SUCCESS) {
8966cefaae1SJack Meng return (status);
8976cefaae1SJack Meng }
8986cefaae1SJack Meng
8996cefaae1SJack Meng mask_bits = mask_bits << (IP_4_BITS - mask_prefix);
9006cefaae1SJack Meng mask_bits = mask_bits - 1;
9016cefaae1SJack Meng /*
9026cefaae1SJack Meng * Set the last mask bits of the ip address with 1, then
9036cefaae1SJack Meng * we can get the broadcast address.
9046cefaae1SJack Meng */
9056cefaae1SJack Meng braddr.s_addr = myaddr.s_addr | mask_bits;
9066cefaae1SJack Meng
9076cefaae1SJack Meng defgateway.s_addr =
9086cefaae1SJack Meng iscsiboot_prop->boot_nic.nic_gw_u.u_in4.s_addr;
9096cefaae1SJack Meng
9106cefaae1SJack Meng /* initialize interface */
9116cefaae1SJack Meng if (t_kopen((file_t *)NULL, dl_udp_netconf.knc_rdev,
9126cefaae1SJack Meng FREAD|FWRITE, &tiptr, CRED()) == 0) {
913dedec472SJack Meng int ret = 0;
914bbe72583SJack Meng if (reset == B_TRUE) {
915bbe72583SJack Meng ret = kdlifconfig(tiptr, AF_INET, &myaddr,
916bbe72583SJack Meng &subnet, NULL, NULL, ifname);
917bbe72583SJack Meng } else if (defgateway.s_addr == 0) {
918dedec472SJack Meng /* No default gate way specified */
919dedec472SJack Meng ret = kdlifconfig(tiptr, AF_INET, &myaddr,
920dedec472SJack Meng &subnet, &braddr, NULL, ifname);
921dedec472SJack Meng } else {
922dedec472SJack Meng ret = kdlifconfig(tiptr, AF_INET, &myaddr,
923dedec472SJack Meng &subnet, &braddr, &defgateway, ifname);
924dedec472SJack Meng }
925dedec472SJack Meng if (ret != 0) {
926bbe72583SJack Meng (void) t_kclose(tiptr, 0);
9276cefaae1SJack Meng cmn_err(CE_WARN, "Failed to configure"
9286cefaae1SJack Meng " iSCSI boot nic");
9296cefaae1SJack Meng return (ISCSI_STATUS_INTERNAL_ERROR);
9306cefaae1SJack Meng }
931bbe72583SJack Meng (void) t_kclose(tiptr, 0);
9326cefaae1SJack Meng } else {
9336cefaae1SJack Meng cmn_err(CE_WARN, "Failed to configure"
9346cefaae1SJack Meng " iSCSI boot nic");
9356cefaae1SJack Meng return (ISCSI_STATUS_INTERNAL_ERROR);
9366cefaae1SJack Meng }
9376cefaae1SJack Meng return (ISCSI_STATUS_SUCCESS);
9386cefaae1SJack Meng } else {
9396cefaae1SJack Meng dl_udp6_netconf.knc_rdev =
9406cefaae1SJack Meng makedevice(clone_major, ddi_name_to_major("udp6"));
9416cefaae1SJack Meng
9426cefaae1SJack Meng bcopy(&iscsiboot_prop->boot_nic.nic_ip_u.u_in6.s6_addr,
9436cefaae1SJack Meng &myaddr6.s6_addr, 16);
9446cefaae1SJack Meng
9456cefaae1SJack Meng (void) memset(&subnet6, 0, sizeof (subnet6));
9466cefaae1SJack Meng mask_prefix = iscsiboot_prop->boot_nic.sub_mask_prefix;
9476cefaae1SJack Meng status = iscsi_prefixlentomask(mask_prefix, IP_6_BITS,
9486cefaae1SJack Meng (uchar_t *)&subnet6.s6_addr);
9496cefaae1SJack Meng if (status != ISCSI_STATUS_SUCCESS) {
9506cefaae1SJack Meng return (status);
9516cefaae1SJack Meng }
9526cefaae1SJack Meng
9536cefaae1SJack Meng if (t_kopen((file_t *)NULL, dl_udp6_netconf.knc_rdev,
9546cefaae1SJack Meng FREAD|FWRITE, &tiptr6, CRED()) == 0) {
9556cefaae1SJack Meng if (kdlifconfig(tiptr6, AF_INET6, &myaddr6,
9566cefaae1SJack Meng &subnet6, NULL, NULL, ifname)) {
9576cefaae1SJack Meng cmn_err(CE_WARN, "Failed to configure"
9586cefaae1SJack Meng " iSCSI boot nic");
959bbe72583SJack Meng (void) t_kclose(tiptr6, 0);
9606cefaae1SJack Meng return (ISCSI_STATUS_INTERNAL_ERROR);
9616cefaae1SJack Meng }
962bbe72583SJack Meng (void) t_kclose(tiptr6, 0);
9636cefaae1SJack Meng } else {
9646cefaae1SJack Meng cmn_err(CE_WARN, "Failed to configure"
9656cefaae1SJack Meng " iSCSI boot nic");
9666cefaae1SJack Meng return (ISCSI_STATUS_INTERNAL_ERROR);
9676cefaae1SJack Meng }
9686cefaae1SJack Meng return (ISCSI_STATUS_SUCCESS);
9696cefaae1SJack Meng }
9706cefaae1SJack Meng }
971