NetBSD/sbin/iscsid/iscsid_lists.c

976 lines
23 KiB
C

/* $NetBSD: iscsid_lists.c,v 1.9 2016/05/29 13:35:45 mlelstv Exp $ */
/*-
* Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "iscsid_globals.h"
/* counter for initiator ID */
static uint32_t initiator_id = 0;
/* -------------------------------------------------------------------------- */
#if 0
/*
* verify_session:
* Verify that a specific session still exists, delete it if not.
*
* Parameter: The session pointer.
*/
static void
verify_session(session_t * sess)
{
generic_entry_t *curr, *next;
int nosess = 0;
for (curr = sess->connections.tqh_first; curr != NULL && !nosess; curr = next) {
next = curr->link.tqe_next;
nosess = verify_connection((connection_t *) curr) == ISCSI_STATUS_INVALID_SESSION_ID;
}
if (!nosess && sess->num_connections)
return;
TAILQ_REMOVE(&list[SESSION_LIST].list, &sess->entry, link);
list[SESSION_LIST].num_entries--;
while ((curr = TAILQ_FIRST(&sess->connections)) != NULL) {
TAILQ_REMOVE(&sess->connections, curr, link);
free(curr);
}
free(sess);
}
/*
* verify_sessions:
* Verify that all sessions in the list still exist.
*/
void
verify_sessions(void)
{
generic_entry_t *curr, *next;
for (curr = list[SESSION_LIST].list.tqh_first; curr != NULL; curr = next) {
next = curr->link.tqe_next;
verify_session((session_t *) curr);
}
}
#endif
/* -------------------------------------------------------------------------- */
/*
* find_id:
* Find a list element by ID.
*
* Parameter: the list head and the ID to search for
*
* Returns: The pointer to the element (or NULL if not found)
*/
generic_entry_t *
find_id(generic_list_t * head, uint32_t id)
{
generic_entry_t *curr;
if (!id)
return NULL;
TAILQ_FOREACH(curr, head, link)
if (curr->sid.id == id)
break;
return curr;
}
/*
* find_name:
* Find a list entry by name.
*
* Parameter: the list head and the symbolic name to search for
*
* Returns: The pointer to the entry (or NULL if not found)
*/
generic_entry_t *
find_name(generic_list_t * head, uint8_t * name)
{
generic_entry_t *curr;
if (!*name)
return NULL;
TAILQ_FOREACH(curr, head, link)
if (strcmp((char *)curr->sid.name, (char *)name) == 0)
break;
return curr;
}
/*
* find_sym_id:
* Find a list entry by name or numeric id.
*
* Parameter: the list head and the symbolic id to search for
*
* Returns: The pointer to the entry (or NULL if not found)
*/
generic_entry_t *
find_sym_id(generic_list_t * head, iscsid_sym_id_t * sid)
{
if (sid->id != 0)
return find_id(head, sid->id);
return (sid->name[0]) ? find_name(head, sid->name) : NULL;
}
/*
* get_id:
* Get the numeric ID for a symbolic ID
*
* Parameter: the list head and the symbolic id
*
* Returns: The numeric ID (0 if not found)
*/
uint32_t
get_id(generic_list_t * head, iscsid_sym_id_t * sid)
{
generic_entry_t *ent;
if (sid->id != 0)
return sid->id;
ent = find_name(head, sid->name);
return (ent != NULL) ? ent->sid.id : 0;
}
/*
* find_target_name:
* Find a target by TargetName.
*
* Parameter: the target name
*
* Returns: The pointer to the target (or NULL if not found)
*/
target_t *
find_target(iscsid_list_kind_t lst, iscsid_sym_id_t * sid)
{
target_t *targ;
if ((targ = (target_t *)(void *)find_sym_id (&list [lst].list, sid)) != NULL)
return targ;
if (lst == TARGET_LIST) {
portal_t *portal;
if ((portal = (void *)find_portal (sid)) != NULL)
return portal->target;
}
return NULL;
}
/*
* find_target_name:
* Find a target by TargetName.
*
* Parameter: the target name
*
* Returns: The pointer to the target (or NULL if not found)
*/
target_t *
find_TargetName(iscsid_list_kind_t lst, uint8_t * name)
{
generic_entry_t *curr;
target_t *t = NULL;
if (lst == PORTAL_LIST)
lst = TARGET_LIST;
TAILQ_FOREACH(curr, &list[lst].list, link) {
t = (void *)curr;
if (strcmp((char *)t->TargetName, (char *)name) == 0)
break;
}
/* return curr instead of t because curr==NULL if name not found */
DEB(10, ("Find_TargetName returns %p", curr));
return (target_t *)curr;
}
/*
* find_portal_by_addr:
* Find a Portal by Address.
*
* Parameter: the associated target, and the address
*
* Returns: The pointer to the portal (or NULL if not found)
*/
portal_t *
find_portal_by_addr(target_t * target, iscsi_portal_address_t * addr)
{
generic_entry_t *curr;
portal_t *p = NULL;
TAILQ_FOREACH(curr, &list[PORTAL_LIST].list, link) {
p = (void *)curr;
DEB(10, ("Find_portal_by_addr - addr %s port %d target %p",
p->addr.address,
p->addr.port,
p->target));
if (strcmp((char *)p->addr.address, (char *)addr->address) == 0 &&
(!addr->port || p->addr.port == addr->port) &&
p->target == target)
break;
}
/* return curr instead of p because curr==NULL if not found */
DEB(10, ("Find_portal_by_addr returns %p", curr));
return (portal_t *)curr;
}
/*
* find_send_target_by_addr:
* Find a Send Target by Address.
*
* Parameter: the address
*
* Returns: The pointer to the portal (or NULL if not found)
*/
send_target_t *
find_send_target_by_addr(iscsi_portal_address_t * addr)
{
generic_entry_t *curr;
send_target_t *t = NULL;
TAILQ_FOREACH(curr, &list[SEND_TARGETS_LIST].list, link) {
t = (void *)curr;
if (strcmp((char *)t->addr.address, (char *)addr->address) == 0 &&
(!addr->port || t->addr.port == addr->port))
break;
}
/* return curr instead of p because curr==NULL if not found */
DEB(10, ("Find_send_target_by_addr returns %p", curr));
return (send_target_t *)curr;
}
/*
* get_list:
* Handle GET_LIST request: Return the list of IDs contained in the list.
*
* Parameter:
* par The request parameters.
* prsp Pointer to address of response buffer.
* prsp_temp Will be set to TRUE if buffer was allocated, FALSE
* for static buffer.
*/
void
get_list(iscsid_get_list_req_t * par, iscsid_response_t ** prsp, int *prsp_temp)
{
iscsid_get_list_rsp_t *res;
iscsid_response_t *rsp = *prsp;
int num;
uint32_t *idp;
generic_list_t *plist;
generic_entry_t *curr;
DEB(10, ("get_list, kind %d", par->list_kind));
if (par->list_kind == SESSION_LIST)
LOCK_SESSIONS;
else if (par->list_kind >= NUM_DAEMON_LISTS) {
rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
return;
}
plist = &list[par->list_kind].list;
num = list[par->list_kind].num_entries;
if (!num) {
if (par->list_kind == SESSION_LIST)
UNLOCK_SESSIONS;
rsp->status = ISCSID_STATUS_LIST_EMPTY;
return;
}
rsp = make_rsp(sizeof(iscsid_get_list_rsp_t) +
(num - 1) * sizeof(uint32_t), prsp, prsp_temp);
if (rsp == NULL) {
if (par->list_kind == SESSION_LIST)
UNLOCK_SESSIONS;
return;
}
/* copy the ID of all list entries */
res = (iscsid_get_list_rsp_t *)(void *)rsp->parameter;
res->num_entries = num;
idp = res->id;
TAILQ_FOREACH(curr, plist, link)
* idp++ = curr->sid.id;
if (par->list_kind == SESSION_LIST)
UNLOCK_SESSIONS;
}
/*
* search_list:
* Handle SEARCH_LIST request: Search the given list for the string or
* address.
* Note: Not all combinations of list and search type make sense.
*
* Parameter:
* par The request parameters.
* prsp Pointer to address of response buffer.
* prsp_temp Will be set to TRUE if buffer was allocated, FALSE
* for static buffer.
*/
void
search_list(iscsid_search_list_req_t * par, iscsid_response_t ** prsp,
int *prsp_temp)
{
iscsid_response_t *rsp = *prsp;
generic_entry_t *elem = NULL;
DEB(10, ("search_list, list_kind %d, search_kind %d",
par->list_kind, par->search_kind));
if (par->list_kind == SESSION_LIST)
LOCK_SESSIONS;
else if (par->list_kind >= NUM_DAEMON_LISTS) {
rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
return;
}
if (!list[par->list_kind].num_entries) {
if (par->list_kind == SESSION_LIST)
UNLOCK_SESSIONS;
rsp->status = ISCSID_STATUS_NOT_FOUND;
return;
}
switch (par->search_kind) {
case FIND_ID:
elem = find_id(&list[par->list_kind].list, par->intval);
break;
case FIND_NAME:
elem = find_name(&list[par->list_kind].list, par->strval);
break;
case FIND_TARGET_NAME:
switch (par->list_kind) {
case TARGET_LIST:
case PORTAL_LIST:
case SEND_TARGETS_LIST:
elem = (void *)find_TargetName(par->list_kind,
par->strval);
break;
case SESSION_LIST:
TAILQ_FOREACH(elem, &list[SESSION_LIST].list, link)
if (strcmp((char *)((session_t *)(void *)elem)->target.TargetName,
(char *)par->strval) == 0)
break;
break;
default:
rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
break;
}
break;
case FIND_ADDRESS:
switch (par->list_kind) {
case PORTAL_LIST:
TAILQ_FOREACH(elem, &list[PORTAL_LIST].list, link) {
portal_t *p = (void *)elem;
if (strcmp((char *)p->addr.address, (char *)par->strval) == 0 &&
(!par->intval ||
p->addr.port == par->intval))
break;
}
break;
case SEND_TARGETS_LIST:
TAILQ_FOREACH(elem, &list[SEND_TARGETS_LIST].list, link) {
send_target_t *t = (void *)elem;
if (strcmp((char *)t->addr.address,
(char *)par->strval) == 0 &&
(!par->intval ||
t->addr.port == par->intval))
break;
}
break;
case ISNS_LIST:
TAILQ_FOREACH(elem, &list[ISNS_LIST].list, link) {
isns_t *i = (void *)elem;
if (strcmp((char *)i->address, (char *)par->strval) == 0 &&
(!par->intval || i->port == par->intval))
break;
}
break;
default:
rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
break;
}
break;
default:
rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
return;
}
if (elem == NULL) {
if (par->list_kind == SESSION_LIST)
UNLOCK_SESSIONS;
rsp->status = ISCSID_STATUS_NOT_FOUND;
return;
}
rsp = make_rsp(sizeof(iscsid_sym_id_t), prsp, prsp_temp);
if (rsp == NULL) {
if (par->list_kind == SESSION_LIST)
UNLOCK_SESSIONS;
return;
}
(void) memcpy(rsp->parameter, &elem->sid, sizeof(elem->sid));
if (par->list_kind == SESSION_LIST)
UNLOCK_SESSIONS;
}
/*
* get_session_list:
* Handle GET_SESSION_LIST request: Return a list of sessions complete
* with basic session info.
*
* Parameter:
* prsp Pointer to address of response buffer.
* prsp_temp Will be set to TRUE if buffer was allocated, FALSE
* for static buffer.
*/
void
get_session_list(iscsid_response_t ** prsp, int *prsp_temp)
{
iscsid_get_session_list_rsp_t *res;
iscsid_response_t *rsp = *prsp;
iscsid_session_list_entry_t *ent;
generic_list_t *plist;
generic_entry_t *curr;
session_t *sess;
connection_t *conn;
int num;
DEB(10, ("get_session_list"));
LOCK_SESSIONS;
plist = &list[SESSION_LIST].list;
num = list[SESSION_LIST].num_entries;
if (!num) {
UNLOCK_SESSIONS;
rsp->status = ISCSID_STATUS_LIST_EMPTY;
return;
}
rsp = make_rsp(sizeof(iscsid_get_session_list_rsp_t) +
(num - 1) * sizeof(iscsid_session_list_entry_t),
prsp, prsp_temp);
if (rsp == NULL) {
UNLOCK_SESSIONS;
return;
}
/* copy the ID of all list entries */
res = (iscsid_get_session_list_rsp_t *)(void *)rsp->parameter;
res->num_entries = num;
ent = res->session;
TAILQ_FOREACH(curr, plist, link) {
sess = (session_t *)(void *)curr;
conn = (connection_t *)(void *)TAILQ_FIRST(&sess->connections);
ent->session_id = sess->entry.sid;
ent->num_connections = sess->num_connections;
if (conn) {
ent->first_connection_id = conn->entry.sid.id;
ent->portal_id = conn->portal.sid.id;
ent->initiator_id = conn->initiator_id;
} else {
ent->first_connection_id = 0;
ent->portal_id = 0;
ent->initiator_id = 0;
}
ent++;
}
UNLOCK_SESSIONS;
}
/*
* get_connection_list:
* Handle GET_CONNECTION_LIST request: Return a list of connections
* for a session.
*
* Parameter:
* prsp Pointer to address of response buffer.
* prsp_temp Will be set to TRUE if buffer was allocated, FALSE
* for static buffer.
*/
void
get_connection_list(iscsid_sym_id_t *req, iscsid_response_t **prsp,
int *prsp_temp)
{
iscsid_get_connection_list_rsp_t *res;
iscsid_response_t *rsp = *prsp;
iscsid_connection_list_entry_t *ent;
generic_entry_t *curr;
session_t *sess;
connection_t *conn;
int num;
DEB(10, ("get_connection_list"));
LOCK_SESSIONS;
if ((sess = find_session(req)) == NULL) {
UNLOCK_SESSIONS;
rsp->status = ISCSID_STATUS_INVALID_SESSION_ID;
return;
}
num = sess->num_connections;
rsp = make_rsp(sizeof(iscsid_get_connection_list_rsp_t) +
(num - 1) * sizeof(iscsid_connection_list_entry_t),
prsp, prsp_temp);
if (rsp == NULL) {
UNLOCK_SESSIONS;
return;
}
/* copy the ID of all list entries */
res = (iscsid_get_connection_list_rsp_t *)(void *)rsp->parameter;
res->num_connections = num;
ent = res->connection;
TAILQ_FOREACH(curr, &sess->connections, link) {
conn = (connection_t *)(void *)curr;
ent->connection_id = conn->entry.sid;
ent->target_portal_id = conn->portal.sid;
ent->target_portal = conn->portal.addr;
ent++;
}
UNLOCK_SESSIONS;
}
/*
* get_connection_info:
* Handle GET_CONNECTION_INFO request: Return information about a connection
*
* Parameter:
* par The request parameters.
* prsp Pointer to address of response buffer.
* prsp_temp Will be set to TRUE if buffer was allocated, FALSE
* for static buffer.
*/
void
get_connection_info(iscsid_get_connection_info_req_t * req,
iscsid_response_t ** prsp, int *prsp_temp)
{
iscsid_get_connection_info_rsp_t *res;
iscsid_response_t *rsp = *prsp;
session_t *sess;
connection_t *conn;
initiator_t *init = NULL;
DEB(10, ("get_connection_info, session %d, connection %d",
req->session_id.id, req->connection_id.id));
LOCK_SESSIONS;
if ((sess = find_session(&req->session_id)) == NULL) {
UNLOCK_SESSIONS;
rsp->status = ISCSID_STATUS_INVALID_SESSION_ID;
return;
}
if (!req->connection_id.id && !req->connection_id.name[0]) {
conn = (connection_t *)(void *)TAILQ_FIRST(&sess->connections);
} else if ((conn = find_connection(sess, &req->connection_id)) == NULL) {
UNLOCK_SESSIONS;
rsp->status = ISCSID_STATUS_INVALID_CONNECTION_ID;
return;
}
rsp = make_rsp(sizeof(iscsid_get_connection_info_rsp_t), prsp, prsp_temp);
if (rsp == NULL) {
UNLOCK_SESSIONS;
return;
}
if (conn && conn->initiator_id)
init = find_initiator_id(conn->initiator_id);
res = (iscsid_get_connection_info_rsp_t *)(void *)rsp->parameter;
res->session_id = sess->entry.sid;
if (conn) {
res->connection_id = conn->entry.sid;
res->target_portal_id = conn->portal.sid;
res->target_portal = conn->portal.addr;
strlcpy((char *)res->TargetName, (char *)conn->target.TargetName,
sizeof(res->TargetName));
strlcpy((char *)res->TargetAlias, (char *)conn->target.TargetAlias,
sizeof(res->TargetAlias));
} else {
res->connection_id.id = 0;
res->connection_id.name[0] = '\0';
res->target_portal_id.id = 0;
res->target_portal_id.name[0] = '\0';
memset(&res->target_portal, 0, sizeof(res->target_portal));
memset(&res->TargetName, 0, sizeof(res->TargetName));
memset(&res->TargetAlias, 0, sizeof(res->TargetAlias));
}
if (init != NULL) {
res->initiator_id = init->entry.sid;
strlcpy((char *)res->initiator_address, (char *)init->address,
sizeof(res->initiator_address));
}
UNLOCK_SESSIONS;
}
/* ------------------------------------------------------------------------- */
/*
* find_initator_by_addr:
* Find an Initiator Portal by Address.
*
* Parameter: the address
*
* Returns: The pointer to the portal (or NULL if not found)
*/
static initiator_t *
find_initiator_by_addr(uint8_t * addr)
{
generic_entry_t *curr;
initiator_t *i = NULL;
TAILQ_FOREACH(curr, &list[INITIATOR_LIST].list, link) {
i = (void *)curr;
if (strcmp((char *)i->address, (char *)addr) == 0)
break;
}
/* return curr instead of i because if not found, curr==NULL */
DEB(9, ("Find_initiator_by_addr returns %p", curr));
return (initiator_t *)curr;
}
/*
* add_initiator_portal:
* Add an initiator portal.
*
* Parameter:
* par The request parameters.
* prsp Pointer to address of response buffer.
* prsp_temp Will be set to TRUE if buffer was allocated, FALSE
* for static buffer.
*/
void
add_initiator_portal(iscsid_add_initiator_req_t *par, iscsid_response_t **prsp,
int *prsp_temp)
{
iscsid_add_initiator_rsp_t *res;
iscsid_response_t *rsp = *prsp;
initiator_t *init;
DEB(9, ("AddInitiatorPortal '%s' (name '%s')", par->address, par->name));
if (find_initiator_by_addr(par->address) != NULL) {
rsp->status = ISCSID_STATUS_DUPLICATE_ENTRY;
return;
}
if (find_initiator_name(par->name) != NULL) {
rsp->status = ISCSID_STATUS_DUPLICATE_NAME;
return;
}
if ((init = calloc(1, sizeof(*init))) == NULL) {
rsp->status = ISCSID_STATUS_NO_RESOURCES;
return;
}
DEB(9, ("AddInitiatorPortal initiator_id = %d", initiator_id));
for (initiator_id++;
!initiator_id || find_initiator_id(initiator_id) != NULL;)
initiator_id++;
init->entry.sid.id = initiator_id;
strlcpy((char *)init->entry.sid.name, (char *)par->name, sizeof(init->entry.sid.name));
strlcpy((char *)init->address, (char *)par->address, sizeof(init->address));
rsp = make_rsp(sizeof(iscsid_add_initiator_rsp_t), prsp, prsp_temp);
if (rsp == NULL)
return;
LOCK_SESSIONS;
TAILQ_INSERT_TAIL(&list[INITIATOR_LIST].list, &init->entry, link);
list[INITIATOR_LIST].num_entries++;
UNLOCK_SESSIONS;
res = (iscsid_add_initiator_rsp_t *)(void *)rsp->parameter;
res->portal_id = init->entry.sid.id;
}
/*
* remove_initiator_portal:
* Handle REMOVE_INITIATOR request: Removes an initiator entry.
*
* Parameter:
* par The request parameter containing the ID.
*
* Returns: status
*/
uint32_t
remove_initiator_portal(iscsid_sym_id_t * par)
{
initiator_t *init;
if ((init = find_initiator(par)) == NULL)
return ISCSID_STATUS_INVALID_INITIATOR_ID;
LOCK_SESSIONS;
list[INITIATOR_LIST].num_entries--;
TAILQ_REMOVE(&list[INITIATOR_LIST].list, &init->entry, link);
UNLOCK_SESSIONS;
free(init);
return ISCSID_STATUS_SUCCESS;
}
/*
* get_initiator_portal:
* Handle GET_INITIATOR_PORTAL request: Return information about the given
* initiator portal.
*
* Parameter:
* par The request parameters.
* prsp Pointer to address of response buffer.
* prsp_temp Will be set to TRUE if buffer was allocated, FALSE
* for static buffer.
*/
void
get_initiator_portal(iscsid_sym_id_t *par, iscsid_response_t **prsp,
int *prsp_temp)
{
iscsid_get_initiator_rsp_t *res;
iscsid_response_t *rsp = *prsp;
initiator_t *init;
DEB(10, ("get_initiator_portal, id %d (%s)", par->id, par->name));
if ((init = find_initiator(par)) == NULL) {
rsp->status = ISCSID_STATUS_INVALID_INITIATOR_ID;
return;
}
rsp = make_rsp(sizeof(iscsid_get_initiator_rsp_t), prsp, prsp_temp);
if (rsp == NULL)
return;
res = (iscsid_get_initiator_rsp_t *)(void *)rsp->parameter;
res->portal_id = init->entry.sid;
strlcpy((char *)res->address, (char *)init->address, sizeof(res->address));
}
/*
* select_initiator:
* Select the initiator portal to use.
* Selects the portal with the least number of active connections.
*
* Returns:
* Pointer to the portal, NULL if no portals are defined.
*
* NOTE: Called with session list locked, so don't lock again.
*/
initiator_t *
select_initiator(void)
{
generic_entry_t *curr;
initiator_t *imin = NULL;
uint32_t ccnt = 64 * 1024; /* probably not more than 64k connections... */
if (!list[INITIATOR_LIST].num_entries)
return NULL;
TAILQ_FOREACH(curr, &list[INITIATOR_LIST].list, link) {
initiator_t *i = (void *)curr;
if ((i->active_connections < ccnt)) {
ccnt = i->active_connections;
imin = i;
}
}
return imin;
}
/* ------------------------------------------------------------------------- */
/*
* event_kill_session:
* Handle SESSION_TERMINATED event: Remove session and all associated
* connections.
*
* Parameter:
* sid Session ID
*/
void
event_kill_session(uint32_t sid)
{
session_t *sess;
connection_t *conn;
portal_t *portal;
initiator_t *init;
LOCK_SESSIONS;
sess = find_session_id(sid);
if (sess == NULL) {
UNLOCK_SESSIONS;
return;
}
TAILQ_REMOVE(&list[SESSION_LIST].list, &sess->entry, link);
list[SESSION_LIST].num_entries--;
UNLOCK_SESSIONS;
while ((conn = (connection_t *)(void *)TAILQ_FIRST(&sess->connections)) != NULL) {
TAILQ_REMOVE(&sess->connections, &conn->entry, link);
portal = find_portal_id(conn->portal.sid.id);
if (portal != NULL)
portal->active_connections--;
init = find_initiator_id(conn->initiator_id);
if (init != NULL)
init->active_connections--;
free(conn);
}
free(sess);
}
/*
* event_kill_connection:
* Handle CONNECTION_TERMINATED event: Remove connection from session.
*
* Parameter:
* sid Session ID
* cid Connection ID
*/
void
event_kill_connection(uint32_t sid, uint32_t cid)
{
session_t *sess;
connection_t *conn;
portal_t *portal;
initiator_t *init;
LOCK_SESSIONS;
sess = find_session_id(sid);
if (sess == NULL) {
UNLOCK_SESSIONS;
return;
}
conn = find_connection_id(sess, cid);
if (conn == NULL) {
UNLOCK_SESSIONS;
return;
}
TAILQ_REMOVE(&sess->connections, &conn->entry, link);
sess->num_connections--;
init = find_initiator_id(conn->initiator_id);
if (init != NULL)
init->active_connections--;
UNLOCK_SESSIONS;
portal = find_portal_id(conn->portal.sid.id);
if (portal != NULL)
portal->active_connections--;
free(conn);
}