1*fcf3ce44SJohn Forte /* 2*fcf3ce44SJohn Forte * CDDL HEADER START 3*fcf3ce44SJohn Forte * 4*fcf3ce44SJohn Forte * The contents of this file are subject to the terms of the 5*fcf3ce44SJohn Forte * Common Development and Distribution License (the "License"). 6*fcf3ce44SJohn Forte * You may not use this file except in compliance with the License. 7*fcf3ce44SJohn Forte * 8*fcf3ce44SJohn Forte * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*fcf3ce44SJohn Forte * or http://www.opensolaris.org/os/licensing. 10*fcf3ce44SJohn Forte * See the License for the specific language governing permissions 11*fcf3ce44SJohn Forte * and limitations under the License. 12*fcf3ce44SJohn Forte * 13*fcf3ce44SJohn Forte * When distributing Covered Code, include this CDDL HEADER in each 14*fcf3ce44SJohn Forte * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*fcf3ce44SJohn Forte * If applicable, add the following below this CDDL HEADER, with the 16*fcf3ce44SJohn Forte * fields enclosed by brackets "[]" replaced with your own identifying 17*fcf3ce44SJohn Forte * information: Portions Copyright [yyyy] [name of copyright owner] 18*fcf3ce44SJohn Forte * 19*fcf3ce44SJohn Forte * CDDL HEADER END 20*fcf3ce44SJohn Forte */ 21*fcf3ce44SJohn Forte /* 22*fcf3ce44SJohn Forte * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23*fcf3ce44SJohn Forte * Use is subject to license terms. 24*fcf3ce44SJohn Forte * 25*fcf3ce44SJohn Forte * iSCSI Software Initiator 26*fcf3ce44SJohn Forte */ 27*fcf3ce44SJohn Forte 28*fcf3ce44SJohn Forte #include <sys/socket.h> /* networking stuff */ 29*fcf3ce44SJohn Forte #include <sys/strsubr.h> /* networking stuff */ 30*fcf3ce44SJohn Forte #include <netinet/tcp.h> /* TCP_NODELAY */ 31*fcf3ce44SJohn Forte #include <sys/socketvar.h> /* _ALLOC_SLEEP */ 32*fcf3ce44SJohn Forte #include <sys/pathname.h> /* declares: lookupname */ 33*fcf3ce44SJohn Forte #include <sys/fs/snode.h> /* defines: VTOS */ 34*fcf3ce44SJohn Forte #include <sys/fs/dv_node.h> /* declares: devfs_lookupname */ 35*fcf3ce44SJohn Forte #include <netinet/in.h> 36*fcf3ce44SJohn Forte #include "iscsi.h" 37*fcf3ce44SJohn Forte 38*fcf3ce44SJohn Forte /* 39*fcf3ce44SJohn Forte * This is a high level description of the default 40*fcf3ce44SJohn Forte * iscsi_net transport interfaces. These are used 41*fcf3ce44SJohn Forte * to create, send, recv, and close standard TCP/IP 42*fcf3ce44SJohn Forte * messages. In addition there are extensions to send 43*fcf3ce44SJohn Forte * and recv iSCSI PDU data. 44*fcf3ce44SJohn Forte * 45*fcf3ce44SJohn Forte * NOTE: It would be very easy for an iSCSI HBA vendor 46*fcf3ce44SJohn Forte * to register their own functions over the top of 47*fcf3ce44SJohn Forte * the default interfaces. This would allow an iSCSI 48*fcf3ce44SJohn Forte * HBA to use the same iscsiadm management interfaces 49*fcf3ce44SJohn Forte * and the Solaris iSCSI session / connection management. 50*fcf3ce44SJohn Forte * The current problem with this approach is we only 51*fcf3ce44SJohn Forte * allow one one registered transport table. This 52*fcf3ce44SJohn Forte * would be pretty easy to correct although will require 53*fcf3ce44SJohn Forte * additional CLI changes to manage multiple interfaces. 54*fcf3ce44SJohn Forte * If a vendor can present compelling performance data, 55*fcf3ce44SJohn Forte * then Sun will be willing to enhance this support for 56*fcf3ce44SJohn Forte * multiple interface tables and better CLI management. 57*fcf3ce44SJohn Forte * 58*fcf3ce44SJohn Forte * The following listing describes the iscsi_net 59*fcf3ce44SJohn Forte * entry points: 60*fcf3ce44SJohn Forte * 61*fcf3ce44SJohn Forte * socket - Creates TCP/IP socket connection. In the 62*fcf3ce44SJohn Forte * default implementation creates a sonode 63*fcf3ce44SJohn Forte * via the sockfs kernel layer. 64*fcf3ce44SJohn Forte * bind - Performs standard TCP/IP BSD operation. In 65*fcf3ce44SJohn Forte * the default implementation this only act 66*fcf3ce44SJohn Forte * as a soft binding based on the IP and routing 67*fcf3ce44SJohn Forte * tables. It would be preferred if this was 68*fcf3ce44SJohn Forte * a hard binding but that is currently not 69*fcf3ce44SJohn Forte * possible with Solaris's networking stack. 70*fcf3ce44SJohn Forte * connect - Performs standard TCP/IP BSD operation. This 71*fcf3ce44SJohn Forte * establishes the TCP SYN to the peer IP address. 72*fcf3ce44SJohn Forte * listen - Performs standard TCP/IP BSD operation. This 73*fcf3ce44SJohn Forte * listens for incoming peer connections. 74*fcf3ce44SJohn Forte * accept - Performs standard TCP/IP BSD operation. This 75*fcf3ce44SJohn Forte * accepts incoming peer connections. 76*fcf3ce44SJohn Forte * shutdown - This disconnects the TCP/IP connection while 77*fcf3ce44SJohn Forte * maintaining the resources. 78*fcf3ce44SJohn Forte * close - This disconnects the TCP/IP connection and 79*fcf3ce44SJohn Forte * releases the resources. 80*fcf3ce44SJohn Forte * 81*fcf3ce44SJohn Forte * getsockopt - Gets socket option for specified socket. 82*fcf3ce44SJohn Forte * setsockopt - Sets socket option for specified socket. 83*fcf3ce44SJohn Forte * 84*fcf3ce44SJohn Forte * The current socket options that are used by the initiator 85*fcf3ce44SJohn Forte * are listed below. 86*fcf3ce44SJohn Forte * 87*fcf3ce44SJohn Forte * TCP_CONN_NOTIFY_THRESHOLD 88*fcf3ce44SJohn Forte * TCP_CONN_ABORT_THRESHOLD 89*fcf3ce44SJohn Forte * TCP_ABORT_THRESHOLD 90*fcf3ce44SJohn Forte * TCP_NODELAY 91*fcf3ce44SJohn Forte * SO_RCVBUF 92*fcf3ce44SJohn Forte * SO_SNDBUF 93*fcf3ce44SJohn Forte * 94*fcf3ce44SJohn Forte * iscsi_net_poll - Poll socket interface for a specified amount 95*fcf3ce44SJohn Forte * of data. If data not received in timeout 96*fcf3ce44SJohn Forte * period fail request. 97*fcf3ce44SJohn Forte * iscsi_net_sendmsg - Send message on socket connection 98*fcf3ce44SJohn Forte * iscsi_net_recvmsg - Receive message on socket connection 99*fcf3ce44SJohn Forte * 100*fcf3ce44SJohn Forte * iscsi_net_sendpdu - Send iSCSI PDU on socket connection 101*fcf3ce44SJohn Forte * iscsi_net_recvhdr - Receive iSCSI header on socket connection 102*fcf3ce44SJohn Forte * iscsi_net_recvdata - Receive iSCSI data on socket connection 103*fcf3ce44SJohn Forte * 104*fcf3ce44SJohn Forte * The iSCSI interfaces have the below optional flags. 105*fcf3ce44SJohn Forte * 106*fcf3ce44SJohn Forte * ISCSI_NET_HEADER_DIGEST - The interface should either 107*fcf3ce44SJohn Forte * generate or validate the iSCSI 108*fcf3ce44SJohn Forte * header digest CRC. 109*fcf3ce44SJohn Forte * ISCSI_NET_DATA_DIGESt - The interface should either 110*fcf3ce44SJohn Forte * generate or validate the iSCSI 111*fcf3ce44SJohn Forte * data digest CRC. 112*fcf3ce44SJohn Forte */ 113*fcf3ce44SJohn Forte 114*fcf3ce44SJohn Forte 115*fcf3ce44SJohn Forte /* global */ 116*fcf3ce44SJohn Forte iscsi_network_t *iscsi_net; 117*fcf3ce44SJohn Forte 118*fcf3ce44SJohn Forte /* consts */ 119*fcf3ce44SJohn Forte 120*fcf3ce44SJohn Forte /* 121*fcf3ce44SJohn Forte * This table is used for quick validation of incoming 122*fcf3ce44SJohn Forte * iSCSI PDU opcodes. A value of '0' in the table below 123*fcf3ce44SJohn Forte * indicated that the opcode is invalid for an iSCSI 124*fcf3ce44SJohn Forte * initiator to receive. 125*fcf3ce44SJohn Forte */ 126*fcf3ce44SJohn Forte const int is_incoming_opcode_invalid[256] = { 127*fcf3ce44SJohn Forte /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ 128*fcf3ce44SJohn Forte /* 0x0X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 129*fcf3ce44SJohn Forte /* 0x1X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 130*fcf3ce44SJohn Forte /* 0x2X */ 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 131*fcf3ce44SJohn Forte /* 0x3X */ 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 132*fcf3ce44SJohn Forte /* 0x4X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 133*fcf3ce44SJohn Forte /* 0x5X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 134*fcf3ce44SJohn Forte /* 0x6X */ 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 135*fcf3ce44SJohn Forte /* 0x7X */ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 136*fcf3ce44SJohn Forte /* 0x8X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 137*fcf3ce44SJohn Forte /* 0x9X */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 138*fcf3ce44SJohn Forte /* 0xAX */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 139*fcf3ce44SJohn Forte /* 0xBX */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 140*fcf3ce44SJohn Forte /* 0xCX */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 141*fcf3ce44SJohn Forte /* 0xDX */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 142*fcf3ce44SJohn Forte /* 0xEX */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 143*fcf3ce44SJohn Forte /* 0xFX */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 144*fcf3ce44SJohn Forte }; 145*fcf3ce44SJohn Forte 146*fcf3ce44SJohn Forte /* prototypes */ 147*fcf3ce44SJohn Forte static void * iscsi_net_socket(int domain, int type, int protocol); 148*fcf3ce44SJohn Forte static int iscsi_net_bind(void *socket, struct sockaddr * 149*fcf3ce44SJohn Forte name, int name_len, int backlog, int flags); 150*fcf3ce44SJohn Forte static int iscsi_net_connect(void *socket, struct sockaddr * 151*fcf3ce44SJohn Forte name, int name_len, int fflag, int flags); 152*fcf3ce44SJohn Forte static int iscsi_net_listen(void *socket, int backlog); 153*fcf3ce44SJohn Forte static void * iscsi_net_accept(void *socket, struct sockaddr *addr, 154*fcf3ce44SJohn Forte int *addr_len); 155*fcf3ce44SJohn Forte static int iscsi_net_getsockname(void *socket); 156*fcf3ce44SJohn Forte static int iscsi_net_getsockopt(void *socket, int level, 157*fcf3ce44SJohn Forte int option_name, void *option_val, int *option_len, int flags); 158*fcf3ce44SJohn Forte static int iscsi_net_setsockopt(void *socket, int level, 159*fcf3ce44SJohn Forte int option_name, void *option_val, int option_len); 160*fcf3ce44SJohn Forte static int iscsi_net_shutdown(void *socket, int how); 161*fcf3ce44SJohn Forte static void iscsi_net_close(void *socket); 162*fcf3ce44SJohn Forte 163*fcf3ce44SJohn Forte static size_t iscsi_net_poll(void *socket, clock_t timeout); 164*fcf3ce44SJohn Forte static size_t iscsi_net_sendmsg(void *socket, struct msghdr *msg); 165*fcf3ce44SJohn Forte static size_t iscsi_net_recvmsg(void *socket, 166*fcf3ce44SJohn Forte struct msghdr *msg, int timeout); 167*fcf3ce44SJohn Forte 168*fcf3ce44SJohn Forte static iscsi_status_t iscsi_net_sendpdu(void *socket, iscsi_hdr_t *ihp, 169*fcf3ce44SJohn Forte char *data, int flags); 170*fcf3ce44SJohn Forte static iscsi_status_t iscsi_net_recvdata(void *socket, iscsi_hdr_t *ihp, 171*fcf3ce44SJohn Forte char *data, int max_data_length, int timeout, int flags); 172*fcf3ce44SJohn Forte static iscsi_status_t iscsi_net_recvhdr(void *socket, iscsi_hdr_t *ihp, 173*fcf3ce44SJohn Forte int header_length, int timeout, int flags); 174*fcf3ce44SJohn Forte 175*fcf3ce44SJohn Forte static void iscsi_net_set_preconnect_options(void *socket); 176*fcf3ce44SJohn Forte static void iscsi_net_set_postconnect_options(void *socket); 177*fcf3ce44SJohn Forte 178*fcf3ce44SJohn Forte /* 179*fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 180*fcf3ce44SJohn Forte * | network interface registration functions | 181*fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 182*fcf3ce44SJohn Forte */ 183*fcf3ce44SJohn Forte 184*fcf3ce44SJohn Forte /* 185*fcf3ce44SJohn Forte * iscsi_net_init - initialize network interface 186*fcf3ce44SJohn Forte */ 187*fcf3ce44SJohn Forte void 188*fcf3ce44SJohn Forte iscsi_net_init() 189*fcf3ce44SJohn Forte { 190*fcf3ce44SJohn Forte iscsi_net = kmem_zalloc(sizeof (*iscsi_net), KM_SLEEP); 191*fcf3ce44SJohn Forte 192*fcf3ce44SJohn Forte iscsi_net->socket = iscsi_net_socket; 193*fcf3ce44SJohn Forte 194*fcf3ce44SJohn Forte iscsi_net->bind = iscsi_net_bind; 195*fcf3ce44SJohn Forte iscsi_net->connect = iscsi_net_connect; 196*fcf3ce44SJohn Forte iscsi_net->listen = iscsi_net_listen; 197*fcf3ce44SJohn Forte iscsi_net->accept = iscsi_net_accept; 198*fcf3ce44SJohn Forte iscsi_net->shutdown = iscsi_net_shutdown; 199*fcf3ce44SJohn Forte iscsi_net->close = iscsi_net_close; 200*fcf3ce44SJohn Forte 201*fcf3ce44SJohn Forte iscsi_net->getsockname = iscsi_net_getsockname; 202*fcf3ce44SJohn Forte iscsi_net->getsockopt = iscsi_net_getsockopt; 203*fcf3ce44SJohn Forte iscsi_net->setsockopt = iscsi_net_setsockopt; 204*fcf3ce44SJohn Forte 205*fcf3ce44SJohn Forte iscsi_net->poll = iscsi_net_poll; 206*fcf3ce44SJohn Forte iscsi_net->sendmsg = iscsi_net_sendmsg; 207*fcf3ce44SJohn Forte iscsi_net->recvmsg = iscsi_net_recvmsg; 208*fcf3ce44SJohn Forte 209*fcf3ce44SJohn Forte iscsi_net->sendpdu = iscsi_net_sendpdu; 210*fcf3ce44SJohn Forte iscsi_net->recvhdr = iscsi_net_recvhdr; 211*fcf3ce44SJohn Forte iscsi_net->recvdata = iscsi_net_recvdata; 212*fcf3ce44SJohn Forte } 213*fcf3ce44SJohn Forte 214*fcf3ce44SJohn Forte /* 215*fcf3ce44SJohn Forte * iscsi_net_fini - release network interface 216*fcf3ce44SJohn Forte */ 217*fcf3ce44SJohn Forte void 218*fcf3ce44SJohn Forte iscsi_net_fini() 219*fcf3ce44SJohn Forte { 220*fcf3ce44SJohn Forte kmem_free(iscsi_net, sizeof (*iscsi_net)); 221*fcf3ce44SJohn Forte iscsi_net = NULL; 222*fcf3ce44SJohn Forte } 223*fcf3ce44SJohn Forte 224*fcf3ce44SJohn Forte 225*fcf3ce44SJohn Forte /* 226*fcf3ce44SJohn Forte * iscsi_net_set_preconnect_options - 227*fcf3ce44SJohn Forte */ 228*fcf3ce44SJohn Forte static void 229*fcf3ce44SJohn Forte iscsi_net_set_preconnect_options(void *socket) 230*fcf3ce44SJohn Forte { 231*fcf3ce44SJohn Forte int ret = 0; 232*fcf3ce44SJohn Forte ret += iscsi_net->setsockopt(socket, IPPROTO_TCP, 233*fcf3ce44SJohn Forte TCP_CONN_NOTIFY_THRESHOLD, (char *)&iscsi_net->tweaks. 234*fcf3ce44SJohn Forte conn_notify_threshold, sizeof (int)); 235*fcf3ce44SJohn Forte ret += iscsi_net->setsockopt(socket, IPPROTO_TCP, 236*fcf3ce44SJohn Forte TCP_CONN_ABORT_THRESHOLD, (char *)&iscsi_net->tweaks. 237*fcf3ce44SJohn Forte conn_abort_threshold, sizeof (int)); 238*fcf3ce44SJohn Forte ret += iscsi_net->setsockopt(socket, IPPROTO_TCP, TCP_ABORT_THRESHOLD, 239*fcf3ce44SJohn Forte (char *)&iscsi_net->tweaks.abort_threshold, sizeof (int)); 240*fcf3ce44SJohn Forte if (ret != 0) { 241*fcf3ce44SJohn Forte cmn_err(CE_NOTE, "iscsi connection failed to set socket option" 242*fcf3ce44SJohn Forte "TCP_CONN_NOTIFY_THRESHOLD, TCP_CONN_ABORT_THRESHOLD or " 243*fcf3ce44SJohn Forte "TCP_ABORT_THRESHOLD"); 244*fcf3ce44SJohn Forte } 245*fcf3ce44SJohn Forte } 246*fcf3ce44SJohn Forte 247*fcf3ce44SJohn Forte /* 248*fcf3ce44SJohn Forte * iscsi_net_set_postconnect_options - 249*fcf3ce44SJohn Forte */ 250*fcf3ce44SJohn Forte static void 251*fcf3ce44SJohn Forte iscsi_net_set_postconnect_options(void *socket) 252*fcf3ce44SJohn Forte { 253*fcf3ce44SJohn Forte int ret = 0; 254*fcf3ce44SJohn Forte ret += iscsi_net->setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, 255*fcf3ce44SJohn Forte (char *)&iscsi_net->tweaks.nodelay, sizeof (int)); 256*fcf3ce44SJohn Forte ret += iscsi_net->setsockopt(socket, SOL_SOCKET, SO_RCVBUF, 257*fcf3ce44SJohn Forte (char *)&iscsi_net->tweaks.rcvbuf, sizeof (int)); 258*fcf3ce44SJohn Forte ret += iscsi_net->setsockopt(socket, SOL_SOCKET, SO_SNDBUF, 259*fcf3ce44SJohn Forte (char *)&iscsi_net->tweaks.sndbuf, sizeof (int)); 260*fcf3ce44SJohn Forte if (ret != 0) { 261*fcf3ce44SJohn Forte cmn_err(CE_NOTE, "iscsi connection failed to set socket option" 262*fcf3ce44SJohn Forte "TCP_NODELAY, SO_RCVBUF or SO_SNDBUF"); 263*fcf3ce44SJohn Forte } 264*fcf3ce44SJohn Forte } 265*fcf3ce44SJohn Forte 266*fcf3ce44SJohn Forte 267*fcf3ce44SJohn Forte /* 268*fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 269*fcf3ce44SJohn Forte * | register network interfaces | 270*fcf3ce44SJohn Forte * +--------------------------------------------------------------------+ 271*fcf3ce44SJohn Forte */ 272*fcf3ce44SJohn Forte 273*fcf3ce44SJohn Forte /* 274*fcf3ce44SJohn Forte * iscsi_net_socket - create socket 275*fcf3ce44SJohn Forte */ 276*fcf3ce44SJohn Forte static void * 277*fcf3ce44SJohn Forte iscsi_net_socket(int domain, int type, int protocol) 278*fcf3ce44SJohn Forte { 279*fcf3ce44SJohn Forte vnode_t *dvp = NULL, 280*fcf3ce44SJohn Forte *vp = NULL; 281*fcf3ce44SJohn Forte struct snode *csp = NULL; 282*fcf3ce44SJohn Forte int err = 0; 283*fcf3ce44SJohn Forte major_t maj; 284*fcf3ce44SJohn Forte 285*fcf3ce44SJohn Forte /* ---- solookup: start ---- */ 286*fcf3ce44SJohn Forte if ((vp = solookup(domain, type, protocol, NULL, &err)) == NULL) { 287*fcf3ce44SJohn Forte 288*fcf3ce44SJohn Forte /* 289*fcf3ce44SJohn Forte * solookup calls sogetvp if the vp is not found in 290*fcf3ce44SJohn Forte * the cache. Since the call to sogetvp is hardwired 291*fcf3ce44SJohn Forte * to use USERSPACE and declared static we'll do the 292*fcf3ce44SJohn Forte * work here instead. 293*fcf3ce44SJohn Forte */ 294*fcf3ce44SJohn Forte err = lookupname(type == SOCK_STREAM ? "/dev/tcp" : "/dev/udp", 295*fcf3ce44SJohn Forte UIO_SYSSPACE, FOLLOW, NULLVPP, &vp); 296*fcf3ce44SJohn Forte if (err) 297*fcf3ce44SJohn Forte return (NULL); 298*fcf3ce44SJohn Forte 299*fcf3ce44SJohn Forte /* ---- check that it is the correct vnode ---- */ 300*fcf3ce44SJohn Forte if (vp->v_type != VCHR) { 301*fcf3ce44SJohn Forte VN_RELE(vp); 302*fcf3ce44SJohn Forte return (NULL); 303*fcf3ce44SJohn Forte } 304*fcf3ce44SJohn Forte 305*fcf3ce44SJohn Forte csp = VTOS(VTOS(vp)->s_commonvp); 306*fcf3ce44SJohn Forte if (!(csp->s_flag & SDIPSET)) { 307*fcf3ce44SJohn Forte char *pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP); 308*fcf3ce44SJohn Forte err = ddi_dev_pathname(vp->v_rdev, S_IFCHR, 309*fcf3ce44SJohn Forte pathname); 310*fcf3ce44SJohn Forte if (err == 0) { 311*fcf3ce44SJohn Forte err = devfs_lookupname(pathname, NULLVPP, 312*fcf3ce44SJohn Forte &dvp); 313*fcf3ce44SJohn Forte } 314*fcf3ce44SJohn Forte VN_RELE(vp); 315*fcf3ce44SJohn Forte kmem_free(pathname, MAXPATHLEN); 316*fcf3ce44SJohn Forte if (err != 0) { 317*fcf3ce44SJohn Forte return (NULL); 318*fcf3ce44SJohn Forte } 319*fcf3ce44SJohn Forte vp = dvp; 320*fcf3ce44SJohn Forte } 321*fcf3ce44SJohn Forte 322*fcf3ce44SJohn Forte maj = getmajor(vp->v_rdev); 323*fcf3ce44SJohn Forte if (!STREAMSTAB(maj)) { 324*fcf3ce44SJohn Forte VN_RELE(vp); 325*fcf3ce44SJohn Forte return (NULL); 326*fcf3ce44SJohn Forte } 327*fcf3ce44SJohn Forte } 328*fcf3ce44SJohn Forte /* ---- solookup: end ---- */ 329*fcf3ce44SJohn Forte return (socreate(vp, domain, type, protocol, SOV_DEFAULT, NULL, &err)); 330*fcf3ce44SJohn Forte } 331*fcf3ce44SJohn Forte 332*fcf3ce44SJohn Forte /* 333*fcf3ce44SJohn Forte * iscsi_net_bind - bind socket to a specific sockaddr 334*fcf3ce44SJohn Forte */ 335*fcf3ce44SJohn Forte static int 336*fcf3ce44SJohn Forte iscsi_net_bind(void *socket, struct sockaddr *name, int name_len, 337*fcf3ce44SJohn Forte int backlog, int flags) 338*fcf3ce44SJohn Forte { 339*fcf3ce44SJohn Forte return (sobind((struct sonode *)socket, name, name_len, 340*fcf3ce44SJohn Forte backlog, flags)); 341*fcf3ce44SJohn Forte } 342*fcf3ce44SJohn Forte 343*fcf3ce44SJohn Forte /* 344*fcf3ce44SJohn Forte * iscsi_net_connect - connect socket to peer sockaddr 345*fcf3ce44SJohn Forte */ 346*fcf3ce44SJohn Forte static int 347*fcf3ce44SJohn Forte iscsi_net_connect(void *socket, struct sockaddr *name, int name_len, 348*fcf3ce44SJohn Forte int fflag, int flags) 349*fcf3ce44SJohn Forte { 350*fcf3ce44SJohn Forte int rval; 351*fcf3ce44SJohn Forte 352*fcf3ce44SJohn Forte iscsi_net_set_preconnect_options(socket); 353*fcf3ce44SJohn Forte rval = soconnect((struct sonode *)socket, name, 354*fcf3ce44SJohn Forte name_len, fflag, flags); 355*fcf3ce44SJohn Forte iscsi_net_set_postconnect_options(socket); 356*fcf3ce44SJohn Forte 357*fcf3ce44SJohn Forte return (rval); 358*fcf3ce44SJohn Forte } 359*fcf3ce44SJohn Forte 360*fcf3ce44SJohn Forte /* 361*fcf3ce44SJohn Forte * iscsi_net_listen - listen to socket for peer connections 362*fcf3ce44SJohn Forte */ 363*fcf3ce44SJohn Forte static int 364*fcf3ce44SJohn Forte iscsi_net_listen(void *socket, int backlog) 365*fcf3ce44SJohn Forte { 366*fcf3ce44SJohn Forte return (solisten((struct sonode *)socket, backlog)); 367*fcf3ce44SJohn Forte } 368*fcf3ce44SJohn Forte 369*fcf3ce44SJohn Forte /* 370*fcf3ce44SJohn Forte * iscsi_net_accept - accept peer socket connections 371*fcf3ce44SJohn Forte */ 372*fcf3ce44SJohn Forte static void * 373*fcf3ce44SJohn Forte iscsi_net_accept(void *socket, struct sockaddr *addr, int *addr_len) 374*fcf3ce44SJohn Forte { 375*fcf3ce44SJohn Forte struct sonode *listening_socket; 376*fcf3ce44SJohn Forte 377*fcf3ce44SJohn Forte (void) soaccept((struct sonode *)socket, 378*fcf3ce44SJohn Forte ((struct sonode *)socket)->so_flag, 379*fcf3ce44SJohn Forte &listening_socket); 380*fcf3ce44SJohn Forte if (listening_socket != NULL) { 381*fcf3ce44SJohn Forte bcopy(listening_socket->so_faddr_sa, addr, 382*fcf3ce44SJohn Forte (socklen_t)listening_socket->so_faddr_len); 383*fcf3ce44SJohn Forte *addr_len = listening_socket->so_faddr_len; 384*fcf3ce44SJohn Forte } else { 385*fcf3ce44SJohn Forte *addr_len = 0; 386*fcf3ce44SJohn Forte } 387*fcf3ce44SJohn Forte 388*fcf3ce44SJohn Forte return ((void *)listening_socket); 389*fcf3ce44SJohn Forte } 390*fcf3ce44SJohn Forte 391*fcf3ce44SJohn Forte /* 392*fcf3ce44SJohn Forte * iscsi_net_getsockname - 393*fcf3ce44SJohn Forte */ 394*fcf3ce44SJohn Forte static int 395*fcf3ce44SJohn Forte iscsi_net_getsockname(void *socket) 396*fcf3ce44SJohn Forte { 397*fcf3ce44SJohn Forte return (sogetsockname((struct sonode *)socket)); 398*fcf3ce44SJohn Forte } 399*fcf3ce44SJohn Forte 400*fcf3ce44SJohn Forte /* 401*fcf3ce44SJohn Forte * iscsi_net_getsockopt - get value of option on socket 402*fcf3ce44SJohn Forte */ 403*fcf3ce44SJohn Forte static int 404*fcf3ce44SJohn Forte iscsi_net_getsockopt(void *socket, int level, int option_name, 405*fcf3ce44SJohn Forte void *option_val, int *option_len, int flags) 406*fcf3ce44SJohn Forte { 407*fcf3ce44SJohn Forte return (sogetsockopt((struct sonode *)socket, level, 408*fcf3ce44SJohn Forte option_name, option_val, (socklen_t *)option_len, 409*fcf3ce44SJohn Forte flags)); 410*fcf3ce44SJohn Forte } 411*fcf3ce44SJohn Forte 412*fcf3ce44SJohn Forte /* 413*fcf3ce44SJohn Forte * iscsi_net_setsockopt - set value for option on socket 414*fcf3ce44SJohn Forte */ 415*fcf3ce44SJohn Forte static int 416*fcf3ce44SJohn Forte iscsi_net_setsockopt(void *socket, int level, int option_name, 417*fcf3ce44SJohn Forte void *option_val, int option_len) 418*fcf3ce44SJohn Forte { 419*fcf3ce44SJohn Forte return (sosetsockopt((struct sonode *)socket, level, 420*fcf3ce44SJohn Forte option_name, option_val, option_len)); 421*fcf3ce44SJohn Forte } 422*fcf3ce44SJohn Forte 423*fcf3ce44SJohn Forte /* 424*fcf3ce44SJohn Forte * iscsi_net_shutdown - shutdown socket connection 425*fcf3ce44SJohn Forte */ 426*fcf3ce44SJohn Forte static int 427*fcf3ce44SJohn Forte iscsi_net_shutdown(void *socket, int how) 428*fcf3ce44SJohn Forte { 429*fcf3ce44SJohn Forte return (soshutdown((struct sonode *)socket, how)); 430*fcf3ce44SJohn Forte } 431*fcf3ce44SJohn Forte 432*fcf3ce44SJohn Forte /* 433*fcf3ce44SJohn Forte * iscsi_net_close - shutdown socket connection and release resources 434*fcf3ce44SJohn Forte */ 435*fcf3ce44SJohn Forte static void 436*fcf3ce44SJohn Forte iscsi_net_close(void *socket) 437*fcf3ce44SJohn Forte { 438*fcf3ce44SJohn Forte vnode_t *vp = SOTOV((struct sonode *)socket); 439*fcf3ce44SJohn Forte (void) soshutdown((struct sonode *)socket, 2); 440*fcf3ce44SJohn Forte (void) VOP_CLOSE(vp, 0, 1, 0, kcred, NULL); 441*fcf3ce44SJohn Forte VN_RELE(vp); 442*fcf3ce44SJohn Forte } 443*fcf3ce44SJohn Forte 444*fcf3ce44SJohn Forte /* 445*fcf3ce44SJohn Forte * iscsi_net_poll - poll socket for data 446*fcf3ce44SJohn Forte */ 447*fcf3ce44SJohn Forte static size_t 448*fcf3ce44SJohn Forte iscsi_net_poll(void *socket, clock_t timeout) 449*fcf3ce44SJohn Forte { 450*fcf3ce44SJohn Forte int pflag; 451*fcf3ce44SJohn Forte uchar_t pri; 452*fcf3ce44SJohn Forte rval_t rval; 453*fcf3ce44SJohn Forte 454*fcf3ce44SJohn Forte pri = 0; 455*fcf3ce44SJohn Forte pflag = MSG_ANY; 456*fcf3ce44SJohn Forte return (kstrgetmsg(SOTOV((struct sonode *)socket), NULL, NULL, 457*fcf3ce44SJohn Forte &pri, &pflag, timeout, &rval)); 458*fcf3ce44SJohn Forte } 459*fcf3ce44SJohn Forte 460*fcf3ce44SJohn Forte /* 461*fcf3ce44SJohn Forte * iscsi_net_sendmsg - send message on socket 462*fcf3ce44SJohn Forte */ 463*fcf3ce44SJohn Forte /* ARGSUSED */ 464*fcf3ce44SJohn Forte static size_t 465*fcf3ce44SJohn Forte iscsi_net_sendmsg(void *socket, struct msghdr *msg) 466*fcf3ce44SJohn Forte { 467*fcf3ce44SJohn Forte int i = 0; 468*fcf3ce44SJohn Forte int total_len = 0; 469*fcf3ce44SJohn Forte struct uio uio; 470*fcf3ce44SJohn Forte 471*fcf3ce44SJohn Forte /* Initialization of the uio structure. */ 472*fcf3ce44SJohn Forte bzero(&uio, sizeof (uio)); 473*fcf3ce44SJohn Forte uio.uio_iov = msg->msg_iov; 474*fcf3ce44SJohn Forte uio.uio_iovcnt = msg->msg_iovlen; 475*fcf3ce44SJohn Forte uio.uio_segflg = UIO_SYSSPACE; 476*fcf3ce44SJohn Forte 477*fcf3ce44SJohn Forte for (i = 0; i < msg->msg_iovlen; i++) { 478*fcf3ce44SJohn Forte total_len += (msg->msg_iov)[i].iov_len; 479*fcf3ce44SJohn Forte } 480*fcf3ce44SJohn Forte uio.uio_resid = total_len; 481*fcf3ce44SJohn Forte 482*fcf3ce44SJohn Forte (void) sosendmsg((struct sonode *)socket, msg, &uio); 483*fcf3ce44SJohn Forte DTRACE_PROBE2(sosendmsg, size_t, total_len, size_t, uio.uio_resid); 484*fcf3ce44SJohn Forte return (total_len - uio.uio_resid); 485*fcf3ce44SJohn Forte } 486*fcf3ce44SJohn Forte 487*fcf3ce44SJohn Forte /* 488*fcf3ce44SJohn Forte * iscsi_net_recvmsg - receive message on socket 489*fcf3ce44SJohn Forte */ 490*fcf3ce44SJohn Forte /* ARGSUSED */ 491*fcf3ce44SJohn Forte static size_t 492*fcf3ce44SJohn Forte iscsi_net_recvmsg(void *socket, struct msghdr *msg, int timeout) 493*fcf3ce44SJohn Forte { 494*fcf3ce44SJohn Forte int idx; 495*fcf3ce44SJohn Forte int total_len = 0; 496*fcf3ce44SJohn Forte struct uio uio; 497*fcf3ce44SJohn Forte uchar_t pri = 0; 498*fcf3ce44SJohn Forte int prflag = MSG_ANY; 499*fcf3ce44SJohn Forte rval_t rval; 500*fcf3ce44SJohn Forte struct sonode *sonode = (struct sonode *)socket; 501*fcf3ce44SJohn Forte 502*fcf3ce44SJohn Forte /* Initialization of the uio structure. */ 503*fcf3ce44SJohn Forte bzero(&uio, sizeof (uio)); 504*fcf3ce44SJohn Forte uio.uio_iov = msg->msg_iov; 505*fcf3ce44SJohn Forte uio.uio_iovcnt = msg->msg_iovlen; 506*fcf3ce44SJohn Forte uio.uio_segflg = UIO_SYSSPACE; 507*fcf3ce44SJohn Forte 508*fcf3ce44SJohn Forte for (idx = 0; idx < msg->msg_iovlen; idx++) { 509*fcf3ce44SJohn Forte total_len += (msg->msg_iov)[idx].iov_len; 510*fcf3ce44SJohn Forte } 511*fcf3ce44SJohn Forte uio.uio_resid = total_len; 512*fcf3ce44SJohn Forte 513*fcf3ce44SJohn Forte /* If timeout requested on receive */ 514*fcf3ce44SJohn Forte if (timeout > 0) { 515*fcf3ce44SJohn Forte boolean_t loopback = B_FALSE; 516*fcf3ce44SJohn Forte 517*fcf3ce44SJohn Forte /* And this isn't a loopback connection */ 518*fcf3ce44SJohn Forte if (sonode->so_laddr.soa_sa->sa_family == AF_INET) { 519*fcf3ce44SJohn Forte struct sockaddr_in *lin = 520*fcf3ce44SJohn Forte (struct sockaddr_in *)sonode->so_laddr.soa_sa; 521*fcf3ce44SJohn Forte struct sockaddr_in *fin = 522*fcf3ce44SJohn Forte (struct sockaddr_in *)sonode->so_faddr.soa_sa; 523*fcf3ce44SJohn Forte 524*fcf3ce44SJohn Forte if ((lin->sin_family == fin->sin_family) && 525*fcf3ce44SJohn Forte (bcmp(&lin->sin_addr, &fin->sin_addr, 526*fcf3ce44SJohn Forte sizeof (struct in_addr)) == 0)) { 527*fcf3ce44SJohn Forte loopback = B_TRUE; 528*fcf3ce44SJohn Forte } 529*fcf3ce44SJohn Forte } else { 530*fcf3ce44SJohn Forte struct sockaddr_in6 *lin6 = 531*fcf3ce44SJohn Forte (struct sockaddr_in6 *)sonode->so_laddr.soa_sa; 532*fcf3ce44SJohn Forte struct sockaddr_in6 *fin6 = 533*fcf3ce44SJohn Forte (struct sockaddr_in6 *)sonode->so_faddr.soa_sa; 534*fcf3ce44SJohn Forte 535*fcf3ce44SJohn Forte if ((lin6->sin6_family == fin6->sin6_family) && 536*fcf3ce44SJohn Forte (bcmp(&lin6->sin6_addr, &fin6->sin6_addr, 537*fcf3ce44SJohn Forte sizeof (struct in6_addr)) == 0)) { 538*fcf3ce44SJohn Forte loopback = B_TRUE; 539*fcf3ce44SJohn Forte } 540*fcf3ce44SJohn Forte } 541*fcf3ce44SJohn Forte 542*fcf3ce44SJohn Forte if (loopback == B_FALSE) { 543*fcf3ce44SJohn Forte /* 544*fcf3ce44SJohn Forte * Then poll device for up to the timeout 545*fcf3ce44SJohn Forte * period or the requested data is received. 546*fcf3ce44SJohn Forte */ 547*fcf3ce44SJohn Forte if (kstrgetmsg(SOTOV(sonode), 548*fcf3ce44SJohn Forte NULL, NULL, &pri, &prflag, timeout * 1000, 549*fcf3ce44SJohn Forte &rval) == ETIME) { 550*fcf3ce44SJohn Forte return (0); 551*fcf3ce44SJohn Forte } 552*fcf3ce44SJohn Forte } 553*fcf3ce44SJohn Forte } 554*fcf3ce44SJohn Forte 555*fcf3ce44SJohn Forte /* 556*fcf3ce44SJohn Forte * Receive the requested data. Block until all 557*fcf3ce44SJohn Forte * data is received. 558*fcf3ce44SJohn Forte * 559*fcf3ce44SJohn Forte * resid occurs only when the connection is 560*fcf3ce44SJohn Forte * disconnected. In that case it will return 561*fcf3ce44SJohn Forte * the amount of data that was not received. 562*fcf3ce44SJohn Forte * In general this is the total amount we 563*fcf3ce44SJohn Forte * requested. 564*fcf3ce44SJohn Forte */ 565*fcf3ce44SJohn Forte (void) sorecvmsg((struct sonode *)socket, msg, &uio); 566*fcf3ce44SJohn Forte DTRACE_PROBE2(sorecvmsg, size_t, total_len, size_t, uio.uio_resid); 567*fcf3ce44SJohn Forte return (total_len - uio.uio_resid); 568*fcf3ce44SJohn Forte } 569*fcf3ce44SJohn Forte 570*fcf3ce44SJohn Forte /* 571*fcf3ce44SJohn Forte * iscsi_net_sendpdu - send iscsi pdu on socket 572*fcf3ce44SJohn Forte */ 573*fcf3ce44SJohn Forte static iscsi_status_t 574*fcf3ce44SJohn Forte iscsi_net_sendpdu(void *socket, iscsi_hdr_t *ihp, char *data, int flags) 575*fcf3ce44SJohn Forte { 576*fcf3ce44SJohn Forte uint32_t pad; 577*fcf3ce44SJohn Forte uint32_t crc_hdr; 578*fcf3ce44SJohn Forte uint32_t crc_data; 579*fcf3ce44SJohn Forte uint32_t pad_len; 580*fcf3ce44SJohn Forte uint32_t data_len; 581*fcf3ce44SJohn Forte iovec_t iovec[ISCSI_MAX_IOVEC]; 582*fcf3ce44SJohn Forte int iovlen = 0; 583*fcf3ce44SJohn Forte size_t total_len = 0; 584*fcf3ce44SJohn Forte size_t send_len; 585*fcf3ce44SJohn Forte struct msghdr msg; 586*fcf3ce44SJohn Forte 587*fcf3ce44SJohn Forte ASSERT(socket != NULL); 588*fcf3ce44SJohn Forte ASSERT(ihp != NULL); 589*fcf3ce44SJohn Forte 590*fcf3ce44SJohn Forte /* 591*fcf3ce44SJohn Forte * Let's send the header first. 'hlength' is in 32-bit 592*fcf3ce44SJohn Forte * quantities, so we need to multiply by four to get bytes 593*fcf3ce44SJohn Forte */ 594*fcf3ce44SJohn Forte ASSERT(iovlen < ISCSI_MAX_IOVEC); 595*fcf3ce44SJohn Forte iovec[iovlen].iov_base = (void *)ihp; 596*fcf3ce44SJohn Forte iovec[iovlen].iov_len = sizeof (*ihp) + ihp->hlength * 4; 597*fcf3ce44SJohn Forte total_len += sizeof (*ihp) + ihp->hlength * 4; 598*fcf3ce44SJohn Forte iovlen++; 599*fcf3ce44SJohn Forte 600*fcf3ce44SJohn Forte /* Let's transmit the header digest if we have to. */ 601*fcf3ce44SJohn Forte if ((flags & ISCSI_NET_HEADER_DIGEST) != 0) { 602*fcf3ce44SJohn Forte ASSERT(iovlen < ISCSI_MAX_IOVEC); 603*fcf3ce44SJohn Forte /* 604*fcf3ce44SJohn Forte * Converting the calculated CRC via htonl is not 605*fcf3ce44SJohn Forte * necessary because iscsi_crc32c calculates 606*fcf3ce44SJohn Forte * the value as it expects to be written 607*fcf3ce44SJohn Forte */ 608*fcf3ce44SJohn Forte crc_hdr = iscsi_crc32c((char *)ihp, 609*fcf3ce44SJohn Forte sizeof (iscsi_hdr_t) + ihp->hlength * 4); 610*fcf3ce44SJohn Forte 611*fcf3ce44SJohn Forte iovec[iovlen].iov_base = (void *)&crc_hdr; 612*fcf3ce44SJohn Forte iovec[iovlen].iov_len = sizeof (crc_hdr); 613*fcf3ce44SJohn Forte total_len += sizeof (crc_hdr); 614*fcf3ce44SJohn Forte iovlen++; 615*fcf3ce44SJohn Forte } 616*fcf3ce44SJohn Forte 617*fcf3ce44SJohn Forte /* Let's transmit the data if any. */ 618*fcf3ce44SJohn Forte data_len = ntoh24(ihp->dlength); 619*fcf3ce44SJohn Forte 620*fcf3ce44SJohn Forte if (data_len) { 621*fcf3ce44SJohn Forte 622*fcf3ce44SJohn Forte ASSERT(iovlen < ISCSI_MAX_IOVEC); 623*fcf3ce44SJohn Forte iovec[iovlen].iov_base = (void *)data; 624*fcf3ce44SJohn Forte iovec[iovlen].iov_len = data_len; 625*fcf3ce44SJohn Forte total_len += data_len; 626*fcf3ce44SJohn Forte iovlen++; 627*fcf3ce44SJohn Forte 628*fcf3ce44SJohn Forte pad_len = ((ISCSI_PAD_WORD_LEN - 629*fcf3ce44SJohn Forte (data_len & (ISCSI_PAD_WORD_LEN - 1))) & 630*fcf3ce44SJohn Forte (ISCSI_PAD_WORD_LEN - 1)); 631*fcf3ce44SJohn Forte 632*fcf3ce44SJohn Forte /* Let's transmit the data pad if any. */ 633*fcf3ce44SJohn Forte if (pad_len) { 634*fcf3ce44SJohn Forte 635*fcf3ce44SJohn Forte ASSERT(iovlen < ISCSI_MAX_IOVEC); 636*fcf3ce44SJohn Forte pad = 0; 637*fcf3ce44SJohn Forte iovec[iovlen].iov_base = (void *)&pad; 638*fcf3ce44SJohn Forte iovec[iovlen].iov_len = pad_len; 639*fcf3ce44SJohn Forte total_len += pad_len; 640*fcf3ce44SJohn Forte iovlen++; 641*fcf3ce44SJohn Forte } 642*fcf3ce44SJohn Forte 643*fcf3ce44SJohn Forte /* Let's transmit the data digest if we have to. */ 644*fcf3ce44SJohn Forte if ((flags & ISCSI_NET_DATA_DIGEST) != 0) { 645*fcf3ce44SJohn Forte 646*fcf3ce44SJohn Forte ASSERT(iovlen < ISCSI_MAX_IOVEC); 647*fcf3ce44SJohn Forte /* 648*fcf3ce44SJohn Forte * Converting the calculated CRC via htonl is not 649*fcf3ce44SJohn Forte * necessary because iscsi_crc32c calculates the 650*fcf3ce44SJohn Forte * value as it expects to be written 651*fcf3ce44SJohn Forte */ 652*fcf3ce44SJohn Forte crc_data = iscsi_crc32c(data, data_len); 653*fcf3ce44SJohn Forte crc_data = iscsi_crc32c_continued( 654*fcf3ce44SJohn Forte (char *)&pad, pad_len, crc_data); 655*fcf3ce44SJohn Forte 656*fcf3ce44SJohn Forte iovec[iovlen].iov_base = (void *)&crc_data; 657*fcf3ce44SJohn Forte iovec[iovlen].iov_len = sizeof (crc_data); 658*fcf3ce44SJohn Forte total_len += sizeof (crc_data); 659*fcf3ce44SJohn Forte iovlen++; 660*fcf3ce44SJohn Forte } 661*fcf3ce44SJohn Forte } 662*fcf3ce44SJohn Forte 663*fcf3ce44SJohn Forte DTRACE_PROBE4(tx, void *, socket, iovec_t *, &iovec[0], 664*fcf3ce44SJohn Forte int, iovlen, int, total_len); 665*fcf3ce44SJohn Forte 666*fcf3ce44SJohn Forte /* Initialization of the message header. */ 667*fcf3ce44SJohn Forte bzero(&msg, sizeof (msg)); 668*fcf3ce44SJohn Forte msg.msg_iov = &iovec[0]; 669*fcf3ce44SJohn Forte msg.msg_flags = MSG_WAITALL; 670*fcf3ce44SJohn Forte msg.msg_iovlen = iovlen; 671*fcf3ce44SJohn Forte 672*fcf3ce44SJohn Forte send_len = iscsi_net->sendmsg((struct sonode *)socket, &msg); 673*fcf3ce44SJohn Forte DTRACE_PROBE2(sendmsg, size_t, total_len, size_t, send_len); 674*fcf3ce44SJohn Forte if (total_len != send_len) { 675*fcf3ce44SJohn Forte return (ISCSI_STATUS_TCP_TX_ERROR); 676*fcf3ce44SJohn Forte } 677*fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS); 678*fcf3ce44SJohn Forte } 679*fcf3ce44SJohn Forte 680*fcf3ce44SJohn Forte /* 681*fcf3ce44SJohn Forte * iscsi_net_recvhdr - receive iscsi hdr on socket 682*fcf3ce44SJohn Forte */ 683*fcf3ce44SJohn Forte static iscsi_status_t 684*fcf3ce44SJohn Forte iscsi_net_recvhdr(void *socket, iscsi_hdr_t *ihp, int header_length, 685*fcf3ce44SJohn Forte int timeout, int flags) 686*fcf3ce44SJohn Forte { 687*fcf3ce44SJohn Forte iovec_t iov[ISCSI_MAX_IOVEC]; 688*fcf3ce44SJohn Forte int iovlen = 1; 689*fcf3ce44SJohn Forte int total_len = 0; 690*fcf3ce44SJohn Forte uint32_t crc_actual = 0; 691*fcf3ce44SJohn Forte uint32_t crc_calculated = 0; 692*fcf3ce44SJohn Forte char *adhdr = NULL; 693*fcf3ce44SJohn Forte int adhdr_length = 0; 694*fcf3ce44SJohn Forte struct msghdr msg; 695*fcf3ce44SJohn Forte size_t recv_len; 696*fcf3ce44SJohn Forte 697*fcf3ce44SJohn Forte ASSERT(socket != NULL); 698*fcf3ce44SJohn Forte ASSERT(ihp != NULL); 699*fcf3ce44SJohn Forte 700*fcf3ce44SJohn Forte if (header_length < sizeof (iscsi_hdr_t)) { 701*fcf3ce44SJohn Forte ASSERT(FALSE); 702*fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR); 703*fcf3ce44SJohn Forte } 704*fcf3ce44SJohn Forte 705*fcf3ce44SJohn Forte /* 706*fcf3ce44SJohn Forte * Receive primary header 707*fcf3ce44SJohn Forte */ 708*fcf3ce44SJohn Forte iov[0].iov_base = (char *)ihp; 709*fcf3ce44SJohn Forte iov[0].iov_len = sizeof (iscsi_hdr_t); 710*fcf3ce44SJohn Forte 711*fcf3ce44SJohn Forte bzero(&msg, sizeof (msg)); 712*fcf3ce44SJohn Forte msg.msg_iov = iov; 713*fcf3ce44SJohn Forte msg.msg_flags = MSG_WAITALL; 714*fcf3ce44SJohn Forte msg.msg_iovlen = iovlen; 715*fcf3ce44SJohn Forte 716*fcf3ce44SJohn Forte recv_len = iscsi_net->recvmsg(socket, &msg, timeout); 717*fcf3ce44SJohn Forte if (recv_len != sizeof (iscsi_hdr_t)) { 718*fcf3ce44SJohn Forte return (ISCSI_STATUS_TCP_RX_ERROR); 719*fcf3ce44SJohn Forte } 720*fcf3ce44SJohn Forte 721*fcf3ce44SJohn Forte DTRACE_PROBE2(rx_hdr, void *, socket, iovec_t *iop, &iov[0]); 722*fcf3ce44SJohn Forte 723*fcf3ce44SJohn Forte /* verify incoming opcode is a valid operation */ 724*fcf3ce44SJohn Forte if (is_incoming_opcode_invalid[ihp->opcode]) { 725*fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%p) protocol error - " 726*fcf3ce44SJohn Forte "received an unsupported opcode:0x%02x", 727*fcf3ce44SJohn Forte socket, ihp->opcode); 728*fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR); 729*fcf3ce44SJohn Forte } 730*fcf3ce44SJohn Forte 731*fcf3ce44SJohn Forte /* 732*fcf3ce44SJohn Forte * Setup receipt of additional header 733*fcf3ce44SJohn Forte */ 734*fcf3ce44SJohn Forte if (ihp->hlength > 0) { 735*fcf3ce44SJohn Forte adhdr = ((char *)ihp) + sizeof (iscsi_hdr_t); 736*fcf3ce44SJohn Forte adhdr_length = header_length - sizeof (iscsi_hdr_t); 737*fcf3ce44SJohn Forte /* make sure enough space is available for adhdr */ 738*fcf3ce44SJohn Forte if (ihp->hlength > adhdr_length) { 739*fcf3ce44SJohn Forte ASSERT(FALSE); 740*fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR); 741*fcf3ce44SJohn Forte } 742*fcf3ce44SJohn Forte 743*fcf3ce44SJohn Forte ASSERT(iovlen < ISCSI_MAX_IOVEC); 744*fcf3ce44SJohn Forte iov[iovlen].iov_base = adhdr; 745*fcf3ce44SJohn Forte iov[iovlen].iov_len = adhdr_length; 746*fcf3ce44SJohn Forte total_len += adhdr_length; 747*fcf3ce44SJohn Forte iovlen++; 748*fcf3ce44SJohn Forte } 749*fcf3ce44SJohn Forte 750*fcf3ce44SJohn Forte /* 751*fcf3ce44SJohn Forte * Setup receipt of header digest if enabled and connection 752*fcf3ce44SJohn Forte * is in full feature mode. 753*fcf3ce44SJohn Forte */ 754*fcf3ce44SJohn Forte if ((flags & ISCSI_NET_HEADER_DIGEST) != 0) { 755*fcf3ce44SJohn Forte ASSERT(iovlen < ISCSI_MAX_IOVEC); 756*fcf3ce44SJohn Forte iov[iovlen].iov_base = (char *)&crc_actual; 757*fcf3ce44SJohn Forte iov[iovlen].iov_len = sizeof (uint32_t); 758*fcf3ce44SJohn Forte total_len += sizeof (uint32_t); 759*fcf3ce44SJohn Forte iovlen++; 760*fcf3ce44SJohn Forte } 761*fcf3ce44SJohn Forte 762*fcf3ce44SJohn Forte /* 763*fcf3ce44SJohn Forte * Read additional header and/or header digest if pieces 764*fcf3ce44SJohn Forte * are available 765*fcf3ce44SJohn Forte */ 766*fcf3ce44SJohn Forte if (iovlen > 1) { 767*fcf3ce44SJohn Forte 768*fcf3ce44SJohn Forte bzero(&msg, sizeof (msg)); 769*fcf3ce44SJohn Forte msg.msg_iov = iov; 770*fcf3ce44SJohn Forte msg.msg_flags = MSG_WAITALL; 771*fcf3ce44SJohn Forte msg.msg_iovlen = iovlen; 772*fcf3ce44SJohn Forte 773*fcf3ce44SJohn Forte recv_len = iscsi_net->recvmsg(socket, &msg, timeout); 774*fcf3ce44SJohn Forte if (recv_len != total_len) { 775*fcf3ce44SJohn Forte return (ISCSI_STATUS_TCP_RX_ERROR); 776*fcf3ce44SJohn Forte } 777*fcf3ce44SJohn Forte 778*fcf3ce44SJohn Forte DTRACE_PROBE4(rx_adhdr_digest, void *, socket, 779*fcf3ce44SJohn Forte iovec_t *iop, &iov[0], int, iovlen, int, total_len); 780*fcf3ce44SJohn Forte 781*fcf3ce44SJohn Forte /* 782*fcf3ce44SJohn Forte * Verify header digest if enabled and connection 783*fcf3ce44SJohn Forte * is in full feature mode 784*fcf3ce44SJohn Forte */ 785*fcf3ce44SJohn Forte if ((flags & ISCSI_NET_HEADER_DIGEST) != 0) { 786*fcf3ce44SJohn Forte crc_calculated = iscsi_crc32c((uchar_t *)ihp, 787*fcf3ce44SJohn Forte sizeof (iscsi_hdr_t) + ihp->hlength * 4); 788*fcf3ce44SJohn Forte 789*fcf3ce44SJohn Forte /* 790*fcf3ce44SJohn Forte * Converting actual CRC read via ntohl is not 791*fcf3ce44SJohn Forte * necessary because iscsi_crc32c calculates the 792*fcf3ce44SJohn Forte * value as it expect to be read 793*fcf3ce44SJohn Forte */ 794*fcf3ce44SJohn Forte if (crc_calculated != crc_actual) { 795*fcf3ce44SJohn Forte /* Invalid Header Digest */ 796*fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%p) " 797*fcf3ce44SJohn Forte "protocol error - encountered a header " 798*fcf3ce44SJohn Forte "digest error expected:0x%08x " 799*fcf3ce44SJohn Forte "received:0x%08x", socket, 800*fcf3ce44SJohn Forte crc_calculated, crc_actual); 801*fcf3ce44SJohn Forte return (ISCSI_STATUS_HEADER_DIGEST_ERROR); 802*fcf3ce44SJohn Forte } 803*fcf3ce44SJohn Forte } 804*fcf3ce44SJohn Forte } 805*fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS); 806*fcf3ce44SJohn Forte } 807*fcf3ce44SJohn Forte 808*fcf3ce44SJohn Forte 809*fcf3ce44SJohn Forte /* 810*fcf3ce44SJohn Forte * iscsi_net_recvdata - receive iscsi data payload from socket 811*fcf3ce44SJohn Forte */ 812*fcf3ce44SJohn Forte static iscsi_status_t 813*fcf3ce44SJohn Forte iscsi_net_recvdata(void *socket, iscsi_hdr_t *ihp, char *data, 814*fcf3ce44SJohn Forte int max_data_length, int timeout, int flags) 815*fcf3ce44SJohn Forte { 816*fcf3ce44SJohn Forte struct iovec iov[3]; 817*fcf3ce44SJohn Forte int iovlen = 1; 818*fcf3ce44SJohn Forte int total_len = 0; 819*fcf3ce44SJohn Forte int dlength = 0; 820*fcf3ce44SJohn Forte int pad_len = 0; 821*fcf3ce44SJohn Forte uint8_t pad[ISCSI_PAD_WORD_LEN]; 822*fcf3ce44SJohn Forte uint32_t crc_calculated = 0; 823*fcf3ce44SJohn Forte uint32_t crc_actual = 0; 824*fcf3ce44SJohn Forte struct msghdr msg; 825*fcf3ce44SJohn Forte size_t recv_len; 826*fcf3ce44SJohn Forte 827*fcf3ce44SJohn Forte ASSERT(socket != NULL); 828*fcf3ce44SJohn Forte ASSERT(ihp != NULL); 829*fcf3ce44SJohn Forte ASSERT(data != NULL); 830*fcf3ce44SJohn Forte 831*fcf3ce44SJohn Forte /* short hand dlength */ 832*fcf3ce44SJohn Forte dlength = ntoh24(ihp->dlength); 833*fcf3ce44SJohn Forte 834*fcf3ce44SJohn Forte /* verify dlength is valid */ 835*fcf3ce44SJohn Forte if (dlength > max_data_length) { 836*fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%p) protocol error - " 837*fcf3ce44SJohn Forte "invalid data lengths itt:0x%x received:0x%x " 838*fcf3ce44SJohn Forte "max expected:0x%x", socket, ihp->itt, 839*fcf3ce44SJohn Forte dlength, max_data_length); 840*fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR); 841*fcf3ce44SJohn Forte } 842*fcf3ce44SJohn Forte 843*fcf3ce44SJohn Forte if (dlength) { 844*fcf3ce44SJohn Forte 845*fcf3ce44SJohn Forte /* calculate pad */ 846*fcf3ce44SJohn Forte pad_len = ((ISCSI_PAD_WORD_LEN - 847*fcf3ce44SJohn Forte (dlength & (ISCSI_PAD_WORD_LEN - 1))) & 848*fcf3ce44SJohn Forte (ISCSI_PAD_WORD_LEN - 1)); 849*fcf3ce44SJohn Forte 850*fcf3ce44SJohn Forte /* setup data iovec */ 851*fcf3ce44SJohn Forte iov[0].iov_base = (char *)data; 852*fcf3ce44SJohn Forte iov[0].iov_len = dlength; 853*fcf3ce44SJohn Forte total_len = dlength; 854*fcf3ce44SJohn Forte 855*fcf3ce44SJohn Forte /* if pad setup pad iovec */ 856*fcf3ce44SJohn Forte if (pad_len) { 857*fcf3ce44SJohn Forte iov[iovlen].iov_base = (char *)&pad; 858*fcf3ce44SJohn Forte iov[iovlen].iov_len = pad_len; 859*fcf3ce44SJohn Forte total_len += pad_len; 860*fcf3ce44SJohn Forte iovlen++; 861*fcf3ce44SJohn Forte } 862*fcf3ce44SJohn Forte 863*fcf3ce44SJohn Forte /* setup data digest */ 864*fcf3ce44SJohn Forte if ((flags & ISCSI_NET_DATA_DIGEST) != 0) { 865*fcf3ce44SJohn Forte iov[iovlen].iov_base = (char *)&crc_actual; 866*fcf3ce44SJohn Forte iov[iovlen].iov_len = sizeof (crc_actual); 867*fcf3ce44SJohn Forte total_len += sizeof (crc_actual); 868*fcf3ce44SJohn Forte iovlen++; 869*fcf3ce44SJohn Forte } 870*fcf3ce44SJohn Forte 871*fcf3ce44SJohn Forte bzero(&msg, sizeof (msg)); 872*fcf3ce44SJohn Forte msg.msg_iov = iov; 873*fcf3ce44SJohn Forte msg.msg_flags = MSG_WAITALL; 874*fcf3ce44SJohn Forte msg.msg_iovlen = iovlen; 875*fcf3ce44SJohn Forte 876*fcf3ce44SJohn Forte recv_len = iscsi_net->recvmsg(socket, &msg, timeout); 877*fcf3ce44SJohn Forte if (recv_len != total_len) { 878*fcf3ce44SJohn Forte return (ISCSI_STATUS_TCP_RX_ERROR); 879*fcf3ce44SJohn Forte } 880*fcf3ce44SJohn Forte 881*fcf3ce44SJohn Forte DTRACE_PROBE4(rx_data, void *, socket, iovec_t *iop, 882*fcf3ce44SJohn Forte &iov[0], int, iovlen, int, total_len); 883*fcf3ce44SJohn Forte 884*fcf3ce44SJohn Forte /* verify data digest is present */ 885*fcf3ce44SJohn Forte if ((flags & ISCSI_NET_DATA_DIGEST) != 0) { 886*fcf3ce44SJohn Forte 887*fcf3ce44SJohn Forte crc_calculated = iscsi_crc32c(data, dlength); 888*fcf3ce44SJohn Forte crc_calculated = iscsi_crc32c_continued( 889*fcf3ce44SJohn Forte (char *)&pad, pad_len, crc_calculated); 890*fcf3ce44SJohn Forte 891*fcf3ce44SJohn Forte /* 892*fcf3ce44SJohn Forte * Converting actual CRC read via ntohl is not 893*fcf3ce44SJohn Forte * necessary because iscsi_crc32c calculates the 894*fcf3ce44SJohn Forte * value as it expects to be read 895*fcf3ce44SJohn Forte */ 896*fcf3ce44SJohn Forte if (crc_calculated != crc_actual) { 897*fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%p) " 898*fcf3ce44SJohn Forte "protocol error - encountered a data " 899*fcf3ce44SJohn Forte "digest error itt:0x%x expected:0x%08x " 900*fcf3ce44SJohn Forte "received:0x%08x", socket, 901*fcf3ce44SJohn Forte ihp->itt, crc_calculated, crc_actual); 902*fcf3ce44SJohn Forte return (ISCSI_STATUS_DATA_DIGEST_ERROR); 903*fcf3ce44SJohn Forte } 904*fcf3ce44SJohn Forte } 905*fcf3ce44SJohn Forte } 906*fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS); 907*fcf3ce44SJohn Forte } 908