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