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