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