xref: /netbsd-src/sbin/iscsid/iscsid_main.c (revision 82974f22171b7d1088bdcd8b127d91946fab6c02)
1 /*	$NetBSD: iscsid_main.c,v 1.12 2019/02/04 08:21:12 mrg 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
usage(void)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
create_node_name(void)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 	int total;
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(3, ("Host Name: <%s>, Host ID: %u", 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 	total = snprintf((char *)snp.InitiatorName, sizeof(snp.InitiatorName),
114 		"iqn.1994-04.org.netbsd:iscsi.%s:%u", snp.InitiatorAlias, hid);
115 	if ((size_t)total > sizeof(snp.InitiatorName)) {
116 		printf("Warning: iSCSI Node InitiatorName too long to set InitiatorAlias!\n");
117 		return ISCSID_STATUS_NO_INITIATOR_NAME;
118 	}
119 
120 	ioctl(driver, ISCSI_SET_NODE_NAME, &snp);
121 	return snp.status;
122 }
123 
124 
125 /*
126  * init_daemon:
127  *    Open driver, create communication socket.
128  *
129  *    Returns:    <0 on error
130  */
131 
132 static int
init_daemon(void)133 init_daemon(void)
134 {
135 	int sock, i;
136 	struct sockaddr_un name;
137 	iscsid_request_t req;
138 
139 	if ((driver = open(DEVICE, O_RDONLY)) < 0) {
140 		perror("opening " DEVICE);
141 		return -1;
142 	}
143 
144 	sock = socket(AF_UNIX, SOCK_DGRAM, 0);
145 	if (sock < 0) {
146 		perror("opening datagram socket");
147 		return -1;
148 	}
149 
150 	name.sun_family = AF_UNIX;
151 	strlcpy(name.sun_path, ISCSID_SOCK_NAME, sizeof(name.sun_path));
152 
153 	req.request = ISCSID_DAEMON_TEST;
154 	req.parameter_length = 0;
155 
156 	i = sendto(sock, &req, sizeof(req), 0, (struct sockaddr *)(void *)&name,
157 				(socklen_t)sizeof(struct sockaddr_un));
158 	if (i == sizeof(req)) {
159 		printf("Daemon already loaded!\n");
160 		close(sock);
161 		return -1;
162 	}
163 
164 	unlink(ISCSID_SOCK_NAME);
165 	if (bind(sock, (struct sockaddr *)(void *)&name, (socklen_t)sizeof(struct sockaddr_un))) {
166 		perror("binding name to socket");
167 		return -1;
168 	}
169 
170 	for (i = 0; i < NUM_DAEMON_LISTS; i++) {
171 		TAILQ_INIT(&list[i].list);
172 		list[i].num_entries = 0;
173 	}
174 
175 	if ((i = pthread_mutex_init(&sesslist_lock, NULL)) != 0) {
176 		printf("Mutex init failed (%d)\n", i);
177 		close(sock);
178 		return -1;
179 	}
180 
181 	if (!register_event_handler()) {
182 		printf("Couldn't register event handler\n");
183 		close(sock);
184 		unlink(ISCSID_SOCK_NAME);
185 		pthread_mutex_destroy(&sesslist_lock);
186 		return -1;
187 	}
188 
189 	create_node_name();
190 
191 	return sock;
192 }
193 
194 
195 /*
196  * make_rsp:
197  *    Allocate a response buffer if the static buffer is insufficient, set
198  *    the response parameter length.
199  *
200  *    Parameter:
201  *          len         Response parameter size (not counting header)
202  *          prsp        Pointer to address of response buffer
203  *          prsp_temp   Will be set to TRUE if buffer was allocated, FALSE
204  *                      for static buffer.
205  *
206  *    Returns:    Pointer to response buffer, NULL if allocation failed.
207  */
208 
209 iscsid_response_t *
make_rsp(size_t len,iscsid_response_t ** prsp,int * prsp_temp)210 make_rsp(size_t len, iscsid_response_t ** prsp, int *prsp_temp)
211 {
212 	iscsid_response_t *rsp;
213 
214 	if ((len + sizeof(iscsid_response_t)) > RSP_BUFFER_SIZE) {
215 		if ((rsp = calloc(1, len)) == NULL) {
216 			(*prsp)->status = ISCSID_STATUS_NO_RESOURCES;
217 			return NULL;
218 		}
219 		*prsp_temp = TRUE;
220 		*prsp = rsp;
221 	} else
222 		rsp = *prsp;
223 
224 	memset (rsp, 0, len + sizeof(iscsid_response_t));
225 	rsp->parameter_length = (uint32_t)len;
226 	return rsp;
227 }
228 
229 
230 /*
231  * process_message:
232  *    minimal parameter check and dispatch for the daemon functions.
233  *
234  *    Parameter:
235  *          req         The request
236  *          prsp        Pointer to address of response buffer
237  *          prsp_temp   Will be set to TRUE if buffer was allocated, FALSE
238  *                      for static buffer.
239  */
240 
241 static void
process_message(iscsid_request_t * req,iscsid_response_t ** prsp,int * prsp_temp)242 process_message(iscsid_request_t *req, iscsid_response_t **prsp, int *prsp_temp)
243 {
244 	iscsid_response_t *rsp;
245 	void *p = req->parameter;
246 
247 	*prsp_temp = FALSE;
248 	*prsp = rsp = (iscsid_response_t *)(void *)rsp_buf;
249 	rsp->parameter_length = 0;
250 	rsp->status = ISCSID_STATUS_SUCCESS;
251 
252 	switch (req->request) {
253 	case ISCSID_ADD_TARGET:
254 		if (req->parameter_length < sizeof(iscsid_add_target_req_t)) {
255 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
256 			break;
257 		}
258 		add_target((iscsid_add_target_req_t *)p, prsp, prsp_temp);
259 		break;
260 
261 	case ISCSID_ADD_PORTAL:
262 		if (req->parameter_length != sizeof(iscsid_add_portal_req_t)) {
263 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
264 			break;
265 		}
266 		add_portal((iscsid_add_portal_req_t *)p, prsp, prsp_temp);
267 		break;
268 
269 	case ISCSID_SET_TARGET_OPTIONS:
270 		if (req->parameter_length != sizeof(iscsid_get_set_target_options_t)) {
271 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
272 			break;
273 		}
274 		rsp->status = set_target_options((iscsid_get_set_target_options_t *)p);
275 		break;
276 
277 	case ISCSID_GET_TARGET_OPTIONS:
278 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
279 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
280 			break;
281 		}
282 		rsp->status = ISCSID_STATUS_NOTIMPL;
283 		break;
284 
285 	case ISCSID_SET_TARGET_AUTHENTICATION:
286 		if (req->parameter_length !=
287 			sizeof(iscsid_set_target_authentication_req_t)) {
288 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
289 			break;
290 		}
291 		rsp->status = set_target_auth((iscsid_set_target_authentication_req_t *)p);
292 		break;
293 
294 	case ISCSID_SLP_FIND_TARGETS:
295 		rsp->status = ISCSID_STATUS_NOTIMPL;
296 		break;
297 
298 	case ISCSID_REFRESH_TARGETS:
299 		if (req->parameter_length < sizeof(iscsid_refresh_req_t)) {
300 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
301 			break;
302 		}
303 		rsp->status = refresh_targets((iscsid_refresh_req_t *)p);
304 		break;
305 
306 	case ISCSID_REMOVE_TARGET:
307 		if (req->parameter_length != sizeof(iscsid_list_id_t)) {
308 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
309 			break;
310 		}
311 		rsp->status = remove_target((iscsid_list_id_t *)p);
312 		break;
313 
314 	case ISCSID_SEARCH_LIST:
315 		if (req->parameter_length != sizeof(iscsid_search_list_req_t)) {
316 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
317 			break;
318 		}
319 		search_list((iscsid_search_list_req_t *)p, prsp, prsp_temp);
320 		break;
321 
322 	case ISCSID_GET_LIST:
323 		if (req->parameter_length != sizeof(iscsid_get_list_req_t)) {
324 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
325 			break;
326 		}
327 		get_list((iscsid_get_list_req_t *)p, prsp, prsp_temp);
328 		break;
329 
330 	case ISCSID_GET_TARGET_INFO:
331 		if (req->parameter_length != sizeof(iscsid_list_id_t)) {
332 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
333 			break;
334 		}
335 		get_target_info((iscsid_list_id_t *)p, prsp, prsp_temp);
336 		break;
337 
338 	case ISCSID_GET_PORTAL_INFO:
339 		if (req->parameter_length != sizeof(iscsid_list_id_t)) {
340 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
341 			break;
342 		}
343 		get_portal_info((iscsid_list_id_t *)p, prsp, prsp_temp);
344 		break;
345 
346 #ifndef ISCSI_MINIMAL
347 	case ISCSID_ADD_ISNS_SERVER:
348 		if (req->parameter_length != sizeof(iscsid_add_isns_server_req_t)) {
349 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
350 			break;
351 		}
352 		add_isns_server((iscsid_add_isns_server_req_t *)p,
353 						prsp, prsp_temp);
354 		break;
355 
356 	case ISCSID_GET_ISNS_SERVER:
357 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
358 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
359 			break;
360 		}
361 		get_isns_server((iscsid_sym_id_t *)p, prsp, prsp_temp);
362 		break;
363 
364 	case ISCSID_SLP_FIND_ISNS_SERVERS:
365 		rsp->status = ISCSID_STATUS_NOTIMPL;
366 		break;
367 
368 	case ISCSID_REMOVE_ISNS_SERVER:
369 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
370 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
371 			break;
372 		}
373 		rsp->status = remove_isns_server((iscsid_sym_id_t *)p);
374 		break;
375 #endif
376 
377 	case ISCSID_ADD_INITIATOR_PORTAL:
378 		if (req->parameter_length != sizeof(iscsid_add_initiator_req_t)) {
379 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
380 			break;
381 		}
382 		add_initiator_portal((iscsid_add_initiator_req_t *)p,
383 							prsp, prsp_temp);
384 		break;
385 
386 	case ISCSID_GET_INITIATOR_PORTAL:
387 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
388 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
389 			break;
390 		}
391 		get_initiator_portal((iscsid_sym_id_t *)p, prsp, prsp_temp);
392 		break;
393 
394 	case ISCSID_REMOVE_INITIATOR_PORTAL:
395 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
396 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
397 			break;
398 		}
399 		rsp->status = remove_initiator_portal((iscsid_sym_id_t *)p);
400 		break;
401 
402 	case ISCSID_LOGIN:
403 		if (req->parameter_length != sizeof(iscsid_login_req_t)) {
404 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
405 			break;
406 		}
407 		log_in((iscsid_login_req_t *)p, rsp);
408 		break;
409 
410 	case ISCSID_ADD_CONNECTION:
411 		if (req->parameter_length != sizeof(iscsid_login_req_t)) {
412 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
413 			break;
414 		}
415 		add_connection((iscsid_login_req_t *)p, rsp);
416 		break;
417 
418 	case ISCSID_LOGOUT:
419 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
420 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
421 			break;
422 		}
423 		rsp->status = log_out((iscsid_sym_id_t *)p);
424 		break;
425 
426 	case ISCSID_REMOVE_CONNECTION:
427 		if (req->parameter_length != sizeof(iscsid_remove_connection_req_t)) {
428 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
429 			break;
430 		}
431 		rsp->status = remove_connection((iscsid_remove_connection_req_t *)p);
432 		break;
433 
434 	case ISCSID_GET_SESSION_LIST:
435 		get_session_list(prsp, prsp_temp);
436 		break;
437 
438 	case ISCSID_GET_CONNECTION_LIST:
439 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
440 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
441 			break;
442 		}
443 		get_connection_list((iscsid_sym_id_t *)p, prsp, prsp_temp);
444 		break;
445 
446 	case ISCSID_GET_CONNECTION_INFO:
447 		if (req->parameter_length != sizeof(iscsid_get_connection_info_req_t)) {
448 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
449 			break;
450 		}
451 		get_connection_info((iscsid_get_connection_info_req_t *)p,
452 							prsp, prsp_temp);
453 		break;
454 
455 	case ISCSID_SET_NODE_NAME:
456 		if (req->parameter_length != sizeof(iscsid_set_node_name_req_t)) {
457 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
458 			break;
459 		}
460 		rsp->status = set_node_name((iscsid_set_node_name_req_t *)p);
461 		break;
462 
463 	case ISCSID_GET_VERSION:
464 		get_version(prsp, prsp_temp);
465 		break;
466 
467 	default:
468 		rsp->status = ISCSID_STATUS_INVALID_REQUEST;
469 		break;
470 	}
471 }
472 
473 void
iscsid_log(const char * fmt,...)474 iscsid_log(const char *fmt, ...)
475 {
476 	va_list ap;
477 	va_start(ap, fmt);
478 	vsyslog(LOG_INFO, fmt, ap);
479 	va_end(ap);
480 }
481 
482 /*
483  * exit_daemon:
484  *    Deregister the event handler, deregister isns servers, then exit program.
485  */
486 
487 static void __dead
exit_daemon(void)488 exit_daemon(void)
489 {
490 	LOCK_SESSIONS;
491 	deregister_event_handler();
492 
493 #ifndef ISCSI_MINIMAL
494 	dereg_all_isns_servers();
495 #endif
496 	exit(0);
497 }
498 
499 static void
handler_exit(void)500 handler_exit(void)
501 {
502 	pthread_kill(main_thread, SIGINT);
503 }
504 
505 static void
sighandler(int sig)506 sighandler(int sig)
507 {
508 }
509 
510 /*
511  * main:
512  *    init, go daemon, then loop reading requests, processing them,
513  *    and sending responses.
514  *    Stops on receiving a terminate message (no response to that one is sent),
515  *    or when an error occurs reading or writing the socket.
516  *
517  *    Parameter:  argc, argv currently ignored.
518  */
519 
520 int
521 /*ARGSUSED*/
main(int argc,char ** argv)522 main(int argc, char **argv)
523 {
524 	int req_temp, rsp_temp, c;
525 	ssize_t ret;
526 	size_t len;
527 	struct sockaddr_un from;
528 	socklen_t fromlen;
529 	iscsid_request_t *req;
530 	iscsid_response_t *rsp;
531 	char *p;
532 	struct sigaction sa;
533 
534 	while ((c = getopt(argc, argv, "Dd:")) != -1)
535 		switch (c) {
536 		case 'D':
537 			debugging++;
538 			break;
539 		case 'd':
540 			debug_level=(int)strtol(optarg, &p, 10);
541 			if (*p)
542 				errx(EXIT_FAILURE, "illegal log level -- %s",
543 				    optarg);
544 			break;
545 		default:
546 			usage();
547 		}
548 
549 	openlog("iscsid", (debugging ? LOG_PERROR : 0) | LOG_PID, LOG_DAEMON);
550 
551 	client_sock = init_daemon();
552 	if (client_sock < 0)
553 		exit(1);
554 
555 	DEBOUT(("iSCSI daemon loaded"));
556 
557 	if (!debugging) {
558 		if (daemon(0, 1) < 0)
559 			err(EXIT_FAILURE, "daemon() failed");
560 		pidfile(NULL);
561 	}
562 
563 	memset(&sa, 0, sizeof(sa));
564 	sa.sa_handler = sighandler;
565 	sigaction(SIGINT, &sa, NULL);
566 	sigaction(SIGTERM, &sa, NULL);
567 
568 	main_thread = pthread_self();
569 	ret = pthread_create(&event_thread, NULL, event_handler, handler_exit);
570 	if (ret) {
571 		printf("Thread creation failed (%zd)\n", ret);
572 		close(client_sock);
573 		unlink(ISCSID_SOCK_NAME);
574 		deregister_event_handler();
575 		pthread_mutex_destroy(&sesslist_lock);
576 		return -1;
577 	}
578 
579     /* ---------------------------------------------------------------------- */
580 
581 	for (;;) {
582 
583 		/* First, get size of request */
584 		req = (iscsid_request_t *)(void *)req_buf;
585 		fromlen = sizeof(from);
586 		len = sizeof(iscsid_request_t);
587 
588 		do {
589 			ret = recvfrom(client_sock, req, len, MSG_PEEK |
590 			    MSG_WAITALL, (struct sockaddr *) &from,
591 			    &fromlen);
592 		} while (ret == -1 && errno == EAGAIN);
593 
594 		if ((size_t)ret != len) {
595 			DEBOUT(("Receiving from socket: %s",strerror(errno)));
596 			break;
597 		}
598 		DEB(2, ("Request %d, parlen %d",
599 				req->request, req->parameter_length));
600 
601 		len += req->parameter_length;
602 
603 		/* now that we know the size, get the buffer for it */
604 		req_temp = (len > REQ_BUFFER_SIZE);
605 
606 		if (req_temp) {
607 			req = malloc(len);
608 			if (!req) {
609 				printf("Can't alloc %zu bytes\n", len);
610 				break;
611 			}
612 		}
613 		/* read the complete request */
614 		fromlen = sizeof(from);
615 		ret = recvfrom(client_sock, req, len, MSG_WAITALL,
616 						(struct sockaddr *)(void *)&from, &fromlen);
617 		if ((size_t)ret != len) {
618 			DEB(2, ("Error receiving from socket!"));
619 			if (req_temp)
620 				free(req);
621 			continue;
622 		}
623 		/* terminate? then go die. */
624 		if (req->request == ISCSID_DAEMON_TERMINATE)
625 			break;
626 
627 		/* No reply required to test message */
628 		if (req->request == ISCSID_DAEMON_TEST) {
629 			if (req_temp)
630 				free(req);
631 			DEB(2, ("Test message!"));
632 			continue;
633 		}
634 		/* no return path? then we can't send a reply, */
635 		/* so don't process the command */
636 		if (!from.sun_path[0]) {
637 			if (req_temp)
638 				free(req);
639 			DEB(2, ("No Return Address!"));
640 			continue;
641 		}
642 		/* process the request */
643 		process_message(req, &rsp, &rsp_temp);
644 		if (rsp == NULL) {
645 			if (req_temp)
646 				free(req);
647 			DEB(2, ("Invalid message!"));
648 			continue;
649 		}
650 
651 		DEB(2, ("Sending reply: status %d, len %d",
652 				rsp->status, rsp->parameter_length));
653 
654 		/* send the response */
655 		len = sizeof(iscsid_response_t) + rsp->parameter_length;
656 		ret = sendto(client_sock, rsp, len, 0,
657 					(struct sockaddr *)(void *)&from, fromlen);
658 		if (len != (size_t)ret) {
659 			DEB(2, ("Error sending reply!"));
660 		}
661 		/* free temp buffers if we needed them */
662 		if (req_temp)
663 			free(req);
664 		if (rsp_temp)
665 			free(rsp);
666 	}
667 
668 	pthread_join(event_thread, NULL);
669 
670 	DEBOUT(("Exiting daemon"));
671 
672 	exit_daemon();
673 
674 	/* we never get here */
675 	return 0;
676 }
677