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