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