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