1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  14  */
  15 
  16 #include <sys/sdt.h>
  17 
  18 #include <krrp_params.h>
  19 
  20 #include "krrp_svc.h"
  21 #include "krrp_session.h"
  22 #include "krrp_ioctl.h"
  23 
  24 static boolean_t krrp_is_input_data_required(krrp_ioctl_cmd_t cmd);
  25 
  26 static int krrp_ioctl_sess_set_private_data(nvlist_t *params,
  27         krrp_error_t *error);
  28 static int krrp_ioctl_sess_get_private_data(nvlist_t *params,
  29     nvlist_t *result, krrp_error_t *error);
  30 
  31 static int krrp_ioctl_sess_status(nvlist_t *params, nvlist_t *result,
  32     krrp_error_t *error);
  33 static int krrp_ioctl_sess_create(nvlist_t *params, krrp_error_t *error);
  34 static int krrp_ioctl_sess_destroy(nvlist_t *params, krrp_error_t *error);
  35 static int krrp_ioctl_sess_run(nvlist_t *params, krrp_error_t *error);
  36 static int krrp_ioctl_sess_send_stop(nvlist_t *params, krrp_error_t *error);
  37 static int krrp_ioctl_sess_create_conn(nvlist_t *params, krrp_error_t *error);
  38 static int krrp_ioctl_sess_create_pdu_engine(nvlist_t *params,
  39     krrp_error_t *error);
  40 
  41 static int krrp_ioctl_sess_create_stream(nvlist_t *params,
  42     boolean_t read_stream, krrp_error_t *error);
  43 static int krrp_ioctl_sess_create_fake_stream(krrp_stream_t **result_stream,
  44     boolean_t sender, nvlist_t *params, krrp_error_t *error);
  45 static int krrp_ioctl_sess_create_read_stream(krrp_stream_t **result_stream,
  46     nvlist_t *params, krrp_error_t *error);
  47 static int krrp_ioctl_sess_create_write_stream(krrp_stream_t **result_stream,
  48     nvlist_t *params, krrp_error_t *error);
  49 
  50 static int krrp_ioctl_sess_conn_throttle(nvlist_t *params, krrp_error_t *error);
  51 static int krrp_ioctl_sess_conn_get_info(nvlist_t *params, nvlist_t *result,
  52     krrp_error_t *error);
  53 
  54 static krrp_sess_t *krrp_ioctl_sess_action_common(nvlist_t *params,
  55     krrp_error_t *error);
  56 
  57 static krrp_stream_read_flag_t krrp_fill_read_stream_flags(nvlist_t *params);
  58 static krrp_stream_write_flag_t krrp_fill_write_stream_flags(nvlist_t *params);
  59 
  60 int
  61 krrp_ioctl_validate_cmd(krrp_ioctl_cmd_t cmd)
  62 {
  63         if (cmd <= KRRP_IOCTL_FIRST || cmd >= KRRP_IOCTL_LAST)
  64                 return (-1);
  65 
  66         return (0);
  67 }
  68 
  69 int krrp_ioctl_process(krrp_ioctl_cmd_t cmd, nvlist_t *input,
  70     nvlist_t *output, krrp_error_t *error)
  71 {
  72         int rc = 0;
  73 
  74         if (input == NULL && krrp_is_input_data_required(cmd)) {
  75                 krrp_error_set(error, KRRP_ERRNO_INVAL, ENODATA);
  76                 rc = -1;
  77                 goto out;
  78         }
  79 
  80         switch (cmd) {
  81         case KRRP_IOCTL_SVC_ENABLE:
  82                 rc = krrp_svc_enable(error);
  83                 break;
  84         case KRRP_IOCTL_SVC_DISABLE:
  85                 rc = krrp_svc_disable(error);
  86                 break;
  87         case KRRP_IOCTL_SVC_STATE:
  88                 krrp_svc_state(output);
  89                 break;
  90         case KRRP_IOCTL_SVC_SET_CONFIG:
  91                 rc = krrp_svc_config(input, NULL, error);
  92                 break;
  93         case KRRP_IOCTL_SVC_GET_CONFIG:
  94                 rc = krrp_svc_config(input, output, error);
  95                 break;
  96         case KRRP_IOCTL_SESS_SET_PRIVATE_DATA:
  97                 rc = krrp_ioctl_sess_set_private_data(input, error);
  98                 break;
  99         case KRRP_IOCTL_SESS_GET_PRIVATE_DATA:
 100                 rc = krrp_ioctl_sess_get_private_data(input, output, error);
 101                 break;
 102         case KRRP_IOCTL_SESS_LIST:
 103                 krrp_svc_list_sessions(output);
 104                 break;
 105         case KRRP_IOCTL_SESS_STATUS:
 106                 rc = krrp_ioctl_sess_status(input, output, error);
 107                 break;
 108         case KRRP_IOCTL_SESS_CREATE:
 109                 rc = krrp_ioctl_sess_create(input, error);
 110                 break;
 111         case KRRP_IOCTL_SESS_DESTROY:
 112                 rc = krrp_ioctl_sess_destroy(input, error);
 113                 break;
 114         case KRRP_IOCTL_SESS_RUN:
 115                 rc = krrp_ioctl_sess_run(input, error);
 116                 break;
 117         case KRRP_IOCTL_SESS_SEND_STOP:
 118                 rc = krrp_ioctl_sess_send_stop(input, error);
 119                 break;
 120         case KRRP_IOCTL_SESS_CREATE_CONN:
 121                 rc = krrp_ioctl_sess_create_conn(input, error);
 122                 break;
 123         case KRRP_IOCTL_SESS_CREATE_PDU_ENGINE:
 124                 rc = krrp_ioctl_sess_create_pdu_engine(input, error);
 125                 break;
 126         case KRRP_IOCTL_SESS_CREATE_READ_STREAM:
 127                 rc = krrp_ioctl_sess_create_stream(input, B_TRUE, error);
 128                 break;
 129         case KRRP_IOCTL_SESS_CREATE_WRITE_STREAM:
 130                 rc = krrp_ioctl_sess_create_stream(input, B_FALSE, error);
 131                 break;
 132         case KRRP_IOCTL_SESS_CONN_THROTTLE:
 133                 rc = krrp_ioctl_sess_conn_throttle(input, error);
 134                 break;
 135         case KRRP_IOCTL_SESS_GET_CONN_INFO:
 136                 rc = krrp_ioctl_sess_conn_get_info(input, output, error);
 137                 break;
 138         default:
 139                 cmn_err(CE_WARN, "Unknown ioctl cmd [%d]", cmd);
 140                 krrp_error_set(error, KRRP_ERRNO_INVAL, ENOTSUP);
 141                 rc = -1;
 142 #ifdef DEBUG
 143                 panic("Unknown ioctl cmd");
 144 #endif
 145         }
 146 
 147 out:
 148         return (rc);
 149 }
 150 
 151 static boolean_t
 152 krrp_is_input_data_required(krrp_ioctl_cmd_t cmd)
 153 {
 154         boolean_t result;
 155 
 156         /*
 157          * If an ioctl requires input data do not forget
 158          * to add it to this switch
 159          */
 160         switch (cmd) {
 161         case KRRP_IOCTL_SVC_SET_CONFIG:
 162         case KRRP_IOCTL_SVC_GET_CONFIG:
 163         case KRRP_IOCTL_SESS_SET_PRIVATE_DATA:
 164         case KRRP_IOCTL_SESS_GET_PRIVATE_DATA:
 165         case KRRP_IOCTL_SESS_STATUS:
 166         case KRRP_IOCTL_SESS_CREATE:
 167         case KRRP_IOCTL_SESS_DESTROY:
 168         case KRRP_IOCTL_SESS_RUN:
 169         case KRRP_IOCTL_SESS_SEND_STOP:
 170         case KRRP_IOCTL_SESS_CREATE_CONN:
 171         case KRRP_IOCTL_SESS_CREATE_PDU_ENGINE:
 172         case KRRP_IOCTL_SESS_CREATE_READ_STREAM:
 173         case KRRP_IOCTL_SESS_CREATE_WRITE_STREAM:
 174                 result = B_TRUE;
 175                 break;
 176         default:
 177                 result = B_FALSE;
 178         }
 179 
 180         return (result);
 181 }
 182 
 183 static int
 184 krrp_ioctl_sess_set_private_data(nvlist_t *params,
 185     krrp_error_t *error)
 186 {
 187         krrp_sess_t *sess = NULL;
 188         int rc;
 189         nvlist_t *private_data = NULL;
 190 
 191         sess = krrp_ioctl_sess_action_common(params, error);
 192         if (sess == NULL)
 193                 return (-1);
 194 
 195         rc = krrp_param_get(KRRP_PARAM_SESS_PRIVATE_DATA,
 196             params, &private_data);
 197         if (rc != 0) {
 198                 krrp_error_set(error, KRRP_ERRNO_SESS, ENODATA);
 199                 goto out;
 200         }
 201 
 202         if (sess->private_data != NULL)
 203                 fnvlist_free(sess->private_data);
 204 
 205         sess->private_data = fnvlist_dup(private_data);
 206 
 207 out:
 208         krrp_sess_rele(sess);
 209         return (rc);
 210 }
 211 
 212 static int
 213 krrp_ioctl_sess_get_private_data(nvlist_t *params, nvlist_t *result,
 214     krrp_error_t *error)
 215 {
 216         krrp_sess_t *sess = NULL;
 217         int rc = -1;
 218 
 219         sess = krrp_ioctl_sess_action_common(params, error);
 220         if (sess == NULL)
 221                 return (-1);
 222 
 223         if (sess->private_data == NULL) {
 224                 krrp_error_set(error, KRRP_ERRNO_SESS, ENODATA);
 225                 goto out;
 226         }
 227 
 228         (void) krrp_param_put(KRRP_PARAM_SESS_PRIVATE_DATA,
 229             result, sess->private_data);
 230         rc = 0;
 231 
 232 out:
 233         krrp_sess_rele(sess);
 234         return (rc);
 235 }
 236 
 237 static int
 238 krrp_ioctl_sess_status(nvlist_t *params, nvlist_t *result,
 239     krrp_error_t *error)
 240 {
 241         krrp_sess_t *sess = NULL;
 242 
 243         sess = krrp_ioctl_sess_action_common(params, error);
 244         if (sess == NULL)
 245                 return (-1);
 246 
 247         krrp_sess_get_status(sess, result);
 248 
 249         krrp_sess_rele(sess);
 250         return (0);
 251 }
 252 
 253 static int
 254 krrp_ioctl_sess_create(nvlist_t *params, krrp_error_t *error)
 255 {
 256         int rc;
 257         const char *sess_id = NULL, *sess_kstat_id = NULL,
 258             *auth_digest = NULL;
 259         krrp_sess_t *sess = NULL;
 260         boolean_t sender = B_FALSE;
 261         boolean_t fake_mode = B_FALSE;
 262         boolean_t compound = B_FALSE;
 263 
 264         rc = krrp_param_get(KRRP_PARAM_SESS_ID, params,
 265             (void *) &sess_id);
 266         if (rc != 0) {
 267                 krrp_error_set(error, KRRP_ERRNO_SESSID, ENOENT);
 268                 return (-1);
 269         }
 270 
 271         rc = krrp_param_get(KRRP_PARAM_SESS_KSTAT_ID, params,
 272             (void *) &sess_kstat_id);
 273         if (rc != 0) {
 274                 krrp_error_set(error, KRRP_ERRNO_KSTATID, ENOENT);
 275                 return (-1);
 276         }
 277 
 278         (void) krrp_param_get(KRRP_PARAM_AUTH_DATA,
 279             params, (void *)&auth_digest);
 280         (void) krrp_param_get(KRRP_PARAM_FAKE_MODE,
 281             params, (void *)&fake_mode);
 282         (void) krrp_param_get(KRRP_PARAM_SESS_SENDER,
 283             params, (void *)&sender);
 284         (void) krrp_param_get(KRRP_PARAM_SESS_COMPOUND,
 285             params, (void *)&compound);
 286 
 287         if (krrp_sess_create(&sess, sess_id, sess_kstat_id,
 288             auth_digest, sender, fake_mode, compound, error) != 0)
 289                 return (-1);
 290 
 291         if (krrp_svc_register_session(sess, error) != 0) {
 292                 krrp_sess_destroy(sess);
 293                 return (-1);
 294         }
 295 
 296         return (0);
 297 }
 298 
 299 static int
 300 krrp_ioctl_sess_destroy(nvlist_t *params, krrp_error_t *error)
 301 {
 302         krrp_sess_t *sess = NULL;
 303 
 304         sess = krrp_ioctl_sess_action_common(params, error);
 305         if (sess == NULL)
 306                 return (-1);
 307 
 308         if (krrp_svc_unregister_session(sess, error) != 0)
 309                 return (-1);
 310 
 311         krrp_sess_destroy(sess);
 312 
 313         return (0);
 314 }
 315 
 316 static int
 317 krrp_ioctl_sess_create_conn(nvlist_t *params, krrp_error_t *error)
 318 {
 319         int rc, remote_port = 0, timeout = 10;
 320         const char *remote_addr = NULL;
 321         krrp_sess_t *sess = NULL;
 322         krrp_conn_t *conn = NULL;
 323 
 324         sess = krrp_ioctl_sess_action_common(params, error);
 325         if (sess == NULL)
 326                 return (-1);
 327 
 328         rc = krrp_param_get(KRRP_PARAM_CONN_TIMEOUT,
 329             params, (void *) &timeout);
 330         if (rc == 0 && (timeout < KRRP_MIN_CONN_TIMEOUT ||
 331             timeout > KRRP_MAX_CONN_TIMEOUT)) {
 332                 rc = -1;
 333                 krrp_error_set(error, KRRP_ERRNO_CONNTIMEOUT, EINVAL);
 334                 goto out;
 335         }
 336 
 337         rc = krrp_param_get(KRRP_PARAM_REMOTE_HOST,
 338             params, (void *) &remote_addr);
 339         if (rc != 0) {
 340                 krrp_error_set(error, KRRP_ERRNO_ADDR, ENOENT);
 341                 goto out;
 342         }
 343 
 344         /* Remote address will be valiated by inet_pton() */
 345 
 346         rc = krrp_param_get(KRRP_PARAM_PORT,
 347             params, (void *) &remote_port);
 348         if (rc != 0) {
 349                 krrp_error_set(error, KRRP_ERRNO_PORT, ENOENT);
 350                 goto out;
 351         }
 352 
 353         if (remote_port < KRRP_MIN_PORT || remote_port > KRRP_MAX_PORT) {
 354                 rc = -1;
 355                 krrp_error_set(error, KRRP_ERRNO_PORT, EINVAL);
 356                 goto out;
 357         }
 358 
 359         rc = krrp_conn_create_from_scratch(&conn,
 360             remote_addr, remote_port, timeout, error);
 361         if (rc != 0)
 362                 goto out;
 363 
 364         rc = krrp_sess_initiator_attach_conn(sess, conn, error);
 365         if (rc != 0)
 366                 krrp_conn_destroy(conn);
 367 
 368 out:
 369         krrp_sess_rele(sess);
 370         return (rc);
 371 }
 372 
 373 static int
 374 krrp_ioctl_sess_create_pdu_engine(nvlist_t *params, krrp_error_t *error)
 375 {
 376         int rc = -1;
 377         krrp_sess_t *sess = NULL;
 378         krrp_pdu_engine_t *pdu_engine = NULL;
 379         boolean_t use_prealloc = B_FALSE;
 380         size_t dblk_data_sz = 0, dblk_head_sz = 0, max_memory = 0;
 381 
 382         sess = krrp_ioctl_sess_action_common(params, error);
 383         if (sess == NULL)
 384                 return (-1);
 385 
 386         /*
 387          * dblk at sender side (since the sender uses ksocket_sendmblk)
 388          * must have some space before data space, because the space is used
 389          * by TCP/IP stack. The size of the space is equal to mblk_wroff,
 390          * that is extracted from sonode_t.
 391          * So to create pdu_engine in this case we need to be sure that
 392          * a connection already established.
 393          */
 394         if (sess->type == KRRP_SESS_SENDER) {
 395                 if (sess->conn == NULL) {
 396                         krrp_error_set(error, KRRP_ERRNO_CONN, ENOENT);
 397                         goto out;
 398                 }
 399 
 400                 dblk_head_sz = sess->conn->mblk_wroff;
 401         }
 402 
 403         rc = krrp_param_get(KRRP_PARAM_DBLK_DATA_SIZE, params,
 404             (void *) &dblk_data_sz);
 405         if (rc != 0) {
 406                 krrp_error_set(error, KRRP_ERRNO_DBLKSZ, ENOENT);
 407                 goto out;
 408         }
 409 
 410         /*
 411          * kmem-allocator works very slowly for mem-blocks >128 KB,
 412          * so the upper limit is 128 KB
 413          *
 414          * the lower limit is just an optimal value
 415          */
 416         if (dblk_data_sz < KRRP_MIN_SESS_PDU_DBLK_DATA_SZ ||
 417             dblk_data_sz > KRRP_MAX_SESS_PDU_DBLK_DATA_SZ) {
 418                 rc = -1;
 419                 krrp_error_set(error, KRRP_ERRNO_DBLKSZ, EINVAL);
 420                 goto out;
 421         }
 422 
 423         rc = krrp_param_get(KRRP_PARAM_MAX_MEMORY, params,
 424             (void *) &max_memory);
 425         if (rc != 0) {
 426                 krrp_error_set(error, KRRP_ERRNO_MAXMEMSZ, ENOENT);
 427                 goto out;
 428         }
 429 
 430         if (max_memory < KRRP_MIN_MAXMEM) {
 431                 rc = -1;
 432                 krrp_error_set(error, KRRP_ERRNO_MAXMEMSZ, EINVAL);
 433                 goto out;
 434         }
 435 
 436         (void) krrp_param_get(KRRP_PARAM_USE_PREALLOCATION, params,
 437             (void *) &use_prealloc);
 438 
 439         rc = krrp_pdu_engine_create(&pdu_engine, B_FALSE,
 440             use_prealloc, max_memory, 0, dblk_head_sz,
 441             dblk_data_sz, error);
 442         if (rc != 0)
 443                 goto out;
 444 
 445         rc = krrp_sess_attach_pdu_engine(sess, pdu_engine, error);
 446         if (rc != 0)
 447                 krrp_pdu_engine_destroy(pdu_engine);
 448 
 449 out:
 450         krrp_sess_rele(sess);
 451         return (rc);
 452 }
 453 
 454 static int
 455 krrp_ioctl_sess_create_stream(nvlist_t *params, boolean_t read_stream,
 456     krrp_error_t *error)
 457 {
 458         int rc = -1;
 459         krrp_sess_t *sess = NULL;
 460         krrp_stream_t *stream = NULL;
 461 
 462         sess = krrp_ioctl_sess_action_common(params, error);
 463         if (sess == NULL)
 464                 return (-1);
 465 
 466         switch (sess->type) {
 467         case KRRP_SESS_SENDER:
 468                 if (!read_stream) {
 469                         krrp_error_set(error, KRRP_ERRNO_SESS, EINVAL);
 470                         goto out;
 471                 }
 472 
 473                 if (sess->fake_mode)
 474                         rc = krrp_ioctl_sess_create_fake_stream(&stream,
 475                             B_TRUE, params, error);
 476                 else
 477                         rc = krrp_ioctl_sess_create_read_stream(&stream,
 478                             params, error);
 479 
 480                 break;
 481         case KRRP_SESS_RECEIVER:
 482                 if (read_stream) {
 483                         krrp_error_set(error, KRRP_ERRNO_SESS, EINVAL);
 484                         goto out;
 485                 }
 486 
 487                 if (sess->fake_mode)
 488                         rc = krrp_ioctl_sess_create_fake_stream(&stream,
 489                             B_FALSE, params, error);
 490                 else
 491                         rc = krrp_ioctl_sess_create_write_stream(&stream,
 492                             params, error);
 493 
 494                 break;
 495         case KRRP_SESS_COMPOUND:
 496                 if (sess->fake_mode && read_stream) {
 497                         krrp_error_set(error, KRRP_ERRNO_SESS, EINVAL);
 498                         goto out;
 499                 }
 500 
 501                 if (read_stream)
 502                         rc = krrp_ioctl_sess_create_read_stream(&stream,
 503                             params, error);
 504                 else if (sess->fake_mode)
 505                         rc = krrp_ioctl_sess_create_fake_stream(&stream,
 506                             B_FALSE, params, error);
 507                 else
 508                         rc = krrp_ioctl_sess_create_write_stream(&stream,
 509                             params, error);
 510 
 511                 break;
 512         }
 513 
 514         if (rc != 0)
 515                 goto out;
 516 
 517         if (read_stream)
 518                 rc = krrp_sess_attach_read_stream(sess, stream, error);
 519         else
 520                 rc = krrp_sess_attach_write_stream(sess, stream, error);
 521 
 522         if (rc != 0)
 523                 krrp_stream_destroy(stream);
 524 
 525 out:
 526         krrp_sess_rele(sess);
 527         return (rc);
 528 }
 529 
 530 static int
 531 krrp_ioctl_sess_create_fake_stream(krrp_stream_t **result_stream,
 532     boolean_t sender, nvlist_t *params, krrp_error_t *error)
 533 {
 534         if (sender) {
 535                 int rc;
 536                 uint64_t fake_data_ds = 0;
 537 
 538                 rc = krrp_param_get(KRRP_PARAM_FAKE_DATA_SIZE,
 539                     params, (void *) &fake_data_ds);
 540                 if (rc != 0) {
 541                         krrp_error_set(error, KRRP_ERRNO_FAKEDSZ, ENOENT);
 542                         return (-1);
 543                 }
 544 
 545                 return (krrp_stream_fake_read_create(result_stream,
 546                     fake_data_ds, error));
 547         } else
 548                 return (krrp_stream_fake_write_create(result_stream, error));
 549 
 550 }
 551 
 552 static int
 553 krrp_ioctl_sess_create_read_stream(krrp_stream_t **result_stream,
 554     nvlist_t *params, krrp_error_t *error)
 555 {
 556         int rc;
 557         const char *dataset = NULL, *base_snap_name = NULL,
 558             *common_snap_name = NULL, *resume_token = NULL,
 559             *skip_snaps_mask = NULL;
 560         uint32_t keep_snaps;
 561         krrp_stream_read_flag_t flags;
 562 
 563         rc = krrp_param_get(KRRP_PARAM_SRC_DATASET,
 564             params, (void *) &dataset);
 565         if (rc != 0) {
 566                 krrp_error_set(error, KRRP_ERRNO_SRCDS, ENOENT);
 567                 return (-1);
 568         }
 569 
 570         (void) krrp_param_get(KRRP_PARAM_RESUME_TOKEN,
 571             params, (void *) &resume_token);
 572 
 573         (void) krrp_param_get(KRRP_PARAM_COMMON_SNAPSHOT,
 574             params, (void *) &common_snap_name);
 575         (void) krrp_param_get(KRRP_PARAM_SRC_SNAPSHOT,
 576             params, (void *) &base_snap_name);
 577 
 578         (void) krrp_param_get(KRRP_PARAM_SKIP_SNAPS_MASK,
 579             params, (void *) &skip_snaps_mask);
 580 
 581         rc = krrp_param_get(KRRP_PARAM_STREAM_KEEP_SNAPS,
 582             params, (void *) &keep_snaps);
 583         if (rc != 0) {
 584                 /* KRRP_PARAM_STREAM_KEEP_SNAPS not defined, so use the MIN */
 585                 keep_snaps = KRRP_MIN_KEEP_SNAPS;
 586         } else if (keep_snaps < KRRP_MIN_KEEP_SNAPS ||
 587             keep_snaps > KRRP_MAX_KEEP_SNAPS) {
 588                 krrp_error_set(error, KRRP_ERRNO_KEEPSNAPS, EINVAL);
 589                 return (-1);
 590         }
 591 
 592         flags = krrp_fill_read_stream_flags(params);
 593 
 594         return (krrp_stream_read_create(result_stream, keep_snaps, dataset,
 595             base_snap_name, common_snap_name, resume_token, flags,
 596             skip_snaps_mask, error));
 597 }
 598 
 599 static int
 600 krrp_ioctl_sess_create_write_stream(krrp_stream_t **result_stream,
 601     nvlist_t *params, krrp_error_t *error)
 602 {
 603         int rc;
 604         const char *dataset = NULL, *common_snap_name = NULL,
 605             *resume_token = NULL;
 606         nvlist_t *ignore_props_list = NULL, *replace_props_list = NULL;
 607         uint32_t keep_snaps;
 608         krrp_stream_write_flag_t flags;
 609 
 610         rc = krrp_param_get(KRRP_PARAM_DST_DATASET,
 611             params, (void *) &dataset);
 612         if (rc != 0) {
 613                 krrp_error_set(error, KRRP_ERRNO_DSTDS, ENOENT);
 614                 return (-1);
 615         }
 616 
 617         (void) krrp_param_get(KRRP_PARAM_RESUME_TOKEN,
 618             params, (void *) &resume_token);
 619 
 620         (void) krrp_param_get(KRRP_PARAM_IGNORE_PROPS_LIST,
 621             params, (void *) &ignore_props_list);
 622         (void) krrp_param_get(KRRP_PARAM_REPLACE_PROPS_LIST,
 623             params, (void *) &replace_props_list);
 624 
 625         (void) krrp_param_get(KRRP_PARAM_COMMON_SNAPSHOT,
 626             params, (void *) &common_snap_name);
 627 
 628         rc = krrp_param_get(KRRP_PARAM_STREAM_KEEP_SNAPS,
 629             params, (void *) &keep_snaps);
 630         if (rc != 0) {
 631                 /* KRRP_PARAM_STREAM_KEEP_SNAPS not defined, so use the MIN */
 632                 keep_snaps = KRRP_MIN_KEEP_SNAPS;
 633         } else if (keep_snaps < KRRP_MIN_KEEP_SNAPS ||
 634             keep_snaps > KRRP_MAX_KEEP_SNAPS) {
 635                 krrp_error_set(error, KRRP_ERRNO_KEEPSNAPS, EINVAL);
 636                 return (-1);
 637         }
 638 
 639         flags = krrp_fill_write_stream_flags(params);
 640 
 641         return (krrp_stream_write_create(result_stream, keep_snaps,
 642             dataset, common_snap_name, resume_token, flags,
 643             ignore_props_list, replace_props_list, error));
 644 }
 645 
 646 static int
 647 krrp_ioctl_sess_run(nvlist_t *params, krrp_error_t *error)
 648 {
 649         krrp_sess_t *sess = NULL;
 650         boolean_t only_once = B_FALSE;
 651         int rc;
 652 
 653         sess = krrp_ioctl_sess_action_common(params, error);
 654         if (sess == NULL)
 655                 return (-1);
 656 
 657         (void) krrp_param_get(KRRP_PARAM_ONLY_ONCE, params,
 658             (void *) &only_once);
 659 
 660         rc = krrp_sess_run(sess, only_once, error);
 661 
 662         krrp_sess_rele(sess);
 663         return (rc);
 664 }
 665 
 666 static int
 667 krrp_ioctl_sess_send_stop(nvlist_t *params, krrp_error_t *error)
 668 {
 669         int rc;
 670         krrp_sess_t *sess = NULL;
 671 
 672         sess = krrp_ioctl_sess_action_common(params, error);
 673         if (sess == NULL)
 674                 return (-1);
 675 
 676         rc = krrp_sess_send_stop(sess, error);
 677 
 678         krrp_sess_rele(sess);
 679         return (rc);
 680 }
 681 
 682 static int
 683 krrp_ioctl_sess_conn_throttle(nvlist_t *params, krrp_error_t *error)
 684 {
 685         int rc;
 686         krrp_sess_t *sess = NULL;
 687         size_t limit = 0;
 688 
 689         sess = krrp_ioctl_sess_action_common(params, error);
 690         if (sess == NULL)
 691                 return (-1);
 692 
 693         rc = krrp_param_get(KRRP_PARAM_THROTTLE,
 694             params, (void *) &limit);
 695         if (rc != 0) {
 696                 krrp_error_set(error, KRRP_ERRNO_THROTTLE, ENOENT);
 697                 goto out;
 698         }
 699 
 700         if (limit < KRRP_MIN_CONN_THROTTLE && limit != 0) {
 701                 krrp_error_set(error, KRRP_ERRNO_THROTTLE, EINVAL);
 702                 rc = -1;
 703                 goto out;
 704         }
 705 
 706         rc = krrp_sess_throttle_conn(sess, limit, error);
 707 
 708 out:
 709         krrp_sess_rele(sess);
 710         return (rc);
 711 }
 712 
 713 static int
 714 krrp_ioctl_sess_conn_get_info(nvlist_t *params, nvlist_t *result,
 715     krrp_error_t *error)
 716 {
 717         int rc;
 718         krrp_sess_t *sess = NULL;
 719 
 720         sess = krrp_ioctl_sess_action_common(params, error);
 721         if (sess == NULL)
 722                 return (-1);
 723 
 724         rc = krrp_sess_get_conn_info(sess, result, error);
 725 
 726         krrp_sess_rele(sess);
 727         return (rc);
 728 }
 729 
 730 static krrp_sess_t *
 731 krrp_ioctl_sess_action_common(nvlist_t *params, krrp_error_t *error)
 732 {
 733         int rc;
 734         krrp_sess_t *sess = NULL;
 735         const char *sess_id = NULL;
 736 
 737         rc = krrp_param_get(KRRP_PARAM_SESS_ID, params,
 738             (void *) &sess_id);
 739         if (rc != 0) {
 740                 krrp_error_set(error, KRRP_ERRNO_SESSID, ENOENT);
 741                 goto out;
 742         }
 743 
 744         sess = krrp_svc_lookup_session(sess_id);
 745         if (sess == NULL) {
 746                 krrp_error_set(error, KRRP_ERRNO_SESS, ENOENT);
 747                 goto out;
 748         }
 749 
 750         if (krrp_sess_try_hold(sess) != 0) {
 751                 krrp_error_set(error, KRRP_ERRNO_SESS, EBUSY);
 752                 sess = NULL;
 753         }
 754 
 755 out:
 756         return (sess);
 757 }
 758 
 759 static krrp_stream_read_flag_t
 760 krrp_fill_read_stream_flags(nvlist_t *params)
 761 {
 762         boolean_t value = B_FALSE;
 763         krrp_stream_read_flag_t flags = 0;
 764 
 765         if (krrp_param_get(KRRP_PARAM_SEND_RECURSIVE,
 766             params, (void *) &value) == 0 && value)
 767                 krrp_stream_set_read_flag(&flags, KRRP_STRMRF_RECURSIVE);
 768 
 769         if (krrp_param_get(KRRP_PARAM_SEND_PROPERTIES,
 770             params, (void *) &value) == 0 && value)
 771                 krrp_stream_set_read_flag(&flags, KRRP_STRMRF_SEND_PROPS);
 772 
 773         if (krrp_param_get(KRRP_PARAM_INCLUDE_ALL_SNAPSHOTS,
 774             params, (void *) &value) == 0 && value)
 775                 krrp_stream_set_read_flag(&flags, KRRP_STRMRF_SEND_ALL_SNAPS);
 776 
 777         if (krrp_param_get(KRRP_PARAM_ENABLE_STREAM_CHKSUM,
 778             params, (void *) &value) == 0 && value)
 779                 krrp_stream_set_read_flag(&flags, KRRP_STRMRF_ENABLE_CHKSUM);
 780 
 781         if (krrp_param_get(KRRP_PARAM_STREAM_EMBEDDED_BLOCKS,
 782             params, (void *) &value) == 0 && value)
 783                 krrp_stream_set_read_flag(&flags, KRRP_STRMRF_EMBEDDED);
 784 
 785         if (krrp_param_get(KRRP_PARAM_STREAM_COMPRESSED_BLOCKS,
 786             params, (void *) &value) == 0 && value)
 787                 krrp_stream_set_read_flag(&flags, KRRP_STRMRF_COMPRESSED);
 788 
 789         if (krrp_param_get(KRRP_PARAM_STREAM_LARGE_BLOCKS,
 790             params, (void *) &value) == 0 && value)
 791                 krrp_stream_set_read_flag(&flags, KRRP_STRMRF_LARGE_BLOCKS);
 792 
 793         return (flags);
 794 }
 795 
 796 static krrp_stream_write_flag_t
 797 krrp_fill_write_stream_flags(nvlist_t *params)
 798 {
 799         boolean_t value = B_FALSE;
 800         krrp_stream_write_flag_t flags = 0;
 801 
 802         if (krrp_param_get(KRRP_PARAM_FORCE_RECEIVE,
 803             params, (void *) &value) == 0 && value)
 804                 krrp_stream_set_write_flag(&flags, KRRP_STRMWF_FORCE_RECV);
 805 
 806         if (krrp_param_get(KRRP_PARAM_ENABLE_STREAM_CHKSUM,
 807             params, (void *) &value) == 0 && value)
 808                 krrp_stream_set_write_flag(&flags, KRRP_STRMWF_ENABLE_CHKSUM);
 809 
 810         if (krrp_param_get(KRRP_PARAM_STREAM_DISCARD_HEAD,
 811             params, (void *) &value) == 0 && value)
 812                 krrp_stream_set_write_flag(&flags, KRRP_STRMWF_DISCARD_HEAD);
 813 
 814         if (krrp_param_get(KRRP_PARAM_STREAM_LEAVE_TAIL,
 815             params, (void *) &value) == 0 && value)
 816                 krrp_stream_set_write_flag(&flags, KRRP_STRMWF_LEAVE_TAIL);
 817 
 818         return (flags);
 819 }