1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2003, 2004 Silicon Graphics International Corp. 5 * Copyright (c) 1997-2007 Kenneth D. Merry 6 * Copyright (c) 2012 The FreeBSD Foundation 7 * Copyright (c) 2017 Jakub Wojciech Klama <jceel@FreeBSD.org> 8 * All rights reserved. 9 * 10 * Portions of this software were developed by Edward Tomasz Napierala 11 * under sponsorship from the FreeBSD Foundation. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions, and the following disclaimer, 18 * without modification. 19 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 20 * substantially similar to the "NO WARRANTY" disclaimer below 21 * ("Disclaimer") and any redistribution must be conditioned upon 22 * including a substantially similar Disclaimer requirement for further 23 * binary redistribution. 24 * 25 * NO WARRANTY 26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 27 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 28 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 29 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 30 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 34 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 35 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGES. 37 * 38 */ 39 40 #include <sys/param.h> 41 #include <sys/capsicum.h> 42 #include <sys/callout.h> 43 #include <sys/ioctl.h> 44 #include <sys/linker.h> 45 #include <sys/module.h> 46 #include <sys/queue.h> 47 #include <sys/sbuf.h> 48 #include <sys/nv.h> 49 #include <sys/stat.h> 50 #include <assert.h> 51 #include <bsdxml.h> 52 #include <capsicum_helpers.h> 53 #include <ctype.h> 54 #include <errno.h> 55 #include <fcntl.h> 56 #include <stdint.h> 57 #include <stdio.h> 58 #include <stdlib.h> 59 #include <string.h> 60 #include <strings.h> 61 #include <cam/scsi/scsi_all.h> 62 #include <cam/scsi/scsi_message.h> 63 #include <cam/ctl/ctl.h> 64 #include <cam/ctl/ctl_io.h> 65 #include <cam/ctl/ctl_backend.h> 66 #include <cam/ctl/ctl_ioctl.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 #define NVLIST_BUFSIZE 1024 77 78 extern bool proxy_mode; 79 80 static int ctl_fd = 0; 81 82 void 83 kernel_init(void) 84 { 85 int retval, saved_errno; 86 87 ctl_fd = open(CTL_DEFAULT_DEV, O_RDWR); 88 if (ctl_fd < 0 && errno == ENOENT) { 89 saved_errno = errno; 90 retval = kldload("ctl"); 91 if (retval != -1) 92 ctl_fd = open(CTL_DEFAULT_DEV, O_RDWR); 93 else 94 errno = saved_errno; 95 } 96 if (ctl_fd < 0) 97 log_err(1, "failed to open %s", CTL_DEFAULT_DEV); 98 #ifdef WANT_ISCSI 99 else { 100 saved_errno = errno; 101 if (modfind("cfiscsi") == -1 && kldload("cfiscsi") == -1) 102 log_warn("couldn't load cfiscsi"); 103 errno = saved_errno; 104 } 105 #endif 106 } 107 108 /* 109 * Name/value pair used for per-LUN attributes. 110 */ 111 struct cctl_lun_nv { 112 char *name; 113 char *value; 114 STAILQ_ENTRY(cctl_lun_nv) links; 115 }; 116 117 /* 118 * Backend LUN information. 119 */ 120 struct cctl_lun { 121 uint64_t lun_id; 122 char *backend_type; 123 uint8_t device_type; 124 uint64_t size_blocks; 125 uint32_t blocksize; 126 char *serial_number; 127 char *device_id; 128 char *ctld_name; 129 STAILQ_HEAD(,cctl_lun_nv) attr_list; 130 STAILQ_ENTRY(cctl_lun) links; 131 }; 132 133 struct cctl_port { 134 uint32_t port_id; 135 char *port_frontend; 136 char *port_name; 137 int pp; 138 int vp; 139 int cfiscsi_state; 140 char *cfiscsi_target; 141 uint16_t cfiscsi_portal_group_tag; 142 char *ctld_portal_group_name; 143 STAILQ_HEAD(,cctl_lun_nv) attr_list; 144 STAILQ_ENTRY(cctl_port) links; 145 }; 146 147 struct cctl_devlist_data { 148 int num_luns; 149 STAILQ_HEAD(,cctl_lun) lun_list; 150 struct cctl_lun *cur_lun; 151 int num_ports; 152 STAILQ_HEAD(,cctl_port) port_list; 153 struct cctl_port *cur_port; 154 int level; 155 struct sbuf *cur_sb[32]; 156 }; 157 158 static void 159 cctl_start_element(void *user_data, const char *name, const char **attr) 160 { 161 int i; 162 struct cctl_devlist_data *devlist; 163 struct cctl_lun *cur_lun; 164 165 devlist = (struct cctl_devlist_data *)user_data; 166 cur_lun = devlist->cur_lun; 167 devlist->level++; 168 if ((u_int)devlist->level >= (sizeof(devlist->cur_sb) / 169 sizeof(devlist->cur_sb[0]))) 170 log_errx(1, "%s: too many nesting levels, %zd max", __func__, 171 nitems(devlist->cur_sb)); 172 173 devlist->cur_sb[devlist->level] = sbuf_new_auto(); 174 if (devlist->cur_sb[devlist->level] == NULL) 175 log_err(1, "%s: unable to allocate sbuf", __func__); 176 177 if (strcmp(name, "lun") == 0) { 178 if (cur_lun != NULL) 179 log_errx(1, "%s: improper lun element nesting", 180 __func__); 181 182 cur_lun = calloc(1, sizeof(*cur_lun)); 183 if (cur_lun == NULL) 184 log_err(1, "%s: cannot allocate %zd bytes", __func__, 185 sizeof(*cur_lun)); 186 187 devlist->num_luns++; 188 devlist->cur_lun = cur_lun; 189 190 STAILQ_INIT(&cur_lun->attr_list); 191 STAILQ_INSERT_TAIL(&devlist->lun_list, cur_lun, links); 192 193 for (i = 0; attr[i] != NULL; i += 2) { 194 if (strcmp(attr[i], "id") == 0) { 195 cur_lun->lun_id = strtoull(attr[i+1], NULL, 0); 196 } else { 197 log_errx(1, "%s: invalid LUN attribute %s = %s", 198 __func__, attr[i], attr[i+1]); 199 } 200 } 201 } 202 } 203 204 static void 205 cctl_end_element(void *user_data, const char *name) 206 { 207 struct cctl_devlist_data *devlist; 208 struct cctl_lun *cur_lun; 209 char *str; 210 211 devlist = (struct cctl_devlist_data *)user_data; 212 cur_lun = devlist->cur_lun; 213 214 if ((cur_lun == NULL) 215 && (strcmp(name, "ctllunlist") != 0)) 216 log_errx(1, "%s: cur_lun == NULL! (name = %s)", __func__, name); 217 218 if (devlist->cur_sb[devlist->level] == NULL) 219 log_errx(1, "%s: no valid sbuf at level %d (name %s)", __func__, 220 devlist->level, name); 221 222 sbuf_finish(devlist->cur_sb[devlist->level]); 223 str = checked_strdup(sbuf_data(devlist->cur_sb[devlist->level])); 224 225 if (strlen(str) == 0) { 226 free(str); 227 str = NULL; 228 } 229 230 sbuf_delete(devlist->cur_sb[devlist->level]); 231 devlist->cur_sb[devlist->level] = NULL; 232 devlist->level--; 233 234 if (strcmp(name, "backend_type") == 0) { 235 cur_lun->backend_type = str; 236 str = NULL; 237 } else if (strcmp(name, "lun_type") == 0) { 238 if (str == NULL) 239 log_errx(1, "%s: %s missing its argument", __func__, name); 240 cur_lun->device_type = strtoull(str, NULL, 0); 241 } else if (strcmp(name, "size") == 0) { 242 if (str == NULL) 243 log_errx(1, "%s: %s missing its argument", __func__, name); 244 cur_lun->size_blocks = strtoull(str, NULL, 0); 245 } else if (strcmp(name, "blocksize") == 0) { 246 if (str == NULL) 247 log_errx(1, "%s: %s missing its argument", __func__, name); 248 cur_lun->blocksize = strtoul(str, NULL, 0); 249 } else if (strcmp(name, "serial_number") == 0) { 250 cur_lun->serial_number = str; 251 str = NULL; 252 } else if (strcmp(name, "device_id") == 0) { 253 cur_lun->device_id = str; 254 str = NULL; 255 } else if (strcmp(name, "ctld_name") == 0) { 256 cur_lun->ctld_name = str; 257 str = NULL; 258 } else if (strcmp(name, "lun") == 0) { 259 devlist->cur_lun = NULL; 260 } else if (strcmp(name, "ctllunlist") == 0) { 261 /* Nothing. */ 262 } else { 263 struct cctl_lun_nv *nv; 264 265 nv = calloc(1, sizeof(*nv)); 266 if (nv == NULL) 267 log_err(1, "%s: can't allocate %zd bytes for nv pair", 268 __func__, sizeof(*nv)); 269 270 nv->name = checked_strdup(name); 271 272 nv->value = str; 273 str = NULL; 274 STAILQ_INSERT_TAIL(&cur_lun->attr_list, nv, links); 275 } 276 277 free(str); 278 } 279 280 static void 281 cctl_start_pelement(void *user_data, const char *name, const char **attr) 282 { 283 int i; 284 struct cctl_devlist_data *devlist; 285 struct cctl_port *cur_port; 286 287 devlist = (struct cctl_devlist_data *)user_data; 288 cur_port = devlist->cur_port; 289 devlist->level++; 290 if ((u_int)devlist->level >= (sizeof(devlist->cur_sb) / 291 sizeof(devlist->cur_sb[0]))) 292 log_errx(1, "%s: too many nesting levels, %zd max", __func__, 293 nitems(devlist->cur_sb)); 294 295 devlist->cur_sb[devlist->level] = sbuf_new_auto(); 296 if (devlist->cur_sb[devlist->level] == NULL) 297 log_err(1, "%s: unable to allocate sbuf", __func__); 298 299 if (strcmp(name, "targ_port") == 0) { 300 if (cur_port != NULL) 301 log_errx(1, "%s: improper port element nesting (%s)", 302 __func__, name); 303 304 cur_port = calloc(1, sizeof(*cur_port)); 305 if (cur_port == NULL) 306 log_err(1, "%s: cannot allocate %zd bytes", __func__, 307 sizeof(*cur_port)); 308 309 devlist->num_ports++; 310 devlist->cur_port = cur_port; 311 312 STAILQ_INIT(&cur_port->attr_list); 313 STAILQ_INSERT_TAIL(&devlist->port_list, cur_port, links); 314 315 for (i = 0; attr[i] != NULL; i += 2) { 316 if (strcmp(attr[i], "id") == 0) { 317 cur_port->port_id = strtoul(attr[i+1], NULL, 0); 318 } else { 319 log_errx(1, "%s: invalid LUN attribute %s = %s", 320 __func__, attr[i], attr[i+1]); 321 } 322 } 323 } 324 } 325 326 static void 327 cctl_end_pelement(void *user_data, const char *name) 328 { 329 struct cctl_devlist_data *devlist; 330 struct cctl_port *cur_port; 331 char *str; 332 333 devlist = (struct cctl_devlist_data *)user_data; 334 cur_port = devlist->cur_port; 335 336 if ((cur_port == NULL) 337 && (strcmp(name, "ctlportlist") != 0)) 338 log_errx(1, "%s: cur_port == NULL! (name = %s)", __func__, name); 339 340 if (devlist->cur_sb[devlist->level] == NULL) 341 log_errx(1, "%s: no valid sbuf at level %d (name %s)", __func__, 342 devlist->level, name); 343 344 sbuf_finish(devlist->cur_sb[devlist->level]); 345 str = checked_strdup(sbuf_data(devlist->cur_sb[devlist->level])); 346 347 if (strlen(str) == 0) { 348 free(str); 349 str = NULL; 350 } 351 352 sbuf_delete(devlist->cur_sb[devlist->level]); 353 devlist->cur_sb[devlist->level] = NULL; 354 devlist->level--; 355 356 if (strcmp(name, "frontend_type") == 0) { 357 cur_port->port_frontend = str; 358 str = NULL; 359 } else if (strcmp(name, "port_name") == 0) { 360 cur_port->port_name = str; 361 str = NULL; 362 } else if (strcmp(name, "physical_port") == 0) { 363 if (str == NULL) 364 log_errx(1, "%s: %s missing its argument", __func__, name); 365 cur_port->pp = strtoul(str, NULL, 0); 366 } else if (strcmp(name, "virtual_port") == 0) { 367 if (str == NULL) 368 log_errx(1, "%s: %s missing its argument", __func__, name); 369 cur_port->vp = strtoul(str, NULL, 0); 370 } else if (strcmp(name, "cfiscsi_target") == 0) { 371 cur_port->cfiscsi_target = str; 372 str = NULL; 373 } else if (strcmp(name, "cfiscsi_state") == 0) { 374 if (str == NULL) 375 log_errx(1, "%s: %s missing its argument", __func__, name); 376 cur_port->cfiscsi_state = strtoul(str, NULL, 0); 377 } else if (strcmp(name, "cfiscsi_portal_group_tag") == 0) { 378 if (str == NULL) 379 log_errx(1, "%s: %s missing its argument", __func__, name); 380 cur_port->cfiscsi_portal_group_tag = strtoul(str, NULL, 0); 381 } else if (strcmp(name, "ctld_portal_group_name") == 0) { 382 cur_port->ctld_portal_group_name = str; 383 str = NULL; 384 } else if (strcmp(name, "targ_port") == 0) { 385 devlist->cur_port = NULL; 386 } else if (strcmp(name, "ctlportlist") == 0) { 387 /* Nothing. */ 388 } else { 389 struct cctl_lun_nv *nv; 390 391 nv = calloc(1, sizeof(*nv)); 392 if (nv == NULL) 393 log_err(1, "%s: can't allocate %zd bytes for nv pair", 394 __func__, sizeof(*nv)); 395 396 nv->name = checked_strdup(name); 397 398 nv->value = str; 399 str = NULL; 400 STAILQ_INSERT_TAIL(&cur_port->attr_list, nv, links); 401 } 402 403 free(str); 404 } 405 406 static void 407 cctl_char_handler(void *user_data, const XML_Char *str, int len) 408 { 409 struct cctl_devlist_data *devlist; 410 411 devlist = (struct cctl_devlist_data *)user_data; 412 413 sbuf_bcat(devlist->cur_sb[devlist->level], str, len); 414 } 415 416 struct conf * 417 conf_new_from_kernel(void) 418 { 419 struct conf *conf = NULL; 420 struct target *targ; 421 struct portal_group *pg; 422 struct pport *pp; 423 struct port *cp; 424 struct lun *cl; 425 struct option *o; 426 struct ctl_lun_list list; 427 struct cctl_devlist_data devlist; 428 struct cctl_lun *lun; 429 struct cctl_port *port; 430 XML_Parser parser; 431 char *str, *name; 432 int len, retval; 433 434 bzero(&devlist, sizeof(devlist)); 435 STAILQ_INIT(&devlist.lun_list); 436 STAILQ_INIT(&devlist.port_list); 437 438 log_debugx("obtaining previously configured CTL luns from the kernel"); 439 440 str = NULL; 441 len = 4096; 442 retry: 443 str = realloc(str, len); 444 if (str == NULL) 445 log_err(1, "realloc"); 446 447 bzero(&list, sizeof(list)); 448 list.alloc_len = len; 449 list.status = CTL_LUN_LIST_NONE; 450 list.lun_xml = str; 451 452 if (ioctl(ctl_fd, CTL_LUN_LIST, &list) == -1) { 453 log_warn("error issuing CTL_LUN_LIST ioctl"); 454 free(str); 455 return (NULL); 456 } 457 458 if (list.status == CTL_LUN_LIST_ERROR) { 459 log_warnx("error returned from CTL_LUN_LIST ioctl: %s", 460 list.error_str); 461 free(str); 462 return (NULL); 463 } 464 465 if (list.status == CTL_LUN_LIST_NEED_MORE_SPACE) { 466 len = len << 1; 467 goto retry; 468 } 469 470 parser = XML_ParserCreate(NULL); 471 if (parser == NULL) { 472 log_warnx("unable to create XML parser"); 473 free(str); 474 return (NULL); 475 } 476 477 XML_SetUserData(parser, &devlist); 478 XML_SetElementHandler(parser, cctl_start_element, cctl_end_element); 479 XML_SetCharacterDataHandler(parser, cctl_char_handler); 480 481 retval = XML_Parse(parser, str, strlen(str), 1); 482 XML_ParserFree(parser); 483 free(str); 484 if (retval != 1) { 485 log_warnx("XML_Parse failed"); 486 return (NULL); 487 } 488 489 str = NULL; 490 len = 4096; 491 retry_port: 492 str = realloc(str, len); 493 if (str == NULL) 494 log_err(1, "realloc"); 495 496 bzero(&list, sizeof(list)); 497 list.alloc_len = len; 498 list.status = CTL_LUN_LIST_NONE; 499 list.lun_xml = str; 500 501 if (ioctl(ctl_fd, CTL_PORT_LIST, &list) == -1) { 502 log_warn("error issuing CTL_PORT_LIST ioctl"); 503 free(str); 504 return (NULL); 505 } 506 507 if (list.status == CTL_LUN_LIST_ERROR) { 508 log_warnx("error returned from CTL_PORT_LIST ioctl: %s", 509 list.error_str); 510 free(str); 511 return (NULL); 512 } 513 514 if (list.status == CTL_LUN_LIST_NEED_MORE_SPACE) { 515 len = len << 1; 516 goto retry_port; 517 } 518 519 parser = XML_ParserCreate(NULL); 520 if (parser == NULL) { 521 log_warnx("unable to create XML parser"); 522 free(str); 523 return (NULL); 524 } 525 526 XML_SetUserData(parser, &devlist); 527 XML_SetElementHandler(parser, cctl_start_pelement, cctl_end_pelement); 528 XML_SetCharacterDataHandler(parser, cctl_char_handler); 529 530 retval = XML_Parse(parser, str, strlen(str), 1); 531 XML_ParserFree(parser); 532 free(str); 533 if (retval != 1) { 534 log_warnx("XML_Parse failed"); 535 return (NULL); 536 } 537 538 conf = conf_new(); 539 540 name = NULL; 541 STAILQ_FOREACH(port, &devlist.port_list, links) { 542 if (strcmp(port->port_frontend, "ha") == 0) 543 continue; 544 free(name); 545 if (port->pp == 0 && port->vp == 0) { 546 name = checked_strdup(port->port_name); 547 } else if (port->vp == 0) { 548 retval = asprintf(&name, "%s/%d", 549 port->port_name, port->pp); 550 if (retval <= 0) 551 log_err(1, "asprintf"); 552 } else { 553 retval = asprintf(&name, "%s/%d/%d", 554 port->port_name, port->pp, port->vp); 555 if (retval <= 0) 556 log_err(1, "asprintf"); 557 } 558 559 if (port->cfiscsi_target == NULL) { 560 log_debugx("CTL port %u \"%s\" wasn't managed by ctld; ", 561 port->port_id, name); 562 pp = pport_find(conf, name); 563 if (pp == NULL) { 564 #if 0 565 log_debugx("found new kernel port %u \"%s\"", 566 port->port_id, name); 567 #endif 568 pp = pport_new(conf, name, port->port_id); 569 if (pp == NULL) { 570 log_warnx("pport_new failed"); 571 continue; 572 } 573 } 574 continue; 575 } 576 if (port->cfiscsi_state != 1) { 577 log_debugx("CTL port %ju is not active (%d); ignoring", 578 (uintmax_t)port->port_id, port->cfiscsi_state); 579 continue; 580 } 581 582 targ = target_find(conf, port->cfiscsi_target); 583 if (targ == NULL) { 584 #if 0 585 log_debugx("found new kernel target %s for CTL port %ld", 586 port->cfiscsi_target, port->port_id); 587 #endif 588 targ = target_new(conf, port->cfiscsi_target); 589 if (targ == NULL) { 590 log_warnx("target_new failed"); 591 continue; 592 } 593 } 594 595 if (port->ctld_portal_group_name == NULL) 596 continue; 597 pg = portal_group_find(conf, port->ctld_portal_group_name); 598 if (pg == NULL) { 599 #if 0 600 log_debugx("found new kernel portal group %s for CTL port %ld", 601 port->ctld_portal_group_name, port->port_id); 602 #endif 603 pg = portal_group_new(conf, port->ctld_portal_group_name); 604 if (pg == NULL) { 605 log_warnx("portal_group_new failed"); 606 continue; 607 } 608 } 609 pg->pg_tag = port->cfiscsi_portal_group_tag; 610 cp = port_new(conf, targ, pg); 611 if (cp == NULL) { 612 log_warnx("port_new failed"); 613 continue; 614 } 615 cp->p_ctl_port = port->port_id; 616 } 617 while ((port = STAILQ_FIRST(&devlist.port_list))) { 618 struct cctl_lun_nv *nv; 619 620 STAILQ_REMOVE_HEAD(&devlist.port_list, links); 621 free(port->port_frontend); 622 free(port->port_name); 623 free(port->cfiscsi_target); 624 free(port->ctld_portal_group_name); 625 while ((nv = STAILQ_FIRST(&port->attr_list))) { 626 STAILQ_REMOVE_HEAD(&port->attr_list, links); 627 free(nv->value); 628 free(nv->name); 629 free(nv); 630 } 631 free(port); 632 } 633 free(name); 634 635 STAILQ_FOREACH(lun, &devlist.lun_list, links) { 636 struct cctl_lun_nv *nv; 637 638 if (lun->ctld_name == NULL) { 639 log_debugx("CTL lun %ju wasn't managed by ctld; " 640 "ignoring", (uintmax_t)lun->lun_id); 641 continue; 642 } 643 644 cl = lun_find(conf, lun->ctld_name); 645 if (cl != NULL) { 646 log_warnx("found CTL lun %ju \"%s\", " 647 "also backed by CTL lun %d; ignoring", 648 (uintmax_t)lun->lun_id, lun->ctld_name, 649 cl->l_ctl_lun); 650 continue; 651 } 652 653 log_debugx("found CTL lun %ju \"%s\"", 654 (uintmax_t)lun->lun_id, lun->ctld_name); 655 656 cl = lun_new(conf, lun->ctld_name); 657 if (cl == NULL) { 658 log_warnx("lun_new failed"); 659 continue; 660 } 661 lun_set_backend(cl, lun->backend_type); 662 lun_set_device_type(cl, lun->device_type); 663 lun_set_blocksize(cl, lun->blocksize); 664 lun_set_device_id(cl, lun->device_id); 665 lun_set_serial(cl, lun->serial_number); 666 lun_set_size(cl, lun->size_blocks * cl->l_blocksize); 667 lun_set_ctl_lun(cl, lun->lun_id); 668 669 STAILQ_FOREACH(nv, &lun->attr_list, links) { 670 if (strcmp(nv->name, "file") == 0 || 671 strcmp(nv->name, "dev") == 0) { 672 lun_set_path(cl, nv->value); 673 continue; 674 } 675 o = option_new(&cl->l_options, nv->name, nv->value); 676 if (o == NULL) 677 log_warnx("unable to add CTL lun option %s " 678 "for CTL lun %ju \"%s\"", 679 nv->name, (uintmax_t) lun->lun_id, 680 cl->l_name); 681 } 682 } 683 while ((lun = STAILQ_FIRST(&devlist.lun_list))) { 684 struct cctl_lun_nv *nv; 685 686 STAILQ_REMOVE_HEAD(&devlist.lun_list, links); 687 while ((nv = STAILQ_FIRST(&lun->attr_list))) { 688 STAILQ_REMOVE_HEAD(&lun->attr_list, links); 689 free(nv->value); 690 free(nv->name); 691 free(nv); 692 } 693 free(lun); 694 } 695 696 return (conf); 697 } 698 699 int 700 kernel_lun_add(struct lun *lun) 701 { 702 struct option *o; 703 struct ctl_lun_req req; 704 int error; 705 706 bzero(&req, sizeof(req)); 707 708 strlcpy(req.backend, lun->l_backend, sizeof(req.backend)); 709 req.reqtype = CTL_LUNREQ_CREATE; 710 711 req.reqdata.create.blocksize_bytes = lun->l_blocksize; 712 713 if (lun->l_size != 0) 714 req.reqdata.create.lun_size_bytes = lun->l_size; 715 716 if (lun->l_ctl_lun >= 0) { 717 req.reqdata.create.req_lun_id = lun->l_ctl_lun; 718 req.reqdata.create.flags |= CTL_LUN_FLAG_ID_REQ; 719 } 720 721 req.reqdata.create.flags |= CTL_LUN_FLAG_DEV_TYPE; 722 req.reqdata.create.device_type = lun->l_device_type; 723 724 if (lun->l_serial != NULL) { 725 strncpy(req.reqdata.create.serial_num, lun->l_serial, 726 sizeof(req.reqdata.create.serial_num)); 727 req.reqdata.create.flags |= CTL_LUN_FLAG_SERIAL_NUM; 728 } 729 730 if (lun->l_device_id != NULL) { 731 strncpy(req.reqdata.create.device_id, lun->l_device_id, 732 sizeof(req.reqdata.create.device_id)); 733 req.reqdata.create.flags |= CTL_LUN_FLAG_DEVID; 734 } 735 736 if (lun->l_path != NULL) { 737 o = option_find(&lun->l_options, "file"); 738 if (o != NULL) { 739 option_set(o, lun->l_path); 740 } else { 741 o = option_new(&lun->l_options, "file", lun->l_path); 742 assert(o != NULL); 743 } 744 } 745 746 o = option_find(&lun->l_options, "ctld_name"); 747 if (o != NULL) { 748 option_set(o, lun->l_name); 749 } else { 750 o = option_new(&lun->l_options, "ctld_name", lun->l_name); 751 assert(o != NULL); 752 } 753 754 o = option_find(&lun->l_options, "scsiname"); 755 if (o == NULL && lun->l_scsiname != NULL) { 756 o = option_new(&lun->l_options, "scsiname", lun->l_scsiname); 757 assert(o != NULL); 758 } 759 760 if (!TAILQ_EMPTY(&lun->l_options)) { 761 req.args_nvl = nvlist_create(0); 762 if (req.args_nvl == NULL) { 763 log_warn("error allocating nvlist"); 764 return (1); 765 } 766 767 TAILQ_FOREACH(o, &lun->l_options, o_next) 768 nvlist_add_string(req.args_nvl, o->o_name, o->o_value); 769 770 req.args = nvlist_pack(req.args_nvl, &req.args_len); 771 if (req.args == NULL) { 772 nvlist_destroy(req.args_nvl); 773 log_warn("error packing nvlist"); 774 return (1); 775 } 776 } 777 778 error = ioctl(ctl_fd, CTL_LUN_REQ, &req); 779 free(req.args); 780 nvlist_destroy(req.args_nvl); 781 782 if (error != 0) { 783 log_warn("error issuing CTL_LUN_REQ ioctl"); 784 return (1); 785 } 786 787 switch (req.status) { 788 case CTL_LUN_ERROR: 789 log_warnx("LUN creation error: %s", req.error_str); 790 return (1); 791 case CTL_LUN_WARNING: 792 log_warnx("LUN creation warning: %s", req.error_str); 793 break; 794 case CTL_LUN_OK: 795 break; 796 default: 797 log_warnx("unknown LUN creation status: %d", 798 req.status); 799 return (1); 800 } 801 802 lun_set_ctl_lun(lun, req.reqdata.create.req_lun_id); 803 return (0); 804 } 805 806 int 807 kernel_lun_modify(struct lun *lun) 808 { 809 struct option *o; 810 struct ctl_lun_req req; 811 int error; 812 813 bzero(&req, sizeof(req)); 814 815 strlcpy(req.backend, lun->l_backend, sizeof(req.backend)); 816 req.reqtype = CTL_LUNREQ_MODIFY; 817 818 req.reqdata.modify.lun_id = lun->l_ctl_lun; 819 req.reqdata.modify.lun_size_bytes = lun->l_size; 820 821 if (lun->l_path != NULL) { 822 o = option_find(&lun->l_options, "file"); 823 if (o != NULL) { 824 option_set(o, lun->l_path); 825 } else { 826 o = option_new(&lun->l_options, "file", lun->l_path); 827 assert(o != NULL); 828 } 829 } 830 831 o = option_find(&lun->l_options, "ctld_name"); 832 if (o != NULL) { 833 option_set(o, lun->l_name); 834 } else { 835 o = option_new(&lun->l_options, "ctld_name", lun->l_name); 836 assert(o != NULL); 837 } 838 839 o = option_find(&lun->l_options, "scsiname"); 840 if (o == NULL && lun->l_scsiname != NULL) { 841 o = option_new(&lun->l_options, "scsiname", lun->l_scsiname); 842 assert(o != NULL); 843 } 844 845 if (!TAILQ_EMPTY(&lun->l_options)) { 846 req.args_nvl = nvlist_create(0); 847 if (req.args_nvl == NULL) { 848 log_warn("error allocating nvlist"); 849 return (1); 850 } 851 852 TAILQ_FOREACH(o, &lun->l_options, o_next) 853 nvlist_add_string(req.args_nvl, o->o_name, o->o_value); 854 855 req.args = nvlist_pack(req.args_nvl, &req.args_len); 856 if (req.args == NULL) { 857 nvlist_destroy(req.args_nvl); 858 log_warn("error packing nvlist"); 859 return (1); 860 } 861 } 862 863 error = ioctl(ctl_fd, CTL_LUN_REQ, &req); 864 free(req.args); 865 nvlist_destroy(req.args_nvl); 866 867 if (error != 0) { 868 log_warn("error issuing CTL_LUN_REQ ioctl"); 869 return (1); 870 } 871 872 switch (req.status) { 873 case CTL_LUN_ERROR: 874 log_warnx("LUN modification error: %s", req.error_str); 875 return (1); 876 case CTL_LUN_WARNING: 877 log_warnx("LUN modification warning: %s", req.error_str); 878 break; 879 case CTL_LUN_OK: 880 break; 881 default: 882 log_warnx("unknown LUN modification status: %d", 883 req.status); 884 return (1); 885 } 886 887 return (0); 888 } 889 890 int 891 kernel_lun_remove(struct lun *lun) 892 { 893 struct ctl_lun_req req; 894 895 bzero(&req, sizeof(req)); 896 897 strlcpy(req.backend, lun->l_backend, sizeof(req.backend)); 898 req.reqtype = CTL_LUNREQ_RM; 899 900 req.reqdata.rm.lun_id = lun->l_ctl_lun; 901 902 if (ioctl(ctl_fd, CTL_LUN_REQ, &req) == -1) { 903 log_warn("error issuing CTL_LUN_REQ ioctl"); 904 return (1); 905 } 906 907 switch (req.status) { 908 case CTL_LUN_ERROR: 909 log_warnx("LUN removal error: %s", req.error_str); 910 return (1); 911 case CTL_LUN_WARNING: 912 log_warnx("LUN removal warning: %s", req.error_str); 913 break; 914 case CTL_LUN_OK: 915 break; 916 default: 917 log_warnx("unknown LUN removal status: %d", req.status); 918 return (1); 919 } 920 921 return (0); 922 } 923 924 void 925 kernel_handoff(struct ctld_connection *conn) 926 { 927 struct ctl_iscsi req; 928 929 bzero(&req, sizeof(req)); 930 931 req.type = CTL_ISCSI_HANDOFF; 932 strlcpy(req.data.handoff.initiator_name, 933 conn->conn_initiator_name, sizeof(req.data.handoff.initiator_name)); 934 strlcpy(req.data.handoff.initiator_addr, 935 conn->conn_initiator_addr, sizeof(req.data.handoff.initiator_addr)); 936 if (conn->conn_initiator_alias != NULL) { 937 strlcpy(req.data.handoff.initiator_alias, 938 conn->conn_initiator_alias, sizeof(req.data.handoff.initiator_alias)); 939 } 940 memcpy(req.data.handoff.initiator_isid, conn->conn_initiator_isid, 941 sizeof(req.data.handoff.initiator_isid)); 942 strlcpy(req.data.handoff.target_name, 943 conn->conn_target->t_name, sizeof(req.data.handoff.target_name)); 944 if (conn->conn_portal->p_portal_group->pg_offload != NULL) { 945 strlcpy(req.data.handoff.offload, 946 conn->conn_portal->p_portal_group->pg_offload, 947 sizeof(req.data.handoff.offload)); 948 } 949 #ifdef ICL_KERNEL_PROXY 950 if (proxy_mode) 951 req.data.handoff.connection_id = conn->conn.conn_socket; 952 else 953 req.data.handoff.socket = conn->conn.conn_socket; 954 #else 955 req.data.handoff.socket = conn->conn.conn_socket; 956 #endif 957 req.data.handoff.portal_group_tag = 958 conn->conn_portal->p_portal_group->pg_tag; 959 if (conn->conn.conn_header_digest == CONN_DIGEST_CRC32C) 960 req.data.handoff.header_digest = CTL_ISCSI_DIGEST_CRC32C; 961 if (conn->conn.conn_data_digest == CONN_DIGEST_CRC32C) 962 req.data.handoff.data_digest = CTL_ISCSI_DIGEST_CRC32C; 963 req.data.handoff.cmdsn = conn->conn.conn_cmdsn; 964 req.data.handoff.statsn = conn->conn.conn_statsn; 965 req.data.handoff.max_recv_data_segment_length = 966 conn->conn.conn_max_recv_data_segment_length; 967 req.data.handoff.max_send_data_segment_length = 968 conn->conn.conn_max_send_data_segment_length; 969 req.data.handoff.max_burst_length = conn->conn.conn_max_burst_length; 970 req.data.handoff.first_burst_length = 971 conn->conn.conn_first_burst_length; 972 req.data.handoff.immediate_data = conn->conn.conn_immediate_data; 973 974 if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) { 975 log_err(1, "error issuing CTL_ISCSI ioctl; " 976 "dropping connection"); 977 } 978 979 if (req.status != CTL_ISCSI_OK) { 980 log_errx(1, "error returned from CTL iSCSI handoff request: " 981 "%s; dropping connection", req.error_str); 982 } 983 } 984 985 void 986 kernel_limits(const char *offload, int s, int *max_recv_dsl, int *max_send_dsl, 987 int *max_burst_length, int *first_burst_length) 988 { 989 struct ctl_iscsi req; 990 struct ctl_iscsi_limits_params *cilp; 991 992 bzero(&req, sizeof(req)); 993 994 req.type = CTL_ISCSI_LIMITS; 995 cilp = (struct ctl_iscsi_limits_params *)&(req.data.limits); 996 if (offload != NULL) { 997 strlcpy(cilp->offload, offload, sizeof(cilp->offload)); 998 } 999 cilp->socket = s; 1000 1001 if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) { 1002 log_err(1, "error issuing CTL_ISCSI ioctl; " 1003 "dropping connection"); 1004 } 1005 1006 if (req.status != CTL_ISCSI_OK) { 1007 log_errx(1, "error returned from CTL iSCSI limits request: " 1008 "%s; dropping connection", req.error_str); 1009 } 1010 1011 if (cilp->max_recv_data_segment_length != 0) { 1012 *max_recv_dsl = cilp->max_recv_data_segment_length; 1013 *max_send_dsl = cilp->max_recv_data_segment_length; 1014 } 1015 if (cilp->max_send_data_segment_length != 0) 1016 *max_send_dsl = cilp->max_send_data_segment_length; 1017 if (cilp->max_burst_length != 0) 1018 *max_burst_length = cilp->max_burst_length; 1019 if (cilp->first_burst_length != 0) 1020 *first_burst_length = cilp->first_burst_length; 1021 if (*max_burst_length < *first_burst_length) 1022 *first_burst_length = *max_burst_length; 1023 1024 if (offload != NULL) { 1025 log_debugx("Kernel limits for offload \"%s\" are " 1026 "MaxRecvDataSegment=%d, max_send_dsl=%d, " 1027 "MaxBurstLength=%d, FirstBurstLength=%d", 1028 offload, *max_recv_dsl, *max_send_dsl, *max_burst_length, 1029 *first_burst_length); 1030 } else { 1031 log_debugx("Kernel limits are " 1032 "MaxRecvDataSegment=%d, max_send_dsl=%d, " 1033 "MaxBurstLength=%d, FirstBurstLength=%d", 1034 *max_recv_dsl, *max_send_dsl, *max_burst_length, 1035 *first_burst_length); 1036 } 1037 } 1038 1039 int 1040 kernel_port_add(struct port *port) 1041 { 1042 struct option *o; 1043 struct ctl_port_entry entry; 1044 struct ctl_req req; 1045 struct ctl_lun_map lm; 1046 struct target *targ = port->p_target; 1047 struct portal_group *pg = port->p_portal_group; 1048 char result_buf[NVLIST_BUFSIZE]; 1049 int error, i; 1050 1051 /* Create iSCSI port. */ 1052 if (port->p_portal_group || port->p_ioctl_port) { 1053 bzero(&req, sizeof(req)); 1054 req.reqtype = CTL_REQ_CREATE; 1055 1056 if (port->p_portal_group) { 1057 strlcpy(req.driver, "iscsi", sizeof(req.driver)); 1058 req.args_nvl = nvlist_create(0); 1059 nvlist_add_string(req.args_nvl, "cfiscsi_target", 1060 targ->t_name); 1061 nvlist_add_string(req.args_nvl, 1062 "ctld_portal_group_name", pg->pg_name); 1063 nvlist_add_stringf(req.args_nvl, 1064 "cfiscsi_portal_group_tag", "%u", pg->pg_tag); 1065 1066 if (targ->t_alias) { 1067 nvlist_add_string(req.args_nvl, 1068 "cfiscsi_target_alias", targ->t_alias); 1069 } 1070 1071 TAILQ_FOREACH(o, &pg->pg_options, o_next) 1072 nvlist_add_string(req.args_nvl, o->o_name, 1073 o->o_value); 1074 } 1075 1076 if (port->p_ioctl_port) { 1077 strlcpy(req.driver, "ioctl", sizeof(req.driver)); 1078 req.args_nvl = nvlist_create(0); 1079 nvlist_add_stringf(req.args_nvl, "pp", "%d", 1080 port->p_ioctl_pp); 1081 nvlist_add_stringf(req.args_nvl, "vp", "%d", 1082 port->p_ioctl_vp); 1083 } 1084 1085 req.args = nvlist_pack(req.args_nvl, &req.args_len); 1086 if (req.args == NULL) { 1087 nvlist_destroy(req.args_nvl); 1088 log_warn("error packing nvlist"); 1089 return (1); 1090 } 1091 1092 req.result = result_buf; 1093 req.result_len = sizeof(result_buf); 1094 error = ioctl(ctl_fd, CTL_PORT_REQ, &req); 1095 free(req.args); 1096 nvlist_destroy(req.args_nvl); 1097 1098 if (error != 0) { 1099 log_warn("error issuing CTL_PORT_REQ ioctl"); 1100 return (1); 1101 } 1102 if (req.status == CTL_LUN_ERROR) { 1103 log_warnx("error returned from port creation request: %s", 1104 req.error_str); 1105 return (1); 1106 } 1107 if (req.status != CTL_LUN_OK) { 1108 log_warnx("unknown port creation request status %d", 1109 req.status); 1110 return (1); 1111 } 1112 1113 req.result_nvl = nvlist_unpack(result_buf, req.result_len, 0); 1114 if (req.result_nvl == NULL) { 1115 log_warnx("error unpacking result nvlist"); 1116 return (1); 1117 } 1118 1119 port->p_ctl_port = nvlist_get_number(req.result_nvl, "port_id"); 1120 nvlist_destroy(req.result_nvl); 1121 } else if (port->p_pport) { 1122 port->p_ctl_port = port->p_pport->pp_ctl_port; 1123 1124 if (strncmp(targ->t_name, "naa.", 4) == 0 && 1125 strlen(targ->t_name) == 20) { 1126 bzero(&entry, sizeof(entry)); 1127 entry.port_type = CTL_PORT_NONE; 1128 entry.targ_port = port->p_ctl_port; 1129 entry.flags |= CTL_PORT_WWNN_VALID; 1130 entry.wwnn = strtoull(targ->t_name + 4, NULL, 16); 1131 if (ioctl(ctl_fd, CTL_SET_PORT_WWNS, &entry) == -1) 1132 log_warn("CTL_SET_PORT_WWNS ioctl failed"); 1133 } 1134 } 1135 1136 /* Explicitly enable mapping to block any access except allowed. */ 1137 lm.port = port->p_ctl_port; 1138 lm.plun = UINT32_MAX; 1139 lm.lun = 0; 1140 error = ioctl(ctl_fd, CTL_LUN_MAP, &lm); 1141 if (error != 0) 1142 log_warn("CTL_LUN_MAP ioctl failed"); 1143 1144 /* Map configured LUNs */ 1145 for (i = 0; i < MAX_LUNS; i++) { 1146 if (targ->t_luns[i] == NULL) 1147 continue; 1148 lm.port = port->p_ctl_port; 1149 lm.plun = i; 1150 lm.lun = targ->t_luns[i]->l_ctl_lun; 1151 error = ioctl(ctl_fd, CTL_LUN_MAP, &lm); 1152 if (error != 0) 1153 log_warn("CTL_LUN_MAP ioctl failed"); 1154 } 1155 1156 /* Enable port */ 1157 bzero(&entry, sizeof(entry)); 1158 entry.targ_port = port->p_ctl_port; 1159 error = ioctl(ctl_fd, CTL_ENABLE_PORT, &entry); 1160 if (error != 0) { 1161 log_warn("CTL_ENABLE_PORT ioctl failed"); 1162 return (-1); 1163 } 1164 1165 return (0); 1166 } 1167 1168 int 1169 kernel_port_update(struct port *port, struct port *oport) 1170 { 1171 struct ctl_lun_map lm; 1172 struct target *targ = port->p_target; 1173 struct target *otarg = oport->p_target; 1174 int error, i; 1175 uint32_t olun; 1176 1177 /* Map configured LUNs and unmap others */ 1178 for (i = 0; i < MAX_LUNS; i++) { 1179 lm.port = port->p_ctl_port; 1180 lm.plun = i; 1181 if (targ->t_luns[i] == NULL) 1182 lm.lun = UINT32_MAX; 1183 else 1184 lm.lun = targ->t_luns[i]->l_ctl_lun; 1185 if (otarg->t_luns[i] == NULL) 1186 olun = UINT32_MAX; 1187 else 1188 olun = otarg->t_luns[i]->l_ctl_lun; 1189 if (lm.lun == olun) 1190 continue; 1191 error = ioctl(ctl_fd, CTL_LUN_MAP, &lm); 1192 if (error != 0) 1193 log_warn("CTL_LUN_MAP ioctl failed"); 1194 } 1195 return (0); 1196 } 1197 1198 int 1199 kernel_port_remove(struct port *port) 1200 { 1201 struct ctl_port_entry entry; 1202 struct ctl_lun_map lm; 1203 struct ctl_req req; 1204 struct target *targ = port->p_target; 1205 struct portal_group *pg = port->p_portal_group; 1206 int error; 1207 1208 /* Disable port */ 1209 bzero(&entry, sizeof(entry)); 1210 entry.targ_port = port->p_ctl_port; 1211 error = ioctl(ctl_fd, CTL_DISABLE_PORT, &entry); 1212 if (error != 0) { 1213 log_warn("CTL_DISABLE_PORT ioctl failed"); 1214 return (-1); 1215 } 1216 1217 /* Remove iSCSI or ioctl port. */ 1218 if (port->p_portal_group || port->p_ioctl_port) { 1219 bzero(&req, sizeof(req)); 1220 strlcpy(req.driver, port->p_ioctl_port ? "ioctl" : "iscsi", 1221 sizeof(req.driver)); 1222 req.reqtype = CTL_REQ_REMOVE; 1223 req.args_nvl = nvlist_create(0); 1224 if (req.args_nvl == NULL) 1225 log_err(1, "nvlist_create"); 1226 1227 if (port->p_ioctl_port) 1228 nvlist_add_stringf(req.args_nvl, "port_id", "%d", 1229 port->p_ctl_port); 1230 else { 1231 nvlist_add_string(req.args_nvl, "cfiscsi_target", 1232 targ->t_name); 1233 nvlist_add_stringf(req.args_nvl, 1234 "cfiscsi_portal_group_tag", "%u", pg->pg_tag); 1235 } 1236 1237 req.args = nvlist_pack(req.args_nvl, &req.args_len); 1238 if (req.args == NULL) { 1239 nvlist_destroy(req.args_nvl); 1240 log_warn("error packing nvlist"); 1241 return (1); 1242 } 1243 1244 error = ioctl(ctl_fd, CTL_PORT_REQ, &req); 1245 free(req.args); 1246 nvlist_destroy(req.args_nvl); 1247 1248 if (error != 0) { 1249 log_warn("error issuing CTL_PORT_REQ ioctl"); 1250 return (1); 1251 } 1252 if (req.status == CTL_LUN_ERROR) { 1253 log_warnx("error returned from port removal request: %s", 1254 req.error_str); 1255 return (1); 1256 } 1257 if (req.status != CTL_LUN_OK) { 1258 log_warnx("unknown port removal request status %d", 1259 req.status); 1260 return (1); 1261 } 1262 } else { 1263 /* Disable LUN mapping. */ 1264 lm.port = port->p_ctl_port; 1265 lm.plun = UINT32_MAX; 1266 lm.lun = UINT32_MAX; 1267 error = ioctl(ctl_fd, CTL_LUN_MAP, &lm); 1268 if (error != 0) 1269 log_warn("CTL_LUN_MAP ioctl failed"); 1270 } 1271 return (0); 1272 } 1273 1274 #ifdef ICL_KERNEL_PROXY 1275 void 1276 kernel_listen(struct addrinfo *ai, bool iser, int portal_id) 1277 { 1278 struct ctl_iscsi req; 1279 1280 bzero(&req, sizeof(req)); 1281 1282 req.type = CTL_ISCSI_LISTEN; 1283 req.data.listen.iser = iser; 1284 req.data.listen.domain = ai->ai_family; 1285 req.data.listen.socktype = ai->ai_socktype; 1286 req.data.listen.protocol = ai->ai_protocol; 1287 req.data.listen.addr = ai->ai_addr; 1288 req.data.listen.addrlen = ai->ai_addrlen; 1289 req.data.listen.portal_id = portal_id; 1290 1291 if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) 1292 log_err(1, "error issuing CTL_ISCSI ioctl"); 1293 1294 if (req.status != CTL_ISCSI_OK) { 1295 log_errx(1, "error returned from CTL iSCSI listen: %s", 1296 req.error_str); 1297 } 1298 } 1299 1300 void 1301 kernel_accept(int *connection_id, int *portal_id, 1302 struct sockaddr *client_sa, socklen_t *client_salen) 1303 { 1304 struct ctl_iscsi req; 1305 struct sockaddr_storage ss; 1306 1307 bzero(&req, sizeof(req)); 1308 1309 req.type = CTL_ISCSI_ACCEPT; 1310 req.data.accept.initiator_addr = (struct sockaddr *)&ss; 1311 1312 if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) 1313 log_err(1, "error issuing CTL_ISCSI ioctl"); 1314 1315 if (req.status != CTL_ISCSI_OK) { 1316 log_errx(1, "error returned from CTL iSCSI accept: %s", 1317 req.error_str); 1318 } 1319 1320 *connection_id = req.data.accept.connection_id; 1321 *portal_id = req.data.accept.portal_id; 1322 *client_salen = req.data.accept.initiator_addrlen; 1323 memcpy(client_sa, &ss, *client_salen); 1324 } 1325 1326 void 1327 kernel_send(struct pdu *pdu) 1328 { 1329 struct ctl_iscsi req; 1330 1331 bzero(&req, sizeof(req)); 1332 1333 req.type = CTL_ISCSI_SEND; 1334 req.data.send.connection_id = pdu->pdu_connection->conn_socket; 1335 req.data.send.bhs = pdu->pdu_bhs; 1336 req.data.send.data_segment_len = pdu->pdu_data_len; 1337 req.data.send.data_segment = pdu->pdu_data; 1338 1339 if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) { 1340 log_err(1, "error issuing CTL_ISCSI ioctl; " 1341 "dropping connection"); 1342 } 1343 1344 if (req.status != CTL_ISCSI_OK) { 1345 log_errx(1, "error returned from CTL iSCSI send: " 1346 "%s; dropping connection", req.error_str); 1347 } 1348 } 1349 1350 void 1351 kernel_receive(struct pdu *pdu) 1352 { 1353 struct connection *conn; 1354 struct ctl_iscsi req; 1355 1356 conn = pdu->pdu_connection; 1357 pdu->pdu_data = malloc(conn->conn_max_recv_data_segment_length); 1358 if (pdu->pdu_data == NULL) 1359 log_err(1, "malloc"); 1360 1361 bzero(&req, sizeof(req)); 1362 1363 req.type = CTL_ISCSI_RECEIVE; 1364 req.data.receive.connection_id = conn->conn_socket; 1365 req.data.receive.bhs = pdu->pdu_bhs; 1366 req.data.receive.data_segment_len = 1367 conn->conn_max_recv_data_segment_length; 1368 req.data.receive.data_segment = pdu->pdu_data; 1369 1370 if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) { 1371 log_err(1, "error issuing CTL_ISCSI ioctl; " 1372 "dropping connection"); 1373 } 1374 1375 if (req.status != CTL_ISCSI_OK) { 1376 log_errx(1, "error returned from CTL iSCSI receive: " 1377 "%s; dropping connection", req.error_str); 1378 } 1379 1380 } 1381 1382 #endif /* ICL_KERNEL_PROXY */ 1383 1384 /* 1385 * XXX: I CANT INTO LATIN 1386 */ 1387 void 1388 kernel_capsicate(void) 1389 { 1390 cap_rights_t rights; 1391 const unsigned long cmds[] = { CTL_ISCSI }; 1392 1393 cap_rights_init(&rights, CAP_IOCTL); 1394 if (caph_rights_limit(ctl_fd, &rights) < 0) 1395 log_err(1, "cap_rights_limit"); 1396 1397 if (caph_ioctls_limit(ctl_fd, cmds, nitems(cmds)) < 0) 1398 log_err(1, "cap_ioctls_limit"); 1399 1400 if (caph_enter() < 0) 1401 log_err(1, "cap_enter"); 1402 1403 if (cap_sandboxed()) 1404 log_debugx("Capsicum capability mode enabled"); 1405 else 1406 log_warnx("Capsicum capability mode not supported"); 1407 } 1408 1409