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