xref: /freebsd/usr.sbin/ctld/kernel.c (revision 84dfba8d183d31e3412639ecb4b8ad4433cf7e80)
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  * $FreeBSD$
36  */
37 
38 #include <sys/ioctl.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <sys/param.h>
42 #include <sys/linker.h>
43 #include <sys/queue.h>
44 #include <sys/callout.h>
45 #include <sys/sbuf.h>
46 #include <sys/capability.h>
47 #include <assert.h>
48 #include <bsdxml.h>
49 #include <ctype.h>
50 #include <errno.h>
51 #include <fcntl.h>
52 #include <stdint.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <strings.h>
57 #include <cam/scsi/scsi_all.h>
58 #include <cam/scsi/scsi_message.h>
59 #include <cam/ctl/ctl.h>
60 #include <cam/ctl/ctl_io.h>
61 #include <cam/ctl/ctl_frontend_internal.h>
62 #include <cam/ctl/ctl_backend.h>
63 #include <cam/ctl/ctl_ioctl.h>
64 #include <cam/ctl/ctl_backend_block.h>
65 #include <cam/ctl/ctl_util.h>
66 #include <cam/ctl/ctl_scsi_all.h>
67 
68 #ifdef ICL_KERNEL_PROXY
69 #include <netdb.h>
70 #endif
71 
72 #include "ctld.h"
73 
74 static int	ctl_fd = 0;
75 
76 void
77 kernel_init(void)
78 {
79 	int retval, saved_errno;
80 
81 	ctl_fd = open(CTL_DEFAULT_DEV, O_RDWR);
82 	if (ctl_fd < 0 && errno == ENOENT) {
83 		saved_errno = errno;
84 		retval = kldload("ctl");
85 		if (retval != -1)
86 			ctl_fd = open(CTL_DEFAULT_DEV, O_RDWR);
87 		else
88 			errno = saved_errno;
89 	}
90 	if (ctl_fd < 0)
91 		log_err(1, "failed to open %s", CTL_DEFAULT_DEV);
92 }
93 
94 /*
95  * Name/value pair used for per-LUN attributes.
96  */
97 struct cctl_lun_nv {
98 	char *name;
99 	char *value;
100 	STAILQ_ENTRY(cctl_lun_nv) links;
101 };
102 
103 /*
104  * Backend LUN information.
105  */
106 struct cctl_lun {
107 	uint64_t lun_id;
108 	char *backend_type;
109 	uint64_t size_blocks;
110 	uint32_t blocksize;
111 	char *serial_number;
112 	char *device_id;
113 	char *cfiscsi_target;
114 	char *cfiscsi_target_alias;
115 	int cfiscsi_lun;
116 	STAILQ_HEAD(,cctl_lun_nv) attr_list;
117 	STAILQ_ENTRY(cctl_lun) links;
118 };
119 
120 struct cctl_devlist_data {
121 	int num_luns;
122 	STAILQ_HEAD(,cctl_lun) lun_list;
123 	struct cctl_lun *cur_lun;
124 	int level;
125 	struct sbuf *cur_sb[32];
126 };
127 
128 static void
129 cctl_start_element(void *user_data, const char *name, const char **attr)
130 {
131 	int i;
132 	struct cctl_devlist_data *devlist;
133 	struct cctl_lun *cur_lun;
134 
135 	devlist = (struct cctl_devlist_data *)user_data;
136 	cur_lun = devlist->cur_lun;
137 	devlist->level++;
138 	if ((u_int)devlist->level >= (sizeof(devlist->cur_sb) /
139 	    sizeof(devlist->cur_sb[0])))
140 		log_errx(1, "%s: too many nesting levels, %zd max", __func__,
141 		     sizeof(devlist->cur_sb) / sizeof(devlist->cur_sb[0]));
142 
143 	devlist->cur_sb[devlist->level] = sbuf_new_auto();
144 	if (devlist->cur_sb[devlist->level] == NULL)
145 		log_err(1, "%s: unable to allocate sbuf", __func__);
146 
147 	if (strcmp(name, "lun") == 0) {
148 		if (cur_lun != NULL)
149 			log_errx(1, "%s: improper lun element nesting",
150 			    __func__);
151 
152 		cur_lun = calloc(1, sizeof(*cur_lun));
153 		if (cur_lun == NULL)
154 			log_err(1, "%s: cannot allocate %zd bytes", __func__,
155 			    sizeof(*cur_lun));
156 
157 		devlist->num_luns++;
158 		devlist->cur_lun = cur_lun;
159 
160 		STAILQ_INIT(&cur_lun->attr_list);
161 		STAILQ_INSERT_TAIL(&devlist->lun_list, cur_lun, links);
162 
163 		for (i = 0; attr[i] != NULL; i += 2) {
164 			if (strcmp(attr[i], "id") == 0) {
165 				cur_lun->lun_id = strtoull(attr[i+1], NULL, 0);
166 			} else {
167 				log_errx(1, "%s: invalid LUN attribute %s = %s",
168 				     __func__, attr[i], attr[i+1]);
169 			}
170 		}
171 	}
172 }
173 
174 static void
175 cctl_end_element(void *user_data, const char *name)
176 {
177 	struct cctl_devlist_data *devlist;
178 	struct cctl_lun *cur_lun;
179 	char *str;
180 
181 	devlist = (struct cctl_devlist_data *)user_data;
182 	cur_lun = devlist->cur_lun;
183 
184 	if ((cur_lun == NULL)
185 	 && (strcmp(name, "ctllunlist") != 0))
186 		log_errx(1, "%s: cur_lun == NULL! (name = %s)", __func__, name);
187 
188 	if (devlist->cur_sb[devlist->level] == NULL)
189 		log_errx(1, "%s: no valid sbuf at level %d (name %s)", __func__,
190 		     devlist->level, name);
191 
192 	sbuf_finish(devlist->cur_sb[devlist->level]);
193 	str = checked_strdup(sbuf_data(devlist->cur_sb[devlist->level]));
194 
195 	if (strlen(str) == 0) {
196 		free(str);
197 		str = NULL;
198 	}
199 
200 	sbuf_delete(devlist->cur_sb[devlist->level]);
201 	devlist->cur_sb[devlist->level] = NULL;
202 	devlist->level--;
203 
204 	if (strcmp(name, "backend_type") == 0) {
205 		cur_lun->backend_type = str;
206 		str = NULL;
207 	} else if (strcmp(name, "size") == 0) {
208 		cur_lun->size_blocks = strtoull(str, NULL, 0);
209 	} else if (strcmp(name, "blocksize") == 0) {
210 		cur_lun->blocksize = strtoul(str, NULL, 0);
211 	} else if (strcmp(name, "serial_number") == 0) {
212 		cur_lun->serial_number = str;
213 		str = NULL;
214 	} else if (strcmp(name, "device_id") == 0) {
215 		cur_lun->device_id = str;
216 		str = NULL;
217 	} else if (strcmp(name, "cfiscsi_target") == 0) {
218 		cur_lun->cfiscsi_target = str;
219 		str = NULL;
220 	} else if (strcmp(name, "cfiscsi_target_alias") == 0) {
221 		cur_lun->cfiscsi_target_alias = str;
222 		str = NULL;
223 	} else if (strcmp(name, "cfiscsi_lun") == 0) {
224 		cur_lun->cfiscsi_lun = strtoul(str, NULL, 0);
225 	} else if (strcmp(name, "lun") == 0) {
226 		devlist->cur_lun = NULL;
227 	} else if (strcmp(name, "ctllunlist") == 0) {
228 
229 	} else {
230 		struct cctl_lun_nv *nv;
231 
232 		nv = calloc(1, sizeof(*nv));
233 		if (nv == NULL)
234 			log_err(1, "%s: can't allocate %zd bytes for nv pair",
235 			    __func__, sizeof(*nv));
236 
237 		nv->name = checked_strdup(name);
238 
239 		nv->value = str;
240 		str = NULL;
241 		STAILQ_INSERT_TAIL(&cur_lun->attr_list, nv, links);
242 	}
243 
244 	free(str);
245 }
246 
247 static void
248 cctl_char_handler(void *user_data, const XML_Char *str, int len)
249 {
250 	struct cctl_devlist_data *devlist;
251 
252 	devlist = (struct cctl_devlist_data *)user_data;
253 
254 	sbuf_bcat(devlist->cur_sb[devlist->level], str, len);
255 }
256 
257 struct conf *
258 conf_new_from_kernel(void)
259 {
260 	struct conf *conf = NULL;
261 	struct target *targ;
262 	struct lun *cl;
263 	struct lun_option *lo;
264 	struct ctl_lun_list list;
265 	struct cctl_devlist_data devlist;
266 	struct cctl_lun *lun;
267 	XML_Parser parser;
268 	char *lun_str = NULL;
269 	int lun_len;
270 	int retval;
271 
272 	lun_len = 4096;
273 
274 	bzero(&devlist, sizeof(devlist));
275 	STAILQ_INIT(&devlist.lun_list);
276 
277 	log_debugx("obtaining previously configured CTL luns from the kernel");
278 
279 retry:
280 	lun_str = realloc(lun_str, lun_len);
281 	if (lun_str == NULL)
282 		log_err(1, "realloc");
283 
284 	bzero(&list, sizeof(list));
285 	list.alloc_len = lun_len;
286 	list.status = CTL_LUN_LIST_NONE;
287 	list.lun_xml = lun_str;
288 
289 	if (ioctl(ctl_fd, CTL_LUN_LIST, &list) == -1) {
290 		log_warn("error issuing CTL_LUN_LIST ioctl");
291 		free(lun_str);
292 		return (NULL);
293 	}
294 
295 	if (list.status == CTL_LUN_LIST_ERROR) {
296 		log_warnx("error returned from CTL_LUN_LIST ioctl: %s",
297 		    list.error_str);
298 		free(lun_str);
299 		return (NULL);
300 	}
301 
302 	if (list.status == CTL_LUN_LIST_NEED_MORE_SPACE) {
303 		lun_len = lun_len << 1;
304 		goto retry;
305 	}
306 
307 	parser = XML_ParserCreate(NULL);
308 	if (parser == NULL) {
309 		log_warnx("unable to create XML parser");
310 		free(lun_str);
311 		return (NULL);
312 	}
313 
314 	XML_SetUserData(parser, &devlist);
315 	XML_SetElementHandler(parser, cctl_start_element, cctl_end_element);
316 	XML_SetCharacterDataHandler(parser, cctl_char_handler);
317 
318 	retval = XML_Parse(parser, lun_str, strlen(lun_str), 1);
319 	XML_ParserFree(parser);
320 	free(lun_str);
321 	if (retval != 1) {
322 		log_warnx("XML_Parse failed");
323 		return (NULL);
324 	}
325 
326 	conf = conf_new();
327 
328 	STAILQ_FOREACH(lun, &devlist.lun_list, links) {
329 		struct cctl_lun_nv *nv;
330 
331 		if (lun->cfiscsi_target == NULL) {
332 			log_debugx("CTL lun %ju wasn't managed by ctld; "
333 			    "ignoring", (uintmax_t)lun->lun_id);
334 			continue;
335 		}
336 
337 		targ = target_find(conf, lun->cfiscsi_target);
338 		if (targ == NULL) {
339 #if 0
340 			log_debugx("found new kernel target %s for CTL lun %ld",
341 			    lun->cfiscsi_target, lun->lun_id);
342 #endif
343 			targ = target_new(conf, lun->cfiscsi_target);
344 			if (targ == NULL) {
345 				log_warnx("target_new failed");
346 				continue;
347 			}
348 		}
349 
350 		cl = lun_find(targ, lun->cfiscsi_lun);
351 		if (cl != NULL) {
352 			log_warnx("found CTL lun %ju, backing lun %d, target "
353 			    "%s, also backed by CTL lun %d; ignoring",
354 			    (uintmax_t) lun->lun_id, cl->l_lun,
355 			    cl->l_target->t_iqn, cl->l_ctl_lun);
356 			continue;
357 		}
358 
359 		log_debugx("found CTL lun %ju, backing lun %d, target %s",
360 		    (uintmax_t)lun->lun_id, lun->cfiscsi_lun, lun->cfiscsi_target);
361 
362 		cl = lun_new(targ, lun->cfiscsi_lun);
363 		if (cl == NULL) {
364 			log_warnx("lun_new failed");
365 			continue;
366 		}
367 		lun_set_backend(cl, lun->backend_type);
368 		lun_set_blocksize(cl, lun->blocksize);
369 		lun_set_device_id(cl, lun->device_id);
370 		lun_set_serial(cl, lun->serial_number);
371 		lun_set_size(cl, lun->size_blocks * cl->l_blocksize);
372 		lun_set_ctl_lun(cl, lun->lun_id);
373 
374 		STAILQ_FOREACH(nv, &lun->attr_list, links) {
375 			if (strcmp(nv->name, "file") == 0 ||
376 			    strcmp(nv->name, "dev") == 0) {
377 				lun_set_path(cl, nv->value);
378 				continue;
379 			}
380 			lo = lun_option_new(cl, nv->name, nv->value);
381 			if (lo == NULL)
382 				log_warnx("unable to add CTL lun option %s "
383 				    "for CTL lun %ju for lun %d, target %s",
384 				    nv->name, (uintmax_t) lun->lun_id,
385 				    cl->l_lun, cl->l_target->t_iqn);
386 		}
387 	}
388 
389 	return (conf);
390 }
391 
392 int
393 kernel_lun_add(struct lun *lun)
394 {
395 	struct lun_option *lo;
396 	struct ctl_lun_req req;
397 	char *tmp;
398 	int error, i, num_options;
399 
400 	bzero(&req, sizeof(req));
401 
402 	strlcpy(req.backend, lun->l_backend, sizeof(req.backend));
403 	req.reqtype = CTL_LUNREQ_CREATE;
404 
405 	req.reqdata.create.blocksize_bytes = lun->l_blocksize;
406 
407 	if (lun->l_size != 0)
408 		req.reqdata.create.lun_size_bytes = lun->l_size;
409 
410 	req.reqdata.create.flags |= CTL_LUN_FLAG_DEV_TYPE;
411 	req.reqdata.create.device_type = T_DIRECT;
412 
413 	if (lun->l_serial != NULL) {
414 		strlcpy(req.reqdata.create.serial_num, lun->l_serial,
415 			sizeof(req.reqdata.create.serial_num));
416 		req.reqdata.create.flags |= CTL_LUN_FLAG_SERIAL_NUM;
417 	}
418 
419 	if (lun->l_device_id != NULL) {
420 		strlcpy(req.reqdata.create.device_id, lun->l_device_id,
421 			sizeof(req.reqdata.create.device_id));
422 		req.reqdata.create.flags |= CTL_LUN_FLAG_DEVID;
423 	}
424 
425 	if (lun->l_path != NULL) {
426 		lo = lun_option_find(lun, "file");
427 		if (lo != NULL) {
428 			lun_option_set(lo, lun->l_path);
429 		} else {
430 			lo = lun_option_new(lun, "file", lun->l_path);
431 			assert(lo != NULL);
432 		}
433 	}
434 
435 	lo = lun_option_find(lun, "cfiscsi_target");
436 	if (lo != NULL) {
437 		lun_option_set(lo, lun->l_target->t_iqn);
438 	} else {
439 		lo = lun_option_new(lun, "cfiscsi_target",
440 		    lun->l_target->t_iqn);
441 		assert(lo != NULL);
442 	}
443 
444 	if (lun->l_target->t_alias != NULL) {
445 		lo = lun_option_find(lun, "cfiscsi_target_alias");
446 		if (lo != NULL) {
447 			lun_option_set(lo, lun->l_target->t_alias);
448 		} else {
449 			lo = lun_option_new(lun, "cfiscsi_target_alias",
450 			    lun->l_target->t_alias);
451 			assert(lo != NULL);
452 		}
453 	}
454 
455 	asprintf(&tmp, "%d", lun->l_lun);
456 	if (tmp == NULL)
457 		log_errx(1, "asprintf");
458 	lo = lun_option_find(lun, "cfiscsi_lun");
459 	if (lo != NULL) {
460 		lun_option_set(lo, tmp);
461 		free(tmp);
462 	} else {
463 		lo = lun_option_new(lun, "cfiscsi_lun", tmp);
464 		free(tmp);
465 		assert(lo != NULL);
466 	}
467 
468 	num_options = 0;
469 	TAILQ_FOREACH(lo, &lun->l_options, lo_next)
470 		num_options++;
471 
472 	req.num_be_args = num_options;
473 	if (num_options > 0) {
474 		req.be_args = malloc(num_options * sizeof(*req.be_args));
475 		if (req.be_args == NULL) {
476 			log_warn("error allocating %zd bytes",
477 			    num_options * sizeof(*req.be_args));
478 			return (1);
479 		}
480 
481 		i = 0;
482 		TAILQ_FOREACH(lo, &lun->l_options, lo_next) {
483 			 /*
484 			  * +1 for the terminating '\0'
485 			  */
486 			req.be_args[i].namelen = strlen(lo->lo_name) + 1;
487 			req.be_args[i].name = lo->lo_name;
488 			req.be_args[i].vallen = strlen(lo->lo_value) + 1;
489 			req.be_args[i].value = lo->lo_value;
490 			req.be_args[i].flags = CTL_BEARG_ASCII | CTL_BEARG_RD;
491 			i++;
492 		}
493 		assert(i == num_options);
494 	}
495 
496 	error = ioctl(ctl_fd, CTL_LUN_REQ, &req);
497 	free(req.be_args);
498 	if (error != 0) {
499 		log_warn("error issuing CTL_LUN_REQ ioctl");
500 		return (1);
501 	}
502 
503 	if (req.status == CTL_LUN_ERROR) {
504 		log_warnx("error returned from LUN creation request: %s",
505 		    req.error_str);
506 		return (1);
507 	}
508 
509 	if (req.status != CTL_LUN_OK) {
510 		log_warnx("unknown LUN creation request status %d",
511 		    req.status);
512 		return (1);
513 	}
514 
515 	lun_set_ctl_lun(lun, req.reqdata.create.req_lun_id);
516 
517 	return (0);
518 }
519 
520 int
521 kernel_lun_resize(struct lun *lun)
522 {
523 	struct ctl_lun_req req;
524 
525 	bzero(&req, sizeof(req));
526 
527 	strlcpy(req.backend, lun->l_backend, sizeof(req.backend));
528 	req.reqtype = CTL_LUNREQ_MODIFY;
529 
530 	req.reqdata.modify.lun_id = lun->l_ctl_lun;
531 	req.reqdata.modify.lun_size_bytes = lun->l_size;
532 
533 	if (ioctl(ctl_fd, CTL_LUN_REQ, &req) == -1) {
534 		log_warn("error issuing CTL_LUN_REQ ioctl");
535 		return (1);
536 	}
537 
538 	if (req.status == CTL_LUN_ERROR) {
539 		log_warnx("error returned from LUN modification request: %s",
540 		    req.error_str);
541 		return (1);
542 	}
543 
544 	if (req.status != CTL_LUN_OK) {
545 		log_warnx("unknown LUN modification request status %d",
546 		    req.status);
547 		return (1);
548 	}
549 
550 	return (0);
551 }
552 
553 int
554 kernel_lun_remove(struct lun *lun)
555 {
556 	struct ctl_lun_req req;
557 
558 	bzero(&req, sizeof(req));
559 
560 	strlcpy(req.backend, lun->l_backend, sizeof(req.backend));
561 	req.reqtype = CTL_LUNREQ_RM;
562 
563 	req.reqdata.rm.lun_id = lun->l_ctl_lun;
564 
565 	if (ioctl(ctl_fd, CTL_LUN_REQ, &req) == -1) {
566 		log_warn("error issuing CTL_LUN_REQ ioctl");
567 		return (1);
568 	}
569 
570 	if (req.status == CTL_LUN_ERROR) {
571 		log_warnx("error returned from LUN removal request: %s",
572 		    req.error_str);
573 		return (1);
574 	}
575 
576 	if (req.status != CTL_LUN_OK) {
577 		log_warnx("unknown LUN removal request status %d", req.status);
578 		return (1);
579 	}
580 
581 	return (0);
582 }
583 
584 void
585 kernel_handoff(struct connection *conn)
586 {
587 	struct ctl_iscsi req;
588 
589 	bzero(&req, sizeof(req));
590 
591 	req.type = CTL_ISCSI_HANDOFF;
592 	strlcpy(req.data.handoff.initiator_name,
593 	    conn->conn_initiator_name, sizeof(req.data.handoff.initiator_name));
594 	strlcpy(req.data.handoff.initiator_addr,
595 	    conn->conn_initiator_addr, sizeof(req.data.handoff.initiator_addr));
596 	if (conn->conn_initiator_alias != NULL) {
597 		strlcpy(req.data.handoff.initiator_alias,
598 		    conn->conn_initiator_alias, sizeof(req.data.handoff.initiator_alias));
599 	}
600 	strlcpy(req.data.handoff.target_name,
601 	    conn->conn_target->t_iqn, sizeof(req.data.handoff.target_name));
602 	req.data.handoff.socket = conn->conn_socket;
603 	req.data.handoff.portal_group_tag =
604 	    conn->conn_portal->p_portal_group->pg_tag;
605 	if (conn->conn_header_digest == CONN_DIGEST_CRC32C)
606 		req.data.handoff.header_digest = CTL_ISCSI_DIGEST_CRC32C;
607 	if (conn->conn_data_digest == CONN_DIGEST_CRC32C)
608 		req.data.handoff.data_digest = CTL_ISCSI_DIGEST_CRC32C;
609 	req.data.handoff.cmdsn = conn->conn_cmdsn;
610 	req.data.handoff.statsn = conn->conn_statsn;
611 	req.data.handoff.max_recv_data_segment_length =
612 	    conn->conn_max_data_segment_length;
613 	req.data.handoff.max_burst_length = conn->conn_max_burst_length;
614 	req.data.handoff.immediate_data = conn->conn_immediate_data;
615 
616 	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1)
617 		log_err(1, "error issuing CTL_ISCSI ioctl; "
618 		    "dropping connection");
619 
620 	if (req.status != CTL_ISCSI_OK)
621 		log_errx(1, "error returned from CTL iSCSI handoff request: "
622 		    "%s; dropping connection", req.error_str);
623 }
624 
625 int
626 kernel_port_on(void)
627 {
628 	struct ctl_port_entry entry;
629 	int error;
630 
631 	bzero(&entry, sizeof(entry));
632 
633 	entry.port_type = CTL_PORT_ISCSI;
634 	entry.targ_port = -1;
635 
636 	error = ioctl(ctl_fd, CTL_ENABLE_PORT, &entry);
637 	if (error != 0) {
638 		log_warn("CTL_ENABLE_PORT ioctl failed");
639 		return (-1);
640 	}
641 
642 	return (0);
643 }
644 
645 int
646 kernel_port_off(void)
647 {
648 	struct ctl_port_entry entry;
649 	int error;
650 
651 	bzero(&entry, sizeof(entry));
652 
653 	entry.port_type = CTL_PORT_ISCSI;
654 	entry.targ_port = -1;
655 
656 	error = ioctl(ctl_fd, CTL_DISABLE_PORT, &entry);
657 	if (error != 0) {
658 		log_warn("CTL_DISABLE_PORT ioctl failed");
659 		return (-1);
660 	}
661 
662 	return (0);
663 }
664 
665 #ifdef ICL_KERNEL_PROXY
666 void
667 kernel_listen(struct addrinfo *ai, bool iser)
668 {
669 	struct ctl_iscsi req;
670 
671 	bzero(&req, sizeof(req));
672 
673 	req.type = CTL_ISCSI_LISTEN;
674 	req.data.listen.iser = iser;
675 	req.data.listen.domain = ai->ai_family;
676 	req.data.listen.socktype = ai->ai_socktype;
677 	req.data.listen.protocol = ai->ai_protocol;
678 	req.data.listen.addr = ai->ai_addr;
679 	req.data.listen.addrlen = ai->ai_addrlen;
680 
681 	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1)
682 		log_warn("error issuing CTL_ISCSI_LISTEN ioctl");
683 }
684 
685 int
686 kernel_accept(void)
687 {
688 	struct ctl_iscsi req;
689 
690 	bzero(&req, sizeof(req));
691 
692 	req.type = CTL_ISCSI_ACCEPT;
693 
694 	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) {
695 		log_warn("error issuing CTL_ISCSI_LISTEN ioctl");
696 		return (0);
697 	}
698 
699 	return (req.data.accept.connection_id);
700 }
701 
702 void
703 kernel_send(struct pdu *pdu)
704 {
705 	struct ctl_iscsi req;
706 
707 	bzero(&req, sizeof(req));
708 
709 	req.type = CTL_ISCSI_SEND;
710 	req.data.send.connection_id = pdu->pdu_connection->conn_socket;
711 	req.data.send.bhs = pdu->pdu_bhs;
712 	req.data.send.data_segment_len = pdu->pdu_data_len;
713 	req.data.send.data_segment = pdu->pdu_data;
714 
715 	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1)
716 		log_err(1, "error issuing CTL_ISCSI ioctl; "
717 		    "dropping connection");
718 
719 	if (req.status != CTL_ISCSI_OK)
720 		log_errx(1, "error returned from CTL iSCSI send: "
721 		    "%s; dropping connection", req.error_str);
722 }
723 
724 void
725 kernel_receive(struct pdu *pdu)
726 {
727 	struct ctl_iscsi req;
728 
729 	pdu->pdu_data = malloc(MAX_DATA_SEGMENT_LENGTH);
730 	if (pdu->pdu_data == NULL)
731 		log_err(1, "malloc");
732 
733 	bzero(&req, sizeof(req));
734 
735 	req.type = CTL_ISCSI_RECEIVE;
736 	req.data.receive.connection_id = pdu->pdu_connection->conn_socket;
737 	req.data.receive.bhs = pdu->pdu_bhs;
738 	req.data.receive.data_segment_len = MAX_DATA_SEGMENT_LENGTH;
739 	req.data.receive.data_segment = pdu->pdu_data;
740 
741 	if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1)
742 		log_err(1, "error issuing CTL_ISCSI ioctl; "
743 		    "dropping connection");
744 
745 	if (req.status != CTL_ISCSI_OK)
746 		log_errx(1, "error returned from CTL iSCSI receive: "
747 		    "%s; dropping connection", req.error_str);
748 
749 }
750 
751 #endif /* ICL_KERNEL_PROXY */
752 
753 /*
754  * XXX: I CANT INTO LATIN
755  */
756 void
757 kernel_capsicate(void)
758 {
759 	int error;
760 	cap_rights_t rights;
761 	const unsigned long cmds[] = { CTL_ISCSI };
762 
763 	cap_rights_init(&rights, CAP_IOCTL);
764 	error = cap_rights_limit(ctl_fd, &rights);
765 	if (error != 0 && errno != ENOSYS)
766 		log_err(1, "cap_rights_limit");
767 
768 	error = cap_ioctls_limit(ctl_fd, cmds,
769 	    sizeof(cmds) / sizeof(cmds[0]));
770 	if (error != 0 && errno != ENOSYS)
771 		log_err(1, "cap_ioctls_limit");
772 
773 	error = cap_enter();
774 	if (error != 0 && errno != ENOSYS)
775 		log_err(1, "cap_enter");
776 
777 	if (cap_sandboxed())
778 		log_debugx("Capsicum capability mode enabled");
779 	else
780 		log_warnx("Capsicum capability mode not supported");
781 }
782 
783