xref: /spdk/lib/iscsi/iscsi_rpc.c (revision 407e88fd2ab020d753e33014cf759353a9901b51)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
5  *   Copyright (c) Intel Corporation.
6  *   All rights reserved.
7  *
8  *   Redistribution and use in source and binary forms, with or without
9  *   modification, are permitted provided that the following conditions
10  *   are met:
11  *
12  *     * Redistributions of source code must retain the above copyright
13  *       notice, this list of conditions and the following disclaimer.
14  *     * Redistributions in binary form must reproduce the above copyright
15  *       notice, this list of conditions and the following disclaimer in
16  *       the documentation and/or other materials provided with the
17  *       distribution.
18  *     * Neither the name of Intel Corporation nor the names of its
19  *       contributors may be used to endorse or promote products derived
20  *       from this software without specific prior written permission.
21  *
22  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include "iscsi/iscsi.h"
36 #include "iscsi/conn.h"
37 #include "iscsi/tgt_node.h"
38 #include "iscsi/portal_grp.h"
39 #include "iscsi/init_grp.h"
40 
41 #include "spdk/rpc.h"
42 #include "spdk/util.h"
43 #include "spdk/event.h"
44 #include "spdk/string.h"
45 #include "spdk_internal/log.h"
46 
47 static void
48 spdk_rpc_get_initiator_groups(struct spdk_jsonrpc_request *request,
49 			      const struct spdk_json_val *params)
50 {
51 	struct spdk_json_write_ctx *w;
52 
53 	if (params != NULL) {
54 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
55 						 "get_initiator_groups requires no parameters");
56 		return;
57 	}
58 
59 	w = spdk_jsonrpc_begin_result(request);
60 	spdk_json_write_array_begin(w);
61 	spdk_iscsi_init_grps_info_json(w);
62 	spdk_json_write_array_end(w);
63 
64 	spdk_jsonrpc_end_result(request, w);
65 }
66 SPDK_RPC_REGISTER("get_initiator_groups", spdk_rpc_get_initiator_groups, SPDK_RPC_RUNTIME)
67 
68 struct rpc_initiator_list {
69 	size_t num_initiators;
70 	char *initiators[MAX_INITIATOR];
71 };
72 
73 static int
74 decode_rpc_initiator_list(const struct spdk_json_val *val, void *out)
75 {
76 	struct rpc_initiator_list *list = out;
77 
78 	return spdk_json_decode_array(val, spdk_json_decode_string, list->initiators, MAX_INITIATOR,
79 				      &list->num_initiators, sizeof(char *));
80 }
81 
82 static void
83 free_rpc_initiator_list(struct rpc_initiator_list *list)
84 {
85 	size_t i;
86 
87 	for (i = 0; i < list->num_initiators; i++) {
88 		free(list->initiators[i]);
89 	}
90 }
91 
92 struct rpc_netmask_list {
93 	size_t num_netmasks;
94 	char *netmasks[MAX_NETMASK];
95 };
96 
97 static int
98 decode_rpc_netmask_list(const struct spdk_json_val *val, void *out)
99 {
100 	struct rpc_netmask_list *list = out;
101 
102 	return spdk_json_decode_array(val, spdk_json_decode_string, list->netmasks, MAX_NETMASK,
103 				      &list->num_netmasks, sizeof(char *));
104 }
105 
106 static void
107 free_rpc_netmask_list(struct rpc_netmask_list *list)
108 {
109 	size_t i;
110 
111 	for (i = 0; i < list->num_netmasks; i++) {
112 		free(list->netmasks[i]);
113 	}
114 }
115 
116 struct rpc_initiator_group {
117 	int32_t tag;
118 	struct rpc_initiator_list initiator_list;
119 	struct rpc_netmask_list netmask_list;
120 };
121 
122 static void
123 free_rpc_initiator_group(struct rpc_initiator_group *ig)
124 {
125 	free_rpc_initiator_list(&ig->initiator_list);
126 	free_rpc_netmask_list(&ig->netmask_list);
127 }
128 
129 static const struct spdk_json_object_decoder rpc_initiator_group_decoders[] = {
130 	{"tag", offsetof(struct rpc_initiator_group, tag), spdk_json_decode_int32},
131 	{"initiators", offsetof(struct rpc_initiator_group, initiator_list), decode_rpc_initiator_list},
132 	{"netmasks", offsetof(struct rpc_initiator_group, netmask_list), decode_rpc_netmask_list},
133 };
134 
135 static void
136 spdk_rpc_add_initiator_group(struct spdk_jsonrpc_request *request,
137 			     const struct spdk_json_val *params)
138 {
139 	struct rpc_initiator_group req = {};
140 	struct spdk_json_write_ctx *w;
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 (spdk_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 	w = spdk_jsonrpc_begin_result(request);
165 	spdk_json_write_bool(w, true);
166 	spdk_jsonrpc_end_result(request, w);
167 	return;
168 
169 invalid:
170 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
171 	free_rpc_initiator_group(&req);
172 }
173 SPDK_RPC_REGISTER("add_initiator_group", spdk_rpc_add_initiator_group, SPDK_RPC_RUNTIME)
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 spdk_rpc_add_initiators_to_initiator_group(struct spdk_jsonrpc_request *request,
183 		const struct spdk_json_val *params)
184 {
185 	struct rpc_initiator_group req = {};
186 	struct spdk_json_write_ctx *w;
187 
188 	if (spdk_json_decode_object(params, rpc_add_or_delete_initiators_decoders,
189 				    SPDK_COUNTOF(rpc_add_or_delete_initiators_decoders), &req)) {
190 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
191 		goto invalid;
192 	}
193 
194 	if (spdk_iscsi_init_grp_add_initiators_from_initiator_list(req.tag,
195 			req.initiator_list.num_initiators,
196 			req.initiator_list.initiators,
197 			req.netmask_list.num_netmasks,
198 			req.netmask_list.netmasks)) {
199 		SPDK_ERRLOG("add_initiators_from_initiator_list failed\n");
200 		goto invalid;
201 	}
202 
203 	free_rpc_initiator_group(&req);
204 
205 	w = spdk_jsonrpc_begin_result(request);
206 	spdk_json_write_bool(w, true);
207 	spdk_jsonrpc_end_result(request, w);
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("add_initiators_to_initiator_group",
215 		  spdk_rpc_add_initiators_to_initiator_group, SPDK_RPC_RUNTIME)
216 
217 static void
218 spdk_rpc_delete_initiators_from_initiator_group(struct spdk_jsonrpc_request *request,
219 		const struct spdk_json_val *params)
220 {
221 	struct rpc_initiator_group req = {};
222 	struct spdk_json_write_ctx *w;
223 
224 	if (spdk_json_decode_object(params, rpc_add_or_delete_initiators_decoders,
225 				    SPDK_COUNTOF(rpc_add_or_delete_initiators_decoders), &req)) {
226 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
227 		goto invalid;
228 	}
229 
230 	if (spdk_iscsi_init_grp_delete_initiators_from_initiator_list(req.tag,
231 			req.initiator_list.num_initiators,
232 			req.initiator_list.initiators,
233 			req.netmask_list.num_netmasks,
234 			req.netmask_list.netmasks)) {
235 		SPDK_ERRLOG("delete_initiators_from_initiator_list failed\n");
236 		goto invalid;
237 	}
238 
239 	free_rpc_initiator_group(&req);
240 
241 	w = spdk_jsonrpc_begin_result(request);
242 	spdk_json_write_bool(w, true);
243 	spdk_jsonrpc_end_result(request, w);
244 	return;
245 
246 invalid:
247 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
248 	free_rpc_initiator_group(&req);
249 }
250 SPDK_RPC_REGISTER("delete_initiators_from_initiator_group",
251 		  spdk_rpc_delete_initiators_from_initiator_group, SPDK_RPC_RUNTIME)
252 
253 struct rpc_delete_initiator_group {
254 	int32_t tag;
255 };
256 
257 static const struct spdk_json_object_decoder rpc_delete_initiator_group_decoders[] = {
258 	{"tag", offsetof(struct rpc_delete_initiator_group, tag), spdk_json_decode_int32},
259 };
260 
261 static void
262 spdk_rpc_delete_initiator_group(struct spdk_jsonrpc_request *request,
263 				const struct spdk_json_val *params)
264 {
265 	struct rpc_delete_initiator_group req = {};
266 	struct spdk_json_write_ctx *w;
267 	struct spdk_iscsi_init_grp *ig;
268 
269 	if (spdk_json_decode_object(params, rpc_delete_initiator_group_decoders,
270 				    SPDK_COUNTOF(rpc_delete_initiator_group_decoders),
271 				    &req)) {
272 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
273 		goto invalid;
274 	}
275 
276 	ig = spdk_iscsi_init_grp_unregister(req.tag);
277 	if (!ig) {
278 		goto invalid;
279 	}
280 	spdk_iscsi_tgt_node_delete_map(NULL, ig);
281 	spdk_iscsi_init_grp_destroy(ig);
282 
283 	w = spdk_jsonrpc_begin_result(request);
284 	spdk_json_write_bool(w, true);
285 	spdk_jsonrpc_end_result(request, w);
286 	return;
287 
288 invalid:
289 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
290 }
291 SPDK_RPC_REGISTER("delete_initiator_group", spdk_rpc_delete_initiator_group, SPDK_RPC_RUNTIME)
292 
293 static void
294 spdk_rpc_get_target_nodes(struct spdk_jsonrpc_request *request,
295 			  const struct spdk_json_val *params)
296 {
297 	struct spdk_json_write_ctx *w;
298 
299 	if (params != NULL) {
300 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
301 						 "get_target_nodes requires no parameters");
302 		return;
303 	}
304 
305 	w = spdk_jsonrpc_begin_result(request);
306 	spdk_json_write_array_begin(w);
307 	spdk_iscsi_tgt_nodes_info_json(w);
308 	spdk_json_write_array_end(w);
309 
310 	spdk_jsonrpc_end_result(request, w);
311 }
312 SPDK_RPC_REGISTER("get_target_nodes", spdk_rpc_get_target_nodes, SPDK_RPC_RUNTIME)
313 
314 struct rpc_pg_ig_map {
315 	int32_t pg_tag;
316 	int32_t ig_tag;
317 };
318 
319 static const struct spdk_json_object_decoder rpc_pg_ig_map_decoders[] = {
320 	{"pg_tag", offsetof(struct rpc_pg_ig_map, pg_tag), spdk_json_decode_int32},
321 	{"ig_tag", offsetof(struct rpc_pg_ig_map, ig_tag), spdk_json_decode_int32},
322 };
323 
324 static int
325 decode_rpc_pg_ig_map(const struct spdk_json_val *val, void *out)
326 {
327 	struct rpc_pg_ig_map *pg_ig_map = out;
328 
329 	return spdk_json_decode_object(val, rpc_pg_ig_map_decoders,
330 				       SPDK_COUNTOF(rpc_pg_ig_map_decoders),
331 				       pg_ig_map);
332 }
333 
334 struct rpc_pg_ig_maps {
335 	size_t num_maps;
336 	struct rpc_pg_ig_map maps[MAX_TARGET_MAP];
337 };
338 
339 static int
340 decode_rpc_pg_ig_maps(const struct spdk_json_val *val, void *out)
341 {
342 	struct rpc_pg_ig_maps *pg_ig_maps = out;
343 
344 	return spdk_json_decode_array(val, decode_rpc_pg_ig_map, pg_ig_maps->maps,
345 				      MAX_TARGET_MAP, &pg_ig_maps->num_maps,
346 				      sizeof(struct rpc_pg_ig_map));
347 }
348 
349 #define RPC_CONSTRUCT_TARGET_NODE_MAX_LUN	64
350 
351 struct rpc_lun {
352 	char *bdev_name;
353 	int32_t lun_id;
354 };
355 
356 static const struct spdk_json_object_decoder rpc_lun_decoders[] = {
357 	{"bdev_name", offsetof(struct rpc_lun, bdev_name), spdk_json_decode_string},
358 	{"lun_id", offsetof(struct rpc_lun, lun_id), spdk_json_decode_int32},
359 };
360 
361 static int
362 decode_rpc_lun(const struct spdk_json_val *val, void *out)
363 {
364 	struct rpc_lun *lun = out;
365 
366 	return spdk_json_decode_object(val, rpc_lun_decoders,
367 				       SPDK_COUNTOF(rpc_lun_decoders), lun);
368 }
369 
370 struct rpc_luns {
371 	size_t num_luns;
372 	struct rpc_lun luns[RPC_CONSTRUCT_TARGET_NODE_MAX_LUN];
373 };
374 
375 static int
376 decode_rpc_luns(const struct spdk_json_val *val, void *out)
377 {
378 	struct rpc_luns *luns = out;
379 
380 	return spdk_json_decode_array(val, decode_rpc_lun, luns->luns,
381 				      RPC_CONSTRUCT_TARGET_NODE_MAX_LUN,
382 				      &luns->num_luns, sizeof(struct rpc_lun));
383 }
384 
385 static void
386 free_rpc_luns(struct rpc_luns *p)
387 {
388 	size_t i;
389 
390 	for (i = 0; i < p->num_luns; i++) {
391 		free(p->luns[i].bdev_name);
392 	}
393 }
394 
395 struct rpc_target_node {
396 	char *name;
397 	char *alias_name;
398 
399 	struct rpc_pg_ig_maps pg_ig_maps;
400 	struct rpc_luns luns;
401 
402 	int32_t queue_depth;
403 	bool disable_chap;
404 	bool require_chap;
405 	bool mutual_chap;
406 	int32_t chap_group;
407 
408 	bool header_digest;
409 	bool data_digest;
410 };
411 
412 static void
413 free_rpc_target_node(struct rpc_target_node *req)
414 {
415 	free(req->name);
416 	free(req->alias_name);
417 	free_rpc_luns(&req->luns);
418 }
419 
420 static const struct spdk_json_object_decoder rpc_target_node_decoders[] = {
421 	{"name", offsetof(struct rpc_target_node, name), spdk_json_decode_string},
422 	{"alias_name", offsetof(struct rpc_target_node, alias_name), spdk_json_decode_string},
423 	{"pg_ig_maps", offsetof(struct rpc_target_node, pg_ig_maps), decode_rpc_pg_ig_maps},
424 	{"luns", offsetof(struct rpc_target_node, luns), decode_rpc_luns},
425 	{"queue_depth", offsetof(struct rpc_target_node, queue_depth), spdk_json_decode_int32},
426 	{"disable_chap", offsetof(struct rpc_target_node, disable_chap), spdk_json_decode_bool, true},
427 	{"require_chap", offsetof(struct rpc_target_node, require_chap), spdk_json_decode_bool, true},
428 	{"mutual_chap", offsetof(struct rpc_target_node, mutual_chap), spdk_json_decode_bool, true},
429 	{"chap_group", offsetof(struct rpc_target_node, chap_group), spdk_json_decode_int32, true},
430 	{"header_digest", offsetof(struct rpc_target_node, header_digest), spdk_json_decode_bool, true},
431 	{"data_digest", offsetof(struct rpc_target_node, data_digest), spdk_json_decode_bool, true},
432 };
433 
434 static void
435 spdk_rpc_construct_target_node(struct spdk_jsonrpc_request *request,
436 			       const struct spdk_json_val *params)
437 {
438 	struct rpc_target_node req = {};
439 	struct spdk_json_write_ctx *w;
440 	struct spdk_iscsi_tgt_node *target;
441 	int32_t pg_tags[MAX_TARGET_MAP] = {0}, ig_tags[MAX_TARGET_MAP] = {0};
442 	char *bdev_names[RPC_CONSTRUCT_TARGET_NODE_MAX_LUN] = {0};
443 	int32_t lun_ids[RPC_CONSTRUCT_TARGET_NODE_MAX_LUN] = {0};
444 	size_t i;
445 
446 	if (spdk_json_decode_object(params, rpc_target_node_decoders,
447 				    SPDK_COUNTOF(rpc_target_node_decoders),
448 				    &req)) {
449 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
450 		goto invalid;
451 	}
452 
453 	for (i = 0; i < req.pg_ig_maps.num_maps; i++) {
454 		pg_tags[i] = req.pg_ig_maps.maps[i].pg_tag;
455 		ig_tags[i] = req.pg_ig_maps.maps[i].ig_tag;
456 	}
457 
458 	for (i = 0; i < req.luns.num_luns; i++) {
459 		bdev_names[i] = req.luns.luns[i].bdev_name;
460 		lun_ids[i] = req.luns.luns[i].lun_id;
461 	}
462 
463 	/*
464 	 * Use default parameters in a few places:
465 	 *  index = -1 : automatically pick an index for the new target node
466 	 *  alias = NULL
467 	 */
468 	target = spdk_iscsi_tgt_node_construct(-1, req.name, req.alias_name,
469 					       pg_tags,
470 					       ig_tags,
471 					       req.pg_ig_maps.num_maps,
472 					       (const char **)bdev_names,
473 					       lun_ids,
474 					       req.luns.num_luns,
475 					       req.queue_depth,
476 					       req.disable_chap,
477 					       req.require_chap,
478 					       req.mutual_chap,
479 					       req.chap_group,
480 					       req.header_digest,
481 					       req.data_digest);
482 
483 	if (target == NULL) {
484 		goto invalid;
485 	}
486 
487 	free_rpc_target_node(&req);
488 
489 	w = spdk_jsonrpc_begin_result(request);
490 	spdk_json_write_bool(w, true);
491 	spdk_jsonrpc_end_result(request, w);
492 	return;
493 
494 invalid:
495 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
496 	free_rpc_target_node(&req);
497 }
498 SPDK_RPC_REGISTER("construct_target_node", spdk_rpc_construct_target_node, SPDK_RPC_RUNTIME)
499 
500 struct rpc_tgt_node_pg_ig_maps {
501 	char *name;
502 	struct rpc_pg_ig_maps pg_ig_maps;
503 };
504 
505 static const struct spdk_json_object_decoder rpc_tgt_node_pg_ig_maps_decoders[] = {
506 	{"name", offsetof(struct rpc_tgt_node_pg_ig_maps, name), spdk_json_decode_string},
507 	{"pg_ig_maps", offsetof(struct rpc_tgt_node_pg_ig_maps, pg_ig_maps), decode_rpc_pg_ig_maps},
508 };
509 
510 static void
511 spdk_rpc_add_pg_ig_maps(struct spdk_jsonrpc_request *request,
512 			const struct spdk_json_val *params)
513 {
514 	struct rpc_tgt_node_pg_ig_maps req = {};
515 	struct spdk_json_write_ctx *w;
516 	struct spdk_iscsi_tgt_node *target;
517 	int32_t pg_tags[MAX_TARGET_MAP] = {0}, ig_tags[MAX_TARGET_MAP] = {0};
518 	size_t i;
519 	int rc;
520 
521 	if (spdk_json_decode_object(params, rpc_tgt_node_pg_ig_maps_decoders,
522 				    SPDK_COUNTOF(rpc_tgt_node_pg_ig_maps_decoders),
523 				    &req)) {
524 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
525 		goto invalid;
526 	}
527 
528 	target = spdk_iscsi_find_tgt_node(req.name);
529 	if (target == NULL) {
530 		SPDK_ERRLOG("target is not found\n");
531 		goto invalid;
532 	}
533 
534 	for (i = 0; i < req.pg_ig_maps.num_maps; i++) {
535 		pg_tags[i] = req.pg_ig_maps.maps[i].pg_tag;
536 		ig_tags[i] = req.pg_ig_maps.maps[i].ig_tag;
537 	}
538 
539 	rc = spdk_iscsi_tgt_node_add_pg_ig_maps(target, pg_tags, ig_tags,
540 						req.pg_ig_maps.num_maps);
541 	if (rc < 0) {
542 		SPDK_ERRLOG("add pg-ig maps failed\n");
543 		goto invalid;
544 	}
545 
546 	free(req.name);
547 
548 	w = spdk_jsonrpc_begin_result(request);
549 	spdk_json_write_bool(w, true);
550 	spdk_jsonrpc_end_result(request, w);
551 	return;
552 
553 invalid:
554 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
555 					 "Invalid parameters");
556 	free(req.name);
557 }
558 SPDK_RPC_REGISTER("add_pg_ig_maps", spdk_rpc_add_pg_ig_maps, SPDK_RPC_RUNTIME)
559 
560 static void
561 spdk_rpc_delete_pg_ig_maps(struct spdk_jsonrpc_request *request,
562 			   const struct spdk_json_val *params)
563 {
564 	struct rpc_tgt_node_pg_ig_maps req = {};
565 	struct spdk_json_write_ctx *w;
566 	struct spdk_iscsi_tgt_node *target;
567 	int32_t pg_tags[MAX_TARGET_MAP] = {0}, ig_tags[MAX_TARGET_MAP] = {0};
568 	size_t i;
569 	int rc;
570 
571 	if (spdk_json_decode_object(params, rpc_tgt_node_pg_ig_maps_decoders,
572 				    SPDK_COUNTOF(rpc_tgt_node_pg_ig_maps_decoders),
573 				    &req)) {
574 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
575 		goto invalid;
576 	}
577 
578 	target = spdk_iscsi_find_tgt_node(req.name);
579 	if (target == NULL) {
580 		SPDK_ERRLOG("target is not found\n");
581 		goto invalid;
582 	}
583 
584 	for (i = 0; i < req.pg_ig_maps.num_maps; i++) {
585 		pg_tags[i] = req.pg_ig_maps.maps[i].pg_tag;
586 		ig_tags[i] = req.pg_ig_maps.maps[i].ig_tag;
587 	}
588 
589 	rc = spdk_iscsi_tgt_node_delete_pg_ig_maps(target, pg_tags, ig_tags,
590 			req.pg_ig_maps.num_maps);
591 	if (rc < 0) {
592 		SPDK_ERRLOG("remove pg-ig maps failed\n");
593 		goto invalid;
594 	}
595 
596 	free(req.name);
597 
598 	w = spdk_jsonrpc_begin_result(request);
599 	spdk_json_write_bool(w, true);
600 	spdk_jsonrpc_end_result(request, w);
601 	return;
602 
603 invalid:
604 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
605 					 "Invalid parameters");
606 	free(req.name);
607 }
608 SPDK_RPC_REGISTER("delete_pg_ig_maps", spdk_rpc_delete_pg_ig_maps, SPDK_RPC_RUNTIME)
609 
610 struct rpc_delete_target_node {
611 	char *name;
612 };
613 
614 static void
615 free_rpc_delete_target_node(struct rpc_delete_target_node *r)
616 {
617 	free(r->name);
618 }
619 
620 static const struct spdk_json_object_decoder rpc_delete_target_node_decoders[] = {
621 	{"name", offsetof(struct rpc_delete_target_node, name), spdk_json_decode_string},
622 };
623 
624 struct rpc_delete_target_node_ctx {
625 	struct rpc_delete_target_node req;
626 	struct spdk_jsonrpc_request *request;
627 };
628 
629 static void
630 rpc_delete_target_node_done(void *cb_arg, int rc)
631 {
632 	struct rpc_delete_target_node_ctx *ctx = cb_arg;
633 	struct spdk_json_write_ctx *w;
634 
635 	free_rpc_delete_target_node(&ctx->req);
636 
637 	w = spdk_jsonrpc_begin_result(ctx->request);
638 	spdk_json_write_bool(w, rc == 0);
639 	spdk_jsonrpc_end_result(ctx->request, w);
640 
641 	free(ctx);
642 }
643 
644 static void
645 spdk_rpc_delete_target_node(struct spdk_jsonrpc_request *request,
646 			    const struct spdk_json_val *params)
647 {
648 	struct rpc_delete_target_node_ctx *ctx;
649 
650 	ctx = calloc(1, sizeof(*ctx));
651 	if (!ctx) {
652 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
653 						 spdk_strerror(ENOMEM));
654 		return;
655 	}
656 
657 	if (spdk_json_decode_object(params, rpc_delete_target_node_decoders,
658 				    SPDK_COUNTOF(rpc_delete_target_node_decoders),
659 				    &ctx->req)) {
660 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
661 		goto invalid;
662 	}
663 
664 	if (ctx->req.name == NULL) {
665 		SPDK_ERRLOG("missing name param\n");
666 		goto invalid;
667 	}
668 
669 	ctx->request = request;
670 
671 	spdk_iscsi_shutdown_tgt_node_by_name(ctx->req.name,
672 					     rpc_delete_target_node_done, ctx);
673 	return;
674 
675 invalid:
676 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
677 	free_rpc_delete_target_node(&ctx->req);
678 	free(ctx);
679 }
680 SPDK_RPC_REGISTER("delete_target_node", spdk_rpc_delete_target_node, SPDK_RPC_RUNTIME)
681 
682 static void
683 spdk_rpc_get_portal_groups(struct spdk_jsonrpc_request *request,
684 			   const struct spdk_json_val *params)
685 {
686 	struct spdk_json_write_ctx *w;
687 
688 	if (params != NULL) {
689 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
690 						 "get_portal_groups requires no parameters");
691 		return;
692 	}
693 
694 	w = spdk_jsonrpc_begin_result(request);
695 	spdk_json_write_array_begin(w);
696 	spdk_iscsi_portal_grps_info_json(w);
697 	spdk_json_write_array_end(w);
698 
699 	spdk_jsonrpc_end_result(request, w);
700 }
701 SPDK_RPC_REGISTER("get_portal_groups", spdk_rpc_get_portal_groups, SPDK_RPC_RUNTIME)
702 
703 struct rpc_portal {
704 	char *host;
705 	char *port;
706 	char *cpumask;
707 };
708 
709 struct rpc_portal_list {
710 	size_t num_portals;
711 	struct rpc_portal portals[MAX_PORTAL];
712 };
713 
714 struct rpc_portal_group {
715 	int32_t tag;
716 	struct rpc_portal_list portal_list;
717 };
718 
719 static void
720 free_rpc_portal(struct rpc_portal *portal)
721 {
722 	free(portal->host);
723 	free(portal->port);
724 	free(portal->cpumask);
725 }
726 
727 static void
728 free_rpc_portal_list(struct rpc_portal_list *pl)
729 {
730 	size_t i;
731 
732 	for (i = 0; i < pl->num_portals; i++) {
733 		free_rpc_portal(&pl->portals[i]);
734 	}
735 	pl->num_portals = 0;
736 }
737 
738 static void
739 free_rpc_portal_group(struct rpc_portal_group *pg)
740 {
741 	free_rpc_portal_list(&pg->portal_list);
742 }
743 
744 static const struct spdk_json_object_decoder rpc_portal_decoders[] = {
745 	{"host", offsetof(struct rpc_portal, host), spdk_json_decode_string},
746 	{"port", offsetof(struct rpc_portal, port), spdk_json_decode_string},
747 	{"cpumask", offsetof(struct rpc_portal, cpumask), spdk_json_decode_string, true},
748 };
749 
750 static int
751 decode_rpc_portal(const struct spdk_json_val *val, void *out)
752 {
753 	struct rpc_portal *portal = out;
754 
755 	return spdk_json_decode_object(val, rpc_portal_decoders,
756 				       SPDK_COUNTOF(rpc_portal_decoders),
757 				       portal);
758 }
759 
760 static int
761 decode_rpc_portal_list(const struct spdk_json_val *val, void *out)
762 {
763 	struct rpc_portal_list *list = out;
764 
765 	return spdk_json_decode_array(val, decode_rpc_portal, list->portals, MAX_PORTAL, &list->num_portals,
766 				      sizeof(struct rpc_portal));
767 }
768 
769 static const struct spdk_json_object_decoder rpc_portal_group_decoders[] = {
770 	{"tag", offsetof(struct rpc_portal_group, tag), spdk_json_decode_int32},
771 	{"portals", offsetof(struct rpc_portal_group, portal_list), decode_rpc_portal_list},
772 };
773 
774 static void
775 spdk_rpc_add_portal_group(struct spdk_jsonrpc_request *request,
776 			  const struct spdk_json_val *params)
777 {
778 	struct rpc_portal_group req = {};
779 	struct spdk_iscsi_portal_grp *pg = NULL;
780 	struct spdk_iscsi_portal *portal;
781 	struct spdk_json_write_ctx *w;
782 	size_t i = 0;
783 	int rc = -1;
784 
785 	if (spdk_json_decode_object(params, rpc_portal_group_decoders,
786 				    SPDK_COUNTOF(rpc_portal_group_decoders),
787 				    &req)) {
788 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
789 		goto out;
790 	}
791 
792 	pg = spdk_iscsi_portal_grp_create(req.tag);
793 	if (pg == NULL) {
794 		SPDK_ERRLOG("portal_grp_create failed\n");
795 		goto out;
796 	}
797 	for (i = 0; i < req.portal_list.num_portals; i++) {
798 		if (req.portal_list.portals[i].cpumask) {
799 			SPDK_WARNLOG("A portal was specified with a CPU mask which is no longer supported.\n");
800 			SPDK_WARNLOG("Ignoring the cpumask.\n");
801 		}
802 
803 		portal = spdk_iscsi_portal_create(req.portal_list.portals[i].host,
804 						  req.portal_list.portals[i].port);
805 		if (portal == NULL) {
806 			SPDK_ERRLOG("portal_create failed\n");
807 			goto out;
808 		}
809 		spdk_iscsi_portal_grp_add_portal(pg, portal);
810 	}
811 
812 	rc = spdk_iscsi_portal_grp_open(pg);
813 	if (rc != 0) {
814 		SPDK_ERRLOG("portal_grp_open failed\n");
815 		goto out;
816 	}
817 
818 	rc = spdk_iscsi_portal_grp_register(pg);
819 	if (rc != 0) {
820 		SPDK_ERRLOG("portal_grp_register failed\n");
821 	}
822 
823 out:
824 	if (rc == 0) {
825 		w = spdk_jsonrpc_begin_result(request);
826 		spdk_json_write_bool(w, true);
827 		spdk_jsonrpc_end_result(request, w);
828 	} else {
829 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
830 
831 		if (pg != NULL) {
832 			spdk_iscsi_portal_grp_release(pg);
833 		}
834 	}
835 	free_rpc_portal_group(&req);
836 }
837 SPDK_RPC_REGISTER("add_portal_group", spdk_rpc_add_portal_group, SPDK_RPC_RUNTIME)
838 
839 struct rpc_delete_portal_group {
840 	int32_t tag;
841 };
842 
843 static const struct spdk_json_object_decoder rpc_delete_portal_group_decoders[] = {
844 	{"tag", offsetof(struct rpc_delete_portal_group, tag), spdk_json_decode_int32},
845 };
846 
847 static void
848 spdk_rpc_delete_portal_group(struct spdk_jsonrpc_request *request,
849 			     const struct spdk_json_val *params)
850 {
851 	struct rpc_delete_portal_group req = {};
852 	struct spdk_json_write_ctx *w;
853 	struct spdk_iscsi_portal_grp *pg;
854 
855 	if (spdk_json_decode_object(params, rpc_delete_portal_group_decoders,
856 				    SPDK_COUNTOF(rpc_delete_portal_group_decoders),
857 				    &req)) {
858 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
859 		goto invalid;
860 	}
861 
862 	pg = spdk_iscsi_portal_grp_unregister(req.tag);
863 	if (!pg) {
864 		goto invalid;
865 	}
866 
867 	spdk_iscsi_tgt_node_delete_map(pg, NULL);
868 	spdk_iscsi_portal_grp_release(pg);
869 
870 	w = spdk_jsonrpc_begin_result(request);
871 	spdk_json_write_bool(w, true);
872 	spdk_jsonrpc_end_result(request, w);
873 	return;
874 
875 invalid:
876 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
877 }
878 SPDK_RPC_REGISTER("delete_portal_group", spdk_rpc_delete_portal_group, SPDK_RPC_RUNTIME)
879 
880 struct rpc_get_iscsi_connections_ctx {
881 	struct spdk_jsonrpc_request *request;
882 	struct spdk_json_write_ctx *w;
883 };
884 
885 static void
886 rpc_get_iscsi_connections_done(struct spdk_io_channel_iter *i, int status)
887 {
888 	struct rpc_get_iscsi_connections_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
889 
890 	spdk_json_write_array_end(ctx->w);
891 	spdk_jsonrpc_end_result(ctx->request, ctx->w);
892 
893 	free(ctx);
894 }
895 
896 static void
897 rpc_get_iscsi_connections(struct spdk_io_channel_iter *i)
898 {
899 	struct rpc_get_iscsi_connections_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
900 	struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i);
901 	struct spdk_iscsi_poll_group *pg = spdk_io_channel_get_ctx(ch);
902 	struct spdk_iscsi_conn *conn;
903 
904 	STAILQ_FOREACH(conn, &pg->connections, link) {
905 		spdk_iscsi_conn_info_json(ctx->w, conn);
906 	}
907 
908 	spdk_for_each_channel_continue(i, 0);
909 }
910 
911 static void
912 spdk_rpc_get_iscsi_connections(struct spdk_jsonrpc_request *request,
913 			       const struct spdk_json_val *params)
914 {
915 	struct rpc_get_iscsi_connections_ctx *ctx;
916 
917 	if (params != NULL) {
918 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
919 						 "get_iscsi_connections requires no parameters");
920 		return;
921 	}
922 
923 	ctx = calloc(1, sizeof(struct rpc_get_iscsi_connections_ctx));
924 	if (ctx == NULL) {
925 		SPDK_ERRLOG("Failed to allocate rpc_get_iscsi_conns_ctx struct\n");
926 		spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
927 		return;
928 	}
929 
930 	ctx->request = request;
931 	ctx->w = spdk_jsonrpc_begin_result(request);
932 
933 	spdk_json_write_array_begin(ctx->w);
934 
935 	spdk_for_each_channel(&g_spdk_iscsi,
936 			      rpc_get_iscsi_connections,
937 			      ctx,
938 			      rpc_get_iscsi_connections_done);
939 }
940 SPDK_RPC_REGISTER("get_iscsi_connections", spdk_rpc_get_iscsi_connections, SPDK_RPC_RUNTIME)
941 
942 struct rpc_target_lun {
943 	char *name;
944 	char *bdev_name;
945 	int32_t lun_id;
946 };
947 
948 static void
949 free_rpc_target_lun(struct rpc_target_lun *req)
950 {
951 	free(req->name);
952 	free(req->bdev_name);
953 }
954 
955 static const struct spdk_json_object_decoder rpc_target_lun_decoders[] = {
956 	{"name", offsetof(struct rpc_target_lun, name), spdk_json_decode_string},
957 	{"bdev_name", offsetof(struct rpc_target_lun, bdev_name), spdk_json_decode_string},
958 	{"lun_id", offsetof(struct rpc_target_lun, lun_id), spdk_json_decode_int32, true},
959 };
960 
961 static void
962 spdk_rpc_target_node_add_lun(struct spdk_jsonrpc_request *request,
963 			     const struct spdk_json_val *params)
964 {
965 	struct rpc_target_lun req = {};
966 	struct spdk_json_write_ctx *w;
967 	struct spdk_iscsi_tgt_node *target;
968 	int rc;
969 
970 	req.lun_id = -1;
971 
972 	if (spdk_json_decode_object(params, rpc_target_lun_decoders,
973 				    SPDK_COUNTOF(rpc_target_lun_decoders), &req)) {
974 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
975 		goto invalid;
976 	}
977 
978 	target = spdk_iscsi_find_tgt_node(req.name);
979 	if (target == NULL) {
980 		SPDK_ERRLOG("target is not found\n");
981 		goto invalid;
982 	}
983 
984 	rc = spdk_iscsi_tgt_node_add_lun(target, req.bdev_name, req.lun_id);
985 	if (rc < 0) {
986 		SPDK_ERRLOG("add lun failed\n");
987 		goto invalid;
988 	}
989 
990 	free_rpc_target_lun(&req);
991 
992 	w = spdk_jsonrpc_begin_result(request);
993 	spdk_json_write_bool(w, true);
994 	spdk_jsonrpc_end_result(request, w);
995 	return;
996 
997 invalid:
998 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
999 					 "Invalid parameters");
1000 	free_rpc_target_lun(&req);
1001 }
1002 SPDK_RPC_REGISTER("target_node_add_lun", spdk_rpc_target_node_add_lun, SPDK_RPC_RUNTIME)
1003 
1004 struct rpc_target_auth {
1005 	char *name;
1006 	bool disable_chap;
1007 	bool require_chap;
1008 	bool mutual_chap;
1009 	int32_t chap_group;
1010 };
1011 
1012 static void
1013 free_rpc_target_auth(struct rpc_target_auth *req)
1014 {
1015 	free(req->name);
1016 }
1017 
1018 static const struct spdk_json_object_decoder rpc_target_auth_decoders[] = {
1019 	{"name", offsetof(struct rpc_target_auth, name), spdk_json_decode_string},
1020 	{"disable_chap", offsetof(struct rpc_target_auth, disable_chap), spdk_json_decode_bool, true},
1021 	{"require_chap", offsetof(struct rpc_target_auth, require_chap), spdk_json_decode_bool, true},
1022 	{"mutual_chap", offsetof(struct rpc_target_auth, mutual_chap), spdk_json_decode_bool, true},
1023 	{"chap_group", offsetof(struct rpc_target_auth, chap_group), spdk_json_decode_int32, true},
1024 };
1025 
1026 static void
1027 spdk_rpc_set_iscsi_target_node_auth(struct spdk_jsonrpc_request *request,
1028 				    const struct spdk_json_val *params)
1029 {
1030 	struct rpc_target_auth req = {};
1031 	struct spdk_json_write_ctx *w;
1032 	struct spdk_iscsi_tgt_node *target;
1033 	int rc;
1034 
1035 	if (spdk_json_decode_object(params, rpc_target_auth_decoders,
1036 				    SPDK_COUNTOF(rpc_target_auth_decoders), &req)) {
1037 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1038 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1039 						 "Invalid parameters");
1040 		goto exit;
1041 	}
1042 
1043 	target = spdk_iscsi_find_tgt_node(req.name);
1044 	if (target == NULL) {
1045 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1046 						     "Could not find target %s", req.name);
1047 		goto exit;
1048 	}
1049 
1050 	rc = spdk_iscsi_tgt_node_set_chap_params(target, req.disable_chap, req.require_chap,
1051 			req.mutual_chap, req.chap_group);
1052 	if (rc < 0) {
1053 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1054 						 "Invalid combination of auth params");
1055 		goto exit;
1056 	}
1057 
1058 	free_rpc_target_auth(&req);
1059 
1060 	w = spdk_jsonrpc_begin_result(request);
1061 	spdk_json_write_bool(w, true);
1062 	spdk_jsonrpc_end_result(request, w);
1063 	return;
1064 
1065 exit:
1066 	free_rpc_target_auth(&req);
1067 }
1068 SPDK_RPC_REGISTER("set_iscsi_target_node_auth", spdk_rpc_set_iscsi_target_node_auth,
1069 		  SPDK_RPC_RUNTIME)
1070 
1071 static void
1072 spdk_rpc_get_iscsi_global_params(struct spdk_jsonrpc_request *request,
1073 				 const struct spdk_json_val *params)
1074 {
1075 	struct spdk_json_write_ctx *w;
1076 
1077 	if (params != NULL) {
1078 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1079 						 "get_iscsi_global_params requires no parameters");
1080 		return;
1081 	}
1082 
1083 	w = spdk_jsonrpc_begin_result(request);
1084 	spdk_iscsi_opts_info_json(w);
1085 
1086 	spdk_jsonrpc_end_result(request, w);
1087 }
1088 SPDK_RPC_REGISTER("get_iscsi_global_params", spdk_rpc_get_iscsi_global_params, SPDK_RPC_RUNTIME)
1089 
1090 struct rpc_discovery_auth {
1091 	bool disable_chap;
1092 	bool require_chap;
1093 	bool mutual_chap;
1094 	int32_t chap_group;
1095 };
1096 
1097 static const struct spdk_json_object_decoder rpc_discovery_auth_decoders[] = {
1098 	{"disable_chap", offsetof(struct rpc_discovery_auth, disable_chap), spdk_json_decode_bool, true},
1099 	{"require_chap", offsetof(struct rpc_discovery_auth, require_chap), spdk_json_decode_bool, true},
1100 	{"mutual_chap", offsetof(struct rpc_discovery_auth, mutual_chap), spdk_json_decode_bool, true},
1101 	{"chap_group", offsetof(struct rpc_discovery_auth, chap_group), spdk_json_decode_int32, true},
1102 };
1103 
1104 static void
1105 spdk_rpc_set_iscsi_discovery_auth(struct spdk_jsonrpc_request *request,
1106 				  const struct spdk_json_val *params)
1107 {
1108 	struct rpc_discovery_auth req = {};
1109 	struct spdk_json_write_ctx *w;
1110 	int rc;
1111 
1112 	if (spdk_json_decode_object(params, rpc_discovery_auth_decoders,
1113 				    SPDK_COUNTOF(rpc_discovery_auth_decoders), &req)) {
1114 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1115 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1116 						 "Invalid parameters");
1117 		return;
1118 	}
1119 
1120 	rc = spdk_iscsi_set_discovery_auth(req.disable_chap, req.require_chap,
1121 					   req.mutual_chap, req.chap_group);
1122 	if (rc < 0) {
1123 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1124 						 "Invalid combination of CHAP params");
1125 		return;
1126 	}
1127 
1128 	w = spdk_jsonrpc_begin_result(request);
1129 	spdk_json_write_bool(w, true);
1130 	spdk_jsonrpc_end_result(request, w);
1131 }
1132 SPDK_RPC_REGISTER("set_iscsi_discovery_auth", spdk_rpc_set_iscsi_discovery_auth, SPDK_RPC_RUNTIME)
1133 
1134 
1135 #define MAX_AUTH_SECRETS	64
1136 
1137 struct rpc_auth_secret {
1138 	char *user;
1139 	char *secret;
1140 	char *muser;
1141 	char *msecret;
1142 };
1143 
1144 static void
1145 free_rpc_auth_secret(struct rpc_auth_secret *_secret)
1146 {
1147 	free(_secret->user);
1148 	free(_secret->secret);
1149 	free(_secret->muser);
1150 	free(_secret->msecret);
1151 }
1152 
1153 static const struct spdk_json_object_decoder rpc_auth_secret_decoders[] = {
1154 	{"user", offsetof(struct rpc_auth_secret, user), spdk_json_decode_string},
1155 	{"secret", offsetof(struct rpc_auth_secret, secret), spdk_json_decode_string},
1156 	{"muser", offsetof(struct rpc_auth_secret, muser), spdk_json_decode_string, true},
1157 	{"msecret", offsetof(struct rpc_auth_secret, msecret), spdk_json_decode_string, true},
1158 };
1159 
1160 static int
1161 decode_rpc_auth_secret(const struct spdk_json_val *val, void *out)
1162 {
1163 	struct rpc_auth_secret *_secret = out;
1164 
1165 	return spdk_json_decode_object(val, rpc_auth_secret_decoders,
1166 				       SPDK_COUNTOF(rpc_auth_secret_decoders), _secret);
1167 }
1168 
1169 struct rpc_auth_secrets {
1170 	size_t num_secret;
1171 	struct rpc_auth_secret secrets[MAX_AUTH_SECRETS];
1172 };
1173 
1174 static void
1175 free_rpc_auth_secrets(struct rpc_auth_secrets *secrets)
1176 {
1177 	size_t i;
1178 
1179 	for (i = 0; i < secrets->num_secret; i++) {
1180 		free_rpc_auth_secret(&secrets->secrets[i]);
1181 	}
1182 }
1183 
1184 static int
1185 decode_rpc_auth_secrets(const struct spdk_json_val *val, void *out)
1186 {
1187 	struct rpc_auth_secrets *secrets = out;
1188 
1189 	return spdk_json_decode_array(val, decode_rpc_auth_secret, secrets->secrets,
1190 				      MAX_AUTH_SECRETS, &secrets->num_secret,
1191 				      sizeof(struct rpc_auth_secret));
1192 }
1193 
1194 struct rpc_auth_group {
1195 	int32_t tag;
1196 	struct rpc_auth_secrets secrets;
1197 };
1198 
1199 static void
1200 free_rpc_auth_group(struct rpc_auth_group *group)
1201 {
1202 	free_rpc_auth_secrets(&group->secrets);
1203 }
1204 
1205 static const struct spdk_json_object_decoder rpc_auth_group_decoders[] = {
1206 	{"tag", offsetof(struct rpc_auth_group, tag), spdk_json_decode_int32},
1207 	{"secrets", offsetof(struct rpc_auth_group, secrets), decode_rpc_auth_secrets, true},
1208 };
1209 
1210 static void
1211 spdk_rpc_add_iscsi_auth_group(struct spdk_jsonrpc_request *request,
1212 			      const struct spdk_json_val *params)
1213 {
1214 	struct rpc_auth_group req = {};
1215 	struct rpc_auth_secret *_secret;
1216 	struct spdk_json_write_ctx *w;
1217 	struct spdk_iscsi_auth_group *group = NULL;
1218 	int rc;
1219 	size_t i;
1220 
1221 	if (spdk_json_decode_object(params, rpc_auth_group_decoders,
1222 				    SPDK_COUNTOF(rpc_auth_group_decoders), &req)) {
1223 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1224 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1225 						 "Invalid parameters");
1226 		free_rpc_auth_group(&req);
1227 		return;
1228 	}
1229 
1230 	pthread_mutex_lock(&g_spdk_iscsi.mutex);
1231 
1232 	rc = spdk_iscsi_add_auth_group(req.tag, &group);
1233 	if (rc != 0) {
1234 		pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1235 
1236 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1237 						     "Could not add auth group (%d), %s",
1238 						     req.tag, spdk_strerror(-rc));
1239 		free_rpc_auth_group(&req);
1240 		return;
1241 	}
1242 
1243 	for (i = 0; i < req.secrets.num_secret; i++) {
1244 		_secret = &req.secrets.secrets[i];
1245 		rc = spdk_iscsi_auth_group_add_secret(group, _secret->user, _secret->secret,
1246 						      _secret->muser, _secret->msecret);
1247 		if (rc != 0) {
1248 			spdk_iscsi_delete_auth_group(group);
1249 			pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1250 
1251 			spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1252 							     "Could not add secret to auth group (%d), %s",
1253 							     req.tag, spdk_strerror(-rc));
1254 			free_rpc_auth_group(&req);
1255 			return;
1256 		}
1257 	}
1258 
1259 	pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1260 
1261 	free_rpc_auth_group(&req);
1262 
1263 	w = spdk_jsonrpc_begin_result(request);
1264 	spdk_json_write_bool(w, true);
1265 	spdk_jsonrpc_end_result(request, w);
1266 }
1267 SPDK_RPC_REGISTER("add_iscsi_auth_group", spdk_rpc_add_iscsi_auth_group, SPDK_RPC_RUNTIME)
1268 
1269 struct rpc_delete_auth_group {
1270 	int32_t tag;
1271 };
1272 
1273 static const struct spdk_json_object_decoder rpc_delete_auth_group_decoders[] = {
1274 	{"tag", offsetof(struct rpc_delete_auth_group, tag), spdk_json_decode_int32},
1275 };
1276 
1277 static void
1278 spdk_rpc_delete_iscsi_auth_group(struct spdk_jsonrpc_request *request,
1279 				 const struct spdk_json_val *params)
1280 {
1281 	struct rpc_delete_auth_group req = {};
1282 	struct spdk_json_write_ctx *w;
1283 	struct spdk_iscsi_auth_group *group;
1284 
1285 	if (spdk_json_decode_object(params, rpc_delete_auth_group_decoders,
1286 				    SPDK_COUNTOF(rpc_delete_auth_group_decoders), &req)) {
1287 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1288 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1289 						 "Invalid parameters");
1290 		return;
1291 	}
1292 
1293 	pthread_mutex_lock(&g_spdk_iscsi.mutex);
1294 
1295 	group = spdk_iscsi_find_auth_group_by_tag(req.tag);
1296 	if (group == NULL) {
1297 		pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1298 
1299 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1300 						     "Could not find auth group (%d)", req.tag);
1301 		return;
1302 	}
1303 
1304 	spdk_iscsi_delete_auth_group(group);
1305 
1306 	pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1307 
1308 	w = spdk_jsonrpc_begin_result(request);
1309 	spdk_json_write_bool(w, true);
1310 	spdk_jsonrpc_end_result(request, w);
1311 }
1312 SPDK_RPC_REGISTER("delete_iscsi_auth_group", spdk_rpc_delete_iscsi_auth_group, SPDK_RPC_RUNTIME)
1313 
1314 struct rpc_add_auth_secret {
1315 	int32_t tag;
1316 	char *user;
1317 	char *secret;
1318 	char *muser;
1319 	char *msecret;
1320 };
1321 
1322 static void
1323 free_rpc_add_auth_secret(struct rpc_add_auth_secret *_secret)
1324 {
1325 	free(_secret->user);
1326 	free(_secret->secret);
1327 	free(_secret->muser);
1328 	free(_secret->msecret);
1329 }
1330 
1331 static const struct spdk_json_object_decoder rpc_add_auth_secret_decoders[] = {
1332 	{"tag", offsetof(struct rpc_add_auth_secret, tag), spdk_json_decode_int32},
1333 	{"user", offsetof(struct rpc_add_auth_secret, user), spdk_json_decode_string},
1334 	{"secret", offsetof(struct rpc_add_auth_secret, secret), spdk_json_decode_string},
1335 	{"muser", offsetof(struct rpc_add_auth_secret, muser), spdk_json_decode_string, true},
1336 	{"msecret", offsetof(struct rpc_add_auth_secret, msecret), spdk_json_decode_string, true},
1337 };
1338 
1339 static void
1340 spdk_rpc_add_secret_to_iscsi_auth_group(struct spdk_jsonrpc_request *request,
1341 					const struct spdk_json_val *params)
1342 {
1343 	struct rpc_add_auth_secret req = {};
1344 	struct spdk_json_write_ctx *w;
1345 	struct spdk_iscsi_auth_group *group;
1346 	int rc;
1347 
1348 	if (spdk_json_decode_object(params, rpc_add_auth_secret_decoders,
1349 				    SPDK_COUNTOF(rpc_add_auth_secret_decoders), &req)) {
1350 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1351 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1352 						 "Invalid parameters");
1353 		free_rpc_add_auth_secret(&req);
1354 		return;
1355 	}
1356 
1357 	pthread_mutex_lock(&g_spdk_iscsi.mutex);
1358 
1359 	group = spdk_iscsi_find_auth_group_by_tag(req.tag);
1360 	if (group == NULL) {
1361 		pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1362 
1363 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1364 						     "Could not find auth group (%d)", req.tag);
1365 		free_rpc_add_auth_secret(&req);
1366 		return;
1367 	}
1368 
1369 	rc = spdk_iscsi_auth_group_add_secret(group, req.user, req.secret, req.muser, req.msecret);
1370 	if (rc != 0) {
1371 		pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1372 
1373 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1374 						     "Could not add secret to auth group (%d), %s",
1375 						     req.tag, spdk_strerror(-rc));
1376 		free_rpc_add_auth_secret(&req);
1377 		return;
1378 	}
1379 
1380 	pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1381 
1382 	free_rpc_add_auth_secret(&req);
1383 
1384 	w = spdk_jsonrpc_begin_result(request);
1385 	spdk_json_write_bool(w, true);
1386 	spdk_jsonrpc_end_result(request, w);
1387 }
1388 SPDK_RPC_REGISTER("add_secret_to_iscsi_auth_group", spdk_rpc_add_secret_to_iscsi_auth_group,
1389 		  SPDK_RPC_RUNTIME)
1390 
1391 struct rpc_delete_auth_secret {
1392 	int32_t tag;
1393 	char *user;
1394 };
1395 
1396 static void
1397 free_rpc_delete_auth_secret(struct rpc_delete_auth_secret *_secret)
1398 {
1399 	free(_secret->user);
1400 }
1401 
1402 static const struct spdk_json_object_decoder rpc_delete_auth_secret_decoders[] = {
1403 	{"tag", offsetof(struct rpc_delete_auth_secret, tag), spdk_json_decode_int32},
1404 	{"user", offsetof(struct rpc_delete_auth_secret, user), spdk_json_decode_string},
1405 };
1406 
1407 static void
1408 spdk_rpc_delete_secret_from_iscsi_auth_group(struct spdk_jsonrpc_request *request,
1409 		const struct spdk_json_val *params)
1410 {
1411 	struct rpc_delete_auth_secret req = {};
1412 	struct spdk_json_write_ctx *w;
1413 	struct spdk_iscsi_auth_group *group;
1414 	int rc;
1415 
1416 	if (spdk_json_decode_object(params, rpc_delete_auth_secret_decoders,
1417 				    SPDK_COUNTOF(rpc_delete_auth_secret_decoders), &req)) {
1418 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1419 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1420 						 "Invalid parameters");
1421 		free_rpc_delete_auth_secret(&req);
1422 		return;
1423 	}
1424 
1425 	pthread_mutex_lock(&g_spdk_iscsi.mutex);
1426 
1427 	group = spdk_iscsi_find_auth_group_by_tag(req.tag);
1428 	if (group == NULL) {
1429 		pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1430 
1431 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1432 						     "Could not find auth group (%d)", req.tag);
1433 		free_rpc_delete_auth_secret(&req);
1434 		return;
1435 	}
1436 
1437 	rc = spdk_iscsi_auth_group_delete_secret(group, req.user);
1438 	if (rc != 0) {
1439 		pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1440 
1441 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1442 						     "Could not delete secret from CHAP group (%d), %s",
1443 						     req.tag, spdk_strerror(-rc));
1444 		free_rpc_delete_auth_secret(&req);
1445 		return;
1446 	}
1447 
1448 	pthread_mutex_unlock(&g_spdk_iscsi.mutex);
1449 
1450 	free_rpc_delete_auth_secret(&req);
1451 
1452 	w = spdk_jsonrpc_begin_result(request);
1453 	spdk_json_write_bool(w, true);
1454 	spdk_jsonrpc_end_result(request, w);
1455 }
1456 SPDK_RPC_REGISTER("delete_secret_from_iscsi_auth_group",
1457 		  spdk_rpc_delete_secret_from_iscsi_auth_group, SPDK_RPC_RUNTIME)
1458 
1459 static void
1460 spdk_rpc_get_iscsi_auth_groups(struct spdk_jsonrpc_request *request,
1461 			       const struct spdk_json_val *params)
1462 {
1463 	struct spdk_json_write_ctx *w;
1464 
1465 	if (params != NULL) {
1466 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1467 						 "get_iscsi_auth_groups requires no parameters");
1468 		return;
1469 	}
1470 
1471 	w = spdk_jsonrpc_begin_result(request);
1472 	spdk_json_write_array_begin(w);
1473 	spdk_iscsi_auth_groups_info_json(w);
1474 	spdk_json_write_array_end(w);
1475 
1476 	spdk_jsonrpc_end_result(request, w);
1477 }
1478 SPDK_RPC_REGISTER("get_iscsi_auth_groups", spdk_rpc_get_iscsi_auth_groups, SPDK_RPC_RUNTIME)
1479 
1480 static const struct spdk_json_object_decoder rpc_set_iscsi_opts_decoders[] = {
1481 	{"auth_file", offsetof(struct spdk_iscsi_opts, authfile), spdk_json_decode_string, true},
1482 	{"node_base", offsetof(struct spdk_iscsi_opts, nodebase), spdk_json_decode_string, true},
1483 	{"nop_timeout", offsetof(struct spdk_iscsi_opts, timeout), spdk_json_decode_int32, true},
1484 	{"nop_in_interval", offsetof(struct spdk_iscsi_opts, nopininterval), spdk_json_decode_int32, true},
1485 	{"no_discovery_auth", offsetof(struct spdk_iscsi_opts, disable_chap), spdk_json_decode_bool, true},
1486 	{"req_discovery_auth", offsetof(struct spdk_iscsi_opts, require_chap), spdk_json_decode_bool, true},
1487 	{"req_discovery_auth_mutual", offsetof(struct spdk_iscsi_opts, mutual_chap), spdk_json_decode_bool, true},
1488 	{"discovery_auth_group", offsetof(struct spdk_iscsi_opts, chap_group), spdk_json_decode_int32, true},
1489 	{"disable_chap", offsetof(struct spdk_iscsi_opts, disable_chap), spdk_json_decode_bool, true},
1490 	{"require_chap", offsetof(struct spdk_iscsi_opts, require_chap), spdk_json_decode_bool, true},
1491 	{"mutual_chap", offsetof(struct spdk_iscsi_opts, mutual_chap), spdk_json_decode_bool, true},
1492 	{"chap_group", offsetof(struct spdk_iscsi_opts, chap_group), spdk_json_decode_int32, true},
1493 	{"max_sessions", offsetof(struct spdk_iscsi_opts, MaxSessions), spdk_json_decode_uint32, true},
1494 	{"max_queue_depth", offsetof(struct spdk_iscsi_opts, MaxQueueDepth), spdk_json_decode_uint32, true},
1495 	{"max_connections_per_session", offsetof(struct spdk_iscsi_opts, MaxConnectionsPerSession), spdk_json_decode_uint32, true},
1496 	{"default_time2wait", offsetof(struct spdk_iscsi_opts, DefaultTime2Wait), spdk_json_decode_uint32, true},
1497 	{"default_time2retain", offsetof(struct spdk_iscsi_opts, DefaultTime2Retain), spdk_json_decode_uint32, true},
1498 	{"first_burst_length", offsetof(struct spdk_iscsi_opts, FirstBurstLength), spdk_json_decode_uint32, true},
1499 	{"immediate_data", offsetof(struct spdk_iscsi_opts, ImmediateData), spdk_json_decode_bool, true},
1500 	{"error_recovery_level", offsetof(struct spdk_iscsi_opts, ErrorRecoveryLevel), spdk_json_decode_uint32, true},
1501 	{"allow_duplicated_isid", offsetof(struct spdk_iscsi_opts, AllowDuplicateIsid), spdk_json_decode_bool, true},
1502 	{"min_connections_per_core", offsetof(struct spdk_iscsi_opts, min_connections_per_core), spdk_json_decode_uint32, true},
1503 };
1504 
1505 static void
1506 spdk_rpc_set_iscsi_options(struct spdk_jsonrpc_request *request,
1507 			   const struct spdk_json_val *params)
1508 {
1509 	struct spdk_iscsi_opts *opts;
1510 	struct spdk_json_write_ctx *w;
1511 
1512 	if (g_spdk_iscsi_opts != NULL) {
1513 		SPDK_ERRLOG("this RPC must not be called more than once.\n");
1514 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1515 						 "Must not call more than once");
1516 		return;
1517 	}
1518 
1519 	opts = spdk_iscsi_opts_alloc();
1520 	if (opts == NULL) {
1521 		SPDK_ERRLOG("spdk_iscsi_opts_alloc() failed.\n");
1522 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1523 						 "Out of memory");
1524 		return;
1525 	}
1526 
1527 	if (params != NULL) {
1528 		if (spdk_json_decode_object(params, rpc_set_iscsi_opts_decoders,
1529 					    SPDK_COUNTOF(rpc_set_iscsi_opts_decoders), opts)) {
1530 			SPDK_ERRLOG("spdk_json_decode_object() failed\n");
1531 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1532 							 "Invalid parameters");
1533 			spdk_iscsi_opts_free(opts);
1534 			return;
1535 		}
1536 	}
1537 
1538 	g_spdk_iscsi_opts = spdk_iscsi_opts_copy(opts);
1539 	spdk_iscsi_opts_free(opts);
1540 
1541 	if (g_spdk_iscsi_opts == NULL) {
1542 		SPDK_ERRLOG("spdk_iscsi_opts_copy() failed\n");
1543 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1544 						 "Out of memory");
1545 		return;
1546 	}
1547 
1548 	w = spdk_jsonrpc_begin_result(request);
1549 	spdk_json_write_bool(w, true);
1550 	spdk_jsonrpc_end_result(request, w);
1551 }
1552 SPDK_RPC_REGISTER("set_iscsi_options", spdk_rpc_set_iscsi_options, SPDK_RPC_STARTUP)
1553