1 /*
   2  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
   4  */
   5 
   6 /*
   7  * BSD 3 Clause License
   8  *
   9  * Copyright (c) 2007, The Storage Networking Industry Association.
  10  *
  11  * Redistribution and use in source and binary forms, with or without
  12  * modification, are permitted provided that the following conditions
  13  * are met:
  14  *      - Redistributions of source code must retain the above copyright
  15  *        notice, this list of conditions and the following disclaimer.
  16  *
  17  *      - Redistributions in binary form must reproduce the above copyright
  18  *        notice, this list of conditions and the following disclaimer in
  19  *        the documentation and/or other materials provided with the
  20  *        distribution.
  21  *
  22  *      - Neither the name of The Storage Networking Industry Association (SNIA)
  23  *        nor the names of its contributors may be used to endorse or promote
  24  *        products derived from this software without specific prior written
  25  *        permission.
  26  *
  27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  28  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  30  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  31  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  37  * POSSIBILITY OF SUCH DAMAGE.
  38  */
  39 /* Copyright (c) 2007, The Storage Networking Industry Association. */
  40 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
  41 #include <sys/types.h>
  42 #include <sys/param.h>
  43 #include <sys/socket.h>
  44 #include <netinet/in.h>
  45 #include <errno.h>
  46 #include <arpa/inet.h>
  47 #include <stdlib.h>
  48 #include <string.h>
  49 #include "ndmpd_common.h"
  50 #include "ndmpd.h"
  51 
  52 static int ndmpd_data_error_send_v4(ndmpd_session_t *session,
  53     ndmp_data_halt_reason reason);
  54 static int ndmpd_data_error_send(ndmpd_session_t *session,
  55     ndmp_data_halt_reason reason);
  56 static void data_accept_connection_v3(void *cookie, int fd, ulong_t mode);
  57 static int create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr,
  58     ushort_t *port);
  59 static ndmp_error data_connect_sock_v3(ndmpd_session_t *session, ulong_t addr,
  60     ushort_t port);
  61 static int discard_data_v3(ndmpd_session_t *session, ulong_t length);
  62 static void nlp_release_job_stat(ndmpd_session_t *session);
  63 static u_longlong_t ndmpd_data_get_info(ndmpd_session_t *session);
  64 
  65 static ndmp_error ndmpd_tar_start_backup_v2(ndmpd_session_t *, char *,
  66     ndmp_pval *, ulong_t);
  67 static ndmp_error ndmpd_tar_start_recover_v2(ndmpd_session_t *, char *,
  68     ndmp_pval *, ulong_t, ndmp_name *, ulong_t);
  69 static ndmp_error ndmpd_tar_start_backup_v3(ndmpd_session_t *, char *,
  70     ndmp_pval *, ulong_t);
  71 static ndmp_error ndmpd_tar_start_recover_v3(ndmpd_session_t *,
  72     ndmp_pval *, ulong_t, ndmp_name_v3 *, ulong_t);
  73 
  74 static ndmp_error ndmpd_zfs_start_op(ndmpd_session_t *,
  75     ndmp_pval *, ulong_t, ndmp_name_v3 *, ulong_t, enum ndmp_data_operation);
  76 
  77 
  78 /*
  79  * ************************************************************************
  80  * NDMP V2 HANDLERS
  81  * ************************************************************************
  82  */
  83 
  84 /*
  85  * ndmpd_data_get_state_v2
  86  *
  87  * Request handler. Returns current data state.
  88  *
  89  * Parameters:
  90  *   connection (input) - connection handle.
  91  *   body       (input) - request message body.
  92  *
  93  * Returns:
  94  *   void
  95  */
  96 /*ARGSUSED*/
  97 void
  98 ndmpd_data_get_state_v2(ndmp_connection_t *connection, void *body)
  99 {
 100         ndmp_data_get_state_reply_v2 reply;
 101         ndmpd_session_t *session = ndmp_get_client_data(connection);
 102 
 103         reply.error = NDMP_NO_ERR;
 104         reply.operation = session->ns_data.dd_operation;
 105         reply.state = session->ns_data.dd_state;
 106         reply.halt_reason = session->ns_data.dd_halt_reason;
 107 
 108         reply.est_time_remain =
 109             session->ns_data.dd_module.dm_stats.ms_est_time_remaining;
 110         reply.est_bytes_remain =
 111             long_long_to_quad(
 112             session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining);
 113 
 114         reply.bytes_processed =
 115             long_long_to_quad(ndmpd_data_get_info(session));
 116 
 117         reply.mover = session->ns_data.dd_mover;
 118         reply.read_offset = long_long_to_quad(session->ns_data.dd_read_offset);
 119         reply.read_length = long_long_to_quad(session->ns_data.dd_read_length);
 120 
 121         ndmp_send_reply(connection, &reply,
 122             "sending data_get_state reply");
 123 }
 124 
 125 
 126 /*
 127  * ndmpd_data_start_backup_v2
 128  *
 129  * Request handler. Starts a backup.
 130  *
 131  * Parameters:
 132  *   connection (input) - connection handle.
 133  *   body       (input) - request message body.
 134  *
 135  * Returns:
 136  *   void
 137  */
 138 void
 139 ndmpd_data_start_backup_v2(ndmp_connection_t *connection, void *body)
 140 {
 141         ndmp_data_start_backup_request_v2 *request;
 142         ndmp_data_start_backup_reply_v2 reply;
 143         ndmpd_session_t *session = ndmp_get_client_data(connection);
 144         ndmp_error err;
 145 
 146         request = (ndmp_data_start_backup_request_v2 *)body;
 147 
 148         reply.error = NDMP_NO_ERR;
 149         session->ns_data.dd_mover = request->mover;
 150 
 151         err = ndmpd_tar_start_backup_v2(session, request->bu_type,
 152             request->env.env_val, request->env.env_len);
 153 
 154         /*
 155          * start_backup sends the reply if the backup is successfully started.
 156          * Otherwise, send the reply containing the error here.
 157          */
 158         if (err != NDMP_NO_ERR) {
 159                 NDMP_LOG(LOG_DEBUG, "err: %d", err);
 160                 reply.error = err;
 161                 ndmp_send_reply(connection, &reply,
 162                     "sending data_start_backup reply");
 163                 ndmpd_data_cleanup(session);
 164         }
 165 }
 166 
 167 /*
 168  * ndmpd_data_start_recover_v2
 169  *
 170  * Request handler. Starts a restore.
 171  *
 172  * Parameters:
 173  *   connection (input) - connection handle.
 174  *   body       (input) - request message body.
 175  *
 176  * Returns:
 177  *   void
 178  */
 179 void
 180 ndmpd_data_start_recover_v2(ndmp_connection_t *connection, void *body)
 181 {
 182         ndmp_data_start_recover_request_v2 *request;
 183         ndmp_data_start_recover_reply_v2 reply;
 184         ndmpd_session_t *session = ndmp_get_client_data(connection);
 185         ndmp_error err;
 186 
 187         request = (ndmp_data_start_recover_request_v2 *) body;
 188         session->ns_data.dd_mover = request->mover;
 189 
 190         err = ndmpd_tar_start_recover_v2(session, request->bu_type,
 191             request->env.env_val, request->env.env_len,
 192             request->nlist.nlist_val, request->nlist.nlist_len);
 193 
 194         /*
 195          * start_recover sends the reply if the recover is successfully started.
 196          * Otherwise, send the reply containing the error here.
 197          */
 198         if (err != NDMP_NO_ERR) {
 199                 reply.error = err;
 200                 ndmp_send_reply(connection, &reply,
 201                     "sending ndmp_data_start_recover_request_v2 reply");
 202                 ndmpd_data_cleanup(session);
 203         }
 204 }
 205 
 206 /*
 207  * ndmpd_data_get_env_v2
 208  *
 209  * Request handler. Returns the environment variable array sent
 210  * with the backup request. This request may only be sent with
 211  * a backup operation is in progress.
 212  *
 213  * Parameters:
 214  *   connection (input) - connection handle.
 215  *   body       (input) - request message body.
 216  *
 217  * Returns:
 218  *   void
 219  */
 220 /*ARGSUSED*/
 221 void
 222 ndmpd_data_get_env_v2(ndmp_connection_t *connection, void *body)
 223 {
 224         ndmp_data_get_env_reply reply;
 225         ndmpd_session_t *session = ndmp_get_client_data(connection);
 226 
 227         (void) memset((void*)&reply, 0, sizeof (reply));
 228         if (session->ns_data.dd_operation != NDMP_DATA_OP_BACKUP) {
 229                 NDMP_LOG(LOG_ERR, "Backup operation not active.");
 230                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 231                 reply.env.env_len = 0;
 232         } else {
 233                 reply.error = NDMP_NO_ERR;
 234                 reply.env.env_len = session->ns_data.dd_env_len;
 235                 reply.env.env_val = session->ns_data.dd_env;
 236         }
 237 
 238         ndmp_send_reply(connection, &reply, "sending data_get_env reply");
 239 }
 240 
 241 
 242 /*
 243  * ndmpd_data_stop_v2
 244  *
 245  * Request handler. Stops the current data operation.
 246  *
 247  * Parameters:
 248  *   connection (input) - connection handle.
 249  *   body       (input) - request message body.
 250  *
 251  * Returns:
 252  *   void
 253  */
 254 /*ARGSUSED*/
 255 void
 256 ndmpd_data_stop_v2(ndmp_connection_t *connection, void *body)
 257 {
 258         ndmp_data_stop_reply reply;
 259         ndmpd_session_t *session = ndmp_get_client_data(connection);
 260 
 261         if (session->ns_data.dd_state != NDMP_DATA_STATE_HALTED) {
 262                 NDMP_LOG(LOG_ERR, "Invalid state to process stop request.");
 263                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 264                 ndmp_send_reply(connection, &reply,
 265                     "sending data_stop reply");
 266                 return;
 267         }
 268         ndmp_waitfor_op(session);
 269         ndmpd_data_cleanup(session);
 270         ndmpd_file_history_cleanup(session, FALSE);
 271 
 272         nlp_release_job_stat(session);
 273 
 274         /* prepare for another data operation */
 275         (void) ndmpd_data_init(session);
 276         ndmpd_file_history_init(session);
 277 
 278         reply.error = NDMP_NO_ERR;
 279         ndmp_send_reply(connection, &reply, "sending data_stop reply");
 280 }
 281 
 282 
 283 /*
 284  * ndmpd_data_abort_v2
 285  *
 286  * Request handler. Aborts the current backup/restore. The operation
 287  * state is not changed to the halted state until after the operation
 288  * has actually been aborted and the notify_halt request has been sent.
 289  *
 290  * Parameters:
 291  *   connection (input) - connection handle.
 292  *   body       (input) - request message body.
 293  *
 294  * Returns:
 295  *   void
 296  */
 297 /*ARGSUSED*/
 298 void
 299 ndmpd_data_abort_v2(ndmp_connection_t *connection, void *body)
 300 {
 301         ndmp_data_abort_reply reply;
 302         ndmpd_session_t *session = ndmp_get_client_data(connection);
 303 
 304         if (session->ns_data.dd_state == NDMP_DATA_STATE_IDLE ||
 305             session->ns_data.dd_state == NDMP_DATA_STATE_HALTED) {
 306                 NDMP_LOG(LOG_ERR, "Invalid state to process abort request.");
 307                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 308                 ndmp_send_reply(connection, &reply,
 309                     "sending data_abort reply");
 310                 return;
 311         }
 312         /*
 313          * Don't go to HALTED state yet. Need to wait for data operation to
 314          * abort. When this happens, ndmpd_done will get called and will
 315          * perform the halt processing.
 316          */
 317         session->ns_data.dd_abort = TRUE;
 318         (*session->ns_data.dd_module.dm_abort_func)(
 319             session->ns_data.dd_module.dm_module_cookie);
 320 
 321         reply.error = NDMP_NO_ERR;
 322         ndmp_send_reply(connection, &reply, "sending data_abort reply");
 323 }
 324 
 325 /*
 326  * ************************************************************************
 327  * NDMP V3 HANDLERS
 328  * ************************************************************************
 329  */
 330 
 331 /*
 332  * ndmpd_data_get_state_v3
 333  *
 334  * Request handler. Returns current data state.
 335  *
 336  * Parameters:
 337  *   connection (input) - connection handle.
 338  *   body       (input) - request message body.
 339  *
 340  * Returns:
 341  *   void
 342  */
 343 /*ARGSUSED*/
 344 void
 345 ndmpd_data_get_state_v3(ndmp_connection_t *connection, void *body)
 346 {
 347         ndmp_data_get_state_reply_v3 reply;
 348         ndmpd_session_t *session = ndmp_get_client_data(connection);
 349 
 350         (void) memset((void*)&reply, 0, sizeof (reply));
 351 
 352         reply.error = NDMP_NO_ERR;
 353         reply.invalid = NDMP_DATA_STATE_EST_BYTES_REMAIN_INVALID
 354             | NDMP_DATA_STATE_EST_TIME_REMAIN_INVALID;
 355         reply.operation = session->ns_data.dd_operation;
 356         reply.state = session->ns_data.dd_state;
 357         reply.halt_reason = session->ns_data.dd_halt_reason;
 358 
 359         if (reply.operation == NDMP_DATA_OP_BACKUP)
 360                 reply.bytes_processed =
 361                     long_long_to_quad(
 362                     session->ns_data.dd_module.dm_stats.ms_bytes_processed);
 363         else
 364                 reply.bytes_processed =
 365                     long_long_to_quad(ndmpd_data_get_info(session));
 366 
 367         reply.est_bytes_remain = long_long_to_quad(0LL);
 368         reply.est_time_remain = 0;
 369         if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE)
 370                 ndmp_copy_addr_v3(&reply.data_connection_addr,
 371                     &session->ns_data.dd_data_addr);
 372         reply.read_offset = long_long_to_quad(session->ns_data.dd_read_offset);
 373         reply.read_length = long_long_to_quad(session->ns_data.dd_read_length);
 374 
 375         ndmp_send_reply(connection, &reply,
 376             "sending ndmp_data_get_state_v3 reply");
 377 }
 378 
 379 
 380 /*
 381  * ndmpd_data_start_backup_v3
 382  *
 383  * Request handler. Starts a backup.
 384  *
 385  * Parameters:
 386  *   connection (input) - connection handle.
 387  *   body       (input) - request message body.
 388  *
 389  * Returns:
 390  *   void
 391  */
 392 void
 393 ndmpd_data_start_backup_v3(ndmp_connection_t *connection, void *body)
 394 {
 395         ndmp_data_start_backup_request_v3 *request;
 396         ndmp_data_start_backup_reply_v3 reply;
 397         ndmpd_session_t *session = ndmp_get_client_data(connection);
 398 
 399         request = (ndmp_data_start_backup_request_v3 *)body;
 400 
 401         (void) memset((void*)&reply, 0, sizeof (reply));
 402 
 403         if (session->ns_data.dd_state != NDMP_DATA_STATE_CONNECTED) {
 404                 NDMP_LOG(LOG_ERR,
 405                     "Can't start new backup in current state.");
 406                 NDMP_LOG(LOG_ERR,
 407                     "Connection to the mover is not established.");
 408                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 409                 goto _error;
 410         }
 411 
 412         if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_LOCAL) {
 413                 if (session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
 414                         NDMP_LOG(LOG_ERR, "Write protected device.");
 415                         reply.error = NDMP_WRITE_PROTECT_ERR;
 416                         goto _error;
 417                 }
 418         }
 419 
 420         if (strcasecmp(request->bu_type, NDMP_TAR_TYPE) == 0) {
 421                 session->ns_butype = NDMP_BUTYPE_TAR;
 422         } else if (strcasecmp(request->bu_type, NDMP_DUMP_TYPE) == 0) {
 423                 session->ns_butype = NDMP_BUTYPE_DUMP;
 424         } else if (strcasecmp(request->bu_type, NDMP_ZFS_TYPE) == 0) {
 425                 session->ns_butype = NDMP_BUTYPE_ZFS;
 426         } else {
 427                 char msg_invalid[32];
 428                 char msg_types[32];
 429 
 430                 (void) snprintf(msg_invalid, 32, "Invalid backup type: %s.",
 431                     request->bu_type);
 432                 (void) snprintf(msg_types, 32,
 433                     "Supported backup types are tar, dump, and zfs.");
 434 
 435                 NDMP_APILOG((void *) session, NDMP_LOG_ERROR, ++ndmp_log_msg_id,
 436                     msg_invalid);
 437                 NDMP_APILOG((void *) session, NDMP_LOG_ERROR, ++ndmp_log_msg_id,
 438                     msg_types);
 439                 NDMP_LOG(LOG_ERR, msg_invalid);
 440                 NDMP_LOG(LOG_ERR, msg_types);
 441 
 442                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 443                 goto _error;
 444         }
 445 
 446         if (session->ns_butype == NDMP_BUTYPE_ZFS) {
 447                 reply.error = ndmpd_zfs_start_op(session, request->env.env_val,
 448                     request->env.env_len, NULL, 0, NDMP_DATA_OP_BACKUP);
 449         } else {
 450                 reply.error = ndmpd_tar_start_backup_v3(session,
 451                     request->bu_type, request->env.env_val,
 452                     request->env.env_len);
 453         }
 454 
 455         /*
 456          * *_start_backup* sends the reply if the backup is
 457          * successfully started.  Otherwise, send the reply
 458          * containing the error here.
 459          */
 460 
 461 _error:
 462 
 463         if (reply.error != NDMP_NO_ERR) {
 464                 ndmp_send_reply(connection, &reply,
 465                     "sending data_start_backup_v3 reply");
 466                 ndmpd_data_cleanup(session);
 467         }
 468 }
 469 
 470 /*
 471  * ndmpd_data_start_recover_v3
 472  *
 473  * Request handler. Starts a restore.
 474  *
 475  * Parameters:
 476  *   connection (input) - connection handle.
 477  *   body       (input) - request message body.
 478  *
 479  * Returns:
 480  *   void
 481  */
 482 void
 483 ndmpd_data_start_recover_v3(ndmp_connection_t *connection, void *body)
 484 {
 485         ndmp_data_start_recover_request_v3 *request;
 486         ndmp_data_start_recover_reply_v3 reply;
 487         ndmpd_session_t *session = ndmp_get_client_data(connection);
 488 
 489         request = (ndmp_data_start_recover_request_v3 *)body;
 490 
 491         (void) memset((void*)&reply, 0, sizeof (reply));
 492 
 493         if (session->ns_data.dd_state != NDMP_DATA_STATE_CONNECTED) {
 494                 NDMP_LOG(LOG_ERR, "Can't start new recover in current state.");
 495                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 496                 goto _error;
 497         }
 498 
 499         if (strcasecmp(request->bu_type, NDMP_TAR_TYPE) == 0) {
 500                 session->ns_butype = NDMP_BUTYPE_TAR;
 501         } else if (strcasecmp(request->bu_type, NDMP_DUMP_TYPE) == 0) {
 502                 session->ns_butype = NDMP_BUTYPE_DUMP;
 503         } else if (strcasecmp(request->bu_type, NDMP_ZFS_TYPE) == 0) {
 504                 session->ns_butype = NDMP_BUTYPE_ZFS;
 505         } else {
 506                 char msg_invalid[32];
 507                 char msg_types[32];
 508 
 509                 (void) snprintf(msg_invalid, 32, "Invalid backup type: %s.",
 510                     request->bu_type);
 511                 (void) snprintf(msg_types, 32,
 512                     "Supported backup types are tar, dump, and zfs.");
 513 
 514                 NDMP_APILOG((void *) session, NDMP_LOG_ERROR, ++ndmp_log_msg_id,
 515                     msg_invalid);
 516                 NDMP_APILOG((void *) session, NDMP_LOG_ERROR, ++ndmp_log_msg_id,
 517                     msg_types);
 518                 NDMP_LOG(LOG_ERR, msg_invalid);
 519                 NDMP_LOG(LOG_ERR, msg_types);
 520 
 521                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 522                 goto _error;
 523         }
 524 
 525         if (session->ns_butype == NDMP_BUTYPE_ZFS) {
 526                 reply.error = ndmpd_zfs_start_op(session, request->env.env_val,
 527                     request->env.env_len, request->nlist.nlist_val,
 528                     request->nlist.nlist_len, NDMP_DATA_OP_RECOVER);
 529         } else {
 530                 reply.error = ndmpd_tar_start_recover_v3(session,
 531                     request->env.env_val, request->env.env_len,
 532                     request->nlist.nlist_val, request->nlist.nlist_len);
 533         }
 534 
 535         /*
 536          * *_start_recover* sends the reply if the recover is
 537          * successfully started.  Otherwise, send the reply
 538          * containing the error here.
 539          */
 540 
 541 _error:
 542 
 543         if (reply.error != NDMP_NO_ERR) {
 544                 ndmp_send_reply(connection, &reply,
 545                     "sending data_start_recover_v3 reply");
 546                 ndmpd_data_error(session, NDMP_DATA_HALT_INTERNAL_ERROR);
 547                 ndmpd_data_cleanup(session);
 548         }
 549 }
 550 
 551 /*
 552  * ndmpd_data_abort_v3
 553  *
 554  * Request handler. Aborts the current backup/restore. The operation
 555  * state is not changed to the halted state until after the operation
 556  * has actually been aborted and the notify_halt request has been sent.
 557  *
 558  * Parameters:
 559  *   connection (input) - connection handle.
 560  *   body       (input) - request message body.
 561  *
 562  * Returns:
 563  *   void
 564  */
 565 /*ARGSUSED*/
 566 void
 567 ndmpd_data_abort_v3(ndmp_connection_t *connection, void *body)
 568 {
 569         ndmp_data_abort_reply reply;
 570         ndmpd_session_t *session = ndmp_get_client_data(connection);
 571 
 572         switch (session->ns_data.dd_state) {
 573         case NDMP_DATA_STATE_IDLE:
 574                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 575                 NDMP_LOG(LOG_ERR, "Invalid state to process abort request.");
 576                 break;
 577 
 578         case NDMP_DATA_STATE_ACTIVE:
 579                 /*
 580                  * Don't go to HALTED state yet.  Need to wait for data
 581                  * operation to abort.  When this happens, ndmpd_done_v3
 582                  * will get called and will perform the halt processing.
 583                  */
 584                 reply.error = NDMP_NO_ERR;
 585                 session->ns_data.dd_abort = TRUE;
 586                 if (session->ns_data.dd_module.dm_abort_func)
 587                         (*session->ns_data.dd_module.dm_abort_func)(
 588                             session->ns_data.dd_module.dm_module_cookie);
 589                 break;
 590 
 591         case NDMP_DATA_STATE_HALTED:
 592         case NDMP_DATA_STATE_LISTEN:
 593         case NDMP_DATA_STATE_CONNECTED:
 594                 reply.error = NDMP_NO_ERR;
 595                 session->ns_data.dd_abort = TRUE;
 596                 ndmpd_data_error(session, NDMP_DATA_HALT_ABORTED);
 597                 break;
 598         default:
 599                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 600                 NDMP_LOG(LOG_DEBUG, "Unknown data V3 state %d",
 601                     session->ns_data.dd_state);
 602         }
 603 
 604         ndmp_send_reply(connection, &reply,
 605             "sending data_abort_v3 reply");
 606 }
 607 
 608 
 609 /*
 610  * ndmpd_data_stop_v3
 611  *
 612  * Request handler. Stops the current data operation.
 613  *
 614  * Parameters:
 615  *   connection (input) - connection handle.
 616  *   body       (input) - request message body.
 617  *
 618  * Returns:
 619  *   void
 620  */
 621 /*ARGSUSED*/
 622 void
 623 ndmpd_data_stop_v3(ndmp_connection_t *connection, void *body)
 624 {
 625         ndmp_data_stop_reply reply;
 626         ndmpd_session_t *session = ndmp_get_client_data(connection);
 627 
 628         if (session->ns_data.dd_state != NDMP_DATA_STATE_HALTED) {
 629                 NDMP_LOG(LOG_ERR, "Invalid state to process stop request.");
 630                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 631                 ndmp_send_reply(connection, &reply,
 632                     "sending data_stop_v3 reply");
 633                 return;
 634         }
 635         ndmp_waitfor_op(session);
 636         ndmpd_data_cleanup(session);
 637         ndmpd_file_history_cleanup(session, FALSE);
 638 
 639         /* prepare for another data operation */
 640         (void) ndmpd_data_init(session);
 641         ndmpd_file_history_init(session);
 642 
 643         reply.error = NDMP_NO_ERR;
 644         ndmp_send_reply(connection, &reply,
 645             "sending data_stop_v3 reply");
 646 }
 647 
 648 
 649 /*
 650  * ndmpd_data_listen_v3
 651  *
 652  * Request handler. Configures the server to listen for a connection
 653  * from a remote mover.
 654  *
 655  * Parameters:
 656  *   connection (input) - connection handle.
 657  *   body       (input) - request message body.
 658  *
 659  * Returns:
 660  *   void
 661  */
 662 void
 663 ndmpd_data_listen_v3(ndmp_connection_t *connection, void *body)
 664 {
 665         ndmp_data_listen_request_v3 *request;
 666         ndmp_data_listen_reply_v3 reply;
 667         ndmpd_session_t *session = ndmp_get_client_data(connection);
 668         ulong_t addr;
 669         ushort_t port;
 670 
 671         request = (ndmp_data_listen_request_v3 *)body;
 672 
 673         (void) memset((void*)&reply, 0, sizeof (reply));
 674 
 675         if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
 676                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 677                 NDMP_LOG(LOG_ERR,
 678                     "Invalid internal data state to process listen request.");
 679         } else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
 680                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 681                 NDMP_LOG(LOG_ERR,
 682                     "Invalid mover state to process listen request.");
 683         } else {
 684                 reply.error = NDMP_NO_ERR;
 685         }
 686 
 687         if (reply.error != NDMP_NO_ERR) {
 688                 ndmp_send_reply(connection, &reply,
 689                     "ndmp_data_listen_request_v3 reply");
 690                 return;
 691         }
 692 
 693         switch (request->addr_type) {
 694         case NDMP_ADDR_LOCAL:
 695                 reply.data_connection_addr.addr_type = request->addr_type;
 696                 session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_LOCAL;
 697                 break;
 698         case NDMP_ADDR_TCP:
 699                 if (create_listen_socket_v3(session, &addr, &port) < 0) {
 700                         reply.error = NDMP_IO_ERR;
 701                         break;
 702                 }
 703 
 704                 reply.error = NDMP_NO_ERR;
 705                 reply.data_connection_addr.addr_type = request->addr_type;
 706                 reply.data_connection_addr.tcp_ip_v3 = htonl(addr);
 707                 reply.data_connection_addr.tcp_port_v3 = htons(port);
 708                 session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_TCP;
 709                 session->ns_data.dd_data_addr.tcp_ip_v3 = addr;
 710                 session->ns_data.dd_data_addr.tcp_port_v3 = ntohs(port);
 711                 NDMP_LOG(LOG_DEBUG, "listen_socket: %d",
 712                     session->ns_data.dd_listen_sock);
 713                 break;
 714 
 715         default:
 716                 NDMP_LOG(LOG_DEBUG, "Invalid address type: %d",
 717                     request->addr_type);
 718                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 719                 break;
 720         }
 721 
 722         if (reply.error == NDMP_NO_ERR)
 723                 session->ns_data.dd_state = NDMP_DATA_STATE_LISTEN;
 724 
 725         ndmp_send_reply(connection, &reply,
 726             "ndmp_data_listen_request_v3 reply");
 727 }
 728 
 729 
 730 /*
 731  * ndmpd_data_connect_v3
 732  *
 733  * Request handler. Connects the data server to either a local
 734  * or remote mover.
 735  *
 736  * Parameters:
 737  *   connection (input) - connection handle.
 738  *   body       (input) - request message body.
 739  *
 740  * Returns:
 741  *   void
 742  */
 743 void
 744 ndmpd_data_connect_v3(ndmp_connection_t *connection, void *body)
 745 {
 746         ndmp_data_connect_request_v3 *request;
 747         ndmp_data_connect_reply_v3 reply;
 748         ndmpd_session_t *session = ndmp_get_client_data(connection);
 749 
 750         request = (ndmp_data_connect_request_v3 *)body;
 751 
 752         (void) memset((void*)&reply, 0, sizeof (reply));
 753 
 754         if (!ndmp_valid_v3addr_type(request->addr.addr_type)) {
 755                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 756                 NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
 757                     request->addr.addr_type);
 758         } else if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
 759                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 760                 NDMP_LOG(LOG_ERR, "Invalid state to process connect request.");
 761         } else {
 762                 reply.error = NDMP_NO_ERR;
 763         }
 764 
 765         if (reply.error != NDMP_NO_ERR) {
 766                 ndmp_send_reply(connection, &reply,
 767                     "sending ndmp_data_connect_v3 reply");
 768                 return;
 769         }
 770 
 771         switch (request->addr.addr_type) {
 772         case NDMP_ADDR_LOCAL:
 773                 /*
 774                  * Verify that the mover is listening for a
 775                  * local connection
 776                  */
 777                 if (session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN ||
 778                     session->ns_mover.md_listen_sock != -1) {
 779                         reply.error = NDMP_ILLEGAL_STATE_ERR;
 780                         NDMP_LOG(LOG_ERR,
 781                             "Mover is not in local listen state.");
 782                 } else {
 783                         session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
 784                 }
 785                 break;
 786 
 787         case NDMP_ADDR_TCP:
 788                 reply.error = data_connect_sock_v3(session,
 789                     request->addr.tcp_ip_v3, request->addr.tcp_port_v3);
 790                 break;
 791 
 792         default:
 793                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 794                 NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
 795                     request->addr.addr_type);
 796         }
 797 
 798         if (reply.error == NDMP_NO_ERR)
 799                 session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
 800 
 801         ndmp_send_reply(connection, &reply,
 802             "sending ndmp_data_connect_v3 reply");
 803 }
 804 
 805 
 806 /*
 807  * ************************************************************************
 808  * NDMP V4 HANDLERS
 809  * ************************************************************************
 810  */
 811 
 812 /*
 813  * ndmpd_data_get_env_v4
 814  *
 815  * Request handler. Returns the environment variable array sent
 816  * with the backup request. This request may only be sent with
 817  * a backup operation is in progress.
 818  *
 819  * Parameters:
 820  *   connection (input) - connection handle.
 821  *   body       (input) - request message body.
 822  *
 823  * Returns:
 824  *   void
 825  */
 826 /*ARGSUSED*/
 827 void
 828 ndmpd_data_get_env_v4(ndmp_connection_t *connection, void *body)
 829 {
 830         ndmp_data_get_env_reply reply;
 831         ndmpd_session_t *session = ndmp_get_client_data(connection);
 832 
 833         (void) memset((void*)&reply, 0, sizeof (reply));
 834 
 835         if (session->ns_data.dd_state != NDMP_DATA_STATE_ACTIVE &&
 836             session->ns_data.dd_state != NDMP_DATA_STATE_HALTED) {
 837                 NDMP_LOG(LOG_ERR, "Invalid state for the data server.");
 838                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 839                 reply.env.env_len = 0;
 840         } else if (session->ns_data.dd_operation != NDMP_DATA_OP_BACKUP) {
 841                 NDMP_LOG(LOG_ERR, "Backup operation not active.");
 842                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 843                 reply.env.env_len = 0;
 844         } else {
 845                 reply.error = NDMP_NO_ERR;
 846                 reply.env.env_len = session->ns_data.dd_env_len;
 847                 reply.env.env_val = session->ns_data.dd_env;
 848         }
 849 
 850         ndmp_send_reply(connection, &reply, "sending data_get_env reply");
 851 }
 852 
 853 /*
 854  * ndmpd_data_get_state_v4
 855  *
 856  * Request handler. Returns current data state.
 857  *
 858  * Parameters:
 859  *   connection (input) - connection handle.
 860  *   body       (input) - request message body.
 861  *
 862  * Returns:
 863  *   void
 864  */
 865 /*ARGSUSED*/
 866 void
 867 ndmpd_data_get_state_v4(ndmp_connection_t *connection, void *body)
 868 {
 869         ndmp_data_get_state_reply_v4 reply;
 870         ndmpd_session_t *session = ndmp_get_client_data(connection);
 871 
 872         (void) memset((void*)&reply, 0, sizeof (reply));
 873 
 874         reply.error = NDMP_NO_ERR;
 875         reply.unsupported = NDMP_DATA_STATE_EST_BYTES_REMAIN_INVALID
 876             | NDMP_DATA_STATE_EST_TIME_REMAIN_INVALID;
 877         reply.operation = session->ns_data.dd_operation;
 878         reply.state = session->ns_data.dd_state;
 879         reply.halt_reason = session->ns_data.dd_halt_reason;
 880 
 881         if (reply.operation == NDMP_DATA_OP_BACKUP)
 882                 reply.bytes_processed = long_long_to_quad(
 883                     session->ns_data.dd_module.dm_stats.ms_bytes_processed);
 884         else
 885                 reply.bytes_processed =
 886                     long_long_to_quad(ndmpd_data_get_info(session));
 887 
 888         reply.est_bytes_remain = long_long_to_quad(0LL);
 889         reply.est_time_remain = 0;
 890         if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE)
 891                 ndmp_copy_addr_v4(&reply.data_connection_addr,
 892                     &session->ns_data.dd_data_addr_v4);
 893 
 894         reply.read_offset = long_long_to_quad(session->ns_data.dd_read_offset);
 895         reply.read_length = long_long_to_quad(session->ns_data.dd_read_length);
 896 
 897         ndmp_send_reply(connection, &reply,
 898             "sending ndmp_data_get_state_v4 reply");
 899         free(reply.data_connection_addr.tcp_addr_v4);
 900 }
 901 
 902 
 903 /*
 904  * ndmpd_data_connect_v4
 905  *
 906  * Request handler. Connects the data server to either a local
 907  * or remote mover.
 908  *
 909  * Parameters:
 910  *   connection (input) - connection handle.
 911  *   body       (input) - request message body.
 912  *
 913  * Returns:
 914  *   void
 915  */
 916 void
 917 ndmpd_data_connect_v4(ndmp_connection_t *connection, void *body)
 918 {
 919         ndmp_data_connect_request_v4 *request;
 920         ndmp_data_connect_reply_v4 reply;
 921         ndmpd_session_t *session = ndmp_get_client_data(connection);
 922 
 923         request = (ndmp_data_connect_request_v4 *)body;
 924 
 925         (void) memset((void*)&reply, 0, sizeof (reply));
 926 
 927         if (!ndmp_valid_v3addr_type(request->addr.addr_type)) {
 928                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 929                 NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
 930                     request->addr.addr_type);
 931         } else if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
 932                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 933                 NDMP_LOG(LOG_ERR, "Invalid state to process connect request.");
 934         } else {
 935                 reply.error = NDMP_NO_ERR;
 936         }
 937 
 938         if (reply.error != NDMP_NO_ERR) {
 939                 ndmp_send_reply(connection, &reply,
 940                     "sending ndmp_data_connect_v4 reply");
 941                 return;
 942         }
 943 
 944         switch (request->addr.addr_type) {
 945         case NDMP_ADDR_LOCAL:
 946                 /*
 947                  * Verify that the mover is listening for a
 948                  * local connection
 949                  */
 950                 if (session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN ||
 951                     session->ns_mover.md_listen_sock != -1) {
 952                         reply.error = NDMP_ILLEGAL_STATE_ERR;
 953                         NDMP_LOG(LOG_ERR,
 954                             "Mover is not in local listen state.");
 955                 } else {
 956                         session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
 957                 }
 958                 break;
 959 
 960         case NDMP_ADDR_TCP:
 961                 reply.error = data_connect_sock_v3(session,
 962                     request->addr.tcp_ip_v4(0), request->addr.tcp_port_v4(0));
 963                 break;
 964 
 965         default:
 966                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 967                 NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
 968                     request->addr.addr_type);
 969         }
 970 
 971         if (reply.error == NDMP_NO_ERR)
 972                 session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
 973 
 974         ndmp_send_reply(connection, &reply,
 975             "sending ndmp_data_connect_v4 reply");
 976 }
 977 
 978 /*
 979  * ndmpd_data_listen_v4
 980  *
 981  * Request handler. Configures the server to listen for a connection
 982  * from a remote mover.
 983  *
 984  * Parameters:
 985  *   connection (input) - connection handle.
 986  *   body       (input) - request message body.
 987  *
 988  * Returns:
 989  *   void
 990  */
 991 void
 992 ndmpd_data_listen_v4(ndmp_connection_t *connection, void *body)
 993 {
 994         ndmp_data_listen_request_v4 *request;
 995         ndmp_data_listen_reply_v4 reply;
 996         ndmpd_session_t *session = ndmp_get_client_data(connection);
 997         ulong_t addr;
 998         ushort_t port;
 999 
1000         request = (ndmp_data_listen_request_v4 *)body;
1001 
1002         (void) memset((void*)&reply, 0, sizeof (reply));
1003 
1004         if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
1005                 reply.error = NDMP_ILLEGAL_STATE_ERR;
1006                 NDMP_LOG(LOG_ERR,
1007                     "Invalid internal data state to process listen request.");
1008         } else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
1009                 reply.error = NDMP_ILLEGAL_STATE_ERR;
1010                 NDMP_LOG(LOG_ERR,
1011                     "Invalid mover state to process listen request.");
1012         } else {
1013                 reply.error = NDMP_NO_ERR;
1014         }
1015 
1016         if (reply.error != NDMP_NO_ERR) {
1017                 ndmp_send_reply(connection, &reply,
1018                     "ndmp_data_listen_request_v4 reply");
1019                 return;
1020         }
1021 
1022         switch (request->addr_type) {
1023         case NDMP_ADDR_LOCAL:
1024                 reply.connect_addr.addr_type = request->addr_type;
1025                 session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_LOCAL;
1026                 break;
1027         case NDMP_ADDR_TCP:
1028                 if (create_listen_socket_v3(session, &addr, &port) < 0) {
1029                         reply.error = NDMP_IO_ERR;
1030                         break;
1031                 }
1032 
1033                 reply.error = NDMP_NO_ERR;
1034                 reply.connect_addr.addr_type = request->addr_type;
1035                 reply.connect_addr.tcp_addr_v4 =
1036                     ndmp_malloc(sizeof (ndmp_tcp_addr_v4));
1037 
1038                 reply.connect_addr.tcp_ip_v4(0) = htonl(addr);
1039                 reply.connect_addr.tcp_port_v4(0) = htons(port);
1040                 reply.connect_addr.tcp_len_v4 = 1;
1041 
1042                 session->ns_data.dd_data_addr_v4.addr_type = NDMP_ADDR_TCP;
1043                 session->ns_data.dd_data_addr_v4.tcp_addr_v4 =
1044                     ndmp_malloc(sizeof (ndmp_tcp_addr_v4));
1045 
1046                 session->ns_data.dd_data_addr_v4.tcp_ip_v4(0) = addr;
1047                 session->ns_data.dd_data_addr_v4.tcp_port_v4(0) = ntohs(port);
1048                 session->ns_data.dd_data_addr_v4.tcp_len_v4 = 1;
1049 
1050                 /* Copy that to data_addr for compatibility */
1051                 session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_TCP;
1052                 session->ns_data.dd_data_addr.tcp_ip_v3 = addr;
1053                 session->ns_data.dd_data_addr.tcp_port_v3 = ntohs(port);
1054                 NDMP_LOG(LOG_DEBUG, "listen_socket: %d",
1055                     session->ns_data.dd_listen_sock);
1056                 break;
1057 
1058         default:
1059                 NDMP_LOG(LOG_DEBUG, "Invalid address type: %d",
1060                     request->addr_type);
1061                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
1062                 break;
1063         }
1064 
1065         if (reply.error == NDMP_NO_ERR)
1066                 session->ns_data.dd_state = NDMP_DATA_STATE_LISTEN;
1067 
1068         ndmp_send_reply(connection, &reply,
1069             "ndmp_data_listen_request_v4 reply");
1070 }
1071 
1072 
1073 /*
1074  * ndmpd_data_start_recover_filehist_v4
1075  *
1076  * Request handler. Recovers the file history (not supported yet)
1077  * This command has an optional support in V4.
1078  *
1079  * Parameters:
1080  *   connection (input) - connection handle.
1081  *   body       (input) - request message body.
1082  *
1083  * Returns:
1084  *   void
1085  */
1086 /*ARGSUSED*/
1087 void
1088 ndmpd_data_start_recover_filehist_v4(ndmp_connection_t *connection, void *body)
1089 {
1090         ndmp_data_start_recover_filehist_reply_v4 reply;
1091 
1092         NDMP_LOG(LOG_DEBUG, "Request not supported");
1093         reply.error = NDMP_NOT_SUPPORTED_ERR;
1094 
1095         ndmp_send_reply(connection, &reply,
1096             "sending ndmp_data_start_recover_filehist_reply_v4 reply");
1097 }
1098 
1099 /*
1100  * ************************************************************************
1101  * LOCALS
1102  * ************************************************************************
1103  */
1104 
1105 /*
1106  * ndmpd_data_error_send
1107  *
1108  * This function sends the notify message to the client.
1109  *
1110  * Parameters:
1111  *   session (input) - session pointer.
1112  *   reason  (input) - halt reason.
1113  *
1114  * Returns:
1115  *   Error code
1116  */
1117 /*ARGSUSED*/
1118 static int
1119 ndmpd_data_error_send(ndmpd_session_t *session, ndmp_data_halt_reason reason)
1120 {
1121         ndmp_notify_data_halted_request req;
1122 
1123         req.reason = session->ns_data.dd_halt_reason;
1124         req.text_reason = "";
1125 
1126         return (ndmp_send_request(session->ns_connection,
1127             NDMP_NOTIFY_DATA_HALTED, NDMP_NO_ERR, &req, 0));
1128 }
1129 
1130 
1131 /*
1132  * ndmpd_data_error_send_v4
1133  *
1134  * This function sends the notify message to the client.
1135  *
1136  * Parameters:
1137  *   session (input) - session pointer.
1138  *   reason  (input) - halt reason.
1139  *
1140  * Returns:
1141  *   Error code
1142  */
1143 /*ARGSUSED*/
1144 static int
1145 ndmpd_data_error_send_v4(ndmpd_session_t *session, ndmp_data_halt_reason reason)
1146 {
1147         ndmp_notify_data_halted_request_v4 req;
1148 
1149         req.reason = session->ns_data.dd_halt_reason;
1150 
1151         return ndmp_send_request(session->ns_connection,
1152             NDMP_NOTIFY_DATA_HALTED, NDMP_NO_ERR, &req, 0);
1153 }
1154 
1155 
1156 /*
1157  * ndmpd_data_error
1158  *
1159  * This function is called when a data error has been detected.
1160  * A notify message is sent to the client and the data server is
1161  * placed into the halted state.
1162  *
1163  * Parameters:
1164  *   session (input) - session pointer.
1165  *   reason  (input) - halt reason.
1166  *
1167  * Returns:
1168  *   void
1169  */
1170 void
1171 ndmpd_data_error(ndmpd_session_t *session, ndmp_data_halt_reason reason)
1172 {
1173         if (session->ns_data.dd_state == NDMP_DATA_STATE_IDLE ||
1174             session->ns_data.dd_state == NDMP_DATA_STATE_HALTED)
1175                 return;
1176 
1177         if (session->ns_data.dd_operation == NDMP_DATA_OP_BACKUP) {
1178                 /*
1179                  * Send/discard any buffered file history data.
1180                  */
1181                 ndmpd_file_history_cleanup(session,
1182                     (reason == NDMP_DATA_HALT_SUCCESSFUL ? TRUE : FALSE));
1183 
1184                 /*
1185                  * If mover local and successful backup, write any
1186                  * remaining buffered data to tape.
1187                  */
1188                 if (session->ns_data.dd_data_addr.addr_type
1189                     == NDMP_ADDR_LOCAL && reason == NDMP_DATA_HALT_SUCCESSFUL)
1190                         (void) ndmpd_local_write_v3(session, 0, 0);
1191         }
1192 
1193         session->ns_data.dd_state = NDMP_DATA_STATE_HALTED;
1194         session->ns_data.dd_halt_reason = reason;
1195 
1196         if (session->ns_protocol_version == NDMPV4) {
1197                 if (ndmpd_data_error_send_v4(session, reason) < 0)
1198                         NDMP_LOG(LOG_DEBUG,
1199                             "Error sending notify_data_halted request");
1200         } else {
1201                 if (ndmpd_data_error_send(session, reason) < 0)
1202                         NDMP_LOG(LOG_DEBUG,
1203                             "Error sending notify_data_halted request");
1204         }
1205 
1206         if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_TCP) {
1207                 if (session->ns_data.dd_sock != -1) {
1208                         (void) ndmpd_remove_file_handler(session,
1209                             session->ns_data.dd_sock);
1210                         /*
1211                          * ndmpcopy: we use the same socket for the mover,
1212                          * so expect to close when mover is done!
1213                          */
1214                         if (session->ns_data.dd_sock !=
1215                             session->ns_mover.md_sock)
1216                                 (void) close(session->ns_data.dd_sock);
1217 
1218                         session->ns_data.dd_sock = -1;
1219                 }
1220                 if (session->ns_data.dd_listen_sock != -1) {
1221                         (void) ndmpd_remove_file_handler(session,
1222                             session->ns_data.dd_listen_sock);
1223 
1224                         (void) close(session->ns_data.dd_listen_sock);
1225                         session->ns_data.dd_listen_sock = -1;
1226                 }
1227         } else {
1228                 ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
1229         }
1230 }
1231 
1232 
1233 /*
1234  * data_accept_connection_v3
1235  *
1236  * Accept a data connection from a remote mover.
1237  * Called by ndmpd_select when a connection is pending on
1238  * the data listen socket.
1239  *
1240  * Parameters:
1241  *   cookie  (input) - session pointer.
1242  *   fd      (input) - file descriptor.
1243  *   mode    (input) - select mode.
1244  *
1245  * Returns:
1246  *   void
1247  */
1248 /*ARGSUSED*/
1249 static void
1250 data_accept_connection_v3(void *cookie, int fd, ulong_t mode)
1251 {
1252         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
1253         int from_len;
1254         struct sockaddr_in from;
1255 
1256         from_len = sizeof (from);
1257         session->ns_data.dd_sock = accept(fd, (struct sockaddr *)&from,
1258             &from_len);
1259 
1260         NDMP_LOG(LOG_DEBUG, "sock fd: %d",
1261             session->ns_data.dd_sock);
1262         NDMP_LOG(LOG_DEBUG, "sin: port %d addr %s",
1263             ntohs(from.sin_port),
1264             inet_ntoa(IN_ADDR(from.sin_addr.s_addr)));
1265 
1266         (void) ndmpd_remove_file_handler(session, fd);
1267         (void) close(session->ns_data.dd_listen_sock);
1268         session->ns_data.dd_listen_sock = -1;
1269 
1270         if (session->ns_data.dd_sock < 0) {
1271                 NDMP_LOG(LOG_DEBUG, "Accept error: %m");
1272                 ndmpd_data_error(session, NDMP_DATA_HALT_CONNECT_ERROR);
1273                 return;
1274         }
1275 
1276         /*
1277          * Save the peer address.
1278          */
1279         session->ns_data.dd_data_addr.tcp_ip_v3 = from.sin_addr.s_addr;
1280         session->ns_data.dd_data_addr.tcp_port_v3 = ntohs(from.sin_port);
1281 
1282         /* Set the parameter of the new socket */
1283         set_socket_options(session->ns_data.dd_sock);
1284 
1285         session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
1286 }
1287 
1288 
1289 /*
1290  * create_listen_socket_v3
1291  *
1292  * Creates the data sockets for listening for a remote mover/data
1293  * incoming connections.
1294  */
1295 static int
1296 create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr, ushort_t *port)
1297 {
1298         session->ns_data.dd_listen_sock = ndmp_create_socket(addr, port);
1299         if (session->ns_data.dd_listen_sock < 0)
1300                 return (-1);
1301 
1302         /*
1303          * Add a file handler for the listen socket.
1304          * ndmpd_select will call data_accept_connection when a
1305          * connection is ready to be accepted.
1306          */
1307         if (ndmpd_add_file_handler(session, (void*)session,
1308             session->ns_data.dd_listen_sock, NDMPD_SELECT_MODE_READ, HC_MOVER,
1309             data_accept_connection_v3) < 0) {
1310                 (void) close(session->ns_data.dd_listen_sock);
1311                 session->ns_data.dd_listen_sock = -1;
1312                 return (-1);
1313         }
1314         NDMP_LOG(LOG_DEBUG, "addr: %s:%d",
1315             inet_ntoa(IN_ADDR(*addr)), ntohs(*port));
1316 
1317         return (0);
1318 }
1319 
1320 
1321 /*
1322  * data_connect_sock_v3
1323  *
1324  * Connect the data interface socket to the specified ip/port
1325  *
1326  * Parameters:
1327  *   session (input) - session pointer.
1328  *   addr    (input) - IP address
1329  *   port    (input) - port number
1330  *
1331  * Returns:
1332  *   NDMP_NO_ERR - backup successfully started.
1333  *   otherwise - error code of backup start error.
1334  */
1335 static ndmp_error
1336 data_connect_sock_v3(ndmpd_session_t *session, ulong_t addr, ushort_t port)
1337 {
1338         int sock;
1339 
1340         sock = ndmp_connect_sock_v3(addr, port);
1341         if (sock < 0)
1342                 return (NDMP_CONNECT_ERR);
1343 
1344         session->ns_data.dd_sock = sock;
1345         session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_TCP;
1346         session->ns_data.dd_data_addr.tcp_ip_v3 = ntohl(addr);
1347         session->ns_data.dd_data_addr.tcp_port_v3 = port;
1348 
1349         return (NDMP_NO_ERR);
1350 }
1351 
1352 
1353 /*
1354  * ndmpd_tar_start_backup_v3
1355  *
1356  * Start the backup work
1357  *
1358  * Parameters:
1359  *   session   (input) - session pointer.
1360  *   bu_type   (input) - backup type.
1361  *   env_val   (input) - environment variable array.
1362  *   env_len   (input) - length of env_val.
1363  *
1364  * Returns:
1365  *   NDMP_NO_ERR - backup successfully started.
1366  *   otherwise - error code of backup start error.
1367  */
1368 static ndmp_error
1369 ndmpd_tar_start_backup_v3(ndmpd_session_t *session, char *bu_type,
1370     ndmp_pval *env_val, ulong_t env_len)
1371 {
1372         int err;
1373         ndmp_lbr_params_t *nlp;
1374         ndmpd_module_params_t *params;
1375         ndmp_data_start_backup_reply_v3 reply;
1376 
1377         (void) memset((void*)&reply, 0, sizeof (reply));
1378 
1379         err = ndmpd_save_env(session, env_val, env_len);
1380         if (err != NDMP_NO_ERR)
1381                 return (err);
1382 
1383         nlp = ndmp_get_nlp(session);
1384         NDMP_FREE(nlp->nlp_params);
1385         params = nlp->nlp_params = ndmp_malloc(sizeof (ndmpd_module_params_t));
1386         if (!params)
1387                 return (NDMP_NO_MEM_ERR);
1388 
1389         params->mp_daemon_cookie = (void *)session;
1390         params->mp_module_cookie = &session->ns_data.dd_module.dm_module_cookie;
1391         params->mp_protocol_version = session->ns_protocol_version;
1392         params->mp_operation = NDMP_DATA_OP_BACKUP;
1393         params->mp_get_env_func = ndmpd_api_get_env;
1394         params->mp_add_env_func = ndmpd_api_add_env;
1395         params->mp_set_env_func = ndmpd_api_set_env;
1396         params->mp_get_name_func = 0;
1397         params->mp_dispatch_func = ndmpd_api_dispatch;
1398         params->mp_done_func = ndmpd_api_done_v3;
1399         if (session->ns_protocol_version == NDMPV4)
1400                 params->mp_log_func_v3 = ndmpd_api_log_v4;
1401         else
1402                 params->mp_log_func_v3 = ndmpd_api_log_v3;
1403 
1404         params->mp_add_file_handler_func = ndmpd_api_add_file_handler;
1405         params->mp_remove_file_handler_func = ndmpd_api_remove_file_handler;
1406         params->mp_write_func = ndmpd_api_write_v3;
1407         params->mp_read_func = 0;
1408         params->mp_file_recovered_func = 0;
1409         params->mp_stats = &session->ns_data.dd_module.dm_stats;
1410         session->ns_data.dd_module.dm_module_cookie = 0;
1411 
1412         if (strcmp(bu_type, NDMP_DUMP_TYPE) == 0) {
1413                 NLP_SET(nlp, NLPF_DUMP);
1414                 params->mp_file_history_path_func = 0;
1415                 params->mp_file_history_dir_func =
1416                     ndmpd_api_file_history_dir_v3;
1417                 params->mp_file_history_node_func =
1418                     ndmpd_api_file_history_node_v3;
1419         } else if (strcmp(bu_type, NDMP_TAR_TYPE) == 0) {
1420                 NLP_SET(nlp, NLPF_TAR);
1421                 params->mp_file_history_path_func =
1422                     ndmpd_api_file_history_file_v3;
1423                 params->mp_file_history_dir_func = 0;
1424                 params->mp_file_history_node_func = 0;
1425         } else {
1426                 NLP_UNSET(nlp, NLPF_DUMP);
1427                 NLP_UNSET(nlp, NLPF_TAR);
1428         }
1429 
1430         session->ns_data.dd_module.dm_start_func = ndmpd_tar_backup_starter_v3;
1431         session->ns_data.dd_module.dm_abort_func = ndmpd_tar_backup_abort_v3;
1432 
1433         session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
1434         session->ns_data.dd_module.dm_stats.ms_est_time_remaining  = 0;
1435         session->ns_data.dd_nlist_v3 = 0;
1436         session->ns_data.dd_nlist_len = 0;
1437         session->ns_data.dd_bytes_left_to_read = 0;
1438         session->ns_data.dd_position = 0;
1439         session->ns_data.dd_discard_length = 0;
1440         session->ns_data.dd_read_offset = 0;
1441         session->ns_data.dd_read_length = 0;
1442 
1443         reply.error = ndmp_backup_get_params_v3(session, params);
1444         if (reply.error != NDMP_NO_ERR) {
1445                 NDMP_LOG(LOG_DEBUG, "err: %d", err);
1446                 NDMP_FREE(nlp->nlp_params);
1447                 return (reply.error);
1448         }
1449 
1450         reply.error = NDMP_NO_ERR;
1451         if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
1452             &reply) < 0) {
1453                 NDMP_LOG(LOG_DEBUG, "Sending data_start_backup_v3 reply");
1454                 return (NDMP_NO_ERR);
1455         }
1456 
1457         NS_INC(nbk);
1458         session->ns_data.dd_state = NDMP_DATA_STATE_ACTIVE;
1459         session->ns_data.dd_operation = NDMP_DATA_OP_BACKUP;
1460         session->ns_data.dd_abort = FALSE;
1461 
1462         /*
1463          * perform the backup
1464          *
1465          * Cannot wait for the thread to exit as we are replying to the
1466          * client request here.
1467          */
1468         err = pthread_create(NULL, NULL,
1469             (funct_t)session->ns_data.dd_module.dm_start_func,
1470             params);
1471         if (err != 0) {
1472                 NDMP_LOG(LOG_ERR, "Can't start backup session.");
1473                 return (NDMP_ILLEGAL_ARGS_ERR);
1474         }
1475 
1476         return (NDMP_NO_ERR);
1477 }
1478 
1479 /*
1480  * ndmpd_tar_start_recover_v3
1481  *
1482  * Start the restore work
1483  *
1484  * Parameters:
1485  *   session   (input) - session pointer.
1486  *   bu_type   (input) - backup type.
1487  *   env_val   (input) - environment variable array.
1488  *   env_len   (input) - length of env_val.
1489  *   nlist_val (input) - list of files.
1490  *   nlist_len (input) - length of nlist_val.
1491  *
1492  * Returns:
1493  *   NDMP_NO_ERR - recover successfully started.
1494  *   otherwise   - error code of recover start error.
1495  */
1496 static ndmp_error
1497 ndmpd_tar_start_recover_v3(ndmpd_session_t *session,
1498     ndmp_pval *env_val, ulong_t env_len, ndmp_name_v3 *nlist_val,
1499     ulong_t nlist_len)
1500 {
1501         ndmp_data_start_recover_reply_v3 reply;
1502         ndmpd_module_params_t *params;
1503         ndmp_lbr_params_t *nlp;
1504         int err;
1505 
1506         (void) memset((void*)&reply, 0, sizeof (reply));
1507 
1508         nlp = ndmp_get_nlp(session);
1509         NDMP_FREE(nlp->nlp_params);
1510         params = nlp->nlp_params = ndmp_malloc(sizeof (ndmpd_module_params_t));
1511         if (!params) {
1512                 return (NDMP_NO_MEM_ERR);
1513         }
1514 
1515         reply.error = ndmpd_save_env(session, env_val, env_len);
1516         if (reply.error != NDMP_NO_ERR) {
1517                 NDMP_FREE(nlp->nlp_params);
1518                 return (NDMP_NO_MEM_ERR);
1519         }
1520 
1521         reply.error = ndmpd_save_nlist_v3(session, nlist_val, nlist_len);
1522         if (reply.error != NDMP_NO_ERR) {
1523                 NDMP_FREE(nlp->nlp_params);
1524                 return (NDMP_NO_MEM_ERR);
1525         }
1526 
1527         /*
1528          * Setup restore parameters.
1529          */
1530         params->mp_daemon_cookie = (void *)session;
1531         params->mp_module_cookie = &session->ns_data.dd_module.dm_module_cookie;
1532         params->mp_protocol_version = session->ns_protocol_version;
1533         params->mp_operation = NDMP_DATA_OP_RECOVER;
1534         params->mp_get_env_func = ndmpd_api_get_env;
1535         params->mp_add_env_func = ndmpd_api_add_env;
1536         params->mp_set_env_func = ndmpd_api_set_env;
1537         params->mp_get_name_func = ndmpd_api_get_name_v3;
1538         params->mp_dispatch_func = ndmpd_api_dispatch;
1539         params->mp_done_func = ndmpd_api_done_v3;
1540         if (session->ns_protocol_version == NDMPV4) {
1541                 params->mp_log_func_v3 = ndmpd_api_log_v4;
1542                 params->mp_file_recovered_func = ndmpd_api_file_recovered_v4;
1543         } else {
1544                 params->mp_log_func_v3 = ndmpd_api_log_v3;
1545                 params->mp_file_recovered_func = ndmpd_api_file_recovered_v3;
1546         }
1547 
1548         params->mp_add_file_handler_func = ndmpd_api_add_file_handler;
1549         params->mp_remove_file_handler_func = ndmpd_api_remove_file_handler;
1550         params->mp_write_func = 0;
1551         params->mp_file_history_path_func = 0;
1552         params->mp_file_history_dir_func = 0;
1553         params->mp_file_history_node_func = 0;
1554         params->mp_read_func = ndmpd_api_read_v3;
1555         params->mp_seek_func = ndmpd_api_seek_v3;
1556         params->mp_stats = &session->ns_data.dd_module.dm_stats;
1557 
1558         session->ns_data.dd_module.dm_module_cookie = 0;
1559         session->ns_data.dd_module.dm_start_func = ndmpd_tar_restore_starter_v3;
1560         session->ns_data.dd_module.dm_abort_func = ndmpd_tar_restore_abort_v3;
1561         session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
1562         session->ns_data.dd_module.dm_stats.ms_est_time_remaining = 0;
1563         session->ns_data.dd_bytes_left_to_read = 0;
1564         session->ns_data.dd_position = 0;
1565         session->ns_data.dd_discard_length = 0;
1566         session->ns_data.dd_read_offset = 0;
1567         session->ns_data.dd_read_length = 0;
1568 
1569         err = ndmp_restore_get_params_v3(session, params);
1570         if (err != NDMP_NO_ERR) {
1571                 NDMP_FREE(nlp->nlp_params);
1572                 return (err);
1573         }
1574 
1575         reply.error = NDMP_NO_ERR;
1576         if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
1577             &reply) < 0) {
1578                 NDMP_FREE(nlp->nlp_params);
1579                 ndmpd_free_nlist_v3(session);
1580                 NDMP_LOG(LOG_DEBUG,
1581                     "Error sending ndmp_data_start_recover_reply");
1582                 ndmpd_data_error(session, NDMP_DATA_HALT_CONNECT_ERROR);
1583                 return (NDMP_NO_ERR);
1584         }
1585 
1586         NS_INC(nrs);
1587         session->ns_data.dd_state = NDMP_DATA_STATE_ACTIVE;
1588         session->ns_data.dd_operation = NDMP_DATA_OP_RECOVER;
1589         session->ns_data.dd_abort = FALSE;
1590 
1591         /*
1592          * perform the restore
1593          *
1594          * Cannot wait for the thread to exit as we are replying to the
1595          * client request here.
1596          */
1597         err = pthread_create(NULL, NULL,
1598             (funct_t)session->ns_data.dd_module.dm_start_func,
1599             params);
1600 
1601         if (err != 0) {
1602                 NDMP_LOG(LOG_ERR, "Can't start recover session.");
1603                 return (NDMP_ILLEGAL_ARGS_ERR);
1604         }
1605         return (NDMP_NO_ERR);
1606 }
1607 
1608 static ndmp_error
1609 ndmpd_zfs_start_op(ndmpd_session_t *session, ndmp_pval *env_val,
1610     ulong_t env_len, ndmp_name_v3 *nlist_val, ulong_t nlist_len,
1611     enum ndmp_data_operation op)
1612 {
1613         ndmpd_zfs_args_t *ndmpd_zfs_args = &session->ns_ndmpd_zfs_args;
1614         ndmp_data_start_backup_reply_v3 backup_reply;
1615         ndmp_data_start_recover_reply_v3 recover_reply;
1616         pthread_t tid;
1617         void *reply;
1618         char str[8];
1619         int err;
1620 
1621         if (ndmpd_zfs_init(session) != 0)
1622                 return (NDMP_UNDEFINED_ERR);
1623 
1624         err = ndmpd_save_env(session, env_val, env_len);
1625         if (err != NDMP_NO_ERR) {
1626                 ndmpd_zfs_fini(ndmpd_zfs_args);
1627                 return (err);
1628         }
1629 
1630         switch (op) {
1631         case NDMP_DATA_OP_BACKUP:
1632                 if (!ndmpd_zfs_backup_parms_valid(ndmpd_zfs_args)) {
1633                         ndmpd_zfs_fini(ndmpd_zfs_args);
1634                         return (NDMP_ILLEGAL_ARGS_ERR);
1635                 }
1636 
1637                 if (ndmpd_zfs_pre_backup(ndmpd_zfs_args)) {
1638                         NDMP_LOG(LOG_ERR, "pre_backup error");
1639                         return (NDMP_ILLEGAL_ARGS_ERR);
1640                 }
1641 
1642                 session->ns_data.dd_module.dm_start_func =
1643                     ndmpd_zfs_backup_starter;
1644                 (void) strlcpy(str, "backup", 8);
1645                 break;
1646         case NDMP_DATA_OP_RECOVER:
1647                 err = ndmpd_save_nlist_v3(session, nlist_val, nlist_len);
1648                 if (err != NDMP_NO_ERR) {
1649                         ndmpd_zfs_fini(ndmpd_zfs_args);
1650                         return (NDMP_NO_MEM_ERR);
1651                 }
1652 
1653                 if (!ndmpd_zfs_restore_parms_valid(ndmpd_zfs_args)) {
1654                         ndmpd_zfs_fini(ndmpd_zfs_args);
1655                         return (NDMP_ILLEGAL_ARGS_ERR);
1656                 }
1657 
1658                 if (ndmpd_zfs_pre_restore(ndmpd_zfs_args)) {
1659                         NDMP_LOG(LOG_ERR, "pre_restore error");
1660                         (void) ndmpd_zfs_post_restore(ndmpd_zfs_args);
1661                         return (NDMP_ILLEGAL_ARGS_ERR);
1662                 }
1663                 session->ns_data.dd_module.dm_start_func =
1664                     ndmpd_zfs_restore_starter;
1665                 (void) strlcpy(str, "recover", 8);
1666                 break;
1667         }
1668 
1669         ndmpd_zfs_params->mp_operation = op;
1670         session->ns_data.dd_operation = op;
1671         session->ns_data.dd_module.dm_abort_func = ndmpd_zfs_abort;
1672         session->ns_data.dd_state = NDMP_DATA_STATE_ACTIVE;
1673         session->ns_data.dd_abort = FALSE;
1674 
1675         if (op == NDMP_DATA_OP_BACKUP) {
1676                 (void) memset((void*)&backup_reply, 0, sizeof (backup_reply));
1677                 backup_reply.error = NDMP_NO_ERR;
1678                 reply = &backup_reply;
1679         } else {
1680                 (void) memset((void*)&recover_reply, 0, sizeof (recover_reply));
1681                 recover_reply.error = NDMP_NO_ERR;
1682                 reply = &recover_reply;
1683         }
1684 
1685         if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
1686             reply) < 0) {
1687                 NDMP_LOG(LOG_DEBUG, "Sending data_start_%s_v3 reply", str);
1688                 if (op == NDMP_DATA_OP_RECOVER)
1689                         ndmpd_data_error(session, NDMP_DATA_HALT_CONNECT_ERROR);
1690                 ndmpd_zfs_fini(ndmpd_zfs_args);
1691                 return (NDMP_NO_ERR);
1692         }
1693 
1694         err = pthread_create(&tid, NULL,
1695             (funct_t)session->ns_data.dd_module.dm_start_func, ndmpd_zfs_args);
1696 
1697         if (err) {
1698                 NDMP_LOG(LOG_ERR, "Can't start %s session (errno %d)",
1699                     str, err);
1700                 ndmpd_zfs_fini(ndmpd_zfs_args);
1701                 MOD_DONE(ndmpd_zfs_params, -1);
1702                 return (NDMP_NO_ERR);
1703         }
1704 
1705         (void) pthread_detach(tid);
1706 
1707         if (op == NDMP_DATA_OP_BACKUP)
1708                 NS_INC(nbk);
1709         else
1710                 NS_INC(nrs);
1711 
1712         ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_NORMAL,
1713             "'zfs' %s starting\n", str);
1714 
1715         return (NDMP_NO_ERR);
1716 }
1717 
1718 /*
1719  * discard_data_v3
1720  *
1721  * Read and discard data from the data connection.
1722  * Called when a module has called ndmpd_seek() prior to
1723  * reading all of the data from the previous seek.
1724  *
1725  * Parameters:
1726  *   session (input) - session pointer.
1727  *
1728  * Returns:
1729  *   number of bytes read and discarded.
1730  *  -1 - error.
1731  */
1732 static int
1733 discard_data_v3(ndmpd_session_t *session, ulong_t length)
1734 {
1735         static char buf[MAX_RECORD_SIZE];
1736         int n, toread;
1737 
1738         toread = (length < MAX_RECORD_SIZE) ? length :
1739             MAX_RECORD_SIZE;
1740 
1741         /* Read and discard the data. */
1742         n = read(session->ns_data.dd_sock, buf, toread);
1743         if (n < 0) {
1744                 NDMP_LOG(LOG_ERR, "Socket read error: %m.");
1745                 n = -1;
1746         }
1747 
1748         return (n);
1749 }
1750 
1751 
1752 /*
1753  * ndmpd_remote_read_v3
1754  *
1755  * Reads data from the remote mover.
1756  *
1757  * Parameters:
1758  *   session (input) - session pointer.
1759  *   data    (input) - data to be written.
1760  *   length  (input) - data length.
1761  *
1762  * Returns:
1763  *   0 - data successfully read.
1764  *  -1 - error.
1765  */
1766 int
1767 ndmpd_remote_read_v3(ndmpd_session_t *session, char *data, ulong_t length)
1768 {
1769         ulong_t count;
1770         ulong_t len;
1771         ssize_t n;
1772         ndmp_notify_data_read_request request;
1773         tlm_job_stats_t *jstat;
1774         longlong_t fsize;
1775 
1776         NDMP_LOG(LOG_DEBUG, "ns_data.dd_xx: [%llu, %llu, %llu, %llu, %llu]",
1777             session->ns_data.dd_bytes_left_to_read,
1778             session->ns_data.dd_read_offset,
1779             session->ns_data.dd_read_length,
1780             session->ns_data.dd_position,
1781             session->ns_data.dd_discard_length);
1782 
1783         count = 0;
1784         while (count < length) {
1785                 len = length - count;
1786 
1787                 /*
1788                  * If the end of the seek window has been reached then
1789                  * send an ndmp_read request to the client.
1790                  * The NDMP client will then send a mover_data_read request to
1791                  * the remote mover and the mover will send more data.
1792                  * This condition can occur if the module attempts to read past
1793                  * a seek window set via a prior call to ndmpd_seek() or
1794                  * the module has not issued a seek. If no seek was issued then
1795                  * pretend that a seek was issued to read the entire tape.
1796                  */
1797                 if (session->ns_data.dd_bytes_left_to_read == 0) {
1798                         /* ndmpd_seek() never called? */
1799                         if (session->ns_data.dd_read_length == 0) {
1800                                 session->ns_data.dd_bytes_left_to_read = ~0LL;
1801                                 session->ns_data.dd_read_offset = 0LL;
1802                                 session->ns_data.dd_read_length = ~0LL;
1803                         } else {
1804                                 /*
1805                                  * While restoring a file, restoreFile()
1806                                  * records the number of bytes still need to
1807                                  * be restored.  We use this as a guidance
1808                                  * when asking for data from the tape.
1809                                  */
1810                                 jstat = session->ns_ndmp_lbr_params->nlp_jstat;
1811                                 fsize = jstat->js_bytes_in_file;
1812 
1813                                 NDMP_LOG(LOG_DEBUG, "bytes_left [%llu / %u]",
1814                                     fsize, len);
1815 
1816                                 /*
1817                                  * Fall back to the old way if fsize if too
1818                                  * small.
1819                                  */
1820                                 if (fsize < len)
1821                                         fsize = len;
1822 
1823                                 session->ns_data.dd_bytes_left_to_read = fsize;
1824                                 session->ns_data.dd_read_offset =
1825                                     session->ns_data.dd_position;
1826                                 session->ns_data.dd_read_length = fsize;
1827                         }
1828 
1829                         request.offset =
1830                             long_long_to_quad(session->ns_data.dd_read_offset);
1831                         request.length =
1832                             long_long_to_quad(session->ns_data.dd_read_length);
1833 
1834                         NDMP_LOG(LOG_DEBUG, "to NOTIFY_DATA_READ [%llu, %llu]",
1835                             session->ns_data.dd_read_offset,
1836                             session->ns_data.dd_read_length);
1837 
1838                         if (ndmp_send_request_lock(session->ns_connection,
1839                             NDMP_NOTIFY_DATA_READ, NDMP_NO_ERR,
1840                             &request, 0) < 0) {
1841                                 NDMP_LOG(LOG_DEBUG,
1842                                     "Sending notify_data_read request");
1843                                 return (-1);
1844                         }
1845                 }
1846 
1847                 /*
1848                  * If the module called ndmpd_seek() prior to reading all of the
1849                  * data that the remote mover was requested to send, then the
1850                  * excess data from the seek has to be discarded.
1851                  */
1852                 if (session->ns_data.dd_discard_length != 0) {
1853                         n = discard_data_v3(session,
1854                             (ulong_t)session->ns_data.dd_discard_length);
1855                         if (n < 0)
1856                                 return (-1);
1857 
1858                         session->ns_data.dd_discard_length -= n;
1859                         continue;
1860                 }
1861 
1862                 /*
1863                  * Don't attempt to read more data than the remote is sending.
1864                  */
1865                 if (len > session->ns_data.dd_bytes_left_to_read)
1866                         len = session->ns_data.dd_bytes_left_to_read;
1867 
1868                 if ((n = read(session->ns_data.dd_sock, &data[count],
1869                     len)) < 0) {
1870                         NDMP_LOG(LOG_ERR, "Socket read error: %m.");
1871                         return (-1);
1872                 }
1873 
1874                 /* read returns 0 if the connection was closed */
1875                 if (n == 0) {
1876                         NDMP_LOG(LOG_DEBUG, "n 0 errno %d",
1877                             errno);
1878                         return (-1);
1879                 }
1880 
1881                 count += n;
1882                 session->ns_data.dd_bytes_left_to_read -= n;
1883                 session->ns_data.dd_position += n;
1884         }
1885         return (0);
1886 }
1887 
1888 /*
1889  * nlp_release_job_stat
1890  *
1891  * Unreference the job statistics
1892  *
1893  * Parameters:
1894  *   session (input) - session pointer.
1895  *
1896  * Returns:
1897  *   void
1898  */
1899 static void
1900 nlp_release_job_stat(ndmpd_session_t *session)
1901 {
1902         ndmp_lbr_params_t *nlp;
1903 
1904         if ((nlp = ndmp_get_nlp(session)) == NULL) {
1905                 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1906                 return;
1907         }
1908         if (nlp->nlp_jstat != NULL) {
1909                 nlp->nlp_bytes_total =
1910                     (u_longlong_t)nlp->nlp_jstat->js_bytes_total;
1911                 tlm_un_ref_job_stats(nlp->nlp_jstat->js_job_name);
1912                 nlp->nlp_jstat = NULL;
1913         } else
1914                 NDMP_LOG(LOG_DEBUG, "JSTAT == NULL");
1915 }
1916 
1917 
1918 /* *** ndmpd global internal functions *********************************** */
1919 
1920 /*
1921  * ndmpd_data_init
1922  *
1923  * Initializes data specific session variables.
1924  *
1925  * Parameters:
1926  *   session (input) - session pointer.
1927  *
1928  * Returns:
1929  *   void
1930  */
1931 int
1932 ndmpd_data_init(ndmpd_session_t *session)
1933 {
1934         session->ns_data.dd_operation = NDMP_DATA_OP_NOACTION;
1935         session->ns_data.dd_state = NDMP_DATA_STATE_IDLE;
1936         session->ns_data.dd_halt_reason = NDMP_DATA_HALT_NA;
1937         session->ns_data.dd_abort = FALSE;
1938         session->ns_data.dd_env = 0;
1939         session->ns_data.dd_env_len = 0;
1940         session->ns_data.dd_nlist = 0;
1941         session->ns_data.dd_nlist_len = 0;
1942         session->ns_data.dd_mover.addr_type = NDMP_ADDR_LOCAL;
1943         session->ns_data.dd_sock = -1;
1944         session->ns_data.dd_read_offset = 0;
1945         session->ns_data.dd_read_length = 0;
1946         session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
1947         session->ns_data.dd_module.dm_stats.ms_est_time_remaining = 0;
1948         /*
1949          * NDMP V3
1950          */
1951         session->ns_data.dd_state = NDMP_DATA_STATE_IDLE;
1952         session->ns_data.dd_nlist_v3 = 0;
1953         session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_LOCAL;
1954         session->ns_data.dd_listen_sock = -1;
1955         session->ns_data.dd_bytes_left_to_read = 0LL;
1956         session->ns_data.dd_position = 0LL;
1957         session->ns_data.dd_discard_length = 0LL;
1958         return (0);
1959 }
1960 
1961 
1962 
1963 /*
1964  * ndmpd_data_cleanup
1965  *
1966  * Releases resources allocated during a data operation.
1967  *
1968  * Parameters:
1969  *   session (input) - session pointer.
1970  *
1971  * Returns:
1972  *   void
1973  */
1974 void
1975 ndmpd_data_cleanup(ndmpd_session_t *session)
1976 {
1977         if (session->ns_data.dd_listen_sock != -1) {
1978                 NDMP_LOG(LOG_DEBUG, "data.listen_sock: %d",
1979                     session->ns_data.dd_listen_sock);
1980                 (void) ndmpd_remove_file_handler(session,
1981                     session->ns_data.dd_listen_sock);
1982                 (void) close(session->ns_data.dd_listen_sock);
1983                 session->ns_data.dd_listen_sock = -1;
1984         }
1985         if (session->ns_data.dd_sock != -1) {
1986                 NDMP_LOG(LOG_DEBUG, "data.sock: %d",
1987                     session->ns_data.dd_sock);
1988 
1989                 /*
1990                  * ndmpcopy: we use the same socket for the mover,
1991                  * so expect to close when mover is done!
1992                  */
1993                 if (session->ns_data.dd_sock != session->ns_mover.md_sock)
1994                         (void) close(session->ns_data.dd_sock);
1995 
1996                 session->ns_data.dd_sock = -1;
1997         }
1998 
1999         ndmpd_free_env(session);
2000         ndmpd_free_nlist(session);
2001 }
2002 
2003 
2004 /*
2005  * ndmp_data_get_mover_mode
2006  *
2007  * Return the mover mode
2008  *
2009  * Parameters:
2010  *   session (input) - session pointer.
2011  *
2012  * Returns:
2013  *   remote - remote backup
2014  *   local  - local backup
2015  */
2016 char *
2017 ndmp_data_get_mover_mode(ndmpd_session_t *session)
2018 {
2019         char *rv;
2020 
2021         switch (session->ns_protocol_version) {
2022         case NDMPV2:
2023                 rv = ((session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP)
2024                     ? "remote" : "local");
2025                 break;
2026         case NDMPV3:
2027                 rv = ((session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_TCP)
2028                     ? "remote" : "local");
2029                 break;
2030         case NDMPV4:
2031                 rv = ((session->ns_data.dd_data_addr.addr_type ==
2032                     NDMP_ADDR_TCP ||
2033                     (session->ns_data.dd_data_addr_v4.addr_type ==
2034                     NDMP_ADDR_TCP)) ? "remote" : "local");
2035                 break;
2036         default:
2037                 rv = "Unknown";
2038                 NDMP_LOG(LOG_ERR, "Invalid protocol version %d.",
2039                     session->ns_protocol_version);
2040         }
2041 
2042         return (rv);
2043 }
2044 
2045 /* *** static functions ******************************************** */
2046 
2047 /*
2048  * ndmpd_tar_start_backup_v2
2049  *
2050  * Request handling code common to version 1 and
2051  * version 2 data_start_backup request handlers.
2052  *
2053  * Parameters:
2054  *   session   (input) - session pointer.
2055  *   bu_type   (input) - backup type.
2056  *   env_val   (input) - environment variable array.
2057  *   env_len   (input) - length of env_val.
2058  *
2059  * Returns:
2060  *   NDMP_NO_ERR - backup successfully started.
2061  *   otherwise - error code of backup start error.
2062  */
2063 static ndmp_error
2064 ndmpd_tar_start_backup_v2(ndmpd_session_t *session, char *bu_type,
2065     ndmp_pval *env_val, ulong_t env_len)
2066 {
2067         ndmp_data_start_backup_reply reply;
2068         ndmpd_module_params_t *params;
2069         ndmp_lbr_params_t *nlp;
2070         int err;
2071 
2072         if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
2073                 NDMP_LOG(LOG_ERR, "Can't start new backup in current state.");
2074                 return (NDMP_ILLEGAL_STATE_ERR);
2075         }
2076         if (strcmp(bu_type, NDMP_DUMP_TYPE) != 0 &&
2077             strcmp(bu_type, NDMP_TAR_TYPE) != 0) {
2078                 NDMP_LOG(LOG_ERR, "Invalid backup type: %s.", bu_type);
2079                 NDMP_LOG(LOG_ERR, "Supported backup types are tar and dump.");
2080                 return (NDMP_ILLEGAL_ARGS_ERR);
2081         }
2082         if ((err = ndmpd_save_env(session, env_val, env_len)) != NDMP_NO_ERR)
2083                 return (err);
2084 
2085         nlp = ndmp_get_nlp(session);
2086         NDMP_FREE(nlp->nlp_params);
2087         params = nlp->nlp_params = ndmp_malloc(sizeof (ndmpd_module_params_t));
2088         if (params == NULL)
2089                 return (NDMP_NO_MEM_ERR);
2090 
2091         params->mp_daemon_cookie = (void *)session;
2092         params->mp_module_cookie = &session->ns_data.dd_module.dm_module_cookie;
2093         params->mp_protocol_version = session->ns_protocol_version;
2094         params->mp_operation = NDMP_DATA_OP_BACKUP;
2095         params->mp_get_env_func = ndmpd_api_get_env;
2096         params->mp_add_env_func = ndmpd_api_add_env;
2097         params->mp_get_name_func = ndmpd_api_get_name;
2098         params->mp_dispatch_func = ndmpd_api_dispatch;
2099         params->mp_done_func = ndmpd_api_done_v2;
2100         params->mp_log_func = ndmpd_api_log_v2;
2101         params->mp_add_file_handler_func = ndmpd_api_add_file_handler;
2102         params->mp_remove_file_handler_func = ndmpd_api_remove_file_handler;
2103         params->mp_write_func = ndmpd_api_write_v2;
2104         params->mp_read_func = 0;
2105         params->mp_file_recovered_func = 0;
2106         params->mp_stats = &session->ns_data.dd_module.dm_stats;
2107 
2108         session->ns_data.dd_module.dm_module_cookie = 0;
2109         if (strcmp(bu_type, NDMP_DUMP_TYPE) == 0) {
2110                 NLP_SET(nlp, NLPF_DUMP);
2111                 params->mp_file_history_path_func = 0;
2112                 params->mp_file_history_dir_func =
2113                     ndmpd_api_file_history_dir_v2;
2114                 params->mp_file_history_node_func =
2115                     ndmpd_api_file_history_node_v2;
2116         } else if (strcmp(bu_type, NDMP_TAR_TYPE) == 0) {
2117                 /* backup type == NDMP_TAR_TYPE */
2118                 NLP_SET(nlp, NLPF_TAR);
2119                 params->mp_file_history_path_func =
2120                     ndmpd_api_file_history_path_v2;
2121                 params->mp_file_history_dir_func = 0;
2122                 params->mp_file_history_node_func = 0;
2123         } else {
2124                 NLP_UNSET(nlp, NLPF_DUMP);
2125                 NLP_UNSET(nlp, NLPF_TAR);
2126         }
2127 
2128         session->ns_data.dd_module.dm_start_func = ndmpd_tar_backup_starter;
2129         session->ns_data.dd_module.dm_abort_func = ndmpd_tar_backup_abort;
2130 
2131         session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
2132         session->ns_data.dd_module.dm_stats.ms_est_time_remaining = 0;
2133         session->ns_data.dd_nlist = 0;
2134         session->ns_data.dd_nlist_len = 0;
2135         session->ns_data.dd_read_offset = 0;
2136         session->ns_data.dd_read_length = 0;
2137 
2138         if ((err = ndmp_backup_extract_params(session,
2139             params)) != NDMP_NO_ERR) {
2140                 NDMP_LOG(LOG_DEBUG, "err: %d", err);
2141                 NDMP_FREE(nlp->nlp_params);
2142                 return (err);
2143         }
2144 
2145         err = ndmpd_mover_connect(session, NDMP_MOVER_MODE_READ);
2146         if (err != NDMP_NO_ERR) {
2147                 NDMP_LOG(LOG_DEBUG,
2148                     "mover connect err: %d", err);
2149                 NDMP_FREE(nlp->nlp_params);
2150                 return (err);
2151         }
2152 
2153         session->ns_data.dd_state = NDMP_DATA_STATE_ACTIVE;
2154 
2155         session->ns_data.dd_operation = NDMP_DATA_OP_BACKUP;
2156         session->ns_data.dd_abort = FALSE;
2157 
2158         NDMP_LOG(LOG_DEBUG, "starting backup");
2159 
2160         reply.error = NDMP_NO_ERR;
2161         if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
2162             &reply) < 0) {
2163                 NDMP_LOG(LOG_DEBUG, "Sending data_start_backup reply");
2164                 NDMP_FREE(nlp->nlp_params);
2165                 if (session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP) {
2166                         /*
2167                          * ndmpcopy: we use the same socket for the mover,
2168                          * so expect to close when mover is done!
2169                          */
2170                         if (session->ns_data.dd_sock !=
2171                             session->ns_mover.md_sock)
2172                                 (void) close(session->ns_data.dd_sock);
2173 
2174                         session->ns_data.dd_sock = -1;
2175                 } else
2176                         ndmpd_mover_error(session,
2177                             NDMP_MOVER_HALT_CONNECT_CLOSED);
2178                 return (NDMP_NO_ERR);
2179         }
2180 
2181         /*
2182          * perform the backup
2183          *
2184          * Cannot wait for the thread to exit as we are replying to the
2185          * client request here.
2186          */
2187         (void) pthread_create(NULL, NULL,
2188             (funct_t)session->ns_data.dd_module.dm_start_func,
2189             params);
2190 
2191         return (NDMP_NO_ERR);
2192 }
2193 
2194 /*
2195  * ndmpd_tar_start_recover_v2
2196  *
2197  * The main recover/restore function
2198  *
2199  * Parameters:
2200  *   session   (input) - session pointer.
2201  *   bu_type   (input) - backup type.
2202  *   env_val   (input) - environment variable array.
2203  *   env_len   (input) - length of env_val.
2204  *   nlist_val (input) - list of files.
2205  *   nlist_len (input) - length of nlist_val.
2206  *
2207  * Returns:
2208  *   NDMP_NO_ERR - recover successfully started.
2209  *   otherwise - error code of backup start error.
2210  */
2211 static ndmp_error
2212 ndmpd_tar_start_recover_v2(ndmpd_session_t *session, char *bu_type,
2213     ndmp_pval *env_val, ulong_t env_len, ndmp_name *nlist_val,
2214     ulong_t nlist_len)
2215 {
2216         ndmp_data_start_recover_reply_v2 reply;
2217         ndmpd_module_params_t *params;
2218         ndmp_lbr_params_t *nlp;
2219         int err;
2220 
2221         if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
2222                 NDMP_LOG(LOG_ERR, "Can't start new recover in current state.");
2223                 return (NDMP_ILLEGAL_STATE_ERR);
2224         }
2225 
2226         if (strcmp(bu_type, NDMP_DUMP_TYPE) != 0 &&
2227             strcmp(bu_type, NDMP_TAR_TYPE) != 0) {
2228                 NDMP_LOG(LOG_ERR, "Invalid backup type: %s.", bu_type);
2229                 NDMP_LOG(LOG_ERR, "Supported backup types are tar and dump.");
2230                 return (NDMP_ILLEGAL_ARGS_ERR);
2231         }
2232 
2233         reply.error = ndmpd_save_env(session, env_val, env_len);
2234         if (reply.error != NDMP_NO_ERR)
2235                 return (NDMP_NO_MEM_ERR);
2236 
2237         reply.error = ndmpd_save_nlist_v2(session, nlist_val, nlist_len);
2238         if (reply.error != NDMP_NO_ERR)
2239                 return (NDMP_NO_MEM_ERR);
2240 
2241         nlp = ndmp_get_nlp(session);
2242         NDMP_FREE(nlp->nlp_params);
2243         params = nlp->nlp_params = ndmp_malloc(sizeof (ndmpd_module_params_t));
2244         if (params == NULL)
2245                 return (NDMP_NO_MEM_ERR);
2246 
2247         /*
2248          * Setup restore parameters.
2249          */
2250         params->mp_daemon_cookie = (void *)session;
2251         params->mp_module_cookie = &session->ns_data.dd_module.dm_module_cookie;
2252         params->mp_protocol_version = session->ns_protocol_version;
2253         params->mp_operation = NDMP_DATA_OP_RECOVER;
2254         params->mp_get_env_func = ndmpd_api_get_env;
2255         params->mp_add_env_func = ndmpd_api_add_env;
2256         params->mp_get_name_func = ndmpd_api_get_name;
2257         params->mp_dispatch_func = ndmpd_api_dispatch;
2258         params->mp_done_func = ndmpd_api_done_v2;
2259         params->mp_log_func = ndmpd_api_log_v2;
2260         params->mp_add_file_handler_func = ndmpd_api_add_file_handler;
2261         params->mp_remove_file_handler_func = ndmpd_api_remove_file_handler;
2262         params->mp_write_func = 0;
2263         params->mp_file_history_path_func = 0;
2264         params->mp_file_history_dir_func = 0;
2265         params->mp_file_history_node_func = 0;
2266         params->mp_read_func = ndmpd_api_read_v2;
2267         params->mp_seek_func = ndmpd_api_seek_v2;
2268         params->mp_file_recovered_func = ndmpd_api_file_recovered_v2;
2269         params->mp_stats = &session->ns_data.dd_module.dm_stats;
2270 
2271         session->ns_data.dd_module.dm_module_cookie = 0;
2272         session->ns_data.dd_module.dm_start_func = ndmpd_tar_restore_starter;
2273         session->ns_data.dd_module.dm_abort_func = ndmpd_tar_restore_abort;
2274         session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
2275         session->ns_data.dd_module.dm_stats.ms_est_time_remaining = 0;
2276         session->ns_data.dd_read_offset = 0;
2277         session->ns_data.dd_read_length = 0;
2278 
2279         if ((err = ndmp_restore_extract_params(session,
2280             params)) != NDMP_NO_ERR) {
2281                 NDMP_FREE(nlp->nlp_params);
2282                 return (err);
2283         }
2284 
2285         err = ndmpd_mover_connect(session, NDMP_MOVER_MODE_WRITE);
2286         if (err != NDMP_NO_ERR) {
2287                 NDMP_FREE(nlp->nlp_params);
2288                 return (err);
2289         }
2290 
2291         session->ns_data.dd_state = NDMP_DATA_STATE_ACTIVE;
2292         session->ns_data.dd_operation = NDMP_DATA_OP_RECOVER;
2293         session->ns_data.dd_abort = FALSE;
2294 
2295         reply.error = NDMP_NO_ERR;
2296         if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
2297             &reply) < 0) {
2298                 NDMP_LOG(LOG_DEBUG, "Sending data_start_recover reply");
2299                 NDMP_FREE(nlp->nlp_params);
2300                 if (session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP) {
2301                         /*
2302                          * ndmpcopy: we use the same socket for the mover,
2303                          * so expect to close when mover is done!
2304                          */
2305                         if (session->ns_data.dd_sock !=
2306                             session->ns_mover.md_sock)
2307                                 (void) close(session->ns_data.dd_sock);
2308 
2309                         session->ns_data.dd_sock = -1;
2310                 } else {
2311                         ndmpd_mover_error(session,
2312                             NDMP_MOVER_HALT_CONNECT_CLOSED);
2313                 }
2314                 return (NDMP_NO_ERR);
2315         }
2316 
2317 
2318         /*
2319          * perform the restore
2320          *
2321          * Cannot wait for the thread to exit as we are replying to the
2322          * client request here.
2323          */
2324         (void) pthread_create(NULL, NULL,
2325             (funct_t)session->ns_data.dd_module.dm_start_func,
2326             params);
2327 
2328         return (NDMP_NO_ERR);
2329 }
2330 
2331 /*
2332  * ndmpd_data_get_info
2333  *
2334  * Return the total number of bytes processed
2335  *
2336  * Parameters:
2337  *   session   (input) - session pointer.
2338  *
2339  * Returns:
2340  *   the number of bytes processed
2341  */
2342 static u_longlong_t
2343 ndmpd_data_get_info(ndmpd_session_t *session)
2344 {
2345         ndmp_lbr_params_t *nlp;
2346 
2347         nlp = ndmp_get_nlp(session);
2348         if (nlp == NULL)
2349                 return ((u_longlong_t)0);
2350 
2351         if (nlp->nlp_jstat == NULL)
2352                 return (nlp->nlp_bytes_total);
2353 
2354         return ((u_longlong_t)nlp->nlp_jstat->js_bytes_total);
2355 }