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
52static int ndmpd_data_error_send_v4(ndmpd_session_t *session,
53    ndmp_data_halt_reason reason);
54static int ndmpd_data_error_send(ndmpd_session_t *session,
55    ndmp_data_halt_reason reason);
56static void data_accept_connection_v3(void *cookie, int fd, ulong_t mode);
57static int create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr,
58    ushort_t *port);
59static ndmp_error data_connect_sock_v3(ndmpd_session_t *session, ulong_t addr,
60    ushort_t port);
61static int discard_data_v3(ndmpd_session_t *session, ulong_t length);
62static void nlp_release_job_stat(ndmpd_session_t *session);
63static u_longlong_t ndmpd_data_get_info(ndmpd_session_t *session);
64
65static ndmp_error ndmpd_tar_start_backup_v2(ndmpd_session_t *, char *,
66    ndmp_pval *, ulong_t);
67static ndmp_error ndmpd_tar_start_recover_v2(ndmpd_session_t *, char *,
68    ndmp_pval *, ulong_t, ndmp_name *, ulong_t);
69static ndmp_error ndmpd_tar_start_backup_v3(ndmpd_session_t *, char *,
70    ndmp_pval *, ulong_t);
71static ndmp_error ndmpd_tar_start_recover_v3(ndmpd_session_t *,
72    ndmp_pval *, ulong_t, ndmp_name_v3 *, ulong_t);
73
74static 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*/
97void
98ndmpd_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 */
138void
139ndmpd_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 */
179void
180ndmpd_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*/
221void
222ndmpd_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*/
255void
256ndmpd_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*/
298void
299ndmpd_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*/
344void
345ndmpd_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 */
392void
393ndmpd_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 */
482void
483ndmpd_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*/
566void
567ndmpd_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*/
622void
623ndmpd_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 */
662void
663ndmpd_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 */
743void
744ndmpd_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*/
827void
828ndmpd_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*/
866void
867ndmpd_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 */
916void
917ndmpd_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 */
991void
992ndmpd_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*/
1087void
1088ndmpd_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*/
1118static int
1119ndmpd_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*/
1144static int
1145ndmpd_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 */
1170void
1171ndmpd_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*/
1249static void
1250data_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 */
1295static int
1296create_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 */
1335static ndmp_error
1336data_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 */
1368static ndmp_error
1369ndmpd_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 */
1496static ndmp_error
1497ndmpd_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
1608static ndmp_error
1609ndmpd_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 */
1732static int
1733discard_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 */
1766int
1767ndmpd_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 */
1899static void
1900nlp_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 */
1931int
1932ndmpd_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 */
1974void
1975ndmpd_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 */
2016char *
2017ndmp_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 */
2063static ndmp_error
2064ndmpd_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 */
2211static ndmp_error
2212ndmpd_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 */
2342static u_longlong_t
2343ndmpd_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