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