Home | History | Annotate | Line # | Download | only in iscsid
iscsid_lists.c revision 1.7.2.1
      1  1.7.2.1       tls /*	$NetBSD: iscsid_lists.c,v 1.7.2.1 2013/02/25 00:28:08 tls 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.6       riz 	DEB(10, ("Find_TargetName returns %p\n", 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.4       riz 		DEB(10, ("Find_portal_by_addr - addr %s port %d target %p\n",
    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.2  christos 	DEB(10, ("Find_portal_by_addr returns %p\n", 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.2  christos 	DEB(10, ("Find_send_target_by_addr returns %p\n", 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.1       agc 	DEB(10, ("get_list, kind %d\n", 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.1       agc 	DEB(10, ("search_list, list_kind %d, search_kind %d\n",
    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.1       agc 	DEB(10, ("get_session_list\n"));
    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.7.2.1       tls 		if (conn) {
    548  1.7.2.1       tls 			ent->first_connection_id = conn->entry.sid.id;
    549  1.7.2.1       tls 			ent->portal_id = conn->portal.sid.id;
    550  1.7.2.1       tls 			ent->initiator_id = conn->initiator_id;
    551  1.7.2.1       tls 		} else {
    552  1.7.2.1       tls 			ent->first_connection_id = 0;
    553  1.7.2.1       tls 			ent->portal_id = 0;
    554  1.7.2.1       tls 			ent->initiator_id = 0;
    555  1.7.2.1       tls 		}
    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.1       agc 	DEB(10, ("get_connection_list\n"));
    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.1       agc 	DEB(10, ("get_connection_info, session %d, connection %d\n",
    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.7.2.1       tls 	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.7.2.1       tls 	if (conn) {
    668  1.7.2.1       tls 		res->connection_id = conn->entry.sid;
    669  1.7.2.1       tls 		res->target_portal_id = conn->portal.sid;
    670  1.7.2.1       tls 		res->target_portal = conn->portal.addr;
    671  1.7.2.1       tls 		strlcpy((char *)res->TargetName, (char *)conn->target.TargetName,
    672  1.7.2.1       tls 			sizeof(res->TargetName));
    673  1.7.2.1       tls 		strlcpy((char *)res->TargetAlias, (char *)conn->target.TargetAlias,
    674  1.7.2.1       tls 			sizeof(res->TargetAlias));
    675  1.7.2.1       tls 	} else {
    676  1.7.2.1       tls 		res->connection_id.id = 0;
    677  1.7.2.1       tls 		res->connection_id.name[0] = '\0';
    678  1.7.2.1       tls 		res->target_portal_id.id = 0;
    679  1.7.2.1       tls 		res->target_portal_id.name[0] = '\0';
    680  1.7.2.1       tls 		memset(&res->target_portal, 0, sizeof(res->target_portal));
    681  1.7.2.1       tls 		memset(&res->TargetName, 0, sizeof(res->TargetName));
    682  1.7.2.1       tls 		memset(&res->TargetAlias, 0, sizeof(res->TargetAlias));
    683  1.7.2.1       tls 	}
    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.1       agc  * find_initator_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.2  christos 	DEB(9, ("Find_initiator_by_addr returns %p\n", 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.1       agc 	DEB(9, ("AddInitiatorPortal '%s' (name '%s')\n", 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.1       agc 	DEB(9, ("AddInitiatorPortal initiator_id = %d\n", 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.1       agc 	DEB(10, ("get_initiator_portal, id %d (%s)\n", 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