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