Home | History | Annotate | Line # | Download | only in iscsid
      1  1.12       mrg /*	$NetBSD: iscsid_main.c,v 1.12 2019/02/04 08:21:12 mrg Exp $	*/
      2   1.1       agc 
      3   1.1       agc /*-
      4   1.1       agc  * Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc.
      5   1.1       agc  * All rights reserved.
      6   1.1       agc  *
      7   1.1       agc  * This code is derived from software contributed to The NetBSD Foundation
      8   1.1       agc  * by Wasabi Systems, Inc.
      9   1.1       agc  *
     10   1.1       agc  * Redistribution and use in source and binary forms, with or without
     11   1.1       agc  * modification, are permitted provided that the following conditions
     12   1.1       agc  * are met:
     13   1.1       agc  * 1. Redistributions of source code must retain the above copyright
     14   1.1       agc  *    notice, this list of conditions and the following disclaimer.
     15   1.1       agc  * 2. Redistributions in binary form must reproduce the above copyright
     16   1.1       agc  *    notice, this list of conditions and the following disclaimer in the
     17   1.1       agc  *    documentation and/or other materials provided with the distribution.
     18   1.1       agc  *
     19   1.1       agc  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20   1.1       agc  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21   1.1       agc  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22   1.1       agc  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23   1.1       agc  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24   1.1       agc  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25   1.1       agc  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26   1.1       agc  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27   1.1       agc  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28   1.1       agc  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29   1.1       agc  * POSSIBILITY OF SUCH DAMAGE.
     30   1.1       agc  */
     31   1.1       agc 
     32   1.1       agc #include "iscsid_globals.h"
     33   1.1       agc 
     34   1.1       agc #include <sys/types.h>
     35   1.1       agc #include <sys/socket.h>
     36   1.1       agc #include <sys/un.h>
     37   1.1       agc #include <sys/sysctl.h>
     38   1.1       agc 
     39   1.1       agc #include <ctype.h>
     40   1.7       riz #include <err.h>
     41   1.1       agc #include <fcntl.h>
     42  1.10   mlelstv #include <syslog.h>
     43  1.10   mlelstv #include <util.h>
     44   1.1       agc 
     45   1.1       agc #define DEVICE    "/dev/iscsi0"
     46   1.1       agc 
     47   1.1       agc /* -------------------------------------------------------------------------- */
     48   1.1       agc 
     49   1.1       agc list_head_t list[NUM_DAEMON_LISTS];	/* the lists this daemon keeps */
     50   1.1       agc 
     51   1.1       agc pthread_mutex_t sesslist_lock;	/* session list lock */
     52  1.10   mlelstv pthread_t main_thread;		/* main thread handle */
     53  1.10   mlelstv pthread_t event_thread;		/* event thread handle */
     54   1.1       agc 
     55  1.10   mlelstv int driver = -1;		/* the driver's file desc */
     56  1.10   mlelstv int client_sock;		/* the client communication socket */
     57   1.1       agc 
     58  1.10   mlelstv int debug_level;		/* How much info to display */
     59  1.10   mlelstv int debugging;
     60   1.1       agc 
     61   1.1       agc /*
     62   1.1       agc    To avoid memory fragmentation (and speed things up a bit), we use the
     63   1.1       agc    static bufs unless the request or response exceeds the buffer size
     64   1.1       agc    (which it normally shouldn't, assuming we don't have thousands
     65   1.1       agc    of list entries).
     66   1.1       agc */
     67   1.3       agc static uint8_t req_buf[REQ_BUFFER_SIZE];	/* default buffer for requests */
     68   1.3       agc static uint8_t rsp_buf[RSP_BUFFER_SIZE];	/* default buffer for responses */
     69   1.1       agc 
     70   1.1       agc /* -------------------------------------------------------------------------- */
     71   1.1       agc 
     72   1.4  christos static void __dead
     73   1.4  christos usage(void)
     74   1.4  christos {
     75   1.7       riz 	fprintf(stderr, "Usage: %s [-d <lvl>] [-n]\n", getprogname());
     76   1.4  christos 	exit(EXIT_FAILURE);
     77   1.4  christos }
     78   1.4  christos 
     79   1.1       agc /*
     80   1.1       agc  * create_node_name:
     81   1.1       agc  *    Create and set default node name.
     82   1.1       agc  *
     83   1.1       agc  *    Returns 0 on success, else an error code.
     84   1.1       agc  */
     85   1.1       agc 
     86   1.3       agc static int
     87   1.1       agc create_node_name(void)
     88   1.1       agc {
     89   1.1       agc 	iscsi_set_node_name_parameters_t snp;
     90   1.1       agc 	uint32_t hid = 0;
     91   1.1       agc 	size_t siz;
     92   1.1       agc 	int mib[2];
     93  1.12       mrg 	int total;
     94   1.1       agc 	unsigned char *s;
     95   1.1       agc 
     96   1.1       agc 	(void) memset(&snp, 0x0, sizeof(snp));
     97   1.1       agc 	mib[0] = CTL_KERN;
     98   1.1       agc 	mib[1] = KERN_HOSTID;
     99   1.1       agc 	siz = sizeof(hid);
    100   1.1       agc 	sysctl(mib, 2, &hid, &siz, NULL, 0);
    101   1.1       agc 	mib[1] = KERN_HOSTNAME;
    102   1.1       agc 	siz = ISCSI_STRING_LENGTH - 45;
    103   1.1       agc 	sysctl(mib, 2, snp.InitiatorAlias, &siz, NULL, 0);
    104   1.1       agc 
    105  1.10   mlelstv 	DEB(3, ("Host Name: <%s>, Host ID: %u", snp.InitiatorAlias, hid));
    106   1.1       agc 	if (!snp.InitiatorAlias[0]) {
    107   1.1       agc 		printf("Warning: iSCSI Node Name not set (No Host Name)!\n");
    108   1.1       agc 		return ISCSID_STATUS_NO_INITIATOR_NAME;
    109   1.1       agc 	}
    110   1.1       agc 	for (s = snp.InitiatorAlias; *s; s++)
    111   1.1       agc 		if (!isalnum((unsigned char) *s) && *s != '-' && *s != '.' && *s != ':')
    112   1.1       agc 			*s = '-';
    113  1.12       mrg 	total = snprintf((char *)snp.InitiatorName, sizeof(snp.InitiatorName),
    114   1.1       agc 		"iqn.1994-04.org.netbsd:iscsi.%s:%u", snp.InitiatorAlias, hid);
    115  1.12       mrg 	if ((size_t)total > sizeof(snp.InitiatorName)) {
    116  1.12       mrg 		printf("Warning: iSCSI Node InitiatorName too long to set InitiatorAlias!\n");
    117  1.12       mrg 		return ISCSID_STATUS_NO_INITIATOR_NAME;
    118  1.12       mrg 	}
    119   1.1       agc 
    120   1.1       agc 	ioctl(driver, ISCSI_SET_NODE_NAME, &snp);
    121   1.1       agc 	return snp.status;
    122   1.1       agc }
    123   1.1       agc 
    124   1.1       agc 
    125   1.1       agc /*
    126   1.1       agc  * init_daemon:
    127   1.1       agc  *    Open driver, create communication socket.
    128   1.1       agc  *
    129   1.1       agc  *    Returns:    <0 on error
    130   1.1       agc  */
    131   1.1       agc 
    132   1.3       agc static int
    133   1.1       agc init_daemon(void)
    134   1.1       agc {
    135   1.1       agc 	int sock, i;
    136   1.1       agc 	struct sockaddr_un name;
    137   1.1       agc 	iscsid_request_t req;
    138   1.1       agc 
    139   1.1       agc 	if ((driver = open(DEVICE, O_RDONLY)) < 0) {
    140   1.1       agc 		perror("opening " DEVICE);
    141   1.1       agc 		return -1;
    142   1.1       agc 	}
    143   1.1       agc 
    144   1.1       agc 	sock = socket(AF_UNIX, SOCK_DGRAM, 0);
    145   1.1       agc 	if (sock < 0) {
    146   1.1       agc 		perror("opening datagram socket");
    147   1.1       agc 		return -1;
    148   1.1       agc 	}
    149   1.1       agc 
    150   1.1       agc 	name.sun_family = AF_UNIX;
    151   1.1       agc 	strlcpy(name.sun_path, ISCSID_SOCK_NAME, sizeof(name.sun_path));
    152   1.1       agc 
    153   1.1       agc 	req.request = ISCSID_DAEMON_TEST;
    154   1.1       agc 	req.parameter_length = 0;
    155   1.1       agc 
    156   1.2  christos 	i = sendto(sock, &req, sizeof(req), 0, (struct sockaddr *)(void *)&name,
    157   1.2  christos 				(socklen_t)sizeof(struct sockaddr_un));
    158   1.1       agc 	if (i == sizeof(req)) {
    159   1.1       agc 		printf("Daemon already loaded!\n");
    160   1.1       agc 		close(sock);
    161   1.1       agc 		return -1;
    162   1.1       agc 	}
    163   1.1       agc 
    164   1.1       agc 	unlink(ISCSID_SOCK_NAME);
    165   1.2  christos 	if (bind(sock, (struct sockaddr *)(void *)&name, (socklen_t)sizeof(struct sockaddr_un))) {
    166   1.1       agc 		perror("binding name to socket");
    167   1.1       agc 		return -1;
    168   1.1       agc 	}
    169   1.1       agc 
    170   1.1       agc 	for (i = 0; i < NUM_DAEMON_LISTS; i++) {
    171   1.1       agc 		TAILQ_INIT(&list[i].list);
    172   1.1       agc 		list[i].num_entries = 0;
    173   1.1       agc 	}
    174   1.1       agc 
    175  1.10   mlelstv 	if ((i = pthread_mutex_init(&sesslist_lock, NULL)) != 0) {
    176   1.1       agc 		printf("Mutex init failed (%d)\n", i);
    177   1.1       agc 		close(sock);
    178   1.1       agc 		return -1;
    179   1.1       agc 	}
    180   1.1       agc 
    181   1.1       agc 	if (!register_event_handler()) {
    182   1.1       agc 		printf("Couldn't register event handler\n");
    183   1.1       agc 		close(sock);
    184   1.1       agc 		unlink(ISCSID_SOCK_NAME);
    185  1.10   mlelstv 		pthread_mutex_destroy(&sesslist_lock);
    186   1.1       agc 		return -1;
    187   1.1       agc 	}
    188   1.1       agc 
    189   1.1       agc 	create_node_name();
    190   1.1       agc 
    191   1.1       agc 	return sock;
    192   1.1       agc }
    193   1.1       agc 
    194   1.1       agc 
    195   1.1       agc /*
    196   1.1       agc  * make_rsp:
    197   1.1       agc  *    Allocate a response buffer if the static buffer is insufficient, set
    198   1.1       agc  *    the response parameter length.
    199   1.1       agc  *
    200   1.1       agc  *    Parameter:
    201   1.1       agc  *          len         Response parameter size (not counting header)
    202   1.1       agc  *          prsp        Pointer to address of response buffer
    203   1.1       agc  *          prsp_temp   Will be set to TRUE if buffer was allocated, FALSE
    204   1.1       agc  *                      for static buffer.
    205   1.1       agc  *
    206   1.1       agc  *    Returns:    Pointer to response buffer, NULL if allocation failed.
    207   1.1       agc  */
    208   1.1       agc 
    209   1.1       agc iscsid_response_t *
    210   1.2  christos make_rsp(size_t len, iscsid_response_t ** prsp, int *prsp_temp)
    211   1.1       agc {
    212   1.1       agc 	iscsid_response_t *rsp;
    213   1.1       agc 
    214   1.1       agc 	if ((len + sizeof(iscsid_response_t)) > RSP_BUFFER_SIZE) {
    215   1.1       agc 		if ((rsp = calloc(1, len)) == NULL) {
    216   1.1       agc 			(*prsp)->status = ISCSID_STATUS_NO_RESOURCES;
    217   1.1       agc 			return NULL;
    218   1.1       agc 		}
    219   1.1       agc 		*prsp_temp = TRUE;
    220   1.1       agc 		*prsp = rsp;
    221   1.1       agc 	} else
    222   1.1       agc 		rsp = *prsp;
    223   1.1       agc 
    224   1.1       agc 	memset (rsp, 0, len + sizeof(iscsid_response_t));
    225   1.2  christos 	rsp->parameter_length = (uint32_t)len;
    226   1.1       agc 	return rsp;
    227   1.1       agc }
    228   1.1       agc 
    229   1.1       agc 
    230   1.1       agc /*
    231   1.1       agc  * process_message:
    232   1.1       agc  *    minimal parameter check and dispatch for the daemon functions.
    233   1.1       agc  *
    234   1.1       agc  *    Parameter:
    235   1.1       agc  *          req         The request
    236   1.1       agc  *          prsp        Pointer to address of response buffer
    237   1.1       agc  *          prsp_temp   Will be set to TRUE if buffer was allocated, FALSE
    238   1.1       agc  *                      for static buffer.
    239   1.1       agc  */
    240   1.1       agc 
    241   1.3       agc static void
    242   1.1       agc process_message(iscsid_request_t *req, iscsid_response_t **prsp, int *prsp_temp)
    243   1.1       agc {
    244   1.1       agc 	iscsid_response_t *rsp;
    245   1.2  christos 	void *p = req->parameter;
    246   1.1       agc 
    247   1.1       agc 	*prsp_temp = FALSE;
    248   1.2  christos 	*prsp = rsp = (iscsid_response_t *)(void *)rsp_buf;
    249   1.1       agc 	rsp->parameter_length = 0;
    250   1.1       agc 	rsp->status = ISCSID_STATUS_SUCCESS;
    251   1.1       agc 
    252   1.1       agc 	switch (req->request) {
    253   1.1       agc 	case ISCSID_ADD_TARGET:
    254   1.1       agc 		if (req->parameter_length < sizeof(iscsid_add_target_req_t)) {
    255   1.1       agc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    256   1.1       agc 			break;
    257   1.1       agc 		}
    258   1.2  christos 		add_target((iscsid_add_target_req_t *)p, prsp, prsp_temp);
    259   1.1       agc 		break;
    260   1.1       agc 
    261   1.1       agc 	case ISCSID_ADD_PORTAL:
    262   1.1       agc 		if (req->parameter_length != sizeof(iscsid_add_portal_req_t)) {
    263   1.1       agc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    264   1.1       agc 			break;
    265   1.1       agc 		}
    266   1.2  christos 		add_portal((iscsid_add_portal_req_t *)p, prsp, prsp_temp);
    267   1.1       agc 		break;
    268   1.1       agc 
    269   1.1       agc 	case ISCSID_SET_TARGET_OPTIONS:
    270   1.1       agc 		if (req->parameter_length != sizeof(iscsid_get_set_target_options_t)) {
    271   1.1       agc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    272   1.1       agc 			break;
    273   1.1       agc 		}
    274   1.2  christos 		rsp->status = set_target_options((iscsid_get_set_target_options_t *)p);
    275   1.1       agc 		break;
    276   1.1       agc 
    277   1.1       agc 	case ISCSID_GET_TARGET_OPTIONS:
    278   1.1       agc 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
    279   1.1       agc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    280   1.1       agc 			break;
    281   1.1       agc 		}
    282   1.1       agc 		rsp->status = ISCSID_STATUS_NOTIMPL;
    283   1.1       agc 		break;
    284   1.1       agc 
    285   1.1       agc 	case ISCSID_SET_TARGET_AUTHENTICATION:
    286   1.1       agc 		if (req->parameter_length !=
    287   1.1       agc 			sizeof(iscsid_set_target_authentication_req_t)) {
    288   1.1       agc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    289   1.1       agc 			break;
    290   1.1       agc 		}
    291   1.2  christos 		rsp->status = set_target_auth((iscsid_set_target_authentication_req_t *)p);
    292   1.1       agc 		break;
    293   1.1       agc 
    294   1.1       agc 	case ISCSID_SLP_FIND_TARGETS:
    295   1.1       agc 		rsp->status = ISCSID_STATUS_NOTIMPL;
    296   1.1       agc 		break;
    297   1.1       agc 
    298   1.1       agc 	case ISCSID_REFRESH_TARGETS:
    299   1.1       agc 		if (req->parameter_length < sizeof(iscsid_refresh_req_t)) {
    300   1.1       agc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    301   1.1       agc 			break;
    302   1.1       agc 		}
    303   1.2  christos 		rsp->status = refresh_targets((iscsid_refresh_req_t *)p);
    304   1.1       agc 		break;
    305   1.1       agc 
    306   1.1       agc 	case ISCSID_REMOVE_TARGET:
    307   1.1       agc 		if (req->parameter_length != sizeof(iscsid_list_id_t)) {
    308   1.1       agc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    309   1.1       agc 			break;
    310   1.1       agc 		}
    311   1.2  christos 		rsp->status = remove_target((iscsid_list_id_t *)p);
    312   1.1       agc 		break;
    313   1.1       agc 
    314   1.1       agc 	case ISCSID_SEARCH_LIST:
    315   1.1       agc 		if (req->parameter_length != sizeof(iscsid_search_list_req_t)) {
    316   1.1       agc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    317   1.1       agc 			break;
    318   1.1       agc 		}
    319   1.2  christos 		search_list((iscsid_search_list_req_t *)p, prsp, prsp_temp);
    320   1.1       agc 		break;
    321   1.1       agc 
    322   1.1       agc 	case ISCSID_GET_LIST:
    323   1.1       agc 		if (req->parameter_length != sizeof(iscsid_get_list_req_t)) {
    324   1.1       agc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    325   1.1       agc 			break;
    326   1.1       agc 		}
    327   1.2  christos 		get_list((iscsid_get_list_req_t *)p, prsp, prsp_temp);
    328   1.1       agc 		break;
    329   1.1       agc 
    330   1.1       agc 	case ISCSID_GET_TARGET_INFO:
    331   1.1       agc 		if (req->parameter_length != sizeof(iscsid_list_id_t)) {
    332   1.1       agc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    333   1.1       agc 			break;
    334   1.1       agc 		}
    335   1.2  christos 		get_target_info((iscsid_list_id_t *)p, prsp, prsp_temp);
    336   1.1       agc 		break;
    337   1.1       agc 
    338   1.1       agc 	case ISCSID_GET_PORTAL_INFO:
    339   1.1       agc 		if (req->parameter_length != sizeof(iscsid_list_id_t)) {
    340   1.1       agc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    341   1.1       agc 			break;
    342   1.1       agc 		}
    343   1.2  christos 		get_portal_info((iscsid_list_id_t *)p, prsp, prsp_temp);
    344   1.1       agc 		break;
    345   1.1       agc 
    346   1.1       agc #ifndef ISCSI_MINIMAL
    347   1.1       agc 	case ISCSID_ADD_ISNS_SERVER:
    348   1.1       agc 		if (req->parameter_length != sizeof(iscsid_add_isns_server_req_t)) {
    349   1.1       agc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    350   1.1       agc 			break;
    351   1.1       agc 		}
    352   1.2  christos 		add_isns_server((iscsid_add_isns_server_req_t *)p,
    353   1.1       agc 						prsp, prsp_temp);
    354   1.1       agc 		break;
    355   1.1       agc 
    356   1.1       agc 	case ISCSID_GET_ISNS_SERVER:
    357   1.1       agc 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
    358   1.1       agc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    359   1.1       agc 			break;
    360   1.1       agc 		}
    361   1.2  christos 		get_isns_server((iscsid_sym_id_t *)p, prsp, prsp_temp);
    362   1.1       agc 		break;
    363   1.1       agc 
    364   1.1       agc 	case ISCSID_SLP_FIND_ISNS_SERVERS:
    365   1.1       agc 		rsp->status = ISCSID_STATUS_NOTIMPL;
    366   1.1       agc 		break;
    367   1.1       agc 
    368   1.1       agc 	case ISCSID_REMOVE_ISNS_SERVER:
    369   1.1       agc 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
    370   1.1       agc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    371   1.1       agc 			break;
    372   1.1       agc 		}
    373   1.2  christos 		rsp->status = remove_isns_server((iscsid_sym_id_t *)p);
    374   1.1       agc 		break;
    375   1.1       agc #endif
    376   1.1       agc 
    377   1.1       agc 	case ISCSID_ADD_INITIATOR_PORTAL:
    378   1.1       agc 		if (req->parameter_length != sizeof(iscsid_add_initiator_req_t)) {
    379   1.1       agc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    380   1.1       agc 			break;
    381   1.1       agc 		}
    382   1.2  christos 		add_initiator_portal((iscsid_add_initiator_req_t *)p,
    383   1.1       agc 							prsp, prsp_temp);
    384   1.1       agc 		break;
    385   1.1       agc 
    386   1.1       agc 	case ISCSID_GET_INITIATOR_PORTAL:
    387   1.1       agc 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
    388   1.1       agc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    389   1.1       agc 			break;
    390   1.1       agc 		}
    391   1.2  christos 		get_initiator_portal((iscsid_sym_id_t *)p, prsp, prsp_temp);
    392   1.1       agc 		break;
    393   1.1       agc 
    394   1.1       agc 	case ISCSID_REMOVE_INITIATOR_PORTAL:
    395   1.1       agc 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
    396   1.1       agc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    397   1.1       agc 			break;
    398   1.1       agc 		}
    399   1.2  christos 		rsp->status = remove_initiator_portal((iscsid_sym_id_t *)p);
    400   1.1       agc 		break;
    401   1.1       agc 
    402   1.1       agc 	case ISCSID_LOGIN:
    403   1.1       agc 		if (req->parameter_length != sizeof(iscsid_login_req_t)) {
    404   1.1       agc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    405   1.1       agc 			break;
    406   1.1       agc 		}
    407  1.10   mlelstv 		log_in((iscsid_login_req_t *)p, rsp);
    408   1.1       agc 		break;
    409   1.1       agc 
    410   1.1       agc 	case ISCSID_ADD_CONNECTION:
    411   1.1       agc 		if (req->parameter_length != sizeof(iscsid_login_req_t)) {
    412   1.1       agc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    413   1.1       agc 			break;
    414   1.1       agc 		}
    415   1.2  christos 		add_connection((iscsid_login_req_t *)p, rsp);
    416   1.1       agc 		break;
    417   1.1       agc 
    418   1.1       agc 	case ISCSID_LOGOUT:
    419   1.1       agc 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
    420   1.1       agc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    421   1.1       agc 			break;
    422   1.1       agc 		}
    423  1.10   mlelstv 		rsp->status = log_out((iscsid_sym_id_t *)p);
    424   1.1       agc 		break;
    425   1.1       agc 
    426   1.1       agc 	case ISCSID_REMOVE_CONNECTION:
    427   1.1       agc 		if (req->parameter_length != sizeof(iscsid_remove_connection_req_t)) {
    428   1.1       agc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    429   1.1       agc 			break;
    430   1.1       agc 		}
    431   1.2  christos 		rsp->status = remove_connection((iscsid_remove_connection_req_t *)p);
    432   1.1       agc 		break;
    433   1.1       agc 
    434   1.1       agc 	case ISCSID_GET_SESSION_LIST:
    435   1.1       agc 		get_session_list(prsp, prsp_temp);
    436   1.1       agc 		break;
    437   1.1       agc 
    438   1.1       agc 	case ISCSID_GET_CONNECTION_LIST:
    439   1.1       agc 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
    440   1.1       agc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    441   1.1       agc 			break;
    442   1.1       agc 		}
    443   1.2  christos 		get_connection_list((iscsid_sym_id_t *)p, prsp, prsp_temp);
    444   1.1       agc 		break;
    445   1.1       agc 
    446   1.1       agc 	case ISCSID_GET_CONNECTION_INFO:
    447   1.1       agc 		if (req->parameter_length != sizeof(iscsid_get_connection_info_req_t)) {
    448   1.1       agc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    449   1.1       agc 			break;
    450   1.1       agc 		}
    451   1.2  christos 		get_connection_info((iscsid_get_connection_info_req_t *)p,
    452   1.1       agc 							prsp, prsp_temp);
    453   1.1       agc 		break;
    454   1.1       agc 
    455   1.1       agc 	case ISCSID_SET_NODE_NAME:
    456   1.1       agc 		if (req->parameter_length != sizeof(iscsid_set_node_name_req_t)) {
    457   1.1       agc 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    458   1.1       agc 			break;
    459   1.1       agc 		}
    460   1.2  christos 		rsp->status = set_node_name((iscsid_set_node_name_req_t *)p);
    461   1.1       agc 		break;
    462   1.1       agc 
    463   1.1       agc 	case ISCSID_GET_VERSION:
    464   1.1       agc 		get_version(prsp, prsp_temp);
    465   1.1       agc 		break;
    466   1.1       agc 
    467   1.1       agc 	default:
    468   1.1       agc 		rsp->status = ISCSID_STATUS_INVALID_REQUEST;
    469   1.1       agc 		break;
    470   1.1       agc 	}
    471   1.1       agc }
    472   1.1       agc 
    473  1.10   mlelstv void
    474  1.10   mlelstv iscsid_log(const char *fmt, ...)
    475  1.10   mlelstv {
    476  1.10   mlelstv 	va_list ap;
    477  1.10   mlelstv 	va_start(ap, fmt);
    478  1.10   mlelstv 	vsyslog(LOG_INFO, fmt, ap);
    479  1.10   mlelstv 	va_end(ap);
    480  1.10   mlelstv }
    481   1.1       agc 
    482   1.1       agc /*
    483   1.1       agc  * exit_daemon:
    484   1.1       agc  *    Deregister the event handler, deregister isns servers, then exit program.
    485   1.1       agc  */
    486   1.1       agc 
    487  1.11   mlelstv static void __dead
    488   1.1       agc exit_daemon(void)
    489   1.1       agc {
    490   1.6       riz 	LOCK_SESSIONS;
    491   1.1       agc 	deregister_event_handler();
    492   1.1       agc 
    493   1.1       agc #ifndef ISCSI_MINIMAL
    494   1.1       agc 	dereg_all_isns_servers();
    495   1.1       agc #endif
    496   1.1       agc 	exit(0);
    497   1.1       agc }
    498   1.1       agc 
    499  1.10   mlelstv static void
    500  1.10   mlelstv handler_exit(void)
    501  1.10   mlelstv {
    502  1.10   mlelstv 	pthread_kill(main_thread, SIGINT);
    503  1.10   mlelstv }
    504  1.10   mlelstv 
    505  1.10   mlelstv static void
    506  1.10   mlelstv sighandler(int sig)
    507  1.10   mlelstv {
    508  1.10   mlelstv }
    509   1.1       agc 
    510   1.1       agc /*
    511   1.1       agc  * main:
    512   1.1       agc  *    init, go daemon, then loop reading requests, processing them,
    513   1.1       agc  *    and sending responses.
    514   1.1       agc  *    Stops on receiving a terminate message (no response to that one is sent),
    515   1.1       agc  *    or when an error occurs reading or writing the socket.
    516   1.1       agc  *
    517   1.1       agc  *    Parameter:  argc, argv currently ignored.
    518   1.1       agc  */
    519   1.1       agc 
    520   1.1       agc int
    521   1.2  christos /*ARGSUSED*/
    522   1.1       agc main(int argc, char **argv)
    523   1.1       agc {
    524   1.4  christos 	int req_temp, rsp_temp, c;
    525   1.2  christos 	ssize_t ret;
    526   1.2  christos 	size_t len;
    527   1.1       agc 	struct sockaddr_un from;
    528   1.1       agc 	socklen_t fromlen;
    529   1.1       agc 	iscsid_request_t *req;
    530   1.1       agc 	iscsid_response_t *rsp;
    531   1.7       riz 	char *p;
    532  1.10   mlelstv 	struct sigaction sa;
    533   1.1       agc 
    534  1.10   mlelstv 	while ((c = getopt(argc, argv, "Dd:")) != -1)
    535   1.4  christos 		switch (c) {
    536  1.10   mlelstv 		case 'D':
    537  1.10   mlelstv 			debugging++;
    538   1.5  christos 			break;
    539   1.4  christos 		case 'd':
    540   1.7       riz 			debug_level=(int)strtol(optarg, &p, 10);
    541   1.7       riz 			if (*p)
    542  1.10   mlelstv 				errx(EXIT_FAILURE, "illegal log level -- %s",
    543   1.7       riz 				    optarg);
    544   1.4  christos 			break;
    545   1.4  christos 		default:
    546   1.4  christos 			usage();
    547   1.4  christos 		}
    548   1.4  christos 
    549  1.10   mlelstv 	openlog("iscsid", (debugging ? LOG_PERROR : 0) | LOG_PID, LOG_DAEMON);
    550  1.10   mlelstv 
    551   1.7       riz 	client_sock = init_daemon();
    552   1.7       riz 	if (client_sock < 0)
    553   1.7       riz 		exit(1);
    554   1.7       riz 
    555  1.10   mlelstv 	DEBOUT(("iSCSI daemon loaded"));
    556   1.7       riz 
    557  1.10   mlelstv 	if (!debugging) {
    558  1.10   mlelstv 		if (daemon(0, 1) < 0)
    559  1.10   mlelstv 			err(EXIT_FAILURE, "daemon() failed");
    560  1.10   mlelstv 		pidfile(NULL);
    561  1.10   mlelstv 	}
    562  1.10   mlelstv 
    563  1.10   mlelstv 	memset(&sa, 0, sizeof(sa));
    564  1.10   mlelstv 	sa.sa_handler = sighandler;
    565  1.10   mlelstv 	sigaction(SIGINT, &sa, NULL);
    566  1.10   mlelstv 	sigaction(SIGTERM, &sa, NULL);
    567  1.10   mlelstv 
    568  1.10   mlelstv 	main_thread = pthread_self();
    569  1.10   mlelstv 	ret = pthread_create(&event_thread, NULL, event_handler, handler_exit);
    570  1.10   mlelstv 	if (ret) {
    571  1.10   mlelstv 		printf("Thread creation failed (%zd)\n", ret);
    572  1.10   mlelstv 		close(client_sock);
    573  1.10   mlelstv 		unlink(ISCSID_SOCK_NAME);
    574  1.10   mlelstv 		deregister_event_handler();
    575  1.10   mlelstv 		pthread_mutex_destroy(&sesslist_lock);
    576  1.10   mlelstv 		return -1;
    577   1.1       agc 	}
    578   1.1       agc 
    579   1.1       agc     /* ---------------------------------------------------------------------- */
    580   1.1       agc 
    581   1.1       agc 	for (;;) {
    582  1.10   mlelstv 
    583   1.1       agc 		/* First, get size of request */
    584   1.2  christos 		req = (iscsid_request_t *)(void *)req_buf;
    585   1.1       agc 		fromlen = sizeof(from);
    586   1.1       agc 		len = sizeof(iscsid_request_t);
    587   1.1       agc 
    588  1.10   mlelstv 		do {
    589  1.10   mlelstv 			ret = recvfrom(client_sock, req, len, MSG_PEEK |
    590  1.10   mlelstv 			    MSG_WAITALL, (struct sockaddr *) &from,
    591  1.10   mlelstv 			    &fromlen);
    592  1.10   mlelstv 		} while (ret == -1 && errno == EAGAIN);
    593   1.1       agc 
    594   1.2  christos 		if ((size_t)ret != len) {
    595  1.10   mlelstv 			DEBOUT(("Receiving from socket: %s",strerror(errno)));
    596   1.1       agc 			break;
    597   1.1       agc 		}
    598  1.10   mlelstv 		DEB(2, ("Request %d, parlen %d",
    599   1.1       agc 				req->request, req->parameter_length));
    600   1.1       agc 
    601   1.1       agc 		len += req->parameter_length;
    602   1.1       agc 
    603   1.1       agc 		/* now that we know the size, get the buffer for it */
    604   1.1       agc 		req_temp = (len > REQ_BUFFER_SIZE);
    605   1.1       agc 
    606   1.1       agc 		if (req_temp) {
    607   1.1       agc 			req = malloc(len);
    608   1.1       agc 			if (!req) {
    609   1.2  christos 				printf("Can't alloc %zu bytes\n", len);
    610   1.1       agc 				break;
    611   1.1       agc 			}
    612   1.1       agc 		}
    613   1.1       agc 		/* read the complete request */
    614   1.1       agc 		fromlen = sizeof(from);
    615   1.1       agc 		ret = recvfrom(client_sock, req, len, MSG_WAITALL,
    616   1.2  christos 						(struct sockaddr *)(void *)&from, &fromlen);
    617   1.2  christos 		if ((size_t)ret != len) {
    618  1.10   mlelstv 			DEB(2, ("Error receiving from socket!"));
    619   1.1       agc 			if (req_temp)
    620   1.1       agc 				free(req);
    621   1.1       agc 			continue;
    622   1.1       agc 		}
    623   1.1       agc 		/* terminate? then go die. */
    624   1.1       agc 		if (req->request == ISCSID_DAEMON_TERMINATE)
    625   1.1       agc 			break;
    626   1.1       agc 
    627   1.1       agc 		/* No reply required to test message */
    628   1.1       agc 		if (req->request == ISCSID_DAEMON_TEST) {
    629   1.1       agc 			if (req_temp)
    630   1.1       agc 				free(req);
    631  1.10   mlelstv 			DEB(2, ("Test message!"));
    632   1.1       agc 			continue;
    633   1.1       agc 		}
    634   1.1       agc 		/* no return path? then we can't send a reply, */
    635   1.1       agc 		/* so don't process the command */
    636   1.1       agc 		if (!from.sun_path[0]) {
    637   1.8   mlelstv 			if (req_temp)
    638   1.8   mlelstv 				free(req);
    639  1.10   mlelstv 			DEB(2, ("No Return Address!"));
    640   1.1       agc 			continue;
    641   1.1       agc 		}
    642   1.1       agc 		/* process the request */
    643   1.1       agc 		process_message(req, &rsp, &rsp_temp);
    644   1.8   mlelstv 		if (rsp == NULL) {
    645   1.8   mlelstv 			if (req_temp)
    646   1.8   mlelstv 				free(req);
    647  1.10   mlelstv 			DEB(2, ("Invalid message!"));
    648   1.8   mlelstv 			continue;
    649   1.8   mlelstv 		}
    650   1.1       agc 
    651  1.10   mlelstv 		DEB(2, ("Sending reply: status %d, len %d",
    652   1.1       agc 				rsp->status, rsp->parameter_length));
    653   1.1       agc 
    654   1.1       agc 		/* send the response */
    655   1.1       agc 		len = sizeof(iscsid_response_t) + rsp->parameter_length;
    656   1.1       agc 		ret = sendto(client_sock, rsp, len, 0,
    657   1.2  christos 					(struct sockaddr *)(void *)&from, fromlen);
    658   1.2  christos 		if (len != (size_t)ret) {
    659  1.10   mlelstv 			DEB(2, ("Error sending reply!"));
    660   1.1       agc 		}
    661   1.1       agc 		/* free temp buffers if we needed them */
    662   1.1       agc 		if (req_temp)
    663   1.1       agc 			free(req);
    664   1.1       agc 		if (rsp_temp)
    665   1.1       agc 			free(rsp);
    666   1.1       agc 	}
    667   1.1       agc 
    668  1.10   mlelstv 	pthread_join(event_thread, NULL);
    669  1.10   mlelstv 
    670  1.10   mlelstv 	DEBOUT(("Exiting daemon"));
    671  1.10   mlelstv 
    672   1.1       agc 	exit_daemon();
    673   1.1       agc 
    674   1.1       agc 	/* we never get here */
    675   1.1       agc 	return 0;
    676   1.1       agc }
    677