1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy is of the CDDL is also available via the Internet
   9  * at http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
  14  */
  15 
  16 /*
  17  * NFS Lock Manager, server-side dispatch tables and
  18  * dispatch programs: nlm_prog_3, nlm_prog4
  19  *
  20  * These are called by RPC framework after the RPC service
  21  * endpoints setup done in nlm_impl.c: nlm_svc_add_ep().
  22  *
  23  * Originally from rpcgen, then reduced.
  24  */
  25 
  26 #include <sys/param.h>
  27 #include <sys/systm.h>
  28 #include <sys/sdt.h>
  29 #include <rpcsvc/nlm_prot.h>
  30 #include "nlm_impl.h"
  31 
  32 /*
  33  * Dispatch entry function pointers.
  34  */
  35 typedef bool_t (*nlm_svc_func_t)(void *, void *, struct svc_req *);
  36 typedef void (*nlm_freeres_func_t)(void *);
  37 
  38 /*
  39  * Entries in the dispatch tables below.
  40  */
  41 struct dispatch_entry {
  42         nlm_svc_func_t          de_svc;         /* service routine function */
  43         xdrproc_t               de_xargs;       /* XDR args decode function */
  44         xdrproc_t               de_xres;        /* XDR res encode function */
  45         nlm_freeres_func_t      de_resfree;     /* free res function */
  46         int                     de_ressz;       /* size of result */
  47         uint_t                  de_flags;       /* flags */
  48 };
  49 
  50 /* Flag bits in de_flags */
  51 #define NLM_DISP_NOREMOTE       1       /* Local calls only */
  52 
  53 /*
  54  * Cast macros for dispatch table function pointers.
  55  */
  56 #define NLM_SVC_FUNC(func)      (nlm_svc_func_t)func
  57 #define NLM_FREERES_FUNC(func)  (nlm_freeres_func_t)func
  58 
  59 /* ARGSUSED */
  60 static bool_t
  61 nlm_null_svc(void *args, void *resp, struct svc_req *sr)
  62 {
  63         return (TRUE);
  64 }
  65 
  66 /*
  67  * The common NLM service dispatch function, used by
  68  * both: nlm_prog_3, nlm_prog_4
  69  */
  70 void
  71 nlm_dispatch(
  72         struct svc_req *rqstp,
  73         SVCXPRT *transp,
  74         const struct dispatch_entry *de)
  75 {
  76         union {
  77                 /* All the arg types */
  78                 nlm_cancargs    au_cancargs;
  79                 nlm_lockargs    au_lockargs;
  80                 nlm_notify      au_notify;
  81                 nlm_res         au_res;
  82                 nlm_shareargs   au_shareargs;
  83                 nlm_sm_status   au_sm_status;
  84                 nlm_testargs    au_testargs;
  85                 nlm_testres     au_testres;
  86                 nlm_unlockargs  au_unlockargs;
  87                 nlm4_cancargs   au_cancargs4;
  88                 nlm4_lockargs   au_lockargs4;
  89                 nlm4_notify     au_notify4;
  90                 nlm4_res        au_res4;
  91                 nlm4_shareargs  au_shareargs4;
  92                 nlm4_testargs   au_testargs4;
  93                 nlm4_testres    au_testres4;
  94                 nlm4_unlockargs au_unlockargs4;
  95         } argu;
  96         void *args = &argu;
  97         union {
  98                 /* All the ret types */
  99                 int             ru_int;
 100                 nlm_res         ru_res;
 101                 nlm_shareres    ru_shareres;
 102                 nlm_testres     ru_testres;
 103                 nlm4_res        ru_res4;
 104                 nlm4_shareres   ru_shareres4;
 105                 nlm4_testres    ru_testres4;
 106 
 107         } resu;
 108         void *res = &resu;
 109         nlm_svc_func_t func;
 110         bool_t do_reply = FALSE;
 111         bool_t dupcached = FALSE;
 112         struct dupreq *dr;
 113         int dupstat;
 114 
 115         if ((func = de->de_svc) == NULL) {
 116                 svcerr_noproc(transp);
 117                 return;
 118         }
 119 
 120         if ((de->de_flags & NLM_DISP_NOREMOTE) &&
 121             !nlm_caller_is_local(transp)) {
 122                 svcerr_noproc(transp);
 123                 return;
 124         }
 125 
 126         /*
 127          * This section from rpcgen, and then modified slightly.
 128          *
 129          * Dispatch entries that should _never_ send a response
 130          * (i.e. all the _MSG and _RES entries) put NULL in the
 131          * de_xres field to indicate that.  For such entries, we
 132          * will NOT call svc_sendreply nor xdr_free().  Normal
 133          * dispatch entries skip svc_sendreply if the dispatch
 134          * function returns zero, but always call xdr_free().
 135          *
 136          * There are more complex cases where some dispatch
 137          * functions need to send their own reply.  We chose
 138          * to indicate those by returning false from the
 139          * service routine.
 140          */
 141         bzero(&argu, sizeof (argu));
 142         if (!SVC_GETARGS(transp, de->de_xargs, args)) {
 143                 svcerr_decode(transp);
 144                 return;
 145         }
 146 
 147         /*
 148          * Duplicate request cache.
 149          *
 150          * Since none of the NLM replies are very large we have simplified the
 151          * DRC by not distinguishing between idempotent and non-idempotent
 152          * requests.
 153          */
 154         dupstat = SVC_DUP_EXT(transp, rqstp, res, de->de_ressz, &dr,
 155             &dupcached);
 156 
 157         switch (dupstat) {
 158         case DUP_ERROR:
 159                 svcerr_systemerr(transp);
 160                 break;
 161         case DUP_INPROGRESS:
 162                 break;
 163         case DUP_NEW:
 164         case DUP_DROP:
 165                 /*
 166                  * When UFS is quiescing it uses lockfs to block vnode
 167                  * operations until it has finished quiescing.  Set the
 168                  * thread's T_DONTPEND flag to prevent the service routine
 169                  * from blocking due to a lockfs lock. (See ufs_check_lockfs)
 170                  */
 171                 curthread->t_flag |= T_DONTPEND;
 172 
 173                 bzero(&resu, sizeof (resu));
 174                 do_reply = (*func)(args, res, rqstp);
 175 
 176                 curthread->t_flag &= ~T_DONTPEND;
 177                 if (curthread->t_flag & T_WOULDBLOCK) {
 178                         curthread->t_flag &= ~T_WOULDBLOCK;
 179                         SVC_DUPDONE_EXT(transp, dr, res, NULL,
 180                             de->de_ressz, DUP_DROP);
 181                         do_reply = FALSE;
 182                         break;
 183                 }
 184                 SVC_DUPDONE_EXT(transp, dr, res, de->de_resfree,
 185                     de->de_ressz, DUP_DONE);
 186                 dupcached = TRUE;
 187                 break;
 188         case DUP_DONE:
 189                 /*
 190                  * The service routine may have been responsible for sending
 191                  * the reply for the original request but for a re-xmitted
 192                  * request we don't invoke the service routine so we must
 193                  * re-xmit the reply from the dispatch function.
 194                  *
 195                  * If de_xres is NULL this is a one-way message so no reply is
 196                  * needed.
 197                  */
 198                 if (de->de_xres != NULL_xdrproc_t) {
 199                         do_reply = TRUE;
 200                 }
 201                 break;
 202         }
 203 
 204         if (do_reply) {
 205                 ASSERT(de->de_xres != NULL_xdrproc_t);
 206                 DTRACE_PROBE3(sendreply, struct svc_req *, rqstp,
 207                     SVCXPRT *, transp, struct dispatch_entry *, de);
 208 
 209                 if (!svc_sendreply(transp, de->de_xres, res)) {
 210                         svcerr_systemerr(transp);
 211                         NLM_ERR("nlm_dispatch(): svc_sendreply() failed!\n");
 212                 }
 213 
 214                 if (!dupcached) {
 215                         xdr_free(de->de_xres, res);
 216                 }
 217         }
 218 
 219         if (!SVC_FREEARGS(transp, de->de_xargs, args))
 220                 NLM_WARN("nlm_dispatch(): unable to free arguments");
 221 }
 222 
 223 /*
 224  * Result free functions.  The functions are called by the RPC duplicate
 225  * request cache code when an entry is being evicted from the cache.
 226  */
 227 static void
 228 nlm_res_free(nlm_res *resp)
 229 {
 230         xdr_free(xdr_nlm_res, (char *)resp);
 231 }
 232 
 233 static void
 234 nlm_shareres_free(nlm_shareres *resp)
 235 {
 236         xdr_free(xdr_nlm_shareres, (char *)resp);
 237 }
 238 
 239 static void
 240 nlm_testres_free(nlm_testres *resp)
 241 {
 242         xdr_free(xdr_nlm_testres, (char *)resp);
 243 }
 244 
 245 static void
 246 nlm4_res_free(nlm4_res *resp)
 247 {
 248         xdr_free(xdr_nlm4_res, (char *)resp);
 249 }
 250 
 251 static void
 252 nlm4_shareres_free(nlm4_shareres *resp)
 253 {
 254         xdr_free(xdr_nlm4_shareres, (char *)resp);
 255 }
 256 
 257 static void
 258 nlm4_testres_free(nlm4_testres *resp)
 259 {
 260         xdr_free(xdr_nlm4_testres, (char *)resp);
 261 }
 262 
 263 /*
 264  * Dispatch tables for each program version.
 265  *
 266  * The tables here were all originally from rpcgen,
 267  * but then arg/resp sizes removed, flags added.
 268  */
 269 
 270 /*
 271  * Dispatch table for versions 1, 2, 3
 272  * (NLM_VERS, NLM_SM, NLM_VERSX)
 273  */
 274 static const struct dispatch_entry
 275 nlm_prog_3_dtable[] = {
 276 
 277         /*
 278          * Version 1 (NLM_VERS) entries.
 279          */
 280 
 281         { /* 0: NULLPROC */
 282         NLM_SVC_FUNC(nlm_null_svc),
 283         (xdrproc_t)xdr_void,
 284         (xdrproc_t)xdr_void,
 285         NULL,
 286         0,
 287         0 },
 288 
 289         { /* 1: NLM_TEST */
 290         NLM_SVC_FUNC(nlm_test_1_svc),
 291         (xdrproc_t)xdr_nlm_testargs,
 292         (xdrproc_t)xdr_nlm_testres,
 293         NLM_FREERES_FUNC(nlm_testres_free),
 294         sizeof (nlm_testres),
 295         0 },
 296 
 297         { /* 2: NLM_LOCK */
 298         NLM_SVC_FUNC(nlm_lock_1_svc),
 299         (xdrproc_t)xdr_nlm_lockargs,
 300         (xdrproc_t)xdr_nlm_res,
 301         NLM_FREERES_FUNC(nlm_res_free),
 302         sizeof (nlm_res),
 303         0 },
 304 
 305         { /* 3: NLM_CANCEL */
 306         NLM_SVC_FUNC(nlm_cancel_1_svc),
 307         (xdrproc_t)xdr_nlm_cancargs,
 308         (xdrproc_t)xdr_nlm_res,
 309         NLM_FREERES_FUNC(nlm_res_free),
 310         sizeof (nlm_res),
 311         0 },
 312 
 313         { /* 4: NLM_UNLOCK */
 314         NLM_SVC_FUNC(nlm_unlock_1_svc),
 315         (xdrproc_t)xdr_nlm_unlockargs,
 316         (xdrproc_t)xdr_nlm_res,
 317         NLM_FREERES_FUNC(nlm_res_free),
 318         sizeof (nlm_res),
 319         0 },
 320 
 321         { /* 5: NLM_GRANTED */
 322         NLM_SVC_FUNC(nlm_granted_1_svc),
 323         (xdrproc_t)xdr_nlm_testargs,
 324         (xdrproc_t)xdr_nlm_res,
 325         NLM_FREERES_FUNC(nlm_res_free),
 326         sizeof (nlm_res),
 327         0 },
 328 
 329         /*
 330          * All the _MSG and _RES entries are "one way" calls that
 331          * skip the usual RPC reply.  We give them a null xdr_res
 332          * function so the dispatcher will not send a reply.
 333          */
 334 
 335         { /* 6: NLM_TEST_MSG */
 336         NLM_SVC_FUNC(nlm_test_msg_1_svc),
 337         (xdrproc_t)xdr_nlm_testargs,
 338         (xdrproc_t)0,
 339         NULL,
 340         0,
 341         0 },
 342 
 343         { /* 7: NLM_LOCK_MSG */
 344         NLM_SVC_FUNC(nlm_lock_msg_1_svc),
 345         (xdrproc_t)xdr_nlm_lockargs,
 346         (xdrproc_t)0,
 347         NULL,
 348         0,
 349         0 },
 350 
 351         { /* 8: NLM_CANCEL_MSG */
 352         NLM_SVC_FUNC(nlm_cancel_msg_1_svc),
 353         (xdrproc_t)xdr_nlm_cancargs,
 354         (xdrproc_t)0,
 355         NULL,
 356         0,
 357         0 },
 358 
 359         { /* 9: NLM_UNLOCK_MSG */
 360         NLM_SVC_FUNC(nlm_unlock_msg_1_svc),
 361         (xdrproc_t)xdr_nlm_unlockargs,
 362         (xdrproc_t)0,
 363         NULL,
 364         0,
 365         0 },
 366 
 367         { /* 10: NLM_GRANTED_MSG */
 368         NLM_SVC_FUNC(nlm_granted_msg_1_svc),
 369         (xdrproc_t)xdr_nlm_testargs,
 370         (xdrproc_t)0,
 371         NULL,
 372         0,
 373         0 },
 374 
 375         { /* 11: NLM_TEST_RES */
 376         NLM_SVC_FUNC(nlm_test_res_1_svc),
 377         (xdrproc_t)xdr_nlm_testres,
 378         (xdrproc_t)0,
 379         NULL,
 380         0,
 381         0 },
 382 
 383         { /* 12: NLM_LOCK_RES */
 384         NLM_SVC_FUNC(nlm_lock_res_1_svc),
 385         (xdrproc_t)xdr_nlm_res,
 386         (xdrproc_t)0,
 387         NULL,
 388         0,
 389         0 },
 390 
 391         { /* 13: NLM_CANCEL_RES */
 392         NLM_SVC_FUNC(nlm_cancel_res_1_svc),
 393         (xdrproc_t)xdr_nlm_res,
 394         (xdrproc_t)0,
 395         NULL,
 396         0,
 397         0 },
 398 
 399         { /* 14: NLM_UNLOCK_RES */
 400         NLM_SVC_FUNC(nlm_unlock_res_1_svc),
 401         (xdrproc_t)xdr_nlm_res,
 402         (xdrproc_t)0,
 403         NULL,
 404         0,
 405         0 },
 406 
 407         { /* 15: NLM_GRANTED_RES */
 408         NLM_SVC_FUNC(nlm_granted_res_1_svc),
 409         (xdrproc_t)xdr_nlm_res,
 410         (xdrproc_t)0,
 411         NULL,
 412         0,
 413         0 },
 414 
 415         { /* 16: not used */
 416         NLM_SVC_FUNC(0),
 417         (xdrproc_t)0,
 418         (xdrproc_t)0,
 419         NULL,
 420         0,
 421         0 },
 422 
 423         { /* 17: NLM_SM_NOTIFY1 */
 424         NLM_SVC_FUNC(nlm_sm_notify1_2_svc),
 425         (xdrproc_t)xdr_nlm_sm_status,
 426         (xdrproc_t)xdr_void,
 427         NULL,
 428         0,
 429         NLM_DISP_NOREMOTE },
 430 
 431         { /* 18: NLM_SM_NOTIFY2 */
 432         NLM_SVC_FUNC(nlm_sm_notify2_2_svc),
 433         (xdrproc_t)xdr_nlm_sm_status,
 434         (xdrproc_t)xdr_void,
 435         NULL,
 436         0,
 437         NLM_DISP_NOREMOTE },
 438 
 439         /*
 440          * Version 3 (NLM_VERSX) entries.
 441          */
 442 
 443         { /* 19: not used */
 444         NLM_SVC_FUNC(0),
 445         (xdrproc_t)0,
 446         (xdrproc_t)0,
 447         NULL,
 448         0,
 449         0 },
 450 
 451         { /* 20: NLM_SHARE */
 452         NLM_SVC_FUNC(nlm_share_3_svc),
 453         (xdrproc_t)xdr_nlm_shareargs,
 454         (xdrproc_t)xdr_nlm_shareres,
 455         NLM_FREERES_FUNC(nlm_shareres_free),
 456         sizeof (nlm_shareres),
 457         0 },
 458 
 459         { /* 21: NLM_UNSHARE */
 460         NLM_SVC_FUNC(nlm_unshare_3_svc),
 461         (xdrproc_t)xdr_nlm_shareargs,
 462         (xdrproc_t)xdr_nlm_shareres,
 463         NLM_FREERES_FUNC(nlm_shareres_free),
 464         sizeof (nlm_shareres),
 465         0 },
 466 
 467         { /* 22: NLM_NM_LOCK */
 468         NLM_SVC_FUNC(nlm_nm_lock_3_svc),
 469         (xdrproc_t)xdr_nlm_lockargs,
 470         (xdrproc_t)xdr_nlm_res,
 471         NLM_FREERES_FUNC(nlm_res_free),
 472         sizeof (nlm_res),
 473         0 },
 474 
 475         { /* 23: NLM_FREE_ALL */
 476         NLM_SVC_FUNC(nlm_free_all_3_svc),
 477         (xdrproc_t)xdr_nlm_notify,
 478         (xdrproc_t)xdr_void,
 479         NULL,
 480         0,
 481         0 },
 482 };
 483 static int nlm_prog_3_dtsize =
 484         sizeof (nlm_prog_3_dtable) /
 485         sizeof (nlm_prog_3_dtable[0]);
 486 
 487 /*
 488  * RPC dispatch function for nlm_prot versions: 1,2,3
 489  */
 490 void
 491 nlm_prog_3(struct svc_req *rqstp, register SVCXPRT *transp)
 492 {
 493         const struct dispatch_entry *de;
 494         rpcproc_t max_proc;
 495 
 496         switch (rqstp->rq_vers) {
 497         case NLM_VERS:
 498                 max_proc = NLM_GRANTED_RES;
 499                 break;
 500         case NLM_SM:
 501                 max_proc = NLM_SM_NOTIFY2;
 502                 break;
 503         case NLM_VERSX:
 504                 max_proc = NLM_FREE_ALL;
 505                 break;
 506         default:
 507                 /* Our svc registration should prevent this. */
 508                 ASSERT(0); /* paranoid */
 509                 svcerr_noprog(transp);
 510                 return;
 511         }
 512         ASSERT(max_proc < nlm_prog_3_dtsize);
 513 
 514         if (rqstp->rq_proc > max_proc) {
 515                 svcerr_noproc(transp);
 516                 return;
 517         }
 518 
 519         de = &nlm_prog_3_dtable[rqstp->rq_proc];
 520 
 521         nlm_dispatch(rqstp, transp, de);
 522 }
 523 
 524 /*
 525  * Dispatch table for version 4 (NLM4_VERS)
 526  */
 527 static const struct dispatch_entry
 528 nlm_prog_4_dtable[] = {
 529 
 530         { /* 0: NULLPROC */
 531         NLM_SVC_FUNC(nlm_null_svc),
 532         (xdrproc_t)xdr_void,
 533         (xdrproc_t)xdr_void,
 534         NULL,
 535         0,
 536         0 },
 537 
 538         { /* 1: NLM4_TEST */
 539         NLM_SVC_FUNC(nlm4_test_4_svc),
 540         (xdrproc_t)xdr_nlm4_testargs,
 541         (xdrproc_t)xdr_nlm4_testres,
 542         NLM_FREERES_FUNC(nlm4_testres_free),
 543         sizeof (nlm4_testres),
 544         0 },
 545 
 546         { /* 2: NLM4_LOCK */
 547         NLM_SVC_FUNC(nlm4_lock_4_svc),
 548         (xdrproc_t)xdr_nlm4_lockargs,
 549         (xdrproc_t)xdr_nlm4_res,
 550         NLM_FREERES_FUNC(nlm4_res_free),
 551         sizeof (nlm4_res),
 552         0 },
 553 
 554         { /* 3: NLM4_CANCEL */
 555         NLM_SVC_FUNC(nlm4_cancel_4_svc),
 556         (xdrproc_t)xdr_nlm4_cancargs,
 557         (xdrproc_t)xdr_nlm4_res,
 558         NLM_FREERES_FUNC(nlm4_res_free),
 559         sizeof (nlm4_res),
 560         0 },
 561 
 562         { /* 4: NLM4_UNLOCK */
 563         NLM_SVC_FUNC(nlm4_unlock_4_svc),
 564         (xdrproc_t)xdr_nlm4_unlockargs,
 565         (xdrproc_t)xdr_nlm4_res,
 566         NLM_FREERES_FUNC(nlm4_res_free),
 567         sizeof (nlm4_res),
 568         0 },
 569 
 570         { /* 5: NLM4_GRANTED */
 571         NLM_SVC_FUNC(nlm4_granted_4_svc),
 572         (xdrproc_t)xdr_nlm4_testargs,
 573         (xdrproc_t)xdr_nlm4_res,
 574         NLM_FREERES_FUNC(nlm4_res_free),
 575         sizeof (nlm4_res),
 576         0 },
 577 
 578         /*
 579          * All the _MSG and _RES entries are "one way" calls that
 580          * skip the usual RPC reply.  We give them a null xdr_res
 581          * function so the dispatcher will not send a reply.
 582          */
 583 
 584         { /* 6: NLM4_TEST_MSG */
 585         NLM_SVC_FUNC(nlm4_test_msg_4_svc),
 586         (xdrproc_t)xdr_nlm4_testargs,
 587         (xdrproc_t)0,
 588         NULL,
 589         0,
 590         0 },
 591 
 592         { /* 7: NLM4_LOCK_MSG */
 593         NLM_SVC_FUNC(nlm4_lock_msg_4_svc),
 594         (xdrproc_t)xdr_nlm4_lockargs,
 595         (xdrproc_t)0,
 596         NULL,
 597         0,
 598         0 },
 599 
 600         { /* 8: NLM4_CANCEL_MSG */
 601         NLM_SVC_FUNC(nlm4_cancel_msg_4_svc),
 602         (xdrproc_t)xdr_nlm4_cancargs,
 603         (xdrproc_t)0,
 604         NULL,
 605         0,
 606         0 },
 607 
 608         { /* 9: NLM4_UNLOCK_MSG */
 609         NLM_SVC_FUNC(nlm4_unlock_msg_4_svc),
 610         (xdrproc_t)xdr_nlm4_unlockargs,
 611         (xdrproc_t)0,
 612         NULL,
 613         0,
 614         0 },
 615 
 616         { /* 10: NLM4_GRANTED_MSG */
 617         NLM_SVC_FUNC(nlm4_granted_msg_4_svc),
 618         (xdrproc_t)xdr_nlm4_testargs,
 619         (xdrproc_t)0,
 620         NULL,
 621         0,
 622         0 },
 623 
 624         { /* 11: NLM4_TEST_RES */
 625         NLM_SVC_FUNC(nlm4_test_res_4_svc),
 626         (xdrproc_t)xdr_nlm4_testres,
 627         (xdrproc_t)0,
 628         NULL,
 629         0,
 630         0 },
 631 
 632         { /* 12: NLM4_LOCK_RES */
 633         NLM_SVC_FUNC(nlm4_lock_res_4_svc),
 634         (xdrproc_t)xdr_nlm4_res,
 635         (xdrproc_t)0,
 636         NULL,
 637         0,
 638         0 },
 639 
 640         { /* 13: NLM4_CANCEL_RES */
 641         NLM_SVC_FUNC(nlm4_cancel_res_4_svc),
 642         (xdrproc_t)xdr_nlm4_res,
 643         (xdrproc_t)0,
 644         NULL,
 645         0,
 646         0 },
 647 
 648         { /* 14: NLM4_UNLOCK_RES */
 649         NLM_SVC_FUNC(nlm4_unlock_res_4_svc),
 650         (xdrproc_t)xdr_nlm4_res,
 651         (xdrproc_t)0,
 652         NULL,
 653         0,
 654         0 },
 655 
 656         { /* 15: NLM4_GRANTED_RES */
 657         NLM_SVC_FUNC(nlm4_granted_res_4_svc),
 658         (xdrproc_t)xdr_nlm4_res,
 659         (xdrproc_t)0,
 660         NULL,
 661         0,
 662         0 },
 663 
 664         { /* 16: not used */
 665         NLM_SVC_FUNC(0),
 666         (xdrproc_t)0,
 667         (xdrproc_t)0,
 668         NULL,
 669         0,
 670         0 },
 671 
 672         { /* 17: NLM_SM_NOTIFY1 (not in v4) */
 673         NLM_SVC_FUNC(0),
 674         (xdrproc_t)0,
 675         (xdrproc_t)0,
 676         NULL,
 677         0,
 678         0 },
 679 
 680         { /* 18: NLM_SM_NOTIFY2 (not in v4) */
 681         NLM_SVC_FUNC(0),
 682         (xdrproc_t)0,
 683         (xdrproc_t)0,
 684         NULL,
 685         0,
 686         0 },
 687 
 688         { /* 19: not used */
 689         NLM_SVC_FUNC(0),
 690         (xdrproc_t)0,
 691         (xdrproc_t)0,
 692         NULL,
 693         0,
 694         0 },
 695 
 696         { /* 20: NLM4_SHARE */
 697         NLM_SVC_FUNC(nlm4_share_4_svc),
 698         (xdrproc_t)xdr_nlm4_shareargs,
 699         (xdrproc_t)xdr_nlm4_shareres,
 700         NLM_FREERES_FUNC(nlm4_shareres_free),
 701         sizeof (nlm4_shareres),
 702         0 },
 703 
 704         { /* 21: NLM4_UNSHARE */
 705         NLM_SVC_FUNC(nlm4_unshare_4_svc),
 706         (xdrproc_t)xdr_nlm4_shareargs,
 707         (xdrproc_t)xdr_nlm4_shareres,
 708         NLM_FREERES_FUNC(nlm4_shareres_free),
 709         sizeof (nlm4_shareres),
 710         0 },
 711 
 712         { /* 22: NLM4_NM_LOCK */
 713         NLM_SVC_FUNC(nlm4_nm_lock_4_svc),
 714         (xdrproc_t)xdr_nlm4_lockargs,
 715         (xdrproc_t)xdr_nlm4_res,
 716         NLM_FREERES_FUNC(nlm4_res_free),
 717         sizeof (nlm4_res),
 718         0 },
 719 
 720         { /* 23: NLM4_FREE_ALL */
 721         NLM_SVC_FUNC(nlm4_free_all_4_svc),
 722         (xdrproc_t)xdr_nlm4_notify,
 723         (xdrproc_t)xdr_void,
 724         NULL,
 725         0,
 726         0 },
 727 };
 728 static int nlm_prog_4_dtsize =
 729         sizeof (nlm_prog_4_dtable) /
 730         sizeof (nlm_prog_4_dtable[0]);
 731 
 732 /*
 733  * RPC dispatch function for nlm_prot version 4.
 734  */
 735 void
 736 nlm_prog_4(struct svc_req *rqstp, register SVCXPRT *transp)
 737 {
 738         const struct dispatch_entry *de;
 739 
 740         if (rqstp->rq_vers != NLM4_VERS) {
 741                 /* Our svc registration should prevent this. */
 742                 ASSERT(0); /* paranoid */
 743                 svcerr_noprog(transp);
 744                 return;
 745         }
 746 
 747         if (rqstp->rq_proc >= nlm_prog_4_dtsize) {
 748                 svcerr_noproc(transp);
 749                 return;
 750         }
 751 
 752         de = &nlm_prog_4_dtable[rqstp->rq_proc];
 753 
 754         nlm_dispatch(rqstp, transp, de);
 755 }