1 /* $NetBSD: iscsid_main.c,v 1.9 2015/05/30 16:00:51 joerg Exp $ */ 2 3 /*- 4 * Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Wasabi Systems, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include "iscsid_globals.h" 33 34 #include <sys/types.h> 35 #include <sys/socket.h> 36 #include <sys/un.h> 37 #include <sys/sysctl.h> 38 39 #include <ctype.h> 40 #include <err.h> 41 #include <fcntl.h> 42 43 #define DEVICE "/dev/iscsi0" 44 45 /* -------------------------------------------------------------------------- */ 46 47 list_head_t list[NUM_DAEMON_LISTS]; /* the lists this daemon keeps */ 48 49 pthread_mutex_t sesslist_lock; /* session list lock */ 50 pthread_t event_thread; /* event thread handle */ 51 52 int driver = -1; /* the driver's file desc */ 53 int client_sock; /* the client communication socket */ 54 55 int debug_level; /* How much info to display */ 56 int nothreads; 57 58 /* 59 To avoid memory fragmentation (and speed things up a bit), we use the 60 static bufs unless the request or response exceeds the buffer size 61 (which it normally shouldn't, assuming we don't have thousands 62 of list entries). 63 */ 64 static uint8_t req_buf[REQ_BUFFER_SIZE]; /* default buffer for requests */ 65 static uint8_t rsp_buf[RSP_BUFFER_SIZE]; /* default buffer for responses */ 66 67 /* -------------------------------------------------------------------------- */ 68 69 static void __dead 70 usage(void) 71 { 72 fprintf(stderr, "Usage: %s [-d <lvl>] [-n]\n", getprogname()); 73 exit(EXIT_FAILURE); 74 } 75 76 77 /* 78 * create_node_name: 79 * Create and set default node name. 80 * 81 * Returns 0 on success, else an error code. 82 */ 83 84 static int 85 create_node_name(void) 86 { 87 iscsi_set_node_name_parameters_t snp; 88 uint32_t hid = 0; 89 size_t siz; 90 int mib[2]; 91 unsigned char *s; 92 93 (void) memset(&snp, 0x0, sizeof(snp)); 94 mib[0] = CTL_KERN; 95 mib[1] = KERN_HOSTID; 96 siz = sizeof(hid); 97 sysctl(mib, 2, &hid, &siz, NULL, 0); 98 mib[1] = KERN_HOSTNAME; 99 siz = ISCSI_STRING_LENGTH - 45; 100 sysctl(mib, 2, snp.InitiatorAlias, &siz, NULL, 0); 101 102 DEB(1, ("Host Name: <%s>, Host ID: %u\n", snp.InitiatorAlias, hid)); 103 if (!snp.InitiatorAlias[0]) { 104 printf("Warning: iSCSI Node Name not set (No Host Name)!\n"); 105 return ISCSID_STATUS_NO_INITIATOR_NAME; 106 } 107 for (s = snp.InitiatorAlias; *s; s++) 108 if (!isalnum((unsigned char) *s) && *s != '-' && *s != '.' && *s != ':') 109 *s = '-'; 110 snprintf((char *)snp.InitiatorName, sizeof(snp.InitiatorName), 111 "iqn.1994-04.org.netbsd:iscsi.%s:%u", snp.InitiatorAlias, hid); 112 113 ioctl(driver, ISCSI_SET_NODE_NAME, &snp); 114 return snp.status; 115 } 116 117 118 /* 119 * init_daemon: 120 * Open driver, create communication socket. 121 * 122 * Returns: <0 on error 123 */ 124 125 static int 126 init_daemon(void) 127 { 128 int sock, i; 129 struct sockaddr_un name; 130 iscsid_request_t req; 131 132 if ((driver = open(DEVICE, O_RDONLY)) < 0) { 133 perror("opening " DEVICE); 134 return -1; 135 } 136 137 sock = socket(AF_UNIX, SOCK_DGRAM, 0); 138 if (sock < 0) { 139 perror("opening datagram socket"); 140 return -1; 141 } 142 143 name.sun_family = AF_UNIX; 144 strlcpy(name.sun_path, ISCSID_SOCK_NAME, sizeof(name.sun_path)); 145 146 req.request = ISCSID_DAEMON_TEST; 147 req.parameter_length = 0; 148 149 i = sendto(sock, &req, sizeof(req), 0, (struct sockaddr *)(void *)&name, 150 (socklen_t)sizeof(struct sockaddr_un)); 151 if (i == sizeof(req)) { 152 printf("Daemon already loaded!\n"); 153 close(sock); 154 return -1; 155 } 156 157 unlink(ISCSID_SOCK_NAME); 158 if (bind(sock, (struct sockaddr *)(void *)&name, (socklen_t)sizeof(struct sockaddr_un))) { 159 perror("binding name to socket"); 160 return -1; 161 } 162 163 for (i = 0; i < NUM_DAEMON_LISTS; i++) { 164 TAILQ_INIT(&list[i].list); 165 list[i].num_entries = 0; 166 } 167 168 if (!nothreads && (i = pthread_mutex_init(&sesslist_lock, NULL)) != 0) { 169 printf("Mutex init failed (%d)\n", i); 170 close(sock); 171 return -1; 172 } 173 174 if (!register_event_handler()) { 175 printf("Couldn't register event handler\n"); 176 close(sock); 177 unlink(ISCSID_SOCK_NAME); 178 if (!nothreads) 179 pthread_mutex_destroy(&sesslist_lock); 180 return -1; 181 } 182 183 create_node_name(); 184 185 return sock; 186 } 187 188 189 /* 190 * make_rsp: 191 * Allocate a response buffer if the static buffer is insufficient, set 192 * the response parameter length. 193 * 194 * Parameter: 195 * len Response parameter size (not counting header) 196 * prsp Pointer to address of response buffer 197 * prsp_temp Will be set to TRUE if buffer was allocated, FALSE 198 * for static buffer. 199 * 200 * Returns: Pointer to response buffer, NULL if allocation failed. 201 */ 202 203 iscsid_response_t * 204 make_rsp(size_t len, iscsid_response_t ** prsp, int *prsp_temp) 205 { 206 iscsid_response_t *rsp; 207 208 if ((len + sizeof(iscsid_response_t)) > RSP_BUFFER_SIZE) { 209 if ((rsp = calloc(1, len)) == NULL) { 210 (*prsp)->status = ISCSID_STATUS_NO_RESOURCES; 211 return NULL; 212 } 213 *prsp_temp = TRUE; 214 *prsp = rsp; 215 } else 216 rsp = *prsp; 217 218 memset (rsp, 0, len + sizeof(iscsid_response_t)); 219 rsp->parameter_length = (uint32_t)len; 220 return rsp; 221 } 222 223 224 /* 225 * process_message: 226 * minimal parameter check and dispatch for the daemon functions. 227 * 228 * Parameter: 229 * req The request 230 * prsp Pointer to address of response buffer 231 * prsp_temp Will be set to TRUE if buffer was allocated, FALSE 232 * for static buffer. 233 */ 234 235 static void 236 process_message(iscsid_request_t *req, iscsid_response_t **prsp, int *prsp_temp) 237 { 238 iscsid_response_t *rsp; 239 void *p = req->parameter; 240 241 *prsp_temp = FALSE; 242 *prsp = rsp = (iscsid_response_t *)(void *)rsp_buf; 243 rsp->parameter_length = 0; 244 rsp->status = ISCSID_STATUS_SUCCESS; 245 246 switch (req->request) { 247 case ISCSID_ADD_TARGET: 248 if (req->parameter_length < sizeof(iscsid_add_target_req_t)) { 249 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 250 break; 251 } 252 add_target((iscsid_add_target_req_t *)p, prsp, prsp_temp); 253 break; 254 255 case ISCSID_ADD_PORTAL: 256 if (req->parameter_length != sizeof(iscsid_add_portal_req_t)) { 257 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 258 break; 259 } 260 add_portal((iscsid_add_portal_req_t *)p, prsp, prsp_temp); 261 break; 262 263 case ISCSID_SET_TARGET_OPTIONS: 264 if (req->parameter_length != sizeof(iscsid_get_set_target_options_t)) { 265 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 266 break; 267 } 268 rsp->status = set_target_options((iscsid_get_set_target_options_t *)p); 269 break; 270 271 case ISCSID_GET_TARGET_OPTIONS: 272 if (req->parameter_length != sizeof(iscsid_sym_id_t)) { 273 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 274 break; 275 } 276 rsp->status = ISCSID_STATUS_NOTIMPL; 277 break; 278 279 case ISCSID_SET_TARGET_AUTHENTICATION: 280 if (req->parameter_length != 281 sizeof(iscsid_set_target_authentication_req_t)) { 282 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 283 break; 284 } 285 rsp->status = set_target_auth((iscsid_set_target_authentication_req_t *)p); 286 break; 287 288 case ISCSID_SLP_FIND_TARGETS: 289 rsp->status = ISCSID_STATUS_NOTIMPL; 290 break; 291 292 case ISCSID_REFRESH_TARGETS: 293 if (req->parameter_length < sizeof(iscsid_refresh_req_t)) { 294 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 295 break; 296 } 297 rsp->status = refresh_targets((iscsid_refresh_req_t *)p); 298 break; 299 300 case ISCSID_REMOVE_TARGET: 301 if (req->parameter_length != sizeof(iscsid_list_id_t)) { 302 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 303 break; 304 } 305 rsp->status = remove_target((iscsid_list_id_t *)p); 306 break; 307 308 case ISCSID_SEARCH_LIST: 309 if (req->parameter_length != sizeof(iscsid_search_list_req_t)) { 310 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 311 break; 312 } 313 search_list((iscsid_search_list_req_t *)p, prsp, prsp_temp); 314 break; 315 316 case ISCSID_GET_LIST: 317 if (req->parameter_length != sizeof(iscsid_get_list_req_t)) { 318 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 319 break; 320 } 321 get_list((iscsid_get_list_req_t *)p, prsp, prsp_temp); 322 break; 323 324 case ISCSID_GET_TARGET_INFO: 325 if (req->parameter_length != sizeof(iscsid_list_id_t)) { 326 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 327 break; 328 } 329 get_target_info((iscsid_list_id_t *)p, prsp, prsp_temp); 330 break; 331 332 case ISCSID_GET_PORTAL_INFO: 333 if (req->parameter_length != sizeof(iscsid_list_id_t)) { 334 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 335 break; 336 } 337 get_portal_info((iscsid_list_id_t *)p, prsp, prsp_temp); 338 break; 339 340 #ifndef ISCSI_MINIMAL 341 case ISCSID_ADD_ISNS_SERVER: 342 if (req->parameter_length != sizeof(iscsid_add_isns_server_req_t)) { 343 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 344 break; 345 } 346 add_isns_server((iscsid_add_isns_server_req_t *)p, 347 prsp, prsp_temp); 348 break; 349 350 case ISCSID_GET_ISNS_SERVER: 351 if (req->parameter_length != sizeof(iscsid_sym_id_t)) { 352 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 353 break; 354 } 355 get_isns_server((iscsid_sym_id_t *)p, prsp, prsp_temp); 356 break; 357 358 case ISCSID_SLP_FIND_ISNS_SERVERS: 359 rsp->status = ISCSID_STATUS_NOTIMPL; 360 break; 361 362 case ISCSID_REMOVE_ISNS_SERVER: 363 if (req->parameter_length != sizeof(iscsid_sym_id_t)) { 364 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 365 break; 366 } 367 rsp->status = remove_isns_server((iscsid_sym_id_t *)p); 368 break; 369 #endif 370 371 case ISCSID_ADD_INITIATOR_PORTAL: 372 if (req->parameter_length != sizeof(iscsid_add_initiator_req_t)) { 373 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 374 break; 375 } 376 add_initiator_portal((iscsid_add_initiator_req_t *)p, 377 prsp, prsp_temp); 378 break; 379 380 case ISCSID_GET_INITIATOR_PORTAL: 381 if (req->parameter_length != sizeof(iscsid_sym_id_t)) { 382 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 383 break; 384 } 385 get_initiator_portal((iscsid_sym_id_t *)p, prsp, prsp_temp); 386 break; 387 388 case ISCSID_REMOVE_INITIATOR_PORTAL: 389 if (req->parameter_length != sizeof(iscsid_sym_id_t)) { 390 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 391 break; 392 } 393 rsp->status = remove_initiator_portal((iscsid_sym_id_t *)p); 394 break; 395 396 case ISCSID_LOGIN: 397 if (req->parameter_length != sizeof(iscsid_login_req_t)) { 398 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 399 break; 400 } 401 login((iscsid_login_req_t *)p, rsp); 402 break; 403 404 case ISCSID_ADD_CONNECTION: 405 if (req->parameter_length != sizeof(iscsid_login_req_t)) { 406 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 407 break; 408 } 409 add_connection((iscsid_login_req_t *)p, rsp); 410 break; 411 412 case ISCSID_LOGOUT: 413 if (req->parameter_length != sizeof(iscsid_sym_id_t)) { 414 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 415 break; 416 } 417 rsp->status = logout((iscsid_sym_id_t *)p); 418 break; 419 420 case ISCSID_REMOVE_CONNECTION: 421 if (req->parameter_length != sizeof(iscsid_remove_connection_req_t)) { 422 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 423 break; 424 } 425 rsp->status = remove_connection((iscsid_remove_connection_req_t *)p); 426 break; 427 428 case ISCSID_GET_SESSION_LIST: 429 get_session_list(prsp, prsp_temp); 430 break; 431 432 case ISCSID_GET_CONNECTION_LIST: 433 if (req->parameter_length != sizeof(iscsid_sym_id_t)) { 434 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 435 break; 436 } 437 get_connection_list((iscsid_sym_id_t *)p, prsp, prsp_temp); 438 break; 439 440 case ISCSID_GET_CONNECTION_INFO: 441 if (req->parameter_length != sizeof(iscsid_get_connection_info_req_t)) { 442 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 443 break; 444 } 445 get_connection_info((iscsid_get_connection_info_req_t *)p, 446 prsp, prsp_temp); 447 break; 448 449 case ISCSID_SET_NODE_NAME: 450 if (req->parameter_length != sizeof(iscsid_set_node_name_req_t)) { 451 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 452 break; 453 } 454 rsp->status = set_node_name((iscsid_set_node_name_req_t *)p); 455 break; 456 457 case ISCSID_GET_VERSION: 458 get_version(prsp, prsp_temp); 459 break; 460 461 default: 462 rsp->status = ISCSID_STATUS_INVALID_REQUEST; 463 break; 464 } 465 } 466 467 468 /* 469 * exit_daemon: 470 * Deregister the event handler, deregister isns servers, then exit program. 471 */ 472 473 void 474 exit_daemon(void) 475 { 476 LOCK_SESSIONS; 477 deregister_event_handler(); 478 479 #ifndef ISCSI_MINIMAL 480 dereg_all_isns_servers(); 481 #endif 482 483 printf("iSCSI Daemon Exits\n"); 484 exit(0); 485 } 486 487 488 /* 489 * main: 490 * init, go daemon, then loop reading requests, processing them, 491 * and sending responses. 492 * Stops on receiving a terminate message (no response to that one is sent), 493 * or when an error occurs reading or writing the socket. 494 * 495 * Parameter: argc, argv currently ignored. 496 */ 497 498 int 499 /*ARGSUSED*/ 500 main(int argc, char **argv) 501 { 502 int req_temp, rsp_temp, c; 503 ssize_t ret; 504 size_t len; 505 struct sockaddr_un from; 506 socklen_t fromlen; 507 iscsid_request_t *req; 508 iscsid_response_t *rsp; 509 struct timeval seltout = { 2, 0 }; /* 2 second poll interval */ 510 char *p; 511 512 while ((c = getopt(argc, argv, "d:n")) != -1) 513 switch (c) { 514 case 'n': 515 nothreads++; 516 break; 517 case 'd': 518 debug_level=(int)strtol(optarg, &p, 10); 519 if (*p) 520 errx(EXIT_FAILURE, "illegal debug level -- %s", 521 optarg); 522 break; 523 default: 524 usage(); 525 } 526 527 client_sock = init_daemon(); 528 if (client_sock < 0) 529 exit(1); 530 531 printf("iSCSI Daemon loaded\n"); 532 533 if (!debug_level) 534 daemon(0, 1); 535 536 if (nothreads) 537 setsockopt(client_sock, SOL_SOCKET, SO_RCVTIMEO, &seltout, 538 sizeof(seltout)); 539 else { 540 ret = pthread_create(&event_thread, NULL, event_handler, NULL); 541 if (ret) { 542 printf("Thread creation failed (%zd)\n", ret); 543 close(client_sock); 544 unlink(ISCSID_SOCK_NAME); 545 deregister_event_handler(); 546 pthread_mutex_destroy(&sesslist_lock); 547 return -1; 548 } 549 } 550 551 /* ---------------------------------------------------------------------- */ 552 553 for (;;) { 554 /* First, get size of request */ 555 req = (iscsid_request_t *)(void *)req_buf; 556 fromlen = sizeof(from); 557 len = sizeof(iscsid_request_t); 558 559 if (nothreads) { 560 do { 561 ret = recvfrom(client_sock, req, len, MSG_PEEK | 562 MSG_WAITALL, (struct sockaddr *)(void *)&from, 563 &fromlen); 564 if (ret == -1) 565 event_handler(NULL); 566 } while (ret == -1 && errno == EAGAIN); 567 } else { 568 do { 569 ret = recvfrom(client_sock, req, len, MSG_PEEK | 570 MSG_WAITALL, (struct sockaddr *) &from, 571 &fromlen); 572 if (ret == -1) 573 event_handler(NULL); 574 } while (ret == -1 && errno == EAGAIN); 575 } 576 577 if ((size_t)ret != len) { 578 perror("Receiving from socket"); 579 break; 580 } 581 DEB(98, ("Request %d, parlen %d\n", 582 req->request, req->parameter_length)); 583 584 len += req->parameter_length; 585 586 /* now that we know the size, get the buffer for it */ 587 req_temp = (len > REQ_BUFFER_SIZE); 588 589 if (req_temp) { 590 req = malloc(len); 591 if (!req) { 592 printf("Can't alloc %zu bytes\n", len); 593 break; 594 } 595 } 596 /* read the complete request */ 597 fromlen = sizeof(from); 598 ret = recvfrom(client_sock, req, len, MSG_WAITALL, 599 (struct sockaddr *)(void *)&from, &fromlen); 600 if ((size_t)ret != len) { 601 DEBOUT(("Error receiving from socket!\n")); 602 if (req_temp) 603 free(req); 604 continue; 605 } 606 /* terminate? then go die. */ 607 if (req->request == ISCSID_DAEMON_TERMINATE) 608 break; 609 610 /* No reply required to test message */ 611 if (req->request == ISCSID_DAEMON_TEST) { 612 if (req_temp) 613 free(req); 614 continue; 615 } 616 /* no return path? then we can't send a reply, */ 617 /* so don't process the command */ 618 if (!from.sun_path[0]) { 619 if (req_temp) 620 free(req); 621 DEBOUT(("No Return Address!\n")); 622 continue; 623 } 624 /* process the request */ 625 process_message(req, &rsp, &rsp_temp); 626 if (rsp == NULL) { 627 if (req_temp) 628 free(req); 629 DEBOUT(("Invalid message!\n")); 630 continue; 631 } 632 633 DEB(98, ("Sending reply: status %d, len %d\n", 634 rsp->status, rsp->parameter_length)); 635 636 /* send the response */ 637 len = sizeof(iscsid_response_t) + rsp->parameter_length; 638 ret = sendto(client_sock, rsp, len, 0, 639 (struct sockaddr *)(void *)&from, fromlen); 640 if (len != (size_t)ret) { 641 DEBOUT(("Error sending reply!\n")); 642 } 643 /* free temp buffers if we needed them */ 644 if (req_temp) 645 free(req); 646 if (rsp_temp) 647 free(rsp); 648 } 649 650 exit_daemon(); 651 652 /* we never get here */ 653 return 0; 654 } 655