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