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