Home | History | Annotate | Line # | Download | only in iscsid
iscsid_main.c revision 1.4
      1 /*	$NetBSD: iscsid_main.c,v 1.4 2012/05/27 19:52:51 christos 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 #ifndef ISCSI_DEBUG
     57 #define ISCSI_DEBUG 0
     58 #endif
     59 int debug_level = ISCSI_DEBUG;	/* How much info to display */
     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]\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 #ifndef ISCSI_NOTHREAD
    174 	if ((i = pthread_mutex_init(&sesslist_lock, NULL)) != 0) {
    175 		printf("Mutex init failed (%d)\n", i);
    176 		close(sock);
    177 		return -1;
    178 	}
    179 #endif
    180 
    181 	if (!register_event_handler()) {
    182 		printf("Couldn't register event handler\n");
    183 		close(sock);
    184 		unlink(ISCSID_SOCK_NAME);
    185 #ifndef ISCSI_NOTHREAD
    186 		pthread_mutex_destroy(&sesslist_lock);
    187 #endif
    188 		return -1;
    189 	}
    190 
    191 	create_node_name();
    192 
    193 	return sock;
    194 }
    195 
    196 
    197 /*
    198  * make_rsp:
    199  *    Allocate a response buffer if the static buffer is insufficient, set
    200  *    the response parameter length.
    201  *
    202  *    Parameter:
    203  *          len         Response parameter size (not counting header)
    204  *          prsp        Pointer to address of response buffer
    205  *          prsp_temp   Will be set to TRUE if buffer was allocated, FALSE
    206  *                      for static buffer.
    207  *
    208  *    Returns:    Pointer to response buffer, NULL if allocation failed.
    209  */
    210 
    211 iscsid_response_t *
    212 make_rsp(size_t len, iscsid_response_t ** prsp, int *prsp_temp)
    213 {
    214 	iscsid_response_t *rsp;
    215 
    216 	if ((len + sizeof(iscsid_response_t)) > RSP_BUFFER_SIZE) {
    217 		if ((rsp = calloc(1, len)) == NULL) {
    218 			(*prsp)->status = ISCSID_STATUS_NO_RESOURCES;
    219 			return NULL;
    220 		}
    221 		*prsp_temp = TRUE;
    222 		*prsp = rsp;
    223 	} else
    224 		rsp = *prsp;
    225 
    226 	memset (rsp, 0, len + sizeof(iscsid_response_t));
    227 	rsp->parameter_length = (uint32_t)len;
    228 	return rsp;
    229 }
    230 
    231 
    232 /*
    233  * process_message:
    234  *    minimal parameter check and dispatch for the daemon functions.
    235  *
    236  *    Parameter:
    237  *          req         The request
    238  *          prsp        Pointer to address of response buffer
    239  *          prsp_temp   Will be set to TRUE if buffer was allocated, FALSE
    240  *                      for static buffer.
    241  */
    242 
    243 static void
    244 process_message(iscsid_request_t *req, iscsid_response_t **prsp, int *prsp_temp)
    245 {
    246 	iscsid_response_t *rsp;
    247 	void *p = req->parameter;
    248 
    249 	*prsp_temp = FALSE;
    250 	*prsp = rsp = (iscsid_response_t *)(void *)rsp_buf;
    251 	rsp->parameter_length = 0;
    252 	rsp->status = ISCSID_STATUS_SUCCESS;
    253 
    254 	switch (req->request) {
    255 	case ISCSID_ADD_TARGET:
    256 		if (req->parameter_length < sizeof(iscsid_add_target_req_t)) {
    257 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    258 			break;
    259 		}
    260 		add_target((iscsid_add_target_req_t *)p, prsp, prsp_temp);
    261 		break;
    262 
    263 	case ISCSID_ADD_PORTAL:
    264 		if (req->parameter_length != sizeof(iscsid_add_portal_req_t)) {
    265 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    266 			break;
    267 		}
    268 		add_portal((iscsid_add_portal_req_t *)p, prsp, prsp_temp);
    269 		break;
    270 
    271 	case ISCSID_SET_TARGET_OPTIONS:
    272 		if (req->parameter_length != sizeof(iscsid_get_set_target_options_t)) {
    273 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    274 			break;
    275 		}
    276 		rsp->status = set_target_options((iscsid_get_set_target_options_t *)p);
    277 		break;
    278 
    279 	case ISCSID_GET_TARGET_OPTIONS:
    280 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
    281 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    282 			break;
    283 		}
    284 		rsp->status = ISCSID_STATUS_NOTIMPL;
    285 		break;
    286 
    287 	case ISCSID_SET_TARGET_AUTHENTICATION:
    288 		if (req->parameter_length !=
    289 			sizeof(iscsid_set_target_authentication_req_t)) {
    290 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    291 			break;
    292 		}
    293 		rsp->status = set_target_auth((iscsid_set_target_authentication_req_t *)p);
    294 		break;
    295 
    296 	case ISCSID_SLP_FIND_TARGETS:
    297 		rsp->status = ISCSID_STATUS_NOTIMPL;
    298 		break;
    299 
    300 	case ISCSID_REFRESH_TARGETS:
    301 		if (req->parameter_length < sizeof(iscsid_refresh_req_t)) {
    302 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    303 			break;
    304 		}
    305 		rsp->status = refresh_targets((iscsid_refresh_req_t *)p);
    306 		break;
    307 
    308 	case ISCSID_REMOVE_TARGET:
    309 		if (req->parameter_length != sizeof(iscsid_list_id_t)) {
    310 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    311 			break;
    312 		}
    313 		rsp->status = remove_target((iscsid_list_id_t *)p);
    314 		break;
    315 
    316 	case ISCSID_SEARCH_LIST:
    317 		if (req->parameter_length != sizeof(iscsid_search_list_req_t)) {
    318 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    319 			break;
    320 		}
    321 		search_list((iscsid_search_list_req_t *)p, prsp, prsp_temp);
    322 		break;
    323 
    324 	case ISCSID_GET_LIST:
    325 		if (req->parameter_length != sizeof(iscsid_get_list_req_t)) {
    326 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    327 			break;
    328 		}
    329 		get_list((iscsid_get_list_req_t *)p, prsp, prsp_temp);
    330 		break;
    331 
    332 	case ISCSID_GET_TARGET_INFO:
    333 		if (req->parameter_length != sizeof(iscsid_list_id_t)) {
    334 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    335 			break;
    336 		}
    337 		get_target_info((iscsid_list_id_t *)p, prsp, prsp_temp);
    338 		break;
    339 
    340 	case ISCSID_GET_PORTAL_INFO:
    341 		if (req->parameter_length != sizeof(iscsid_list_id_t)) {
    342 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    343 			break;
    344 		}
    345 		get_portal_info((iscsid_list_id_t *)p, prsp, prsp_temp);
    346 		break;
    347 
    348 #ifndef ISCSI_MINIMAL
    349 	case ISCSID_ADD_ISNS_SERVER:
    350 		if (req->parameter_length != sizeof(iscsid_add_isns_server_req_t)) {
    351 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    352 			break;
    353 		}
    354 		add_isns_server((iscsid_add_isns_server_req_t *)p,
    355 						prsp, prsp_temp);
    356 		break;
    357 
    358 	case ISCSID_GET_ISNS_SERVER:
    359 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
    360 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    361 			break;
    362 		}
    363 		get_isns_server((iscsid_sym_id_t *)p, prsp, prsp_temp);
    364 		break;
    365 
    366 	case ISCSID_SLP_FIND_ISNS_SERVERS:
    367 		rsp->status = ISCSID_STATUS_NOTIMPL;
    368 		break;
    369 
    370 	case ISCSID_REMOVE_ISNS_SERVER:
    371 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
    372 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    373 			break;
    374 		}
    375 		rsp->status = remove_isns_server((iscsid_sym_id_t *)p);
    376 		break;
    377 #endif
    378 
    379 	case ISCSID_ADD_INITIATOR_PORTAL:
    380 		if (req->parameter_length != sizeof(iscsid_add_initiator_req_t)) {
    381 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    382 			break;
    383 		}
    384 		add_initiator_portal((iscsid_add_initiator_req_t *)p,
    385 							prsp, prsp_temp);
    386 		break;
    387 
    388 	case ISCSID_GET_INITIATOR_PORTAL:
    389 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
    390 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    391 			break;
    392 		}
    393 		get_initiator_portal((iscsid_sym_id_t *)p, prsp, prsp_temp);
    394 		break;
    395 
    396 	case ISCSID_REMOVE_INITIATOR_PORTAL:
    397 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
    398 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    399 			break;
    400 		}
    401 		rsp->status = remove_initiator_portal((iscsid_sym_id_t *)p);
    402 		break;
    403 
    404 	case ISCSID_LOGIN:
    405 		if (req->parameter_length != sizeof(iscsid_login_req_t)) {
    406 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    407 			break;
    408 		}
    409 		login((iscsid_login_req_t *)p, rsp);
    410 		break;
    411 
    412 	case ISCSID_ADD_CONNECTION:
    413 		if (req->parameter_length != sizeof(iscsid_login_req_t)) {
    414 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    415 			break;
    416 		}
    417 		add_connection((iscsid_login_req_t *)p, rsp);
    418 		break;
    419 
    420 	case ISCSID_LOGOUT:
    421 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
    422 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    423 			break;
    424 		}
    425 		rsp->status = logout((iscsid_sym_id_t *)p);
    426 		break;
    427 
    428 	case ISCSID_REMOVE_CONNECTION:
    429 		if (req->parameter_length != sizeof(iscsid_remove_connection_req_t)) {
    430 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    431 			break;
    432 		}
    433 		rsp->status = remove_connection((iscsid_remove_connection_req_t *)p);
    434 		break;
    435 
    436 	case ISCSID_GET_SESSION_LIST:
    437 		get_session_list(prsp, prsp_temp);
    438 		break;
    439 
    440 	case ISCSID_GET_CONNECTION_LIST:
    441 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
    442 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    443 			break;
    444 		}
    445 		get_connection_list((iscsid_sym_id_t *)p, prsp, prsp_temp);
    446 		break;
    447 
    448 	case ISCSID_GET_CONNECTION_INFO:
    449 		if (req->parameter_length != sizeof(iscsid_get_connection_info_req_t)) {
    450 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    451 			break;
    452 		}
    453 		get_connection_info((iscsid_get_connection_info_req_t *)p,
    454 							prsp, prsp_temp);
    455 		break;
    456 
    457 	case ISCSID_SET_NODE_NAME:
    458 		if (req->parameter_length != sizeof(iscsid_set_node_name_req_t)) {
    459 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    460 			break;
    461 		}
    462 		rsp->status = set_node_name((iscsid_set_node_name_req_t *)p);
    463 		break;
    464 
    465 	case ISCSID_GET_VERSION:
    466 		get_version(prsp, prsp_temp);
    467 		break;
    468 
    469 	default:
    470 		rsp->status = ISCSID_STATUS_INVALID_REQUEST;
    471 		break;
    472 	}
    473 }
    474 
    475 
    476 /*
    477  * exit_daemon:
    478  *    Deregister the event handler, deregister isns servers, then exit program.
    479  */
    480 
    481 void
    482 exit_daemon(void)
    483 {
    484 #ifndef ISCSI_NOTHREAD
    485 	LOCK_SESSIONS;
    486 #endif
    487 	deregister_event_handler();
    488 
    489 #ifndef ISCSI_MINIMAL
    490 	dereg_all_isns_servers();
    491 #endif
    492 
    493 	printf("iSCSI Daemon Exits\n");
    494 	exit(0);
    495 }
    496 
    497 
    498 /*
    499  * main:
    500  *    init, go daemon, then loop reading requests, processing them,
    501  *    and sending responses.
    502  *    Stops on receiving a terminate message (no response to that one is sent),
    503  *    or when an error occurs reading or writing the socket.
    504  *
    505  *    Parameter:  argc, argv currently ignored.
    506  */
    507 
    508 int
    509 /*ARGSUSED*/
    510 main(int argc, char **argv)
    511 {
    512 	int req_temp, rsp_temp, c;
    513 	ssize_t ret;
    514 	size_t len;
    515 	struct sockaddr_un from;
    516 	socklen_t fromlen;
    517 	iscsid_request_t *req;
    518 	iscsid_response_t *rsp;
    519 #ifdef ISCSI_NOTHREAD
    520 	struct timeval seltout = { 2, 0 };	/* 2 second poll interval */
    521 #endif
    522 
    523 	client_sock = init_daemon();
    524 	if (client_sock < 0)
    525 		exit(1);
    526 
    527 	printf("iSCSI Daemon loaded\n");
    528 
    529 	while ((c = getopt(argc, argv, "d")) != -1)
    530 		switch (c) {
    531 		case 'd':
    532 			debug_level++;
    533 			break;
    534 		default:
    535 			usage();
    536 		}
    537 
    538 	if (!debug_level)
    539 		daemon(0, 1);
    540 
    541 #ifndef ISCSI_NOTHREAD
    542 	ret = pthread_create(&event_thread, NULL, event_handler, NULL);
    543 	if (ret) {
    544 		printf("Thread creation failed (%zd)\n", ret);
    545 		close(client_sock);
    546 		unlink(ISCSID_SOCK_NAME);
    547 		deregister_event_handler();
    548 		pthread_mutex_destroy(&sesslist_lock);
    549 		return -1;
    550 	}
    551 #else
    552 	setsockopt(client_sock, SOL_SOCKET, SO_RCVTIMEO, &seltout, sizeof(seltout));
    553 #endif
    554 
    555     /* ---------------------------------------------------------------------- */
    556 
    557 	for (;;) {
    558 		/* First, get size of request */
    559 		req = (iscsid_request_t *)(void *)req_buf;
    560 		fromlen = sizeof(from);
    561 		len = sizeof(iscsid_request_t);
    562 
    563 #ifdef ISCSI_NOTHREAD
    564 		do {
    565 			ret = recvfrom(client_sock, req, len, MSG_PEEK | MSG_WAITALL,
    566 							(struct sockaddr *) &from, &fromlen);
    567 			if (ret == -1)
    568 				event_handler(NULL);
    569 		} while (ret == -1 && errno == EAGAIN);
    570 #else
    571 		ret = recvfrom(client_sock, req, len, MSG_PEEK | MSG_WAITALL,
    572 					 (struct sockaddr *)(void *)&from, &fromlen);
    573 #endif
    574 
    575 		if ((size_t)ret != len) {
    576 			perror("Receiving from socket");
    577 			break;
    578 		}
    579 		DEB(99, ("Request %d, parlen %d\n",
    580 				req->request, req->parameter_length));
    581 
    582 		len += req->parameter_length;
    583 
    584 		/* now that we know the size, get the buffer for it */
    585 		req_temp = (len > REQ_BUFFER_SIZE);
    586 
    587 		if (req_temp) {
    588 			req = malloc(len);
    589 			if (!req) {
    590 				printf("Can't alloc %zu bytes\n", len);
    591 				break;
    592 			}
    593 		}
    594 		/* read the complete request */
    595 		fromlen = sizeof(from);
    596 		ret = recvfrom(client_sock, req, len, MSG_WAITALL,
    597 						(struct sockaddr *)(void *)&from, &fromlen);
    598 		if ((size_t)ret != len) {
    599 			DEBOUT(("Error receiving from socket!\n"));
    600 			if (req_temp)
    601 				free(req);
    602 			continue;
    603 		}
    604 		/* terminate? then go die. */
    605 		if (req->request == ISCSID_DAEMON_TERMINATE)
    606 			break;
    607 
    608 		/* No reply required to test message */
    609 		if (req->request == ISCSID_DAEMON_TEST) {
    610 			if (req_temp)
    611 				free(req);
    612 			continue;
    613 		}
    614 		/* no return path? then we can't send a reply, */
    615 		/* so don't process the command */
    616 		if (!from.sun_path[0]) {
    617 			DEBOUT(("No Return Address!\n"));
    618 			continue;
    619 		}
    620 		/* process the request */
    621 		process_message(req, &rsp, &rsp_temp);
    622 		if (rsp == NULL)
    623 			break;
    624 
    625 		DEB(99, ("Sending reply: status %d, len %d\n",
    626 				rsp->status, rsp->parameter_length));
    627 
    628 		/* send the response */
    629 		len = sizeof(iscsid_response_t) + rsp->parameter_length;
    630 		ret = sendto(client_sock, rsp, len, 0,
    631 					(struct sockaddr *)(void *)&from, fromlen);
    632 		if (len != (size_t)ret) {
    633 			DEBOUT(("Error sending reply!\n"));
    634 		}
    635 		/* free temp buffers if we needed them */
    636 		if (req_temp)
    637 			free(req);
    638 		if (rsp_temp)
    639 			free(rsp);
    640 	}
    641 
    642 	exit_daemon();
    643 
    644 	/* we never get here */
    645 	return 0;
    646 }
    647