1/*
2 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3 */
4
5/*
6 * BSD 3 Clause License
7 *
8 * Copyright (c) 2007, The Storage Networking Industry Association.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 	- Redistributions of source code must retain the above copyright
14 *	  notice, this list of conditions and the following disclaimer.
15 *
16 * 	- Redistributions in binary form must reproduce the above copyright
17 *	  notice, this list of conditions and the following disclaimer in
18 *	  the documentation and/or other materials provided with the
19 *	  distribution.
20 *
21 *	- Neither the name of The Storage Networking Industry Association (SNIA)
22 *	  nor the names of its contributors may be used to endorse or promote
23 *	  products derived from this software without specific prior written
24 *	  permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38/* Copyright (c) 2007, The Storage Networking Industry Association. */
39/* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
40/* Copyright 2014 Nexenta Systems, Inc.  All rights reserved. */
41
42#include <sys/ioctl.h>
43#include <sys/types.h>
44#include <sys/socket.h>
45#include <sys/socketvar.h>
46#include <netinet/in.h>
47#include <arpa/inet.h>
48#include <net/if.h>
49#include <errno.h>
50#include <fcntl.h>
51#include <netdb.h>
52#include <stdlib.h>
53#include <unistd.h>
54#include <string.h>
55#include "ndmpd_common.h"
56#include "ndmpd.h"
57#include <sys/mtio.h>
58
59/*
60 * Maximum mover record size
61 */
62#define	MAX_MOVER_RECSIZE	(512*KILOBYTE)
63
64static int create_listen_socket_v2(ndmpd_session_t *session, ulong_t *addr,
65    ushort_t *port);
66static int tape_read(ndmpd_session_t *session, char *data);
67static int change_tape(ndmpd_session_t *session);
68static int discard_data(ndmpd_session_t *session, ulong_t length);
69static int mover_tape_read_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf);
70static int mover_socket_write_one_buf(ndmpd_session_t *session,
71    tlm_buffer_t *buf);
72static int start_mover_for_restore(ndmpd_session_t *session);
73static int mover_socket_read_one_buf(ndmpd_session_t *session,
74    tlm_buffer_t *buf, long read_size);
75static int mover_tape_write_one_buf(ndmpd_session_t *session,
76    tlm_buffer_t *buf);
77static int start_mover_for_backup(ndmpd_session_t *session);
78static boolean_t is_writer_running_v3(ndmpd_session_t *session);
79static int mover_pause_v3(ndmpd_session_t *session,
80    ndmp_mover_pause_reason reason);
81static int mover_tape_write_v3(ndmpd_session_t *session, char *data,
82    ssize_t length);
83static int mover_tape_flush_v3(ndmpd_session_t *session);
84static int mover_tape_read_v3(ndmpd_session_t *session, char *data);
85static int create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr,
86    ushort_t *port);
87static void mover_data_read_v3(void *cookie, int fd, ulong_t mode);
88static void accept_connection(void *cookie, int fd, ulong_t mode);
89static void mover_data_write_v3(void *cookie, int fd, ulong_t mode);
90static void accept_connection_v3(void *cookie, int fd, ulong_t mode);
91static ndmp_error mover_connect_sock(ndmpd_session_t *session,
92    ndmp_mover_mode mode, ulong_t addr, ushort_t port);
93static boolean_t is_writer_running(ndmpd_session_t *session);
94static int set_socket_nonblock(int sock);
95
96
97int ndmp_max_mover_recsize = MAX_MOVER_RECSIZE; /* patchable */
98
99#define	TAPE_READ_ERR		-1
100#define	TAPE_NO_WRITER_ERR	-2
101
102/*
103 * Set non-blocking mode for socket.
104 */
105static int
106set_socket_nonblock(int sock)
107{
108	int flags;
109
110	flags = fcntl(sock, F_GETFL, 0);
111	if (flags < 0)
112		return (0);
113	return (fcntl(sock, F_SETFL, flags|O_NONBLOCK) == 0);
114}
115
116/*
117 * ************************************************************************
118 * NDMP V2 HANDLERS
119 * ************************************************************************
120 */
121
122/*
123 * ndmpd_mover_get_state_v2
124 *
125 * This handler handles the mover_get_state request.
126 * Status information for the mover state machine is returned.
127 *
128 * Parameters:
129 *   connection (input) - connection handle.
130 *   body       (input) - request message body.
131 *
132 * Returns:
133 *   void
134 */
135/*ARGSUSED*/
136void
137ndmpd_mover_get_state_v2(ndmp_connection_t *connection, void *body)
138{
139	ndmp_mover_get_state_reply_v2 reply;
140	ndmpd_session_t *session = ndmp_get_client_data(connection);
141
142	reply.error = NDMP_NO_ERR;
143	reply.state = session->ns_mover.md_state;
144	reply.pause_reason = session->ns_mover.md_pause_reason;
145	reply.halt_reason = session->ns_mover.md_halt_reason;
146	reply.record_size = session->ns_mover.md_record_size;
147	reply.record_num = session->ns_mover.md_record_num;
148	reply.data_written =
149	    long_long_to_quad(session->ns_mover.md_data_written);
150	reply.seek_position =
151	    long_long_to_quad(session->ns_mover.md_seek_position);
152	reply.bytes_left_to_read =
153	    long_long_to_quad(session->ns_mover.md_bytes_left_to_read);
154	reply.window_offset =
155	    long_long_to_quad(session->ns_mover.md_window_offset);
156	reply.window_length =
157	    long_long_to_quad(session->ns_mover.md_window_length);
158
159	ndmp_send_reply(connection, (void *) &reply,
160	    "sending tape_get_state reply");
161}
162
163
164/*
165 * ndmpd_mover_listen_v2
166 *
167 * This handler handles mover_listen requests.
168 *
169 * Parameters:
170 *   connection (input) - connection handle.
171 *   body       (input) - request message body.
172 *
173 * Returns:
174 *   void
175 */
176void
177ndmpd_mover_listen_v2(ndmp_connection_t *connection, void *body)
178{
179	ndmp_mover_listen_request_v2 *request;
180	ndmp_mover_listen_reply_v2 reply;
181	ndmpd_session_t *session = ndmp_get_client_data(connection);
182	ulong_t addr;
183	ushort_t port;
184
185	request = (ndmp_mover_listen_request_v2 *)body;
186
187	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE ||
188	    session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
189		NDMP_LOG(LOG_DEBUG, "Invalid state");
190		reply.error = NDMP_ILLEGAL_STATE_ERR;
191		ndmp_send_reply(connection, (void *) &reply,
192		    "sending mover_listen reply");
193		return;
194	}
195	session->ns_mover.md_mode = request->mode;
196
197	if (request->addr_type == NDMP_ADDR_LOCAL) {
198		reply.mover.addr_type = NDMP_ADDR_LOCAL;
199	} else {
200		if (create_listen_socket_v2(session, &addr, &port) < 0) {
201			reply.error = NDMP_IO_ERR;
202			ndmp_send_reply(connection, (void *) &reply,
203			    "sending mover_listen reply");
204			return;
205		}
206		reply.mover.addr_type = NDMP_ADDR_TCP;
207		reply.mover.ndmp_mover_addr_u.addr.ip_addr = htonl(addr);
208		reply.mover.ndmp_mover_addr_u.addr.port = htons(port);
209	}
210
211	session->ns_mover.md_state = NDMP_MOVER_STATE_LISTEN;
212
213	/*
214	 * ndmp window should always set by client during restore
215	 */
216
217	/* Set the default window. */
218	session->ns_mover.md_window_offset = 0;
219	session->ns_mover.md_window_length = MAX_WINDOW_SIZE;
220	session->ns_mover.md_position = 0;
221
222	reply.error = NDMP_NO_ERR;
223	ndmp_send_reply(connection, (void *) &reply,
224	    "sending mover_listen reply");
225}
226
227
228/*
229 * ndmpd_mover_continue_v2
230 *
231 * This handler handles mover_continue requests.
232 *
233 * Parameters:
234 *   connection (input) - connection handle.
235 *   body       (input) - request message body.
236 *
237 * Returns:
238 *   void
239 */
240/*ARGSUSED*/
241void
242ndmpd_mover_continue_v2(ndmp_connection_t *connection, void *body)
243{
244	ndmp_mover_continue_reply reply;
245	ndmpd_session_t *session = ndmp_get_client_data(connection);
246
247	if (session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
248		NDMP_LOG(LOG_DEBUG, "Invalid state");
249
250		reply.error = NDMP_ILLEGAL_STATE_ERR;
251		ndmp_send_reply(connection, (void *) &reply,
252		    "sending mover_continue reply");
253		return;
254	}
255	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
256	reply.error = NDMP_NO_ERR;
257	ndmp_send_reply(connection, (void *) &reply,
258	    "sending mover_continue reply");
259}
260
261
262/*
263 * ndmpd_mover_abort_v2
264 *
265 * This handler handles mover_abort requests.
266 *
267 * Parameters:
268 *   connection (input) - connection handle.
269 *   body       (input) - request message body.
270 *
271 * Returns:
272 *   void
273 */
274/*ARGSUSED*/
275void
276ndmpd_mover_abort_v2(ndmp_connection_t *connection, void *body)
277{
278	ndmp_mover_abort_reply reply;
279	ndmpd_session_t *session = ndmp_get_client_data(connection);
280
281	if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
282	    session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
283		NDMP_LOG(LOG_DEBUG, "Invalid state");
284
285		reply.error = NDMP_ILLEGAL_STATE_ERR;
286		ndmp_send_reply(connection, (void *) &reply,
287		    "sending mover_abort reply");
288		return;
289	}
290
291	reply.error = NDMP_NO_ERR;
292	ndmp_send_reply(connection, (void *) &reply,
293	    "sending mover_abort reply");
294
295	ndmpd_mover_error(session, NDMP_MOVER_HALT_ABORTED);
296	ndmp_stop_buffer_worker(session);
297}
298
299
300/*
301 * ndmpd_mover_stop_v2
302 *
303 * This handler handles mover_stop requests.
304 *
305 * Parameters:
306 *   connection (input) - connection handle.
307 *   body       (input) - request message body.
308 *
309 * Returns:
310 *   void
311 */
312/*ARGSUSED*/
313void
314ndmpd_mover_stop_v2(ndmp_connection_t *connection, void *body)
315{
316	ndmp_mover_stop_reply reply;
317	ndmpd_session_t *session = ndmp_get_client_data(connection);
318
319	if (session->ns_mover.md_state != NDMP_MOVER_STATE_HALTED) {
320		NDMP_LOG(LOG_DEBUG, "Invalid state");
321
322		reply.error = NDMP_ILLEGAL_STATE_ERR;
323		ndmp_send_reply(connection, (void *) &reply,
324		    "sending mover_stop reply");
325		return;
326	}
327
328	ndmp_waitfor_op(session);
329	reply.error = NDMP_NO_ERR;
330	ndmp_send_reply(connection, (void *) &reply,
331	    "sending mover_stop reply");
332
333	ndmp_lbr_cleanup(session);
334	ndmpd_mover_cleanup(session);
335	(void) ndmpd_mover_init(session);
336	(void) ndmp_lbr_init(session);
337}
338
339
340/*
341 * ndmpd_mover_set_window_v2
342 *
343 * This handler handles mover_set_window requests.
344 *
345 *
346 * Parameters:
347 *   connection (input) - connection handle.
348 *   body       (input) - request message body.
349 *
350 * Returns:
351 *   void
352 */
353void
354ndmpd_mover_set_window_v2(ndmp_connection_t *connection, void *body)
355{
356	ndmp_mover_set_window_request *request;
357	ndmp_mover_set_window_reply reply;
358	ndmpd_session_t *session = ndmp_get_client_data(connection);
359
360	request = (ndmp_mover_set_window_request *) body;
361
362	/*
363	 * The NDMPv2 specification states that "a window can be set only
364	 * when in the listen or paused state."
365	 *
366	 * See the comment in ndmpd_mover_set_window_v3 regarding the reason for
367	 * allowing it in the idle state as well.
368	 */
369	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE &&
370	    session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED &&
371	    session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN) {
372		reply.error = NDMP_ILLEGAL_STATE_ERR;
373		NDMP_LOG(LOG_DEBUG, "Invalid state %d",
374		    session->ns_mover.md_state);
375	} else {
376		if (quad_to_long_long(request->length) == 0) {
377			reply.error = NDMP_ILLEGAL_ARGS_ERR;
378			NDMP_LOG(LOG_DEBUG, "Invalid window size %d",
379			    quad_to_long_long(request->length));
380		} else {
381			reply.error = NDMP_NO_ERR;
382			session->ns_mover.md_window_offset =
383			    quad_to_long_long(request->offset);
384			session->ns_mover.md_window_length =
385			    quad_to_long_long(request->length);
386			session->ns_mover.md_position =
387			    session->ns_mover.md_window_offset;
388		}
389	}
390
391	ndmp_send_reply(connection, (void *) &reply,
392	    "sending mover_set_window reply");
393}
394
395
396/*
397 * ndmpd_mover_read_v2
398 *
399 * This handler handles mover_read requests. If the requested offset is
400 * outside of the current window, the mover is paused and a notify_mover_paused
401 * request is sent notifying the client that a seek is required. If the
402 * requested offest is within the window but not within the current record,
403 * then the tape is positioned to the record containing the requested offest.
404 * The requested amount of data is then read from the tape device and written
405 * to the data connection.
406 *
407 * Parameters:
408 *   connection (input) - connection handle.
409 *   body       (input) - request message body.
410 *
411 * Returns:
412 *   void
413 */
414void
415ndmpd_mover_read_v2(ndmp_connection_t *connection, void *body)
416{
417	ndmp_mover_read_request *request = (ndmp_mover_read_request *) body;
418	ndmp_mover_read_reply reply;
419	ndmpd_session_t *session = ndmp_get_client_data(connection);
420	int err;
421
422	if (session->ns_mover.md_state != NDMP_MOVER_STATE_ACTIVE ||
423	    session->ns_mover.md_bytes_left_to_read != 0 ||
424	    session->ns_mover.md_mode != NDMP_MOVER_MODE_WRITE) {
425		NDMP_LOG(LOG_DEBUG, "Invalid state");
426		reply.error = NDMP_ILLEGAL_STATE_ERR;
427		ndmp_send_reply(connection, &reply,
428		    "sending mover_read reply");
429		return;
430	}
431	if (session->ns_tape.td_fd == -1) {
432		NDMP_LOG(LOG_DEBUG, "Tape device is not open");
433		reply.error = NDMP_DEV_NOT_OPEN_ERR;
434		ndmp_send_reply(connection, &reply,
435		    "sending mover_read reply");
436		return;
437	}
438
439	reply.error = NDMP_NO_ERR;
440	ndmp_send_reply(connection, &reply, "sending mover_read reply");
441
442	err = ndmpd_mover_seek(session, quad_to_long_long(request->offset),
443	    quad_to_long_long(request->length));
444	if (err < 0) {
445		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
446		return;
447	}
448	/*
449	 * Just return if we are waiting for the NDMP client to
450	 * complete the seek.
451	 */
452	if (err == 1)
453		return;
454
455	/*
456	 * Start the mover for restore in the 3-way backups.
457	 */
458	if (start_mover_for_restore(session) < 0)
459		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
460}
461
462
463/*
464 * ndmpd_mover_close_v2
465 *
466 * This handler handles mover_close requests.
467 *
468 * Parameters:
469 *   connection (input) - connection handle.
470 *   body       (input) - request message body.
471 *
472 * Returns:
473 *   void
474 */
475/*ARGSUSED*/
476void
477ndmpd_mover_close_v2(ndmp_connection_t *connection, void *body)
478{
479	ndmp_mover_close_reply reply;
480	ndmpd_session_t *session = ndmp_get_client_data(connection);
481
482	if (session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
483		NDMP_LOG(LOG_DEBUG, "Invalid state");
484
485		reply.error = NDMP_ILLEGAL_STATE_ERR;
486		ndmp_send_reply(connection, &reply,
487		    "sending mover_close reply");
488		return;
489	}
490	free(session->ns_mover.md_data_addr_v4.tcp_addr_v4);
491
492	reply.error = NDMP_NO_ERR;
493	ndmp_send_reply(connection, &reply, "sending mover_close reply");
494
495	ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
496}
497
498
499/*
500 * ndmpd_mover_set_record_size_v2
501 *
502 * This handler handles mover_set_record_size requests.
503 *
504 * Parameters:
505 *   connection (input) - connection handle.
506 *   body       (input) - request message body.
507 *
508 * Returns:
509 *   void
510 */
511void
512ndmpd_mover_set_record_size_v2(ndmp_connection_t *connection, void *body)
513{
514	ndmp_mover_set_record_size_request *request;
515	ndmp_mover_set_record_size_reply reply;
516	ndmpd_session_t *session = ndmp_get_client_data(connection);
517
518	request = (ndmp_mover_set_record_size_request *) body;
519
520	session->ns_mover.md_record_size = request->len;
521	session->ns_mover.md_buf = realloc(session->ns_mover.md_buf,
522	    request->len);
523
524	reply.error = NDMP_NO_ERR;
525	ndmp_send_reply(connection, &reply,
526	    "sending mover_set_record_size reply");
527}
528
529
530/*
531 * ************************************************************************
532 * NDMP V3 HANDLERS
533 * ************************************************************************
534 */
535
536/*
537 * ndmpd_mover_get_state_v3
538 *
539 * This handler handles the ndmp_mover_get_state_request.
540 * Status information for the mover state machine is returned.
541 *
542 * Parameters:
543 *   connection (input) - connection handle.
544 *   body       (input) - request message body.
545 *
546 * Returns:
547 *   void
548 */
549/*ARGSUSED*/
550void
551ndmpd_mover_get_state_v3(ndmp_connection_t *connection, void *body)
552{
553	ndmp_mover_get_state_reply_v3 reply;
554	ndmpd_session_t *session = ndmp_get_client_data(connection);
555
556	(void) memset((void*)&reply, 0, sizeof (reply));
557
558	reply.error = NDMP_NO_ERR;
559	reply.state = session->ns_mover.md_state;
560	reply.pause_reason = session->ns_mover.md_pause_reason;
561	reply.halt_reason = session->ns_mover.md_halt_reason;
562	reply.record_size = session->ns_mover.md_record_size;
563	reply.record_num = session->ns_mover.md_record_num;
564	reply.data_written =
565	    long_long_to_quad(session->ns_mover.md_data_written);
566	reply.seek_position =
567	    long_long_to_quad(session->ns_mover.md_seek_position);
568	reply.bytes_left_to_read =
569	    long_long_to_quad(session->ns_mover.md_bytes_left_to_read);
570	reply.window_offset =
571	    long_long_to_quad(session->ns_mover.md_window_offset);
572	reply.window_length =
573	    long_long_to_quad(session->ns_mover.md_window_length);
574	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE)
575		ndmp_copy_addr_v3(&reply.data_connection_addr,
576		    &session->ns_mover.md_data_addr);
577
578	ndmp_send_reply(connection, &reply,
579	    "sending ndmp_mover_get_state reply");
580}
581
582
583/*
584 * ndmpd_mover_listen_v3
585 *
586 * This handler handles ndmp_mover_listen_requests.
587 * A TCP/IP socket is created that is used to listen for
588 * and accept data connections initiated by a remote
589 * data server.
590 *
591 * Parameters:
592 *   connection (input) - connection handle.
593 *   body       (input) - request message body.
594 *
595 * Returns:
596 *   void
597 */
598void
599ndmpd_mover_listen_v3(ndmp_connection_t *connection, void *body)
600{
601	ndmp_mover_listen_request_v3 *request;
602	ndmp_mover_listen_reply_v3 reply;
603	ndmpd_session_t *session = ndmp_get_client_data(connection);
604	ulong_t addr;
605	ushort_t port;
606
607	request = (ndmp_mover_listen_request_v3 *)body;
608
609	(void) memset((void*)&reply, 0, sizeof (reply));
610	reply.error = NDMP_NO_ERR;
611
612	if (request->mode != NDMP_MOVER_MODE_READ &&
613	    request->mode != NDMP_MOVER_MODE_WRITE) {
614		reply.error = NDMP_ILLEGAL_ARGS_ERR;
615		NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
616	} else if (!ndmp_valid_v3addr_type(request->addr_type)) {
617		reply.error = NDMP_ILLEGAL_ARGS_ERR;
618		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
619		    request->addr_type);
620	} else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
621		reply.error = NDMP_ILLEGAL_STATE_ERR;
622		NDMP_LOG(LOG_DEBUG,
623		    "Invalid mover state to process listen request");
624	} else if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
625		reply.error = NDMP_ILLEGAL_STATE_ERR;
626		NDMP_LOG(LOG_DEBUG,
627		    "Invalid data state to process listen request");
628	} else if (session->ns_tape.td_fd == -1) {
629		reply.error = NDMP_DEV_NOT_OPEN_ERR;
630		NDMP_LOG(LOG_DEBUG, "No tape device open");
631	} else if (request->mode == NDMP_MOVER_MODE_READ &&
632	    session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
633		reply.error = NDMP_PERMISSION_ERR;
634		NDMP_LOG(LOG_ERR, "Write protected device.");
635	}
636
637	if (reply.error != NDMP_NO_ERR) {
638		ndmp_send_reply(connection, &reply,
639		    "error sending ndmp_mover_listen reply");
640		return;
641	}
642
643	switch (request->addr_type) {
644	case NDMP_ADDR_LOCAL:
645		reply.data_connection_addr.addr_type = NDMP_ADDR_LOCAL;
646		session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_LOCAL;
647		reply.error = NDMP_NO_ERR;
648		break;
649	case NDMP_ADDR_TCP:
650		if (create_listen_socket_v3(session, &addr, &port) < 0) {
651			reply.error = NDMP_IO_ERR;
652			break;
653		}
654		reply.error = NDMP_NO_ERR;
655		reply.data_connection_addr.addr_type = NDMP_ADDR_TCP;
656		reply.data_connection_addr.tcp_ip_v3 = htonl(addr);
657		reply.data_connection_addr.tcp_port_v3 = htons(port);
658		session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_TCP;
659		session->ns_mover.md_data_addr.tcp_ip_v3 = addr;
660		session->ns_mover.md_data_addr.tcp_port_v3 = ntohs(port);
661		NDMP_LOG(LOG_DEBUG, "listen_socket: %d",
662		    session->ns_mover.md_listen_sock);
663		break;
664	default:
665		reply.error = NDMP_ILLEGAL_ARGS_ERR;
666		NDMP_LOG(LOG_DEBUG, "Invalid address type: %d",
667		    request->addr_type);
668	}
669
670	if (reply.error == NDMP_NO_ERR) {
671		session->ns_mover.md_mode = request->mode;
672		session->ns_mover.md_state = NDMP_MOVER_STATE_LISTEN;
673	}
674
675	ndmp_send_reply(connection, &reply,
676	    "error sending ndmp_mover_listen reply");
677}
678
679
680/*
681 * ndmpd_mover_continue_v3
682 *
683 * This handler handles ndmp_mover_continue_requests.
684 *
685 * Parameters:
686 *   connection (input) - connection handle.
687 *   body       (input) - request message body.
688 *
689 * Returns:
690 *   void
691 */
692/*ARGSUSED*/
693void
694ndmpd_mover_continue_v3(ndmp_connection_t *connection, void *body)
695{
696	ndmp_mover_continue_reply reply;
697	ndmpd_session_t *session = ndmp_get_client_data(connection);
698	ndmp_lbr_params_t *nlp = ndmp_get_nlp(session);
699	int ret;
700
701	(void) memset((void*)&reply, 0, sizeof (reply));
702
703	if (session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
704		NDMP_LOG(LOG_DEBUG, "Invalid state");
705		reply.error = NDMP_ILLEGAL_STATE_ERR;
706		ndmp_send_reply(connection, (void *) &reply,
707		    "sending mover_continue reply");
708		return;
709	}
710
711	if (session->ns_protocol_version == NDMPV4 &&
712	    !session->ns_mover.md_pre_cond) {
713		NDMP_LOG(LOG_DEBUG, "Precondition check");
714		reply.error = NDMP_PRECONDITION_ERR;
715		ndmp_send_reply(connection, (void *) &reply,
716		    "sending mover_continue reply");
717		return;
718	}
719	/*
720	 * Restore the file handler if the mover is remote to the data
721	 * server and the handler was removed pending the continuation of a
722	 * seek request. The handler is removed in mover_data_write().
723	 */
724	if (session->ns_mover.md_pause_reason == NDMP_MOVER_PAUSE_SEEK &&
725	    session->ns_mover.md_sock != -1) {
726		/*
727		 * If we are here, it means that we needed DMA interference
728		 * for seek. We should be on the right window, so we do not
729		 * need the DMA interference anymore.
730		 * We do another seek inside the Window to move to the
731		 * exact position on the tape.
732		 * If the resore is running without DAR the pause reason should
733		 * not be seek.
734		 */
735		ret = ndmpd_mover_seek(session,
736		    session->ns_mover.md_seek_position,
737		    session->ns_mover.md_bytes_left_to_read);
738		if (ret < 0) {
739			ndmpd_mover_error(session,
740			    NDMP_MOVER_HALT_INTERNAL_ERROR);
741			return;
742		}
743
744		if (!ret) {
745			if (ndmpd_add_file_handler(session, (void*) session,
746			    session->ns_mover.md_sock, NDMPD_SELECT_MODE_WRITE,
747			    HC_MOVER, mover_data_write_v3) < 0)
748				ndmpd_mover_error(session,
749				    NDMP_MOVER_HALT_INTERNAL_ERROR);
750		} else {
751			/*
752			 * This should not happen because we should be in the
753			 * right window. This means that DMA does not follow
754			 * the V3 spec.
755			 */
756			NDMP_LOG(LOG_DEBUG, "DMA Error.");
757			ndmpd_mover_error(session,
758			    NDMP_MOVER_HALT_INTERNAL_ERROR);
759			return;
760		}
761	}
762
763	(void) mutex_lock(&nlp->nlp_mtx);
764	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
765	session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_NA;
766	/* The tape has been likely exchanged, reset tape block counter */
767	session->ns_tape.td_record_count = 0;
768	(void) cond_broadcast(&nlp->nlp_cv);
769	(void) mutex_unlock(&nlp->nlp_mtx);
770
771	reply.error = NDMP_NO_ERR;
772	ndmp_send_reply(connection, (void *) &reply,
773	    "sending mover_continue reply");
774}
775
776
777/*
778 * ndmpd_mover_abort_v3
779 *
780 * This handler handles mover_abort requests.
781 *
782 * Parameters:
783 *   connection (input) - connection handle.
784 *   body       (input) - request message body.
785 *
786 * Returns:
787 *   void
788 */
789/*ARGSUSED*/
790void
791ndmpd_mover_abort_v3(ndmp_connection_t *connection, void *body)
792{
793	ndmp_mover_abort_reply reply;
794	ndmpd_session_t *session = ndmp_get_client_data(connection);
795
796	if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
797	    session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
798		NDMP_LOG(LOG_DEBUG, "Invalid state");
799
800		reply.error = NDMP_ILLEGAL_STATE_ERR;
801		ndmp_send_reply(connection, (void *) &reply,
802		    "sending mover_abort reply");
803		return;
804	}
805
806	reply.error = NDMP_NO_ERR;
807	ndmp_send_reply(connection, (void *) &reply,
808	    "sending mover_abort reply");
809
810	ndmpd_mover_error(session, NDMP_MOVER_HALT_ABORTED);
811}
812
813
814/*
815 * ndmpd_mover_set_window_v3
816 *
817 * This handler handles mover_set_window requests.
818 *
819 *
820 * Parameters:
821 *   connection (input) - connection handle.
822 *   body       (input) - request message body.
823 *
824 * Returns:
825 *   void
826 */
827void
828ndmpd_mover_set_window_v3(ndmp_connection_t *connection, void *body)
829{
830	ndmp_mover_set_window_request *request;
831	ndmp_mover_set_window_reply reply;
832	ndmpd_session_t *session = ndmp_get_client_data(connection);
833
834	request = (ndmp_mover_set_window_request *) body;
835
836	/*
837	 * Note: The spec says that the window can be set only in the listen
838	 * and paused states.  We let this happen when mover is in the idle
839	 * state as well.  I can't rememebr which NDMP client (net_backup 4.5
840	 * or net_worker 6.1.1) forced us to do this!
841	 */
842	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE &&
843	    session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN &&
844	    session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
845		reply.error = NDMP_ILLEGAL_STATE_ERR;
846		NDMP_LOG(LOG_DEBUG, "Invalid state %d",
847		    session->ns_mover.md_state);
848	} else if (session->ns_mover.md_record_size == 0) {
849		if (session->ns_protocol_version == NDMPV4)
850			reply.error = NDMP_PRECONDITION_ERR;
851		else
852			reply.error = NDMP_ILLEGAL_ARGS_ERR;
853		NDMP_LOG(LOG_DEBUG, "Invalid record size 0");
854	} else
855		reply.error = NDMP_NO_ERR;
856
857	if (quad_to_long_long(request->length) == 0) {
858		reply.error = NDMP_ILLEGAL_ARGS_ERR;
859		NDMP_LOG(LOG_DEBUG, "Invalid window size %d",
860		    quad_to_long_long(request->length));
861	}
862
863	if (reply.error != NDMP_NO_ERR) {
864		ndmp_send_reply(connection, (void *) &reply,
865		    "sending mover_set_window_v3 reply");
866		return;
867	}
868
869	session->ns_mover.md_pre_cond = TRUE;
870	session->ns_mover.md_window_offset = quad_to_long_long(request->offset);
871	session->ns_mover.md_window_length = quad_to_long_long(request->length);
872
873	/*
874	 * We have to update the position for DAR. DAR needs this
875	 * information to position to the right index on tape,
876	 * especially when we span the tapes.
877	 */
878#ifdef	NO_POSITION_CHANGE
879	/*
880	 * Do not change the mover position if we are reading from
881	 * the tape.  In this way, we can use the position+window_length
882	 * to know how much we can write to a tape before pausing with
883	 * EOW reason.
884	 */
885	if (session->ns_mover.md_mode != NDMP_MOVER_MODE_WRITE)
886#endif	/* NO_POSITION_CHANGE */
887		session->ns_mover.md_position =
888		    session->ns_mover.md_window_offset;
889
890	ndmp_send_reply(connection, (void *) &reply,
891	    "sending mover_set_window_v3 reply");
892}
893
894
895/*
896 * ndmpd_mover_read_v3
897 *
898 * This handler handles ndmp_mover_read_requests.
899 * If the requested offset is outside of the current window, the mover
900 * is paused and a notify_mover_paused request is sent notifying the
901 * client that a seek is required. If the requested offest is within
902 * the window but not within the current record, then the tape is
903 * positioned to the record containing the requested offest. The requested
904 * amount of data is then read from the tape device and written to the
905 * data connection.
906 *
907 * Parameters:
908 *   connection (input) - connection handle.
909 *   body       (input) - request message body.
910 *
911 * Returns:
912 *   void
913 */
914void
915ndmpd_mover_read_v3(ndmp_connection_t *connection, void *body)
916{
917	ndmp_mover_read_request *request = (ndmp_mover_read_request *)body;
918	ndmp_mover_read_reply reply;
919	ndmpd_session_t *session = ndmp_get_client_data(connection);
920	int err;
921
922	(void) memset((void*)&reply, 0, sizeof (reply));
923
924	if (session->ns_mover.md_state != NDMP_MOVER_STATE_ACTIVE ||
925	    session->ns_mover.md_mode != NDMP_MOVER_MODE_WRITE) {
926		reply.error = NDMP_ILLEGAL_STATE_ERR;
927		NDMP_LOG(LOG_DEBUG, "Invalid state");
928	} else if (session->ns_mover.md_bytes_left_to_read != 0) {
929		reply.error = NDMP_READ_IN_PROGRESS_ERR;
930		NDMP_LOG(LOG_DEBUG, "In progress");
931	} else if (session->ns_tape.td_fd == -1) {
932		reply.error = NDMP_DEV_NOT_OPEN_ERR;
933		NDMP_LOG(LOG_DEBUG, "Tape device is not open");
934	} else if (quad_to_long_long(request->length) == 0 ||
935	    (quad_to_long_long(request->length) == MAX_WINDOW_SIZE &&
936	    quad_to_long_long(request->offset) != 0)) {
937		reply.error = NDMP_ILLEGAL_ARGS_ERR;
938		NDMP_LOG(LOG_DEBUG, "Illegal args");
939	} else {
940		reply.error = NDMP_NO_ERR;
941	}
942
943	ndmp_send_reply(connection, (void *) &reply,
944	    "sending ndmp_mover_read_reply");
945	if (reply.error != NDMP_NO_ERR)
946		return;
947
948	err = ndmpd_mover_seek(session, quad_to_long_long(request->offset),
949	    quad_to_long_long(request->length));
950	if (err < 0) {
951		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
952		return;
953	}
954
955	/*
956	 * Just return if we are waiting for the DMA to complete the seek.
957	 */
958	if (err == 1)
959		return;
960
961	/*
962	 * Setup a handler function that will be called when
963	 * data can be written to the data connection without blocking.
964	 */
965	if (ndmpd_add_file_handler(session, (void*)session,
966	    session->ns_mover.md_sock, NDMPD_SELECT_MODE_WRITE, HC_MOVER,
967	    mover_data_write_v3) < 0) {
968		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
969		return;
970	}
971}
972
973
974/*
975 * ndmpd_mover_set_record_size_v3
976 *
977 * This handler handles mover_set_record_size requests.
978 *
979 * Parameters:
980 *   connection (input) - connection handle.
981 *   body       (input) - request message body.
982 *
983 * Returns:
984 *   void
985 */
986void
987ndmpd_mover_set_record_size_v3(ndmp_connection_t *connection, void *body)
988{
989	ndmp_mover_set_record_size_request *request;
990	ndmp_mover_set_record_size_reply reply;
991	ndmpd_session_t *session = ndmp_get_client_data(connection);
992	char *cp;
993
994	request = (ndmp_mover_set_record_size_request *) body;
995
996	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
997		reply.error = NDMP_ILLEGAL_STATE_ERR;
998		NDMP_LOG(LOG_DEBUG, "Invalid mover state %d",
999		    session->ns_mover.md_state);
1000	} else if (request->len > (unsigned int)ndmp_max_mover_recsize) {
1001		reply.error = NDMP_ILLEGAL_ARGS_ERR;
1002		NDMP_LOG(LOG_DEBUG,
1003		    "Invalid argument %d, should be > 0 and <= %d",
1004		    request->len, ndmp_max_mover_recsize);
1005	} else if (request->len == session->ns_mover.md_record_size)
1006		reply.error = NDMP_NO_ERR;
1007	else if (!(cp = realloc(session->ns_mover.md_buf, request->len))) {
1008		reply.error = NDMP_NO_MEM_ERR;
1009	} else {
1010		reply.error = NDMP_NO_ERR;
1011		session->ns_mover.md_buf = cp;
1012		session->ns_mover.md_record_size = request->len;
1013		session->ns_mover.md_window_offset = 0;
1014		session->ns_mover.md_window_length = 0;
1015	}
1016
1017	ndmp_send_reply(connection, (void *) &reply,
1018	    "sending mover_set_record_size reply");
1019}
1020
1021
1022/*
1023 * ndmpd_mover_connect_v3
1024 *   Request handler. Connects the mover to either a local
1025 *   or remote data server.
1026 *
1027 * Parameters:
1028 *   connection (input) - connection handle.
1029 *   body       (input) - request message body.
1030 *
1031 * Returns:
1032 *   void
1033 */
1034void
1035ndmpd_mover_connect_v3(ndmp_connection_t *connection, void *body)
1036{
1037	ndmp_mover_connect_request_v3 *request;
1038	ndmp_mover_connect_reply_v3 reply;
1039	ndmpd_session_t *session = ndmp_get_client_data(connection);
1040
1041	request = (ndmp_mover_connect_request_v3*)body;
1042
1043	(void) memset((void*)&reply, 0, sizeof (reply));
1044
1045	if (request->mode != NDMP_MOVER_MODE_READ &&
1046	    request->mode != NDMP_MOVER_MODE_WRITE) {
1047		reply.error = NDMP_ILLEGAL_ARGS_ERR;
1048		NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
1049	} else if (!ndmp_valid_v3addr_type(request->addr.addr_type)) {
1050		reply.error = NDMP_ILLEGAL_ARGS_ERR;
1051		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
1052		    request->addr.addr_type);
1053	} else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
1054		reply.error = NDMP_ILLEGAL_STATE_ERR;
1055		NDMP_LOG(LOG_DEBUG, "Invalid state %d: mover is not idle",
1056		    session->ns_mover.md_state);
1057	} else if (session->ns_tape.td_fd == -1) {
1058		reply.error = NDMP_DEV_NOT_OPEN_ERR;
1059		NDMP_LOG(LOG_DEBUG, "No tape device open");
1060	} else if (request->mode == NDMP_MOVER_MODE_READ &&
1061	    session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
1062		reply.error = NDMP_WRITE_PROTECT_ERR;
1063		NDMP_LOG(LOG_ERR, "Write protected device.");
1064	} else
1065		reply.error = NDMP_NO_ERR;
1066
1067	if (reply.error != NDMP_NO_ERR) {
1068		ndmp_send_reply(connection, (void *) &reply,
1069		    "sending ndmp_mover_connect reply");
1070		return;
1071	}
1072
1073	switch (request->addr.addr_type) {
1074	case NDMP_ADDR_LOCAL:
1075		/*
1076		 * Verify that the data server is listening for a
1077		 * local connection.
1078		 */
1079		if (session->ns_data.dd_state != NDMP_DATA_STATE_LISTEN ||
1080		    session->ns_data.dd_listen_sock != -1) {
1081			NDMP_LOG(LOG_DEBUG,
1082			    "Data server is not in local listen state");
1083			reply.error = NDMP_ILLEGAL_STATE_ERR;
1084		} else
1085			session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
1086		break;
1087
1088	case NDMP_ADDR_TCP:
1089		reply.error = mover_connect_sock(session, request->mode,
1090		    request->addr.tcp_ip_v3, request->addr.tcp_port_v3);
1091		break;
1092
1093	default:
1094		reply.error = NDMP_ILLEGAL_ARGS_ERR;
1095		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
1096		    request->addr.addr_type);
1097	}
1098
1099	if (reply.error == NDMP_NO_ERR) {
1100		session->ns_mover.md_data_addr.addr_type =
1101		    request->addr.addr_type;
1102		session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
1103		session->ns_mover.md_mode = request->mode;
1104	}
1105
1106	ndmp_send_reply(connection, (void *) &reply,
1107	    "sending ndmp_mover_connect reply");
1108}
1109
1110
1111/*
1112 * ************************************************************************
1113 * NDMP V4 HANDLERS
1114 * ************************************************************************
1115 */
1116
1117/*
1118 * ndmpd_mover_get_state_v4
1119 *
1120 * This handler handles the ndmp_mover_get_state_request.
1121 * Status information for the mover state machine is returned.
1122 *
1123 * Parameters:
1124 *   connection (input) - connection handle.
1125 *   body       (input) - request message body.
1126 *
1127 * Returns:
1128 *   void
1129 */
1130/*ARGSUSED*/
1131void
1132ndmpd_mover_get_state_v4(ndmp_connection_t *connection, void *body)
1133{
1134	ndmp_mover_get_state_reply_v4 reply;
1135	ndmpd_session_t *session = ndmp_get_client_data(connection);
1136
1137	(void) memset((void*)&reply, 0, sizeof (reply));
1138
1139	reply.error = NDMP_NO_ERR;
1140	reply.state = session->ns_mover.md_state;
1141	reply.mode = session->ns_mover.md_mode;
1142	reply.pause_reason = session->ns_mover.md_pause_reason;
1143	reply.halt_reason = session->ns_mover.md_halt_reason;
1144	reply.record_size = session->ns_mover.md_record_size;
1145	reply.record_num = session->ns_mover.md_record_num;
1146	reply.bytes_moved =
1147	    long_long_to_quad(session->ns_mover.md_data_written);
1148	reply.seek_position =
1149	    long_long_to_quad(session->ns_mover.md_seek_position);
1150	reply.bytes_left_to_read =
1151	    long_long_to_quad(session->ns_mover.md_bytes_left_to_read);
1152	reply.window_offset =
1153	    long_long_to_quad(session->ns_mover.md_window_offset);
1154	reply.window_length =
1155	    long_long_to_quad(session->ns_mover.md_window_length);
1156	if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE)
1157		ndmp_copy_addr_v4(&reply.data_connection_addr,
1158		    &session->ns_mover.md_data_addr_v4);
1159
1160	ndmp_send_reply(connection, (void *) &reply,
1161	    "sending ndmp_mover_get_state reply");
1162	free(reply.data_connection_addr.tcp_addr_v4);
1163}
1164
1165
1166/*
1167 * ndmpd_mover_listen_v4
1168 *
1169 * This handler handles ndmp_mover_listen_requests.
1170 * A TCP/IP socket is created that is used to listen for
1171 * and accept data connections initiated by a remote
1172 * data server.
1173 *
1174 * Parameters:
1175 *   connection (input) - connection handle.
1176 *   body       (input) - request message body.
1177 *
1178 * Returns:
1179 *   void
1180 */
1181void
1182ndmpd_mover_listen_v4(ndmp_connection_t *connection, void *body)
1183{
1184	ndmp_mover_listen_request_v4 *request;
1185
1186	ndmp_mover_listen_reply_v4 reply;
1187	ndmpd_session_t *session = ndmp_get_client_data(connection);
1188	ulong_t addr;
1189	ushort_t port;
1190
1191	request = (ndmp_mover_listen_request_v4 *)body;
1192
1193	(void) memset((void*)&reply, 0, sizeof (reply));
1194	reply.error = NDMP_NO_ERR;
1195
1196	if (request->mode != NDMP_MOVER_MODE_READ &&
1197	    request->mode != NDMP_MOVER_MODE_WRITE) {
1198		reply.error = NDMP_ILLEGAL_ARGS_ERR;
1199		NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
1200	} else if (!ndmp_valid_v3addr_type(request->addr_type)) {
1201		reply.error = NDMP_ILLEGAL_ARGS_ERR;
1202		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
1203		    request->addr_type);
1204	} else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
1205		reply.error = NDMP_ILLEGAL_STATE_ERR;
1206		NDMP_LOG(LOG_DEBUG,
1207		    "Invalid mover state to process listen request");
1208	} else if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
1209		reply.error = NDMP_ILLEGAL_STATE_ERR;
1210		NDMP_LOG(LOG_DEBUG,
1211		    "Invalid data state to process listen request");
1212	} else if (session->ns_tape.td_fd == -1) {
1213		reply.error = NDMP_DEV_NOT_OPEN_ERR;
1214		NDMP_LOG(LOG_DEBUG, "No tape device open");
1215	} else if (session->ns_mover.md_record_size == 0) {
1216		reply.error = NDMP_PRECONDITION_ERR;
1217		NDMP_LOG(LOG_DEBUG, "Invalid record size 0");
1218	} else if (request->mode == NDMP_MOVER_MODE_READ &&
1219	    session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
1220		reply.error = NDMP_PERMISSION_ERR;
1221		NDMP_LOG(LOG_ERR, "Write protected device.");
1222	}
1223
1224	if (reply.error != NDMP_NO_ERR) {
1225		ndmp_send_reply(connection, (void *) &reply,
1226		    "error sending ndmp_mover_listen reply");
1227		return;
1228	}
1229
1230	switch (request->addr_type) {
1231	case NDMP_ADDR_LOCAL:
1232		reply.connect_addr.addr_type = NDMP_ADDR_LOCAL;
1233		session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_LOCAL;
1234		reply.error = NDMP_NO_ERR;
1235		break;
1236	case NDMP_ADDR_TCP:
1237		if (create_listen_socket_v3(session, &addr, &port) < 0) {
1238			reply.error = NDMP_IO_ERR;
1239			break;
1240		}
1241		reply.error = NDMP_NO_ERR;
1242
1243		session->ns_mover.md_data_addr_v4.addr_type = NDMP_ADDR_TCP;
1244		session->ns_mover.md_data_addr_v4.tcp_len_v4 = 1;
1245		session->ns_mover.md_data_addr_v4.tcp_addr_v4 =
1246		    ndmp_malloc(sizeof (ndmp_tcp_addr_v4));
1247
1248		session->ns_mover.md_data_addr_v4.tcp_ip_v4(0) = addr;
1249		session->ns_mover.md_data_addr_v4.tcp_port_v4(0) = ntohs(port);
1250
1251		ndmp_copy_addr_v4(&reply.connect_addr,
1252		    &session->ns_mover.md_data_addr_v4);
1253
1254		/* For compatibility with V3 */
1255		session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_TCP;
1256		session->ns_mover.md_data_addr.tcp_ip_v3 = addr;
1257		session->ns_mover.md_data_addr.tcp_port_v3 = ntohs(port);
1258		NDMP_LOG(LOG_DEBUG, "listen_socket: %d",
1259		    session->ns_mover.md_listen_sock);
1260		break;
1261	default:
1262		reply.error = NDMP_ILLEGAL_ARGS_ERR;
1263		NDMP_LOG(LOG_DEBUG, "Invalid address type: %d",
1264		    request->addr_type);
1265	}
1266
1267	if (reply.error == NDMP_NO_ERR) {
1268		session->ns_mover.md_mode = request->mode;
1269		session->ns_mover.md_state = NDMP_MOVER_STATE_LISTEN;
1270	}
1271
1272	ndmp_send_reply(connection, (void *) &reply,
1273	    "error sending ndmp_mover_listen reply");
1274	free(reply.connect_addr.tcp_addr_v4);
1275}
1276
1277/*
1278 * ndmpd_mover_connect_v4
1279 *   Request handler. Connects the mover to either a local
1280 *   or remote data server.
1281 *
1282 * Parameters:
1283 *   connection (input) - connection handle.
1284 *   body       (input) - request message body.
1285 *
1286 * Returns:
1287 *   void
1288 */
1289void
1290ndmpd_mover_connect_v4(ndmp_connection_t *connection, void *body)
1291{
1292	ndmp_mover_connect_request_v4 *request;
1293	ndmp_mover_connect_reply_v4 reply;
1294	ndmpd_session_t *session = ndmp_get_client_data(connection);
1295
1296	request = (ndmp_mover_connect_request_v4 *)body;
1297	(void) memset((void*)&reply, 0, sizeof (reply));
1298
1299	if (request->mode != NDMP_MOVER_MODE_READ &&
1300	    request->mode != NDMP_MOVER_MODE_WRITE) {
1301		reply.error = NDMP_ILLEGAL_ARGS_ERR;
1302		NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
1303	} else if (!ndmp_valid_v3addr_type(request->addr.addr_type)) {
1304		reply.error = NDMP_ILLEGAL_ARGS_ERR;
1305		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
1306		    request->addr.addr_type);
1307	} else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
1308		reply.error = NDMP_ILLEGAL_STATE_ERR;
1309		NDMP_LOG(LOG_DEBUG, "Invalid state %d: mover is not idle",
1310		    session->ns_mover.md_state);
1311	} else if (session->ns_tape.td_fd == -1) {
1312		reply.error = NDMP_DEV_NOT_OPEN_ERR;
1313		NDMP_LOG(LOG_DEBUG, "No tape device open");
1314	} else if (request->mode == NDMP_MOVER_MODE_READ &&
1315	    session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
1316		reply.error = NDMP_PERMISSION_ERR;
1317		NDMP_LOG(LOG_ERR, "Write protected device.");
1318	} else if (session->ns_mover.md_record_size == 0) {
1319		reply.error = NDMP_PRECONDITION_ERR;
1320		NDMP_LOG(LOG_DEBUG, "Invalid record size 0");
1321	} else
1322		reply.error = NDMP_NO_ERR;
1323
1324	if (reply.error != NDMP_NO_ERR) {
1325		ndmp_send_reply(connection, (void *) &reply,
1326		    "sending ndmp_mover_connect reply");
1327		return;
1328	}
1329
1330	switch (request->addr.addr_type) {
1331	case NDMP_ADDR_LOCAL:
1332		/*
1333		 * Verify that the data server is listening for a
1334		 * local connection.
1335		 */
1336		if (session->ns_data.dd_state != NDMP_DATA_STATE_LISTEN ||
1337		    session->ns_data.dd_listen_sock != -1) {
1338			NDMP_LOG(LOG_DEBUG,
1339			    "Data server is not in local listen state");
1340			reply.error = NDMP_ILLEGAL_STATE_ERR;
1341		} else
1342			session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
1343		break;
1344
1345	case NDMP_ADDR_TCP:
1346		reply.error = mover_connect_sock(session, request->mode,
1347		    request->addr.tcp_ip_v4(0), request->addr.tcp_port_v4(0));
1348		break;
1349
1350	default:
1351		reply.error = NDMP_ILLEGAL_ARGS_ERR;
1352		NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
1353		    request->addr.addr_type);
1354	}
1355
1356	if (reply.error == NDMP_NO_ERR) {
1357		session->ns_mover.md_data_addr.addr_type =
1358		    request->addr.addr_type;
1359		session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
1360		session->ns_mover.md_mode = request->mode;
1361	}
1362
1363	ndmp_send_reply(connection, (void *) &reply,
1364	    "sending ndmp_mover_connect reply");
1365}
1366
1367
1368
1369/*
1370 * ************************************************************************
1371 * LOCALS
1372 * ************************************************************************
1373 */
1374
1375/*
1376 * ndmpd_local_write
1377 *
1378 * Writes data to the mover.
1379 * Buffers and write data to the tape device.
1380 * A full tape record is buffered before being written.
1381 *
1382 * Parameters:
1383 *   session    (input) - session pointer.
1384 *   data       (input) - data to be written.
1385 *   length     (input) - data length.
1386 *
1387 * Returns:
1388 *   0 - data successfully written.
1389 *  -1 - error.
1390 */
1391int
1392ndmpd_local_write(ndmpd_session_t *session, char *data, ulong_t length)
1393{
1394	ulong_t count = 0;
1395	ssize_t n;
1396	ulong_t len;
1397
1398	/*
1399	 * A length of 0 indicates that any buffered data should be
1400	 * flushed to tape.
1401	 */
1402	if (length == 0) {
1403		if (session->ns_mover.md_w_index == 0)
1404			return (0);
1405
1406		(void) memset(
1407		    &session->ns_mover.md_buf[session->ns_mover.md_w_index],
1408		    0, session->ns_mover.md_record_size -
1409		    session->ns_mover.md_w_index);
1410
1411		n = mover_tape_write_v3(session, session->ns_mover.md_buf,
1412		    session->ns_mover.md_record_size);
1413		if (n <= 0) {
1414			ndmpd_mover_error(session,
1415			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
1416			    NDMP_MOVER_HALT_INTERNAL_ERROR));
1417			return (-1);
1418		}
1419		session->ns_mover.md_position += n;
1420		session->ns_mover.md_data_written +=
1421		    session->ns_mover.md_w_index;
1422		session->ns_mover.md_record_num++;
1423		session->ns_mover.md_w_index = 0;
1424		return (0);
1425	}
1426	/* Break the data into records. */
1427	while (count < length) {
1428		/*
1429		 * Determine if data needs to be buffered or
1430		 * can be written directly from user supplied location.
1431		 * We can fast path the write if there is no pending
1432		 * buffered data and there is at least a full record's worth
1433		 * of data to be written.
1434		 */
1435		if (session->ns_mover.md_w_index == 0 &&
1436		    length - count >= session->ns_mover.md_record_size) {
1437			n = mover_tape_write_v3(session, &data[count],
1438			    session->ns_mover.md_record_size);
1439			if (n <= 0) {
1440				ndmpd_mover_error(session,
1441				    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
1442				    NDMP_MOVER_HALT_INTERNAL_ERROR));
1443				return (-1);
1444			}
1445			session->ns_mover.md_position += n;
1446			session->ns_mover.md_data_written += n;
1447			session->ns_mover.md_record_num++;
1448			count += n;
1449			continue;
1450		}
1451		/* Buffer the data */
1452		len = length - count;
1453		if (len > session->ns_mover.md_record_size -
1454		    session->ns_mover.md_w_index)
1455			len = session->ns_mover.md_record_size -
1456			    session->ns_mover.md_w_index;
1457
1458		(void) memcpy(
1459		    &session->ns_mover.md_buf[session->ns_mover.md_w_index],
1460		    &data[count], len);
1461		session->ns_mover.md_w_index += len;
1462		count += len;
1463
1464		/* Write the buffer if its full */
1465		if (session->ns_mover.md_w_index ==
1466		    session->ns_mover.md_record_size) {
1467			n = mover_tape_write_v3(session,
1468			    session->ns_mover.md_buf,
1469			    session->ns_mover.md_record_size);
1470			if (n <= 0) {
1471				ndmpd_mover_error(session,
1472				    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
1473				    NDMP_MOVER_HALT_INTERNAL_ERROR));
1474				return (-1);
1475			}
1476			session->ns_mover.md_position += n;
1477			session->ns_mover.md_data_written += n;
1478			session->ns_mover.md_record_num++;
1479			session->ns_mover.md_w_index = 0;
1480		}
1481	}
1482
1483	return (0);
1484}
1485
1486
1487/*
1488 * ndmpd_remote_write
1489 *
1490 * Writes data to the remote mover.
1491 *
1492 * Parameters:
1493 *   session    (input) - session pointer.
1494 *   data       (input) - data to be written.
1495 *   length     (input) - data length.
1496 *
1497 * Returns:
1498 *   0 - data successfully written.
1499 *  -1 - error.
1500 */
1501int
1502ndmpd_remote_write(ndmpd_session_t *session, char *data, ulong_t length)
1503{
1504	ssize_t n;
1505	ulong_t count = 0;
1506
1507	while (count < length) {
1508		if (session->ns_eof == TRUE ||
1509		    session->ns_data.dd_abort == TRUE)
1510			return (-1);
1511
1512		if ((n = write(session->ns_data.dd_sock, &data[count],
1513		    length - count)) < 0) {
1514			NDMP_LOG(LOG_ERR, "Socket write error: %m.");
1515			return (-1);
1516		}
1517		count += n;
1518	}
1519
1520	return (0);
1521}
1522
1523/*
1524 * ndmpd_local_read
1525 *
1526 * Reads data from the local tape device.
1527 * Full tape records are read and buffered.
1528 *
1529 * Parameters:
1530 *   session (input) - session pointer.
1531 *   data    (input) - location to store data.
1532 *   length  (input) - data length.
1533 *
1534 * Returns:
1535 *   0 - data successfully read.
1536 *  -1 - error.
1537 *   1 - session terminated or operation aborted.
1538 */
1539int
1540ndmpd_local_read(ndmpd_session_t *session, char *data, ulong_t length)
1541{
1542	ulong_t count = 0;
1543	ssize_t n;
1544	ulong_t len;
1545	ndmp_notify_mover_paused_request pause_request;
1546
1547	/*
1548	 * Automatically increase the seek window if necessary.
1549	 * This is needed in the event the module attempts to read
1550	 * past a seek window set via a prior call to ndmpd_seek() or
1551	 * the module has not issued a seek. If no seek was issued then
1552	 * pretend that a seek was issued to read the entire tape.
1553	 */
1554	if (length > session->ns_mover.md_bytes_left_to_read) {
1555		/* ndmpd_seek() never called? */
1556		if (session->ns_data.dd_read_length == 0) {
1557			session->ns_mover.md_bytes_left_to_read = ~0LL;
1558			session->ns_data.dd_read_offset = 0LL;
1559			session->ns_data.dd_read_length = ~0LL;
1560		} else {
1561			session->ns_mover.md_bytes_left_to_read = length;
1562			session->ns_data.dd_read_offset =
1563			    session->ns_mover.md_position;
1564			session->ns_data.dd_read_length = length;
1565		}
1566	}
1567	/*
1568	 * Read as many records as necessary to satisfy the request.
1569	 */
1570	while (count < length) {
1571		/*
1572		 * If the end of the mover window has been reached,
1573		 * then notify the client that a new data window is needed.
1574		 */
1575		if (session->ns_mover.md_position >=
1576		    session->ns_mover.md_window_offset +
1577		    session->ns_mover.md_window_length) {
1578
1579			session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
1580			session->ns_mover.md_pause_reason =
1581			    NDMP_MOVER_PAUSE_SEEK;
1582			pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
1583			pause_request.seek_position =
1584			    long_long_to_quad(session->ns_mover.md_position);
1585
1586			if (ndmp_send_request(session->ns_connection,
1587			    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
1588			    (void *) &pause_request, 0) < 0) {
1589				NDMP_LOG(LOG_DEBUG,
1590				    "Sending notify_mover_paused request");
1591				ndmpd_mover_error(session,
1592				    NDMP_MOVER_HALT_INTERNAL_ERROR);
1593				return (-1);
1594			}
1595			/*
1596			 * Wait until the state is changed by
1597			 * an abort or continue request.
1598			 */
1599			if (ndmp_wait_for_mover(session) != 0)
1600				return (1);
1601		}
1602		len = length - count;
1603
1604		/*
1605		 * Prevent reading past the end of the window.
1606		 */
1607		if (len >
1608		    session->ns_mover.md_window_offset +
1609		    session->ns_mover.md_window_length -
1610		    session->ns_mover.md_position)
1611			len = session->ns_mover.md_window_offset +
1612			    session->ns_mover.md_window_length -
1613			    session->ns_mover.md_position;
1614
1615		/*
1616		 * Copy from the data buffer first.
1617		 */
1618		if (session->ns_mover.md_w_index -
1619		    session->ns_mover.md_r_index != 0) {
1620			/*
1621			 * Limit the copy to the amount of data in the buffer.
1622			 */
1623			if (len > session->ns_mover.md_w_index -
1624			    session->ns_mover.md_r_index)
1625				len = session->ns_mover.md_w_index
1626				    - session->ns_mover.md_r_index;
1627
1628			(void) memcpy((void *) &data[count],
1629			    &session->ns_mover.md_buf[session->
1630			    ns_mover.md_r_index], len);
1631			count += len;
1632			session->ns_mover.md_r_index += len;
1633			session->ns_mover.md_bytes_left_to_read -= len;
1634			session->ns_mover.md_position += len;
1635			continue;
1636		}
1637		/*
1638		 * Determine if data needs to be buffered or
1639		 * can be read directly to user supplied location.
1640		 * We can fast path the read if at least a full record
1641		 * needs to be read and there is no seek pending.
1642		 * This is done to eliminate a buffer copy.
1643		 */
1644		if (len >= session->ns_mover.md_record_size &&
1645		    session->ns_mover.md_position >=
1646		    session->ns_mover.md_seek_position) {
1647			n = tape_read(session, &data[count]);
1648			if (n <= 0) {
1649				if (n == TAPE_NO_WRITER_ERR)
1650					return (1);
1651
1652				ndmpd_mover_error(session,
1653				    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
1654				    NDMP_MOVER_HALT_INTERNAL_ERROR));
1655				return (n == 0) ? (1) : (-1);
1656			}
1657			count += n;
1658			session->ns_mover.md_bytes_left_to_read -= n;
1659			session->ns_mover.md_position += n;
1660			continue;
1661		}
1662		/* Read the next record into the buffer. */
1663		n = tape_read(session, session->ns_mover.md_buf);
1664		if (n <= 0) {
1665			if (n == TAPE_NO_WRITER_ERR)
1666				return (1);
1667
1668			ndmpd_mover_error(session,
1669			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
1670			    NDMP_MOVER_HALT_INTERNAL_ERROR));
1671			return (n == 0) ? (1) : (-1);
1672		}
1673		session->ns_mover.md_w_index = n;
1674		session->ns_mover.md_r_index = 0;
1675
1676		NDMP_LOG(LOG_DEBUG, "n: %d", n);
1677
1678		/*
1679		 * Discard data if the current data stream position is
1680		 * prior to the seek position. This is necessary if a seek
1681		 * request set the seek pointer to a position that is not a
1682		 * record boundary. The seek request handler can only position
1683		 * to the start of a record.
1684		 */
1685		if (session->ns_mover.md_position <
1686		    session->ns_mover.md_seek_position) {
1687			session->ns_mover.md_r_index =
1688			    session->ns_mover.md_seek_position -
1689			    session->ns_mover.md_position;
1690			session->ns_mover.md_position =
1691			    session->ns_mover.md_seek_position;
1692		}
1693	}
1694
1695	return (0);
1696}
1697
1698
1699/*
1700 * ndmpd_remote_read
1701 *
1702 * Reads data from the remote mover.
1703 *
1704 * Parameters:
1705 *   session (input) - session pointer.
1706 *   data    (input) - data to be written.
1707 *   length  (input) - data length.
1708 *
1709 * Returns:
1710 *   0 - data successfully read.
1711 *  -1 - error.
1712 *   1 - session terminated or operation aborted.
1713 */
1714int
1715ndmpd_remote_read(ndmpd_session_t *session, char *data, ulong_t length)
1716{
1717	ulong_t count = 0;
1718	ssize_t n;
1719	ulong_t len;
1720	ndmp_notify_data_read_request request;
1721
1722	while (count < length) {
1723		len = length - count;
1724
1725		/*
1726		 * If the end of the seek window has been reached then
1727		 * send an ndmp_read request to the client.
1728		 * The NDMP client will then send a mover_data_read request to
1729		 * the remote mover and the mover will send more data.
1730		 * This condition can occur if the module attempts to read past
1731		 * a seek window set via a prior call to ndmpd_seek() or
1732		 * the module has not issued a seek. If no seek was issued then
1733		 * pretend that a seek was issued to read the entire tape.
1734		 */
1735		if (session->ns_mover.md_bytes_left_to_read == 0) {
1736			/* ndmpd_seek() never called? */
1737			if (session->ns_data.dd_read_length == 0) {
1738				session->ns_mover.md_bytes_left_to_read = ~0LL;
1739				session->ns_data.dd_read_offset = 0LL;
1740				session->ns_data.dd_read_length = ~0LL;
1741			} else {
1742				session->ns_mover.md_bytes_left_to_read = len;
1743				session->ns_data.dd_read_offset =
1744				    session->ns_mover.md_position;
1745				session->ns_data.dd_read_length = len;
1746			}
1747
1748			request.offset =
1749			    long_long_to_quad(session->ns_data.dd_read_offset);
1750			request.length =
1751			    long_long_to_quad(session->ns_data.dd_read_length);
1752
1753			if (ndmp_send_request_lock(session->ns_connection,
1754			    NDMP_NOTIFY_DATA_READ, NDMP_NO_ERR,
1755			    (void *) &request, 0) < 0) {
1756				NDMP_LOG(LOG_DEBUG,
1757				    "Sending notify_data_read request");
1758				return (-1);
1759			}
1760		}
1761		if (session->ns_eof == TRUE ||
1762		    session->ns_data.dd_abort == TRUE)
1763			return (1);
1764
1765		/*
1766		 * If the module called ndmpd_seek() prior to reading all of the
1767		 * data that the remote mover was requested to send, then the
1768		 * excess data from the seek has to be discardd.
1769		 */
1770		if (session->ns_mover.md_discard_length != 0) {
1771			n = discard_data(session,
1772			    (ulong_t)session->ns_mover.md_discard_length);
1773			if (n < 0)
1774				return (-1);
1775			session->ns_mover.md_discard_length -= n;
1776			continue;
1777		}
1778		/*
1779		 * Don't attempt to read more data than the remote is sending.
1780		 */
1781		if (len > session->ns_mover.md_bytes_left_to_read)
1782			len = session->ns_mover.md_bytes_left_to_read;
1783
1784		NDMP_LOG(LOG_DEBUG, "len: %u", len);
1785
1786		if ((n = read(session->ns_data.dd_sock, &data[count],
1787		    len)) < 0) {
1788			NDMP_LOG(LOG_ERR, "Socket read error: %m.");
1789			return (-1);
1790		}
1791		/* read returns 0 if the connection was closed */
1792		if (n == 0)
1793			return (-1);
1794
1795		count += n;
1796		session->ns_mover.md_bytes_left_to_read -= n;
1797		session->ns_mover.md_position += n;
1798	}
1799
1800	return (0);
1801}
1802
1803/* *** ndmpd internal functions ***************************************** */
1804
1805/*
1806 * ndmpd_mover_init
1807 *
1808 * Initialize mover specific session variables.
1809 * Don't initialize variables such as record_size that need to
1810 * persist across data operations. A client may open a connection and
1811 * do multiple backups after setting the record_size.
1812 *
1813 * Parameters:
1814 *   session (input) - session pointer.
1815 *
1816 * Returns:
1817 *   0 - success.
1818 *  -1 - error.
1819 */
1820int
1821ndmpd_mover_init(ndmpd_session_t *session)
1822{
1823	session->ns_mover.md_state = NDMP_MOVER_STATE_IDLE;
1824	session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_NA;
1825	session->ns_mover.md_halt_reason = NDMP_MOVER_HALT_NA;
1826	session->ns_mover.md_data_written = 0LL;
1827	session->ns_mover.md_seek_position = 0LL;
1828	session->ns_mover.md_bytes_left_to_read = 0LL;
1829	session->ns_mover.md_window_offset = 0LL;
1830	session->ns_mover.md_window_length = MAX_WINDOW_SIZE;
1831	session->ns_mover.md_position = 0LL;
1832	session->ns_mover.md_discard_length = 0;
1833	session->ns_mover.md_record_num = 0;
1834	session->ns_mover.md_record_size = 0;
1835	session->ns_mover.md_listen_sock = -1;
1836	session->ns_mover.md_pre_cond = FALSE;
1837	session->ns_mover.md_sock = -1;
1838	session->ns_mover.md_r_index = 0;
1839	session->ns_mover.md_w_index = 0;
1840	session->ns_mover.md_buf = ndmp_malloc(MAX_RECORD_SIZE);
1841	if (!session->ns_mover.md_buf)
1842		return (-1);
1843
1844	if (ndmp_get_version(session->ns_connection) == NDMPV3) {
1845		session->ns_mover.md_mode = NDMP_MOVER_MODE_READ;
1846		(void) memset(&session->ns_mover.md_data_addr, 0,
1847		    sizeof (ndmp_addr_v3));
1848	}
1849	return (0);
1850}
1851
1852
1853/*
1854 * ndmpd_mover_shut_down
1855 *
1856 * Shutdown the mover. It closes all the sockets.
1857 *
1858 * Parameters:
1859 *   session (input) - session pointer.
1860 *
1861 * Returns:
1862 *   void
1863 */
1864void
1865ndmpd_mover_shut_down(ndmpd_session_t *session)
1866{
1867	ndmp_lbr_params_t *nlp;
1868
1869	if ((nlp = ndmp_get_nlp(session)) == NULL)
1870		return;
1871
1872	(void) mutex_lock(&nlp->nlp_mtx);
1873	if (session->ns_mover.md_listen_sock != -1) {
1874		NDMP_LOG(LOG_DEBUG, "mover.listen_sock: %d",
1875		    session->ns_mover.md_listen_sock);
1876		(void) ndmpd_remove_file_handler(session,
1877		    session->ns_mover.md_listen_sock);
1878		(void) close(session->ns_mover.md_listen_sock);
1879		session->ns_mover.md_listen_sock = -1;
1880	}
1881	if (session->ns_mover.md_sock != -1) {
1882		NDMP_LOG(LOG_DEBUG, "mover.sock: %d",
1883		    session->ns_mover.md_sock);
1884		(void) ndmpd_remove_file_handler(session,
1885		    session->ns_mover.md_sock);
1886		(void) close(session->ns_mover.md_sock);
1887		session->ns_mover.md_sock = -1;
1888	}
1889	(void) cond_broadcast(&nlp->nlp_cv);
1890	(void) mutex_unlock(&nlp->nlp_mtx);
1891}
1892
1893
1894/*
1895 * ndmpd_mover_cleanup
1896 *
1897 * Parameters:
1898 *   session (input) - session pointer.
1899 *
1900 * Returns:
1901 *   void
1902 */
1903void
1904ndmpd_mover_cleanup(ndmpd_session_t *session)
1905{
1906	NDMP_FREE(session->ns_mover.md_buf);
1907}
1908
1909
1910/*
1911 * ndmpd_mover_connect
1912 *   Create a connection to the specified mover.
1913 *
1914 * Parameters:
1915 *   session (input) - session pointer
1916 *
1917 * Returns:
1918 *   error code.
1919 */
1920ndmp_error
1921ndmpd_mover_connect(ndmpd_session_t *session, ndmp_mover_mode mover_mode)
1922{
1923	ndmp_mover_addr *mover = &session->ns_data.dd_mover;
1924	struct sockaddr_in sin;
1925	int sock = -1;
1926
1927	if (mover->addr_type == NDMP_ADDR_TCP) {
1928		if (mover->ndmp_mover_addr_u.addr.ip_addr) {
1929			(void) memset((void *) &sin, 0, sizeof (sin));
1930			sin.sin_family = AF_INET;
1931			sin.sin_addr.s_addr =
1932			    htonl(mover->ndmp_mover_addr_u.addr.ip_addr);
1933			sin.sin_port =
1934			    htons(mover->ndmp_mover_addr_u.addr.port);
1935
1936			/*
1937			 * If the address type is TCP but both the address and
1938			 * the port number are zero, we have to use a different
1939			 * socket than the mover socket. This can happen when
1940			 * using NDMP disk to disk copy (AKA D2D copy).
1941			 * The NDMPCopy client will send a zero address to
1942			 * direct the server to use the mover socket as the
1943			 * data socket to receive the recovery data.
1944			 */
1945			if (sin.sin_addr.s_addr == 0 && sin.sin_port == 0) {
1946				session->ns_data.dd_sock =
1947				    session->ns_mover.md_sock;
1948				return (NDMP_NO_ERR);
1949			}
1950
1951			NDMP_LOG(LOG_DEBUG, "addr: %u port: %u",
1952			    mover->ndmp_mover_addr_u.addr.ip_addr,
1953			    (ulong_t)sin.sin_port);
1954
1955			if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
1956				NDMP_LOG(LOG_DEBUG, "Socket error: %m");
1957				return (NDMP_IO_ERR);
1958			}
1959			if (connect(sock, (struct sockaddr *)&sin,
1960			    sizeof (sin)) < 0) {
1961				NDMP_LOG(LOG_DEBUG, "Connect error: %m");
1962				(void) close(sock);
1963				return (NDMP_IO_ERR);
1964			}
1965			set_socket_options(sock);
1966		} else {
1967			if ((session->ns_mover.md_state !=
1968			    NDMP_MOVER_STATE_ACTIVE) ||
1969			    (session->ns_mover.md_sock == -1)) {
1970
1971				NDMP_LOG(LOG_DEBUG,
1972				    "Not in active  state mover"
1973				    "  state = %d or Invalid mover sock=%d",
1974				    session->ns_mover.md_state,
1975				    session->ns_mover.md_sock);
1976				return (NDMP_ILLEGAL_STATE_ERR);
1977			}
1978
1979			sock = session->ns_mover.md_sock;
1980			NDMP_LOG(LOG_DEBUG,
1981			    "session: 0x%x setting data sock fd: %d to be"
1982			    " same as listen_sock", session, sock);
1983		}
1984
1985		NDMP_LOG(LOG_DEBUG, "sock fd: %d", sock);
1986
1987		session->ns_data.dd_sock = sock;
1988
1989		NDMP_LOG(LOG_DEBUG, "data.mover_sock: %u", sock);
1990
1991		return (NDMP_NO_ERR);
1992	}
1993	/* Local mover connection. */
1994
1995	if (session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN) {
1996		NDMP_LOG(LOG_DEBUG, "Mover is not in listen state");
1997		return (NDMP_ILLEGAL_STATE_ERR);
1998	}
1999	if (session->ns_tape.td_fd == -1) {
2000		NDMP_LOG(LOG_DEBUG, "Tape device not open");
2001		return (NDMP_DEV_NOT_OPEN_ERR);
2002	}
2003	if (mover_mode == NDMP_MOVER_MODE_READ &&
2004	    session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
2005		NDMP_LOG(LOG_ERR, "Write protected device.");
2006		return (NDMP_WRITE_PROTECT_ERR);
2007	}
2008	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
2009	session->ns_mover.md_mode = mover_mode;
2010
2011	return (NDMP_NO_ERR);
2012}
2013
2014
2015
2016/*
2017 * ndmpd_mover_seek
2018 *
2019 * Seek to the requested data stream position.
2020 * If the requested offset is outside of the current window,
2021 * the mover is paused and a notify_mover_paused request is sent
2022 * notifying the client that a seek is required.
2023 * If the requested offest is within the window but not within the
2024 * current record, then the tape is positioned to the record containing
2025 * the requested offest.
2026 * The requested amount of data is then read from the tape device and
2027 * written to the data connection.
2028 *
2029 * Parameters:
2030 *   session (input) - session pointer.
2031 *   offset  (input) - data stream position to seek to.
2032 *   length  (input) - amount of data that will be read.
2033 *
2034 * Returns:
2035 *   1 - seek pending completion by the NDMP client.
2036 *   0 - seek successfully completed.
2037 *  -1 - error.
2038 */
2039int
2040ndmpd_mover_seek(ndmpd_session_t *session, u_longlong_t offset,
2041    u_longlong_t length)
2042{
2043	int ctlcmd;
2044	int ctlcnt;
2045	u_longlong_t tape_position;
2046	u_longlong_t buf_position;
2047	ndmp_notify_mover_paused_request pause_request;
2048
2049	session->ns_mover.md_seek_position = offset;
2050	session->ns_mover.md_bytes_left_to_read = length;
2051
2052	/*
2053	 * If the requested position is outside of the window,
2054	 * notify the client that a seek is required.
2055	 */
2056	if (session->ns_mover.md_seek_position <
2057	    session->ns_mover.md_window_offset ||
2058	    session->ns_mover.md_seek_position >=
2059	    session->ns_mover.md_window_offset +
2060	    session->ns_mover.md_window_length) {
2061		NDMP_LOG(LOG_DEBUG, "MOVER_PAUSE_SEEK(%llu)",
2062		    session->ns_mover.md_seek_position);
2063
2064		session->ns_mover.md_w_index = 0;
2065		session->ns_mover.md_r_index = 0;
2066
2067		session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
2068		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK;
2069		pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
2070		pause_request.seek_position = long_long_to_quad(offset);
2071
2072		if (ndmp_send_request(session->ns_connection,
2073		    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
2074		    (void *) &pause_request, 0) < 0) {
2075			NDMP_LOG(LOG_DEBUG,
2076			    "Sending notify_mover_paused request");
2077			return (-1);
2078		}
2079		return (1);
2080	}
2081	/*
2082	 * Determine the data stream position of the first byte in the
2083	 * data buffer.
2084	 */
2085	buf_position = session->ns_mover.md_position -
2086	    (session->ns_mover.md_position % session->ns_mover.md_record_size);
2087
2088	/*
2089	 * Determine the data stream position of the next byte that
2090	 * will be read from tape.
2091	 */
2092	tape_position = buf_position;
2093	if (session->ns_mover.md_w_index != 0)
2094		tape_position += session->ns_mover.md_record_size;
2095
2096	/*
2097	 * Check if requested position is for data that has been read and is
2098	 * in the buffer.
2099	 */
2100	if (offset >= buf_position && offset < tape_position) {
2101		session->ns_mover.md_position = offset;
2102		session->ns_mover.md_r_index = session->ns_mover.md_position -
2103		    buf_position;
2104
2105		NDMP_LOG(LOG_DEBUG, "pos %llu r_index %u",
2106		    session->ns_mover.md_position,
2107		    session->ns_mover.md_r_index);
2108
2109		return (0);
2110	}
2111
2112	ctlcmd = 0;
2113	if (tape_position > session->ns_mover.md_seek_position) {
2114		/* Need to seek backward. */
2115		ctlcmd = MTBSR;
2116		ctlcnt = (int)((tape_position - offset - 1)
2117		    / session->ns_mover.md_record_size) + 1;
2118		tape_position -= ((u_longlong_t)(((tape_position - offset - 1) /
2119		    session->ns_mover.md_record_size) + 1) *
2120		    (u_longlong_t)session->ns_mover.md_record_size);
2121
2122	} else if (offset >= tape_position + session->ns_mover.md_record_size) {
2123		/* Need to seek forward. */
2124		ctlcmd = MTFSR;
2125		ctlcnt = (int)((offset - tape_position)
2126		    / session->ns_mover.md_record_size);
2127		tape_position += ((u_longlong_t)(((offset - tape_position) /
2128		    session->ns_mover.md_record_size)) *
2129		    (u_longlong_t)session->ns_mover.md_record_size);
2130	}
2131	/* Reposition the tape if necessary. */
2132	if (ctlcmd) {
2133		NDMP_LOG(LOG_DEBUG, "cmd %d count %d",
2134		    ctlcmd, ctlcnt);
2135		(void) ndmp_mtioctl(session->ns_tape.td_fd, ctlcmd, ctlcnt);
2136	}
2137
2138	session->ns_mover.md_position = tape_position;
2139	session->ns_mover.md_r_index = 0;
2140	session->ns_mover.md_w_index = 0;
2141
2142	NDMP_LOG(LOG_DEBUG, "pos %llu", session->ns_mover.md_position);
2143
2144	return (0);
2145}
2146
2147
2148/* ** static functions ************************************************** */
2149
2150/*
2151 * create_listen_socket_v2
2152 *
2153 * Creates a socket for listening for accepting data connections.
2154 *
2155 * Parameters:
2156 *   session (input)  - session pointer.
2157 *   addr    (output) - location to store address of socket.
2158 *   port    (output) - location to store port of socket.
2159 *
2160 * Returns:
2161 *   0 - success.
2162 *  -1 - error.
2163 */
2164static int
2165create_listen_socket_v2(ndmpd_session_t *session, ulong_t *addr, ushort_t *port)
2166{
2167	session->ns_mover.md_listen_sock = ndmp_create_socket(addr, port);
2168	if (session->ns_mover.md_listen_sock < 0)
2169		return (-1);
2170
2171	/*
2172	 * Add a file handler for the listen socket.
2173	 * ndmpd_select will call accept_connection when a
2174	 * connection is ready to be accepted.
2175	 */
2176	if (ndmpd_add_file_handler(session, (void *) session,
2177	    session->ns_mover.md_listen_sock, NDMPD_SELECT_MODE_READ, HC_MOVER,
2178	    accept_connection) < 0) {
2179		(void) close(session->ns_mover.md_listen_sock);
2180		session->ns_mover.md_listen_sock = -1;
2181		return (-1);
2182	}
2183
2184	NDMP_LOG(LOG_DEBUG, "addr: 0x%x, port: %d", *addr, *port);
2185	return (0);
2186}
2187
2188/*
2189 * accept_connection
2190 *
2191 * Accept a data connection from a data server.
2192 * Called by ndmpd_select when a connection is pending on
2193 * the mover listen socket.
2194 *
2195 * Parameters:
2196 *   cookie  (input) - session pointer.
2197 *   fd      (input) - file descriptor.
2198 *   mode    (input) - select mode.
2199 *
2200 * Returns:
2201 *   void.
2202 */
2203/*ARGSUSED*/
2204static void
2205accept_connection(void *cookie, int fd, ulong_t mode)
2206{
2207	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
2208	struct sockaddr_in from;
2209	int from_len;
2210
2211	from_len = sizeof (from);
2212	session->ns_mover.md_sock = accept(fd, (struct sockaddr *)&from,
2213	    &from_len);
2214
2215	(void) ndmpd_remove_file_handler(session, fd);
2216	(void) close(session->ns_mover.md_listen_sock);
2217	session->ns_mover.md_listen_sock = -1;
2218
2219	if (session->ns_mover.md_sock < 0) {
2220		NDMP_LOG(LOG_DEBUG, "Accept error: %m");
2221		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_ERROR);
2222		return;
2223	}
2224	set_socket_options(session->ns_mover.md_sock);
2225
2226	NDMP_LOG(LOG_DEBUG, "sock fd: %d", session->ns_mover.md_sock);
2227
2228	if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ) {
2229		if (start_mover_for_backup(session) < 0) {
2230			ndmpd_mover_error(session,
2231			    NDMP_MOVER_HALT_INTERNAL_ERROR);
2232			return;
2233		}
2234		NDMP_LOG(LOG_DEBUG, "Backup connection established by %s:%d",
2235		    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
2236		    ntohs(from.sin_port));
2237	} else {
2238		NDMP_LOG(LOG_DEBUG, "Restore connection established by %s:%d",
2239		    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
2240		    ntohs(from.sin_port));
2241	}
2242
2243	NDMP_LOG(LOG_DEBUG, "Received connection");
2244
2245	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
2246}
2247
2248/*
2249 * tape_read
2250 *
2251 * Reads a data record from tape. Detects and handles EOT conditions.
2252 *
2253 * Parameters:
2254 *   session (input) - session pointer.
2255 *   data    (input) - location to read data to.
2256 *
2257 * Returns:
2258 *    0 - operation aborted.
2259 *   -1 - tape read error.
2260 *   otherwise - number of bytes read.
2261 */
2262static int
2263tape_read(ndmpd_session_t *session, char *data)
2264{
2265	ssize_t n;
2266	int err;
2267	int count = session->ns_mover.md_record_size;
2268
2269	for (; ; ) {
2270		n = read(session->ns_tape.td_fd, data, count);
2271		if (n < 0) {
2272			NDMP_LOG(LOG_ERR, "Tape read error: %m.");
2273			return (TAPE_READ_ERR);
2274		}
2275		NS_ADD(rtape, n);
2276
2277		if (n == 0) {
2278			if (!is_writer_running(session))
2279				return (TAPE_NO_WRITER_ERR);
2280
2281			/*
2282			 * End of media reached.
2283			 * Notify client and wait for the client to
2284			 * either abort the data operation or continue the
2285			 * operation after changing the tape.
2286			 */
2287			NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
2288			    ++ndmp_log_msg_id,
2289			    "End of tape reached. Load next tape");
2290
2291			NDMP_LOG(LOG_DEBUG,
2292			    "End of tape reached. Load next tape");
2293
2294			err = change_tape(session);
2295
2296			/* Operation aborted or connection terminated? */
2297			if (err < 0) {
2298				/*
2299				 * K.L. Go back one record if it is read
2300				 * but not used.
2301				 */
2302
2303				if (count != session->ns_mover.md_record_size) {
2304					(void) ndmp_mtioctl(
2305					    session->ns_tape.td_fd, MTBSR, 1);
2306				}
2307				return (0);
2308			}
2309			/* Retry the read from the new tape. */
2310			continue;
2311		}
2312
2313		/* Change to pass Veritas Netbackup prequal test. */
2314		data += n;
2315		count -= n;
2316		if (count <= 0) {
2317			session->ns_mover.md_record_num++;
2318			session->ns_tape.td_record_count++;
2319			return (n);
2320		}
2321	}
2322}
2323
2324/*
2325 * change_tape
2326 *
2327 * Send a notify_pause request (protocol version 1) or
2328 * notify_mover_pause request (protocol version 2) to the
2329 * NDMP client to inform
2330 * the client that a tape volume change is required.
2331 * Process messages until the data/mover operation is either aborted
2332 * or continued.
2333 *
2334 * Parameters:
2335 *   client_data (input) - session pointer.
2336 *
2337 * Returns:
2338 *   0 - operation has been continued.
2339 *  -1 - operation has been aborted.
2340 */
2341static int
2342change_tape(ndmpd_session_t *session)
2343{
2344	ndmp_notify_mover_paused_request request;
2345
2346	session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
2347
2348	if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ)
2349		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_EOM;
2350	else
2351		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_EOF;
2352
2353	request.reason = session->ns_mover.md_pause_reason;
2354	request.seek_position = long_long_to_quad(0LL);
2355
2356	NDMP_LOG(LOG_DEBUG, "ndmp_send_request: MOVER_PAUSED, reason: %d",
2357	    session->ns_mover.md_pause_reason);
2358
2359	if (ndmp_send_request(session->ns_connection,
2360	    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
2361	    (void *) &request, 0) < 0) {
2362		NDMP_LOG(LOG_DEBUG,
2363		    "Sending notify_mover_paused request");
2364		return (-1);
2365	}
2366	/*
2367	 * Wait for until the state is changed by
2368	 * an abort or continue request.
2369	 */
2370	return (ndmp_wait_for_mover(session));
2371}
2372
2373
2374/*
2375 * discard_data
2376 *
2377 * Read and discard data from the data connection.
2378 * Called when a module has called ndmpd_seek() prior to
2379 * reading all of the data from the previous seek.
2380 *
2381 * Parameters:
2382 *   session (input) - session pointer.
2383 *
2384 * Returns:
2385 *   number of bytes read and discarded.
2386 *  -1 - error.
2387 */
2388static int
2389discard_data(ndmpd_session_t *session, ulong_t length)
2390{
2391	int n;
2392	char *addr;
2393
2394	if ((addr = ndmp_malloc(length)) == NULL)
2395		return (-1);
2396
2397	/* Read and discard the data. */
2398	n = read(session->ns_mover.md_sock, addr, length);
2399	if (n < 0) {
2400		NDMP_LOG(LOG_ERR, "Socket read error: %m.");
2401		free(addr);
2402		return (-1);
2403	}
2404
2405	free(addr);
2406	return (n);
2407}
2408
2409
2410/*
2411 * mover_tape_read_one_buf
2412 *
2413 * Read one buffer from the tape. This is used by mover_tape_reader
2414 *
2415 * Parameters:
2416 *   session (input) - session pointer.
2417 *   buf (input) - buffer read
2418 *
2419 * Returns:
2420 *   0: on success
2421 *  -1: otherwise
2422 */
2423static int
2424mover_tape_read_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf)
2425{
2426	int n;
2427
2428	tlm_buffer_mark_empty(buf);
2429
2430	/*
2431	 * If the end of the mover window has been reached,
2432	 * then notify the client that a seek is needed.
2433	 * Remove the file handler to prevent this function from
2434	 * being called. The handler will be reinstalled in
2435	 * ndmpd_mover_continue.
2436	 */
2437
2438	if (session->ns_mover.md_position >=
2439	    session->ns_mover.md_window_offset +
2440	    session->ns_mover.md_window_length) {
2441		ndmp_notify_mover_paused_request pause_request;
2442
2443		NDMP_LOG(LOG_DEBUG, "end of mover window");
2444
2445		session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
2446		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK;
2447		pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
2448		pause_request.seek_position =
2449		    long_long_to_quad(session->ns_mover.md_position);
2450
2451		if (ndmp_send_request(session->ns_connection,
2452		    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
2453		    (void *) &pause_request, 0) < 0) {
2454			NDMP_LOG(LOG_DEBUG,
2455			    "Sending notify_mover_paused request");
2456			ndmpd_mover_error(session,
2457			    NDMP_MOVER_HALT_INTERNAL_ERROR);
2458		}
2459		buf->tb_errno = EIO;
2460		return (TAPE_READ_ERR);
2461	}
2462
2463	n = tape_read(session, buf->tb_buffer_data);
2464
2465	NDMP_LOG(LOG_DEBUG, "read %d bytes from tape", n);
2466
2467	if (n <= 0) {
2468		if (n < 0)
2469			ndmpd_mover_error(session,
2470			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
2471			    NDMP_MOVER_HALT_INTERNAL_ERROR));
2472		return (TAPE_READ_ERR);
2473	}
2474
2475	buf->tb_full = TRUE;
2476	buf->tb_buffer_size = session->ns_mover.md_record_size;
2477
2478	/*
2479	 * Discard data if the current data stream position is
2480	 * prior to the seek position. This is necessary if a seek
2481	 * request set the seek pointer to a position that is not a
2482	 * record boundary. The seek request handler can only position
2483	 * to the start of a record.
2484	 */
2485	if (session->ns_mover.md_position < session->ns_mover.md_seek_position)
2486		session->ns_mover.md_position =
2487		    session->ns_mover.md_seek_position;
2488
2489	return (0);
2490}
2491
2492
2493/*
2494 * mover_tape_reader
2495 *
2496 * Mover tape reader thread. It is launched when the mover is started
2497 * for restore.
2498 *
2499 * Parameters:
2500 *   session (input) - session pointer.
2501 *
2502 * Returns:
2503 *   0: on success
2504 *  -1: otherwise
2505 */
2506int
2507mover_tape_reader(ndmpd_session_t *session)
2508{
2509	int bidx;	/* buffer index */
2510	int rv;
2511	ndmp_lbr_params_t *nlp;
2512	tlm_buffer_t *buf;
2513	tlm_buffers_t *bufs;
2514	tlm_cmd_t *lcmd;	/* Local command */
2515	tlm_commands_t *cmds;	/* Commands structure */
2516
2517	if ((nlp = ndmp_get_nlp(session)) == NULL) {
2518		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2519		return (-1);
2520	}
2521
2522	cmds = &nlp->nlp_cmds;
2523	lcmd = cmds->tcs_command;
2524	bufs = lcmd->tc_buffers;
2525
2526	lcmd->tc_ref++;
2527	cmds->tcs_reader_count++;
2528
2529	/*
2530	 * Let our parent thread know that we are running.
2531	 */
2532	tlm_cmd_signal(cmds->tcs_command, TLM_TAPE_READER);
2533
2534	buf = tlm_buffer_in_buf(bufs, &bidx);
2535	while (cmds->tcs_reader == TLM_RESTORE_RUN &&
2536	    lcmd->tc_reader == TLM_RESTORE_RUN) {
2537		buf = tlm_buffer_in_buf(bufs, NULL);
2538
2539		if (buf->tb_full) {
2540			NDMP_LOG(LOG_DEBUG, "R%d", bidx);
2541			/*
2542			 * The buffer is still full, wait for the consumer
2543			 * thread to use it.
2544			 */
2545			tlm_buffer_out_buf_timed_wait(bufs, 100);
2546
2547		} else {
2548			NDMP_LOG(LOG_DEBUG, "r%d", bidx);
2549
2550			rv = mover_tape_read_one_buf(session, buf);
2551			/*
2552			 * If there was an error while reading, such as
2553			 * end of stream.
2554			 */
2555			if (rv < 0) {
2556				NDMP_LOG(LOG_DEBUG, "Exiting, rv: %d", rv);
2557				break;
2558			}
2559
2560			/*
2561			 * Can we do more buffering?
2562			 */
2563			if (is_buffer_erroneous(buf)) {
2564				NDMP_LOG(LOG_DEBUG,
2565				    "Exiting, errno: %d, eot: %d, eof: %d",
2566				    buf->tb_errno, buf->tb_eot, buf->tb_eof);
2567				break;
2568			}
2569
2570			(void) tlm_buffer_advance_in_idx(bufs);
2571			tlm_buffer_release_in_buf(bufs);
2572			bidx = bufs->tbs_buffer_in;
2573		}
2574	}
2575
2576	/* If the consumer is waiting for us, wake it up. */
2577	tlm_buffer_release_in_buf(bufs);
2578
2579	/*
2580	 * Clean up.
2581	 */
2582	cmds->tcs_reader_count--;
2583	lcmd->tc_ref--;
2584	lcmd->tc_writer = TLM_STOP;
2585	return (0);
2586}
2587
2588
2589/*
2590 * mover_socket_write_one_buf
2591 *
2592 * Write one buffer to the network socket. This is used by mover_socket_writer
2593 *
2594 * Parameters:
2595 *   session (input) - session pointer.
2596 *   buf (input) - buffer read
2597 *
2598 * Returns:
2599 *   0: on success
2600 *  -1: otherwise
2601 */
2602static int
2603mover_socket_write_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf)
2604{
2605	int n;
2606
2607	/* Write the data to the data connection. */
2608	errno = 0;
2609	n = write(session->ns_mover.md_sock, buf->tb_buffer_data,
2610	    buf->tb_buffer_size);
2611
2612	NDMP_LOG(LOG_DEBUG, "n: %d, len: %d", n, buf->tb_buffer_size);
2613
2614	if (n < 0) {
2615		NDMP_LOG(LOG_DEBUG, "n: %d, errno: %m", n);
2616		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
2617		return (-1);
2618	}
2619
2620	session->ns_mover.md_position += n;
2621	session->ns_mover.md_bytes_left_to_read -= n;
2622	tlm_buffer_mark_empty(buf);
2623
2624	/*
2625	 * If the read limit has been reached,
2626	 * then remove the file handler to prevent this
2627	 * function from getting called. The next mover_read request
2628	 * will reinstall the handler.
2629	 */
2630	if (session->ns_mover.md_bytes_left_to_read == 0) {
2631		NDMP_LOG(LOG_DEBUG, "bytes_left_to_read == 0");
2632		(void) ndmpd_remove_file_handler(session,
2633		    session->ns_mover.md_sock);
2634		return (-1);
2635	}
2636
2637	return (0);
2638}
2639
2640
2641
2642/*
2643 * mover_socket_writer
2644 *
2645 * Mover's socket writer thread. This thread sends the read buffer
2646 * from the tape to the data server through the network socket.
2647 *
2648 * Parameters:
2649 *   session (input) - session pointer.
2650 *
2651 * Returns:
2652 *   0: on success
2653 *  -1: otherwise
2654 */
2655int
2656mover_socket_writer(ndmpd_session_t *session)
2657{
2658	int bidx;	/* buffer index */
2659	ndmp_lbr_params_t *nlp;
2660	tlm_buffer_t *buf;
2661	tlm_buffers_t *bufs;
2662	tlm_cmd_t *lcmd;	/* Local command */
2663	tlm_commands_t *cmds;	/* Commands structure */
2664
2665	if ((nlp = ndmp_get_nlp(session)) == NULL) {
2666		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2667		return (-1);
2668	}
2669
2670	cmds = &nlp->nlp_cmds;
2671	lcmd = cmds->tcs_command;
2672	bufs = lcmd->tc_buffers;
2673
2674	lcmd->tc_ref++;
2675	cmds->tcs_writer_count++;
2676
2677	/*
2678	 * Let our parent thread know that we are running.
2679	 */
2680	tlm_cmd_signal(cmds->tcs_command, TLM_SOCK_WRITER);
2681
2682	bidx = bufs->tbs_buffer_out;
2683	while (cmds->tcs_writer != (int)TLM_ABORT &&
2684	    lcmd->tc_writer != (int)TLM_ABORT) {
2685		buf = &bufs->tbs_buffer[bidx];
2686
2687		if (buf->tb_full) {
2688			NDMP_LOG(LOG_DEBUG, "w%d", bidx);
2689
2690			if (mover_socket_write_one_buf(session, buf) < 0) {
2691				NDMP_LOG(LOG_DEBUG,
2692				    "mover_socket_write_one_buf() < 0");
2693				break;
2694			}
2695
2696			(void) tlm_buffer_advance_out_idx(bufs);
2697			tlm_buffer_release_out_buf(bufs);
2698			bidx = bufs->tbs_buffer_out;
2699		} else {
2700			if (lcmd->tc_writer != TLM_RESTORE_RUN) {
2701				/* No more data is coming, time to exit */
2702				NDMP_LOG(LOG_DEBUG, "Time to exit");
2703				break;
2704			}
2705			NDMP_LOG(LOG_DEBUG, "W%d", bidx);
2706			/*
2707			 * The buffer is not full, wait for the producer
2708			 * thread to fill it.
2709			 */
2710			tlm_buffer_in_buf_timed_wait(bufs, 100);
2711		}
2712	}
2713
2714	if (cmds->tcs_writer == (int)TLM_ABORT)
2715		NDMP_LOG(LOG_DEBUG, "cmds->tcs_writer == (int)TLM_ABORT");
2716	if (lcmd->tc_writer == (int)TLM_ABORT)
2717		NDMP_LOG(LOG_DEBUG, "lcmd->tc_writer == TLM_ABORT");
2718
2719	/* If the producer is waiting for us, wake it up. */
2720	tlm_buffer_release_out_buf(bufs);
2721
2722	/*
2723	 * Clean up.
2724	 */
2725	cmds->tcs_writer_count--;
2726	lcmd->tc_ref--;
2727	lcmd->tc_reader = TLM_STOP;
2728	return (0);
2729}
2730
2731
2732/*
2733 * start_mover_for_restore
2734 *
2735 * Creates the mover tape reader and network writer threads for
2736 * the mover to perform the 3-way restore.
2737 *
2738 * Parameters:
2739 *   session (input) - session pointer.
2740 *
2741 * Returns:
2742 *   0: on success
2743 *  -1: otherwise
2744 */
2745static int
2746start_mover_for_restore(ndmpd_session_t *session)
2747{
2748	ndmp_lbr_params_t *nlp;
2749	tlm_commands_t *cmds;
2750	long xfer_size;
2751	int rc;
2752
2753	if ((nlp = ndmp_get_nlp(session)) == NULL) {
2754		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2755		return (-1);
2756	}
2757
2758	cmds = &nlp->nlp_cmds;
2759	(void) memset(cmds, 0, sizeof (*cmds));
2760	cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN;
2761	xfer_size = ndmp_buffer_get_size(session);
2762	cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size);
2763	if (cmds->tcs_command == NULL)
2764		return (-1);
2765
2766	cmds->tcs_command->tc_reader = TLM_RESTORE_RUN;
2767	cmds->tcs_command->tc_writer = TLM_RESTORE_RUN;
2768
2769	/*
2770	 * We intentionnally don't wait for the threads to start since the
2771	 * reply of the request (which resulted in calling this function)
2772	 * must be sent to the client before probable errors are sent
2773	 * to the client.
2774	 */
2775	rc = pthread_create(NULL, NULL, (funct_t)mover_tape_reader, session);
2776	if (rc == 0) {
2777		tlm_cmd_wait(cmds->tcs_command, TLM_TAPE_READER);
2778	} else {
2779		NDMP_LOG(LOG_DEBUG, "Launch mover_tape_reader: %s",
2780		    strerror(rc));
2781		return (-1);
2782	}
2783
2784	rc = pthread_create(NULL, NULL, (funct_t)mover_socket_writer, session);
2785	if (rc == 0) {
2786		tlm_cmd_wait(cmds->tcs_command, TLM_SOCK_WRITER);
2787	} else {
2788		NDMP_LOG(LOG_DEBUG, "Launch mover_socket_writer: %s",
2789		    strerror(rc));
2790		return (-1);
2791	}
2792
2793	tlm_release_reader_writer_ipc(cmds->tcs_command);
2794	return (0);
2795}
2796
2797
2798/*
2799 * mover_socket_read_one_buf
2800 *
2801 * Read one buffer from the network socket for the mover. This is used
2802 * by mover_socket_reader
2803 *
2804 * Parameters:
2805 *   session (input) - session pointer.
2806 *   buf (input) - buffer read
2807 *   read_size (input) - size to be read
2808 *
2809 * Returns:
2810 *   0: on success
2811 *  -1: otherwise
2812 */
2813static int
2814mover_socket_read_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf,
2815    long read_size)
2816{
2817	int n, index;
2818	long toread;
2819
2820	tlm_buffer_mark_empty(buf);
2821	for (index = 0, toread = read_size; toread > 0; ) {
2822		errno = 0;
2823		NDMP_LOG(LOG_DEBUG, "index: %d, toread: %d", index, toread);
2824
2825		n = read(session->ns_mover.md_sock, &buf->tb_buffer_data[index],
2826		    toread);
2827		if (n == 0) {
2828			NDMP_LOG(LOG_DEBUG, "n: %d", n);
2829			break;
2830		} else if (n > 0) {
2831			NDMP_LOG(LOG_DEBUG, "n: %d", n);
2832			index += n;
2833			toread -= n;
2834		} else {
2835			buf->tb_eof = TRUE;
2836			buf->tb_errno = errno;
2837			buf->tb_buffer_size = 0;
2838			NDMP_LOG(LOG_DEBUG, "n: %d, errno: %m", n);
2839			return (-1);
2840		}
2841	}
2842
2843	if (index > 0) {
2844		buf->tb_full = TRUE;
2845		buf->tb_buffer_size = read_size;
2846		if (read_size > 0)
2847			(void) memset(&buf->tb_buffer_data[index], 0,
2848			    read_size - index);
2849	} else {
2850		buf->tb_eof = TRUE;
2851		buf->tb_buffer_size = 0;
2852	}
2853
2854	NDMP_LOG(LOG_DEBUG, "full: %d, eot: %d, eof: %d,"
2855	    " errno: %d, size: %d, data: 0x%x",
2856	    buf->tb_full, buf->tb_eot, buf->tb_eof, buf->tb_errno,
2857	    buf->tb_buffer_size, buf->tb_buffer_data);
2858
2859	return (0);
2860}
2861
2862
2863
2864/*
2865 * mover_socket_reader
2866 *
2867 * Mover socket reader thread. This is used when reading data from the
2868 * network socket for performing remote backups.
2869 *
2870 * Parameters:
2871 *   session (input) - session pointer.
2872 *
2873 * Returns:
2874 *   0: on success
2875 *  -1: otherwise
2876 */
2877int
2878mover_socket_reader(ndmpd_session_t *session)
2879{
2880	int bidx;	/* buffer index */
2881	ndmp_lbr_params_t *nlp;
2882	tlm_buffer_t *buf;
2883	tlm_buffers_t *bufs;
2884	tlm_cmd_t *lcmd;	/* Local command */
2885	tlm_commands_t *cmds;	/* Commands structure */
2886	static int nr = 0;
2887
2888	if ((nlp = ndmp_get_nlp(session)) == NULL) {
2889		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2890		return (-1);
2891	}
2892
2893	cmds = &nlp->nlp_cmds;
2894	lcmd = cmds->tcs_command;
2895	bufs = lcmd->tc_buffers;
2896
2897	lcmd->tc_ref++;
2898	cmds->tcs_reader_count++;
2899
2900	/*
2901	 * Let our parent thread know that we are running.
2902	 */
2903	tlm_cmd_signal(cmds->tcs_command, TLM_SOCK_READER);
2904
2905	bidx = bufs->tbs_buffer_in;
2906	while (cmds->tcs_reader == TLM_BACKUP_RUN &&
2907	    lcmd->tc_reader == TLM_BACKUP_RUN) {
2908		buf = &bufs->tbs_buffer[bidx];
2909
2910		if (buf->tb_full) {
2911			NDMP_LOG(LOG_DEBUG, "R%d", bidx);
2912			/*
2913			 * The buffer is still full, wait for the consumer
2914			 * thread to use it.
2915			 */
2916			tlm_buffer_out_buf_timed_wait(bufs, 100);
2917		} else {
2918			NDMP_LOG(LOG_DEBUG, "r%d, nr: %d", bidx, ++nr);
2919
2920			(void) mover_socket_read_one_buf(session, buf,
2921			    bufs->tbs_data_transfer_size);
2922
2923			/*
2924			 * Can we do more buffering?
2925			 */
2926			if (is_buffer_erroneous(buf)) {
2927				NDMP_LOG(LOG_DEBUG,
2928				    "Exiting, errno: %d, eot: %d, eof: %d",
2929				    buf->tb_errno, buf->tb_eot, buf->tb_eof);
2930				break;
2931			}
2932
2933			(void) tlm_buffer_advance_in_idx(bufs);
2934			tlm_buffer_release_in_buf(bufs);
2935			bidx = bufs->tbs_buffer_in;
2936		}
2937	}
2938
2939	if (cmds->tcs_reader != TLM_BACKUP_RUN)
2940		NDMP_LOG(LOG_DEBUG, "cmds->tcs_reader != TLM_BACKUP_RUN");
2941	if (lcmd->tc_reader != TLM_BACKUP_RUN)
2942		NDMP_LOG(LOG_DEBUG, "lcmd->tc_reader != TLM_BACKUP_RUN");
2943	NDMP_LOG(LOG_DEBUG, "nr: %d", nr);
2944
2945	/* If the consumer is waiting for us, wake it up. */
2946	tlm_buffer_release_in_buf(bufs);
2947
2948	/*
2949	 * Clean up.
2950	 */
2951	cmds->tcs_reader_count--;
2952	lcmd->tc_ref--;
2953	lcmd->tc_writer = TLM_STOP;
2954	return (0);
2955}
2956
2957
2958/*
2959 * mover_tape_writer_one_buf
2960 *
2961 * Write one buffer for the mover to the local tape device. This is
2962 * used by mover_tape_writer thread.
2963 *
2964 * Parameters:
2965 *   session (input) - session pointer.
2966 *   buf (input) - buffer read
2967 *
2968 * Returns:
2969 *   0: on success
2970 *  -1: otherwise
2971 */
2972static int
2973mover_tape_write_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf)
2974{
2975	int n;
2976
2977	NDMP_LOG(LOG_DEBUG, "full: %d, eot: %d, eof: %d,"
2978	    " errno: %d, size: %d, data: 0x%x",
2979	    buf->tb_full, buf->tb_eot, buf->tb_eof, buf->tb_errno,
2980	    buf->tb_buffer_size, buf->tb_buffer_data);
2981
2982	n = mover_tape_write_v3(session, buf->tb_buffer_data,
2983	    buf->tb_buffer_size);
2984
2985	NDMP_LOG(LOG_DEBUG, "n: %d", n);
2986
2987	if (n <= 0) {
2988		ndmpd_mover_error(session, (n == 0 ? NDMP_MOVER_HALT_ABORTED
2989		    : NDMP_MOVER_HALT_INTERNAL_ERROR));
2990		return (-1);
2991	}
2992	session->ns_mover.md_position += n;
2993	session->ns_mover.md_data_written += n;
2994	session->ns_mover.md_record_num++;
2995
2996	NDMP_LOG(LOG_DEBUG, "Calling tlm_buffer_mark_empty(buf)");
2997	tlm_buffer_mark_empty(buf);
2998
2999	return (0);
3000}
3001
3002
3003/*
3004 * mover_tape_writer
3005 *
3006 * Mover tape writer thread. This is used for performing remote backups
3007 * in a 3-way configuration. It writes the data from network socket to
3008 * the locally attached tape device.
3009 *
3010 * Parameters:
3011 *   session (input) - session pointer.
3012 *
3013 * Returns:
3014 *   0: on success
3015 *  -1: otherwise
3016 */
3017int
3018mover_tape_writer(ndmpd_session_t *session)
3019{
3020	int bidx;
3021	ndmp_lbr_params_t *nlp;
3022	tlm_buffer_t *buf;
3023	tlm_buffers_t *bufs;
3024	tlm_cmd_t *lcmd;
3025	tlm_commands_t *cmds;
3026	static int nw = 0;
3027
3028	if ((nlp = ndmp_get_nlp(session)) == NULL) {
3029		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
3030		return (-1);
3031	}
3032
3033	cmds = &nlp->nlp_cmds;
3034	lcmd = cmds->tcs_command;
3035	bufs = lcmd->tc_buffers;
3036
3037	lcmd->tc_ref++;
3038	cmds->tcs_writer_count++;
3039
3040	/*
3041	 * Let our parent thread know that we are running.
3042	 */
3043	tlm_cmd_signal(cmds->tcs_command, TLM_TAPE_WRITER);
3044
3045	bidx = bufs->tbs_buffer_out;
3046	buf = &bufs->tbs_buffer[bidx];
3047	while (cmds->tcs_writer != (int)TLM_ABORT &&
3048	    lcmd->tc_writer != (int)TLM_ABORT) {
3049		if (buf->tb_full) {
3050			NDMP_LOG(LOG_DEBUG, "w%d, nw: %d", bidx, ++nw);
3051
3052			if (mover_tape_write_one_buf(session, buf) < 0) {
3053				NDMP_LOG(LOG_DEBUG,
3054				    "mover_tape_write_one_buf() failed");
3055				break;
3056			}
3057
3058			(void) tlm_buffer_advance_out_idx(bufs);
3059			tlm_buffer_release_out_buf(bufs);
3060			bidx = bufs->tbs_buffer_out;
3061			buf = &bufs->tbs_buffer[bidx];
3062		} else {
3063			if (lcmd->tc_writer != TLM_BACKUP_RUN) {
3064				/* No more data is coming, time to exit */
3065				NDMP_LOG(LOG_DEBUG, "Time to exit");
3066				break;
3067			}
3068			NDMP_LOG(LOG_DEBUG, "W%d", bidx);
3069			/*
3070			 * The buffer is not full, wait for the producer
3071			 * thread to fill it.
3072			 */
3073			tlm_buffer_in_buf_timed_wait(bufs, 100);
3074		}
3075	}
3076
3077	if (cmds->tcs_writer == (int)TLM_ABORT)
3078		NDMP_LOG(LOG_DEBUG, "cmds->tcs_writer == TLM_ABORT");
3079	if (lcmd->tc_writer == (int)TLM_ABORT)
3080		NDMP_LOG(LOG_DEBUG, "lcmd->tc_writer == TLM_ABORT");
3081	NDMP_LOG(LOG_DEBUG, "nw: %d", nw);
3082
3083	if (buf->tb_errno == 0) {
3084		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
3085	} else {
3086		NDMP_LOG(LOG_DEBUG, "buf->tb_errno: %d", buf->tb_errno);
3087		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
3088	}
3089
3090	/* If the producer is waiting for us, wake it up. */
3091	tlm_buffer_release_out_buf(bufs);
3092
3093	/*
3094	 * Clean up.
3095	 */
3096	cmds->tcs_writer_count--;
3097	lcmd->tc_ref--;
3098	lcmd->tc_reader = TLM_STOP;
3099	return (0);
3100}
3101
3102
3103/*
3104 * start_mover_for_backup
3105 *
3106 * Starts a remote backup by running socket reader and tape
3107 * writer threads. The mover runs a remote backup in a 3-way backup
3108 * configuration.
3109 *
3110 * Parameters:
3111 *   session (input) - session pointer.
3112 *
3113 * Returns:
3114 *   0: on success
3115 *  -1: otherwise
3116 */
3117static int
3118start_mover_for_backup(ndmpd_session_t *session)
3119{
3120	ndmp_lbr_params_t *nlp;
3121	tlm_commands_t *cmds;
3122	int rc;
3123
3124	if ((nlp = ndmp_get_nlp(session)) == NULL) {
3125		NDMP_LOG(LOG_DEBUG, "nlp == NULL");
3126		return (-1);
3127	}
3128
3129	cmds = &nlp->nlp_cmds;
3130	(void) memset(cmds, 0, sizeof (*cmds));
3131	cmds->tcs_reader = cmds->tcs_writer = TLM_BACKUP_RUN;
3132	cmds->tcs_command = tlm_create_reader_writer_ipc(TRUE,
3133	    session->ns_mover.md_record_size);
3134	if (cmds->tcs_command == NULL)
3135		return (-1);
3136
3137	cmds->tcs_command->tc_reader = TLM_BACKUP_RUN;
3138	cmds->tcs_command->tc_writer = TLM_BACKUP_RUN;
3139
3140	/*
3141	 * We intentionally don't wait for the threads to start since the
3142	 * reply of the request (which resulted in calling this function)
3143	 * must be sent to the client before probable errors are sent
3144	 * to the client.
3145	 */
3146	rc = pthread_create(NULL, NULL, (funct_t)mover_socket_reader, session);
3147	if (rc == 0) {
3148		tlm_cmd_wait(cmds->tcs_command, TLM_SOCK_READER);
3149	} else {
3150		NDMP_LOG(LOG_DEBUG, "Launch mover_socket_reader: %s",
3151		    strerror(rc));
3152		return (-1);
3153	}
3154
3155	rc = pthread_create(NULL, NULL, (funct_t)mover_tape_writer, session);
3156	if (rc == 0) {
3157		tlm_cmd_wait(cmds->tcs_command, TLM_TAPE_WRITER);
3158	} else {
3159		NDMP_LOG(LOG_DEBUG, "Launch mover_tape_writer: %s",
3160		    strerror(rc));
3161		return (-1);
3162	}
3163
3164	tlm_release_reader_writer_ipc(cmds->tcs_command);
3165	return (0);
3166}
3167
3168
3169/*
3170 * is_writer_running
3171 *
3172 * Find out if the writer thread has started or not.
3173 *
3174 * Parameters:
3175 *   session (input) - session pointer.
3176 *
3177 * Returns:
3178 *   0: not started
3179 *   non-zero: started
3180 *	Note: non-zero is also returned if the backup type is
3181 *		neither TAR nor DUMP.  I.e. the is_writer_running()
3182 *		check does not apply in this case and things should
3183 * 		appear successful.
3184 */
3185static boolean_t
3186is_writer_running(ndmpd_session_t *session)
3187{
3188	boolean_t rv;
3189	ndmp_lbr_params_t *nlp;
3190
3191	if (session && (session->ns_butype > NDMP_BUTYPE_DUMP))
3192		return (1);
3193
3194	if (session == NULL)
3195		rv = 0;
3196	else if ((nlp = ndmp_get_nlp(session)) == NULL)
3197		rv = 0;
3198	else
3199		rv = (nlp->nlp_cmds.tcs_writer_count > 0);
3200
3201	return (rv);
3202}
3203
3204
3205/*
3206 * is_writer_running_v3
3207 *
3208 * Find out if the writer thread has started or not.
3209 *
3210 * Parameters:
3211 *   session (input) - session pointer.
3212 *
3213 * Returns:
3214 *   0: not started
3215 *   non-zero: started
3216 *	Note: non-zero is also returned if the backup type is
3217 *		neither TAR nor DUMP.  I.e. the is_writer_running()
3218 *		check does not apply in this case and things should
3219 * 		appear successful.
3220 */
3221static boolean_t
3222is_writer_running_v3(ndmpd_session_t *session)
3223{
3224	boolean_t rv;
3225	ndmp_lbr_params_t *nlp;
3226
3227	if (session && (session->ns_butype > NDMP_BUTYPE_DUMP))
3228		return (1);
3229
3230	if (session == NULL)
3231		rv = 0;
3232	else if (session->ns_mover.md_data_addr.addr_type == NDMP_ADDR_TCP)
3233		rv = 1;
3234	else if ((nlp = ndmp_get_nlp(session)) == NULL)
3235		rv = 0;
3236	else
3237		rv = (nlp->nlp_cmds.tcs_writer_count > 0);
3238
3239	return (rv);
3240}
3241
3242
3243/*
3244 * ndmpd_mover_error_send
3245 *
3246 * This function sends the notify message to the client.
3247 *
3248 * Parameters:
3249 *   session (input) - session pointer.
3250 *   reason  (input) - halt reason.
3251 *
3252 * Returns:
3253 *   Error code
3254 */
3255int
3256ndmpd_mover_error_send(ndmpd_session_t *session, ndmp_mover_halt_reason reason)
3257{
3258	ndmp_notify_mover_halted_request req;
3259
3260	req.reason = reason;
3261	req.text_reason = "";
3262
3263	return (ndmp_send_request(session->ns_connection,
3264	    NDMP_NOTIFY_MOVER_HALTED, NDMP_NO_ERR, (void *)&req, 0));
3265}
3266
3267
3268/*
3269 * ndmpd_mover_error_send_v4
3270 *
3271 * This function sends the notify message to the client.
3272 *
3273 * Parameters:
3274 *   session (input) - session pointer.
3275 *   reason  (input) - halt reason.
3276 *
3277 * Returns:
3278 *   Error code
3279 */
3280int
3281ndmpd_mover_error_send_v4(ndmpd_session_t *session,
3282    ndmp_mover_halt_reason reason)
3283{
3284	ndmp_notify_mover_halted_request_v4 req;
3285
3286	req.reason = reason;
3287
3288	return (ndmp_send_request(session->ns_connection,
3289	    NDMP_NOTIFY_MOVER_HALTED, NDMP_NO_ERR, (void *)&req, 0));
3290}
3291
3292
3293/*
3294 * ndmpd_mover_error
3295 *
3296 * This function is called when an unrecoverable mover error
3297 * has been detected. A notify message is sent to the client and the
3298 * mover is placed into the halted state.
3299 *
3300 * Parameters:
3301 *   session (input) - session pointer.
3302 *   reason  (input) - halt reason.
3303 *
3304 * Returns:
3305 *   void.
3306 */
3307void
3308ndmpd_mover_error(ndmpd_session_t *session, ndmp_mover_halt_reason reason)
3309{
3310	ndmp_lbr_params_t *nlp = ndmp_get_nlp(session);
3311
3312	if (session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED ||
3313	    (session->ns_protocol_version > NDMPV2 &&
3314	    session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE))
3315		return;
3316
3317	if (session->ns_protocol_version == NDMPV4) {
3318		if (ndmpd_mover_error_send_v4(session, reason) < 0)
3319			NDMP_LOG(LOG_DEBUG,
3320			    "Error sending notify_mover_halted request");
3321	} else {
3322		/* No media error in V3 */
3323		if (reason == NDMP_MOVER_HALT_MEDIA_ERROR)
3324			reason = NDMP_MOVER_HALT_INTERNAL_ERROR;
3325		if (ndmpd_mover_error_send(session, reason) < 0)
3326			NDMP_LOG(LOG_DEBUG,
3327			    "Error sending notify_mover_halted request");
3328	}
3329
3330	(void) mutex_lock(&nlp->nlp_mtx);
3331	if (session->ns_mover.md_listen_sock != -1) {
3332		(void) ndmpd_remove_file_handler(session,
3333		    session->ns_mover.md_listen_sock);
3334		(void) close(session->ns_mover.md_listen_sock);
3335		session->ns_mover.md_listen_sock = -1;
3336	}
3337	if (session->ns_mover.md_sock != -1) {
3338		(void) ndmpd_remove_file_handler(session,
3339		    session->ns_mover.md_sock);
3340		(void) close(session->ns_mover.md_sock);
3341		session->ns_mover.md_sock = -1;
3342	}
3343
3344	session->ns_mover.md_state = NDMP_MOVER_STATE_HALTED;
3345	session->ns_mover.md_halt_reason = reason;
3346	(void) cond_broadcast(&nlp->nlp_cv);
3347	(void) mutex_unlock(&nlp->nlp_mtx);
3348}
3349
3350
3351/*
3352 * mover_pause_v3
3353 *
3354 * Send an ndmp_notify_mover_paused request to the
3355 * NDMP client to inform the client that its attention is required.
3356 * Process messages until the data/mover operation is either aborted
3357 * or continued.
3358 *
3359 * Parameters:
3360 *   client_data (input) - session pointer.
3361 *   reason (input) - pause reason.
3362 *
3363 * Returns:
3364 *   0 - operation has been continued.
3365 *  -1 - operation has been aborted.
3366 */
3367static int
3368mover_pause_v3(ndmpd_session_t *session, ndmp_mover_pause_reason reason)
3369{
3370	int rv;
3371	ndmp_notify_mover_paused_request request;
3372
3373	rv = 0;
3374	session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
3375	session->ns_mover.md_pause_reason = reason;
3376	session->ns_mover.md_pre_cond = FALSE;
3377
3378	request.reason = session->ns_mover.md_pause_reason;
3379	request.seek_position =
3380	    long_long_to_quad(session->ns_mover.md_position);
3381
3382	if (ndmp_send_request(session->ns_connection, NDMP_NOTIFY_MOVER_PAUSED,
3383	    NDMP_NO_ERR, (void *)&request, 0) < 0) {
3384		NDMP_LOG(LOG_DEBUG,
3385		    "Error sending notify_mover_paused_request");
3386		return (-1);
3387	}
3388
3389	/*
3390	 * 3-way operations are single-thread.  The same thread
3391	 * should process the messages.
3392	 *
3393	 * 2-way operations are multi-thread.  The main thread
3394	 * processes the messages.  We just need to wait and
3395	 * see if the mover state changes or the operation aborts.
3396	 */
3397	if (session->ns_mover.md_data_addr.addr_type == NDMP_ADDR_TCP) {
3398		/*
3399		 * Process messages until the state is changed by
3400		 * an abort, continue, or close request .
3401		 */
3402		for (; ; ) {
3403			if (ndmpd_select(session, TRUE, HC_CLIENT) < 0)
3404				return (-1);
3405
3406			if (session->ns_eof == TRUE)
3407				return (-1);
3408
3409			switch (session->ns_mover.md_state) {
3410			case NDMP_MOVER_STATE_ACTIVE:
3411				session->ns_tape.td_record_count = 0;
3412				return (0);
3413
3414			case NDMP_MOVER_STATE_PAUSED:
3415				continue;
3416
3417			default:
3418				return (-1);
3419			}
3420		}
3421
3422	} else {
3423		if (session->ns_mover.md_data_addr.addr_type ==
3424		    NDMP_ADDR_LOCAL) {
3425			rv = ndmp_wait_for_mover(session);
3426		} else {
3427			NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
3428			    session->ns_mover.md_data_addr.addr_type);
3429			rv = -1;
3430		}
3431	}
3432
3433	return (rv);
3434}
3435
3436
3437/*
3438 * mover_tape_write_v3
3439 *
3440 * Writes a data record to tape. Detects and handles EOT conditions.
3441 *
3442 * Parameters:
3443 *   session (input) - session pointer.
3444 *   data    (input) - data to be written.
3445 *   length  (input) - length of data to be written.
3446 *
3447 * Returns:
3448 *    0 - operation aborted by client.
3449 *   -1 - error.
3450 *   otherwise - number of bytes written.
3451 */
3452static int
3453mover_tape_write_v3(ndmpd_session_t *session, char *data, ssize_t length)
3454{
3455	ssize_t n;
3456	ssize_t count = length;
3457
3458	while (count > 0) {
3459		/*
3460		 * Enforce mover window on write.
3461		 */
3462		if (session->ns_mover.md_position >=
3463		    session->ns_mover.md_window_offset +
3464		    session->ns_mover.md_window_length) {
3465			NDMP_LOG(LOG_DEBUG, "MOVER_PAUSE_EOW");
3466
3467			if (mover_pause_v3(session, NDMP_MOVER_PAUSE_EOW) < 0)
3468				/* Operation aborted or connection terminated */
3469				return (-1);
3470
3471		}
3472
3473		n = write(session->ns_tape.td_fd, data, count);
3474		if (n < 0) {
3475			NDMP_LOG(LOG_ERR, "Tape write error: %m.");
3476			return (-1);
3477		} else if (n > 0) {
3478			NS_ADD(wtape, n);
3479			count -= n;
3480			data += n;
3481			session->ns_tape.td_record_count++;
3482		}
3483
3484		/* EOM handling */
3485		if (count > 0) {
3486			struct mtget mtstatus;
3487
3488			(void) ioctl(session->ns_tape.td_fd, MTIOCGET,
3489			    &mtstatus);
3490			NDMP_LOG(LOG_DEBUG, "EOM detected (%d written bytes, "
3491			    "mover record %d, file #%d, block #%d)", n,
3492			    session->ns_tape.td_record_count,
3493			    mtstatus.mt_fileno, mtstatus.mt_blkno);
3494
3495			/*
3496			 * Notify the client to either abort the operation
3497			 * or change the tape.
3498			 */
3499			NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3500			    ++ndmp_log_msg_id,
3501			    "End of tape reached. Load next tape");
3502
3503			if (mover_pause_v3(session, NDMP_MOVER_PAUSE_EOM) < 0)
3504				/* Operation aborted or connection terminated */
3505				return (-1);
3506		}
3507	}
3508
3509	return (length);
3510}
3511
3512
3513/*
3514 * mover_tape_flush_v3
3515 *
3516 * Writes all remaining buffered data to tape. A partial record is
3517 * padded out to a full record with zeros.
3518 *
3519 * Parameters:
3520 *   session (input) - session pointer.
3521 *   data    (input) - data to be written.
3522 *   length  (input) - length of data to be written.
3523 *
3524 * Returns:
3525 *   -1 - error.
3526 *   otherwise - number of bytes written.
3527 */
3528static int
3529mover_tape_flush_v3(ndmpd_session_t *session)
3530{
3531	int n;
3532
3533	if (session->ns_mover.md_w_index == 0)
3534		return (0);
3535
3536	(void) memset((void*)&session->ns_mover.md_buf[session->
3537	    ns_mover.md_w_index], 0,
3538	    session->ns_mover.md_record_size - session->ns_mover.md_w_index);
3539
3540	n = mover_tape_write_v3(session, session->ns_mover.md_buf,
3541	    session->ns_mover.md_record_size);
3542	if (n < 0) {
3543		NDMP_LOG(LOG_ERR, "Tape write error: %m.");
3544		return (-1);
3545	}
3546
3547	session->ns_mover.md_w_index = 0;
3548	session->ns_mover.md_position += n;
3549	return (n);
3550}
3551
3552
3553/*
3554 * ndmpd_local_write_v3
3555 *
3556 * Buffers and writes data to the tape device.
3557 * A full tape record is buffered before being written.
3558 *
3559 * Parameters:
3560 *   session    (input) - session pointer.
3561 *   data       (input) - data to be written.
3562 *   length     (input) - data length.
3563 *
3564 * Returns:
3565 *   0 - data successfully written.
3566 *  -1 - error.
3567 */
3568int
3569ndmpd_local_write_v3(ndmpd_session_t *session, char *data, ulong_t length)
3570{
3571	ulong_t count = 0;
3572	ssize_t n;
3573	ulong_t len;
3574
3575	if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
3576	    session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
3577	    session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
3578		NDMP_LOG(LOG_DEBUG, "Invalid mover state to write data");
3579		return (-1);
3580	}
3581
3582	/*
3583	 * A length of 0 indicates that any buffered data should be
3584	 * flushed to tape.
3585	 */
3586	if (length == 0) {
3587		if (session->ns_mover.md_w_index == 0)
3588			return (0);
3589
3590		(void) memset((void*)&session->ns_mover.md_buf[session->
3591		    ns_mover.md_w_index], 0, session->ns_mover.md_record_size -
3592		    session->ns_mover.md_w_index);
3593
3594		n = mover_tape_write_v3(session, session->ns_mover.md_buf,
3595		    session->ns_mover.md_record_size);
3596		if (n <= 0) {
3597			ndmpd_mover_error(session,
3598			    (n == 0 ?  NDMP_MOVER_HALT_ABORTED :
3599			    NDMP_MOVER_HALT_MEDIA_ERROR));
3600			return (-1);
3601		}
3602
3603		session->ns_mover.md_position += n;
3604		session->ns_mover.md_data_written +=
3605		    session->ns_mover.md_w_index;
3606		session->ns_mover.md_record_num++;
3607		session->ns_mover.md_w_index = 0;
3608		return (0);
3609	}
3610
3611	/* Break the data into records. */
3612	while (count < length) {
3613		/*
3614		 * Determine if data needs to be buffered or
3615		 * can be written directly from user supplied location.
3616		 * We can fast path the write if there is no pending
3617		 * buffered data and there is at least a full records worth
3618		 * of data to be written.
3619		 */
3620		if (session->ns_mover.md_w_index == 0 &&
3621		    length - count >= session->ns_mover.md_record_size) {
3622			n = mover_tape_write_v3(session, &data[count],
3623			    session->ns_mover.md_record_size);
3624			if (n <= 0) {
3625				ndmpd_mover_error(session,
3626				    (n == 0 ?  NDMP_MOVER_HALT_ABORTED :
3627				    NDMP_MOVER_HALT_MEDIA_ERROR));
3628				return (-1);
3629			}
3630
3631			session->ns_mover.md_position += n;
3632			session->ns_mover.md_data_written += n;
3633			session->ns_mover.md_record_num++;
3634			count += n;
3635			continue;
3636		}
3637
3638		/* Buffer the data */
3639		len = length - count;
3640		if (len > session->ns_mover.md_record_size -
3641		    session->ns_mover.md_w_index)
3642			len = session->ns_mover.md_record_size -
3643			    session->ns_mover.md_w_index;
3644
3645		(void) memcpy(&session->ns_mover.md_buf[session->
3646		    ns_mover.md_w_index], &data[count], len);
3647		session->ns_mover.md_w_index += len;
3648		count += len;
3649
3650		/* Write the buffer if its full */
3651		if (session->ns_mover.md_w_index ==
3652		    session->ns_mover.md_record_size) {
3653			n = mover_tape_write_v3(session,
3654			    session->ns_mover.md_buf,
3655			    session->ns_mover.md_record_size);
3656			if (n <= 0) {
3657				ndmpd_mover_error(session,
3658				    (n == 0 ?  NDMP_MOVER_HALT_ABORTED :
3659				    NDMP_MOVER_HALT_MEDIA_ERROR));
3660				return (-1);
3661			}
3662
3663			session->ns_mover.md_position += n;
3664			session->ns_mover.md_data_written += n;
3665			session->ns_mover.md_record_num++;
3666			session->ns_mover.md_w_index = 0;
3667		}
3668	}
3669
3670	return (0);
3671}
3672
3673
3674/*
3675 * mover_data_read_v3
3676 *
3677 * Reads backup data from the data connection and writes the
3678 * received data to the tape device.
3679 *
3680 * Parameters:
3681 *   cookie  (input) - session pointer.
3682 *   fd      (input) - file descriptor.
3683 *   mode    (input) - select mode.
3684 *
3685 * Returns:
3686 *   void.
3687 */
3688/*ARGSUSED*/
3689static void
3690mover_data_read_v3(void *cookie, int fd, ulong_t mode)
3691{
3692	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
3693	int n;
3694	ulong_t index;
3695
3696	n = read(fd, &session->ns_mover.md_buf[session->ns_mover.md_w_index],
3697	    session->ns_mover.md_record_size - session->ns_mover.md_w_index);
3698
3699	/*
3700	 * Since this function is only called when select believes data
3701	 * is available to be read, a return of zero indicates the
3702	 * connection has been closed.
3703	 */
3704	if (n <= 0) {
3705		if (n == 0) {
3706			NDMP_LOG(LOG_DEBUG, "Data connection closed");
3707			ndmpd_mover_error(session,
3708			    NDMP_MOVER_HALT_CONNECT_CLOSED);
3709		} else {
3710			/* Socket is non-blocking, perhaps there are no data */
3711			if (errno == EAGAIN) {
3712				NDMP_LOG(LOG_ERR, "No data to read");
3713				return;
3714			}
3715
3716			NDMP_LOG(LOG_ERR, "Failed to read from socket: %m");
3717			ndmpd_mover_error(session,
3718			    NDMP_MOVER_HALT_INTERNAL_ERROR);
3719		}
3720
3721		/* Save the index since mover_tape_flush_v3 resets it. */
3722		index = session->ns_mover.md_w_index;
3723
3724		/* Flush any buffered data to tape. */
3725		if (mover_tape_flush_v3(session) > 0) {
3726			session->ns_mover.md_data_written += index;
3727			session->ns_mover.md_record_num++;
3728		}
3729
3730		return;
3731	}
3732
3733	NDMP_LOG(LOG_DEBUG, "n %d", n);
3734
3735	session->ns_mover.md_w_index += n;
3736
3737	if (session->ns_mover.md_w_index == session->ns_mover.md_record_size) {
3738		n = mover_tape_write_v3(session, session->ns_mover.md_buf,
3739		    session->ns_mover.md_record_size);
3740		if (n <= 0) {
3741			ndmpd_mover_error(session,
3742			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
3743			    NDMP_MOVER_HALT_MEDIA_ERROR));
3744			return;
3745		}
3746
3747		session->ns_mover.md_position += n;
3748		session->ns_mover.md_w_index = 0;
3749		session->ns_mover.md_data_written += n;
3750		session->ns_mover.md_record_num++;
3751	}
3752}
3753
3754/*
3755 * mover_tape_read_v3
3756 *
3757 * Reads a data record from tape. Detects and handles EOT conditions.
3758 *
3759 * Parameters:
3760 *   session (input) - session pointer.
3761 *   data    (input) - location to read data to.
3762 *
3763 * Returns:
3764 *   0 - operation aborted.
3765 *   TAPE_READ_ERR - tape read IO error.
3766 *   TAPE_NO_WRITER_ERR - no writer is running during tape read
3767 *   otherwise - number of bytes read.
3768 */
3769static int
3770mover_tape_read_v3(ndmpd_session_t *session, char *data)
3771{
3772	int pause_reason;
3773	ssize_t	 n;
3774	int err;
3775	int count;
3776
3777	count = session->ns_mover.md_record_size;
3778	while (count > 0) {
3779		pause_reason = NDMP_MOVER_PAUSE_NA;
3780
3781		n = read(session->ns_tape.td_fd, data, count);
3782		if (n < 0) {
3783			/*
3784			 * If at beginning of file and read fails with EIO,
3785			 * then it's repeated attempt to read at EOT.
3786			 */
3787			if (errno == EIO && tape_is_at_bof(session)) {
3788				NDMP_LOG(LOG_DEBUG, "Repeated read at EOT");
3789				pause_reason = NDMP_MOVER_PAUSE_EOM;
3790				NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3791				    ++ndmp_log_msg_id,
3792				    "End of tape reached. Load next tape");
3793			}
3794			/*
3795			 * According to NDMPv4 spec preferred error code when
3796			 * trying to read from blank tape is NDMP_EOM_ERR.
3797			 */
3798			else if (errno == EIO && tape_is_at_bot(session)) {
3799				NDMP_LOG(LOG_ERR,
3800				    "Blank tape detected, returning EOM");
3801				NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3802				    ++ndmp_log_msg_id,
3803				    "Blank tape. Load another tape");
3804				pause_reason = NDMP_MOVER_PAUSE_EOM;
3805			} else {
3806				NDMP_LOG(LOG_ERR, "Tape read error: %m.");
3807				return (TAPE_READ_ERR);
3808			}
3809		} else if (n > 0) {
3810			NS_ADD(rtape, n);
3811			data += n;
3812			count -= n;
3813			session->ns_tape.td_record_count++;
3814		} else {
3815			if (!is_writer_running_v3(session))
3816				return (TAPE_NO_WRITER_ERR);
3817
3818			/*
3819			 * End of file or media reached. Notify client and
3820			 * wait for the client to either abort the data
3821			 * operation or continue the operation after changing
3822			 * the tape.
3823			 */
3824			if (tape_is_at_bof(session)) {
3825				NDMP_LOG(LOG_DEBUG, "EOT detected");
3826				pause_reason = NDMP_MOVER_PAUSE_EOM;
3827				NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3828				    ++ndmp_log_msg_id, "End of medium reached");
3829			} else {
3830				NDMP_LOG(LOG_DEBUG, "EOF detected");
3831				/* reposition the tape to BOT side of FM */
3832				fm_dance(session);
3833				pause_reason = NDMP_MOVER_PAUSE_EOF;
3834				NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3835				    ++ndmp_log_msg_id, "End of file reached.");
3836			}
3837		}
3838
3839		if (pause_reason != NDMP_MOVER_PAUSE_NA) {
3840			err = mover_pause_v3(session, pause_reason);
3841
3842			/* Operation aborted or connection terminated? */
3843			if (err < 0) {
3844				return (0);
3845			}
3846			/* Retry the read from new location */
3847		}
3848	}
3849	return (session->ns_mover.md_record_size);
3850}
3851
3852
3853/*
3854 * mover_data_write_v3
3855 *
3856 * Reads backup data from the tape device and writes the
3857 * data to the data connection.
3858 * This function is called by ndmpd_select when the data connection
3859 * is ready for more data to be written.
3860 *
3861 * Parameters:
3862 *   cookie  (input) - session pointer.
3863 *   fd      (input) - file descriptor.
3864 *   mode    (input) - select mode.
3865 *
3866 * Returns:
3867 *   void.
3868 */
3869/*ARGSUSED*/
3870static void
3871mover_data_write_v3(void *cookie, int fd, ulong_t mode)
3872{
3873	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
3874	int n;
3875	ulong_t len;
3876	u_longlong_t wlen;
3877	ndmp_notify_mover_paused_request pause_request;
3878
3879	/*
3880	 * If the end of the mover window has been reached,
3881	 * then notify the client that a seek is needed.
3882	 * Remove the file handler to prevent this function from
3883	 * being called. The handler will be reinstalled in
3884	 * ndmpd_mover_continue.
3885	 */
3886	if (session->ns_mover.md_position >= session->ns_mover.md_window_offset
3887	    + session->ns_mover.md_window_length) {
3888		NDMP_LOG(LOG_DEBUG,
3889		    "MOVER_PAUSE_SEEK(%llu)", session->ns_mover.md_position);
3890
3891		session->ns_mover.md_w_index = 0;
3892		session->ns_mover.md_r_index = 0;
3893
3894		session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
3895		session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK;
3896		pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
3897		pause_request.seek_position =
3898		    long_long_to_quad(session->ns_mover.md_position);
3899		session->ns_mover.md_seek_position =
3900		    session->ns_mover.md_position;
3901
3902		(void) ndmpd_remove_file_handler(session, fd);
3903
3904		if (ndmp_send_request(session->ns_connection,
3905		    NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
3906		    (void *)&pause_request, 0) < 0) {
3907			NDMP_LOG(LOG_DEBUG,
3908			    "Sending notify_mover_paused request");
3909			ndmpd_mover_error(session,
3910			    NDMP_MOVER_HALT_INTERNAL_ERROR);
3911		}
3912		return;
3913	}
3914
3915	/*
3916	 * Read more data into the tape buffer if the buffer is empty.
3917	 */
3918	if (session->ns_mover.md_w_index == 0) {
3919		n = mover_tape_read_v3(session, session->ns_mover.md_buf);
3920
3921		NDMP_LOG(LOG_DEBUG,
3922		    "read %u bytes from tape", n);
3923
3924		if (n <= 0) {
3925			ndmpd_mover_error(session, (n == 0 ?
3926			    NDMP_MOVER_HALT_ABORTED
3927			    : NDMP_MOVER_HALT_MEDIA_ERROR));
3928			return;
3929		}
3930
3931		/*
3932		 * Discard data if the current data stream position is
3933		 * prior to the seek position. This is necessary if a seek
3934		 * request set the seek pointer to a position that is not a
3935		 * record boundary. The seek request handler can only position
3936		 * to the start of a record.
3937		 */
3938		if (session->ns_mover.md_position <
3939		    session->ns_mover.md_seek_position) {
3940			session->ns_mover.md_r_index =
3941			    session->ns_mover.md_seek_position -
3942			    session->ns_mover.md_position;
3943			session->ns_mover.md_position =
3944			    session->ns_mover.md_seek_position;
3945		}
3946
3947		session->ns_mover.md_w_index = n;
3948		session->ns_mover.md_record_num++;
3949	}
3950
3951	/*
3952	 * The limit on the total amount of data to be sent can be
3953	 * dictated by either the end of the mover window or the end of the
3954	 * seek window.
3955	 * First determine which window applies and then determine if the
3956	 * send length needs to be less than a full record to avoid
3957	 * exceeding the window.
3958	 */
3959	if (session->ns_mover.md_position +
3960	    session->ns_mover.md_bytes_left_to_read >
3961	    session->ns_mover.md_window_offset +
3962	    session->ns_mover.md_window_length)
3963		wlen = session->ns_mover.md_window_offset +
3964		    session->ns_mover.md_window_length -
3965		    session->ns_mover.md_position;
3966	else
3967		wlen = session->ns_mover.md_bytes_left_to_read;
3968
3969	NDMP_LOG(LOG_DEBUG, "wlen window restrictions: %llu", wlen);
3970
3971	/*
3972	 * Now limit the length to the amount of data in the buffer.
3973	 */
3974	if (wlen > session->ns_mover.md_w_index - session->ns_mover.md_r_index)
3975		wlen = session->ns_mover.md_w_index -
3976		    session->ns_mover.md_r_index;
3977
3978	len = wlen & 0xffffffff;
3979	NDMP_LOG(LOG_DEBUG,
3980	    "buffer restrictions: wlen %llu len %u", wlen, len);
3981
3982	/*
3983	 * Write the data to the data connection.
3984	 */
3985	n = write(session->ns_mover.md_sock,
3986	    &session->ns_mover.md_buf[session->ns_mover.md_r_index], len);
3987
3988	if (n < 0) {
3989		/* Socket is non-blocking, perhaps the write queue is full */
3990		if (errno == EAGAIN) {
3991			NDMP_LOG(LOG_ERR, "Cannot write to socket");
3992			return;
3993		}
3994		NDMP_LOG(LOG_ERR, "Failed to write to socket: %m");
3995		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
3996		return;
3997	}
3998
3999	NDMP_LOG(LOG_DEBUG,
4000	    "wrote %u of %u bytes to data connection position %llu r_index %lu",
4001	    n, len, session->ns_mover.md_position,
4002	    session->ns_mover.md_r_index);
4003
4004	session->ns_mover.md_r_index += n;
4005	session->ns_mover.md_position += n;
4006	session->ns_mover.md_bytes_left_to_read -= n;
4007
4008	/*
4009	 * If all data in the buffer has been written,
4010	 * zero the buffer indices. The next call to this function
4011	 * will read more data from the tape device into the buffer.
4012	 */
4013	if (session->ns_mover.md_r_index == session->ns_mover.md_w_index) {
4014		session->ns_mover.md_r_index = 0;
4015		session->ns_mover.md_w_index = 0;
4016	}
4017
4018	/*
4019	 * If the read limit has been reached,
4020	 * then remove the file handler to prevent this
4021	 * function from getting called. The next mover_read request
4022	 * will reinstall the handler.
4023	 */
4024	if (session->ns_mover.md_bytes_left_to_read == 0)
4025		(void) ndmpd_remove_file_handler(session, fd);
4026}
4027
4028
4029/*
4030 * accept_connection_v3
4031 *
4032 * Accept a data connection from a data server.
4033 * Called by ndmpd_select when a connection is pending on
4034 * the mover listen socket.
4035 *
4036 * Parameters:
4037 *   cookie  (input) - session pointer.
4038 *   fd      (input) - file descriptor.
4039 *   mode    (input) - select mode.
4040 *
4041 * Returns:
4042 *   void.
4043 */
4044/*ARGSUSED*/
4045static void
4046accept_connection_v3(void *cookie, int fd, ulong_t mode)
4047{
4048	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
4049	int from_len;
4050	struct sockaddr_in from;
4051
4052	from_len = sizeof (from);
4053	session->ns_mover.md_sock = accept(fd, (struct sockaddr *)&from,
4054	    &from_len);
4055
4056	NDMP_LOG(LOG_DEBUG, "sin: port %d addr %s", ntohs(from.sin_port),
4057	    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)));
4058
4059	(void) ndmpd_remove_file_handler(session, fd);
4060	(void) close(session->ns_mover.md_listen_sock);
4061	session->ns_mover.md_listen_sock = -1;
4062
4063	if (session->ns_mover.md_sock < 0) {
4064		NDMP_LOG(LOG_DEBUG, "Accept error: %m");
4065		ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_ERROR);
4066		return;
4067	}
4068
4069	/*
4070	 * Save the peer address.
4071	 */
4072	session->ns_mover.md_data_addr.tcp_ip_v3 = from.sin_addr.s_addr;
4073	session->ns_mover.md_data_addr.tcp_port_v3 = ntohs(from.sin_port);
4074
4075	/* Set the parameter of the new socket */
4076	set_socket_options(session->ns_mover.md_sock);
4077
4078	/*
4079	 * Backup/restore is handled by a callback called from main event loop,
4080	 * which reads/writes data to md_sock socket. IO on socket must be
4081	 * non-blocking, otherwise ndmpd would be unable to process other
4082	 * incoming requests.
4083	 */
4084	if (!set_socket_nonblock(session->ns_mover.md_sock)) {
4085		NDMP_LOG(LOG_ERR, "Could not set non-blocking mode "
4086		    "on socket: %m");
4087		ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
4088		return;
4089	}
4090
4091	NDMP_LOG(LOG_DEBUG, "sock fd: %d", session->ns_mover.md_sock);
4092
4093	if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ) {
4094		if (ndmpd_add_file_handler(session, (void*)session,
4095		    session->ns_mover.md_sock, NDMPD_SELECT_MODE_READ,
4096		    HC_MOVER, mover_data_read_v3) < 0) {
4097			ndmpd_mover_error(session,
4098			    NDMP_MOVER_HALT_INTERNAL_ERROR);
4099			return;
4100		}
4101		NDMP_LOG(LOG_DEBUG, "Backup connection established by %s:%d",
4102		    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
4103		    ntohs(from.sin_port));
4104	} else {
4105		NDMP_LOG(LOG_DEBUG, "Restore connection established by %s:%d",
4106		    inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
4107		    ntohs(from.sin_port));
4108	}
4109
4110	session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
4111}
4112
4113
4114/*
4115 * create_listen_socket_v3
4116 *
4117 * Creates a socket for listening for accepting data connections.
4118 *
4119 * Parameters:
4120 *   session (input)  - session pointer.
4121 *   addr    (output) - location to store address of socket.
4122 *   port    (output) - location to store port of socket.
4123 *
4124 * Returns:
4125 *   0 - success.
4126 *  -1 - error.
4127 */
4128static int
4129create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr, ushort_t *port)
4130{
4131	session->ns_mover.md_listen_sock = ndmp_create_socket(addr, port);
4132	if (session->ns_mover.md_listen_sock < 0)
4133		return (-1);
4134
4135	/*
4136	 * Add a file handler for the listen socket.
4137	 * ndmpd_select will call accept_connection when a
4138	 * connection is ready to be accepted.
4139	 */
4140	if (ndmpd_add_file_handler(session, (void *) session,
4141	    session->ns_mover.md_listen_sock, NDMPD_SELECT_MODE_READ, HC_MOVER,
4142	    accept_connection_v3) < 0) {
4143		(void) close(session->ns_mover.md_listen_sock);
4144		session->ns_mover.md_listen_sock = -1;
4145		return (-1);
4146	}
4147	NDMP_LOG(LOG_DEBUG, "IP %s port %d",
4148	    inet_ntoa(*(struct in_addr *)addr), ntohs(*port));
4149	return (0);
4150}
4151
4152
4153/*
4154 * mover_connect_sock
4155 *
4156 * Connect the mover to the specified address
4157 *
4158 * Parameters:
4159 *   session (input)  - session pointer.
4160 *   mode    (input)  - mover mode.
4161 *   addr    (output) - location to store address of socket.
4162 *   port    (output) - location to store port of socket.
4163 *
4164 * Returns:
4165 *   error code.
4166 */
4167static ndmp_error
4168mover_connect_sock(ndmpd_session_t *session, ndmp_mover_mode mode,
4169    ulong_t addr, ushort_t port)
4170{
4171	int sock;
4172
4173	sock = ndmp_connect_sock_v3(addr, port);
4174	if (sock < 0)
4175		return (NDMP_CONNECT_ERR);
4176
4177	/*
4178	 * Backup/restore is handled by a callback called from main event loop,
4179	 * which reads/writes data to md_sock socket. IO on socket must be
4180	 * non-blocking, otherwise ndmpd would be unable to process other
4181	 * incoming requests.
4182	 */
4183	if (!set_socket_nonblock(sock)) {
4184		NDMP_LOG(LOG_ERR, "Could not set non-blocking mode "
4185		    "on socket: %m");
4186		(void) close(sock);
4187		return (NDMP_CONNECT_ERR);
4188	}
4189
4190	if (mode == NDMP_MOVER_MODE_READ) {
4191		if (ndmpd_add_file_handler(session, (void*)session, sock,
4192		    NDMPD_SELECT_MODE_READ, HC_MOVER, mover_data_read_v3) < 0) {
4193			(void) close(sock);
4194			return (NDMP_CONNECT_ERR);
4195		}
4196	}
4197	session->ns_mover.md_sock = sock;
4198	session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_TCP;
4199	session->ns_mover.md_data_addr.tcp_ip_v3 = ntohl(addr);
4200	session->ns_mover.md_data_addr.tcp_port_v3 = port;
4201	return (NDMP_NO_ERR);
4202}
4203
4204
4205/*
4206 * ndmpd_local_read_v3
4207 *
4208 * Reads data from the local tape device.
4209 * Full tape records are read and buffered.
4210 *
4211 * Parameters:
4212 *   session (input) - session pointer.
4213 *   data    (input) - location to store data.
4214 *   length  (input) - data length.
4215 *
4216 * Returns:
4217 *   1 - no read error but no writer running
4218 *   0 - data successfully read.
4219 *  -1 - error.
4220 */
4221int
4222ndmpd_local_read_v3(ndmpd_session_t *session, char *data, ulong_t length)
4223{
4224	ulong_t count;
4225	ulong_t len;
4226	ssize_t n;
4227
4228	count = 0;
4229	if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
4230	    session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
4231	    session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
4232		NDMP_LOG(LOG_DEBUG, "Invalid mover state to read data");
4233		return (-1);
4234	}
4235
4236	/*
4237	 * Automatically increase the seek window if necessary.
4238	 * This is needed in the event the module attempts to read
4239	 * past a seek window set via a prior call to ndmpd_seek() or
4240	 * the module has not issued a seek. If no seek was issued then
4241	 * pretend that a seek was issued to read the entire tape.
4242	 */
4243	if (length > session->ns_mover.md_bytes_left_to_read) {
4244		/* ndmpd_seek() never called? */
4245		if (session->ns_data.dd_read_length == 0) {
4246			session->ns_mover.md_bytes_left_to_read = ~0LL;
4247			session->ns_data.dd_read_offset = 0LL;
4248			session->ns_data.dd_read_length = ~0LL;
4249		} else {
4250			session->ns_mover.md_bytes_left_to_read = length;
4251			session->ns_data.dd_read_offset =
4252			    session->ns_mover.md_position;
4253			session->ns_data.dd_read_length = length;
4254		}
4255	}
4256
4257	/*
4258	 * Read as many records as necessary to satisfy the request.
4259	 */
4260	while (count < length) {
4261		/*
4262		 * If the end of the mover window has been reached,
4263		 * then notify the client that a new data window is needed.
4264		 */
4265		if (session->ns_mover.md_position >=
4266		    session->ns_mover.md_window_offset +
4267		    session->ns_mover.md_window_length) {
4268			if (mover_pause_v3(session,
4269			    NDMP_MOVER_PAUSE_SEEK) < 0) {
4270				ndmpd_mover_error(session,
4271				    NDMP_MOVER_HALT_INTERNAL_ERROR);
4272				return (-1);
4273			}
4274			continue;
4275		}
4276
4277		len = length - count;
4278
4279		/*
4280		 * Prevent reading past the end of the window.
4281		 */
4282		if (len > session->ns_mover.md_window_offset +
4283		    session->ns_mover.md_window_length -
4284		    session->ns_mover.md_position)
4285			len = session->ns_mover.md_window_offset +
4286			    session->ns_mover.md_window_length -
4287			    session->ns_mover.md_position;
4288
4289		/*
4290		 * Copy from the data buffer first.
4291		 */
4292		if (session->ns_mover.md_w_index -
4293		    session->ns_mover.md_r_index != 0) {
4294			/*
4295			 * Limit the copy to the amount of data in the buffer.
4296			 */
4297			if (len > session->ns_mover.md_w_index -
4298			    session->ns_mover.md_r_index)
4299				len = session->ns_mover.md_w_index -
4300				    session->ns_mover.md_r_index;
4301			(void) memcpy((void*)&data[count],
4302			    &session->ns_mover.md_buf[session->
4303			    ns_mover.md_r_index], len);
4304			count += len;
4305			session->ns_mover.md_r_index += len;
4306			session->ns_mover.md_bytes_left_to_read -= len;
4307			session->ns_mover.md_position += len;
4308			continue;
4309		}
4310
4311		/*
4312		 * Determine if data needs to be buffered or
4313		 * can be read directly to user supplied location.
4314		 * We can fast path the read if at least a full record
4315		 * needs to be read and there is no seek pending.
4316		 * This is done to eliminate a buffer copy.
4317		 */
4318		if (len >= session->ns_mover.md_record_size &&
4319		    session->ns_mover.md_position >=
4320		    session->ns_mover.md_seek_position) {
4321			n = mover_tape_read_v3(session, &data[count]);
4322			if (n <= 0) {
4323				if (n == TAPE_NO_WRITER_ERR)
4324					return (1);
4325
4326				ndmpd_mover_error(session,
4327				    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
4328				    NDMP_MOVER_HALT_MEDIA_ERROR));
4329				return ((n == 0) ? 1 : -1);
4330			}
4331
4332			count += n;
4333			session->ns_mover.md_bytes_left_to_read -= n;
4334			session->ns_mover.md_position += n;
4335			session->ns_mover.md_record_num++;
4336			continue;
4337		}
4338
4339		/* Read the next record into the buffer. */
4340		n = mover_tape_read_v3(session, session->ns_mover.md_buf);
4341		if (n <= 0) {
4342			if (n == TAPE_NO_WRITER_ERR)
4343				return (1);
4344
4345			ndmpd_mover_error(session,
4346			    (n == 0 ? NDMP_MOVER_HALT_ABORTED :
4347			    NDMP_MOVER_HALT_MEDIA_ERROR));
4348			return ((n == 0) ? 1 : -1);
4349		}
4350
4351		session->ns_mover.md_w_index = n;
4352		session->ns_mover.md_r_index = 0;
4353		session->ns_mover.md_record_num++;
4354
4355		NDMP_LOG(LOG_DEBUG, "n: %d", n);
4356
4357		/*
4358		 * Discard data if the current data stream position is
4359		 * prior to the seek position. This is necessary if a seek
4360		 * request set the seek pointer to a position that is not a
4361		 * record boundary. The seek request handler can only position
4362		 * to the start of a record.
4363		 */
4364		if (session->ns_mover.md_position <
4365		    session->ns_mover.md_seek_position) {
4366			session->ns_mover.md_r_index =
4367			    session->ns_mover.md_seek_position -
4368			    session->ns_mover.md_position;
4369			session->ns_mover.md_position =
4370			    session->ns_mover.md_seek_position;
4371		}
4372	}
4373
4374	return (0);
4375}
4376