iscsid_main.c revision 1.7 1 /* $NetBSD: iscsid_main.c,v 1.7 2012/05/28 00:13:19 riz 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 DEBOUT(("No Return Address!\n"));
625 continue;
626 }
627 /* process the request */
628 process_message(req, &rsp, &rsp_temp);
629 if (rsp == NULL)
630 break;
631
632 DEB(98, ("Sending reply: status %d, len %d\n",
633 rsp->status, rsp->parameter_length));
634
635 /* send the response */
636 len = sizeof(iscsid_response_t) + rsp->parameter_length;
637 ret = sendto(client_sock, rsp, len, 0,
638 (struct sockaddr *)(void *)&from, fromlen);
639 if (len != (size_t)ret) {
640 DEBOUT(("Error sending reply!\n"));
641 }
642 /* free temp buffers if we needed them */
643 if (req_temp)
644 free(req);
645 if (rsp_temp)
646 free(rsp);
647 }
648
649 exit_daemon();
650
651 /* we never get here */
652 return 0;
653 }
654