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