1255570Strasz/*-
2255570Strasz * Copyright (c) 2003, 2004 Silicon Graphics International Corp.
3255570Strasz * Copyright (c) 1997-2007 Kenneth D. Merry
4255570Strasz * Copyright (c) 2012 The FreeBSD Foundation
5255570Strasz * All rights reserved.
6255570Strasz *
7255570Strasz * Portions of this software were developed by Edward Tomasz Napierala
8255570Strasz * under sponsorship from the FreeBSD Foundation.
9255570Strasz *
10255570Strasz * Redistribution and use in source and binary forms, with or without
11255570Strasz * modification, are permitted provided that the following conditions
12255570Strasz * are met:
13255570Strasz * 1. Redistributions of source code must retain the above copyright
14255570Strasz *    notice, this list of conditions, and the following disclaimer,
15255570Strasz *    without modification.
16255570Strasz * 2. Redistributions in binary form must reproduce at minimum a disclaimer
17255570Strasz *    substantially similar to the "NO WARRANTY" disclaimer below
18255570Strasz *    ("Disclaimer") and any redistribution must be conditioned upon
19255570Strasz *    including a substantially similar Disclaimer requirement for further
20255570Strasz *    binary redistribution.
21255570Strasz *
22255570Strasz * NO WARRANTY
23255570Strasz * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24255570Strasz * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25255570Strasz * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
26255570Strasz * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27255570Strasz * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28255570Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29255570Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30255570Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31255570Strasz * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
32255570Strasz * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33255570Strasz * POSSIBILITY OF SUCH DAMAGES.
34255570Strasz *
35255570Strasz */
36255570Strasz
37270888Strasz#include <sys/cdefs.h>
38270888Strasz__FBSDID("$FreeBSD$");
39270888Strasz
40255570Strasz#include <sys/ioctl.h>
41255570Strasz#include <sys/types.h>
42255570Strasz#include <sys/stat.h>
43255570Strasz#include <sys/param.h>
44255570Strasz#include <sys/linker.h>
45255570Strasz#include <sys/queue.h>
46255570Strasz#include <sys/callout.h>
47255570Strasz#include <sys/sbuf.h>
48255570Strasz#include <sys/capability.h>
49255570Strasz#include <assert.h>
50255570Strasz#include <bsdxml.h>
51255570Strasz#include <ctype.h>
52255570Strasz#include <errno.h>
53255570Strasz#include <fcntl.h>
54255570Strasz#include <stdint.h>
55255570Strasz#include <stdio.h>
56255570Strasz#include <stdlib.h>
57255570Strasz#include <string.h>
58255570Strasz#include <strings.h>
59255570Strasz#include <cam/scsi/scsi_all.h>
60255570Strasz#include <cam/scsi/scsi_message.h>
61255570Strasz#include <cam/ctl/ctl.h>
62255570Strasz#include <cam/ctl/ctl_io.h>
63255570Strasz#include <cam/ctl/ctl_frontend_internal.h>
64255570Strasz#include <cam/ctl/ctl_backend.h>
65255570Strasz#include <cam/ctl/ctl_ioctl.h>
66255570Strasz#include <cam/ctl/ctl_backend_block.h>
67255570Strasz#include <cam/ctl/ctl_util.h>
68255570Strasz#include <cam/ctl/ctl_scsi_all.h>
69255570Strasz
70265507Strasz#include "ctld.h"
71265507Strasz
72255570Strasz#ifdef ICL_KERNEL_PROXY
73255570Strasz#include <netdb.h>
74255570Strasz#endif
75255570Strasz
76265507Straszextern bool proxy_mode;
77255570Strasz
78255570Straszstatic int	ctl_fd = 0;
79255570Strasz
80255570Straszvoid
81255570Straszkernel_init(void)
82255570Strasz{
83255570Strasz	int retval, saved_errno;
84255570Strasz
85255570Strasz	ctl_fd = open(CTL_DEFAULT_DEV, O_RDWR);
86255665Strasz	if (ctl_fd < 0 && errno == ENOENT) {
87255570Strasz		saved_errno = errno;
88255570Strasz		retval = kldload("ctl");
89255570Strasz		if (retval != -1)
90255570Strasz			ctl_fd = open(CTL_DEFAULT_DEV, O_RDWR);
91255570Strasz		else
92255570Strasz			errno = saved_errno;
93255570Strasz	}
94255570Strasz	if (ctl_fd < 0)
95255570Strasz		log_err(1, "failed to open %s", CTL_DEFAULT_DEV);
96255570Strasz}
97255570Strasz
98255570Strasz/*
99255570Strasz * Name/value pair used for per-LUN attributes.
100255570Strasz */
101255570Straszstruct cctl_lun_nv {
102255570Strasz	char *name;
103255570Strasz	char *value;
104255570Strasz	STAILQ_ENTRY(cctl_lun_nv) links;
105255570Strasz};
106255570Strasz
107255570Strasz/*
108255570Strasz * Backend LUN information.
109255570Strasz */
110255570Straszstruct cctl_lun {
111255570Strasz	uint64_t lun_id;
112255570Strasz	char *backend_type;
113255570Strasz	uint64_t size_blocks;
114255570Strasz	uint32_t blocksize;
115255570Strasz	char *serial_number;
116255570Strasz	char *device_id;
117255570Strasz	char *cfiscsi_target;
118255570Strasz	int cfiscsi_lun;
119255570Strasz	STAILQ_HEAD(,cctl_lun_nv) attr_list;
120255570Strasz	STAILQ_ENTRY(cctl_lun) links;
121255570Strasz};
122255570Strasz
123268682Smavstruct cctl_port {
124268682Smav	uint32_t port_id;
125268688Smav	int cfiscsi_status;
126268682Smav	char *cfiscsi_target;
127268682Smav	uint16_t cfiscsi_portal_group_tag;
128268682Smav	STAILQ_HEAD(,cctl_lun_nv) attr_list;
129268682Smav	STAILQ_ENTRY(cctl_port) links;
130268682Smav};
131268682Smav
132255570Straszstruct cctl_devlist_data {
133255570Strasz	int num_luns;
134255570Strasz	STAILQ_HEAD(,cctl_lun) lun_list;
135255570Strasz	struct cctl_lun *cur_lun;
136268682Smav	int num_ports;
137268682Smav	STAILQ_HEAD(,cctl_port) port_list;
138268682Smav	struct cctl_port *cur_port;
139255570Strasz	int level;
140255570Strasz	struct sbuf *cur_sb[32];
141255570Strasz};
142255570Strasz
143255570Straszstatic void
144255570Straszcctl_start_element(void *user_data, const char *name, const char **attr)
145255570Strasz{
146255570Strasz	int i;
147255570Strasz	struct cctl_devlist_data *devlist;
148255570Strasz	struct cctl_lun *cur_lun;
149255570Strasz
150255570Strasz	devlist = (struct cctl_devlist_data *)user_data;
151255570Strasz	cur_lun = devlist->cur_lun;
152255570Strasz	devlist->level++;
153256189Strasz	if ((u_int)devlist->level >= (sizeof(devlist->cur_sb) /
154255570Strasz	    sizeof(devlist->cur_sb[0])))
155255570Strasz		log_errx(1, "%s: too many nesting levels, %zd max", __func__,
156255570Strasz		     sizeof(devlist->cur_sb) / sizeof(devlist->cur_sb[0]));
157255570Strasz
158255570Strasz	devlist->cur_sb[devlist->level] = sbuf_new_auto();
159255570Strasz	if (devlist->cur_sb[devlist->level] == NULL)
160255570Strasz		log_err(1, "%s: unable to allocate sbuf", __func__);
161255570Strasz
162255570Strasz	if (strcmp(name, "lun") == 0) {
163255570Strasz		if (cur_lun != NULL)
164255570Strasz			log_errx(1, "%s: improper lun element nesting",
165255570Strasz			    __func__);
166255570Strasz
167255570Strasz		cur_lun = calloc(1, sizeof(*cur_lun));
168255570Strasz		if (cur_lun == NULL)
169255570Strasz			log_err(1, "%s: cannot allocate %zd bytes", __func__,
170255570Strasz			    sizeof(*cur_lun));
171255570Strasz
172255570Strasz		devlist->num_luns++;
173255570Strasz		devlist->cur_lun = cur_lun;
174255570Strasz
175255570Strasz		STAILQ_INIT(&cur_lun->attr_list);
176255570Strasz		STAILQ_INSERT_TAIL(&devlist->lun_list, cur_lun, links);
177255570Strasz
178255570Strasz		for (i = 0; attr[i] != NULL; i += 2) {
179255570Strasz			if (strcmp(attr[i], "id") == 0) {
180255570Strasz				cur_lun->lun_id = strtoull(attr[i+1], NULL, 0);
181255570Strasz			} else {
182255570Strasz				log_errx(1, "%s: invalid LUN attribute %s = %s",
183255570Strasz				     __func__, attr[i], attr[i+1]);
184255570Strasz			}
185255570Strasz		}
186255570Strasz	}
187255570Strasz}
188255570Strasz
189255570Straszstatic void
190255570Straszcctl_end_element(void *user_data, const char *name)
191255570Strasz{
192255570Strasz	struct cctl_devlist_data *devlist;
193255570Strasz	struct cctl_lun *cur_lun;
194255570Strasz	char *str;
195255570Strasz
196255570Strasz	devlist = (struct cctl_devlist_data *)user_data;
197255570Strasz	cur_lun = devlist->cur_lun;
198255570Strasz
199255570Strasz	if ((cur_lun == NULL)
200255570Strasz	 && (strcmp(name, "ctllunlist") != 0))
201255570Strasz		log_errx(1, "%s: cur_lun == NULL! (name = %s)", __func__, name);
202255570Strasz
203255570Strasz	if (devlist->cur_sb[devlist->level] == NULL)
204255570Strasz		log_errx(1, "%s: no valid sbuf at level %d (name %s)", __func__,
205255570Strasz		     devlist->level, name);
206255570Strasz
207255570Strasz	sbuf_finish(devlist->cur_sb[devlist->level]);
208255570Strasz	str = checked_strdup(sbuf_data(devlist->cur_sb[devlist->level]));
209255570Strasz
210255570Strasz	if (strlen(str) == 0) {
211255570Strasz		free(str);
212255570Strasz		str = NULL;
213255570Strasz	}
214255570Strasz
215255570Strasz	sbuf_delete(devlist->cur_sb[devlist->level]);
216255570Strasz	devlist->cur_sb[devlist->level] = NULL;
217255570Strasz	devlist->level--;
218255570Strasz
219255570Strasz	if (strcmp(name, "backend_type") == 0) {
220255570Strasz		cur_lun->backend_type = str;
221255570Strasz		str = NULL;
222255570Strasz	} else if (strcmp(name, "size") == 0) {
223255570Strasz		cur_lun->size_blocks = strtoull(str, NULL, 0);
224255570Strasz	} else if (strcmp(name, "blocksize") == 0) {
225255570Strasz		cur_lun->blocksize = strtoul(str, NULL, 0);
226255570Strasz	} else if (strcmp(name, "serial_number") == 0) {
227255570Strasz		cur_lun->serial_number = str;
228255570Strasz		str = NULL;
229255570Strasz	} else if (strcmp(name, "device_id") == 0) {
230255570Strasz		cur_lun->device_id = str;
231255570Strasz		str = NULL;
232255570Strasz	} else if (strcmp(name, "cfiscsi_target") == 0) {
233255570Strasz		cur_lun->cfiscsi_target = str;
234255570Strasz		str = NULL;
235255570Strasz	} else if (strcmp(name, "cfiscsi_lun") == 0) {
236255570Strasz		cur_lun->cfiscsi_lun = strtoul(str, NULL, 0);
237255570Strasz	} else if (strcmp(name, "lun") == 0) {
238255570Strasz		devlist->cur_lun = NULL;
239255570Strasz	} else if (strcmp(name, "ctllunlist") == 0) {
240255570Strasz
241255570Strasz	} else {
242255570Strasz		struct cctl_lun_nv *nv;
243255570Strasz
244255570Strasz		nv = calloc(1, sizeof(*nv));
245255570Strasz		if (nv == NULL)
246255570Strasz			log_err(1, "%s: can't allocate %zd bytes for nv pair",
247255570Strasz			    __func__, sizeof(*nv));
248255570Strasz
249255570Strasz		nv->name = checked_strdup(name);
250255570Strasz
251255570Strasz		nv->value = str;
252255570Strasz		str = NULL;
253255570Strasz		STAILQ_INSERT_TAIL(&cur_lun->attr_list, nv, links);
254255570Strasz	}
255255570Strasz
256255570Strasz	free(str);
257255570Strasz}
258255570Strasz
259255570Straszstatic void
260268682Smavcctl_start_pelement(void *user_data, const char *name, const char **attr)
261268682Smav{
262268682Smav	int i;
263268682Smav	struct cctl_devlist_data *devlist;
264268682Smav	struct cctl_port *cur_port;
265268682Smav
266268682Smav	devlist = (struct cctl_devlist_data *)user_data;
267268682Smav	cur_port = devlist->cur_port;
268268682Smav	devlist->level++;
269268682Smav	if ((u_int)devlist->level >= (sizeof(devlist->cur_sb) /
270268682Smav	    sizeof(devlist->cur_sb[0])))
271268682Smav		log_errx(1, "%s: too many nesting levels, %zd max", __func__,
272268682Smav		     sizeof(devlist->cur_sb) / sizeof(devlist->cur_sb[0]));
273268682Smav
274268682Smav	devlist->cur_sb[devlist->level] = sbuf_new_auto();
275268682Smav	if (devlist->cur_sb[devlist->level] == NULL)
276268682Smav		log_err(1, "%s: unable to allocate sbuf", __func__);
277268682Smav
278268682Smav	if (strcmp(name, "targ_port") == 0) {
279268682Smav		if (cur_port != NULL)
280268682Smav			log_errx(1, "%s: improper port element nesting (%s)",
281268682Smav			    __func__, name);
282268682Smav
283268682Smav		cur_port = calloc(1, sizeof(*cur_port));
284268682Smav		if (cur_port == NULL)
285268682Smav			log_err(1, "%s: cannot allocate %zd bytes", __func__,
286268682Smav			    sizeof(*cur_port));
287268682Smav
288268682Smav		devlist->num_ports++;
289268682Smav		devlist->cur_port = cur_port;
290268682Smav
291268682Smav		STAILQ_INIT(&cur_port->attr_list);
292268682Smav		STAILQ_INSERT_TAIL(&devlist->port_list, cur_port, links);
293268682Smav
294268682Smav		for (i = 0; attr[i] != NULL; i += 2) {
295268682Smav			if (strcmp(attr[i], "id") == 0) {
296268682Smav				cur_port->port_id = strtoul(attr[i+1], NULL, 0);
297268682Smav			} else {
298268682Smav				log_errx(1, "%s: invalid LUN attribute %s = %s",
299268682Smav				     __func__, attr[i], attr[i+1]);
300268682Smav			}
301268682Smav		}
302268682Smav	}
303268682Smav}
304268682Smav
305268682Smavstatic void
306268682Smavcctl_end_pelement(void *user_data, const char *name)
307268682Smav{
308268682Smav	struct cctl_devlist_data *devlist;
309268682Smav	struct cctl_port *cur_port;
310268682Smav	char *str;
311268682Smav
312268682Smav	devlist = (struct cctl_devlist_data *)user_data;
313268682Smav	cur_port = devlist->cur_port;
314268682Smav
315268682Smav	if ((cur_port == NULL)
316268682Smav	 && (strcmp(name, "ctlportlist") != 0))
317268682Smav		log_errx(1, "%s: cur_port == NULL! (name = %s)", __func__, name);
318268682Smav
319268682Smav	if (devlist->cur_sb[devlist->level] == NULL)
320268682Smav		log_errx(1, "%s: no valid sbuf at level %d (name %s)", __func__,
321268682Smav		     devlist->level, name);
322268682Smav
323268682Smav	sbuf_finish(devlist->cur_sb[devlist->level]);
324268682Smav	str = checked_strdup(sbuf_data(devlist->cur_sb[devlist->level]));
325268682Smav
326268682Smav	if (strlen(str) == 0) {
327268682Smav		free(str);
328268682Smav		str = NULL;
329268682Smav	}
330268682Smav
331268682Smav	sbuf_delete(devlist->cur_sb[devlist->level]);
332268682Smav	devlist->cur_sb[devlist->level] = NULL;
333268682Smav	devlist->level--;
334268682Smav
335268682Smav	if (strcmp(name, "cfiscsi_target") == 0) {
336268682Smav		cur_port->cfiscsi_target = str;
337268682Smav		str = NULL;
338268688Smav	} else if (strcmp(name, "cfiscsi_status") == 0) {
339268688Smav		cur_port->cfiscsi_status = strtoul(str, NULL, 0);
340268682Smav	} else if (strcmp(name, "cfiscsi_portal_group_tag") == 0) {
341268682Smav		cur_port->cfiscsi_portal_group_tag = strtoul(str, NULL, 0);
342268682Smav	} else if (strcmp(name, "targ_port") == 0) {
343268682Smav		devlist->cur_port = NULL;
344268682Smav	} else if (strcmp(name, "ctlportlist") == 0) {
345268682Smav
346268682Smav	} else {
347268682Smav		struct cctl_lun_nv *nv;
348268682Smav
349268682Smav		nv = calloc(1, sizeof(*nv));
350268682Smav		if (nv == NULL)
351268682Smav			log_err(1, "%s: can't allocate %zd bytes for nv pair",
352268682Smav			    __func__, sizeof(*nv));
353268682Smav
354268682Smav		nv->name = checked_strdup(name);
355268682Smav
356268682Smav		nv->value = str;
357268682Smav		str = NULL;
358268682Smav		STAILQ_INSERT_TAIL(&cur_port->attr_list, nv, links);
359268682Smav	}
360268682Smav
361268682Smav	free(str);
362268682Smav}
363268682Smav
364268682Smavstatic void
365255570Straszcctl_char_handler(void *user_data, const XML_Char *str, int len)
366255570Strasz{
367255570Strasz	struct cctl_devlist_data *devlist;
368255570Strasz
369255570Strasz	devlist = (struct cctl_devlist_data *)user_data;
370255570Strasz
371255570Strasz	sbuf_bcat(devlist->cur_sb[devlist->level], str, len);
372255570Strasz}
373255570Strasz
374255570Straszstruct conf *
375255570Straszconf_new_from_kernel(void)
376255570Strasz{
377255570Strasz	struct conf *conf = NULL;
378255570Strasz	struct target *targ;
379255570Strasz	struct lun *cl;
380255570Strasz	struct lun_option *lo;
381255570Strasz	struct ctl_lun_list list;
382255570Strasz	struct cctl_devlist_data devlist;
383255570Strasz	struct cctl_lun *lun;
384268682Smav	struct cctl_port *port;
385255570Strasz	XML_Parser parser;
386268682Smav	char *str;
387268682Smav	int len, retval;
388255570Strasz
389255570Strasz	bzero(&devlist, sizeof(devlist));
390255570Strasz	STAILQ_INIT(&devlist.lun_list);
391268682Smav	STAILQ_INIT(&devlist.port_list);
392255570Strasz
393255570Strasz	log_debugx("obtaining previously configured CTL luns from the kernel");
394255570Strasz
395268682Smav	str = NULL;
396268682Smav	len = 4096;
397255570Straszretry:
398268682Smav	str = realloc(str, len);
399268682Smav	if (str == NULL)
400255570Strasz		log_err(1, "realloc");
401255570Strasz
402255570Strasz	bzero(&list, sizeof(list));
403268682Smav	list.alloc_len = len;
404255570Strasz	list.status = CTL_LUN_LIST_NONE;
405268682Smav	list.lun_xml = str;
406255570Strasz
407255570Strasz	if (ioctl(ctl_fd, CTL_LUN_LIST, &list) == -1) {
408255570Strasz		log_warn("error issuing CTL_LUN_LIST ioctl");
409268682Smav		free(str);
410255570Strasz		return (NULL);
411255570Strasz	}
412255570Strasz
413255570Strasz	if (list.status == CTL_LUN_LIST_ERROR) {
414255570Strasz		log_warnx("error returned from CTL_LUN_LIST ioctl: %s",
415255570Strasz		    list.error_str);
416268682Smav		free(str);
417255570Strasz		return (NULL);
418255570Strasz	}
419255570Strasz
420255570Strasz	if (list.status == CTL_LUN_LIST_NEED_MORE_SPACE) {
421268682Smav		len = len << 1;
422255570Strasz		goto retry;
423255570Strasz	}
424255570Strasz
425255570Strasz	parser = XML_ParserCreate(NULL);
426255570Strasz	if (parser == NULL) {
427255570Strasz		log_warnx("unable to create XML parser");
428268682Smav		free(str);
429255570Strasz		return (NULL);
430255570Strasz	}
431255570Strasz
432255570Strasz	XML_SetUserData(parser, &devlist);
433255570Strasz	XML_SetElementHandler(parser, cctl_start_element, cctl_end_element);
434255570Strasz	XML_SetCharacterDataHandler(parser, cctl_char_handler);
435255570Strasz
436268682Smav	retval = XML_Parse(parser, str, strlen(str), 1);
437255570Strasz	XML_ParserFree(parser);
438268682Smav	free(str);
439255570Strasz	if (retval != 1) {
440255570Strasz		log_warnx("XML_Parse failed");
441255570Strasz		return (NULL);
442255570Strasz	}
443255570Strasz
444268682Smav	str = NULL;
445268682Smav	len = 4096;
446268682Smavretry_port:
447268682Smav	str = realloc(str, len);
448268682Smav	if (str == NULL)
449268682Smav		log_err(1, "realloc");
450268682Smav
451268682Smav	bzero(&list, sizeof(list));
452268682Smav	list.alloc_len = len;
453268682Smav	list.status = CTL_LUN_LIST_NONE;
454268682Smav	list.lun_xml = str;
455268682Smav
456268682Smav	if (ioctl(ctl_fd, CTL_PORT_LIST, &list) == -1) {
457268682Smav		log_warn("error issuing CTL_PORT_LIST ioctl");
458268682Smav		free(str);
459268682Smav		return (NULL);
460268682Smav	}
461268682Smav
462268682Smav	if (list.status == CTL_PORT_LIST_ERROR) {
463268682Smav		log_warnx("error returned from CTL_PORT_LIST ioctl: %s",
464268682Smav		    list.error_str);
465268682Smav		free(str);
466268682Smav		return (NULL);
467268682Smav	}
468268682Smav
469268682Smav	if (list.status == CTL_LUN_LIST_NEED_MORE_SPACE) {
470268682Smav		len = len << 1;
471268682Smav		goto retry_port;
472268682Smav	}
473268682Smav
474268682Smav	parser = XML_ParserCreate(NULL);
475268682Smav	if (parser == NULL) {
476268682Smav		log_warnx("unable to create XML parser");
477268682Smav		free(str);
478268682Smav		return (NULL);
479268682Smav	}
480268682Smav
481268682Smav	XML_SetUserData(parser, &devlist);
482268682Smav	XML_SetElementHandler(parser, cctl_start_pelement, cctl_end_pelement);
483268682Smav	XML_SetCharacterDataHandler(parser, cctl_char_handler);
484268682Smav
485268682Smav	retval = XML_Parse(parser, str, strlen(str), 1);
486268682Smav	XML_ParserFree(parser);
487268682Smav	free(str);
488268682Smav	if (retval != 1) {
489268682Smav		log_warnx("XML_Parse failed");
490268682Smav		return (NULL);
491268682Smav	}
492268682Smav
493255570Strasz	conf = conf_new();
494255570Strasz
495268682Smav	STAILQ_FOREACH(port, &devlist.port_list, links) {
496268682Smav
497268682Smav		if (port->cfiscsi_target == NULL) {
498268682Smav			log_debugx("CTL port %ju wasn't managed by ctld; "
499268682Smav			    "ignoring", (uintmax_t)port->port_id);
500268682Smav			continue;
501268682Smav		}
502268688Smav		if (port->cfiscsi_status != 1) {
503268688Smav			log_debugx("CTL port %ju is not active (%d); ignoring",
504268688Smav			    (uintmax_t)port->port_id, port->cfiscsi_status);
505268688Smav			continue;
506268688Smav		}
507268682Smav
508268682Smav		targ = target_find(conf, port->cfiscsi_target);
509268682Smav		if (targ == NULL) {
510268682Smav#if 0
511268682Smav			log_debugx("found new kernel target %s for CTL port %ld",
512268682Smav			    port->cfiscsi_target, port->port_id);
513268682Smav#endif
514268682Smav			targ = target_new(conf, port->cfiscsi_target);
515268682Smav			if (targ == NULL) {
516268682Smav				log_warnx("target_new failed");
517268682Smav				continue;
518268682Smav			}
519268682Smav		}
520268682Smav	}
521268682Smav
522255570Strasz	STAILQ_FOREACH(lun, &devlist.lun_list, links) {
523255570Strasz		struct cctl_lun_nv *nv;
524255570Strasz
525255570Strasz		if (lun->cfiscsi_target == NULL) {
526255570Strasz			log_debugx("CTL lun %ju wasn't managed by ctld; "
527255570Strasz			    "ignoring", (uintmax_t)lun->lun_id);
528255570Strasz			continue;
529255570Strasz		}
530255570Strasz
531255570Strasz		targ = target_find(conf, lun->cfiscsi_target);
532255570Strasz		if (targ == NULL) {
533255570Strasz#if 0
534255570Strasz			log_debugx("found new kernel target %s for CTL lun %ld",
535255570Strasz			    lun->cfiscsi_target, lun->lun_id);
536255570Strasz#endif
537255570Strasz			targ = target_new(conf, lun->cfiscsi_target);
538255570Strasz			if (targ == NULL) {
539255570Strasz				log_warnx("target_new failed");
540255570Strasz				continue;
541255570Strasz			}
542255570Strasz		}
543255570Strasz
544255570Strasz		cl = lun_find(targ, lun->cfiscsi_lun);
545255570Strasz		if (cl != NULL) {
546255570Strasz			log_warnx("found CTL lun %ju, backing lun %d, target "
547255570Strasz			    "%s, also backed by CTL lun %d; ignoring",
548255570Strasz			    (uintmax_t) lun->lun_id, cl->l_lun,
549263723Strasz			    cl->l_target->t_name, cl->l_ctl_lun);
550255570Strasz			continue;
551255570Strasz		}
552255570Strasz
553255570Strasz		log_debugx("found CTL lun %ju, backing lun %d, target %s",
554255570Strasz		    (uintmax_t)lun->lun_id, lun->cfiscsi_lun, lun->cfiscsi_target);
555255570Strasz
556255570Strasz		cl = lun_new(targ, lun->cfiscsi_lun);
557255570Strasz		if (cl == NULL) {
558255570Strasz			log_warnx("lun_new failed");
559255570Strasz			continue;
560255570Strasz		}
561255570Strasz		lun_set_backend(cl, lun->backend_type);
562255570Strasz		lun_set_blocksize(cl, lun->blocksize);
563255570Strasz		lun_set_device_id(cl, lun->device_id);
564255570Strasz		lun_set_serial(cl, lun->serial_number);
565255570Strasz		lun_set_size(cl, lun->size_blocks * cl->l_blocksize);
566255570Strasz		lun_set_ctl_lun(cl, lun->lun_id);
567255570Strasz
568255570Strasz		STAILQ_FOREACH(nv, &lun->attr_list, links) {
569255570Strasz			if (strcmp(nv->name, "file") == 0 ||
570255570Strasz			    strcmp(nv->name, "dev") == 0) {
571255570Strasz				lun_set_path(cl, nv->value);
572255570Strasz				continue;
573255570Strasz			}
574255570Strasz			lo = lun_option_new(cl, nv->name, nv->value);
575255570Strasz			if (lo == NULL)
576255570Strasz				log_warnx("unable to add CTL lun option %s "
577255570Strasz				    "for CTL lun %ju for lun %d, target %s",
578255570Strasz				    nv->name, (uintmax_t) lun->lun_id,
579263723Strasz				    cl->l_lun, cl->l_target->t_name);
580255570Strasz		}
581255570Strasz	}
582255570Strasz
583255570Strasz	return (conf);
584255570Strasz}
585255570Strasz
586268682Smavstatic void
587268682Smavstr_arg(struct ctl_be_arg *arg, const char *name, const char *value)
588268682Smav{
589268682Smav
590268682Smav	arg->namelen = strlen(name) + 1;
591268682Smav	arg->name = __DECONST(char *, name);
592268682Smav	arg->vallen = strlen(value) + 1;
593268682Smav	arg->value = __DECONST(char *, value);
594268682Smav	arg->flags = CTL_BEARG_ASCII | CTL_BEARG_RD;
595268682Smav}
596268682Smav
597255570Straszint
598255570Straszkernel_lun_add(struct lun *lun)
599255570Strasz{
600255570Strasz	struct lun_option *lo;
601255570Strasz	struct ctl_lun_req req;
602255570Strasz	char *tmp;
603255570Strasz	int error, i, num_options;
604255570Strasz
605255570Strasz	bzero(&req, sizeof(req));
606255570Strasz
607255570Strasz	strlcpy(req.backend, lun->l_backend, sizeof(req.backend));
608255570Strasz	req.reqtype = CTL_LUNREQ_CREATE;
609255570Strasz
610255570Strasz	req.reqdata.create.blocksize_bytes = lun->l_blocksize;
611255570Strasz
612255570Strasz	if (lun->l_size != 0)
613255570Strasz		req.reqdata.create.lun_size_bytes = lun->l_size;
614255570Strasz
615255570Strasz	req.reqdata.create.flags |= CTL_LUN_FLAG_DEV_TYPE;
616255570Strasz	req.reqdata.create.device_type = T_DIRECT;
617255570Strasz
618255570Strasz	if (lun->l_serial != NULL) {
619268262Smav		strncpy(req.reqdata.create.serial_num, lun->l_serial,
620255570Strasz			sizeof(req.reqdata.create.serial_num));
621255570Strasz		req.reqdata.create.flags |= CTL_LUN_FLAG_SERIAL_NUM;
622255570Strasz	}
623255570Strasz
624255570Strasz	if (lun->l_device_id != NULL) {
625268262Smav		strncpy(req.reqdata.create.device_id, lun->l_device_id,
626255570Strasz			sizeof(req.reqdata.create.device_id));
627255570Strasz		req.reqdata.create.flags |= CTL_LUN_FLAG_DEVID;
628255570Strasz	}
629255570Strasz
630255570Strasz	if (lun->l_path != NULL) {
631255570Strasz		lo = lun_option_find(lun, "file");
632255570Strasz		if (lo != NULL) {
633255570Strasz			lun_option_set(lo, lun->l_path);
634255570Strasz		} else {
635255570Strasz			lo = lun_option_new(lun, "file", lun->l_path);
636255570Strasz			assert(lo != NULL);
637255570Strasz		}
638255570Strasz	}
639255570Strasz
640255570Strasz	lo = lun_option_find(lun, "cfiscsi_target");
641255570Strasz	if (lo != NULL) {
642263723Strasz		lun_option_set(lo, lun->l_target->t_name);
643255570Strasz	} else {
644255570Strasz		lo = lun_option_new(lun, "cfiscsi_target",
645263723Strasz		    lun->l_target->t_name);
646255570Strasz		assert(lo != NULL);
647255570Strasz	}
648255570Strasz
649255570Strasz	asprintf(&tmp, "%d", lun->l_lun);
650255570Strasz	if (tmp == NULL)
651255570Strasz		log_errx(1, "asprintf");
652255570Strasz	lo = lun_option_find(lun, "cfiscsi_lun");
653255570Strasz	if (lo != NULL) {
654255570Strasz		lun_option_set(lo, tmp);
655255570Strasz		free(tmp);
656255570Strasz	} else {
657255570Strasz		lo = lun_option_new(lun, "cfiscsi_lun", tmp);
658255570Strasz		free(tmp);
659255570Strasz		assert(lo != NULL);
660255570Strasz	}
661255570Strasz
662268683Smav	asprintf(&tmp, "%s,lun,%d", lun->l_target->t_name, lun->l_lun);
663268683Smav	if (tmp == NULL)
664268683Smav		log_errx(1, "asprintf");
665268683Smav	lo = lun_option_find(lun, "scsiname");
666268683Smav	if (lo != NULL) {
667268683Smav		lun_option_set(lo, tmp);
668268683Smav		free(tmp);
669268683Smav	} else {
670268683Smav		lo = lun_option_new(lun, "scsiname", tmp);
671268683Smav		free(tmp);
672268683Smav		assert(lo != NULL);
673268683Smav	}
674268683Smav
675255570Strasz	num_options = 0;
676255570Strasz	TAILQ_FOREACH(lo, &lun->l_options, lo_next)
677255570Strasz		num_options++;
678255570Strasz
679255570Strasz	req.num_be_args = num_options;
680255570Strasz	if (num_options > 0) {
681255570Strasz		req.be_args = malloc(num_options * sizeof(*req.be_args));
682255570Strasz		if (req.be_args == NULL) {
683255570Strasz			log_warn("error allocating %zd bytes",
684255570Strasz			    num_options * sizeof(*req.be_args));
685255570Strasz			return (1);
686255570Strasz		}
687255570Strasz
688255570Strasz		i = 0;
689255570Strasz		TAILQ_FOREACH(lo, &lun->l_options, lo_next) {
690268682Smav			str_arg(&req.be_args[i], lo->lo_name, lo->lo_value);
691255570Strasz			i++;
692255570Strasz		}
693255570Strasz		assert(i == num_options);
694255570Strasz	}
695255570Strasz
696255570Strasz	error = ioctl(ctl_fd, CTL_LUN_REQ, &req);
697255570Strasz	free(req.be_args);
698255570Strasz	if (error != 0) {
699255570Strasz		log_warn("error issuing CTL_LUN_REQ ioctl");
700255570Strasz		return (1);
701255570Strasz	}
702255570Strasz
703255570Strasz	if (req.status == CTL_LUN_ERROR) {
704255570Strasz		log_warnx("error returned from LUN creation request: %s",
705255570Strasz		    req.error_str);
706255570Strasz		return (1);
707255570Strasz	}
708255570Strasz
709255570Strasz	if (req.status != CTL_LUN_OK) {
710255570Strasz		log_warnx("unknown LUN creation request status %d",
711255570Strasz		    req.status);
712255570Strasz		return (1);
713255570Strasz	}
714255570Strasz
715255570Strasz	lun_set_ctl_lun(lun, req.reqdata.create.req_lun_id);
716255570Strasz
717255570Strasz	return (0);
718255570Strasz}
719255570Strasz
720255570Straszint
721255570Straszkernel_lun_resize(struct lun *lun)
722255570Strasz{
723255570Strasz	struct ctl_lun_req req;
724255570Strasz
725255570Strasz	bzero(&req, sizeof(req));
726255570Strasz
727255570Strasz	strlcpy(req.backend, lun->l_backend, sizeof(req.backend));
728255570Strasz	req.reqtype = CTL_LUNREQ_MODIFY;
729255570Strasz
730255570Strasz	req.reqdata.modify.lun_id = lun->l_ctl_lun;
731255570Strasz	req.reqdata.modify.lun_size_bytes = lun->l_size;
732255570Strasz
733255570Strasz	if (ioctl(ctl_fd, CTL_LUN_REQ, &req) == -1) {
734255570Strasz		log_warn("error issuing CTL_LUN_REQ ioctl");
735255570Strasz		return (1);
736255570Strasz	}
737255570Strasz
738255570Strasz	if (req.status == CTL_LUN_ERROR) {
739255570Strasz		log_warnx("error returned from LUN modification request: %s",
740255570Strasz		    req.error_str);
741255570Strasz		return (1);
742255570Strasz	}
743255570Strasz
744255570Strasz	if (req.status != CTL_LUN_OK) {
745255570Strasz		log_warnx("unknown LUN modification request status %d",
746255570Strasz		    req.status);
747255570Strasz		return (1);
748255570Strasz	}
749255570Strasz
750255570Strasz	return (0);
751255570Strasz}
752255570Strasz
753255570Straszint
754255570Straszkernel_lun_remove(struct lun *lun)
755255570Strasz{
756255570Strasz	struct ctl_lun_req req;
757255570Strasz
758255570Strasz	bzero(&req, sizeof(req));
759255570Strasz
760255570Strasz	strlcpy(req.backend, lun->l_backend, sizeof(req.backend));
761255570Strasz	req.reqtype = CTL_LUNREQ_RM;
762255570Strasz
763255570Strasz	req.reqdata.rm.lun_id = lun->l_ctl_lun;
764255570Strasz
765255570Strasz	if (ioctl(ctl_fd, CTL_LUN_REQ, &req) == -1) {
766255570Strasz		log_warn("error issuing CTL_LUN_REQ ioctl");
767255570Strasz		return (1);
768255570Strasz	}
769255570Strasz
770255570Strasz	if (req.status == CTL_LUN_ERROR) {
771255570Strasz		log_warnx("error returned from LUN removal request: %s",
772255570Strasz		    req.error_str);
773255570Strasz		return (1);
774255570Strasz	}
775255570Strasz
776255570Strasz	if (req.status != CTL_LUN_OK) {
777255570Strasz		log_warnx("unknown LUN removal request status %d", req.status);
778255570Strasz		return (1);
779255570Strasz	}
780255570Strasz
781255570Strasz	return (0);
782255570Strasz}
783255570Strasz
784255570Straszvoid
785255570Straszkernel_handoff(struct connection *conn)
786255570Strasz{
787255570Strasz	struct ctl_iscsi req;
788255570Strasz
789255570Strasz	bzero(&req, sizeof(req));
790255570Strasz
791255570Strasz	req.type = CTL_ISCSI_HANDOFF;
792255570Strasz	strlcpy(req.data.handoff.initiator_name,
793255570Strasz	    conn->conn_initiator_name, sizeof(req.data.handoff.initiator_name));
794255570Strasz	strlcpy(req.data.handoff.initiator_addr,
795255570Strasz	    conn->conn_initiator_addr, sizeof(req.data.handoff.initiator_addr));
796255570Strasz	if (conn->conn_initiator_alias != NULL) {
797255570Strasz		strlcpy(req.data.handoff.initiator_alias,
798255570Strasz		    conn->conn_initiator_alias, sizeof(req.data.handoff.initiator_alias));
799255570Strasz	}
800268684Smav	memcpy(req.data.handoff.initiator_isid, conn->conn_initiator_isid,
801268684Smav	    sizeof(req.data.handoff.initiator_isid));
802255570Strasz	strlcpy(req.data.handoff.target_name,
803263723Strasz	    conn->conn_target->t_name, sizeof(req.data.handoff.target_name));
804265507Strasz#ifdef ICL_KERNEL_PROXY
805265507Strasz	if (proxy_mode)
806265507Strasz		req.data.handoff.connection_id = conn->conn_socket;
807265507Strasz	else
808265507Strasz		req.data.handoff.socket = conn->conn_socket;
809265507Strasz#else
810255570Strasz	req.data.handoff.socket = conn->conn_socket;
811265507Strasz#endif
812255570Strasz	req.data.handoff.portal_group_tag =
813255570Strasz	    conn->conn_portal->p_portal_group->pg_tag;
814255570Strasz	if (conn->conn_header_digest == CONN_DIGEST_CRC32C)
815255570Strasz		req.data.handoff.header_digest = CTL_ISCSI_DIGEST_CRC32C;
816255570Strasz	if (conn->conn_data_digest == CONN_DIGEST_CRC32C)
817255570Strasz		req.data.handoff.data_digest = CTL_ISCSI_DIGEST_CRC32C;
818255570Strasz	req.data.handoff.cmdsn = conn->conn_cmdsn;
819255570Strasz	req.data.handoff.statsn = conn->conn_statsn;
820255570Strasz	req.data.handoff.max_recv_data_segment_length =
821255570Strasz	    conn->conn_max_data_segment_length;
822255570Strasz	req.data.handoff.max_burst_length = conn->conn_max_burst_length;
823255570Strasz	req.data.handoff.immediate_data = conn->conn_immediate_data;
824255570Strasz
825265509Strasz	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) {
826255570Strasz		log_err(1, "error issuing CTL_ISCSI ioctl; "
827255570Strasz		    "dropping connection");
828265509Strasz	}
829255570Strasz
830265509Strasz	if (req.status != CTL_ISCSI_OK) {
831255570Strasz		log_errx(1, "error returned from CTL iSCSI handoff request: "
832255570Strasz		    "%s; dropping connection", req.error_str);
833265509Strasz	}
834255570Strasz}
835255570Strasz
836255570Straszint
837268682Smavkernel_port_add(struct target *targ)
838255570Strasz{
839255570Strasz	struct ctl_port_entry entry;
840268682Smav	struct ctl_req req;
841268682Smav	char tagstr[16];
842255570Strasz	int error;
843268682Smav	uint32_t port_id = -1;
844255570Strasz
845268682Smav	bzero(&req, sizeof(req));
846268682Smav	strlcpy(req.driver, "iscsi", sizeof(req.driver));
847268682Smav	req.reqtype = CTL_REQ_CREATE;
848268682Smav	req.num_args = 4;
849268682Smav	req.args = malloc(req.num_args * sizeof(*req.args));
850268682Smav	req.args[0].namelen = sizeof("port_id");
851268682Smav	req.args[0].name = __DECONST(char *, "port_id");
852268682Smav	req.args[0].vallen = sizeof(port_id);
853268682Smav	req.args[0].value = &port_id;
854268682Smav	req.args[0].flags = CTL_BEARG_WR;
855268682Smav	str_arg(&req.args[1], "cfiscsi_target", targ->t_name);
856268682Smav	snprintf(tagstr, sizeof(tagstr), "%d", targ->t_portal_group->pg_tag);
857268910Smav	str_arg(&req.args[2], "cfiscsi_portal_group_tag", tagstr);
858268910Smav	if (targ->t_alias)
859268910Smav		str_arg(&req.args[3], "cfiscsi_target_alias", targ->t_alias);
860268910Smav	else
861268910Smav		req.num_args--;
862268682Smav
863268682Smav	error = ioctl(ctl_fd, CTL_PORT_REQ, &req);
864268682Smav	free(req.args);
865268682Smav	if (error != 0) {
866268682Smav		log_warn("error issuing CTL_PORT_REQ ioctl");
867268682Smav		return (1);
868268682Smav	}
869268682Smav
870268682Smav	if (req.status == CTL_LUN_ERROR) {
871268682Smav		log_warnx("error returned from port creation request: %s",
872268682Smav		    req.error_str);
873268682Smav		return (1);
874268682Smav	}
875268682Smav
876268682Smav	if (req.status != CTL_LUN_OK) {
877268682Smav		log_warnx("unknown port creation request status %d",
878268682Smav		    req.status);
879268682Smav		return (1);
880268682Smav	}
881268682Smav
882255678Strasz	bzero(&entry, sizeof(entry));
883268682Smav	entry.targ_port = port_id;
884255570Strasz
885255570Strasz	error = ioctl(ctl_fd, CTL_ENABLE_PORT, &entry);
886255570Strasz	if (error != 0) {
887255570Strasz		log_warn("CTL_ENABLE_PORT ioctl failed");
888255570Strasz		return (-1);
889255570Strasz	}
890255570Strasz
891255570Strasz	return (0);
892255570Strasz}
893255570Strasz
894255570Straszint
895268682Smavkernel_port_remove(struct target *targ)
896255570Strasz{
897268682Smav	struct ctl_req req;
898268682Smav	char tagstr[16];
899255570Strasz	int error;
900255570Strasz
901268682Smav	bzero(&req, sizeof(req));
902268682Smav	strlcpy(req.driver, "iscsi", sizeof(req.driver));
903268682Smav	req.reqtype = CTL_REQ_REMOVE;
904268682Smav	req.num_args = 2;
905268682Smav	req.args = malloc(req.num_args * sizeof(*req.args));
906268682Smav	str_arg(&req.args[0], "cfiscsi_target", targ->t_name);
907268682Smav	if (targ->t_portal_group) {
908268682Smav		snprintf(tagstr, sizeof(tagstr), "%d",
909268682Smav		    targ->t_portal_group->pg_tag);
910268682Smav		str_arg(&req.args[1], "cfiscsi_portal_group_tag", tagstr);
911268682Smav	} else
912268682Smav		req.num_args--;
913255570Strasz
914268682Smav	error = ioctl(ctl_fd, CTL_PORT_REQ, &req);
915268682Smav	free(req.args);
916255570Strasz	if (error != 0) {
917268682Smav		log_warn("error issuing CTL_PORT_REQ ioctl");
918268682Smav		return (1);
919255570Strasz	}
920255570Strasz
921268682Smav	if (req.status == CTL_LUN_ERROR) {
922268682Smav		log_warnx("error returned from port removal request: %s",
923268682Smav		    req.error_str);
924268682Smav		return (1);
925268682Smav	}
926268682Smav
927268682Smav	if (req.status != CTL_LUN_OK) {
928268682Smav		log_warnx("unknown port removal request status %d",
929268682Smav		    req.status);
930268682Smav		return (1);
931268682Smav	}
932268682Smav
933255570Strasz	return (0);
934255570Strasz}
935255570Strasz
936255570Strasz#ifdef ICL_KERNEL_PROXY
937255570Straszvoid
938265509Straszkernel_listen(struct addrinfo *ai, bool iser, int portal_id)
939255570Strasz{
940255570Strasz	struct ctl_iscsi req;
941255570Strasz
942255570Strasz	bzero(&req, sizeof(req));
943255570Strasz
944255570Strasz	req.type = CTL_ISCSI_LISTEN;
945255570Strasz	req.data.listen.iser = iser;
946255570Strasz	req.data.listen.domain = ai->ai_family;
947255570Strasz	req.data.listen.socktype = ai->ai_socktype;
948255570Strasz	req.data.listen.protocol = ai->ai_protocol;
949255570Strasz	req.data.listen.addr = ai->ai_addr;
950255570Strasz	req.data.listen.addrlen = ai->ai_addrlen;
951265509Strasz	req.data.listen.portal_id = portal_id;
952255570Strasz
953265509Strasz	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1)
954263713Strasz		log_err(1, "error issuing CTL_ISCSI ioctl");
955263713Strasz
956263713Strasz	if (req.status != CTL_ISCSI_OK) {
957263713Strasz		log_errx(1, "error returned from CTL iSCSI listen: %s",
958263713Strasz		    req.error_str);
959263713Strasz	}
960255570Strasz}
961255570Strasz
962265509Straszvoid
963265513Straszkernel_accept(int *connection_id, int *portal_id,
964265513Strasz    struct sockaddr *client_sa, socklen_t *client_salen)
965255570Strasz{
966255570Strasz	struct ctl_iscsi req;
967265513Strasz	struct sockaddr_storage ss;
968255570Strasz
969255570Strasz	bzero(&req, sizeof(req));
970255570Strasz
971255570Strasz	req.type = CTL_ISCSI_ACCEPT;
972265513Strasz	req.data.accept.initiator_addr = (struct sockaddr *)&ss;
973255570Strasz
974265509Strasz	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1)
975265509Strasz		log_err(1, "error issuing CTL_ISCSI ioctl");
976255570Strasz
977263713Strasz	if (req.status != CTL_ISCSI_OK) {
978265509Strasz		log_errx(1, "error returned from CTL iSCSI accept: %s",
979263713Strasz		    req.error_str);
980263713Strasz	}
981263713Strasz
982265509Strasz	*connection_id = req.data.accept.connection_id;
983265509Strasz	*portal_id = req.data.accept.portal_id;
984265513Strasz	*client_salen = req.data.accept.initiator_addrlen;
985265513Strasz	memcpy(client_sa, &ss, *client_salen);
986255570Strasz}
987255570Strasz
988255570Straszvoid
989255570Straszkernel_send(struct pdu *pdu)
990255570Strasz{
991255570Strasz	struct ctl_iscsi req;
992255570Strasz
993255570Strasz	bzero(&req, sizeof(req));
994255570Strasz
995255570Strasz	req.type = CTL_ISCSI_SEND;
996255570Strasz	req.data.send.connection_id = pdu->pdu_connection->conn_socket;
997255570Strasz	req.data.send.bhs = pdu->pdu_bhs;
998255570Strasz	req.data.send.data_segment_len = pdu->pdu_data_len;
999255570Strasz	req.data.send.data_segment = pdu->pdu_data;
1000255570Strasz
1001263713Strasz	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) {
1002255570Strasz		log_err(1, "error issuing CTL_ISCSI ioctl; "
1003255570Strasz		    "dropping connection");
1004263713Strasz	}
1005255570Strasz
1006263713Strasz	if (req.status != CTL_ISCSI_OK) {
1007255570Strasz		log_errx(1, "error returned from CTL iSCSI send: "
1008255570Strasz		    "%s; dropping connection", req.error_str);
1009263713Strasz	}
1010255570Strasz}
1011255570Strasz
1012255570Straszvoid
1013255570Straszkernel_receive(struct pdu *pdu)
1014255570Strasz{
1015255570Strasz	struct ctl_iscsi req;
1016255570Strasz
1017255570Strasz	pdu->pdu_data = malloc(MAX_DATA_SEGMENT_LENGTH);
1018255570Strasz	if (pdu->pdu_data == NULL)
1019255570Strasz		log_err(1, "malloc");
1020255570Strasz
1021255570Strasz	bzero(&req, sizeof(req));
1022255570Strasz
1023255570Strasz	req.type = CTL_ISCSI_RECEIVE;
1024255570Strasz	req.data.receive.connection_id = pdu->pdu_connection->conn_socket;
1025255570Strasz	req.data.receive.bhs = pdu->pdu_bhs;
1026255570Strasz	req.data.receive.data_segment_len = MAX_DATA_SEGMENT_LENGTH;
1027255570Strasz	req.data.receive.data_segment = pdu->pdu_data;
1028255570Strasz
1029263713Strasz	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) {
1030255570Strasz		log_err(1, "error issuing CTL_ISCSI ioctl; "
1031255570Strasz		    "dropping connection");
1032263713Strasz	}
1033255570Strasz
1034263713Strasz	if (req.status != CTL_ISCSI_OK) {
1035255570Strasz		log_errx(1, "error returned from CTL iSCSI receive: "
1036255570Strasz		    "%s; dropping connection", req.error_str);
1037263713Strasz	}
1038255570Strasz
1039255570Strasz}
1040255570Strasz
1041255570Strasz#endif /* ICL_KERNEL_PROXY */
1042255570Strasz
1043255570Strasz/*
1044255570Strasz * XXX: I CANT INTO LATIN
1045255570Strasz */
1046255570Straszvoid
1047255570Straszkernel_capsicate(void)
1048255570Strasz{
1049255570Strasz	int error;
1050255570Strasz	cap_rights_t rights;
1051255570Strasz	const unsigned long cmds[] = { CTL_ISCSI };
1052255570Strasz
1053255570Strasz	cap_rights_init(&rights, CAP_IOCTL);
1054255570Strasz	error = cap_rights_limit(ctl_fd, &rights);
1055255570Strasz	if (error != 0 && errno != ENOSYS)
1056255570Strasz		log_err(1, "cap_rights_limit");
1057255570Strasz
1058255570Strasz	error = cap_ioctls_limit(ctl_fd, cmds,
1059255570Strasz	    sizeof(cmds) / sizeof(cmds[0]));
1060255570Strasz	if (error != 0 && errno != ENOSYS)
1061255570Strasz		log_err(1, "cap_ioctls_limit");
1062255570Strasz
1063255570Strasz	error = cap_enter();
1064255570Strasz	if (error != 0 && errno != ENOSYS)
1065255570Strasz		log_err(1, "cap_enter");
1066255570Strasz
1067255570Strasz	if (cap_sandboxed())
1068255570Strasz		log_debugx("Capsicum capability mode enabled");
1069255570Strasz	else
1070255570Strasz		log_warnx("Capsicum capability mode not supported");
1071255570Strasz}
1072255570Strasz
1073