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