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