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