1 1.7 andvar /* $NetBSD: iscsid_targets.c,v 1.7 2022/05/24 20:50:17 andvar Exp $ */ 2 1.1 agc 3 1.1 agc /*- 4 1.1 agc * Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc. 5 1.1 agc * All rights reserved. 6 1.1 agc * 7 1.1 agc * This code is derived from software contributed to The NetBSD Foundation 8 1.1 agc * by Wasabi Systems, Inc. 9 1.1 agc * 10 1.1 agc * Redistribution and use in source and binary forms, with or without 11 1.1 agc * modification, are permitted provided that the following conditions 12 1.1 agc * are met: 13 1.1 agc * 1. Redistributions of source code must retain the above copyright 14 1.1 agc * notice, this list of conditions and the following disclaimer. 15 1.1 agc * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 agc * notice, this list of conditions and the following disclaimer in the 17 1.1 agc * documentation and/or other materials provided with the distribution. 18 1.1 agc * 19 1.1 agc * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 agc * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 agc * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 agc * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 agc * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 agc * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 agc * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 agc * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 agc * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 agc * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 agc * POSSIBILITY OF SUCH DAMAGE. 30 1.1 agc */ 31 1.1 agc 32 1.1 agc #include "iscsid_globals.h" 33 1.1 agc 34 1.1 agc #include <ctype.h> 35 1.1 agc 36 1.1 agc /* counter for portal and target ID */ 37 1.3 agc static uint32_t portarget_id = 0; 38 1.1 agc 39 1.1 agc /* counter for send_targets ID */ 40 1.3 agc static uint32_t send_target_id = 0; 41 1.1 agc 42 1.1 agc 43 1.1 agc /* 44 1.1 agc * create_portal: 45 1.1 agc * Create a portal entry and link it into the appropriate lists. 46 1.1 agc * May also create the associated portal group entry if it does not exist. 47 1.1 agc * Will return the existing entry if the address matches a defined portal. 48 1.1 agc * 49 1.1 agc * Parameter: 50 1.1 agc * target the pointer to the target 51 1.1 agc * addr the portal address (includes tag) 52 1.1 agc * dtype portal discovery type 53 1.1 agc * did discovery ID 54 1.1 agc * 55 1.1 agc * Returns: pointer to created portal 56 1.1 agc */ 57 1.1 agc 58 1.3 agc static portal_t * 59 1.1 agc create_portal(target_t *target, iscsi_portal_address_t *addr, 60 1.1 agc iscsi_portal_types_t dtype, uint32_t did) 61 1.1 agc { 62 1.1 agc portal_group_t *curr; 63 1.1 agc portal_t *portal; 64 1.1 agc u_short tag = addr->group_tag; 65 1.1 agc 66 1.6 mlelstv DEB(9, ("Create Portal addr %s port %d group %d", 67 1.1 agc addr->address, addr->port, addr->group_tag)); 68 1.1 agc 69 1.1 agc if ((portal = find_portal_by_addr(target, addr)) != NULL) 70 1.1 agc return portal; 71 1.1 agc 72 1.1 agc portal = calloc(1, sizeof(*portal)); 73 1.1 agc if (!portal) { 74 1.6 mlelstv DEBOUT(("Out of memory in create_portal!")); 75 1.1 agc return NULL; 76 1.1 agc } 77 1.1 agc portal->addr = *addr; 78 1.1 agc portal->target = target; 79 1.1 agc portal->portaltype = dtype; 80 1.1 agc portal->discoveryid = did; 81 1.1 agc if (!portal->addr.port) { 82 1.1 agc portal->addr.port = ISCSI_DEFAULT_PORT; 83 1.1 agc } 84 1.1 agc for (portarget_id++; !portarget_id || 85 1.1 agc find_portal_id(portarget_id) != NULL || 86 1.1 agc find_target_id(TARGET_LIST, portarget_id) != NULL;) { 87 1.1 agc portarget_id++; 88 1.1 agc } 89 1.1 agc portal->entry.sid.id = portarget_id; 90 1.1 agc 91 1.1 agc TAILQ_FOREACH(curr, &target->group_list, groups) 92 1.1 agc if (curr->tag == tag) 93 1.1 agc break; 94 1.1 agc 95 1.1 agc if (!curr) { 96 1.1 agc curr = calloc(1, sizeof(*curr)); 97 1.1 agc if (!curr) { 98 1.1 agc free(portal); 99 1.6 mlelstv DEBOUT(("Out of memory in create_portal!")); 100 1.1 agc return NULL; 101 1.1 agc } 102 1.1 agc curr->tag = tag; 103 1.1 agc TAILQ_INIT(&curr->portals); 104 1.1 agc TAILQ_INSERT_TAIL(&target->group_list, curr, groups); 105 1.1 agc target->num_groups++; 106 1.1 agc } 107 1.1 agc 108 1.1 agc portal->group = curr; 109 1.1 agc 110 1.1 agc TAILQ_INSERT_TAIL(&curr->portals, portal, group_list); 111 1.1 agc curr->num_portals++; 112 1.1 agc target->num_portals++; 113 1.1 agc 114 1.1 agc TAILQ_INSERT_TAIL(&list[PORTAL_LIST].list, &portal->entry, link); 115 1.1 agc list[PORTAL_LIST].num_entries++; 116 1.1 agc 117 1.6 mlelstv DEB(9, ("create_portal returns %p", portal)); 118 1.1 agc return portal; 119 1.1 agc } 120 1.1 agc 121 1.1 agc 122 1.1 agc /* 123 1.1 agc * delete_portal: 124 1.1 agc * Delete a portal entry after unlinking it from its lists. 125 1.1 agc * May also delete the associated portal group entry if the group is empty. 126 1.1 agc * 127 1.1 agc * Parameter: 128 1.1 agc * portal the pointer to the portal 129 1.1 agc * delete_empty delete empty target if true 130 1.1 agc */ 131 1.1 agc 132 1.1 agc void 133 1.1 agc delete_portal(portal_t * portal, boolean_t delete_empty) 134 1.1 agc { 135 1.1 agc portal_group_t *curr = portal->group; 136 1.1 agc target_t *target = portal->target; 137 1.1 agc 138 1.1 agc TAILQ_REMOVE(&curr->portals, portal, group_list); 139 1.1 agc TAILQ_REMOVE(&list[PORTAL_LIST].list, &portal->entry, link); 140 1.1 agc curr->num_portals--; 141 1.1 agc target->num_portals--; 142 1.1 agc list[PORTAL_LIST].num_entries--; 143 1.1 agc 144 1.1 agc if (!curr->num_portals) { 145 1.1 agc TAILQ_REMOVE(&target->group_list, curr, groups); 146 1.1 agc free(curr); 147 1.1 agc target->num_groups--; 148 1.1 agc } 149 1.1 agc free(portal); 150 1.1 agc 151 1.1 agc /* Optionally delete target if no portals left */ 152 1.1 agc if (delete_empty && !target->num_portals) { 153 1.1 agc TAILQ_REMOVE(&list[TARGET_LIST].list, &target->entry, link); 154 1.1 agc list[TARGET_LIST].num_entries--; 155 1.1 agc free(target); 156 1.1 agc } 157 1.1 agc } 158 1.1 agc 159 1.1 agc 160 1.1 agc /* 161 1.1 agc * create_target: 162 1.1 agc * Create a target structure and initialize it. 163 1.1 agc * 164 1.1 agc * Parameter: 165 1.1 agc * name The target name 166 1.1 agc * 167 1.1 agc * Returns: Pointer to target structure, NULL if allocation failed. 168 1.1 agc */ 169 1.1 agc 170 1.3 agc static target_t * 171 1.1 agc create_target(uint8_t * name) 172 1.1 agc { 173 1.1 agc target_t *target; 174 1.1 agc 175 1.6 mlelstv DEB(9, ("Create Target %s", name)); 176 1.1 agc 177 1.1 agc if ((target = calloc(1, sizeof(*target))) == NULL) { 178 1.6 mlelstv DEBOUT(("Out of memory in create_target!")); 179 1.1 agc return NULL; 180 1.1 agc } 181 1.1 agc 182 1.1 agc TAILQ_INIT(&target->group_list); 183 1.1 agc 184 1.1 agc for (portarget_id++; 185 1.1 agc !portarget_id || 186 1.1 agc find_portal_id(portarget_id) != NULL || 187 1.1 agc find_target_id(TARGET_LIST, portarget_id) != NULL; 188 1.1 agc portarget_id++) { 189 1.1 agc } 190 1.1 agc 191 1.1 agc target->entry.sid.id = portarget_id; 192 1.1 agc strlcpy((char *)target->TargetName, (char *)name, sizeof(target->TargetName)); 193 1.1 agc 194 1.1 agc return target; 195 1.1 agc } 196 1.1 agc 197 1.1 agc 198 1.1 agc /* 199 1.1 agc * delete_target: 200 1.1 agc * Delete a target entry after unlinking it from its lists. 201 1.1 agc * Also deletes all portals associated with the target. 202 1.1 agc * 203 1.1 agc * Parameter: 204 1.1 agc * target the pointer to the target 205 1.1 agc */ 206 1.1 agc 207 1.3 agc static void 208 1.1 agc delete_target(target_t * target) 209 1.1 agc { 210 1.1 agc portal_group_t *cgroup; 211 1.1 agc portal_t *curr = NULL; 212 1.1 agc 213 1.1 agc /* First delete all portals in all portal groups. */ 214 1.1 agc /* (this will also delete the groups) */ 215 1.1 agc while (target->num_groups) { 216 1.1 agc cgroup = TAILQ_FIRST(&target->group_list); 217 1.1 agc while (cgroup && cgroup->num_portals) { 218 1.1 agc curr = TAILQ_FIRST(&cgroup->portals); 219 1.1 agc if (curr) 220 1.1 agc delete_portal(curr, FALSE); 221 1.1 agc } 222 1.1 agc } 223 1.1 agc 224 1.1 agc /*Now delete the target itself */ 225 1.1 agc TAILQ_REMOVE(&list[TARGET_LIST].list, &target->entry, link); 226 1.1 agc list[TARGET_LIST].num_entries--; 227 1.1 agc free(target); 228 1.1 agc } 229 1.1 agc 230 1.1 agc 231 1.1 agc /* 232 1.1 agc * create_send_target: 233 1.1 agc * Create a send_target structure and initialize it. 234 1.1 agc * 235 1.1 agc * Parameter: 236 1.1 agc * name The target name 237 1.1 agc * addr The portal address 238 1.1 agc * 239 1.1 agc * Returns: Pointer to structure, NULL if allocation failed. 240 1.1 agc */ 241 1.1 agc 242 1.3 agc static target_t * 243 1.1 agc create_send_target(uint8_t * name, iscsi_portal_address_t * addr) 244 1.1 agc { 245 1.1 agc send_target_t *target; 246 1.1 agc 247 1.6 mlelstv DEB(9, ("Create Send Target %s", name)); 248 1.1 agc 249 1.1 agc if ((target = calloc(1, sizeof(*target))) == NULL) 250 1.1 agc return NULL; 251 1.1 agc 252 1.1 agc for (send_target_id++; 253 1.1 agc !send_target_id 254 1.1 agc || find_target_id(SEND_TARGETS_LIST, send_target_id) != NULL;) 255 1.1 agc send_target_id++; 256 1.1 agc 257 1.1 agc target->entry.sid.id = send_target_id; 258 1.1 agc strlcpy((char *)target->TargetName, (char *)name, sizeof(target->TargetName)); 259 1.1 agc target->addr = *addr; 260 1.1 agc target->num_groups = 1; 261 1.1 agc target->num_portals = 1; 262 1.1 agc 263 1.2 christos return (target_t *)(void *)target; 264 1.1 agc } 265 1.1 agc 266 1.1 agc /* 267 1.1 agc * delete_send_target: 268 1.1 agc * Delete a send_target entry after unlinking it from its lists. 269 1.1 agc * 270 1.1 agc * Parameter: 271 1.1 agc * send_target the pointer to the send_target 272 1.1 agc */ 273 1.1 agc 274 1.3 agc static void 275 1.1 agc delete_send_target(send_target_t * send_target) 276 1.1 agc { 277 1.1 agc generic_entry_t *curr; 278 1.1 agc uint32_t id; 279 1.1 agc 280 1.1 agc id = send_target->entry.sid.id; 281 1.1 agc 282 1.1 agc TAILQ_FOREACH(curr, &list[PORTAL_LIST].list, link) { 283 1.2 christos portal_t *p = (void *)curr; 284 1.2 christos if (p->portaltype == PORTAL_TYPE_SENDTARGET && 285 1.2 christos p->discoveryid == id) 286 1.2 christos p->discoveryid = 0; /* mark deleted */ 287 1.1 agc } 288 1.1 agc 289 1.1 agc TAILQ_REMOVE(&list[SEND_TARGETS_LIST].list, &send_target->entry, link); 290 1.1 agc list[SEND_TARGETS_LIST].num_entries--; 291 1.1 agc free(send_target); 292 1.1 agc } 293 1.1 agc 294 1.1 agc 295 1.1 agc 296 1.1 agc /* 297 1.1 agc * add_target: 298 1.1 agc * Handle ADD_TARGET request: Create a target or send_target and its 299 1.1 agc * associated portals. 300 1.1 agc * This routine allows the same target to be defined more than once, 301 1.1 agc * adding any missing data (for example additional portals). 302 1.1 agc * 303 1.1 agc * Parameter: 304 1.1 agc * par The request parameters. 305 1.1 agc * prsp Pointer to address of response buffer. 306 1.1 agc * prsp_temp Will be set to TRUE if buffer was allocated, FALSE 307 1.1 agc * for static buffer. 308 1.1 agc */ 309 1.1 agc 310 1.1 agc 311 1.1 agc void 312 1.1 agc add_target(iscsid_add_target_req_t *par, iscsid_response_t **prsp, 313 1.1 agc int *prsp_temp) 314 1.1 agc { 315 1.1 agc iscsid_add_target_rsp_t *res; 316 1.1 agc iscsid_response_t *rsp = *prsp; 317 1.1 agc target_t *target, *tn; 318 1.1 agc portal_t *portal; 319 1.1 agc int i, num; 320 1.1 agc 321 1.6 mlelstv DEB(9, ("Add Target, name %s, num_portals %d", 322 1.1 agc par->TargetName, par->num_portals)); 323 1.1 agc 324 1.1 agc if (par->list_kind == SEND_TARGETS_LIST && par->num_portals != 1) { 325 1.1 agc rsp->status = ISCSID_STATUS_PARAMETER_INVALID; 326 1.1 agc return; 327 1.1 agc } 328 1.1 agc /* check to see if the target already exists */ 329 1.1 agc if ((par->TargetName[0] && 330 1.1 agc (target = find_TargetName(par->list_kind, par->TargetName)) != NULL) || 331 1.1 agc (par->list_kind == SEND_TARGETS_LIST && 332 1.2 christos (target = (target_t *)(void *) 333 1.1 agc find_send_target_by_addr(&par->portal[0])) != NULL)) { 334 1.1 agc num = target->num_portals; 335 1.1 agc 336 1.1 agc /* symbolic name? */ 337 1.1 agc if (par->sym_name[0]) { 338 1.1 agc /* already named? rename if OK */ 339 1.1 agc tn = find_target_symname(par->list_kind, par->sym_name); 340 1.1 agc if (tn && tn != target) { 341 1.1 agc rsp->status = ISCSID_STATUS_DUPLICATE_NAME; 342 1.1 agc return; 343 1.1 agc } 344 1.1 agc strlcpy((char *)target->entry.sid.name, (char *)par->sym_name, sizeof(target->entry.sid.name)); 345 1.1 agc } 346 1.1 agc } else { 347 1.1 agc if (par->sym_name[0] && 348 1.1 agc (find_target_symname(par->list_kind, par->sym_name) || 349 1.1 agc find_portal_name(par->sym_name))) { 350 1.1 agc rsp->status = ISCSID_STATUS_DUPLICATE_NAME; 351 1.1 agc return; 352 1.1 agc } 353 1.1 agc 354 1.1 agc if (par->list_kind == SEND_TARGETS_LIST) 355 1.1 agc target = create_send_target(par->TargetName, &par->portal[0]); 356 1.1 agc else 357 1.1 agc target = create_target(par->TargetName); 358 1.1 agc 359 1.1 agc if (target == NULL) { 360 1.1 agc rsp->status = ISCSID_STATUS_NO_RESOURCES; 361 1.1 agc return; 362 1.1 agc } 363 1.1 agc num = 0; 364 1.1 agc strlcpy((char *)target->entry.sid.name, (char *)par->sym_name, 365 1.1 agc sizeof(target->entry.sid.name)); 366 1.1 agc } 367 1.1 agc 368 1.1 agc rsp = make_rsp(sizeof(*res) + (par->num_portals * sizeof(uint32_t)), 369 1.1 agc prsp, prsp_temp); 370 1.1 agc if (rsp == NULL) 371 1.1 agc return; 372 1.1 agc 373 1.2 christos res = (iscsid_add_target_rsp_t *)(void *)rsp->parameter; 374 1.1 agc res->target_id = target->entry.sid.id; 375 1.1 agc 376 1.1 agc /* link into target list */ 377 1.1 agc if (!num) { 378 1.1 agc TAILQ_INSERT_TAIL(&list[par->list_kind].list, &target->entry, 379 1.1 agc link); 380 1.1 agc list[par->list_kind].num_entries++; 381 1.1 agc } 382 1.1 agc 383 1.1 agc /* 384 1.1 agc Add the given portals. Note that create_portal also checks for 385 1.1 agc duplicate entries, and returns the pointer to the existing entry 386 1.1 agc if the request is a duplicate. 387 1.1 agc */ 388 1.1 agc 389 1.1 agc if (par->list_kind == SEND_TARGETS_LIST) { 390 1.1 agc res->portal_id[0] = target->entry.sid.id; 391 1.1 agc res->num_portals = 1; 392 1.1 agc } else { 393 1.1 agc for (i = 0; i < (int)par->num_portals; i++) { 394 1.1 agc portal = create_portal(target, &par->portal[i], 395 1.1 agc PORTAL_TYPE_STATIC, 396 1.1 agc target->entry.sid.id); 397 1.1 agc if (portal == NULL) { 398 1.1 agc rsp->status = ISCSID_STATUS_NO_RESOURCES; 399 1.1 agc break; 400 1.1 agc } 401 1.1 agc res->portal_id[i] = portal->entry.sid.id; 402 1.1 agc } 403 1.1 agc res->num_portals = i; 404 1.1 agc } 405 1.1 agc 406 1.6 mlelstv DEB(9, ("AddTarget returns")); 407 1.1 agc } 408 1.1 agc 409 1.1 agc 410 1.1 agc /* 411 1.1 agc * add_discovered_target: 412 1.1 agc * Check whether the given target and portal already exist. 413 1.1 agc * If not, add them. 414 1.1 agc * 415 1.1 agc * Parameter: 416 1.1 agc * TargetName 417 1.1 agc * portal 418 1.1 agc * dtype = type of portal added: PORTAL_TYPE_SENDTARGET or 419 1.1 agc * PORTAL_TYPE_ISNS 420 1.1 agc * did = ID of SendTargets or iSNS for which portal was discovered 421 1.1 agc * 422 1.1 agc * Returns: Pointer to created target, NULL on error (out of memory) 423 1.1 agc * Always sets portaltype to dtype even if portal already exists 424 1.1 agc * (used for refreshing to mark portals that we find) 425 1.1 agc */ 426 1.1 agc 427 1.1 agc target_t * 428 1.1 agc add_discovered_target(uint8_t * TargetName, iscsi_portal_address_t * addr, 429 1.1 agc iscsi_portal_types_t dtype, uint32_t did) 430 1.1 agc { 431 1.1 agc target_t *target; 432 1.1 agc portal_t *portal; 433 1.1 agc 434 1.6 mlelstv DEB(9, ("Add Discovered Target, name %s, addr %s", 435 1.1 agc TargetName, addr->address)); 436 1.1 agc 437 1.1 agc if ((target = find_TargetName(TARGET_LIST, TargetName)) == NULL) { 438 1.1 agc if ((target = create_target(TargetName)) == NULL) { 439 1.1 agc return NULL; 440 1.1 agc } 441 1.1 agc portal = create_portal(target, addr, dtype, did); 442 1.1 agc if (portal == NULL) { 443 1.1 agc free(target); 444 1.1 agc return NULL; 445 1.1 agc } 446 1.1 agc TAILQ_INSERT_TAIL(&list[TARGET_LIST].list, &target->entry, link); 447 1.1 agc list[TARGET_LIST].num_entries++; 448 1.1 agc } else if ((portal = create_portal(target, addr, dtype, did)) == NULL) { 449 1.1 agc return NULL; 450 1.1 agc } 451 1.1 agc portal->portaltype = dtype; 452 1.1 agc 453 1.1 agc return target; 454 1.1 agc } 455 1.1 agc 456 1.1 agc 457 1.1 agc /* 458 1.1 agc * set_target_options: 459 1.1 agc * Handle SET_TARGET_OPTIONS request: Copy the given options into the 460 1.1 agc * target structure. 461 1.1 agc * 462 1.1 agc * Parameter: 463 1.1 agc * par The request parameters. 464 1.1 agc * 465 1.1 agc * Returns: status 466 1.1 agc */ 467 1.1 agc 468 1.1 agc uint32_t 469 1.1 agc set_target_options(iscsid_get_set_target_options_t * par) 470 1.1 agc { 471 1.1 agc target_t *target; 472 1.1 agc 473 1.1 agc if ((target = find_target(par->list_kind, &par->target_id)) == NULL) 474 1.1 agc return ISCSID_STATUS_INVALID_TARGET_ID; 475 1.1 agc 476 1.1 agc target->options = *par; 477 1.1 agc 478 1.1 agc return ISCSID_STATUS_SUCCESS; 479 1.1 agc } 480 1.1 agc 481 1.1 agc 482 1.1 agc /* 483 1.1 agc * set_target_auth: 484 1.1 agc * Handle SET_TARGET_AUTHENTICATION request: Copy the given options into the 485 1.1 agc * target structure. 486 1.1 agc * 487 1.1 agc * Parameter: 488 1.1 agc * par The request parameters. 489 1.1 agc * 490 1.1 agc * Returns: status 491 1.1 agc */ 492 1.1 agc 493 1.1 agc uint32_t 494 1.1 agc set_target_auth(iscsid_set_target_authentication_req_t * par) 495 1.1 agc { 496 1.1 agc target_t *target; 497 1.1 agc 498 1.1 agc if ((target = find_target(par->list_kind, &par->target_id)) == NULL) { 499 1.1 agc return ISCSID_STATUS_INVALID_TARGET_ID; 500 1.1 agc } 501 1.1 agc target->auth = *par; 502 1.1 agc 503 1.1 agc return ISCSID_STATUS_SUCCESS; 504 1.1 agc } 505 1.1 agc 506 1.1 agc 507 1.1 agc /* 508 1.1 agc * get_target_info: 509 1.1 agc * Handle GET_TARGET_INFO request: Return information about the given 510 1.1 agc * target and its portals. If a portal ID is given, returns only the 511 1.1 agc * target info and the ID of this portal. 512 1.1 agc * 513 1.1 agc * Parameter: 514 1.1 agc * par The request parameters. 515 1.1 agc * prsp Pointer to address of response buffer. 516 1.1 agc * prsp_temp Will be set to TRUE if buffer was allocated, FALSE 517 1.1 agc * for static buffer. 518 1.1 agc */ 519 1.1 agc 520 1.1 agc void 521 1.1 agc get_target_info(iscsid_list_id_t *par, iscsid_response_t **prsp, int *prsp_temp) 522 1.1 agc { 523 1.1 agc iscsid_get_target_rsp_t *res; 524 1.1 agc iscsid_response_t *rsp = *prsp; 525 1.1 agc uint32_t *idp; 526 1.1 agc target_t *target; 527 1.1 agc portal_group_t *cgroup; 528 1.1 agc portal_t *curr = NULL; 529 1.1 agc int num = 1; 530 1.1 agc 531 1.6 mlelstv DEB(10, ("get_target_info, id %d", par->id.id)); 532 1.1 agc 533 1.1 agc if ((target = find_target(par->list_kind, &par->id)) == NULL) { 534 1.1 agc if (par->list_kind == SEND_TARGETS_LIST || 535 1.1 agc (curr = find_portal(&par->id)) == NULL) { 536 1.1 agc rsp->status = ISCSID_STATUS_INVALID_TARGET_ID; 537 1.1 agc return; 538 1.1 agc } 539 1.1 agc target = curr->target; 540 1.1 agc } else if (par->list_kind != SEND_TARGETS_LIST) { 541 1.1 agc num = target->num_portals; 542 1.1 agc } 543 1.1 agc rsp = make_rsp(sizeof(*res) + (num - 1) * sizeof(uint32_t), 544 1.1 agc prsp, prsp_temp); 545 1.1 agc if (rsp == NULL) 546 1.1 agc return; 547 1.1 agc 548 1.2 christos res = (iscsid_get_target_rsp_t *)(void *)rsp->parameter; 549 1.1 agc res->target_id = target->entry.sid; 550 1.1 agc strlcpy((char *)res->TargetName, (char *)target->TargetName, 551 1.1 agc sizeof(res->TargetName)); 552 1.1 agc strlcpy((char *)res->TargetAlias, (char *)target->TargetAlias, 553 1.1 agc sizeof(res->TargetAlias)); 554 1.1 agc 555 1.1 agc res->num_portals = num; 556 1.1 agc idp = res->portal; 557 1.1 agc 558 1.1 agc if (curr) { 559 1.1 agc *idp = curr->entry.sid.id; 560 1.1 agc } else if (par->list_kind != SEND_TARGETS_LIST) { 561 1.1 agc TAILQ_FOREACH(cgroup, &target->group_list, groups) 562 1.1 agc TAILQ_FOREACH(curr, &cgroup->portals, group_list) 563 1.1 agc * idp++ = curr->entry.sid.id; 564 1.1 agc } else 565 1.1 agc *idp = target->entry.sid.id; 566 1.1 agc } 567 1.1 agc 568 1.1 agc 569 1.1 agc /* 570 1.1 agc * add_portal: 571 1.1 agc * Handle ADD_PORTAL request: Add a portal to an existing target. 572 1.1 agc * 573 1.1 agc * Parameter: 574 1.1 agc * par The request parameters. 575 1.1 agc * prsp Pointer to address of response buffer. 576 1.1 agc * prsp_temp Will be set to TRUE if buffer was allocated, FALSE 577 1.1 agc * for static buffer. 578 1.1 agc */ 579 1.1 agc 580 1.1 agc 581 1.1 agc void 582 1.1 agc add_portal(iscsid_add_portal_req_t *par, iscsid_response_t **prsp, 583 1.1 agc int *prsp_temp) 584 1.1 agc { 585 1.1 agc iscsid_add_portal_rsp_t *res; 586 1.1 agc iscsid_response_t *rsp = *prsp; 587 1.1 agc target_t *target; 588 1.1 agc portal_t *portal; 589 1.1 agc 590 1.6 mlelstv DEB(9, ("Add portal: target %d (%s), symname %s, addr %s", 591 1.1 agc par->target_id.id, par->target_id.name, 592 1.1 agc par->sym_name, par->portal.address)); 593 1.1 agc 594 1.1 agc if ((target = find_target(TARGET_LIST, &par->target_id)) == NULL) { 595 1.1 agc rsp->status = ISCSID_STATUS_INVALID_TARGET_ID; 596 1.1 agc return; 597 1.1 agc } 598 1.1 agc 599 1.1 agc if (par->sym_name[0] && 600 1.1 agc (find_target_symname(TARGET_LIST, par->sym_name) || 601 1.1 agc find_portal_name(par->sym_name))) { 602 1.1 agc rsp->status = ISCSID_STATUS_DUPLICATE_NAME; 603 1.1 agc return; 604 1.1 agc } 605 1.1 agc 606 1.1 agc portal = create_portal(target, &par->portal, PORTAL_TYPE_STATIC, 607 1.1 agc target->entry.sid.id); 608 1.1 agc if (portal == NULL) { 609 1.1 agc rsp->status = ISCSID_STATUS_NO_RESOURCES; 610 1.1 agc return; 611 1.1 agc } 612 1.1 agc 613 1.1 agc if (par->sym_name[0]) { 614 1.1 agc strlcpy((char *)portal->entry.sid.name, (char *)par->sym_name, 615 1.1 agc sizeof(portal->entry.sid.name)); 616 1.1 agc } 617 1.1 agc portal->options = par->options; 618 1.1 agc 619 1.1 agc rsp = make_rsp(sizeof(*res), prsp, prsp_temp); 620 1.1 agc if (rsp == NULL) 621 1.1 agc return; 622 1.2 christos #if 0 /*XXX: christos res is uninitialized here?? */ 623 1.1 agc res->target_id = target->entry.sid; 624 1.1 agc res->portal_id = portal->entry.sid; 625 1.2 christos #endif 626 1.1 agc 627 1.6 mlelstv DEB(9, ("AddPortal success (id %d)", portal->entry.sid.id)); 628 1.1 agc } 629 1.1 agc 630 1.1 agc 631 1.1 agc /* 632 1.1 agc * get_portal_info: 633 1.1 agc * Handle GET_PORTAL_INFO request: Return information about the given 634 1.1 agc * portal. 635 1.1 agc * 636 1.1 agc * Parameter: 637 1.1 agc * par The request parameters. 638 1.1 agc * prsp Pointer to address of response buffer. 639 1.1 agc * prsp_temp Will be set to TRUE if buffer was allocated, FALSE 640 1.1 agc * for static buffer. 641 1.1 agc */ 642 1.1 agc 643 1.1 agc void 644 1.1 agc get_portal_info(iscsid_list_id_t *par, iscsid_response_t **prsp, int *prsp_temp) 645 1.1 agc { 646 1.1 agc iscsid_get_portal_rsp_t *res; 647 1.1 agc iscsid_response_t *rsp = *prsp; 648 1.1 agc portal_t *portal = NULL; 649 1.1 agc send_target_t *starg = NULL; 650 1.1 agc int err; 651 1.1 agc 652 1.6 mlelstv DEB(10, ("get_portal_info, id %d", par->id.id)); 653 1.1 agc 654 1.1 agc if (par->list_kind == SEND_TARGETS_LIST) 655 1.2 christos err = ((starg = (send_target_t *)(void *)find_target(par->list_kind, 656 1.1 agc &par->id)) == NULL); 657 1.1 agc else 658 1.1 agc err = ((portal = find_portal(&par->id)) == NULL); 659 1.1 agc 660 1.1 agc if (err) { 661 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PORTAL_ID; 662 1.1 agc return; 663 1.1 agc } 664 1.1 agc 665 1.1 agc rsp = make_rsp(sizeof(*res), prsp, prsp_temp); 666 1.1 agc if (rsp == NULL) 667 1.1 agc return; 668 1.1 agc 669 1.2 christos res = (iscsid_get_portal_rsp_t *)(void *)rsp->parameter; 670 1.1 agc if (par->list_kind == SEND_TARGETS_LIST) { 671 1.1 agc res->target_id = starg->entry.sid; 672 1.1 agc res->portal_id = starg->entry.sid; 673 1.1 agc res->portal = starg->addr; 674 1.1 agc } else { 675 1.1 agc res->target_id = portal->target->entry.sid; 676 1.1 agc res->portal_id = portal->entry.sid; 677 1.1 agc res->portal = portal->addr; 678 1.1 agc } 679 1.1 agc } 680 1.1 agc 681 1.1 agc /* 682 1.1 agc * remove_target: 683 1.1 agc * Handle REMOVE_TARGET request: Removes a target, target portal, 684 1.1 agc * or Send-Targets portal from its respective list. 685 1.1 agc * Removing a target will remove all associated portals. 686 1.1 agc * 687 1.1 agc * Parameter: 688 1.1 agc * par The request parameters = iscsid_list_id_t 689 1.1 agc * containing the target ID. 690 1.1 agc * 691 1.1 agc * Returns: status 692 1.1 agc */ 693 1.1 agc 694 1.1 agc uint32_t 695 1.1 agc remove_target(iscsid_list_id_t * par) 696 1.1 agc { 697 1.1 agc target_t *target = NULL; 698 1.1 agc portal_t *portal = NULL; 699 1.1 agc send_target_t *starg = NULL; 700 1.1 agc int err; 701 1.1 agc 702 1.6 mlelstv DEB(9, ("remove_target, id %d", par->id.id)); 703 1.1 agc 704 1.1 agc if (par->list_kind == SEND_TARGETS_LIST) { 705 1.2 christos err = ((starg = (send_target_t *)(void *)find_target(par->list_kind, 706 1.1 agc &par->id)) == NULL); 707 1.1 agc if (!err) { 708 1.1 agc delete_send_target(starg); 709 1.1 agc } 710 1.1 agc } else if (par->list_kind == PORTAL_LIST) { 711 1.1 agc err = ((portal = find_portal(&par->id)) == NULL); 712 1.1 agc if (!err) { 713 1.1 agc delete_portal(portal, FALSE); 714 1.1 agc } 715 1.1 agc } else { 716 1.1 agc target = find_target(par->list_kind, &par->id); 717 1.1 agc err = (target == NULL); 718 1.1 agc if (!err) { 719 1.1 agc delete_target(target); 720 1.1 agc } 721 1.1 agc } 722 1.1 agc 723 1.1 agc return err ? ISCSID_STATUS_INVALID_PORTAL_ID : ISCSID_STATUS_SUCCESS; 724 1.1 agc } 725 1.1 agc 726 1.1 agc 727 1.1 agc 728 1.1 agc /* 729 1.1 agc * cl_get_address: 730 1.1 agc * Get an address specification that may include port and group tag. 731 1.1 agc * 732 1.1 agc * Parameter: 733 1.1 agc * portal The portal address 734 1.1 agc * str The parameter string to scan 735 1.1 agc * 736 1.1 agc * Returns: 0 on error, 1 if OK. 737 1.1 agc */ 738 1.1 agc 739 1.3 agc static int 740 1.1 agc cl_get_address(iscsi_portal_address_t * portal, char *str) 741 1.1 agc { 742 1.1 agc char *sp, *sp2; 743 1.1 agc int val; 744 1.1 agc 745 1.1 agc /* is there a port? don't check inside square brackets (IPv6 addr) */ 746 1.1 agc for (sp = str + 1, val = 0; *sp && (*sp != ':' || val); sp++) { 747 1.1 agc if (*sp == '[') 748 1.1 agc val = 1; 749 1.1 agc else if (*sp == ']') 750 1.1 agc val = 0; 751 1.1 agc } 752 1.1 agc 753 1.1 agc /* */ 754 1.1 agc if (*sp) { 755 1.1 agc for (sp2 = sp + 1; *sp2 && *sp2 != ':'; sp2++); 756 1.1 agc /* if there's a second colon, assume it's an unbracketed IPv6 757 1.1 agc * address */ 758 1.1 agc if (!*sp2) { 759 1.1 agc /* truncate source, that's the address */ 760 1.1 agc *sp++ = '\0'; 761 1.1 agc if (sscanf(sp, "%d", &val) != 1) 762 1.1 agc return 0; 763 1.1 agc if (val < 0 || val > 0xffff) 764 1.1 agc return 0; 765 1.1 agc portal->port = (uint16_t) val; 766 1.1 agc } 767 1.1 agc /* is there a group tag? */ 768 1.1 agc for (; isdigit((unsigned char)*sp); sp++) { 769 1.1 agc } 770 1.1 agc if (*sp && *sp != ',') 771 1.1 agc return 0; 772 1.1 agc } else 773 1.1 agc for (sp = str + 1; *sp && *sp != ','; sp++); 774 1.1 agc 775 1.1 agc if (*sp) { 776 1.1 agc if (sscanf(sp + 1, "%d", &val) != 1) 777 1.1 agc return 0; 778 1.1 agc if (val < 0 || val > 0xffff) 779 1.1 agc return 0; 780 1.1 agc portal->group_tag = (uint16_t) val; 781 1.1 agc /* truncate source, that's the address */ 782 1.1 agc *sp = '\0'; 783 1.1 agc } 784 1.1 agc /* only check length, don't verify correct format (too many 785 1.1 agc * possibilities) */ 786 1.1 agc if (strlen(str) >= sizeof(portal->address)) 787 1.1 agc return 0; 788 1.1 agc 789 1.1 agc strlcpy((char *)portal->address, str, sizeof(portal->address)); 790 1.1 agc 791 1.1 agc return 1; 792 1.1 agc } 793 1.1 agc 794 1.1 agc /* 795 1.1 agc * refresh_send_target: 796 1.1 agc * Handle REFRESH_TARGETS request for a Send Target 797 1.1 agc * 798 1.1 agc * Parameter: 799 1.1 agc * id The send target ID. 800 1.1 agc * 801 1.1 agc * Returns: status 802 1.1 agc */ 803 1.1 agc 804 1.1 agc 805 1.3 agc static uint32_t 806 1.1 agc refresh_send_target(uint32_t id) 807 1.1 agc { 808 1.1 agc uint8_t *response_buffer = NULL; 809 1.1 agc uint32_t response_size; 810 1.1 agc uint32_t ret; 811 1.1 agc uint8_t *TargetName; 812 1.1 agc iscsi_portal_address_t addr; 813 1.1 agc uint8_t *tp, *sp; 814 1.1 agc generic_entry_t *curr; 815 1.1 agc generic_entry_t *next; 816 1.1 agc send_target_t *sendtarg; 817 1.1 agc int rc; 818 1.1 agc 819 1.1 agc /* 820 1.1 agc * Go through our list of portals and mark each one 821 1.1 agc * belonging to the current sendtargets group to refreshing 822 1.1 agc * This mark is used afterwards to remove any portals that 823 1.1 agc * were not refreshed (because the mark gets reset for portals 824 1.1 agc * that are refreshed). 825 1.1 agc */ 826 1.1 agc 827 1.1 agc TAILQ_FOREACH(curr, &list[PORTAL_LIST].list, link) { 828 1.2 christos portal_t *p = (void *)curr; 829 1.2 christos if (p->portaltype == PORTAL_TYPE_SENDTARGET && 830 1.2 christos p->discoveryid == id) { 831 1.2 christos p->portaltype = PORTAL_TYPE_REFRESHING; 832 1.1 agc } 833 1.1 agc } 834 1.1 agc 835 1.1 agc if ((ret = send_targets(id, &response_buffer, &response_size)) == 0) { 836 1.1 agc /* 837 1.1 agc * Parse the response target list 838 1.1 agc * The SendTargets response in response_buffer is a list of 839 1.1 agc * target strings. Each target string consists of a TargetName 840 1.1 agc * string, followed by 0 or more TargetAddress strings: 841 1.1 agc * 842 1.1 agc * TargetName=<target-name> 843 1.1 agc * TargetAddress=<hostname-or-ip>[:<tcp-port>], 844 1.1 agc * <portal-group-tag> 845 1.1 agc * The entire list is terminated by a null (after 846 1.1 agc * response_size bytes) (this terminating NULL was placed 847 1.1 agc * there by send_targets routine.) 848 1.1 agc */ 849 1.1 agc 850 1.1 agc tp = response_buffer; 851 1.1 agc while (*tp) { 852 1.1 agc if (strncmp((char *)tp, "TargetName=", 11) != 0) { 853 1.6 mlelstv DEBOUT(("Response not TargetName <%s>", tp)); 854 1.1 agc break; 855 1.1 agc } 856 1.1 agc tp += 11; 857 1.1 agc TargetName = tp; /*Point to target name */ 858 1.1 agc while (*tp++) { 859 1.1 agc } 860 1.1 agc rc = -1; /* Mark no address found yet */ 861 1.1 agc 862 1.1 agc /*Now process any "TargetAddress" entries following */ 863 1.1 agc while (*tp && strncmp((char *)tp, "TargetAddress=", 14) == 0) { 864 1.1 agc tp += 14; 865 1.1 agc sp = tp; /* save start of address */ 866 1.1 agc while (*tp++) { 867 1.1 agc } 868 1.1 agc /*Get the target address */ 869 1.1 agc rc = cl_get_address(&addr, (char *)sp); 870 1.1 agc if (rc) { 871 1.1 agc add_discovered_target(TargetName, 872 1.1 agc &addr, PORTAL_TYPE_SENDTARGET, 873 1.1 agc id); 874 1.1 agc } else { 875 1.6 mlelstv DEBOUT(("Syntax error in returned target address <%s>", sp)); 876 1.1 agc break; 877 1.1 agc } 878 1.1 agc } 879 1.1 agc 880 1.1 agc if (rc == -1) { 881 1.1 agc /* There are no TargetAddress entries 882 1.1 agc * associated with TargetName. This means the 883 1.1 agc * sendtarget address is used. */ 884 1.1 agc sendtarg = find_send_target_id(id); 885 1.1 agc if (sendtarg != NULL) { 886 1.1 agc add_discovered_target(TargetName, 887 1.1 agc &sendtarg->addr, 888 1.1 agc PORTAL_TYPE_SENDTARGET, id); 889 1.1 agc } 890 1.1 agc } 891 1.1 agc } /* end of while */ 892 1.1 agc } 893 1.1 agc /* 894 1.1 agc * Go through our list of portals and look for ones 895 1.1 agc * that are still marked for refreshing. 896 1.1 agc * These are ones that are no longer there and should be removed. 897 1.1 agc */ 898 1.1 agc 899 1.1 agc for (curr = TAILQ_FIRST(&list[PORTAL_LIST].list); curr != NULL; 900 1.1 agc curr = next) { 901 1.2 christos portal_t *p = (void *)curr; 902 1.1 agc next = TAILQ_NEXT(curr, link); 903 1.2 christos if (p->portaltype == PORTAL_TYPE_REFRESHING) 904 1.2 christos delete_portal(p, TRUE); 905 1.1 agc } 906 1.1 agc 907 1.1 agc /* 908 1.1 agc * Clean up 909 1.1 agc */ 910 1.1 agc 911 1.1 agc if (response_buffer != NULL) 912 1.1 agc free(response_buffer); 913 1.1 agc 914 1.1 agc return ret; 915 1.1 agc } 916 1.1 agc 917 1.1 agc 918 1.1 agc /* 919 1.1 agc * cleanup_send_target_orphans: 920 1.1 agc * Delete portals that were discovered through a now deleted send target. 921 1.1 agc */ 922 1.1 agc 923 1.1 agc 924 1.3 agc static void 925 1.1 agc cleanup_orphans(iscsi_portal_types_t type) 926 1.1 agc { 927 1.1 agc generic_entry_t *curr; 928 1.1 agc generic_entry_t *next; 929 1.1 agc 930 1.1 agc /* 931 1.1 agc * Go through the list of portals and look for ones marked with a zero 932 1.1 agc * discovery ID, those are associated with send targets that no 933 1.1 agc * longer exist. 934 1.1 agc */ 935 1.1 agc 936 1.1 agc for (curr = TAILQ_FIRST(&list[PORTAL_LIST].list); curr != NULL; 937 1.1 agc curr = next) { 938 1.2 christos portal_t *p = (void *)curr; 939 1.1 agc next = TAILQ_NEXT(curr, link); 940 1.2 christos if (p->portaltype == type && p->discoveryid == 0) { 941 1.2 christos delete_portal(p, TRUE); 942 1.1 agc } 943 1.1 agc } 944 1.1 agc } 945 1.1 agc 946 1.1 agc 947 1.1 agc /* 948 1.1 agc * refresh_targets: 949 1.1 agc * Handle REFRESH_TARGETS request: 950 1.1 agc * Refreshes the list of targets discovered via SendTargets or iSNS 951 1.1 agc * 952 1.1 agc * Parameter: 953 1.1 agc * The request parameter = iscsid_refresh_targets_req_t containing: 954 1.1 agc * iscsid_list_kind_t kind; Kind: 955 1.1 agc * SEND_TARGETS_LIST 956 1.1 agc * ISNS_LIST 957 1.1 agc * uint32_t num_ids; # of targets in list 958 1.1 agc * uint32_t id [1]; List of targets 959 1.1 agc * 960 1.1 agc * Returns: status 961 1.1 agc */ 962 1.1 agc 963 1.1 agc uint32_t 964 1.1 agc refresh_targets(iscsid_refresh_req_t * par) 965 1.1 agc { 966 1.1 agc uint32_t t; 967 1.1 agc uint32_t rc, retval; 968 1.1 agc generic_entry_t *curr; 969 1.1 agc 970 1.1 agc retval = ISCSID_STATUS_NO_TARGETS_FOUND; 971 1.1 agc 972 1.1 agc switch (par->kind) { 973 1.1 agc case TARGET_LIST: 974 1.1 agc /* 975 1.1 agc * Refreshing for a specific target makes no sense if it's 976 1.7 andvar * static. Maybe implement it for dynamically discovered 977 1.1 agc * targets? But then it's best done through the discovering 978 1.1 agc * instance, or we'll refresh much more than just the given 979 1.1 agc * target. And refreshing the whole list is iffy as well. So 980 1.1 agc * refuse this op on the target list for now. 981 1.1 agc */ 982 1.1 agc break; 983 1.1 agc 984 1.1 agc case SEND_TARGETS_LIST: 985 1.6 mlelstv DEB(9, ("Refresh Send Targets List - num_ids = %d", 986 1.1 agc par->num_ids)); 987 1.1 agc if (par->num_ids) { 988 1.1 agc /* Target ids are specified */ 989 1.1 agc for (t = 0; t < par->num_ids; t++) { 990 1.1 agc rc = refresh_send_target(par->id[t]); 991 1.1 agc if (rc == 0) { 992 1.1 agc retval = ISCSID_STATUS_SUCCESS; 993 1.1 agc } 994 1.1 agc } 995 1.1 agc } else { 996 1.1 agc cleanup_orphans(PORTAL_TYPE_SENDTARGET); 997 1.1 agc 998 1.1 agc /* No target ids specified - refresh all. */ 999 1.1 agc TAILQ_FOREACH(curr, &list[SEND_TARGETS_LIST].list, link) 1000 1.1 agc if ((rc = refresh_send_target(curr->sid.id)) == 0) 1001 1.1 agc retval = ISCSID_STATUS_SUCCESS; 1002 1.1 agc } 1003 1.1 agc return retval; 1004 1.1 agc 1005 1.1 agc #ifndef ISCSI_MINIMAL 1006 1.1 agc case ISNS_LIST: 1007 1.6 mlelstv DEB(9, ("Refresh iSNS List - num_ids = %d", par->num_ids)); 1008 1.1 agc if (par->num_ids) { 1009 1.1 agc /*Target ids are specified */ 1010 1.1 agc for (t = 0; t < par->num_ids; t++) 1011 1.1 agc if ((rc = refresh_isns_server(par->id[t])) == 0) 1012 1.1 agc retval = ISCSI_STATUS_SUCCESS; 1013 1.1 agc } else { 1014 1.1 agc cleanup_orphans(PORTAL_TYPE_ISNS); 1015 1.1 agc 1016 1.1 agc /*No target ids specified - refresh all. */ 1017 1.1 agc TAILQ_FOREACH(curr, &list[ISNS_LIST].list, link) 1018 1.1 agc if ((rc = refresh_isns_server(curr->sid.id)) == 0) 1019 1.1 agc retval = ISCSI_STATUS_SUCCESS; 1020 1.1 agc } 1021 1.1 agc return retval; 1022 1.1 agc #endif 1023 1.1 agc 1024 1.1 agc default: 1025 1.1 agc break; 1026 1.1 agc } 1027 1.1 agc 1028 1.1 agc return ISCSID_STATUS_PARAMETER_INVALID; 1029 1.1 agc } 1030