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