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