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