1/*
2 * Copyright (c) 2010-2011 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**      cnassoc.c
82**
83**  FACILITY:
84**
85**      Remote Procedure Call (RPC)
86**
87**  ABSTRACT:
88**
89**  The NCA Connection Protocol Service's Association Service.
90**
91**
92 */
93
94#include <commonp.h>    /* Common declarations for all RPC runtime */
95#include <com.h>        /* Common communications services */
96#include <comprot.h>    /* Common protocol services */
97#include <cnp.h>        /* NCA Connection private declarations */
98#include <cnid.h>       /* NCA Connection local ID service */
99#include <cnrcvr.h>     /* NCA Connection receiver thread */
100#include <cnnet.h>      /* NCA Connection network service */
101#include <cnpkt.h>	/* NCA Connection packet encoding */
102#include <cnsm.h>       /* NCA Connection state machine service */
103#include <cnassm.h>     /* NCA Connection association state machine */
104#include <cnasgsm.h>    /* NCA Connection association group state machine */
105#include <comauth.h>    /* Externals for Auth. Services sub-component   */
106#include <cncall.h>     /* NCA connection call service */
107#include <cnassoc.h>
108
109#include <dce/rpcexc.h>
110
111#if HAVE_LWIO_LWIO_H
112#include <lwio/lwio.h>
113#endif
114
115
116
117/******************************************************************************/
118/*
119 * Internal variables
120 */
121/******************************************************************************/
122/*
123 * We want to serialize the group create operation.  We do this so
124 * that we do not wind up with multiple groups if multiple threads
125 * from a client make RPCs to the same server.  This would be especially
126 * painful if there are context handles since each of these groups will
127 * have to maintain an association.  (If all the associations were in
128 * a single group, only one association needs to be maintained.)
129 *
130 * The following variables simulate a mutex around the group
131 * create operation.  We call this the grp_new mutex.  We do not
132 * use a real mutex because mutex waits are non-cancellable.  We
133 * want this operation to be cancellable to support cancel timeouts
134 * even when there is no association.
135 *
136 * To acquire the grp_new mutex, a thread must set grp_new_in_progress to
137 * true. A thread must acquire this mutex prior to creating a group.
138 * If you have nested calls to assoc_request, only the outermost
139 * [initial] call to assoc_request should acquire the grp_new mutex.
140 *
141 * To release the grp_new mutex, a thread should clear grp_new_in_progress
142 * and do a condition broadcast on grp_new_wt.  Only the call frame
143 * that acquired the grp_new mutex should release it.
144 *
145 * grp_new_waiters is an optimization.  It is the number of threads
146 * waiting for the grp_new mutex.  A thread must
147 * increment this prior to waiting for the grp_new mutex.
148 * We don't signal the grp_new_wt condition variable if
149 * there are no waiters when the grp_new mutex is released.
150 */
151INTERNAL rpc_cond_t             grp_new_wt;
152INTERNAL unsigned16             grp_new_waiters;
153INTERNAL boolean32              grp_new_in_progress;
154
155
156/******************************************************************************/
157/*
158 * Internal routine declarations
159 */
160/******************************************************************************/
161/*
162 * R P C _ _ C N _ A S S O C _ O P E N
163 */
164
165INTERNAL void rpc__cn_assoc_open (
166    rpc_cn_assoc_p_t             /*assoc*/,
167    rpc_addr_p_t                 /*rpc_addr*/,
168    rpc_if_rep_p_t               /*if_r*/,
169    rpc_cn_local_id_t            /*grp_id*/,
170    rpc_auth_info_p_t            /*auth_info*/,
171    rpc_transport_info_p_t       /*transport_info*/,
172    rpc_transfer_syntax_t       * /*syntax*/,
173    unsigned16                  * /*context_id*/,
174    rpc_cn_sec_context_p_t      * /*sec*/,
175    unsigned32                  * /*st*/);
176
177/*
178 * R P C _ _ C N _ A S S O C _ A L T E R _ C O N T E X T
179 */
180
181INTERNAL void rpc__cn_assoc_alter_context (
182    rpc_cn_assoc_p_t             /*assoc*/,
183    rpc_if_rep_p_t               /*if_r*/,
184    rpc_auth_info_p_t            /*info*/,
185    rpc_transfer_syntax_t       * /*syntax*/,
186    unsigned16                  * /*context_id*/,
187    rpc_cn_sec_context_p_t      * /*sec*/,
188    unsigned32                  * /*st*/);
189
190/*
191 * R P C _ _ C N _ A S S O C _ R E C L A I M
192 */
193
194INTERNAL void rpc__cn_assoc_reclaim (
195    rpc_cn_local_id_t            /*grp_id*/,
196    unsigned32                   /*type*/,
197    boolean32			 /*loop*/);
198
199/*
200 * R P C _ _ C N _ A S S O C _ T I M E R _ R E C L A I M
201 */
202
203INTERNAL void rpc__cn_assoc_timer_reclaim (
204    unsigned32                   /*type*/);
205
206/*
207 * R P C _ _ C N _ A S S O C _ A C B _ A L L O C
208 */
209
210INTERNAL rpc_cn_assoc_t *rpc__cn_assoc_acb_alloc (
211    boolean32                    /*wait*/,
212    unsigned32                   /*type*/,
213    unsigned32                  * /*st*/);
214
215/*
216 * R P C _ _ C N _ A S S O C _ G R P _ I N I T
217 */
218
219INTERNAL void rpc__cn_assoc_grp_init (
220    rpc_cn_assoc_grp_p_t         /*assoc_grp*/,
221    unsigned32                   /*index*/);
222
223/*
224 * R P C _ _ C N _ A S S O C _ G R P _ C R E A T E
225 */
226
227INTERNAL rpc_cn_local_id_t rpc__cn_assoc_grp_create (
228    unsigned32                  * /*st*/);
229
230/*
231 * R P C _ _ C N _ A S S O C _ S Y N T A X _ A L L O C
232 */
233
234INTERNAL rpc_cn_syntax_t *rpc__cn_assoc_syntax_alloc (
235    rpc_if_rep_p_t               /*if_r*/,
236    unsigned32                  * /*st*/);
237
238
239/******************************************************************************/
240/*
241 * Macros
242 */
243/******************************************************************************/
244
245
246/******************************************************************************/
247/*
248 * Local defines
249 */
250/******************************************************************************/
251
252/*
253 * The number of association groups to allocate when the table needs
254 * to grow.
255 */
256#define RPC_C_ASSOC_GRP_ALLOC_SIZE              10
257
258/*
259 * The default number of associations allowed on an association
260 * group.
261 */
262#define RPC_C_ASSOC_GRP_MAX_ASSOCS_DEFAULT      0xffffffff
263
264/*
265 * The maximum resource wait in seconds. This is the maximum amount
266 * of time trying to request an association. This value is specified
267 * as 300 in Appendix A of the NCA connection architecture spec.
268 */
269#define RPC_C_ASSOC_MAX_RESOURCE_WAIT           60
270
271/*
272 * The client idle connection disconnect time in seconds.
273 * This value is specified as 300 in Appendix A of the NCA connection
274 * architecture spec.
275 */
276#define RPC_C_ASSOC_CLIENT_DISC_TIMER           60
277
278/*
279 * The server idle connection disconnect time in seconds.
280 * This value is specified as 300 in Appendix A of the NCA connection
281 * architecture spec.
282 */
283#define RPC_C_ASSOC_SERVER_DISC_TIMER           60
284
285/*
286 * The initial amount of time in seconds to wait before retrying an
287 * association request. This corresponds to the slot time in the
288 * exponential backoff algorithm used.
289 */
290#define RPC_C_ASSOC_INITIAL_WAIT_INTERVAL       1
291
292/*
293 * The maximum amount of time in seconds after each connection
294 * request attempt.
295 */
296#define RPC_C_ASSOC_MAX_WAIT_INTERVAL           5
297
298
299/******************************************************************************/
300/*
301 * Routine definitions
302 */
303/******************************************************************************/
304/*
305**++
306**
307**  ROUTINE NAME:       rpc__cn_assoc_request
308**
309**  SCOPE:              PRIVATE - declared in cnassoc.h
310**
311**  DESCRIPTION:
312**
313**  This routine is called by the client call state machine
314**  when an association is needed to perform an RPC over. The
315**  returned association will contain a connection to the
316**  desired address space as will have had the full presentation
317**  negotiation performed over it.
318**
319**  INPUTS:
320**
321**      call_r          The call rep for the RPC.
322**      binding_r       The binding rep containing the server
323**                      address space address.
324**      if_r            The interface rep through which this RPC is
325**                      being made containing the presentation
326**                      negotiation information.
327**
328**  INPUTS/OUTPUTS:     none
329**
330**  OUTPUTS:
331**
332**      syntax          The negotiated transfer syntax.
333**      context_id      The context id of the transfer syntax
334**                      assigned by the client runtime.
335**      sec             The pointer to the negotiated security
336**                      context element, NULL if none.
337**      st              The return status of this routine.
338**                      rpc_s_ok
339**                      rpc_s_tsyntaxes_unsupported
340**                      rpc_s_unknown_if
341**
342**  IMPLICIT INPUTS:    none
343**
344**  IMPLICIT OUTPUTS:   none
345**
346**  FUNCTION VALUE:
347**
348**      return          The association. NULL if not created.
349**
350**  SIDE EFFECTS:       none
351**
352**--
353**/
354
355PRIVATE rpc_cn_assoc_t *rpc__cn_assoc_request
356(
357  rpc_cn_call_rep_p_t     call_r,
358  rpc_cn_binding_rep_p_t  binding_r,
359  rpc_if_rep_p_t          if_r,
360  rpc_transfer_syntax_t   *syntax,
361  unsigned16              *context_id,
362  rpc_cn_sec_context_p_t  *sec,
363  unsigned32              *st
364)
365{
366    rpc_cn_assoc_t      * volatile assoc = NULL;
367    rpc_cn_assoc_grp_t  * volatile assoc_grp = NULL;
368    rpc_addr_p_t        rpc_addr;
369    unsigned32 volatile wait_interval, total_wait;
370    rpc_cn_local_id_t   grp_id;
371    rpc_cn_local_id_t volatile rem_grp_id;
372    struct timespec     timespec;
373    struct timespec     abstime;
374
375    /*
376     * i_hold_grp_new_mutex means that this call frame holds the
377     * grp_new mutex. The grp_new_mutex is described above.
378     */
379    volatile boolean    i_hold_grp_new_mutex;
380
381    volatile boolean32  retry_op;
382    volatile boolean    old_server = true; /* MS servers are 5.0 servers */
383    unsigned32          temp_st;
384
385    //DO_NOT_CLOBBER(assoc);
386    //DO_NOT_CLOBBER(assoc_grp);
387    //DO_NOT_CLOBBER(wait_interval);
388    //DO_NOT_CLOBBER(total_wait);
389    //DO_NOT_CLOBBER(rem_grp_id);
390    //DO_NOT_CLOBBER(i_hold_grp_new_mutex);
391    //DO_NOT_CLOBBER(old_server);
392
393    RPC_LOG_CN_ASSOC_REQ_NTR;
394    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_request);
395    CODING_ERROR (st);
396
397    /*
398     * The CN RPC protocol looks at the binding timeout as a binary
399     * value. If the timeout is infinite it will try forever to
400     * establish a connection. If not it will try once and rely on the
401     * transport protocol below to perform the appropriate retries.
402     * It would be nice if we could turn some generic transport knob
403     * to tell it how hard to try but as of today there is no such facility.
404     */
405    wait_interval = RPC_C_ASSOC_INITIAL_WAIT_INTERVAL;
406    i_hold_grp_new_mutex = false;
407    total_wait = 0;
408
409    while (true)
410    {
411        /*
412         * Ideally we'd like to use an association which already exists,
413         * is open, and has already had the transfer syntax negotiated for
414         * the abstract syntax (interface UUID and version) given. To
415         * find a cached association we must first find an association
416         * group representing the server address space given in the
417         * binding rep. There are two ways of finding an association
418         * group. First we can use the group ID contained in the
419         * connection part of the binding rep. This will get us directly
420         * to an association group. If that doesn't work we can use the
421         * RPC address contained in the common part of the binding rep.
422         * This means we have to scan and compare possibly all the
423         * association groups.
424         */
425        grp_id = rpc__cn_assoc_grp_lkup_by_id (binding_r->grp_id,
426                                               RPC_C_CN_ASSOC_GRP_CLIENT,
427                                               binding_r->common.transport_info,
428                                               st);
429        if (*st != rpc_s_ok)
430        {
431            /*
432             * The assoc group was not found using the group ID in the
433             * binding rep. Now try the RPC address in the binding rep.
434             */
435            grp_id = rpc__cn_assoc_grp_lkup_by_addr (binding_r->common.rpc_addr,
436                                                     binding_r->common.transport_info,
437                                                     RPC_C_CN_ASSOC_GRP_CLIENT,
438                                                     st);
439        }
440
441        /*
442         * Check whether an association group was found.
443         */
444        assoc_grp = RPC_CN_ASSOC_GRP (grp_id);
445        if (assoc_grp != NULL)
446        {
447            /*
448             * We now have an association group. Save the group id in the
449             * binding rep for use on subsequent lookups and look for an open
450             * association on the group.
451             */
452            binding_r->grp_id.all = assoc_grp->grp_id.all;
453            RPC_LIST_FIRST (assoc_grp->grp_assoc_list,
454                            assoc,
455                            rpc_cn_assoc_p_t);
456
457            /*
458             * Cycle through all the associations on this group
459             * looking for an unallocated one.
460             */
461            while (assoc != NULL)
462            {
463                /*
464                 * Look at the reference count of the association to determine
465                 * whether it is allocated.
466                 */
467                if (assoc->assoc_ref_count == 0)
468                {
469                    /*
470                     * Store the call rep in the association for use
471                     * in cancel timeout processing.
472                     */
473                    assoc->call_rep = call_r;
474
475                    /*
476                     * Allocate the association.
477                     * Send an association allocate request through
478                     * the association state machine. This will put
479                     * the association into the active state and
480                     * will prevent other threads from allocating it.
481                     */
482                    rpc__cn_assoc_alloc (assoc, st);
483                    if (*st == rpc_s_ok)
484                    {
485                        /*
486                         * This association is active. Send an alter
487                         * presentation context event through the
488                         * association state machine if necessary.
489                         */
490                        RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
491                                        ("CN: call_rep->%p assoc->%p desc->%p negotiating presentation syntax over existing association\n",
492                                         assoc->call_rep,
493                                         assoc,
494                                         assoc->cn_ctlblk.cn_sock));
495                        rpc__cn_assoc_alter_context (assoc,
496                                                     if_r,
497                                                     binding_r->common.auth_info,
498                                                     syntax,
499                                                     context_id,
500                                                     sec,
501                                                     st);
502
503                        RPC_LOG_CN_ASSOC_REQ_XIT;
504                        if (*st != rpc_s_ok)
505                        {
506                            /*
507                             * The alter context request failed.
508                             * Just deallocate the association and
509                             * return NULL.
510                             */
511                            RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
512                                            ("CN: call_rep->%p assoc->%p desc->%p presentation negotiation failed st = %x\n",
513                                             assoc->call_rep,
514                                             assoc,
515                                             assoc->cn_ctlblk.cn_sock,
516                                             *st));
517
518                            /*
519                             * The call is about to be orphaned, so remove it from the assoc
520                             */
521                            if (assoc->call_rep == call_r)
522                            {
523                                assoc->call_rep = NULL;
524                            }
525
526                            rpc__cn_assoc_dealloc (assoc,
527                                                   call_r,
528                                                   &temp_st);
529                            return (NULL);
530                        }
531                        else
532                        {
533                            /*
534                             * The alter context request succeeded.
535                             * Return the association.
536                             */
537                            RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
538                                            ("CN: call_rep->%p assoc->%p desc->%p presentation negotiation succeeded\n",
539                                             assoc->call_rep,
540                                             assoc,
541                                             assoc->cn_ctlblk.cn_sock));
542
543                            /*
544                             * Update transport information on binding handle
545                             */
546
547                            rpc__transport_info_release(binding_r->common.transport_info);
548                            binding_r->common.transport_info = assoc->transport_info;
549                            rpc__transport_info_retain(binding_r->common.transport_info);
550
551                            return (assoc);
552                        }
553                    }
554                }
555                RPC_LIST_NEXT (assoc, assoc, rpc_cn_assoc_p_t);
556            } /* while (assoc != NULL) */
557
558            /*
559             * Remember the secondary address for this group we're
560             * going to need it below to establish a new
561             * session/transport connection.
562             */
563            rpc_addr = assoc_grp->grp_secaddr;
564
565            /*
566             * Remember the remote group id for this group. It will
567             * be sent to the server when the association is requested.
568             */
569            rem_grp_id = assoc_grp->grp_remid;
570        } /* end if (assoc_grp != NULL) */
571
572        else /* assoc_grp == NULL */
573        {
574
575            /*
576             * Use the address in the binding rep to establish the
577             * new session/transport connection.
578             */
579            rpc_addr = binding_r->common.rpc_addr;
580            RPC_CN_LOCAL_ID_CLEAR (rem_grp_id);
581
582            /*
583             * We don't have an association group at this point.
584             * We want to serialize the creation of association
585             * groups to prevent multiple association
586             * groups to the same server address space.
587             * We therefore acquire the grp_new mutex.
588             *
589             * Note: we can still get multiple association
590             * groups to the same address space if we have
591             * recursive calls to assoc_request.  We can also
592             * get them if multiple threads from the same client
593             * use different protocol sequences to call the same
594             * server.  But we don't expect either of these to be
595             * frequent occurences.
596             */
597
598            /*
599             * Attempt to acquire the grp_new mutex.
600             */
601            if (grp_new_in_progress)
602            {
603                /*
604                 * Some other thread holds the grp_new mutex. We'll
605                 * have to record ourself as a waiter for it and be
606                 * patient.
607                 */
608                grp_new_waiters++;
609
610                while (grp_new_in_progress)
611                {
612                    /*
613                     * Since this is a cancellable operation we'll set
614                     * up an exception handler.
615                     */
616                    retry_op = true;
617                    DCETHREAD_TRY
618                    {
619                        RPC_COND_WAIT (grp_new_wt,
620					   rpc_g_global_mutex);
621                    }
622                    DCETHREAD_CATCH (dcethread_interrupt_e)
623                    {
624                        /*
625                         * Record the fact that a cancel has been
626                         * detected. Also, start a timer if this is
627                         * the first cancel detected.
628                         */
629                        rpc__cn_call_local_cancel (call_r,
630                                                   &retry_op,
631                                                   st);
632                        assert(assoc != NULL);
633                        RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL,
634                                        ("(rpc__cn_assoc_request) call_rep->%p assoc->%p desc->%p cancel caught before association setup\n",
635                                         call_r,
636                                         assoc,
637                                         assoc->cn_ctlblk.cn_sock));
638                    }
639                    DCETHREAD_ENDTRY
640
641                    /*
642                     * If the cancel timer expired decrement the
643                     * count of threads waiting to establish a new
644                     * association and return.
645                     */
646                    if (!retry_op)
647                    {
648                        grp_new_waiters--;
649                        return (NULL);
650                    }
651                }
652
653                /*
654                 * We're done waiting. Try for an existing
655                 * association or at least existing group by going
656                 * through the loop again.
657                 */
658                grp_new_waiters--;
659                continue;
660            }
661            else  /* grp_new_in_progress is false; i.e., grp_new mutex
662                   * is available.
663                   */
664            {
665                /*
666                 * There is no other thread opening a new
667                 * association. Acquire the grp_new mutex.
668                 * We also set i_hold_grp_new_mutex.
669                 *
670                 * Note: If we get here, we are by definition, in
671                 * the outermost call to assoc_request.
672                 */
673                grp_new_in_progress = true;
674                i_hold_grp_new_mutex = true;
675
676            }
677        } /* end else (assoc_grp == NULL) */
678
679        /*
680         * Determine whether the association group we have at
681         * this point, if any, can support another association.
682         */
683        if ((assoc_grp == NULL)
684             ||
685            (assoc_grp->grp_cur_assoc < assoc_grp->grp_max_assoc))
686        {
687            /*
688             * We can add another association to the group (if we
689             * have one) if it can be established. First create an
690             * association control block structure and its receiver thread.
691             * We don't check the return value because it always
692             * returns rpc_s_ok.
693             */
694            assoc = rpc__cn_assoc_acb_alloc (true,
695                                             RPC_C_CN_ASSOC_CLIENT,
696                                             st);
697            if (*st != rpc_s_ok) {
698                if (i_hold_grp_new_mutex) {
699                    grp_new_in_progress = false;
700                    RPC_COND_BROADCAST (grp_new_wt, rpc_g_global_mutex);
701                }
702                return NULL;
703            }
704
705            /*
706             * We have an association control block. Send an
707             * association request event through its state machine.
708             * Set the association reference count to 1 so that this
709             * association will not be allocated by another thread
710             * while still being set up.
711             */
712            RPC_CN_ASSOC_ACB_INC_REF (assoc);
713            assoc->assoc_ref_count++;
714            if (old_server)
715            {
716                assoc->assoc_vers_minor = RPC_C_CN_PROTO_VERS_COMPAT;
717            }
718
719            /*
720             * Store the call rep in the association for use
721             * in cancel timeout processing.
722             */
723            assoc->call_rep = call_r;
724            RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
725                            ("CN: call_rep->%p assoc->%p desc->%p establishing connection & negotiating presentation syntax\n",
726                             assoc->call_rep,
727                             assoc,
728                             assoc->cn_ctlblk.cn_sock));
729
730            rpc__cn_assoc_open (assoc,
731                                rpc_addr,
732                                if_r,
733                                rem_grp_id,
734                                binding_r->common.auth_info,
735                                binding_r->common.transport_info,
736                                syntax,
737                                context_id,
738                                sec,
739                                st);
740
741            /*
742             * Release the grp_new mutex if we locked it.
743             */
744            if (i_hold_grp_new_mutex)
745            {
746                /*
747                 * A new association has just been opened so reset
748                 * the flag to allow other thread's which want to open
749                 * new associations to do so.
750                 */
751                grp_new_in_progress = false;
752                RPC_COND_BROADCAST (grp_new_wt,
753                                    rpc_g_global_mutex);
754            }
755            RPC_CN_ASSOC_ACB_DEC_REF (assoc);
756            assoc->assoc_ref_count--;
757            if (*st == rpc_s_ok)
758            {
759                /*
760                 * Allocate the association.
761                 * Send an association allocate request through the association state
762                 * machine. This will put the association into the active state.
763                 */
764                RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
765                                ("CN: call_rep->%p assoc->%p desc->%p presentation negotiation succeeded\n",
766                                 assoc->call_rep,
767                                 assoc,
768                                 assoc->cn_ctlblk.cn_sock));
769
770                rpc__cn_assoc_alloc (assoc, st);
771                if (*st == rpc_s_ok)
772                {
773                    /*
774                     * We now have an association group. Save the group id in the
775                     * binding rep for use on subsequent lookups and look for an open
776                     * association on the group.
777                     */
778                    binding_r->grp_id.all = assoc->assoc_grp_id.all;
779
780                    /*
781                     * Update transport information on binding handle
782                     */
783
784                    rpc__transport_info_release(binding_r->common.transport_info);
785                    binding_r->common.transport_info = assoc->transport_info;
786                    rpc__transport_info_retain(binding_r->common.transport_info);
787
788                    /*
789                     * The association has been allocated and is now
790                     * ready for an RPC.
791                     */
792                    RPC_LOG_CN_ASSOC_REQ_XIT;
793                    return (assoc);
794                }
795            }
796            else
797            {
798                /*
799                 * The association open failed. We may have failed
800                 * while trying to establish a session/transport
801                 * connection or during or after presentation
802                 * negotiation. If the connect request failed the
803                 * association will be in the closed state and the acb
804                 * just has to be dealloced to go back on the
805                 * lookaside list. If the presentation
806                 * negotiation failed the association will already
807                 * on a group. We can also just deallocate the
808                 * acb in this case since it is attached to an
809                 * association group. If a cancel timeout occured
810                 * the negotiation will eventually complete and the
811                 * association will be placed on a group.
812                 */
813                RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
814                                ("CN: call_rep->%p assoc->%p desc->%p presentation negotiation failed st = %x\n",
815                                 assoc->call_rep,
816                                 assoc,
817                                 assoc->cn_ctlblk.cn_sock,
818                                 *st));
819
820                /*
821                 * The call is about to be orphaned, so remove it from the assoc
822                 */
823                if (assoc->call_rep == call_r)
824                {
825                    assoc->call_rep = NULL;
826                }
827
828                if ((old_server == false) &&
829		    (*st == rpc_s_connection_closed) &&
830                    ((assoc->assoc_vers_minor == RPC_C_CN_PROTO_VERS_COMPAT) ||
831                     (assoc->bind_packets_sent > 1)))
832                {
833                    /* Probably a 5.0 server with fragmented BINDs - retry */
834                    old_server = true;
835                    RPC_CN_ASSOC_ACB_INC_REF (assoc);
836                    rpc__cn_assoc_acb_dealloc (assoc);
837                    assoc = NULL;
838                    continue;
839                }
840
841                RPC_CN_ASSOC_ACB_INC_REF (assoc);
842                rpc__cn_assoc_acb_dealloc (assoc);
843                assoc = NULL;
844
845                /*
846                 * Return a failure immediately if:
847                 *
848                 * 1) the association open failed because it was
849                 *    rejected or a local error occurred OR
850                 *
851                 * 2) the connection request failed and the binding
852                 *    timeout was less than 6
853                 */
854                if (!rpc__cn_network_connect_fail (*st))
855                {
856                    return (NULL);
857                }
858                else
859                {
860                    if (binding_r->common.timeout < 6)
861                    {
862                        return (NULL);
863                    }
864                }
865            } /* end else (*st != rpc_s_ok) */
866        } /* end if (assoc_grp == NULL) || (assoc_grp->grp_cur_assoc */
867          /* < assoc_grp->grp_max_assoc) */
868        else
869        {
870            *st = rpc_s_assoc_grp_max_exceeded;
871        }
872
873        /*
874         * We've dropped to this point in the for loop if
875         *
876         * 1) the connection request failed because it either timed
877         *    out or the server rejected it and the binding timeout
878         *    was 6 or higher or
879         *
880         * 2) the maximum number of associations were reached on a
881         *    particular group.
882         *
883         * In any case we will try to reclaim some open
884         * associations, and perform an exponential backoff.
885         */
886        timespec.tv_sec = MIN (RPC_RANDOM_GET (0, wait_interval),
887                               RPC_C_ASSOC_MAX_WAIT_INTERVAL);
888        timespec.tv_nsec = 0;
889        RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
890                        ("CN: call_rep->%p assoc->%p desc->%p backing off %lu seconds before retrying ...\n",
891                         call_r,
892                         NULL,
893                         NULL,
894                         (unsigned long)timespec.tv_sec));
895        if (!RPC_CN_LOCAL_ID_VALID (grp_id))
896        {
897            rpc__cn_assoc_reclaim (grp_id, RPC_C_CN_ASSOC_GRP_CLIENT, true);
898            RPC_CN_UNLOCK ();
899            retry_op = true;
900            DCETHREAD_TRY
901            {
902                dcethread_delay (&timespec);
903            }
904            DCETHREAD_CATCH (dcethread_interrupt_e)
905            {
906                RPC_CN_LOCK ();
907
908                /*
909                 * Record the fact that a cancel has been
910                 * detected. Also, start a timer if this is
911                 * the first cancel detected.
912                 */
913                rpc__cn_call_local_cancel (call_r,
914                                           &retry_op,
915                                           st);
916                RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL,
917                                ("(rpc__cn_assoc_request) call_rep->%p assoc->%p desc->%p cancel caught before association setup\n",
918                                 call_r,
919                                 NULL,
920                                 NULL));
921                RPC_CN_UNLOCK ();
922            }
923            DCETHREAD_ENDTRY
924            RPC_CN_LOCK ();
925            if (!retry_op)
926            {
927                return (NULL);
928            }
929        }
930        else
931        {
932            assoc_grp = RPC_CN_ASSOC_GRP (grp_id);
933            assert(assoc_grp != NULL);
934            rpc__cn_assoc_reclaim (assoc_grp->grp_id,
935                                   RPC_C_CN_ASSOC_GRP_CLIENT,
936				   true);
937            assoc_grp->grp_assoc_waiters++;
938            dcethread_get_expiration (&timespec, &abstime);
939            retry_op = true;
940            DCETHREAD_TRY
941            {
942                RPC_COND_TIMED_WAIT (assoc_grp->grp_assoc_wt,
943                                     rpc_g_global_mutex,
944                                     &abstime);
945            }
946            DCETHREAD_CATCH (dcethread_interrupt_e)
947            {
948                /*
949                 * Record the fact that a cancel has been
950                 * detected. Also, start a timer if this is
951                 * the first cancel detected.
952                 */
953                rpc__cn_call_local_cancel (call_r,
954                                           &retry_op,
955                                           st);
956                RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL,
957                                ("(rpc__cn_assoc_request) call_rep->%p cancel caught before association setup\n",
958                                 call_r));
959            }
960            DCETHREAD_ENDTRY
961            if (!retry_op)
962            {
963                return (NULL);
964            }
965            assoc_grp->grp_assoc_waiters--;
966        }
967
968        total_wait = total_wait + wait_interval;
969        if (binding_r->common.timeout != rpc_c_binding_infinite_timeout)
970        {
971            if (total_wait >
972                MIN ((binding_r->common.timeout * 6), RPC_C_ASSOC_MAX_RESOURCE_WAIT))
973            {
974                break;
975            }
976        }
977        wait_interval = MIN ((wait_interval * 2), RPC_C_ASSOC_MAX_WAIT_INTERVAL);
978    } /* while (true) */
979
980    /*
981     * The status code returned from here will be the last one
982     * returned from the rpc__socket_connect call.
983     */
984    return (NULL);
985}
986
987
988/***********************************************************************/
989/*
990**++
991**
992**  ROUTINE NAME:       rpc__cn_assoc_listen
993**
994**  SCOPE:              PRIVATE - declared in cnassoc.h
995**
996**  DESCRIPTION:
997**
998**  This routine is called when a new connection has been accepted.
999**  A new association will be set up, including its receiver
1000**  thread, and returned.
1001**
1002**  INPUTS:
1003**
1004**      desc            The network descriptor of the new connection.
1005**      endpoint        The local endpoint the connection came into.
1006**
1007**  INPUTS/OUTPUTS:     none
1008**
1009**  OUTPUTS:
1010**
1011**      st              The return status of this routine.
1012**                      rpc_s_ok
1013**
1014**  IMPLICIT INPUTS:    none
1015**
1016**  IMPLICIT OUTPUTS:   none
1017**
1018**  FUNCTION VALUE:
1019**
1020**      return          The association. NULL if not created.
1021**
1022**  SIDE EFFECTS:       none
1023**
1024**--
1025**/
1026
1027PRIVATE rpc_cn_assoc_t *rpc__cn_assoc_listen
1028(
1029   rpc_socket_t            newsock,
1030   unsigned_char_p_t       endpoint,
1031   unsigned32              *st
1032)
1033{
1034    rpc_cn_assoc_t      *assoc;
1035    rpc_socket_error_t serr = RPC_C_SOCKET_OK;
1036    rpc_transport_info_p_t transport_info = NULL;
1037
1038    RPC_LOG_CN_ASSOC_LIS_NTR;
1039    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_listen);
1040    CODING_ERROR (st);
1041
1042    /*
1043     * Create a server association.
1044     */
1045    assoc = rpc__cn_assoc_acb_alloc (false, RPC_C_CN_ASSOC_SERVER, st);
1046    if (*st != rpc_s_ok)
1047    {
1048        /*
1049         * The creation failed. The caller will close the socket.
1050         */
1051        return (NULL);
1052    }
1053
1054    /*
1055     * Indicate that there is a valid connection.
1056     */
1057    assoc->cn_ctlblk.cn_state = RPC_C_CN_OPEN;
1058    assoc->cn_ctlblk.cn_sock  = newsock;
1059    assoc->cn_ctlblk.cn_listening_endpoint = endpoint;
1060
1061    /* Attempt to query socket for transport information */
1062    serr = rpc__socket_inq_transport_info(newsock, &transport_info);
1063    if (RPC_SOCKET_IS_ERR(serr))
1064    {
1065        RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_ERRORS,
1066                        ("(rpc__cn_assoc_listen) desc->%p rpc__socket_inq_transport_info failed, error = %d\n",
1067                         assoc->cn_ctlblk.cn_sock,
1068                         serr));
1069    }
1070    else
1071    {
1072        rpc__transport_info_release(assoc->transport_info);
1073        assoc->transport_info = transport_info;
1074    }
1075
1076    /*
1077     * A connection is now set up. Tell the receiver thread to begin
1078     * receiving on the connection.
1079     */
1080    if (assoc->cn_ctlblk.cn_rcvr_waiters)
1081    {
1082        RPC_COND_SIGNAL (assoc->cn_ctlblk.cn_rcvr_cond,
1083                         rpc_g_global_mutex);
1084    }
1085    else
1086    {
1087        RPC_DBG_PRINTF (rpc_e_dbg_threads, RPC_C_CN_DBG_THREADS,
1088	    ( "####### assoc->%p We're not signalling here\n", assoc ));
1089    }
1090    *st = rpc_s_ok;
1091    RPC_LOG_CN_ASSOC_LIS_XIT;
1092    return (assoc);
1093}
1094
1095
1096/******************************************************************************/
1097/*
1098**++
1099**
1100**  ROUTINE NAME:       rpc__cn_assoc_alloc
1101**
1102**  SCOPE:              PRIVATE - declared in cnassoc.h
1103**
1104**  DESCRIPTION:
1105**
1106**      This routine will send an association allocate request
1107**      through the association state and allocate the association
1108**      control block.
1109**
1110**  INPUTS:
1111**
1112**      assoc           The association being allocated
1113**
1114**  INPUTS/OUTPUTS:     none
1115**
1116**  OUTPUTS:
1117**
1118**      st              The return status of this routine.
1119**                      rpc_s_ok
1120**
1121**  IMPLICIT INPUTS:    none
1122**
1123**  IMPLICIT OUTPUTS:   none
1124**
1125**  FUNCTION VALUE:     none
1126**
1127**  SIDE EFFECTS:       none
1128**
1129**--
1130**/
1131
1132PRIVATE void rpc__cn_assoc_alloc
1133(
1134  rpc_cn_assoc_p_t        assoc,
1135  unsigned32              *st
1136)
1137{
1138    RPC_LOG_CN_ASSOC_ALLOC_NTR;
1139    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_alloc);
1140    CODING_ERROR(st);
1141
1142    RPC_CN_STATS_INCR (alloced_assocs);
1143    RPC_CN_ASSOC_ACB_INC_REF (assoc);
1144    RPC_CN_ASSOC_EVAL_USER_EVENT (assoc,
1145                                  RPC_C_ASSOC_ALLOCATE_REQ,
1146                                  NULL,
1147                                  *st);
1148    RPC_LOG_CN_ASSOC_ALLOC_XIT;
1149}
1150
1151
1152/******************************************************************************/
1153/*
1154**++
1155**
1156**  ROUTINE NAME:       rpc__cn_assoc_dealloc
1157**
1158**  SCOPE:              PRIVATE - declared in cnassoc.h
1159**
1160**  DESCRIPTION:
1161**
1162**  This routine will send a deallocate event through the
1163**  association state machine and deallocate the association
1164**  control block.
1165**
1166**  INPUTS:
1167**
1168**      assoc           The association being deallocated
1169**	call_rep	The call rep of the association.
1170**
1171**  INPUTS/OUTPUTS:     none
1172**
1173**  OUTPUTS:
1174**
1175**      st              The return status of this routine.
1176**                      rpc_s_ok
1177**
1178**  IMPLICIT INPUTS:    none
1179**
1180**  IMPLICIT OUTPUTS:   none
1181**
1182**  FUNCTION VALUE:     none
1183**
1184**  SIDE EFFECTS:       none
1185**
1186**--
1187**/
1188
1189PRIVATE void rpc__cn_assoc_dealloc
1190(
1191  rpc_cn_assoc_p_t        assoc,
1192  rpc_cn_call_rep_p_t     call_rep,
1193  unsigned32              *st
1194)
1195{
1196    rpc_cn_assoc_grp_t  *assoc_grp;
1197    rpc_cn_fragbuf_t    *fragbuf;
1198
1199    RPC_LOG_CN_ASSOC_DEALLOC_NTR;
1200    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_dealloc);
1201    CODING_ERROR(st);
1202
1203    *st = rpc_s_ok;
1204    if (assoc != NULL)
1205    {
1206        /*
1207         * Send a deallocate request through the association state
1208         * machine. Make sure to clear the association status code
1209         * first so that the deallocate request will be processed (the
1210         * macro EVAL_USER_EVENT checks that the association status is
1211         * OK before processing the event).
1212         */
1213        RPC_CN_STATS_INCR (dealloced_assocs);
1214        assoc->assoc_status = rpc_s_ok;
1215        RPC_CN_ASSOC_EVAL_USER_EVENT (assoc,
1216                                      RPC_C_ASSOC_DEALLOCATE_REQ,
1217                                      NULL,
1218                                      *st);
1219
1220        /*
1221         * Signal any threads waiting for an association that they can
1222         * retry. Only client threads wait for an existing association.
1223         */
1224        assoc_grp = RPC_CN_ASSOC_GRP (assoc->assoc_grp_id);
1225        if ((assoc_grp != NULL) &&
1226            (assoc_grp->grp_assoc_waiters) &&
1227            (assoc->assoc_flags & RPC_C_CN_ASSOC_CLIENT))
1228        {
1229            RPC_COND_SIGNAL (assoc_grp->grp_assoc_wt,
1230                             rpc_g_global_mutex);
1231        }
1232
1233        /*
1234         * If the passed call_rep is the same as the call rep in the passed
1235         * assoc, then it's ok to flush the receive queue of the association
1236         * just in case this call was orphaned. (The alter context request
1237         * failed in rpc__cn_assoc_request().)
1238         * If both the call rep in the passed assoc and the assoc in the
1239         * passed call rep are NULL, then it's ok to flush the receive queue
1240         * of the association just in case this call was orphaned. (The link
1241         * was broken by rpc__cn_assoc_pop_call().)
1242         * Otherwise, don't flush the receive queue - it means that this
1243         * call rep belongs to an orphaned or being about to finish call.
1244         * The call rep in the assoc refers to a queued call to be executed.
1245         */
1246        if (call_rep == assoc->call_rep
1247            || (assoc->call_rep == NULL && call_rep->assoc == NULL))
1248        {
1249
1250            /*
1251             * Flush the receive queue of the association just in case this
1252             * call was orphaned.
1253             */
1254            RPC_LIST_FIRST (assoc->msg_list,
1255                            fragbuf,
1256                            rpc_cn_fragbuf_p_t);
1257            while (fragbuf != NULL)
1258            {
1259                rpc_cn_fragbuf_t    *next_fragbuf;
1260
1261                RPC_LIST_NEXT (fragbuf,
1262                               next_fragbuf,
1263                               rpc_cn_fragbuf_p_t);
1264                if (fragbuf->fragbuf_dealloc != NULL)
1265                {
1266                    (*fragbuf->fragbuf_dealloc)(fragbuf);
1267                }
1268                fragbuf = next_fragbuf;
1269            }
1270            RPC_LIST_INIT (assoc->msg_list);
1271        }
1272
1273        /*
1274         * Deallocate the association control block.
1275         */
1276        rpc__cn_assoc_acb_dealloc (assoc);
1277    }
1278    RPC_LOG_CN_ASSOC_DEALLOC_XIT;
1279}
1280
1281
1282/***********************************************************************/
1283/*
1284**++
1285**
1286**  ROUTINE NAME:       rpc__cn_assoc_abort
1287**
1288**  SCOPE:              PRIVATE - declared in cnassoc.h
1289**
1290**  DESCRIPTION:
1291**
1292**  This routine will send an abort association request through the
1293**  association state machine.  The caller of this routine is assumed
1294**  to not have a reference to the acb (i.e. it may be the association
1295**  timer reclaimation thread).
1296**
1297**  INPUTS:
1298**
1299**      assoc           The association.
1300**
1301**  INPUTS/OUTPUTS:     none
1302**
1303**  OUTPUTS:
1304**
1305**      st              The return status of this routine.
1306**                      rpc_s_ok
1307**
1308**  IMPLICIT INPUTS:    none
1309**
1310**  IMPLICIT OUTPUTS:   none
1311**
1312**  FUNCTION VALUE:     none
1313**
1314**  SIDE EFFECTS:       none
1315**
1316**--
1317**/
1318
1319PRIVATE void rpc__cn_assoc_abort
1320(
1321  rpc_cn_assoc_p_t        assoc,
1322  unsigned32              *st
1323)
1324{
1325    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_abort);
1326
1327    RPC_CN_STATS_INCR (aborted_assocs);
1328
1329    /*
1330     * Send an association abort request through the association
1331     * state machine. Make sure to clear the association status code
1332     * first so the event will be processed.
1333     */
1334    assoc->assoc_status = rpc_s_ok;
1335    RPC_CN_ASSOC_EVAL_USER_EVENT (assoc,
1336                                  RPC_C_ASSOC_ABORT_REQ,
1337                                  NULL,
1338                                  *st);
1339}
1340
1341
1342/******************************************************************************/
1343/*
1344**++
1345**
1346**  ROUTINE NAME:       rpc__cn_assoc_pop_call
1347**
1348**  SCOPE:              PRIVATE - declared in cnassoc.h
1349**
1350**  DESCRIPTION:
1351**
1352**  This routine will return the call rep contained on the association.
1353**
1354**  INPUTS:
1355**
1356**      assoc           The association containing the call rep.
1357**
1358**  INPUTS/OUTPUTS:     none
1359**
1360**  OUTPUTS:            none
1361**
1362**  IMPLICIT INPUTS:    none
1363**
1364**  IMPLICIT OUTPUTS:   none
1365**
1366**  FUNCTION VALUE:
1367**
1368**      call_r          The call rep.
1369**
1370**  SIDE EFFECTS:       none
1371**
1372**--
1373**/
1374
1375PRIVATE rpc_cn_call_rep_t *rpc__cn_assoc_pop_call
1376(
1377  rpc_cn_assoc_p_t   assoc,
1378  rpc_cn_call_rep_p_t  call_rep
1379)
1380{
1381    rpc_cn_call_rep_t   *call_r;
1382    rpc_cn_assoc_grp_t  *assoc_grp;
1383    unsigned32          st;
1384
1385    RPC_LOG_CN_ASSOC_POP_CALL_NTR;
1386    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_pop_call);
1387
1388    if (assoc != NULL)
1389    {
1390        /*
1391         * Decrement the association group's total call count. If it
1392         * becomes zero, it's a server association group and the current
1393         * state is call wait send a no calls indication event through
1394         * the group's state machine.
1395         */
1396        assoc_grp = RPC_CN_ASSOC_GRP (assoc->assoc_grp_id);
1397        if (assoc_grp != NULL)
1398        {
1399            assoc_grp->grp_callcnt--;
1400            if ((assoc_grp->grp_flags & RPC_C_CN_ASSOC_GRP_SERVER)
1401                &&
1402                (assoc_grp->grp_callcnt == 0)
1403                &&
1404                (assoc_grp->grp_state.cur_state ==
1405                 RPC_C_SERVER_ASSOC_GRP_CALL_WAIT))
1406            {
1407                RPC_CN_ASSOC_GRP_EVAL_EVENT (assoc_grp,
1408                                             RPC_C_ASSOC_GRP_NO_CALLS_IND,
1409                                             assoc,
1410                                             assoc_grp->grp_status);
1411            }
1412        }
1413
1414        /*
1415         * If this was the last call on a client association send a
1416         * calls done event through its state machine.
1417         */
1418        if (assoc->assoc_flags & RPC_C_CN_ASSOC_CLIENT)
1419        {
1420            /*
1421             * Make sure to clear the association status code first
1422             * so this event will be processed.
1423             */
1424            assoc->assoc_status = rpc_s_ok;
1425            RPC_CN_ASSOC_EVAL_USER_EVENT (assoc,
1426                                          RPC_C_ASSOC_CALLS_DONE,
1427                                          NULL,
1428                                          st);
1429        }
1430
1431        /*
1432         * Save a pointer to the call rep on the association.
1433         */
1434        call_r = assoc->call_rep;
1435
1436        /*
1437         * If the passed call_rep is the same as the call rep in the
1438         * passed assoc, then it's ok to break the link. Otherwise,
1439         * don't change the assoc - it means that this call rep belongs
1440         * to an orphaned call. The assoc refers to a queued call to be
1441         * executed.
1442         */
1443        if (call_rep == call_r)
1444        {
1445            assoc->call_rep = NULL;
1446        }
1447
1448        /*
1449         * Break the connection from the call rep back to the association.
1450         */
1451        call_rep->assoc = NULL;
1452
1453        RPC_LOG_CN_ASSOC_POP_CALL_XIT;
1454    }
1455    else
1456    {
1457        call_r = NULL;
1458    }
1459
1460    return (call_r);
1461}
1462
1463
1464/******************************************************************************/
1465/*
1466**++
1467**
1468**  ROUTINE NAME:       rpc__cn_assoc_push_call
1469**
1470**  SCOPE:              PRIVATE - declared in cnassoc.h
1471**
1472**  DESCRIPTION:
1473**
1474**  This routine will put a call rep on an association.
1475**
1476**  INPUTS:
1477**
1478**      assoc           The association containing the call rep.
1479**      call_r          The call rep to be placed.
1480**
1481**  INPUTS/OUTPUTS:     none
1482**
1483**  OUTPUTS:            none
1484**
1485**  IMPLICIT INPUTS:    none
1486**
1487**  IMPLICIT OUTPUTS:   none
1488**
1489**  FUNCTION VALUE:     none
1490**
1491**  SIDE EFFECTS:       none
1492**
1493**--
1494**/
1495
1496PRIVATE void rpc__cn_assoc_push_call
1497(
1498  rpc_cn_assoc_p_t        assoc,
1499  rpc_cn_call_rep_p_t     call_r,
1500  unsigned32              *st
1501)
1502{
1503    rpc_cn_assoc_grp_t  *assoc_grp;
1504
1505    RPC_LOG_CN_ASSOC_PUSH_CALL_NTR;
1506    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_push_call);
1507
1508    /*
1509     * Push the new call rep onto the association.
1510     */
1511    assoc->call_rep = call_r;
1512
1513    /*
1514     * Increment the association group's total call count.
1515     */
1516    assoc_grp = RPC_CN_ASSOC_GRP (assoc->assoc_grp_id);
1517    if (assoc_grp != NULL)
1518    {
1519        *st = rpc_s_ok;
1520        assoc_grp->grp_callcnt++;
1521    }
1522    else
1523    {
1524        *st = rpc_s_assoc_grp_not_found;
1525    }
1526
1527    RPC_LOG_CN_ASSOC_PUSH_CALL_XIT;
1528}
1529
1530
1531/******************************************************************************/
1532/*
1533**++
1534**
1535**  ROUTINE NAME:       rpc__cn_assoc_queue_frag
1536**
1537**  SCOPE:              PRIVATE - declared in cnassoc.h
1538**
1539**  DESCRIPTION:
1540**
1541**  This routine will queue a fragment buffer on the end of the
1542**  message list of an association. In addition it will notify any
1543**  thread waiting for a fragment buffer on this association that
1544**  one is available.
1545**
1546**  INPUTS:
1547**
1548**      assoc           The association containing the queue of
1549**                      fragment buffers.
1550**      fragbuf         The fragment buffer to queue.
1551**      signal          true if the condition variable should be signalled.
1552**
1553**  INPUTS/OUTPUTS:     none
1554**
1555**  OUTPUTS:            none
1556**
1557**  IMPLICIT INPUTS:    none
1558**
1559**  IMPLICIT OUTPUTS:   none
1560**
1561**  FUNCTION VALUE:     none
1562**
1563**  SIDE EFFECTS:       none
1564**
1565**--
1566**/
1567
1568PRIVATE void rpc__cn_assoc_queue_frag
1569(
1570  rpc_cn_assoc_p_t        assoc,
1571  rpc_cn_fragbuf_p_t      fragbuf,
1572  boolean32               signal
1573)
1574{
1575    RPC_LOG_CN_ASSOC_Q_FRAG_NTR;
1576    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_queue_frag);
1577
1578    /*
1579     * Queue the fragment buffer to the tail of the list.
1580     */
1581    RPC_LIST_ADD_TAIL (assoc->msg_list, fragbuf, rpc_cn_fragbuf_p_t);
1582
1583    /*
1584     * Notify any waiting threads that there's a buffer on this
1585     * association if the caller indicated it and there are waiters.
1586     */
1587    if (signal && assoc->assoc_msg_waiters)
1588    {
1589        RPC_COND_SIGNAL (assoc->assoc_msg_cond,
1590                         rpc_g_global_mutex);
1591    }
1592    RPC_LOG_CN_ASSOC_Q_FRAG_XIT;
1593}
1594
1595
1596/******************************************************************************/
1597/*
1598**++
1599**
1600**  ROUTINE NAME:       rpc__cn_assoc_queue_dummy_frag
1601**
1602**  SCOPE:              PRIVATE - declared in cnassoc.h
1603**
1604**  DESCRIPTION:
1605**
1606**  This routine will queue the built-in dummy fragment buffer on
1607**  the end of the  message list of an association. In addition it will notify
1608**  any thread waiting for a fragment buffer on this association that
1609**  one is available.
1610**
1611**  INPUTS:
1612**
1613**      assoc           The association containing the queue of
1614**                      fragment buffers.
1615**
1616**  INPUTS/OUTPUTS:     none
1617**
1618**  OUTPUTS:            none
1619**
1620**  IMPLICIT INPUTS:    none
1621**
1622**  IMPLICIT OUTPUTS:   none
1623**
1624**  FUNCTION VALUE:     none
1625**
1626**  SIDE EFFECTS:       none
1627**
1628**--
1629**/
1630
1631PRIVATE void rpc__cn_assoc_queue_dummy_frag
1632(
1633  rpc_cn_assoc_p_t        assoc
1634)
1635{
1636    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_queue_dummy_frag);
1637
1638    /*
1639     * Queue the fragment buffer to the tail of the list.
1640     */
1641    RPC_LIST_ADD_TAIL (assoc->msg_list,
1642                       &assoc->assoc_dummy_fragbuf,
1643                       rpc_cn_fragbuf_p_t);
1644
1645    /*
1646     * Notify any waiting threads that there's a buffer on this
1647     * association if the caller indicated it and there are waiters.
1648     */
1649    if (assoc->assoc_msg_waiters)
1650    {
1651        RPC_COND_SIGNAL (assoc->assoc_msg_cond,
1652                         rpc_g_global_mutex);
1653    }
1654}
1655
1656
1657/******************************************************************************/
1658/*
1659**++
1660**
1661**  ROUTINE NAME:       rpc__cn_assoc_receive_frag
1662**
1663**  SCOPE:              PRIVATE - declared in cnassoc.h
1664**
1665**  DESCRIPTION:
1666**
1667**  This routine will receive a fragment over the connection
1668**  attached to an association.
1669**
1670**  INPUTS:
1671**
1672**      assoc           The association to receive from.
1673**      fragbuf         The place to put the received fragment.
1674**
1675**  INPUTS/OUTPUTS:     none
1676**
1677**  OUTPUTS:
1678**
1679**      st              The return status of this routine.
1680**                      rpc_s_ok
1681**
1682**  IMPLICIT INPUTS:    none
1683**
1684**  IMPLICIT OUTPUTS:   none
1685**
1686**  FUNCTION VALUE:
1687**
1688**                      rpc_s_ok
1689**
1690**  SIDE EFFECTS:       none
1691**
1692**--
1693**/
1694
1695PRIVATE void rpc__cn_assoc_receive_frag
1696(
1697  rpc_cn_assoc_p_t        assoc,
1698  rpc_cn_fragbuf_p_t      *fragbuf,
1699  unsigned32              *st
1700)
1701{
1702    volatile boolean32  retry_op;
1703    rpc_cn_call_rep_p_t call_rep;
1704    rpc_binding_rep_p_t binding_r;
1705
1706    RPC_LOG_CN_ASSOC_RECV_FRAG_NTR;
1707    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_receive_frag);
1708    CODING_ERROR(st);
1709
1710    /*
1711     * Wait for the receiver thread to put something on the queue.
1712     */
1713    retry_op = true;
1714    while ((assoc->assoc_status == rpc_s_ok) && (RPC_LIST_EMPTY (assoc->msg_list)))
1715    {
1716        /*
1717         * Save the assoc's call_rep before we begin the wait.
1718         */
1719        call_rep = assoc->call_rep;
1720        binding_r = call_rep->binding_rep;
1721        assert(binding_r != NULL);
1722
1723        assoc->assoc_msg_waiters++;
1724
1725        /*
1726         * Since this is a cancellable operation we'll set
1727         * up an exception handler.
1728         */
1729        RPC_LOG_TRY_PRE;
1730        DCETHREAD_TRY
1731        RPC_LOG_TRY_POST;
1732        {
1733            RPC_COND_WAIT (assoc->assoc_msg_cond,
1734                           rpc_g_global_mutex);
1735        }
1736        RPC_LOG_CATCH_PRE;
1737        DCETHREAD_CATCH (dcethread_interrupt_e)
1738        RPC_LOG_CATCH_POST;
1739        {
1740            RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL,
1741                            ("(rpc__cn_assoc_receive_frag) call_rep->%p assoc->%p desc->%p cancel caught\n",
1742                             assoc->call_rep,
1743                             assoc,
1744                             assoc->cn_ctlblk.cn_sock));
1745            rpc__cn_call_local_cancel (call_rep,
1746                                       &retry_op,
1747                                       st);
1748        }
1749        RPC_LOG_ENDTRY_PRE;
1750        DCETHREAD_ENDTRY
1751        RPC_LOG_ENDTRY_POST;
1752
1753        assoc->assoc_msg_waiters--;
1754
1755        /*
1756         * If the call_rep is different from the original call, it means
1757         * the original call was orphaned and another call began in
1758         * another call executor thread (on this assoc). In this
1759         * case we don't want to read a fragbuf (it doesn't belong to us).
1760         * We'll get here when the stop_orphan_action_rtn either signals
1761         * the assoc_msg_cond condition variable cancels the call executor
1762         * thread.
1763         */
1764        if (call_rep != assoc->call_rep)
1765        {
1766            *st = rpc_s_call_orphaned;
1767            return;
1768        }
1769
1770        /*
1771         * If a cancel was caught and the operation should not be
1772         * retried just return now. The error status is already set up.
1773         */
1774        if (!retry_op)
1775        {
1776            return;
1777        }
1778    }
1779
1780    /*
1781     * Remove a fragment from the queue.
1782     */
1783    RPC_LIST_REMOVE_HEAD (assoc->msg_list,
1784                          *fragbuf,
1785                          rpc_cn_fragbuf_p_t);
1786
1787    *st = assoc->assoc_status;
1788    RPC_LOG_CN_ASSOC_RECV_FRAG_XIT;
1789}
1790
1791
1792/******************************************************************************/
1793/*
1794**++
1795**
1796**  ROUTINE NAME:       rpc__cn_assoc_send_frag
1797**
1798**  SCOPE:              PRIVATE - declared in cnassoc.h
1799**
1800**  DESCRIPTION:
1801**
1802**  This routine will send a vector of fragments over the connection
1803**  attached to an association.
1804**
1805**  INPUTS:
1806**
1807**      assoc           The association to send over.
1808**      iovector        The iovector containing the buffers to be sent.
1809**      sec             The security context element containing
1810**                      information required to apply the authn
1811**                      level requested, NULL if none.
1812**
1813**  INPUTS/OUTPUTS:     none
1814**
1815**  OUTPUTS:
1816**
1817**      st              The return status of this routine.
1818**                      rpc_s_ok
1819**                      rpc_s_connection_aborted
1820**                      rpc_s_connection_closed
1821**
1822**  IMPLICIT INPUTS:    none
1823**
1824**  IMPLICIT OUTPUTS:   none
1825**
1826**  FUNCTION VALUE:     none
1827**
1828**  SIDE EFFECTS:       none
1829**
1830**--
1831**/
1832
1833PRIVATE void rpc__cn_assoc_send_frag
1834(
1835  rpc_cn_assoc_p_t        assoc,
1836  rpc_iovector_p_t        iovector,
1837  rpc_cn_sec_context_p_t  sec,
1838  unsigned32              *st
1839)
1840{
1841    rpc_socket_iovec_t          iov[RPC_C_MAX_IOVEC_LEN];
1842    volatile int                iovcnt;
1843    rpc_socket_iovec_t          * volatile iovp;
1844    rpc_socket_iovec_t          out_iov;
1845    static rpc_addr_p_t         addr = NULL;
1846    volatile size_t             bytes_to_send;
1847    volatile boolean32          free_iov_buffer;
1848    volatile boolean32          retry_op;
1849    volatile rpc_socket_error_t serr;
1850    size_t                      cc;
1851    byte_p_t                    volatile save_base = NULL;
1852
1853    //DO_NOT_CLOBBER(iovcnt);
1854    //DO_NOT_CLOBBER(iovp);
1855    //DO_NOT_CLOBBER(bytes_to_send);
1856    //DO_NOT_CLOBBER(free_iov_buffer);
1857    //DO_NOT_CLOBBER(save_base);
1858
1859    RPC_LOG_CN_ASSOC_SEND_FRAG_NTR;
1860    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_send_frag);
1861    CODING_ERROR(st);
1862
1863    if (!assoc->cn_ctlblk.cn_sock)
1864    {
1865        *st = rpc_s_connection_closed;
1866        return;
1867    }
1868
1869    memset(&iov[0], 0, sizeof(iov));
1870
1871    /*
1872     * Convert the RPC iovector array of buffers passed in the
1873     * system defined iov array of buffers to be handed to the
1874     * socket interface.
1875     */
1876    RPC_CN_NETWORK_IOVECTOR_TO_IOV (iovector,
1877                                    iov,
1878                                    iovcnt,
1879                                    bytes_to_send);
1880    iovp = &iov[0];
1881
1882    /*
1883     * Apply the authentication level requested, if any.
1884     */
1885    free_iov_buffer = false;
1886    if (sec != NULL)
1887    {
1888        RPC_CN_AUTH_PRE_SEND (&assoc->security,
1889                              sec,
1890                              iovp,
1891                              iovcnt,
1892                              &out_iov,
1893                              st);
1894        if (*st != rpc_s_ok)
1895        {
1896            if (assoc->assoc_flags & RPC_C_CN_ASSOC_SERVER)
1897            {
1898                dce_error_string_t error_text;
1899                int temp_status;
1900
1901                dce_error_inq_text(*st, error_text, &temp_status);
1902
1903                /*
1904                 * rpc_m_call_failed_s
1905                 * "%s on server failed: %s"
1906                 */
1907                rpc_dce_svc_printf (
1908                    __FILE__, __LINE__,
1909                    "%s %x",
1910                    rpc_svc_auth,
1911                    svc_c_sev_error,
1912                    rpc_m_call_failed_s,
1913                    "RPC_CN_AUTH_PRE_SEND",
1914                    error_text );
1915            }
1916            return;
1917        };
1918
1919        /*
1920         * The pre_send routine may have had to coalesce the iov
1921         * elements given to it into a single buffer for encryption.
1922         * If so then we should send that instead of what was given
1923         * to pre_send.
1924         */
1925        if (out_iov.iov_base != NULL)
1926        {
1927            iovp = &out_iov;
1928            iovcnt = 1;
1929            bytes_to_send = iovp->iov_len;
1930            free_iov_buffer = true;
1931            save_base = iovp->iov_base;
1932        }
1933    }
1934
1935    /*
1936     * Now send the constructed system iov array on the connection
1937     * identified in the association control block.
1938     */
1939    serr = 0;
1940    /* be careful, retry_op really is read contrary to what clang
1941     analyzer states */
1942    retry_op = true;
1943    while ((bytes_to_send) && (!RPC_SOCKET_IS_ERR (serr)))
1944    {
1945        RPC_LOG_TRY_PRE;
1946        DCETHREAD_TRY
1947        RPC_LOG_TRY_POST;
1948        {
1949            /*
1950             * Unlock the global mutex in case we get flow blocked. This
1951             * will allow other threads to continue. Set the "in_sendmsg"
1952             * flag to indicate to the receiver thread that we are in sendmsg
1953             * so it should not send any events through the state machine
1954             * until we are done.
1955             */
1956            assoc->cn_ctlblk.in_sendmsg = true;
1957            RPC_CN_UNLOCK ();
1958
1959#ifdef NON_CANCELLABLE_IO
1960            /*
1961             * By posix definition dcethread_enableasync is not a "cancel
1962             * point" because it must return an error status and an errno.
1963             * dcethread_enableasync(1) will not deliver
1964             * a pending cancel nor will the cancel be delivered asynchronously,
1965             * thus the need for dcethread_testcancel.
1966             */
1967            dcethread_enableasync_throw(1);
1968	    dcethread_checkinterrupt_throw();
1969#endif /* NON_CANCELLABLE_IO */
1970            serr = rpc__socket_sendmsg (
1971                assoc->cn_ctlblk.cn_sock,
1972                iovp,
1973                iovcnt,
1974                addr,
1975                &cc);
1976
1977#ifdef NON_CANCELLABLE_IO
1978	    dcethread_enableasync_throw(0);
1979#endif /* NON_CANCELLABLE_IO */
1980            /*
1981             * A sendmsg has just completed. Re-aquire the global mutex
1982             * and notify our receiver thread that we are done if it is
1983             * waiting.
1984	     *
1985	     * NOTE that we also need to reacquire the mutex in
1986	     * every DCETHREAD_CATCH clause associated with this TRY/ENDTRY.
1987             */
1988            RPC_CN_LOCK ();
1989            assoc->cn_ctlblk.in_sendmsg = false;
1990
1991        }
1992        RPC_LOG_CATCH_PRE;
1993        DCETHREAD_CATCH (dcethread_interrupt_e)
1994        RPC_LOG_CATCH_POST;
1995        {
1996#ifdef NON_CANCELLABLE_IO
1997            dcethread_enableasync_throw(0);
1998#endif /* NON_CANCELLABLE_IO */
1999            /*
2000             * A sendmsg has just completed. Re-aquire the global mutex
2001             * and notify our receiver thread that we are done if it is
2002             * waiting.
2003	     */
2004	    RPC_CN_LOCK ();
2005            assoc->cn_ctlblk.in_sendmsg = false;
2006
2007            /*
2008             * The test for cancel is before any data has been sent.
2009             * Set count of bytes of data sent to zero.
2010             */
2011            cc = 0;
2012            /*
2013             * Do NOT forward the cancel to the server just record
2014             * that it was detected.
2015             * Note: this is a copy of rpc__cn_call_local_cancel()
2016             * with the call to rpc__cn_call_forward_cancel() removed.
2017             */
2018            if (RPC_CALL_IS_CLIENT (((rpc_call_rep_t *) assoc->call_rep)))
2019            {
2020                /*
2021                 * Record the cancel that was just detected.
2022                 */
2023                assoc->call_rep->u.client.cancel.local_count++;
2024                rpc__cn_call_start_cancel_timer (assoc->call_rep, st);
2025                if (*st == rpc_s_ok)
2026                {
2027                    retry_op = true;
2028                }
2029                else
2030                {
2031                    retry_op = false;
2032                }
2033            }
2034            else
2035            {
2036                retry_op = false;
2037                *st = rpc_s_call_cancelled;
2038            }
2039
2040            RPC_DBG_PRINTF (rpc_e_dbg_cancel, RPC_C_CN_DBG_CANCEL,
2041                            ("(rpc__cn_assoc_send_frag) call_rep->%p assoc->%p desc->%p cancel caught\n",
2042                             assoc->call_rep,
2043                             assoc,
2044                             assoc->cn_ctlblk.cn_sock));
2045
2046        }
2047        DCETHREAD_CATCH (dcethread_SIGPIPE_e)
2048        {
2049#ifdef NON_CANCELLABLE_IO
2050	    dcethread_enableasync_throw(0);
2051#endif
2052            /*
2053             * A sendmsg has just completed. Re-aquire the global mutex
2054             * and notify our receiver thread that we are done if it is
2055             * waiting.
2056	     */
2057	    RPC_CN_LOCK ();
2058            assoc->cn_ctlblk.in_sendmsg = false;
2059
2060            cc = -1;
2061            serr = RPC_C_SOCKET_EPIPE;
2062        }
2063        RPC_LOG_ENDTRY_PRE;
2064        DCETHREAD_ENDTRY
2065        RPC_LOG_ENDTRY_POST;
2066
2067        if (assoc->cn_ctlblk.waiting_for_sendmsg_complete)
2068        {
2069            RPC_COND_SIGNAL (assoc->cn_ctlblk.cn_rcvr_cond,
2070                             rpc_g_global_mutex);
2071        }
2072
2073        /*
2074         * If a cancel was caught and the operation should not be
2075         * retried just return now. The error status is already set
2076         * up.
2077         */
2078        if (!retry_op)
2079        {
2080            return;
2081        }
2082
2083        /*
2084         * Check the operation for an error.
2085         */
2086        if (RPC_SOCKET_IS_ERR (serr))
2087        {
2088            RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_ERRORS,
2089                            ("(rpc__cn_assoc_send_frag) call_rep->%p assoc->%p desc->%p SENDMSG failed, error=%d\n",
2090                             assoc->call_rep,
2091                             assoc,
2092                             assoc->cn_ctlblk.cn_sock,
2093                             RPC_SOCKET_ETOI(serr)));
2094            /*
2095             * The transmit failed. Find out why.
2096             */
2097            switch (serr)
2098            {
2099                case (RPC_C_SOCKET_ECONNRESET):
2100                assoc->assoc_status = rpc_s_connection_aborted;
2101                *st = rpc_s_connection_aborted;
2102                break;
2103
2104                default:
2105                assoc->assoc_status = rpc_s_connection_closed;
2106                *st = rpc_s_connection_closed;
2107            }
2108            break;
2109        }
2110
2111        RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
2112                        ("CN: call_rep->%p assoc->%p desc->%p sent %ld bytes\n",
2113                         assoc->call_rep,
2114                         assoc,
2115                         assoc->cn_ctlblk.cn_sock,
2116                         cc));
2117        bytes_to_send -= cc;
2118        if (bytes_to_send)
2119        {
2120            RPC_CN_NETWORK_IOV_ADJUST (iovp, iovcnt, cc);
2121        }
2122    }
2123
2124    /*
2125     * Free the security allocated contiguous buffer is we have to.
2126     */
2127    if (free_iov_buffer)
2128    {
2129        RPC_MEM_FREE (save_base,
2130                      RPC_C_MEM_CN_ENCRYPT_BUF);
2131    }
2132
2133    if (!RPC_SOCKET_IS_ERR (serr))
2134    {
2135        /*
2136         * Keep some stats on the packets sent.
2137         */
2138        RPC_CN_STATS_INCR (pstats[RPC_CN_PKT_PTYPE (((rpc_cn_packet_p_t) iovector->elt[0].data_addr))].sent);
2139        RPC_CN_STATS_INCR (pkts_sent);
2140        *st = rpc_s_ok;
2141        RPC_CN_PKT_TRC (((rpc_cn_packet_p_t) iovector->elt[0].data_addr));
2142        RPC_CN_IOV_DUMP (iovector);
2143
2144        /*
2145         * Increment the per-association security context next send
2146         * sequence number.
2147         */
2148        assoc->security.assoc_next_snd_seq++;
2149    }
2150    RPC_LOG_CN_ASSOC_SEND_FRAG_XIT;
2151}
2152
2153
2154/******************************************************************************/
2155/*
2156**++
2157**
2158**  ROUTINE NAME:       rpc__cn_assoc_send_fragbuf
2159**
2160**  SCOPE:              PRIVATE - declared in cnassoc.h
2161**
2162**  DESCRIPTION:
2163**
2164**      This routine will convert a fragbuf to a vector of fragments
2165**      and send them over a connection. If indicated the fragbuf will
2166**      then be freed.
2167**
2168**  INPUTS:
2169**
2170**      assoc           The association to send over.
2171**      fragbuf         The fragbuf to be sent.
2172**      sec             The security context element containing
2173**                      information required to apply the authn
2174**                      level requested, NULL if none.
2175**      freebuf         Flags to indicate we should free the fragbuf.
2176**
2177**  INPUTS/OUTPUTS:     none
2178**
2179**  OUTPUTS:
2180**
2181**      st              The return status of this routine.
2182**
2183**  IMPLICIT INPUTS:    none
2184**
2185**  IMPLICIT OUTPUTS:   none
2186**
2187**  FUNCTION VALUE:     none
2188**
2189**  SIDE EFFECTS:       none
2190**
2191**--
2192**/
2193
2194PRIVATE void rpc__cn_assoc_send_fragbuf
2195(
2196  rpc_cn_assoc_p_t        assoc,
2197  rpc_cn_fragbuf_p_t      fragbuf,
2198  rpc_cn_sec_context_p_t  sec,
2199  boolean32                freebuf,
2200  unsigned32              *st
2201)
2202{
2203    rpc_iovector_t              iovector;
2204
2205    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_send_fragbuf);
2206
2207    /*
2208     * The PDU is ready to be sent. Put it into an RPC
2209     * iovector structure.
2210     */
2211    iovector.num_elt = 1;
2212    iovector.elt[0].flags = 0;
2213    iovector.elt[0].data_addr = (byte_p_t) fragbuf->data_p;
2214    iovector.elt[0].data_len = fragbuf->data_size;
2215
2216    /*
2217     * Now actually send the PDU.
2218     */
2219    rpc__cn_assoc_send_frag (assoc, &iovector, sec, st);
2220
2221    /*
2222     * Free up the fragment buffer we used whether the send
2223     * succeeded or failed.
2224     */
2225    if (freebuf)
2226        (*fragbuf->fragbuf_dealloc)(fragbuf);
2227}
2228
2229
2230/******************************************************************************/
2231/*
2232**++
2233**
2234**  ROUTINE NAME:       rpc__cn_assoc_syntax_negotiate
2235**
2236**  SCOPE:              PRIVATE - declared in cnassoc.h
2237**
2238**  DESCRIPTION:
2239**
2240**  This routine takes as input a list of abstract syntaxes. Each
2241**  abstract syntax has a list of transfer syntaxes associated with
2242**  it. This routine will determine whether any of the transfer syntaxes
2243**  associated with an abstract syntax are supported. Since an abstract
2244**  syntax is really an interface UUID and version this is done by
2245**  performing an interface lookup which returns the interface
2246**  specification data structure. This structure contains the list of
2247**  transfer syntaxes the stub supports. Note that this is another
2248**  place we'd have to expand the list of transfer syntaxes if procdural
2249**  marshaling were being supported.
2250**
2251**  INPUTS:
2252**
2253**      assoc           The association over which the negotiation
2254**                      is taking place.
2255**      pres_cont_list  A list of abstract syntaxes. Each abstract
2256**                      syntax contains a list of transfer syntaxes.
2257**
2258**  INPUTS/OUTPUTS:
2259**
2260**      size            On input, the size left for formatting the
2261**                      presentation result list. On output the
2262**                      actual size taken for it.
2263**
2264**  OUTPUTS:
2265**
2266**      pres_result_list A list of negotiated transfer syntaxes. One
2267**                      for each abstract syntax in the
2268**                      presentation context list.
2269**      st              The return status of this routine.
2270**
2271**  IMPLICIT INPUTS:    none
2272**
2273**  IMPLICIT OUTPUTS:   none
2274**
2275**  FUNCTION VALUE:     none
2276**
2277**  SIDE EFFECTS:       none
2278**
2279**--
2280**/
2281
2282PRIVATE void rpc__cn_assoc_syntax_negotiate
2283(
2284  rpc_cn_assoc_p_t                assoc,
2285  rpc_cn_pres_cont_list_p_t       pres_cont_list,
2286  unsigned32                      *size,
2287  rpc_cn_pres_result_list_t       *pres_result_list,
2288  unsigned32                      *st
2289)
2290{
2291    unsigned16                  ihint;
2292    rpc_if_rep_t                *if_r;
2293    boolean                     syntax_match;
2294    rpc_cn_syntax_t             *pres_context;
2295    unsigned32                  i, j, k;
2296
2297    CODING_ERROR (st);
2298    RPC_LOG_CN_ASSOC_SYN_NEG_NTR;
2299    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_syntax_negotiate);
2300
2301    if ((i = sizeof (rpc_cn_pres_result_list_t) +
2302        (sizeof (rpc_cn_pres_result_t) *
2303         (pres_cont_list->n_context_elem - 1))) > *size)
2304    {
2305        *st = RPC_S_HEADER_FULL;
2306        *size = 0;
2307        return;
2308    }
2309
2310    *size = i;
2311    *st = rpc_s_ok;
2312
2313    /*
2314     * The number of results has to be the same as the number of
2315     * context elements in the list.
2316     */
2317    pres_result_list->n_results = pres_cont_list->n_context_elem;
2318
2319    /*
2320     * For each element in the presentation context list determine
2321     * if the server stub supports a common transfer syntaxes.
2322     */
2323    for (i = 0; i < pres_cont_list->n_context_elem; i++)
2324    {
2325        /*
2326         * Find the interface specification for the abstract syntax
2327         * (really interface UUID and version). The interface spec
2328         * contains the list of transfer syntaxes supported by the stub.
2329         */
2330        ihint = RPC_C_INVALID_IHINT;
2331        rpc__if_lookup (&pres_cont_list->pres_cont_elem[i].abstract_syntax.id,
2332                        pres_cont_list->pres_cont_elem[i].abstract_syntax.version,
2333                        NULL,
2334                        &ihint,
2335                        &if_r,
2336                        NULL,
2337                        NULL,
2338                        st);
2339
2340#ifdef DEBUG
2341        if (RPC_DBG_EXACT (rpc_es_dbg_cn_errors,
2342                           RPC_C_CN_DBG_IF_LOOKUP))
2343        {
2344            *st = RPC_S_CN_DBG_FAILURE;
2345        }
2346#endif
2347
2348        if (*st != rpc_s_ok)
2349        {
2350            RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
2351                            ("CN: call_rep->%p assoc->%p desc->%p presentation negotiation failed - abstract syntax not registered - st = %x\n",
2352                             assoc->call_rep,
2353                             assoc,
2354                             assoc->cn_ctlblk.cn_sock,
2355                             *st));
2356
2357            /*
2358             * There is no interface registered for the abstract
2359             * syntax given. Fill in the result for this abstract
2360             * syntax in the result list.
2361             */
2362            pres_result_list->pres_results[i].result =
2363            RPC_C_CN_PCONT_PROVIDER_REJECTION;
2364
2365            pres_result_list->pres_results[i].reason =
2366            RPC_C_CN_PPROV_ABSTRACT_SYNTAX_NOT_SUPPORTED;
2367
2368            memset ((char *)&(pres_result_list->pres_results[i].transfer_syntax),
2369                    0,
2370                    sizeof (rpc_cn_pres_syntax_id_t));
2371        }
2372        else
2373        {
2374            /*
2375             * An interface was found. Now try and find a transfer
2376             * syntax common to both the list given in the
2377             * presentation context list and the list in the
2378             * interface spec.
2379             */
2380            for (j = 0, syntax_match = false;
2381                 (!syntax_match) &&
2382                 (j < pres_cont_list->pres_cont_elem[i].n_transfer_syn);
2383                 j++)
2384            {
2385                for (k = 0; k < if_r->syntax_vector.count; k++)
2386                {
2387                    if (RPC_CN_ASSOC_SYNTAX_EQUAL (
2388                       &(pres_cont_list->pres_cont_elem[i].transfer_syntaxes[j]),
2389                       &(if_r->syntax_vector.syntax_id[k]),
2390                       &st))
2391                    {
2392                        RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
2393                                        ("CN: call_rep->%p assoc->%p desc->%p presentation syntax negotiated\n",
2394                                         assoc->call_rep,
2395                                         assoc,
2396                                         assoc->cn_ctlblk.cn_sock));
2397
2398                        /*
2399                         * We have a transfer syntax which matches.
2400                         * Allocate a syntax element, fill it in,
2401                         * and put it on the association syntax list.
2402                         * Mark the the syntax appropriately in the presentation
2403                         * results list and skip to the next
2404                         * abstract syntax. Note that the transfer
2405                         * syntax UUID is not filled in. The server
2406                         * stub requires only the syntax vector index.
2407                         */
2408                        pres_context = rpc__cn_assoc_syntax_alloc (if_r, st);
2409
2410                        pres_context->syntax_ihint = ihint;
2411                        pres_context->syntax_pres_id = pres_cont_list->pres_cont_elem[i].pres_context_id;
2412                        pres_context->syntax_valid = true;
2413                        pres_context->syntax_vector_index = k;
2414                        RPC_LIST_ADD_TAIL (assoc->syntax_list, pres_context, rpc_cn_syntax_p_t);
2415
2416                        pres_result_list->pres_results[i].result =
2417                        RPC_C_CN_PCONT_ACCEPTANCE;
2418
2419                        pres_result_list->pres_results[i].transfer_syntax =
2420                        pres_cont_list->pres_cont_elem[i].transfer_syntaxes[j];
2421
2422                        syntax_match = true;
2423                        break;
2424                    }
2425                } /* end for (k...) */
2426            } /* end for (j...) */
2427
2428#ifdef DEBUG
2429            if (RPC_DBG_EXACT(rpc_es_dbg_cn_errors,
2430                              RPC_C_CN_DBG_NO_XFER_SYNTAX))
2431            {
2432                syntax_match = false;
2433            }
2434#endif
2435
2436            /*
2437             * See if a syntax was matched for this abstract syntax.
2438             */
2439            if (!syntax_match)
2440            {
2441                RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
2442                                ("CN: call_rep->%p assoc->%p desc->%p presentation negotiation failed - no matching transfer syntax\n",
2443                                 assoc->call_rep,
2444                                 assoc,
2445                                 assoc->cn_ctlblk.cn_sock));
2446
2447                /*
2448                 * No matching syntax was found. Mark the
2449                 * presentation result list appropriately.
2450                 */
2451                pres_result_list->pres_results[i].result =
2452                RPC_C_CN_PCONT_PROVIDER_REJECTION;
2453
2454                pres_result_list->pres_results[i].reason =
2455                RPC_C_CN_PPROV_PROPOSED_TRANSFER_SYNTAXES_NOT_SUPPORTED;
2456
2457                memset ((char *)&(pres_result_list->pres_results[i].transfer_syntax),
2458                        0,
2459                        sizeof (rpc_cn_pres_syntax_id_t));
2460            } /* end if (!syntax_match) */
2461        } /* end else (st != rpc_s_unkwown_if) */
2462    } /* end for (i = 0; i < pres_cont_list->n_context_elem; i++) */
2463
2464    *st = rpc_s_ok;
2465    RPC_LOG_CN_ASSOC_SYN_NEG_XIT;
2466}
2467
2468
2469/******************************************************************************/
2470/*
2471**++
2472**
2473**  ROUTINE NAME:       rpc__cn_assoc_syntax_lkup_by_id
2474**
2475**  SCOPE:              PRIVATE - declared in cnassoc.h
2476**
2477**  DESCRIPTION:
2478**
2479**  This routine will lookup the presentation context element by
2480**  matching the presentation context id.
2481**
2482**  INPUTS:
2483**
2484**      assoc           The association being looked up.
2485**	context_id	The context id of the presentation context being looked up.
2486**
2487**  INPUTS/OUTPUTS:     none
2488**
2489**  OUTPUTS:
2490**
2491**      pres_context    The pointer to the matching presentation
2492**                      context element.
2493**	st		The return status of this routine.
2494**                      rpc_s_ok
2495**                      rpc_s_context_id_not_found
2496**
2497**  IMPLICIT INPUTS:    none
2498**
2499**  IMPLICIT OUTPUTS:   none
2500**
2501**  FUNCTION VALUE:     none
2502**
2503**  SIDE EFFECTS:       none
2504**
2505**--
2506**/
2507
2508PRIVATE void rpc__cn_assoc_syntax_lkup_by_id
2509(
2510  rpc_cn_assoc_p_t		assoc,
2511  unsigned32                      context_id,
2512  rpc_cn_syntax_p_t               *pres_context,
2513  unsigned32    		        *st
2514)
2515{
2516    RPC_LOG_CN_ASSOC_SYN_LKUP_NTR;
2517    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_syntax_lkup_by_id);
2518    CODING_ERROR(st);
2519
2520    /*
2521     * Scan the syntax list on the association for a match on the
2522     * context id.
2523     */
2524    RPC_LIST_FIRST (assoc->syntax_list,
2525                    *pres_context,
2526                    rpc_cn_syntax_p_t);
2527    while (*pres_context != NULL)
2528    {
2529        /*
2530         * Compare the presentation context id in the syntax element
2531         * with the one passed in.
2532         */
2533        if ((*pres_context)->syntax_pres_id == context_id)
2534        {
2535            /*
2536             * We have a match. Return it.
2537             */
2538            *st = rpc_s_ok;
2539            return;
2540        }
2541        RPC_LIST_NEXT (*pres_context, *pres_context, rpc_cn_syntax_p_t);
2542    }
2543    RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_ERRORS,
2544                    ("CN: call_rep->%p assoc->%p desc->%p presentation context for context id given not found context_id->%x\n",
2545                     assoc->call_rep,
2546                     assoc,
2547                     assoc->cn_ctlblk.cn_sock,
2548                     context_id));
2549    *st = rpc_s_context_id_not_found;
2550    RPC_LOG_CN_ASSOC_SYN_LKUP_XIT;
2551}
2552
2553
2554/******************************************************************************/
2555/*
2556**++
2557**
2558**  ROUTINE NAME:       rpc__cn_assoc_syntax_lkup_by_cl
2559**
2560**  SCOPE:              PRIVATE - declared in cnassoc.h
2561**
2562**  DESCRIPTION:
2563**
2564**  This routine will lookup the presentation context element by
2565**  matching the call id.
2566**
2567**  INPUTS:
2568**
2569**      assoc           The association being looked up.
2570**	call_id	        The call id of the presentation context being looked up.
2571**
2572**  INPUTS/OUTPUTS:     none
2573**
2574**  OUTPUTS:
2575**
2576**      pres_context    The pointer to the matching presentation
2577**                      context element.
2578**	st		The return status of this routine.
2579**                      rpc_s_ok
2580**                      rpc_s_call_id_not_found
2581**
2582**  IMPLICIT INPUTS:    none
2583**
2584**  IMPLICIT OUTPUTS:   none
2585**
2586**  FUNCTION VALUE:     none
2587**
2588**  SIDE EFFECTS:       none
2589**
2590**--
2591**/
2592
2593PRIVATE void rpc__cn_assoc_syntax_lkup_by_cl
2594(
2595rpc_cn_assoc_p_t		assoc,
2596unsigned32                      call_id,
2597rpc_cn_syntax_p_t               *pres_context,
2598unsigned32    		        *st
2599)
2600{
2601    RPC_LOG_CN_ASSOC_SYN_LKUP_NTR;
2602    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_syntax_lkup_by_cl);
2603    CODING_ERROR(st);
2604
2605    /*
2606     * Scan the syntax list on the association for a match on the
2607     * context id.
2608     */
2609    RPC_LIST_FIRST (assoc->syntax_list,
2610                    *pres_context,
2611                    rpc_cn_syntax_p_t);
2612    while (*pres_context != NULL)
2613    {
2614        /*
2615         * Compare the presentation context id in the syntax element
2616         * with the one passed in.
2617         */
2618        if ((*pres_context)->syntax_call_id == call_id)
2619        {
2620            /*
2621             * We have a match. Return it.
2622             */
2623            *st = rpc_s_ok;
2624            return;
2625        }
2626        RPC_LIST_NEXT (*pres_context, *pres_context, rpc_cn_syntax_p_t);
2627    }
2628    RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_ERRORS,
2629                    ("CN: call_rep->%p assoc->%p desc->%p presentation context for call id given not found call_id->%x\n",
2630                     assoc->call_rep,
2631                     assoc,
2632                     assoc->cn_ctlblk.cn_sock,
2633                     call_id));
2634    *st = rpc_s_call_id_not_found;
2635    RPC_LOG_CN_ASSOC_SYN_LKUP_XIT;
2636}
2637
2638
2639/******************************************************************************/
2640/*
2641**++
2642**
2643**  ROUTINE NAME:       rpc__cn_assoc_sec_lkup_by_id
2644**
2645**  SCOPE:              PRIVATE - declared in cnassoc.h
2646**
2647**  DESCRIPTION:
2648**
2649**  This routine will lookup the security context element on an
2650**  association corresponding to the key ID given.
2651**
2652**  INPUTS:
2653**
2654**      assoc           The association being looked up.
2655**	key_id	        The key ID of the security context being looked up.
2656**
2657**  INPUTS/OUTPUTS:     none
2658**
2659**  OUTPUTS:
2660**
2661**      sec             The security context element.
2662**	st		The return status of this routine.
2663**                      rpc_s_ok
2664**                      rpc_s_key_id_not_found
2665**
2666**  IMPLICIT INPUTS:    none
2667**
2668**  IMPLICIT OUTPUTS:   none
2669**
2670**  FUNCTION VALUE:     none
2671**
2672**  SIDE EFFECTS:       none
2673**
2674**--
2675**/
2676
2677PRIVATE void rpc__cn_assoc_sec_lkup_by_id
2678(
2679  rpc_cn_assoc_p_t		        assoc,
2680  unsigned32                              key_id,
2681  rpc_cn_sec_context_p_t                  *sec,
2682  unsigned32    		                *st
2683)
2684{
2685    rpc_cn_sec_context_t                *sec_context;
2686
2687    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_sec_lkup_by_id);
2688    CODING_ERROR(st);
2689
2690    /*
2691     * Scan the security context list on the association for a match on the
2692     * context id.
2693     */
2694    RPC_LIST_FIRST (assoc->security.context_list,
2695                    sec_context,
2696                    rpc_cn_sec_context_p_t);
2697    while (sec_context != NULL)
2698    {
2699        /*
2700         * Compare the key ID in the security context element
2701         * with the one passed in.
2702         */
2703        if (sec_context->sec_key_id == key_id)
2704        {
2705            /*
2706             * We have a match. Return the pointer to the security
2707             * context element.
2708             */
2709            *sec = sec_context;
2710            *st = rpc_s_ok;
2711            return;
2712        }
2713        RPC_LIST_NEXT (sec_context, sec_context, rpc_cn_sec_context_p_t);
2714    }
2715    RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_SECURITY_ERRORS,
2716                    ("CN: call_rep->%p assoc->%p desc->%p no matching security context element for key id key_id->%x\n",
2717                     assoc->call_rep,
2718                     assoc,
2719                     assoc->cn_ctlblk.cn_sock,
2720                     key_id));
2721    *sec = NULL;
2722    *st = rpc_s_key_id_not_found;
2723}
2724
2725
2726/******************************************************************************/
2727/*
2728**++
2729**
2730**  ROUTINE NAME:       rpc__cn_assoc_sec_lkup_by_cl
2731**
2732**  SCOPE:              PRIVATE - declared in cnassoc.h
2733**
2734**  DESCRIPTION:
2735**
2736**  This routine will lookup the security context element on an
2737**  association corresponding to the call id given.
2738**
2739**  INPUTS:
2740**
2741**      assoc           The association being looked up.
2742**	call_id	        The call ID of the security context being looked up.
2743**
2744**  INPUTS/OUTPUTS:     none
2745**
2746**  OUTPUTS:
2747**
2748**      sec             The security context element.
2749**	st		The return status of this routine.
2750**                      rpc_s_ok
2751**                      rpc_s_call_id_not_found
2752**
2753**  IMPLICIT INPUTS:    none
2754**
2755**  IMPLICIT OUTPUTS:   none
2756**
2757**  FUNCTION VALUE:     none
2758**
2759**  SIDE EFFECTS:       none
2760**
2761**--
2762**/
2763
2764PRIVATE void rpc__cn_assoc_sec_lkup_by_cl
2765(
2766  rpc_cn_assoc_p_t		        assoc,
2767  unsigned32                            call_id,
2768  rpc_cn_sec_context_p_t                *sec,
2769  unsigned32    		        *st
2770)
2771{
2772    rpc_cn_sec_context_t                *sec_context;
2773
2774    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_sec_lkup_by_cl);
2775    CODING_ERROR(st);
2776
2777    /*
2778     * Scan the security context list on the association for a match on the
2779     * context id.
2780     */
2781    RPC_LIST_FIRST (assoc->security.context_list,
2782                    sec_context,
2783                    rpc_cn_sec_context_p_t);
2784    while (sec_context != NULL)
2785    {
2786        /*
2787         * Compare the key ID in the security context element
2788         * with the one passed in.
2789         */
2790        if (sec_context->sec_last_call_id == call_id)
2791        {
2792            /*
2793             * We have a match. Return the pointer to the security
2794             * context element.
2795             */
2796            *sec = sec_context;
2797            *st = rpc_s_ok;
2798            return;
2799        }
2800        RPC_LIST_NEXT (sec_context, sec_context, rpc_cn_sec_context_p_t);
2801    }
2802    RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_SECURITY_ERRORS,
2803                    ("CN: call_rep->%p assoc->%p desc->%p no matching security context element for call id call_id->%x\n",
2804                     assoc->call_rep,
2805                     assoc,
2806                     assoc->cn_ctlblk.cn_sock,
2807                     call_id));
2808    *sec = NULL;
2809    *st = rpc_s_call_id_not_found;
2810}
2811
2812
2813/******************************************************************************/
2814/*
2815**++
2816**
2817**  ROUTINE NAME:       rpc__cn_assoc_post_error
2818**
2819**  SCOPE:              PRIVATE - declared in cnassoc.h
2820**
2821**  DESCRIPTION:
2822**
2823**  This routine is called when the network receiver thread
2824**  encounters a fatal local error. Errors with the connection
2825**  are sent through the association state machine. This
2826**  routine will close the connection, post a no connection indication
2827**  event to the association state machine and mark the association with
2828**  the appropriate status code
2829**
2830**  INPUTS:
2831**
2832**      assoc           The association.
2833**      st              The error encountered.
2834**
2835**  INPUTS/OUTPUTS:     none
2836**
2837**  OUTPUTS:            none
2838**
2839**  IMPLICIT INPUTS:    none
2840**
2841**  IMPLICIT OUTPUTS:   none
2842**
2843**  FUNCTION VALUE:     none
2844**
2845**  SIDE EFFECTS:       none
2846**
2847**--
2848**/
2849
2850PRIVATE void rpc__cn_assoc_post_error
2851(
2852  rpc_cn_assoc_p_t        assoc,
2853  unsigned32              st
2854)
2855{
2856    unsigned32          local_st;
2857
2858    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_post_error);
2859
2860    RPC_DBG_PRINTF (rpc_e_dbg_general, RPC_C_CN_DBG_GENERAL,
2861                    ("(rpc__cn_assoc_post_error) st->%08x cn_state->%d cur_state->%d\n",
2862                     st, assoc->cn_ctlblk.cn_state, assoc->assoc_state.cur_state));
2863
2864    if ((assoc->cn_ctlblk.cn_state != RPC_C_CN_CLOSED)
2865        &&
2866        (assoc->assoc_state.cur_state != RPC_C_SM_CLOSED_STATE))
2867    {
2868        /*
2869         * First close the connection on the association. We will ignore
2870         * any error status from this routine.
2871         */
2872	if (st != rpc_s_connection_closed) {
2873            rpc__cn_network_close_connect (assoc, &local_st);
2874	}
2875
2876        /*
2877         * Post a no connection indication event to the association
2878         * state machine. This will transition the association into the
2879         * correct state and set the association message list condition
2880         * variable. Setting this will wake up any threads blocked
2881         * waiting for receive data.
2882         *
2883         * Make sure to clear the association status code first
2884         * so this event will be processed.
2885         */
2886        assoc->assoc_status = rpc_s_ok;
2887        RPC_CN_ASSOC_EVAL_USER_EVENT (assoc,
2888                                      RPC_C_ASSOC_NO_CONN_IND,
2889                                      NULL,
2890                                      st);
2891    }
2892    else
2893    {
2894        return;
2895    }
2896
2897    /*
2898     * Mark the association with the status code passed in as an
2899     * argument.
2900     */
2901    assoc->assoc_status = st;
2902}
2903
2904
2905/***********************************************************************/
2906/*
2907**++
2908**
2909**  ROUTINE NAME:       rpc__cn_assoc_sm_protocol_error
2910**
2911**  SCOPE:              PRIVATE
2912**
2913**  DESCRIPTION:
2914**
2915**  Action routine invoked when an illegal transition is detected.
2916**  This routine writes an error message to stdout and DIEs.
2917**
2918**  INPUTS:
2919**
2920**      spc_struct      The special structure which is passed to the
2921**                      state machine event evaluation routine.
2922**			This is assumed to be the assoc.
2923**
2924**      event_param     The event specific argument.
2925**
2926**  INPUTS/OUTPUTS:
2927**      sm              The control block from the event
2928**                      evaluation routine.  Input is the current
2929**                      status and event for the control block.
2930**                      Output is the next state or updated
2931**                      current state, for the control block.
2932**
2933**  OUTPUTS:            none
2934**
2935**  IMPLICIT INPUTS:    none
2936**
2937**  IMPLICIT OUTPUTS:   none
2938**
2939**  FUNCTION VALUE:     unsigned32
2940**
2941**  SIDE EFFECTS:       output is printed on stdout.
2942**
2943**--
2944**/
2945PRIVATE unsigned32 rpc__cn_assoc_sm_protocol_error
2946(
2947  dce_pointer_t       spc_struct,
2948  dce_pointer_t       event_param ATTRIBUTE_UNUSED,
2949  dce_pointer_t       sm ATTRIBUTE_UNUSED
2950)
2951{
2952    rpc_cn_assoc_t      *assoc;
2953
2954    assoc = (rpc_cn_assoc_t *) spc_struct;
2955
2956    /*
2957     * "Illegal state transition detected in CN {server|client} association
2958     * state machine [cur_state: %s, cur_event: %s, assoc: %x]"
2959     */
2960    if (assoc->assoc_flags & RPC_C_CN_ASSOC_SERVER)
2961    {
2962        rpc_dce_svc_printf (
2963            __FILE__, __LINE__,
2964            "%s %s %x",
2965            rpc_svc_cn_state,
2966            svc_c_sev_fatal | svc_c_action_abort,
2967            rpc_m_cn_ill_state_trans_sa,
2968            rpc_g_cn_assoc_server_states[assoc->assoc_state.cur_state-RPC_C_CN_STATEBASE],
2969            rpc_g_cn_assoc_server_events[assoc->assoc_state.cur_event-RPC_C_CN_STATEBASE],
2970            assoc );
2971    }
2972    else
2973    {
2974        rpc_dce_svc_printf (
2975            __FILE__, __LINE__,
2976	        "%s %s %x",
2977            rpc_svc_cn_state,
2978            svc_c_sev_fatal | svc_c_action_abort,
2979            rpc_m_cn_ill_state_trans_ca,
2980            rpc_g_cn_assoc_client_states[assoc->assoc_state.cur_state-RPC_C_CN_STATEBASE],
2981            rpc_g_cn_assoc_client_events[assoc->assoc_state.cur_event-RPC_C_CN_STATEBASE],
2982            assoc );
2983    }
2984	/* FIXME: what should be returned ? */
2985	 return 0;
2986}
2987
2988
2989/*
2990**++
2991**
2992**  ROUTINE NAME:       rpc__cn_call_status_to_prej
2993**
2994**  SCOPE:              INTERNAL
2995**
2996**  DESCRIPTION:
2997**
2998**  This routine will translate a local status code into a
2999**  presentation provider bind NACK reason code.
3000**
3001**  INPUTS:
3002**
3003**      st              The local status code.
3004**
3005**  INPUTS/OUTPUTS:     none
3006**
3007**  OUTPUTS:            none
3008**
3009**  IMPLICIT INPUTS:    none
3010**
3011**  IMPLICIT OUTPUTS:   none
3012**
3013**  FUNCTION VALUE:
3014**
3015**      unsigned32      The presentation provider reason code.
3016**
3017**  SIDE EFFECTS:       none
3018**
3019**--
3020**/
3021
3022PRIVATE unsigned32 rpc__cn_assoc_status_to_prej
3023(
3024unsigned32      st
3025)
3026{
3027    switch ((int)st)
3028    {
3029        case rpc_s_assoc_grp_max_exceeded:
3030        case RPC_S_HEADER_FULL:
3031        return (RPC_C_CN_PREJ_LOCAL_LIMIT_EXCEEDED);
3032
3033        case rpc_s_rpc_prot_version_mismatch:
3034        return (RPC_C_CN_PREJ_PROTOCOL_VERSION_NOT_SUPPORTED);
3035
3036        default:
3037        return (RPC_C_CN_PREJ_REASON_NOT_SPECIFIED);
3038    }
3039}
3040
3041
3042/*
3043**++
3044**
3045**  ROUTINE NAME:       rpc__cn_call_prej_to_status
3046**
3047**  SCOPE:              INTERNAL
3048**
3049**  DESCRIPTION:
3050**
3051**  This routine will translate a presentation provider bind NACK
3052**  reason code into a local status code.
3053**
3054**
3055**  INPUTS:
3056**
3057**      prej      The presentation provider reason code.
3058**
3059**  INPUTS/OUTPUTS:     none
3060**
3061**  OUTPUTS:            none
3062**
3063**  IMPLICIT INPUTS:    none
3064**
3065**  IMPLICIT OUTPUTS:   none
3066**
3067**  FUNCTION VALUE:
3068**
3069**      unsigned32      The local status code.
3070**
3071**  SIDE EFFECTS:       none
3072**
3073**--
3074**/
3075
3076PRIVATE unsigned32 rpc__cn_assoc_prej_to_status
3077(
3078unsigned32      prej
3079)
3080{
3081    switch ((int)prej)
3082    {
3083        case RPC_C_CN_PREJ_LOCAL_LIMIT_EXCEEDED:
3084        case RPC_C_CN_PREJ_TEMPORARY_CONGESTION:
3085        return (rpc_s_server_too_busy);
3086
3087        case RPC_C_CN_PREJ_PROTOCOL_VERSION_NOT_SUPPORTED:
3088        return (rpc_s_rpc_prot_version_mismatch);
3089
3090	/* Win 2003 server (and possibly other Microsoft products) return
3091	 * a bind_nak with reject reason 0 (reason not specified) if a second
3092	 * bind session is created to the same named pipe from a different
3093	 * tcp connection.
3094	 *
3095	 * To work around this issue, we treat it like the server rejected the
3096	 * bind because there are too many remote connections. This causes
3097	 * the bind to be retried, or an existing binding is reused when it
3098	 * becomes free (which works for win 2003 server).
3099	 */
3100        case RPC_C_CN_PREJ_REASON_NOT_SPECIFIED:
3101        return (rpc_s_too_many_rem_connects);
3102
3103        case RPC_C_CN_PREJ_AUTH_TYPE_NOT_RECOGNIZED:
3104        return (rpc_s_unknown_authn_service);
3105
3106        case RPC_C_CN_PREJ_INVALID_CHECKSUM:
3107        return (rpc_s_invalid_checksum);
3108
3109        default:
3110        return (rpc_s_unknown_reject);
3111    }
3112}
3113
3114
3115/*
3116**++
3117**
3118**  ROUTINE NAME:       rpc__cn_call_pprov_to_status
3119**
3120**  SCOPE:              INTERNAL
3121**
3122**  DESCRIPTION:
3123**
3124**  This routine will translate a presentation provider bind NACK
3125**  reason code into a local status code.
3126**
3127**
3128**  INPUTS:
3129**
3130**      pprov      The presentation provider reason code.
3131**
3132**  INPUTS/OUTPUTS:     none
3133**
3134**  OUTPUTS:            none
3135**
3136**  IMPLICIT INPUTS:    none
3137**
3138**  IMPLICIT OUTPUTS:   none
3139**
3140**  FUNCTION VALUE:
3141**
3142**      unsigned32      The local status code.
3143**
3144**  SIDE EFFECTS:       none
3145**
3146**--
3147**/
3148
3149PRIVATE unsigned32 rpc__cn_assoc_pprov_to_status
3150(
3151unsigned32      pprov
3152)
3153{
3154    switch ((int)pprov)
3155    {
3156        case RPC_C_CN_PPROV_LOCAL_LIMIT_EXCEEDED:
3157        return (rpc_s_server_too_busy);
3158
3159        case RPC_C_CN_PPROV_PROPOSED_TRANSFER_SYNTAXES_NOT_SUPPORTED:
3160        return (rpc_s_tsyntaxes_unsupported);
3161
3162        case RPC_C_CN_PPROV_ABSTRACT_SYNTAX_NOT_SUPPORTED:
3163        return (rpc_s_unknown_if);
3164
3165        case RPC_C_CN_PPROV_REASON_NOT_SPECIFIED:
3166        default:
3167        return (rpc_s_unknown_reject);
3168    }
3169}
3170
3171
3172/***********************************************************************/
3173/*
3174**++
3175**
3176**  ROUTINE NAME:       rpc__cn_assoc_open
3177**
3178**  SCOPE:              INTERNAL - declared locally
3179**
3180**  DESCRIPTION:
3181**
3182**  This routine will send an association request event through
3183**  the association state machine. This routine will then wait
3184**  until the association request has been accepted. It will
3185**  then allocate the association and record the negotiated
3186**  transfer syntax.
3187**
3188**  INPUTS:
3189**
3190**      assoc           The association.
3191**      call_r          The call rep which will hold the binding and
3192**                      interface reps for the state machine action routines.
3193**      binding_r       The binding rep containing the server address.
3194**      if_r            The interface specification rep containing
3195**                      the abstract syntax and supported
3196**                      transfer syntaxes.
3197**      info            The authentication information structure
3198**                      containing the per-principal-pair security
3199**                      information, NULL if none.
3200**
3201**  INPUTS/OUTPUTS:     none
3202**
3203**  OUTPUTS:
3204**
3205**      syntax          The negotiated transfer syntax.
3206**      context_id      The transfer syntax's context id.
3207**      sec             The negotiated security context element,
3208**                      NULL if none.
3209**      st              The return status of this routine.
3210**                      rpc_s_ok
3211**                      rpc_s_tsyntaxes_unsupported
3212**                      rpc_s_unknown_if
3213**
3214**  IMPLICIT INPUTS:    none
3215**
3216**  IMPLICIT OUTPUTS:   none
3217**
3218**  FUNCTION VALUE:     none
3219**
3220**  SIDE EFFECTS:       none
3221**
3222**--
3223**/
3224
3225INTERNAL void rpc__cn_assoc_open
3226(
3227  rpc_cn_assoc_p_t        assoc,
3228  rpc_addr_p_t            rpc_addr,
3229  rpc_if_rep_p_t          if_r,
3230  rpc_cn_local_id_t       grp_id,
3231  rpc_auth_info_p_t       auth_info,
3232  rpc_transport_info_p_t  transport_info,
3233  rpc_transfer_syntax_t   *syntax,
3234  unsigned16              *context_id,
3235  rpc_cn_sec_context_p_t  *sec,
3236  unsigned32              *st
3237)
3238{
3239    rpc_cn_syntax_t             *pres_context;
3240    rpc_cn_sec_context_t        *sec_context;
3241    rpc_cn_fragbuf_t            *fragbuf;
3242    rpc_cn_assoc_sm_work_t      assoc_sm_work;
3243
3244    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_open);
3245    CODING_ERROR (st);
3246
3247    /*
3248     * Init the work structure needed by the action routine.
3249     */
3250    memset (&assoc_sm_work, 0, sizeof (rpc_cn_assoc_sm_work_t));
3251
3252    /*
3253     * Allocate and init a presentation context element and add it
3254     * to the tail of the association presentation context element
3255     * list. Also, put a pointer to it in the state machine work structure.
3256     */
3257    pres_context = rpc__cn_assoc_syntax_alloc (if_r, st);
3258    if (*st != rpc_s_ok)
3259    {
3260        return;
3261    }
3262    RPC_LIST_ADD_TAIL (assoc->syntax_list, pres_context, rpc_cn_syntax_p_t);
3263    assoc_sm_work.pres_context = pres_context;
3264
3265    /*
3266     * Determine whether security is required for the RPC being
3267     * executed.
3268     */
3269    if (RPC_CN_AUTH_REQUIRED (auth_info))
3270    {
3271        /*
3272         * Allocate and init a security context element and add it
3273         * to the tail of the association security context element
3274         * list. Also, put a pointer to it in the state machine work structure.
3275         */
3276        sec_context = rpc__cn_assoc_sec_alloc (auth_info, st);
3277        assert(sec_context != NULL);
3278        if (*st != rpc_s_ok)
3279        {
3280            RPC_LIST_REMOVE (assoc->syntax_list, pres_context);
3281            rpc__cn_assoc_syntax_free (&pres_context);
3282            return;
3283        }
3284        RPC_LIST_ADD_TAIL (assoc->security.context_list, sec_context, rpc_cn_sec_context_p_t);
3285        assoc_sm_work.sec_context = sec_context;
3286    }
3287    else
3288    {
3289        sec_context = NULL;
3290    }
3291
3292    /*
3293     * Set the association group ID in the state machine work
3294     * structure.
3295     */
3296    assoc_sm_work.grp_id = grp_id.all;
3297
3298    /*
3299     * Record the address to which the connection is being made in
3300     * the association.
3301     */
3302
3303    /*
3304     *  Here is another one of those marvelous chances for the rpc_addr to
3305     *  become a dangling reference.  We make sure that this association
3306     *  has it's own rpc_addr memory.
3307    */
3308    {
3309        rpc_addr_p_t    rpc_addr1;
3310
3311        rpc__naf_addr_copy(rpc_addr, &rpc_addr1, st);
3312
3313        if ( *st != rpc_s_ok )
3314            return;
3315
3316        assoc->cn_ctlblk.rpc_addr = rpc_addr1;
3317    }
3318
3319    assoc->transport_info = transport_info;
3320
3321    if (transport_info)
3322    {
3323        rpc__transport_info_retain(transport_info);
3324    }
3325
3326    /*
3327     * This seems redundant, but we need this structure in the association
3328     * in case we have to retry the bind due to protocol version mismatch.
3329     */
3330    assoc->assoc_sm_work = &assoc_sm_work;
3331
3332    /*
3333     * Send an association request through the association state
3334     * machine. This will create a transport connection and return
3335     * an association in the open state with the transport syntax
3336     * and optional security context negotiated.
3337     */
3338    RPC_CN_ASSOC_EVAL_USER_EVENT (assoc,
3339                                  RPC_C_ASSOC_REQ,
3340                                  &assoc_sm_work,
3341                                  *st);
3342
3343#ifdef DEBUG
3344    if (RPC_DBG_EXACT(rpc_es_dbg_cn_errors, RPC_C_CN_DBG_ASSOC_REQ_FAIL))
3345    {
3346        assoc->assoc_status = RPC_S_CN_DBG_FAILURE;
3347    }
3348#endif
3349
3350    RPC_DBG_PRINTF (rpc_es_dbg_general, RPC_C_CN_DBG_GENERAL,
3351	    ("(%s) RPC_CN_ASSOC_EVAL_USER_EVENT(.., RPC_C_ASSOC_REQ,...) returned %#08x, %#08x\n",
3352		 __func__, assoc->assoc_status, *st));
3353
3354    *st = assoc->assoc_status;
3355    if (*st != rpc_s_ok)
3356    {
3357        RPC_LIST_REMOVE (assoc->syntax_list, pres_context);
3358        rpc__cn_assoc_syntax_free (&pres_context);
3359        if (RPC_CN_AUTH_REQUIRED (auth_info))
3360        {
3361            RPC_LIST_REMOVE (assoc->security.context_list, sec_context);
3362            rpc__cn_assoc_sec_free (&sec_context);
3363        }
3364        return;
3365    }
3366
3367    /*
3368     * Wait for both presentation and optional security context
3369     * negotiations to complete either successfully or with an error.
3370     */
3371    while (!(pres_context->syntax_valid)
3372           ||
3373           (RPC_CN_AUTH_REQUIRED (auth_info) && (sec_context->sec_state != RPC_C_SEC_STATE_COMPLETE)))
3374    {
3375        rpc__cn_assoc_receive_frag (assoc, &fragbuf, st);
3376        if (*st != rpc_s_ok)
3377        {
3378            return;
3379        }
3380
3381        /*
3382         * If either the presentation or security negotiations
3383         * complete with an error return.
3384         */
3385        if (pres_context->syntax_status != rpc_s_ok)
3386        {
3387            *st = pres_context->syntax_status;
3388            return;
3389        }
3390        if (RPC_CN_AUTH_REQUIRED (auth_info) && (sec_context->sec_status != rpc_s_ok))
3391        {
3392            *st = sec_context->sec_status;
3393            return;
3394        }
3395        if (RPC_CN_AUTH_REQUIRED (auth_info) && (sec_context->sec_state == RPC_C_SEC_STATE_INCOMPLETE))
3396        {
3397            RPC_CN_ASSOC_EVAL_USER_EVENT (assoc,
3398                                          RPC_C_ASSOC_ALTER_CONTEXT_REQ,
3399                                          &assoc_sm_work,
3400                                          *st);
3401        }
3402    }
3403
3404    /*
3405     * The negotiations have completed. Copy out the results. Note
3406     * that the presentation syntax UUID is not copied. The client
3407     * stub does not require it.
3408     */
3409    *sec = sec_context;
3410    syntax->index = pres_context->syntax_vector_index;
3411    syntax->convert_epv = pres_context->syntax_epv;
3412    *context_id = pres_context->syntax_pres_id;
3413
3414    /*
3415     * Mark the call_rep PDU header with the negotiated minor
3416     * version number.
3417     */
3418    RPC_CN_PKT_VERS_MINOR ((rpc_cn_packet_p_t)
3419        RPC_CN_CREP_SEND_HDR (assoc->call_rep)) = assoc->assoc_vers_minor;
3420
3421    *st = rpc_s_ok;
3422}
3423
3424
3425/***********************************************************************/
3426/*
3427**++
3428**
3429**  ROUTINE NAME:       rpc__cn_assoc_alter_context
3430**
3431**  SCOPE:              INTERNAL - declared locally
3432**
3433**  DESCRIPTION:
3434**
3435**  This routine will either locate a previously established or
3436**  estblish a new presentation and optional security context for the
3437**  current RPC.
3438**
3439**  INPUTS:
3440**
3441**      assoc           The association.
3442**      if_r            The interface specification rep containing
3443**                      the abstract syntax and supported
3444**                      transfer syntaxes.
3445**      info            The authentication information structure
3446**                      containing the per-principal-pair security
3447**                      information, NULL if none.
3448**
3449**  INPUTS/OUTPUTS:     none
3450**
3451**  OUTPUTS:
3452**
3453**      syntax          The negotiated transfer syntax.
3454**      context_id      The transfer syntax's context id.
3455**      sec             The negotiated security context element,
3456**                      NULL if none.
3457**      st              The return status of this routine.
3458**                      rpc_s_ok
3459**
3460**  IMPLICIT INPUTS:    none
3461**
3462**  IMPLICIT OUTPUTS:   none
3463**
3464**  FUNCTION VALUE:     none
3465**
3466**  SIDE EFFECTS:       none
3467**
3468**--
3469**/
3470
3471INTERNAL void rpc__cn_assoc_alter_context
3472(
3473rpc_cn_assoc_p_t        assoc,
3474rpc_if_rep_p_t          if_r,
3475rpc_auth_info_p_t       info,
3476rpc_transfer_syntax_t   *syntax,
3477unsigned16              *context_id,
3478rpc_cn_sec_context_p_t  *sec,
3479unsigned32              *st
3480)
3481{
3482    rpc_cn_syntax_t             *pres_context;
3483    rpc_cn_sec_context_t        *sec_context;
3484    rpc_cn_fragbuf_t            *fragbuf;
3485    rpc_cn_assoc_sm_work_t      assoc_sm_work;
3486    boolean                     pres_context_setup;
3487    boolean                     sec_context_setup = false;
3488    boolean32                   sec_cred_changed = false;
3489    rpc_cn_assoc_grp_t          * volatile assoc_grp = NULL;
3490
3491    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_alter_context);
3492    CODING_ERROR (st);
3493
3494    /*
3495     * Clear local booleans to indicate whether a presentation context and
3496     * optional security context are set up.
3497     */
3498    pres_context_setup = false;
3499
3500    /*
3501     * Scan all previously negotiated presentation contexts.
3502     */
3503    RPC_LIST_FIRST (assoc->syntax_list, pres_context, rpc_cn_syntax_p_t);
3504    while (pres_context != NULL)
3505    {
3506        /*
3507         * If the interface UUID and version in the input argument
3508         * ifspec match the presentation context abstract UUID and
3509         * version this presentation context can be use for the
3510         * current RPC.
3511         */
3512#if (uuid_c_version == 1)
3513        if ((memcmp (&pres_context->syntax_abstract_id.id,
3514                     &if_r->id,
3515                     sizeof (idl_uuid_t)) == 0)
3516#else
3517***Make sure memcmp works on this version of UUIDs***
3518#endif
3519            &&
3520            (pres_context->syntax_abstract_id.version == if_r->vers))
3521        {
3522            /*
3523             * Handle the case where a previous negotiation was
3524             * orphaned and failed with a presentation provider reject
3525             * (an rpc_bind_ack or rpc_alter_context_response was returned).
3526             */
3527            if (pres_context->syntax_status != rpc_s_ok)
3528            {
3529                *st = pres_context->syntax_status;
3530                return;
3531            }
3532            pres_context_setup = true;
3533            break;
3534        }
3535        RPC_LIST_NEXT (pres_context, pres_context, rpc_cn_syntax_p_t);
3536    }
3537
3538    /*
3539     * Determine whether the current RPC requires security.
3540     */
3541    if (RPC_CN_AUTH_REQUIRED (info))
3542    {
3543	RPC_DBG_PRINTF (rpc_e_dbg_auth, RPC_C_CN_DBG_GENERAL,
3544		("(%s) auth required principal=%s level=%u protocol=%u\n",
3545		 __func__, info->server_princ_name,
3546		 info->authn_level, info->authn_protocol));
3547        /*
3548         * Scan all previously negotiated security contexts.
3549         */
3550        RPC_LIST_FIRST (assoc->security.context_list, sec_context, rpc_cn_sec_context_p_t);
3551        while (sec_context != NULL)
3552        {
3553            /*
3554             * If the auth info passed in equals the auth info in
3555             * the security context element this security context can
3556             * be use for the current RPC.
3557             */
3558            if (info == sec_context->sec_info)
3559            {
3560                /*
3561                 * This security context element matches the auth
3562                 * info we're looking for, which means the client and
3563                 * server principal IDs as well as the authn protocol
3564                 * match. We'll at least reuse the memory for this
3565                 * structure even if we have to send an
3566                 * rpc_alter_context PDU to update it.
3567                 */
3568
3569                /*
3570                 * Determine whether the credentials have been
3571                 * refreshed since this security context was set up.
3572                 * If so, we'll have to send an rpc_alter_context PDU
3573                 * to update the security context with the new
3574                 * credentials.
3575                 */
3576                sec_cred_changed = RPC_CN_AUTH_CRED_CHANGED (sec_context, st);
3577                break;
3578            }
3579            RPC_LIST_NEXT (sec_context, sec_context, rpc_cn_sec_context_p_t);
3580        }
3581    }
3582    else
3583    {
3584        sec_context = NULL;
3585    }
3586
3587    /*
3588     * Determine whether either a presentation or security
3589     * context negotiation has to occur.
3590     */
3591    if ((!pres_context_setup)
3592        ||
3593        (RPC_CN_AUTH_REQUIRED (info) && (sec_context == NULL))
3594        ||
3595        (RPC_CN_AUTH_REQUIRED (info) && (sec_cred_changed)))
3596    {
3597        /*
3598         * Init the work structure needed by the action routine.
3599         */
3600        memset (&assoc_sm_work, 0, sizeof (rpc_cn_assoc_sm_work_t));
3601
3602        if (!pres_context_setup)
3603        {
3604            /*
3605             * We didn't find a presentation context element on
3606             * the association for the current RPC. Allocate and
3607             * init a presentation context element and add it
3608             * to the tail of the association presentation context element
3609             * list. Also, put a pointer to it in the state machine work structure.
3610             */
3611            pres_context = rpc__cn_assoc_syntax_alloc (if_r, st);
3612            if (*st != rpc_s_ok)
3613            {
3614                return;
3615            }
3616            RPC_LIST_ADD_TAIL (assoc->syntax_list, pres_context, rpc_cn_syntax_p_t);
3617            assoc_sm_work.pres_context = pres_context;
3618        }
3619        else
3620        {
3621            /* MSRPC seems to expect a context negotiation even if we aren't
3622               changing the presentation context, so just send what we already
3623               have */
3624            assoc_sm_work.pres_context = pres_context;
3625            assoc_sm_work.reuse_context = TRUE;
3626        }
3627
3628
3629        /*
3630         * If authentication is required on this call, we may have
3631         * to send an rpc_alter_context PDU. The only time one doesn't
3632         * have to be sent is when a security context has been
3633         * established which has valid credentials and has been
3634         * successfully established previously.
3635         */
3636        if (RPC_CN_AUTH_REQUIRED (info))
3637        {
3638            /*
3639             * If the security context pointer is NULL we didn't
3640             * find a match above. This means we need to allocate
3641             * memory for a new security context element and send an
3642             * rpc_alter_context PDU to set it up.
3643             */
3644            if (sec_context == NULL)
3645            {
3646                /*
3647                 * Allocate and init a security context element and add it
3648                 * to the tail of the association security context element
3649                 * list. Also, put a pointer to it in the state machine work structure.
3650                 */
3651                sec_context = rpc__cn_assoc_sec_alloc (info, st);
3652                if (*st != rpc_s_ok)
3653                {
3654                    if (!pres_context_setup)
3655                    {
3656                        RPC_LIST_REMOVE (assoc->syntax_list, pres_context);
3657                        rpc__cn_assoc_syntax_free (&pres_context);
3658                    }
3659                    return;
3660                }
3661                sec_context_setup = false;
3662                RPC_LIST_ADD_TAIL (assoc->security.context_list, sec_context, rpc_cn_sec_context_p_t);
3663                assoc_sm_work.sec_context = sec_context;
3664            }
3665            else
3666            {
3667                sec_context_setup = true;
3668            }
3669
3670            /*
3671             * The indication that a previous security context setup
3672             * has failed is when the status code is not rpc_s_ok in
3673             * it. This condition, or a credential change, means that
3674             * an rpc_alter_context PDU should be sent to update the
3675             * existing security context.
3676             */
3677            if ((sec_context->sec_status != rpc_s_ok)
3678                ||
3679                sec_cred_changed)
3680            {
3681                assoc_sm_work.sec_context = sec_context;
3682            }
3683        }
3684
3685        assoc_grp = RPC_CN_ASSOC_GRP(assoc->assoc_grp_id);
3686        assoc_sm_work.grp_id = assoc_grp->grp_remid.all;
3687
3688        /*
3689         * Evaluate an alter_context event through the client
3690         * association state machine. This will result in an
3691         * alter_context PDU being transmitted to the server.
3692         */
3693        RPC_CN_ASSOC_EVAL_USER_EVENT (assoc,
3694                                      RPC_C_ASSOC_ALTER_CONTEXT_REQ,
3695                                      &assoc_sm_work,
3696                                      *st);
3697        *st = assoc->assoc_status;
3698        if (*st != rpc_s_ok)
3699        {
3700            if (!pres_context_setup)
3701            {
3702                RPC_LIST_REMOVE (assoc->syntax_list, pres_context);
3703                rpc__cn_assoc_syntax_free (&pres_context);
3704            }
3705
3706            if (RPC_CN_AUTH_REQUIRED (info) && (!sec_context_setup))
3707            {
3708                assert (sec_context != NULL);
3709                RPC_LIST_REMOVE (assoc->security.context_list, sec_context);
3710                rpc__cn_assoc_sec_free (&sec_context);
3711            }
3712            return;
3713        }
3714
3715    }
3716
3717    /*
3718     * If we need authentication, then we must have a security context by now.
3719     */
3720    if (RPC_CN_AUTH_REQUIRED (info)) {
3721        assert (RPC_CN_AUTH_REQUIRED (info) && sec_context != NULL);
3722    }
3723
3724    /*
3725     * Wait for both presentation and optional security context
3726     * negotiations to complete either successfully or with an error.
3727     */
3728    while (!(pres_context->syntax_valid)
3729           ||
3730           (RPC_CN_AUTH_REQUIRED (info) && (sec_context->sec_state != RPC_C_SEC_STATE_COMPLETE)))
3731    {
3732        rpc__cn_assoc_receive_frag (assoc, &fragbuf, st);
3733        if (*st != rpc_s_ok)
3734        {
3735            return;
3736        }
3737        /*
3738         * If either the presentation or security negotiations
3739         * complete with an error return.
3740         */
3741        if (pres_context->syntax_status != rpc_s_ok)
3742        {
3743            *st = pres_context->syntax_status;
3744            return;
3745        }
3746        if (RPC_CN_AUTH_REQUIRED (info) && (sec_context->sec_status != rpc_s_ok))
3747        {
3748            *st = sec_context->sec_status;
3749            return;
3750        }
3751    }
3752
3753    /*
3754     * The negotiations have completed. Copy out the results. Note
3755     * that the presentation syntax UUID is not copied. The client
3756     * stub does not require it.
3757     */
3758    *sec = sec_context;
3759    syntax->index = pres_context->syntax_vector_index;
3760    syntax->convert_epv = pres_context->syntax_epv;
3761    *context_id = pres_context->syntax_pres_id;
3762    *st = rpc_s_ok;
3763}
3764
3765
3766/***********************************************************************/
3767/*
3768**++
3769**
3770**  ROUTINE NAME:       rpc__cn_assoc_sec_alloc
3771**
3772**  SCOPE:              PRIVATE - declared in cnassoc.h
3773**
3774**  DESCRIPTION:
3775**
3776**  This routine will allocate and intialize a security context element.
3777**
3778**  INPUTS:
3779**
3780**      info            The per-principal-pair security information.
3781**
3782**  INPUTS/OUTPUTS:     none
3783**
3784**  OUTPUTS:
3785**
3786**      st              The return status of this routine.
3787**                      rpc_s_ok
3788**
3789**  IMPLICIT INPUTS:    none
3790**
3791**  IMPLICIT OUTPUTS:   none
3792**
3793**  FUNCTION VALUE:     none
3794**
3795**  SIDE EFFECTS:       none
3796**
3797**--
3798**/
3799
3800PRIVATE rpc_cn_sec_context_t *rpc__cn_assoc_sec_alloc
3801(
3802  rpc_auth_info_p_t       info,
3803  unsigned32              *st
3804)
3805{
3806    rpc_cn_sec_context_t        *sec_context;
3807    rpc_cn_auth_info_t          *cn_info;
3808
3809#ifdef DEBUG
3810    if (RPC_DBG_EXACT(rpc_es_dbg_cn_errors, RPC_C_CN_DBG_SEC_ALLOC_FAIL))
3811    {
3812        *st = RPC_S_CN_DBG_FAILURE;
3813        return (NULL);
3814    }
3815#endif
3816
3817    /*
3818     * Allocate a CN specific per-principal-pair security
3819     * information structure.
3820     */
3821    RPC_CN_AUTH_GET_PROT_INFO (info, &cn_info, st);
3822    if (*st != rpc_s_ok)
3823    {
3824        if (info->is_server)
3825        {
3826            dce_error_string_t error_text;
3827            int temp_status;
3828
3829            dce_error_inq_text(*st, error_text, &temp_status);
3830
3831            /*
3832             * rpc_m_call_failed_s
3833             * "%s on server failed: %s"
3834             */
3835            rpc_dce_svc_printf (
3836                __FILE__, __LINE__,
3837                "%s %x",
3838                rpc_svc_auth,
3839                svc_c_sev_error,
3840                rpc_m_call_failed_s,
3841                "RPC_CN_AUTH_GET_PROT_INFO",
3842                error_text );
3843        }
3844        return (NULL);
3845    }
3846    cn_info->cn_epv = RPC_CN_AUTH_PROT_EPV (info->authn_protocol);
3847
3848    /*
3849     * Allocate a security context element and init it.
3850     */
3851    sec_context = (rpc_cn_sec_context_t *)
3852        rpc__list_element_alloc (&rpc_g_cn_sec_lookaside_list, true);
3853    if (sec_context == NULL) {
3854        *st = rpc_s_no_memory;
3855        return NULL;
3856    }
3857    sec_context->sec_state = RPC_C_SEC_STATE_INVALID;
3858    sec_context->sec_status = rpc_s_ok;
3859    sec_context->sec_info = info;
3860    sec_context->sec_cn_info = cn_info;
3861
3862    /*
3863     * Note that the credentials themselves in the auth_info
3864     * structure were already checked for expiration in
3865     * rpc__cn_call_start() on the client side. It therefore isn't
3866     * necessary to do any more checking here since they were either
3867     * refreshed or an error was returned back in call_start.
3868     *
3869     * On the server, the client has not been authenticated yet.
3870     * This security context may therefore be invalid.
3871     *
3872     * Add a reference to the auth information structure since a
3873     * pointer to it is being kept in the security context element.
3874     */
3875    RPC_CN_AUTH_ADD_REFERENCE (info);
3876    return (sec_context);
3877}
3878
3879
3880/***********************************************************************/
3881/*
3882**++
3883**
3884**  ROUTINE NAME:       rpc__cn_assoc_sec_free
3885**
3886**  SCOPE:              PRIVATE - declared in cnassoc.h
3887**
3888**  DESCRIPTION:
3889**
3890**  This routine will free a security context element,
3891**  dereference the per-principal-pair security information, and free
3892**  the CN specific per-principal-pair security information.
3893**
3894**  INPUTS:             none
3895**
3896**  INPUTS/OUTPUTS:
3897**
3898**      sec             The security context element, NULL on output.
3899**
3900**  OUTPUTS:            none
3901**
3902**  IMPLICIT INPUTS:    none
3903**
3904**  IMPLICIT OUTPUTS:   none
3905**
3906**  FUNCTION VALUE:     none
3907**
3908**  SIDE EFFECTS:       none
3909**
3910**--
3911**/
3912
3913PRIVATE void rpc__cn_assoc_sec_free
3914(
3915  rpc_cn_sec_context_p_t  *sec
3916)
3917{
3918    /*
3919     * Free the CN specific per-principal-pair security
3920     * information structure.
3921     */
3922    RPC_CN_AUTH_FREE_PROT_INFO ((*sec)->sec_info, &(*sec)->sec_cn_info);
3923
3924    /*
3925     * Remove the reference to the auth information structure.
3926     */
3927    RPC_CN_AUTH_RELEASE_REFERENCE ((rpc_auth_info_p_t *) &(*sec)->sec_info);
3928
3929    /*
3930     * Free the security context element.
3931     */
3932    rpc__list_element_free (&rpc_g_cn_sec_lookaside_list,
3933                            (dce_pointer_t) (*sec));
3934
3935    *sec = NULL;
3936}
3937
3938
3939/***********************************************************************/
3940/*
3941**++
3942**
3943**  ROUTINE NAME:       rpc__cn_assoc_syntax_alloc
3944**
3945**  SCOPE:              INTERNAL - declared locally
3946**
3947**  DESCRIPTION:
3948**
3949**  This routine will allocate and intialize a presentation context element.
3950**
3951**  INPUTS:
3952**
3953**      if_r            The interface spec.
3954**
3955**  INPUTS/OUTPUTS:     none
3956**
3957**  OUTPUTS:
3958**
3959**      st              The return status of this routine.
3960**                      rpc_s_ok
3961**
3962**  IMPLICIT INPUTS:    none
3963**
3964**  IMPLICIT OUTPUTS:   none
3965**
3966**  FUNCTION VALUE:     none
3967**
3968**  SIDE EFFECTS:       none
3969**
3970**--
3971**/
3972
3973INTERNAL rpc_cn_syntax_t *rpc__cn_assoc_syntax_alloc
3974(
3975  rpc_if_rep_p_t          if_r,
3976  unsigned32              *st
3977)
3978{
3979    rpc_cn_syntax_t             *pres_context;
3980
3981    pres_context =
3982        (rpc_cn_syntax_t *)rpc__list_element_alloc (&rpc_g_cn_syntax_lookaside_list,
3983                                                 true);
3984    if (pres_context == NULL) {
3985        *st = rpc_s_no_memory;
3986        return NULL;
3987    }
3988    pres_context->syntax_valid = false;
3989    pres_context->syntax_status = rpc_s_ok;
3990    pres_context->syntax_abstract_id.id = if_r->id;
3991    pres_context->syntax_abstract_id.version = if_r->vers;
3992    pres_context->syntax_vector = &if_r->syntax_vector;
3993    pres_context->syntax_epv = NULL;
3994    *st = rpc_s_ok;
3995    return (pres_context);
3996}
3997
3998
3999/***********************************************************************/
4000/*
4001**++
4002**
4003**  ROUTINE NAME:       rpc__cn_assoc_syntax_free
4004**
4005**  SCOPE:              PRIVATE - declated in cnassoc.h
4006**
4007**  DESCRIPTION:
4008**
4009**  This routine will free a presentation context element.
4010**
4011**  INPUTS:             none
4012**
4013**  INPUTS/OUTPUTS:
4014**
4015**      syntax          The presentation context element, NULL on output.
4016**
4017**  OUTPUTS:            none
4018**
4019**  IMPLICIT INPUTS:    none
4020**
4021**  IMPLICIT OUTPUTS:   none
4022**
4023**  FUNCTION VALUE:     none
4024**
4025**  SIDE EFFECTS:       none
4026**
4027**--
4028**/
4029
4030PRIVATE void rpc__cn_assoc_syntax_free
4031(
4032  rpc_cn_syntax_p_t       *syntax
4033)
4034{
4035    /*
4036     * Free the presentation context element.
4037     */
4038    rpc__list_element_free (&rpc_g_cn_syntax_lookaside_list,
4039                            (dce_pointer_t) *syntax);
4040    *syntax = NULL;
4041}
4042
4043
4044/******************************************************************************/
4045/*
4046**++
4047**
4048**  ROUTINE NAME:       rpc__cn_assoc_timer_reclaim
4049**
4050**  SCOPE:              INTERNAL - declared locally
4051**
4052**  DESCRIPTION:
4053**
4054**  This routine is called at timed intervals to close
4055**  associations which have been inactive.
4056**
4057**  INPUTS:
4058**
4059**      type            The type of associations to reclaim.
4060**
4061**  INPUTS/OUTPUTS:     none
4062**
4063**  OUTPUTS:            none
4064**
4065**  IMPLICIT INPUTS:    none
4066**
4067**  IMPLICIT OUTPUTS:   none
4068**
4069**  FUNCTION VALUE:     none
4070**
4071**  SIDE EFFECTS:       none
4072**
4073**--
4074**/
4075
4076INTERNAL void rpc__cn_assoc_timer_reclaim
4077(
4078 unsigned32       type
4079)
4080{
4081    rpc_cn_local_id_t   grp_id;
4082
4083    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_timer_reclaim);
4084
4085    /*
4086     * Reclaim associations of the given type. Provide an invalid
4087     * group id so that no group is off limits to the policy.
4088     */
4089    RPC_CN_LOCAL_ID_CLEAR (grp_id);
4090    RPC_CN_LOCK ();
4091    rpc__cn_assoc_reclaim (grp_id, type, false);
4092    RPC_CN_UNLOCK ();
4093}
4094
4095
4096/******************************************************************************/
4097/*
4098**++
4099**
4100**  ROUTINE NAME:       rpc__cn_assoc_reclaim
4101**
4102**  SCOPE:              INTERNAL - declared locally
4103**
4104**  DESCRIPTION:
4105**
4106**  This routine is called to invoke the local policy algorithm
4107**  to determine which associations/connections should be closed.
4108**
4109**  INPUTS:
4110**
4111**      grp_id          The association group id over which an open
4112**                      association is needed.
4113**      type            The type of associations to be reclaimed.
4114**
4115**      loop            If loop is false, we will stop after finding
4116**                      the first association to shut down.
4117**
4118**  INPUTS/OUTPUTS:     none
4119**
4120**  OUTPUTS:            none
4121**
4122**  IMPLICIT INPUTS:    none
4123**
4124**  IMPLICIT OUTPUTS:   none
4125**
4126**  FUNCTION VALUE:     none
4127**
4128**  SIDE EFFECTS:       none
4129**
4130**--
4131**/
4132
4133INTERNAL void rpc__cn_assoc_reclaim
4134(
4135  rpc_cn_local_id_t grp_id,
4136  unsigned32 type,
4137  boolean32 loop
4138)
4139{
4140    unsigned32          i;
4141    boolean		shutdown_or_abort = false;
4142    rpc_cn_assoc_t      *assoc;
4143    unsigned32          st;
4144
4145    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_reclaim);
4146
4147    /*
4148     * Check whether there are any active groups.
4149     */
4150    if (rpc_g_cn_assoc_grp_tbl.grp_active_count != 0)
4151    {
4152        /*
4153         * Scan all the association groups in the group table.
4154         */
4155        for (i = 0;
4156             i < rpc_g_cn_assoc_grp_tbl.grp_count;
4157             i++)
4158        {
4159            /*
4160             * Check whether the group id given matches, the group is active
4161             * and of the right type.  Also, check if there is any active
4162             * context handle between a client and server (i.e. the association
4163             * will be allowed to shutdown if the group reference count
4164             * is zero or there is more than one association on the group).
4165             * Note that for future enhancement, we should implement the
4166             * checking on the activeness of the context handle as a predicate
4167             * through server association FSM.
4168             */
4169	    if ((!RPC_CN_LOCAL_ID_EQUAL
4170		(rpc_g_cn_assoc_grp_tbl.assoc_grp_vector[i].grp_id, grp_id))
4171		&&
4172		(rpc_g_cn_assoc_grp_tbl.assoc_grp_vector[i].grp_flags & type)
4173		&&
4174		(rpc_g_cn_assoc_grp_tbl.assoc_grp_vector[i].grp_state.cur_state
4175		 == RPC_C_ASSOC_GRP_ACTIVE)
4176		&&
4177		(rpc_g_cn_assoc_grp_tbl.assoc_grp_vector[i].grp_refcnt == 0
4178		 ||
4179		 rpc_g_cn_assoc_grp_tbl.assoc_grp_vector[i].grp_cur_assoc > 1)
4180		)
4181	    {
4182                /*
4183                 * The group id doesn't match and the group is of the
4184                 * correct type and is active. Scan the associations on its
4185                 * list.
4186                 */
4187                RPC_LIST_FIRST
4188		    (rpc_g_cn_assoc_grp_tbl.assoc_grp_vector[i].grp_assoc_list,
4189                    assoc,
4190                    rpc_cn_assoc_p_t);
4191                while (assoc != NULL)
4192                {
4193                    /*
4194                     * Check whether the association is free for
4195                     * reclaimation.
4196                     */
4197                    if (assoc->assoc_ref_count == 0)
4198                    {
4199                       /*
4200                         * Increment the association reference count so
4201                         * that this association won't be deallocated by
4202                         * the receiver thread when we try to send the
4203                         * shutdown request.
4204                         */
4205                        RPC_CN_ASSOC_ACB_INC_REF(assoc);
4206
4207                        /*
4208                         * This association has no active references.
4209                         */
4210                        if (assoc->assoc_flags & RPC_C_CN_ASSOC_SCANNED)
4211                        {
4212                            /*
4213                             * The association has been scanned previsouly.
4214                             * Check the shutdown request count to see if
4215                             * it reached the maximum allowed
4216                             */
4217                            if (0 /* Windows RPC runtime never sends shutdowns */ &&
4218                                assoc->assoc_shutdown_req_count <=
4219                                RPC_C_CN_ASSOC_SERVER_MAX_SHUTDOWN_REQ_COUNT)
4220                            {
4221                                /*
4222                                 * Haven't reached the maximum shutdown
4223                                 * request count, send an additional shutdown
4224                                 * message to the client.  We do this by sending
4225                                 * a shutdown request through its state machine
4226                                 * and increase the shutdown request count.
4227                                 */
4228                                RPC_CN_ASSOC_EVAL_USER_EVENT (assoc,
4229                                                              RPC_C_ASSOC_SHUTDOWN_REQ,
4230                                                              NULL,
4231                                                              st);
4232                                assoc->assoc_shutdown_req_count++ ;
4233				shutdown_or_abort = true;
4234                            }
4235                            else
4236                            {
4237                                /*
4238                                 * Architecture spec requires that a client
4239                                 * responds to a shutdown message.  If we get
4240                                 * no response from repeated shutdowns, we
4241                                 * assume that the client is not working
4242                                 * properly and abort the association.
4243                                 *
4244                                 * We have sent the client the maximum number
4245                                 * of shutdown requests.  The client has not
4246                                 * initiated an orderly shutdown process.  The
4247                                 * client might be hung.  It's time to abort
4248                                 * the association!
4249                                 */
4250                                rpc__cn_assoc_abort (assoc, &st);
4251				shutdown_or_abort = true;
4252                            }
4253                        }
4254                        else
4255                        {
4256                            /*
4257                             * The association has no active
4258                             * references but also was not previously
4259                             * scanned. Mark it as scanned now.
4260                             */
4261                            assoc->assoc_flags |= RPC_C_CN_ASSOC_SCANNED;
4262                        }
4263
4264                        /*
4265                         * Done with the shutdown attempt, so decrement the
4266                         * reference count. This is done via the acb dealloc
4267                         * routine.
4268                         */
4269                        rpc__cn_assoc_acb_dealloc (assoc);
4270                    }
4271		    if (loop == false && shutdown_or_abort == true)
4272			return;
4273                    RPC_LIST_NEXT (assoc, assoc, rpc_cn_assoc_p_t);
4274                } /* end while (assoc != NULL) */
4275            } /* end if ((!RPC_CN_LOCAL_ID (...)) */
4276        } /* end for (i = 0; ... ) */
4277    }
4278}
4279
4280
4281/***********************************************************************/
4282/*
4283**++
4284**
4285**  ROUTINE NAME:       rpc__cn_assoc_acb_alloc
4286**
4287**  SCOPE:              INTERNAL - declared locally
4288**
4289**  DESCRIPTION:
4290**
4291**  This routine will create and initialize, if needed, an
4292**  association control block by allocating one off the
4293**  association lookaside list.
4294**
4295**  INPUTS:
4296**
4297**      wait            A boolean indicating whether this routine is
4298**                      allowed to block waiting for memory if necessary.
4299**      type            The type of association requested (client or server).
4300**
4301**  INPUTS/OUTPUTS:     none
4302**
4303**  OUTPUTS:
4304**
4305**      st              The return status of this routine.
4306**                      rpc_s_ok
4307**
4308**  IMPLICIT INPUTS:    none
4309**
4310**  IMPLICIT OUTPUTS:   none
4311**
4312**  FUNCTION VALUE:
4313**
4314**      assoc           The initialized association.
4315**
4316**  SIDE EFFECTS:       none
4317**
4318**--
4319**/
4320
4321INTERNAL rpc_cn_assoc_t *rpc__cn_assoc_acb_alloc
4322(
4323    boolean32       wait,
4324    unsigned32      type,
4325    unsigned32      *st
4326)
4327{
4328    rpc_cn_assoc_t      *assoc;
4329
4330    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_acb_alloc);
4331    CODING_ERROR(st);
4332
4333    /*
4334     * Allocate an association control block. The returned block
4335     * will have a receiver thread assigned to it which will be
4336     * blocked on a the connection condition variable contained in the
4337     * association. Once a connection has been established this
4338     * condition variable will be set and the receiver thread will
4339     * begin waiting for data on the connection.
4340     */
4341    assoc = (rpc_cn_assoc_t *)
4342        rpc__list_element_alloc (&rpc_g_cn_assoc_lookaside_list, wait);
4343    if (assoc == NULL) {
4344        *st = rpc_s_no_memory;
4345        return (NULL);
4346    }
4347
4348    assoc->cn_ctlblk.rpc_addr = NULL;
4349
4350    /*
4351     * Find out what type of association is being created and
4352     * initialize the state tables in the association accordingly.
4353     */
4354    if (type == RPC_C_CN_ASSOC_CLIENT)
4355    {
4356        /*
4357         * Initialize the association with the client tables.
4358         */
4359        rpc__cn_sm_init (rpc_g_cn_client_assoc_sm,
4360                         rpc_g_cn_client_assoc_act_tbl,
4361                         &(assoc->assoc_state),
4362			 rpc_c_cn_cl_assoc );
4363    }
4364    else
4365    {
4366        /*
4367         * Initialize the association with the server tables.
4368         */
4369        rpc__cn_sm_init (rpc_g_cn_server_assoc_sm,
4370                         rpc_g_cn_server_assoc_act_tbl,
4371                         &(assoc->assoc_state),
4372			 rpc_c_cn_svr_assoc );
4373    }
4374    assoc->assoc_flags |= type;
4375
4376    /*
4377     * We use our version number until we negotiate different.
4378     */
4379    assoc->assoc_vers_minor = RPC_C_CN_PROTO_VERS_MINOR;
4380
4381    *st = rpc_s_ok;
4382    return (assoc);
4383}
4384
4385
4386/***********************************************************************/
4387/*
4388**++
4389**
4390**  ROUTINE NAME:       rpc__cn_assoc_acb_dealloc
4391**
4392**  SCOPE:              PRIVATE - declared in cnassoc.h
4393**
4394**  DESCRIPTION:
4395**
4396**  This routine will return an association control block to the
4397**  association lookaside list.
4398**
4399**  INPUTS:
4400**
4401**      assoc           The association to be freed.
4402**
4403**  INPUTS/OUTPUTS:     none
4404**
4405**  OUTPUTS:            none
4406**
4407**  IMPLICIT INPUTS:    none
4408**
4409**  IMPLICIT OUTPUTS:   none
4410**
4411**  FUNCTION VALUE:     none
4412**
4413**  SIDE EFFECTS:       none
4414**
4415**--
4416**/
4417
4418PRIVATE void rpc__cn_assoc_acb_dealloc
4419(
4420  rpc_cn_assoc_p_t   assoc
4421)
4422{
4423    rpc_cn_fragbuf_t            *fragbuf;
4424    rpc_cn_syntax_t             *pres_context;
4425    rpc_cn_sec_context_t        *sec_context;
4426
4427    RPC_LOG_CN_ASSOC_ACB_DEAL_NTR;
4428    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_acb_dealloc);
4429
4430    RPC_CN_ASSOC_ACB_DEC_REF (assoc);
4431
4432    if (assoc->assoc_acb_ref_count == 0)
4433    {
4434        /*
4435         * Clear the pointer to the endpoint of the socket
4436         * descriptor contained in the connection control block.
4437         * Note that this memory is NOT freed. It is used by all
4438         * connections which come in on the descriptor in the
4439         * select pool and as such cannot be freed until this
4440         * descriptor is removed (there is no way to remove it right
4441         * now.)
4442         */
4443        assoc->cn_ctlblk.cn_listening_endpoint = NULL;
4444
4445        /*
4446         * Free all fragment buffers on the association message list
4447         * and clear the waiters field.
4448         */
4449        assoc->assoc_msg_waiters = 0;
4450        RPC_LIST_FIRST (assoc->msg_list,
4451                        fragbuf,
4452                        rpc_cn_fragbuf_p_t);
4453        while (fragbuf != NULL)
4454        {
4455            rpc_cn_fragbuf_t    *next_fragbuf;
4456
4457            RPC_LIST_NEXT (fragbuf,
4458                           next_fragbuf,
4459                           rpc_cn_fragbuf_p_t);
4460            if (fragbuf->fragbuf_dealloc != NULL)
4461            {
4462                (*fragbuf->fragbuf_dealloc)(fragbuf);
4463            }
4464            fragbuf = next_fragbuf;
4465        }
4466        RPC_LIST_INIT (assoc->msg_list);
4467
4468        /*
4469         * Free all the syntax elements on the association syntax
4470         * list.
4471         */
4472        RPC_LIST_FIRST (assoc->syntax_list,
4473                        pres_context,
4474                        rpc_cn_syntax_p_t);
4475        while (pres_context != NULL)
4476        {
4477            rpc_cn_syntax_t     *next_pres_context;
4478
4479            RPC_LIST_NEXT (pres_context, next_pres_context, rpc_cn_syntax_p_t);
4480            rpc__cn_assoc_syntax_free (&pres_context);
4481            pres_context = next_pres_context;
4482        }
4483        RPC_LIST_INIT (assoc->syntax_list);
4484
4485        /*
4486         * Free all the security context elements.
4487         */
4488        RPC_LIST_FIRST (assoc->security.context_list,
4489                        sec_context,
4490                        rpc_cn_sec_context_p_t);
4491        while (sec_context != NULL)
4492        {
4493            rpc_cn_sec_context_t        *next_sec_context;
4494
4495            RPC_LIST_NEXT (sec_context, next_sec_context, rpc_cn_sec_context_p_t);
4496            rpc__cn_assoc_sec_free (&sec_context);
4497            sec_context = next_sec_context;
4498        }
4499        RPC_LIST_INIT (assoc->security.context_list);
4500
4501        memset (&assoc->security, 0, sizeof (rpc_cn_assoc_sec_context_t));
4502
4503        /*
4504         * Free the call rep on the assoc.
4505         */
4506        if (assoc->call_rep != NULL)
4507        {
4508            /*
4509             * If this assoc is pointing to a call_rep that doesn't point
4510             * back to it then this assoc is probably a client assoc that
4511             * failed the presentation negotiation sequence and the call
4512             * rep already went back to the heap.  Hence this call_rep is
4513             * probably paired with another association at this time and
4514             * so it would be wrong to release the assoc from it.
4515             */
4516            if ( assoc->call_rep->assoc == assoc )
4517                assoc->call_rep->assoc = NULL;
4518            assoc->call_rep = NULL;
4519        }
4520
4521        rpc__transport_info_release(assoc->transport_info);
4522        assoc->transport_info = NULL;
4523        assoc->cn_ctlblk.cn_state = RPC_C_SM_CLOSED_STATE;
4524        assoc->assoc_status = rpc_s_ok;
4525        assoc->assoc_local_status = rpc_s_ok;
4526        RPC_CN_LOCAL_ID_CLEAR (assoc->assoc_grp_id);
4527        assoc->assoc_flags = 0;
4528        RPC_CN_ASSOC_CONTEXT_ID (assoc) = 0;
4529        assoc->assoc_max_xmit_frag = 0;
4530        assoc->assoc_max_recv_frag = 0;
4531        assoc->assoc_vers_minor = RPC_C_CN_PROTO_VERS_MINOR;
4532        assoc->assoc_ref_count = 0;
4533        assoc->assoc_shutdown_req_count = 0;
4534        assoc->cn_ctlblk.exit_rcvr = false;
4535        assoc->cn_ctlblk.in_sendmsg = false;
4536        assoc->cn_ctlblk.waiting_for_sendmsg_complete = false;
4537        assoc->assoc_sm_work = NULL;
4538
4539        /*
4540         * Free the rpc addr memory of the assoc.
4541         */
4542	{
4543	    error_status_t st;
4544
4545	    if (assoc->cn_ctlblk.rpc_addr)
4546	        rpc__naf_addr_free (&assoc->cn_ctlblk.rpc_addr, &st);
4547
4548	    assoc->cn_ctlblk.rpc_addr = NULL;
4549        }
4550
4551        /*
4552         * Finally free the association to the association lookaside
4553         * list.
4554         */
4555        rpc__list_element_free (&rpc_g_cn_assoc_lookaside_list,
4556                                (dce_pointer_t) assoc);
4557    }
4558    RPC_LOG_CN_ASSOC_ACB_DEAL_XIT;
4559}
4560
4561/******************************************************************************/
4562
4563
4564/*
4565**++
4566**
4567**  ROUTINE NAME:       rpc__cn_assoc_acb_create
4568**
4569**  SCOPE:              PRIVATE - declared in cnassoc.h
4570**
4571**  DESCRIPTION:
4572**
4573**  This routine will initialize an association control block
4574**  which is allocated from heap by rpc__list_element_alloc. It
4575**  will create the mutexes and condition variables as well as
4576**  create the receiver thread.
4577**
4578**  INPUTS:
4579**
4580**      assoc           The association control block to be initialized.
4581**
4582**  INPUTS/OUTPUTS:     none
4583**
4584**  OUTPUTS:            none
4585**
4586**  IMPLICIT INPUTS:    none
4587**
4588**  IMPLICIT OUTPUTS:   none
4589**
4590**  FUNCTION VALUE:     none
4591**
4592**  SIDE EFFECTS:       none
4593**
4594**--
4595**/
4596
4597PRIVATE void rpc__cn_assoc_acb_create
4598(
4599  rpc_cn_assoc_p_t        assoc
4600)
4601{
4602    RPC_LOG_CN_ASSOC_ACB_CR_NTR;
4603    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_acb_create);
4604
4605    memset (assoc, 0, sizeof (rpc_cn_assoc_t));
4606    assoc->alter_call_id = -1;
4607    RPC_COND_INIT (assoc->cn_ctlblk.cn_rcvr_cond, rpc_g_global_mutex);
4608    RPC_COND_INIT (assoc->assoc_msg_cond, rpc_g_global_mutex);
4609
4610    /*
4611     * Create the receiver thread.
4612     */
4613    RPC_DBG_PRINTF (rpc_e_dbg_threads, RPC_C_CN_DBG_THREADS,
4614        ( "####### assoc->%p Created receiver thread\n", assoc ));
4615
4616    DCETHREAD_TRY {
4617    dcethread_create_throw (&(assoc->cn_ctlblk.cn_rcvr_thread_id),
4618                    &rpc_g_default_dcethread_attr,
4619                    (dcethread_startroutine) rpc__cn_network_receiver,
4620                    (dcethread_addr) assoc);
4621    } DCETHREAD_CATCH_ALL(THIS_CATCH) {
4622        DCETHREAD_RERAISE;
4623    } DCETHREAD_ENDTRY
4624
4625    RPC_LOG_CN_ASSOC_ACB_CR_XIT;
4626}
4627
4628
4629/***********************************************************************/
4630/*
4631**++
4632**
4633**  ROUTINE NAME:       rpc__cn_assoc_acb_free
4634**
4635**  SCOPE:              PRIVATE - declared in cnassoc.h
4636**
4637**  DESCRIPTION:
4638**
4639**  This routine will free the mutexes, condition variables and
4640**  receiver thread contained in an association control block before the
4641**  rpc__list_element_free routine returns it to heap storage.
4642**
4643**  INPUTS:
4644**
4645**      assoc           The association control block being freed.
4646**
4647**  INPUTS/OUTPUTS:     none
4648**
4649**  OUTPUTS:            none
4650**
4651**  IMPLICIT INPUTS:    none
4652**
4653**  IMPLICIT OUTPUTS:   none
4654**
4655**  FUNCTION VALUE:     none
4656**
4657**  SIDE EFFECTS:       none
4658**
4659**--
4660**/
4661
4662PRIVATE void rpc__cn_assoc_acb_free
4663(
4664 rpc_cn_assoc_p_t        assoc
4665)
4666{
4667    rpc_cn_ctlblk_t     * volatile ccb;
4668    dcethread*          current_thread_id;
4669    void *		dcethread_exit_status;
4670    int                 prev_cancel_state;
4671
4672    //DO_NOT_CLOBBER(ccb);
4673
4674    RPC_LOG_CN_ASSOC_ACB_FR_NTR;
4675    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_acb_free);
4676
4677    /*
4678     * Get a pointer to the connection control block contained in
4679     * the association control block.
4680     */
4681    ccb = &assoc->cn_ctlblk;
4682
4683#ifdef notdef
4684    if (ccb->cn_rcvr_thread_id == (dcethread*) NULL)
4685    {
4686        RPC_LOG_CN_ASSOC_ACB_FR_XIT;
4687        return;
4688    }
4689#endif
4690
4691    /*
4692     * Determine whether we are now running in the receiver thread.
4693     */
4694    current_thread_id = dcethread_self();
4695    if (dcethread_equal (current_thread_id, ccb->cn_rcvr_thread_id) )
4696    {
4697        /*
4698         * We are the receiver thread.
4699         * Send a cancel to ourselves so we will exit out of
4700         * the while loop in rpc__cn_network_receiver() without
4701         * having to reference the assoc which are going to
4702         * (possibly) free soon.
4703         */
4704        RPC_COND_DELETE (ccb->cn_rcvr_cond, rpc_g_global_mutex);
4705        RPC_COND_DELETE (assoc->assoc_msg_cond, rpc_g_global_mutex);
4706        ccb->exit_rcvr = true;
4707        dcethread_detach_throw (ccb->cn_rcvr_thread_id);
4708        dcethread_interrupt_throw (ccb->cn_rcvr_thread_id);
4709    }
4710    else
4711    {
4712        /*
4713         * The receiver thread is now running with the CN global mutex
4714         * locked. We don't want to blow away anything in the association
4715         * or connection control block until we're sure the receiver
4716         * thread has terminated. To ensure this send the receiver thread a
4717         * cancel and then wait until it exits by using the
4718         * dcethread_join() function. This function will not return
4719         * until the receiver thread has terminated.
4720         */
4721        ccb->exit_rcvr = true;
4722        dcethread_interrupt_throw (ccb->cn_rcvr_thread_id);
4723
4724        /*
4725         * Since this is a cancellable operation we'll turn cancels
4726         * off here. There's nothing we can do with them at this point.
4727         * The CN mutex must be unlocked also while we do the join.
4728         * This is because the receiver thread may need to lock the CN
4729         * mutex in order to exit. For instance, the receiver thread
4730         * may be blocked on the condition variable waiting for a new
4731         * connection. The process of unblocking from this condition
4732         * variable by definition acquires the CN mutex.
4733         */
4734        prev_cancel_state = dcethread_enableinterrupt_throw (0);
4735        RPC_CN_UNLOCK ();
4736        dcethread_join_throw (ccb->cn_rcvr_thread_id,
4737                      &dcethread_exit_status);
4738        RPC_CN_LOCK ();
4739        dcethread_enableinterrupt_throw (prev_cancel_state);
4740
4741        /*
4742         * Now that the receiver thread has terminated we can delete the
4743         * receiver thread and association receive queue condition variable.
4744         */
4745        RPC_COND_DELETE (ccb->cn_rcvr_cond, rpc_g_global_mutex);
4746        RPC_COND_DELETE (assoc->assoc_msg_cond, rpc_g_global_mutex);
4747    }
4748
4749    {
4750        error_status_t st;
4751
4752        if (ccb->rpc_addr)
4753            rpc__naf_addr_free (&ccb->rpc_addr, &st);
4754    }
4755
4756    RPC_LOG_CN_ASSOC_ACB_FR_XIT;
4757}
4758
4759/*****************************************************************************/
4760/*****************************************************************************/
4761/*****************************************************************************/
4762
4763/*****************************************************************************/
4764/*
4765**++
4766**
4767**  ROUTINE NAME:       rpc__cn_assoc_grp_init
4768**
4769**  SCOPE:              INTERNAL - declared locally
4770**
4771**  DESCRIPTION:
4772**
4773**  This routine will initialize all the fields of the
4774**  association group given.
4775**
4776**  INPUTS:
4777**
4778**      assoc_grp       The association group to be initialized.
4779**      index           The index part of the local ID assigned to
4780**                      this group.
4781**
4782**  INPUTS/OUTPUTS:     none
4783**
4784**  OUTPUTS:            none
4785**
4786**  IMPLICIT INPUTS:    none
4787**
4788**  IMPLICIT OUTPUTS:   none
4789**
4790**  FUNCTION VALUE:     none
4791**
4792**  SIDE EFFECTS:       none
4793**
4794**--
4795**/
4796
4797INTERNAL void rpc__cn_assoc_grp_init
4798(
4799 rpc_cn_assoc_grp_p_t    assoc_grp,
4800 unsigned32              index
4801)
4802{
4803    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_grp_init);
4804
4805    /*
4806     * Initialize all the fields in the association group given.
4807     */
4808    memset (assoc_grp, 0, sizeof (rpc_cn_assoc_grp_t));
4809    rpc__cn_gen_local_id (index, &assoc_grp->grp_id);
4810    assoc_grp->grp_max_assoc = (typeof(assoc_grp->grp_max_assoc))(RPC_C_ASSOC_GRP_MAX_ASSOCS_DEFAULT);
4811    RPC_COND_INIT (assoc_grp->grp_assoc_wt, rpc_g_global_mutex);
4812    RPC_CN_STATS_INCR (assoc_grps);
4813}
4814
4815
4816/******************************************************************************/
4817/*
4818**++
4819**
4820**  ROUTINE NAME:       rpc__cn_assoc_grp_create
4821**
4822**  SCOPE:              INTERNAL - declared locally
4823**
4824**  DESCRIPTION:
4825**
4826**  This routine will expand the existing assoc group table by a
4827**  fixed amount. It does this by determining the size
4828**  of the old table, allocating a piece of memory that size plus
4829**  some increment and copying the old table into it. The
4830**  old table is then freed.
4831**
4832**  INPUTS:             none
4833**
4834**  INPUTS/OUTPUTS:     none
4835**
4836**  OUTPUTS:
4837**
4838**      st              The return status of this routine.
4839**                      rpc_s_ok
4840**
4841**  IMPLICIT INPUTS:    none
4842**
4843**  IMPLICIT OUTPUTS:   none
4844**
4845**  FUNCTION VALUE:     ID of the first association group in
4846**                      the expanded area of the new table.
4847**
4848**  SIDE EFFECTS:       none
4849**
4850**--
4851**/
4852
4853INTERNAL rpc_cn_local_id_t rpc__cn_assoc_grp_create
4854(
4855  unsigned32              *st
4856)
4857{
4858    rpc_cn_assoc_grp_t  *new_assoc_grp;
4859    rpc_cn_local_id_t   grp_id;
4860    unsigned16          old_count;
4861    unsigned16          new_count;
4862    unsigned32          i;
4863
4864    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_grp_create);
4865    CODING_ERROR (st);
4866
4867    /*
4868     * Compute the size of the new table.
4869     */
4870    old_count = rpc_g_cn_assoc_grp_tbl.grp_count;
4871    new_count = old_count + RPC_C_ASSOC_GRP_ALLOC_SIZE;
4872
4873    /*
4874     * First allocate a new association group table larger than the
4875     * existing by a fixed amount.
4876     */
4877    RPC_MEM_ALLOC (new_assoc_grp,
4878                   rpc_cn_assoc_grp_p_t,
4879                   sizeof(rpc_cn_assoc_grp_t) * new_count,
4880                   RPC_C_MEM_CN_ASSOC_GRP_BLK,
4881                   RPC_C_MEM_WAITOK);
4882    if (new_assoc_grp == NULL) {
4883        *st = rpc_s_no_memory;
4884        RPC_CN_LOCAL_ID_CLEAR (grp_id);
4885        return (grp_id);
4886    }
4887
4888    /*
4889     * If there is an old association group table copy it into the
4890     * new table and free it.
4891     */
4892    if (rpc_g_cn_assoc_grp_tbl.assoc_grp_vector != NULL)
4893    {
4894        memcpy (new_assoc_grp,
4895                rpc_g_cn_assoc_grp_tbl.assoc_grp_vector,
4896                (old_count * sizeof (rpc_cn_assoc_grp_t)));
4897        for (i = 0; i < old_count; i++)
4898        {
4899            /*
4900             * Relocate the "last" pointer in the head of the grp_assoc_list.
4901             * We don't check group's state because they must be all active.
4902             * Otherwise, this function never get called. (grp_assoc_list.next
4903             * shouldn't be NULL.)
4904             */
4905            if (new_assoc_grp[i].grp_assoc_list.next != NULL)
4906            {
4907                ((rpc_list_p_t)(new_assoc_grp[i].grp_assoc_list.next))->last =
4908                    (dce_pointer_t)&new_assoc_grp[i].grp_assoc_list;
4909            }
4910        }
4911
4912        RPC_MEM_FREE (rpc_g_cn_assoc_grp_tbl.assoc_grp_vector,
4913                      RPC_C_MEM_CN_ASSOC_GRP_BLK);
4914    }
4915
4916    /*
4917     * Update the count of association groups and point to the new
4918     * association group table.
4919     */
4920    rpc_g_cn_assoc_grp_tbl.grp_count = new_count;
4921    rpc_g_cn_assoc_grp_tbl.assoc_grp_vector = new_assoc_grp;
4922
4923    /*
4924     * Initialize the association groups in the table just
4925     * allocated.
4926     */
4927    for (i = old_count; i < new_count; i++)
4928    {
4929        rpc__cn_assoc_grp_init (&new_assoc_grp[i], i);
4930    }
4931
4932    /*
4933     * Return a pointer to the beginning of the new area in the
4934     * new table.
4935     */
4936    grp_id = new_assoc_grp[old_count].grp_id;
4937    *st = rpc_s_ok;
4938    return (grp_id);
4939}
4940
4941
4942/******************************************************************************/
4943/*
4944**++
4945**
4946**  ROUTINE NAME:       rpc__cn_assoc_grp_alloc
4947**
4948**  SCOPE:              PRIVATE - declared in cnassoc.h
4949**
4950**  DESCRIPTION:
4951**
4952**  This routine will locate an inactive association group slot
4953**  in the association table, possibly by increasing the
4954**  size of the table. This association group slot will be
4955**  initialized and the association will be added to the list.
4956**
4957**  INPUTS:
4958**
4959**      rpc_addr        The primary RPC address of the group.
4960**      type            The type of associations on this group.
4961**      rem_id          The remote group ID.
4962**
4963**
4964**  INPUTS/OUTPUTS:     none
4965**
4966**  OUTPUTS:
4967**
4968**      st              The return status of this routine.
4969**                      rpc_s_ok
4970**
4971**  IMPLICIT INPUTS:    none
4972**
4973**  IMPLICIT OUTPUTS:   none
4974**
4975**  FUNCTION VALUE:     none
4976**
4977**  SIDE EFFECTS:       none
4978**
4979**--
4980**/
4981
4982PRIVATE rpc_cn_local_id_t rpc__cn_assoc_grp_alloc
4983(
4984  rpc_addr_p_t            rpc_addr,
4985  rpc_transport_info_p_t  transport_info,
4986  unsigned32              type,
4987  unsigned32              rem_id,
4988  unsigned32              *st
4989)
4990{
4991    rpc_cn_assoc_grp_t  *assoc_grp;
4992    rpc_cn_local_id_t   grp_id;
4993    unsigned32          i;
4994    boolean             found_assoc_grp;
4995
4996    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_grp_alloc);
4997    CODING_ERROR (st);
4998
4999#ifdef DEBUG
5000    if (RPC_DBG_EXACT(rpc_es_dbg_cn_errors, RPC_C_CN_DBG_GRP_ALLOC))
5001    {
5002        *st = RPC_S_CN_DBG_FAILURE;
5003        RPC_CN_LOCAL_ID_CLEAR (grp_id);
5004        return(grp_id);
5005    }
5006#endif
5007
5008    /*
5009     * Ideally we'd like to locate an association group in the
5010     * existing table which is not being used. Worst case we'll
5011     * increase the size of the table to get a new group.
5012     *
5013     * Get a pointer to the group vector so this code will be easier
5014     * to read.
5015     */
5016    assoc_grp = rpc_g_cn_assoc_grp_tbl.assoc_grp_vector;
5017    for (i = 0, found_assoc_grp = false;
5018         i < rpc_g_cn_assoc_grp_tbl.grp_count;
5019         i++)
5020    {
5021        if (assoc_grp[i].grp_state.cur_state == RPC_C_ASSOC_GRP_CLOSED)
5022        {
5023            assoc_grp = &assoc_grp[i];
5024            found_assoc_grp = true;
5025            break;
5026        }
5027    }
5028
5029    if (!found_assoc_grp)
5030    {
5031        /*
5032         * The association group table will have to be expanded to
5033         * get a free group.
5034         */
5035        grp_id = rpc__cn_assoc_grp_create (st);
5036        if (!RPC_CN_LOCAL_ID_VALID (grp_id))
5037        {
5038            return (grp_id);
5039        }
5040        else
5041        {
5042            assoc_grp = RPC_CN_ASSOC_GRP (grp_id);
5043        }
5044    }
5045
5046    /*
5047     * At this point we have a group which has just been initialized.
5048     *
5049     * Copy the RPC address, if given, into the group.
5050     */
5051    if (rpc_addr != NULL)
5052    {
5053        rpc__naf_addr_copy (rpc_addr, &assoc_grp->grp_address, st);
5054        assert(assoc_grp != NULL);
5055        assoc_grp->grp_secaddr = NULL;
5056        if (*st != rpc_s_ok)
5057        {
5058            RPC_CN_LOCAL_ID_CLEAR (grp_id);
5059            return (grp_id);
5060        }
5061    }
5062
5063    assert(assoc_grp != NULL);
5064    assoc_grp->grp_transport_info = transport_info;
5065
5066    if (transport_info)
5067    {
5068        rpc__transport_info_retain(transport_info);
5069    }
5070
5071    /*
5072     * Set up the type of this association group.
5073     */
5074    assoc_grp->grp_flags |= type;
5075
5076    /*
5077     * Initialize the remote group id.
5078     */
5079    assoc_grp->grp_remid.all = rem_id;
5080
5081    /*
5082     * Initialize the state machine control block in the group based
5083     * on its type.
5084     */
5085    if (type == RPC_C_CN_ASSOC_GRP_CLIENT)
5086    {
5087        /*
5088         * Initialize with the client state tables.
5089         */
5090        rpc__cn_sm_init (rpc_g_cn_client_grp_sm,
5091                         rpc_g_cn_client_grp_action_tbl,
5092                         &(assoc_grp->grp_state),
5093			 rpc_c_cn_cl_a_g );
5094    }
5095    else
5096    {
5097        /*
5098         * Initialize with the server state tables.
5099         */
5100        rpc__cn_sm_init (rpc_g_cn_server_grp_sm,
5101                         rpc_g_cn_server_grp_action_tbl,
5102                         &(assoc_grp->grp_state),
5103			 rpc_c_cn_svr_a_g );
5104    }
5105
5106    /*
5107     * Finally send a new association event through the group state
5108     * machine.
5109     */
5110    RPC_CN_ASSOC_GRP_EVAL_EVENT (assoc_grp,
5111                                 RPC_C_ASSOC_GRP_NEW,
5112                                 NULL,
5113                                 assoc_grp->grp_status);
5114
5115    /*
5116     * Increment the the number of active groups in the association
5117     * group table.
5118     */
5119    rpc_g_cn_assoc_grp_tbl.grp_active_count++;
5120    *st = assoc_grp->grp_status;
5121    grp_id = assoc_grp->grp_id;
5122    return (grp_id);
5123}
5124
5125
5126/******************************************************************************/
5127/*
5128**++
5129**
5130**  ROUTINE NAME:       rpc__cn_assoc_grp_dealloc
5131**
5132**  SCOPE:              PRIVATE - declared in cnassoc.h
5133**
5134**  DESCRIPTION:
5135**
5136**  This routine will any resources on an association group. It
5137**  is assumed the association list is empty.
5138**
5139**  INPUTS:
5140**
5141**      grp_id          The id of the group being deallocated.
5142**
5143**
5144**  INPUTS/OUTPUTS:     none
5145**
5146**  OUTPUTS:            none
5147**
5148**  IMPLICIT INPUTS:    none
5149**
5150**  IMPLICIT OUTPUTS:   none
5151**
5152**  FUNCTION VALUE:     none
5153**
5154**  SIDE EFFECTS:       none
5155**
5156**--
5157**/
5158
5159PRIVATE void rpc__cn_assoc_grp_dealloc
5160(
5161  rpc_cn_local_id_t       grp_id
5162)
5163{
5164    rpc_cn_assoc_grp_t  *assoc_grp;
5165    rpc_addr_p_t        rpc_addr;
5166    unsigned32          st;
5167
5168    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_grp_dealloc);
5169
5170    /*
5171     * Check whether a primary RPC address exists on the group.
5172     */
5173    assoc_grp = RPC_CN_ASSOC_GRP (grp_id);
5174    assert(assoc_grp != NULL);
5175    if ((rpc_addr = assoc_grp->grp_address) != NULL)
5176    {
5177        /*
5178         * Free the RPC address.
5179         */
5180        rpc__naf_addr_free (&assoc_grp->grp_address, &st);
5181    }
5182
5183    /*
5184     * Check whether a secondary RPC address exists on the group.
5185     */
5186    if ((rpc_addr != assoc_grp->grp_secaddr)
5187        &&
5188        (assoc_grp->grp_secaddr != NULL))
5189    {
5190        /*
5191         * Free the RPC address.
5192         */
5193        rpc__naf_addr_free (&assoc_grp->grp_secaddr, &st);
5194    }
5195
5196    if (assoc_grp->grp_transport_info)
5197    {
5198        rpc__transport_info_release(assoc_grp->grp_transport_info);
5199        assoc_grp->grp_transport_info = NULL;
5200    }
5201
5202    /*
5203     * Set up other fields in the group for the next time it is
5204     * allocated.
5205     */
5206    RPC_CN_LOCAL_ID_CLEAR (assoc_grp->grp_remid);
5207    assoc_grp->grp_flags = 0;
5208    assoc_grp->grp_address = NULL;
5209    assoc_grp->grp_secaddr = NULL;
5210    assoc_grp->grp_refcnt = 0;
5211    assoc_grp->grp_max_assoc = (typeof(assoc_grp->grp_max_assoc))(RPC_C_ASSOC_GRP_MAX_ASSOCS_DEFAULT);
5212    assoc_grp->grp_cur_assoc = 0;
5213    assoc_grp->grp_assoc_waiters = 0;
5214    assoc_grp->grp_status = rpc_s_ok;
5215    assoc_grp->grp_next_key_id = 0;
5216    RPC_LIST_INIT (assoc_grp->grp_assoc_list);
5217    assoc_grp->grp_liveness_mntr = NULL;
5218    assoc_grp->grp_callcnt = 0;
5219
5220    /*
5221     * Regenerate the local ID since there may still be bindings
5222     * which have the old ID of this association group in it.
5223     */
5224    rpc__cn_gen_local_id (assoc_grp->grp_id.parts.id_index, &assoc_grp->grp_id);
5225
5226    /*
5227     * Decrement the the number of active groups in the association
5228     * group table.
5229     */
5230    rpc_g_cn_assoc_grp_tbl.grp_active_count--;
5231}
5232
5233
5234/******************************************************************************/
5235/*
5236**++
5237**
5238**  ROUTINE NAME:       rpc__cn_assoc_grp_add_assoc
5239**
5240**  SCOPE:              PRIVATE - declared in cnassoc.h
5241**
5242**  DESCRIPTION:
5243**
5244**  This routine will add the specified association to the
5245**  association list in the group.
5246**
5247**  INPUTS:
5248**
5249**      grp_id          The association group id.
5250**      assoc           The association to be added.
5251**
5252**  INPUTS/OUTPUTS:     none
5253**
5254**  OUTPUTS:            none
5255**
5256**  IMPLICIT INPUTS:    none
5257**
5258**  IMPLICIT OUTPUTS:   none
5259**
5260**  FUNCTION VALUE:     none
5261**
5262**  SIDE EFFECTS:       none
5263**
5264**--
5265**/
5266
5267PRIVATE void rpc__cn_assoc_grp_add_assoc
5268(
5269  rpc_cn_local_id_t       grp_id,
5270  rpc_cn_assoc_p_t        assoc
5271)
5272{
5273    rpc_cn_assoc_grp_t  *assoc_grp;
5274
5275    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_grp_add_assoc);
5276
5277    /*
5278     * Add the new association to the group by sending an add
5279     * association to group event through the group state machine.
5280     */
5281    assoc_grp = RPC_CN_ASSOC_GRP (grp_id);
5282    assert(assoc_grp != NULL);
5283    RPC_CN_ASSOC_GRP_EVAL_EVENT (assoc_grp,
5284                                 RPC_C_ASSOC_GRP_ADD_ASSOC,
5285                                 assoc,
5286                                 assoc_grp->grp_status);
5287}
5288
5289
5290/******************************************************************************/
5291/*
5292**++
5293**
5294**  ROUTINE NAME:       rpc__cn_assoc_grp_rem_assoc
5295**
5296**  SCOPE:              PRIVATE - declared in cnassoc.h
5297**
5298**  DESCRIPTION:
5299**
5300**  This routine will remove an association from the association
5301**  list on a group. If this results in the list becoming empty
5302**  the RPC address on the association group is freed and the
5303**  group is initialized.
5304**
5305**  INPUTS:
5306**
5307**      grp_id          The association group id.
5308**      assoc           The association to be removed.
5309**
5310**
5311**  INPUTS/OUTPUTS:     none
5312**
5313**  OUTPUTS:
5314**
5315**      st              The return status of this routine.
5316**                      rpc_s_ok
5317**
5318**  IMPLICIT INPUTS:    none
5319**
5320**  IMPLICIT OUTPUTS:   none
5321**
5322**  FUNCTION VALUE:     none
5323**
5324**  SIDE EFFECTS:       none
5325**
5326**--
5327**/
5328
5329PRIVATE void rpc__cn_assoc_grp_rem_assoc
5330(
5331  rpc_cn_local_id_t       grp_id,
5332  rpc_cn_assoc_p_t        assoc
5333)
5334{
5335    rpc_cn_assoc_grp_t  *assoc_grp;
5336
5337    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_grp_rem_assoc);
5338
5339    /*
5340     * If the association group passed in is NULL then this
5341     * operation is a no-op.
5342     */
5343    if (RPC_CN_LOCAL_ID_VALID (grp_id))
5344    {
5345        /*
5346         * Remove the association from the group by sending a remove
5347         * association from group event through the group state machine.
5348         */
5349        assoc_grp = RPC_CN_ASSOC_GRP (grp_id);
5350        assert(assoc_grp != NULL);
5351        RPC_CN_ASSOC_GRP_EVAL_EVENT (assoc_grp,
5352                                     RPC_C_ASSOC_GRP_REM_ASSOC,
5353                                     assoc,
5354                                     assoc_grp->grp_status);
5355
5356        /*
5357         * If this is a server association group and there are no
5358         * calls currently running on this association group and we
5359         * are in the call wait state then post a no calls
5360         * indication event to the group state machine.
5361         */
5362        if ((assoc_grp->grp_flags & RPC_C_CN_ASSOC_GRP_SERVER)
5363            &&
5364            (assoc_grp->grp_callcnt == 0)
5365            &&
5366            (assoc_grp->grp_state.cur_state ==
5367             RPC_C_SERVER_ASSOC_GRP_CALL_WAIT))
5368        {
5369            RPC_CN_ASSOC_GRP_EVAL_EVENT (assoc_grp,
5370                                         RPC_C_ASSOC_GRP_NO_CALLS_IND,
5371                                         assoc,
5372                                         assoc_grp->grp_status);
5373        }
5374    }
5375}
5376
5377
5378/******************************************************************************/
5379/*
5380**++
5381**
5382**  ROUTINE NAME:       rpc__cn_assoc_grp_lkup_by_addr
5383**
5384**  SCOPE:              PRIVATE - declared in cnassoc.h
5385**
5386**  DESCRIPTION:
5387**
5388**  This routine will scan the association group table for a
5389**  group which is active and whose RPC address matches that given
5390**  as an input argument. If a matching group is found a pointer to it is
5391**  returned otherwise a NULL is returned.
5392**
5393**  INPUTS:
5394**
5395**      rpc_addr        The address of a remote address space.
5396**      type            The type of association group (client or server).
5397**
5398**  INPUTS/OUTPUTS:     none
5399**
5400**  OUTPUTS:
5401**
5402**      st              The return status of this routine.
5403**                      rpc_s_ok
5404**                      rpc_s_assoc_grp_not_found
5405**
5406**  IMPLICIT INPUTS:    none
5407**
5408**  IMPLICIT OUTPUTS:   none
5409**
5410**  FUNCTION VALUE:
5411**
5412**      return          The id of the association group pointer found.
5413**
5414**  SIDE EFFECTS:       none
5415**
5416**--
5417**/
5418
5419PRIVATE rpc_cn_local_id_t rpc__cn_assoc_grp_lkup_by_addr
5420(
5421  rpc_addr_p_t            rpc_addr,
5422  rpc_transport_info_p_t  transport_info,
5423  unsigned32              type,
5424  unsigned32              *st
5425)
5426{
5427    boolean             addrs_equal;
5428    unsigned32          i;
5429    rpc_cn_assoc_grp_t  *assoc_grp;
5430    rpc_cn_local_id_t   grp_id;
5431
5432    RPC_LOG_CN_GRP_ADDR_LKUP_NTR;
5433    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_grp_lkup_by_addr);
5434    CODING_ERROR (st);
5435
5436    /*
5437     * Check whether a valid RPC address was given for the lookup.
5438     */
5439    if (rpc_addr != NULL)
5440    {
5441        /*
5442         * Get a pointer to the group vector so this code will be easier
5443         * to read.
5444         */
5445        assoc_grp = rpc_g_cn_assoc_grp_tbl.assoc_grp_vector;
5446
5447        /*
5448         * An association group will be located by using the RPC address
5449         * given.
5450         */
5451        for (i = 0; i < rpc_g_cn_assoc_grp_tbl.grp_count; i++)
5452        {
5453            /*
5454             * Check all groups which are the right type and are active
5455             */
5456            if ((assoc_grp[i].grp_flags & type)
5457                &&
5458                (assoc_grp[i].grp_state.cur_state == RPC_C_ASSOC_GRP_ACTIVE))
5459            {
5460
5461                /*
5462                 * The association group has associations. Compare the RPC
5463                 * address given against the primary address in the
5464                 * association group.
5465                 */
5466                addrs_equal = rpc__naf_addr_compare (rpc_addr,
5467                                                     assoc_grp[i].grp_address,
5468                                                     st);
5469                /*
5470                 * If the input argument RPC address matched that in
5471                 * the association group return it.
5472                 */
5473                if (!addrs_equal)
5474                {
5475                    /* address do not match, so continue searching */
5476                    continue;
5477                }
5478#ifndef __APPLE__
5479                if (!transport_info)
5480                {
5481                    /* addresses matched, but no transport_info to check, so
5482                     go ahead and use this group */
5483                    *st = rpc_s_ok;
5484                    return (assoc_grp[i].grp_id);
5485                }
5486#endif
5487                if (rpc__transport_info_equal(assoc_grp[i].grp_transport_info, transport_info))
5488                {
5489                    /* addresses matched and transport_info matched, so
5490                     go ahead and use this group */
5491                    *st = rpc_s_ok;
5492                    return (assoc_grp[i].grp_id);
5493                }
5494            }
5495        }
5496    }
5497
5498    /*
5499     * There were no matching association groups. Return NULL.
5500     */
5501    *st = rpc_s_assoc_grp_not_found;
5502    RPC_CN_LOCAL_ID_CLEAR (grp_id);
5503    RPC_LOG_CN_GRP_ADDR_LKUP_XIT;
5504    return (grp_id);
5505}
5506
5507
5508/******************************************************************************/
5509/*
5510**++
5511**
5512**  ROUTINE NAME:       rpc__cn_assoc_grp_lkup_by_remid
5513**
5514**  SCOPE:              PRIVATE - declared in cnassoc.h
5515**
5516**  DESCRIPTION:
5517**
5518**  This routine will scan the association group table for a
5519**  group whose remote group id matches that given as an input
5520**  argument. If a matching group is found a pointer to it is
5521**  returned otherwise a NULL is returned.
5522**
5523**  INPUTS:
5524**
5525**      rem_id          The remote group id.
5526**      type            The type of association group (client or server).
5527**      rpc_addr        The address of the server to which the
5528**                      association was established.
5529**
5530**  INPUTS/OUTPUTS:     none
5531**
5532**  OUTPUTS:
5533**
5534**      st              The return status of this routine.
5535**                      rpc_s_ok
5536**                      rpc_s_assoc_grp_not_found
5537**
5538**  IMPLICIT INPUTS:    none
5539**
5540**  IMPLICIT OUTPUTS:   none
5541**
5542**  FUNCTION VALUE:
5543**
5544**      return          The id of the association group pointer found.
5545**
5546**  SIDE EFFECTS:       none
5547**
5548**--
5549**/
5550
5551PRIVATE rpc_cn_local_id_t rpc__cn_assoc_grp_lkup_by_remid
5552(
5553  unsigned32              rem_id,
5554  unsigned32              type,
5555  rpc_addr_p_t            rpc_addr,
5556  unsigned32              *st
5557)
5558{
5559    unsigned32          i;
5560    rpc_cn_assoc_grp_t  *assoc_grp;
5561    rpc_cn_local_id_t   grp_id;
5562
5563    RPC_LOG_CN_GRP_REMID_LKUP_NTR;
5564    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_grp_lkup_by_remid);
5565    CODING_ERROR (st);
5566
5567    /*
5568     * Get a pointer to the group vector so this code will be easier
5569     * to read.
5570     */
5571    assoc_grp = rpc_g_cn_assoc_grp_tbl.assoc_grp_vector;
5572
5573    /*
5574     * An association group will be located by using the RPC address
5575     * given.
5576     */
5577    for (i = 0; i < rpc_g_cn_assoc_grp_tbl.grp_count; i++)
5578    {
5579        /*
5580         * Check all groups which are the right type and are active.
5581         */
5582        if ((assoc_grp[i].grp_flags & type)
5583            &&
5584            (assoc_grp[i].grp_state.cur_state == RPC_C_ASSOC_GRP_ACTIVE))
5585        {
5586            /*
5587             * The association group has associations. Compare the remote
5588             * group id given against the remote group id in the
5589             * association group.
5590             */
5591            if (assoc_grp[i].grp_remid.all == rem_id)
5592            {
5593                boolean             addrs_equal;
5594
5595                /*
5596                 * Check whether the primary address on the
5597                 * association group matches that to which the
5598                 * association was established.
5599                 */
5600                addrs_equal = rpc__naf_addr_compare (rpc_addr,
5601                                                     assoc_grp[i].grp_address,
5602                                                     st);
5603                if (addrs_equal)
5604                {
5605                    *st = rpc_s_ok;
5606                    RPC_LOG_CN_GRP_REMID_LKUP_XIT;
5607                    return (assoc_grp[i].grp_id);
5608                }
5609            }
5610        }
5611    }
5612
5613    /*
5614     * There were no matching association groups. Return NULL.
5615     */
5616    *st = rpc_s_assoc_grp_not_found;
5617    RPC_CN_LOCAL_ID_CLEAR (grp_id);
5618    return (grp_id);
5619}
5620
5621
5622/******************************************************************************/
5623/*
5624**++
5625**
5626**  ROUTINE NAME:       rpc__cn_assoc_grp_lkup_by_id
5627**
5628**  SCOPE:              PRIVATE - declared in cnassoc.h
5629**
5630**  DESCRIPTION:
5631**
5632**  This routine will match the group ID given against the entry
5633**  in the association group table. If the group is active and
5634**  entire group ID given matches that in the association group that
5635**  group is returned otherwise an invalid local id is returned.
5636**
5637**  INPUTS:
5638**
5639**      grp_id          The association group ID to compare against.
5640**      type            The type of association group (client or server).
5641**
5642**  INPUTS/OUTPUTS:     none
5643**
5644**  OUTPUTS:
5645**
5646**      st              The return status of this routine.
5647**                      rpc_s_ok
5648**                      rpc_s_assoc_grp_not_found
5649**
5650**  IMPLICIT INPUTS:    none
5651**
5652**  IMPLICIT OUTPUTS:   none
5653**
5654**  FUNCTION VALUE:
5655**
5656**      return          The id of the association group pointer found.
5657**
5658**  SIDE EFFECTS:       none
5659**
5660**--
5661**/
5662
5663PRIVATE rpc_cn_local_id_t rpc__cn_assoc_grp_lkup_by_id
5664(
5665  rpc_cn_local_id_t       grp_id,
5666  unsigned32              type,
5667  rpc_transport_info_p_t  transport_info,
5668  unsigned32              *st
5669)
5670{
5671    rpc_cn_assoc_grp_t  *assoc_grp;
5672    rpc_cn_local_id_t   ret_grp_id;
5673
5674    RPC_LOG_CN_GRP_ID_LKUP_NTR;
5675    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_grp_lkup_by_id);
5676    CODING_ERROR (st);
5677
5678#ifdef DEBUG
5679    if (RPC_DBG_EXACT(rpc_es_dbg_cn_errors,
5680                      RPC_C_CN_DBG_GRP_LKUP_BY_ID))
5681    {
5682        *st = rpc_s_assoc_grp_not_found;
5683        RPC_CN_LOCAL_ID_CLEAR (ret_grp_id);
5684        return (ret_grp_id);
5685    }
5686#endif
5687
5688    /*
5689     * First determine if we were given a valid group ID.
5690     */
5691    if (RPC_CN_LOCAL_ID_VALID (grp_id) &&
5692        grp_id.parts.id_index < rpc_g_cn_assoc_grp_tbl.grp_count)
5693    {
5694        /*
5695         * An association group will be located by using the lower 16
5696         * bits of the id as an index into the association group table.
5697         */
5698        assoc_grp = RPC_CN_ASSOC_GRP (grp_id);
5699
5700        /*
5701         * To use this association group the entire group id must match
5702         * and must be the right type.
5703         */
5704        assert(assoc_grp != NULL);
5705        if ( RPC_CN_LOCAL_ID_EQUAL (assoc_grp->grp_id, grp_id) &&
5706            (assoc_grp->grp_flags & type) &&
5707            (assoc_grp->grp_state.cur_state == RPC_C_ASSOC_GRP_ACTIVE) )
5708        {
5709#ifndef __APPLE__
5710            if (!transport_info)
5711            {
5712                /* grp_ids matched, but no transport_info to check, so
5713                 go ahead and use this group */
5714                *st = rpc_s_ok;
5715                RPC_LOG_CN_GRP_ID_LKUP_XIT;
5716                return (grp_id);
5717            }
5718#endif
5719            if (rpc__transport_info_equal(assoc_grp->grp_transport_info, transport_info))
5720            {
5721                /* grp_ids matched and transport_info matched, so
5722                 go ahead and use this group */
5723                *st = rpc_s_ok;
5724                RPC_LOG_CN_GRP_ID_LKUP_XIT;
5725                return (grp_id);
5726            }
5727        }
5728    }
5729
5730    *st = rpc_s_assoc_grp_not_found;
5731    RPC_CN_LOCAL_ID_CLEAR (ret_grp_id);
5732    return (ret_grp_id);
5733}
5734
5735
5736/******************************************************************************/
5737/*
5738**++
5739**
5740**  ROUTINE NAME:       rpc__cn_assoc_grp_tbl_init
5741**
5742**  SCOPE:              PRIVATE - declared in cnassoc.h
5743**
5744**  DESCRIPTION:
5745**
5746**  This routine will initialize the association group table.
5747**
5748**  INPUTS:             none
5749**
5750**  INPUTS/OUTPUTS:     none
5751**
5752**  OUTPUTS:            none
5753**
5754**  IMPLICIT INPUTS:    none
5755**
5756**  IMPLICIT OUTPUTS:   none
5757**
5758**  FUNCTION VALUE:     none
5759**
5760**  SIDE EFFECTS:       none
5761**
5762**--
5763**/
5764
5765PRIVATE void rpc__cn_assoc_grp_tbl_init (void)
5766{
5767    unsigned32          st;
5768    unsigned32          server_disc_time = 0;
5769    unsigned32          client_disc_time = 0;
5770    char                *x;
5771
5772    RPC_CN_DBG_RTN_PRINTF(rpc__cn_assoc_grp_tbl_init);
5773
5774    /*
5775     * Init the new association condition variable, count and wakeup
5776     * variables internal to this module.
5777     */
5778    RPC_COND_INIT (grp_new_wt,
5779                   rpc_g_global_mutex);
5780    grp_new_in_progress = false;
5781    grp_new_waiters = 0;
5782
5783    /*
5784     * Init the association group counts.
5785     */
5786    rpc_g_cn_assoc_grp_tbl.grp_count = 0;
5787    rpc_g_cn_assoc_grp_tbl.grp_active_count = 0;
5788
5789    /*
5790     * Init the association group vector to NULL.
5791     */
5792    rpc_g_cn_assoc_grp_tbl.assoc_grp_vector = NULL;
5793
5794    /*
5795     * Start the client and server reclaimation timers with the
5796     * values as specified in the NCA Connection Architecture
5797     * spec.
5798     */
5799    x = getenv("RPC_CLIENT_DISC_TIME");
5800    if (x != NULL)
5801        client_disc_time = (unsigned32)atoi(x);
5802   if (client_disc_time == 0)
5803        client_disc_time = RPC_C_ASSOC_CLIENT_DISC_TIMER;
5804
5805    rpc__timer_set (&rpc_g_cn_assoc_grp_tbl.grp_client_timer,
5806                    (rpc_timer_proc_p_t) rpc__cn_assoc_timer_reclaim,
5807                    (dce_pointer_t) RPC_C_CN_ASSOC_GRP_CLIENT,
5808                    RPC_CLOCK_SEC (client_disc_time));
5809
5810    x = getenv("RPC_SERVER_DISC_TIME");
5811    if (x != NULL)
5812        server_disc_time = (unsigned32)atoi(x);
5813   if (server_disc_time == 0)
5814        server_disc_time = RPC_C_ASSOC_SERVER_DISC_TIMER;
5815
5816    rpc__timer_set (&rpc_g_cn_assoc_grp_tbl.grp_server_timer,
5817                    (rpc_timer_proc_p_t) rpc__cn_assoc_timer_reclaim,
5818                    (dce_pointer_t) RPC_C_CN_ASSOC_GRP_SERVER,
5819                    RPC_CLOCK_SEC (server_disc_time));
5820
5821    /*
5822     * Put some association groups in the table so this doesn't have
5823     * to be done on the first RPC.
5824     */
5825    (void) rpc__cn_assoc_grp_create (&st);
5826}
5827
5828
5829/***********************************************************************/
5830/*
5831**++
5832**
5833**  ROUTINE NAME:       rpc__cn_grp_sm_protocol_error
5834**
5835**  SCOPE:              PRIVATE
5836**
5837**  DESCRIPTION:
5838**
5839**  Action routine invoked when an illegal transition is detected.
5840**  This routine writes an error message to stdout and DIEs.
5841**
5842**  INPUTS:
5843**
5844**      spc_struct      The special structure which is passed to the
5845**                      state machine event evaluation routine.
5846**			This is assumed to be the assoc grp.
5847**
5848**      event_param     The event specific argument.
5849**
5850**  INPUTS/OUTPUTS:
5851**      sm              The control block from the event
5852**                      evaluation routine.  Input is the current
5853**                      status and event for the control block.
5854**                      Output is the next state or updated
5855**                      current state, for the control block.
5856**
5857**  OUTPUTS:            none
5858**
5859**  IMPLICIT INPUTS:    none
5860**
5861**  IMPLICIT OUTPUTS:   none
5862**
5863**  FUNCTION VALUE:     unsigned32
5864**
5865**  SIDE EFFECTS:       output is printed on stdout.
5866**
5867**--
5868**/
5869
5870PRIVATE unsigned32     rpc__cn_grp_sm_protocol_error
5871(
5872    dce_pointer_t       spc_struct,
5873    dce_pointer_t       event_param ATTRIBUTE_UNUSED,
5874    dce_pointer_t       sm ATTRIBUTE_UNUSED
5875)
5876{
5877    rpc_cn_assoc_grp_t  *assoc_grp;
5878
5879    RPC_CN_DBG_RTN_PRINTF(rpc__cn_grp_sm_protocol_error);
5880    assoc_grp = (rpc_cn_assoc_grp_t *) spc_struct;
5881
5882    /*
5883     * "Illegal state transition detected in CN {server|client} association
5884     * group state machine [cur_state: %d, cur_event: %d, grp: %x]"
5885     */
5886    rpc_dce_svc_printf (
5887        __FILE__, __LINE__,
5888        "%d %d %x",
5889        rpc_svc_cn_state,
5890        svc_c_sev_fatal | svc_c_action_abort,
5891        (assoc_grp->grp_flags & RPC_C_CN_ASSOC_GRP_SERVER) ?
5892	    rpc_m_cn_ill_state_trans_sg : rpc_m_cn_ill_state_trans_cg,
5893        assoc_grp->grp_state.cur_state,
5894        assoc_grp->grp_state.cur_event,
5895        assoc_grp );
5896	 return 0;
5897}
5898