iscsid_lists.c revision 1.2.2.2 1 /* $NetBSD: iscsid_lists.c,v 1.2.2.2 2012/10/30 18:59:28 yamt 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 /* return curr instead of t because curr==NULL if name not found */
236 DEB(10, ("Find_TargetName returns %p\n", 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 *
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 /* return curr instead of p because curr==NULL if not found */
270 DEB(10, ("Find_portal_by_addr returns %p\n", 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 *
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\n", 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
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\n", 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
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\n",
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
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\n"));
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->first_connection_id = conn->entry.sid.id;
547 ent->num_connections = sess->num_connections;
548 ent->portal_id = conn->portal.sid.id;
549 ent->initiator_id = conn->initiator_id;
550 ent++;
551 }
552 UNLOCK_SESSIONS;
553 }
554
555 /*
556 * get_connection_list:
557 * Handle GET_CONNECTION_LIST request: Return a list of connections
558 * for a session.
559 *
560 * Parameter:
561 * prsp Pointer to address of response buffer.
562 * prsp_temp Will be set to TRUE if buffer was allocated, FALSE
563 * for static buffer.
564 */
565
566 void
567 get_connection_list(iscsid_sym_id_t *req, iscsid_response_t **prsp,
568 int *prsp_temp)
569 {
570 iscsid_get_connection_list_rsp_t *res;
571 iscsid_response_t *rsp = *prsp;
572 iscsid_connection_list_entry_t *ent;
573 generic_entry_t *curr;
574 session_t *sess;
575 connection_t *conn;
576 int num;
577
578 DEB(10, ("get_connection_list\n"));
579
580 LOCK_SESSIONS;
581 if ((sess = find_session(req)) == NULL) {
582 UNLOCK_SESSIONS;
583 rsp->status = ISCSID_STATUS_INVALID_SESSION_ID;
584 return;
585 }
586
587 num = sess->num_connections;
588 rsp = make_rsp(sizeof(iscsid_get_connection_list_rsp_t) +
589 (num - 1) * sizeof(iscsid_connection_list_entry_t),
590 prsp, prsp_temp);
591 if (rsp == NULL) {
592 UNLOCK_SESSIONS;
593 return;
594 }
595 /* copy the ID of all list entries */
596 res = (iscsid_get_connection_list_rsp_t *)(void *)rsp->parameter;
597 res->num_connections = num;
598 ent = res->connection;
599
600 TAILQ_FOREACH(curr, &sess->connections, link) {
601 conn = (connection_t *)(void *)curr;
602 ent->connection_id = conn->entry.sid;
603 ent->target_portal_id = conn->portal.sid;
604 ent->target_portal = conn->portal.addr;
605 ent++;
606 }
607 UNLOCK_SESSIONS;
608 }
609
610
611 /*
612 * get_connection_info:
613 * Handle GET_CONNECTION_INFO request: Return information about a connection
614 *
615 * Parameter:
616 * par The request parameters.
617 * prsp Pointer to address of response buffer.
618 * prsp_temp Will be set to TRUE if buffer was allocated, FALSE
619 * for static buffer.
620 */
621
622 void
623 get_connection_info(iscsid_get_connection_info_req_t * req,
624 iscsid_response_t ** prsp, int *prsp_temp)
625 {
626 iscsid_get_connection_info_rsp_t *res;
627 iscsid_response_t *rsp = *prsp;
628 session_t *sess;
629 connection_t *conn;
630 initiator_t *init = NULL;
631
632 DEB(10, ("get_connection_info, session %d, connection %d\n",
633 req->session_id.id, req->connection_id.id));
634
635 LOCK_SESSIONS;
636 if ((sess = find_session(&req->session_id)) == NULL) {
637 UNLOCK_SESSIONS;
638 rsp->status = ISCSID_STATUS_INVALID_SESSION_ID;
639 return;
640 }
641 if (!req->connection_id.id && !req->connection_id.name[0]) {
642 conn = (connection_t *)(void *)TAILQ_FIRST(&sess->connections);
643 } else if ((conn = find_connection(sess, &req->connection_id)) == NULL) {
644 UNLOCK_SESSIONS;
645 rsp->status = ISCSID_STATUS_INVALID_CONNECTION_ID;
646 return;
647 }
648
649 rsp = make_rsp(sizeof(iscsid_get_connection_info_rsp_t), prsp, prsp_temp);
650 if (rsp == NULL) {
651 UNLOCK_SESSIONS;
652 return;
653 }
654
655 if (conn->initiator_id)
656 init = find_initiator_id(conn->initiator_id);
657
658 res = (iscsid_get_connection_info_rsp_t *)(void *)rsp->parameter;
659
660 res->session_id = sess->entry.sid;
661 res->connection_id = conn->entry.sid;
662 res->target_portal_id = conn->portal.sid;
663 res->target_portal = conn->portal.addr;
664 strlcpy((char *)res->TargetName, (char *)conn->target.TargetName,
665 sizeof(res->TargetName));
666 strlcpy((char *)res->TargetAlias, (char *)conn->target.TargetAlias,
667 sizeof(res->TargetAlias));
668 if (init != NULL) {
669 res->initiator_id = init->entry.sid;
670 strlcpy((char *)res->initiator_address, (char *)init->address,
671 sizeof(res->initiator_address));
672 }
673 UNLOCK_SESSIONS;
674 }
675
676 /* ------------------------------------------------------------------------- */
677
678 /*
679 * find_initator_by_addr:
680 * Find an Initiator Portal by Address.
681 *
682 * Parameter: the address
683 *
684 * Returns: The pointer to the portal (or NULL if not found)
685 */
686
687 static initiator_t *
688 find_initiator_by_addr(uint8_t * addr)
689 {
690 generic_entry_t *curr;
691 initiator_t *i = NULL;
692
693 TAILQ_FOREACH(curr, &list[INITIATOR_LIST].list, link) {
694 i = (void *)curr;
695 if (strcmp((char *)i->address, (char *)addr) == 0)
696 break;
697 }
698
699 /* return curr instead of i because if not found, curr==NULL */
700 DEB(9, ("Find_initiator_by_addr returns %p\n", curr));
701 return (initiator_t *)curr;
702 }
703
704
705 /*
706 * add_initiator_portal:
707 * Add an initiator portal.
708 *
709 * Parameter:
710 * par The request parameters.
711 * prsp Pointer to address of response buffer.
712 * prsp_temp Will be set to TRUE if buffer was allocated, FALSE
713 * for static buffer.
714 */
715
716 void
717 add_initiator_portal(iscsid_add_initiator_req_t *par, iscsid_response_t **prsp,
718 int *prsp_temp)
719 {
720 iscsid_add_initiator_rsp_t *res;
721 iscsid_response_t *rsp = *prsp;
722 initiator_t *init;
723
724 DEB(9, ("AddInitiatorPortal '%s' (name '%s')\n", par->address, par->name));
725
726 if (find_initiator_by_addr(par->address) != NULL) {
727 rsp->status = ISCSID_STATUS_DUPLICATE_ENTRY;
728 return;
729 }
730
731 if (find_initiator_name(par->name) != NULL) {
732 rsp->status = ISCSID_STATUS_DUPLICATE_NAME;
733 return;
734 }
735
736 if ((init = calloc(1, sizeof(*init))) == NULL) {
737 rsp->status = ISCSID_STATUS_NO_RESOURCES;
738 return;
739 }
740
741 DEB(9, ("AddInitiatorPortal initiator_id = %d\n", initiator_id));
742
743 for (initiator_id++;
744 !initiator_id || find_initiator_id(initiator_id) != NULL;)
745 initiator_id++;
746
747 init->entry.sid.id = initiator_id;
748 strlcpy((char *)init->entry.sid.name, (char *)par->name, sizeof(init->entry.sid.name));
749 strlcpy((char *)init->address, (char *)par->address, sizeof(init->address));
750
751 rsp = make_rsp(sizeof(iscsid_add_initiator_rsp_t), prsp, prsp_temp);
752 if (rsp == NULL)
753 return;
754
755 LOCK_SESSIONS;
756 TAILQ_INSERT_TAIL(&list[INITIATOR_LIST].list, &init->entry, link);
757 list[INITIATOR_LIST].num_entries++;
758 UNLOCK_SESSIONS;
759
760 res = (iscsid_add_initiator_rsp_t *)(void *)rsp->parameter;
761 res->portal_id = init->entry.sid.id;
762 }
763
764
765 /*
766 * remove_initiator_portal:
767 * Handle REMOVE_INITIATOR request: Removes an initiator entry.
768 *
769 * Parameter:
770 * par The request parameter containing the ID.
771 *
772 * Returns: status
773 */
774
775 uint32_t
776 remove_initiator_portal(iscsid_sym_id_t * par)
777 {
778 initiator_t *init;
779
780 if ((init = find_initiator(par)) == NULL)
781 return ISCSID_STATUS_INVALID_INITIATOR_ID;
782
783 LOCK_SESSIONS;
784 list[INITIATOR_LIST].num_entries--;
785
786 TAILQ_REMOVE(&list[INITIATOR_LIST].list, &init->entry, link);
787 UNLOCK_SESSIONS;
788
789 free(init);
790
791 return ISCSID_STATUS_SUCCESS;
792 }
793
794
795
796 /*
797 * get_initiator_portal:
798 * Handle GET_INITIATOR_PORTAL request: Return information about the given
799 * initiator portal.
800 *
801 * Parameter:
802 * par The request parameters.
803 * prsp Pointer to address of response buffer.
804 * prsp_temp Will be set to TRUE if buffer was allocated, FALSE
805 * for static buffer.
806 */
807
808 void
809 get_initiator_portal(iscsid_sym_id_t *par, iscsid_response_t **prsp,
810 int *prsp_temp)
811 {
812 iscsid_get_initiator_rsp_t *res;
813 iscsid_response_t *rsp = *prsp;
814 initiator_t *init;
815
816 DEB(10, ("get_initiator_portal, id %d (%s)\n", par->id, par->name));
817
818 if ((init = find_initiator(par)) == NULL) {
819 rsp->status = ISCSID_STATUS_INVALID_INITIATOR_ID;
820 return;
821 }
822
823 rsp = make_rsp(sizeof(iscsid_get_initiator_rsp_t), prsp, prsp_temp);
824 if (rsp == NULL)
825 return;
826
827 res = (iscsid_get_initiator_rsp_t *)(void *)rsp->parameter;
828 res->portal_id = init->entry.sid;
829 strlcpy((char *)res->address, (char *)init->address, sizeof(res->address));
830 }
831
832
833 /*
834 * select_initiator:
835 * Select the initiator portal to use.
836 * Selects the portal with the least number of active connections.
837 *
838 * Returns:
839 * Pointer to the portal, NULL if no portals are defined.
840 *
841 * NOTE: Called with session list locked, so don't lock again.
842 */
843
844 initiator_t *
845 select_initiator(void)
846 {
847 generic_entry_t *curr;
848 initiator_t *imin = NULL;
849 uint32_t ccnt = 64 * 1024; /* probably not more than 64k connections... */
850
851 if (!list[INITIATOR_LIST].num_entries)
852 return NULL;
853
854 TAILQ_FOREACH(curr, &list[INITIATOR_LIST].list, link) {
855 initiator_t *i = (void *)curr;
856 if ((i->active_connections < ccnt)) {
857 ccnt = i->active_connections;
858 imin = i;
859 }
860 }
861 return imin;
862 }
863
864 /* ------------------------------------------------------------------------- */
865
866 /*
867 * event_kill_session:
868 * Handle SESSION_TERMINATED event: Remove session and all associated
869 * connections.
870 *
871 * Parameter:
872 * sid Session ID
873 */
874
875 void
876 event_kill_session(uint32_t sid)
877 {
878 session_t *sess;
879 connection_t *conn;
880 portal_t *portal;
881 initiator_t *init;
882
883 LOCK_SESSIONS;
884
885 sess = find_session_id(sid);
886
887 if (sess == NULL) {
888 UNLOCK_SESSIONS;
889 return;
890 }
891
892 TAILQ_REMOVE(&list[SESSION_LIST].list, &sess->entry, link);
893 list[SESSION_LIST].num_entries--;
894
895 UNLOCK_SESSIONS;
896
897 while ((conn = (connection_t *)(void *)TAILQ_FIRST(&sess->connections)) != NULL) {
898 TAILQ_REMOVE(&sess->connections, &conn->entry, link);
899
900 portal = find_portal_id(conn->portal.sid.id);
901 if (portal != NULL)
902 portal->active_connections--;
903
904 init = find_initiator_id(conn->initiator_id);
905 if (init != NULL)
906 init->active_connections--;
907
908 free(conn);
909 }
910 free(sess);
911 }
912
913
914 /*
915 * event_kill_connection:
916 * Handle CONNECTION_TERMINATED event: Remove connection from session.
917 *
918 * Parameter:
919 * sid Session ID
920 * cid Connection ID
921 */
922
923 void
924 event_kill_connection(uint32_t sid, uint32_t cid)
925 {
926 session_t *sess;
927 connection_t *conn;
928 portal_t *portal;
929 initiator_t *init;
930
931 LOCK_SESSIONS;
932
933 sess = find_session_id(sid);
934 if (sess == NULL) {
935 UNLOCK_SESSIONS;
936 return;
937 }
938
939 conn = find_connection_id(sess, cid);
940 if (conn == NULL) {
941 UNLOCK_SESSIONS;
942 return;
943 }
944
945 TAILQ_REMOVE(&sess->connections, &conn->entry, link);
946 sess->num_connections--;
947
948 init = find_initiator_id(conn->initiator_id);
949 if (init != NULL)
950 init->active_connections--;
951
952 UNLOCK_SESSIONS;
953
954 portal = find_portal_id(conn->portal.sid.id);
955 if (portal != NULL)
956 portal->active_connections--;
957
958 free(conn);
959 }
960