xref: /spdk/lib/iscsi/iscsi_rpc.c (revision 9889ab2dc80e40dae92dcef361d53dcba722043d)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
5  *   Copyright (c) Intel Corporation.
6  *   All rights reserved.
7  *
8  *   Redistribution and use in source and binary forms, with or without
9  *   modification, are permitted provided that the following conditions
10  *   are met:
11  *
12  *     * Redistributions of source code must retain the above copyright
13  *       notice, this list of conditions and the following disclaimer.
14  *     * Redistributions in binary form must reproduce the above copyright
15  *       notice, this list of conditions and the following disclaimer in
16  *       the documentation and/or other materials provided with the
17  *       distribution.
18  *     * Neither the name of Intel Corporation nor the names of its
19  *       contributors may be used to endorse or promote products derived
20  *       from this software without specific prior written permission.
21  *
22  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include "iscsi/iscsi.h"
36 #include "iscsi/conn.h"
37 #include "iscsi/tgt_node.h"
38 #include "iscsi/portal_grp.h"
39 #include "iscsi/init_grp.h"
40 
41 #include "spdk/rpc.h"
42 #include "spdk/util.h"
43 #include "spdk/event.h"
44 #include "spdk/string.h"
45 #include "spdk_internal/log.h"
46 
47 static void
48 spdk_rpc_iscsi_get_initiator_groups(struct spdk_jsonrpc_request *request,
49 				    const struct spdk_json_val *params)
50 {
51 	struct spdk_json_write_ctx *w;
52 
53 	if (params != NULL) {
54 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
55 						 "iscsi_get_initiator_groups requires no parameters");
56 		return;
57 	}
58 
59 	w = spdk_jsonrpc_begin_result(request);
60 	spdk_json_write_array_begin(w);
61 	spdk_iscsi_init_grps_info_json(w);
62 	spdk_json_write_array_end(w);
63 
64 	spdk_jsonrpc_end_result(request, w);
65 }
66 SPDK_RPC_REGISTER("iscsi_get_initiator_groups", spdk_rpc_iscsi_get_initiator_groups,
67 		  SPDK_RPC_RUNTIME)
68 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_get_initiator_groups, get_initiator_groups)
69 
70 struct rpc_initiator_list {
71 	size_t num_initiators;
72 	char *initiators[MAX_INITIATOR];
73 };
74 
75 static int
76 decode_rpc_initiator_list(const struct spdk_json_val *val, void *out)
77 {
78 	struct rpc_initiator_list *list = out;
79 
80 	return spdk_json_decode_array(val, spdk_json_decode_string, list->initiators, MAX_INITIATOR,
81 				      &list->num_initiators, sizeof(char *));
82 }
83 
84 static void
85 free_rpc_initiator_list(struct rpc_initiator_list *list)
86 {
87 	size_t i;
88 
89 	for (i = 0; i < list->num_initiators; i++) {
90 		free(list->initiators[i]);
91 	}
92 }
93 
94 struct rpc_netmask_list {
95 	size_t num_netmasks;
96 	char *netmasks[MAX_NETMASK];
97 };
98 
99 static int
100 decode_rpc_netmask_list(const struct spdk_json_val *val, void *out)
101 {
102 	struct rpc_netmask_list *list = out;
103 
104 	return spdk_json_decode_array(val, spdk_json_decode_string, list->netmasks, MAX_NETMASK,
105 				      &list->num_netmasks, sizeof(char *));
106 }
107 
108 static void
109 free_rpc_netmask_list(struct rpc_netmask_list *list)
110 {
111 	size_t i;
112 
113 	for (i = 0; i < list->num_netmasks; i++) {
114 		free(list->netmasks[i]);
115 	}
116 }
117 
118 struct rpc_initiator_group {
119 	int32_t tag;
120 	struct rpc_initiator_list initiator_list;
121 	struct rpc_netmask_list netmask_list;
122 };
123 
124 static void
125 free_rpc_initiator_group(struct rpc_initiator_group *ig)
126 {
127 	free_rpc_initiator_list(&ig->initiator_list);
128 	free_rpc_netmask_list(&ig->netmask_list);
129 }
130 
131 static const struct spdk_json_object_decoder rpc_initiator_group_decoders[] = {
132 	{"tag", offsetof(struct rpc_initiator_group, tag), spdk_json_decode_int32},
133 	{"initiators", offsetof(struct rpc_initiator_group, initiator_list), decode_rpc_initiator_list},
134 	{"netmasks", offsetof(struct rpc_initiator_group, netmask_list), decode_rpc_netmask_list},
135 };
136 
137 static void
138 spdk_rpc_iscsi_create_initiator_group(struct spdk_jsonrpc_request *request,
139 				      const struct spdk_json_val *params)
140 {
141 	struct rpc_initiator_group req = {};
142 	struct spdk_json_write_ctx *w;
143 
144 	if (spdk_json_decode_object(params, rpc_initiator_group_decoders,
145 				    SPDK_COUNTOF(rpc_initiator_group_decoders), &req)) {
146 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
147 		goto invalid;
148 	}
149 
150 	if (req.initiator_list.num_initiators == 0 ||
151 	    req.netmask_list.num_netmasks == 0) {
152 		goto invalid;
153 	}
154 
155 	if (spdk_iscsi_init_grp_create_from_initiator_list(req.tag,
156 			req.initiator_list.num_initiators,
157 			req.initiator_list.initiators,
158 			req.netmask_list.num_netmasks,
159 			req.netmask_list.netmasks)) {
160 		SPDK_ERRLOG("create_from_initiator_list failed\n");
161 		goto invalid;
162 	}
163 
164 	free_rpc_initiator_group(&req);
165 
166 	w = spdk_jsonrpc_begin_result(request);
167 	spdk_json_write_bool(w, true);
168 	spdk_jsonrpc_end_result(request, w);
169 	return;
170 
171 invalid:
172 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
173 	free_rpc_initiator_group(&req);
174 }
175 SPDK_RPC_REGISTER("iscsi_create_initiator_group", spdk_rpc_iscsi_create_initiator_group,
176 		  SPDK_RPC_RUNTIME)
177 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_create_initiator_group, add_initiator_group)
178 
179 static const struct spdk_json_object_decoder rpc_add_or_delete_initiators_decoders[] = {
180 	{"tag", offsetof(struct rpc_initiator_group, tag), spdk_json_decode_int32},
181 	{"initiators", offsetof(struct rpc_initiator_group, initiator_list), decode_rpc_initiator_list, true},
182 	{"netmasks", offsetof(struct rpc_initiator_group, netmask_list), decode_rpc_netmask_list, true},
183 };
184 
185 static void
186 spdk_rpc_iscsi_initiator_group_add_initiators(struct spdk_jsonrpc_request *request,
187 		const struct spdk_json_val *params)
188 {
189 	struct rpc_initiator_group req = {};
190 	struct spdk_json_write_ctx *w;
191 
192 	if (spdk_json_decode_object(params, rpc_add_or_delete_initiators_decoders,
193 				    SPDK_COUNTOF(rpc_add_or_delete_initiators_decoders), &req)) {
194 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
195 		goto invalid;
196 	}
197 
198 	if (spdk_iscsi_init_grp_add_initiators_from_initiator_list(req.tag,
199 			req.initiator_list.num_initiators,
200 			req.initiator_list.initiators,
201 			req.netmask_list.num_netmasks,
202 			req.netmask_list.netmasks)) {
203 		SPDK_ERRLOG("add_initiators_from_initiator_list failed\n");
204 		goto invalid;
205 	}
206 
207 	free_rpc_initiator_group(&req);
208 
209 	w = spdk_jsonrpc_begin_result(request);
210 	spdk_json_write_bool(w, true);
211 	spdk_jsonrpc_end_result(request, w);
212 	return;
213 
214 invalid:
215 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
216 	free_rpc_initiator_group(&req);
217 }
218 SPDK_RPC_REGISTER("iscsi_initiator_group_add_initiators",
219 		  spdk_rpc_iscsi_initiator_group_add_initiators, SPDK_RPC_RUNTIME)
220 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_initiator_group_add_initiators,
221 				   add_initiators_to_initiator_group)
222 
223 static void
224 spdk_rpc_iscsi_initiator_group_remove_initiators(struct spdk_jsonrpc_request *request,
225 		const struct spdk_json_val *params)
226 {
227 	struct rpc_initiator_group req = {};
228 	struct spdk_json_write_ctx *w;
229 
230 	if (spdk_json_decode_object(params, rpc_add_or_delete_initiators_decoders,
231 				    SPDK_COUNTOF(rpc_add_or_delete_initiators_decoders), &req)) {
232 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
233 		goto invalid;
234 	}
235 
236 	if (spdk_iscsi_init_grp_delete_initiators_from_initiator_list(req.tag,
237 			req.initiator_list.num_initiators,
238 			req.initiator_list.initiators,
239 			req.netmask_list.num_netmasks,
240 			req.netmask_list.netmasks)) {
241 		SPDK_ERRLOG("delete_initiators_from_initiator_list failed\n");
242 		goto invalid;
243 	}
244 
245 	free_rpc_initiator_group(&req);
246 
247 	w = spdk_jsonrpc_begin_result(request);
248 	spdk_json_write_bool(w, true);
249 	spdk_jsonrpc_end_result(request, w);
250 	return;
251 
252 invalid:
253 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
254 	free_rpc_initiator_group(&req);
255 }
256 SPDK_RPC_REGISTER("iscsi_initiator_group_remove_initiators",
257 		  spdk_rpc_iscsi_initiator_group_remove_initiators, SPDK_RPC_RUNTIME)
258 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_initiator_group_remove_initiators,
259 				   delete_initiators_from_initiator_group)
260 
261 struct rpc_iscsi_delete_initiator_group {
262 	int32_t tag;
263 };
264 
265 static const struct spdk_json_object_decoder rpc_iscsi_delete_initiator_group_decoders[] = {
266 	{"tag", offsetof(struct rpc_iscsi_delete_initiator_group, tag), spdk_json_decode_int32},
267 };
268 
269 static void
270 spdk_rpc_iscsi_delete_initiator_group(struct spdk_jsonrpc_request *request,
271 				      const struct spdk_json_val *params)
272 {
273 	struct rpc_iscsi_delete_initiator_group req = {};
274 	struct spdk_json_write_ctx *w;
275 	struct spdk_iscsi_init_grp *ig;
276 
277 	if (spdk_json_decode_object(params, rpc_iscsi_delete_initiator_group_decoders,
278 				    SPDK_COUNTOF(rpc_iscsi_delete_initiator_group_decoders),
279 				    &req)) {
280 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
281 		goto invalid;
282 	}
283 
284 	ig = spdk_iscsi_init_grp_unregister(req.tag);
285 	if (!ig) {
286 		goto invalid;
287 	}
288 	spdk_iscsi_tgt_node_delete_map(NULL, ig);
289 	spdk_iscsi_init_grp_destroy(ig);
290 
291 	w = spdk_jsonrpc_begin_result(request);
292 	spdk_json_write_bool(w, true);
293 	spdk_jsonrpc_end_result(request, w);
294 	return;
295 
296 invalid:
297 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
298 }
299 SPDK_RPC_REGISTER("iscsi_delete_initiator_group", spdk_rpc_iscsi_delete_initiator_group,
300 		  SPDK_RPC_RUNTIME)
301 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_delete_initiator_group, delete_initiator_group)
302 
303 static void
304 spdk_rpc_iscsi_get_target_nodes(struct spdk_jsonrpc_request *request,
305 				const struct spdk_json_val *params)
306 {
307 	struct spdk_json_write_ctx *w;
308 
309 	if (params != NULL) {
310 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
311 						 "iscsi_get_target_nodes requires no parameters");
312 		return;
313 	}
314 
315 	w = spdk_jsonrpc_begin_result(request);
316 	spdk_json_write_array_begin(w);
317 	spdk_iscsi_tgt_nodes_info_json(w);
318 	spdk_json_write_array_end(w);
319 
320 	spdk_jsonrpc_end_result(request, w);
321 }
322 SPDK_RPC_REGISTER("iscsi_get_target_nodes", spdk_rpc_iscsi_get_target_nodes, SPDK_RPC_RUNTIME)
323 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_get_target_nodes, get_target_nodes)
324 
325 struct rpc_pg_ig_map {
326 	int32_t pg_tag;
327 	int32_t ig_tag;
328 };
329 
330 static const struct spdk_json_object_decoder rpc_pg_ig_map_decoders[] = {
331 	{"pg_tag", offsetof(struct rpc_pg_ig_map, pg_tag), spdk_json_decode_int32},
332 	{"ig_tag", offsetof(struct rpc_pg_ig_map, ig_tag), spdk_json_decode_int32},
333 };
334 
335 static int
336 decode_rpc_pg_ig_map(const struct spdk_json_val *val, void *out)
337 {
338 	struct rpc_pg_ig_map *pg_ig_map = out;
339 
340 	return spdk_json_decode_object(val, rpc_pg_ig_map_decoders,
341 				       SPDK_COUNTOF(rpc_pg_ig_map_decoders),
342 				       pg_ig_map);
343 }
344 
345 struct rpc_pg_ig_maps {
346 	size_t num_maps;
347 	struct rpc_pg_ig_map maps[MAX_TARGET_MAP];
348 };
349 
350 static int
351 decode_rpc_pg_ig_maps(const struct spdk_json_val *val, void *out)
352 {
353 	struct rpc_pg_ig_maps *pg_ig_maps = out;
354 
355 	return spdk_json_decode_array(val, decode_rpc_pg_ig_map, pg_ig_maps->maps,
356 				      MAX_TARGET_MAP, &pg_ig_maps->num_maps,
357 				      sizeof(struct rpc_pg_ig_map));
358 }
359 
360 #define RPC_ISCSI_CREATE_TARGET_NODE_MAX_LUN	64
361 
362 struct rpc_lun {
363 	char *bdev_name;
364 	int32_t lun_id;
365 };
366 
367 static const struct spdk_json_object_decoder rpc_lun_decoders[] = {
368 	{"bdev_name", offsetof(struct rpc_lun, bdev_name), spdk_json_decode_string},
369 	{"lun_id", offsetof(struct rpc_lun, lun_id), spdk_json_decode_int32},
370 };
371 
372 static int
373 decode_rpc_lun(const struct spdk_json_val *val, void *out)
374 {
375 	struct rpc_lun *lun = out;
376 
377 	return spdk_json_decode_object(val, rpc_lun_decoders,
378 				       SPDK_COUNTOF(rpc_lun_decoders), lun);
379 }
380 
381 struct rpc_luns {
382 	size_t num_luns;
383 	struct rpc_lun luns[RPC_ISCSI_CREATE_TARGET_NODE_MAX_LUN];
384 };
385 
386 static int
387 decode_rpc_luns(const struct spdk_json_val *val, void *out)
388 {
389 	struct rpc_luns *luns = out;
390 
391 	return spdk_json_decode_array(val, decode_rpc_lun, luns->luns,
392 				      RPC_ISCSI_CREATE_TARGET_NODE_MAX_LUN,
393 				      &luns->num_luns, sizeof(struct rpc_lun));
394 }
395 
396 static void
397 free_rpc_luns(struct rpc_luns *p)
398 {
399 	size_t i;
400 
401 	for (i = 0; i < p->num_luns; i++) {
402 		free(p->luns[i].bdev_name);
403 	}
404 }
405 
406 struct rpc_target_node {
407 	char *name;
408 	char *alias_name;
409 
410 	struct rpc_pg_ig_maps pg_ig_maps;
411 	struct rpc_luns luns;
412 
413 	int32_t queue_depth;
414 	bool disable_chap;
415 	bool require_chap;
416 	bool mutual_chap;
417 	int32_t chap_group;
418 
419 	bool header_digest;
420 	bool data_digest;
421 };
422 
423 static void
424 free_rpc_target_node(struct rpc_target_node *req)
425 {
426 	free(req->name);
427 	free(req->alias_name);
428 	free_rpc_luns(&req->luns);
429 }
430 
431 static const struct spdk_json_object_decoder rpc_target_node_decoders[] = {
432 	{"name", offsetof(struct rpc_target_node, name), spdk_json_decode_string},
433 	{"alias_name", offsetof(struct rpc_target_node, alias_name), spdk_json_decode_string},
434 	{"pg_ig_maps", offsetof(struct rpc_target_node, pg_ig_maps), decode_rpc_pg_ig_maps},
435 	{"luns", offsetof(struct rpc_target_node, luns), decode_rpc_luns},
436 	{"queue_depth", offsetof(struct rpc_target_node, queue_depth), spdk_json_decode_int32},
437 	{"disable_chap", offsetof(struct rpc_target_node, disable_chap), spdk_json_decode_bool, true},
438 	{"require_chap", offsetof(struct rpc_target_node, require_chap), spdk_json_decode_bool, true},
439 	{"mutual_chap", offsetof(struct rpc_target_node, mutual_chap), spdk_json_decode_bool, true},
440 	{"chap_group", offsetof(struct rpc_target_node, chap_group), spdk_json_decode_int32, true},
441 	{"header_digest", offsetof(struct rpc_target_node, header_digest), spdk_json_decode_bool, true},
442 	{"data_digest", offsetof(struct rpc_target_node, data_digest), spdk_json_decode_bool, true},
443 };
444 
445 static void
446 spdk_rpc_iscsi_create_target_node(struct spdk_jsonrpc_request *request,
447 				  const struct spdk_json_val *params)
448 {
449 	struct rpc_target_node req = {};
450 	struct spdk_json_write_ctx *w;
451 	struct spdk_iscsi_tgt_node *target;
452 	int32_t pg_tags[MAX_TARGET_MAP] = {0}, ig_tags[MAX_TARGET_MAP] = {0};
453 	char *bdev_names[RPC_ISCSI_CREATE_TARGET_NODE_MAX_LUN] = {0};
454 	int32_t lun_ids[RPC_ISCSI_CREATE_TARGET_NODE_MAX_LUN] = {0};
455 	size_t i;
456 
457 	if (spdk_json_decode_object(params, rpc_target_node_decoders,
458 				    SPDK_COUNTOF(rpc_target_node_decoders),
459 				    &req)) {
460 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
461 		goto invalid;
462 	}
463 
464 	for (i = 0; i < req.pg_ig_maps.num_maps; i++) {
465 		pg_tags[i] = req.pg_ig_maps.maps[i].pg_tag;
466 		ig_tags[i] = req.pg_ig_maps.maps[i].ig_tag;
467 	}
468 
469 	for (i = 0; i < req.luns.num_luns; i++) {
470 		bdev_names[i] = req.luns.luns[i].bdev_name;
471 		lun_ids[i] = req.luns.luns[i].lun_id;
472 	}
473 
474 	/*
475 	 * Use default parameters in a few places:
476 	 *  index = -1 : automatically pick an index for the new target node
477 	 *  alias = NULL
478 	 */
479 	target = spdk_iscsi_tgt_node_construct(-1, req.name, req.alias_name,
480 					       pg_tags,
481 					       ig_tags,
482 					       req.pg_ig_maps.num_maps,
483 					       (const char **)bdev_names,
484 					       lun_ids,
485 					       req.luns.num_luns,
486 					       req.queue_depth,
487 					       req.disable_chap,
488 					       req.require_chap,
489 					       req.mutual_chap,
490 					       req.chap_group,
491 					       req.header_digest,
492 					       req.data_digest);
493 
494 	if (target == NULL) {
495 		goto invalid;
496 	}
497 
498 	free_rpc_target_node(&req);
499 
500 	w = spdk_jsonrpc_begin_result(request);
501 	spdk_json_write_bool(w, true);
502 	spdk_jsonrpc_end_result(request, w);
503 	return;
504 
505 invalid:
506 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
507 	free_rpc_target_node(&req);
508 }
509 SPDK_RPC_REGISTER("iscsi_create_target_node", spdk_rpc_iscsi_create_target_node, SPDK_RPC_RUNTIME)
510 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_create_target_node, construct_target_node)
511 
512 struct rpc_tgt_node_pg_ig_maps {
513 	char *name;
514 	struct rpc_pg_ig_maps pg_ig_maps;
515 };
516 
517 static const struct spdk_json_object_decoder rpc_tgt_node_pg_ig_maps_decoders[] = {
518 	{"name", offsetof(struct rpc_tgt_node_pg_ig_maps, name), spdk_json_decode_string},
519 	{"pg_ig_maps", offsetof(struct rpc_tgt_node_pg_ig_maps, pg_ig_maps), decode_rpc_pg_ig_maps},
520 };
521 
522 static void
523 spdk_rpc_iscsi_target_node_add_pg_ig_maps(struct spdk_jsonrpc_request *request,
524 		const struct spdk_json_val *params)
525 {
526 	struct rpc_tgt_node_pg_ig_maps req = {};
527 	struct spdk_json_write_ctx *w;
528 	struct spdk_iscsi_tgt_node *target;
529 	int32_t pg_tags[MAX_TARGET_MAP] = {0}, ig_tags[MAX_TARGET_MAP] = {0};
530 	size_t i;
531 	int rc;
532 
533 	if (spdk_json_decode_object(params, rpc_tgt_node_pg_ig_maps_decoders,
534 				    SPDK_COUNTOF(rpc_tgt_node_pg_ig_maps_decoders),
535 				    &req)) {
536 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
537 		goto invalid;
538 	}
539 
540 	target = spdk_iscsi_find_tgt_node(req.name);
541 	if (target == NULL) {
542 		SPDK_ERRLOG("target is not found\n");
543 		goto invalid;
544 	}
545 
546 	for (i = 0; i < req.pg_ig_maps.num_maps; i++) {
547 		pg_tags[i] = req.pg_ig_maps.maps[i].pg_tag;
548 		ig_tags[i] = req.pg_ig_maps.maps[i].ig_tag;
549 	}
550 
551 	rc = spdk_iscsi_target_node_add_pg_ig_maps(target, pg_tags, ig_tags,
552 			req.pg_ig_maps.num_maps);
553 	if (rc < 0) {
554 		SPDK_ERRLOG("add pg-ig maps failed\n");
555 		goto invalid;
556 	}
557 
558 	free(req.name);
559 
560 	w = spdk_jsonrpc_begin_result(request);
561 	spdk_json_write_bool(w, true);
562 	spdk_jsonrpc_end_result(request, w);
563 	return;
564 
565 invalid:
566 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
567 					 "Invalid parameters");
568 	free(req.name);
569 }
570 SPDK_RPC_REGISTER("iscsi_target_node_add_pg_ig_maps",
571 		  spdk_rpc_iscsi_target_node_add_pg_ig_maps, SPDK_RPC_RUNTIME)
572 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_target_node_add_pg_ig_maps, add_pg_ig_maps)
573 
574 static void
575 spdk_rpc_iscsi_target_node_remove_pg_ig_maps(struct spdk_jsonrpc_request *request,
576 		const struct spdk_json_val *params)
577 {
578 	struct rpc_tgt_node_pg_ig_maps req = {};
579 	struct spdk_json_write_ctx *w;
580 	struct spdk_iscsi_tgt_node *target;
581 	int32_t pg_tags[MAX_TARGET_MAP] = {0}, ig_tags[MAX_TARGET_MAP] = {0};
582 	size_t i;
583 	int rc;
584 
585 	if (spdk_json_decode_object(params, rpc_tgt_node_pg_ig_maps_decoders,
586 				    SPDK_COUNTOF(rpc_tgt_node_pg_ig_maps_decoders),
587 				    &req)) {
588 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
589 		goto invalid;
590 	}
591 
592 	target = spdk_iscsi_find_tgt_node(req.name);
593 	if (target == NULL) {
594 		SPDK_ERRLOG("target is not found\n");
595 		goto invalid;
596 	}
597 
598 	for (i = 0; i < req.pg_ig_maps.num_maps; i++) {
599 		pg_tags[i] = req.pg_ig_maps.maps[i].pg_tag;
600 		ig_tags[i] = req.pg_ig_maps.maps[i].ig_tag;
601 	}
602 
603 	rc = spdk_iscsi_target_node_remove_pg_ig_maps(target, pg_tags, ig_tags,
604 			req.pg_ig_maps.num_maps);
605 	if (rc < 0) {
606 		SPDK_ERRLOG("remove pg-ig maps failed\n");
607 		goto invalid;
608 	}
609 
610 	free(req.name);
611 
612 	w = spdk_jsonrpc_begin_result(request);
613 	spdk_json_write_bool(w, true);
614 	spdk_jsonrpc_end_result(request, w);
615 	return;
616 
617 invalid:
618 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
619 					 "Invalid parameters");
620 	free(req.name);
621 }
622 SPDK_RPC_REGISTER("iscsi_target_node_remove_pg_ig_maps",
623 		  spdk_rpc_iscsi_target_node_remove_pg_ig_maps, SPDK_RPC_RUNTIME)
624 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_target_node_remove_pg_ig_maps,
625 				   delete_pg_ig_maps)
626 
627 struct rpc_iscsi_delete_target_node {
628 	char *name;
629 };
630 
631 static void
632 free_rpc_iscsi_delete_target_node(struct rpc_iscsi_delete_target_node *r)
633 {
634 	free(r->name);
635 }
636 
637 static const struct spdk_json_object_decoder rpc_iscsi_delete_target_node_decoders[] = {
638 	{"name", offsetof(struct rpc_iscsi_delete_target_node, name), spdk_json_decode_string},
639 };
640 
641 struct rpc_iscsi_delete_target_node_ctx {
642 	struct rpc_iscsi_delete_target_node req;
643 	struct spdk_jsonrpc_request *request;
644 };
645 
646 static void
647 rpc_iscsi_delete_target_node_done(void *cb_arg, int rc)
648 {
649 	struct rpc_iscsi_delete_target_node_ctx *ctx = cb_arg;
650 	struct spdk_json_write_ctx *w;
651 
652 	free_rpc_iscsi_delete_target_node(&ctx->req);
653 
654 	w = spdk_jsonrpc_begin_result(ctx->request);
655 	spdk_json_write_bool(w, rc == 0);
656 	spdk_jsonrpc_end_result(ctx->request, w);
657 
658 	free(ctx);
659 }
660 
661 static void
662 spdk_rpc_iscsi_delete_target_node(struct spdk_jsonrpc_request *request,
663 				  const struct spdk_json_val *params)
664 {
665 	struct rpc_iscsi_delete_target_node_ctx *ctx;
666 
667 	ctx = calloc(1, sizeof(*ctx));
668 	if (!ctx) {
669 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
670 						 spdk_strerror(ENOMEM));
671 		return;
672 	}
673 
674 	if (spdk_json_decode_object(params, rpc_iscsi_delete_target_node_decoders,
675 				    SPDK_COUNTOF(rpc_iscsi_delete_target_node_decoders),
676 				    &ctx->req)) {
677 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
678 		goto invalid;
679 	}
680 
681 	if (ctx->req.name == NULL) {
682 		SPDK_ERRLOG("missing name param\n");
683 		goto invalid;
684 	}
685 
686 	ctx->request = request;
687 
688 	spdk_iscsi_shutdown_tgt_node_by_name(ctx->req.name,
689 					     rpc_iscsi_delete_target_node_done, ctx);
690 	return;
691 
692 invalid:
693 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
694 	free_rpc_iscsi_delete_target_node(&ctx->req);
695 	free(ctx);
696 }
697 SPDK_RPC_REGISTER("iscsi_delete_target_node", spdk_rpc_iscsi_delete_target_node, SPDK_RPC_RUNTIME)
698 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_delete_target_node, delete_target_node)
699 
700 static void
701 spdk_rpc_iscsi_get_portal_groups(struct spdk_jsonrpc_request *request,
702 				 const struct spdk_json_val *params)
703 {
704 	struct spdk_json_write_ctx *w;
705 
706 	if (params != NULL) {
707 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
708 						 "iscsi_get_portal_groups requires no parameters");
709 		return;
710 	}
711 
712 	w = spdk_jsonrpc_begin_result(request);
713 	spdk_json_write_array_begin(w);
714 	spdk_iscsi_portal_grps_info_json(w);
715 	spdk_json_write_array_end(w);
716 
717 	spdk_jsonrpc_end_result(request, w);
718 }
719 SPDK_RPC_REGISTER("iscsi_get_portal_groups", spdk_rpc_iscsi_get_portal_groups, SPDK_RPC_RUNTIME)
720 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_get_portal_groups, get_portal_groups)
721 
722 struct rpc_portal {
723 	char *host;
724 	char *port;
725 	char *cpumask;
726 };
727 
728 struct rpc_portal_list {
729 	size_t num_portals;
730 	struct rpc_portal portals[MAX_PORTAL];
731 };
732 
733 struct rpc_portal_group {
734 	int32_t tag;
735 	struct rpc_portal_list portal_list;
736 };
737 
738 static void
739 free_rpc_portal(struct rpc_portal *portal)
740 {
741 	free(portal->host);
742 	free(portal->port);
743 	free(portal->cpumask);
744 }
745 
746 static void
747 free_rpc_portal_list(struct rpc_portal_list *pl)
748 {
749 	size_t i;
750 
751 	for (i = 0; i < pl->num_portals; i++) {
752 		free_rpc_portal(&pl->portals[i]);
753 	}
754 	pl->num_portals = 0;
755 }
756 
757 static void
758 free_rpc_portal_group(struct rpc_portal_group *pg)
759 {
760 	free_rpc_portal_list(&pg->portal_list);
761 }
762 
763 static const struct spdk_json_object_decoder rpc_portal_decoders[] = {
764 	{"host", offsetof(struct rpc_portal, host), spdk_json_decode_string},
765 	{"port", offsetof(struct rpc_portal, port), spdk_json_decode_string},
766 	{"cpumask", offsetof(struct rpc_portal, cpumask), spdk_json_decode_string, true},
767 };
768 
769 static int
770 decode_rpc_portal(const struct spdk_json_val *val, void *out)
771 {
772 	struct rpc_portal *portal = out;
773 
774 	return spdk_json_decode_object(val, rpc_portal_decoders,
775 				       SPDK_COUNTOF(rpc_portal_decoders),
776 				       portal);
777 }
778 
779 static int
780 decode_rpc_portal_list(const struct spdk_json_val *val, void *out)
781 {
782 	struct rpc_portal_list *list = out;
783 
784 	return spdk_json_decode_array(val, decode_rpc_portal, list->portals, MAX_PORTAL, &list->num_portals,
785 				      sizeof(struct rpc_portal));
786 }
787 
788 static const struct spdk_json_object_decoder rpc_portal_group_decoders[] = {
789 	{"tag", offsetof(struct rpc_portal_group, tag), spdk_json_decode_int32},
790 	{"portals", offsetof(struct rpc_portal_group, portal_list), decode_rpc_portal_list},
791 };
792 
793 static void
794 spdk_rpc_iscsi_create_portal_group(struct spdk_jsonrpc_request *request,
795 				   const struct spdk_json_val *params)
796 {
797 	struct rpc_portal_group req = {};
798 	struct spdk_iscsi_portal_grp *pg = NULL;
799 	struct spdk_iscsi_portal *portal;
800 	struct spdk_json_write_ctx *w;
801 	size_t i = 0;
802 	int rc = -1;
803 
804 	if (spdk_json_decode_object(params, rpc_portal_group_decoders,
805 				    SPDK_COUNTOF(rpc_portal_group_decoders),
806 				    &req)) {
807 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
808 		goto out;
809 	}
810 
811 	pg = spdk_iscsi_portal_grp_create(req.tag);
812 	if (pg == NULL) {
813 		SPDK_ERRLOG("portal_grp_create failed\n");
814 		goto out;
815 	}
816 	for (i = 0; i < req.portal_list.num_portals; i++) {
817 		if (req.portal_list.portals[i].cpumask) {
818 			SPDK_WARNLOG("A portal was specified with a CPU mask which is no longer supported.\n");
819 			SPDK_WARNLOG("Ignoring the cpumask.\n");
820 		}
821 
822 		portal = spdk_iscsi_portal_create(req.portal_list.portals[i].host,
823 						  req.portal_list.portals[i].port);
824 		if (portal == NULL) {
825 			SPDK_ERRLOG("portal_create failed\n");
826 			goto out;
827 		}
828 		spdk_iscsi_portal_grp_add_portal(pg, portal);
829 	}
830 
831 	rc = spdk_iscsi_portal_grp_open(pg);
832 	if (rc != 0) {
833 		SPDK_ERRLOG("portal_grp_open failed\n");
834 		goto out;
835 	}
836 
837 	rc = spdk_iscsi_portal_grp_register(pg);
838 	if (rc != 0) {
839 		SPDK_ERRLOG("portal_grp_register failed\n");
840 	}
841 
842 out:
843 	if (rc == 0) {
844 		w = spdk_jsonrpc_begin_result(request);
845 		spdk_json_write_bool(w, true);
846 		spdk_jsonrpc_end_result(request, w);
847 	} else {
848 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
849 
850 		if (pg != NULL) {
851 			spdk_iscsi_portal_grp_release(pg);
852 		}
853 	}
854 	free_rpc_portal_group(&req);
855 }
856 SPDK_RPC_REGISTER("iscsi_create_portal_group", spdk_rpc_iscsi_create_portal_group, SPDK_RPC_RUNTIME)
857 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_create_portal_group, add_portal_group)
858 
859 struct rpc_iscsi_delete_portal_group {
860 	int32_t tag;
861 };
862 
863 static const struct spdk_json_object_decoder rpc_iscsi_delete_portal_group_decoders[] = {
864 	{"tag", offsetof(struct rpc_iscsi_delete_portal_group, tag), spdk_json_decode_int32},
865 };
866 
867 static void
868 spdk_rpc_iscsi_delete_portal_group(struct spdk_jsonrpc_request *request,
869 				   const struct spdk_json_val *params)
870 {
871 	struct rpc_iscsi_delete_portal_group req = {};
872 	struct spdk_json_write_ctx *w;
873 	struct spdk_iscsi_portal_grp *pg;
874 
875 	if (spdk_json_decode_object(params, rpc_iscsi_delete_portal_group_decoders,
876 				    SPDK_COUNTOF(rpc_iscsi_delete_portal_group_decoders),
877 				    &req)) {
878 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
879 		goto invalid;
880 	}
881 
882 	pg = spdk_iscsi_portal_grp_unregister(req.tag);
883 	if (!pg) {
884 		goto invalid;
885 	}
886 
887 	spdk_iscsi_tgt_node_delete_map(pg, NULL);
888 	spdk_iscsi_portal_grp_release(pg);
889 
890 	w = spdk_jsonrpc_begin_result(request);
891 	spdk_json_write_bool(w, true);
892 	spdk_jsonrpc_end_result(request, w);
893 	return;
894 
895 invalid:
896 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
897 }
898 SPDK_RPC_REGISTER("iscsi_delete_portal_group", spdk_rpc_iscsi_delete_portal_group, SPDK_RPC_RUNTIME)
899 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_delete_portal_group, delete_portal_group)
900 
901 struct rpc_portal_group_auth {
902 	int32_t tag;
903 	bool disable_chap;
904 	bool require_chap;
905 	bool mutual_chap;
906 	int32_t chap_group;
907 };
908 
909 static const struct spdk_json_object_decoder rpc_portal_group_auth_decoders[] = {
910 	{"tag", offsetof(struct rpc_portal_group_auth, tag), spdk_json_decode_int32},
911 	{"disable_chap", offsetof(struct rpc_portal_group_auth, disable_chap), spdk_json_decode_bool, true},
912 	{"require_chap", offsetof(struct rpc_portal_group_auth, require_chap), spdk_json_decode_bool, true},
913 	{"mutual_chap", offsetof(struct rpc_portal_group_auth, mutual_chap), spdk_json_decode_bool, true},
914 	{"chap_group", offsetof(struct rpc_portal_group_auth, chap_group), spdk_json_decode_int32, true},
915 };
916 
917 static void
918 spdk_rpc_iscsi_portal_group_set_auth(struct spdk_jsonrpc_request *request,
919 				     const struct spdk_json_val *params)
920 {
921 	struct rpc_portal_group_auth req = {};
922 	struct spdk_json_write_ctx *w;
923 	struct spdk_iscsi_portal_grp *pg;
924 	int rc;
925 
926 	if (spdk_json_decode_object(params, rpc_portal_group_auth_decoders,
927 				    SPDK_COUNTOF(rpc_portal_group_auth_decoders), &req)) {
928 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
929 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
930 						 "Invalid parameters");
931 		return;
932 	}
933 
934 	pthread_mutex_lock(&g_spdk_iscsi.mutex);
935 
936 	pg = spdk_iscsi_portal_grp_find_by_tag(req.tag);
937 	if (pg == NULL) {
938 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
939 						     "Could not find portal group %d", req.tag);
940 		goto exit;
941 	}
942 
943 	rc = spdk_iscsi_portal_grp_set_chap_params(pg, req.disable_chap, req.require_chap,
944 			req.mutual_chap, req.chap_group);
945 	if (rc < 0) {
946 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
947 						 "Invalid combination of auth params");
948 		goto exit;
949 	}
950 
951 	pthread_mutex_unlock(&g_spdk_iscsi.mutex);
952 
953 	w = spdk_jsonrpc_begin_result(request);
954 	spdk_json_write_bool(w, true);
955 	spdk_jsonrpc_end_result(request, w);
956 
957 	return;
958 
959 exit:
960 	pthread_mutex_unlock(&g_spdk_iscsi.mutex);
961 }
962 SPDK_RPC_REGISTER("iscsi_portal_group_set_auth", spdk_rpc_iscsi_portal_group_set_auth,
963 		  SPDK_RPC_RUNTIME)
964 
965 struct rpc_iscsi_get_connections_ctx {
966 	struct spdk_jsonrpc_request *request;
967 	struct spdk_json_write_ctx *w;
968 };
969 
970 static void
971 rpc_iscsi_get_connections_done(struct spdk_io_channel_iter *i, int status)
972 {
973 	struct rpc_iscsi_get_connections_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
974 
975 	spdk_json_write_array_end(ctx->w);
976 	spdk_jsonrpc_end_result(ctx->request, ctx->w);
977 
978 	free(ctx);
979 }
980 
981 static void
982 rpc_iscsi_get_connections(struct spdk_io_channel_iter *i)
983 {
984 	struct rpc_iscsi_get_connections_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
985 	struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i);
986 	struct spdk_iscsi_poll_group *pg = spdk_io_channel_get_ctx(ch);
987 	struct spdk_iscsi_conn *conn;
988 
989 	STAILQ_FOREACH(conn, &pg->connections, link) {
990 		spdk_iscsi_conn_info_json(ctx->w, conn);
991 	}
992 
993 	spdk_for_each_channel_continue(i, 0);
994 }
995 
996 static void
997 spdk_rpc_iscsi_get_connections(struct spdk_jsonrpc_request *request,
998 			       const struct spdk_json_val *params)
999 {
1000 	struct rpc_iscsi_get_connections_ctx *ctx;
1001 
1002 	if (params != NULL) {
1003 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1004 						 "iscsi_get_connections requires no parameters");
1005 		return;
1006 	}
1007 
1008 	ctx = calloc(1, sizeof(struct rpc_iscsi_get_connections_ctx));
1009 	if (ctx == NULL) {
1010 		SPDK_ERRLOG("Failed to allocate rpc_get_iscsi_conns_ctx struct\n");
1011 		spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
1012 		return;
1013 	}
1014 
1015 	ctx->request = request;
1016 	ctx->w = spdk_jsonrpc_begin_result(request);
1017 
1018 	spdk_json_write_array_begin(ctx->w);
1019 
1020 	spdk_for_each_channel(&g_spdk_iscsi,
1021 			      rpc_iscsi_get_connections,
1022 			      ctx,
1023 			      rpc_iscsi_get_connections_done);
1024 }
1025 SPDK_RPC_REGISTER("iscsi_get_connections", spdk_rpc_iscsi_get_connections, SPDK_RPC_RUNTIME)
1026 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_get_connections, get_iscsi_connections)
1027 
1028 struct rpc_target_lun {
1029 	char *name;
1030 	char *bdev_name;
1031 	int32_t lun_id;
1032 };
1033 
1034 static void
1035 free_rpc_target_lun(struct rpc_target_lun *req)
1036 {
1037 	free(req->name);
1038 	free(req->bdev_name);
1039 }
1040 
1041 static const struct spdk_json_object_decoder rpc_target_lun_decoders[] = {
1042 	{"name", offsetof(struct rpc_target_lun, name), spdk_json_decode_string},
1043 	{"bdev_name", offsetof(struct rpc_target_lun, bdev_name), spdk_json_decode_string},
1044 	{"lun_id", offsetof(struct rpc_target_lun, lun_id), spdk_json_decode_int32, true},
1045 };
1046 
1047 static void
1048 spdk_rpc_iscsi_target_node_add_lun(struct spdk_jsonrpc_request *request,
1049 				   const struct spdk_json_val *params)
1050 {
1051 	struct rpc_target_lun req = {};
1052 	struct spdk_json_write_ctx *w;
1053 	struct spdk_iscsi_tgt_node *target;
1054 	int rc;
1055 
1056 	req.lun_id = -1;
1057 
1058 	if (spdk_json_decode_object(params, rpc_target_lun_decoders,
1059 				    SPDK_COUNTOF(rpc_target_lun_decoders), &req)) {
1060 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1061 		goto invalid;
1062 	}
1063 
1064 	target = spdk_iscsi_find_tgt_node(req.name);
1065 	if (target == NULL) {
1066 		SPDK_ERRLOG("target is not found\n");
1067 		goto invalid;
1068 	}
1069 
1070 	rc = spdk_iscsi_tgt_node_add_lun(target, req.bdev_name, req.lun_id);
1071 	if (rc < 0) {
1072 		SPDK_ERRLOG("add lun failed\n");
1073 		goto invalid;
1074 	}
1075 
1076 	free_rpc_target_lun(&req);
1077 
1078 	w = spdk_jsonrpc_begin_result(request);
1079 	spdk_json_write_bool(w, true);
1080 	spdk_jsonrpc_end_result(request, w);
1081 	return;
1082 
1083 invalid:
1084 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1085 					 "Invalid parameters");
1086 	free_rpc_target_lun(&req);
1087 }
1088 SPDK_RPC_REGISTER("iscsi_target_node_add_lun", spdk_rpc_iscsi_target_node_add_lun, SPDK_RPC_RUNTIME)
1089 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_target_node_add_lun, target_node_add_lun)
1090 
1091 struct rpc_target_auth {
1092 	char *name;
1093 	bool disable_chap;
1094 	bool require_chap;
1095 	bool mutual_chap;
1096 	int32_t chap_group;
1097 };
1098 
1099 static void
1100 free_rpc_target_auth(struct rpc_target_auth *req)
1101 {
1102 	free(req->name);
1103 }
1104 
1105 static const struct spdk_json_object_decoder rpc_target_auth_decoders[] = {
1106 	{"name", offsetof(struct rpc_target_auth, name), spdk_json_decode_string},
1107 	{"disable_chap", offsetof(struct rpc_target_auth, disable_chap), spdk_json_decode_bool, true},
1108 	{"require_chap", offsetof(struct rpc_target_auth, require_chap), spdk_json_decode_bool, true},
1109 	{"mutual_chap", offsetof(struct rpc_target_auth, mutual_chap), spdk_json_decode_bool, true},
1110 	{"chap_group", offsetof(struct rpc_target_auth, chap_group), spdk_json_decode_int32, true},
1111 };
1112 
1113 static void
1114 spdk_rpc_iscsi_target_node_set_auth(struct spdk_jsonrpc_request *request,
1115 				    const struct spdk_json_val *params)
1116 {
1117 	struct rpc_target_auth req = {};
1118 	struct spdk_json_write_ctx *w;
1119 	struct spdk_iscsi_tgt_node *target;
1120 	int rc;
1121 
1122 	if (spdk_json_decode_object(params, rpc_target_auth_decoders,
1123 				    SPDK_COUNTOF(rpc_target_auth_decoders), &req)) {
1124 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1125 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1126 						 "Invalid parameters");
1127 		goto exit;
1128 	}
1129 
1130 	target = spdk_iscsi_find_tgt_node(req.name);
1131 	if (target == NULL) {
1132 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1133 						     "Could not find target %s", req.name);
1134 		goto exit;
1135 	}
1136 
1137 	rc = spdk_iscsi_tgt_node_set_chap_params(target, req.disable_chap, req.require_chap,
1138 			req.mutual_chap, req.chap_group);
1139 	if (rc < 0) {
1140 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1141 						 "Invalid combination of auth params");
1142 		goto exit;
1143 	}
1144 
1145 	free_rpc_target_auth(&req);
1146 
1147 	w = spdk_jsonrpc_begin_result(request);
1148 	spdk_json_write_bool(w, true);
1149 	spdk_jsonrpc_end_result(request, w);
1150 	return;
1151 
1152 exit:
1153 	free_rpc_target_auth(&req);
1154 }
1155 SPDK_RPC_REGISTER("iscsi_target_node_set_auth", spdk_rpc_iscsi_target_node_set_auth,
1156 		  SPDK_RPC_RUNTIME)
1157 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_target_node_set_auth, set_iscsi_target_node_auth)
1158 
1159 static void
1160 spdk_rpc_iscsi_get_options(struct spdk_jsonrpc_request *request,
1161 			   const struct spdk_json_val *params)
1162 {
1163 	struct spdk_json_write_ctx *w;
1164 
1165 	if (params != NULL) {
1166 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1167 						 "iscsi_get_options requires no parameters");
1168 		return;
1169 	}
1170 
1171 	w = spdk_jsonrpc_begin_result(request);
1172 	spdk_iscsi_opts_info_json(w);
1173 
1174 	spdk_jsonrpc_end_result(request, w);
1175 }
1176 SPDK_RPC_REGISTER("iscsi_get_options", spdk_rpc_iscsi_get_options, SPDK_RPC_RUNTIME)
1177 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_get_options, get_iscsi_global_params)
1178 
1179 struct rpc_discovery_auth {
1180 	bool disable_chap;
1181 	bool require_chap;
1182 	bool mutual_chap;
1183 	int32_t chap_group;
1184 };
1185 
1186 static const struct spdk_json_object_decoder rpc_discovery_auth_decoders[] = {
1187 	{"disable_chap", offsetof(struct rpc_discovery_auth, disable_chap), spdk_json_decode_bool, true},
1188 	{"require_chap", offsetof(struct rpc_discovery_auth, require_chap), spdk_json_decode_bool, true},
1189 	{"mutual_chap", offsetof(struct rpc_discovery_auth, mutual_chap), spdk_json_decode_bool, true},
1190 	{"chap_group", offsetof(struct rpc_discovery_auth, chap_group), spdk_json_decode_int32, true},
1191 };
1192 
1193 static void
1194 spdk_rpc_iscsi_set_discovery_auth(struct spdk_jsonrpc_request *request,
1195 				  const struct spdk_json_val *params)
1196 {
1197 	struct rpc_discovery_auth req = {};
1198 	struct spdk_json_write_ctx *w;
1199 	int rc;
1200 
1201 	if (spdk_json_decode_object(params, rpc_discovery_auth_decoders,
1202 				    SPDK_COUNTOF(rpc_discovery_auth_decoders), &req)) {
1203 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1204 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1205 						 "Invalid parameters");
1206 		return;
1207 	}
1208 
1209 	rc = spdk_iscsi_set_discovery_auth(req.disable_chap, req.require_chap,
1210 					   req.mutual_chap, req.chap_group);
1211 	if (rc < 0) {
1212 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1213 						 "Invalid combination of CHAP params");
1214 		return;
1215 	}
1216 
1217 	w = spdk_jsonrpc_begin_result(request);
1218 	spdk_json_write_bool(w, true);
1219 	spdk_jsonrpc_end_result(request, w);
1220 }
1221 SPDK_RPC_REGISTER("iscsi_set_discovery_auth", spdk_rpc_iscsi_set_discovery_auth, SPDK_RPC_RUNTIME)
1222 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_set_discovery_auth, set_iscsi_discovery_auth)
1223 
1224 #define MAX_AUTH_SECRETS	64
1225 
1226 struct rpc_auth_secret {
1227 	char *user;
1228 	char *secret;
1229 	char *muser;
1230 	char *msecret;
1231 };
1232 
1233 static void
1234 free_rpc_auth_secret(struct rpc_auth_secret *_secret)
1235 {
1236 	free(_secret->user);
1237 	free(_secret->secret);
1238 	free(_secret->muser);
1239 	free(_secret->msecret);
1240 }
1241 
1242 static const struct spdk_json_object_decoder rpc_auth_secret_decoders[] = {
1243 	{"user", offsetof(struct rpc_auth_secret, user), spdk_json_decode_string},
1244 	{"secret", offsetof(struct rpc_auth_secret, secret), spdk_json_decode_string},
1245 	{"muser", offsetof(struct rpc_auth_secret, muser), spdk_json_decode_string, true},
1246 	{"msecret", offsetof(struct rpc_auth_secret, msecret), spdk_json_decode_string, true},
1247 };
1248 
1249 static int
1250 decode_rpc_auth_secret(const struct spdk_json_val *val, void *out)
1251 {
1252 	struct rpc_auth_secret *_secret = out;
1253 
1254 	return spdk_json_decode_object(val, rpc_auth_secret_decoders,
1255 				       SPDK_COUNTOF(rpc_auth_secret_decoders), _secret);
1256 }
1257 
1258 struct rpc_auth_secrets {
1259 	size_t num_secret;
1260 	struct rpc_auth_secret secrets[MAX_AUTH_SECRETS];
1261 };
1262 
1263 static void
1264 free_rpc_auth_secrets(struct rpc_auth_secrets *secrets)
1265 {
1266 	size_t i;
1267 
1268 	for (i = 0; i < secrets->num_secret; i++) {
1269 		free_rpc_auth_secret(&secrets->secrets[i]);
1270 	}
1271 }
1272 
1273 static int
1274 decode_rpc_auth_secrets(const struct spdk_json_val *val, void *out)
1275 {
1276 	struct rpc_auth_secrets *secrets = out;
1277 
1278 	return spdk_json_decode_array(val, decode_rpc_auth_secret, secrets->secrets,
1279 				      MAX_AUTH_SECRETS, &secrets->num_secret,
1280 				      sizeof(struct rpc_auth_secret));
1281 }
1282 
1283 struct rpc_auth_group {
1284 	int32_t tag;
1285 	struct rpc_auth_secrets secrets;
1286 };
1287 
1288 static void
1289 free_rpc_auth_group(struct rpc_auth_group *group)
1290 {
1291 	free_rpc_auth_secrets(&group->secrets);
1292 }
1293 
1294 static const struct spdk_json_object_decoder rpc_auth_group_decoders[] = {
1295 	{"tag", offsetof(struct rpc_auth_group, tag), spdk_json_decode_int32},
1296 	{"secrets", offsetof(struct rpc_auth_group, secrets), decode_rpc_auth_secrets, true},
1297 };
1298 
1299 static void
1300 spdk_rpc_iscsi_create_auth_group(struct spdk_jsonrpc_request *request,
1301 				 const struct spdk_json_val *params)
1302 {
1303 	struct rpc_auth_group req = {};
1304 	struct rpc_auth_secret *_secret;
1305 	struct spdk_json_write_ctx *w;
1306 	struct spdk_iscsi_auth_group *group = NULL;
1307 	int rc;
1308 	size_t i;
1309 
1310 	if (spdk_json_decode_object(params, rpc_auth_group_decoders,
1311 				    SPDK_COUNTOF(rpc_auth_group_decoders), &req)) {
1312 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1313 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1314 						 "Invalid parameters");
1315 		free_rpc_auth_group(&req);
1316 		return;
1317 	}
1318 
1319 	pthread_mutex_lock(&g_spdk_iscsi.mutex);
1320 
1321 	rc = spdk_iscsi_add_auth_group(req.tag, &group);
1322 	if (rc != 0) {
1323 		pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1324 
1325 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1326 						     "Could not add auth group (%d), %s",
1327 						     req.tag, spdk_strerror(-rc));
1328 		free_rpc_auth_group(&req);
1329 		return;
1330 	}
1331 
1332 	for (i = 0; i < req.secrets.num_secret; i++) {
1333 		_secret = &req.secrets.secrets[i];
1334 		rc = spdk_iscsi_auth_group_add_secret(group, _secret->user, _secret->secret,
1335 						      _secret->muser, _secret->msecret);
1336 		if (rc != 0) {
1337 			spdk_iscsi_delete_auth_group(group);
1338 			pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1339 
1340 			spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1341 							     "Could not add secret to auth group (%d), %s",
1342 							     req.tag, spdk_strerror(-rc));
1343 			free_rpc_auth_group(&req);
1344 			return;
1345 		}
1346 	}
1347 
1348 	pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1349 
1350 	free_rpc_auth_group(&req);
1351 
1352 	w = spdk_jsonrpc_begin_result(request);
1353 	spdk_json_write_bool(w, true);
1354 	spdk_jsonrpc_end_result(request, w);
1355 }
1356 SPDK_RPC_REGISTER("iscsi_create_auth_group", spdk_rpc_iscsi_create_auth_group, SPDK_RPC_RUNTIME)
1357 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_create_auth_group, add_iscsi_auth_group)
1358 
1359 struct rpc_delete_auth_group {
1360 	int32_t tag;
1361 };
1362 
1363 static const struct spdk_json_object_decoder rpc_delete_auth_group_decoders[] = {
1364 	{"tag", offsetof(struct rpc_delete_auth_group, tag), spdk_json_decode_int32},
1365 };
1366 
1367 static void
1368 spdk_rpc_iscsi_delete_auth_group(struct spdk_jsonrpc_request *request,
1369 				 const struct spdk_json_val *params)
1370 {
1371 	struct rpc_delete_auth_group req = {};
1372 	struct spdk_json_write_ctx *w;
1373 	struct spdk_iscsi_auth_group *group;
1374 
1375 	if (spdk_json_decode_object(params, rpc_delete_auth_group_decoders,
1376 				    SPDK_COUNTOF(rpc_delete_auth_group_decoders), &req)) {
1377 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1378 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1379 						 "Invalid parameters");
1380 		return;
1381 	}
1382 
1383 	pthread_mutex_lock(&g_spdk_iscsi.mutex);
1384 
1385 	group = spdk_iscsi_find_auth_group_by_tag(req.tag);
1386 	if (group == NULL) {
1387 		pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1388 
1389 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1390 						     "Could not find auth group (%d)", req.tag);
1391 		return;
1392 	}
1393 
1394 	spdk_iscsi_delete_auth_group(group);
1395 
1396 	pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1397 
1398 	w = spdk_jsonrpc_begin_result(request);
1399 	spdk_json_write_bool(w, true);
1400 	spdk_jsonrpc_end_result(request, w);
1401 }
1402 SPDK_RPC_REGISTER("iscsi_delete_auth_group", spdk_rpc_iscsi_delete_auth_group, SPDK_RPC_RUNTIME)
1403 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_delete_auth_group, delete_iscsi_auth_group)
1404 
1405 struct rpc_add_auth_secret {
1406 	int32_t tag;
1407 	char *user;
1408 	char *secret;
1409 	char *muser;
1410 	char *msecret;
1411 };
1412 
1413 static void
1414 free_rpc_add_auth_secret(struct rpc_add_auth_secret *_secret)
1415 {
1416 	free(_secret->user);
1417 	free(_secret->secret);
1418 	free(_secret->muser);
1419 	free(_secret->msecret);
1420 }
1421 
1422 static const struct spdk_json_object_decoder rpc_add_auth_secret_decoders[] = {
1423 	{"tag", offsetof(struct rpc_add_auth_secret, tag), spdk_json_decode_int32},
1424 	{"user", offsetof(struct rpc_add_auth_secret, user), spdk_json_decode_string},
1425 	{"secret", offsetof(struct rpc_add_auth_secret, secret), spdk_json_decode_string},
1426 	{"muser", offsetof(struct rpc_add_auth_secret, muser), spdk_json_decode_string, true},
1427 	{"msecret", offsetof(struct rpc_add_auth_secret, msecret), spdk_json_decode_string, true},
1428 };
1429 
1430 static void
1431 spdk_rpc_iscsi_auth_group_add_secret(struct spdk_jsonrpc_request *request,
1432 				     const struct spdk_json_val *params)
1433 {
1434 	struct rpc_add_auth_secret req = {};
1435 	struct spdk_json_write_ctx *w;
1436 	struct spdk_iscsi_auth_group *group;
1437 	int rc;
1438 
1439 	if (spdk_json_decode_object(params, rpc_add_auth_secret_decoders,
1440 				    SPDK_COUNTOF(rpc_add_auth_secret_decoders), &req)) {
1441 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1442 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1443 						 "Invalid parameters");
1444 		free_rpc_add_auth_secret(&req);
1445 		return;
1446 	}
1447 
1448 	pthread_mutex_lock(&g_spdk_iscsi.mutex);
1449 
1450 	group = spdk_iscsi_find_auth_group_by_tag(req.tag);
1451 	if (group == NULL) {
1452 		pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1453 
1454 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1455 						     "Could not find auth group (%d)", req.tag);
1456 		free_rpc_add_auth_secret(&req);
1457 		return;
1458 	}
1459 
1460 	rc = spdk_iscsi_auth_group_add_secret(group, req.user, req.secret, req.muser, req.msecret);
1461 	if (rc != 0) {
1462 		pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1463 
1464 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1465 						     "Could not add secret to auth group (%d), %s",
1466 						     req.tag, spdk_strerror(-rc));
1467 		free_rpc_add_auth_secret(&req);
1468 		return;
1469 	}
1470 
1471 	pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1472 
1473 	free_rpc_add_auth_secret(&req);
1474 
1475 	w = spdk_jsonrpc_begin_result(request);
1476 	spdk_json_write_bool(w, true);
1477 	spdk_jsonrpc_end_result(request, w);
1478 }
1479 SPDK_RPC_REGISTER("iscsi_auth_group_add_secret", spdk_rpc_iscsi_auth_group_add_secret,
1480 		  SPDK_RPC_RUNTIME)
1481 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_auth_group_add_secret, add_secret_to_iscsi_auth_group)
1482 
1483 
1484 struct rpc_remove_auth_secret {
1485 	int32_t tag;
1486 	char *user;
1487 };
1488 
1489 static void
1490 free_rpc_remove_auth_secret(struct rpc_remove_auth_secret *_secret)
1491 {
1492 	free(_secret->user);
1493 }
1494 
1495 static const struct spdk_json_object_decoder rpc_remove_auth_secret_decoders[] = {
1496 	{"tag", offsetof(struct rpc_remove_auth_secret, tag), spdk_json_decode_int32},
1497 	{"user", offsetof(struct rpc_remove_auth_secret, user), spdk_json_decode_string},
1498 };
1499 
1500 static void
1501 spdk_rpc_iscsi_auth_group_remove_secret(struct spdk_jsonrpc_request *request,
1502 					const struct spdk_json_val *params)
1503 {
1504 	struct rpc_remove_auth_secret req = {};
1505 	struct spdk_json_write_ctx *w;
1506 	struct spdk_iscsi_auth_group *group;
1507 	int rc;
1508 
1509 	if (spdk_json_decode_object(params, rpc_remove_auth_secret_decoders,
1510 				    SPDK_COUNTOF(rpc_remove_auth_secret_decoders), &req)) {
1511 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1512 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1513 						 "Invalid parameters");
1514 		free_rpc_remove_auth_secret(&req);
1515 		return;
1516 	}
1517 
1518 	pthread_mutex_lock(&g_spdk_iscsi.mutex);
1519 
1520 	group = spdk_iscsi_find_auth_group_by_tag(req.tag);
1521 	if (group == NULL) {
1522 		pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1523 
1524 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1525 						     "Could not find auth group (%d)", req.tag);
1526 		free_rpc_remove_auth_secret(&req);
1527 		return;
1528 	}
1529 
1530 	rc = spdk_iscsi_auth_group_delete_secret(group, req.user);
1531 	if (rc != 0) {
1532 		pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1533 
1534 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1535 						     "Could not delete secret from CHAP group (%d), %s",
1536 						     req.tag, spdk_strerror(-rc));
1537 		free_rpc_remove_auth_secret(&req);
1538 		return;
1539 	}
1540 
1541 	pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1542 
1543 	free_rpc_remove_auth_secret(&req);
1544 
1545 	w = spdk_jsonrpc_begin_result(request);
1546 	spdk_json_write_bool(w, true);
1547 	spdk_jsonrpc_end_result(request, w);
1548 }
1549 SPDK_RPC_REGISTER("iscsi_auth_group_remove_secret",
1550 		  spdk_rpc_iscsi_auth_group_remove_secret, SPDK_RPC_RUNTIME)
1551 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_auth_group_remove_secret,
1552 				   delete_secret_from_iscsi_auth_group)
1553 
1554 static void
1555 spdk_rpc_iscsi_get_auth_groups(struct spdk_jsonrpc_request *request,
1556 			       const struct spdk_json_val *params)
1557 {
1558 	struct spdk_json_write_ctx *w;
1559 
1560 	if (params != NULL) {
1561 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1562 						 "iscsi_get_auth_groups requires no parameters");
1563 		return;
1564 	}
1565 
1566 	w = spdk_jsonrpc_begin_result(request);
1567 	spdk_json_write_array_begin(w);
1568 	spdk_iscsi_auth_groups_info_json(w);
1569 	spdk_json_write_array_end(w);
1570 
1571 	spdk_jsonrpc_end_result(request, w);
1572 }
1573 SPDK_RPC_REGISTER("iscsi_get_auth_groups", spdk_rpc_iscsi_get_auth_groups, SPDK_RPC_RUNTIME)
1574 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_get_auth_groups, get_iscsi_auth_groups)
1575 
1576 static const struct spdk_json_object_decoder rpc_set_iscsi_opts_decoders[] = {
1577 	{"auth_file", offsetof(struct spdk_iscsi_opts, authfile), spdk_json_decode_string, true},
1578 	{"node_base", offsetof(struct spdk_iscsi_opts, nodebase), spdk_json_decode_string, true},
1579 	{"nop_timeout", offsetof(struct spdk_iscsi_opts, timeout), spdk_json_decode_int32, true},
1580 	{"nop_in_interval", offsetof(struct spdk_iscsi_opts, nopininterval), spdk_json_decode_int32, true},
1581 	{"no_discovery_auth", offsetof(struct spdk_iscsi_opts, disable_chap), spdk_json_decode_bool, true},
1582 	{"req_discovery_auth", offsetof(struct spdk_iscsi_opts, require_chap), spdk_json_decode_bool, true},
1583 	{"req_discovery_auth_mutual", offsetof(struct spdk_iscsi_opts, mutual_chap), spdk_json_decode_bool, true},
1584 	{"discovery_auth_group", offsetof(struct spdk_iscsi_opts, chap_group), spdk_json_decode_int32, true},
1585 	{"disable_chap", offsetof(struct spdk_iscsi_opts, disable_chap), spdk_json_decode_bool, true},
1586 	{"require_chap", offsetof(struct spdk_iscsi_opts, require_chap), spdk_json_decode_bool, true},
1587 	{"mutual_chap", offsetof(struct spdk_iscsi_opts, mutual_chap), spdk_json_decode_bool, true},
1588 	{"chap_group", offsetof(struct spdk_iscsi_opts, chap_group), spdk_json_decode_int32, true},
1589 	{"max_sessions", offsetof(struct spdk_iscsi_opts, MaxSessions), spdk_json_decode_uint32, true},
1590 	{"max_queue_depth", offsetof(struct spdk_iscsi_opts, MaxQueueDepth), spdk_json_decode_uint32, true},
1591 	{"max_connections_per_session", offsetof(struct spdk_iscsi_opts, MaxConnectionsPerSession), spdk_json_decode_uint32, true},
1592 	{"default_time2wait", offsetof(struct spdk_iscsi_opts, DefaultTime2Wait), spdk_json_decode_uint32, true},
1593 	{"default_time2retain", offsetof(struct spdk_iscsi_opts, DefaultTime2Retain), spdk_json_decode_uint32, true},
1594 	{"first_burst_length", offsetof(struct spdk_iscsi_opts, FirstBurstLength), spdk_json_decode_uint32, true},
1595 	{"immediate_data", offsetof(struct spdk_iscsi_opts, ImmediateData), spdk_json_decode_bool, true},
1596 	{"error_recovery_level", offsetof(struct spdk_iscsi_opts, ErrorRecoveryLevel), spdk_json_decode_uint32, true},
1597 	{"allow_duplicated_isid", offsetof(struct spdk_iscsi_opts, AllowDuplicateIsid), spdk_json_decode_bool, true},
1598 };
1599 
1600 static void
1601 spdk_rpc_iscsi_set_options(struct spdk_jsonrpc_request *request,
1602 			   const struct spdk_json_val *params)
1603 {
1604 	struct spdk_iscsi_opts *opts;
1605 	struct spdk_json_write_ctx *w;
1606 
1607 	if (g_spdk_iscsi_opts != NULL) {
1608 		SPDK_ERRLOG("this RPC must not be called more than once.\n");
1609 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1610 						 "Must not call more than once");
1611 		return;
1612 	}
1613 
1614 	opts = spdk_iscsi_opts_alloc();
1615 	if (opts == NULL) {
1616 		SPDK_ERRLOG("spdk_iscsi_opts_alloc() failed.\n");
1617 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1618 						 "Out of memory");
1619 		return;
1620 	}
1621 
1622 	if (params != NULL) {
1623 		if (spdk_json_decode_object(params, rpc_set_iscsi_opts_decoders,
1624 					    SPDK_COUNTOF(rpc_set_iscsi_opts_decoders), opts)) {
1625 			SPDK_ERRLOG("spdk_json_decode_object() failed\n");
1626 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1627 							 "Invalid parameters");
1628 			spdk_iscsi_opts_free(opts);
1629 			return;
1630 		}
1631 	}
1632 
1633 	g_spdk_iscsi_opts = spdk_iscsi_opts_copy(opts);
1634 	spdk_iscsi_opts_free(opts);
1635 
1636 	if (g_spdk_iscsi_opts == NULL) {
1637 		SPDK_ERRLOG("spdk_iscsi_opts_copy() failed\n");
1638 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1639 						 "Out of memory");
1640 		return;
1641 	}
1642 
1643 	w = spdk_jsonrpc_begin_result(request);
1644 	spdk_json_write_bool(w, true);
1645 	spdk_jsonrpc_end_result(request, w);
1646 }
1647 SPDK_RPC_REGISTER("iscsi_set_options", spdk_rpc_iscsi_set_options, SPDK_RPC_STARTUP)
1648 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_set_options, set_iscsi_options)
1649