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