Home | History | Annotate | Line # | Download | only in iscsid
iscsid_lists.c revision 1.1
      1 /*	$NetBSD: iscsid_lists.c,v 1.1 2011/10/23 21:11:23 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 == (int)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 *)find_sym_id (&list [lst].list, sid)) != NULL)
    201 		return targ;
    202 	if (lst == TARGET_LIST) {
    203 		portal_t *portal;
    204 
    205 		if ((portal = 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 
    226 	if (lst == PORTAL_LIST)
    227 		lst = TARGET_LIST;
    228 
    229 	TAILQ_FOREACH(curr, &list[lst].list, link)
    230 		if (strcmp((char *)((target_t *) curr)->TargetName, (char *)name) == 0)
    231 			break;
    232 
    233 	DEB(10, ("Find_TagetName returns %x\n", (int) curr));
    234 
    235 	return (target_t *) curr;
    236 }
    237 
    238 
    239 /*
    240  * find_portal_by_addr:
    241  *    Find a Portal by Address.
    242  *
    243  *    Parameter:  the associated target, and the address
    244  *
    245  *    Returns:    The pointer to the portal (or NULL if not found)
    246  */
    247 
    248 portal_t *
    249 find_portal_by_addr(target_t * target, iscsi_portal_address_t * addr)
    250 {
    251 	generic_entry_t *curr;
    252 
    253 	TAILQ_FOREACH(curr, &list[PORTAL_LIST].list, link) {
    254 		DEB(10, ("Find_portal_by_addr - addr %s port %d target %x\n",
    255 				 ((portal_t *) curr)->addr.address,
    256 				 ((portal_t *) curr)->addr.port,
    257 				 (int) ((portal_t *) curr)->target));
    258 
    259 		if (strcmp((char *)((portal_t *) curr)->addr.address, (char *)addr->address) == 0 &&
    260 			(!addr->port || ((portal_t *) curr)->addr.port == addr->port) &&
    261 			((portal_t *) curr)->target == target)
    262 			break;
    263 	}
    264 
    265 	DEB(10, ("Find_portal_by_addr returns %x\n", (int) curr));
    266 	return (portal_t *) curr;
    267 }
    268 
    269 
    270 /*
    271  * find_send_target_by_addr:
    272  *    Find a Send Target by Address.
    273  *
    274  *    Parameter:  the address
    275  *
    276  *    Returns:    The pointer to the portal (or NULL if not found)
    277  */
    278 
    279 send_target_t *
    280 find_send_target_by_addr(iscsi_portal_address_t * addr)
    281 {
    282 	generic_entry_t *curr;
    283 
    284 	TAILQ_FOREACH(curr, &list[SEND_TARGETS_LIST].list, link) {
    285 		if (strcmp((char *)((send_target_t *) curr)->addr.address, (char *)addr->address) == 0 &&
    286 			(!addr->port || ((send_target_t *) curr)->addr.port == addr->port))
    287 			break;
    288 	}
    289 
    290 	DEB(10, ("Find_send_target_by_addr returns %x\n", (int) curr));
    291 	return (send_target_t *) curr;
    292 }
    293 
    294 
    295 /*
    296  * get_list:
    297  *    Handle GET_LIST request: Return the list of IDs contained in the list.
    298  *
    299  *    Parameter:
    300  *          par         The request parameters.
    301  *          prsp        Pointer to address of response buffer.
    302  *          prsp_temp   Will be set to TRUE if buffer was allocated, FALSE
    303  *                      for static buffer.
    304  */
    305 
    306 void
    307 get_list(iscsid_get_list_req_t * par, iscsid_response_t ** prsp, int *prsp_temp)
    308 {
    309 	iscsid_get_list_rsp_t *res;
    310 	iscsid_response_t *rsp = *prsp;
    311 	int num;
    312 	uint32_t *idp;
    313 	generic_list_t *plist;
    314 	generic_entry_t *curr;
    315 
    316 	DEB(10, ("get_list, kind %d\n", par->list_kind));
    317 
    318 	if (par->list_kind == SESSION_LIST)
    319 		LOCK_SESSIONS;
    320 	else if (par->list_kind >= NUM_DAEMON_LISTS) {
    321 		rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    322 		return;
    323 	}
    324 
    325 	plist = &list[par->list_kind].list;
    326 	num = list[par->list_kind].num_entries;
    327 
    328 	if (!num) {
    329 		if (par->list_kind == SESSION_LIST)
    330 			UNLOCK_SESSIONS;
    331 		rsp->status = ISCSID_STATUS_LIST_EMPTY;
    332 		return;
    333 	}
    334 
    335 	rsp = make_rsp(sizeof(iscsid_get_list_rsp_t) +
    336 					(num - 1) * sizeof(uint32_t), prsp, prsp_temp);
    337 	if (rsp == NULL) {
    338 		if (par->list_kind == SESSION_LIST)
    339 			UNLOCK_SESSIONS;
    340 		return;
    341 	}
    342 	/* copy the ID of all list entries */
    343 	res = (iscsid_get_list_rsp_t *) rsp->parameter;
    344 	res->num_entries = num;
    345 	idp = res->id;
    346 
    347 	TAILQ_FOREACH(curr, plist, link)
    348 		* idp++ = curr->sid.id;
    349 
    350 	if (par->list_kind == SESSION_LIST)
    351 		UNLOCK_SESSIONS;
    352 }
    353 
    354 
    355 /*
    356  * search_list:
    357  *    Handle SEARCH_LIST request: Search the given list for the string or
    358  *    address.
    359  *    Note: Not all combinations of list and search type make sense.
    360  *
    361  *    Parameter:
    362  *          par         The request parameters.
    363  *          prsp        Pointer to address of response buffer.
    364  *          prsp_temp   Will be set to TRUE if buffer was allocated, FALSE
    365  *                      for static buffer.
    366  */
    367 
    368 void
    369 search_list(iscsid_search_list_req_t * par, iscsid_response_t ** prsp,
    370 			int *prsp_temp)
    371 {
    372 	iscsid_response_t *rsp = *prsp;
    373 	generic_entry_t *elem = NULL;
    374 
    375 	DEB(10, ("search_list, list_kind %d, search_kind %d\n",
    376 			 par->list_kind, par->search_kind));
    377 
    378 	if (par->list_kind == SESSION_LIST)
    379 		LOCK_SESSIONS;
    380 	else if (par->list_kind >= NUM_DAEMON_LISTS) {
    381 		rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    382 		return;
    383 	}
    384 
    385 	if (!list[par->list_kind].num_entries) {
    386 		if (par->list_kind == SESSION_LIST)
    387 			UNLOCK_SESSIONS;
    388 		rsp->status = ISCSID_STATUS_NOT_FOUND;
    389 		return;
    390 	}
    391 
    392 	switch (par->search_kind) {
    393 	case FIND_ID:
    394 		elem = find_id(&list[par->list_kind].list, par->intval);
    395 		break;
    396 
    397 	case FIND_NAME:
    398 		elem = find_name(&list[par->list_kind].list, par->strval);
    399 		break;
    400 
    401 	case FIND_TARGET_NAME:
    402 		switch (par->list_kind) {
    403 		case TARGET_LIST:
    404 		case PORTAL_LIST:
    405 		case SEND_TARGETS_LIST:
    406 			elem = (generic_entry_t *) find_TargetName(par->list_kind,
    407 														par->strval);
    408 			break;
    409 
    410 		case SESSION_LIST:
    411 			TAILQ_FOREACH(elem, &list[SESSION_LIST].list, link)
    412 				if (strcmp((char *)((session_t *) elem)->target.TargetName,
    413 							(char *)par->strval) == 0)
    414 					break;
    415 			break;
    416 
    417 		default:
    418 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    419 			break;
    420 		}
    421 		break;
    422 
    423 	case FIND_ADDRESS:
    424 		switch (par->list_kind) {
    425 		case PORTAL_LIST:
    426 			TAILQ_FOREACH(elem, &list[PORTAL_LIST].list, link) {
    427 				if (strcmp((char *)((portal_t *) elem)->addr.address, (char *)par->strval) == 0 &&
    428 					(!par->intval ||
    429 					 ((portal_t *) elem)->addr.port == par->intval))
    430 					break;
    431 			}
    432 			break;
    433 
    434 		case SEND_TARGETS_LIST:
    435 			TAILQ_FOREACH(elem, &list[SEND_TARGETS_LIST].list, link) {
    436 				if (strcmp((char *)((send_target_t *) elem)->addr.address,
    437 							(char *)par->strval) == 0 &&
    438 					(!par->intval ||
    439 					 ((send_target_t *) elem)->addr.port == par->intval))
    440 					break;
    441 			}
    442 			break;
    443 
    444 		case ISNS_LIST:
    445 			TAILQ_FOREACH(elem, &list[ISNS_LIST].list, link) {
    446 				if (strcmp((char *)((isns_t *) elem)->address, (char *)par->strval) == 0 &&
    447 					(!par->intval || ((isns_t *) elem)->port == par->intval))
    448 					break;
    449 			}
    450 			break;
    451 
    452 		default:
    453 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    454 			break;
    455 		}
    456 		break;
    457 
    458 	default:
    459 		rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
    460 		return;
    461 	}
    462 
    463 	if (elem == NULL) {
    464 		if (par->list_kind == SESSION_LIST)
    465 			UNLOCK_SESSIONS;
    466 		rsp->status = ISCSID_STATUS_NOT_FOUND;
    467 		return;
    468 	}
    469 
    470 	rsp = make_rsp(sizeof(iscsid_sym_id_t), prsp, prsp_temp);
    471 	if (rsp == NULL) {
    472 		if (par->list_kind == SESSION_LIST)
    473 			UNLOCK_SESSIONS;
    474 		return;
    475 	}
    476 
    477 	(void) memcpy(rsp->parameter, &elem->sid, sizeof(elem->sid));
    478 	if (par->list_kind == SESSION_LIST)
    479 		UNLOCK_SESSIONS;
    480 }
    481 
    482 
    483 /*
    484  * get_session_list:
    485  *    Handle GET_SESSION_LIST request: Return a list of sessions complete
    486  *    with basic session info.
    487  *
    488  *    Parameter:
    489  *          prsp        Pointer to address of response buffer.
    490  *          prsp_temp   Will be set to TRUE if buffer was allocated, FALSE
    491  *                      for static buffer.
    492  */
    493 
    494 void
    495 get_session_list(iscsid_response_t ** prsp, int *prsp_temp)
    496 {
    497 	iscsid_get_session_list_rsp_t *res;
    498 	iscsid_response_t *rsp = *prsp;
    499 	iscsid_session_list_entry_t *ent;
    500 	generic_list_t *plist;
    501 	generic_entry_t *curr;
    502 	session_t *sess;
    503 	connection_t *conn;
    504 	int num;
    505 
    506 	DEB(10, ("get_session_list\n"));
    507 
    508 	LOCK_SESSIONS;
    509 	plist = &list[SESSION_LIST].list;
    510 	num = list[SESSION_LIST].num_entries;
    511 
    512 	if (!num) {
    513 		UNLOCK_SESSIONS;
    514 		rsp->status = ISCSID_STATUS_LIST_EMPTY;
    515 		return;
    516 	}
    517 
    518 	rsp = make_rsp(sizeof(iscsid_get_session_list_rsp_t) +
    519 				   (num - 1) * sizeof(iscsid_session_list_entry_t),
    520 					prsp, prsp_temp);
    521 	if (rsp == NULL) {
    522 		UNLOCK_SESSIONS;
    523 		return;
    524 	}
    525 	/* copy the ID of all list entries */
    526 	res = (iscsid_get_session_list_rsp_t *) rsp->parameter;
    527 	res->num_entries = num;
    528 	ent = res->session;
    529 
    530 	TAILQ_FOREACH(curr, plist, link) {
    531 		sess = (session_t *) curr;
    532 		conn = (connection_t *) TAILQ_FIRST(&sess->connections);
    533 
    534 		ent->session_id = sess->entry.sid;
    535 		ent->first_connection_id = conn->entry.sid.id;
    536 		ent->num_connections = sess->num_connections;
    537 		ent->portal_id = conn->portal.sid.id;
    538 		ent->initiator_id = conn->initiator_id;
    539 		ent++;
    540 	}
    541 	UNLOCK_SESSIONS;
    542 }
    543 
    544 /*
    545  * get_connection_list:
    546  *    Handle GET_CONNECTION_LIST request: Return a list of connections
    547  *    for a session.
    548  *
    549  *    Parameter:
    550  *          prsp        Pointer to address of response buffer.
    551  *          prsp_temp   Will be set to TRUE if buffer was allocated, FALSE
    552  *                      for static buffer.
    553  */
    554 
    555 void
    556 get_connection_list(iscsid_sym_id_t *req, iscsid_response_t **prsp,
    557 					int *prsp_temp)
    558 {
    559 	iscsid_get_connection_list_rsp_t *res;
    560 	iscsid_response_t *rsp = *prsp;
    561 	iscsid_connection_list_entry_t *ent;
    562 	generic_entry_t *curr;
    563 	session_t *sess;
    564 	connection_t *conn;
    565 	int num;
    566 
    567 	DEB(10, ("get_connection_list\n"));
    568 
    569 	LOCK_SESSIONS;
    570 	if ((sess = find_session(req)) == NULL) {
    571 		UNLOCK_SESSIONS;
    572 		rsp->status = ISCSID_STATUS_INVALID_SESSION_ID;
    573 		return;
    574 	}
    575 
    576 	num = sess->num_connections;
    577 	rsp = make_rsp(sizeof(iscsid_get_connection_list_rsp_t) +
    578 				   (num - 1) * sizeof(iscsid_connection_list_entry_t),
    579 					prsp, prsp_temp);
    580 	if (rsp == NULL) {
    581 		UNLOCK_SESSIONS;
    582 		return;
    583 	}
    584 	/* copy the ID of all list entries */
    585 	res = (iscsid_get_connection_list_rsp_t *) rsp->parameter;
    586 	res->num_connections = num;
    587 	ent = res->connection;
    588 
    589 	TAILQ_FOREACH(curr, &sess->connections, link) {
    590 		conn = (connection_t *) curr;
    591 		ent->connection_id = conn->entry.sid;
    592 		ent->target_portal_id = conn->portal.sid;
    593 		ent->target_portal = conn->portal.addr;
    594 		ent++;
    595 	}
    596 	UNLOCK_SESSIONS;
    597 }
    598 
    599 
    600 /*
    601  * get_connection_info:
    602  *    Handle GET_CONNECTION_INFO request: Return information about a connection
    603  *
    604  *    Parameter:
    605  *          par         The request parameters.
    606  *          prsp        Pointer to address of response buffer.
    607  *          prsp_temp   Will be set to TRUE if buffer was allocated, FALSE
    608  *                      for static buffer.
    609  */
    610 
    611 void
    612 get_connection_info(iscsid_get_connection_info_req_t * req,
    613 					iscsid_response_t ** prsp, int *prsp_temp)
    614 {
    615 	iscsid_get_connection_info_rsp_t *res;
    616 	iscsid_response_t *rsp = *prsp;
    617 	session_t *sess;
    618 	connection_t *conn;
    619 	initiator_t *init = NULL;
    620 
    621 	DEB(10, ("get_connection_info, session %d, connection %d\n",
    622 			 req->session_id.id, req->connection_id.id));
    623 
    624 	LOCK_SESSIONS;
    625 	if ((sess = find_session(&req->session_id)) == NULL) {
    626 		UNLOCK_SESSIONS;
    627 		rsp->status = ISCSID_STATUS_INVALID_SESSION_ID;
    628 		return;
    629 	}
    630 	if (!req->connection_id.id && !req->connection_id.name[0]) {
    631 		conn = (connection_t *) TAILQ_FIRST(&sess->connections);
    632 	} else if ((conn = find_connection(sess, &req->connection_id)) == NULL) {
    633 		UNLOCK_SESSIONS;
    634 		rsp->status = ISCSID_STATUS_INVALID_CONNECTION_ID;
    635 		return;
    636 	}
    637 
    638 	rsp = make_rsp(sizeof(iscsid_get_connection_info_rsp_t), prsp, prsp_temp);
    639 	if (rsp == NULL) {
    640 		UNLOCK_SESSIONS;
    641 		return;
    642 	}
    643 
    644 	if (conn->initiator_id)
    645 		init = find_initiator_id(conn->initiator_id);
    646 
    647 	res = (iscsid_get_connection_info_rsp_t *) rsp->parameter;
    648 
    649 	res->session_id = sess->entry.sid;
    650 	res->connection_id = conn->entry.sid;
    651 	res->target_portal_id = conn->portal.sid;
    652 	res->target_portal = conn->portal.addr;
    653 	strlcpy((char *)res->TargetName, (char *)conn->target.TargetName,
    654 		sizeof(res->TargetName));
    655 	strlcpy((char *)res->TargetAlias, (char *)conn->target.TargetAlias,
    656 		sizeof(res->TargetAlias));
    657 	if (init != NULL) {
    658 		res->initiator_id = init->entry.sid;
    659 		strlcpy((char *)res->initiator_address, (char *)init->address,
    660 			sizeof(res->initiator_address));
    661 	}
    662 	UNLOCK_SESSIONS;
    663 }
    664 
    665 /* ------------------------------------------------------------------------- */
    666 
    667 /*
    668  * find_initator_by_addr:
    669  *    Find an Initiator Portal by Address.
    670  *
    671  *    Parameter:  the address
    672  *
    673  *    Returns:    The pointer to the portal (or NULL if not found)
    674  */
    675 
    676 STATIC initiator_t *
    677 find_initiator_by_addr(uint8_t * addr)
    678 {
    679 	generic_entry_t *curr;
    680 
    681 	TAILQ_FOREACH(curr, &list[INITIATOR_LIST].list, link)
    682 		if (strcmp((char *)((initiator_t *) curr)->address, (char *)addr) == 0)
    683 			break;
    684 
    685 	DEB(9, ("Find_initiator_by_addr returns %x\n", (int) curr));
    686 	return (initiator_t *) curr;
    687 }
    688 
    689 
    690 /*
    691  * add_initiator_portal:
    692  *    Add an initiator portal.
    693  *
    694  *    Parameter:
    695  *          par         The request parameters.
    696  *          prsp        Pointer to address of response buffer.
    697  *          prsp_temp   Will be set to TRUE if buffer was allocated, FALSE
    698  *                      for static buffer.
    699  */
    700 
    701 void
    702 add_initiator_portal(iscsid_add_initiator_req_t *par, iscsid_response_t **prsp,
    703 					 int *prsp_temp)
    704 {
    705 	iscsid_add_initiator_rsp_t *res;
    706 	iscsid_response_t *rsp = *prsp;
    707 	initiator_t *init;
    708 
    709 	DEB(9, ("AddInitiatorPortal '%s' (name '%s')\n", par->address, par->name));
    710 
    711 	if (find_initiator_by_addr(par->address) != NULL) {
    712 		rsp->status = ISCSID_STATUS_DUPLICATE_ENTRY;
    713 		return;
    714 	}
    715 
    716 	if (find_initiator_name(par->name) != NULL) {
    717 		rsp->status = ISCSID_STATUS_DUPLICATE_NAME;
    718 		return;
    719 	}
    720 
    721 	if ((init = calloc(1, sizeof(*init))) == NULL) {
    722 		rsp->status = ISCSID_STATUS_NO_RESOURCES;
    723 		return;
    724 	}
    725 
    726 	DEB(9, ("AddInitiatorPortal initiator_id = %d\n", initiator_id));
    727 
    728 	for (initiator_id++;
    729 		 !initiator_id || find_initiator_id(initiator_id) != NULL;)
    730 		initiator_id++;
    731 
    732 	init->entry.sid.id = initiator_id;
    733 	strlcpy((char *)init->entry.sid.name, (char *)par->name, sizeof(init->entry.sid.name));
    734 	strlcpy((char *)init->address, (char *)par->address, sizeof(init->address));
    735 
    736 	rsp = make_rsp(sizeof(iscsid_add_initiator_rsp_t), prsp, prsp_temp);
    737 	if (rsp == NULL)
    738 		return;
    739 
    740 	LOCK_SESSIONS;
    741 	TAILQ_INSERT_TAIL(&list[INITIATOR_LIST].list, &init->entry, link);
    742 	list[INITIATOR_LIST].num_entries++;
    743 	UNLOCK_SESSIONS;
    744 
    745 	res = (iscsid_add_initiator_rsp_t *) rsp->parameter;
    746 	res->portal_id = init->entry.sid.id;
    747 }
    748 
    749 
    750 /*
    751  * remove_initiator_portal:
    752  *    Handle REMOVE_INITIATOR request: Removes an initiator entry.
    753  *
    754  *    Parameter:
    755  *          par         The request parameter containing the ID.
    756  *
    757  *    Returns:     status
    758  */
    759 
    760 uint32_t
    761 remove_initiator_portal(iscsid_sym_id_t * par)
    762 {
    763 	initiator_t *init;
    764 
    765 	if ((init = find_initiator(par)) == NULL)
    766 		return ISCSID_STATUS_INVALID_INITIATOR_ID;
    767 
    768 	LOCK_SESSIONS;
    769 	list[INITIATOR_LIST].num_entries--;
    770 
    771 	TAILQ_REMOVE(&list[INITIATOR_LIST].list, &init->entry, link);
    772 	UNLOCK_SESSIONS;
    773 
    774 	free(init);
    775 
    776 	return ISCSID_STATUS_SUCCESS;
    777 }
    778 
    779 
    780 
    781 /*
    782  * get_initiator_portal:
    783  *    Handle GET_INITIATOR_PORTAL request: Return information about the given
    784  *    initiator portal.
    785  *
    786  *    Parameter:
    787  *          par         The request parameters.
    788  *          prsp        Pointer to address of response buffer.
    789  *          prsp_temp   Will be set to TRUE if buffer was allocated, FALSE
    790  *                      for static buffer.
    791  */
    792 
    793 void
    794 get_initiator_portal(iscsid_sym_id_t *par, iscsid_response_t **prsp,
    795 					 int *prsp_temp)
    796 {
    797 	iscsid_get_initiator_rsp_t *res;
    798 	iscsid_response_t *rsp = *prsp;
    799 	initiator_t *init;
    800 
    801 	DEB(10, ("get_initiator_portal, id %d (%s)\n", par->id, par->name));
    802 
    803 	if ((init = find_initiator(par)) == NULL) {
    804 		rsp->status = ISCSID_STATUS_INVALID_INITIATOR_ID;
    805 		return;
    806 	}
    807 
    808 	rsp = make_rsp(sizeof(iscsid_get_initiator_rsp_t), prsp, prsp_temp);
    809 	if (rsp == NULL)
    810 		return;
    811 
    812 	res = (iscsid_get_initiator_rsp_t *) rsp->parameter;
    813 	res->portal_id = init->entry.sid;
    814 	strlcpy((char *)res->address, (char *)init->address, sizeof(res->address));
    815 }
    816 
    817 
    818 /*
    819  * select_initiator:
    820  *    Select the initiator portal to use.
    821  *    Selects the portal with the least number of active connections.
    822  *
    823  *    Returns:
    824  *       Pointer to the portal, NULL if no portals are defined.
    825  *
    826  *    NOTE: Called with session list locked, so don't lock again.
    827  */
    828 
    829 initiator_t *
    830 select_initiator(void)
    831 {
    832 	generic_entry_t *curr;
    833 	initiator_t *imin = NULL;
    834 	uint32_t ccnt = 64 * 1024;	/* probably not more than 64k connections... */
    835 
    836 	if (!list[INITIATOR_LIST].num_entries)
    837 		return NULL;
    838 
    839 	TAILQ_FOREACH(curr, &list[INITIATOR_LIST].list, link) {
    840 		if ((((initiator_t *) curr)->active_connections < ccnt)) {
    841 			ccnt = ((initiator_t *) curr)->active_connections;
    842 			imin = (initiator_t *) curr;
    843 		}
    844 	}
    845 	return imin;
    846 }
    847 
    848 /* ------------------------------------------------------------------------- */
    849 
    850 /*
    851  * event_kill_session:
    852  *    Handle SESSION_TERMINATED event: Remove session and all associated
    853  *    connections.
    854  *
    855  *    Parameter:
    856  *          sid         Session ID
    857  */
    858 
    859 void
    860 event_kill_session(uint32_t sid)
    861 {
    862 	session_t *sess;
    863 	connection_t *conn;
    864 	portal_t *portal;
    865 	initiator_t *init;
    866 
    867 	LOCK_SESSIONS;
    868 
    869 	sess = find_session_id(sid);
    870 
    871 	if (sess == NULL) {
    872 		UNLOCK_SESSIONS;
    873 		return;
    874 	}
    875 
    876 	TAILQ_REMOVE(&list[SESSION_LIST].list, &sess->entry, link);
    877 	list[SESSION_LIST].num_entries--;
    878 
    879 	UNLOCK_SESSIONS;
    880 
    881 	while ((conn = (connection_t *) TAILQ_FIRST(&sess->connections)) != NULL) {
    882 		TAILQ_REMOVE(&sess->connections, &conn->entry, link);
    883 
    884 		portal = find_portal_id(conn->portal.sid.id);
    885 		if (portal != NULL)
    886 			portal->active_connections--;
    887 
    888 		init = find_initiator_id(conn->initiator_id);
    889 		if (init != NULL)
    890 			init->active_connections--;
    891 
    892 		free(conn);
    893 	}
    894 	free(sess);
    895 }
    896 
    897 
    898 /*
    899  * event_kill_connection:
    900  *    Handle CONNECTION_TERMINATED event: Remove connection from session.
    901  *
    902  *    Parameter:
    903  *          sid         Session ID
    904  *          cid         Connection ID
    905  */
    906 
    907 void
    908 event_kill_connection(uint32_t sid, uint32_t cid)
    909 {
    910 	session_t *sess;
    911 	connection_t *conn;
    912 	portal_t *portal;
    913 	initiator_t *init;
    914 
    915 	LOCK_SESSIONS;
    916 
    917 	sess = find_session_id(sid);
    918 	if (sess == NULL) {
    919 		UNLOCK_SESSIONS;
    920 		return;
    921 	}
    922 
    923 	conn = find_connection_id(sess, cid);
    924 	if (conn == NULL) {
    925 		UNLOCK_SESSIONS;
    926 		return;
    927 	}
    928 
    929 	TAILQ_REMOVE(&sess->connections, &conn->entry, link);
    930 	sess->num_connections--;
    931 
    932 	init = find_initiator_id(conn->initiator_id);
    933 	if (init != NULL)
    934 		init->active_connections--;
    935 
    936 	UNLOCK_SESSIONS;
    937 
    938 	portal = find_portal_id(conn->portal.sid.id);
    939 	if (portal != NULL)
    940 		portal->active_connections--;
    941 
    942 	free(conn);
    943 }
    944