xref: /spdk/lib/iscsi/iscsi_rpc.c (revision 6b6dfea6c704a049e553024aa7e44ae916948e20)
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_delete_target_node {
628 	char *name;
629 };
630 
631 static void
632 free_rpc_delete_target_node(struct rpc_delete_target_node *r)
633 {
634 	free(r->name);
635 }
636 
637 static const struct spdk_json_object_decoder rpc_delete_target_node_decoders[] = {
638 	{"name", offsetof(struct rpc_delete_target_node, name), spdk_json_decode_string},
639 };
640 
641 struct rpc_delete_target_node_ctx {
642 	struct rpc_delete_target_node req;
643 	struct spdk_jsonrpc_request *request;
644 };
645 
646 static void
647 rpc_delete_target_node_done(void *cb_arg, int rc)
648 {
649 	struct rpc_delete_target_node_ctx *ctx = cb_arg;
650 	struct spdk_json_write_ctx *w;
651 
652 	free_rpc_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_delete_target_node(struct spdk_jsonrpc_request *request,
663 			    const struct spdk_json_val *params)
664 {
665 	struct rpc_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_delete_target_node_decoders,
675 				    SPDK_COUNTOF(rpc_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_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_delete_target_node(&ctx->req);
695 	free(ctx);
696 }
697 SPDK_RPC_REGISTER("delete_target_node", spdk_rpc_delete_target_node, SPDK_RPC_RUNTIME)
698 
699 static void
700 spdk_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 	spdk_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", spdk_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 	char *cpumask;
725 };
726 
727 struct rpc_portal_list {
728 	size_t num_portals;
729 	struct rpc_portal portals[MAX_PORTAL];
730 };
731 
732 struct rpc_portal_group {
733 	int32_t tag;
734 	struct rpc_portal_list portal_list;
735 };
736 
737 static void
738 free_rpc_portal(struct rpc_portal *portal)
739 {
740 	free(portal->host);
741 	free(portal->port);
742 	free(portal->cpumask);
743 }
744 
745 static void
746 free_rpc_portal_list(struct rpc_portal_list *pl)
747 {
748 	size_t i;
749 
750 	for (i = 0; i < pl->num_portals; i++) {
751 		free_rpc_portal(&pl->portals[i]);
752 	}
753 	pl->num_portals = 0;
754 }
755 
756 static void
757 free_rpc_portal_group(struct rpc_portal_group *pg)
758 {
759 	free_rpc_portal_list(&pg->portal_list);
760 }
761 
762 static const struct spdk_json_object_decoder rpc_portal_decoders[] = {
763 	{"host", offsetof(struct rpc_portal, host), spdk_json_decode_string},
764 	{"port", offsetof(struct rpc_portal, port), spdk_json_decode_string},
765 	{"cpumask", offsetof(struct rpc_portal, cpumask), spdk_json_decode_string, true},
766 };
767 
768 static int
769 decode_rpc_portal(const struct spdk_json_val *val, void *out)
770 {
771 	struct rpc_portal *portal = out;
772 
773 	return spdk_json_decode_object(val, rpc_portal_decoders,
774 				       SPDK_COUNTOF(rpc_portal_decoders),
775 				       portal);
776 }
777 
778 static int
779 decode_rpc_portal_list(const struct spdk_json_val *val, void *out)
780 {
781 	struct rpc_portal_list *list = out;
782 
783 	return spdk_json_decode_array(val, decode_rpc_portal, list->portals, MAX_PORTAL, &list->num_portals,
784 				      sizeof(struct rpc_portal));
785 }
786 
787 static const struct spdk_json_object_decoder rpc_portal_group_decoders[] = {
788 	{"tag", offsetof(struct rpc_portal_group, tag), spdk_json_decode_int32},
789 	{"portals", offsetof(struct rpc_portal_group, portal_list), decode_rpc_portal_list},
790 };
791 
792 static void
793 spdk_rpc_iscsi_create_portal_group(struct spdk_jsonrpc_request *request,
794 				   const struct spdk_json_val *params)
795 {
796 	struct rpc_portal_group req = {};
797 	struct spdk_iscsi_portal_grp *pg = NULL;
798 	struct spdk_iscsi_portal *portal;
799 	struct spdk_json_write_ctx *w;
800 	size_t i = 0;
801 	int rc = -1;
802 
803 	if (spdk_json_decode_object(params, rpc_portal_group_decoders,
804 				    SPDK_COUNTOF(rpc_portal_group_decoders),
805 				    &req)) {
806 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
807 		goto out;
808 	}
809 
810 	pg = spdk_iscsi_portal_grp_create(req.tag);
811 	if (pg == NULL) {
812 		SPDK_ERRLOG("portal_grp_create failed\n");
813 		goto out;
814 	}
815 	for (i = 0; i < req.portal_list.num_portals; i++) {
816 		if (req.portal_list.portals[i].cpumask) {
817 			SPDK_WARNLOG("A portal was specified with a CPU mask which is no longer supported.\n");
818 			SPDK_WARNLOG("Ignoring the cpumask.\n");
819 		}
820 
821 		portal = spdk_iscsi_portal_create(req.portal_list.portals[i].host,
822 						  req.portal_list.portals[i].port);
823 		if (portal == NULL) {
824 			SPDK_ERRLOG("portal_create failed\n");
825 			goto out;
826 		}
827 		spdk_iscsi_portal_grp_add_portal(pg, portal);
828 	}
829 
830 	rc = spdk_iscsi_portal_grp_open(pg);
831 	if (rc != 0) {
832 		SPDK_ERRLOG("portal_grp_open failed\n");
833 		goto out;
834 	}
835 
836 	rc = spdk_iscsi_portal_grp_register(pg);
837 	if (rc != 0) {
838 		SPDK_ERRLOG("portal_grp_register failed\n");
839 	}
840 
841 out:
842 	if (rc == 0) {
843 		w = spdk_jsonrpc_begin_result(request);
844 		spdk_json_write_bool(w, true);
845 		spdk_jsonrpc_end_result(request, w);
846 	} else {
847 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
848 
849 		if (pg != NULL) {
850 			spdk_iscsi_portal_grp_release(pg);
851 		}
852 	}
853 	free_rpc_portal_group(&req);
854 }
855 SPDK_RPC_REGISTER("iscsi_create_portal_group", spdk_rpc_iscsi_create_portal_group, SPDK_RPC_RUNTIME)
856 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_create_portal_group, add_portal_group)
857 
858 struct rpc_iscsi_delete_portal_group {
859 	int32_t tag;
860 };
861 
862 static const struct spdk_json_object_decoder rpc_iscsi_delete_portal_group_decoders[] = {
863 	{"tag", offsetof(struct rpc_iscsi_delete_portal_group, tag), spdk_json_decode_int32},
864 };
865 
866 static void
867 spdk_rpc_iscsi_delete_portal_group(struct spdk_jsonrpc_request *request,
868 				   const struct spdk_json_val *params)
869 {
870 	struct rpc_iscsi_delete_portal_group req = {};
871 	struct spdk_json_write_ctx *w;
872 	struct spdk_iscsi_portal_grp *pg;
873 
874 	if (spdk_json_decode_object(params, rpc_iscsi_delete_portal_group_decoders,
875 				    SPDK_COUNTOF(rpc_iscsi_delete_portal_group_decoders),
876 				    &req)) {
877 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
878 		goto invalid;
879 	}
880 
881 	pg = spdk_iscsi_portal_grp_unregister(req.tag);
882 	if (!pg) {
883 		goto invalid;
884 	}
885 
886 	spdk_iscsi_tgt_node_delete_map(pg, NULL);
887 	spdk_iscsi_portal_grp_release(pg);
888 
889 	w = spdk_jsonrpc_begin_result(request);
890 	spdk_json_write_bool(w, true);
891 	spdk_jsonrpc_end_result(request, w);
892 	return;
893 
894 invalid:
895 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
896 }
897 SPDK_RPC_REGISTER("iscsi_delete_portal_group", spdk_rpc_iscsi_delete_portal_group, SPDK_RPC_RUNTIME)
898 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_delete_portal_group, delete_portal_group)
899 
900 struct rpc_iscsi_get_connections_ctx {
901 	struct spdk_jsonrpc_request *request;
902 	struct spdk_json_write_ctx *w;
903 };
904 
905 static void
906 rpc_iscsi_get_connections_done(struct spdk_io_channel_iter *i, int status)
907 {
908 	struct rpc_iscsi_get_connections_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
909 
910 	spdk_json_write_array_end(ctx->w);
911 	spdk_jsonrpc_end_result(ctx->request, ctx->w);
912 
913 	free(ctx);
914 }
915 
916 static void
917 rpc_iscsi_get_connections(struct spdk_io_channel_iter *i)
918 {
919 	struct rpc_iscsi_get_connections_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
920 	struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i);
921 	struct spdk_iscsi_poll_group *pg = spdk_io_channel_get_ctx(ch);
922 	struct spdk_iscsi_conn *conn;
923 
924 	STAILQ_FOREACH(conn, &pg->connections, link) {
925 		spdk_iscsi_conn_info_json(ctx->w, conn);
926 	}
927 
928 	spdk_for_each_channel_continue(i, 0);
929 }
930 
931 static void
932 spdk_rpc_iscsi_get_connections(struct spdk_jsonrpc_request *request,
933 			       const struct spdk_json_val *params)
934 {
935 	struct rpc_iscsi_get_connections_ctx *ctx;
936 
937 	if (params != NULL) {
938 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
939 						 "iscsi_get_connections requires no parameters");
940 		return;
941 	}
942 
943 	ctx = calloc(1, sizeof(struct rpc_iscsi_get_connections_ctx));
944 	if (ctx == NULL) {
945 		SPDK_ERRLOG("Failed to allocate rpc_get_iscsi_conns_ctx struct\n");
946 		spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
947 		return;
948 	}
949 
950 	ctx->request = request;
951 	ctx->w = spdk_jsonrpc_begin_result(request);
952 
953 	spdk_json_write_array_begin(ctx->w);
954 
955 	spdk_for_each_channel(&g_spdk_iscsi,
956 			      rpc_iscsi_get_connections,
957 			      ctx,
958 			      rpc_iscsi_get_connections_done);
959 }
960 SPDK_RPC_REGISTER("iscsi_get_connections", spdk_rpc_iscsi_get_connections, SPDK_RPC_RUNTIME)
961 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_get_connections, get_iscsi_connections)
962 
963 struct rpc_target_lun {
964 	char *name;
965 	char *bdev_name;
966 	int32_t lun_id;
967 };
968 
969 static void
970 free_rpc_target_lun(struct rpc_target_lun *req)
971 {
972 	free(req->name);
973 	free(req->bdev_name);
974 }
975 
976 static const struct spdk_json_object_decoder rpc_target_lun_decoders[] = {
977 	{"name", offsetof(struct rpc_target_lun, name), spdk_json_decode_string},
978 	{"bdev_name", offsetof(struct rpc_target_lun, bdev_name), spdk_json_decode_string},
979 	{"lun_id", offsetof(struct rpc_target_lun, lun_id), spdk_json_decode_int32, true},
980 };
981 
982 static void
983 spdk_rpc_iscsi_target_node_add_lun(struct spdk_jsonrpc_request *request,
984 				   const struct spdk_json_val *params)
985 {
986 	struct rpc_target_lun req = {};
987 	struct spdk_json_write_ctx *w;
988 	struct spdk_iscsi_tgt_node *target;
989 	int rc;
990 
991 	req.lun_id = -1;
992 
993 	if (spdk_json_decode_object(params, rpc_target_lun_decoders,
994 				    SPDK_COUNTOF(rpc_target_lun_decoders), &req)) {
995 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
996 		goto invalid;
997 	}
998 
999 	target = spdk_iscsi_find_tgt_node(req.name);
1000 	if (target == NULL) {
1001 		SPDK_ERRLOG("target is not found\n");
1002 		goto invalid;
1003 	}
1004 
1005 	rc = spdk_iscsi_tgt_node_add_lun(target, req.bdev_name, req.lun_id);
1006 	if (rc < 0) {
1007 		SPDK_ERRLOG("add lun failed\n");
1008 		goto invalid;
1009 	}
1010 
1011 	free_rpc_target_lun(&req);
1012 
1013 	w = spdk_jsonrpc_begin_result(request);
1014 	spdk_json_write_bool(w, true);
1015 	spdk_jsonrpc_end_result(request, w);
1016 	return;
1017 
1018 invalid:
1019 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1020 					 "Invalid parameters");
1021 	free_rpc_target_lun(&req);
1022 }
1023 SPDK_RPC_REGISTER("iscsi_target_node_add_lun", spdk_rpc_iscsi_target_node_add_lun, SPDK_RPC_RUNTIME)
1024 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_target_node_add_lun, target_node_add_lun)
1025 
1026 struct rpc_target_auth {
1027 	char *name;
1028 	bool disable_chap;
1029 	bool require_chap;
1030 	bool mutual_chap;
1031 	int32_t chap_group;
1032 };
1033 
1034 static void
1035 free_rpc_target_auth(struct rpc_target_auth *req)
1036 {
1037 	free(req->name);
1038 }
1039 
1040 static const struct spdk_json_object_decoder rpc_target_auth_decoders[] = {
1041 	{"name", offsetof(struct rpc_target_auth, name), spdk_json_decode_string},
1042 	{"disable_chap", offsetof(struct rpc_target_auth, disable_chap), spdk_json_decode_bool, true},
1043 	{"require_chap", offsetof(struct rpc_target_auth, require_chap), spdk_json_decode_bool, true},
1044 	{"mutual_chap", offsetof(struct rpc_target_auth, mutual_chap), spdk_json_decode_bool, true},
1045 	{"chap_group", offsetof(struct rpc_target_auth, chap_group), spdk_json_decode_int32, true},
1046 };
1047 
1048 static void
1049 spdk_rpc_iscsi_target_node_set_auth(struct spdk_jsonrpc_request *request,
1050 				    const struct spdk_json_val *params)
1051 {
1052 	struct rpc_target_auth req = {};
1053 	struct spdk_json_write_ctx *w;
1054 	struct spdk_iscsi_tgt_node *target;
1055 	int rc;
1056 
1057 	if (spdk_json_decode_object(params, rpc_target_auth_decoders,
1058 				    SPDK_COUNTOF(rpc_target_auth_decoders), &req)) {
1059 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1060 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1061 						 "Invalid parameters");
1062 		goto exit;
1063 	}
1064 
1065 	target = spdk_iscsi_find_tgt_node(req.name);
1066 	if (target == NULL) {
1067 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1068 						     "Could not find target %s", req.name);
1069 		goto exit;
1070 	}
1071 
1072 	rc = spdk_iscsi_tgt_node_set_chap_params(target, req.disable_chap, req.require_chap,
1073 			req.mutual_chap, req.chap_group);
1074 	if (rc < 0) {
1075 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1076 						 "Invalid combination of auth params");
1077 		goto exit;
1078 	}
1079 
1080 	free_rpc_target_auth(&req);
1081 
1082 	w = spdk_jsonrpc_begin_result(request);
1083 	spdk_json_write_bool(w, true);
1084 	spdk_jsonrpc_end_result(request, w);
1085 	return;
1086 
1087 exit:
1088 	free_rpc_target_auth(&req);
1089 }
1090 SPDK_RPC_REGISTER("iscsi_target_node_set_auth", spdk_rpc_iscsi_target_node_set_auth,
1091 		  SPDK_RPC_RUNTIME)
1092 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_target_node_set_auth, set_iscsi_target_node_auth)
1093 
1094 static void
1095 spdk_rpc_iscsi_get_options(struct spdk_jsonrpc_request *request,
1096 			   const struct spdk_json_val *params)
1097 {
1098 	struct spdk_json_write_ctx *w;
1099 
1100 	if (params != NULL) {
1101 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1102 						 "iscsi_get_options requires no parameters");
1103 		return;
1104 	}
1105 
1106 	w = spdk_jsonrpc_begin_result(request);
1107 	spdk_iscsi_opts_info_json(w);
1108 
1109 	spdk_jsonrpc_end_result(request, w);
1110 }
1111 SPDK_RPC_REGISTER("iscsi_get_options", spdk_rpc_iscsi_get_options, SPDK_RPC_RUNTIME)
1112 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_get_options, get_iscsi_global_params)
1113 
1114 struct rpc_discovery_auth {
1115 	bool disable_chap;
1116 	bool require_chap;
1117 	bool mutual_chap;
1118 	int32_t chap_group;
1119 };
1120 
1121 static const struct spdk_json_object_decoder rpc_discovery_auth_decoders[] = {
1122 	{"disable_chap", offsetof(struct rpc_discovery_auth, disable_chap), spdk_json_decode_bool, true},
1123 	{"require_chap", offsetof(struct rpc_discovery_auth, require_chap), spdk_json_decode_bool, true},
1124 	{"mutual_chap", offsetof(struct rpc_discovery_auth, mutual_chap), spdk_json_decode_bool, true},
1125 	{"chap_group", offsetof(struct rpc_discovery_auth, chap_group), spdk_json_decode_int32, true},
1126 };
1127 
1128 static void
1129 spdk_rpc_iscsi_set_discovery_auth(struct spdk_jsonrpc_request *request,
1130 				  const struct spdk_json_val *params)
1131 {
1132 	struct rpc_discovery_auth req = {};
1133 	struct spdk_json_write_ctx *w;
1134 	int rc;
1135 
1136 	if (spdk_json_decode_object(params, rpc_discovery_auth_decoders,
1137 				    SPDK_COUNTOF(rpc_discovery_auth_decoders), &req)) {
1138 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1139 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1140 						 "Invalid parameters");
1141 		return;
1142 	}
1143 
1144 	rc = spdk_iscsi_set_discovery_auth(req.disable_chap, req.require_chap,
1145 					   req.mutual_chap, req.chap_group);
1146 	if (rc < 0) {
1147 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1148 						 "Invalid combination of CHAP params");
1149 		return;
1150 	}
1151 
1152 	w = spdk_jsonrpc_begin_result(request);
1153 	spdk_json_write_bool(w, true);
1154 	spdk_jsonrpc_end_result(request, w);
1155 }
1156 SPDK_RPC_REGISTER("iscsi_set_discovery_auth", spdk_rpc_iscsi_set_discovery_auth, SPDK_RPC_RUNTIME)
1157 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_set_discovery_auth, set_iscsi_discovery_auth)
1158 
1159 #define MAX_AUTH_SECRETS	64
1160 
1161 struct rpc_auth_secret {
1162 	char *user;
1163 	char *secret;
1164 	char *muser;
1165 	char *msecret;
1166 };
1167 
1168 static void
1169 free_rpc_auth_secret(struct rpc_auth_secret *_secret)
1170 {
1171 	free(_secret->user);
1172 	free(_secret->secret);
1173 	free(_secret->muser);
1174 	free(_secret->msecret);
1175 }
1176 
1177 static const struct spdk_json_object_decoder rpc_auth_secret_decoders[] = {
1178 	{"user", offsetof(struct rpc_auth_secret, user), spdk_json_decode_string},
1179 	{"secret", offsetof(struct rpc_auth_secret, secret), spdk_json_decode_string},
1180 	{"muser", offsetof(struct rpc_auth_secret, muser), spdk_json_decode_string, true},
1181 	{"msecret", offsetof(struct rpc_auth_secret, msecret), spdk_json_decode_string, true},
1182 };
1183 
1184 static int
1185 decode_rpc_auth_secret(const struct spdk_json_val *val, void *out)
1186 {
1187 	struct rpc_auth_secret *_secret = out;
1188 
1189 	return spdk_json_decode_object(val, rpc_auth_secret_decoders,
1190 				       SPDK_COUNTOF(rpc_auth_secret_decoders), _secret);
1191 }
1192 
1193 struct rpc_auth_secrets {
1194 	size_t num_secret;
1195 	struct rpc_auth_secret secrets[MAX_AUTH_SECRETS];
1196 };
1197 
1198 static void
1199 free_rpc_auth_secrets(struct rpc_auth_secrets *secrets)
1200 {
1201 	size_t i;
1202 
1203 	for (i = 0; i < secrets->num_secret; i++) {
1204 		free_rpc_auth_secret(&secrets->secrets[i]);
1205 	}
1206 }
1207 
1208 static int
1209 decode_rpc_auth_secrets(const struct spdk_json_val *val, void *out)
1210 {
1211 	struct rpc_auth_secrets *secrets = out;
1212 
1213 	return spdk_json_decode_array(val, decode_rpc_auth_secret, secrets->secrets,
1214 				      MAX_AUTH_SECRETS, &secrets->num_secret,
1215 				      sizeof(struct rpc_auth_secret));
1216 }
1217 
1218 struct rpc_auth_group {
1219 	int32_t tag;
1220 	struct rpc_auth_secrets secrets;
1221 };
1222 
1223 static void
1224 free_rpc_auth_group(struct rpc_auth_group *group)
1225 {
1226 	free_rpc_auth_secrets(&group->secrets);
1227 }
1228 
1229 static const struct spdk_json_object_decoder rpc_auth_group_decoders[] = {
1230 	{"tag", offsetof(struct rpc_auth_group, tag), spdk_json_decode_int32},
1231 	{"secrets", offsetof(struct rpc_auth_group, secrets), decode_rpc_auth_secrets, true},
1232 };
1233 
1234 static void
1235 spdk_rpc_iscsi_create_auth_group(struct spdk_jsonrpc_request *request,
1236 				 const struct spdk_json_val *params)
1237 {
1238 	struct rpc_auth_group req = {};
1239 	struct rpc_auth_secret *_secret;
1240 	struct spdk_json_write_ctx *w;
1241 	struct spdk_iscsi_auth_group *group = NULL;
1242 	int rc;
1243 	size_t i;
1244 
1245 	if (spdk_json_decode_object(params, rpc_auth_group_decoders,
1246 				    SPDK_COUNTOF(rpc_auth_group_decoders), &req)) {
1247 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1248 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1249 						 "Invalid parameters");
1250 		free_rpc_auth_group(&req);
1251 		return;
1252 	}
1253 
1254 	pthread_mutex_lock(&g_spdk_iscsi.mutex);
1255 
1256 	rc = spdk_iscsi_add_auth_group(req.tag, &group);
1257 	if (rc != 0) {
1258 		pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1259 
1260 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1261 						     "Could not add auth group (%d), %s",
1262 						     req.tag, spdk_strerror(-rc));
1263 		free_rpc_auth_group(&req);
1264 		return;
1265 	}
1266 
1267 	for (i = 0; i < req.secrets.num_secret; i++) {
1268 		_secret = &req.secrets.secrets[i];
1269 		rc = spdk_iscsi_auth_group_add_secret(group, _secret->user, _secret->secret,
1270 						      _secret->muser, _secret->msecret);
1271 		if (rc != 0) {
1272 			spdk_iscsi_delete_auth_group(group);
1273 			pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1274 
1275 			spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1276 							     "Could not add secret to auth group (%d), %s",
1277 							     req.tag, spdk_strerror(-rc));
1278 			free_rpc_auth_group(&req);
1279 			return;
1280 		}
1281 	}
1282 
1283 	pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1284 
1285 	free_rpc_auth_group(&req);
1286 
1287 	w = spdk_jsonrpc_begin_result(request);
1288 	spdk_json_write_bool(w, true);
1289 	spdk_jsonrpc_end_result(request, w);
1290 }
1291 SPDK_RPC_REGISTER("iscsi_create_auth_group", spdk_rpc_iscsi_create_auth_group, SPDK_RPC_RUNTIME)
1292 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_create_auth_group, add_iscsi_auth_group)
1293 
1294 struct rpc_delete_auth_group {
1295 	int32_t tag;
1296 };
1297 
1298 static const struct spdk_json_object_decoder rpc_delete_auth_group_decoders[] = {
1299 	{"tag", offsetof(struct rpc_delete_auth_group, tag), spdk_json_decode_int32},
1300 };
1301 
1302 static void
1303 spdk_rpc_iscsi_delete_auth_group(struct spdk_jsonrpc_request *request,
1304 				 const struct spdk_json_val *params)
1305 {
1306 	struct rpc_delete_auth_group req = {};
1307 	struct spdk_json_write_ctx *w;
1308 	struct spdk_iscsi_auth_group *group;
1309 
1310 	if (spdk_json_decode_object(params, rpc_delete_auth_group_decoders,
1311 				    SPDK_COUNTOF(rpc_delete_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 		return;
1316 	}
1317 
1318 	pthread_mutex_lock(&g_spdk_iscsi.mutex);
1319 
1320 	group = spdk_iscsi_find_auth_group_by_tag(req.tag);
1321 	if (group == NULL) {
1322 		pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1323 
1324 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1325 						     "Could not find auth group (%d)", req.tag);
1326 		return;
1327 	}
1328 
1329 	spdk_iscsi_delete_auth_group(group);
1330 
1331 	pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1332 
1333 	w = spdk_jsonrpc_begin_result(request);
1334 	spdk_json_write_bool(w, true);
1335 	spdk_jsonrpc_end_result(request, w);
1336 }
1337 SPDK_RPC_REGISTER("iscsi_delete_auth_group", spdk_rpc_iscsi_delete_auth_group, SPDK_RPC_RUNTIME)
1338 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_delete_auth_group, delete_iscsi_auth_group)
1339 
1340 struct rpc_add_auth_secret {
1341 	int32_t tag;
1342 	char *user;
1343 	char *secret;
1344 	char *muser;
1345 	char *msecret;
1346 };
1347 
1348 static void
1349 free_rpc_add_auth_secret(struct rpc_add_auth_secret *_secret)
1350 {
1351 	free(_secret->user);
1352 	free(_secret->secret);
1353 	free(_secret->muser);
1354 	free(_secret->msecret);
1355 }
1356 
1357 static const struct spdk_json_object_decoder rpc_add_auth_secret_decoders[] = {
1358 	{"tag", offsetof(struct rpc_add_auth_secret, tag), spdk_json_decode_int32},
1359 	{"user", offsetof(struct rpc_add_auth_secret, user), spdk_json_decode_string},
1360 	{"secret", offsetof(struct rpc_add_auth_secret, secret), spdk_json_decode_string},
1361 	{"muser", offsetof(struct rpc_add_auth_secret, muser), spdk_json_decode_string, true},
1362 	{"msecret", offsetof(struct rpc_add_auth_secret, msecret), spdk_json_decode_string, true},
1363 };
1364 
1365 static void
1366 spdk_rpc_iscsi_auth_group_add_secret(struct spdk_jsonrpc_request *request,
1367 				     const struct spdk_json_val *params)
1368 {
1369 	struct rpc_add_auth_secret req = {};
1370 	struct spdk_json_write_ctx *w;
1371 	struct spdk_iscsi_auth_group *group;
1372 	int rc;
1373 
1374 	if (spdk_json_decode_object(params, rpc_add_auth_secret_decoders,
1375 				    SPDK_COUNTOF(rpc_add_auth_secret_decoders), &req)) {
1376 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1377 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1378 						 "Invalid parameters");
1379 		free_rpc_add_auth_secret(&req);
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 		free_rpc_add_auth_secret(&req);
1392 		return;
1393 	}
1394 
1395 	rc = spdk_iscsi_auth_group_add_secret(group, req.user, req.secret, req.muser, req.msecret);
1396 	if (rc != 0) {
1397 		pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1398 
1399 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1400 						     "Could not add secret to auth group (%d), %s",
1401 						     req.tag, spdk_strerror(-rc));
1402 		free_rpc_add_auth_secret(&req);
1403 		return;
1404 	}
1405 
1406 	pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1407 
1408 	free_rpc_add_auth_secret(&req);
1409 
1410 	w = spdk_jsonrpc_begin_result(request);
1411 	spdk_json_write_bool(w, true);
1412 	spdk_jsonrpc_end_result(request, w);
1413 }
1414 SPDK_RPC_REGISTER("iscsi_auth_group_add_secret", spdk_rpc_iscsi_auth_group_add_secret,
1415 		  SPDK_RPC_RUNTIME)
1416 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_auth_group_add_secret, add_secret_to_iscsi_auth_group)
1417 
1418 
1419 struct rpc_remove_auth_secret {
1420 	int32_t tag;
1421 	char *user;
1422 };
1423 
1424 static void
1425 free_rpc_remove_auth_secret(struct rpc_remove_auth_secret *_secret)
1426 {
1427 	free(_secret->user);
1428 }
1429 
1430 static const struct spdk_json_object_decoder rpc_remove_auth_secret_decoders[] = {
1431 	{"tag", offsetof(struct rpc_remove_auth_secret, tag), spdk_json_decode_int32},
1432 	{"user", offsetof(struct rpc_remove_auth_secret, user), spdk_json_decode_string},
1433 };
1434 
1435 static void
1436 spdk_rpc_iscsi_auth_group_remove_secret(struct spdk_jsonrpc_request *request,
1437 					const struct spdk_json_val *params)
1438 {
1439 	struct rpc_remove_auth_secret req = {};
1440 	struct spdk_json_write_ctx *w;
1441 	struct spdk_iscsi_auth_group *group;
1442 	int rc;
1443 
1444 	if (spdk_json_decode_object(params, rpc_remove_auth_secret_decoders,
1445 				    SPDK_COUNTOF(rpc_remove_auth_secret_decoders), &req)) {
1446 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1447 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1448 						 "Invalid parameters");
1449 		free_rpc_remove_auth_secret(&req);
1450 		return;
1451 	}
1452 
1453 	pthread_mutex_lock(&g_spdk_iscsi.mutex);
1454 
1455 	group = spdk_iscsi_find_auth_group_by_tag(req.tag);
1456 	if (group == NULL) {
1457 		pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1458 
1459 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1460 						     "Could not find auth group (%d)", req.tag);
1461 		free_rpc_remove_auth_secret(&req);
1462 		return;
1463 	}
1464 
1465 	rc = spdk_iscsi_auth_group_delete_secret(group, req.user);
1466 	if (rc != 0) {
1467 		pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1468 
1469 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1470 						     "Could not delete secret from CHAP group (%d), %s",
1471 						     req.tag, spdk_strerror(-rc));
1472 		free_rpc_remove_auth_secret(&req);
1473 		return;
1474 	}
1475 
1476 	pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1477 
1478 	free_rpc_remove_auth_secret(&req);
1479 
1480 	w = spdk_jsonrpc_begin_result(request);
1481 	spdk_json_write_bool(w, true);
1482 	spdk_jsonrpc_end_result(request, w);
1483 }
1484 SPDK_RPC_REGISTER("iscsi_auth_group_remove_secret",
1485 		  spdk_rpc_iscsi_auth_group_remove_secret, SPDK_RPC_RUNTIME)
1486 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_auth_group_remove_secret,
1487 				   delete_secret_from_iscsi_auth_group)
1488 
1489 static void
1490 spdk_rpc_iscsi_get_auth_groups(struct spdk_jsonrpc_request *request,
1491 			       const struct spdk_json_val *params)
1492 {
1493 	struct spdk_json_write_ctx *w;
1494 
1495 	if (params != NULL) {
1496 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1497 						 "iscsi_get_auth_groups requires no parameters");
1498 		return;
1499 	}
1500 
1501 	w = spdk_jsonrpc_begin_result(request);
1502 	spdk_json_write_array_begin(w);
1503 	spdk_iscsi_auth_groups_info_json(w);
1504 	spdk_json_write_array_end(w);
1505 
1506 	spdk_jsonrpc_end_result(request, w);
1507 }
1508 SPDK_RPC_REGISTER("iscsi_get_auth_groups", spdk_rpc_iscsi_get_auth_groups, SPDK_RPC_RUNTIME)
1509 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_get_auth_groups, get_iscsi_auth_groups)
1510 
1511 static const struct spdk_json_object_decoder rpc_set_iscsi_opts_decoders[] = {
1512 	{"auth_file", offsetof(struct spdk_iscsi_opts, authfile), spdk_json_decode_string, true},
1513 	{"node_base", offsetof(struct spdk_iscsi_opts, nodebase), spdk_json_decode_string, true},
1514 	{"nop_timeout", offsetof(struct spdk_iscsi_opts, timeout), spdk_json_decode_int32, true},
1515 	{"nop_in_interval", offsetof(struct spdk_iscsi_opts, nopininterval), spdk_json_decode_int32, true},
1516 	{"no_discovery_auth", offsetof(struct spdk_iscsi_opts, disable_chap), spdk_json_decode_bool, true},
1517 	{"req_discovery_auth", offsetof(struct spdk_iscsi_opts, require_chap), spdk_json_decode_bool, true},
1518 	{"req_discovery_auth_mutual", offsetof(struct spdk_iscsi_opts, mutual_chap), spdk_json_decode_bool, true},
1519 	{"discovery_auth_group", offsetof(struct spdk_iscsi_opts, chap_group), spdk_json_decode_int32, true},
1520 	{"disable_chap", offsetof(struct spdk_iscsi_opts, disable_chap), spdk_json_decode_bool, true},
1521 	{"require_chap", offsetof(struct spdk_iscsi_opts, require_chap), spdk_json_decode_bool, true},
1522 	{"mutual_chap", offsetof(struct spdk_iscsi_opts, mutual_chap), spdk_json_decode_bool, true},
1523 	{"chap_group", offsetof(struct spdk_iscsi_opts, chap_group), spdk_json_decode_int32, true},
1524 	{"max_sessions", offsetof(struct spdk_iscsi_opts, MaxSessions), spdk_json_decode_uint32, true},
1525 	{"max_queue_depth", offsetof(struct spdk_iscsi_opts, MaxQueueDepth), spdk_json_decode_uint32, true},
1526 	{"max_connections_per_session", offsetof(struct spdk_iscsi_opts, MaxConnectionsPerSession), spdk_json_decode_uint32, true},
1527 	{"default_time2wait", offsetof(struct spdk_iscsi_opts, DefaultTime2Wait), spdk_json_decode_uint32, true},
1528 	{"default_time2retain", offsetof(struct spdk_iscsi_opts, DefaultTime2Retain), spdk_json_decode_uint32, true},
1529 	{"first_burst_length", offsetof(struct spdk_iscsi_opts, FirstBurstLength), spdk_json_decode_uint32, true},
1530 	{"immediate_data", offsetof(struct spdk_iscsi_opts, ImmediateData), spdk_json_decode_bool, true},
1531 	{"error_recovery_level", offsetof(struct spdk_iscsi_opts, ErrorRecoveryLevel), spdk_json_decode_uint32, true},
1532 	{"allow_duplicated_isid", offsetof(struct spdk_iscsi_opts, AllowDuplicateIsid), spdk_json_decode_bool, true},
1533 };
1534 
1535 static void
1536 spdk_rpc_iscsi_set_options(struct spdk_jsonrpc_request *request,
1537 			   const struct spdk_json_val *params)
1538 {
1539 	struct spdk_iscsi_opts *opts;
1540 	struct spdk_json_write_ctx *w;
1541 
1542 	if (g_spdk_iscsi_opts != NULL) {
1543 		SPDK_ERRLOG("this RPC must not be called more than once.\n");
1544 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1545 						 "Must not call more than once");
1546 		return;
1547 	}
1548 
1549 	opts = spdk_iscsi_opts_alloc();
1550 	if (opts == NULL) {
1551 		SPDK_ERRLOG("spdk_iscsi_opts_alloc() failed.\n");
1552 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1553 						 "Out of memory");
1554 		return;
1555 	}
1556 
1557 	if (params != NULL) {
1558 		if (spdk_json_decode_object(params, rpc_set_iscsi_opts_decoders,
1559 					    SPDK_COUNTOF(rpc_set_iscsi_opts_decoders), opts)) {
1560 			SPDK_ERRLOG("spdk_json_decode_object() failed\n");
1561 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1562 							 "Invalid parameters");
1563 			spdk_iscsi_opts_free(opts);
1564 			return;
1565 		}
1566 	}
1567 
1568 	g_spdk_iscsi_opts = spdk_iscsi_opts_copy(opts);
1569 	spdk_iscsi_opts_free(opts);
1570 
1571 	if (g_spdk_iscsi_opts == NULL) {
1572 		SPDK_ERRLOG("spdk_iscsi_opts_copy() failed\n");
1573 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1574 						 "Out of memory");
1575 		return;
1576 	}
1577 
1578 	w = spdk_jsonrpc_begin_result(request);
1579 	spdk_json_write_bool(w, true);
1580 	spdk_jsonrpc_end_result(request, w);
1581 }
1582 SPDK_RPC_REGISTER("iscsi_set_options", spdk_rpc_iscsi_set_options, SPDK_RPC_STARTUP)
1583 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_set_options, set_iscsi_options)
1584