xref: /illumos-gate/usr/src/cmd/ndmpd/ndmp/ndmpd_data.c (revision 15c07adc1c7b828006b5e3c4d528b92229d6bd23)
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 }
2356