iscsid_targets.c revision 1.7 1 1.7 andvar /* $NetBSD: iscsid_targets.c,v 1.7 2022/05/24 20:50:17 andvar Exp $ */
2 1.1 agc
3 1.1 agc /*-
4 1.1 agc * Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc.
5 1.1 agc * All rights reserved.
6 1.1 agc *
7 1.1 agc * This code is derived from software contributed to The NetBSD Foundation
8 1.1 agc * by Wasabi Systems, Inc.
9 1.1 agc *
10 1.1 agc * Redistribution and use in source and binary forms, with or without
11 1.1 agc * modification, are permitted provided that the following conditions
12 1.1 agc * are met:
13 1.1 agc * 1. Redistributions of source code must retain the above copyright
14 1.1 agc * notice, this list of conditions and the following disclaimer.
15 1.1 agc * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 agc * notice, this list of conditions and the following disclaimer in the
17 1.1 agc * documentation and/or other materials provided with the distribution.
18 1.1 agc *
19 1.1 agc * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 agc * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 agc * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 agc * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 agc * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 agc * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 agc * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 agc * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 agc * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 agc * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 agc * POSSIBILITY OF SUCH DAMAGE.
30 1.1 agc */
31 1.1 agc
32 1.1 agc #include "iscsid_globals.h"
33 1.1 agc
34 1.1 agc #include <ctype.h>
35 1.1 agc
36 1.1 agc /* counter for portal and target ID */
37 1.3 agc static uint32_t portarget_id = 0;
38 1.1 agc
39 1.1 agc /* counter for send_targets ID */
40 1.3 agc static uint32_t send_target_id = 0;
41 1.1 agc
42 1.1 agc
43 1.1 agc /*
44 1.1 agc * create_portal:
45 1.1 agc * Create a portal entry and link it into the appropriate lists.
46 1.1 agc * May also create the associated portal group entry if it does not exist.
47 1.1 agc * Will return the existing entry if the address matches a defined portal.
48 1.1 agc *
49 1.1 agc * Parameter:
50 1.1 agc * target the pointer to the target
51 1.1 agc * addr the portal address (includes tag)
52 1.1 agc * dtype portal discovery type
53 1.1 agc * did discovery ID
54 1.1 agc *
55 1.1 agc * Returns: pointer to created portal
56 1.1 agc */
57 1.1 agc
58 1.3 agc static portal_t *
59 1.1 agc create_portal(target_t *target, iscsi_portal_address_t *addr,
60 1.1 agc iscsi_portal_types_t dtype, uint32_t did)
61 1.1 agc {
62 1.1 agc portal_group_t *curr;
63 1.1 agc portal_t *portal;
64 1.1 agc u_short tag = addr->group_tag;
65 1.1 agc
66 1.6 mlelstv DEB(9, ("Create Portal addr %s port %d group %d",
67 1.1 agc addr->address, addr->port, addr->group_tag));
68 1.1 agc
69 1.1 agc if ((portal = find_portal_by_addr(target, addr)) != NULL)
70 1.1 agc return portal;
71 1.1 agc
72 1.1 agc portal = calloc(1, sizeof(*portal));
73 1.1 agc if (!portal) {
74 1.6 mlelstv DEBOUT(("Out of memory in create_portal!"));
75 1.1 agc return NULL;
76 1.1 agc }
77 1.1 agc portal->addr = *addr;
78 1.1 agc portal->target = target;
79 1.1 agc portal->portaltype = dtype;
80 1.1 agc portal->discoveryid = did;
81 1.1 agc if (!portal->addr.port) {
82 1.1 agc portal->addr.port = ISCSI_DEFAULT_PORT;
83 1.1 agc }
84 1.1 agc for (portarget_id++; !portarget_id ||
85 1.1 agc find_portal_id(portarget_id) != NULL ||
86 1.1 agc find_target_id(TARGET_LIST, portarget_id) != NULL;) {
87 1.1 agc portarget_id++;
88 1.1 agc }
89 1.1 agc portal->entry.sid.id = portarget_id;
90 1.1 agc
91 1.1 agc TAILQ_FOREACH(curr, &target->group_list, groups)
92 1.1 agc if (curr->tag == tag)
93 1.1 agc break;
94 1.1 agc
95 1.1 agc if (!curr) {
96 1.1 agc curr = calloc(1, sizeof(*curr));
97 1.1 agc if (!curr) {
98 1.1 agc free(portal);
99 1.6 mlelstv DEBOUT(("Out of memory in create_portal!"));
100 1.1 agc return NULL;
101 1.1 agc }
102 1.1 agc curr->tag = tag;
103 1.1 agc TAILQ_INIT(&curr->portals);
104 1.1 agc TAILQ_INSERT_TAIL(&target->group_list, curr, groups);
105 1.1 agc target->num_groups++;
106 1.1 agc }
107 1.1 agc
108 1.1 agc portal->group = curr;
109 1.1 agc
110 1.1 agc TAILQ_INSERT_TAIL(&curr->portals, portal, group_list);
111 1.1 agc curr->num_portals++;
112 1.1 agc target->num_portals++;
113 1.1 agc
114 1.1 agc TAILQ_INSERT_TAIL(&list[PORTAL_LIST].list, &portal->entry, link);
115 1.1 agc list[PORTAL_LIST].num_entries++;
116 1.1 agc
117 1.6 mlelstv DEB(9, ("create_portal returns %p", portal));
118 1.1 agc return portal;
119 1.1 agc }
120 1.1 agc
121 1.1 agc
122 1.1 agc /*
123 1.1 agc * delete_portal:
124 1.1 agc * Delete a portal entry after unlinking it from its lists.
125 1.1 agc * May also delete the associated portal group entry if the group is empty.
126 1.1 agc *
127 1.1 agc * Parameter:
128 1.1 agc * portal the pointer to the portal
129 1.1 agc * delete_empty delete empty target if true
130 1.1 agc */
131 1.1 agc
132 1.1 agc void
133 1.1 agc delete_portal(portal_t * portal, boolean_t delete_empty)
134 1.1 agc {
135 1.1 agc portal_group_t *curr = portal->group;
136 1.1 agc target_t *target = portal->target;
137 1.1 agc
138 1.1 agc TAILQ_REMOVE(&curr->portals, portal, group_list);
139 1.1 agc TAILQ_REMOVE(&list[PORTAL_LIST].list, &portal->entry, link);
140 1.1 agc curr->num_portals--;
141 1.1 agc target->num_portals--;
142 1.1 agc list[PORTAL_LIST].num_entries--;
143 1.1 agc
144 1.1 agc if (!curr->num_portals) {
145 1.1 agc TAILQ_REMOVE(&target->group_list, curr, groups);
146 1.1 agc free(curr);
147 1.1 agc target->num_groups--;
148 1.1 agc }
149 1.1 agc free(portal);
150 1.1 agc
151 1.1 agc /* Optionally delete target if no portals left */
152 1.1 agc if (delete_empty && !target->num_portals) {
153 1.1 agc TAILQ_REMOVE(&list[TARGET_LIST].list, &target->entry, link);
154 1.1 agc list[TARGET_LIST].num_entries--;
155 1.1 agc free(target);
156 1.1 agc }
157 1.1 agc }
158 1.1 agc
159 1.1 agc
160 1.1 agc /*
161 1.1 agc * create_target:
162 1.1 agc * Create a target structure and initialize it.
163 1.1 agc *
164 1.1 agc * Parameter:
165 1.1 agc * name The target name
166 1.1 agc *
167 1.1 agc * Returns: Pointer to target structure, NULL if allocation failed.
168 1.1 agc */
169 1.1 agc
170 1.3 agc static target_t *
171 1.1 agc create_target(uint8_t * name)
172 1.1 agc {
173 1.1 agc target_t *target;
174 1.1 agc
175 1.6 mlelstv DEB(9, ("Create Target %s", name));
176 1.1 agc
177 1.1 agc if ((target = calloc(1, sizeof(*target))) == NULL) {
178 1.6 mlelstv DEBOUT(("Out of memory in create_target!"));
179 1.1 agc return NULL;
180 1.1 agc }
181 1.1 agc
182 1.1 agc TAILQ_INIT(&target->group_list);
183 1.1 agc
184 1.1 agc for (portarget_id++;
185 1.1 agc !portarget_id ||
186 1.1 agc find_portal_id(portarget_id) != NULL ||
187 1.1 agc find_target_id(TARGET_LIST, portarget_id) != NULL;
188 1.1 agc portarget_id++) {
189 1.1 agc }
190 1.1 agc
191 1.1 agc target->entry.sid.id = portarget_id;
192 1.1 agc strlcpy((char *)target->TargetName, (char *)name, sizeof(target->TargetName));
193 1.1 agc
194 1.1 agc return target;
195 1.1 agc }
196 1.1 agc
197 1.1 agc
198 1.1 agc /*
199 1.1 agc * delete_target:
200 1.1 agc * Delete a target entry after unlinking it from its lists.
201 1.1 agc * Also deletes all portals associated with the target.
202 1.1 agc *
203 1.1 agc * Parameter:
204 1.1 agc * target the pointer to the target
205 1.1 agc */
206 1.1 agc
207 1.3 agc static void
208 1.1 agc delete_target(target_t * target)
209 1.1 agc {
210 1.1 agc portal_group_t *cgroup;
211 1.1 agc portal_t *curr = NULL;
212 1.1 agc
213 1.1 agc /* First delete all portals in all portal groups. */
214 1.1 agc /* (this will also delete the groups) */
215 1.1 agc while (target->num_groups) {
216 1.1 agc cgroup = TAILQ_FIRST(&target->group_list);
217 1.1 agc while (cgroup && cgroup->num_portals) {
218 1.1 agc curr = TAILQ_FIRST(&cgroup->portals);
219 1.1 agc if (curr)
220 1.1 agc delete_portal(curr, FALSE);
221 1.1 agc }
222 1.1 agc }
223 1.1 agc
224 1.1 agc /*Now delete the target itself */
225 1.1 agc TAILQ_REMOVE(&list[TARGET_LIST].list, &target->entry, link);
226 1.1 agc list[TARGET_LIST].num_entries--;
227 1.1 agc free(target);
228 1.1 agc }
229 1.1 agc
230 1.1 agc
231 1.1 agc /*
232 1.1 agc * create_send_target:
233 1.1 agc * Create a send_target structure and initialize it.
234 1.1 agc *
235 1.1 agc * Parameter:
236 1.1 agc * name The target name
237 1.1 agc * addr The portal address
238 1.1 agc *
239 1.1 agc * Returns: Pointer to structure, NULL if allocation failed.
240 1.1 agc */
241 1.1 agc
242 1.3 agc static target_t *
243 1.1 agc create_send_target(uint8_t * name, iscsi_portal_address_t * addr)
244 1.1 agc {
245 1.1 agc send_target_t *target;
246 1.1 agc
247 1.6 mlelstv DEB(9, ("Create Send Target %s", name));
248 1.1 agc
249 1.1 agc if ((target = calloc(1, sizeof(*target))) == NULL)
250 1.1 agc return NULL;
251 1.1 agc
252 1.1 agc for (send_target_id++;
253 1.1 agc !send_target_id
254 1.1 agc || find_target_id(SEND_TARGETS_LIST, send_target_id) != NULL;)
255 1.1 agc send_target_id++;
256 1.1 agc
257 1.1 agc target->entry.sid.id = send_target_id;
258 1.1 agc strlcpy((char *)target->TargetName, (char *)name, sizeof(target->TargetName));
259 1.1 agc target->addr = *addr;
260 1.1 agc target->num_groups = 1;
261 1.1 agc target->num_portals = 1;
262 1.1 agc
263 1.2 christos return (target_t *)(void *)target;
264 1.1 agc }
265 1.1 agc
266 1.1 agc /*
267 1.1 agc * delete_send_target:
268 1.1 agc * Delete a send_target entry after unlinking it from its lists.
269 1.1 agc *
270 1.1 agc * Parameter:
271 1.1 agc * send_target the pointer to the send_target
272 1.1 agc */
273 1.1 agc
274 1.3 agc static void
275 1.1 agc delete_send_target(send_target_t * send_target)
276 1.1 agc {
277 1.1 agc generic_entry_t *curr;
278 1.1 agc uint32_t id;
279 1.1 agc
280 1.1 agc id = send_target->entry.sid.id;
281 1.1 agc
282 1.1 agc TAILQ_FOREACH(curr, &list[PORTAL_LIST].list, link) {
283 1.2 christos portal_t *p = (void *)curr;
284 1.2 christos if (p->portaltype == PORTAL_TYPE_SENDTARGET &&
285 1.2 christos p->discoveryid == id)
286 1.2 christos p->discoveryid = 0; /* mark deleted */
287 1.1 agc }
288 1.1 agc
289 1.1 agc TAILQ_REMOVE(&list[SEND_TARGETS_LIST].list, &send_target->entry, link);
290 1.1 agc list[SEND_TARGETS_LIST].num_entries--;
291 1.1 agc free(send_target);
292 1.1 agc }
293 1.1 agc
294 1.1 agc
295 1.1 agc
296 1.1 agc /*
297 1.1 agc * add_target:
298 1.1 agc * Handle ADD_TARGET request: Create a target or send_target and its
299 1.1 agc * associated portals.
300 1.1 agc * This routine allows the same target to be defined more than once,
301 1.1 agc * adding any missing data (for example additional portals).
302 1.1 agc *
303 1.1 agc * Parameter:
304 1.1 agc * par The request parameters.
305 1.1 agc * prsp Pointer to address of response buffer.
306 1.1 agc * prsp_temp Will be set to TRUE if buffer was allocated, FALSE
307 1.1 agc * for static buffer.
308 1.1 agc */
309 1.1 agc
310 1.1 agc
311 1.1 agc void
312 1.1 agc add_target(iscsid_add_target_req_t *par, iscsid_response_t **prsp,
313 1.1 agc int *prsp_temp)
314 1.1 agc {
315 1.1 agc iscsid_add_target_rsp_t *res;
316 1.1 agc iscsid_response_t *rsp = *prsp;
317 1.1 agc target_t *target, *tn;
318 1.1 agc portal_t *portal;
319 1.1 agc int i, num;
320 1.1 agc
321 1.6 mlelstv DEB(9, ("Add Target, name %s, num_portals %d",
322 1.1 agc par->TargetName, par->num_portals));
323 1.1 agc
324 1.1 agc if (par->list_kind == SEND_TARGETS_LIST && par->num_portals != 1) {
325 1.1 agc rsp->status = ISCSID_STATUS_PARAMETER_INVALID;
326 1.1 agc return;
327 1.1 agc }
328 1.1 agc /* check to see if the target already exists */
329 1.1 agc if ((par->TargetName[0] &&
330 1.1 agc (target = find_TargetName(par->list_kind, par->TargetName)) != NULL) ||
331 1.1 agc (par->list_kind == SEND_TARGETS_LIST &&
332 1.2 christos (target = (target_t *)(void *)
333 1.1 agc find_send_target_by_addr(&par->portal[0])) != NULL)) {
334 1.1 agc num = target->num_portals;
335 1.1 agc
336 1.1 agc /* symbolic name? */
337 1.1 agc if (par->sym_name[0]) {
338 1.1 agc /* already named? rename if OK */
339 1.1 agc tn = find_target_symname(par->list_kind, par->sym_name);
340 1.1 agc if (tn && tn != target) {
341 1.1 agc rsp->status = ISCSID_STATUS_DUPLICATE_NAME;
342 1.1 agc return;
343 1.1 agc }
344 1.1 agc strlcpy((char *)target->entry.sid.name, (char *)par->sym_name, sizeof(target->entry.sid.name));
345 1.1 agc }
346 1.1 agc } else {
347 1.1 agc if (par->sym_name[0] &&
348 1.1 agc (find_target_symname(par->list_kind, par->sym_name) ||
349 1.1 agc find_portal_name(par->sym_name))) {
350 1.1 agc rsp->status = ISCSID_STATUS_DUPLICATE_NAME;
351 1.1 agc return;
352 1.1 agc }
353 1.1 agc
354 1.1 agc if (par->list_kind == SEND_TARGETS_LIST)
355 1.1 agc target = create_send_target(par->TargetName, &par->portal[0]);
356 1.1 agc else
357 1.1 agc target = create_target(par->TargetName);
358 1.1 agc
359 1.1 agc if (target == NULL) {
360 1.1 agc rsp->status = ISCSID_STATUS_NO_RESOURCES;
361 1.1 agc return;
362 1.1 agc }
363 1.1 agc num = 0;
364 1.1 agc strlcpy((char *)target->entry.sid.name, (char *)par->sym_name,
365 1.1 agc sizeof(target->entry.sid.name));
366 1.1 agc }
367 1.1 agc
368 1.1 agc rsp = make_rsp(sizeof(*res) + (par->num_portals * sizeof(uint32_t)),
369 1.1 agc prsp, prsp_temp);
370 1.1 agc if (rsp == NULL)
371 1.1 agc return;
372 1.1 agc
373 1.2 christos res = (iscsid_add_target_rsp_t *)(void *)rsp->parameter;
374 1.1 agc res->target_id = target->entry.sid.id;
375 1.1 agc
376 1.1 agc /* link into target list */
377 1.1 agc if (!num) {
378 1.1 agc TAILQ_INSERT_TAIL(&list[par->list_kind].list, &target->entry,
379 1.1 agc link);
380 1.1 agc list[par->list_kind].num_entries++;
381 1.1 agc }
382 1.1 agc
383 1.1 agc /*
384 1.1 agc Add the given portals. Note that create_portal also checks for
385 1.1 agc duplicate entries, and returns the pointer to the existing entry
386 1.1 agc if the request is a duplicate.
387 1.1 agc */
388 1.1 agc
389 1.1 agc if (par->list_kind == SEND_TARGETS_LIST) {
390 1.1 agc res->portal_id[0] = target->entry.sid.id;
391 1.1 agc res->num_portals = 1;
392 1.1 agc } else {
393 1.1 agc for (i = 0; i < (int)par->num_portals; i++) {
394 1.1 agc portal = create_portal(target, &par->portal[i],
395 1.1 agc PORTAL_TYPE_STATIC,
396 1.1 agc target->entry.sid.id);
397 1.1 agc if (portal == NULL) {
398 1.1 agc rsp->status = ISCSID_STATUS_NO_RESOURCES;
399 1.1 agc break;
400 1.1 agc }
401 1.1 agc res->portal_id[i] = portal->entry.sid.id;
402 1.1 agc }
403 1.1 agc res->num_portals = i;
404 1.1 agc }
405 1.1 agc
406 1.6 mlelstv DEB(9, ("AddTarget returns"));
407 1.1 agc }
408 1.1 agc
409 1.1 agc
410 1.1 agc /*
411 1.1 agc * add_discovered_target:
412 1.1 agc * Check whether the given target and portal already exist.
413 1.1 agc * If not, add them.
414 1.1 agc *
415 1.1 agc * Parameter:
416 1.1 agc * TargetName
417 1.1 agc * portal
418 1.1 agc * dtype = type of portal added: PORTAL_TYPE_SENDTARGET or
419 1.1 agc * PORTAL_TYPE_ISNS
420 1.1 agc * did = ID of SendTargets or iSNS for which portal was discovered
421 1.1 agc *
422 1.1 agc * Returns: Pointer to created target, NULL on error (out of memory)
423 1.1 agc * Always sets portaltype to dtype even if portal already exists
424 1.1 agc * (used for refreshing to mark portals that we find)
425 1.1 agc */
426 1.1 agc
427 1.1 agc target_t *
428 1.1 agc add_discovered_target(uint8_t * TargetName, iscsi_portal_address_t * addr,
429 1.1 agc iscsi_portal_types_t dtype, uint32_t did)
430 1.1 agc {
431 1.1 agc target_t *target;
432 1.1 agc portal_t *portal;
433 1.1 agc
434 1.6 mlelstv DEB(9, ("Add Discovered Target, name %s, addr %s",
435 1.1 agc TargetName, addr->address));
436 1.1 agc
437 1.1 agc if ((target = find_TargetName(TARGET_LIST, TargetName)) == NULL) {
438 1.1 agc if ((target = create_target(TargetName)) == NULL) {
439 1.1 agc return NULL;
440 1.1 agc }
441 1.1 agc portal = create_portal(target, addr, dtype, did);
442 1.1 agc if (portal == NULL) {
443 1.1 agc free(target);
444 1.1 agc return NULL;
445 1.1 agc }
446 1.1 agc TAILQ_INSERT_TAIL(&list[TARGET_LIST].list, &target->entry, link);
447 1.1 agc list[TARGET_LIST].num_entries++;
448 1.1 agc } else if ((portal = create_portal(target, addr, dtype, did)) == NULL) {
449 1.1 agc return NULL;
450 1.1 agc }
451 1.1 agc portal->portaltype = dtype;
452 1.1 agc
453 1.1 agc return target;
454 1.1 agc }
455 1.1 agc
456 1.1 agc
457 1.1 agc /*
458 1.1 agc * set_target_options:
459 1.1 agc * Handle SET_TARGET_OPTIONS request: Copy the given options into the
460 1.1 agc * target structure.
461 1.1 agc *
462 1.1 agc * Parameter:
463 1.1 agc * par The request parameters.
464 1.1 agc *
465 1.1 agc * Returns: status
466 1.1 agc */
467 1.1 agc
468 1.1 agc uint32_t
469 1.1 agc set_target_options(iscsid_get_set_target_options_t * par)
470 1.1 agc {
471 1.1 agc target_t *target;
472 1.1 agc
473 1.1 agc if ((target = find_target(par->list_kind, &par->target_id)) == NULL)
474 1.1 agc return ISCSID_STATUS_INVALID_TARGET_ID;
475 1.1 agc
476 1.1 agc target->options = *par;
477 1.1 agc
478 1.1 agc return ISCSID_STATUS_SUCCESS;
479 1.1 agc }
480 1.1 agc
481 1.1 agc
482 1.1 agc /*
483 1.1 agc * set_target_auth:
484 1.1 agc * Handle SET_TARGET_AUTHENTICATION request: Copy the given options into the
485 1.1 agc * target structure.
486 1.1 agc *
487 1.1 agc * Parameter:
488 1.1 agc * par The request parameters.
489 1.1 agc *
490 1.1 agc * Returns: status
491 1.1 agc */
492 1.1 agc
493 1.1 agc uint32_t
494 1.1 agc set_target_auth(iscsid_set_target_authentication_req_t * par)
495 1.1 agc {
496 1.1 agc target_t *target;
497 1.1 agc
498 1.1 agc if ((target = find_target(par->list_kind, &par->target_id)) == NULL) {
499 1.1 agc return ISCSID_STATUS_INVALID_TARGET_ID;
500 1.1 agc }
501 1.1 agc target->auth = *par;
502 1.1 agc
503 1.1 agc return ISCSID_STATUS_SUCCESS;
504 1.1 agc }
505 1.1 agc
506 1.1 agc
507 1.1 agc /*
508 1.1 agc * get_target_info:
509 1.1 agc * Handle GET_TARGET_INFO request: Return information about the given
510 1.1 agc * target and its portals. If a portal ID is given, returns only the
511 1.1 agc * target info and the ID of this portal.
512 1.1 agc *
513 1.1 agc * Parameter:
514 1.1 agc * par The request parameters.
515 1.1 agc * prsp Pointer to address of response buffer.
516 1.1 agc * prsp_temp Will be set to TRUE if buffer was allocated, FALSE
517 1.1 agc * for static buffer.
518 1.1 agc */
519 1.1 agc
520 1.1 agc void
521 1.1 agc get_target_info(iscsid_list_id_t *par, iscsid_response_t **prsp, int *prsp_temp)
522 1.1 agc {
523 1.1 agc iscsid_get_target_rsp_t *res;
524 1.1 agc iscsid_response_t *rsp = *prsp;
525 1.1 agc uint32_t *idp;
526 1.1 agc target_t *target;
527 1.1 agc portal_group_t *cgroup;
528 1.1 agc portal_t *curr = NULL;
529 1.1 agc int num = 1;
530 1.1 agc
531 1.6 mlelstv DEB(10, ("get_target_info, id %d", par->id.id));
532 1.1 agc
533 1.1 agc if ((target = find_target(par->list_kind, &par->id)) == NULL) {
534 1.1 agc if (par->list_kind == SEND_TARGETS_LIST ||
535 1.1 agc (curr = find_portal(&par->id)) == NULL) {
536 1.1 agc rsp->status = ISCSID_STATUS_INVALID_TARGET_ID;
537 1.1 agc return;
538 1.1 agc }
539 1.1 agc target = curr->target;
540 1.1 agc } else if (par->list_kind != SEND_TARGETS_LIST) {
541 1.1 agc num = target->num_portals;
542 1.1 agc }
543 1.1 agc rsp = make_rsp(sizeof(*res) + (num - 1) * sizeof(uint32_t),
544 1.1 agc prsp, prsp_temp);
545 1.1 agc if (rsp == NULL)
546 1.1 agc return;
547 1.1 agc
548 1.2 christos res = (iscsid_get_target_rsp_t *)(void *)rsp->parameter;
549 1.1 agc res->target_id = target->entry.sid;
550 1.1 agc strlcpy((char *)res->TargetName, (char *)target->TargetName,
551 1.1 agc sizeof(res->TargetName));
552 1.1 agc strlcpy((char *)res->TargetAlias, (char *)target->TargetAlias,
553 1.1 agc sizeof(res->TargetAlias));
554 1.1 agc
555 1.1 agc res->num_portals = num;
556 1.1 agc idp = res->portal;
557 1.1 agc
558 1.1 agc if (curr) {
559 1.1 agc *idp = curr->entry.sid.id;
560 1.1 agc } else if (par->list_kind != SEND_TARGETS_LIST) {
561 1.1 agc TAILQ_FOREACH(cgroup, &target->group_list, groups)
562 1.1 agc TAILQ_FOREACH(curr, &cgroup->portals, group_list)
563 1.1 agc * idp++ = curr->entry.sid.id;
564 1.1 agc } else
565 1.1 agc *idp = target->entry.sid.id;
566 1.1 agc }
567 1.1 agc
568 1.1 agc
569 1.1 agc /*
570 1.1 agc * add_portal:
571 1.1 agc * Handle ADD_PORTAL request: Add a portal to an existing target.
572 1.1 agc *
573 1.1 agc * Parameter:
574 1.1 agc * par The request parameters.
575 1.1 agc * prsp Pointer to address of response buffer.
576 1.1 agc * prsp_temp Will be set to TRUE if buffer was allocated, FALSE
577 1.1 agc * for static buffer.
578 1.1 agc */
579 1.1 agc
580 1.1 agc
581 1.1 agc void
582 1.1 agc add_portal(iscsid_add_portal_req_t *par, iscsid_response_t **prsp,
583 1.1 agc int *prsp_temp)
584 1.1 agc {
585 1.1 agc iscsid_add_portal_rsp_t *res;
586 1.1 agc iscsid_response_t *rsp = *prsp;
587 1.1 agc target_t *target;
588 1.1 agc portal_t *portal;
589 1.1 agc
590 1.6 mlelstv DEB(9, ("Add portal: target %d (%s), symname %s, addr %s",
591 1.1 agc par->target_id.id, par->target_id.name,
592 1.1 agc par->sym_name, par->portal.address));
593 1.1 agc
594 1.1 agc if ((target = find_target(TARGET_LIST, &par->target_id)) == NULL) {
595 1.1 agc rsp->status = ISCSID_STATUS_INVALID_TARGET_ID;
596 1.1 agc return;
597 1.1 agc }
598 1.1 agc
599 1.1 agc if (par->sym_name[0] &&
600 1.1 agc (find_target_symname(TARGET_LIST, par->sym_name) ||
601 1.1 agc find_portal_name(par->sym_name))) {
602 1.1 agc rsp->status = ISCSID_STATUS_DUPLICATE_NAME;
603 1.1 agc return;
604 1.1 agc }
605 1.1 agc
606 1.1 agc portal = create_portal(target, &par->portal, PORTAL_TYPE_STATIC,
607 1.1 agc target->entry.sid.id);
608 1.1 agc if (portal == NULL) {
609 1.1 agc rsp->status = ISCSID_STATUS_NO_RESOURCES;
610 1.1 agc return;
611 1.1 agc }
612 1.1 agc
613 1.1 agc if (par->sym_name[0]) {
614 1.1 agc strlcpy((char *)portal->entry.sid.name, (char *)par->sym_name,
615 1.1 agc sizeof(portal->entry.sid.name));
616 1.1 agc }
617 1.1 agc portal->options = par->options;
618 1.1 agc
619 1.1 agc rsp = make_rsp(sizeof(*res), prsp, prsp_temp);
620 1.1 agc if (rsp == NULL)
621 1.1 agc return;
622 1.2 christos #if 0 /*XXX: christos res is uninitialized here?? */
623 1.1 agc res->target_id = target->entry.sid;
624 1.1 agc res->portal_id = portal->entry.sid;
625 1.2 christos #endif
626 1.1 agc
627 1.6 mlelstv DEB(9, ("AddPortal success (id %d)", portal->entry.sid.id));
628 1.1 agc }
629 1.1 agc
630 1.1 agc
631 1.1 agc /*
632 1.1 agc * get_portal_info:
633 1.1 agc * Handle GET_PORTAL_INFO request: Return information about the given
634 1.1 agc * portal.
635 1.1 agc *
636 1.1 agc * Parameter:
637 1.1 agc * par The request parameters.
638 1.1 agc * prsp Pointer to address of response buffer.
639 1.1 agc * prsp_temp Will be set to TRUE if buffer was allocated, FALSE
640 1.1 agc * for static buffer.
641 1.1 agc */
642 1.1 agc
643 1.1 agc void
644 1.1 agc get_portal_info(iscsid_list_id_t *par, iscsid_response_t **prsp, int *prsp_temp)
645 1.1 agc {
646 1.1 agc iscsid_get_portal_rsp_t *res;
647 1.1 agc iscsid_response_t *rsp = *prsp;
648 1.1 agc portal_t *portal = NULL;
649 1.1 agc send_target_t *starg = NULL;
650 1.1 agc int err;
651 1.1 agc
652 1.6 mlelstv DEB(10, ("get_portal_info, id %d", par->id.id));
653 1.1 agc
654 1.1 agc if (par->list_kind == SEND_TARGETS_LIST)
655 1.2 christos err = ((starg = (send_target_t *)(void *)find_target(par->list_kind,
656 1.1 agc &par->id)) == NULL);
657 1.1 agc else
658 1.1 agc err = ((portal = find_portal(&par->id)) == NULL);
659 1.1 agc
660 1.1 agc if (err) {
661 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PORTAL_ID;
662 1.1 agc return;
663 1.1 agc }
664 1.1 agc
665 1.1 agc rsp = make_rsp(sizeof(*res), prsp, prsp_temp);
666 1.1 agc if (rsp == NULL)
667 1.1 agc return;
668 1.1 agc
669 1.2 christos res = (iscsid_get_portal_rsp_t *)(void *)rsp->parameter;
670 1.1 agc if (par->list_kind == SEND_TARGETS_LIST) {
671 1.1 agc res->target_id = starg->entry.sid;
672 1.1 agc res->portal_id = starg->entry.sid;
673 1.1 agc res->portal = starg->addr;
674 1.1 agc } else {
675 1.1 agc res->target_id = portal->target->entry.sid;
676 1.1 agc res->portal_id = portal->entry.sid;
677 1.1 agc res->portal = portal->addr;
678 1.1 agc }
679 1.1 agc }
680 1.1 agc
681 1.1 agc /*
682 1.1 agc * remove_target:
683 1.1 agc * Handle REMOVE_TARGET request: Removes a target, target portal,
684 1.1 agc * or Send-Targets portal from its respective list.
685 1.1 agc * Removing a target will remove all associated portals.
686 1.1 agc *
687 1.1 agc * Parameter:
688 1.1 agc * par The request parameters = iscsid_list_id_t
689 1.1 agc * containing the target ID.
690 1.1 agc *
691 1.1 agc * Returns: status
692 1.1 agc */
693 1.1 agc
694 1.1 agc uint32_t
695 1.1 agc remove_target(iscsid_list_id_t * par)
696 1.1 agc {
697 1.1 agc target_t *target = NULL;
698 1.1 agc portal_t *portal = NULL;
699 1.1 agc send_target_t *starg = NULL;
700 1.1 agc int err;
701 1.1 agc
702 1.6 mlelstv DEB(9, ("remove_target, id %d", par->id.id));
703 1.1 agc
704 1.1 agc if (par->list_kind == SEND_TARGETS_LIST) {
705 1.2 christos err = ((starg = (send_target_t *)(void *)find_target(par->list_kind,
706 1.1 agc &par->id)) == NULL);
707 1.1 agc if (!err) {
708 1.1 agc delete_send_target(starg);
709 1.1 agc }
710 1.1 agc } else if (par->list_kind == PORTAL_LIST) {
711 1.1 agc err = ((portal = find_portal(&par->id)) == NULL);
712 1.1 agc if (!err) {
713 1.1 agc delete_portal(portal, FALSE);
714 1.1 agc }
715 1.1 agc } else {
716 1.1 agc target = find_target(par->list_kind, &par->id);
717 1.1 agc err = (target == NULL);
718 1.1 agc if (!err) {
719 1.1 agc delete_target(target);
720 1.1 agc }
721 1.1 agc }
722 1.1 agc
723 1.1 agc return err ? ISCSID_STATUS_INVALID_PORTAL_ID : ISCSID_STATUS_SUCCESS;
724 1.1 agc }
725 1.1 agc
726 1.1 agc
727 1.1 agc
728 1.1 agc /*
729 1.1 agc * cl_get_address:
730 1.1 agc * Get an address specification that may include port and group tag.
731 1.1 agc *
732 1.1 agc * Parameter:
733 1.1 agc * portal The portal address
734 1.1 agc * str The parameter string to scan
735 1.1 agc *
736 1.1 agc * Returns: 0 on error, 1 if OK.
737 1.1 agc */
738 1.1 agc
739 1.3 agc static int
740 1.1 agc cl_get_address(iscsi_portal_address_t * portal, char *str)
741 1.1 agc {
742 1.1 agc char *sp, *sp2;
743 1.1 agc int val;
744 1.1 agc
745 1.1 agc /* is there a port? don't check inside square brackets (IPv6 addr) */
746 1.1 agc for (sp = str + 1, val = 0; *sp && (*sp != ':' || val); sp++) {
747 1.1 agc if (*sp == '[')
748 1.1 agc val = 1;
749 1.1 agc else if (*sp == ']')
750 1.1 agc val = 0;
751 1.1 agc }
752 1.1 agc
753 1.1 agc /* */
754 1.1 agc if (*sp) {
755 1.1 agc for (sp2 = sp + 1; *sp2 && *sp2 != ':'; sp2++);
756 1.1 agc /* if there's a second colon, assume it's an unbracketed IPv6
757 1.1 agc * address */
758 1.1 agc if (!*sp2) {
759 1.1 agc /* truncate source, that's the address */
760 1.1 agc *sp++ = '\0';
761 1.1 agc if (sscanf(sp, "%d", &val) != 1)
762 1.1 agc return 0;
763 1.1 agc if (val < 0 || val > 0xffff)
764 1.1 agc return 0;
765 1.1 agc portal->port = (uint16_t) val;
766 1.1 agc }
767 1.1 agc /* is there a group tag? */
768 1.1 agc for (; isdigit((unsigned char)*sp); sp++) {
769 1.1 agc }
770 1.1 agc if (*sp && *sp != ',')
771 1.1 agc return 0;
772 1.1 agc } else
773 1.1 agc for (sp = str + 1; *sp && *sp != ','; sp++);
774 1.1 agc
775 1.1 agc if (*sp) {
776 1.1 agc if (sscanf(sp + 1, "%d", &val) != 1)
777 1.1 agc return 0;
778 1.1 agc if (val < 0 || val > 0xffff)
779 1.1 agc return 0;
780 1.1 agc portal->group_tag = (uint16_t) val;
781 1.1 agc /* truncate source, that's the address */
782 1.1 agc *sp = '\0';
783 1.1 agc }
784 1.1 agc /* only check length, don't verify correct format (too many
785 1.1 agc * possibilities) */
786 1.1 agc if (strlen(str) >= sizeof(portal->address))
787 1.1 agc return 0;
788 1.1 agc
789 1.1 agc strlcpy((char *)portal->address, str, sizeof(portal->address));
790 1.1 agc
791 1.1 agc return 1;
792 1.1 agc }
793 1.1 agc
794 1.1 agc /*
795 1.1 agc * refresh_send_target:
796 1.1 agc * Handle REFRESH_TARGETS request for a Send Target
797 1.1 agc *
798 1.1 agc * Parameter:
799 1.1 agc * id The send target ID.
800 1.1 agc *
801 1.1 agc * Returns: status
802 1.1 agc */
803 1.1 agc
804 1.1 agc
805 1.3 agc static uint32_t
806 1.1 agc refresh_send_target(uint32_t id)
807 1.1 agc {
808 1.1 agc uint8_t *response_buffer = NULL;
809 1.1 agc uint32_t response_size;
810 1.1 agc uint32_t ret;
811 1.1 agc uint8_t *TargetName;
812 1.1 agc iscsi_portal_address_t addr;
813 1.1 agc uint8_t *tp, *sp;
814 1.1 agc generic_entry_t *curr;
815 1.1 agc generic_entry_t *next;
816 1.1 agc send_target_t *sendtarg;
817 1.1 agc int rc;
818 1.1 agc
819 1.1 agc /*
820 1.1 agc * Go through our list of portals and mark each one
821 1.1 agc * belonging to the current sendtargets group to refreshing
822 1.1 agc * This mark is used afterwards to remove any portals that
823 1.1 agc * were not refreshed (because the mark gets reset for portals
824 1.1 agc * that are refreshed).
825 1.1 agc */
826 1.1 agc
827 1.1 agc TAILQ_FOREACH(curr, &list[PORTAL_LIST].list, link) {
828 1.2 christos portal_t *p = (void *)curr;
829 1.2 christos if (p->portaltype == PORTAL_TYPE_SENDTARGET &&
830 1.2 christos p->discoveryid == id) {
831 1.2 christos p->portaltype = PORTAL_TYPE_REFRESHING;
832 1.1 agc }
833 1.1 agc }
834 1.1 agc
835 1.1 agc if ((ret = send_targets(id, &response_buffer, &response_size)) == 0) {
836 1.1 agc /*
837 1.1 agc * Parse the response target list
838 1.1 agc * The SendTargets response in response_buffer is a list of
839 1.1 agc * target strings. Each target string consists of a TargetName
840 1.1 agc * string, followed by 0 or more TargetAddress strings:
841 1.1 agc *
842 1.1 agc * TargetName=<target-name>
843 1.1 agc * TargetAddress=<hostname-or-ip>[:<tcp-port>],
844 1.1 agc * <portal-group-tag>
845 1.1 agc * The entire list is terminated by a null (after
846 1.1 agc * response_size bytes) (this terminating NULL was placed
847 1.1 agc * there by send_targets routine.)
848 1.1 agc */
849 1.1 agc
850 1.1 agc tp = response_buffer;
851 1.1 agc while (*tp) {
852 1.1 agc if (strncmp((char *)tp, "TargetName=", 11) != 0) {
853 1.6 mlelstv DEBOUT(("Response not TargetName <%s>", tp));
854 1.1 agc break;
855 1.1 agc }
856 1.1 agc tp += 11;
857 1.1 agc TargetName = tp; /*Point to target name */
858 1.1 agc while (*tp++) {
859 1.1 agc }
860 1.1 agc rc = -1; /* Mark no address found yet */
861 1.1 agc
862 1.1 agc /*Now process any "TargetAddress" entries following */
863 1.1 agc while (*tp && strncmp((char *)tp, "TargetAddress=", 14) == 0) {
864 1.1 agc tp += 14;
865 1.1 agc sp = tp; /* save start of address */
866 1.1 agc while (*tp++) {
867 1.1 agc }
868 1.1 agc /*Get the target address */
869 1.1 agc rc = cl_get_address(&addr, (char *)sp);
870 1.1 agc if (rc) {
871 1.1 agc add_discovered_target(TargetName,
872 1.1 agc &addr, PORTAL_TYPE_SENDTARGET,
873 1.1 agc id);
874 1.1 agc } else {
875 1.6 mlelstv DEBOUT(("Syntax error in returned target address <%s>", sp));
876 1.1 agc break;
877 1.1 agc }
878 1.1 agc }
879 1.1 agc
880 1.1 agc if (rc == -1) {
881 1.1 agc /* There are no TargetAddress entries
882 1.1 agc * associated with TargetName. This means the
883 1.1 agc * sendtarget address is used. */
884 1.1 agc sendtarg = find_send_target_id(id);
885 1.1 agc if (sendtarg != NULL) {
886 1.1 agc add_discovered_target(TargetName,
887 1.1 agc &sendtarg->addr,
888 1.1 agc PORTAL_TYPE_SENDTARGET, id);
889 1.1 agc }
890 1.1 agc }
891 1.1 agc } /* end of while */
892 1.1 agc }
893 1.1 agc /*
894 1.1 agc * Go through our list of portals and look for ones
895 1.1 agc * that are still marked for refreshing.
896 1.1 agc * These are ones that are no longer there and should be removed.
897 1.1 agc */
898 1.1 agc
899 1.1 agc for (curr = TAILQ_FIRST(&list[PORTAL_LIST].list); curr != NULL;
900 1.1 agc curr = next) {
901 1.2 christos portal_t *p = (void *)curr;
902 1.1 agc next = TAILQ_NEXT(curr, link);
903 1.2 christos if (p->portaltype == PORTAL_TYPE_REFRESHING)
904 1.2 christos delete_portal(p, TRUE);
905 1.1 agc }
906 1.1 agc
907 1.1 agc /*
908 1.1 agc * Clean up
909 1.1 agc */
910 1.1 agc
911 1.1 agc if (response_buffer != NULL)
912 1.1 agc free(response_buffer);
913 1.1 agc
914 1.1 agc return ret;
915 1.1 agc }
916 1.1 agc
917 1.1 agc
918 1.1 agc /*
919 1.1 agc * cleanup_send_target_orphans:
920 1.1 agc * Delete portals that were discovered through a now deleted send target.
921 1.1 agc */
922 1.1 agc
923 1.1 agc
924 1.3 agc static void
925 1.1 agc cleanup_orphans(iscsi_portal_types_t type)
926 1.1 agc {
927 1.1 agc generic_entry_t *curr;
928 1.1 agc generic_entry_t *next;
929 1.1 agc
930 1.1 agc /*
931 1.1 agc * Go through the list of portals and look for ones marked with a zero
932 1.1 agc * discovery ID, those are associated with send targets that no
933 1.1 agc * longer exist.
934 1.1 agc */
935 1.1 agc
936 1.1 agc for (curr = TAILQ_FIRST(&list[PORTAL_LIST].list); curr != NULL;
937 1.1 agc curr = next) {
938 1.2 christos portal_t *p = (void *)curr;
939 1.1 agc next = TAILQ_NEXT(curr, link);
940 1.2 christos if (p->portaltype == type && p->discoveryid == 0) {
941 1.2 christos delete_portal(p, TRUE);
942 1.1 agc }
943 1.1 agc }
944 1.1 agc }
945 1.1 agc
946 1.1 agc
947 1.1 agc /*
948 1.1 agc * refresh_targets:
949 1.1 agc * Handle REFRESH_TARGETS request:
950 1.1 agc * Refreshes the list of targets discovered via SendTargets or iSNS
951 1.1 agc *
952 1.1 agc * Parameter:
953 1.1 agc * The request parameter = iscsid_refresh_targets_req_t containing:
954 1.1 agc * iscsid_list_kind_t kind; Kind:
955 1.1 agc * SEND_TARGETS_LIST
956 1.1 agc * ISNS_LIST
957 1.1 agc * uint32_t num_ids; # of targets in list
958 1.1 agc * uint32_t id [1]; List of targets
959 1.1 agc *
960 1.1 agc * Returns: status
961 1.1 agc */
962 1.1 agc
963 1.1 agc uint32_t
964 1.1 agc refresh_targets(iscsid_refresh_req_t * par)
965 1.1 agc {
966 1.1 agc uint32_t t;
967 1.1 agc uint32_t rc, retval;
968 1.1 agc generic_entry_t *curr;
969 1.1 agc
970 1.1 agc retval = ISCSID_STATUS_NO_TARGETS_FOUND;
971 1.1 agc
972 1.1 agc switch (par->kind) {
973 1.1 agc case TARGET_LIST:
974 1.1 agc /*
975 1.1 agc * Refreshing for a specific target makes no sense if it's
976 1.7 andvar * static. Maybe implement it for dynamically discovered
977 1.1 agc * targets? But then it's best done through the discovering
978 1.1 agc * instance, or we'll refresh much more than just the given
979 1.1 agc * target. And refreshing the whole list is iffy as well. So
980 1.1 agc * refuse this op on the target list for now.
981 1.1 agc */
982 1.1 agc break;
983 1.1 agc
984 1.1 agc case SEND_TARGETS_LIST:
985 1.6 mlelstv DEB(9, ("Refresh Send Targets List - num_ids = %d",
986 1.1 agc par->num_ids));
987 1.1 agc if (par->num_ids) {
988 1.1 agc /* Target ids are specified */
989 1.1 agc for (t = 0; t < par->num_ids; t++) {
990 1.1 agc rc = refresh_send_target(par->id[t]);
991 1.1 agc if (rc == 0) {
992 1.1 agc retval = ISCSID_STATUS_SUCCESS;
993 1.1 agc }
994 1.1 agc }
995 1.1 agc } else {
996 1.1 agc cleanup_orphans(PORTAL_TYPE_SENDTARGET);
997 1.1 agc
998 1.1 agc /* No target ids specified - refresh all. */
999 1.1 agc TAILQ_FOREACH(curr, &list[SEND_TARGETS_LIST].list, link)
1000 1.1 agc if ((rc = refresh_send_target(curr->sid.id)) == 0)
1001 1.1 agc retval = ISCSID_STATUS_SUCCESS;
1002 1.1 agc }
1003 1.1 agc return retval;
1004 1.1 agc
1005 1.1 agc #ifndef ISCSI_MINIMAL
1006 1.1 agc case ISNS_LIST:
1007 1.6 mlelstv DEB(9, ("Refresh iSNS List - num_ids = %d", par->num_ids));
1008 1.1 agc if (par->num_ids) {
1009 1.1 agc /*Target ids are specified */
1010 1.1 agc for (t = 0; t < par->num_ids; t++)
1011 1.1 agc if ((rc = refresh_isns_server(par->id[t])) == 0)
1012 1.1 agc retval = ISCSI_STATUS_SUCCESS;
1013 1.1 agc } else {
1014 1.1 agc cleanup_orphans(PORTAL_TYPE_ISNS);
1015 1.1 agc
1016 1.1 agc /*No target ids specified - refresh all. */
1017 1.1 agc TAILQ_FOREACH(curr, &list[ISNS_LIST].list, link)
1018 1.1 agc if ((rc = refresh_isns_server(curr->sid.id)) == 0)
1019 1.1 agc retval = ISCSI_STATUS_SUCCESS;
1020 1.1 agc }
1021 1.1 agc return retval;
1022 1.1 agc #endif
1023 1.1 agc
1024 1.1 agc default:
1025 1.1 agc break;
1026 1.1 agc }
1027 1.1 agc
1028 1.1 agc return ISCSID_STATUS_PARAMETER_INVALID;
1029 1.1 agc }
1030