Home | History | Annotate | Line # | Download | only in iscsid
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