xref: /spdk/lib/iscsi/iscsi_rpc.c (revision 12fbe739a31b09aff0d05f354d4f3bbef99afc55)
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 static void
997 free_rpc_target_lun(struct rpc_target_lun *req)
998 {
999 	free(req->name);
1000 	free(req->bdev_name);
1001 }
1002 
1003 static const struct spdk_json_object_decoder rpc_target_lun_decoders[] = {
1004 	{"name", offsetof(struct rpc_target_lun, name), spdk_json_decode_string},
1005 	{"bdev_name", offsetof(struct rpc_target_lun, bdev_name), spdk_json_decode_string},
1006 	{"lun_id", offsetof(struct rpc_target_lun, lun_id), spdk_json_decode_int32, true},
1007 };
1008 
1009 static void
1010 rpc_iscsi_target_node_add_lun(struct spdk_jsonrpc_request *request,
1011 			      const struct spdk_json_val *params)
1012 {
1013 	struct rpc_target_lun req = {};
1014 	struct spdk_iscsi_tgt_node *target;
1015 	int rc;
1016 
1017 	req.lun_id = -1;
1018 
1019 	if (spdk_json_decode_object(params, rpc_target_lun_decoders,
1020 				    SPDK_COUNTOF(rpc_target_lun_decoders), &req)) {
1021 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1022 		goto invalid;
1023 	}
1024 
1025 	target = iscsi_find_tgt_node(req.name);
1026 	if (target == NULL) {
1027 		SPDK_ERRLOG("target is not found\n");
1028 		goto invalid;
1029 	}
1030 
1031 	rc = iscsi_tgt_node_add_lun(target, req.bdev_name, req.lun_id);
1032 	if (rc < 0) {
1033 		SPDK_ERRLOG("add lun failed\n");
1034 		goto invalid;
1035 	}
1036 
1037 	free_rpc_target_lun(&req);
1038 
1039 	spdk_jsonrpc_send_bool_response(request, true);
1040 	return;
1041 
1042 invalid:
1043 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1044 					 "Invalid parameters");
1045 	free_rpc_target_lun(&req);
1046 }
1047 SPDK_RPC_REGISTER("iscsi_target_node_add_lun", rpc_iscsi_target_node_add_lun, SPDK_RPC_RUNTIME)
1048 
1049 struct rpc_target_auth {
1050 	char *name;
1051 	bool disable_chap;
1052 	bool require_chap;
1053 	bool mutual_chap;
1054 	int32_t chap_group;
1055 };
1056 
1057 static void
1058 free_rpc_target_auth(struct rpc_target_auth *req)
1059 {
1060 	free(req->name);
1061 }
1062 
1063 static const struct spdk_json_object_decoder rpc_target_auth_decoders[] = {
1064 	{"name", offsetof(struct rpc_target_auth, name), spdk_json_decode_string},
1065 	{"disable_chap", offsetof(struct rpc_target_auth, disable_chap), spdk_json_decode_bool, true},
1066 	{"require_chap", offsetof(struct rpc_target_auth, require_chap), spdk_json_decode_bool, true},
1067 	{"mutual_chap", offsetof(struct rpc_target_auth, mutual_chap), spdk_json_decode_bool, true},
1068 	{"chap_group", offsetof(struct rpc_target_auth, chap_group), spdk_json_decode_int32, true},
1069 };
1070 
1071 static void
1072 rpc_iscsi_target_node_set_auth(struct spdk_jsonrpc_request *request,
1073 			       const struct spdk_json_val *params)
1074 {
1075 	struct rpc_target_auth req = {};
1076 	struct spdk_iscsi_tgt_node *target;
1077 	int rc;
1078 
1079 	if (spdk_json_decode_object(params, rpc_target_auth_decoders,
1080 				    SPDK_COUNTOF(rpc_target_auth_decoders), &req)) {
1081 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1082 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1083 						 "Invalid parameters");
1084 		goto exit;
1085 	}
1086 
1087 	target = iscsi_find_tgt_node(req.name);
1088 	if (target == NULL) {
1089 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1090 						     "Could not find target %s", req.name);
1091 		goto exit;
1092 	}
1093 
1094 	rc = iscsi_tgt_node_set_chap_params(target, req.disable_chap, req.require_chap,
1095 					    req.mutual_chap, req.chap_group);
1096 	if (rc < 0) {
1097 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1098 						 "Invalid combination of auth params");
1099 		goto exit;
1100 	}
1101 
1102 	free_rpc_target_auth(&req);
1103 
1104 	spdk_jsonrpc_send_bool_response(request, true);
1105 	return;
1106 
1107 exit:
1108 	free_rpc_target_auth(&req);
1109 }
1110 SPDK_RPC_REGISTER("iscsi_target_node_set_auth", rpc_iscsi_target_node_set_auth,
1111 		  SPDK_RPC_RUNTIME)
1112 
1113 struct rpc_target_redirect {
1114 	char *name;
1115 	int32_t pg_tag;
1116 	char *redirect_host;
1117 	char *redirect_port;
1118 };
1119 
1120 static void
1121 free_rpc_target_redirect(struct rpc_target_redirect *req)
1122 {
1123 	free(req->name);
1124 	free(req->redirect_host);
1125 	free(req->redirect_port);
1126 }
1127 
1128 static const struct spdk_json_object_decoder rpc_target_redirect_decoders[] = {
1129 	{"name", offsetof(struct rpc_target_redirect, name), spdk_json_decode_string},
1130 	{"pg_tag", offsetof(struct rpc_target_redirect, pg_tag), spdk_json_decode_int32},
1131 	{"redirect_host", offsetof(struct rpc_target_redirect, redirect_host), spdk_json_decode_string, true},
1132 	{"redirect_port", offsetof(struct rpc_target_redirect, redirect_port), spdk_json_decode_string, true},
1133 };
1134 
1135 static void
1136 rpc_iscsi_target_node_set_redirect(struct spdk_jsonrpc_request *request,
1137 				   const struct spdk_json_val *params)
1138 {
1139 	struct rpc_target_redirect req = {};
1140 	struct spdk_iscsi_tgt_node *target;
1141 	int rc;
1142 
1143 	if (spdk_json_decode_object(params, rpc_target_redirect_decoders,
1144 				    SPDK_COUNTOF(rpc_target_redirect_decoders),
1145 				    &req)) {
1146 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1147 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1148 						 "Invalid parameters");
1149 		free_rpc_target_redirect(&req);
1150 		return;
1151 	}
1152 
1153 	target = iscsi_find_tgt_node(req.name);
1154 	if (target == NULL) {
1155 		SPDK_ERRLOG("target %s is not found\n", req.name);
1156 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1157 						     "Target %s is not found", req.name);
1158 		free_rpc_target_redirect(&req);
1159 		return;
1160 	}
1161 
1162 	rc = iscsi_tgt_node_redirect(target, req.pg_tag, req.redirect_host, req.redirect_port);
1163 	if (rc != 0) {
1164 		SPDK_ERRLOG("failed to redirect target %s\n", req.name);
1165 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1166 						     "Failed to redirect target %s, (%d): %s",
1167 						     req.name, rc, spdk_strerror(-rc));
1168 		free_rpc_target_redirect(&req);
1169 		return;
1170 	}
1171 
1172 	free_rpc_target_redirect(&req);
1173 
1174 	spdk_jsonrpc_send_bool_response(request, true);
1175 }
1176 SPDK_RPC_REGISTER("iscsi_target_node_set_redirect", rpc_iscsi_target_node_set_redirect,
1177 		  SPDK_RPC_RUNTIME)
1178 
1179 struct rpc_target_logout {
1180 	char *name;
1181 	int32_t pg_tag;
1182 };
1183 
1184 static void
1185 free_rpc_target_logout(struct rpc_target_logout *req)
1186 {
1187 	free(req->name);
1188 }
1189 
1190 static const struct spdk_json_object_decoder rpc_target_logout_decoders[] = {
1191 	{"name", offsetof(struct rpc_target_logout, name), spdk_json_decode_string},
1192 	{"pg_tag", offsetof(struct rpc_target_logout, pg_tag), spdk_json_decode_int32, true},
1193 };
1194 
1195 static void
1196 rpc_iscsi_target_node_request_logout(struct spdk_jsonrpc_request *request,
1197 				     const struct spdk_json_val *params)
1198 {
1199 	struct rpc_target_logout req = {};
1200 	struct spdk_iscsi_tgt_node *target;
1201 
1202 	/* If pg_tag is omitted, request all connections to the specified target
1203 	 * to logout.
1204 	 */
1205 	req.pg_tag = -1;
1206 
1207 	if (spdk_json_decode_object(params, rpc_target_logout_decoders,
1208 				    SPDK_COUNTOF(rpc_target_logout_decoders),
1209 				    &req)) {
1210 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1211 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1212 						 "Invalid parameters");
1213 		free_rpc_target_logout(&req);
1214 		return;
1215 	}
1216 
1217 	target = iscsi_find_tgt_node(req.name);
1218 	if (target == NULL) {
1219 		SPDK_ERRLOG("target %s is not found\n", req.name);
1220 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1221 						     "Target %s is not found", req.name);
1222 		free_rpc_target_logout(&req);
1223 		return;
1224 	}
1225 
1226 	iscsi_conns_request_logout(target, req.pg_tag);
1227 
1228 	free_rpc_target_logout(&req);
1229 
1230 	spdk_jsonrpc_send_bool_response(request, true);
1231 }
1232 SPDK_RPC_REGISTER("iscsi_target_node_request_logout", rpc_iscsi_target_node_request_logout,
1233 		  SPDK_RPC_RUNTIME)
1234 
1235 static void
1236 rpc_iscsi_get_options(struct spdk_jsonrpc_request *request,
1237 		      const struct spdk_json_val *params)
1238 {
1239 	struct spdk_json_write_ctx *w;
1240 
1241 	if (params != NULL) {
1242 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1243 						 "iscsi_get_options requires no parameters");
1244 		return;
1245 	}
1246 
1247 	w = spdk_jsonrpc_begin_result(request);
1248 	iscsi_opts_info_json(w);
1249 
1250 	spdk_jsonrpc_end_result(request, w);
1251 }
1252 SPDK_RPC_REGISTER("iscsi_get_options", rpc_iscsi_get_options, SPDK_RPC_RUNTIME)
1253 
1254 struct rpc_discovery_auth {
1255 	bool disable_chap;
1256 	bool require_chap;
1257 	bool mutual_chap;
1258 	int32_t chap_group;
1259 };
1260 
1261 static const struct spdk_json_object_decoder rpc_discovery_auth_decoders[] = {
1262 	{"disable_chap", offsetof(struct rpc_discovery_auth, disable_chap), spdk_json_decode_bool, true},
1263 	{"require_chap", offsetof(struct rpc_discovery_auth, require_chap), spdk_json_decode_bool, true},
1264 	{"mutual_chap", offsetof(struct rpc_discovery_auth, mutual_chap), spdk_json_decode_bool, true},
1265 	{"chap_group", offsetof(struct rpc_discovery_auth, chap_group), spdk_json_decode_int32, true},
1266 };
1267 
1268 static void
1269 rpc_iscsi_set_discovery_auth(struct spdk_jsonrpc_request *request,
1270 			     const struct spdk_json_val *params)
1271 {
1272 	struct rpc_discovery_auth req = {};
1273 	int rc;
1274 
1275 	if (spdk_json_decode_object(params, rpc_discovery_auth_decoders,
1276 				    SPDK_COUNTOF(rpc_discovery_auth_decoders), &req)) {
1277 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1278 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1279 						 "Invalid parameters");
1280 		return;
1281 	}
1282 
1283 	rc = iscsi_set_discovery_auth(req.disable_chap, req.require_chap,
1284 				      req.mutual_chap, req.chap_group);
1285 	if (rc < 0) {
1286 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1287 						 "Invalid combination of CHAP params");
1288 		return;
1289 	}
1290 
1291 	spdk_jsonrpc_send_bool_response(request, true);
1292 }
1293 SPDK_RPC_REGISTER("iscsi_set_discovery_auth", rpc_iscsi_set_discovery_auth, SPDK_RPC_RUNTIME)
1294 
1295 #define MAX_AUTH_SECRETS	64
1296 
1297 struct rpc_auth_secret {
1298 	char *user;
1299 	char *secret;
1300 	char *muser;
1301 	char *msecret;
1302 };
1303 
1304 static void
1305 free_rpc_auth_secret(struct rpc_auth_secret *_secret)
1306 {
1307 	free(_secret->user);
1308 	free(_secret->secret);
1309 	free(_secret->muser);
1310 	free(_secret->msecret);
1311 }
1312 
1313 static const struct spdk_json_object_decoder rpc_auth_secret_decoders[] = {
1314 	{"user", offsetof(struct rpc_auth_secret, user), spdk_json_decode_string},
1315 	{"secret", offsetof(struct rpc_auth_secret, secret), spdk_json_decode_string},
1316 	{"muser", offsetof(struct rpc_auth_secret, muser), spdk_json_decode_string, true},
1317 	{"msecret", offsetof(struct rpc_auth_secret, msecret), spdk_json_decode_string, true},
1318 };
1319 
1320 static int
1321 decode_rpc_auth_secret(const struct spdk_json_val *val, void *out)
1322 {
1323 	struct rpc_auth_secret *_secret = out;
1324 
1325 	return spdk_json_decode_object(val, rpc_auth_secret_decoders,
1326 				       SPDK_COUNTOF(rpc_auth_secret_decoders), _secret);
1327 }
1328 
1329 struct rpc_auth_secrets {
1330 	size_t num_secret;
1331 	struct rpc_auth_secret secrets[MAX_AUTH_SECRETS];
1332 };
1333 
1334 static void
1335 free_rpc_auth_secrets(struct rpc_auth_secrets *secrets)
1336 {
1337 	size_t i;
1338 
1339 	for (i = 0; i < secrets->num_secret; i++) {
1340 		free_rpc_auth_secret(&secrets->secrets[i]);
1341 	}
1342 }
1343 
1344 static int
1345 decode_rpc_auth_secrets(const struct spdk_json_val *val, void *out)
1346 {
1347 	struct rpc_auth_secrets *secrets = out;
1348 
1349 	return spdk_json_decode_array(val, decode_rpc_auth_secret, secrets->secrets,
1350 				      MAX_AUTH_SECRETS, &secrets->num_secret,
1351 				      sizeof(struct rpc_auth_secret));
1352 }
1353 
1354 struct rpc_auth_group {
1355 	int32_t tag;
1356 	struct rpc_auth_secrets secrets;
1357 };
1358 
1359 static void
1360 free_rpc_auth_group(struct rpc_auth_group *group)
1361 {
1362 	free_rpc_auth_secrets(&group->secrets);
1363 }
1364 
1365 static const struct spdk_json_object_decoder rpc_auth_group_decoders[] = {
1366 	{"tag", offsetof(struct rpc_auth_group, tag), spdk_json_decode_int32},
1367 	{"secrets", offsetof(struct rpc_auth_group, secrets), decode_rpc_auth_secrets, true},
1368 };
1369 
1370 static void
1371 rpc_iscsi_create_auth_group(struct spdk_jsonrpc_request *request,
1372 			    const struct spdk_json_val *params)
1373 {
1374 	struct rpc_auth_group req = {};
1375 	struct rpc_auth_secret *_secret;
1376 	struct spdk_iscsi_auth_group *group = NULL;
1377 	int rc;
1378 	size_t i;
1379 
1380 	if (spdk_json_decode_object(params, rpc_auth_group_decoders,
1381 				    SPDK_COUNTOF(rpc_auth_group_decoders), &req)) {
1382 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1383 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1384 						 "Invalid parameters");
1385 		free_rpc_auth_group(&req);
1386 		return;
1387 	}
1388 
1389 	pthread_mutex_lock(&g_iscsi.mutex);
1390 
1391 	rc = iscsi_add_auth_group(req.tag, &group);
1392 	if (rc != 0) {
1393 		pthread_mutex_unlock(&g_iscsi.mutex);
1394 
1395 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1396 						     "Could not add auth group (%d), %s",
1397 						     req.tag, spdk_strerror(-rc));
1398 		free_rpc_auth_group(&req);
1399 		return;
1400 	}
1401 
1402 	for (i = 0; i < req.secrets.num_secret; i++) {
1403 		_secret = &req.secrets.secrets[i];
1404 		rc = iscsi_auth_group_add_secret(group, _secret->user, _secret->secret,
1405 						 _secret->muser, _secret->msecret);
1406 		if (rc != 0) {
1407 			iscsi_delete_auth_group(group);
1408 			pthread_mutex_unlock(&g_iscsi.mutex);
1409 
1410 			spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1411 							     "Could not add secret to auth group (%d), %s",
1412 							     req.tag, spdk_strerror(-rc));
1413 			free_rpc_auth_group(&req);
1414 			return;
1415 		}
1416 	}
1417 
1418 	pthread_mutex_unlock(&g_iscsi.mutex);
1419 
1420 	free_rpc_auth_group(&req);
1421 
1422 	spdk_jsonrpc_send_bool_response(request, true);
1423 }
1424 SPDK_RPC_REGISTER("iscsi_create_auth_group", rpc_iscsi_create_auth_group, SPDK_RPC_RUNTIME)
1425 
1426 struct rpc_delete_auth_group {
1427 	int32_t tag;
1428 };
1429 
1430 static const struct spdk_json_object_decoder rpc_delete_auth_group_decoders[] = {
1431 	{"tag", offsetof(struct rpc_delete_auth_group, tag), spdk_json_decode_int32},
1432 };
1433 
1434 static void
1435 rpc_iscsi_delete_auth_group(struct spdk_jsonrpc_request *request,
1436 			    const struct spdk_json_val *params)
1437 {
1438 	struct rpc_delete_auth_group req = {};
1439 	struct spdk_iscsi_auth_group *group;
1440 
1441 	if (spdk_json_decode_object(params, rpc_delete_auth_group_decoders,
1442 				    SPDK_COUNTOF(rpc_delete_auth_group_decoders), &req)) {
1443 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1444 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1445 						 "Invalid parameters");
1446 		return;
1447 	}
1448 
1449 	pthread_mutex_lock(&g_iscsi.mutex);
1450 
1451 	group = iscsi_find_auth_group_by_tag(req.tag);
1452 	if (group == NULL) {
1453 		pthread_mutex_unlock(&g_iscsi.mutex);
1454 
1455 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1456 						     "Could not find auth group (%d)", req.tag);
1457 		return;
1458 	}
1459 
1460 	iscsi_delete_auth_group(group);
1461 
1462 	pthread_mutex_unlock(&g_iscsi.mutex);
1463 
1464 	spdk_jsonrpc_send_bool_response(request, true);
1465 }
1466 SPDK_RPC_REGISTER("iscsi_delete_auth_group", rpc_iscsi_delete_auth_group, SPDK_RPC_RUNTIME)
1467 
1468 struct rpc_add_auth_secret {
1469 	int32_t tag;
1470 	char *user;
1471 	char *secret;
1472 	char *muser;
1473 	char *msecret;
1474 };
1475 
1476 static void
1477 free_rpc_add_auth_secret(struct rpc_add_auth_secret *_secret)
1478 {
1479 	free(_secret->user);
1480 	free(_secret->secret);
1481 	free(_secret->muser);
1482 	free(_secret->msecret);
1483 }
1484 
1485 static const struct spdk_json_object_decoder rpc_add_auth_secret_decoders[] = {
1486 	{"tag", offsetof(struct rpc_add_auth_secret, tag), spdk_json_decode_int32},
1487 	{"user", offsetof(struct rpc_add_auth_secret, user), spdk_json_decode_string},
1488 	{"secret", offsetof(struct rpc_add_auth_secret, secret), spdk_json_decode_string},
1489 	{"muser", offsetof(struct rpc_add_auth_secret, muser), spdk_json_decode_string, true},
1490 	{"msecret", offsetof(struct rpc_add_auth_secret, msecret), spdk_json_decode_string, true},
1491 };
1492 
1493 static void
1494 rpc_iscsi_auth_group_add_secret(struct spdk_jsonrpc_request *request,
1495 				const struct spdk_json_val *params)
1496 {
1497 	struct rpc_add_auth_secret req = {};
1498 	struct spdk_iscsi_auth_group *group;
1499 	int rc;
1500 
1501 	if (spdk_json_decode_object(params, rpc_add_auth_secret_decoders,
1502 				    SPDK_COUNTOF(rpc_add_auth_secret_decoders), &req)) {
1503 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1504 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1505 						 "Invalid parameters");
1506 		free_rpc_add_auth_secret(&req);
1507 		return;
1508 	}
1509 
1510 	pthread_mutex_lock(&g_iscsi.mutex);
1511 
1512 	group = iscsi_find_auth_group_by_tag(req.tag);
1513 	if (group == NULL) {
1514 		pthread_mutex_unlock(&g_iscsi.mutex);
1515 
1516 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1517 						     "Could not find auth group (%d)", req.tag);
1518 		free_rpc_add_auth_secret(&req);
1519 		return;
1520 	}
1521 
1522 	rc = iscsi_auth_group_add_secret(group, req.user, req.secret, req.muser, req.msecret);
1523 	if (rc != 0) {
1524 		pthread_mutex_unlock(&g_iscsi.mutex);
1525 
1526 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1527 						     "Could not add secret to auth group (%d), %s",
1528 						     req.tag, spdk_strerror(-rc));
1529 		free_rpc_add_auth_secret(&req);
1530 		return;
1531 	}
1532 
1533 	pthread_mutex_unlock(&g_iscsi.mutex);
1534 
1535 	free_rpc_add_auth_secret(&req);
1536 
1537 	spdk_jsonrpc_send_bool_response(request, true);
1538 }
1539 SPDK_RPC_REGISTER("iscsi_auth_group_add_secret", rpc_iscsi_auth_group_add_secret,
1540 		  SPDK_RPC_RUNTIME)
1541 
1542 
1543 struct rpc_remove_auth_secret {
1544 	int32_t tag;
1545 	char *user;
1546 };
1547 
1548 static void
1549 free_rpc_remove_auth_secret(struct rpc_remove_auth_secret *_secret)
1550 {
1551 	free(_secret->user);
1552 }
1553 
1554 static const struct spdk_json_object_decoder rpc_remove_auth_secret_decoders[] = {
1555 	{"tag", offsetof(struct rpc_remove_auth_secret, tag), spdk_json_decode_int32},
1556 	{"user", offsetof(struct rpc_remove_auth_secret, user), spdk_json_decode_string},
1557 };
1558 
1559 static void
1560 rpc_iscsi_auth_group_remove_secret(struct spdk_jsonrpc_request *request,
1561 				   const struct spdk_json_val *params)
1562 {
1563 	struct rpc_remove_auth_secret req = {};
1564 	struct spdk_iscsi_auth_group *group;
1565 	int rc;
1566 
1567 	if (spdk_json_decode_object(params, rpc_remove_auth_secret_decoders,
1568 				    SPDK_COUNTOF(rpc_remove_auth_secret_decoders), &req)) {
1569 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1570 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1571 						 "Invalid parameters");
1572 		free_rpc_remove_auth_secret(&req);
1573 		return;
1574 	}
1575 
1576 	pthread_mutex_lock(&g_iscsi.mutex);
1577 
1578 	group = iscsi_find_auth_group_by_tag(req.tag);
1579 	if (group == NULL) {
1580 		pthread_mutex_unlock(&g_iscsi.mutex);
1581 
1582 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1583 						     "Could not find auth group (%d)", req.tag);
1584 		free_rpc_remove_auth_secret(&req);
1585 		return;
1586 	}
1587 
1588 	rc = iscsi_auth_group_delete_secret(group, req.user);
1589 	if (rc != 0) {
1590 		pthread_mutex_unlock(&g_iscsi.mutex);
1591 
1592 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1593 						     "Could not delete secret from CHAP group (%d), %s",
1594 						     req.tag, spdk_strerror(-rc));
1595 		free_rpc_remove_auth_secret(&req);
1596 		return;
1597 	}
1598 
1599 	pthread_mutex_unlock(&g_iscsi.mutex);
1600 
1601 	free_rpc_remove_auth_secret(&req);
1602 
1603 	spdk_jsonrpc_send_bool_response(request, true);
1604 }
1605 SPDK_RPC_REGISTER("iscsi_auth_group_remove_secret",
1606 		  rpc_iscsi_auth_group_remove_secret, SPDK_RPC_RUNTIME)
1607 
1608 static void
1609 rpc_iscsi_get_auth_groups(struct spdk_jsonrpc_request *request,
1610 			  const struct spdk_json_val *params)
1611 {
1612 	struct spdk_json_write_ctx *w;
1613 
1614 	if (params != NULL) {
1615 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1616 						 "iscsi_get_auth_groups requires no parameters");
1617 		return;
1618 	}
1619 
1620 	w = spdk_jsonrpc_begin_result(request);
1621 	spdk_json_write_array_begin(w);
1622 	iscsi_auth_groups_info_json(w);
1623 	spdk_json_write_array_end(w);
1624 
1625 	spdk_jsonrpc_end_result(request, w);
1626 }
1627 SPDK_RPC_REGISTER("iscsi_get_auth_groups", rpc_iscsi_get_auth_groups, SPDK_RPC_RUNTIME)
1628 
1629 static const struct spdk_json_object_decoder rpc_set_iscsi_opts_decoders[] = {
1630 	{"auth_file", offsetof(struct spdk_iscsi_opts, authfile), spdk_json_decode_string, true},
1631 	{"node_base", offsetof(struct spdk_iscsi_opts, nodebase), spdk_json_decode_string, true},
1632 	{"nop_timeout", offsetof(struct spdk_iscsi_opts, timeout), spdk_json_decode_int32, true},
1633 	{"nop_in_interval", offsetof(struct spdk_iscsi_opts, nopininterval), spdk_json_decode_int32, true},
1634 	{"no_discovery_auth", offsetof(struct spdk_iscsi_opts, disable_chap), spdk_json_decode_bool, true},
1635 	{"req_discovery_auth", offsetof(struct spdk_iscsi_opts, require_chap), spdk_json_decode_bool, true},
1636 	{"req_discovery_auth_mutual", offsetof(struct spdk_iscsi_opts, mutual_chap), spdk_json_decode_bool, true},
1637 	{"discovery_auth_group", offsetof(struct spdk_iscsi_opts, chap_group), spdk_json_decode_int32, true},
1638 	{"disable_chap", offsetof(struct spdk_iscsi_opts, disable_chap), spdk_json_decode_bool, true},
1639 	{"require_chap", offsetof(struct spdk_iscsi_opts, require_chap), spdk_json_decode_bool, true},
1640 	{"mutual_chap", offsetof(struct spdk_iscsi_opts, mutual_chap), spdk_json_decode_bool, true},
1641 	{"chap_group", offsetof(struct spdk_iscsi_opts, chap_group), spdk_json_decode_int32, true},
1642 	{"max_sessions", offsetof(struct spdk_iscsi_opts, MaxSessions), spdk_json_decode_uint32, true},
1643 	{"max_queue_depth", offsetof(struct spdk_iscsi_opts, MaxQueueDepth), spdk_json_decode_uint32, true},
1644 	{"max_connections_per_session", offsetof(struct spdk_iscsi_opts, MaxConnectionsPerSession), spdk_json_decode_uint32, true},
1645 	{"default_time2wait", offsetof(struct spdk_iscsi_opts, DefaultTime2Wait), spdk_json_decode_uint32, true},
1646 	{"default_time2retain", offsetof(struct spdk_iscsi_opts, DefaultTime2Retain), spdk_json_decode_uint32, true},
1647 	{"first_burst_length", offsetof(struct spdk_iscsi_opts, FirstBurstLength), spdk_json_decode_uint32, true},
1648 	{"immediate_data", offsetof(struct spdk_iscsi_opts, ImmediateData), spdk_json_decode_bool, true},
1649 	{"error_recovery_level", offsetof(struct spdk_iscsi_opts, ErrorRecoveryLevel), spdk_json_decode_uint32, true},
1650 	{"allow_duplicated_isid", offsetof(struct spdk_iscsi_opts, AllowDuplicateIsid), spdk_json_decode_bool, true},
1651 	{"max_large_datain_per_connection", offsetof(struct spdk_iscsi_opts, MaxLargeDataInPerConnection), spdk_json_decode_uint32, true},
1652 	{"max_r2t_per_connection", offsetof(struct spdk_iscsi_opts, MaxR2TPerConnection), spdk_json_decode_uint32, true},
1653 	{"pdu_pool_size", offsetof(struct spdk_iscsi_opts, pdu_pool_size), spdk_json_decode_uint32, true},
1654 	{"immediate_data_pool_size", offsetof(struct spdk_iscsi_opts, immediate_data_pool_size), spdk_json_decode_uint32, true},
1655 	{"data_out_pool_size", offsetof(struct spdk_iscsi_opts, data_out_pool_size), spdk_json_decode_uint32, true},
1656 };
1657 
1658 static void
1659 rpc_iscsi_set_options(struct spdk_jsonrpc_request *request,
1660 		      const struct spdk_json_val *params)
1661 {
1662 	struct spdk_iscsi_opts *opts;
1663 
1664 	if (g_spdk_iscsi_opts != NULL) {
1665 		SPDK_ERRLOG("this RPC must not be called more than once.\n");
1666 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1667 						 "Must not call more than once");
1668 		return;
1669 	}
1670 
1671 	opts = iscsi_opts_alloc();
1672 	if (opts == NULL) {
1673 		SPDK_ERRLOG("iscsi_opts_alloc() failed.\n");
1674 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1675 						 "Out of memory");
1676 		return;
1677 	}
1678 
1679 	if (params != NULL) {
1680 		if (spdk_json_decode_object(params, rpc_set_iscsi_opts_decoders,
1681 					    SPDK_COUNTOF(rpc_set_iscsi_opts_decoders), opts)) {
1682 			SPDK_ERRLOG("spdk_json_decode_object() failed\n");
1683 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1684 							 "Invalid parameters");
1685 			iscsi_opts_free(opts);
1686 			return;
1687 		}
1688 	}
1689 
1690 	g_spdk_iscsi_opts = iscsi_opts_copy(opts);
1691 	iscsi_opts_free(opts);
1692 
1693 	if (g_spdk_iscsi_opts == NULL) {
1694 		SPDK_ERRLOG("iscsi_opts_copy() failed\n");
1695 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1696 						 "Out of memory");
1697 		return;
1698 	}
1699 
1700 	spdk_jsonrpc_send_bool_response(request, true);
1701 }
1702 SPDK_RPC_REGISTER("iscsi_set_options", rpc_iscsi_set_options, SPDK_RPC_STARTUP)
1703