iscsid_targets.c revision 1.1 1 1.1 agc /* $NetBSD: iscsid_targets.c,v 1.1 2011/10/23 21:11:23 agc 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.1 agc STATIC uint32_t portarget_id = 0;
38 1.1 agc
39 1.1 agc /* counter for send_targets ID */
40 1.1 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.1 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.1 agc DEB(9, ("Create Portal addr %s port %d group %d\n",
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.1 agc DEBOUT(("Out of memory in create_portal!\n"));
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.1 agc DEBOUT(("Out of memory in create_portal!\n"));
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.1 agc DEB(9, ("create_portal returns %x\n", (int) 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.1 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.1 agc DEB(9, ("Create Target %s\n", name));
176 1.1 agc
177 1.1 agc if ((target = calloc(1, sizeof(*target))) == NULL) {
178 1.1 agc DEBOUT(("Out of memory in create_target!\n"));
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.1 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.1 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.1 agc DEB(9, ("Create Send Target %s\n", 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.1 agc return (target_t *) 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.1 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.1 agc if (((portal_t *) curr)->portaltype == PORTAL_TYPE_SENDTARGET &&
284 1.1 agc ((portal_t *) curr)->discoveryid == id)
285 1.1 agc ((portal_t *) curr)->discoveryid = 0; /* mark deleted */
286 1.1 agc }
287 1.1 agc
288 1.1 agc TAILQ_REMOVE(&list[SEND_TARGETS_LIST].list, &send_target->entry, link);
289 1.1 agc list[SEND_TARGETS_LIST].num_entries--;
290 1.1 agc free(send_target);
291 1.1 agc }
292 1.1 agc
293 1.1 agc
294 1.1 agc
295 1.1 agc /*
296 1.1 agc * add_target:
297 1.1 agc * Handle ADD_TARGET request: Create a target or send_target and its
298 1.1 agc * associated portals.
299 1.1 agc * This routine allows the same target to be defined more than once,
300 1.1 agc * adding any missing data (for example additional portals).
301 1.1 agc *
302 1.1 agc * Parameter:
303 1.1 agc * par The request parameters.
304 1.1 agc * prsp Pointer to address of response buffer.
305 1.1 agc * prsp_temp Will be set to TRUE if buffer was allocated, FALSE
306 1.1 agc * for static buffer.
307 1.1 agc */
308 1.1 agc
309 1.1 agc
310 1.1 agc void
311 1.1 agc add_target(iscsid_add_target_req_t *par, iscsid_response_t **prsp,
312 1.1 agc int *prsp_temp)
313 1.1 agc {
314 1.1 agc iscsid_add_target_rsp_t *res;
315 1.1 agc iscsid_response_t *rsp = *prsp;
316 1.1 agc target_t *target, *tn;
317 1.1 agc portal_t *portal;
318 1.1 agc int i, num;
319 1.1 agc
320 1.1 agc DEB(9, ("Add Target, name %s, num_portals %d\n",
321 1.1 agc par->TargetName, par->num_portals));
322 1.1 agc
323 1.1 agc if (par->list_kind == SEND_TARGETS_LIST && par->num_portals != 1) {
324 1.1 agc rsp->status = ISCSID_STATUS_PARAMETER_INVALID;
325 1.1 agc return;
326 1.1 agc }
327 1.1 agc /* check to see if the target already exists */
328 1.1 agc if ((par->TargetName[0] &&
329 1.1 agc (target = find_TargetName(par->list_kind, par->TargetName)) != NULL) ||
330 1.1 agc (par->list_kind == SEND_TARGETS_LIST &&
331 1.1 agc (target = (target_t *)
332 1.1 agc find_send_target_by_addr(&par->portal[0])) != NULL)) {
333 1.1 agc num = target->num_portals;
334 1.1 agc
335 1.1 agc /* symbolic name? */
336 1.1 agc if (par->sym_name[0]) {
337 1.1 agc /* already named? rename if OK */
338 1.1 agc tn = find_target_symname(par->list_kind, par->sym_name);
339 1.1 agc if (tn && tn != target) {
340 1.1 agc rsp->status = ISCSID_STATUS_DUPLICATE_NAME;
341 1.1 agc return;
342 1.1 agc }
343 1.1 agc strlcpy((char *)target->entry.sid.name, (char *)par->sym_name, sizeof(target->entry.sid.name));
344 1.1 agc }
345 1.1 agc } else {
346 1.1 agc if (par->sym_name[0] &&
347 1.1 agc (find_target_symname(par->list_kind, par->sym_name) ||
348 1.1 agc find_portal_name(par->sym_name))) {
349 1.1 agc rsp->status = ISCSID_STATUS_DUPLICATE_NAME;
350 1.1 agc return;
351 1.1 agc }
352 1.1 agc
353 1.1 agc if (par->list_kind == SEND_TARGETS_LIST)
354 1.1 agc target = create_send_target(par->TargetName, &par->portal[0]);
355 1.1 agc else
356 1.1 agc target = create_target(par->TargetName);
357 1.1 agc
358 1.1 agc if (target == NULL) {
359 1.1 agc rsp->status = ISCSID_STATUS_NO_RESOURCES;
360 1.1 agc return;
361 1.1 agc }
362 1.1 agc num = 0;
363 1.1 agc strlcpy((char *)target->entry.sid.name, (char *)par->sym_name,
364 1.1 agc sizeof(target->entry.sid.name));
365 1.1 agc }
366 1.1 agc
367 1.1 agc rsp = make_rsp(sizeof(*res) + (par->num_portals * sizeof(uint32_t)),
368 1.1 agc prsp, prsp_temp);
369 1.1 agc if (rsp == NULL)
370 1.1 agc return;
371 1.1 agc
372 1.1 agc res = (iscsid_add_target_rsp_t *) rsp->parameter;
373 1.1 agc res->target_id = target->entry.sid.id;
374 1.1 agc
375 1.1 agc /* link into target list */
376 1.1 agc if (!num) {
377 1.1 agc TAILQ_INSERT_TAIL(&list[par->list_kind].list, &target->entry,
378 1.1 agc link);
379 1.1 agc list[par->list_kind].num_entries++;
380 1.1 agc }
381 1.1 agc
382 1.1 agc /*
383 1.1 agc Add the given portals. Note that create_portal also checks for
384 1.1 agc duplicate entries, and returns the pointer to the existing entry
385 1.1 agc if the request is a duplicate.
386 1.1 agc */
387 1.1 agc
388 1.1 agc if (par->list_kind == SEND_TARGETS_LIST) {
389 1.1 agc res->portal_id[0] = target->entry.sid.id;
390 1.1 agc res->num_portals = 1;
391 1.1 agc } else {
392 1.1 agc for (i = 0; i < (int)par->num_portals; i++) {
393 1.1 agc portal = create_portal(target, &par->portal[i],
394 1.1 agc PORTAL_TYPE_STATIC,
395 1.1 agc target->entry.sid.id);
396 1.1 agc if (portal == NULL) {
397 1.1 agc rsp->status = ISCSID_STATUS_NO_RESOURCES;
398 1.1 agc break;
399 1.1 agc }
400 1.1 agc res->portal_id[i] = portal->entry.sid.id;
401 1.1 agc }
402 1.1 agc res->num_portals = i;
403 1.1 agc }
404 1.1 agc
405 1.1 agc DEB(9, ("AddTarget returns\n"));
406 1.1 agc }
407 1.1 agc
408 1.1 agc
409 1.1 agc /*
410 1.1 agc * add_discovered_target:
411 1.1 agc * Check whether the given target and portal already exist.
412 1.1 agc * If not, add them.
413 1.1 agc *
414 1.1 agc * Parameter:
415 1.1 agc * TargetName
416 1.1 agc * portal
417 1.1 agc * dtype = type of portal added: PORTAL_TYPE_SENDTARGET or
418 1.1 agc * PORTAL_TYPE_ISNS
419 1.1 agc * did = ID of SendTargets or iSNS for which portal was discovered
420 1.1 agc *
421 1.1 agc * Returns: Pointer to created target, NULL on error (out of memory)
422 1.1 agc * Always sets portaltype to dtype even if portal already exists
423 1.1 agc * (used for refreshing to mark portals that we find)
424 1.1 agc */
425 1.1 agc
426 1.1 agc target_t *
427 1.1 agc add_discovered_target(uint8_t * TargetName, iscsi_portal_address_t * addr,
428 1.1 agc iscsi_portal_types_t dtype, uint32_t did)
429 1.1 agc {
430 1.1 agc target_t *target;
431 1.1 agc portal_t *portal;
432 1.1 agc
433 1.1 agc DEB(9, ("Add Discovered Target, name %s, addr %s\n",
434 1.1 agc TargetName, addr->address));
435 1.1 agc
436 1.1 agc if ((target = find_TargetName(TARGET_LIST, TargetName)) == NULL) {
437 1.1 agc if ((target = create_target(TargetName)) == NULL) {
438 1.1 agc return NULL;
439 1.1 agc }
440 1.1 agc portal = create_portal(target, addr, dtype, did);
441 1.1 agc if (portal == NULL) {
442 1.1 agc free(target);
443 1.1 agc return NULL;
444 1.1 agc }
445 1.1 agc TAILQ_INSERT_TAIL(&list[TARGET_LIST].list, &target->entry, link);
446 1.1 agc list[TARGET_LIST].num_entries++;
447 1.1 agc } else if ((portal = create_portal(target, addr, dtype, did)) == NULL) {
448 1.1 agc return NULL;
449 1.1 agc }
450 1.1 agc portal->portaltype = dtype;
451 1.1 agc
452 1.1 agc return target;
453 1.1 agc }
454 1.1 agc
455 1.1 agc
456 1.1 agc /*
457 1.1 agc * set_target_options:
458 1.1 agc * Handle SET_TARGET_OPTIONS request: Copy the given options into the
459 1.1 agc * target structure.
460 1.1 agc *
461 1.1 agc * Parameter:
462 1.1 agc * par The request parameters.
463 1.1 agc *
464 1.1 agc * Returns: status
465 1.1 agc */
466 1.1 agc
467 1.1 agc uint32_t
468 1.1 agc set_target_options(iscsid_get_set_target_options_t * par)
469 1.1 agc {
470 1.1 agc target_t *target;
471 1.1 agc
472 1.1 agc if ((target = find_target(par->list_kind, &par->target_id)) == NULL)
473 1.1 agc return ISCSID_STATUS_INVALID_TARGET_ID;
474 1.1 agc
475 1.1 agc target->options = *par;
476 1.1 agc
477 1.1 agc return ISCSID_STATUS_SUCCESS;
478 1.1 agc }
479 1.1 agc
480 1.1 agc
481 1.1 agc /*
482 1.1 agc * set_target_auth:
483 1.1 agc * Handle SET_TARGET_AUTHENTICATION request: Copy the given options into the
484 1.1 agc * target structure.
485 1.1 agc *
486 1.1 agc * Parameter:
487 1.1 agc * par The request parameters.
488 1.1 agc *
489 1.1 agc * Returns: status
490 1.1 agc */
491 1.1 agc
492 1.1 agc uint32_t
493 1.1 agc set_target_auth(iscsid_set_target_authentication_req_t * par)
494 1.1 agc {
495 1.1 agc target_t *target;
496 1.1 agc
497 1.1 agc if ((target = find_target(par->list_kind, &par->target_id)) == NULL) {
498 1.1 agc return ISCSID_STATUS_INVALID_TARGET_ID;
499 1.1 agc }
500 1.1 agc target->auth = *par;
501 1.1 agc
502 1.1 agc return ISCSID_STATUS_SUCCESS;
503 1.1 agc }
504 1.1 agc
505 1.1 agc
506 1.1 agc /*
507 1.1 agc * get_target_info:
508 1.1 agc * Handle GET_TARGET_INFO request: Return information about the given
509 1.1 agc * target and its portals. If a portal ID is given, returns only the
510 1.1 agc * target info and the ID of this portal.
511 1.1 agc *
512 1.1 agc * Parameter:
513 1.1 agc * par The request parameters.
514 1.1 agc * prsp Pointer to address of response buffer.
515 1.1 agc * prsp_temp Will be set to TRUE if buffer was allocated, FALSE
516 1.1 agc * for static buffer.
517 1.1 agc */
518 1.1 agc
519 1.1 agc void
520 1.1 agc get_target_info(iscsid_list_id_t *par, iscsid_response_t **prsp, int *prsp_temp)
521 1.1 agc {
522 1.1 agc iscsid_get_target_rsp_t *res;
523 1.1 agc iscsid_response_t *rsp = *prsp;
524 1.1 agc uint32_t *idp;
525 1.1 agc target_t *target;
526 1.1 agc portal_group_t *cgroup;
527 1.1 agc portal_t *curr = NULL;
528 1.1 agc int num = 1;
529 1.1 agc
530 1.1 agc DEB(10, ("get_target_info, id %d\n", par->id.id));
531 1.1 agc
532 1.1 agc if ((target = find_target(par->list_kind, &par->id)) == NULL) {
533 1.1 agc if (par->list_kind == SEND_TARGETS_LIST ||
534 1.1 agc (curr = find_portal(&par->id)) == NULL) {
535 1.1 agc rsp->status = ISCSID_STATUS_INVALID_TARGET_ID;
536 1.1 agc return;
537 1.1 agc }
538 1.1 agc target = curr->target;
539 1.1 agc } else if (par->list_kind != SEND_TARGETS_LIST) {
540 1.1 agc num = target->num_portals;
541 1.1 agc }
542 1.1 agc rsp = make_rsp(sizeof(*res) + (num - 1) * sizeof(uint32_t),
543 1.1 agc prsp, prsp_temp);
544 1.1 agc if (rsp == NULL)
545 1.1 agc return;
546 1.1 agc
547 1.1 agc res = (iscsid_get_target_rsp_t *) rsp->parameter;
548 1.1 agc res->target_id = target->entry.sid;
549 1.1 agc strlcpy((char *)res->TargetName, (char *)target->TargetName,
550 1.1 agc sizeof(res->TargetName));
551 1.1 agc strlcpy((char *)res->TargetAlias, (char *)target->TargetAlias,
552 1.1 agc sizeof(res->TargetAlias));
553 1.1 agc
554 1.1 agc res->num_portals = num;
555 1.1 agc idp = res->portal;
556 1.1 agc
557 1.1 agc if (curr) {
558 1.1 agc *idp = curr->entry.sid.id;
559 1.1 agc } else if (par->list_kind != SEND_TARGETS_LIST) {
560 1.1 agc TAILQ_FOREACH(cgroup, &target->group_list, groups)
561 1.1 agc TAILQ_FOREACH(curr, &cgroup->portals, group_list)
562 1.1 agc * idp++ = curr->entry.sid.id;
563 1.1 agc } else
564 1.1 agc *idp = target->entry.sid.id;
565 1.1 agc }
566 1.1 agc
567 1.1 agc
568 1.1 agc /*
569 1.1 agc * add_portal:
570 1.1 agc * Handle ADD_PORTAL request: Add a portal to an existing target.
571 1.1 agc *
572 1.1 agc * Parameter:
573 1.1 agc * par The request parameters.
574 1.1 agc * prsp Pointer to address of response buffer.
575 1.1 agc * prsp_temp Will be set to TRUE if buffer was allocated, FALSE
576 1.1 agc * for static buffer.
577 1.1 agc */
578 1.1 agc
579 1.1 agc
580 1.1 agc void
581 1.1 agc add_portal(iscsid_add_portal_req_t *par, iscsid_response_t **prsp,
582 1.1 agc int *prsp_temp)
583 1.1 agc {
584 1.1 agc iscsid_add_portal_rsp_t *res;
585 1.1 agc iscsid_response_t *rsp = *prsp;
586 1.1 agc target_t *target;
587 1.1 agc portal_t *portal;
588 1.1 agc
589 1.1 agc DEB(9, ("Add portal: target %d (%s), symname %s, addr %s\n",
590 1.1 agc par->target_id.id, par->target_id.name,
591 1.1 agc par->sym_name, par->portal.address));
592 1.1 agc
593 1.1 agc if ((target = find_target(TARGET_LIST, &par->target_id)) == NULL) {
594 1.1 agc rsp->status = ISCSID_STATUS_INVALID_TARGET_ID;
595 1.1 agc return;
596 1.1 agc }
597 1.1 agc
598 1.1 agc if (par->sym_name[0] &&
599 1.1 agc (find_target_symname(TARGET_LIST, par->sym_name) ||
600 1.1 agc find_portal_name(par->sym_name))) {
601 1.1 agc rsp->status = ISCSID_STATUS_DUPLICATE_NAME;
602 1.1 agc return;
603 1.1 agc }
604 1.1 agc
605 1.1 agc portal = create_portal(target, &par->portal, PORTAL_TYPE_STATIC,
606 1.1 agc target->entry.sid.id);
607 1.1 agc if (portal == NULL) {
608 1.1 agc rsp->status = ISCSID_STATUS_NO_RESOURCES;
609 1.1 agc return;
610 1.1 agc }
611 1.1 agc
612 1.1 agc if (par->sym_name[0]) {
613 1.1 agc strlcpy((char *)portal->entry.sid.name, (char *)par->sym_name,
614 1.1 agc sizeof(portal->entry.sid.name));
615 1.1 agc }
616 1.1 agc portal->options = par->options;
617 1.1 agc
618 1.1 agc rsp = make_rsp(sizeof(*res), prsp, prsp_temp);
619 1.1 agc if (rsp == NULL)
620 1.1 agc return;
621 1.1 agc
622 1.1 agc res = (iscsid_add_portal_rsp_t *) rsp->parameter;
623 1.1 agc res->target_id = target->entry.sid;
624 1.1 agc res->portal_id = portal->entry.sid;
625 1.1 agc
626 1.1 agc DEB(9, ("AddPortal success (id %d)\n", portal->entry.sid.id));
627 1.1 agc }
628 1.1 agc
629 1.1 agc
630 1.1 agc /*
631 1.1 agc * get_portal_info:
632 1.1 agc * Handle GET_PORTAL_INFO request: Return information about the given
633 1.1 agc * portal.
634 1.1 agc *
635 1.1 agc * Parameter:
636 1.1 agc * par The request parameters.
637 1.1 agc * prsp Pointer to address of response buffer.
638 1.1 agc * prsp_temp Will be set to TRUE if buffer was allocated, FALSE
639 1.1 agc * for static buffer.
640 1.1 agc */
641 1.1 agc
642 1.1 agc void
643 1.1 agc get_portal_info(iscsid_list_id_t *par, iscsid_response_t **prsp, int *prsp_temp)
644 1.1 agc {
645 1.1 agc iscsid_get_portal_rsp_t *res;
646 1.1 agc iscsid_response_t *rsp = *prsp;
647 1.1 agc portal_t *portal = NULL;
648 1.1 agc send_target_t *starg = NULL;
649 1.1 agc int err;
650 1.1 agc
651 1.1 agc DEB(10, ("get_portal_info, id %d\n", par->id.id));
652 1.1 agc
653 1.1 agc if (par->list_kind == SEND_TARGETS_LIST)
654 1.1 agc err = ((starg = (send_target_t *) find_target(par->list_kind,
655 1.1 agc &par->id)) == NULL);
656 1.1 agc else
657 1.1 agc err = ((portal = find_portal(&par->id)) == NULL);
658 1.1 agc
659 1.1 agc if (err) {
660 1.1 agc rsp->status = ISCSID_STATUS_INVALID_PORTAL_ID;
661 1.1 agc return;
662 1.1 agc }
663 1.1 agc
664 1.1 agc rsp = make_rsp(sizeof(*res), prsp, prsp_temp);
665 1.1 agc if (rsp == NULL)
666 1.1 agc return;
667 1.1 agc
668 1.1 agc res = (iscsid_get_portal_rsp_t *) rsp->parameter;
669 1.1 agc if (par->list_kind == SEND_TARGETS_LIST) {
670 1.1 agc res->target_id = starg->entry.sid;
671 1.1 agc res->portal_id = starg->entry.sid;
672 1.1 agc res->portal = starg->addr;
673 1.1 agc } else {
674 1.1 agc res->target_id = portal->target->entry.sid;
675 1.1 agc res->portal_id = portal->entry.sid;
676 1.1 agc res->portal = portal->addr;
677 1.1 agc }
678 1.1 agc }
679 1.1 agc
680 1.1 agc /*
681 1.1 agc * remove_target:
682 1.1 agc * Handle REMOVE_TARGET request: Removes a target, target portal,
683 1.1 agc * or Send-Targets portal from its respective list.
684 1.1 agc * Removing a target will remove all associated portals.
685 1.1 agc *
686 1.1 agc * Parameter:
687 1.1 agc * par The request parameters = iscsid_list_id_t
688 1.1 agc * containing the target ID.
689 1.1 agc *
690 1.1 agc * Returns: status
691 1.1 agc */
692 1.1 agc
693 1.1 agc uint32_t
694 1.1 agc remove_target(iscsid_list_id_t * par)
695 1.1 agc {
696 1.1 agc target_t *target = NULL;
697 1.1 agc portal_t *portal = NULL;
698 1.1 agc send_target_t *starg = NULL;
699 1.1 agc int err;
700 1.1 agc
701 1.1 agc DEB(9, ("remove_target, id %d\n", par->id.id));
702 1.1 agc
703 1.1 agc if (par->list_kind == SEND_TARGETS_LIST) {
704 1.1 agc err = ((starg = (send_target_t *) find_target(par->list_kind,
705 1.1 agc &par->id)) == NULL);
706 1.1 agc if (!err) {
707 1.1 agc delete_send_target(starg);
708 1.1 agc }
709 1.1 agc } else if (par->list_kind == PORTAL_LIST) {
710 1.1 agc err = ((portal = find_portal(&par->id)) == NULL);
711 1.1 agc if (!err) {
712 1.1 agc delete_portal(portal, FALSE);
713 1.1 agc }
714 1.1 agc } else {
715 1.1 agc target = find_target(par->list_kind, &par->id);
716 1.1 agc err = (target == NULL);
717 1.1 agc if (!err) {
718 1.1 agc delete_target(target);
719 1.1 agc }
720 1.1 agc }
721 1.1 agc
722 1.1 agc return err ? ISCSID_STATUS_INVALID_PORTAL_ID : ISCSID_STATUS_SUCCESS;
723 1.1 agc }
724 1.1 agc
725 1.1 agc
726 1.1 agc
727 1.1 agc /*
728 1.1 agc * cl_get_address:
729 1.1 agc * Get an address specification that may include port and group tag.
730 1.1 agc *
731 1.1 agc * Parameter:
732 1.1 agc * portal The portal address
733 1.1 agc * str The parameter string to scan
734 1.1 agc *
735 1.1 agc * Returns: 0 on error, 1 if OK.
736 1.1 agc */
737 1.1 agc
738 1.1 agc STATIC int
739 1.1 agc cl_get_address(iscsi_portal_address_t * portal, char *str)
740 1.1 agc {
741 1.1 agc char *sp, *sp2;
742 1.1 agc int val;
743 1.1 agc
744 1.1 agc /* is there a port? don't check inside square brackets (IPv6 addr) */
745 1.1 agc for (sp = str + 1, val = 0; *sp && (*sp != ':' || val); sp++) {
746 1.1 agc if (*sp == '[')
747 1.1 agc val = 1;
748 1.1 agc else if (*sp == ']')
749 1.1 agc val = 0;
750 1.1 agc }
751 1.1 agc
752 1.1 agc /* */
753 1.1 agc if (*sp) {
754 1.1 agc for (sp2 = sp + 1; *sp2 && *sp2 != ':'; sp2++);
755 1.1 agc /* if there's a second colon, assume it's an unbracketed IPv6
756 1.1 agc * address */
757 1.1 agc if (!*sp2) {
758 1.1 agc /* truncate source, that's the address */
759 1.1 agc *sp++ = '\0';
760 1.1 agc if (sscanf(sp, "%d", &val) != 1)
761 1.1 agc return 0;
762 1.1 agc if (val < 0 || val > 0xffff)
763 1.1 agc return 0;
764 1.1 agc portal->port = (uint16_t) val;
765 1.1 agc }
766 1.1 agc /* is there a group tag? */
767 1.1 agc for (; isdigit((unsigned char)*sp); sp++) {
768 1.1 agc }
769 1.1 agc if (*sp && *sp != ',')
770 1.1 agc return 0;
771 1.1 agc } else
772 1.1 agc for (sp = str + 1; *sp && *sp != ','; sp++);
773 1.1 agc
774 1.1 agc if (*sp) {
775 1.1 agc if (sscanf(sp + 1, "%d", &val) != 1)
776 1.1 agc return 0;
777 1.1 agc if (val < 0 || val > 0xffff)
778 1.1 agc return 0;
779 1.1 agc portal->group_tag = (uint16_t) val;
780 1.1 agc /* truncate source, that's the address */
781 1.1 agc *sp = '\0';
782 1.1 agc }
783 1.1 agc /* only check length, don't verify correct format (too many
784 1.1 agc * possibilities) */
785 1.1 agc if (strlen(str) >= sizeof(portal->address))
786 1.1 agc return 0;
787 1.1 agc
788 1.1 agc strlcpy((char *)portal->address, str, sizeof(portal->address));
789 1.1 agc
790 1.1 agc return 1;
791 1.1 agc }
792 1.1 agc
793 1.1 agc /*
794 1.1 agc * refresh_send_target:
795 1.1 agc * Handle REFRESH_TARGETS request for a Send Target
796 1.1 agc *
797 1.1 agc * Parameter:
798 1.1 agc * id The send target ID.
799 1.1 agc *
800 1.1 agc * Returns: status
801 1.1 agc */
802 1.1 agc
803 1.1 agc
804 1.1 agc STATIC uint32_t
805 1.1 agc refresh_send_target(uint32_t id)
806 1.1 agc {
807 1.1 agc uint8_t *response_buffer = NULL;
808 1.1 agc uint32_t response_size;
809 1.1 agc uint32_t ret;
810 1.1 agc uint8_t *TargetName;
811 1.1 agc iscsi_portal_address_t addr;
812 1.1 agc uint8_t *tp, *sp;
813 1.1 agc generic_entry_t *curr;
814 1.1 agc generic_entry_t *next;
815 1.1 agc send_target_t *sendtarg;
816 1.1 agc int rc;
817 1.1 agc
818 1.1 agc /*
819 1.1 agc * Go through our list of portals and mark each one
820 1.1 agc * belonging to the current sendtargets group to refreshing
821 1.1 agc * This mark is used afterwards to remove any portals that
822 1.1 agc * were not refreshed (because the mark gets reset for portals
823 1.1 agc * that are refreshed).
824 1.1 agc */
825 1.1 agc
826 1.1 agc TAILQ_FOREACH(curr, &list[PORTAL_LIST].list, link) {
827 1.1 agc if (((portal_t *) curr)->portaltype == PORTAL_TYPE_SENDTARGET &&
828 1.1 agc ((portal_t *) curr)->discoveryid == id) {
829 1.1 agc ((portal_t *)curr)->portaltype = PORTAL_TYPE_REFRESHING;
830 1.1 agc }
831 1.1 agc }
832 1.1 agc
833 1.1 agc if ((ret = send_targets(id, &response_buffer, &response_size)) == 0) {
834 1.1 agc /*
835 1.1 agc * Parse the response target list
836 1.1 agc * The SendTargets response in response_buffer is a list of
837 1.1 agc * target strings. Each target string consists of a TargetName
838 1.1 agc * string, followed by 0 or more TargetAddress strings:
839 1.1 agc *
840 1.1 agc * TargetName=<target-name>
841 1.1 agc * TargetAddress=<hostname-or-ip>[:<tcp-port>],
842 1.1 agc * <portal-group-tag>
843 1.1 agc * The entire list is terminated by a null (after
844 1.1 agc * response_size bytes) (this terminating NULL was placed
845 1.1 agc * there by send_targets routine.)
846 1.1 agc */
847 1.1 agc
848 1.1 agc tp = response_buffer;
849 1.1 agc while (*tp) {
850 1.1 agc if (strncmp((char *)tp, "TargetName=", 11) != 0) {
851 1.1 agc DEBOUT(("Response not TargetName <%s>\n", tp));
852 1.1 agc break;
853 1.1 agc }
854 1.1 agc tp += 11;
855 1.1 agc TargetName = tp; /*Point to target name */
856 1.1 agc while (*tp++) {
857 1.1 agc }
858 1.1 agc rc = -1; /* Mark no address found yet */
859 1.1 agc
860 1.1 agc /*Now process any "TargetAddress" entries following */
861 1.1 agc while (*tp && strncmp((char *)tp, "TargetAddress=", 14) == 0) {
862 1.1 agc tp += 14;
863 1.1 agc sp = tp; /* save start of address */
864 1.1 agc while (*tp++) {
865 1.1 agc }
866 1.1 agc /*Get the target address */
867 1.1 agc rc = cl_get_address(&addr, (char *)sp);
868 1.1 agc if (rc) {
869 1.1 agc add_discovered_target(TargetName,
870 1.1 agc &addr, PORTAL_TYPE_SENDTARGET,
871 1.1 agc id);
872 1.1 agc } else {
873 1.1 agc DEBOUT(("Syntax error in returned target address <%s>\n",
874 1.1 agc tp));
875 1.1 agc break;
876 1.1 agc }
877 1.1 agc }
878 1.1 agc
879 1.1 agc if (rc == -1) {
880 1.1 agc /* There are no TargetAddress entries
881 1.1 agc * associated with TargetName. This means the
882 1.1 agc * sendtarget address is used. */
883 1.1 agc sendtarg = find_send_target_id(id);
884 1.1 agc if (sendtarg != NULL) {
885 1.1 agc add_discovered_target(TargetName,
886 1.1 agc &sendtarg->addr,
887 1.1 agc PORTAL_TYPE_SENDTARGET, id);
888 1.1 agc }
889 1.1 agc }
890 1.1 agc } /* end of while */
891 1.1 agc }
892 1.1 agc /*
893 1.1 agc * Go through our list of portals and look for ones
894 1.1 agc * that are still marked for refreshing.
895 1.1 agc * These are ones that are no longer there and should be removed.
896 1.1 agc */
897 1.1 agc
898 1.1 agc for (curr = TAILQ_FIRST(&list[PORTAL_LIST].list); curr != NULL;
899 1.1 agc curr = next) {
900 1.1 agc next = TAILQ_NEXT(curr, link);
901 1.1 agc if (((portal_t *) curr)->portaltype == PORTAL_TYPE_REFRESHING)
902 1.1 agc delete_portal((portal_t *) curr, TRUE);
903 1.1 agc }
904 1.1 agc
905 1.1 agc /*
906 1.1 agc * Clean up
907 1.1 agc */
908 1.1 agc
909 1.1 agc if (response_buffer != NULL)
910 1.1 agc free(response_buffer);
911 1.1 agc
912 1.1 agc return ret;
913 1.1 agc }
914 1.1 agc
915 1.1 agc
916 1.1 agc /*
917 1.1 agc * cleanup_send_target_orphans:
918 1.1 agc * Delete portals that were discovered through a now deleted send target.
919 1.1 agc */
920 1.1 agc
921 1.1 agc
922 1.1 agc STATIC void
923 1.1 agc cleanup_orphans(iscsi_portal_types_t type)
924 1.1 agc {
925 1.1 agc generic_entry_t *curr;
926 1.1 agc generic_entry_t *next;
927 1.1 agc
928 1.1 agc /*
929 1.1 agc * Go through the list of portals and look for ones marked with a zero
930 1.1 agc * discovery ID, those are associated with send targets that no
931 1.1 agc * longer exist.
932 1.1 agc */
933 1.1 agc
934 1.1 agc for (curr = TAILQ_FIRST(&list[PORTAL_LIST].list); curr != NULL;
935 1.1 agc curr = next) {
936 1.1 agc next = TAILQ_NEXT(curr, link);
937 1.1 agc if (((portal_t *)curr)->portaltype == type &&
938 1.1 agc ((portal_t *)curr)->discoveryid == 0) {
939 1.1 agc delete_portal((portal_t *) curr, TRUE);
940 1.1 agc }
941 1.1 agc }
942 1.1 agc }
943 1.1 agc
944 1.1 agc
945 1.1 agc /*
946 1.1 agc * refresh_targets:
947 1.1 agc * Handle REFRESH_TARGETS request:
948 1.1 agc * Refreshes the list of targets discovered via SendTargets or iSNS
949 1.1 agc *
950 1.1 agc * Parameter:
951 1.1 agc * The request parameter = iscsid_refresh_targets_req_t containing:
952 1.1 agc * iscsid_list_kind_t kind; Kind:
953 1.1 agc * SEND_TARGETS_LIST
954 1.1 agc * ISNS_LIST
955 1.1 agc * uint32_t num_ids; # of targets in list
956 1.1 agc * uint32_t id [1]; List of targets
957 1.1 agc *
958 1.1 agc * Returns: status
959 1.1 agc */
960 1.1 agc
961 1.1 agc uint32_t
962 1.1 agc refresh_targets(iscsid_refresh_req_t * par)
963 1.1 agc {
964 1.1 agc uint32_t t;
965 1.1 agc uint32_t rc, retval;
966 1.1 agc generic_entry_t *curr;
967 1.1 agc
968 1.1 agc retval = ISCSID_STATUS_NO_TARGETS_FOUND;
969 1.1 agc
970 1.1 agc switch (par->kind) {
971 1.1 agc case TARGET_LIST:
972 1.1 agc /*
973 1.1 agc * Refreshing for a specific target makes no sense if it's
974 1.1 agc * static. Maybe implement it for dynamically dicovered
975 1.1 agc * targets? But then it's best done through the discovering
976 1.1 agc * instance, or we'll refresh much more than just the given
977 1.1 agc * target. And refreshing the whole list is iffy as well. So
978 1.1 agc * refuse this op on the target list for now.
979 1.1 agc */
980 1.1 agc break;
981 1.1 agc
982 1.1 agc case SEND_TARGETS_LIST:
983 1.1 agc DEB(9, ("Refresh Send Targets List - num_ids = %d\n",
984 1.1 agc par->num_ids));
985 1.1 agc if (par->num_ids) {
986 1.1 agc /* Target ids are specified */
987 1.1 agc for (t = 0; t < par->num_ids; t++) {
988 1.1 agc rc = refresh_send_target(par->id[t]);
989 1.1 agc if (rc == 0) {
990 1.1 agc retval = ISCSID_STATUS_SUCCESS;
991 1.1 agc }
992 1.1 agc }
993 1.1 agc } else {
994 1.1 agc cleanup_orphans(PORTAL_TYPE_SENDTARGET);
995 1.1 agc
996 1.1 agc /* No target ids specified - refresh all. */
997 1.1 agc TAILQ_FOREACH(curr, &list[SEND_TARGETS_LIST].list, link)
998 1.1 agc if ((rc = refresh_send_target(curr->sid.id)) == 0)
999 1.1 agc retval = ISCSID_STATUS_SUCCESS;
1000 1.1 agc }
1001 1.1 agc return retval;
1002 1.1 agc
1003 1.1 agc #ifndef ISCSI_MINIMAL
1004 1.1 agc case ISNS_LIST:
1005 1.1 agc DEB(9, ("Refresh iSNS List - num_ids = %d\n", par->num_ids));
1006 1.1 agc if (par->num_ids) {
1007 1.1 agc /*Target ids are specified */
1008 1.1 agc for (t = 0; t < par->num_ids; t++)
1009 1.1 agc if ((rc = refresh_isns_server(par->id[t])) == 0)
1010 1.1 agc retval = ISCSI_STATUS_SUCCESS;
1011 1.1 agc } else {
1012 1.1 agc cleanup_orphans(PORTAL_TYPE_ISNS);
1013 1.1 agc
1014 1.1 agc /*No target ids specified - refresh all. */
1015 1.1 agc TAILQ_FOREACH(curr, &list[ISNS_LIST].list, link)
1016 1.1 agc if ((rc = refresh_isns_server(curr->sid.id)) == 0)
1017 1.1 agc retval = ISCSI_STATUS_SUCCESS;
1018 1.1 agc }
1019 1.1 agc return retval;
1020 1.1 agc #endif
1021 1.1 agc
1022 1.1 agc default:
1023 1.1 agc break;
1024 1.1 agc }
1025 1.1 agc
1026 1.1 agc return ISCSID_STATUS_PARAMETER_INVALID;
1027 1.1 agc }
1028