xref: /freebsd/usr.sbin/ctld/kernel.c (revision 5bd73b51076b5cb5a2c9810f76c1d7ed20c4460e)
1 /*-
2  * Copyright (c) 2003, 2004 Silicon Graphics International Corp.
3  * Copyright (c) 1997-2007 Kenneth D. Merry
4  * Copyright (c) 2012 The FreeBSD Foundation
5  * All rights reserved.
6  *
7  * Portions of this software were developed by Edward Tomasz Napierala
8  * under sponsorship from the FreeBSD Foundation.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions, and the following disclaimer,
15  *    without modification.
16  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
17  *    substantially similar to the "NO WARRANTY" disclaimer below
18  *    ("Disclaimer") and any redistribution must be conditioned upon
19  *    including a substantially similar Disclaimer requirement for further
20  *    binary redistribution.
21  *
22  * NO WARRANTY
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
26  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
32  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGES.
34  *
35  */
36 
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD$");
39 
40 #include <sys/ioctl.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <sys/param.h>
44 #include <sys/linker.h>
45 #include <sys/queue.h>
46 #include <sys/callout.h>
47 #include <sys/sbuf.h>
48 #include <sys/capsicum.h>
49 #include <assert.h>
50 #include <bsdxml.h>
51 #include <ctype.h>
52 #include <errno.h>
53 #include <fcntl.h>
54 #include <stdint.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <strings.h>
59 #include <cam/scsi/scsi_all.h>
60 #include <cam/scsi/scsi_message.h>
61 #include <cam/ctl/ctl.h>
62 #include <cam/ctl/ctl_io.h>
63 #include <cam/ctl/ctl_frontend_internal.h>
64 #include <cam/ctl/ctl_backend.h>
65 #include <cam/ctl/ctl_ioctl.h>
66 #include <cam/ctl/ctl_backend_block.h>
67 #include <cam/ctl/ctl_util.h>
68 #include <cam/ctl/ctl_scsi_all.h>
69 
70 #include "ctld.h"
71 
72 #ifdef ICL_KERNEL_PROXY
73 #include <netdb.h>
74 #endif
75 
76 extern bool proxy_mode;
77 
78 static int	ctl_fd = 0;
79 
80 void
81 kernel_init(void)
82 {
83 	int retval, saved_errno;
84 
85 	ctl_fd = open(CTL_DEFAULT_DEV, O_RDWR);
86 	if (ctl_fd < 0 && errno == ENOENT) {
87 		saved_errno = errno;
88 		retval = kldload("ctl");
89 		if (retval != -1)
90 			ctl_fd = open(CTL_DEFAULT_DEV, O_RDWR);
91 		else
92 			errno = saved_errno;
93 	}
94 	if (ctl_fd < 0)
95 		log_err(1, "failed to open %s", CTL_DEFAULT_DEV);
96 }
97 
98 /*
99  * Name/value pair used for per-LUN attributes.
100  */
101 struct cctl_lun_nv {
102 	char *name;
103 	char *value;
104 	STAILQ_ENTRY(cctl_lun_nv) links;
105 };
106 
107 /*
108  * Backend LUN information.
109  */
110 struct cctl_lun {
111 	uint64_t lun_id;
112 	char *backend_type;
113 	uint64_t size_blocks;
114 	uint32_t blocksize;
115 	char *serial_number;
116 	char *device_id;
117 	char *cfiscsi_target;
118 	int cfiscsi_lun;
119 	STAILQ_HEAD(,cctl_lun_nv) attr_list;
120 	STAILQ_ENTRY(cctl_lun) links;
121 };
122 
123 struct cctl_port {
124 	uint32_t port_id;
125 	int cfiscsi_status;
126 	char *cfiscsi_target;
127 	uint16_t cfiscsi_portal_group_tag;
128 	STAILQ_HEAD(,cctl_lun_nv) attr_list;
129 	STAILQ_ENTRY(cctl_port) links;
130 };
131 
132 struct cctl_devlist_data {
133 	int num_luns;
134 	STAILQ_HEAD(,cctl_lun) lun_list;
135 	struct cctl_lun *cur_lun;
136 	int num_ports;
137 	STAILQ_HEAD(,cctl_port) port_list;
138 	struct cctl_port *cur_port;
139 	int level;
140 	struct sbuf *cur_sb[32];
141 };
142 
143 static void
144 cctl_start_element(void *user_data, const char *name, const char **attr)
145 {
146 	int i;
147 	struct cctl_devlist_data *devlist;
148 	struct cctl_lun *cur_lun;
149 
150 	devlist = (struct cctl_devlist_data *)user_data;
151 	cur_lun = devlist->cur_lun;
152 	devlist->level++;
153 	if ((u_int)devlist->level >= (sizeof(devlist->cur_sb) /
154 	    sizeof(devlist->cur_sb[0])))
155 		log_errx(1, "%s: too many nesting levels, %zd max", __func__,
156 		     sizeof(devlist->cur_sb) / sizeof(devlist->cur_sb[0]));
157 
158 	devlist->cur_sb[devlist->level] = sbuf_new_auto();
159 	if (devlist->cur_sb[devlist->level] == NULL)
160 		log_err(1, "%s: unable to allocate sbuf", __func__);
161 
162 	if (strcmp(name, "lun") == 0) {
163 		if (cur_lun != NULL)
164 			log_errx(1, "%s: improper lun element nesting",
165 			    __func__);
166 
167 		cur_lun = calloc(1, sizeof(*cur_lun));
168 		if (cur_lun == NULL)
169 			log_err(1, "%s: cannot allocate %zd bytes", __func__,
170 			    sizeof(*cur_lun));
171 
172 		devlist->num_luns++;
173 		devlist->cur_lun = cur_lun;
174 
175 		STAILQ_INIT(&cur_lun->attr_list);
176 		STAILQ_INSERT_TAIL(&devlist->lun_list, cur_lun, links);
177 
178 		for (i = 0; attr[i] != NULL; i += 2) {
179 			if (strcmp(attr[i], "id") == 0) {
180 				cur_lun->lun_id = strtoull(attr[i+1], NULL, 0);
181 			} else {
182 				log_errx(1, "%s: invalid LUN attribute %s = %s",
183 				     __func__, attr[i], attr[i+1]);
184 			}
185 		}
186 	}
187 }
188 
189 static void
190 cctl_end_element(void *user_data, const char *name)
191 {
192 	struct cctl_devlist_data *devlist;
193 	struct cctl_lun *cur_lun;
194 	char *str;
195 
196 	devlist = (struct cctl_devlist_data *)user_data;
197 	cur_lun = devlist->cur_lun;
198 
199 	if ((cur_lun == NULL)
200 	 && (strcmp(name, "ctllunlist") != 0))
201 		log_errx(1, "%s: cur_lun == NULL! (name = %s)", __func__, name);
202 
203 	if (devlist->cur_sb[devlist->level] == NULL)
204 		log_errx(1, "%s: no valid sbuf at level %d (name %s)", __func__,
205 		     devlist->level, name);
206 
207 	sbuf_finish(devlist->cur_sb[devlist->level]);
208 	str = checked_strdup(sbuf_data(devlist->cur_sb[devlist->level]));
209 
210 	if (strlen(str) == 0) {
211 		free(str);
212 		str = NULL;
213 	}
214 
215 	sbuf_delete(devlist->cur_sb[devlist->level]);
216 	devlist->cur_sb[devlist->level] = NULL;
217 	devlist->level--;
218 
219 	if (strcmp(name, "backend_type") == 0) {
220 		cur_lun->backend_type = str;
221 		str = NULL;
222 	} else if (strcmp(name, "size") == 0) {
223 		cur_lun->size_blocks = strtoull(str, NULL, 0);
224 	} else if (strcmp(name, "blocksize") == 0) {
225 		cur_lun->blocksize = strtoul(str, NULL, 0);
226 	} else if (strcmp(name, "serial_number") == 0) {
227 		cur_lun->serial_number = str;
228 		str = NULL;
229 	} else if (strcmp(name, "device_id") == 0) {
230 		cur_lun->device_id = str;
231 		str = NULL;
232 	} else if (strcmp(name, "cfiscsi_target") == 0) {
233 		cur_lun->cfiscsi_target = str;
234 		str = NULL;
235 	} else if (strcmp(name, "cfiscsi_lun") == 0) {
236 		cur_lun->cfiscsi_lun = strtoul(str, NULL, 0);
237 	} else if (strcmp(name, "lun") == 0) {
238 		devlist->cur_lun = NULL;
239 	} else if (strcmp(name, "ctllunlist") == 0) {
240 
241 	} else {
242 		struct cctl_lun_nv *nv;
243 
244 		nv = calloc(1, sizeof(*nv));
245 		if (nv == NULL)
246 			log_err(1, "%s: can't allocate %zd bytes for nv pair",
247 			    __func__, sizeof(*nv));
248 
249 		nv->name = checked_strdup(name);
250 
251 		nv->value = str;
252 		str = NULL;
253 		STAILQ_INSERT_TAIL(&cur_lun->attr_list, nv, links);
254 	}
255 
256 	free(str);
257 }
258 
259 static void
260 cctl_start_pelement(void *user_data, const char *name, const char **attr)
261 {
262 	int i;
263 	struct cctl_devlist_data *devlist;
264 	struct cctl_port *cur_port;
265 
266 	devlist = (struct cctl_devlist_data *)user_data;
267 	cur_port = devlist->cur_port;
268 	devlist->level++;
269 	if ((u_int)devlist->level >= (sizeof(devlist->cur_sb) /
270 	    sizeof(devlist->cur_sb[0])))
271 		log_errx(1, "%s: too many nesting levels, %zd max", __func__,
272 		     sizeof(devlist->cur_sb) / sizeof(devlist->cur_sb[0]));
273 
274 	devlist->cur_sb[devlist->level] = sbuf_new_auto();
275 	if (devlist->cur_sb[devlist->level] == NULL)
276 		log_err(1, "%s: unable to allocate sbuf", __func__);
277 
278 	if (strcmp(name, "targ_port") == 0) {
279 		if (cur_port != NULL)
280 			log_errx(1, "%s: improper port element nesting (%s)",
281 			    __func__, name);
282 
283 		cur_port = calloc(1, sizeof(*cur_port));
284 		if (cur_port == NULL)
285 			log_err(1, "%s: cannot allocate %zd bytes", __func__,
286 			    sizeof(*cur_port));
287 
288 		devlist->num_ports++;
289 		devlist->cur_port = cur_port;
290 
291 		STAILQ_INIT(&cur_port->attr_list);
292 		STAILQ_INSERT_TAIL(&devlist->port_list, cur_port, links);
293 
294 		for (i = 0; attr[i] != NULL; i += 2) {
295 			if (strcmp(attr[i], "id") == 0) {
296 				cur_port->port_id = strtoul(attr[i+1], NULL, 0);
297 			} else {
298 				log_errx(1, "%s: invalid LUN attribute %s = %s",
299 				     __func__, attr[i], attr[i+1]);
300 			}
301 		}
302 	}
303 }
304 
305 static void
306 cctl_end_pelement(void *user_data, const char *name)
307 {
308 	struct cctl_devlist_data *devlist;
309 	struct cctl_port *cur_port;
310 	char *str;
311 
312 	devlist = (struct cctl_devlist_data *)user_data;
313 	cur_port = devlist->cur_port;
314 
315 	if ((cur_port == NULL)
316 	 && (strcmp(name, "ctlportlist") != 0))
317 		log_errx(1, "%s: cur_port == NULL! (name = %s)", __func__, name);
318 
319 	if (devlist->cur_sb[devlist->level] == NULL)
320 		log_errx(1, "%s: no valid sbuf at level %d (name %s)", __func__,
321 		     devlist->level, name);
322 
323 	sbuf_finish(devlist->cur_sb[devlist->level]);
324 	str = checked_strdup(sbuf_data(devlist->cur_sb[devlist->level]));
325 
326 	if (strlen(str) == 0) {
327 		free(str);
328 		str = NULL;
329 	}
330 
331 	sbuf_delete(devlist->cur_sb[devlist->level]);
332 	devlist->cur_sb[devlist->level] = NULL;
333 	devlist->level--;
334 
335 	if (strcmp(name, "cfiscsi_target") == 0) {
336 		cur_port->cfiscsi_target = str;
337 		str = NULL;
338 	} else if (strcmp(name, "cfiscsi_status") == 0) {
339 		cur_port->cfiscsi_status = strtoul(str, NULL, 0);
340 	} else if (strcmp(name, "cfiscsi_portal_group_tag") == 0) {
341 		cur_port->cfiscsi_portal_group_tag = strtoul(str, NULL, 0);
342 	} else if (strcmp(name, "targ_port") == 0) {
343 		devlist->cur_port = NULL;
344 	} else if (strcmp(name, "ctlportlist") == 0) {
345 
346 	} else {
347 		struct cctl_lun_nv *nv;
348 
349 		nv = calloc(1, sizeof(*nv));
350 		if (nv == NULL)
351 			log_err(1, "%s: can't allocate %zd bytes for nv pair",
352 			    __func__, sizeof(*nv));
353 
354 		nv->name = checked_strdup(name);
355 
356 		nv->value = str;
357 		str = NULL;
358 		STAILQ_INSERT_TAIL(&cur_port->attr_list, nv, links);
359 	}
360 
361 	free(str);
362 }
363 
364 static void
365 cctl_char_handler(void *user_data, const XML_Char *str, int len)
366 {
367 	struct cctl_devlist_data *devlist;
368 
369 	devlist = (struct cctl_devlist_data *)user_data;
370 
371 	sbuf_bcat(devlist->cur_sb[devlist->level], str, len);
372 }
373 
374 struct conf *
375 conf_new_from_kernel(void)
376 {
377 	struct conf *conf = NULL;
378 	struct target *targ;
379 	struct lun *cl;
380 	struct lun_option *lo;
381 	struct ctl_lun_list list;
382 	struct cctl_devlist_data devlist;
383 	struct cctl_lun *lun;
384 	struct cctl_port *port;
385 	XML_Parser parser;
386 	char *str;
387 	int len, retval;
388 
389 	bzero(&devlist, sizeof(devlist));
390 	STAILQ_INIT(&devlist.lun_list);
391 	STAILQ_INIT(&devlist.port_list);
392 
393 	log_debugx("obtaining previously configured CTL luns from the kernel");
394 
395 	str = NULL;
396 	len = 4096;
397 retry:
398 	str = realloc(str, len);
399 	if (str == NULL)
400 		log_err(1, "realloc");
401 
402 	bzero(&list, sizeof(list));
403 	list.alloc_len = len;
404 	list.status = CTL_LUN_LIST_NONE;
405 	list.lun_xml = str;
406 
407 	if (ioctl(ctl_fd, CTL_LUN_LIST, &list) == -1) {
408 		log_warn("error issuing CTL_LUN_LIST ioctl");
409 		free(str);
410 		return (NULL);
411 	}
412 
413 	if (list.status == CTL_LUN_LIST_ERROR) {
414 		log_warnx("error returned from CTL_LUN_LIST ioctl: %s",
415 		    list.error_str);
416 		free(str);
417 		return (NULL);
418 	}
419 
420 	if (list.status == CTL_LUN_LIST_NEED_MORE_SPACE) {
421 		len = len << 1;
422 		goto retry;
423 	}
424 
425 	parser = XML_ParserCreate(NULL);
426 	if (parser == NULL) {
427 		log_warnx("unable to create XML parser");
428 		free(str);
429 		return (NULL);
430 	}
431 
432 	XML_SetUserData(parser, &devlist);
433 	XML_SetElementHandler(parser, cctl_start_element, cctl_end_element);
434 	XML_SetCharacterDataHandler(parser, cctl_char_handler);
435 
436 	retval = XML_Parse(parser, str, strlen(str), 1);
437 	XML_ParserFree(parser);
438 	free(str);
439 	if (retval != 1) {
440 		log_warnx("XML_Parse failed");
441 		return (NULL);
442 	}
443 
444 	str = NULL;
445 	len = 4096;
446 retry_port:
447 	str = realloc(str, len);
448 	if (str == NULL)
449 		log_err(1, "realloc");
450 
451 	bzero(&list, sizeof(list));
452 	list.alloc_len = len;
453 	list.status = CTL_LUN_LIST_NONE;
454 	list.lun_xml = str;
455 
456 	if (ioctl(ctl_fd, CTL_PORT_LIST, &list) == -1) {
457 		log_warn("error issuing CTL_PORT_LIST ioctl");
458 		free(str);
459 		return (NULL);
460 	}
461 
462 	if (list.status == CTL_PORT_LIST_ERROR) {
463 		log_warnx("error returned from CTL_PORT_LIST ioctl: %s",
464 		    list.error_str);
465 		free(str);
466 		return (NULL);
467 	}
468 
469 	if (list.status == CTL_LUN_LIST_NEED_MORE_SPACE) {
470 		len = len << 1;
471 		goto retry_port;
472 	}
473 
474 	parser = XML_ParserCreate(NULL);
475 	if (parser == NULL) {
476 		log_warnx("unable to create XML parser");
477 		free(str);
478 		return (NULL);
479 	}
480 
481 	XML_SetUserData(parser, &devlist);
482 	XML_SetElementHandler(parser, cctl_start_pelement, cctl_end_pelement);
483 	XML_SetCharacterDataHandler(parser, cctl_char_handler);
484 
485 	retval = XML_Parse(parser, str, strlen(str), 1);
486 	XML_ParserFree(parser);
487 	free(str);
488 	if (retval != 1) {
489 		log_warnx("XML_Parse failed");
490 		return (NULL);
491 	}
492 
493 	conf = conf_new();
494 
495 	STAILQ_FOREACH(port, &devlist.port_list, links) {
496 
497 		if (port->cfiscsi_target == NULL) {
498 			log_debugx("CTL port %ju wasn't managed by ctld; "
499 			    "ignoring", (uintmax_t)port->port_id);
500 			continue;
501 		}
502 		if (port->cfiscsi_status != 1) {
503 			log_debugx("CTL port %ju is not active (%d); ignoring",
504 			    (uintmax_t)port->port_id, port->cfiscsi_status);
505 			continue;
506 		}
507 
508 		targ = target_find(conf, port->cfiscsi_target);
509 		if (targ == NULL) {
510 #if 0
511 			log_debugx("found new kernel target %s for CTL port %ld",
512 			    port->cfiscsi_target, port->port_id);
513 #endif
514 			targ = target_new(conf, port->cfiscsi_target);
515 			if (targ == NULL) {
516 				log_warnx("target_new failed");
517 				continue;
518 			}
519 		}
520 	}
521 
522 	STAILQ_FOREACH(lun, &devlist.lun_list, links) {
523 		struct cctl_lun_nv *nv;
524 
525 		if (lun->cfiscsi_target == NULL) {
526 			log_debugx("CTL lun %ju wasn't managed by ctld; "
527 			    "ignoring", (uintmax_t)lun->lun_id);
528 			continue;
529 		}
530 
531 		targ = target_find(conf, lun->cfiscsi_target);
532 		if (targ == NULL) {
533 #if 0
534 			log_debugx("found new kernel target %s for CTL lun %ld",
535 			    lun->cfiscsi_target, lun->lun_id);
536 #endif
537 			targ = target_new(conf, lun->cfiscsi_target);
538 			if (targ == NULL) {
539 				log_warnx("target_new failed");
540 				continue;
541 			}
542 		}
543 
544 		cl = lun_find(targ, lun->cfiscsi_lun);
545 		if (cl != NULL) {
546 			log_warnx("found CTL lun %ju, backing lun %d, target "
547 			    "%s, also backed by CTL lun %d; ignoring",
548 			    (uintmax_t) lun->lun_id, cl->l_lun,
549 			    cl->l_target->t_name, cl->l_ctl_lun);
550 			continue;
551 		}
552 
553 		log_debugx("found CTL lun %ju, backing lun %d, target %s",
554 		    (uintmax_t)lun->lun_id, lun->cfiscsi_lun, lun->cfiscsi_target);
555 
556 		cl = lun_new(targ, lun->cfiscsi_lun);
557 		if (cl == NULL) {
558 			log_warnx("lun_new failed");
559 			continue;
560 		}
561 		lun_set_backend(cl, lun->backend_type);
562 		lun_set_blocksize(cl, lun->blocksize);
563 		lun_set_device_id(cl, lun->device_id);
564 		lun_set_serial(cl, lun->serial_number);
565 		lun_set_size(cl, lun->size_blocks * cl->l_blocksize);
566 		lun_set_ctl_lun(cl, lun->lun_id);
567 
568 		STAILQ_FOREACH(nv, &lun->attr_list, links) {
569 			if (strcmp(nv->name, "file") == 0 ||
570 			    strcmp(nv->name, "dev") == 0) {
571 				lun_set_path(cl, nv->value);
572 				continue;
573 			}
574 			lo = lun_option_new(cl, nv->name, nv->value);
575 			if (lo == NULL)
576 				log_warnx("unable to add CTL lun option %s "
577 				    "for CTL lun %ju for lun %d, target %s",
578 				    nv->name, (uintmax_t) lun->lun_id,
579 				    cl->l_lun, cl->l_target->t_name);
580 		}
581 	}
582 
583 	return (conf);
584 }
585 
586 static void
587 str_arg(struct ctl_be_arg *arg, const char *name, const char *value)
588 {
589 
590 	arg->namelen = strlen(name) + 1;
591 	arg->name = __DECONST(char *, name);
592 	arg->vallen = strlen(value) + 1;
593 	arg->value = __DECONST(char *, value);
594 	arg->flags = CTL_BEARG_ASCII | CTL_BEARG_RD;
595 }
596 
597 int
598 kernel_lun_add(struct lun *lun)
599 {
600 	struct lun_option *lo;
601 	struct ctl_lun_req req;
602 	char *tmp;
603 	int error, i, num_options;
604 
605 	bzero(&req, sizeof(req));
606 
607 	strlcpy(req.backend, lun->l_backend, sizeof(req.backend));
608 	req.reqtype = CTL_LUNREQ_CREATE;
609 
610 	req.reqdata.create.blocksize_bytes = lun->l_blocksize;
611 
612 	if (lun->l_size != 0)
613 		req.reqdata.create.lun_size_bytes = lun->l_size;
614 
615 	req.reqdata.create.flags |= CTL_LUN_FLAG_DEV_TYPE;
616 	req.reqdata.create.device_type = T_DIRECT;
617 
618 	if (lun->l_serial != NULL) {
619 		strncpy(req.reqdata.create.serial_num, lun->l_serial,
620 			sizeof(req.reqdata.create.serial_num));
621 		req.reqdata.create.flags |= CTL_LUN_FLAG_SERIAL_NUM;
622 	}
623 
624 	if (lun->l_device_id != NULL) {
625 		strncpy(req.reqdata.create.device_id, lun->l_device_id,
626 			sizeof(req.reqdata.create.device_id));
627 		req.reqdata.create.flags |= CTL_LUN_FLAG_DEVID;
628 	}
629 
630 	if (lun->l_path != NULL) {
631 		lo = lun_option_find(lun, "file");
632 		if (lo != NULL) {
633 			lun_option_set(lo, lun->l_path);
634 		} else {
635 			lo = lun_option_new(lun, "file", lun->l_path);
636 			assert(lo != NULL);
637 		}
638 	}
639 
640 	lo = lun_option_find(lun, "cfiscsi_target");
641 	if (lo != NULL) {
642 		lun_option_set(lo, lun->l_target->t_name);
643 	} else {
644 		lo = lun_option_new(lun, "cfiscsi_target",
645 		    lun->l_target->t_name);
646 		assert(lo != NULL);
647 	}
648 
649 	asprintf(&tmp, "%d", lun->l_lun);
650 	if (tmp == NULL)
651 		log_errx(1, "asprintf");
652 	lo = lun_option_find(lun, "cfiscsi_lun");
653 	if (lo != NULL) {
654 		lun_option_set(lo, tmp);
655 		free(tmp);
656 	} else {
657 		lo = lun_option_new(lun, "cfiscsi_lun", tmp);
658 		free(tmp);
659 		assert(lo != NULL);
660 	}
661 
662 	asprintf(&tmp, "%s,lun,%d", lun->l_target->t_name, lun->l_lun);
663 	if (tmp == NULL)
664 		log_errx(1, "asprintf");
665 	lo = lun_option_find(lun, "scsiname");
666 	if (lo != NULL) {
667 		lun_option_set(lo, tmp);
668 		free(tmp);
669 	} else {
670 		lo = lun_option_new(lun, "scsiname", tmp);
671 		free(tmp);
672 		assert(lo != NULL);
673 	}
674 
675 	num_options = 0;
676 	TAILQ_FOREACH(lo, &lun->l_options, lo_next)
677 		num_options++;
678 
679 	req.num_be_args = num_options;
680 	if (num_options > 0) {
681 		req.be_args = malloc(num_options * sizeof(*req.be_args));
682 		if (req.be_args == NULL) {
683 			log_warn("error allocating %zd bytes",
684 			    num_options * sizeof(*req.be_args));
685 			return (1);
686 		}
687 
688 		i = 0;
689 		TAILQ_FOREACH(lo, &lun->l_options, lo_next) {
690 			str_arg(&req.be_args[i], lo->lo_name, lo->lo_value);
691 			i++;
692 		}
693 		assert(i == num_options);
694 	}
695 
696 	error = ioctl(ctl_fd, CTL_LUN_REQ, &req);
697 	free(req.be_args);
698 	if (error != 0) {
699 		log_warn("error issuing CTL_LUN_REQ ioctl");
700 		return (1);
701 	}
702 
703 	switch (req.status) {
704 	case CTL_LUN_ERROR:
705 		log_warnx("LUN creation error: %s", req.error_str);
706 		return (1);
707 	case CTL_LUN_WARNING:
708 		log_warnx("LUN creation warning: %s", req.error_str);
709 		break;
710 	case CTL_LUN_OK:
711 		break;
712 	default:
713 		log_warnx("unknown LUN creation status: %d",
714 		    req.status);
715 		return (1);
716 	}
717 
718 	lun_set_ctl_lun(lun, req.reqdata.create.req_lun_id);
719 	return (0);
720 }
721 
722 int
723 kernel_lun_resize(struct lun *lun)
724 {
725 	struct ctl_lun_req req;
726 
727 	bzero(&req, sizeof(req));
728 
729 	strlcpy(req.backend, lun->l_backend, sizeof(req.backend));
730 	req.reqtype = CTL_LUNREQ_MODIFY;
731 
732 	req.reqdata.modify.lun_id = lun->l_ctl_lun;
733 	req.reqdata.modify.lun_size_bytes = lun->l_size;
734 
735 	if (ioctl(ctl_fd, CTL_LUN_REQ, &req) == -1) {
736 		log_warn("error issuing CTL_LUN_REQ ioctl");
737 		return (1);
738 	}
739 
740 	switch (req.status) {
741 	case CTL_LUN_ERROR:
742 		log_warnx("LUN modification error: %s", req.error_str);
743 		return (1);
744 	case CTL_LUN_WARNING:
745 		log_warnx("LUN modification warning: %s", req.error_str);
746 		break;
747 	case CTL_LUN_OK:
748 		break;
749 	default:
750 		log_warnx("unknown LUN modification status: %d",
751 		    req.status);
752 		return (1);
753 	}
754 
755 	return (0);
756 }
757 
758 int
759 kernel_lun_remove(struct lun *lun)
760 {
761 	struct ctl_lun_req req;
762 
763 	bzero(&req, sizeof(req));
764 
765 	strlcpy(req.backend, lun->l_backend, sizeof(req.backend));
766 	req.reqtype = CTL_LUNREQ_RM;
767 
768 	req.reqdata.rm.lun_id = lun->l_ctl_lun;
769 
770 	if (ioctl(ctl_fd, CTL_LUN_REQ, &req) == -1) {
771 		log_warn("error issuing CTL_LUN_REQ ioctl");
772 		return (1);
773 	}
774 
775 	switch (req.status) {
776 	case CTL_LUN_ERROR:
777 		log_warnx("LUN removal error: %s", req.error_str);
778 		return (1);
779 	case CTL_LUN_WARNING:
780 		log_warnx("LUN removal warning: %s", req.error_str);
781 		break;
782 	case CTL_LUN_OK:
783 		break;
784 	default:
785 		log_warnx("unknown LUN removal status: %d", req.status);
786 		return (1);
787 	}
788 
789 	return (0);
790 }
791 
792 void
793 kernel_handoff(struct connection *conn)
794 {
795 	struct ctl_iscsi req;
796 
797 	bzero(&req, sizeof(req));
798 
799 	req.type = CTL_ISCSI_HANDOFF;
800 	strlcpy(req.data.handoff.initiator_name,
801 	    conn->conn_initiator_name, sizeof(req.data.handoff.initiator_name));
802 	strlcpy(req.data.handoff.initiator_addr,
803 	    conn->conn_initiator_addr, sizeof(req.data.handoff.initiator_addr));
804 	if (conn->conn_initiator_alias != NULL) {
805 		strlcpy(req.data.handoff.initiator_alias,
806 		    conn->conn_initiator_alias, sizeof(req.data.handoff.initiator_alias));
807 	}
808 	memcpy(req.data.handoff.initiator_isid, conn->conn_initiator_isid,
809 	    sizeof(req.data.handoff.initiator_isid));
810 	strlcpy(req.data.handoff.target_name,
811 	    conn->conn_target->t_name, sizeof(req.data.handoff.target_name));
812 #ifdef ICL_KERNEL_PROXY
813 	if (proxy_mode)
814 		req.data.handoff.connection_id = conn->conn_socket;
815 	else
816 		req.data.handoff.socket = conn->conn_socket;
817 #else
818 	req.data.handoff.socket = conn->conn_socket;
819 #endif
820 	req.data.handoff.portal_group_tag =
821 	    conn->conn_portal->p_portal_group->pg_tag;
822 	if (conn->conn_header_digest == CONN_DIGEST_CRC32C)
823 		req.data.handoff.header_digest = CTL_ISCSI_DIGEST_CRC32C;
824 	if (conn->conn_data_digest == CONN_DIGEST_CRC32C)
825 		req.data.handoff.data_digest = CTL_ISCSI_DIGEST_CRC32C;
826 	req.data.handoff.cmdsn = conn->conn_cmdsn;
827 	req.data.handoff.statsn = conn->conn_statsn;
828 	req.data.handoff.max_recv_data_segment_length =
829 	    conn->conn_max_data_segment_length;
830 	req.data.handoff.max_burst_length = conn->conn_max_burst_length;
831 	req.data.handoff.immediate_data = conn->conn_immediate_data;
832 
833 	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) {
834 		log_err(1, "error issuing CTL_ISCSI ioctl; "
835 		    "dropping connection");
836 	}
837 
838 	if (req.status != CTL_ISCSI_OK) {
839 		log_errx(1, "error returned from CTL iSCSI handoff request: "
840 		    "%s; dropping connection", req.error_str);
841 	}
842 }
843 
844 int
845 kernel_port_add(struct target *targ)
846 {
847 	struct ctl_port_entry entry;
848 	struct ctl_req req;
849 	char tagstr[16];
850 	int error;
851 	uint32_t port_id = -1;
852 
853 	bzero(&req, sizeof(req));
854 	strlcpy(req.driver, "iscsi", sizeof(req.driver));
855 	req.reqtype = CTL_REQ_CREATE;
856 	req.num_args = 4;
857 	req.args = malloc(req.num_args * sizeof(*req.args));
858 	req.args[0].namelen = sizeof("port_id");
859 	req.args[0].name = __DECONST(char *, "port_id");
860 	req.args[0].vallen = sizeof(port_id);
861 	req.args[0].value = &port_id;
862 	req.args[0].flags = CTL_BEARG_WR;
863 	str_arg(&req.args[1], "cfiscsi_target", targ->t_name);
864 	snprintf(tagstr, sizeof(tagstr), "%d", targ->t_portal_group->pg_tag);
865 	str_arg(&req.args[2], "cfiscsi_portal_group_tag", tagstr);
866 	if (targ->t_alias)
867 		str_arg(&req.args[3], "cfiscsi_target_alias", targ->t_alias);
868 	else
869 		req.num_args--;
870 
871 	error = ioctl(ctl_fd, CTL_PORT_REQ, &req);
872 	free(req.args);
873 	if (error != 0) {
874 		log_warn("error issuing CTL_PORT_REQ ioctl");
875 		return (1);
876 	}
877 
878 	if (req.status == CTL_LUN_ERROR) {
879 		log_warnx("error returned from port creation request: %s",
880 		    req.error_str);
881 		return (1);
882 	}
883 
884 	if (req.status != CTL_LUN_OK) {
885 		log_warnx("unknown port creation request status %d",
886 		    req.status);
887 		return (1);
888 	}
889 
890 	bzero(&entry, sizeof(entry));
891 	entry.targ_port = port_id;
892 
893 	error = ioctl(ctl_fd, CTL_ENABLE_PORT, &entry);
894 	if (error != 0) {
895 		log_warn("CTL_ENABLE_PORT ioctl failed");
896 		return (-1);
897 	}
898 
899 	return (0);
900 }
901 
902 int
903 kernel_port_remove(struct target *targ)
904 {
905 	struct ctl_req req;
906 	char tagstr[16];
907 	int error;
908 
909 	bzero(&req, sizeof(req));
910 	strlcpy(req.driver, "iscsi", sizeof(req.driver));
911 	req.reqtype = CTL_REQ_REMOVE;
912 	req.num_args = 2;
913 	req.args = malloc(req.num_args * sizeof(*req.args));
914 	str_arg(&req.args[0], "cfiscsi_target", targ->t_name);
915 	if (targ->t_portal_group) {
916 		snprintf(tagstr, sizeof(tagstr), "%d",
917 		    targ->t_portal_group->pg_tag);
918 		str_arg(&req.args[1], "cfiscsi_portal_group_tag", tagstr);
919 	} else
920 		req.num_args--;
921 
922 	error = ioctl(ctl_fd, CTL_PORT_REQ, &req);
923 	free(req.args);
924 	if (error != 0) {
925 		log_warn("error issuing CTL_PORT_REQ ioctl");
926 		return (1);
927 	}
928 
929 	if (req.status == CTL_LUN_ERROR) {
930 		log_warnx("error returned from port removal request: %s",
931 		    req.error_str);
932 		return (1);
933 	}
934 
935 	if (req.status != CTL_LUN_OK) {
936 		log_warnx("unknown port removal request status %d",
937 		    req.status);
938 		return (1);
939 	}
940 
941 	return (0);
942 }
943 
944 #ifdef ICL_KERNEL_PROXY
945 void
946 kernel_listen(struct addrinfo *ai, bool iser, int portal_id)
947 {
948 	struct ctl_iscsi req;
949 
950 	bzero(&req, sizeof(req));
951 
952 	req.type = CTL_ISCSI_LISTEN;
953 	req.data.listen.iser = iser;
954 	req.data.listen.domain = ai->ai_family;
955 	req.data.listen.socktype = ai->ai_socktype;
956 	req.data.listen.protocol = ai->ai_protocol;
957 	req.data.listen.addr = ai->ai_addr;
958 	req.data.listen.addrlen = ai->ai_addrlen;
959 	req.data.listen.portal_id = portal_id;
960 
961 	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1)
962 		log_err(1, "error issuing CTL_ISCSI ioctl");
963 
964 	if (req.status != CTL_ISCSI_OK) {
965 		log_errx(1, "error returned from CTL iSCSI listen: %s",
966 		    req.error_str);
967 	}
968 }
969 
970 void
971 kernel_accept(int *connection_id, int *portal_id,
972     struct sockaddr *client_sa, socklen_t *client_salen)
973 {
974 	struct ctl_iscsi req;
975 	struct sockaddr_storage ss;
976 
977 	bzero(&req, sizeof(req));
978 
979 	req.type = CTL_ISCSI_ACCEPT;
980 	req.data.accept.initiator_addr = (struct sockaddr *)&ss;
981 
982 	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1)
983 		log_err(1, "error issuing CTL_ISCSI ioctl");
984 
985 	if (req.status != CTL_ISCSI_OK) {
986 		log_errx(1, "error returned from CTL iSCSI accept: %s",
987 		    req.error_str);
988 	}
989 
990 	*connection_id = req.data.accept.connection_id;
991 	*portal_id = req.data.accept.portal_id;
992 	*client_salen = req.data.accept.initiator_addrlen;
993 	memcpy(client_sa, &ss, *client_salen);
994 }
995 
996 void
997 kernel_send(struct pdu *pdu)
998 {
999 	struct ctl_iscsi req;
1000 
1001 	bzero(&req, sizeof(req));
1002 
1003 	req.type = CTL_ISCSI_SEND;
1004 	req.data.send.connection_id = pdu->pdu_connection->conn_socket;
1005 	req.data.send.bhs = pdu->pdu_bhs;
1006 	req.data.send.data_segment_len = pdu->pdu_data_len;
1007 	req.data.send.data_segment = pdu->pdu_data;
1008 
1009 	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) {
1010 		log_err(1, "error issuing CTL_ISCSI ioctl; "
1011 		    "dropping connection");
1012 	}
1013 
1014 	if (req.status != CTL_ISCSI_OK) {
1015 		log_errx(1, "error returned from CTL iSCSI send: "
1016 		    "%s; dropping connection", req.error_str);
1017 	}
1018 }
1019 
1020 void
1021 kernel_receive(struct pdu *pdu)
1022 {
1023 	struct ctl_iscsi req;
1024 
1025 	pdu->pdu_data = malloc(MAX_DATA_SEGMENT_LENGTH);
1026 	if (pdu->pdu_data == NULL)
1027 		log_err(1, "malloc");
1028 
1029 	bzero(&req, sizeof(req));
1030 
1031 	req.type = CTL_ISCSI_RECEIVE;
1032 	req.data.receive.connection_id = pdu->pdu_connection->conn_socket;
1033 	req.data.receive.bhs = pdu->pdu_bhs;
1034 	req.data.receive.data_segment_len = MAX_DATA_SEGMENT_LENGTH;
1035 	req.data.receive.data_segment = pdu->pdu_data;
1036 
1037 	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) {
1038 		log_err(1, "error issuing CTL_ISCSI ioctl; "
1039 		    "dropping connection");
1040 	}
1041 
1042 	if (req.status != CTL_ISCSI_OK) {
1043 		log_errx(1, "error returned from CTL iSCSI receive: "
1044 		    "%s; dropping connection", req.error_str);
1045 	}
1046 
1047 }
1048 
1049 #endif /* ICL_KERNEL_PROXY */
1050 
1051 /*
1052  * XXX: I CANT INTO LATIN
1053  */
1054 void
1055 kernel_capsicate(void)
1056 {
1057 	int error;
1058 	cap_rights_t rights;
1059 	const unsigned long cmds[] = { CTL_ISCSI };
1060 
1061 	cap_rights_init(&rights, CAP_IOCTL);
1062 	error = cap_rights_limit(ctl_fd, &rights);
1063 	if (error != 0 && errno != ENOSYS)
1064 		log_err(1, "cap_rights_limit");
1065 
1066 	error = cap_ioctls_limit(ctl_fd, cmds,
1067 	    sizeof(cmds) / sizeof(cmds[0]));
1068 	if (error != 0 && errno != ENOSYS)
1069 		log_err(1, "cap_ioctls_limit");
1070 
1071 	error = cap_enter();
1072 	if (error != 0 && errno != ENOSYS)
1073 		log_err(1, "cap_enter");
1074 
1075 	if (cap_sandboxed())
1076 		log_debugx("Capsicum capability mode enabled");
1077 	else
1078 		log_warnx("Capsicum capability mode not supported");
1079 }
1080 
1081