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