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