xref: /netbsd-src/sbin/iscsid/iscsid_main.c (revision 82974f22171b7d1088bdcd8b127d91946fab6c02)
1*82974f22Smrg /*	$NetBSD: iscsid_main.c,v 1.12 2019/02/04 08:21:12 mrg Exp $	*/
275a17f3cSagc 
375a17f3cSagc /*-
475a17f3cSagc  * Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc.
575a17f3cSagc  * All rights reserved.
675a17f3cSagc  *
775a17f3cSagc  * This code is derived from software contributed to The NetBSD Foundation
875a17f3cSagc  * by Wasabi Systems, Inc.
975a17f3cSagc  *
1075a17f3cSagc  * Redistribution and use in source and binary forms, with or without
1175a17f3cSagc  * modification, are permitted provided that the following conditions
1275a17f3cSagc  * are met:
1375a17f3cSagc  * 1. Redistributions of source code must retain the above copyright
1475a17f3cSagc  *    notice, this list of conditions and the following disclaimer.
1575a17f3cSagc  * 2. Redistributions in binary form must reproduce the above copyright
1675a17f3cSagc  *    notice, this list of conditions and the following disclaimer in the
1775a17f3cSagc  *    documentation and/or other materials provided with the distribution.
1875a17f3cSagc  *
1975a17f3cSagc  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2075a17f3cSagc  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2175a17f3cSagc  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2275a17f3cSagc  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2375a17f3cSagc  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2475a17f3cSagc  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2575a17f3cSagc  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2675a17f3cSagc  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2775a17f3cSagc  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2875a17f3cSagc  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2975a17f3cSagc  * POSSIBILITY OF SUCH DAMAGE.
3075a17f3cSagc  */
3175a17f3cSagc 
3275a17f3cSagc #include "iscsid_globals.h"
3375a17f3cSagc 
3475a17f3cSagc #include <sys/types.h>
3575a17f3cSagc #include <sys/socket.h>
3675a17f3cSagc #include <sys/un.h>
3775a17f3cSagc #include <sys/sysctl.h>
3875a17f3cSagc 
3975a17f3cSagc #include <ctype.h>
40c08d1e52Sriz #include <err.h>
4175a17f3cSagc #include <fcntl.h>
426fea88c2Smlelstv #include <syslog.h>
436fea88c2Smlelstv #include <util.h>
4475a17f3cSagc 
4575a17f3cSagc #define DEVICE    "/dev/iscsi0"
4675a17f3cSagc 
4775a17f3cSagc /* -------------------------------------------------------------------------- */
4875a17f3cSagc 
4975a17f3cSagc list_head_t list[NUM_DAEMON_LISTS];	/* the lists this daemon keeps */
5075a17f3cSagc 
5175a17f3cSagc pthread_mutex_t sesslist_lock;	/* session list lock */
526fea88c2Smlelstv pthread_t main_thread;		/* main thread handle */
5375a17f3cSagc pthread_t event_thread;		/* event thread handle */
5475a17f3cSagc 
5575a17f3cSagc int driver = -1;		/* the driver's file desc */
5675a17f3cSagc int client_sock;		/* the client communication socket */
5775a17f3cSagc 
58e85ef03bSjoerg int debug_level;		/* How much info to display */
596fea88c2Smlelstv int debugging;
6075a17f3cSagc 
6175a17f3cSagc /*
6275a17f3cSagc    To avoid memory fragmentation (and speed things up a bit), we use the
6375a17f3cSagc    static bufs unless the request or response exceeds the buffer size
6475a17f3cSagc    (which it normally shouldn't, assuming we don't have thousands
6575a17f3cSagc    of list entries).
6675a17f3cSagc */
6738a27f5aSagc static uint8_t req_buf[REQ_BUFFER_SIZE];	/* default buffer for requests */
6838a27f5aSagc static uint8_t rsp_buf[RSP_BUFFER_SIZE];	/* default buffer for responses */
6975a17f3cSagc 
7075a17f3cSagc /* -------------------------------------------------------------------------- */
7175a17f3cSagc 
7268a964c3Schristos static void __dead
usage(void)7368a964c3Schristos usage(void)
7468a964c3Schristos {
75c08d1e52Sriz 	fprintf(stderr, "Usage: %s [-d <lvl>] [-n]\n", getprogname());
7668a964c3Schristos 	exit(EXIT_FAILURE);
7768a964c3Schristos }
7868a964c3Schristos 
7975a17f3cSagc /*
8075a17f3cSagc  * create_node_name:
8175a17f3cSagc  *    Create and set default node name.
8275a17f3cSagc  *
8375a17f3cSagc  *    Returns 0 on success, else an error code.
8475a17f3cSagc  */
8575a17f3cSagc 
8638a27f5aSagc static int
create_node_name(void)8775a17f3cSagc create_node_name(void)
8875a17f3cSagc {
8975a17f3cSagc 	iscsi_set_node_name_parameters_t snp;
9075a17f3cSagc 	uint32_t hid = 0;
9175a17f3cSagc 	size_t siz;
9275a17f3cSagc 	int mib[2];
93*82974f22Smrg 	int total;
9475a17f3cSagc 	unsigned char *s;
9575a17f3cSagc 
9675a17f3cSagc 	(void) memset(&snp, 0x0, sizeof(snp));
9775a17f3cSagc 	mib[0] = CTL_KERN;
9875a17f3cSagc 	mib[1] = KERN_HOSTID;
9975a17f3cSagc 	siz = sizeof(hid);
10075a17f3cSagc 	sysctl(mib, 2, &hid, &siz, NULL, 0);
10175a17f3cSagc 	mib[1] = KERN_HOSTNAME;
10275a17f3cSagc 	siz = ISCSI_STRING_LENGTH - 45;
10375a17f3cSagc 	sysctl(mib, 2, snp.InitiatorAlias, &siz, NULL, 0);
10475a17f3cSagc 
1056fea88c2Smlelstv 	DEB(3, ("Host Name: <%s>, Host ID: %u", snp.InitiatorAlias, hid));
10675a17f3cSagc 	if (!snp.InitiatorAlias[0]) {
10775a17f3cSagc 		printf("Warning: iSCSI Node Name not set (No Host Name)!\n");
10875a17f3cSagc 		return ISCSID_STATUS_NO_INITIATOR_NAME;
10975a17f3cSagc 	}
11075a17f3cSagc 	for (s = snp.InitiatorAlias; *s; s++)
11175a17f3cSagc 		if (!isalnum((unsigned char) *s) && *s != '-' && *s != '.' && *s != ':')
11275a17f3cSagc 			*s = '-';
113*82974f22Smrg 	total = snprintf((char *)snp.InitiatorName, sizeof(snp.InitiatorName),
11475a17f3cSagc 		"iqn.1994-04.org.netbsd:iscsi.%s:%u", snp.InitiatorAlias, hid);
115*82974f22Smrg 	if ((size_t)total > sizeof(snp.InitiatorName)) {
116*82974f22Smrg 		printf("Warning: iSCSI Node InitiatorName too long to set InitiatorAlias!\n");
117*82974f22Smrg 		return ISCSID_STATUS_NO_INITIATOR_NAME;
118*82974f22Smrg 	}
11975a17f3cSagc 
12075a17f3cSagc 	ioctl(driver, ISCSI_SET_NODE_NAME, &snp);
12175a17f3cSagc 	return snp.status;
12275a17f3cSagc }
12375a17f3cSagc 
12475a17f3cSagc 
12575a17f3cSagc /*
12675a17f3cSagc  * init_daemon:
12775a17f3cSagc  *    Open driver, create communication socket.
12875a17f3cSagc  *
12975a17f3cSagc  *    Returns:    <0 on error
13075a17f3cSagc  */
13175a17f3cSagc 
13238a27f5aSagc static int
init_daemon(void)13375a17f3cSagc init_daemon(void)
13475a17f3cSagc {
13575a17f3cSagc 	int sock, i;
13675a17f3cSagc 	struct sockaddr_un name;
13775a17f3cSagc 	iscsid_request_t req;
13875a17f3cSagc 
13975a17f3cSagc 	if ((driver = open(DEVICE, O_RDONLY)) < 0) {
14075a17f3cSagc 		perror("opening " DEVICE);
14175a17f3cSagc 		return -1;
14275a17f3cSagc 	}
14375a17f3cSagc 
14475a17f3cSagc 	sock = socket(AF_UNIX, SOCK_DGRAM, 0);
14575a17f3cSagc 	if (sock < 0) {
14675a17f3cSagc 		perror("opening datagram socket");
14775a17f3cSagc 		return -1;
14875a17f3cSagc 	}
14975a17f3cSagc 
15075a17f3cSagc 	name.sun_family = AF_UNIX;
15175a17f3cSagc 	strlcpy(name.sun_path, ISCSID_SOCK_NAME, sizeof(name.sun_path));
15275a17f3cSagc 
15375a17f3cSagc 	req.request = ISCSID_DAEMON_TEST;
15475a17f3cSagc 	req.parameter_length = 0;
15575a17f3cSagc 
156f7720048Schristos 	i = sendto(sock, &req, sizeof(req), 0, (struct sockaddr *)(void *)&name,
157f7720048Schristos 				(socklen_t)sizeof(struct sockaddr_un));
15875a17f3cSagc 	if (i == sizeof(req)) {
15975a17f3cSagc 		printf("Daemon already loaded!\n");
16075a17f3cSagc 		close(sock);
16175a17f3cSagc 		return -1;
16275a17f3cSagc 	}
16375a17f3cSagc 
16475a17f3cSagc 	unlink(ISCSID_SOCK_NAME);
165f7720048Schristos 	if (bind(sock, (struct sockaddr *)(void *)&name, (socklen_t)sizeof(struct sockaddr_un))) {
16675a17f3cSagc 		perror("binding name to socket");
16775a17f3cSagc 		return -1;
16875a17f3cSagc 	}
16975a17f3cSagc 
17075a17f3cSagc 	for (i = 0; i < NUM_DAEMON_LISTS; i++) {
17175a17f3cSagc 		TAILQ_INIT(&list[i].list);
17275a17f3cSagc 		list[i].num_entries = 0;
17375a17f3cSagc 	}
17475a17f3cSagc 
1756fea88c2Smlelstv 	if ((i = pthread_mutex_init(&sesslist_lock, NULL)) != 0) {
17675a17f3cSagc 		printf("Mutex init failed (%d)\n", i);
17775a17f3cSagc 		close(sock);
17875a17f3cSagc 		return -1;
17975a17f3cSagc 	}
18075a17f3cSagc 
18175a17f3cSagc 	if (!register_event_handler()) {
18275a17f3cSagc 		printf("Couldn't register event handler\n");
18375a17f3cSagc 		close(sock);
18475a17f3cSagc 		unlink(ISCSID_SOCK_NAME);
18575a17f3cSagc 		pthread_mutex_destroy(&sesslist_lock);
18675a17f3cSagc 		return -1;
18775a17f3cSagc 	}
18875a17f3cSagc 
18975a17f3cSagc 	create_node_name();
19075a17f3cSagc 
19175a17f3cSagc 	return sock;
19275a17f3cSagc }
19375a17f3cSagc 
19475a17f3cSagc 
19575a17f3cSagc /*
19675a17f3cSagc  * make_rsp:
19775a17f3cSagc  *    Allocate a response buffer if the static buffer is insufficient, set
19875a17f3cSagc  *    the response parameter length.
19975a17f3cSagc  *
20075a17f3cSagc  *    Parameter:
20175a17f3cSagc  *          len         Response parameter size (not counting header)
20275a17f3cSagc  *          prsp        Pointer to address of response buffer
20375a17f3cSagc  *          prsp_temp   Will be set to TRUE if buffer was allocated, FALSE
20475a17f3cSagc  *                      for static buffer.
20575a17f3cSagc  *
20675a17f3cSagc  *    Returns:    Pointer to response buffer, NULL if allocation failed.
20775a17f3cSagc  */
20875a17f3cSagc 
20975a17f3cSagc iscsid_response_t *
make_rsp(size_t len,iscsid_response_t ** prsp,int * prsp_temp)210f7720048Schristos make_rsp(size_t len, iscsid_response_t ** prsp, int *prsp_temp)
21175a17f3cSagc {
21275a17f3cSagc 	iscsid_response_t *rsp;
21375a17f3cSagc 
21475a17f3cSagc 	if ((len + sizeof(iscsid_response_t)) > RSP_BUFFER_SIZE) {
21575a17f3cSagc 		if ((rsp = calloc(1, len)) == NULL) {
21675a17f3cSagc 			(*prsp)->status = ISCSID_STATUS_NO_RESOURCES;
21775a17f3cSagc 			return NULL;
21875a17f3cSagc 		}
21975a17f3cSagc 		*prsp_temp = TRUE;
22075a17f3cSagc 		*prsp = rsp;
22175a17f3cSagc 	} else
22275a17f3cSagc 		rsp = *prsp;
22375a17f3cSagc 
22475a17f3cSagc 	memset (rsp, 0, len + sizeof(iscsid_response_t));
225f7720048Schristos 	rsp->parameter_length = (uint32_t)len;
22675a17f3cSagc 	return rsp;
22775a17f3cSagc }
22875a17f3cSagc 
22975a17f3cSagc 
23075a17f3cSagc /*
23175a17f3cSagc  * process_message:
23275a17f3cSagc  *    minimal parameter check and dispatch for the daemon functions.
23375a17f3cSagc  *
23475a17f3cSagc  *    Parameter:
23575a17f3cSagc  *          req         The request
23675a17f3cSagc  *          prsp        Pointer to address of response buffer
23775a17f3cSagc  *          prsp_temp   Will be set to TRUE if buffer was allocated, FALSE
23875a17f3cSagc  *                      for static buffer.
23975a17f3cSagc  */
24075a17f3cSagc 
24138a27f5aSagc static void
process_message(iscsid_request_t * req,iscsid_response_t ** prsp,int * prsp_temp)24275a17f3cSagc process_message(iscsid_request_t *req, iscsid_response_t **prsp, int *prsp_temp)
24375a17f3cSagc {
24475a17f3cSagc 	iscsid_response_t *rsp;
245f7720048Schristos 	void *p = req->parameter;
24675a17f3cSagc 
24775a17f3cSagc 	*prsp_temp = FALSE;
248f7720048Schristos 	*prsp = rsp = (iscsid_response_t *)(void *)rsp_buf;
24975a17f3cSagc 	rsp->parameter_length = 0;
25075a17f3cSagc 	rsp->status = ISCSID_STATUS_SUCCESS;
25175a17f3cSagc 
25275a17f3cSagc 	switch (req->request) {
25375a17f3cSagc 	case ISCSID_ADD_TARGET:
25475a17f3cSagc 		if (req->parameter_length < sizeof(iscsid_add_target_req_t)) {
25575a17f3cSagc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
25675a17f3cSagc 			break;
25775a17f3cSagc 		}
258f7720048Schristos 		add_target((iscsid_add_target_req_t *)p, prsp, prsp_temp);
25975a17f3cSagc 		break;
26075a17f3cSagc 
26175a17f3cSagc 	case ISCSID_ADD_PORTAL:
26275a17f3cSagc 		if (req->parameter_length != sizeof(iscsid_add_portal_req_t)) {
26375a17f3cSagc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
26475a17f3cSagc 			break;
26575a17f3cSagc 		}
266f7720048Schristos 		add_portal((iscsid_add_portal_req_t *)p, prsp, prsp_temp);
26775a17f3cSagc 		break;
26875a17f3cSagc 
26975a17f3cSagc 	case ISCSID_SET_TARGET_OPTIONS:
27075a17f3cSagc 		if (req->parameter_length != sizeof(iscsid_get_set_target_options_t)) {
27175a17f3cSagc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
27275a17f3cSagc 			break;
27375a17f3cSagc 		}
274f7720048Schristos 		rsp->status = set_target_options((iscsid_get_set_target_options_t *)p);
27575a17f3cSagc 		break;
27675a17f3cSagc 
27775a17f3cSagc 	case ISCSID_GET_TARGET_OPTIONS:
27875a17f3cSagc 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
27975a17f3cSagc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
28075a17f3cSagc 			break;
28175a17f3cSagc 		}
28275a17f3cSagc 		rsp->status = ISCSID_STATUS_NOTIMPL;
28375a17f3cSagc 		break;
28475a17f3cSagc 
28575a17f3cSagc 	case ISCSID_SET_TARGET_AUTHENTICATION:
28675a17f3cSagc 		if (req->parameter_length !=
28775a17f3cSagc 			sizeof(iscsid_set_target_authentication_req_t)) {
28875a17f3cSagc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
28975a17f3cSagc 			break;
29075a17f3cSagc 		}
291f7720048Schristos 		rsp->status = set_target_auth((iscsid_set_target_authentication_req_t *)p);
29275a17f3cSagc 		break;
29375a17f3cSagc 
29475a17f3cSagc 	case ISCSID_SLP_FIND_TARGETS:
29575a17f3cSagc 		rsp->status = ISCSID_STATUS_NOTIMPL;
29675a17f3cSagc 		break;
29775a17f3cSagc 
29875a17f3cSagc 	case ISCSID_REFRESH_TARGETS:
29975a17f3cSagc 		if (req->parameter_length < sizeof(iscsid_refresh_req_t)) {
30075a17f3cSagc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
30175a17f3cSagc 			break;
30275a17f3cSagc 		}
303f7720048Schristos 		rsp->status = refresh_targets((iscsid_refresh_req_t *)p);
30475a17f3cSagc 		break;
30575a17f3cSagc 
30675a17f3cSagc 	case ISCSID_REMOVE_TARGET:
30775a17f3cSagc 		if (req->parameter_length != sizeof(iscsid_list_id_t)) {
30875a17f3cSagc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
30975a17f3cSagc 			break;
31075a17f3cSagc 		}
311f7720048Schristos 		rsp->status = remove_target((iscsid_list_id_t *)p);
31275a17f3cSagc 		break;
31375a17f3cSagc 
31475a17f3cSagc 	case ISCSID_SEARCH_LIST:
31575a17f3cSagc 		if (req->parameter_length != sizeof(iscsid_search_list_req_t)) {
31675a17f3cSagc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
31775a17f3cSagc 			break;
31875a17f3cSagc 		}
319f7720048Schristos 		search_list((iscsid_search_list_req_t *)p, prsp, prsp_temp);
32075a17f3cSagc 		break;
32175a17f3cSagc 
32275a17f3cSagc 	case ISCSID_GET_LIST:
32375a17f3cSagc 		if (req->parameter_length != sizeof(iscsid_get_list_req_t)) {
32475a17f3cSagc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
32575a17f3cSagc 			break;
32675a17f3cSagc 		}
327f7720048Schristos 		get_list((iscsid_get_list_req_t *)p, prsp, prsp_temp);
32875a17f3cSagc 		break;
32975a17f3cSagc 
33075a17f3cSagc 	case ISCSID_GET_TARGET_INFO:
33175a17f3cSagc 		if (req->parameter_length != sizeof(iscsid_list_id_t)) {
33275a17f3cSagc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
33375a17f3cSagc 			break;
33475a17f3cSagc 		}
335f7720048Schristos 		get_target_info((iscsid_list_id_t *)p, prsp, prsp_temp);
33675a17f3cSagc 		break;
33775a17f3cSagc 
33875a17f3cSagc 	case ISCSID_GET_PORTAL_INFO:
33975a17f3cSagc 		if (req->parameter_length != sizeof(iscsid_list_id_t)) {
34075a17f3cSagc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
34175a17f3cSagc 			break;
34275a17f3cSagc 		}
343f7720048Schristos 		get_portal_info((iscsid_list_id_t *)p, prsp, prsp_temp);
34475a17f3cSagc 		break;
34575a17f3cSagc 
34675a17f3cSagc #ifndef ISCSI_MINIMAL
34775a17f3cSagc 	case ISCSID_ADD_ISNS_SERVER:
34875a17f3cSagc 		if (req->parameter_length != sizeof(iscsid_add_isns_server_req_t)) {
34975a17f3cSagc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
35075a17f3cSagc 			break;
35175a17f3cSagc 		}
352f7720048Schristos 		add_isns_server((iscsid_add_isns_server_req_t *)p,
35375a17f3cSagc 						prsp, prsp_temp);
35475a17f3cSagc 		break;
35575a17f3cSagc 
35675a17f3cSagc 	case ISCSID_GET_ISNS_SERVER:
35775a17f3cSagc 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
35875a17f3cSagc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
35975a17f3cSagc 			break;
36075a17f3cSagc 		}
361f7720048Schristos 		get_isns_server((iscsid_sym_id_t *)p, prsp, prsp_temp);
36275a17f3cSagc 		break;
36375a17f3cSagc 
36475a17f3cSagc 	case ISCSID_SLP_FIND_ISNS_SERVERS:
36575a17f3cSagc 		rsp->status = ISCSID_STATUS_NOTIMPL;
36675a17f3cSagc 		break;
36775a17f3cSagc 
36875a17f3cSagc 	case ISCSID_REMOVE_ISNS_SERVER:
36975a17f3cSagc 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
37075a17f3cSagc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
37175a17f3cSagc 			break;
37275a17f3cSagc 		}
373f7720048Schristos 		rsp->status = remove_isns_server((iscsid_sym_id_t *)p);
37475a17f3cSagc 		break;
37575a17f3cSagc #endif
37675a17f3cSagc 
37775a17f3cSagc 	case ISCSID_ADD_INITIATOR_PORTAL:
37875a17f3cSagc 		if (req->parameter_length != sizeof(iscsid_add_initiator_req_t)) {
37975a17f3cSagc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
38075a17f3cSagc 			break;
38175a17f3cSagc 		}
382f7720048Schristos 		add_initiator_portal((iscsid_add_initiator_req_t *)p,
38375a17f3cSagc 							prsp, prsp_temp);
38475a17f3cSagc 		break;
38575a17f3cSagc 
38675a17f3cSagc 	case ISCSID_GET_INITIATOR_PORTAL:
38775a17f3cSagc 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
38875a17f3cSagc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
38975a17f3cSagc 			break;
39075a17f3cSagc 		}
391f7720048Schristos 		get_initiator_portal((iscsid_sym_id_t *)p, prsp, prsp_temp);
39275a17f3cSagc 		break;
39375a17f3cSagc 
39475a17f3cSagc 	case ISCSID_REMOVE_INITIATOR_PORTAL:
39575a17f3cSagc 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
39675a17f3cSagc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
39775a17f3cSagc 			break;
39875a17f3cSagc 		}
399f7720048Schristos 		rsp->status = remove_initiator_portal((iscsid_sym_id_t *)p);
40075a17f3cSagc 		break;
40175a17f3cSagc 
40275a17f3cSagc 	case ISCSID_LOGIN:
40375a17f3cSagc 		if (req->parameter_length != sizeof(iscsid_login_req_t)) {
40475a17f3cSagc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
40575a17f3cSagc 			break;
40675a17f3cSagc 		}
4076fea88c2Smlelstv 		log_in((iscsid_login_req_t *)p, rsp);
40875a17f3cSagc 		break;
40975a17f3cSagc 
41075a17f3cSagc 	case ISCSID_ADD_CONNECTION:
41175a17f3cSagc 		if (req->parameter_length != sizeof(iscsid_login_req_t)) {
41275a17f3cSagc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
41375a17f3cSagc 			break;
41475a17f3cSagc 		}
415f7720048Schristos 		add_connection((iscsid_login_req_t *)p, rsp);
41675a17f3cSagc 		break;
41775a17f3cSagc 
41875a17f3cSagc 	case ISCSID_LOGOUT:
41975a17f3cSagc 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
42075a17f3cSagc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
42175a17f3cSagc 			break;
42275a17f3cSagc 		}
4236fea88c2Smlelstv 		rsp->status = log_out((iscsid_sym_id_t *)p);
42475a17f3cSagc 		break;
42575a17f3cSagc 
42675a17f3cSagc 	case ISCSID_REMOVE_CONNECTION:
42775a17f3cSagc 		if (req->parameter_length != sizeof(iscsid_remove_connection_req_t)) {
42875a17f3cSagc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
42975a17f3cSagc 			break;
43075a17f3cSagc 		}
431f7720048Schristos 		rsp->status = remove_connection((iscsid_remove_connection_req_t *)p);
43275a17f3cSagc 		break;
43375a17f3cSagc 
43475a17f3cSagc 	case ISCSID_GET_SESSION_LIST:
43575a17f3cSagc 		get_session_list(prsp, prsp_temp);
43675a17f3cSagc 		break;
43775a17f3cSagc 
43875a17f3cSagc 	case ISCSID_GET_CONNECTION_LIST:
43975a17f3cSagc 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
44075a17f3cSagc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
44175a17f3cSagc 			break;
44275a17f3cSagc 		}
443f7720048Schristos 		get_connection_list((iscsid_sym_id_t *)p, prsp, prsp_temp);
44475a17f3cSagc 		break;
44575a17f3cSagc 
44675a17f3cSagc 	case ISCSID_GET_CONNECTION_INFO:
44775a17f3cSagc 		if (req->parameter_length != sizeof(iscsid_get_connection_info_req_t)) {
44875a17f3cSagc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
44975a17f3cSagc 			break;
45075a17f3cSagc 		}
451f7720048Schristos 		get_connection_info((iscsid_get_connection_info_req_t *)p,
45275a17f3cSagc 							prsp, prsp_temp);
45375a17f3cSagc 		break;
45475a17f3cSagc 
45575a17f3cSagc 	case ISCSID_SET_NODE_NAME:
45675a17f3cSagc 		if (req->parameter_length != sizeof(iscsid_set_node_name_req_t)) {
45775a17f3cSagc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
45875a17f3cSagc 			break;
45975a17f3cSagc 		}
460f7720048Schristos 		rsp->status = set_node_name((iscsid_set_node_name_req_t *)p);
46175a17f3cSagc 		break;
46275a17f3cSagc 
46375a17f3cSagc 	case ISCSID_GET_VERSION:
46475a17f3cSagc 		get_version(prsp, prsp_temp);
46575a17f3cSagc 		break;
46675a17f3cSagc 
46775a17f3cSagc 	default:
46875a17f3cSagc 		rsp->status = ISCSID_STATUS_INVALID_REQUEST;
46975a17f3cSagc 		break;
47075a17f3cSagc 	}
47175a17f3cSagc }
47275a17f3cSagc 
4736fea88c2Smlelstv void
iscsid_log(const char * fmt,...)4746fea88c2Smlelstv iscsid_log(const char *fmt, ...)
4756fea88c2Smlelstv {
4766fea88c2Smlelstv 	va_list ap;
4776fea88c2Smlelstv 	va_start(ap, fmt);
4786fea88c2Smlelstv 	vsyslog(LOG_INFO, fmt, ap);
4796fea88c2Smlelstv 	va_end(ap);
4806fea88c2Smlelstv }
48175a17f3cSagc 
48275a17f3cSagc /*
48375a17f3cSagc  * exit_daemon:
48475a17f3cSagc  *    Deregister the event handler, deregister isns servers, then exit program.
48575a17f3cSagc  */
48675a17f3cSagc 
48744b25f2fSmlelstv static void __dead
exit_daemon(void)48875a17f3cSagc exit_daemon(void)
48975a17f3cSagc {
49075a17f3cSagc 	LOCK_SESSIONS;
49175a17f3cSagc 	deregister_event_handler();
49275a17f3cSagc 
49375a17f3cSagc #ifndef ISCSI_MINIMAL
49475a17f3cSagc 	dereg_all_isns_servers();
49575a17f3cSagc #endif
49675a17f3cSagc 	exit(0);
49775a17f3cSagc }
49875a17f3cSagc 
4996fea88c2Smlelstv static void
handler_exit(void)5006fea88c2Smlelstv handler_exit(void)
5016fea88c2Smlelstv {
5026fea88c2Smlelstv 	pthread_kill(main_thread, SIGINT);
5036fea88c2Smlelstv }
5046fea88c2Smlelstv 
5056fea88c2Smlelstv static void
sighandler(int sig)5066fea88c2Smlelstv sighandler(int sig)
5076fea88c2Smlelstv {
5086fea88c2Smlelstv }
50975a17f3cSagc 
51075a17f3cSagc /*
51175a17f3cSagc  * main:
51275a17f3cSagc  *    init, go daemon, then loop reading requests, processing them,
51375a17f3cSagc  *    and sending responses.
51475a17f3cSagc  *    Stops on receiving a terminate message (no response to that one is sent),
51575a17f3cSagc  *    or when an error occurs reading or writing the socket.
51675a17f3cSagc  *
51775a17f3cSagc  *    Parameter:  argc, argv currently ignored.
51875a17f3cSagc  */
51975a17f3cSagc 
52075a17f3cSagc int
521f7720048Schristos /*ARGSUSED*/
main(int argc,char ** argv)52275a17f3cSagc main(int argc, char **argv)
52375a17f3cSagc {
52468a964c3Schristos 	int req_temp, rsp_temp, c;
525f7720048Schristos 	ssize_t ret;
526f7720048Schristos 	size_t len;
52775a17f3cSagc 	struct sockaddr_un from;
52875a17f3cSagc 	socklen_t fromlen;
52975a17f3cSagc 	iscsid_request_t *req;
53075a17f3cSagc 	iscsid_response_t *rsp;
531c08d1e52Sriz 	char *p;
5326fea88c2Smlelstv 	struct sigaction sa;
533c08d1e52Sriz 
5346fea88c2Smlelstv 	while ((c = getopt(argc, argv, "Dd:")) != -1)
535c08d1e52Sriz 		switch (c) {
5366fea88c2Smlelstv 		case 'D':
5376fea88c2Smlelstv 			debugging++;
538c08d1e52Sriz 			break;
539c08d1e52Sriz 		case 'd':
540c08d1e52Sriz 			debug_level=(int)strtol(optarg, &p, 10);
541c08d1e52Sriz 			if (*p)
5426fea88c2Smlelstv 				errx(EXIT_FAILURE, "illegal log level -- %s",
543c08d1e52Sriz 				    optarg);
544c08d1e52Sriz 			break;
545c08d1e52Sriz 		default:
546c08d1e52Sriz 			usage();
547c08d1e52Sriz 		}
54875a17f3cSagc 
5496fea88c2Smlelstv 	openlog("iscsid", (debugging ? LOG_PERROR : 0) | LOG_PID, LOG_DAEMON);
5506fea88c2Smlelstv 
55175a17f3cSagc 	client_sock = init_daemon();
55275a17f3cSagc 	if (client_sock < 0)
55375a17f3cSagc 		exit(1);
55475a17f3cSagc 
5556fea88c2Smlelstv 	DEBOUT(("iSCSI daemon loaded"));
55675a17f3cSagc 
5576fea88c2Smlelstv 	if (!debugging) {
5586fea88c2Smlelstv 		if (daemon(0, 1) < 0)
5596fea88c2Smlelstv 			err(EXIT_FAILURE, "daemon() failed");
5606fea88c2Smlelstv 		pidfile(NULL);
5616fea88c2Smlelstv 	}
56275a17f3cSagc 
5636fea88c2Smlelstv 	memset(&sa, 0, sizeof(sa));
5646fea88c2Smlelstv 	sa.sa_handler = sighandler;
5656fea88c2Smlelstv 	sigaction(SIGINT, &sa, NULL);
5666fea88c2Smlelstv 	sigaction(SIGTERM, &sa, NULL);
5676fea88c2Smlelstv 
5686fea88c2Smlelstv 	main_thread = pthread_self();
5696fea88c2Smlelstv 	ret = pthread_create(&event_thread, NULL, event_handler, handler_exit);
57075a17f3cSagc 	if (ret) {
571f7720048Schristos 		printf("Thread creation failed (%zd)\n", ret);
57275a17f3cSagc 		close(client_sock);
57375a17f3cSagc 		unlink(ISCSID_SOCK_NAME);
57475a17f3cSagc 		deregister_event_handler();
57575a17f3cSagc 		pthread_mutex_destroy(&sesslist_lock);
57675a17f3cSagc 		return -1;
57775a17f3cSagc 	}
57875a17f3cSagc 
57975a17f3cSagc     /* ---------------------------------------------------------------------- */
58075a17f3cSagc 
58175a17f3cSagc 	for (;;) {
5826fea88c2Smlelstv 
58375a17f3cSagc 		/* First, get size of request */
584f7720048Schristos 		req = (iscsid_request_t *)(void *)req_buf;
58575a17f3cSagc 		fromlen = sizeof(from);
58675a17f3cSagc 		len = sizeof(iscsid_request_t);
58775a17f3cSagc 
58875a17f3cSagc 		do {
589f547f456Schristos 			ret = recvfrom(client_sock, req, len, MSG_PEEK |
590f547f456Schristos 			    MSG_WAITALL, (struct sockaddr *) &from,
591f547f456Schristos 			    &fromlen);
59275a17f3cSagc 		} while (ret == -1 && errno == EAGAIN);
59375a17f3cSagc 
594f7720048Schristos 		if ((size_t)ret != len) {
5956fea88c2Smlelstv 			DEBOUT(("Receiving from socket: %s",strerror(errno)));
59675a17f3cSagc 			break;
59775a17f3cSagc 		}
5986fea88c2Smlelstv 		DEB(2, ("Request %d, parlen %d",
59975a17f3cSagc 				req->request, req->parameter_length));
60075a17f3cSagc 
60175a17f3cSagc 		len += req->parameter_length;
60275a17f3cSagc 
60375a17f3cSagc 		/* now that we know the size, get the buffer for it */
60475a17f3cSagc 		req_temp = (len > REQ_BUFFER_SIZE);
60575a17f3cSagc 
60675a17f3cSagc 		if (req_temp) {
60775a17f3cSagc 			req = malloc(len);
60875a17f3cSagc 			if (!req) {
609f7720048Schristos 				printf("Can't alloc %zu bytes\n", len);
61075a17f3cSagc 				break;
61175a17f3cSagc 			}
61275a17f3cSagc 		}
61375a17f3cSagc 		/* read the complete request */
61475a17f3cSagc 		fromlen = sizeof(from);
61575a17f3cSagc 		ret = recvfrom(client_sock, req, len, MSG_WAITALL,
616f7720048Schristos 						(struct sockaddr *)(void *)&from, &fromlen);
617f7720048Schristos 		if ((size_t)ret != len) {
6186fea88c2Smlelstv 			DEB(2, ("Error receiving from socket!"));
61975a17f3cSagc 			if (req_temp)
62075a17f3cSagc 				free(req);
62175a17f3cSagc 			continue;
62275a17f3cSagc 		}
62375a17f3cSagc 		/* terminate? then go die. */
62475a17f3cSagc 		if (req->request == ISCSID_DAEMON_TERMINATE)
62575a17f3cSagc 			break;
62675a17f3cSagc 
62775a17f3cSagc 		/* No reply required to test message */
62875a17f3cSagc 		if (req->request == ISCSID_DAEMON_TEST) {
62975a17f3cSagc 			if (req_temp)
63075a17f3cSagc 				free(req);
6316fea88c2Smlelstv 			DEB(2, ("Test message!"));
63275a17f3cSagc 			continue;
63375a17f3cSagc 		}
63475a17f3cSagc 		/* no return path? then we can't send a reply, */
63575a17f3cSagc 		/* so don't process the command */
63675a17f3cSagc 		if (!from.sun_path[0]) {
6374fa33b60Smlelstv 			if (req_temp)
6384fa33b60Smlelstv 				free(req);
6396fea88c2Smlelstv 			DEB(2, ("No Return Address!"));
64075a17f3cSagc 			continue;
64175a17f3cSagc 		}
64275a17f3cSagc 		/* process the request */
64375a17f3cSagc 		process_message(req, &rsp, &rsp_temp);
6444fa33b60Smlelstv 		if (rsp == NULL) {
6454fa33b60Smlelstv 			if (req_temp)
6464fa33b60Smlelstv 				free(req);
6476fea88c2Smlelstv 			DEB(2, ("Invalid message!"));
6484fa33b60Smlelstv 			continue;
6494fa33b60Smlelstv 		}
65075a17f3cSagc 
6516fea88c2Smlelstv 		DEB(2, ("Sending reply: status %d, len %d",
65275a17f3cSagc 				rsp->status, rsp->parameter_length));
65375a17f3cSagc 
65475a17f3cSagc 		/* send the response */
65575a17f3cSagc 		len = sizeof(iscsid_response_t) + rsp->parameter_length;
65675a17f3cSagc 		ret = sendto(client_sock, rsp, len, 0,
657f7720048Schristos 					(struct sockaddr *)(void *)&from, fromlen);
658f7720048Schristos 		if (len != (size_t)ret) {
6596fea88c2Smlelstv 			DEB(2, ("Error sending reply!"));
66075a17f3cSagc 		}
66175a17f3cSagc 		/* free temp buffers if we needed them */
66275a17f3cSagc 		if (req_temp)
66375a17f3cSagc 			free(req);
66475a17f3cSagc 		if (rsp_temp)
66575a17f3cSagc 			free(rsp);
66675a17f3cSagc 	}
66775a17f3cSagc 
6686fea88c2Smlelstv 	pthread_join(event_thread, NULL);
6696fea88c2Smlelstv 
6706fea88c2Smlelstv 	DEBOUT(("Exiting daemon"));
6716fea88c2Smlelstv 
67275a17f3cSagc 	exit_daemon();
67375a17f3cSagc 
67475a17f3cSagc 	/* we never get here */
67575a17f3cSagc 	return 0;
67675a17f3cSagc }
677