]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - usr.sbin/ctld/kernel.c
MFC r274853:
[FreeBSD/stable/10.git] / usr.sbin / ctld / kernel.c
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/capability.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                 /* Nothing. */
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                 /* Nothing. */
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