xref: /netbsd-src/sbin/iscsid/iscsid_main.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
1 /*	$NetBSD: iscsid_main.c,v 1.8 2012/12/29 08:28:20 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 
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 			if (req_temp)
625 				free(req);
626 			DEBOUT(("No Return Address!\n"));
627 			continue;
628 		}
629 		/* process the request */
630 		process_message(req, &rsp, &rsp_temp);
631 		if (rsp == NULL) {
632 			if (req_temp)
633 				free(req);
634 			DEBOUT(("Invalid message!\n"));
635 			continue;
636 		}
637 
638 		DEB(98, ("Sending reply: status %d, len %d\n",
639 				rsp->status, rsp->parameter_length));
640 
641 		/* send the response */
642 		len = sizeof(iscsid_response_t) + rsp->parameter_length;
643 		ret = sendto(client_sock, rsp, len, 0,
644 					(struct sockaddr *)(void *)&from, fromlen);
645 		if (len != (size_t)ret) {
646 			DEBOUT(("Error sending reply!\n"));
647 		}
648 		/* free temp buffers if we needed them */
649 		if (req_temp)
650 			free(req);
651 		if (rsp_temp)
652 			free(rsp);
653 	}
654 
655 	exit_daemon();
656 
657 	/* we never get here */
658 	return 0;
659 }
660