1/*
2 * Copyright (c) 2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
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 *
10 * 1.  Redistributions of source code must retain the above copyright
11 *     notice, this list of conditions and the following 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 * 3.  Neither the name of Apple Inc. ("Apple") nor the names of its
16 *     contributors may be used to endorse or promote products derived from
17 *     this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * Portions of this software have been released under the following terms:
31 *
32 * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC.
33 * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY
34 * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION
35 *
36 * To anyone who acknowledges that this file is provided "AS IS"
37 * without any express or implied warranty:
38 * permission to use, copy, modify, and distribute this file for any
39 * purpose is hereby granted without fee, provided that the above
40 * copyright notices and this notice appears in all source code copies,
41 * and that none of the names of Open Software Foundation, Inc., Hewlett-
42 * Packard Company or Digital Equipment Corporation be used
43 * in advertising or publicity pertaining to distribution of the software
44 * without specific, written prior permission.  Neither Open Software
45 * Foundation, Inc., Hewlett-Packard Company nor Digital
46 * Equipment Corporation makes any representations about the suitability
47 * of this software for any purpose.
48 *
49 * Copyright (c) 2007, Novell, Inc. All rights reserved.
50 * Redistribution and use in source and binary forms, with or without
51 * modification, are permitted provided that the following conditions
52 * are met:
53 *
54 * 1.  Redistributions of source code must retain the above copyright
55 *     notice, this list of conditions and the following disclaimer.
56 * 2.  Redistributions in binary form must reproduce the above copyright
57 *     notice, this list of conditions and the following disclaimer in the
58 *     documentation and/or other materials provided with the distribution.
59 * 3.  Neither the name of Novell Inc. nor the names of its contributors
60 *     may be used to endorse or promote products derived from this
61 *     this software without specific prior written permission.
62 *
63 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
64 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
65 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
66 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
67 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
68 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
69 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
70 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
71 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
72 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
73 *
74 * @APPLE_LICENSE_HEADER_END@
75 */
76
77/*
78**
79**  NAME
80**
81**      comif.c
82**
83**  FACILITY:
84**
85**      Remote Procedure Call (RPC)
86**
87**  ABSTRACT:
88**
89**  Interface Service for the Common Communications Service.  Contains
90**  routines to register an interface, unregister an interface, perform lookups
91**  of interface specifications within the Interface Registry Table, which is
92**  contained within this module.
93**
94**
95*/
96
97#include <commonp.h>    /* Common internals for RPC runtime system  */
98#include <com.h>        /* Externals for Common Services component  */
99#include <comp.h>       /* Internals for Common Services component  */
100
101#include <dce/mgmt.h>
102
103/*
104 * the size of the interface registry hash table
105 * - pick a prime number to avoid collisions
106 */
107#define RPC_C_IF_REGISTRY_SIZE       31
108
109/*
110 *  The Interface Registry Table, where interface specifications
111 *  are registered, and upon which the routines contained within
112 *  this module perform their actions.  Protected by "if_mutex".
113 */
114INTERNAL rpc_list_t if_registry[RPC_C_IF_REGISTRY_SIZE] = { {0,0} };
115INTERNAL rpc_mutex_t if_mutex;
116
117/*
118 * an if registry list entry
119 */
120typedef struct
121{
122    rpc_list_t      link;
123    rpc_if_rep_p_t  if_spec;
124    rpc_mgr_epv_t   default_mepv;
125    unsigned        copied_mepv: 1; /* 1 = mepv copied at registration time  */
126    unsigned        internal: 1; /* 1 = internal if; don't wildcard unregstr */
127    rpc_list_t      type_info_list;
128    unsigned32      flags;
129    unsigned32      max_calls;
130    unsigned32      max_rpc_size;
131    rpc_if_callback_fn_t if_callback;
132} rpc_if_rgy_entry_t, *rpc_if_rgy_entry_p_t;
133
134/*
135 * an if type/info list entry
136 */
137typedef struct
138{
139    rpc_list_t      link;
140    idl_uuid_t          type;        /* type of object to which entry applies    */
141    rpc_mgr_epv_t   mepv;        /* pointer to manager procedures            */
142    unsigned        copied_mepv: 1; /* 1 = mepv copied at registration time  */
143} rpc_if_type_info_t, *rpc_if_type_info_p_t;
144
145INTERNAL void unregister_if_entry (
146        rpc_if_rgy_entry_p_t    /*if_entry*/,
147        uuid_p_t                /*mgr_type_uuid*/,
148        unsigned32              * /*status*/
149    );
150
151/*
152**++
153**
154**  ROUTINE NAME:       rpc__if_init
155**
156**  SCOPE:              PRIVATE - declared in com.h
157**
158**  DESCRIPTION:
159**
160**  Initializes this module.
161**
162**  INPUTS:             none
163**
164**  INPUTS/OUTPUTS:     none
165**
166**  OUTPUTS:
167**
168**      status          The result of the operation.
169**
170**  IMPLICIT INPUTS:    none
171**
172**  IMPLICIT OUTPUTS:   none
173**
174**  FUNCTION VALUE:     void
175**
176**  SIDE EFFECTS:       none
177**
178**--
179**/
180
181PRIVATE void rpc__if_init
182(
183    unsigned32 * status
184)
185{
186    RPC_MUTEX_INIT (if_mutex);
187    *status = rpc_s_ok;
188}
189
190/*
191**++
192**
193**  ROUTINE NAME:       rpc__if_fork_handler
194**
195**  SCOPE:              PRIVATE - declared in com.h
196**
197**  DESCRIPTION:
198**
199**  Initializes this module.
200**
201**  INPUTS:             stage   The stage of the fork we are
202**                              currently handling.
203**
204**  INPUTS/OUTPUTS:     none
205**
206**  OUTPUTS:            none
207**
208**  IMPLICIT INPUTS:    none
209**
210**  IMPLICIT OUTPUTS:   none
211**
212**  FUNCTION VALUE:     void
213**
214**  SIDE EFFECTS:       none
215**
216**--
217**/
218
219PRIVATE void rpc__if_fork_handler
220(
221  rpc_fork_stage_id_t stage
222)
223{
224    unsigned32 i;
225
226    switch ((int)stage)
227    {
228        case RPC_C_PREFORK:
229                break;
230        case RPC_C_POSTFORK_PARENT:
231                break;
232        case RPC_C_POSTFORK_CHILD:
233                /*
234                 * Empty the Interface Registry Table
235                 */
236                for (i = 0; i < RPC_C_IF_REGISTRY_SIZE; i++)
237                {
238                    if_registry[i].next = NULL;
239                    if_registry[i].last = NULL;
240                }
241                break;
242    }
243}
244
245
246/*
247**++
248**
249**  ROUTINE NAME:       rpc_server_register_if
250**
251**  SCOPE:              PUBLIC - declared in rpc.idl
252**
253**  DESCRIPTION:
254**
255**  See description of "rpc__server_register_if_int".
256**
257**  INPUTS:
258**
259**      ifspec_h        Pointer to the ifspec
260**
261**      mgr_type_uuid   The interface type (if any)
262**
263**      mgr_epv         The manager epv for this interface
264**
265**  INPUTS/OUTPUTS:     none
266**
267**  OUTPUTS:
268**
269**      status          The result of the operation. One of:
270**                          rpc_s_ok
271**                          rpc_s_type_already_registered
272**                          rpc_s_no_memory
273**                          rpc_s_coding_error
274**
275**  IMPLICIT INPUTS:    none
276**
277**  IMPLICIT OUTPUTS:   none
278**
279**  FUNCTION VALUE:     void
280**
281**  SIDE EFFECTS:       none
282**
283**--
284**/
285
286PUBLIC void rpc_server_register_if
287(
288    rpc_if_handle_t             ifspec_h,
289    uuid_p_t                    mgr_type_uuid,
290    rpc_mgr_epv_t               mgr_epv,
291    unsigned32                  *status
292)
293{
294    CODING_ERROR (status);
295    RPC_VERIFY_INIT ();
296
297    rpc__server_register_if_int
298        (ifspec_h, mgr_type_uuid, mgr_epv, 0,
299         rpc_c_listen_max_calls_default, -1, NULL, false, status);
300}
301
302/*
303**++
304**
305**  ROUTINE NAME:       rpc__server_register_if_int
306**
307**  SCOPE:              PRIVATE - declared in com.h
308**
309**  DESCRIPTION:
310**
311**  Perform a hash lookup through the Interface Registry Table to try to
312**  locate the interface spec requested. If the search fails, add the
313**  interface entry to the appropriate list. Then proceed to insert the type
314**  uuid specified into the linked list for the requested interface.  If the
315**  requested interface was located by the lookup, simply insert the type
316**  uuid.
317**
318**  If a NULL manager entry point vector is specified, use the one in the
319**  ifspec.
320**
321**  INPUTS:
322**
323**      ifspec_h        Pointer to the ifspec
324**
325**      mgr_type_uuid   The interface type (if any)
326**
327**      mgr_epv         The manager epv for this interface
328**
329**      flags           Registration flags
330**
331**      max_calls       Maximum calls
332**
333**      max_rpc_size    Maximum RPC size (-1 for no maximum)
334**
335**      if_callback     Security callback
336**
337**      is_internal     T => manager should not be unregisterable by wildcarding
338**
339**  INPUTS/OUTPUTS:     none
340**
341**  OUTPUTS:
342**
343**      status          The result of the operation. One of:
344**                          rpc_s_ok
345**                          rpc_s_type_already_registered
346**                          rpc_s_no_memory
347**                          rpc_s_coding_error
348**
349**  IMPLICIT INPUTS:    none
350**
351**  IMPLICIT OUTPUTS:   none
352**
353**  FUNCTION VALUE:     void
354**
355**  SIDE EFFECTS:       none
356**
357**--
358**/
359
360PRIVATE void rpc__server_register_if_int
361(
362    rpc_if_handle_t             ifspec_h,
363    uuid_p_t                    mgr_type_uuid,
364    rpc_mgr_epv_t               mgr_epv,
365    unsigned32                  flags,
366    unsigned32                  max_calls,
367    unsigned32                  max_rpc_size,
368    rpc_if_callback_fn_t        if_callback,
369    boolean32                   is_internal,
370    unsigned32                  *status
371)
372{
373    rpc_if_rep_p_t              if_rep = (rpc_if_rep_p_t) ifspec_h;
374    rpc_mgr_epv_t               mepv;
375    rpc_if_rgy_entry_p_t        if_entry;
376    unsigned32                  index;
377    unsigned32                  ctr;
378    boolean                     copied_mepv = false;
379    boolean                     if_entry_alloced = false;
380    boolean                     if_entry_added = false;
381
382    CODING_ERROR (status);
383
384    RPC_IF_VALIDATE(if_rep, status);
385    if (*status != rpc_s_ok)
386    {
387        return;
388    }
389
390    /*
391     * check to see if a NULL mgr_epv was passed
392     * - if so, use the default one in the ifspec
393     * - if it's non-NULL, make a copy of it
394     */
395    if (mgr_epv == (rpc_mgr_epv_t) NULL)
396    {
397        mepv = if_rep->manager_epv;
398        if (mepv == NULL)
399        {
400            *status = rpc_s_no_mepv;
401            return;
402        }
403    }
404    else
405    {
406        RPC_MEM_ALLOC (
407            mepv,
408            rpc_mgr_epv_t,
409            sizeof (rpc_mgr_epv_t *) +
410                (sizeof (rpc_mgr_proc_t) * (if_rep->opcnt - 1)),
411            RPC_C_MEM_MGR_EPV,
412            RPC_C_MEM_WAITOK);
413
414        if (mepv == NULL)
415        {
416            *status = rpc_s_no_memory;
417            return;
418        }
419
420        /*
421         * fill the manager epv entries into the copy
422         */
423        for (ctr = 0; ctr < if_rep->opcnt; ctr++)
424        {
425            mepv[ctr] = mgr_epv[ctr];
426        }
427
428        copied_mepv = true;
429    }
430
431    /*
432     * compute a hash value using the interface uuid - check the status
433     * from uuid_hash to make sure the uuid has a valid format
434     */
435    index = (uuid_hash (&(if_rep->id), status)) % RPC_C_IF_REGISTRY_SIZE;
436
437    if (*status != uuid_s_ok)
438    {
439        if (copied_mepv)
440        {
441            RPC_MEM_FREE (mepv, RPC_C_MEM_MGR_EPV);
442        }
443        return;
444    }
445
446    /*
447     * take out a lock to protect access to the if registry
448     */
449    RPC_MUTEX_LOCK (if_mutex);
450
451    /*
452     * see if the specified interface already exists in the registry
453     */
454    RPC_LIST_FIRST (if_registry[index], if_entry, rpc_if_rgy_entry_p_t);
455
456    while (if_entry != NULL)
457    {
458        /*
459         * see if the if uuid and version match
460         */
461        if ((UUID_EQ (if_entry->if_spec->id, if_rep->id, status))
462            && if_entry->if_spec->vers == if_rep->vers)
463        {
464            break;
465        }
466
467        RPC_LIST_NEXT (if_entry, if_entry, rpc_if_rgy_entry_p_t);
468    }
469
470    /*
471     * if no entry was found, create one and add it to the list
472     */
473    if (if_entry == NULL)
474    {
475        RPC_MEM_ALLOC (
476            if_entry,
477            rpc_if_rgy_entry_p_t,
478            sizeof (rpc_if_rgy_entry_t),
479            RPC_C_MEM_IF_RGY_ENTRY,
480            RPC_C_MEM_WAITOK);
481
482        if (if_entry == NULL)
483        {
484            *status = rpc_s_no_memory;
485            goto ERROR_AND_LOCKED;
486        }
487        if_entry_alloced = true;
488
489        /*
490         * initialize the entry
491         */
492        if_entry->if_spec = if_rep;
493        if_entry->default_mepv = NULL;
494        if_entry->internal = is_internal;
495        RPC_LIST_INIT (if_entry->type_info_list);
496        if_entry->flags = flags;
497        if_entry->max_calls = max_calls;
498        if_entry->max_rpc_size = max_rpc_size;
499        if_entry->if_callback = if_callback;
500
501        /*
502         * put it on the list for this hash index
503         */
504        RPC_LIST_ADD_TAIL (if_registry[index], if_entry, rpc_if_rgy_entry_p_t);
505        if_entry_added = true;
506    }
507
508    /*
509     * see if a manager type was specified (and is non-nil)
510     */
511    if (mgr_type_uuid != NULL && !(uuid_is_nil (mgr_type_uuid, status)))
512    {
513	rpc_if_type_info_p_t type_info = NULL;
514
515        /*
516         * see if the specified mgr type already exists for this entry
517         */
518        RPC_LIST_FIRST
519            (if_entry->type_info_list, type_info, rpc_if_type_info_p_t);
520
521        while (type_info != NULL)
522        {
523            /*
524             * see if the type uuid matches the one specified
525             */
526            if (UUID_EQ (type_info->type, *mgr_type_uuid, status))
527            {
528                *status = rpc_s_type_already_registered;
529                goto ERROR_AND_LOCKED;
530            }
531
532            RPC_LIST_NEXT (type_info, type_info, rpc_if_type_info_p_t);
533        }
534
535        /*
536         * no entry was found, create one and add it to the list
537         */
538        assert (type_info == NULL);
539
540	/*
541	 * malloc a type uuid/manager epv list element
542	 */
543	RPC_MEM_ALLOC (
544	    type_info,
545	    rpc_if_type_info_p_t,
546	    sizeof (rpc_if_type_info_t),
547	    RPC_C_MEM_IF_TYPE_INFO,
548	    RPC_C_MEM_WAITOK);
549
550	if (type_info == NULL)
551	{
552	    *status = rpc_s_no_memory;
553	    goto ERROR_AND_LOCKED;
554	}
555
556	/*
557	 * fill in the supplied type info
558	 */
559	type_info->type = *mgr_type_uuid;
560	type_info->mepv = mepv;
561	type_info->copied_mepv = copied_mepv;
562
563	/*
564	 * add the type info entry to the list for this interface
565	 */
566	RPC_LIST_ADD_TAIL
567	    (if_entry->type_info_list, type_info, rpc_if_type_info_p_t);
568    }
569    else
570    {
571        /*
572         * set the default manager epv
573         */
574        if (if_entry->default_mepv != NULL)
575        {
576            *status = rpc_s_type_already_registered;
577            goto ERROR_AND_LOCKED;
578        }
579        if_entry->default_mepv = mepv;
580        if_entry->copied_mepv = copied_mepv;
581    }
582
583    /*
584     * free the global lock and return
585     */
586    RPC_MUTEX_UNLOCK (if_mutex);
587    *status = rpc_s_ok;
588    return;
589
590ERROR_AND_LOCKED:
591    /*
592     * perform necessary cleanup, free the global lock and return
593     * (the return status already set).
594     */
595
596    if (if_entry_alloced)
597    {
598        if (if_entry_added)
599        {
600            RPC_LIST_REMOVE (if_registry[index], if_entry);
601        }
602        RPC_MEM_FREE (if_entry, RPC_C_MEM_IF_RGY_ENTRY);
603    }
604    if (copied_mepv)
605    {
606        RPC_MEM_FREE (mepv, RPC_C_MEM_MGR_EPV);
607    }
608
609    RPC_MUTEX_UNLOCK (if_mutex);
610    return;
611}
612
613/*
614**++
615**
616**  ROUTINE NAME:       rpc_server_unregister_if_int
617**
618**  SCOPE:              PRIVATE - declared in com.h
619**
620**  DESCRIPTION:
621**
622**  Perform a hash lookup on the Interface Registry Table to locate the
623**  specified interface spec. If the search fails, return
624**  'rpc_s_unknown_if'.  If a registered interface is located with the
625**  UUID and version specified in the if_spec, it is deleted from the
626**  Interface Registry Table along with the linked list of Type UUIDs.
627**
628**  Also returns the pointer to the ifspec in the entry that was
629**  unregistered.  This pointer turns out to be needed by the compatibility
630**  library.
631**
632**  INPUTS:
633**
634**      ifspec_h            Pointer to the ifspec
635**
636**      mgr_type_uuid       The type uuid of the manager epv to unregister.
637**
638**  INPUTS/OUTPUTS:     none
639**
640**  OUTPUTS:
641**
642**      rtn_ifspec_h    Pointer to the ifspec that was in the entry that was
643**                      unregistered.
644**
645**      status          The result of the operation. One of:
646**                          rpc_s_ok
647**                          rpc_s_unknown_if
648**                          rpc_s_coding_error
649**
650**  IMPLICIT INPUTS:    none
651**
652**  IMPLICIT OUTPUTS:   none
653**
654**  FUNCTION VALUE:     void
655**
656**  SIDE EFFECTS:       none
657**
658**--
659**/
660
661PRIVATE void rpc__server_unregister_if_int
662(
663    rpc_if_handle_t             ifspec_h,
664    uuid_p_t                    mgr_type_uuid,
665    rpc_if_handle_t             *rtn_ifspec_h,
666    unsigned32                  *status
667)
668{
669    rpc_if_rep_p_t              if_rep = (rpc_if_rep_p_t) ifspec_h;
670    unsigned32                  index;
671    rpc_if_rgy_entry_p_t        if_entry, next_if_entry;
672    boolean                     found_mgr_type;
673
674    CODING_ERROR (status);
675
676    *rtn_ifspec_h = NULL;
677
678    /*
679     * take out a lock to protect access to the if registry
680     */
681    RPC_MUTEX_LOCK (if_mutex);
682
683    /*
684     * see what kind of unregister is wanted
685     */
686    if (if_rep == NULL)
687    {
688        /*
689         * go through the whole registry hash table
690         */
691        for (index = 0, found_mgr_type = false;
692            index < RPC_C_IF_REGISTRY_SIZE; index++)
693        {
694            /*
695             * walk the list of entries for each hash value
696             */
697            RPC_LIST_FIRST (if_registry[index], if_entry, rpc_if_rgy_entry_p_t);
698
699            while (if_entry != NULL)
700            {
701                /*
702                 * do whatever unregister is required for this entry
703                 */
704                if (! if_entry->internal)
705                {
706                    unregister_if_entry (if_entry, mgr_type_uuid, status);
707
708                    if (*status != rpc_s_ok)
709                    {
710                        if (*status != rpc_s_unknown_mgr_type)
711                        {
712                            RPC_MUTEX_UNLOCK (if_mutex);
713                            return;
714                        }
715                    }
716                    else
717                    {
718                        found_mgr_type = true;
719                    }
720                }
721
722                RPC_LIST_NEXT (if_entry, next_if_entry, rpc_if_rgy_entry_p_t);
723
724                /*
725                 * See if there are any mgr types left for this interface
726                 * entry.  If not, remove this entry from the list for this
727                 * hash value, and free the entry.
728                 */
729                if (RPC_LIST_EMPTY (if_entry->type_info_list) &&
730                    if_entry->default_mepv == NULL)
731                {
732                    RPC_LIST_REMOVE (if_registry[index], if_entry);
733
734                    RPC_MEM_FREE (if_entry, RPC_C_MEM_IF_RGY_ENTRY);
735                }
736
737                if_entry = next_if_entry;
738            }
739        }
740
741        if (!found_mgr_type)
742        {
743            RPC_MUTEX_UNLOCK (if_mutex);
744            *status = rpc_s_unknown_mgr_type;
745            return;
746        }
747    }
748    else
749    {
750        /*
751         * compute a hash value using the interface uuid - check the status
752         * from uuid_hash to make sure the uuid has a valid format
753         */
754        index = uuid_hash (&(if_rep->id), status) % RPC_C_IF_REGISTRY_SIZE;
755
756        if (*status != uuid_s_ok)
757        {
758            RPC_MUTEX_UNLOCK (if_mutex);
759            return;
760        }
761
762        /*
763         * walk the list of entries for this hash value
764         */
765        RPC_LIST_FIRST (if_registry[index], if_entry, rpc_if_rgy_entry_p_t);
766
767        while (if_entry != NULL)
768        {
769            if (! if_entry->internal)
770            {
771                /*
772                 * see if the if uuid and version match
773                 */
774                if ((UUID_EQ (if_entry->if_spec->id, if_rep->id, status))
775                    && if_entry->if_spec->vers == if_rep->vers)
776                {
777                    /*
778                     * snag the ifspec now, before the if entry (maybe) gets
779                     * freed.
780                     */
781                    *rtn_ifspec_h = (rpc_if_handle_t) if_entry->if_spec;
782
783                    /*
784                     * do whatever unregister is required for this entry
785                     */
786                    unregister_if_entry (if_entry, mgr_type_uuid, status);
787
788                    if (*status != rpc_s_ok)
789                    {
790                        RPC_MUTEX_UNLOCK (if_mutex);
791                        return;
792                    }
793
794                    /*
795                     * See if there are any mgr types left for this
796                     * interface entry.  If not, remove this entry from
797                     * the list for this hash value, and free the entry.
798                     */
799                    if (RPC_LIST_EMPTY (if_entry->type_info_list) &&
800                        if_entry->default_mepv == NULL)
801                    {
802                        RPC_LIST_REMOVE (if_registry[index], if_entry);
803
804                        RPC_MEM_FREE (if_entry, RPC_C_MEM_IF_RGY_ENTRY);
805                    }
806
807                    /*
808                     * finished searching
809                     */
810                    break;
811                }
812            }
813
814            RPC_LIST_NEXT (if_entry, if_entry, rpc_if_rgy_entry_p_t);
815        }
816
817        if (*rtn_ifspec_h == NULL)
818        {
819            RPC_MUTEX_UNLOCK (if_mutex);
820            *status = rpc_s_unknown_if;
821            return;
822        }
823    }
824
825    RPC_MUTEX_UNLOCK (if_mutex);
826    *status = rpc_s_ok;
827    return;
828}
829
830/*
831**++
832**
833**  ROUTINE NAME:       rpc_server_unregister_if
834**
835**  SCOPE:              PUBLIC - declared in rpc.idl
836**
837**  DESCRIPTION:
838**
839**  See description of "rpc__server_unregister_int".
840**
841**  INPUTS:
842**
843**      ifspec_h            Pointer to the ifspec
844**
845**      mgr_type_uuid       The type uuid of the manager epv to unregister.
846**
847**  INPUTS/OUTPUTS:     none
848**
849**  OUTPUTS:
850**
851**      status          The result of the operation. One of:
852**                          rpc_s_ok
853**                          rpc_s_unknown_if
854**                          rpc_s_coding_error
855**
856**  IMPLICIT INPUTS:    none
857**
858**  IMPLICIT OUTPUTS:   none
859**
860**  FUNCTION VALUE:     void
861**
862**  SIDE EFFECTS:       none
863**
864**--
865**/
866
867PUBLIC void rpc_server_unregister_if
868(
869    rpc_if_handle_t             ifspec_h,
870    uuid_p_t                    mgr_type_uuid,
871    unsigned32                  *status
872)
873{
874    rpc_if_handle_t             rtn_ifspec_h;
875
876    CODING_ERROR (status);
877    RPC_VERIFY_INIT ();
878
879    rpc__server_unregister_if_int (ifspec_h, mgr_type_uuid, &rtn_ifspec_h, status);
880}
881
882/*
883**  This routine is called by rpc_server_unregister_if() to process a single
884**  interface entry in the if registry.
885**/
886
887INTERNAL void unregister_if_entry
888(
889    rpc_if_rgy_entry_p_t    if_entry,
890    uuid_p_t                mgr_type_uuid,
891    unsigned32              *status
892)
893{
894    rpc_if_type_info_p_t        type_info;
895    rpc_if_type_info_p_t        current_type_info;
896
897    /*
898     * see if this is a wildcard operation
899     */
900    if (mgr_type_uuid == NULL)
901    {
902        /*
903         * free the default manager epv if copied on register
904         */
905        if (if_entry->copied_mepv)
906        {
907            RPC_MEM_FREE (if_entry->default_mepv, RPC_C_MEM_MGR_EPV);
908        }
909
910        if_entry->default_mepv = NULL;
911
912        /*
913         * walk the type info list and remove all entries
914         */
915        RPC_LIST_FIRST
916            (if_entry->type_info_list, type_info, rpc_if_type_info_p_t);
917
918        while (type_info != NULL)
919        {
920            /*
921             * free the mepv if copied during register
922             */
923            if (type_info->copied_mepv)
924            {
925                RPC_MEM_FREE (type_info->mepv, RPC_C_MEM_MGR_EPV);
926            }
927
928            /*
929             * remove this entry from the list for this interface
930             */
931            RPC_LIST_REMOVE (if_entry->type_info_list, type_info);
932
933            /*
934             * save this entry and get the next one on the list
935             */
936            current_type_info = type_info;
937
938            RPC_LIST_FIRST
939                (if_entry->type_info_list, type_info, rpc_if_type_info_p_t);
940
941            /*
942             * free the type info entry itself
943             */
944            RPC_MEM_FREE (current_type_info, RPC_C_MEM_IF_TYPE_INFO);
945        }
946    }
947    else
948    {
949        /*
950         * see if this is an unregister for the default manager epv
951         */
952        if (uuid_is_nil (mgr_type_uuid, status))
953        {
954            if (if_entry->default_mepv == NULL)
955            {
956                *status = rpc_s_unknown_mgr_type;
957                return;
958            }
959
960            /*
961             * free the default manager epv if copied on register
962             */
963            if (if_entry->copied_mepv)
964            {
965                RPC_MEM_FREE (if_entry->default_mepv, RPC_C_MEM_MGR_EPV);
966            }
967
968            if_entry->default_mepv = NULL;
969        }
970        else
971        {
972            /*
973             * walk the type info list looking for matches
974             */
975            RPC_LIST_FIRST
976                (if_entry->type_info_list, type_info, rpc_if_type_info_p_t);
977
978            while (type_info != NULL)
979            {
980                /*
981                 * only remove entries whose type uuid's match the one specified
982                 */
983                if (UUID_EQ (type_info->type, *mgr_type_uuid, status))
984                {
985                    /*
986                     * free the mepv if copied during register
987                     */
988                    if (type_info->copied_mepv)
989                    {
990                        RPC_MEM_FREE (type_info->mepv, RPC_C_MEM_MGR_EPV);
991                    }
992
993                    /*
994                     * remove this entry from the list for this interface
995                     */
996                    RPC_LIST_REMOVE (if_entry->type_info_list, type_info);
997
998                    /*
999                     * free the type info entry itself
1000                     */
1001                    RPC_MEM_FREE (type_info, RPC_C_MEM_IF_TYPE_INFO);
1002
1003                    /*
1004                     * then stop the search
1005                     */
1006                    break;
1007                }
1008
1009                RPC_LIST_NEXT (type_info, type_info, rpc_if_type_info_p_t);
1010            }
1011
1012            if (type_info == NULL)
1013            {
1014                *status = rpc_s_unknown_mgr_type;
1015                return;
1016            }
1017        }
1018    }
1019
1020    *status = rpc_s_ok;
1021    return;
1022}
1023
1024/*
1025**++
1026**
1027**  ROUTINE NAME:       rpc__if_lookup
1028**
1029**  SCOPE:              PRIVATE - declared in comif.h
1030**
1031**  DESCRIPTION:
1032**
1033**  Look into the Interface Registry Table for the Interface requested.
1034**  The search is conducted in either one or two steps.  First the index
1035**  from a previous request that is remembered in 'ihint' is tried,  then
1036**  if this fails to locate the interface, a regular hash lookup is performed.
1037**  If the interface can't be located 'rpc_s_unknown_if' is returned.
1038**
1039**  Once the interface is located, its attached linked list of type UUIDs
1040**  is searched for the type UUID specified.  If the requested type uuid
1041**  is not found 'rpc_s_unknown_mgr_type' is returned.  Once the requested
1042**  interface and type UUID are located a pointer to the interface
1043**  specification is returned. Also returned are the server stub epv
1044**  and the manager epv. The index to this Interface registry is saved in
1045**  the location pointed to by 'ihint', under the assumption that a subsequent
1046**  lookup may request this same interface.
1047**
1048**  INPUTS:
1049**
1050**      if_uuid         The interface UUID to lookup
1051**
1052**      if_vers         The interface version to lookup
1053**
1054**      mgr_type_uuid   The interface type (if any)
1055**                      (set this to NULL or the nil uuid to cause the
1056**                      default manager epv to be returned)
1057**
1058**  INPUTS/OUTPUTS:
1059**
1060**      ihint           A hint of the index into the table for this if
1061**
1062**  OUTPUTS:
1063**
1064**      ifspec_h        Pointer to the ifspec
1065**                      (NULL on input if not wanted)
1066**
1067**      sepv            The server stub epv for this interface
1068**                      (NULL on input if not wanted)
1069**
1070**      mepv            The manager epv for this interface
1071**                      (NULL on input if not wanted)
1072**
1073**      status          The result of the operation. One of:
1074**                          rpc_s_ok
1075**                          rpc_s_unknown_if
1076**                          rpc_s_unknown_mgr_type
1077**                          rpc_s_coding_error
1078**
1079**  IMPLICIT INPUTS:    none
1080**
1081**  IMPLICIT OUTPUTS:   none
1082**
1083**  FUNCTION VALUE:     void
1084**
1085**  SIDE EFFECTS:       none
1086**
1087**--
1088**/
1089
1090PRIVATE void rpc__if_lookup
1091(
1092    uuid_p_t                    if_uuid,
1093    unsigned32                  if_vers,
1094    uuid_p_t                    mgr_type_uuid,
1095    unsigned16                  *ihint,
1096    rpc_if_rep_p_t              *ifspec,
1097    rpc_v2_server_stub_epv_t    *sepv,
1098    rpc_mgr_epv_t               *mepv,
1099    unsigned32                  *status
1100)
1101{
1102    return rpc__if_lookup2 (if_uuid, if_vers, mgr_type_uuid,
1103                            ihint, ifspec, sepv, mepv,
1104                            NULL, NULL, NULL, NULL, status);
1105}
1106
1107
1108/*
1109**++
1110**
1111**  ROUTINE NAME:       rpc__if_lookup2
1112**
1113**  SCOPE:              PRIVATE - declared in comif.h
1114**
1115**  DESCRIPTION:
1116**
1117**  Look into the Interface Registry Table for the Interface requested.
1118**  The search is conducted in either one or two steps.  First the index
1119**  from a previous request that is remembered in 'ihint' is tried,  then
1120**  if this fails to locate the interface, a regular hash lookup is performed.
1121**  If the interface can't be located 'rpc_s_unknown_if' is returned.
1122**
1123**  Once the interface is located, its attached linked list of type UUIDs
1124**  is searched for the type UUID specified.  If the requested type uuid
1125**  is not found 'rpc_s_unknown_mgr_type' is returned.  Once the requested
1126**  interface and type UUID are located a pointer to the interface
1127**  specification is returned. Also returned are the server stub epv
1128**  and the manager epv. The index to this Interface registry is saved in
1129**  the location pointed to by 'ihint', under the assumption that a subsequent
1130**  lookup may request this same interface.
1131**
1132**  INPUTS:
1133**
1134**      if_uuid         The interface UUID to lookup
1135**
1136**      if_vers         The interface version to lookup
1137**
1138**      mgr_type_uuid   The interface type (if any)
1139**                      (set this to NULL or the nil uuid to cause the
1140**                      default manager epv to be returned)
1141**
1142**  INPUTS/OUTPUTS:
1143**
1144**      ihint           A hint of the index into the table for this if
1145**
1146**  OUTPUTS:
1147**
1148**      ifspec_h        Pointer to the ifspec
1149**                      (NULL on input if not wanted)
1150**
1151**      sepv            The server stub epv for this interface
1152**                      (NULL on input if not wanted)
1153**
1154**      mepv            The manager epv for this interface
1155**                      (NULL on input if not wanted)
1156**
1157**      flags           The interface registration flags
1158**                      (NULL on input if not wanted)
1159**
1160**      max_calls       The maximum number of concurrent RPCs
1161**                      (NULL on input if not wanted)
1162**
1163**      max_rpc_size    The maximum size of incoming data blocks
1164**                      (NULL on input if not wanted)
1165**
1166**      if_callback     The security callback function
1167**                      (NULL on input if not wanted)
1168**
1169**      status          The result of the operation. One of:
1170**                          rpc_s_ok
1171**                          rpc_s_unknown_if
1172**                          rpc_s_unknown_mgr_type
1173**                          rpc_s_coding_error
1174**
1175**  IMPLICIT INPUTS:    none
1176**
1177**  IMPLICIT OUTPUTS:   none
1178**
1179**  FUNCTION VALUE:     void
1180**
1181**  SIDE EFFECTS:       none
1182**
1183**--
1184**/
1185
1186PRIVATE void rpc__if_lookup2
1187(
1188    uuid_p_t                    if_uuid,
1189    unsigned32                  if_vers,
1190    uuid_p_t                    mgr_type_uuid,
1191    unsigned16                  *ihint,
1192    rpc_if_rep_p_t              *ifspec,
1193    rpc_v2_server_stub_epv_t    *sepv,
1194    rpc_mgr_epv_t               *mepv,
1195    unsigned32                  *flags,
1196    unsigned32                  *max_calls,
1197    unsigned32                  *max_rpc_size,
1198    rpc_if_callback_fn_t        *if_callback,
1199    unsigned32                  *status
1200)
1201{
1202    rpc_if_rgy_entry_p_t        if_entry = NULL;
1203    rpc_if_type_info_p_t        type_info;
1204    unsigned32                  index;
1205    unsigned32                  entry_count = 0;
1206    unsigned32                  temp_status;
1207
1208    RPC_LOG_IF_LOOKUP_NTR;
1209    CODING_ERROR (status);
1210
1211    /*
1212     * take out a lock to protect access to the if registry
1213     */
1214    RPC_MUTEX_LOCK (if_mutex);
1215
1216    /*
1217     * see if the interface hint we're given is valid
1218     */
1219    if (*ihint != RPC_C_INVALID_IHINT)
1220    {
1221        /*
1222         * extract the hash value from the low byte of the ihint
1223         * and the list entry count form the high byte
1224         */
1225        index = *ihint & 0x00FF;
1226        entry_count = (*ihint & 0xFF00) >> 8;
1227
1228        /*
1229         * try to find a match using the hints provided
1230         */
1231        RPC_LIST_LOOKUP
1232            (if_registry[index], if_entry, rpc_if_rgy_entry_p_t, entry_count);
1233
1234        if (if_entry != NULL &&
1235            ! RPC_IF_IS_COMPATIBLE (if_entry, if_uuid, if_vers, status))
1236        {
1237            if_entry = NULL;
1238        }
1239    }
1240    else
1241    {
1242        /*
1243         * compute a hash value using the interface uuid - check the status
1244         * from uuid_hash to make sure the uuid has a valid format
1245         */
1246        index = uuid_hash (if_uuid, status) % RPC_C_IF_REGISTRY_SIZE;
1247
1248        if (*status != uuid_s_ok)
1249        {
1250            RPC_MUTEX_UNLOCK (if_mutex);
1251            return;
1252        }
1253    }
1254
1255    /*
1256     * if we got this far and didn't find a match, search the whole list
1257     * under the current hash value for the given interface
1258     */
1259    if (if_entry == NULL)
1260    {
1261        RPC_LIST_FIRST (if_registry[index], if_entry, rpc_if_rgy_entry_p_t);
1262
1263        for (entry_count = 1; if_entry != NULL; entry_count++)
1264        {
1265            if (RPC_IF_IS_COMPATIBLE (if_entry, if_uuid, if_vers, status))
1266            {
1267                break;
1268            }
1269
1270            RPC_LIST_NEXT (if_entry, if_entry, rpc_if_rgy_entry_p_t);
1271        }
1272    }
1273
1274    /*
1275     * if still no entry was found, report unknown interface
1276     */
1277    if (if_entry == NULL)
1278    {
1279        *ihint = RPC_C_INVALID_IHINT;
1280        *status = rpc_s_unknown_if;
1281        RPC_MUTEX_UNLOCK (if_mutex);
1282        return;
1283    }
1284
1285    /*
1286     * if a manager type uuid is given, and is not the nil uuid, try to match
1287     * for a registered type - otherwise, return the default manager epv
1288     */
1289    if (mgr_type_uuid != NULL && !(uuid_is_nil (mgr_type_uuid, status)))
1290    {
1291        /*
1292         * scan the type uuid/mgr epv list for a match
1293         */
1294        RPC_LIST_FIRST
1295            (if_entry->type_info_list, type_info, rpc_if_type_info_p_t);
1296
1297        while (type_info != NULL)
1298        {
1299            if (UUID_EQ (type_info->type, *mgr_type_uuid, status))
1300            {
1301                if (mepv != NULL)
1302                {
1303                    *mepv = type_info->mepv;
1304                }
1305
1306                break;
1307            }
1308
1309            RPC_LIST_NEXT (type_info, type_info, rpc_if_type_info_p_t);
1310        }
1311
1312        if (type_info == NULL)
1313        {
1314            /*
1315             * if no 'type' match is found, invalidate the interface
1316             * hint.  But before giving up entirely, if the interface
1317             * we're looking for is the internal mgmt interface, try
1318             * one more time using a NIL type; this lets clients make
1319             * remote mgmt calls using bindings that might have a typed
1320             * object in them.
1321             */
1322            *ihint = RPC_C_INVALID_IHINT;
1323            *status = rpc_s_unknown_mgr_type;
1324            RPC_MUTEX_UNLOCK (if_mutex);
1325
1326            if (UUID_EQ (((rpc_if_rep_p_t) mgmt_v1_0_s_ifspec)->id, *if_uuid, &temp_status))
1327            {
1328                rpc__if_lookup2 (if_uuid, if_vers, NULL, ihint, ifspec, sepv, mepv,
1329                                 flags, max_calls, max_rpc_size, if_callback, status);
1330            }
1331
1332            return;
1333        }
1334    }
1335    else
1336    {
1337        /*
1338         * The default (nil-type) manager epv is requested,
1339         * return an error if one isn't registered and a manager epv
1340         * is wanted.
1341         */
1342        if (mepv != NULL)
1343        {
1344            if (if_entry->default_mepv == NULL)
1345            {
1346                *ihint = RPC_C_INVALID_IHINT;
1347                *status = rpc_s_unknown_mgr_type;
1348                RPC_MUTEX_UNLOCK (if_mutex);
1349                return;
1350            }
1351            *mepv = if_entry->default_mepv;
1352        }
1353    }
1354
1355    /*
1356     * if a complete match is found, return its info (if wanted)
1357     */
1358    if (ifspec != NULL)
1359    {
1360        *ifspec = if_entry->if_spec;
1361    }
1362
1363    if (sepv != NULL)
1364    {
1365        *sepv = if_entry->if_spec->server_epv;
1366    }
1367
1368    if (flags != NULL)
1369    {
1370        *flags = if_entry->flags;
1371    }
1372
1373    if (max_calls != NULL)
1374    {
1375        *max_calls = if_entry->max_calls;
1376    }
1377
1378    if (max_rpc_size != NULL)
1379    {
1380        *max_rpc_size = if_entry->max_rpc_size;
1381    }
1382
1383    if (if_callback != NULL)
1384    {
1385        *if_callback = if_entry->if_callback;
1386    }
1387
1388    /*
1389     * provide a useful hint for future references to this interface
1390     */
1391    *ihint = (unsigned16) (index | ((entry_count & 0x00FF) << 8));
1392
1393    RPC_MUTEX_UNLOCK (if_mutex);
1394    *status = rpc_s_ok;
1395    RPC_LOG_IF_LOOKUP_XIT;
1396
1397    return;
1398}
1399
1400/*
1401**++
1402**
1403**  ROUTINE NAME:       rpc_if_inq_id
1404**
1405**  SCOPE:              PUBLIC - declared in rpc.idl
1406**
1407**  DESCRIPTION:
1408**
1409**  Extract the interface id (UUID and version numbers) from the given
1410**  interface spec.
1411**
1412**  INPUTS:
1413**
1414**      ifspec_h        Pointer to the ifspec
1415**
1416**  INPUTS/OUTPUTS:     none
1417**
1418**  OUTPUTS:
1419**
1420**      if_id           The interface id.
1421**
1422**      status          The result of the operation. One of:
1423**                          rpc_s_ok
1424**                          rpc_s_coding_error
1425**
1426**  IMPLICIT INPUTS:    none
1427**
1428**  IMPLICIT OUTPUTS:   none
1429**
1430**  FUNCTION VALUE:     void
1431**
1432**  SIDE EFFECTS:       none
1433**
1434**--
1435**/
1436
1437PUBLIC void rpc_if_inq_id
1438(
1439    rpc_if_handle_t             ifspec_h,
1440    rpc_if_id_t                 *if_id,
1441    unsigned32                  *status
1442)
1443{
1444    CODING_ERROR (status);
1445    RPC_VERIFY_INIT ();
1446
1447    /*
1448     * copy the interface UUID from the if_spec
1449     */
1450    if_id->uuid = ((rpc_if_rep_p_t) (ifspec_h))->id;
1451
1452    /*
1453     * convert the old form of the version number (single unsigned long)
1454     * into the new form (major and minor unsigned16's)
1455     */
1456    if_id->vers_major = RPC_IF_VERS_MAJOR(((rpc_if_rep_p_t) ifspec_h)->vers);
1457    if_id->vers_minor = RPC_IF_VERS_MINOR(((rpc_if_rep_p_t) (ifspec_h))->vers);
1458
1459    *status = rpc_s_ok;
1460}
1461
1462/*
1463**++
1464**
1465**  ROUTINE NAME:       rpc__if_id_compare
1466**
1467**  SCOPE:              PRIVATE - declared in com.h
1468**
1469**  DESCRIPTION:
1470**
1471**  Compares two interface id's and matches based on the version option.
1472**
1473**  INPUTS:
1474**
1475**      if_id_ref       The reference interface id against which the comparison
1476**                      is to be made.
1477**
1478**      if_id           The interface id to be compared to the reference.
1479**
1480**      if_vers_option  The criteria by which the if version numbers are to
1481**                      be compared. One of:
1482**                          rpc_c_vers_all
1483**                          rpc_c_vers_compatible
1484**                          rpc_c_vers_exact
1485**                          rpc_c_vers_major_only
1486**                          rpc_c_vers_upto
1487**
1488**  INPUTS/OUTPUTS:     none
1489**
1490**  OUTPUTS:
1491**
1492**      status          The result of the operation. One of:
1493**                          rpc_s_ok
1494**                          the result of uuid_equal()
1495**
1496**  IMPLICIT INPUTS:    none
1497**
1498**  IMPLICIT OUTPUTS:   none
1499**
1500**  FUNCTION VALUE:
1501**
1502**      true if the interface id is compatible with the reference
1503**      false if the interface id is not compatible with the reference
1504**
1505**  SIDE EFFECTS:       none
1506**
1507**--
1508**/
1509
1510PRIVATE boolean rpc__if_id_compare
1511(
1512    rpc_if_id_p_t           if_id_ref,
1513    rpc_if_id_p_t           if_id,
1514    unsigned32              if_vers_option,
1515    unsigned32              *status
1516)
1517{
1518    *status = rpc_s_ok;
1519
1520    /*
1521     * see if the returned if uuid matches the one given
1522     */
1523    if (! (UUID_EQ (if_id->uuid, if_id_ref->uuid, status)))
1524    {
1525        /*
1526         * return "incompatible" and the status of uuid_equal()
1527         */
1528        return (false);
1529    }
1530    else
1531    {
1532        /*
1533         * if they do match, check what the version option is
1534         */
1535        switch ((int)if_vers_option)
1536        {
1537            /*
1538             * any version is ok
1539             */
1540            case rpc_c_vers_all:
1541            {
1542                return (true);
1543            }
1544
1545            /*
1546             * major versions must match, minor version must be greater than
1547             * or equal to minor version in the reference
1548             */
1549            case rpc_c_vers_compatible:
1550            {
1551                if (if_id->vers_major == if_id_ref->vers_major &&
1552                    if_id->vers_minor >= if_id_ref->vers_minor)
1553                {
1554                    return (true);
1555                }
1556                else
1557                {
1558                    return (false);
1559                }
1560            }
1561
1562            /*
1563             * major and minor versions must match
1564             */
1565            case rpc_c_vers_exact:
1566            {
1567                if (if_id->vers_major == if_id_ref->vers_major &&
1568                    if_id->vers_minor == if_id_ref->vers_minor)
1569                {
1570                    return (true);
1571                }
1572                else
1573                {
1574                    return (false);
1575                }
1576            }
1577
1578            /*
1579             * major versions must match - minor versions are ignored
1580             */
1581            case rpc_c_vers_major_only:
1582            {
1583                if (if_id->vers_major == if_id_ref->vers_major)
1584                {
1585                    return (true);
1586                }
1587                else
1588                {
1589                    return (false);
1590                }
1591            }
1592
1593            /*
1594             * major version and minor version must both be less than or
1595             * equal to their counterparts in the reference
1596             */
1597            case rpc_c_vers_upto:
1598            {
1599                if (if_id->vers_major < if_id_ref->vers_major)
1600                {
1601                    return (true);
1602                }
1603                else
1604                {
1605                    if (if_id->vers_major == if_id_ref->vers_major &&
1606                        if_id->vers_minor <= if_id_ref->vers_minor)
1607                    {
1608                        return (true);
1609                    }
1610                    else
1611                    {
1612                        return (false);
1613                    }
1614                }
1615            }
1616        }
1617        return (false);
1618    }
1619}
1620
1621/*
1622**++
1623**
1624**  ROUTINE NAME:       rpc_if_id_vector_free
1625**
1626**  SCOPE:              PUBLIC - declared in rpc.idl
1627**
1628**  DESCRIPTION:
1629**
1630**  Free the memory allocated for an rpc_if_id_vector_t.
1631**
1632**  INPUTS:             none
1633**
1634**  INPUTS/OUTPUTS:
1635**
1636**      if_id_vector    The vector of interface id's to be freed.
1637**
1638**  OUTPUTS:
1639**
1640**      status          The result of the operation. One of:
1641**                          rpc_s_ok
1642**                          rpc_s_coding_error
1643**                          rpc_s_invalid_arg
1644**
1645**  IMPLICIT INPUTS:    none
1646**
1647**  IMPLICIT OUTPUTS:   none
1648**
1649**  FUNCTION VALUE:     void
1650**
1651**  SIDE EFFECTS:       none
1652**
1653**--
1654**/
1655
1656PUBLIC void rpc_if_id_vector_free
1657(
1658    rpc_if_id_vector_p_t    *if_id_vector,
1659    unsigned32              *status
1660)
1661{
1662    unsigned32              i;
1663
1664    CODING_ERROR (status);
1665    RPC_VERIFY_INIT ();
1666
1667    /*
1668     * check to see if if_id_vector is NULL, and if
1669     * so, return an error status
1670     */
1671    if (if_id_vector == NULL)
1672    {
1673        *status = rpc_s_invalid_arg;
1674        return;
1675    }
1676
1677    /*
1678     * walk the if id vector and free each element
1679     */
1680    for (i = 0; i < (*if_id_vector)->count; i++)
1681    {
1682        if ((*if_id_vector)->if_id[i] != NULL)
1683        {
1684            RPC_MEM_FREE ((*if_id_vector)->if_id[i], RPC_C_MEM_IF_ID);
1685        }
1686    }
1687
1688    /*
1689     * then free the vector itself
1690     */
1691    RPC_MEM_FREE ((*if_id_vector), RPC_C_MEM_IF_ID_VECTOR);
1692
1693    /*
1694     * return a NULL pointer
1695     */
1696    *if_id_vector = NULL;
1697    *status = rpc_s_ok;
1698    return;
1699}
1700
1701/*
1702**++
1703**
1704**  ROUTINE NAME:       rpc__if_inq_endpoint
1705**
1706**  SCOPE:              PRIVATE - declared in comif.h
1707**
1708**  DESCRIPTION:
1709**
1710**  With the given interface spec, search through the associated array
1711**  of RPC Protocol Sequence/endpoint pairs.  Compare the Protocol Sequence
1712**  ID given to the one in the ifspec (protocol_id's are used instead
1713**  of protseq id strings to make handling of aliases simpler and
1714**  localized). Filter out any extraneous info, such as "endpoint=" and
1715**  other information the user may have put into the endpoint attribute in
1716**  the idl file.  If the requested endpoint can't be located, return
1717**  'rpc_s_endpoint_not_found'.
1718**
1719**  INPUTS:
1720**
1721**      ifspec_h        Pointer to the ifspec
1722**
1723**      protseq_id      The protocol sequence to be matched
1724**
1725**  INPUTS/OUTPUTS:     none
1726**
1727**  OUTPUTS:
1728**
1729**      endpoint        The endpoint contained int he ifspec for the
1730**                      given protocol sequence.
1731**
1732**      status          The result of the operation. One of:
1733**                          rpc_s_ok
1734**                          rpc_s_endpoint_not_found
1735**                          rpc_s_coding_error
1736**
1737**  IMPLICIT INPUTS:    none
1738**
1739**  IMPLICIT OUTPUTS:   none
1740**
1741**  FUNCTION VALUE:     void
1742**
1743**  SIDE EFFECTS:       none
1744**
1745**--
1746**/
1747
1748PRIVATE void rpc__if_inq_endpoint
1749(
1750    rpc_if_rep_p_t              ifspec,
1751    rpc_protseq_id_t            protseq_id,
1752    unsigned_char_t             **endpoint,
1753    unsigned32                  *status
1754)
1755{
1756    unsigned16              ctr;
1757    rpc_protseq_id_t        pseq_id;
1758    unsigned_char_t         *scratch_endpoint;
1759
1760    CODING_ERROR (status);
1761
1762    for (ctr = 0; ctr < ifspec->endpoint_vector.count; ctr++)
1763    {
1764        pseq_id = rpc__network_pseq_id_from_pseq (
1765            ifspec->endpoint_vector.endpoint_vector_elt[ctr].rpc_protseq,
1766            status);
1767        if (*status == rpc_s_protseq_not_supported)
1768        {
1769            *status = rpc_s_ok;
1770            continue;
1771        }
1772        if (*status != rpc_s_ok)	{
1773            return;
1774		  }
1775
1776        if (pseq_id == protseq_id)
1777        {
1778            size_t len;
1779            /*
1780             * Allocate enough space so we can place brackets around the
1781             * string before attempting to filter it.  We need 3 extra
1782             * bytes, for '[', ']', and '\0'.
1783             */
1784            len = strlen ((char *) ifspec->endpoint_vector.endpoint_vector_elt[ctr].endpoint) + 3;
1785            RPC_MEM_ALLOC (
1786                scratch_endpoint,
1787                unsigned_char_p_t,
1788                len,
1789                RPC_C_MEM_STRING,
1790                RPC_C_MEM_WAITOK);
1791
1792            snprintf ((char *) scratch_endpoint, len, "[%s]",
1793                      (char *) (ifspec->endpoint_vector.endpoint_vector_elt[ctr].endpoint));
1794
1795            /*
1796             * Extract just the endpoint portion.
1797             */
1798            rpc_string_binding_parse(scratch_endpoint, NULL, NULL, NULL,
1799                endpoint, NULL, status);
1800
1801            RPC_MEM_FREE(scratch_endpoint, RPC_C_MEM_STRING);
1802
1803            return;
1804        }
1805    }
1806    *status = rpc_s_endpoint_not_found;
1807}
1808
1809/*
1810**++
1811**
1812**  ROUTINE NAME:       rpc__if_set_wk_endpoint
1813**
1814**  SCOPE:              PRIVATE - declared in comif.h
1815**
1816**  DESCRIPTION:
1817**
1818**  Set an RPC addr's endpoint based on the well-known endpoint in the
1819**  given ifspec, if there is one.
1820**
1821**  INPUTS:
1822**
1823**      ifspec_h        Pointer to the ifspec
1824**
1825**  INPUTS/OUTPUTS:
1826**
1827**      rpc_addr        The rpc address in which to set the endpoint
1828**
1829**  OUTPUTS:
1830**
1831**      status          The result of the operation. One of:
1832**                          rpc_s_ok
1833**                          rpc_s_too_many_ifs
1834**                          rpc_s_no_memory
1835**                          rpc_s_coding_error
1836**
1837**  IMPLICIT INPUTS:    none
1838**
1839**  IMPLICIT OUTPUTS:   none
1840**
1841**  FUNCTION VALUE:     void
1842**
1843**  SIDE EFFECTS:       none
1844**
1845**--
1846**/
1847
1848PRIVATE void rpc__if_set_wk_endpoint
1849(
1850  rpc_if_rep_p_t          ifspec,
1851  rpc_addr_p_t            *rpc_addr,
1852  unsigned32              *status
1853)
1854{
1855    unsigned_char_p_t       endpoint;
1856    unsigned32              temp_status;
1857
1858    CODING_ERROR (status);
1859
1860    /*
1861     * get the endpoint from the if spec
1862     */
1863    rpc__if_inq_endpoint (
1864        ifspec,
1865        (*rpc_addr)->rpc_protseq_id,
1866        &endpoint,
1867        status);
1868
1869    if (*status == rpc_s_ok)
1870    {
1871        /*
1872         * call the naf extension service to put the endpoint in the rpc addr
1873         */
1874        rpc__naf_addr_set_endpoint (endpoint, rpc_addr, status);
1875        rpc_string_free (&endpoint, &temp_status);
1876    }
1877
1878    return;
1879}
1880
1881/*
1882**++
1883**
1884**  ROUTINE NAME:       rpc__if_mgmt_inq_num_registered
1885**
1886**  SCOPE:              PRIVATE - declared in com.h
1887**
1888**  DESCRIPTION:
1889**
1890**  Perform a linear search through the Interface Registry Table.
1891**  For each slot found to contain a registered Interface specification,
1892**  increment a counter.  Return the number of active slots located.
1893**
1894**  INPUTS:             none
1895**
1896**  INPUTS/OUTPUTS:     none
1897**
1898**  OUTPUTS:            none
1899**
1900**  IMPLICIT INPUTS:    none
1901**
1902**  IMPLICIT OUTPUTS:   none
1903**
1904**  FUNCTION VALUE:
1905**
1906**      count           The number of registered interfaces.
1907**
1908**  SIDE EFFECTS:       none
1909**
1910**--
1911**/
1912
1913PRIVATE unsigned32 rpc__if_mgmt_inq_num_registered( void )
1914{
1915    unsigned32              entry_count = 0;
1916    unsigned32              index;
1917    rpc_if_rgy_entry_p_t    if_entry;
1918
1919    /*
1920     * take out a lock to protect access to the if registry
1921     */
1922    RPC_MUTEX_LOCK (if_mutex);
1923
1924    /*
1925     * walk the hash table
1926     */
1927    for (index = 0; index < RPC_C_IF_REGISTRY_SIZE; index++)
1928    {
1929        /*
1930         * walk the list under this hash entry
1931         */
1932        RPC_LIST_FIRST (if_registry[index], if_entry, rpc_if_rgy_entry_p_t);
1933
1934        while (if_entry != NULL)
1935        {
1936            /*
1937             * don't count internal entries
1938             */
1939            if (! if_entry->internal)
1940            {
1941                /*
1942                 * bump the count for each entry in the list
1943                 */
1944                entry_count++;
1945            }
1946
1947            RPC_LIST_NEXT (if_entry, if_entry, rpc_if_rgy_entry_p_t);
1948        }
1949    }
1950
1951    RPC_MUTEX_UNLOCK (if_mutex);
1952
1953    /*
1954     * report the total number of entries found
1955     */
1956    return (entry_count);
1957}
1958
1959/*
1960**++
1961**
1962**  ROUTINE NAME:       rpc__if_mgmt_inq_if_ids
1963**
1964**  SCOPE:              PRIVATE - declared in com.h
1965**
1966**  DESCRIPTION:
1967**
1968**  Obtain the number of active entries in the Interface Registry Table.
1969**  Then allocate enough memory to hold a vector of if_id elements.  Scan
1970**  through the Interface Registry Table and for each active interface copy
1971**  its UUID and Version into an rpc_if_id_t element. Return a pointer, to
1972**  the vector of info elements that have been built.
1973**
1974**  INPUTS:             none
1975**
1976**  INPUTS/OUTPUTS:     none
1977**
1978**  OUTPUTS:
1979**
1980**      if_info         Pointer to an if id vector
1981**
1982**      status          The result of the operation. One of:
1983**                          rpc_s_ok
1984**                          rpc_s_no_interfaces
1985**                          rpc_s_no_memory
1986**                          rpc_s_coding_error
1987**
1988**  IMPLICIT INPUTS:    none
1989**
1990**  IMPLICIT OUTPUTS:   none
1991**
1992**  FUNCTION VALUE:     void
1993**
1994**  SIDE EFFECTS:       none
1995**
1996**--
1997**/
1998
1999PRIVATE void rpc__if_mgmt_inq_if_ids
2000(
2001    rpc_if_id_vector_p_t    *if_id_vector,
2002    unsigned32              *status
2003)
2004{
2005    rpc_if_rgy_entry_p_t    if_entry;
2006    unsigned32              if_count;
2007    unsigned32              index;
2008    unsigned32              if_id_index;
2009    unsigned32              temp_status;
2010
2011    CODING_ERROR (status);
2012
2013    /*
2014     * find the number of registered interfaces
2015     */
2016    if ((if_count = rpc__if_mgmt_inq_num_registered()) == 0)
2017    {
2018        *status = rpc_s_no_interfaces;
2019	*if_id_vector = NULL;
2020        return;
2021    }
2022
2023    /*
2024     * allocate memory for the if id vector
2025     */
2026    RPC_MEM_ALLOC (
2027        *if_id_vector,
2028        rpc_if_id_vector_p_t,
2029        ((sizeof if_count) + (if_count * sizeof (rpc_if_id_p_t))),
2030        RPC_C_MEM_IF_ID_VECTOR,
2031        RPC_C_MEM_WAITOK);
2032
2033    /*
2034     * set the count field in the vector
2035     */
2036    (*if_id_vector)->count = if_count;
2037
2038    /*
2039     * take out a lock to protect access to the if registry
2040     */
2041    RPC_MUTEX_LOCK (if_mutex);
2042
2043    /*
2044     * search through Interface Registry Table
2045     */
2046    for (index = 0, if_id_index = 0; index < RPC_C_IF_REGISTRY_SIZE; index++)
2047    {
2048        /*
2049         * walk the list under this hash entry
2050         */
2051        RPC_LIST_FIRST (if_registry[index], if_entry, rpc_if_rgy_entry_p_t);
2052
2053        while (if_entry != NULL)
2054        {
2055            /*
2056             * don't report internal entries
2057             */
2058            if (! if_entry->internal)
2059            {
2060                /*
2061                 * allocate memory for the if id
2062                 */
2063                RPC_MEM_ALLOC (
2064                    (*if_id_vector)->if_id[if_id_index],
2065                    rpc_if_id_p_t,
2066                    sizeof (rpc_if_id_t),
2067                    RPC_C_MEM_IF_ID,
2068                    RPC_C_MEM_WAITOK);
2069
2070                /*
2071                 * extract the if id info for this registry entry
2072                 */
2073                rpc_if_inq_id ((rpc_if_handle_t) (if_entry->if_spec),
2074                    (*if_id_vector)->if_id[if_id_index], status);
2075
2076                if (*status != rpc_s_ok)
2077                {
2078                    /*
2079                     * If anything went wrong, free the vector allocated;
2080                     * but first reset the count field to the right value.
2081                     */
2082                    (*if_id_vector)->count = if_id_index;
2083                    rpc_if_id_vector_free (if_id_vector, &temp_status);
2084                    RPC_MUTEX_UNLOCK (if_mutex);
2085                    return;
2086                }
2087                if_id_index++;
2088            }
2089
2090            RPC_LIST_NEXT (if_entry, if_entry, rpc_if_rgy_entry_p_t);
2091        }
2092    }
2093
2094    RPC_MUTEX_UNLOCK (if_mutex);
2095    *status = rpc_s_ok;
2096    return;
2097}
2098
2099/*
2100**++
2101**
2102**  ROUTINE NAME:       rpc_server_inq_if
2103**
2104**  SCOPE:              PUBLIC - declared in rpc.idl
2105**
2106**  DESCRIPTION:
2107**
2108**  Given an interface spec and type ID, return the manager EPV that has
2109**  been registered for them (if any).
2110**
2111**  INPUTS:
2112**
2113**      ifspec_h        Pointer to the ifspec
2114**
2115**  INPUTS/OUTPUTS:     none
2116**
2117**  OUTPUTS:
2118**
2119**      mgr_type_uuid   The interface type
2120**
2121**      mgr_epv         The manager epv for this interface
2122**
2123**  IMPLICIT INPUTS:    none
2124**
2125**  IMPLICIT OUTPUTS:   none
2126**
2127**  FUNCTION VALUE:     void
2128**
2129**  SIDE EFFECTS:       none
2130**
2131**--
2132**/
2133
2134PUBLIC void rpc_server_inq_if
2135(
2136    rpc_if_handle_t             ifspec_h,
2137    uuid_p_t                    mgr_type_uuid,
2138    rpc_mgr_epv_t               *mgr_epv,
2139    unsigned32                  *status
2140)
2141{
2142    rpc_if_rep_p_t              ifspec = (rpc_if_rep_p_t) ifspec_h;
2143    unsigned16                  ihint = RPC_C_INVALID_IHINT;
2144
2145    CODING_ERROR (status);
2146    RPC_VERIFY_INIT ();
2147
2148    rpc__if_lookup2 (&ifspec->id, ifspec->vers, mgr_type_uuid,
2149                     &ihint, NULL, NULL, mgr_epv,
2150                     NULL, NULL, NULL, NULL, status);
2151}
2152
2153
2154/*
2155**++
2156**
2157**  ROUTINE NAME:       rpc_server_register_if_ex
2158**
2159**  SCOPE:              PUBLIC - declared in rpc.idl
2160**
2161**  DESCRIPTION:
2162**
2163**  See description of "rpc__server_register_if_int".
2164**
2165**  INPUTS:
2166**
2167**      ifspec_h        Pointer to the ifspec
2168**
2169**      mgr_type_uuid   The interface type (if any)
2170**
2171**      mgr_epv         The manager epv for this interface
2172**
2173**      flags           Registration flags
2174**
2175**      max_calls       The maximum number of calls
2176**
2177**      if_callback     Security callback
2178**
2179**  INPUTS/OUTPUTS:     none
2180**
2181**  OUTPUTS:
2182**
2183**      status          The result of the operation. One of:
2184**                          rpc_s_ok
2185**                          rpc_s_type_already_registered
2186**                          rpc_s_no_memory
2187**                          rpc_s_coding_error
2188**
2189**  IMPLICIT INPUTS:    none
2190**
2191**  IMPLICIT OUTPUTS:   none
2192**
2193**  FUNCTION VALUE:     void
2194**
2195**  SIDE EFFECTS:       none
2196**
2197**--
2198**/
2199
2200PUBLIC void rpc_server_register_if_ex
2201(
2202    rpc_if_handle_t             ifspec_h,
2203    uuid_p_t                    mgr_type_uuid,
2204    rpc_mgr_epv_t               mgr_epv,
2205    unsigned32                  flags,
2206    unsigned32                  max_calls,
2207    rpc_if_callback_fn_t        if_callback,
2208    unsigned32                  *status
2209)
2210{
2211    CODING_ERROR (status);
2212    RPC_VERIFY_INIT ();
2213
2214    rpc__server_register_if_int
2215        (ifspec_h, mgr_type_uuid, mgr_epv, flags,
2216         max_calls, -1, if_callback, false, status);
2217}
2218
2219
2220/*
2221**++
2222**
2223**  ROUTINE NAME:       rpc_server_register_if_2
2224**
2225**  SCOPE:              PUBLIC - declared in rpc.idl
2226**
2227**  DESCRIPTION:
2228**
2229**  See description of "rpc__server_register_if_int".
2230**
2231**  INPUTS:
2232**
2233**      ifspec_h        Pointer to the ifspec
2234**
2235**      mgr_type_uuid   The interface type (if any)
2236**
2237**      mgr_epv         The manager epv for this interface
2238**
2239**      flags           Registration flags
2240**
2241**      max_calls       The maximum number of calls
2242**
2243**      max_rpc_size    Maximum RPC size in bytes
2244**
2245**      if_callback     Security callback
2246**
2247**  INPUTS/OUTPUTS:     none
2248**
2249**  OUTPUTS:
2250**
2251**      status          The result of the operation. One of:
2252**                          rpc_s_ok
2253**                          rpc_s_type_already_registered
2254**                          rpc_s_no_memory
2255**                          rpc_s_coding_error
2256**
2257**  IMPLICIT INPUTS:    none
2258**
2259**  IMPLICIT OUTPUTS:   none
2260**
2261**  FUNCTION VALUE:     void
2262**
2263**  SIDE EFFECTS:       none
2264**
2265**--
2266**/
2267
2268PUBLIC void rpc_server_register_if_2
2269(
2270    rpc_if_handle_t             ifspec_h,
2271    uuid_p_t                    mgr_type_uuid,
2272    rpc_mgr_epv_t               mgr_epv,
2273    unsigned32                  flags,
2274    unsigned32                  max_calls,
2275    unsigned32                  max_rpc_size,
2276    rpc_if_callback_fn_t        if_callback,
2277    unsigned32                  *status
2278)
2279{
2280    CODING_ERROR (status);
2281    RPC_VERIFY_INIT ();
2282
2283    rpc__server_register_if_int
2284        (ifspec_h, mgr_type_uuid, mgr_epv, flags,
2285         max_calls, max_rpc_size, if_callback, false, status);
2286}
2287