xref: /spdk/lib/iscsi/iscsi_rpc.c (revision 0098e636761237b77c12c30c2408263a5d2260cc)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
3  *   Copyright (c) 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 	spdk_jsonrpc_send_bool_response(ctx->request, rc == 0);
591 	free(ctx);
592 }
593 
594 static void
595 rpc_iscsi_delete_target_node(struct spdk_jsonrpc_request *request,
596 			     const struct spdk_json_val *params)
597 {
598 	struct rpc_iscsi_delete_target_node_ctx *ctx;
599 
600 	ctx = calloc(1, sizeof(*ctx));
601 	if (!ctx) {
602 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
603 						 spdk_strerror(ENOMEM));
604 		return;
605 	}
606 
607 	if (spdk_json_decode_object(params, rpc_iscsi_delete_target_node_decoders,
608 				    SPDK_COUNTOF(rpc_iscsi_delete_target_node_decoders),
609 				    &ctx->req)) {
610 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
611 		goto invalid;
612 	}
613 
614 	if (ctx->req.name == NULL) {
615 		SPDK_ERRLOG("missing name param\n");
616 		goto invalid;
617 	}
618 
619 	ctx->request = request;
620 
621 	iscsi_shutdown_tgt_node_by_name(ctx->req.name,
622 					rpc_iscsi_delete_target_node_done, ctx);
623 	return;
624 
625 invalid:
626 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
627 	free_rpc_iscsi_delete_target_node(&ctx->req);
628 	free(ctx);
629 }
630 SPDK_RPC_REGISTER("iscsi_delete_target_node", rpc_iscsi_delete_target_node, SPDK_RPC_RUNTIME)
631 
632 static void
633 rpc_iscsi_get_portal_groups(struct spdk_jsonrpc_request *request,
634 			    const struct spdk_json_val *params)
635 {
636 	struct spdk_json_write_ctx *w;
637 
638 	if (params != NULL) {
639 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
640 						 "iscsi_get_portal_groups requires no parameters");
641 		return;
642 	}
643 
644 	w = spdk_jsonrpc_begin_result(request);
645 	spdk_json_write_array_begin(w);
646 	iscsi_portal_grps_info_json(w);
647 	spdk_json_write_array_end(w);
648 
649 	spdk_jsonrpc_end_result(request, w);
650 }
651 SPDK_RPC_REGISTER("iscsi_get_portal_groups", rpc_iscsi_get_portal_groups, SPDK_RPC_RUNTIME)
652 
653 struct rpc_portal {
654 	char *host;
655 	char *port;
656 };
657 
658 struct rpc_portal_list {
659 	size_t num_portals;
660 	struct rpc_portal portals[MAX_PORTAL];
661 };
662 
663 struct rpc_portal_group {
664 	int32_t tag;
665 	struct rpc_portal_list portal_list;
666 	bool is_private;
667 	bool wait;
668 };
669 
670 static void
671 free_rpc_portal(struct rpc_portal *portal)
672 {
673 	free(portal->host);
674 	free(portal->port);
675 }
676 
677 static void
678 free_rpc_portal_list(struct rpc_portal_list *pl)
679 {
680 	size_t i;
681 
682 	for (i = 0; i < pl->num_portals; i++) {
683 		free_rpc_portal(&pl->portals[i]);
684 	}
685 	pl->num_portals = 0;
686 }
687 
688 static void
689 free_rpc_portal_group(struct rpc_portal_group *pg)
690 {
691 	free_rpc_portal_list(&pg->portal_list);
692 }
693 
694 static const struct spdk_json_object_decoder rpc_portal_decoders[] = {
695 	{"host", offsetof(struct rpc_portal, host), spdk_json_decode_string},
696 	{"port", offsetof(struct rpc_portal, port), spdk_json_decode_string},
697 };
698 
699 static int
700 decode_rpc_portal(const struct spdk_json_val *val, void *out)
701 {
702 	struct rpc_portal *portal = out;
703 
704 	return spdk_json_decode_object(val, rpc_portal_decoders,
705 				       SPDK_COUNTOF(rpc_portal_decoders),
706 				       portal);
707 }
708 
709 static int
710 decode_rpc_portal_list(const struct spdk_json_val *val, void *out)
711 {
712 	struct rpc_portal_list *list = out;
713 
714 	return spdk_json_decode_array(val, decode_rpc_portal, list->portals, MAX_PORTAL, &list->num_portals,
715 				      sizeof(struct rpc_portal));
716 }
717 
718 static const struct spdk_json_object_decoder rpc_portal_group_decoders[] = {
719 	{"tag", offsetof(struct rpc_portal_group, tag), spdk_json_decode_int32},
720 	{"portals", offsetof(struct rpc_portal_group, portal_list), decode_rpc_portal_list},
721 	{"private", offsetof(struct rpc_portal_group, is_private), spdk_json_decode_bool, true},
722 	{"wait", offsetof(struct rpc_portal_group, wait), spdk_json_decode_bool, true},
723 };
724 
725 static void
726 rpc_iscsi_create_portal_group(struct spdk_jsonrpc_request *request,
727 			      const struct spdk_json_val *params)
728 {
729 	struct rpc_portal_group req = {};
730 	struct spdk_iscsi_portal_grp *pg = NULL;
731 	struct spdk_iscsi_portal *portal;
732 	size_t i = 0;
733 	int rc = -1;
734 
735 	if (spdk_json_decode_object(params, rpc_portal_group_decoders,
736 				    SPDK_COUNTOF(rpc_portal_group_decoders),
737 				    &req)) {
738 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
739 		goto out;
740 	}
741 
742 	pg = iscsi_portal_grp_create(req.tag, req.is_private);
743 	if (pg == NULL) {
744 		SPDK_ERRLOG("portal_grp_create failed\n");
745 		goto out;
746 	}
747 	for (i = 0; i < req.portal_list.num_portals; i++) {
748 		portal = iscsi_portal_create(req.portal_list.portals[i].host,
749 					     req.portal_list.portals[i].port);
750 		if (portal == NULL) {
751 			SPDK_ERRLOG("portal_create failed\n");
752 			goto out;
753 		}
754 		iscsi_portal_grp_add_portal(pg, portal);
755 	}
756 
757 	rc = iscsi_portal_grp_open(pg, req.wait);
758 	if (rc != 0) {
759 		SPDK_ERRLOG("portal_grp_open failed\n");
760 		goto out;
761 	}
762 
763 	rc = iscsi_portal_grp_register(pg);
764 	if (rc != 0) {
765 		SPDK_ERRLOG("portal_grp_register failed\n");
766 	}
767 
768 out:
769 	if (rc == 0) {
770 		spdk_jsonrpc_send_bool_response(request, true);
771 	} else {
772 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
773 
774 		if (pg != NULL) {
775 			iscsi_portal_grp_release(pg);
776 		}
777 	}
778 	free_rpc_portal_group(&req);
779 }
780 SPDK_RPC_REGISTER("iscsi_create_portal_group", rpc_iscsi_create_portal_group, SPDK_RPC_RUNTIME)
781 
782 struct rpc_iscsi_change_portal_group {
783 	int32_t tag;
784 };
785 
786 static const struct spdk_json_object_decoder rpc_iscsi_change_portal_group_decoders[] = {
787 	{"tag", offsetof(struct rpc_iscsi_change_portal_group, tag), spdk_json_decode_int32},
788 };
789 
790 typedef int (*iscsi_change_portal_grp_fn)(int pg_tag);
791 
792 static void
793 _rpc_iscsi_change_portal_group(struct spdk_jsonrpc_request *request,
794 			       const struct spdk_json_val *params,
795 			       iscsi_change_portal_grp_fn fn)
796 {
797 	struct rpc_iscsi_change_portal_group req = {};
798 	int rc;
799 
800 	if (spdk_json_decode_object(params, rpc_iscsi_change_portal_group_decoders,
801 				    SPDK_COUNTOF(rpc_iscsi_change_portal_group_decoders),
802 				    &req)) {
803 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
804 		goto invalid;
805 	}
806 
807 	rc = fn(req.tag);
808 	if (rc != 0) {
809 		goto invalid;
810 	}
811 
812 	spdk_jsonrpc_send_bool_response(request, true);
813 	return;
814 
815 invalid:
816 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
817 }
818 
819 static int
820 _rpc_iscsi_delete_portal_group(int pg_tag)
821 {
822 	struct spdk_iscsi_portal_grp *pg;
823 
824 	pg = iscsi_portal_grp_unregister(pg_tag);
825 	if (!pg) {
826 		return -ENODEV;
827 	}
828 
829 	iscsi_tgt_node_delete_map(pg, NULL);
830 	iscsi_portal_grp_release(pg);
831 	return 0;
832 }
833 
834 static void
835 rpc_iscsi_delete_portal_group(struct spdk_jsonrpc_request *request,
836 			      const struct spdk_json_val *params)
837 {
838 	_rpc_iscsi_change_portal_group(request, params, _rpc_iscsi_delete_portal_group);
839 }
840 SPDK_RPC_REGISTER("iscsi_delete_portal_group", rpc_iscsi_delete_portal_group, SPDK_RPC_RUNTIME)
841 
842 static int
843 _rpc_iscsi_start_portal_group(int pg_tag)
844 {
845 	struct spdk_iscsi_portal_grp *pg;
846 
847 	pg = iscsi_portal_grp_find_by_tag(pg_tag);
848 	if (!pg) {
849 		return -ENODEV;
850 	}
851 
852 	iscsi_portal_grp_resume(pg);
853 	return 0;
854 }
855 
856 static void
857 rpc_iscsi_start_portal_group(struct spdk_jsonrpc_request *request,
858 			     const struct spdk_json_val *params)
859 {
860 	_rpc_iscsi_change_portal_group(request, params, _rpc_iscsi_start_portal_group);
861 }
862 SPDK_RPC_REGISTER("iscsi_start_portal_group", rpc_iscsi_start_portal_group, SPDK_RPC_RUNTIME)
863 
864 struct rpc_portal_group_auth {
865 	int32_t tag;
866 	bool disable_chap;
867 	bool require_chap;
868 	bool mutual_chap;
869 	int32_t chap_group;
870 };
871 
872 static const struct spdk_json_object_decoder rpc_portal_group_auth_decoders[] = {
873 	{"tag", offsetof(struct rpc_portal_group_auth, tag), spdk_json_decode_int32},
874 	{"disable_chap", offsetof(struct rpc_portal_group_auth, disable_chap), spdk_json_decode_bool, true},
875 	{"require_chap", offsetof(struct rpc_portal_group_auth, require_chap), spdk_json_decode_bool, true},
876 	{"mutual_chap", offsetof(struct rpc_portal_group_auth, mutual_chap), spdk_json_decode_bool, true},
877 	{"chap_group", offsetof(struct rpc_portal_group_auth, chap_group), spdk_json_decode_int32, true},
878 };
879 
880 static void
881 rpc_iscsi_portal_group_set_auth(struct spdk_jsonrpc_request *request,
882 				const struct spdk_json_val *params)
883 {
884 	struct rpc_portal_group_auth req = {};
885 	struct spdk_iscsi_portal_grp *pg;
886 	int rc;
887 
888 	if (spdk_json_decode_object(params, rpc_portal_group_auth_decoders,
889 				    SPDK_COUNTOF(rpc_portal_group_auth_decoders), &req)) {
890 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
891 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
892 						 "Invalid parameters");
893 		return;
894 	}
895 
896 	pthread_mutex_lock(&g_iscsi.mutex);
897 
898 	pg = iscsi_portal_grp_find_by_tag(req.tag);
899 	if (pg == NULL) {
900 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
901 						     "Could not find portal group %d", req.tag);
902 		goto exit;
903 	}
904 
905 	rc = iscsi_portal_grp_set_chap_params(pg, req.disable_chap, req.require_chap,
906 					      req.mutual_chap, req.chap_group);
907 	if (rc < 0) {
908 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
909 						 "Invalid combination of auth params");
910 		goto exit;
911 	}
912 
913 	pthread_mutex_unlock(&g_iscsi.mutex);
914 
915 	spdk_jsonrpc_send_bool_response(request, true);
916 	return;
917 
918 exit:
919 	pthread_mutex_unlock(&g_iscsi.mutex);
920 }
921 SPDK_RPC_REGISTER("iscsi_portal_group_set_auth", rpc_iscsi_portal_group_set_auth,
922 		  SPDK_RPC_RUNTIME)
923 
924 struct rpc_iscsi_get_connections_ctx {
925 	struct spdk_jsonrpc_request *request;
926 	struct spdk_json_write_ctx *w;
927 };
928 
929 static void
930 _rpc_iscsi_get_connections_done(struct spdk_io_channel_iter *i, int status)
931 {
932 	struct rpc_iscsi_get_connections_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
933 
934 	spdk_json_write_array_end(ctx->w);
935 	spdk_jsonrpc_end_result(ctx->request, ctx->w);
936 
937 	free(ctx);
938 }
939 
940 static void
941 _rpc_iscsi_get_connections(struct spdk_io_channel_iter *i)
942 {
943 	struct rpc_iscsi_get_connections_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
944 	struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i);
945 	struct spdk_iscsi_poll_group *pg = spdk_io_channel_get_ctx(ch);
946 	struct spdk_iscsi_conn *conn;
947 
948 	STAILQ_FOREACH(conn, &pg->connections, pg_link) {
949 		iscsi_conn_info_json(ctx->w, conn);
950 	}
951 
952 	spdk_for_each_channel_continue(i, 0);
953 }
954 
955 static void
956 rpc_iscsi_get_connections(struct spdk_jsonrpc_request *request,
957 			  const struct spdk_json_val *params)
958 {
959 	struct rpc_iscsi_get_connections_ctx *ctx;
960 
961 	if (params != NULL) {
962 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
963 						 "iscsi_get_connections requires no parameters");
964 		return;
965 	}
966 
967 	ctx = calloc(1, sizeof(struct rpc_iscsi_get_connections_ctx));
968 	if (ctx == NULL) {
969 		SPDK_ERRLOG("Failed to allocate rpc_get_iscsi_conns_ctx struct\n");
970 		spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
971 		return;
972 	}
973 
974 	ctx->request = request;
975 	ctx->w = spdk_jsonrpc_begin_result(request);
976 
977 	spdk_json_write_array_begin(ctx->w);
978 
979 	spdk_for_each_channel(&g_iscsi,
980 			      _rpc_iscsi_get_connections,
981 			      ctx,
982 			      _rpc_iscsi_get_connections_done);
983 }
984 SPDK_RPC_REGISTER("iscsi_get_connections", rpc_iscsi_get_connections, SPDK_RPC_RUNTIME)
985 
986 struct rpc_target_lun {
987 	char *name;
988 	char *bdev_name;
989 	int32_t lun_id;
990 };
991 
992 static void
993 free_rpc_target_lun(struct rpc_target_lun *req)
994 {
995 	free(req->name);
996 	free(req->bdev_name);
997 }
998 
999 static const struct spdk_json_object_decoder rpc_target_lun_decoders[] = {
1000 	{"name", offsetof(struct rpc_target_lun, name), spdk_json_decode_string},
1001 	{"bdev_name", offsetof(struct rpc_target_lun, bdev_name), spdk_json_decode_string},
1002 	{"lun_id", offsetof(struct rpc_target_lun, lun_id), spdk_json_decode_int32, true},
1003 };
1004 
1005 static void
1006 rpc_iscsi_target_node_add_lun(struct spdk_jsonrpc_request *request,
1007 			      const struct spdk_json_val *params)
1008 {
1009 	struct rpc_target_lun req = {};
1010 	struct spdk_iscsi_tgt_node *target;
1011 	int rc;
1012 
1013 	req.lun_id = -1;
1014 
1015 	if (spdk_json_decode_object(params, rpc_target_lun_decoders,
1016 				    SPDK_COUNTOF(rpc_target_lun_decoders), &req)) {
1017 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1018 		goto invalid;
1019 	}
1020 
1021 	target = iscsi_find_tgt_node(req.name);
1022 	if (target == NULL) {
1023 		SPDK_ERRLOG("target is not found\n");
1024 		goto invalid;
1025 	}
1026 
1027 	rc = iscsi_tgt_node_add_lun(target, req.bdev_name, req.lun_id);
1028 	if (rc < 0) {
1029 		SPDK_ERRLOG("add lun failed\n");
1030 		goto invalid;
1031 	}
1032 
1033 	free_rpc_target_lun(&req);
1034 
1035 	spdk_jsonrpc_send_bool_response(request, true);
1036 	return;
1037 
1038 invalid:
1039 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1040 					 "Invalid parameters");
1041 	free_rpc_target_lun(&req);
1042 }
1043 SPDK_RPC_REGISTER("iscsi_target_node_add_lun", rpc_iscsi_target_node_add_lun, SPDK_RPC_RUNTIME)
1044 
1045 struct rpc_target_auth {
1046 	char *name;
1047 	bool disable_chap;
1048 	bool require_chap;
1049 	bool mutual_chap;
1050 	int32_t chap_group;
1051 };
1052 
1053 static void
1054 free_rpc_target_auth(struct rpc_target_auth *req)
1055 {
1056 	free(req->name);
1057 }
1058 
1059 static const struct spdk_json_object_decoder rpc_target_auth_decoders[] = {
1060 	{"name", offsetof(struct rpc_target_auth, name), spdk_json_decode_string},
1061 	{"disable_chap", offsetof(struct rpc_target_auth, disable_chap), spdk_json_decode_bool, true},
1062 	{"require_chap", offsetof(struct rpc_target_auth, require_chap), spdk_json_decode_bool, true},
1063 	{"mutual_chap", offsetof(struct rpc_target_auth, mutual_chap), spdk_json_decode_bool, true},
1064 	{"chap_group", offsetof(struct rpc_target_auth, chap_group), spdk_json_decode_int32, true},
1065 };
1066 
1067 static void
1068 rpc_iscsi_target_node_set_auth(struct spdk_jsonrpc_request *request,
1069 			       const struct spdk_json_val *params)
1070 {
1071 	struct rpc_target_auth req = {};
1072 	struct spdk_iscsi_tgt_node *target;
1073 	int rc;
1074 
1075 	if (spdk_json_decode_object(params, rpc_target_auth_decoders,
1076 				    SPDK_COUNTOF(rpc_target_auth_decoders), &req)) {
1077 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1078 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1079 						 "Invalid parameters");
1080 		goto exit;
1081 	}
1082 
1083 	target = iscsi_find_tgt_node(req.name);
1084 	if (target == NULL) {
1085 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1086 						     "Could not find target %s", req.name);
1087 		goto exit;
1088 	}
1089 
1090 	rc = iscsi_tgt_node_set_chap_params(target, req.disable_chap, req.require_chap,
1091 					    req.mutual_chap, req.chap_group);
1092 	if (rc < 0) {
1093 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1094 						 "Invalid combination of auth params");
1095 		goto exit;
1096 	}
1097 
1098 	free_rpc_target_auth(&req);
1099 
1100 	spdk_jsonrpc_send_bool_response(request, true);
1101 	return;
1102 
1103 exit:
1104 	free_rpc_target_auth(&req);
1105 }
1106 SPDK_RPC_REGISTER("iscsi_target_node_set_auth", rpc_iscsi_target_node_set_auth,
1107 		  SPDK_RPC_RUNTIME)
1108 
1109 struct rpc_target_redirect {
1110 	char *name;
1111 	int32_t pg_tag;
1112 	char *redirect_host;
1113 	char *redirect_port;
1114 };
1115 
1116 static void
1117 free_rpc_target_redirect(struct rpc_target_redirect *req)
1118 {
1119 	free(req->name);
1120 	free(req->redirect_host);
1121 	free(req->redirect_port);
1122 }
1123 
1124 static const struct spdk_json_object_decoder rpc_target_redirect_decoders[] = {
1125 	{"name", offsetof(struct rpc_target_redirect, name), spdk_json_decode_string},
1126 	{"pg_tag", offsetof(struct rpc_target_redirect, pg_tag), spdk_json_decode_int32},
1127 	{"redirect_host", offsetof(struct rpc_target_redirect, redirect_host), spdk_json_decode_string, true},
1128 	{"redirect_port", offsetof(struct rpc_target_redirect, redirect_port), spdk_json_decode_string, true},
1129 };
1130 
1131 static void
1132 rpc_iscsi_target_node_set_redirect(struct spdk_jsonrpc_request *request,
1133 				   const struct spdk_json_val *params)
1134 {
1135 	struct rpc_target_redirect req = {};
1136 	struct spdk_iscsi_tgt_node *target;
1137 	int rc;
1138 
1139 	if (spdk_json_decode_object(params, rpc_target_redirect_decoders,
1140 				    SPDK_COUNTOF(rpc_target_redirect_decoders),
1141 				    &req)) {
1142 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1143 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1144 						 "Invalid parameters");
1145 		free_rpc_target_redirect(&req);
1146 		return;
1147 	}
1148 
1149 	target = iscsi_find_tgt_node(req.name);
1150 	if (target == NULL) {
1151 		SPDK_ERRLOG("target %s is not found\n", req.name);
1152 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1153 						     "Target %s is not found", req.name);
1154 		free_rpc_target_redirect(&req);
1155 		return;
1156 	}
1157 
1158 	rc = iscsi_tgt_node_redirect(target, req.pg_tag, req.redirect_host, req.redirect_port);
1159 	if (rc != 0) {
1160 		SPDK_ERRLOG("failed to redirect target %s\n", req.name);
1161 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1162 						     "Failed to redirect target %s, (%d): %s",
1163 						     req.name, rc, spdk_strerror(-rc));
1164 		free_rpc_target_redirect(&req);
1165 		return;
1166 	}
1167 
1168 	free_rpc_target_redirect(&req);
1169 
1170 	spdk_jsonrpc_send_bool_response(request, true);
1171 }
1172 SPDK_RPC_REGISTER("iscsi_target_node_set_redirect", rpc_iscsi_target_node_set_redirect,
1173 		  SPDK_RPC_RUNTIME)
1174 
1175 struct rpc_target_logout {
1176 	char *name;
1177 	int32_t pg_tag;
1178 };
1179 
1180 static void
1181 free_rpc_target_logout(struct rpc_target_logout *req)
1182 {
1183 	free(req->name);
1184 }
1185 
1186 static const struct spdk_json_object_decoder rpc_target_logout_decoders[] = {
1187 	{"name", offsetof(struct rpc_target_logout, name), spdk_json_decode_string},
1188 	{"pg_tag", offsetof(struct rpc_target_logout, pg_tag), spdk_json_decode_int32, true},
1189 };
1190 
1191 static void
1192 rpc_iscsi_target_node_request_logout(struct spdk_jsonrpc_request *request,
1193 				     const struct spdk_json_val *params)
1194 {
1195 	struct rpc_target_logout req = {};
1196 	struct spdk_iscsi_tgt_node *target;
1197 
1198 	/* If pg_tag is omitted, request all connections to the specified target
1199 	 * to logout.
1200 	 */
1201 	req.pg_tag = -1;
1202 
1203 	if (spdk_json_decode_object(params, rpc_target_logout_decoders,
1204 				    SPDK_COUNTOF(rpc_target_logout_decoders),
1205 				    &req)) {
1206 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1207 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1208 						 "Invalid parameters");
1209 		free_rpc_target_logout(&req);
1210 		return;
1211 	}
1212 
1213 	target = iscsi_find_tgt_node(req.name);
1214 	if (target == NULL) {
1215 		SPDK_ERRLOG("target %s is not found\n", req.name);
1216 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1217 						     "Target %s is not found", req.name);
1218 		free_rpc_target_logout(&req);
1219 		return;
1220 	}
1221 
1222 	iscsi_conns_request_logout(target, req.pg_tag);
1223 
1224 	free_rpc_target_logout(&req);
1225 
1226 	spdk_jsonrpc_send_bool_response(request, true);
1227 }
1228 SPDK_RPC_REGISTER("iscsi_target_node_request_logout", rpc_iscsi_target_node_request_logout,
1229 		  SPDK_RPC_RUNTIME)
1230 
1231 static void
1232 rpc_iscsi_get_options(struct spdk_jsonrpc_request *request,
1233 		      const struct spdk_json_val *params)
1234 {
1235 	struct spdk_json_write_ctx *w;
1236 
1237 	if (params != NULL) {
1238 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1239 						 "iscsi_get_options requires no parameters");
1240 		return;
1241 	}
1242 
1243 	w = spdk_jsonrpc_begin_result(request);
1244 	iscsi_opts_info_json(w);
1245 
1246 	spdk_jsonrpc_end_result(request, w);
1247 }
1248 SPDK_RPC_REGISTER("iscsi_get_options", rpc_iscsi_get_options, SPDK_RPC_RUNTIME)
1249 
1250 struct rpc_discovery_auth {
1251 	bool disable_chap;
1252 	bool require_chap;
1253 	bool mutual_chap;
1254 	int32_t chap_group;
1255 };
1256 
1257 static const struct spdk_json_object_decoder rpc_discovery_auth_decoders[] = {
1258 	{"disable_chap", offsetof(struct rpc_discovery_auth, disable_chap), spdk_json_decode_bool, true},
1259 	{"require_chap", offsetof(struct rpc_discovery_auth, require_chap), spdk_json_decode_bool, true},
1260 	{"mutual_chap", offsetof(struct rpc_discovery_auth, mutual_chap), spdk_json_decode_bool, true},
1261 	{"chap_group", offsetof(struct rpc_discovery_auth, chap_group), spdk_json_decode_int32, true},
1262 };
1263 
1264 static void
1265 rpc_iscsi_set_discovery_auth(struct spdk_jsonrpc_request *request,
1266 			     const struct spdk_json_val *params)
1267 {
1268 	struct rpc_discovery_auth req = {};
1269 	int rc;
1270 
1271 	if (spdk_json_decode_object(params, rpc_discovery_auth_decoders,
1272 				    SPDK_COUNTOF(rpc_discovery_auth_decoders), &req)) {
1273 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1274 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1275 						 "Invalid parameters");
1276 		return;
1277 	}
1278 
1279 	rc = iscsi_set_discovery_auth(req.disable_chap, req.require_chap,
1280 				      req.mutual_chap, req.chap_group);
1281 	if (rc < 0) {
1282 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1283 						 "Invalid combination of CHAP params");
1284 		return;
1285 	}
1286 
1287 	spdk_jsonrpc_send_bool_response(request, true);
1288 }
1289 SPDK_RPC_REGISTER("iscsi_set_discovery_auth", rpc_iscsi_set_discovery_auth, SPDK_RPC_RUNTIME)
1290 
1291 #define MAX_AUTH_SECRETS	64
1292 
1293 struct rpc_auth_secret {
1294 	char *user;
1295 	char *secret;
1296 	char *muser;
1297 	char *msecret;
1298 };
1299 
1300 static void
1301 free_rpc_auth_secret(struct rpc_auth_secret *_secret)
1302 {
1303 	free(_secret->user);
1304 	free(_secret->secret);
1305 	free(_secret->muser);
1306 	free(_secret->msecret);
1307 }
1308 
1309 static const struct spdk_json_object_decoder rpc_auth_secret_decoders[] = {
1310 	{"user", offsetof(struct rpc_auth_secret, user), spdk_json_decode_string},
1311 	{"secret", offsetof(struct rpc_auth_secret, secret), spdk_json_decode_string},
1312 	{"muser", offsetof(struct rpc_auth_secret, muser), spdk_json_decode_string, true},
1313 	{"msecret", offsetof(struct rpc_auth_secret, msecret), spdk_json_decode_string, true},
1314 };
1315 
1316 static int
1317 decode_rpc_auth_secret(const struct spdk_json_val *val, void *out)
1318 {
1319 	struct rpc_auth_secret *_secret = out;
1320 
1321 	return spdk_json_decode_object(val, rpc_auth_secret_decoders,
1322 				       SPDK_COUNTOF(rpc_auth_secret_decoders), _secret);
1323 }
1324 
1325 struct rpc_auth_secrets {
1326 	size_t num_secret;
1327 	struct rpc_auth_secret secrets[MAX_AUTH_SECRETS];
1328 };
1329 
1330 static void
1331 free_rpc_auth_secrets(struct rpc_auth_secrets *secrets)
1332 {
1333 	size_t i;
1334 
1335 	for (i = 0; i < secrets->num_secret; i++) {
1336 		free_rpc_auth_secret(&secrets->secrets[i]);
1337 	}
1338 }
1339 
1340 static int
1341 decode_rpc_auth_secrets(const struct spdk_json_val *val, void *out)
1342 {
1343 	struct rpc_auth_secrets *secrets = out;
1344 
1345 	return spdk_json_decode_array(val, decode_rpc_auth_secret, secrets->secrets,
1346 				      MAX_AUTH_SECRETS, &secrets->num_secret,
1347 				      sizeof(struct rpc_auth_secret));
1348 }
1349 
1350 struct rpc_auth_group {
1351 	int32_t tag;
1352 	struct rpc_auth_secrets secrets;
1353 };
1354 
1355 static void
1356 free_rpc_auth_group(struct rpc_auth_group *group)
1357 {
1358 	free_rpc_auth_secrets(&group->secrets);
1359 }
1360 
1361 static const struct spdk_json_object_decoder rpc_auth_group_decoders[] = {
1362 	{"tag", offsetof(struct rpc_auth_group, tag), spdk_json_decode_int32},
1363 	{"secrets", offsetof(struct rpc_auth_group, secrets), decode_rpc_auth_secrets, true},
1364 };
1365 
1366 static void
1367 rpc_iscsi_create_auth_group(struct spdk_jsonrpc_request *request,
1368 			    const struct spdk_json_val *params)
1369 {
1370 	struct rpc_auth_group req = {};
1371 	struct rpc_auth_secret *_secret;
1372 	struct spdk_iscsi_auth_group *group = NULL;
1373 	int rc;
1374 	size_t i;
1375 
1376 	if (spdk_json_decode_object(params, rpc_auth_group_decoders,
1377 				    SPDK_COUNTOF(rpc_auth_group_decoders), &req)) {
1378 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1379 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1380 						 "Invalid parameters");
1381 		free_rpc_auth_group(&req);
1382 		return;
1383 	}
1384 
1385 	pthread_mutex_lock(&g_iscsi.mutex);
1386 
1387 	rc = iscsi_add_auth_group(req.tag, &group);
1388 	if (rc != 0) {
1389 		pthread_mutex_unlock(&g_iscsi.mutex);
1390 
1391 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1392 						     "Could not add auth group (%d), %s",
1393 						     req.tag, spdk_strerror(-rc));
1394 		free_rpc_auth_group(&req);
1395 		return;
1396 	}
1397 
1398 	for (i = 0; i < req.secrets.num_secret; i++) {
1399 		_secret = &req.secrets.secrets[i];
1400 		rc = iscsi_auth_group_add_secret(group, _secret->user, _secret->secret,
1401 						 _secret->muser, _secret->msecret);
1402 		if (rc != 0) {
1403 			iscsi_delete_auth_group(group);
1404 			pthread_mutex_unlock(&g_iscsi.mutex);
1405 
1406 			spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1407 							     "Could not add secret to auth group (%d), %s",
1408 							     req.tag, spdk_strerror(-rc));
1409 			free_rpc_auth_group(&req);
1410 			return;
1411 		}
1412 	}
1413 
1414 	pthread_mutex_unlock(&g_iscsi.mutex);
1415 
1416 	free_rpc_auth_group(&req);
1417 
1418 	spdk_jsonrpc_send_bool_response(request, true);
1419 }
1420 SPDK_RPC_REGISTER("iscsi_create_auth_group", rpc_iscsi_create_auth_group, SPDK_RPC_RUNTIME)
1421 
1422 struct rpc_delete_auth_group {
1423 	int32_t tag;
1424 };
1425 
1426 static const struct spdk_json_object_decoder rpc_delete_auth_group_decoders[] = {
1427 	{"tag", offsetof(struct rpc_delete_auth_group, tag), spdk_json_decode_int32},
1428 };
1429 
1430 static void
1431 rpc_iscsi_delete_auth_group(struct spdk_jsonrpc_request *request,
1432 			    const struct spdk_json_val *params)
1433 {
1434 	struct rpc_delete_auth_group req = {};
1435 	struct spdk_iscsi_auth_group *group;
1436 
1437 	if (spdk_json_decode_object(params, rpc_delete_auth_group_decoders,
1438 				    SPDK_COUNTOF(rpc_delete_auth_group_decoders), &req)) {
1439 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1440 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1441 						 "Invalid parameters");
1442 		return;
1443 	}
1444 
1445 	pthread_mutex_lock(&g_iscsi.mutex);
1446 
1447 	group = iscsi_find_auth_group_by_tag(req.tag);
1448 	if (group == NULL) {
1449 		pthread_mutex_unlock(&g_iscsi.mutex);
1450 
1451 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1452 						     "Could not find auth group (%d)", req.tag);
1453 		return;
1454 	}
1455 
1456 	iscsi_delete_auth_group(group);
1457 
1458 	pthread_mutex_unlock(&g_iscsi.mutex);
1459 
1460 	spdk_jsonrpc_send_bool_response(request, true);
1461 }
1462 SPDK_RPC_REGISTER("iscsi_delete_auth_group", rpc_iscsi_delete_auth_group, SPDK_RPC_RUNTIME)
1463 
1464 struct rpc_add_auth_secret {
1465 	int32_t tag;
1466 	char *user;
1467 	char *secret;
1468 	char *muser;
1469 	char *msecret;
1470 };
1471 
1472 static void
1473 free_rpc_add_auth_secret(struct rpc_add_auth_secret *_secret)
1474 {
1475 	free(_secret->user);
1476 	free(_secret->secret);
1477 	free(_secret->muser);
1478 	free(_secret->msecret);
1479 }
1480 
1481 static const struct spdk_json_object_decoder rpc_add_auth_secret_decoders[] = {
1482 	{"tag", offsetof(struct rpc_add_auth_secret, tag), spdk_json_decode_int32},
1483 	{"user", offsetof(struct rpc_add_auth_secret, user), spdk_json_decode_string},
1484 	{"secret", offsetof(struct rpc_add_auth_secret, secret), spdk_json_decode_string},
1485 	{"muser", offsetof(struct rpc_add_auth_secret, muser), spdk_json_decode_string, true},
1486 	{"msecret", offsetof(struct rpc_add_auth_secret, msecret), spdk_json_decode_string, true},
1487 };
1488 
1489 static void
1490 rpc_iscsi_auth_group_add_secret(struct spdk_jsonrpc_request *request,
1491 				const struct spdk_json_val *params)
1492 {
1493 	struct rpc_add_auth_secret req = {};
1494 	struct spdk_iscsi_auth_group *group;
1495 	int rc;
1496 
1497 	if (spdk_json_decode_object(params, rpc_add_auth_secret_decoders,
1498 				    SPDK_COUNTOF(rpc_add_auth_secret_decoders), &req)) {
1499 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1500 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1501 						 "Invalid parameters");
1502 		free_rpc_add_auth_secret(&req);
1503 		return;
1504 	}
1505 
1506 	pthread_mutex_lock(&g_iscsi.mutex);
1507 
1508 	group = iscsi_find_auth_group_by_tag(req.tag);
1509 	if (group == NULL) {
1510 		pthread_mutex_unlock(&g_iscsi.mutex);
1511 
1512 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1513 						     "Could not find auth group (%d)", req.tag);
1514 		free_rpc_add_auth_secret(&req);
1515 		return;
1516 	}
1517 
1518 	rc = iscsi_auth_group_add_secret(group, req.user, req.secret, req.muser, req.msecret);
1519 	if (rc != 0) {
1520 		pthread_mutex_unlock(&g_iscsi.mutex);
1521 
1522 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1523 						     "Could not add secret to auth group (%d), %s",
1524 						     req.tag, spdk_strerror(-rc));
1525 		free_rpc_add_auth_secret(&req);
1526 		return;
1527 	}
1528 
1529 	pthread_mutex_unlock(&g_iscsi.mutex);
1530 
1531 	free_rpc_add_auth_secret(&req);
1532 
1533 	spdk_jsonrpc_send_bool_response(request, true);
1534 }
1535 SPDK_RPC_REGISTER("iscsi_auth_group_add_secret", rpc_iscsi_auth_group_add_secret,
1536 		  SPDK_RPC_RUNTIME)
1537 
1538 
1539 struct rpc_remove_auth_secret {
1540 	int32_t tag;
1541 	char *user;
1542 };
1543 
1544 static void
1545 free_rpc_remove_auth_secret(struct rpc_remove_auth_secret *_secret)
1546 {
1547 	free(_secret->user);
1548 }
1549 
1550 static const struct spdk_json_object_decoder rpc_remove_auth_secret_decoders[] = {
1551 	{"tag", offsetof(struct rpc_remove_auth_secret, tag), spdk_json_decode_int32},
1552 	{"user", offsetof(struct rpc_remove_auth_secret, user), spdk_json_decode_string},
1553 };
1554 
1555 static void
1556 rpc_iscsi_auth_group_remove_secret(struct spdk_jsonrpc_request *request,
1557 				   const struct spdk_json_val *params)
1558 {
1559 	struct rpc_remove_auth_secret req = {};
1560 	struct spdk_iscsi_auth_group *group;
1561 	int rc;
1562 
1563 	if (spdk_json_decode_object(params, rpc_remove_auth_secret_decoders,
1564 				    SPDK_COUNTOF(rpc_remove_auth_secret_decoders), &req)) {
1565 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1566 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1567 						 "Invalid parameters");
1568 		free_rpc_remove_auth_secret(&req);
1569 		return;
1570 	}
1571 
1572 	pthread_mutex_lock(&g_iscsi.mutex);
1573 
1574 	group = iscsi_find_auth_group_by_tag(req.tag);
1575 	if (group == NULL) {
1576 		pthread_mutex_unlock(&g_iscsi.mutex);
1577 
1578 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1579 						     "Could not find auth group (%d)", req.tag);
1580 		free_rpc_remove_auth_secret(&req);
1581 		return;
1582 	}
1583 
1584 	rc = iscsi_auth_group_delete_secret(group, req.user);
1585 	if (rc != 0) {
1586 		pthread_mutex_unlock(&g_iscsi.mutex);
1587 
1588 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1589 						     "Could not delete secret from CHAP group (%d), %s",
1590 						     req.tag, spdk_strerror(-rc));
1591 		free_rpc_remove_auth_secret(&req);
1592 		return;
1593 	}
1594 
1595 	pthread_mutex_unlock(&g_iscsi.mutex);
1596 
1597 	free_rpc_remove_auth_secret(&req);
1598 
1599 	spdk_jsonrpc_send_bool_response(request, true);
1600 }
1601 SPDK_RPC_REGISTER("iscsi_auth_group_remove_secret",
1602 		  rpc_iscsi_auth_group_remove_secret, SPDK_RPC_RUNTIME)
1603 
1604 static void
1605 rpc_iscsi_get_auth_groups(struct spdk_jsonrpc_request *request,
1606 			  const struct spdk_json_val *params)
1607 {
1608 	struct spdk_json_write_ctx *w;
1609 
1610 	if (params != NULL) {
1611 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1612 						 "iscsi_get_auth_groups requires no parameters");
1613 		return;
1614 	}
1615 
1616 	w = spdk_jsonrpc_begin_result(request);
1617 	spdk_json_write_array_begin(w);
1618 	iscsi_auth_groups_info_json(w);
1619 	spdk_json_write_array_end(w);
1620 
1621 	spdk_jsonrpc_end_result(request, w);
1622 }
1623 SPDK_RPC_REGISTER("iscsi_get_auth_groups", rpc_iscsi_get_auth_groups, SPDK_RPC_RUNTIME)
1624 
1625 static const struct spdk_json_object_decoder rpc_set_iscsi_opts_decoders[] = {
1626 	{"auth_file", offsetof(struct spdk_iscsi_opts, authfile), spdk_json_decode_string, true},
1627 	{"node_base", offsetof(struct spdk_iscsi_opts, nodebase), spdk_json_decode_string, true},
1628 	{"nop_timeout", offsetof(struct spdk_iscsi_opts, timeout), spdk_json_decode_int32, true},
1629 	{"nop_in_interval", offsetof(struct spdk_iscsi_opts, nopininterval), spdk_json_decode_int32, true},
1630 	{"no_discovery_auth", offsetof(struct spdk_iscsi_opts, disable_chap), spdk_json_decode_bool, true},
1631 	{"req_discovery_auth", offsetof(struct spdk_iscsi_opts, require_chap), spdk_json_decode_bool, true},
1632 	{"req_discovery_auth_mutual", offsetof(struct spdk_iscsi_opts, mutual_chap), spdk_json_decode_bool, true},
1633 	{"discovery_auth_group", offsetof(struct spdk_iscsi_opts, chap_group), spdk_json_decode_int32, true},
1634 	{"disable_chap", offsetof(struct spdk_iscsi_opts, disable_chap), spdk_json_decode_bool, true},
1635 	{"require_chap", offsetof(struct spdk_iscsi_opts, require_chap), spdk_json_decode_bool, true},
1636 	{"mutual_chap", offsetof(struct spdk_iscsi_opts, mutual_chap), spdk_json_decode_bool, true},
1637 	{"chap_group", offsetof(struct spdk_iscsi_opts, chap_group), spdk_json_decode_int32, true},
1638 	{"max_sessions", offsetof(struct spdk_iscsi_opts, MaxSessions), spdk_json_decode_uint32, true},
1639 	{"max_queue_depth", offsetof(struct spdk_iscsi_opts, MaxQueueDepth), spdk_json_decode_uint32, true},
1640 	{"max_connections_per_session", offsetof(struct spdk_iscsi_opts, MaxConnectionsPerSession), spdk_json_decode_uint32, true},
1641 	{"default_time2wait", offsetof(struct spdk_iscsi_opts, DefaultTime2Wait), spdk_json_decode_uint32, true},
1642 	{"default_time2retain", offsetof(struct spdk_iscsi_opts, DefaultTime2Retain), spdk_json_decode_uint32, true},
1643 	{"first_burst_length", offsetof(struct spdk_iscsi_opts, FirstBurstLength), spdk_json_decode_uint32, true},
1644 	{"immediate_data", offsetof(struct spdk_iscsi_opts, ImmediateData), spdk_json_decode_bool, true},
1645 	{"error_recovery_level", offsetof(struct spdk_iscsi_opts, ErrorRecoveryLevel), spdk_json_decode_uint32, true},
1646 	{"allow_duplicated_isid", offsetof(struct spdk_iscsi_opts, AllowDuplicateIsid), spdk_json_decode_bool, true},
1647 	{"max_large_datain_per_connection", offsetof(struct spdk_iscsi_opts, MaxLargeDataInPerConnection), spdk_json_decode_uint32, true},
1648 	{"max_r2t_per_connection", offsetof(struct spdk_iscsi_opts, MaxR2TPerConnection), spdk_json_decode_uint32, true},
1649 	{"pdu_pool_size", offsetof(struct spdk_iscsi_opts, pdu_pool_size), spdk_json_decode_uint32, true},
1650 	{"immediate_data_pool_size", offsetof(struct spdk_iscsi_opts, immediate_data_pool_size), spdk_json_decode_uint32, true},
1651 	{"data_out_pool_size", offsetof(struct spdk_iscsi_opts, data_out_pool_size), spdk_json_decode_uint32, true},
1652 };
1653 
1654 static void
1655 rpc_iscsi_set_options(struct spdk_jsonrpc_request *request,
1656 		      const struct spdk_json_val *params)
1657 {
1658 	struct spdk_iscsi_opts *opts;
1659 
1660 	if (g_spdk_iscsi_opts != NULL) {
1661 		SPDK_ERRLOG("this RPC must not be called more than once.\n");
1662 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1663 						 "Must not call more than once");
1664 		return;
1665 	}
1666 
1667 	opts = iscsi_opts_alloc();
1668 	if (opts == NULL) {
1669 		SPDK_ERRLOG("iscsi_opts_alloc() failed.\n");
1670 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1671 						 "Out of memory");
1672 		return;
1673 	}
1674 
1675 	if (params != NULL) {
1676 		if (spdk_json_decode_object(params, rpc_set_iscsi_opts_decoders,
1677 					    SPDK_COUNTOF(rpc_set_iscsi_opts_decoders), opts)) {
1678 			SPDK_ERRLOG("spdk_json_decode_object() failed\n");
1679 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1680 							 "Invalid parameters");
1681 			iscsi_opts_free(opts);
1682 			return;
1683 		}
1684 	}
1685 
1686 	g_spdk_iscsi_opts = iscsi_opts_copy(opts);
1687 	iscsi_opts_free(opts);
1688 
1689 	if (g_spdk_iscsi_opts == NULL) {
1690 		SPDK_ERRLOG("iscsi_opts_copy() failed\n");
1691 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1692 						 "Out of memory");
1693 		return;
1694 	}
1695 
1696 	spdk_jsonrpc_send_bool_response(request, true);
1697 }
1698 SPDK_RPC_REGISTER("iscsi_set_options", rpc_iscsi_set_options, SPDK_RPC_STARTUP)
1699