1 1.10 andvar /* $NetBSD: iscsid_lists.c,v 1.10 2022/05/31 08:43:14 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 33 1.1 agc #include "iscsid_globals.h" 34 1.1 agc 35 1.1 agc /* counter for initiator ID */ 36 1.3 agc static uint32_t initiator_id = 0; 37 1.1 agc 38 1.1 agc /* -------------------------------------------------------------------------- */ 39 1.1 agc 40 1.1 agc #if 0 41 1.1 agc 42 1.1 agc /* 43 1.1 agc * verify_session: 44 1.1 agc * Verify that a specific session still exists, delete it if not. 45 1.1 agc * 46 1.1 agc * Parameter: The session pointer. 47 1.1 agc */ 48 1.1 agc 49 1.3 agc static void 50 1.1 agc verify_session(session_t * sess) 51 1.1 agc { 52 1.1 agc generic_entry_t *curr, *next; 53 1.1 agc int nosess = 0; 54 1.1 agc 55 1.1 agc for (curr = sess->connections.tqh_first; curr != NULL && !nosess; curr = next) { 56 1.1 agc next = curr->link.tqe_next; 57 1.1 agc nosess = verify_connection((connection_t *) curr) == ISCSI_STATUS_INVALID_SESSION_ID; 58 1.1 agc } 59 1.1 agc 60 1.1 agc if (!nosess && sess->num_connections) 61 1.1 agc return; 62 1.1 agc 63 1.1 agc TAILQ_REMOVE(&list[SESSION_LIST].list, &sess->entry, link); 64 1.1 agc list[SESSION_LIST].num_entries--; 65 1.1 agc 66 1.1 agc while ((curr = TAILQ_FIRST(&sess->connections)) != NULL) { 67 1.1 agc TAILQ_REMOVE(&sess->connections, curr, link); 68 1.1 agc free(curr); 69 1.1 agc } 70 1.1 agc free(sess); 71 1.1 agc } 72 1.1 agc 73 1.1 agc 74 1.1 agc /* 75 1.1 agc * verify_sessions: 76 1.1 agc * Verify that all sessions in the list still exist. 77 1.1 agc */ 78 1.1 agc 79 1.1 agc void 80 1.1 agc verify_sessions(void) 81 1.1 agc { 82 1.1 agc generic_entry_t *curr, *next; 83 1.1 agc 84 1.1 agc for (curr = list[SESSION_LIST].list.tqh_first; curr != NULL; curr = next) { 85 1.1 agc next = curr->link.tqe_next; 86 1.1 agc verify_session((session_t *) curr); 87 1.1 agc } 88 1.1 agc } 89 1.1 agc 90 1.1 agc #endif 91 1.1 agc 92 1.1 agc /* -------------------------------------------------------------------------- */ 93 1.1 agc 94 1.1 agc /* 95 1.1 agc * find_id: 96 1.1 agc * Find a list element by ID. 97 1.1 agc * 98 1.1 agc * Parameter: the list head and the ID to search for 99 1.1 agc * 100 1.1 agc * Returns: The pointer to the element (or NULL if not found) 101 1.1 agc */ 102 1.1 agc 103 1.1 agc generic_entry_t * 104 1.1 agc find_id(generic_list_t * head, uint32_t id) 105 1.1 agc { 106 1.1 agc generic_entry_t *curr; 107 1.1 agc 108 1.1 agc if (!id) 109 1.1 agc return NULL; 110 1.1 agc 111 1.1 agc TAILQ_FOREACH(curr, head, link) 112 1.2 christos if (curr->sid.id == id) 113 1.1 agc break; 114 1.1 agc 115 1.1 agc return curr; 116 1.1 agc } 117 1.1 agc 118 1.1 agc /* 119 1.1 agc * find_name: 120 1.1 agc * Find a list entry by name. 121 1.1 agc * 122 1.1 agc * Parameter: the list head and the symbolic name to search for 123 1.1 agc * 124 1.1 agc * Returns: The pointer to the entry (or NULL if not found) 125 1.1 agc */ 126 1.1 agc 127 1.1 agc generic_entry_t * 128 1.1 agc find_name(generic_list_t * head, uint8_t * name) 129 1.1 agc { 130 1.1 agc generic_entry_t *curr; 131 1.1 agc 132 1.1 agc if (!*name) 133 1.1 agc return NULL; 134 1.1 agc 135 1.1 agc TAILQ_FOREACH(curr, head, link) 136 1.1 agc if (strcmp((char *)curr->sid.name, (char *)name) == 0) 137 1.1 agc break; 138 1.1 agc 139 1.1 agc return curr; 140 1.1 agc } 141 1.1 agc 142 1.1 agc 143 1.1 agc /* 144 1.1 agc * find_sym_id: 145 1.1 agc * Find a list entry by name or numeric id. 146 1.1 agc * 147 1.1 agc * Parameter: the list head and the symbolic id to search for 148 1.1 agc * 149 1.1 agc * Returns: The pointer to the entry (or NULL if not found) 150 1.1 agc */ 151 1.1 agc 152 1.1 agc generic_entry_t * 153 1.1 agc find_sym_id(generic_list_t * head, iscsid_sym_id_t * sid) 154 1.1 agc { 155 1.1 agc 156 1.1 agc if (sid->id != 0) 157 1.1 agc return find_id(head, sid->id); 158 1.1 agc 159 1.1 agc return (sid->name[0]) ? find_name(head, sid->name) : NULL; 160 1.1 agc } 161 1.1 agc 162 1.1 agc 163 1.1 agc /* 164 1.1 agc * get_id: 165 1.1 agc * Get the numeric ID for a symbolic ID 166 1.1 agc * 167 1.1 agc * Parameter: the list head and the symbolic id 168 1.1 agc * 169 1.1 agc * Returns: The numeric ID (0 if not found) 170 1.1 agc */ 171 1.1 agc 172 1.1 agc uint32_t 173 1.1 agc get_id(generic_list_t * head, iscsid_sym_id_t * sid) 174 1.1 agc { 175 1.1 agc generic_entry_t *ent; 176 1.1 agc 177 1.1 agc if (sid->id != 0) 178 1.1 agc return sid->id; 179 1.1 agc 180 1.1 agc ent = find_name(head, sid->name); 181 1.1 agc return (ent != NULL) ? ent->sid.id : 0; 182 1.1 agc } 183 1.1 agc 184 1.1 agc 185 1.1 agc /* 186 1.1 agc * find_target_name: 187 1.1 agc * Find a target by TargetName. 188 1.1 agc * 189 1.1 agc * Parameter: the target name 190 1.1 agc * 191 1.1 agc * Returns: The pointer to the target (or NULL if not found) 192 1.1 agc */ 193 1.1 agc 194 1.1 agc target_t * 195 1.1 agc find_target(iscsid_list_kind_t lst, iscsid_sym_id_t * sid) 196 1.1 agc { 197 1.1 agc target_t *targ; 198 1.1 agc 199 1.2 christos if ((targ = (target_t *)(void *)find_sym_id (&list [lst].list, sid)) != NULL) 200 1.1 agc return targ; 201 1.1 agc if (lst == TARGET_LIST) { 202 1.1 agc portal_t *portal; 203 1.1 agc 204 1.2 christos if ((portal = (void *)find_portal (sid)) != NULL) 205 1.1 agc return portal->target; 206 1.1 agc } 207 1.1 agc return NULL; 208 1.1 agc } 209 1.1 agc 210 1.1 agc 211 1.1 agc /* 212 1.1 agc * find_target_name: 213 1.1 agc * Find a target by TargetName. 214 1.1 agc * 215 1.1 agc * Parameter: the target name 216 1.1 agc * 217 1.1 agc * Returns: The pointer to the target (or NULL if not found) 218 1.1 agc */ 219 1.1 agc 220 1.1 agc target_t * 221 1.1 agc find_TargetName(iscsid_list_kind_t lst, uint8_t * name) 222 1.1 agc { 223 1.1 agc generic_entry_t *curr; 224 1.2 christos target_t *t = NULL; 225 1.1 agc 226 1.1 agc if (lst == PORTAL_LIST) 227 1.1 agc lst = TARGET_LIST; 228 1.1 agc 229 1.2 christos TAILQ_FOREACH(curr, &list[lst].list, link) { 230 1.2 christos t = (void *)curr; 231 1.2 christos if (strcmp((char *)t->TargetName, (char *)name) == 0) 232 1.1 agc break; 233 1.2 christos } 234 1.1 agc 235 1.7 riz /* return curr instead of t because curr==NULL if name not found */ 236 1.9 mlelstv DEB(10, ("Find_TargetName returns %p", curr)); 237 1.6 riz return (target_t *)curr; 238 1.1 agc } 239 1.1 agc 240 1.1 agc 241 1.1 agc /* 242 1.1 agc * find_portal_by_addr: 243 1.1 agc * Find a Portal by Address. 244 1.1 agc * 245 1.1 agc * Parameter: the associated target, and the address 246 1.1 agc * 247 1.1 agc * Returns: The pointer to the portal (or NULL if not found) 248 1.1 agc */ 249 1.1 agc 250 1.1 agc portal_t * 251 1.1 agc find_portal_by_addr(target_t * target, iscsi_portal_address_t * addr) 252 1.1 agc { 253 1.1 agc generic_entry_t *curr; 254 1.2 christos portal_t *p = NULL; 255 1.1 agc 256 1.1 agc TAILQ_FOREACH(curr, &list[PORTAL_LIST].list, link) { 257 1.2 christos p = (void *)curr; 258 1.9 mlelstv DEB(10, ("Find_portal_by_addr - addr %s port %d target %p", 259 1.2 christos p->addr.address, 260 1.2 christos p->addr.port, 261 1.4 riz p->target)); 262 1.1 agc 263 1.2 christos if (strcmp((char *)p->addr.address, (char *)addr->address) == 0 && 264 1.2 christos (!addr->port || p->addr.port == addr->port) && 265 1.2 christos p->target == target) 266 1.1 agc break; 267 1.1 agc } 268 1.1 agc 269 1.7 riz /* return curr instead of p because curr==NULL if not found */ 270 1.9 mlelstv DEB(10, ("Find_portal_by_addr returns %p", curr)); 271 1.7 riz return (portal_t *)curr; 272 1.1 agc } 273 1.1 agc 274 1.1 agc 275 1.1 agc /* 276 1.1 agc * find_send_target_by_addr: 277 1.1 agc * Find a Send Target by Address. 278 1.1 agc * 279 1.1 agc * Parameter: the address 280 1.1 agc * 281 1.1 agc * Returns: The pointer to the portal (or NULL if not found) 282 1.1 agc */ 283 1.1 agc 284 1.1 agc send_target_t * 285 1.1 agc find_send_target_by_addr(iscsi_portal_address_t * addr) 286 1.1 agc { 287 1.1 agc generic_entry_t *curr; 288 1.2 christos send_target_t *t = NULL; 289 1.1 agc 290 1.1 agc TAILQ_FOREACH(curr, &list[SEND_TARGETS_LIST].list, link) { 291 1.2 christos t = (void *)curr; 292 1.2 christos if (strcmp((char *)t->addr.address, (char *)addr->address) == 0 && 293 1.2 christos (!addr->port || t->addr.port == addr->port)) 294 1.1 agc break; 295 1.1 agc } 296 1.1 agc 297 1.7 riz /* return curr instead of p because curr==NULL if not found */ 298 1.9 mlelstv DEB(10, ("Find_send_target_by_addr returns %p", curr)); 299 1.7 riz return (send_target_t *)curr; 300 1.1 agc } 301 1.1 agc 302 1.1 agc 303 1.1 agc /* 304 1.1 agc * get_list: 305 1.1 agc * Handle GET_LIST request: Return the list of IDs contained in the list. 306 1.1 agc * 307 1.1 agc * Parameter: 308 1.1 agc * par The request parameters. 309 1.1 agc * prsp Pointer to address of response buffer. 310 1.1 agc * prsp_temp Will be set to TRUE if buffer was allocated, FALSE 311 1.1 agc * for static buffer. 312 1.1 agc */ 313 1.1 agc 314 1.1 agc void 315 1.1 agc get_list(iscsid_get_list_req_t * par, iscsid_response_t ** prsp, int *prsp_temp) 316 1.1 agc { 317 1.1 agc iscsid_get_list_rsp_t *res; 318 1.1 agc iscsid_response_t *rsp = *prsp; 319 1.1 agc int num; 320 1.1 agc uint32_t *idp; 321 1.1 agc generic_list_t *plist; 322 1.1 agc generic_entry_t *curr; 323 1.1 agc 324 1.9 mlelstv DEB(10, ("get_list, kind %d", par->list_kind)); 325 1.1 agc 326 1.1 agc if (par->list_kind == SESSION_LIST) 327 1.1 agc LOCK_SESSIONS; 328 1.1 agc else if (par->list_kind >= NUM_DAEMON_LISTS) { 329 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 330 1.1 agc return; 331 1.1 agc } 332 1.1 agc 333 1.1 agc plist = &list[par->list_kind].list; 334 1.1 agc num = list[par->list_kind].num_entries; 335 1.1 agc 336 1.1 agc if (!num) { 337 1.1 agc if (par->list_kind == SESSION_LIST) 338 1.1 agc UNLOCK_SESSIONS; 339 1.1 agc rsp->status = ISCSID_STATUS_LIST_EMPTY; 340 1.1 agc return; 341 1.1 agc } 342 1.1 agc 343 1.1 agc rsp = make_rsp(sizeof(iscsid_get_list_rsp_t) + 344 1.1 agc (num - 1) * sizeof(uint32_t), prsp, prsp_temp); 345 1.1 agc if (rsp == NULL) { 346 1.1 agc if (par->list_kind == SESSION_LIST) 347 1.1 agc UNLOCK_SESSIONS; 348 1.1 agc return; 349 1.1 agc } 350 1.1 agc /* copy the ID of all list entries */ 351 1.2 christos res = (iscsid_get_list_rsp_t *)(void *)rsp->parameter; 352 1.1 agc res->num_entries = num; 353 1.1 agc idp = res->id; 354 1.1 agc 355 1.1 agc TAILQ_FOREACH(curr, plist, link) 356 1.1 agc * idp++ = curr->sid.id; 357 1.1 agc 358 1.1 agc if (par->list_kind == SESSION_LIST) 359 1.1 agc UNLOCK_SESSIONS; 360 1.1 agc } 361 1.1 agc 362 1.1 agc 363 1.1 agc /* 364 1.1 agc * search_list: 365 1.1 agc * Handle SEARCH_LIST request: Search the given list for the string or 366 1.1 agc * address. 367 1.1 agc * Note: Not all combinations of list and search type make sense. 368 1.1 agc * 369 1.1 agc * Parameter: 370 1.1 agc * par The request parameters. 371 1.1 agc * prsp Pointer to address of response buffer. 372 1.1 agc * prsp_temp Will be set to TRUE if buffer was allocated, FALSE 373 1.1 agc * for static buffer. 374 1.1 agc */ 375 1.1 agc 376 1.1 agc void 377 1.1 agc search_list(iscsid_search_list_req_t * par, iscsid_response_t ** prsp, 378 1.1 agc int *prsp_temp) 379 1.1 agc { 380 1.1 agc iscsid_response_t *rsp = *prsp; 381 1.1 agc generic_entry_t *elem = NULL; 382 1.1 agc 383 1.9 mlelstv DEB(10, ("search_list, list_kind %d, search_kind %d", 384 1.1 agc par->list_kind, par->search_kind)); 385 1.1 agc 386 1.1 agc if (par->list_kind == SESSION_LIST) 387 1.1 agc LOCK_SESSIONS; 388 1.1 agc else if (par->list_kind >= NUM_DAEMON_LISTS) { 389 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 390 1.1 agc return; 391 1.1 agc } 392 1.1 agc 393 1.1 agc if (!list[par->list_kind].num_entries) { 394 1.1 agc if (par->list_kind == SESSION_LIST) 395 1.1 agc UNLOCK_SESSIONS; 396 1.1 agc rsp->status = ISCSID_STATUS_NOT_FOUND; 397 1.1 agc return; 398 1.1 agc } 399 1.1 agc 400 1.1 agc switch (par->search_kind) { 401 1.1 agc case FIND_ID: 402 1.1 agc elem = find_id(&list[par->list_kind].list, par->intval); 403 1.1 agc break; 404 1.1 agc 405 1.1 agc case FIND_NAME: 406 1.1 agc elem = find_name(&list[par->list_kind].list, par->strval); 407 1.1 agc break; 408 1.1 agc 409 1.1 agc case FIND_TARGET_NAME: 410 1.1 agc switch (par->list_kind) { 411 1.1 agc case TARGET_LIST: 412 1.1 agc case PORTAL_LIST: 413 1.1 agc case SEND_TARGETS_LIST: 414 1.2 christos elem = (void *)find_TargetName(par->list_kind, 415 1.1 agc par->strval); 416 1.1 agc break; 417 1.1 agc 418 1.1 agc case SESSION_LIST: 419 1.1 agc TAILQ_FOREACH(elem, &list[SESSION_LIST].list, link) 420 1.2 christos if (strcmp((char *)((session_t *)(void *)elem)->target.TargetName, 421 1.1 agc (char *)par->strval) == 0) 422 1.1 agc break; 423 1.1 agc break; 424 1.1 agc 425 1.1 agc default: 426 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 427 1.1 agc break; 428 1.1 agc } 429 1.1 agc break; 430 1.1 agc 431 1.1 agc case FIND_ADDRESS: 432 1.1 agc switch (par->list_kind) { 433 1.1 agc case PORTAL_LIST: 434 1.1 agc TAILQ_FOREACH(elem, &list[PORTAL_LIST].list, link) { 435 1.2 christos portal_t *p = (void *)elem; 436 1.2 christos if (strcmp((char *)p->addr.address, (char *)par->strval) == 0 && 437 1.1 agc (!par->intval || 438 1.2 christos p->addr.port == par->intval)) 439 1.1 agc break; 440 1.1 agc } 441 1.1 agc break; 442 1.1 agc 443 1.1 agc case SEND_TARGETS_LIST: 444 1.1 agc TAILQ_FOREACH(elem, &list[SEND_TARGETS_LIST].list, link) { 445 1.2 christos send_target_t *t = (void *)elem; 446 1.2 christos if (strcmp((char *)t->addr.address, 447 1.1 agc (char *)par->strval) == 0 && 448 1.1 agc (!par->intval || 449 1.2 christos t->addr.port == par->intval)) 450 1.1 agc break; 451 1.1 agc } 452 1.1 agc break; 453 1.1 agc 454 1.1 agc case ISNS_LIST: 455 1.1 agc TAILQ_FOREACH(elem, &list[ISNS_LIST].list, link) { 456 1.2 christos isns_t *i = (void *)elem; 457 1.2 christos if (strcmp((char *)i->address, (char *)par->strval) == 0 && 458 1.2 christos (!par->intval || i->port == par->intval)) 459 1.1 agc break; 460 1.1 agc } 461 1.1 agc break; 462 1.1 agc 463 1.1 agc default: 464 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 465 1.1 agc break; 466 1.1 agc } 467 1.1 agc break; 468 1.1 agc 469 1.1 agc default: 470 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 471 1.1 agc return; 472 1.1 agc } 473 1.1 agc 474 1.1 agc if (elem == NULL) { 475 1.1 agc if (par->list_kind == SESSION_LIST) 476 1.1 agc UNLOCK_SESSIONS; 477 1.1 agc rsp->status = ISCSID_STATUS_NOT_FOUND; 478 1.1 agc return; 479 1.1 agc } 480 1.1 agc 481 1.1 agc rsp = make_rsp(sizeof(iscsid_sym_id_t), prsp, prsp_temp); 482 1.1 agc if (rsp == NULL) { 483 1.1 agc if (par->list_kind == SESSION_LIST) 484 1.1 agc UNLOCK_SESSIONS; 485 1.1 agc return; 486 1.1 agc } 487 1.1 agc 488 1.1 agc (void) memcpy(rsp->parameter, &elem->sid, sizeof(elem->sid)); 489 1.1 agc if (par->list_kind == SESSION_LIST) 490 1.1 agc UNLOCK_SESSIONS; 491 1.1 agc } 492 1.1 agc 493 1.1 agc 494 1.1 agc /* 495 1.1 agc * get_session_list: 496 1.1 agc * Handle GET_SESSION_LIST request: Return a list of sessions complete 497 1.1 agc * with basic session info. 498 1.1 agc * 499 1.1 agc * Parameter: 500 1.1 agc * prsp Pointer to address of response buffer. 501 1.1 agc * prsp_temp Will be set to TRUE if buffer was allocated, FALSE 502 1.1 agc * for static buffer. 503 1.1 agc */ 504 1.1 agc 505 1.1 agc void 506 1.1 agc get_session_list(iscsid_response_t ** prsp, int *prsp_temp) 507 1.1 agc { 508 1.1 agc iscsid_get_session_list_rsp_t *res; 509 1.1 agc iscsid_response_t *rsp = *prsp; 510 1.1 agc iscsid_session_list_entry_t *ent; 511 1.1 agc generic_list_t *plist; 512 1.1 agc generic_entry_t *curr; 513 1.1 agc session_t *sess; 514 1.1 agc connection_t *conn; 515 1.1 agc int num; 516 1.1 agc 517 1.9 mlelstv DEB(10, ("get_session_list")); 518 1.1 agc 519 1.1 agc LOCK_SESSIONS; 520 1.1 agc plist = &list[SESSION_LIST].list; 521 1.1 agc num = list[SESSION_LIST].num_entries; 522 1.1 agc 523 1.1 agc if (!num) { 524 1.1 agc UNLOCK_SESSIONS; 525 1.1 agc rsp->status = ISCSID_STATUS_LIST_EMPTY; 526 1.1 agc return; 527 1.1 agc } 528 1.1 agc 529 1.1 agc rsp = make_rsp(sizeof(iscsid_get_session_list_rsp_t) + 530 1.1 agc (num - 1) * sizeof(iscsid_session_list_entry_t), 531 1.1 agc prsp, prsp_temp); 532 1.1 agc if (rsp == NULL) { 533 1.1 agc UNLOCK_SESSIONS; 534 1.1 agc return; 535 1.1 agc } 536 1.1 agc /* copy the ID of all list entries */ 537 1.2 christos res = (iscsid_get_session_list_rsp_t *)(void *)rsp->parameter; 538 1.1 agc res->num_entries = num; 539 1.1 agc ent = res->session; 540 1.1 agc 541 1.1 agc TAILQ_FOREACH(curr, plist, link) { 542 1.2 christos sess = (session_t *)(void *)curr; 543 1.2 christos conn = (connection_t *)(void *)TAILQ_FIRST(&sess->connections); 544 1.1 agc 545 1.1 agc ent->session_id = sess->entry.sid; 546 1.1 agc ent->num_connections = sess->num_connections; 547 1.8 mlelstv if (conn) { 548 1.8 mlelstv ent->first_connection_id = conn->entry.sid.id; 549 1.8 mlelstv ent->portal_id = conn->portal.sid.id; 550 1.8 mlelstv ent->initiator_id = conn->initiator_id; 551 1.8 mlelstv } else { 552 1.8 mlelstv ent->first_connection_id = 0; 553 1.8 mlelstv ent->portal_id = 0; 554 1.8 mlelstv ent->initiator_id = 0; 555 1.8 mlelstv } 556 1.1 agc ent++; 557 1.1 agc } 558 1.1 agc UNLOCK_SESSIONS; 559 1.1 agc } 560 1.1 agc 561 1.1 agc /* 562 1.1 agc * get_connection_list: 563 1.1 agc * Handle GET_CONNECTION_LIST request: Return a list of connections 564 1.1 agc * for a session. 565 1.1 agc * 566 1.1 agc * Parameter: 567 1.1 agc * prsp Pointer to address of response buffer. 568 1.1 agc * prsp_temp Will be set to TRUE if buffer was allocated, FALSE 569 1.1 agc * for static buffer. 570 1.1 agc */ 571 1.1 agc 572 1.1 agc void 573 1.1 agc get_connection_list(iscsid_sym_id_t *req, iscsid_response_t **prsp, 574 1.1 agc int *prsp_temp) 575 1.1 agc { 576 1.1 agc iscsid_get_connection_list_rsp_t *res; 577 1.1 agc iscsid_response_t *rsp = *prsp; 578 1.1 agc iscsid_connection_list_entry_t *ent; 579 1.1 agc generic_entry_t *curr; 580 1.1 agc session_t *sess; 581 1.1 agc connection_t *conn; 582 1.1 agc int num; 583 1.1 agc 584 1.9 mlelstv DEB(10, ("get_connection_list")); 585 1.1 agc 586 1.1 agc LOCK_SESSIONS; 587 1.1 agc if ((sess = find_session(req)) == NULL) { 588 1.1 agc UNLOCK_SESSIONS; 589 1.1 agc rsp->status = ISCSID_STATUS_INVALID_SESSION_ID; 590 1.1 agc return; 591 1.1 agc } 592 1.1 agc 593 1.1 agc num = sess->num_connections; 594 1.1 agc rsp = make_rsp(sizeof(iscsid_get_connection_list_rsp_t) + 595 1.1 agc (num - 1) * sizeof(iscsid_connection_list_entry_t), 596 1.1 agc prsp, prsp_temp); 597 1.1 agc if (rsp == NULL) { 598 1.1 agc UNLOCK_SESSIONS; 599 1.1 agc return; 600 1.1 agc } 601 1.1 agc /* copy the ID of all list entries */ 602 1.2 christos res = (iscsid_get_connection_list_rsp_t *)(void *)rsp->parameter; 603 1.1 agc res->num_connections = num; 604 1.1 agc ent = res->connection; 605 1.1 agc 606 1.1 agc TAILQ_FOREACH(curr, &sess->connections, link) { 607 1.2 christos conn = (connection_t *)(void *)curr; 608 1.1 agc ent->connection_id = conn->entry.sid; 609 1.1 agc ent->target_portal_id = conn->portal.sid; 610 1.1 agc ent->target_portal = conn->portal.addr; 611 1.1 agc ent++; 612 1.1 agc } 613 1.1 agc UNLOCK_SESSIONS; 614 1.1 agc } 615 1.1 agc 616 1.1 agc 617 1.1 agc /* 618 1.1 agc * get_connection_info: 619 1.1 agc * Handle GET_CONNECTION_INFO request: Return information about a connection 620 1.1 agc * 621 1.1 agc * Parameter: 622 1.1 agc * par The request parameters. 623 1.1 agc * prsp Pointer to address of response buffer. 624 1.1 agc * prsp_temp Will be set to TRUE if buffer was allocated, FALSE 625 1.1 agc * for static buffer. 626 1.1 agc */ 627 1.1 agc 628 1.1 agc void 629 1.1 agc get_connection_info(iscsid_get_connection_info_req_t * req, 630 1.1 agc iscsid_response_t ** prsp, int *prsp_temp) 631 1.1 agc { 632 1.1 agc iscsid_get_connection_info_rsp_t *res; 633 1.1 agc iscsid_response_t *rsp = *prsp; 634 1.1 agc session_t *sess; 635 1.1 agc connection_t *conn; 636 1.1 agc initiator_t *init = NULL; 637 1.1 agc 638 1.9 mlelstv DEB(10, ("get_connection_info, session %d, connection %d", 639 1.1 agc req->session_id.id, req->connection_id.id)); 640 1.1 agc 641 1.1 agc LOCK_SESSIONS; 642 1.1 agc if ((sess = find_session(&req->session_id)) == NULL) { 643 1.1 agc UNLOCK_SESSIONS; 644 1.1 agc rsp->status = ISCSID_STATUS_INVALID_SESSION_ID; 645 1.1 agc return; 646 1.1 agc } 647 1.1 agc if (!req->connection_id.id && !req->connection_id.name[0]) { 648 1.2 christos conn = (connection_t *)(void *)TAILQ_FIRST(&sess->connections); 649 1.1 agc } else if ((conn = find_connection(sess, &req->connection_id)) == NULL) { 650 1.1 agc UNLOCK_SESSIONS; 651 1.1 agc rsp->status = ISCSID_STATUS_INVALID_CONNECTION_ID; 652 1.1 agc return; 653 1.1 agc } 654 1.1 agc 655 1.1 agc rsp = make_rsp(sizeof(iscsid_get_connection_info_rsp_t), prsp, prsp_temp); 656 1.1 agc if (rsp == NULL) { 657 1.1 agc UNLOCK_SESSIONS; 658 1.1 agc return; 659 1.1 agc } 660 1.1 agc 661 1.8 mlelstv if (conn && conn->initiator_id) 662 1.1 agc init = find_initiator_id(conn->initiator_id); 663 1.1 agc 664 1.2 christos res = (iscsid_get_connection_info_rsp_t *)(void *)rsp->parameter; 665 1.1 agc 666 1.1 agc res->session_id = sess->entry.sid; 667 1.8 mlelstv if (conn) { 668 1.8 mlelstv res->connection_id = conn->entry.sid; 669 1.8 mlelstv res->target_portal_id = conn->portal.sid; 670 1.8 mlelstv res->target_portal = conn->portal.addr; 671 1.8 mlelstv strlcpy((char *)res->TargetName, (char *)conn->target.TargetName, 672 1.8 mlelstv sizeof(res->TargetName)); 673 1.8 mlelstv strlcpy((char *)res->TargetAlias, (char *)conn->target.TargetAlias, 674 1.8 mlelstv sizeof(res->TargetAlias)); 675 1.8 mlelstv } else { 676 1.8 mlelstv res->connection_id.id = 0; 677 1.8 mlelstv res->connection_id.name[0] = '\0'; 678 1.8 mlelstv res->target_portal_id.id = 0; 679 1.8 mlelstv res->target_portal_id.name[0] = '\0'; 680 1.8 mlelstv memset(&res->target_portal, 0, sizeof(res->target_portal)); 681 1.8 mlelstv memset(&res->TargetName, 0, sizeof(res->TargetName)); 682 1.8 mlelstv memset(&res->TargetAlias, 0, sizeof(res->TargetAlias)); 683 1.8 mlelstv } 684 1.1 agc if (init != NULL) { 685 1.1 agc res->initiator_id = init->entry.sid; 686 1.1 agc strlcpy((char *)res->initiator_address, (char *)init->address, 687 1.1 agc sizeof(res->initiator_address)); 688 1.1 agc } 689 1.1 agc UNLOCK_SESSIONS; 690 1.1 agc } 691 1.1 agc 692 1.1 agc /* ------------------------------------------------------------------------- */ 693 1.1 agc 694 1.1 agc /* 695 1.10 andvar * find_initiator_by_addr: 696 1.1 agc * Find an Initiator Portal by Address. 697 1.1 agc * 698 1.1 agc * Parameter: the address 699 1.1 agc * 700 1.1 agc * Returns: The pointer to the portal (or NULL if not found) 701 1.1 agc */ 702 1.1 agc 703 1.3 agc static initiator_t * 704 1.1 agc find_initiator_by_addr(uint8_t * addr) 705 1.1 agc { 706 1.1 agc generic_entry_t *curr; 707 1.2 christos initiator_t *i = NULL; 708 1.1 agc 709 1.2 christos TAILQ_FOREACH(curr, &list[INITIATOR_LIST].list, link) { 710 1.2 christos i = (void *)curr; 711 1.2 christos if (strcmp((char *)i->address, (char *)addr) == 0) 712 1.1 agc break; 713 1.2 christos } 714 1.1 agc 715 1.7 riz /* return curr instead of i because if not found, curr==NULL */ 716 1.9 mlelstv DEB(9, ("Find_initiator_by_addr returns %p", curr)); 717 1.7 riz return (initiator_t *)curr; 718 1.1 agc } 719 1.1 agc 720 1.1 agc 721 1.1 agc /* 722 1.1 agc * add_initiator_portal: 723 1.1 agc * Add an initiator portal. 724 1.1 agc * 725 1.1 agc * Parameter: 726 1.1 agc * par The request parameters. 727 1.1 agc * prsp Pointer to address of response buffer. 728 1.1 agc * prsp_temp Will be set to TRUE if buffer was allocated, FALSE 729 1.1 agc * for static buffer. 730 1.1 agc */ 731 1.1 agc 732 1.1 agc void 733 1.1 agc add_initiator_portal(iscsid_add_initiator_req_t *par, iscsid_response_t **prsp, 734 1.1 agc int *prsp_temp) 735 1.1 agc { 736 1.1 agc iscsid_add_initiator_rsp_t *res; 737 1.1 agc iscsid_response_t *rsp = *prsp; 738 1.1 agc initiator_t *init; 739 1.1 agc 740 1.9 mlelstv DEB(9, ("AddInitiatorPortal '%s' (name '%s')", par->address, par->name)); 741 1.1 agc 742 1.1 agc if (find_initiator_by_addr(par->address) != NULL) { 743 1.1 agc rsp->status = ISCSID_STATUS_DUPLICATE_ENTRY; 744 1.1 agc return; 745 1.1 agc } 746 1.1 agc 747 1.1 agc if (find_initiator_name(par->name) != NULL) { 748 1.1 agc rsp->status = ISCSID_STATUS_DUPLICATE_NAME; 749 1.1 agc return; 750 1.1 agc } 751 1.1 agc 752 1.1 agc if ((init = calloc(1, sizeof(*init))) == NULL) { 753 1.1 agc rsp->status = ISCSID_STATUS_NO_RESOURCES; 754 1.1 agc return; 755 1.1 agc } 756 1.1 agc 757 1.9 mlelstv DEB(9, ("AddInitiatorPortal initiator_id = %d", initiator_id)); 758 1.1 agc 759 1.1 agc for (initiator_id++; 760 1.1 agc !initiator_id || find_initiator_id(initiator_id) != NULL;) 761 1.1 agc initiator_id++; 762 1.1 agc 763 1.1 agc init->entry.sid.id = initiator_id; 764 1.1 agc strlcpy((char *)init->entry.sid.name, (char *)par->name, sizeof(init->entry.sid.name)); 765 1.1 agc strlcpy((char *)init->address, (char *)par->address, sizeof(init->address)); 766 1.1 agc 767 1.1 agc rsp = make_rsp(sizeof(iscsid_add_initiator_rsp_t), prsp, prsp_temp); 768 1.1 agc if (rsp == NULL) 769 1.1 agc return; 770 1.1 agc 771 1.1 agc LOCK_SESSIONS; 772 1.1 agc TAILQ_INSERT_TAIL(&list[INITIATOR_LIST].list, &init->entry, link); 773 1.1 agc list[INITIATOR_LIST].num_entries++; 774 1.1 agc UNLOCK_SESSIONS; 775 1.1 agc 776 1.2 christos res = (iscsid_add_initiator_rsp_t *)(void *)rsp->parameter; 777 1.1 agc res->portal_id = init->entry.sid.id; 778 1.1 agc } 779 1.1 agc 780 1.1 agc 781 1.1 agc /* 782 1.1 agc * remove_initiator_portal: 783 1.1 agc * Handle REMOVE_INITIATOR request: Removes an initiator entry. 784 1.1 agc * 785 1.1 agc * Parameter: 786 1.1 agc * par The request parameter containing the ID. 787 1.1 agc * 788 1.1 agc * Returns: status 789 1.1 agc */ 790 1.1 agc 791 1.1 agc uint32_t 792 1.1 agc remove_initiator_portal(iscsid_sym_id_t * par) 793 1.1 agc { 794 1.1 agc initiator_t *init; 795 1.1 agc 796 1.1 agc if ((init = find_initiator(par)) == NULL) 797 1.1 agc return ISCSID_STATUS_INVALID_INITIATOR_ID; 798 1.1 agc 799 1.1 agc LOCK_SESSIONS; 800 1.1 agc list[INITIATOR_LIST].num_entries--; 801 1.1 agc 802 1.1 agc TAILQ_REMOVE(&list[INITIATOR_LIST].list, &init->entry, link); 803 1.1 agc UNLOCK_SESSIONS; 804 1.1 agc 805 1.1 agc free(init); 806 1.1 agc 807 1.1 agc return ISCSID_STATUS_SUCCESS; 808 1.1 agc } 809 1.1 agc 810 1.1 agc 811 1.1 agc 812 1.1 agc /* 813 1.1 agc * get_initiator_portal: 814 1.1 agc * Handle GET_INITIATOR_PORTAL request: Return information about the given 815 1.1 agc * initiator portal. 816 1.1 agc * 817 1.1 agc * Parameter: 818 1.1 agc * par The request parameters. 819 1.1 agc * prsp Pointer to address of response buffer. 820 1.1 agc * prsp_temp Will be set to TRUE if buffer was allocated, FALSE 821 1.1 agc * for static buffer. 822 1.1 agc */ 823 1.1 agc 824 1.1 agc void 825 1.1 agc get_initiator_portal(iscsid_sym_id_t *par, iscsid_response_t **prsp, 826 1.1 agc int *prsp_temp) 827 1.1 agc { 828 1.1 agc iscsid_get_initiator_rsp_t *res; 829 1.1 agc iscsid_response_t *rsp = *prsp; 830 1.1 agc initiator_t *init; 831 1.1 agc 832 1.9 mlelstv DEB(10, ("get_initiator_portal, id %d (%s)", par->id, par->name)); 833 1.1 agc 834 1.1 agc if ((init = find_initiator(par)) == NULL) { 835 1.1 agc rsp->status = ISCSID_STATUS_INVALID_INITIATOR_ID; 836 1.1 agc return; 837 1.1 agc } 838 1.1 agc 839 1.1 agc rsp = make_rsp(sizeof(iscsid_get_initiator_rsp_t), prsp, prsp_temp); 840 1.1 agc if (rsp == NULL) 841 1.1 agc return; 842 1.1 agc 843 1.2 christos res = (iscsid_get_initiator_rsp_t *)(void *)rsp->parameter; 844 1.1 agc res->portal_id = init->entry.sid; 845 1.1 agc strlcpy((char *)res->address, (char *)init->address, sizeof(res->address)); 846 1.1 agc } 847 1.1 agc 848 1.1 agc 849 1.1 agc /* 850 1.1 agc * select_initiator: 851 1.1 agc * Select the initiator portal to use. 852 1.1 agc * Selects the portal with the least number of active connections. 853 1.1 agc * 854 1.1 agc * Returns: 855 1.1 agc * Pointer to the portal, NULL if no portals are defined. 856 1.1 agc * 857 1.1 agc * NOTE: Called with session list locked, so don't lock again. 858 1.1 agc */ 859 1.1 agc 860 1.1 agc initiator_t * 861 1.1 agc select_initiator(void) 862 1.1 agc { 863 1.1 agc generic_entry_t *curr; 864 1.1 agc initiator_t *imin = NULL; 865 1.1 agc uint32_t ccnt = 64 * 1024; /* probably not more than 64k connections... */ 866 1.1 agc 867 1.1 agc if (!list[INITIATOR_LIST].num_entries) 868 1.1 agc return NULL; 869 1.1 agc 870 1.1 agc TAILQ_FOREACH(curr, &list[INITIATOR_LIST].list, link) { 871 1.2 christos initiator_t *i = (void *)curr; 872 1.2 christos if ((i->active_connections < ccnt)) { 873 1.2 christos ccnt = i->active_connections; 874 1.2 christos imin = i; 875 1.1 agc } 876 1.1 agc } 877 1.1 agc return imin; 878 1.1 agc } 879 1.1 agc 880 1.1 agc /* ------------------------------------------------------------------------- */ 881 1.1 agc 882 1.1 agc /* 883 1.1 agc * event_kill_session: 884 1.1 agc * Handle SESSION_TERMINATED event: Remove session and all associated 885 1.1 agc * connections. 886 1.1 agc * 887 1.1 agc * Parameter: 888 1.1 agc * sid Session ID 889 1.1 agc */ 890 1.1 agc 891 1.1 agc void 892 1.1 agc event_kill_session(uint32_t sid) 893 1.1 agc { 894 1.1 agc session_t *sess; 895 1.1 agc connection_t *conn; 896 1.1 agc portal_t *portal; 897 1.1 agc initiator_t *init; 898 1.1 agc 899 1.1 agc LOCK_SESSIONS; 900 1.1 agc 901 1.1 agc sess = find_session_id(sid); 902 1.1 agc 903 1.1 agc if (sess == NULL) { 904 1.1 agc UNLOCK_SESSIONS; 905 1.1 agc return; 906 1.1 agc } 907 1.1 agc 908 1.1 agc TAILQ_REMOVE(&list[SESSION_LIST].list, &sess->entry, link); 909 1.1 agc list[SESSION_LIST].num_entries--; 910 1.1 agc 911 1.1 agc UNLOCK_SESSIONS; 912 1.1 agc 913 1.2 christos while ((conn = (connection_t *)(void *)TAILQ_FIRST(&sess->connections)) != NULL) { 914 1.1 agc TAILQ_REMOVE(&sess->connections, &conn->entry, link); 915 1.1 agc 916 1.1 agc portal = find_portal_id(conn->portal.sid.id); 917 1.1 agc if (portal != NULL) 918 1.1 agc portal->active_connections--; 919 1.1 agc 920 1.1 agc init = find_initiator_id(conn->initiator_id); 921 1.1 agc if (init != NULL) 922 1.1 agc init->active_connections--; 923 1.1 agc 924 1.1 agc free(conn); 925 1.1 agc } 926 1.1 agc free(sess); 927 1.1 agc } 928 1.1 agc 929 1.1 agc 930 1.1 agc /* 931 1.1 agc * event_kill_connection: 932 1.1 agc * Handle CONNECTION_TERMINATED event: Remove connection from session. 933 1.1 agc * 934 1.1 agc * Parameter: 935 1.1 agc * sid Session ID 936 1.1 agc * cid Connection ID 937 1.1 agc */ 938 1.1 agc 939 1.1 agc void 940 1.1 agc event_kill_connection(uint32_t sid, uint32_t cid) 941 1.1 agc { 942 1.1 agc session_t *sess; 943 1.1 agc connection_t *conn; 944 1.1 agc portal_t *portal; 945 1.1 agc initiator_t *init; 946 1.1 agc 947 1.1 agc LOCK_SESSIONS; 948 1.1 agc 949 1.1 agc sess = find_session_id(sid); 950 1.1 agc if (sess == NULL) { 951 1.1 agc UNLOCK_SESSIONS; 952 1.1 agc return; 953 1.1 agc } 954 1.1 agc 955 1.1 agc conn = find_connection_id(sess, cid); 956 1.1 agc if (conn == NULL) { 957 1.1 agc UNLOCK_SESSIONS; 958 1.1 agc return; 959 1.1 agc } 960 1.1 agc 961 1.1 agc TAILQ_REMOVE(&sess->connections, &conn->entry, link); 962 1.1 agc sess->num_connections--; 963 1.1 agc 964 1.1 agc init = find_initiator_id(conn->initiator_id); 965 1.1 agc if (init != NULL) 966 1.1 agc init->active_connections--; 967 1.1 agc 968 1.1 agc UNLOCK_SESSIONS; 969 1.1 agc 970 1.1 agc portal = find_portal_id(conn->portal.sid.id); 971 1.1 agc if (portal != NULL) 972 1.1 agc portal->active_connections--; 973 1.1 agc 974 1.1 agc free(conn); 975 1.1 agc } 976