Imported Upstream version 3.2.0
[debian/amanda] / ndmp-src / ndma_comm_dispatch.c
1 /*
2  * Copyright (c) 1998,1999,2000
3  *      Traakan, Inc., Los Altos, CA
4  *      All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice unmodified, this list of conditions, and the following
11  *    disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 /*
30  * Project:  NDMJOB
31  * Ident:    $Id: $
32  *
33  * Description:
34  *      Think of ndma_dispatch_request() as a parser (like yacc(1) input).
35  *      This parses (audits) the sequence of requests. If the requests
36  *      conform to the "grammar", semantic actions are taken.
37  *
38  *      This is, admittedly, a huge source file. The idea
39  *      is to have all audits and associated errors here. This
40  *      makes review, study, comparing to the specification, and
41  *      discussion easier because we don't get balled up in
42  *      the implementation of semantics. Further, with the hope
43  *      of wide-scale deployment, revisions of this source file
44  *      can readily be integrated into derivative works without
45  *      disturbing other portions.
46  */
47
48
49 #include "ndmagents.h"
50
51
52 extern struct ndm_dispatch_version_table ndma_dispatch_version_table[];
53
54 static int              connect_open_common (struct ndm_session *sess,
55                                 struct ndmp_xa_buf *xa,
56                                 struct ndmconn *ref_conn,
57                                 int protocol_version);
58
59
60
61 int
62 ndma_dispatch_request (struct ndm_session *sess,
63   struct ndmp_xa_buf *arg_xa, struct ndmconn *ref_conn)
64 {
65         struct ndm_dispatch_request_table *drt;
66         struct ndmp_xa_buf *    xa = arg_xa;
67         struct ndmp_xa_buf      xl_xa;
68         struct reqrep_xlate *   rrxl = 0;
69         unsigned                protocol_version = ref_conn->protocol_version;
70         unsigned                msg = xa->request.header.message;
71         int                     rc;
72
73         NDMOS_MACRO_ZEROFILL (&xa->reply);
74
75         xa->reply.protocol_version = xa->request.protocol_version;
76         xa->reply.flags |= NDMNMB_FLAG_NO_FREE;
77
78         xa->reply.header.sequence = 0;          /* filled-in by xmit logic */
79         xa->reply.header.time_stamp = 0;        /* filled-in by xmit logic */
80         xa->reply.header.message_type = NDMP0_MESSAGE_REPLY;
81         xa->reply.header.message = xa->request.header.message;
82         xa->reply.header.reply_sequence = xa->request.header.sequence;
83         xa->reply.header.error = NDMP0_NO_ERR;
84
85         /* assume no error */
86         ndmnmb_set_reply_error_raw (&xa->reply, NDMP0_NO_ERR);
87
88         switch ((int)msg & 0xFFFFFF00) {
89         case 0x0500:    /* notify */
90         case 0x0600:    /* log */
91         case 0x0700:    /* file history */
92                 xa->reply.flags |= NDMNMB_FLAG_NO_SEND;
93                 break;
94         }
95
96         /* sanity check */
97         if (xa->request.protocol_version != protocol_version) {
98                 xa->reply.header.error = NDMP0_UNDEFINED_ERR;
99                 return 0;
100         }
101
102         /*
103          * If the session is not open and the message
104          * is anything other than CONNECT_OPEN, the client
105          * has implicitly agreed to the protocol_version
106          * offered by NOTIFY_CONNECTED (ref ndmconn_accept()).
107          * Effectively perform CONNECT_OPEN for that
108          * protocol_version.
109          */
110         if (!sess->conn_open && msg != NDMP0_CONNECT_OPEN) {
111                 connect_open_common (sess, xa, ref_conn,
112                                         ref_conn->protocol_version);
113         }
114
115         /*
116          * Give the OS/implementation specific module a chance
117          * to intercept the request. Some requests are only implemented
118          * by the module. Some requests are reimplemented by the module
119          * when the standard implementation is inadequate to the app.
120          */
121         rc = ndmos_dispatch_request (sess, xa, ref_conn);
122         if (rc >= 0) {
123                 return rc;      /* request intercepted */
124         }
125
126         /*
127          * See if there is a standard, protocol_version specific
128          * dispatch function for the request.
129          */
130         drt = ndma_drt_lookup (ndma_dispatch_version_table,
131                                         protocol_version, msg);
132         if (drt) {
133                 goto have_drt;
134         }
135
136         /*
137          * Typical case....
138          * Find the protocol_version specific translation
139          * functions for this request/reply. The request
140          * is translated from its native version, NDMPvX,
141          * into NDMPv9. The NDMPv9 form is dispatched.
142          * The resulting reply is translated back to
143          * the native version
144          */
145
146         rrxl = reqrep_xlate_lookup_version (reqrep_xlate_version_table,
147                                 protocol_version);
148
149         /* find the protocol_version translation table */
150         if (!rrxl) {
151                 /* can't do it */
152                 xa->reply.header.error = NDMP0_NOT_SUPPORTED_ERR;
153                 return 0;
154         }
155
156         /* find the interface's translation table entry */
157         rrxl = ndmp_reqrep_by_vx (rrxl, msg);
158         if (!rrxl) {
159                 /* can't do it */
160                 xa->reply.header.error = NDMP0_NOT_SUPPORTED_ERR;
161                 return 0;
162         }
163
164         /* find the NDMPv9 dispatch table entry */
165         drt = ndma_drt_lookup (ndma_dispatch_version_table, NDMP9VER,
166                                 rrxl->v9_message);
167
168         if (!drt) {
169                 /* can't do it */
170                 xa->reply.header.error = NDMP0_NOT_SUPPORTED_ERR;
171                 return 0;
172         }
173
174   have_drt:
175         /*
176          * Permission checks, always.
177          */
178
179         if (!sess->conn_open
180          && !(drt->flags & NDM_DRT_FLAG_OK_NOT_CONNECTED)) {
181                 xa->reply.header.error = NDMP0_PERMISSION_ERR;
182                 return 0;
183         }
184
185         if (!sess->conn_authorized
186          && !(drt->flags & NDM_DRT_FLAG_OK_NOT_AUTHORIZED)) {
187                 xa->reply.header.error = NDMP0_NOT_AUTHORIZED_ERR;
188                 return 0;
189         }
190
191         /*
192          * If there is a translation afoot, translate the request now.
193          */
194
195         if (rrxl) {
196                 NDMOS_MACRO_ZEROFILL (&xl_xa);
197                 xa = &xl_xa;
198
199                 xa->request.header = arg_xa->request.header;
200                 xa->request.header.message = rrxl->v9_message;
201                 xa->request.protocol_version = NDMP9VER;
202
203                 xa->reply.header = arg_xa->reply.header;
204                 xa->reply.flags = arg_xa->reply.flags;
205                 xa->reply.protocol_version = NDMP9VER;
206
207                 rc = (*rrxl->request_xto9)(
208                                 (void*)&arg_xa->request.body,
209                                 (void*)&xa->request.body);
210
211                 if (rc < 0) {
212                         /* unrecoverable translation error */
213                         xa = arg_xa;
214                         xa->reply.header.error = NDMP0_UNDEFINED_ERR;
215                         return 0;
216                 }
217                 /* NB: rc>0 means that there were tolerated xlate errors */
218
219                 /* allow reply to be freed */
220                 xa->reply.flags &= ~NDMNMB_FLAG_NO_FREE;
221         }
222
223         rc = (*drt->dispatch_request)(sess, xa, ref_conn);
224
225         /* free up any memory allocated as part of the xto9 request */
226         if (rrxl)
227             (*rrxl->free_request_xto9)((void*)&xa->request.body);
228
229         if (rc < 0) {
230                 /* unrecoverable dispatch error */
231                 if (rrxl) {
232                         ndmnmb_free (&xa->reply);       /* clean up partials */
233                         xa = arg_xa;
234                 }
235                 xa->reply.header.error = NDMP0_NOT_SUPPORTED_ERR;
236                 return 0;
237         }
238
239         if (rrxl) {
240                 rc = (*rrxl->reply_9tox)(
241                                 (void*)&xa->reply.body,
242                                 (void*)&arg_xa->reply.body);
243
244                 /* free up any memory allocated as part of the 9tox reply */
245                 if (rrxl)
246                     (*rrxl->free_reply_9tox)((void*)&arg_xa->reply.body);
247
248                 ndmnmb_free (&xa->reply);       /* clean up */
249
250                 xa = arg_xa;
251
252                 if (rc < 0) {
253                         /* unrecoverable translation error */
254                         xa->reply.header.error = NDMP0_UNDEFINED_ERR;
255                         return 0;
256                 }
257                 /* NB: rc>0 means that there were tolerated xlate errors */
258         }
259         return 0;
260 }
261
262 int
263 ndma_dispatch_raise_error (struct ndm_session *sess,
264   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn,
265   ndmp9_error error, char *errstr)
266 {
267         int                     protocol_version = ref_conn->protocol_version;
268         ndmp0_message           msg = xa->request.header.message;
269
270         if (errstr) {
271                 ndmalogf (sess, 0, 2, "op=%s err=%s why=%s",
272                         ndmp_message_to_str (protocol_version, msg),
273                         ndmp9_error_to_str (error),
274                         errstr);
275         }
276
277         ndmnmb_set_reply_error (&xa->reply, error);
278
279         return 1;
280 }
281
282
283
284
285 /*
286  * Access paths to ndma_dispatch_request()
287  ****************************************************************
288  */
289
290 /* incomming requests on a ndmconn connection */
291 int
292 ndma_dispatch_conn (struct ndm_session *sess, struct ndmconn *conn)
293 {
294         struct ndmp_xa_buf      xa;
295         int                     rc;
296
297         NDMOS_MACRO_ZEROFILL (&xa);
298
299         rc = ndmconn_recv_nmb (conn, &xa.request);
300         if (rc) {
301             ndmnmb_free (&xa.request);
302             return rc;
303         }
304
305         ndma_dispatch_request (sess, &xa, conn);
306         ndmnmb_free (&xa.request);
307
308         if (! (xa.reply.flags & NDMNMB_FLAG_NO_SEND)) {
309                 rc = ndmconn_send_nmb (conn, &xa.reply);
310                 if (rc) return rc;
311         }
312
313         ndmnmb_free (&xa.reply);
314
315         return 0;
316 }
317
318 void
319 ndma_dispatch_ctrl_unexpected (struct ndmconn *conn, struct ndmp_msg_buf *nmb)
320 {
321         int                     protocol_version = conn->protocol_version;
322         struct ndm_session *    sess = conn->context;
323         struct ndmp_xa_buf      xa;
324
325         if (nmb->header.message_type != NDMP0_MESSAGE_REQUEST) {
326                 ndmalogf (sess, conn->chan.name, 1,
327                         "Unexpected message -- probably reply "
328                         "w/ wrong reply_sequence");
329 #if 0
330                 /* causes crash, needs investigation */
331                 ndmnmb_snoop (&sess->param.log, "WTF", 5,
332                                         nmb, conn->chan.name);
333 #endif
334                 ndmnmb_free (nmb);
335                 return;
336         }
337
338         NDMOS_MACRO_ZEROFILL (&xa);
339         xa.request = *nmb;
340
341         ndmalogf (sess, conn->chan.name, 4, "Async request %s",
342                         ndmp_message_to_str (protocol_version,
343                                 xa.request.header.message));
344
345         ndma_dispatch_request (sess, &xa, conn);
346
347         if (! (xa.reply.flags & NDMNMB_FLAG_NO_SEND)) {
348                 ndmconn_send_nmb (conn, &xa.reply);
349         }
350
351         ndmnmb_free (&xa.reply);
352 }
353
354
355
356 int
357 ndma_call_no_tattle (struct ndmconn *conn, struct ndmp_xa_buf *arg_xa)
358 {
359         struct ndmp_xa_buf *    xa = arg_xa;
360         struct ndmp_xa_buf      xl_xa;
361         struct reqrep_xlate *   rrxl = 0;
362         unsigned                protocol_version = conn->protocol_version;
363         unsigned                msg = xa->request.header.message;
364         int                     rc;
365
366         if (xa->request.protocol_version == NDMP9VER) {
367                 /*
368                  * Typical case....
369                  * Find the protocol_version specific translation
370                  * functions for this request/reply. The request
371                  * is translated to its native version, NDMPvX,
372                  * from NDMPv9. The NDMPvX form is transmitted.
373                  * The resulting reply is translated back to NDMPv9.
374                  * NDMPvX is determined by the connection.
375                  */
376
377                 rrxl = reqrep_xlate_lookup_version (reqrep_xlate_version_table,
378                                 protocol_version);
379
380                 /* find the protocol_version translation table */
381                 if (!rrxl) {
382                         /* can't do it */
383                         xa->reply.header.error = NDMP0_NOT_SUPPORTED_ERR;
384                         rc = NDMCONN_CALL_STATUS_HDR_ERROR;
385                         conn->last_header_error = xa->reply.header.error;
386                         return rc;
387                 }
388
389                 /* find the interface's translation table entry */
390                 rrxl = ndmp_reqrep_by_v9 (rrxl, msg);
391                 if (!rrxl) {
392                         /* can't do it */
393                         xa->reply.header.error = NDMP0_NOT_SUPPORTED_ERR;
394                         rc = NDMCONN_CALL_STATUS_HDR_ERROR;
395                         conn->last_header_error = xa->reply.header.error;
396                         return rc;
397                 }
398
399                 NDMOS_MACRO_ZEROFILL (&xl_xa);
400                 xa = &xl_xa;
401
402                 xa->request.header = arg_xa->request.header;
403                 xa->request.header.message = rrxl->vx_message;
404                 xa->request.protocol_version = protocol_version;
405
406                 rc = (*rrxl->request_9tox)(
407                                 (void*)&arg_xa->request.body,
408                                 (void*)&xa->request.body);
409
410                 if (rc < 0) {
411                         /* unrecoverable translation error */
412                         ndmnmb_free (&xa->request);     /* clean up partials */
413                         xa = arg_xa;
414                         xa->reply.header.error = NDMP0_NOT_SUPPORTED_ERR;
415                         rc = NDMCONN_CALL_STATUS_HDR_ERROR;
416                         conn->last_header_error = xa->reply.header.error;
417                         return rc;
418                 }
419                 /* NB: rc>0 means that there were tolerated xlate errors */
420         }
421
422         if (conn->conn_type == NDMCONN_TYPE_RESIDENT) {
423                 struct ndm_session *sess = conn->context;
424
425                 conn->last_message = xa->request.header.message;
426                 conn->last_call_status = NDMCONN_CALL_STATUS_BOTCH;
427                 conn->last_header_error = -1;   /* invalid */
428                 conn->last_reply_error = -1;    /* invalid */
429
430                 xa->request.header.sequence = conn->next_sequence++;
431
432                 ndmconn_snoop_nmb (conn, &xa->request, "Send");
433
434                 rc = ndma_dispatch_request (sess, xa, conn);
435
436                 xa->reply.header.sequence = conn->next_sequence++;
437
438                 if (! (xa->reply.flags & NDMNMB_FLAG_NO_SEND))
439                         ndmconn_snoop_nmb (conn, &xa->reply, "Recv");
440                 if (rc) {
441                         /* keep it */
442                 } else if (xa->reply.header.error != NDMP0_NO_ERR) {
443                         rc = NDMCONN_CALL_STATUS_HDR_ERROR;
444                         conn->last_header_error = xa->reply.header.error;
445                 } else {
446                         conn->last_header_error = NDMP9_NO_ERR;
447                         conn->last_reply_error =
448                                         ndmnmb_get_reply_error (&xa->reply);
449
450                         if (conn->last_reply_error == NDMP9_NO_ERR) {
451                                 rc = NDMCONN_CALL_STATUS_OK;
452                         } else {
453                                 rc = NDMCONN_CALL_STATUS_REPLY_ERROR;
454                         }
455                 }
456         } else {
457                 rc = ndmconn_call (conn, xa);
458                 if (rc == 0) {
459                     if ((conn->time_limit > 0) &&
460                         (conn->received_time > conn->sent_time)) {
461                         int delta;
462
463                         delta = conn->received_time - conn->sent_time;
464                         if (delta > conn->time_limit)
465                             rc = NDMCONN_CALL_STATUS_REPLY_LATE;
466                     }
467                 }
468         }
469
470
471         if (rrxl) {
472                 int             xrc;
473
474                 xrc = (*rrxl->reply_xto9)(
475                                 (void*)&xa->reply.body,
476                                 (void*)&arg_xa->reply.body);
477
478                 ndmnmb_free (&xa->request);     /* clean up */
479                 ndmnmb_free (&xa->reply);       /* clean up */
480
481                 arg_xa->reply.header = xa->reply.header;
482                 arg_xa->reply.flags = xa->reply.flags;
483                 arg_xa->reply.protocol_version = NDMP9VER;
484
485                 xa = arg_xa;
486
487                 if (xrc < 0) {
488                         /* unrecoverable translation error */
489                         xa->reply.header.error = NDMP0_UNDEFINED_ERR;
490                         rc = NDMCONN_CALL_STATUS_HDR_ERROR;
491                         conn->last_header_error = xa->reply.header.error;
492                         return rc;
493                 }
494                 /* NB: rc>0 means that there were tolerated xlate errors */
495         }
496
497         return rc;
498 }
499
500 int
501 ndma_call (struct ndmconn *conn, struct ndmp_xa_buf *xa)
502 {
503         int             rc;
504
505         rc = ndma_call_no_tattle (conn, xa);
506
507         if (rc) {
508                 ndma_tattle (conn, xa, rc);
509         }
510         return rc;
511 }
512
513 int
514 ndma_send_to_control (struct ndm_session *sess, struct ndmp_xa_buf *xa,
515   struct ndmconn *from_conn)
516 {
517         struct ndmconn *        conn = sess->plumb.control;
518         int                     rc;
519
520         if (conn->conn_type == NDMCONN_TYPE_RESIDENT && from_conn) {
521                 /*
522                  * Control and sending agent are
523                  * resident. Substitute the sending
524                  * agents "connection" so that logs
525                  * look right and right protocol_version
526                  * is used.
527                  */
528                 conn = from_conn;
529         }
530
531         rc = ndma_call_no_tattle (conn, xa);
532
533         if (rc) {
534                 ndma_tattle (conn, xa, rc);
535         }
536         return rc;
537 }
538
539 int
540 ndma_tattle (struct ndmconn *conn, struct ndmp_xa_buf *xa, int rc)
541 {
542         struct ndm_session *sess = conn->context;
543         int             protocol_version = conn->protocol_version;
544         unsigned        msg = xa->request.header.message;
545         char *          tag = conn->chan.name;
546         char *          msgname = ndmp_message_to_str (protocol_version, msg);
547         unsigned        err;
548
549         switch (rc) {
550         case 0:
551                 ndmalogf (sess, tag, 2, " ?OK %s", msgname);
552                 break;
553
554         case 1: /* no error in header, error in reply */
555                 err = ndmnmb_get_reply_error_raw (&xa->reply);
556                 ndmalogf (sess, tag, 2, " ERR %s  %s",
557                         msgname,
558                         ndmp_error_to_str (protocol_version, err));
559                 break;
560
561         case 2: /* no error in header or in reply, response late */
562                 ndmalogf (sess, tag, 2, " REPLY LATE %s, took %d seconds",
563                           msgname,
564                           (conn->received_time - conn->sent_time));
565                 break;
566
567         case -2: /* error in header, no reply body */
568                 err = xa->reply.header.error;
569                 ndmalogf (sess, tag, 2, " ERR-AGENT %s  %s",
570                         msgname,
571                         ndmp_error_to_str (protocol_version, err));
572                 break;
573
574         default:
575                 ndmalogf (sess, tag, 2, " ERR-CONN %s  %s",
576                         msgname,
577                         ndmconn_get_err_msg (conn));
578                 break;
579         }
580
581         return 0;
582 }
583
584
585
586
587 /*
588  * NDMPx_CONNECT Interfaces
589  ****************************************************************
590  */
591
592
593
594
595 /*
596  * NDMP[0234]_CONNECT_OPEN
597  */
598 int
599 ndmp_sxa_connect_open (struct ndm_session *sess,
600   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
601 {
602     NDMS_WITH(ndmp0_connect_open)
603         if (sess->conn_open) {
604             if (request->protocol_version != ref_conn->protocol_version) {
605                 NDMADR_RAISE_ILLEGAL_ARGS("too late to change version");
606             }
607         } else {
608             switch (request->protocol_version) {
609 #ifndef NDMOS_OPTION_NO_NDMP2
610             case NDMP2VER:
611 #endif /* !NDMOS_OPTION_NO_NDMP2 */
612 #ifndef NDMOS_OPTION_NO_NDMP3
613             case NDMP3VER:
614 #endif /* !NDMOS_OPTION_NO_NDMP3 */
615 #ifndef NDMOS_OPTION_NO_NDMP4
616             case NDMP4VER:
617 #endif /* !NDMOS_OPTION_NO_NDMP4 */
618                 connect_open_common (sess, xa, ref_conn,
619                                         request->protocol_version);
620                 break;
621
622             default:
623                 NDMADR_RAISE_ILLEGAL_ARGS("unsupport protocol version");
624                 break;
625             }
626         }
627     NDMS_ENDWITH
628
629     return 0;
630 }
631
632 static int
633 connect_open_common (struct ndm_session *sess,
634   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn,
635   int protocol_version)
636 {
637 #ifndef NDMOS_OPTION_NO_DATA_AGENT
638         sess->data_acb.protocol_version = protocol_version;
639 #endif /* !NDMOS_OPTION_NO_DATA_AGENT */
640 #ifndef NDMOS_OPTION_NO_TAPE_AGENT
641         sess->tape_acb.protocol_version = protocol_version;
642 #endif /* !NDMOS_OPTION_NO_TAPE_AGENT */
643 #ifndef NDMOS_OPTION_NO_ROBOT_AGENT
644         sess->robot_acb.protocol_version = protocol_version;
645 #endif /* !NDMOS_OPTION_NO_ROBOT_AGENT */
646
647         ref_conn->protocol_version = protocol_version;
648         sess->conn_open = 1;
649
650         return 0;
651 }
652
653
654
655
656 /*
657  * NDMP[234]_CONNECT_CLIENT_AUTH
658  */
659 int
660 ndmp_sxa_connect_client_auth (struct ndm_session *sess,
661   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
662 {
663         ndmp9_auth_type auth_type;
664         char *          name = 0;
665         char *          proof = 0;
666
667       NDMS_WITH(ndmp9_connect_client_auth)
668
669         auth_type = request->auth_data.auth_type;
670         switch (auth_type) {
671         default:
672                 NDMADR_RAISE_ILLEGAL_ARGS ("auth_type");
673
674         case NDMP9_AUTH_TEXT:
675             {
676                 ndmp9_auth_text *       p;
677
678                 p = &request->auth_data.ndmp9_auth_data_u.auth_text;
679                 name = p->auth_id;
680                 proof = p->auth_password;
681                 if (!ndmos_ok_name_password (sess, name, proof)) {
682                         NDMADR_RAISE(NDMP9_NOT_AUTHORIZED_ERR,
683                                                 "password not OK");
684                 }
685             }
686             break;
687
688         case NDMP9_AUTH_MD5:
689             {
690                 ndmp9_auth_md5 *        p;
691
692                 p = &request->auth_data.ndmp9_auth_data_u.auth_md5;
693                 name = p->auth_id;
694                 proof = p->auth_digest;
695
696                 if (!sess->md5_challenge_valid) {
697                         NDMADR_RAISE(NDMP9_NOT_AUTHORIZED_ERR,
698                                         "no challenge");
699                 }
700
701                 if (!ndmos_ok_name_md5_digest (sess, name, proof)) {
702                         NDMADR_RAISE(NDMP9_NOT_AUTHORIZED_ERR,
703                                         "digest not OK");
704                 }
705             }
706             break;
707         }
708         sess->conn_authorized = 1;
709
710         return 0;
711       NDMS_ENDWITH
712 }
713
714
715
716
717 /*
718  * NDMP[023]_CONNECT_CLOSE
719  */
720 int
721 ndmp_sxa_connect_close (struct ndm_session *sess,
722   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
723 {
724         xa->reply.flags |= NDMNMB_FLAG_NO_SEND; /* ??? */
725
726         /* TODO: shutdown everything */
727         sess->connect_status = 0;
728         ndmchan_set_eof (&ref_conn->chan);
729
730         return 0;
731 }
732
733
734
735
736 /*
737  * NDMP[23]_CONNECT_SERVER_AUTH
738  */
739 int
740 ndmp_sxa_connect_server_auth (struct ndm_session *sess,
741   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
742 {
743         return NDMADR_UNIMPLEMENTED_MESSAGE;
744 }
745
746
747
748
749 /*
750  * NDMPx_CONFIG Interfaces
751  ****************************************************************
752  */
753
754
755
756
757 /*
758  * NDMP[234]_CONFIG_GET_HOST_INFO
759  * NDMP[34]_CONFIG_GET_SERVER_INFO
760  * NDMP2_CONFIG_GET_MOVER_TYPE
761  * NDMP[34]_CONFIG_GET_CONNECTION_TYPE
762  * NDMP[34]_CONFIG_GET_BUTYPE_INFO
763  * NDMP[34]_CONFIG_GET_FS_INFO
764  * NDMP[34]_CONFIG_GET_TAPE_INFO
765  * NDMP[34]_CONFIG_GET_SCSI_INFO
766  */
767 int
768 ndmp_sxa_config_get_info (struct ndm_session *sess,
769   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
770 {
771       NDMS_WITH_VOID_REQUEST(ndmp9_config_get_info)
772         ndmos_sync_config_info (sess);
773
774         if (sess->config_info.conntypes == 0) {
775                 /* OS left it for us to do */
776 #ifndef NDMOS_OPTION_NO_DATA_AGENT
777 #ifndef NDMOS_OPTION_NO_TAPE_AGENT
778                 sess->config_info.conntypes |= NDMP9_CONFIG_CONNTYPE_LOCAL;
779                 sess->config_info.conntypes |= NDMP9_CONFIG_CONNTYPE_TCP;
780 #else /* !NDMOS_OPTION_NO_TAPE_AGENT */
781                 sess->config_info.conntypes |= NDMP9_CONFIG_CONNTYPE_TCP;
782 #endif /* !NDMOS_OPTION_NO_TAPE_AGENT */
783 #else /* !NDMOS_OPTION_NO_DATA_AGENT */
784 #ifndef NDMOS_OPTION_NO_TAPE_AGENT
785                 sess->config_info.conntypes |= NDMP9_CONFIG_CONNTYPE_TCP;
786 #else /* !NDMOS_OPTION_NO_TAPE_AGENT */
787 #endif /* !NDMOS_OPTION_NO_TAPE_AGENT */
788 #endif /* !NDMOS_OPTION_NO_DATA_AGENT */
789         }
790
791         if (sess->config_info.authtypes == 0) {
792                 /* OS left it for us to do */
793                 sess->config_info.authtypes |= NDMP9_CONFIG_AUTHTYPE_TEXT;
794                 sess->config_info.authtypes |= NDMP9_CONFIG_AUTHTYPE_MD5;
795         }
796
797         reply->config_info = sess->config_info;
798
799         return 0;
800       NDMS_ENDWITH
801 }
802
803
804
805
806 #ifndef NDMOS_OPTION_NO_NDMP2
807 /*
808  * NDMP2_CONFIG_GET_BUTYPE_ATTR
809  */
810 int
811 ndmp2_sxa_config_get_butype_attr (struct ndm_session *sess,
812   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
813 {
814         ndmp9_config_info *     ci = &sess->config_info;
815         ndmp9_butype_info *     bu = 0;
816         unsigned int            i;
817
818         assert (xa->request.protocol_version == NDMP2VER);
819
820       NDMS_WITH(ndmp2_config_get_butype_attr)
821         ndmos_sync_config_info (sess);
822
823         for (i = 0; i < ci->butype_info.butype_info_len; i++) {
824                 bu = &ci->butype_info.butype_info_val[i];
825
826                 if (strcmp (request->name, bu->butype_name) == 0) {
827                         break;
828                 }
829         }
830
831         if (i >= ci->butype_info.butype_info_len) {
832                 NDMADR_RAISE_ILLEGAL_ARGS("butype");
833         }
834
835         reply->attrs = bu->v2attr.value;
836
837         return 0;
838       NDMS_ENDWITH
839 }
840 #endif /* !NDMOS_OPTION_NO_NDMP2 */
841
842
843
844
845 /*
846  * NDMP[234]_CONFIG_GET_AUTH_ATTR
847  *
848  * Credits to Rajiv of NetApp for helping with MD5 stuff.
849  */
850 int
851 ndmp_sxa_config_get_auth_attr (struct ndm_session *sess,
852   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
853 {
854       NDMS_WITH(ndmp9_config_get_auth_attr)
855         switch (request->auth_type) {
856         default:
857                 NDMADR_RAISE_ILLEGAL_ARGS ("auth_type");
858
859         case NDMP9_AUTH_NONE:
860                 break;
861
862         case NDMP9_AUTH_TEXT:
863                 break;
864
865         case NDMP9_AUTH_MD5:
866                 ndmos_get_md5_challenge (sess);
867                 NDMOS_API_BCOPY (sess->md5_challenge,
868                         reply->server_attr.ndmp9_auth_attr_u.challenge, 64);
869                 break;
870         }
871         reply->server_attr.auth_type = request->auth_type;
872
873         return 0;
874       NDMS_ENDWITH
875 }
876
877
878
879
880 #ifndef NDMOS_OPTION_NO_ROBOT_AGENT     /* Surrounds SCSI intfs */
881 /*
882  * NDMPx_SCSI Interfaces
883  ****************************************************************
884  *
885  * If these are implemented, they should already have been
886  * intercepted by ndmos_dispatch_request(). There is absolutely
887  * no way to implement this generically, nor is there merit to
888  * a generic "layer".
889  *
890  * Still, just in case, they are implemented here.
891  */
892
893 static ndmp9_error      scsi_open_ok (struct ndm_session *sess);
894 static ndmp9_error      scsi_op_ok (struct ndm_session *sess);
895
896
897
898
899 /*
900  * NDMP[234]_SCSI_OPEN
901  */
902 int
903 ndmp_sxa_scsi_open (struct ndm_session *sess,
904   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
905 {
906         ndmp9_error             error;
907
908       NDMS_WITH(ndmp9_scsi_open)
909         error = scsi_open_ok (sess);
910         if (error != NDMP9_NO_ERR) {
911                 NDMADR_RAISE(error, "!scsi_open_ok");
912         }
913
914         error = ndmos_scsi_open (sess, request->device);
915         if (error != NDMP9_NO_ERR) {
916                 NDMADR_RAISE(error, "scsi_open");
917         }
918
919         return 0;
920       NDMS_ENDWITH
921 }
922
923
924
925
926 /*
927  * NDMP[234]_SCSI_CLOSE
928  */
929 int
930 ndmp_sxa_scsi_close (struct ndm_session *sess,
931   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
932 {
933         ndmp9_error             error;
934
935       NDMS_WITH_VOID_REQUEST(ndmp9_scsi_close)
936         error = scsi_op_ok (sess);
937         if (error != NDMP9_NO_ERR) {
938                 NDMADR_RAISE(error, "!scsi_op_ok");
939         }
940
941         error = ndmos_scsi_close (sess);
942         if (error != NDMP9_NO_ERR) {
943                 NDMADR_RAISE(error, "scsi_close");
944         }
945
946         return 0;
947       NDMS_ENDWITH
948 }
949
950
951
952
953 /*
954  * NDMP[234]_SCSI_GET_STATE
955  */
956 int
957 ndmp_sxa_scsi_get_state (struct ndm_session *sess,
958   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
959 {
960         struct ndm_robot_agent *ra = &sess->robot_acb;
961
962       NDMS_WITH_VOID_REQUEST(ndmp9_scsi_get_state)
963         ndmos_scsi_sync_state (sess);
964
965         *reply = ra->scsi_state;
966
967         return 0;
968       NDMS_ENDWITH
969 }
970
971
972
973
974 /*
975  * NDMP[23]_SCSI_SET_TARGET
976  */
977 int
978 ndmp_sxa_scsi_set_target (struct ndm_session *sess,
979   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
980 {
981         ndmp9_error             error;
982
983       NDMS_WITH(ndmp9_scsi_set_target)
984         error = scsi_op_ok (sess);
985         if (error != NDMP9_NO_ERR) {
986                 NDMADR_RAISE(error, "!scsi_op_ok");
987         }
988
989         error = ndmos_scsi_set_target (sess);
990         if (error != NDMP9_NO_ERR) {
991                 NDMADR_RAISE(error, "scsi_set_target");
992         }
993
994         return 0;
995       NDMS_ENDWITH
996 }
997
998
999
1000
1001 /*
1002  * NDMP[234]_SCSI_RESET_DEVICE
1003  */
1004 int
1005 ndmp_sxa_scsi_reset_device (struct ndm_session *sess,
1006   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
1007 {
1008         ndmp9_error             error;
1009
1010       NDMS_WITH_VOID_REQUEST(ndmp9_scsi_reset_device)
1011         error = scsi_op_ok (sess);
1012         if (error != NDMP9_NO_ERR) {
1013                 NDMADR_RAISE(error, "!scsi_op_ok");
1014         }
1015
1016         error = ndmos_scsi_reset_device (sess);
1017         if (error != NDMP9_NO_ERR) {
1018                 NDMADR_RAISE(error, "scsi_reset_device");
1019         }
1020
1021         return 0;
1022       NDMS_ENDWITH
1023 }
1024
1025
1026
1027
1028 /*
1029  * NDMP[23]_SCSI_RESET_BUS
1030  */
1031 int
1032 ndmp_sxa_scsi_reset_bus (struct ndm_session *sess,
1033   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
1034 {
1035         ndmp9_error             error;
1036
1037       NDMS_WITH_VOID_REQUEST(ndmp9_scsi_reset_bus)
1038         error = scsi_op_ok (sess);
1039         if (error != NDMP9_NO_ERR) {
1040                 NDMADR_RAISE(error, "!scsi_op_ok");
1041         }
1042
1043         error = ndmos_scsi_reset_bus (sess);
1044         if (error != NDMP9_NO_ERR) {
1045                 NDMADR_RAISE(error, "scsi_reset_bus");
1046         }
1047
1048         return 0;
1049       NDMS_ENDWITH
1050 }
1051
1052
1053
1054
1055 /*
1056  * NDMP[234]_SCSI_EXECUTE_CDB
1057  */
1058 int
1059 ndmp_sxa_scsi_execute_cdb (struct ndm_session *sess,
1060   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
1061 {
1062         ndmp9_error             error;
1063
1064       NDMS_WITH(ndmp9_scsi_execute_cdb)
1065         error = scsi_op_ok (sess);
1066         if (error != NDMP9_NO_ERR) {
1067                 NDMADR_RAISE(error, "!scsi_op_ok");
1068         }
1069
1070         error = ndmos_scsi_execute_cdb (sess, request, reply);
1071         if (error != NDMP9_NO_ERR) {
1072                 NDMADR_RAISE(error, "scsi_execute_cdb");
1073         }
1074
1075         return 0;
1076       NDMS_ENDWITH
1077 }
1078
1079
1080
1081
1082 /*
1083  * NDMPx_SCSI helper routines
1084  */
1085
1086 static ndmp9_error
1087 scsi_open_ok (struct ndm_session *sess)
1088 {
1089         struct ndm_robot_agent *        ra = &sess->robot_acb;
1090
1091         ndmos_scsi_sync_state(sess);
1092         if (ra->scsi_state.error != NDMP9_DEV_NOT_OPEN_ERR)
1093                 return NDMP9_DEVICE_OPENED_ERR;
1094
1095 #ifndef NDMOS_OPTION_ALLOW_SCSI_AND_TAPE_BOTH_OPEN
1096 #ifndef NDMOS_OPTION_NO_TAPE_AGENT
1097         ndmos_tape_sync_state(sess);
1098         if (sess->tape_acb.tape_state.error != NDMP9_DEV_NOT_OPEN_ERR)
1099                 return NDMP9_DEVICE_OPENED_ERR;
1100 #endif /* !NDMOS_OPTION_NO_TAPE_AGENT */
1101 #endif /* NDMOS_OPTION_ALLOW_SCSI_AND_TAPE_BOTH_OPEN */
1102
1103         return NDMP9_NO_ERR;
1104 }
1105
1106 static ndmp9_error
1107 scsi_op_ok (struct ndm_session *sess)
1108 {
1109         struct ndm_robot_agent *        ra = &sess->robot_acb;
1110
1111         ndmos_scsi_sync_state(sess);
1112         if (ra->scsi_state.error != NDMP9_NO_ERR)
1113                 return NDMP9_DEV_NOT_OPEN_ERR;
1114
1115         return NDMP9_NO_ERR;
1116 }
1117 #endif /* !NDMOS_OPTION_NO_ROBOT_AGENT */       /* Surrounds SCSI intfs */
1118
1119
1120
1121
1122 #ifndef NDMOS_OPTION_NO_TAPE_AGENT              /* Surrounds TAPE intfs */
1123 /*
1124  * NDMPx_TAPE Interfaces
1125  ****************************************************************
1126  */
1127 static ndmp9_error      tape_open_ok (struct ndm_session *sess,
1128                                 int will_write);
1129 static ndmp9_error      tape_op_ok (struct ndm_session *sess,
1130                                 int will_write);
1131
1132
1133
1134
1135 /*
1136  * NDMP[234]_TAPE_OPEN
1137  */
1138 int
1139 ndmp_sxa_tape_open (struct ndm_session *sess,
1140   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
1141 {
1142         ndmp9_error             error;
1143         int                     will_write;
1144
1145       NDMS_WITH(ndmp9_tape_open)
1146         switch (request->mode) {
1147         default:
1148                 NDMADR_RAISE_ILLEGAL_ARGS("tape_mode");
1149
1150         case NDMP9_TAPE_READ_MODE:
1151                 will_write = 0;
1152                 break;
1153
1154         case NDMP9_TAPE_RDWR_MODE:
1155         case NDMP9_TAPE_RAW_MODE:
1156                 will_write = 1;
1157                 break;
1158         }
1159
1160         error = tape_open_ok (sess, will_write);
1161         if (error != NDMP9_NO_ERR) {
1162                 NDMADR_RAISE(error, "!tape_open_ok");
1163         }
1164
1165         error = ndmos_tape_open (sess, request->device, will_write);
1166         if (error != NDMP9_NO_ERR) {
1167                 NDMADR_RAISE(error, "tape_open");
1168         }
1169
1170         return 0;
1171       NDMS_ENDWITH
1172 }
1173
1174
1175
1176
1177 /*
1178  * NDMP[234]_TAPE_CLOSE
1179  */
1180 int
1181 ndmp_sxa_tape_close (struct ndm_session *sess,
1182   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
1183 {
1184         ndmp9_error             error;
1185
1186       NDMS_WITH_VOID_REQUEST(ndmp9_tape_close)
1187         error = tape_op_ok (sess, 0);
1188         if (error != NDMP9_NO_ERR) {
1189                 NDMADR_RAISE(error, "!tape_op_ok");
1190         }
1191
1192         error = ndmos_tape_close (sess);
1193         if (error != NDMP9_NO_ERR) {
1194                 NDMADR_RAISE(error, "tape_close");
1195         }
1196
1197         return 0;
1198       NDMS_ENDWITH
1199 }
1200
1201
1202
1203
1204 /*
1205  * NDMP[234]_TAPE_GET_STATE
1206  */
1207 int
1208 ndmp_sxa_tape_get_state (struct ndm_session *sess,
1209   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
1210 {
1211         struct ndm_tape_agent * ta = &sess->tape_acb;
1212
1213       NDMS_WITH_VOID_REQUEST(ndmp9_tape_get_state)
1214
1215         ndmos_tape_sync_state(sess);
1216
1217         *reply = ta->tape_state;
1218
1219         return 0;
1220       NDMS_ENDWITH
1221 }
1222
1223
1224
1225
1226 /*
1227  * NDMP[234]_TAPE_MTIO
1228  */
1229 int
1230 ndmp_sxa_tape_mtio (struct ndm_session *sess,
1231   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
1232 {
1233         ndmp9_error             error;
1234         ndmp9_tape_mtio_op      tape_op;
1235         int                     will_write = 0;
1236         unsigned long           resid = 0;
1237
1238       NDMS_WITH(ndmp9_tape_mtio)
1239
1240         switch (request->tape_op) {
1241         default:
1242                 NDMADR_RAISE_ILLEGAL_ARGS("tape_op");
1243
1244         case NDMP9_MTIO_EOF:
1245                 will_write = 1;
1246                 tape_op = NDMP9_MTIO_EOF;
1247                 break;
1248
1249         case NDMP9_MTIO_FSF:
1250         case NDMP9_MTIO_BSF:
1251         case NDMP9_MTIO_FSR:
1252         case NDMP9_MTIO_BSR:
1253         case NDMP9_MTIO_REW:
1254         case NDMP9_MTIO_OFF:
1255                 tape_op = request->tape_op;
1256                 break;
1257         }
1258
1259         error = tape_op_ok (sess, will_write);
1260         if (error != NDMP9_NO_ERR) {
1261                 NDMADR_RAISE(error, "!tape_op_ok");
1262         }
1263
1264         error = ndmos_tape_mtio (sess, tape_op, request->count, &resid);
1265
1266         reply->error = error;
1267         reply->resid_count = resid;
1268
1269         return 0;
1270       NDMS_ENDWITH
1271 }
1272
1273
1274
1275
1276 /*
1277  * NDMP[234]_TAPE_WRITE
1278  */
1279 int
1280 ndmp_sxa_tape_write (struct ndm_session *sess,
1281   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
1282 {
1283         ndmp9_error             error;
1284         unsigned long           done_count = 0;
1285
1286       NDMS_WITH(ndmp9_tape_write)
1287         if (request->data_out.data_out_len == 0) {
1288                 /*
1289                  * NDMPv4 clarification -- a tape read or write with
1290                  * a count==0 is a no-op. This is undoubtedly influenced
1291                  * by the SCSI Sequential Access specification which
1292                  * says much the same thing.
1293                  *
1294                  * NDMPv[23] MAY return NDMP_NO_ERR or
1295                  * NDMP_ILLEGAL_ARGS_ERR.
1296                  */
1297                 reply->error = NDMP9_NO_ERR;
1298                 reply->count = 0;
1299
1300                 return 0;
1301         }
1302
1303         if (!NDMOS_MACRO_OK_TAPE_REC_LEN(request->data_out.data_out_len)) {
1304                 NDMADR_RAISE_ILLEGAL_ARGS("!ok_tape_rec_len");
1305         }
1306
1307         error = tape_op_ok (sess, 1);
1308         if (error != NDMP9_NO_ERR) {
1309                 NDMADR_RAISE(error, "!tape_op_ok");
1310         }
1311
1312         error = ndmos_tape_write (sess, request->data_out.data_out_val,
1313                                 request->data_out.data_out_len,
1314                                 &done_count);
1315         reply->error = error;
1316         reply->count = done_count;
1317
1318         return 0;
1319       NDMS_ENDWITH
1320 }
1321
1322
1323
1324
1325 /*
1326  * NDMP[234]_TAPE_READ
1327  */
1328 int
1329 ndmp_sxa_tape_read (struct ndm_session *sess,
1330   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
1331 {
1332         struct ndm_tape_agent * ta = &sess->tape_acb;
1333         ndmp9_error             error;
1334         unsigned long           done_count = 0;
1335
1336       NDMS_WITH(ndmp9_tape_read)
1337         if (request->count == 0) {
1338                 /*
1339                  * NDMPv4 clarification -- a tape read or write with
1340                  * a count==0 is a no-op. This is undoubtedly influenced
1341                  * by the SCSI Sequential Access specification which
1342                  * says much the same thing.
1343                  *
1344                  * NDMPv[23] MAY return NDMP_NO_ERR or
1345                  * NDMP_ILLEGAL_ARGS_ERR.
1346                  */
1347                 reply->error = NDMP9_NO_ERR;
1348                 reply->data_in.data_in_val = ta->tape_buffer;
1349                 reply->data_in.data_in_len = 0;
1350
1351                 return 0;
1352         }
1353
1354         if (!NDMOS_MACRO_OK_TAPE_REC_LEN(request->count)) {
1355                 NDMADR_RAISE_ILLEGAL_ARGS("!ok_tape_rec_len");
1356         }
1357
1358         error = tape_op_ok (sess, 0);
1359         if (error != NDMP9_NO_ERR) {
1360                 NDMADR_RAISE(error, "!tape_op_ok");
1361         }
1362
1363         error = ndmos_tape_read (sess, ta->tape_buffer,
1364                                 request->count,
1365                                 &done_count);
1366         reply->error = error;
1367         reply->data_in.data_in_val = ta->tape_buffer;
1368         reply->data_in.data_in_len = done_count;
1369
1370         return 0;
1371       NDMS_ENDWITH
1372 }
1373
1374
1375
1376
1377 /*
1378  * NDMP[234]_TAPE_EXECUTE_CDB
1379  *
1380  * If this is implemented, it should already have been
1381  * intercepted by ndmos_dispatch_request().
1382  * There is absolutely no way to implement this generically,
1383  * nor is there merit to a generic "layer".
1384  * Still, just in case, it is implemented here.
1385  */
1386 int
1387 ndmp_sxa_tape_execute_cdb (struct ndm_session *sess,
1388   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
1389 {
1390       NDMS_WITH(ndmp9_tape_execute_cdb)
1391         return NDMADR_UNIMPLEMENTED_MESSAGE;
1392       NDMS_ENDWITH
1393 }
1394
1395
1396
1397
1398 /*
1399  * NDMPx_TAPE helper routines
1400  */
1401
1402 static ndmp9_error
1403 tape_open_ok (struct ndm_session *sess, int will_write)
1404 {
1405         struct ndm_tape_agent *         ta = &sess->tape_acb;
1406
1407         ndmos_tape_sync_state(sess);
1408         if (ta->tape_state.state != NDMP9_TAPE_STATE_IDLE)
1409                 return NDMP9_DEVICE_OPENED_ERR;
1410
1411 #ifndef NDMOS_OPTION_ALLOW_SCSI_AND_TAPE_BOTH_OPEN
1412 #ifndef NDMOS_OPTION_NO_ROBOT_AGENT
1413         ndmos_scsi_sync_state(sess);
1414         if (sess->robot_acb.scsi_state.error != NDMP9_DEV_NOT_OPEN_ERR)
1415                 return NDMP9_DEVICE_OPENED_ERR;
1416 #endif /* !NDMOS_OPTION_NO_ROBOT_AGENT */
1417 #endif /* NDMOS_OPTION_ALLOW_SCSI_AND_TAPE_BOTH_OPEN */
1418
1419         return NDMP9_NO_ERR;
1420 }
1421
1422 /*
1423  * Tape operation is only OK if it is open and the MOVER
1424  * hasn't got a hold of it. We can't allow tape operations
1425  * to interfere with the MOVER.
1426  */
1427
1428 static ndmp9_error
1429 tape_op_ok (struct ndm_session *sess, int will_write)
1430 {
1431         struct ndm_tape_agent *         ta = &sess->tape_acb;
1432
1433         ndmos_tape_sync_state(sess);
1434         switch (ta->tape_state.state) {
1435         case NDMP9_TAPE_STATE_IDLE:
1436                 return NDMP9_DEV_NOT_OPEN_ERR;
1437
1438         case NDMP9_TAPE_STATE_OPEN:
1439                 if (will_write && !NDMTA_TAPE_IS_WRITABLE(ta))
1440                         return NDMP9_PERMISSION_ERR;
1441                 break;
1442
1443         case NDMP9_TAPE_STATE_MOVER:
1444                 return NDMP9_ILLEGAL_STATE_ERR;
1445         }
1446
1447         return NDMP9_NO_ERR;
1448 }
1449 #endif /* !NDMOS_OPTION_NO_TAPE_AGENT */        /* Surrounds TAPE intfs */
1450
1451
1452
1453
1454 #ifndef NDMOS_OPTION_NO_DATA_AGENT              /* Surrounds DATA intfs */
1455 /*
1456  * NDMPx_DATA Interfaces
1457  ****************************************************************
1458  */
1459
1460 static int              data_ok_bu_type (struct ndm_session *sess,
1461                                 struct ndmp_xa_buf *xa,
1462                                 struct ndmconn *ref_conn,
1463                                 char *bu_type);
1464
1465 static int              data_can_connect_and_start (struct ndm_session *sess,
1466                                 struct ndmp_xa_buf *xa,
1467                                 struct ndmconn *ref_conn,
1468                                 ndmp9_addr *data_addr,
1469                                 ndmp9_mover_mode mover_mode);
1470
1471 static int              data_can_connect (struct ndm_session *sess,
1472                                 struct ndmp_xa_buf *xa,
1473                                 struct ndmconn *ref_conn,
1474                                 ndmp9_addr *data_addr);
1475
1476 static int              data_can_start (struct ndm_session *sess,
1477                                 struct ndmp_xa_buf *xa,
1478                                 struct ndmconn *ref_conn,
1479                                 ndmp9_mover_mode mover_mode);
1480
1481 static int              data_connect (struct ndm_session *sess,
1482                                 struct ndmp_xa_buf *xa,
1483                                 struct ndmconn *ref_conn,
1484                                 ndmp9_addr *data_addr);
1485
1486 static ndmp9_error      data_copy_environment (struct ndm_session *sess,
1487                                 ndmp9_pval *env, unsigned n_env);
1488
1489 static ndmp9_error      data_copy_nlist (struct ndm_session *sess,
1490                                 ndmp9_name *nlist, unsigned n_nlist);
1491
1492
1493
1494
1495
1496 /*
1497  * NDMP[234]_DATA_GET_STATE
1498  */
1499 int
1500 ndmp_sxa_data_get_state (struct ndm_session *sess,
1501   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
1502 {
1503         struct ndm_data_agent * da = &sess->data_acb;
1504
1505       NDMS_WITH_VOID_REQUEST(ndmp9_data_get_state)
1506         *reply = da->data_state;
1507
1508         return 0;
1509       NDMS_ENDWITH
1510 }
1511
1512
1513
1514
1515 /*
1516  * NDMP[234]_DATA_START_BACKUP
1517  */
1518 int
1519 ndmp_sxa_data_start_backup (struct ndm_session *sess,
1520   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
1521 {
1522         int                     rc;
1523         ndmp9_error             error;
1524
1525       NDMS_WITH(ndmp9_data_start_backup)
1526         rc = data_ok_bu_type (sess, xa, ref_conn, request->bu_type);
1527         if (rc) {
1528                 return rc;
1529         }
1530
1531         if (request->addr.addr_type != NDMP9_ADDR_AS_CONNECTED) {
1532                 rc = data_can_connect_and_start (sess, xa, ref_conn,
1533                                 &request->addr, NDMP9_MOVER_MODE_READ);
1534         } else {
1535                 rc = data_can_start (sess, xa, ref_conn,
1536                                 NDMP9_MOVER_MODE_READ);
1537         }
1538         if (rc) {
1539                 return rc;      /* already tattled */
1540         }
1541
1542         strcpy (sess->data_acb.bu_type, request->bu_type);
1543
1544         error = data_copy_environment (sess,
1545                         request->env.env_val, request->env.env_len);
1546         if (error != NDMP9_NO_ERR) {
1547                 ndmda_belay (sess);
1548                 NDMADR_RAISE(error, "copy-env");
1549         }
1550
1551         if (request->addr.addr_type != NDMP9_ADDR_AS_CONNECTED) {
1552                 rc = data_connect (sess, xa, ref_conn, &request->addr);
1553                 if (rc) {
1554                         ndmda_belay (sess);
1555                         return rc;      /* already tattled */
1556                 }
1557         }
1558
1559         error = ndmda_data_start_backup (sess);
1560         if (error != NDMP9_NO_ERR) {
1561                 /* TODO: undo everything */
1562                 ndmda_belay (sess);
1563                 NDMADR_RAISE(error, "start_backup");
1564         }
1565
1566         return 0;
1567       NDMS_ENDWITH
1568 }
1569
1570
1571
1572
1573 /*
1574  * NDMP[234]_DATA_START_RECOVER
1575  */
1576 int
1577 ndmp_sxa_data_start_recover (struct ndm_session *sess,
1578   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
1579 {
1580         ndmp9_error             error;
1581         int                     rc;
1582
1583       NDMS_WITH(ndmp9_data_start_recover)
1584         rc = data_ok_bu_type (sess, xa, ref_conn, request->bu_type);
1585         if (rc) {
1586                 return rc;
1587         }
1588
1589         if (request->addr.addr_type != NDMP9_ADDR_AS_CONNECTED) {
1590                 rc = data_can_connect_and_start (sess, xa, ref_conn,
1591                                 &request->addr, NDMP9_MOVER_MODE_WRITE);
1592         } else {
1593                 rc = data_can_start (sess, xa, ref_conn,
1594                                 NDMP9_MOVER_MODE_WRITE);
1595         }
1596         if (rc) {
1597                 return rc;      /* already tattled */
1598         }
1599
1600         strcpy (sess->data_acb.bu_type, request->bu_type);
1601
1602         error = data_copy_environment (sess,
1603                         request->env.env_val, request->env.env_len);
1604         if (error != NDMP9_NO_ERR) {
1605                 ndmda_belay (sess);
1606                 NDMADR_RAISE(error, "copy-env");
1607         }
1608
1609         error = data_copy_nlist (sess,
1610                 request->nlist.nlist_val, request->nlist.nlist_len);
1611
1612         if (error != NDMP9_NO_ERR) {
1613                 ndmda_belay (sess);
1614                 NDMADR_RAISE(error, "copy-nlist");
1615         }
1616
1617         if (request->addr.addr_type != NDMP9_ADDR_AS_CONNECTED) {
1618                 rc = data_connect (sess, xa, ref_conn, &request->addr);
1619                 if (rc) {
1620                         ndmda_belay (sess);
1621                         return rc;      /* already tattled */
1622                 }
1623         }
1624
1625         error = ndmda_data_start_recover (sess);
1626         if (error != NDMP9_NO_ERR) {
1627                 /* TODO: undo everything */
1628                 ndmda_belay (sess);
1629                 NDMADR_RAISE(error, "start_recover");
1630         }
1631
1632         return 0;
1633       NDMS_ENDWITH
1634 }
1635
1636
1637
1638
1639 /*
1640  * NDMP[234]_DATA_ABORT
1641  */
1642 int
1643 ndmp_sxa_data_abort (struct ndm_session *sess,
1644   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
1645 {
1646         struct ndm_data_agent * da = &sess->data_acb;
1647
1648       NDMS_WITH_VOID_REQUEST(ndmp9_data_abort)
1649         if (da->data_state.state != NDMP9_DATA_STATE_ACTIVE)
1650                 NDMADR_RAISE_ILLEGAL_STATE("data_state !ACTIVE");
1651
1652         ndmda_data_abort (sess);
1653
1654         return 0;
1655       NDMS_ENDWITH
1656 }
1657
1658
1659
1660
1661 /*
1662  * NDMP[234]_DATA_GET_ENV
1663  */
1664 int
1665 ndmp_sxa_data_get_env (struct ndm_session *sess,
1666   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
1667 {
1668         struct ndm_data_agent * da = &sess->data_acb;
1669
1670       NDMS_WITH_VOID_REQUEST(ndmp9_data_get_env)
1671         if (da->data_state.state == NDMP9_DATA_STATE_IDLE) {
1672                 NDMADR_RAISE_ILLEGAL_STATE("data_state IDLE");
1673         }
1674         if (da->data_state.operation != NDMP9_DATA_OP_BACKUP) {
1675                 NDMADR_RAISE_ILLEGAL_STATE("data_op !BACKUP");
1676         }
1677
1678         ndmda_sync_environment (sess);
1679
1680         ndmalogf (sess, ref_conn->chan.name, 6, "n_env=%d", da->env_tab.n_env);
1681
1682         reply->env.env_len = da->env_tab.n_env;
1683         reply->env.env_val = da->env_tab.env;
1684
1685 #if 0
1686         xa->reply.flags &= ~NDMNMB_FLAG_NO_FREE;  /* free env after xmit */
1687 #endif
1688
1689         return 0;
1690       NDMS_ENDWITH
1691 }
1692
1693
1694
1695
1696 /*
1697  * NDMP[234]_DATA_STOP
1698  */
1699 int
1700 ndmp_sxa_data_stop (struct ndm_session *sess,
1701   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
1702 {
1703         struct ndm_data_agent * da = &sess->data_acb;
1704
1705       NDMS_WITH_VOID_REQUEST(ndmp9_data_stop)
1706         if (da->data_state.state != NDMP9_DATA_STATE_HALTED) {
1707                 NDMADR_RAISE_ILLEGAL_STATE("data_state !HALTED");
1708         }
1709
1710         ndmda_data_stop (sess);
1711
1712         return 0;
1713       NDMS_ENDWITH
1714 }
1715
1716
1717
1718
1719 /*
1720  * NDMP[234]_DATA_START_RECOVER_FILEHIST
1721  * This is a Traakan extension to NDMPv2 and NDMPv3
1722  * Adopted for NDMPv4
1723  */
1724 int
1725 ndmp_sxa_data_start_recover_filehist (struct ndm_session *sess,
1726   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
1727 {
1728         ndmp9_error             error;
1729         int                     rc;
1730
1731       NDMS_WITH(ndmp9_data_start_recover)
1732         rc = data_ok_bu_type (sess, xa, ref_conn, request->bu_type);
1733         if (rc) {
1734                 return rc;
1735         }
1736
1737         if (request->addr.addr_type != NDMP9_ADDR_AS_CONNECTED) {
1738                 rc = data_can_connect_and_start (sess, xa, ref_conn,
1739                                 &request->addr, NDMP9_MOVER_MODE_WRITE);
1740         } else {
1741                 rc = data_can_start (sess, xa, ref_conn,
1742                                 NDMP9_MOVER_MODE_WRITE);
1743         }
1744         if (rc) {
1745                 return rc;      /* already tattled */
1746         }
1747
1748         strcpy (sess->data_acb.bu_type, request->bu_type);
1749
1750         error = data_copy_environment (sess,
1751                         request->env.env_val, request->env.env_len);
1752         if (error != NDMP9_NO_ERR) {
1753                 ndmda_belay (sess);
1754                 NDMADR_RAISE(error, "copy-env");
1755         }
1756
1757         error = data_copy_nlist (sess,
1758                 request->nlist.nlist_val, request->nlist.nlist_len);
1759
1760         if (error != NDMP9_NO_ERR) {
1761                 ndmda_belay (sess);
1762                 NDMADR_RAISE(error, "copy-nlist");
1763         }
1764
1765         if (request->addr.addr_type != NDMP9_ADDR_AS_CONNECTED) {
1766                 rc = data_connect (sess, xa, ref_conn, &request->addr);
1767                 if (rc) {
1768                         ndmda_belay (sess);
1769                         return rc;      /* already tattled */
1770                 }
1771         }
1772
1773         error = ndmda_data_start_recover_fh (sess);
1774         if (error != NDMP9_NO_ERR) {
1775                 /* TODO: undo everything */
1776                 ndmda_belay (sess);
1777                 NDMADR_RAISE(error, "start_recover_filehist");
1778         }
1779
1780         return 0;
1781       NDMS_ENDWITH
1782 }
1783
1784
1785 #ifndef NDMOS_EFFECT_NO_NDMP3_NOR_NDMP4 /* Surrounds NDMPv[34] DATA intfs */
1786 /*
1787  * NDMP[34]_DATA_CONNECT
1788  */
1789 int
1790 ndmp_sxa_data_connect (struct ndm_session *sess,
1791   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
1792 {
1793
1794       NDMS_WITH(ndmp9_data_connect)
1795         return data_connect (sess, xa, ref_conn, &request->addr);
1796       NDMS_ENDWITH
1797 }
1798
1799
1800
1801
1802 #ifdef notyet
1803 static int              data_listen_common34 (struct ndm_session *sess,
1804                                 struct ndmp_xa_buf *xa,
1805                                 struct ndmconn *ref_conn,
1806                                 ndmp9_addr_type addr_type);
1807
1808 /*
1809  * NDMP[34]_DATA_LISTEN
1810  */
1811 int
1812 ndmadr_data_listen (struct ndm_session *sess,
1813   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
1814 {
1815     struct ndm_data_agent *     da = &sess->data_acb;
1816     int                         rc;
1817
1818     switch (xa->request.protocol_version) {
1819     default: return NDMADR_UNIMPLEMENTED_VERSION; /* should never happen */
1820
1821 #ifndef NDMOS_OPTION_NO_NDMP2
1822     case NDMP2VER:
1823         /* not part of NDMPv2 */
1824         return NDMADR_UNSPECIFIED_MESSAGE;
1825 #endif /* !NDMOS_OPTION_NO_NDMP2 */
1826
1827 #ifndef NDMOS_OPTION_NO_NDMP3
1828     case NDMP3VER:
1829       NDMS_WITH(ndmp3_data_listen)
1830         ndmp9_addr_type         addr_type;
1831
1832         /* Check args, map along the way */
1833         switch (request->addr_type) {
1834         default:                addr_type = -1; break;
1835         case NDMP3_ADDR_LOCAL:  addr_type = NDMP9_ADDR_LOCAL;   break;
1836         case NDMP3_ADDR_TCP:    addr_type = NDMP9_ADDR_TCP;     break;
1837         }
1838
1839         rc = data_listen_common34 (sess, xa, ref_conn, addr_type);
1840         if (rc)
1841                 return rc;      /* something went wrong */
1842
1843         ndmp_9to3_addr (&da->data_state.data_connection_addr,
1844                                 &reply->data_connection_addr);
1845         /* reply->error already set to NDMPx_NO_ERROR */
1846       NDMS_ENDWITH
1847       break;
1848 #endif /* !NDMOS_OPTION_NO_NDMP3 */
1849
1850 #ifndef NDMOS_OPTION_NO_NDMP4
1851     case NDMP4VER:
1852       NDMS_WITH(ndmp4_data_listen)
1853         ndmp9_addr_type         addr_type;
1854
1855         /* Check args, map along the way */
1856         switch (request->addr_type) {
1857         default:                addr_type = -1; break;
1858         case NDMP4_ADDR_LOCAL:  addr_type = NDMP9_ADDR_LOCAL;   break;
1859         case NDMP4_ADDR_TCP:    addr_type = NDMP9_ADDR_TCP;     break;
1860         }
1861
1862         rc = data_listen_common34 (sess, xa, ref_conn, addr_type);
1863         if (rc)
1864                 return rc;      /* something went wrong */
1865
1866         ndmp_9to4_addr (&da->data_state.data_connection_addr,
1867                                 &reply->data_connection_addr);
1868         /* reply->error already set to NDMPx_NO_ERROR */
1869       NDMS_ENDWITH
1870       break;
1871 #endif /* !NDMOS_OPTION_NO_NDMP4 */
1872     }
1873     return 0;
1874 }
1875
1876 /* this same intf is expected in v4, so _common() now */
1877 static int
1878 data_listen_common34 (struct ndm_session *sess,
1879   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn,
1880   ndmp9_addr_type addr_type)
1881 {
1882         struct ndm_data_agent * da = &sess->data_acb;
1883 #ifndef NDMOS_OPTION_NO_TAPE_AGENT
1884         struct ndm_tape_agent * ta = &sess->tape_acb;
1885 #endif /* !NDMOS_OPTION_NO_TAPE_AGENT */
1886         ndmp9_error             error;
1887         char                    reason[100];
1888
1889         /* Check args */
1890
1891         switch (addr_type) {
1892         default:                NDMADR_RAISE_ILLEGAL_ARGS("mover_addr_type");
1893         case NDMP9_ADDR_LOCAL:
1894 #ifdef NDMOS_OPTION_NO_TAPE_AGENT
1895                 NDMADR_RAISE_ILLEGAL_ARGS("data LOCAL w/o local TAPE agent");
1896 #endif /* NDMOS_OPTION_NO_TAPE_AGENT */
1897                 break;
1898
1899         case NDMP9_ADDR_TCP:
1900                 break;
1901         }
1902
1903         /* Check states -- this should cover everything */
1904         if (da->data_state.state != NDMP9_DATA_STATE_IDLE)
1905                 NDMADR_RAISE_ILLEGAL_STATE("data_state !IDLE");
1906 #ifndef NDMOS_OPTION_NO_TAPE_AGENT
1907         if (ta->mover_state.state != NDMP9_MOVER_STATE_IDLE)
1908                 NDMADR_RAISE_ILLEGAL_STATE("mover_state !IDLE");
1909 #endif /* !NDMOS_OPTION_NO_TAPE_AGENT */
1910
1911         /*
1912          * Check image stream state -- should already be reflected
1913          * in the mover and data states. This extra check gives
1914          * us an extra measure of robustness and sanity
1915          * check on the implementation.
1916          */
1917         error = ndmis_audit_data_listen (sess, addr_type, reason);
1918         if (error != NDMP9_NO_ERR) NDMADR_RAISE(error, reason);
1919
1920         error = ndmis_data_listen (sess, addr_type,
1921                         &da->data_state.data_connection_addr,
1922                         reason);
1923         if (error != NDMP9_NO_ERR) NDMADR_RAISE(error, reason);
1924
1925         error = ndmda_data_listen(sess);
1926         if (error != NDMP9_NO_ERR) {
1927                 /* TODO: belay ndmis_data_listen() */
1928                 NDMADR_RAISE(error, "!data_listen");
1929         }
1930
1931         return 0;
1932 }
1933 #endif /* notyet */
1934
1935 #endif /* !NDMOS_EFFECT_NO_NDMP3_NOR_NDMP4  Surrounds NDMPv[34] DATA intfs */
1936
1937
1938
1939
1940 /*
1941  * NDMPx_DATA helper routines
1942  */
1943
1944
1945 static int
1946 data_ok_bu_type (struct ndm_session *sess,
1947   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn,
1948   char *bu_type)
1949 {
1950         ndmp9_config_info *     ci = &sess->config_info;
1951         ndmp9_butype_info *     bu;
1952         unsigned int            i;
1953
1954         ndmos_sync_config_info (sess);
1955
1956         for (i = 0; i < ci->butype_info.butype_info_len; i++) {
1957                 bu = &ci->butype_info.butype_info_val[i];
1958
1959                 if (strcmp (bu_type, bu->butype_name) == 0) {
1960                         return 0;
1961                 }
1962         }
1963
1964         NDMADR_RAISE_ILLEGAL_ARGS ("bu_type");
1965 }
1966
1967
1968 /*
1969  * Data can only start if the mover is ready.
1970  * Just mode and state checks.
1971  */
1972
1973 static int
1974 data_can_connect_and_start (struct ndm_session *sess,
1975   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn,
1976   ndmp9_addr *data_addr,
1977   ndmp9_mover_mode mover_mode)
1978 {
1979         int                     rc;
1980
1981         /* Check args */
1982         switch (mover_mode) {
1983         default:                NDMADR_RAISE_ILLEGAL_ARGS("mover_mode");
1984         case NDMP9_MOVER_MODE_READ:     /* aka BACKUP */
1985         case NDMP9_MOVER_MODE_WRITE:    /* aka RECOVER */
1986                 break;
1987         }
1988
1989         rc = data_can_connect (sess, xa, ref_conn, data_addr);
1990         if (rc) return rc;
1991
1992 #ifndef NDMOS_OPTION_NO_TAPE_AGENT
1993         if (data_addr->addr_type == NDMP9_ADDR_LOCAL) {
1994                 struct ndm_tape_agent *         ta = &sess->tape_acb;
1995                 ndmp9_mover_get_state_reply *   ms = &ta->mover_state;
1996
1997                 if (ms->mode != mover_mode)
1998                         NDMADR_RAISE_ILLEGAL_STATE("mover_mode mismatch");
1999         }
2000 #endif /* !NDMOS_OPTION_NO_TAPE_AGENT */
2001
2002         return 0;
2003 }
2004
2005 static int
2006 data_can_connect (struct ndm_session *sess,
2007   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn,
2008   ndmp9_addr *data_addr)
2009 {
2010         struct ndm_data_agent * da = &sess->data_acb;
2011 #ifndef NDMOS_OPTION_NO_TAPE_AGENT
2012         struct ndm_tape_agent * ta = &sess->tape_acb;
2013 #endif /* !NDMOS_OPTION_NO_TAPE_AGENT */
2014         ndmp9_error             error;
2015         char                    reason[100];
2016
2017         /* Check args */
2018         switch (data_addr->addr_type) {
2019         default:                NDMADR_RAISE_ILLEGAL_ARGS("addr_type");
2020         case NDMP9_ADDR_LOCAL:
2021 #ifdef NDMOS_OPTION_NO_TAPE_AGENT
2022                 NDMADR_RAISE_ILLEGAL_ARGS("mover LOCAL w/o local DATA agent");
2023 #endif /* NDMOS_OPTION_NO_TAPE_AGENT */
2024                 break;
2025
2026         case NDMP9_ADDR_TCP:
2027                 break;
2028         }
2029
2030         /* Check states -- this should cover everything */
2031         if (da->data_state.state != NDMP9_DATA_STATE_IDLE)
2032                 NDMADR_RAISE_ILLEGAL_STATE("data_state !IDLE");
2033
2034 #ifndef NDMOS_OPTION_NO_TAPE_AGENT
2035         if (data_addr->addr_type == NDMP9_ADDR_LOCAL) {
2036                 ndmp9_mover_get_state_reply *ms = &ta->mover_state;
2037
2038                 if (ms->state != NDMP9_MOVER_STATE_LISTEN)
2039                         NDMADR_RAISE_ILLEGAL_STATE("mover_state !LISTEN");
2040
2041                 if (ms->data_connection_addr.addr_type != NDMP9_ADDR_LOCAL)
2042                         NDMADR_RAISE_ILLEGAL_STATE("mover_addr !LOCAL");
2043
2044         } else {
2045                 if (ta->mover_state.state != NDMP9_MOVER_STATE_IDLE)
2046                         NDMADR_RAISE_ILLEGAL_STATE("mover_state !IDLE");
2047         }
2048 #endif /* !NDMOS_OPTION_NO_TAPE_AGENT */
2049
2050         /*
2051          * Check image stream state -- should already be reflected
2052          * in the mover and data states. This extra check gives
2053          * us an extra measure of robustness and sanity
2054          * check on the implementation.
2055          */
2056         error = ndmis_audit_data_connect (sess, data_addr->addr_type, reason);
2057         if (error != NDMP9_NO_ERR) NDMADR_RAISE(error, reason);
2058
2059         return 0;
2060 }
2061
2062 static int
2063 data_can_start (struct ndm_session *sess,
2064   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn,
2065   ndmp9_mover_mode mover_mode)
2066 {
2067         struct ndm_data_agent * da = &sess->data_acb;
2068         ndmp9_data_get_state_reply *ds = &da->data_state;
2069 #ifndef NDMOS_OPTION_NO_TAPE_AGENT
2070         struct ndm_tape_agent * ta = &sess->tape_acb;
2071 #endif /* !NDMOS_OPTION_NO_TAPE_AGENT */
2072
2073         /* Check args */
2074         switch (mover_mode) {
2075         default:                NDMADR_RAISE_ILLEGAL_ARGS("mover_mode");
2076         case NDMP9_MOVER_MODE_READ:     /* aka BACKUP */
2077         case NDMP9_MOVER_MODE_WRITE:    /* aka RECOVER */
2078                 break;
2079         }
2080
2081         /* Check states -- this should cover everything */
2082         if (da->data_state.state != NDMP9_DATA_STATE_CONNECTED)
2083                 NDMADR_RAISE_ILLEGAL_STATE("data_state !CONNECTED");
2084
2085 #ifndef NDMOS_OPTION_NO_TAPE_AGENT
2086         if (ds->data_connection_addr.addr_type == NDMP9_ADDR_LOCAL) {
2087                 ndmp9_mover_get_state_reply *ms = &ta->mover_state;
2088
2089                 if (ms->state != NDMP9_MOVER_STATE_ACTIVE)
2090                         NDMADR_RAISE_ILLEGAL_STATE("mover_state !ACTIVE");
2091
2092                 if (ms->data_connection_addr.addr_type != NDMP9_ADDR_LOCAL)
2093                         NDMADR_RAISE_ILLEGAL_STATE("mover_addr !LOCAL");
2094
2095                 if (ms->mode != mover_mode)
2096                         NDMADR_RAISE_ILLEGAL_STATE("mover_mode mismatch");
2097         } else {
2098                 if (ta->mover_state.state != NDMP9_MOVER_STATE_IDLE)
2099                         NDMADR_RAISE_ILLEGAL_STATE("mover_state !IDLE");
2100         }
2101 #endif /* !NDMOS_OPTION_NO_TAPE_AGENT */
2102
2103         return 0;
2104 }
2105
2106 /*
2107  * For NDMPv2, called from ndmadr_data_start_{backup,recover,recover_filhist}()
2108  * For NDMPv[34], called from ndmp_sxa_data_connect()
2109  */
2110 static int
2111 data_connect (struct ndm_session *sess,
2112   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn,
2113   ndmp9_addr *data_addr)
2114 {
2115         struct ndm_data_agent * da = &sess->data_acb;
2116         int                     rc;
2117         ndmp9_error             error;
2118         char                    reason[100];
2119
2120         rc = data_can_connect (sess, xa, ref_conn, data_addr);
2121         if (rc)
2122                 return rc;
2123
2124         /*
2125          * Audits done, connect already
2126          */
2127         error = ndmis_data_connect (sess, data_addr, reason);
2128         if (error != NDMP9_NO_ERR) NDMADR_RAISE(error, reason);
2129
2130         da->data_state.data_connection_addr = *data_addr;
2131         /* alt: da->....data_connection_addr = sess->...peer_addr */
2132
2133         error = ndmda_data_connect (sess);
2134         if (error != NDMP9_NO_ERR) {
2135                 /* TODO: belay ndmis_data_connect() */
2136                 NDMADR_RAISE(error, "!data_connect");
2137         }
2138
2139         da->data_state.data_connection_addr = *data_addr;
2140
2141         return 0;
2142 }
2143
2144 static ndmp9_error
2145 data_copy_environment (struct ndm_session *sess,
2146   ndmp9_pval *env, unsigned n_env)
2147 {
2148         int                     rc;
2149
2150         if (n_env > NDM_MAX_ENV)
2151                 return NDMP9_ILLEGAL_ARGS_ERR;
2152
2153         rc = ndmda_copy_environment (sess, env, n_env);
2154         if (rc != 0)
2155                 return NDMP9_NO_MEM_ERR;
2156
2157         return NDMP9_NO_ERR;
2158 }
2159
2160 static ndmp9_error
2161 data_copy_nlist (struct ndm_session *sess,
2162   ndmp9_name *nlist, unsigned n_nlist)
2163 {
2164         int                     rc;
2165
2166         if (n_nlist >= NDM_MAX_NLIST)
2167                 return NDMP9_ILLEGAL_ARGS_ERR;
2168
2169         rc = ndmda_copy_nlist (sess, nlist, n_nlist);
2170         if (rc != 0)
2171                 return NDMP9_NO_MEM_ERR;
2172
2173         return NDMP9_NO_ERR;
2174 }
2175
2176
2177 #endif /* !NDMOS_OPTION_NO_DATA_AGENT */        /* Surrounds DATA intfs */
2178
2179
2180
2181
2182 #ifndef NDMOS_OPTION_NO_TAPE_AGENT              /* Surrounds MOVER intfs */
2183 /*
2184  * NDMPx_MOVER Interfaces
2185  ****************************************************************
2186  */
2187
2188 static ndmp9_error      mover_can_proceed (struct ndm_session *sess,
2189                                 int will_write);
2190
2191
2192
2193
2194
2195
2196
2197 /*
2198  * NDMP[234]_MOVER_GET_STATE
2199  */
2200 int
2201 ndmp_sxa_mover_get_state (struct ndm_session *sess,
2202   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
2203 {
2204         struct ndm_tape_agent * ta = &sess->tape_acb;
2205
2206       NDMS_WITH_VOID_REQUEST(ndmp9_mover_get_state)
2207         ndmta_mover_sync_state(sess);
2208         *reply = ta->mover_state;
2209         return 0;
2210       NDMS_ENDWITH
2211 }
2212
2213
2214
2215
2216 /*
2217  * NDMP[234]_MOVER_LISTEN
2218  */
2219 int
2220 ndmp_sxa_mover_listen (struct ndm_session *sess,
2221   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
2222 {
2223 #ifndef NDMOS_OPTION_NO_DATA_AGENT
2224         struct ndm_data_agent * da = &sess->data_acb;
2225 #endif /* !NDMOS_OPTION_NO_DATA_AGENT */
2226         struct ndm_tape_agent * ta = &sess->tape_acb;
2227         ndmp9_error             error;
2228         int                     will_write;
2229         char                    reason[100];
2230
2231       NDMS_WITH(ndmp9_mover_listen)
2232         ndmalogf (sess, 0, 6, "mover_listen_common() addr_type=%s mode=%s",
2233                         ndmp9_addr_type_to_str (request->addr_type),
2234                         ndmp9_mover_mode_to_str (request->mode));
2235
2236         /* Check args */
2237         switch (request->mode) {
2238         default:
2239                 NDMADR_RAISE_ILLEGAL_ARGS("mover_mode");
2240
2241         case NDMP9_MOVER_MODE_READ:
2242                 will_write = 1;
2243                 break;
2244
2245         case NDMP9_MOVER_MODE_WRITE:
2246                 will_write = 0;
2247                 break;
2248         }
2249
2250         switch (request->addr_type) {
2251         default:
2252                 NDMADR_RAISE_ILLEGAL_ARGS("mover_addr_type");
2253
2254         case NDMP9_ADDR_LOCAL:
2255 #ifdef NDMOS_OPTION_NO_DATA_AGENT
2256                 NDMADR_RAISE_ILLEGAL_ARGS("mover LOCAL w/o local DATA agent");
2257 #endif /* NDMOS_OPTION_NO_DATA_AGENT */
2258                 break;
2259
2260         case NDMP9_ADDR_TCP:
2261                 break;
2262         }
2263
2264         /* Check states -- this should cover everything */
2265         if (ta->mover_state.state != NDMP9_MOVER_STATE_IDLE) {
2266                 NDMADR_RAISE_ILLEGAL_STATE("mover_state !IDLE");
2267         }
2268 #ifndef NDMOS_OPTION_NO_DATA_AGENT
2269         if (da->data_state.state != NDMP9_DATA_STATE_IDLE) {
2270                 NDMADR_RAISE_ILLEGAL_STATE("data_state !IDLE");
2271         }
2272 #endif /* !NDMOS_OPTION_NO_DATA_AGENT */
2273
2274         /* Check that the tape is ready to go */
2275         error = mover_can_proceed (sess, will_write);
2276         if (error != NDMP9_NO_ERR) {
2277                 NDMADR_RAISE(error, "!mover_can_proceed");
2278         }
2279
2280         /*
2281          * Check image stream state -- should already be reflected
2282          * in the mover and data states. This extra check gives
2283          * us an extra measure of robustness and sanity
2284          * check on the implementation.
2285          */
2286         error = ndmis_audit_tape_listen (sess, request->addr_type, reason);
2287         if (error != NDMP9_NO_ERR) {
2288                 NDMADR_RAISE(error, reason);
2289         }
2290
2291         error = ndmis_tape_listen (sess, request->addr_type,
2292                         &ta->mover_state.data_connection_addr,
2293                         reason);
2294         if (error != NDMP9_NO_ERR) {
2295                 NDMADR_RAISE(error, reason);
2296         }
2297
2298         error = ndmta_mover_listen(sess, request->mode);
2299         if (error != NDMP9_NO_ERR) {
2300                 /* TODO: belay ndmis_tape_listen() */
2301                 NDMADR_RAISE(error, "!mover_listen");
2302         }
2303
2304         reply->data_connection_addr = ta->mover_state.data_connection_addr;
2305
2306         return 0;
2307       NDMS_ENDWITH
2308 }
2309
2310
2311
2312
2313 /*
2314  * NDMP[234]_MOVER_CONTINUE
2315  */
2316 int
2317 ndmp_sxa_mover_continue (struct ndm_session *sess,
2318   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
2319 {
2320         struct ndm_tape_agent * ta = &sess->tape_acb;
2321         ndmp9_error             error;
2322         int                     will_write;
2323
2324       NDMS_WITH_VOID_REQUEST(ndmp9_mover_continue)
2325         if (ta->mover_state.state != NDMP9_MOVER_STATE_PAUSED) {
2326                 NDMADR_RAISE_ILLEGAL_STATE("mover_state !PAUSED");
2327         }
2328
2329         will_write = ta->mover_state.mode == NDMP9_MOVER_MODE_READ;
2330
2331         error = mover_can_proceed (sess, will_write);
2332         if (error != NDMP9_NO_ERR) {
2333                 NDMADR_RAISE(error, "!mover_can_proceed");
2334         }
2335
2336         ndmta_mover_continue (sess);
2337
2338         return 0;
2339       NDMS_ENDWITH
2340 }
2341
2342
2343
2344
2345 /*
2346  * NDMP[234]_MOVER_ABORT
2347  */
2348 int
2349 ndmp_sxa_mover_abort (struct ndm_session *sess,
2350   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
2351 {
2352         struct ndm_tape_agent * ta = &sess->tape_acb;
2353
2354       NDMS_WITH_VOID_REQUEST(ndmp9_mover_abort)
2355         if (ta->mover_state.state != NDMP9_MOVER_STATE_LISTEN
2356          && ta->mover_state.state != NDMP9_MOVER_STATE_ACTIVE
2357          && ta->mover_state.state != NDMP9_MOVER_STATE_PAUSED) {
2358                 NDMADR_RAISE_ILLEGAL_STATE("mover_state");
2359         }
2360
2361         ndmta_mover_abort (sess);
2362
2363         return 0;
2364       NDMS_ENDWITH
2365 }
2366
2367
2368
2369
2370 /*
2371  * NDMP[234]_MOVER_STOP
2372  */
2373 int
2374 ndmp_sxa_mover_stop (struct ndm_session *sess,
2375   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
2376 {
2377         struct ndm_tape_agent * ta = &sess->tape_acb;
2378
2379       NDMS_WITH_VOID_REQUEST(ndmp9_mover_stop)
2380         if (ta->mover_state.state != NDMP9_MOVER_STATE_HALTED) {
2381                 NDMADR_RAISE_ILLEGAL_STATE("mover_state !HALTED");
2382         }
2383
2384         ndmta_mover_stop (sess);
2385
2386         return 0;
2387       NDMS_ENDWITH
2388 }
2389
2390
2391
2392
2393 /*
2394  * NDMP[234]_MOVER_SET_WINDOW
2395  */
2396 int
2397 ndmp_sxa_mover_set_window (struct ndm_session *sess,
2398   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
2399 {
2400         struct ndm_tape_agent * ta = &sess->tape_acb;
2401         struct ndmp9_mover_get_state_reply *ms = &ta->mover_state;
2402         unsigned long long      max_len;
2403         unsigned long long      end_win;
2404
2405       NDMS_WITH(ndmp9_mover_set_window)
2406         ndmta_mover_sync_state (sess);
2407
2408         if (ref_conn->protocol_version < NDMP4VER) {
2409                 /*
2410                  * NDMP[23] require the Mover be in LISTEN state.
2411                  * Unclear sequence for MOVER_CONNECT.
2412                  */
2413                 if (ms->state != NDMP9_MOVER_STATE_LISTEN
2414                  && ms->state != NDMP9_MOVER_STATE_PAUSED) {
2415                         NDMADR_RAISE_ILLEGAL_STATE("mover_state !LISTEN/PAUSED");
2416                 }
2417         } else {
2418                 /*
2419                  * NDMP4 require the Mover be in IDLE state.
2420                  * This always preceeds both MOVER_LISTEN or
2421                  * MOVER_CONNECT.
2422                  */
2423                 if (ms->state != NDMP9_MOVER_STATE_IDLE
2424                  && ms->state != NDMP9_MOVER_STATE_PAUSED) {
2425                         NDMADR_RAISE_ILLEGAL_STATE("mover_state !IDLE/PAUSED");
2426                 }
2427         }
2428
2429         if (request->offset % ms->record_size != 0) {
2430                 NDMADR_RAISE_ILLEGAL_ARGS("off !record_size");
2431         }
2432
2433         /* TODO: NDMPv4 subtle semantic changes here */
2434
2435         /* If a maximum length window is required following a mover transition
2436          * to the PAUSED state, a window length of all ones (binary) minus the
2437          * current window offset MUST be specified." (NDMPv4 RFC, Section
2438          * 3.6.2.2) -- we allow length = NDMP_LENGTH_INFINITY too */
2439
2440         if (request->length != NDMP_LENGTH_INFINITY
2441                 && request->length + request->offset != NDMP_LENGTH_INFINITY) {
2442                 if (request->length % ms->record_size != 0) {
2443                         NDMADR_RAISE_ILLEGAL_ARGS("len !record_size");
2444                 }
2445 #if 0
2446                 /* Too pedantic. Sometimes needed (like for testing) */
2447                 if (request->length == 0) {
2448                         NDMADR_RAISE_ILLEGAL_ARGS("length 0");
2449                 }
2450 #endif
2451
2452                 max_len = NDMP_LENGTH_INFINITY - request->offset;
2453                 max_len -= max_len % ms->record_size;
2454                 if (request->length > max_len) {  /* learn math fella */
2455                         NDMADR_RAISE_ILLEGAL_ARGS("length too long");
2456                 }
2457                 end_win = request->offset + request->length;
2458         } else {
2459                 end_win = NDMP_LENGTH_INFINITY;
2460         }
2461         ms->window_offset = request->offset;
2462         /* record_num should probably be one less than this value, but the spec
2463          * says to divide, so we divide */
2464         ms->record_num = request->offset / ms->record_size;
2465         ms->window_length = request->length;
2466         ta->mover_window_end = end_win;
2467         ta->mover_window_first_blockno = ta->tape_state.blockno.value;
2468
2469         return 0;
2470       NDMS_ENDWITH
2471 }
2472
2473
2474
2475
2476 /*
2477  * NDMP[234]_MOVER_READ
2478  */
2479 int
2480 ndmp_sxa_mover_read (struct ndm_session *sess,
2481   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
2482 {
2483         struct ndm_tape_agent * ta = &sess->tape_acb;
2484         struct ndmp9_mover_get_state_reply *ms = &ta->mover_state;
2485
2486       NDMS_WITH(ndmp9_mover_read)
2487         ndmta_mover_sync_state (sess);
2488
2489         if (ms->state != NDMP9_MOVER_STATE_ACTIVE) {
2490                 NDMADR_RAISE_ILLEGAL_STATE("mover_state !ACTIVE");
2491         }
2492
2493         if (ms->bytes_left_to_read > 0) {
2494                 NDMADR_RAISE_ILLEGAL_STATE("byte_left_to_read");
2495         }
2496
2497         if (ms->data_connection_addr.addr_type != NDMP9_ADDR_TCP) {
2498                 NDMADR_RAISE_ILLEGAL_STATE("mover_addr !TCP");
2499         }
2500
2501         if (ms->mode != NDMP9_MOVER_MODE_WRITE) {
2502                 NDMADR_RAISE_ILLEGAL_STATE("mover_mode !WRITE");
2503         }
2504
2505         ndmta_mover_read (sess, request->offset, request->length);
2506
2507         return 0;
2508       NDMS_ENDWITH
2509 }
2510
2511
2512
2513
2514 /*
2515  * NDMP[234]_MOVER_CLOSE
2516  */
2517 int
2518 ndmp_sxa_mover_close (struct ndm_session *sess,
2519   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
2520 {
2521         struct ndm_tape_agent * ta = &sess->tape_acb;
2522
2523       NDMS_WITH_VOID_REQUEST(ndmp9_mover_close) {
2524         if (ta->mover_state.state == NDMP9_MOVER_STATE_IDLE)
2525                 NDMADR_RAISE_ILLEGAL_STATE("mover_state !IDLE");
2526         }
2527
2528         ndmta_mover_close (sess);
2529
2530         return 0;
2531       NDMS_ENDWITH
2532 }
2533
2534
2535
2536
2537 /*
2538  * NDMP[234]_MOVER_SET_RECORD_SIZE
2539  */
2540 int
2541 ndmp_sxa_mover_set_record_size (struct ndm_session *sess,
2542   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
2543 {
2544         struct ndm_tape_agent * ta = &sess->tape_acb;
2545         struct ndmp9_mover_get_state_reply *ms = &ta->mover_state;
2546
2547       NDMS_WITH(ndmp9_mover_set_record_size)
2548         ndmta_mover_sync_state (sess);
2549
2550         if (ms->state != NDMP9_MOVER_STATE_IDLE
2551          && ms->state != NDMP9_MOVER_STATE_PAUSED)
2552                 NDMADR_RAISE_ILLEGAL_STATE("mover_state !IDLE/PAUSED");
2553
2554         if (!NDMOS_MACRO_OK_TAPE_REC_LEN(request->record_size))
2555                 NDMADR_RAISE_ILLEGAL_ARGS("!ok_tape_rec_len");
2556
2557         ta->mover_state.record_size = request->record_size;
2558
2559         return 0;
2560       NDMS_ENDWITH
2561 }
2562
2563
2564
2565 #ifndef NDMOS_EFFECT_NO_NDMP3_NOR_NDMP4 /* Surrounds NDMPv[34] MOVER intfs */
2566
2567 static int              mover_connect_common34 (struct ndm_session *sess,
2568                                 struct ndmp_xa_buf *xa,
2569                                 struct ndmconn *ref_conn,
2570                                 ndmp9_addr *addr,
2571                                 ndmp9_mover_mode mover_mode);
2572
2573 /*
2574  * NDMP[34]_MOVER_CONNECT
2575  */
2576 int
2577 ndmp_sxa_mover_connect (struct ndm_session *sess,
2578   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
2579 {
2580 #ifndef NDMOS_OPTION_NO_DATA_AGENT
2581         struct ndm_data_agent * da = &sess->data_acb;
2582 #endif /* !NDMOS_OPTION_NO_DATA_AGENT */
2583         struct ndm_tape_agent * ta = &sess->tape_acb;
2584         ndmp9_error             error;
2585         int                     will_write;
2586         char                    reason[100];
2587
2588       NDMS_WITH(ndmp9_mover_connect)
2589
2590         /* Check args */
2591         switch (request->mode) {
2592         default:                NDMADR_RAISE_ILLEGAL_ARGS("mover_mode");
2593         case NDMP9_MOVER_MODE_READ:
2594                 will_write = 1;
2595                 break;
2596
2597         case NDMP9_MOVER_MODE_WRITE:
2598                 will_write = 0;
2599                 break;
2600         }
2601
2602         switch (request->addr.addr_type) {
2603         default:                NDMADR_RAISE_ILLEGAL_ARGS("mover_addr_type");
2604         case NDMP9_ADDR_LOCAL:
2605 #ifdef NDMOS_OPTION_NO_DATA_AGENT
2606                 NDMADR_RAISE_ILLEGAL_ARGS("mover LOCAL w/o local DATA agent");
2607 #endif /* NDMOS_OPTION_NO_DATA_AGENT */
2608                 break;
2609
2610         case NDMP9_ADDR_TCP:
2611                 break;
2612         }
2613
2614         /* Check states -- this should cover everything */
2615         if (ta->mover_state.state != NDMP9_MOVER_STATE_IDLE)
2616                 NDMADR_RAISE_ILLEGAL_STATE("mover_state !IDLE");
2617 #ifndef NDMOS_OPTION_NO_DATA_AGENT
2618         if (request->addr.addr_type == NDMP9_ADDR_LOCAL) {
2619                 ndmp9_data_get_state_reply *ds = &da->data_state;
2620
2621                 if (ds->state != NDMP9_DATA_STATE_LISTEN)
2622                         NDMADR_RAISE_ILLEGAL_STATE("data_state !LISTEN");
2623
2624                 if (ds->data_connection_addr.addr_type != NDMP9_ADDR_LOCAL)
2625                         NDMADR_RAISE_ILLEGAL_STATE("data_addr !LOCAL");
2626         } else {
2627                 if (da->data_state.state != NDMP9_DATA_STATE_IDLE)
2628                         NDMADR_RAISE_ILLEGAL_STATE("data_state !IDLE");
2629         }
2630 #endif /* !NDMOS_OPTION_NO_DATA_AGENT */
2631
2632         /* Check that the tape is ready to go */
2633         error = mover_can_proceed (sess, will_write);
2634         if (error != NDMP9_NO_ERR) NDMADR_RAISE(error, "!mover_can_proceed");
2635
2636         /*
2637          * Check image stream state -- should already be reflected
2638          * in the mover and data states. This extra check gives
2639          * us an extra measure of robustness and sanity
2640          * check on the implementation.
2641          */
2642         error = ndmis_audit_tape_connect (sess, request->addr.addr_type, reason);
2643         if (error != NDMP9_NO_ERR) NDMADR_RAISE(error, reason);
2644
2645         error = ndmis_tape_connect (sess, &request->addr, reason);
2646         if (error != NDMP9_NO_ERR) NDMADR_RAISE(error, reason);
2647
2648         ta->mover_state.data_connection_addr = request->addr;
2649         /* alt: ta->....data_connection_addr = sess->...peer_addr */
2650
2651         error = ndmta_mover_connect (sess, request->mode);
2652         if (error != NDMP9_NO_ERR) {
2653                 /* TODO: belay ndmis_tape_connect() */
2654                 NDMADR_RAISE(error, "!mover_connect");
2655         }
2656
2657         return 0;
2658       NDMS_ENDWITH
2659 }
2660 #endif /* !NDMOS_EFFECT_NO_NDMP3_NOR_NDMP4  Surrounds NDMPv[34] MOVER intfs */
2661
2662
2663
2664 /*
2665  * NDMPx_MOVER helper routines
2666  */
2667
2668 /*
2669  * MOVER can only proceed from IDLE->LISTEN or PAUSED->ACTIVE
2670  * if the tape drive is ready.
2671  */
2672
2673 static ndmp9_error
2674 mover_can_proceed (struct ndm_session *sess, int will_write)
2675 {
2676         struct ndm_tape_agent *         ta = &sess->tape_acb;
2677
2678         ndmos_tape_sync_state(sess);
2679         if (ta->tape_state.state != NDMP9_TAPE_STATE_OPEN)
2680                 return NDMP9_DEV_NOT_OPEN_ERR;
2681
2682         if (will_write && !NDMTA_TAPE_IS_WRITABLE(ta))
2683                 return NDMP9_PERMISSION_ERR;
2684
2685         return NDMP9_NO_ERR;
2686 }
2687
2688 #endif /* !NDMOS_OPTION_NO_TAPE_AGENT */        /* Surrounds MOVER intfs */
2689
2690
2691
2692
2693 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT           /* Surrounds NOTIFY intfs */
2694 /*
2695  * NDMPx_NOTIFY Interfaces
2696  ****************************************************************
2697  */
2698
2699
2700
2701
2702 /*
2703  * NDMP[234]_NOTIFY_DATA_HALTED
2704  */
2705 int
2706 ndmp_sxa_notify_data_halted (struct ndm_session *sess,
2707   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
2708 {
2709         struct ndm_control_agent *ca = &sess->control_acb;
2710
2711       NDMS_WITH_NO_REPLY(ndmp9_notify_data_halted)
2712         xa->reply.flags |= NDMNMB_FLAG_NO_SEND;
2713
2714         ca->pending_notify_data_halted++;
2715
2716         return 0;
2717       NDMS_ENDWITH
2718 }
2719
2720
2721
2722
2723 /*
2724  * NDMP[234]_NOTIFY_CONNECTED
2725  */
2726 int
2727 ndmp_sxa_notify_connected (struct ndm_session *sess,
2728   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
2729 {
2730       NDMS_WITH_NO_REPLY(ndmp9_notify_connected)
2731         xa->reply.flags |= NDMNMB_FLAG_NO_SEND;
2732         /* Just ignore? */
2733         return 0;
2734       NDMS_ENDWITH
2735 }
2736
2737
2738
2739
2740 /*
2741  * NDMP[234]_NOTIFY_MOVER_HALTED
2742  */
2743 int
2744 ndmp_sxa_notify_mover_halted (struct ndm_session *sess,
2745   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
2746 {
2747         struct ndm_control_agent *      ca = &sess->control_acb;
2748
2749       NDMS_WITH_NO_REPLY(ndmp9_notify_mover_halted)
2750         xa->reply.flags |= NDMNMB_FLAG_NO_SEND;
2751
2752         ca->pending_notify_mover_halted++;
2753
2754         return 0;
2755       NDMS_ENDWITH
2756 }
2757
2758
2759
2760
2761 /*
2762  * NDMP[234]_NOTIFY_MOVER_PAUSED
2763  */
2764 int
2765 ndmp_sxa_notify_mover_paused (struct ndm_session *sess,
2766   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
2767 {
2768         struct ndm_control_agent *      ca = &sess->control_acb;
2769
2770       NDMS_WITH_NO_REPLY(ndmp9_notify_mover_paused)
2771         xa->reply.flags |= NDMNMB_FLAG_NO_SEND;
2772
2773         ca->pending_notify_mover_paused++;
2774         ca->last_notify_mover_paused.reason = request->reason;
2775         ca->last_notify_mover_paused.seek_position = request->seek_position;
2776
2777         return 0;
2778       NDMS_ENDWITH
2779 }
2780
2781
2782
2783
2784 /*
2785  * NDMP[234]_NOTIFY_DATA_READ
2786  */
2787 int
2788 ndmp_sxa_notify_data_read (struct ndm_session *sess,
2789   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
2790 {
2791         struct ndm_control_agent *      ca = &sess->control_acb;
2792
2793       NDMS_WITH_NO_REPLY(ndmp9_notify_data_read)
2794         xa->reply.flags |= NDMNMB_FLAG_NO_SEND;
2795
2796         ca->pending_notify_data_read++;
2797         ca->last_notify_data_read.offset = request->offset;
2798         ca->last_notify_data_read.length = request->length;
2799
2800         return 0;
2801       NDMS_ENDWITH
2802 }
2803 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */     /* Surrounds NOTIFY intfs */
2804
2805
2806
2807
2808 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT           /* Surrounds LOG intfs */
2809 /*
2810  * NDMPx_LOG Interfaces
2811  ****************************************************************
2812  */
2813
2814
2815
2816 /*
2817  * NDMP[234]_LOG_FILE
2818  */
2819 int
2820 ndmp_sxa_log_file (struct ndm_session *sess,
2821   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
2822 {
2823         struct ndm_control_agent *ca = &sess->control_acb;
2824         char                    prefix[32];
2825         char *                  tag;
2826         int                     lev = 0;
2827
2828         xa->reply.flags |= NDMNMB_FLAG_NO_SEND;
2829
2830         NDMS_WITH_NO_REPLY(ndmp9_log_file)
2831                 switch (request->recovery_status) {
2832                 case NDMP9_RECOVERY_SUCCESSFUL:
2833                         tag =  "OK";
2834                         lev = 1;
2835                         break;
2836
2837                 case NDMP9_RECOVERY_FAILED_PERMISSION:
2838                         tag =  "Bad Permission";
2839                         break;
2840
2841                 case NDMP9_RECOVERY_FAILED_NOT_FOUND:
2842                         tag =  "Not found";
2843                         break;
2844
2845                 case NDMP9_RECOVERY_FAILED_NO_DIRECTORY:
2846                         tag =  "No directory";
2847                         break;
2848
2849                 case NDMP9_RECOVERY_FAILED_OUT_OF_MEMORY:
2850                         tag =  "Out of mem";
2851                         break;
2852
2853                 case NDMP9_RECOVERY_FAILED_IO_ERROR:
2854                         tag =  "I/O error";
2855                         break;
2856
2857                 case NDMP9_RECOVERY_FAILED_UNDEFINED_ERROR:
2858                         tag =  "General error";
2859                         break;
2860
2861                 default:
2862                         tag =  "n";
2863                         break;
2864                 }
2865
2866                 /* count the notification and whether it is good news or not */
2867                 ca->recover_log_file_count++;
2868                 if (lev == 1) {
2869                     ca->recover_log_file_ok++;
2870                 } else {
2871                     ca->recover_log_file_error++;
2872                 }
2873
2874                 sprintf (prefix, "%cLF", ref_conn->chan.name[1]);
2875
2876                 ndmalogf (sess, prefix, lev, "%s: %s", tag, request->name);
2877         NDMS_ENDWITH
2878
2879         return 0;
2880 }
2881
2882
2883
2884
2885 #ifndef NDMOS_OPTION_NO_NDMP2
2886 /*
2887  * NDMP2_LOG_LOG
2888  */
2889 int
2890 ndmp2_sxa_log_log (struct ndm_session *sess,
2891   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
2892 {
2893         char                    prefix[32];
2894         char *                  tag;
2895         int                     lev;
2896
2897         xa->reply.flags |= NDMNMB_FLAG_NO_SEND;
2898
2899         NDMS_WITH_NO_REPLY(ndmp2_log_log)
2900                 tag =  "n";
2901                 lev = 1;
2902
2903                 sprintf (prefix, "%cLM%s", ref_conn->chan.name[1], tag);
2904
2905                 ndmalogf (sess, prefix, lev, "LOG_LOG: '%s'", request->entry);
2906         NDMS_ENDWITH
2907
2908         return 0;
2909 }
2910
2911 /*
2912  * NDMP2_LOG_DEBUG
2913  */
2914 int
2915 ndmp2_sxa_log_debug (struct ndm_session *sess,
2916   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
2917 {
2918         char                    prefix[32];
2919         char *                  tag;
2920         int                     lev;
2921
2922         xa->reply.flags |= NDMNMB_FLAG_NO_SEND;
2923
2924         NDMS_WITH_NO_REPLY(ndmp2_log_debug)
2925                 tag =  "d";
2926                 lev = 2;
2927
2928                 sprintf (prefix, "%cLM%s", ref_conn->chan.name[1], tag);
2929
2930                 ndmalogf (sess, prefix, lev, "LOG_DEBUG: '%s'", request->message);
2931         NDMS_ENDWITH
2932
2933         return 0;
2934 }
2935
2936 #endif /* !NDMOS_OPTION_NO_NDMP2 */
2937
2938
2939
2940
2941 /*
2942  * NDMP[34]_LOG_MESSAGE
2943  */
2944 int
2945 ndmp_sxa_log_message (struct ndm_session *sess,
2946   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
2947 {
2948         char                    prefix[32];
2949         char *                  tag;
2950         int                     lev;
2951
2952         xa->reply.flags |= NDMNMB_FLAG_NO_SEND;
2953
2954         NDMS_WITH_NO_REPLY(ndmp9_log_message)
2955                 switch (request->log_type) {
2956                 case NDMP9_LOG_NORMAL:
2957                         tag =  "n";
2958                         lev = 1;
2959                         break;
2960
2961                 case NDMP9_LOG_DEBUG:
2962                         tag =  "d";
2963                         lev = 2;
2964                         break;
2965
2966                 case NDMP9_LOG_ERROR:
2967                         tag = "e";
2968                         lev = 0;
2969                         break;
2970
2971                 case NDMP9_LOG_WARNING:
2972                         tag = "w";
2973                         lev = 0;
2974                         break;
2975
2976                 default:
2977                         tag = "?";
2978                         lev = 0;
2979                         break;
2980                 }
2981
2982                 sprintf (prefix, "%cLM%s", ref_conn->chan.name[1], tag);
2983
2984                 ndmalogf (sess, prefix, lev, "LOG_MESSAGE: '%s'", request->entry);
2985         NDMS_ENDWITH
2986
2987         return 0;
2988 }
2989
2990 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */     /* Surrounds LOG intfs */
2991
2992
2993
2994
2995 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT           /* Surrounds FH intfs */
2996 /*
2997  * NDMPx_FH Interfaces
2998  ****************************************************************
2999  */
3000
3001
3002
3003
3004 /*
3005  * NDMP2_FH_ADD_UNIX_PATH
3006  * NDMP[34]_FH_ADD_FILE
3007  */
3008 int
3009 ndmp_sxa_fh_add_file (struct ndm_session *sess,
3010   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
3011 {
3012         struct ndm_control_agent *ca = &sess->control_acb;
3013         struct ndmlog *         ixlog = &ca->job.index_log;
3014         int                     tagc = ref_conn->chan.name[1];
3015         unsigned int            i;
3016         ndmp9_file *            file;
3017
3018         xa->reply.flags |= NDMNMB_FLAG_NO_SEND;
3019
3020         NDMS_WITH_NO_REPLY(ndmp9_fh_add_file)
3021                 for (i = 0; i < request->files.files_len; i++) {
3022                         file = &request->files.files_val[i];
3023
3024                         ndmfhdb_add_file (ixlog, tagc,
3025                                 file->unix_path, &file->fstat);
3026                 }
3027         NDMS_ENDWITH
3028
3029         return 0;
3030 }
3031
3032
3033
3034
3035 /*
3036  * NDMP2_FH_ADD_UNIX_DIR
3037  * NDMP[34]_FH_ADD_DIR
3038  */
3039 int
3040 ndmp_sxa_fh_add_dir (struct ndm_session *sess,
3041   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
3042 {
3043         struct ndm_control_agent *ca = &sess->control_acb;
3044         struct ndmlog *         ixlog = &ca->job.index_log;
3045         int                     tagc = ref_conn->chan.name[1];
3046         char *                  raw_name;
3047         unsigned int            i;
3048         ndmp9_dir *             dir;
3049
3050         xa->reply.flags |= NDMNMB_FLAG_NO_SEND;
3051
3052         NDMS_WITH_NO_REPLY(ndmp9_fh_add_dir)
3053                 for (i = 0; i < request->dirs.dirs_len; i++) {
3054                         dir = &request->dirs.dirs_val[i];
3055
3056                         raw_name = dir->unix_name;
3057
3058                         switch (ca->job.n_dir_entry) {
3059                         case 0:
3060                                 if (strcmp (raw_name, ".") == 0) {
3061                                         /* goodness */
3062                                         ndmfhdb_add_dirnode_root (ixlog,
3063                                                 tagc, dir->node);
3064                                         ca->job.root_node = dir->node;
3065                                 } else {
3066                                         /* ungoodness */
3067                                         ndmalogf (sess, 0, 0,
3068                                                 "WARNING: First add_dir "
3069                                                 "entry is non-conforming");
3070                                 }
3071                                 break;
3072
3073                         case 1:
3074                                 if (strcmp (raw_name, "..") == 0
3075                                  && dir->parent == dir->node
3076                                  && dir->node == ca->job.root_node) {
3077                                         /* goodness */
3078                                 } else {
3079                                         /* ungoodness */
3080                                         /* NetApp is non-conforming */
3081                                         /* ndmalogf (sess, 0, 0,
3082                                                 "WARNING: Second add_dir "
3083                                                 "entry is non-conforming"); */
3084                                 }
3085                                 break;
3086
3087                         default:
3088                                 break;
3089                         }
3090
3091                         ndmfhdb_add_dir (ixlog, tagc,
3092                                 dir->unix_name, dir->parent, dir->node);
3093
3094                         ca->job.n_dir_entry++;
3095                 }
3096         NDMS_ENDWITH
3097
3098         return 0;
3099 }
3100
3101
3102
3103
3104 /*
3105  * NDMP2_FH_ADD_UNIX_NODE
3106  * NDMP[34]_FH_ADD_NODE
3107  */
3108 int
3109 ndmp_sxa_fh_add_node (struct ndm_session *sess,
3110   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
3111 {
3112         struct ndm_control_agent *ca = &sess->control_acb;
3113         struct ndmlog *         ixlog = &ca->job.index_log;
3114         int                     tagc = ref_conn->chan.name[1];
3115         unsigned int            i;
3116         ndmp9_node *            node;
3117
3118         xa->reply.flags |= NDMNMB_FLAG_NO_SEND;
3119
3120         NDMS_WITH_NO_REPLY(ndmp9_fh_add_node)
3121                 for (i = 0; i < request->nodes.nodes_len; i++) {
3122                         node = &request->nodes.nodes_val[i];
3123
3124                         ndmfhdb_add_node (ixlog, tagc,
3125                                 node->fstat.node.value, &node->fstat);
3126                 }
3127         NDMS_ENDWITH
3128
3129         return 0;
3130 }
3131 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */     /* Surrounds FH intfs */
3132
3133
3134
3135 /*
3136  * Common helper interfaces
3137  ****************************************************************
3138  * These do complicated state checks which are called from
3139  * several of the interfaces above.
3140  */
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150 #ifndef NDMOS_OPTION_NO_TAPE_AGENT
3151 /*
3152  * Shortcut for DATA->MOVER READ requests when NDMP9_ADDR_LOCAL
3153  * (local MOVER). This is implemented here because of the
3154  * state (sanity) checks. This should track the
3155  * NDMP9_MOVER_READ stanza in ndma_dispatch_request().
3156  */
3157
3158 int
3159 ndmta_local_mover_read (struct ndm_session *sess,
3160   unsigned long long offset, unsigned long long length)
3161 {
3162         struct ndm_tape_agent * ta = &sess->tape_acb;
3163         struct ndmp9_mover_get_state_reply *ms = &ta->mover_state;
3164         char *                  errstr = 0;
3165
3166         if (ms->state != NDMP9_MOVER_STATE_ACTIVE
3167          && ms->state != NDMP9_MOVER_STATE_LISTEN) {
3168                 errstr = "mover_state !ACTIVE";
3169                 goto senderr;
3170         }
3171         if (ms->bytes_left_to_read > 0) {
3172                 errstr = "byte_left_to_read";
3173                 goto senderr;
3174         }
3175         if (ms->data_connection_addr.addr_type != NDMP9_ADDR_LOCAL) {
3176                 errstr = "mover_addr !LOCAL";
3177                 goto senderr;
3178         }
3179         if (ms->mode != NDMP9_MOVER_MODE_WRITE) {
3180                 errstr = "mover_mode !WRITE";
3181                 goto senderr;
3182         }
3183
3184         ms->seek_position = offset;
3185         ms->bytes_left_to_read = length;
3186         ta->mover_want_pos = offset;
3187
3188         return 0;
3189
3190   senderr:
3191         if (errstr) {
3192                 ndmalogf (sess, 0, 2, "local_read error why=%s", errstr);
3193         }
3194
3195         return -1;
3196 }
3197 #endif /* !NDMOS_OPTION_NO_TAPE_AGENT */
3198
3199
3200
3201
3202
3203
3204
3205 /*
3206  * Dispatch Version Table and Dispatch Request Tables (DVT/DRT)
3207  ****************************************************************
3208  */
3209
3210 struct ndm_dispatch_request_table *
3211 ndma_drt_lookup (struct ndm_dispatch_version_table *dvt,
3212   unsigned protocol_version, unsigned message)
3213 {
3214         struct ndm_dispatch_request_table *     drt;
3215
3216         for (; dvt->protocol_version >= 0; dvt++) {
3217                 if (dvt->protocol_version == (int)protocol_version)
3218                         break;
3219         }
3220
3221         if (dvt->protocol_version < 0)
3222                 return 0;
3223
3224         for (drt = dvt->dispatch_request_table; drt->message; drt++) {
3225                 if (drt->message == message)
3226                         return drt;
3227         }
3228
3229         return 0;
3230 }
3231
3232 struct ndm_dispatch_request_table ndma_dispatch_request_table_v0[] = {
3233    { NDMP0_CONNECT_OPEN,
3234      NDM_DRT_FLAG_OK_NOT_CONNECTED+NDM_DRT_FLAG_OK_NOT_AUTHORIZED,
3235      ndmp_sxa_connect_open,
3236    },
3237    { NDMP0_CONNECT_CLOSE,
3238      NDM_DRT_FLAG_OK_NOT_CONNECTED+NDM_DRT_FLAG_OK_NOT_AUTHORIZED,
3239      ndmp_sxa_connect_close,
3240    },
3241 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT           /* Surrounds NOTIFY intfs */
3242    { NDMP0_NOTIFY_CONNECTED,
3243      0,
3244      ndmp_sxa_notify_connected,
3245    },
3246 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */     /* Surrounds NOTIFY intfs */
3247    {0}
3248 };
3249
3250
3251
3252 #ifndef NDMOS_OPTION_NO_NDMP2
3253 struct ndm_dispatch_request_table ndma_dispatch_request_table_v2[] = {
3254    { NDMP2_CONFIG_GET_BUTYPE_ATTR,
3255      NDM_DRT_FLAG_OK_NOT_AUTHORIZED,
3256      ndmp2_sxa_config_get_butype_attr
3257    },
3258    { NDMP2_LOG_LOG,     0,      ndmp2_sxa_log_log },
3259    { NDMP2_LOG_DEBUG,   0,      ndmp2_sxa_log_debug },
3260    {0}
3261 };
3262 #endif /* !NDMOS_OPTION_NO_NDMP2 */
3263
3264 #ifndef NDMOS_OPTION_NO_NDMP3
3265 struct ndm_dispatch_request_table ndma_dispatch_request_table_v3[] = {
3266    {0}
3267 };
3268 #endif /* !NDMOS_OPTION_NO_NDMP3 */
3269
3270 #ifndef NDMOS_OPTION_NO_NDMP4
3271 struct ndm_dispatch_request_table ndma_dispatch_request_table_v4[] = {
3272    {0}
3273 };
3274 #endif /* !NDMOS_OPTION_NO_NDMP4 */
3275
3276
3277 struct ndm_dispatch_request_table ndma_dispatch_request_table_v9[] = {
3278    { NDMP9_CONNECT_OPEN,
3279      NDM_DRT_FLAG_OK_NOT_CONNECTED+NDM_DRT_FLAG_OK_NOT_AUTHORIZED,
3280      ndmp_sxa_connect_open
3281    },
3282    { NDMP9_CONNECT_CLIENT_AUTH,
3283      NDM_DRT_FLAG_OK_NOT_AUTHORIZED,
3284      ndmp_sxa_connect_client_auth
3285    },
3286    { NDMP9_CONNECT_CLOSE,
3287      NDM_DRT_FLAG_OK_NOT_AUTHORIZED,
3288      ndmp_sxa_connect_close
3289    },
3290    { NDMP9_CONNECT_SERVER_AUTH,
3291      NDM_DRT_FLAG_OK_NOT_AUTHORIZED,
3292      ndmp_sxa_connect_server_auth
3293    },
3294    { NDMP9_CONFIG_GET_HOST_INFO,
3295      NDM_DRT_FLAG_OK_NOT_AUTHORIZED,
3296      ndmp_sxa_config_get_info
3297    },
3298    { NDMP9_CONFIG_GET_CONNECTION_TYPE,
3299      NDM_DRT_FLAG_OK_NOT_AUTHORIZED,
3300      ndmp_sxa_config_get_info
3301    },
3302    { NDMP9_CONFIG_GET_AUTH_ATTR,
3303      NDM_DRT_FLAG_OK_NOT_AUTHORIZED,
3304      ndmp_sxa_config_get_auth_attr
3305    },
3306    { NDMP9_CONFIG_GET_BUTYPE_INFO,
3307      NDM_DRT_FLAG_OK_NOT_AUTHORIZED,
3308      ndmp_sxa_config_get_info
3309    },
3310    { NDMP9_CONFIG_GET_FS_INFO,
3311      NDM_DRT_FLAG_OK_NOT_AUTHORIZED,
3312      ndmp_sxa_config_get_info
3313    },
3314    { NDMP9_CONFIG_GET_TAPE_INFO,
3315      NDM_DRT_FLAG_OK_NOT_AUTHORIZED,
3316      ndmp_sxa_config_get_info
3317    },
3318    { NDMP9_CONFIG_GET_SCSI_INFO,
3319      NDM_DRT_FLAG_OK_NOT_AUTHORIZED,
3320      ndmp_sxa_config_get_info
3321    },
3322    { NDMP9_CONFIG_GET_SERVER_INFO,
3323      NDM_DRT_FLAG_OK_NOT_AUTHORIZED,
3324      ndmp_sxa_config_get_info
3325    },
3326 #ifndef NDMOS_OPTION_NO_ROBOT_AGENT             /* Surrounds SCSI intfs */
3327    { NDMP9_SCSI_OPEN,                   0, ndmp_sxa_scsi_open },
3328    { NDMP9_SCSI_CLOSE,                  0, ndmp_sxa_scsi_close },
3329    { NDMP9_SCSI_GET_STATE,              0, ndmp_sxa_scsi_get_state },
3330    { NDMP9_SCSI_SET_TARGET,             0, ndmp_sxa_scsi_set_target },
3331    { NDMP9_SCSI_RESET_DEVICE,           0, ndmp_sxa_scsi_reset_device },
3332    { NDMP9_SCSI_RESET_BUS,              0, ndmp_sxa_scsi_reset_bus },
3333    { NDMP9_SCSI_EXECUTE_CDB,            0, ndmp_sxa_scsi_execute_cdb },
3334 #endif /* !NDMOS_OPTION_NO_ROBOT_AGENT */       /* Surrounds SCSI intfs */
3335 #ifndef NDMOS_OPTION_NO_TAPE_AGENT              /* Surrounds TAPE intfs */
3336    { NDMP9_TAPE_OPEN,                   0, ndmp_sxa_tape_open },
3337    { NDMP9_TAPE_CLOSE,                  0, ndmp_sxa_tape_close },
3338    { NDMP9_TAPE_GET_STATE,              0, ndmp_sxa_tape_get_state },
3339    { NDMP9_TAPE_MTIO,                   0, ndmp_sxa_tape_mtio },
3340    { NDMP9_TAPE_WRITE,                  0, ndmp_sxa_tape_write },
3341    { NDMP9_TAPE_READ,                   0, ndmp_sxa_tape_read },
3342    { NDMP9_TAPE_EXECUTE_CDB,            0, ndmp_sxa_tape_execute_cdb },
3343 #endif /* !NDMOS_OPTION_NO_TAPE_AGENT */        /* Surrounds TAPE intfs */
3344 #ifndef NDMOS_OPTION_NO_DATA_AGENT              /* Surrounds DATA intfs */
3345    { NDMP9_DATA_GET_STATE,              0, ndmp_sxa_data_get_state },
3346    { NDMP9_DATA_START_BACKUP,           0, ndmp_sxa_data_start_backup },
3347    { NDMP9_DATA_START_RECOVER,          0, ndmp_sxa_data_start_recover },
3348    { NDMP9_DATA_ABORT,                  0, ndmp_sxa_data_abort },
3349    { NDMP9_DATA_GET_ENV,                0, ndmp_sxa_data_get_env },
3350    { NDMP9_DATA_STOP,                   0, ndmp_sxa_data_stop },
3351 #ifndef NDMOS_EFFECT_NO_NDMP3_NOR_NDMP4 /* Surrounds NDMPv[34] DATA intfs */
3352 #ifdef notyet
3353    { NDMP9_DATA_LISTEN,                 0, ndmp_sxa_data_listen },
3354 #endif /* notyet */
3355    { NDMP9_DATA_CONNECT,                0, ndmp_sxa_data_connect },
3356 #endif /* NDMOS_EFFECT_NO_NDMP3_NOR_NDMP4  Surrounds NDMPv[34] DATA intfs */
3357    { NDMP9_DATA_START_RECOVER_FILEHIST, 0,
3358                                 ndmp_sxa_data_start_recover_filehist },
3359 #endif /* !NDMOS_OPTION_NO_DATA_AGENT */        /* Surrounds DATA intfs */
3360 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT           /* Surrounds NOTIFY intfs */
3361    { NDMP9_NOTIFY_DATA_HALTED,          0, ndmp_sxa_notify_data_halted },
3362    { NDMP9_NOTIFY_CONNECTED,            0, ndmp_sxa_notify_connected },
3363    { NDMP9_NOTIFY_MOVER_HALTED,         0, ndmp_sxa_notify_mover_halted },
3364    { NDMP9_NOTIFY_MOVER_PAUSED,         0, ndmp_sxa_notify_mover_paused },
3365    { NDMP9_NOTIFY_DATA_READ,            0, ndmp_sxa_notify_data_read },
3366 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */     /* Surrounds NOTIFY intfs */
3367 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT           /* Surrounds LOG intfs */
3368    { NDMP9_LOG_FILE,                    0, ndmp_sxa_log_file },
3369    { NDMP9_LOG_MESSAGE,                 0, ndmp_sxa_log_message },
3370 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */     /* Surrounds LOG intfs */
3371 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT           /* Surrounds FH intfs */
3372    { NDMP9_FH_ADD_FILE,                 0, ndmp_sxa_fh_add_file },
3373    { NDMP9_FH_ADD_DIR,                  0, ndmp_sxa_fh_add_dir },
3374    { NDMP9_FH_ADD_NODE,                 0, ndmp_sxa_fh_add_node },
3375 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */     /* Surrounds FH intfs */
3376 #ifndef NDMOS_OPTION_NO_TAPE_AGENT              /* Surrounds MOVER intfs */
3377    { NDMP9_MOVER_GET_STATE,             0, ndmp_sxa_mover_get_state },
3378    { NDMP9_MOVER_LISTEN,                0, ndmp_sxa_mover_listen },
3379    { NDMP9_MOVER_CONTINUE,              0, ndmp_sxa_mover_continue },
3380    { NDMP9_MOVER_ABORT,                 0, ndmp_sxa_mover_abort },
3381    { NDMP9_MOVER_STOP,                  0, ndmp_sxa_mover_stop },
3382    { NDMP9_MOVER_SET_WINDOW,            0, ndmp_sxa_mover_set_window },
3383    { NDMP9_MOVER_READ,                  0, ndmp_sxa_mover_read },
3384    { NDMP9_MOVER_CLOSE,                 0, ndmp_sxa_mover_close },
3385    { NDMP9_MOVER_SET_RECORD_SIZE,       0, ndmp_sxa_mover_set_record_size },
3386    { NDMP9_MOVER_CONNECT,               0, ndmp_sxa_mover_connect },
3387 #endif /* !NDMOS_OPTION_NO_TAPE_AGENT */        /* Surrounds MOVER intfs */
3388    {0}
3389 };
3390
3391
3392 struct ndm_dispatch_version_table ndma_dispatch_version_table[] = {
3393         { 0,            ndma_dispatch_request_table_v0 },
3394 #ifndef NDMOS_OPTION_NO_NDMP2
3395         { NDMP2VER,     ndma_dispatch_request_table_v2 },
3396 #endif /* !NDMOS_OPTION_NO_NDMP2 */
3397 #ifndef NDMOS_OPTION_NO_NDMP3
3398         { NDMP3VER,     ndma_dispatch_request_table_v3 },
3399 #endif /* !NDMOS_OPTION_NO_NDMP3 */
3400 #ifndef NDMOS_OPTION_NO_NDMP4
3401         { NDMP4VER,     ndma_dispatch_request_table_v4 },
3402 #endif /* !NDMOS_OPTION_NO_NDMP4 */
3403         { NDMP9VER,     ndma_dispatch_request_table_v9 },
3404
3405         { -1 }
3406 };