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 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/socket.h> 31 #include <netinet/in.h> 32 #include <arpa/inet.h> 33 #include <stdio.h> 34 #include <unistd.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <strings.h> 38 #include <syslog.h> 39 #include <ctype.h> 40 #include <pthread.h> 41 #include <netdb.h> 42 #include <libintl.h> 43 #include <errno.h> 44 #include <assert.h> 45 #include <fcntl.h> 46 #include <sys/byteorder.h> 47 48 #include "isns_protocol.h" 49 #include "isns_client.h" 50 #include "queue.h" 51 52 extern target_queue_t *mgmtq; 53 54 static uint16_t xid = 0; 55 static pthread_mutex_t xid_lock = PTHREAD_MUTEX_INITIALIZER; 56 57 /* 58 * more than 1 processes can accessing get_xid 59 */ 60 static uint16_t 61 get_xid() 62 { 63 uint16_t tmp; 64 65 (void) pthread_mutex_lock(&xid_lock); 66 tmp = xid++; 67 (void) pthread_mutex_unlock(&xid_lock); 68 return (tmp); 69 } 70 71 void 72 ntoh_tlv(isns_tlv_t *tlv) 73 { 74 uint32_t val; 75 76 tlv->attr_id = ntohl(tlv->attr_id); 77 tlv->attr_len = ntohl(tlv->attr_len); 78 79 switch (tlv->attr_id) { 80 case ISNS_DELIMITER_ATTR_ID: 81 break; 82 case ISNS_ISCSI_NAME_ATTR_ID: 83 case ISNS_EID_ATTR_ID: 84 case ISNS_ISCSI_ALIAS_ATTR_ID: 85 case ISNS_PORTAL_NAME_ATTR_ID: 86 case ISNS_PG_ISCSI_NAME_ATTR_ID: 87 break; 88 89 case ISNS_PORTAL_IP_ADDR_ATTR_ID: 90 case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID: 91 bcopy(tlv->attr_value, &val, 4); 92 *tlv->attr_value = ntohl(val); 93 break; 94 95 default: 96 switch (tlv->attr_len) { 97 case 4: 98 val = ntohl( 99 (uint32_t)(*tlv->attr_value)); 100 bcopy(&val, tlv->attr_value, 4); 101 break; 102 default: 103 break; 104 } 105 break; 106 } 107 } 108 109 /* 110 * print_ntoh_tlv print network byte order tag-length-value attribute 111 */ 112 void 113 print_ntoh_tlv(isns_tlv_t *tlv) 114 { 115 uint32_t tag, len, val, pf_type; 116 char buf[256]; 117 struct sockaddr_in6 sin6; 118 119 tag = ntohl(tlv->attr_id); 120 len = ntohl(tlv->attr_len); 121 122 if (len == 0) { 123 queue_prt(mgmtq, Q_ISNS_DBG, "Zero length tag: %d\n", tag); 124 return; 125 } 126 127 switch (tag) { 128 case ISNS_DELIMITER_ATTR_ID: 129 break; 130 case ISNS_ISCSI_NAME_ATTR_ID: 131 case ISNS_EID_ATTR_ID: 132 case ISNS_ISCSI_ALIAS_ATTR_ID: 133 case ISNS_PORTAL_NAME_ATTR_ID: 134 case ISNS_PG_ISCSI_NAME_ATTR_ID: 135 queue_prt(mgmtq, Q_ISNS_DBG, 136 "Tag %d: Value: %s\n", tag, tlv->attr_value); 137 break; 138 139 case ISNS_PORTAL_IP_ADDR_ATTR_ID: 140 case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID: 141 bcopy(tlv->attr_value, &pf_type, 4); 142 pf_type = ntohl(pf_type); 143 pf_type = (pf_type == sizeof (in6_addr_t)) 144 ? PF_INET6 : PF_INET; 145 switch (pf_type) { 146 case PF_INET: 147 /* RFC2372 IPv4 mapped IPv6 address */ 148 if (inet_ntop(pf_type, 149 (void *)&tlv->attr_value[12], 150 buf, 256) == NULL) { 151 syslog(LOG_ERR, 152 "inet_ntop failed"); 153 break; 154 } 155 queue_prt(mgmtq, Q_ISNS_DBG, 156 "IP_ADDR %s\n", buf); 157 break; 158 case PF_INET6: 159 bcopy(tlv->attr_value, &sin6, 160 sizeof (struct sockaddr_in6)); 161 (void) inet_ntop(pf_type, 162 (void *)&sin6.sin6_addr, 163 buf, 256); 164 break; 165 default: 166 queue_prt(mgmtq, Q_ISNS_DBG, 167 "unknown pf_type\n"); 168 break; 169 } 170 break; 171 172 default: 173 switch (len) { 174 case 4: 175 bcopy(tlv->attr_value, &val, 4); 176 val = ntohl(val); 177 queue_prt(mgmtq, Q_ISNS_DBG, 178 "Tag: %d Value: %ld\n", tag, val); 179 break; 180 default: 181 break; 182 } 183 break; 184 } 185 } 186 187 void 188 print_attr(isns_tlv_t *attr, void *pval, uint32_t ival) 189 { 190 uint32_t tag = ntohl(attr->attr_id); 191 uint32_t len = ntohl(attr->attr_len); 192 uint32_t pf_type; 193 char buf[256]; 194 195 queue_prt(mgmtq, Q_ISNS_DBG, "Tag: %d Length: %d\n", tag, len); 196 switch (tag) { 197 case ISNS_DELIMITER_ATTR_ID: 198 break; 199 200 case ISNS_ISCSI_NAME_ATTR_ID: 201 case ISNS_EID_ATTR_ID: 202 case ISNS_ISCSI_ALIAS_ATTR_ID: 203 case ISNS_PORTAL_NAME_ATTR_ID: 204 case ISNS_PG_ISCSI_NAME_ATTR_ID: 205 if (len && pval != NULL) { 206 queue_prt(mgmtq, Q_ISNS_DBG, "Value: %s\n", 207 attr->attr_value); 208 } 209 break; 210 211 case ISNS_PORTAL_IP_ADDR_ATTR_ID: 212 case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID: 213 if (len) { 214 pf_type = (ival == sizeof (in6_addr_t)) 215 ? PF_INET6 : PF_INET; 216 (void) inet_ntop(pf_type, pval, buf, 256); 217 queue_prt(mgmtq, Q_ISNS_DBG, "IP_ADDR %s\n", 218 buf); 219 } 220 break; 221 222 default: 223 switch (len) { 224 case 4: 225 queue_prt(mgmtq, Q_ISNS_DBG, 226 "Value: %d\n", 227 ntohl(*attr->attr_value)); 228 break; 229 default: 230 break; 231 } 232 break; 233 } 234 } 235 236 void 237 print_isns_hdr(isns_hdr_t *hdr) 238 { 239 queue_prt(mgmtq, Q_ISNS_DBG, "hdr->version %d\n", hdr->version); 240 queue_prt(mgmtq, Q_ISNS_DBG, "hdr->func_id %x\n", hdr->func_id); 241 queue_prt(mgmtq, Q_ISNS_DBG, "hdr->pdu_len %d\n", hdr->pdu_len); 242 queue_prt(mgmtq, Q_ISNS_DBG, "hdr->flags %x\n", hdr->flags); 243 queue_prt(mgmtq, Q_ISNS_DBG, "hdr->xid %d\n", hdr->xid); 244 queue_prt(mgmtq, Q_ISNS_DBG, "hdr->seqid %d\n", hdr->seqid); 245 } 246 247 void 248 ntoh_isns_hdr(isns_hdr_t *hdr) 249 { 250 hdr->version = ntohs(hdr->version); 251 hdr->func_id = ntohs(hdr->func_id); 252 hdr->pdu_len = ntohs(hdr->pdu_len); 253 hdr->flags = ntohs(hdr->flags); 254 hdr->xid = ntohs(hdr->xid); 255 hdr->seqid = ntohs(hdr->seqid); 256 } 257 258 int 259 isns_append_attr(isns_pdu_t *pdu, uint32_t tag, uint32_t len, 260 void *pval, uint32_t ival) 261 { 262 uint32_t val; 263 uint32_t pad_len; 264 uint16_t pdu_len; 265 isns_tlv_t *attr; 266 char *tlv; 267 268 if (pdu == NULL) { 269 syslog(LOG_ALERT, "NULL PDU\n"); 270 return (-1); 271 } 272 273 /* get current pdu payload length */ 274 pdu_len = ntohs(pdu->payload_len); 275 276 /* pad 4 bytes alignment */ 277 pad_len = PAD4(len); 278 279 if ((pdu_len + pad_len) > MAX_PDU_PAYLOAD_SZ) { 280 syslog(LOG_ALERT, "Exceeded PDU size\n"); 281 return (-1); 282 } 283 284 if ((attr = (isns_tlv_t *)malloc(ISNS_ATTR_SZ(pad_len))) == NULL) { 285 syslog(LOG_ALERT, "Malloc error"); 286 return (-1); 287 } 288 bzero(attr, ISNS_ATTR_SZ(pad_len)); 289 attr->attr_id = htonl(tag); 290 attr->attr_len = htonl(pad_len); 291 292 switch (tag) { 293 case ISNS_DELIMITER_ATTR_ID: 294 break; 295 296 case ISNS_ISCSI_NAME_ATTR_ID: 297 case ISNS_EID_ATTR_ID: 298 case ISNS_ISCSI_ALIAS_ATTR_ID: 299 case ISNS_PORTAL_NAME_ATTR_ID: 300 case ISNS_PG_ISCSI_NAME_ATTR_ID: 301 if (len && pval != NULL) { 302 bcopy(pval, attr->attr_value, len); 303 } 304 break; 305 306 case ISNS_PORTAL_IP_ADDR_ATTR_ID: 307 case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID: 308 if (len && ival == sizeof (in_addr_t)) { 309 /* IPv4 */ 310 attr->attr_value[10] = 0xFF; 311 attr->attr_value[11] = 0xFF; 312 bcopy(pval, ((attr->attr_value) + 12), ival); 313 } else if (len && ival == sizeof (in6_addr_t)) { 314 /* IPv6 */ 315 bcopy(pval, attr->attr_value, ival); 316 } 317 break; 318 319 default: 320 switch (len) { 321 case 4: 322 val = htonl(ival); 323 bcopy(&val, attr->attr_value, 4); 324 break; 325 default: 326 break; 327 } 328 break; 329 } 330 331 /* copy attribute to pdu */ 332 tlv = (char *)pdu + ISNSP_HEADER_SIZE + pdu_len; 333 bcopy(attr, tlv, ISNS_ATTR_SZ(pad_len)); 334 pdu->payload_len = htons(pdu_len + ISNS_ATTR_SZ(pad_len)); 335 336 /* debug only */ 337 print_ntoh_tlv(attr); 338 339 free(attr); 340 return (0); 341 } 342 343 int 344 isns_create_pdu(uint16_t func_id, uint32_t flags, isns_pdu_t **pdu) 345 { 346 size_t pdu_sz = MAX_PDU_SZ; 347 348 if ((*pdu = (isns_pdu_t *)malloc(pdu_sz)) == NULL) { 349 syslog(LOG_ERR, "isns_create_pdu malloc failure"); 350 return (-1); 351 } 352 353 bzero(*pdu, pdu_sz); 354 (*pdu)->payload_len = 0; 355 (*pdu)->seq = 0; 356 (*pdu)->xid = htons(get_xid()); 357 (*pdu)->version = htons((uint16_t)ISNSP_VERSION); 358 (*pdu)->func_id = htons((uint16_t)(func_id)); 359 (*pdu)->flags = htons((uint16_t)(flags | ISNS_FLAG_CLIENT | 360 ISNS_FLAG_FIRST_PDU | ISNS_FLAG_LAST_PDU)); 361 return (0); 362 } 363 364 void 365 isns_free_pdu(void *pdu) 366 { 367 free(pdu); 368 } 369 370 /* 371 * Desc: Open connection to the isns server 372 * Args: isns server name or isns server ip-addr 373 * Return: -1 if open failed, descriptor to socket if open succeeded 374 */ 375 int 376 isns_open(char *server) 377 { 378 struct addrinfo hints, *ai, *aip; 379 struct sockaddr *sa; 380 struct sockaddr_in sin; 381 struct sockaddr_in6 sin6; 382 size_t sa_len; 383 int so; 384 int ret; 385 fd_set rfdset; 386 fd_set wfdset; 387 fd_set errfdset; 388 struct timeval timeout; 389 Boolean_t shouldsockblock = False; 390 int socket_ready = 0; 391 timeout.tv_sec = 5; /* 5 Secs Timeout */ 392 timeout.tv_usec = 0; /* 0 uSecs Timeout */ 393 394 if (server == NULL) { 395 syslog(LOG_ERR, "ISNS server ID required"); 396 return (-1); 397 } 398 399 bzero(&hints, sizeof (struct addrinfo)); 400 hints.ai_family = AF_UNSPEC; 401 if ((ret = getaddrinfo(server, NULL, NULL, &ai)) != 0) { 402 syslog(LOG_ALERT, "getaddrinfo failed on server %s: %s", server, 403 gai_strerror(ret)); 404 return (-1); 405 } 406 407 aip = ai; 408 do { 409 so = socket(aip->ai_family, SOCK_STREAM, 0); 410 if (so != -1) { 411 412 /* set it to non blocking so connect wont hang */ 413 if (setsocknonblocking(so) == -1) { 414 (void) close(so); 415 continue; 416 } 417 418 sa_len = aip->ai_addrlen; 419 switch (aip->ai_family) { 420 case PF_INET: 421 bzero(&sin, 422 sizeof (struct sockaddr_in)); 423 sa = (struct sockaddr *)&sin; 424 bcopy(aip->ai_addr, sa, sa_len); 425 sin.sin_port = htons( 426 ISNS_DEFAULT_SERVER_PORT); 427 break; 428 case PF_INET6: 429 bzero(&sin6, 430 sizeof (struct sockaddr_in6)); 431 sa = (struct sockaddr *)&sin6; 432 bcopy(aip->ai_addr, sa, sa_len); 433 sin6.sin6_port = 434 htons(ISNS_DEFAULT_SERVER_PORT); 435 break; 436 default: 437 syslog(LOG_ALERT, "Bad protocol"); 438 (void) close(so); 439 continue; 440 } 441 442 ret = connect(so, sa, sa_len); 443 if (ret == 0) { 444 /* 445 * connection succeeded with out 446 * blocking 447 */ 448 shouldsockblock = True; 449 } 450 451 if (ret < 0) { 452 if (errno == EINPROGRESS) { 453 FD_ZERO(&rfdset); 454 FD_ZERO(&wfdset); 455 FD_ZERO(&errfdset); 456 FD_SET(so, &rfdset); 457 FD_SET(so, &wfdset); 458 FD_SET(so, &errfdset); 459 socket_ready = 460 select(so + 1, &rfdset, &wfdset, 461 &errfdset, &timeout); 462 if (socket_ready < 0) { 463 syslog(LOG_ALERT, 464 "failed to connect with" 465 " isns, err=%d", errno); 466 (void) close(so); 467 } else if (socket_ready == 0) { 468 syslog(LOG_ALERT, 469 "time out failed" 470 " to connect with isns"); 471 (void) close(so); 472 } else { /* Socket is ready */ 473 /* 474 * Check if socket is ready 475 */ 476 if (is_socket_ready(so, 477 &rfdset, &wfdset, 478 &errfdset) == True) 479 shouldsockblock = True; 480 else 481 (void) close(so); 482 } 483 } else { 484 syslog(LOG_WARNING, 485 "Connect failed no progress"); 486 (void) close(so); 487 } 488 } 489 490 if (shouldsockblock == True) { 491 if (-1 == setsockblocking(so)) { 492 (void) close(so); 493 shouldsockblock = False; 494 } else { 495 freeaddrinfo(ai); 496 return (so); 497 } 498 } 499 500 } 501 } while ((aip = aip->ai_next) != NULL); 502 503 if (ai != NULL) 504 freeaddrinfo(ai); 505 return (-1); 506 } 507 508 /* 509 * According to: 510 * UNIX Network Programming Volume 1, Third Edition: 511 * The Sockets Networking APIBOOK: 512 * 513 * When the connection completes successfully, the descriptor becomes 514 * writable (p. 531 of TCPv2). 515 * When the connection establishment encounters an error, the descriptor 516 * becomes both readable and writable (p. 530 of TCPv2). 517 */ 518 Boolean_t 519 is_socket_ready(int so, fd_set *rfdset, fd_set *wfdset, 520 fd_set *errfdset) 521 { 522 if ((FD_ISSET(so, wfdset) && 523 FD_ISSET(so, rfdset)) || 524 FD_ISSET(so, errfdset)) { 525 return (False); 526 } else { 527 return (True); 528 } 529 } 530 531 int 532 setsocknonblocking(int so) 533 { 534 int flags; 535 /* set it to non blocking */ 536 if (-1 == (flags = fcntl(so, F_GETFL, 0))) { 537 syslog(LOG_WARNING, 538 "Failed to get socket flags. Blocking.."); 539 return (-1); 540 } 541 542 if (fcntl(so, F_SETFL, flags | O_NONBLOCK) == -1) { 543 syslog(LOG_WARNING, 544 "Failed to set socket in non blocking mode"); 545 return (-1); 546 } 547 return (0); 548 } 549 550 int 551 setsockblocking(int so) 552 { 553 int flags; 554 /* set it to non blocking */ 555 if (-1 == (flags = fcntl(so, F_GETFL, 0))) { 556 syslog(LOG_WARNING, " Failed to get flags on socket.."); 557 return (-1); 558 } 559 560 flags &= ~O_NONBLOCK; 561 if (fcntl(so, F_SETFL, flags) == -1) { 562 syslog(LOG_WARNING, " failed to set socket to blocking"); 563 return (-1); 564 } 565 return (0); 566 } 567 568 569 void 570 isns_close(int so) 571 { 572 if (so) { 573 (void) close(so); 574 } 575 } 576 577 /* 578 * isns_send allocated pdu, caller needs to free pdu when done processing 579 */ 580 int 581 isns_send(int so, isns_pdu_t *pdu) 582 { 583 size_t len; 584 585 assert(pdu != NULL); 586 587 len = ISNSP_HEADER_SIZE + ntohs(pdu->payload_len); 588 if (send(so, pdu, len, 0) == -1) { 589 syslog(LOG_ALERT, "isns_send failure"); 590 return (-1); 591 } 592 return (0); 593 } 594 595 /* 596 * Desc: isns_recv malloc memory for the isns response message, user needs 597 * to isns_free() memory after process the response message. The 598 * isns header is converted to host byte order, the remaining TLV 599 * attributes can be converted using ntoh_tlv() 600 */ 601 int 602 isns_recv(int so, isns_rsp_t **pdu) 603 { 604 isns_hdr_t hdr, hdr1; 605 isns_rsp_t *rsp; 606 uint8_t *ptr; 607 size_t total_pdu_len; 608 int len; 609 uint16_t xid_x, func_id_x, seqid_x; 610 boolean_t done; 611 612 *pdu = NULL; 613 total_pdu_len = 0; 614 seqid_x = 0; 615 done = FALSE; 616 617 do { 618 /* read pdu header 1st */ 619 do { 620 len = recv(so, &hdr1, ISNSP_HEADER_SIZE, MSG_WAITALL); 621 } while ((len == -1) && (errno == EINTR)); 622 623 if (len != ISNSP_HEADER_SIZE) { 624 syslog(LOG_ALERT, "isns_recv fail to read header"); 625 return (-1); 626 } 627 628 /* normalize the pdu header for processing */ 629 bcopy(&hdr1, &hdr, sizeof (isns_hdr_t)); 630 ntoh_isns_hdr(&hdr); 631 632 if (IS_1ST_PDU(hdr.flags)) { 633 if (hdr.seqid != 0) { 634 syslog(LOG_ALERT, "ISNS out of sequence"); 635 return (-1); 636 } 637 xid_x = hdr.xid; 638 func_id_x = hdr.func_id; 639 } 640 641 if (IS_LAST_PDU(hdr.flags)) { 642 done = TRUE; 643 } 644 645 /* verify seq, xid, func_id */ 646 if (seqid_x != hdr.seqid) { 647 syslog(LOG_ALERT, "ISNS out of sequence"); 648 return (-1); 649 } 650 if (xid_x != hdr.xid || func_id_x != hdr.func_id) { 651 syslog(LOG_ALERT, "Non matching xid or func_id"); 652 return (-1); 653 } 654 655 ++seqid_x; /* next expected seqid */ 656 657 /* malloc size + previous payload length */ 658 if ((ptr = malloc(ISNSP_HEADER_SIZE + hdr.pdu_len 659 + total_pdu_len)) == NULL) { 660 syslog(LOG_ALERT, "Malloc failure"); 661 return (-1); 662 } 663 bzero(ptr, ISNSP_HEADER_SIZE + hdr.pdu_len); 664 665 if (hdr.seqid == 0) { 666 *pdu = (void *)ptr; 667 bcopy(&hdr1, ptr, ISNSP_HEADER_SIZE); 668 ptr += ISNSP_HEADER_SIZE; 669 if ((len = recv(so, ptr, hdr.pdu_len, MSG_WAITALL)) 670 != hdr.pdu_len) { 671 syslog(LOG_ERR, 672 "isns_recv fail to read 1st payload"); 673 free(*pdu); 674 *pdu = NULL; 675 return (-1); 676 } 677 } else { 678 /* merge the pdu */ 679 bcopy(*pdu, ptr, ISNSP_HEADER_SIZE + total_pdu_len); 680 free(*pdu); 681 *pdu = (void *)ptr; 682 ptr += (ISNSP_HEADER_SIZE + total_pdu_len); 683 if (recv(so, ptr, hdr.pdu_len, MSG_WAITALL) 684 != hdr.pdu_len) { 685 syslog(LOG_ERR, 686 "isns_recv fail to read payload"); 687 free(*pdu); 688 *pdu = NULL; 689 return (-1); 690 } 691 } 692 total_pdu_len += hdr.pdu_len; 693 694 } while (done == FALSE); 695 696 /* normalize the response status */ 697 rsp = (isns_rsp_t *)*pdu; 698 rsp->pdu_len = htons(total_pdu_len); 699 ntoh_isns_hdr((isns_hdr_t *)rsp); 700 701 return (0); 702 } 703