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